rev 3169 - people/dato/packages/trunk/amarok/debian/patches

Adeodato Simó adeodato at costa.debian.org
Mon Feb 20 03:51:43 UTC 2006


Author: adeodato
Date: 2006-02-20 03:51:13 +0000 (Mon, 20 Feb 2006)
New Revision: 3169

Added:
   people/dato/packages/trunk/amarok/debian/patches/svn_upto_r511476.diff
Removed:
   people/dato/packages/trunk/amarok/debian/patches/fix_m4a_ftbfs.diff
Modified:
   people/dato/packages/trunk/amarok/debian/patches/series
Log:
Okay, let's do a full SVN pull. Much bigger, but should get us much
more fixes.


Deleted: people/dato/packages/trunk/amarok/debian/patches/fix_m4a_ftbfs.diff

Modified: people/dato/packages/trunk/amarok/debian/patches/series
===================================================================
--- people/dato/packages/trunk/amarok/debian/patches/series	2006-02-19 20:19:58 UTC (rev 3168)
+++ people/dato/packages/trunk/amarok/debian/patches/series	2006-02-20 03:51:13 UTC (rev 3169)
@@ -1,3 +1,4 @@
+svn_upto_r511476.diff -p0
 am_maintainer_mode.patch -p0
 disable_no_undefined.patch -p0
 no_libadd_in_convenience_libs.diff -p0
@@ -4,4 +5,3 @@
 gmo_files_at_build_time.patch -p0
 disable-final.diff -p0
 some-binaries-in-usr-lib.patch -p0
-fix_m4a_ftbfs.diff -p0

Added: people/dato/packages/trunk/amarok/debian/patches/svn_upto_r511476.diff
===================================================================
--- people/dato/packages/trunk/amarok/debian/patches/svn_upto_r511476.diff	2006-02-19 20:19:58 UTC (rev 3168)
+++ people/dato/packages/trunk/amarok/debian/patches/svn_upto_r511476.diff	2006-02-20 03:51:13 UTC (rev 3169)
@@ -0,0 +1,31829 @@
+Index: party.cpp
+===================================================================
+--- amarok/src/party.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/party.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -89,11 +89,18 @@
+ }
+ 
+ void
++Party::disable()
++{
++    setDynamicMode( false, false );
++}
++
++void
+ Party::editActiveParty()
+ {
+     if( m_currentParty == 0 )
+         return;
+     ConfigDynamic::editDynamicPlaylist(PlaylistWindow::self(), m_currentParty);
++    loadConfig( m_currentParty );
+ }
+ 
+ #define partyInfo(function, default) { \
+@@ -153,13 +160,13 @@
+ 
+     if ( AmarokConfig::dynamicPreviousCount() != previousCount() )
+     {
+-        Playlist::instance()->adjustPartyPrevious( previousCount() );
++        Playlist::instance()->adjustPartyPrevious( previousCount(), true );
+         AmarokConfig::setDynamicPreviousCount( previousCount() );
+     }
+ 
+     if ( AmarokConfig::dynamicUpcomingCount() != upcomingCount() )
+     {
+-        Playlist::instance()->adjustPartyUpcoming( upcomingCount(), type );
++        Playlist::instance()->adjustPartyUpcoming( upcomingCount(), true, type );
+         AmarokConfig::setDynamicUpcomingCount( upcomingCount() );
+     }
+ 
+Index: collectiondb.cpp
+===================================================================
+--- amarok/src/collectiondb.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/collectiondb.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -5,6 +5,7 @@
+ // (c) 2005 Jeff Mitchell <kde-dev at emailgoeshere.com>
+ // (c) 2005 Isaiah Damron <xepo at trifault.net>
+ // (c) 2005 Alexandre Pereira de Oliveira <aleprj at gmail.com>
++// (c) 2006 Jonas Hurrelmann <j at outpo.st>
+ // See COPYING file for licensing information.
+ 
+ #define DEBUG_PREFIX "CollectionDB"
+@@ -21,6 +22,7 @@
+ #include "mediabrowser.h"
+ #include "metabundle.h"           //updateTags()
+ #include "playlist.h"
++#include "playlistloader.h"
+ #include "playlistbrowser.h"
+ #include "scancontroller.h"
+ #include "scrobbler.h"
+@@ -32,6 +34,7 @@
+ #include <qmutex.h>
+ #include <qregexp.h>              //setHTMLLyrics()
+ #include <qtimer.h>
++#include <qpainter.h>             //createDragPixmap()
+ 
+ #include <pthread.h>              //debugging, can be removed later
+ 
+@@ -814,6 +817,188 @@
+     }
+ }
+ 
++QPixmap
++CollectionDB::createDragPixmap(const KURL::List &urls)
++{
++
++    // settings
++    const int maxCovers = 4; // maximum number of cover images to show
++    const int coverSpacing = 20; // spacing between stacked covers
++    const int fontSpacing = 5; // spacing between covers and info text
++    const int fontSize = 12; // font size for info text
++    const int minWidth = 300; // minimum width (such that info text fits)
++    const int coverW = AmarokConfig::coverPreviewSize(); // size for "..." cover
++    const int coverH = coverW;
++
++
++    int covers = 0;
++    int songs = 0;
++    int pixmapW = 0;
++    int pixmapH = 0;
++    int remoteUrls = 0;
++
++//    QMap<QString, int> artistMap;
++    QMap<QString, int> albumMap;
++    QPixmap coverPm[maxCovers];
++
++    // iterate urls, get covers and count artist/albums
++    KURL::List::ConstIterator it = urls.begin();
++    for( ; it != urls.end(); ++it )
++    {
++        KURL src = ( *it );
++        // if its a playlist we need an other iteration pass...
++        BundleList bundles;
++        if ( PlaylistFile::isPlaylistFile( src ) ) {
++            if( src.isLocalFile() ) {
++                PlaylistFile plf( src.path() );
++                bundles = plf.bundles();
++            }
++            else remoteUrls++;
++        }
++        else {
++            bundles += MetaBundle(src);
++        }
++
++        for( BundleList::Iterator bundit = bundles.begin(), end = bundles.end(); bundit != end; ++bundit ) {
++            KURL url = (*bundit).url();
++            if (url.isLocalFile()) {
++                MetaBundle mb = MetaBundle(url); // why does the metabundle from playlistfile not have an artist/album field?
++                songs++;
++
++                if ( ! albumMap.contains(mb.artist()+mb.album()) ) {
++                    debug() << "fetching cover for " <<  mb.artist() << " / " << mb.album() << endl;
++                    QString coverName = CollectionDB::instance()->albumImage( mb.artist(), mb.album(), 1 );
++                    if (( coverName.find( "nocover.png" ) == -1 ) && ( covers < maxCovers )) {
++                        debug() << "adding cover " << coverName << endl;
++                        coverPm[covers++].load( coverName );
++                    }
++                    else {
++                        debug() << "no cover found - skipping " << coverName << endl;
++                    }
++                    albumMap[mb.artist()+mb.album()]=1;
++                }
++//                artistMap[mb.artist()]=1;
++            }
++            else {
++                remoteUrls++;
++            }
++        }
++    }
++
++    int albums = albumMap.count();
++//    int artists = artistMap.count();
++
++    // make a better text...
++    QString m_text;
++    if ( songs > 0 )
++        m_text= i18n("One song from ", "%n songs from ", songs)+i18n("one album", "%n albums",albums);
++    else if ( remoteUrls > 0 )
++        m_text= i18n("One remote file", "%n remote files", remoteUrls);
++    else
++        m_text= i18n("Unknown item");
++
++    // font... TODO: from config?
++    QFont font("Arial", fontSize);
++    QFontMetrics fm(font);
++    int fontH = fm.height()+2;
++
++    if ( covers > 0 ) {
++        // insert "..." cover as first image if appropiate
++        if ( covers < albums ) {
++            if ( covers < maxCovers ) covers++;
++            for ( int i = maxCovers-1; i > 0; i-- )
++                coverPm[i] = coverPm[i-1];
++            QImage im( locate( "data","amarok/images/more_albums.png" ) );
++	    coverPm[0].convertFromImage(im.smoothScale(coverW, coverH, QImage::ScaleMin));
++        }
++
++        pixmapH = coverPm[0].height();
++        pixmapW = coverPm[0].width();
++
++        // caluclate pixmap height
++        int dW, dH;
++        for (int i = 1; i < covers; i++ ) {
++            dW = coverPm[i].width() - coverPm[i-1].width() + coverSpacing;
++            dH = coverPm[i].height() - coverPm[i-1].height() + coverSpacing;
++            if ( dW > 0 ) pixmapW += dW;
++            if ( dH > 0 ) pixmapH += dH;
++        }
++        pixmapH += fontSpacing + fontH;
++
++        if (pixmapW < minWidth)
++            pixmapW = minWidth;
++    }
++    else {
++        pixmapW = minWidth;
++        pixmapH = fontH;
++    }
++
++
++    QPixmap pmdrag(pixmapW, pixmapH);
++    QPixmap pmtext(pixmapW, fontH);
++
++    QPainter p;
++    p.begin(&pmtext);
++    p.fillRect(0, 0, pixmapW, fontH, QBrush(Qt::black));
++    p.setPen(Qt::white);
++    p.setFont(font);
++    p.drawText(2, fm.ascent() + 1, m_text);
++    p.end();
++
++    int w = pmtext.width();
++    int h = pmtext.height();
++
++    // simple morphological dilation of image for masking with outline (to get font with contour)
++    QImage input = pmtext.convertToImage().convertDepth(32);
++    QImage output(w, h, 1, 2, QImage::LittleEndian); // check endianess?
++    output.fill(0);
++    int x, y;
++    for (x = 1; x < w - 1; x++) {
++	for (y = 1; y < h - 1; y++) {
++	    if ((*((uint *) input.scanLine(y) + x - 1) ^ 0xff000000)
++		|| (*((uint *) input.scanLine(y - 1) + x) ^ 0xff000000)
++		|| (*((uint *) input.scanLine(y) + x) ^ 0xff000000)
++		|| (*((uint *) input.scanLine(y + 1) + x) ^ 0xff000000)
++		|| (*((uint *) input.scanLine(y) + x + 1) ^ 0xff000000)) {
++//		if (output.bitOrder() == QImage::LittleEndian)
++		    *(output.scanLine(y) + (x >> 3)) |= 1 << (x & 7);
++//		else
++//		    *(output.scanLine(y) + (x >> 3)) |= 1 << (7 - (x & 7));
++	    }
++	}
++    }
++    QBitmap pmtextMask(pixmapW, fontH);
++    pmtextMask = output;
++
++    // when we have found no covers, just display the text message
++    if (covers == 0) {
++	pmtext.setMask(pmtextMask);
++	return pmtext;
++    }
++
++    // compose image
++    p.begin(&pmdrag);
++    p.setBackgroundMode(Qt::TransparentMode);
++    for (int i = 0; i < covers; i++) {
++	bitBlt(&pmdrag, i * coverSpacing, i * coverSpacing, &coverPm[i], 0, Qt::CopyROP);
++    }
++    bitBlt(&pmdrag, 0, pixmapH - fontH, &pmtext, 0, Qt::CopyROP);
++    p.end();
++
++
++
++    QBitmap pmdragMask(pmdrag.size(), true);
++    for (int i = 0; i < covers; i++) {
++        QBitmap coverMask(coverPm[i].width(), coverPm[i].height());
++        coverMask.fill(Qt::color1);
++	bitBlt(&pmdragMask, i * coverSpacing, i * coverSpacing, &coverMask, 0, Qt::CopyROP);
++    }
++    bitBlt(&pmdragMask, 0, pixmapH - fontH, &pmtextMask, 0, Qt::CopyROP);
++    pmdrag.setMask(pmdragMask);
++
++    return pmdrag;
++}
++
+ QImage
+ CollectionDB::fetchImage(const KURL& url, QString &/*tmpFile*/)
+ {
+@@ -2464,26 +2649,33 @@
+     }
+     else
+     {
+-        if ( adminValue( "Database Stats Version" ).toInt() != DATABASE_STATS_VERSION )
++        if ( adminValue( "Database Stats Version" ).toInt() != DATABASE_STATS_VERSION
++          || config->readNumEntry( "Database Stats Version", 0 ) != DATABASE_STATS_VERSION )
+         {
+             debug() << "Different database stats version detected! Stats table will be updated or rebuilt." << endl;
+-            debug() << "Creating a backup of the database in "
+-                    << amaroK::saveLocation()+"collection-backup.db" << "." << endl;
+-            debug() << "Unfortunately, this only works for SQLite databases." << endl;
+ 
+-            bool copied = KIO::NetAccess::file_copy( amaroK::saveLocation()+"collection.db",
+-                                                     amaroK::saveLocation()+"collection-backup.db",
+-                                                     -1 /*perms*/, true /*overwrite*/, false /*resume*/ );
++            if( getType() == DbConnection::sqlite && QFile::exists( amaroK::saveLocation()+"collection.db" ) )
++            {
++                debug() << "Creating a backup of the database in "
++                        << amaroK::saveLocation()+"collection-backup.db" << "." << endl;
+ 
+-            if( !copied )
+-            {
+-                debug() << "Backup failed! Perhaps you are not using SQLite, or the volume is not writable." << endl;
+-                debug() << "Error was: " << KIO::NetAccess::lastErrorString() << endl;
++                bool copied = KIO::NetAccess::file_copy( amaroK::saveLocation()+"collection.db",
++                                                         amaroK::saveLocation()+"collection-backup.db",
++                                                         -1 /*perms*/, true /*overwrite*/, false /*resume*/ );
++
++                if( !copied )
++                {
++                    debug() << "Backup failed! Perhaps the volume is not writable." << endl;
++                    debug() << "Error was: " << KIO::NetAccess::lastErrorString() << endl;
++                }
+             }
+ 
+             int prev = adminValue( "Database Stats Version" ).toInt();
+-            if( !prev && config->readNumEntry( "Database Stats Version", 0 )
+-                      && config->readNumEntry( "Database Stats Version", 0 ) != DATABASE_STATS_VERSION )
++
++            /* If config returns 3 or lower, it came from an amaroK version that was not aware of
++               admin table, so we can't trust this table at all */
++            if( !prev || ( config->readNumEntry( "Database Stats Version", 0 )
++                      && config->readNumEntry( "Database Stats Version", 0 ) <= 3  ) )
+                 prev = config->readNumEntry( "Database Stats Version", 0 );
+ 
+             //pre somewhere in the 1.3-1.4 timeframe, the version wasn't stored in the DB, so try to guess it
+Index: scripts/lyrics_astraweb/lyrics_astraweb.rb
+===================================================================
+--- amarok/src/scripts/lyrics_astraweb/lyrics_astraweb.rb	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/scripts/lyrics_astraweb/lyrics_astraweb.rb	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -85,8 +85,6 @@
+ 
+     doc = REXML::Document.new()
+     root = doc.add_element( "lyrics" )
+-    root.add_attribute( "site", "Astraweb" )
+-    root.add_attribute( "site_url", "http://lyrics.astraweb.com" )
+     root.add_attribute( "artist", artist )
+     root.add_attribute( "title", title )
+     root.text = lyrics
+Index: scripts/lyrics_astraweb/lyrics_astraweb.spec
+===================================================================
+--- amarok/src/scripts/lyrics_astraweb/lyrics_astraweb.spec	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/scripts/lyrics_astraweb/lyrics_astraweb.spec	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -1,2 +1,6 @@
+ name = Astraweb
+ type = lyrics
++
++[Lyrics]
++site = Astraweb
++site_url = http://lyrics.astraweb.com
+Index: scripts/lyrics_lyrc/lyrics_lyrc.rb
+===================================================================
+--- amarok/src/scripts/lyrics_lyrc/lyrics_lyrc.rb	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/scripts/lyrics_lyrc/lyrics_lyrc.rb	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -43,9 +43,6 @@
+     doc = REXML::Document.new()
+     root = doc.add_element( "lyrics" )
+ 
+-    root.add_attribute( "add_url", "http://lyrc.com.ar/en/add/add.php?grupo=MAGIC_ARTIST&tema=MAGIC_TITLE&disco=MAGIC_ALBUM&ano=MAGIC_YEAR" )
+-    root.add_attribute( "site", "Lyrc" )
+-    root.add_attribute( "site_url", "http://lyrc.com.ar" )
+     root.add_attribute( "title", /(<b>)([^<]*)/.match( lyrics )[2].to_s() )
+     root.add_attribute( "artist", /(<u>)([^<]*)/.match( lyrics )[2].to_s() )
+ 
+@@ -74,8 +71,6 @@
+     doc = REXML::Document.new()
+     root = doc.add_element( "suggestions" )
+ 
+-    root.add_attribute( "add_url", "http://lyrc.com.ar/en/add/add.php?grupo=MAGIC_ARTIST&tema=MAGIC_TITLE&disco=MAGIC_ALBUM&ano=MAGIC_YEAR" )
+-
+     entries = lyrics.split( "<br>" )
+     entries.delete_at( 0 )
+ 
+@@ -126,6 +121,7 @@
+     lyrics = response.body()
+     lyrics.gsub!( "\n", "" ) # No need for LF, just complicates our RegExps
+     lyrics.gsub!( "\r", "" ) # No need for CR, just complicates our RegExps
++    lyrics.gsub!( '´', "'" ) # Lyrc has weird encodings
+ 
+     # Remove images, links, scripts, styles and fonts
+     lyrics.gsub!( /<[iI][mM][gG][^>]*>/, "" )
+Index: scripts/lyrics_lyrc/lyrics_lyrc.spec
+===================================================================
+--- amarok/src/scripts/lyrics_lyrc/lyrics_lyrc.spec	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/scripts/lyrics_lyrc/lyrics_lyrc.spec	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -1,2 +1,7 @@
+ name = Lyrc
+ type = lyrics
++
++[Lyrics]
++add_url = http://lyrc.com.ar/en/add/add.php?grupo=MAGIC_ARTIST&tema=MAGIC_TITLE&disco=MAGIC_ALBUM&ano=MAGIC_YEAR
++site = Lyrc
++site_url = http://lyrc.com.ar
+Index: scripts/databasescripts/staleImages.rb
+===================================================================
+--- amarok/src/scripts/databasescripts/staleImages.rb	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 0)
++++ amarok/src/scripts/databasescripts/staleImages.rb	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -0,0 +1,27 @@
++#!/usr/bin/env ruby
++#
++# script to remove stale images in the database
++#
++# (c) 2006 Roland Gigler <rolandg at web.de>
++# License: GNU General Public License V2
++
++`dcop amarok playlist shortStatusMessage "Removing stale 'images' entries from the database"`
++
++qresult = `dcop amarok collection query "SELECT path FROM images;"`
++result = qresult.split( "\n" )
++
++i = 0
++
++result.each do |url|
++    #puts "url: #{url}"
++    unless FileTest.exist?( url )
++        i = i + 1
++        #url.gsub!(/[']/, '\\\\\'')
++        puts "Deleting: #{url}"
++        `dcop amarok collection query "DELETE FROM images WHERE path = '#{url}'"`
++    end
++end
++
++if i > 0
++    `dcop amarok playlist popupMessage "Removed #{i} stale 'images' entries from the database"`
++end
+
+Property changes on: scripts/databasescripts/staleImages.rb
+___________________________________________________________________
+Name: svn:executable
+   + *
+
+Index: scripts/databasescripts/staleArtists.rb
+===================================================================
+--- amarok/src/scripts/databasescripts/staleArtists.rb	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 0)
++++ amarok/src/scripts/databasescripts/staleArtists.rb	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -0,0 +1,33 @@
++#!/usr/bin/env ruby
++#
++# script to remove stale entries in some database tables (artist)
++#
++# (c) 2006 Roland Gigler <rolandg at web.de>
++# License: GNU General Public License V2
++
++`dcop amarok playlist shortStatusMessage "Removing stale 'artist' entries from the database"`
++
++qresult = `dcop amarok collection query "SELECT id FROM artist;"`
++result = qresult.split( "\n" )
++
++i = 0
++
++result.each do |id|
++    print "Checking: #{id}, "
++    qresult2 = `dcop amarok collection query "SELECT COUNT() FROM tags where artist = #{id};"`
++    count = qresult2.chomp()
++    printf "count: %s\n", count
++    if  count == "0"
++        i = i + 1
++	qresult3 = `dcop amarok collection query "SELECT name FROM artist where id = #{id} ;"`
++        result3 = qresult3.split( "\n" )
++        puts "==>: Deleting: #{id}, #{result3}"
++        `dcop amarok collection query "DELETE FROM artist WHERE id = '#{id}'"`
++    end
++end
++puts "i: #{i}"
++
++if i > 0
++    `dcop amarok playlist popupMessage "Removed #{i} stale 'artist' entries from the database"`
++end
++
+
+Property changes on: scripts/databasescripts/staleArtists.rb
+___________________________________________________________________
+Name: svn:executable
+   + *
+
+Index: scripts/databasescripts/staleAlbums.rb
+===================================================================
+--- amarok/src/scripts/databasescripts/staleAlbums.rb	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 0)
++++ amarok/src/scripts/databasescripts/staleAlbums.rb	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -0,0 +1,34 @@
++#!/usr/bin/env ruby
++#
++# script to remove stale entries in some database tables (album)
++#
++# (c) 2006 Roland Gigler <rolandg at web.de>
++# License: GNU General Public License V2
++
++`dcop amarok playlist shortStatusMessage "Removing stale 'album' entries from the database"`
++
++qresult = `dcop amarok collection query "SELECT id FROM album;"`
++result = qresult.split( "\n" )
++
++i = 0
++
++result.each do |id|
++    print "Checking: #{id}, "
++    qresult2 = `dcop amarok collection query "SELECT COUNT() FROM tags where album = #{id};"`
++    count = qresult2.chomp()
++    printf "count: %s", count
++    if  count == "0"
++        i = i + 1
++	qresult3 = `dcop amarok collection query "SELECT name FROM album where id = #{id} ;"`
++        result3 = qresult3.split( "\n" )
++        puts "==>: Deleting: #{id}, #{result3}"
++        `dcop amarok collection query "DELETE FROM album WHERE id = '#{id}'"`
++    end
++    print "\n"
++end
++puts "removed #{i} albums."
++
++if i > 0
++    `dcop amarok playlist popupMessage "Removed #{i} stale 'album' entries from the database"`
++end
++
+
+Property changes on: scripts/databasescripts/staleAlbums.rb
+___________________________________________________________________
+Name: svn:executable
+   + *
+
+Index: podcastsettings.cpp
+===================================================================
+--- amarok/src/podcastsettings.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/podcastsettings.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -22,7 +22,7 @@
+ PodcastSettings::PodcastSettings( const QDomNode &channelSettings, const QString &title )
+     : m_title( title )
+ {
+-    m_saveLocation = channelSettings.namedItem( "savelocation").toElement().text();
++    m_saveLocation = KURL::fromPathOrURL( channelSettings.namedItem( "savelocation").toElement().text() );
+     m_autoScan = channelSettings.namedItem( "autoscan").toElement().text() == "true";
+     m_interval = channelSettings.namedItem( "scaninterval").toElement().text().toInt();
+     m_fetch = channelSettings.namedItem("fetch").toElement().text() == "automatic"?AUTOMATIC:STREAM;
+@@ -49,7 +49,7 @@
+ PodcastSettings::PodcastSettings( const QString &title )
+     : m_title( title )
+ {
+-    m_saveLocation = amaroK::saveLocation( "podcasts/data/" );
++    m_saveLocation = KURL::fromPathOrURL( amaroK::saveLocation( "podcasts/data/" ) );
+     m_autoScan = false;
+     m_interval = 4;
+     m_fetch = STREAM;
+@@ -104,7 +104,7 @@
+ 
+ 
+ PodcastSettingsDialog::PodcastSettingsDialog( PodcastSettings *settings, PodcastSettings *parentSettings, QWidget* parent )
+-                            : KDialogBase(  parent, 0, true, i18n("Configure %1").arg( settings->m_title)
++                            : KDialogBase(  parent, 0, true, i18n("Configure %1").arg( settings->m_title )
+                             , KDialogBase::User1|KDialogBase::Ok|KDialogBase::Cancel
+                             , KDialogBase::Ok, true
+                             , KGuiItem(i18n("reset"), "reset" ) )
+Index: playerwindow.cpp
+===================================================================
+--- amarok/src/playerwindow.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/playerwindow.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -367,11 +367,14 @@
+     m_pSlider->setEnabled( bundle.length() > 0 );
+ 
+     m_rateString     = bundle.prettyBitrate();
+-    const QString Hz = bundle.prettySampleRate( true );
++    QString Hz = bundle.prettySampleRate( true );
+     if( !Hz.isEmpty() )
+     {
+-        if( !m_rateString.isEmpty() ) m_rateString += " - ";
+-        m_rateString += Hz;
++        Hz = i18n("%1 Hz").arg( Hz );
++        if( m_rateString.isEmpty() )
++            m_rateString = Hz;
++        else
++            m_rateString = i18n("%1 - %2").arg( m_rateString, Hz );
+     }
+ 
+     QStringList list( bundle.prettyTitle() );
+Index: metabundle.h
+===================================================================
+--- amarok/src/metabundle.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/metabundle.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -198,6 +198,8 @@
+     QString prettyBitrate() const;
+     QString prettyLength() const;
+     QString prettySampleRate( bool shortened = false ) const;
++    QString prettyFilesize() const;
++    QString prettyRating() const;
+ 
+ public: //modifiers
+     virtual void setUrl( const KURL &url );
+@@ -226,6 +228,9 @@
+ public: //static helper functions
+     static QString prettyBitrate( int );
+     static QString prettyLength( int, bool showHours = false ); //must be int, see Unavailable, etc. above
++    static QString prettyFilesize( int );
++    static QString prettyRating( int );
++    static QStringList ratingList();
+     static QString prettyTime( uint, bool showHours = true );
+     static QString zeroPad( uint i );
+     static QString prettyTitle( const QString &filename );
+@@ -333,6 +338,8 @@
+ inline QString MetaBundle::prettyURL() const { return m_url.prettyURL(); }
+ inline QString MetaBundle::prettyBitrate() const { return prettyBitrate( m_bitrate ); }
+ inline QString MetaBundle::prettyLength() const { return prettyLength( m_length, true ); }
++inline QString MetaBundle::prettyFilesize() const { return prettyFilesize( m_filesize ); }
++inline QString MetaBundle::prettyRating() const { return prettyRating( m_rating ); }
+ inline QString MetaBundle::prettySampleRate( bool shortened ) const
+     {
+         if ( shortened )
+Index: hintlineedit.h
+===================================================================
+--- amarok/src/hintlineedit.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 0)
++++ amarok/src/hintlineedit.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -0,0 +1,27 @@
++#ifndef HINTLINEEDIT_H
++#define HINTLINEEDIT_H
++
++#include <klineedit.h> //baseclass
++
++class QVBox;
++class QLabel;
++class QWidget;
++
++class HintLineEdit : public KLineEdit
++{
++    Q_OBJECT
++
++public:
++    HintLineEdit( const QString &hint, const QString &text, QWidget *parent = 0, const char *name = 0 );
++    HintLineEdit( const QString &text, QWidget *parent = 0, const char *name = 0 );
++    HintLineEdit( QWidget *parent = 0, const char *name = 0 );
++    virtual ~HintLineEdit();
++    virtual QObject *parent();
++    virtual void setHint( const QString &hint );
++private:
++    void init();
++    QVBox *m_vbox;
++    QLabel *m_hint;
++};
++
++#endif
+Index: mediabrowser.h
+===================================================================
+--- amarok/src/mediabrowser.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/mediabrowser.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -434,7 +434,15 @@
+         QString           getTransferDir() { return m_transferDir; }
+         Medium *          getMedium() { return m_medium; }
+ 
++        void              setSpacesToUnderscores( bool yesno ) { m_spacesToUnderscores = yesno; }
++        bool              getSpacesToUnderscores() { return m_spacesToUnderscores; }
+ 
++        void              setFirstSort( QString text ) { m_firstSort = text; }
++        void              setSecondSort( QString text ) { m_secondSort = text; }
++        void              setThirdSort( QString text ) { m_thirdSort = text; }
++
++
++
+     public slots:
+         void abortTransfer();
+         void transferFiles();
+@@ -544,6 +552,9 @@
+         MediaView       *m_view;
+         Medium          *m_medium;
+         QString          m_transferDir;
++        QString          m_firstSort;
++        QString          m_secondSort;
++        QString          m_thirdSort;
+         bool             m_wait;
+         bool             m_waitForDeletion;
+         bool             m_copyFailed;
+@@ -556,6 +567,8 @@
+         bool             m_deleting;
+         bool             m_deferredDisconnect;
+         bool             m_runDisconnectHook;
++        bool             m_spacesToUnderscores;
++
+         MediaItem       *m_transferredItem;
+         QString          m_type;
+ 
+Index: playlist.cpp
+===================================================================
+--- amarok/src/playlist.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/playlist.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -294,8 +294,6 @@
+              this,       SLOT( saveUndoState() ) );
+     connect( CollectionDB::instance(), SIGNAL( scoreChanged( const QString&, int ) ),
+              this,       SLOT( scoreChanged( const QString&, int ) ) );
+-    connect( CollectionDB::instance(), SIGNAL( scoreChanged( const QString&, int ) ),
+-             this,       SLOT( playCountChanged( const QString& ) ) );
+     connect( CollectionDB::instance(), SIGNAL( ratingChanged( const QString&, int ) ),
+              this,       SLOT( ratingChanged( const QString&, int ) ) );
+     connect( header(), SIGNAL( indexChange( int, int, int ) ),
+@@ -740,7 +738,7 @@
+  */
+ 
+ void
+-Playlist::adjustPartyUpcoming( uint songCount, const int type )
++Playlist::adjustPartyUpcoming( uint songCount, bool saveUndo, const int type )
+ {
+     bool requireTracks = false;
+     int  currentPos = 0;
+@@ -796,7 +794,8 @@
+         }
+ 
+         if( list.isEmpty() ) return;
+-        saveUndoState();
++        if ( saveUndo )
++            saveUndoState();
+ 
+         //remove the items
+         for( QListViewItem *item = list.first(); item; item = list.next() )
+@@ -813,7 +812,7 @@
+   */
+ 
+ void
+-Playlist::adjustPartyPrevious( uint songCount )
++Playlist::adjustPartyPrevious( uint songCount, bool saveUndo )
+ {
+     int current = currentTrackIndex();
+     int x = current - songCount;
+@@ -823,7 +822,8 @@
+     for( QListViewItemIterator it( firstChild() ); y < x ; list.prepend( *it ), ++it, y++ );
+ 
+     if( list.isEmpty() ) return;
+-    saveUndoState();
++    if ( saveUndo )
++        saveUndoState();
+ 
+     //remove the items
+     for( QListViewItem *item = list.first(); item; item = list.next() )
+@@ -1051,7 +1051,8 @@
+                 if( AmarokConfig::entireAlbums() )
+                 {
+                     if ( m_prevAlbums.count() <= 8 ) {
+-                        m_prevAlbums.clear();
++                        while( m_prevAlbums.count() )
++                            removeFromPreviousAlbums();
+ 
+                         // don't add it to previous albums if we only have one album in the playlist
+                         // would loop infinitely otherwise
+@@ -1061,7 +1062,7 @@
+                                 albums.append( (*it)->m_album );
+ 
+                         if ( albums.count() > 1 )
+-                            m_prevAlbums.append( m_currentTrack->m_album );
++                            appendToPreviousAlbums( m_currentTrack->m_album );
+                     }
+                     else {
+                         m_prevAlbums.first(); //set's current item to first item
+@@ -1069,14 +1070,15 @@
+                         //keep 80 tracks in the previous list so item time user pushes play
+                         //we don't risk playing anything too recent
+                         while( m_prevAlbums.count() > 8 )
+-                            m_prevAlbums.remove(); //removes current item
++                            removeFromPreviousAlbums();; //removes current item
+                     }
+                 }
+ 
+                 else
+                 {
+                     if ( m_prevTracks.count() <= 80 ) {
+-                        m_prevTracks.clear();
++                        while( m_prevTracks.count() )
++                            removeFromPreviousTracks();
+ 
+                         // don't add it to previous tracks if we only have one file in the playlist
+                         // would loop infinitely otherwise
+@@ -1085,7 +1087,7 @@
+                             ++count;
+ 
+                         if ( count > 1 )
+-                            m_prevTracks.append( m_currentTrack );
++                            appendToPreviousTracks( m_currentTrack );
+                     }
+                     else {
+                         m_prevTracks.first(); //set's current item to first item
+@@ -1093,7 +1095,7 @@
+                         //keep 80 tracks in the previous list so item time user pushes play
+                         //we don't risk playing anything too recent
+                         while( m_prevTracks.count() > 80 )
+-                            m_prevTracks.remove(); //removes current item
++                            removeFromPreviousTracks(); //removes current item
+                     }
+                 }
+ 
+@@ -1224,26 +1226,18 @@
+ Playlist::advancePartyTrack( PlaylistItem *item )
+ {
+     MyIterator it( this, MyIterator::Visible );
+-
+     if( !item ) item = currentTrack();
+ 
+-    int x;
+-    for( x=0 ; *it; ++it, x++ )
++    for( int x=0 ; *it; ++it, x++ )
+     {
+         if( *it == item )
+         {
+             if( AmarokConfig::dynamicMarkHistory() ) (*it)->setEnabled( false );
+-            if( x < AmarokConfig::dynamicPreviousCount() )
+-                break;
+-
+-            if( AmarokConfig::dynamicCycleTracks() )
+-            {
+-                PlaylistItem *first = firstChild();
+-                if( first )
+-                {
+-                    removeItem( first ); //first visible item
+-                    delete first;
+-                }
++            for ( PlaylistItem *first = firstChild();
++                  AmarokConfig::dynamicCycleTracks() && x >= AmarokConfig::dynamicPreviousCount() && first;
++                  first = firstChild(), x-- ) {
++                removeItem( first ); //first visible item
++                delete first;
+             }
+             break;
+         }
+@@ -1277,13 +1271,13 @@
+             PlaylistAlbum* a = m_prevAlbums.last();
+             while( a && !a->tracks.count() )
+             {
+-                m_prevAlbums.remove();
++                removeFromPreviousAlbums();
+                 a = m_prevAlbums.last();
+             }
+             if( a )
+             {
+                 item = a->tracks.getLast();
+-                m_prevAlbums.remove();
++                removeFromPreviousAlbums();
+             }
+         }
+         if( !item )
+@@ -1297,11 +1291,11 @@
+         else {
+             // if enough songs in buffer, jump to the previous one
+             m_prevTracks.last();
+-            m_prevTracks.remove(); //remove the track playing now
++            removeFromPreviousTracks(); //remove the track playing now
+             item = m_prevTracks.last();
+ 
+             // we need to remove this item now, since it will be added in activate() again
+-            m_prevTracks.remove();
++            removeFromPreviousTracks();
+         }
+     }
+ 
+@@ -1642,10 +1636,12 @@
+         return;
+ 
+     if( AmarokConfig::entireAlbums() )
++    {
+         if( !item->nextInAlbum() )
+-            m_prevAlbums.append( item->m_album );
++            appendToPreviousAlbums( item->m_album );
++    }
+     else
+-        m_prevTracks.append( item );
++        appendToPreviousTracks( item );
+ 
+     //if we are playing something from the next tracks
+     //list, remove it from the list
+@@ -1675,19 +1671,7 @@
+     const int col = header()->sectionAt( contentsPos.x() );
+ 
+     QString text;
+-    if( col == PlaylistItem::Rating )
+-        switch( item->rating() )
+-        {
+-            case 0: text = i18n( "Not rated" ); break;
+-            case 1: text = i18n( "Crap" ); break;
+-            case 2: text = i18n( "Tolerable" ); break;
+-            case 3: text = i18n( "Good" ); break;
+-            case 4: text = i18n( "Excellent" ); break;
+-            case 5: text = i18n( "Inconceivable!" ); break;
+-            default: text = "This is a bug.";
+-        }
+-    else
+-        text = item->text( col );
++    text = item->text( col );
+ 
+     QRect irect = itemRect( item );
+     const int headerPos = header()->sectionPos( col );
+@@ -2078,6 +2062,8 @@
+     // that depends on a PlaylistItem, we are about to crash amaroK
+     // never unlock() the Playlist until it is safe!
+     safeClear();
++    m_total = 0;
++    m_albums.clear();
+ }
+ 
+ /**
+@@ -2096,7 +2082,8 @@
+     QListViewItem *n;
+     while( c ) {
+         n = c->nextSibling();
+-        delete c;
++        if ( !( (PlaylistItem *)( c ) )->isEmpty() ) //avoid deleting markers
++            delete c;
+         c = n;
+     }
+     blockSignals( block );
+@@ -2367,7 +2354,9 @@
+         list += url;
+     }
+ 
+-    return new KURLDrag( list, viewport() );
++    KURLDrag *drag = new KURLDrag( list, viewport() );
++    drag->setPixmap(CollectionDB::createDragPixmap(list), QPoint(CollectionDB::DRAGPIXMAP_OFFSET_X,CollectionDB::DRAGPIXMAP_OFFSET_Y));
++    return drag;
+ }
+ 
+ #include <qsimplerichtext.h>
+@@ -2880,6 +2869,8 @@
+                 prev->setEnabled( false );
+ 
+             activate( after );
++            if ( AmarokConfig::dynamicCycleTracks() )
++                adjustPartyPrevious( AmarokConfig::dynamicPreviousCount() );
+         }
+ 
+         if( m_queueDirt )
+@@ -3055,8 +3046,10 @@
+         PlaylistItem *item = (PlaylistItem *)(*it);
+         int     queueIndex = m_nextTracks.findRef( item );
+         bool    isQueued   = queueIndex != -1;
++        bool    isMarker   = item->isEmpty();
++        // markers are used by playlistloader, and removing them is not good
+ 
+-        if( !item->isEnabled() || item == m_currentTrack || isQueued )
++        if( !item->isEnabled() || item == m_currentTrack || isQueued || isMarker )
+             continue;
+ 
+         list.prepend( *it );
+@@ -3441,6 +3434,8 @@
+         if ( item->url().path() == path )
+         {
+             item->setScore( score );
++            item->setPlayCount( CollectionDB::instance()->getPlayCount( path ) );
++            item->setLastPlay( CollectionDB::instance()->getLastPlay( path ).toTime_t() );
+             item->filter( m_filter );
+         }
+     }
+@@ -3461,17 +3456,47 @@
+ }
+ 
+ void
+-Playlist::playCountChanged( const QString &path )
++Playlist::appendToPreviousTracks( PlaylistItem *item )
+ {
+-    for( MyIt it( this, MyIt::All ); *it; ++it )
++    if( !m_prevTracks.containsRef( item ) )
+     {
+-        PlaylistItem *item = (PlaylistItem*)*it;
+-        if ( item->url().path() == path )
+-            item->setPlayCount( CollectionDB::instance()->getPlayCount( path ) );
++        m_total -= item->totalIncrementAmount();
++        m_prevTracks.append( item );
+     }
+ }
+ 
+ void
++Playlist::appendToPreviousAlbums( PlaylistAlbum *album )
++{
++    if( !m_prevAlbums.containsRef( album ) )
++    {
++        m_total -= album->total;
++        m_prevAlbums.append( album );
++    }
++}
++
++void
++Playlist::removeFromPreviousTracks( PlaylistItem *item )
++{
++    if( ( item && m_prevTracks.removeRef( item ) ) ||
++        ( ( item = m_prevTracks.current() ) && m_prevTracks.remove() ) )
++    {
++        m_total += item->totalIncrementAmount();
++    }
++}
++
++void
++Playlist::removeFromPreviousAlbums( PlaylistAlbum *album )
++{
++    if( ( album && m_prevAlbums.removeRef( album ) ) ||
++        ( ( album = m_prevAlbums.current() ) && m_prevAlbums.remove() ) )
++    {
++        m_total += album->total;
++    }
++}
++
++
++void
+ Playlist::showContextMenu( QListViewItem *item, const QPoint &p, int col ) //SLOT
+ {
+     //if clicked on an empty area
+@@ -3571,7 +3596,7 @@
+                 break;
+             }
+ 
+-    if( itemCount == 1 && ( item->isCurrent() || item->isQueued() ||
++    if( itemCount == 1 && ( item->isCurrent() || item->isQueued() || m_stopAfterTrack == item ||
+                             ( !AmarokConfig::randomMode() && ( amaroK::repeatPlaylist() || afterCurrent ) ) ||
+                             ( AmarokConfig::entireAlbums() && m_currentTrack &&
+                               item->m_album == m_currentTrack->m_album &&
+@@ -3583,7 +3608,7 @@
+         popup.setItemChecked( STOP_DONE, m_stopAfterTrack == item );
+     }
+ 
+-    if( isCurrent )
++    if( isCurrent && itemCount == 1 )
+     {
+         popup.insertItem( SmallIconSet( "repeat_track" ), i18n( "&Repeat Track" ), REPEAT );
+         popup.setItemChecked( REPEAT, amaroK::repeatTrack() );
+@@ -4069,7 +4094,7 @@
+        emit queueChanged( PLItemList(), PLItemList( item ) );
+ 
+     //keep recent buffer synchronised
+-    m_prevTracks.removeRef( item ); //removes all pointers to item
++    removeFromPreviousTracks( item ); //removes all pointers to item
+ 
+     updateNextPrev();
+ }
+@@ -4183,6 +4208,8 @@
+     emit queueChanged( PLItemList(), prev );
+     ThreadWeaver::instance()->abortAllJobsNamed( "TagWriter" );
+     safeClear();
++    m_total = 0;
++    m_albums.clear();
+ 
+     insertMediaInternal( url, 0 ); //because the listview is empty, undoState won't be forced
+ 
+Index: playlistbrowser.cpp
+===================================================================
+--- amarok/src/playlistbrowser.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/playlistbrowser.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -1046,7 +1046,7 @@
+         if( isPodcastItem( *it ) )
+         {
+             #define item static_cast<PodcastItem*>(*it)
+-            if( item->hasDownloaded() )
++            if( item->isOnDisk() )
+                 urls.append( item->localUrl() );
+             #undef  item
+         }
+@@ -1083,7 +1083,7 @@
+             for( QListViewItem *ch = (*it)->firstChild(); ch; ch = ch->nextSibling() )
+             {
+                 #define ch static_cast<PodcastItem*>(ch)
+-                if( ch->hasDownloaded() )
++                if( ch->isOnDisk() )
+                 {
+                     //delete downloaded media
+                     urls.append( ch->localUrl() );
+@@ -1109,7 +1109,7 @@
+         if( isPodcastItem( *it ) )
+         {
+             #define item static_cast<PodcastItem*>(*it)
+-            if( !item->hasDownloaded() )
++            if( !item->isOnDisk() )
+                 m_podcastDownloadQueue.append( item );
+             #undef  item
+         }
+@@ -1562,7 +1562,7 @@
+         {
+             #define child static_cast<PodcastItem *>(child)
+ 
+-            child->hasDownloaded() ?
++            child->isOnDisk() ?
+                 list.append( child->localUrl() ):
+                 list.append( child->url()      );
+ 
+@@ -1582,12 +1582,13 @@
+         #define item static_cast<PodcastItem *>(item)
+         KURL::List list;
+ 
+-        item->hasDownloaded() ?
++        item->isOnDisk() ?
+             list.append( item->localUrl() ):
+             list.append( item->url()      );
+ 
+         Playlist::instance()->insertMedia( list, Playlist::DirectPlay );
+         item->setNew( false );
++        item->setListened();
+ 
+         #undef item
+     }
+@@ -2224,7 +2225,7 @@
+                     const QStringList values = CollectionDB::instance()->query( static_cast<SmartPlaylist *>(item)->query() );
+                     int i=0;
+                     for( for_iterators( QStringList, values ); it != end; ++it ) {
+-                        if(i%11 == 10)
++                        if(i%12 == 11)
+                         {
+                             urls << KURL( *it );
+                         }
+@@ -2365,15 +2366,15 @@
+             menu.insertSeparator();
+             menu.insertItem( SmallIconSet( "usbpendrive_unmount" ),
+                              i18n( "Add to Media Device &Transfer Queue" ), MEDIA_DEVICE );
+-            menu.setItemEnabled( MEDIA_DEVICE, item->hasDownloaded() );
++            menu.setItemEnabled( MEDIA_DEVICE, item->isOnDisk() );
+         }
+ 
+         menu.insertSeparator();
+         menu.insertItem( SmallIconSet( "down" ), i18n( "&Download Media" ), GET );
+         menu.insertItem( SmallIconSet( "editdelete" ), i18n( "De&lete Podcast" ), DELETE );
+ 
+-        menu.setItemEnabled( GET, !item->hasDownloaded() );
+-        menu.setItemEnabled( DELETE, item->hasDownloaded() );
++        menu.setItemEnabled( GET, !item->isOnDisk() );
++        menu.setItemEnabled( DELETE, item->isOnDisk() );
+ 
+         switch( menu.exec( p ) )
+         {
+@@ -2382,7 +2383,7 @@
+                 break;
+ 
+             case QUEUE:
+-                if( item->hasDownloaded() )
++                if( item->isOnDisk() )
+                     Playlist::instance()->insertMedia( item->localUrl(), Playlist::Queue );
+                 else
+                     Playlist::instance()->insertMedia( item->url(), Playlist::Queue );
+@@ -2407,7 +2408,7 @@
+                         if(isPodcastItem( *it ) )
+                         {
+                             PodcastItem *podcast = static_cast<PodcastItem*>(*it);
+-                            if(podcast->hasDownloaded())
++                            if(podcast->isOnDisk())
+                             {
+                                 podcast->addToMediaDevice();
+                             }
+@@ -2961,7 +2962,7 @@
+         else if( isPodcastItem( *it ) )
+         {
+             #define item static_cast<PodcastItem *>(*it)
+-            if( item->hasDownloaded() )
++            if( item->isOnDisk() )
+                 urls += item->localUrl();
+             else
+                 urls += item->url();
+@@ -3004,6 +3005,7 @@
+     }
+ 
+     drag->addDragObject( new KURLDrag( urls, viewport() ) );
++    drag->setPixmap(CollectionDB::createDragPixmap(urls), QPoint(CollectionDB::DRAGPIXMAP_OFFSET_X,CollectionDB::DRAGPIXMAP_OFFSET_Y));
+     drag->dragCopy();
+ 
+ }
+Index: queuemanager.cpp
+===================================================================
+--- amarok/src/queuemanager.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/queuemanager.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -329,9 +329,7 @@
+ 
+         if( current.find( item ) == current.end() ) //avoid duplication
+         {
+-            QString title = item->artist();
+-            title.append( i18n(" - " ) );
+-            title.append( item->title() );
++            QString title = i18n("%1 - %2").arg( item->artist(), item->title() );
+ 
+             after = new QueueItem( m_listview, after, title );
+             m_map[ after ] = item;
+@@ -371,9 +369,7 @@
+     QValueList<PlaylistItem*>         current = m_map.values();
+     QValueListIterator<PlaylistItem*> newItem = current.find( item );
+ 
+-    QString title = item->artist();
+-    title.append( i18n(" - " ) );
+-    title.append( item->title() );
++    QString title = i18n("%1 - %2").arg( item->artist(), item->title() );
+ 
+     if( newItem == current.end() ) //avoid duplication
+     {
+@@ -426,9 +422,7 @@
+ 
+     for( PlaylistItem *item = list.first(); item; item = list.next() )
+     {
+-        QString title = item->artist();
+-        title.append( i18n(" - " ) );
+-        title.append( item->title() );
++        QString title = i18n("%1 - %2").arg( item->artist(), item->title() );
+ 
+         last = new QueueItem( m_listview, last, title );
+         m_map[ last ] = item;
+Index: sqlite/os_win.c
+===================================================================
+--- amarok/src/sqlite/os_win.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/os_win.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -35,6 +35,49 @@
+ #include "os_common.h"
+ 
+ /*
++** Determine if we are dealing with WindowsCE - which has a much
++** reduced API.
++*/
++#if defined(_WIN32_WCE)
++# define OS_WINCE 1
++#else
++# define OS_WINCE 0
++#endif
++
++/*
++** WinCE lacks native support for file locking so we have to fake it
++** with some code of our own.
++*/
++#if OS_WINCE
++typedef struct winceLock {
++  int nReaders;       /* Number of reader locks obtained */
++  BOOL bPending;      /* Indicates a pending lock has been obtained */
++  BOOL bReserved;     /* Indicates a reserved lock has been obtained */
++  BOOL bExclusive;    /* Indicates an exclusive lock has been obtained */
++} winceLock;
++#endif
++
++/*
++** The winFile structure is a subclass of OsFile specific to the win32
++** portability layer.
++*/
++typedef struct winFile winFile;
++struct winFile {
++  IoMethod const *pMethod;/* Must be first */
++  HANDLE h;               /* Handle for accessing the file */
++  unsigned char locktype; /* Type of lock currently held on this file */
++  short sharedLockByte;   /* Randomly chosen byte used as a shared lock */
++#if OS_WINCE
++  WCHAR *zDeleteOnClose;  /* Name of file to delete when closing */
++  HANDLE hMutex;          /* Mutex used to control access to shared lock */  
++  HANDLE hShared;         /* Shared memory segment used for locking */
++  winceLock local;        /* Locks obtained by this instance of winFile */
++  winceLock *shared;      /* Global shared lock memory for the file  */
++#endif
++};
++
++
++/*
+ ** Do not include any of the File I/O interface procedures if the
+ ** SQLITE_OMIT_DISKIO macro is defined (indicating that there database
+ ** will be in-memory only)
+@@ -56,8 +99,8 @@
+ int sqlite3_os_type = 0;
+ 
+ /*
+-** Return true (non-zero) if we are running under WinNT, Win2K or WinXP.
+-** Return false (zero) for Win95, Win98, or WinME.
++** Return true (non-zero) if we are running under WinNT, Win2K, WinXP,
++** or WinCE.  Return false (zero) for Win95, Win98, or WinME.
+ **
+ ** Here is an interesting observation:  Win95, Win98, and WinME lack
+ ** the LockFileEx() API.  But we can still statically link against that
+@@ -66,15 +109,19 @@
+ ** WinNT/2K/XP so that we will know whether or not we can safely call
+ ** the LockFileEx() API.
+ */
+-static int isNT(void){
+-  if( sqlite3_os_type==0 ){
+-    OSVERSIONINFO sInfo;
+-    sInfo.dwOSVersionInfoSize = sizeof(sInfo);
+-    GetVersionEx(&sInfo);
+-    sqlite3_os_type = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
++#if OS_WINCE
++# define isNT()  (1)
++#else
++  static int isNT(void){
++    if( sqlite3_os_type==0 ){
++      OSVERSIONINFO sInfo;
++      sInfo.dwOSVersionInfoSize = sizeof(sInfo);
++      GetVersionEx(&sInfo);
++      sqlite3_os_type = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
++    }
++    return sqlite3_os_type==2;
+   }
+-  return sqlite3_os_type==2;
+-}
++#endif /* OS_WINCE */
+ 
+ /*
+ ** Convert a UTF-8 string to UTF-32.  Space to hold the returned string
+@@ -122,17 +169,326 @@
+   return zFilename;
+ }
+ 
++#if OS_WINCE
++/*************************************************************************
++** This section contains code for WinCE only.
++*/
++/*
++** WindowsCE does not have a localtime() function.  So create a
++** substitute.
++*/
++#include <time.h>
++struct tm *__cdecl localtime(const time_t *t)
++{
++  static struct tm y;
++  FILETIME uTm, lTm;
++  SYSTEMTIME pTm;
++  i64 t64;
++  t64 = *t;
++  t64 = (t64 + 11644473600)*10000000;
++  uTm.dwLowDateTime = t64 & 0xFFFFFFFF;
++  uTm.dwHighDateTime= t64 >> 32;
++  FileTimeToLocalFileTime(&uTm,&lTm);
++  FileTimeToSystemTime(&lTm,&pTm);
++  y.tm_year = pTm.wYear - 1900;
++  y.tm_mon = pTm.wMonth - 1;
++  y.tm_wday = pTm.wDayOfWeek;
++  y.tm_mday = pTm.wDay;
++  y.tm_hour = pTm.wHour;
++  y.tm_min = pTm.wMinute;
++  y.tm_sec = pTm.wSecond;
++  return &y;
++}
+ 
++/* This will never be called, but defined to make the code compile */
++#define GetTempPathA(a,b)
++
++#define LockFile(a,b,c,d,e)       winceLockFile(&a, b, c, d, e)
++#define UnlockFile(a,b,c,d,e)     winceUnlockFile(&a, b, c, d, e)
++#define LockFileEx(a,b,c,d,e,f)   winceLockFileEx(&a, b, c, d, e, f)
++
++#define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-offsetof(winFile,h)]
++
+ /*
++** Acquire a lock on the handle h
++*/
++static void winceMutexAcquire(HANDLE h){
++   DWORD dwErr;
++   do {
++     dwErr = WaitForSingleObject(h, INFINITE);
++   } while (dwErr != WAIT_OBJECT_0 && dwErr != WAIT_ABANDONED);
++}
++/*
++** Release a lock acquired by winceMutexAcquire()
++*/
++#define winceMutexRelease(h) ReleaseMutex(h)
++
++/*
++** Create the mutex and shared memory used for locking in the file
++** descriptor pFile
++*/
++static BOOL winceCreateLock(const char *zFilename, winFile *pFile){
++  WCHAR *zTok;
++  WCHAR *zName = utf8ToUnicode(zFilename);
++  BOOL bInit = TRUE;
++
++  /* Initialize the local lockdata */
++  ZeroMemory(&pFile->local, sizeof(pFile->local));
++
++  /* Replace the backslashes from the filename and lowercase it
++  ** to derive a mutex name. */
++  zTok = CharLowerW(zName);
++  for (;*zTok;zTok++){
++    if (*zTok == '\\') *zTok = '_';
++  }
++
++  /* Create/open the named mutex */
++  pFile->hMutex = CreateMutexW(NULL, FALSE, zName);
++  if (!pFile->hMutex){
++    sqliteFree(zName);
++    return FALSE;
++  }
++
++  /* Acquire the mutex before continuing */
++  winceMutexAcquire(pFile->hMutex);
++  
++  /* Since the names of named mutexes, semaphores, file mappings etc are 
++  ** case-sensitive, take advantage of that by uppercasing the mutex name
++  ** and using that as the shared filemapping name.
++  */
++  CharUpperW(zName);
++  pFile->hShared = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL,
++                                       PAGE_READWRITE, 0, sizeof(winceLock),
++                                       zName);  
++
++  /* Set a flag that indicates we're the first to create the memory so it 
++  ** must be zero-initialized */
++  if (GetLastError() == ERROR_ALREADY_EXISTS){
++    bInit = FALSE;
++  }
++
++  sqliteFree(zName);
++
++  /* If we succeeded in making the shared memory handle, map it. */
++  if (pFile->hShared){
++    pFile->shared = (winceLock*)MapViewOfFile(pFile->hShared, 
++             FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(winceLock));
++    /* If mapping failed, close the shared memory handle and erase it */
++    if (!pFile->shared){
++      CloseHandle(pFile->hShared);
++      pFile->hShared = NULL;
++    }
++  }
++
++  /* If shared memory could not be created, then close the mutex and fail */
++  if (pFile->hShared == NULL){
++    winceMutexRelease(pFile->hMutex);
++    CloseHandle(pFile->hMutex);
++    pFile->hMutex = NULL;
++    return FALSE;
++  }
++  
++  /* Initialize the shared memory if we're supposed to */
++  if (bInit) {
++    ZeroMemory(pFile->shared, sizeof(winceLock));
++  }
++
++  winceMutexRelease(pFile->hMutex);
++  return TRUE;
++}
++
++/*
++** Destroy the part of winFile that deals with wince locks
++*/
++static void winceDestroyLock(winFile *pFile){
++  if (pFile->hMutex){
++    /* Acquire the mutex */
++    winceMutexAcquire(pFile->hMutex);
++
++    /* The following blocks should probably assert in debug mode, but they
++       are to cleanup in case any locks remained open */
++    if (pFile->local.nReaders){
++      pFile->shared->nReaders --;
++    }
++    if (pFile->local.bReserved){
++      pFile->shared->bReserved = FALSE;
++    }
++    if (pFile->local.bPending){
++      pFile->shared->bPending = FALSE;
++    }
++    if (pFile->local.bExclusive){
++      pFile->shared->bExclusive = FALSE;
++    }
++
++    /* De-reference and close our copy of the shared memory handle */
++    UnmapViewOfFile(pFile->shared);
++    CloseHandle(pFile->hShared);
++
++    /* Done with the mutex */
++    winceMutexRelease(pFile->hMutex);    
++    CloseHandle(pFile->hMutex);
++    pFile->hMutex = NULL;
++  }
++}
++
++/* 
++** An implementation of the LockFile() API of windows for wince
++*/
++static BOOL winceLockFile(
++  HANDLE *phFile,
++  DWORD dwFileOffsetLow,
++  DWORD dwFileOffsetHigh,
++  DWORD nNumberOfBytesToLockLow,
++  DWORD nNumberOfBytesToLockHigh
++){
++  winFile *pFile = HANDLE_TO_WINFILE(phFile);
++  BOOL bReturn = FALSE;
++
++  if (!pFile->hMutex) return TRUE;
++  winceMutexAcquire(pFile->hMutex);
++
++  /* Wanting an exclusive lock? */
++  if (dwFileOffsetLow == SHARED_FIRST
++       && nNumberOfBytesToLockLow == SHARED_SIZE){
++    if (pFile->shared->nReaders == 0 && pFile->shared->bExclusive == 0){
++       pFile->shared->bExclusive = TRUE;
++       pFile->local.bExclusive = TRUE;
++       bReturn = TRUE;
++    }
++  }
++
++  /* Want a read-only lock? */
++  else if ((dwFileOffsetLow >= SHARED_FIRST &&
++            dwFileOffsetLow < SHARED_FIRST + SHARED_SIZE) &&
++            nNumberOfBytesToLockLow == 1){
++    if (pFile->shared->bExclusive == 0){
++      pFile->local.nReaders ++;
++      if (pFile->local.nReaders == 1){
++        pFile->shared->nReaders ++;
++      }
++      bReturn = TRUE;
++    }
++  }
++
++  /* Want a pending lock? */
++  else if (dwFileOffsetLow == PENDING_BYTE && nNumberOfBytesToLockLow == 1){
++    /* If no pending lock has been acquired, then acquire it */
++    if (pFile->shared->bPending == 0) {
++      pFile->shared->bPending = TRUE;
++      pFile->local.bPending = TRUE;
++      bReturn = TRUE;
++    }
++  }
++  /* Want a reserved lock? */
++  else if (dwFileOffsetLow == RESERVED_BYTE && nNumberOfBytesToLockLow == 1){
++    if (pFile->shared->bReserved == 0) {
++      pFile->shared->bReserved = TRUE;
++      pFile->local.bReserved = TRUE;
++      bReturn = TRUE;
++    }
++  }
++
++  winceMutexRelease(pFile->hMutex);
++  return bReturn;
++}
++
++/*
++** An implementation of the UnlockFile API of windows for wince
++*/
++static BOOL winceUnlockFile(
++  HANDLE *phFile,
++  DWORD dwFileOffsetLow,
++  DWORD dwFileOffsetHigh,
++  DWORD nNumberOfBytesToUnlockLow,
++  DWORD nNumberOfBytesToUnlockHigh
++){
++  winFile *pFile = HANDLE_TO_WINFILE(phFile);
++  BOOL bReturn = FALSE;
++
++  if (!pFile->hMutex) return TRUE;
++  winceMutexAcquire(pFile->hMutex);
++
++  /* Releasing a reader lock or an exclusive lock */
++  if (dwFileOffsetLow >= SHARED_FIRST &&
++       dwFileOffsetLow < SHARED_FIRST + SHARED_SIZE){
++    /* Did we have an exclusive lock? */
++    if (pFile->local.bExclusive){
++      pFile->local.bExclusive = FALSE;
++      pFile->shared->bExclusive = FALSE;
++      bReturn = TRUE;
++    }
++
++    /* Did we just have a reader lock? */
++    else if (pFile->local.nReaders){
++      pFile->local.nReaders --;
++      if (pFile->local.nReaders == 0)
++      {
++        pFile->shared->nReaders --;
++      }
++      bReturn = TRUE;
++    }
++  }
++
++  /* Releasing a pending lock */
++  else if (dwFileOffsetLow == PENDING_BYTE && nNumberOfBytesToUnlockLow == 1){
++    if (pFile->local.bPending){
++      pFile->local.bPending = FALSE;
++      pFile->shared->bPending = FALSE;
++      bReturn = TRUE;
++    }
++  }
++  /* Releasing a reserved lock */
++  else if (dwFileOffsetLow == RESERVED_BYTE && nNumberOfBytesToUnlockLow == 1){
++    if (pFile->local.bReserved) {
++      pFile->local.bReserved = FALSE;
++      pFile->shared->bReserved = FALSE;
++      bReturn = TRUE;
++    }
++  }
++
++  winceMutexRelease(pFile->hMutex);
++  return bReturn;
++}
++
++/*
++** An implementation of the LockFileEx() API of windows for wince
++*/
++static BOOL winceLockFileEx(
++  HANDLE *phFile,
++  DWORD dwFlags,
++  DWORD dwReserved,
++  DWORD nNumberOfBytesToLockLow,
++  DWORD nNumberOfBytesToLockHigh,
++  LPOVERLAPPED lpOverlapped
++){
++  /* If the caller wants a shared read lock, forward this call
++  ** to winceLockFile */
++  if (lpOverlapped->Offset == SHARED_FIRST &&
++      dwFlags == 1 &&
++      nNumberOfBytesToLockLow == SHARED_SIZE){
++    return winceLockFile(phFile, SHARED_FIRST, 0, 1, 0);
++  }
++  return FALSE;
++}
++/*
++** End of the special code for wince
++*****************************************************************************/
++#endif /* OS_WINCE */
++
++/*
+ ** Delete the named file
+ */
+-int sqlite3OsDelete(const char *zFilename){
++int sqlite3WinDelete(const char *zFilename){
+   WCHAR *zWide = utf8ToUnicode(zFilename);
+   if( zWide ){
+     DeleteFileW(zWide);
+     sqliteFree(zWide);
+   }else{
++#if OS_WINCE
++    return SQLITE_NOMEM;
++#else
+     DeleteFileA(zFilename);
++#endif
+   }
+   TRACE2("DELETE \"%s\"\n", zFilename);
+   return SQLITE_OK;
+@@ -141,18 +497,25 @@
+ /*
+ ** Return TRUE if the named file exists.
+ */
+-int sqlite3OsFileExists(const char *zFilename){
++int sqlite3WinFileExists(const char *zFilename){
+   int exists = 0;
+   WCHAR *zWide = utf8ToUnicode(zFilename);
+   if( zWide ){
+     exists = GetFileAttributesW(zWide) != 0xffffffff;
+     sqliteFree(zWide);
+   }else{
++#if OS_WINCE
++    return SQLITE_NOMEM;
++#else
+     exists = GetFileAttributesA(zFilename) != 0xffffffff;
++#endif
+   }
+   return exists;
+ }
+ 
++/* Forward declaration */
++static int allocateWinFile(winFile *pInit, OsFile **pId);
++
+ /*
+ ** Attempt to open a file for both reading and writing.  If that
+ ** fails, try opening it read-only.  If the file does not exist,
+@@ -166,14 +529,15 @@
+ ** On failure, the function returns SQLITE_CANTOPEN and leaves
+ ** *id and *pReadonly unchanged.
+ */
+-int sqlite3OsOpenReadWrite(
++int sqlite3WinOpenReadWrite(
+   const char *zFilename,
+-  OsFile *id,
++  OsFile **pId,
+   int *pReadonly
+ ){
++  winFile f;
+   HANDLE h;
+   WCHAR *zWide = utf8ToUnicode(zFilename);
+-  assert( !id->isOpen );
++  assert( *pId==0 );
+   if( zWide ){
+     h = CreateFileW(zWide,
+        GENERIC_READ | GENERIC_WRITE,
+@@ -200,8 +564,18 @@
+     }else{
+       *pReadonly = 0;
+     }
++#if OS_WINCE
++    if (!winceCreateLock(zFilename, &f)){
++      CloseHandle(h);
++      sqliteFree(zWide);
++      return SQLITE_CANTOPEN;
++    }
++#endif
+     sqliteFree(zWide);
+   }else{
++#if OS_WINCE
++    return SQLITE_NOMEM;
++#else
+     h = CreateFileA(zFilename,
+        GENERIC_READ | GENERIC_WRITE,
+        FILE_SHARE_READ | FILE_SHARE_WRITE,
+@@ -226,14 +600,14 @@
+     }else{
+       *pReadonly = 0;
+     }
++#endif /* OS_WINCE */
+   }
+-  id->h = h;
+-  id->locktype = NO_LOCK;
+-  id->sharedLockByte = 0;
+-  id->isOpen = 1;
+-  OpenCounter(+1);
++  f.h = h;
++#if OS_WINCE
++  f.zDeleteOnClose = 0;
++#endif
+   TRACE3("OPEN R/W %d \"%s\"\n", h, zFilename);
+-  return SQLITE_OK;
++  return allocateWinFile(&f, pId);
+ }
+ 
+ 
+@@ -251,17 +625,18 @@
+ **
+ ** On failure, return SQLITE_CANTOPEN.
+ */
+-int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
++int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
++  winFile f;
+   HANDLE h;
+   int fileflags;
+   WCHAR *zWide = utf8ToUnicode(zFilename);
+-  assert( !id->isOpen );
++  assert( *pId == 0 );
++  fileflags = FILE_FLAG_RANDOM_ACCESS;
++#if !OS_WINCE
+   if( delFlag ){
+-    fileflags = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_RANDOM_ACCESS 
+-                     | FILE_FLAG_DELETE_ON_CLOSE;
+-  }else{
+-    fileflags = FILE_FLAG_RANDOM_ACCESS;
++    fileflags |= FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE;
+   }
++#endif
+   if( zWide ){
+     h = CreateFileW(zWide,
+        GENERIC_READ | GENERIC_WRITE,
+@@ -273,6 +648,9 @@
+     );
+     sqliteFree(zWide);
+   }else{
++#if OS_WINCE
++    return SQLITE_NOMEM;
++#else
+     h = CreateFileA(zFilename,
+        GENERIC_READ | GENERIC_WRITE,
+        0,
+@@ -281,17 +659,18 @@
+        fileflags,
+        NULL
+     );
++#endif /* OS_WINCE */
+   }
+   if( h==INVALID_HANDLE_VALUE ){
+     return SQLITE_CANTOPEN;
+   }
+-  id->h = h;
+-  id->locktype = NO_LOCK;
+-  id->sharedLockByte = 0;
+-  id->isOpen = 1;
+-  OpenCounter(+1);
++  f.h = h;
++#if OS_WINCE
++  f.zDeleteOnClose = delFlag ? utf8ToUnicode(zFilename) : 0;
++  f.hMutex = NULL;
++#endif
+   TRACE3("OPEN EX %d \"%s\"\n", h, zFilename);
+-  return SQLITE_OK;
++  return allocateWinFile(&f, pId);
+ }
+ 
+ /*
+@@ -301,10 +680,11 @@
+ **
+ ** On failure, return SQLITE_CANTOPEN.
+ */
+-int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
++int sqlite3WinOpenReadOnly(const char *zFilename, OsFile **pId){
++  winFile f;
+   HANDLE h;
+   WCHAR *zWide = utf8ToUnicode(zFilename);
+-  assert( !id->isOpen );
++  assert( *pId==0 );
+   if( zWide ){
+     h = CreateFileW(zWide,
+        GENERIC_READ,
+@@ -316,6 +696,9 @@
+     );
+     sqliteFree(zWide);
+   }else{
++#if OS_WINCE
++    return SQLITE_NOMEM;
++#else
+     h = CreateFileA(zFilename,
+        GENERIC_READ,
+        0,
+@@ -324,17 +707,18 @@
+        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
+        NULL
+     );
++#endif
+   }
+   if( h==INVALID_HANDLE_VALUE ){
+     return SQLITE_CANTOPEN;
+   }
+-  id->h = h;
+-  id->locktype = NO_LOCK;
+-  id->sharedLockByte = 0;
+-  id->isOpen = 1;
+-  OpenCounter(+1);
++  f.h = h;
++#if OS_WINCE
++  f.zDeleteOnClose = 0;
++  f.hMutex = NULL;
++#endif
+   TRACE3("OPEN RO %d \"%s\"\n", h, zFilename);
+-  return SQLITE_OK;
++  return allocateWinFile(&f, pId);
+ }
+ 
+ /*
+@@ -353,9 +737,9 @@
+ ** On failure, the function returns SQLITE_CANTOPEN and leaves
+ ** *id unchanged.
+ */
+-int sqlite3OsOpenDirectory(
+-  const char *zDirname,
+-  OsFile *id
++static int winOpenDirectory(
++  OsFile *id,
++  const char *zDirname
+ ){
+   return SQLITE_OK;
+ }
+@@ -371,7 +755,7 @@
+ ** Create a temporary file name in zBuf.  zBuf must be big enough to
+ ** hold at least SQLITE_TEMPNAME_SIZE characters.
+ */
+-int sqlite3OsTempFileName(char *zBuf){
++int sqlite3WinTempFileName(char *zBuf){
+   static char zChars[] =
+     "abcdefghijklmnopqrstuvwxyz"
+     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+@@ -413,12 +797,21 @@
+ /*
+ ** Close a file.
+ */
+-int sqlite3OsClose(OsFile *id){
+-  if( id->isOpen ){
+-    TRACE2("CLOSE %d\n", id->h);
+-    CloseHandle(id->h);
++static int winClose(OsFile **pId){
++  winFile *pFile;
++  if( pId && (pFile = (winFile*)*pId)!=0 ){
++    TRACE2("CLOSE %d\n", pFile->h);
++    CloseHandle(pFile->h);
++#if OS_WINCE
++    winceDestroyLock(pFile);
++    if( pFile->zDeleteOnClose ){
++      DeleteFileW(pFile->zDeleteOnClose);
++      sqliteFree(pFile->zDeleteOnClose);
++    }
++#endif
+     OpenCounter(-1);
+-    id->isOpen = 0;
++    sqliteFree(pFile);
++    *pId = 0;
+   }
+   return SQLITE_OK;
+ }
+@@ -428,12 +821,12 @@
+ ** bytes were read successfully and SQLITE_IOERR if anything goes
+ ** wrong.
+ */
+-int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
++static int winRead(OsFile *id, void *pBuf, int amt){
+   DWORD got;
+-  assert( id->isOpen );
++  assert( id!=0 );
+   SimulateIOError(SQLITE_IOERR);
+-  TRACE3("READ %d lock=%d\n", id->h, id->locktype);
+-  if( !ReadFile(id->h, pBuf, amt, &got, 0) ){
++  TRACE3("READ %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype);
++  if( !ReadFile(((winFile*)id)->h, pBuf, amt, &got, 0) ){
+     got = 0;
+   }
+   if( got==(DWORD)amt ){
+@@ -447,15 +840,16 @@
+ ** Write data from a buffer into a file.  Return SQLITE_OK on success
+ ** or some other error code on failure.
+ */
+-int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
++static int winWrite(OsFile *id, const void *pBuf, int amt){
+   int rc = 0;
+   DWORD wrote;
+-  assert( id->isOpen );
++  assert( id!=0 );
+   SimulateIOError(SQLITE_IOERR);
+   SimulateDiskfullError;
+-  TRACE3("WRITE %d lock=%d\n", id->h, id->locktype);
++  TRACE3("WRITE %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype);
+   assert( amt>0 );
+-  while( amt>0 && (rc = WriteFile(id->h, pBuf, amt, &wrote, 0))!=0 && wrote>0 ){
++  while( amt>0 && (rc = WriteFile(((winFile*)id)->h, pBuf, amt, &wrote, 0))!=0
++         && wrote>0 ){
+     amt -= wrote;
+     pBuf = &((char*)pBuf)[wrote];
+   }
+@@ -475,17 +869,17 @@
+ /*
+ ** Move the read/write pointer in a file.
+ */
+-int sqlite3OsSeek(OsFile *id, i64 offset){
++static int winSeek(OsFile *id, i64 offset){
+   LONG upperBits = offset>>32;
+   LONG lowerBits = offset & 0xffffffff;
+   DWORD rc;
+-  assert( id->isOpen );
++  assert( id!=0 );
+ #ifdef SQLITE_TEST
+   if( offset ) SimulateDiskfullError
+ #endif
+   SEEK(offset/1024 + 1);
+-  rc = SetFilePointer(id->h, lowerBits, &upperBits, FILE_BEGIN);
+-  TRACE3("SEEK %d %lld\n", id->h, offset);
++  rc = SetFilePointer(((winFile*)id)->h, lowerBits, &upperBits, FILE_BEGIN);
++  TRACE3("SEEK %d %lld\n", ((winFile*)id)->h, offset);
+   if( rc==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR ){
+     return SQLITE_FULL;
+   }
+@@ -495,10 +889,10 @@
+ /*
+ ** Make sure all writes to a particular file are committed to disk.
+ */
+-int sqlite3OsSync(OsFile *id, int dataOnly){
+-  assert( id->isOpen );
+-  TRACE3("SYNC %d lock=%d\n", id->h, id->locktype);
+-  if( FlushFileBuffers(id->h) ){
++static int winSync(OsFile *id, int dataOnly){
++  assert( id!=0 );
++  TRACE3("SYNC %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype);
++  if( FlushFileBuffers(((winFile*)id)->h) ){
+     return SQLITE_OK;
+   }else{
+     return SQLITE_IOERR;
+@@ -509,7 +903,7 @@
+ ** Sync the directory zDirname. This is a no-op on operating systems other
+ ** than UNIX.
+ */
+-int sqlite3OsSyncDirectory(const char *zDirname){
++int sqlite3WinSyncDirectory(const char *zDirname){
+   SimulateIOError(SQLITE_IOERR);
+   return SQLITE_OK;
+ }
+@@ -517,34 +911,41 @@
+ /*
+ ** Truncate an open file to a specified size
+ */
+-int sqlite3OsTruncate(OsFile *id, i64 nByte){
++static int winTruncate(OsFile *id, i64 nByte){
+   LONG upperBits = nByte>>32;
+-  assert( id->isOpen );
+-  TRACE3("TRUNCATE %d %lld\n", id->h, nByte);
++  assert( id!=0 );
++  TRACE3("TRUNCATE %d %lld\n", ((winFile*)id)->h, nByte);
+   SimulateIOError(SQLITE_IOERR);
+-  SetFilePointer(id->h, nByte, &upperBits, FILE_BEGIN);
+-  SetEndOfFile(id->h);
++  SetFilePointer(((winFile*)id)->h, nByte, &upperBits, FILE_BEGIN);
++  SetEndOfFile(((winFile*)id)->h);
+   return SQLITE_OK;
+ }
+ 
+ /*
+ ** Determine the current size of a file in bytes
+ */
+-int sqlite3OsFileSize(OsFile *id, i64 *pSize){
++static int winFileSize(OsFile *id, i64 *pSize){
+   DWORD upperBits, lowerBits;
+-  assert( id->isOpen );
++  assert( id!=0 );
+   SimulateIOError(SQLITE_IOERR);
+-  lowerBits = GetFileSize(id->h, &upperBits);
++  lowerBits = GetFileSize(((winFile*)id)->h, &upperBits);
+   *pSize = (((i64)upperBits)<<32) + lowerBits;
+   return SQLITE_OK;
+ }
+ 
+ /*
++** LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems.
++*/
++#ifndef LOCKFILE_FAIL_IMMEDIATELY
++# define LOCKFILE_FAIL_IMMEDIATELY 1
++#endif
++
++/*
+ ** Acquire a reader lock.
+ ** Different API routines are called depending on whether or not this
+ ** is Win95 or WinNT.
+ */
+-static int getReadLock(OsFile *id){
++static int getReadLock(winFile *id){
+   int res;
+   if( isNT() ){
+     OVERLAPPED ovlp;
+@@ -564,12 +965,12 @@
+ /*
+ ** Undo a readlock
+ */
+-static int unlockReadLock(OsFile *id){
++static int unlockReadLock(winFile *pFile){
+   int res;
+   if( isNT() ){
+-    res = UnlockFile(id->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
++    res = UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
+   }else{
+-    res = UnlockFile(id->h, SHARED_FIRST + id->sharedLockByte, 0, 1, 0);
++    res = UnlockFile(pFile->h, SHARED_FIRST + pFile->sharedLockByte, 0, 1, 0);
+   }
+   return res;
+ }
+@@ -579,7 +980,7 @@
+ ** Check that a given pathname is a directory and is writable 
+ **
+ */
+-int sqlite3OsIsDirWritable(char *zDirname){
++int sqlite3WinIsDirWritable(char *zDirname){
+   int fileAttr;
+   WCHAR *zWide;
+   if( zDirname==0 ) return 0;
+@@ -589,7 +990,11 @@
+     fileAttr = GetFileAttributesW(zWide);
+     sqliteFree(zWide);
+   }else{
++#if OS_WINCE
++    return 0;
++#else
+     fileAttr = GetFileAttributesA(zDirname);
++#endif
+   }
+   if( fileAttr == 0xffffffff ) return 0;
+   if( (fileAttr & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY ){
+@@ -620,45 +1025,46 @@
+ **    RESERVED -> (PENDING) -> EXCLUSIVE
+ **    PENDING -> EXCLUSIVE
+ **
+-** This routine will only increase a lock.  The sqlite3OsUnlock() routine
++** This routine will only increase a lock.  The winUnlock() routine
+ ** erases all locks at once and returns us immediately to locking level 0.
+ ** It is not possible to lower the locking level one step at a time.  You
+ ** must go straight to locking level 0.
+ */
+-int sqlite3OsLock(OsFile *id, int locktype){
++static int winLock(OsFile *id, int locktype){
+   int rc = SQLITE_OK;    /* Return code from subroutines */
+   int res = 1;           /* Result of a windows lock call */
+   int newLocktype;       /* Set id->locktype to this value before exiting */
+   int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */
++  winFile *pFile = (winFile*)id;
+ 
+-  assert( id->isOpen );
++  assert( pFile!=0 );
+   TRACE5("LOCK %d %d was %d(%d)\n",
+-          id->h, locktype, id->locktype, id->sharedLockByte);
++          pFile->h, locktype, pFile->locktype, pFile->sharedLockByte);
+ 
+   /* If there is already a lock of this type or more restrictive on the
+   ** OsFile, do nothing. Don't use the end_lock: exit path, as
+   ** sqlite3OsEnterMutex() hasn't been called yet.
+   */
+-  if( id->locktype>=locktype ){
++  if( pFile->locktype>=locktype ){
+     return SQLITE_OK;
+   }
+ 
+   /* Make sure the locking sequence is correct
+   */
+-  assert( id->locktype!=NO_LOCK || locktype==SHARED_LOCK );
++  assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK );
+   assert( locktype!=PENDING_LOCK );
+-  assert( locktype!=RESERVED_LOCK || id->locktype==SHARED_LOCK );
++  assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK );
+ 
+   /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or
+   ** a SHARED lock.  If we are acquiring a SHARED lock, the acquisition of
+   ** the PENDING_LOCK byte is temporary.
+   */
+-  newLocktype = id->locktype;
+-  if( id->locktype==NO_LOCK
+-   || (locktype==EXCLUSIVE_LOCK && id->locktype==RESERVED_LOCK)
++  newLocktype = pFile->locktype;
++  if( pFile->locktype==NO_LOCK
++   || (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK)
+   ){
+     int cnt = 3;
+-    while( cnt-->0 && (res = LockFile(id->h, PENDING_BYTE, 0, 1, 0))==0 ){
++    while( cnt-->0 && (res = LockFile(pFile->h, PENDING_BYTE, 0, 1, 0))==0 ){
+       /* Try 3 times to get the pending lock.  The pending lock might be
+       ** held by another reader process who will release it momentarily.
+       */
+@@ -671,8 +1077,8 @@
+   /* Acquire a shared lock
+   */
+   if( locktype==SHARED_LOCK && res ){
+-    assert( id->locktype==NO_LOCK );
+-    res = getReadLock(id);
++    assert( pFile->locktype==NO_LOCK );
++    res = getReadLock(pFile);
+     if( res ){
+       newLocktype = SHARED_LOCK;
+     }
+@@ -681,8 +1087,8 @@
+   /* Acquire a RESERVED lock
+   */
+   if( locktype==RESERVED_LOCK && res ){
+-    assert( id->locktype==SHARED_LOCK );
+-    res = LockFile(id->h, RESERVED_BYTE, 0, 1, 0);
++    assert( pFile->locktype==SHARED_LOCK );
++    res = LockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
+     if( res ){
+       newLocktype = RESERVED_LOCK;
+     }
+@@ -698,10 +1104,10 @@
+   /* Acquire an EXCLUSIVE lock
+   */
+   if( locktype==EXCLUSIVE_LOCK && res ){
+-    assert( id->locktype>=SHARED_LOCK );
+-    res = unlockReadLock(id);
++    assert( pFile->locktype>=SHARED_LOCK );
++    res = unlockReadLock(pFile);
+     TRACE2("unreadlock = %d\n", res);
+-    res = LockFile(id->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
++    res = LockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
+     if( res ){
+       newLocktype = EXCLUSIVE_LOCK;
+     }else{
+@@ -713,7 +1119,7 @@
+   ** release it now.
+   */
+   if( gotPendingLock && locktype==SHARED_LOCK ){
+-    UnlockFile(id->h, PENDING_BYTE, 0, 1, 0);
++    UnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0);
+   }
+ 
+   /* Update the state of the lock has held in the file descriptor then
+@@ -722,11 +1128,11 @@
+   if( res ){
+     rc = SQLITE_OK;
+   }else{
+-    TRACE4("LOCK FAILED %d trying for %d but got %d\n", id->h,
++    TRACE4("LOCK FAILED %d trying for %d but got %d\n", pFile->h,
+            locktype, newLocktype);
+     rc = SQLITE_BUSY;
+   }
+-  id->locktype = newLocktype;
++  pFile->locktype = newLocktype;
+   return rc;
+ }
+ 
+@@ -735,19 +1141,20 @@
+ ** file by this or any other process. If such a lock is held, return
+ ** non-zero, otherwise zero.
+ */
+-int sqlite3OsCheckReservedLock(OsFile *id){
++static int winCheckReservedLock(OsFile *id){
+   int rc;
+-  assert( id->isOpen );
+-  if( id->locktype>=RESERVED_LOCK ){
++  winFile *pFile = (winFile*)id;
++  assert( pFile!=0 );
++  if( pFile->locktype>=RESERVED_LOCK ){
+     rc = 1;
+-    TRACE3("TEST WR-LOCK %d %d (local)\n", id->h, rc);
++    TRACE3("TEST WR-LOCK %d %d (local)\n", pFile->h, rc);
+   }else{
+-    rc = LockFile(id->h, RESERVED_BYTE, 0, 1, 0);
++    rc = LockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
+     if( rc ){
+-      UnlockFile(id->h, RESERVED_BYTE, 0, 1, 0);
++      UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
+     }
+     rc = !rc;
+-    TRACE3("TEST WR-LOCK %d %d (remote)\n", id->h, rc);
++    TRACE3("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc);
+   }
+   return rc;
+ }
+@@ -763,32 +1170,33 @@
+ ** is NO_LOCK.  If the second argument is SHARED_LOCK then this routine
+ ** might return SQLITE_IOERR;
+ */
+-int sqlite3OsUnlock(OsFile *id, int locktype){
++static int winUnlock(OsFile *id, int locktype){
+   int type;
+   int rc = SQLITE_OK;
+-  assert( id->isOpen );
++  winFile *pFile = (winFile*)id;
++  assert( pFile!=0 );
+   assert( locktype<=SHARED_LOCK );
+-  TRACE5("UNLOCK %d to %d was %d(%d)\n", id->h, locktype,
+-          id->locktype, id->sharedLockByte);
+-  type = id->locktype;
++  TRACE5("UNLOCK %d to %d was %d(%d)\n", pFile->h, locktype,
++          pFile->locktype, pFile->sharedLockByte);
++  type = pFile->locktype;
+   if( type>=EXCLUSIVE_LOCK ){
+-    UnlockFile(id->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
+-    if( locktype==SHARED_LOCK && !getReadLock(id) ){
++    UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
++    if( locktype==SHARED_LOCK && !getReadLock(pFile) ){
+       /* This should never happen.  We should always be able to
+       ** reacquire the read lock */
+       rc = SQLITE_IOERR;
+     }
+   }
+   if( type>=RESERVED_LOCK ){
+-    UnlockFile(id->h, RESERVED_BYTE, 0, 1, 0);
++    UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
+   }
+   if( locktype==NO_LOCK && type>=SHARED_LOCK ){
+-    unlockReadLock(id);
++    unlockReadLock(pFile);
+   }
+   if( type>=PENDING_LOCK ){
+-    UnlockFile(id->h, PENDING_BYTE, 0, 1, 0);
++    UnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0);
+   }
+-  id->locktype = locktype;
++  pFile->locktype = locktype;
+   return rc;
+ }
+ 
+@@ -798,17 +1206,21 @@
+ ** The calling function is responsible for freeing this space once it
+ ** is no longer needed.
+ */
+-char *sqlite3OsFullPathname(const char *zRelative){
+-  char *zNotUsed;
++char *sqlite3WinFullPathname(const char *zRelative){
+   char *zFull;
+-  WCHAR *zWide;
++#if defined(__CYGWIN__)
+   int nByte;
+-#ifdef __CYGWIN__
+   nByte = strlen(zRelative) + MAX_PATH + 1001;
+   zFull = sqliteMalloc( nByte );
+   if( zFull==0 ) return 0;
+   if( cygwin_conv_to_full_win32_path(zRelative, zFull) ) return 0;
++#elif OS_WINCE
++  /* WinCE has no concept of a relative pathname, or so I am told. */
++  zFull = sqliteStrDup(zRelative);
+ #else
++  char *zNotUsed;
++  WCHAR *zWide;
++  int nByte;
+   zWide = utf8ToUnicode(zRelative);
+   if( zWide ){
+     WCHAR *zTemp, *zNotUsedW;
+@@ -829,6 +1241,76 @@
+   return zFull;
+ }
+ 
++/*
++** The fullSync option is meaningless on windows.   This is a no-op.
++*/
++static void winSetFullSync(OsFile *id, int v){
++  return;
++}
++
++/*
++** Return the underlying file handle for an OsFile
++*/
++static int winFileHandle(OsFile *id){
++  return (int)((winFile*)id)->h;
++}
++
++/*
++** Return an integer that indices the type of lock currently held
++** by this handle.  (Used for testing and analysis only.)
++*/
++static int winLockState(OsFile *id){
++  return ((winFile*)id)->locktype;
++}
++
++/*
++** This vector defines all the methods that can operate on an OsFile
++** for win32.
++*/
++static const IoMethod sqlite3WinIoMethod = {
++  winClose,
++  winOpenDirectory,
++  winRead,
++  winWrite,
++  winSeek,
++  winTruncate,
++  winSync,
++  winSetFullSync,
++  winFileHandle,
++  winFileSize,
++  winLock,
++  winUnlock,
++  winLockState,
++  winCheckReservedLock,
++};
++
++/*
++** Allocate memory for an OsFile.  Initialize the new OsFile
++** to the value given in pInit and return a pointer to the new
++** OsFile.  If we run out of memory, close the file and return NULL.
++*/
++static int allocateWinFile(winFile *pInit, OsFile **pId){
++  winFile *pNew;
++  pNew = sqliteMalloc( sizeof(*pNew) );
++  if( pNew==0 ){
++    CloseHandle(pInit->h);
++#if OS_WINCE
++    sqliteFree(pInit->zDeleteOnClose);
++#endif
++    *pId = 0;
++    return SQLITE_NOMEM;
++  }else{
++    *pNew = *pInit;
++    pNew->pMethod = &sqlite3WinIoMethod;
++    pNew->locktype = NO_LOCK;
++    pNew->sharedLockByte = 0;
++    *pId = (OsFile*)pNew;
++    OpenCounter(+1);
++    return SQLITE_OK;
++  }
++}
++
++
+ #endif /* SQLITE_OMIT_DISKIO */
+ /***************************************************************************
+ ** Everything above deals with file I/O.  Everything that follows deals
+@@ -840,7 +1322,7 @@
+ ** is written into the buffer zBuf[256].  The calling function must
+ ** supply a sufficiently large buffer.
+ */
+-int sqlite3OsRandomSeed(char *zBuf){
++int sqlite3WinRandomSeed(char *zBuf){
+   /* We have to initialize zBuf to prevent valgrind from reporting
+   ** errors.  The reports issued by valgrind are incorrect - we would
+   ** prefer that the randomness be increased by making use of the
+@@ -861,7 +1343,7 @@
+ /*
+ ** Sleep for a little while.  Return the amount of time slept.
+ */
+-int sqlite3OsSleep(int ms){
++int sqlite3WinSleep(int ms){
+   Sleep(ms);
+   return ms;
+ }
+@@ -871,18 +1353,22 @@
+ */
+ static int inMutex = 0;
+ #ifdef SQLITE_W32_THREADS
++  static DWORD mutexOwner;
+   static CRITICAL_SECTION cs;
+ #endif
+ 
+ /*
+-** The following pair of routine implement mutual exclusion for
++** The following pair of routines implement mutual exclusion for
+ ** multi-threaded processes.  Only a single thread is allowed to
+ ** executed code that is surrounded by EnterMutex() and LeaveMutex().
+ **
+ ** SQLite uses only a single Mutex.  There is not much critical
+ ** code and what little there is executes quickly and without blocking.
++**
++** Version 3.3.1 and earlier used a simple mutex.  Beginning with
++** version 3.3.2, a recursive mutex is required.
+ */
+-void sqlite3OsEnterMutex(){
++void sqlite3WinEnterMutex(){
+ #ifdef SQLITE_W32_THREADS
+   static int isInit = 0;
+   while( !isInit ){
+@@ -895,19 +1381,36 @@
+     }
+   }
+   EnterCriticalSection(&cs);
++  mutexOwner = GetCurrentThreadId();
+ #endif
+-  assert( !inMutex );
+-  inMutex = 1;
++  inMutex++;
+ }
+-void sqlite3OsLeaveMutex(){
++void sqlite3WinLeaveMutex(){
+   assert( inMutex );
+-  inMutex = 0;
++  inMutex--;
+ #ifdef SQLITE_W32_THREADS
++  assert( mutexOwner==GetCurrentThreadId() );
+   LeaveCriticalSection(&cs);
+ #endif
+ }
+ 
+ /*
++** Return TRUE if the mutex is currently held.
++**
++** If the thisThreadOnly parameter is true, return true if and only if the
++** calling thread holds the mutex.  If the parameter is false, return
++** true if any thread holds the mutex.
++*/
++int sqlite3WinInMutex(int thisThreadOnly){
++#ifdef SQLITE_W32_THREADS
++  return inMutex>0 && (thisThreadOnly==0 || mutexOwner==GetCurrentThreadId());
++#else
++  return inMutex>0;
++#endif
++}
++
++
++/*
+ ** The following variable, if set to a non-zero value, becomes the result
+ ** returned from sqlite3OsCurrentTime().  This is used for testing.
+ */
+@@ -920,13 +1423,19 @@
+ ** current time and date as a Julian Day number into *prNow and
+ ** return 0.  Return 1 if the time and date cannot be found.
+ */
+-int sqlite3OsCurrentTime(double *prNow){
++int sqlite3WinCurrentTime(double *prNow){
+   FILETIME ft;
+   /* FILETIME structure is a 64-bit value representing the number of 
+      100-nanosecond intervals since January 1, 1601 (= JD 2305813.5). 
+   */
+   double now;
++#if OS_WINCE
++  SYSTEMTIME time;
++  GetSystemTime(&time);
++  SystemTimeToFileTime(&time,&ft);
++#else
+   GetSystemTimeAsFileTime( &ft );
++#endif
+   now = ((double)ft.dwHighDateTime) * 4294967296.0; 
+   *prNow = (now + ft.dwLowDateTime)/864000000000.0 + 2305813.5;
+ #ifdef SQLITE_TEST
+@@ -937,4 +1446,71 @@
+   return 0;
+ }
+ 
++/*
++** Remember the number of thread-specific-data blocks allocated.
++** Use this to verify that we are not leaking thread-specific-data.
++** Ticket #1601
++*/
++#ifdef SQLITE_TEST
++int sqlite3_tsd_count = 0;
++# define TSD_COUNTER_INCR InterlockedIncrement(&sqlite3_tsd_count)
++# define TSD_COUNTER_DECR InterlockedDecrement(&sqlite3_tsd_count)
++#else
++# define TSD_COUNTER_INCR  /* no-op */
++# define TSD_COUNTER_DECR  /* no-op */
++#endif
++
++
++
++/*
++** If called with allocateFlag>1, then return a pointer to thread
++** specific data for the current thread.  Allocate and zero the
++** thread-specific data if it does not already exist necessary.
++**
++** If called with allocateFlag==0, then check the current thread
++** specific data.  Return it if it exists.  If it does not exist,
++** then return NULL.
++**
++** If called with allocateFlag<0, check to see if the thread specific
++** data is allocated and is all zero.  If it is then deallocate it.
++** Return a pointer to the thread specific data or NULL if it is
++** unallocated or gets deallocated.
++*/
++ThreadData *sqlite3WinThreadSpecificData(int allocateFlag){
++  static int key;
++  static int keyInit = 0;
++  static const ThreadData zeroData = {0};
++  ThreadData *pTsd;
++
++  if( !keyInit ){
++    sqlite3OsEnterMutex();
++    if( !keyInit ){
++      key = TlsAlloc();
++      if( key==0xffffffff ){
++        sqlite3OsLeaveMutex();
++        return 0;
++      }
++      keyInit = 1;
++    }
++    sqlite3OsLeaveMutex();
++  }
++  pTsd = TlsGetValue(key);
++  if( allocateFlag>0 ){
++    if( !pTsd ){
++      pTsd = sqlite3OsMalloc( sizeof(zeroData) );
++      if( pTsd ){
++        *pTsd = zeroData;
++        TlsSetValue(key, pTsd);
++        TSD_COUNTER_INCR;
++      }
++    }
++  }else if( pTsd!=0 && allocateFlag<0 
++              && memcmp(pTsd, &zeroData, sizeof(ThreadData))==0 ){
++    sqlite3OsFree(pTsd);
++    TlsSetValue(key, 0);
++    TSD_COUNTER_DECR;
++    pTsd = 0;
++  }
++  return pTsd;
++}
+ #endif /* OS_WIN */
+Index: sqlite/prepare.c
+===================================================================
+--- amarok/src/sqlite/prepare.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/prepare.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -13,7 +13,7 @@
+ ** interface, and routines that contribute to loading the database schema
+ ** from disk.
+ **
+-** $Id: prepare.c,v 1.4 2005/09/10 16:46:13 drh Exp $
++** $Id: prepare.c,v 1.31 2006/02/10 02:27:43 danielk1977 Exp $
+ */
+ #include "sqliteInt.h"
+ #include "os.h"
+@@ -24,7 +24,7 @@
+ ** that the database is corrupt.
+ */
+ static void corruptSchema(InitData *pData, const char *zExtra){
+-  if( !sqlite3_malloc_failed ){
++  if( !sqlite3MallocFailed() ){
+     sqlite3SetString(pData->pzErrMsg, "malformed database schema",
+        zExtra!=0 && zExtra[0]!=0 ? " - " : (char*)0, zExtra, (char*)0);
+   }
+@@ -49,6 +49,10 @@
+   sqlite3 *db = pData->db;
+   int iDb;
+ 
++  if( sqlite3MallocFailed() ){
++    return SQLITE_NOMEM;
++  }
++
+   assert( argc==4 );
+   if( argv==0 ) return 0;   /* Might happen if EMPTY_RESULT_CALLBACKS are on */
+   if( argv[1]==0 || argv[3]==0 ){
+@@ -71,7 +75,11 @@
+     rc = sqlite3_exec(db, argv[2], 0, 0, &zErr);
+     db->init.iDb = 0;
+     if( SQLITE_OK!=rc ){
+-      corruptSchema(pData, zErr);
++      if( rc==SQLITE_NOMEM ){
++        sqlite3FailedMalloc();
++      }else{
++        corruptSchema(pData, zErr);
++      }
+       sqlite3_free(zErr);
+       return rc;
+     }
+@@ -111,6 +119,7 @@
+   BtCursor *curMain;
+   int size;
+   Table *pTab;
++  Db *pDb;
+   char const *azArg[5];
+   char zDbNum[30];
+   int meta[10];
+@@ -145,6 +154,7 @@
+ #endif
+ 
+   assert( iDb>=0 && iDb<db->nDb );
++  assert( db->aDb[iDb].pSchema );
+ 
+   /* zMasterSchema and zInitScript are set to point at the master schema
+   ** and initialisation script appropriate for the database being
+@@ -180,11 +190,14 @@
+ 
+   /* Create a cursor to hold the database open
+   */
+-  if( db->aDb[iDb].pBt==0 ){
+-    if( !OMIT_TEMPDB && iDb==1 ) DbSetProperty(db, 1, DB_SchemaLoaded);
++  pDb = &db->aDb[iDb];
++  if( pDb->pBt==0 ){
++    if( !OMIT_TEMPDB && iDb==1 ){
++      DbSetProperty(db, 1, DB_SchemaLoaded);
++    }
+     return SQLITE_OK;
+   }
+-  rc = sqlite3BtreeCursor(db->aDb[iDb].pBt, MASTER_ROOT, 0, 0, 0, &curMain);
++  rc = sqlite3BtreeCursor(pDb->pBt, MASTER_ROOT, 0, 0, 0, &curMain);
+   if( rc!=SQLITE_OK && rc!=SQLITE_EMPTY ){
+     sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0);
+     return rc;
+@@ -204,13 +217,13 @@
+   **    meta[8]
+   **    meta[9]
+   **
+-  ** Note: The hash defined SQLITE_UTF* symbols in sqliteInt.h correspond to
++  ** Note: The #defined SQLITE_UTF* symbols in sqliteInt.h correspond to
+   ** the possible values of meta[4].
+   */
+   if( rc==SQLITE_OK ){
+     int i;
+     for(i=0; rc==SQLITE_OK && i<sizeof(meta)/sizeof(meta[0]); i++){
+-      rc = sqlite3BtreeGetMeta(db->aDb[iDb].pBt, i+1, (u32 *)&meta[i]);
++      rc = sqlite3BtreeGetMeta(pDb->pBt, i+1, (u32 *)&meta[i]);
+     }
+     if( rc ){
+       sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0);
+@@ -220,7 +233,7 @@
+   }else{
+     memset(meta, 0, sizeof(meta));
+   }
+-  db->aDb[iDb].schema_cookie = meta[0];
++  pDb->pSchema->schema_cookie = meta[0];
+ 
+   /* If opening a non-empty database, check the text encoding. For the
+   ** main database, set sqlite3.enc to the encoding of the main database.
+@@ -229,55 +242,44 @@
+   */
+   if( meta[4] ){  /* text encoding */
+     if( iDb==0 ){
+-      /* If opening the main database, set db->enc. */
+-      db->enc = (u8)meta[4];
+-      db->pDfltColl = sqlite3FindCollSeq(db, db->enc, "BINARY", 6, 0);
++      /* If opening the main database, set ENC(db). */
++      ENC(db) = (u8)meta[4];
++      db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 6, 0);
+     }else{
+-      /* If opening an attached database, the encoding much match db->enc */
+-      if( meta[4]!=db->enc ){
++      /* If opening an attached database, the encoding much match ENC(db) */
++      if( meta[4]!=ENC(db) ){
+         sqlite3BtreeCloseCursor(curMain);
+         sqlite3SetString(pzErrMsg, "attached databases must use the same"
+             " text encoding as main database", (char*)0);
+         return SQLITE_ERROR;
+       }
+     }
++  }else{
++    DbSetProperty(db, iDb, DB_Empty);
+   }
++  pDb->pSchema->enc = ENC(db);
+ 
+   size = meta[2];
+   if( size==0 ){ size = MAX_PAGES; }
+-  db->aDb[iDb].cache_size = size;
++  pDb->pSchema->cache_size = size;
++  sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
+ 
+-  if( iDb==0 ){
+-    db->file_format = meta[1];
+-    if( db->file_format==0 ){
+-      /* This happens if the database was initially empty */
+-      db->file_format = 1;
+-    }
+-
+-    if( db->file_format==2 || db->file_format==3 ){
+-      /* File format 2 is treated exactly as file format 1. New 
+-      ** databases are created with file format 1.
+-      */ 
+-      db->file_format = 1;
+-    }
+-  }
+-
+   /*
+   ** file_format==1    Version 3.0.0.
+-  ** file_format==2    Version 3.1.3.
+-  ** file_format==3    Version 3.1.4.
+-  **
+-  ** Version 3.0 can only use files with file_format==1. Version 3.1.3
+-  ** can read and write files with file_format==1 or file_format==2.
+-  ** Version 3.1.4 can read and write file formats 1, 2 and 3.
++  ** file_format==2    Version 3.1.3.  // ALTER TABLE ADD COLUMN
++  ** file_format==3    Version 3.1.4.  // ditto but with non-NULL defaults
++  ** file_format==4    Version 3.3.0.  // DESC indices.  Boolean constants
+   */
+-  if( meta[1]>3 ){
++  pDb->pSchema->file_format = meta[1];
++  if( pDb->pSchema->file_format==0 ){
++    pDb->pSchema->file_format = 1;
++  }
++  if( pDb->pSchema->file_format>SQLITE_MAX_FILE_FORMAT ){
+     sqlite3BtreeCloseCursor(curMain);
+     sqlite3SetString(pzErrMsg, "unsupported file format", (char*)0);
+     return SQLITE_ERROR;
+   }
+ 
+-  sqlite3BtreeSetCacheSize(db->aDb[iDb].pBt, db->aDb[iDb].cache_size);
+ 
+   /* Read the schema information out of the schema tables
+   */
+@@ -301,8 +303,8 @@
+ #endif
+     sqlite3BtreeCloseCursor(curMain);
+   }
+-  if( sqlite3_malloc_failed ){
+-    sqlite3SetString(pzErrMsg, "out of memory", (char*)0);
++  if( sqlite3MallocFailed() ){
++    /* sqlite3SetString(pzErrMsg, "out of memory", (char*)0); */
+     rc = SQLITE_NOMEM;
+     sqlite3ResetInternalSchema(db, 0);
+   }
+@@ -320,14 +322,15 @@
+ ** created using ATTACH statements.  Return a success code.  If an
+ ** error occurs, write an error message into *pzErrMsg.
+ **
+-** After the database is initialized, the SQLITE_Initialized
+-** bit is set in the flags field of the sqlite structure. 
++** After a database is initialized, the DB_SchemaLoaded bit is set
++** bit is set in the flags field of the Db structure. If the database
++** file was of zero-length, then the DB_Empty flag is also set.
+ */
+ int sqlite3Init(sqlite3 *db, char **pzErrMsg){
+   int i, rc;
++  int called_initone = 0;
+   
+   if( db->init.busy ) return SQLITE_OK;
+-  assert( (db->flags & SQLITE_Initialized)==0 );
+   rc = SQLITE_OK;
+   db->init.busy = 1;
+   for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
+@@ -336,6 +339,7 @@
+     if( rc ){
+       sqlite3ResetInternalSchema(db, i);
+     }
++    called_initone = 1;
+   }
+ 
+   /* Once all the other databases have been initialised, load the schema
+@@ -348,19 +352,16 @@
+     if( rc ){
+       sqlite3ResetInternalSchema(db, 1);
+     }
++    called_initone = 1;
+   }
+ #endif
+ 
+   db->init.busy = 0;
+-  if( rc==SQLITE_OK ){
+-    db->flags |= SQLITE_Initialized;
++  if( rc==SQLITE_OK && called_initone ){
+     sqlite3CommitInternalChanges(db);
+   }
+ 
+-  if( rc!=SQLITE_OK ){
+-    db->flags &= ~SQLITE_Initialized;
+-  }
+-  return rc;
++  return rc; 
+ }
+ 
+ /*
+@@ -371,11 +372,8 @@
+   int rc = SQLITE_OK;
+   sqlite3 *db = pParse->db;
+   if( !db->init.busy ){
+-    if( (db->flags & SQLITE_Initialized)==0 ){
+-      rc = sqlite3Init(db, &pParse->zErrMsg);
+-    }
++    rc = sqlite3Init(db, &pParse->zErrMsg);
+   }
+-  assert( rc!=SQLITE_OK || (db->flags & SQLITE_Initialized) || db->init.busy );
+   if( rc!=SQLITE_OK ){
+     pParse->rc = rc;
+     pParse->nErr++;
+@@ -402,7 +400,7 @@
+     rc = sqlite3BtreeCursor(pBt, MASTER_ROOT, 0, 0, 0, &curTemp);
+     if( rc==SQLITE_OK ){
+       rc = sqlite3BtreeGetMeta(pBt, 1, (u32 *)&cookie);
+-      if( rc==SQLITE_OK && cookie!=db->aDb[iDb].schema_cookie ){
++      if( rc==SQLITE_OK && cookie!=db->aDb[iDb].pSchema->schema_cookie ){
+         allOk = 0;
+       }
+       sqlite3BtreeCloseCursor(curTemp);
+@@ -412,6 +410,88 @@
+ }
+ 
+ /*
++** Free all resources held by the schema structure. The void* argument points
++** at a Schema struct. This function does not call sqliteFree() on the 
++** pointer itself, it just cleans up subsiduary resources (i.e. the contents
++** of the schema hash tables).
++*/
++void sqlite3SchemaFree(void *p){
++  Hash temp1;
++  Hash temp2;
++  HashElem *pElem;
++  Schema *pSchema = (Schema *)p;
++
++  temp1 = pSchema->tblHash;
++  temp2 = pSchema->trigHash;
++  sqlite3HashInit(&pSchema->trigHash, SQLITE_HASH_STRING, 0);
++  sqlite3HashClear(&pSchema->aFKey);
++  sqlite3HashClear(&pSchema->idxHash);
++  for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
++    sqlite3DeleteTrigger((Trigger*)sqliteHashData(pElem));
++  }
++  sqlite3HashClear(&temp2);
++  sqlite3HashInit(&pSchema->tblHash, SQLITE_HASH_STRING, 0);
++  for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
++    Table *pTab = sqliteHashData(pElem);
++    sqlite3DeleteTable(0, pTab);
++  }
++  sqlite3HashClear(&temp1);
++  pSchema->pSeqTab = 0;
++  pSchema->flags &= ~DB_SchemaLoaded;
++}
++
++/*
++** Find and return the schema associated with a BTree.  Create
++** a new one if necessary.
++*/
++Schema *sqlite3SchemaGet(Btree *pBt){
++  Schema * p;
++  if( pBt ){
++    p = (Schema *)sqlite3BtreeSchema(pBt,sizeof(Schema),sqlite3SchemaFree);
++  }else{
++    p = (Schema *)sqliteMalloc(sizeof(Schema));
++  }
++  if( p && 0==p->file_format ){
++    sqlite3HashInit(&p->tblHash, SQLITE_HASH_STRING, 0);
++    sqlite3HashInit(&p->idxHash, SQLITE_HASH_STRING, 0);
++    sqlite3HashInit(&p->trigHash, SQLITE_HASH_STRING, 0);
++    sqlite3HashInit(&p->aFKey, SQLITE_HASH_STRING, 1);
++  }
++  return p;
++}
++
++/*
++** Convert a schema pointer into the iDb index that indicates
++** which database file in db->aDb[] the schema refers to.
++**
++** If the same database is attached more than once, the first
++** attached database is returned.
++*/
++int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
++  int i = -1000000;
++
++  /* If pSchema is NULL, then return -1000000. This happens when code in 
++  ** expr.c is trying to resolve a reference to a transient table (i.e. one
++  ** created by a sub-select). In this case the return value of this 
++  ** function should never be used.
++  **
++  ** We return -1000000 instead of the more usual -1 simply because using
++  ** -1000000 as incorrectly using -1000000 index into db->aDb[] is much 
++  ** more likely to cause a segfault than -1 (of course there are assert()
++  ** statements too, but it never hurts to play the odds).
++  */
++  if( pSchema ){
++    for(i=0; i<db->nDb; i++){
++      if( db->aDb[i].pSchema==pSchema ){
++        break;
++      }
++    }
++    assert( i>=0 &&i>=0 &&  i<db->nDb );
++  }
++  return i;
++}
++
++/*
+ ** Compile the UTF-8 encoded SQL statement zSql into a statement handle.
+ */
+ int sqlite3_prepare(
+@@ -424,10 +504,10 @@
+   Parse sParse;
+   char *zErrMsg = 0;
+   int rc = SQLITE_OK;
++  int i;
+ 
+-  if( sqlite3_malloc_failed ){
+-    return SQLITE_NOMEM;
+-  }
++  /* Assert that malloc() has not failed */
++  assert( !sqlite3MallocFailed() );
+ 
+   assert( ppStmt );
+   *ppStmt = 0;
+@@ -435,19 +515,35 @@
+     return SQLITE_MISUSE;
+   }
+ 
++  /* If any attached database schemas are locked, do not proceed with
++  ** compilation. Instead return SQLITE_LOCKED immediately.
++  */
++  for(i=0; i<db->nDb; i++) {
++    Btree *pBt = db->aDb[i].pBt;
++    if( pBt && sqlite3BtreeSchemaLocked(pBt) ){
++      const char *zDb = db->aDb[i].zName;
++      sqlite3Error(db, SQLITE_LOCKED, "database schema is locked: %s", zDb);
++      sqlite3SafetyOff(db);
++      return SQLITE_LOCKED;
++    }
++  }
++  
+   memset(&sParse, 0, sizeof(sParse));
+   sParse.db = db;
+-  sqlite3RunParser(&sParse, zSql, &zErrMsg);
++  if( nBytes>=0 && zSql[nBytes]!=0 ){
++    char *zSqlCopy = sqlite3StrNDup(zSql, nBytes);
++    sqlite3RunParser(&sParse, zSqlCopy, &zErrMsg);
++    sParse.zTail += zSql - zSqlCopy;
++    sqliteFree(zSqlCopy);
++  }else{
++    sqlite3RunParser(&sParse, zSql, &zErrMsg);
++  }
+ 
+-  if( sqlite3_malloc_failed ){
+-    rc = SQLITE_NOMEM;
+-    sqlite3RollbackAll(db);
+-    sqlite3ResetInternalSchema(db, 0);
+-    db->flags &= ~SQLITE_InTrans;
+-    goto prepare_out;
++  if( sqlite3MallocFailed() ){
++    sParse.rc = SQLITE_NOMEM;
+   }
+   if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK;
+-  if( sParse.rc!=SQLITE_OK && sParse.checkSchema && !schemaIsValid(db) ){
++  if( sParse.checkSchema && !schemaIsValid(db) ){
+     sParse.rc = SQLITE_SCHEMA;
+   }
+   if( sParse.rc==SQLITE_SCHEMA ){
+@@ -460,21 +556,20 @@
+   if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){
+     if( sParse.explain==2 ){
+       sqlite3VdbeSetNumCols(sParse.pVdbe, 3);
+-      sqlite3VdbeSetColName(sParse.pVdbe, 0, "order", P3_STATIC);
+-      sqlite3VdbeSetColName(sParse.pVdbe, 1, "from", P3_STATIC);
+-      sqlite3VdbeSetColName(sParse.pVdbe, 2, "detail", P3_STATIC);
++      sqlite3VdbeSetColName(sParse.pVdbe, 0, COLNAME_NAME, "order", P3_STATIC);
++      sqlite3VdbeSetColName(sParse.pVdbe, 1, COLNAME_NAME, "from", P3_STATIC);
++      sqlite3VdbeSetColName(sParse.pVdbe, 2, COLNAME_NAME, "detail", P3_STATIC);
+     }else{
+       sqlite3VdbeSetNumCols(sParse.pVdbe, 5);
+-      sqlite3VdbeSetColName(sParse.pVdbe, 0, "addr", P3_STATIC);
+-      sqlite3VdbeSetColName(sParse.pVdbe, 1, "opcode", P3_STATIC);
+-      sqlite3VdbeSetColName(sParse.pVdbe, 2, "p1", P3_STATIC);
+-      sqlite3VdbeSetColName(sParse.pVdbe, 3, "p2", P3_STATIC);
+-      sqlite3VdbeSetColName(sParse.pVdbe, 4, "p3", P3_STATIC);
++      sqlite3VdbeSetColName(sParse.pVdbe, 0, COLNAME_NAME, "addr", P3_STATIC);
++      sqlite3VdbeSetColName(sParse.pVdbe, 1, COLNAME_NAME, "opcode", P3_STATIC);
++      sqlite3VdbeSetColName(sParse.pVdbe, 2, COLNAME_NAME, "p1", P3_STATIC);
++      sqlite3VdbeSetColName(sParse.pVdbe, 3, COLNAME_NAME, "p2", P3_STATIC);
++      sqlite3VdbeSetColName(sParse.pVdbe, 4, COLNAME_NAME, "p3", P3_STATIC);
+     }
+   } 
+ #endif
+ 
+-prepare_out:
+   if( sqlite3SafetyOff(db) ){
+     rc = SQLITE_MISUSE;
+   }
+@@ -490,6 +585,9 @@
+   }else{
+     sqlite3Error(db, rc, 0);
+   }
++
++  rc = sqlite3ApiExit(db, rc);
++  sqlite3ReleaseThreadData();
+   return rc;
+ }
+ 
+@@ -508,22 +606,17 @@
+   ** encoded string to UTF-8, then invoking sqlite3_prepare(). The
+   ** tricky bit is figuring out the pointer to return in *pzTail.
+   */
+-  char const *zSql8 = 0;
+-  char const *zTail8 = 0;
+-  int rc;
+-  sqlite3_value *pTmp;
++  char *zSql8;
++  const char *zTail8 = 0;
++  int rc = SQLITE_OK;
+ 
+   if( sqlite3SafetyCheck(db) ){
+     return SQLITE_MISUSE;
+   }
+-  pTmp = sqlite3GetTransientValue(db);
+-  sqlite3ValueSetStr(pTmp, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC);
+-  zSql8 = sqlite3ValueText(pTmp, SQLITE_UTF8);
+-  if( !zSql8 ){
+-    sqlite3Error(db, SQLITE_NOMEM, 0);
+-    return SQLITE_NOMEM;
++  zSql8 = sqlite3utf16to8(zSql, nBytes);
++  if( zSql8 ){
++    rc = sqlite3_prepare(db, zSql8, -1, ppStmt, &zTail8);
+   }
+-  rc = sqlite3_prepare(db, zSql8, -1, ppStmt, &zTail8);
+ 
+   if( zTail8 && pzTail ){
+     /* If sqlite3_prepare returns a tail pointer, we calculate the
+@@ -534,7 +627,7 @@
+     int chars_parsed = sqlite3utf8CharLen(zSql8, zTail8-zSql8);
+     *pzTail = (u8 *)zSql + sqlite3utf16ByteLen(zSql, chars_parsed);
+   }
+- 
+-  return rc;
++  sqliteFree(zSql8); 
++  return sqlite3ApiExit(db, rc);
+ }
+ #endif /* SQLITE_OMIT_UTF16 */
+Index: sqlite/vdbeaux.c
+===================================================================
+--- amarok/src/sqlite/vdbeaux.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/vdbeaux.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -58,8 +58,14 @@
+ /*
+ ** Resize the Vdbe.aOp array so that it contains at least N
+ ** elements. If the Vdbe is in VDBE_MAGIC_RUN state, then
+-** the Vdbe.aOp array will be sized to contain exactly N 
+-** elements.
++** the Vdbe.aOp array will be sized to contain exactly N
++** elements. Vdbe.nOpAlloc is set to reflect the new size of
++** the array.
++**
++** If an out-of-memory error occurs while resizing the array,
++** Vdbe.aOp and Vdbe.nOpAlloc remain unchanged (this is so that
++** any opcodes already allocated can be correctly deallocated
++** along with the rest of the Vdbe).
+ */
+ static void resizeOpArray(Vdbe *p, int N){
+   int runMode = p->magic==VDBE_MAGIC_RUN;
+@@ -102,7 +108,7 @@
+   p->nOp++;
+   assert( p->magic==VDBE_MAGIC_INIT );
+   resizeOpArray(p, i+1);
+-  if( sqlite3_malloc_failed ){
++  if( sqlite3MallocFailed() ){
+     return 0;
+   }
+   pOp = &p->aOp[i];
+@@ -147,7 +153,7 @@
+   assert( p->magic==VDBE_MAGIC_INIT );
+   if( i>=p->nLabelAlloc ){
+     p->nLabelAlloc = p->nLabelAlloc*2 + 10;
+-    sqlite3ReallocOrFree((void**)&p->aLabel,
++    sqliteReallocOrFree((void**)&p->aLabel,
+                           p->nLabelAlloc*sizeof(p->aLabel[0]));
+   }
+   if( p->aLabel ){
+@@ -202,6 +208,7 @@
+     NOPUSH_MASK_6 + (NOPUSH_MASK_7<<16),
+     NOPUSH_MASK_8 + (NOPUSH_MASK_9<<16)
+   };
++  assert( op<32*5 );
+   return (masks[op>>5] & (1<<(op&0x1F)));
+ }
+ 
+@@ -300,7 +307,7 @@
+   int addr;
+   assert( p->magic==VDBE_MAGIC_INIT );
+   resizeOpArray(p, p->nOp + nOp);
+-  if( sqlite3_malloc_failed ){
++  if( sqlite3MallocFailed() ){
+     return 0;
+   }
+   addr = p->nOp;
+@@ -414,8 +421,10 @@
+ void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
+   Op *pOp;
+   assert( p->magic==VDBE_MAGIC_INIT );
+-  if( p==0 || p->aOp==0 ){
+-    freeP3(n, (void*)*(char**)&zP3);
++  if( p==0 || p->aOp==0 || sqlite3MallocFailed() ){
++    if (n != P3_KEYINFO) {
++      freeP3(n, (void*)*(char**)&zP3);
++    }
+     return;
+   }
+   if( addr<0 || addr>=p->nOp ){
+@@ -432,16 +441,18 @@
+     KeyInfo *pKeyInfo;
+     int nField, nByte;
+ 
+-    /* KeyInfo structures that include an KeyInfo.aSortOrder are always
+-    ** sent in using P3_KEYINFO_HANDOFF.  The KeyInfo.aSortOrder array
+-    ** is not duplicated when P3_KEYINFO is used. */
+-    /* assert( pKeyInfo->aSortOrder==0 ); */
+     nField = ((KeyInfo*)zP3)->nField;
+-    nByte = sizeof(*pKeyInfo) + (nField-1)*sizeof(pKeyInfo->aColl[0]);
++    nByte = sizeof(*pKeyInfo) + (nField-1)*sizeof(pKeyInfo->aColl[0]) + nField;
+     pKeyInfo = sqliteMallocRaw( nByte );
+     pOp->p3 = (char*)pKeyInfo;
+     if( pKeyInfo ){
++      unsigned char *aSortOrder;
+       memcpy(pKeyInfo, zP3, nByte);
++      aSortOrder = pKeyInfo->aSortOrder;
++      if( aSortOrder ){
++        pKeyInfo->aSortOrder = (unsigned char*)&pKeyInfo->aColl[nField];
++        memcpy(pKeyInfo->aSortOrder, aSortOrder, nField);
++      }
+       pOp->p3type = P3_KEYINFO;
+     }else{
+       pOp->p3type = P3_NOTUSED;
+@@ -467,7 +478,8 @@
+ void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){
+   va_list ap;
+   assert( p->nOp>0 );
+-  assert( p->aOp==0 || p->aOp[p->nOp-1].p3==0 );
++  assert( p->aOp==0 || p->aOp[p->nOp-1].p3==0 
++          || sqlite3MallocFailed() );
+   va_start(ap, zFormat);
+   sqlite3VdbeChangeP3(p, -1, sqlite3VMPrintf(zFormat, ap), P3_DYNAMIC);
+   va_end(ap);
+@@ -733,7 +745,7 @@
+       + nMem*sizeof(Mem)               /* aMem */
+       + nCursor*sizeof(Cursor*)        /* apCsr */
+     );
+-    if( !sqlite3_malloc_failed ){
++    if( !sqlite3MallocFailed() ){
+       p->aMem = &p->aStack[nStack];
+       p->nMem = nMem;
+       p->aVar = &p->aMem[nMem];
+@@ -777,6 +789,8 @@
+   p->explain |= isExplain;
+   p->magic = VDBE_MAGIC_RUN;
+   p->nChange = 0;
++  p->cacheCtr = 1;
++  p->minWriteFileFormat = 255;
+ #ifdef VDBE_PROFILE
+   {
+     int i;
+@@ -857,9 +871,10 @@
+ void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){
+   Mem *pColName;
+   int n;
+-  assert( 0==p->nResColumn );
++  releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
++  sqliteFree(p->aColName);
++  n = nResColumn*COLNAME_N;
+   p->nResColumn = nResColumn;
+-  n = nResColumn*2;
+   p->aColName = pColName = (Mem*)sqliteMalloc( sizeof(Mem)*n );
+   if( p->aColName==0 ) return;
+   while( n-- > 0 ){
+@@ -878,13 +893,14 @@
+ ** the string is freed using sqliteFree() when the vdbe is finished with
+ ** it. Otherwise, N bytes of zName are copied.
+ */
+-int sqlite3VdbeSetColName(Vdbe *p, int idx, const char *zName, int N){
++int sqlite3VdbeSetColName(Vdbe *p, int idx, int var, const char *zName, int N){
+   int rc;
+   Mem *pColName;
+-  assert( idx<(2*p->nResColumn) );
+-  if( sqlite3_malloc_failed ) return SQLITE_NOMEM;
++  assert( idx<p->nResColumn );
++  assert( var<COLNAME_N );
++  if( sqlite3MallocFailed() ) return SQLITE_NOMEM;
+   assert( p->aColName!=0 );
+-  pColName = &(p->aColName[idx]);
++  pColName = &(p->aColName[idx+var*p->nResColumn]);
+   if( N==P3_DYNAMIC || N==P3_STATIC ){
+     rc = sqlite3VdbeMemSetStr(pColName, zName, -1, SQLITE_UTF8, SQLITE_STATIC);
+   }else{
+@@ -919,7 +935,6 @@
+ 
+   /* If there are any write-transactions at all, invoke the commit hook */
+   if( needXcommit && db->xCommitCallback ){
+-    int rc;
+     sqlite3SafetyOff(db);
+     rc = db->xCommitCallback(db->pCommitArg);
+     sqlite3SafetyOn(db);
+@@ -965,7 +980,7 @@
+     int needSync = 0;
+     char *zMaster = 0;   /* File-name for the master journal */
+     char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt);
+-    OsFile master;
++    OsFile *master = 0;
+ 
+     /* Select a master journal file name */
+     do {
+@@ -979,7 +994,6 @@
+     }while( sqlite3OsFileExists(zMaster) );
+ 
+     /* Open the master journal. */
+-    memset(&master, 0, sizeof(master));
+     rc = sqlite3OsOpenExclusive(zMaster, &master, 0);
+     if( rc!=SQLITE_OK ){
+       sqliteFree(zMaster);
+@@ -1001,7 +1015,7 @@
+         if( !needSync && !sqlite3BtreeSyncDisabled(pBt) ){
+           needSync = 1;
+         }
+-        rc = sqlite3OsWrite(&master, zFile, strlen(zFile)+1);
++        rc = sqlite3OsWrite(master, zFile, strlen(zFile)+1);
+         if( rc!=SQLITE_OK ){
+           sqlite3OsClose(&master);
+           sqlite3OsDelete(zMaster);
+@@ -1016,9 +1030,9 @@
+     ** the master journal file is store in so that it gets synced too.
+     */
+     zMainFile = sqlite3BtreeGetDirname(db->aDb[0].pBt);
+-    rc = sqlite3OsOpenDirectory(zMainFile, &master);
++    rc = sqlite3OsOpenDirectory(master, zMainFile);
+     if( rc!=SQLITE_OK ||
+-          (needSync && (rc=sqlite3OsSync(&master,0))!=SQLITE_OK) ){
++          (needSync && (rc=sqlite3OsSync(master,0))!=SQLITE_OK) ){
+       sqlite3OsClose(&master);
+       sqlite3OsDelete(zMaster);
+       sqliteFree(zMaster);
+@@ -1094,10 +1108,10 @@
+ ** aborted so that they do not have data rolled out from underneath
+ ** them leading to a segfault.
+ */
+-static void abortOtherActiveVdbes(Vdbe *pVdbe){
++void sqlite3AbortOtherActiveVdbes(sqlite3 *db, Vdbe *pExcept){
+   Vdbe *pOther;
+-  for(pOther=pVdbe->db->pVdbe; pOther; pOther=pOther->pNext){
+-    if( pOther==pVdbe ) continue;
++  for(pOther=db->pVdbe; pOther; pOther=pOther->pNext){
++    if( pOther==pExcept ) continue;
+     if( pOther->magic!=VDBE_MAGIC_RUN || pOther->pc<0 ) continue;
+     closeAllCursors(pOther);
+     pOther->aborted = 1;
+@@ -1146,7 +1160,39 @@
+   sqlite3 *db = p->db;
+   int i;
+   int (*xFunc)(Btree *pBt) = 0;  /* Function to call on each btree backend */
++  int isSpecialError;            /* Set to true if SQLITE_NOMEM or IOERR */
+ 
++  /* This function contains the logic that determines if a statement or
++  ** transaction will be committed or rolled back as a result of the
++  ** execution of this virtual machine. 
++  **
++  ** Special errors:
++  **
++  **     If an SQLITE_NOMEM error has occured in a statement that writes to
++  **     the database, then either a statement or transaction must be rolled
++  **     back to ensure the tree-structures are in a consistent state. A
++  **     statement transaction is rolled back if one is open, otherwise the
++  **     entire transaction must be rolled back.
++  **
++  **     If an SQLITE_IOERR error has occured in a statement that writes to
++  **     the database, then the entire transaction must be rolled back. The
++  **     I/O error may have caused garbage to be written to the journal 
++  **     file. Were the transaction to continue and eventually be rolled 
++  **     back that garbage might end up in the database file.
++  **     
++  **     In both of the above cases, the Vdbe.errorAction variable is 
++  **     ignored. If the sqlite3.autoCommit flag is false and a transaction
++  **     is rolled back, it will be set to true.
++  **
++  ** Other errors:
++  **
++  ** No error:
++  **
++  */
++
++  if( sqlite3MallocFailed() ){
++    p->rc = SQLITE_NOMEM;
++  }
+   if( p->magic!=VDBE_MAGIC_RUN ){
+     /* Already halted.  Nothing to do. */
+     assert( p->magic==VDBE_MAGIC_HALT );
+@@ -1154,67 +1200,133 @@
+   }
+   closeAllCursors(p);
+   checkActiveVdbeCnt(db);
+-  if( p->pc<0 ){
+-    /* No commit or rollback needed if the program never started */
+-  }else if( db->autoCommit && db->activeVdbeCnt==1 ){
+-    if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
+-      /* The auto-commit flag is true, there are no other active queries
+-      ** using this handle and the vdbe program was successful or hit an
+-      ** 'OR FAIL' constraint. This means a commit is required.
++
++  /* No commit or rollback needed if the program never started */
++  if( p->pc>=0 ){
++
++    /* Check for one of the special errors - SQLITE_NOMEM or SQLITE_IOERR */
++    isSpecialError = ((p->rc==SQLITE_NOMEM || p->rc==SQLITE_IOERR)?1:0);
++    if( isSpecialError ){
++      /* This loop does static analysis of the query to see which of the
++      ** following three categories it falls into:
++      **
++      **     Read-only
++      **     Query with statement journal
++      **     Query without statement journal
++      **
++      ** We could do something more elegant than this static analysis (i.e.
++      ** store the type of query as part of the compliation phase), but 
++      ** handling malloc() or IO failure is a fairly obscure edge case so 
++      ** this is probably easier. Todo: Might be an opportunity to reduce 
++      ** code size a very small amount though...
+       */
+-      int rc = vdbeCommit(db);
+-      if( rc==SQLITE_BUSY ){
+-        return SQLITE_BUSY;
+-      }else if( rc!=SQLITE_OK ){
+-        p->rc = rc;
+-        xFunc = sqlite3BtreeRollback;
++      int isReadOnly = 1;
++      int isStatement = 0;
++      assert(p->aOp || p->nOp==0);
++      for(i=0; i<p->nOp; i++){ 
++        switch( p->aOp[i].opcode ){
++          case OP_Transaction:
++            isReadOnly = 0;
++            break;
++          case OP_Statement:
++            isStatement = 1;
++            break;
++        }
+       }
+-    }else{
+-      xFunc = sqlite3BtreeRollback;
++  
++      /* If the query was read-only, we need do no rollback at all. Otherwise,
++      ** proceed with the special handling.
++      */
++      if( !isReadOnly ){
++        if( p->rc==SQLITE_NOMEM && isStatement ){
++          xFunc = sqlite3BtreeRollbackStmt;
++        }else{
++          /* We are forced to roll back the active transaction. Before doing
++          ** so, abort any other statements this handle currently has active.
++          */
++          sqlite3AbortOtherActiveVdbes(db, p);
++          sqlite3RollbackAll(db);
++          db->autoCommit = 1;
++        }
++      }
+     }
+-  }else{
+-    if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
+-      xFunc = sqlite3BtreeCommitStmt;
+-    }else if( p->errorAction==OE_Abort ){
+-      xFunc = sqlite3BtreeRollbackStmt;
+-    }else{
+-      xFunc = sqlite3BtreeRollback;
+-      db->autoCommit = 1;
+-      abortOtherActiveVdbes(p);
++  
++    /* If the auto-commit flag is set and this is the only active vdbe, then
++    ** we do either a commit or rollback of the current transaction. 
++    **
++    ** Note: This block also runs if one of the special errors handled 
++    ** above has occured. 
++    */
++    if( db->autoCommit && db->activeVdbeCnt==1 ){
++      if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){
++	/* The auto-commit flag is true, and the vdbe program was 
++        ** successful or hit an 'OR FAIL' constraint. This means a commit 
++        ** is required.
++        */
++        int rc = vdbeCommit(db);
++        if( rc==SQLITE_BUSY ){
++          return SQLITE_BUSY;
++        }else if( rc!=SQLITE_OK ){
++          p->rc = rc;
++          sqlite3RollbackAll(db);
++        }else{
++          sqlite3CommitInternalChanges(db);
++        }
++      }else{
++        sqlite3RollbackAll(db);
++      }
++    }else if( !xFunc ){
++      if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
++        xFunc = sqlite3BtreeCommitStmt;
++      }else if( p->errorAction==OE_Abort ){
++        xFunc = sqlite3BtreeRollbackStmt;
++      }else{
++        sqlite3AbortOtherActiveVdbes(db, p);
++        sqlite3RollbackAll(db);
++        db->autoCommit = 1;
++      }
+     }
+-  }
+-
+-  /* If xFunc is not NULL, then it is one of sqlite3BtreeRollback,
+-  ** sqlite3BtreeRollbackStmt or sqlite3BtreeCommitStmt. Call it once on
+-  ** each backend. If an error occurs and the return code is still
+-  ** SQLITE_OK, set the return code to the new error value.
+-  */
+-  for(i=0; xFunc && i<db->nDb; i++){ 
+-    int rc;
+-    Btree *pBt = db->aDb[i].pBt;
+-    if( pBt ){
+-      rc = xFunc(pBt);
+-      if( p->rc==SQLITE_OK ) p->rc = rc;
++  
++    /* If xFunc is not NULL, then it is one of sqlite3BtreeRollbackStmt or
++    ** sqlite3BtreeCommitStmt. Call it once on each backend. If an error occurs
++    ** and the return code is still SQLITE_OK, set the return code to the new
++    ** error value.
++    */
++    assert(!xFunc ||
++      xFunc==sqlite3BtreeCommitStmt ||
++      xFunc==sqlite3BtreeRollbackStmt
++    );
++    for(i=0; xFunc && i<db->nDb; i++){ 
++      int rc;
++      Btree *pBt = db->aDb[i].pBt;
++      if( pBt ){
++        rc = xFunc(pBt);
++        if( rc && (p->rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT) ){
++          p->rc = rc;
++          sqlite3SetString(&p->zErrMsg, 0);
++        }
++      }
+     }
+-  }
+-
+-  /* If this was an INSERT, UPDATE or DELETE, set the change counter. */
+-  if( p->changeCntOn && p->pc>=0 ){
+-    if( !xFunc || xFunc==sqlite3BtreeCommitStmt ){
+-      sqlite3VdbeSetChanges(db, p->nChange);
+-    }else{
+-      sqlite3VdbeSetChanges(db, 0);
++  
++    /* If this was an INSERT, UPDATE or DELETE and the statement was committed, 
++    ** set the change counter. 
++    */
++    if( p->changeCntOn && p->pc>=0 ){
++      if( !xFunc || xFunc==sqlite3BtreeCommitStmt ){
++        sqlite3VdbeSetChanges(db, p->nChange);
++      }else{
++        sqlite3VdbeSetChanges(db, 0);
++      }
++      p->nChange = 0;
+     }
+-    p->nChange = 0;
++  
++    /* Rollback or commit any schema changes that occurred. */
++    if( p->rc!=SQLITE_OK && db->flags&SQLITE_InternChanges ){
++      sqlite3ResetInternalSchema(db, 0);
++      db->flags = (db->flags | SQLITE_InternChanges);
++    }
+   }
+ 
+-  /* Rollback or commit any schema changes that occurred. */
+-  if( p->rc!=SQLITE_OK ){
+-    sqlite3RollbackInternalChanges(db);
+-  }else if( db->flags & SQLITE_InternChanges ){
+-    sqlite3CommitInternalChanges(db);
+-  }
+-
+   /* We have successfully halted and closed the VM.  Record this fact. */
+   if( p->pc>=0 ){
+     db->activeVdbeCnt--;
+@@ -1255,8 +1367,9 @@
+   */
+   if( p->pc>=0 ){
+     if( p->zErrMsg ){
+-      sqlite3Error(p->db, p->rc, "%s", p->zErrMsg);
+-      sqliteFree(p->zErrMsg);
++      sqlite3* db = p->db;
++      sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, sqlite3FreeX);
++      db->errCode = p->rc;
+       p->zErrMsg = 0;
+     }else if( p->rc ){
+       sqlite3Error(p->db, p->rc, 0);
+@@ -1277,7 +1390,7 @@
+ 
+   /* Save profiling information from this VDBE run.
+   */
+-  assert( p->pTos<&p->aStack[p->pc<0?0:p->pc] || sqlite3_malloc_failed==1 );
++  assert( p->pTos<&p->aStack[p->pc<0?0:p->pc] || !p->aStack );
+ #ifdef VDBE_PROFILE
+   {
+     FILE *out = fopen("vdbe_profile.out", "a");
+@@ -1369,7 +1482,7 @@
+   releaseMemArray(p->aVar, p->nVar);
+   sqliteFree(p->aLabel);
+   sqliteFree(p->aStack);
+-  releaseMemArray(p->aColName, p->nResColumn*2);
++  releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
+   sqliteFree(p->aColName);
+   p->magic = VDBE_MAGIC_DEAD;
+   sqliteFree(p);
+@@ -1401,7 +1514,7 @@
+     }
+     sqlite3_search_count++;
+     p->deferredMoveto = 0;
+-    p->cacheValid = 0;
++    p->cacheStatus = CACHE_STALE;
+   }
+   return SQLITE_OK;
+ }
+@@ -1438,16 +1551,20 @@
+ **      5                     6            signed integer
+ **      6                     8            signed integer
+ **      7                     8            IEEE float
+-**     8-11                                reserved for expansion
++**      8                     0            Integer constant 0
++**      9                     0            Integer constant 1
++**     10,11                               reserved for expansion
+ **    N>=12 and even       (N-12)/2        BLOB
+ **    N>=13 and odd        (N-13)/2        text
+ **
++** The 8 and 9 types were added in 3.3.0, file format 4.  Prior versions
++** of SQLite will not understand those serial types.
+ */
+ 
+ /*
+ ** Return the serial-type for the value stored in pMem.
+ */
+-u32 sqlite3VdbeSerialType(Mem *pMem){
++u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
+   int flags = pMem->flags;
+ 
+   if( flags&MEM_Null ){
+@@ -1457,7 +1574,11 @@
+     /* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */
+ #   define MAX_6BYTE ((((i64)0x00001000)<<32)-1)
+     i64 i = pMem->i;
+-    u64 u = i<0 ? -i : i;
++    u64 u;
++    if( file_format>=4 && (i&1)==i ){
++      return 8+i;
++    }
++    u = i<0 ? -i : i;
+     if( u<=127 ) return 1;
+     if( u<=32767 ) return 2;
+     if( u<=8388607 ) return 3;
+@@ -1496,17 +1617,12 @@
+ ** buf. It is assumed that the caller has allocated sufficient space.
+ ** Return the number of bytes written.
+ */ 
+-int sqlite3VdbeSerialPut(unsigned char *buf, Mem *pMem){
+-  u32 serial_type = sqlite3VdbeSerialType(pMem);
++int sqlite3VdbeSerialPut(unsigned char *buf, Mem *pMem, int file_format){
++  u32 serial_type = sqlite3VdbeSerialType(pMem, file_format);
+   int len;
+ 
+-  /* NULL */
+-  if( serial_type==0 ){
+-    return 0;
+-  }
+- 
+   /* Integer and Real */
+-  if( serial_type<=7 ){
++  if( serial_type<=7 && serial_type>0 ){
+     u64 v;
+     int i;
+     if( serial_type==7 ){
+@@ -1521,12 +1637,16 @@
+     }
+     return len;
+   }
+-  
++
+   /* String or blob */
+-  assert( serial_type>=12 );
+-  len = sqlite3VdbeSerialTypeLen(serial_type);
+-  memcpy(buf, pMem->z, len);
+-  return len;
++  if( serial_type>=12 ){
++    len = sqlite3VdbeSerialTypeLen(serial_type);
++    memcpy(buf, pMem->z, len);
++    return len;
++  }
++
++  /* NULL or constants 0 or 1 */
++  return 0;
+ }
+ 
+ /*
+@@ -1539,8 +1659,6 @@
+   Mem *pMem                     /* Memory cell to write value into */
+ ){
+   switch( serial_type ){
+-    case 8:    /* Reserved for future use */
+-    case 9:    /* Reserved for future use */
+     case 10:   /* Reserved for future use */
+     case 11:   /* Reserved for future use */
+     case 0: {  /* NULL */
+@@ -1579,7 +1697,7 @@
+     case 7: { /* IEEE floating point */
+       u64 x;
+       u32 y;
+-#ifndef NDEBUG
++#if !defined(NDEBUG) && !defined(SQLITE_OMIT_FLOATING_POINT)
+       /* Verify that integers and floating point values use the same
+       ** byte order.  The byte order differs on some (broken) architectures.
+       */
+@@ -1599,6 +1717,12 @@
+       }
+       return 8;
+     }
++    case 8:    /* Integer 0 */
++    case 9: {  /* Integer 1 */
++      pMem->i = serial_type-8;
++      pMem->flags = MEM_Int;
++      return 0;
++    }
+     default: {
+       int len = (serial_type-12)/2;
+       pMem->z = (char *)buf;
+@@ -1616,6 +1740,23 @@
+ }
+ 
+ /*
++** The header of a record consists of a sequence variable-length integers.
++** These integers are almost always small and are encoded as a single byte.
++** The following macro takes advantage this fact to provide a fast decode
++** of the integers in a record header.  It is faster for the common case
++** where the integer is a single byte.  It is a little slower when the
++** integer is two or more bytes.  But overall it is faster.
++**
++** The following expressions are equivalent:
++**
++**     x = sqlite3GetVarint32( A, &B );
++**
++**     x = GetVarint( A, B );
++**
++*/
++#define GetVarint(A,B)  ((B = *(A))<=0x7f ? 1 : sqlite3GetVarint32(A, &B))
++
++/*
+ ** This function compares the two table rows or index records specified by 
+ ** {nKey1, pKey1} and {nKey2, pKey2}, returning a negative, zero
+ ** or positive integer if {nKey1, pKey1} is less than, equal to or 
+@@ -1642,9 +1783,9 @@
+   mem1.enc = pKeyInfo->enc;
+   mem2.enc = pKeyInfo->enc;
+   
+-  idx1 = sqlite3GetVarint32(pKey1, &szHdr1);
++  idx1 = GetVarint(aKey1, szHdr1);
+   d1 = szHdr1;
+-  idx2 = sqlite3GetVarint32(pKey2, &szHdr2);
++  idx2 = GetVarint(aKey2, szHdr2);
+   d2 = szHdr2;
+   nField = pKeyInfo->nField;
+   while( idx1<szHdr1 && idx2<szHdr2 ){
+@@ -1652,9 +1793,9 @@
+     u32 serial_type2;
+ 
+     /* Read the serial types for the next element in each key. */
+-    idx1 += sqlite3GetVarint32(&aKey1[idx1], &serial_type1);
++    idx1 += GetVarint( aKey1+idx1, serial_type1 );
+     if( d1>=nKey1 && sqlite3VdbeSerialTypeLen(serial_type1)>0 ) break;
+-    idx2 += sqlite3GetVarint32(&aKey2[idx2], &serial_type2);
++    idx2 += GetVarint( aKey2+idx2, serial_type2 );
+     if( d2>=nKey2 && sqlite3VdbeSerialTypeLen(serial_type2)>0 ) break;
+ 
+     /* Assert that there is enough space left in each key for the blob of
+@@ -1686,9 +1827,8 @@
+     }else if( d2<nKey2 ){
+       rc = -1;
+     }
+-  }
+-
+-  if( pKeyInfo->aSortOrder && i<pKeyInfo->nField && pKeyInfo->aSortOrder[i] ){
++  }else if( pKeyInfo->aSortOrder && i<pKeyInfo->nField
++               && pKeyInfo->aSortOrder[i] ){
+     rc = -rc;
+   }
+ 
+@@ -1732,10 +1872,10 @@
+   if( rc ){
+     return rc;
+   }
+-  sqlite3GetVarint32(m.z, &szHdr);
+-  sqlite3GetVarint32(&m.z[szHdr-1], &typeRowid);
++  sqlite3GetVarint32((u8*)m.z, &szHdr);
++  sqlite3GetVarint32((u8*)&m.z[szHdr-1], &typeRowid);
+   lenRowid = sqlite3VdbeSerialTypeLen(typeRowid);
+-  sqlite3VdbeSerialGet(&m.z[m.n-lenRowid], typeRowid, &v);
++  sqlite3VdbeSerialGet((u8*)&m.z[m.n-lenRowid], typeRowid, &v);
+   *rowid = v.i;
+   sqlite3VdbeMemRelease(&m);
+   return SQLITE_OK;
+@@ -1771,7 +1911,7 @@
+   if( rc ){
+     return rc;
+   }
+-  lenRowid = sqlite3VdbeIdxRowidLen(m.n, m.z);
++  lenRowid = sqlite3VdbeIdxRowidLen(m.n, (u8*)m.z);
+   *res = sqlite3VdbeRecordCompare(pC->pKeyInfo, m.n-lenRowid, m.z, nKey, pKey);
+   sqlite3VdbeMemRelease(&m);
+   return SQLITE_OK;
+Index: sqlite/build.c
+===================================================================
+--- amarok/src/sqlite/build.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/build.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -36,7 +36,87 @@
+   pParse->nVar = 0;
+ }
+ 
++#ifndef SQLITE_OMIT_SHARED_CACHE
+ /*
++** The TableLock structure is only used by the sqlite3TableLock() and
++** codeTableLocks() functions.
++*/
++struct TableLock {
++  int iDb;
++  int iTab;
++  u8 isWriteLock;
++  const char *zName;
++};
++
++/*
++** Have the compiled statement lock the table with rootpage iTab in database
++** iDb at the shared-cache level when executed. The isWriteLock argument 
++** is zero for a read-lock, or non-zero for a write-lock.
++**
++** The zName parameter should point to the unqualified table name. This is
++** used to provide a more informative error message should the lock fail.
++*/
++void sqlite3TableLock(
++  Parse *pParse, 
++  int iDb, 
++  int iTab, 
++  u8 isWriteLock,  
++  const char *zName
++){
++  int i;
++  int nBytes;
++  TableLock *p;
++
++  if( 0==sqlite3ThreadDataReadOnly()->useSharedData || iDb<0 ){
++    return;
++  }
++
++  for(i=0; i<pParse->nTableLock; i++){
++    p = &pParse->aTableLock[i];
++    if( p->iDb==iDb && p->iTab==iTab ){
++      p->isWriteLock = (p->isWriteLock || isWriteLock);
++      return;
++    }
++  }
++
++  nBytes = sizeof(TableLock) * (pParse->nTableLock+1);
++  sqliteReallocOrFree((void **)&pParse->aTableLock, nBytes);
++  if( pParse->aTableLock ){
++    p = &pParse->aTableLock[pParse->nTableLock++];
++    p->iDb = iDb;
++    p->iTab = iTab;
++    p->isWriteLock = isWriteLock;
++    p->zName = zName;
++  }
++}
++
++/*
++** Code an OP_TableLock instruction for each table locked by the
++** statement (configured by calls to sqlite3TableLock()).
++*/
++static void codeTableLocks(Parse *pParse){
++  int i;
++  Vdbe *pVdbe; 
++  assert( sqlite3ThreadDataReadOnly()->useSharedData || pParse->nTableLock==0 );
++
++  if( 0==(pVdbe = sqlite3GetVdbe(pParse)) ){
++    return;
++  }
++
++  for(i=0; i<pParse->nTableLock; i++){
++    TableLock *p = &pParse->aTableLock[i];
++    int p1 = p->iDb;
++    if( p->isWriteLock ){
++      p1 = -1*(p1+1);
++    }
++    sqlite3VdbeOp3(pVdbe, OP_TableLock, p1, p->iTab, p->zName, P3_STATIC);
++  }
++}
++#else
++  #define codeTableLocks(x)
++#endif
++
++/*
+ ** This routine is called after a single SQL statement has been
+ ** parsed and a VDBE program to execute that statement has been
+ ** prepared.  This routine puts the finishing touches on the
+@@ -50,7 +130,7 @@
+   sqlite3 *db;
+   Vdbe *v;
+ 
+-  if( sqlite3_malloc_failed ) return;
++  if( sqlite3MallocFailed() ) return;
+   if( pParse->nested ) return;
+   if( !pParse->pVdbe ){
+     if( pParse->rc==SQLITE_OK && pParse->nErr ){
+@@ -82,6 +162,12 @@
+         sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
+         sqlite3VdbeAddOp(v, OP_VerifyCookie, iDb, pParse->cookieValue[iDb]);
+       }
++
++      /* Once all the cookies have been verified and transactions opened, 
++      ** obtain the required table-locks. This is a no-op unless the 
++      ** shared-cache feature is enabled.
++      */
++      codeTableLocks(pParse);
+       sqlite3VdbeAddOp(v, OP_Goto, 0, pParse->cookieGoto);
+     }
+ 
+@@ -168,11 +254,10 @@
+   Table *p = 0;
+   int i;
+   assert( zName!=0 );
+-  assert( (db->flags & SQLITE_Initialized) || db->init.busy );
+   for(i=OMIT_TEMPDB; i<db->nDb; i++){
+     int j = (i<2) ? i^1 : i;   /* Search TEMP before MAIN */
+     if( zDatabase!=0 && sqlite3StrICmp(zDatabase, db->aDb[j].zName) ) continue;
+-    p = sqlite3HashFind(&db->aDb[j].tblHash, zName, strlen(zName)+1);
++    p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName, strlen(zName)+1);
+     if( p ) break;
+   }
+   return p;
+@@ -224,11 +309,14 @@
+ Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){
+   Index *p = 0;
+   int i;
+-  assert( (db->flags & SQLITE_Initialized) || db->init.busy );
+   for(i=OMIT_TEMPDB; i<db->nDb; i++){
+     int j = (i<2) ? i^1 : i;  /* Search TEMP before MAIN */
++    Schema *pSchema = db->aDb[j].pSchema;
+     if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zName) ) continue;
+-    p = sqlite3HashFind(&db->aDb[j].idxHash, zName, strlen(zName)+1);
++    assert( pSchema || (j==1 && !db->aDb[1].pBt) );
++    if( pSchema ){
++      p = sqlite3HashFind(&pSchema->idxHash, zName, strlen(zName)+1);
++    }
+     if( p ) break;
+   }
+   return p;
+@@ -252,10 +340,9 @@
+ */
+ static void sqliteDeleteIndex(sqlite3 *db, Index *p){
+   Index *pOld;
++  const char *zName = p->zName;
+ 
+-  assert( db!=0 && p->zName!=0 );
+-  pOld = sqlite3HashInsert(&db->aDb[p->iDb].idxHash, p->zName,
+-                          strlen(p->zName)+1, 0);
++  pOld = sqlite3HashInsert(&p->pSchema->idxHash, zName, strlen( zName)+1, 0);
+   assert( pOld==0 || pOld==p );
+   freeIndex(p);
+ }
+@@ -269,9 +356,10 @@
+ void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){
+   Index *pIndex;
+   int len;
++  Hash *pHash = &db->aDb[iDb].pSchema->idxHash;
+ 
+   len = strlen(zIdxName);
+-  pIndex = sqlite3HashInsert(&db->aDb[iDb].idxHash, zIdxName, len+1, 0);
++  pIndex = sqlite3HashInsert(pHash, zIdxName, len+1, 0);
+   if( pIndex ){
+     if( pIndex->pTable->pIndex==pIndex ){
+       pIndex->pTable->pIndex = pIndex->pNext;
+@@ -299,39 +387,21 @@
+ ** single file indicated.
+ */
+ void sqlite3ResetInternalSchema(sqlite3 *db, int iDb){
+-  HashElem *pElem;
+-  Hash temp1;
+-  Hash temp2;
+   int i, j;
+ 
+   assert( iDb>=0 && iDb<db->nDb );
+-  db->flags &= ~SQLITE_Initialized;
+   for(i=iDb; i<db->nDb; i++){
+     Db *pDb = &db->aDb[i];
+-    temp1 = pDb->tblHash;
+-    temp2 = pDb->trigHash;
+-    sqlite3HashInit(&pDb->trigHash, SQLITE_HASH_STRING, 0);
+-    sqlite3HashClear(&pDb->aFKey);
+-    sqlite3HashClear(&pDb->idxHash);
+-    for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
+-      sqlite3DeleteTrigger((Trigger*)sqliteHashData(pElem));
++    if( pDb->pSchema ){
++      sqlite3SchemaFree(pDb->pSchema);
+     }
+-    sqlite3HashClear(&temp2);
+-    sqlite3HashInit(&pDb->tblHash, SQLITE_HASH_STRING, 0);
+-    for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
+-      Table *pTab = sqliteHashData(pElem);
+-      sqlite3DeleteTable(db, pTab);
+-    }
+-    sqlite3HashClear(&temp1);
+-    pDb->pSeqTab = 0;
+-    DbClearProperty(db, i, DB_SchemaLoaded);
+     if( iDb>0 ) return;
+   }
+   assert( iDb==0 );
+   db->flags &= ~SQLITE_InternChanges;
+ 
+   /* If one or more of the auxiliary database files has been closed,
+-  ** then remove then from the auxiliary database list.  We take the
++  ** then remove them from the auxiliary database list.  We take the
+   ** opportunity to do this here since we have just deleted all of the
+   ** schema hash tables and therefore do not have to make any changes
+   ** to any of those tables.
+@@ -394,6 +464,7 @@
+       sqliteFree(pCol->zName);
+       sqlite3ExprDelete(pCol->pDflt);
+       sqliteFree(pCol->zType);
++      sqliteFree(pCol->zColl);
+     }
+     sqliteFree(pTable->aCol);
+   }
+@@ -420,6 +491,8 @@
+   Index *pIndex, *pNext;
+   FKey *pFKey, *pNextFKey;
+ 
++  db = 0;
++
+   if( pTable==0 ) return;
+ 
+   /* Do not delete the table until the reference count reaches zero. */
+@@ -433,7 +506,7 @@
+   */
+   for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){
+     pNext = pIndex->pNext;
+-    assert( pIndex->iDb==pTable->iDb || (pTable->iDb==0 && pIndex->iDb==1) );
++    assert( pIndex->pSchema==pTable->pSchema );
+     sqliteDeleteIndex(db, pIndex);
+   }
+ 
+@@ -443,8 +516,7 @@
+   */
+   for(pFKey=pTable->pFKey; pFKey; pFKey=pNextFKey){
+     pNextFKey = pFKey->pNextFrom;
+-    assert( pTable->iDb<db->nDb );
+-    assert( sqlite3HashFind(&db->aDb[pTable->iDb].aFKey,
++    assert( sqlite3HashFind(&pTable->pSchema->aFKey,
+                            pFKey->zTo, strlen(pFKey->zTo)+1)!=pFKey );
+     sqliteFree(pFKey);
+   }
+@@ -456,6 +528,9 @@
+   sqliteFree(pTable->zName);
+   sqliteFree(pTable->zColAff);
+   sqlite3SelectDelete(pTable->pSelect);
++#ifndef SQLITE_OMIT_CHECK
++  sqlite3ExprDelete(pTable->pCheck);
++#endif
+   sqliteFree(pTable);
+ }
+ 
+@@ -472,14 +547,14 @@
+   assert( iDb>=0 && iDb<db->nDb );
+   assert( zTabName && zTabName[0] );
+   pDb = &db->aDb[iDb];
+-  p = sqlite3HashInsert(&pDb->tblHash, zTabName, strlen(zTabName)+1, 0);
++  p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, strlen(zTabName)+1,0);
+   if( p ){
+ #ifndef SQLITE_OMIT_FOREIGN_KEY
+     for(pF1=p->pFKey; pF1; pF1=pF1->pNextFrom){
+       int nTo = strlen(pF1->zTo) + 1;
+-      pF2 = sqlite3HashFind(&pDb->aFKey, pF1->zTo, nTo);
++      pF2 = sqlite3HashFind(&pDb->pSchema->aFKey, pF1->zTo, nTo);
+       if( pF2==pF1 ){
+-        sqlite3HashInsert(&pDb->aFKey, pF1->zTo, nTo, pF1->pNextTo);
++        sqlite3HashInsert(&pDb->pSchema->aFKey, pF1->zTo, nTo, pF1->pNextTo);
+       }else{
+         while( pF2 && pF2->pNextTo!=pF1 ){ pF2=pF2->pNextTo; }
+         if( pF2 ){
+@@ -506,7 +581,7 @@
+ char *sqlite3NameFromToken(Token *pName){
+   char *zName;
+   if( pName ){
+-    zName = sqliteStrNDup(pName->z, pName->n);
++    zName = sqliteStrNDup((char*)pName->z, pName->n);
+     sqlite3Dequote(zName);
+   }else{
+     zName = 0;
+@@ -518,7 +593,9 @@
+ ** Open the sqlite_master table stored in database number iDb for
+ ** writing. The table is opened using cursor 0.
+ */
+-void sqlite3OpenMasterTable(Vdbe *v, int iDb){
++void sqlite3OpenMasterTable(Parse *p, int iDb){
++  Vdbe *v = sqlite3GetVdbe(p);
++  sqlite3TableLock(p, iDb, MASTER_ROOT, 1, SCHEMA_TABLE(iDb));
+   sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
+   sqlite3VdbeAddOp(v, OP_OpenWrite, 0, MASTER_ROOT);
+   sqlite3VdbeAddOp(v, OP_SetNumColumns, 0, 5); /* sqlite_master has 5 columns */
+@@ -632,7 +709,8 @@
+   Token *pName1,   /* First part of the name of the table or view */
+   Token *pName2,   /* Second part of the name of the table or view */
+   int isTemp,      /* True if this is a TEMP table */
+-  int isView       /* True if this is a VIEW */
++  int isView,      /* True if this is a VIEW */
++  int noErr        /* Do nothing if table already exists */
+ ){
+   Table *pTable;
+   char *zName = 0; /* The name of the new table */
+@@ -710,7 +788,9 @@
+   }
+   pTable = sqlite3FindTable(db, zName, db->aDb[iDb].zName);
+   if( pTable ){
+-    sqlite3ErrorMsg(pParse, "table %T already exists", pName);
++    if( !noErr ){
++      sqlite3ErrorMsg(pParse, "table %T already exists", pName);
++    }
+     goto begin_table_error;
+   }
+   if( sqlite3FindIndex(db, zName, 0)!=0 && (iDb==0 || !db->init.busy) ){
+@@ -728,7 +808,7 @@
+   pTable->aCol = 0;
+   pTable->iPKey = -1;
+   pTable->pIndex = 0;
+-  pTable->iDb = iDb;
++  pTable->pSchema = db->aDb[iDb].pSchema;
+   pTable->nRef = 1;
+   if( pParse->pNewTable ) sqlite3DeleteTable(db, pParse->pNewTable);
+   pParse->pNewTable = pTable;
+@@ -739,7 +819,7 @@
+   */
+ #ifndef SQLITE_OMIT_AUTOINCREMENT
+   if( !pParse->nested && strcmp(zName, "sqlite_sequence")==0 ){
+-    db->aDb[iDb].pSeqTab = pTable;
++    pTable->pSchema->pSeqTab = pTable;
+   }
+ #endif
+ 
+@@ -753,6 +833,7 @@
+   */
+   if( !db->init.busy && (v = sqlite3GetVdbe(pParse))!=0 ){
+     int lbl;
++    int fileFormat;
+     sqlite3BeginWriteOperation(pParse, 0, iDb);
+ 
+     /* If the file format and encoding in the database have not been set, 
+@@ -761,9 +842,11 @@
+     sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 1);   /* file_format */
+     lbl = sqlite3VdbeMakeLabel(v);
+     sqlite3VdbeAddOp(v, OP_If, 0, lbl);
+-    sqlite3VdbeAddOp(v, OP_Integer, db->file_format, 0);
++    fileFormat = (db->flags & SQLITE_LegacyFileFmt)!=0 ?
++                  1 : SQLITE_DEFAULT_FILE_FORMAT;
++    sqlite3VdbeAddOp(v, OP_Integer, fileFormat, 0);
+     sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 1);
+-    sqlite3VdbeAddOp(v, OP_Integer, db->enc, 0);
++    sqlite3VdbeAddOp(v, OP_Integer, ENC(db), 0);
+     sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 4);
+     sqlite3VdbeResolveLabel(v, lbl);
+ 
+@@ -783,7 +866,7 @@
+     {
+       sqlite3VdbeAddOp(v, OP_CreateTable, iDb, 0);
+     }
+-    sqlite3OpenMasterTable(v, iDb);
++    sqlite3OpenMasterTable(pParse, iDb);
+     sqlite3VdbeAddOp(v, OP_NewRowid, 0, 0);
+     sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
+     sqlite3VdbeAddOp(v, OP_Null, 0, 0);
+@@ -855,7 +938,6 @@
+   ** be called next to set pCol->affinity correctly.
+   */
+   pCol->affinity = SQLITE_AFF_NONE;
+-  pCol->pColl = pParse->db->pDfltColl;
+   p->nCol++;
+ }
+ 
+@@ -891,6 +973,9 @@
+ ** 'CLOB'        | SQLITE_AFF_TEXT
+ ** 'TEXT'        | SQLITE_AFF_TEXT
+ ** 'BLOB'        | SQLITE_AFF_NONE
++** 'REAL'        | SQLITE_AFF_REAL
++** 'FLOA'        | SQLITE_AFF_REAL
++** 'DOUB'        | SQLITE_AFF_REAL
+ **
+ ** If none of the substrings in the above table are found,
+ ** SQLITE_AFF_NUMERIC is returned.
+@@ -911,10 +996,21 @@
+     }else if( h==(('t'<<24)+('e'<<16)+('x'<<8)+'t') ){       /* TEXT */
+       aff = SQLITE_AFF_TEXT;
+     }else if( h==(('b'<<24)+('l'<<16)+('o'<<8)+'b')          /* BLOB */
++        && (aff==SQLITE_AFF_NUMERIC || aff==SQLITE_AFF_REAL) ){
++      aff = SQLITE_AFF_NONE;
++#ifndef SQLITE_OMIT_FLOATING_POINT
++    }else if( h==(('r'<<24)+('e'<<16)+('a'<<8)+'l')          /* REAL */
+         && aff==SQLITE_AFF_NUMERIC ){
+-      aff = SQLITE_AFF_NONE;
++      aff = SQLITE_AFF_REAL;
++    }else if( h==(('f'<<24)+('l'<<16)+('o'<<8)+'a')          /* FLOA */
++        && aff==SQLITE_AFF_NUMERIC ){
++      aff = SQLITE_AFF_REAL;
++    }else if( h==(('d'<<24)+('o'<<16)+('u'<<8)+'b')          /* DOUB */
++        && aff==SQLITE_AFF_NUMERIC ){
++      aff = SQLITE_AFF_REAL;
++#endif
+     }else if( (h&0x00FFFFFF)==(('i'<<16)+('n'<<8)+'t') ){    /* INT */
+-      aff = SQLITE_AFF_INTEGER; 
++      aff = SQLITE_AFF_INTEGER;
+       break;
+     }
+   }
+@@ -993,7 +1089,8 @@
+   Parse *pParse,    /* Parsing context */
+   ExprList *pList,  /* List of field names to be indexed */
+   int onError,      /* What to do with a uniqueness conflict */
+-  int autoInc       /* True if the AUTOINCREMENT keyword is present */
++  int autoInc,      /* True if the AUTOINCREMENT keyword is present */
++  int sortOrder     /* SQLITE_SO_ASC or SQLITE_SO_DESC */
+ ){
+   Table *pTab = pParse->pNewTable;
+   char *zType = 0;
+@@ -1024,7 +1121,8 @@
+   if( iCol>=0 && iCol<pTab->nCol ){
+     zType = pTab->aCol[iCol].zType;
+   }
+-  if( zType && sqlite3StrICmp(zType, "INTEGER")==0 ){
++  if( zType && sqlite3StrICmp(zType, "INTEGER")==0
++        && sortOrder==SQLITE_SO_ASC ){
+     pTab->iPKey = iCol;
+     pTab->keyConf = onError;
+     pTab->autoInc = autoInc;
+@@ -1034,7 +1132,7 @@
+        "INTEGER PRIMARY KEY");
+ #endif
+   }else{
+-    sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0);
++    sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0, sortOrder, 0);
+     pList = 0;
+   }
+ 
+@@ -1044,46 +1142,50 @@
+ }
+ 
+ /*
++** Add a new CHECK constraint to the table currently under construction.
++*/
++void sqlite3AddCheckConstraint(
++  Parse *pParse,    /* Parsing context */
++  Expr *pCheckExpr  /* The check expression */
++){
++#ifndef SQLITE_OMIT_CHECK
++  Table *pTab = pParse->pNewTable;
++  if( pTab ){
++    /* The CHECK expression must be duplicated so that tokens refer
++    ** to malloced space and not the (ephemeral) text of the CREATE TABLE
++    ** statement */
++    pTab->pCheck = sqlite3ExprAnd(pTab->pCheck, sqlite3ExprDup(pCheckExpr));
++  }
++#endif
++  sqlite3ExprDelete(pCheckExpr);
++}
++
++/*
+ ** Set the collation function of the most recently parsed table column
+ ** to the CollSeq given.
+ */
+ void sqlite3AddCollateType(Parse *pParse, const char *zType, int nType){
+   Table *p;
+-  Index *pIdx;
+-  CollSeq *pColl;
+   int i;
+ 
+   if( (p = pParse->pNewTable)==0 ) return;
+   i = p->nCol-1;
+ 
+-  pColl = sqlite3LocateCollSeq(pParse, zType, nType);
+-  p->aCol[i].pColl = pColl;
+-
+-  /* If the column is declared as "<name> PRIMARY KEY COLLATE <type>",
+-  ** then an index may have been created on this column before the
+-  ** collation type was added. Correct this if it is the case.
+-  */
+-  for(pIdx = p->pIndex; pIdx; pIdx=pIdx->pNext){
+-    assert( pIdx->nColumn==1 );
+-    if( pIdx->aiColumn[0]==i ) pIdx->keyInfo.aColl[0] = pColl;
+-  }
+-}
+-
+-/*
+-** Call sqlite3CheckCollSeq() for all collating sequences in an index,
+-** in order to verify that all the necessary collating sequences are
+-** loaded.
+-*/
+-int sqlite3CheckIndexCollSeq(Parse *pParse, Index *pIdx){
+-  if( pIdx ){
+-    int i;
+-    for(i=0; i<pIdx->nColumn; i++){
+-      if( sqlite3CheckCollSeq(pParse, pIdx->keyInfo.aColl[i]) ){
+-        return SQLITE_ERROR;
++  if( sqlite3LocateCollSeq(pParse, zType, nType) ){
++    Index *pIdx;
++    p->aCol[i].zColl = sqliteStrNDup(zType, nType);
++  
++    /* If the column is declared as "<name> PRIMARY KEY COLLATE <type>",
++    ** then an index may have been created on this column before the
++    ** collation type was added. Correct this if it is the case.
++    */
++    for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){
++      assert( pIdx->nColumn==1 );
++      if( pIdx->aiColumn[0]==i ){
++        pIdx->azColl[0] = p->aCol[i].zColl;
+       }
+     }
+   }
+-  return SQLITE_OK;
+ }
+ 
+ /*
+@@ -1102,10 +1204,11 @@
+ */
+ CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName){
+   sqlite3 *db = pParse->db;
+-  u8 enc = db->enc;
++  u8 enc = ENC(db);
+   u8 initbusy = db->init.busy;
++  CollSeq *pColl;
+ 
+-  CollSeq *pColl = sqlite3FindCollSeq(db, enc, zName, nName, initbusy);
++  pColl = sqlite3FindCollSeq(db, enc, zName, nName, initbusy);
+   if( !initbusy && (!pColl || !pColl->xCmp) ){
+     pColl = sqlite3GetCollSeq(db, pColl, zName, nName);
+     if( !pColl ){
+@@ -1138,7 +1241,7 @@
+ ** 1 chance in 2^32.  So we're safe enough.
+ */
+ void sqlite3ChangeCookie(sqlite3 *db, Vdbe *v, int iDb){
+-  sqlite3VdbeAddOp(v, OP_Integer, db->aDb[iDb].schema_cookie+1, 0);
++  sqlite3VdbeAddOp(v, OP_Integer, db->aDb[iDb].pSchema->schema_cookie+1, 0);
+   sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 0);
+ }
+ 
+@@ -1186,7 +1289,7 @@
+ ** table.  Memory to hold the text of the statement is obtained
+ ** from sqliteMalloc() and must be freed by the calling function.
+ */
+-static char *createTableStmt(Table *p){
++static char *createTableStmt(Table *p, int isTemp){
+   int i, k, n;
+   char *zStmt;
+   char *zSep, *zSep2, *zEnd, *z;
+@@ -1212,7 +1315,7 @@
+   n += 35 + 6*p->nCol;
+   zStmt = sqliteMallocRaw( n );
+   if( zStmt==0 ) return 0;
+-  strcpy(zStmt, !OMIT_TEMPDB&&p->iDb==1 ? "CREATE TEMP TABLE ":"CREATE TABLE ");
++  strcpy(zStmt, !OMIT_TEMPDB&&isTemp ? "CREATE TEMP TABLE ":"CREATE TABLE ");
+   k = strlen(zStmt);
+   identPut(zStmt, &k, p->zName);
+   zStmt[k++] = '(';
+@@ -1259,13 +1362,40 @@
+ ){
+   Table *p;
+   sqlite3 *db = pParse->db;
++  int iDb;
+ 
+-  if( (pEnd==0 && pSelect==0) || pParse->nErr || sqlite3_malloc_failed ) return;
++  if( (pEnd==0 && pSelect==0) || pParse->nErr || sqlite3MallocFailed() ) {
++    return;
++  }
+   p = pParse->pNewTable;
+   if( p==0 ) return;
+ 
+   assert( !db->init.busy || !pSelect );
+ 
++  iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema);
++
++#ifndef SQLITE_OMIT_CHECK
++  /* Resolve names in all CHECK constraint expressions.
++  */
++  if( p->pCheck ){
++    SrcList sSrc;                   /* Fake SrcList for pParse->pNewTable */
++    NameContext sNC;                /* Name context for pParse->pNewTable */
++
++    memset(&sNC, 0, sizeof(sNC));
++    memset(&sSrc, 0, sizeof(sSrc));
++    sSrc.nSrc = 1;
++    sSrc.a[0].zName = p->zName;
++    sSrc.a[0].pTab = p;
++    sSrc.a[0].iCursor = -1;
++    sNC.pParse = pParse;
++    sNC.pSrcList = &sSrc;
++    sNC.isCheck = 1;
++    if( sqlite3ExprResolveNames(&sNC, p->pCheck) ){
++      return;
++    }
++  }
++#endif /* !defined(SQLITE_OMIT_CHECK) */
++
+   /* If the db->init.busy is 1 it means we are reading the SQL off the
+   ** "sqlite_master" or "sqlite_temp_master" table on the disk.
+   ** So do not write to the disk again.  Extract the root page number
+@@ -1318,11 +1448,16 @@
+     ** Once the SELECT has been coded by sqlite3Select(), it is in a
+     ** suitable state to query for the column names and types to be used
+     ** by the new table.
++    **
++    ** A shared-cache write-lock is not required to write to the new table,
++    ** as a schema-lock must have already been obtained to create it. Since
++    ** a schema-lock excludes all other database users, the write-lock would
++    ** be redundant.
+     */
+     if( pSelect ){
+       Table *pSelTab;
+       sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
+-      sqlite3VdbeAddOp(v, OP_Integer, p->iDb, 0);
++      sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
+       sqlite3VdbeAddOp(v, OP_OpenWrite, 1, 0);
+       pParse->nTab = 2;
+       sqlite3Select(pParse, pSelect, SRT_Table, 1, 0, 0, 0, 0);
+@@ -1341,7 +1476,7 @@
+ 
+     /* Compute the complete text of the CREATE statement */
+     if( pSelect ){
+-      zStmt = createTableStmt(p);
++      zStmt = createTableStmt(p, p->pSchema==pParse->db->aDb[1].pSchema);
+     }else{
+       n = pEnd->z - pParse->sNameToken.z + 1;
+       zStmt = sqlite3MPrintf("CREATE %s %.*s", zType2, n, pParse->sNameToken.z);
+@@ -1357,22 +1492,22 @@
+       "UPDATE %Q.%s "
+          "SET type='%s', name=%Q, tbl_name=%Q, rootpage=#0, sql=%Q "
+        "WHERE rowid=#1",
+-      db->aDb[p->iDb].zName, SCHEMA_TABLE(p->iDb),
++      db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
+       zType,
+       p->zName,
+       p->zName,
+       zStmt
+     );
+     sqliteFree(zStmt);
+-    sqlite3ChangeCookie(db, v, p->iDb);
++    sqlite3ChangeCookie(db, v, iDb);
+ 
+ #ifndef SQLITE_OMIT_AUTOINCREMENT
+     /* Check to see if we need to create an sqlite_sequence table for
+     ** keeping track of autoincrement keys.
+     */
+     if( p->autoInc ){
+-      Db *pDb = &db->aDb[p->iDb];
+-      if( pDb->pSeqTab==0 ){
++      Db *pDb = &db->aDb[iDb];
++      if( pDb->pSchema->pSeqTab==0 ){
+         sqlite3NestedParse(pParse,
+           "CREATE TABLE %Q.sqlite_sequence(name,seq)",
+           pDb->zName
+@@ -1382,7 +1517,7 @@
+ #endif
+ 
+     /* Reparse everything to update our internal data structures */
+-    sqlite3VdbeOp3(v, OP_ParseSchema, p->iDb, 0,
++    sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0,
+         sqlite3MPrintf("tbl_name='%q'",p->zName), P3_DYNAMIC);
+   }
+ 
+@@ -1392,8 +1527,8 @@
+   if( db->init.busy && pParse->nErr==0 ){
+     Table *pOld;
+     FKey *pFKey; 
+-    Db *pDb = &db->aDb[p->iDb];
+-    pOld = sqlite3HashInsert(&pDb->tblHash, p->zName, strlen(p->zName)+1, p);
++    Schema *pSchema = p->pSchema;
++    pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, strlen(p->zName)+1,p);
+     if( pOld ){
+       assert( p==pOld );  /* Malloc must have failed inside HashInsert() */
+       return;
+@@ -1401,8 +1536,8 @@
+ #ifndef SQLITE_OMIT_FOREIGN_KEY
+     for(pFKey=p->pFKey; pFKey; pFKey=pFKey->pNextFrom){
+       int nTo = strlen(pFKey->zTo) + 1;
+-      pFKey->pNextTo = sqlite3HashFind(&pDb->aFKey, pFKey->zTo, nTo);
+-      sqlite3HashInsert(&pDb->aFKey, pFKey->zTo, nTo, pFKey);
++      pFKey->pNextTo = sqlite3HashFind(&pSchema->aFKey, pFKey->zTo, nTo);
++      sqlite3HashInsert(&pSchema->aFKey, pFKey->zTo, nTo, pFKey);
+     }
+ #endif
+     pParse->pNewTable = 0;
+@@ -1411,9 +1546,14 @@
+ 
+ #ifndef SQLITE_OMIT_ALTERTABLE
+     if( !p->pSelect ){
++      const char *zName = (const char *)pParse->sNameToken.z;
++      int nName;
+       assert( !pSelect && pCons && pEnd );
+-      if( pCons->z==0 ) pCons = pEnd;
+-      p->addColOffset = 13 + (pCons->z - pParse->sNameToken.z);
++      if( pCons->z==0 ){
++        pCons = pEnd;
++      }
++      nName = (const char *)pCons->z - zName;
++      p->addColOffset = 13 + sqlite3utf8CharLen(zName, nName);
+     }
+ #endif
+   }
+@@ -1437,20 +1577,22 @@
+   Token sEnd;
+   DbFixer sFix;
+   Token *pName;
++  int iDb;
+ 
+   if( pParse->nVar>0 ){
+     sqlite3ErrorMsg(pParse, "parameters are not allowed in views");
+     sqlite3SelectDelete(pSelect);
+     return;
+   }
+-  sqlite3StartTable(pParse, pBegin, pName1, pName2, isTemp, 1);
++  sqlite3StartTable(pParse, pBegin, pName1, pName2, isTemp, 1, 0);
+   p = pParse->pNewTable;
+   if( p==0 || pParse->nErr ){
+     sqlite3SelectDelete(pSelect);
+     return;
+   }
+   sqlite3TwoPartName(pParse, pName1, pName2, &pName);
+-  if( sqlite3FixInit(&sFix, pParse, p->iDb, "view", pName)
++  iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema);
++  if( sqlite3FixInit(&sFix, pParse, iDb, "view", pName)
+     && sqlite3FixSelect(&sFix, pSelect)
+   ){
+     sqlite3SelectDelete(pSelect);
+@@ -1464,6 +1606,9 @@
+   */
+   p->pSelect = sqlite3SelectDup(pSelect);
+   sqlite3SelectDelete(pSelect);
++  if( sqlite3MallocFailed() ){
++    return;
++  }
+   if( !pParse->db->init.busy ){
+     sqlite3ViewGetColumnNames(pParse, p);
+   }
+@@ -1517,12 +1662,10 @@
+   ** Actually, this error is caught previously and so the following test
+   ** should always fail.  But we will leave it in place just to be safe.
+   */
+-#if 0
+   if( pTable->nCol<0 ){
+     sqlite3ErrorMsg(pParse, "view %s is circularly defined", pTable->zName);
+     return 1;
+   }
+-#endif
+   assert( pTable->nCol>=0 );
+ 
+   /* If we get this far, it means we need to compute the table names.
+@@ -1534,24 +1677,28 @@
+   */
+   assert( pTable->pSelect );
+   pSel = sqlite3SelectDup(pTable->pSelect);
+-  n = pParse->nTab;
+-  sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
+-  pTable->nCol = -1;
+-  pSelTab = sqlite3ResultSetOfSelect(pParse, 0, pSel);
+-  pParse->nTab = n;
+-  if( pSelTab ){
+-    assert( pTable->aCol==0 );
+-    pTable->nCol = pSelTab->nCol;
+-    pTable->aCol = pSelTab->aCol;
+-    pSelTab->nCol = 0;
+-    pSelTab->aCol = 0;
+-    sqlite3DeleteTable(0, pSelTab);
+-    DbSetProperty(pParse->db, pTable->iDb, DB_UnresetViews);
+-  }else{
+-    pTable->nCol = 0;
++  if( pSel ){
++    n = pParse->nTab;
++    sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
++    pTable->nCol = -1;
++    pSelTab = sqlite3ResultSetOfSelect(pParse, 0, pSel);
++    pParse->nTab = n;
++    if( pSelTab ){
++      assert( pTable->aCol==0 );
++      pTable->nCol = pSelTab->nCol;
++      pTable->aCol = pSelTab->aCol;
++      pSelTab->nCol = 0;
++      pSelTab->aCol = 0;
++      sqlite3DeleteTable(0, pSelTab);
++      pTable->pSchema->flags |= DB_UnresetViews;
++    }else{
++      pTable->nCol = 0;
++      nErr++;
++    }
++    sqlite3SelectDelete(pSel);
++  } else {
+     nErr++;
+   }
+-  sqlite3SelectDelete(pSel);
+   return nErr;  
+ }
+ #endif /* SQLITE_OMIT_VIEW */
+@@ -1563,7 +1710,7 @@
+ static void sqliteViewResetAll(sqlite3 *db, int idx){
+   HashElem *i;
+   if( !DbHasProperty(db, idx, DB_UnresetViews) ) return;
+-  for(i=sqliteHashFirst(&db->aDb[idx].tblHash); i; i=sqliteHashNext(i)){
++  for(i=sqliteHashFirst(&db->aDb[idx].pSchema->tblHash); i;i=sqliteHashNext(i)){
+     Table *pTab = sqliteHashData(i);
+     if( pTab->pSelect ){
+       sqliteResetColumnNames(pTab);
+@@ -1584,15 +1731,18 @@
+ #ifndef SQLITE_OMIT_AUTOVACUUM
+ void sqlite3RootPageMoved(Db *pDb, int iFrom, int iTo){
+   HashElem *pElem;
+-  
+-  for(pElem=sqliteHashFirst(&pDb->tblHash); pElem; pElem=sqliteHashNext(pElem)){
++  Hash *pHash;
++
++  pHash = &pDb->pSchema->tblHash;
++  for(pElem=sqliteHashFirst(pHash); pElem; pElem=sqliteHashNext(pElem)){
+     Table *pTab = sqliteHashData(pElem);
+     if( pTab->tnum==iFrom ){
+       pTab->tnum = iTo;
+       return;
+     }
+   }
+-  for(pElem=sqliteHashFirst(&pDb->idxHash); pElem; pElem=sqliteHashNext(pElem)){
++  pHash = &pDb->pSchema->idxHash;
++  for(pElem=sqliteHashFirst(pHash); pElem; pElem=sqliteHashNext(pElem)){
+     Index *pIdx = sqliteHashData(pElem);
+     if( pIdx->tnum==iFrom ){
+       pIdx->tnum = iTo;
+@@ -1636,9 +1786,10 @@
+ static void destroyTable(Parse *pParse, Table *pTab){
+ #ifdef SQLITE_OMIT_AUTOVACUUM
+   Index *pIdx;
+-  destroyRootPage(pParse, pTab->tnum, pTab->iDb);
++  int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
++  destroyRootPage(pParse, pTab->tnum, iDb);
+   for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+-    destroyRootPage(pParse, pIdx->tnum, pIdx->iDb);
++    destroyRootPage(pParse, pIdx->tnum, iDb);
+   }
+ #else
+   /* If the database may be auto-vacuum capable (if SQLITE_OMIT_AUTOVACUUM
+@@ -1669,14 +1820,18 @@
+     }
+     for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+       int iIdx = pIdx->tnum;
+-      assert( pIdx->iDb==pTab->iDb );
++      assert( pIdx->pSchema==pTab->pSchema );
+       if( (iDestroyed==0 || (iIdx<iDestroyed)) && iIdx>iLargest ){
+         iLargest = iIdx;
+       }
+     }
+-    if( iLargest==0 ) return;
+-    destroyRootPage(pParse, iLargest, pTab->iDb);
+-    iDestroyed = iLargest;
++    if( iLargest==0 ){
++      return;
++    }else{
++      int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
++      destroyRootPage(pParse, iLargest, iDb);
++      iDestroyed = iLargest;
++    }
+   }
+ #endif
+ }
+@@ -1685,24 +1840,31 @@
+ ** This routine is called to do the work of a DROP TABLE statement.
+ ** pName is the name of the table to be dropped.
+ */
+-void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView){
++void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
+   Table *pTab;
+   Vdbe *v;
+   sqlite3 *db = pParse->db;
+   int iDb;
+ 
+-  if( pParse->nErr || sqlite3_malloc_failed ) goto exit_drop_table;
++  if( pParse->nErr || sqlite3MallocFailed() ){
++    goto exit_drop_table;
++  }
+   assert( pName->nSrc==1 );
+   pTab = sqlite3LocateTable(pParse, pName->a[0].zName, pName->a[0].zDatabase);
+ 
+-  if( pTab==0 ) goto exit_drop_table;
+-  iDb = pTab->iDb;
++  if( pTab==0 ){
++    if( noErr ){
++      sqlite3ErrorClear(pParse);
++    }
++    goto exit_drop_table;
++  }
++  iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
+   assert( iDb>=0 && iDb<db->nDb );
+ #ifndef SQLITE_OMIT_AUTHORIZATION
+   {
+     int code;
+-    const char *zTab = SCHEMA_TABLE(pTab->iDb);
+-    const char *zDb = db->aDb[pTab->iDb].zName;
++    const char *zTab = SCHEMA_TABLE(iDb);
++    const char *zDb = db->aDb[iDb].zName;
+     if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){
+       goto exit_drop_table;
+     }
+@@ -1727,7 +1889,7 @@
+     }
+   }
+ #endif
+-  if( pTab->readOnly || pTab==db->aDb[iDb].pSeqTab ){
++  if( pTab->readOnly || pTab==db->aDb[iDb].pSchema->pSeqTab ){
+     sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName);
+     goto exit_drop_table;
+   }
+@@ -1752,7 +1914,6 @@
+   v = sqlite3GetVdbe(pParse);
+   if( v ){
+     Trigger *pTrigger;
+-    int iDb = pTab->iDb;
+     Db *pDb = &db->aDb[iDb];
+     sqlite3BeginWriteOperation(pParse, 0, iDb);
+ 
+@@ -1762,7 +1923,8 @@
+     */
+     pTrigger = pTab->pTrigger;
+     while( pTrigger ){
+-      assert( pTrigger->iDb==iDb || pTrigger->iDb==1 );
++      assert( pTrigger->pSchema==pTab->pSchema || 
++          pTrigger->pSchema==db->aDb[1].pSchema );
+       sqlite3DropTriggerPtr(pParse, pTrigger, 1);
+       pTrigger = pTrigger->pNext;
+     }
+@@ -1958,21 +2120,18 @@
+   int addr1;                     /* Address of top of loop */
+   int tnum;                      /* Root page of index */
+   Vdbe *v;                       /* Generate code into this virtual machine */
++  KeyInfo *pKey;                 /* KeyInfo for index */
++  int iDb = sqlite3SchemaToIndex(pParse->db, pIndex->pSchema);
+ 
+ #ifndef SQLITE_OMIT_AUTHORIZATION
+   if( sqlite3AuthCheck(pParse, SQLITE_REINDEX, pIndex->zName, 0,
+-      pParse->db->aDb[pIndex->iDb].zName ) ){
++      pParse->db->aDb[iDb].zName ) ){
+     return;
+   }
+ #endif
+ 
+-  /* Ensure all the required collation sequences are available. This
+-  ** routine will invoke the collation-needed callback if necessary (and
+-  ** if one has been registered).
+-  */
+-  if( sqlite3CheckIndexCollSeq(pParse, pIndex) ){
+-    return;
+-  }
++  /* Require a write-lock on the table to perform this operation */
++  sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName);
+ 
+   v = sqlite3GetVdbe(pParse);
+   if( v==0 ) return;
+@@ -1981,12 +2140,12 @@
+     tnum = 0;
+   }else{
+     tnum = pIndex->tnum;
+-    sqlite3VdbeAddOp(v, OP_Clear, tnum, pIndex->iDb);
++    sqlite3VdbeAddOp(v, OP_Clear, tnum, iDb);
+   }
+-  sqlite3VdbeAddOp(v, OP_Integer, pIndex->iDb, 0);
+-  sqlite3VdbeOp3(v, OP_OpenWrite, iIdx, tnum,
+-                    (char*)&pIndex->keyInfo, P3_KEYINFO);
+-  sqlite3OpenTableForReading(v, iTab, pTab);
++  sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
++  pKey = sqlite3IndexKeyinfo(pParse, pIndex);
++  sqlite3VdbeOp3(v, OP_OpenWrite, iIdx, tnum, (char *)pKey, P3_KEYINFO_HANDOFF);
++  sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
+   addr1 = sqlite3VdbeAddOp(v, OP_Rewind, iTab, 0);
+   sqlite3GenerateIndexKey(v, pIndex, iTab);
+   if( pIndex->onError!=OE_None ){
+@@ -2027,21 +2186,31 @@
+   ExprList *pList,   /* A list of columns to be indexed */
+   int onError,       /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
+   Token *pStart,     /* The CREATE token that begins a CREATE TABLE statement */
+-  Token *pEnd        /* The ")" that closes the CREATE INDEX statement */
++  Token *pEnd,       /* The ")" that closes the CREATE INDEX statement */
++  int sortOrder,     /* Sort order of primary key when pList==NULL */
++  int ifNotExist     /* Omit error if index already exists */
+ ){
+-  Table *pTab = 0;   /* Table to be indexed */
+-  Index *pIndex = 0; /* The index to be created */
+-  char *zName = 0;
++  Table *pTab = 0;     /* Table to be indexed */
++  Index *pIndex = 0;   /* The index to be created */
++  char *zName = 0;     /* Name of the index */
++  int nName;           /* Number of characters in zName */
+   int i, j;
+-  Token nullId;    /* Fake token for an empty ID list */
+-  DbFixer sFix;    /* For assigning database names to pTable */
++  Token nullId;        /* Fake token for an empty ID list */
++  DbFixer sFix;        /* For assigning database names to pTable */
++  int sortOrderMask;   /* 1 to honor DESC in index.  0 to ignore. */
+   sqlite3 *db = pParse->db;
++  Db *pDb;             /* The specific table containing the indexed database */
++  int iDb;             /* Index of the database that is being written */
++  Token *pName = 0;    /* Unqualified name of the index to create */
++  struct ExprList_item *pListItem; /* For looping over pList */
++  int nCol;
++  int nExtra = 0;
++  char *zExtra;
+ 
+-  int iDb;          /* Index of the database that is being written */
+-  Token *pName = 0; /* Unqualified name of the index to create */
++  if( pParse->nErr || sqlite3MallocFailed() ){
++    goto exit_create_index;
++  }
+ 
+-  if( pParse->nErr || sqlite3_malloc_failed ) goto exit_create_index;
+-
+   /*
+   ** Find the table that is to be indexed.  Return early if not found.
+   */
+@@ -2060,7 +2229,7 @@
+     ** is a temp table. If so, set the database to 1.
+     */
+     pTab = sqlite3SrcListLookup(pParse, pTblName);
+-    if( pName2 && pName2->n==0 && pTab && pTab->iDb==1 ){
++    if( pName2 && pName2->n==0 && pTab && pTab->pSchema==db->aDb[1].pSchema ){
+       iDb = 1;
+     }
+ #endif
+@@ -2075,12 +2244,14 @@
+     pTab = sqlite3LocateTable(pParse, pTblName->a[0].zName, 
+         pTblName->a[0].zDatabase);
+     if( !pTab ) goto exit_create_index;
+-    assert( iDb==pTab->iDb );
++    assert( db->aDb[iDb].pSchema==pTab->pSchema );
+   }else{
+     assert( pName==0 );
+-    pTab =  pParse->pNewTable;
+-    iDb = pTab->iDb;
++    pTab = pParse->pNewTable;
++    if( !pTab ) goto exit_create_index;
++    iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
+   }
++  pDb = &db->aDb[iDb];
+ 
+   if( pTab==0 || pParse->nErr ) goto exit_create_index;
+   if( pTab->readOnly ){
+@@ -2116,8 +2287,10 @@
+     }
+     if( !db->init.busy ){
+       if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) goto exit_create_index;
+-      if( sqlite3FindIndex(db, zName, db->aDb[iDb].zName)!=0 ){
+-        sqlite3ErrorMsg(pParse, "index %s already exists", zName);
++      if( sqlite3FindIndex(db, zName, pDb->zName)!=0 ){
++        if( !ifNotExist ){
++          sqlite3ErrorMsg(pParse, "index %s already exists", zName);
++        }
+         goto exit_create_index;
+       }
+       if( sqlite3FindTable(db, zName, 0)!=0 ){
+@@ -2140,7 +2313,7 @@
+   */
+ #ifndef SQLITE_OMIT_AUTHORIZATION
+   {
+-    const char *zDb = db->aDb[iDb].zName;
++    const char *zDb = pDb->zName;
+     if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iDb), 0, zDb) ){
+       goto exit_create_index;
+     }
+@@ -2157,56 +2330,96 @@
+   ** So create a fake list to simulate this.
+   */
+   if( pList==0 ){
+-    nullId.z = pTab->aCol[pTab->nCol-1].zName;
+-    nullId.n = strlen(nullId.z);
++    nullId.z = (u8*)pTab->aCol[pTab->nCol-1].zName;
++    nullId.n = strlen((char*)nullId.z);
+     pList = sqlite3ExprListAppend(0, 0, &nullId);
+     if( pList==0 ) goto exit_create_index;
++    pList->a[0].sortOrder = sortOrder;
+   }
+ 
++  /* Figure out how many bytes of space are required to store explicitly
++  ** specified collation sequence names.
++  */
++  for(i=0; i<pList->nExpr; i++){
++    Expr *pExpr = pList->a[i].pExpr;
++    if( pExpr ){
++      nExtra += (1 + strlen(pExpr->pColl->zName));
++    }
++  }
++
+   /* 
+   ** Allocate the index structure. 
+   */
+-  pIndex = sqliteMalloc( sizeof(Index) + strlen(zName) + 1 + sizeof(int) +
+-                        (sizeof(int)*2 + sizeof(CollSeq*))*pList->nExpr );
+-  if( sqlite3_malloc_failed ) goto exit_create_index;
+-  pIndex->aiColumn = (int*)&pIndex->keyInfo.aColl[pList->nExpr];
+-  pIndex->aiRowEst = (unsigned*)&pIndex->aiColumn[pList->nExpr];
+-  pIndex->zName = (char*)&pIndex->aiRowEst[pList->nExpr+1];
++  nName = strlen(zName);
++  nCol = pList->nExpr;
++  pIndex = sqliteMalloc( 
++      sizeof(Index) +              /* Index structure  */
++      sizeof(int)*nCol +           /* Index.aiColumn   */
++      sizeof(int)*(nCol+1) +       /* Index.aiRowEst   */
++      sizeof(char *)*nCol +        /* Index.azColl     */
++      sizeof(u8)*nCol +            /* Index.aSortOrder */
++      nName + 1 +                  /* Index.zName      */
++      nExtra                       /* Collation sequence names */
++  );
++  if( sqlite3MallocFailed() ) goto exit_create_index;
++  pIndex->azColl = (char**)(&pIndex[1]);
++  pIndex->aiColumn = (int *)(&pIndex->azColl[nCol]);
++  pIndex->aiRowEst = (unsigned *)(&pIndex->aiColumn[nCol]);
++  pIndex->aSortOrder = (u8 *)(&pIndex->aiRowEst[nCol+1]);
++  pIndex->zName = (char *)(&pIndex->aSortOrder[nCol]);
++  zExtra = (char *)(&pIndex->zName[nName+1]);
+   strcpy(pIndex->zName, zName);
+   pIndex->pTable = pTab;
+   pIndex->nColumn = pList->nExpr;
+   pIndex->onError = onError;
+   pIndex->autoIndex = pName==0;
+-  pIndex->iDb = iDb;
++  pIndex->pSchema = db->aDb[iDb].pSchema;
+ 
++  /* Check to see if we should honor DESC requests on index columns
++  */
++  if( pDb->pSchema->file_format>=4 ){
++    sortOrderMask = -1;   /* Honor DESC */
++  }else{
++    sortOrderMask = 0;    /* Ignore DESC */
++  }
++
+   /* Scan the names of the columns of the table to be indexed and
+   ** load the column indices into the Index structure.  Report an error
+   ** if any column is not found.
+   */
+-  for(i=0; i<pList->nExpr; i++){
+-    for(j=0; j<pTab->nCol; j++){
+-      if( sqlite3StrICmp(pList->a[i].zName, pTab->aCol[j].zName)==0 ) break;
++  for(i=0, pListItem=pList->a; i<pList->nExpr; i++, pListItem++){
++    const char *zColName = pListItem->zName;
++    Column *pTabCol;
++    int requestedSortOrder;
++    char *zColl;                   /* Collation sequence */
++
++    for(j=0, pTabCol=pTab->aCol; j<pTab->nCol; j++, pTabCol++){
++      if( sqlite3StrICmp(zColName, pTabCol->zName)==0 ) break;
+     }
+     if( j>=pTab->nCol ){
+       sqlite3ErrorMsg(pParse, "table %s has no column named %s",
+-        pTab->zName, pList->a[i].zName);
++        pTab->zName, zColName);
+       goto exit_create_index;
+     }
+     pIndex->aiColumn[i] = j;
+-    if( pList->a[i].pExpr ){
+-      assert( pList->a[i].pExpr->pColl );
+-      pIndex->keyInfo.aColl[i] = pList->a[i].pExpr->pColl;
++    if( pListItem->pExpr ){
++      assert( pListItem->pExpr->pColl );
++      zColl = zExtra;
++      strcpy(zExtra, pListItem->pExpr->pColl->zName);
++      zExtra += (strlen(zColl) + 1);
+     }else{
+-      pIndex->keyInfo.aColl[i] = pTab->aCol[j].pColl;
++      zColl = pTab->aCol[j].zColl;
++      if( !zColl ){
++        zColl = db->pDfltColl->zName;
++      }
+     }
+-    assert( pIndex->keyInfo.aColl[i] );
+-    if( !db->init.busy && 
+-        sqlite3CheckCollSeq(pParse, pIndex->keyInfo.aColl[i]) 
+-    ){
++    if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl, -1) ){
+       goto exit_create_index;
+     }
++    pIndex->azColl[i] = zColl;
++    requestedSortOrder = pListItem->sortOrder & sortOrderMask;
++    pIndex->aSortOrder[i] = requestedSortOrder;
+   }
+-  pIndex->keyInfo.nField = pList->nExpr;
+   sqlite3DefaultRowEst(pIndex);
+ 
+   if( pTab==pParse->pNewTable ){
+@@ -2232,8 +2445,11 @@
+ 
+       if( pIdx->nColumn!=pIndex->nColumn ) continue;
+       for(k=0; k<pIdx->nColumn; k++){
++        const char *z1 = pIdx->azColl[k];
++        const char *z2 = pIndex->azColl[k];
+         if( pIdx->aiColumn[k]!=pIndex->aiColumn[k] ) break;
+-        if( pIdx->keyInfo.aColl[k]!=pIndex->keyInfo.aColl[k] ) break;
++        if( pIdx->aSortOrder[k]!=pIndex->aSortOrder[k] ) break;
++        if( z1!=z2 && sqlite3StrICmp(z1, z2) ) break;
+       }
+       if( k==pIdx->nColumn ){
+         if( pIdx->onError!=pIndex->onError ){
+@@ -2262,7 +2478,7 @@
+   */
+   if( db->init.busy ){
+     Index *p;
+-    p = sqlite3HashInsert(&db->aDb[pIndex->iDb].idxHash, 
++    p = sqlite3HashInsert(&pIndex->pSchema->idxHash, 
+                          pIndex->zName, strlen(pIndex->zName)+1, pIndex);
+     if( p ){
+       assert( p==pIndex );  /* Malloc must have failed */
+@@ -2297,6 +2513,7 @@
+     v = sqlite3GetVdbe(pParse);
+     if( v==0 ) goto exit_create_index;
+ 
++
+     /* Create the rootpage for the index
+     */
+     sqlite3BeginWriteOperation(pParse, 1, iDb);
+@@ -2375,6 +2592,22 @@
+ }
+ 
+ /*
++** Generate code to make sure the file format number is at least minFormat.
++** The generated code will increase the file format number if necessary.
++*/
++void sqlite3MinimumFileFormat(Parse *pParse, int iDb, int minFormat){
++  Vdbe *v;
++  v = sqlite3GetVdbe(pParse);
++  if( v ){
++    sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 1);
++    sqlite3VdbeAddOp(v, OP_Integer, minFormat, 0);
++    sqlite3VdbeAddOp(v, OP_Ge, 0, sqlite3VdbeCurrentAddr(v)+3);
++    sqlite3VdbeAddOp(v, OP_Integer, minFormat, 0);
++    sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 1);
++  }
++}
++
++/*
+ ** Fill the Index.aiRowEst[] array with default information - information
+ ** to be used when we have not run the ANALYZE command.
+ **
+@@ -2409,12 +2642,13 @@
+ ** This routine will drop an existing named index.  This routine
+ ** implements the DROP INDEX statement.
+ */
+-void sqlite3DropIndex(Parse *pParse, SrcList *pName){
++void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
+   Index *pIndex;
+   Vdbe *v;
+   sqlite3 *db = pParse->db;
++  int iDb;
+ 
+-  if( pParse->nErr || sqlite3_malloc_failed ){
++  if( pParse->nErr || sqlite3MallocFailed() ){
+     goto exit_drop_index;
+   }
+   assert( pName->nSrc==1 );
+@@ -2423,7 +2657,9 @@
+   }
+   pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase);
+   if( pIndex==0 ){
+-    sqlite3ErrorMsg(pParse, "no such index: %S", pName, 0);
++    if( !ifExists ){
++      sqlite3ErrorMsg(pParse, "no such index: %S", pName, 0);
++    }
+     pParse->checkSchema = 1;
+     goto exit_drop_index;
+   }
+@@ -2432,16 +2668,17 @@
+       "or PRIMARY KEY constraint cannot be dropped", 0);
+     goto exit_drop_index;
+   }
++  iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
+ #ifndef SQLITE_OMIT_AUTHORIZATION
+   {
+     int code = SQLITE_DROP_INDEX;
+     Table *pTab = pIndex->pTable;
+-    const char *zDb = db->aDb[pIndex->iDb].zName;
+-    const char *zTab = SCHEMA_TABLE(pIndex->iDb);
++    const char *zDb = db->aDb[iDb].zName;
++    const char *zTab = SCHEMA_TABLE(iDb);
+     if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
+       goto exit_drop_index;
+     }
+-    if( !OMIT_TEMPDB && pIndex->iDb ) code = SQLITE_DROP_TEMP_INDEX;
++    if( !OMIT_TEMPDB && iDb ) code = SQLITE_DROP_TEMP_INDEX;
+     if( sqlite3AuthCheck(pParse, code, pIndex->zName, pTab->zName, zDb) ){
+       goto exit_drop_index;
+     }
+@@ -2451,7 +2688,6 @@
+   /* Generate code to remove the index and from the master table */
+   v = sqlite3GetVdbe(pParse);
+   if( v ){
+-    int iDb = pIndex->iDb;
+     sqlite3NestedParse(pParse,
+        "DELETE FROM %Q.%s WHERE name=%Q",
+        db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
+@@ -2611,6 +2847,7 @@
+   pItem->zName = sqlite3NameFromToken(pTable);
+   pItem->zDatabase = sqlite3NameFromToken(pDatabase);
+   pItem->iCursor = -1;
++  pItem->isPopulated = 0;
+   pList->nSrc++;
+   return pList;
+ }
+@@ -2621,11 +2858,14 @@
+ void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){
+   int i;
+   struct SrcList_item *pItem;
+-  for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
+-    if( pItem->iCursor>=0 ) break;
+-    pItem->iCursor = pParse->nTab++;
+-    if( pItem->pSelect ){
+-      sqlite3SrcListAssignCursors(pParse, pItem->pSelect->pSrc);
++  assert(pList || sqlite3MallocFailed() );
++  if( pList ){
++    for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
++      if( pItem->iCursor>=0 ) break;
++      pItem->iCursor = pParse->nTab++;
++      if( pItem->pSelect ){
++        sqlite3SrcListAssignCursors(pParse, pItem->pSelect->pSrc);
++      }
+     }
+   }
+ }
+@@ -2667,7 +2907,7 @@
+   int i;
+ 
+   if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
+-  if( pParse->nErr || sqlite3_malloc_failed ) return;
++  if( pParse->nErr || sqlite3MallocFailed() ) return;
+   if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ) return;
+ 
+   v = sqlite3GetVdbe(pParse);
+@@ -2688,7 +2928,7 @@
+   Vdbe *v;
+ 
+   if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
+-  if( pParse->nErr || sqlite3_malloc_failed ) return;
++  if( pParse->nErr || sqlite3MallocFailed() ) return;
+   if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ) return;
+ 
+   v = sqlite3GetVdbe(pParse);
+@@ -2705,7 +2945,7 @@
+   Vdbe *v;
+ 
+   if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
+-  if( pParse->nErr || sqlite3_malloc_failed ) return;
++  if( pParse->nErr || sqlite3MallocFailed() ) return;
+   if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ) return;
+ 
+   v = sqlite3GetVdbe(pParse);
+@@ -2737,6 +2977,7 @@
+         return 1;
+       }
+     }
++    assert( db->aDb[1].pSchema );
+   }
+   return 0;
+ }
+@@ -2781,7 +3022,7 @@
+     mask = 1<<iDb;
+     if( (pParse->cookieMask & mask)==0 ){
+       pParse->cookieMask |= mask;
+-      pParse->cookieValue[iDb] = db->aDb[iDb].schema_cookie;
++      pParse->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie;
+       if( !OMIT_TEMPDB && iDb==1 ){
+         sqlite3OpenTempDatabase(pParse);
+       }
+@@ -2825,12 +3066,13 @@
+ ** true if it does and false if it does not.
+ */
+ #ifndef SQLITE_OMIT_REINDEX
+-static int collationMatch(CollSeq *pColl, Index *pIndex){
+-  int n = pIndex->keyInfo.nField;
+-  CollSeq **pp = pIndex->keyInfo.aColl;
+-  while( n-- ){
+-    if( *pp==pColl ) return 1;
+-    pp++;
++static int collationMatch(const char *zColl, Index *pIndex){
++  int i;
++  for(i=0; i<pIndex->nColumn; i++){
++    const char *z = pIndex->azColl[i];
++    if( z==zColl || (z && zColl && 0==sqlite3StrICmp(z, zColl)) ){
++      return 1;
++    }
+   }
+   return 0;
+ }
+@@ -2841,12 +3083,13 @@
+ ** If pColl==0 then recompute all indices of pTab.
+ */
+ #ifndef SQLITE_OMIT_REINDEX
+-static void reindexTable(Parse *pParse, Table *pTab, CollSeq *pColl){
++static void reindexTable(Parse *pParse, Table *pTab, char const *zColl){
+   Index *pIndex;              /* An index associated with pTab */
+ 
+   for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){
+-    if( pColl==0 || collationMatch(pColl,pIndex) ){
+-      sqlite3BeginWriteOperation(pParse, 0, pTab->iDb);
++    if( zColl==0 || collationMatch(zColl, pIndex) ){
++      int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
++      sqlite3BeginWriteOperation(pParse, 0, iDb);
+       sqlite3RefillIndex(pParse, pIndex, -1);
+     }
+   }
+@@ -2859,7 +3102,7 @@
+ ** all indices everywhere.
+ */
+ #ifndef SQLITE_OMIT_REINDEX
+-static void reindexDatabases(Parse *pParse, CollSeq *pColl){
++static void reindexDatabases(Parse *pParse, char const *zColl){
+   Db *pDb;                    /* A single database */
+   int iDb;                    /* The database index number */
+   sqlite3 *db = pParse->db;   /* The database connection */
+@@ -2868,9 +3111,9 @@
+ 
+   for(iDb=0, pDb=db->aDb; iDb<db->nDb; iDb++, pDb++){
+     if( pDb==0 ) continue;
+-    for(k=sqliteHashFirst(&pDb->tblHash);  k; k=sqliteHashNext(k)){
++    for(k=sqliteHashFirst(&pDb->pSchema->tblHash);  k; k=sqliteHashNext(k)){
+       pTab = (Table*)sqliteHashData(k);
+-      reindexTable(pParse, pTab, pColl);
++      reindexTable(pParse, pTab, zColl);
+     }
+   }
+ }
+@@ -2910,9 +3153,14 @@
+     reindexDatabases(pParse, 0);
+     return;
+   }else if( pName2==0 || pName2->z==0 ){
+-    pColl = sqlite3FindCollSeq(db, db->enc, pName1->z, pName1->n, 0);
++    assert( pName1->z );
++    pColl = sqlite3FindCollSeq(db, ENC(db), (char*)pName1->z, pName1->n, 0);
+     if( pColl ){
+-      reindexDatabases(pParse, pColl);
++      char *zColl = sqliteStrNDup((const char *)pName1->z, pName1->n);
++      if( zColl ){
++        reindexDatabases(pParse, zColl);
++        sqliteFree(zColl);
++      }
+       return;
+     }
+   }
+@@ -2936,3 +3184,38 @@
+   sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed");
+ }
+ #endif
++
++/*
++** Return a dynamicly allocated KeyInfo structure that can be used
++** with OP_OpenRead or OP_OpenWrite to access database index pIdx.
++**
++** If successful, a pointer to the new structure is returned. In this case
++** the caller is responsible for calling sqliteFree() on the returned 
++** pointer. If an error occurs (out of memory or missing collation 
++** sequence), NULL is returned and the state of pParse updated to reflect
++** the error.
++*/
++KeyInfo *sqlite3IndexKeyinfo(Parse *pParse, Index *pIdx){
++  int i;
++  int nCol = pIdx->nColumn;
++  int nBytes = sizeof(KeyInfo) + (nCol-1)*sizeof(CollSeq*) + nCol;
++  KeyInfo *pKey = (KeyInfo *)sqliteMalloc(nBytes);
++
++  if( pKey ){
++    pKey->aSortOrder = (u8 *)&(pKey->aColl[nCol]);
++    assert( &pKey->aSortOrder[nCol]==&(((u8 *)pKey)[nBytes]) );
++    for(i=0; i<nCol; i++){
++      char *zColl = pIdx->azColl[i];
++      assert( zColl );
++      pKey->aColl[i] = sqlite3LocateCollSeq(pParse, zColl, -1);
++      pKey->aSortOrder[i] = pIdx->aSortOrder[i];
++    }
++    pKey->nField = nCol;
++  }
++
++  if( pParse->nErr ){
++    sqliteFree(pKey);
++    pKey = 0;
++  }
++  return pKey;
++}
+Index: sqlite/vdbeInt.h
+===================================================================
+--- amarok/src/sqlite/vdbeInt.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/vdbeInt.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -60,6 +60,7 @@
+ */
+ struct Cursor {
+   BtCursor *pCursor;    /* The cursor structure of the backend */
++  int iDb;              /* Index of cursor database in db->aDb[] (or -1) */
+   i64 lastRowid;        /* Last rowid from a Next or NextIdx operation */
+   i64 nextRowid;        /* Next rowid returned by OP_NewRowid */
+   Bool zeroed;          /* True if zeroed out and ready for reuse */
+@@ -85,9 +86,10 @@
+ 
+   /* Cached information about the header for the data record that the
+   ** cursor is currently pointing to.  Only valid if cacheValid is true.
+-  ** zRow might point to (ephemeral) data for the current row, or it might
+-  ** be NULL. */
+-  Bool cacheValid;      /* True if the cache is valid */
++  ** aRow might point to (ephemeral) data for the current row, or it might
++  ** be NULL.
++  */
++  int cacheStatus;      /* Cache is valid if this matches Vdbe.cacheCtr */
+   int payloadSize;      /* Total number of bytes in the record */
+   u32 *aType;           /* Type values for all entries in the record */
+   u32 *aOffset;         /* Cached offsets to the start of each columns data */
+@@ -103,6 +105,11 @@
+ #define NBFS 32
+ 
+ /*
++** A value for Cursor.cacheValid that means the cache is always invalid.
++*/
++#define CACHE_STALE 0
++
++/*
+ ** Internally, the vdbe manipulates nearly all SQL values as Mem
+ ** structures. Each Mem struct may cache multiple representations (string,
+ ** integer etc.) of the same value.  A value (and therefore Mem structure)
+@@ -250,7 +257,7 @@
+ */
+ typedef struct Context Context;
+ struct Context {
+-  int lastRowid;    /* Last insert rowid (sqlite3.lastRowid) */
++  i64 lastRowid;    /* Last insert rowid (sqlite3.lastRowid) */
+   int nChange;      /* Statement changes (Vdbe.nChanges)     */
+   Fifo sFifo;       /* Records that will participate in a DELETE or UPDATE */
+ };
+@@ -286,6 +293,7 @@
+   int nMem;               /* Number of memory locations currently allocated */
+   Mem *aMem;              /* The memory locations */
+   int nCallback;          /* Number of callbacks invoked so far */
++  int cacheCtr;           /* Cursor row cache generation counter */
+   Fifo sFifo;             /* A list of ROWIDs */
+   int contextStackTop;    /* Index of top element in the context stack */
+   int contextStackDepth;  /* The size of the "context" stack */
+@@ -306,6 +314,7 @@
+   u8 changeCntOn;         /* True to update the change-counter */
+   u8 aborted;             /* True if ROLLBACK in another VM causes an abort */
+   u8 expired;             /* True if the VM needs to be recompiled */
++  u8 minWriteFileFormat;  /* Minimum file format for writable database files */
+   int nChange;            /* Number of db changes made since last reset */
+   i64 startTime;          /* Time when query started - used for profiling */
+ };
+@@ -331,8 +340,8 @@
+ void sqlite3VdbePrintSql(Vdbe*);
+ #endif
+ int sqlite3VdbeSerialTypeLen(u32);
+-u32 sqlite3VdbeSerialType(Mem*);
+-int sqlite3VdbeSerialPut(unsigned char*, Mem*);
++u32 sqlite3VdbeSerialType(Mem*, int);
++int sqlite3VdbeSerialPut(unsigned char*, Mem*, int);
+ int sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
+ void sqlite3VdbeDeleteAuxData(VdbeFunc*, int);
+ 
+@@ -360,10 +369,12 @@
+ i64 sqlite3VdbeIntValue(Mem*);
+ int sqlite3VdbeMemIntegerify(Mem*);
+ double sqlite3VdbeRealValue(Mem*);
++void sqlite3VdbeIntegerAffinity(Mem*);
+ int sqlite3VdbeMemRealify(Mem*);
++int sqlite3VdbeMemNumerify(Mem*);
+ int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*);
+ void sqlite3VdbeMemRelease(Mem *p);
+-void sqlite3VdbeMemFinalize(Mem*, FuncDef*);
++int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
+ #ifndef NDEBUG
+ void sqlite3VdbeMemSanity(Mem*, u8);
+ int sqlite3VdbeOpcodeNoPush(u8);
+Index: sqlite/opcodes.h
+===================================================================
+--- amarok/src/sqlite/opcodes.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/opcodes.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -1,149 +1,159 @@
+ /* Automatically generated.  Do not edit */
+ /* See the mkopcodeh.awk script for details */
+ #define OP_MemLoad                              1
+-#define OP_HexBlob                            134   /* same as TK_BLOB     */
++#define OP_HexBlob                            125   /* same as TK_BLOB     */
+ #define OP_Column                               2
+ #define OP_SetCookie                            3
+ #define OP_IfMemPos                             4
+-#define OP_Real                               133   /* same as TK_FLOAT    */
++#define OP_Real                               124   /* same as TK_FLOAT    */
+ #define OP_Sequence                             5
+ #define OP_MoveGt                               6
+-#define OP_Ge                                  80   /* same as TK_GE       */
++#define OP_Ge                                  71   /* same as TK_GE       */
+ #define OP_RowKey                               7
+-#define OP_Eq                                  76   /* same as TK_EQ       */
++#define OP_Eq                                  67   /* same as TK_EQ       */
+ #define OP_OpenWrite                            8
+-#define OP_NotNull                             74   /* same as TK_NOTNULL  */
++#define OP_NotNull                             65   /* same as TK_NOTNULL  */
+ #define OP_If                                   9
+-#define OP_ToInt                               10
+-#define OP_String8                             95   /* same as TK_STRING   */
+-#define OP_Pop                                 11
+-#define OP_CollSeq                             12
+-#define OP_OpenRead                            13
+-#define OP_Expire                              14
+-#define OP_AutoCommit                          15
+-#define OP_Gt                                  77   /* same as TK_GT       */
+-#define OP_IntegrityCk                         16
++#define OP_ToInt                              140   /* same as TK_TO_INT   */
++#define OP_String8                             86   /* same as TK_STRING   */
++#define OP_Pop                                 10
++#define OP_CollSeq                             11
++#define OP_OpenRead                            12
++#define OP_Expire                              13
++#define OP_AutoCommit                          14
++#define OP_Gt                                  68   /* same as TK_GT       */
++#define OP_IntegrityCk                         15
+ #define OP_Sort                                17
+ #define OP_Function                            18
+-#define OP_And                                 68   /* same as TK_AND      */
+-#define OP_Subtract                            87   /* same as TK_MINUS    */
++#define OP_And                                 60   /* same as TK_AND      */
++#define OP_Subtract                            78   /* same as TK_MINUS    */
+ #define OP_Noop                                19
+ #define OP_Return                              20
+-#define OP_Remainder                           90   /* same as TK_REM      */
++#define OP_Remainder                           81   /* same as TK_REM      */
+ #define OP_NewRowid                            21
+-#define OP_Multiply                            88   /* same as TK_STAR     */
+-#define OP_Variable                            22
+-#define OP_String                              23
+-#define OP_ParseSchema                         24
+-#define OP_Close                               25
+-#define OP_CreateIndex                         26
+-#define OP_IsUnique                            27
+-#define OP_IdxIsNull                           28
+-#define OP_NotFound                            29
+-#define OP_Int64                               30
+-#define OP_MustBeInt                           31
+-#define OP_Halt                                32
+-#define OP_Rowid                               33
+-#define OP_IdxLT                               34
+-#define OP_AddImm                              35
+-#define OP_Statement                           36
+-#define OP_RowData                             37
+-#define OP_MemMax                              38
+-#define OP_Push                                39
+-#define OP_Or                                  67   /* same as TK_OR       */
+-#define OP_NotExists                           40
+-#define OP_MemIncr                             41
+-#define OP_Gosub                               42
+-#define OP_Divide                              89   /* same as TK_SLASH    */
+-#define OP_Integer                             43
+-#define OP_ToNumeric                           44
+-#define OP_MemInt                              45
+-#define OP_Prev                                46
+-#define OP_Concat                              91   /* same as TK_CONCAT   */
+-#define OP_BitAnd                              82   /* same as TK_BITAND   */
+-#define OP_CreateTable                         47
+-#define OP_Last                                48
+-#define OP_IsNull                              73   /* same as TK_ISNULL   */
+-#define OP_IdxRowid                            49
+-#define OP_MakeIdxRec                          50
+-#define OP_ShiftRight                          85   /* same as TK_RSHIFT   */
+-#define OP_ResetCount                          51
+-#define OP_FifoWrite                           52
+-#define OP_Callback                            53
+-#define OP_ContextPush                         54
+-#define OP_DropTrigger                         55
+-#define OP_DropIndex                           56
+-#define OP_IdxGE                               57
+-#define OP_IdxDelete                           58
+-#define OP_Vacuum                              59
+-#define OP_MoveLe                              60
+-#define OP_IfNot                               61
+-#define OP_DropTable                           62
+-#define OP_MakeRecord                          63
+-#define OP_ToBlob                              64
+-#define OP_Delete                              65
+-#define OP_AggFinal                            66
+-#define OP_ShiftLeft                           84   /* same as TK_LSHIFT   */
+-#define OP_Dup                                 70
+-#define OP_Goto                                71
+-#define OP_FifoRead                            72
+-#define OP_Clear                               81
+-#define OP_IdxGT                               93
++#define OP_Multiply                            79   /* same as TK_STAR     */
++#define OP_IfMemNeg                            22
++#define OP_Variable                            23
++#define OP_String                              24
++#define OP_RealAffinity                        25
++#define OP_ParseSchema                         26
++#define OP_Close                               27
++#define OP_CreateIndex                         28
++#define OP_IsUnique                            29
++#define OP_IdxIsNull                           30
++#define OP_NotFound                            31
++#define OP_Int64                               32
++#define OP_MustBeInt                           33
++#define OP_Halt                                34
++#define OP_Rowid                               35
++#define OP_IdxLT                               36
++#define OP_AddImm                              37
++#define OP_Statement                           38
++#define OP_RowData                             39
++#define OP_MemMax                              40
++#define OP_Push                                41
++#define OP_Or                                  59   /* same as TK_OR       */
++#define OP_NotExists                           42
++#define OP_MemIncr                             43
++#define OP_Gosub                               44
++#define OP_Divide                              80   /* same as TK_SLASH    */
++#define OP_Integer                             45
++#define OP_ToNumeric                          139   /* same as TK_TO_NUMERIC*/
++#define OP_MemInt                              46
++#define OP_Prev                                47
++#define OP_Concat                              82   /* same as TK_CONCAT   */
++#define OP_BitAnd                              73   /* same as TK_BITAND   */
++#define OP_CreateTable                         48
++#define OP_Last                                49
++#define OP_IsNull                              64   /* same as TK_ISNULL   */
++#define OP_IdxRowid                            50
++#define OP_MakeIdxRec                          51
++#define OP_ShiftRight                          76   /* same as TK_RSHIFT   */
++#define OP_ResetCount                          52
++#define OP_FifoWrite                           53
++#define OP_Callback                            54
++#define OP_ContextPush                         55
++#define OP_DropTrigger                         56
++#define OP_DropIndex                           57
++#define OP_IdxGE                               58
++#define OP_IdxDelete                           61
++#define OP_Vacuum                              62
++#define OP_MoveLe                              63
++#define OP_IfNot                               72
++#define OP_DropTable                           84
++#define OP_MakeRecord                          87
++#define OP_ToBlob                             138   /* same as TK_TO_BLOB  */
++#define OP_Delete                              88
++#define OP_AggFinal                            89
++#define OP_ShiftLeft                           75   /* same as TK_LSHIFT   */
++#define OP_Dup                                 90
++#define OP_Goto                                91
++#define OP_TableLock                           92
++#define OP_FifoRead                            93
++#define OP_Clear                               94
++#define OP_IdxGT                               95
+ #define OP_MoveLt                              96
+-#define OP_Le                                  78   /* same as TK_LE       */
++#define OP_Le                                  69   /* same as TK_LE       */
+ #define OP_VerifyCookie                        97
+ #define OP_AggStep                             98
+ #define OP_Pull                                99
+-#define OP_ToText                             100
+-#define OP_Not                                 69   /* same as TK_NOT      */
+-#define OP_SetNumColumns                      101
+-#define OP_AbsValue                           102
+-#define OP_Transaction                        103
+-#define OP_Negative                            92   /* same as TK_UMINUS   */
+-#define OP_Ne                                  75   /* same as TK_NE       */
+-#define OP_ContextPop                         104
+-#define OP_BitOr                               83   /* same as TK_BITOR    */
+-#define OP_Next                               105
+-#define OP_IdxInsert                          106
+-#define OP_Distinct                           107
+-#define OP_Lt                                  79   /* same as TK_LT       */
+-#define OP_Insert                             108
+-#define OP_Destroy                            109
+-#define OP_ReadCookie                         110
+-#define OP_ForceInt                           111
+-#define OP_LoadAnalysis                       112
+-#define OP_OpenVirtual                        113
+-#define OP_Explain                            114
++#define OP_ToText                             137   /* same as TK_TO_TEXT  */
++#define OP_Not                                 16   /* same as TK_NOT      */
++#define OP_ToReal                             141   /* same as TK_TO_REAL  */
++#define OP_SetNumColumns                      100
++#define OP_AbsValue                           101
++#define OP_Transaction                        102
++#define OP_Negative                            83   /* same as TK_UMINUS   */
++#define OP_Ne                                  66   /* same as TK_NE       */
++#define OP_ContextPop                         103
++#define OP_BitOr                               74   /* same as TK_BITOR    */
++#define OP_Next                               104
++#define OP_IdxInsert                          105
++#define OP_Distinct                           106
++#define OP_Lt                                  70   /* same as TK_LT       */
++#define OP_Insert                             107
++#define OP_Destroy                            108
++#define OP_ReadCookie                         109
++#define OP_ForceInt                           110
++#define OP_LoadAnalysis                       111
++#define OP_OpenVirtual                        112
++#define OP_Explain                            113
++#define OP_IfMemZero                          114
+ #define OP_OpenPseudo                         115
+ #define OP_Null                               116
+ #define OP_Blob                               117
+-#define OP_Add                                 86   /* same as TK_PLUS     */
++#define OP_Add                                 77   /* same as TK_PLUS     */
+ #define OP_MemStore                           118
+ #define OP_Rewind                             119
+ #define OP_MoveGe                             120
+-#define OP_BitNot                              94   /* same as TK_BITNOT   */
++#define OP_BitNot                              85   /* same as TK_BITNOT   */
+ #define OP_MemMove                            121
+ #define OP_MemNull                            122
+ #define OP_Found                              123
+-#define OP_NullRow                            124
++#define OP_NullRow                            126
+ 
+ /* The following opcode values are never used */
+-#define OP_NotUsed_125                        125
+-#define OP_NotUsed_126                        126
+ #define OP_NotUsed_127                        127
+ #define OP_NotUsed_128                        128
+ #define OP_NotUsed_129                        129
+ #define OP_NotUsed_130                        130
+ #define OP_NotUsed_131                        131
+ #define OP_NotUsed_132                        132
++#define OP_NotUsed_133                        133
++#define OP_NotUsed_134                        134
++#define OP_NotUsed_135                        135
++#define OP_NotUsed_136                        136
+ 
+-#define NOPUSH_MASK_0 65368
+-#define NOPUSH_MASK_1 47898
+-#define NOPUSH_MASK_2 22493
+-#define NOPUSH_MASK_3 32761
+-#define NOPUSH_MASK_4 65215
+-#define NOPUSH_MASK_5 30719
+-#define NOPUSH_MASK_6 40895
+-#define NOPUSH_MASK_7 6603
+-#define NOPUSH_MASK_8 0
+-#define NOPUSH_MASK_9 0
++/* Opcodes that are guaranteed to never push a value onto the stack
++** contain a 1 their corresponding position of the following mask
++** set.  See the opcodeNoPush() function in vdbeaux.c  */
++#define NOPUSH_MASK_0 0x7f58
++#define NOPUSH_MASK_1 0xee5b
++#define NOPUSH_MASK_2 0x9f76
++#define NOPUSH_MASK_3 0xfff2
++#define NOPUSH_MASK_4 0xffff
++#define NOPUSH_MASK_5 0xdb3b
++#define NOPUSH_MASK_6 0xcfdf
++#define NOPUSH_MASK_7 0x49cd
++#define NOPUSH_MASK_8 0x3e00
++#define NOPUSH_MASK_9 0x0000
+Index: sqlite/btree.c
+===================================================================
+--- amarok/src/sqlite/btree.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/btree.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -230,6 +230,7 @@
+ 
+ /* Forward declarations */
+ typedef struct MemPage MemPage;
++typedef struct BtLock BtLock;
+ 
+ /*
+ ** This is a magic string that appears at the beginning of every
+@@ -285,10 +286,10 @@
+   u16 nFree;           /* Number of free bytes on the page */
+   u16 nCell;           /* Number of cells on this page, local and ovfl */
+   struct _OvflCell {   /* Cells that will not fit on aData[] */
+-    u8 *pCell;           /* Pointers to the body of the overflow cell */
+-    u16 idx;             /* Insert this cell before idx-th non-overflow cell */
++    u8 *pCell;          /* Pointers to the body of the overflow cell */
++    u16 idx;            /* Insert this cell before idx-th non-overflow cell */
+   } aOvfl[5];
+-  struct Btree *pBt;   /* Pointer back to BTree structure */
++  BtShared *pBt;       /* Pointer back to BTree structure */
+   u8 *aData;           /* Pointer back to the start of the page */
+   Pgno pgno;           /* Page number for this page */
+   MemPage *pParent;    /* The parent of this page.  NULL for root */
+@@ -301,14 +302,32 @@
+ */
+ #define EXTRA_SIZE sizeof(MemPage)
+ 
++/* Btree handle */
++struct Btree {
++  sqlite3 *pSqlite;
++  BtShared *pBt;
++  u8 inTrans;            /* TRANS_NONE, TRANS_READ or TRANS_WRITE */
++};
++
+ /*
++** Btree.inTrans may take one of the following values.
++**
++** If the shared-data extension is enabled, there may be multiple users
++** of the Btree structure. At most one of these may open a write transaction,
++** but any number may have active read transactions. Variable Btree.pDb 
++** points to the handle that owns any current write-transaction.
++*/
++#define TRANS_NONE  0
++#define TRANS_READ  1
++#define TRANS_WRITE 2
++
++/*
+ ** Everything we need to know about an open database
+ */
+-struct Btree {
++struct BtShared {
+   Pager *pPager;        /* The page cache */
+   BtCursor *pCursor;    /* A list of all open cursors */
+   MemPage *pPage1;      /* First page of the database */
+-  u8 inTrans;           /* True if a transaction is in progress */
+   u8 inStmt;            /* True if we are in a statement subtransaction */
+   u8 readOnly;          /* True if the underlying file is readonly */
+   u8 maxEmbedFrac;      /* Maximum payload as % of total page size */
+@@ -325,17 +344,18 @@
+   int maxLeaf;          /* Maximum local payload in a LEAFDATA table */
+   int minLeaf;          /* Minimum local payload in a LEAFDATA table */
+   BusyHandler *pBusyHandler;   /* Callback for when there is lock contention */
++  u8 inTransaction;     /* Transaction state */
++  int nRef;             /* Number of references to this structure */
++  int nTransaction;     /* Number of open transactions (read + write) */
++  void *pSchema;        /* Pointer to space allocated by sqlite3BtreeSchema() */
++  void (*xFreeSchema)(void*);  /* Destructor for BtShared.pSchema */
++#ifndef SQLITE_OMIT_SHARED_CACHE
++  BtLock *pLock;        /* List of locks held on this shared-btree struct */
++  BtShared *pNext;      /* Next in ThreadData.pBtree linked list */
++#endif
+ };
+-typedef Btree Bt;
+ 
+ /*
+-** Btree.inTrans may take one of the following values.
+-*/
+-#define TRANS_NONE  0
+-#define TRANS_READ  1
+-#define TRANS_WRITE 2
+-
+-/*
+ ** An instance of the following structure is used to hold information
+ ** about a cell.  The parseCellPtr() function fills in this structure
+ ** based on information extract from the raw disk page.
+@@ -357,7 +377,7 @@
+ ** MemPage.aCell[] of the entry.
+ */
+ struct BtCursor {
+-  Btree *pBt;               /* The Btree to which this cursor belongs */
++  Btree *pBtree;            /* The Btree to which this cursor belongs */
+   BtCursor *pNext, *pPrev;  /* Forms a linked list of all cursors */
+   int (*xCompare)(void*,int,const void*,int,const void*); /* Key comp func */
+   void *pArg;               /* First arg to xCompare() */
+@@ -366,10 +386,39 @@
+   int idx;                  /* Index of the entry in pPage->aCell[] */
+   CellInfo info;            /* A parse of the cell we are pointing at */
+   u8 wrFlag;                /* True if writable */
+-  u8 isValid;               /* TRUE if points to a valid entry */
++  u8 eState;                /* One of the CURSOR_XXX constants (see below) */
++#ifndef SQLITE_OMIT_SHARED_CACHE
++  void *pKey;
++  i64 nKey;
++  int skip;        /* (skip<0) -> Prev() is a no-op. (skip>0) -> Next() is */
++#endif
+ };
+ 
+ /*
++** Potential values for BtCursor.eState. The first two values (VALID and 
++** INVALID) may occur in any build. The third (REQUIRESEEK) may only occur 
++** if sqlite was compiled without the OMIT_SHARED_CACHE symbol defined.
++**
++** CURSOR_VALID:
++**   Cursor points to a valid entry. getPayload() etc. may be called.
++**
++** CURSOR_INVALID:
++**   Cursor does not point to a valid entry. This can happen (for example) 
++**   because the table is empty or because BtreeCursorFirst() has not been
++**   called.
++**
++** CURSOR_REQUIRESEEK:
++**   The table that this cursor was opened on still exists, but has been 
++**   modified since the cursor was last used. The cursor position is saved
++**   in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in 
++**   this state, restoreOrClearCursorPosition() can be called to attempt to
++**   seek the cursor to the saved position.
++*/
++#define CURSOR_INVALID           0
++#define CURSOR_VALID             1
++#define CURSOR_REQUIRESEEK       2
++
++/*
+ ** The TRACE macro will print high-level status information about the
+ ** btree operation when the global variable sqlite3_btree_trace is
+ ** enabled.
+@@ -385,7 +434,7 @@
+ /*
+ ** Forward declaration
+ */
+-static int checkReadLocks(Btree*,Pgno,BtCursor*);
++static int checkReadLocks(BtShared*,Pgno,BtCursor*);
+ 
+ /*
+ ** Read or write a two- and four-byte big-endian integer values.
+@@ -413,7 +462,8 @@
+ ** file.
+ */
+ #define getVarint    sqlite3GetVarint
+-#define getVarint32  sqlite3GetVarint32
++/* #define getVarint32  sqlite3GetVarint32 */
++#define getVarint32(A,B)  ((*B=*(A))<=0x7f?1:sqlite3GetVarint32(A,B))
+ #define putVarint    sqlite3PutVarint
+ 
+ /* The database page the PENDING_BYTE occupies. This page is never used.
+@@ -422,6 +472,274 @@
+ */
+ #define PENDING_BYTE_PAGE(pBt) ((PENDING_BYTE/(pBt)->pageSize)+1)
+ 
++/*
++** A linked list of the following structures is stored at BtShared.pLock.
++** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor 
++** is opened on the table with root page BtShared.iTable. Locks are removed
++** from this list when a transaction is committed or rolled back, or when
++** a btree handle is closed.
++*/
++struct BtLock {
++  Btree *pBtree;        /* Btree handle holding this lock */
++  Pgno iTable;          /* Root page of table */
++  u8 eLock;             /* READ_LOCK or WRITE_LOCK */
++  BtLock *pNext;        /* Next in BtShared.pLock list */
++};
++
++/* Candidate values for BtLock.eLock */
++#define READ_LOCK     1
++#define WRITE_LOCK    2
++
++#ifdef SQLITE_OMIT_SHARED_CACHE
++  /*
++  ** The functions queryTableLock(), lockTable() and unlockAllTables()
++  ** manipulate entries in the BtShared.pLock linked list used to store
++  ** shared-cache table level locks. If the library is compiled with the
++  ** shared-cache feature disabled, then there is only ever one user
++  ** of each BtShared structure and so this locking is not necessary. 
++  ** So define the lock related functions as no-ops.
++  */
++  #define queryTableLock(a,b,c) SQLITE_OK
++  #define lockTable(a,b,c) SQLITE_OK
++  #define unlockAllTables(a)
++  #define restoreOrClearCursorPosition(a,b) SQLITE_OK
++  #define saveAllCursors(a,b,c) SQLITE_OK
++
++#else
++
++static void releasePage(MemPage *pPage);
++
++/*
++** Save the current cursor position in the variables BtCursor.nKey 
++** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK.
++*/
++static int saveCursorPosition(BtCursor *pCur){
++  int rc;
++
++  assert( CURSOR_VALID==pCur->eState );
++  assert( 0==pCur->pKey );
++
++  rc = sqlite3BtreeKeySize(pCur, &pCur->nKey);
++
++  /* If this is an intKey table, then the above call to BtreeKeySize()
++  ** stores the integer key in pCur->nKey. In this case this value is
++  ** all that is required. Otherwise, if pCur is not open on an intKey
++  ** table, then malloc space for and store the pCur->nKey bytes of key 
++  ** data.
++  */
++  if( rc==SQLITE_OK && 0==pCur->pPage->intKey){
++    void *pKey = sqliteMalloc(pCur->nKey);
++    if( pKey ){
++      rc = sqlite3BtreeKey(pCur, 0, pCur->nKey, pKey);
++      if( rc==SQLITE_OK ){
++        pCur->pKey = pKey;
++      }else{
++        sqliteFree(pKey);
++      }
++    }else{
++      rc = SQLITE_NOMEM;
++    }
++  }
++  assert( !pCur->pPage->intKey || !pCur->pKey );
++
++  if( rc==SQLITE_OK ){
++    releasePage(pCur->pPage);
++    pCur->pPage = 0;
++    pCur->eState = CURSOR_REQUIRESEEK;
++  }
++
++  return rc;
++}
++
++/*
++** Save the positions of all cursors except pExcept open on the table 
++** with root-page iRoot. Usually, this is called just before cursor
++** pExcept is used to modify the table (BtreeDelete() or BtreeInsert()).
++*/
++static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){
++  BtCursor *p;
++  if( sqlite3ThreadDataReadOnly()->useSharedData ){
++    for(p=pBt->pCursor; p; p=p->pNext){
++      if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) && 
++          p->eState==CURSOR_VALID ){
++        int rc = saveCursorPosition(p);
++        if( SQLITE_OK!=rc ){
++          return rc;
++        }
++      }
++    }
++  }
++  return SQLITE_OK;
++}
++
++/*
++** Restore the cursor to the position it was in (or as close to as possible)
++** when saveCursorPosition() was called. Note that this call deletes the 
++** saved position info stored by saveCursorPosition(), so there can be
++** at most one effective restoreOrClearCursorPosition() call after each 
++** saveCursorPosition().
++**
++** If the second argument argument - doSeek - is false, then instead of 
++** returning the cursor to it's saved position, any saved position is deleted
++** and the cursor state set to CURSOR_INVALID.
++*/
++static int restoreOrClearCursorPositionX(BtCursor *pCur, int doSeek){
++  int rc = SQLITE_OK;
++  assert( sqlite3ThreadDataReadOnly()->useSharedData );
++  assert( pCur->eState==CURSOR_REQUIRESEEK );
++  pCur->eState = CURSOR_INVALID;
++  if( doSeek ){
++    rc = sqlite3BtreeMoveto(pCur, pCur->pKey, pCur->nKey, &pCur->skip);
++  }
++  if( rc==SQLITE_OK ){
++    sqliteFree(pCur->pKey);
++    pCur->pKey = 0;
++    assert( CURSOR_VALID==pCur->eState || CURSOR_INVALID==pCur->eState );
++  }
++  return rc;
++}
++
++#define restoreOrClearCursorPosition(p,x) \
++  (p->eState==CURSOR_REQUIRESEEK?restoreOrClearCursorPositionX(p,x):SQLITE_OK)
++
++/*
++** Query to see if btree handle p may obtain a lock of type eLock 
++** (READ_LOCK or WRITE_LOCK) on the table with root-page iTab. Return
++** SQLITE_OK if the lock may be obtained (by calling lockTable()), or
++** SQLITE_LOCKED if not.
++*/
++static int queryTableLock(Btree *p, Pgno iTab, u8 eLock){
++  BtShared *pBt = p->pBt;
++  BtLock *pIter;
++
++  /* This is a no-op if the shared-cache is not enabled */
++  if( 0==sqlite3ThreadDataReadOnly()->useSharedData ){
++    return SQLITE_OK;
++  }
++
++  /* This (along with lockTable()) is where the ReadUncommitted flag is
++  ** dealt with. If the caller is querying for a read-lock and the flag is
++  ** set, it is unconditionally granted - even if there are write-locks
++  ** on the table. If a write-lock is requested, the ReadUncommitted flag
++  ** is not considered.
++  **
++  ** In function lockTable(), if a read-lock is demanded and the 
++  ** ReadUncommitted flag is set, no entry is added to the locks list 
++  ** (BtShared.pLock).
++  **
++  ** To summarize: If the ReadUncommitted flag is set, then read cursors do
++  ** not create or respect table locks. The locking procedure for a 
++  ** write-cursor does not change.
++  */
++  if( 
++    !p->pSqlite || 
++    0==(p->pSqlite->flags&SQLITE_ReadUncommitted) || 
++    eLock==WRITE_LOCK ||
++    iTab==MASTER_ROOT
++  ){
++    for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){
++      if( pIter->pBtree!=p && pIter->iTable==iTab && 
++          (pIter->eLock!=eLock || eLock!=READ_LOCK) ){
++        return SQLITE_LOCKED;
++      }
++    }
++  }
++  return SQLITE_OK;
++}
++
++/*
++** Add a lock on the table with root-page iTable to the shared-btree used
++** by Btree handle p. Parameter eLock must be either READ_LOCK or 
++** WRITE_LOCK.
++**
++** SQLITE_OK is returned if the lock is added successfully. SQLITE_BUSY and
++** SQLITE_NOMEM may also be returned.
++*/
++static int lockTable(Btree *p, Pgno iTable, u8 eLock){
++  BtShared *pBt = p->pBt;
++  BtLock *pLock = 0;
++  BtLock *pIter;
++
++  /* This is a no-op if the shared-cache is not enabled */
++  if( 0==sqlite3ThreadDataReadOnly()->useSharedData ){
++    return SQLITE_OK;
++  }
++
++  assert( SQLITE_OK==queryTableLock(p, iTable, eLock) );
++
++  /* If the read-uncommitted flag is set and a read-lock is requested,
++  ** return early without adding an entry to the BtShared.pLock list. See
++  ** comment in function queryTableLock() for more info on handling 
++  ** the ReadUncommitted flag.
++  */
++  if( 
++    (p->pSqlite) && 
++    (p->pSqlite->flags&SQLITE_ReadUncommitted) && 
++    (eLock==READ_LOCK) &&
++    iTable!=MASTER_ROOT
++  ){
++    return SQLITE_OK;
++  }
++
++  /* First search the list for an existing lock on this table. */
++  for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){
++    if( pIter->iTable==iTable && pIter->pBtree==p ){
++      pLock = pIter;
++      break;
++    }
++  }
++
++  /* If the above search did not find a BtLock struct associating Btree p
++  ** with table iTable, allocate one and link it into the list.
++  */
++  if( !pLock ){
++    pLock = (BtLock *)sqliteMalloc(sizeof(BtLock));
++    if( !pLock ){
++      return SQLITE_NOMEM;
++    }
++    pLock->iTable = iTable;
++    pLock->pBtree = p;
++    pLock->pNext = pBt->pLock;
++    pBt->pLock = pLock;
++  }
++
++  /* Set the BtLock.eLock variable to the maximum of the current lock
++  ** and the requested lock. This means if a write-lock was already held
++  ** and a read-lock requested, we don't incorrectly downgrade the lock.
++  */
++  assert( WRITE_LOCK>READ_LOCK );
++  if( eLock>pLock->eLock ){
++    pLock->eLock = eLock;
++  }
++
++  return SQLITE_OK;
++}
++
++/*
++** Release all the table locks (locks obtained via calls to the lockTable()
++** procedure) held by Btree handle p.
++*/
++static void unlockAllTables(Btree *p){
++  BtLock **ppIter = &p->pBt->pLock;
++
++  /* If the shared-cache extension is not enabled, there should be no
++  ** locks in the BtShared.pLock list, making this procedure a no-op. Assert
++  ** that this is the case.
++  */
++  assert( sqlite3ThreadDataReadOnly()->useSharedData || 0==*ppIter );
++
++  while( *ppIter ){
++    BtLock *pLock = *ppIter;
++    if( pLock->pBtree==p ){
++      *ppIter = pLock->pNext;
++      sqliteFree(pLock);
++    }else{
++      ppIter = &pLock->pNext;
++    }
++  }
++}
++#endif /* SQLITE_OMIT_SHARED_CACHE */
++
+ #ifndef SQLITE_OMIT_AUTOVACUUM
+ /*
+ ** These macros define the location of the pointer-map entry for a 
+@@ -438,10 +756,20 @@
+ ** used to test if pgno is a pointer-map page. PTRMAP_ISPAGE implements
+ ** this test.
+ */
+-#define PTRMAP_PAGENO(pgsz, pgno) (((pgno-2)/(pgsz/5+1))*(pgsz/5+1)+2)
+-#define PTRMAP_PTROFFSET(pgsz, pgno) (((pgno-2)%(pgsz/5+1)-1)*5)
+-#define PTRMAP_ISPAGE(pgsz, pgno) (PTRMAP_PAGENO(pgsz,pgno)==pgno)
++#define PTRMAP_PAGENO(pBt, pgno) ptrmapPageno(pBt, pgno)
++#define PTRMAP_PTROFFSET(pBt, pgno) (5*(pgno-ptrmapPageno(pBt, pgno)-1))
++#define PTRMAP_ISPAGE(pBt, pgno) (PTRMAP_PAGENO((pBt),(pgno))==(pgno))
+ 
++static Pgno ptrmapPageno(BtShared *pBt, Pgno pgno){
++  int nPagesPerMapPage = (pBt->usableSize/5)+1;
++  int iPtrMap = (pgno-2)/nPagesPerMapPage;
++  int ret = (iPtrMap*nPagesPerMapPage) + 2; 
++  if( ret==PENDING_BYTE_PAGE(pBt) ){
++    ret++;
++  }
++  return ret;
++}
++
+ /*
+ ** The pointer map is a lookup table that identifies the parent page for
+ ** each child page in the database file.  The parent page is the page that
+@@ -486,22 +814,25 @@
+ ** so that it maps to type 'eType' and parent page number 'pgno'.
+ ** An error code is returned if something goes wrong, otherwise SQLITE_OK.
+ */
+-static int ptrmapPut(Btree *pBt, Pgno key, u8 eType, Pgno parent){
++static int ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent){
+   u8 *pPtrmap;    /* The pointer map page */
+   Pgno iPtrmap;   /* The pointer map page number */
+   int offset;     /* Offset in pointer map page */
+   int rc;
+ 
++  /* The master-journal page number must never be used as a pointer map page */
++  assert( 0==PTRMAP_ISPAGE(pBt, PENDING_BYTE_PAGE(pBt)) );
++
+   assert( pBt->autoVacuum );
+   if( key==0 ){
+     return SQLITE_CORRUPT_BKPT;
+   }
+-  iPtrmap = PTRMAP_PAGENO(pBt->usableSize, key);
++  iPtrmap = PTRMAP_PAGENO(pBt, key);
+   rc = sqlite3pager_get(pBt->pPager, iPtrmap, (void **)&pPtrmap);
+   if( rc!=SQLITE_OK ){
+     return rc;
+   }
+-  offset = PTRMAP_PTROFFSET(pBt->usableSize, key);
++  offset = PTRMAP_PTROFFSET(pBt, key);
+ 
+   if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){
+     TRACE(("PTRMAP_UPDATE: %d->(%d,%d)\n", key, eType, parent));
+@@ -523,19 +854,19 @@
+ ** the type and parent page number to *pEType and *pPgno respectively.
+ ** An error code is returned if something goes wrong, otherwise SQLITE_OK.
+ */
+-static int ptrmapGet(Btree *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
++static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
+   int iPtrmap;       /* Pointer map page index */
+   u8 *pPtrmap;       /* Pointer map page data */
+   int offset;        /* Offset of entry in pointer map */
+   int rc;
+ 
+-  iPtrmap = PTRMAP_PAGENO(pBt->usableSize, key);
++  iPtrmap = PTRMAP_PAGENO(pBt, key);
+   rc = sqlite3pager_get(pBt->pPager, iPtrmap, (void **)&pPtrmap);
+   if( rc!=0 ){
+     return rc;
+   }
+ 
+-  offset = PTRMAP_PTROFFSET(pBt->usableSize, key);
++  offset = PTRMAP_PTROFFSET(pBt, key);
+   if( pEType ) *pEType = pPtrmap[offset];
+   if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]);
+ 
+@@ -604,12 +935,16 @@
+   }else{
+     nPayload = 0;
+   }
+-  n += getVarint(&pCell[n], (u64 *)&pInfo->nKey);
+-  pInfo->nHeader = n;
+   pInfo->nData = nPayload;
+-  if( !pPage->intKey ){
+-    nPayload += pInfo->nKey;
++  if( pPage->intKey ){
++    n += getVarint(&pCell[n], (u64 *)&pInfo->nKey);
++  }else{
++    u32 x;
++    n += getVarint32(&pCell[n], &x);
++    pInfo->nKey = x;
++    nPayload += x;
+   }
++  pInfo->nHeader = n;
+   if( nPayload<=pPage->maxLocal ){
+     /* This is the (easy) common case where the entire payload fits
+     ** on the local page.  No overflow is required.
+@@ -790,10 +1125,20 @@
+ # define pageIntegrity(X)
+ #endif
+ 
++/* A bunch of assert() statements to check the transaction state variables
++** of handle p (type Btree*) are internally consistent.
++*/
++#define btreeIntegrity(p) \
++  assert( p->inTrans!=TRANS_NONE || p->pBt->nTransaction<p->pBt->nRef ); \
++  assert( p->pBt->nTransaction<=p->pBt->nRef ); \
++  assert( p->pBt->inTransaction!=TRANS_NONE || p->pBt->nTransaction==0 ); \
++  assert( p->pBt->inTransaction>=p->inTrans ); 
++
+ /*
+ ** Defragment the page given.  All Cells are moved to the
+-** beginning of the page and all free space is collected 
+-** into one big FreeBlk at the end of the page.
++** end of the page and all free space is collected into one
++** big FreeBlk that occurs in between the header and cell
++** pointer array and the cell content area.
+ */
+ static int defragmentPage(MemPage *pPage){
+   int i;                     /* Loop counter */
+@@ -977,7 +1322,7 @@
+ ** and initialize fields of the MemPage structure accordingly.
+ */
+ static void decodeFlags(MemPage *pPage, int flagByte){
+-  Btree *pBt;     /* A copy of pPage->pBt */
++  BtShared *pBt;     /* A copy of pPage->pBt */
+ 
+   assert( pPage->hdrOffset==(pPage->pgno==1 ? 100 : 0) );
+   pPage->intKey = (flagByte & (PTF_INTKEY|PTF_LEAFDATA))!=0;
+@@ -1017,7 +1362,7 @@
+   int pc;            /* Address of a freeblock within pPage->aData[] */
+   int hdr;           /* Offset to beginning of page header */
+   u8 *data;          /* Equal to pPage->aData */
+-  Btree *pBt;        /* The main btree structure */
++  BtShared *pBt;        /* The main btree structure */
+   int usableSize;    /* Amount of usable space on each page */
+   int cellOffset;    /* Offset from start of page to first cell pointer */
+   int nFree;         /* Number of unused bytes on the page */
+@@ -1090,7 +1435,7 @@
+ */
+ static void zeroPage(MemPage *pPage, int flags){
+   unsigned char *data = pPage->aData;
+-  Btree *pBt = pPage->pBt;
++  BtShared *pBt = pPage->pBt;
+   int hdr = pPage->hdrOffset;
+   int first;
+ 
+@@ -1118,7 +1463,7 @@
+ ** Get a page from the pager.  Initialize the MemPage.pBt and
+ ** MemPage.aData elements if needed.
+ */
+-static int getPage(Btree *pBt, Pgno pgno, MemPage **ppPage){
++static int getPage(BtShared *pBt, Pgno pgno, MemPage **ppPage){
+   int rc;
+   unsigned char *aData;
+   MemPage *pPage;
+@@ -1139,7 +1484,7 @@
+ ** getPage() and initPage().
+ */
+ static int getAndInitPage(
+-  Btree *pBt,          /* The database file */
++  BtShared *pBt,          /* The database file */
+   Pgno pgno,           /* Number of the page to get */
+   MemPage **ppPage,    /* Write the page pointer here */
+   MemPage *pParent     /* Parent of the page */
+@@ -1212,14 +1557,62 @@
+ */
+ int sqlite3BtreeOpen(
+   const char *zFilename,  /* Name of the file containing the BTree database */
++  sqlite3 *pSqlite,       /* Associated database handle */
+   Btree **ppBtree,        /* Pointer to new Btree object written here */
+   int flags               /* Options */
+ ){
+-  Btree *pBt;
++  BtShared *pBt;          /* Shared part of btree structure */
++  Btree *p;               /* Handle to return */
+   int rc;
+   int nReserve;
+   unsigned char zDbHeader[100];
++#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO)
++  const ThreadData *pTsdro;
++#endif
+ 
++  /* Set the variable isMemdb to true for an in-memory database, or 
++  ** false for a file-based database. This symbol is only required if
++  ** either of the shared-data or autovacuum features are compiled 
++  ** into the library.
++  */
++#if !defined(SQLITE_OMIT_SHARED_CACHE) || !defined(SQLITE_OMIT_AUTOVACUUM)
++  #ifdef SQLITE_OMIT_MEMORYDB
++  const int isMemdb = !zFilename;
++  #else
++  const int isMemdb = !zFilename || (strcmp(zFilename, ":memory:")?0:1);
++  #endif
++#endif
++
++  p = sqliteMalloc(sizeof(Btree));
++  if( !p ){
++    return SQLITE_NOMEM;
++  }
++  p->inTrans = TRANS_NONE;
++  p->pSqlite = pSqlite;
++
++  /* Try to find an existing Btree structure opened on zFilename. */
++#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO)
++  pTsdro = sqlite3ThreadDataReadOnly();
++  if( pTsdro->useSharedData && zFilename && !isMemdb ){
++    char *zFullPathname = sqlite3OsFullPathname(zFilename);
++    if( !zFullPathname ){
++      sqliteFree(p);
++      return SQLITE_NOMEM;
++    }
++    for(pBt=pTsdro->pBtree; pBt; pBt=pBt->pNext){
++      assert( pBt->nRef>0 );
++      if( 0==strcmp(zFullPathname, sqlite3pager_filename(pBt->pPager)) ){
++        p->pBt = pBt;
++        *ppBtree = p;
++        pBt->nRef++;
++        sqliteFree(zFullPathname);
++        return SQLITE_OK;
++      }
++    }
++    sqliteFree(zFullPathname);
++  }
++#endif
++
+   /*
+   ** The following asserts make sure that structures used by the btree are
+   ** the right size.  This is to guard against size changes that result
+@@ -1234,15 +1627,19 @@
+   pBt = sqliteMalloc( sizeof(*pBt) );
+   if( pBt==0 ){
+     *ppBtree = 0;
++    sqliteFree(p);
+     return SQLITE_NOMEM;
+   }
+   rc = sqlite3pager_open(&pBt->pPager, zFilename, EXTRA_SIZE, flags);
+   if( rc!=SQLITE_OK ){
+     if( pBt->pPager ) sqlite3pager_close(pBt->pPager);
+     sqliteFree(pBt);
++    sqliteFree(p);
+     *ppBtree = 0;
+     return rc;
+   }
++  p->pBt = pBt;
++
+   sqlite3pager_set_destructor(pBt->pPager, pageDestructor);
+   sqlite3pager_set_reiniter(pBt->pPager, pageReinit);
+   pBt->pCursor = 0;
+@@ -1263,11 +1660,7 @@
+     ** then ":memory:" is just a regular file-name. Respect the auto-vacuum
+     ** default in this case.
+     */
+-#ifndef SQLITE_OMIT_MEMORYDB
+-    if( zFilename && strcmp(zFilename,":memory:") ){
+-#else
+-    if( zFilename ){
+-#endif
++    if( zFilename && !isMemdb ){
+       pBt->autoVacuum = SQLITE_DEFAULT_AUTOVACUUM;
+     }
+ #endif
+@@ -1285,18 +1678,87 @@
+   pBt->usableSize = pBt->pageSize - nReserve;
+   assert( (pBt->pageSize & 7)==0 );  /* 8-byte alignment of pageSize */
+   sqlite3pager_set_pagesize(pBt->pPager, pBt->pageSize);
+-  *ppBtree = pBt;
++
++#ifndef SQLITE_OMIT_SHARED_CACHE
++  /* Add the new btree to the linked list starting at ThreadData.pBtree.
++  ** There is no chance that a malloc() may fail inside of the 
++  ** sqlite3ThreadData() call, as the ThreadData structure must have already
++  ** been allocated for pTsdro->useSharedData to be non-zero.
++  */
++  if( pTsdro->useSharedData && zFilename && !isMemdb ){
++    pBt->pNext = pTsdro->pBtree;
++    sqlite3ThreadData()->pBtree = pBt;
++  }
++#endif
++  pBt->nRef = 1;
++  *ppBtree = p;
+   return SQLITE_OK;
+ }
+ 
+ /*
+ ** Close an open database and invalidate all cursors.
+ */
+-int sqlite3BtreeClose(Btree *pBt){
+-  while( pBt->pCursor ){
+-    sqlite3BtreeCloseCursor(pBt->pCursor);
++int sqlite3BtreeClose(Btree *p){
++  BtShared *pBt = p->pBt;
++  BtCursor *pCur;
++
++#ifndef SQLITE_OMIT_SHARED_CACHE
++  ThreadData *pTsd;
++#endif
++
++  /* Close all cursors opened via this handle.  */
++  pCur = pBt->pCursor;
++  while( pCur ){
++    BtCursor *pTmp = pCur;
++    pCur = pCur->pNext;
++    if( pTmp->pBtree==p ){
++      sqlite3BtreeCloseCursor(pTmp);
++    }
+   }
++
++  /* Rollback any active transaction and free the handle structure.
++  ** The call to sqlite3BtreeRollback() drops any table-locks held by
++  ** this handle.
++  */
++  sqlite3BtreeRollback(p);
++  sqliteFree(p);
++
++#ifndef SQLITE_OMIT_SHARED_CACHE
++  /* If there are still other outstanding references to the shared-btree
++  ** structure, return now. The remainder of this procedure cleans 
++  ** up the shared-btree.
++  */
++  assert( pBt->nRef>0 );
++  pBt->nRef--;
++  if( pBt->nRef ){
++    return SQLITE_OK;
++  }
++
++  /* Remove the shared-btree from the thread wide list. Call 
++  ** ThreadDataReadOnly() and then cast away the const property of the 
++  ** pointer to avoid allocating thread data if it is not really required.
++  */
++  pTsd = (ThreadData *)sqlite3ThreadDataReadOnly();
++  if( pTsd->pBtree==pBt ){
++    assert( pTsd==sqlite3ThreadData() );
++    pTsd->pBtree = pBt->pNext;
++  }else{
++    BtShared *pPrev;
++    for(pPrev=pTsd->pBtree; pPrev && pPrev->pNext!=pBt; pPrev=pPrev->pNext);
++    if( pPrev ){
++      assert( pTsd==sqlite3ThreadData() );
++      pPrev->pNext = pBt->pNext;
++    }
++  }
++#endif
++
++  /* Close the pager and free the shared-btree structure */
++  assert( !pBt->pCursor );
+   sqlite3pager_close(pBt->pPager);
++  if( pBt->xFreeSchema && pBt->pSchema ){
++    pBt->xFreeSchema(pBt->pSchema);
++  }
++  sqliteFree(pBt->pSchema);
+   sqliteFree(pBt);
+   return SQLITE_OK;
+ }
+@@ -1304,7 +1766,8 @@
+ /*
+ ** Change the busy handler callback function.
+ */
+-int sqlite3BtreeSetBusyHandler(Btree *pBt, BusyHandler *pHandler){
++int sqlite3BtreeSetBusyHandler(Btree *p, BusyHandler *pHandler){
++  BtShared *pBt = p->pBt;
+   pBt->pBusyHandler = pHandler;
+   sqlite3pager_set_busyhandler(pBt->pPager, pHandler);
+   return SQLITE_OK;
+@@ -1325,7 +1788,8 @@
+ ** Synchronous is on by default so database corruption is not
+ ** normally a worry.
+ */
+-int sqlite3BtreeSetCacheSize(Btree *pBt, int mxPage){
++int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){
++  BtShared *pBt = p->pBt;
+   sqlite3pager_set_cachesize(pBt->pPager, mxPage);
+   return SQLITE_OK;
+ }
+@@ -1339,8 +1803,9 @@
+ ** probability of damage to near zero but with a write performance reduction.
+ */
+ #ifndef SQLITE_OMIT_PAGER_PRAGMAS
+-int sqlite3BtreeSetSafetyLevel(Btree *pBt, int level){
+-  sqlite3pager_set_safety_level(pBt->pPager, level);
++int sqlite3BtreeSetSafetyLevel(Btree *p, int level, int fullSync){
++  BtShared *pBt = p->pBt;
++  sqlite3pager_set_safety_level(pBt->pPager, level, fullSync);
+   return SQLITE_OK;
+ }
+ #endif
+@@ -1349,7 +1814,8 @@
+ ** Return TRUE if the given btree is set to safety level 1.  In other
+ ** words, return TRUE if no sync() occurs on the disk files.
+ */
+-int sqlite3BtreeSyncDisabled(Btree *pBt){
++int sqlite3BtreeSyncDisabled(Btree *p){
++  BtShared *pBt = p->pBt;
+   assert( pBt && pBt->pPager );
+   return sqlite3pager_nosync(pBt->pPager);
+ }
+@@ -1370,7 +1836,8 @@
+ ** If parameter nReserve is less than zero, then the number of reserved
+ ** bytes per page is left unchanged.
+ */
+-int sqlite3BtreeSetPageSize(Btree *pBt, int pageSize, int nReserve){
++int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve){
++  BtShared *pBt = p->pBt;
+   if( pBt->pageSizeFixed ){
+     return SQLITE_READONLY;
+   }
+@@ -1380,6 +1847,7 @@
+   if( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE &&
+         ((pageSize-1)&pageSize)==0 ){
+     assert( (pageSize & 7)==0 );
++    assert( !pBt->pPage1 && !pBt->pCursor );
+     pBt->pageSize = sqlite3pager_set_pagesize(pBt->pPager, pageSize);
+   }
+   pBt->usableSize = pBt->pageSize - nReserve;
+@@ -1389,11 +1857,11 @@
+ /*
+ ** Return the currently defined page size
+ */
+-int sqlite3BtreeGetPageSize(Btree *pBt){
+-  return pBt->pageSize;
++int sqlite3BtreeGetPageSize(Btree *p){
++  return p->pBt->pageSize;
+ }
+-int sqlite3BtreeGetReserve(Btree *pBt){
+-  return pBt->pageSize - pBt->usableSize;
++int sqlite3BtreeGetReserve(Btree *p){
++  return p->pBt->pageSize - p->pBt->usableSize;
+ }
+ #endif /* !defined(SQLITE_OMIT_PAGER_PRAGMAS) || !defined(SQLITE_OMIT_VACUUM) */
+ 
+@@ -1403,7 +1871,8 @@
+ ** is disabled. The default value for the auto-vacuum property is 
+ ** determined by the SQLITE_DEFAULT_AUTOVACUUM macro.
+ */
+-int sqlite3BtreeSetAutoVacuum(Btree *pBt, int autoVacuum){
++int sqlite3BtreeSetAutoVacuum(Btree *p, int autoVacuum){
++  BtShared *pBt = p->pBt;;
+ #ifdef SQLITE_OMIT_AUTOVACUUM
+   return SQLITE_READONLY;
+ #else
+@@ -1419,11 +1888,11 @@
+ ** Return the value of the 'auto-vacuum' property. If auto-vacuum is 
+ ** enabled 1 is returned. Otherwise 0.
+ */
+-int sqlite3BtreeGetAutoVacuum(Btree *pBt){
++int sqlite3BtreeGetAutoVacuum(Btree *p){
+ #ifdef SQLITE_OMIT_AUTOVACUUM
+   return 0;
+ #else
+-  return pBt->autoVacuum;
++  return p->pBt->autoVacuum;
+ #endif
+ }
+ 
+@@ -1438,7 +1907,7 @@
+ ** is returned if we run out of memory.  SQLITE_PROTOCOL is returned
+ ** if there is a locking protocol violation.
+ */
+-static int lockBtree(Btree *pBt){
++static int lockBtree(BtShared *pBt){
+   int rc, pageSize;
+   MemPage *pPage1;
+   if( pBt->pPage1 ) return SQLITE_OK;
+@@ -1510,11 +1979,18 @@
+ ** This routine works like lockBtree() except that it also invokes the
+ ** busy callback if there is lock contention.
+ */
+-static int lockBtreeWithRetry(Btree *pBt){
++static int lockBtreeWithRetry(Btree *pRef){
+   int rc = SQLITE_OK;
+-  if( pBt->inTrans==TRANS_NONE ){
+-    rc = sqlite3BtreeBeginTrans(pBt, 0);
+-    pBt->inTrans = TRANS_NONE;
++  if( pRef->inTrans==TRANS_NONE ){
++    u8 inTransaction = pRef->pBt->inTransaction;
++    btreeIntegrity(pRef);
++    rc = sqlite3BtreeBeginTrans(pRef, 0);
++    pRef->pBt->inTransaction = inTransaction;
++    pRef->inTrans = TRANS_NONE;
++    if( rc==SQLITE_OK ){
++      pRef->pBt->nTransaction--;
++    }
++    btreeIntegrity(pRef);
+   }
+   return rc;
+ }
+@@ -1530,11 +2006,11 @@
+ **
+ ** If there is a transaction in progress, this routine is a no-op.
+ */
+-static void unlockBtreeIfUnused(Btree *pBt){
+-  if( pBt->inTrans==TRANS_NONE && pBt->pCursor==0 && pBt->pPage1!=0 ){
++static void unlockBtreeIfUnused(BtShared *pBt){
++  if( pBt->inTransaction==TRANS_NONE && pBt->pCursor==0 && pBt->pPage1!=0 ){
+     if( pBt->pPage1->aData==0 ){
+       MemPage *pPage = pBt->pPage1;
+-      pPage->aData = &((char*)pPage)[-pBt->pageSize];
++      pPage->aData = &((u8*)pPage)[-pBt->pageSize];
+       pPage->pBt = pBt;
+       pPage->pgno = 1;
+     }
+@@ -1548,7 +2024,7 @@
+ ** Create a new database by initializing the first page of the
+ ** file.
+ */
+-static int newDatabase(Btree *pBt){
++static int newDatabase(BtShared *pBt){
+   MemPage *pP1;
+   unsigned char *data;
+   int rc;
+@@ -1613,14 +2089,17 @@
+ ** when A already has a read lock, we encourage A to give up and let B
+ ** proceed.
+ */
+-int sqlite3BtreeBeginTrans(Btree *pBt, int wrflag){
++int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
++  BtShared *pBt = p->pBt;
+   int rc = SQLITE_OK;
+ 
++  btreeIntegrity(p);
++
+   /* If the btree is already in a write-transaction, or it
+   ** is already in a read-transaction and a read-transaction
+   ** is requested, this is a no-op.
+   */
+-  if( pBt->inTrans==TRANS_WRITE || (pBt->inTrans==TRANS_READ && !wrflag) ){
++  if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){
+     return SQLITE_OK;
+   }
+ 
+@@ -1629,6 +2108,14 @@
+     return SQLITE_READONLY;
+   }
+ 
++  /* If another database handle has already opened a write transaction 
++  ** on this shared-btree structure and a second write transaction is
++  ** requested, return SQLITE_BUSY.
++  */
++  if( pBt->inTransaction==TRANS_WRITE && wrflag ){
++    return SQLITE_BUSY;
++  }
++
+   do {
+     if( pBt->pPage1==0 ){
+       rc = lockBtree(pBt);
+@@ -1642,13 +2129,24 @@
+     }
+   
+     if( rc==SQLITE_OK ){
+-      pBt->inTrans = (wrflag?TRANS_WRITE:TRANS_READ);
+       if( wrflag ) pBt->inStmt = 0;
+     }else{
+       unlockBtreeIfUnused(pBt);
+     }
+-  }while( rc==SQLITE_BUSY && pBt->inTrans==TRANS_NONE &&
++  }while( rc==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE &&
+           sqlite3InvokeBusyHandler(pBt->pBusyHandler) );
++
++  if( rc==SQLITE_OK ){
++    if( p->inTrans==TRANS_NONE ){
++      pBt->nTransaction++;
++    }
++    p->inTrans = (wrflag?TRANS_WRITE:TRANS_READ);
++    if( p->inTrans>pBt->inTransaction ){
++      pBt->inTransaction = p->inTrans;
++    }
++  }
++
++  btreeIntegrity(p);
+   return rc;
+ }
+ 
+@@ -1663,7 +2161,7 @@
+   int i;                             /* Counter variable */
+   int nCell;                         /* Number of cells in page pPage */
+   int rc = SQLITE_OK;                /* Return code */
+-  Btree *pBt = pPage->pBt;
++  BtShared *pBt = pPage->pBt;
+   int isInitOrig = pPage->isInit;
+   Pgno pgno = pPage->pgno;
+ 
+@@ -1763,7 +2261,7 @@
+ ** database. The pDbPage reference remains valid.
+ */
+ static int relocatePage(
+-  Btree *pBt,              /* Btree */
++  BtShared *pBt,           /* Btree */
+   MemPage *pDbPage,        /* Open page to move */
+   u8 eType,                /* Pointer map 'type' entry for pDbPage */
+   Pgno iPtrPage,           /* Pointer map 'page-no' entry for pDbPage */
+@@ -1833,19 +2331,19 @@
+ }
+ 
+ /* Forward declaration required by autoVacuumCommit(). */
+-static int allocatePage(Btree *, MemPage **, Pgno *, Pgno, u8);
++static int allocatePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
+ 
+ /*
+ ** This routine is called prior to sqlite3pager_commit when a transaction
+ ** is commited for an auto-vacuum database.
+ */
+-static int autoVacuumCommit(Btree *pBt, Pgno *nTrunc){
++static int autoVacuumCommit(BtShared *pBt, Pgno *nTrunc){
+   Pager *pPager = pBt->pPager;
+-  Pgno nFreeList;   /* Number of pages remaining on the free-list. */
+-  int nPtrMap;      /* Number of pointer-map pages deallocated */
+-  Pgno origSize;  /* Pages in the database file */
+-  Pgno finSize;   /* Pages in the database file after truncation */
+-  int rc;           /* Return code */
++  Pgno nFreeList;            /* Number of pages remaining on the free-list. */
++  int nPtrMap;               /* Number of pointer-map pages deallocated */
++  Pgno origSize;             /* Pages in the database file */
++  Pgno finSize;              /* Pages in the database file after truncation */
++  int rc;                    /* Return code */
+   u8 eType;
+   int pgsz = pBt->pageSize;  /* Page size for this database */
+   Pgno iDbPage;              /* The database page to move */
+@@ -1859,7 +2357,7 @@
+ #endif
+ 
+   assert( pBt->autoVacuum );
+-  if( PTRMAP_ISPAGE(pgsz, sqlite3pager_pagecount(pPager)) ){
++  if( PTRMAP_ISPAGE(pBt, sqlite3pager_pagecount(pPager)) ){
+     return SQLITE_CORRUPT_BKPT;
+   }
+ 
+@@ -1872,15 +2370,27 @@
+     return SQLITE_OK;
+   }
+ 
++  /* This block figures out how many pages there are in the database
++  ** now (variable origSize), and how many there will be after the
++  ** truncation (variable finSize).
++  **
++  ** The final size is the original size, less the number of free pages
++  ** in the database, less any pointer-map pages that will no longer
++  ** be required, less 1 if the pending-byte page was part of the database
++  ** but is not after the truncation.
++  **/
+   origSize = sqlite3pager_pagecount(pPager);
+-  nPtrMap = (nFreeList-origSize+PTRMAP_PAGENO(pgsz, origSize)+pgsz/5)/(pgsz/5);
++  if( origSize==PENDING_BYTE_PAGE(pBt) ){
++    origSize--;
++  }
++  nPtrMap = (nFreeList-origSize+PTRMAP_PAGENO(pBt, origSize)+pgsz/5)/(pgsz/5);
+   finSize = origSize - nFreeList - nPtrMap;
+-  if( origSize>=PENDING_BYTE_PAGE(pBt) && finSize<=PENDING_BYTE_PAGE(pBt) ){
++  if( origSize>PENDING_BYTE_PAGE(pBt) && finSize<=PENDING_BYTE_PAGE(pBt) ){
+     finSize--;
+-    if( PTRMAP_ISPAGE(pBt->usableSize, finSize) ){
+-      finSize--;
+-    }
+   }
++  while( PTRMAP_ISPAGE(pBt, finSize) || finSize==PENDING_BYTE_PAGE(pBt) ){
++    finSize--;
++  }
+   TRACE(("AUTOVACUUM: Begin (db size %d->%d)\n", origSize, finSize));
+ 
+   /* Variable 'finSize' will be the size of the file in pages after
+@@ -1891,7 +2401,7 @@
+   */
+   for( iDbPage=finSize+1; iDbPage<=origSize; iDbPage++ ){
+     /* If iDbPage is a pointer map page, or the pending-byte page, skip it. */
+-    if( PTRMAP_ISPAGE(pgsz, iDbPage) || iDbPage==PENDING_BYTE_PAGE(pBt) ){
++    if( PTRMAP_ISPAGE(pBt, iDbPage) || iDbPage==PENDING_BYTE_PAGE(pBt) ){
+       continue;
+     }
+ 
+@@ -1928,6 +2438,12 @@
+     releasePage(pFreeMemPage);
+     pFreeMemPage = 0;
+ 
++    /* Relocate the page into the body of the file. Note that although the 
++    ** page has moved within the database file, the pDbMemPage pointer 
++    ** remains valid. This means that this function can run without
++    ** invalidating cursors open on the btree. This is important in 
++    ** shared-cache mode.
++    */
+     rc = relocatePage(pBt, pDbMemPage, eType, iPtrPage, iFreePage);
+     releasePage(pDbMemPage);
+     if( rc!=SQLITE_OK ) goto autovacuum_out;
+@@ -1943,6 +2459,7 @@
+   put4byte(&pBt->pPage1->aData[36], 0);
+   if( rc!=SQLITE_OK ) goto autovacuum_out;
+   *nTrunc = finSize;
++  assert( finSize!=PENDING_BYTE_PAGE(pBt) );
+ 
+ autovacuum_out:
+   assert( nRef==*sqlite3pager_stats(pPager) );
+@@ -1959,15 +2476,47 @@
+ ** This will release the write lock on the database file.  If there
+ ** are no active cursors, it also releases the read lock.
+ */
+-int sqlite3BtreeCommit(Btree *pBt){
+-  int rc = SQLITE_OK;
+-  if( pBt->inTrans==TRANS_WRITE ){
++int sqlite3BtreeCommit(Btree *p){
++  BtShared *pBt = p->pBt;
++
++  btreeIntegrity(p);
++
++  /* If the handle has a write-transaction open, commit the shared-btrees 
++  ** transaction and set the shared state to TRANS_READ.
++  */
++  if( p->inTrans==TRANS_WRITE ){
++    int rc;
++    assert( pBt->inTransaction==TRANS_WRITE );
++    assert( pBt->nTransaction>0 );
+     rc = sqlite3pager_commit(pBt->pPager);
++    if( rc!=SQLITE_OK ){
++      return rc;
++    }
++    pBt->inTransaction = TRANS_READ;
++    pBt->inStmt = 0;
+   }
+-  pBt->inTrans = TRANS_NONE;
+-  pBt->inStmt = 0;
++  unlockAllTables(p);
++
++  /* If the handle has any kind of transaction open, decrement the transaction
++  ** count of the shared btree. If the transaction count reaches 0, set
++  ** the shared state to TRANS_NONE. The unlockBtreeIfUnused() call below
++  ** will unlock the pager.
++  */
++  if( p->inTrans!=TRANS_NONE ){
++    pBt->nTransaction--;
++    if( 0==pBt->nTransaction ){
++      pBt->inTransaction = TRANS_NONE;
++    }
++  }
++
++  /* Set the handles current transaction state to TRANS_NONE and unlock
++  ** the pager if this call closed the only read or write transaction.
++  */
++  p->inTrans = TRANS_NONE;
+   unlockBtreeIfUnused(pBt);
+-  return rc;
++
++  btreeIntegrity(p);
++  return SQLITE_OK;
+ }
+ 
+ #ifndef NDEBUG
+@@ -1976,29 +2525,30 @@
+ ** in assert() expressions, so it is only compiled if NDEBUG is not
+ ** defined.
+ */
+-static int countWriteCursors(Btree *pBt){
++static int countWriteCursors(BtShared *pBt){
+   BtCursor *pCur;
+   int r = 0;
+   for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
+-    if( pCur->wrFlag ) r++;
++    if( pCur->wrFlag ) r++; 
+   }
+   return r;
+ }
+ #endif
+ 
+-#ifdef SQLITE_TEST
++#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
+ /*
+ ** Print debugging information about all cursors to standard output.
+ */
+-void sqlite3BtreeCursorList(Btree *pBt){
++void sqlite3BtreeCursorList(Btree *p){
+   BtCursor *pCur;
++  BtShared *pBt = p->pBt;
+   for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
+     MemPage *pPage = pCur->pPage;
+     char *zMode = pCur->wrFlag ? "rw" : "ro";
+     sqlite3DebugPrintf("CURSOR %p rooted at %4d(%s) currently at %d.%d%s\n",
+        pCur, pCur->pgnoRoot, zMode,
+        pPage ? pPage->pgno : 0, pCur->idx,
+-       pCur->isValid ? "" : " eof"
++       (pCur->eState==CURSOR_VALID) ? "" : " eof"
+     );
+   }
+ }
+@@ -2013,11 +2563,41 @@
+ ** This will release the write lock on the database file.  If there
+ ** are no active cursors, it also releases the read lock.
+ */
+-int sqlite3BtreeRollback(Btree *pBt){
+-  int rc = SQLITE_OK;
++int sqlite3BtreeRollback(Btree *p){
++  int rc;
++  BtShared *pBt = p->pBt;
+   MemPage *pPage1;
+-  if( pBt->inTrans==TRANS_WRITE ){
+-    rc = sqlite3pager_rollback(pBt->pPager);
++
++  rc = saveAllCursors(pBt, 0, 0);
++#ifndef SQLITE_OMIT_SHARED_CACHE
++  if( rc!=SQLITE_OK ){
++    /* This is a horrible situation. An IO or malloc() error occured whilst
++    ** trying to save cursor positions. If this is an automatic rollback (as
++    ** the result of a constraint, malloc() failure or IO error) then 
++    ** the cache may be internally inconsistent (not contain valid trees) so
++    ** we cannot simply return the error to the caller. Instead, abort 
++    ** all queries that may be using any of the cursors that failed to save.
++    */
++    while( pBt->pCursor ){
++      sqlite3 *db = pBt->pCursor->pBtree->pSqlite;
++      if( db ){
++        sqlite3AbortOtherActiveVdbes(db, 0);
++      }
++    }
++  }
++#endif
++  btreeIntegrity(p);
++  unlockAllTables(p);
++
++  if( p->inTrans==TRANS_WRITE ){
++    int rc2;
++
++    assert( TRANS_WRITE==pBt->inTransaction );
++    rc2 = sqlite3pager_rollback(pBt->pPager);
++    if( rc2!=SQLITE_OK ){
++      rc = rc2;
++    }
++
+     /* The rollback may have destroyed the pPage1->aData value.  So
+     ** call getPage() on page 1 again to make sure pPage1->aData is
+     ** set correctly. */
+@@ -2025,10 +2605,22 @@
+       releasePage(pPage1);
+     }
+     assert( countWriteCursors(pBt)==0 );
++    pBt->inTransaction = TRANS_READ;
+   }
+-  pBt->inTrans = TRANS_NONE;
++
++  if( p->inTrans!=TRANS_NONE ){
++    assert( pBt->nTransaction>0 );
++    pBt->nTransaction--;
++    if( 0==pBt->nTransaction ){
++      pBt->inTransaction = TRANS_NONE;
++    }
++  }
++
++  p->inTrans = TRANS_NONE;
+   pBt->inStmt = 0;
+   unlockBtreeIfUnused(pBt);
++
++  btreeIntegrity(p);
+   return rc;
+ }
+ 
+@@ -2047,11 +2639,13 @@
+ ** error occurs within the statement, the effect of that one statement
+ ** can be rolled back without having to rollback the entire transaction.
+ */
+-int sqlite3BtreeBeginStmt(Btree *pBt){
++int sqlite3BtreeBeginStmt(Btree *p){
+   int rc;
+-  if( (pBt->inTrans!=TRANS_WRITE) || pBt->inStmt ){
++  BtShared *pBt = p->pBt;
++  if( (p->inTrans!=TRANS_WRITE) || pBt->inStmt ){
+     return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
+   }
++  assert( pBt->inTransaction==TRANS_WRITE );
+   rc = pBt->readOnly ? SQLITE_OK : sqlite3pager_stmt_begin(pBt->pPager);
+   pBt->inStmt = 1;
+   return rc;
+@@ -2062,8 +2656,9 @@
+ ** Commit the statment subtransaction currently in progress.  If no
+ ** subtransaction is active, this is a no-op.
+ */
+-int sqlite3BtreeCommitStmt(Btree *pBt){
++int sqlite3BtreeCommitStmt(Btree *p){
+   int rc;
++  BtShared *pBt = p->pBt;
+   if( pBt->inStmt && !pBt->readOnly ){
+     rc = sqlite3pager_stmt_commit(pBt->pPager);
+   }else{
+@@ -2081,12 +2676,16 @@
+ ** to use a cursor that was open at the beginning of this operation
+ ** will result in an error.
+ */
+-int sqlite3BtreeRollbackStmt(Btree *pBt){
+-  int rc;
+-  if( pBt->inStmt==0 || pBt->readOnly ) return SQLITE_OK;
+-  rc = sqlite3pager_stmt_rollback(pBt->pPager);
+-  assert( countWriteCursors(pBt)==0 );
+-  pBt->inStmt = 0;
++int sqlite3BtreeRollbackStmt(Btree *p){
++  int rc = SQLITE_OK;
++  BtShared *pBt = p->pBt;
++  sqlite3MallocDisallow();
++  if( pBt->inStmt && !pBt->readOnly ){
++    rc = sqlite3pager_stmt_rollback(pBt->pPager);
++    assert( countWriteCursors(pBt)==0 );
++    pBt->inStmt = 0;
++  }
++  sqlite3MallocAllow();
+   return rc;
+ }
+ 
+@@ -2150,7 +2749,7 @@
+ ** always ignored for INTKEY tables.
+ */
+ int sqlite3BtreeCursor(
+-  Btree *pBt,                                 /* The btree */
++  Btree *p,                                   /* The btree */
+   int iTable,                                 /* Root page of table to open */
+   int wrFlag,                                 /* 1 to write. 0 read-only */
+   int (*xCmp)(void*,int,const void*,int,const void*), /* Key Comparison func */
+@@ -2159,6 +2758,7 @@
+ ){
+   int rc;
+   BtCursor *pCur;
++  BtShared *pBt = p->pBt;
+ 
+   *ppCur = 0;
+   if( wrFlag ){
+@@ -2169,19 +2769,19 @@
+       return SQLITE_LOCKED;
+     }
+   }
++
+   if( pBt->pPage1==0 ){
+-    rc = lockBtreeWithRetry(pBt);
++    rc = lockBtreeWithRetry(p);
+     if( rc!=SQLITE_OK ){
+       return rc;
+     }
+   }
+-  pCur = sqliteMallocRaw( sizeof(*pCur) );
++  pCur = sqliteMalloc( sizeof(*pCur) );
+   if( pCur==0 ){
+     rc = SQLITE_NOMEM;
+     goto create_cursor_exception;
+   }
+   pCur->pgnoRoot = (Pgno)iTable;
+-  pCur->pPage = 0;  /* For exit-handler, in case getAndInitPage() fails. */
+   if( iTable==1 && sqlite3pager_pagecount(pBt->pPager)==0 ){
+     rc = SQLITE_EMPTY;
+     goto create_cursor_exception;
+@@ -2190,22 +2790,24 @@
+   if( rc!=SQLITE_OK ){
+     goto create_cursor_exception;
+   }
++
++  /* Now that no other errors can occur, finish filling in the BtCursor
++  ** variables, link the cursor into the BtShared list and set *ppCur (the
++  ** output argument to this function).
++  */
+   pCur->xCompare = xCmp ? xCmp : dfltCompare;
+   pCur->pArg = pArg;
+-  pCur->pBt = pBt;
++  pCur->pBtree = p;
+   pCur->wrFlag = wrFlag;
+-  pCur->idx = 0;
+-  memset(&pCur->info, 0, sizeof(pCur->info));
+   pCur->pNext = pBt->pCursor;
+   if( pCur->pNext ){
+     pCur->pNext->pPrev = pCur;
+   }
+-  pCur->pPrev = 0;
+   pBt->pCursor = pCur;
+-  pCur->isValid = 0;
++  pCur->eState = CURSOR_INVALID;
+   *ppCur = pCur;
++
+   return SQLITE_OK;
+-
+ create_cursor_exception:
+   if( pCur ){
+     releasePage(pCur->pPage);
+@@ -2234,7 +2836,8 @@
+ ** when the last cursor is closed.
+ */
+ int sqlite3BtreeCloseCursor(BtCursor *pCur){
+-  Btree *pBt = pCur->pBt;
++  BtShared *pBt = pCur->pBtree->pBt;
++  restoreOrClearCursorPosition(pCur, 0);
+   if( pCur->pPrev ){
+     pCur->pPrev->pNext = pCur->pNext;
+   }else{
+@@ -2301,13 +2904,17 @@
+ ** itself, not the number of bytes in the key.
+ */
+ int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){
+-  if( !pCur->isValid ){
+-    *pSize = 0;
+-  }else{
+-    getCellInfo(pCur);
+-    *pSize = pCur->info.nKey;
++  int rc = restoreOrClearCursorPosition(pCur, 1);
++  if( rc==SQLITE_OK ){
++    assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID );
++    if( pCur->eState==CURSOR_INVALID ){
++      *pSize = 0;
++    }else{
++      getCellInfo(pCur);
++      *pSize = pCur->info.nKey;
++    }
+   }
+-  return SQLITE_OK;
++  return rc;
+ }
+ 
+ /*
+@@ -2318,14 +2925,18 @@
+ ** the database is empty) then *pSize is set to 0.
+ */
+ int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
+-  if( !pCur->isValid ){
+-    /* Not pointing at a valid entry - set *pSize to 0. */
+-    *pSize = 0;
+-  }else{
+-    getCellInfo(pCur);
+-    *pSize = pCur->info.nData;
++  int rc = restoreOrClearCursorPosition(pCur, 1);
++  if( rc==SQLITE_OK ){
++    assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID );
++    if( pCur->eState==CURSOR_INVALID ){
++      /* Not pointing at a valid entry - set *pSize to 0. */
++      *pSize = 0;
++    }else{
++      getCellInfo(pCur);
++      *pSize = pCur->info.nData;
++    }
+   }
+-  return SQLITE_OK;
++  return rc;
+ }
+ 
+ /*
+@@ -2348,19 +2959,18 @@
+   Pgno nextPage;
+   int rc;
+   MemPage *pPage;
+-  Btree *pBt;
++  BtShared *pBt;
+   int ovflSize;
+   u32 nKey;
+ 
+   assert( pCur!=0 && pCur->pPage!=0 );
+-  assert( pCur->isValid );
+-  pBt = pCur->pBt;
++  assert( pCur->eState==CURSOR_VALID );
++  pBt = pCur->pBtree->pBt;
+   pPage = pCur->pPage;
+   pageIntegrity(pPage);
+   assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
+   getCellInfo(pCur);
+-  aPayload = pCur->info.pCell;
+-  aPayload += pCur->info.nHeader;
++  aPayload = pCur->info.pCell + pCur->info.nHeader;
+   if( pPage->intKey ){
+     nKey = 0;
+   }else{
+@@ -2429,14 +3039,18 @@
+ ** the available payload.
+ */
+ int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
+-  assert( pCur->isValid );
+-  assert( pCur->pPage!=0 );
+-  if( pCur->pPage->intKey ){
+-    return SQLITE_CORRUPT_BKPT;
++  int rc = restoreOrClearCursorPosition(pCur, 1);
++  if( rc==SQLITE_OK ){
++    assert( pCur->eState==CURSOR_VALID );
++    assert( pCur->pPage!=0 );
++    if( pCur->pPage->intKey ){
++      return SQLITE_CORRUPT_BKPT;
++    }
++    assert( pCur->pPage->intKey==0 );
++    assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
++    rc = getPayload(pCur, offset, amt, (unsigned char*)pBuf, 0);
+   }
+-  assert( pCur->pPage->intKey==0 );
+-  assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
+-  return getPayload(pCur, offset, amt, (unsigned char*)pBuf, 0);
++  return rc;
+ }
+ 
+ /*
+@@ -2449,10 +3063,14 @@
+ ** the available payload.
+ */
+ int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
+-  assert( pCur->isValid );
+-  assert( pCur->pPage!=0 );
+-  assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
+-  return getPayload(pCur, offset, amt, pBuf, 1);
++  int rc = restoreOrClearCursorPosition(pCur, 1);
++  if( rc==SQLITE_OK ){
++    assert( pCur->eState==CURSOR_VALID );
++    assert( pCur->pPage!=0 );
++    assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
++    rc = getPayload(pCur, offset, amt, pBuf, 1);
++  }
++  return rc;
+ }
+ 
+ /*
+@@ -2485,7 +3103,7 @@
+   int nLocal;
+ 
+   assert( pCur!=0 && pCur->pPage!=0 );
+-  assert( pCur->isValid );
++  assert( pCur->eState==CURSOR_VALID );
+   pPage = pCur->pPage;
+   pageIntegrity(pPage);
+   assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
+@@ -2523,10 +3141,16 @@
+ ** in the common case where no overflow pages are used.
+ */
+ const void *sqlite3BtreeKeyFetch(BtCursor *pCur, int *pAmt){
+-  return (const void*)fetchPayload(pCur, pAmt, 0);
++  if( pCur->eState==CURSOR_VALID ){
++    return (const void*)fetchPayload(pCur, pAmt, 0);
++  }
++  return 0;
+ }
+ const void *sqlite3BtreeDataFetch(BtCursor *pCur, int *pAmt){
+-  return (const void*)fetchPayload(pCur, pAmt, 1);
++  if( pCur->eState==CURSOR_VALID ){
++    return (const void*)fetchPayload(pCur, pAmt, 1);
++  }
++  return 0;
+ }
+ 
+ 
+@@ -2538,9 +3162,9 @@
+   int rc;
+   MemPage *pNewPage;
+   MemPage *pOldPage;
+-  Btree *pBt = pCur->pBt;
++  BtShared *pBt = pCur->pBtree->pBt;
+ 
+-  assert( pCur->isValid );
++  assert( pCur->eState==CURSOR_VALID );
+   rc = getAndInitPage(pBt, newPgno, &pNewPage, pCur->pPage);
+   if( rc ) return rc;
+   pageIntegrity(pNewPage);
+@@ -2587,7 +3211,7 @@
+   MemPage *pPage;
+   int idxParent;
+ 
+-  assert( pCur->isValid );
++  assert( pCur->eState==CURSOR_VALID );
+   pPage = pCur->pPage;
+   assert( pPage!=0 );
+   assert( !isRootPage(pPage) );
+@@ -2609,17 +3233,24 @@
+ */
+ static int moveToRoot(BtCursor *pCur){
+   MemPage *pRoot;
+-  int rc;
+-  Btree *pBt = pCur->pBt;
++  int rc = SQLITE_OK;
++  BtShared *pBt = pCur->pBtree->pBt;
+ 
+-  rc = getAndInitPage(pBt, pCur->pgnoRoot, &pRoot, 0);
+-  if( rc ){
+-    pCur->isValid = 0;
+-    return rc;
++  restoreOrClearCursorPosition(pCur, 0);
++  pRoot = pCur->pPage;
++  if( pRoot && pRoot->pgno==pCur->pgnoRoot ){
++    assert( pRoot->isInit );
++  }else{
++    if( 
++      SQLITE_OK!=(rc = getAndInitPage(pBt, pCur->pgnoRoot, &pRoot, 0))
++    ){
++      pCur->eState = CURSOR_INVALID;
++      return rc;
++    }
++    releasePage(pCur->pPage);
++    pageIntegrity(pRoot);
++    pCur->pPage = pRoot;
+   }
+-  releasePage(pCur->pPage);
+-  pageIntegrity(pRoot);
+-  pCur->pPage = pRoot;
+   pCur->idx = 0;
+   pCur->info.nSize = 0;
+   if( pRoot->nCell==0 && !pRoot->leaf ){
+@@ -2627,23 +3258,26 @@
+     assert( pRoot->pgno==1 );
+     subpage = get4byte(&pRoot->aData[pRoot->hdrOffset+8]);
+     assert( subpage>0 );
+-    pCur->isValid = 1;
++    pCur->eState = CURSOR_VALID;
+     rc = moveToChild(pCur, subpage);
+   }
+-  pCur->isValid = pCur->pPage->nCell>0;
++  pCur->eState = ((pCur->pPage->nCell>0)?CURSOR_VALID:CURSOR_INVALID);
+   return rc;
+ }
+ 
+ /*
+ ** Move the cursor down to the left-most leaf entry beneath the
+ ** entry to which it is currently pointing.
++**
++** The left-most leaf is the one with the smallest key - the first
++** in ascending order.
+ */
+ static int moveToLeftmost(BtCursor *pCur){
+   Pgno pgno;
+   int rc;
+   MemPage *pPage;
+ 
+-  assert( pCur->isValid );
++  assert( pCur->eState==CURSOR_VALID );
+   while( !(pPage = pCur->pPage)->leaf ){
+     assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
+     pgno = get4byte(findCell(pPage, pCur->idx));
+@@ -2659,13 +3293,16 @@
+ ** between moveToLeftmost() and moveToRightmost().  moveToLeftmost()
+ ** finds the left-most entry beneath the *entry* whereas moveToRightmost()
+ ** finds the right-most entry beneath the *page*.
++**
++** The right-most entry is the one with the largest key - the last
++** key in ascending order.
+ */
+ static int moveToRightmost(BtCursor *pCur){
+   Pgno pgno;
+   int rc;
+   MemPage *pPage;
+ 
+-  assert( pCur->isValid );
++  assert( pCur->eState==CURSOR_VALID );
+   while( !(pPage = pCur->pPage)->leaf ){
+     pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
+     pCur->idx = pPage->nCell;
+@@ -2685,7 +3322,7 @@
+   int rc;
+   rc = moveToRoot(pCur);
+   if( rc ) return rc;
+-  if( pCur->isValid==0 ){
++  if( pCur->eState==CURSOR_INVALID ){
+     assert( pCur->pPage->nCell==0 );
+     *pRes = 1;
+     return SQLITE_OK;
+@@ -2704,12 +3341,12 @@
+   int rc;
+   rc = moveToRoot(pCur);
+   if( rc ) return rc;
+-  if( pCur->isValid==0 ){
++  if( CURSOR_INVALID==pCur->eState ){
+     assert( pCur->pPage->nCell==0 );
+     *pRes = 1;
+     return SQLITE_OK;
+   }
+-  assert( pCur->isValid );
++  assert( pCur->eState==CURSOR_VALID );
+   *pRes = 0;
+   rc = moveToRightmost(pCur);
+   return rc;
+@@ -2720,7 +3357,7 @@
+ **
+ ** For INTKEY tables, only the nKey parameter is used.  pKey is
+ ** ignored.  For other tables, nKey is the number of bytes of data
+-** in nKey.  The comparison function specified when the cursor was
++** in pKey.  The comparison function specified when the cursor was
+ ** created is used to compare keys.
+ **
+ ** If an exact match is not found, then the cursor is always
+@@ -2744,11 +3381,13 @@
+ */
+ int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, i64 nKey, int *pRes){
+   int rc;
++  int tryRightmost;
+   rc = moveToRoot(pCur);
+   if( rc ) return rc;
+   assert( pCur->pPage );
+   assert( pCur->pPage->isInit );
+-  if( pCur->isValid==0 ){
++  tryRightmost = pCur->pPage->intKey;
++  if( pCur->eState==CURSOR_INVALID ){
+     *pRes = -1;
+     assert( pCur->pPage->nCell==0 );
+     return SQLITE_OK;
+@@ -2769,18 +3408,29 @@
+       i64 nCellKey;
+       pCur->idx = (lwr+upr)/2;
+       pCur->info.nSize = 0;
+-      sqlite3BtreeKeySize(pCur, &nCellKey);
+       if( pPage->intKey ){
++        u8 *pCell;
++        if( tryRightmost ){
++          pCur->idx = upr;
++        }
++        pCell = findCell(pPage, pCur->idx) + pPage->childPtrSize;
++        if( pPage->hasData ){
++          u32 dummy;
++          pCell += getVarint32(pCell, &dummy);
++        }
++        getVarint(pCell, (u64 *)&nCellKey);
+         if( nCellKey<nKey ){
+           c = -1;
+         }else if( nCellKey>nKey ){
+           c = +1;
++          tryRightmost = 0;
+         }else{
+           c = 0;
+         }
+       }else{
+         int available;
+         pCellKey = (void *)fetchPayload(pCur, &available, 0);
++        nCellKey = pCur->info.nKey;
+         if( available>=nCellKey ){
+           c = pCur->xCompare(pCur->pArg, nCellKey, pCellKey, nKey, pKey);
+         }else{
+@@ -2840,7 +3490,11 @@
+ ** the first entry.  TRUE is also returned if the table is empty.
+ */
+ int sqlite3BtreeEof(BtCursor *pCur){
+-  return pCur->isValid==0;
++  /* TODO: What if the cursor is in CURSOR_REQUIRESEEK but all table entries
++  ** have been deleted? This API will need to change to return an error code
++  ** as well as the boolean result value.
++  */
++  return (CURSOR_VALID!=pCur->eState);
+ }
+ 
+ /*
+@@ -2851,10 +3505,24 @@
+ */
+ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
+   int rc;
+-  MemPage *pPage = pCur->pPage;
++  MemPage *pPage;
+ 
++#ifndef SQLITE_OMIT_SHARED_CACHE
++  rc = restoreOrClearCursorPosition(pCur, 1);
++  if( rc!=SQLITE_OK ){
++    return rc;
++  }
++  if( pCur->skip>0 ){
++    pCur->skip = 0;
++    *pRes = 0;
++    return SQLITE_OK;
++  }
++  pCur->skip = 0;
++#endif 
++
+   assert( pRes!=0 );
+-  if( pCur->isValid==0 ){
++  pPage = pCur->pPage;
++  if( CURSOR_INVALID==pCur->eState ){
+     *pRes = 1;
+     return SQLITE_OK;
+   }
+@@ -2874,7 +3542,7 @@
+     do{
+       if( isRootPage(pPage) ){
+         *pRes = 1;
+-        pCur->isValid = 0;
++        pCur->eState = CURSOR_INVALID;
+         return SQLITE_OK;
+       }
+       moveToParent(pCur);
+@@ -2906,7 +3574,21 @@
+   int rc;
+   Pgno pgno;
+   MemPage *pPage;
+-  if( pCur->isValid==0 ){
++
++#ifndef SQLITE_OMIT_SHARED_CACHE
++  rc = restoreOrClearCursorPosition(pCur, 1);
++  if( rc!=SQLITE_OK ){
++    return rc;
++  }
++  if( pCur->skip<0 ){
++    pCur->skip = 0;
++    *pRes = 0;
++    return SQLITE_OK;
++  }
++  pCur->skip = 0;
++#endif
++
++  if( CURSOR_INVALID==pCur->eState ){
+     *pRes = 1;
+     return SQLITE_OK;
+   }
+@@ -2922,7 +3604,7 @@
+   }else{
+     while( pCur->idx==0 ){
+       if( isRootPage(pPage) ){
+-        pCur->isValid = 0;
++        pCur->eState = CURSOR_INVALID;
+         *pRes = 1;
+         return SQLITE_OK;
+       }
+@@ -2963,7 +3645,7 @@
+ ** is only used by auto-vacuum databases when allocating a new table.
+ */
+ static int allocatePage(
+-  Btree *pBt, 
++  BtShared *pBt, 
+   MemPage **ppPage, 
+   Pgno *pPgno, 
+   Pgno nearby,
+@@ -3150,7 +3832,7 @@
+     *pPgno = sqlite3pager_pagecount(pBt->pPager) + 1;
+ 
+ #ifndef SQLITE_OMIT_AUTOVACUUM
+-    if( pBt->autoVacuum && PTRMAP_ISPAGE(pBt->usableSize, *pPgno) ){
++    if( pBt->autoVacuum && PTRMAP_ISPAGE(pBt, *pPgno) ){
+       /* If *pPgno refers to a pointer-map page, allocate two new pages
+       ** at the end of the file instead of one. The first allocated page
+       ** becomes a new pointer-map page, the second is used by the caller.
+@@ -3181,7 +3863,7 @@
+ ** sqlite3pager_unref() is NOT called for pPage.
+ */
+ static int freePage(MemPage *pPage){
+-  Btree *pBt = pPage->pBt;
++  BtShared *pBt = pPage->pBt;
+   MemPage *pPage1 = pBt->pPage1;
+   int rc, n, k;
+ 
+@@ -3249,7 +3931,7 @@
+ ** Free any overflow pages associated with the given Cell.
+ */
+ static int clearCell(MemPage *pPage, unsigned char *pCell){
+-  Btree *pBt = pPage->pBt;
++  BtShared *pBt = pPage->pBt;
+   CellInfo info;
+   Pgno ovflPgno;
+   int rc;
+@@ -3301,7 +3983,7 @@
+   MemPage *pToRelease = 0;
+   unsigned char *pPrior;
+   unsigned char *pPayload;
+-  Btree *pBt = pPage->pBt;
++  BtShared *pBt = pPage->pBt;
+   Pgno pgnoOvfl = 0;
+   int nHeader;
+   CellInfo info;
+@@ -3390,7 +4072,7 @@
+ ** given in the second argument so that MemPage.pParent holds the
+ ** pointer in the third argument.
+ */
+-static int reparentPage(Btree *pBt, Pgno pgno, MemPage *pNewParent, int idx){
++static int reparentPage(BtShared *pBt, Pgno pgno, MemPage *pNewParent, int idx){
+   MemPage *pThis;
+   unsigned char *aData;
+ 
+@@ -3433,7 +4115,7 @@
+ */
+ static int reparentChildPages(MemPage *pPage){
+   int i;
+-  Btree *pBt = pPage->pBt;
++  BtShared *pBt = pPage->pBt;
+   int rc = SQLITE_OK;
+ 
+   if( pPage->leaf ) return SQLITE_OK;
+@@ -3666,7 +4348,7 @@
+   u8 *pCell;
+   int szCell;
+   CellInfo info;
+-  Btree *pBt = pPage->pBt;
++  BtShared *pBt = pPage->pBt;
+   int parentIdx = pParent->nCell;   /* pParent new divider cell index */
+   int parentSize;                   /* Size of new divider cell */
+   u8 parentCell[64];                /* Space for the new divider cell */
+@@ -3775,7 +4457,7 @@
+ */
+ static int balance_nonroot(MemPage *pPage){
+   MemPage *pParent;            /* The parent of pPage */
+-  Btree *pBt;                  /* The whole database */
++  BtShared *pBt;                  /* The whole database */
+   int nCell = 0;               /* Number of cells in apCell[] */
+   int nMaxCells = 0;           /* Allocated size of apCell, szCell, aFrom. */
+   int nOld;                    /* Number of pages in apOld[] */
+@@ -3796,7 +4478,6 @@
+   MemPage *apCopy[NB];         /* Private copies of apOld[] pages */
+   MemPage *apNew[NB+2];        /* pPage and up to NB siblings after balancing */
+   Pgno pgnoNew[NB+2];          /* Page numbers for each page in apNew[] */
+-  int idxDiv[NB];              /* Indices of divider cells in pParent */
+   u8 *apDiv[NB];               /* Divider cells in pParent */
+   int cntNew[NB+2];            /* Index in aCell[] of cell after i-th page */
+   int szNew[NB+2];             /* Combined size of cells place on i-th page */
+@@ -3815,8 +4496,10 @@
+   assert( sqlite3pager_iswriteable(pPage->aData) );
+   pBt = pPage->pBt;
+   pParent = pPage->pParent;
+-  sqlite3pager_write(pParent->aData);
+   assert( pParent );
++  if( SQLITE_OK!=(rc = sqlite3pager_write(pParent->aData)) ){
++    return rc;
++  }
+   TRACE(("BALANCE: begin page %d child of %d\n", pPage->pgno, pParent->pgno));
+ 
+ #ifndef SQLITE_OMIT_QUICKBALANCE
+@@ -3888,7 +4571,6 @@
+   nDiv = 0;
+   for(i=0, k=nxDiv; i<NB; i++, k++){
+     if( k<pParent->nCell ){
+-      idxDiv[i] = k;
+       apDiv[i] = findCell(pParent, k);
+       nDiv++;
+       assert( !pParent->leaf );
+@@ -4326,7 +5008,7 @@
+   MemPage *pChild;             /* The only child page of pPage */
+   Pgno pgnoChild;              /* Page number for pChild */
+   int rc = SQLITE_OK;          /* Return code from subprocedures */
+-  Btree *pBt;                  /* The main BTree structure */
++  BtShared *pBt;                  /* The main BTree structure */
+   int mxCellPerPage;           /* Maximum number of cells per page */
+   u8 **apCell;                 /* All cells from pages being balanced */
+   int *szCell;                 /* Local size of all cells */
+@@ -4428,7 +5110,7 @@
+   int rc;             /* Return value from subprocedures */
+   MemPage *pChild;    /* Pointer to a new child page */
+   Pgno pgnoChild;     /* Page number of the new child page */
+-  Btree *pBt;         /* The BTree */
++  BtShared *pBt;         /* The BTree */
+   int usableSize;     /* Total usable size of a page */
+   u8 *data;           /* Content of the parent page */
+   u8 *cdata;          /* Content of the child page */
+@@ -4517,10 +5199,12 @@
+ ** a page entirely and we do not want to leave any cursors 
+ ** pointing to non-existant pages or cells.
+ */
+-static int checkReadLocks(Btree *pBt, Pgno pgnoRoot, BtCursor *pExclude){
++static int checkReadLocks(BtShared *pBt, Pgno pgnoRoot, BtCursor *pExclude){
+   BtCursor *p;
+   for(p=pBt->pCursor; p; p=p->pNext){
++    u32 flags = (p->pBtree->pSqlite ? p->pBtree->pSqlite->flags : 0);
+     if( p->pgnoRoot!=pgnoRoot || p==pExclude ) continue;
++    if( p->wrFlag==0 && flags&SQLITE_ReadUncommitted ) continue;
+     if( p->wrFlag==0 ) return SQLITE_LOCKED;
+     if( p->pPage->pgno!=p->pgnoRoot ){
+       moveToRoot(p);
+@@ -4547,11 +5231,11 @@
+   int loc;
+   int szNew;
+   MemPage *pPage;
+-  Btree *pBt = pCur->pBt;
++  BtShared *pBt = pCur->pBtree->pBt;
+   unsigned char *oldCell;
+   unsigned char *newCell = 0;
+ 
+-  if( pBt->inTrans!=TRANS_WRITE ){
++  if( pBt->inTransaction!=TRANS_WRITE ){
+     /* Must start a transaction before doing an insert */
+     return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
+   }
+@@ -4562,8 +5246,16 @@
+   if( checkReadLocks(pBt, pCur->pgnoRoot, pCur) ){
+     return SQLITE_LOCKED; /* The table pCur points to has a read lock */
+   }
+-  rc = sqlite3BtreeMoveto(pCur, pKey, nKey, &loc);
+-  if( rc ) return rc;
++
++  /* Save the positions of any other cursors open on this table */
++  restoreOrClearCursorPosition(pCur, 0);
++  if( 
++    SQLITE_OK!=(rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur)) ||
++    SQLITE_OK!=(rc = sqlite3BtreeMoveto(pCur, pKey, nKey, &loc))
++  ){
++    return rc;
++  }
++
+   pPage = pCur->pPage;
+   assert( pPage->intKey || nKey>=0 );
+   assert( pPage->leaf || !pPage->leafData );
+@@ -4579,7 +5271,7 @@
+   if( rc ) goto end_insert;
+   assert( szNew==cellSizePtr(pPage, newCell) );
+   assert( szNew<=MX_CELL_SIZE(pBt) );
+-  if( loc==0 && pCur->isValid ){
++  if( loc==0 && CURSOR_VALID==pCur->eState ){
+     int szOld;
+     assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
+     oldCell = findCell(pPage, pCur->idx);
+@@ -4619,10 +5311,10 @@
+   unsigned char *pCell;
+   int rc;
+   Pgno pgnoChild = 0;
+-  Btree *pBt = pCur->pBt;
++  BtShared *pBt = pCur->pBtree->pBt;
+ 
+   assert( pPage->isInit );
+-  if( pBt->inTrans!=TRANS_WRITE ){
++  if( pBt->inTransaction!=TRANS_WRITE ){
+     /* Must start a transaction before doing a delete */
+     return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
+   }
+@@ -4636,9 +5328,20 @@
+   if( checkReadLocks(pBt, pCur->pgnoRoot, pCur) ){
+     return SQLITE_LOCKED; /* The table pCur points to has a read lock */
+   }
+-  rc = sqlite3pager_write(pPage->aData);
+-  if( rc ) return rc;
+ 
++  /* Restore the current cursor position (a no-op if the cursor is not in 
++  ** CURSOR_REQUIRESEEK state) and save the positions of any other cursors 
++  ** open on the same table. Then call sqlite3pager_write() on the page
++  ** that the entry will be deleted from.
++  */
++  if( 
++    (rc = restoreOrClearCursorPosition(pCur, 1))!=0 ||
++    (rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur))!=0 ||
++    (rc = sqlite3pager_write(pPage->aData))!=0
++  ){
++    return rc;
++  }
++
+   /* Locate the cell within it's page and leave pCell pointing to the
+   ** data. The clearCell() call frees any overflow pages associated with the
+   ** cell. The cell itself is still intact.
+@@ -4660,7 +5363,9 @@
+     */
+     BtCursor leafCur;
+     unsigned char *pNext;
+-    int szNext;
++    int szNext;  /* The compiler warning is wrong: szNext is always 
++                 ** initialized before use.  Adding an extra initialization
++                 ** to silence the compiler slows down the code. */
+     int notUsed;
+     unsigned char *tempCell = 0;
+     assert( !pPage->leafData );
+@@ -4722,11 +5427,12 @@
+ **     BTREE_INTKEY|BTREE_LEAFDATA     Used for SQL tables with rowid keys
+ **     BTREE_ZERODATA                  Used for SQL indices
+ */
+-int sqlite3BtreeCreateTable(Btree *pBt, int *piTable, int flags){
++int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){
++  BtShared *pBt = p->pBt;
+   MemPage *pRoot;
+   Pgno pgnoRoot;
+   int rc;
+-  if( pBt->inTrans!=TRANS_WRITE ){
++  if( pBt->inTransaction!=TRANS_WRITE ){
+     /* Must start a transaction first */
+     return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
+   }
+@@ -4753,14 +5459,14 @@
+     ** root page of the new table should go. meta[3] is the largest root-page
+     ** created so far, so the new root-page is (meta[3]+1).
+     */
+-    rc = sqlite3BtreeGetMeta(pBt, 4, &pgnoRoot);
++    rc = sqlite3BtreeGetMeta(p, 4, &pgnoRoot);
+     if( rc!=SQLITE_OK ) return rc;
+     pgnoRoot++;
+ 
+     /* The new root-page may not be allocated on a pointer-map page, or the
+     ** PENDING_BYTE page.
+     */
+-    if( pgnoRoot==PTRMAP_PAGENO(pBt->usableSize, pgnoRoot) ||
++    if( pgnoRoot==PTRMAP_PAGENO(pBt, pgnoRoot) ||
+         pgnoRoot==PENDING_BYTE_PAGE(pBt) ){
+       pgnoRoot++;
+     }
+@@ -4820,7 +5526,7 @@
+       releasePage(pRoot);
+       return rc;
+     }
+-    rc = sqlite3BtreeUpdateMeta(pBt, 4, pgnoRoot);
++    rc = sqlite3BtreeUpdateMeta(p, 4, pgnoRoot);
+     if( rc ){
+       releasePage(pRoot);
+       return rc;
+@@ -4843,7 +5549,7 @@
+ ** the page to the freelist.
+ */
+ static int clearDatabasePage(
+-  Btree *pBt,           /* The BTree that contains the table */
++  BtShared *pBt,           /* The BTree that contains the table */
+   Pgno pgno,            /* Page number to clear */
+   MemPage *pParent,     /* Parent page.  NULL for the root */
+   int freePageFlag      /* Deallocate page if true */
+@@ -4894,23 +5600,35 @@
+ ** read cursors on the table.  Open write cursors are moved to the
+ ** root of the table.
+ */
+-int sqlite3BtreeClearTable(Btree *pBt, int iTable){
++int sqlite3BtreeClearTable(Btree *p, int iTable){
+   int rc;
+   BtCursor *pCur;
+-  if( pBt->inTrans!=TRANS_WRITE ){
++  BtShared *pBt = p->pBt;
++  sqlite3 *db = p->pSqlite;
++  if( p->inTrans!=TRANS_WRITE ){
+     return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
+   }
+-  for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
+-    if( pCur->pgnoRoot==(Pgno)iTable ){
+-      if( pCur->wrFlag==0 ) return SQLITE_LOCKED;
+-      moveToRoot(pCur);
++
++  /* If this connection is not in read-uncommitted mode and currently has
++  ** a read-cursor open on the table being cleared, return SQLITE_LOCKED.
++  */
++  if( 0==db || 0==(db->flags&SQLITE_ReadUncommitted) ){
++    for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
++      if( pCur->pBtree==p && pCur->pgnoRoot==(Pgno)iTable ){
++        if( 0==pCur->wrFlag ){
++          return SQLITE_LOCKED;
++        }
++        moveToRoot(pCur);
++      }
+     }
+   }
+-  rc = clearDatabasePage(pBt, (Pgno)iTable, 0, 0);
+-  if( rc ){
+-    sqlite3BtreeRollback(pBt);
++
++  /* Save the position of all cursors open on this table */
++  if( SQLITE_OK!=(rc = saveAllCursors(pBt, iTable, 0)) ){
++    return rc;
+   }
+-  return rc;
++
++  return clearDatabasePage(pBt, (Pgno)iTable, 0, 0);
+ }
+ 
+ /*
+@@ -4933,11 +5651,12 @@
+ ** The last root page is recorded in meta[3] and the value of
+ ** meta[3] is updated by this procedure.
+ */
+-int sqlite3BtreeDropTable(Btree *pBt, int iTable, int *piMoved){
++int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
+   int rc;
+   MemPage *pPage = 0;
++  BtShared *pBt = p->pBt;
+ 
+-  if( pBt->inTrans!=TRANS_WRITE ){
++  if( p->inTrans!=TRANS_WRITE ){
+     return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
+   }
+ 
+@@ -4953,7 +5672,7 @@
+ 
+   rc = getPage(pBt, (Pgno)iTable, &pPage);
+   if( rc ) return rc;
+-  rc = sqlite3BtreeClearTable(pBt, iTable);
++  rc = sqlite3BtreeClearTable(p, iTable);
+   if( rc ){
+     releasePage(pPage);
+     return rc;
+@@ -4968,7 +5687,7 @@
+ #else
+     if( pBt->autoVacuum ){
+       Pgno maxRootPgno;
+-      rc = sqlite3BtreeGetMeta(pBt, 4, &maxRootPgno);
++      rc = sqlite3BtreeGetMeta(p, 4, &maxRootPgno);
+       if( rc!=SQLITE_OK ){
+         releasePage(pPage);
+         return rc;
+@@ -5020,12 +5739,12 @@
+       if( maxRootPgno==PENDING_BYTE_PAGE(pBt) ){
+         maxRootPgno--;
+       }
+-      if( maxRootPgno==PTRMAP_PAGENO(pBt->usableSize, maxRootPgno) ){
++      if( maxRootPgno==PTRMAP_PAGENO(pBt, maxRootPgno) ){
+         maxRootPgno--;
+       }
+       assert( maxRootPgno!=PENDING_BYTE_PAGE(pBt) );
+ 
+-      rc = sqlite3BtreeUpdateMeta(pBt, 4, maxRootPgno);
++      rc = sqlite3BtreeUpdateMeta(p, 4, maxRootPgno);
+     }else{
+       rc = freePage(pPage);
+       releasePage(pPage);
+@@ -5050,10 +5769,21 @@
+ ** layer (and the SetCookie and ReadCookie opcodes) the number of
+ ** free pages is not visible.  So Cookie[0] is the same as Meta[1].
+ */
+-int sqlite3BtreeGetMeta(Btree *pBt, int idx, u32 *pMeta){
++int sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){
+   int rc;
+   unsigned char *pP1;
++  BtShared *pBt = p->pBt;
+ 
++  /* Reading a meta-data value requires a read-lock on page 1 (and hence
++  ** the sqlite_master table. We grab this lock regardless of whether or
++  ** not the SQLITE_ReadUncommitted flag is set (the table rooted at page
++  ** 1 is treated as a special case by queryTableLock() and lockTable()).
++  */
++  rc = queryTableLock(p, 1, READ_LOCK);
++  if( rc!=SQLITE_OK ){
++    return rc;
++  }
++
+   assert( idx>=0 && idx<=15 );
+   rc = sqlite3pager_get(pBt->pPager, 1, (void**)&pP1);
+   if( rc ) return rc;
+@@ -5067,18 +5797,21 @@
+   if( idx==4 && *pMeta>0 ) pBt->readOnly = 1;
+ #endif
+ 
+-  return SQLITE_OK;
++  /* Grab the read-lock on page 1. */
++  rc = lockTable(p, 1, READ_LOCK);
++  return rc;
+ }
+ 
+ /*
+ ** Write meta-information back into the database.  Meta[0] is
+ ** read-only and may not be written.
+ */
+-int sqlite3BtreeUpdateMeta(Btree *pBt, int idx, u32 iMeta){
++int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){
++  BtShared *pBt = p->pBt;
+   unsigned char *pP1;
+   int rc;
+   assert( idx>=1 && idx<=15 );
+-  if( pBt->inTrans!=TRANS_WRITE ){
++  if( p->inTrans!=TRANS_WRITE ){
+     return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
+   }
+   assert( pBt->pPage1!=0 );
+@@ -5094,6 +5827,9 @@
+ ** is currently pointing to.
+ */
+ int sqlite3BtreeFlags(BtCursor *pCur){
++  /* TODO: What about CURSOR_REQUIRESEEK state? Probably need to call
++  ** restoreOrClearCursorPosition() here.
++  */
+   MemPage *pPage = pCur->pPage;
+   return pPage ? pPage->aData[pPage->hdrOffset] : 0;
+ }
+@@ -5103,7 +5839,7 @@
+ ** Print a disassembly of the given page on standard output.  This routine
+ ** is used for debugging and testing only.
+ */
+-static int btreePageDump(Btree *pBt, int pgno, int recursive, MemPage *pParent){
++static int btreePageDump(BtShared *pBt, int pgno, int recursive, MemPage *pParent){
+   int rc;
+   MemPage *pPage;
+   int i, j, c;
+@@ -5199,12 +5935,12 @@
+   fflush(stdout);
+   return SQLITE_OK;
+ }
+-int sqlite3BtreePageDump(Btree *pBt, int pgno, int recursive){
+-  return btreePageDump(pBt, pgno, recursive, 0);
++int sqlite3BtreePageDump(Btree *p, int pgno, int recursive){
++  return btreePageDump(p->pBt, pgno, recursive, 0);
+ }
+ #endif
+ 
+-#ifdef SQLITE_TEST
++#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
+ /*
+ ** Fill aResult[] with information about the entry and page that the
+ ** cursor is pointing to.
+@@ -5227,6 +5963,11 @@
+   MemPage *pPage = pCur->pPage;
+   BtCursor tmpCur;
+ 
++  int rc = restoreOrClearCursorPosition(pCur, 1);
++  if( rc!=SQLITE_OK ){
++    return rc;
++  }
++
+   pageIntegrity(pPage);
+   assert( pPage->isInit );
+   getTempCursor(pCur, &tmpCur);
+@@ -5273,8 +6014,8 @@
+ ** Return the pager associated with a BTree.  This routine is used for
+ ** testing and debugging only.
+ */
+-Pager *sqlite3BtreePager(Btree *pBt){
+-  return pBt->pPager;
++Pager *sqlite3BtreePager(Btree *p){
++  return p->pBt->pPager;
+ }
+ 
+ /*
+@@ -5283,7 +6024,7 @@
+ */
+ typedef struct IntegrityCk IntegrityCk;
+ struct IntegrityCk {
+-  Btree *pBt;    /* The tree being checked out */
++  BtShared *pBt;    /* The tree being checked out */
+   Pager *pPager; /* The associated pager.  Also accessible by pBt->pPager */
+   int nPage;     /* Number of pages in the database */
+   int *anRef;    /* Number of times each page is referenced */
+@@ -5474,8 +6215,7 @@
+   int hdr, cellStart;
+   int nCell;
+   u8 *data;
+-  BtCursor cur;
+-  Btree *pBt;
++  BtShared *pBt;
+   int usableSize;
+   char zContext[100];
+   char *hit;
+@@ -5484,7 +6224,7 @@
+ 
+   /* Check that the page exists
+   */
+-  cur.pBt = pBt = pCheck->pBt;
++  pBt = pCheck->pBt;
+   usableSize = pBt->usableSize;
+   if( iPage==0 ) return 0;
+   if( checkRef(pCheck, iPage, zParentContext) ) return 0;
+@@ -5502,7 +6242,6 @@
+   /* Check out all the cells.
+   */
+   depth = 0;
+-  cur.pPage = pPage;
+   for(i=0; i<pPage->nCell; i++){
+     u8 *pCell;
+     int sz;
+@@ -5618,13 +6357,14 @@
+ ** and a pointer to that error message is returned.  The calling function
+ ** is responsible for freeing the error message when it is done.
+ */
+-char *sqlite3BtreeIntegrityCheck(Btree *pBt, int *aRoot, int nRoot){
++char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
+   int i;
+   int nRef;
+   IntegrityCk sCheck;
++  BtShared *pBt = p->pBt;
+ 
+   nRef = *sqlite3pager_stats(pBt->pPager);
+-  if( lockBtreeWithRetry(pBt)!=SQLITE_OK ){
++  if( lockBtreeWithRetry(p)!=SQLITE_OK ){
+     return sqliteStrDup("Unable to acquire a read lock on the database");
+   }
+   sCheck.pBt = pBt;
+@@ -5676,11 +6416,11 @@
+     ** references to pointer-map pages.
+     */
+     if( sCheck.anRef[i]==0 && 
+-       (PTRMAP_PAGENO(pBt->usableSize, i)!=i || !pBt->autoVacuum) ){
++       (PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){
+       checkAppendMsg(&sCheck, 0, "Page %d is never used", i);
+     }
+     if( sCheck.anRef[i]!=0 && 
+-       (PTRMAP_PAGENO(pBt->usableSize, i)==i && pBt->autoVacuum) ){
++       (PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){
+       checkAppendMsg(&sCheck, 0, "Pointer map page %d is referenced", i);
+     }
+ #endif
+@@ -5706,17 +6446,17 @@
+ /*
+ ** Return the full pathname of the underlying database file.
+ */
+-const char *sqlite3BtreeGetFilename(Btree *pBt){
+-  assert( pBt->pPager!=0 );
+-  return sqlite3pager_filename(pBt->pPager);
++const char *sqlite3BtreeGetFilename(Btree *p){
++  assert( p->pBt->pPager!=0 );
++  return sqlite3pager_filename(p->pBt->pPager);
+ }
+ 
+ /*
+ ** Return the pathname of the directory that contains the database file.
+ */
+-const char *sqlite3BtreeGetDirname(Btree *pBt){
+-  assert( pBt->pPager!=0 );
+-  return sqlite3pager_dirname(pBt->pPager);
++const char *sqlite3BtreeGetDirname(Btree *p){
++  assert( p->pBt->pPager!=0 );
++  return sqlite3pager_dirname(p->pBt->pPager);
+ }
+ 
+ /*
+@@ -5724,9 +6464,9 @@
+ ** value of this routine is the same regardless of whether the journal file
+ ** has been created or not.
+ */
+-const char *sqlite3BtreeGetJournalname(Btree *pBt){
+-  assert( pBt->pPager!=0 );
+-  return sqlite3pager_journalname(pBt->pPager);
++const char *sqlite3BtreeGetJournalname(Btree *p){
++  assert( p->pBt->pPager!=0 );
++  return sqlite3pager_journalname(p->pBt->pPager);
+ }
+ 
+ #ifndef SQLITE_OMIT_VACUUM
+@@ -5737,11 +6477,14 @@
+ ** The size of file pBtFrom may be reduced by this operation.
+ ** If anything goes wrong, the transaction on pBtFrom is rolled back.
+ */
+-int sqlite3BtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){
++int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
+   int rc = SQLITE_OK;
+   Pgno i, nPage, nToPage, iSkip;
+ 
+-  if( pBtTo->inTrans!=TRANS_WRITE || pBtFrom->inTrans!=TRANS_WRITE ){
++  BtShared *pBtTo = pTo->pBt;
++  BtShared *pBtFrom = pFrom->pBt;
++
++  if( pTo->inTrans!=TRANS_WRITE || pFrom->inTrans!=TRANS_WRITE ){
+     return SQLITE_ERROR;
+   }
+   if( pBtTo->pCursor ) return SQLITE_BUSY;
+@@ -5770,7 +6513,7 @@
+     rc = sqlite3pager_truncate(pBtTo->pPager, nPage);
+   }
+   if( rc ){
+-    sqlite3BtreeRollback(pBtTo);
++    sqlite3BtreeRollback(pTo);
+   }
+   return rc;  
+ }
+@@ -5779,15 +6522,15 @@
+ /*
+ ** Return non-zero if a transaction is active.
+ */
+-int sqlite3BtreeIsInTrans(Btree *pBt){
+-  return (pBt && (pBt->inTrans==TRANS_WRITE));
++int sqlite3BtreeIsInTrans(Btree *p){
++  return (p && (p->inTrans==TRANS_WRITE));
+ }
+ 
+ /*
+ ** Return non-zero if a statement transaction is active.
+ */
+-int sqlite3BtreeIsInStmt(Btree *pBt){
+-  return (pBt && pBt->inStmt);
++int sqlite3BtreeIsInStmt(Btree *p){
++  return (p->pBt && p->pBt->inStmt);
+ }
+ 
+ /*
+@@ -5804,30 +6547,93 @@
+ ** Once this is routine has returned, the only thing required to commit
+ ** the write-transaction for this database file is to delete the journal.
+ */
+-int sqlite3BtreeSync(Btree *pBt, const char *zMaster){
+-  if( pBt->inTrans==TRANS_WRITE ){
++int sqlite3BtreeSync(Btree *p, const char *zMaster){
++  int rc = SQLITE_OK;
++  if( p->inTrans==TRANS_WRITE ){
++    BtShared *pBt = p->pBt;
++    Pgno nTrunc = 0;
+ #ifndef SQLITE_OMIT_AUTOVACUUM
+-    Pgno nTrunc = 0;
+     if( pBt->autoVacuum ){
+-      int rc = autoVacuumCommit(pBt, &nTrunc); 
+-      if( rc!=SQLITE_OK ) return rc;
++      rc = autoVacuumCommit(pBt, &nTrunc); 
++      if( rc!=SQLITE_OK ){
++        return rc;
++      }
+     }
+-    return sqlite3pager_sync(pBt->pPager, zMaster, nTrunc);
+ #endif
+-    return sqlite3pager_sync(pBt->pPager, zMaster, 0);
++    rc = sqlite3pager_sync(pBt->pPager, zMaster, nTrunc);
+   }
+-  return SQLITE_OK;
++  return rc;
+ }
+ 
+-#ifndef SQLITE_OMIT_GLOBALRECOVER
+ /*
+-** Reset the btree and underlying pager after a malloc() failure. Any
+-** transaction that was active when malloc() failed is rolled back.
++** This function returns a pointer to a blob of memory associated with
++** a single shared-btree. The memory is used by client code for it's own
++** purposes (for example, to store a high-level schema associated with 
++** the shared-btree). The btree layer manages reference counting issues.
++**
++** The first time this is called on a shared-btree, nBytes bytes of memory
++** are allocated, zeroed, and returned to the caller. For each subsequent 
++** call the nBytes parameter is ignored and a pointer to the same blob
++** of memory returned. 
++**
++** Just before the shared-btree is closed, the function passed as the 
++** xFree argument when the memory allocation was made is invoked on the 
++** blob of allocated memory. This function should not call sqliteFree()
++** on the memory, the btree layer does that.
+ */
+-int sqlite3BtreeReset(Btree *pBt){
+-  if( pBt->pCursor ) return SQLITE_BUSY;
+-  pBt->inTrans = TRANS_NONE;
+-  unlockBtreeIfUnused(pBt);
+-  return sqlite3pager_reset(pBt->pPager);
++void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void *)){
++  BtShared *pBt = p->pBt;
++  if( !pBt->pSchema ){
++    pBt->pSchema = sqliteMalloc(nBytes);
++    pBt->xFreeSchema = xFree;
++  }
++  return pBt->pSchema;
+ }
++
++/*
++** Return true if another user of the same shared btree as the argument
++** handle holds an exclusive lock on the sqlite_master table.
++*/
++int sqlite3BtreeSchemaLocked(Btree *p){
++  return (queryTableLock(p, MASTER_ROOT, READ_LOCK)!=SQLITE_OK);
++}
++
++int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){
++  int rc = SQLITE_OK;
++#ifndef SQLITE_OMIT_SHARED_CACHE
++  u8 lockType = (isWriteLock?WRITE_LOCK:READ_LOCK);
++  rc = queryTableLock(p, iTab, lockType);
++  if( rc==SQLITE_OK ){
++    rc = lockTable(p, iTab, lockType);
++  }
+ #endif
++  return rc;
++}
++
++/*
++** The following debugging interface has to be in this file (rather
++** than in, for example, test1.c) so that it can get access to
++** the definition of BtShared.
++*/
++#if defined(SQLITE_DEBUG) && defined(TCLSH)
++#include <tcl.h>
++int sqlite3_shared_cache_report(
++  void * clientData,
++  Tcl_Interp *interp,
++  int objc,
++  Tcl_Obj *CONST objv[]
++){
++  const ThreadData *pTd = sqlite3ThreadDataReadOnly();
++  if( pTd->useSharedData ){
++    BtShared *pBt;
++    Tcl_Obj *pRet = Tcl_NewObj();
++    for(pBt=pTd->pBtree; pBt; pBt=pBt->pNext){
++      const char *zFile = sqlite3pager_filename(pBt->pPager);
++      Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(zFile, -1));
++      Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(pBt->nRef));
++    }
++    Tcl_SetObjResult(interp, pRet);
++  }
++  return TCL_OK;
++}
++#endif
+Index: sqlite/delete.c
+===================================================================
+--- amarok/src/sqlite/delete.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/delete.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -59,14 +59,19 @@
+ /*
+ ** Generate code that will open a table for reading.
+ */
+-void sqlite3OpenTableForReading(
+-  Vdbe *v,        /* Generate code into this VDBE */
++void sqlite3OpenTable(
++  Parse *p,       /* Generate code into this VDBE */
+   int iCur,       /* The cursor number of the table */
+-  Table *pTab     /* The table to be opened */
++  int iDb,        /* The database index in sqlite3.aDb[] */
++  Table *pTab,    /* The table to be opened */
++  int opcode      /* OP_OpenRead or OP_OpenWrite */
+ ){
+-  sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
++  Vdbe *v = sqlite3GetVdbe(p);
++  assert( opcode==OP_OpenWrite || opcode==OP_OpenRead );
++  sqlite3TableLock(p, iDb, pTab->tnum, (opcode==OP_OpenWrite), pTab->zName);
++  sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
+   VdbeComment((v, "# %s", pTab->zName));
+-  sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum);
++  sqlite3VdbeAddOp(v, opcode, iCur, pTab->tnum);
+   sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol);
+ }
+ 
+@@ -95,6 +100,7 @@
+   AuthContext sContext;  /* Authorization context */
+   int oldIdx = -1;       /* Cursor for the OLD table of AFTER triggers */
+   NameContext sNC;       /* Name context to resolve expressions in */
++  int iDb;
+ 
+ #ifndef SQLITE_OMIT_TRIGGER
+   int isView;                  /* True if attempting to delete from a view */
+@@ -102,7 +108,7 @@
+ #endif
+ 
+   sContext.pParse = 0;
+-  if( pParse->nErr || sqlite3_malloc_failed ){
++  if( pParse->nErr || sqlite3MallocFailed() ){
+     goto delete_from_cleanup;
+   }
+   db = pParse->db;
+@@ -134,8 +140,9 @@
+   if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){
+     goto delete_from_cleanup;
+   }
+-  assert( pTab->iDb<db->nDb );
+-  zDb = db->aDb[pTab->iDb].zName;
++  iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
++  assert( iDb<db->nDb );
++  zDb = db->aDb[iDb].zName;
+   if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){
+     goto delete_from_cleanup;
+   }
+@@ -176,7 +183,7 @@
+     goto delete_from_cleanup;
+   }
+   if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
+-  sqlite3BeginWriteOperation(pParse, triggers_exist, pTab->iDb);
++  sqlite3BeginWriteOperation(pParse, triggers_exist, iDb);
+ 
+   /* If we are trying to delete from a view, realize that view into
+   ** a ephemeral table.
+@@ -203,20 +210,24 @@
+       /* If counting rows deleted, just count the total number of
+       ** entries in the table. */
+       int endOfLoop = sqlite3VdbeMakeLabel(v);
+-      int addr;
++      int addr2;
+       if( !isView ){
+-        sqlite3OpenTableForReading(v, iCur, pTab);
++        sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
+       }
+       sqlite3VdbeAddOp(v, OP_Rewind, iCur, sqlite3VdbeCurrentAddr(v)+2);
+-      addr = sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
+-      sqlite3VdbeAddOp(v, OP_Next, iCur, addr);
++      addr2 = sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
++      sqlite3VdbeAddOp(v, OP_Next, iCur, addr2);
+       sqlite3VdbeResolveLabel(v, endOfLoop);
+       sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
+     }
+     if( !isView ){
+-      sqlite3VdbeAddOp(v, OP_Clear, pTab->tnum, pTab->iDb);
++      sqlite3VdbeAddOp(v, OP_Clear, pTab->tnum, iDb);
++      if( !pParse->nested ){
++        sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
++      }
+       for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+-        sqlite3VdbeAddOp(v, OP_Clear, pIdx->tnum, pIdx->iDb);
++        assert( pIdx->pSchema==pTab->pSchema );
++        sqlite3VdbeAddOp(v, OP_Clear, pIdx->tnum, iDb);
+       }
+     }
+   }
+@@ -225,13 +236,6 @@
+   ** the table and pick which records to delete.
+   */
+   else{
+-    /* Ensure all required collation sequences are available. */
+-    for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+-      if( sqlite3CheckIndexCollSeq(pParse, pIdx) ){
+-        goto delete_from_cleanup;
+-      }
+-    }
+-
+     /* Begin the database scan
+     */
+     pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0);
+@@ -269,7 +273,7 @@
+       addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end);
+       if( !isView ){
+         sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
+-        sqlite3OpenTableForReading(v, iCur, pTab);
++        sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
+       }
+       sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
+       sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
+@@ -339,7 +343,7 @@
+   if( db->flags & SQLITE_CountRows && pParse->nested==0 && !pParse->trigStack ){
+     sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
+     sqlite3VdbeSetNumCols(v, 1);
+-    sqlite3VdbeSetColName(v, 0, "rows deleted", P3_STATIC);
++    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", P3_STATIC);
+   }
+ 
+ delete_from_cleanup:
+@@ -380,6 +384,9 @@
+   addr = sqlite3VdbeAddOp(v, OP_NotExists, iCur, 0);
+   sqlite3GenerateRowIndexDelete(db, v, pTab, iCur, 0);
+   sqlite3VdbeAddOp(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0));
++  if( count ){
++    sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
++  }
+   sqlite3VdbeJumpHere(v, addr);
+ }
+ 
+Index: sqlite/printf.c
+===================================================================
+--- amarok/src/sqlite/printf.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/printf.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -120,10 +120,12 @@
+   {  'u', 10, 0, etRADIX,      0,  0 },
+   {  'x', 16, 0, etRADIX,      16, 1 },
+   {  'X', 16, 0, etRADIX,      0,  4 },
++#ifndef SQLITE_OMIT_FLOATING_POINT
+   {  'f',  0, 1, etFLOAT,      0,  0 },
+   {  'e',  0, 1, etEXP,        30, 0 },
+   {  'E',  0, 1, etEXP,        14, 0 },
+   {  'G',  0, 1, etGENERIC,    14, 0 },
++#endif
+   {  'i', 10, 1, etRADIX,      0,  0 },
+   {  'n',  0, 0, etSIZE,       0,  0 },
+   {  '%',  0, 0, etPERCENT,    0,  0 },
+@@ -134,10 +136,10 @@
+ #define etNINFO  (sizeof(fmtinfo)/sizeof(fmtinfo[0]))
+ 
+ /*
+-** If NOFLOATINGPOINT is defined, then none of the floating point
++** If SQLITE_OMIT_FLOATING_POINT is defined, then none of the floating point
+ ** conversions will work.
+ */
+-#ifndef etNOFLOATINGPOINT
++#ifndef SQLITE_OMIT_FLOATING_POINT
+ /*
+ ** "*val" is a double such that 0.1 <= *val < 10.0
+ ** Return the ascii code for the leading digit of *val, then
+@@ -161,7 +163,7 @@
+   *val = (*val - d)*10.0;
+   return digit;
+ }
+-#endif
++#endif /* SQLITE_OMIT_FLOATING_POINT */
+ 
+ /*
+ ** On machines with a small stack size, you can redefine the
+@@ -234,7 +236,7 @@
+   static const char spaces[] =
+    "                                                                         ";
+ #define etSPACESIZE (sizeof(spaces)-1)
+-#ifndef etNOFLOATINGPOINT
++#ifndef SQLITE_OMIT_FLOATING_POINT
+   int  exp, e2;              /* exponent of real numbers */
+   double rounder;            /* Used for rounding floating point values */
+   etByte flag_dp;            /* True if decimal point should be shown */
+@@ -425,7 +427,7 @@
+       case etEXP:
+       case etGENERIC:
+         realvalue = va_arg(ap,double);
+-#ifndef etNOFLOATINGPOINT
++#ifndef SQLITE_OMIT_FLOATING_POINT
+         if( precision<0 ) precision = 6;         /* Set default precision */
+         if( precision>etBUFSIZE/2-10 ) precision = etBUFSIZE/2-10;
+         if( realvalue<0.0 ){
+@@ -594,13 +596,13 @@
+         break;
+       case etSQLESCAPE:
+       case etSQLESCAPE2: {
+-        int i, j, n, c, isnull;
++        int i, j, n, ch, isnull;
+         int needQuote;
+-        char *arg = va_arg(ap,char*);
+-        isnull = arg==0;
+-        if( isnull ) arg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
+-        for(i=n=0; (c=arg[i])!=0; i++){
+-          if( c=='\'' )  n++;
++        char *escarg = va_arg(ap,char*);
++        isnull = escarg==0;
++        if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
++        for(i=n=0; (ch=escarg[i])!=0; i++){
++          if( ch=='\'' )  n++;
+         }
+         needQuote = !isnull && xtype==etSQLESCAPE2;
+         n += i + 1 + needQuote*2;
+@@ -612,9 +614,9 @@
+         }
+         j = 0;
+         if( needQuote ) bufpt[j++] = '\'';
+-        for(i=0; (c=arg[i])!=0; i++){
+-          bufpt[j++] = c;
+-          if( c=='\'' ) bufpt[j++] = c;
++        for(i=0; (ch=escarg[i])!=0; i++){
++          bufpt[j++] = ch;
++          if( ch=='\'' ) bufpt[j++] = ch;
+         }
+         if( needQuote ) bufpt[j++] = '\'';
+         bufpt[j] = 0;
+@@ -625,7 +627,7 @@
+       case etTOKEN: {
+         Token *pToken = va_arg(ap, Token*);
+         if( pToken && pToken->z ){
+-          (*func)(arg, pToken->z, pToken->n);
++          (*func)(arg, (char*)pToken->z, pToken->n);
+         }
+         length = width = 0;
+         break;
+Index: sqlite/analyze.c
+===================================================================
+--- amarok/src/sqlite/analyze.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/analyze.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -11,7 +11,7 @@
+ *************************************************************************
+ ** This file contains code associated with the ANALYZE command.
+ **
+-** @(#) $Id: analyze.c,v 1.9 2005/09/20 17:42:23 drh Exp $
++** @(#) $Id: analyze.c,v 1.16 2006/01/10 17:58:23 danielk1977 Exp $
+ */
+ #ifndef SQLITE_OMIT_ANALYZE
+ #include "sqliteInt.h"
+@@ -61,8 +61,14 @@
+     sqlite3VdbeAddOp(v, OP_Clear, pStat->tnum, iDb);
+   }
+ 
+-  /* Open the sqlite_stat1 table for writing.
++  /* Open the sqlite_stat1 table for writing. Unless it was created
++  ** by this vdbe program, lock it for writing at the shared-cache level. 
++  ** If this vdbe did create the sqlite_stat1 table, then it must have 
++  ** already obtained a schema-lock, making the write-lock redundant.
+   */
++  if( iRootPage>0 ){
++    sqlite3TableLock(pParse, iDb, iRootPage, 1, "sqlite_stat1");
++  }
+   sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
+   sqlite3VdbeAddOp(v, OP_OpenWrite, iStatCur, iRootPage);
+   sqlite3VdbeAddOp(v, OP_SetNumColumns, iStatCur, 3);
+@@ -86,6 +92,7 @@
+   int topOfLoop;   /* The top of the loop */
+   int endOfLoop;   /* The end of the loop */
+   int addr;        /* The address of an instruction */
++  int iDb;         /* Index of database containing pTab */
+ 
+   v = sqlite3GetVdbe(pParse);
+   if( pTab==0 || pTab->pIndex==0 ){
+@@ -93,21 +100,29 @@
+     return;
+   }
+ 
++  iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
++  assert( iDb>=0 );
+ #ifndef SQLITE_OMIT_AUTHORIZATION
+   if( sqlite3AuthCheck(pParse, SQLITE_ANALYZE, pTab->zName, 0,
+-      pParse->db->aDb[pTab->iDb].zName ) ){
++      pParse->db->aDb[iDb].zName ) ){
+     return;
+   }
+ #endif
+ 
++  /* Establish a read-lock on the table at the shared-cache level. */
++  sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
++
+   iIdxCur = pParse->nTab;
+   for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
++    KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
++
+     /* Open a cursor to the index to be analyzed
+     */
+-    sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
++    assert( iDb==sqlite3SchemaToIndex(pParse->db, pIdx->pSchema) );
++    sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
+     VdbeComment((v, "# %s", pIdx->zName));
+     sqlite3VdbeOp3(v, OP_OpenRead, iIdxCur, pIdx->tnum,
+-                     (char*)&pIdx->keyInfo, P3_KEYINFO);
++        (char *)pKey, P3_KEYINFO_HANDOFF);
+     nCol = pIdx->nColumn;
+     if( iMem+nCol*2>=pParse->nMem ){
+       pParse->nMem = iMem+nCol*2+1;
+@@ -139,7 +154,7 @@
+     endOfLoop = sqlite3VdbeMakeLabel(v);
+     sqlite3VdbeAddOp(v, OP_Rewind, iIdxCur, endOfLoop);
+     topOfLoop = sqlite3VdbeCurrentAddr(v);
+-    sqlite3VdbeAddOp(v, OP_MemIncr, iMem, 0);
++    sqlite3VdbeAddOp(v, OP_MemIncr, 1, iMem);
+     for(i=0; i<nCol; i++){
+       sqlite3VdbeAddOp(v, OP_Column, iIdxCur, i);
+       sqlite3VdbeAddOp(v, OP_MemLoad, iMem+nCol+i+1, 0);
+@@ -147,7 +162,7 @@
+     }
+     sqlite3VdbeAddOp(v, OP_Goto, 0, endOfLoop);
+     for(i=0; i<nCol; i++){
+-      addr = sqlite3VdbeAddOp(v, OP_MemIncr, iMem+i+1, 0);
++      addr = sqlite3VdbeAddOp(v, OP_MemIncr, 1, iMem+i+1);
+       sqlite3VdbeChangeP2(v, topOfLoop + 3*i + 3, addr);
+       sqlite3VdbeAddOp(v, OP_Column, iIdxCur, i);
+       sqlite3VdbeAddOp(v, OP_MemStore, iMem+nCol+i+1, 1);
+@@ -188,13 +203,14 @@
+       sqlite3VdbeAddOp(v, OP_AddImm, -1, 0);
+       sqlite3VdbeAddOp(v, OP_MemLoad, iMem+i+1, 0);
+       sqlite3VdbeAddOp(v, OP_Divide, 0, 0);
++      sqlite3VdbeAddOp(v, OP_ToInt, 0, 0);
+       if( i==nCol-1 ){
+         sqlite3VdbeAddOp(v, OP_Concat, nCol*2-1, 0);
+       }else{
+         sqlite3VdbeAddOp(v, OP_Dup, 1, 0);
+       }
+     }
+-    sqlite3VdbeOp3(v, OP_MakeRecord, 3, 0, "ttt", 0);
++    sqlite3VdbeOp3(v, OP_MakeRecord, 3, 0, "aaa", 0);
+     sqlite3VdbeAddOp(v, OP_Insert, iStatCur, 0);
+     sqlite3VdbeJumpHere(v, addr);
+   }
+@@ -214,6 +230,7 @@
+ */
+ static void analyzeDatabase(Parse *pParse, int iDb){
+   sqlite3 *db = pParse->db;
++  Schema *pSchema = db->aDb[iDb].pSchema;    /* Schema of database iDb */
+   HashElem *k;
+   int iStatCur;
+   int iMem;
+@@ -222,7 +239,7 @@
+   iStatCur = pParse->nTab++;
+   openStatTable(pParse, iDb, iStatCur, 0);
+   iMem = pParse->nMem;
+-  for(k=sqliteHashFirst(&db->aDb[iDb].tblHash);  k; k=sqliteHashNext(k)){
++  for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
+     Table *pTab = (Table*)sqliteHashData(k);
+     analyzeOneTable(pParse, pTab, iStatCur, iMem);
+   }
+@@ -238,7 +255,7 @@
+   int iStatCur;
+ 
+   assert( pTab!=0 );
+-  iDb = pTab->iDb;
++  iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
+   sqlite3BeginWriteOperation(pParse, 0, iDb);
+   iStatCur = pParse->nTab++;
+   openStatTable(pParse, iDb, iStatCur, pTab->zName);
+@@ -360,7 +377,7 @@
+   char *zSql;
+ 
+   /* Clear any prior statistics */
+-  for(i=sqliteHashFirst(&db->aDb[iDb].idxHash); i; i=sqliteHashNext(i)){
++  for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
+     Index *pIdx = sqliteHashData(i);
+     sqlite3DefaultRowEst(pIdx);
+   }
+Index: sqlite/trigger.c
+===================================================================
+--- amarok/src/sqlite/trigger.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/trigger.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -58,6 +58,7 @@
+   int iDb;                /* The database to store the trigger in */
+   Token *pName;           /* The unqualified db name */
+   DbFixer sFix;
++  int iTabDb;
+ 
+   if( isTemp ){
+     /* If TEMP was specified, then the trigger name may not be qualified. */
+@@ -80,14 +81,16 @@
+   ** If sqlite3SrcListLookup() returns 0, indicating the table does not
+   ** exist, the error is caught by the block below.
+   */
+-  if( !pTableName || sqlite3_malloc_failed ) goto trigger_cleanup;
++  if( !pTableName || sqlite3MallocFailed() ){
++    goto trigger_cleanup;
++  }
+   pTab = sqlite3SrcListLookup(pParse, pTableName);
+-  if( pName2->n==0 && pTab && pTab->iDb==1 ){
++  if( pName2->n==0 && pTab && pTab->pSchema==db->aDb[1].pSchema ){
+     iDb = 1;
+   }
+ 
+   /* Ensure the table name matches database name and that the table exists */
+-  if( sqlite3_malloc_failed ) goto trigger_cleanup;
++  if( sqlite3MallocFailed() ) goto trigger_cleanup;
+   assert( pTableName->nSrc==1 );
+   if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName) && 
+       sqlite3FixSrcList(&sFix, pTableName) ){
+@@ -105,7 +108,7 @@
+   if( !zName || SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
+     goto trigger_cleanup;
+   }
+-  if( sqlite3HashFind(&(db->aDb[iDb].trigHash), zName,pName->n+1) ){
++  if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash), zName,pName->n+1) ){
+     sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
+     goto trigger_cleanup;
+   }
+@@ -130,17 +133,18 @@
+         " trigger on table: %S", pTableName, 0);
+     goto trigger_cleanup;
+   }
++  iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
+ 
+ #ifndef SQLITE_OMIT_AUTHORIZATION
+   {
+     int code = SQLITE_CREATE_TRIGGER;
+-    const char *zDb = db->aDb[pTab->iDb].zName;
++    const char *zDb = db->aDb[iTabDb].zName;
+     const char *zDbTrig = isTemp ? db->aDb[1].zName : zDb;
+-    if( pTab->iDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER;
++    if( iTabDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER;
+     if( sqlite3AuthCheck(pParse, code, zName, pTab->zName, zDbTrig) ){
+       goto trigger_cleanup;
+     }
+-    if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(pTab->iDb),0,zDb)){
++    if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iTabDb),0,zDb)){
+       goto trigger_cleanup;
+     }
+   }
+@@ -161,8 +165,8 @@
+   pTrigger->name = zName;
+   zName = 0;
+   pTrigger->table = sqliteStrDup(pTableName->a[0].zName);
+-  pTrigger->iDb = iDb;
+-  pTrigger->iTabDb = pTab->iDb;
++  pTrigger->pSchema = db->aDb[iDb].pSchema;
++  pTrigger->pTabSchema = pTab->pSchema;
+   pTrigger->op = op;
+   pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER;
+   pTrigger->pWhen = sqlite3ExprDup(pWhen);
+@@ -196,16 +200,18 @@
+   Trigger *pTrig = 0;     /* The trigger whose construction is finishing up */
+   sqlite3 *db = pParse->db;  /* The database */
+   DbFixer sFix;
++  int iDb;                   /* Database containing the trigger */
+ 
+   pTrig = pParse->pNewTrigger;
+   pParse->pNewTrigger = 0;
+-  if( pParse->nErr || pTrig==0 ) goto triggerfinish_cleanup;
++  if( pParse->nErr || !pTrig ) goto triggerfinish_cleanup;
++  iDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema);
+   pTrig->step_list = pStepList;
+   while( pStepList ){
+     pStepList->pTrig = pTrig;
+     pStepList = pStepList->pNext;
+   }
+-  if( sqlite3FixInit(&sFix, pParse, pTrig->iDb, "trigger", &pTrig->nameToken) 
++  if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", &pTrig->nameToken) 
+           && sqlite3FixTriggerStep(&sFix, pTrig->step_list) ){
+     goto triggerfinish_cleanup;
+   }
+@@ -223,7 +229,7 @@
+       { OP_String8,    0, 0,  "CREATE TRIGGER "},
+       { OP_String8,    0, 0,  0          },  /* 6: SQL */
+       { OP_Concat,     0, 0,  0          }, 
+-      { OP_MakeRecord, 5, 0,  "tttit"    },
++      { OP_MakeRecord, 5, 0,  "aaada"    },
+       { OP_Insert,     0, 0,  0          },
+     };
+     int addr;
+@@ -232,28 +238,30 @@
+     /* Make an entry in the sqlite_master table */
+     v = sqlite3GetVdbe(pParse);
+     if( v==0 ) goto triggerfinish_cleanup;
+-    sqlite3BeginWriteOperation(pParse, 0, pTrig->iDb);
+-    sqlite3OpenMasterTable(v, pTrig->iDb);
++    sqlite3BeginWriteOperation(pParse, 0, iDb);
++    sqlite3OpenMasterTable(pParse, iDb);
+     addr = sqlite3VdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
+     sqlite3VdbeChangeP3(v, addr+2, pTrig->name, 0); 
+     sqlite3VdbeChangeP3(v, addr+3, pTrig->table, 0); 
+-    sqlite3VdbeChangeP3(v, addr+6, pAll->z, pAll->n);
+-    sqlite3ChangeCookie(db, v, pTrig->iDb);
++    sqlite3VdbeChangeP3(v, addr+6, (char*)pAll->z, pAll->n);
++    sqlite3ChangeCookie(db, v, iDb);
+     sqlite3VdbeAddOp(v, OP_Close, 0, 0);
+-    sqlite3VdbeOp3(v, OP_ParseSchema, pTrig->iDb, 0, 
++    sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, 
+        sqlite3MPrintf("type='trigger' AND name='%q'", pTrig->name), P3_DYNAMIC);
+   }
+ 
+   if( db->init.busy ){
++    int n;
+     Table *pTab;
+     Trigger *pDel;
+-    pDel = sqlite3HashInsert(&db->aDb[pTrig->iDb].trigHash, 
++    pDel = sqlite3HashInsert(&db->aDb[iDb].pSchema->trigHash, 
+                      pTrig->name, strlen(pTrig->name)+1, pTrig);
+     if( pDel ){
+-      assert( sqlite3_malloc_failed && pDel==pTrig );
++      assert( sqlite3MallocFailed() && pDel==pTrig );
+       goto triggerfinish_cleanup;
+     }
+-    pTab = sqlite3LocateTable(pParse,pTrig->table,db->aDb[pTrig->iTabDb].zName);
++    n = strlen(pTrig->table) + 1;
++    pTab = sqlite3HashFind(&pTrig->pTabSchema->tblHash, pTrig->table, n);
+     assert( pTab!=0 );
+     pTrig->pNext = pTab->pTrigger;
+     pTab->pTrigger = pTrig;
+@@ -278,7 +286,7 @@
+ */
+ static void sqlitePersistTriggerStep(TriggerStep *p){
+   if( p->target.z ){
+-    p->target.z = sqliteStrNDup(p->target.z, p->target.n);
++    p->target.z = (u8*)sqliteStrNDup((char*)p->target.z, p->target.n);
+     p->target.dyn = 1;
+   }
+   if( p->pSelect ){
+@@ -312,7 +320,10 @@
+ */
+ TriggerStep *sqlite3TriggerSelectStep(Select *pSelect){
+   TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
+-  if( pTriggerStep==0 ) return 0;
++  if( pTriggerStep==0 ) {
++    sqlite3SelectDelete(pSelect);
++    return 0;
++  }
+ 
+   pTriggerStep->op = TK_SELECT;
+   pTriggerStep->pSelect = pSelect;
+@@ -430,7 +441,7 @@
+   int nName;
+   sqlite3 *db = pParse->db;
+ 
+-  if( sqlite3_malloc_failed ) goto drop_trigger_cleanup;
++  if( sqlite3MallocFailed() ) goto drop_trigger_cleanup;
+   if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
+     goto drop_trigger_cleanup;
+   }
+@@ -442,7 +453,7 @@
+   for(i=OMIT_TEMPDB; i<db->nDb; i++){
+     int j = (i<2) ? i^1 : i;  /* Search TEMP before MAIN */
+     if( zDb && sqlite3StrICmp(db->aDb[j].zName, zDb) ) continue;
+-    pTrigger = sqlite3HashFind(&(db->aDb[j].trigHash), zName, nName+1);
++    pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName, nName+1);
+     if( pTrigger ) break;
+   }
+   if( !pTrigger ){
+@@ -460,7 +471,8 @@
+ ** is set on.
+ */
+ static Table *tableOfTrigger(sqlite3 *db, Trigger *pTrigger){
+-  return sqlite3FindTable(db,pTrigger->table,db->aDb[pTrigger->iTabDb].zName);
++  int n = strlen(pTrigger->table) + 1;
++  return sqlite3HashFind(&pTrigger->pTabSchema->tblHash, pTrigger->table, n);
+ }
+ 
+ 
+@@ -475,11 +487,11 @@
+   sqlite3 *db = pParse->db;
+   int iDb;
+ 
+-  iDb = pTrigger->iDb;
++  iDb = sqlite3SchemaToIndex(pParse->db, pTrigger->pSchema);
+   assert( iDb>=0 && iDb<db->nDb );
+   pTable = tableOfTrigger(db, pTrigger);
+   assert(pTable);
+-  assert( pTable->iDb==iDb || iDb==1 );
++  assert( pTable->pSchema==pTrigger->pSchema || iDb==1 );
+ #ifndef SQLITE_OMIT_AUTHORIZATION
+   {
+     int code = SQLITE_DROP_TRIGGER;
+@@ -510,7 +522,7 @@
+     };
+ 
+     sqlite3BeginWriteOperation(pParse, 0, iDb);
+-    sqlite3OpenMasterTable(v, iDb);
++    sqlite3OpenMasterTable(pParse, iDb);
+     base = sqlite3VdbeAddOpList(v,  ArraySize(dropTrigger), dropTrigger);
+     sqlite3VdbeChangeP3(v, base+1, pTrigger->name, 0);
+     sqlite3ChangeCookie(db, v, iDb);
+@@ -525,7 +537,7 @@
+ void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){
+   Trigger *pTrigger;
+   int nName = strlen(zName);
+-  pTrigger = sqlite3HashInsert(&(db->aDb[iDb].trigHash), zName, nName+1, 0);
++  pTrigger = sqlite3HashInsert(&(db->aDb[iDb].pSchema->trigHash), zName, nName+1, 0);
+   if( pTrigger ){
+     Table *pTable = tableOfTrigger(db, pTrigger);
+     assert( pTable!=0 );
+@@ -617,11 +629,11 @@
+   int iDb;             /* Index of the database to use */
+   SrcList *pSrc;       /* SrcList to be returned */
+ 
+-  iDb = pStep->pTrig->iDb;
++  iDb = sqlite3SchemaToIndex(pParse->db, pStep->pTrig->pSchema);
+   if( iDb==0 || iDb>=2 ){
+     assert( iDb<pParse->db->nDb );
+-    sDb.z = pParse->db->aDb[iDb].zName;
+-    sDb.n = strlen(sDb.z);
++    sDb.z = (u8*)pParse->db->aDb[iDb].zName;
++    sDb.n = strlen((char*)sDb.z);
+     pSrc = sqlite3SrcListAppend(0, &sDb, &pStep->target);
+   } else {
+     pSrc = sqlite3SrcListAppend(0, &pStep->target, 0);
+@@ -730,8 +742,7 @@
+   int orconf,          /* ON CONFLICT policy */
+   int ignoreJump       /* Instruction to jump to for RAISE(IGNORE) */
+ ){
+-  Trigger *pTrigger;
+-  TriggerStack *pStack;
++  Trigger *p;
+   TriggerStack trigStackEntry;
+ 
+   assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);
+@@ -739,22 +750,21 @@
+ 
+   assert(newIdx != -1 || oldIdx != -1);
+ 
+-  pTrigger = pTab->pTrigger;
+-  while( pTrigger ){
++  for(p=pTab->pTrigger; p; p=p->pNext){
+     int fire_this = 0;
+ 
+-    /* determine whether we should code this trigger */
+-    if( pTrigger->op == op && pTrigger->tr_tm == tr_tm ){
+-      fire_this = 1;
+-      for(pStack=pParse->trigStack; pStack; pStack=pStack->pNext){
+-        if( pStack->pTrigger==pTrigger ){
+-	  fire_this = 0;
+-	}
++    /* Determine whether we should code this trigger */
++    if( 
++      p->op==op && 
++      p->tr_tm==tr_tm && 
++      (p->pSchema==p->pTabSchema || p->pSchema==pParse->db->aDb[1].pSchema) &&
++      (op!=TK_UPDATE||!p->pColumns||checkColumnOverLap(p->pColumns,pChanges))
++    ){
++      TriggerStack *pS;      /* Pointer to trigger-stack entry */
++      for(pS=pParse->trigStack; pS && p!=pS->pTrigger; pS=pS->pNext);
++      if( !pS ){
++        fire_this = 1;
+       }
+-      if( op == TK_UPDATE && pTrigger->pColumns &&
+-          !checkColumnOverLap(pTrigger->pColumns, pChanges) ){
+-        fire_this = 0;
+-      }
+     }
+  
+     if( fire_this ){
+@@ -767,18 +777,18 @@
+       sNC.pParse = pParse;
+ 
+       /* Push an entry on to the trigger stack */
+-      trigStackEntry.pTrigger = pTrigger;
++      trigStackEntry.pTrigger = p;
+       trigStackEntry.newIdx = newIdx;
+       trigStackEntry.oldIdx = oldIdx;
+       trigStackEntry.pTab = pTab;
+       trigStackEntry.pNext = pParse->trigStack;
+       trigStackEntry.ignoreJump = ignoreJump;
+       pParse->trigStack = &trigStackEntry;
+-      sqlite3AuthContextPush(pParse, &sContext, pTrigger->name);
++      sqlite3AuthContextPush(pParse, &sContext, p->name);
+ 
+       /* code the WHEN clause */
+       endTrigger = sqlite3VdbeMakeLabel(pParse->pVdbe);
+-      whenExpr = sqlite3ExprDup(pTrigger->pWhen);
++      whenExpr = sqlite3ExprDup(p->pWhen);
+       if( sqlite3ExprResolveNames(&sNC, whenExpr) ){
+         pParse->trigStack = trigStackEntry.pNext;
+         sqlite3ExprDelete(whenExpr);
+@@ -787,7 +797,7 @@
+       sqlite3ExprIfFalse(pParse, whenExpr, endTrigger, 1);
+       sqlite3ExprDelete(whenExpr);
+ 
+-      codeTriggerProgram(pParse, pTrigger->step_list, orconf); 
++      codeTriggerProgram(pParse, p->step_list, orconf); 
+ 
+       /* Pop the entry off the trigger stack */
+       pParse->trigStack = trigStackEntry.pNext;
+@@ -795,7 +805,6 @@
+ 
+       sqlite3VdbeResolveLabel(pParse->pVdbe, endTrigger);
+     }
+-    pTrigger = pTrigger->pNext;
+   }
+   return 0;
+ }
+Index: sqlite/legacy.c
+===================================================================
+--- amarok/src/sqlite/legacy.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/legacy.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -68,9 +68,8 @@
+     nCallback = 0;
+ 
+     nCol = sqlite3_column_count(pStmt);
+-    azCols = sqliteMalloc(2*nCol*sizeof(const char *));
+-    if( nCol && !azCols ){
+-      rc = SQLITE_NOMEM;
++    azCols = sqliteMalloc(2*nCol*sizeof(const char *) + 1);
++    if( azCols==0 ){
+       goto exec_out;
+     }
+ 
+@@ -122,9 +121,7 @@
+   if( pStmt ) sqlite3_finalize(pStmt);
+   if( azCols ) sqliteFree(azCols);
+ 
+-  if( sqlite3_malloc_failed ){
+-    rc = SQLITE_NOMEM;
+-  }
++  rc = sqlite3ApiExit(0, rc);
+   if( rc!=SQLITE_OK && rc==sqlite3_errcode(db) && pzErrMsg ){
+     *pzErrMsg = malloc(1+strlen(sqlite3_errmsg(db)));
+     if( *pzErrMsg ){
+Index: sqlite/attach.c
+===================================================================
+--- amarok/src/sqlite/attach.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/attach.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -16,199 +16,340 @@
+ #include "sqliteInt.h"
+ 
+ /*
+-** This routine is called by the parser to process an ATTACH statement:
++** Resolve an expression that was part of an ATTACH or DETACH statement. This
++** is slightly different from resolving a normal SQL expression, because simple
++** identifiers are treated as strings, not possible column names or aliases.
+ **
+-**     ATTACH DATABASE filename AS dbname
++** i.e. if the parser sees:
+ **
+-** The pFilename and pDbname arguments are the tokens that define the
+-** filename and dbname in the ATTACH statement.
++**     ATTACH DATABASE abc AS def
++**
++** it treats the two expressions as literal strings 'abc' and 'def' instead of
++** looking for columns of the same name.
++**
++** This only applies to the root node of pExpr, so the statement:
++**
++**     ATTACH DATABASE abc||def AS 'db2'
++**
++** will fail because neither abc or def can be resolved.
+ */
+-void sqlite3Attach(
+-  Parse *pParse,       /* The parser context */
+-  Token *pFilename,    /* Name of database file */
+-  Token *pDbname,      /* Name of the database to use internally */
+-  int keyType,         /* 0: no key.  1: TEXT,  2: BLOB */
+-  Token *pKey          /* Text of the key for keytype 1 and 2 */
++static int resolveAttachExpr(NameContext *pName, Expr *pExpr)
++{
++  int rc = SQLITE_OK;
++  if( pExpr ){
++    if( pExpr->op!=TK_ID ){
++      rc = sqlite3ExprResolveNames(pName, pExpr);
++    }else{
++      pExpr->op = TK_STRING;
++    }
++  }
++  return rc;
++}
++
++/*
++** An SQL user-function registered to do the work of an ATTACH statement. The
++** three arguments to the function come directly from an attach statement:
++**
++**     ATTACH DATABASE x AS y KEY z
++**
++**     SELECT sqlite_attach(x, y, z)
++**
++** If the optional "KEY z" syntax is omitted, an SQL NULL is passed as the
++** third argument.
++*/
++static void attachFunc(
++  sqlite3_context *context,
++  int argc,
++  sqlite3_value **argv
+ ){
++  int i;
++  int rc = 0;
++  sqlite3 *db = sqlite3_user_data(context);
++  const char *zName;
++  const char *zFile;
+   Db *aNew;
+-  int rc, i;
+-  char *zFile = 0;
+-  char *zName = 0;
+-  sqlite3 *db;
+-  Vdbe *v;
++  char zErr[128];
++  char *zErrDyn = 0;
+ 
+-  v = sqlite3GetVdbe(pParse);
+-  if( !v ) return;
+-  sqlite3VdbeAddOp(v, OP_Expire, 1, 0);
+-  sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
+-  if( pParse->explain ) return;
+-  db = pParse->db;
++  zFile = (const char *)sqlite3_value_text(argv[0]);
++  zName = (const char *)sqlite3_value_text(argv[1]);
++
++  /* Check for the following errors:
++  **
++  **     * Too many attached databases,
++  **     * Transaction currently open
++  **     * Specified database name already being used.
++  */
+   if( db->nDb>=MAX_ATTACHED+2 ){
+-    sqlite3ErrorMsg(pParse, "too many attached databases - max %d", 
+-       MAX_ATTACHED);
+-    pParse->rc = SQLITE_ERROR;
+-    return;
++    sqlite3_snprintf(
++      127, zErr, "too many attached databases - max %d", MAX_ATTACHED
++    );
++    goto attach_error;
+   }
+-
+   if( !db->autoCommit ){
+-    sqlite3ErrorMsg(pParse, "cannot ATTACH database within transaction");
+-    pParse->rc = SQLITE_ERROR;
+-    return;
++    strcpy(zErr, "cannot ATTACH database within transaction");
++    goto attach_error;
+   }
+-
+-  zFile = sqlite3NameFromToken(pFilename);
+-  if( zFile==0 ){
+-    goto attach_end;
+-  }
+-#ifndef SQLITE_OMIT_AUTHORIZATION
+-  if( sqlite3AuthCheck(pParse, SQLITE_ATTACH, zFile, 0, 0)!=SQLITE_OK ){
+-    goto attach_end;
+-  }
+-#endif /* SQLITE_OMIT_AUTHORIZATION */
+-
+-  zName = sqlite3NameFromToken(pDbname);
+-  if( zName==0 ){
+-    goto attach_end;
+-  }
+   for(i=0; i<db->nDb; i++){
+     char *z = db->aDb[i].zName;
+     if( z && sqlite3StrICmp(z, zName)==0 ){
+-      sqlite3ErrorMsg(pParse, "database %s is already in use", zName);
+-      pParse->rc = SQLITE_ERROR;
+-      goto attach_end;
++      sqlite3_snprintf(127, zErr, "database %s is already in use", zName);
++      goto attach_error;
+     }
+   }
+ 
++  /* Allocate the new entry in the db->aDb[] array and initialise the schema
++  ** hash tables.
++  */
+   if( db->aDb==db->aDbStatic ){
+     aNew = sqliteMalloc( sizeof(db->aDb[0])*3 );
+     if( aNew==0 ){
+-      goto attach_end;
++      return;
+     }
+     memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2);
+   }else{
+     aNew = sqliteRealloc(db->aDb, sizeof(db->aDb[0])*(db->nDb+1) );
+     if( aNew==0 ){
+-      goto attach_end;
++      return;
+     } 
+   }
+   db->aDb = aNew;
+   aNew = &db->aDb[db->nDb++];
+   memset(aNew, 0, sizeof(*aNew));
+-  sqlite3HashInit(&aNew->tblHash, SQLITE_HASH_STRING, 0);
+-  sqlite3HashInit(&aNew->idxHash, SQLITE_HASH_STRING, 0);
+-  sqlite3HashInit(&aNew->trigHash, SQLITE_HASH_STRING, 0);
+-  sqlite3HashInit(&aNew->aFKey, SQLITE_HASH_STRING, 1);
+-  aNew->zName = zName;
+-  zName = 0;
+-  aNew->safety_level = 3;
++
++  /* Open the database file. If the btree is successfully opened, use
++  ** it to obtain the database schema. At this point the schema may
++  ** or may not be initialised.
++  */
+   rc = sqlite3BtreeFactory(db, zFile, 0, MAX_PAGES, &aNew->pBt);
+-  if( rc ){
+-    sqlite3ErrorMsg(pParse, "unable to open database: %s", zFile);
++  if( rc==SQLITE_OK ){
++    aNew->pSchema = sqlite3SchemaGet(aNew->pBt);
++    if( !aNew->pSchema ){
++      rc = SQLITE_NOMEM;
++    }else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){
++      strcpy(zErr, 
++        "attached databases must use the same text encoding as main database");
++      goto attach_error;
++    }
+   }
++  aNew->zName = sqliteStrDup(zName);
++  aNew->safety_level = 3;
++
+ #if SQLITE_HAS_CODEC
+   {
+     extern int sqlite3CodecAttach(sqlite3*, int, void*, int);
++    extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
++    int nKey;
+     char *zKey;
+-    int nKey;
+-    if( keyType==0 ){
+-      /* No key specified.  Use the key from the main database */
+-      extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
+-      sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
+-    }else if( keyType==1 ){
+-      /* Key specified as text */
+-      zKey = sqlite3NameFromToken(pKey);
+-      nKey = strlen(zKey);
+-    }else{
+-      /* Key specified as a BLOB */
+-      char *zTemp;
+-      assert( keyType==2 );
+-      pKey->z++;
+-      pKey->n--;
+-      zTemp = sqlite3NameFromToken(pKey);
+-      zKey = sqlite3HexToBlob(zTemp);
+-      sqliteFree(zTemp);
++    int t = sqlite3_value_type(argv[2]);
++    switch( t ){
++      case SQLITE_INTEGER:
++      case SQLITE_FLOAT:
++        zErrDyn = sqliteStrDup("Invalid key value");
++        rc = SQLITE_ERROR;
++        break;
++        
++      case SQLITE_TEXT:
++      case SQLITE_BLOB:
++        nKey = sqlite3_value_bytes(argv[2]);
++        zKey = (char *)sqlite3_value_blob(argv[2]);
++        sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
++        break;
++
++      case SQLITE_NULL:
++        /* No key specified.  Use the key from the main database */
++        sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
++        sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
++        break;
+     }
+-    sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
+-    if( keyType ){
+-      sqliteFree(zKey);
+-    }
+   }
+ #endif
+-  db->flags &= ~SQLITE_Initialized;
+-  if( pParse->nErr==0 && rc==SQLITE_OK ){
+-    rc = sqlite3ReadSchema(pParse);
++
++  /* If the file was opened successfully, read the schema for the new database.
++  ** If this fails, or if opening the file failed, then close the file and 
++  ** remove the entry from the db->aDb[] array. i.e. put everything back the way
++  ** we found it.
++  */
++  if( rc==SQLITE_OK ){
++    sqlite3SafetyOn(db);
++    rc = sqlite3Init(db, &zErrDyn);
++    sqlite3SafetyOff(db);
+   }
+   if( rc ){
+-    int i = db->nDb - 1;
+-    assert( i>=2 );
+-    if( db->aDb[i].pBt ){
+-      sqlite3BtreeClose(db->aDb[i].pBt);
+-      db->aDb[i].pBt = 0;
++    int iDb = db->nDb - 1;
++    assert( iDb>=2 );
++    if( db->aDb[iDb].pBt ){
++      sqlite3BtreeClose(db->aDb[iDb].pBt);
++      db->aDb[iDb].pBt = 0;
++      db->aDb[iDb].pSchema = 0;
+     }
+     sqlite3ResetInternalSchema(db, 0);
+-    assert( pParse->nErr>0 );  /* Always set by sqlite3ReadSchema() */
+-    if( pParse->rc==SQLITE_OK ){
+-      pParse->rc = SQLITE_ERROR;
+-    }
++    db->nDb = iDb;
++    sqlite3_snprintf(127, zErr, "unable to open database: %s", zFile);
++    goto attach_error;
+   }
++  
++  return;
+ 
+-attach_end:
+-  sqliteFree(zFile);
+-  sqliteFree(zName);
++attach_error:
++  /* Return an error if we get here */
++  if( zErrDyn ){
++    sqlite3_result_error(context, zErrDyn, -1);
++    sqliteFree(zErrDyn);
++  }else{
++    zErr[sizeof(zErr)-1] = 0;
++    sqlite3_result_error(context, zErr, -1);
++  }
+ }
+ 
+ /*
+-** This routine is called by the parser to process a DETACH statement:
++** An SQL user-function registered to do the work of an DETACH statement. The
++** three arguments to the function come directly from a detach statement:
+ **
+-**    DETACH DATABASE dbname
++**     DETACH DATABASE x
+ **
+-** The pDbname argument is the name of the database in the DETACH statement.
++**     SELECT sqlite_detach(x)
+ */
+-void sqlite3Detach(Parse *pParse, Token *pDbname){
++static void detachFunc(
++  sqlite3_context *context,
++  int argc,
++  sqlite3_value **argv
++){
++  const char *zName = (const char *)sqlite3_value_text(argv[0]);
++  sqlite3 *db = sqlite3_user_data(context);
+   int i;
+-  sqlite3 *db;
+-  Vdbe *v;
+   Db *pDb = 0;
+-  char *zName;
++  char zErr[128];
+ 
+-  v = sqlite3GetVdbe(pParse);
+-  if( !v ) return;
+-  sqlite3VdbeAddOp(v, OP_Expire, 0, 0);
+-  sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
+-  if( pParse->explain ) return;
+-  db = pParse->db;
+-  zName = sqlite3NameFromToken(pDbname);
+-  if( zName==0 ) return;
++  assert(zName);
+   for(i=0; i<db->nDb; i++){
+     pDb = &db->aDb[i];
+     if( pDb->pBt==0 ) continue;
+     if( sqlite3StrICmp(pDb->zName, zName)==0 ) break;
+   }
++
+   if( i>=db->nDb ){
+-    sqlite3ErrorMsg(pParse, "no such database: %z", zName);
+-    return;
++    sqlite3_snprintf(sizeof(zErr), zErr, "no such database: %s", zName);
++    goto detach_error;
+   }
+   if( i<2 ){
+-    sqlite3ErrorMsg(pParse, "cannot detach database %z", zName);
+-    return;
++    sqlite3_snprintf(sizeof(zErr), zErr, "cannot detach database %s", zName);
++    goto detach_error;
+   }
+-  sqliteFree(zName);
+   if( !db->autoCommit ){
+-    sqlite3ErrorMsg(pParse, "cannot DETACH database within transaction");
+-    pParse->rc = SQLITE_ERROR;
+-    return;
++    strcpy(zErr, "cannot DETACH database within transaction");
++    goto detach_error;
+   }
+-#ifndef SQLITE_OMIT_AUTHORIZATION
+-  if( sqlite3AuthCheck(pParse,SQLITE_DETACH,db->aDb[i].zName,0,0)!=SQLITE_OK ){
+-    return;
+-  }
+-#endif /* SQLITE_OMIT_AUTHORIZATION */
++
+   sqlite3BtreeClose(pDb->pBt);
+   pDb->pBt = 0;
++  pDb->pSchema = 0;
+   sqlite3ResetInternalSchema(db, 0);
++  return;
++
++detach_error:
++  sqlite3_result_error(context, zErr, -1);
+ }
+ 
+ /*
++** This procedure generates VDBE code for a single invocation of either the
++** sqlite_detach() or sqlite_attach() SQL user functions.
++*/
++static void codeAttach(
++  Parse *pParse,       /* The parser context */
++  int type,            /* Either SQLITE_ATTACH or SQLITE_DETACH */
++  const char *zFunc,   /* Either "sqlite_attach" or "sqlite_detach */
++  int nFunc,           /* Number of args to pass to zFunc */
++  Expr *pAuthArg,      /* Expression to pass to authorization callback */
++  Expr *pFilename,     /* Name of database file */
++  Expr *pDbname,       /* Name of the database to use internally */
++  Expr *pKey           /* Database key for encryption extension */
++){
++  int rc;
++  NameContext sName;
++  Vdbe *v;
++  FuncDef *pFunc;
++  sqlite3* db = pParse->db;
++
++#ifndef SQLITE_OMIT_AUTHORIZATION
++  assert( sqlite3MallocFailed() || pAuthArg );
++  if( pAuthArg ){
++    char *zAuthArg = sqlite3NameFromToken(&pAuthArg->span);
++    if( !zAuthArg ){
++      goto attach_end;
++    }
++    rc = sqlite3AuthCheck(pParse, type, zAuthArg, 0, 0);
++    sqliteFree(zAuthArg);
++    if(rc!=SQLITE_OK ){
++      goto attach_end;
++    }
++  }
++#endif /* SQLITE_OMIT_AUTHORIZATION */
++
++  memset(&sName, 0, sizeof(NameContext));
++  sName.pParse = pParse;
++
++  if( 
++      SQLITE_OK!=(rc = resolveAttachExpr(&sName, pFilename)) ||
++      SQLITE_OK!=(rc = resolveAttachExpr(&sName, pDbname)) ||
++      SQLITE_OK!=(rc = resolveAttachExpr(&sName, pKey))
++  ){
++    pParse->nErr++;
++    goto attach_end;
++  }
++
++  v = sqlite3GetVdbe(pParse);
++  sqlite3ExprCode(pParse, pFilename);
++  sqlite3ExprCode(pParse, pDbname);
++  sqlite3ExprCode(pParse, pKey);
++
++  assert( v || sqlite3MallocFailed() );
++  if( v ){
++    sqlite3VdbeAddOp(v, OP_Function, 0, nFunc);
++    pFunc = sqlite3FindFunction(db, zFunc, strlen(zFunc), nFunc, SQLITE_UTF8,0);
++    sqlite3VdbeChangeP3(v, -1, (char *)pFunc, P3_FUNCDEF);
++
++    /* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this
++    ** statement only). For DETACH, set it to false (expire all existing
++    ** statements).
++    */
++    sqlite3VdbeAddOp(v, OP_Expire, (type==SQLITE_ATTACH), 0);
++  }
++  
++attach_end:
++  sqlite3ExprDelete(pFilename);
++  sqlite3ExprDelete(pDbname);
++  sqlite3ExprDelete(pKey);
++}
++
++/*
++** Called by the parser to compile a DETACH statement.
++**
++**     DETACH pDbname
++*/
++void sqlite3Detach(Parse *pParse, Expr *pDbname){
++  codeAttach(pParse, SQLITE_DETACH, "sqlite_detach", 1, pDbname, 0, 0, pDbname);
++}
++
++/*
++** Called by the parser to compile an ATTACH statement.
++**
++**     ATTACH p AS pDbname KEY pKey
++*/
++void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){
++  codeAttach(pParse, SQLITE_ATTACH, "sqlite_attach", 3, p, p, pDbname, pKey);
++}
++
++/*
++** Register the functions sqlite_attach and sqlite_detach.
++*/
++void sqlite3AttachFunctions(sqlite3 *db){
++  static const int enc = SQLITE_UTF8;
++  sqlite3CreateFunc(db, "sqlite_attach", 3, enc, db, attachFunc, 0, 0);
++  sqlite3CreateFunc(db, "sqlite_detach", 1, enc, db, detachFunc, 0, 0);
++}
++
++/*
+ ** Initialize a DbFixer structure.  This routine must be called prior
+ ** to passing the structure to one of the sqliteFixAAAA() routines below.
+ **
+Index: sqlite/btree.h
+===================================================================
+--- amarok/src/sqlite/btree.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/btree.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -36,10 +36,12 @@
+ */
+ typedef struct Btree Btree;
+ typedef struct BtCursor BtCursor;
++typedef struct BtShared BtShared;
+ 
+ 
+ int sqlite3BtreeOpen(
+   const char *zFilename,   /* Name of database file to open */
++  sqlite3 *db,             /* Associated database connection */
+   Btree **,                /* Return open Btree* here */
+   int flags                /* Flags */
+ );
+@@ -57,7 +59,7 @@
+ int sqlite3BtreeClose(Btree*);
+ int sqlite3BtreeSetBusyHandler(Btree*,BusyHandler*);
+ int sqlite3BtreeSetCacheSize(Btree*,int);
+-int sqlite3BtreeSetSafetyLevel(Btree*,int);
++int sqlite3BtreeSetSafetyLevel(Btree*,int,int);
+ int sqlite3BtreeSyncDisabled(Btree*);
+ int sqlite3BtreeSetPageSize(Btree*,int,int);
+ int sqlite3BtreeGetPageSize(Btree*);
+@@ -74,7 +76,9 @@
+ int sqlite3BtreeIsInTrans(Btree*);
+ int sqlite3BtreeIsInStmt(Btree*);
+ int sqlite3BtreeSync(Btree*, const char *zMaster);
+-int sqlite3BtreeReset(Btree *);
++void *sqlite3BtreeSchema(Btree *, int, void(*)(void *));
++int sqlite3BtreeSchemaLocked(Btree *);
++int sqlite3BtreeLockTable(Btree *, int, u8);
+ 
+ const char *sqlite3BtreeGetFilename(Btree *);
+ const char *sqlite3BtreeGetDirname(Btree *);
+Index: sqlite/alter.c
+===================================================================
+--- amarok/src/sqlite/alter.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/alter.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -47,7 +47,7 @@
+ 
+   int token;
+   Token tname;
+-  char const *zCsr = zSql;
++  unsigned char const *zCsr = zSql;
+   int len = 0;
+   char *zRet;
+ 
+@@ -96,7 +96,7 @@
+   int token;
+   Token tname;
+   int dist = 3;
+-  char const *zCsr = zSql;
++  unsigned char const *zCsr = zSql;
+   int len = 0;
+   char *zRet;
+ 
+@@ -162,7 +162,7 @@
+   int i;
+ 
+   for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
+-    sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg,
++    sqlite3CreateFunc(db, aFuncs[i].zName, aFuncs[i].nArg,
+         SQLITE_UTF8, 0, aFuncs[i].xFunc, 0, 0);
+   }
+ }
+@@ -177,9 +177,16 @@
+   Trigger *pTrig;
+   char *zWhere = 0;
+   char *tmp = 0;
+-  if( pTab->iDb!=1 ){
++  const Schema *pTempSchema = pParse->db->aDb[1].pSchema; /* Temp db schema */
++
++  /* If the table is not located in the temp-db (in which case NULL is 
++  ** returned, loop through the tables list of triggers. For each trigger
++  ** that is not part of the temp-db schema, add a clause to the WHERE 
++  ** expression being built up in zWhere.
++  */
++  if( pTab->pSchema!=pTempSchema ){
+     for( pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext ){
+-      if( pTrig->iDb==1 ){
++      if( pTrig->pSchema==pTempSchema ){
+         if( !zWhere ){
+           zWhere = sqlite3MPrintf("name=%Q", pTrig->name);
+         }else{
+@@ -204,20 +211,22 @@
+ static void reloadTableSchema(Parse *pParse, Table *pTab, const char *zName){
+   Vdbe *v;
+   char *zWhere;
+-  int iDb;
++  int iDb;                   /* Index of database containing pTab */
+ #ifndef SQLITE_OMIT_TRIGGER
+   Trigger *pTrig;
+ #endif
+ 
+   v = sqlite3GetVdbe(pParse);
+   if( !v ) return;
+-  iDb = pTab->iDb;
++  iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
++  assert( iDb>=0 );
+ 
+ #ifndef SQLITE_OMIT_TRIGGER
+   /* Drop any table triggers from the internal schema. */
+   for(pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext){
+-    assert( pTrig->iDb==iDb || pTrig->iDb==1 );
+-    sqlite3VdbeOp3(v, OP_DropTrigger, pTrig->iDb, 0, pTrig->name, 0);
++    int iTrigDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema);
++    assert( iTrigDb==iDb || iTrigDb==1 );
++    sqlite3VdbeOp3(v, OP_DropTrigger, iTrigDb, 0, pTrig->name, 0);
+   }
+ #endif
+ 
+@@ -233,7 +242,7 @@
+   /* Now, if the table is not stored in the temp database, reload any temp 
+   ** triggers. Don't use IN(...) in case SQLITE_OMIT_SUBQUERY is defined. 
+   */
+-  if( (zWhere=whereTempTriggers(pParse, pTab)) ){
++  if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){
+     sqlite3VdbeOp3(v, OP_ParseSchema, 1, 0, zWhere, P3_DYNAMIC);
+   }
+ #endif
+@@ -258,12 +267,12 @@
+   char *zWhere = 0;         /* Where clause to locate temp triggers */
+ #endif
+   
+-  if( sqlite3_malloc_failed ) goto exit_rename_table;
++  if( sqlite3MallocFailed() ) goto exit_rename_table;
+   assert( pSrc->nSrc==1 );
+ 
+   pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase);
+   if( !pTab ) goto exit_rename_table;
+-  iDb = pTab->iDb;
++  iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
+   zDb = db->aDb[iDb].zName;
+ 
+   /* Get a NULL terminated version of the new table name. */
+@@ -349,7 +358,7 @@
+   ** table. Don't do this if the table being ALTERed is itself located in
+   ** the temp database.
+   */
+-  if( (zWhere=whereTempTriggers(pParse, pTab)) ){
++  if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){
+     sqlite3NestedParse(pParse, 
+         "UPDATE sqlite_temp_master SET "
+             "sql = sqlite_rename_trigger(sql, %Q), "
+@@ -385,13 +394,12 @@
+   char *zCol;               /* Null-terminated column definition */
+   Column *pCol;             /* The new column */
+   Expr *pDflt;              /* Default value for the new column */
+-  Vdbe *v;
+ 
+   if( pParse->nErr ) return;
+   pNew = pParse->pNewTable;
+   assert( pNew );
+ 
+-  iDb = pNew->iDb;
++  iDb = sqlite3SchemaToIndex(pParse->db, pNew->pSchema);
+   zDb = pParse->db->aDb[iDb].zName;
+   zTab = pNew->zName;
+   pCol = &pNew->aCol[pNew->nCol-1];
+@@ -399,6 +407,13 @@
+   pTab = sqlite3FindTable(pParse->db, zTab, zDb);
+   assert( pTab );
+ 
++#ifndef SQLITE_OMIT_AUTHORIZATION
++  /* Invoke the authorization callback. */
++  if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){
++    return;
++  }
++#endif
++
+   /* If the default value for the new column was specified with a 
+   ** literal NULL, then set pDflt to 0. This simplifies checking
+   ** for an SQL NULL default below.
+@@ -442,7 +457,7 @@
+   }
+ 
+   /* Modify the CREATE TABLE statement. */
+-  zCol = sqliteStrNDup(pColDef->z, pColDef->n);
++  zCol = sqliteStrNDup((char*)pColDef->z, pColDef->n);
+   if( zCol ){
+     char *zEnd = &zCol[pColDef->n-1];
+     while( (zEnd>zCol && *zEnd==';') || isspace(*(unsigned char *)zEnd) ){
+@@ -462,22 +477,12 @@
+   ** format to 2. If the default value of the new column is not NULL,
+   ** the file format becomes 3.
+   */
+-  if( (v=sqlite3GetVdbe(pParse)) ){
+-    int f = (pDflt?3:2);
++  sqlite3MinimumFileFormat(pParse, iDb, pDflt ? 3 : 2);
+ 
+-    /* Only set the file format to $f if it is currently less than $f. */
+-    sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 1);
+-    sqlite3VdbeAddOp(v, OP_Integer, f, 0);
+-    sqlite3VdbeAddOp(v, OP_Ge, 0, sqlite3VdbeCurrentAddr(v)+3);
+-    sqlite3VdbeAddOp(v, OP_Integer, f, 0);
+-    sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 1);
+-  }
+-
+   /* Reload the schema of the modified table. */
+   reloadTableSchema(pParse, pTab, pTab->zName);
+ }
+ 
+-
+ /*
+ ** This function is called by the parser after the table-name in
+ ** an "ALTER TABLE <table-name> ADD" statement is parsed. Argument 
+@@ -501,10 +506,9 @@
+   int i;
+   int nAlloc;
+ 
+-
+   /* Look up the table being altered. */
+   assert( pParse->pNewTable==0 );
+-  if( sqlite3_malloc_failed ) goto exit_begin_add_column;
++  if( sqlite3MallocFailed() ) goto exit_begin_add_column;
+   pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase);
+   if( !pTab ) goto exit_begin_add_column;
+ 
+@@ -515,7 +519,7 @@
+   }
+ 
+   assert( pTab->addColOffset>0 );
+-  iDb = pTab->iDb;
++  iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
+ 
+   /* Put a copy of the Table struct in Parse.pNewTable for the
+   ** sqlite3AddColumn() function and friends to modify.
+@@ -537,10 +541,11 @@
+   for(i=0; i<pNew->nCol; i++){
+     Column *pCol = &pNew->aCol[i];
+     pCol->zName = sqliteStrDup(pCol->zName);
++    pCol->zColl = 0;
+     pCol->zType = 0;
+     pCol->pDflt = 0;
+   }
+-  pNew->iDb = iDb;
++  pNew->pSchema = pParse->db->aDb[iDb].pSchema;
+   pNew->addColOffset = pTab->addColOffset;
+   pNew->nRef = 1;
+ 
+Index: sqlite/pragma.c
+===================================================================
+--- amarok/src/sqlite/pragma.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/pragma.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -36,7 +36,7 @@
+ ** to support legacy SQL code.  The safety level used to be boolean
+ ** and older scripts may have used numbers 0 for OFF and 1 for ON.
+ */
+-static int getSafetyLevel(const u8 *z){
++static int getSafetyLevel(const char *z){
+                              /* 123456789 123456789 */
+   static const char zText[] = "onoffalseyestruefull";
+   static const u8 iOffset[] = {0, 1, 2, 4, 9, 12, 16};
+@@ -58,7 +58,7 @@
+ /*
+ ** Interpret the given string as a boolean value.
+ */
+-static int getBoolean(const u8 *z){
++static int getBoolean(const char *z){
+   return getSafetyLevel(z)&1;
+ }
+ 
+@@ -128,7 +128,7 @@
+   sqlite3VdbeAddOp(v, OP_Integer, value, 0);
+   if( pParse->explain==0 ){
+     sqlite3VdbeSetNumCols(v, 1);
+-    sqlite3VdbeSetColName(v, 0, zLabel, P3_STATIC);
++    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLabel, P3_STATIC);
+   }
+   sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
+ }
+@@ -151,9 +151,18 @@
+     { "short_column_names",       SQLITE_ShortColNames },
+     { "count_changes",            SQLITE_CountRows     },
+     { "empty_result_callbacks",   SQLITE_NullCallback  },
++    { "legacy_file_format",       SQLITE_LegacyFileFmt },
++    { "fullfsync",                SQLITE_FullFSync     },
++#ifndef SQLITE_OMIT_CHECK
++    { "ignore_check_constraints", SQLITE_IgnoreChecks  },
++#endif
+     /* The following is VERY experimental */
+     { "writable_schema",          SQLITE_WriteSchema   },
+     { "omit_readlock",            SQLITE_NoReadlock    },
++
++    /* TODO: Maybe it shouldn't be possible to change the ReadUncommitted
++    ** flag if there are any active statements. */
++    { "read_uncommitted",         SQLITE_ReadUncommitted },
+   };
+   int i;
+   const struct sPragmaType *p;
+@@ -172,10 +181,6 @@
+             db->flags &= ~p->mask;
+           }
+         }
+-        /* If one of these pragmas is executed, any prepared statements
+-        ** need to be recompiled.
+-        */
+-        sqlite3VdbeAddOp(v, OP_Expire, 0, 0);
+       }
+       return 1;
+     }
+@@ -266,7 +271,7 @@
+     if( sqlite3ReadSchema(pParse) ) goto pragma_out;
+     if( !zRight ){
+       sqlite3VdbeSetNumCols(v, 1);
+-      sqlite3VdbeSetColName(v, 0, "cache_size", P3_STATIC);
++      sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cache_size", P3_STATIC);
+       addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
+       sqlite3VdbeChangeP1(v, addr, iDb);
+       sqlite3VdbeChangeP1(v, addr+5, MAX_PAGES);
+@@ -280,8 +285,8 @@
+       sqlite3VdbeAddOp(v, OP_Ge, 0, addr+3);
+       sqlite3VdbeAddOp(v, OP_Negative, 0, 0);
+       sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 2);
+-      pDb->cache_size = size;
+-      sqlite3BtreeSetCacheSize(pDb->pBt, pDb->cache_size);
++      pDb->pSchema->cache_size = size;
++      sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
+     }
+   }else
+ 
+@@ -342,12 +347,12 @@
+   if( sqlite3StrICmp(zLeft,"cache_size")==0 ){
+     if( sqlite3ReadSchema(pParse) ) goto pragma_out;
+     if( !zRight ){
+-      returnSingleInt(pParse, "cache_size", pDb->cache_size);
++      returnSingleInt(pParse, "cache_size", pDb->pSchema->cache_size);
+     }else{
+       int size = atoi(zRight);
+       if( size<0 ) size = -size;
+-      pDb->cache_size = size;
+-      sqlite3BtreeSetCacheSize(pDb->pBt, pDb->cache_size);
++      pDb->pSchema->cache_size = size;
++      sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
+     }
+   }else
+ 
+@@ -384,7 +389,8 @@
+     if( !zRight ){
+       if( sqlite3_temp_directory ){
+         sqlite3VdbeSetNumCols(v, 1);
+-        sqlite3VdbeSetColName(v, 0, "temp_store_directory", P3_STATIC);
++        sqlite3VdbeSetColName(v, 0, COLNAME_NAME, 
++            "temp_store_directory", P3_STATIC);
+         sqlite3VdbeOp3(v, OP_String8, 0, 0, sqlite3_temp_directory, 0);
+         sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
+       }
+@@ -428,7 +434,6 @@
+             "Safety level may not be changed inside a transaction");
+       }else{
+         pDb->safety_level = getSafetyLevel(zRight)+1;
+-        sqlite3BtreeSetSafetyLevel(pDb->pBt, pDb->safety_level);
+       }
+     }
+   }else
+@@ -460,22 +465,23 @@
+     pTab = sqlite3FindTable(db, zRight, zDb);
+     if( pTab ){
+       int i;
++      Column *pCol;
+       sqlite3VdbeSetNumCols(v, 6);
+-      sqlite3VdbeSetColName(v, 0, "cid", P3_STATIC);
+-      sqlite3VdbeSetColName(v, 1, "name", P3_STATIC);
+-      sqlite3VdbeSetColName(v, 2, "type", P3_STATIC);
+-      sqlite3VdbeSetColName(v, 3, "notnull", P3_STATIC);
+-      sqlite3VdbeSetColName(v, 4, "dflt_value", P3_STATIC);
+-      sqlite3VdbeSetColName(v, 5, "pk", P3_STATIC);
++      sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cid", P3_STATIC);
++      sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P3_STATIC);
++      sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "type", P3_STATIC);
++      sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "notnull", P3_STATIC);
++      sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "dflt_value", P3_STATIC);
++      sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "pk", P3_STATIC);
+       sqlite3ViewGetColumnNames(pParse, pTab);
+-      for(i=0; i<pTab->nCol; i++){
++      for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
+         sqlite3VdbeAddOp(v, OP_Integer, i, 0);
+-        sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->aCol[i].zName, 0);
++        sqlite3VdbeOp3(v, OP_String8, 0, 0, pCol->zName, 0);
+         sqlite3VdbeOp3(v, OP_String8, 0, 0,
+-           pTab->aCol[i].zType ? pTab->aCol[i].zType : "numeric", 0);
+-        sqlite3VdbeAddOp(v, OP_Integer, pTab->aCol[i].notNull, 0);
+-        sqlite3ExprCode(pParse, pTab->aCol[i].pDflt);
+-        sqlite3VdbeAddOp(v, OP_Integer, pTab->aCol[i].isPrimKey, 0);
++           pCol->zType ? pCol->zType : "numeric", 0);
++        sqlite3VdbeAddOp(v, OP_Integer, pCol->notNull, 0);
++        sqlite3ExprCode(pParse, pCol->pDflt);
++        sqlite3VdbeAddOp(v, OP_Integer, pCol->isPrimKey, 0);
+         sqlite3VdbeAddOp(v, OP_Callback, 6, 0);
+       }
+     }
+@@ -490,9 +496,9 @@
+       int i;
+       pTab = pIdx->pTable;
+       sqlite3VdbeSetNumCols(v, 3);
+-      sqlite3VdbeSetColName(v, 0, "seqno", P3_STATIC);
+-      sqlite3VdbeSetColName(v, 1, "cid", P3_STATIC);
+-      sqlite3VdbeSetColName(v, 2, "name", P3_STATIC);
++      sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seqno", P3_STATIC);
++      sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "cid", P3_STATIC);
++      sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "name", P3_STATIC);
+       for(i=0; i<pIdx->nColumn; i++){
+         int cnum = pIdx->aiColumn[i];
+         sqlite3VdbeAddOp(v, OP_Integer, i, 0);
+@@ -515,9 +521,9 @@
+       if( pIdx ){
+         int i = 0; 
+         sqlite3VdbeSetNumCols(v, 3);
+-        sqlite3VdbeSetColName(v, 0, "seq", P3_STATIC);
+-        sqlite3VdbeSetColName(v, 1, "name", P3_STATIC);
+-        sqlite3VdbeSetColName(v, 2, "unique", P3_STATIC);
++        sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P3_STATIC);
++        sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P3_STATIC);
++        sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", P3_STATIC);
+         while(pIdx){
+           sqlite3VdbeAddOp(v, OP_Integer, i, 0);
+           sqlite3VdbeOp3(v, OP_String8, 0, 0, pIdx->zName, 0);
+@@ -534,9 +540,9 @@
+     int i;
+     if( sqlite3ReadSchema(pParse) ) goto pragma_out;
+     sqlite3VdbeSetNumCols(v, 3);
+-    sqlite3VdbeSetColName(v, 0, "seq", P3_STATIC);
+-    sqlite3VdbeSetColName(v, 1, "name", P3_STATIC);
+-    sqlite3VdbeSetColName(v, 2, "file", P3_STATIC);
++    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P3_STATIC);
++    sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P3_STATIC);
++    sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "file", P3_STATIC);
+     for(i=0; i<db->nDb; i++){
+       if( db->aDb[i].pBt==0 ) continue;
+       assert( db->aDb[i].zName!=0 );
+@@ -552,8 +558,8 @@
+     int i = 0;
+     HashElem *p;
+     sqlite3VdbeSetNumCols(v, 2);
+-    sqlite3VdbeSetColName(v, 0, "seq", P3_STATIC);
+-    sqlite3VdbeSetColName(v, 1, "name", P3_STATIC);
++    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P3_STATIC);
++    sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P3_STATIC);
+     for(p=sqliteHashFirst(&db->aCollSeq); p; p=sqliteHashNext(p)){
+       CollSeq *pColl = (CollSeq *)sqliteHashData(p);
+       sqlite3VdbeAddOp(v, OP_Integer, i++, 0);
+@@ -575,11 +581,11 @@
+       if( pFK ){
+         int i = 0; 
+         sqlite3VdbeSetNumCols(v, 5);
+-        sqlite3VdbeSetColName(v, 0, "id", P3_STATIC);
+-        sqlite3VdbeSetColName(v, 1, "seq", P3_STATIC);
+-        sqlite3VdbeSetColName(v, 2, "table", P3_STATIC);
+-        sqlite3VdbeSetColName(v, 3, "from", P3_STATIC);
+-        sqlite3VdbeSetColName(v, 4, "to", P3_STATIC);
++        sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "id", P3_STATIC);
++        sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "seq", P3_STATIC);
++        sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "table", P3_STATIC);
++        sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "from", P3_STATIC);
++        sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "to", P3_STATIC);
+         while(pFK){
+           int j;
+           for(j=0; j<pFK->nCol; j++){
+@@ -641,12 +647,13 @@
+     /* Initialize the VDBE program */
+     if( sqlite3ReadSchema(pParse) ) goto pragma_out;
+     sqlite3VdbeSetNumCols(v, 1);
+-    sqlite3VdbeSetColName(v, 0, "integrity_check", P3_STATIC);
++    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "integrity_check", P3_STATIC);
+     sqlite3VdbeAddOp(v, OP_MemInt, 0, 0);  /* Initialize error count to 0 */
+ 
+     /* Do an integrity check on each database file */
+     for(i=0; i<db->nDb; i++){
+       HashElem *x;
++      Hash *pTbls;
+       int cnt = 0;
+ 
+       if( OMIT_TEMPDB && i==1 ) continue;
+@@ -655,13 +662,13 @@
+ 
+       /* Do an integrity check of the B-Tree
+       */
+-      for(x=sqliteHashFirst(&db->aDb[i].tblHash); x; x=sqliteHashNext(x)){
++      pTbls = &db->aDb[i].pSchema->tblHash;
++      for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
+         Table *pTab = sqliteHashData(x);
+         Index *pIdx;
+         sqlite3VdbeAddOp(v, OP_Integer, pTab->tnum, 0);
+         cnt++;
+         for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+-          if( sqlite3CheckIndexCollSeq(pParse, pIdx) ) goto pragma_out;
+           sqlite3VdbeAddOp(v, OP_Integer, pIdx->tnum, 0);
+           cnt++;
+         }
+@@ -670,18 +677,19 @@
+       sqlite3VdbeAddOp(v, OP_IntegrityCk, cnt, i);
+       sqlite3VdbeAddOp(v, OP_Dup, 0, 1);
+       addr = sqlite3VdbeOp3(v, OP_String8, 0, 0, "ok", P3_STATIC);
+-      sqlite3VdbeAddOp(v, OP_Eq, 0, addr+6);
++      sqlite3VdbeAddOp(v, OP_Eq, 0, addr+7);
+       sqlite3VdbeOp3(v, OP_String8, 0, 0,
+          sqlite3MPrintf("*** in database %s ***\n", db->aDb[i].zName),
+          P3_DYNAMIC);
+       sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
+       sqlite3VdbeAddOp(v, OP_Concat, 0, 1);
+       sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
++      sqlite3VdbeAddOp(v, OP_MemIncr, 1, 0);
+ 
+       /* Make sure all the indices are constructed correctly.
+       */
+       sqlite3CodeVerifySchema(pParse, i);
+-      for(x=sqliteHashFirst(&db->aDb[i].tblHash); x; x=sqliteHashNext(x)){
++      for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
+         Table *pTab = sqliteHashData(x);
+         Index *pIdx;
+         int loopTop;
+@@ -690,11 +698,11 @@
+         sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead);
+         sqlite3VdbeAddOp(v, OP_MemInt, 0, 1);
+         loopTop = sqlite3VdbeAddOp(v, OP_Rewind, 1, 0);
+-        sqlite3VdbeAddOp(v, OP_MemIncr, 1, 0);
++        sqlite3VdbeAddOp(v, OP_MemIncr, 1, 1);
+         for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
+           int jmp2;
+           static const VdbeOpList idxErr[] = {
+-            { OP_MemIncr,     0,  0,  0},
++            { OP_MemIncr,     1,  0,  0},
+             { OP_String8,     0,  0,  "rowid "},
+             { OP_Rowid,       1,  0,  0},
+             { OP_String8,     0,  0,  " missing from index "},
+@@ -714,12 +722,12 @@
+           static const VdbeOpList cntIdx[] = {
+              { OP_MemInt,       0,  2,  0},
+              { OP_Rewind,       0,  0,  0},  /* 1 */
+-             { OP_MemIncr,      2,  0,  0},
++             { OP_MemIncr,      1,  2,  0},
+              { OP_Next,         0,  0,  0},  /* 3 */
+              { OP_MemLoad,      1,  0,  0},
+              { OP_MemLoad,      2,  0,  0},
+              { OP_Eq,           0,  0,  0},  /* 6 */
+-             { OP_MemIncr,      0,  0,  0},
++             { OP_MemIncr,      1,  0,  0},
+              { OP_String8,      0,  0,  "wrong # of entries in index "},
+              { OP_String8,      0,  0,  0},  /* 9 */
+              { OP_Concat,       0,  0,  0},
+@@ -784,10 +792,10 @@
+     if( !zRight ){    /* "PRAGMA encoding" */
+       if( sqlite3ReadSchema(pParse) ) goto pragma_out;
+       sqlite3VdbeSetNumCols(v, 1);
+-      sqlite3VdbeSetColName(v, 0, "encoding", P3_STATIC);
++      sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "encoding", P3_STATIC);
+       sqlite3VdbeAddOp(v, OP_String8, 0, 0);
+       for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
+-        if( pEnc->enc==pParse->db->enc ){
++        if( pEnc->enc==ENC(pParse->db) ){
+           sqlite3VdbeChangeP3(v, -1, pEnc->zName, P3_STATIC);
+           break;
+         }
+@@ -799,10 +807,13 @@
+       ** will be overwritten when the schema is next loaded. If it does not
+       ** already exists, it will be created to use the new encoding value.
+       */
+-      if( !(pParse->db->flags&SQLITE_Initialized) ){
++      if( 
++        !(DbHasProperty(db, 0, DB_SchemaLoaded)) || 
++        DbHasProperty(db, 0, DB_Empty) 
++      ){
+         for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
+           if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){
+-            pParse->db->enc = pEnc->enc;
++            ENC(pParse->db) = pEnc->enc;
+             break;
+           }
+         }
+@@ -887,8 +898,8 @@
+     int i;
+     Vdbe *v = sqlite3GetVdbe(pParse);
+     sqlite3VdbeSetNumCols(v, 2);
+-    sqlite3VdbeSetColName(v, 0, "database", P3_STATIC);
+-    sqlite3VdbeSetColName(v, 1, "status", P3_STATIC);
++    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "database", P3_STATIC);
++    sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "status", P3_STATIC);
+     for(i=0; i<db->nDb; i++){
+       Btree *pBt;
+       Pager *pPager;
+@@ -918,6 +929,12 @@
+   }else
+ #endif
+ 
++#if SQLITE_HAS_CODEC
++  if( sqlite3StrICmp(zLeft, "key")==0 ){
++    sqlite3_key(db, zRight, strlen(zRight));
++  }else
++#endif
++
+   {}
+ 
+   if( v ){
+@@ -926,6 +943,15 @@
+     ** are only valid for a single execution.
+     */
+     sqlite3VdbeAddOp(v, OP_Expire, 1, 0);
++
++    /*
++    ** Reset the safety level, in case the fullfsync flag or synchronous
++    ** setting changed.
++    */
++    if( db->autoCommit ){
++      sqlite3BtreeSetSafetyLevel(pDb->pBt, pDb->safety_level,
++                 (db->flags&SQLITE_FullFSync)!=0);
++    }
+   }
+ pragma_out:
+   sqliteFree(zLeft);
+Index: sqlite/vdbeapi.c
+===================================================================
+--- amarok/src/sqlite/vdbeapi.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/vdbeapi.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -58,7 +58,7 @@
+   return sqlite3VdbeIntValue((Mem*)pVal);
+ }
+ const unsigned char *sqlite3_value_text(sqlite3_value *pVal){
+-  return (const char *)sqlite3ValueText(pVal, SQLITE_UTF8);
++  return (const unsigned char *)sqlite3ValueText(pVal, SQLITE_UTF8);
+ }
+ #ifndef SQLITE_OMIT_UTF16
+ const void *sqlite3_value_text16(sqlite3_value* pVal){
+@@ -74,6 +74,7 @@
+ int sqlite3_value_type(sqlite3_value* pVal){
+   return pVal->type;
+ }
++/* sqlite3_value_numeric_type() defined in vdbe.c */
+ 
+ /**************************** sqlite3_result_  *******************************
+ ** The following routines are used by user-defined functions to specify
+@@ -95,10 +96,12 @@
+   pCtx->isError = 1;
+   sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF8, SQLITE_TRANSIENT);
+ }
++#ifndef SQLITE_OMIT_UTF16
+ void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){
+   pCtx->isError = 1;
+   sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT);
+ }
++#endif
+ void sqlite3_result_int(sqlite3_context *pCtx, int iVal){
+   sqlite3VdbeMemSetInt64(&pCtx->s, (i64)iVal);
+ }
+@@ -156,6 +159,9 @@
+   sqlite3 *db;
+   int rc;
+ 
++  /* Assert that malloc() has not failed */
++  assert( !sqlite3MallocFailed() );
++
+   if( p==0 || p->magic!=VDBE_MAGIC_RUN ){
+     return SQLITE_MISUSE;
+   }
+@@ -238,7 +244,8 @@
+   }
+ #endif
+ 
+-  sqlite3Error(p->db, rc, p->zErrMsg ? "%s" : 0, p->zErrMsg);
++  sqlite3Error(p->db, rc, 0);
++  p->rc = sqlite3ApiExit(p->db, p->rc);
+   return rc;
+ }
+ 
+@@ -329,9 +336,10 @@
+ ** Return the number of times the Step function of a aggregate has been 
+ ** called.
+ **
+-** This routine is defined here in vdbe.c because it depends on knowing
+-** the internals of the sqlite3_context structure which is only defined in
+-** this source file.
++** This function is deprecated.  Do not use it for new code.  It is
++** provide only to avoid breaking legacy code.  New aggregate function
++** implementations should keep their own counts within their aggregate
++** context.
+ */
+ int sqlite3_aggregate_count(sqlite3_context *p){
+   assert( p && p->pFunc && p->pFunc->xStep );
+@@ -375,30 +383,76 @@
+   return &pVm->pTos[(1-vals)+i];
+ }
+ 
++/*
++** This function is called after invoking an sqlite3_value_XXX function on a 
++** column value (i.e. a value returned by evaluating an SQL expression in the
++** select list of a SELECT statement) that may cause a malloc() failure. If 
++** malloc() has failed, the threads mallocFailed flag is cleared and the result
++** code of statement pStmt set to SQLITE_NOMEM.
++**
++** Specificly, this is called from within:
++**
++**     sqlite3_column_int()
++**     sqlite3_column_int64()
++**     sqlite3_column_text()
++**     sqlite3_column_text16()
++**     sqlite3_column_real()
++**     sqlite3_column_bytes()
++**     sqlite3_column_bytes16()
++**
++** But not for sqlite3_column_blob(), which never calls malloc().
++*/
++static void columnMallocFailure(sqlite3_stmt *pStmt)
++{
++  /* If malloc() failed during an encoding conversion within an
++  ** sqlite3_column_XXX API, then set the return code of the statement to
++  ** SQLITE_NOMEM. The next call to _step() (if any) will return SQLITE_ERROR
++  ** and _finalize() will return NOMEM.
++  */
++  Vdbe *p = (Vdbe *)pStmt;
++  p->rc = sqlite3ApiExit(0, p->rc);
++}
++
+ /**************************** sqlite3_column_  *******************************
+ ** The following routines are used to access elements of the current row
+ ** in the result set.
+ */
+ const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int i){
+-  return sqlite3_value_blob( columnMem(pStmt,i) );
++  const void *val;
++  sqlite3MallocDisallow();
++  val = sqlite3_value_blob( columnMem(pStmt,i) );
++  sqlite3MallocAllow();
++  return val;
+ }
+ int sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){
+-  return sqlite3_value_bytes( columnMem(pStmt,i) );
++  int val = sqlite3_value_bytes( columnMem(pStmt,i) );
++  columnMallocFailure(pStmt);
++  return val;
+ }
+ int sqlite3_column_bytes16(sqlite3_stmt *pStmt, int i){
+-  return sqlite3_value_bytes16( columnMem(pStmt,i) );
++  int val = sqlite3_value_bytes16( columnMem(pStmt,i) );
++  columnMallocFailure(pStmt);
++  return val;
+ }
+ double sqlite3_column_double(sqlite3_stmt *pStmt, int i){
+-  return sqlite3_value_double( columnMem(pStmt,i) );
++  double val = sqlite3_value_double( columnMem(pStmt,i) );
++  columnMallocFailure(pStmt);
++  return val;
+ }
+ int sqlite3_column_int(sqlite3_stmt *pStmt, int i){
+-  return sqlite3_value_int( columnMem(pStmt,i) );
++  int val = sqlite3_value_int( columnMem(pStmt,i) );
++  columnMallocFailure(pStmt);
++  return val;
+ }
+ sqlite_int64 sqlite3_column_int64(sqlite3_stmt *pStmt, int i){
+-  return sqlite3_value_int64( columnMem(pStmt,i) );
++  sqlite_int64 val = sqlite3_value_int64( columnMem(pStmt,i) );
++  columnMallocFailure(pStmt);
++  return val;
+ }
+ const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){
+-  return sqlite3_value_text( columnMem(pStmt,i) );
++  const unsigned char *val = sqlite3_value_text( columnMem(pStmt,i) );
++  columnMallocFailure(pStmt);
++  return val;
+ }
+ #if 0
+ sqlite3_value *sqlite3_column_value(sqlite3_stmt *pStmt, int i){
+@@ -407,13 +461,22 @@
+ #endif
+ #ifndef SQLITE_OMIT_UTF16
+ const void *sqlite3_column_text16(sqlite3_stmt *pStmt, int i){
+-  return sqlite3_value_text16( columnMem(pStmt,i) );
++  const void *val = sqlite3_value_text16( columnMem(pStmt,i) );
++  columnMallocFailure(pStmt);
++  return val;
+ }
+ #endif /* SQLITE_OMIT_UTF16 */
+ int sqlite3_column_type(sqlite3_stmt *pStmt, int i){
+   return sqlite3_value_type( columnMem(pStmt,i) );
+ }
+ 
++/* The following function is experimental and subject to change or
++** removal */
++/*int sqlite3_column_numeric_type(sqlite3_stmt *pStmt, int i){
++**  return sqlite3_value_numeric_type( columnMem(pStmt,i) );
++**}
++*/
++
+ /*
+ ** Convert the N-th element of pStmt->pColName[] into a string using
+ ** xFunc() then return that string.  If N is out of range, return 0.
+@@ -436,6 +499,7 @@
+   const void *(*xFunc)(Mem*),
+   int useType
+ ){
++  const void *ret;
+   Vdbe *p = (Vdbe *)pStmt;
+   int n = sqlite3_column_count(pStmt);
+ 
+@@ -443,20 +507,27 @@
+     return 0;
+   }
+   N += useType*n;
+-  return xFunc(&p->aColName[N]);
++  ret = xFunc(&p->aColName[N]);
++
++  /* A malloc may have failed inside of the xFunc() call. If this is the case,
++  ** clear the mallocFailed flag and return NULL.
++  */
++  sqlite3ApiExit(0, 0);
++  return ret;
+ }
+ 
+-
+ /*
+ ** Return the name of the Nth column of the result set returned by SQL
+ ** statement pStmt.
+ */
+ const char *sqlite3_column_name(sqlite3_stmt *pStmt, int N){
+-  return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, 0);
++  return columnName(
++      pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_NAME);
+ }
+ #ifndef SQLITE_OMIT_UTF16
+ const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){
+-  return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, 0);
++  return columnName(
++      pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_NAME);
+ }
+ #endif
+ 
+@@ -465,26 +536,30 @@
+ ** of the result set of SQL statement pStmt.
+ */
+ const char *sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){
+-  return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, 1);
++  return columnName(
++      pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DECLTYPE);
+ }
+ #ifndef SQLITE_OMIT_UTF16
+ const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){
+-  return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, 1);
++  return columnName(
++      pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DECLTYPE);
+ }
+ #endif /* SQLITE_OMIT_UTF16 */
+ 
+-#if !defined(SQLITE_OMIT_ORIGIN_NAMES) && 0
++#ifdef SQLITE_ENABLE_COLUMN_METADATA
+ /*
+ ** Return the name of the database from which a result column derives.
+ ** NULL is returned if the result column is an expression or constant or
+ ** anything else which is not an unabiguous reference to a database column.
+ */
+ const char *sqlite3_column_database_name(sqlite3_stmt *pStmt, int N){
+-  return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, 2);
++  return columnName(
++      pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DATABASE);
+ }
+ #ifndef SQLITE_OMIT_UTF16
+ const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N){
+-  return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, 2);
++  return columnName(
++      pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DATABASE);
+ }
+ #endif /* SQLITE_OMIT_UTF16 */
+ 
+@@ -494,11 +569,13 @@
+ ** anything else which is not an unabiguous reference to a database column.
+ */
+ const char *sqlite3_column_table_name(sqlite3_stmt *pStmt, int N){
+-  return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, 3);
++  return columnName(
++      pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_TABLE);
+ }
+ #ifndef SQLITE_OMIT_UTF16
+ const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){
+-  return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, 3);
++  return columnName(
++      pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_TABLE);
+ }
+ #endif /* SQLITE_OMIT_UTF16 */
+ 
+@@ -508,18 +585,18 @@
+ ** anything else which is not an unabiguous reference to a database column.
+ */
+ const char *sqlite3_column_origin_name(sqlite3_stmt *pStmt, int N){
+-  return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, 4);
++  return columnName(
++      pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_COLUMN);
+ }
+ #ifndef SQLITE_OMIT_UTF16
+ const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){
+-  return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, 4);
++  return columnName(
++      pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_COLUMN);
+ }
+ #endif /* SQLITE_OMIT_UTF16 */
+-#endif /* SQLITE_OMIT_ORIGIN_NAMES */
++#endif /* SQLITE_ENABLE_COLUMN_METADATA */
+ 
+ 
+-
+-
+ /******************************* sqlite3_bind_  ***************************
+ ** 
+ ** Routines used to attach values to wildcards in a compiled SQL statement.
+@@ -571,13 +648,12 @@
+   }
+   pVar = &p->aVar[i-1];
+   rc = sqlite3VdbeMemSetStr(pVar, zData, nData, encoding, xDel);
+-  if( rc ){
+-    return rc;
+-  }
+   if( rc==SQLITE_OK && encoding!=0 ){
+-    rc = sqlite3VdbeChangeEncoding(pVar, p->db->enc);
++    rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db));
+   }
+-  return rc;
++
++  sqlite3Error(((Vdbe *)pStmt)->db, rc, 0);
++  return sqlite3ApiExit(((Vdbe *)pStmt)->db, rc);
+ }
+ 
+ 
+@@ -721,7 +797,9 @@
+     return SQLITE_ERROR;
+   }
+   for(i=0; rc==SQLITE_OK && i<pFrom->nVar; i++){
++    sqlite3MallocDisallow();
+     rc = sqlite3VdbeMemMove(&pTo->aVar[i], &pFrom->aVar[i]);
++    sqlite3MallocAllow();
+   }
+   return rc;
+ }
+Index: sqlite/util.c
+===================================================================
+--- amarok/src/sqlite/util.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/util.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -17,39 +17,175 @@
+ ** $Id$
+ */
+ #include "sqliteInt.h"
++#include "os.h"
+ #include <stdarg.h>
+ #include <ctype.h>
+ 
+-#if SQLITE_MEMDEBUG>2 && defined(__GLIBC__)
+-#include <execinfo.h>
+-void print_stack_trace(){
+-  void *bt[30];
+-  int i;
+-  int n = backtrace(bt, 30);
++/*
++** MALLOC WRAPPER ARCHITECTURE
++**
++** The sqlite code accesses dynamic memory allocation/deallocation by invoking
++** the following six APIs (which may be implemented as macros).
++**
++**     sqlite3Malloc()
++**     sqlite3MallocRaw()
++**     sqlite3Realloc()
++**     sqlite3ReallocOrFree()
++**     sqlite3Free()
++**     sqlite3AllocSize()
++**
++** The function sqlite3FreeX performs the same task as sqlite3Free and is
++** guaranteed to be a real function. The same holds for sqlite3MallocX
++**
++** The above APIs are implemented in terms of the functions provided in the
++** operating-system interface. The OS interface is never accessed directly
++** by code outside of this file.
++**
++**     sqlite3OsMalloc()
++**     sqlite3OsRealloc()
++**     sqlite3OsFree()
++**     sqlite3OsAllocationSize()
++**
++** Functions sqlite3MallocRaw() and sqlite3Realloc() may invoke 
++** sqlite3_release_memory() if a call to sqlite3OsMalloc() or
++** sqlite3OsRealloc() fails (or if the soft-heap-limit for the thread is
++** exceeded). Function sqlite3Malloc() usually invokes
++** sqlite3MallocRaw().
++**
++** MALLOC TEST WRAPPER ARCHITECTURE
++**
++** The test wrapper provides extra test facilities to ensure the library 
++** does not leak memory and handles the failure of the underlying OS level
++** allocation system correctly. It is only present if the library is 
++** compiled with the SQLITE_MEMDEBUG macro set.
++**
++**     * Guardposts to detect overwrites.
++**     * Ability to cause a specific Malloc() or Realloc() to fail.
++**     * Audit outstanding memory allocations (i.e check for leaks).
++*/
+ 
+-  fprintf(stderr, "STACK: ");
+-  for(i=0; i<n;i++){
+-    fprintf(stderr, "%p ", bt[i]);
++#define MAX(x,y) ((x)>(y)?(x):(y))
++
++#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) && !defined(SQLITE_OMIT_DISKIO)
++/*
++** Set the soft heap-size limit for the current thread. Passing a negative
++** value indicates no limit.
++*/
++void sqlite3_soft_heap_limit(int n){
++  ThreadData *pTd = sqlite3ThreadData();
++  if( pTd ){
++    pTd->nSoftHeapLimit = n;
+   }
+-  fprintf(stderr, "\n");
++  sqlite3ReleaseThreadData();
+ }
++
++/*
++** Release memory held by SQLite instances created by the current thread.
++*/
++int sqlite3_release_memory(int n){
++  return sqlite3pager_release_memory(n);
++}
+ #else
+-#define print_stack_trace()
++/* If SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined, then define a version
++** of sqlite3_release_memory() to be used by other code in this file.
++** This is done for no better reason than to reduce the number of 
++** pre-processor #ifndef statements.
++*/
++#define sqlite3_release_memory(x) 0    /* 0 == no memory freed */
+ #endif
+ 
++#ifdef SQLITE_MEMDEBUG
++/*--------------------------------------------------------------------------
++** Begin code for memory allocation system test layer.
++**
++** Memory debugging is turned on by defining the SQLITE_MEMDEBUG macro.
++**
++** SQLITE_MEMDEBUG==1    -> Fence-posting only (thread safe) 
++** SQLITE_MEMDEBUG==2    -> Fence-posting + linked list of allocations (not ts)
++** SQLITE_MEMDEBUG==3    -> Above + backtraces (not thread safe, req. glibc)
++*/
++
++/* Figure out whether or not to store backtrace() information for each malloc.
++** The backtrace() function is only used if SQLITE_MEMDEBUG is set to 2 or 
++** greater and glibc is in use. If we don't want to use backtrace(), then just
++** define it as an empty macro and set the amount of space reserved to 0.
++*/
++#if defined(__GLIBC__) && SQLITE_MEMDEBUG>2
++  extern int backtrace(void **, int);
++  #define TESTALLOC_STACKSIZE 128
++  #define TESTALLOC_STACKFRAMES ((TESTALLOC_STACKSIZE-8)/sizeof(void*))
++#else
++  #define backtrace(x, y)
++  #define TESTALLOC_STACKSIZE 0
++  #define TESTALLOC_STACKFRAMES 0
++#endif
++
+ /*
+-** If malloc() ever fails, this global variable gets set to 1.
+-** This causes the library to abort and never again function.
++** Number of 32-bit guard words.  This should probably be a multiple of
++** 2 since on 64-bit machines we want the value returned by sqliteMalloc()
++** to be 8-byte aligned.
+ */
+-int sqlite3_malloc_failed = 0;
++#ifndef TESTALLOC_NGUARD
++# define TESTALLOC_NGUARD 2
++#endif
+ 
+ /*
+-** If SQLITE_MEMDEBUG is defined, then use versions of malloc() and
+-** free() that track memory usage and check for buffer overruns.
++** Size reserved for storing file-name along with each malloc()ed blob.
+ */
+-#ifdef SQLITE_MEMDEBUG
++#define TESTALLOC_FILESIZE 64
+ 
+ /*
++** Size reserved for storing the user string. Each time a Malloc() or Realloc()
++** call succeeds, up to TESTALLOC_USERSIZE bytes of the string pointed to by
++** sqlite3_malloc_id are stored along with the other test system metadata.
++*/
++#define TESTALLOC_USERSIZE 64
++const char *sqlite3_malloc_id = 0;
++
++/*
++** Blocks used by the test layer have the following format:
++**
++**        <sizeof(void *) pNext pointer>
++**        <sizeof(void *) pPrev pointer>
++**        <TESTALLOC_NGUARD 32-bit guard words>
++**            <The application level allocation>
++**        <TESTALLOC_NGUARD 32-bit guard words>
++**        <32-bit line number>
++**        <TESTALLOC_FILESIZE bytes containing null-terminated file name>
++**        <TESTALLOC_STACKSIZE bytes of backtrace() output>
++*/ 
++
++#define TESTALLOC_OFFSET_GUARD1(p)    (sizeof(void *) * 2)
++#define TESTALLOC_OFFSET_DATA(p) ( \
++  TESTALLOC_OFFSET_GUARD1(p) + sizeof(u32) * TESTALLOC_NGUARD \
++)
++#define TESTALLOC_OFFSET_GUARD2(p) ( \
++  TESTALLOC_OFFSET_DATA(p) + sqlite3OsAllocationSize(p) - TESTALLOC_OVERHEAD \
++)
++#define TESTALLOC_OFFSET_LINENUMBER(p) ( \
++  TESTALLOC_OFFSET_GUARD2(p) + sizeof(u32) * TESTALLOC_NGUARD \
++)
++#define TESTALLOC_OFFSET_FILENAME(p) ( \
++  TESTALLOC_OFFSET_LINENUMBER(p) + sizeof(u32) \
++)
++#define TESTALLOC_OFFSET_USER(p) ( \
++  TESTALLOC_OFFSET_FILENAME(p) + TESTALLOC_FILESIZE \
++)
++#define TESTALLOC_OFFSET_STACK(p) ( \
++  TESTALLOC_OFFSET_USER(p) + TESTALLOC_USERSIZE + 8 - \
++  (TESTALLOC_OFFSET_USER(p) % 8) \
++)
++
++#define TESTALLOC_OVERHEAD ( \
++  sizeof(void *)*2 +                   /* pPrev and pNext pointers */   \
++  TESTALLOC_NGUARD*sizeof(u32)*2 +              /* Guard words */       \
++  sizeof(u32) + TESTALLOC_FILESIZE +   /* File and line number */       \
++  TESTALLOC_USERSIZE +                 /* User string */                \
++  TESTALLOC_STACKSIZE                  /* backtrace() stack */          \
++)
++
++
++/*
+ ** For keeping track of the number of mallocs and frees.   This
+ ** is used to check for memory leaks.  The iMallocFail and iMallocReset
+ ** values are used to simulate malloc() failures during testing in 
+@@ -58,35 +194,31 @@
+ */
+ int sqlite3_nMalloc;         /* Number of sqliteMalloc() calls */
+ int sqlite3_nFree;           /* Number of sqliteFree() calls */
+-int sqlite3_memUsed;         /* Total memory obtained from malloc */
+-int sqlite3_memMax;          /* Mem usage high-water mark */
++int sqlite3_memUsed;         /* TODO Total memory obtained from malloc */
++int sqlite3_memMax;          /* TODO Mem usage high-water mark */
+ int sqlite3_iMallocFail;     /* Fail sqliteMalloc() after this many calls */
+ int sqlite3_iMallocReset = -1; /* When iMallocFail reaches 0, set to this */
+-#if SQLITE_MEMDEBUG>1
+-static int memcnt = 0;
+-#endif
+ 
+-/*
+-** Number of 32-bit guard words.  This should probably be a multiple of
+-** 2 since on 64-bit machines we want the value returned by sqliteMalloc()
+-** to be 8-byte aligned.
+-*/
+-#define N_GUARD 2
++void *sqlite3_pFirst = 0;         /* Pointer to linked list of allocations */
++int sqlite3_nMaxAlloc = 0;        /* High water mark of ThreadData.nAlloc */
++int sqlite3_mallocDisallowed = 0; /* assert() in sqlite3Malloc() if set */
++int sqlite3_isFail = 0;           /* True if all malloc calls should fail */
++const char *sqlite3_zFile = 0;    /* Filename to associate debug info with */
++int sqlite3_iLine = 0;            /* Line number for debug info */
+ 
+ /*
+ ** Check for a simulated memory allocation failure.  Return true if
+ ** the failure should be simulated.  Return false to proceed as normal.
+ */
+-static int simulatedMallocFailure(int n, char *zFile, int line){
++int sqlite3TestMallocFail(){
++  if( sqlite3_isFail ){
++    return 1;
++  }
+   if( sqlite3_iMallocFail>=0 ){
+     sqlite3_iMallocFail--;
+     if( sqlite3_iMallocFail==0 ){
+-      sqlite3_malloc_failed++;
+-#if SQLITE_MEMDEBUG>1
+-      fprintf(stderr,"**** failed to allocate %d bytes at %s:%d\n",
+-              n, zFile,line);
+-#endif
+       sqlite3_iMallocFail = sqlite3_iMallocReset;
++      sqlite3_isFail = 1;
+       return 1;
+     }
+   }
+@@ -94,292 +226,485 @@
+ }
+ 
+ /*
+-** Allocate new memory and set it to zero.  Return NULL if
+-** no memory is available.
++** The argument is a pointer returned by sqlite3OsMalloc() or xRealloc().
++** assert() that the first and last (TESTALLOC_NGUARD*4) bytes are set to the
++** values set by the applyGuards() function.
+ */
+-void *sqlite3Malloc_(int n, int bZero, char *zFile, int line){
+-  void *p;
+-  int *pi;
+-  int i, k;
+-  if( n==0 ){
+-    return 0;
++static void checkGuards(u32 *p)
++{
++  int i;
++  char *zAlloc = (char *)p;
++  char *z;
++
++  /* First set of guard words */
++  z = &zAlloc[TESTALLOC_OFFSET_GUARD1(p)];
++  for(i=0; i<TESTALLOC_NGUARD; i++){
++    assert(((u32 *)z)[i]==0xdead1122);
+   }
+-  if( simulatedMallocFailure(n, zFile, line) ){
+-    return 0;
++
++  /* Second set of guard words */
++  z = &zAlloc[TESTALLOC_OFFSET_GUARD2(p)];
++  for(i=0; i<TESTALLOC_NGUARD; i++){
++    u32 guard = 0;
++    memcpy(&guard, &z[i*sizeof(u32)], sizeof(u32));
++    assert(guard==0xdead3344);
+   }
+-  sqlite3_memUsed += n;
+-  if( sqlite3_memMax<sqlite3_memUsed ) sqlite3_memMax = sqlite3_memUsed;
+-  k = (n+sizeof(int)-1)/sizeof(int);
+-  pi = malloc( (N_GUARD*2+1+k)*sizeof(int));
+-  if( pi==0 ){
+-    if( n>0 ) sqlite3_malloc_failed++;
+-    return 0;
++}
++
++/*
++** The argument is a pointer returned by sqlite3OsMalloc() or Realloc(). The
++** first and last (TESTALLOC_NGUARD*4) bytes are set to known values for use as 
++** guard-posts.
++*/
++static void applyGuards(u32 *p)
++{
++  int i;
++  char *z;
++  char *zAlloc = (char *)p;
++
++  /* First set of guard words */
++  z = &zAlloc[TESTALLOC_OFFSET_GUARD1(p)];
++  for(i=0; i<TESTALLOC_NGUARD; i++){
++    ((u32 *)z)[i] = 0xdead1122;
+   }
+-  sqlite3_nMalloc++;
+-  for(i=0; i<N_GUARD; i++) pi[i] = 0xdead1122;
+-  pi[N_GUARD] = n;
+-  for(i=0; i<N_GUARD; i++) pi[k+1+N_GUARD+i] = 0xdead3344;
+-  p = &pi[N_GUARD+1];
+-  memset(p, bZero==0, n);
+-#if SQLITE_MEMDEBUG>1
+-  print_stack_trace();
+-  fprintf(stderr,"%06d malloc %d bytes at 0x%x from %s:%d\n",
+-      ++memcnt, n, (int)p, zFile,line);
+-#endif
+-  return p;
++
++  /* Second set of guard words */
++  z = &zAlloc[TESTALLOC_OFFSET_GUARD2(p)];
++  for(i=0; i<TESTALLOC_NGUARD; i++){
++    static const int guard = 0xdead3344;
++    memcpy(&z[i*sizeof(u32)], &guard, sizeof(u32));
++  }
++
++  /* Line number */
++  z = &((char *)z)[TESTALLOC_NGUARD*sizeof(u32)];             /* Guard words */
++  z = &zAlloc[TESTALLOC_OFFSET_LINENUMBER(p)];
++  memcpy(z, &sqlite3_iLine, sizeof(u32));
++
++  /* File name */
++  z = &zAlloc[TESTALLOC_OFFSET_FILENAME(p)];
++  strncpy(z, sqlite3_zFile, TESTALLOC_FILESIZE);
++  z[TESTALLOC_FILESIZE - 1] = '\0';
++
++  /* User string */
++  z = &zAlloc[TESTALLOC_OFFSET_USER(p)];
++  z[0] = 0;
++  if( sqlite3_malloc_id ){
++    strncpy(z, sqlite3_malloc_id, TESTALLOC_USERSIZE);
++    z[TESTALLOC_USERSIZE-1] = 0;
++  }
++
++  /* backtrace() stack */
++  z = &zAlloc[TESTALLOC_OFFSET_STACK(p)];
++  backtrace((void **)z, TESTALLOC_STACKFRAMES);
++
++  /* Sanity check to make sure checkGuards() is working */
++  checkGuards(p);
+ }
+ 
+ /*
+-** This version of malloc is always a real function, never a macro
++** The argument is a malloc()ed pointer as returned by the test-wrapper.
++** Return a pointer to the Os level allocation.
+ */
+-void *sqlite3MallocX(int n){
+-  return sqlite3Malloc_(n, 0, __FILE__, __LINE__);
++static void *getOsPointer(void *p)
++{
++  char *z = (char *)p;
++  return (void *)(&z[-1 * TESTALLOC_OFFSET_DATA(p)]);
+ }
+ 
++
++#if SQLITE_MEMDEBUG>1
+ /*
+-** Check to see if the given pointer was obtained from sqliteMalloc()
+-** and is able to hold at least N bytes.  Raise an exception if this
+-** is not the case.
+-**
+-** This routine is used for testing purposes only.
++** The argument points to an Os level allocation. Link it into the threads list
++** of allocations.
+ */
+-void sqlite3CheckMemory(void *p, int N){
+-  int *pi = p;
+-  int n, i, k;
+-  pi -= N_GUARD+1;
+-  for(i=0; i<N_GUARD; i++){
+-    assert( pi[i]==0xdead1122 );
++static void linkAlloc(void *p){
++  void **pp = (void **)p;
++  pp[0] = 0;
++  pp[1] = sqlite3_pFirst;
++  if( sqlite3_pFirst ){
++    ((void **)sqlite3_pFirst)[0] = p;
+   }
+-  n = pi[N_GUARD];
+-  assert( N>=0 && N<n );
+-  k = (n+sizeof(int)-1)/sizeof(int);
+-  for(i=0; i<N_GUARD; i++){
+-    assert( pi[k+N_GUARD+1+i]==0xdead3344 );
+-  }
++  sqlite3_pFirst = p;
+ }
+ 
+ /*
+-** Free memory previously obtained from sqliteMalloc()
++** The argument points to an Os level allocation. Unlinke it from the threads
++** list of allocations.
+ */
+-void sqlite3Free_(void *p, char *zFile, int line){
+-  if( p ){
+-    int *pi, i, k, n;
+-    pi = p;
+-    pi -= N_GUARD+1;
+-    sqlite3_nFree++;
+-    for(i=0; i<N_GUARD; i++){
+-      if( pi[i]!=0xdead1122 ){
+-        fprintf(stderr,"Low-end memory corruption at 0x%x\n", (int)p);
+-        return;
+-      }
++static void unlinkAlloc(void *p)
++{
++  void **pp = (void **)p;
++  if( p==sqlite3_pFirst ){
++    assert(!pp[0]);
++    assert(!pp[1] || ((void **)(pp[1]))[0]==p);
++    sqlite3_pFirst = pp[1];
++    if( sqlite3_pFirst ){
++      ((void **)sqlite3_pFirst)[0] = 0;
+     }
+-    n = pi[N_GUARD];
+-    sqlite3_memUsed -= n;
+-    k = (n+sizeof(int)-1)/sizeof(int);
+-    for(i=0; i<N_GUARD; i++){
+-      if( pi[k+N_GUARD+1+i]!=0xdead3344 ){
+-        fprintf(stderr,"High-end memory corruption at 0x%x\n", (int)p);
+-        return;
+-      }
++  }else{
++    void **pprev = pp[0];
++    void **pnext = pp[1];
++    assert(pprev);
++    assert(pprev[1]==p);
++    pprev[1] = (void *)pnext;
++    if( pnext ){
++      assert(pnext[0]==p);
++      pnext[0] = (void *)pprev;
+     }
+-    memset(pi, 0xff, (k+N_GUARD*2+1)*sizeof(int));
+-#if SQLITE_MEMDEBUG>1
+-    fprintf(stderr,"%06d free %d bytes at 0x%x from %s:%d\n",
+-         ++memcnt, n, (int)p, zFile,line);
+-#endif
+-    free(pi);
+   }
+ }
+ 
+ /*
+-** Resize a prior allocation.  If p==0, then this routine
+-** works just like sqliteMalloc().  If n==0, then this routine
+-** works just like sqliteFree().
++** Pointer p is a pointer to an OS level allocation that has just been
++** realloc()ed. Set the list pointers that point to this entry to it's new
++** location.
+ */
+-void *sqlite3Realloc_(void *oldP, int n, char *zFile, int line){
+-  int *oldPi, *pi, i, k, oldN, oldK;
+-  void *p;
+-  if( oldP==0 ){
+-    return sqlite3Malloc_(n,1,zFile,line);
++static void relinkAlloc(void *p)
++{
++  void **pp = (void **)p;
++  if( pp[0] ){
++    ((void **)(pp[0]))[1] = p;
++  }else{
++    sqlite3_pFirst = p;
+   }
+-  if( n==0 ){
+-    sqlite3Free_(oldP,zFile,line);
+-    return 0;
++  if( pp[1] ){
++    ((void **)(pp[1]))[0] = p;
+   }
+-  if( simulatedMallocFailure(n, zFile, line) ){
+-    return 0;
+-  }
+-  oldPi = oldP;
+-  oldPi -= N_GUARD+1;
+-  if( oldPi[0]!=0xdead1122 ){
+-    fprintf(stderr,"Low-end memory corruption in realloc at 0x%x\n", (int)oldP);
+-    return 0;
+-  }
+-  oldN = oldPi[N_GUARD];
+-  sqlite3_memUsed -= oldN;
+-  oldK = (oldN+sizeof(int)-1)/sizeof(int);
+-  for(i=0; i<N_GUARD; i++){
+-    if( oldPi[oldK+N_GUARD+1+i]!=0xdead3344 ){
+-      fprintf(stderr,"High-end memory corruption in realloc at 0x%x\n",
+-              (int)oldP);
+-      return 0;
++}
++#else
++#define linkAlloc(x)
++#define relinkAlloc(x)
++#define unlinkAlloc(x)
++#endif
++
++/*
++** This function sets the result of the Tcl interpreter passed as an argument
++** to a list containing an entry for each currently outstanding call made to 
++** sqliteMalloc and friends by the current thread. Each list entry is itself a
++** list, consisting of the following (in order):
++**
++**     * The number of bytes allocated
++**     * The __FILE__ macro at the time of the sqliteMalloc() call.
++**     * The __LINE__ macro ...
++**     * The value of the sqlite3_malloc_id variable ...
++**     * The output of backtrace() (if available) ...
++**
++** Todo: We could have a version of this function that outputs to stdout, 
++** to debug memory leaks when Tcl is not available.
++*/
++#if defined(TCLSH) && defined(SQLITE_DEBUG) && SQLITE_MEMDEBUG>1
++#include <tcl.h>
++int sqlite3OutstandingMallocs(Tcl_Interp *interp){
++  void *p;
++  Tcl_Obj *pRes = Tcl_NewObj();
++  Tcl_IncrRefCount(pRes);
++
++
++  for(p=sqlite3_pFirst; p; p=((void **)p)[1]){
++    Tcl_Obj *pEntry = Tcl_NewObj();
++    Tcl_Obj *pStack = Tcl_NewObj();
++    char *z;
++    u32 iLine;
++    int nBytes = sqlite3OsAllocationSize(p) - TESTALLOC_OVERHEAD;
++    char *zAlloc = (char *)p;
++    int i;
++
++    Tcl_ListObjAppendElement(0, pEntry, Tcl_NewIntObj(nBytes));
++
++    z = &zAlloc[TESTALLOC_OFFSET_FILENAME(p)];
++    Tcl_ListObjAppendElement(0, pEntry, Tcl_NewStringObj(z, -1));
++
++    z = &zAlloc[TESTALLOC_OFFSET_LINENUMBER(p)];
++    memcpy(&iLine, z, sizeof(u32));
++    Tcl_ListObjAppendElement(0, pEntry, Tcl_NewIntObj(iLine));
++
++    z = &zAlloc[TESTALLOC_OFFSET_USER(p)];
++    Tcl_ListObjAppendElement(0, pEntry, Tcl_NewStringObj(z, -1));
++
++    z = &zAlloc[TESTALLOC_OFFSET_STACK(p)];
++    for(i=0; i<TESTALLOC_STACKFRAMES; i++){
++      char zHex[128];
++      sprintf(zHex, "%p", ((void **)z)[i]);
++      Tcl_ListObjAppendElement(0, pStack, Tcl_NewStringObj(zHex, -1));
+     }
++
++    Tcl_ListObjAppendElement(0, pEntry, pStack);
++    Tcl_ListObjAppendElement(0, pRes, pEntry);
+   }
+-  k = (n + sizeof(int) - 1)/sizeof(int);
+-  pi = malloc( (k+N_GUARD*2+1)*sizeof(int) );
+-  if( pi==0 ){
+-    if( n>0 ) sqlite3_malloc_failed++;
+-    return 0;
+-  }
+-  for(i=0; i<N_GUARD; i++) pi[i] = 0xdead1122;
+-  pi[N_GUARD] = n;
+-  sqlite3_memUsed += n;
+-  if( sqlite3_memMax<sqlite3_memUsed ) sqlite3_memMax = sqlite3_memUsed;
+-  for(i=0; i<N_GUARD; i++) pi[k+N_GUARD+1+i] = 0xdead3344;
+-  p = &pi[N_GUARD+1];
+-  memcpy(p, oldP, n>oldN ? oldN : n);
+-  if( n>oldN ){
+-    memset(&((char*)p)[oldN], 0x55, n-oldN);
+-  }
+-  memset(oldPi, 0xab, (oldK+N_GUARD+2)*sizeof(int));
+-  free(oldPi);
+-#if SQLITE_MEMDEBUG>1
+-  print_stack_trace();
+-  fprintf(stderr,"%06d realloc %d to %d bytes at 0x%x to 0x%x at %s:%d\n",
+-    ++memcnt, oldN, n, (int)oldP, (int)p, zFile, line);
++
++  Tcl_ResetResult(interp);
++  Tcl_SetObjResult(interp, pRes);
++  Tcl_DecrRefCount(pRes);
++  return TCL_OK;
++}
+ #endif
+-  return p;
+-}
+ 
+ /*
+-** Make a copy of a string in memory obtained from sqliteMalloc()
++** This is the test layer's wrapper around sqlite3OsMalloc().
+ */
+-char *sqlite3StrDup_(const char *z, char *zFile, int line){
+-  char *zNew;
+-  if( z==0 ) return 0;
+-  zNew = sqlite3Malloc_(strlen(z)+1, 0, zFile, line);
+-  if( zNew ) strcpy(zNew, z);
+-  return zNew;
++static void * OSMALLOC(int n){
++#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
++  sqlite3_nMaxAlloc = 
++      MAX(sqlite3_nMaxAlloc, sqlite3ThreadDataReadOnly()->nAlloc);
++#endif
++  assert( !sqlite3_mallocDisallowed );
++  if( !sqlite3TestMallocFail() ){
++    u32 *p;
++    p = (u32 *)sqlite3OsMalloc(n + TESTALLOC_OVERHEAD);
++    assert(p);
++    sqlite3_nMalloc++;
++    applyGuards(p);
++    linkAlloc(p);
++    return (void *)(&p[TESTALLOC_NGUARD + 2*sizeof(void *)/sizeof(u32)]);
++  }
++  return 0;
+ }
+-char *sqlite3StrNDup_(const char *z, int n, char *zFile, int line){
+-  char *zNew;
+-  if( z==0 ) return 0;
+-  zNew = sqlite3Malloc_(n+1, 0, zFile, line);
+-  if( zNew ){
+-    memcpy(zNew, z, n);
+-    zNew[n] = 0;
++
++static int OSSIZEOF(void *p){
++  if( p ){
++    u32 *pOs = (u32 *)getOsPointer(p);
++    return sqlite3OsAllocationSize(pOs) - TESTALLOC_OVERHEAD;
+   }
+-  return zNew;
++  return 0;
+ }
+ 
+ /*
+-** A version of sqliteFree that is always a function, not a macro.
++** This is the test layer's wrapper around sqlite3OsFree(). The argument is a
++** pointer to the space allocated for the application to use.
+ */
+-void sqlite3FreeX(void *p){
+-  sqliteFree(p);
++static void OSFREE(void *pFree){
++  u32 *p = (u32 *)getOsPointer(pFree);   /* p points to Os level allocation */
++  checkGuards(p);
++  unlinkAlloc(p);
++  memset(pFree, 0x55, OSSIZEOF(pFree));
++  sqlite3OsFree(p);
++  sqlite3_nFree++;
+ }
+-#endif /* SQLITE_MEMDEBUG */
+ 
+ /*
+-** The following versions of malloc() and free() are for use in a
+-** normal build.
++** This is the test layer's wrapper around sqlite3OsRealloc().
+ */
+-#if !defined(SQLITE_MEMDEBUG)
++static void * OSREALLOC(void *pRealloc, int n){
++#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
++  sqlite3_nMaxAlloc = 
++      MAX(sqlite3_nMaxAlloc, sqlite3ThreadDataReadOnly()->nAlloc);
++#endif
++  assert( !sqlite3_mallocDisallowed );
++  if( !sqlite3TestMallocFail() ){
++    u32 *p = (u32 *)getOsPointer(pRealloc);
++    checkGuards(p);
++    p = sqlite3OsRealloc(p, n + TESTALLOC_OVERHEAD);
++    applyGuards(p);
++    relinkAlloc(p);
++    return (void *)(&p[TESTALLOC_NGUARD + 2*sizeof(void *)/sizeof(u32)]);
++  }
++  return 0;
++}
+ 
++static void OSMALLOC_FAILED(){
++  sqlite3_isFail = 0;
++}
++
++#else
++/* Define macros to call the sqlite3OsXXX interface directly if 
++** the SQLITE_MEMDEBUG macro is not defined.
++*/
++#define OSMALLOC(x)        sqlite3OsMalloc(x)
++#define OSREALLOC(x,y)     sqlite3OsRealloc(x,y)
++#define OSFREE(x)          sqlite3OsFree(x)
++#define OSSIZEOF(x)        sqlite3OsAllocationSize(x)
++#define OSMALLOC_FAILED()
++
++#endif  /* SQLITE_MEMDEBUG */
+ /*
+-** Allocate new memory and set it to zero.  Return NULL if
+-** no memory is available.  See also sqliteMallocRaw().
++** End code for memory allocation system test layer.
++**--------------------------------------------------------------------------*/
++
++/*
++** This routine is called when we are about to allocate n additional bytes
++** of memory.  If the new allocation will put is over the soft allocation
++** limit, then invoke sqlite3_release_memory() to try to release some
++** memory before continuing with the allocation.
++**
++** This routine also makes sure that the thread-specific-data (TSD) has
++** be allocated.  If it has not and can not be allocated, then return
++** false.  The updateMemoryUsedCount() routine below will deallocate
++** the TSD if it ought to be.
++**
++** If SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined, this routine is
++** a no-op
++*/ 
++#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
++static int enforceSoftLimit(int n){
++  ThreadData *pTsd = sqlite3ThreadData();
++  if( pTsd==0 ){
++    return 0;
++  }
++  assert( pTsd->nAlloc>=0 );
++  if( n>0 && pTsd->nSoftHeapLimit>0 ){
++    while( pTsd->nAlloc+n>pTsd->nSoftHeapLimit && sqlite3_release_memory(n) );
++  }
++  return 1;
++}
++#else
++# define enforceSoftLimit(X)  1
++#endif
++
++/*
++** Update the count of total outstanding memory that is held in
++** thread-specific-data (TSD).  If after this update the TSD is
++** no longer being used, then deallocate it.
++**
++** If SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined, this routine is
++** a no-op
+ */
+-void *sqlite3Malloc(int n){
+-  void *p;
+-  if( n==0 ) return 0;
+-  if( (p = malloc(n))==0 ){
+-    if( n>0 ) sqlite3_malloc_failed++;
+-  }else{
+-    memset(p, 0, n);
++#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
++static void updateMemoryUsedCount(int n){
++  ThreadData *pTsd = sqlite3ThreadData();
++  if( pTsd ){
++    pTsd->nAlloc += n;
++    assert( pTsd->nAlloc>=0 );
++    if( pTsd->nAlloc==0 && pTsd->nSoftHeapLimit==0 ){
++      sqlite3ReleaseThreadData();
++    }
+   }
+-  return p;
+ }
++#else
++#define updateMemoryUsedCount(x)  /* no-op */
++#endif
+ 
+ /*
+-** Allocate new memory but do not set it to zero.  Return NULL if
+-** no memory is available.  See also sqliteMalloc().
++** Allocate and return N bytes of uninitialised memory by calling
++** sqlite3OsMalloc(). If the Malloc() call fails, attempt to free memory 
++** by calling sqlite3_release_memory().
+ */
+ void *sqlite3MallocRaw(int n){
+-  void *p;
+-  if( n==0 ) return 0;
+-  if( (p = malloc(n))==0 ){
+-    if( n>0 ) sqlite3_malloc_failed++;
++  void *p = 0;
++  if( n>0 && !sqlite3MallocFailed() && enforceSoftLimit(n) ){
++    while( (p = OSMALLOC(n))==0 && sqlite3_release_memory(n) );
++    if( !p ){
++      sqlite3FailedMalloc();
++      OSMALLOC_FAILED();
++    }else{
++      updateMemoryUsedCount(OSSIZEOF(p));
++    }
+   }
+   return p;
+ }
+ 
+ /*
+-** Free memory previously obtained from sqliteMalloc()
++** Resize the allocation at p to n bytes by calling sqlite3OsRealloc(). The
++** pointer to the new allocation is returned.  If the Realloc() call fails,
++** attempt to free memory by calling sqlite3_release_memory().
+ */
++void *sqlite3Realloc(void *p, int n){
++  if( sqlite3MallocFailed() ){
++    return 0;
++  }
++
++  if( !p ){
++    return sqlite3Malloc(n);
++  }else{
++    void *np = 0;
++#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
++    int origSize = OSSIZEOF(p);
++#endif
++    if( enforceSoftLimit(n - origSize) ){
++      while( (np = OSREALLOC(p, n))==0 && sqlite3_release_memory(n) );
++      if( !np ){
++        sqlite3FailedMalloc();
++        OSMALLOC_FAILED();
++      }else{
++        updateMemoryUsedCount(OSSIZEOF(np) - origSize);
++      }
++    }
++    return np;
++  }
++}
++
++/*
++** Free the memory pointed to by p. p must be either a NULL pointer or a 
++** value returned by a previous call to sqlite3Malloc() or sqlite3Realloc().
++*/
+ void sqlite3FreeX(void *p){
+   if( p ){
+-    free(p);
++    updateMemoryUsedCount(0 - OSSIZEOF(p));
++    OSFREE(p);
+   }
+ }
+ 
+ /*
+-** Resize a prior allocation.  If p==0, then this routine
+-** works just like sqliteMalloc().  If n==0, then this routine
+-** works just like sqliteFree().
++** A version of sqliteMalloc() that is always a function, not a macro.
++** Currently, this is used only to alloc to allocate the parser engine.
+ */
+-void *sqlite3Realloc(void *p, int n){
+-  void *p2;
+-  if( p==0 ){
+-    return sqliteMalloc(n);
++void *sqlite3MallocX(int n){
++  return sqliteMalloc(n);
++}
++
++/*
++** sqlite3Malloc
++** sqlite3ReallocOrFree
++**
++** These two are implemented as wrappers around sqlite3MallocRaw(), 
++** sqlite3Realloc() and sqlite3Free().
++*/ 
++void *sqlite3Malloc(int n){
++  void *p = sqlite3MallocRaw(n);
++  if( p ){
++    memset(p, 0, n);
+   }
+-  if( n==0 ){
+-    sqliteFree(p);
+-    return 0;
++  return p;
++}
++void sqlite3ReallocOrFree(void **pp, int n){
++  void *p = sqlite3Realloc(*pp, n);
++  if( !p ){
++    sqlite3FreeX(*pp);
+   }
+-  p2 = realloc(p, n);
+-  if( p2==0 ){
+-    if( n>0 ) sqlite3_malloc_failed++;
+-  }
+-  return p2;
++  *pp = p;
+ }
+ 
+ /*
+-** Make a copy of a string in memory obtained from sqliteMalloc()
++** Return the number of bytes allocated at location p. p must be either 
++** a NULL pointer (in which case 0 is returned) or a pointer returned by 
++** sqlite3Malloc(), sqlite3Realloc() or sqlite3ReallocOrFree().
++**
++** The number of bytes allocated does not include any overhead inserted by 
++** any malloc() wrapper functions that may be called. So the value returned
++** is the number of bytes that were available to SQLite using pointer p, 
++** regardless of how much memory was actually allocated.
+ */
++#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
++int sqlite3AllocSize(void *p){
++  return OSSIZEOF(p);
++}
++#endif
++
++/*
++** Make a copy of a string in memory obtained from sqliteMalloc(). These 
++** functions call sqlite3MallocRaw() directly instead of sqliteMalloc(). This
++** is because when memory debugging is turned on, these two functions are 
++** called via macros that record the current file and line number in the
++** ThreadData structure.
++*/
+ char *sqlite3StrDup(const char *z){
+   char *zNew;
+   if( z==0 ) return 0;
+-  zNew = sqliteMallocRaw(strlen(z)+1);
++  zNew = sqlite3MallocRaw(strlen(z)+1);
+   if( zNew ) strcpy(zNew, z);
+   return zNew;
+ }
+ char *sqlite3StrNDup(const char *z, int n){
+   char *zNew;
+   if( z==0 ) return 0;
+-  zNew = sqliteMallocRaw(n+1);
++  zNew = sqlite3MallocRaw(n+1);
+   if( zNew ){
+     memcpy(zNew, z, n);
+     zNew[n] = 0;
+   }
+   return zNew;
+ }
+-#endif /* !defined(SQLITE_MEMDEBUG) */
+ 
+ /*
+-** Reallocate a buffer to a different size.  This is similar to
+-** sqliteRealloc() except that if the allocation fails the buffer
+-** is freed.
+-*/
+-void sqlite3ReallocOrFree(void **ppBuf, int newSize){
+-  void *pNew = sqliteRealloc(*ppBuf, newSize);
+-  if( pNew==0 ){
+-    sqliteFree(*ppBuf);
+-  }
+-  *ppBuf = pNew;
+-}
+-
+-/*
+ ** Create a string from the 2nd and subsequent arguments (up to the
+ ** first NULL argument), store the string in memory obtained from
+ ** sqliteMalloc() and make the pointer indicated by the 1st argument
+@@ -411,11 +736,6 @@
+     zResult += strlen(zResult);
+   }
+   va_end(ap);
+-#ifdef SQLITE_MEMDEBUG
+-#if SQLITE_MEMDEBUG>1
+-  fprintf(stderr,"string at 0x%x is %s\n", (int)*pz, *pz);
+-#endif
+-#endif
+ }
+ 
+ /*
+@@ -440,7 +760,7 @@
+ ** to NULL.
+ */
+ void sqlite3Error(sqlite3 *db, int err_code, const char *zFormat, ...){
+-  if( db && (db->pErr || (db->pErr = sqlite3ValueNew())) ){
++  if( db && (db->pErr || (db->pErr = sqlite3ValueNew())!=0) ){
+     db->errCode = err_code;
+     if( zFormat ){
+       char *z;
+@@ -482,6 +802,15 @@
+ }
+ 
+ /*
++** Clear the error message in pParse, if any
++*/
++void sqlite3ErrorClear(Parse *pParse){
++  sqliteFree(pParse->zErrMsg);
++  pParse->zErrMsg = 0;
++  pParse->nErr = 0;
++}
++
++/*
+ ** Convert an SQL-style quoted string into a normal string by removing
+ ** the quote characters.  The conversion is done in-place.  If the
+ ** input does not begin with a quote character, then this routine
+@@ -606,6 +935,7 @@
+ ** for SQL.  So this routine always uses "." regardless of locale.
+ */
+ int sqlite3AtoF(const char *z, double *pResult){
++#ifndef SQLITE_OMIT_FLOATING_POINT
+   int sign = 1;
+   const char *zBegin = z;
+   LONGDOUBLE_TYPE v1 = 0.0;
+@@ -656,6 +986,9 @@
+   }
+   *pResult = sign<0 ? -v1 : v1;
+   return z - zBegin;
++#else
++  return sqlite3atoi64(z, pResult);
++#endif /* SQLITE_OMIT_FLOATING_POINT */
+ }
+ 
+ /*
+@@ -1003,3 +1336,95 @@
+   return p;
+ }
+ #endif
++
++/*
++** Return a pointer to the ThreadData associated with the calling thread.
++*/
++ThreadData *sqlite3ThreadData(){
++  ThreadData *p = (ThreadData*)sqlite3OsThreadSpecificData(1);
++  if( !p ){
++    sqlite3FailedMalloc();
++  }
++  return p;
++}
++
++/*
++** Return a pointer to the ThreadData associated with the calling thread.
++** If no ThreadData has been allocated to this thread yet, return a pointer
++** to a substitute ThreadData structure that is all zeros. 
++*/
++const ThreadData *sqlite3ThreadDataReadOnly(){
++  static const ThreadData zeroData = {0};  /* Initializer to silence warnings
++                                           ** from broken compilers */
++  const ThreadData *pTd = sqlite3OsThreadSpecificData(0);
++  return pTd ? pTd : &zeroData;
++}
++
++/*
++** Check to see if the ThreadData for this thread is all zero.  If it
++** is, then deallocate it. 
++*/
++void sqlite3ReleaseThreadData(){
++  sqlite3OsThreadSpecificData(-1);
++}
++
++/*
++** This function must be called before exiting any API function (i.e. 
++** returning control to the user) that has called sqlite3Malloc or
++** sqlite3Realloc.
++**
++** The returned value is normally a copy of the second argument to this
++** function. However, if a malloc() failure has occured since the previous
++** invocation SQLITE_NOMEM is returned instead. 
++**
++** If the first argument, db, is not NULL and a malloc() error has occured,
++** then the connection error-code (the value returned by sqlite3_errcode())
++** is set to SQLITE_NOMEM.
++*/
++static int mallocHasFailed = 0;
++int sqlite3ApiExit(sqlite3* db, int rc){
++  if( sqlite3MallocFailed() ){
++    mallocHasFailed = 0;
++    sqlite3OsLeaveMutex();
++    sqlite3Error(db, SQLITE_NOMEM, 0);
++    rc = SQLITE_NOMEM;
++  }
++  return rc;
++}
++
++/* 
++** Return true is a malloc has failed in this thread since the last call
++** to sqlite3ApiExit(), or false otherwise.
++*/
++int sqlite3MallocFailed(){
++  return (mallocHasFailed && sqlite3OsInMutex(1));
++}
++
++/* 
++** Set the "malloc has failed" condition to true for this thread.
++*/
++void sqlite3FailedMalloc(){
++  sqlite3OsEnterMutex();
++  assert( mallocHasFailed==0 );
++  mallocHasFailed = 1;
++}
++
++#ifdef SQLITE_MEMDEBUG
++/*
++** This function sets a flag in the thread-specific-data structure that will
++** cause an assert to fail if sqliteMalloc() or sqliteRealloc() is called.
++*/
++void sqlite3MallocDisallow(){
++  assert( sqlite3_mallocDisallowed>=0 );
++  sqlite3_mallocDisallowed++;
++}
++
++/*
++** This function clears the flag set in the thread-specific-data structure set
++** by sqlite3MallocDisallow().
++*/
++void sqlite3MallocAllow(){
++  assert( sqlite3_mallocDisallowed>0 );
++  sqlite3_mallocDisallowed--;
++}
++#endif
+Index: sqlite/select.c
+===================================================================
+--- amarok/src/sqlite/select.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/select.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -18,6 +18,23 @@
+ 
+ 
+ /*
++** Delete all the content of a Select structure but do not deallocate
++** the select structure itself.
++*/
++static void clearSelect(Select *p){
++  sqlite3ExprListDelete(p->pEList);
++  sqlite3SrcListDelete(p->pSrc);
++  sqlite3ExprDelete(p->pWhere);
++  sqlite3ExprListDelete(p->pGroupBy);
++  sqlite3ExprDelete(p->pHaving);
++  sqlite3ExprListDelete(p->pOrderBy);
++  sqlite3SelectDelete(p->pPrior);
++  sqlite3ExprDelete(p->pLimit);
++  sqlite3ExprDelete(p->pOffset);
++}
++
++
++/*
+ ** Allocate a new Select structure and return a pointer to that
+ ** structure.
+ */
+@@ -33,41 +50,49 @@
+   Expr *pOffset         /* OFFSET value.  NULL means no offset */
+ ){
+   Select *pNew;
++  Select standin;
+   pNew = sqliteMalloc( sizeof(*pNew) );
+   assert( !pOffset || pLimit );   /* Can't have OFFSET without LIMIT. */
+   if( pNew==0 ){
+-    sqlite3ExprListDelete(pEList);
+-    sqlite3SrcListDelete(pSrc);
+-    sqlite3ExprDelete(pWhere);
+-    sqlite3ExprListDelete(pGroupBy);
+-    sqlite3ExprDelete(pHaving);
+-    sqlite3ExprListDelete(pOrderBy);
+-    sqlite3ExprDelete(pLimit);
+-    sqlite3ExprDelete(pOffset);
+-  }else{
+-    if( pEList==0 ){
+-      pEList = sqlite3ExprListAppend(0, sqlite3Expr(TK_ALL,0,0,0), 0);
+-    }
+-    pNew->pEList = pEList;
+-    pNew->pSrc = pSrc;
+-    pNew->pWhere = pWhere;
+-    pNew->pGroupBy = pGroupBy;
+-    pNew->pHaving = pHaving;
+-    pNew->pOrderBy = pOrderBy;
+-    pNew->isDistinct = isDistinct;
+-    pNew->op = TK_SELECT;
+-    pNew->pLimit = pLimit;
+-    pNew->pOffset = pOffset;
+-    pNew->iLimit = -1;
+-    pNew->iOffset = -1;
+-    pNew->addrOpenVirt[0] = -1;
+-    pNew->addrOpenVirt[1] = -1;
+-    pNew->addrOpenVirt[2] = -1;
++    pNew = &standin;
++    memset(pNew, 0, sizeof(*pNew));
+   }
++  if( pEList==0 ){
++    pEList = sqlite3ExprListAppend(0, sqlite3Expr(TK_ALL,0,0,0), 0);
++  }
++  pNew->pEList = pEList;
++  pNew->pSrc = pSrc;
++  pNew->pWhere = pWhere;
++  pNew->pGroupBy = pGroupBy;
++  pNew->pHaving = pHaving;
++  pNew->pOrderBy = pOrderBy;
++  pNew->isDistinct = isDistinct;
++  pNew->op = TK_SELECT;
++  pNew->pLimit = pLimit;
++  pNew->pOffset = pOffset;
++  pNew->iLimit = -1;
++  pNew->iOffset = -1;
++  pNew->addrOpenVirt[0] = -1;
++  pNew->addrOpenVirt[1] = -1;
++  pNew->addrOpenVirt[2] = -1;
++  if( pNew==&standin) {
++    clearSelect(pNew);
++    pNew = 0;
++  }
+   return pNew;
+ }
+ 
+ /*
++** Delete the given Select structure and all of its substructures.
++*/
++void sqlite3SelectDelete(Select *p){
++  if( p ){
++    clearSelect(p);
++    sqliteFree(p);
++  }
++}
++
++/*
+ ** Given 1 to 3 identifiers preceeding the JOIN keyword, determine the
+ ** type of join.  Return an integer constant that expresses that type
+ ** in terms of the following bit values:
+@@ -109,7 +134,7 @@
+     p = apAll[i];
+     for(j=0; j<sizeof(keywords)/sizeof(keywords[0]); j++){
+       if( p->n==keywords[j].nChar 
+-          && sqlite3StrNICmp(p->z, keywords[j].zKeyword, p->n)==0 ){
++          && sqlite3StrNICmp((char*)p->z, keywords[j].zKeyword, p->n)==0 ){
+         jointype |= keywords[j].code;
+         break;
+       }
+@@ -154,8 +179,8 @@
+ ** Set the value of a token to a '\000'-terminated string.
+ */
+ static void setToken(Token *p, const char *z){
+-  p->z = z;
+-  p->n = strlen(z);
++  p->z = (u8*)z;
++  p->n = z ? strlen(z) : 0;
+   p->dyn = 0;
+ }
+ 
+@@ -331,59 +356,53 @@
+ }
+ 
+ /*
+-** Delete the given Select structure and all of its substructures.
+-*/
+-void sqlite3SelectDelete(Select *p){
+-  if( p==0 ) return;
+-  sqlite3ExprListDelete(p->pEList);
+-  sqlite3SrcListDelete(p->pSrc);
+-  sqlite3ExprDelete(p->pWhere);
+-  sqlite3ExprListDelete(p->pGroupBy);
+-  sqlite3ExprDelete(p->pHaving);
+-  sqlite3ExprListDelete(p->pOrderBy);
+-  sqlite3SelectDelete(p->pPrior);
+-  sqlite3ExprDelete(p->pLimit);
+-  sqlite3ExprDelete(p->pOffset);
+-  sqliteFree(p);
+-}
+-
+-/*
+ ** Insert code into "v" that will push the record on the top of the
+ ** stack into the sorter.
+ */
+-static void pushOntoSorter(Parse *pParse, Vdbe *v, ExprList *pOrderBy){
++static void pushOntoSorter(
++  Parse *pParse,         /* Parser context */
++  ExprList *pOrderBy,    /* The ORDER BY clause */
++  Select *pSelect        /* The whole SELECT statement */
++){
++  Vdbe *v = pParse->pVdbe;
+   sqlite3ExprCodeExprList(pParse, pOrderBy);
+   sqlite3VdbeAddOp(v, OP_Sequence, pOrderBy->iECursor, 0);
+   sqlite3VdbeAddOp(v, OP_Pull, pOrderBy->nExpr + 1, 0);
+   sqlite3VdbeAddOp(v, OP_MakeRecord, pOrderBy->nExpr + 2, 0);
+   sqlite3VdbeAddOp(v, OP_IdxInsert, pOrderBy->iECursor, 0);
++  if( pSelect->iLimit>=0 ){
++    int addr1, addr2;
++    addr1 = sqlite3VdbeAddOp(v, OP_IfMemZero, pSelect->iLimit+1, 0);
++    sqlite3VdbeAddOp(v, OP_MemIncr, -1, pSelect->iLimit+1);
++    addr2 = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
++    sqlite3VdbeJumpHere(v, addr1);
++    sqlite3VdbeAddOp(v, OP_Last, pOrderBy->iECursor, 0);
++    sqlite3VdbeAddOp(v, OP_Delete, pOrderBy->iECursor, 0);
++    sqlite3VdbeJumpHere(v, addr2);
++    pSelect->iLimit = -1;
++  }
+ }
+ 
+ /*
+-** Add code to implement the OFFSET and LIMIT
++** Add code to implement the OFFSET
+ */
+-static void codeLimiter(
++static void codeOffset(
+   Vdbe *v,          /* Generate code into this VM */
+   Select *p,        /* The SELECT statement being coded */
+   int iContinue,    /* Jump here to skip the current record */
+-  int iBreak,       /* Jump here to end the loop */
+   int nPop          /* Number of times to pop stack when jumping */
+ ){
+   if( p->iOffset>=0 && iContinue!=0 ){
+-    int addr = sqlite3VdbeCurrentAddr(v) + 3;
+-    if( nPop>0 ) addr++;
+-    sqlite3VdbeAddOp(v, OP_MemIncr, p->iOffset, 0);
+-    sqlite3VdbeAddOp(v, OP_IfMemPos, p->iOffset, addr);
++    int addr;
++    sqlite3VdbeAddOp(v, OP_MemIncr, -1, p->iOffset);
++    addr = sqlite3VdbeAddOp(v, OP_IfMemNeg, p->iOffset, 0);
+     if( nPop>0 ){
+       sqlite3VdbeAddOp(v, OP_Pop, nPop, 0);
+     }
+     sqlite3VdbeAddOp(v, OP_Goto, 0, iContinue);
+     VdbeComment((v, "# skip OFFSET records"));
++    sqlite3VdbeJumpHere(v, addr);
+   }
+-  if( p->iLimit>=0 && iBreak!=0 ){
+-    sqlite3VdbeAddOp(v, OP_MemIncr, p->iLimit, iBreak);
+-    VdbeComment((v, "# exit when LIMIT reached"));
+-  }
+ }
+ 
+ /*
+@@ -447,9 +466,9 @@
+   /* If there was a LIMIT clause on the SELECT statement, then do the check
+   ** to see if this row should be output.
+   */
+-  hasDistinct = distinct>=0 && pEList && pEList->nExpr>0;
++  hasDistinct = distinct>=0 && pEList->nExpr>0;
+   if( pOrderBy==0 && !hasDistinct ){
+-    codeLimiter(v, p, iContinue, iBreak, 0);
++    codeOffset(v, p, iContinue, 0);
+   }
+ 
+   /* Pull the requested columns.
+@@ -471,7 +490,7 @@
+     int n = pEList->nExpr;
+     codeDistinct(v, distinct, iContinue, n, n+1);
+     if( pOrderBy==0 ){
+-      codeLimiter(v, p, iContinue, iBreak, nColumn);
++      codeOffset(v, p, iContinue, nColumn);
+     }
+   }
+ 
+@@ -509,7 +528,7 @@
+     case SRT_VirtualTab: {
+       sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
+       if( pOrderBy ){
+-        pushOntoSorter(pParse, v, pOrderBy);
++        pushOntoSorter(pParse, pOrderBy, p);
+       }else{
+         sqlite3VdbeAddOp(v, OP_NewRowid, iParm, 0);
+         sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
+@@ -536,29 +555,37 @@
+         ** ORDER BY in this case since the order of entries in the set
+         ** does not matter.  But there might be a LIMIT clause, in which
+         ** case the order does matter */
+-        pushOntoSorter(pParse, v, pOrderBy);
++        pushOntoSorter(pParse, pOrderBy, p);
+       }else{
+-        char aff = (iParm>>16)&0xFF;
+-        aff = sqlite3CompareAffinity(pEList->a[0].pExpr, aff);
+-        sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &aff, 1);
++        char affinity = (iParm>>16)&0xFF;
++        affinity = sqlite3CompareAffinity(pEList->a[0].pExpr, affinity);
++        sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &affinity, 1);
+         sqlite3VdbeAddOp(v, OP_IdxInsert, (iParm&0x0000FFFF), 0);
+       }
+       sqlite3VdbeJumpHere(v, addr2);
+       break;
+     }
+ 
++    /* If any row exist in the result set, record that fact and abort.
++    */
++    case SRT_Exists: {
++      sqlite3VdbeAddOp(v, OP_MemInt, 1, iParm);
++      sqlite3VdbeAddOp(v, OP_Pop, nColumn, 0);
++      /* The LIMIT clause will terminate the loop for us */
++      break;
++    }
++
+     /* If this is a scalar select that is part of an expression, then
+     ** store the results in the appropriate memory cell and break out
+     ** of the scan loop.
+     */
+-    case SRT_Exists:
+     case SRT_Mem: {
+       assert( nColumn==1 );
+       if( pOrderBy ){
+-        pushOntoSorter(pParse, v, pOrderBy);
++        pushOntoSorter(pParse, pOrderBy, p);
+       }else{
+         sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1);
+-        sqlite3VdbeAddOp(v, OP_Goto, 0, iBreak);
++        /* The LIMIT clause will jump out of the loop for us */
+       }
+       break;
+     }
+@@ -572,7 +599,7 @@
+     case SRT_Callback: {
+       if( pOrderBy ){
+         sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
+-        pushOntoSorter(pParse, v, pOrderBy);
++        pushOntoSorter(pParse, pOrderBy, p);
+       }else if( eDest==SRT_Subroutine ){
+         sqlite3VdbeAddOp(v, OP_Gosub, 0, iParm);
+       }else{
+@@ -594,6 +621,13 @@
+     }
+ #endif
+   }
++
++  /* Jump to the end of the loop if the LIMIT is reached.
++  */
++  if( p->iLimit>=0 && pOrderBy==0 ){
++    sqlite3VdbeAddOp(v, OP_MemIncr, -1, p->iLimit);
++    sqlite3VdbeAddOp(v, OP_IfMemZero, p->iLimit, iBreak);
++  }
+   return 0;
+ }
+ 
+@@ -622,9 +656,9 @@
+   nExpr = pList->nExpr;
+   pInfo = sqliteMalloc( sizeof(*pInfo) + nExpr*(sizeof(CollSeq*)+1) );
+   if( pInfo ){
+-    pInfo->aSortOrder = (char*)&pInfo->aColl[nExpr];
++    pInfo->aSortOrder = (u8*)&pInfo->aColl[nExpr];
+     pInfo->nField = nExpr;
+-    pInfo->enc = db->enc;
++    pInfo->enc = ENC(db);
+     for(i=0, pItem=pList->a; i<nExpr; i++, pItem++){
+       CollSeq *pColl;
+       pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
+@@ -661,7 +695,7 @@
+ 
+   iTab = pOrderBy->iECursor;
+   addr = 1 + sqlite3VdbeAddOp(v, OP_Sort, iTab, brk);
+-  codeLimiter(v, p, cont, brk, 0);
++  codeOffset(v, p, cont, 0);
+   sqlite3VdbeAddOp(v, OP_Column, iTab, pOrderBy->nExpr + 1);
+   switch( eDest ){
+     case SRT_Table:
+@@ -677,15 +711,14 @@
+       sqlite3VdbeAddOp(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3);
+       sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
+       sqlite3VdbeAddOp(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+3);
+-      sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, "n", P3_STATIC);
++      sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, "c", P3_STATIC);
+       sqlite3VdbeAddOp(v, OP_IdxInsert, (iParm&0x0000FFFF), 0);
+       break;
+     }
+-    case SRT_Exists:
+     case SRT_Mem: {
+       assert( nColumn==1 );
+       sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1);
+-      sqlite3VdbeAddOp(v, OP_Goto, 0, brk);
++      /* The LIMIT clause will terminate the loop for us */
+       break;
+     }
+ #endif
+@@ -710,6 +743,16 @@
+       break;
+     }
+   }
++
++  /* Jump to the end of the loop when the LIMIT is reached
++  */
++  if( p->iLimit>=0 ){
++    sqlite3VdbeAddOp(v, OP_MemIncr, -1, p->iLimit);
++    sqlite3VdbeAddOp(v, OP_IfMemZero, p->iLimit, brk);
++  }
++
++  /* The bottom of the loop
++  */
+   sqlite3VdbeResolveLabel(v, cont);
+   sqlite3VdbeAddOp(v, OP_Next, iTab, addr);
+   sqlite3VdbeResolveLabel(v, brk);
+@@ -719,14 +762,31 @@
+ ** Return a pointer to a string containing the 'declaration type' of the
+ ** expression pExpr. The string may be treated as static by the caller.
+ **
+-** If the declaration type is the exact datatype definition extracted from
+-** the original CREATE TABLE statement if the expression is a column.
++** The declaration type is the exact datatype definition extracted from the
++** original CREATE TABLE statement if the expression is a column. The
++** declaration type for a ROWID field is INTEGER. Exactly when an expression
++** is considered a column can be complex in the presence of subqueries. The
++** result-set expression in all of the following SELECT statements is 
++** considered a column by this function.
++**
++**   SELECT col FROM tbl;
++**   SELECT (SELECT col FROM tbl;
++**   SELECT (SELECT col FROM tbl);
++**   SELECT abc FROM (SELECT col AS abc FROM tbl);
+ ** 
+-** The declaration type for an expression is either TEXT, NUMERIC or ANY.
+-** The declaration type for a ROWID field is INTEGER.
++** The declaration type for any expression other than a column is NULL.
+ */
+-static const char *columnType(NameContext *pNC, Expr *pExpr){
+-  char const *zType;
++static const char *columnType(
++  NameContext *pNC, 
++  Expr *pExpr,
++  const char **pzOriginDb,
++  const char **pzOriginTab,
++  const char **pzOriginCol
++){
++  char const *zType = 0;
++  char const *zOriginDb = 0;
++  char const *zOriginTab = 0;
++  char const *zOriginCol = 0;
+   int j;
+   if( pExpr==0 || pNC->pSrcList==0 ) return 0;
+ 
+@@ -738,17 +798,24 @@
+ 
+   switch( pExpr->op ){
+     case TK_COLUMN: {
+-      Table *pTab = 0;
+-      int iCol = pExpr->iColumn;
++      /* The expression is a column. Locate the table the column is being
++      ** extracted from in NameContext.pSrcList. This table may be real
++      ** database table or a subquery.
++      */
++      Table *pTab = 0;            /* Table structure column is extracted from */
++      Select *pS = 0;             /* Select the column is extracted from */
++      int iCol = pExpr->iColumn;  /* Index of column in pTab */
+       while( pNC && !pTab ){
+         SrcList *pTabList = pNC->pSrcList;
+         for(j=0;j<pTabList->nSrc && pTabList->a[j].iCursor!=pExpr->iTable;j++);
+         if( j<pTabList->nSrc ){
+           pTab = pTabList->a[j].pTab;
++          pS = pTabList->a[j].pSelect;
+         }else{
+           pNC = pNC->pNext;
+         }
+       }
++
+       if( pTab==0 ){
+         /* FIX ME:
+         ** This can occurs if you have something like "SELECT new.x;" inside
+@@ -763,30 +830,72 @@
+         zType = "TEXT";
+         break;
+       }
++
+       assert( pTab );
+-      if( iCol<0 ) iCol = pTab->iPKey;
+-      assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
+-      if( iCol<0 ){
+-        zType = "INTEGER";
+-      }else{
+-        zType = pTab->aCol[iCol].zType;
++#ifndef SQLITE_OMIT_SUBQUERY
++      if( pS ){
++        /* The "table" is actually a sub-select or a view in the FROM clause
++        ** of the SELECT statement. Return the declaration type and origin
++        ** data for the result-set column of the sub-select.
++        */
++        if( iCol>=0 && iCol<pS->pEList->nExpr ){
++          /* If iCol is less than zero, then the expression requests the
++          ** rowid of the sub-select or view. This expression is legal (see 
++          ** test case misc2.2.2) - it always evaluates to NULL.
++          */
++          NameContext sNC;
++          Expr *p = pS->pEList->a[iCol].pExpr;
++          sNC.pSrcList = pS->pSrc;
++          sNC.pNext = 0;
++          sNC.pParse = pNC->pParse;
++          zType = columnType(&sNC, p, &zOriginDb, &zOriginTab, &zOriginCol); 
++        }
++      }else
++#endif
++      if( pTab->pSchema ){
++        /* A real table */
++        assert( !pS );
++        if( iCol<0 ) iCol = pTab->iPKey;
++        assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
++        if( iCol<0 ){
++          zType = "INTEGER";
++          zOriginCol = "rowid";
++        }else{
++          zType = pTab->aCol[iCol].zType;
++          zOriginCol = pTab->aCol[iCol].zName;
++        }
++        zOriginTab = pTab->zName;
++        if( pNC->pParse ){
++          int iDb = sqlite3SchemaToIndex(pNC->pParse->db, pTab->pSchema);
++          zOriginDb = pNC->pParse->db->aDb[iDb].zName;
++        }
+       }
+       break;
+     }
+ #ifndef SQLITE_OMIT_SUBQUERY
+     case TK_SELECT: {
++      /* The expression is a sub-select. Return the declaration type and
++      ** origin info for the single column in the result set of the SELECT
++      ** statement.
++      */
+       NameContext sNC;
+       Select *pS = pExpr->pSelect;
+-      sNC.pSrcList = pExpr->pSelect->pSrc;
++      Expr *p = pS->pEList->a[0].pExpr;
++      sNC.pSrcList = pS->pSrc;
+       sNC.pNext = pNC;
+-      zType = columnType(&sNC, pS->pEList->a[0].pExpr); 
++      sNC.pParse = pNC->pParse;
++      zType = columnType(&sNC, p, &zOriginDb, &zOriginTab, &zOriginCol); 
+       break;
+     }
+ #endif
+-    default:
+-      zType = 0;
+   }
+   
++  if( pzOriginDb ){
++    assert( pzOriginTab && pzOriginCol );
++    *pzOriginDb = zOriginDb;
++    *pzOriginTab = zOriginTab;
++    *pzOriginCol = zOriginCol;
++  }
+   return zType;
+ }
+ 
+@@ -803,14 +912,22 @@
+   int i;
+   NameContext sNC;
+   sNC.pSrcList = pTabList;
++  sNC.pParse = pParse;
+   for(i=0; i<pEList->nExpr; i++){
+     Expr *p = pEList->a[i].pExpr;
+-    const char *zType = columnType(&sNC, p);
+-    if( zType==0 ) continue;
+-    /* The vdbe must make it's own copy of the column-type, in case the 
+-    ** schema is reset before this virtual machine is deleted.
++    const char *zOrigDb = 0;
++    const char *zOrigTab = 0;
++    const char *zOrigCol = 0;
++    const char *zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol);
++
++    /* The vdbe must make it's own copy of the column-type and other 
++    ** column specific strings, in case the schema is reset before this
++    ** virtual machine is deleted.
+     */
+-    sqlite3VdbeSetColName(v, i+pEList->nExpr, zType, strlen(zType));
++    sqlite3VdbeSetColName(v, i, COLNAME_DECLTYPE, zType, P3_TRANSIENT);
++    sqlite3VdbeSetColName(v, i, COLNAME_DATABASE, zOrigDb, P3_TRANSIENT);
++    sqlite3VdbeSetColName(v, i, COLNAME_TABLE, zOrigTab, P3_TRANSIENT);
++    sqlite3VdbeSetColName(v, i, COLNAME_COLUMN, zOrigCol, P3_TRANSIENT);
+   }
+ }
+ 
+@@ -837,7 +954,7 @@
+ #endif
+ 
+   assert( v!=0 );
+-  if( pParse->colNamesSet || v==0 || sqlite3_malloc_failed ) return;
++  if( pParse->colNamesSet || v==0 || sqlite3MallocFailed() ) return;
+   pParse->colNamesSet = 1;
+   fullNames = (db->flags & SQLITE_FullColNames)!=0;
+   shortNames = (db->flags & SQLITE_ShortColNames)!=0;
+@@ -848,7 +965,7 @@
+     if( p==0 ) continue;
+     if( pEList->a[i].zName ){
+       char *zName = pEList->a[i].zName;
+-      sqlite3VdbeSetColName(v, i, zName, strlen(zName));
++      sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, strlen(zName));
+       continue;
+     }
+     if( p->op==TK_COLUMN && pTabList ){
+@@ -866,26 +983,26 @@
+         zCol = pTab->aCol[iCol].zName;
+       }
+       if( !shortNames && !fullNames && p->span.z && p->span.z[0] ){
+-        sqlite3VdbeSetColName(v, i, p->span.z, p->span.n);
++        sqlite3VdbeSetColName(v, i, COLNAME_NAME, (char*)p->span.z, p->span.n);
+       }else if( fullNames || (!shortNames && pTabList->nSrc>1) ){
+         char *zName = 0;
+         char *zTab;
+  
+         zTab = pTabList->a[j].zAlias;
+         if( fullNames || zTab==0 ) zTab = pTab->zName;
+-        sqlite3SetString(&zName, zTab, ".", zCol, 0);
+-        sqlite3VdbeSetColName(v, i, zName, P3_DYNAMIC);
++        sqlite3SetString(&zName, zTab, ".", zCol, (char*)0);
++        sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, P3_DYNAMIC);
+       }else{
+-        sqlite3VdbeSetColName(v, i, zCol, strlen(zCol));
++        sqlite3VdbeSetColName(v, i, COLNAME_NAME, zCol, strlen(zCol));
+       }
+     }else if( p->span.z && p->span.z[0] ){
+-      sqlite3VdbeSetColName(v, i, p->span.z, p->span.n);
++      sqlite3VdbeSetColName(v, i, COLNAME_NAME, (char*)p->span.z, p->span.n);
+       /* sqlite3VdbeCompressSpace(v, addr); */
+     }else{
+       char zName[30];
+       assert( p->op!=TK_COLUMN || pTabList==0 );
+       sprintf(zName, "column%d", i+1);
+-      sqlite3VdbeSetColName(v, i, zName, 0);
++      sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, 0);
+     }
+   }
+   generateColumnTypes(pParse, pTabList, pEList);
+@@ -943,6 +1060,7 @@
+     char *zType;
+     char *zName;
+     char *zBasename;
++    CollSeq *pColl;
+     int cnt;
+     NameContext sNC;
+     
+@@ -965,7 +1083,7 @@
+       zName = sqlite3MPrintf("column%d", i+1);
+     }
+     sqlite3Dequote(zName);
+-    if( sqlite3_malloc_failed ){
++    if( sqlite3MallocFailed() ){
+       sqliteFree(zName);
+       sqlite3DeleteTable(0, pTab);
+       return 0;
+@@ -992,12 +1110,12 @@
+     */
+     memset(&sNC, 0, sizeof(sNC));
+     sNC.pSrcList = pSelect->pSrc;
+-    zType = sqliteStrDup(columnType(&sNC, p));
++    zType = sqliteStrDup(columnType(&sNC, p, 0, 0, 0));
+     pCol->zType = zType;
+     pCol->affinity = sqlite3ExprAffinity(p);
+-    pCol->pColl = sqlite3ExprCollSeq(pParse, p);
+-    if( !pCol->pColl ){
+-      pCol->pColl = pParse->db->pDfltColl;
++    pColl = sqlite3ExprCollSeq(pParse, p);
++    if( pColl ){
++      pCol->zColl = sqliteStrDup(pColl->zName);
+     }
+   }
+   pTab->iPKey = -1;
+@@ -1034,10 +1152,11 @@
+   int i, j, k, rc;
+   SrcList *pTabList;
+   ExprList *pEList;
+-  Table *pTab;
+   struct SrcList_item *pFrom;
+ 
+-  if( p==0 || p->pSrc==0 || sqlite3_malloc_failed ) return 1;
++  if( p==0 || p->pSrc==0 || sqlite3MallocFailed() ){
++    return 1;
++  }
+   pTabList = p->pSrc;
+   pEList = p->pEList;
+ 
+@@ -1051,6 +1170,7 @@
+   ** then create a transient table structure to describe the subquery.
+   */
+   for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
++    Table *pTab;
+     if( pFrom->pTab!=0 ){
+       /* This statement has already been prepared.  There is no need
+       ** to go further. */
+@@ -1145,7 +1265,11 @@
+         /* This particular expression does not need to be expanded.
+         */
+         pNew = sqlite3ExprListAppend(pNew, a[k].pExpr, 0);
+-        pNew->a[pNew->nExpr-1].zName = a[k].zName;
++        if( pNew ){
++          pNew->a[pNew->nExpr-1].zName = a[k].zName;
++        }else{
++          rc = 1;
++        }
+         a[k].pExpr = 0;
+         a[k].zName = 0;
+       }else{
+@@ -1170,7 +1294,7 @@
+           }
+           tableSeen = 1;
+           for(j=0; j<pTab->nCol; j++){
+-            Expr *pExpr, *pLeft, *pRight;
++            Expr *pExpr, *pRight;
+             char *zName = pTab->aCol[j].zName;
+ 
+             if( i>0 ){
+@@ -1191,7 +1315,7 @@
+             if( pRight==0 ) break;
+             setToken(&pRight->token, zName);
+             if( zTabName && (longNames || pTabList->nSrc>1) ){
+-              pLeft = sqlite3Expr(TK_ID, 0, 0, 0);
++              Expr *pLeft = sqlite3Expr(TK_ID, 0, 0, 0);
+               pExpr = sqlite3Expr(TK_DOT, pLeft, pRight, 0);
+               if( pExpr==0 ) break;
+               setToken(&pLeft->token, zTabName);
+@@ -1326,25 +1450,31 @@
+   return v;
+ }
+ 
++
+ /*
+ ** Compute the iLimit and iOffset fields of the SELECT based on the
+-** pLimit and pOffset expressions.  nLimit and nOffset hold the expressions
++** pLimit and pOffset expressions.  pLimit and pOffset hold the expressions
+ ** that appear in the original SQL statement after the LIMIT and OFFSET
+ ** keywords.  Or NULL if those keywords are omitted. iLimit and iOffset 
+ ** are the integer memory register numbers for counters used to compute 
+ ** the limit and offset.  If there is no limit and/or offset, then 
+ ** iLimit and iOffset are negative.
+ **
+-** This routine changes the values if iLimit and iOffset only if
+-** a limit or offset is defined by nLimit and nOffset.  iLimit and
++** This routine changes the values of iLimit and iOffset only if
++** a limit or offset is defined by pLimit and pOffset.  iLimit and
+ ** iOffset should have been preset to appropriate default values
+ ** (usually but not always -1) prior to calling this routine.
+-** Only if nLimit>=0 or nOffset>0 do the limit registers get
++** Only if pLimit!=0 or pOffset!=0 do the limit registers get
+ ** redefined.  The UNION ALL operator uses this property to force
+ ** the reuse of the same limit and offset registers across multiple
+ ** SELECT statements.
+ */
+-static void computeLimitRegisters(Parse *pParse, Select *p){
++static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
++  Vdbe *v = 0;
++  int iLimit = 0;
++  int iOffset;
++  int addr1, addr2;
++
+   /* 
+   ** "LIMIT -1" always shows all rows.  There is some
+   ** contraversy about what the correct behavior should be.
+@@ -1352,27 +1482,42 @@
+   ** no rows.
+   */
+   if( p->pLimit ){
+-    int iMem = pParse->nMem++;
+-    Vdbe *v = sqlite3GetVdbe(pParse);
++    p->iLimit = iLimit = pParse->nMem;
++    pParse->nMem += 2;
++    v = sqlite3GetVdbe(pParse);
+     if( v==0 ) return;
+     sqlite3ExprCode(pParse, p->pLimit);
+     sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0);
+-    sqlite3VdbeAddOp(v, OP_Negative, 0, 0);
+-    sqlite3VdbeAddOp(v, OP_MemStore, iMem, 1);
++    sqlite3VdbeAddOp(v, OP_MemStore, iLimit, 0);
+     VdbeComment((v, "# LIMIT counter"));
+-    p->iLimit = iMem;
++    sqlite3VdbeAddOp(v, OP_IfMemZero, iLimit, iBreak);
+   }
+   if( p->pOffset ){
+-    int iMem = pParse->nMem++;
+-    Vdbe *v = sqlite3GetVdbe(pParse);
++    p->iOffset = iOffset = pParse->nMem++;
++    v = sqlite3GetVdbe(pParse);
+     if( v==0 ) return;
+     sqlite3ExprCode(pParse, p->pOffset);
+     sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0);
+-    sqlite3VdbeAddOp(v, OP_Negative, 0, 0);
+-    sqlite3VdbeAddOp(v, OP_MemStore, iMem, 1);
++    sqlite3VdbeAddOp(v, OP_MemStore, iOffset, p->pLimit==0);
+     VdbeComment((v, "# OFFSET counter"));
+-    p->iOffset = iMem;
++    addr1 = sqlite3VdbeAddOp(v, OP_IfMemPos, iOffset, 0);
++    sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
++    sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
++    sqlite3VdbeJumpHere(v, addr1);
++    if( p->pLimit ){
++      sqlite3VdbeAddOp(v, OP_Add, 0, 0);
++    }
+   }
++  if( p->pLimit ){
++    addr1 = sqlite3VdbeAddOp(v, OP_IfMemPos, iLimit, 0);
++    sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
++    sqlite3VdbeAddOp(v, OP_MemInt, -1, iLimit+1);
++    addr2 = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
++    sqlite3VdbeJumpHere(v, addr1);
++    sqlite3VdbeAddOp(v, OP_MemStore, iLimit+1, 1);
++    VdbeComment((v, "# LIMIT+OFFSET"));
++    sqlite3VdbeJumpHere(v, addr2);
++  }
+ }
+ 
+ /*
+@@ -1519,23 +1664,31 @@
+   switch( p->op ){
+     case TK_ALL: {
+       if( pOrderBy==0 ){
++        int addr = 0;
+         assert( !pPrior->pLimit );
+         pPrior->pLimit = p->pLimit;
+         pPrior->pOffset = p->pOffset;
+         rc = sqlite3Select(pParse, pPrior, eDest, iParm, 0, 0, 0, aff);
++        p->pLimit = 0;
++        p->pOffset = 0;
+         if( rc ){
+           goto multi_select_end;
+         }
+         p->pPrior = 0;
+         p->iLimit = pPrior->iLimit;
+         p->iOffset = pPrior->iOffset;
+-        p->pLimit = 0;
+-        p->pOffset = 0;
++        if( p->iLimit>=0 ){
++          addr = sqlite3VdbeAddOp(v, OP_IfMemZero, p->iLimit, 0);
++          VdbeComment((v, "# Jump ahead if LIMIT reached"));
++        }
+         rc = sqlite3Select(pParse, p, eDest, iParm, 0, 0, 0, aff);
+         p->pPrior = pPrior;
+         if( rc ){
+           goto multi_select_end;
+         }
++        if( addr ){
++          sqlite3VdbeJumpHere(v, addr);
++        }
+         break;
+       }
+       /* For UNION ALL ... ORDER BY fall through to the next case */
+@@ -1622,8 +1775,8 @@
+         }
+         iBreak = sqlite3VdbeMakeLabel(v);
+         iCont = sqlite3VdbeMakeLabel(v);
++        computeLimitRegisters(pParse, p, iBreak);
+         sqlite3VdbeAddOp(v, OP_Rewind, unionTab, iBreak);
+-        computeLimitRegisters(pParse, p);
+         iStart = sqlite3VdbeCurrentAddr(v);
+         rc = selectInnerLoop(pParse, p, p->pEList, unionTab, p->pEList->nExpr,
+                              pOrderBy, -1, eDest, iParm, 
+@@ -1698,8 +1851,8 @@
+       }
+       iBreak = sqlite3VdbeMakeLabel(v);
+       iCont = sqlite3VdbeMakeLabel(v);
++      computeLimitRegisters(pParse, p, iBreak);
+       sqlite3VdbeAddOp(v, OP_Rewind, tab1, iBreak);
+-      computeLimitRegisters(pParse, p);
+       iStart = sqlite3VdbeAddOp(v, OP_RowKey, tab1, 0);
+       sqlite3VdbeAddOp(v, OP_NotFound, tab2, iCont);
+       rc = selectInnerLoop(pParse, p, p->pEList, tab1, p->pEList->nExpr,
+@@ -1760,7 +1913,7 @@
+       goto multi_select_end;
+     }
+ 
+-    pKeyInfo->enc = pParse->db->enc;
++    pKeyInfo->enc = ENC(pParse->db);
+     pKeyInfo->nField = nCol;
+ 
+     for(i=0, apColl=pKeyInfo->aColl; i<nCol; i++, apColl++){
+@@ -1786,15 +1939,15 @@
+ 
+     if( pOrderBy ){
+       struct ExprList_item *pOTerm = pOrderBy->a;
+-      int nExpr = pOrderBy->nExpr;
++      int nOrderByExpr = pOrderBy->nExpr;
+       int addr;
+       u8 *pSortOrder;
+ 
+-      aCopy = (CollSeq**)&pKeyInfo[1];
+-      pSortOrder = pKeyInfo->aSortOrder = (u8*)&aCopy[nExpr];
++      aCopy = &pKeyInfo->aColl[nCol];
++      pSortOrder = pKeyInfo->aSortOrder = (u8*)&aCopy[nCol];
+       memcpy(aCopy, pKeyInfo->aColl, nCol*sizeof(CollSeq*));
+       apColl = pKeyInfo->aColl;
+-      for(i=0; i<pOrderBy->nExpr; i++, pOTerm++, apColl++, pSortOrder++){
++      for(i=0; i<nOrderByExpr; i++, pOTerm++, apColl++, pSortOrder++){
+         Expr *pExpr = pOTerm->pExpr;
+         char *zName = pOTerm->zName;
+         assert( pExpr->op==TK_COLUMN && pExpr->iColumn<nCol );
+@@ -1809,7 +1962,7 @@
+       assert( p->addrOpenVirt[2]>=0 );
+       addr = p->addrOpenVirt[2];
+       sqlite3VdbeChangeP2(v, addr, p->pEList->nExpr+2);
+-      pKeyInfo->nField = pOrderBy->nExpr;
++      pKeyInfo->nField = nOrderByExpr;
+       sqlite3VdbeChangeP3(v, addr, (char*)pKeyInfo, P3_KEYINFO_HANDOFF);
+       pKeyInfo = 0;
+       generateSortTail(pParse, p, v, p->pEList->nExpr, eDest, iParm);
+@@ -1949,6 +2102,10 @@
+ **  (12)  The subquery is not the right term of a LEFT OUTER JOIN or the
+ **        subquery has no WHERE clause.  (added by ticket #350)
+ **
++**  (13)  The subquery and outer query do not both use LIMIT
++**
++**  (14)  The subquery does not use OFFSET
++**
+ ** In this routine, the "p" parameter is a pointer to the outer query.
+ ** The subquery is p->pSrc->a[iFrom].  isAgg is true if the outer query
+ ** uses aggregates and subqueryIsAgg is true if the subquery uses aggregates.
+@@ -1983,18 +2140,26 @@
+   pSubitem = &pSrc->a[iFrom];
+   pSub = pSubitem->pSelect;
+   assert( pSub!=0 );
+-  if( isAgg && subqueryIsAgg ) return 0;
+-  if( subqueryIsAgg && pSrc->nSrc>1 ) return 0;
++  if( isAgg && subqueryIsAgg ) return 0;                 /* Restriction (1)  */
++  if( subqueryIsAgg && pSrc->nSrc>1 ) return 0;          /* Restriction (2)  */
+   pSubSrc = pSub->pSrc;
+   assert( pSubSrc );
+-  if( (pSub->pLimit && p->pLimit) || pSub->pOffset || 
+-      (pSub->pLimit && isAgg) ) return 0;
+-  if( pSubSrc->nSrc==0 ) return 0;
+-  if( pSub->isDistinct && (pSrc->nSrc>1 || isAgg) ){
+-     return 0;
++  /* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants,
++  ** not arbitrary expresssions, we allowed some combining of LIMIT and OFFSET
++  ** because they could be computed at compile-time.  But when LIMIT and OFFSET
++  ** became arbitrary expressions, we were forced to add restrictions (13)
++  ** and (14). */
++  if( pSub->pLimit && p->pLimit ) return 0;              /* Restriction (13) */
++  if( pSub->pOffset ) return 0;                          /* Restriction (14) */
++  if( pSubSrc->nSrc==0 ) return 0;                       /* Restriction (7)  */
++  if( (pSub->isDistinct || pSub->pLimit) 
++         && (pSrc->nSrc>1 || isAgg) ){          /* Restrictions (4)(5)(8)(9) */
++     return 0;       
+   }
+-  if( p->isDistinct && subqueryIsAgg ) return 0;
+-  if( (p->disallowOrderBy || p->pOrderBy) && pSub->pOrderBy ) return 0;
++  if( p->isDistinct && subqueryIsAgg ) return 0;         /* Restriction (6)  */
++  if( (p->disallowOrderBy || p->pOrderBy) && pSub->pOrderBy ){
++     return 0;                                           /* Restriction (11) */
++  }
+ 
+   /* Restriction 3:  If the subquery is a join, make sure the subquery is 
+   ** not used as the right operand of an outer join.  Examples of why this
+@@ -2085,7 +2250,7 @@
+   for(i=0; i<pList->nExpr; i++){
+     Expr *pExpr;
+     if( pList->a[i].zName==0 && (pExpr = pList->a[i].pExpr)->span.z!=0 ){
+-      pList->a[i].zName = sqliteStrNDup(pExpr->span.z, pExpr->span.n);
++      pList->a[i].zName = sqliteStrNDup((char*)pExpr->span.z, pExpr->span.n);
+     }
+   }
+   if( isAgg ){
+@@ -2124,6 +2289,9 @@
+ 
+   /*
+   ** SELECT ... FROM (SELECT ... LIMIT a OFFSET b) LIMIT x OFFSET y;
++  **
++  ** One is tempted to try to add a and b to combine the limits.  But this
++  ** does not work if either limit is negative.
+   */
+   if( pSub->pLimit ){
+     p->pLimit = pSub->pLimit;
+@@ -2166,10 +2334,11 @@
+   int base;
+   Vdbe *v;
+   int seekOp;
+-  int cont;
+   ExprList *pEList, *pList, eList;
+   struct ExprList_item eListItem;
+   SrcList *pSrc;
++  int brk;
++  int iDb;
+ 
+   /* Check to see if this query is a simple min() or max() query.  Return
+   ** zero if it is  not.
+@@ -2184,9 +2353,9 @@
+   pList = pExpr->pList;
+   if( pList==0 || pList->nExpr!=1 ) return 0;
+   if( pExpr->token.n!=3 ) return 0;
+-  if( sqlite3StrNICmp(pExpr->token.z,"min",3)==0 ){
++  if( sqlite3StrNICmp((char*)pExpr->token.z,"min",3)==0 ){
+     seekOp = OP_Rewind;
+-  }else if( sqlite3StrNICmp(pExpr->token.z,"max",3)==0 ){
++  }else if( sqlite3StrNICmp((char*)pExpr->token.z,"max",3)==0 ){
+     seekOp = OP_Last;
+   }else{
+     return 0;
+@@ -2196,6 +2365,7 @@
+   iCol = pExpr->iColumn;
+   pTab = pSrc->a[0].pTab;
+ 
++
+   /* If we get to here, it means the query is of the correct form.
+   ** Check to make sure we have an index and make pIdx point to the
+   ** appropriate index.  If the min() or max() is on an INTEGER PRIMARY
+@@ -2208,7 +2378,10 @@
+     CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr);
+     for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+       assert( pIdx->nColumn>=1 );
+-      if( pIdx->aiColumn[0]==iCol && pIdx->keyInfo.aColl[0]==pColl ) break;
++      if( pIdx->aiColumn[0]==iCol && 
++          0==sqlite3StrICmp(pIdx->azColl[0], pColl->zName) ){
++        break;
++      }
+     }
+     if( pIdx==0 ) return 0;
+   }
+@@ -2231,13 +2404,16 @@
+   ** the min() or max() is on the INTEGER PRIMARY KEY, then find the first
+   ** or last entry in the main table.
+   */
+-  sqlite3CodeVerifySchema(pParse, pTab->iDb);
++  iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
++  assert( iDb>=0 || pTab->isTransient );
++  sqlite3CodeVerifySchema(pParse, iDb);
++  sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
+   base = pSrc->a[0].iCursor;
+-  computeLimitRegisters(pParse, p);
++  brk = sqlite3VdbeMakeLabel(v);
++  computeLimitRegisters(pParse, p, brk);
+   if( pSrc->a[0].pSelect==0 ){
+-    sqlite3OpenTableForReading(v, base, pTab);
++    sqlite3OpenTable(pParse, base, iDb, pTab, OP_OpenRead);
+   }
+-  cont = sqlite3VdbeMakeLabel(v);
+   if( pIdx==0 ){
+     sqlite3VdbeAddOp(v, seekOp, base, 0);
+   }else{
+@@ -2248,10 +2424,12 @@
+     ** "INSERT INTO x SELECT max() FROM x".
+     */
+     int iIdx;
++    KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
+     iIdx = pParse->nTab++;
+-    sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
+-    sqlite3VdbeOp3(v, OP_OpenRead, iIdx, pIdx->tnum,
+-                   (char*)&pIdx->keyInfo, P3_KEYINFO);
++    assert( pIdx->pSchema==pTab->pSchema );
++    sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
++    sqlite3VdbeOp3(v, OP_OpenRead, iIdx, pIdx->tnum, 
++        (char*)pKey, P3_KEYINFO_HANDOFF);
+     if( seekOp==OP_Rewind ){
+       sqlite3VdbeAddOp(v, OP_Null, 0, 0);
+       sqlite3VdbeAddOp(v, OP_MakeRecord, 1, 0);
+@@ -2266,8 +2444,8 @@
+   memset(&eListItem, 0, sizeof(eListItem));
+   eList.a = &eListItem;
+   eList.a[0].pExpr = pExpr;
+-  selectInnerLoop(pParse, p, &eList, 0, 0, 0, -1, eDest, iParm, cont, cont, 0);
+-  sqlite3VdbeResolveLabel(v, cont);
++  selectInnerLoop(pParse, p, &eList, 0, 0, 0, -1, eDest, iParm, brk, brk, 0);
++  sqlite3VdbeResolveLabel(v, brk);
+   sqlite3VdbeAddOp(v, OP_Close, base, 0);
+   
+   return 1;
+@@ -2356,14 +2534,8 @@
+   /* Resolve the expressions in the LIMIT and OFFSET clauses. These
+   ** are not allowed to refer to any names, so pass an empty NameContext.
+   */
++  memset(&sNC, 0, sizeof(sNC));
+   sNC.pParse = pParse;
+-  sNC.hasAgg = 0;
+-  sNC.nErr = 0;
+-  sNC.nRef = 0;
+-  sNC.pEList = 0;
+-  sNC.allowAgg = 0;
+-  sNC.pSrcList = 0;
+-  sNC.pNext = 0;
+   if( sqlite3ExprResolveNames(&sNC, p->pLimit) ||
+       sqlite3ExprResolveNames(&sNC, p->pOffset) ){
+     return SQLITE_ERROR;
+@@ -2615,8 +2787,11 @@
+   int rc = 1;            /* Value to return from this function */
+   int addrSortIndex;     /* Address of an OP_OpenVirtual instruction */
+   AggInfo sAggInfo;      /* Information used by aggregate queries */
++  int iEnd;              /* Address of the end of the query */
+ 
+-  if( sqlite3_malloc_failed || pParse->nErr || p==0 ) return 1;
++  if( p==0 || sqlite3MallocFailed() || pParse->nErr ){
++    return 1;
++  }
+   if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
+   memset(&sAggInfo, 0, sizeof(sAggInfo));
+ 
+@@ -2663,7 +2838,6 @@
+   /* If writing to memory or generating a set
+   ** only a single column may be output.
+   */
+-  assert( eDest!=SRT_Exists || pEList->nExpr==1 );
+ #ifndef SQLITE_OMIT_SUBQUERY
+   if( (eDest==SRT_Mem || eDest==SRT_Set) && pEList->nExpr>1 ){
+     sqlite3ErrorMsg(pParse, "only a single result allowed for "
+@@ -2683,13 +2857,6 @@
+   v = sqlite3GetVdbe(pParse);
+   if( v==0 ) goto select_end;
+ 
+-  /* Identify column names if we will be using them in a callback.  This
+-  ** step is skipped if the output is going to some other destination.
+-  */
+-  if( eDest==SRT_Callback ){
+-    generateColumnNames(pParse, pTabList, pEList);
+-  }
+-
+   /* Generate code for all sub-queries in the FROM clause
+   */
+ #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
+@@ -2698,7 +2865,7 @@
+     int needRestoreContext;
+     struct SrcList_item *pItem = &pTabList->a[i];
+ 
+-    if( pItem->pSelect==0 ) continue;
++    if( pItem->pSelect==0 || pItem->isPopulated ) continue;
+     if( pItem->zName!=0 ){
+       zSavedAuthContext = pParse->zAuthContext;
+       pParse->zAuthContext = pItem->zName;
+@@ -2772,7 +2939,8 @@
+ 
+   /* Set the limiter.
+   */
+-  computeLimitRegisters(pParse, p);
++  iEnd = sqlite3VdbeMakeLabel(v);
++  computeLimitRegisters(pParse, p, iEnd);
+ 
+   /* If the output is destined for a temporary table, open that table.
+   */
+@@ -2780,15 +2948,6 @@
+     sqlite3VdbeAddOp(v, OP_OpenVirtual, iParm, pEList->nExpr);
+   }
+ 
+-
+-  /* Initialize the memory cell to NULL for SRT_Mem or 0 for SRT_Exists
+-  */
+-  if( eDest==SRT_Mem ){
+-    sqlite3VdbeAddOp(v, OP_MemNull, iParm, 0);
+-  }else if( eDest==SRT_Exists ){
+-    sqlite3VdbeAddOp(v, OP_MemInt, 0, iParm);
+-  }
+-
+   /* Open a virtual index to use for the distinct set.
+   */
+   if( isDistinct ){
+@@ -2879,7 +3038,7 @@
+         goto select_end;
+       }
+     }
+-    if( sqlite3_malloc_failed ) goto select_end;
++    if( sqlite3MallocFailed() ) goto select_end;
+ 
+     /* Processing for aggregates with GROUP BY is very different and
+     ** much more complex tha aggregates without a GROUP BY.
+@@ -3100,18 +3259,21 @@
+ 
+ #ifndef SQLITE_OMIT_SUBQUERY
+   /* If this was a subquery, we have now converted the subquery into a
+-  ** temporary table.  So delete the subquery structure from the parent
+-  ** to prevent this subquery from being evaluated again and to force the
+-  ** the use of the temporary table.
++  ** temporary table.  So set the SrcList_item.isPopulated flag to prevent
++  ** this subquery from being evaluated again and to force the use of
++  ** the temporary table.
+   */
+   if( pParent ){
+     assert( pParent->pSrc->nSrc>parentTab );
+     assert( pParent->pSrc->a[parentTab].pSelect==p );
+-    sqlite3SelectDelete(p);
+-    pParent->pSrc->a[parentTab].pSelect = 0;
++    pParent->pSrc->a[parentTab].isPopulated = 1;
+   }
+ #endif
+ 
++  /* Jump here to skip this query
++  */
++  sqlite3VdbeResolveLabel(v, iEnd);
++
+   /* The SELECT was successfully coded.   Set the return code to 0
+   ** to indicate no errors.
+   */
+@@ -3121,6 +3283,14 @@
+   ** successful coding of the SELECT.
+   */
+ select_end:
++
++  /* Identify column names if we will be using them in a callback.  This
++  ** step is skipped if the output is going to some other destination.
++  */
++  if( rc==SQLITE_OK && eDest==SRT_Callback ){
++    generateColumnNames(pParse, pTabList, pEList);
++  }
++
+   sqliteFree(sAggInfo.aCol);
+   sqliteFree(sAggInfo.aFunc);
+   return rc;
+Index: sqlite/os.c
+===================================================================
+--- amarok/src/sqlite/os.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 0)
++++ amarok/src/sqlite/os.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -0,0 +1,92 @@
++/*
++** 2005 November 29
++**
++** The author disclaims copyright to this source code.  In place of
++** a legal notice, here is a blessing:
++**
++**    May you do good and not evil.
++**    May you find forgiveness for yourself and forgive others.
++**    May you share freely, never taking more than you give.
++**
++******************************************************************************
++**
++** This file contains OS interface code that is common to all
++** architectures.
++*/
++#define _SQLITE_OS_C_ 1
++#include "sqliteInt.h"
++#include "os.h"
++
++/*
++** The following routines are convenience wrappers around methods
++** of the OsFile object.  This is mostly just syntactic sugar.  All
++** of this would be completely automatic if SQLite were coded using
++** C++ instead of plain old C.
++*/
++int sqlite3OsClose(OsFile **pId){
++  OsFile *id;
++  if( pId!=0 && (id = *pId)!=0 ){
++    return id->pMethod->xClose(pId);
++  }else{
++    return SQLITE_OK;
++  }
++}
++int sqlite3OsOpenDirectory(OsFile *id, const char *zName){
++  return id->pMethod->xOpenDirectory(id, zName);
++}
++int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
++  return id->pMethod->xRead(id, pBuf, amt);
++}
++int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
++  return id->pMethod->xWrite(id, pBuf, amt);
++}
++int sqlite3OsSeek(OsFile *id, i64 offset){
++  return id->pMethod->xSeek(id, offset);
++}
++int sqlite3OsTruncate(OsFile *id, i64 size){
++  return id->pMethod->xTruncate(id, size);
++}
++int sqlite3OsSync(OsFile *id, int fullsync){
++  return id->pMethod->xSync(id, fullsync);
++}
++void sqlite3OsSetFullSync(OsFile *id, int value){
++  id->pMethod->xSetFullSync(id, value);
++}
++#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
++/* This method is currently only used while interactively debugging the 
++** pager. More specificly, it can only be used when sqlite3DebugPrintf() is
++** included in the build. */
++int sqlite3OsFileHandle(OsFile *id){
++  return id->pMethod->xFileHandle(id);
++}
++#endif
++int sqlite3OsFileSize(OsFile *id, i64 *pSize){
++  return id->pMethod->xFileSize(id, pSize);
++}
++int sqlite3OsLock(OsFile *id, int lockType){
++  return id->pMethod->xLock(id, lockType);
++}
++int sqlite3OsUnlock(OsFile *id, int lockType){
++  return id->pMethod->xUnlock(id, lockType);
++}
++int sqlite3OsLockState(OsFile *id){
++  return id->pMethod->xLockState(id);
++}
++int sqlite3OsCheckReservedLock(OsFile *id){
++  return id->pMethod->xCheckReservedLock(id);
++}
++
++#ifdef SQLITE_ENABLE_REDEF_IO
++/*
++** A function to return a pointer to the virtual function table.
++** This routine really does not accomplish very much since the
++** virtual function table is a global variable and anybody who
++** can call this function can just as easily access the variable
++** for themselves.  Nevertheless, we include this routine for
++** backwards compatibility with an earlier redefinable I/O
++** interface design.
++*/
++struct sqlite3OsVtbl *sqlite3_os_switch(void){
++  return &sqlite3Os;
++}
++#endif
+Index: sqlite/hash.c
+===================================================================
+--- amarok/src/sqlite/hash.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/hash.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -294,6 +294,11 @@
+   }
+   sqliteFree( elem );
+   pH->count--;
++  if( pH->count<=0 ){
++    assert( pH->first==0 );
++    assert( pH->count==0 );
++    sqlite3HashClear(pH);
++  }
+ }
+ 
+ /* Attempt to locate an element of the hash table pH with a key
+Index: sqlite/os.h
+===================================================================
+--- amarok/src/sqlite/os.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/os.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -18,12 +18,10 @@
+ #define _SQLITE_OS_H_
+ 
+ /*
+-** Figure out if we are dealing with Unix, Windows or MacOS.
+-**
+-** N.B. MacOS means Mac Classic (or Carbon). Treat Darwin (OS X) as Unix.
+-**      The MacOS build is designed to use CodeWarrior (tested with v8)
++** Figure out if we are dealing with Unix, Windows, or some other
++** operating system.
+ */
+-#if !defined(OS_UNIX) && !defined(OS_TEST) && !defined(OS_OTHER)
++#if !defined(OS_UNIX) && !defined(OS_OTHER)
+ # define OS_OTHER 0
+ # ifndef OS_WIN
+ #   if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__)
+@@ -42,27 +40,17 @@
+ # endif
+ #endif
+ 
++
+ /*
+-** Invoke the appropriate operating-system specific header file.
++** Define the maximum size of a temporary filename
+ */
+-#if OS_TEST
+-# include "os_test.h"
+-#endif
+-#if OS_UNIX
+-# include "os_unix.h"
+-#endif
+ #if OS_WIN
+-# include "os_win.h"
++# include <windows.h>
++# define SQLITE_TEMPNAME_SIZE (MAX_PATH+50)
++#else
++# define SQLITE_TEMPNAME_SIZE 200
+ #endif
+ 
+-/* os_other.c and os_other.h are not delivered with SQLite.  These files
+-** are place-holders that can be filled in by third-party developers to
+-** implement backends to their on proprietary operating systems.
+-*/
+-#if OS_OTHER
+-# include "os_other.h"
+-#endif
+-
+ /* If the SET_FULLSYNC macro is not defined above, then make it
+ ** a no-op
+ */
+@@ -84,6 +72,104 @@
+ #endif
+ 
+ /*
++** Define the interfaces for Unix and for Windows.
++*/
++#if OS_UNIX
++#define sqlite3OsOpenReadWrite      sqlite3UnixOpenReadWrite
++#define sqlite3OsOpenExclusive      sqlite3UnixOpenExclusive
++#define sqlite3OsOpenReadOnly       sqlite3UnixOpenReadOnly
++#define sqlite3OsDelete             sqlite3UnixDelete
++#define sqlite3OsFileExists         sqlite3UnixFileExists
++#define sqlite3OsFullPathname       sqlite3UnixFullPathname
++#define sqlite3OsIsDirWritable      sqlite3UnixIsDirWritable
++#define sqlite3OsSyncDirectory      sqlite3UnixSyncDirectory
++#define sqlite3OsTempFileName       sqlite3UnixTempFileName
++#define sqlite3OsRandomSeed         sqlite3UnixRandomSeed
++#define sqlite3OsSleep              sqlite3UnixSleep
++#define sqlite3OsCurrentTime        sqlite3UnixCurrentTime
++#define sqlite3OsEnterMutex         sqlite3UnixEnterMutex
++#define sqlite3OsLeaveMutex         sqlite3UnixLeaveMutex
++#define sqlite3OsInMutex            sqlite3UnixInMutex
++#define sqlite3OsThreadSpecificData sqlite3UnixThreadSpecificData
++#define sqlite3OsMalloc             sqlite3GenericMalloc
++#define sqlite3OsRealloc            sqlite3GenericRealloc
++#define sqlite3OsFree               sqlite3GenericFree
++#define sqlite3OsAllocationSize     sqlite3GenericAllocationSize
++#endif
++#if OS_WIN
++#define sqlite3OsOpenReadWrite      sqlite3WinOpenReadWrite
++#define sqlite3OsOpenExclusive      sqlite3WinOpenExclusive
++#define sqlite3OsOpenReadOnly       sqlite3WinOpenReadOnly
++#define sqlite3OsDelete             sqlite3WinDelete
++#define sqlite3OsFileExists         sqlite3WinFileExists
++#define sqlite3OsFullPathname       sqlite3WinFullPathname
++#define sqlite3OsIsDirWritable      sqlite3WinIsDirWritable
++#define sqlite3OsSyncDirectory      sqlite3WinSyncDirectory
++#define sqlite3OsTempFileName       sqlite3WinTempFileName
++#define sqlite3OsRandomSeed         sqlite3WinRandomSeed
++#define sqlite3OsSleep              sqlite3WinSleep
++#define sqlite3OsCurrentTime        sqlite3WinCurrentTime
++#define sqlite3OsEnterMutex         sqlite3WinEnterMutex
++#define sqlite3OsLeaveMutex         sqlite3WinLeaveMutex
++#define sqlite3OsInMutex            sqlite3WinInMutex
++#define sqlite3OsThreadSpecificData sqlite3WinThreadSpecificData
++#define sqlite3OsMalloc             sqlite3GenericMalloc
++#define sqlite3OsRealloc            sqlite3GenericRealloc
++#define sqlite3OsFree               sqlite3GenericFree
++#define sqlite3OsAllocationSize     sqlite3GenericAllocationSize
++#endif
++
++/*
++** If using an alternative OS interface, then we must have an "os_other.h"
++** header file available for that interface.  Presumably the "os_other.h"
++** header file contains #defines similar to those above.
++*/
++#if OS_OTHER
++# include "os_other.h"
++#endif
++
++
++
++/*
++** Forward declarations
++*/
++typedef struct OsFile OsFile;
++typedef struct IoMethod IoMethod;
++
++/*
++** An instance of the following structure contains pointers to all
++** methods on an OsFile object.
++*/
++struct IoMethod {
++  int (*xClose)(OsFile**);
++  int (*xOpenDirectory)(OsFile*, const char*);
++  int (*xRead)(OsFile*, void*, int amt);
++  int (*xWrite)(OsFile*, const void*, int amt);
++  int (*xSeek)(OsFile*, i64 offset);
++  int (*xTruncate)(OsFile*, i64 size);
++  int (*xSync)(OsFile*, int);
++  void (*xSetFullSync)(OsFile *id, int setting);
++  int (*xFileHandle)(OsFile *id);
++  int (*xFileSize)(OsFile*, i64 *pSize);
++  int (*xLock)(OsFile*, int);
++  int (*xUnlock)(OsFile*, int);
++  int (*xLockState)(OsFile *id);
++  int (*xCheckReservedLock)(OsFile *id);
++};
++
++/*
++** The OsFile object describes an open disk file in an OS-dependent way.
++** The version of OsFile defined here is a generic version.  Each OS
++** implementation defines its own subclass of this structure that contains
++** additional information needed to handle file I/O.  But the pMethod
++** entry (pointing to the virtual function table) always occurs first
++** so that we can always find the appropriate methods.
++*/
++struct OsFile {
++  IoMethod const *pMethod;
++};
++
++/*
+ ** The following values may be passed as the second argument to
+ ** sqlite3OsLock(). The various locks exhibit the following semantics:
+ **
+@@ -137,8 +223,10 @@
+ ** a random byte is selected for a shared lock.  The pool of bytes for
+ ** shared locks begins at SHARED_FIRST. 
+ **
+-** These #defines are available in os.h so that Unix can use the same
+-** byte ranges for locking.  This leaves open the possiblity of having
++** These #defines are available in sqlite_aux.h so that adaptors for
++** connecting SQLite to other operating systems can use the same byte
++** ranges for locking.  In particular, the same locking strategy and
++** byte ranges are used for Unix.  This leaves open the possiblity of having
+ ** clients on win95, winNT, and unix all talking to the same shared file
+ ** and all locking correctly.  To do so would require that samba (or whatever
+ ** tool is being used for file sharing) implements locks correctly between
+@@ -172,36 +260,181 @@
+ #define SHARED_FIRST      (PENDING_BYTE+2)
+ #define SHARED_SIZE       510
+ 
+-
+-int sqlite3OsDelete(const char*);
+-int sqlite3OsFileExists(const char*);
+-int sqlite3OsOpenReadWrite(const char*, OsFile*, int*);
+-int sqlite3OsOpenExclusive(const char*, OsFile*, int);
+-int sqlite3OsOpenReadOnly(const char*, OsFile*);
+-int sqlite3OsOpenDirectory(const char*, OsFile*);
+-int sqlite3OsSyncDirectory(const char*);
+-int sqlite3OsTempFileName(char*);
+-int sqlite3OsIsDirWritable(char*);
+-int sqlite3OsClose(OsFile*);
++/*
++** Prototypes for operating system interface routines.
++*/
++int sqlite3OsClose(OsFile**);
++int sqlite3OsOpenDirectory(OsFile*, const char*);
+ int sqlite3OsRead(OsFile*, void*, int amt);
+ int sqlite3OsWrite(OsFile*, const void*, int amt);
+ int sqlite3OsSeek(OsFile*, i64 offset);
++int sqlite3OsTruncate(OsFile*, i64 size);
+ int sqlite3OsSync(OsFile*, int);
+-int sqlite3OsTruncate(OsFile*, i64 size);
++void sqlite3OsSetFullSync(OsFile *id, int setting);
++int sqlite3OsFileHandle(OsFile *id);
+ int sqlite3OsFileSize(OsFile*, i64 *pSize);
+-char *sqlite3OsFullPathname(const char*);
+ int sqlite3OsLock(OsFile*, int);
+ int sqlite3OsUnlock(OsFile*, int);
++int sqlite3OsLockState(OsFile *id);
+ int sqlite3OsCheckReservedLock(OsFile *id);
+-
+-
+-/* The interface for file I/O is above.  Other miscellaneous functions
+-** are below */
+-
++int sqlite3OsOpenReadWrite(const char*, OsFile**, int*);
++int sqlite3OsOpenExclusive(const char*, OsFile**, int);
++int sqlite3OsOpenReadOnly(const char*, OsFile**);
++int sqlite3OsDelete(const char*);
++int sqlite3OsFileExists(const char*);
++char *sqlite3OsFullPathname(const char*);
++int sqlite3OsIsDirWritable(char*);
++int sqlite3OsSyncDirectory(const char*);
++int sqlite3OsTempFileName(char*);
+ int sqlite3OsRandomSeed(char*);
+ int sqlite3OsSleep(int ms);
+ int sqlite3OsCurrentTime(double*);
+ void sqlite3OsEnterMutex(void);
+ void sqlite3OsLeaveMutex(void);
++int sqlite3OsInMutex(int);
++ThreadData *sqlite3OsThreadSpecificData(int);
++void *sqlite3OsMalloc(int);
++void *sqlite3OsRealloc(void *, int);
++void sqlite3OsFree(void *);
++int sqlite3OsAllocationSize(void *);
+ 
++/*
++** If the SQLITE_ENABLE_REDEF_IO macro is defined, then the OS-layer
++** interface routines are not called directly but are invoked using
++** pointers to functions.  This allows the implementation of various
++** OS-layer interface routines to be modified at run-time.  There are
++** obscure but legitimate reasons for wanting to do this.  But for
++** most users, a direct call to the underlying interface is preferable
++** so the the redefinable I/O interface is turned off by default.
++*/
++#ifdef SQLITE_ENABLE_REDEF_IO
++
++/*
++** When redefinable I/O is enabled, a single global instance of the
++** following structure holds pointers to the routines that SQLite 
++** uses to talk with the underlying operating system.  Modify this
++** structure (before using any SQLite API!) to accomodate perculiar
++** operating system interfaces or behaviors.
++*/
++struct sqlite3OsVtbl {
++  int (*xOpenReadWrite)(const char*, OsFile**, int*);
++  int (*xOpenExclusive)(const char*, OsFile**, int);
++  int (*xOpenReadOnly)(const char*, OsFile**);
++
++  int (*xDelete)(const char*);
++  int (*xFileExists)(const char*);
++  char *(*xFullPathname)(const char*);
++  int (*xIsDirWritable)(char*);
++  int (*xSyncDirectory)(const char*);
++  int (*xTempFileName)(char*);
++
++  int (*xRandomSeed)(char*);
++  int (*xSleep)(int ms);
++  int (*xCurrentTime)(double*);
++
++  void (*xEnterMutex)(void);
++  void (*xLeaveMutex)(void);
++  int (*xInMutex)(int);
++  ThreadData *(*xThreadSpecificData)(int);
++
++  void *(*xMalloc)(int);
++  void *(*xRealloc)(void *, int);
++  void (*xFree)(void *);
++  int (*xAllocationSize)(void *);
++};
++
++/* Macro used to comment out routines that do not exists when there is
++** no disk I/O 
++*/
++#ifdef SQLITE_OMIT_DISKIO
++# define IF_DISKIO(X)  0
++#else
++# define IF_DISKIO(X)  X
++#endif
++
++#ifdef _SQLITE_OS_C_
++  /*
++  ** The os.c file implements the global virtual function table.
++  */
++  struct sqlite3OsVtbl sqlite3Os = {
++    IF_DISKIO( sqlite3OsOpenReadWrite ),
++    IF_DISKIO( sqlite3OsOpenExclusive ),
++    IF_DISKIO( sqlite3OsOpenReadOnly ),
++    IF_DISKIO( sqlite3OsDelete ),
++    IF_DISKIO( sqlite3OsFileExists ),
++    IF_DISKIO( sqlite3OsFullPathname ),
++    IF_DISKIO( sqlite3OsIsDirWritable ),
++    IF_DISKIO( sqlite3OsSyncDirectory ),
++    IF_DISKIO( sqlite3OsTempFileName ),
++    sqlite3OsRandomSeed,
++    sqlite3OsSleep,
++    sqlite3OsCurrentTime,
++    sqlite3OsEnterMutex,
++    sqlite3OsLeaveMutex,
++    sqlite3OsInMutex,
++    sqlite3OsThreadSpecificData,
++    sqlite3OsMalloc,
++    sqlite3OsRealloc,
++    sqlite3OsFree,
++    sqlite3OsAllocationSize
++  };
++#else
++  /*
++  ** Files other than os.c just reference the global virtual function table. 
++  */
++  extern struct sqlite3OsVtbl sqlite3Os;
++#endif /* _SQLITE_OS_C_ */
++
++
++/* This additional API routine is available with redefinable I/O */
++struct sqlite3OsVtbl *sqlite3_os_switch(void);
++
++
++/*
++** Redefine the OS interface to go through the virtual function table
++** rather than calling routines directly.
++*/
++#undef sqlite3OsOpenReadWrite
++#undef sqlite3OsOpenExclusive
++#undef sqlite3OsOpenReadOnly
++#undef sqlite3OsDelete
++#undef sqlite3OsFileExists
++#undef sqlite3OsFullPathname
++#undef sqlite3OsIsDirWritable
++#undef sqlite3OsSyncDirectory
++#undef sqlite3OsTempFileName
++#undef sqlite3OsRandomSeed
++#undef sqlite3OsSleep
++#undef sqlite3OsCurrentTime
++#undef sqlite3OsEnterMutex
++#undef sqlite3OsLeaveMutex
++#undef sqlite3OsInMutex
++#undef sqlite3OsThreadSpecificData
++#undef sqlite3OsMalloc
++#undef sqlite3OsRealloc
++#undef sqlite3OsFree
++#undef sqlite3OsAllocationSize
++#define sqlite3OsOpenReadWrite      sqlite3Os.xOpenReadWrite
++#define sqlite3OsOpenExclusive      sqlite3Os.xOpenExclusive
++#define sqlite3OsOpenReadOnly       sqlite3Os.xOpenReadOnly
++#define sqlite3OsDelete             sqlite3Os.xDelete
++#define sqlite3OsFileExists         sqlite3Os.xFileExists
++#define sqlite3OsFullPathname       sqlite3Os.xFullPathname
++#define sqlite3OsIsDirWritable      sqlite3Os.xIsDirWritable
++#define sqlite3OsSyncDirectory      sqlite3Os.xSyncDirectory
++#define sqlite3OsTempFileName       sqlite3Os.xTempFileName
++#define sqlite3OsRandomSeed         sqlite3Os.xRandomSeed
++#define sqlite3OsSleep              sqlite3Os.xSleep
++#define sqlite3OsCurrentTime        sqlite3Os.xCurrentTime
++#define sqlite3OsEnterMutex         sqlite3Os.xEnterMutex
++#define sqlite3OsLeaveMutex         sqlite3Os.xLeaveMutex
++#define sqlite3OsInMutex            sqlite3Os.xInMutex
++#define sqlite3OsThreadSpecificData sqlite3Os.xThreadSpecificData
++#define sqlite3OsMalloc             sqlite3Os.xMalloc
++#define sqlite3OsRealloc            sqlite3Os.xRealloc
++#define sqlite3OsFree               sqlite3Os.xFree
++#define sqlite3OsAllocationSize     sqlite3Os.xAllocationSize
++
++#endif /* SQLITE_ENABLE_REDEF_IO */
++
+ #endif /* _SQLITE_OS_H_ */
+Index: sqlite/tokenize.c
+===================================================================
+--- amarok/src/sqlite/tokenize.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/tokenize.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -196,9 +196,13 @@
+           }
+         }
+       }
+-      if( c ) i++;
+-      *tokenType = TK_STRING;
+-      return i;
++      if( c ){
++        *tokenType = TK_STRING;
++        return i+1;
++      }else{
++        *tokenType = TK_ILLEGAL;
++        return i;
++      }
+     }
+     case '.': {
+ #ifndef SQLITE_OMIT_FLOATING_POINT
+@@ -257,6 +261,7 @@
+ #ifndef SQLITE_OMIT_TCL_VARIABLE
+     case '$':
+ #endif
++    case '@':  /* For compatibility with MS SQL Server */
+     case ':': {
+       int n = 0;
+       *tokenType = TK_VARIABLE;
+@@ -344,7 +349,6 @@
+   i = 0;
+   pEngine = sqlite3ParserAlloc((void*(*)(int))sqlite3MallocX);
+   if( pEngine==0 ){
+-    sqlite3SetString(pzErrMsg, "out of memory", (char*)0);
+     return SQLITE_NOMEM;
+   }
+   assert( pParse->sLastToken.dyn==0 );
+@@ -355,9 +359,9 @@
+   assert( pParse->nVarExprAlloc==0 );
+   assert( pParse->apVarExpr==0 );
+   pParse->zTail = pParse->zSql = zSql;
+-  while( sqlite3_malloc_failed==0 && zSql[i]!=0 ){
++  while( !sqlite3MallocFailed() && zSql[i]!=0 ){
+     assert( i>=0 );
+-    pParse->sLastToken.z = &zSql[i];
++    pParse->sLastToken.z = (u8*)&zSql[i];
+     assert( pParse->sLastToken.dyn==0 );
+     pParse->sLastToken.n = getToken((unsigned char*)&zSql[i],&tokenType);
+     i += pParse->sLastToken.n;
+@@ -403,12 +407,11 @@
+     sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse);
+   }
+   sqlite3ParserFree(pEngine, sqlite3FreeX);
+-  if( sqlite3_malloc_failed ){
++  if( sqlite3MallocFailed() ){
+     pParse->rc = SQLITE_NOMEM;
+   }
+   if( pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE && pParse->zErrMsg==0 ){
+-    sqlite3SetString(&pParse->zErrMsg, sqlite3ErrStr(pParse->rc),
+-                    (char*)0);
++    sqlite3SetString(&pParse->zErrMsg, sqlite3ErrStr(pParse->rc), (char*)0);
+   }
+   if( pParse->zErrMsg ){
+     if( pzErrMsg && *pzErrMsg==0 ){
+@@ -423,6 +426,13 @@
+     sqlite3VdbeDelete(pParse->pVdbe);
+     pParse->pVdbe = 0;
+   }
++#ifndef SQLITE_OMIT_SHARED_CACHE
++  if( pParse->nested==0 ){
++    sqliteFree(pParse->aTableLock);
++    pParse->aTableLock = 0;
++    pParse->nTableLock = 0;
++  }
++#endif
+   sqlite3DeleteTable(pParse->db, pParse->pNewTable);
+   sqlite3DeleteTrigger(pParse->pNewTrigger);
+   sqliteFree(pParse->apVarExpr);
+Index: sqlite/keywordhash.h
+===================================================================
+--- amarok/src/sqlite/keywordhash.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/keywordhash.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -1,28 +1,28 @@
+-/* Hash score: 158 */
++/* Hash score: 159 */
+ static int keywordCode(const char *z, int n){
+-  static const char zText[535] =
++  static const char zText[537] =
+     "ABORTABLEFTEMPORARYADDATABASELECTHENDEFAULTRANSACTIONATURALTER"
+     "AISEACHECKEYAFTEREFERENCESCAPELSEXCEPTRIGGEREGEXPLAINITIALLYANALYZE"
+     "XCLUSIVEXISTSTATEMENTANDEFERRABLEATTACHAVINGLOBEFOREIGNOREINDEX"
+     "AUTOINCREMENTBEGINNERENAMEBETWEENOTNULLIKEBYCASCADEFERREDELETE"
+     "CASECASTCOLLATECOLUMNCOMMITCONFLICTCONSTRAINTERSECTCREATECROSS"
+     "CURRENT_DATECURRENT_TIMESTAMPLANDESCDETACHDISTINCTDROPRAGMATCH"
+-    "FAILIMITFROMFULLGROUPDATEIMMEDIATEINSERTINSTEADINTOFFSETISNULL"
++    "FAILIMITFROMFULLGROUPDATEIFIMMEDIATEINSERTINSTEADINTOFFSETISNULL"
+     "JOINORDEREPLACEOUTERESTRICTPRIMARYQUERYRIGHTROLLBACKROWHENUNION"
+     "UNIQUEUSINGVACUUMVALUESVIEWHERE";
+   static const unsigned char aHash[127] = {
+-      91,  80, 106,  90,   0,   4,   0,   0, 113,   0,  83,   0,   0,
+-      94,  44,  76,  92,   0, 105, 108,  96,   0,   0,  10,   0,   0,
+-     112,   0, 109, 102,   0,  28,  48,   0,  41,   0,   0,  65,  71,
+-       0,  63,  19,   0, 104,  36, 103,   0, 107,  74,   0,   0,  33,
+-       0,  61,  37,   0,   8,   0, 114,  38,  12,   0,  77,  40,  25,
++      92,  80, 107,  91,   0,   4,   0,   0, 114,   0,  83,   0,   0,
++      95,  44,  76,  93,   0, 106, 109,  97,  90,   0,  10,   0,   0,
++     113,   0, 110, 103,   0,  28,  48,   0,  41,   0,   0,  65,  71,
++       0,  63,  19,   0, 105,  36, 104,   0, 108,  74,   0,   0,  33,
++       0,  61,  37,   0,   8,   0, 115,  38,  12,   0,  77,  40,  25,
+       66,   0,   0,  31,  81,  53,  30,  50,  20,  88,   0,  34,   0,
+       75,  26,   0,  72,   0,   0,   0,  64,  47,  67,  22,  87,  29,
+-      69,  86,   0,   1,   0,   9, 100,  58,  18,   0, 111,  82,  98,
+-      54,   6,  85,   0,   0,  49,  93,   0, 101,   0,  70,   0,   0,
+-      15,   0, 115,  51,  56,   0,   2,  55,   0, 110,
++      69,  86,   0,   1,   0,   9, 101,  58,  18,   0, 112,  82,  99,
++      54,   6,  85,   0,   0,  49,  94,   0, 102,   0,  70,   0,   0,
++      15,   0, 116,  51,  56,   0,   2,  55,   0, 111,
+   };
+-  static const unsigned char aNext[115] = {
++  static const unsigned char aNext[116] = {
+        0,   0,   0,   0,   0,   3,   0,   0,   0,   0,   0,   0,   0,
+        0,   0,   0,   0,   0,   0,   0,   0,  17,   0,   0,   0,   0,
+        0,  11,   0,   0,   0,   0,   5,  13,   0,   7,   0,   0,   0,
+@@ -30,32 +30,32 @@
+        0,   0,  16,   0,  23,  52,   0,   0,   0,   0,  45,   0,  59,
+        0,   0,   0,   0,   0,   0,   0,   0,  73,  42,   0,  24,  60,
+       21,   0,  79,   0,   0,  68,   0,   0,  84,  46,   0,   0,   0,
+-       0,   0,   0,   0,  39,  95,  97,   0,   0,  99,   0,  32,   0,
+-      14,  27,  78,   0,  57,  89,   0,  35,   0,  62,   0,
++       0,   0,   0,   0,   0,  39,  96,  98,   0,   0, 100,   0,  32,
++       0,  14,  27,  78,   0,  57,  89,   0,  35,   0,  62,   0,
+   };
+-  static const unsigned char aLen[115] = {
++  static const unsigned char aLen[116] = {
+        5,   5,   4,   4,   9,   2,   3,   8,   2,   6,   4,   3,   7,
+       11,   2,   7,   5,   5,   4,   5,   3,   5,  10,   6,   4,   6,
+        7,   6,   7,   9,   3,   7,   9,   6,   9,   3,  10,   6,   6,
+        4,   6,   3,   7,   6,   7,   5,  13,   2,   2,   5,   5,   6,
+        7,   3,   7,   4,   4,   2,   7,   3,   8,   6,   4,   4,   7,
+        6,   6,   8,  10,   9,   6,   5,  12,  12,  17,   4,   4,   6,
+-       8,   2,   4,   6,   5,   4,   5,   4,   4,   5,   6,   9,   6,
+-       7,   4,   2,   6,   3,   6,   4,   5,   7,   5,   8,   7,   5,
+-       5,   8,   3,   4,   5,   6,   5,   6,   6,   4,   5,
++       8,   2,   4,   6,   5,   4,   5,   4,   4,   5,   6,   2,   9,
++       6,   7,   4,   2,   6,   3,   6,   4,   5,   7,   5,   8,   7,
++       5,   5,   8,   3,   4,   5,   6,   5,   6,   6,   4,   5,
+   };
+-  static const unsigned short int aOffset[115] = {
++  static const unsigned short int aOffset[116] = {
+        0,   4,   7,  10,  10,  14,  19,  21,  26,  27,  32,  34,  36,
+       42,  51,  52,  57,  61,  65,  67,  71,  74,  78,  86,  91,  94,
+       99, 105, 108, 113, 118, 122, 128, 136, 141, 150, 152, 162, 167,
+      172, 175, 177, 177, 181, 185, 187, 192, 194, 196, 205, 208, 212,
+      218, 224, 224, 227, 230, 234, 236, 237, 241, 248, 254, 258, 262,
+      269, 275, 281, 289, 296, 305, 311, 316, 328, 328, 344, 348, 352,
+-     358, 359, 366, 369, 373, 378, 381, 386, 390, 394, 397, 403, 412,
+-     418, 425, 428, 428, 431, 434, 440, 444, 448, 455, 459, 467, 474,
+-     479, 484, 492, 494, 498, 503, 509, 514, 520, 526, 529,
++     358, 359, 366, 369, 373, 378, 381, 386, 390, 394, 397, 403, 405,
++     414, 420, 427, 430, 430, 433, 436, 442, 446, 450, 457, 461, 469,
++     476, 481, 486, 494, 496, 500, 505, 511, 516, 522, 528, 531,
+   };
+-  static const unsigned char aCode[115] = {
++  static const unsigned char aCode[116] = {
+     TK_ABORT,      TK_TABLE,      TK_JOIN_KW,    TK_TEMP,       TK_TEMP,       
+     TK_OR,         TK_ADD,        TK_DATABASE,   TK_AS,         TK_SELECT,     
+     TK_THEN,       TK_END,        TK_DEFAULT,    TK_TRANSACTION,TK_ON,         
+@@ -73,12 +73,13 @@
+     TK_CREATE,     TK_JOIN_KW,    TK_CTIME_KW,   TK_CTIME_KW,   TK_CTIME_KW,   
+     TK_PLAN,       TK_DESC,       TK_DETACH,     TK_DISTINCT,   TK_IS,         
+     TK_DROP,       TK_PRAGMA,     TK_MATCH,      TK_FAIL,       TK_LIMIT,      
+-    TK_FROM,       TK_JOIN_KW,    TK_GROUP,      TK_UPDATE,     TK_IMMEDIATE,  
+-    TK_INSERT,     TK_INSTEAD,    TK_INTO,       TK_OF,         TK_OFFSET,     
+-    TK_SET,        TK_ISNULL,     TK_JOIN,       TK_ORDER,      TK_REPLACE,    
+-    TK_JOIN_KW,    TK_RESTRICT,   TK_PRIMARY,    TK_QUERY,      TK_JOIN_KW,    
+-    TK_ROLLBACK,   TK_ROW,        TK_WHEN,       TK_UNION,      TK_UNIQUE,     
+-    TK_USING,      TK_VACUUM,     TK_VALUES,     TK_VIEW,       TK_WHERE,      
++    TK_FROM,       TK_JOIN_KW,    TK_GROUP,      TK_UPDATE,     TK_IF,         
++    TK_IMMEDIATE,  TK_INSERT,     TK_INSTEAD,    TK_INTO,       TK_OF,         
++    TK_OFFSET,     TK_SET,        TK_ISNULL,     TK_JOIN,       TK_ORDER,      
++    TK_REPLACE,    TK_JOIN_KW,    TK_RESTRICT,   TK_PRIMARY,    TK_QUERY,      
++    TK_JOIN_KW,    TK_ROLLBACK,   TK_ROW,        TK_WHEN,       TK_UNION,      
++    TK_UNIQUE,     TK_USING,      TK_VACUUM,     TK_VALUES,     TK_VIEW,       
++    TK_WHERE,      
+   };
+   int h, i;
+   if( n<2 ) return TK_ID;
+@@ -92,6 +93,6 @@
+   }
+   return TK_ID;
+ }
+-int sqlite3KeywordCode(const char *z, int n){
+-  return keywordCode(z, n);
++int sqlite3KeywordCode(const unsigned char *z, int n){
++  return keywordCode((char*)z, n);
+ }
+Index: sqlite/pager.c
+===================================================================
+--- amarok/src/sqlite/pager.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/pager.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -46,21 +46,14 @@
+ 
+ /*
+ ** The following two macros are used within the TRACEX() macros above
+-** to print out file-descriptors. They are required so that tracing
+-** can be turned on when using both the regular os_unix.c and os_test.c
+-** backends.
++** to print out file-descriptors. 
+ **
+ ** PAGERID() takes a pointer to a Pager struct as it's argument. The
+ ** associated file-descriptor is returned. FILEHANDLEID() takes an OsFile
+ ** struct as it's argument.
+ */
+-#ifdef OS_TEST
+-#define PAGERID(p) (p->fd->fd.h)
+-#define FILEHANDLEID(fd) (fd->fd.h)
+-#else
+-#define PAGERID(p) (p->fd.h)
+-#define FILEHANDLEID(fd) (fd.h)
+-#endif
++#define PAGERID(p) FILEHANDLEID(&(p)->fd)
++#define FILEHANDLEID(fd) (sqlite3OsFileHandle(&fd))
+ 
+ /*
+ ** The page cache as a whole is always in one of the following
+@@ -232,6 +225,14 @@
+ 
+ /*
+ ** A open page cache is an instance of the following structure.
++**
++** Pager.errCode may be set to SQLITE_IOERR, SQLITE_CORRUPT, SQLITE_PROTOCOL
++** or SQLITE_FULL. Once one of the first three errors occurs, it persists
++** and is returned as the result of every major pager API call.  The
++** SQLITE_FULL return code is slightly different. It persists only until the
++** next successful rollback is performed on the pager cache. Also,
++** SQLITE_FULL does not affect the sqlite3pager_get() and sqlite3pager_lookup()
++** APIs, they may still be used successfully.
+ */
+ struct Pager {
+   u8 journalOpen;             /* True if journal file descriptors is valid */
+@@ -243,8 +244,9 @@
+   u8 stmtAutoopen;            /* Open stmt journal when main journal is opened*/
+   u8 noSync;                  /* Do not sync the journal if true */
+   u8 fullSync;                /* Do extra syncs of the journal for robustness */
++  u8 full_fsync;              /* Use F_FULLFSYNC when available */
+   u8 state;                   /* PAGER_UNLOCK, _SHARED, _RESERVED, etc. */
+-  u8 errMask;                 /* One of several kinds of errors */
++  u8 errCode;                 /* One of several kinds of errors */
+   u8 tempFile;                /* zFilename is a temporary file */
+   u8 readOnly;                /* True for a read-only database */
+   u8 needSync;                /* True if an fsync() is needed on the journal */
+@@ -269,8 +271,8 @@
+   char *zFilename;            /* Name of the database file */
+   char *zJournal;             /* Name of the journal file */
+   char *zDirectory;           /* Directory hold database and journal files */
+-  OsFile fd, jfd;             /* File descriptors for database and journal */
+-  OsFile stfd;                /* File descriptor for the statement subjournal*/
++  OsFile *fd, *jfd;           /* File descriptors for database and journal */
++  OsFile *stfd;               /* File descriptor for the statement subjournal*/
+   BusyHandler *pBusyHandler;  /* Pointer to sqlite.busyHandler */
+   PgHdr *pFirst, *pLast;      /* List of free pages */
+   PgHdr *pFirstSynced;        /* First free page with PgHdr.needSync==0 */
+@@ -291,6 +293,9 @@
+   void (*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
+   void *pCodecArg;            /* First argument to xCodec() */
+   PgHdr *aHash[N_PG_HASH];    /* Hash table to map page number to PgHdr */
++#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
++  Pager *pNext;               /* Linked list of pagers in this thread */
++#endif
+ };
+ 
+ /*
+@@ -304,15 +309,6 @@
+ #endif
+ 
+ /*
+-** These are bits that can be set in Pager.errMask.
+-*/
+-#define PAGER_ERR_FULL     0x01  /* a write() failed */
+-#define PAGER_ERR_MEM      0x02  /* malloc() failed */
+-#define PAGER_ERR_LOCK     0x04  /* error in the locking protocol */
+-#define PAGER_ERR_CORRUPT  0x08  /* database or journal corruption */
+-#define PAGER_ERR_DISK     0x10  /* general disk I/O error - bad hard drive? */
+-
+-/*
+ ** Journal files begin with the following magic string.  The data
+ ** was obtained from /dev/random.  It is used only as a sanity check.
+ **
+@@ -411,28 +407,31 @@
+ ** All values are stored on disk as big-endian.
+ */
+ static int read32bits(OsFile *fd, u32 *pRes){
+-  u32 res;
+-  int rc;
+-  rc = sqlite3OsRead(fd, &res, sizeof(res));
++  unsigned char ac[4];
++  int rc = sqlite3OsRead(fd, ac, sizeof(ac));
+   if( rc==SQLITE_OK ){
+-    unsigned char ac[4];
+-    memcpy(ac, &res, 4);
+-    res = (ac[0]<<24) | (ac[1]<<16) | (ac[2]<<8) | ac[3];
++    *pRes = (ac[0]<<24) | (ac[1]<<16) | (ac[2]<<8) | ac[3];
+   }
+-  *pRes = res;
+   return rc;
+ }
+ 
+ /*
+-** Write a 32-bit integer into the given file descriptor.  Return SQLITE_OK
+-** on success or an error code is something goes wrong.
++** Write a 32-bit integer into a string buffer in big-endian byte order.
+ */
+-static int write32bits(OsFile *fd, u32 val){
+-  unsigned char ac[4];
++static void put32bits(char *ac, u32 val){
+   ac[0] = (val>>24) & 0xff;
+   ac[1] = (val>>16) & 0xff;
+   ac[2] = (val>>8) & 0xff;
+   ac[3] = val & 0xff;
++}
++
++/*
++** Write a 32-bit integer into the given file descriptor.  Return SQLITE_OK
++** on success or an error code is something goes wrong.
++*/
++static int write32bits(OsFile *fd, u32 val){
++  char ac[4];
++  put32bits(ac, val);
+   return sqlite3OsWrite(fd, ac, 4);
+ }
+ 
+@@ -441,12 +440,9 @@
+ ** 'p' at offset 'offset'.
+ */
+ static void store32bits(u32 val, PgHdr *p, int offset){
+-  unsigned char *ac;
+-  ac = &((unsigned char*)PGHDR_TO_DATA(p))[offset];
+-  ac[0] = (val>>24) & 0xff;
+-  ac[1] = (val>>16) & 0xff;
+-  ac[2] = (val>>8) & 0xff;
+-  ac[3] = val & 0xff;
++  char *ac;
++  ac = &((char*)PGHDR_TO_DATA(p))[offset];
++  put32bits(ac, val);
+ }
+ 
+ /*
+@@ -461,16 +457,25 @@
+ 
+ 
+ /*
+-** Convert the bits in the pPager->errMask into an approprate
+-** return code.
++** This function should be called when an error occurs within the pager
++** code. The first argument is a pointer to the pager structure, the
++** second the error-code about to be returned by a pager API function. 
++** The value returned is a copy of the second argument to this function. 
++**
++** If the second argument is SQLITE_IOERR, SQLITE_CORRUPT or SQLITE_PROTOCOL,
++** the error becomes persistent. All subsequent API calls on this Pager
++** will immediately return the same error code.
+ */
+-static int pager_errcode(Pager *pPager){
+-  int rc = SQLITE_OK;
+-  if( pPager->errMask & PAGER_ERR_LOCK )    rc = SQLITE_PROTOCOL;
+-  if( pPager->errMask & PAGER_ERR_DISK )    rc = SQLITE_IOERR;
+-  if( pPager->errMask & PAGER_ERR_FULL )    rc = SQLITE_FULL;
+-  if( pPager->errMask & PAGER_ERR_MEM )     rc = SQLITE_NOMEM;
+-  if( pPager->errMask & PAGER_ERR_CORRUPT ) rc = SQLITE_CORRUPT;
++static int pager_error(Pager *pPager, int rc){
++  assert( pPager->errCode==SQLITE_FULL || pPager->errCode==SQLITE_OK );
++  if( 
++    rc==SQLITE_FULL ||
++    rc==SQLITE_IOERR ||
++    rc==SQLITE_CORRUPT ||
++    rc==SQLITE_PROTOCOL
++  ){
++    pPager->errCode = rc;
++  }
+   return rc;
+ }
+ 
+@@ -496,7 +501,7 @@
+ #define CHECK_PAGE(x) checkPage(x)
+ static void checkPage(PgHdr *pPg){
+   Pager *pPager = pPg->pPager;
+-  assert( !pPg->pageHash || pPager->errMask || MEMDB || pPg->dirty || 
++  assert( !pPg->pageHash || pPager->errCode || MEMDB || pPg->dirty || 
+       pPg->pageHash==pager_pagehash(pPg) );
+ }
+ 
+@@ -597,7 +602,7 @@
+   assert( offset>=c );
+   assert( (offset-c)<JOURNAL_HDR_SZ(pPager) );
+   pPager->journalOff = offset;
+-  return sqlite3OsSeek(&pPager->jfd, pPager->journalOff);
++  return sqlite3OsSeek(pPager->jfd, pPager->journalOff);
+ }
+ 
+ /*
+@@ -615,6 +620,7 @@
+ ** Followed by (JOURNAL_HDR_SZ - 24) bytes of unused space.
+ */
+ static int writeJournalHdr(Pager *pPager){
++  char zHeader[sizeof(aJournalMagic)+16];
+ 
+   int rc = seekJournalHdr(pPager);
+   if( rc ) return rc;
+@@ -633,33 +639,25 @@
+   ** Actually maybe the whole journal header should be delayed until that
+   ** point. Think about this.
+   */
+-  rc = sqlite3OsWrite(&pPager->jfd, aJournalMagic, sizeof(aJournalMagic));
++  memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic));
++  /* The nRec Field. 0xFFFFFFFF for no-sync journals. */
++  put32bits(&zHeader[sizeof(aJournalMagic)], pPager->noSync ? 0xffffffff : 0);
++  /* The random check-hash initialiser */ 
++  sqlite3Randomness(sizeof(pPager->cksumInit), &pPager->cksumInit);
++  put32bits(&zHeader[sizeof(aJournalMagic)+4], pPager->cksumInit);
++  /* The initial database size */
++  put32bits(&zHeader[sizeof(aJournalMagic)+8], pPager->dbSize);
++  /* The assumed sector size for this process */
++  put32bits(&zHeader[sizeof(aJournalMagic)+12], pPager->sectorSize);
++  rc = sqlite3OsWrite(pPager->jfd, zHeader, sizeof(zHeader));
+ 
+-  if( rc==SQLITE_OK ){
+-    /* The nRec Field. 0xFFFFFFFF for no-sync journals. */
+-    rc = write32bits(&pPager->jfd, pPager->noSync ? 0xffffffff : 0);
+-  }
+-  if( rc==SQLITE_OK ){
+-    /* The random check-hash initialiser */ 
+-    sqlite3Randomness(sizeof(pPager->cksumInit), &pPager->cksumInit);
+-    rc = write32bits(&pPager->jfd, pPager->cksumInit);
+-  }
+-  if( rc==SQLITE_OK ){
+-    /* The initial database size */
+-    rc = write32bits(&pPager->jfd, pPager->dbSize);
+-  }
+-  if( rc==SQLITE_OK ){
+-    /* The assumed sector size for this process */
+-    rc = write32bits(&pPager->jfd, pPager->sectorSize);
+-  }
+-
+   /* The journal header has been written successfully. Seek the journal
+   ** file descriptor to the end of the journal header sector.
+   */
+   if( rc==SQLITE_OK ){
+-    rc = sqlite3OsSeek(&pPager->jfd, pPager->journalOff-1);
++    rc = sqlite3OsSeek(pPager->jfd, pPager->journalOff-1);
+     if( rc==SQLITE_OK ){
+-      rc = sqlite3OsWrite(&pPager->jfd, "\000", 1);
++      rc = sqlite3OsWrite(pPager->jfd, "\000", 1);
+     }
+   }
+   return rc;
+@@ -697,20 +695,20 @@
+     return SQLITE_DONE;
+   }
+ 
+-  rc = sqlite3OsRead(&pPager->jfd, aMagic, sizeof(aMagic));
++  rc = sqlite3OsRead(pPager->jfd, aMagic, sizeof(aMagic));
+   if( rc ) return rc;
+ 
+   if( memcmp(aMagic, aJournalMagic, sizeof(aMagic))!=0 ){
+     return SQLITE_DONE;
+   }
+ 
+-  rc = read32bits(&pPager->jfd, pNRec);
++  rc = read32bits(pPager->jfd, pNRec);
+   if( rc ) return rc;
+ 
+-  rc = read32bits(&pPager->jfd, &pPager->cksumInit);
++  rc = read32bits(pPager->jfd, &pPager->cksumInit);
+   if( rc ) return rc;
+ 
+-  rc = read32bits(&pPager->jfd, pDbSize);
++  rc = read32bits(pPager->jfd, pDbSize);
+   if( rc ) return rc;
+ 
+   /* Update the assumed sector-size to match the value used by 
+@@ -719,11 +717,11 @@
+   ** is being called from within pager_playback(). The local value
+   ** of Pager.sectorSize is restored at the end of that routine.
+   */
+-  rc = read32bits(&pPager->jfd, (u32 *)&pPager->sectorSize);
++  rc = read32bits(pPager->jfd, (u32 *)&pPager->sectorSize);
+   if( rc ) return rc;
+ 
+   pPager->journalOff += JOURNAL_HDR_SZ(pPager);
+-  rc = sqlite3OsSeek(&pPager->jfd, pPager->journalOff);
++  rc = sqlite3OsSeek(pPager->jfd, pPager->journalOff);
+   return rc;
+ }
+ 
+@@ -743,12 +741,16 @@
+ **
+ ** The master journal page checksum is the sum of the bytes in the master
+ ** journal name.
++**
++** If zMaster is a NULL pointer (occurs for a single database transaction), 
++** this call is a no-op.
+ */
+ static int writeMasterJournal(Pager *pPager, const char *zMaster){
+   int rc;
+   int len; 
+   int i; 
+-  u32 cksum = 0; 
++  u32 cksum = 0;
++  char zBuf[sizeof(aJournalMagic)+2*4];
+ 
+   if( !zMaster || pPager->setMaster) return SQLITE_OK;
+   pPager->setMaster = 1;
+@@ -768,19 +770,16 @@
+   }
+   pPager->journalOff += (len+20);
+ 
+-  rc = write32bits(&pPager->jfd, PAGER_MJ_PGNO(pPager));
++  rc = write32bits(pPager->jfd, PAGER_MJ_PGNO(pPager));
+   if( rc!=SQLITE_OK ) return rc;
+ 
+-  rc = sqlite3OsWrite(&pPager->jfd, zMaster, len);
++  rc = sqlite3OsWrite(pPager->jfd, zMaster, len);
+   if( rc!=SQLITE_OK ) return rc;
+ 
+-  rc = write32bits(&pPager->jfd, len);
+-  if( rc!=SQLITE_OK ) return rc;
+-
+-  rc = write32bits(&pPager->jfd, cksum);
+-  if( rc!=SQLITE_OK ) return rc;
+-
+-  rc = sqlite3OsWrite(&pPager->jfd, aJournalMagic, sizeof(aJournalMagic));
++  put32bits(zBuf, len);
++  put32bits(&zBuf[4], cksum);
++  memcpy(&zBuf[8], aJournalMagic, sizeof(aJournalMagic));
++  rc = sqlite3OsWrite(pPager->jfd, zBuf, 8+sizeof(aJournalMagic));
+   pPager->needSync = !pPager->noSync;
+   return rc;
+ }
+@@ -844,7 +843,7 @@
+ */
+ static void pager_reset(Pager *pPager){
+   PgHdr *pPg, *pNext;
+-  if( pPager->errMask ) return;
++  if( pPager->errCode ) return;
+   for(pPg=pPager->pAll; pPg; pPg=pNext){
+     pNext = pPg->pNextAll;
+     sqliteFree(pPg);
+@@ -858,7 +857,7 @@
+   if( pPager->state>=PAGER_RESERVED ){
+     sqlite3pager_rollback(pPager);
+   }
+-  sqlite3OsUnlock(&pPager->fd, NO_LOCK);
++  sqlite3OsUnlock(pPager->fd, NO_LOCK);
+   pPager->state = PAGER_UNLOCK;
+   pPager->dbSize = -1;
+   pPager->nRef = 0;
+@@ -866,29 +865,6 @@
+ }
+ 
+ /*
+-** This function is used to reset the pager after a malloc() failure. This
+-** doesn't work with in-memory databases. If a malloc() fails when an 
+-** in-memory database is in use it is not possible to recover.
+-**
+-** If a transaction or statement transaction is active, it is rolled back.
+-**
+-** It is an error to call this function if any pages are in use.
+-*/
+-#ifndef SQLITE_OMIT_GLOBALRECOVER
+-int sqlite3pager_reset(Pager *pPager){
+-  if( pPager ){
+-    if( pPager->nRef || MEMDB ){
+-      return SQLITE_ERROR;
+-    }
+-    pPager->errMask &= ~(PAGER_ERR_MEM);
+-    pager_reset(pPager);
+-  }
+-  return SQLITE_OK;
+-}
+-#endif
+-
+-
+-/*
+ ** When this routine is called, the pager has the journal file open and
+ ** a RESERVED or EXCLUSIVE lock on the database.  This routine releases
+ ** the database lock and acquires a SHARED lock in its place.  The journal
+@@ -930,10 +906,12 @@
+     assert( pPager->aInJournal==0 );
+     assert( pPager->dirtyCache==0 || pPager->useJournal==0 );
+   }
+-  rc = sqlite3OsUnlock(&pPager->fd, SHARED_LOCK);
++  rc = sqlite3OsUnlock(pPager->fd, SHARED_LOCK);
+   pPager->state = PAGER_SHARED;
+   pPager->origDbSize = 0;
+   pPager->setMaster = 0;
++  pPager->needSync = 0;
++  pPager->pFirstSynced = pPager->pFirst;
+   return rc;
+ }
+ 
+@@ -957,7 +935,7 @@
+ ** only the middle sector is corrupt, we will still have a reasonable
+ ** chance of failing the checksum and thus detecting the problem.
+ */
+-static u32 pager_cksum(Pager *pPager, Pgno pgno, const char *aData){
++static u32 pager_cksum(Pager *pPager, Pgno pgno, const u8 *aData){
+   u32 cksum = pPager->cksumInit;
+   int i = pPager->pageSize-200;
+   while( i>0 ){
+@@ -985,7 +963,7 @@
+   /* useCksum should be true for the main journal and false for
+   ** statement journals.  Verify that this is always the case
+   */
+-  assert( jfd == (useCksum ? &pPager->jfd : &pPager->stfd) );
++  assert( jfd == (useCksum ? pPager->jfd : pPager->stfd) );
+ 
+ 
+   rc = read32bits(jfd, &pgno);
+@@ -1040,9 +1018,9 @@
+   assert( pPager->state>=PAGER_EXCLUSIVE || pPg!=0 );
+   TRACE3("PLAYBACK %d page %d\n", PAGERID(pPager), pgno);
+   if( pPager->state>=PAGER_EXCLUSIVE && (pPg==0 || pPg->needSync==0) ){
+-    rc = sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize);
++    rc = sqlite3OsSeek(pPager->fd, (pgno-1)*(i64)pPager->pageSize);
+     if( rc==SQLITE_OK ){
+-      rc = sqlite3OsWrite(&pPager->fd, aData, pPager->pageSize);
++      rc = sqlite3OsWrite(pPager->fd, aData, pPager->pageSize);
+     }
+     if( pPg ) pPg->dirty = 0;
+   }
+@@ -1082,18 +1060,17 @@
+ static int pager_delmaster(const char *zMaster){
+   int rc;
+   int master_open = 0;
+-  OsFile master;
++  OsFile *master = 0;
+   char *zMasterJournal = 0; /* Contents of master journal file */
+   i64 nMasterJournal;       /* Size of master journal file */
+ 
+   /* Open the master journal file exclusively in case some other process
+   ** is running this routine also. Not that it makes too much difference.
+   */
+-  memset(&master, 0, sizeof(master));
+   rc = sqlite3OsOpenReadOnly(zMaster, &master);
+   if( rc!=SQLITE_OK ) goto delmaster_out;
+   master_open = 1;
+-  rc = sqlite3OsFileSize(&master, &nMasterJournal);
++  rc = sqlite3OsFileSize(master, &nMasterJournal);
+   if( rc!=SQLITE_OK ) goto delmaster_out;
+ 
+   if( nMasterJournal>0 ){
+@@ -1108,7 +1085,7 @@
+       rc = SQLITE_NOMEM;
+       goto delmaster_out;
+     }
+-    rc = sqlite3OsRead(&master, zMasterJournal, nMasterJournal);
++    rc = sqlite3OsRead(master, zMasterJournal, nMasterJournal);
+     if( rc!=SQLITE_OK ) goto delmaster_out;
+ 
+     zJournal = zMasterJournal;
+@@ -1118,16 +1095,15 @@
+         ** Open it and check if it points at the master journal. If
+         ** so, return without deleting the master journal file.
+         */
+-        OsFile journal;
++        OsFile *journal = 0;
+         int c;
+ 
+-        memset(&journal, 0, sizeof(journal));
+         rc = sqlite3OsOpenReadOnly(zJournal, &journal);
+         if( rc!=SQLITE_OK ){
+           goto delmaster_out;
+         }
+ 
+-        rc = readMasterJournal(&journal, &zMasterPtr);
++        rc = readMasterJournal(journal, &zMasterPtr);
+         sqlite3OsClose(&journal);
+         if( rc!=SQLITE_OK ){
+           goto delmaster_out;
+@@ -1172,9 +1148,9 @@
+     char zBuf[SQLITE_MAX_PAGE_SIZE];
+     if( !pPg->dirty ) continue;
+     if( (int)pPg->pgno <= pPager->origDbSize ){
+-      rc = sqlite3OsSeek(&pPager->fd, pPager->pageSize*(i64)(pPg->pgno-1));
++      rc = sqlite3OsSeek(pPager->fd, pPager->pageSize*(i64)(pPg->pgno-1));
+       if( rc==SQLITE_OK ){
+-        rc = sqlite3OsRead(&pPager->fd, zBuf, pPager->pageSize);
++        rc = sqlite3OsRead(pPager->fd, zBuf, pPager->pageSize);
+       }
+       TRACE3("REFETCH %d page %d\n", PAGERID(pPager), pPg->pgno);
+       if( rc ) break;
+@@ -1205,7 +1181,7 @@
+ */
+ static int pager_truncate(Pager *pPager, int nPage){
+   assert( pPager->state>=PAGER_EXCLUSIVE );
+-  return sqlite3OsTruncate(&pPager->fd, pPager->pageSize*(i64)nPage);
++  return sqlite3OsTruncate(pPager->fd, pPager->pageSize*(i64)nPage);
+ }
+ 
+ /*
+@@ -1273,7 +1249,7 @@
+   ** the journal is empty.
+   */
+   assert( pPager->journalOpen );
+-  rc = sqlite3OsFileSize(&pPager->jfd, &szJ);
++  rc = sqlite3OsFileSize(pPager->jfd, &szJ);
+   if( rc!=SQLITE_OK ){
+     goto end_playback;
+   }
+@@ -1283,7 +1259,7 @@
+   ** present on disk, then the journal is not hot and does not need to be
+   ** played back.
+   */
+-  rc = readMasterJournal(&pPager->jfd, &zMaster);
++  rc = readMasterJournal(pPager->jfd, &zMaster);
+   assert( rc!=SQLITE_DONE );
+   if( rc!=SQLITE_OK || (zMaster && !sqlite3OsFileExists(zMaster)) ){
+     sqliteFree(zMaster);
+@@ -1291,7 +1267,7 @@
+     if( rc==SQLITE_DONE ) rc = SQLITE_OK;
+     goto end_playback;
+   }
+-  sqlite3OsSeek(&pPager->jfd, 0);
++  sqlite3OsSeek(pPager->jfd, 0);
+   pPager->journalOff = 0;
+ 
+   /* This loop terminates either when the readJournalHdr() call returns
+@@ -1334,13 +1310,13 @@
+       pPager->dbSize = mxPg;
+     }
+ 
+-    /* rc = sqlite3OsSeek(&pPager->jfd, JOURNAL_HDR_SZ(pPager)); */
++    /* rc = sqlite3OsSeek(pPager->jfd, JOURNAL_HDR_SZ(pPager)); */
+     if( rc!=SQLITE_OK ) goto end_playback;
+   
+     /* Copy original pages out of the journal and back into the database file.
+     */
+     for(i=0; i<nRec; i++){
+-      rc = pager_playback_one_page(pPager, &pPager->jfd, 1);
++      rc = pager_playback_one_page(pPager, pPager->jfd, 1);
+       if( rc!=SQLITE_OK ){
+         if( rc==SQLITE_DONE ){
+           rc = SQLITE_OK;
+@@ -1407,7 +1383,7 @@
+ #ifndef NDEBUG 
+   {
+     i64 os_szJ;
+-    rc = sqlite3OsFileSize(&pPager->jfd, &os_szJ);
++    rc = sqlite3OsFileSize(pPager->jfd, &os_szJ);
+     if( rc!=SQLITE_OK ) return rc;
+     assert( szJ==os_szJ );
+   }
+@@ -1433,7 +1409,7 @@
+   /* Figure out how many records are in the statement journal.
+   */
+   assert( pPager->stmtInUse && pPager->journalOpen );
+-  sqlite3OsSeek(&pPager->stfd, 0);
++  sqlite3OsSeek(pPager->stfd, 0);
+   nRec = pPager->stmtNRec;
+   
+   /* Copy original pages out of the statement journal and back into the
+@@ -1442,7 +1418,7 @@
+   ** journals.
+   */
+   for(i=nRec-1; i>=0; i--){
+-    rc = pager_playback_one_page(pPager, &pPager->stfd, 0);
++    rc = pager_playback_one_page(pPager, pPager->stfd, 0);
+     assert( rc!=SQLITE_DONE );
+     if( rc!=SQLITE_OK ) goto end_stmt_playback;
+   }
+@@ -1455,7 +1431,7 @@
+   ** If it is not zero, then Pager.stmtHdrOff is the offset to the start
+   ** of the first journal header written during this statement transaction.
+   */
+-  rc = sqlite3OsSeek(&pPager->jfd, pPager->stmtJSize);
++  rc = sqlite3OsSeek(pPager->jfd, pPager->stmtJSize);
+   if( rc!=SQLITE_OK ){
+     goto end_stmt_playback;
+   }
+@@ -1463,24 +1439,24 @@
+   pPager->cksumInit = pPager->stmtCksum;
+   assert( JOURNAL_HDR_SZ(pPager)<(pPager->pageSize+8) );
+   while( pPager->journalOff <= (hdrOff-(pPager->pageSize+8)) ){
+-    rc = pager_playback_one_page(pPager, &pPager->jfd, 1);
++    rc = pager_playback_one_page(pPager, pPager->jfd, 1);
+     assert( rc!=SQLITE_DONE );
+     if( rc!=SQLITE_OK ) goto end_stmt_playback;
+   }
+ 
+   while( pPager->journalOff < szJ ){
+-    u32 nRec;
++    u32 nJRec;         /* Number of Journal Records */
+     u32 dummy;
+-    rc = readJournalHdr(pPager, szJ, &nRec, &dummy);
++    rc = readJournalHdr(pPager, szJ, &nJRec, &dummy);
+     if( rc!=SQLITE_OK ){
+       assert( rc!=SQLITE_DONE );
+       goto end_stmt_playback;
+     }
+-    if( nRec==0 ){
+-      nRec = (szJ - pPager->journalOff) / (pPager->pageSize+8);
++    if( nJRec==0 ){
++      nJRec = (szJ - pPager->journalOff) / (pPager->pageSize+8);
+     }
+-    for(i=nRec-1; i>=0 && pPager->journalOff < szJ; i--){
+-      rc = pager_playback_one_page(pPager, &pPager->jfd, 1);
++    for(i=nJRec-1; i>=0 && pPager->journalOff < szJ; i--){
++      rc = pager_playback_one_page(pPager, pPager->jfd, 1);
+       assert( rc!=SQLITE_DONE );
+       if( rc!=SQLITE_OK ) goto end_stmt_playback;
+     }
+@@ -1489,10 +1465,7 @@
+   pPager->journalOff = szJ;
+   
+ end_stmt_playback:
+-  if( rc!=SQLITE_OK ){
+-    pPager->errMask |= PAGER_ERR_CORRUPT;
+-    rc = SQLITE_CORRUPT;
+-  }else{
++  if( rc==SQLITE_OK) {
+     pPager->journalOff = szJ;
+     /* pager_reload_cache(pPager); */
+   }
+@@ -1537,9 +1510,10 @@
+ ** and FULL=3.
+ */
+ #ifndef SQLITE_OMIT_PAGER_PRAGMAS
+-void sqlite3pager_set_safety_level(Pager *pPager, int level){
++void sqlite3pager_set_safety_level(Pager *pPager, int level, int full_fsync){
+   pPager->noSync =  level==1 || pPager->tempFile;
+   pPager->fullSync = level==3 && !pPager->tempFile;
++  pPager->full_fsync = full_fsync;
+   if( pPager->noSync ) pPager->needSync = 0;
+ }
+ #endif
+@@ -1560,14 +1534,14 @@
+ ** The OS will automatically delete the temporary file when it is
+ ** closed.
+ */
+-static int sqlite3pager_opentemp(char *zFile, OsFile *fd){
++static int sqlite3pager_opentemp(char *zFile, OsFile **pFd){
+   int cnt = 8;
+   int rc;
+   sqlite3_opentemp_count++;  /* Used for testing and analysis only */
+   do{
+     cnt--;
+     sqlite3OsTempFileName(zFile);
+-    rc = sqlite3OsOpenExclusive(zFile, fd, 1);
++    rc = sqlite3OsOpenExclusive(zFile, pFd, 1);
+   }while( cnt>0 && rc!=SQLITE_OK && rc!=SQLITE_NOMEM );
+   return rc;
+ }
+@@ -1592,10 +1566,10 @@
+   int nExtra,              /* Extra bytes append to each in-memory page */
+   int flags                /* flags controlling this file */
+ ){
+-  Pager *pPager;
++  Pager *pPager = 0;
+   char *zFullPathname = 0;
+-  int nameLen;
+-  OsFile fd;
++  int nameLen;  /* Compiler is wrong. This is always initialized before use */
++  OsFile *fd;
+   int rc = SQLITE_OK;
+   int i;
+   int tempFile = 0;
+@@ -1604,18 +1578,36 @@
+   int useJournal = (flags & PAGER_OMIT_JOURNAL)==0;
+   int noReadlock = (flags & PAGER_NO_READLOCK)!=0;
+   char zTemp[SQLITE_TEMPNAME_SIZE];
++#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
++  /* A malloc() cannot fail in sqlite3ThreadData() as one or more calls to 
++  ** malloc() must have already been made by this thread before it gets
++  ** to this point. This means the ThreadData must have been allocated already
++  ** so that ThreadData.nAlloc can be set. It would be nice to assert
++  ** that ThreadData.nAlloc is non-zero, but alas this breaks test cases 
++  ** written to invoke the pager directly.
++  */
++  ThreadData *pTsd = sqlite3ThreadData();
++  assert( pTsd );
++#endif
+ 
++  /* If malloc() has already failed return SQLITE_NOMEM. Before even
++  ** testing for this, set *ppPager to NULL so the caller knows the pager
++  ** structure was never allocated. 
++  */
+   *ppPager = 0;
+-  memset(&fd, 0, sizeof(fd));
+-  if( sqlite3_malloc_failed ){
++  if( sqlite3MallocFailed() ){
+     return SQLITE_NOMEM;
+   }
++  memset(&fd, 0, sizeof(fd));
++
++  /* Open the pager file and set zFullPathname to point at malloc()ed 
++  ** memory containing the complete filename (i.e. including the directory).
++  */
+   if( zFilename && zFilename[0] ){
+ #ifndef SQLITE_OMIT_MEMORYDB
+     if( strcmp(zFilename,":memory:")==0 ){
+       memDb = 1;
+       zFullPathname = sqliteStrDup("");
+-      rc = SQLITE_OK;
+     }else
+ #endif
+     {
+@@ -1632,66 +1624,75 @@
+       tempFile = 1;
+     }
+   }
+-  if( !zFullPathname ){
+-    sqlite3OsClose(&fd);
+-    return SQLITE_NOMEM;
++
++  /* Allocate the Pager structure. As part of the same allocation, allocate
++  ** space for the full paths of the file, directory and journal 
++  ** (Pager.zFilename, Pager.zDirectory and Pager.zJournal).
++  */
++  if( zFullPathname ){
++    nameLen = strlen(zFullPathname);
++    pPager = sqliteMalloc( sizeof(*pPager) + nameLen*3 + 30 );
+   }
+-  if( rc!=SQLITE_OK ){
++
++  /* If an error occured in either of the blocks above, free the memory 
++  ** pointed to by zFullPathname, free the Pager structure and close the 
++  ** file. Since the pager is not allocated there is no need to set 
++  ** any Pager.errMask variables.
++  */
++  if( !pPager || !zFullPathname || rc!=SQLITE_OK ){
+     sqlite3OsClose(&fd);
+     sqliteFree(zFullPathname);
+-    return rc;
++    sqliteFree(pPager);
++    return ((rc==SQLITE_OK)?SQLITE_NOMEM:rc);
+   }
+-  nameLen = strlen(zFullPathname);
+-  pPager = sqliteMalloc( sizeof(*pPager) + nameLen*3 + 30 );
+-  if( pPager==0 ){
+-    sqlite3OsClose(&fd);
+-    sqliteFree(zFullPathname);
+-    return SQLITE_NOMEM;
+-  }
++
+   TRACE3("OPEN %d %s\n", FILEHANDLEID(fd), zFullPathname);
+   pPager->zFilename = (char*)&pPager[1];
+   pPager->zDirectory = &pPager->zFilename[nameLen+1];
+   pPager->zJournal = &pPager->zDirectory[nameLen+1];
+   strcpy(pPager->zFilename, zFullPathname);
+   strcpy(pPager->zDirectory, zFullPathname);
++
+   for(i=nameLen; i>0 && pPager->zDirectory[i-1]!='/'; i--){}
+   if( i>0 ) pPager->zDirectory[i-1] = 0;
+   strcpy(pPager->zJournal, zFullPathname);
+   sqliteFree(zFullPathname);
+   strcpy(&pPager->zJournal[nameLen], "-journal");
+   pPager->fd = fd;
+-#if OS_UNIX
+-  pPager->fd.pPager = pPager;
+-#endif
+-  pPager->journalOpen = 0;
++  /* pPager->journalOpen = 0; */
+   pPager->useJournal = useJournal && !memDb;
+   pPager->noReadlock = noReadlock && readOnly;
+-  pPager->stmtOpen = 0;
+-  pPager->stmtInUse = 0;
+-  pPager->nRef = 0;
++  /* pPager->stmtOpen = 0; */
++  /* pPager->stmtInUse = 0; */
++  /* pPager->nRef = 0; */
+   pPager->dbSize = memDb-1;
+   pPager->pageSize = SQLITE_DEFAULT_PAGE_SIZE;
+-  pPager->stmtSize = 0;
+-  pPager->stmtJSize = 0;
+-  pPager->nPage = 0;
+-  pPager->nMaxPage = 0;
++  /* pPager->stmtSize = 0; */
++  /* pPager->stmtJSize = 0; */
++  /* pPager->nPage = 0; */
++  /* pPager->nMaxPage = 0; */
+   pPager->mxPage = 100;
+-  pPager->state = PAGER_UNLOCK;
+-  pPager->errMask = 0;
++  assert( PAGER_UNLOCK==0 );
++  /* pPager->state = PAGER_UNLOCK; */
++  /* pPager->errMask = 0; */
+   pPager->tempFile = tempFile;
+   pPager->memDb = memDb;
+   pPager->readOnly = readOnly;
+-  pPager->needSync = 0;
++  /* pPager->needSync = 0; */
+   pPager->noSync = pPager->tempFile || !useJournal;
+   pPager->fullSync = (pPager->noSync?0:1);
+-  pPager->pFirst = 0;
+-  pPager->pFirstSynced = 0;
+-  pPager->pLast = 0;
++  /* pPager->pFirst = 0; */
++  /* pPager->pFirstSynced = 0; */
++  /* pPager->pLast = 0; */
+   pPager->nExtra = FORCE_ALIGNMENT(nExtra);
+   pPager->sectorSize = PAGER_SECTOR_SIZE;
+-  pPager->pBusyHandler = 0;
+-  memset(pPager->aHash, 0, sizeof(pPager->aHash));
++  /* pPager->pBusyHandler = 0; */
++  /* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */
+   *ppPager = pPager;
++#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
++  pPager->pNext = pTsd->pPager;
++  pTsd->pPager = pPager;
++#endif
+   return SQLITE_OK;
+ }
+ 
+@@ -1739,14 +1740,50 @@
+ }
+ 
+ /*
++** The following set of routines are used to disable the simulated
++** I/O error mechanism.  These routines are used to avoid simulated
++** errors in places where we do not care about errors.
++**
++** Unless -DSQLITE_TEST=1 is used, these routines are all no-ops
++** and generate no code.
++*/
++#ifdef SQLITE_TEST
++extern int sqlite3_io_error_pending;
++extern int sqlite3_io_error_hit;
++static int saved_cnt;
++void clear_simulated_io_error(){
++  sqlite3_io_error_hit = 0;
++}
++void disable_simulated_io_errors(void){
++  saved_cnt = sqlite3_io_error_pending;
++  sqlite3_io_error_pending = -1;
++}
++void enable_simulated_io_errors(void){
++  sqlite3_io_error_pending = saved_cnt;
++}
++#else
++# define clear_simulated_io_error()
++# define disable_simulated_io_errors()
++# define enable_simulated_io_errors()
++#endif
++
++/*
+ ** Read the first N bytes from the beginning of the file into memory
+-** that pDest points to.  No error checking is done.
++** that pDest points to. 
++**
++** No error checking is done. The rational for this is that this function 
++** may be called even if the file does not exist or contain a header. In 
++** these cases sqlite3OsRead() will return an error, to which the correct 
++** response is to zero the memory at pDest and continue.  A real IO error 
++** will presumably recur and be picked up later (Todo: Think about this).
+ */
+ void sqlite3pager_read_fileheader(Pager *pPager, int N, unsigned char *pDest){
+   memset(pDest, 0, N);
+   if( MEMDB==0 ){
+-    sqlite3OsSeek(&pPager->fd, 0);
+-    sqlite3OsRead(&pPager->fd, pDest, N);
++    disable_simulated_io_errors();
++    sqlite3OsSeek(pPager->fd, 0);
++    sqlite3OsRead(pPager->fd, pDest, N);
++    enable_simulated_io_errors();
+   }
+ }
+ 
+@@ -1765,8 +1802,8 @@
+   if( pPager->dbSize>=0 ){
+     n = pPager->dbSize;
+   } else {
+-    if( sqlite3OsFileSize(&pPager->fd, &n)!=SQLITE_OK ){
+-      pPager->errMask |= PAGER_ERR_DISK;
++    if( sqlite3OsFileSize(pPager->fd, &n)!=SQLITE_OK ){
++      pager_error(pPager, SQLITE_IOERR);
+       return 0;
+     }
+     if( n>0 && n<pPager->pageSize ){
+@@ -1897,7 +1934,7 @@
+     rc = SQLITE_OK;
+   }else{
+     do {
+-      rc = sqlite3OsLock(&pPager->fd, locktype);
++      rc = sqlite3OsLock(pPager->fd, locktype);
+     }while( rc==SQLITE_BUSY && sqlite3InvokeBusyHandler(pPager->pBusyHandler) );
+     if( rc==SQLITE_OK ){
+       pPager->state = locktype;
+@@ -1912,8 +1949,8 @@
+ int sqlite3pager_truncate(Pager *pPager, Pgno nPage){
+   int rc;
+   sqlite3pager_pagecount(pPager);
+-  if( pPager->errMask!=0 ){
+-    rc = pager_errcode(pPager);
++  if( pPager->errCode ){
++    rc = pPager->errCode;
+     return rc;
+   }
+   if( nPage>=(unsigned)pPager->dbSize ){
+@@ -1950,9 +1987,25 @@
+ ** and their memory is freed.  Any attempt to use a page associated
+ ** with this page cache after this function returns will likely
+ ** result in a coredump.
++**
++** This function always succeeds. If a transaction is active an attempt
++** is made to roll it back. If an error occurs during the rollback 
++** a hot journal may be left in the filesystem but no error is returned
++** to the caller.
+ */
+ int sqlite3pager_close(Pager *pPager){
+   PgHdr *pPg, *pNext;
++#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
++  /* A malloc() cannot fail in sqlite3ThreadData() as one or more calls to 
++  ** malloc() must have already been made by this thread before it gets
++  ** to this point. This means the ThreadData must have been allocated already
++  ** so that ThreadData.nAlloc can be set.
++  */
++  ThreadData *pTsd = sqlite3ThreadData();
++  assert( pPager );
++  assert( pTsd && pTsd->nAlloc );
++#endif
++
+   switch( pPager->state ){
+     case PAGER_RESERVED:
+     case PAGER_SYNCED: 
+@@ -1961,24 +2014,18 @@
+       ** operation. So disable IO error simulation so that testing
+       ** works more easily.
+       */
+-#if defined(SQLITE_TEST) && (defined(OS_UNIX) || defined(OS_WIN))
+-      extern int sqlite3_io_error_pending;
+-      int ioerr_cnt = sqlite3_io_error_pending;
+-      sqlite3_io_error_pending = -1;
+-#endif
++      disable_simulated_io_errors();
+       sqlite3pager_rollback(pPager);
+-#if defined(SQLITE_TEST) && (defined(OS_UNIX) || defined(OS_WIN))
+-      sqlite3_io_error_pending = ioerr_cnt;
+-#endif
++      enable_simulated_io_errors();
+       if( !MEMDB ){
+-        sqlite3OsUnlock(&pPager->fd, NO_LOCK);
++        sqlite3OsUnlock(pPager->fd, NO_LOCK);
+       }
+-      assert( pPager->errMask || pPager->journalOpen==0 );
++      assert( pPager->errCode || pPager->journalOpen==0 );
+       break;
+     }
+     case PAGER_SHARED: {
+       if( !MEMDB ){
+-        sqlite3OsUnlock(&pPager->fd, NO_LOCK);
++        sqlite3OsUnlock(pPager->fd, NO_LOCK);
+       }
+       break;
+     }
+@@ -2000,7 +2047,7 @@
+     sqliteFree(pPg);
+   }
+   TRACE2("CLOSE %d\n", PAGERID(pPager));
+-  assert( pPager->errMask || (pPager->journalOpen==0 && pPager->stmtOpen==0) );
++  assert( pPager->errCode || (pPager->journalOpen==0 && pPager->stmtOpen==0) );
+   if( pPager->journalOpen ){
+     sqlite3OsClose(&pPager->jfd);
+   }
+@@ -2015,6 +2062,19 @@
+   ** }
+   */
+ 
++#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
++  /* Remove the pager from the linked list of pagers starting at 
++  ** ThreadData.pPager if memory-management is enabled.
++  */
++  if( pPager==pTsd->pPager ){
++    pTsd->pPager = pPager->pNext;
++  }else{
++    Pager *pTmp;
++    for(pTmp = pTsd->pPager; pTmp->pNext!=pPager; pTmp=pTmp->pNext);
++    pTmp->pNext = pPager->pNext;
++  }
++#endif
++
+   sqliteFree(pPager);
+   return SQLITE_OK;
+ }
+@@ -2120,7 +2180,7 @@
+         ** with the nRec computed from the size of the journal file.
+         */
+         i64 jSz;
+-        rc = sqlite3OsFileSize(&pPager->jfd, &jSz);
++        rc = sqlite3OsFileSize(pPager->jfd, &jSz);
+         if( rc!=0 ) return rc;
+         assert( pPager->journalOff==jSz );
+       }
+@@ -2133,20 +2193,20 @@
+         */
+         if( pPager->fullSync ){
+           TRACE2("SYNC journal of %d\n", PAGERID(pPager));
+-          rc = sqlite3OsSync(&pPager->jfd, 0);
++          rc = sqlite3OsSync(pPager->jfd, 0);
+           if( rc!=0 ) return rc;
+         }
+-        rc = sqlite3OsSeek(&pPager->jfd,
++        rc = sqlite3OsSeek(pPager->jfd,
+                            pPager->journalHdr + sizeof(aJournalMagic));
+         if( rc ) return rc;
+-        rc = write32bits(&pPager->jfd, pPager->nRec);
++        rc = write32bits(pPager->jfd, pPager->nRec);
+         if( rc ) return rc;
+ 
+-        rc = sqlite3OsSeek(&pPager->jfd, pPager->journalOff);
++        rc = sqlite3OsSeek(pPager->jfd, pPager->journalOff);
+         if( rc ) return rc;
+       }
+       TRACE2("SYNC journal of %d\n", PAGERID(pPager));
+-      rc = sqlite3OsSync(&pPager->jfd, pPager->fullSync);
++      rc = sqlite3OsSync(pPager->jfd, pPager->full_fsync);
+       if( rc!=0 ) return rc;
+       pPager->journalStarted = 1;
+     }
+@@ -2211,7 +2271,7 @@
+ 
+   while( pList ){
+     assert( pList->dirty );
+-    rc = sqlite3OsSeek(&pPager->fd, (pList->pgno-1)*(i64)pPager->pageSize);
++    rc = sqlite3OsSeek(pPager->fd, (pList->pgno-1)*(i64)pPager->pageSize);
+     if( rc ) return rc;
+     /* If there are dirty pages in the page cache with page numbers greater
+     ** than Pager.dbSize, this means sqlite3pager_truncate() was called to
+@@ -2221,7 +2281,8 @@
+     if( pList->pgno<=pPager->dbSize ){
+       CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 6);
+       TRACE3("STORE %d page %d\n", PAGERID(pPager), pList->pgno);
+-      rc = sqlite3OsWrite(&pPager->fd, PGHDR_TO_DATA(pList), pPager->pageSize);
++      rc = sqlite3OsWrite(pPager->fd, PGHDR_TO_DATA(pList),
++                             pPager->pageSize);
+       CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 0);
+       TEST_INCR(pPager->nWrite);
+     }
+@@ -2268,7 +2329,7 @@
+ static int hasHotJournal(Pager *pPager){
+   if( !pPager->useJournal ) return 0;
+   if( !sqlite3OsFileExists(pPager->zJournal) ) return 0;
+-  if( sqlite3OsCheckReservedLock(&pPager->fd) ) return 0;
++  if( sqlite3OsCheckReservedLock(pPager->fd) ) return 0;
+   if( sqlite3pager_pagecount(pPager)==0 ){
+     sqlite3OsDelete(pPager->zJournal);
+     return 0;
+@@ -2278,6 +2339,170 @@
+ }
+ 
+ /*
++** Try to find a page in the cache that can be recycled. 
++**
++** This routine may return SQLITE_IOERR, SQLITE_FULL or SQLITE_OK. It 
++** does not set the pPager->errCode variable.
++*/
++static int pager_recycle(Pager *pPager, int syncOk, PgHdr **ppPg){
++  PgHdr *pPg;
++  *ppPg = 0;
++
++  /* Find a page to recycle.  Try to locate a page that does not
++  ** require us to do an fsync() on the journal.
++  */
++  pPg = pPager->pFirstSynced;
++
++  /* If we could not find a page that does not require an fsync()
++  ** on the journal file then fsync the journal file.  This is a
++  ** very slow operation, so we work hard to avoid it.  But sometimes
++  ** it can't be helped.
++  */
++  if( pPg==0 && pPager->pFirst && syncOk && !MEMDB){
++    int rc = syncJournal(pPager);
++    if( rc!=0 ){
++      return rc;
++    }
++    if( pPager->fullSync ){
++      /* If in full-sync mode, write a new journal header into the
++      ** journal file. This is done to avoid ever modifying a journal
++      ** header that is involved in the rollback of pages that have
++      ** already been written to the database (in case the header is
++      ** trashed when the nRec field is updated).
++      */
++      pPager->nRec = 0;
++      assert( pPager->journalOff > 0 );
++      rc = writeJournalHdr(pPager);
++      if( rc!=0 ){
++        return rc;
++      }
++    }
++    pPg = pPager->pFirst;
++  }
++  if( pPg==0 ){
++    return SQLITE_OK;
++  }
++
++  assert( pPg->nRef==0 );
++
++  /* Write the page to the database file if it is dirty.
++  */
++  if( pPg->dirty ){
++    int rc;
++    assert( pPg->needSync==0 );
++    pPg->pDirty = 0;
++    rc = pager_write_pagelist( pPg );
++    if( rc!=SQLITE_OK ){
++      return rc;
++    }
++  }
++  assert( pPg->dirty==0 );
++
++  /* If the page we are recycling is marked as alwaysRollback, then
++  ** set the global alwaysRollback flag, thus disabling the
++  ** sqlite_dont_rollback() optimization for the rest of this transaction.
++  ** It is necessary to do this because the page marked alwaysRollback
++  ** might be reloaded at a later time but at that point we won't remember
++  ** that is was marked alwaysRollback.  This means that all pages must
++  ** be marked as alwaysRollback from here on out.
++  */
++  if( pPg->alwaysRollback ){
++    pPager->alwaysRollback = 1;
++  }
++
++  /* Unlink the old page from the free list and the hash table
++  */
++  unlinkPage(pPg);
++  TEST_INCR(pPager->nOvfl);
++
++  *ppPg = pPg;
++  return SQLITE_OK;
++}
++
++/*
++** This function is called to free superfluous dynamically allocated memory
++** held by the pager system. Memory in use by any SQLite pager allocated
++** by the current thread may be sqliteFree()ed.
++**
++** nReq is the number of bytes of memory required. Once this much has
++** been released, the function returns. A negative value for nReq means
++** free as much memory as possible. The return value is the total number 
++** of bytes of memory released.
++*/
++#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
++int sqlite3pager_release_memory(int nReq){
++  const ThreadData *pTsdro = sqlite3ThreadDataReadOnly();
++  Pager *p;
++  int nReleased = 0;
++  int i;
++
++  /* If the the global mutex is held, this subroutine becomes a
++  ** o-op; zero bytes of memory are freed.  This is because
++  ** some of the code invoked by this function may also
++  ** try to obtain the mutex, resulting in a deadlock.
++  */
++  if( sqlite3OsInMutex(0) ){
++    return 0;
++  }
++
++  /* Outermost loop runs for at most two iterations. First iteration we
++  ** try to find memory that can be released without calling fsync(). Second
++  ** iteration (which only runs if the first failed to free nReq bytes of
++  ** memory) is permitted to call fsync(). This is of course much more 
++  ** expensive.
++  */
++  for(i=0; i<=1; i++){
++
++    /* Loop through all the SQLite pagers opened by the current thread. */
++    for(p=pTsdro->pPager; p && (nReq<0 || nReleased<nReq); p=p->pNext){
++      PgHdr *pPg;
++      int rc;
++
++      /* For each pager, try to free as many pages as possible (without 
++      ** calling fsync() if this is the first iteration of the outermost 
++      ** loop).
++      */
++      while( SQLITE_OK==(rc = pager_recycle(p, i, &pPg)) && pPg) {
++        /* We've found a page to free. At this point the page has been 
++        ** removed from the page hash-table, free-list and synced-list 
++        ** (pFirstSynced). It is still in the all pages (pAll) list. 
++        ** Remove it from this list before freeing.
++        **
++        ** Todo: Check the Pager.pStmt list to make sure this is Ok. It 
++        ** probably is though.
++        */
++        PgHdr *pTmp;
++        assert( pPg );
++        page_remove_from_stmt_list(pPg);
++        if( pPg==p->pAll ){
++           p->pAll = pPg->pNextAll;
++        }else{
++          for( pTmp=p->pAll; pTmp->pNextAll!=pPg; pTmp=pTmp->pNextAll );
++          pTmp->pNextAll = pPg->pNextAll;
++        }
++        nReleased += sqliteAllocSize(pPg);
++        sqliteFree(pPg);
++      }
++
++      if( rc!=SQLITE_OK ){
++        /* An error occured whilst writing to the database file or 
++        ** journal in pager_recycle(). The error is not returned to the 
++        ** caller of this function. Instead, set the Pager.errCode variable.
++        ** The error will be returned to the user (or users, in the case 
++        ** of a shared pager cache) of the pager for which the error occured.
++        */
++        assert( rc==SQLITE_IOERR || rc==SQLITE_FULL );
++        assert( p->state>=PAGER_RESERVED );
++        pager_error(p, rc);
++      }
++    }
++  }
++
++  return nReleased;
++}
++#endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */
++
++/*
+ ** Acquire a page.
+ **
+ ** A read lock on the disk file is obtained when the first page is acquired. 
+@@ -2315,8 +2540,8 @@
+   */ 
+   assert( pPager!=0 );
+   *ppPage = 0;
+-  if( pPager->errMask & ~(PAGER_ERR_FULL) ){
+-    return pager_errcode(pPager);
++  if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){
++    return pPager->errCode;
+   }
+ 
+   /* If this is the first page accessed, then get a SHARED lock
+@@ -2326,7 +2551,7 @@
+     if( !pPager->noReadlock ){
+       rc = pager_wait_on_lock(pPager, SHARED_LOCK);
+       if( rc!=SQLITE_OK ){
+-        return rc;
++        return pager_error(pPager, rc);
+       }
+     }
+ 
+@@ -2334,8 +2559,6 @@
+     ** database file, then it either needs to be played back or deleted.
+     */
+     if( hasHotJournal(pPager) ){
+-       int rc;
+-
+        /* Get an EXCLUSIVE lock on the database file. At this point it is
+        ** important that a RESERVED lock is not obtained on the way to the
+        ** EXCLUSIVE lock. If it were, another process might open the
+@@ -2347,11 +2570,11 @@
+        ** second process will get to this point in the code and fail to
+        ** obtain it's own EXCLUSIVE lock on the database file.
+        */
+-       rc = sqlite3OsLock(&pPager->fd, EXCLUSIVE_LOCK);
++       rc = sqlite3OsLock(pPager->fd, EXCLUSIVE_LOCK);
+        if( rc!=SQLITE_OK ){
+-         sqlite3OsUnlock(&pPager->fd, NO_LOCK);
++         sqlite3OsUnlock(pPager->fd, NO_LOCK);
+          pPager->state = PAGER_UNLOCK;
+-         return rc;
++         return pager_error(pPager, rc);
+        }
+        pPager->state = PAGER_EXCLUSIVE;
+ 
+@@ -2365,7 +2588,7 @@
+        */
+        rc = sqlite3OsOpenReadOnly(pPager->zJournal, &pPager->jfd);
+        if( rc!=SQLITE_OK ){
+-         sqlite3OsUnlock(&pPager->fd, NO_LOCK);
++         sqlite3OsUnlock(pPager->fd, NO_LOCK);
+          pPager->state = PAGER_UNLOCK;
+          return SQLITE_BUSY;
+        }
+@@ -2380,7 +2603,7 @@
+        */
+        rc = pager_playback(pPager);
+        if( rc!=SQLITE_OK ){
+-         return rc;
++         return pager_error(pPager, rc);
+        }
+     }
+     pPg = 0;
+@@ -2401,7 +2624,6 @@
+                               + sizeof(u32) + pPager->nExtra
+                               + MEMDB*sizeof(PgHistory) );
+       if( pPg==0 ){
+-        pPager->errMask |= PAGER_ERR_MEM;
+         return SQLITE_NOMEM;
+       }
+       memset(pPg, 0, sizeof(*pPg));
+@@ -2417,70 +2639,11 @@
+         pPager->nMaxPage++;
+       }
+     }else{
+-      /* Find a page to recycle.  Try to locate a page that does not
+-      ** require us to do an fsync() on the journal.
+-      */
+-      pPg = pPager->pFirstSynced;
+-
+-      /* If we could not find a page that does not require an fsync()
+-      ** on the journal file then fsync the journal file.  This is a
+-      ** very slow operation, so we work hard to avoid it.  But sometimes
+-      ** it can't be helped.
+-      */
+-      if( pPg==0 ){
+-        int rc = syncJournal(pPager);
+-        if( rc!=0 ){
+-          sqlite3pager_rollback(pPager);
+-          return SQLITE_IOERR;
+-        }
+-        if( pPager->fullSync ){
+-          /* If in full-sync mode, write a new journal header into the
+-	  ** journal file. This is done to avoid ever modifying a journal
+-	  ** header that is involved in the rollback of pages that have
+-	  ** already been written to the database (in case the header is
+-	  ** trashed when the nRec field is updated).
+-          */
+-          pPager->nRec = 0;
+-          assert( pPager->journalOff > 0 );
+-          rc = writeJournalHdr(pPager);
+-          if( rc!=0 ){
+-            sqlite3pager_rollback(pPager);
+-            return SQLITE_IOERR;
+-          }
+-        }
+-        pPg = pPager->pFirst;
++      rc = pager_recycle(pPager, 1, &pPg);
++      if( rc!=SQLITE_OK ){
++        return rc;
+       }
+-      assert( pPg->nRef==0 );
+-
+-      /* Write the page to the database file if it is dirty.
+-      */
+-      if( pPg->dirty ){
+-        assert( pPg->needSync==0 );
+-        pPg->pDirty = 0;
+-        rc = pager_write_pagelist( pPg );
+-        if( rc!=SQLITE_OK ){
+-          sqlite3pager_rollback(pPager);
+-          return SQLITE_IOERR;
+-        }
+-      }
+-      assert( pPg->dirty==0 );
+-
+-      /* If the page we are recycling is marked as alwaysRollback, then
+-      ** set the global alwaysRollback flag, thus disabling the
+-      ** sqlite_dont_rollback() optimization for the rest of this transaction.
+-      ** It is necessary to do this because the page marked alwaysRollback
+-      ** might be reloaded at a later time but at that point we won't remember
+-      ** that is was marked alwaysRollback.  This means that all pages must
+-      ** be marked as alwaysRollback from here on out.
+-      */
+-      if( pPg->alwaysRollback ){
+-        pPager->alwaysRollback = 1;
+-      }
+-
+-      /* Unlink the old page from the free list and the hash table
+-      */
+-      unlinkPage(pPg);
+-      TEST_INCR(pPager->nOvfl);
++      assert(pPg) ;
+     }
+     pPg->pgno = pgno;
+     if( pPager->aInJournal && (int)pgno<=pPager->origDbSize ){
+@@ -2501,46 +2664,58 @@
+     pPg->dirty = 0;
+     pPg->nRef = 1;
+     REFINFO(pPg);
++
+     pPager->nRef++;
+-    h = pager_hash(pgno);
+-    pPg->pNextHash = pPager->aHash[h];
+-    pPager->aHash[h] = pPg;
+-    if( pPg->pNextHash ){
+-      assert( pPg->pNextHash->pPrevHash==0 );
+-      pPg->pNextHash->pPrevHash = pPg;
+-    }
+     if( pPager->nExtra>0 ){
+       memset(PGHDR_TO_EXTRA(pPg, pPager), 0, pPager->nExtra);
+     }
+-    if( pPager->errMask!=0 ){
++    if( pPager->errCode ){
+       sqlite3pager_unref(PGHDR_TO_DATA(pPg));
+-      rc = pager_errcode(pPager);
++      rc = pPager->errCode;
+       return rc;
+     }
+-    if( sqlite3pager_pagecount(pPager)<(int)pgno ){
++
++    /* Populate the page with data, either by reading from the database
++    ** file, or by setting the entire page to zero.
++    */
++    if( sqlite3pager_pagecount(pPager)<(int)pgno || MEMDB ){
+       memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize);
+     }else{
+-      int rc;
+       assert( MEMDB==0 );
+-      rc = sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize);
++      rc = sqlite3OsSeek(pPager->fd, (pgno-1)*(i64)pPager->pageSize);
+       if( rc==SQLITE_OK ){
+-        rc = sqlite3OsRead(&pPager->fd, PGHDR_TO_DATA(pPg), pPager->pageSize);
++        rc = sqlite3OsRead(pPager->fd, PGHDR_TO_DATA(pPg),
++                              pPager->pageSize);
+       }
+       TRACE3("FETCH %d page %d\n", PAGERID(pPager), pPg->pgno);
+       CODEC(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
+       if( rc!=SQLITE_OK ){
+         i64 fileSize;
+-        if( sqlite3OsFileSize(&pPager->fd,&fileSize)!=SQLITE_OK
+-               || fileSize>=pgno*pPager->pageSize ){
++        int rc2 = sqlite3OsFileSize(pPager->fd, &fileSize);
++        if( rc2!=SQLITE_OK || fileSize>=pgno*pPager->pageSize ){
++	  /* An IO error occured in one of the the sqlite3OsSeek() or
++          ** sqlite3OsRead() calls above. */
++          pPg->pgno = 0;
+           sqlite3pager_unref(PGHDR_TO_DATA(pPg));
+           return rc;
+         }else{
++          clear_simulated_io_error();
+           memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize);
+         }
+       }else{
+         TEST_INCR(pPager->nRead);
+       }
+     }
++
++    /* Link the page into the page hash table */
++    h = pager_hash(pgno);
++    pPg->pNextHash = pPager->aHash[h];
++    pPager->aHash[h] = pPg;
++    if( pPg->pNextHash ){
++      assert( pPg->pNextHash->pPrevHash==0 );
++      pPg->pNextHash->pPrevHash = pPg;
++    }
++
+ #ifdef SQLITE_CHECK_PAGES
+     pPg->pageHash = pager_pagehash(pPg);
+ #endif
+@@ -2569,7 +2744,7 @@
+ 
+   assert( pPager!=0 );
+   assert( pgno!=0 );
+-  if( pPager->errMask & ~(PAGER_ERR_FULL) ){
++  if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){
+     return 0;
+   }
+   pPg = pager_lookup(pPager, pgno);
+@@ -2651,23 +2826,24 @@
+     rc = SQLITE_NOMEM;
+     goto failed_to_open_journal;
+   }
+-  rc = sqlite3OsOpenExclusive(pPager->zJournal, &pPager->jfd,pPager->tempFile);
++  rc = sqlite3OsOpenExclusive(pPager->zJournal, &pPager->jfd,
++                                 pPager->tempFile);
+   pPager->journalOff = 0;
+   pPager->setMaster = 0;
+   pPager->journalHdr = 0;
+   if( rc!=SQLITE_OK ){
+     goto failed_to_open_journal;
+   }
+-  SET_FULLSYNC(pPager->jfd, pPager->fullSync);
+-  SET_FULLSYNC(pPager->fd, pPager->fullSync);
+-  sqlite3OsOpenDirectory(pPager->zDirectory, &pPager->jfd);
++  sqlite3OsSetFullSync(pPager->jfd, pPager->full_fsync);
++  sqlite3OsSetFullSync(pPager->fd, pPager->full_fsync);
++  sqlite3OsOpenDirectory(pPager->jfd, pPager->zDirectory);
+   pPager->journalOpen = 1;
+   pPager->journalStarted = 0;
+   pPager->needSync = 0;
+   pPager->alwaysRollback = 0;
+   pPager->nRec = 0;
+-  if( pPager->errMask!=0 ){
+-    rc = pager_errcode(pPager);
++  if( pPager->errCode ){
++    rc = pPager->errCode;
+     goto failed_to_open_journal;
+   }
+   pPager->origDbSize = pPager->dbSize;
+@@ -2677,7 +2853,7 @@
+   if( pPager->stmtAutoopen && rc==SQLITE_OK ){
+     rc = sqlite3pager_stmt_begin(pPager);
+   }
+-  if( rc!=SQLITE_OK ){
++  if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){
+     rc = pager_unwritelock(pPager);
+     if( rc==SQLITE_OK ){
+       rc = SQLITE_FULL;
+@@ -2688,8 +2864,17 @@
+ failed_to_open_journal:
+   sqliteFree(pPager->aInJournal);
+   pPager->aInJournal = 0;
+-  sqlite3OsUnlock(&pPager->fd, NO_LOCK);
+-  pPager->state = PAGER_UNLOCK;
++  if( rc==SQLITE_NOMEM ){
++    /* If this was a malloc() failure, then we will not be closing the pager
++    ** file. So delete any journal file we may have just created. Otherwise,
++    ** the system will get confused, we have a read-lock on the file and a
++    ** mysterious journal has appeared in the filesystem.
++    */
++    sqlite3OsDelete(pPager->zJournal);
++  }else{
++    sqlite3OsUnlock(pPager->fd, NO_LOCK);
++    pPager->state = PAGER_UNLOCK;
++  }
+   return rc;
+ }
+ 
+@@ -2732,7 +2917,7 @@
+       pPager->state = PAGER_EXCLUSIVE;
+       pPager->origDbSize = pPager->dbSize;
+     }else{
+-      rc = sqlite3OsLock(&pPager->fd, RESERVED_LOCK);
++      rc = sqlite3OsLock(pPager->fd, RESERVED_LOCK);
+       if( rc==SQLITE_OK ){
+         pPager->state = PAGER_RESERVED;
+         if( exFlag ){
+@@ -2776,8 +2961,8 @@
+ 
+   /* Check for errors
+   */
+-  if( pPager->errMask ){ 
+-    return pager_errcode(pPager);
++  if( pPager->errCode ){ 
++    return pPager->errCode;
+   }
+   if( pPager->readOnly ){
+     return SQLITE_PERM;
+@@ -2843,17 +3028,21 @@
+           store32bits(cksum, pPg, pPager->pageSize);
+           szPg = pPager->pageSize+8;
+           store32bits(pPg->pgno, pPg, -4);
+-          rc = sqlite3OsWrite(&pPager->jfd, &((char*)pData)[-4], szPg);
++
++          rc = sqlite3OsWrite(pPager->jfd, &((char*)pData)[-4], szPg);
+           pPager->journalOff += szPg;
+           TRACE4("JOURNAL %d page %d needSync=%d\n",
+                   PAGERID(pPager), pPg->pgno, pPg->needSync);
+           CODEC(pPager, pData, pPg->pgno, 0);
+           *(u32*)PGHDR_TO_EXTRA(pPg, pPager) = saved;
++
++	  /* An error has occured writing to the journal file. The 
++          ** transaction will be rolled back by the layer above.
++          */
+           if( rc!=SQLITE_OK ){
+-            sqlite3pager_rollback(pPager);
+-            pPager->errMask |= PAGER_ERR_FULL;
+             return rc;
+           }
++
+           pPager->nRec++;
+           assert( pPager->aInJournal!=0 );
+           pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7);
+@@ -2892,12 +3081,11 @@
+       }else{
+         store32bits(pPg->pgno, pPg, -4);
+         CODEC(pPager, pData, pPg->pgno, 7);
+-        rc = sqlite3OsWrite(&pPager->stfd,((char*)pData)-4, pPager->pageSize+4);
++        rc = sqlite3OsWrite(pPager->stfd,((char*)pData)-4,
++                               pPager->pageSize+4);
+         TRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno);
+         CODEC(pPager, pData, pPg->pgno, 0);
+         if( rc!=SQLITE_OK ){
+-          sqlite3pager_rollback(pPager);
+-          pPager->errMask |= PAGER_ERR_FULL;
+           return rc;
+         }
+         pPager->stmtNRec++;
+@@ -2924,10 +3112,12 @@
+ ** to sqlite3pager_write().  In other words, return TRUE if it is ok
+ ** to change the content of the page.
+ */
++#ifndef NDEBUG
+ int sqlite3pager_iswriteable(void *pData){
+   PgHdr *pPg = DATA_TO_PGHDR(pData);
+   return pPg->dirty;
+ }
++#endif
+ 
+ #ifndef SQLITE_OMIT_VACUUM
+ /*
+@@ -2981,7 +3171,7 @@
+ 
+   pPg = pager_lookup(pPager, pgno);
+   pPg->alwaysRollback = 1;
+-  if( pPg && pPg->dirty ){
++  if( pPg && pPg->dirty && !pPager->stmtInUse ){
+     if( pPager->dbSize==(int)pPg->pgno && pPager->origDbSize<pPager->dbSize ){
+       /* If this pages is the last page in the file and the file has grown
+       ** during the current transaction, then do NOT mark the page as clean.
+@@ -3057,17 +3247,9 @@
+   int rc;
+   PgHdr *pPg;
+ 
+-  if( pPager->errMask==PAGER_ERR_FULL ){
+-    rc = sqlite3pager_rollback(pPager);
+-    if( rc==SQLITE_OK ){
+-      rc = SQLITE_FULL;
+-    }
+-    return rc;
++  if( pPager->errCode ){
++    return pPager->errCode;
+   }
+-  if( pPager->errMask!=0 ){
+-    rc = pager_errcode(pPager);
+-    return rc;
+-  }
+   if( pPager->state<PAGER_RESERVED ){
+     return SQLITE_ERROR;
+   }
+@@ -3104,18 +3286,11 @@
+   }
+   assert( pPager->journalOpen );
+   rc = sqlite3pager_sync(pPager, 0, 0);
+-  if( rc!=SQLITE_OK ){
+-    goto commit_abort;
++  if( rc==SQLITE_OK ){
++    rc = pager_unwritelock(pPager);
++    pPager->dbSize = -1;
+   }
+-  rc = pager_unwritelock(pPager);
+-  pPager->dbSize = -1;
+   return rc;
+-
+-  /* Jump here if anything goes wrong during the commit process.
+-  */
+-commit_abort:
+-  sqlite3pager_rollback(pPager);
+-  return rc;
+ }
+ 
+ /*
+@@ -3176,11 +3351,11 @@
+     return rc;
+   }
+ 
+-  if( pPager->errMask!=0 && pPager->errMask!=PAGER_ERR_FULL ){
++  if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){
+     if( pPager->state>=PAGER_EXCLUSIVE ){
+       pager_playback(pPager);
+     }
+-    return pager_errcode(pPager);
++    return pPager->errCode;
+   }
+   if( pPager->state==PAGER_RESERVED ){
+     int rc2;
+@@ -3192,12 +3367,13 @@
+   }else{
+     rc = pager_playback(pPager);
+   }
+-  if( rc!=SQLITE_OK ){
+-    rc = SQLITE_CORRUPT_BKPT;
+-    pPager->errMask |= PAGER_ERR_CORRUPT;
+-  }
+   pPager->dbSize = -1;
+-  return rc;
++
++  /* If an error occurs during a ROLLBACK, we can no longer trust the pager
++  ** cache. So call pager_error() on the way out to make any error 
++  ** persistent.
++  */
++  return pager_error(pPager, rc);
+ }
+ 
+ /*
+@@ -3218,7 +3394,7 @@
+   a[2] = pPager->mxPage;
+   a[3] = pPager->dbSize;
+   a[4] = pPager->state;
+-  a[5] = pPager->errMask;
++  a[5] = pPager->errCode;
+ #ifdef SQLITE_TEST
+   a[6] = pPager->nHit;
+   a[7] = pPager->nMiss;
+@@ -3254,11 +3430,11 @@
+   assert( pPager->journalOpen );
+   pPager->aInStmt = sqliteMalloc( pPager->dbSize/8 + 1 );
+   if( pPager->aInStmt==0 ){
+-    sqlite3OsLock(&pPager->fd, SHARED_LOCK);
++    /* sqlite3OsLock(pPager->fd, SHARED_LOCK); */
+     return SQLITE_NOMEM;
+   }
+ #ifndef NDEBUG
+-  rc = sqlite3OsFileSize(&pPager->jfd, &pPager->stmtJSize);
++  rc = sqlite3OsFileSize(pPager->jfd, &pPager->stmtJSize);
+   if( rc ) goto stmt_begin_failed;
+   assert( pPager->stmtJSize == pPager->journalOff );
+ #endif
+@@ -3291,8 +3467,8 @@
+     PgHdr *pPg, *pNext;
+     TRACE2("STMT-COMMIT %d\n", PAGERID(pPager));
+     if( !MEMDB ){
+-      sqlite3OsSeek(&pPager->stfd, 0);
+-      /* sqlite3OsTruncate(&pPager->stfd, 0); */
++      sqlite3OsSeek(pPager->stfd, 0);
++      /* sqlite3OsTruncate(pPager->stfd, 0); */
+       sqliteFree( pPager->aInStmt );
+       pPager->aInStmt = 0;
+     }
+@@ -3495,7 +3671,7 @@
+ 
+     /* Sync the database file. */
+     if( !pPager->noSync ){
+-      rc = sqlite3OsSync(&pPager->fd, 0);
++      rc = sqlite3OsSync(pPager->fd, 0);
+     }
+ 
+     pPager->state = PAGER_SYNCED;
+@@ -3609,11 +3785,7 @@
+ ** PENDING_LOCK, or EXCLUSIVE_LOCK.
+ */
+ int sqlite3pager_lockstate(Pager *pPager){
+-#ifdef OS_TEST
+-  return pPager->fd->fd.locktype;
+-#else
+-  return pPager->fd.locktype;
+-#endif
++  return sqlite3OsLockState(pPager->fd);
+ }
+ #endif
+ 
+Index: sqlite/os_common.h
+===================================================================
+--- amarok/src/sqlite/os_common.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/os_common.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -88,6 +88,7 @@
+ ** is used for testing the I/O recovery logic.
+ */
+ #ifdef SQLITE_TEST
++int sqlite3_io_error_hit = 0;
+ int sqlite3_io_error_pending = 0;
+ int sqlite3_diskfull_pending = 0;
+ int sqlite3_diskfull = 0;
+@@ -95,7 +96,7 @@
+    if( sqlite3_io_error_pending ) \
+      if( sqlite3_io_error_pending-- == 1 ){ local_ioerr(); return A; }
+ static void local_ioerr(){
+-  sqlite3_io_error_pending = 0;  /* Really just a place to set a breakpoint */
++  sqlite3_io_error_hit = 1;  /* Really just a place to set a breakpoint */
+ }
+ #define SimulateDiskfullError \
+    if( sqlite3_diskfull_pending ){ \
+@@ -121,3 +122,67 @@
+ #else
+ #define OpenCounter(X)
+ #endif
++
++/*
++** sqlite3GenericMalloc
++** sqlite3GenericRealloc
++** sqlite3GenericOsFree
++** sqlite3GenericAllocationSize
++**
++** Implementation of the os level dynamic memory allocation interface in terms
++** of the standard malloc(), realloc() and free() found in many operating
++** systems. No rocket science here.
++**
++** There are two versions of these four functions here. The version
++** implemented here is only used if memory-management or memory-debugging is
++** enabled. This version allocates an extra 8-bytes at the beginning of each
++** block and stores the size of the allocation there.
++**
++** If neither memory-management or debugging is enabled, the second
++** set of implementations is used instead.
++*/
++#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) || defined (SQLITE_MEMDEBUG)
++void *sqlite3GenericMalloc(int n){
++  char *p = (char *)malloc(n+8);
++  assert(n>0);
++  assert(sizeof(int)<=8);
++  if( p ){
++    *(int *)p = n;
++    p += 8;
++  }
++  return (void *)p;
++}
++void *sqlite3GenericRealloc(void *p, int n){
++  char *p2 = ((char *)p - 8);
++  assert(n>0);
++  p2 = (char*)realloc(p2, n+8);
++  if( p2 ){
++    *(int *)p2 = n;
++    p2 += 8;
++  }
++  return (void *)p2;
++}
++void sqlite3GenericFree(void *p){
++  assert(p);
++  free((void *)((char *)p - 8));
++}
++int sqlite3GenericAllocationSize(void *p){
++  return p ? *(int *)((char *)p - 8) : 0;
++}
++#else
++void *sqlite3GenericMalloc(int n){
++  char *p = (char *)malloc(n);
++  return (void *)p;
++}
++void *sqlite3GenericRealloc(void *p, int n){
++  assert(n>0);
++  p = realloc(p, n);
++  return p;
++}
++void sqlite3GenericFree(void *p){
++  assert(p);
++  free(p);
++}
++/* Never actually used, but needed for the linker */
++int sqlite3GenericAllocationSize(void *p){ return 0; }
++#endif
+Index: sqlite/utf.c
+===================================================================
+--- amarok/src/sqlite/utf.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/utf.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -272,7 +272,7 @@
+       assert( rc==SQLITE_NOMEM );
+       return SQLITE_NOMEM;
+     }
+-    zIn = pMem->z;
++    zIn = (u8*)pMem->z;
+     zTerm = &zIn[pMem->n];
+     while( zIn<zTerm ){
+       temp = *zIn;
+@@ -308,7 +308,7 @@
+   ** obtained from malloc(), or Mem.zShort, if it large enough and not in
+   ** use, or the zShort array on the stack (see above).
+   */
+-  zIn = pMem->z;
++  zIn = (u8*)pMem->z;
+   zTerm = &zIn[pMem->n];
+   if( len>NBFS ){
+     zOut = sqliteMallocRaw(len);
+@@ -360,12 +360,12 @@
+   pMem->enc = desiredEnc;
+   if( zOut==zShort ){
+     memcpy(pMem->zShort, zOut, len);
+-    zOut = pMem->zShort;
++    zOut = (u8*)pMem->zShort;
+     pMem->flags |= (MEM_Term|MEM_Short);
+   }else{
+     pMem->flags |= (MEM_Term|MEM_Dyn);
+   }
+-  pMem->z = zOut;
++  pMem->z = (char*)zOut;
+ 
+ translate_out:
+ #if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
+@@ -451,6 +451,23 @@
+ 
+ #ifndef SQLITE_OMIT_UTF16
+ /*
++** Convert a UTF-16 string in the native encoding into a UTF-8 string.
++** Memory to hold the UTF-8 string is obtained from malloc and must be
++** freed by the calling function.
++**
++** NULL is returned if there is an allocation error.
++*/
++char *sqlite3utf16to8(const void *z, int nByte){
++  Mem m;
++  memset(&m, 0, sizeof(m));
++  sqlite3VdbeMemSetStr(&m, z, nByte, SQLITE_UTF16NATIVE, SQLITE_STATIC);
++  sqlite3VdbeChangeEncoding(&m, SQLITE_UTF8);
++  assert( m.flags & MEM_Term );
++  assert( m.flags & MEM_Str );
++  return (m.flags & MEM_Dyn)!=0 ? m.z : sqliteStrDup(m.z);
++}
++
++/*
+ ** pZ is a UTF-16 encoded unicode string. If nChar is less than zero,
+ ** return the number of bytes up to (but not including), the first pair
+ ** of consecutive 0x00 bytes in pZ. If nChar is not less than zero,
+@@ -462,6 +479,15 @@
+   char const *z = zIn;
+   int n = 0;
+   if( SQLITE_UTF16NATIVE==SQLITE_UTF16BE ){
++    /* Using an "if (SQLITE_UTF16NATIVE==SQLITE_UTF16BE)" construct here
++    ** and in other parts of this file means that at one branch will
++    ** not be covered by coverage testing on any single host. But coverage
++    ** will be complete if the tests are run on both a little-endian and 
++    ** big-endian host. Because both the UTF16NATIVE and SQLITE_UTF16BE
++    ** macros are constant at compile time the compiler can determine
++    ** which branch will be followed. It is therefore assumed that no runtime
++    ** penalty is paid for this "if" statement.
++    */
+     while( c && ((nChar<0) || n<nChar) ){
+       READ_UTF16BE(z, c);
+       n++;
+Index: sqlite/vacuum.c
+===================================================================
+--- amarok/src/sqlite/vacuum.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/vacuum.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -17,6 +17,7 @@
+ ** $Id$
+ */
+ #include "sqliteInt.h"
++#include "vdbeInt.h"
+ #include "os.h"
+ 
+ #ifndef SQLITE_OMIT_VACUUM
+@@ -58,7 +59,7 @@
+   if( rc!=SQLITE_OK ) return rc;
+ 
+   while( SQLITE_ROW==sqlite3_step(pStmt) ){
+-    rc = execSql(db, sqlite3_column_text(pStmt, 0));
++    rc = execSql(db, (char*)sqlite3_column_text(pStmt, 0));
+     if( rc!=SQLITE_OK ){
+       sqlite3_finalize(pStmt);
+       return rc;
+@@ -100,11 +101,12 @@
+   Btree *pMain;           /* The database being vacuumed */
+   Btree *pTemp;
+   char *zSql = 0;
+-  int writeschema_flag;   /* Saved value of the write-schema flag */
++  int saved_flags;       /* Saved value of the db->flags */
++  Db *pDb = 0;           /* Database to detach at end of vacuum */
+ 
+   /* Save the current value of the write-schema flag before setting it. */
+-  writeschema_flag = db->flags&SQLITE_WriteSchema;
+-  db->flags |= SQLITE_WriteSchema;
++  saved_flags = db->flags;
++  db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
+ 
+   if( !db->autoCommit ){
+     sqlite3SetString(pzErrMsg, "cannot VACUUM from within a transaction", 
+@@ -164,19 +166,23 @@
+   sqliteFree(zSql);
+   zSql = 0;
+   if( rc!=SQLITE_OK ) goto end_of_vacuum;
++  pDb = &db->aDb[db->nDb-1];
+   assert( strcmp(db->aDb[db->nDb-1].zName,"vacuum_db")==0 );
+   pTemp = db->aDb[db->nDb-1].pBt;
+   sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain),
+      sqlite3BtreeGetReserve(pMain));
+   assert( sqlite3BtreeGetPageSize(pTemp)==sqlite3BtreeGetPageSize(pMain) );
+-  execSql(db, "PRAGMA vacuum_db.synchronous=OFF");
++  rc = execSql(db, "PRAGMA vacuum_db.synchronous=OFF");
++  if( rc!=SQLITE_OK ){
++    goto end_of_vacuum;
++  }
+ 
+ #ifndef SQLITE_OMIT_AUTOVACUUM
+   sqlite3BtreeSetAutoVacuum(pTemp, sqlite3BtreeGetAutoVacuum(pMain));
+ #endif
+ 
+   /* Begin a transaction */
+-  rc = execSql(db, "BEGIN;");
++  rc = execSql(db, "BEGIN EXCLUSIVE;");
+   if( rc!=SQLITE_OK ) goto end_of_vacuum;
+ 
+   /* Query the schema of the main database. Create a mirror schema
+@@ -247,7 +253,7 @@
+   ** opened for writing. This way, the SQL transaction used to create the
+   ** temporary database never needs to be committed.
+   */
+-  if( sqlite3BtreeIsInTrans(pTemp) ){
++  if( rc==SQLITE_OK ){
+     u32 meta;
+     int i;
+ 
+@@ -264,26 +270,27 @@
+        6, 0,    /* Preserve the user version */
+     };
+ 
+-    assert( 0==sqlite3BtreeIsInTrans(pMain) );
+-    rc = sqlite3BtreeBeginTrans(pMain, 1);
+-    if( rc!=SQLITE_OK ) goto end_of_vacuum;
++    assert( 1==sqlite3BtreeIsInTrans(pTemp) );
++    assert( 1==sqlite3BtreeIsInTrans(pMain) );
+ 
+     /* Copy Btree meta values */
+     for(i=0; i<sizeof(aCopy)/sizeof(aCopy[0]); i+=2){
+       rc = sqlite3BtreeGetMeta(pMain, aCopy[i], &meta);
+       if( rc!=SQLITE_OK ) goto end_of_vacuum;
+       rc = sqlite3BtreeUpdateMeta(pTemp, aCopy[i], meta+aCopy[i+1]);
++      if( rc!=SQLITE_OK ) goto end_of_vacuum;
+     }
+ 
+     rc = sqlite3BtreeCopyFile(pMain, pTemp);
+     if( rc!=SQLITE_OK ) goto end_of_vacuum;
++    rc = sqlite3BtreeCommit(pTemp);
++    if( rc!=SQLITE_OK ) goto end_of_vacuum;
+     rc = sqlite3BtreeCommit(pMain);
+   }
+ 
+ end_of_vacuum:
+-  /* Restore the original value of the write-schema flag. */
+-  db->flags &= ~SQLITE_WriteSchema;
+-  db->flags |= writeschema_flag;
++  /* Restore the original value of db->flags */
++  db->flags = saved_flags;
+ 
+   /* Currently there is an SQL level transaction open on the vacuum
+   ** database. No locks are held on any other files (since the main file
+@@ -293,16 +300,28 @@
+   ** is closed by the DETACH.
+   */
+   db->autoCommit = 1;
+-  if( rc==SQLITE_OK ){
+-    rc = execSql(db, "DETACH vacuum_db;");
+-  }else{
+-    execSql(db, "DETACH vacuum_db;");
++
++  if( pDb ){
++    sqlite3MallocDisallow();
++    sqlite3BtreeClose(pDb->pBt);
++    sqlite3MallocAllow();
++    pDb->pBt = 0;
++    pDb->pSchema = 0;
+   }
++
++  /* If one of the execSql() calls above returned SQLITE_NOMEM, then the
++  ** mallocFailed flag will be clear (because execSql() calls sqlite3_exec()).
++  ** Fix this so the flag and return code match.
++  */
++  if( rc==SQLITE_NOMEM ){
++    sqlite3MallocFailed();
++  }
++
+   if( zTemp ){
+     sqlite3OsDelete(zTemp);
+     sqliteFree(zTemp);
+   }
+-  if( zSql ) sqliteFree( zSql );
++  sqliteFree( zSql );
+   sqlite3ResetInternalSchema(db, 0);
+ #endif
+ 
+Index: sqlite/auth.c
+===================================================================
+--- amarok/src/sqlite/auth.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/auth.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -112,10 +112,17 @@
+   int iSrc;             /* Index in pTabList->a[] of table being read */
+   const char *zDBase;   /* Name of database being accessed */
+   TriggerStack *pStack; /* The stack of current triggers */
++  int iDb;              /* The index of the database the expression refers to */
+ 
+   if( db->xAuth==0 ) return;
+   if( pExpr->op==TK_AS ) return;
+   assert( pExpr->op==TK_COLUMN );
++  iDb = sqlite3SchemaToIndex(pParse->db, pExpr->pSchema);
++  if( iDb<0 ){
++    /* An attempt to read a column out of a subquery or other
++    ** temporary table. */
++    return;
++  }
+   for(iSrc=0; pTabList && iSrc<pTabList->nSrc; iSrc++){
+     if( pExpr->iTable==pTabList->a[iSrc].iCursor ) break;
+   }
+@@ -140,14 +147,14 @@
+   }else{
+     zCol = "ROWID";
+   }
+-  assert( pExpr->iDb<db->nDb );
+-  zDBase = db->aDb[pExpr->iDb].zName;
++  assert( iDb>=0 && iDb<db->nDb );
++  zDBase = db->aDb[iDb].zName;
+   rc = db->xAuth(db->pAuthArg, SQLITE_READ, pTab->zName, zCol, zDBase, 
+                  pParse->zAuthContext);
+   if( rc==SQLITE_IGNORE ){
+     pExpr->op = TK_NULL;
+   }else if( rc==SQLITE_DENY ){
+-    if( db->nDb>2 || pExpr->iDb!=0 ){
++    if( db->nDb>2 || iDb!=0 ){
+       sqlite3ErrorMsg(pParse, "access to %s.%s.%s is prohibited", 
+          zDBase, pTab->zName, zCol);
+     }else{
+Index: sqlite/pager.h
+===================================================================
+--- amarok/src/sqlite/pager.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/pager.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -16,6 +16,9 @@
+ ** @(#) $Id$
+ */
+ 
++#ifndef _PAGER_H_
++#define _PAGER_H_
++
+ /*
+ ** The default size of a database page.
+ */
+@@ -96,7 +99,7 @@
+ void sqlite3pager_dont_rollback(void*);
+ void sqlite3pager_dont_write(Pager*, Pgno);
+ int *sqlite3pager_stats(Pager*);
+-void sqlite3pager_set_safety_level(Pager*,int);
++void sqlite3pager_set_safety_level(Pager*,int,int);
+ const char *sqlite3pager_filename(Pager*);
+ const char *sqlite3pager_dirname(Pager*);
+ const char *sqlite3pager_journalname(Pager*);
+@@ -105,6 +108,7 @@
+ void sqlite3pager_set_codec(Pager*,void(*)(void*,void*,Pgno,int),void*);
+ int sqlite3pager_movepage(Pager*,void*,Pgno);
+ int sqlite3pager_reset(Pager*);
++int sqlite3pager_release_memory(int);
+ 
+ #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
+ int sqlite3pager_lockstate(Pager*);
+@@ -114,3 +118,5 @@
+ void sqlite3pager_refdump(Pager*);
+ int pager3_refinfo_enable;
+ #endif
++
++#endif /* _PAGER_H_ */
+Index: sqlite/insert.c
+===================================================================
+--- amarok/src/sqlite/insert.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/insert.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -23,10 +23,11 @@
+ **
+ **  Character      Column affinity
+ **  ------------------------------
+-**  'n'            NUMERIC
+-**  'i'            INTEGER
+-**  't'            TEXT
+-**  'o'            NONE
++**  'a'            TEXT
++**  'b'            NONE
++**  'c'            NUMERIC
++**  'd'            INTEGER
++**  'e'            REAL
+ */
+ void sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
+   if( !pIdx->zColAff ){
+@@ -61,10 +62,11 @@
+ **
+ **  Character      Column affinity
+ **  ------------------------------
+-**  'n'            NUMERIC
+-**  'i'            INTEGER
+-**  't'            TEXT
+-**  'o'            NONE
++**  'a'            TEXT
++**  'b'            NONE
++**  'c'            NUMERIC
++**  'd'            INTEGER
++**  'e'            REAL
+ */
+ void sqlite3TableAffinityStr(Vdbe *v, Table *pTab){
+   /* The first time a column affinity string for a particular table
+@@ -102,15 +104,15 @@
+ **
+ ** No checking is done for sub-selects that are part of expressions.
+ */
+-static int selectReadsTable(Select *p, int iDb, int iTab){
++static int selectReadsTable(Select *p, Schema *pSchema, int iTab){
+   int i;
+   struct SrcList_item *pItem;
+   if( p->pSrc==0 ) return 0;
+   for(i=0, pItem=p->pSrc->a; i<p->pSrc->nSrc; i++, pItem++){
+     if( pItem->pSelect ){
+-      if( selectReadsTable(pItem->pSelect, iDb, iTab) ) return 1;
++      if( selectReadsTable(pItem->pSelect, pSchema, iTab) ) return 1;
+     }else{
+-      if( pItem->pTab->iDb==iDb && pItem->pTab->tnum==iTab ) return 1;
++      if( pItem->pTab->pSchema==pSchema && pItem->pTab->tnum==iTab ) return 1;
+     }
+   }
+   return 0;
+@@ -212,6 +214,7 @@
+   int newIdx = -1;      /* Cursor for the NEW table */
+   Db *pDb;              /* The database containing table being inserted into */
+   int counterMem = 0;   /* Memory cell holding AUTOINCREMENT counter */
++  int iDb;
+ 
+ #ifndef SQLITE_OMIT_TRIGGER
+   int isView;                 /* True if attempting to insert into a view */
+@@ -219,10 +222,12 @@
+ #endif
+ 
+ #ifndef SQLITE_OMIT_AUTOINCREMENT
+-  int counterRowid;     /* Memory cell holding rowid of autoinc counter */
++  int counterRowid = 0;  /* Memory cell holding rowid of autoinc counter */
+ #endif
+ 
+-  if( pParse->nErr || sqlite3_malloc_failed ) goto insert_cleanup;
++  if( pParse->nErr || sqlite3MallocFailed() ){
++    goto insert_cleanup;
++  }
+   db = pParse->db;
+ 
+   /* Locate the table into which we will be inserting new information.
+@@ -234,8 +239,9 @@
+   if( pTab==0 ){
+     goto insert_cleanup;
+   }
+-  assert( pTab->iDb<db->nDb );
+-  pDb = &db->aDb[pTab->iDb];
++  iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
++  assert( iDb<db->nDb );
++  pDb = &db->aDb[iDb];
+   zDb = pDb->zName;
+   if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb) ){
+     goto insert_cleanup;
+@@ -271,19 +277,12 @@
+     goto insert_cleanup;
+   }
+ 
+-  /* Ensure all required collation sequences are available. */
+-  for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+-    if( sqlite3CheckIndexCollSeq(pParse, pIdx) ){
+-      goto insert_cleanup;
+-    }
+-  }
+-
+   /* Allocate a VDBE
+   */
+   v = sqlite3GetVdbe(pParse);
+   if( v==0 ) goto insert_cleanup;
+   if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
+-  sqlite3BeginWriteOperation(pParse, pSelect || triggers_exist, pTab->iDb);
++  sqlite3BeginWriteOperation(pParse, pSelect || triggers_exist, iDb);
+ 
+   /* if there are row triggers, allocate a temp table for new.* references. */
+   if( triggers_exist ){
+@@ -298,22 +297,20 @@
+   */
+   if( pTab->autoInc ){
+     int iCur = pParse->nTab;
+-    int base = sqlite3VdbeCurrentAddr(v);
++    int addr = sqlite3VdbeCurrentAddr(v);
+     counterRowid = pParse->nMem++;
+     counterMem = pParse->nMem++;
+-    sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
+-    sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pDb->pSeqTab->tnum);
+-    sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, 2);
+-    sqlite3VdbeAddOp(v, OP_Rewind, iCur, base+13);
++    sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenRead);
++    sqlite3VdbeAddOp(v, OP_Rewind, iCur, addr+13);
+     sqlite3VdbeAddOp(v, OP_Column, iCur, 0);
+     sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0);
+-    sqlite3VdbeAddOp(v, OP_Ne, 28417, base+12);
++    sqlite3VdbeAddOp(v, OP_Ne, 0x100, addr+12);
+     sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
+     sqlite3VdbeAddOp(v, OP_MemStore, counterRowid, 1);
+     sqlite3VdbeAddOp(v, OP_Column, iCur, 1);
+     sqlite3VdbeAddOp(v, OP_MemStore, counterMem, 1);
+-    sqlite3VdbeAddOp(v, OP_Goto, 0, base+13);
+-    sqlite3VdbeAddOp(v, OP_Next, iCur, base+4);
++    sqlite3VdbeAddOp(v, OP_Goto, 0, addr+13);
++    sqlite3VdbeAddOp(v, OP_Next, iCur, addr+4);
+     sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
+   }
+ #endif /* SQLITE_OMIT_AUTOINCREMENT */
+@@ -336,7 +333,9 @@
+ 
+     /* Resolve the expressions in the SELECT statement and execute it. */
+     rc = sqlite3Select(pParse, pSelect, SRT_Subroutine, iInsertBlock,0,0,0,0);
+-    if( rc || pParse->nErr || sqlite3_malloc_failed ) goto insert_cleanup;
++    if( rc || pParse->nErr || sqlite3MallocFailed() ){
++      goto insert_cleanup;
++    }
+ 
+     iCleanup = sqlite3VdbeMakeLabel(v);
+     sqlite3VdbeAddOp(v, OP_Goto, 0, iCleanup);
+@@ -351,7 +350,7 @@
+     ** of the tables being read by the SELECT statement.  Also use a 
+     ** temp table in the case of row triggers.
+     */
+-    if( triggers_exist || selectReadsTable(pSelect, pTab->iDb, pTab->tnum) ){
++    if( triggers_exist || selectReadsTable(pSelect,pTab->pSchema,pTab->tnum) ){
+       useTempTable = 1;
+     }
+ 
+@@ -362,7 +361,6 @@
+       srcTab = pParse->nTab++;
+       sqlite3VdbeResolveLabel(v, iInsertBlock);
+       sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
+-      sqlite3TableAffinityStr(v, pTab);
+       sqlite3VdbeAddOp(v, OP_NewRowid, srcTab, 0);
+       sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
+       sqlite3VdbeAddOp(v, OP_Insert, srcTab, 0);
+@@ -635,7 +633,7 @@
+   /* Update the count of rows that are inserted
+   */
+   if( (db->flags & SQLITE_CountRows)!=0 ){
+-    sqlite3VdbeAddOp(v, OP_MemIncr, iCntMem, 0);
++    sqlite3VdbeAddOp(v, OP_MemIncr, 1, iCntMem);
+   }
+ 
+   if( triggers_exist ){
+@@ -682,12 +680,10 @@
+   */
+   if( pTab->autoInc ){
+     int iCur = pParse->nTab;
+-    int base = sqlite3VdbeCurrentAddr(v);
+-    sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
+-    sqlite3VdbeAddOp(v, OP_OpenWrite, iCur, pDb->pSeqTab->tnum);
+-    sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, 2);
++    int addr = sqlite3VdbeCurrentAddr(v);
++    sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenWrite);
+     sqlite3VdbeAddOp(v, OP_MemLoad, counterRowid, 0);
+-    sqlite3VdbeAddOp(v, OP_NotNull, -1, base+7);
++    sqlite3VdbeAddOp(v, OP_NotNull, -1, addr+7);
+     sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
+     sqlite3VdbeAddOp(v, OP_NewRowid, iCur, 0);
+     sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0);
+@@ -707,7 +703,7 @@
+     sqlite3VdbeAddOp(v, OP_MemLoad, iCntMem, 0);
+     sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
+     sqlite3VdbeSetNumCols(v, 1);
+-    sqlite3VdbeSetColName(v, 0, "rows inserted", P3_STATIC);
++    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows inserted", P3_STATIC);
+   }
+ 
+ insert_cleanup:
+@@ -870,7 +866,18 @@
+ 
+   /* Test all CHECK constraints
+   */
+-  /**** TBD ****/
++#ifndef SQLITE_OMIT_CHECK
++  if( pTab->pCheck && (pParse->db->flags & SQLITE_IgnoreChecks)==0 ){
++    int allOk = sqlite3VdbeMakeLabel(v);
++    assert( pParse->ckOffset==0 );
++    pParse->ckOffset = nCol;
++    sqlite3ExprIfTrue(pParse, pTab->pCheck, allOk, 1);
++    assert( pParse->ckOffset==nCol );
++    pParse->ckOffset = 0;
++    sqlite3VdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, OE_Abort);
++    sqlite3VdbeResolveLabel(v, allOk);
++  }
++#endif /* !defined(SQLITE_OMIT_CHECK) */
+ 
+   /* If we have an INTEGER PRIMARY KEY, make sure the primary key
+   ** of the new record does not previously exist.  Except, if this
+@@ -1067,9 +1074,13 @@
+   if( pParse->nested ){
+     pik_flags = 0;
+   }else{
+-    pik_flags = (OPFLAG_NCHANGE|(isUpdate?0:OPFLAG_LASTROWID));
++    pik_flags = OPFLAG_NCHANGE;
++    pik_flags |= (isUpdate?OPFLAG_ISUPDATE:OPFLAG_LASTROWID);
+   }
+   sqlite3VdbeAddOp(v, OP_Insert, base, pik_flags);
++  if( !pParse->nested ){
++    sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
++  }
+   
+   if( isUpdate && rowidChng ){
+     sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
+@@ -1088,18 +1099,17 @@
+   int op           /* OP_OpenRead or OP_OpenWrite */
+ ){
+   int i;
++  int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
+   Index *pIdx;
+   Vdbe *v = sqlite3GetVdbe(pParse);
+   assert( v!=0 );
+-  sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
+-  VdbeComment((v, "# %s", pTab->zName));
+-  sqlite3VdbeAddOp(v, op, base, pTab->tnum);
+-  sqlite3VdbeAddOp(v, OP_SetNumColumns, base, pTab->nCol);
++  sqlite3OpenTable(pParse, base, iDb, pTab, op);
+   for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
+-    sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
++    KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
++    assert( pIdx->pSchema==pTab->pSchema );
++    sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
+     VdbeComment((v, "# %s", pIdx->zName));
+-    sqlite3VdbeOp3(v, op, i+base, pIdx->tnum,
+-                   (char*)&pIdx->keyInfo, P3_KEYINFO);
++    sqlite3VdbeOp3(v, op, i+base, pIdx->tnum, (char*)pKey, P3_KEYINFO_HANDOFF);
+   }
+   if( pParse->nTab<=base+i ){
+     pParse->nTab = base+i;
+Index: sqlite/complete.c
+===================================================================
+--- amarok/src/sqlite/complete.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/complete.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -16,7 +16,7 @@
+ ** separating it out, the code will be automatically omitted from
+ ** static links that do not use it.
+ **
+-** $Id: complete.c,v 1.1 2005/08/14 17:53:21 drh Exp $
++** $Id: complete.c,v 1.3 2006/01/18 15:25:17 danielk1977 Exp $
+ */
+ #include "sqliteInt.h"
+ #ifndef SQLITE_OMIT_COMPLETE
+@@ -257,7 +257,7 @@
+     rc = sqlite3_complete(zSql8);
+   }
+   sqlite3ValueFree(pVal);
+-  return rc;
++  return sqlite3ApiExit(0, rc);
+ }
+ #endif /* SQLITE_OMIT_UTF16 */
+ #endif /* SQLITE_OMIT_COMPLETE */
+Index: sqlite/parse.c
+===================================================================
+--- amarok/src/sqlite/parse.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/parse.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -23,7 +23,7 @@
+ ** GLOB, NOT LIKE, and NOT GLOB operators.
+ */
+ struct LikeOp {
+-  Token operator;  /* "like" or "glob" or "regexp" */
++  Token eOperator;  /* "like" or "glob" or "regexp" */
+   int not;         /* True if the NOT keyword is present */
+ };
+ 
+@@ -93,35 +93,35 @@
+ **                       defined, then do no error processing.
+ */
+ #define YYCODETYPE unsigned char
+-#define YYNOCODE 247
++#define YYNOCODE 240
+ #define YYACTIONTYPE unsigned short int
+ #define sqlite3ParserTOKENTYPE Token
+ typedef union {
+   sqlite3ParserTOKENTYPE yy0;
+-  struct TrigEvent yy30;
+-  Expr* yy62;
+-  SrcList* yy151;
+-  Token yy198;
+-  struct LimitVal yy220;
+-  struct LikeOp yy222;
+-  IdList* yy240;
+-  int yy280;
+-  struct {int value; int mask;} yy359;
+-  TriggerStep* yy360;
+-  struct AttachKey yy361;
+-  Select* yy375;
+-  ExprList* yy418;
+-  int yy493;
++  struct {int value; int mask;} yy13;
++  struct TrigEvent yy132;
++  IdList* yy160;
++  Expr* yy178;
++  int yy230;
++  Select* yy239;
++  TriggerStep* yy247;
++  struct LimitVal yy270;
++  SrcList* yy285;
++  Expr * yy292;
++  Token yy384;
++  struct LikeOp yy440;
++  ExprList* yy462;
++  int yy479;
+ } YYMINORTYPE;
+ #define YYSTACKDEPTH 100
+ #define sqlite3ParserARG_SDECL Parse *pParse;
+ #define sqlite3ParserARG_PDECL ,Parse *pParse
+ #define sqlite3ParserARG_FETCH Parse *pParse = yypParser->pParse
+ #define sqlite3ParserARG_STORE yypParser->pParse = pParse
+-#define YYNSTATE 581
+-#define YYNRULE 311
+-#define YYERRORSYMBOL 146
+-#define YYERRSYMDT yy493
++#define YYNSTATE 560
++#define YYNRULE 295
++#define YYERRORSYMBOL 137
++#define YYERRSYMDT yy479
+ #define YYFALLBACK 1
+ #define YY_NO_ACTION      (YYNSTATE+YYNRULE+2)
+ #define YY_ACCEPT_ACTION  (YYNSTATE+YYNRULE+1)
+@@ -175,485 +175,396 @@
+ **  yy_default[]       Default action for each state.
+ */
+ static const YYACTIONTYPE yy_action[] = {
+- /*     0 */   286,  584,  113,  140,  142,  138,  144,  581,  150,  152,
+- /*    10 */   154,  156,  158,  160,  162,  164,  166,  168,    3,  577,
+- /*    20 */   740,  170,  178,  150,  152,  154,  156,  158,  160,  162,
+- /*    30 */   164,  166,  168,  158,  160,  162,  164,  166,  168,  135,
+- /*    40 */    97,  171,  181,  186,  191,  180,  185,  146,  148,  140,
+- /*    50 */   142,  138,  144,   51,  150,  152,  154,  156,  158,  160,
+- /*    60 */   162,  164,  166,  168,   16,   17,   18,  114,    7,  248,
+- /*    70 */   150,  152,  154,  156,  158,  160,  162,  164,  166,  168,
+- /*    80 */    13,   37,  362,   40,   59,   67,   69,  326,  357,  170,
+- /*    90 */     6,    5,  331,   95,  364,  359,   25,  374,  258,  893,
+- /*   100 */     1,  580,  514,   13,    4,  575,   33,  135,   97,  171,
+- /*   110 */   181,  186,  191,  180,  185,  146,  148,  140,  142,  138,
+- /*   120 */   144,    9,  150,  152,  154,  156,  158,  160,  162,  164,
+- /*   130 */   166,  168,  374,  136,  592,   80,  112,   99,  269,   34,
+- /*   140 */    32,   33,  132,  373,  115,   14,   15,  378,  333,   99,
+- /*   150 */   380,  387,  392,   13,  367,  370,  194,  170,   78,  500,
+- /*   160 */   525,  315,  395,  369,  375,  408,   10,   98,   14,   15,
+- /*   170 */    78,  200,  286,  864,  113,  135,   97,  171,  181,  186,
+- /*   180 */   191,  180,  185,  146,  148,  140,  142,  138,  144,   80,
+- /*   190 */   150,  152,  154,  156,  158,  160,  162,  164,  166,  168,
+- /*   200 */   104,  105,  106,  661,  496,  376,  374,  170,  467,   13,
+- /*   210 */     2,   28,  237,    4,  409,   33,    3,  577,   14,   15,
+- /*   220 */    51,  132,  133,  115,  241,  135,   97,  171,  181,  186,
+- /*   230 */   191,  180,  185,  146,  148,  140,  142,  138,  144,  114,
+- /*   240 */   150,  152,  154,  156,  158,  160,  162,  164,  166,  168,
+- /*   250 */    40,   59,   67,   69,  326,  357,  136,   44,   45,  501,
+- /*   260 */   473,  463,  359,   36,  361,  130,  128,  660,  275,   31,
+- /*   270 */    84,   99,  356,  378,   14,   15,  380,  387,  392,   52,
+- /*   280 */   170,  117,  122,  123,  113,  541,  369,  643,  395,  348,
+- /*   290 */    98,   54,   78,  200,  302,   57,   58,  819,  135,   97,
+- /*   300 */   171,  181,  186,  191,  180,  185,  146,  148,  140,  142,
+- /*   310 */   138,  144,  861,  150,  152,  154,  156,  158,  160,  162,
+- /*   320 */   164,  166,  168,  104,  105,  106,  817,   80,   48,  316,
+- /*   330 */   162,  164,  166,  168,  319,  277,   12,   49,   99,  303,
+- /*   340 */   283,  818,   99,  124,  304,   99,  241,  172,  593,  114,
+- /*   350 */    50,  193,   46,  378,  170,   13,  380,  387,  392,   78,
+- /*   360 */   260,  276,   47,   78,  200,   64,   78,  260,  395,  174,
+- /*   370 */   175,  221,  135,   97,  171,  181,  186,  191,  180,  185,
+- /*   380 */   146,  148,  140,  142,  138,  144,  199,  150,  152,  154,
+- /*   390 */   156,  158,  160,  162,  164,  166,  168,  173,  252,  261,
+- /*   400 */   120,  122,  123,  212,  170,  268,  254,  130,  128,  288,
+- /*   410 */   590,  176,  246,  187,  192,  414,  195,  241,  197,  198,
+- /*   420 */    14,   15,  135,   97,  171,  181,  186,  191,  180,  185,
+- /*   430 */   146,  148,  140,  142,  138,  144,  433,  150,  152,  154,
+- /*   440 */   156,  158,  160,  162,  164,  166,  168,  311,   99,  707,
+- /*   450 */    99,  422,  708,  417,  275,   81,  318,  598,   99,  219,
+- /*   460 */    13,  231,  124,   13,  176,   48,  187,  192,   20,   78,
+- /*   470 */   317,   78,  214,  195,   49,  197,  198,  462,  170,   78,
+- /*   480 */   200,  116,   27,   13,  410,  113,  591,   50,   80,  225,
+- /*   490 */   195,   11,  197,  198,  506,  235,  135,   97,  171,  181,
+- /*   500 */   186,  191,  180,  185,  146,  148,  140,  142,  138,  144,
+- /*   510 */    80,  150,  152,  154,  156,  158,  160,  162,  164,  166,
+- /*   520 */   168,  277,  215,  324,  606,   14,   15,  301,   14,   15,
+- /*   530 */   512,   13,  508,  240,  196,  486,  195,  685,  197,  198,
+- /*   540 */    22,  834,  445,  331,  462,  170,  444,  276,   14,   15,
+- /*   550 */   114,  468,  278,  394,  599,  280,  470,  288,  446,  680,
+- /*   560 */    13,  321,  404,  135,   97,  171,  181,  186,  191,  180,
+- /*   570 */   185,  146,  148,  140,  142,  138,  144,   80,  150,  152,
+- /*   580 */   154,  156,  158,  160,  162,  164,  166,  168,   74,   99,
+- /*   590 */   540,  366,   73,   99,  352,  289,   14,   15,  176,  333,
+- /*   600 */   187,  192,  486,  869,  359,  273,  283,  542,  543,  867,
+- /*   610 */    78,  500,  510,  170,   78,  323,  682,  176,  472,  187,
+- /*   620 */   192,  746,  118,  470,  119,   14,   15,  195,  346,  197,
+- /*   630 */   198,  135,   97,  171,  181,  186,  191,  180,  185,  146,
+- /*   640 */   148,  140,  142,  138,  144,   99,  150,  152,  154,  156,
+- /*   650 */   158,  160,  162,  164,  166,  168,  532,  334,  341,  343,
+- /*   660 */   841,   39,  195,  170,  197,  198,   78,   94,  124,  356,
+- /*   670 */   271,  353,  439,  441,  440,  544,  883,  428,   72,  862,
+- /*   680 */   288,  135,   97,  171,  181,  186,  191,  180,  185,  146,
+- /*   690 */   148,  140,  142,  138,  144,   13,  150,  152,  154,  156,
+- /*   700 */   158,  160,  162,  164,  166,  168,  195,   99,  197,  198,
+- /*   710 */   406,  330,  195,  170,  197,  198,  568,  405,  306,  195,
+- /*   720 */    42,  197,  198,   65,  195,  539,  197,  198,   78,   96,
+- /*   730 */    66,  135,   97,  171,  181,  186,  191,  180,  185,  146,
+- /*   740 */   148,  140,  142,  138,  144,  885,  150,  152,  154,  156,
+- /*   750 */   158,  160,  162,  164,  166,  168,   99,  740,   99,  298,
+- /*   760 */    14,   15,  272,  170,   13,   74,  572,   86,  600,   73,
+- /*   770 */   126,  127,  614,  709,  309,  478,   24,   78,  247,   78,
+- /*   780 */   111,  135,   97,  171,  181,  186,  191,  180,  185,  146,
+- /*   790 */   148,  140,  142,  138,  144,   99,  150,  152,  154,  156,
+- /*   800 */   158,  160,  162,  164,  166,  168,   99,  238,  113,  239,
+- /*   810 */   295,   26,  296,  170,  338,  337,   78,  137,  294,  320,
+- /*   820 */   347,  239,  348,  390,  211,  348,   30,   78,  139,   14,
+- /*   830 */    15,  135,  189,  171,  181,  186,  191,  180,  185,  146,
+- /*   840 */   148,  140,  142,  138,  144,   99,  150,  152,  154,  156,
+- /*   850 */   158,  160,  162,  164,  166,  168,   99,   80,   99,  372,
+- /*   860 */   399,  442,  348,  170,  298,  243,   78,  141,  363,  601,
+- /*   870 */   428,  437,  438,  114,  411,  269,  605,   78,  143,   78,
+- /*   880 */   145,  448,   97,  171,  181,  186,  191,  180,  185,  146,
+- /*   890 */   148,  140,  142,  138,  144,   99,  150,  152,  154,  156,
+- /*   900 */   158,  160,  162,  164,  166,  168,   99,   80,   99,  430,
+- /*   910 */    99,  296,  555,  170,  413,  856,   78,  147,  672,  457,
+- /*   920 */   352,  348,  298,  443,  465,   45,   35,   78,  149,   78,
+- /*   930 */   151,   78,  153,  171,  181,  186,  191,  180,  185,  146,
+- /*   940 */   148,  140,  142,  138,  144,   99,  150,  152,  154,  156,
+- /*   950 */   158,  160,  162,  164,  166,  168,   99,  459,   99,   29,
+- /*   960 */    79,  464,  183,  483,   71,  339,   78,  155,  709,  421,
+- /*   970 */   428,   79,  109,   99,  491,   71,  296,   78,  157,   78,
+- /*   980 */   159,  490,  243,  109,   99,  340,   99,  449,  857,  223,
+- /*   990 */    99,  460,  182,  709,   78,  161,   99,  349,  827,  136,
+- /*  1000 */   223,   99,   80,  201,   99,   78,  163,   78,  165,  507,
+- /*  1010 */   136,   78,  167,   42,  201,   38,  493,   78,  169,  569,
+- /*  1020 */   207,  205,   78,  177,  674,   78,  179,  477,  203,   76,
+- /*  1030 */    77,  207,  205,   98,   99,   84,   99,   42,  336,  203,
+- /*  1040 */    76,   77,   99,   43,   98,   41,  428,   79,  494,   80,
+- /*  1050 */   428,   71,   84,   99,  352,   78,  188,   78,  190,  109,
+- /*  1060 */   499,  428,  497,   78,  202,   60,  104,  105,  106,  107,
+- /*  1070 */   108,  209,  213,   99,   78,  204,  223,  104,  105,  106,
+- /*  1080 */   107,  108,  209,  213,  820,  509,  136,   53,  383,  511,
+- /*  1090 */   201,   99,   56,   61,   78,  206,   55,  428,  428,  889,
+- /*  1100 */   513,   99,  243,   99,  352,   99,   79,  207,  205,  312,
+- /*  1110 */    71,   99,   78,  208,  483,  203,   76,   77,  109,  533,
+- /*  1120 */    98,  497,   78,  220,   78,  222,   78,  232,   84,   99,
+- /*  1130 */   428,  353,   78,  234,  352,  223,  517,  521,  389,   99,
+- /*  1140 */    62,  530,   99,   64,   63,  136,   68,  529,   70,  201,
+- /*  1150 */    78,  236,  352,  104,  105,  106,  107,  108,  209,  213,
+- /*  1160 */    78,  249,   99,   78,  265,  877,  207,  205,  398,  527,
+- /*  1170 */    99,  615,  616,  313,  203,   76,   77,   99,  523,   98,
+- /*  1180 */    80,  353,    8,   78,  270,   99,  456,   19,   21,   23,
+- /*  1190 */   412,   78,  300,   75,   78,  310,   82,   84,   78,  365,
+- /*  1200 */   563,   83,  547,   99,   87,  553,   78,  393,   85,  557,
+- /*  1210 */    99,  353,  104,  105,  106,  107,  108,  209,  213,   99,
+- /*  1220 */   269,  536,   99,  467,   78,  434,   88,  266,  534,  353,
+- /*  1230 */   560,   78,  481,  566,  264,   89,  250,   90,   93,   91,
+- /*  1240 */    78,  485,  101,   78,  498,   92,  100,  102,  103,  110,
+- /*  1250 */   131,  121,  134,  125,  129,  168,  184,  242,  686,  687,
+- /*  1260 */   688,  210,  233,  218,  224,  216,  227,  226,  217,  229,
+- /*  1270 */   228,  230,  243,  251,  515,  519,  463,  245,  253,  244,
+- /*  1280 */   505,  257,  255,  256,  258,   84,  259,  262,  263,  239,
+- /*  1290 */   267,  279,  274,  281,  282,  299,  285,  292,  284,  287,
+- /*  1300 */   290,  293,  297,  305,  314,  291,  307,  322,  308,  325,
+- /*  1310 */   327,  345,  329,  328,  332,  350,  354,  330,  358,  335,
+- /*  1320 */   342,  379,  381,  382,  344,  351,  368,  385,  355,  371,
+- /*  1330 */   388,  360,  396,  397,  400,  401,  415,   54,  416,  386,
+- /*  1340 */   384,  391,  418,  402,  407,  419,  377,  420,  423,  424,
+- /*  1350 */   403,  426,  425,  427,  429,  435,  431,  849,  436,  854,
+- /*  1360 */   432,  855,  450,  447,  451,  452,  454,  453,  825,  455,
+- /*  1370 */   458,  826,  469,  461,  466,  747,  748,  848,  471,  464,
+- /*  1380 */   863,  480,  474,  475,  476,  482,  865,  479,  487,  484,
+- /*  1390 */   489,  488,  492,  866,  495,  868,  504,  679,  502,  681,
+- /*  1400 */   833,  875,  518,  503,  516,  739,  520,  524,  522,  742,
+- /*  1410 */   745,  531,  526,  835,  535,  528,  538,  537,  836,  837,
+- /*  1420 */   838,  839,  545,  546,  840,  550,  876,  556,  551,  878,
+- /*  1430 */   548,  549,  554,  879,  559,  882,  884,  562,  886,  561,
+- /*  1440 */   552,  558,  564,  567,  570,  565,  571,  887,  576,  574,
+- /*  1450 */   573,  888,  578,  559,  559,  579,
++ /*     0 */   279,   68,  283,   70,  148,  166,  546,  419,   62,   62,
++ /*    10 */    62,   62,  202,   64,   64,   64,   64,   65,   65,   66,
++ /*    20 */    66,   66,   67,   67,  548,  549,  432,   69,   64,   64,
++ /*    30 */    64,   64,   65,   65,   66,   66,   66,   67,   68,  454,
++ /*    40 */    70,  148,  499,   61,   59,  287,  440,  441,  437,  437,
++ /*    50 */    63,   63,   62,   62,   62,   62,  501,   64,   64,   64,
++ /*    60 */    64,   65,   65,   66,   66,   66,   67,  279,  371,  283,
++ /*    70 */   419,    2,  377,   80,  158,  115,  220,  304,  225,  305,
++ /*    80 */   170,  245,  856,  119,  559,  504,  204,    2,  246,  389,
++ /*    90 */   496,  219,   22,  432,  514,   21,  419,   58,  493,  171,
++ /*   100 */    64,   64,   64,   64,   65,   65,   66,   66,   66,   67,
++ /*   110 */    61,   59,  287,  440,  441,  437,  437,   63,   63,   62,
++ /*   120 */    62,   62,   62,  512,   64,   64,   64,   64,   65,   65,
++ /*   130 */    66,   66,   66,   67,  279,  378,  379,  175,  202,  377,
++ /*   140 */   330,  333,  334,  220,  304,  225,  305,  170,  245,  203,
++ /*   150 */   146,  357,  335,  281,  377,  246,   55,  301,  373,  419,
++ /*   160 */   432,  505,   92,  200,  530,   66,   66,   66,   67,  525,
++ /*   170 */   192,   65,   65,   66,   66,   66,   67,   61,   59,  287,
++ /*   180 */   440,  441,  437,  437,   63,   63,   62,   62,   62,   62,
++ /*   190 */   433,   64,   64,   64,   64,   65,   65,   66,   66,   66,
++ /*   200 */    67,  279,  378,  379,  411,  431,  110,  226,  427,  205,
++ /*   210 */   435,  436,  308,  358,  261,  260,  175,  378,  379,  330,
++ /*   220 */   333,  334,  372,  369,  202,  511,  480,  432,  547,  362,
++ /*   230 */   466,  335,  510,  500,  410,   41,  276,  414,  434,  429,
++ /*   240 */   503,  162,  233,  527,   61,   59,  287,  440,  441,  437,
++ /*   250 */   437,   63,   63,   62,   62,   62,   62,  319,   64,   64,
++ /*   260 */    64,   64,   65,   65,   66,   66,   66,   67,  279,  472,
++ /*   270 */   416,  416,  416,  308,  322,  236,  308,   68,  308,   70,
++ /*   280 */   148,    1,  308,  793,  308,  377,   68,  153,   70,  148,
++ /*   290 */   149,  377,  325,  282,  432,  410,   35,  551,  410,   35,
++ /*   300 */   410,   36,  427,  205,  410,   35,  410,   35,  286,  422,
++ /*   310 */   423,   61,   59,  287,  440,  441,  437,  437,   63,   63,
++ /*   320 */    62,   62,   62,   62,  411,   64,   64,   64,   64,   65,
++ /*   330 */    65,   66,   66,   66,   67,  308,  504,  466,  290,  255,
++ /*   340 */   279,  324,  485,  147,  237,  388,   21,  288,  378,  379,
++ /*   350 */   451,  419,  232,  451,  378,  379,  308,  410,   28,  451,
++ /*   360 */   175,  450,  486,  330,  333,  334,  432,  215,  347,  145,
++ /*   370 */   513,  204,  350,  186,  168,  335,  238,  411,  410,   41,
++ /*   380 */   256,  462,   76,   61,   59,  287,  440,  441,  437,  437,
++ /*   390 */    63,   63,   62,   62,   62,   62,  309,   64,   64,   64,
++ /*   400 */    64,   65,   65,   66,   66,   66,   67,  411,  411,  186,
++ /*   410 */   396,  308,  279,  291,  419,  338,  476,  308,  390,  234,
++ /*   420 */   169,  154,  397,  475,  396,  327,  493,  311,  422,  423,
++ /*   430 */   444,  377,  356,  410,   49,  398,  397,  394,  432,  410,
++ /*   440 */    49,  502,  171,  411,  429,  312,  162,  395,  351,  398,
++ /*   450 */   497,  318,  470,  352,   79,   61,   59,  287,  440,  441,
++ /*   460 */   437,  437,   63,   63,   62,   62,   62,   62,  356,   64,
++ /*   470 */    64,   64,   64,   65,   65,   66,   66,   66,   67,  279,
++ /*   480 */   298,  445,  376,  479,  532,  405,  299,   11,  504,  352,
++ /*   490 */   204,  377,  406,  377,  378,  379,  281,  556,   21,  491,
++ /*   500 */   491,  246,  560,  372,  369,  432,  392,  393,  314,  123,
++ /*   510 */   443,  443,  166,  289,  419,  314,  116,  443,  443,  251,
++ /*   520 */   264,  463,   61,   59,  287,  440,  441,  437,  437,   63,
++ /*   530 */    63,   62,   62,   62,   62,  292,   64,   64,   64,   64,
++ /*   540 */    65,   65,   66,   66,   66,   67,  279,  459,  328,  474,
++ /*   550 */   498,  308,  202,  308,  378,  379,  378,  379,  181,  131,
++ /*   560 */   179,  265,  308,    5,  308,  363,  314,  355,  443,  443,
++ /*   570 */   410,    3,  432,  410,   29,  410,   24,  419,  243,  244,
++ /*   580 */   380,  381,  382,  404,  410,   33,  410,   54,  466,   61,
++ /*   590 */    59,  287,  440,  441,  437,  437,   63,   63,   62,   62,
++ /*   600 */    62,   62,  308,   64,   64,   64,   64,   65,   65,   66,
++ /*   610 */    66,   66,   67,  279,  521,  344,  521,  249,  308,  491,
++ /*   620 */   308,  470,  308,  470,  410,   25,  308,  240,  308,  314,
++ /*   630 */   308,  443,  443,  213,  172,  173,  174,  142,  266,  432,
++ /*   640 */   410,   52,  410,   97,  410,   94,  528,  393,  410,   99,
++ /*   650 */   410,  100,  410,  111,  212,  255,   61,   59,  287,  440,
++ /*   660 */   441,  437,  437,   63,   63,   62,   62,   62,   62,  308,
++ /*   670 */    64,   64,   64,   64,   65,   65,   66,   66,   66,   67,
++ /*   680 */   279,  308,  345,  188,  297,   91,  308,  491,  308,  415,
++ /*   690 */   308,  410,  112,  308,  428,  308,  537,  308,  244,  165,
++ /*   700 */   154,  409,  355,  410,   18,  408,  432,  320,  410,   98,
++ /*   710 */   410,   34,  410,   95,  313,  410,   53,  410,  113,  410,
++ /*   720 */   114,  255,  293,   61,   59,  287,  440,  441,  437,  437,
++ /*   730 */    63,   63,   62,   62,   62,   62,  308,   64,   64,   64,
++ /*   740 */    64,   65,   65,   66,   66,   66,   67,  279,  308,  491,
++ /*   750 */   491,  523,  308,  452,  308,  522,  308,  461,  410,   26,
++ /*   760 */   308,   75,  539,   77,  308,  460,  244,  346,  214,  465,
++ /*   770 */   410,   37,  469,  432,  410,   38,  410,   27,  410,   39,
++ /*   780 */   242,   82,  410,   40,  294,  296,  410,   42,  438,  329,
++ /*   790 */    61,   59,  287,  440,  441,  437,  437,   63,   63,   62,
++ /*   800 */    62,   62,   62,  308,   64,   64,   64,   64,   65,   65,
++ /*   810 */    66,   66,   66,   67,  279,  308,  409,  190,  221,  308,
++ /*   820 */   408,  308,  152,  308,  159,  410,   43,  308,  244,  244,
++ /*   830 */   222,   20,  308,  139,  425,  425,  481,  410,   44,  482,
++ /*   840 */   432,  410,   30,  410,   31,  410,   45,  487,  461,  410,
++ /*   850 */    46,  411,  506,  255,  410,   47,  488,   61,   71,  287,
++ /*   860 */   440,  441,  437,  437,   63,   63,   62,   62,   62,   62,
++ /*   870 */   308,   64,   64,   64,   64,   65,   65,   66,   66,   66,
++ /*   880 */    67,  279,  308,  401,  402,  250,  308,  193,  308,  420,
++ /*   890 */   308,   23,  410,   48,  540,  449,  255,   14,  468,  477,
++ /*   900 */   167,   14,  484,  483,  410,   32,  252,  432,  410,   12,
++ /*   910 */   410,   50,  410,   51,  255,  255,  594,  255,  255,  150,
++ /*   920 */   489,  411,  123,  253,  279,   59,  287,  440,  441,  437,
++ /*   930 */   437,   63,   63,   62,   62,   62,   62,  541,   64,   64,
++ /*   940 */    64,   64,   65,   65,   66,   66,   66,   67,  254,  248,
++ /*   950 */   432,  123,  337,  411,  123,  267,  269,  196,  361,  366,
++ /*   960 */   183,  177,  180,  519,  520,  526,  534,  123,  167,  287,
++ /*   970 */   440,  441,  437,  437,   63,   63,   62,   62,   62,   62,
++ /*   980 */   342,   64,   64,   64,   64,   65,   65,   66,   66,   66,
++ /*   990 */    67,   72,  315,  259,    4,  411,  411,  535,  285,   89,
++ /*  1000 */   544,  349,   89,  353,  354,   19,  310,   72,  315,  368,
++ /*  1010 */     4,  386,  262,  263,  285,  223,  545,  270,  364,  273,
++ /*  1020 */   274,  141,  310,  317,  227,  316,  555,  424,  426,  480,
++ /*  1030 */   455,  458,  490,  431,  332,  492,  533,  157,  543,  317,
++ /*  1040 */   375,  383,  384,  385,    8,  302,  303,  391,  284,  431,
++ /*  1050 */   404,  399,   74,   73,  224,  403,  407,   82,  323,  321,
++ /*  1060 */    72,  306,  307,  400,  231,  414,   81,  206,   74,   73,
++ /*  1070 */   473,   57,   78,  164,  453,  412,   72,  306,  307,   72,
++ /*  1080 */   315,  414,    4,  228,  202,  229,  285,  235,  230,  456,
++ /*  1090 */   457,  413,  207,  120,  310,   83,  326,  102,  416,  416,
++ /*  1100 */   416,  417,  418,   13,  239,  495,  467,  241,  277,  208,
++ /*  1110 */   471,  317,  494,  210,  416,  416,  416,  417,  418,   13,
++ /*  1120 */   211,  431,  156,  278,  339,  507,  508,  216,  217,  218,
++ /*  1130 */   106,  509,  515,  178,  343,   84,  341,  182,  517,  456,
++ /*  1140 */    74,   73,   86,  198,  518,  271,  257,  184,   72,  306,
++ /*  1150 */   307,  348,  272,  414,  118,  529,  187,  127,  536,  359,
++ /*  1160 */   128,  136,  129,  542,  195,  130,  530,  133,  300,  552,
++ /*  1170 */   553,  194,  137,  197,  431,   90,  554,  557,   96,  209,
++ /*  1180 */   101,  374,  387,  117,  201,   56,  416,  416,  416,  417,
++ /*  1190 */   418,   13,   93,  143,  144,  595,  596,  109,  160,  161,
++ /*  1200 */    60,  439,  500,  421,  430,  442,  414,  138,  446,  151,
++ /*  1210 */     6,  447,  155,  448,  163,  360,  268,  260,   15,    7,
++ /*  1220 */    14,  280,  121,  464,  122,  478,  202,  103,  104,  331,
++ /*  1230 */   247,   85,  105,  336,  222,  176,  340,  140,  516,  416,
++ /*  1240 */   416,  416,  124,  295,  125,  167,  524,  258,  107,  185,
++ /*  1250 */   365,    9,  531,   10,  126,  189,   16,  538,  191,  132,
++ /*  1260 */   134,   87,   88,  135,   17,  108,  275,  550,  367,  199,
++ /*  1270 */   370,  536,  558,
+ };
+ static const YYCODETYPE yy_lookahead[] = {
+- /*     0 */    28,   11,   30,   77,   78,   79,   80,    0,   82,   83,
+- /*    10 */    84,   85,   86,   87,   88,   89,   90,   91,   11,   12,
+- /*    20 */    11,   49,   81,   82,   83,   84,   85,   86,   87,   88,
+- /*    30 */    89,   90,   91,   86,   87,   88,   89,   90,   91,   67,
+- /*    40 */    68,   69,   70,   71,   72,   73,   74,   75,   76,   77,
+- /*    50 */    78,   79,   80,   69,   82,   83,   84,   85,   86,   87,
+- /*    60 */    88,   89,   90,   91,   17,   18,   19,   95,   11,   29,
+- /*    70 */    82,   83,   84,   85,   86,   87,   88,   89,   90,   91,
+- /*    80 */    30,   97,   98,   99,  100,  101,  102,  103,  104,   49,
+- /*    90 */   150,  151,   50,   53,   26,  111,  156,  155,   30,  147,
+- /*   100 */   148,  149,  162,   30,  152,  163,  164,   67,   68,   69,
+- /*   110 */    70,   71,   72,   73,   74,   75,   76,   77,   78,   79,
+- /*   120 */    80,  153,   82,   83,   84,   85,   86,   87,   88,   89,
+- /*   130 */    90,   91,  155,   65,   11,  195,   28,  155,  129,  165,
+- /*   140 */   163,  164,  168,  169,  170,   95,   96,   97,  106,  155,
+- /*   150 */   100,  101,  102,   30,   86,   87,  162,   49,  176,  177,
+- /*   160 */   220,   88,  112,   95,  187,  188,  154,   99,   95,   96,
+- /*   170 */   176,  177,   28,   21,   30,   67,   68,   69,   70,   71,
+- /*   180 */    72,   73,   74,   75,   76,   77,   78,   79,   80,  195,
+- /*   190 */    82,   83,   84,   85,   86,   87,   88,   89,   90,   91,
+- /*   200 */   132,  133,  134,   27,  222,   29,  155,   49,   56,   30,
+- /*   210 */   149,  160,  218,  152,  163,  164,   11,   12,   95,   96,
+- /*   220 */    69,  168,  169,  170,  230,   67,   68,   69,   70,   71,
+- /*   230 */    72,   73,   74,   75,   76,   77,   78,   79,   80,   95,
+- /*   240 */    82,   83,   84,   85,   86,   87,   88,   89,   90,   91,
+- /*   250 */    99,  100,  101,  102,  103,  104,   65,  192,  193,  107,
+- /*   260 */   108,  109,  111,  174,  175,   86,   87,   27,   29,   29,
+- /*   270 */   118,  155,  183,   97,   95,   96,  100,  101,  102,   99,
+- /*   280 */    49,  171,  172,  173,   30,  106,   95,   27,  112,   29,
+- /*   290 */    99,  111,  176,  177,  162,   17,   18,  139,   67,   68,
+- /*   300 */    69,   70,   71,   72,   73,   74,   75,   76,   77,   78,
+- /*   310 */    79,   80,   15,   82,   83,   84,   85,   86,   87,   88,
+- /*   320 */    89,   90,   91,  132,  133,  134,   21,  195,   22,   27,
+- /*   330 */    88,   89,   90,   91,  218,   96,  155,   31,  155,  207,
+- /*   340 */   208,   21,  155,  233,  212,  155,  230,   49,   11,   95,
+- /*   350 */    44,   26,   46,   97,   49,   30,  100,  101,  102,  176,
+- /*   360 */   177,  122,   56,  176,  177,  105,  176,  177,  112,   71,
+- /*   370 */    72,  140,   67,   68,   69,   70,   71,   72,   73,   74,
+- /*   380 */    75,   76,   77,   78,   79,   80,   27,   82,   83,   84,
+- /*   390 */    85,   86,   87,   88,   89,   90,   91,   99,  215,  216,
+- /*   400 */   171,  172,  173,   27,   49,  218,  216,   86,   87,  168,
+- /*   410 */    11,  223,  224,  225,  226,   24,  114,  230,  116,  117,
+- /*   420 */    95,   96,   67,   68,   69,   70,   71,   72,   73,   74,
+- /*   430 */    75,   76,   77,   78,   79,   80,  139,   82,   83,   84,
+- /*   440 */    85,   86,   87,   88,   89,   90,   91,  206,  155,   27,
+- /*   450 */   155,   60,   27,   62,   29,  162,   27,   11,  155,  139,
+- /*   460 */    30,  141,  233,   30,  223,   22,  225,  226,  154,  176,
+- /*   470 */   177,  176,  177,  114,   31,  116,  117,  162,   49,  176,
+- /*   480 */   177,   26,   26,   30,   28,   30,   11,   44,  195,   46,
+- /*   490 */   114,   16,  116,  117,   24,  140,   67,   68,   69,   70,
+- /*   500 */    71,   72,   73,   74,   75,   76,   77,   78,   79,   80,
+- /*   510 */   195,   82,   83,   84,   85,   86,   87,   88,   89,   90,
+- /*   520 */    91,   96,  227,   27,   11,   95,   96,   26,   95,   96,
+- /*   530 */    60,   30,   62,  230,  115,  220,  114,  118,  116,  117,
+- /*   540 */   154,   11,   32,   50,  162,   49,   36,  122,   95,   96,
+- /*   550 */    95,  236,  122,  178,   11,  122,  241,  168,   48,   11,
+- /*   560 */    30,   88,   69,   67,   68,   69,   70,   71,   72,   73,
+- /*   570 */    74,   75,   76,   77,   78,   79,   80,  195,   82,   83,
+- /*   580 */    84,   85,   86,   87,   88,   89,   90,   91,  115,  155,
+- /*   590 */   155,   27,  119,  155,  155,  206,   95,   96,  223,  106,
+- /*   600 */   225,  226,  220,   11,  111,  207,  208,  172,  173,   11,
+- /*   610 */   176,  177,  142,   49,  176,  177,   11,  223,  236,  225,
+- /*   620 */   226,   11,   27,  241,   29,   95,   96,  114,  189,  116,
+- /*   630 */   117,   67,   68,   69,   70,   71,   72,   73,   74,   75,
+- /*   640 */    76,   77,   78,   79,   80,  155,   82,   83,   84,   85,
+- /*   650 */    86,   87,   88,   89,   90,   91,  222,  107,  108,  109,
+- /*   660 */    11,  175,  114,   49,  116,  117,  176,  177,  233,  183,
+- /*   670 */    29,  232,  107,  108,  109,   26,   11,  155,   26,   15,
+- /*   680 */   168,   67,   68,   69,   70,   71,   72,   73,   74,   75,
+- /*   690 */    76,   77,   78,   79,   80,   30,   82,   83,   84,   85,
+- /*   700 */    86,   87,   88,   89,   90,   91,  114,  155,  116,  117,
+- /*   710 */   183,  184,  114,   49,  116,  117,  194,  190,  206,  114,
+- /*   720 */   106,  116,  117,   34,  114,   76,  116,  117,  176,  177,
+- /*   730 */    41,   67,   68,   69,   70,   71,   72,   73,   74,   75,
+- /*   740 */    76,   77,   78,   79,   80,   11,   82,   83,   84,   85,
+- /*   750 */    86,   87,   88,   89,   90,   91,  155,   11,  155,  155,
+- /*   760 */    95,   96,  121,   49,   30,  115,  244,  198,   11,  119,
+- /*   770 */   132,  133,  120,   28,  205,   29,  154,  176,  177,  176,
+- /*   780 */   177,   67,   68,   69,   70,   71,   72,   73,   74,   75,
+- /*   790 */    76,   77,   78,   79,   80,  155,   82,   83,   84,   85,
+- /*   800 */    86,   87,   88,   89,   90,   91,  155,   27,   30,   29,
+- /*   810 */    27,  157,   29,   49,   98,   99,  176,  177,  214,   27,
+- /*   820 */    27,   29,   29,   27,  162,   29,   27,  176,  177,   95,
+- /*   830 */    96,   67,   68,   69,   70,   71,   72,   73,   74,   75,
+- /*   840 */    76,   77,   78,   79,   80,  155,   82,   83,   84,   85,
+- /*   850 */    86,   87,   88,   89,   90,   91,  155,  195,  155,  167,
+- /*   860 */    27,   52,   29,   49,  155,  120,  176,  177,  176,   11,
+- /*   870 */   155,   58,   59,   95,  162,  129,   11,  176,  177,  176,
+- /*   880 */   177,   25,   68,   69,   70,   71,   72,   73,   74,   75,
+- /*   890 */    76,   77,   78,   79,   80,  155,   82,   83,   84,   85,
+- /*   900 */    86,   87,   88,   89,   90,   91,  155,  195,  155,  194,
+- /*   910 */   155,   29,  134,   49,  158,  106,  176,  177,   11,   27,
+- /*   920 */   155,   29,  155,  214,  192,  193,  166,  176,  177,  176,
+- /*   930 */   177,  176,  177,   69,   70,   71,   72,   73,   74,   75,
+- /*   940 */    76,   77,   78,   79,   80,  155,   82,   83,   84,   85,
+- /*   950 */    86,   87,   88,   89,   90,   91,  155,  101,  155,  161,
+- /*   960 */    26,   67,   69,  155,   30,   37,  176,  177,  106,  162,
+- /*   970 */   155,   26,   38,  155,   27,   30,   29,  176,  177,  176,
+- /*   980 */   177,  214,  120,   38,  155,   57,  155,  231,  106,   55,
+- /*   990 */   155,  235,   99,   11,  176,  177,  155,  232,  142,   65,
+- /*  1000 */    55,  155,  195,   69,  155,  176,  177,  176,  177,  194,
+- /*  1010 */    65,  176,  177,  106,   69,  155,  162,  176,  177,   64,
+- /*  1020 */    86,   87,  176,  177,  130,  176,  177,  219,   94,   95,
+- /*  1030 */    96,   86,   87,   99,  155,  118,  155,  106,  110,   94,
+- /*  1040 */    95,   96,  155,   39,   99,  178,  155,   26,  131,  195,
+- /*  1050 */   155,   30,  118,  155,  155,  176,  177,  176,  177,   38,
+- /*  1060 */    27,  155,   29,  176,  177,   51,  132,  133,  134,  135,
+- /*  1070 */   136,  137,  138,  155,  176,  177,   55,  132,  133,  134,
+- /*  1080 */   135,  136,  137,  138,  139,  194,   65,  178,  189,  194,
+- /*  1090 */    69,  155,   47,  179,  176,  177,  186,  155,  155,  144,
+- /*  1100 */   194,  155,  120,  155,  155,  155,   26,   86,   87,   88,
+- /*  1110 */    30,  155,  176,  177,  155,   94,   95,   96,   38,   27,
+- /*  1120 */    99,   29,  176,  177,  176,  177,  176,  177,  118,  155,
+- /*  1130 */   155,  232,  176,  177,  155,   55,  194,  194,  189,  155,
+- /*  1140 */   178,  131,  155,  105,  180,   65,  178,  162,   26,   69,
+- /*  1150 */   176,  177,  155,  132,  133,  134,  135,  136,  137,  138,
+- /*  1160 */   176,  177,  155,  176,  177,   11,   86,   87,  189,  194,
+- /*  1170 */   155,  120,  120,  155,   94,   95,   96,  155,  219,   99,
+- /*  1180 */   195,  232,   15,  176,  177,  155,  189,   20,   21,   22,
+- /*  1190 */    23,  176,  177,  197,  176,  177,  196,  118,  176,  177,
+- /*  1200 */    33,  195,   35,  155,  199,   51,  176,  177,  197,   42,
+- /*  1210 */   155,  232,  132,  133,  134,  135,  136,  137,  138,  155,
+- /*  1220 */   129,   54,  155,   56,  176,  177,  200,  126,   61,  232,
+- /*  1230 */    63,  176,  177,   66,  127,  201,  124,  202,  128,  203,
+- /*  1240 */   176,  177,  155,  176,  177,  204,  120,  120,  155,   26,
+- /*  1250 */   168,   27,   27,  234,  234,   91,   99,  155,  118,  118,
+- /*  1260 */   118,   26,  139,   21,   26,  228,  193,   27,  229,  155,
+- /*  1270 */    29,   27,  120,  125,  107,  108,  109,  159,   29,  155,
+- /*  1280 */   113,  104,  217,  179,   30,  118,  167,  217,  179,   29,
+- /*  1290 */   125,  155,  209,  155,  122,  106,  159,  123,  155,  155,
+- /*  1300 */   210,   26,  155,   27,  120,  211,  210,   27,  211,  178,
+- /*  1310 */   155,   26,  182,  181,  155,  217,  217,  184,  167,  185,
+- /*  1320 */   185,  155,   51,   26,  185,  179,  176,   27,  179,  176,
+- /*  1330 */    26,  186,   51,   26,  103,  155,  155,  111,  159,  178,
+- /*  1340 */   180,  178,  155,  181,  188,  159,  188,   28,  155,  159,
+- /*  1350 */   182,  238,  237,  106,  159,   45,  239,   15,   43,  106,
+- /*  1360 */   240,  106,  142,   52,  155,  159,  155,  106,   11,   26,
+- /*  1370 */   178,  142,   21,   15,  191,  130,  130,   11,   11,   67,
+- /*  1380 */    21,   76,  191,  155,  110,  200,   11,  155,  130,   76,
+- /*  1390 */    26,  155,  221,   11,   26,   11,  200,   11,  121,   11,
+- /*  1400 */    11,   11,  200,  155,  121,   11,  191,  200,  110,   11,
+- /*  1410 */    11,   26,  130,   11,  155,  221,  159,  155,   11,   11,
+- /*  1420 */    11,   11,  155,   27,   11,   28,   11,   40,  155,   11,
+- /*  1430 */   242,  168,  168,   11,  155,   11,   11,  159,   11,  155,
+- /*  1440 */   243,  242,  155,   24,  143,  159,  155,   11,  145,  245,
+- /*  1450 */   144,   11,   13,  246,  246,   14,
++ /*     0 */    16,  216,   16,  218,  219,   21,  146,   23,   68,   69,
++ /*    10 */    70,   71,  109,   73,   74,   75,   76,   77,   78,   79,
++ /*    20 */    80,   81,   82,   82,  164,  165,   42,   72,   73,   74,
++ /*    30 */    75,   76,   77,   78,   79,   80,   81,   82,  216,  217,
++ /*    40 */   218,  219,  168,   59,   60,   61,   62,   63,   64,   65,
++ /*    50 */    66,   67,   68,   69,   70,   71,  168,   73,   74,   75,
++ /*    60 */    76,   77,   78,   79,   80,   81,   82,   16,  140,   16,
++ /*    70 */    86,  143,   23,   22,   88,   89,   90,   91,   92,   93,
++ /*    80 */    94,   95,  138,  139,  140,  146,  226,  143,  102,  166,
++ /*    90 */   167,  152,   19,   42,  155,  156,   23,   46,  175,   43,
++ /*   100 */    73,   74,   75,   76,   77,   78,   79,   80,   81,   82,
++ /*   110 */    59,   60,   61,   62,   63,   64,   65,   66,   67,   68,
++ /*   120 */    69,   70,   71,  180,   73,   74,   75,   76,   77,   78,
++ /*   130 */    79,   80,   81,   82,   16,   86,   87,   88,  109,   23,
++ /*   140 */    91,   92,   93,   90,   91,   92,   93,   94,   95,  191,
++ /*   150 */    22,  122,  103,   97,   23,  102,  198,  141,  142,   86,
++ /*   160 */    42,  180,   44,  147,   49,   79,   80,   81,   82,   18,
++ /*   170 */   154,   77,   78,   79,   80,   81,   82,   59,   60,   61,
++ /*   180 */    62,   63,   64,   65,   66,   67,   68,   69,   70,   71,
++ /*   190 */    42,   73,   74,   75,   76,   77,   78,   79,   80,   81,
++ /*   200 */    82,   16,   86,   87,  188,   58,   21,  189,   77,   78,
++ /*   210 */    62,   63,  146,   98,   99,  100,   88,   86,   87,   91,
++ /*   220 */    92,   93,    1,    2,  109,  175,  176,   42,   97,  213,
++ /*   230 */   160,  103,  182,   86,  168,  169,  157,   90,   90,  160,
++ /*   240 */   161,  162,  146,   92,   59,   60,   61,   62,   63,   64,
++ /*   250 */    65,   66,   67,   68,   69,   70,   71,  185,   73,   74,
++ /*   260 */    75,   76,   77,   78,   79,   80,   81,   82,   16,  199,
++ /*   270 */   123,  124,  125,  146,  208,  209,  146,  216,  146,  218,
++ /*   280 */   219,   19,  146,  132,  146,   23,  216,  146,  218,  219,
++ /*   290 */   154,   23,  146,  149,   42,  168,  169,  236,  168,  169,
++ /*   300 */   168,  169,   77,   78,  168,  169,  168,  169,  163,  164,
++ /*   310 */   165,   59,   60,   61,   62,   63,   64,   65,   66,   67,
++ /*   320 */    68,   69,   70,   71,  188,   73,   74,   75,   76,   77,
++ /*   330 */    78,   79,   80,   81,   82,  146,  146,  160,  211,  146,
++ /*   340 */    16,  211,   30,  154,  146,  155,  156,  211,   86,   87,
++ /*   350 */   223,   23,  220,  223,   86,   87,  146,  168,  169,  223,
++ /*   360 */    88,  223,   50,   91,   92,   93,   42,  144,  224,  179,
++ /*   370 */   180,  226,  228,  154,  154,  103,  199,  188,  168,  169,
++ /*   380 */   187,  113,  130,   59,   60,   61,   62,   63,   64,   65,
++ /*   390 */    66,   67,   68,   69,   70,   71,  146,   73,   74,   75,
++ /*   400 */    76,   77,   78,   79,   80,   81,   82,  188,  188,  154,
++ /*   410 */    12,  146,   16,  101,   86,   16,   20,  146,  167,  209,
++ /*   420 */   200,  201,   24,   20,   12,  205,  175,  163,  164,  165,
++ /*   430 */    20,   23,  213,  168,  169,   37,   24,   39,   42,  168,
++ /*   440 */   169,  159,   43,  188,  160,  161,  162,   49,  229,   37,
++ /*   450 */   168,   39,  146,  234,  130,   59,   60,   61,   62,   63,
++ /*   460 */    64,   65,   66,   67,   68,   69,   70,   71,  213,   73,
++ /*   470 */    74,   75,   76,   77,   78,   79,   80,   81,   82,   16,
++ /*   480 */   215,   20,  146,   20,  229,   27,  215,   19,  146,  234,
++ /*   490 */   226,   23,   34,   23,   86,   87,   97,  155,  156,  146,
++ /*   500 */   146,  102,    0,    1,    2,   42,  184,  185,  105,   22,
++ /*   510 */   107,  108,   21,  207,   23,  105,  146,  107,  108,   14,
++ /*   520 */    14,  113,   59,   60,   61,   62,   63,   64,   65,   66,
++ /*   530 */    67,   68,   69,   70,   71,  181,   73,   74,   75,   76,
++ /*   540 */    77,   78,   79,   80,   81,   82,   16,   22,  146,   79,
++ /*   550 */    20,  146,  109,  146,   86,   87,   86,   87,   53,   53,
++ /*   560 */    55,   55,  146,  190,  146,  122,  105,  146,  107,  108,
++ /*   570 */   168,  169,   42,  168,  169,  168,  169,   86,  225,  225,
++ /*   580 */     7,    8,    9,   96,  168,  169,  168,  169,  160,   59,
++ /*   590 */    60,   61,   62,   63,   64,   65,   66,   67,   68,   69,
++ /*   600 */    70,   71,  146,   73,   74,   75,   76,   77,   78,   79,
++ /*   610 */    80,   81,   82,   16,   98,   99,  100,   20,  146,  146,
++ /*   620 */   146,  146,  146,  146,  168,  169,  146,  199,  146,  105,
++ /*   630 */   146,  107,  108,  212,   98,   99,  100,  112,  132,   42,
++ /*   640 */   168,  169,  168,  169,  168,  169,  184,  185,  168,  169,
++ /*   650 */   168,  169,  168,  169,  181,  146,   59,   60,   61,   62,
++ /*   660 */    63,   64,   65,   66,   67,   68,   69,   70,   71,  146,
++ /*   670 */    73,   74,   75,   76,   77,   78,   79,   80,   81,   82,
++ /*   680 */    16,  146,  207,   22,  207,   21,  146,  146,  146,  146,
++ /*   690 */   146,  168,  169,  146,  160,  146,  187,  146,  225,  200,
++ /*   700 */   201,  106,  146,  168,  169,  110,   42,  146,  168,  169,
++ /*   710 */   168,  169,  168,  169,   16,  168,  169,  168,  169,  168,
++ /*   720 */   169,  146,  181,   59,   60,   61,   62,   63,   64,   65,
++ /*   730 */    66,   67,   68,   69,   70,   71,  146,   73,   74,   75,
++ /*   740 */    76,   77,   78,   79,   80,   81,   82,   16,  146,  146,
++ /*   750 */   146,   25,  146,  146,  146,   29,  146,   22,  168,  169,
++ /*   760 */   146,  129,  187,  131,  146,  202,  225,   41,  212,  146,
++ /*   770 */   168,  169,  146,   42,  168,  169,  168,  169,  168,  169,
++ /*   780 */   146,  120,  168,  169,  181,  181,  168,  169,   90,   79,
++ /*   790 */    59,   60,   61,   62,   63,   64,   65,   66,   67,   68,
++ /*   800 */    69,   70,   71,  146,   73,   74,   75,   76,   77,   78,
++ /*   810 */    79,   80,   81,   82,   16,  146,  106,  154,   90,  146,
++ /*   820 */   110,  146,   87,  146,   19,  168,  169,  146,  225,  225,
++ /*   830 */   102,   19,  146,   21,  123,  124,  146,  168,  169,  177,
++ /*   840 */    42,  168,  169,  168,  169,  168,  169,  177,  113,  168,
++ /*   850 */   169,  188,  146,  146,  168,  169,  177,   59,   60,   61,
++ /*   860 */    62,   63,   64,   65,   66,   67,   68,   69,   70,   71,
++ /*   870 */   146,   73,   74,   75,   76,   77,   78,   79,   80,   81,
++ /*   880 */    82,   16,  146,    7,    8,  146,  146,  154,  146,   20,
++ /*   890 */   146,   22,  168,  169,  187,   20,  146,   22,   20,   20,
++ /*   900 */    22,   22,   89,   90,  168,  169,  146,   42,  168,  169,
++ /*   910 */   168,  169,  168,  169,  146,  146,  111,  146,  146,  154,
++ /*   920 */    20,  188,   22,  146,   16,   60,   61,   62,   63,   64,
++ /*   930 */    65,   66,   67,   68,   69,   70,   71,  187,   73,   74,
++ /*   940 */    75,   76,   77,   78,   79,   80,   81,   82,  146,   20,
++ /*   950 */    42,   22,   20,  188,   22,  187,  187,   19,  187,  187,
++ /*   960 */   230,  154,  154,   51,   52,   20,   20,   22,   22,   61,
++ /*   970 */    62,   63,   64,   65,   66,   67,   68,   69,   70,   71,
++ /*   980 */   231,   73,   74,   75,   76,   77,   78,   79,   80,   81,
++ /*   990 */    82,   16,   17,  146,   19,  188,  188,   20,   23,   22,
++ /*  1000 */    20,  146,   22,  146,  146,   67,   31,   16,   17,  237,
++ /*  1010 */    19,  148,  146,  146,   23,  171,  146,  146,  146,  146,
++ /*  1020 */   146,  190,   31,   48,  192,  222,  146,  227,  227,  176,
++ /*  1030 */   171,  171,  171,   58,  172,  171,  193,    6,  193,   48,
++ /*  1040 */   145,  145,  145,  145,   22,  153,   97,  170,   40,   58,
++ /*  1050 */    96,  170,   77,   78,  170,  172,  170,  120,  117,  115,
++ /*  1060 */    85,   86,   87,  178,  196,   90,  118,  221,   77,   78,
++ /*  1070 */    79,  119,  129,  111,  151,  188,   85,   86,   87,   16,
++ /*  1080 */    17,   90,   19,  193,  109,  194,   23,   95,  195,   23,
++ /*  1090 */   159,  197,  210,  151,   31,   97,  114,   19,  123,  124,
++ /*  1100 */   125,  126,  127,  128,  203,  178,  204,  203,  173,  210,
++ /*  1110 */   204,   48,  159,  210,  123,  124,  125,  126,  127,  128,
++ /*  1120 */   210,   58,    5,  173,   15,  170,  170,   10,   11,   12,
++ /*  1130 */    13,  170,  151,  150,   38,   19,  151,  151,  151,   23,
++ /*  1140 */    77,   78,  129,   26,  233,   28,  232,  150,   85,   86,
++ /*  1150 */    87,  151,   35,   90,   59,  183,  183,   19,  193,   15,
++ /*  1160 */   186,  214,  186,  193,   47,  186,   49,  183,  151,   33,
++ /*  1170 */   151,   54,  214,   56,   58,  235,  151,  136,  158,  174,
++ /*  1180 */   174,    1,   20,   32,   44,   19,  123,  124,  125,  126,
++ /*  1190 */   127,  128,  235,   77,   78,  111,  111,  238,  111,  111,
++ /*  1200 */    19,   90,   86,   20,   20,  106,   90,   19,   11,   19,
++ /*  1210 */   116,   20,  111,   20,   22,   98,   99,  100,   22,  116,
++ /*  1220 */    22,  104,   19,  113,   20,   20,  109,   19,   19,   44,
++ /*  1230 */    20,   19,   19,   44,  102,   94,   16,   21,   17,  123,
++ /*  1240 */   124,  125,   97,   36,   45,   22,   45,  132,   19,   97,
++ /*  1250 */   133,    5,   11,    1,  101,  121,   19,   17,  112,  112,
++ /*  1260 */   101,   67,   67,  121,   19,   14,  135,   20,   57,  134,
++ /*  1270 */     3,  239,    4,
+ };
+-#define YY_SHIFT_USE_DFLT (-75)
++#define YY_SHIFT_USE_DFLT (-98)
++#define YY_SHIFT_MAX 370
+ static const short yy_shift_ofst[] = {
+- /*     0 */   205,    7,  -75,  -75, 1167,  -10,   57,  -75,   47,  475,
+- /*    10 */   399,  123,  337,  -75,  -75,  -75,  -75,  -75,  -75,  475,
+- /*    20 */   446,  475,  543,  475,  757,  456,  858,  453,  240,  799,
+- /*    30 */   865,   50,  -75,  254,  -75,  -16,  -75,  453,  151,  -75,
+- /*    40 */   931,  -75, 1004,  306,  -75,  -75,  -75,  -75,  -75,  -75,
+- /*    50 */   -75,  180,  931,  -75, 1045,  -75,  278,  -75,  -75, 1014,
+- /*    60 */   689,  931, 1038,  -75,  -75,  -75,  -75,  931,  -75, 1122,
+- /*    70 */  1080,  652,  473,  -75,  -75, 1080, 1051, 1052,  -75,  934,
+- /*    80 */   -75,  302, 1079,  -75,  650,  -75,  641, 1091, 1101, 1107,
+- /*    90 */  1112, 1110,  -75, 1080,   40, 1080,  714, 1080,  -75, 1126,
+- /*   100 */   453, 1127,  453,  -75,  -75,  -75,  -75,  -75,  -75, 1223,
+- /*   110 */  1080,  108,  254,  -75,  -75,  455,  321,  595,  -75,  321,
+- /*   120 */  1224,  -75,  -75,  -75,  638,  -75,  -75,  -75,  638,  -75,
+- /*   130 */   -75,  -75,  -75, 1225,  -75, 1080,  -75,  814, 1080,  -12,
+- /*   140 */  1080,  -12, 1080,  -12, 1080,  -12, 1080,  -74, 1080,  -74,
+- /*   150 */  1080,  -53, 1080,  -53, 1080,  -53, 1080,  -53, 1080,  242,
+- /*   160 */  1080,  242, 1080, 1164, 1080, 1164, 1080, 1164, 1080,  -75,
+- /*   170 */   -75,  298,  -75,  -75,  -75,  -75, 1080,  -59, 1080,  -12,
+- /*   180 */   -75,  893,  -75, 1157,  -75,  -75,  -75, 1080,  764, 1080,
+- /*   190 */   -74,  -75,  325,  934,  359,  419, 1140, 1141, 1142,  -75,
+- /*   200 */   714, 1080,  864, 1080,  -75, 1080,  -75, 1080,  -75, 1235,
+- /*   210 */  1079,  376,  -75,  945,  158, 1123,  320, 1242,  -75, 1080,
+- /*   220 */   231, 1080,  714, 1238,  443, 1240,  -75, 1241,  453, 1244,
+- /*   230 */   -75, 1080,  305, 1080,  355, 1080,  714,  780,  -75, 1080,
+- /*   240 */   -75,  -75, 1152,  453,  -75,  -75,  -75,  864, 1080,  714,
+- /*   250 */  1148, 1080, 1249, 1080, 1177,  689,  -75, 1254,  -75,  -75,
+- /*   260 */   714, 1177,  689,  -75, 1080,  714, 1165, 1080, 1260, 1080,
+- /*   270 */   714,  -75,  -75,  239,  -75,  -75,  -75,  430,  -75,  433,
+- /*   280 */   -75, 1172,  -75,  501, 1152,  144,  453,  -75,  -75, 1189,
+- /*   290 */  1174,  -75, 1275,  453,  783,  -75,  453,  -75,  -75, 1080,
+- /*   300 */   714, 1079,  422,  425, 1276,  144, 1189, 1174,  -75, 1021,
+- /*   310 */   -28,  -75,  -75, 1184,   73,  -75,  -75,  429,  -75,  792,
+- /*   320 */   -75, 1280,  -75,  496,  931,  -75,  453, 1285,  -75,   42,
+- /*   330 */   -75,  453,  -75,  550,  928,  -75,  716,  -75,  -75,  -75,
+- /*   340 */   -75,  928,  -75,  928,  -75,  453,  793,  -75,  453, 1177,
+- /*   350 */   689,  -75,  -75, 1177,  689,  -75,  -75, 1254,  -75, 1045,
+- /*   360 */   -75,  -75,   68,  -75, 1080,  564,  -75,  191,  -75,  -75,
+- /*   370 */   191,  -75,  -75,  -75,  -75,  176,  256,  -75,  453,  -75,
+- /*   380 */  1271, 1297,  453,  260, 1300,  931,  -75, 1304,  453,  796,
+- /*   390 */   931,  -75, 1080,  614,  -75, 1281, 1307,  453,  833, 1231,
+- /*   400 */   453, 1285,  -75,  493, 1226,  -75,  -75,  -75,  -75,  -75,
+- /*   410 */  1079,  513,  856,  391,  453, 1152,  -75,  453,  745, 1319,
+- /*   420 */  1079,  548,  453, 1152,  510,  565, 1247,  453, 1152,  -75,
+- /*   430 */  1310,  297, 1342, 1080,  664, 1315,  813,  -75,  -75, 1253,
+- /*   440 */  1255,  809,  453,  882,  -75,  -75, 1311,  -75,  -75, 1220,
+- /*   450 */   453,  862, 1261,  453, 1343,  453,  892,  907, 1357, 1229,
+- /*   460 */  1358,  152,  592,  894,  306,  -75, 1245, 1246, 1351, 1366,
+- /*   470 */  1367,  152, 1359, 1312,  453, 1274,  453,  746,  453, 1305,
+- /*   480 */  1080,  714, 1375, 1313, 1080,  714, 1258,  453, 1364,  453,
+- /*   490 */   947,  -75,  917,  598, 1368, 1080, 1033, 1080,  714, 1382,
+- /*   500 */   714, 1277,  453,    9, 1384,  470,  453, 1386,  453, 1388,
+- /*   510 */   453, 1389,  453, 1390,  605, 1283,  453,    9, 1394, 1312,
+- /*   520 */   453, 1298,  453,  746, 1398, 1282,  453, 1364, 1010,  610,
+- /*   530 */  1385, 1080, 1092, 1399,  530, 1402,  453, 1152,  649,  179,
+- /*   540 */  1407, 1408, 1409, 1410,  453, 1396, 1413, 1387,  254, 1397,
+- /*   550 */   453, 1154, 1415,  778, 1418, 1422,  -75, 1387,  453, 1424,
+- /*   560 */   665,  982, 1425,  734,  982, 1427, 1419,  453,  955, 1301,
+- /*   570 */   453, 1436, 1306, 1303,  453, 1440,  -75, 1439, 1441,  -75,
+- /*   580 */   -75,
++ /*     0 */   221,  975, 1117,  -16,  975, 1063, 1063, 1063,   49,  115,
++ /*    10 */   115,  -97,  118, 1063, 1063, 1063, 1063, 1063,  -45,  131,
++ /*    20 */   116,  328,  225,  225,   51,  185,  252,  324,  396,  463,
++ /*    30 */   530,  597,  664,  731,  798,  731,  731,  731,  731,  731,
++ /*    40 */   731,  731,  731,  731,  731,  731,  731,  731,  731,  731,
++ /*    50 */   731,  731,  865,  908,  908,  991, 1063, 1063, 1063, 1063,
++ /*    60 */  1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063,
++ /*    70 */  1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063,
++ /*    80 */  1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063,
++ /*    90 */  1063, 1063, 1063, 1063,  -60,  -60,  -14,   27,   27,   94,
++ /*   100 */    86,  399,  116,  116,  116,  116,  151,  116,  116,  116,
++ /*   110 */   328,  -59,  -98,  -98,  -98, 1116,   53,  398,  398,  502,
++ /*   120 */   491,  116,  491,  116,  116,  116,  116,  116,  116,  116,
++ /*   130 */   116,  116,  116,  116,  116,  116,   29,  443,  -97,  -97,
++ /*   140 */   -97,  -98,  -98,  147,  147,  128,  272,  403,  262,  410,
++ /*   150 */   461,  412,  268,  408,  468,  470,  573,  116,  116,  710,
++ /*   160 */   116,  116,   73,  116,  116,  735,  116,  116,  524,  735,
++ /*   170 */   116,  116,  312,  312,  312,  116,  116,  524,  116,  116,
++ /*   180 */   524,  116,  726,  516,  116,  116,  524,  116,  116,  116,
++ /*   190 */   524,  116,  524,  524,  116,  116,  116,  116,  116,  116,
++ /*   200 */   812,  458,  595,  525,  711,  711,  632,  458,  458,   56,
++ /*   210 */   458,  458,  487,  661,  661, 1031, 1031, 1031, 1031, 1022,
++ /*   220 */   949,  949, 1008,  949,  954,  949,  -97,  937,  941,  948,
++ /*   230 */   944,  952,  943,  962,  992, 1066,  992,  962,  998,  982,
++ /*   240 */   998,  982, 1078,  992,  992, 1066, 1008,  949,  949,  949,
++ /*   250 */  1078, 1109,  962,  962,  962,  962, 1096, 1013, 1109,  962,
++ /*   260 */  1095, 1095, 1138,  937, 1144, 1144, 1144,  937, 1095, 1138,
++ /*   270 */   962, 1136, 1136,  962,  962, 1041,  -98,  -98,  -98,  148,
++ /*   280 */   506,  536,  505,  728,  876,  805,  869,  698,  875,  878,
++ /*   290 */   879,  813,  900,  929,  932,  912,  945,  946,  977,  980,
++ /*   300 */   938, 1180, 1162, 1151, 1140, 1166, 1084, 1085, 1087, 1088,
++ /*   310 */  1181, 1183, 1184, 1111, 1099, 1188, 1197, 1190, 1191, 1192,
++ /*   320 */  1193, 1094, 1196, 1103, 1198, 1110, 1203, 1204, 1101, 1205,
++ /*   330 */  1185, 1208, 1210, 1209, 1212, 1189, 1213, 1141, 1132, 1220,
++ /*   340 */  1221, 1216, 1145, 1207, 1199, 1223, 1201, 1115, 1152, 1229,
++ /*   350 */  1246, 1241, 1252, 1153, 1194, 1195, 1134, 1237, 1146, 1240,
++ /*   360 */  1147, 1159, 1142, 1245, 1247, 1251, 1211, 1135, 1131, 1267,
++ /*   370 */  1268,
+ };
+-#define YY_REDUCE_USE_DFLT (-61)
++#define YY_REDUCE_USE_DFLT (-216)
++#define YY_REDUCE_MAX 278
+ static const short yy_reduce_ofst[] = {
+- /*     0 */   -48,   61,  -61,  -61,  -60,  -61,  -61,  -61,  -32,   12,
+- /*    10 */   -61,  181,  -61,  -61,  -61,  -61,  -61,  -61,  -61,  314,
+- /*    20 */   -61,  386,  -61,  622,  -61,  654,  -61,   51,  798,  -61,
+- /*    30 */   -61,  -23,  -61,  -26,  760,   89,  -61,  860,  486,  -61,
+- /*    40 */   867,  -61,  -61,   65,  -61,  -61,  -61,  -61,  -61,  -61,
+- /*    50 */   -61,  -61,  909,  -61,  910,  -61,  -61,  -61,  -61,  -61,
+- /*    60 */   914,  962,  964,  -61,  -61,  -61,  -61,  968,  -61,  -61,
+- /*    70 */   438,  -61,  996,  -61,  -61,  116,  -61,  -61,  -61,  293,
+- /*    80 */   -61, 1000, 1006,  -61, 1011,  569, 1005, 1026, 1034, 1035,
+- /*    90 */  1036, 1041,  -61,  490,  394,  552,  394,  601,  -61,  -61,
+- /*   100 */  1087,  -61, 1093,  -61,  -61,  -61,  -61,  -61,  -61,  -61,
+- /*   110 */   603,  394,   53,  -61,  -61, 1082,  110,  -61,  -61,  229,
+- /*   120 */   -61,  -61,  -61,  -61, 1019,  -61,  -61,  -61, 1020,  -61,
+- /*   130 */   -61,  -61,  -61,  -61,  -61,  640,  -61,  394,  651,  394,
+- /*   140 */   690,  394,  701,  394,  703,  394,  740,  394,  751,  394,
+- /*   150 */   753,  394,  755,  394,  790,  394,  801,  394,  803,  394,
+- /*   160 */   818,  394,  829,  394,  831,  394,  835,  394,  841,  394,
+- /*   170 */   -61,  -61,  -61,  -61,  -61,  -61,  846,  188,  849,  394,
+- /*   180 */   -61,  -61,  -61,  -61,  -61,  -61,  -61,  879,  394,  881,
+- /*   190 */   394,  -61, 1102,   -6, 1000,  -61,  -61,  -61,  -61,  -61,
+- /*   200 */   394,  887,  394,  898,  394,  918,  394,  936,  394,  -61,
+- /*   210 */   662, 1000,  -61,  295,  394, 1037, 1039,  -61,  -61,  946,
+- /*   220 */   394,  948,  394,  -61, 1073,  -61,  -61,  -61, 1114,  -61,
+- /*   230 */   -61,  950,  394,  956,  394,  974,  394,  -61,  -61,  303,
+- /*   240 */   -61,  -61, 1118, 1124,  -61,  -61,  -61,  394,  984,  394,
+- /*   250 */   -61,  183,  -61,  190, 1065, 1104,  -61, 1119,  -61,  -61,
+- /*   260 */   394, 1070, 1109,  -61,  987,  394,  -61,  187,  -61, 1007,
+- /*   270 */   394,  -61,  398, 1083,  -61,  -61,  -61, 1136,  -61, 1138,
+- /*   280 */   -61,  -61,  -61, 1143, 1137,  389, 1144,  -61,  -61, 1090,
+- /*   290 */  1094,  -61,  -61,  604,  -61,  -61, 1147,  -61,  -61, 1015,
+- /*   300 */   394,  132, 1000, 1083,  -61,  512, 1096, 1097,  -61, 1018,
+- /*   310 */   241,  -61,  -61,  -61, 1087,  -61,  -61,  394,  -61,  -61,
+- /*   320 */   -61,  -61,  -61,  394, 1131,  -61, 1155, 1132, 1130, 1133,
+- /*   330 */   -61, 1159,  -61,  -61, 1134,  -61,  -61,  -61,  -61,  -61,
+- /*   340 */   -61, 1135,  -61, 1139,  -61,  439,  -61,  -61,  765, 1098,
+- /*   350 */  1146,  -61,  -61, 1099, 1149,  -61,  -61, 1151,  -61, 1145,
+- /*   360 */   -61,  -61,  692,  -61, 1022,  394,  -61, 1150,  -61,  -61,
+- /*   370 */  1153,  -61,  -61,  -61,  -61, 1156, 1158,  -61, 1166,  -61,
+- /*   380 */   -61,  -61,  899, 1160,  -61, 1161,  -61,  -61,  949,  -61,
+- /*   390 */  1163,  -61, 1030,  375,  -61,  -61,  -61,  979,  -61,  -61,
+- /*   400 */  1180, 1162, 1168,  527,  -61,  -61,  -61,  -61,  -61,  -61,
+- /*   410 */   712, 1000,  756,  -61, 1181, 1179,  -61, 1187, 1186,  -61,
+- /*   420 */   807, 1000, 1193, 1190, 1115, 1113,  -61,  715, 1195,  -61,
+- /*   430 */  1117, 1120,  -61, 1048,  394,  -61,  -61,  -61,  -61,  -61,
+- /*   440 */   -61,  -61,  709,  -61,  -61,  -61,  -61,  -61,  -61,  -61,
+- /*   450 */  1209, 1206,  -61, 1211,  -61,  997,  -61, 1192,  -61,  -61,
+- /*   460 */   -61,  315, 1000, 1183,  732,  -61,  -61,  -61,  -61,  -61,
+- /*   470 */   -61,  382,  -61, 1191, 1228,  -61,  808, 1185, 1232,  -61,
+- /*   480 */  1055,  394,  -61,  -61, 1064,  394,  -61, 1236, 1171,  767,
+- /*   490 */   -61,  -61,  854, 1000,  -61,  -18,  -61, 1067,  394,  -61,
+- /*   500 */   394,  -61, 1248, 1196,  -61,  -61,  815,  -61,  891,  -61,
+- /*   510 */   895,  -61,  906,  -61, 1000,  -61,  942, 1202,  -61, 1215,
+- /*   520 */   943,  -61,  959, 1207,  -61,  -61,  975, 1194,  985, 1000,
+- /*   530 */   -61,  434,  -61,  -61, 1259,  -61, 1262, 1257,  -61,  435,
+- /*   540 */   -61,  -61,  -61,  -61, 1267,  -61,  -61, 1188, 1263,  -61,
+- /*   550 */  1273, 1197,  -61, 1264,  -61,  -61,  -61, 1199, 1279,  -61,
+- /*   560 */  1284, 1278,  -61, 1287, 1286,  -61,  -61,  522,  -61,  -61,
+- /*   570 */  1291,  -61,  -61, 1204,  -58,  -61,  -61,  -61,  -61,  -61,
+- /*   580 */   -61,
++ /*     0 */   -56,  136,   16,   70,  189,  127,   66,  130,  190,  219,
++ /*    10 */   255,  220,   61,  132,  138,  210,  265,  271, -178, -140,
++ /*    20 */   -61,   79,  145,  264, -215, -215, -215, -215, -215, -215,
++ /*    30 */  -215, -215, -215, -215, -215, -215, -215, -215, -215, -215,
++ /*    40 */  -215, -215, -215, -215, -215, -215, -215, -215, -215, -215,
++ /*    50 */  -215, -215, -215, -215, -215,  402,  405,  407,  416,  418,
++ /*    60 */   456,  472,  474,  476,  480,  482,  484,  523,  535,  540,
++ /*    70 */   542,  544,  547,  549,  551,  590,  602,  606,  608,  610,
++ /*    80 */   614,  618,  657,  669,  673,  675,  677,  681,  686,  724,
++ /*    90 */   736,  740,  742,  744, -215, -215,  -77, -215, -215, -215,
++ /*   100 */  -215,   50,  354,  473,  541,  603,  144,  604,  772,  342,
++ /*   110 */   284, -215, -215, -215, -215,  282,  251,  322,  462,  -72,
++ /*   120 */   177,  306,  428,  353,  193,  475,  421,  477,  509,  575,
++ /*   130 */   707,  750,  768,  771,  556,  769,  663,  733,  765,  807,
++ /*   140 */   808,  -42,  499, -126, -112,  -57,  -19,   18,   96,   18,
++ /*   150 */    18,   72,  141,  146,  198,  250,  223,  336,  370,  373,
++ /*   160 */   250,  543,  534,  561,  607,  563,  623,  626,   18,  563,
++ /*   170 */   634,  690,  662,  670,  679,  706,  739,   18,  760,  777,
++ /*   180 */    18,  802,  730,  749,  847,  855,   18,  857,  858,  866,
++ /*   190 */    18,  867,   18,   18,  870,  871,  872,  873,  874,  880,
++ /*   200 */   863,  844,  831,  832,  800,  801,  803,  859,  860,  853,
++ /*   210 */   861,  864,  862,  843,  845,  895,  896,  897,  898,  892,
++ /*   220 */   877,  881,  885,  884,  883,  886,  887,  890,  891,  893,
++ /*   230 */   868,  894,  846,  923,  882,  931,  899,  942,  901,  902,
++ /*   240 */   904,  906,  935,  903,  910,  953,  927,  955,  956,  961,
++ /*   250 */   950,  983,  981,  985,  986,  987,  914,  911,  997, 1000,
++ /*   260 */   972,  973,  947,  965,  974,  976,  979,  970,  984,  958,
++ /*   270 */  1017,  940,  957, 1019, 1025,  959, 1020, 1005, 1006,
+ };
+ static const YYACTIONTYPE yy_default[] = {
+- /*     0 */   587,  587,  582,  585,  892,  892,  892,  586,  594,  892,
+- /*    10 */   892,  892,  892,  614,  615,  616,  595,  596,  597,  892,
+- /*    20 */   892,  892,  892,  892,  892,  892,  892,  892,  892,  892,
+- /*    30 */   892,  892,  607,  617,  627,  609,  626,  892,  892,  628,
+- /*    40 */   672,  635,  892,  892,  673,  676,  677,  678,  872,  873,
+- /*    50 */   874,  892,  672,  636,  657,  655,  892,  658,  659,  892,
+- /*    60 */   728,  672,  643,  637,  644,  726,  727,  672,  638,  892,
+- /*    70 */   892,  758,  692,  690,  691,  824,  764,  759,  755,  892,
+- /*    80 */   683,  892,  892,  684,  692,  694,  701,  740,  731,  733,
+- /*    90 */   721,  735,  689,  892,  736,  892,  737,  892,  757,  892,
+- /*   100 */   892,  760,  892,  761,  762,  763,  765,  766,  767,  892,
+- /*   110 */   892,  892,  892,  612,  613,  619,  847,  892,  620,  847,
+- /*   120 */   892,  621,  624,  625,  892,  842,  844,  845,  892,  843,
+- /*   130 */   846,  623,  622,  892,  768,  892,  771,  773,  892,  774,
+- /*   140 */   892,  775,  892,  776,  892,  777,  892,  778,  892,  779,
+- /*   150 */   892,  780,  892,  781,  892,  782,  892,  783,  892,  784,
+- /*   160 */   892,  785,  892,  786,  892,  787,  892,  788,  892,  789,
+- /*   170 */   790,  892,  791,  798,  805,  808,  892,  793,  892,  792,
+- /*   180 */   795,  892,  796,  892,  799,  797,  804,  892,  892,  892,
+- /*   190 */   806,  807,  892,  824,  892,  892,  892,  892,  892,  811,
+- /*   200 */   823,  892,  800,  892,  801,  892,  802,  892,  803,  892,
+- /*   210 */   892,  892,  813,  892,  892,  892,  892,  892,  814,  892,
+- /*   220 */   892,  892,  815,  892,  892,  892,  870,  892,  892,  892,
+- /*   230 */   871,  892,  892,  892,  892,  892,  816,  892,  809,  824,
+- /*   240 */   821,  822,  709,  892,  710,  812,  794,  772,  892,  738,
+- /*   250 */   892,  892,  722,  892,  729,  728,  723,  892,  611,  730,
+- /*   260 */   725,  729,  728,  724,  892,  734,  892,  824,  732,  892,
+- /*   270 */   741,  693,  704,  702,  703,  712,  713,  892,  714,  892,
+- /*   280 */   715,  892,  716,  892,  709,  700,  892,  698,  699,  718,
+- /*   290 */   720,  705,  892,  892,  892,  719,  892,  753,  754,  892,
+- /*   300 */   717,  704,  892,  892,  892,  700,  718,  720,  706,  892,
+- /*   310 */   700,  695,  696,  892,  892,  697,  810,  892,  756,  892,
+- /*   320 */   769,  892,  770,  892,  672,  639,  892,  828,  645,  640,
+- /*   330 */   646,  892,  647,  892,  892,  648,  892,  651,  652,  653,
+- /*   340 */   654,  892,  649,  892,  650,  892,  892,  829,  892,  729,
+- /*   350 */   728,  830,  832,  729,  728,  831,  641,  892,  642,  657,
+- /*   360 */   656,  629,  892,  630,  892,  892,  631,  892,  632,  764,
+- /*   370 */   892,  633,  634,  618,  610,  892,  892,  662,  892,  665,
+- /*   380 */   892,  892,  892,  892,  892,  672,  666,  892,  892,  892,
+- /*   390 */   672,  667,  892,  672,  668,  892,  892,  892,  892,  892,
+- /*   400 */   892,  828,  645,  670,  892,  669,  671,  663,  664,  608,
+- /*   410 */   892,  892,  604,  892,  892,  709,  602,  892,  892,  892,
+- /*   420 */   892,  892,  892,  709,  853,  892,  892,  892,  709,  711,
+- /*   430 */   858,  892,  892,  892,  892,  892,  892,  859,  860,  892,
+- /*   440 */   892,  892,  892,  892,  850,  851,  892,  852,  603,  892,
+- /*   450 */   892,  892,  892,  892,  892,  892,  892,  892,  892,  892,
+- /*   460 */   892,  892,  892,  892,  892,  675,  892,  892,  892,  892,
+- /*   470 */   892,  892,  892,  674,  892,  892,  892,  892,  892,  892,
+- /*   480 */   892,  743,  892,  892,  892,  744,  892,  892,  751,  892,
+- /*   490 */   892,  752,  892,  892,  892,  892,  892,  892,  749,  892,
+- /*   500 */   750,  892,  892,  892,  892,  892,  892,  892,  892,  892,
+- /*   510 */   892,  892,  892,  892,  892,  892,  892,  892,  892,  674,
+- /*   520 */   892,  892,  892,  892,  892,  892,  892,  751,  892,  892,
+- /*   530 */   892,  892,  892,  892,  892,  892,  892,  709,  892,  847,
+- /*   540 */   892,  892,  892,  892,  892,  892,  892,  881,  892,  892,
+- /*   550 */   892,  892,  892,  892,  892,  892,  880,  881,  892,  892,
+- /*   560 */   892,  892,  892,  892,  892,  892,  892,  892,  892,  892,
+- /*   570 */   892,  892,  892,  890,  892,  892,  891,  588,  892,  589,
+- /*   580 */   583,
++ /*     0 */   566,  790,  855,  681,  855,  790,  855,  790,  855,  828,
++ /*    10 */   828,  685,  841,  786,  790,  855,  855,  855,  761,  812,
++ /*    20 */   855,  597,  812,  812,  716,  855,  855,  855,  855,  855,
++ /*    30 */   855,  855,  855,  717,  855,  789,  785,  781,  783,  782,
++ /*    40 */   718,  705,  714,  721,  697,  826,  723,  724,  729,  730,
++ /*    50 */   842,  845,  751,  767,  750,  855,  855,  855,  855,  855,
++ /*    60 */   855,  855,  855,  855,  855,  855,  855,  855,  855,  855,
++ /*    70 */   855,  855,  855,  855,  855,  855,  855,  855,  855,  855,
++ /*    80 */   855,  855,  855,  855,  855,  855,  855,  855,  855,  855,
++ /*    90 */   855,  855,  855,  855,  753,  772,  590,  752,  760,  754,
++ /*   100 */   755,  650,  855,  855,  855,  855,  585,  855,  855,  855,
++ /*   110 */   855,  756,  757,  768,  769,  855,  855,  855,  855,  566,
++ /*   120 */   681,  855,  681,  855,  855,  855,  855,  855,  855,  855,
++ /*   130 */   855,  855,  855,  855,  855,  855,  855,  855,  855,  855,
++ /*   140 */   855,  675,  685,  855,  855,  641,  855,  855,  855,  855,
++ /*   150 */   855,  855,  855,  855,  855,  855,  573,  571,  855,  673,
++ /*   160 */   855,  855,  599,  855,  855,  683,  855,  855,  688,  689,
++ /*   170 */   855,  855,  855,  855,  855,  855,  855,  587,  855,  855,
++ /*   180 */   662,  855,  818,  855,  855,  855,  833,  855,  855,  855,
++ /*   190 */   831,  855,  664,  726,  800,  855,  855,  846,  848,  855,
++ /*   200 */   855,  708,  673,  682,  855,  855,  784,  708,  708,  620,
++ /*   210 */   708,  708,  623,  720,  720,  570,  570,  570,  570,  640,
++ /*   220 */   652,  652,  637,  652,  623,  652,  855,  720,  711,  713,
++ /*   230 */   701,  715,  855,  690,  709,  855,  709,  690,  698,  700,
++ /*   240 */   698,  700,  794,  709,  709,  855,  637,  652,  652,  652,
++ /*   250 */   794,  582,  690,  690,  690,  690,  822,  825,  582,  690,
++ /*   260 */   654,  654,  731,  720,  661,  661,  661,  720,  654,  731,
++ /*   270 */   690,  844,  844,  690,  690,  853,  607,  625,  625,  855,
++ /*   280 */   855,  855,  855,  855,  855,  738,  855,  855,  855,  855,
++ /*   290 */   855,  855,  855,  855,  855,  855,  855,  855,  855,  855,
++ /*   300 */   807,  855,  855,  855,  855,  855,  743,  739,  855,  740,
++ /*   310 */   855,  855,  855,  855,  667,  855,  855,  855,  855,  855,
++ /*   320 */   855,  855,  702,  855,  712,  855,  855,  855,  855,  855,
++ /*   330 */   855,  855,  855,  855,  855,  855,  855,  855,  855,  855,
++ /*   340 */   855,  855,  855,  855,  820,  821,  855,  855,  855,  855,
++ /*   350 */   855,  855,  855,  855,  855,  855,  855,  855,  855,  855,
++ /*   360 */   855,  855,  855,  855,  855,  855,  852,  855,  855,  567,
++ /*   370 */   855,  561,  564,  563,  565,  569,  572,  594,  595,  596,
++ /*   380 */   574,  575,  576,  577,  578,  579,  580,  586,  588,  606,
++ /*   390 */   608,  615,  653,  656,  657,  658,  836,  837,  838,  616,
++ /*   400 */   635,  638,  639,  617,  624,  706,  707,  618,  671,  672,
++ /*   410 */   735,  665,  666,  670,  737,  741,  742,  744,  745,  593,
++ /*   420 */   600,  601,  604,  605,  808,  810,  809,  811,  603,  602,
++ /*   430 */   746,  749,  758,  759,  765,  771,  774,  763,  764,  766,
++ /*   440 */   770,  773,  668,  669,  777,  779,  780,  834,  835,  775,
++ /*   450 */   787,  788,  691,  778,  762,  703,  592,  710,  704,  674,
++ /*   460 */   684,  693,  694,  695,  696,  679,  680,  686,  699,  733,
++ /*   470 */   734,  687,  676,  677,  678,  776,  736,  747,  748,  619,
++ /*   480 */   626,  627,  628,  631,  632,  633,  634,  629,  630,  795,
++ /*   490 */   796,  798,  797,  621,  622,  636,  609,  610,  611,  612,
++ /*   500 */   743,  613,  614,  598,  591,  642,  645,  646,  647,  648,
++ /*   510 */   649,  651,  643,  644,  589,  581,  583,  692,  814,  823,
++ /*   520 */   824,  819,  815,  816,  817,  584,  791,  792,  655,  727,
++ /*   530 */   728,  813,  827,  829,  732,  830,  832,  659,  660,  663,
++ /*   540 */   799,  839,  719,  722,  725,  801,  802,  803,  804,  805,
++ /*   550 */   806,  840,  843,  847,  849,  850,  851,  854,  568,  562,
+ };
+ #define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
+ 
+@@ -670,75 +581,66 @@
+ #ifdef YYFALLBACK
+ static const YYCODETYPE yyFallback[] = {
+     0,  /*          $ => nothing */
+-    0,  /* END_OF_FILE => nothing */
+-    0,  /*    ILLEGAL => nothing */
+-    0,  /*      SPACE => nothing */
+-    0,  /* UNCLOSED_STRING => nothing */
+-    0,  /*    COMMENT => nothing */
+-    0,  /*   FUNCTION => nothing */
+-    0,  /*     COLUMN => nothing */
+-    0,  /* AGG_FUNCTION => nothing */
+-    0,  /* AGG_COLUMN => nothing */
+-    0,  /* CONST_FUNC => nothing */
+     0,  /*       SEMI => nothing */
+-   30,  /*    EXPLAIN => ID */
+-   30,  /*      QUERY => ID */
+-   30,  /*       PLAN => ID */
+-   30,  /*      BEGIN => ID */
++   23,  /*    EXPLAIN => ID */
++   23,  /*      QUERY => ID */
++   23,  /*       PLAN => ID */
++   23,  /*      BEGIN => ID */
+     0,  /* TRANSACTION => nothing */
+-   30,  /*   DEFERRED => ID */
+-   30,  /*  IMMEDIATE => ID */
+-   30,  /*  EXCLUSIVE => ID */
++   23,  /*   DEFERRED => ID */
++   23,  /*  IMMEDIATE => ID */
++   23,  /*  EXCLUSIVE => ID */
+     0,  /*     COMMIT => nothing */
+-   30,  /*        END => ID */
++   23,  /*        END => ID */
+     0,  /*   ROLLBACK => nothing */
+     0,  /*     CREATE => nothing */
+     0,  /*      TABLE => nothing */
+-   30,  /*       TEMP => ID */
++   23,  /*         IF => ID */
++    0,  /*        NOT => nothing */
++    0,  /*     EXISTS => nothing */
++   23,  /*       TEMP => ID */
+     0,  /*         LP => nothing */
+     0,  /*         RP => nothing */
+     0,  /*         AS => nothing */
+     0,  /*      COMMA => nothing */
+     0,  /*         ID => nothing */
+-   30,  /*      ABORT => ID */
+-   30,  /*      AFTER => ID */
+-   30,  /*    ANALYZE => ID */
+-   30,  /*        ASC => ID */
+-   30,  /*     ATTACH => ID */
+-   30,  /*     BEFORE => ID */
+-   30,  /*    CASCADE => ID */
+-   30,  /*       CAST => ID */
+-   30,  /*   CONFLICT => ID */
+-   30,  /*   DATABASE => ID */
+-   30,  /*       DESC => ID */
+-   30,  /*     DETACH => ID */
+-   30,  /*       EACH => ID */
+-   30,  /*       FAIL => ID */
+-   30,  /*        FOR => ID */
+-   30,  /*     IGNORE => ID */
+-   30,  /*  INITIALLY => ID */
+-   30,  /*    INSTEAD => ID */
+-   30,  /*    LIKE_KW => ID */
+-   30,  /*      MATCH => ID */
+-   30,  /*        KEY => ID */
+-   30,  /*         OF => ID */
+-   30,  /*     OFFSET => ID */
+-   30,  /*     PRAGMA => ID */
+-   30,  /*      RAISE => ID */
+-   30,  /*    REPLACE => ID */
+-   30,  /*   RESTRICT => ID */
+-   30,  /*        ROW => ID */
+-   30,  /*  STATEMENT => ID */
+-   30,  /*    TRIGGER => ID */
+-   30,  /*     VACUUM => ID */
+-   30,  /*       VIEW => ID */
+-   30,  /*    REINDEX => ID */
+-   30,  /*     RENAME => ID */
+-   30,  /*   CTIME_KW => ID */
+-   30,  /*      ALTER => ID */
++   23,  /*      ABORT => ID */
++   23,  /*      AFTER => ID */
++   23,  /*    ANALYZE => ID */
++   23,  /*        ASC => ID */
++   23,  /*     ATTACH => ID */
++   23,  /*     BEFORE => ID */
++   23,  /*    CASCADE => ID */
++   23,  /*       CAST => ID */
++   23,  /*   CONFLICT => ID */
++   23,  /*   DATABASE => ID */
++   23,  /*       DESC => ID */
++   23,  /*     DETACH => ID */
++   23,  /*       EACH => ID */
++   23,  /*       FAIL => ID */
++   23,  /*        FOR => ID */
++   23,  /*     IGNORE => ID */
++   23,  /*  INITIALLY => ID */
++   23,  /*    INSTEAD => ID */
++   23,  /*    LIKE_KW => ID */
++   23,  /*      MATCH => ID */
++   23,  /*        KEY => ID */
++   23,  /*         OF => ID */
++   23,  /*     OFFSET => ID */
++   23,  /*     PRAGMA => ID */
++   23,  /*      RAISE => ID */
++   23,  /*    REPLACE => ID */
++   23,  /*   RESTRICT => ID */
++   23,  /*        ROW => ID */
++   23,  /*  STATEMENT => ID */
++   23,  /*    TRIGGER => ID */
++   23,  /*     VACUUM => ID */
++   23,  /*       VIEW => ID */
++   23,  /*    REINDEX => ID */
++   23,  /*     RENAME => ID */
++   23,  /*   CTIME_KW => ID */
+     0,  /*         OR => nothing */
+     0,  /*        AND => nothing */
+-    0,  /*        NOT => nothing */
+     0,  /*         IS => nothing */
+     0,  /*    BETWEEN => nothing */
+     0,  /*         IN => nothing */
+@@ -785,8 +687,8 @@
+     0,  /*       DROP => nothing */
+     0,  /*      UNION => nothing */
+     0,  /*        ALL => nothing */
+-    0,  /*  INTERSECT => nothing */
+     0,  /*     EXCEPT => nothing */
++    0,  /*  INTERSECT => nothing */
+     0,  /*     SELECT => nothing */
+     0,  /*   DISTINCT => nothing */
+     0,  /*        DOT => nothing */
+@@ -806,12 +708,12 @@
+     0,  /*       BLOB => nothing */
+     0,  /*   REGISTER => nothing */
+     0,  /*   VARIABLE => nothing */
+-    0,  /*     EXISTS => nothing */
+     0,  /*       CASE => nothing */
+     0,  /*       WHEN => nothing */
+     0,  /*       THEN => nothing */
+     0,  /*       ELSE => nothing */
+     0,  /*      INDEX => nothing */
++    0,  /*      ALTER => nothing */
+     0,  /*         TO => nothing */
+     0,  /*        ADD => nothing */
+     0,  /*   COLUMNKW => nothing */
+@@ -885,46 +787,44 @@
+ /* For tracing shifts, the names of all terminals and nonterminals
+ ** are required.  The following table supplies these names */
+ static const char *const yyTokenName[] = { 
+-  "$",             "END_OF_FILE",   "ILLEGAL",       "SPACE",       
+-  "UNCLOSED_STRING",  "COMMENT",       "FUNCTION",      "COLUMN",      
+-  "AGG_FUNCTION",  "AGG_COLUMN",    "CONST_FUNC",    "SEMI",        
+-  "EXPLAIN",       "QUERY",         "PLAN",          "BEGIN",       
+-  "TRANSACTION",   "DEFERRED",      "IMMEDIATE",     "EXCLUSIVE",   
+-  "COMMIT",        "END",           "ROLLBACK",      "CREATE",      
+-  "TABLE",         "TEMP",          "LP",            "RP",          
+-  "AS",            "COMMA",         "ID",            "ABORT",       
+-  "AFTER",         "ANALYZE",       "ASC",           "ATTACH",      
+-  "BEFORE",        "CASCADE",       "CAST",          "CONFLICT",    
+-  "DATABASE",      "DESC",          "DETACH",        "EACH",        
+-  "FAIL",          "FOR",           "IGNORE",        "INITIALLY",   
+-  "INSTEAD",       "LIKE_KW",       "MATCH",         "KEY",         
+-  "OF",            "OFFSET",        "PRAGMA",        "RAISE",       
+-  "REPLACE",       "RESTRICT",      "ROW",           "STATEMENT",   
+-  "TRIGGER",       "VACUUM",        "VIEW",          "REINDEX",     
+-  "RENAME",        "CTIME_KW",      "ALTER",         "OR",          
+-  "AND",           "NOT",           "IS",            "BETWEEN",     
+-  "IN",            "ISNULL",        "NOTNULL",       "NE",          
+-  "EQ",            "GT",            "LE",            "LT",          
+-  "GE",            "ESCAPE",        "BITAND",        "BITOR",       
+-  "LSHIFT",        "RSHIFT",        "PLUS",          "MINUS",       
+-  "STAR",          "SLASH",         "REM",           "CONCAT",      
+-  "UMINUS",        "UPLUS",         "BITNOT",        "STRING",      
+-  "JOIN_KW",       "CONSTRAINT",    "DEFAULT",       "NULL",        
+-  "PRIMARY",       "UNIQUE",        "CHECK",         "REFERENCES",  
+-  "COLLATE",       "AUTOINCR",      "ON",            "DELETE",      
+-  "UPDATE",        "INSERT",        "SET",           "DEFERRABLE",  
+-  "FOREIGN",       "DROP",          "UNION",         "ALL",         
+-  "INTERSECT",     "EXCEPT",        "SELECT",        "DISTINCT",    
+-  "DOT",           "FROM",          "JOIN",          "USING",       
+-  "ORDER",         "BY",            "GROUP",         "HAVING",      
+-  "LIMIT",         "WHERE",         "INTO",          "VALUES",      
+-  "INTEGER",       "FLOAT",         "BLOB",          "REGISTER",    
+-  "VARIABLE",      "EXISTS",        "CASE",          "WHEN",        
+-  "THEN",          "ELSE",          "INDEX",         "TO",          
+-  "ADD",           "COLUMNKW",      "error",         "input",       
+-  "cmdlist",       "ecmd",          "cmdx",          "cmd",         
+-  "explain",       "transtype",     "trans_opt",     "nm",          
+-  "create_table",  "create_table_args",  "temp",          "dbnm",        
++  "$",             "SEMI",          "EXPLAIN",       "QUERY",       
++  "PLAN",          "BEGIN",         "TRANSACTION",   "DEFERRED",    
++  "IMMEDIATE",     "EXCLUSIVE",     "COMMIT",        "END",         
++  "ROLLBACK",      "CREATE",        "TABLE",         "IF",          
++  "NOT",           "EXISTS",        "TEMP",          "LP",          
++  "RP",            "AS",            "COMMA",         "ID",          
++  "ABORT",         "AFTER",         "ANALYZE",       "ASC",         
++  "ATTACH",        "BEFORE",        "CASCADE",       "CAST",        
++  "CONFLICT",      "DATABASE",      "DESC",          "DETACH",      
++  "EACH",          "FAIL",          "FOR",           "IGNORE",      
++  "INITIALLY",     "INSTEAD",       "LIKE_KW",       "MATCH",       
++  "KEY",           "OF",            "OFFSET",        "PRAGMA",      
++  "RAISE",         "REPLACE",       "RESTRICT",      "ROW",         
++  "STATEMENT",     "TRIGGER",       "VACUUM",        "VIEW",        
++  "REINDEX",       "RENAME",        "CTIME_KW",      "OR",          
++  "AND",           "IS",            "BETWEEN",       "IN",          
++  "ISNULL",        "NOTNULL",       "NE",            "EQ",          
++  "GT",            "LE",            "LT",            "GE",          
++  "ESCAPE",        "BITAND",        "BITOR",         "LSHIFT",      
++  "RSHIFT",        "PLUS",          "MINUS",         "STAR",        
++  "SLASH",         "REM",           "CONCAT",        "UMINUS",      
++  "UPLUS",         "BITNOT",        "STRING",        "JOIN_KW",     
++  "CONSTRAINT",    "DEFAULT",       "NULL",          "PRIMARY",     
++  "UNIQUE",        "CHECK",         "REFERENCES",    "COLLATE",     
++  "AUTOINCR",      "ON",            "DELETE",        "UPDATE",      
++  "INSERT",        "SET",           "DEFERRABLE",    "FOREIGN",     
++  "DROP",          "UNION",         "ALL",           "EXCEPT",      
++  "INTERSECT",     "SELECT",        "DISTINCT",      "DOT",         
++  "FROM",          "JOIN",          "USING",         "ORDER",       
++  "BY",            "GROUP",         "HAVING",        "LIMIT",       
++  "WHERE",         "INTO",          "VALUES",        "INTEGER",     
++  "FLOAT",         "BLOB",          "REGISTER",      "VARIABLE",    
++  "CASE",          "WHEN",          "THEN",          "ELSE",        
++  "INDEX",         "ALTER",         "TO",            "ADD",         
++  "COLUMNKW",      "error",         "input",         "cmdlist",     
++  "ecmd",          "cmdx",          "cmd",           "explain",     
++  "transtype",     "trans_opt",     "nm",            "create_table",
++  "create_table_args",  "temp",          "ifnotexists",   "dbnm",        
+   "columnlist",    "conslist_opt",  "select",        "column",      
+   "columnid",      "type",          "carglist",      "id",          
+   "ids",           "typetoken",     "typename",      "signed",      
+@@ -933,20 +833,20 @@
+   "autoinc",       "idxlist_opt",   "refargs",       "defer_subclause",
+   "refarg",        "refact",        "init_deferred_pred_opt",  "conslist",    
+   "tcons",         "idxlist",       "defer_subclause_opt",  "orconf",      
+-  "resolvetype",   "raisetype",     "fullname",      "oneselect",   
+-  "multiselect_op",  "distinct",      "selcollist",    "from",        
+-  "where_opt",     "groupby_opt",   "having_opt",    "orderby_opt", 
+-  "limit_opt",     "sclp",          "as",            "seltablist",  
+-  "stl_prefix",    "joinop",        "on_opt",        "using_opt",   
+-  "seltablist_paren",  "joinop2",       "inscollist",    "sortlist",    
+-  "sortitem",      "collate",       "exprlist",      "setlist",     
+-  "insert_cmd",    "inscollist_opt",  "itemlist",      "likeop",      
+-  "escape",        "between_op",    "in_op",         "case_operand",
+-  "case_exprlist",  "case_else",     "expritem",      "uniqueflag",  
+-  "idxitem",       "plus_opt",      "number",        "trigger_decl",
+-  "trigger_cmd_list",  "trigger_time",  "trigger_event",  "foreach_clause",
+-  "when_clause",   "trigger_cmd",   "database_kw_opt",  "key_opt",     
+-  "add_column_fullname",  "kwcolumn_opt",
++  "resolvetype",   "raisetype",     "ifexists",      "fullname",    
++  "oneselect",     "multiselect_op",  "distinct",      "selcollist",  
++  "from",          "where_opt",     "groupby_opt",   "having_opt",  
++  "orderby_opt",   "limit_opt",     "sclp",          "as",          
++  "seltablist",    "stl_prefix",    "joinop",        "on_opt",      
++  "using_opt",     "seltablist_paren",  "joinop2",       "inscollist",  
++  "sortlist",      "sortitem",      "collate",       "exprlist",    
++  "setlist",       "insert_cmd",    "inscollist_opt",  "itemlist",    
++  "likeop",        "escape",        "between_op",    "in_op",       
++  "case_operand",  "case_exprlist",  "case_else",     "expritem",    
++  "uniqueflag",    "idxitem",       "plus_opt",      "number",      
++  "trigger_decl",  "trigger_cmd_list",  "trigger_time",  "trigger_event",
++  "foreach_clause",  "when_clause",   "trigger_cmd",   "database_kw_opt",
++  "key_opt",       "add_column_fullname",  "kwcolumn_opt",
+ };
+ #endif /* NDEBUG */
+ 
+@@ -975,296 +875,280 @@
+  /*  18 */ "cmd ::= END trans_opt",
+  /*  19 */ "cmd ::= ROLLBACK trans_opt",
+  /*  20 */ "cmd ::= create_table create_table_args",
+- /*  21 */ "create_table ::= CREATE temp TABLE nm dbnm",
+- /*  22 */ "temp ::= TEMP",
+- /*  23 */ "temp ::=",
+- /*  24 */ "create_table_args ::= LP columnlist conslist_opt RP",
+- /*  25 */ "create_table_args ::= AS select",
+- /*  26 */ "columnlist ::= columnlist COMMA column",
+- /*  27 */ "columnlist ::= column",
+- /*  28 */ "column ::= columnid type carglist",
+- /*  29 */ "columnid ::= nm",
+- /*  30 */ "id ::= ID",
+- /*  31 */ "ids ::= ID",
+- /*  32 */ "ids ::= STRING",
+- /*  33 */ "nm ::= ID",
+- /*  34 */ "nm ::= STRING",
+- /*  35 */ "nm ::= JOIN_KW",
+- /*  36 */ "type ::=",
+- /*  37 */ "type ::= typetoken",
+- /*  38 */ "typetoken ::= typename",
+- /*  39 */ "typetoken ::= typename LP signed RP",
+- /*  40 */ "typetoken ::= typename LP signed COMMA signed RP",
+- /*  41 */ "typename ::= ids",
+- /*  42 */ "typename ::= typename ids",
+- /*  43 */ "signed ::= plus_num",
+- /*  44 */ "signed ::= minus_num",
+- /*  45 */ "carglist ::= carglist carg",
+- /*  46 */ "carglist ::=",
+- /*  47 */ "carg ::= CONSTRAINT nm ccons",
+- /*  48 */ "carg ::= ccons",
+- /*  49 */ "carg ::= DEFAULT term",
+- /*  50 */ "carg ::= DEFAULT LP expr RP",
+- /*  51 */ "carg ::= DEFAULT PLUS term",
+- /*  52 */ "carg ::= DEFAULT MINUS term",
+- /*  53 */ "carg ::= DEFAULT id",
+- /*  54 */ "ccons ::= NULL onconf",
+- /*  55 */ "ccons ::= NOT NULL onconf",
+- /*  56 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc",
+- /*  57 */ "ccons ::= UNIQUE onconf",
+- /*  58 */ "ccons ::= CHECK LP expr RP onconf",
+- /*  59 */ "ccons ::= REFERENCES nm idxlist_opt refargs",
+- /*  60 */ "ccons ::= defer_subclause",
+- /*  61 */ "ccons ::= COLLATE id",
+- /*  62 */ "autoinc ::=",
+- /*  63 */ "autoinc ::= AUTOINCR",
+- /*  64 */ "refargs ::=",
+- /*  65 */ "refargs ::= refargs refarg",
+- /*  66 */ "refarg ::= MATCH nm",
+- /*  67 */ "refarg ::= ON DELETE refact",
+- /*  68 */ "refarg ::= ON UPDATE refact",
+- /*  69 */ "refarg ::= ON INSERT refact",
+- /*  70 */ "refact ::= SET NULL",
+- /*  71 */ "refact ::= SET DEFAULT",
+- /*  72 */ "refact ::= CASCADE",
+- /*  73 */ "refact ::= RESTRICT",
+- /*  74 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt",
+- /*  75 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt",
+- /*  76 */ "init_deferred_pred_opt ::=",
+- /*  77 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED",
+- /*  78 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE",
+- /*  79 */ "conslist_opt ::=",
+- /*  80 */ "conslist_opt ::= COMMA conslist",
+- /*  81 */ "conslist ::= conslist COMMA tcons",
+- /*  82 */ "conslist ::= conslist tcons",
+- /*  83 */ "conslist ::= tcons",
+- /*  84 */ "tcons ::= CONSTRAINT nm",
+- /*  85 */ "tcons ::= PRIMARY KEY LP idxlist autoinc RP onconf",
+- /*  86 */ "tcons ::= UNIQUE LP idxlist RP onconf",
+- /*  87 */ "tcons ::= CHECK expr onconf",
+- /*  88 */ "tcons ::= FOREIGN KEY LP idxlist RP REFERENCES nm idxlist_opt refargs defer_subclause_opt",
+- /*  89 */ "defer_subclause_opt ::=",
+- /*  90 */ "defer_subclause_opt ::= defer_subclause",
+- /*  91 */ "onconf ::=",
+- /*  92 */ "onconf ::= ON CONFLICT resolvetype",
+- /*  93 */ "orconf ::=",
+- /*  94 */ "orconf ::= OR resolvetype",
+- /*  95 */ "resolvetype ::= raisetype",
+- /*  96 */ "resolvetype ::= IGNORE",
+- /*  97 */ "resolvetype ::= REPLACE",
+- /*  98 */ "cmd ::= DROP TABLE fullname",
+- /*  99 */ "cmd ::= CREATE temp VIEW nm dbnm AS select",
+- /* 100 */ "cmd ::= DROP VIEW fullname",
+- /* 101 */ "cmd ::= select",
+- /* 102 */ "select ::= oneselect",
+- /* 103 */ "select ::= select multiselect_op oneselect",
+- /* 104 */ "multiselect_op ::= UNION",
+- /* 105 */ "multiselect_op ::= UNION ALL",
+- /* 106 */ "multiselect_op ::= INTERSECT",
+- /* 107 */ "multiselect_op ::= EXCEPT",
+- /* 108 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt",
+- /* 109 */ "distinct ::= DISTINCT",
+- /* 110 */ "distinct ::= ALL",
+- /* 111 */ "distinct ::=",
+- /* 112 */ "sclp ::= selcollist COMMA",
+- /* 113 */ "sclp ::=",
+- /* 114 */ "selcollist ::= sclp expr as",
+- /* 115 */ "selcollist ::= sclp STAR",
+- /* 116 */ "selcollist ::= sclp nm DOT STAR",
+- /* 117 */ "as ::= AS nm",
+- /* 118 */ "as ::= ids",
+- /* 119 */ "as ::=",
+- /* 120 */ "from ::=",
+- /* 121 */ "from ::= FROM seltablist",
+- /* 122 */ "stl_prefix ::= seltablist joinop",
+- /* 123 */ "stl_prefix ::=",
+- /* 124 */ "seltablist ::= stl_prefix nm dbnm as on_opt using_opt",
+- /* 125 */ "seltablist ::= stl_prefix LP seltablist_paren RP as on_opt using_opt",
+- /* 126 */ "seltablist_paren ::= select",
+- /* 127 */ "seltablist_paren ::= seltablist",
+- /* 128 */ "dbnm ::=",
+- /* 129 */ "dbnm ::= DOT nm",
+- /* 130 */ "fullname ::= nm dbnm",
+- /* 131 */ "joinop ::= COMMA",
+- /* 132 */ "joinop ::= JOIN",
+- /* 133 */ "joinop ::= JOIN_KW JOIN",
+- /* 134 */ "joinop ::= JOIN_KW nm JOIN",
+- /* 135 */ "joinop ::= JOIN_KW nm nm JOIN",
+- /* 136 */ "on_opt ::= ON expr",
+- /* 137 */ "on_opt ::=",
+- /* 138 */ "using_opt ::= USING LP inscollist RP",
+- /* 139 */ "using_opt ::=",
+- /* 140 */ "orderby_opt ::=",
+- /* 141 */ "orderby_opt ::= ORDER BY sortlist",
+- /* 142 */ "sortlist ::= sortlist COMMA sortitem collate sortorder",
+- /* 143 */ "sortlist ::= sortitem collate sortorder",
+- /* 144 */ "sortitem ::= expr",
+- /* 145 */ "sortorder ::= ASC",
+- /* 146 */ "sortorder ::= DESC",
+- /* 147 */ "sortorder ::=",
+- /* 148 */ "collate ::=",
+- /* 149 */ "collate ::= COLLATE id",
+- /* 150 */ "groupby_opt ::=",
+- /* 151 */ "groupby_opt ::= GROUP BY exprlist",
+- /* 152 */ "having_opt ::=",
+- /* 153 */ "having_opt ::= HAVING expr",
+- /* 154 */ "limit_opt ::=",
+- /* 155 */ "limit_opt ::= LIMIT expr",
+- /* 156 */ "limit_opt ::= LIMIT expr OFFSET expr",
+- /* 157 */ "limit_opt ::= LIMIT expr COMMA expr",
+- /* 158 */ "cmd ::= DELETE FROM fullname where_opt",
+- /* 159 */ "where_opt ::=",
+- /* 160 */ "where_opt ::= WHERE expr",
+- /* 161 */ "cmd ::= UPDATE orconf fullname SET setlist where_opt",
+- /* 162 */ "setlist ::= setlist COMMA nm EQ expr",
+- /* 163 */ "setlist ::= nm EQ expr",
+- /* 164 */ "cmd ::= insert_cmd INTO fullname inscollist_opt VALUES LP itemlist RP",
+- /* 165 */ "cmd ::= insert_cmd INTO fullname inscollist_opt select",
+- /* 166 */ "insert_cmd ::= INSERT orconf",
+- /* 167 */ "insert_cmd ::= REPLACE",
+- /* 168 */ "itemlist ::= itemlist COMMA expr",
+- /* 169 */ "itemlist ::= expr",
+- /* 170 */ "inscollist_opt ::=",
+- /* 171 */ "inscollist_opt ::= LP inscollist RP",
+- /* 172 */ "inscollist ::= inscollist COMMA nm",
+- /* 173 */ "inscollist ::= nm",
+- /* 174 */ "expr ::= term",
+- /* 175 */ "expr ::= LP expr RP",
+- /* 176 */ "term ::= NULL",
+- /* 177 */ "expr ::= ID",
+- /* 178 */ "expr ::= JOIN_KW",
+- /* 179 */ "expr ::= nm DOT nm",
+- /* 180 */ "expr ::= nm DOT nm DOT nm",
+- /* 181 */ "term ::= INTEGER",
+- /* 182 */ "term ::= FLOAT",
++ /*  21 */ "create_table ::= CREATE temp TABLE ifnotexists nm dbnm",
++ /*  22 */ "ifnotexists ::=",
++ /*  23 */ "ifnotexists ::= IF NOT EXISTS",
++ /*  24 */ "temp ::= TEMP",
++ /*  25 */ "temp ::=",
++ /*  26 */ "create_table_args ::= LP columnlist conslist_opt RP",
++ /*  27 */ "create_table_args ::= AS select",
++ /*  28 */ "columnlist ::= columnlist COMMA column",
++ /*  29 */ "columnlist ::= column",
++ /*  30 */ "column ::= columnid type carglist",
++ /*  31 */ "columnid ::= nm",
++ /*  32 */ "id ::= ID",
++ /*  33 */ "ids ::= ID|STRING",
++ /*  34 */ "nm ::= ID",
++ /*  35 */ "nm ::= STRING",
++ /*  36 */ "nm ::= JOIN_KW",
++ /*  37 */ "type ::=",
++ /*  38 */ "type ::= typetoken",
++ /*  39 */ "typetoken ::= typename",
++ /*  40 */ "typetoken ::= typename LP signed RP",
++ /*  41 */ "typetoken ::= typename LP signed COMMA signed RP",
++ /*  42 */ "typename ::= ids",
++ /*  43 */ "typename ::= typename ids",
++ /*  44 */ "signed ::= plus_num",
++ /*  45 */ "signed ::= minus_num",
++ /*  46 */ "carglist ::= carglist carg",
++ /*  47 */ "carglist ::=",
++ /*  48 */ "carg ::= CONSTRAINT nm ccons",
++ /*  49 */ "carg ::= ccons",
++ /*  50 */ "carg ::= DEFAULT term",
++ /*  51 */ "carg ::= DEFAULT LP expr RP",
++ /*  52 */ "carg ::= DEFAULT PLUS term",
++ /*  53 */ "carg ::= DEFAULT MINUS term",
++ /*  54 */ "carg ::= DEFAULT id",
++ /*  55 */ "ccons ::= NULL onconf",
++ /*  56 */ "ccons ::= NOT NULL onconf",
++ /*  57 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc",
++ /*  58 */ "ccons ::= UNIQUE onconf",
++ /*  59 */ "ccons ::= CHECK LP expr RP",
++ /*  60 */ "ccons ::= REFERENCES nm idxlist_opt refargs",
++ /*  61 */ "ccons ::= defer_subclause",
++ /*  62 */ "ccons ::= COLLATE id",
++ /*  63 */ "autoinc ::=",
++ /*  64 */ "autoinc ::= AUTOINCR",
++ /*  65 */ "refargs ::=",
++ /*  66 */ "refargs ::= refargs refarg",
++ /*  67 */ "refarg ::= MATCH nm",
++ /*  68 */ "refarg ::= ON DELETE refact",
++ /*  69 */ "refarg ::= ON UPDATE refact",
++ /*  70 */ "refarg ::= ON INSERT refact",
++ /*  71 */ "refact ::= SET NULL",
++ /*  72 */ "refact ::= SET DEFAULT",
++ /*  73 */ "refact ::= CASCADE",
++ /*  74 */ "refact ::= RESTRICT",
++ /*  75 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt",
++ /*  76 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt",
++ /*  77 */ "init_deferred_pred_opt ::=",
++ /*  78 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED",
++ /*  79 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE",
++ /*  80 */ "conslist_opt ::=",
++ /*  81 */ "conslist_opt ::= COMMA conslist",
++ /*  82 */ "conslist ::= conslist COMMA tcons",
++ /*  83 */ "conslist ::= conslist tcons",
++ /*  84 */ "conslist ::= tcons",
++ /*  85 */ "tcons ::= CONSTRAINT nm",
++ /*  86 */ "tcons ::= PRIMARY KEY LP idxlist autoinc RP onconf",
++ /*  87 */ "tcons ::= UNIQUE LP idxlist RP onconf",
++ /*  88 */ "tcons ::= CHECK LP expr RP onconf",
++ /*  89 */ "tcons ::= FOREIGN KEY LP idxlist RP REFERENCES nm idxlist_opt refargs defer_subclause_opt",
++ /*  90 */ "defer_subclause_opt ::=",
++ /*  91 */ "defer_subclause_opt ::= defer_subclause",
++ /*  92 */ "onconf ::=",
++ /*  93 */ "onconf ::= ON CONFLICT resolvetype",
++ /*  94 */ "orconf ::=",
++ /*  95 */ "orconf ::= OR resolvetype",
++ /*  96 */ "resolvetype ::= raisetype",
++ /*  97 */ "resolvetype ::= IGNORE",
++ /*  98 */ "resolvetype ::= REPLACE",
++ /*  99 */ "cmd ::= DROP TABLE ifexists fullname",
++ /* 100 */ "ifexists ::= IF EXISTS",
++ /* 101 */ "ifexists ::=",
++ /* 102 */ "cmd ::= CREATE temp VIEW nm dbnm AS select",
++ /* 103 */ "cmd ::= DROP VIEW ifexists fullname",
++ /* 104 */ "cmd ::= select",
++ /* 105 */ "select ::= oneselect",
++ /* 106 */ "select ::= select multiselect_op oneselect",
++ /* 107 */ "multiselect_op ::= UNION",
++ /* 108 */ "multiselect_op ::= UNION ALL",
++ /* 109 */ "multiselect_op ::= EXCEPT|INTERSECT",
++ /* 110 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt",
++ /* 111 */ "distinct ::= DISTINCT",
++ /* 112 */ "distinct ::= ALL",
++ /* 113 */ "distinct ::=",
++ /* 114 */ "sclp ::= selcollist COMMA",
++ /* 115 */ "sclp ::=",
++ /* 116 */ "selcollist ::= sclp expr as",
++ /* 117 */ "selcollist ::= sclp STAR",
++ /* 118 */ "selcollist ::= sclp nm DOT STAR",
++ /* 119 */ "as ::= AS nm",
++ /* 120 */ "as ::= ids",
++ /* 121 */ "as ::=",
++ /* 122 */ "from ::=",
++ /* 123 */ "from ::= FROM seltablist",
++ /* 124 */ "stl_prefix ::= seltablist joinop",
++ /* 125 */ "stl_prefix ::=",
++ /* 126 */ "seltablist ::= stl_prefix nm dbnm as on_opt using_opt",
++ /* 127 */ "seltablist ::= stl_prefix LP seltablist_paren RP as on_opt using_opt",
++ /* 128 */ "seltablist_paren ::= select",
++ /* 129 */ "seltablist_paren ::= seltablist",
++ /* 130 */ "dbnm ::=",
++ /* 131 */ "dbnm ::= DOT nm",
++ /* 132 */ "fullname ::= nm dbnm",
++ /* 133 */ "joinop ::= COMMA|JOIN",
++ /* 134 */ "joinop ::= JOIN_KW JOIN",
++ /* 135 */ "joinop ::= JOIN_KW nm JOIN",
++ /* 136 */ "joinop ::= JOIN_KW nm nm JOIN",
++ /* 137 */ "on_opt ::= ON expr",
++ /* 138 */ "on_opt ::=",
++ /* 139 */ "using_opt ::= USING LP inscollist RP",
++ /* 140 */ "using_opt ::=",
++ /* 141 */ "orderby_opt ::=",
++ /* 142 */ "orderby_opt ::= ORDER BY sortlist",
++ /* 143 */ "sortlist ::= sortlist COMMA sortitem collate sortorder",
++ /* 144 */ "sortlist ::= sortitem collate sortorder",
++ /* 145 */ "sortitem ::= expr",
++ /* 146 */ "sortorder ::= ASC",
++ /* 147 */ "sortorder ::= DESC",
++ /* 148 */ "sortorder ::=",
++ /* 149 */ "collate ::=",
++ /* 150 */ "collate ::= COLLATE id",
++ /* 151 */ "groupby_opt ::=",
++ /* 152 */ "groupby_opt ::= GROUP BY exprlist",
++ /* 153 */ "having_opt ::=",
++ /* 154 */ "having_opt ::= HAVING expr",
++ /* 155 */ "limit_opt ::=",
++ /* 156 */ "limit_opt ::= LIMIT expr",
++ /* 157 */ "limit_opt ::= LIMIT expr OFFSET expr",
++ /* 158 */ "limit_opt ::= LIMIT expr COMMA expr",
++ /* 159 */ "cmd ::= DELETE FROM fullname where_opt",
++ /* 160 */ "where_opt ::=",
++ /* 161 */ "where_opt ::= WHERE expr",
++ /* 162 */ "cmd ::= UPDATE orconf fullname SET setlist where_opt",
++ /* 163 */ "setlist ::= setlist COMMA nm EQ expr",
++ /* 164 */ "setlist ::= nm EQ expr",
++ /* 165 */ "cmd ::= insert_cmd INTO fullname inscollist_opt VALUES LP itemlist RP",
++ /* 166 */ "cmd ::= insert_cmd INTO fullname inscollist_opt select",
++ /* 167 */ "insert_cmd ::= INSERT orconf",
++ /* 168 */ "insert_cmd ::= REPLACE",
++ /* 169 */ "itemlist ::= itemlist COMMA expr",
++ /* 170 */ "itemlist ::= expr",
++ /* 171 */ "inscollist_opt ::=",
++ /* 172 */ "inscollist_opt ::= LP inscollist RP",
++ /* 173 */ "inscollist ::= inscollist COMMA nm",
++ /* 174 */ "inscollist ::= nm",
++ /* 175 */ "expr ::= term",
++ /* 176 */ "expr ::= LP expr RP",
++ /* 177 */ "term ::= NULL",
++ /* 178 */ "expr ::= ID",
++ /* 179 */ "expr ::= JOIN_KW",
++ /* 180 */ "expr ::= nm DOT nm",
++ /* 181 */ "expr ::= nm DOT nm DOT nm",
++ /* 182 */ "term ::= INTEGER|FLOAT|BLOB",
+  /* 183 */ "term ::= STRING",
+- /* 184 */ "term ::= BLOB",
+- /* 185 */ "expr ::= REGISTER",
+- /* 186 */ "expr ::= VARIABLE",
+- /* 187 */ "expr ::= CAST LP expr AS typetoken RP",
+- /* 188 */ "expr ::= ID LP distinct exprlist RP",
+- /* 189 */ "expr ::= ID LP STAR RP",
+- /* 190 */ "term ::= CTIME_KW",
+- /* 191 */ "expr ::= expr AND expr",
+- /* 192 */ "expr ::= expr OR expr",
+- /* 193 */ "expr ::= expr LT expr",
+- /* 194 */ "expr ::= expr GT expr",
+- /* 195 */ "expr ::= expr LE expr",
+- /* 196 */ "expr ::= expr GE expr",
+- /* 197 */ "expr ::= expr NE expr",
+- /* 198 */ "expr ::= expr EQ expr",
+- /* 199 */ "expr ::= expr BITAND expr",
+- /* 200 */ "expr ::= expr BITOR expr",
+- /* 201 */ "expr ::= expr LSHIFT expr",
+- /* 202 */ "expr ::= expr RSHIFT expr",
+- /* 203 */ "expr ::= expr PLUS expr",
+- /* 204 */ "expr ::= expr MINUS expr",
+- /* 205 */ "expr ::= expr STAR expr",
+- /* 206 */ "expr ::= expr SLASH expr",
+- /* 207 */ "expr ::= expr REM expr",
+- /* 208 */ "expr ::= expr CONCAT expr",
+- /* 209 */ "likeop ::= LIKE_KW",
+- /* 210 */ "likeop ::= NOT LIKE_KW",
+- /* 211 */ "escape ::= ESCAPE expr",
+- /* 212 */ "escape ::=",
+- /* 213 */ "expr ::= expr likeop expr escape",
+- /* 214 */ "expr ::= expr ISNULL",
+- /* 215 */ "expr ::= expr IS NULL",
+- /* 216 */ "expr ::= expr NOTNULL",
+- /* 217 */ "expr ::= expr NOT NULL",
+- /* 218 */ "expr ::= expr IS NOT NULL",
+- /* 219 */ "expr ::= NOT expr",
+- /* 220 */ "expr ::= BITNOT expr",
+- /* 221 */ "expr ::= MINUS expr",
+- /* 222 */ "expr ::= PLUS expr",
+- /* 223 */ "between_op ::= BETWEEN",
+- /* 224 */ "between_op ::= NOT BETWEEN",
+- /* 225 */ "expr ::= expr between_op expr AND expr",
+- /* 226 */ "in_op ::= IN",
+- /* 227 */ "in_op ::= NOT IN",
+- /* 228 */ "expr ::= expr in_op LP exprlist RP",
+- /* 229 */ "expr ::= LP select RP",
+- /* 230 */ "expr ::= expr in_op LP select RP",
+- /* 231 */ "expr ::= expr in_op nm dbnm",
+- /* 232 */ "expr ::= EXISTS LP select RP",
+- /* 233 */ "expr ::= CASE case_operand case_exprlist case_else END",
+- /* 234 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
+- /* 235 */ "case_exprlist ::= WHEN expr THEN expr",
+- /* 236 */ "case_else ::= ELSE expr",
+- /* 237 */ "case_else ::=",
+- /* 238 */ "case_operand ::= expr",
+- /* 239 */ "case_operand ::=",
+- /* 240 */ "exprlist ::= exprlist COMMA expritem",
+- /* 241 */ "exprlist ::= expritem",
+- /* 242 */ "expritem ::= expr",
+- /* 243 */ "expritem ::=",
+- /* 244 */ "cmd ::= CREATE uniqueflag INDEX nm dbnm ON nm LP idxlist RP onconf",
+- /* 245 */ "uniqueflag ::= UNIQUE",
+- /* 246 */ "uniqueflag ::=",
+- /* 247 */ "idxlist_opt ::=",
+- /* 248 */ "idxlist_opt ::= LP idxlist RP",
+- /* 249 */ "idxlist ::= idxlist COMMA idxitem collate sortorder",
+- /* 250 */ "idxlist ::= idxitem collate sortorder",
+- /* 251 */ "idxitem ::= nm",
+- /* 252 */ "cmd ::= DROP INDEX fullname",
+- /* 253 */ "cmd ::= VACUUM",
+- /* 254 */ "cmd ::= VACUUM nm",
+- /* 255 */ "cmd ::= PRAGMA nm dbnm EQ nm",
+- /* 256 */ "cmd ::= PRAGMA nm dbnm EQ ON",
+- /* 257 */ "cmd ::= PRAGMA nm dbnm EQ plus_num",
+- /* 258 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
+- /* 259 */ "cmd ::= PRAGMA nm dbnm LP nm RP",
+- /* 260 */ "cmd ::= PRAGMA nm dbnm",
+- /* 261 */ "plus_num ::= plus_opt number",
+- /* 262 */ "minus_num ::= MINUS number",
+- /* 263 */ "number ::= INTEGER",
+- /* 264 */ "number ::= FLOAT",
+- /* 265 */ "plus_opt ::= PLUS",
+- /* 266 */ "plus_opt ::=",
+- /* 267 */ "cmd ::= CREATE trigger_decl BEGIN trigger_cmd_list END",
+- /* 268 */ "trigger_decl ::= temp TRIGGER nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
+- /* 269 */ "trigger_time ::= BEFORE",
+- /* 270 */ "trigger_time ::= AFTER",
+- /* 271 */ "trigger_time ::= INSTEAD OF",
+- /* 272 */ "trigger_time ::=",
+- /* 273 */ "trigger_event ::= DELETE",
+- /* 274 */ "trigger_event ::= INSERT",
+- /* 275 */ "trigger_event ::= UPDATE",
+- /* 276 */ "trigger_event ::= UPDATE OF inscollist",
+- /* 277 */ "foreach_clause ::=",
+- /* 278 */ "foreach_clause ::= FOR EACH ROW",
+- /* 279 */ "foreach_clause ::= FOR EACH STATEMENT",
+- /* 280 */ "when_clause ::=",
+- /* 281 */ "when_clause ::= WHEN expr",
+- /* 282 */ "trigger_cmd_list ::= trigger_cmd SEMI trigger_cmd_list",
+- /* 283 */ "trigger_cmd_list ::=",
+- /* 284 */ "trigger_cmd ::= UPDATE orconf nm SET setlist where_opt",
+- /* 285 */ "trigger_cmd ::= insert_cmd INTO nm inscollist_opt VALUES LP itemlist RP",
+- /* 286 */ "trigger_cmd ::= insert_cmd INTO nm inscollist_opt select",
+- /* 287 */ "trigger_cmd ::= DELETE FROM nm where_opt",
+- /* 288 */ "trigger_cmd ::= select",
+- /* 289 */ "expr ::= RAISE LP IGNORE RP",
+- /* 290 */ "expr ::= RAISE LP raisetype COMMA nm RP",
+- /* 291 */ "raisetype ::= ROLLBACK",
+- /* 292 */ "raisetype ::= ABORT",
+- /* 293 */ "raisetype ::= FAIL",
+- /* 294 */ "cmd ::= DROP TRIGGER fullname",
+- /* 295 */ "cmd ::= ATTACH database_kw_opt ids AS nm key_opt",
+- /* 296 */ "key_opt ::=",
+- /* 297 */ "key_opt ::= KEY ids",
+- /* 298 */ "key_opt ::= KEY BLOB",
+- /* 299 */ "database_kw_opt ::= DATABASE",
+- /* 300 */ "database_kw_opt ::=",
+- /* 301 */ "cmd ::= DETACH database_kw_opt nm",
+- /* 302 */ "cmd ::= REINDEX",
+- /* 303 */ "cmd ::= REINDEX nm dbnm",
+- /* 304 */ "cmd ::= ANALYZE",
+- /* 305 */ "cmd ::= ANALYZE nm dbnm",
+- /* 306 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
+- /* 307 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column",
+- /* 308 */ "add_column_fullname ::= fullname",
+- /* 309 */ "kwcolumn_opt ::=",
+- /* 310 */ "kwcolumn_opt ::= COLUMNKW",
++ /* 184 */ "expr ::= REGISTER",
++ /* 185 */ "expr ::= VARIABLE",
++ /* 186 */ "expr ::= CAST LP expr AS typetoken RP",
++ /* 187 */ "expr ::= ID LP distinct exprlist RP",
++ /* 188 */ "expr ::= ID LP STAR RP",
++ /* 189 */ "term ::= CTIME_KW",
++ /* 190 */ "expr ::= expr AND expr",
++ /* 191 */ "expr ::= expr OR expr",
++ /* 192 */ "expr ::= expr LT|GT|GE|LE expr",
++ /* 193 */ "expr ::= expr EQ|NE expr",
++ /* 194 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
++ /* 195 */ "expr ::= expr PLUS|MINUS expr",
++ /* 196 */ "expr ::= expr STAR|SLASH|REM expr",
++ /* 197 */ "expr ::= expr CONCAT expr",
++ /* 198 */ "likeop ::= LIKE_KW",
++ /* 199 */ "likeop ::= NOT LIKE_KW",
++ /* 200 */ "escape ::= ESCAPE expr",
++ /* 201 */ "escape ::=",
++ /* 202 */ "expr ::= expr likeop expr escape",
++ /* 203 */ "expr ::= expr ISNULL|NOTNULL",
++ /* 204 */ "expr ::= expr IS NULL",
++ /* 205 */ "expr ::= expr NOT NULL",
++ /* 206 */ "expr ::= expr IS NOT NULL",
++ /* 207 */ "expr ::= NOT|BITNOT expr",
++ /* 208 */ "expr ::= MINUS expr",
++ /* 209 */ "expr ::= PLUS expr",
++ /* 210 */ "between_op ::= BETWEEN",
++ /* 211 */ "between_op ::= NOT BETWEEN",
++ /* 212 */ "expr ::= expr between_op expr AND expr",
++ /* 213 */ "in_op ::= IN",
++ /* 214 */ "in_op ::= NOT IN",
++ /* 215 */ "expr ::= expr in_op LP exprlist RP",
++ /* 216 */ "expr ::= LP select RP",
++ /* 217 */ "expr ::= expr in_op LP select RP",
++ /* 218 */ "expr ::= expr in_op nm dbnm",
++ /* 219 */ "expr ::= EXISTS LP select RP",
++ /* 220 */ "expr ::= CASE case_operand case_exprlist case_else END",
++ /* 221 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
++ /* 222 */ "case_exprlist ::= WHEN expr THEN expr",
++ /* 223 */ "case_else ::= ELSE expr",
++ /* 224 */ "case_else ::=",
++ /* 225 */ "case_operand ::= expr",
++ /* 226 */ "case_operand ::=",
++ /* 227 */ "exprlist ::= exprlist COMMA expritem",
++ /* 228 */ "exprlist ::= expritem",
++ /* 229 */ "expritem ::= expr",
++ /* 230 */ "expritem ::=",
++ /* 231 */ "cmd ::= CREATE uniqueflag INDEX ifnotexists nm dbnm ON nm LP idxlist RP",
++ /* 232 */ "uniqueflag ::= UNIQUE",
++ /* 233 */ "uniqueflag ::=",
++ /* 234 */ "idxlist_opt ::=",
++ /* 235 */ "idxlist_opt ::= LP idxlist RP",
++ /* 236 */ "idxlist ::= idxlist COMMA idxitem collate sortorder",
++ /* 237 */ "idxlist ::= idxitem collate sortorder",
++ /* 238 */ "idxitem ::= nm",
++ /* 239 */ "cmd ::= DROP INDEX ifexists fullname",
++ /* 240 */ "cmd ::= VACUUM",
++ /* 241 */ "cmd ::= VACUUM nm",
++ /* 242 */ "cmd ::= PRAGMA nm dbnm EQ nm",
++ /* 243 */ "cmd ::= PRAGMA nm dbnm EQ ON",
++ /* 244 */ "cmd ::= PRAGMA nm dbnm EQ plus_num",
++ /* 245 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
++ /* 246 */ "cmd ::= PRAGMA nm dbnm LP nm RP",
++ /* 247 */ "cmd ::= PRAGMA nm dbnm",
++ /* 248 */ "plus_num ::= plus_opt number",
++ /* 249 */ "minus_num ::= MINUS number",
++ /* 250 */ "number ::= INTEGER|FLOAT",
++ /* 251 */ "plus_opt ::= PLUS",
++ /* 252 */ "plus_opt ::=",
++ /* 253 */ "cmd ::= CREATE trigger_decl BEGIN trigger_cmd_list END",
++ /* 254 */ "trigger_decl ::= temp TRIGGER nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
++ /* 255 */ "trigger_time ::= BEFORE",
++ /* 256 */ "trigger_time ::= AFTER",
++ /* 257 */ "trigger_time ::= INSTEAD OF",
++ /* 258 */ "trigger_time ::=",
++ /* 259 */ "trigger_event ::= DELETE|INSERT",
++ /* 260 */ "trigger_event ::= UPDATE",
++ /* 261 */ "trigger_event ::= UPDATE OF inscollist",
++ /* 262 */ "foreach_clause ::=",
++ /* 263 */ "foreach_clause ::= FOR EACH ROW",
++ /* 264 */ "foreach_clause ::= FOR EACH STATEMENT",
++ /* 265 */ "when_clause ::=",
++ /* 266 */ "when_clause ::= WHEN expr",
++ /* 267 */ "trigger_cmd_list ::= trigger_cmd SEMI trigger_cmd_list",
++ /* 268 */ "trigger_cmd_list ::=",
++ /* 269 */ "trigger_cmd ::= UPDATE orconf nm SET setlist where_opt",
++ /* 270 */ "trigger_cmd ::= insert_cmd INTO nm inscollist_opt VALUES LP itemlist RP",
++ /* 271 */ "trigger_cmd ::= insert_cmd INTO nm inscollist_opt select",
++ /* 272 */ "trigger_cmd ::= DELETE FROM nm where_opt",
++ /* 273 */ "trigger_cmd ::= select",
++ /* 274 */ "expr ::= RAISE LP IGNORE RP",
++ /* 275 */ "expr ::= RAISE LP raisetype COMMA nm RP",
++ /* 276 */ "raisetype ::= ROLLBACK",
++ /* 277 */ "raisetype ::= ABORT",
++ /* 278 */ "raisetype ::= FAIL",
++ /* 279 */ "cmd ::= DROP TRIGGER fullname",
++ /* 280 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
++ /* 281 */ "key_opt ::=",
++ /* 282 */ "key_opt ::= KEY expr",
++ /* 283 */ "database_kw_opt ::= DATABASE",
++ /* 284 */ "database_kw_opt ::=",
++ /* 285 */ "cmd ::= DETACH database_kw_opt expr",
++ /* 286 */ "cmd ::= REINDEX",
++ /* 287 */ "cmd ::= REINDEX nm dbnm",
++ /* 288 */ "cmd ::= ANALYZE",
++ /* 289 */ "cmd ::= ANALYZE nm dbnm",
++ /* 290 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
++ /* 291 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column",
++ /* 292 */ "add_column_fullname ::= fullname",
++ /* 293 */ "kwcolumn_opt ::=",
++ /* 294 */ "kwcolumn_opt ::= COLUMNKW",
+ };
+ #endif /* NDEBUG */
+ 
+@@ -1322,73 +1206,82 @@
+     ** which appear on the RHS of the rule, but which are not used
+     ** inside the C code.
+     */
+-    case 162:
+-    case 195:
+-    case 212:
+-#line 370 "parse.y"
+-{sqlite3SelectDelete((yypminor->yy375));}
+-#line 1332 "parse.c"
++    case 154:
++    case 188:
++    case 205:
++#line 368 "parse.y"
++{sqlite3SelectDelete((yypminor->yy239));}
++#line 1216 "parse.c"
+       break;
+-    case 176:
+-    case 177:
+-    case 200:
+-    case 202:
+-    case 210:
+-    case 216:
+-    case 230:
+-#line 629 "parse.y"
+-{sqlite3ExprDelete((yypminor->yy62));}
+-#line 1343 "parse.c"
+-      break;
+-    case 181:
+-    case 189:
+-    case 198:
+-    case 201:
++    case 168:
++    case 169:
++    case 193:
++    case 195:
+     case 203:
+-    case 205:
+-    case 215:
+-    case 218:
+-    case 219:
++    case 209:
++    case 217:
++    case 220:
+     case 222:
+-    case 228:
+-#line 876 "parse.y"
+-{sqlite3ExprListDelete((yypminor->yy418));}
+-#line 1358 "parse.c"
++    case 223:
++    case 233:
++#line 625 "parse.y"
++{sqlite3ExprDelete((yypminor->yy178));}
++#line 1231 "parse.c"
+       break;
++    case 173:
++    case 181:
++    case 191:
+     case 194:
+-    case 199:
+-    case 207:
++    case 196:
++    case 198:
+     case 208:
+-#line 499 "parse.y"
+-{sqlite3SrcListDelete((yypminor->yy151));}
+-#line 1366 "parse.c"
++    case 211:
++    case 212:
++    case 215:
++    case 221:
++#line 855 "parse.y"
++{sqlite3ExprListDelete((yypminor->yy462));}
++#line 1246 "parse.c"
+       break;
+-    case 204:
+-#line 561 "parse.y"
++    case 187:
++    case 192:
++    case 200:
++    case 201:
++#line 496 "parse.y"
++{sqlite3SrcListDelete((yypminor->yy285));}
++#line 1254 "parse.c"
++      break;
++    case 197:
++#line 557 "parse.y"
+ {
+-  sqlite3ExprDelete((yypminor->yy220).pLimit);
+-  sqlite3ExprDelete((yypminor->yy220).pOffset);
++  sqlite3ExprDelete((yypminor->yy270).pLimit);
++  sqlite3ExprDelete((yypminor->yy270).pOffset);
+ }
+-#line 1374 "parse.c"
++#line 1262 "parse.c"
+       break;
+-    case 211:
++    case 204:
++    case 207:
+     case 214:
+-    case 221:
+-#line 517 "parse.y"
+-{sqlite3IdListDelete((yypminor->yy240));}
+-#line 1381 "parse.c"
++#line 513 "parse.y"
++{sqlite3IdListDelete((yypminor->yy160));}
++#line 1269 "parse.c"
+       break;
+-    case 236:
+-    case 241:
+-#line 969 "parse.y"
+-{sqlite3DeleteTriggerStep((yypminor->yy360));}
+-#line 1387 "parse.c"
++    case 229:
++    case 234:
++#line 949 "parse.y"
++{sqlite3DeleteTriggerStep((yypminor->yy247));}
++#line 1275 "parse.c"
+       break;
+-    case 238:
+-#line 953 "parse.y"
+-{sqlite3IdListDelete((yypminor->yy30).b);}
+-#line 1392 "parse.c"
++    case 231:
++#line 933 "parse.y"
++{sqlite3IdListDelete((yypminor->yy132).b);}
++#line 1280 "parse.c"
+       break;
++    case 236:
++#line 1008 "parse.y"
++{sqlite3ExprDelete((yypminor->yy292));}
++#line 1285 "parse.c"
++      break;
+     default:  break;   /* If no destructor action specified: do nothing */
+   }
+ }
+@@ -1456,9 +1349,7 @@
+   int i;
+   int stateno = pParser->yystack[pParser->yyidx].stateno;
+  
+-  /* if( pParser->yyidx<0 ) return YY_NO_ACTION;  */
+-  i = yy_shift_ofst[stateno];
+-  if( i==YY_SHIFT_USE_DFLT ){
++  if( stateno>YY_SHIFT_MAX || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){
+     return yy_default[stateno];
+   }
+   if( iLookAhead==YYNOCODE ){
+@@ -1500,8 +1391,8 @@
+   int i;
+   /* int stateno = pParser->yystack[pParser->yyidx].stateno; */
+  
+-  i = yy_reduce_ofst[stateno];
+-  if( i==YY_REDUCE_USE_DFLT ){
++  if( stateno>YY_REDUCE_MAX ||
++      (i = yy_reduce_ofst[stateno])==YY_REDUCE_USE_DFLT ){
+     return yy_default[stateno];
+   }
+   if( iLookAhead==YYNOCODE ){
+@@ -1563,317 +1454,301 @@
+   YYCODETYPE lhs;         /* Symbol on the left-hand side of the rule */
+   unsigned char nrhs;     /* Number of right-hand side symbols in the rule */
+ } yyRuleInfo[] = {
+-  { 147, 1 },
+-  { 148, 2 },
+-  { 148, 1 },
+-  { 150, 1 },
++  { 138, 1 },
++  { 139, 2 },
++  { 139, 1 },
++  { 141, 1 },
++  { 140, 1 },
++  { 140, 3 },
++  { 143, 0 },
++  { 143, 1 },
++  { 143, 3 },
++  { 142, 3 },
++  { 145, 0 },
++  { 145, 1 },
++  { 145, 2 },
++  { 144, 0 },
++  { 144, 1 },
++  { 144, 1 },
++  { 144, 1 },
++  { 142, 2 },
++  { 142, 2 },
++  { 142, 2 },
++  { 142, 2 },
++  { 147, 6 },
++  { 150, 0 },
++  { 150, 3 },
+   { 149, 1 },
+-  { 149, 3 },
+-  { 152, 0 },
+-  { 152, 1 },
++  { 149, 0 },
++  { 148, 4 },
++  { 148, 2 },
+   { 152, 3 },
+-  { 151, 3 },
+-  { 154, 0 },
+-  { 154, 1 },
+-  { 154, 2 },
+-  { 153, 0 },
+-  { 153, 1 },
+-  { 153, 1 },
+-  { 153, 1 },
+-  { 151, 2 },
+-  { 151, 2 },
+-  { 151, 2 },
+-  { 151, 2 },
+-  { 156, 5 },
+-  { 158, 1 },
+-  { 158, 0 },
+-  { 157, 4 },
+-  { 157, 2 },
+-  { 160, 3 },
++  { 152, 1 },
++  { 155, 3 },
++  { 156, 1 },
++  { 159, 1 },
+   { 160, 1 },
+-  { 163, 3 },
+-  { 164, 1 },
+-  { 167, 1 },
+-  { 168, 1 },
+-  { 168, 1 },
+-  { 155, 1 },
+-  { 155, 1 },
+-  { 155, 1 },
+-  { 165, 0 },
+-  { 165, 1 },
+-  { 169, 1 },
+-  { 169, 4 },
+-  { 169, 6 },
+-  { 170, 1 },
+-  { 170, 2 },
+-  { 171, 1 },
+-  { 171, 1 },
++  { 146, 1 },
++  { 146, 1 },
++  { 146, 1 },
++  { 157, 0 },
++  { 157, 1 },
++  { 161, 1 },
++  { 161, 4 },
++  { 161, 6 },
++  { 162, 1 },
++  { 162, 2 },
++  { 163, 1 },
++  { 163, 1 },
++  { 158, 2 },
++  { 158, 0 },
++  { 166, 3 },
++  { 166, 1 },
+   { 166, 2 },
+-  { 166, 0 },
+-  { 174, 3 },
+-  { 174, 1 },
++  { 166, 4 },
++  { 166, 3 },
++  { 166, 3 },
++  { 166, 2 },
++  { 167, 2 },
++  { 167, 3 },
++  { 167, 5 },
++  { 167, 2 },
++  { 167, 4 },
++  { 167, 4 },
++  { 167, 1 },
++  { 167, 2 },
++  { 172, 0 },
++  { 172, 1 },
++  { 174, 0 },
+   { 174, 2 },
+-  { 174, 4 },
+-  { 174, 3 },
+-  { 174, 3 },
+-  { 174, 2 },
+-  { 175, 2 },
++  { 176, 2 },
++  { 176, 3 },
++  { 176, 3 },
++  { 176, 3 },
++  { 177, 2 },
++  { 177, 2 },
++  { 177, 1 },
++  { 177, 1 },
+   { 175, 3 },
+-  { 175, 5 },
+   { 175, 2 },
+-  { 175, 5 },
+-  { 175, 4 },
+-  { 175, 1 },
+-  { 175, 2 },
+-  { 180, 0 },
+-  { 180, 1 },
++  { 178, 0 },
++  { 178, 2 },
++  { 178, 2 },
++  { 153, 0 },
++  { 153, 2 },
++  { 179, 3 },
++  { 179, 2 },
++  { 179, 1 },
++  { 180, 2 },
++  { 180, 7 },
++  { 180, 5 },
++  { 180, 5 },
++  { 180, 10 },
+   { 182, 0 },
+-  { 182, 2 },
+-  { 184, 2 },
+-  { 184, 3 },
+-  { 184, 3 },
+-  { 184, 3 },
+-  { 185, 2 },
+-  { 185, 2 },
+-  { 185, 1 },
+-  { 185, 1 },
+-  { 183, 3 },
++  { 182, 1 },
++  { 170, 0 },
++  { 170, 3 },
++  { 183, 0 },
+   { 183, 2 },
+-  { 186, 0 },
++  { 184, 1 },
++  { 184, 1 },
++  { 184, 1 },
++  { 142, 4 },
+   { 186, 2 },
+-  { 186, 2 },
+-  { 161, 0 },
+-  { 161, 2 },
+-  { 187, 3 },
+-  { 187, 2 },
+-  { 187, 1 },
+-  { 188, 2 },
+-  { 188, 7 },
+-  { 188, 5 },
+-  { 188, 3 },
+-  { 188, 10 },
+-  { 190, 0 },
++  { 186, 0 },
++  { 142, 7 },
++  { 142, 4 },
++  { 142, 1 },
++  { 154, 1 },
++  { 154, 3 },
++  { 189, 1 },
++  { 189, 2 },
++  { 189, 1 },
++  { 188, 9 },
+   { 190, 1 },
+-  { 178, 0 },
+-  { 178, 3 },
+-  { 191, 0 },
+-  { 191, 2 },
+-  { 192, 1 },
+-  { 192, 1 },
+-  { 192, 1 },
+-  { 151, 3 },
+-  { 151, 7 },
+-  { 151, 3 },
+-  { 151, 1 },
+-  { 162, 1 },
+-  { 162, 3 },
+-  { 196, 1 },
+-  { 196, 2 },
+-  { 196, 1 },
+-  { 196, 1 },
+-  { 195, 9 },
+-  { 197, 1 },
+-  { 197, 1 },
+-  { 197, 0 },
+-  { 205, 2 },
+-  { 205, 0 },
+-  { 198, 3 },
++  { 190, 1 },
++  { 190, 0 },
+   { 198, 2 },
+-  { 198, 4 },
+-  { 206, 2 },
+-  { 206, 1 },
+-  { 206, 0 },
+-  { 199, 0 },
++  { 198, 0 },
++  { 191, 3 },
++  { 191, 2 },
++  { 191, 4 },
+   { 199, 2 },
+-  { 208, 2 },
+-  { 208, 0 },
+-  { 207, 6 },
+-  { 207, 7 },
+-  { 212, 1 },
+-  { 212, 1 },
+-  { 159, 0 },
+-  { 159, 2 },
+-  { 194, 2 },
++  { 199, 1 },
++  { 199, 0 },
++  { 192, 0 },
++  { 192, 2 },
++  { 201, 2 },
++  { 201, 0 },
++  { 200, 6 },
++  { 200, 7 },
++  { 205, 1 },
++  { 205, 1 },
++  { 151, 0 },
++  { 151, 2 },
++  { 187, 2 },
++  { 202, 1 },
++  { 202, 2 },
++  { 202, 3 },
++  { 202, 4 },
++  { 203, 2 },
++  { 203, 0 },
++  { 204, 4 },
++  { 204, 0 },
++  { 196, 0 },
++  { 196, 3 },
++  { 208, 5 },
++  { 208, 3 },
+   { 209, 1 },
+-  { 209, 1 },
+-  { 209, 2 },
+-  { 209, 3 },
+-  { 209, 4 },
+-  { 210, 2 },
++  { 171, 1 },
++  { 171, 1 },
++  { 171, 0 },
+   { 210, 0 },
+-  { 211, 4 },
+-  { 211, 0 },
+-  { 203, 0 },
+-  { 203, 3 },
+-  { 215, 5 },
++  { 210, 2 },
++  { 194, 0 },
++  { 194, 3 },
++  { 195, 0 },
++  { 195, 2 },
++  { 197, 0 },
++  { 197, 2 },
++  { 197, 4 },
++  { 197, 4 },
++  { 142, 4 },
++  { 193, 0 },
++  { 193, 2 },
++  { 142, 6 },
++  { 212, 5 },
++  { 212, 3 },
++  { 142, 8 },
++  { 142, 5 },
++  { 213, 2 },
++  { 213, 1 },
+   { 215, 3 },
++  { 215, 1 },
++  { 214, 0 },
++  { 214, 3 },
++  { 207, 3 },
++  { 207, 1 },
++  { 169, 1 },
++  { 169, 3 },
++  { 168, 1 },
++  { 169, 1 },
++  { 169, 1 },
++  { 169, 3 },
++  { 169, 5 },
++  { 168, 1 },
++  { 168, 1 },
++  { 169, 1 },
++  { 169, 1 },
++  { 169, 6 },
++  { 169, 5 },
++  { 169, 4 },
++  { 168, 1 },
++  { 169, 3 },
++  { 169, 3 },
++  { 169, 3 },
++  { 169, 3 },
++  { 169, 3 },
++  { 169, 3 },
++  { 169, 3 },
++  { 169, 3 },
+   { 216, 1 },
+-  { 179, 1 },
+-  { 179, 1 },
+-  { 179, 0 },
+-  { 217, 0 },
++  { 216, 2 },
+   { 217, 2 },
+-  { 201, 0 },
+-  { 201, 3 },
+-  { 202, 0 },
+-  { 202, 2 },
+-  { 204, 0 },
+-  { 204, 2 },
+-  { 204, 4 },
+-  { 204, 4 },
+-  { 151, 4 },
+-  { 200, 0 },
+-  { 200, 2 },
+-  { 151, 6 },
+-  { 219, 5 },
+-  { 219, 3 },
+-  { 151, 8 },
+-  { 151, 5 },
+-  { 220, 2 },
++  { 217, 0 },
++  { 169, 4 },
++  { 169, 2 },
++  { 169, 3 },
++  { 169, 3 },
++  { 169, 4 },
++  { 169, 2 },
++  { 169, 2 },
++  { 169, 2 },
++  { 218, 1 },
++  { 218, 2 },
++  { 169, 5 },
++  { 219, 1 },
++  { 219, 2 },
++  { 169, 5 },
++  { 169, 3 },
++  { 169, 5 },
++  { 169, 4 },
++  { 169, 4 },
++  { 169, 5 },
++  { 221, 5 },
++  { 221, 4 },
++  { 222, 2 },
++  { 222, 0 },
+   { 220, 1 },
+-  { 222, 3 },
+-  { 222, 1 },
+-  { 221, 0 },
+-  { 221, 3 },
+-  { 214, 3 },
+-  { 214, 1 },
+-  { 177, 1 },
+-  { 177, 3 },
+-  { 176, 1 },
+-  { 177, 1 },
+-  { 177, 1 },
+-  { 177, 3 },
+-  { 177, 5 },
+-  { 176, 1 },
+-  { 176, 1 },
+-  { 176, 1 },
+-  { 176, 1 },
+-  { 177, 1 },
+-  { 177, 1 },
+-  { 177, 6 },
+-  { 177, 5 },
+-  { 177, 4 },
+-  { 176, 1 },
+-  { 177, 3 },
+-  { 177, 3 },
+-  { 177, 3 },
+-  { 177, 3 },
+-  { 177, 3 },
+-  { 177, 3 },
+-  { 177, 3 },
+-  { 177, 3 },
+-  { 177, 3 },
+-  { 177, 3 },
+-  { 177, 3 },
+-  { 177, 3 },
+-  { 177, 3 },
+-  { 177, 3 },
+-  { 177, 3 },
+-  { 177, 3 },
+-  { 177, 3 },
+-  { 177, 3 },
++  { 220, 0 },
++  { 211, 3 },
++  { 211, 1 },
+   { 223, 1 },
+-  { 223, 2 },
+-  { 224, 2 },
++  { 223, 0 },
++  { 142, 11 },
++  { 224, 1 },
+   { 224, 0 },
+-  { 177, 4 },
+-  { 177, 2 },
+-  { 177, 3 },
+-  { 177, 2 },
+-  { 177, 3 },
+-  { 177, 4 },
+-  { 177, 2 },
+-  { 177, 2 },
+-  { 177, 2 },
+-  { 177, 2 },
++  { 173, 0 },
++  { 173, 3 },
++  { 181, 5 },
++  { 181, 3 },
+   { 225, 1 },
+-  { 225, 2 },
+-  { 177, 5 },
+-  { 226, 1 },
+-  { 226, 2 },
+-  { 177, 5 },
+-  { 177, 3 },
+-  { 177, 5 },
+-  { 177, 4 },
+-  { 177, 4 },
+-  { 177, 5 },
+-  { 228, 5 },
+-  { 228, 4 },
+-  { 229, 2 },
+-  { 229, 0 },
++  { 142, 4 },
++  { 142, 1 },
++  { 142, 2 },
++  { 142, 5 },
++  { 142, 5 },
++  { 142, 5 },
++  { 142, 5 },
++  { 142, 6 },
++  { 142, 3 },
++  { 164, 2 },
++  { 165, 2 },
+   { 227, 1 },
+-  { 227, 0 },
+-  { 218, 3 },
+-  { 218, 1 },
++  { 226, 1 },
++  { 226, 0 },
++  { 142, 5 },
++  { 228, 10 },
+   { 230, 1 },
++  { 230, 1 },
++  { 230, 2 },
+   { 230, 0 },
+-  { 151, 11 },
+   { 231, 1 },
+-  { 231, 0 },
+-  { 181, 0 },
+-  { 181, 3 },
+-  { 189, 5 },
+-  { 189, 3 },
+-  { 232, 1 },
+-  { 151, 3 },
+-  { 151, 1 },
+-  { 151, 2 },
+-  { 151, 5 },
+-  { 151, 5 },
+-  { 151, 5 },
+-  { 151, 5 },
+-  { 151, 6 },
+-  { 151, 3 },
+-  { 172, 2 },
+-  { 173, 2 },
+-  { 234, 1 },
+-  { 234, 1 },
+-  { 233, 1 },
++  { 231, 1 },
++  { 231, 3 },
++  { 232, 0 },
++  { 232, 3 },
++  { 232, 3 },
+   { 233, 0 },
+-  { 151, 5 },
+-  { 235, 10 },
++  { 233, 2 },
++  { 229, 3 },
++  { 229, 0 },
++  { 234, 6 },
++  { 234, 8 },
++  { 234, 5 },
++  { 234, 4 },
++  { 234, 1 },
++  { 169, 4 },
++  { 169, 6 },
++  { 185, 1 },
++  { 185, 1 },
++  { 185, 1 },
++  { 142, 3 },
++  { 142, 6 },
++  { 236, 0 },
++  { 236, 2 },
++  { 235, 1 },
++  { 235, 0 },
++  { 142, 3 },
++  { 142, 1 },
++  { 142, 3 },
++  { 142, 1 },
++  { 142, 3 },
++  { 142, 6 },
++  { 142, 6 },
+   { 237, 1 },
+-  { 237, 1 },
+-  { 237, 2 },
+-  { 237, 0 },
++  { 238, 0 },
+   { 238, 1 },
+-  { 238, 1 },
+-  { 238, 1 },
+-  { 238, 3 },
+-  { 239, 0 },
+-  { 239, 3 },
+-  { 239, 3 },
+-  { 240, 0 },
+-  { 240, 2 },
+-  { 236, 3 },
+-  { 236, 0 },
+-  { 241, 6 },
+-  { 241, 8 },
+-  { 241, 5 },
+-  { 241, 4 },
+-  { 241, 1 },
+-  { 177, 4 },
+-  { 177, 6 },
+-  { 193, 1 },
+-  { 193, 1 },
+-  { 193, 1 },
+-  { 151, 3 },
+-  { 151, 6 },
+-  { 243, 0 },
+-  { 243, 2 },
+-  { 243, 2 },
+-  { 242, 1 },
+-  { 242, 0 },
+-  { 151, 3 },
+-  { 151, 1 },
+-  { 151, 3 },
+-  { 151, 1 },
+-  { 151, 3 },
+-  { 151, 6 },
+-  { 151, 6 },
+-  { 244, 1 },
+-  { 245, 0 },
+-  { 245, 1 },
+ };
+ 
+ static void yy_accept(yyParser*);  /* Forward Declaration */
+@@ -1923,777 +1798,781 @@
+   **     break;
+   */
+       case 3:
+-#line 102 "parse.y"
++#line 95 "parse.y"
+ { sqlite3FinishCoding(pParse); }
+-#line 1930 "parse.c"
++#line 1805 "parse.c"
+         break;
+       case 6:
+-#line 105 "parse.y"
++#line 98 "parse.y"
+ { sqlite3BeginParse(pParse, 0); }
+-#line 1935 "parse.c"
++#line 1810 "parse.c"
+         break;
+       case 7:
+-#line 107 "parse.y"
++#line 100 "parse.y"
+ { sqlite3BeginParse(pParse, 1); }
+-#line 1940 "parse.c"
++#line 1815 "parse.c"
+         break;
+       case 8:
+-#line 108 "parse.y"
++#line 101 "parse.y"
+ { sqlite3BeginParse(pParse, 2); }
+-#line 1945 "parse.c"
++#line 1820 "parse.c"
+         break;
+       case 9:
+-#line 114 "parse.y"
+-{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy280);}
+-#line 1950 "parse.c"
++#line 107 "parse.y"
++{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy230);}
++#line 1825 "parse.c"
+         break;
+       case 13:
+-#line 119 "parse.y"
+-{yygotominor.yy280 = TK_DEFERRED;}
+-#line 1955 "parse.c"
++#line 112 "parse.y"
++{yygotominor.yy230 = TK_DEFERRED;}
++#line 1830 "parse.c"
+         break;
+       case 14:
+       case 15:
+       case 16:
+-      case 104:
+-      case 106:
+       case 107:
+-#line 120 "parse.y"
+-{yygotominor.yy280 = yymsp[0].major;}
+-#line 1965 "parse.c"
++      case 109:
++#line 113 "parse.y"
++{yygotominor.yy230 = yymsp[0].major;}
++#line 1839 "parse.c"
+         break;
+       case 17:
+       case 18:
+-#line 123 "parse.y"
++#line 116 "parse.y"
+ {sqlite3CommitTransaction(pParse);}
+-#line 1971 "parse.c"
++#line 1845 "parse.c"
+         break;
+       case 19:
+-#line 125 "parse.y"
++#line 118 "parse.y"
+ {sqlite3RollbackTransaction(pParse);}
+-#line 1976 "parse.c"
++#line 1850 "parse.c"
+         break;
+       case 21:
+-#line 130 "parse.y"
++#line 123 "parse.y"
+ {
+-   sqlite3StartTable(pParse,&yymsp[-4].minor.yy0,&yymsp[-1].minor.yy198,&yymsp[0].minor.yy198,yymsp[-3].minor.yy280,0);
++   sqlite3StartTable(pParse,&yymsp[-5].minor.yy0,&yymsp[-1].minor.yy384,&yymsp[0].minor.yy384,yymsp[-4].minor.yy230,0,yymsp[-2].minor.yy230);
+ }
+-#line 1983 "parse.c"
++#line 1857 "parse.c"
+         break;
+       case 22:
++      case 25:
+       case 63:
+       case 77:
+-      case 109:
+-      case 224:
+-      case 227:
+-#line 135 "parse.y"
+-{yygotominor.yy280 = 1;}
+-#line 1993 "parse.c"
++      case 79:
++      case 90:
++      case 101:
++      case 112:
++      case 113:
++      case 210:
++      case 213:
++#line 127 "parse.y"
++{yygotominor.yy230 = 0;}
++#line 1872 "parse.c"
+         break;
+       case 23:
+-      case 62:
+-      case 76:
++      case 24:
++      case 64:
+       case 78:
+-      case 89:
+-      case 110:
++      case 100:
+       case 111:
+-      case 223:
+-      case 226:
+-#line 137 "parse.y"
+-{yygotominor.yy280 = 0;}
+-#line 2006 "parse.c"
++      case 211:
++      case 214:
++#line 128 "parse.y"
++{yygotominor.yy230 = 1;}
++#line 1884 "parse.c"
+         break;
+-      case 24:
+-#line 138 "parse.y"
++      case 26:
++#line 134 "parse.y"
+ {
+-  sqlite3EndTable(pParse,&yymsp[-1].minor.yy198,&yymsp[0].minor.yy0,0);
++  sqlite3EndTable(pParse,&yymsp[-1].minor.yy384,&yymsp[0].minor.yy0,0);
+ }
+-#line 2013 "parse.c"
++#line 1891 "parse.c"
+         break;
+-      case 25:
+-#line 141 "parse.y"
++      case 27:
++#line 137 "parse.y"
+ {
+-  sqlite3EndTable(pParse,0,0,yymsp[0].minor.yy375);
+-  sqlite3SelectDelete(yymsp[0].minor.yy375);
++  sqlite3EndTable(pParse,0,0,yymsp[0].minor.yy239);
++  sqlite3SelectDelete(yymsp[0].minor.yy239);
+ }
+-#line 2021 "parse.c"
++#line 1899 "parse.c"
+         break;
+-      case 28:
+-#line 153 "parse.y"
++      case 30:
++#line 149 "parse.y"
+ {
+-  yygotominor.yy198.z = yymsp[-2].minor.yy198.z;
+-  yygotominor.yy198.n = (pParse->sLastToken.z-yymsp[-2].minor.yy198.z) + pParse->sLastToken.n;
++  yygotominor.yy384.z = yymsp[-2].minor.yy384.z;
++  yygotominor.yy384.n = (pParse->sLastToken.z-yymsp[-2].minor.yy384.z) + pParse->sLastToken.n;
+ }
+-#line 2029 "parse.c"
++#line 1907 "parse.c"
+         break;
+-      case 29:
+-#line 157 "parse.y"
++      case 31:
++#line 153 "parse.y"
+ {
+-  sqlite3AddColumn(pParse,&yymsp[0].minor.yy198);
+-  yygotominor.yy198 = yymsp[0].minor.yy198;
++  sqlite3AddColumn(pParse,&yymsp[0].minor.yy384);
++  yygotominor.yy384 = yymsp[0].minor.yy384;
+ }
+-#line 2037 "parse.c"
++#line 1915 "parse.c"
+         break;
+-      case 30:
+-      case 31:
+       case 32:
+       case 33:
+       case 34:
+       case 35:
+-      case 263:
+-      case 264:
+-#line 167 "parse.y"
+-{yygotominor.yy198 = yymsp[0].minor.yy0;}
+-#line 2049 "parse.c"
++      case 36:
++      case 250:
++#line 163 "parse.y"
++{yygotominor.yy384 = yymsp[0].minor.yy0;}
++#line 1925 "parse.c"
+         break;
+-      case 37:
+-#line 227 "parse.y"
+-{sqlite3AddColumnType(pParse,&yymsp[0].minor.yy198);}
+-#line 2054 "parse.c"
+-        break;
+       case 38:
+-      case 41:
+-      case 117:
+-      case 118:
+-      case 129:
+-      case 149:
+-      case 251:
+-      case 261:
+-      case 262:
+-#line 228 "parse.y"
+-{yygotominor.yy198 = yymsp[0].minor.yy198;}
+-#line 2067 "parse.c"
++#line 222 "parse.y"
++{sqlite3AddColumnType(pParse,&yymsp[0].minor.yy384);}
++#line 1930 "parse.c"
+         break;
+       case 39:
+-#line 229 "parse.y"
++      case 42:
++      case 119:
++      case 120:
++      case 131:
++      case 150:
++      case 238:
++      case 248:
++      case 249:
++#line 223 "parse.y"
++{yygotominor.yy384 = yymsp[0].minor.yy384;}
++#line 1943 "parse.c"
++        break;
++      case 40:
++#line 224 "parse.y"
+ {
+-  yygotominor.yy198.z = yymsp[-3].minor.yy198.z;
+-  yygotominor.yy198.n = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy198.z;
++  yygotominor.yy384.z = yymsp[-3].minor.yy384.z;
++  yygotominor.yy384.n = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy384.z;
+ }
+-#line 2075 "parse.c"
++#line 1951 "parse.c"
+         break;
+-      case 40:
+-#line 233 "parse.y"
++      case 41:
++#line 228 "parse.y"
+ {
+-  yygotominor.yy198.z = yymsp[-5].minor.yy198.z;
+-  yygotominor.yy198.n = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy198.z;
++  yygotominor.yy384.z = yymsp[-5].minor.yy384.z;
++  yygotominor.yy384.n = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy384.z;
+ }
+-#line 2083 "parse.c"
++#line 1959 "parse.c"
+         break;
+-      case 42:
+-#line 239 "parse.y"
+-{yygotominor.yy198.z=yymsp[-1].minor.yy198.z; yygotominor.yy198.n=yymsp[0].minor.yy198.n+(yymsp[0].minor.yy198.z-yymsp[-1].minor.yy198.z);}
+-#line 2088 "parse.c"
+-        break;
+       case 43:
+-#line 241 "parse.y"
+-{ yygotominor.yy280 = atoi(yymsp[0].minor.yy198.z); }
+-#line 2093 "parse.c"
++#line 234 "parse.y"
++{yygotominor.yy384.z=yymsp[-1].minor.yy384.z; yygotominor.yy384.n=yymsp[0].minor.yy384.n+(yymsp[0].minor.yy384.z-yymsp[-1].minor.yy384.z);}
++#line 1964 "parse.c"
+         break;
+       case 44:
+-#line 242 "parse.y"
+-{ yygotominor.yy280 = -atoi(yymsp[0].minor.yy198.z); }
+-#line 2098 "parse.c"
++#line 236 "parse.y"
++{ yygotominor.yy230 = atoi((char*)yymsp[0].minor.yy384.z); }
++#line 1969 "parse.c"
+         break;
+-      case 49:
+-      case 51:
+-#line 251 "parse.y"
+-{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy62);}
+-#line 2104 "parse.c"
++      case 45:
++#line 237 "parse.y"
++{ yygotominor.yy230 = -atoi((char*)yymsp[0].minor.yy384.z); }
++#line 1974 "parse.c"
+         break;
+       case 50:
+-#line 252 "parse.y"
+-{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy62);}
+-#line 2109 "parse.c"
+-        break;
+       case 52:
+-#line 254 "parse.y"
++#line 246 "parse.y"
++{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy178);}
++#line 1980 "parse.c"
++        break;
++      case 51:
++#line 247 "parse.y"
++{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy178);}
++#line 1985 "parse.c"
++        break;
++      case 53:
++#line 249 "parse.y"
+ {
+-  Expr *p = sqlite3Expr(TK_UMINUS, yymsp[0].minor.yy62, 0, 0);
++  Expr *p = sqlite3Expr(TK_UMINUS, yymsp[0].minor.yy178, 0, 0);
+   sqlite3AddDefaultValue(pParse,p);
+ }
+-#line 2117 "parse.c"
++#line 1993 "parse.c"
+         break;
+-      case 53:
+-#line 258 "parse.y"
++      case 54:
++#line 253 "parse.y"
+ {
+-  Expr *p = sqlite3Expr(TK_STRING, 0, 0, &yymsp[0].minor.yy198);
++  Expr *p = sqlite3Expr(TK_STRING, 0, 0, &yymsp[0].minor.yy384);
+   sqlite3AddDefaultValue(pParse,p);
+ }
+-#line 2125 "parse.c"
++#line 2001 "parse.c"
+         break;
+-      case 55:
+-#line 267 "parse.y"
+-{sqlite3AddNotNull(pParse, yymsp[0].minor.yy280);}
+-#line 2130 "parse.c"
+-        break;
+       case 56:
+-#line 269 "parse.y"
+-{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy280,yymsp[0].minor.yy280);}
+-#line 2135 "parse.c"
++#line 262 "parse.y"
++{sqlite3AddNotNull(pParse, yymsp[0].minor.yy230);}
++#line 2006 "parse.c"
+         break;
+       case 57:
+-#line 270 "parse.y"
+-{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy280,0,0);}
+-#line 2140 "parse.c"
++#line 264 "parse.y"
++{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy230,yymsp[0].minor.yy230,yymsp[-2].minor.yy230);}
++#line 2011 "parse.c"
+         break;
+       case 58:
+-#line 271 "parse.y"
+-{sqlite3ExprDelete(yymsp[-2].minor.yy62);}
+-#line 2145 "parse.c"
++#line 265 "parse.y"
++{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy230,0,0,0,0);}
++#line 2016 "parse.c"
+         break;
+       case 59:
+-#line 273 "parse.y"
+-{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy198,yymsp[-1].minor.yy418,yymsp[0].minor.yy280);}
+-#line 2150 "parse.c"
++#line 266 "parse.y"
++{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy178);}
++#line 2021 "parse.c"
+         break;
+       case 60:
+-#line 274 "parse.y"
+-{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy280);}
+-#line 2155 "parse.c"
++#line 268 "parse.y"
++{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy384,yymsp[-1].minor.yy462,yymsp[0].minor.yy230);}
++#line 2026 "parse.c"
+         break;
+       case 61:
+-#line 275 "parse.y"
+-{sqlite3AddCollateType(pParse, yymsp[0].minor.yy198.z, yymsp[0].minor.yy198.n);}
+-#line 2160 "parse.c"
++#line 269 "parse.y"
++{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy230);}
++#line 2031 "parse.c"
+         break;
+-      case 64:
+-#line 288 "parse.y"
+-{ yygotominor.yy280 = OE_Restrict * 0x010101; }
+-#line 2165 "parse.c"
++      case 62:
++#line 270 "parse.y"
++{sqlite3AddCollateType(pParse, (char*)yymsp[0].minor.yy384.z, yymsp[0].minor.yy384.n);}
++#line 2036 "parse.c"
+         break;
+       case 65:
+-#line 289 "parse.y"
+-{ yygotominor.yy280 = (yymsp[-1].minor.yy280 & yymsp[0].minor.yy359.mask) | yymsp[0].minor.yy359.value; }
+-#line 2170 "parse.c"
++#line 283 "parse.y"
++{ yygotominor.yy230 = OE_Restrict * 0x010101; }
++#line 2041 "parse.c"
+         break;
+       case 66:
+-#line 291 "parse.y"
+-{ yygotominor.yy359.value = 0;     yygotominor.yy359.mask = 0x000000; }
+-#line 2175 "parse.c"
++#line 284 "parse.y"
++{ yygotominor.yy230 = (yymsp[-1].minor.yy230 & yymsp[0].minor.yy13.mask) | yymsp[0].minor.yy13.value; }
++#line 2046 "parse.c"
+         break;
+       case 67:
+-#line 292 "parse.y"
+-{ yygotominor.yy359.value = yymsp[0].minor.yy280;     yygotominor.yy359.mask = 0x0000ff; }
+-#line 2180 "parse.c"
++#line 286 "parse.y"
++{ yygotominor.yy13.value = 0;     yygotominor.yy13.mask = 0x000000; }
++#line 2051 "parse.c"
+         break;
+       case 68:
+-#line 293 "parse.y"
+-{ yygotominor.yy359.value = yymsp[0].minor.yy280<<8;  yygotominor.yy359.mask = 0x00ff00; }
+-#line 2185 "parse.c"
++#line 287 "parse.y"
++{ yygotominor.yy13.value = yymsp[0].minor.yy230;     yygotominor.yy13.mask = 0x0000ff; }
++#line 2056 "parse.c"
+         break;
+       case 69:
+-#line 294 "parse.y"
+-{ yygotominor.yy359.value = yymsp[0].minor.yy280<<16; yygotominor.yy359.mask = 0xff0000; }
+-#line 2190 "parse.c"
++#line 288 "parse.y"
++{ yygotominor.yy13.value = yymsp[0].minor.yy230<<8;  yygotominor.yy13.mask = 0x00ff00; }
++#line 2061 "parse.c"
+         break;
+       case 70:
+-#line 296 "parse.y"
+-{ yygotominor.yy280 = OE_SetNull; }
+-#line 2195 "parse.c"
++#line 289 "parse.y"
++{ yygotominor.yy13.value = yymsp[0].minor.yy230<<16; yygotominor.yy13.mask = 0xff0000; }
++#line 2066 "parse.c"
+         break;
+       case 71:
+-#line 297 "parse.y"
+-{ yygotominor.yy280 = OE_SetDflt; }
+-#line 2200 "parse.c"
++#line 291 "parse.y"
++{ yygotominor.yy230 = OE_SetNull; }
++#line 2071 "parse.c"
+         break;
+       case 72:
+-#line 298 "parse.y"
+-{ yygotominor.yy280 = OE_Cascade; }
+-#line 2205 "parse.c"
++#line 292 "parse.y"
++{ yygotominor.yy230 = OE_SetDflt; }
++#line 2076 "parse.c"
+         break;
+       case 73:
+-#line 299 "parse.y"
+-{ yygotominor.yy280 = OE_Restrict; }
+-#line 2210 "parse.c"
++#line 293 "parse.y"
++{ yygotominor.yy230 = OE_Cascade; }
++#line 2081 "parse.c"
+         break;
+       case 74:
++#line 294 "parse.y"
++{ yygotominor.yy230 = OE_Restrict; }
++#line 2086 "parse.c"
++        break;
+       case 75:
+-      case 90:
+-      case 92:
+-      case 94:
++      case 76:
++      case 91:
++      case 93:
+       case 95:
+-      case 166:
+-#line 301 "parse.y"
+-{yygotominor.yy280 = yymsp[0].minor.yy280;}
+-#line 2221 "parse.c"
++      case 96:
++      case 167:
++#line 296 "parse.y"
++{yygotominor.yy230 = yymsp[0].minor.yy230;}
++#line 2097 "parse.c"
+         break;
+-      case 79:
+-#line 311 "parse.y"
+-{yygotominor.yy198.n = 0; yygotominor.yy198.z = 0;}
+-#line 2226 "parse.c"
+-        break;
+       case 80:
+-#line 312 "parse.y"
+-{yygotominor.yy198 = yymsp[-1].minor.yy0;}
+-#line 2231 "parse.c"
++#line 306 "parse.y"
++{yygotominor.yy384.n = 0; yygotominor.yy384.z = 0;}
++#line 2102 "parse.c"
+         break;
+-      case 85:
+-#line 318 "parse.y"
+-{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy418,yymsp[0].minor.yy280,yymsp[-2].minor.yy280);}
+-#line 2236 "parse.c"
++      case 81:
++#line 307 "parse.y"
++{yygotominor.yy384 = yymsp[-1].minor.yy0;}
++#line 2107 "parse.c"
+         break;
+       case 86:
+-#line 320 "parse.y"
+-{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy418,yymsp[0].minor.yy280,0,0);}
+-#line 2241 "parse.c"
++#line 313 "parse.y"
++{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy462,yymsp[0].minor.yy230,yymsp[-2].minor.yy230,0);}
++#line 2112 "parse.c"
+         break;
++      case 87:
++#line 315 "parse.y"
++{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy462,yymsp[0].minor.yy230,0,0,0,0);}
++#line 2117 "parse.c"
++        break;
+       case 88:
+-#line 323 "parse.y"
++#line 316 "parse.y"
++{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy178);}
++#line 2122 "parse.c"
++        break;
++      case 89:
++#line 318 "parse.y"
+ {
+-    sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy418, &yymsp[-3].minor.yy198, yymsp[-2].minor.yy418, yymsp[-1].minor.yy280);
+-    sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy280);
++    sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy462, &yymsp[-3].minor.yy384, yymsp[-2].minor.yy462, yymsp[-1].minor.yy230);
++    sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy230);
+ }
+-#line 2249 "parse.c"
++#line 2130 "parse.c"
+         break;
+-      case 91:
+-      case 93:
+-#line 337 "parse.y"
+-{yygotominor.yy280 = OE_Default;}
+-#line 2255 "parse.c"
++      case 92:
++      case 94:
++#line 332 "parse.y"
++{yygotominor.yy230 = OE_Default;}
++#line 2136 "parse.c"
+         break;
+-      case 96:
+-#line 342 "parse.y"
+-{yygotominor.yy280 = OE_Ignore;}
+-#line 2260 "parse.c"
+-        break;
+       case 97:
+-      case 167:
+-#line 343 "parse.y"
+-{yygotominor.yy280 = OE_Replace;}
+-#line 2266 "parse.c"
++#line 337 "parse.y"
++{yygotominor.yy230 = OE_Ignore;}
++#line 2141 "parse.c"
+         break;
+       case 98:
+-#line 347 "parse.y"
++      case 168:
++#line 338 "parse.y"
++{yygotominor.yy230 = OE_Replace;}
++#line 2147 "parse.c"
++        break;
++      case 99:
++#line 342 "parse.y"
+ {
+-  sqlite3DropTable(pParse, yymsp[0].minor.yy151, 0);
++  sqlite3DropTable(pParse, yymsp[0].minor.yy285, 0, yymsp[-1].minor.yy230);
+ }
+-#line 2273 "parse.c"
++#line 2154 "parse.c"
+         break;
+-      case 99:
+-#line 354 "parse.y"
++      case 102:
++#line 352 "parse.y"
+ {
+-  sqlite3CreateView(pParse, &yymsp[-6].minor.yy0, &yymsp[-3].minor.yy198, &yymsp[-2].minor.yy198, yymsp[0].minor.yy375, yymsp[-5].minor.yy280);
++  sqlite3CreateView(pParse, &yymsp[-6].minor.yy0, &yymsp[-3].minor.yy384, &yymsp[-2].minor.yy384, yymsp[0].minor.yy239, yymsp[-5].minor.yy230);
+ }
+-#line 2280 "parse.c"
++#line 2161 "parse.c"
+         break;
+-      case 100:
+-#line 357 "parse.y"
++      case 103:
++#line 355 "parse.y"
+ {
+-  sqlite3DropTable(pParse, yymsp[0].minor.yy151, 1);
++  sqlite3DropTable(pParse, yymsp[0].minor.yy285, 1, yymsp[-1].minor.yy230);
+ }
+-#line 2287 "parse.c"
++#line 2168 "parse.c"
+         break;
+-      case 101:
+-#line 364 "parse.y"
++      case 104:
++#line 362 "parse.y"
+ {
+-  sqlite3Select(pParse, yymsp[0].minor.yy375, SRT_Callback, 0, 0, 0, 0, 0);
+-  sqlite3SelectDelete(yymsp[0].minor.yy375);
++  sqlite3Select(pParse, yymsp[0].minor.yy239, SRT_Callback, 0, 0, 0, 0, 0);
++  sqlite3SelectDelete(yymsp[0].minor.yy239);
+ }
+-#line 2295 "parse.c"
++#line 2176 "parse.c"
+         break;
+-      case 102:
+-      case 126:
+-#line 374 "parse.y"
+-{yygotominor.yy375 = yymsp[0].minor.yy375;}
+-#line 2301 "parse.c"
++      case 105:
++      case 128:
++#line 372 "parse.y"
++{yygotominor.yy239 = yymsp[0].minor.yy239;}
++#line 2182 "parse.c"
+         break;
+-      case 103:
+-#line 376 "parse.y"
++      case 106:
++#line 374 "parse.y"
+ {
+-  if( yymsp[0].minor.yy375 ){
+-    yymsp[0].minor.yy375->op = yymsp[-1].minor.yy280;
+-    yymsp[0].minor.yy375->pPrior = yymsp[-2].minor.yy375;
++  if( yymsp[0].minor.yy239 ){
++    yymsp[0].minor.yy239->op = yymsp[-1].minor.yy230;
++    yymsp[0].minor.yy239->pPrior = yymsp[-2].minor.yy239;
+   }
+-  yygotominor.yy375 = yymsp[0].minor.yy375;
++  yygotominor.yy239 = yymsp[0].minor.yy239;
+ }
+-#line 2312 "parse.c"
++#line 2193 "parse.c"
+         break;
+-      case 105:
+-#line 385 "parse.y"
+-{yygotominor.yy280 = TK_ALL;}
+-#line 2317 "parse.c"
+-        break;
+       case 108:
+-#line 390 "parse.y"
++#line 383 "parse.y"
++{yygotominor.yy230 = TK_ALL;}
++#line 2198 "parse.c"
++        break;
++      case 110:
++#line 387 "parse.y"
+ {
+-  yygotominor.yy375 = sqlite3SelectNew(yymsp[-6].minor.yy418,yymsp[-5].minor.yy151,yymsp[-4].minor.yy62,yymsp[-3].minor.yy418,yymsp[-2].minor.yy62,yymsp[-1].minor.yy418,yymsp[-7].minor.yy280,yymsp[0].minor.yy220.pLimit,yymsp[0].minor.yy220.pOffset);
++  yygotominor.yy239 = sqlite3SelectNew(yymsp[-6].minor.yy462,yymsp[-5].minor.yy285,yymsp[-4].minor.yy178,yymsp[-3].minor.yy462,yymsp[-2].minor.yy178,yymsp[-1].minor.yy462,yymsp[-7].minor.yy230,yymsp[0].minor.yy270.pLimit,yymsp[0].minor.yy270.pOffset);
+ }
+-#line 2324 "parse.c"
++#line 2205 "parse.c"
+         break;
+-      case 112:
+-      case 248:
+-#line 411 "parse.y"
+-{yygotominor.yy418 = yymsp[-1].minor.yy418;}
+-#line 2330 "parse.c"
++      case 114:
++      case 235:
++#line 408 "parse.y"
++{yygotominor.yy462 = yymsp[-1].minor.yy462;}
++#line 2211 "parse.c"
+         break;
+-      case 113:
+-      case 140:
+-      case 150:
+-      case 247:
+-#line 412 "parse.y"
+-{yygotominor.yy418 = 0;}
+-#line 2338 "parse.c"
++      case 115:
++      case 141:
++      case 151:
++      case 234:
++#line 409 "parse.y"
++{yygotominor.yy462 = 0;}
++#line 2219 "parse.c"
+         break;
+-      case 114:
+-#line 413 "parse.y"
++      case 116:
++#line 410 "parse.y"
+ {
+-   yygotominor.yy418 = sqlite3ExprListAppend(yymsp[-2].minor.yy418,yymsp[-1].minor.yy62,yymsp[0].minor.yy198.n?&yymsp[0].minor.yy198:0);
++   yygotominor.yy462 = sqlite3ExprListAppend(yymsp[-2].minor.yy462,yymsp[-1].minor.yy178,yymsp[0].minor.yy384.n?&yymsp[0].minor.yy384:0);
+ }
+-#line 2345 "parse.c"
++#line 2226 "parse.c"
+         break;
+-      case 115:
+-#line 416 "parse.y"
++      case 117:
++#line 413 "parse.y"
+ {
+-  yygotominor.yy418 = sqlite3ExprListAppend(yymsp[-1].minor.yy418, sqlite3Expr(TK_ALL, 0, 0, 0), 0);
++  yygotominor.yy462 = sqlite3ExprListAppend(yymsp[-1].minor.yy462, sqlite3Expr(TK_ALL, 0, 0, 0), 0);
+ }
+-#line 2352 "parse.c"
++#line 2233 "parse.c"
+         break;
+-      case 116:
+-#line 419 "parse.y"
++      case 118:
++#line 416 "parse.y"
+ {
+   Expr *pRight = sqlite3Expr(TK_ALL, 0, 0, 0);
+-  Expr *pLeft = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy198);
+-  yygotominor.yy418 = sqlite3ExprListAppend(yymsp[-3].minor.yy418, sqlite3Expr(TK_DOT, pLeft, pRight, 0), 0);
++  Expr *pLeft = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy384);
++  yygotominor.yy462 = sqlite3ExprListAppend(yymsp[-3].minor.yy462, sqlite3Expr(TK_DOT, pLeft, pRight, 0), 0);
+ }
+-#line 2361 "parse.c"
++#line 2242 "parse.c"
+         break;
+-      case 119:
+-#line 431 "parse.y"
+-{yygotominor.yy198.n = 0;}
+-#line 2366 "parse.c"
+-        break;
+-      case 120:
+-#line 443 "parse.y"
+-{yygotominor.yy151 = sqliteMalloc(sizeof(*yygotominor.yy151));}
+-#line 2371 "parse.c"
+-        break;
+       case 121:
+-#line 444 "parse.y"
+-{yygotominor.yy151 = yymsp[0].minor.yy151;}
+-#line 2376 "parse.c"
++#line 428 "parse.y"
++{yygotominor.yy384.n = 0;}
++#line 2247 "parse.c"
+         break;
+       case 122:
+-#line 449 "parse.y"
+-{
+-   yygotominor.yy151 = yymsp[-1].minor.yy151;
+-   if( yygotominor.yy151 && yygotominor.yy151->nSrc>0 ) yygotominor.yy151->a[yygotominor.yy151->nSrc-1].jointype = yymsp[0].minor.yy280;
+-}
+-#line 2384 "parse.c"
++#line 440 "parse.y"
++{yygotominor.yy285 = sqliteMalloc(sizeof(*yygotominor.yy285));}
++#line 2252 "parse.c"
+         break;
+       case 123:
+-#line 453 "parse.y"
+-{yygotominor.yy151 = 0;}
+-#line 2389 "parse.c"
++#line 441 "parse.y"
++{yygotominor.yy285 = yymsp[0].minor.yy285;}
++#line 2257 "parse.c"
+         break;
+       case 124:
+-#line 454 "parse.y"
++#line 446 "parse.y"
+ {
+-  yygotominor.yy151 = sqlite3SrcListAppend(yymsp[-5].minor.yy151,&yymsp[-4].minor.yy198,&yymsp[-3].minor.yy198);
+-  if( yymsp[-2].minor.yy198.n ) sqlite3SrcListAddAlias(yygotominor.yy151,&yymsp[-2].minor.yy198);
+-  if( yymsp[-1].minor.yy62 ){
+-    if( yygotominor.yy151 && yygotominor.yy151->nSrc>1 ){ yygotominor.yy151->a[yygotominor.yy151->nSrc-2].pOn = yymsp[-1].minor.yy62; }
+-    else { sqlite3ExprDelete(yymsp[-1].minor.yy62); }
++   yygotominor.yy285 = yymsp[-1].minor.yy285;
++   if( yygotominor.yy285 && yygotominor.yy285->nSrc>0 ) yygotominor.yy285->a[yygotominor.yy285->nSrc-1].jointype = yymsp[0].minor.yy230;
++}
++#line 2265 "parse.c"
++        break;
++      case 125:
++#line 450 "parse.y"
++{yygotominor.yy285 = 0;}
++#line 2270 "parse.c"
++        break;
++      case 126:
++#line 451 "parse.y"
++{
++  yygotominor.yy285 = sqlite3SrcListAppend(yymsp[-5].minor.yy285,&yymsp[-4].minor.yy384,&yymsp[-3].minor.yy384);
++  if( yymsp[-2].minor.yy384.n ) sqlite3SrcListAddAlias(yygotominor.yy285,&yymsp[-2].minor.yy384);
++  if( yymsp[-1].minor.yy178 ){
++    if( yygotominor.yy285 && yygotominor.yy285->nSrc>1 ){ yygotominor.yy285->a[yygotominor.yy285->nSrc-2].pOn = yymsp[-1].minor.yy178; }
++    else { sqlite3ExprDelete(yymsp[-1].minor.yy178); }
+   }
+-  if( yymsp[0].minor.yy240 ){
+-    if( yygotominor.yy151 && yygotominor.yy151->nSrc>1 ){ yygotominor.yy151->a[yygotominor.yy151->nSrc-2].pUsing = yymsp[0].minor.yy240; }
+-    else { sqlite3IdListDelete(yymsp[0].minor.yy240); }
++  if( yymsp[0].minor.yy160 ){
++    if( yygotominor.yy285 && yygotominor.yy285->nSrc>1 ){ yygotominor.yy285->a[yygotominor.yy285->nSrc-2].pUsing = yymsp[0].minor.yy160; }
++    else { sqlite3IdListDelete(yymsp[0].minor.yy160); }
+   }
+ }
+-#line 2405 "parse.c"
++#line 2286 "parse.c"
+         break;
+-      case 125:
+-#line 468 "parse.y"
++      case 127:
++#line 465 "parse.y"
+ {
+-    yygotominor.yy151 = sqlite3SrcListAppend(yymsp[-6].minor.yy151,0,0);
+-    yygotominor.yy151->a[yygotominor.yy151->nSrc-1].pSelect = yymsp[-4].minor.yy375;
+-    if( yymsp[-2].minor.yy198.n ) sqlite3SrcListAddAlias(yygotominor.yy151,&yymsp[-2].minor.yy198);
+-    if( yymsp[-1].minor.yy62 ){
+-      if( yygotominor.yy151 && yygotominor.yy151->nSrc>1 ){ yygotominor.yy151->a[yygotominor.yy151->nSrc-2].pOn = yymsp[-1].minor.yy62; }
+-      else { sqlite3ExprDelete(yymsp[-1].minor.yy62); }
++    yygotominor.yy285 = sqlite3SrcListAppend(yymsp[-6].minor.yy285,0,0);
++    yygotominor.yy285->a[yygotominor.yy285->nSrc-1].pSelect = yymsp[-4].minor.yy239;
++    if( yymsp[-2].minor.yy384.n ) sqlite3SrcListAddAlias(yygotominor.yy285,&yymsp[-2].minor.yy384);
++    if( yymsp[-1].minor.yy178 ){
++      if( yygotominor.yy285 && yygotominor.yy285->nSrc>1 ){ yygotominor.yy285->a[yygotominor.yy285->nSrc-2].pOn = yymsp[-1].minor.yy178; }
++      else { sqlite3ExprDelete(yymsp[-1].minor.yy178); }
+     }
+-    if( yymsp[0].minor.yy240 ){
+-      if( yygotominor.yy151 && yygotominor.yy151->nSrc>1 ){ yygotominor.yy151->a[yygotominor.yy151->nSrc-2].pUsing = yymsp[0].minor.yy240; }
+-      else { sqlite3IdListDelete(yymsp[0].minor.yy240); }
++    if( yymsp[0].minor.yy160 ){
++      if( yygotominor.yy285 && yygotominor.yy285->nSrc>1 ){ yygotominor.yy285->a[yygotominor.yy285->nSrc-2].pUsing = yymsp[0].minor.yy160; }
++      else { sqlite3IdListDelete(yymsp[0].minor.yy160); }
+     }
+   }
+-#line 2422 "parse.c"
++#line 2303 "parse.c"
+         break;
+-      case 127:
+-#line 489 "parse.y"
++      case 129:
++#line 486 "parse.y"
+ {
+-     yygotominor.yy375 = sqlite3SelectNew(0,yymsp[0].minor.yy151,0,0,0,0,0,0,0);
++     yygotominor.yy239 = sqlite3SelectNew(0,yymsp[0].minor.yy285,0,0,0,0,0,0,0);
+   }
+-#line 2429 "parse.c"
++#line 2310 "parse.c"
+         break;
+-      case 128:
+-#line 495 "parse.y"
+-{yygotominor.yy198.z=0; yygotominor.yy198.n=0;}
+-#line 2434 "parse.c"
+-        break;
+       case 130:
+-#line 500 "parse.y"
+-{yygotominor.yy151 = sqlite3SrcListAppend(0,&yymsp[-1].minor.yy198,&yymsp[0].minor.yy198);}
+-#line 2439 "parse.c"
++#line 492 "parse.y"
++{yygotominor.yy384.z=0; yygotominor.yy384.n=0;}
++#line 2315 "parse.c"
+         break;
+-      case 131:
+       case 132:
+-#line 504 "parse.y"
+-{ yygotominor.yy280 = JT_INNER; }
+-#line 2445 "parse.c"
++#line 497 "parse.y"
++{yygotominor.yy285 = sqlite3SrcListAppend(0,&yymsp[-1].minor.yy384,&yymsp[0].minor.yy384);}
++#line 2320 "parse.c"
+         break;
+       case 133:
+-#line 506 "parse.y"
+-{ yygotominor.yy280 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); }
+-#line 2450 "parse.c"
++#line 501 "parse.y"
++{ yygotominor.yy230 = JT_INNER; }
++#line 2325 "parse.c"
+         break;
+       case 134:
+-#line 507 "parse.y"
+-{ yygotominor.yy280 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy198,0); }
+-#line 2455 "parse.c"
++#line 502 "parse.y"
++{ yygotominor.yy230 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); }
++#line 2330 "parse.c"
+         break;
+       case 135:
+-#line 509 "parse.y"
+-{ yygotominor.yy280 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy198,&yymsp[-1].minor.yy198); }
+-#line 2460 "parse.c"
++#line 503 "parse.y"
++{ yygotominor.yy230 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy384,0); }
++#line 2335 "parse.c"
+         break;
+       case 136:
+-      case 144:
+-      case 153:
+-      case 160:
+-      case 174:
+-      case 211:
+-      case 236:
+-      case 238:
+-      case 242:
+-#line 513 "parse.y"
+-{yygotominor.yy62 = yymsp[0].minor.yy62;}
+-#line 2473 "parse.c"
++#line 505 "parse.y"
++{ yygotominor.yy230 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy384,&yymsp[-1].minor.yy384); }
++#line 2340 "parse.c"
+         break;
+       case 137:
+-      case 152:
+-      case 159:
+-      case 212:
+-      case 237:
+-      case 239:
+-      case 243:
+-#line 514 "parse.y"
+-{yygotominor.yy62 = 0;}
+-#line 2484 "parse.c"
++      case 145:
++      case 154:
++      case 161:
++      case 175:
++      case 200:
++      case 223:
++      case 225:
++      case 229:
++#line 509 "parse.y"
++{yygotominor.yy178 = yymsp[0].minor.yy178;}
++#line 2353 "parse.c"
+         break;
+       case 138:
+-      case 171:
+-#line 518 "parse.y"
+-{yygotominor.yy240 = yymsp[-1].minor.yy240;}
+-#line 2490 "parse.c"
++      case 153:
++      case 160:
++      case 201:
++      case 224:
++      case 226:
++      case 230:
++#line 510 "parse.y"
++{yygotominor.yy178 = 0;}
++#line 2364 "parse.c"
+         break;
+       case 139:
+-      case 170:
+-#line 519 "parse.y"
+-{yygotominor.yy240 = 0;}
+-#line 2496 "parse.c"
++      case 172:
++#line 514 "parse.y"
++{yygotominor.yy160 = yymsp[-1].minor.yy160;}
++#line 2370 "parse.c"
+         break;
+-      case 141:
+-      case 151:
+-#line 530 "parse.y"
+-{yygotominor.yy418 = yymsp[0].minor.yy418;}
+-#line 2502 "parse.c"
++      case 140:
++      case 171:
++#line 515 "parse.y"
++{yygotominor.yy160 = 0;}
++#line 2376 "parse.c"
+         break;
+       case 142:
+-#line 531 "parse.y"
++      case 152:
++#line 526 "parse.y"
++{yygotominor.yy462 = yymsp[0].minor.yy462;}
++#line 2382 "parse.c"
++        break;
++      case 143:
++#line 527 "parse.y"
+ {
+-  yygotominor.yy418 = sqlite3ExprListAppend(yymsp[-4].minor.yy418,yymsp[-2].minor.yy62,yymsp[-1].minor.yy198.n>0?&yymsp[-1].minor.yy198:0);
+-  if( yygotominor.yy418 ) yygotominor.yy418->a[yygotominor.yy418->nExpr-1].sortOrder = yymsp[0].minor.yy280;
++  yygotominor.yy462 = sqlite3ExprListAppend(yymsp[-4].minor.yy462,yymsp[-2].minor.yy178,yymsp[-1].minor.yy384.n>0?&yymsp[-1].minor.yy384:0);
++  if( yygotominor.yy462 ) yygotominor.yy462->a[yygotominor.yy462->nExpr-1].sortOrder = yymsp[0].minor.yy230;
+ }
+-#line 2510 "parse.c"
++#line 2390 "parse.c"
+         break;
+-      case 143:
+-#line 535 "parse.y"
++      case 144:
++#line 531 "parse.y"
+ {
+-  yygotominor.yy418 = sqlite3ExprListAppend(0,yymsp[-2].minor.yy62,yymsp[-1].minor.yy198.n>0?&yymsp[-1].minor.yy198:0);
+-  if( yygotominor.yy418 && yygotominor.yy418->a ) yygotominor.yy418->a[0].sortOrder = yymsp[0].minor.yy280;
++  yygotominor.yy462 = sqlite3ExprListAppend(0,yymsp[-2].minor.yy178,yymsp[-1].minor.yy384.n>0?&yymsp[-1].minor.yy384:0);
++  if( yygotominor.yy462 && yygotominor.yy462->a ) yygotominor.yy462->a[0].sortOrder = yymsp[0].minor.yy230;
+ }
+-#line 2518 "parse.c"
++#line 2398 "parse.c"
+         break;
+-      case 145:
+-      case 147:
+-#line 544 "parse.y"
+-{yygotominor.yy280 = SQLITE_SO_ASC;}
+-#line 2524 "parse.c"
+-        break;
+       case 146:
+-#line 545 "parse.y"
+-{yygotominor.yy280 = SQLITE_SO_DESC;}
+-#line 2529 "parse.c"
+-        break;
+       case 148:
+-#line 547 "parse.y"
+-{yygotominor.yy198.z = 0; yygotominor.yy198.n = 0;}
+-#line 2534 "parse.c"
++#line 540 "parse.y"
++{yygotominor.yy230 = SQLITE_SO_ASC;}
++#line 2404 "parse.c"
+         break;
+-      case 154:
+-#line 565 "parse.y"
+-{yygotominor.yy220.pLimit = 0; yygotominor.yy220.pOffset = 0;}
+-#line 2539 "parse.c"
++      case 147:
++#line 541 "parse.y"
++{yygotominor.yy230 = SQLITE_SO_DESC;}
++#line 2409 "parse.c"
+         break;
++      case 149:
++#line 543 "parse.y"
++{yygotominor.yy384.z = 0; yygotominor.yy384.n = 0;}
++#line 2414 "parse.c"
++        break;
+       case 155:
+-#line 566 "parse.y"
+-{yygotominor.yy220.pLimit = yymsp[0].minor.yy62; yygotominor.yy220.pOffset = 0;}
+-#line 2544 "parse.c"
++#line 561 "parse.y"
++{yygotominor.yy270.pLimit = 0; yygotominor.yy270.pOffset = 0;}
++#line 2419 "parse.c"
+         break;
+       case 156:
+-#line 568 "parse.y"
+-{yygotominor.yy220.pLimit = yymsp[-2].minor.yy62; yygotominor.yy220.pOffset = yymsp[0].minor.yy62;}
+-#line 2549 "parse.c"
++#line 562 "parse.y"
++{yygotominor.yy270.pLimit = yymsp[0].minor.yy178; yygotominor.yy270.pOffset = 0;}
++#line 2424 "parse.c"
+         break;
+       case 157:
+-#line 570 "parse.y"
+-{yygotominor.yy220.pOffset = yymsp[-2].minor.yy62; yygotominor.yy220.pLimit = yymsp[0].minor.yy62;}
+-#line 2554 "parse.c"
++#line 564 "parse.y"
++{yygotominor.yy270.pLimit = yymsp[-2].minor.yy178; yygotominor.yy270.pOffset = yymsp[0].minor.yy178;}
++#line 2429 "parse.c"
+         break;
+       case 158:
+-#line 574 "parse.y"
+-{sqlite3DeleteFrom(pParse,yymsp[-1].minor.yy151,yymsp[0].minor.yy62);}
+-#line 2559 "parse.c"
++#line 566 "parse.y"
++{yygotominor.yy270.pOffset = yymsp[-2].minor.yy178; yygotominor.yy270.pLimit = yymsp[0].minor.yy178;}
++#line 2434 "parse.c"
+         break;
+-      case 161:
+-#line 585 "parse.y"
+-{sqlite3Update(pParse,yymsp[-3].minor.yy151,yymsp[-1].minor.yy418,yymsp[0].minor.yy62,yymsp[-4].minor.yy280);}
+-#line 2564 "parse.c"
++      case 159:
++#line 570 "parse.y"
++{sqlite3DeleteFrom(pParse,yymsp[-1].minor.yy285,yymsp[0].minor.yy178);}
++#line 2439 "parse.c"
+         break;
+       case 162:
+-#line 591 "parse.y"
+-{yygotominor.yy418 = sqlite3ExprListAppend(yymsp[-4].minor.yy418,yymsp[0].minor.yy62,&yymsp[-2].minor.yy198);}
+-#line 2569 "parse.c"
++#line 581 "parse.y"
++{sqlite3Update(pParse,yymsp[-3].minor.yy285,yymsp[-1].minor.yy462,yymsp[0].minor.yy178,yymsp[-4].minor.yy230);}
++#line 2444 "parse.c"
+         break;
+       case 163:
+-#line 592 "parse.y"
+-{yygotominor.yy418 = sqlite3ExprListAppend(0,yymsp[0].minor.yy62,&yymsp[-2].minor.yy198);}
+-#line 2574 "parse.c"
++#line 587 "parse.y"
++{yygotominor.yy462 = sqlite3ExprListAppend(yymsp[-4].minor.yy462,yymsp[0].minor.yy178,&yymsp[-2].minor.yy384);}
++#line 2449 "parse.c"
+         break;
+       case 164:
+-#line 598 "parse.y"
+-{sqlite3Insert(pParse, yymsp[-5].minor.yy151, yymsp[-1].minor.yy418, 0, yymsp[-4].minor.yy240, yymsp[-7].minor.yy280);}
+-#line 2579 "parse.c"
++#line 588 "parse.y"
++{yygotominor.yy462 = sqlite3ExprListAppend(0,yymsp[0].minor.yy178,&yymsp[-2].minor.yy384);}
++#line 2454 "parse.c"
+         break;
+       case 165:
+-#line 600 "parse.y"
+-{sqlite3Insert(pParse, yymsp[-2].minor.yy151, 0, yymsp[0].minor.yy375, yymsp[-1].minor.yy240, yymsp[-4].minor.yy280);}
+-#line 2584 "parse.c"
++#line 594 "parse.y"
++{sqlite3Insert(pParse, yymsp[-5].minor.yy285, yymsp[-1].minor.yy462, 0, yymsp[-4].minor.yy160, yymsp[-7].minor.yy230);}
++#line 2459 "parse.c"
+         break;
+-      case 168:
+-      case 240:
+-#line 610 "parse.y"
+-{yygotominor.yy418 = sqlite3ExprListAppend(yymsp[-2].minor.yy418,yymsp[0].minor.yy62,0);}
+-#line 2590 "parse.c"
++      case 166:
++#line 596 "parse.y"
++{sqlite3Insert(pParse, yymsp[-2].minor.yy285, 0, yymsp[0].minor.yy239, yymsp[-1].minor.yy160, yymsp[-4].minor.yy230);}
++#line 2464 "parse.c"
+         break;
+       case 169:
+-      case 241:
+-#line 611 "parse.y"
+-{yygotominor.yy418 = sqlite3ExprListAppend(0,yymsp[0].minor.yy62,0);}
+-#line 2596 "parse.c"
++      case 227:
++#line 606 "parse.y"
++{yygotominor.yy462 = sqlite3ExprListAppend(yymsp[-2].minor.yy462,yymsp[0].minor.yy178,0);}
++#line 2470 "parse.c"
+         break;
+-      case 172:
+-#line 620 "parse.y"
+-{yygotominor.yy240 = sqlite3IdListAppend(yymsp[-2].minor.yy240,&yymsp[0].minor.yy198);}
+-#line 2601 "parse.c"
++      case 170:
++      case 228:
++#line 607 "parse.y"
++{yygotominor.yy462 = sqlite3ExprListAppend(0,yymsp[0].minor.yy178,0);}
++#line 2476 "parse.c"
+         break;
+       case 173:
+-#line 621 "parse.y"
+-{yygotominor.yy240 = sqlite3IdListAppend(0,&yymsp[0].minor.yy198);}
+-#line 2606 "parse.c"
++#line 616 "parse.y"
++{yygotominor.yy160 = sqlite3IdListAppend(yymsp[-2].minor.yy160,&yymsp[0].minor.yy384);}
++#line 2481 "parse.c"
+         break;
+-      case 175:
+-#line 632 "parse.y"
+-{yygotominor.yy62 = yymsp[-1].minor.yy62; sqlite3ExprSpan(yygotominor.yy62,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); }
+-#line 2611 "parse.c"
++      case 174:
++#line 617 "parse.y"
++{yygotominor.yy160 = sqlite3IdListAppend(0,&yymsp[0].minor.yy384);}
++#line 2486 "parse.c"
+         break;
+       case 176:
+-      case 181:
++#line 628 "parse.y"
++{yygotominor.yy178 = yymsp[-1].minor.yy178; sqlite3ExprSpan(yygotominor.yy178,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); }
++#line 2491 "parse.c"
++        break;
++      case 177:
+       case 182:
+       case 183:
+-      case 184:
+-#line 633 "parse.y"
+-{yygotominor.yy62 = sqlite3Expr(yymsp[0].major, 0, 0, &yymsp[0].minor.yy0);}
+-#line 2620 "parse.c"
++#line 629 "parse.y"
++{yygotominor.yy178 = sqlite3Expr(yymsp[0].major, 0, 0, &yymsp[0].minor.yy0);}
++#line 2498 "parse.c"
+         break;
+-      case 177:
+       case 178:
+-#line 634 "parse.y"
+-{yygotominor.yy62 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy0);}
+-#line 2626 "parse.c"
+-        break;
+       case 179:
+-#line 636 "parse.y"
++#line 630 "parse.y"
++{yygotominor.yy178 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy0);}
++#line 2504 "parse.c"
++        break;
++      case 180:
++#line 632 "parse.y"
+ {
+-  Expr *temp1 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy198);
+-  Expr *temp2 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy198);
+-  yygotominor.yy62 = sqlite3Expr(TK_DOT, temp1, temp2, 0);
++  Expr *temp1 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy384);
++  Expr *temp2 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy384);
++  yygotominor.yy178 = sqlite3Expr(TK_DOT, temp1, temp2, 0);
+ }
+-#line 2635 "parse.c"
++#line 2513 "parse.c"
+         break;
+-      case 180:
+-#line 641 "parse.y"
++      case 181:
++#line 637 "parse.y"
+ {
+-  Expr *temp1 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-4].minor.yy198);
+-  Expr *temp2 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy198);
+-  Expr *temp3 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy198);
++  Expr *temp1 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-4].minor.yy384);
++  Expr *temp2 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy384);
++  Expr *temp3 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy384);
+   Expr *temp4 = sqlite3Expr(TK_DOT, temp2, temp3, 0);
+-  yygotominor.yy62 = sqlite3Expr(TK_DOT, temp1, temp4, 0);
++  yygotominor.yy178 = sqlite3Expr(TK_DOT, temp1, temp4, 0);
+ }
+-#line 2646 "parse.c"
++#line 2524 "parse.c"
+         break;
++      case 184:
++#line 646 "parse.y"
++{yygotominor.yy178 = sqlite3RegisterExpr(pParse, &yymsp[0].minor.yy0);}
++#line 2529 "parse.c"
++        break;
+       case 185:
+-#line 652 "parse.y"
+-{yygotominor.yy62 = sqlite3RegisterExpr(pParse, &yymsp[0].minor.yy0);}
+-#line 2651 "parse.c"
++#line 647 "parse.y"
++{
++  Token *pToken = &yymsp[0].minor.yy0;
++  Expr *pExpr = yygotominor.yy178 = sqlite3Expr(TK_VARIABLE, 0, 0, pToken);
++  sqlite3ExprAssignVarNumber(pParse, pExpr);
++}
++#line 2538 "parse.c"
+         break;
+       case 186:
+ #line 653 "parse.y"
+ {
+-  Token *pToken = &yymsp[0].minor.yy0;
+-  Expr *pExpr = yygotominor.yy62 = sqlite3Expr(TK_VARIABLE, 0, 0, pToken);
+-  sqlite3ExprAssignVarNumber(pParse, pExpr);
++  yygotominor.yy178 = sqlite3Expr(TK_CAST, yymsp[-3].minor.yy178, 0, &yymsp[-1].minor.yy384);
++  sqlite3ExprSpan(yygotominor.yy178,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0);
+ }
+-#line 2660 "parse.c"
++#line 2546 "parse.c"
+         break;
+       case 187:
+-#line 659 "parse.y"
++#line 658 "parse.y"
+ {
+-  yygotominor.yy62 = sqlite3Expr(TK_CAST, yymsp[-3].minor.yy62, 0, &yymsp[-1].minor.yy198);
+-  sqlite3ExprSpan(yygotominor.yy62,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0);
++  yygotominor.yy178 = sqlite3ExprFunction(yymsp[-1].minor.yy462, &yymsp[-4].minor.yy0);
++  sqlite3ExprSpan(yygotominor.yy178,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0);
++  if( yymsp[-2].minor.yy230 ){
++    yygotominor.yy178->flags |= EP_Distinct;
++  }
+ }
+-#line 2668 "parse.c"
++#line 2557 "parse.c"
+         break;
+       case 188:
+-#line 664 "parse.y"
++#line 665 "parse.y"
+ {
+-  yygotominor.yy62 = sqlite3ExprFunction(yymsp[-1].minor.yy418, &yymsp[-4].minor.yy0);
+-  sqlite3ExprSpan(yygotominor.yy62,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0);
+-  if( yymsp[-2].minor.yy280 ){
+-    yygotominor.yy62->flags |= EP_Distinct;
+-  }
++  yygotominor.yy178 = sqlite3ExprFunction(0, &yymsp[-3].minor.yy0);
++  sqlite3ExprSpan(yygotominor.yy178,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0);
+ }
+-#line 2679 "parse.c"
++#line 2565 "parse.c"
+         break;
+       case 189:
+-#line 671 "parse.y"
++#line 669 "parse.y"
+ {
+-  yygotominor.yy62 = sqlite3ExprFunction(0, &yymsp[-3].minor.yy0);
+-  sqlite3ExprSpan(yygotominor.yy62,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0);
+-}
+-#line 2687 "parse.c"
+-        break;
+-      case 190:
+-#line 675 "parse.y"
+-{
+   /* The CURRENT_TIME, CURRENT_DATE, and CURRENT_TIMESTAMP values are
+   ** treated as functions that return constants */
+-  yygotominor.yy62 = sqlite3ExprFunction(0,&yymsp[0].minor.yy0);
+-  if( yygotominor.yy62 ) yygotominor.yy62->op = TK_CONST_FUNC;  
++  yygotominor.yy178 = sqlite3ExprFunction(0,&yymsp[0].minor.yy0);
++  if( yygotominor.yy178 ) yygotominor.yy178->op = TK_CONST_FUNC;  
+ }
+-#line 2697 "parse.c"
++#line 2575 "parse.c"
+         break;
++      case 190:
+       case 191:
+       case 192:
+       case 193:
+@@ -2701,516 +2580,491 @@
+       case 195:
+       case 196:
+       case 197:
++#line 675 "parse.y"
++{yygotominor.yy178 = sqlite3Expr(yymsp[-1].major, yymsp[-2].minor.yy178, yymsp[0].minor.yy178, 0);}
++#line 2587 "parse.c"
++        break;
+       case 198:
++#line 685 "parse.y"
++{yygotominor.yy440.eOperator = yymsp[0].minor.yy0; yygotominor.yy440.not = 0;}
++#line 2592 "parse.c"
++        break;
+       case 199:
+-      case 200:
+-      case 201:
+-      case 202:
+-      case 203:
+-      case 204:
+-      case 205:
+-      case 206:
+-      case 207:
+-      case 208:
+-#line 681 "parse.y"
+-{yygotominor.yy62 = sqlite3Expr(yymsp[-1].major, yymsp[-2].minor.yy62, yymsp[0].minor.yy62, 0);}
+-#line 2719 "parse.c"
++#line 686 "parse.y"
++{yygotominor.yy440.eOperator = yymsp[0].minor.yy0; yygotominor.yy440.not = 1;}
++#line 2597 "parse.c"
+         break;
+-      case 209:
+-#line 700 "parse.y"
+-{yygotominor.yy222.operator = yymsp[0].minor.yy0; yygotominor.yy222.not = 0;}
+-#line 2724 "parse.c"
+-        break;
+-      case 210:
+-#line 701 "parse.y"
+-{yygotominor.yy222.operator = yymsp[0].minor.yy0; yygotominor.yy222.not = 1;}
+-#line 2729 "parse.c"
+-        break;
+-      case 213:
+-#line 705 "parse.y"
++      case 202:
++#line 691 "parse.y"
+ {
+-  ExprList *pList = sqlite3ExprListAppend(0, yymsp[-1].minor.yy62, 0);
+-  pList = sqlite3ExprListAppend(pList, yymsp[-3].minor.yy62, 0);
+-  if( yymsp[0].minor.yy62 ){
+-    pList = sqlite3ExprListAppend(pList, yymsp[0].minor.yy62, 0);
++  ExprList *pList = sqlite3ExprListAppend(0, yymsp[-1].minor.yy178, 0);
++  pList = sqlite3ExprListAppend(pList, yymsp[-3].minor.yy178, 0);
++  if( yymsp[0].minor.yy178 ){
++    pList = sqlite3ExprListAppend(pList, yymsp[0].minor.yy178, 0);
+   }
+-  yygotominor.yy62 = sqlite3ExprFunction(pList, &yymsp[-2].minor.yy222.operator);
+-  if( yymsp[-2].minor.yy222.not ) yygotominor.yy62 = sqlite3Expr(TK_NOT, yygotominor.yy62, 0, 0);
+-  sqlite3ExprSpan(yygotominor.yy62, &yymsp[-3].minor.yy62->span, &yymsp[-1].minor.yy62->span);
++  yygotominor.yy178 = sqlite3ExprFunction(pList, &yymsp[-2].minor.yy440.eOperator);
++  if( yymsp[-2].minor.yy440.not ) yygotominor.yy178 = sqlite3Expr(TK_NOT, yygotominor.yy178, 0, 0);
++  sqlite3ExprSpan(yygotominor.yy178, &yymsp[-3].minor.yy178->span, &yymsp[-1].minor.yy178->span);
+ }
+-#line 2743 "parse.c"
++#line 2611 "parse.c"
+         break;
+-      case 214:
+-#line 716 "parse.y"
++      case 203:
++#line 702 "parse.y"
+ {
+-  yygotominor.yy62 = sqlite3Expr(TK_ISNULL, yymsp[-1].minor.yy62, 0, 0);
+-  sqlite3ExprSpan(yygotominor.yy62,&yymsp[-1].minor.yy62->span,&yymsp[0].minor.yy0);
++  yygotominor.yy178 = sqlite3Expr(yymsp[0].major, yymsp[-1].minor.yy178, 0, 0);
++  sqlite3ExprSpan(yygotominor.yy178,&yymsp[-1].minor.yy178->span,&yymsp[0].minor.yy0);
+ }
+-#line 2751 "parse.c"
++#line 2619 "parse.c"
+         break;
+-      case 215:
+-#line 720 "parse.y"
++      case 204:
++#line 706 "parse.y"
+ {
+-  yygotominor.yy62 = sqlite3Expr(TK_ISNULL, yymsp[-2].minor.yy62, 0, 0);
+-  sqlite3ExprSpan(yygotominor.yy62,&yymsp[-2].minor.yy62->span,&yymsp[0].minor.yy0);
++  yygotominor.yy178 = sqlite3Expr(TK_ISNULL, yymsp[-2].minor.yy178, 0, 0);
++  sqlite3ExprSpan(yygotominor.yy178,&yymsp[-2].minor.yy178->span,&yymsp[0].minor.yy0);
+ }
+-#line 2759 "parse.c"
++#line 2627 "parse.c"
+         break;
+-      case 216:
+-#line 724 "parse.y"
++      case 205:
++#line 710 "parse.y"
+ {
+-  yygotominor.yy62 = sqlite3Expr(TK_NOTNULL, yymsp[-1].minor.yy62, 0, 0);
+-  sqlite3ExprSpan(yygotominor.yy62,&yymsp[-1].minor.yy62->span,&yymsp[0].minor.yy0);
++  yygotominor.yy178 = sqlite3Expr(TK_NOTNULL, yymsp[-2].minor.yy178, 0, 0);
++  sqlite3ExprSpan(yygotominor.yy178,&yymsp[-2].minor.yy178->span,&yymsp[0].minor.yy0);
+ }
+-#line 2767 "parse.c"
++#line 2635 "parse.c"
+         break;
+-      case 217:
+-#line 728 "parse.y"
++      case 206:
++#line 714 "parse.y"
+ {
+-  yygotominor.yy62 = sqlite3Expr(TK_NOTNULL, yymsp[-2].minor.yy62, 0, 0);
+-  sqlite3ExprSpan(yygotominor.yy62,&yymsp[-2].minor.yy62->span,&yymsp[0].minor.yy0);
++  yygotominor.yy178 = sqlite3Expr(TK_NOTNULL, yymsp[-3].minor.yy178, 0, 0);
++  sqlite3ExprSpan(yygotominor.yy178,&yymsp[-3].minor.yy178->span,&yymsp[0].minor.yy0);
+ }
+-#line 2775 "parse.c"
++#line 2643 "parse.c"
+         break;
+-      case 218:
+-#line 732 "parse.y"
++      case 207:
++#line 718 "parse.y"
+ {
+-  yygotominor.yy62 = sqlite3Expr(TK_NOTNULL, yymsp[-3].minor.yy62, 0, 0);
+-  sqlite3ExprSpan(yygotominor.yy62,&yymsp[-3].minor.yy62->span,&yymsp[0].minor.yy0);
++  yygotominor.yy178 = sqlite3Expr(yymsp[-1].major, yymsp[0].minor.yy178, 0, 0);
++  sqlite3ExprSpan(yygotominor.yy178,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy178->span);
+ }
+-#line 2783 "parse.c"
++#line 2651 "parse.c"
+         break;
+-      case 219:
+-      case 220:
+-#line 736 "parse.y"
++      case 208:
++#line 722 "parse.y"
+ {
+-  yygotominor.yy62 = sqlite3Expr(yymsp[-1].major, yymsp[0].minor.yy62, 0, 0);
+-  sqlite3ExprSpan(yygotominor.yy62,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy62->span);
++  yygotominor.yy178 = sqlite3Expr(TK_UMINUS, yymsp[0].minor.yy178, 0, 0);
++  sqlite3ExprSpan(yygotominor.yy178,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy178->span);
+ }
+-#line 2792 "parse.c"
++#line 2659 "parse.c"
+         break;
+-      case 221:
+-#line 744 "parse.y"
++      case 209:
++#line 726 "parse.y"
+ {
+-  yygotominor.yy62 = sqlite3Expr(TK_UMINUS, yymsp[0].minor.yy62, 0, 0);
+-  sqlite3ExprSpan(yygotominor.yy62,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy62->span);
++  yygotominor.yy178 = sqlite3Expr(TK_UPLUS, yymsp[0].minor.yy178, 0, 0);
++  sqlite3ExprSpan(yygotominor.yy178,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy178->span);
+ }
+-#line 2800 "parse.c"
++#line 2667 "parse.c"
+         break;
+-      case 222:
+-#line 748 "parse.y"
++      case 212:
++#line 733 "parse.y"
+ {
+-  yygotominor.yy62 = sqlite3Expr(TK_UPLUS, yymsp[0].minor.yy62, 0, 0);
+-  sqlite3ExprSpan(yygotominor.yy62,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy62->span);
+-}
+-#line 2808 "parse.c"
+-        break;
+-      case 225:
+-#line 755 "parse.y"
+-{
+-  ExprList *pList = sqlite3ExprListAppend(0, yymsp[-2].minor.yy62, 0);
+-  pList = sqlite3ExprListAppend(pList, yymsp[0].minor.yy62, 0);
+-  yygotominor.yy62 = sqlite3Expr(TK_BETWEEN, yymsp[-4].minor.yy62, 0, 0);
+-  if( yygotominor.yy62 ){
+-    yygotominor.yy62->pList = pList;
++  ExprList *pList = sqlite3ExprListAppend(0, yymsp[-2].minor.yy178, 0);
++  pList = sqlite3ExprListAppend(pList, yymsp[0].minor.yy178, 0);
++  yygotominor.yy178 = sqlite3Expr(TK_BETWEEN, yymsp[-4].minor.yy178, 0, 0);
++  if( yygotominor.yy178 ){
++    yygotominor.yy178->pList = pList;
+   }else{
+     sqlite3ExprListDelete(pList);
+   } 
+-  if( yymsp[-3].minor.yy280 ) yygotominor.yy62 = sqlite3Expr(TK_NOT, yygotominor.yy62, 0, 0);
+-  sqlite3ExprSpan(yygotominor.yy62,&yymsp[-4].minor.yy62->span,&yymsp[0].minor.yy62->span);
++  if( yymsp[-3].minor.yy230 ) yygotominor.yy178 = sqlite3Expr(TK_NOT, yygotominor.yy178, 0, 0);
++  sqlite3ExprSpan(yygotominor.yy178,&yymsp[-4].minor.yy178->span,&yymsp[0].minor.yy178->span);
+ }
+-#line 2824 "parse.c"
++#line 2683 "parse.c"
+         break;
+-      case 228:
+-#line 771 "parse.y"
++      case 215:
++#line 749 "parse.y"
+ {
+-    yygotominor.yy62 = sqlite3Expr(TK_IN, yymsp[-4].minor.yy62, 0, 0);
+-    if( yygotominor.yy62 ){
+-      yygotominor.yy62->pList = yymsp[-1].minor.yy418;
++    yygotominor.yy178 = sqlite3Expr(TK_IN, yymsp[-4].minor.yy178, 0, 0);
++    if( yygotominor.yy178 ){
++      yygotominor.yy178->pList = yymsp[-1].minor.yy462;
+     }else{
+-      sqlite3ExprListDelete(yymsp[-1].minor.yy418);
++      sqlite3ExprListDelete(yymsp[-1].minor.yy462);
+     }
+-    if( yymsp[-3].minor.yy280 ) yygotominor.yy62 = sqlite3Expr(TK_NOT, yygotominor.yy62, 0, 0);
+-    sqlite3ExprSpan(yygotominor.yy62,&yymsp[-4].minor.yy62->span,&yymsp[0].minor.yy0);
++    if( yymsp[-3].minor.yy230 ) yygotominor.yy178 = sqlite3Expr(TK_NOT, yygotominor.yy178, 0, 0);
++    sqlite3ExprSpan(yygotominor.yy178,&yymsp[-4].minor.yy178->span,&yymsp[0].minor.yy0);
+   }
+-#line 2838 "parse.c"
++#line 2697 "parse.c"
+         break;
+-      case 229:
+-#line 781 "parse.y"
++      case 216:
++#line 759 "parse.y"
+ {
+-    yygotominor.yy62 = sqlite3Expr(TK_SELECT, 0, 0, 0);
+-    if( yygotominor.yy62 ){
+-      yygotominor.yy62->pSelect = yymsp[-1].minor.yy375;
++    yygotominor.yy178 = sqlite3Expr(TK_SELECT, 0, 0, 0);
++    if( yygotominor.yy178 ){
++      yygotominor.yy178->pSelect = yymsp[-1].minor.yy239;
+     }else{
+-      sqlite3SelectDelete(yymsp[-1].minor.yy375);
++      sqlite3SelectDelete(yymsp[-1].minor.yy239);
+     }
+-    sqlite3ExprSpan(yygotominor.yy62,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);
++    sqlite3ExprSpan(yygotominor.yy178,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);
+   }
+-#line 2851 "parse.c"
++#line 2710 "parse.c"
+         break;
+-      case 230:
+-#line 790 "parse.y"
++      case 217:
++#line 768 "parse.y"
+ {
+-    yygotominor.yy62 = sqlite3Expr(TK_IN, yymsp[-4].minor.yy62, 0, 0);
+-    if( yygotominor.yy62 ){
+-      yygotominor.yy62->pSelect = yymsp[-1].minor.yy375;
++    yygotominor.yy178 = sqlite3Expr(TK_IN, yymsp[-4].minor.yy178, 0, 0);
++    if( yygotominor.yy178 ){
++      yygotominor.yy178->pSelect = yymsp[-1].minor.yy239;
+     }else{
+-      sqlite3SelectDelete(yymsp[-1].minor.yy375);
++      sqlite3SelectDelete(yymsp[-1].minor.yy239);
+     }
+-    if( yymsp[-3].minor.yy280 ) yygotominor.yy62 = sqlite3Expr(TK_NOT, yygotominor.yy62, 0, 0);
+-    sqlite3ExprSpan(yygotominor.yy62,&yymsp[-4].minor.yy62->span,&yymsp[0].minor.yy0);
++    if( yymsp[-3].minor.yy230 ) yygotominor.yy178 = sqlite3Expr(TK_NOT, yygotominor.yy178, 0, 0);
++    sqlite3ExprSpan(yygotominor.yy178,&yymsp[-4].minor.yy178->span,&yymsp[0].minor.yy0);
+   }
+-#line 2865 "parse.c"
++#line 2724 "parse.c"
+         break;
+-      case 231:
+-#line 800 "parse.y"
++      case 218:
++#line 778 "parse.y"
+ {
+-    SrcList *pSrc = sqlite3SrcListAppend(0,&yymsp[-1].minor.yy198,&yymsp[0].minor.yy198);
+-    yygotominor.yy62 = sqlite3Expr(TK_IN, yymsp[-3].minor.yy62, 0, 0);
+-    if( yygotominor.yy62 ){
+-      yygotominor.yy62->pSelect = sqlite3SelectNew(0,pSrc,0,0,0,0,0,0,0);
++    SrcList *pSrc = sqlite3SrcListAppend(0,&yymsp[-1].minor.yy384,&yymsp[0].minor.yy384);
++    yygotominor.yy178 = sqlite3Expr(TK_IN, yymsp[-3].minor.yy178, 0, 0);
++    if( yygotominor.yy178 ){
++      yygotominor.yy178->pSelect = sqlite3SelectNew(0,pSrc,0,0,0,0,0,0,0);
+     }else{
+       sqlite3SrcListDelete(pSrc);
+     }
+-    if( yymsp[-2].minor.yy280 ) yygotominor.yy62 = sqlite3Expr(TK_NOT, yygotominor.yy62, 0, 0);
+-    sqlite3ExprSpan(yygotominor.yy62,&yymsp[-3].minor.yy62->span,yymsp[0].minor.yy198.z?&yymsp[0].minor.yy198:&yymsp[-1].minor.yy198);
++    if( yymsp[-2].minor.yy230 ) yygotominor.yy178 = sqlite3Expr(TK_NOT, yygotominor.yy178, 0, 0);
++    sqlite3ExprSpan(yygotominor.yy178,&yymsp[-3].minor.yy178->span,yymsp[0].minor.yy384.z?&yymsp[0].minor.yy384:&yymsp[-1].minor.yy384);
+   }
+-#line 2880 "parse.c"
++#line 2739 "parse.c"
+         break;
+-      case 232:
+-#line 811 "parse.y"
++      case 219:
++#line 789 "parse.y"
+ {
+-    Expr *p = yygotominor.yy62 = sqlite3Expr(TK_EXISTS, 0, 0, 0);
++    Expr *p = yygotominor.yy178 = sqlite3Expr(TK_EXISTS, 0, 0, 0);
+     if( p ){
+-      p->pSelect = yymsp[-1].minor.yy375;
++      p->pSelect = yymsp[-1].minor.yy239;
+       sqlite3ExprSpan(p,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0);
+     }else{
+-      sqlite3SelectDelete(yymsp[-1].minor.yy375);
++      sqlite3SelectDelete(yymsp[-1].minor.yy239);
+     }
+   }
+-#line 2893 "parse.c"
++#line 2752 "parse.c"
+         break;
+-      case 233:
+-#line 823 "parse.y"
++      case 220:
++#line 801 "parse.y"
+ {
+-  yygotominor.yy62 = sqlite3Expr(TK_CASE, yymsp[-3].minor.yy62, yymsp[-1].minor.yy62, 0);
+-  if( yygotominor.yy62 ){
+-    yygotominor.yy62->pList = yymsp[-2].minor.yy418;
++  yygotominor.yy178 = sqlite3Expr(TK_CASE, yymsp[-3].minor.yy178, yymsp[-1].minor.yy178, 0);
++  if( yygotominor.yy178 ){
++    yygotominor.yy178->pList = yymsp[-2].minor.yy462;
+   }else{
+-    sqlite3ExprListDelete(yymsp[-2].minor.yy418);
++    sqlite3ExprListDelete(yymsp[-2].minor.yy462);
+   }
+-  sqlite3ExprSpan(yygotominor.yy62, &yymsp[-4].minor.yy0, &yymsp[0].minor.yy0);
++  sqlite3ExprSpan(yygotominor.yy178, &yymsp[-4].minor.yy0, &yymsp[0].minor.yy0);
+ }
+-#line 2906 "parse.c"
++#line 2765 "parse.c"
+         break;
+-      case 234:
+-#line 834 "parse.y"
++      case 221:
++#line 812 "parse.y"
+ {
+-  yygotominor.yy418 = sqlite3ExprListAppend(yymsp[-4].minor.yy418, yymsp[-2].minor.yy62, 0);
+-  yygotominor.yy418 = sqlite3ExprListAppend(yygotominor.yy418, yymsp[0].minor.yy62, 0);
++  yygotominor.yy462 = sqlite3ExprListAppend(yymsp[-4].minor.yy462, yymsp[-2].minor.yy178, 0);
++  yygotominor.yy462 = sqlite3ExprListAppend(yygotominor.yy462, yymsp[0].minor.yy178, 0);
+ }
+-#line 2914 "parse.c"
++#line 2773 "parse.c"
+         break;
+-      case 235:
+-#line 838 "parse.y"
++      case 222:
++#line 816 "parse.y"
+ {
+-  yygotominor.yy418 = sqlite3ExprListAppend(0, yymsp[-2].minor.yy62, 0);
+-  yygotominor.yy418 = sqlite3ExprListAppend(yygotominor.yy418, yymsp[0].minor.yy62, 0);
++  yygotominor.yy462 = sqlite3ExprListAppend(0, yymsp[-2].minor.yy178, 0);
++  yygotominor.yy462 = sqlite3ExprListAppend(yygotominor.yy462, yymsp[0].minor.yy178, 0);
+ }
+-#line 2922 "parse.c"
++#line 2781 "parse.c"
+         break;
+-      case 244:
+-#line 863 "parse.y"
++      case 231:
++#line 843 "parse.y"
+ {
+-  if( yymsp[-9].minor.yy280!=OE_None ) yymsp[-9].minor.yy280 = yymsp[0].minor.yy280;
+-  if( yymsp[-9].minor.yy280==OE_Default) yymsp[-9].minor.yy280 = OE_Abort;
+-  sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy198, &yymsp[-6].minor.yy198, sqlite3SrcListAppend(0,&yymsp[-4].minor.yy198,0),yymsp[-2].minor.yy418,yymsp[-9].minor.yy280, &yymsp[-10].minor.yy0, &yymsp[-1].minor.yy0);
++  sqlite3CreateIndex(pParse, &yymsp[-6].minor.yy384, &yymsp[-5].minor.yy384, sqlite3SrcListAppend(0,&yymsp[-3].minor.yy384,0), yymsp[-1].minor.yy462, yymsp[-9].minor.yy230,
++                      &yymsp[-10].minor.yy0, &yymsp[0].minor.yy0, SQLITE_SO_ASC, yymsp[-7].minor.yy230);
+ }
+-#line 2931 "parse.c"
++#line 2789 "parse.c"
+         break;
+-      case 245:
+-      case 292:
+-#line 870 "parse.y"
+-{yygotominor.yy280 = OE_Abort;}
+-#line 2937 "parse.c"
++      case 232:
++      case 277:
++#line 849 "parse.y"
++{yygotominor.yy230 = OE_Abort;}
++#line 2795 "parse.c"
+         break;
+-      case 246:
+-#line 871 "parse.y"
+-{yygotominor.yy280 = OE_None;}
+-#line 2942 "parse.c"
++      case 233:
++#line 850 "parse.y"
++{yygotominor.yy230 = OE_None;}
++#line 2800 "parse.c"
+         break;
+-      case 249:
+-#line 881 "parse.y"
++      case 236:
++#line 860 "parse.y"
+ {
+   Expr *p = 0;
+-  if( yymsp[-1].minor.yy198.n>0 ){
++  if( yymsp[-1].minor.yy384.n>0 ){
+     p = sqlite3Expr(TK_COLUMN, 0, 0, 0);
+-    if( p ) p->pColl = sqlite3LocateCollSeq(pParse, yymsp[-1].minor.yy198.z, yymsp[-1].minor.yy198.n);
++    if( p ) p->pColl = sqlite3LocateCollSeq(pParse, (char*)yymsp[-1].minor.yy384.z, yymsp[-1].minor.yy384.n);
+   }
+-  yygotominor.yy418 = sqlite3ExprListAppend(yymsp[-4].minor.yy418, p, &yymsp[-2].minor.yy198);
++  yygotominor.yy462 = sqlite3ExprListAppend(yymsp[-4].minor.yy462, p, &yymsp[-2].minor.yy384);
++  if( yygotominor.yy462 ) yygotominor.yy462->a[yygotominor.yy462->nExpr-1].sortOrder = yymsp[0].minor.yy230;
+ }
+-#line 2954 "parse.c"
++#line 2813 "parse.c"
+         break;
+-      case 250:
+-#line 889 "parse.y"
++      case 237:
++#line 869 "parse.y"
+ {
+   Expr *p = 0;
+-  if( yymsp[-1].minor.yy198.n>0 ){
++  if( yymsp[-1].minor.yy384.n>0 ){
+     p = sqlite3Expr(TK_COLUMN, 0, 0, 0);
+-    if( p ) p->pColl = sqlite3LocateCollSeq(pParse, yymsp[-1].minor.yy198.z, yymsp[-1].minor.yy198.n);
++    if( p ) p->pColl = sqlite3LocateCollSeq(pParse, (char*)yymsp[-1].minor.yy384.z, yymsp[-1].minor.yy384.n);
+   }
+-  yygotominor.yy418 = sqlite3ExprListAppend(0, p, &yymsp[-2].minor.yy198);
++  yygotominor.yy462 = sqlite3ExprListAppend(0, p, &yymsp[-2].minor.yy384);
++  if( yygotominor.yy462 ) yygotominor.yy462->a[yygotominor.yy462->nExpr-1].sortOrder = yymsp[0].minor.yy230;
+ }
+-#line 2966 "parse.c"
++#line 2826 "parse.c"
+         break;
+-      case 252:
+-#line 902 "parse.y"
+-{sqlite3DropIndex(pParse, yymsp[0].minor.yy151);}
+-#line 2971 "parse.c"
++      case 239:
++#line 883 "parse.y"
++{sqlite3DropIndex(pParse, yymsp[0].minor.yy285, yymsp[-1].minor.yy230);}
++#line 2831 "parse.c"
+         break;
+-      case 253:
+-      case 254:
+-#line 906 "parse.y"
++      case 240:
++      case 241:
++#line 887 "parse.y"
+ {sqlite3Vacuum(pParse,0);}
+-#line 2977 "parse.c"
++#line 2837 "parse.c"
+         break;
+-      case 255:
+-      case 257:
+-#line 912 "parse.y"
+-{sqlite3Pragma(pParse,&yymsp[-3].minor.yy198,&yymsp[-2].minor.yy198,&yymsp[0].minor.yy198,0);}
+-#line 2983 "parse.c"
++      case 242:
++      case 244:
++#line 893 "parse.y"
++{sqlite3Pragma(pParse,&yymsp[-3].minor.yy384,&yymsp[-2].minor.yy384,&yymsp[0].minor.yy384,0);}
++#line 2843 "parse.c"
+         break;
+-      case 256:
+-#line 913 "parse.y"
+-{sqlite3Pragma(pParse,&yymsp[-3].minor.yy198,&yymsp[-2].minor.yy198,&yymsp[0].minor.yy0,0);}
+-#line 2988 "parse.c"
++      case 243:
++#line 894 "parse.y"
++{sqlite3Pragma(pParse,&yymsp[-3].minor.yy384,&yymsp[-2].minor.yy384,&yymsp[0].minor.yy0,0);}
++#line 2848 "parse.c"
+         break;
+-      case 258:
+-#line 915 "parse.y"
++      case 245:
++#line 896 "parse.y"
+ {
+-  sqlite3Pragma(pParse,&yymsp[-3].minor.yy198,&yymsp[-2].minor.yy198,&yymsp[0].minor.yy198,1);
++  sqlite3Pragma(pParse,&yymsp[-3].minor.yy384,&yymsp[-2].minor.yy384,&yymsp[0].minor.yy384,1);
+ }
+-#line 2995 "parse.c"
++#line 2855 "parse.c"
+         break;
+-      case 259:
+-#line 918 "parse.y"
+-{sqlite3Pragma(pParse,&yymsp[-4].minor.yy198,&yymsp[-3].minor.yy198,&yymsp[-1].minor.yy198,0);}
+-#line 3000 "parse.c"
++      case 246:
++#line 899 "parse.y"
++{sqlite3Pragma(pParse,&yymsp[-4].minor.yy384,&yymsp[-3].minor.yy384,&yymsp[-1].minor.yy384,0);}
++#line 2860 "parse.c"
+         break;
+-      case 260:
+-#line 919 "parse.y"
+-{sqlite3Pragma(pParse,&yymsp[-1].minor.yy198,&yymsp[0].minor.yy198,0,0);}
+-#line 3005 "parse.c"
++      case 247:
++#line 900 "parse.y"
++{sqlite3Pragma(pParse,&yymsp[-1].minor.yy384,&yymsp[0].minor.yy384,0,0);}
++#line 2865 "parse.c"
+         break;
+-      case 267:
+-#line 932 "parse.y"
++      case 253:
++#line 912 "parse.y"
+ {
+   Token all;
+-  all.z = yymsp[-3].minor.yy198.z;
+-  all.n = (yymsp[0].minor.yy0.z - yymsp[-3].minor.yy198.z) + yymsp[0].minor.yy0.n;
+-  sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy360, &all);
++  all.z = yymsp[-3].minor.yy384.z;
++  all.n = (yymsp[0].minor.yy0.z - yymsp[-3].minor.yy384.z) + yymsp[0].minor.yy0.n;
++  sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy247, &all);
+ }
+-#line 3015 "parse.c"
++#line 2875 "parse.c"
+         break;
+-      case 268:
+-#line 941 "parse.y"
++      case 254:
++#line 921 "parse.y"
+ {
+-  sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy198, &yymsp[-6].minor.yy198, yymsp[-5].minor.yy280, yymsp[-4].minor.yy30.a, yymsp[-4].minor.yy30.b, yymsp[-2].minor.yy151, yymsp[-1].minor.yy280, yymsp[0].minor.yy62, yymsp[-9].minor.yy280);
+-  yygotominor.yy198 = (yymsp[-6].minor.yy198.n==0?yymsp[-7].minor.yy198:yymsp[-6].minor.yy198);
++  sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy384, &yymsp[-6].minor.yy384, yymsp[-5].minor.yy230, yymsp[-4].minor.yy132.a, yymsp[-4].minor.yy132.b, yymsp[-2].minor.yy285, yymsp[-1].minor.yy230, yymsp[0].minor.yy178, yymsp[-9].minor.yy230);
++  yygotominor.yy384 = (yymsp[-6].minor.yy384.n==0?yymsp[-7].minor.yy384:yymsp[-6].minor.yy384);
+ }
+-#line 3023 "parse.c"
++#line 2883 "parse.c"
+         break;
+-      case 269:
+-      case 272:
+-#line 947 "parse.y"
+-{ yygotominor.yy280 = TK_BEFORE; }
+-#line 3029 "parse.c"
++      case 255:
++      case 258:
++#line 927 "parse.y"
++{ yygotominor.yy230 = TK_BEFORE; }
++#line 2889 "parse.c"
+         break;
+-      case 270:
+-#line 948 "parse.y"
+-{ yygotominor.yy280 = TK_AFTER;  }
+-#line 3034 "parse.c"
++      case 256:
++#line 928 "parse.y"
++{ yygotominor.yy230 = TK_AFTER;  }
++#line 2894 "parse.c"
+         break;
+-      case 271:
+-#line 949 "parse.y"
+-{ yygotominor.yy280 = TK_INSTEAD;}
+-#line 3039 "parse.c"
++      case 257:
++#line 929 "parse.y"
++{ yygotominor.yy230 = TK_INSTEAD;}
++#line 2899 "parse.c"
+         break;
+-      case 273:
+-      case 274:
+-      case 275:
+-#line 954 "parse.y"
+-{yygotominor.yy30.a = yymsp[0].major; yygotominor.yy30.b = 0;}
+-#line 3046 "parse.c"
++      case 259:
++      case 260:
++#line 934 "parse.y"
++{yygotominor.yy132.a = yymsp[0].major; yygotominor.yy132.b = 0;}
++#line 2905 "parse.c"
+         break;
+-      case 276:
+-#line 957 "parse.y"
+-{yygotominor.yy30.a = TK_UPDATE; yygotominor.yy30.b = yymsp[0].minor.yy240;}
+-#line 3051 "parse.c"
++      case 261:
++#line 936 "parse.y"
++{yygotominor.yy132.a = TK_UPDATE; yygotominor.yy132.b = yymsp[0].minor.yy160;}
++#line 2910 "parse.c"
+         break;
+-      case 277:
+-      case 278:
+-#line 960 "parse.y"
+-{ yygotominor.yy280 = TK_ROW; }
+-#line 3057 "parse.c"
++      case 262:
++      case 263:
++#line 939 "parse.y"
++{ yygotominor.yy230 = TK_ROW; }
++#line 2916 "parse.c"
+         break;
+-      case 279:
+-#line 962 "parse.y"
+-{ yygotominor.yy280 = TK_STATEMENT; }
+-#line 3062 "parse.c"
++      case 264:
++#line 941 "parse.y"
++{ yygotominor.yy230 = TK_STATEMENT; }
++#line 2921 "parse.c"
+         break;
+-      case 280:
+-#line 965 "parse.y"
+-{ yygotominor.yy62 = 0; }
+-#line 3067 "parse.c"
++      case 265:
++#line 945 "parse.y"
++{ yygotominor.yy178 = 0; }
++#line 2926 "parse.c"
+         break;
+-      case 281:
+-#line 966 "parse.y"
+-{ yygotominor.yy62 = yymsp[0].minor.yy62; }
+-#line 3072 "parse.c"
++      case 266:
++#line 946 "parse.y"
++{ yygotominor.yy178 = yymsp[0].minor.yy178; }
++#line 2931 "parse.c"
+         break;
+-      case 282:
+-#line 970 "parse.y"
++      case 267:
++#line 950 "parse.y"
+ {
+-  yymsp[-2].minor.yy360->pNext = yymsp[0].minor.yy360;
+-  yygotominor.yy360 = yymsp[-2].minor.yy360;
++  yymsp[-2].minor.yy247->pNext = yymsp[0].minor.yy247;
++  yygotominor.yy247 = yymsp[-2].minor.yy247;
+ }
+-#line 3080 "parse.c"
++#line 2939 "parse.c"
+         break;
+-      case 283:
+-#line 974 "parse.y"
+-{ yygotominor.yy360 = 0; }
+-#line 3085 "parse.c"
++      case 268:
++#line 954 "parse.y"
++{ yygotominor.yy247 = 0; }
++#line 2944 "parse.c"
+         break;
+-      case 284:
+-#line 980 "parse.y"
+-{ yygotominor.yy360 = sqlite3TriggerUpdateStep(&yymsp[-3].minor.yy198, yymsp[-1].minor.yy418, yymsp[0].minor.yy62, yymsp[-4].minor.yy280); }
+-#line 3090 "parse.c"
++      case 269:
++#line 960 "parse.y"
++{ yygotominor.yy247 = sqlite3TriggerUpdateStep(&yymsp[-3].minor.yy384, yymsp[-1].minor.yy462, yymsp[0].minor.yy178, yymsp[-4].minor.yy230); }
++#line 2949 "parse.c"
+         break;
+-      case 285:
+-#line 985 "parse.y"
+-{yygotominor.yy360 = sqlite3TriggerInsertStep(&yymsp[-5].minor.yy198, yymsp[-4].minor.yy240, yymsp[-1].minor.yy418, 0, yymsp[-7].minor.yy280);}
+-#line 3095 "parse.c"
++      case 270:
++#line 965 "parse.y"
++{yygotominor.yy247 = sqlite3TriggerInsertStep(&yymsp[-5].minor.yy384, yymsp[-4].minor.yy160, yymsp[-1].minor.yy462, 0, yymsp[-7].minor.yy230);}
++#line 2954 "parse.c"
+         break;
+-      case 286:
+-#line 988 "parse.y"
+-{yygotominor.yy360 = sqlite3TriggerInsertStep(&yymsp[-2].minor.yy198, yymsp[-1].minor.yy240, 0, yymsp[0].minor.yy375, yymsp[-4].minor.yy280);}
+-#line 3100 "parse.c"
++      case 271:
++#line 968 "parse.y"
++{yygotominor.yy247 = sqlite3TriggerInsertStep(&yymsp[-2].minor.yy384, yymsp[-1].minor.yy160, 0, yymsp[0].minor.yy239, yymsp[-4].minor.yy230);}
++#line 2959 "parse.c"
+         break;
+-      case 287:
+-#line 992 "parse.y"
+-{yygotominor.yy360 = sqlite3TriggerDeleteStep(&yymsp[-1].minor.yy198, yymsp[0].minor.yy62);}
+-#line 3105 "parse.c"
++      case 272:
++#line 972 "parse.y"
++{yygotominor.yy247 = sqlite3TriggerDeleteStep(&yymsp[-1].minor.yy384, yymsp[0].minor.yy178);}
++#line 2964 "parse.c"
+         break;
+-      case 288:
+-#line 995 "parse.y"
+-{yygotominor.yy360 = sqlite3TriggerSelectStep(yymsp[0].minor.yy375); }
+-#line 3110 "parse.c"
++      case 273:
++#line 975 "parse.y"
++{yygotominor.yy247 = sqlite3TriggerSelectStep(yymsp[0].minor.yy239); }
++#line 2969 "parse.c"
+         break;
+-      case 289:
+-#line 998 "parse.y"
++      case 274:
++#line 978 "parse.y"
+ {
+-  yygotominor.yy62 = sqlite3Expr(TK_RAISE, 0, 0, 0); 
+-  yygotominor.yy62->iColumn = OE_Ignore;
+-  sqlite3ExprSpan(yygotominor.yy62, &yymsp[-3].minor.yy0, &yymsp[0].minor.yy0);
++  yygotominor.yy178 = sqlite3Expr(TK_RAISE, 0, 0, 0); 
++  yygotominor.yy178->iColumn = OE_Ignore;
++  sqlite3ExprSpan(yygotominor.yy178, &yymsp[-3].minor.yy0, &yymsp[0].minor.yy0);
+ }
+-#line 3119 "parse.c"
++#line 2978 "parse.c"
+         break;
+-      case 290:
+-#line 1003 "parse.y"
++      case 275:
++#line 983 "parse.y"
+ {
+-  yygotominor.yy62 = sqlite3Expr(TK_RAISE, 0, 0, &yymsp[-1].minor.yy198); 
+-  yygotominor.yy62->iColumn = yymsp[-3].minor.yy280;
+-  sqlite3ExprSpan(yygotominor.yy62, &yymsp[-5].minor.yy0, &yymsp[0].minor.yy0);
++  yygotominor.yy178 = sqlite3Expr(TK_RAISE, 0, 0, &yymsp[-1].minor.yy384); 
++  yygotominor.yy178->iColumn = yymsp[-3].minor.yy230;
++  sqlite3ExprSpan(yygotominor.yy178, &yymsp[-5].minor.yy0, &yymsp[0].minor.yy0);
+ }
+-#line 3128 "parse.c"
++#line 2987 "parse.c"
+         break;
+-      case 291:
+-#line 1011 "parse.y"
+-{yygotominor.yy280 = OE_Rollback;}
+-#line 3133 "parse.c"
++      case 276:
++#line 991 "parse.y"
++{yygotominor.yy230 = OE_Rollback;}
++#line 2992 "parse.c"
+         break;
+-      case 293:
+-#line 1013 "parse.y"
+-{yygotominor.yy280 = OE_Fail;}
+-#line 3138 "parse.c"
++      case 278:
++#line 993 "parse.y"
++{yygotominor.yy230 = OE_Fail;}
++#line 2997 "parse.c"
+         break;
+-      case 294:
+-#line 1018 "parse.y"
++      case 279:
++#line 998 "parse.y"
+ {
+-  sqlite3DropTrigger(pParse,yymsp[0].minor.yy151);
++  sqlite3DropTrigger(pParse,yymsp[0].minor.yy285);
+ }
+-#line 3145 "parse.c"
++#line 3004 "parse.c"
+         break;
+-      case 295:
+-#line 1024 "parse.y"
++      case 280:
++#line 1004 "parse.y"
+ {
+-  sqlite3Attach(pParse, &yymsp[-3].minor.yy198, &yymsp[-1].minor.yy198, yymsp[0].minor.yy361.type, &yymsp[0].minor.yy361.key);
++  sqlite3Attach(pParse, yymsp[-3].minor.yy178, yymsp[-1].minor.yy178, yymsp[0].minor.yy292);
+ }
+-#line 3152 "parse.c"
++#line 3011 "parse.c"
+         break;
+-      case 296:
+-#line 1028 "parse.y"
+-{ yygotominor.yy361.type = 0; }
+-#line 3157 "parse.c"
++      case 281:
++#line 1009 "parse.y"
++{ yygotominor.yy292 = 0; }
++#line 3016 "parse.c"
+         break;
+-      case 297:
+-#line 1029 "parse.y"
+-{ yygotominor.yy361.type=1; yygotominor.yy361.key = yymsp[0].minor.yy198; }
+-#line 3162 "parse.c"
++      case 282:
++#line 1010 "parse.y"
++{ yygotominor.yy292 = yymsp[0].minor.yy178; }
++#line 3021 "parse.c"
+         break;
+-      case 298:
+-#line 1030 "parse.y"
+-{ yygotominor.yy361.type=2; yygotominor.yy361.key = yymsp[0].minor.yy0; }
+-#line 3167 "parse.c"
+-        break;
+-      case 301:
+-#line 1036 "parse.y"
++      case 285:
++#line 1016 "parse.y"
+ {
+-  sqlite3Detach(pParse, &yymsp[0].minor.yy198);
++  sqlite3Detach(pParse, yymsp[0].minor.yy178);
+ }
+-#line 3174 "parse.c"
++#line 3028 "parse.c"
+         break;
+-      case 302:
+-#line 1042 "parse.y"
++      case 286:
++#line 1022 "parse.y"
+ {sqlite3Reindex(pParse, 0, 0);}
+-#line 3179 "parse.c"
++#line 3033 "parse.c"
+         break;
+-      case 303:
+-#line 1043 "parse.y"
+-{sqlite3Reindex(pParse, &yymsp[-1].minor.yy198, &yymsp[0].minor.yy198);}
+-#line 3184 "parse.c"
++      case 287:
++#line 1023 "parse.y"
++{sqlite3Reindex(pParse, &yymsp[-1].minor.yy384, &yymsp[0].minor.yy384);}
++#line 3038 "parse.c"
+         break;
+-      case 304:
+-#line 1048 "parse.y"
++      case 288:
++#line 1028 "parse.y"
+ {sqlite3Analyze(pParse, 0, 0);}
+-#line 3189 "parse.c"
++#line 3043 "parse.c"
+         break;
+-      case 305:
+-#line 1049 "parse.y"
+-{sqlite3Analyze(pParse, &yymsp[-1].minor.yy198, &yymsp[0].minor.yy198);}
+-#line 3194 "parse.c"
++      case 289:
++#line 1029 "parse.y"
++{sqlite3Analyze(pParse, &yymsp[-1].minor.yy384, &yymsp[0].minor.yy384);}
++#line 3048 "parse.c"
+         break;
+-      case 306:
+-#line 1054 "parse.y"
++      case 290:
++#line 1034 "parse.y"
+ {
+-  sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy151,&yymsp[0].minor.yy198);
++  sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy285,&yymsp[0].minor.yy384);
+ }
+-#line 3201 "parse.c"
++#line 3055 "parse.c"
+         break;
+-      case 307:
+-#line 1057 "parse.y"
++      case 291:
++#line 1037 "parse.y"
+ {
+-  sqlite3AlterFinishAddColumn(pParse, &yymsp[0].minor.yy198);
++  sqlite3AlterFinishAddColumn(pParse, &yymsp[0].minor.yy384);
+ }
+-#line 3208 "parse.c"
++#line 3062 "parse.c"
+         break;
+-      case 308:
+-#line 1060 "parse.y"
++      case 292:
++#line 1040 "parse.y"
+ {
+-  sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy151);
++  sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy285);
+ }
+-#line 3215 "parse.c"
++#line 3069 "parse.c"
+         break;
+   };
+   yygoto = yyRuleInfo[yyruleno].lhs;
+@@ -3276,7 +3130,7 @@
+       sqlite3ErrorMsg(pParse, "incomplete SQL statement");
+     }
+   }
+-#line 3282 "parse.c"
++#line 3136 "parse.c"
+   sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
+ }
+ 
+Index: sqlite/where.c
+===================================================================
+--- amarok/src/sqlite/where.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/where.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -83,7 +83,7 @@
+   i16 iParent;            /* Disable pWC->a[iParent] when this term disabled */
+   i16 leftCursor;         /* Cursor number of X in "X <op> <expr>" */
+   i16 leftColumn;         /* Column number of X in "X <op> <expr>" */
+-  u16 operator;           /* A WO_xx value describing <op> */
++  u16 eOperator;          /* A WO_xx value describing <op> */
+   u8 flags;               /* Bit flags.  See below */
+   u8 nChild;              /* Number of children that must disable us */
+   WhereClause *pWC;       /* The clause this term is part of */
+@@ -418,13 +418,13 @@
+     if( pTerm->leftCursor==iCur
+        && (pTerm->prereqRight & notReady)==0
+        && pTerm->leftColumn==iColumn
+-       && (pTerm->operator & op)!=0
++       && (pTerm->eOperator & op)!=0
+     ){
+       if( iCur>=0 && pIdx ){
+         Expr *pX = pTerm->pExpr;
+         CollSeq *pColl;
+         char idxaff;
+-        int k;
++        int j;
+         Parse *pParse = pWC->pParse;
+ 
+         idxaff = pIdx->pTable->aCol[iColumn].affinity;
+@@ -438,9 +438,9 @@
+             pColl = pParse->db->pDfltColl;
+           }
+         }
+-        for(k=0; k<pIdx->nColumn && pIdx->aiColumn[k]!=iColumn; k++){}
+-        assert( k<pIdx->nColumn );
+-        if( pColl!=pIdx->keyInfo.aColl[k] ) continue;
++        for(j=0; j<pIdx->nColumn && pIdx->aiColumn[j]!=iColumn; j++){}
++        assert( j<pIdx->nColumn );
++        if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ) continue;
+       }
+       return pTerm;
+     }
+@@ -511,7 +511,7 @@
+     return 0;
+   }
+   sqlite3DequoteExpr(pRight);
+-  z = pRight->token.z;
++  z = (char *)pRight->token.z;
+   for(cnt=0; (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2]; cnt++){}
+   if( cnt==0 || 255==(u8)z[cnt] ){
+     return 0;
+@@ -523,6 +523,16 @@
+ #endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */
+ 
+ /*
++** If the pBase expression originated in the ON or USING clause of
++** a join, then transfer the appropriate markings over to derived.
++*/
++static void transferJoinMarkings(Expr *pDerived, Expr *pBase){
++  pDerived->flags |= pBase->flags & EP_FromJoin;
++  pDerived->iRightJoinTable = pBase->iRightJoinTable;
++}
++
++
++/*
+ ** The input to this routine is an WhereTerm structure with only the
+ ** "pExpr" field filled in.  The job of this routine is to analyze the
+ ** subexpression and populate all the other fields of the WhereTerm
+@@ -547,7 +557,7 @@
+   int nPattern;
+   int isComplete;
+ 
+-  if( sqlite3_malloc_failed ) return;
++  if( sqlite3MallocFailed() ) return;
+   prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft);
+   if( pExpr->op==TK_IN ){
+     assert( pExpr->pRight==0 );
+@@ -563,14 +573,14 @@
+   pTerm->prereqAll = prereqAll;
+   pTerm->leftCursor = -1;
+   pTerm->iParent = -1;
+-  pTerm->operator = 0;
++  pTerm->eOperator = 0;
+   if( allowedOp(pExpr->op) && (pTerm->prereqRight & prereqLeft)==0 ){
+     Expr *pLeft = pExpr->pLeft;
+     Expr *pRight = pExpr->pRight;
+     if( pLeft->op==TK_COLUMN ){
+       pTerm->leftCursor = pLeft->iTable;
+       pTerm->leftColumn = pLeft->iColumn;
+-      pTerm->operator = operatorMask(pExpr->op);
++      pTerm->eOperator = operatorMask(pExpr->op);
+     }
+     if( pRight && pRight->op==TK_COLUMN ){
+       WhereTerm *pNew;
+@@ -595,7 +605,7 @@
+       pNew->leftColumn = pLeft->iColumn;
+       pNew->prereqRight = prereqLeft;
+       pNew->prereqAll = prereqAll;
+-      pNew->operator = operatorMask(pDup->op);
++      pNew->eOperator = operatorMask(pDup->op);
+     }
+   }
+ 
+@@ -623,7 +633,7 @@
+   }
+ #endif /* SQLITE_OMIT_BETWEEN_OPTIMIZATION */
+ 
+-#ifndef SQLITE_OMIT_OR_OPTIMIZATION
++#if !defined(SQLITE_OMIT_OR_OPTIMIZATION) && !defined(SQLITE_OMIT_SUBQUERY)
+   /* Attempt to convert OR-connected terms into an IN operator so that
+   ** they can make use of indices.  Example:
+   **
+@@ -632,6 +642,9 @@
+   ** is converted into
+   **
+   **      x IN (expr1,expr2,expr3)
++  **
++  ** This optimization must be omitted if OMIT_SUBQUERY is defined because
++  ** the compiler for the the IN operator is part of sub-queries.
+   */
+   else if( pExpr->op==TK_OR ){
+     int ok;
+@@ -651,7 +664,7 @@
+       iCursor = sOr.a[j].leftCursor;
+       ok = iCursor>=0;
+       for(i=sOr.nTerm-1, pOrTerm=sOr.a; i>=0 && ok; i--, pOrTerm++){
+-        if( pOrTerm->operator!=WO_EQ ){
++        if( pOrTerm->eOperator!=WO_EQ ){
+           goto or_not_possible;
+         }
+         if( pOrTerm->leftCursor==iCursor && pOrTerm->leftColumn==iColumn ){
+@@ -680,14 +693,17 @@
+       }
+       pNew = sqlite3Expr(TK_IN, pDup, 0, 0);
+       if( pNew ){
++        int idxNew;
++        transferJoinMarkings(pNew, pExpr);
+         pNew->pList = pList;
++        idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC);
++        exprAnalyze(pSrc, pMaskSet, pWC, idxNew);
++        pTerm = &pWC->a[idxTerm];
++        pWC->a[idxNew].iParent = idxTerm;
++        pTerm->nChild = 1;
+       }else{
+         sqlite3ExprListDelete(pList);
+       }
+-      pTerm->pExpr = pNew;
+-      pTerm->flags |= TERM_DYNAMIC;
+-      exprAnalyze(pSrc, pMaskSet, pWC, idxTerm);
+-      pTerm = &pWC->a[idxTerm];
+     }
+ or_not_possible:
+     whereClauseClear(&sOr);
+@@ -762,7 +778,7 @@
+   int *pbRev              /* Set to 1 if ORDER BY is DESC */
+ ){
+   int i, j;                       /* Loop counters */
+-  int sortOrder = SQLITE_SO_ASC;  /* Which direction we are sorting */
++  int sortOrder = 0;              /* XOR of index and ORDER BY sort direction */
+   int nTerm;                      /* Number of ORDER BY terms */
+   struct ExprList_item *pTerm;    /* A term of the ORDER BY clause */
+   sqlite3 *db = pParse->db;
+@@ -777,6 +793,7 @@
+   for(i=j=0, pTerm=pOrderBy->a; j<nTerm && i<pIdx->nColumn; i++){
+     Expr *pExpr;       /* The expression of the ORDER BY pTerm */
+     CollSeq *pColl;    /* The collating sequence of pExpr */
++    int termSortOrder; /* Sort order for this term */
+ 
+     pExpr = pTerm->pExpr;
+     if( pExpr->op!=TK_COLUMN || pExpr->iTable!=base ){
+@@ -786,7 +803,8 @@
+     }
+     pColl = sqlite3ExprCollSeq(pParse, pExpr);
+     if( !pColl ) pColl = db->pDfltColl;
+-    if( pExpr->iColumn!=pIdx->aiColumn[i] || pColl!=pIdx->keyInfo.aColl[i] ){
++    if( pExpr->iColumn!=pIdx->aiColumn[i] || 
++        sqlite3StrICmp(pColl->zName, pIdx->azColl[i]) ){
+       /* Term j of the ORDER BY clause does not match column i of the index */
+       if( i<nEqCol ){
+         /* If an index column that is constrained by == fails to match an
+@@ -800,14 +818,18 @@
+         return 0;
+       }
+     }
++    assert( pIdx->aSortOrder!=0 );
++    assert( pTerm->sortOrder==0 || pTerm->sortOrder==1 );
++    assert( pIdx->aSortOrder[i]==0 || pIdx->aSortOrder[i]==1 );
++    termSortOrder = pIdx->aSortOrder[i] ^ pTerm->sortOrder;
+     if( i>nEqCol ){
+-      if( pTerm->sortOrder!=sortOrder ){
++      if( termSortOrder!=sortOrder ){
+         /* Indices can only be used if all ORDER BY terms past the
+         ** equality constraints are all either DESC or ASC. */
+         return 0;
+       }
+     }else{
+-      sortOrder = pTerm->sortOrder;
++      sortOrder = termSortOrder;
+     }
+     j++;
+     pTerm++;
+@@ -817,7 +839,7 @@
+   ** are covered.
+   */
+   if( j>=nTerm ){
+-    *pbRev = sortOrder==SQLITE_SO_DESC;
++    *pbRev = sortOrder!=0;
+     return 1;
+   }
+   return 0;
+@@ -854,10 +876,10 @@
+ ** logN is a little off.
+ */
+ static double estLog(double N){
+-  double logN = 1.0;
+-  double x = 10.0;
++  double logN = 1;
++  double x = 10;
+   while( N>x ){
+-    logN += 1.0;
++    logN += 1;
+     x *= 10;
+   }
+   return logN;
+@@ -893,7 +915,7 @@
+ ){
+   WhereTerm *pTerm;
+   Index *bestIdx = 0;         /* Index that gives the lowest cost */
+-  double lowestCost = 1.0e99; /* The cost of using bestIdx */
++  double lowestCost;          /* The cost of using bestIdx */
+   int bestFlags = 0;          /* Flags associated with bestIdx */
+   int bestNEq = 0;            /* Best value for nEq */
+   int iCur = pSrc->iCursor;   /* The cursor of the table to be accessed */
+@@ -904,6 +926,7 @@
+   double cost;                /* Cost of using pProbe */
+ 
+   TRACE(("bestIndex: tbl=%s notReady=%x\n", pSrc->pTab->zName, notReady));
++  lowestCost = SQLITE_BIG_DBL;
+ 
+   /* Check for a rowid=EXPR or rowid IN (...) constraints
+   */
+@@ -912,7 +935,7 @@
+     Expr *pExpr;
+     *ppIndex = 0;
+     bestFlags = WHERE_ROWID_EQ;
+-    if( pTerm->operator & WO_EQ ){
++    if( pTerm->eOperator & WO_EQ ){
+       /* Rowid== is always the best pick.  Look no further.  Because only
+       ** a single row is generated, output is always in sorted order */
+       *pFlags = WHERE_ROWID_EQ | WHERE_UNIQUE;
+@@ -928,7 +951,7 @@
+       /* Rowid IN (SELECT): cost is NlogN where N is the number of rows
+       ** in the result of the inner select.  We have no way to estimate
+       ** that value so make a wild guess. */
+-      lowestCost = 200.0;
++      lowestCost = 200;
+     }
+     TRACE(("... rowid IN cost: %.9g\n", lowestCost));
+   }
+@@ -937,7 +960,7 @@
+   ** entries are in the table, use 1 million as a guess.
+   */
+   pProbe = pSrc->pTab->pIndex;
+-  cost = pProbe ? pProbe->aiRowEst[0] : 1000000.0;
++  cost = pProbe ? pProbe->aiRowEst[0] : 1000000;
+   TRACE(("... table scan base cost: %.9g\n", cost));
+   flags = WHERE_ROWID_RANGE;
+ 
+@@ -947,11 +970,11 @@
+   if( pTerm ){
+     if( findTerm(pWC, iCur, -1, notReady, WO_LT|WO_LE, 0) ){
+       flags |= WHERE_TOP_LIMIT;
+-      cost *= 0.333;  /* Guess that rowid<EXPR eliminates two-thirds or rows */
++      cost /= 3;  /* Guess that rowid<EXPR eliminates two-thirds or rows */
+     }
+     if( findTerm(pWC, iCur, -1, notReady, WO_GT|WO_GE, 0) ){
+       flags |= WHERE_BTM_LIMIT;
+-      cost *= 0.333;  /* Guess that rowid>EXPR eliminates two-thirds of rows */
++      cost /= 3;  /* Guess that rowid>EXPR eliminates two-thirds of rows */
+     }
+     TRACE(("... rowid range reduces cost to %.9g\n", cost));
+   }else{
+@@ -980,7 +1003,7 @@
+   */
+   for(; pProbe; pProbe=pProbe->pNext){
+     int i;                       /* Loop counter */
+-    double inMultiplier = 1.0;
++    double inMultiplier = 1;
+ 
+     TRACE(("... index %s:\n", pProbe->zName));
+ 
+@@ -993,13 +1016,13 @@
+       pTerm = findTerm(pWC, iCur, j, notReady, WO_EQ|WO_IN, pProbe);
+       if( pTerm==0 ) break;
+       flags |= WHERE_COLUMN_EQ;
+-      if( pTerm->operator & WO_IN ){
++      if( pTerm->eOperator & WO_IN ){
+         Expr *pExpr = pTerm->pExpr;
+         flags |= WHERE_COLUMN_IN;
+         if( pExpr->pSelect!=0 ){
+-          inMultiplier *= 100.0;
++          inMultiplier *= 100;
+         }else if( pExpr->pList!=0 ){
+-          inMultiplier *= pExpr->pList->nExpr + 1.0;
++          inMultiplier *= pExpr->pList->nExpr + 1;
+         }
+       }
+     }
+@@ -1020,11 +1043,11 @@
+         flags |= WHERE_COLUMN_RANGE;
+         if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pProbe) ){
+           flags |= WHERE_TOP_LIMIT;
+-          cost *= 0.333;
++          cost /= 3;
+         }
+         if( findTerm(pWC, iCur, j, notReady, WO_GT|WO_GE, pProbe) ){
+           flags |= WHERE_BTM_LIMIT;
+-          cost *= 0.333;
++          cost /= 3;
+         }
+         TRACE(("...... range reduces cost to %.9g\n", cost));
+       }
+@@ -1063,7 +1086,7 @@
+       }
+       if( m==0 ){
+         flags |= WHERE_IDX_ONLY;
+-        cost *= 0.5;
++        cost /= 2;
+         TRACE(("...... idx-only reduces cost to %.9g\n", cost));
+       }
+     }
+@@ -1134,14 +1157,24 @@
+ **    *  Check the top nColumn entries on the stack.  If any
+ **       of those entries are NULL, jump immediately to brk,
+ **       which is the loop exit, since no index entry will match
+-**       if any part of the key is NULL.
++**       if any part of the key is NULL. Pop (nColumn+nExtra) 
++**       elements from the stack.
+ **
+ **    *  Construct a probe entry from the top nColumn entries in
+-**       the stack with affinities appropriate for index pIdx.
++**       the stack with affinities appropriate for index pIdx. 
++**       Only nColumn elements are popped from the stack in this case
++**       (by OP_MakeRecord).
++**
+ */
+-static void buildIndexProbe(Vdbe *v, int nColumn, int brk, Index *pIdx){
++static void buildIndexProbe(
++  Vdbe *v, 
++  int nColumn, 
++  int nExtra, 
++  int brk, 
++  Index *pIdx
++){
+   sqlite3VdbeAddOp(v, OP_NotNull, -nColumn, sqlite3VdbeCurrentAddr(v)+3);
+-  sqlite3VdbeAddOp(v, OP_Pop, nColumn, 0);
++  sqlite3VdbeAddOp(v, OP_Pop, nColumn+nExtra, 0);
+   sqlite3VdbeAddOp(v, OP_Goto, 0, brk);
+   sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
+   sqlite3IndexAffinityStr(v, pIdx);
+@@ -1180,7 +1213,7 @@
+     sqlite3VdbeAddOp(v, OP_Rewind, iTab, brk);
+     VdbeComment((v, "# %.*s", pX->span.n, pX->span.z));
+     pLevel->nIn++;
+-    sqlite3ReallocOrFree((void**)&pLevel->aInLoop,
++    sqliteReallocOrFree((void**)&pLevel->aInLoop,
+                                  sizeof(pLevel->aInLoop[0])*3*pLevel->nIn);
+     aIn = pLevel->aInLoop;
+     if( aIn ){
+@@ -1408,7 +1441,7 @@
+   ** return value.
+   */
+   pWInfo = sqliteMalloc( sizeof(WhereInfo) + pTabList->nSrc*sizeof(WhereLevel));
+-  if( sqlite3_malloc_failed ){
++  if( sqlite3MallocFailed() ){
+     goto whereBeginNoMem;
+   }
+   pWInfo->pParse = pParse;
+@@ -1432,7 +1465,7 @@
+     createMask(&maskSet, pTabList->a[i].iCursor);
+   }
+   exprAnalyzeAll(pTabList, &maskSet, &wc);
+-  if( sqlite3_malloc_failed ){
++  if( sqlite3MallocFailed() ){
+     goto whereBeginNoMem;
+   }
+ 
+@@ -1464,11 +1497,19 @@
+     Index *pBest = 0;           /* The best index seen so far */
+     int bestFlags = 0;          /* Flags associated with pBest */
+     int bestNEq = 0;            /* nEq associated with pBest */
+-    double lowestCost = 1.0e99; /* Cost of the pBest */
+-    int bestJ;                  /* The value of j */
++    double lowestCost;          /* Cost of the pBest */
++    int bestJ = 0;              /* The value of j */
+     Bitmask m;                  /* Bitmask value for j or bestJ */
++    int once = 0;               /* True when first table is seen */
+ 
++    lowestCost = SQLITE_BIG_DBL;
+     for(j=iFrom, pTabItem=&pTabList->a[j]; j<pTabList->nSrc; j++, pTabItem++){
++      if( once && 
++          ((pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0
++           || (j>0 && (pTabItem[-1].jointype & (JT_LEFT|JT_CROSS))!=0))
++      ){
++        break;
++      }
+       m = getMask(&maskSet, pTabItem->iCursor);
+       if( (m & notReady)==0 ){
+         if( j==iFrom ) iFrom++;
+@@ -1478,17 +1519,13 @@
+                        (i==0 && ppOrderBy) ? *ppOrderBy : 0,
+                        &pIdx, &flags, &nEq);
+       if( cost<lowestCost ){
++        once = 1;
+         lowestCost = cost;
+         pBest = pIdx;
+         bestFlags = flags;
+         bestNEq = nEq;
+         bestJ = j;
+       }
+-      if( (pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0
+-         || (j>0 && (pTabItem[-1].jointype & (JT_LEFT|JT_CROSS))!=0)
+-      ){
+-        break;
+-      }
+     }
+     TRACE(("*** Optimizer choose table %d for loop %d\n", bestJ,
+            pLevel-pWInfo->a));
+@@ -1524,8 +1561,9 @@
+   sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */
+   pLevel = pWInfo->a;
+   for(i=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){
+-    Table *pTab;
+-    Index *pIx;
++    Table *pTab;     /* Table to open */
++    Index *pIx;      /* Index used to access pTab (if any) */
++    int iDb;         /* Index of database containing table/index */
+     int iIdxCur = pLevel->iIdxCur;
+ 
+ #ifndef SQLITE_OMIT_EXPLAIN
+@@ -1538,27 +1576,41 @@
+       }
+       if( (pIx = pLevel->pIdx)!=0 ){
+         zMsg = sqlite3MPrintf("%z WITH INDEX %s", zMsg, pIx->zName);
++      }else if( pLevel->flags & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){
++        zMsg = sqlite3MPrintf("%z USING PRIMARY KEY", zMsg);
+       }
+       sqlite3VdbeOp3(v, OP_Explain, i, pLevel->iFrom, zMsg, P3_DYNAMIC);
+     }
+ #endif /* SQLITE_OMIT_EXPLAIN */
+     pTabItem = &pTabList->a[pLevel->iFrom];
+     pTab = pTabItem->pTab;
++    iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
+     if( pTab->isTransient || pTab->pSelect ) continue;
+     if( (pLevel->flags & WHERE_IDX_ONLY)==0 ){
+-      sqlite3OpenTableForReading(v, pTabItem->iCursor, pTab);
++      sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, OP_OpenRead);
++      if( pTab->nCol<(sizeof(Bitmask)*8) ){
++        Bitmask b = pTabItem->colUsed;
++        int n = 0;
++        for(; b; b=b>>1, n++);
++        sqlite3VdbeChangeP2(v, sqlite3VdbeCurrentAddr(v)-1, n);
++        assert( n<=pTab->nCol );
++      }
++    }else{
++      sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
+     }
+     pLevel->iTabCur = pTabItem->iCursor;
+     if( (pIx = pLevel->pIdx)!=0 ){
+-      sqlite3VdbeAddOp(v, OP_Integer, pIx->iDb, 0);
++      KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIx);
++      assert( pIx->pSchema==pTab->pSchema );
++      sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
+       VdbeComment((v, "# %s", pIx->zName));
+       sqlite3VdbeOp3(v, OP_OpenRead, iIdxCur, pIx->tnum,
+-                     (char*)&pIx->keyInfo, P3_KEYINFO);
++                     (char*)pKey, P3_KEYINFO_HANDOFF);
+     }
+     if( (pLevel->flags & WHERE_IDX_ONLY)!=0 ){
+       sqlite3VdbeAddOp(v, OP_SetNumColumns, iIdxCur, pIx->nColumn+1);
+     }
+-    sqlite3CodeVerifySchema(pParse, pTab->iDb);
++    sqlite3CodeVerifySchema(pParse, iDb);
+   }
+   pWInfo->iTop = sqlite3VdbeCurrentAddr(v);
+ 
+@@ -1667,7 +1719,7 @@
+       if( testOp!=OP_Noop ){
+         sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
+         sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
+-        sqlite3VdbeAddOp(v, testOp, 'n', brk);
++        sqlite3VdbeAddOp(v, testOp, SQLITE_AFF_NUMERIC, brk);
+       }
+     }else if( pLevel->flags & WHERE_COLUMN_RANGE ){
+       /* Case 3: The WHERE clause term that refers to the right-most
+@@ -1683,8 +1735,11 @@
+       */
+       int start;
+       int nEq = pLevel->nEq;
+-      int leFlag=0, geFlag=0;
++      int topEq=0;        /* True if top limit uses ==. False is strictly < */
++      int btmEq=0;        /* True if btm limit uses ==. False if strictly > */
++      int topOp, btmOp;   /* Operators for the top and bottom search bounds */
+       int testOp;
++      int nNotNull;       /* Number of rows of index that must be non-NULL */
+       int topLimit = (pLevel->flags & WHERE_TOP_LIMIT)!=0;
+       int btmLimit = (pLevel->flags & WHERE_BTM_LIMIT)!=0;
+ 
+@@ -1701,6 +1756,21 @@
+         sqlite3VdbeAddOp(v, OP_Dup, nEq-1, 0);
+       }
+ 
++      /* Figure out what comparison operators to use for top and bottom 
++      ** search bounds. For an ascending index, the bottom bound is a > or >=
++      ** operator and the top bound is a < or <= operator.  For a descending
++      ** index the operators are reversed.
++      */
++      nNotNull = nEq + topLimit;
++      if( pIdx->aSortOrder[nEq]==SQLITE_SO_ASC ){
++        topOp = WO_LT|WO_LE;
++        btmOp = WO_GT|WO_GE;
++      }else{
++        topOp = WO_GT|WO_GE;
++        btmOp = WO_LT|WO_LE;
++        SWAP(int, topLimit, btmLimit);
++      }
++
+       /* Generate the termination key.  This is the key value that
+       ** will end the search.  There is no termination key if there
+       ** are no equality terms and no "X<..." term.
+@@ -1711,24 +1781,24 @@
+       if( topLimit ){
+         Expr *pX;
+         int k = pIdx->aiColumn[j];
+-        pTerm = findTerm(&wc, iCur, k, notReady, WO_LT|WO_LE, pIdx);
++        pTerm = findTerm(&wc, iCur, k, notReady, topOp, pIdx);
+         assert( pTerm!=0 );
+         pX = pTerm->pExpr;
+         assert( (pTerm->flags & TERM_CODED)==0 );
+         sqlite3ExprCode(pParse, pX->pRight);
+-        leFlag = pX->op==TK_LE;
++        topEq = pTerm->eOperator & (WO_LE|WO_GE);
+         disableTerm(pLevel, pTerm);
+         testOp = OP_IdxGE;
+       }else{
+         testOp = nEq>0 ? OP_IdxGE : OP_Noop;
+-        leFlag = 1;
++        topEq = 1;
+       }
+       if( testOp!=OP_Noop ){
+         int nCol = nEq + topLimit;
+         pLevel->iMem = pParse->nMem++;
+-        buildIndexProbe(v, nCol, brk, pIdx);
++        buildIndexProbe(v, nCol, nEq, brk, pIdx);
+         if( bRev ){
+-          int op = leFlag ? OP_MoveLe : OP_MoveLt;
++          int op = topEq ? OP_MoveLe : OP_MoveLt;
+           sqlite3VdbeAddOp(v, op, iIdxCur, brk);
+         }else{
+           sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
+@@ -1749,25 +1819,25 @@
+       if( btmLimit ){
+         Expr *pX;
+         int k = pIdx->aiColumn[j];
+-        pTerm = findTerm(&wc, iCur, k, notReady, WO_GT|WO_GE, pIdx);
++        pTerm = findTerm(&wc, iCur, k, notReady, btmOp, pIdx);
+         assert( pTerm!=0 );
+         pX = pTerm->pExpr;
+         assert( (pTerm->flags & TERM_CODED)==0 );
+         sqlite3ExprCode(pParse, pX->pRight);
+-        geFlag = pX->op==TK_GE;
++        btmEq = pTerm->eOperator & (WO_LE|WO_GE);
+         disableTerm(pLevel, pTerm);
+       }else{
+-        geFlag = 1;
++        btmEq = 1;
+       }
+       if( nEq>0 || btmLimit ){
+         int nCol = nEq + btmLimit;
+-        buildIndexProbe(v, nCol, brk, pIdx);
++        buildIndexProbe(v, nCol, 0, brk, pIdx);
+         if( bRev ){
+           pLevel->iMem = pParse->nMem++;
+           sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
+           testOp = OP_IdxLT;
+         }else{
+-          int op = geFlag ? OP_MoveGe : OP_MoveGt;
++          int op = btmEq ? OP_MoveGe : OP_MoveGt;
+           sqlite3VdbeAddOp(v, op, iIdxCur, brk);
+         }
+       }else if( bRev ){
+@@ -1784,12 +1854,12 @@
+       if( testOp!=OP_Noop ){
+         sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
+         sqlite3VdbeAddOp(v, testOp, iIdxCur, brk);
+-        if( (leFlag && !bRev) || (!geFlag && bRev) ){
++        if( (topEq && !bRev) || (!btmEq && bRev) ){
+           sqlite3VdbeChangeP3(v, -1, "+", P3_STATIC);
+         }
+       }
+       sqlite3VdbeAddOp(v, OP_RowKey, iIdxCur, 0);
+-      sqlite3VdbeAddOp(v, OP_IdxIsNull, nEq + topLimit, cont);
++      sqlite3VdbeAddOp(v, OP_IdxIsNull, nNotNull, cont);
+       if( !omitTable ){
+         sqlite3VdbeAddOp(v, OP_IdxRowid, iIdxCur, 0);
+         sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
+@@ -1815,7 +1885,7 @@
+       /* Generate a single key that will be used to both start and terminate
+       ** the search
+       */
+-      buildIndexProbe(v, nEq, brk, pIdx);
++      buildIndexProbe(v, nEq, 0, brk, pIdx);
+       sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 0);
+ 
+       /* Generate code (1) to move to the first matching element of the table.
+@@ -2018,14 +2088,14 @@
+     ** reference the index.
+     */
+     if( pLevel->flags & WHERE_IDX_ONLY ){
+-      int i, j, last;
++      int k, j, last;
+       VdbeOp *pOp;
+       Index *pIdx = pLevel->pIdx;
+ 
+       assert( pIdx!=0 );
+       pOp = sqlite3VdbeGetOp(v, pWInfo->iTop);
+       last = sqlite3VdbeCurrentAddr(v);
+-      for(i=pWInfo->iTop; i<last; i++, pOp++){
++      for(k=pWInfo->iTop; k<last; k++, pOp++){
+         if( pOp->p1!=pLevel->iTabCur ) continue;
+         if( pOp->opcode==OP_Column ){
+           pOp->p1 = pLevel->iIdxCur;
+Index: sqlite/date.c
+===================================================================
+--- amarok/src/sqlite/date.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/date.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -105,18 +105,20 @@
+     val = 0;
+     while( N-- ){
+       if( !isdigit(*(u8*)zDate) ){
+-        return cnt;
++        goto end_getDigits;
+       }
+       val = val*10 + *zDate - '0';
+       zDate++;
+     }
+     if( val<min || val>max || (nextC!=0 && nextC!=*zDate) ){
+-      return cnt;
++      goto end_getDigits;
+     }
+     *pVal = val;
+     zDate++;
+     cnt++;
+   }while( nextC );
++end_getDigits:
++  va_end(ap);
+   return cnt;
+ }
+ 
+@@ -236,7 +238,7 @@
+   if( p->validHMS ){
+     p->rJD += (p->h*3600.0 + p->m*60.0 + p->s)/86400.0;
+     if( p->validTZ ){
+-      p->rJD += p->tz*60/86400.0;
++      p->rJD -= p->tz*60/86400.0;
+       p->validHMS = 0;
+       p->validTZ = 0;
+     }
+@@ -639,10 +641,10 @@
+   int i;
+   if( argc==0 ) return 1;
+   if( SQLITE_NULL==sqlite3_value_type(argv[0]) || 
+-      parseDateOrTime(sqlite3_value_text(argv[0]), p) ) return 1;
++      parseDateOrTime((char*)sqlite3_value_text(argv[0]), p) ) return 1;
+   for(i=1; i<argc; i++){
+     if( SQLITE_NULL==sqlite3_value_type(argv[i]) || 
+-        parseModifier(sqlite3_value_text(argv[i]), p) ) return 1;
++        parseModifier((char*)sqlite3_value_text(argv[i]), p) ) return 1;
+   }
+   return 0;
+ }
+@@ -755,7 +757,7 @@
+   DateTime x;
+   int n, i, j;
+   char *z;
+-  const char *zFmt = sqlite3_value_text(argv[0]);
++  const char *zFmt = (const char*)sqlite3_value_text(argv[0]);
+   char zBuf[100];
+   if( zFmt==0 || isDate(argc-1, argv+1, &x) ) return;
+   for(i=0, n=1; zFmt[i]; i++, n++){
+@@ -816,20 +818,20 @@
+         case 'H':  sprintf(&z[j],"%02d",x.h); j+=2; break;
+         case 'W': /* Fall thru */
+         case 'j': {
+-          int n;             /* Number of days since 1st day of year */
++          int nDay;             /* Number of days since 1st day of year */
+           DateTime y = x;
+           y.validJD = 0;
+           y.M = 1;
+           y.D = 1;
+           computeJD(&y);
+-          n = x.rJD - y.rJD;
++          nDay = x.rJD - y.rJD;
+           if( zFmt[i]=='W' ){
+             int wd;   /* 0=Monday, 1=Tuesday, ... 6=Sunday */
+             wd = ((int)(x.rJD+0.5)) % 7;
+-            sprintf(&z[j],"%02d",(n+7-wd)/7);
++            sprintf(&z[j],"%02d",(nDay+7-wd)/7);
+             j += 2;
+           }else{
+-            sprintf(&z[j],"%03d",n+1);
++            sprintf(&z[j],"%03d",nDay+1);
+             j += 3;
+           }
+           break;
+@@ -974,7 +976,7 @@
+   int i;
+ 
+   for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
+-    sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg,
++    sqlite3CreateFunc(db, aFuncs[i].zName, aFuncs[i].nArg,
+         SQLITE_UTF8, 0, aFuncs[i].xFunc, 0, 0);
+   }
+ #else
+@@ -989,7 +991,7 @@
+   int i;
+ 
+   for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
+-    sqlite3_create_function(db, aFuncs[i].zName, 0, SQLITE_UTF8, 
++    sqlite3CreateFunc(db, aFuncs[i].zName, 0, SQLITE_UTF8, 
+         aFuncs[i].zFormat, currentTimeFunc, 0, 0);
+   }
+ #endif
+Index: sqlite/expr.c
+===================================================================
+--- amarok/src/sqlite/expr.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/expr.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -75,12 +75,10 @@
+ char sqlite3CompareAffinity(Expr *pExpr, char aff2){
+   char aff1 = sqlite3ExprAffinity(pExpr);
+   if( aff1 && aff2 ){
+-    /* Both sides of the comparison are columns. If one has numeric or
+-    ** integer affinity, use that. Otherwise use no affinity.
++    /* Both sides of the comparison are columns. If one has numeric
++    ** affinity, use that. Otherwise use no affinity.
+     */
+-    if( aff1==SQLITE_AFF_INTEGER || aff2==SQLITE_AFF_INTEGER ){
+-      return SQLITE_AFF_INTEGER;
+-    }else if( aff1==SQLITE_AFF_NUMERIC || aff2==SQLITE_AFF_NUMERIC ){
++    if( sqlite3IsNumericAffinity(aff1) || sqlite3IsNumericAffinity(aff2) ){
+       return SQLITE_AFF_NUMERIC;
+     }else{
+       return SQLITE_AFF_NONE;
+@@ -89,7 +87,6 @@
+     /* Neither side of the comparison is a column.  Compare the
+     ** results directly.
+     */
+-    /* return SQLITE_AFF_NUMERIC;  // Ticket #805 */
+     return SQLITE_AFF_NONE;
+   }else{
+     /* One side is a column, the other is not. Use the columns affinity. */
+@@ -129,11 +126,14 @@
+ */
+ int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity){
+   char aff = comparisonAffinity(pExpr);
+-  return 
+-    (aff==SQLITE_AFF_NONE) ||
+-    (aff==SQLITE_AFF_NUMERIC && idx_affinity==SQLITE_AFF_INTEGER) ||
+-    (aff==SQLITE_AFF_INTEGER && idx_affinity==SQLITE_AFF_NUMERIC) ||
+-    (aff==idx_affinity);
++  switch( aff ){
++    case SQLITE_AFF_NONE:
++      return 1;
++    case SQLITE_AFF_TEXT:
++      return idx_affinity==SQLITE_AFF_TEXT;
++    default:
++      return sqlite3IsNumericAffinity(idx_affinity);
++  }
+ }
+ 
+ /*
+@@ -235,7 +235,7 @@
+   if( p==0 ){
+     return 0;  /* Malloc failed */
+   }
+-  depth = atoi(&pToken->z[1]);
++  depth = atoi((char*)&pToken->z[1]);
+   p->iTable = pParse->nMem++;
+   sqlite3VdbeAddOp(v, OP_Dup, depth, 0);
+   sqlite3VdbeAddOp(v, OP_MemStore, p->iTable, 1);
+@@ -263,7 +263,7 @@
+ void sqlite3ExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){
+   assert( pRight!=0 );
+   assert( pLeft!=0 );
+-  if( !sqlite3_malloc_failed && pRight->z && pLeft->z ){
++  if( !sqlite3MallocFailed() && pRight->z && pLeft->z ){
+     assert( pLeft->dyn==0 || pLeft->z[pLeft->n]==0 );
+     if( pLeft->dyn==0 && pRight->dyn==0 ){
+       pExpr->span.z = pLeft->z;
+@@ -280,6 +280,7 @@
+ */
+ Expr *sqlite3ExprFunction(ExprList *pList, Token *pToken){
+   Expr *pNew;
++  assert( pToken );
+   pNew = sqliteMalloc( sizeof(Expr) );
+   if( pNew==0 ){
+     sqlite3ExprListDelete(pList); /* Avoid leaking memory when malloc fails */
+@@ -287,12 +288,8 @@
+   }
+   pNew->op = TK_FUNCTION;
+   pNew->pList = pList;
+-  if( pToken ){
+-    assert( pToken->dyn==0 );
+-    pNew->token = *pToken;
+-  }else{
+-    pNew->token.z = 0;
+-  }
++  assert( pToken->dyn==0 );
++  pNew->token = *pToken;
+   pNew->span = pNew->token;
+   return pNew;
+ }
+@@ -327,7 +324,7 @@
+     /* Wildcard of the form "?nnn".  Convert "nnn" to an integer and
+     ** use it as the variable number */
+     int i;
+-    pExpr->iTable = i = atoi(&pToken->z[1]);
++    pExpr->iTable = i = atoi((char*)&pToken->z[1]);
+     if( i<1 || i>SQLITE_MAX_VARIABLE_NUMBER ){
+       sqlite3ErrorMsg(pParse, "variable number must be between ?1 and ?%d",
+           SQLITE_MAX_VARIABLE_NUMBER);
+@@ -355,10 +352,10 @@
+       pExpr->iTable = ++pParse->nVar;
+       if( pParse->nVarExpr>=pParse->nVarExprAlloc-1 ){
+         pParse->nVarExprAlloc += pParse->nVarExprAlloc + 10;
+-        sqlite3ReallocOrFree((void**)&pParse->apVarExpr,
++        sqliteReallocOrFree((void**)&pParse->apVarExpr,
+                        pParse->nVarExprAlloc*sizeof(pParse->apVarExpr[0]) );
+       }
+-      if( !sqlite3_malloc_failed ){
++      if( !sqlite3MallocFailed() ){
+         assert( pParse->apVarExpr!=0 );
+         pParse->apVarExpr[pParse->nVarExpr++] = pExpr;
+       }
+@@ -415,7 +412,7 @@
+   if( pNew==0 ) return 0;
+   memcpy(pNew, p, sizeof(*pNew));
+   if( p->token.z!=0 ){
+-    pNew->token.z = sqliteStrNDup(p->token.z, p->token.n);
++    pNew->token.z = (u8*)sqliteStrNDup((char*)p->token.z, p->token.n);
+     pNew->token.dyn = 1;
+   }else{
+     assert( pNew->token.z==0 );
+@@ -432,7 +429,7 @@
+   if( pTo->dyn ) sqliteFree((char*)pTo->z);
+   if( pFrom->z ){
+     pTo->n = pFrom->n;
+-    pTo->z = sqliteStrNDup(pFrom->z, pFrom->n);
++    pTo->z = (u8*)sqliteStrNDup((char*)pFrom->z, pFrom->n);
+     pTo->dyn = 1;
+   }else{
+     pTo->z = 0;
+@@ -462,7 +459,8 @@
+       sqlite3TokenCopy(&pNewExpr->span, &pOldExpr->span);
+     }
+     assert( pNewExpr==0 || pNewExpr->span.z!=0 
+-            || pOldExpr->span.z==0 || sqlite3_malloc_failed );
++            || pOldExpr->span.z==0
++            || sqlite3MallocFailed() );
+     pItem->zName = sqliteStrDup(pOldItem->zName);
+     pItem->sortOrder = pOldItem->sortOrder;
+     pItem->isAgg = pOldItem->isAgg;
+@@ -497,6 +495,7 @@
+     pNewItem->zAlias = sqliteStrDup(pOldItem->zAlias);
+     pNewItem->jointype = pOldItem->jointype;
+     pNewItem->iCursor = pOldItem->iCursor;
++    pNewItem->isPopulated = pOldItem->isPopulated;
+     pTab = pNewItem->pTab = pOldItem->pTab;
+     if( pTab ){
+       pTab->nRef++;
+@@ -752,7 +751,7 @@
+ int sqlite3ExprIsInteger(Expr *p, int *pValue){
+   switch( p->op ){
+     case TK_INTEGER: {
+-      if( sqlite3GetInt32(p->token.z, pValue) ){
++      if( sqlite3GetInt32((char*)p->token.z, pValue) ){
+         return 1;
+       }
+       break;
+@@ -809,7 +808,7 @@
+ ** in pParse and return non-zero.  Return zero on success.
+ */
+ static int lookupName(
+-  Parse *pParse,      /* The parsing context */
++  Parse *pParse,       /* The parsing context */
+   Token *pDbToken,     /* Name of the database containing table, or NULL */
+   Token *pTableToken,  /* Name of table containing column, or NULL */
+   Token *pColumnToken, /* Name of the column. */
+@@ -831,19 +830,19 @@
+   zDb = sqlite3NameFromToken(pDbToken);
+   zTab = sqlite3NameFromToken(pTableToken);
+   zCol = sqlite3NameFromToken(pColumnToken);
+-  if( sqlite3_malloc_failed ){
++  if( sqlite3MallocFailed() ){
+     goto lookupname_end;
+   }
+ 
+   pExpr->iTable = -1;
+   while( pNC && cnt==0 ){
++    ExprList *pEList;
+     SrcList *pSrcList = pNC->pSrcList;
+-    ExprList *pEList = pNC->pEList;
+ 
+-    /* assert( zTab==0 || pEList==0 ); */
+     if( pSrcList ){
+       for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
+         Table *pTab = pItem->pTab;
++        int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
+         Column *pCol;
+   
+         if( pTab==0 ) continue;
+@@ -855,27 +854,28 @@
+           }else{
+             char *zTabName = pTab->zName;
+             if( zTabName==0 || sqlite3StrICmp(zTabName, zTab)!=0 ) continue;
+-            if( zDb!=0 && sqlite3StrICmp(db->aDb[pTab->iDb].zName, zDb)!=0 ){
++            if( zDb!=0 && sqlite3StrICmp(db->aDb[iDb].zName, zDb)!=0 ){
+               continue;
+             }
+           }
+         }
+         if( 0==(cntTab++) ){
+           pExpr->iTable = pItem->iCursor;
+-          pExpr->iDb = pTab->iDb;
++          pExpr->pSchema = pTab->pSchema;
+           pMatch = pItem;
+         }
+         for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
+           if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
++            const char *zColl = pTab->aCol[j].zColl;
+             IdList *pUsing;
+             cnt++;
+             pExpr->iTable = pItem->iCursor;
+             pMatch = pItem;
+-            pExpr->iDb = pTab->iDb;
++            pExpr->pSchema = pTab->pSchema;
+             /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
+             pExpr->iColumn = j==pTab->iPKey ? -1 : j;
+             pExpr->affinity = pTab->aCol[j].affinity;
+-            pExpr->pColl = pTab->aCol[j].pColl;
++            pExpr->pColl = sqlite3FindCollSeq(db, ENC(db), zColl,-1, 0);
+             if( pItem->jointype & JT_NATURAL ){
+               /* If this match occurred in the left table of a natural join,
+               ** then skip the right table to avoid a duplicate match */
+@@ -919,17 +919,18 @@
+       }
+ 
+       if( pTab ){ 
+-        int j;
++        int iCol;
+         Column *pCol = pTab->aCol;
+ 
+-        pExpr->iDb = pTab->iDb;
++        pExpr->pSchema = pTab->pSchema;
+         cntTab++;
+-        for(j=0; j < pTab->nCol; j++, pCol++) {
++        for(iCol=0; iCol < pTab->nCol; iCol++, pCol++) {
+           if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
++            const char *zColl = pTab->aCol[iCol].zColl;
+             cnt++;
+-            pExpr->iColumn = j==pTab->iPKey ? -1 : j;
+-            pExpr->affinity = pTab->aCol[j].affinity;
+-            pExpr->pColl = pTab->aCol[j].pColl;
++            pExpr->iColumn = iCol==pTab->iPKey ? -1 : iCol;
++            pExpr->affinity = pTab->aCol[iCol].affinity;
++            pExpr->pColl = sqlite3FindCollSeq(db, ENC(db), zColl,-1, 0);
+             pExpr->pTab = pTab;
+             break;
+           }
+@@ -959,7 +960,7 @@
+     ** Note that the expression in the result set should have already been
+     ** resolved by the time the WHERE clause is resolved.
+     */
+-    if( cnt==0 && pEList!=0 && zTab==0 ){
++    if( cnt==0 && (pEList = pNC->pEList)!=0 && zTab==0 ){
+       for(j=0; j<pEList->nExpr; j++){
+         char *zAs = pEList->a[j].zName;
+         if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){
+@@ -1006,9 +1007,9 @@
+     char *zErr;
+     zErr = cnt==0 ? "no such column: %s" : "ambiguous column name: %s";
+     if( zDb ){
+-      sqlite3SetString(&z, zDb, ".", zTab, ".", zCol, 0);
++      sqlite3SetString(&z, zDb, ".", zTab, ".", zCol, (char*)0);
+     }else if( zTab ){
+-      sqlite3SetString(&z, zTab, ".", zCol, 0);
++      sqlite3SetString(&z, zTab, ".", zCol, (char*)0);
+     }else{
+       z = sqliteStrDup(zCol);
+     }
+@@ -1077,20 +1078,19 @@
+ */
+ static int nameResolverStep(void *pArg, Expr *pExpr){
+   NameContext *pNC = (NameContext*)pArg;
+-  SrcList *pSrcList;
+   Parse *pParse;
+ 
+   if( pExpr==0 ) return 1;
+   assert( pNC!=0 );
+-  pSrcList = pNC->pSrcList;
+   pParse = pNC->pParse;
+ 
+   if( ExprHasAnyProperty(pExpr, EP_Resolved) ) return 1;
+   ExprSetProperty(pExpr, EP_Resolved);
+ #ifndef NDEBUG
+-  if( pSrcList ){
++  if( pNC->pSrcList && pNC->pSrcList->nAlloc>0 ){
++    SrcList *pSrcList = pNC->pSrcList;
+     int i;
+-    for(i=0; i<pSrcList->nSrc; i++){
++    for(i=0; i<pNC->pSrcList->nSrc; i++){
+       assert( pSrcList->a[i].iCursor>=0 && pSrcList->a[i].iCursor<pParse->nTab);
+     }
+   }
+@@ -1149,9 +1149,9 @@
+       int nId;                    /* Number of characters in function name */
+       const char *zId;            /* The function name. */
+       FuncDef *pDef;              /* Information about the function */
+-      int enc = pParse->db->enc;  /* The database encoding */
++      int enc = ENC(pParse->db);  /* The database encoding */
+ 
+-      zId = pExpr->token.z;
++      zId = (char*)pExpr->token.z;
+       nId = pExpr->token.n;
+       pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0);
+       if( pDef==0 ){
+@@ -1197,13 +1197,27 @@
+     case TK_IN: {
+       if( pExpr->pSelect ){
+         int nRef = pNC->nRef;
++#ifndef SQLITE_OMIT_CHECK
++        if( pNC->isCheck ){
++          sqlite3ErrorMsg(pParse,"subqueries prohibited in CHECK constraints");
++        }
++#endif
+         sqlite3SelectResolve(pParse, pExpr->pSelect, pNC);
+         assert( pNC->nRef>=nRef );
+         if( nRef!=pNC->nRef ){
+           ExprSetProperty(pExpr, EP_VarSelect);
+         }
+       }
++      break;
+     }
++#ifndef SQLITE_OMIT_CHECK
++    case TK_VARIABLE: {
++      if( pNC->isCheck ){
++        sqlite3ErrorMsg(pParse,"parameters prohibited in CHECK constraints");
++      }
++      break;
++    }
++#endif
+   }
+   return 0;
+ }
+@@ -1261,17 +1275,16 @@
+ 
+ 
+ /*
+-** Generate code for subqueries and IN operators.
++** Generate code for scalar subqueries used as an expression
++** and IN operators.  Examples:
+ **
+-** IN operators comes in two forms:
++**     (SELECT a FROM b)          -- subquery
++**     EXISTS (SELECT a FROM b)   -- EXISTS subquery
++**     x IN (4,5,11)              -- IN operator with list on right-hand side
++**     x IN (SELECT a FROM b)     -- IN operator with subquery on the right
+ **
+-**           expr IN (exprlist)
+-** and
+-**           expr IN (SELECT ...)
+-**
+-** The first form is handled by creating a set holding the list
+-** of allowed values.  The second form causes the SELECT to generate 
+-** a temporary table.
++** The pExpr parameter describes the expression that contains the IN
++** operator or subquery.
+ */
+ #ifndef SQLITE_OMIT_SUBQUERY
+ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
+@@ -1293,7 +1306,7 @@
+     int mem = pParse->nMem++;
+     sqlite3VdbeAddOp(v, OP_MemLoad, mem, 0);
+     testAddr = sqlite3VdbeAddOp(v, OP_If, 0, 0);
+-    assert( testAddr>0 || sqlite3_malloc_failed );
++    assert( testAddr>0 || sqlite3MallocFailed() );
+     sqlite3VdbeAddOp(v, OP_MemInt, 1, mem);
+   }
+ 
+@@ -1367,9 +1380,9 @@
+           */
+           if( testAddr>0 && !sqlite3ExprIsConstant(pE2) ){
+             VdbeOp *aOp = sqlite3VdbeGetOp(v, testAddr-1);
+-            int i;
+-            for(i=0; i<3; i++){
+-              aOp[i].opcode = OP_Noop;
++            int j;
++            for(j=0; j<3; j++){
++              aOp[j].opcode = OP_Noop;
+             }
+             testAddr = 0;
+           }
+@@ -1390,21 +1403,25 @@
+       ** value of this select in a memory cell and record the number
+       ** of the memory cell in iColumn.
+       */
++      static const Token one = { (u8*)"1", 0, 1 };
++      Select *pSel;
++      int iMem;
+       int sop;
+-      Select *pSel;
+ 
+-      pExpr->iColumn = pParse->nMem++;
++      pExpr->iColumn = iMem = pParse->nMem++;
+       pSel = pExpr->pSelect;
+       if( pExpr->op==TK_SELECT ){
+         sop = SRT_Mem;
++        sqlite3VdbeAddOp(v, OP_MemNull, iMem, 0);
++        VdbeComment((v, "# Init subquery result"));
+       }else{
+-        static const Token one = { "1", 0, 1 };
+         sop = SRT_Exists;
+-        sqlite3ExprListDelete(pSel->pEList);
+-        pSel->pEList = sqlite3ExprListAppend(0, 
+-                          sqlite3Expr(TK_INTEGER, 0, 0, &one), 0);
++        sqlite3VdbeAddOp(v, OP_MemInt, 0, iMem);
++        VdbeComment((v, "# Init EXISTS result"));
+       }
+-      sqlite3Select(pParse, pSel, sop, pExpr->iColumn, 0, 0, 0, 0);
++      sqlite3ExprDelete(pSel->pLimit);
++      pSel->pLimit = sqlite3Expr(TK_INTEGER, 0, 0, &one);
++      sqlite3Select(pParse, pSel, sop, iMem, 0, 0, 0, 0);
+       break;
+     }
+   }
+@@ -1444,6 +1461,8 @@
+ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
+   Vdbe *v = pParse->pVdbe;
+   int op;
++  int stackChng = 1;    /* Amount of change to stack depth */
++
+   if( v==0 ) return;
+   if( pExpr==0 ){
+     sqlite3VdbeAddOp(v, OP_Null, 0, 0);
+@@ -1465,16 +1484,27 @@
+       /* Otherwise, fall thru into the TK_COLUMN case */
+     }
+     case TK_COLUMN: {
+-      if( pExpr->iColumn>=0 ){
+-        sqlite3VdbeAddOp(v, OP_Column, pExpr->iTable, pExpr->iColumn);
+-        sqlite3ColumnDefault(v, pExpr->pTab, pExpr->iColumn);
++      if( pExpr->iTable<0 ){
++        /* This only happens when coding check constraints */
++        assert( pParse->ckOffset>0 );
++        sqlite3VdbeAddOp(v, OP_Dup, pParse->ckOffset-pExpr->iColumn-1, 1);
++      }else if( pExpr->iColumn>=0 ){
++        Table *pTab = pExpr->pTab;
++        int iCol = pExpr->iColumn;
++        sqlite3VdbeAddOp(v, OP_Column, pExpr->iTable, iCol);
++        sqlite3ColumnDefault(v, pTab, iCol);
++#ifndef SQLITE_OMIT_FLOATING_POINT
++        if( pTab && pTab->aCol[iCol].affinity==SQLITE_AFF_REAL ){
++          sqlite3VdbeAddOp(v, OP_RealAffinity, 0, 0);
++        }
++#endif
+       }else{
+         sqlite3VdbeAddOp(v, OP_Rowid, pExpr->iTable, 0);
+       }
+       break;
+     }
+     case TK_INTEGER: {
+-      codeInteger(v, pExpr->token.z, pExpr->token.n);
++      codeInteger(v, (char*)pExpr->token.z, pExpr->token.n);
+       break;
+     }
+     case TK_FLOAT:
+@@ -1482,7 +1512,7 @@
+       assert( TK_FLOAT==OP_Real );
+       assert( TK_STRING==OP_String8 );
+       sqlite3DequoteExpr(pExpr);
+-      sqlite3VdbeOp3(v, op, 0, 0, pExpr->token.z, pExpr->token.n);
++      sqlite3VdbeOp3(v, op, 0, 0, (char*)pExpr->token.z, pExpr->token.n);
+       break;
+     }
+     case TK_NULL: {
+@@ -1495,7 +1525,7 @@
+       const char *z;
+       assert( TK_BLOB==OP_HexBlob );
+       n = pExpr->token.n - 3;
+-      z = pExpr->token.z + 2;
++      z = (char*)pExpr->token.z + 2;
+       assert( n>=0 );
+       if( n==0 ){
+         z = "";
+@@ -1507,7 +1537,7 @@
+     case TK_VARIABLE: {
+       sqlite3VdbeAddOp(v, OP_Variable, pExpr->iTable, 0);
+       if( pExpr->token.n>1 ){
+-        sqlite3VdbeChangeP3(v, -1, pExpr->token.z, pExpr->token.n);
++        sqlite3VdbeChangeP3(v, -1, (char*)pExpr->token.z, pExpr->token.n);
+       }
+       break;
+     }
+@@ -1518,16 +1548,17 @@
+ #ifndef SQLITE_OMIT_CAST
+     case TK_CAST: {
+       /* Expressions of the form:   CAST(pLeft AS token) */
+-      int aff, op;
++      int aff, to_op;
+       sqlite3ExprCode(pParse, pExpr->pLeft);
+       aff = sqlite3AffinityType(&pExpr->token);
+-      switch( aff ){
+-        case SQLITE_AFF_INTEGER:   op = OP_ToInt;      break;
+-        case SQLITE_AFF_NUMERIC:   op = OP_ToNumeric;  break;
+-        case SQLITE_AFF_TEXT:      op = OP_ToText;     break;
+-        case SQLITE_AFF_NONE:      op = OP_ToBlob;     break;
+-      }
+-      sqlite3VdbeAddOp(v, op, 0, 0);
++      to_op = aff - SQLITE_AFF_TEXT + OP_ToText;
++      assert( to_op==OP_ToText    || aff!=SQLITE_AFF_TEXT    );
++      assert( to_op==OP_ToBlob    || aff!=SQLITE_AFF_NONE    );
++      assert( to_op==OP_ToNumeric || aff!=SQLITE_AFF_NUMERIC );
++      assert( to_op==OP_ToInt     || aff!=SQLITE_AFF_INTEGER );
++      assert( to_op==OP_ToReal    || aff!=SQLITE_AFF_REAL    );
++      sqlite3VdbeAddOp(v, to_op, 0, 0);
++      stackChng = 0;
+       break;
+     }
+ #endif /* SQLITE_OMIT_CAST */
+@@ -1546,6 +1577,7 @@
+       sqlite3ExprCode(pParse, pExpr->pLeft);
+       sqlite3ExprCode(pParse, pExpr->pRight);
+       codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, 0, 0);
++      stackChng = -1;
+       break;
+     }
+     case TK_AND:
+@@ -1574,6 +1606,7 @@
+       sqlite3ExprCode(pParse, pExpr->pLeft);
+       sqlite3ExprCode(pParse, pExpr->pRight);
+       sqlite3VdbeAddOp(v, op, 0, 0);
++      stackChng = -1;
+       break;
+     }
+     case TK_UMINUS: {
+@@ -1581,8 +1614,7 @@
+       assert( pLeft );
+       if( pLeft->op==TK_FLOAT || pLeft->op==TK_INTEGER ){
+         Token *p = &pLeft->token;
+-        char *z = sqliteMalloc( p->n + 2 );
+-        sprintf(z, "-%.*s", p->n, p->z);
++        char *z = sqlite3MPrintf("-%.*s", p->n, p->z);
+         if( pLeft->op==TK_FLOAT ){
+           sqlite3VdbeOp3(v, OP_Real, 0, 0, z, p->n+1);
+         }else{
+@@ -1599,6 +1631,7 @@
+       assert( TK_NOT==OP_Not );
+       sqlite3ExprCode(pParse, pExpr->pLeft);
+       sqlite3VdbeAddOp(v, op, 0, 0);
++      stackChng = 0;
+       break;
+     }
+     case TK_ISNULL:
+@@ -1611,11 +1644,17 @@
+       dest = sqlite3VdbeCurrentAddr(v) + 2;
+       sqlite3VdbeAddOp(v, op, 1, dest);
+       sqlite3VdbeAddOp(v, OP_AddImm, -1, 0);
++      stackChng = 0;
+       break;
+     }
+     case TK_AGG_FUNCTION: {
+       AggInfo *pInfo = pExpr->pAggInfo;
+-      sqlite3VdbeAddOp(v, OP_MemLoad, pInfo->aFunc[pExpr->iAgg].iMem, 0);
++      if( pInfo==0 ){
++        sqlite3ErrorMsg(pParse, "misuse of aggregate: %T",
++            &pExpr->span);
++      }else{
++        sqlite3VdbeAddOp(v, OP_MemLoad, pInfo->aFunc[pExpr->iAgg].iMem, 0);
++      }
+       break;
+     }
+     case TK_CONST_FUNC:
+@@ -1627,9 +1666,9 @@
+       const char *zId;
+       int constMask = 0;
+       int i;
+-      u8 enc = pParse->db->enc;
++      u8 enc = ENC(pParse->db);
+       CollSeq *pColl = 0;
+-      zId = pExpr->token.z;
++      zId = (char*)pExpr->token.z;
+       nId = pExpr->token.n;
+       pDef = sqlite3FindFunction(pParse->db, zId, nId, nExpr, enc, 0);
+       assert( pDef!=0 );
+@@ -1647,6 +1686,7 @@
+         sqlite3VdbeOp3(v, OP_CollSeq, 0, 0, (char *)pColl, P3_COLLSEQ);
+       }
+       sqlite3VdbeOp3(v, OP_Function, constMask, nExpr, (char*)pDef, P3_FUNCDEF);
++      stackChng = 1-nExpr;
+       break;
+     }
+ #ifndef SQLITE_OMIT_SUBQUERY
+@@ -1660,6 +1700,7 @@
+     case TK_IN: {
+       int addr;
+       char affinity;
++      int ckOffset = pParse->ckOffset;
+       sqlite3CodeSubselect(pParse, pExpr);
+ 
+       /* Figure out the affinity to use to create a key from the results
+@@ -1669,6 +1710,7 @@
+       affinity = comparisonAffinity(pExpr);
+ 
+       sqlite3VdbeAddOp(v, OP_Integer, 1, 0);
++      pParse->ckOffset = ckOffset+1;
+ 
+       /* Code the <expr> from "<expr> IN (...)". The temporary table
+       ** pExpr->iTable contains the values that make up the (...) set.
+@@ -1705,6 +1747,7 @@
+     case TK_UPLUS:
+     case TK_AS: {
+       sqlite3ExprCode(pParse, pExpr->pLeft);
++      stackChng = 0;
+       break;
+     }
+     case TK_CASE: {
+@@ -1763,17 +1806,23 @@
+                  pExpr->iColumn == OE_Fail );
+          sqlite3DequoteExpr(pExpr);
+          sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, pExpr->iColumn,
+-                        pExpr->token.z, pExpr->token.n);
++                        (char*)pExpr->token.z, pExpr->token.n);
+       } else {
+          assert( pExpr->iColumn == OE_Ignore );
+          sqlite3VdbeAddOp(v, OP_ContextPop, 0, 0);
+          sqlite3VdbeAddOp(v, OP_Goto, 0, pParse->trigStack->ignoreJump);
+          VdbeComment((v, "# raise(IGNORE)"));
+       }
++      stackChng = 0;
++      break;
+     }
+ #endif
+-    break;
+   }
++
++  if( pParse->ckOffset ){
++    pParse->ckOffset += stackChng;
++    assert( pParse->ckOffset );
++  }
+ }
+ 
+ #ifndef SQLITE_OMIT_TRIGGER
+@@ -1840,6 +1889,7 @@
+ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
+   Vdbe *v = pParse->pVdbe;
+   int op = 0;
++  int ckOffset = pParse->ckOffset;
+   if( v==0 || pExpr==0 ) return;
+   op = pExpr->op;
+   switch( op ){
+@@ -1914,6 +1964,7 @@
+       break;
+     }
+   }
++  pParse->ckOffset = ckOffset;
+ }
+ 
+ /*
+@@ -1927,6 +1978,7 @@
+ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
+   Vdbe *v = pParse->pVdbe;
+   int op = 0;
++  int ckOffset = pParse->ckOffset;
+   if( v==0 || pExpr==0 ) return;
+ 
+   /* The value of pExpr->op and op are related as follows:
+@@ -2023,6 +2075,7 @@
+       break;
+     }
+   }
++  pParse->ckOffset = ckOffset;
+ }
+ 
+ /*
+@@ -2031,10 +2084,8 @@
+ */
+ int sqlite3ExprCompare(Expr *pA, Expr *pB){
+   int i;
+-  if( pA==0 ){
+-    return pB==0;
+-  }else if( pB==0 ){
+-    return 0;
++  if( pA==0||pB==0 ){
++    return pB==pA;
+   }
+   if( pA->op!=pB->op ) return 0;
+   if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 0;
+@@ -2056,7 +2107,9 @@
+   if( pA->token.z ){
+     if( pB->token.z==0 ) return 0;
+     if( pB->token.n!=pA->token.n ) return 0;
+-    if( sqlite3StrNICmp(pA->token.z, pB->token.z, pB->token.n)!=0 ) return 0;
++    if( sqlite3StrNICmp((char*)pA->token.z,(char*)pB->token.z,pB->token.n)!=0 ){
++      return 0;
++    }
+   }
+   return 1;
+ }
+@@ -2180,14 +2233,14 @@
+         if( i>=pAggInfo->nFunc ){
+           /* pExpr is original.  Make a new entry in pAggInfo->aFunc[]
+           */
+-          u8 enc = pParse->db->enc;
++          u8 enc = ENC(pParse->db);
+           i = addAggInfoFunc(pAggInfo);
+           if( i>=0 ){
+             pItem = &pAggInfo->aFunc[i];
+             pItem->pExpr = pExpr;
+             pItem->iMem = pParse->nMem++;
+             pItem->pFunc = sqlite3FindFunction(pParse->db,
+-                   pExpr->token.z, pExpr->token.n,
++                   (char*)pExpr->token.z, pExpr->token.n,
+                    pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0);
+             if( pExpr->flags & EP_Distinct ){
+               pItem->iDistinct = pParse->nTab++;
+Index: sqlite/parse.h
+===================================================================
+--- amarok/src/sqlite/parse.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/parse.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -1,145 +1,151 @@
+-#define TK_END_OF_FILE                     1
+-#define TK_ILLEGAL                         2
+-#define TK_SPACE                           3
+-#define TK_UNCLOSED_STRING                 4
+-#define TK_COMMENT                         5
+-#define TK_FUNCTION                        6
+-#define TK_COLUMN                          7
+-#define TK_AGG_FUNCTION                    8
+-#define TK_AGG_COLUMN                      9
+-#define TK_CONST_FUNC                     10
+-#define TK_SEMI                           11
+-#define TK_EXPLAIN                        12
+-#define TK_QUERY                          13
+-#define TK_PLAN                           14
+-#define TK_BEGIN                          15
+-#define TK_TRANSACTION                    16
+-#define TK_DEFERRED                       17
+-#define TK_IMMEDIATE                      18
+-#define TK_EXCLUSIVE                      19
+-#define TK_COMMIT                         20
+-#define TK_END                            21
+-#define TK_ROLLBACK                       22
+-#define TK_CREATE                         23
+-#define TK_TABLE                          24
+-#define TK_TEMP                           25
+-#define TK_LP                             26
+-#define TK_RP                             27
+-#define TK_AS                             28
+-#define TK_COMMA                          29
+-#define TK_ID                             30
+-#define TK_ABORT                          31
+-#define TK_AFTER                          32
+-#define TK_ANALYZE                        33
+-#define TK_ASC                            34
+-#define TK_ATTACH                         35
+-#define TK_BEFORE                         36
+-#define TK_CASCADE                        37
+-#define TK_CAST                           38
+-#define TK_CONFLICT                       39
+-#define TK_DATABASE                       40
+-#define TK_DESC                           41
+-#define TK_DETACH                         42
+-#define TK_EACH                           43
+-#define TK_FAIL                           44
+-#define TK_FOR                            45
+-#define TK_IGNORE                         46
+-#define TK_INITIALLY                      47
+-#define TK_INSTEAD                        48
+-#define TK_LIKE_KW                        49
+-#define TK_MATCH                          50
+-#define TK_KEY                            51
+-#define TK_OF                             52
+-#define TK_OFFSET                         53
+-#define TK_PRAGMA                         54
+-#define TK_RAISE                          55
+-#define TK_REPLACE                        56
+-#define TK_RESTRICT                       57
+-#define TK_ROW                            58
+-#define TK_STATEMENT                      59
+-#define TK_TRIGGER                        60
+-#define TK_VACUUM                         61
+-#define TK_VIEW                           62
+-#define TK_REINDEX                        63
+-#define TK_RENAME                         64
+-#define TK_CTIME_KW                       65
+-#define TK_ALTER                          66
+-#define TK_OR                             67
+-#define TK_AND                            68
+-#define TK_NOT                            69
+-#define TK_IS                             70
+-#define TK_BETWEEN                        71
+-#define TK_IN                             72
+-#define TK_ISNULL                         73
+-#define TK_NOTNULL                        74
+-#define TK_NE                             75
+-#define TK_EQ                             76
+-#define TK_GT                             77
+-#define TK_LE                             78
+-#define TK_LT                             79
+-#define TK_GE                             80
+-#define TK_ESCAPE                         81
+-#define TK_BITAND                         82
+-#define TK_BITOR                          83
+-#define TK_LSHIFT                         84
+-#define TK_RSHIFT                         85
+-#define TK_PLUS                           86
+-#define TK_MINUS                          87
+-#define TK_STAR                           88
+-#define TK_SLASH                          89
+-#define TK_REM                            90
+-#define TK_CONCAT                         91
+-#define TK_UMINUS                         92
+-#define TK_UPLUS                          93
+-#define TK_BITNOT                         94
+-#define TK_STRING                         95
+-#define TK_JOIN_KW                        96
+-#define TK_CONSTRAINT                     97
+-#define TK_DEFAULT                        98
+-#define TK_NULL                           99
+-#define TK_PRIMARY                        100
+-#define TK_UNIQUE                         101
+-#define TK_CHECK                          102
+-#define TK_REFERENCES                     103
+-#define TK_COLLATE                        104
+-#define TK_AUTOINCR                       105
+-#define TK_ON                             106
+-#define TK_DELETE                         107
+-#define TK_UPDATE                         108
+-#define TK_INSERT                         109
+-#define TK_SET                            110
+-#define TK_DEFERRABLE                     111
+-#define TK_FOREIGN                        112
+-#define TK_DROP                           113
+-#define TK_UNION                          114
+-#define TK_ALL                            115
+-#define TK_INTERSECT                      116
+-#define TK_EXCEPT                         117
+-#define TK_SELECT                         118
+-#define TK_DISTINCT                       119
+-#define TK_DOT                            120
+-#define TK_FROM                           121
+-#define TK_JOIN                           122
+-#define TK_USING                          123
+-#define TK_ORDER                          124
+-#define TK_BY                             125
+-#define TK_GROUP                          126
+-#define TK_HAVING                         127
+-#define TK_LIMIT                          128
+-#define TK_WHERE                          129
+-#define TK_INTO                           130
+-#define TK_VALUES                         131
+-#define TK_INTEGER                        132
+-#define TK_FLOAT                          133
+-#define TK_BLOB                           134
+-#define TK_REGISTER                       135
+-#define TK_VARIABLE                       136
+-#define TK_EXISTS                         137
+-#define TK_CASE                           138
+-#define TK_WHEN                           139
+-#define TK_THEN                           140
+-#define TK_ELSE                           141
+-#define TK_INDEX                          142
+-#define TK_TO                             143
+-#define TK_ADD                            144
+-#define TK_COLUMNKW                       145
++#define TK_SEMI                            1
++#define TK_EXPLAIN                         2
++#define TK_QUERY                           3
++#define TK_PLAN                            4
++#define TK_BEGIN                           5
++#define TK_TRANSACTION                     6
++#define TK_DEFERRED                        7
++#define TK_IMMEDIATE                       8
++#define TK_EXCLUSIVE                       9
++#define TK_COMMIT                         10
++#define TK_END                            11
++#define TK_ROLLBACK                       12
++#define TK_CREATE                         13
++#define TK_TABLE                          14
++#define TK_IF                             15
++#define TK_NOT                            16
++#define TK_EXISTS                         17
++#define TK_TEMP                           18
++#define TK_LP                             19
++#define TK_RP                             20
++#define TK_AS                             21
++#define TK_COMMA                          22
++#define TK_ID                             23
++#define TK_ABORT                          24
++#define TK_AFTER                          25
++#define TK_ANALYZE                        26
++#define TK_ASC                            27
++#define TK_ATTACH                         28
++#define TK_BEFORE                         29
++#define TK_CASCADE                        30
++#define TK_CAST                           31
++#define TK_CONFLICT                       32
++#define TK_DATABASE                       33
++#define TK_DESC                           34
++#define TK_DETACH                         35
++#define TK_EACH                           36
++#define TK_FAIL                           37
++#define TK_FOR                            38
++#define TK_IGNORE                         39
++#define TK_INITIALLY                      40
++#define TK_INSTEAD                        41
++#define TK_LIKE_KW                        42
++#define TK_MATCH                          43
++#define TK_KEY                            44
++#define TK_OF                             45
++#define TK_OFFSET                         46
++#define TK_PRAGMA                         47
++#define TK_RAISE                          48
++#define TK_REPLACE                        49
++#define TK_RESTRICT                       50
++#define TK_ROW                            51
++#define TK_STATEMENT                      52
++#define TK_TRIGGER                        53
++#define TK_VACUUM                         54
++#define TK_VIEW                           55
++#define TK_REINDEX                        56
++#define TK_RENAME                         57
++#define TK_CTIME_KW                       58
++#define TK_OR                             59
++#define TK_AND                            60
++#define TK_IS                             61
++#define TK_BETWEEN                        62
++#define TK_IN                             63
++#define TK_ISNULL                         64
++#define TK_NOTNULL                        65
++#define TK_NE                             66
++#define TK_EQ                             67
++#define TK_GT                             68
++#define TK_LE                             69
++#define TK_LT                             70
++#define TK_GE                             71
++#define TK_ESCAPE                         72
++#define TK_BITAND                         73
++#define TK_BITOR                          74
++#define TK_LSHIFT                         75
++#define TK_RSHIFT                         76
++#define TK_PLUS                           77
++#define TK_MINUS                          78
++#define TK_STAR                           79
++#define TK_SLASH                          80
++#define TK_REM                            81
++#define TK_CONCAT                         82
++#define TK_UMINUS                         83
++#define TK_UPLUS                          84
++#define TK_BITNOT                         85
++#define TK_STRING                         86
++#define TK_JOIN_KW                        87
++#define TK_CONSTRAINT                     88
++#define TK_DEFAULT                        89
++#define TK_NULL                           90
++#define TK_PRIMARY                        91
++#define TK_UNIQUE                         92
++#define TK_CHECK                          93
++#define TK_REFERENCES                     94
++#define TK_COLLATE                        95
++#define TK_AUTOINCR                       96
++#define TK_ON                             97
++#define TK_DELETE                         98
++#define TK_UPDATE                         99
++#define TK_INSERT                         100
++#define TK_SET                            101
++#define TK_DEFERRABLE                     102
++#define TK_FOREIGN                        103
++#define TK_DROP                           104
++#define TK_UNION                          105
++#define TK_ALL                            106
++#define TK_EXCEPT                         107
++#define TK_INTERSECT                      108
++#define TK_SELECT                         109
++#define TK_DISTINCT                       110
++#define TK_DOT                            111
++#define TK_FROM                           112
++#define TK_JOIN                           113
++#define TK_USING                          114
++#define TK_ORDER                          115
++#define TK_BY                             116
++#define TK_GROUP                          117
++#define TK_HAVING                         118
++#define TK_LIMIT                          119
++#define TK_WHERE                          120
++#define TK_INTO                           121
++#define TK_VALUES                         122
++#define TK_INTEGER                        123
++#define TK_FLOAT                          124
++#define TK_BLOB                           125
++#define TK_REGISTER                       126
++#define TK_VARIABLE                       127
++#define TK_CASE                           128
++#define TK_WHEN                           129
++#define TK_THEN                           130
++#define TK_ELSE                           131
++#define TK_INDEX                          132
++#define TK_ALTER                          133
++#define TK_TO                             134
++#define TK_ADD                            135
++#define TK_COLUMNKW                       136
++#define TK_TO_TEXT                        137
++#define TK_TO_BLOB                        138
++#define TK_TO_NUMERIC                     139
++#define TK_TO_INT                         140
++#define TK_TO_REAL                        141
++#define TK_END_OF_FILE                    142
++#define TK_ILLEGAL                        143
++#define TK_SPACE                          144
++#define TK_UNCLOSED_STRING                145
++#define TK_COMMENT                        146
++#define TK_FUNCTION                       147
++#define TK_COLUMN                         148
++#define TK_AGG_FUNCTION                   149
++#define TK_AGG_COLUMN                     150
++#define TK_CONST_FUNC                     151
+Index: sqlite/vdbemem.c
+===================================================================
+--- amarok/src/sqlite/vdbemem.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/vdbemem.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -41,11 +41,21 @@
+ #ifdef SQLITE_OMIT_UTF16
+   return SQLITE_ERROR;
+ #else
++
++  /* MemTranslate() may return SQLITE_OK or SQLITE_NOMEM. If NOMEM is returned,
++  ** then the encoding of the value may not have changed.
++  */
+   rc = sqlite3VdbeMemTranslate(pMem, desiredEnc);
++  assert(rc==SQLITE_OK    || rc==SQLITE_NOMEM);
++  assert(rc==SQLITE_OK    || pMem->enc!=desiredEnc);
++  assert(rc==SQLITE_NOMEM || pMem->enc==desiredEnc);
++
+   if( rc==SQLITE_NOMEM ){
++/*
+     sqlite3VdbeMemRelease(pMem);
+     pMem->flags = MEM_Null;
+     pMem->z = 0;
++*/
+   }
+   return rc;
+ #endif
+@@ -73,7 +83,7 @@
+   memcpy(z, pMem->z, n );
+   z[n] = 0;
+   z[n+1] = 0;
+-  pMem->z = z;
++  pMem->z = (char*)z;
+   pMem->flags &= ~(MEM_Ephem|MEM_Static|MEM_Short);
+   return SQLITE_OK;
+ }
+@@ -93,7 +103,7 @@
+   assert( (pMem->flags & MEM_Dyn)==0 );
+   assert( pMem->flags & (MEM_Str|MEM_Blob) );
+   if( (n = pMem->n)+2<sizeof(pMem->zShort) ){
+-    z = pMem->zShort;
++    z = (u8*)pMem->zShort;
+     pMem->flags |= MEM_Short|MEM_Term;
+   }else{
+     z = sqliteMallocRaw( n+2 );
+@@ -106,7 +116,7 @@
+   memcpy(z, pMem->z, n );
+   z[n] = 0;
+   z[n+1] = 0;
+-  pMem->z = z;
++  pMem->z = (char*)z;
+   pMem->flags &= ~(MEM_Ephem|MEM_Static);
+   return SQLITE_OK;
+ }
+@@ -162,7 +172,7 @@
+ int sqlite3VdbeMemStringify(Mem *pMem, int enc){
+   int rc = SQLITE_OK;
+   int fg = pMem->flags;
+-  u8 *z = pMem->zShort;
++  char *z = pMem->zShort;
+ 
+   assert( !(fg&(MEM_Str|MEM_Blob)) );
+   assert( fg&(MEM_Int|MEM_Real) );
+@@ -173,11 +183,11 @@
+   ** 
+   ** FIX ME: It would be better if sqlite3_snprintf() could do UTF-16.
+   */
+-  if( fg & MEM_Real ){
++  if( fg & MEM_Int ){
++    sqlite3_snprintf(NBFS, z, "%lld", pMem->i);
++  }else{
++    assert( fg & MEM_Real );
+     sqlite3_snprintf(NBFS, z, "%!.15g", pMem->r);
+-  }else{
+-    assert( fg & MEM_Int );
+-    sqlite3_snprintf(NBFS, z, "%lld", pMem->i);
+   }
+   pMem->n = strlen(z);
+   pMem->z = z;
+@@ -191,8 +201,12 @@
+ ** Memory cell pMem contains the context of an aggregate function.
+ ** This routine calls the finalize method for that function.  The
+ ** result of the aggregate is stored back into pMem.
++**
++** Return SQLITE_ERROR if the finalizer reports an error.  SQLITE_OK
++** otherwise.
+ */
+-void sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
++int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
++  int rc = SQLITE_OK;
+   if( pFunc && pFunc->xFinalize ){
+     sqlite3_context ctx;
+     assert( (pMem->flags & MEM_Null)!=0 || pFunc==*(FuncDef**)&pMem->i );
+@@ -200,6 +214,7 @@
+     ctx.s.z = pMem->zShort;
+     ctx.pMem = pMem;
+     ctx.pFunc = pFunc;
++    ctx.isError = 0;
+     pFunc->xFinalize(&ctx);
+     if( pMem->z && pMem->z!=pMem->zShort ){
+       sqliteFree( pMem->z );
+@@ -208,7 +223,11 @@
+     if( pMem->flags & MEM_Short ){
+       pMem->z = pMem->zShort;
+     }
++    if( ctx.isError ){
++      rc = SQLITE_ERROR;
++    }
+   }
++  return rc;
+ }
+ 
+ /*
+@@ -254,7 +273,7 @@
+     i64 value;
+     if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8)
+        || sqlite3VdbeMemNulTerminate(pMem) ){
+-      return SQLITE_NOMEM;
++      return 0;
+     }
+     assert( pMem->z );
+     sqlite3atoi64(pMem->z, &value);
+@@ -265,16 +284,6 @@
+ }
+ 
+ /*
+-** Convert pMem to type integer.  Invalidate any prior representations.
+-*/
+-int sqlite3VdbeMemIntegerify(Mem *pMem){
+-  pMem->i = sqlite3VdbeIntValue(pMem);
+-  sqlite3VdbeMemRelease(pMem);
+-  pMem->flags = MEM_Int;
+-  return SQLITE_OK;
+-}
+-
+-/*
+ ** Return the best representation of pMem that we can get into a
+ ** double.  If pMem is already a double or an integer, return its
+ ** value.  If it is a string or blob, try to convert it to a double.
+@@ -289,7 +298,7 @@
+     double val = 0.0;
+     if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8)
+        || sqlite3VdbeMemNulTerminate(pMem) ){
+-      return SQLITE_NOMEM;
++      return 0.0;
+     }
+     assert( pMem->z );
+     sqlite3AtoF(pMem->z, &val);
+@@ -300,9 +309,31 @@
+ }
+ 
+ /*
+-** Convert pMem so that it is of type MEM_Real.  Invalidate any
+-** prior representations.
++** The MEM structure is already a MEM_Real.  Try to also make it a
++** MEM_Int if we can.
+ */
++void sqlite3VdbeIntegerAffinity(Mem *pMem){
++  assert( pMem->flags & MEM_Real );
++  pMem->i = pMem->r;
++  if( ((double)pMem->i)==pMem->r ){
++    pMem->flags |= MEM_Int;
++  }
++}
++
++/*
++** Convert pMem to type integer.  Invalidate any prior representations.
++*/
++int sqlite3VdbeMemIntegerify(Mem *pMem){
++  pMem->i = sqlite3VdbeIntValue(pMem);
++  sqlite3VdbeMemRelease(pMem);
++  pMem->flags = MEM_Int;
++  return SQLITE_OK;
++}
++
++/*
++** Convert pMem so that it is of type MEM_Real.
++** Invalidate any prior representations.
++*/
+ int sqlite3VdbeMemRealify(Mem *pMem){
+   pMem->r = sqlite3VdbeRealValue(pMem);
+   sqlite3VdbeMemRelease(pMem);
+@@ -311,6 +342,16 @@
+ }
+ 
+ /*
++** Convert pMem so that it has types MEM_Real or MEM_Int or both.
++** Invalidate any prior representations.
++*/
++int sqlite3VdbeMemNumerify(Mem *pMem){
++  sqlite3VdbeMemRealify(pMem);
++  sqlite3VdbeIntegerAffinity(pMem);
++  return SQLITE_OK;
++}
++
++/*
+ ** Delete any previous value and set the value stored in *pMem to NULL.
+ */
+ void sqlite3VdbeMemSetNull(Mem *pMem){
+@@ -547,9 +588,9 @@
+     assert( pMem1->enc==SQLITE_UTF8 || 
+             pMem1->enc==SQLITE_UTF16LE || pMem1->enc==SQLITE_UTF16BE );
+ 
+-    /* This assert may fail if the collation sequence is deleted after this
+-    ** vdbe program is compiled. The documentation defines this as an
+-    ** undefined condition. A crash is usual result.
++    /* The collation sequence must be defined at this point, even if
++    ** the user deletes the collation sequence after the vdbe program is
++    ** compiled (this was not always the case).
+     */
+     assert( !pColl || pColl->xCmp );
+ 
+@@ -719,12 +760,15 @@
+   if( pVal->flags&MEM_Null ){
+     return 0;
+   }
++  assert( (MEM_Blob>>3) == MEM_Str );
++  pVal->flags |= (pVal->flags & MEM_Blob)>>3;
+   if( pVal->flags&MEM_Str ){
+     sqlite3VdbeChangeEncoding(pVal, enc);
+   }else if( !(pVal->flags&MEM_Blob) ){
+     sqlite3VdbeMemStringify(pVal, enc);
+   }
+-  return (const void *)(pVal->z);
++  assert(pVal->enc==enc || sqlite3MallocFailed() );
++  return (const void *)(pVal->enc==enc ? (pVal->z) : 0);
+ }
+ 
+ /*
+@@ -766,7 +810,7 @@
+   op = pExpr->op;
+ 
+   if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){
+-    zVal = sqliteStrNDup(pExpr->token.z, pExpr->token.n);
++    zVal = sqliteStrNDup((char*)pExpr->token.z, pExpr->token.n);
+     pVal = sqlite3ValueNew();
+     if( !zVal || !pVal ) goto no_mem;
+     sqlite3Dequote(zVal);
+@@ -786,7 +830,7 @@
+   else if( op==TK_BLOB ){
+     int nVal;
+     pVal = sqlite3ValueNew();
+-    zVal = sqliteStrNDup(pExpr->token.z+1, pExpr->token.n-1);
++    zVal = sqliteStrNDup((char*)pExpr->token.z+1, pExpr->token.n-1);
+     if( !zVal || !pVal ) goto no_mem;
+     sqlite3Dequote(zVal);
+     nVal = strlen(zVal)/2;
+Index: sqlite/vdbe.c
+===================================================================
+--- amarok/src/sqlite/vdbe.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/vdbe.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -101,6 +101,22 @@
+ */
+ #define Dynamicify(P,enc) sqlite3VdbeMemDynamicify(P)
+ 
++/*
++** The header of a record consists of a sequence variable-length integers.
++** These integers are almost always small and are encoded as a single byte.
++** The following macro takes advantage this fact to provide a fast decode
++** of the integers in a record header.  It is faster for the common case
++** where the integer is a single byte.  It is a little slower when the
++** integer is two or more bytes.  But overall it is faster.
++**
++** The following expressions are equivalent:
++**
++**     x = sqlite3GetVarint32( A, &B );
++**
++**     x = GetVarint( A, B );
++**
++*/
++#define GetVarint(A,B)  ((B = *(A))<=0x7f ? 1 : sqlite3GetVarint32(A, &B))
+ 
+ /*
+ ** An ephemeral string value (signified by the MEM_Ephem flag) contains
+@@ -118,23 +134,6 @@
+        && sqlite3VdbeMemMakeWriteable(P) ){ goto no_mem;}
+ 
+ /*
+-** Convert the given stack entity into a integer if it isn't one
+-** already.
+-**
+-** Any prior string or real representation is invalidated.  
+-** NULLs are converted into 0.
+-*/
+-#define Integerify(P) sqlite3VdbeMemIntegerify(P)
+-
+-/*
+-** Convert P so that it has type MEM_Real.
+-**
+-** Any prior string or integer representation is invalidated.
+-** NULLs are converted into 0.0.
+-*/
+-#define Realify(P) sqlite3VdbeMemRealify(P)
+-
+-/*
+ ** Argument pMem points at a memory cell that will be passed to a
+ ** user-defined function or returned to the user as the result of a query.
+ ** The second argument, 'db_enc' is the text encoding used by the vdbe for
+@@ -177,30 +176,64 @@
+ ** Allocate cursor number iCur.  Return a pointer to it.  Return NULL
+ ** if we run out of memory.
+ */
+-static Cursor *allocateCursor(Vdbe *p, int iCur){
++static Cursor *allocateCursor(Vdbe *p, int iCur, int iDb){
+   Cursor *pCx;
+   assert( iCur<p->nCursor );
+   if( p->apCsr[iCur] ){
+     sqlite3VdbeFreeCursor(p->apCsr[iCur]);
+   }
+   p->apCsr[iCur] = pCx = sqliteMalloc( sizeof(Cursor) );
++  if( pCx ){
++    pCx->iDb = iDb;
++  }
+   return pCx;
+ }
+ 
+ /*
+-** Apply any conversion required by the supplied column affinity to
+-** memory cell pRec. affinity may be one of:
++** Try to convert a value into a numeric representation if we can
++** do so without loss of information.  In other words, if the string
++** looks like a number, convert it into a number.  If it does not
++** look like a number, leave it alone.
++*/
++static void applyNumericAffinity(Mem *pRec){
++  if( (pRec->flags & (MEM_Real|MEM_Int))==0 ){
++    int realnum;
++    sqlite3VdbeMemNulTerminate(pRec);
++    if( (pRec->flags&MEM_Str)
++         && sqlite3IsNumber(pRec->z, &realnum, pRec->enc) ){
++      i64 value;
++      sqlite3VdbeChangeEncoding(pRec, SQLITE_UTF8);
++      if( !realnum && sqlite3atoi64(pRec->z, &value) ){
++        sqlite3VdbeMemRelease(pRec);
++        pRec->i = value;
++        pRec->flags = MEM_Int;
++      }else{
++        sqlite3VdbeMemRealify(pRec);
++      }
++    }
++  }
++}
++
++/*
++** Processing is determine by the affinity parameter:
+ **
+-** SQLITE_AFF_NUMERIC
+-** SQLITE_AFF_TEXT
+-** SQLITE_AFF_NONE
+-** SQLITE_AFF_INTEGER
++** SQLITE_AFF_INTEGER:
++** SQLITE_AFF_REAL:
++** SQLITE_AFF_NUMERIC:
++**    Try to convert pRec to an integer representation or a 
++**    floating-point representation if an integer representation
++**    is not possible.  Note that the integer representation is
++**    always preferred, even if the affinity is REAL, because
++**    an integer representation is more space efficient on disk.
+ **
++** SQLITE_AFF_TEXT:
++**    Convert pRec to a text representation.
++**
++** SQLITE_AFF_NONE:
++**    No-op.  pRec is unchanged.
+ */
+ static void applyAffinity(Mem *pRec, char affinity, u8 enc){
+-  if( affinity==SQLITE_AFF_NONE ){
+-    /* do nothing */
+-  }else if( affinity==SQLITE_AFF_TEXT ){
++  if( affinity==SQLITE_AFF_TEXT ){
+     /* Only attempt the conversion to TEXT if there is an integer or real
+     ** representation (blob and NULL do not get converted) but no string
+     ** representation.
+@@ -209,36 +242,32 @@
+       sqlite3VdbeMemStringify(pRec, enc);
+     }
+     pRec->flags &= ~(MEM_Real|MEM_Int);
+-  }else{
+-    if( 0==(pRec->flags&(MEM_Real|MEM_Int)) ){
+-      /* pRec does not have a valid integer or real representation. 
+-      ** Attempt a conversion if pRec has a string representation and
+-      ** it looks like a number.
+-      */
+-      int realnum;
+-      sqlite3VdbeMemNulTerminate(pRec);
+-      if( pRec->flags&MEM_Str && sqlite3IsNumber(pRec->z, &realnum, enc) ){
+-        if( realnum ){
+-          Realify(pRec);
+-        }else{
+-          Integerify(pRec);
+-        }
+-      }
++  }else if( affinity!=SQLITE_AFF_NONE ){
++    assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL
++             || affinity==SQLITE_AFF_NUMERIC );
++    applyNumericAffinity(pRec);
++    if( pRec->flags & MEM_Real ){
++      sqlite3VdbeIntegerAffinity(pRec);
+     }
+-
+-    if( affinity==SQLITE_AFF_INTEGER ){
+-      /* For INTEGER affinity, try to convert a real value to an int */
+-      if( (pRec->flags&MEM_Real) && !(pRec->flags&MEM_Int) ){
+-        pRec->i = pRec->r;
+-        if( ((double)pRec->i)==pRec->r ){
+-          pRec->flags |= MEM_Int;
+-        }
+-      }
+-    }
+   }
+ }
+ 
+ /*
++** Try to convert the type of a function argument or a result column
++** into a numeric representation.  Use either INTEGER or REAL whichever
++** is appropriate.  But only do the conversion if it is possible without
++** loss of information and return the revised type of the argument.
++**
++** This is an EXPERIMENTAL api and is subject to change or removal.
++*/
++int sqlite3_value_numeric_type(sqlite3_value *pVal){
++  Mem *pMem = (Mem*)pVal;
++  applyNumericAffinity(pMem);
++  storeTypeInfo(pMem, 0);
++  return pMem->type;
++}
++
++/*
+ ** Exported version of applyAffinity(). This one works on sqlite3_value*, 
+ ** not the internal Mem* type.
+ */
+@@ -388,6 +417,7 @@
+   Op *pOp;                   /* Current operation */
+   int rc = SQLITE_OK;        /* Value to return */
+   sqlite3 *db = p->db;       /* The database */
++  u8 encoding = ENC(db);     /* The database encoding */
+   Mem *pTos;                 /* Top entry in the operand stack */
+ #ifdef VDBE_PROFILE
+   unsigned long long start;  /* CPU clock count at start of opcode */
+@@ -402,11 +432,15 @@
+ 
+   if( p->magic!=VDBE_MAGIC_RUN ) return SQLITE_MISUSE;
+   assert( db->magic==SQLITE_MAGIC_BUSY );
++  pTos = p->pTos;
++  if( p->rc==SQLITE_NOMEM ){
++    /* This happens if a malloc() inside a call to sqlite3_column_text() or
++    ** sqlite3_column_text16() failed.  */
++    goto no_mem;
++  }
+   assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY );
+   p->rc = SQLITE_OK;
+   assert( p->explain==0 );
+-  pTos = p->pTos;
+-  if( sqlite3_malloc_failed ) goto no_mem;
+   if( p->popStack ){
+     popStack(&pTos, p->popStack);
+     p->popStack = 0;
+@@ -417,7 +451,7 @@
+   for(pc=p->pc; rc==SQLITE_OK; pc++){
+     assert( pc>=0 && pc<p->nOp );
+     assert( pTos<=&p->aStack[pc] );
+-    if( sqlite3_malloc_failed ) goto no_mem;
++    if( sqlite3MallocFailed() ) goto no_mem;
+ #ifdef VDBE_PROFILE
+     origPc = pc;
+     start = hwtime();
+@@ -644,24 +678,25 @@
+   pTos->enc = SQLITE_UTF8;
+   pTos->r = sqlite3VdbeRealValue(pTos);
+   pTos->flags |= MEM_Real;
+-  sqlite3VdbeChangeEncoding(pTos, db->enc);
++  sqlite3VdbeChangeEncoding(pTos, encoding);
+   break;
+ }
+ 
+ /* Opcode: String8 * * P3
+ **
+-** P3 points to a nul terminated UTF-8 string. This opcode is transformed
++** P3 points to a nul terminated UTF-8 string. This opcode is transformed 
+ ** into an OP_String before it is executed for the first time.
+ */
+ case OP_String8: {         /* same as TK_STRING */
+-#ifndef SQLITE_OMIT_UTF16
++  assert( pOp->p3!=0 );
+   pOp->opcode = OP_String;
++  pOp->p1 = strlen(pOp->p3);
+ 
+-  assert( pOp->p3!=0 );
+-  if( db->enc!=SQLITE_UTF8 ){
++#ifndef SQLITE_OMIT_UTF16
++  if( encoding!=SQLITE_UTF8 ){
+     pTos++;
+     sqlite3VdbeMemSetStr(pTos, pOp->p3, -1, SQLITE_UTF8, SQLITE_STATIC);
+-    if( SQLITE_OK!=sqlite3VdbeChangeEncoding(pTos, db->enc) ) goto no_mem;
++    if( SQLITE_OK!=sqlite3VdbeChangeEncoding(pTos, encoding) ) goto no_mem;
+     if( SQLITE_OK!=sqlite3VdbeMemDynamicify(pTos) ) goto no_mem;
+     pTos->flags &= ~(MEM_Dyn);
+     pTos->flags |= MEM_Static;
+@@ -670,34 +705,24 @@
+     }
+     pOp->p3type = P3_DYNAMIC;
+     pOp->p3 = pTos->z;
++    pOp->p1 = pTos->n;
+     break;
+   }
+ #endif
+   /* Otherwise fall through to the next case, OP_String */
+ }
+   
+-/* Opcode: String * * P3
++/* Opcode: String P1 * P3
+ **
+-** The string value P3 is pushed onto the stack.  If P3==0 then a
+-** NULL is pushed onto the stack. P3 is assumed to be a nul terminated
+-** string encoded with the database native encoding.
++** The string value P3 of length P1 (bytes) is pushed onto the stack.
+ */
+ case OP_String: {
+   pTos++;
+   assert( pOp->p3!=0 );
+   pTos->flags = MEM_Str|MEM_Static|MEM_Term;
+   pTos->z = pOp->p3;
+-#ifndef SQLITE_OMIT_UTF16
+-  if( db->enc==SQLITE_UTF8 ){
+-    pTos->n = strlen(pTos->z);
+-  }else{
+-    pTos->n  = sqlite3utf16ByteLen(pTos->z, -1);
+-  }
+-#else
+-  assert( db->enc==SQLITE_UTF8 );
+-  pTos->n = strlen(pTos->z);
+-#endif
+-  pTos->enc = db->enc;
++  pTos->n = pOp->p1;
++  pTos->enc = encoding;
+   break;
+ }
+ 
+@@ -868,20 +893,45 @@
+ 
+ /* Opcode: Callback P1 * *
+ **
+-** Pop P1 values off the stack and form them into an array.  Then
+-** invoke the callback function using the newly formed array as the
+-** 3rd parameter.
++** The top P1 values on the stack represent a single result row from
++** a query.  This opcode causes the sqlite3_step() call to terminate
++** with an SQLITE_ROW return code and it sets up the sqlite3_stmt
++** structure to provide access to the top P1 values as the result
++** row.  When the sqlite3_step() function is run again, the top P1
++** values will be automatically popped from the stack before the next
++** instruction executes.
+ */
+ case OP_Callback: {            /* no-push */
+-  int i;
++  Mem *pMem;
++  Mem *pFirstColumn;
+   assert( p->nResColumn==pOp->p1 );
+ 
+-  for(i=0; i<pOp->p1; i++){
+-    Mem *pVal = &pTos[0-i];
+-    sqlite3VdbeMemNulTerminate(pVal);
+-    storeTypeInfo(pVal, db->enc);
++  /* Data in the pager might be moved or changed out from under us
++  ** in between the return from this sqlite3_step() call and the
++  ** next call to sqlite3_step().  So deephermeralize everything on 
++  ** the stack.  Note that ephemeral data is never stored in memory 
++  ** cells so we do not have to worry about them.
++  */
++  pFirstColumn = &pTos[0-pOp->p1];
++  for(pMem = p->aStack; pMem<pFirstColumn; pMem++){
++    Deephemeralize(pMem);
+   }
+ 
++  /* Invalidate all ephemeral cursor row caches */
++  p->cacheCtr = (p->cacheCtr + 2)|1;
++
++  /* Make sure the results of the current row are \000 terminated
++  ** and have an assigned type.  The results are deephemeralized as
++  ** as side effect.
++  */
++  for(; pMem<=pTos; pMem++ ){
++    sqlite3VdbeMemNulTerminate(pMem);
++    storeTypeInfo(pMem, encoding);
++  }
++
++  /* Set up the statement structure so that it will pop the current
++  ** results from the stack when the statement returns.
++  */
+   p->resOnStack = 1;
+   p->nCallback++;
+   p->popStack = pOp->p1;
+@@ -917,7 +967,7 @@
+       nByte = -1;
+       break;
+     }
+-    Stringify(pTerm, db->enc);
++    Stringify(pTerm, encoding);
+     nByte += pTerm->n;
+   }
+ 
+@@ -956,7 +1006,7 @@
+     pTos->n = j;
+     pTos->flags = MEM_Str|MEM_Dyn|MEM_Term;
+     pTos->xDel = 0;
+-    pTos->enc = db->enc;
++    pTos->enc = encoding;
+     pTos->z = zNew;
+   }
+   break;
+@@ -1014,8 +1064,10 @@
+ case OP_Divide:                /* same as TK_SLASH, no-push */
+ case OP_Remainder: {           /* same as TK_REM, no-push */
+   Mem *pNos = &pTos[-1];
++  int flags;
+   assert( pNos>=p->aStack );
+-  if( ((pTos->flags | pNos->flags) & MEM_Null)!=0 ){
++  flags = pTos->flags | pNos->flags;
++  if( (flags & MEM_Null)!=0 ){
+     Release(pTos);
+     pTos--;
+     Release(pTos);
+@@ -1070,6 +1122,9 @@
+     Release(pTos);
+     pTos->r = b;
+     pTos->flags = MEM_Real;
++    if( (flags & MEM_Real)==0 ){
++      sqlite3VdbeIntegerAffinity(pTos);
++    }
+   }
+   break;
+ 
+@@ -1125,7 +1180,7 @@
+   pArg = &pTos[1-n];
+   for(i=0; i<n; i++, pArg++){
+     apVal[i] = pArg;
+-    storeTypeInfo(pArg, db->enc);
++    storeTypeInfo(pArg, encoding);
+   }
+ 
+   assert( pOp->p3type==P3_FUNCDEF || pOp->p3type==P3_VDBEFUNC );
+@@ -1150,7 +1205,7 @@
+   if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
+   (*ctx.pFunc->xFunc)(&ctx, n, apVal);
+   if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
+-  if( sqlite3_malloc_failed ) goto no_mem;
++  if( sqlite3MallocFailed() ) goto no_mem;
+   popStack(&pTos, n);
+ 
+   /* If any auxilary data functions have been called by this user function,
+@@ -1162,22 +1217,17 @@
+     pOp->p3type = P3_VDBEFUNC;
+   }
+ 
++  /* If the function returned an error, throw an exception */
++  if( ctx.isError ){
++    sqlite3SetString(&p->zErrMsg, sqlite3_value_text(&ctx.s), (char*)0);
++    rc = SQLITE_ERROR;
++  }
++
+   /* Copy the result of the function to the top of the stack */
+-  sqlite3VdbeChangeEncoding(&ctx.s, db->enc);
++  sqlite3VdbeChangeEncoding(&ctx.s, encoding);
+   pTos++;
+   pTos->flags = 0;
+   sqlite3VdbeMemMove(pTos, &ctx.s);
+-
+-  /* If the function returned an error, throw an exception */
+-  if( ctx.isError ){
+-    if( !(pTos->flags&MEM_Str) ){
+-      sqlite3SetString(&p->zErrMsg, "user function error", (char*)0);
+-    }else{
+-      sqlite3SetString(&p->zErrMsg, sqlite3_value_text(pTos), (char*)0);
+-      sqlite3VdbeChangeEncoding(pTos, db->enc);
+-    }
+-    rc = SQLITE_ERROR;
+-  }
+   break;
+ }
+ 
+@@ -1214,7 +1264,7 @@
+ case OP_ShiftLeft:              /* same as TK_LSHIFT, no-push */
+ case OP_ShiftRight: {           /* same as TK_RSHIFT, no-push */
+   Mem *pNos = &pTos[-1];
+-  int a, b;
++  i64 a, b;
+ 
+   assert( pNos>=p->aStack );
+   if( (pTos->flags | pNos->flags) & MEM_Null ){
+@@ -1249,7 +1299,7 @@
+ */
+ case OP_AddImm: {            /* no-push */
+   assert( pTos>=p->aStack );
+-  Integerify(pTos);
++  sqlite3VdbeMemIntegerify(pTos);
+   pTos->i += pOp->p1;
+   break;
+ }
+@@ -1267,7 +1317,7 @@
+ case OP_ForceInt: {            /* no-push */
+   i64 v;
+   assert( pTos>=p->aStack );
+-  applyAffinity(pTos, SQLITE_AFF_INTEGER, db->enc);
++  applyAffinity(pTos, SQLITE_AFF_NUMERIC, encoding);
+   if( (pTos->flags & (MEM_Int|MEM_Real))==0 ){
+     Release(pTos);
+     pTos--;
+@@ -1277,7 +1327,8 @@
+   if( pTos->flags & MEM_Int ){
+     v = pTos->i + (pOp->p1!=0);
+   }else{
+-    Realify(pTos);
++    /* FIX ME:  should this not be assert( pTos->flags & MEM_Real ) ??? */
++    sqlite3VdbeMemRealify(pTos);
+     v = (int)pTos->r;
+     if( pTos->r>(double)v ) v++;
+     if( pOp->p1 && pTos->r==(double)v ) v++;
+@@ -1301,7 +1352,7 @@
+ */
+ case OP_MustBeInt: {            /* no-push */
+   assert( pTos>=p->aStack );
+-  applyAffinity(pTos, SQLITE_AFF_INTEGER, db->enc);
++  applyAffinity(pTos, SQLITE_AFF_NUMERIC, encoding);
+   if( (pTos->flags & MEM_Int)==0 ){
+     if( pOp->p2==0 ){
+       rc = SQLITE_MISMATCH;
+@@ -1317,67 +1368,39 @@
+   break;
+ }
+ 
+-#ifndef SQLITE_OMIT_CAST
+-/* Opcode: ToInt * * *
++/* Opcode: RealAffinity * * *
+ **
+-** Force the value on the top of the stack to be an integer.  If
+-** The value is currently a real number, drop its fractional part.
+-** If the value is text or blob, try to convert it to an integer using the
+-** equivalent of atoi() and store 0 if no such conversion is possible.
++** If the top of the stack is an integer, convert it to a real value.
+ **
+-** A NULL value is not changed by this routine.  It remains NULL.
++** This opcode is used when extracting information from a column that
++** has REAL affinity.  Such column values may still be stored as
++** integers, for space efficiency, but after extraction we want them
++** to have only a real value.
+ */
+-case OP_ToInt: {                  /* no-push */
++case OP_RealAffinity: {                  /* no-push */
+   assert( pTos>=p->aStack );
+-  if( pTos->flags & MEM_Null ) break;
+-  assert( MEM_Str==(MEM_Blob>>3) );
+-  pTos->flags |= (pTos->flags&MEM_Blob)>>3;
+-  applyAffinity(pTos, SQLITE_AFF_INTEGER, db->enc);
+-  sqlite3VdbeMemIntegerify(pTos);
+-  break;
+-}
+-
+-/* Opcode: ToNumeric * * *
+-**
+-** Force the value on the top of the stack to be numeric (either an
+-** integer or a floating-point number.
+-** If the value is text or blob, try to convert it to an using the
+-** equivalent of atoi() or atof() and store 0 if no such conversion 
+-** is possible.
+-**
+-** A NULL value is not changed by this routine.  It remains NULL.
+-*/
+-case OP_ToNumeric: {                  /* no-push */
+-  assert( pTos>=p->aStack );
+-  if( pTos->flags & MEM_Null ) break;
+-  assert( MEM_Str==(MEM_Blob>>3) );
+-  pTos->flags |= (pTos->flags&MEM_Blob)>>3;
+-  applyAffinity(pTos, SQLITE_AFF_NUMERIC, db->enc);
+-  if( (pTos->flags & (MEM_Int|MEM_Real))==0 ){
++  if( pTos->flags & MEM_Int ){
+     sqlite3VdbeMemRealify(pTos);
+-  }else{
+-    sqlite3VdbeMemRelease(pTos);
+   }
+-  assert( (pTos->flags & MEM_Dyn)==0 );
+-  pTos->flags &= (MEM_Int|MEM_Real);
+   break;
+ }
+ 
++#ifndef SQLITE_OMIT_CAST
+ /* Opcode: ToText * * *
+ **
+ ** Force the value on the top of the stack to be text.
+-** If the value is numeric, convert it to an using the
++** If the value is numeric, convert it to a string using the
+ ** equivalent of printf().  Blob values are unchanged and
+ ** are afterwards simply interpreted as text.
+ **
+ ** A NULL value is not changed by this routine.  It remains NULL.
+ */
+-case OP_ToText: {                  /* no-push */
++case OP_ToText: {                  /* same as TK_TO_TEXT, no-push */
+   assert( pTos>=p->aStack );
+   if( pTos->flags & MEM_Null ) break;
+   assert( MEM_Str==(MEM_Blob>>3) );
+   pTos->flags |= (pTos->flags&MEM_Blob)>>3;
+-  applyAffinity(pTos, SQLITE_AFF_TEXT, db->enc);
++  applyAffinity(pTos, SQLITE_AFF_TEXT, encoding);
+   assert( pTos->flags & MEM_Str );
+   pTos->flags &= ~(MEM_Int|MEM_Real|MEM_Blob);
+   break;
+@@ -1392,19 +1415,73 @@
+ **
+ ** A NULL value is not changed by this routine.  It remains NULL.
+ */
+-case OP_ToBlob: {                  /* no-push */
++case OP_ToBlob: {                  /* same as TK_TO_BLOB, no-push */
+   assert( pTos>=p->aStack );
+   if( pTos->flags & MEM_Null ) break;
+   if( (pTos->flags & MEM_Blob)==0 ){
+-    applyAffinity(pTos, SQLITE_AFF_TEXT, db->enc);
++    applyAffinity(pTos, SQLITE_AFF_TEXT, encoding);
+     assert( pTos->flags & MEM_Str );
+     pTos->flags |= MEM_Blob;
+   }
+   pTos->flags &= ~(MEM_Int|MEM_Real|MEM_Str);
+   break;
+ }
++
++/* Opcode: ToNumeric * * *
++**
++** Force the value on the top of the stack to be numeric (either an
++** integer or a floating-point number.)
++** If the value is text or blob, try to convert it to an using the
++** equivalent of atoi() or atof() and store 0 if no such conversion 
++** is possible.
++**
++** A NULL value is not changed by this routine.  It remains NULL.
++*/
++case OP_ToNumeric: {                  /* same as TK_TO_NUMERIC, no-push */
++  assert( pTos>=p->aStack );
++  if( (pTos->flags & MEM_Null)==0 ){
++    sqlite3VdbeMemNumerify(pTos);
++  }
++  break;
++}
+ #endif /* SQLITE_OMIT_CAST */
+ 
++/* Opcode: ToInt * * *
++**
++** Force the value on the top of the stack to be an integer.  If
++** The value is currently a real number, drop its fractional part.
++** If the value is text or blob, try to convert it to an integer using the
++** equivalent of atoi() and store 0 if no such conversion is possible.
++**
++** A NULL value is not changed by this routine.  It remains NULL.
++*/
++case OP_ToInt: {                  /* same as TK_TO_INT, no-push */
++  assert( pTos>=p->aStack );
++  if( (pTos->flags & MEM_Null)==0 ){
++    sqlite3VdbeMemIntegerify(pTos);
++  }
++  break;
++}
++
++#ifndef SQLITE_OMIT_CAST
++/* Opcode: ToReal * * *
++**
++** Force the value on the top of the stack to be a floating point number.
++** If The value is currently an integer, convert it.
++** If the value is text or blob, try to convert it to an integer using the
++** equivalent of atoi() and store 0 if no such conversion is possible.
++**
++** A NULL value is not changed by this routine.  It remains NULL.
++*/
++case OP_ToReal: {                  /* same as TK_TO_REAL, no-push */
++  assert( pTos>=p->aStack );
++  if( (pTos->flags & MEM_Null)==0 ){
++    sqlite3VdbeMemRealify(pTos);
++  }
++  break;
++}
++#endif /* SQLITE_OMIT_CAST */
++
+ /* Opcode: Eq P1 P2 P3
+ **
+ ** Pop the top two elements from the stack.  If they are equal, then
+@@ -1422,7 +1499,8 @@
+ ** 0x200 is set but is NULL when the 0x200 bit of P1 is clear.
+ **
+ ** The least significant byte of P1 (mask 0xff) must be an affinity character -
+-** 'n', 't', 'i' or 'o' - or 0x00. An attempt is made to coerce both values
++** SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER, and so forth. An attempt is made 
++** to coerce both values
+ ** according to the affinity before the comparison is made. If the byte is
+ ** 0x00, then numeric affinity is used.
+ **
+@@ -1522,8 +1600,8 @@
+ 
+   affinity = pOp->p1 & 0xFF;
+   if( affinity ){
+-    applyAffinity(pNos, affinity, db->enc);
+-    applyAffinity(pTos, affinity, db->enc);
++    applyAffinity(pNos, affinity, encoding);
++    applyAffinity(pTos, affinity, encoding);
+   }
+ 
+   assert( pOp->p3type==P3_COLLSEQ || pOp->p3==0 );
+@@ -1571,13 +1649,13 @@
+   if( pTos->flags & MEM_Null ){
+     v1 = 2;
+   }else{
+-    Integerify(pTos);
++    sqlite3VdbeMemIntegerify(pTos);
+     v1 = pTos->i==0;
+   }
+   if( pNos->flags & MEM_Null ){
+     v2 = 2;
+   }else{
+-    Integerify(pNos);
++    sqlite3VdbeMemIntegerify(pNos);
+     v2 = pNos->i==0;
+   }
+   if( pOp->opcode==OP_And ){
+@@ -1614,6 +1692,7 @@
+ case OP_AbsValue: {
+   assert( pTos>=p->aStack );
+   if( pTos->flags & MEM_Real ){
++    neg_abs_real_case:
+     Release(pTos);
+     if( pOp->opcode==OP_Negative || pTos->r<0.0 ){
+       pTos->r = -pTos->r;
+@@ -1628,11 +1707,8 @@
+   }else if( pTos->flags & MEM_Null ){
+     /* Do nothing */
+   }else{
+-    Realify(pTos);
+-    if( pOp->opcode==OP_Negative || pTos->r<0.0 ){
+-      pTos->r = -pTos->r;
+-    }
+-    pTos->flags = MEM_Real;
++    sqlite3VdbeMemNumerify(pTos);
++    goto neg_abs_real_case;
+   }
+   break;
+ }
+@@ -1646,7 +1722,7 @@
+ case OP_Not: {                /* same as TK_NOT, no-push */
+   assert( pTos>=p->aStack );
+   if( pTos->flags & MEM_Null ) break;  /* Do nothing to NULLs */
+-  Integerify(pTos);
++  sqlite3VdbeMemIntegerify(pTos);
+   assert( (pTos->flags & MEM_Dyn)==0 );
+   pTos->i = !pTos->i;
+   pTos->flags = MEM_Int;
+@@ -1662,7 +1738,7 @@
+ case OP_BitNot: {             /* same as TK_BITNOT, no-push */
+   assert( pTos>=p->aStack );
+   if( pTos->flags & MEM_Null ) break;  /* Do nothing to NULLs */
+-  Integerify(pTos);
++  sqlite3VdbeMemIntegerify(pTos);
+   assert( (pTos->flags & MEM_Dyn)==0 );
+   pTos->i = ~pTos->i;
+   pTos->flags = MEM_Int;
+@@ -1819,10 +1895,7 @@
+   u32 *aType;        /* aType[i] holds the numeric type of the i-th column */
+   u32 *aOffset;      /* aOffset[i] is offset to start of data for i-th column */
+   u32 nField;        /* number of fields in the record */
+-  u32 szHdr;         /* Number of bytes in the record header */
+   int len;           /* The length of the serialized data for the column */
+-  int offset = 0;    /* Offset into the data */
+-  int idx;           /* Index into the header */
+   int i;             /* Loop counter */
+   char *zData;       /* Part of the record being decoded */
+   Mem sMem;          /* For storing the record being decoded */
+@@ -1868,9 +1941,9 @@
+     pCrsr = pC->pCursor;
+     if( pC->nullRow ){
+       payloadSize = 0;
+-    }else if( pC->cacheValid ){
++    }else if( pC->cacheStatus==p->cacheCtr ){
+       payloadSize = pC->payloadSize;
+-      zRec = pC->aRow;
++      zRec = (char*)pC->aRow;
+     }else if( pC->isIndex ){
+       i64 payloadSize64;
+       sqlite3BtreeKeySize(pCrsr, &payloadSize64);
+@@ -1884,7 +1957,7 @@
+     /* The record is the sole entry of a pseudo-table */
+     payloadSize = pC->nData;
+     zRec = pC->pData;
+-    pC->cacheValid = 0;
++    pC->cacheStatus = CACHE_STALE;
+     assert( payloadSize==0 || zRec!=0 );
+     nField = pC->nField;
+     pCrsr = 0;
+@@ -1898,7 +1971,7 @@
+ 
+   /* If payloadSize is 0, then just push a NULL onto the stack. */
+   if( payloadSize==0 ){
+-    pTos->flags = MEM_Null;
++    assert( pTos->flags==MEM_Null );
+     break;
+   }
+ 
+@@ -1907,11 +1980,15 @@
+   /* Read and parse the table header.  Store the results of the parse
+   ** into the record header cache fields of the cursor.
+   */
+-  if( pC && pC->cacheValid ){
++  if( pC && pC->cacheStatus==p->cacheCtr ){
+     aType = pC->aType;
+     aOffset = pC->aOffset;
+   }else{
+-    int avail;    /* Number of bytes of available data */
++    u8 *zIdx;        /* Index into header */
++    u8 *zEndHdr;     /* Pointer to first byte after the header */
++    u32 offset;      /* Offset into the data */
++    int szHdrSz;     /* Size of the header size field at start of record */
++    int avail;       /* Number of bytes of available data */
+     if( pC && pC->aType ){
+       aType = pC->aType;
+     }else{
+@@ -1937,60 +2014,59 @@
+       ** the record.
+       */
+       if( avail>=payloadSize ){
+-        zRec = pC->aRow = zData;
++        zRec = zData;
++        pC->aRow = (u8*)zData;
+       }else{
+         pC->aRow = 0;
+       }
+     }
+-    idx = sqlite3GetVarint32(zData, &szHdr);
++    assert( zRec!=0 || avail>=payloadSize || avail>=9 );
++    szHdrSz = GetVarint((u8*)zData, offset);
+ 
+-
+     /* The KeyFetch() or DataFetch() above are fast and will get the entire
+     ** record header in most cases.  But they will fail to get the complete
+     ** record header if the record header does not fit on a single page
+     ** in the B-Tree.  When that happens, use sqlite3VdbeMemFromBtree() to
+     ** acquire the complete header text.
+     */
+-    if( !zRec && avail<szHdr ){
+-      rc = sqlite3VdbeMemFromBtree(pCrsr, 0, szHdr, pC->isIndex, &sMem);
++    if( !zRec && avail<offset ){
++      rc = sqlite3VdbeMemFromBtree(pCrsr, 0, offset, pC->isIndex, &sMem);
+       if( rc!=SQLITE_OK ){
+         goto op_column_out;
+       }
+       zData = sMem.z;
+     }
++    zEndHdr = (u8 *)&zData[offset];
++    zIdx = (u8 *)&zData[szHdrSz];
+ 
+     /* Scan the header and use it to fill in the aType[] and aOffset[]
+     ** arrays.  aType[i] will contain the type integer for the i-th
+     ** column and aOffset[i] will contain the offset from the beginning
+     ** of the record to the start of the data for the i-th column
+     */
+-    offset = szHdr;
+-    assert( offset>0 );
+-    i = 0;
+-    while( idx<szHdr && i<nField && offset<=payloadSize ){
+-      aOffset[i] = offset;
+-      idx += sqlite3GetVarint32(&zData[idx], &aType[i]);
+-      offset += sqlite3VdbeSerialTypeLen(aType[i]);
+-      i++;
++    for(i=0; i<nField; i++){
++      if( zIdx<zEndHdr ){
++        aOffset[i] = offset;
++        zIdx += GetVarint(zIdx, aType[i]);
++        offset += sqlite3VdbeSerialTypeLen(aType[i]);
++      }else{
++        /* If i is less that nField, then there are less fields in this
++        ** record than SetNumColumns indicated there are columns in the
++        ** table. Set the offset for any extra columns not present in
++        ** the record to 0. This tells code below to push a NULL onto the
++        ** stack instead of deserializing a value from the record.
++        */
++        aOffset[i] = 0;
++      }
+     }
+     Release(&sMem);
+     sMem.flags = MEM_Null;
+ 
+-    /* If i is less that nField, then there are less fields in this
+-    ** record than SetNumColumns indicated there are columns in the
+-    ** table. Set the offset for any extra columns not present in
+-    ** the record to 0. This tells code below to push a NULL onto the
+-    ** stack instead of deserializing a value from the record.
++    /* If we have read more header data than was contained in the header,
++    ** or if the end of the last field appears to be past the end of the
++    ** record, then we must be dealing with a corrupt database.
+     */
+-    while( i<nField ){
+-      aOffset[i++] = 0;
+-    }
+-
+-    /* The header should end at the start of data and the data should
+-    ** end at last byte of the record. If this is not the case then
+-    ** we are dealing with a malformed record.
+-    */
+-    if( idx!=szHdr || offset!=payloadSize ){
++    if( zIdx>zEndHdr || offset>payloadSize ){
+       rc = SQLITE_CORRUPT_BKPT;
+       goto op_column_out;
+     }
+@@ -2001,7 +2077,7 @@
+       pC->payloadSize = payloadSize;
+       pC->aType = aType;
+       pC->aOffset = aOffset;
+-      pC->cacheValid = 1;
++      pC->cacheStatus = p->cacheCtr;
+     }
+   }
+ 
+@@ -2023,8 +2099,8 @@
+       }
+       zData = sMem.z;
+     }
+-    sqlite3VdbeSerialGet(zData, aType[p2], pTos);
+-    pTos->enc = db->enc;
++    sqlite3VdbeSerialGet((u8*)zData, aType[p2], pTos);
++    pTos->enc = encoding;
+   }else{
+     if( pOp->p3type==P3_MEM ){
+       sqlite3VdbeMemShallowCopy(pTos, (Mem *)(pOp->p3), MEM_Static);
+@@ -2081,17 +2157,14 @@
+ ** field of the index key (i.e. the first character of P3 corresponds to the
+ ** lowest element on the stack).
+ **
+-** The mapping from character to affinity is as follows:
+-**    'n' = NUMERIC.
+-**    'i' = INTEGER.
+-**    't' = TEXT.
+-**    'o' = NONE.
++** The mapping from character to affinity is given by the SQLITE_AFF_
++** macros defined in sqliteInt.h.
+ **
+ ** If P3 is NULL then all index fields have the affinity NONE.
+ **
+ ** See also OP_MakeIdxRec
+ */
+-/* Opcode: MakeRecordI P1 P2 P3
++/* Opcode: MakeIdxRec P1 P2 P3
+ **
+ ** This opcode works just OP_MakeRecord except that it reads an extra
+ ** integer from the stack (thus reading a total of abs(P1+1) entries)
+@@ -2133,6 +2206,7 @@
+   int jumpIfNull;        /* Jump here if non-zero and any entries are NULL. */
+   int addRowid;          /* True to append a rowid column at the end */
+   char *zAffinity;       /* The affinity string for the record */
++  int file_format;       /* File format to use for encoding */
+ 
+   leaveOnStack = ((pOp->p1<0)?1:0);
+   nField = pOp->p1 * (leaveOnStack?-1:1);
+@@ -2143,18 +2217,19 @@
+   pData0 = &pTos[1-nField];
+   assert( pData0>=p->aStack );
+   containsNull = 0;
++  file_format = p->minWriteFileFormat;
+ 
+   /* Loop through the elements that will make up the record to figure
+   ** out how much space is required for the new record.
+   */
+   for(pRec=pData0; pRec<=pTos; pRec++){
+     if( zAffinity ){
+-      applyAffinity(pRec, zAffinity[pRec-pData0], db->enc);
++      applyAffinity(pRec, zAffinity[pRec-pData0], encoding);
+     }
+     if( pRec->flags&MEM_Null ){
+       containsNull = 1;
+     }
+-    serial_type = sqlite3VdbeSerialType(pRec);
++    serial_type = sqlite3VdbeSerialType(pRec, file_format);
+     nData += sqlite3VdbeSerialTypeLen(serial_type);
+     nHdr += sqlite3VarintLen(serial_type);
+   }
+@@ -2166,8 +2241,8 @@
+   if( addRowid ){
+     pRowid = &pTos[0-nField];
+     assert( pRowid>=p->aStack );
+-    Integerify(pRowid);
+-    serial_type = sqlite3VdbeSerialType(pRowid);
++    sqlite3VdbeMemIntegerify(pRowid);
++    serial_type = sqlite3VdbeSerialType(pRowid, 0);
+     nData += sqlite3VdbeSerialTypeLen(serial_type);
+     nHdr += sqlite3VarintLen(serial_type);
+   }
+@@ -2186,24 +2261,24 @@
+       goto no_mem;
+     }
+   }else{
+-    zNewRecord = zTemp;
++    zNewRecord = (u8*)zTemp;
+   }
+ 
+   /* Write the record */
+   zCsr = zNewRecord;
+   zCsr += sqlite3PutVarint(zCsr, nHdr);
+   for(pRec=pData0; pRec<=pTos; pRec++){
+-    serial_type = sqlite3VdbeSerialType(pRec);
++    serial_type = sqlite3VdbeSerialType(pRec, file_format);
+     zCsr += sqlite3PutVarint(zCsr, serial_type);      /* serial type */
+   }
+   if( addRowid ){
+-    zCsr += sqlite3PutVarint(zCsr, sqlite3VdbeSerialType(pRowid));
++    zCsr += sqlite3PutVarint(zCsr, sqlite3VdbeSerialType(pRowid, 0));
+   }
+   for(pRec=pData0; pRec<=pTos; pRec++){
+-    zCsr += sqlite3VdbeSerialPut(zCsr, pRec);  /* serial data */
++    zCsr += sqlite3VdbeSerialPut(zCsr, pRec, file_format);  /* serial data */
+   }
+   if( addRowid ){
+-    zCsr += sqlite3VdbeSerialPut(zCsr, pRowid);
++    zCsr += sqlite3VdbeSerialPut(zCsr, pRowid, 0);
+   }
+   assert( zCsr==(zNewRecord+nByte) );
+ 
+@@ -2220,7 +2295,7 @@
+     pTos->flags = MEM_Blob | MEM_Short;
+   }else{
+     assert( zNewRecord!=(unsigned char *)zTemp );
+-    pTos->z = zNewRecord;
++    pTos->z = (char*)zNewRecord;
+     pTos->flags = MEM_Blob | MEM_Dyn;
+     pTos->xDel = 0;
+   }
+@@ -2248,7 +2323,7 @@
+ case OP_Statement: {       /* no-push */
+   int i = pOp->p1;
+   Btree *pBt;
+-  if( i>=0 && i<db->nDb && (pBt = db->aDb[i].pBt) && !(db->autoCommit) ){
++  if( i>=0 && i<db->nDb && (pBt = db->aDb[i].pBt)!=0 && !(db->autoCommit) ){
+     assert( sqlite3BtreeIsInTrans(pBt) );
+     if( !sqlite3BtreeIsInStmt(pBt) ){
+       rc = sqlite3BtreeBeginStmt(pBt);
+@@ -2280,26 +2355,29 @@
+     ** that the other VMs must complete first. 
+     */
+     sqlite3SetString(&p->zErrMsg, "cannot ", rollback?"rollback":"commit", 
+-        " transaction - SQL statements in progress", 0);
++        " transaction - SQL statements in progress", (char*)0);
+     rc = SQLITE_ERROR;
+   }else if( i!=db->autoCommit ){
+-    db->autoCommit = i;
+     if( pOp->p2 ){
+       assert( i==1 );
+       sqlite3RollbackAll(db);
+-    }else if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){
+-      p->pTos = pTos;
+-      p->pc = pc;
+-      db->autoCommit = 1-i;
+-      p->rc = SQLITE_BUSY;
+-      return SQLITE_BUSY;
++      db->autoCommit = 1;
++    }else{
++      db->autoCommit = i;
++      if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){
++        p->pTos = pTos;
++        p->pc = pc;
++        db->autoCommit = 1-i;
++        p->rc = SQLITE_BUSY;
++        return SQLITE_BUSY;
++      }
+     }
+     return SQLITE_DONE;
+   }else{
+     sqlite3SetString(&p->zErrMsg,
+         (!i)?"cannot start a transaction within a transaction":(
+         (rollback)?"cannot rollback - no transaction is active":
+-                   "cannot commit - no transaction is active"), 0);
++                   "cannot commit - no transaction is active"), (char*)0);
+          
+     rc = SQLITE_ERROR;
+   }
+@@ -2396,16 +2474,24 @@
+   pDb = &db->aDb[pOp->p1];
+   assert( pDb->pBt!=0 );
+   assert( pTos>=p->aStack );
+-  Integerify(pTos);
++  sqlite3VdbeMemIntegerify(pTos);
+   /* See note about index shifting on OP_ReadCookie */
+   rc = sqlite3BtreeUpdateMeta(pDb->pBt, 1+pOp->p2, (int)pTos->i);
+   if( pOp->p2==0 ){
+     /* When the schema cookie changes, record the new cookie internally */
+-    pDb->schema_cookie = pTos->i;
++    pDb->pSchema->schema_cookie = pTos->i;
+     db->flags |= SQLITE_InternChanges;
++  }else if( pOp->p2==1 ){
++    /* Record changes in the file format */
++    pDb->pSchema->file_format = pTos->i;
+   }
+   assert( (pTos->flags & MEM_Dyn)==0 );
+   pTos--;
++  if( pOp->p1==1 ){
++    /* Invalidate all prepared statements whenever the TEMP database
++    ** schema is changed.  Ticket #1644 */
++    sqlite3ExpirePreparedStatements(db);
++  }
+   break;
+ }
+ 
+@@ -2493,26 +2579,35 @@
+   Btree *pX;
+   int iDb;
+   Cursor *pCur;
++  Db *pDb;
+   
+   assert( pTos>=p->aStack );
+-  Integerify(pTos);
++  sqlite3VdbeMemIntegerify(pTos);
+   iDb = pTos->i;
+   assert( (pTos->flags & MEM_Dyn)==0 );
+   pTos--;
+   assert( iDb>=0 && iDb<db->nDb );
+-  pX = db->aDb[iDb].pBt;
++  pDb = &db->aDb[iDb];
++  pX = pDb->pBt;
+   assert( pX!=0 );
+-  wrFlag = pOp->opcode==OP_OpenWrite;
++  if( pOp->opcode==OP_OpenWrite ){
++    wrFlag = 1;
++    if( pDb->pSchema->file_format < p->minWriteFileFormat ){
++      p->minWriteFileFormat = pDb->pSchema->file_format;
++    }
++  }else{
++    wrFlag = 0;
++  }
+   if( p2<=0 ){
+     assert( pTos>=p->aStack );
+-    Integerify(pTos);
++    sqlite3VdbeMemIntegerify(pTos);
+     p2 = pTos->i;
+     assert( (pTos->flags & MEM_Dyn)==0 );
+     pTos--;
+     assert( p2>=2 );
+   }
+   assert( i>=0 );
+-  pCur = allocateCursor(p, i);
++  pCur = allocateCursor(p, i, iDb);
+   if( pCur==0 ) goto no_mem;
+   pCur->nullRow = 1;
+   if( pX==0 ) break;
+@@ -2524,7 +2619,7 @@
+   if( pOp->p3type==P3_KEYINFO ){
+     pCur->pKeyInfo = (KeyInfo*)pOp->p3;
+     pCur->pIncrKey = &pCur->pKeyInfo->incrKey;
+-    pCur->pKeyInfo->enc = p->db->enc;
++    pCur->pKeyInfo->enc = ENC(p->db);
+   }else{
+     pCur->pKeyInfo = 0;
+     pCur->pIncrKey = &pCur->bogusIncrKey;
+@@ -2590,7 +2685,7 @@
+   int i = pOp->p1;
+   Cursor *pCx;
+   assert( i>=0 );
+-  pCx = allocateCursor(p, i);
++  pCx = allocateCursor(p, i, -1);
+   if( pCx==0 ) goto no_mem;
+   pCx->nullRow = 1;
+   rc = sqlite3BtreeFactory(db, 0, 1, TEMP_PAGES, &pCx->pBt);
+@@ -2612,7 +2707,7 @@
+         rc = sqlite3BtreeCursor(pCx->pBt, pgno, 1, sqlite3VdbeRecordCompare,
+             pOp->p3, &pCx->pCursor);
+         pCx->pKeyInfo = (KeyInfo*)pOp->p3;
+-        pCx->pKeyInfo->enc = p->db->enc;
++        pCx->pKeyInfo->enc = ENC(p->db);
+         pCx->pIncrKey = &pCx->pKeyInfo->incrKey;
+       }
+       pCx->isTable = 0;
+@@ -2642,7 +2737,7 @@
+   int i = pOp->p1;
+   Cursor *pCx;
+   assert( i>=0 );
+-  pCx = allocateCursor(p, i);
++  pCx = allocateCursor(p, i, -1);
+   if( pCx==0 ) goto no_mem;
+   pCx->nullRow = 1;
+   pCx->pseudoTable = 1;
+@@ -2725,7 +2820,7 @@
+     *pC->pIncrKey = oc==OP_MoveGt || oc==OP_MoveLe;
+     if( pC->isTable ){
+       i64 iKey;
+-      Integerify(pTos);
++      sqlite3VdbeMemIntegerify(pTos);
+       iKey = intToKey(pTos->i);
+       if( pOp->p2==0 && pOp->opcode==OP_MoveGe ){
+         pC->movetoTarget = iKey;
+@@ -2741,7 +2836,8 @@
+       pC->lastRowid = pTos->i;
+       pC->rowidIsValid = res==0;
+     }else{
+-      Stringify(pTos, db->enc);
++      assert( pTos->flags & MEM_Blob );
++      /* Stringify(pTos, encoding); */
+       rc = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res);
+       if( rc!=SQLITE_OK ){
+         goto abort_due_to_error;
+@@ -2749,7 +2845,7 @@
+       pC->rowidIsValid = 0;
+     }
+     pC->deferredMoveto = 0;
+-    pC->cacheValid = 0;
++    pC->cacheStatus = CACHE_STALE;
+     *pC->pIncrKey = 0;
+     sqlite3_search_count++;
+     if( oc==OP_MoveGe || oc==OP_MoveGt ){
+@@ -2846,11 +2942,11 @@
+   if( (pC = p->apCsr[i])->pCursor!=0 ){
+     int res, rx;
+     assert( pC->isTable==0 );
+-    Stringify(pTos, db->enc);
++    Stringify(pTos, encoding);
+     rx = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res);
+     alreadyExists = rx==SQLITE_OK && res==0;
+     pC->deferredMoveto = 0;
+-    pC->cacheValid = 0;
++    pC->cacheStatus = CACHE_STALE;
+   }
+   if( pOp->opcode==OP_Found ){
+     if( alreadyExists ) pc = pOp->p2 - 1;
+@@ -2868,7 +2964,7 @@
+ **
+ ** The top of the stack is an integer record number.  Call this
+ ** record number R.  The next on the stack is an index key created
+-** using MakeIdxKey.  Call it K.  This instruction pops R from the
++** using MakeIdxRec.  Call it K.  This instruction pops R from the
+ ** stack but it leaves K unchanged.
+ **
+ ** P1 is an index.  So it has no data and its key consists of a
+@@ -2895,7 +2991,7 @@
+   /* Pop the value R off the top of the stack
+   */
+   assert( pNos>=p->aStack );
+-  Integerify(pTos);
++  sqlite3VdbeMemIntegerify(pTos);
+   R = pTos->i;
+   assert( (pTos->flags & MEM_Dyn)==0 );
+   pTos--;
+@@ -2904,7 +3000,7 @@
+   assert( pCx!=0 );
+   pCrsr = pCx->pCursor;
+   if( pCrsr!=0 ){
+-    int res, rc;
++    int res;
+     i64 v;         /* The record number on the P1 entry that matches K */
+     char *zKey;    /* The value of K */
+     int nKey;      /* Number of bytes in K */
+@@ -2913,20 +3009,22 @@
+ 
+     /* Make sure K is a string and make zKey point to K
+     */
+-    Stringify(pNos, db->enc);
++    Stringify(pNos, encoding);
+     zKey = pNos->z;
+     nKey = pNos->n;
+ 
+-    szRowid = sqlite3VdbeIdxRowidLen(nKey, zKey);
++    szRowid = sqlite3VdbeIdxRowidLen(nKey, (u8*)zKey);
+     len = nKey-szRowid;
+ 
+     /* Search for an entry in P1 where all but the last four bytes match K.
+     ** If there is no such entry, jump immediately to P2.
+     */
+     assert( pCx->deferredMoveto==0 );
+-    pCx->cacheValid = 0;
++    pCx->cacheStatus = CACHE_STALE;
+     rc = sqlite3BtreeMoveto(pCrsr, zKey, len, &res);
+-    if( rc!=SQLITE_OK ) goto abort_due_to_error;
++    if( rc!=SQLITE_OK ){
++      goto abort_due_to_error;
++    }
+     if( res<0 ){
+       rc = sqlite3BtreeNext(pCrsr, &res);
+       if( res ){
+@@ -2934,7 +3032,7 @@
+         break;
+       }
+     }
+-    rc = sqlite3VdbeIdxKeyCompare(pCx, len, zKey, &res); 
++    rc = sqlite3VdbeIdxKeyCompare(pCx, len, (u8*)zKey, &res); 
+     if( rc!=SQLITE_OK ) goto abort_due_to_error;
+     if( res>0 ){
+       pc = pOp->p2 - 1;
+@@ -2997,7 +3095,7 @@
+     pC->lastRowid = pTos->i;
+     pC->rowidIsValid = res==0;
+     pC->nullRow = 0;
+-    pC->cacheValid = 0;
++    pC->cacheStatus = CACHE_STALE;
+     if( res!=0 ){
+       pc = pOp->p2 - 1;
+       pC->rowidIsValid = 0;
+@@ -3105,7 +3203,10 @@
+       if( pC->nextRowidValid ){
+         v = pC->nextRowid;
+       }else{
+-        rx = sqlite3BtreeLast(pC->pCursor, &res);
++        rc = sqlite3BtreeLast(pC->pCursor, &res);
++        if( rc!=SQLITE_OK ){
++          goto abort_due_to_error;
++        }
+         if( res ){
+           v = 1;
+         }else{
+@@ -3124,7 +3225,7 @@
+         Mem *pMem;
+         assert( pOp->p2>0 && pOp->p2<p->nMem );  /* P2 is a valid memory cell */
+         pMem = &p->aMem[pOp->p2];
+-        Integerify(pMem);
++        sqlite3VdbeMemIntegerify(pMem);
+         assert( (pMem->flags & MEM_Int)!=0 );  /* mem(P2) holds an integer */
+         if( pMem->i==MAX_ROWID || pC->useRandomRowid ){
+           rc = SQLITE_FULL;
+@@ -3170,7 +3271,7 @@
+     }
+     pC->rowidIsValid = 0;
+     pC->deferredMoveto = 0;
+-    pC->cacheValid = 0;
++    pC->cacheStatus = CACHE_STALE;
+   }
+   pTos++;
+   pTos->i = v;
+@@ -3178,7 +3279,7 @@
+   break;
+ }
+ 
+-/* Opcode: Insert P1 P2 *
++/* Opcode: Insert P1 P2 P3
+ **
+ ** Write an entry into the table of cursor P1.  A new entry is
+ ** created if it doesn't already exist or the data for an existing
+@@ -3210,7 +3311,7 @@
+ 
+     if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++;
+     if( pOp->p2 & OPFLAG_LASTROWID ) db->lastRowid = pNos->i;
+-    if( pC->nextRowidValid && pTos->i>=pC->nextRowid ){
++    if( pC->nextRowidValid && pNos->i>=pC->nextRowid ){
+       pC->nextRowidValid = 0;
+     }
+     if( pTos->flags & MEM_Null ){
+@@ -3244,13 +3345,24 @@
+     
+     pC->rowidIsValid = 0;
+     pC->deferredMoveto = 0;
+-    pC->cacheValid = 0;
++    pC->cacheStatus = CACHE_STALE;
++
++    /* Invoke the update-hook if required. */
++    if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p3 ){
++      const char *zDb = db->aDb[pC->iDb].zName;
++      const char *zTbl = pOp->p3;
++      int op = ((pOp->p2 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT);
++      assert( pC->isTable );
++      db->xUpdateCallback(db->pUpdateArg, op, zDb, zTbl, iKey);
++      assert( pC->iDb>=0 );
++    }
+   }
+   popStack(&pTos, 2);
++
+   break;
+ }
+ 
+-/* Opcode: Delete P1 P2 *
++/* Opcode: Delete P1 P2 P3
+ **
+ ** Delete the record at which the P1 cursor is currently pointing.
+ **
+@@ -3271,11 +3383,37 @@
+   pC = p->apCsr[i];
+   assert( pC!=0 );
+   if( pC->pCursor!=0 ){
++    i64 iKey;
++
++    /* If the update-hook will be invoked, set iKey to the rowid of the
++    ** row being deleted.
++    */
++    if( db->xUpdateCallback && pOp->p3 ){
++      assert( pC->isTable );
++      if( pC->rowidIsValid ){
++        iKey = pC->lastRowid;
++      }else{
++        rc = sqlite3BtreeKeySize(pC->pCursor, &iKey);
++        if( rc ){
++          goto abort_due_to_error;
++        }
++        iKey = keyToInt(iKey);
++      }
++    }
++
+     rc = sqlite3VdbeCursorMoveto(pC);
+     if( rc ) goto abort_due_to_error;
+     rc = sqlite3BtreeDelete(pC->pCursor);
+     pC->nextRowidValid = 0;
+-    pC->cacheValid = 0;
++    pC->cacheStatus = CACHE_STALE;
++
++    /* Invoke the update-hook if required. */
++    if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p3 ){
++      const char *zDb = db->aDb[pC->iDb].zName;
++      const char *zTbl = pOp->p3;
++      db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, zTbl, iKey);
++      assert( pC->iDb>=0 );
++    }
+   }
+   if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++;
+   break;
+@@ -3445,7 +3583,7 @@
+     rc = sqlite3BtreeLast(pCrsr, &res);
+     pC->nullRow = res;
+     pC->deferredMoveto = 0;
+-    pC->cacheValid = 0;
++    pC->cacheStatus = CACHE_STALE;
+     if( res && pOp->p2>0 ){
+       pc = pOp->p2 - 1;
+     }
+@@ -3494,7 +3632,7 @@
+     rc = sqlite3BtreeFirst(pCrsr, &res);
+     pC->atFirst = res==0;
+     pC->deferredMoveto = 0;
+-    pC->cacheValid = 0;
++    pC->cacheStatus = CACHE_STALE;
+   }else{
+     res = 1;
+   }
+@@ -3539,7 +3677,7 @@
+       rc = pOp->opcode==OP_Next ? sqlite3BtreeNext(pCrsr, &res) :
+                                   sqlite3BtreePrevious(pCrsr, &res);
+       pC->nullRow = res;
+-      pC->cacheValid = 0;
++      pC->cacheStatus = CACHE_STALE;
+     }
+     if( res==0 ){
+       pc = pOp->p2 - 1;
+@@ -3554,9 +3692,9 @@
+ 
+ /* Opcode: IdxInsert P1 * *
+ **
+-** The top of the stack holds a SQL index key made using the
+-** MakeIdxKey instruction.  This opcode writes that key into the
+-** index P1.  Data for the entry is nil.
++** The top of the stack holds a SQL index key made using either the
++** MakeIdxRec or MakeRecord instructions.  This opcode writes that key
++** into the index P1.  Data for the entry is nil.
+ **
+ ** This instruction only works for indices.  The equivalent instruction
+ ** for tables is OP_Insert.
+@@ -3576,7 +3714,7 @@
+     assert( pC->isTable==0 );
+     rc = sqlite3BtreeInsert(pCrsr, zKey, nKey, "", 0);
+     assert( pC->deferredMoveto==0 );
+-    pC->cacheValid = 0;
++    pC->cacheStatus = CACHE_STALE;
+   }
+   Release(pTos);
+   pTos--;
+@@ -3585,7 +3723,8 @@
+ 
+ /* Opcode: IdxDelete P1 * *
+ **
+-** The top of the stack is an index key built using the MakeIdxKey opcode.
++** The top of the stack is an index key built using the either the
++** MakeIdxRec or MakeRecord opcodes.
+ ** This opcode removes that entry from the index.
+ */
+ case OP_IdxDelete: {        /* no-push */
+@@ -3597,13 +3736,13 @@
+   assert( i>=0 && i<p->nCursor );
+   assert( p->apCsr[i]!=0 );
+   if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
+-    int rx, res;
+-    rx = sqlite3BtreeMoveto(pCrsr, pTos->z, pTos->n, &res);
+-    if( rx==SQLITE_OK && res==0 ){
++    int res;
++    rc = sqlite3BtreeMoveto(pCrsr, pTos->z, pTos->n, &res);
++    if( rc==SQLITE_OK && res==0 ){
+       rc = sqlite3BtreeDelete(pCrsr);
+     }
+     assert( pC->deferredMoveto==0 );
+-    pC->cacheValid = 0;
++    pC->cacheStatus = CACHE_STALE;
+   }
+   Release(pTos);
+   pTos--;
+@@ -3616,7 +3755,7 @@
+ ** the end of the index key pointed to by cursor P1.  This integer should be
+ ** the rowid of the table entry to which this index entry points.
+ **
+-** See also: Rowid, MakeIdxKey.
++** See also: Rowid, MakeIdxRec.
+ */
+ case OP_IdxRowid: {
+   int i = pOp->p1;
+@@ -3700,14 +3839,14 @@
+   assert( p->apCsr[i]!=0 );
+   assert( pTos>=p->aStack );
+   if( (pC = p->apCsr[i])->pCursor!=0 ){
+-    int res, rc;
++    int res;
+  
+     assert( pTos->flags & MEM_Blob );  /* Created using OP_Make*Key */
+-    Stringify(pTos, db->enc);
++    Stringify(pTos, encoding);
+     assert( pC->deferredMoveto==0 );
+     *pC->pIncrKey = pOp->p3!=0;
+     assert( pOp->p3==0 || pOp->opcode!=OP_IdxGT );
+-    rc = sqlite3VdbeIdxKeyCompare(pC, pTos->n, pTos->z, &res);
++    rc = sqlite3VdbeIdxKeyCompare(pC, pTos->n, (u8*)pTos->z, &res);
+     *pC->pIncrKey = 0;
+     if( rc!=SQLITE_OK ){
+       break;
+@@ -3729,7 +3868,7 @@
+ /* Opcode: IdxIsNull P1 P2 *
+ **
+ ** The top of the stack contains an index entry such as might be generated
+-** by the MakeIdxKey opcode.  This routine looks at the first P1 fields of
++** by the MakeIdxRec opcode.  This routine looks at the first P1 fields of
+ ** that key.  If any of the first P1 fields are NULL, then a jump is made
+ ** to address P2.  Otherwise we fall straight through.
+ **
+@@ -3745,9 +3884,9 @@
+   assert( pTos->flags & MEM_Blob );
+   z = pTos->z;
+   n = pTos->n;
+-  k = sqlite3GetVarint32(z, &serial_type);
++  k = sqlite3GetVarint32((u8*)z, &serial_type);
+   for(; k<n && i>0; i--){
+-    k += sqlite3GetVarint32(&z[k], &serial_type);
++    k += sqlite3GetVarint32((u8*)&z[k], &serial_type);
+     if( serial_type==0 ){   /* Serial type 0 is a NULL */
+       pc = pOp->p2-1;
+       break;
+@@ -3810,6 +3949,41 @@
+ ** See also: Destroy
+ */
+ case OP_Clear: {        /* no-push */
++
++  /* For consistency with the way other features of SQLite operate
++  ** with a truncate, we will also skip the update callback.
++  */
++#if 0
++  Btree *pBt = db->aDb[pOp->p2].pBt;
++  if( db->xUpdateCallback && pOp->p3 ){
++    const char *zDb = db->aDb[pOp->p2].zName;
++    const char *zTbl = pOp->p3;
++    BtCursor *pCur = 0;
++    int fin = 0;
++
++    rc = sqlite3BtreeCursor(pBt, pOp->p1, 0, 0, 0, &pCur);
++    if( rc!=SQLITE_OK ){
++      goto abort_due_to_error;
++    }
++    for(
++      rc=sqlite3BtreeFirst(pCur, &fin); 
++      rc==SQLITE_OK && !fin; 
++      rc=sqlite3BtreeNext(pCur, &fin)
++    ){
++      i64 iKey;
++      rc = sqlite3BtreeKeySize(pCur, &iKey);
++      if( rc ){
++        break;
++      }
++      iKey = keyToInt(iKey);
++      db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, zTbl, iKey);
++    }
++    sqlite3BtreeCloseCursor(pCur);
++    if( rc!=SQLITE_OK ){
++      goto abort_due_to_error;
++    }
++  }
++#endif
+   rc = sqlite3BtreeClearTable(db->aDb[pOp->p2].pBt, pOp->p1);
+   break;
+ }
+@@ -3885,10 +4059,15 @@
+   sqlite3SafetyOff(db);
+   assert( db->init.busy==0 );
+   db->init.busy = 1;
++  assert( !sqlite3MallocFailed() );
+   rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
++  sqliteFree(zSql);
+   db->init.busy = 0;
+   sqlite3SafetyOn(db);
+-  sqliteFree(zSql);
++  if( rc==SQLITE_NOMEM ){
++    sqlite3FailedMalloc();
++    goto no_mem;
++  }
+   break;  
+ }
+ 
+@@ -3992,7 +4171,7 @@
+     pTos->xDel = 0;
+   }
+   pTos->enc = SQLITE_UTF8;
+-  sqlite3VdbeChangeEncoding(pTos, db->enc);
++  sqlite3VdbeChangeEncoding(pTos, encoding);
+   sqliteFree(aRoot);
+   break;
+ }
+@@ -4005,7 +4184,7 @@
+ */
+ case OP_FifoWrite: {        /* no-push */
+   assert( pTos>=p->aStack );
+-  Integerify(pTos);
++  sqlite3VdbeMemIntegerify(pTos);
+   sqlite3VdbeFifoPush(&p->sFifo, pTos->i);
+   assert( (pTos->flags & MEM_Dyn)==0 );
+   pTos--;
+@@ -4046,7 +4225,7 @@
+   /* FIX ME: This should be allocated as part of the vdbe at compile-time */
+   if( i>=p->contextStackDepth ){
+     p->contextStackDepth = i+1;
+-    sqlite3ReallocOrFree((void**)&p->contextStack, sizeof(Context)*(i+1));
++    sqliteReallocOrFree((void**)&p->contextStack, sizeof(Context)*(i+1));
+     if( p->contextStack==0 ) goto no_mem;
+   }
+   pContext = &p->contextStack[i];
+@@ -4129,8 +4308,8 @@
+   assert( pTos>=p->aStack );
+   assert( i>=0 && i<p->nMem );
+   pMem = &p->aMem[i];
+-  Integerify(pMem);
+-  Integerify(pTos);
++  sqlite3VdbeMemIntegerify(pMem);
++  sqlite3VdbeMemIntegerify(pTos);
+   if( pMem->i<pTos->i){
+     pMem->i = pTos->i;
+   }
+@@ -4140,30 +4319,27 @@
+ 
+ /* Opcode: MemIncr P1 P2 *
+ **
+-** Increment the integer valued memory cell P1 by 1.  If P2 is not zero
+-** and the result after the increment is exactly 1, then jump
+-** to P2.
++** Increment the integer valued memory cell P2 by the value in P1.
+ **
+-** This instruction throws an error if the memory cell is not initially
+-** an integer.
++** It is illegal to use this instruction on a memory cell that does
++** not contain an integer.  An assertion fault will result if you try.
+ */
+ case OP_MemIncr: {        /* no-push */
+-  int i = pOp->p1;
++  int i = pOp->p2;
+   Mem *pMem;
+   assert( i>=0 && i<p->nMem );
+   pMem = &p->aMem[i];
+   assert( pMem->flags==MEM_Int );
+-  pMem->i++;
+-  if( pOp->p2>0 && pMem->i==1 ){
+-     pc = pOp->p2 - 1;
+-  }
++  pMem->i += pOp->p1;
+   break;
+ }
+ 
+ /* Opcode: IfMemPos P1 P2 *
+ **
+-** If the value of memory cell P1 is 1 or greater, jump to P2. This
+-** opcode assumes that memory cell P1 holds an integer value.
++** If the value of memory cell P1 is 1 or greater, jump to P2.
++**
++** It is illegal to use this instruction on a memory cell that does
++** not contain an integer.  An assertion fault will result if you try.
+ */
+ case OP_IfMemPos: {        /* no-push */
+   int i = pOp->p1;
+@@ -4177,6 +4353,44 @@
+   break;
+ }
+ 
++/* Opcode: IfMemNeg P1 P2 *
++**
++** If the value of memory cell P1 is less than zero, jump to P2. 
++**
++** It is illegal to use this instruction on a memory cell that does
++** not contain an integer.  An assertion fault will result if you try.
++*/
++case OP_IfMemNeg: {        /* no-push */
++  int i = pOp->p1;
++  Mem *pMem;
++  assert( i>=0 && i<p->nMem );
++  pMem = &p->aMem[i];
++  assert( pMem->flags==MEM_Int );
++  if( pMem->i<0 ){
++     pc = pOp->p2 - 1;
++  }
++  break;
++}
++
++/* Opcode: IfMemZero P1 P2 *
++**
++** If the value of memory cell P1 is exactly 0, jump to P2. 
++**
++** It is illegal to use this instruction on a memory cell that does
++** not contain an integer.  An assertion fault will result if you try.
++*/
++case OP_IfMemZero: {        /* no-push */
++  int i = pOp->p1;
++  Mem *pMem;
++  assert( i>=0 && i<p->nMem );
++  pMem = &p->aMem[i];
++  assert( pMem->flags==MEM_Int );
++  if( pMem->i==0 ){
++     pc = pOp->p2 - 1;
++  }
++  break;
++}
++
+ /* Opcode: MemNull P1 * *
+ **
+ ** Store a NULL in memory cell P1
+@@ -4233,12 +4447,15 @@
+   assert( apVal || n==0 );
+   for(i=0; i<n; i++, pRec++){
+     apVal[i] = pRec;
+-    storeTypeInfo(pRec, db->enc);
++    storeTypeInfo(pRec, encoding);
+   }
+   ctx.pFunc = (FuncDef*)pOp->p3;
+   assert( pOp->p1>=0 && pOp->p1<p->nMem );
+   ctx.pMem = pMem = &p->aMem[pOp->p1];
+   pMem->n++;
++  ctx.s.flags = MEM_Null;
++  ctx.s.z = 0;
++  ctx.s.xDel = 0;
+   ctx.isError = 0;
+   ctx.pColl = 0;
+   if( ctx.pFunc->needCollSeq ){
+@@ -4250,8 +4467,10 @@
+   (ctx.pFunc->xStep)(&ctx, n, apVal);
+   popStack(&pTos, n);
+   if( ctx.isError ){
++    sqlite3SetString(&p->zErrMsg, sqlite3_value_text(&ctx.s), (char*)0);
+     rc = SQLITE_ERROR;
+   }
++  sqlite3VdbeMemRelease(&ctx.s);
+   break;
+ }
+ 
+@@ -4272,7 +4491,10 @@
+   assert( pOp->p1>=0 && pOp->p1<p->nMem );
+   pMem = &p->aMem[pOp->p1];
+   assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 );
+-  sqlite3VdbeMemFinalize(pMem, (FuncDef*)pOp->p3);
++  rc = sqlite3VdbeMemFinalize(pMem, (FuncDef*)pOp->p3);
++  if( rc==SQLITE_ERROR ){
++    sqlite3SetString(&p->zErrMsg, sqlite3_value_text(pMem), (char*)0);
++  }
+   break;
+ }
+ 
+@@ -4308,6 +4530,37 @@
+   break;
+ }
+ 
++#ifndef SQLITE_OMIT_SHARED_CACHE
++/* Opcode: TableLock P1 P2 P3
++**
++** Obtain a lock on a particular table. This instruction is only used when
++** the shared-cache feature is enabled. 
++**
++** If P1 is not negative, then it is the index of the index of the database
++** in sqlite3.aDb[] and a read-lock is required. If P1 is negative, a 
++** write-lock is required. In this case the index of the database is the 
++** absolute value of P1 minus one (iDb = abs(P1) - 1;) and a write-lock is
++** required. 
++**
++** P2 contains the root-page of the table to lock.
++**
++** P3 contains a pointer to the name of the table being locked. This is only
++** used to generate an error message if the lock cannot be obtained.
++*/
++case OP_TableLock: {        /* no-push */
++  int p1 = pOp->p1; 
++  u8 isWriteLock = (p1<0);
++  if( isWriteLock ){
++    p1 = (-1*p1)-1;
++  }
++  rc = sqlite3BtreeLockTable(db->aDb[p1].pBt, pOp->p2, isWriteLock);
++  if( rc==SQLITE_LOCKED ){
++    const char *z = (const char *)pOp->p3;
++    sqlite3SetString(&p->zErrMsg, "database table is locked: ", z, (char*)0);
++  }
++  break;
++}
++#endif /* SHARED_OMIT_SHARED_CACHE */
+ 
+ /* An other opcode is illegal...
+ */
+@@ -4347,7 +4600,7 @@
+ #ifndef NDEBUG
+     /* Sanity checking on the top element of the stack */
+     if( pTos>=p->aStack ){
+-      sqlite3VdbeMemSanity(pTos, db->enc);
++      sqlite3VdbeMemSanity(pTos, encoding);
+     }
+     assert( pc>=-1 && pc<p->nOp );
+ #ifdef SQLITE_DEBUG
+@@ -4410,7 +4663,7 @@
+   */
+ abort_due_to_error:
+   if( p->zErrMsg==0 ){
+-    if( sqlite3_malloc_failed ) rc = SQLITE_NOMEM;
++    if( sqlite3MallocFailed() ) rc = SQLITE_NOMEM;
+     sqlite3SetString(&p->zErrMsg, sqlite3ErrStr(rc), (char*)0);
+   }
+   goto vdbe_halt;
+Index: sqlite/sqliteInt.h
+===================================================================
+--- amarok/src/sqlite/sqliteInt.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/sqliteInt.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -17,13 +17,20 @@
+ #define _SQLITEINT_H_
+ 
+ /*
++** Extra interface definitions for those who need them
++*/
++#ifdef SQLITE_EXTRA
++# include "sqliteExtra.h"
++#endif
++
++/*
+ ** Many people are failing to set -DNDEBUG=1 when compiling SQLite.
+ ** Setting NDEBUG makes the code smaller and run faster.  So the following
+ ** lines are added to automatically set NDEBUG unless the -DSQLITE_DEBUG=1
+ ** option is set.  Thus NDEBUG becomes an opt-in rather than an opt-out
+ ** feature.
+ */
+-#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
++#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) 
+ # define NDEBUG 1
+ #endif
+ 
+@@ -60,6 +67,23 @@
+ #include <stddef.h>
+ 
+ /*
++** If compiling for a processor that lacks floating point support,
++** substitute integer for floating-point
++*/
++#ifdef SQLITE_OMIT_FLOATING_POINT
++# define double sqlite_int64
++# define LONGDOUBLE_TYPE sqlite_int64
++# ifndef SQLITE_BIG_DBL
++#   define SQLITE_BIG_DBL (0x7fffffffffffffff)
++# endif
++# define SQLITE_OMIT_DATETIME_FUNCS 1
++# define SQLITE_OMIT_TRACE 1
++#endif
++#ifndef SQLITE_BIG_DBL
++# define SQLITE_BIG_DBL (1e99)
++#endif
++
++/*
+ ** The maximum number of in-memory pages to use for the main database
+ ** table and for temporary tables. Internally, the MAX_PAGES and 
+ ** TEMP_PAGES macros are used. To override the default values at
+@@ -129,18 +153,15 @@
+ #define SQLITE_MAX_VARIABLE_NUMBER 999
+ 
+ /*
+-** When building SQLite for embedded systems where memory is scarce,
+-** you can define one or more of the following macros to omit extra
+-** features of the library and thus keep the size of the library to
+-** a minimum.
++** The "file format" number is an integer that is incremented whenever
++** the VDBE-level file format changes.  The following macros define the
++** the default file format for new databases and the maximum file format
++** that the library can read.
+ */
+-/* #define SQLITE_OMIT_AUTHORIZATION  1 */
+-/* #define SQLITE_OMIT_MEMORYDB     1 */
+-/* #define SQLITE_OMIT_VACUUM         1 */
+-/* #define SQLITE_OMIT_DATETIME_FUNCS 1 */
+-/* #define SQLITE_OMIT_PROGRESS_CALLBACK 1 */
+-/* #define SQLITE_OMIT_AUTOVACUUM */
+-/* #define SQLITE_OMIT_ALTERTABLE */
++#define SQLITE_MAX_FILE_FORMAT 4
++#ifndef SQLITE_DEFAULT_FILE_FORMAT
++# define SQLITE_DEFAULT_FILE_FORMAT 4
++#endif
+ 
+ /*
+ ** Provide a default value for TEMP_STORE in case it is not specified
+@@ -228,6 +249,7 @@
+ */
+ #include "vdbe.h"
+ #include "btree.h"
++#include "pager.h"
+ 
+ /*
+ ** This macro casts a pointer to an integer.  Useful for doing
+@@ -235,54 +257,67 @@
+ */
+ #define Addr(X)  ((uptr)X)
+ 
+-/*
+-** If memory allocation problems are found, recompile with
+-**
+-**      -DSQLITE_DEBUG=1
+-**
+-** to enable some sanity checking on malloc() and free().  To
+-** check for memory leaks, recompile with
+-**
+-**      -DSQLITE_DEBUG=2
+-**
+-** and a line of text will be written to standard error for
+-** each malloc() and free().  This output can be analyzed
+-** by an AWK script to determine if there are any leaks.
+-*/
+ #ifdef SQLITE_MEMDEBUG
+-# define sqliteMalloc(X)    sqlite3Malloc_(X,1,__FILE__,__LINE__)
+-# define sqliteMallocRaw(X) sqlite3Malloc_(X,0,__FILE__,__LINE__)
+-# define sqliteFree(X)      sqlite3Free_(X,__FILE__,__LINE__)
+-# define sqliteRealloc(X,Y) sqlite3Realloc_(X,Y,__FILE__,__LINE__)
+-# define sqliteStrDup(X)    sqlite3StrDup_(X,__FILE__,__LINE__)
+-# define sqliteStrNDup(X,Y) sqlite3StrNDup_(X,Y,__FILE__,__LINE__)
+-#else
+-# define sqliteFree          sqlite3FreeX
+-# define sqliteMalloc        sqlite3Malloc
+-# define sqliteMallocRaw     sqlite3MallocRaw
+-# define sqliteRealloc       sqlite3Realloc
+-# define sqliteStrDup        sqlite3StrDup
+-# define sqliteStrNDup       sqlite3StrNDup
+-#endif
+-
+ /*
+-** This variable gets set if malloc() ever fails.  After it gets set,
+-** the SQLite library shuts down permanently.
+-*/
+-extern int sqlite3_malloc_failed;
+-
+-/*
+ ** The following global variables are used for testing and debugging
+-** only.  They only work if SQLITE_DEBUG is defined.
++** only.  They only work if SQLITE_MEMDEBUG is defined.
+ */
+-#ifdef SQLITE_MEMDEBUG
+ extern int sqlite3_nMalloc;      /* Number of sqliteMalloc() calls */
+ extern int sqlite3_nFree;        /* Number of sqliteFree() calls */
+ extern int sqlite3_iMallocFail;  /* Fail sqliteMalloc() after this many calls */
+ extern int sqlite3_iMallocReset; /* Set iMallocFail to this when it reaches 0 */
++
++
++extern void *sqlite3_pFirst;         /* Pointer to linked list of allocations */
++extern int sqlite3_nMaxAlloc;        /* High water mark of ThreadData.nAlloc */
++extern int sqlite3_mallocDisallowed; /* assert() in sqlite3Malloc() if set */
++extern int sqlite3_isFail;           /* True if all malloc calls should fail */
++extern const char *sqlite3_zFile;    /* Filename to associate debug info with */
++extern int sqlite3_iLine;            /* Line number for debug info */
++
++#define ENTER_MALLOC (sqlite3_zFile = __FILE__, sqlite3_iLine = __LINE__)
++#define sqliteMalloc(x)          (ENTER_MALLOC, sqlite3Malloc(x))
++#define sqliteMallocRaw(x)       (ENTER_MALLOC, sqlite3MallocRaw(x))
++#define sqliteRealloc(x,y)       (ENTER_MALLOC, sqlite3Realloc(x,y))
++#define sqliteStrDup(x)          (ENTER_MALLOC, sqlite3StrDup(x))
++#define sqliteStrNDup(x,y)       (ENTER_MALLOC, sqlite3StrNDup(x,y))
++#define sqliteReallocOrFree(x,y) (ENTER_MALLOC, sqlite3ReallocOrFree(x,y))
++
++#else
++
++#define sqliteMalloc(x)          sqlite3Malloc(x)
++#define sqliteMallocRaw(x)       sqlite3MallocRaw(x)
++#define sqliteRealloc(x,y)       sqlite3Realloc(x,y)
++#define sqliteStrDup(x)          sqlite3StrDup(x)
++#define sqliteStrNDup(x,y)       sqlite3StrNDup(x,y)
++#define sqliteReallocOrFree(x,y) sqlite3ReallocOrFree(x,y)
++
+ #endif
+ 
++#define sqliteFree(x)          sqlite3FreeX(x)
++#define sqliteAllocSize(x)     sqlite3AllocSize(x)
++
++
+ /*
++** An instance of this structure might be allocated to store information
++** specific to a single thread.
++*/
++struct ThreadData {
++  int dummy;               /* So that this structure is never empty */
++
++#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
++  int nSoftHeapLimit;      /* Suggested max mem allocation.  No limit if <0 */
++  int nAlloc;              /* Number of bytes currently allocated */
++  Pager *pPager;           /* Linked list of all pagers in this thread */
++#endif
++
++#ifndef SQLITE_OMIT_SHARED_CACHE
++  u8 useSharedData;        /* True if shared pagers and schemas are enabled */
++  BtShared *pBtree;        /* Linked list of all currently open BTrees */
++#endif
++};
++
++/*
+ ** Name of the master database table.  The master database table
+ ** is a special table that holds the names and attributes of all
+ ** user tables and indices.
+@@ -314,6 +349,7 @@
+ typedef struct CollSeq CollSeq;
+ typedef struct Column Column;
+ typedef struct Db Db;
++typedef struct Schema Schema;
+ typedef struct Expr Expr;
+ typedef struct ExprList ExprList;
+ typedef struct FKey FKey;
+@@ -326,7 +362,9 @@
+ typedef struct Parse Parse;
+ typedef struct Select Select;
+ typedef struct SrcList SrcList;
++typedef struct ThreadData ThreadData;
+ typedef struct Table Table;
++typedef struct TableLock TableLock;
+ typedef struct Token Token;
+ typedef struct TriggerStack TriggerStack;
+ typedef struct TriggerStep TriggerStep;
+@@ -344,28 +382,37 @@
+ struct Db {
+   char *zName;         /* Name of this database */
+   Btree *pBt;          /* The B*Tree structure for this database file */
++  u8 inTrans;          /* 0: not writable.  1: Transaction.  2: Checkpoint */
++  u8 safety_level;     /* How aggressive at synching data to disk */
++  void *pAux;               /* Auxiliary data.  Usually NULL */
++  void (*xFreeAux)(void*);  /* Routine to free pAux */
++  Schema *pSchema;     /* Pointer to database schema (possibly shared) */
++};
++
++/*
++** An instance of the following structure stores a database schema.
++*/
++struct Schema {
+   int schema_cookie;   /* Database schema version number for this file */
+   Hash tblHash;        /* All tables indexed by name */
+   Hash idxHash;        /* All (named) indices indexed by name */
+   Hash trigHash;       /* All triggers indexed by name */
+   Hash aFKey;          /* Foreign keys indexed by to-table */
+-  u16 flags;           /* Flags associated with this database */
+-  u8 inTrans;          /* 0: not writable.  1: Transaction.  2: Checkpoint */
+-  u8 safety_level;     /* How aggressive at synching data to disk */
++  Table *pSeqTab;      /* The sqlite_sequence table used by AUTOINCREMENT */
++  u8 file_format;      /* Schema format version for this file */
++  u8 enc;              /* Text encoding used by this database */
++  u16 flags;           /* Flags associated with this schema */
+   int cache_size;      /* Number of pages to use in the cache */
+-  Table *pSeqTab;      /* The sqlite_sequence table used by AUTOINCREMENT */
+-  void *pAux;               /* Auxiliary data.  Usually NULL */
+-  void (*xFreeAux)(void*);  /* Routine to free pAux */
+ };
+ 
+ /*
+ ** These macros can be used to test, set, or clear bits in the 
+ ** Db.flags field.
+ */
+-#define DbHasProperty(D,I,P)     (((D)->aDb[I].flags&(P))==(P))
+-#define DbHasAnyProperty(D,I,P)  (((D)->aDb[I].flags&(P))!=0)
+-#define DbSetProperty(D,I,P)     (D)->aDb[I].flags|=(P)
+-#define DbClearProperty(D,I,P)   (D)->aDb[I].flags&=~(P)
++#define DbHasProperty(D,I,P)     (((D)->aDb[I].pSchema->flags&(P))==(P))
++#define DbHasAnyProperty(D,I,P)  (((D)->aDb[I].pSchema->flags&(P))!=0)
++#define DbSetProperty(D,I,P)     (D)->aDb[I].pSchema->flags|=(P)
++#define DbClearProperty(D,I,P)   (D)->aDb[I].pSchema->flags&=~(P)
+ 
+ /*
+ ** Allowed values for the DB.flags field.
+@@ -379,6 +426,7 @@
+ */
+ #define DB_SchemaLoaded    0x0001  /* The schema has been loaded */
+ #define DB_UnresetViews    0x0002  /* Some views have defined column names */
++#define DB_Empty           0x0004  /* The file is empty (length 0 bytes) */
+ 
+ #define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE)
+ 
+@@ -413,9 +461,7 @@
+   Db *aDb;                      /* All backends */
+   int flags;                    /* Miscellanous flags. See below */
+   int errCode;                  /* Most recent error code (SQLITE_*) */
+-  u8 enc;                       /* Text encoding for this database. */
+   u8 autoCommit;                /* The auto-commit flag. */
+-  u8 file_format;               /* What file format version is this database? */
+   u8 temp_store;                /* 1: file 2: memory 0: default */
+   int nTable;                   /* Number of tables in the database */
+   CollSeq *pDfltColl;           /* The default collating sequence (BINARY) */
+@@ -435,12 +481,15 @@
+   void *pTraceArg;                          /* Argument to the trace function */
+   void (*xProfile)(void*,const char*,u64);  /* Profiling function */
+   void *pProfileArg;                        /* Argument to profile function */
+-  void *pCommitArg;             /* Argument to xCommitCallback() */   
+-  int (*xCommitCallback)(void*);/* Invoked at every commit. */
++  void *pCommitArg;                 /* Argument to xCommitCallback() */   
++  int (*xCommitCallback)(void*);    /* Invoked at every commit. */
++  void *pRollbackArg;               /* Argument to xRollbackCallback() */   
++  void (*xRollbackCallback)(void*); /* Invoked at every commit. */
++  void *pUpdateArg;
++  void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64);
+   void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*);
+   void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*);
+   void *pCollNeededArg;
+-  sqlite3_value *pValue;        /* Value used for transient conversions */
+   sqlite3_value *pErr;          /* Most recent error message */
+   char *zErrMsg;                /* Most recent error message (UTF-8 encoded) */
+   char *zErrMsg16;              /* Most recent error message (UTF-16 encoded) */
+@@ -467,6 +516,8 @@
+ #endif
+ };
+ 
++#define ENC(db) ((db)->aDb[0].pSchema->enc)
++
+ /*
+ ** Possible values for the sqlite.flags and or Db.flags fields.
+ **
+@@ -475,7 +526,6 @@
+ ** transaction is active on that particular database file.
+ */
+ #define SQLITE_VdbeTrace      0x00000001  /* True to trace VDBE execution */
+-#define SQLITE_Initialized    0x00000002  /* True after initialization */
+ #define SQLITE_Interrupt      0x00000004  /* Cancel current operation */
+ #define SQLITE_InTrans        0x00000008  /* True if in a transaction */
+ #define SQLITE_InternChanges  0x00000010  /* Uncommitted Hash table changes */
+@@ -491,6 +541,10 @@
+ #define SQLITE_WriteSchema    0x00000800  /* OK to update SQLITE_MASTER */
+ #define SQLITE_NoReadlock     0x00001000  /* Readlocks are omitted when 
+                                           ** accessing read-only databases */
++#define SQLITE_IgnoreChecks   0x00002000  /* Do not enforce check constraints */
++#define SQLITE_ReadUncommitted 0x00004000  /* For shared-cache mode */
++#define SQLITE_LegacyFileFmt  0x00008000  /* Create new databases in format 1 */
++#define SQLITE_FullFSync      0x00010000  /* Use full fsync on the backend */
+ 
+ /*
+ ** Possible values for the sqlite.magic field.
+@@ -535,7 +589,7 @@
+   char *zName;     /* Name of this column */
+   Expr *pDflt;     /* Default value of this column */
+   char *zType;     /* Data type for this column */
+-  CollSeq *pColl;  /* Collating sequence.  If NULL, use the default */
++  char *zColl;     /* Collating sequence.  If NULL, use the default */
+   u8 notNull;      /* True if there is a NOT NULL constraint */
+   u8 isPrimKey;    /* True if this column is part of the PRIMARY KEY */
+   char affinity;   /* One of the SQLITE_AFF_... values */
+@@ -551,7 +605,7 @@
+ ** processes text encoded in UTF-16 (CollSeq.xCmp16), using the machine
+ ** native byte order. When a collation sequence is invoked, SQLite selects
+ ** the version that will require the least expensive encoding
+-** transalations, if any.
++** translations, if any.
+ **
+ ** The CollSeq.pUser member variable is an extra parameter that passed in
+ ** as the first argument to the UTF-8 comparison function, xCmp.
+@@ -586,12 +640,25 @@
+ 
+ /*
+ ** Column affinity types.
++**
++** These used to have mnemonic name like 'i' for SQLITE_AFF_INTEGER and
++** 't' for SQLITE_AFF_TEXT.  But we can save a little space and improve
++** the speed a little by number the values consecutively.  
++**
++** But rather than start with 0 or 1, we begin with 'a'.  That way,
++** when multiple affinity types are concatenated into a string and
++** used as the P3 operand, they will be more readable.
++**
++** Note also that the numeric types are grouped together so that testing
++** for a numeric type is a single comparison.
+ */
+-#define SQLITE_AFF_INTEGER  'i'
+-#define SQLITE_AFF_NUMERIC  'n'
+-#define SQLITE_AFF_TEXT     't'
+-#define SQLITE_AFF_NONE     'o'
++#define SQLITE_AFF_TEXT     'a'
++#define SQLITE_AFF_NONE     'b'
++#define SQLITE_AFF_NUMERIC  'c'
++#define SQLITE_AFF_INTEGER  'd'
++#define SQLITE_AFF_REAL     'e'
+ 
++#define sqlite3IsNumericAffinity(X)  ((X)>=SQLITE_AFF_NUMERIC)
+ 
+ /*
+ ** Each SQL table is represented in memory by an instance of the
+@@ -632,7 +699,6 @@
+   int tnum;        /* Root BTree node for this table (see note above) */
+   Select *pSelect; /* NULL for tables.  Points to definition if a view. */
+   u8 readOnly;     /* True if this table should not be written by the user */
+-  u8 iDb;          /* Index into sqlite.aDb[] of the backend for this table */
+   u8 isTransient;  /* True if automatically deleted when VDBE finishes */
+   u8 hasPrimKey;   /* True if there exists a primary key */
+   u8 keyConf;      /* What to do in case of uniqueness conflict on iPKey */
+@@ -641,9 +707,13 @@
+   Trigger *pTrigger; /* List of SQL triggers on this table */
+   FKey *pFKey;       /* Linked list of all foreign keys in this table */
+   char *zColAff;     /* String defining the affinity of each column */
++#ifndef SQLITE_OMIT_CHECK
++  Expr *pCheck;      /* The AND of all CHECK constraints */
++#endif
+ #ifndef SQLITE_OMIT_ALTERTABLE
+   int addColOffset;  /* Offset in CREATE TABLE statement to add a new column */
+ #endif
++  Schema *pSchema;
+ };
+ 
+ /*
+@@ -779,10 +849,11 @@
+   int tnum;        /* Page containing root of this index in database file */
+   u8 onError;      /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
+   u8 autoIndex;    /* True if is automatically created (ex: by UNIQUE) */
+-  u8 iDb;          /* Index in sqlite.aDb[] of where this index is stored */
+   char *zColAff;   /* String defining the affinity of each column */
+   Index *pNext;    /* The next index associated with the same table */
+-  KeyInfo keyInfo; /* Info on how to order keys.  MUST BE LAST */
++  Schema *pSchema; /* Schema containing this index */
++  u8 *aSortOrder;  /* Array of size Index.nColumn. True==DESC, False==ASC */
++  char **azColl;   /* Array of collation sequence names for index */
+ };
+ 
+ /*
+@@ -891,7 +962,6 @@
+ struct Expr {
+   u8 op;                 /* Operation performed by this node */
+   char affinity;         /* The affinity of the column or 0 if not a column */
+-  u8 iDb;                /* Database referenced by this expression */
+   u8 flags;              /* Various flags.  See below */
+   CollSeq *pColl;        /* The collation type of the column or 0 */
+   Expr *pLeft, *pRight;  /* Left and right subnodes */
+@@ -907,6 +977,7 @@
+   Select *pSelect;       /* When the expression is a sub-select.  Also the
+                          ** right side of "<expr> IN (<select>)" */
+   Table *pTab;           /* Table for OP_Column expressions. */
++  Schema *pSchema;
+ };
+ 
+ /*
+@@ -999,6 +1070,7 @@
+     char *zAlias;     /* The "B" part of a "A AS B" phrase.  zName is the "A" */
+     Table *pTab;      /* An SQL table corresponding to zName */
+     Select *pSelect;  /* A SELECT statement used in place of a table name */
++    u8 isPopulated;   /* Temporary table associated with SELECT is populated */
+     u8 jointype;      /* Type of join between this table and the next */
+     i16 iCursor;      /* The VDBE cursor number used to access this table */
+     Expr *pOn;        /* The ON clause of a join */
+@@ -1087,6 +1159,7 @@
+   int nErr;            /* Number of errors encountered while resolving names */
+   u8 allowAgg;         /* Aggregate functions allowed here */
+   u8 hasAgg;           /* True if aggregates are seen */
++  u8 isCheck;          /* True if resolving names in a CHECK constraint */
+   int nDepth;          /* Depth of subquery recursion. 1 for no recursion */
+   AggInfo *pAggInfo;   /* Information about aggregates at this level */
+   NameContext *pNext;  /* Next outer name context.  NULL for outermost */
+@@ -1149,7 +1222,7 @@
+ #define SRT_Table        7  /* Store result as data with an automatic rowid */
+ #define SRT_VirtualTab   8  /* Create virtual table and store like SRT_Table */
+ #define SRT_Subroutine   9  /* Call a subroutine to handle results */
+-#define SRT_Exists      10  /* Put 0 or 1 in a memory cell */
++#define SRT_Exists      10  /* Store 1 if the result is not empty */
+ 
+ /*
+ ** An SQL parser context.  A copy of this structure is passed through
+@@ -1160,6 +1233,12 @@
+ ** generate call themselves recursively, the first part of the structure
+ ** is constant but the second part is reset at the beginning and end of
+ ** each recursion.
++**
++** The nTableLock and aTableLock variables are only used if the shared-cache 
++** feature is enabled (if sqlite3Tsd()->useSharedData is true). They are
++** used to store the set of table-locks required by the statement being
++** compiled. Function sqlite3TableLock() is used to add entries to the
++** list.
+ */
+ struct Parse {
+   sqlite3 *db;         /* The main database structure */
+@@ -1174,10 +1253,15 @@
+   int nTab;            /* Number of previously allocated VDBE cursors */
+   int nMem;            /* Number of memory cells used so far */
+   int nSet;            /* Number of sets used so far */
++  int ckOffset;        /* Stack offset to data used by CHECK constraints */
+   u32 writeMask;       /* Start a write transaction on these databases */
+   u32 cookieMask;      /* Bitmask of schema verified databases */
+   int cookieGoto;      /* Address of OP_Goto to cookie verifier subroutine */
+   int cookieValue[MAX_ATTACHED+2];  /* Values of cookies to verify */
++#ifndef SQLITE_OMIT_SHARED_CACHE
++  int nTableLock;        /* Number of locks in aTableLock */
++  TableLock *aTableLock; /* Required table locks for shared-cache mode */
++#endif
+ 
+   /* Above is constant between recursions.  Below is reset before and after
+   ** each recursion */
+@@ -1212,6 +1296,7 @@
+ */
+ #define OPFLAG_NCHANGE   1    /* Set to update db->nChange */
+ #define OPFLAG_LASTROWID 2    /* Set to update db->lastRowid */
++#define OPFLAG_ISUPDATE  4    /* This OP_Insert is an sql UPDATE */
+ 
+ /*
+  * Each trigger present in the database schema is stored as an instance of
+@@ -1231,8 +1316,6 @@
+ struct Trigger {
+   char *name;             /* The name of the trigger                        */
+   char *table;            /* The table or view to which the trigger applies */
+-  u8 iDb;                 /* Database containing this trigger               */
+-  u8 iTabDb;              /* Database containing Trigger.table              */
+   u8 op;                  /* One of TK_DELETE, TK_UPDATE, TK_INSERT         */
+   u8 tr_tm;               /* One of TRIGGER_BEFORE, TRIGGER_AFTER */
+   Expr *pWhen;            /* The WHEN clause of the expresion (may be NULL) */
+@@ -1240,7 +1323,8 @@
+                              the <column-list> is stored here */
+   int foreach;            /* One of TK_ROW or TK_STATEMENT */
+   Token nameToken;        /* Token containing zName. Use during parsing only */
+-
++  Schema *pSchema;        /* Schema containing the trigger */
++  Schema *pTabSchema;     /* Schema containing the table */
+   TriggerStep *step_list; /* Link list of trigger program steps             */
+   Trigger *pNext;         /* Next trigger associated with the table */
+ };
+@@ -1398,35 +1482,29 @@
+ int sqlite3Compare(const char *, const char *);
+ int sqlite3SortCompare(const char *, const char *);
+ void sqlite3RealToSortable(double r, char *);
+-#ifdef SQLITE_MEMDEBUG
+-  void *sqlite3Malloc_(int,int,char*,int);
+-  void sqlite3Free_(void*,char*,int);
+-  void *sqlite3Realloc_(void*,int,char*,int);
+-  char *sqlite3StrDup_(const char*,char*,int);
+-  char *sqlite3StrNDup_(const char*, int,char*,int);
+-  void sqlite3CheckMemory(void*,int);
+-#else
+-  void *sqlite3Malloc(int);
+-  void *sqlite3MallocRaw(int);
+-  void sqlite3Free(void*);
+-  void *sqlite3Realloc(void*,int);
+-  char *sqlite3StrDup(const char*);
+-  char *sqlite3StrNDup(const char*, int);
++
++void *sqlite3Malloc(int);
++void *sqlite3MallocRaw(int);
++void sqlite3Free(void*);
++void *sqlite3Realloc(void*,int);
++char *sqlite3StrDup(const char*);
++char *sqlite3StrNDup(const char*, int);
+ # define sqlite3CheckMemory(a,b)
+-# define sqlite3MallocX sqlite3Malloc
+-#endif
+ void sqlite3ReallocOrFree(void**,int);
+ void sqlite3FreeX(void*);
+ void *sqlite3MallocX(int);
++int sqlite3AllocSize(void *);
++
+ char *sqlite3MPrintf(const char*, ...);
+ char *sqlite3VMPrintf(const char*, va_list);
+ void sqlite3DebugPrintf(const char*, ...);
+ void *sqlite3TextToPtr(const char*);
+ void sqlite3SetString(char **, ...);
+ void sqlite3ErrorMsg(Parse*, const char*, ...);
++void sqlite3ErrorClear(Parse*);
+ void sqlite3Dequote(char*);
+ void sqlite3DequoteExpr(Expr*);
+-int sqlite3KeywordCode(const char*, int);
++int sqlite3KeywordCode(const unsigned char*, int);
+ int sqlite3RunParser(Parse*, const char*, char **);
+ void sqlite3FinishCoding(Parse*);
+ Expr *sqlite3Expr(int, Expr*, Expr*, const Token*);
+@@ -1446,11 +1524,12 @@
+ void sqlite3RollbackInternalChanges(sqlite3*);
+ void sqlite3CommitInternalChanges(sqlite3*);
+ Table *sqlite3ResultSetOfSelect(Parse*,char*,Select*);
+-void sqlite3OpenMasterTable(Vdbe *v, int);
+-void sqlite3StartTable(Parse*,Token*,Token*,Token*,int,int);
++void sqlite3OpenMasterTable(Parse *, int);
++void sqlite3StartTable(Parse*,Token*,Token*,Token*,int,int,int);
+ void sqlite3AddColumn(Parse*,Token*);
+ void sqlite3AddNotNull(Parse*, int);
+-void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int);
++void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int);
++void sqlite3AddCheckConstraint(Parse*, Expr*);
+ void sqlite3AddColumnType(Parse*,Token*);
+ void sqlite3AddDefaultValue(Parse*,Expr*);
+ void sqlite3AddCollateType(Parse*, const char*, int);
+@@ -1463,7 +1542,7 @@
+ # define sqlite3ViewGetColumnNames(A,B) 0
+ #endif
+ 
+-void sqlite3DropTable(Parse*, SrcList*, int);
++void sqlite3DropTable(Parse*, SrcList*, int, int);
+ void sqlite3DeleteTable(sqlite3*, Table*);
+ void sqlite3Insert(Parse*, SrcList*, ExprList*, Select*, IdList*, int);
+ int sqlite3ArrayAllocate(void**,int,int);
+@@ -1475,8 +1554,8 @@
+ void sqlite3IdListDelete(IdList*);
+ void sqlite3SrcListDelete(SrcList*);
+ void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
+-                        Token*);
+-void sqlite3DropIndex(Parse*, SrcList*);
++                        Token*, int, int);
++void sqlite3DropIndex(Parse*, SrcList*, int);
+ void sqlite3AddKeyType(Vdbe*, ExprList*);
+ void sqlite3AddIdxKeyType(Vdbe*, Index*);
+ int sqlite3Select(Parse*, Select*, int, int, Select*, int, int*, char *aff);
+@@ -1486,8 +1565,7 @@
+ void sqlite3SelectUnbind(Select*);
+ Table *sqlite3SrcListLookup(Parse*, SrcList*);
+ int sqlite3IsReadOnly(Parse*, Table*, int);
+-void sqlite3OpenTableForReading(Vdbe*, int iCur, Table*);
+-void sqlite3OpenTable(Vdbe*, int iCur, Table*, int);
++void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
+ void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
+ void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
+ WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**);
+@@ -1583,8 +1661,8 @@
+ # define sqlite3AuthContextPush(a,b,c)
+ # define sqlite3AuthContextPop(a)  ((void)(a))
+ #endif
+-void sqlite3Attach(Parse*, Token*, Token*, int, Token*);
+-void sqlite3Detach(Parse*, Token*);
++void sqlite3Attach(Parse*, Expr*, Expr*, Expr*);
++void sqlite3Detach(Parse*, Expr*);
+ int sqlite3BtreeFactory(const sqlite3 *db, const char *zFilename,
+                        int omitJournal, int nCache, Btree **ppBtree);
+ int sqlite3FixInit(DbFixer*, Parse*, int, const char*, const Token*);
+@@ -1630,7 +1708,7 @@
+ void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, void(*)(void*));
+ void sqlite3ValueFree(sqlite3_value*);
+ sqlite3_value *sqlite3ValueNew(void);
+-sqlite3_value *sqlite3GetTransientValue(sqlite3*db);
++char *sqlite3utf16to8(const void*, int);
+ int sqlite3ValueFromExpr(Expr *, u8, u8, sqlite3_value **);
+ void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8);
+ extern const unsigned char sqlite3UpperToLower[];
+@@ -1656,7 +1734,39 @@
+ void sqlite3DefaultRowEst(Index*);
+ void sqlite3RegisterLikeFunctions(sqlite3*, int);
+ int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*);
++ThreadData *sqlite3ThreadData(void);
++const ThreadData *sqlite3ThreadDataReadOnly(void);
++void sqlite3ReleaseThreadData(void);
++void sqlite3AttachFunctions(sqlite3 *);
++void sqlite3MinimumFileFormat(Parse*, int, int);
++void sqlite3SchemaFree(void *);
++Schema *sqlite3SchemaGet(Btree *);
++int sqlite3SchemaToIndex(sqlite3 *db, Schema *);
++KeyInfo *sqlite3IndexKeyinfo(Parse *, Index *);
++int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *, 
++  void (*)(sqlite3_context*,int,sqlite3_value **),
++  void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*));
++int sqlite3ApiExit(sqlite3 *db, int);
++int sqlite3MallocFailed(void);
++void sqlite3FailedMalloc(void);
++void sqlite3AbortOtherActiveVdbes(sqlite3 *, Vdbe *);
+ 
++#ifndef SQLITE_OMIT_SHARED_CACHE
++  void sqlite3TableLock(Parse *, int, int, u8, const char *);
++#else
++  #define sqlite3TableLock(v,w,x,y,z)
++#endif
++
++#ifdef SQLITE_MEMDEBUG
++  void sqlite3MallocDisallow(void);
++  void sqlite3MallocAllow(void);
++  int sqlite3TestMallocFail(void);
++#else
++  #define sqlite3TestMallocFail() 0
++  #define sqlite3MallocDisallow()
++  #define sqlite3MallocAllow()
++#endif
++
+ #ifdef SQLITE_SSE
+ #include "sseInt.h"
+ #endif
+Index: sqlite/update.c
+===================================================================
+--- amarok/src/sqlite/update.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/update.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -17,8 +17,8 @@
+ #include "sqliteInt.h"
+ 
+ /*
+-** The most recently coded instruction was an OP_Column to retrieve column
+-** 'i' of table pTab. This routine sets the P3 parameter of the 
++** The most recently coded instruction was an OP_Column to retrieve the
++** i-th column of table pTab. This routine sets the P3 parameter of the 
+ ** OP_Column to the default value, if any.
+ **
+ ** The default value of a column is specified by a DEFAULT clause in the 
+@@ -44,7 +44,7 @@
+ void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i){
+   if( pTab && !pTab->pSelect ){
+     sqlite3_value *pValue;
+-    u8 enc = sqlite3VdbeDb(v)->enc;
++    u8 enc = ENC(sqlite3VdbeDb(v));
+     Column *pCol = &pTab->aCol[i];
+     sqlite3ValueFromExpr(pCol->pDflt, enc, pCol->affinity, &pValue);
+     if( pValue ){
+@@ -89,6 +89,7 @@
+   int openAll = 0;       /* True if all indices need to be opened */
+   AuthContext sContext;  /* The authorization context */
+   NameContext sNC;       /* The name-context to resolve expressions in */
++  int iDb;               /* Database containing the table being updated */
+ 
+ #ifndef SQLITE_OMIT_TRIGGER
+   int isView;                  /* Trying to update a view */
+@@ -99,7 +100,9 @@
+   int oldIdx      = -1;  /* index of trigger "old" temp table       */
+ 
+   sContext.pParse = 0;
+-  if( pParse->nErr || sqlite3_malloc_failed ) goto update_cleanup;
++  if( pParse->nErr || sqlite3MallocFailed() ){
++    goto update_cleanup;
++  }
+   db = pParse->db;
+   assert( pTabList->nSrc==1 );
+ 
+@@ -107,6 +110,7 @@
+   */
+   pTab = sqlite3SrcListLookup(pParse, pTabList);
+   if( pTab==0 ) goto update_cleanup;
++  iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
+ 
+   /* Figure out if we have any triggers and if the table being
+   ** updated is a view
+@@ -192,7 +196,7 @@
+     {
+       int rc;
+       rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab->zName,
+-                           pTab->aCol[j].zName, db->aDb[pTab->iDb].zName);
++                           pTab->aCol[j].zName, db->aDb[iDb].zName);
+       if( rc==SQLITE_DENY ){
+         goto update_cleanup;
+       }else if( rc==SQLITE_IGNORE ){
+@@ -231,7 +235,6 @@
+       }
+     }
+     if( i<pIdx->nColumn ){
+-      if( sqlite3CheckIndexCollSeq(pParse, pIdx) ) goto update_cleanup;
+       apIdx[nIdx++] = pIdx;
+       aIdxUsed[j] = 1;
+     }else{
+@@ -257,7 +260,7 @@
+   v = sqlite3GetVdbe(pParse);
+   if( v==0 ) goto update_cleanup;
+   if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
+-  sqlite3BeginWriteOperation(pParse, 1, pTab->iDb);
++  sqlite3BeginWriteOperation(pParse, 1, iDb);
+ 
+   /* If we are trying to update a view, realize that view into
+   ** a ephemeral table.
+@@ -307,7 +310,7 @@
+       /* Open a cursor and make it point to the record that is
+       ** being updated.
+       */
+-      sqlite3OpenTableForReading(v, iCur, pTab);
++      sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
+     }
+     sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
+ 
+@@ -362,9 +365,7 @@
+     ** action, then we need to open all indices because we might need
+     ** to be deleting some records.
+     */
+-    sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
+-    sqlite3VdbeAddOp(v, OP_OpenWrite, iCur, pTab->tnum);
+-    sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol);
++    sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite); 
+     if( onError==OE_Replace ){
+       openAll = 1;
+     }else{
+@@ -378,9 +379,10 @@
+     }
+     for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
+       if( openAll || aIdxUsed[i] ){
+-        sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
++        KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
++        sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
+         sqlite3VdbeOp3(v, OP_OpenWrite, iCur+i+1, pIdx->tnum,
+-                       (char*)&pIdx->keyInfo, P3_KEYINFO);
++                       (char*)pKey, P3_KEYINFO_HANDOFF);
+         assert( pParse->nTab>iCur+i+1 );
+       }
+     }
+@@ -492,7 +494,7 @@
+   if( db->flags & SQLITE_CountRows && !pParse->trigStack && pParse->nested==0 ){
+     sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
+     sqlite3VdbeSetNumCols(v, 1);
+-    sqlite3VdbeSetColName(v, 0, "rows updated", P3_STATIC);
++    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", P3_STATIC);
+   }
+ 
+ update_cleanup:
+Index: sqlite/os_unix.c
+===================================================================
+--- amarok/src/sqlite/os_unix.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/os_unix.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -16,15 +16,100 @@
+ #include "os.h"
+ #if OS_UNIX              /* This file is used on unix only */
+ 
++/*
++** These #defines should enable >2GB file support on Posix if the
++** underlying operating system supports it.  If the OS lacks
++** large file support, these should be no-ops.
++**
++** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch
++** on the compiler command line.  This is necessary if you are compiling
++** on a recent machine (ex: RedHat 7.2) but you want your code to work
++** on an older machine (ex: RedHat 6.0).  If you compile on RedHat 7.2
++** without this option, LFS is enable.  But LFS does not exist in the kernel
++** in RedHat 6.0, so the code won't work.  Hence, for maximum binary
++** portability you should omit LFS.
++*/
++#ifndef SQLITE_DISABLE_LFS
++# define _LARGE_FILE       1
++# ifndef _FILE_OFFSET_BITS
++#   define _FILE_OFFSET_BITS 64
++# endif
++# define _LARGEFILE_SOURCE 1
++#endif
+ 
++/*
++** standard include files.
++*/
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++#include <unistd.h>
+ #include <time.h>
+ #include <sys/time.h>
+ #include <errno.h>
+-#include <unistd.h>
+ 
+ /*
++** If we are to be thread-safe, include the pthreads header and define
++** the SQLITE_UNIX_THREADS macro.
++*/
++#if defined(THREADSAFE) && THREADSAFE
++# include <pthread.h>
++# define SQLITE_UNIX_THREADS 1
++#endif
++
++/*
++** Default permissions when creating a new file
++*/
++#ifndef SQLITE_DEFAULT_FILE_PERMISSIONS
++# define SQLITE_DEFAULT_FILE_PERMISSIONS 0644
++#endif
++
++
++
++/*
++** The unixFile structure is subclass of OsFile specific for the unix
++** protability layer.
++*/
++typedef struct unixFile unixFile;
++struct unixFile {
++  IoMethod const *pMethod;  /* Always the first entry */
++  struct openCnt *pOpen;    /* Info about all open fd's on this inode */
++  struct lockInfo *pLock;   /* Info about locks on this inode */
++  int h;                    /* The file descriptor */
++  unsigned char locktype;   /* The type of lock held on this fd */
++  unsigned char isOpen;     /* True if needs to be closed */
++  unsigned char fullSync;   /* Use F_FULLSYNC if available */
++  int dirfd;                /* File descriptor for the directory */
++#ifdef SQLITE_UNIX_THREADS
++  pthread_t tid;            /* The thread that "owns" this OsFile */
++#endif
++};
++
++/*
++** Provide the ability to override some OS-layer functions during
++** testing.  This is used to simulate OS crashes to verify that 
++** commits are atomic even in the event of an OS crash.
++*/
++#ifdef SQLITE_CRASH_TEST
++  extern int sqlite3CrashTestEnable;
++  extern int sqlite3CrashOpenReadWrite(const char*, OsFile**, int*);
++  extern int sqlite3CrashOpenExclusive(const char*, OsFile**, int);
++  extern int sqlite3CrashOpenReadOnly(const char*, OsFile**, int);
++# define CRASH_TEST_OVERRIDE(X,A,B,C) \
++    if(sqlite3CrashTestEnable){ return X(A,B,C); }
++#else
++# define CRASH_TEST_OVERRIDE(X,A,B,C)  /* no-op */
++#endif
++
++
++/*
++** Include code that is common to all os_*.c files
++*/
++#include "os_common.h"
++
++/*
+ ** Do not include any of the File I/O interface procedures if the
+-** SQLITE_OMIT_DISKIO macro is defined (indicating that there database
++** SQLITE_OMIT_DISKIO macro is defined (indicating that the database
+ ** will be in-memory only)
+ */
+ #ifndef SQLITE_OMIT_DISKIO
+@@ -51,18 +136,13 @@
+ ** The DJGPP compiler environment looks mostly like Unix, but it
+ ** lacks the fcntl() system call.  So redefine fcntl() to be something
+ ** that always succeeds.  This means that locking does not occur under
+-** DJGPP.  But its DOS - what did you expect?
++** DJGPP.  But it's DOS - what did you expect?
+ */
+ #ifdef __DJGPP__
+ # define fcntl(A,B,C) 0
+ #endif
+ 
+ /*
+-** Include code that is common to all os_*.c files
+-*/
+-#include "os_common.h"
+-
+-/*
+ ** The threadid macro resolves to the thread-id or to 0.  Used for
+ ** testing and debugging only.
+ */
+@@ -80,10 +160,18 @@
+ ** means that sqlite3* database handles cannot be moved from one thread
+ ** to another.  This logic makes sure a user does not try to do that
+ ** by mistake.
++**
++** Version 3.3.1 (2006-01-15):  OsFiles can be moved from one thread to
++** another as long as we are running on a system that supports threads
++** overriding each others locks (which now the most common behavior)
++** or if no locks are held.  But the OsFile.pLock field needs to be
++** recomputed because its key includes the thread-id.  See the 
++** transferOwnership() function below for additional information
+ */
+-#ifdef SQLITE_UNIX_THREADS
+-# define SET_THREADID(X)   X->tid = pthread_self()
+-# define CHECK_THREADID(X) (!pthread_equal(X->tid, pthread_self()))
++#if defined(SQLITE_UNIX_THREADS)
++# define SET_THREADID(X)   (X)->tid = pthread_self()
++# define CHECK_THREADID(X) (threadsOverrideEachOthersLocks==0 && \
++                            !pthread_equal((X)->tid, pthread_self()))
+ #else
+ # define SET_THREADID(X)
+ # define CHECK_THREADID(X) 0
+@@ -195,14 +283,14 @@
+ **
+ ** If threads cannot override each others locks, then we set the
+ ** lockKey.tid field to the thread ID.  If threads can override
+-** each others locks then tid is always set to zero.  tid is also
+-** set to zero if we compile without threading support.
++** each others locks then tid is always set to zero.  tid is omitted
++** if we compile without threading support.
+ */
+ struct lockKey {
+   dev_t dev;       /* Device number */
+   ino_t ino;       /* Inode number */
+ #ifdef SQLITE_UNIX_THREADS
+-  pthread_t tid;   /* Thread ID or zero if threads cannot override each other */
++  pthread_t tid;   /* Thread ID or zero if threads can override each other */
+ #endif
+ };
+ 
+@@ -248,8 +336,9 @@
+ };
+ 
+ /* 
+-** These hash table maps inodes and process IDs into lockInfo and openCnt
+-** structures.  Access to these hash tables must be protected by a mutex.
++** These hash tables map inodes and file descriptors (really, lockKey and
++** openKey structures) into lockInfo and openCnt structures.  Access to 
++** these hash tables must be protected by a mutex.
+ */
+ static Hash lockHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 };
+ static Hash openHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 };
+@@ -263,8 +352,25 @@
+ **    0:  No.  Threads cannot override each others locks.
+ **    1:  Yes.  Threads can override each others locks.
+ **   -1:  We don't know yet.
++**
++** On some systems, we know at compile-time if threads can override each
++** others locks.  On those systems, the SQLITE_THREAD_OVERRIDE_LOCK macro
++** will be set appropriately.  On other systems, we have to check at
++** runtime.  On these latter systems, SQLTIE_THREAD_OVERRIDE_LOCK is
++** undefined.
++**
++** This variable normally has file scope only.  But during testing, we make
++** it a global so that the test code can change its value in order to verify
++** that the right stuff happens in either case.
+ */
+-static int threadsOverrideEachOthersLocks = -1;
++#ifndef SQLITE_THREAD_OVERRIDE_LOCK
++# define SQLITE_THREAD_OVERRIDE_LOCK -1
++#endif
++#ifdef SQLITE_TEST
++int threadsOverrideEachOthersLocks = SQLITE_THREAD_OVERRIDE_LOCK;
++#else
++static int threadsOverrideEachOthersLocks = SQLITE_THREAD_OVERRIDE_LOCK;
++#endif
+ 
+ /*
+ ** This structure holds information passed into individual test
+@@ -283,7 +389,7 @@
+ ** This routine is used for troubleshooting locks on multithreaded
+ ** platforms.  Enable by compiling with the -DSQLITE_LOCK_TRACE
+ ** command-line option on the compiler.  This code is normally
+-** turnned off.
++** turned off.
+ */
+ static int lockTrace(int fd, int op, struct flock *p){
+   char *zOpName, *zType;
+@@ -353,7 +459,7 @@
+ ** can override each others locks then sets the 
+ ** threadsOverrideEachOthersLocks variable appropriately.
+ */
+-static void testThreadLockingBehavior(fd_orig){
++static void testThreadLockingBehavior(int fd_orig){
+   int fd;
+   struct threadTestData d[2];
+   pthread_t t[2];
+@@ -381,6 +487,7 @@
+ ** Release a lockInfo structure previously allocated by findLockInfo().
+ */
+ static void releaseLockInfo(struct lockInfo *pLock){
++  assert( sqlite3OsInMutex(1) );
+   pLock->nRef--;
+   if( pLock->nRef==0 ){
+     sqlite3HashInsert(&lockHash, &pLock->key, sizeof(pLock->key), 0);
+@@ -392,18 +499,19 @@
+ ** Release a openCnt structure previously allocated by findLockInfo().
+ */
+ static void releaseOpenCnt(struct openCnt *pOpen){
++  assert( sqlite3OsInMutex(1) );
+   pOpen->nRef--;
+   if( pOpen->nRef==0 ){
+     sqlite3HashInsert(&openHash, &pOpen->key, sizeof(pOpen->key), 0);
+-    sqliteFree(pOpen->aPending);
++    free(pOpen->aPending);
+     sqliteFree(pOpen);
+   }
+ }
+ 
+ /*
+ ** Given a file descriptor, locate lockInfo and openCnt structures that
+-** describes that file descriptor.  Create a new ones if necessary.  The
+-** return values might be unset if an error occurs.
++** describes that file descriptor.  Create new ones if necessary.  The
++** return values might be uninitialized if an error occurs.
+ **
+ ** Return the number of errors.
+ */
+@@ -420,6 +528,8 @@
+   struct openCnt *pOpen;
+   rc = fstat(fd, &statbuf);
+   if( rc!=0 ) return 1;
++
++  assert( sqlite3OsInMutex(1) );
+   memset(&key1, 0, sizeof(key1));
+   key1.dev = statbuf.st_dev;
+   key1.ino = statbuf.st_ino;
+@@ -436,7 +546,10 @@
+   if( pLock==0 ){
+     struct lockInfo *pOld;
+     pLock = sqliteMallocRaw( sizeof(*pLock) );
+-    if( pLock==0 ) return 1;
++    if( pLock==0 ){
++      rc = 1;
++      goto exit_findlockinfo;
++    }
+     pLock->key = key1;
+     pLock->nRef = 1;
+     pLock->cnt = 0;
+@@ -445,43 +558,113 @@
+     if( pOld!=0 ){
+       assert( pOld==pLock );
+       sqliteFree(pLock);
+-      return 1;
++      rc = 1;
++      goto exit_findlockinfo;
+     }
+   }else{
+     pLock->nRef++;
+   }
+   *ppLock = pLock;
+-  pOpen = (struct openCnt*)sqlite3HashFind(&openHash, &key2, sizeof(key2));
+-  if( pOpen==0 ){
+-    struct openCnt *pOld;
+-    pOpen = sqliteMallocRaw( sizeof(*pOpen) );
++  if( ppOpen!=0 ){
++    pOpen = (struct openCnt*)sqlite3HashFind(&openHash, &key2, sizeof(key2));
+     if( pOpen==0 ){
+-      releaseLockInfo(pLock);
+-      return 1;
++      struct openCnt *pOld;
++      pOpen = sqliteMallocRaw( sizeof(*pOpen) );
++      if( pOpen==0 ){
++        releaseLockInfo(pLock);
++        rc = 1;
++        goto exit_findlockinfo;
++      }
++      pOpen->key = key2;
++      pOpen->nRef = 1;
++      pOpen->nLock = 0;
++      pOpen->nPending = 0;
++      pOpen->aPending = 0;
++      pOld = sqlite3HashInsert(&openHash, &pOpen->key, sizeof(key2), pOpen);
++      if( pOld!=0 ){
++        assert( pOld==pOpen );
++        sqliteFree(pOpen);
++        releaseLockInfo(pLock);
++        rc = 1;
++        goto exit_findlockinfo;
++      }
++    }else{
++      pOpen->nRef++;
+     }
+-    pOpen->key = key2;
+-    pOpen->nRef = 1;
+-    pOpen->nLock = 0;
+-    pOpen->nPending = 0;
+-    pOpen->aPending = 0;
+-    pOld = sqlite3HashInsert(&openHash, &pOpen->key, sizeof(key2), pOpen);
+-    if( pOld!=0 ){
+-      assert( pOld==pOpen );
+-      sqliteFree(pOpen);
+-      releaseLockInfo(pLock);
+-      return 1;
+-    }
+-  }else{
+-    pOpen->nRef++;
++    *ppOpen = pOpen;
+   }
+-  *ppOpen = pOpen;
+-  return 0;
++
++exit_findlockinfo:
++  return rc;
+ }
+ 
++#ifdef SQLITE_DEBUG
+ /*
++** Helper function for printing out trace information from debugging
++** binaries. This returns the string represetation of the supplied
++** integer lock-type.
++*/
++static const char *locktypeName(int locktype){
++  switch( locktype ){
++  case NO_LOCK: return "NONE";
++  case SHARED_LOCK: return "SHARED";
++  case RESERVED_LOCK: return "RESERVED";
++  case PENDING_LOCK: return "PENDING";
++  case EXCLUSIVE_LOCK: return "EXCLUSIVE";
++  }
++  return "ERROR";
++}
++#endif
++
++/*
++** If we are currently in a different thread than the thread that the
++** unixFile argument belongs to, then transfer ownership of the unixFile
++** over to the current thread.
++**
++** A unixFile is only owned by a thread on systems where one thread is
++** unable to override locks created by a different thread.  RedHat9 is
++** an example of such a system.
++**
++** Ownership transfer is only allowed if the unixFile is currently unlocked.
++** If the unixFile is locked and an ownership is wrong, then return
++** SQLITE_MISUSE.  SQLITE_OK is returned if everything works.
++*/
++#ifdef SQLITE_UNIX_THREADS
++static int transferOwnership(unixFile *pFile){
++  int rc;
++  pthread_t hSelf;
++  if( threadsOverrideEachOthersLocks ){
++    /* Ownership transfers not needed on this system */
++    return SQLITE_OK;
++  }
++  hSelf = pthread_self();
++  if( pthread_equal(pFile->tid, hSelf) ){
++    /* We are still in the same thread */
++    TRACE1("No-transfer, same thread\n");
++    return SQLITE_OK;
++  }
++  if( pFile->locktype!=NO_LOCK ){
++    /* We cannot change ownership while we are holding a lock! */
++    return SQLITE_MISUSE;
++  }
++  TRACE4("Transfer ownership of %d from %d to %d\n", pFile->h,pFile->tid,hSelf);
++  pFile->tid = hSelf;
++  releaseLockInfo(pFile->pLock);
++  rc = findLockInfo(pFile->h, &pFile->pLock, 0);
++  TRACE5("LOCK    %d is now %s(%s,%d)\n", pFile->h,
++     locktypeName(pFile->locktype),
++     locktypeName(pFile->pLock->locktype), pFile->pLock->cnt);
++  return rc;
++}
++#else
++  /* On single-threaded builds, ownership transfer is a no-op */
++# define transferOwnership(X) SQLITE_OK
++#endif
++
++/*
+ ** Delete the named file
+ */
+-int sqlite3OsDelete(const char *zFilename){
++int sqlite3UnixDelete(const char *zFilename){
+   unlink(zFilename);
+   return SQLITE_OK;
+ }
+@@ -489,10 +672,13 @@
+ /*
+ ** Return TRUE if the named file exists.
+ */
+-int sqlite3OsFileExists(const char *zFilename){
++int sqlite3UnixFileExists(const char *zFilename){
+   return access(zFilename, 0)==0;
+ }
+ 
++/* Forward declaration */
++static int allocateUnixFile(unixFile *pInit, OsFile **pId);
++
+ /*
+ ** Attempt to open a file for both reading and writing.  If that
+ ** fails, try opening it read-only.  If the file does not exist,
+@@ -506,25 +692,26 @@
+ ** On failure, the function returns SQLITE_CANTOPEN and leaves
+ ** *id and *pReadonly unchanged.
+ */
+-int sqlite3OsOpenReadWrite(
++int sqlite3UnixOpenReadWrite(
+   const char *zFilename,
+-  OsFile *id,
++  OsFile **pId,
+   int *pReadonly
+ ){
+   int rc;
+-  assert( !id->isOpen );
+-  id->dirfd = -1;
+-  SET_THREADID(id);
+-  id->h = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY,
++  unixFile f;
++
++  CRASH_TEST_OVERRIDE(sqlite3CrashOpenReadWrite, zFilename, pId, pReadonly);
++  assert( 0==*pId );
++  f.h = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY,
+                           SQLITE_DEFAULT_FILE_PERMISSIONS);
+-  if( id->h<0 ){
++  if( f.h<0 ){
+ #ifdef EISDIR
+     if( errno==EISDIR ){
+       return SQLITE_CANTOPEN;
+     }
+ #endif
+-    id->h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);
+-    if( id->h<0 ){
++    f.h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);
++    if( f.h<0 ){
+       return SQLITE_CANTOPEN; 
+     }
+     *pReadonly = 1;
+@@ -532,17 +719,14 @@
+     *pReadonly = 0;
+   }
+   sqlite3OsEnterMutex();
+-  rc = findLockInfo(id->h, &id->pLock, &id->pOpen);
++  rc = findLockInfo(f.h, &f.pLock, &f.pOpen);
+   sqlite3OsLeaveMutex();
+   if( rc ){
+-    close(id->h);
++    close(f.h);
+     return SQLITE_NOMEM;
+   }
+-  id->locktype = 0;
+-  id->isOpen = 1;
+-  TRACE3("OPEN    %-3d %s\n", id->h, zFilename);
+-  OpenCounter(+1);
+-  return SQLITE_OK;
++  TRACE3("OPEN    %-3d %s\n", f.h, zFilename);
++  return allocateUnixFile(&f, pId);
+ }
+ 
+ 
+@@ -560,36 +744,34 @@
+ **
+ ** On failure, return SQLITE_CANTOPEN.
+ */
+-int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
++int sqlite3UnixOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
+   int rc;
+-  assert( !id->isOpen );
++  unixFile f;
++
++  CRASH_TEST_OVERRIDE(sqlite3CrashOpenExclusive, zFilename, pId, delFlag);
++  assert( 0==*pId );
+   if( access(zFilename, 0)==0 ){
+     return SQLITE_CANTOPEN;
+   }
+-  SET_THREADID(id);
+-  id->dirfd = -1;
+-  id->h = open(zFilename,
++  f.h = open(zFilename,
+                 O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_LARGEFILE|O_BINARY,
+                 SQLITE_DEFAULT_FILE_PERMISSIONS);
+-  if( id->h<0 ){
++  if( f.h<0 ){
+     return SQLITE_CANTOPEN;
+   }
+   sqlite3OsEnterMutex();
+-  rc = findLockInfo(id->h, &id->pLock, &id->pOpen);
++  rc = findLockInfo(f.h, &f.pLock, &f.pOpen);
+   sqlite3OsLeaveMutex();
+   if( rc ){
+-    close(id->h);
++    close(f.h);
+     unlink(zFilename);
+     return SQLITE_NOMEM;
+   }
+-  id->locktype = 0;
+-  id->isOpen = 1;
+   if( delFlag ){
+     unlink(zFilename);
+   }
+-  TRACE3("OPEN-EX %-3d %s\n", id->h, zFilename);
+-  OpenCounter(+1);
+-  return SQLITE_OK;
++  TRACE3("OPEN-EX %-3d %s\n", f.h, zFilename);
++  return allocateUnixFile(&f, pId);
+ }
+ 
+ /*
+@@ -599,27 +781,25 @@
+ **
+ ** On failure, return SQLITE_CANTOPEN.
+ */
+-int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
++int sqlite3UnixOpenReadOnly(const char *zFilename, OsFile **pId){
+   int rc;
+-  assert( !id->isOpen );
+-  SET_THREADID(id);
+-  id->dirfd = -1;
+-  id->h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);
+-  if( id->h<0 ){
++  unixFile f;
++
++  CRASH_TEST_OVERRIDE(sqlite3CrashOpenReadOnly, zFilename, pId, 0);
++  assert( 0==*pId );
++  f.h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);
++  if( f.h<0 ){
+     return SQLITE_CANTOPEN;
+   }
+   sqlite3OsEnterMutex();
+-  rc = findLockInfo(id->h, &id->pLock, &id->pOpen);
++  rc = findLockInfo(f.h, &f.pLock, &f.pOpen);
+   sqlite3OsLeaveMutex();
+   if( rc ){
+-    close(id->h);
++    close(f.h);
+     return SQLITE_NOMEM;
+   }
+-  id->locktype = 0;
+-  id->isOpen = 1;
+-  TRACE3("OPEN-RO %-3d %s\n", id->h, zFilename);
+-  OpenCounter(+1);
+-  return SQLITE_OK;
++  TRACE3("OPEN-RO %-3d %s\n", f.h, zFilename);
++  return allocateUnixFile(&f, pId);
+ }
+ 
+ /*
+@@ -631,29 +811,30 @@
+ ** This routine is only meaningful for Unix.  It is a no-op under
+ ** windows since windows does not support hard links.
+ **
+-** On success, a handle for a previously open file is at *id is
++** On success, a handle for a previously open file at *id is
+ ** updated with the new directory file descriptor and SQLITE_OK is
+ ** returned.
+ **
+ ** On failure, the function returns SQLITE_CANTOPEN and leaves
+ ** *id unchanged.
+ */
+-int sqlite3OsOpenDirectory(
+-  const char *zDirname,
+-  OsFile *id
++static int unixOpenDirectory(
++  OsFile *id,
++  const char *zDirname
+ ){
+-  if( !id->isOpen ){
++  unixFile *pFile = (unixFile*)id;
++  if( pFile==0 ){
+     /* Do not open the directory if the corresponding file is not already
+     ** open. */
+     return SQLITE_CANTOPEN;
+   }
+-  SET_THREADID(id);
+-  assert( id->dirfd<0 );
+-  id->dirfd = open(zDirname, O_RDONLY|O_BINARY, 0);
+-  if( id->dirfd<0 ){
++  SET_THREADID(pFile);
++  assert( pFile->dirfd<0 );
++  pFile->dirfd = open(zDirname, O_RDONLY|O_BINARY, 0);
++  if( pFile->dirfd<0 ){
+     return SQLITE_CANTOPEN; 
+   }
+-  TRACE3("OPENDIR %-3d %s\n", id->dirfd, zDirname);
++  TRACE3("OPENDIR %-3d %s\n", pFile->dirfd, zDirname);
+   return SQLITE_OK;
+ }
+ 
+@@ -661,6 +842,8 @@
+ ** If the following global variable points to a string which is the
+ ** name of a directory, then that directory will be used to store
+ ** temporary files.
++**
++** See also the "PRAGMA temp_store_directory" SQL command.
+ */
+ char *sqlite3_temp_directory = 0;
+ 
+@@ -668,7 +851,7 @@
+ ** Create a temporary file name in zBuf.  zBuf must be big enough to
+ ** hold at least SQLITE_TEMPNAME_SIZE characters.
+ */
+-int sqlite3OsTempFileName(char *zBuf){
++int sqlite3UnixTempFileName(char *zBuf){
+   static const char *azDirs[] = {
+      0,
+      "/var/tmp",
+@@ -704,35 +887,36 @@
+   return SQLITE_OK; 
+ }
+ 
+-#ifndef SQLITE_OMIT_PAGER_PRAGMAS
+ /*
+ ** Check that a given pathname is a directory and is writable 
+ **
+ */
+-int sqlite3OsIsDirWritable(char *zBuf){
++int sqlite3UnixIsDirWritable(char *zBuf){
++#ifndef SQLITE_OMIT_PAGER_PRAGMAS
+   struct stat buf;
+   if( zBuf==0 ) return 0;
+   if( zBuf[0]==0 ) return 0;
+   if( stat(zBuf, &buf) ) return 0;
+   if( !S_ISDIR(buf.st_mode) ) return 0;
+   if( access(zBuf, 07) ) return 0;
++#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
+   return 1;
+ }
+-#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
+ 
+ /*
+ ** Read data from a file into a buffer.  Return SQLITE_OK if all
+ ** bytes were read successfully and SQLITE_IOERR if anything goes
+ ** wrong.
+ */
+-int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
++static int unixRead(OsFile *id, void *pBuf, int amt){
+   int got;
+-  assert( id->isOpen );
++  assert( id );
+   SimulateIOError(SQLITE_IOERR);
+   TIMER_START;
+-  got = read(id->h, pBuf, amt);
++  got = read(((unixFile*)id)->h, pBuf, amt);
+   TIMER_END;
+-  TRACE5("READ    %-3d %5d %7d %d\n", id->h, got, last_page, TIMER_ELAPSED);
++  TRACE5("READ    %-3d %5d %7d %d\n", ((unixFile*)id)->h, got,
++          last_page, TIMER_ELAPSED);
+   SEEK(0);
+   /* if( got<0 ) got = 0; */
+   if( got==amt ){
+@@ -746,19 +930,20 @@
+ ** Write data from a buffer into a file.  Return SQLITE_OK on success
+ ** or some other error code on failure.
+ */
+-int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
++static int unixWrite(OsFile *id, const void *pBuf, int amt){
+   int wrote = 0;
+-  assert( id->isOpen );
++  assert( id );
+   assert( amt>0 );
+   SimulateIOError(SQLITE_IOERR);
+   SimulateDiskfullError;
+   TIMER_START;
+-  while( amt>0 && (wrote = write(id->h, pBuf, amt))>0 ){
++  while( amt>0 && (wrote = write(((unixFile*)id)->h, pBuf, amt))>0 ){
+     amt -= wrote;
+     pBuf = &((char*)pBuf)[wrote];
+   }
+   TIMER_END;
+-  TRACE5("WRITE   %-3d %5d %7d %d\n", id->h, wrote, last_page, TIMER_ELAPSED);
++  TRACE5("WRITE   %-3d %5d %7d %d\n", ((unixFile*)id)->h, wrote,
++          last_page, TIMER_ELAPSED);
+   SEEK(0);
+   if( amt>0 ){
+     return SQLITE_FULL;
+@@ -769,13 +954,13 @@
+ /*
+ ** Move the read/write pointer in a file.
+ */
+-int sqlite3OsSeek(OsFile *id, i64 offset){
+-  assert( id->isOpen );
++static int unixSeek(OsFile *id, i64 offset){
++  assert( id );
+   SEEK(offset/1024 + 1);
+ #ifdef SQLITE_TEST
+   if( offset ) SimulateDiskfullError
+ #endif
+-  lseek(id->h, offset, SEEK_SET);
++  lseek(((unixFile*)id)->h, offset, SEEK_SET);
+   return SQLITE_OK;
+ }
+ 
+@@ -788,8 +973,27 @@
+ int sqlite3_fullsync_count = 0;
+ #endif
+ 
++/*
++** Use the fdatasync() API only if the HAVE_FDATASYNC macro is defined.
++** Otherwise use fsync() in its place.
++*/
++#ifndef HAVE_FDATASYNC
++# define fdatasync fsync
++#endif
+ 
+ /*
++** Define HAVE_FULLFSYNC to 0 or 1 depending on whether or not
++** the F_FULLFSYNC macro is defined.  F_FULLFSYNC is currently
++** only available on Mac OS X.  But that could change.
++*/
++#ifdef F_FULLFSYNC
++# define HAVE_FULLFSYNC 1
++#else
++# define HAVE_FULLFSYNC 0
++#endif
++
++
++/*
+ ** The fsync() system call does not work as advertised on many
+ ** unix systems.  The following procedure is an attempt to make
+ ** it work better.
+@@ -819,7 +1023,7 @@
+   rc = SQLITE_OK;
+ #else
+ 
+-#ifdef F_FULLFSYNC
++#if HAVE_FULLFSYNC
+   if( fullSync ){
+     rc = fcntl(fd, F_FULLFSYNC, 0);
+   }else{
+@@ -829,12 +1033,9 @@
+   if( rc ) rc = fsync(fd);
+ 
+ #else /* if !defined(F_FULLSYNC) */
+-#if  defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO>0
+   if( dataOnly ){
+     rc = fdatasync(fd);
+-  }else
+-#endif /* _POSIX_SYNCHRONIZED_IO > 0 */
+-  {
++  }else{
+     rc = fsync(fd);
+   }
+ #endif /* defined(F_FULLFSYNC) */
+@@ -858,18 +1059,34 @@
+ ** the directory entry for the journal was never created) and the transaction
+ ** will not roll back - possibly leading to database corruption.
+ */
+-int sqlite3OsSync(OsFile *id, int dataOnly){
+-  assert( id->isOpen );
++static int unixSync(OsFile *id, int dataOnly){
++  unixFile *pFile = (unixFile*)id;
++  assert( pFile );
+   SimulateIOError(SQLITE_IOERR);
+-  TRACE2("SYNC    %-3d\n", id->h);
+-  if( full_fsync(id->h, id->fullSync, dataOnly) ){
++  TRACE2("SYNC    %-3d\n", pFile->h);
++  if( full_fsync(pFile->h, pFile->fullSync, dataOnly) ){
+     return SQLITE_IOERR;
+   }
+-  if( id->dirfd>=0 ){
+-    TRACE2("DIRSYNC %-3d\n", id->dirfd);
+-    full_fsync(id->dirfd, id->fullSync, 0);
+-    close(id->dirfd);  /* Only need to sync once, so close the directory */
+-    id->dirfd = -1;    /* when we are done. */
++  if( pFile->dirfd>=0 ){
++    TRACE4("DIRSYNC %-3d (have_fullfsync=%d fullsync=%d)\n", pFile->dirfd,
++            HAVE_FULLFSYNC, pFile->fullSync);
++#ifndef SQLITE_DISABLE_DIRSYNC
++    /* The directory sync is only attempted if full_fsync is
++    ** turned off or unavailable.  If a full_fsync occurred above,
++    ** then the directory sync is superfluous.
++    */
++    if( (!HAVE_FULLFSYNC || !pFile->fullSync) && full_fsync(pFile->dirfd,0,0) ){
++       /*
++       ** We have received multiple reports of fsync() returning
++       ** errors when applied to directories on certain file systems.
++       ** A failed directory sync is not a big deal.  So it seems
++       ** better to ignore the error.  Ticket #1657
++       */
++       /* return SQLITE_IOERR; */
++    }
++#endif
++    close(pFile->dirfd);  /* Only need to sync once, so close the directory */
++    pFile->dirfd = -1;    /* when we are done. */
+   }
+   return SQLITE_OK;
+ }
+@@ -882,7 +1099,10 @@
+ ** before making changes to individual journals on a multi-database commit.
+ ** The F_FULLFSYNC option is not needed here.
+ */
+-int sqlite3OsSyncDirectory(const char *zDirname){
++int sqlite3UnixSyncDirectory(const char *zDirname){
++#ifdef SQLITE_DISABLE_DIRSYNC
++  return SQLITE_OK;
++#else
+   int fd;
+   int r;
+   SimulateIOError(SQLITE_IOERR);
+@@ -894,25 +1114,26 @@
+   r = fsync(fd);
+   close(fd);
+   return ((r==0)?SQLITE_OK:SQLITE_IOERR);
++#endif
+ }
+ 
+ /*
+ ** Truncate an open file to a specified size
+ */
+-int sqlite3OsTruncate(OsFile *id, i64 nByte){
+-  assert( id->isOpen );
++static int unixTruncate(OsFile *id, i64 nByte){
++  assert( id );
+   SimulateIOError(SQLITE_IOERR);
+-  return ftruncate(id->h, nByte)==0 ? SQLITE_OK : SQLITE_IOERR;
++  return ftruncate(((unixFile*)id)->h, nByte)==0 ? SQLITE_OK : SQLITE_IOERR;
+ }
+ 
+ /*
+ ** Determine the current size of a file in bytes
+ */
+-int sqlite3OsFileSize(OsFile *id, i64 *pSize){
++static int unixFileSize(OsFile *id, i64 *pSize){
+   struct stat buf;
+-  assert( id->isOpen );
++  assert( id );
+   SimulateIOError(SQLITE_IOERR);
+-  if( fstat(id->h, &buf)!=0 ){
++  if( fstat(((unixFile*)id)->h, &buf)!=0 ){
+     return SQLITE_IOERR;
+   }
+   *pSize = buf.st_size;
+@@ -925,15 +1146,15 @@
+ ** non-zero.  If the file is unlocked or holds only SHARED locks, then
+ ** return zero.
+ */
+-int sqlite3OsCheckReservedLock(OsFile *id){
++static int unixCheckReservedLock(OsFile *id){
+   int r = 0;
++  unixFile *pFile = (unixFile*)id;
+ 
+-  assert( id->isOpen );
+-  if( CHECK_THREADID(id) ) return SQLITE_MISUSE;
+-  sqlite3OsEnterMutex(); /* Needed because id->pLock is shared across threads */
++  assert( pFile );
++  sqlite3OsEnterMutex(); /* Because pFile->pLock is shared across threads */
+ 
+   /* Check if a thread in this process holds such a lock */
+-  if( id->pLock->locktype>SHARED_LOCK ){
++  if( pFile->pLock->locktype>SHARED_LOCK ){
+     r = 1;
+   }
+ 
+@@ -945,37 +1166,19 @@
+     lock.l_start = RESERVED_BYTE;
+     lock.l_len = 1;
+     lock.l_type = F_WRLCK;
+-    fcntl(id->h, F_GETLK, &lock);
++    fcntl(pFile->h, F_GETLK, &lock);
+     if( lock.l_type!=F_UNLCK ){
+       r = 1;
+     }
+   }
+   
+   sqlite3OsLeaveMutex();
+-  TRACE3("TEST WR-LOCK %d %d\n", id->h, r);
++  TRACE3("TEST WR-LOCK %d %d\n", pFile->h, r);
+ 
+   return r;
+ }
+ 
+-#ifdef SQLITE_DEBUG
+ /*
+-** Helper function for printing out trace information from debugging
+-** binaries. This returns the string represetation of the supplied
+-** integer lock-type.
+-*/
+-static const char * locktypeName(int locktype){
+-  switch( locktype ){
+-  case NO_LOCK: return "NONE";
+-  case SHARED_LOCK: return "SHARED";
+-  case RESERVED_LOCK: return "RESERVED";
+-  case PENDING_LOCK: return "PENDING";
+-  case EXCLUSIVE_LOCK: return "EXCLUSIVE";
+-  }
+-  return "ERROR";
+-}
+-#endif
+-
+-/*
+ ** Lock the file with the lock specified by parameter locktype - one
+ ** of the following:
+ **
+@@ -999,7 +1202,7 @@
+ ** This routine will only increase a lock.  Use the sqlite3OsUnlock()
+ ** routine to lower a locking level.
+ */
+-int sqlite3OsLock(OsFile *id, int locktype){
++static int unixLock(OsFile *id, int locktype){
+   /* The following describes the implementation of the various locks and
+   ** lock transitions in terms of the POSIX advisory shared and exclusive
+   ** lock primitives (called read-locks and write-locks below, to avoid
+@@ -1039,39 +1242,49 @@
+   ** even if the locking primitive used is always a write-lock.
+   */
+   int rc = SQLITE_OK;
+-  struct lockInfo *pLock = id->pLock;
++  unixFile *pFile = (unixFile*)id;
++  struct lockInfo *pLock = pFile->pLock;
+   struct flock lock;
+   int s;
+ 
+-  assert( id->isOpen );
+-  TRACE7("LOCK    %d %s was %s(%s,%d) pid=%d\n", id->h, locktypeName(locktype), 
+-      locktypeName(id->locktype), locktypeName(pLock->locktype), pLock->cnt
+-      ,getpid() );
+-  if( CHECK_THREADID(id) ) return SQLITE_MISUSE;
++  assert( pFile );
++  TRACE7("LOCK    %d %s was %s(%s,%d) pid=%d\n", pFile->h,
++      locktypeName(locktype), locktypeName(pFile->locktype),
++      locktypeName(pLock->locktype), pLock->cnt , getpid());
+ 
+   /* If there is already a lock of this type or more restrictive on the
+   ** OsFile, do nothing. Don't use the end_lock: exit path, as
+   ** sqlite3OsEnterMutex() hasn't been called yet.
+   */
+-  if( id->locktype>=locktype ){
+-    TRACE3("LOCK    %d %s ok (already held)\n", id->h, locktypeName(locktype));
++  if( pFile->locktype>=locktype ){
++    TRACE3("LOCK    %d %s ok (already held)\n", pFile->h,
++            locktypeName(locktype));
+     return SQLITE_OK;
+   }
+ 
+   /* Make sure the locking sequence is correct
+   */
+-  assert( id->locktype!=NO_LOCK || locktype==SHARED_LOCK );
++  assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK );
+   assert( locktype!=PENDING_LOCK );
+-  assert( locktype!=RESERVED_LOCK || id->locktype==SHARED_LOCK );
++  assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK );
+ 
+-  /* This mutex is needed because id->pLock is shared across threads
++  /* This mutex is needed because pFile->pLock is shared across threads
+   */
+   sqlite3OsEnterMutex();
+ 
++  /* Make sure the current thread owns the pFile.
++  */
++  rc = transferOwnership(pFile);
++  if( rc!=SQLITE_OK ){
++    sqlite3OsLeaveMutex();
++    return rc;
++  }
++  pLock = pFile->pLock;
++
+   /* If some thread using this PID has a lock via a different OsFile*
+   ** handle that precludes the requested lock, return BUSY.
+   */
+-  if( (id->locktype!=pLock->locktype && 
++  if( (pFile->locktype!=pLock->locktype && 
+           (pLock->locktype>=PENDING_LOCK || locktype>SHARED_LOCK))
+   ){
+     rc = SQLITE_BUSY;
+@@ -1085,11 +1298,11 @@
+   if( locktype==SHARED_LOCK && 
+       (pLock->locktype==SHARED_LOCK || pLock->locktype==RESERVED_LOCK) ){
+     assert( locktype==SHARED_LOCK );
+-    assert( id->locktype==0 );
++    assert( pFile->locktype==0 );
+     assert( pLock->cnt>0 );
+-    id->locktype = SHARED_LOCK;
++    pFile->locktype = SHARED_LOCK;
+     pLock->cnt++;
+-    id->pOpen->nLock++;
++    pFile->pOpen->nLock++;
+     goto end_lock;
+   }
+ 
+@@ -1102,11 +1315,11 @@
+   ** be released.
+   */
+   if( locktype==SHARED_LOCK 
+-      || (locktype==EXCLUSIVE_LOCK && id->locktype<PENDING_LOCK)
++      || (locktype==EXCLUSIVE_LOCK && pFile->locktype<PENDING_LOCK)
+   ){
+     lock.l_type = (locktype==SHARED_LOCK?F_RDLCK:F_WRLCK);
+     lock.l_start = PENDING_BYTE;
+-    s = fcntl(id->h, F_SETLK, &lock);
++    s = fcntl(pFile->h, F_SETLK, &lock);
+     if( s ){
+       rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
+       goto end_lock;
+@@ -1124,21 +1337,21 @@
+     /* Now get the read-lock */
+     lock.l_start = SHARED_FIRST;
+     lock.l_len = SHARED_SIZE;
+-    s = fcntl(id->h, F_SETLK, &lock);
++    s = fcntl(pFile->h, F_SETLK, &lock);
+ 
+     /* Drop the temporary PENDING lock */
+     lock.l_start = PENDING_BYTE;
+     lock.l_len = 1L;
+     lock.l_type = F_UNLCK;
+-    if( fcntl(id->h, F_SETLK, &lock)!=0 ){
++    if( fcntl(pFile->h, F_SETLK, &lock)!=0 ){
+       rc = SQLITE_IOERR;  /* This should never happen */
+       goto end_lock;
+     }
+     if( s ){
+       rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
+     }else{
+-      id->locktype = SHARED_LOCK;
+-      id->pOpen->nLock++;
++      pFile->locktype = SHARED_LOCK;
++      pFile->pOpen->nLock++;
+       pLock->cnt = 1;
+     }
+   }else if( locktype==EXCLUSIVE_LOCK && pLock->cnt>1 ){
+@@ -1150,7 +1363,7 @@
+     ** assumed that there is a SHARED or greater lock on the file
+     ** already.
+     */
+-    assert( 0!=id->locktype );
++    assert( 0!=pFile->locktype );
+     lock.l_type = F_WRLCK;
+     switch( locktype ){
+       case RESERVED_LOCK:
+@@ -1163,63 +1376,62 @@
+       default:
+         assert(0);
+     }
+-    s = fcntl(id->h, F_SETLK, &lock);
++    s = fcntl(pFile->h, F_SETLK, &lock);
+     if( s ){
+       rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
+     }
+   }
+   
+   if( rc==SQLITE_OK ){
+-    id->locktype = locktype;
++    pFile->locktype = locktype;
+     pLock->locktype = locktype;
+   }else if( locktype==EXCLUSIVE_LOCK ){
+-    id->locktype = PENDING_LOCK;
++    pFile->locktype = PENDING_LOCK;
+     pLock->locktype = PENDING_LOCK;
+   }
+ 
+ end_lock:
+   sqlite3OsLeaveMutex();
+-  TRACE4("LOCK    %d %s %s\n", id->h, locktypeName(locktype), 
++  TRACE4("LOCK    %d %s %s\n", pFile->h, locktypeName(locktype), 
+       rc==SQLITE_OK ? "ok" : "failed");
+   return rc;
+ }
+ 
+ /*
+-** Lower the locking level on file descriptor id to locktype.  locktype
++** Lower the locking level on file descriptor pFile to locktype.  locktype
+ ** must be either NO_LOCK or SHARED_LOCK.
+ **
+ ** If the locking level of the file descriptor is already at or below
+ ** the requested locking level, this routine is a no-op.
+-**
+-** It is not possible for this routine to fail if the second argument
+-** is NO_LOCK.  If the second argument is SHARED_LOCK, this routine
+-** might return SQLITE_IOERR instead of SQLITE_OK.
+ */
+-int sqlite3OsUnlock(OsFile *id, int locktype){
++static int unixUnlock(OsFile *id, int locktype){
+   struct lockInfo *pLock;
+   struct flock lock;
+   int rc = SQLITE_OK;
++  unixFile *pFile = (unixFile*)id;
+ 
+-  assert( id->isOpen );
+-  TRACE7("UNLOCK  %d %d was %d(%d,%d) pid=%d\n", id->h, locktype, id->locktype, 
+-      id->pLock->locktype, id->pLock->cnt, getpid());
+-  if( CHECK_THREADID(id) ) return SQLITE_MISUSE;
++  assert( pFile );
++  TRACE7("UNLOCK  %d %d was %d(%d,%d) pid=%d\n", pFile->h, locktype,
++      pFile->locktype, pFile->pLock->locktype, pFile->pLock->cnt, getpid());
+ 
+   assert( locktype<=SHARED_LOCK );
+-  if( id->locktype<=locktype ){
++  if( pFile->locktype<=locktype ){
+     return SQLITE_OK;
+   }
++  if( CHECK_THREADID(pFile) ){
++    return SQLITE_MISUSE;
++  }
+   sqlite3OsEnterMutex();
+-  pLock = id->pLock;
++  pLock = pFile->pLock;
+   assert( pLock->cnt!=0 );
+-  if( id->locktype>SHARED_LOCK ){
+-    assert( pLock->locktype==id->locktype );
++  if( pFile->locktype>SHARED_LOCK ){
++    assert( pLock->locktype==pFile->locktype );
+     if( locktype==SHARED_LOCK ){
+       lock.l_type = F_RDLCK;
+       lock.l_whence = SEEK_SET;
+       lock.l_start = SHARED_FIRST;
+       lock.l_len = SHARED_SIZE;
+-      if( fcntl(id->h, F_SETLK, &lock)!=0 ){
++      if( fcntl(pFile->h, F_SETLK, &lock)!=0 ){
+         /* This should never happen */
+         rc = SQLITE_IOERR;
+       }
+@@ -1228,7 +1440,7 @@
+     lock.l_whence = SEEK_SET;
+     lock.l_start = PENDING_BYTE;
+     lock.l_len = 2L;  assert( PENDING_BYTE+1==RESERVED_BYTE );
+-    if( fcntl(id->h, F_SETLK, &lock)==0 ){
++    if( fcntl(pFile->h, F_SETLK, &lock)==0 ){
+       pLock->locktype = SHARED_LOCK;
+     }else{
+       rc = SQLITE_IOERR;  /* This should never happen */
+@@ -1246,7 +1458,7 @@
+       lock.l_type = F_UNLCK;
+       lock.l_whence = SEEK_SET;
+       lock.l_start = lock.l_len = 0L;
+-      if( fcntl(id->h, F_SETLK, &lock)==0 ){
++      if( fcntl(pFile->h, F_SETLK, &lock)==0 ){
+         pLock->locktype = NO_LOCK;
+       }else{
+         rc = SQLITE_IOERR;  /* This should never happen */
+@@ -1257,7 +1469,7 @@
+     ** count reaches zero, close any other file descriptors whose close
+     ** was deferred because of outstanding locks.
+     */
+-    pOpen = id->pOpen;
++    pOpen = pFile->pOpen;
+     pOpen->nLock--;
+     assert( pOpen->nLock>=0 );
+     if( pOpen->nLock==0 && pOpen->nPending>0 ){
+@@ -1265,26 +1477,28 @@
+       for(i=0; i<pOpen->nPending; i++){
+         close(pOpen->aPending[i]);
+       }
+-      sqliteFree(pOpen->aPending);
++      free(pOpen->aPending);
+       pOpen->nPending = 0;
+       pOpen->aPending = 0;
+     }
+   }
+   sqlite3OsLeaveMutex();
+-  id->locktype = locktype;
++  pFile->locktype = locktype;
+   return rc;
+ }
+ 
+ /*
+ ** Close a file.
+ */
+-int sqlite3OsClose(OsFile *id){
+-  if( !id->isOpen ) return SQLITE_OK;
+-  if( CHECK_THREADID(id) ) return SQLITE_MISUSE;
+-  sqlite3OsUnlock(id, NO_LOCK);
++static int unixClose(OsFile **pId){
++  unixFile *id = (unixFile*)*pId;
++
++  if( !id ) return SQLITE_OK;
++  unixUnlock(*pId, NO_LOCK);
+   if( id->dirfd>=0 ) close(id->dirfd);
+   id->dirfd = -1;
+   sqlite3OsEnterMutex();
++
+   if( id->pOpen->nLock ){
+     /* If there are outstanding locks, do not actually close the file just
+     ** yet because that would clear those locks.  Instead, add the file
+@@ -1293,7 +1507,7 @@
+     */
+     int *aNew;
+     struct openCnt *pOpen = id->pOpen;
+-    aNew = sqliteRealloc( pOpen->aPending, (pOpen->nPending+1)*sizeof(int) );
++    aNew = realloc( pOpen->aPending, (pOpen->nPending+1)*sizeof(int) );
+     if( aNew==0 ){
+       /* If a malloc fails, just leak the file descriptor */
+     }else{
+@@ -1307,10 +1521,13 @@
+   }
+   releaseLockInfo(id->pLock);
+   releaseOpenCnt(id->pOpen);
++
+   sqlite3OsLeaveMutex();
+   id->isOpen = 0;
+   TRACE2("CLOSE   %-3d\n", id->h);
+   OpenCounter(-1);
++  sqliteFree(id);
++  *pId = 0;
+   return SQLITE_OK;
+ }
+ 
+@@ -1320,7 +1537,7 @@
+ ** The calling function is responsible for freeing this space once it
+ ** is no longer needed.
+ */
+-char *sqlite3OsFullPathname(const char *zRelative){
++char *sqlite3UnixFullPathname(const char *zRelative){
+   char *zFull = 0;
+   if( zRelative[0]=='/' ){
+     sqlite3SetString(&zFull, zRelative, (char*)0);
+@@ -1337,7 +1554,79 @@
+   return zFull;
+ }
+ 
++/*
++** Change the value of the fullsync flag in the given file descriptor.
++*/
++static void unixSetFullSync(OsFile *id, int v){
++  ((unixFile*)id)->fullSync = v;
++}
+ 
++/*
++** Return the underlying file handle for an OsFile
++*/
++static int unixFileHandle(OsFile *id){
++  return ((unixFile*)id)->h;
++}
++
++/*
++** Return an integer that indices the type of lock currently held
++** by this handle.  (Used for testing and analysis only.)
++*/
++static int unixLockState(OsFile *id){
++  return ((unixFile*)id)->locktype;
++}
++
++/*
++** This vector defines all the methods that can operate on an OsFile
++** for unix.
++*/
++static const IoMethod sqlite3UnixIoMethod = {
++  unixClose,
++  unixOpenDirectory,
++  unixRead,
++  unixWrite,
++  unixSeek,
++  unixTruncate,
++  unixSync,
++  unixSetFullSync,
++  unixFileHandle,
++  unixFileSize,
++  unixLock,
++  unixUnlock,
++  unixLockState,
++  unixCheckReservedLock,
++};
++
++/*
++** Allocate memory for a unixFile.  Initialize the new unixFile
++** to the value given in pInit and return a pointer to the new
++** OsFile.  If we run out of memory, close the file and return NULL.
++*/
++static int allocateUnixFile(unixFile *pInit, OsFile **pId){
++  unixFile *pNew;
++  pInit->dirfd = -1;
++  pInit->fullSync = 0;
++  pInit->locktype = 0;
++  SET_THREADID(pInit);
++  pNew = sqliteMalloc( sizeof(unixFile) );
++  if( pNew==0 ){
++    close(pInit->h);
++    sqlite3OsEnterMutex();
++    releaseLockInfo(pInit->pLock);
++    releaseOpenCnt(pInit->pOpen);
++    sqlite3OsLeaveMutex();
++    *pId = 0;
++    return SQLITE_NOMEM;
++  }else{
++    *pNew = *pInit;
++    pNew->pMethod = &sqlite3UnixIoMethod;
++    *pId = (OsFile*)pNew;
++    OpenCounter(+1);
++    return SQLITE_OK;
++  }
++}
++
++
+ #endif /* SQLITE_OMIT_DISKIO */
+ /***************************************************************************
+ ** Everything above deals with file I/O.  Everything that follows deals
+@@ -1350,7 +1639,7 @@
+ ** is written into the buffer zBuf[256].  The calling function must
+ ** supply a sufficiently large buffer.
+ */
+-int sqlite3OsRandomSeed(char *zBuf){
++int sqlite3UnixRandomSeed(char *zBuf){
+   /* We have to initialize zBuf to prevent valgrind from reporting
+   ** errors.  The reports issued by valgrind are incorrect - we would
+   ** prefer that the randomness be increased by making use of the
+@@ -1360,7 +1649,7 @@
+   ** in the random seed.
+   **
+   ** When testing, initializing zBuf[] to zero is all we do.  That means
+-  ** that we always use the same random number sequence.* This makes the
++  ** that we always use the same random number sequence.  This makes the
+   ** tests repeatable.
+   */
+   memset(zBuf, 0, 256);
+@@ -1369,7 +1658,9 @@
+     int pid, fd;
+     fd = open("/dev/urandom", O_RDONLY);
+     if( fd<0 ){
+-      time((time_t*)zBuf);
++      time_t t;
++      time(&t);
++      memcpy(zBuf, &t, sizeof(t));
+       pid = getpid();
+       memcpy(&zBuf[sizeof(time_t)], &pid, sizeof(pid));
+     }else{
+@@ -1383,8 +1674,9 @@
+ 
+ /*
+ ** Sleep for a little while.  Return the amount of time slept.
++** The argument is the number of milliseconds we want to sleep.
+ */
+-int sqlite3OsSleep(int ms){
++int sqlite3UnixSleep(int ms){
+ #if defined(HAVE_USLEEP) && HAVE_USLEEP
+   usleep(ms*1000);
+   return ms;
+@@ -1395,11 +1687,42 @@
+ }
+ 
+ /*
+-** Static variables used for thread synchronization
++** Static variables used for thread synchronization.
++**
++** inMutex      the nesting depth of the recursive mutex.  The thread
++**              holding mutexMain can read this variable at any time.
++**              But is must hold mutexAux to change this variable.  Other
++**              threads must hold mutexAux to read the variable and can
++**              never write.
++**
++** mutexOwner   The thread id of the thread holding mutexMain.  Same
++**              access rules as for inMutex.
++**
++** mutexOwnerValid   True if the value in mutexOwner is valid.  The same
++**                   access rules apply as for inMutex.
++**
++** mutexMain    The main mutex.  Hold this mutex in order to get exclusive
++**              access to SQLite data structures.
++**
++** mutexAux     An auxiliary mutex needed to access variables defined above.
++**
++** Mutexes are always acquired in this order: mutexMain mutexAux.   It
++** is not necessary to acquire mutexMain in order to get mutexAux - just
++** do not attempt to acquire them in the reverse order: mutexAux mutexMain.
++** Either get the mutexes with mutexMain first or get mutexAux only.
++**
++** When running on a platform where the three variables inMutex, mutexOwner,
++** and mutexOwnerValid can be set atomically, the mutexAux is not required.
++** On many systems, all three are 32-bit integers and writing to a 32-bit
++** integer is atomic.  I think.  But there are no guarantees.  So it seems
++** safer to protect them using mutexAux.
+ */
+ static int inMutex = 0;
+ #ifdef SQLITE_UNIX_THREADS
+-static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
++static pthread_t mutexOwner;          /* Thread holding mutexMain */
++static int mutexOwnerValid = 0;       /* True if mutexOwner is valid */
++static pthread_mutex_t mutexMain = PTHREAD_MUTEX_INITIALIZER; /* The mutex */
++static pthread_mutex_t mutexAux = PTHREAD_MUTEX_INITIALIZER;  /* Aux mutex */
+ #endif
+ 
+ /*
+@@ -1409,23 +1732,168 @@
+ **
+ ** SQLite uses only a single Mutex.  There is not much critical
+ ** code and what little there is executes quickly and without blocking.
++**
++** As of version 3.3.2, this mutex must be recursive.
+ */
+-void sqlite3OsEnterMutex(){
++void sqlite3UnixEnterMutex(){
+ #ifdef SQLITE_UNIX_THREADS
+-  pthread_mutex_lock(&mutex);
++  pthread_mutex_lock(&mutexAux);
++  if( !mutexOwnerValid || !pthread_equal(mutexOwner, pthread_self()) ){
++    pthread_mutex_unlock(&mutexAux);
++    pthread_mutex_lock(&mutexMain);
++    assert( inMutex==0 );
++    assert( !mutexOwnerValid );
++    pthread_mutex_lock(&mutexAux);
++    mutexOwner = pthread_self();
++    mutexOwnerValid = 1;
++  }
++  inMutex++;
++  pthread_mutex_unlock(&mutexAux);
++#else
++  inMutex++;
+ #endif
+-  assert( !inMutex );
+-  inMutex = 1;
+ }
+-void sqlite3OsLeaveMutex(){
+-  assert( inMutex );
+-  inMutex = 0;
++void sqlite3UnixLeaveMutex(){
++  assert( inMutex>0 );
+ #ifdef SQLITE_UNIX_THREADS
+-  pthread_mutex_unlock(&mutex);
++  pthread_mutex_lock(&mutexAux);
++  inMutex--;
++  assert( pthread_equal(mutexOwner, pthread_self()) );
++  if( inMutex==0 ){
++    assert( mutexOwnerValid );
++    mutexOwnerValid = 0;
++    pthread_mutex_unlock(&mutexMain);
++  }
++  pthread_mutex_unlock(&mutexAux);
++#else
++  inMutex--;
+ #endif
+ }
+ 
+ /*
++** Return TRUE if the mutex is currently held.
++**
++** If the thisThrd parameter is true, return true only if the
++** calling thread holds the mutex.  If the parameter is false, return
++** true if any thread holds the mutex.
++*/
++int sqlite3UnixInMutex(int thisThrd){
++#ifdef SQLITE_UNIX_THREADS
++  int rc;
++  pthread_mutex_lock(&mutexAux);
++  rc = inMutex>0 && (thisThrd==0 || pthread_equal(mutexOwner,pthread_self()));
++  pthread_mutex_unlock(&mutexAux);
++  return rc;
++#else
++  return inMutex>0;
++#endif
++}
++
++/*
++** Remember the number of thread-specific-data blocks allocated.
++** Use this to verify that we are not leaking thread-specific-data.
++** Ticket #1601
++*/
++#ifdef SQLITE_TEST
++int sqlite3_tsd_count = 0;
++# ifdef SQLITE_UNIX_THREADS
++    static pthread_mutex_t tsd_counter_mutex = PTHREAD_MUTEX_INITIALIZER;
++#   define TSD_COUNTER(N) \
++             pthread_mutex_lock(&tsd_counter_mutex); \
++             sqlite3_tsd_count += N; \
++             pthread_mutex_unlock(&tsd_counter_mutex);
++# else
++#   define TSD_COUNTER(N)  sqlite3_tsd_count += N
++# endif
++#else
++# define TSD_COUNTER(N)  /* no-op */
++#endif
++
++/*
++** If called with allocateFlag>0, then return a pointer to thread
++** specific data for the current thread.  Allocate and zero the
++** thread-specific data if it does not already exist.
++**
++** If called with allocateFlag==0, then check the current thread
++** specific data.  Return it if it exists.  If it does not exist,
++** then return NULL.
++**
++** If called with allocateFlag<0, check to see if the thread specific
++** data is allocated and is all zero.  If it is then deallocate it.
++** Return a pointer to the thread specific data or NULL if it is
++** unallocated or gets deallocated.
++*/
++ThreadData *sqlite3UnixThreadSpecificData(int allocateFlag){
++  static const ThreadData zeroData = {0};  /* Initializer to silence warnings
++                                           ** from broken compilers */
++#ifdef SQLITE_UNIX_THREADS
++  static pthread_key_t key;
++  static int keyInit = 0;
++  ThreadData *pTsd;
++
++  if( !keyInit ){
++    sqlite3OsEnterMutex();
++    if( !keyInit ){
++      int rc;
++      rc = pthread_key_create(&key, 0);
++      if( rc ){
++        sqlite3OsLeaveMutex();
++        return 0;
++      }
++      keyInit = 1;
++    }
++    sqlite3OsLeaveMutex();
++  }
++
++  pTsd = pthread_getspecific(key);
++  if( allocateFlag>0 ){
++    if( pTsd==0 ){
++      if( !sqlite3TestMallocFail() ){
++        pTsd = sqlite3OsMalloc(sizeof(zeroData));
++      }
++#ifdef SQLITE_MEMDEBUG
++      sqlite3_isFail = 0;
++#endif
++      if( pTsd ){
++        *pTsd = zeroData;
++        pthread_setspecific(key, pTsd);
++        TSD_COUNTER(+1);
++      }
++    }
++  }else if( pTsd!=0 && allocateFlag<0 
++            && memcmp(pTsd, &zeroData, sizeof(ThreadData))==0 ){
++    sqlite3OsFree(pTsd);
++    pthread_setspecific(key, 0);
++    TSD_COUNTER(-1);
++    pTsd = 0;
++  }
++  return pTsd;
++#else
++  static ThreadData *pTsd = 0;
++  if( allocateFlag>0 ){
++    if( pTsd==0 ){
++      if( !sqlite3TestMallocFail() ){
++        pTsd = sqlite3OsMalloc( sizeof(zeroData) );
++      }
++#ifdef SQLITE_MEMDEBUG
++      sqlite3_isFail = 0;
++#endif
++      if( pTsd ){
++        *pTsd = zeroData;
++        TSD_COUNTER(+1);
++      }
++    }
++  }else if( pTsd!=0 && allocateFlag<0
++            && memcmp(pTsd, &zeroData, sizeof(ThreadData))==0 ){
++    sqlite3OsFree(pTsd);
++    TSD_COUNTER(-1);
++    pTsd = 0;
++  }
++  return pTsd;
++#endif
++}
++
++/*
+ ** The following variable, if set to a non-zero value, becomes the result
+ ** returned from sqlite3OsCurrentTime().  This is used for testing.
+ */
+@@ -1438,7 +1906,7 @@
+ ** current time and date as a Julian Day number into *prNow and
+ ** return 0.  Return 1 if the time and date cannot be found.
+ */
+-int sqlite3OsCurrentTime(double *prNow){
++int sqlite3UnixCurrentTime(double *prNow){
+ #ifdef NO_GETTOD
+   time_t t;
+   time(&t);
+Index: sqlite/main.c
+===================================================================
+--- amarok/src/sqlite/main.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/main.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -26,32 +26,9 @@
+ */
+ const int sqlite3one = 1;
+ 
+-#ifndef SQLITE_OMIT_GLOBALRECOVER
+ /*
+-** Linked list of all open database handles. This is used by the 
+-** sqlite3_global_recover() function. Entries are added to the list
+-** by openDatabase() and removed by sqlite3_close().
+-*/
+-static sqlite3 *pDbList = 0;
+-#endif
+-
+-#ifndef SQLITE_OMIT_UTF16
+-/* 
+-** Return the transient sqlite3_value object used for encoding conversions
+-** during SQL compilation.
+-*/
+-sqlite3_value *sqlite3GetTransientValue(sqlite3 *db){
+-  if( !db->pValue ){
+-    db->pValue = sqlite3ValueNew();
+-  }
+-  return db->pValue;
+-}
+-#endif
+-
+-/*
+ ** The version of the library
+ */
+-const char rcsid3[] = "@(#) \044Id: SQLite version " SQLITE_VERSION " $";
+ const char sqlite3_version[] = SQLITE_VERSION;
+ const char *sqlite3_libversion(void){ return sqlite3_version; }
+ int sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; }
+@@ -158,6 +135,9 @@
+     if( pDb->pBt ){
+       sqlite3BtreeClose(pDb->pBt);
+       pDb->pBt = 0;
++      if( j!=1 ){
++        pDb->pSchema = 0;
++      }
+     }
+   }
+   sqlite3ResetInternalSchema(db, 0);
+@@ -179,33 +159,21 @@
+ 
+   sqlite3HashClear(&db->aFunc);
+   sqlite3Error(db, SQLITE_OK, 0); /* Deallocates any cached error strings. */
+-  if( db->pValue ){
+-    sqlite3ValueFree(db->pValue);
+-  }
+   if( db->pErr ){
+     sqlite3ValueFree(db->pErr);
+   }
+ 
+-#ifndef SQLITE_OMIT_GLOBALRECOVER
+-  {
+-    sqlite3 *pPrev;
+-    sqlite3OsEnterMutex();
+-    pPrev = pDbList;
+-    while( pPrev && pPrev->pNext!=db ){
+-      pPrev = pPrev->pNext;
+-    }
+-    if( pPrev ){
+-      pPrev->pNext = db->pNext;
+-    }else{
+-      assert( pDbList==db );
+-      pDbList = db->pNext;
+-    }
+-    sqlite3OsLeaveMutex();
+-  }
+-#endif
++  db->magic = SQLITE_MAGIC_ERROR;
+ 
+-  db->magic = SQLITE_MAGIC_ERROR;
++  /* The temp-database schema is allocated differently from the other schema
++  ** objects (using sqliteMalloc() directly, instead of sqlite3BtreeSchema()).
++  ** So it needs to be freed here. Todo: Why not roll the temp schema into
++  ** the same sqliteMalloc() as the one that allocates the database 
++  ** structure?
++  */
++  sqliteFree(db->aDb[1].pSchema);
+   sqliteFree(db);
++  sqlite3ReleaseThreadData();
+   return SQLITE_OK;
+ }
+ 
+@@ -214,13 +182,24 @@
+ */
+ void sqlite3RollbackAll(sqlite3 *db){
+   int i;
++  int inTrans = 0;
+   for(i=0; i<db->nDb; i++){
+     if( db->aDb[i].pBt ){
++      if( sqlite3BtreeIsInTrans(db->aDb[i].pBt) ){
++        inTrans = 1;
++      }
+       sqlite3BtreeRollback(db->aDb[i].pBt);
+       db->aDb[i].inTrans = 0;
+     }
+   }
+-  sqlite3ResetInternalSchema(db, 0);
++  if( db->flags&SQLITE_InternChanges ){
++    sqlite3ResetInternalSchema(db, 0);
++  }
++
++  /* If one has been configured, invoke the rollback-hook callback */
++  if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){
++    db->xRollbackCallback(db->pRollbackArg);
++  }
+ }
+ 
+ /*
+@@ -402,9 +381,12 @@
+ void sqlite3_free(char *p){ free(p); }
+ 
+ /*
+-** Create new user functions.
++** This function is exactly the same as sqlite3_create_function(), except
++** that it is designed to be called by internal code. The difference is
++** that if a malloc() fails in sqlite3_create_function(), an error code
++** is returned and the mallocFailed flag cleared. 
+ */
+-int sqlite3_create_function(
++int sqlite3CreateFunc(
+   sqlite3 *db,
+   const char *zFunctionName,
+   int nArg,
+@@ -441,10 +423,10 @@
+     enc = SQLITE_UTF16NATIVE;
+   }else if( enc==SQLITE_ANY ){
+     int rc;
+-    rc = sqlite3_create_function(db, zFunctionName, nArg, SQLITE_UTF8,
++    rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8,
+          pUserData, xFunc, xStep, xFinal);
+     if( rc!=SQLITE_OK ) return rc;
+-    rc = sqlite3_create_function(db, zFunctionName, nArg, SQLITE_UTF16LE,
++    rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE,
+         pUserData, xFunc, xStep, xFinal);
+     if( rc!=SQLITE_OK ) return rc;
+     enc = SQLITE_UTF16BE;
+@@ -463,6 +445,7 @@
+     if( db->activeVdbeCnt ){
+       sqlite3Error(db, SQLITE_BUSY, 
+         "Unable to delete/modify user-function due to active statements");
++      assert( !sqlite3MallocFailed() );
+       return SQLITE_BUSY;
+     }else{
+       sqlite3ExpirePreparedStatements(db);
+@@ -470,42 +453,56 @@
+   }
+ 
+   p = sqlite3FindFunction(db, zFunctionName, nName, nArg, enc, 1);
+-  if( p==0 ) return SQLITE_NOMEM;
+-  p->flags = 0;
+-  p->xFunc = xFunc;
+-  p->xStep = xStep;
+-  p->xFinalize = xFinal;
+-  p->pUserData = pUserData;
++  if( p ){
++    p->flags = 0;
++    p->xFunc = xFunc;
++    p->xStep = xStep;
++    p->xFinalize = xFinal;
++    p->pUserData = pUserData;
++  }
+   return SQLITE_OK;
+ }
++
++/*
++** Create new user functions.
++*/
++int sqlite3_create_function(
++  sqlite3 *db,
++  const char *zFunctionName,
++  int nArg,
++  int enc,
++  void *p,
++  void (*xFunc)(sqlite3_context*,int,sqlite3_value **),
++  void (*xStep)(sqlite3_context*,int,sqlite3_value **),
++  void (*xFinal)(sqlite3_context*)
++){
++  int rc;
++  assert( !sqlite3MallocFailed() );
++  rc = sqlite3CreateFunc(db, zFunctionName, nArg, enc, p, xFunc, xStep, xFinal);
++
++  return sqlite3ApiExit(db, rc);
++}
++
+ #ifndef SQLITE_OMIT_UTF16
+ int sqlite3_create_function16(
+   sqlite3 *db,
+   const void *zFunctionName,
+   int nArg,
+   int eTextRep,
+-  void *pUserData,
++  void *p,
+   void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
+   void (*xStep)(sqlite3_context*,int,sqlite3_value**),
+   void (*xFinal)(sqlite3_context*)
+ ){
+   int rc;
+-  char const *zFunc8;
+-  sqlite3_value *pTmp;
++  char *zFunc8;
++  assert( !sqlite3MallocFailed() );
+ 
+-  if( sqlite3SafetyCheck(db) ){
+-    return SQLITE_MISUSE;
+-  }
+-  pTmp = sqlite3GetTransientValue(db);
+-  sqlite3ValueSetStr(pTmp, -1, zFunctionName, SQLITE_UTF16NATIVE,SQLITE_STATIC);
+-  zFunc8 = sqlite3ValueText(pTmp, SQLITE_UTF8);
++  zFunc8 = sqlite3utf16to8(zFunctionName, -1);
++  rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xFunc, xStep, xFinal);
++  sqliteFree(zFunc8);
+ 
+-  if( !zFunc8 ){
+-    return SQLITE_NOMEM;
+-  }
+-  rc = sqlite3_create_function(db, zFunc8, nArg, eTextRep, 
+-      pUserData, xFunc, xStep, xFinal);
+-  return rc;
++  return sqlite3ApiExit(db, rc);
+ }
+ #endif
+ 
+@@ -547,7 +544,7 @@
+ /*** EXPERIMENTAL ***
+ **
+ ** Register a function to be invoked when a transaction comments.
+-** If either function returns non-zero, then the commit becomes a
++** If the invoked function returns non-zero, then the commit becomes a
+ ** rollback.
+ */
+ void *sqlite3_commit_hook(
+@@ -561,8 +558,37 @@
+   return pOld;
+ }
+ 
++/*
++** Register a callback to be invoked each time a row is updated,
++** inserted or deleted using this database connection.
++*/
++void *sqlite3_update_hook(
++  sqlite3 *db,              /* Attach the hook to this database */
++  void (*xCallback)(void*,int,char const *,char const *,sqlite_int64),
++  void *pArg                /* Argument to the function */
++){
++  void *pRet = db->pUpdateArg;
++  db->xUpdateCallback = xCallback;
++  db->pUpdateArg = pArg;
++  return pRet;
++}
+ 
+ /*
++** Register a callback to be invoked each time a transaction is rolled
++** back by this database connection.
++*/
++void *sqlite3_rollback_hook(
++  sqlite3 *db,              /* Attach the hook to this database */
++  void (*xCallback)(void*), /* Callback function */
++  void *pArg                /* Argument to the function */
++){
++  void *pRet = db->pRollbackArg;
++  db->xRollbackCallback = xCallback;
++  db->pRollbackArg = pArg;
++  return pRet;
++}
++
++/*
+ ** This routine is called to create a connection to a database BTree
+ ** driver.  If zFilename is the name of a file, then that file is
+ ** opened and used.  If zFilename is the magic name ":memory:" then
+@@ -621,7 +647,7 @@
+ #endif /* SQLITE_OMIT_MEMORYDB */
+   }
+ 
+-  rc = sqlite3BtreeOpen(zFilename, ppBtree, btree_flags);
++  rc = sqlite3BtreeOpen(zFilename, (sqlite3 *)db, ppBtree, btree_flags);
+   if( rc==SQLITE_OK ){
+     sqlite3BtreeSetBusyHandler(*ppBtree, (void*)&db->busyHandler);
+     sqlite3BtreeSetCacheSize(*ppBtree, nCache);
+@@ -635,13 +661,13 @@
+ */
+ const char *sqlite3_errmsg(sqlite3 *db){
+   const char *z;
+-  if( sqlite3_malloc_failed ){
++  if( !db || sqlite3MallocFailed() ){
+     return sqlite3ErrStr(SQLITE_NOMEM);
+   }
+   if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){
+     return sqlite3ErrStr(SQLITE_MISUSE);
+   }
+-  z = sqlite3_value_text(db->pErr);
++  z = (char*)sqlite3_value_text(db->pErr);
+   if( z==0 ){
+     z = sqlite3ErrStr(db->errCode);
+   }
+@@ -674,7 +700,7 @@
+   };
+ 
+   const void *z;
+-  if( sqlite3_malloc_failed ){
++  if( sqlite3MallocFailed() ){
+     return (void *)(&outOfMemBe[SQLITE_UTF16NATIVE==SQLITE_UTF16LE?1:0]);
+   }
+   if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){
+@@ -686,15 +712,17 @@
+          SQLITE_UTF8, SQLITE_STATIC);
+     z = sqlite3_value_text16(db->pErr);
+   }
++  sqlite3ApiExit(0, 0);
+   return z;
+ }
+ #endif /* SQLITE_OMIT_UTF16 */
+ 
+ /*
+-** Return the most recent error code generated by an SQLite routine.
++** Return the most recent error code generated by an SQLite routine. If NULL is
++** passed to this function, we assume a malloc() failed during sqlite3_open().
+ */
+ int sqlite3_errcode(sqlite3 *db){
+-  if( sqlite3_malloc_failed ){
++  if( !db || sqlite3MallocFailed() ){
+     return SQLITE_NOMEM;
+   }
+   if( sqlite3SafetyCheck(db) ){
+@@ -704,6 +732,64 @@
+ }
+ 
+ /*
++** Create a new collating function for database "db".  The name is zName
++** and the encoding is enc.
++*/
++static int createCollation(
++  sqlite3* db, 
++  const char *zName, 
++  int enc, 
++  void* pCtx,
++  int(*xCompare)(void*,int,const void*,int,const void*)
++){
++  CollSeq *pColl;
++  
++  if( sqlite3SafetyCheck(db) ){
++    return SQLITE_MISUSE;
++  }
++
++  /* If SQLITE_UTF16 is specified as the encoding type, transform this
++  ** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the
++  ** SQLITE_UTF16NATIVE macro. SQLITE_UTF16 is not used internally.
++  */
++  if( enc==SQLITE_UTF16 ){
++    enc = SQLITE_UTF16NATIVE;
++  }
++
++  if( enc!=SQLITE_UTF8 && enc!=SQLITE_UTF16LE && enc!=SQLITE_UTF16BE ){
++    sqlite3Error(db, SQLITE_ERROR, 
++        "Param 3 to sqlite3_create_collation() must be one of "
++        "SQLITE_UTF8, SQLITE_UTF16, SQLITE_UTF16LE or SQLITE_UTF16BE"
++    );
++    return SQLITE_ERROR;
++  }
++
++  /* Check if this call is removing or replacing an existing collation 
++  ** sequence. If so, and there are active VMs, return busy. If there
++  ** are no active VMs, invalidate any pre-compiled statements.
++  */
++  pColl = sqlite3FindCollSeq(db, (u8)enc, zName, strlen(zName), 0);
++  if( pColl && pColl->xCmp ){
++    if( db->activeVdbeCnt ){
++      sqlite3Error(db, SQLITE_BUSY, 
++        "Unable to delete/modify collation sequence due to active statements");
++      return SQLITE_BUSY;
++    }
++    sqlite3ExpirePreparedStatements(db);
++  }
++
++  pColl = sqlite3FindCollSeq(db, (u8)enc, zName, strlen(zName), 1);
++  if( pColl ){
++    pColl->xCmp = xCompare;
++    pColl->pUser = pCtx;
++    pColl->enc = enc;
++  }
++  sqlite3Error(db, SQLITE_OK, 0);
++  return SQLITE_OK;
++}
++
++
++/*
+ ** This routine does the work of opening a database on behalf of
+ ** sqlite3_open() and sqlite3_open16(). The database filename "zFilename"  
+ ** is UTF-8 encoded.
+@@ -713,9 +799,11 @@
+   sqlite3 **ppDb         /* OUT: Returned database handle */
+ ){
+   sqlite3 *db;
+-  int rc, i;
++  int rc;
+   CollSeq *pColl;
+ 
++  assert( !sqlite3MallocFailed() );
++
+   /* Allocate the sqlite data structure */
+   db = sqliteMalloc( sizeof(sqlite3) );
+   if( db==0 ) goto opendb_out;
+@@ -723,33 +811,27 @@
+   db->magic = SQLITE_MAGIC_BUSY;
+   db->nDb = 2;
+   db->aDb = db->aDbStatic;
+-  db->enc = SQLITE_UTF8;
+   db->autoCommit = 1;
+   db->flags |= SQLITE_ShortColNames;
+   sqlite3HashInit(&db->aFunc, SQLITE_HASH_STRING, 0);
+   sqlite3HashInit(&db->aCollSeq, SQLITE_HASH_STRING, 0);
+-  for(i=0; i<db->nDb; i++){
+-    sqlite3HashInit(&db->aDb[i].tblHash, SQLITE_HASH_STRING, 0);
+-    sqlite3HashInit(&db->aDb[i].idxHash, SQLITE_HASH_STRING, 0);
+-    sqlite3HashInit(&db->aDb[i].trigHash, SQLITE_HASH_STRING, 0);
+-    sqlite3HashInit(&db->aDb[i].aFKey, SQLITE_HASH_STRING, 1);
+-  }
+-  
++
+   /* Add the default collation sequence BINARY. BINARY works for both UTF-8
+   ** and UTF-16, so add a version for each to avoid any unnecessary
+   ** conversions. The only error that can occur here is a malloc() failure.
+   */
+-  if( sqlite3_create_collation(db, "BINARY", SQLITE_UTF8, 0,binCollFunc) ||
+-      sqlite3_create_collation(db, "BINARY", SQLITE_UTF16, 0,binCollFunc) ||
+-      !(db->pDfltColl = sqlite3FindCollSeq(db, db->enc, "BINARY", 6, 0)) ){
+-    rc = db->errCode;
+-    assert( rc!=SQLITE_OK );
++  if( createCollation(db, "BINARY", SQLITE_UTF8, 0, binCollFunc) ||
++      createCollation(db, "BINARY", SQLITE_UTF16BE, 0, binCollFunc) ||
++      createCollation(db, "BINARY", SQLITE_UTF16LE, 0, binCollFunc) ||
++      (db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 6, 0))==0 
++  ){
++    assert( sqlite3MallocFailed() );
+     db->magic = SQLITE_MAGIC_CLOSED;
+     goto opendb_out;
+   }
+ 
+   /* Also add a UTF-8 case-insensitive collation sequence. */
+-  sqlite3_create_collation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc);
++  createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc);
+ 
+   /* Set flags on the built-in collating sequences */
+   db->pDfltColl->type = SQLITE_COLL_BINARY;
+@@ -765,7 +847,15 @@
+     db->magic = SQLITE_MAGIC_CLOSED;
+     goto opendb_out;
+   }
++#ifndef SQLITE_OMIT_PARSER
++  db->aDb[0].pSchema = sqlite3SchemaGet(db->aDb[0].pBt);
++  db->aDb[1].pSchema = sqlite3SchemaGet(0);
++#endif
+ 
++  if( db->aDb[0].pSchema ){
++    ENC(db) = SQLITE_UTF8;
++  }
++
+   /* The default safety_level for the main database is 'full'; for the temp
+   ** database it is 'NONE'. This matches the pager layer defaults.  
+   */
+@@ -776,29 +866,23 @@
+   db->aDb[1].safety_level = 1;
+ #endif
+ 
+-
+   /* Register all built-in functions, but do not attempt to read the
+   ** database schema yet. This is delayed until the first time the database
+   ** is accessed.
+   */
+-  sqlite3RegisterBuiltinFunctions(db);
+-  sqlite3Error(db, SQLITE_OK, 0);
++  if( !sqlite3MallocFailed() ){
++    sqlite3RegisterBuiltinFunctions(db);
++    sqlite3Error(db, SQLITE_OK, 0);
++  }
+   db->magic = SQLITE_MAGIC_OPEN;
+ 
+ opendb_out:
+-  if( sqlite3_errcode(db)==SQLITE_OK && sqlite3_malloc_failed ){
+-    sqlite3Error(db, SQLITE_NOMEM, 0);
++  if( SQLITE_NOMEM==(rc = sqlite3_errcode(db)) ){
++    sqlite3_close(db);
++    db = 0;
+   }
+   *ppDb = db;
+-#ifndef SQLITE_OMIT_GLOBALRECOVER
+-  if( db ){
+-    sqlite3OsEnterMutex();
+-    db->pNext = pDbList;
+-    pDbList = db;
+-    sqlite3OsLeaveMutex();
+-  }
+-#endif
+-  return sqlite3_errcode(db);
++  return sqlite3ApiExit(0, rc);
+ }
+ 
+ /*
+@@ -820,9 +904,10 @@
+   sqlite3 **ppDb
+ ){
+   char const *zFilename8;   /* zFilename encoded in UTF-8 instead of UTF-16 */
+-  int rc = SQLITE_NOMEM;
++  int rc = SQLITE_OK;
+   sqlite3_value *pVal;
+ 
++  assert( zFilename );
+   assert( ppDb );
+   *ppDb = 0;
+   pVal = sqlite3ValueNew();
+@@ -831,14 +916,16 @@
+   if( zFilename8 ){
+     rc = openDatabase(zFilename8, ppDb);
+     if( rc==SQLITE_OK && *ppDb ){
+-      sqlite3_exec(*ppDb, "PRAGMA encoding = 'UTF-16'", 0, 0, 0);
++      rc = sqlite3_exec(*ppDb, "PRAGMA encoding = 'UTF-16'", 0, 0, 0);
++      if( rc!=SQLITE_OK ){
++        sqlite3_close(*ppDb);
++        *ppDb = 0;
++      }
+     }
+   }
+-  if( pVal ){
+-    sqlite3ValueFree(pVal);
+-  }
++  sqlite3ValueFree(pVal);
+ 
+-  return rc;
++  return sqlite3ApiExit(0, rc);
+ }
+ #endif /* SQLITE_OMIT_UTF16 */
+ 
+@@ -890,53 +977,10 @@
+   void* pCtx,
+   int(*xCompare)(void*,int,const void*,int,const void*)
+ ){
+-  CollSeq *pColl;
+-  int rc = SQLITE_OK;
+-  
+-  if( sqlite3SafetyCheck(db) ){
+-    return SQLITE_MISUSE;
+-  }
+-
+-  /* If SQLITE_UTF16 is specified as the encoding type, transform this
+-  ** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the
+-  ** SQLITE_UTF16NATIVE macro. SQLITE_UTF16 is not used internally.
+-  */
+-  if( enc==SQLITE_UTF16 ){
+-    enc = SQLITE_UTF16NATIVE;
+-  }
+-
+-  if( enc!=SQLITE_UTF8 && enc!=SQLITE_UTF16LE && enc!=SQLITE_UTF16BE ){
+-    sqlite3Error(db, SQLITE_ERROR, 
+-        "Param 3 to sqlite3_create_collation() must be one of "
+-        "SQLITE_UTF8, SQLITE_UTF16, SQLITE_UTF16LE or SQLITE_UTF16BE"
+-    );
+-    return SQLITE_ERROR;
+-  }
+-
+-  /* Check if this call is removing or replacing an existing collation 
+-  ** sequence. If so, and there are active VMs, return busy. If there
+-  ** are no active VMs, invalidate any pre-compiled statements.
+-  */
+-  pColl = sqlite3FindCollSeq(db, (u8)enc, zName, strlen(zName), 0);
+-  if( pColl && pColl->xCmp ){
+-    if( db->activeVdbeCnt ){
+-      sqlite3Error(db, SQLITE_BUSY, 
+-        "Unable to delete/modify collation sequence due to active statements");
+-      return SQLITE_BUSY;
+-    }
+-    sqlite3ExpirePreparedStatements(db);
+-  }
+-
+-  pColl = sqlite3FindCollSeq(db, (u8)enc, zName, strlen(zName), 1);
+-  if( 0==pColl ){
+-    rc = SQLITE_NOMEM;
+-  }else{
+-    pColl->xCmp = xCompare;
+-    pColl->pUser = pCtx;
+-    pColl->enc = enc;
+-  }
+-  sqlite3Error(db, rc, 0);
+-  return rc;
++  int rc;
++  assert( !sqlite3MallocFailed() );
++  rc = createCollation(db, zName, enc, pCtx, xCompare);
++  return sqlite3ApiExit(db, rc);
+ }
+ 
+ #ifndef SQLITE_OMIT_UTF16
+@@ -950,15 +994,15 @@
+   void* pCtx,
+   int(*xCompare)(void*,int,const void*,int,const void*)
+ ){
+-  char const *zName8;
+-  sqlite3_value *pTmp;
+-  if( sqlite3SafetyCheck(db) ){
+-    return SQLITE_MISUSE;
++  int rc = SQLITE_OK;
++  char *zName8; 
++  assert( !sqlite3MallocFailed() );
++  zName8 = sqlite3utf16to8(zName, -1);
++  if( zName8 ){
++    rc = createCollation(db, zName8, enc, pCtx, xCompare);
++    sqliteFree(zName8);
+   }
+-  pTmp = sqlite3GetTransientValue(db);
+-  sqlite3ValueSetStr(pTmp, -1, zName, SQLITE_UTF16NATIVE, SQLITE_STATIC);
+-  zName8 = sqlite3ValueText(pTmp, SQLITE_UTF8);
+-  return sqlite3_create_collation(db, zName8, enc, pCtx, xCompare);
++  return sqlite3ApiExit(db, rc);
+ }
+ #endif /* SQLITE_OMIT_UTF16 */
+ 
+@@ -1002,37 +1046,11 @@
+ 
+ #ifndef SQLITE_OMIT_GLOBALRECOVER
+ /*
+-** This function is called to recover from a malloc failure that occured
+-** within SQLite. 
+-**
+-** This function is *not* threadsafe. Calling this from within a threaded
+-** application when threads other than the caller have used SQLite is 
+-** dangerous and will almost certainly result in malfunctions.
++** This function is now an anachronism. It used to be used to recover from a
++** malloc() failure, but SQLite now does this automatically.
+ */
+ int sqlite3_global_recover(){
+-  int rc = SQLITE_OK;
+-
+-  if( sqlite3_malloc_failed ){
+-    sqlite3 *db;
+-    int i;
+-    sqlite3_malloc_failed = 0;
+-    for(db=pDbList; db; db=db->pNext ){
+-      sqlite3ExpirePreparedStatements(db);
+-      for(i=0; i<db->nDb; i++){
+-        Btree *pBt = db->aDb[i].pBt;
+-        if( pBt && (rc=sqlite3BtreeReset(pBt)) ){
+-          goto recover_out;
+-        }
+-      } 
+-      db->autoCommit = 1;
+-    }
+-  }
+-
+-recover_out:
+-  if( rc!=SQLITE_OK ){
+-    sqlite3_malloc_failed = 1;
+-  }
+-  return rc;
++  return SQLITE_OK;
+ }
+ #endif
+ 
+@@ -1058,3 +1076,158 @@
+   return SQLITE_CORRUPT;
+ }
+ #endif
++
++
++#ifndef SQLITE_OMIT_SHARED_CACHE
++/*
++** Enable or disable the shared pager and schema features for the
++** current thread.
++**
++** This routine should only be called when there are no open
++** database connections.
++*/
++int sqlite3_enable_shared_cache(int enable){
++  ThreadData *pTd = sqlite3ThreadData();
++  if( pTd ){
++    /* It is only legal to call sqlite3_enable_shared_cache() when there
++    ** are no currently open b-trees that were opened by the calling thread.
++    ** This condition is only easy to detect if the shared-cache were 
++    ** previously enabled (and is being disabled). 
++    */
++    if( pTd->pBtree && !enable ){
++      assert( pTd->useSharedData );
++      return SQLITE_MISUSE;
++    }
++
++    pTd->useSharedData = enable;
++    sqlite3ReleaseThreadData();
++  }
++  return sqlite3ApiExit(0, SQLITE_OK);
++}
++#endif
++
++/*
++** This is a convenience routine that makes sure that all thread-specific
++** data for this thread has been deallocated.
++*/
++void sqlite3_thread_cleanup(void){
++  ThreadData *pTd = sqlite3OsThreadSpecificData(0);
++  if( pTd ){
++    memset(pTd, 0, sizeof(*pTd));
++    sqlite3OsThreadSpecificData(-1);
++  }
++}
++
++/*
++** Return meta information about a specific column of a database table.
++** See comment in sqlite3.h (sqlite.h.in) for details.
++*/
++#ifdef SQLITE_ENABLE_COLUMN_METADATA
++int sqlite3_table_column_metadata(
++  sqlite3 *db,                /* Connection handle */
++  const char *zDbName,        /* Database name or NULL */
++  const char *zTableName,     /* Table name */
++  const char *zColumnName,    /* Column name */
++  char const **pzDataType,    /* OUTPUT: Declared data type */
++  char const **pzCollSeq,     /* OUTPUT: Collation sequence name */
++  int *pNotNull,              /* OUTPUT: True if NOT NULL constraint exists */
++  int *pPrimaryKey,           /* OUTPUT: True if column part of PK */
++  int *pAutoinc               /* OUTPUT: True if colums is auto-increment */
++){
++  int rc;
++  char *zErrMsg = 0;
++  Table *pTab = 0;
++  Column *pCol = 0;
++  int iCol;
++
++  char const *zDataType = 0;
++  char const *zCollSeq = 0;
++  int notnull = 0;
++  int primarykey = 0;
++  int autoinc = 0;
++
++  /* Ensure the database schema has been loaded */
++  if( sqlite3SafetyOn(db) ){
++    return SQLITE_MISUSE;
++  }
++  rc = sqlite3Init(db, &zErrMsg);
++  if( SQLITE_OK!=rc ){
++    goto error_out;
++  }
++
++  /* Locate the table in question */
++  pTab = sqlite3FindTable(db, zTableName, zDbName);
++  if( !pTab || pTab->pSelect ){
++    pTab = 0;
++    goto error_out;
++  }
++
++  /* Find the column for which info is requested */
++  if( sqlite3IsRowid(zColumnName) ){
++    iCol = pTab->iPKey;
++    if( iCol>=0 ){
++      pCol = &pTab->aCol[iCol];
++    }
++  }else{
++    for(iCol=0; iCol<pTab->nCol; iCol++){
++      pCol = &pTab->aCol[iCol];
++      if( 0==sqlite3StrICmp(pCol->zName, zColumnName) ){
++        break;
++      }
++    }
++    if( iCol==pTab->nCol ){
++      pTab = 0;
++      goto error_out;
++    }
++  }
++
++  /* The following block stores the meta information that will be returned
++  ** to the caller in local variables zDataType, zCollSeq, notnull, primarykey
++  ** and autoinc. At this point there are two possibilities:
++  ** 
++  **     1. The specified column name was rowid", "oid" or "_rowid_" 
++  **        and there is no explicitly declared IPK column. 
++  **
++  **     2. The table is not a view and the column name identified an 
++  **        explicitly declared column. Copy meta information from *pCol.
++  */ 
++  if( pCol ){
++    zDataType = pCol->zType;
++    zCollSeq = pCol->zColl;
++    notnull = (pCol->notNull?1:0);
++    primarykey  = (pCol->isPrimKey?1:0);
++    autoinc = ((pTab->iPKey==iCol && pTab->autoInc)?1:0);
++  }else{
++    zDataType = "INTEGER";
++    primarykey = 1;
++  }
++  if( !zCollSeq ){
++    zCollSeq = "BINARY";
++  }
++
++error_out:
++  if( sqlite3SafetyOff(db) ){
++    rc = SQLITE_MISUSE;
++  }
++
++  /* Whether the function call succeeded or failed, set the output parameters
++  ** to whatever their local counterparts contain. If an error did occur,
++  ** this has the effect of zeroing all output parameters.
++  */
++  if( pzDataType ) *pzDataType = zDataType;
++  if( pzCollSeq ) *pzCollSeq = zCollSeq;
++  if( pNotNull ) *pNotNull = notnull;
++  if( pPrimaryKey ) *pPrimaryKey = primarykey;
++  if( pAutoinc ) *pAutoinc = autoinc;
++
++  if( SQLITE_OK==rc && !pTab ){
++    sqlite3SetString(&zErrMsg, "no such table column: ", zTableName, ".", 
++        zColumnName, 0);
++    rc = SQLITE_ERROR;
++  }
++  sqlite3Error(db, rc, (zErrMsg?"%s":0), zErrMsg);
++  sqliteFree(zErrMsg);
++  return sqlite3ApiExit(db, rc);
++}
++#endif
++
+Index: sqlite/vdbe.h
+===================================================================
+--- amarok/src/sqlite/vdbe.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/vdbe.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -69,6 +69,7 @@
+ #define P3_KEYINFO  (-6)  /* P3 is a pointer to a KeyInfo structure */
+ #define P3_VDBEFUNC (-7)  /* P3 is a pointer to a VdbeFunc structure */
+ #define P3_MEM      (-8)  /* P3 is a pointer to a Mem*    structure */
++#define P3_TRANSIENT (-9)  /* P3 is a pointer to a transient string */
+ 
+ /* When adding a P3 argument using P3_KEYINFO, a copy of the KeyInfo structure
+ ** is made.  That copy is freed when the Vdbe is finalized.  But if the
+@@ -80,6 +81,17 @@
+ #define P3_KEYINFO_HANDOFF (-9)
+ 
+ /*
++** The Vdbe.aColName array contains 5n Mem structures, where n is the 
++** number of columns of data returned by the statement.
++*/
++#define COLNAME_NAME     0
++#define COLNAME_DECLTYPE 1
++#define COLNAME_DATABASE 2
++#define COLNAME_TABLE    3
++#define COLNAME_COLUMN   4
++#define COLNAME_N        5      /* Number of COLNAME_xxx symbols */
++
++/*
+ ** The following macro converts a relative address in the p2 field
+ ** of a VdbeOp structure into a negative number so that 
+ ** sqlite3VdbeAddOpList() knows that the address is relative.  Calling
+@@ -117,7 +129,7 @@
+ int sqlite3VdbeReset(Vdbe*);
+ int sqliteVdbeSetVariables(Vdbe*,int,const char**);
+ void sqlite3VdbeSetNumCols(Vdbe*,int);
+-int sqlite3VdbeSetColName(Vdbe*, int, const char *, int);
++int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, int);
+ void sqlite3VdbeCountChanges(Vdbe*);
+ sqlite3 *sqlite3VdbeDb(Vdbe*);
+ 
+Index: sqlite/table.c
+===================================================================
+--- amarok/src/sqlite/table.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/table.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -16,10 +16,12 @@
+ ** These routines are in a separate files so that they will not be linked
+ ** if they are not used.
+ */
++#include "sqliteInt.h"
+ #include <stdlib.h>
+ #include <string.h>
+-#include "sqliteInt.h"
+ 
++#ifndef SQLITE_OMIT_GET_TABLE
++
+ /*
+ ** This structure is used to pass data from sqlite3_get_table() through
+ ** to the callback function is uses to build the result.
+@@ -143,6 +145,7 @@
+   res.azResult[0] = 0;
+   rc = sqlite3_exec(db, zSql, sqlite3_get_table_cb, &res, pzErrMsg);
+   if( res.azResult ){
++    assert( sizeof(res.azResult[0])>= sizeof(res.nData) );
+     res.azResult[0] = (char*)res.nData;
+   }
+   if( rc==SQLITE_ABORT ){
+@@ -193,3 +196,5 @@
+     free(azResult);
+   }
+ }
++
++#endif /* SQLITE_OMIT_GET_TABLE */
+Index: sqlite/Makefile.am
+===================================================================
+--- amarok/src/sqlite/Makefile.am	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/Makefile.am	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -30,6 +30,7 @@
+     legacy.c \
+     main.c \
+     opcodes.c \
++    os.c \
+     os_unix.c \
+     os_win.c \
+     pager.c \
+Index: sqlite/sqlite3.h
+===================================================================
+--- amarok/src/sqlite/sqlite3.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/sqlite3.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -31,7 +31,7 @@
+ #ifdef SQLITE_VERSION
+ # undef SQLITE_VERSION
+ #endif
+-#define SQLITE_VERSION         "3.2.7"
++#define SQLITE_VERSION         "3.3.4"
+ 
+ /*
+ ** The format of the version string is "X.Y.Z<trailing string>", where
+@@ -48,7 +48,7 @@
+ #ifdef SQLITE_VERSION_NUMBER
+ # undef SQLITE_VERSION_NUMBER
+ #endif
+-#define SQLITE_VERSION_NUMBER 3002007
++#define SQLITE_VERSION_NUMBER 3003004
+ 
+ /*
+ ** The version string is also compiled into the library so that a program
+@@ -86,6 +86,13 @@
+   typedef unsigned long long int sqlite_uint64;
+ #endif
+ 
++/*
++** If compiling for a processor that lacks floating point support,
++** substitute integer for floating-point
++*/
++#ifdef SQLITE_OMIT_FLOATING_POINT
++# define double sqlite_int64
++#endif
+ 
+ /*
+ ** A function to close the database.
+@@ -157,6 +164,7 @@
+ ** Return values for sqlite3_exec() and sqlite3_step()
+ */
+ #define SQLITE_OK           0   /* Successful result */
++/* beginning-of-error-codes */
+ #define SQLITE_ERROR        1   /* SQL error or missing database */
+ #define SQLITE_INTERNAL     2   /* NOT USED. Internal logic error in SQLite */
+ #define SQLITE_PERM         3   /* Access permission denied */
+@@ -185,6 +193,7 @@
+ #define SQLITE_NOTADB      26   /* File opened that is not a database file */
+ #define SQLITE_ROW         100  /* sqlite3_step() has another row ready */
+ #define SQLITE_DONE        101  /* sqlite3_step() has finished executing */
++/* end-of-error-codes */
+ 
+ /*
+ ** Each entry in an SQLite table has a unique integer key.  (The key is
+@@ -717,6 +726,30 @@
+ const void *sqlite3_column_name16(sqlite3_stmt*,int);
+ 
+ /*
++** The first parameter to the following calls is a compiled SQL statement.
++** These functions return information about the Nth column returned by 
++** the statement, where N is the second function argument.
++**
++** If the Nth column returned by the statement is not a column value,
++** then all of the functions return NULL. Otherwise, the return the 
++** name of the attached database, table and column that the expression
++** extracts a value from.
++**
++** As with all other SQLite APIs, those postfixed with "16" return UTF-16
++** encoded strings, the other functions return UTF-8. The memory containing
++** the returned strings is valid until the statement handle is finalized().
++**
++** These APIs are only available if the library was compiled with the 
++** SQLITE_ENABLE_COLUMN_METADATA preprocessor symbol defined.
++*/
++const char *sqlite3_column_database_name(sqlite3_stmt*,int);
++const void *sqlite3_column_database_name16(sqlite3_stmt*,int);
++const char *sqlite3_column_table_name(sqlite3_stmt*,int);
++const void *sqlite3_column_table_name16(sqlite3_stmt*,int);
++const char *sqlite3_column_origin_name(sqlite3_stmt*,int);
++const void *sqlite3_column_origin_name16(sqlite3_stmt*,int);
++
++/*
+ ** The first parameter is a compiled SQL statement. If this statement
+ ** is a SELECT statement, the Nth column of the returned result set 
+ ** of the SELECT is a table column then the declared type of the table
+@@ -728,7 +761,7 @@
+ **
+ ** And the following statement compiled:
+ **
+-** SELECT c1 + 1, 0 FROM t1;
++** SELECT c1 + 1, c1 FROM t1;
+ **
+ ** Then this routine would return the string "VARIANT" for the second
+ ** result column (i==1), and a NULL pointer for the first result column
+@@ -748,7 +781,7 @@
+ **
+ ** And the following statement compiled:
+ **
+-** SELECT c1 + 1, 0 FROM t1;
++** SELECT c1 + 1, c1 FROM t1;
+ **
+ ** Then this routine would return the string "INTEGER" for the second
+ ** result column (i==1), and a NULL pointer for the first result column
+@@ -889,6 +922,7 @@
+ const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
+ const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
+ int sqlite3_column_type(sqlite3_stmt*, int iCol);
++int sqlite3_column_numeric_type(sqlite3_stmt*, int iCol);
+ 
+ /*
+ ** The sqlite3_finalize() function is called to delete a compiled
+@@ -972,9 +1006,8 @@
+ );
+ 
+ /*
+-** The next routine returns the number of calls to xStep for a particular
+-** aggregate function instance.  The current call to xStep counts so this
+-** routine always returns at least 1.
++** This function is deprecated.  Do not use it.  It continues to exist
++** so as not to break legacy code.  But new code should avoid using it.
+ */
+ int sqlite3_aggregate_count(sqlite3_context*);
+ 
+@@ -997,6 +1030,7 @@
+ const void *sqlite3_value_text16le(sqlite3_value*);
+ const void *sqlite3_value_text16be(sqlite3_value*);
+ int sqlite3_value_type(sqlite3_value*);
++int sqlite3_value_numeric_type(sqlite3_value*);
+ 
+ /*
+ ** Aggregate functions use the following routine to allocate
+@@ -1251,7 +1285,7 @@
+ ** This functionality can be omitted from a build by defining the 
+ ** SQLITE_OMIT_GLOBALRECOVER at compile time.
+ */
+-int sqlite3_global_recover();
++int sqlite3_global_recover(void);
+ 
+ /*
+ ** Test to see whether or not the database connection is in autocommit
+@@ -1269,6 +1303,175 @@
+ */
+ sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
+ 
++/*
++** Register a callback function with the database connection identified by the 
++** first argument to be invoked whenever a row is updated, inserted or deleted.
++** Any callback set by a previous call to this function for the same 
++** database connection is overridden.
++**
++** The second argument is a pointer to the function to invoke when a 
++** row is updated, inserted or deleted. The first argument to the callback is
++** a copy of the third argument to sqlite3_update_hook. The second callback 
++** argument is one of SQLITE_INSERT, SQLITE_DELETE or SQLITE_UPDATE, depending
++** on the operation that caused the callback to be invoked. The third and 
++** fourth arguments to the callback contain pointers to the database and 
++** table name containing the affected row. The final callback parameter is 
++** the rowid of the row. In the case of an update, this is the rowid after 
++** the update takes place.
++**
++** The update hook is not invoked when internal system tables are
++** modified (i.e. sqlite_master and sqlite_sequence).
++**
++** If another function was previously registered, its pArg value is returned.
++** Otherwise NULL is returned.
++*/
++void *sqlite3_update_hook(
++  sqlite3*, 
++  void(*)(void *,int ,char const *,char const *,sqlite_int64),
++  void*
++);
++
++/*
++** Register a callback to be invoked whenever a transaction is rolled
++** back. 
++**
++** The new callback function overrides any existing rollback-hook
++** callback. If there was an existing callback, then it's pArg value 
++** (the third argument to sqlite3_rollback_hook() when it was registered) 
++** is returned. Otherwise, NULL is returned.
++**
++** For the purposes of this API, a transaction is said to have been 
++** rolled back if an explicit "ROLLBACK" statement is executed, or
++** an error or constraint causes an implicit rollback to occur. The 
++** callback is not invoked if a transaction is automatically rolled
++** back because the database connection is closed.
++*/
++void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
++
++/*
++** This function is only available if the library is compiled without
++** the SQLITE_OMIT_SHARED_CACHE macro defined. It is used to enable or
++** disable (if the argument is true or false, respectively) the 
++** "shared pager" feature.
++*/
++int sqlite3_enable_shared_cache(int);
++
++/*
++** Attempt to free N bytes of heap memory by deallocating non-essential
++** memory allocations held by the database library (example: memory 
++** used to cache database pages to improve performance).
++**
++** This function is not a part of standard builds.  It is only created
++** if SQLite is compiled with the SQLITE_ENABLE_MEMORY_MANAGEMENT macro.
++*/
++int sqlite3_release_memory(int);
++
++/*
++** Place a "soft" limit on the amount of heap memory that may be allocated by
++** SQLite within the current thread. If an internal allocation is requested 
++** that would exceed the specified limit, sqlite3_release_memory() is invoked
++** one or more times to free up some space before the allocation is made.
++**
++** The limit is called "soft", because if sqlite3_release_memory() cannot free
++** sufficient memory to prevent the limit from being exceeded, the memory is
++** allocated anyway and the current operation proceeds.
++**
++** This function is only available if the library was compiled with the 
++** SQLITE_ENABLE_MEMORY_MANAGEMENT option set.
++** memory-management has been enabled.
++*/
++void sqlite3_soft_heap_limit(int);
++
++/*
++** This routine makes sure that all thread-local storage has been
++** deallocated for the current thread.
++**
++** This routine is not technically necessary.  All thread-local storage
++** will be automatically deallocated once memory-management and
++** shared-cache are disabled and the soft heap limit has been set
++** to zero.  This routine is provided as a convenience for users who
++** want to make absolutely sure they have not forgotten something
++** prior to killing off a thread.
++*/
++void sqlite3_thread_cleanup(void);
++
++/*
++** Return meta information about a specific column of a specific database
++** table accessible using the connection handle passed as the first function 
++** argument.
++**
++** The column is identified by the second, third and fourth parameters to 
++** this function. The second parameter is either the name of the database
++** (i.e. "main", "temp" or an attached database) containing the specified
++** table or NULL. If it is NULL, then all attached databases are searched
++** for the table using the same algorithm as the database engine uses to 
++** resolve unqualified table references.
++**
++** The third and fourth parameters to this function are the table and column 
++** name of the desired column, respectively. Neither of these parameters 
++** may be NULL.
++**
++** Meta information is returned by writing to the memory locations passed as
++** the 5th and subsequent parameters to this function. Any of these 
++** arguments may be NULL, in which case the corresponding element of meta 
++** information is ommitted.
++**
++** Parameter     Output Type      Description
++** -----------------------------------
++**
++**   5th         const char*      Data type
++**   6th         const char*      Name of the default collation sequence 
++**   7th         int              True if the column has a NOT NULL constraint
++**   8th         int              True if the column is part of the PRIMARY KEY
++**   9th         int              True if the column is AUTOINCREMENT
++**
++**
++** The memory pointed to by the character pointers returned for the 
++** declaration type and collation sequence is valid only until the next 
++** call to any sqlite API function.
++**
++** If the specified table is actually a view, then an error is returned.
++**
++** If the specified column is "rowid", "oid" or "_rowid_" and an 
++** INTEGER PRIMARY KEY column has been explicitly declared, then the output 
++** parameters are set for the explicitly declared column. If there is no
++** explicitly declared IPK column, then the output parameters are set as 
++** follows:
++**
++**     data type: "INTEGER"
++**     collation sequence: "BINARY"
++**     not null: 0
++**     primary key: 1
++**     auto increment: 0
++**
++** This function may load one or more schemas from database files. If an
++** error occurs during this process, or if the requested table or column
++** cannot be found, an SQLITE error code is returned and an error message
++** left in the database handle (to be retrieved using sqlite3_errmsg()).
++**
++** This API is only available if the library was compiled with the
++** SQLITE_ENABLE_COLUMN_METADATA preprocessor symbol defined.
++*/
++int sqlite3_table_column_metadata(
++  sqlite3 *db,                /* Connection handle */
++  const char *zDbName,        /* Database name or NULL */
++  const char *zTableName,     /* Table name */
++  const char *zColumnName,    /* Column name */
++  char const **pzDataType,    /* OUTPUT: Declared data type */
++  char const **pzCollSeq,     /* OUTPUT: Collation sequence name */
++  int *pNotNull,              /* OUTPUT: True if NOT NULL constraint exists */
++  int *pPrimaryKey,           /* OUTPUT: True if column part of PK */
++  int *pAutoinc               /* OUTPUT: True if colums is auto-increment */
++);
++
++/*
++** Undo the hack that converts floating point types to integer for
++** builds on processors without floating point support.
++*/
++#ifdef SQLITE_OMIT_FLOATING_POINT
++# undef double
++#endif
++
+ #ifdef __cplusplus
+ }  /* End of the 'extern "C"' block */
+ #endif
+Index: sqlite/func.c
+===================================================================
+--- amarok/src/sqlite/func.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/func.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -20,7 +20,7 @@
+ */
+ #include "sqliteInt.h"
+ #include <ctype.h>
+-#include <math.h>
++/* #include <math.h> */
+ #include <stdlib.h>
+ #include <assert.h>
+ #include "vdbeInt.h"
+@@ -101,7 +101,7 @@
+       break;
+     }
+     case SQLITE_TEXT: {
+-      const char *z = sqlite3_value_text(argv[0]);
++      const unsigned char *z = sqlite3_value_text(argv[0]);
+       for(len=0; *z; z++){ if( (0xc0&*z)!=0x80 ) len++; }
+       sqlite3_result_int(context, len);
+       break;
+@@ -146,8 +146,8 @@
+   int argc,
+   sqlite3_value **argv
+ ){
+-  const char *z;
+-  const char *z2;
++  const unsigned char *z;
++  const unsigned char *z2;
+   int i;
+   int p1, p2, len;
+ 
+@@ -178,7 +178,7 @@
+   }
+   while( z[i] && (z[i]&0xc0)==0x80 ){ i++; p2++; }
+   if( p2<0 ) p2 = 0;
+-  sqlite3_result_text(context, &z[p1], p2, SQLITE_TRANSIENT);
++  sqlite3_result_text(context, (char*)&z[p1], p2, SQLITE_TRANSIENT);
+ }
+ 
+ /*
+@@ -210,11 +210,11 @@
+   if( argc<1 || SQLITE_NULL==sqlite3_value_type(argv[0]) ) return;
+   z = sqliteMalloc(sqlite3_value_bytes(argv[0])+1);
+   if( z==0 ) return;
+-  strcpy(z, sqlite3_value_text(argv[0]));
++  strcpy((char*)z, (char*)sqlite3_value_text(argv[0]));
+   for(i=0; z[i]; i++){
+     z[i] = toupper(z[i]);
+   }
+-  sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT);
++  sqlite3_result_text(context, (char*)z, -1, SQLITE_TRANSIENT);
+   sqliteFree(z);
+ }
+ static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
+@@ -223,11 +223,11 @@
+   if( argc<1 || SQLITE_NULL==sqlite3_value_type(argv[0]) ) return;
+   z = sqliteMalloc(sqlite3_value_bytes(argv[0])+1);
+   if( z==0 ) return;
+-  strcpy(z, sqlite3_value_text(argv[0]));
++  strcpy((char*)z, (char*)sqlite3_value_text(argv[0]));
+   for(i=0; z[i]; i++){
+     z[i] = tolower(z[i]);
+   }
+-  sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT);
++  sqlite3_result_text(context, (char*)z, -1, SQLITE_TRANSIENT);
+   sqliteFree(z);
+ }
+ 
+@@ -495,7 +495,7 @@
+     ** Otherwise, return an error.
+     */
+     const unsigned char *zEsc = sqlite3_value_text(argv[2]);
+-    if( sqlite3utf8CharLen(zEsc, -1)!=1 ){
++    if( sqlite3utf8CharLen((char*)zEsc, -1)!=1 ){
+       sqlite3_result_error(context, 
+           "ESCAPE expression must be a single character", -1);
+       return;
+@@ -592,7 +592,7 @@
+     }
+     case SQLITE_TEXT: {
+       int i,j,n;
+-      const char *zArg = sqlite3_value_text(argv[0]);
++      const unsigned char *zArg = sqlite3_value_text(argv[0]);
+       char *z;
+ 
+       for(i=n=0; zArg[i]; i++){ if( zArg[i]=='\'' ) n++; }
+@@ -692,7 +692,7 @@
+     zBuf[i] = zSrc[zBuf[i]%(sizeof(zSrc)-1)];
+   }
+   zBuf[n] = 0;
+-  sqlite3_result_text(context, zBuf, n, SQLITE_TRANSIENT);
++  sqlite3_result_text(context, (char*)zBuf, n, SQLITE_TRANSIENT);
+ }
+ #endif /* SQLITE_TEST */
+ 
+@@ -728,17 +728,17 @@
+   test_destructor_count_var++;
+   assert( nArg==1 );
+   if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
+-  len = sqlite3ValueBytes(argv[0], db->enc); 
++  len = sqlite3ValueBytes(argv[0], ENC(db)); 
+   zVal = sqliteMalloc(len+3);
+   zVal[len] = 0;
+   zVal[len-1] = 0;
+   assert( zVal );
+   zVal++;
+-  memcpy(zVal, sqlite3ValueText(argv[0], db->enc), len);
+-  if( db->enc==SQLITE_UTF8 ){
++  memcpy(zVal, sqlite3ValueText(argv[0], ENC(db)), len);
++  if( ENC(db)==SQLITE_UTF8 ){
+     sqlite3_result_text(pCtx, zVal, -1, destructor);
+ #ifndef SQLITE_OMIT_UTF16
+-  }else if( db->enc==SQLITE_UTF16LE ){
++  }else if( ENC(db)==SQLITE_UTF16LE ){
+     sqlite3_result_text16le(pCtx, zVal, -1, destructor);
+   }else{
+     sqlite3_result_text16be(pCtx, zVal, -1, destructor);
+@@ -776,7 +776,7 @@
+   char *zRet = sqliteMalloc(nArg*2);
+   if( !zRet ) return;
+   for(i=0; i<nArg; i++){
+-    char const *z = sqlite3_value_text(argv[i]);
++    char const *z = (char*)sqlite3_value_text(argv[i]);
+     if( z ){
+       char *zAux = sqlite3_get_auxdata(pCtx, i);
+       if( zAux ){
+@@ -807,7 +807,7 @@
+   int nArg,
+   sqlite3_value **argv
+ ){
+-  sqlite3_result_error(pCtx, sqlite3_value_text(argv[0]), 0);
++  sqlite3_result_error(pCtx, (char*)sqlite3_value_text(argv[0]), 0);
+ }
+ #endif /* SQLITE_TEST */
+ 
+@@ -817,25 +817,46 @@
+ */
+ typedef struct SumCtx SumCtx;
+ struct SumCtx {
+-  double sum;     /* Sum of terms */
+-  int cnt;        /* Number of elements summed */
+-  u8 seenFloat;   /* True if there has been any floating point value */
++  LONGDOUBLE_TYPE sum;    /* Sum of terms */
++  i64 cnt;                /* Number of elements summed */
++  u8 approx;              /* True if sum is approximate */
+ };
+ 
+ /*
+-** Routines used to compute the sum or average.
++** Routines used to compute the sum, average, and total.
++**
++** The SUM() function follows the (broken) SQL standard which means
++** that it returns NULL if it sums over no inputs.  TOTAL returns
++** 0.0 in that case.  In addition, TOTAL always returns a float where
++** SUM might return an integer if it never encounters a floating point
++** value.
++**
++** I am told that SUM() should raise an exception if it encounters
++** a integer overflow.  But after pondering this, I decided that 
++** behavior leads to brittle programs.  So instead, I have coded
++** SUM() to revert to using floating point if it encounters an
++** integer overflow.  The answer may not be exact, but it will be
++** close.  If the SUM() function returns an integer, the value is
++** exact.  If SUM() returns a floating point value, it means the
++** value might be approximated.
+ */
+ static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
+   SumCtx *p;
+   int type;
+   assert( argc==1 );
+   p = sqlite3_aggregate_context(context, sizeof(*p));
+-  type = sqlite3_value_type(argv[0]);
++  type = sqlite3_value_numeric_type(argv[0]);
+   if( p && type!=SQLITE_NULL ){
+-    p->sum += sqlite3_value_double(argv[0]);
+     p->cnt++;
+-    if( type==SQLITE_FLOAT ){
+-      p->seenFloat = 1;
++    if( type==SQLITE_INTEGER ){
++      p->sum += sqlite3_value_int64(argv[0]);
++      if( !p->approx ){
++        i64 iVal;
++        p->approx = p->sum!=(LONGDOUBLE_TYPE)(iVal = (i64)p->sum);
++      }
++    }else{
++      p->sum += sqlite3_value_double(argv[0]);
++      p->approx = 1;
+     }
+   }
+ }
+@@ -843,7 +864,7 @@
+   SumCtx *p;
+   p = sqlite3_aggregate_context(context, 0);
+   if( p && p->cnt>0 ){
+-    if( p->seenFloat ){
++    if( p->approx ){
+       sqlite3_result_double(context, p->sum);
+     }else{
+       sqlite3_result_int64(context, (i64)p->sum);
+@@ -857,25 +878,19 @@
+     sqlite3_result_double(context, p->sum/(double)p->cnt);
+   }
+ }
++static void totalFinalize(sqlite3_context *context){
++  SumCtx *p;
++  p = sqlite3_aggregate_context(context, 0);
++  sqlite3_result_double(context, p ? p->sum : 0.0);
++}
+ 
+ /*
+-** An instance of the following structure holds the context of a
+-** variance or standard deviation computation.
+-*/
+-typedef struct StdDevCtx StdDevCtx;
+-struct StdDevCtx {
+-  double sum;     /* Sum of terms */
+-  double sum2;    /* Sum of the squares of terms */
+-  int cnt;        /* Number of terms counted */
+-};
+-
+-/*
+ ** The following structure keeps track of state information for the
+ ** count() aggregate function.
+ */
+ typedef struct CountCtx CountCtx;
+ struct CountCtx {
+-  int n;
++  i64 n;
+ };
+ 
+ /*
+@@ -891,7 +906,7 @@
+ static void countFinalize(sqlite3_context *context){
+   CountCtx *p;
+   p = sqlite3_aggregate_context(context, 0);
+-  sqlite3_result_int(context, p ? p->n : 0);
++  sqlite3_result_int64(context, p ? p->n : 0);
+ }
+ 
+ /*
+@@ -1000,6 +1015,7 @@
+     { "min",    1, 0, 1, minmaxStep,   minMaxFinalize },
+     { "max",    1, 2, 1, minmaxStep,   minMaxFinalize },
+     { "sum",    1, 0, 0, sumStep,      sumFinalize    },
++    { "total",  1, 0, 0, sumStep,      totalFinalize    },
+     { "avg",    1, 0, 0, sumStep,      avgFinalize    },
+     { "count",  0, 0, 0, countStep,    countFinalize  },
+     { "count",  1, 0, 0, countStep,    countFinalize  },
+@@ -1012,7 +1028,7 @@
+       case 1: pArg = db; break;
+       case 2: pArg = (void *)(-1); break;
+     }
+-    sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg,
++    sqlite3CreateFunc(db, aFuncs[i].zName, aFuncs[i].nArg,
+         aFuncs[i].eTextRep, pArg, aFuncs[i].xFunc, 0, 0);
+     if( aFuncs[i].needCollSeq ){
+       FuncDef *pFunc = sqlite3FindFunction(db, aFuncs[i].zName, 
+@@ -1025,13 +1041,16 @@
+ #ifndef SQLITE_OMIT_ALTERTABLE
+   sqlite3AlterFunctions(db);
+ #endif
++#ifndef SQLITE_OMIT_PARSER
++  sqlite3AttachFunctions(db);
++#endif
+   for(i=0; i<sizeof(aAggs)/sizeof(aAggs[0]); i++){
+     void *pArg = 0;
+     switch( aAggs[i].argType ){
+       case 1: pArg = db; break;
+       case 2: pArg = (void *)(-1); break;
+     }
+-    sqlite3_create_function(db, aAggs[i].zName, aAggs[i].nArg, SQLITE_UTF8, 
++    sqlite3CreateFunc(db, aAggs[i].zName, aAggs[i].nArg, SQLITE_UTF8, 
+         pArg, 0, aAggs[i].xStep, aAggs[i].xFinalize);
+     if( aAggs[i].needCollSeq ){
+       FuncDef *pFunc = sqlite3FindFunction( db, aAggs[i].zName,
+@@ -1075,9 +1094,9 @@
+   }else{
+     pInfo = (struct compareInfo*)&likeInfoNorm;
+   }
+-  sqlite3_create_function(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0);
+-  sqlite3_create_function(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0);
+-  sqlite3_create_function(db, "glob", 2, SQLITE_UTF8, 
++  sqlite3CreateFunc(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0);
++  sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0);
++  sqlite3CreateFunc(db, "glob", 2, SQLITE_UTF8, 
+       (struct compareInfo*)&globInfo, likeFunc, 0,0);
+   setLikeOptFlag(db, "glob", SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE);
+   setLikeOptFlag(db, "like", 
+@@ -1099,7 +1118,7 @@
+   if( pExpr->pList->nExpr!=2 ){
+     return 0;
+   }
+-  pDef = sqlite3FindFunction(db, pExpr->token.z, pExpr->token.n, 2,
++  pDef = sqlite3FindFunction(db, (char*)pExpr->token.z, pExpr->token.n, 2,
+                              SQLITE_UTF8, 0);
+   if( pDef==0 || (pDef->flags & SQLITE_FUNC_LIKE)==0 ){
+     return 0;
+Index: sqlite/opcodes.c
+===================================================================
+--- amarok/src/sqlite/opcodes.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/opcodes.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -11,111 +11,111 @@
+  /*   7 */ "RowKey",
+  /*   8 */ "OpenWrite",
+  /*   9 */ "If",
+- /*  10 */ "ToInt",
+- /*  11 */ "Pop",
+- /*  12 */ "CollSeq",
+- /*  13 */ "OpenRead",
+- /*  14 */ "Expire",
+- /*  15 */ "AutoCommit",
+- /*  16 */ "IntegrityCk",
++ /*  10 */ "Pop",
++ /*  11 */ "CollSeq",
++ /*  12 */ "OpenRead",
++ /*  13 */ "Expire",
++ /*  14 */ "AutoCommit",
++ /*  15 */ "IntegrityCk",
++ /*  16 */ "Not",
+  /*  17 */ "Sort",
+  /*  18 */ "Function",
+  /*  19 */ "Noop",
+  /*  20 */ "Return",
+  /*  21 */ "NewRowid",
+- /*  22 */ "Variable",
+- /*  23 */ "String",
+- /*  24 */ "ParseSchema",
+- /*  25 */ "Close",
+- /*  26 */ "CreateIndex",
+- /*  27 */ "IsUnique",
+- /*  28 */ "IdxIsNull",
+- /*  29 */ "NotFound",
+- /*  30 */ "Int64",
+- /*  31 */ "MustBeInt",
+- /*  32 */ "Halt",
+- /*  33 */ "Rowid",
+- /*  34 */ "IdxLT",
+- /*  35 */ "AddImm",
+- /*  36 */ "Statement",
+- /*  37 */ "RowData",
+- /*  38 */ "MemMax",
+- /*  39 */ "Push",
+- /*  40 */ "NotExists",
+- /*  41 */ "MemIncr",
+- /*  42 */ "Gosub",
+- /*  43 */ "Integer",
+- /*  44 */ "ToNumeric",
+- /*  45 */ "MemInt",
+- /*  46 */ "Prev",
+- /*  47 */ "CreateTable",
+- /*  48 */ "Last",
+- /*  49 */ "IdxRowid",
+- /*  50 */ "MakeIdxRec",
+- /*  51 */ "ResetCount",
+- /*  52 */ "FifoWrite",
+- /*  53 */ "Callback",
+- /*  54 */ "ContextPush",
+- /*  55 */ "DropTrigger",
+- /*  56 */ "DropIndex",
+- /*  57 */ "IdxGE",
+- /*  58 */ "IdxDelete",
+- /*  59 */ "Vacuum",
+- /*  60 */ "MoveLe",
+- /*  61 */ "IfNot",
+- /*  62 */ "DropTable",
+- /*  63 */ "MakeRecord",
+- /*  64 */ "ToBlob",
+- /*  65 */ "Delete",
+- /*  66 */ "AggFinal",
+- /*  67 */ "Or",
+- /*  68 */ "And",
+- /*  69 */ "Not",
+- /*  70 */ "Dup",
+- /*  71 */ "Goto",
+- /*  72 */ "FifoRead",
+- /*  73 */ "IsNull",
+- /*  74 */ "NotNull",
+- /*  75 */ "Ne",
+- /*  76 */ "Eq",
+- /*  77 */ "Gt",
+- /*  78 */ "Le",
+- /*  79 */ "Lt",
+- /*  80 */ "Ge",
+- /*  81 */ "Clear",
+- /*  82 */ "BitAnd",
+- /*  83 */ "BitOr",
+- /*  84 */ "ShiftLeft",
+- /*  85 */ "ShiftRight",
+- /*  86 */ "Add",
+- /*  87 */ "Subtract",
+- /*  88 */ "Multiply",
+- /*  89 */ "Divide",
+- /*  90 */ "Remainder",
+- /*  91 */ "Concat",
+- /*  92 */ "Negative",
+- /*  93 */ "IdxGT",
+- /*  94 */ "BitNot",
+- /*  95 */ "String8",
++ /*  22 */ "IfMemNeg",
++ /*  23 */ "Variable",
++ /*  24 */ "String",
++ /*  25 */ "RealAffinity",
++ /*  26 */ "ParseSchema",
++ /*  27 */ "Close",
++ /*  28 */ "CreateIndex",
++ /*  29 */ "IsUnique",
++ /*  30 */ "IdxIsNull",
++ /*  31 */ "NotFound",
++ /*  32 */ "Int64",
++ /*  33 */ "MustBeInt",
++ /*  34 */ "Halt",
++ /*  35 */ "Rowid",
++ /*  36 */ "IdxLT",
++ /*  37 */ "AddImm",
++ /*  38 */ "Statement",
++ /*  39 */ "RowData",
++ /*  40 */ "MemMax",
++ /*  41 */ "Push",
++ /*  42 */ "NotExists",
++ /*  43 */ "MemIncr",
++ /*  44 */ "Gosub",
++ /*  45 */ "Integer",
++ /*  46 */ "MemInt",
++ /*  47 */ "Prev",
++ /*  48 */ "CreateTable",
++ /*  49 */ "Last",
++ /*  50 */ "IdxRowid",
++ /*  51 */ "MakeIdxRec",
++ /*  52 */ "ResetCount",
++ /*  53 */ "FifoWrite",
++ /*  54 */ "Callback",
++ /*  55 */ "ContextPush",
++ /*  56 */ "DropTrigger",
++ /*  57 */ "DropIndex",
++ /*  58 */ "IdxGE",
++ /*  59 */ "Or",
++ /*  60 */ "And",
++ /*  61 */ "IdxDelete",
++ /*  62 */ "Vacuum",
++ /*  63 */ "MoveLe",
++ /*  64 */ "IsNull",
++ /*  65 */ "NotNull",
++ /*  66 */ "Ne",
++ /*  67 */ "Eq",
++ /*  68 */ "Gt",
++ /*  69 */ "Le",
++ /*  70 */ "Lt",
++ /*  71 */ "Ge",
++ /*  72 */ "IfNot",
++ /*  73 */ "BitAnd",
++ /*  74 */ "BitOr",
++ /*  75 */ "ShiftLeft",
++ /*  76 */ "ShiftRight",
++ /*  77 */ "Add",
++ /*  78 */ "Subtract",
++ /*  79 */ "Multiply",
++ /*  80 */ "Divide",
++ /*  81 */ "Remainder",
++ /*  82 */ "Concat",
++ /*  83 */ "Negative",
++ /*  84 */ "DropTable",
++ /*  85 */ "BitNot",
++ /*  86 */ "String8",
++ /*  87 */ "MakeRecord",
++ /*  88 */ "Delete",
++ /*  89 */ "AggFinal",
++ /*  90 */ "Dup",
++ /*  91 */ "Goto",
++ /*  92 */ "TableLock",
++ /*  93 */ "FifoRead",
++ /*  94 */ "Clear",
++ /*  95 */ "IdxGT",
+  /*  96 */ "MoveLt",
+  /*  97 */ "VerifyCookie",
+  /*  98 */ "AggStep",
+  /*  99 */ "Pull",
+- /* 100 */ "ToText",
+- /* 101 */ "SetNumColumns",
+- /* 102 */ "AbsValue",
+- /* 103 */ "Transaction",
+- /* 104 */ "ContextPop",
+- /* 105 */ "Next",
+- /* 106 */ "IdxInsert",
+- /* 107 */ "Distinct",
+- /* 108 */ "Insert",
+- /* 109 */ "Destroy",
+- /* 110 */ "ReadCookie",
+- /* 111 */ "ForceInt",
+- /* 112 */ "LoadAnalysis",
+- /* 113 */ "OpenVirtual",
+- /* 114 */ "Explain",
++ /* 100 */ "SetNumColumns",
++ /* 101 */ "AbsValue",
++ /* 102 */ "Transaction",
++ /* 103 */ "ContextPop",
++ /* 104 */ "Next",
++ /* 105 */ "IdxInsert",
++ /* 106 */ "Distinct",
++ /* 107 */ "Insert",
++ /* 108 */ "Destroy",
++ /* 109 */ "ReadCookie",
++ /* 110 */ "ForceInt",
++ /* 111 */ "LoadAnalysis",
++ /* 112 */ "OpenVirtual",
++ /* 113 */ "Explain",
++ /* 114 */ "IfMemZero",
+  /* 115 */ "OpenPseudo",
+  /* 116 */ "Null",
+  /* 117 */ "Blob",
+@@ -125,16 +125,23 @@
+  /* 121 */ "MemMove",
+  /* 122 */ "MemNull",
+  /* 123 */ "Found",
+- /* 124 */ "NullRow",
+- /* 125 */ "NotUsed_125",
+- /* 126 */ "NotUsed_126",
++ /* 124 */ "Real",
++ /* 125 */ "HexBlob",
++ /* 126 */ "NullRow",
+  /* 127 */ "NotUsed_127",
+  /* 128 */ "NotUsed_128",
+  /* 129 */ "NotUsed_129",
+  /* 130 */ "NotUsed_130",
+  /* 131 */ "NotUsed_131",
+  /* 132 */ "NotUsed_132",
+- /* 133 */ "Real",
+- /* 134 */ "HexBlob",
++ /* 133 */ "NotUsed_133",
++ /* 134 */ "NotUsed_134",
++ /* 135 */ "NotUsed_135",
++ /* 136 */ "NotUsed_136",
++ /* 137 */ "ToText",
++ /* 138 */ "ToBlob",
++ /* 139 */ "ToNumeric",
++ /* 140 */ "ToInt",
++ /* 141 */ "ToReal",
+ };
+ #endif
+Index: sqlite/callback.c
+===================================================================
+--- amarok/src/sqlite/callback.c	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/sqlite/callback.c	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -13,7 +13,7 @@
+ ** This file contains functions used to access the internal hash tables
+ ** of user defined functions and collation sequences.
+ **
+-** $Id: callback.c,v 1.3 2005/08/14 01:20:38 drh Exp $
++** $Id: callback.c,v 1.12 2006/01/18 16:51:35 danielk1977 Exp $
+ */
+ 
+ #include "sqliteInt.h"
+@@ -29,17 +29,19 @@
+   if( db->xCollNeeded ){
+     char *zExternal = sqliteStrNDup(zName, nName);
+     if( !zExternal ) return;
+-    db->xCollNeeded(db->pCollNeededArg, db, (int)db->enc, zExternal);
++    db->xCollNeeded(db->pCollNeededArg, db, (int)ENC(db), zExternal);
+     sqliteFree(zExternal);
+   }
+ #ifndef SQLITE_OMIT_UTF16
+   if( db->xCollNeeded16 ){
+     char const *zExternal;
+-    sqlite3_value *pTmp = sqlite3GetTransientValue(db);
+-    sqlite3ValueSetStr(pTmp, -1, zName, SQLITE_UTF8, SQLITE_STATIC);
++    sqlite3_value *pTmp = sqlite3ValueNew();
++    sqlite3ValueSetStr(pTmp, nName, zName, SQLITE_UTF8, SQLITE_STATIC);
+     zExternal = sqlite3ValueText(pTmp, SQLITE_UTF16NATIVE);
+-    if( !zExternal ) return;
+-    db->xCollNeeded16(db->pCollNeededArg, db, (int)db->enc, zExternal);
++    if( zExternal ){
++      db->xCollNeeded16(db->pCollNeededArg, db, (int)ENC(db), zExternal);
++    }
++    sqlite3ValueFree(pTmp);
+   }
+ #endif
+ }
+@@ -90,14 +92,14 @@
+ 
+   p = pColl;
+   if( !p ){
+-    p = sqlite3FindCollSeq(db, db->enc, zName, nName, 0);
++    p = sqlite3FindCollSeq(db, ENC(db), zName, nName, 0);
+   }
+   if( !p || !p->xCmp ){
+     /* No collation sequence of this type for this encoding is registered.
+     ** Call the collation factory to see if it can supply us with one.
+     */
+     callCollNeeded(db, zName, nName);
+-    p = sqlite3FindCollSeq(db, db->enc, zName, nName, 0);
++    p = sqlite3FindCollSeq(db, ENC(db), zName, nName, 0);
+   }
+   if( p && !p->xCmp && synthCollSeq(db, p) ){
+     p = 0;
+@@ -128,6 +130,7 @@
+       pParse->nErr++;
+       return SQLITE_ERROR;
+     }
++    assert( p==pColl );
+   }
+   return SQLITE_OK;
+ }
+@@ -175,7 +178,8 @@
+       ** return the pColl pointer to be deleted (because it wasn't added
+       ** to the hash table).
+       */
+-      assert( !pDel || (sqlite3_malloc_failed && pDel==pColl) );
++      assert( !pDel ||
++              (sqlite3MallocFailed() && pDel==pColl) );
+       sqliteFree(pDel);
+     }
+   }
+@@ -197,7 +201,12 @@
+   int nName,
+   int create
+ ){
+-  CollSeq *pColl = findCollSeqEntry(db, zName, nName, create);
++  CollSeq *pColl;
++  if( zName ){
++    pColl = findCollSeqEntry(db, zName, nName, create);
++  }else{
++    pColl = db->pDfltColl;
++  }
+   assert( SQLITE_UTF8==1 && SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
+   assert( enc>=SQLITE_UTF8 && enc<=SQLITE_UTF16BE );
+   if( pColl ) pColl += enc-1;
+@@ -286,7 +295,7 @@
+   ** new entry to the hash table and return it.
+   */
+   if( createFlag && bestmatch<6 && 
+-      (pBest = sqliteMalloc(sizeof(*pBest)+nName)) ){
++      (pBest = sqliteMalloc(sizeof(*pBest)+nName))!=0 ){
+     pBest->nArg = nArg;
+     pBest->pNext = pFirst;
+     pBest->iPrefEnc = enc;
+Index: mediabrowser.cpp
+===================================================================
+--- amarok/src/mediabrowser.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/mediabrowser.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -17,6 +17,7 @@
+ #include "contextbrowser.h"
+ #include "debug.h"
+ #include "devicemanager.h"
++#include "hintlineedit.h"
+ #include "mediabrowser.h"
+ #include "medium.h"
+ #include "mediumpluginchooser.h"
+@@ -329,9 +330,10 @@
+     }
+ 
+     if ( newflag )
+-        amaroK::StatusBar::instance()->longMessageThreadSafe( i18n("amaroK has detected new portable media devices. "
+-                                                                   "Press the \"Manage Device Plugins...\" button in the "
+-                                                                   "Media Browser tab to select plugins for these devices.") );
++        amaroK::StatusBar::instance()->longMessageThreadSafe( i18n("amaroK has detected new portable media devices.\n"
++                                                                   "Press the \"Manage Plugins...\" suboption of the\n"
++                                                                   "Configure button in the Media Browser tab to\n"
++                                                                   "select plugins for these devices.") );
+ 
+     connect( m_toolbar->getButton(CONNECT),    SIGNAL( clicked() ),        SLOT( connectClicked() ) );
+     connect( m_toolbar->getButton(DISCONNECT), SIGNAL( clicked() ),        SLOT( disconnectClicked() ) );
+@@ -559,7 +561,9 @@
+ KURL
+ MediaBrowser::transcode( const KURL &src, const QString &filetype )
+ {
+-    if( !ScriptManager::instance()->transcodeScriptRunning() )
++    const ScriptManager* const sm = ScriptManager::instance();
++
++    if( sm->transcodeScriptRunning() == QString::null )
+     {
+         debug() << "cannot transcode with no transcoder registered" << endl;
+         return KURL();
+@@ -570,7 +574,7 @@
+     m_transcodedUrl = KURL();
+     ScriptManager::instance()->notifyTranscode( src.url(), filetype );
+ 
+-    while( m_waitForTranscode && ScriptManager::instance()->transcodeScriptRunning() )
++    while( m_waitForTranscode && sm->transcodeScriptRunning() != QString::null )
+     {
+         usleep( 10000 );
+         kapp->processEvents( 100 );
+@@ -1049,6 +1053,7 @@
+     KURL::List urls = nodeBuildDragList( 0 );
+     debug() << urls.first().path() << endl;
+     KURLDrag* d = new KURLDrag( urls, this );
++    d->setPixmap(CollectionDB::createDragPixmap(urls), QPoint(CollectionDB::DRAGPIXMAP_OFFSET_X,CollectionDB::DRAGPIXMAP_OFFSET_Y));
+     d->dragCopy();
+ }
+ 
+@@ -1492,9 +1497,9 @@
+     connect( m_configPluginCombo, SIGNAL(activated( int )), SLOT(configSelectPlugin( int )) );
+ 
+     QLabel *connectLabel = 0;
+-    QLineEdit *connectEdit = 0;
++    HintLineEdit *connectEdit = 0;
+     QLabel *disconnectLabel = 0;
+-    QLineEdit *disconnectEdit = 0;
++    HintLineEdit *disconnectEdit = 0;
+     QCheckBox *transcodeCheck = 0;
+     QButtonGroup *transcodeGroup = 0;
+     QRadioButton *transcodeAlways = 0;
+@@ -1507,14 +1512,16 @@
+         // pre-connect/post-disconnect (mount/umount)
+         connectLabel = new QLabel( m_configBox );
+         connectLabel->setText( i18n( "Pre-&connect command:" ) );
+-        connectEdit = new QLineEdit( currentDevice()->m_preconnectcmd, m_configBox );
++        connectEdit = new HintLineEdit( currentDevice()->m_preconnectcmd, m_configBox );
++        connectEdit->setHint( i18n( "Example: mount %d" ) );
+         connectLabel->setBuddy( connectEdit );
+         QToolTip::add( connectEdit, i18n( "Set a command to be run before connecting to your device (e.g. a mount command) here.\n%d is replaced by the device node, %m by the mount point.\nEmpty commands are not executed." ) );
+ 
+         disconnectLabel = new QLabel( m_configBox );
+         disconnectLabel->setText( i18n( "Post-&disconnect command:" ) );
+-        disconnectEdit = new QLineEdit( currentDevice()->m_postdisconnectcmd, m_configBox );
++        disconnectEdit = new HintLineEdit( currentDevice()->m_postdisconnectcmd, m_configBox );
+         disconnectLabel->setBuddy( disconnectEdit );
++        disconnectEdit->setHint( i18n( "Example: eject %d" ) );
+         QToolTip::add( disconnectEdit, i18n( "Set a command to be run after disconnecting from your device (e.g. an eject command) here.\n%d is replaced by the device node, %m by the mount point.\nEmpty commands are not executed." ) );
+ 
+         // transcode
+@@ -1693,13 +1700,13 @@
+     QString text = i18n( "1 track in queue", "%n tracks in queue", m_queue->childCount() );
+     if(m_queue->childCount() > 0)
+     {
+-        text += " (" + KIO::convertSize( m_queue->totalSize() ) + ")";
++        text += i18n(" (%1)").arg( KIO::convertSize( m_queue->totalSize() ) );
+     }
+ 
+     KIO::filesize_t total, avail;
+     if( currentDevice() && currentDevice()->getCapacity(&total, &avail) )
+     {
+-        text += " - " + i18n( "%1 of %2 available" ).arg( KIO::convertSize( avail ) ).arg( KIO::convertSize( total ) );
++        text += i18n( " - %1 of %2 available" ).arg( KIO::convertSize( avail ) ).arg( KIO::convertSize( total ) );
+ 
+         m_stats->m_used = total-avail;
+         m_stats->m_total = total;
+@@ -1773,6 +1780,9 @@
+     , m_view( NULL )
+     , m_medium( NULL )
+     , m_transferDir( QString::null )
++    , m_firstSort( QString::null )
++    , m_secondSort( QString::null )
++    , m_thirdSort( QString::null )
+     , m_wait( false )
+     , m_requireMount( false )
+     , m_hasPodcast( false )
+@@ -2064,7 +2074,8 @@
+                 updateButtons();
+         }
+     }
+-    currentDevice()->m_transferDir = QString::null;
++    if( currentDevice()->m_medium )
++        currentDevice()->m_transferDir = currentDevice()->m_medium->mountPoint();
+ }
+ 
+ void
+@@ -2346,7 +2357,10 @@
+ MediaDevice::transferFiles()
+ {
+     if( !lockDevice( true ) )
++    {
++        setSpacesToUnderscores( false );
+         return;
++    }
+ 
+     setCancelled( false );
+ 
+@@ -2496,6 +2510,7 @@
+     unlockDevice();
+     fileTransferFinished();
+ 
++    setSpacesToUnderscores( false );
+     m_parent->updateButtons();
+     m_transferring = false;
+ 
+@@ -2985,9 +3000,9 @@
+     {
+         MediaItem *item = static_cast<MediaItem *>(it);
+ 
+-        if( !m_parent->currentDevice()
++        if( item && ( !m_parent->currentDevice()
+                 || !m_parent->currentDevice()->isConnected()
+-                || !m_parent->currentDevice()->trackExists(*item->bundle()) )
++                || !m_parent->currentDevice()->trackExists(*item->bundle()) ) )
+             total += ((item->size()+1023)/1024)*1024;
+     }
+ 
+Index: engine/mas/amarok_masengine_plugin.desktop
+===================================================================
+--- amarok/src/engine/mas/amarok_masengine_plugin.desktop	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/engine/mas/amarok_masengine_plugin.desktop	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -2,6 +2,7 @@
+ Type=Service
+ Name=MAS Engine
+ Name[bg]=Система MAS
++Name[bn]=এম-এ-এস ইঞ্জিন
+ Name[br]=Keflusker MAS
+ Name[cs]=MAS systém
+ Name[da]=MAS-motor
+@@ -38,6 +39,7 @@
+ Name[zh_TW]=MAS 解碼引擎
+ Comment=Plugin for amaroK
+ Comment[bg]=Приставка за amaroK
++Comment[bn]=আমারক-এর জন্য প্লাগিন
+ Comment[br]=Lugent evit amaroK
+ Comment[cs]=Modul pro amaroK
+ Comment[de]=Modul für amaroK
+@@ -83,7 +85,7 @@
+ X-KDE-amaroK-email=rolandg at web.de
+ X-KDE-amaroK-rank=100
+ X-KDE-amaroK-version=1
+-X-KDE-amaroK-framework-version=16
++X-KDE-amaroK-framework-version=18
+ 
+ 
+ 
+Index: engine/void/amarok_void-engine_plugin.desktop
+===================================================================
+--- amarok/src/engine/void/amarok_void-engine_plugin.desktop	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/engine/void/amarok_void-engine_plugin.desktop	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -2,6 +2,7 @@
+ Type=Service
+ Name=<no engine>
+ Name[bg]=<без система>
++Name[bn]=<কোনও ইঞ্জিন নয়>
+ Name[br]=<keflusker ebet>
+ Name[cs]=<žádný systém>
+ Name[da]=<ingen motor>
+@@ -37,6 +38,7 @@
+ X-KDE-Library=libamarok_void-engine_plugin
+ Comment=Plugin for amaroK
+ Comment[bg]=Приставка за amaroK
++Comment[bn]=আমারক-এর জন্য প্লাগিন
+ Comment[br]=Lugent evit amaroK
+ Comment[cs]=Modul pro amaroK
+ Comment[de]=Modul für amaroK
+@@ -81,6 +83,6 @@
+ X-KDE-amaroK-email=max.howell at methylblue.com
+ X-KDE-amaroK-rank=1
+ X-KDE-amaroK-version=1
+-X-KDE-amaroK-framework-version=16
++X-KDE-amaroK-framework-version=18
+ 
+ 
+Index: engine/akode/amarok_aKode-engine.desktop
+===================================================================
+--- amarok/src/engine/akode/amarok_aKode-engine.desktop	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/engine/akode/amarok_aKode-engine.desktop	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -2,6 +2,7 @@
+ Type=Service
+ Name=aKode Engine
+ Name[bg]=Система aKode
++Name[bn]=aKode ইঞ্জিন
+ Name[br]=Keflusker aKode
+ Name[cs]=aKode
+ Name[da]=aKode-motor
+@@ -36,6 +37,7 @@
+ X-KDE-Library=libamarok_aKode-engine
+ Comment=aKode audio-engine for amaroK
+ Comment[bg]=Аудио система aKode за amaroK
++Comment[bn]=আমারক-এর জন্য aKode অডিও ইঞ্জিন
+ Comment[br]=Keflusker klevet aKode evit amaroK
+ Comment[cs]=Zvukový modul aKode pro amaroK
+ Comment[da]=aKode lyd-motor for amaroK
+@@ -74,5 +76,5 @@
+ X-KDE-amaroK-email=kde at carewolf.com
+ X-KDE-amaroK-rank=2
+ X-KDE-amaroK-version=1
+-X-KDE-amaroK-framework-version=16
++X-KDE-amaroK-framework-version=18
+ 
+Index: engine/xine/amarok_xine-engine.desktop
+===================================================================
+--- amarok/src/engine/xine/amarok_xine-engine.desktop	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/engine/xine/amarok_xine-engine.desktop	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -2,6 +2,7 @@
+ Type=Service
+ Name=xine Engine
+ Name[bg]=Система Xine
++Name[bn]=জাইন ইঞ্জিন
+ Name[br]=Keflusker xine
+ Name[cs]=xine
+ Name[de]=xine
+@@ -40,6 +41,7 @@
+ X-KDE-Library=libamarok_xine-engine
+ Comment=Plugin for amaroK
+ Comment[bg]=Приставка за amaroK
++Comment[bn]=আমারক-এর জন্য প্লাগিন
+ Comment[br]=Lugent evit amaroK
+ Comment[cs]=Modul pro amaroK
+ Comment[de]=Modul für amaroK
+@@ -84,6 +86,6 @@
+ X-KDE-amaroK-email=max.howell at methylblue.com
+ X-KDE-amaroK-rank=255
+ X-KDE-amaroK-version=1
+-X-KDE-amaroK-framework-version=16
++X-KDE-amaroK-framework-version=18
+ 
+ 
+Index: engine/nmm/amarok_nmmengine_plugin.desktop
+===================================================================
+--- amarok/src/engine/nmm/amarok_nmmengine_plugin.desktop	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/engine/nmm/amarok_nmmengine_plugin.desktop	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -2,6 +2,7 @@
+ Type=Service
+ Name=NMM Engine
+ Name[bg]=Система NMM
++Name[bn]=এনএমএম ইঞ্জিন
+ Name[br]=Keflusker NMM
+ Name[cs]=NMM
+ Name[de]=NMM
+@@ -39,6 +40,7 @@
+ X-KDE-Library=libamarok_nmmengine_plugin
+ Comment=amaroK plugin
+ Comment[bg]=Приставка за amaroK
++Comment[bn]=আমারক প্লাগিন
+ Comment[br]=Lugent amaroK
+ Comment[cs]=amaroK modul
+ Comment[da]=Plugin for amaroK
+@@ -84,6 +86,6 @@
+ X-KDE-amaroK-email=nmm-dev at graphics.cs.uni-sb.de
+ X-KDE-amaroK-rank=50
+ X-KDE-amaroK-version=1
+-X-KDE-amaroK-framework-version=16
++X-KDE-amaroK-framework-version=18
+ 
+ 
+Index: engine/arts/amarok_artsengine_plugin.desktop
+===================================================================
+--- amarok/src/engine/arts/amarok_artsengine_plugin.desktop	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/engine/arts/amarok_artsengine_plugin.desktop	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -2,6 +2,7 @@
+ Type=Service
+ Name=aRts Engine
+ Name[bg]=Система aRts
++Name[bn]=আর্টস ইঞ্জিন
+ Name[br]=Keflusker aRts
+ Name[cs]=aRts
+ Name[da]=aRts-motor
+@@ -40,6 +41,7 @@
+ X-KDE-Library=libamarok_artsengine_plugin
+ Comment=Plugin for amaroK
+ Comment[bg]=Приставка за amaroK
++Comment[bn]=আমারক-এর জন্য প্লাগিন
+ Comment[br]=Lugent evit amaroK
+ Comment[cs]=Modul pro amaroK
+ Comment[de]=Modul für amaroK
+@@ -84,7 +86,7 @@
+ X-KDE-amaroK-email=markey at web.de
+ X-KDE-amaroK-rank=50
+ X-KDE-amaroK-version=1
+-X-KDE-amaroK-framework-version=16
++X-KDE-amaroK-framework-version=18
+ 
+ 
+ 
+Index: engine/helix/amarok_helixengine_plugin.desktop
+===================================================================
+--- amarok/src/engine/helix/amarok_helixengine_plugin.desktop	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/engine/helix/amarok_helixengine_plugin.desktop	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -2,6 +2,7 @@
+ Type=Service
+ Name=Helix Engine
+ Name[bg]=Система Helix
++Name[bn]=হেলিক্স ইঞ্জিন
+ Name[br]=Keflusker Helix
+ Name[da]=Helix motor
+ Name[de]=Helix
+@@ -35,6 +36,7 @@
+ X-KDE-Library=libamarok_helixengine_plugin
+ Comment=Plugin for amaroK
+ Comment[bg]=Приставка за amaroK
++Comment[bn]=আমারক-এর জন্য প্লাগিন
+ Comment[br]=Lugent evit amaroK
+ Comment[cs]=Modul pro amaroK
+ Comment[de]=Modul für amaroK
+@@ -79,7 +81,7 @@
+ X-KDE-amaroK-email=paul at cifarelli.net
+ X-KDE-amaroK-rank=75
+ X-KDE-amaroK-version=1
+-X-KDE-amaroK-framework-version=16
++X-KDE-amaroK-framework-version=18
+ 
+ 
+ 
+Index: engine/gst/amarok_gstengine_plugin.desktop
+===================================================================
+--- amarok/src/engine/gst/amarok_gstengine_plugin.desktop	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/engine/gst/amarok_gstengine_plugin.desktop	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -2,6 +2,7 @@
+ Type=Service
+ Name=GStreamer Engine
+ Name[bg]=Система GStreamer
++Name[bn]=জিস্ট্রীমার ইঞ্জিন
+ Name[br]=Keflusker GStreamer
+ Name[cs]=GStreamer
+ Name[da]=GStreamer-motor
+@@ -40,6 +41,7 @@
+ X-KDE-Library=libamarok_gstengine_plugin
+ Comment=Plugin for amaroK
+ Comment[bg]=Приставка за amaroK
++Comment[bn]=আমারক-এর জন্য প্লাগিন
+ Comment[br]=Lugent evit amaroK
+ Comment[cs]=Modul pro amaroK
+ Comment[de]=Modul für amaroK
+@@ -84,6 +86,6 @@
+ X-KDE-amaroK-email=markey at web.de
+ X-KDE-amaroK-rank=254
+ X-KDE-amaroK-version=1
+-X-KDE-amaroK-framework-version=16
++X-KDE-amaroK-framework-version=18
+ 
+ 
+Index: engine/kdemm/amarok_kdemmengine_plugin.desktop
+===================================================================
+--- amarok/src/engine/kdemm/amarok_kdemmengine_plugin.desktop	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/engine/kdemm/amarok_kdemmengine_plugin.desktop	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -2,6 +2,7 @@
+ Type=Service
+ Name=KDEMM Engine
+ Name[bg]=Система KDEMM
++Name[bn]=কেডিই-এমএম ইঞ্জিন
+ Name[br]=Keflusker KDEMM
+ Name[cs]=KDEMM systém
+ Name[da]=KDEMM-motor
+@@ -38,6 +39,7 @@
+ Name[zh_TW]=KDEMM 引擎
+ Comment=Plugin for amaroK
+ Comment[bg]=Приставка за amaroK
++Comment[bn]=আমারক-এর জন্য প্লাগিন
+ Comment[br]=Lugent evit amaroK
+ Comment[cs]=Modul pro amaroK
+ Comment[de]=Modul für amaroK
+@@ -83,7 +85,7 @@
+ X-KDE-amaroK-email=rolandg at web.de
+ X-KDE-amaroK-rank=100
+ X-KDE-amaroK-version=1
+-X-KDE-amaroK-framework-version=16
++X-KDE-amaroK-framework-version=18
+ 
+ 
+ 
+Index: engine/gst10/amarok_gst10engine_plugin.desktop
+===================================================================
+--- amarok/src/engine/gst10/amarok_gst10engine_plugin.desktop	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/engine/gst10/amarok_gst10engine_plugin.desktop	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -2,6 +2,7 @@
+ Type=Service
+ Name=GStreamer 0.10 Engine
+ Name[bg]=Система GStreamer 0.10
++Name[bn]=জিস্ট্রীমার ০.১০ ইঞ্জিন
+ Name[br]=Keflusker GStreamer 0.10
+ Name[cs]=GStreamer 0.10
+ Name[da]=GStreamer-0.10-motor
+@@ -10,6 +11,7 @@
+ Name[fi]=GStreamer 0.10
+ Name[fr]=Moteur GStreamer 0.10
+ Name[ga]=Inneall GStreamer 0.10
++Name[it]=Motore GStreamer 0.10
+ Name[ja]=GStreamer 0.10 エンジン
+ Name[pa]=ਜੀਸਟਰੀਮਰ 0.10 ਇੰਜਣ
+ Name[pt]=Motor GStreamer 0.10
+@@ -18,9 +20,11 @@
+ Name[sv]=Gstreamer 0.10-gränssnitt
+ Name[tr]=GStreamer 0.10 Motoru
+ Name[xx]=xxGStreamer 0.10 Enginexx
++Name[zh_CN]=GStreamer 0.10 引擎
+ X-KDE-Library=libamarok_gst10engine_plugin
+ Comment=Plugin for amaroK
+ Comment[bg]=Приставка за amaroK
++Comment[bn]=আমারক-এর জন্য প্লাগিন
+ Comment[br]=Lugent evit amaroK
+ Comment[cs]=Modul pro amaroK
+ Comment[de]=Modul für amaroK
+@@ -65,6 +69,6 @@
+ X-KDE-amaroK-email=markey at web.de
+ X-KDE-amaroK-rank=254
+ X-KDE-amaroK-version=1
+-X-KDE-amaroK-framework-version=16
++X-KDE-amaroK-framework-version=18
+ 
+ 
+Index: engine/gst10/gstengine.cpp
+===================================================================
+--- amarok/src/engine/gst10/gstengine.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/engine/gst10/gstengine.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -114,6 +114,7 @@
+ 	 }
+ 	 default: ;
+       }
++      gst_message_unref( msg );
+       return GST_BUS_DROP;
+ }
+ 
+@@ -131,6 +132,8 @@
+     }
+ 
+     gst_pad_link( pad, audiopad );
++
++    gst_object_unref( audiopad );
+ }
+ 
+ /*
+Index: playlistwindow.cpp
+===================================================================
+--- amarok/src/playlistwindow.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/playlistwindow.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -729,7 +729,7 @@
+         }
+ 
+         if( useArtist && useAlbum )
+-            title = artist + " - " + album;
++            title = i18n("%1 - %2").arg( artist, album );
+         else if( useArtist )
+             title = artist;
+         else if( useAlbum )
+@@ -933,6 +933,9 @@
+     KPushButton* repopButton = new KPushButton( i18n("Repopulate"), this, "DynamicModeRepopulate" );
+     connect( repopButton, SIGNAL(clicked()), Party::instance(), SLOT(repopulate()) );
+ 
++    KPushButton* disableButton = new KPushButton( i18n("Turn Off"), this, "DynamicModeDisable" );
++    connect( disableButton, SIGNAL(clicked()), Party::instance(), SLOT(disable()) );
++
+     connect(Party::instance(), SIGNAL(titleChanged(const QString&)), this, SLOT( changeTitle(const QString&)));
+     toggledDynamic( AmarokConfig::dynamicMode() );
+ }
+Index: pluginmanager.h
+===================================================================
+--- amarok/src/pluginmanager.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/pluginmanager.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -28,7 +28,7 @@
+ {
+     public:
+         /** Bump this number whenever the plugin framework gets incompatible with older versions */
+-        static const int FrameworkVersion = 16;
++        static const int FrameworkVersion = 18;
+ 
+         /**
+          * It will return a list of services that match your
+Index: transferdialog.h
+===================================================================
+--- amarok/src/transferdialog.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/transferdialog.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -14,6 +14,7 @@
+ 
+ #include "mediabrowser.h"
+ 
++#include <qcheckbox.h>
+ #include <qmap.h>
+ #include <qsignalmapper.h>
+ #include <kdialogbase.h>
+@@ -42,8 +43,10 @@
+         void slotCancel();
+         void sort1_activated( int index );
+         void sort2_activated( int index );
++        void convertSpaces_toggled( bool on );
+ 
+     private:
++        MediaDevice                     *m_dev;
+         bool                             m_accepted;
+         KComboBox                       *m_sort1;
+         KComboBox                       *m_sort2;
+Index: playlistitem.cpp
+===================================================================
+--- amarok/src/playlistitem.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/playlistitem.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -200,6 +200,8 @@
+         case Genre:
+         case Comment:
+             return exactText( column ); //HACK
++        case Rating:
++            return isEditing( column ) ? exactText( column ) : prettyText( column );
+         default:
+         {
+             if( column != Title && isEditing( column ) )
+@@ -994,8 +996,7 @@
+ {
+     if( AmarokConfig::entireAlbums() )
+     {
+-        listView()->m_total -= m_album->total;
+-        Q_INT64 total = m_album->total * m_album->tracks.count();
++        const uint prevCount = m_album->tracks.count();
+         if( !track() || !m_album->tracks.count() || ( m_album->tracks.getLast()->track() && m_album->tracks.getLast()->track() < track() ) )
+             m_album->tracks.append( this );
+         else
+@@ -1005,11 +1006,14 @@
+                     m_album->tracks.insert( i, this );
+                     break;
+                 }
++        const Q_INT64 prevTotal = m_album->total;
++        Q_INT64 total = m_album->total * prevCount;
+         total += totalIncrementAmount();
+         m_album->total = Q_INT64( double( total + 0.5 ) / m_album->tracks.count() );
+-        listView()->m_total += m_album->total;
++        if( listView()->m_prevAlbums.findRef( m_album ) == -1 )
++            listView()->m_total = listView()->m_total - prevTotal + m_album->total;
+     }
+-    else
++    else if( listView()->m_prevTracks.findRef( this ) == -1 )
+         listView()->m_total += totalIncrementAmount();
+ }
+ 
+@@ -1017,14 +1021,16 @@
+ {
+     if( AmarokConfig::entireAlbums() )
+     {
+-        listView()->m_total -= m_album->total;
++        const Q_INT64 prevTotal = m_album->total;
+         Q_INT64 total = m_album->total * m_album->tracks.count();
+         m_album->tracks.removeRef( this );
+         total -= totalIncrementAmount();
+         m_album->total = Q_INT64( double( total + 0.5 ) / m_album->tracks.count() );
+-        listView()->m_total += m_album->total;
++        if( listView()->m_prevAlbums.findRef( m_album ) == -1 )
++            listView()->m_total = listView()->m_total - prevTotal + m_album->total;
+     }
+-    listView()->m_total -= totalIncrementAmount();
++    else if( listView()->m_prevTracks.findRef( this ) == -1 )
++        listView()->m_total -= totalIncrementAmount();
+ }
+ 
+ int PlaylistItem::totalIncrementAmount() const
+Index: images/more_albums.png
+===================================================================
+Cannot display: file marked as a binary type.
+svn:mime-type = application/octet-stream
+
+Property changes on: images/more_albums.png
+___________________________________________________________________
+Name: svn:mime-type
+   + application/octet-stream
+
+Index: images/nocover.png
+===================================================================
+Cannot display: file marked as a binary type.
+svn:mime-type = image/png
+Index: images/nocover.svg
+===================================================================
+Cannot display: file marked as a binary type.
+svn:mime-type = image/svg+xml
+Index: images/splash_screen.png
+===================================================================
+Cannot display: file marked as a binary type.
+svn:mime-type = image/png
+Index: playlistbrowseritem.cpp
+===================================================================
+--- amarok/src/playlistbrowseritem.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/playlistbrowseritem.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -1042,6 +1042,7 @@
+         , m_updating( false )
+         , m_new( false )
+         , m_hasProblem( false )
++        , m_settings( 0 )
+         , m_last( 0 )
+         , m_parent( static_cast<PlaylistCategory*>(parent) )
+ {
+@@ -1064,6 +1065,7 @@
+     , m_new( false )
+     , m_hasProblem( false )
+     , m_channelSettings( channelSettings )
++    , m_settings( 0 )
+     , m_last( 0 )
+     , m_parent( static_cast<PlaylistCategory*>(parent) )
+ {
+@@ -1081,6 +1083,7 @@
+                                 const KURL &url, const QDomNode &channelSettings, const QDomDocument &xmlDefinition )
+     : PlaylistBrowserEntry( parent, after )
+     , m_url( url )
++    , m_doc( xmlDefinition )
+     , m_loading1( QPixmap( locate("data", "amarok/images/loading1.png" ) ) )
+     , m_loading2( QPixmap( locate("data", "amarok/images/loading2.png" ) ) )
+     , m_fetching( false )
+@@ -1088,10 +1091,11 @@
+     , m_new( false )
+     , m_hasProblem( false )
+     , m_channelSettings( channelSettings )
++    , m_settings( 0 )
+     , m_last( 0 )
+     , m_parent( static_cast<PlaylistCategory*>(parent) )
+ {
+-    QDomNode type = xmlDefinition.namedItem("rss");
++    QDomNode type = m_doc.namedItem("rss");
+     if( !type.isNull() )
+         setXml( type.namedItem("channel"), RSS );
+     else
+@@ -1103,6 +1107,20 @@
+     setPixmap( 0, SmallIcon("player_playlist_2") );
+ }
+ 
++void PodcastChannel::createSettings()
++{
++    if( m_channelSettings.isNull() ) //no channelsettings found, create new PodcastSettings based on settings from parent
++    {
++        m_settings = new PodcastSettings(
++                PlaylistBrowser::instance()->getPodcastSettings( m_parent )
++                ,  m_title );
++    }
++    else
++    {
++        m_settings = new PodcastSettings( m_channelSettings, m_title );
++    }
++}
++
+ void
+ PodcastChannel::configure()
+ {
+@@ -1136,7 +1154,7 @@
+             // get a list of the urls of already downloaded items
+             while( item )
+             {
+-                if( item->hasDownloaded() )
++                if( item->isOnDisk() )
+                     copyList << item->localUrl();
+ 
+                 item->setLocalUrlBase( m_settings->m_saveLocation.prettyURL() );
+@@ -1166,6 +1184,8 @@
+             downloadChildren();
+         }
+     }
++
++    delete dialog;
+ }
+ 
+ void
+@@ -1175,7 +1195,7 @@
+     while( item )
+     {
+         #define item static_cast<PodcastItem*>(item)
+-        if( !item->hasDownloaded() )
++        if( item->isNew() )
+             m_podcastDownloadQueue.append( item );
+         #undef  item
+ 
+@@ -1240,19 +1260,15 @@
+         amaroK::StatusBar::instance()->shortMessage( i18n( "Unable to connect to Podcast server." ) );
+         debug() << "Unable to retrieve podcast information. KIO Error: " << job->error() << endl;
+ 
+-        m_title.isEmpty() ?
+-            setText( 0, m_url.prettyURL() ) :
+-                setText( 0, m_title );
++        if( m_title.isEmpty() )
++            m_title = m_url.prettyURL();
++        setText( 0, m_title );
+ 
+-        if( !m_updating ) // podcastchannel is created, therefore m_settings doesn't exist yet
+-            if( m_channelSettings.isNull() ) //no channelsettings found, create new PodcastSettings based on settings from parent
+-            {
+-                m_settings = new PodcastSettings(
+-                        PlaylistBrowser::instance()->getPodcastSettings( m_parent )
+-                        , m_title );
+-            }
+-        else
+-            m_settings = new PodcastSettings( m_channelSettings, m_title );
++        if( m_settings == 0)
++        {
++            debug() << "creating settings for " << m_title << endl;
++            createSettings();
++        }
+ 
+         setPixmap( 0, SmallIcon("cancel") );
+ 
+@@ -1270,21 +1286,36 @@
+         if( m_title.isEmpty() )
+             setText( 0, m_url.prettyURL() );
+ 
++        if( m_settings == 0)
++        {
++            debug() << "creating settings for " << m_title << endl;
++            createSettings();
++        }
++
+         setPixmap( 0, SmallIcon("cancel") );
+         return;
+     }
++
++    if(m_doc.toString().isEmpty())
++        m_doc = d.cloneNode().toDocument();
++
+     QDomNode type = d.namedItem("rss");
+     if( type.isNull() || type.toElement().attribute( "version" ) != "2.0" )
+     {
+         type = d.namedItem("feed");
+         if( type.isNull() )
+         {
+-            //FIXME: Update error message after string freeze
+-            amaroK::StatusBar::instance()->shortMessage( i18n("Sorry, only RSS 2.0 feeds for podcasts!") );
++            amaroK::StatusBar::instance()->shortMessage( i18n("Sorry, only RSS 2.0 or Atom feeds for podcasts!") );
+ 
+             if( m_title.isEmpty() )
+                 setText( 0, m_url.prettyURL() );
+ 
++            if( m_settings == 0)
++            {
++                debug() << "creating settings for " << m_title << endl;
++                createSettings();
++            }
++
+             setPixmap( 0, SmallIcon("cancel") );
+             return;
+         }
+@@ -1298,7 +1329,10 @@
+     else
+         setXml( type.namedItem("channel"), RSS );
+ 
+-    ///BEGIN Cache the xml
++}
++
++void PodcastChannel::saveCache( const QDomDocument &doc )
++{
+     QFile file( amaroK::saveLocation( "podcasts/" ) +  m_cache );
+ 
+     QTextStream stream( &file );
+@@ -1306,8 +1340,7 @@
+     if( !file.open( IO_WriteOnly ) ) return;
+ 
+     stream.setEncoding( QTextStream::UnicodeUTF8 );
+-    stream << d.toString();
+-    ///END Cache the xml
++    stream << doc.toString();
+ }
+ 
+ void
+@@ -1352,18 +1385,10 @@
+     const bool isAtom = ( feedType == ATOM );
+ 
+     m_title = xml.namedItem( "title" ).toElement().text();
++    createSettings();
++
+     setText( 0, m_title );
+ 
+-    if( !m_updating ) // podcastchannel is created, therefore m_settings doesn't exist yet
+-        if( m_channelSettings.isNull() ) //no channelsettings found, create new PodcastSettings based on settings from parent
+-        {
+-            m_settings = new PodcastSettings(
+-                    PlaylistBrowser::instance()->getPodcastSettings( m_parent )
+-                    , m_title );
+-        }
+-        else
+-            m_settings = new PodcastSettings( m_channelSettings, m_title );
+-
+     m_cache = KURL::encode_string( m_title + "_" + m_url.fileName() );
+ 
+     QString weblink = QString::null;
+@@ -1397,6 +1422,7 @@
+     {
+         if( m_updating )
+         {
++            QDomNode node;
+             // podcasts get inserted in a chronological order,
+             // no need to continue traversing, we must have them already
+             if( first && first->hasXml( n, feedType ) )
+@@ -1412,7 +1438,9 @@
+                 {
+                     if( nodes.toElement().attribute("rel") == "enclosure" )
+                     {
+-                        updatingLast = new PodcastItem( this, updatingLast, n.toElement(), feedType );
++                        QDomNode feed = m_doc.namedItem("feed");
++                        node = feed.insertBefore( n.cloneNode(), feed.namedItem("entry") );
++                        updatingLast = new PodcastItem( this, updatingLast, node.toElement(), feedType );
+                         updatingLast->setNew();
+                         break;
+                     }
+@@ -1420,7 +1448,9 @@
+             }
+             else if( !n.namedItem( "enclosure" ).toElement().attribute( "url" ).isEmpty() )
+             {
+-                updatingLast = new PodcastItem( this, updatingLast, n.toElement(), feedType );
++                QDomNode channel = m_doc.namedItem("rss").namedItem("channel");
++                node = channel.insertBefore(n.cloneNode(), channel.namedItem("item") );
++                updatingLast = new PodcastItem( this, updatingLast, node.toElement(), feedType );
+                 updatingLast->setNew();
+             }
+         }
+@@ -1438,7 +1468,7 @@
+                     if( nodes.toElement().attribute("rel") == "enclosure" )
+                     {
+                         updatingLast = new PodcastItem( this, updatingLast, n.toElement(), feedType );
+-                        updatingLast->setNew();
++//                         updatingLast->setNew();
+                         break;
+                     }
+                 }
+@@ -1463,6 +1493,8 @@
+         setNew();
+         amaroK::StatusBar::instance()->shortMessage( i18n("New podcasts have been retrieved!") );
+     }
++
++    saveCache();
+ }
+ 
+ void
+@@ -1504,7 +1536,7 @@
+         if( m_last && m_last != firstChild() )
+             newLast = (PodcastItem *)m_last->itemAbove();
+ 
+-        if( m_last->hasDownloaded() )
++        if( m_last->isOnDisk() )
+             urls.append( m_last->localUrl() );
+ 
+         delete m_last;
+@@ -1528,46 +1560,53 @@
+         attr.appendChild( t );
+         i.appendChild( attr );
+ 
+-        attr = doc.createElement( "savelocation" );
+-        t = doc.createTextNode( m_settings->m_saveLocation.prettyURL() );
+-        attr.appendChild( t );
+-        i.appendChild( attr );
+-
+         attr = doc.createElement( "cache" );
+         t = doc.createTextNode( m_cache );
+         attr.appendChild( t );
+         i.appendChild( attr );
+ 
+-        attr = doc.createElement( "autoscan" );
+-        t = doc.createTextNode( m_settings->m_autoScan ? "true" : "false" );
+-        attr.appendChild( t );
+-        i.appendChild( attr );
++        if( m_settings )
++        {
++            attr = doc.createElement( "savelocation" );
++            t = doc.createTextNode( m_settings->m_saveLocation.prettyURL() );
++            attr.appendChild( t );
++            i.appendChild( attr );
+ 
+-        attr = doc.createElement( "scaninterval" );
+-        t = doc.createTextNode( QString::number( m_settings->m_interval ) );
+-        attr.appendChild( t );
+-        i.appendChild( attr );
++            attr = doc.createElement( "autoscan" );
++            t = doc.createTextNode( m_settings->m_autoScan ? "true" : "false" );
++            attr.appendChild( t );
++            i.appendChild( attr );
+ 
+-        attr = doc.createElement( "fetch" );
+-        t = doc.createTextNode( ( m_settings->m_fetch == AUTOMATIC ) ? "automatic" : "stream" );
+-        attr.appendChild( t );
+-        i.appendChild( attr );
++            attr = doc.createElement( "scaninterval" );
++            t = doc.createTextNode( QString::number( m_settings->m_interval ) );
++            attr.appendChild( t );
++            i.appendChild( attr );
+ 
+-        attr = doc.createElement( "autotransfer" );
+-        t = doc.createTextNode( ( m_settings->m_addToMediaDevice ) ? "true" : "false" );
+-        attr.appendChild( t );
+-        i.appendChild( attr );
++            attr = doc.createElement( "fetch" );
++            t = doc.createTextNode( ( m_settings->m_fetch == AUTOMATIC ) ? "automatic" : "stream" );
++            attr.appendChild( t );
++            i.appendChild( attr );
+ 
+-        attr = doc.createElement( "purge" );
+-        t = doc.createTextNode( m_settings->m_purge ? "true" : "false" );
+-        attr.appendChild( t );
+-        i.appendChild( attr );
++            attr = doc.createElement( "autotransfer" );
++            t = doc.createTextNode( ( m_settings->m_addToMediaDevice ) ? "true" : "false" );
++            attr.appendChild( t );
++            i.appendChild( attr );
+ 
+-        attr = doc.createElement( "purgecount" );
+-        t = doc.createTextNode( QString::number( m_settings->m_purgeCount ) );
+-        attr.appendChild( t );
+-        i.appendChild( attr );
++            attr = doc.createElement( "purge" );
++            t = doc.createTextNode( m_settings->m_purge ? "true" : "false" );
++            attr.appendChild( t );
++            i.appendChild( attr );
+ 
++            attr = doc.createElement( "purgecount" );
++            t = doc.createTextNode( QString::number( m_settings->m_purgeCount ) );
++            attr.appendChild( t );
++            i.appendChild( attr );
++        }
++        else
++        {
++            debug() << "BUG: m_settings is 0 for podcast " << m_url.prettyURL() << endl;
++        }
++
+         return i;
+ }
+ 
+@@ -1607,7 +1646,9 @@
+       , m_loading1( QPixmap( locate("data", "amarok/images/loading1.png" ) ) )
+       , m_loading2( QPixmap( locate("data", "amarok/images/loading2.png" ) ) )
+       , m_fetching( false )
++      , m_xml( xml )
+       , m_downloaded( false )
++      , m_onDisk( false )
+       , m_new( false )
+ {
+     const bool isAtom = ( feedType == ATOM );
+@@ -1655,12 +1696,29 @@
+ 
+     m_localUrlString = m_localUrl.path();
+ 
+-    m_downloaded = QFile::exists( m_localUrlString );
++    if( QFile::exists( m_localUrl.path() ) )
++    {
++        m_onDisk = true;
++        m_downloaded = true;
++        m_xml.setAttribute("downloaded", "true"); //mark as downloaded in the xml
++    }
+ 
++    if( xml.hasAttribute("downloaded") )
++    {
++        if(xml.attribute("downloaded") == "true")
++            m_downloaded = true;
++    }
++    else
++    {
++        m_xml.setAttribute("downloaded", "false");
++        setNew(false);
++    }
++
+     setText( 0, m_title );
+     updatePixmap();
+     setDragEnabled( true );
+     setRenameEnabled( 0, false );
++
+ }
+ 
+ void
+@@ -1668,6 +1726,8 @@
+ {
+     if( m_new )
+         setPixmap( 0, SmallIcon("favorites") );
++    else if( m_onDisk )
++        setPixmap( 0, SmallIcon( "down" ) );
+     else if( m_downloaded )
+         setPixmap( 0, SmallIcon( "sound" ) );
+     else
+@@ -1675,18 +1735,18 @@
+ }
+ 
+ const bool
+-PodcastItem::hasDownloaded()
++PodcastItem::isOnDisk()
+ {
+-    m_downloaded = QFile::exists( m_localUrlString );
++    m_onDisk = QFile::exists( m_localUrlString );
+     updatePixmap();
+-    return m_downloaded;
++    return m_onDisk;
+ }
+ 
+ void
+ PodcastItem::downloadMedia()
+ {
+     KURL m_localDir = KURL::fromPathOrURL(m_localUrl.directory(true, true) );
+-    if( hasDownloaded() )
++    if( isOnDisk() )
+         return;
+ 
+     setText(0, i18n( "Downloading Media..." ) );
+@@ -1709,12 +1769,15 @@
+ 
+ void PodcastItem::createLocalDir( const KURL &localDir )
+ {
+-    if( !QFile::exists( localDir.path() ) )
++    QString localDirString = localDir.path();
++    debug() << "checking " << localDirString << endl;
++    if( !QFile::exists( localDirString ) )
+     {
+-        debug() << "checking " << localDir.path() << endl;
+-        createLocalDir( localDir.directory( true, true ) );
+-        debug() << "creating " << localDir.path() << endl;
+-        KIO::mkdir( localDir, -1 );
++        QString parentDirString = localDir.directory( true, true );
++        createLocalDir( parentDirString );
++        debug() << "creating " << localDirString << endl;
++        QDir dir( localDirString );
++        dir.mkdir( localDirString );
+     }
+ }
+ 
+@@ -1728,7 +1791,7 @@
+ 
+     stopAnimation();
+     setText( 0, m_title );
+-    m_downloaded = false;
++    m_onDisk = false;
+     updatePixmap();
+ }
+ 
+@@ -1748,6 +1811,8 @@
+         return;
+     }
+ 
++    m_onDisk = true;
++    m_xml.setAttribute("downloaded", "true"); //mark as downloaded in the xml
+     m_downloaded = true;
+ 
+     PodcastChannel *channel = dynamic_cast<PodcastChannel *>( m_parent );
+@@ -1758,6 +1823,8 @@
+     }
+ 
+     updatePixmap();
++    dynamic_cast<PodcastChannel*>(m_parent)->saveCache();
++
+ }
+ 
+ void
+@@ -1879,6 +1946,14 @@
+     updatePixmap();
+ }
+ 
++void PodcastItem::setListened( bool n )
++{
++    m_downloaded = n;
++    if( n )
++        m_xml.setAttribute("downloaded", "true"); //mark as downloaded in the xml
++    updatePixmap();
++}
++
+ void
+ PodcastItem::startAnimation()
+ {
+@@ -2025,6 +2100,7 @@
+     str += body.arg( i18n( "Date" ),        m_date );
+     str += body.arg( i18n( "Type" ),        m_type );
+     str += body.arg( i18n( "Description" ), m_description );
++    str += body.arg( i18n( "URL" ), m_url.prettyURL() );
+     str += "</table></body></html>";
+ 
+     PlaylistBrowser::instance()->setInfo( str );
+Index: tagdialog.h
+===================================================================
+--- amarok/src/tagdialog.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/tagdialog.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -31,7 +31,7 @@
+ 
+     public:
+ 
+-        enum Changes { NOCHANGE=0, SCORECHANGED=1, TAGSCHANGED=2, LYRICSCHANGED=4 };
++        enum Changes { NOCHANGE=0, SCORECHANGED=1, TAGSCHANGED=2, LYRICSCHANGED=4, RATINGCHANGED=8 };
+ 
+         TagDialog( const KURL& url, QWidget* parent = 0 );
+         TagDialog( const KURL::List list, QWidget* parent = 0 );
+@@ -76,6 +76,7 @@
+         void loadLyrics( const KURL& url );
+         MetaBundle bundleForURL( const KURL &url );
+         int scoreForURL( const KURL &url );
++        int ratingForURL( const KURL &url );
+         QString lyricsForURL( const KURL &url );
+         void saveTags();
+         bool writeTag( MetaBundle mb, bool updateCB=true );
+@@ -97,6 +98,7 @@
+         PlaylistItem* m_playlistItem;
+         QMap<QString, MetaBundle> storedTags;
+         QMap<QString, int> storedScores;
++        QMap<QString, int> storedRatings;
+         QMap<QString, QString> storedLyrics;
+         KURL::List m_urlList;
+         QString m_buttonMbText;
+Index: amarok.desktop
+===================================================================
+--- amarok/src/amarok.desktop	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/amarok.desktop	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -3,6 +3,7 @@
+ Version=0.9.4
+ Encoding=UTF-8
+ Name=amaroK
++Name[bn]=আমারক
+ Name[fr]=AmaroK
+ Name[hi]=अमारोक
+ Name[pa]=ਅਮਰੋਕ
+@@ -10,6 +11,7 @@
+ Name[xx]=xxamaroKxx
+ GenericName=Audio Player
+ GenericName[bg]=Аудио плеър
++GenericName[bn]=অডিও প্লেয়ার
+ GenericName[br]=C'hoarier klevet
+ GenericName[cs]=Zvukový přehrávač
+ GenericName[da]=Lydafspiller
+@@ -49,6 +51,7 @@
+ Exec=amarok %U
+ Comment=Uncle Rodney says, "10/10, amaroK is seriously super!"
+ Comment[bg]=Аудио плеър с много възможности
++Comment[bn]=অ্যাঙ্কল রডনি বলেন, "আমারক সত্যিই দারুন, ১০/১০!"
+ Comment[cs]=Strýček Rodney říká, "10/10, amaroK je vážně super!"
+ Comment[da]=Onkel Rodney siger, "10/10, amaroK er virkelig super!"
+ Comment[de]=Onkel Rodney sagt, "10/10, amaroK is seriously super!"
+Index: collectionbrowser.h
+===================================================================
+--- amarok/src/collectionbrowser.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/collectionbrowser.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -13,6 +13,7 @@
+ #include <klistview.h>       //baseclass
+ #include <qstringlist.h>     //stack allocated
+ #include <kurl.h>            //stack allocated
++#include <kdialogbase.h>     //baseclass
+ 
+ #include "collectiondb.h"
+ 
+@@ -213,5 +214,25 @@
+         QString                 m_cacheCurrentItem;
+ };
+ 
++// why is signal detailsClicked() missing from KDialogBase?
++class OrganizeCollectionDialogBase : public KDialogBase
++{
++    Q_OBJECT
++    public:
++    OrganizeCollectionDialogBase( QWidget *parent=0, const char *name=0, bool modal=true,
++            const QString &caption=QString::null,
++            int buttonMask=Ok|Apply|Cancel )
++        : KDialogBase( parent, name, modal, caption, buttonMask )
++    {
++    }
+ 
++    signals:
++        void detailsClicked();
++    public slots:
++        void slotDetails() { KDialogBase::slotDetails(); emit detailsClicked(); adjustSize(); }
++};
++
++
++
++
+ #endif /* AMAROK_COLLECTIONBROWSER_H */
+Index: collectiondb.h
+===================================================================
+--- amarok/src/collectiondb.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/collectiondb.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -5,6 +5,7 @@
+ // (c) 2005 Jeff Mitchell <kde-dev at emailgoeshere.com>
+ // (c) 2005 Isaiah Damron <xepo at trifault.net>
+ // (c) 2005 Alexandre Pereira de Oliveira <aleprj at gmail.com>
++// (c) 2006 Jonas Hurrelmann <j at outpo.st>
+ // See COPYING file for licensing information.
+ 
+ #ifndef AMAROK_COLLECTIONDB_H
+@@ -305,6 +306,10 @@
+         QString findDirectoryImage( const QString& artist, const QString& album, uint width = 0 );
+         QString findMetaBundleImage( MetaBundle trackInformation, const uint = 1 );
+ 
++        static QPixmap createDragPixmap(const KURL::List &urls);
++        static const int DRAGPIXMAP_OFFSET_X = -12;
++        static const int DRAGPIXMAP_OFFSET_Y = -28;
++
+         /**
+          * Retrieves the path to the image for the album of the requested item
+          * @param width the size of the image. 0 == full size, 1 == preview size
+Index: atomicstring.h
+===================================================================
+--- amarok/src/atomicstring.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/atomicstring.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -18,18 +18,22 @@
+ */
+ 
+ /**
+-    AtomicString is a thin wrapper over QString that makes sure only one copy of any equivalent string is stored in memory at any one time.
+-    As a side benefit, comparing AtomicStrings is reduced to a pointer comparison.
+-    Constructing an AtomicString is slower than constructing a QString as a hash has to be generated to ensure uniqueness.
+-    According to benchmarks, Paul Hsieh's SuperFastHash (which is currently used) can hash 5 million 256 byte strings in 1.34s on a 1.62GHz Athlon XP.
+-    For other use, the overhead compared to a QString should be minimal.
+-**/
++ * A thin wrapper over QString which ensures only a single copy of string data
++ * is stored for equivalent strings. As a side benefit, testing for equality
++ * is reduced to a pointer comparison. Construction is slower than a QString,
++ * as it must be checked for equality with existing strings. (A hash set is
++ * used for this purpose. According to benchmarks, Paul Hsieh's SuperFastHash
++ * (which is currently used -- see http://www.azillionmonkeys.com/qed/hash.html)
++ * can hash 5 million 256 byte strings in 1.34s on a 1.62GHz Athlon XP.) For
++ * other use, the overhead compared to a plain QString should be minimal.
++ *
++ * @author Gábor Lehel <illissius at gmail.com>
++ */
+ 
+ #ifndef AMAROK_ATOMICSTRING_H
+ #define AMAROK_ATOMICSTRING_H
+ 
+ #include "config.h"
+-#include <ksharedptr.h>
+ #ifdef __GNUC__
+     #include <ext/hash_set>
+ #else
+@@ -42,50 +46,94 @@
+ class LIBAMAROK_EXPORT AtomicString
+ {
+ public:
+-    /** Constructs a null AtomicString, which is equivalent to QString::null. */
++    /**
++     * Constructs an empty string.
++     * @see isEmpty
++     */
+     AtomicString();
+ 
+-    /** Copies an AtomicString. This is as fast as copying a KSharedPtr. */
++    /**
++     * Constructs a copy of \p string. This operation takes constant time.
++     * @param string the string to copy
++     * @see operator=
++     */
+     AtomicString( const AtomicString &other );
+ 
+-    /** Constructs an AtomicString from a QString.
+-        This is slower than constructing a QString as a hash function must be run on it. */
++    /**
++     * Constructs a copy of \p string.
++     * @param string the string to copy
++     */
+     AtomicString( const QString &string );
+ 
+-    virtual ~AtomicString();
++    /**
++     * Destroys the string.
++     * Note: this isn't virtual, to halve sizeof().
++     */
++    ~AtomicString();
+ 
+-    /** Copies an AtomicString. This is as fast as copying a KSharedPtr.
+-        Note that you can pass a QString here and an AtomicString will be constructed from it. */
++    /**
++     * Makes this string a copy of \p string. This operation takes constant time.
++     * @param string the string to copy
++     */
+     AtomicString &operator=( const AtomicString &other );
+ 
+-    /** Tests for equivalence with another AtomicString. This is just a pointer comparison.
+-        Note that you can pass a QString here and an AtomicString will be constructed from it. */
++    /**
++     * This operation takes constant time.
++     * @return whether this string and \p string are equivalent
++     */
+     bool operator==( const AtomicString &other ) const;
+ 
+-    /** Returns the string. */
++    /**
++     * @return the string
++     */
+     QString string() const;
+ 
+-    /** Implicitly casts to a QString. */
++    /**
++     * Implicitly casts to a QString.
++     * @return the string
++     */
+     inline operator QString() const { return string(); }
+ 
+-    /** Provided for convenience, so you can do atomicstring->QStringfunction(),
+-        instead of atomicstring.string().QStringfunction(). */
++    /**
++     * For convenience, so you can do atomicstring->QStringfunction(),
++     * instead of atomicstring.string().QStringfunction().
++     */
+     const QString *operator->() const;
+ 
+-    /** Returns a deep copy of the string. Useful for threading. */
++    /**
++     * Useful for threading.
++     * @return a deep copy of the string
++     */
+     QString deepCopy() const;
+ 
+-    /** For convenience, in AtomicString's case they are equivalent. */
+-    bool isNull() const;
+-    inline bool isEmpty() const { return isNull(); }
++    /**
++     * For convenience. Equivalent to isNull().
++     * @return whether the string is empty
++     * @see isNull
++     */
++    bool isEmpty() const;
+ 
+-    /** Returns the internal pointer to the string.
+-        The pointer is guaranteed to be equivalent for equivalent strings, and different for different ones.
+-        This is useful for certain kinds of hacks, but shouldn't normally be used. */
++    /**
++     * For convenience. Equivalent to isEmpty().
++     * @return whether the string is empty
++     * @see isEmpty
++     */
++    inline bool isNull() const { return isEmpty(); }
++
++    /**
++     * Returns the internal pointer to the string.
++     * Guaranteed to be equivalent for equivalent strings, and different for
++     * different ones. This can be useful for certain kinds of hacks, but
++     * shouldn't normally be used.
++     * @return the internal pointer to the string
++     */
+     const QString *ptr() const;
+ 
+-    /** For debugging purposes -- lists all strings and how many places they're used to stderr. */
+-    static void listContents();
++    /**
++     * For debugging purposes.
++     * @return the number of nonempty AtomicStrings equivalent to this one
++     */
++    uint refcount() const;
+ 
+ private:
+     #ifdef __GNUC__
+@@ -97,12 +145,15 @@
+         typedef std::set<QString*, less> set_type;
+     #endif
+ 
+-    static set_type s_store;
+-
+     class Data;
+     friend class Data;
+ 
+-    KSharedPtr<Data> m_string;
++    void ref( Data* );
++    void deref( Data* );
++
++    static set_type s_store;
++
++    Data *m_string;
+ };
+ 
+ #endif
+Index: konquisidebar/amarok.desktop
+===================================================================
+--- amarok/src/konquisidebar/amarok.desktop	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/konquisidebar/amarok.desktop	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -3,6 +3,7 @@
+ Type=Link
+ URL=
+ Name=amaroK
++Name[bn]=আমারক
+ Name[fr]=AmaroK
+ Name[hi]=अमारोक
+ Name[pa]=ਅਮਰੋਕ
+@@ -10,6 +11,7 @@
+ Name[xx]=xxamaroKxx
+ GenericName=Audio Player
+ GenericName[bg]=Аудио плеър
++GenericName[bn]=অডিও প্লেয়ার
+ GenericName[br]=C'hoarier klevet
+ GenericName[cs]=Zvukový přehrávač
+ GenericName[da]=Lydafspiller
+@@ -48,6 +50,7 @@
+ GenericName[zh_TW]=音樂播放器
+ Comment=Uncle Rodney says, "10/10, amaroK is seriously super!"
+ Comment[bg]=Аудио плеър с много възможности
++Comment[bn]=অ্যাঙ্কল রডনি বলেন, "আমারক সত্যিই দারুন, ১০/১০!"
+ Comment[cs]=Strýček Rodney říká, "10/10, amaroK je vážně super!"
+ Comment[da]=Onkel Rodney siger, "10/10, amaroK er virkelig super!"
+ Comment[de]=Onkel Rodney sagt, "10/10, amaroK is seriously super!"
+Index: metabundle.cpp
+===================================================================
+--- amarok/src/metabundle.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/metabundle.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -508,10 +508,10 @@
+         case Bitrate:    text = prettyBitrate( bitrate() );                                          break;
+         case SampleRate: text = prettySampleRate();                                                  break;
+         case Score:      text = QString::number( score() );                                          break;
+-        case Rating:     text = rating() ? QString::number( rating() ) : QString::null;              break;
++        case Rating:     text = prettyRating();                                                      break;
+         case PlayCount:  text = QString::number( playCount() );                                      break;
+         case LastPlayed: text = amaroK::verboseTimeSince( lastPlay() );                              break;
+-        case Filesize:   text = KIO::convertSize( filesize() );                                      break;
++        case Filesize:   text = prettyFilesize();                                                      break;
+         case Mood:       text = QString::null;                                                       break;
+         default: warning() << "Tried to get the text of a nonexistent column!" << endl;              break;
+     }
+@@ -740,8 +740,11 @@
+ 
+     //FIXME doesn't work for resume playback
+ 
+-    if( !s.isEmpty() ) s += i18n(" - ");
+-    s += title();
++    if( s.isEmpty() )
++        s = title();
++    else
++        s = i18n("%1 - %2").arg( artist(), title() );
++
+     if( s.isEmpty() ) s = prettyTitle( filename() );
+ 
+     return s;
+@@ -821,7 +824,33 @@
+                 : prettyGeneric( "%1", i );
+ }
+ 
++QString
++MetaBundle::prettyFilesize( int s ) {
++    return KIO::convertSize( s );
++}
++
++QString
++MetaBundle::prettyRating( int r ) {
++    switch( r )
++    {
++        case 1: return i18n( "1 - Crap" );
++        case 2: return i18n( "2 - Tolerable" );
++        case 3: return i18n( "3 - Good" );
++        case 4: return i18n( "4 - Excellent" );
++        case 5: return i18n( "5 - Inconceivable!" );
++        case 0: default: return i18n( "Not rated" ); // assume weird values as not rated
++    }
++}
++
+ QStringList
++MetaBundle::ratingList() {
++    QStringList list;
++    for ( int i = 0; i<=5; i++ )
++        list += prettyRating( i );
++    return list;
++}
++
++QStringList
+ MetaBundle::genreList() //static
+ {
+     QStringList list;
+Index: hintlineedit.cpp
+===================================================================
+--- amarok/src/hintlineedit.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 0)
++++ amarok/src/hintlineedit.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -0,0 +1,58 @@
++#include <hintlineedit.h>
++#include <qvbox.h>
++#include <qlabel.h>
++#include <qfont.h>
++
++HintLineEdit::HintLineEdit( const QString &hint, const QString &text, QWidget *parent, const char *name )
++   : KLineEdit( text, 0, name )
++   , m_vbox( new QVBox( parent ) )
++{
++    init();
++    m_hint->setText( hint );
++}
++
++HintLineEdit::HintLineEdit( const QString &text, QWidget *parent, const char *name )
++   : KLineEdit( text, 0, name )
++   , m_vbox( new QVBox( parent ) )
++{
++    init();
++}
++
++HintLineEdit::HintLineEdit( QWidget *parent, const char *name )
++   : KLineEdit( 0, name )
++   , m_vbox( new QVBox( parent ) )
++{
++    init();
++}
++
++void
++HintLineEdit::init()
++{
++    reparent( m_vbox, 0, QPoint(0,0), true );
++    m_hint = new QLabel( m_vbox );
++    //m_hint->setBuddy( this );
++    m_hint->setFocusPolicy( NoFocus );
++    QFont font;
++    font.setPointSize( font.pointSize() - 2);
++    m_hint->setFont( font );
++}
++
++HintLineEdit::~HintLineEdit()
++{
++    reparent( 0, 0, QPoint(0,0), false );
++    delete m_vbox;
++}
++
++void
++HintLineEdit::setHint( const QString &hint )
++{
++    m_hint->setText( hint );
++}
++
++QObject *
++HintLineEdit::parent()
++{
++    return m_vbox->parent();
++}
++
++#include "hintlineedit.moc"
+Index: app.cpp
+===================================================================
+--- amarok/src/app.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/app.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -84,8 +84,8 @@
+     I18N_NOOP( "amaroK" ), APP_VERSION,
+     I18N_NOOP( "The audio player for KDE" ), KAboutData::License_GPL,
+     I18N_NOOP( "(C) 2002-2003, Mark Kretschmann\n(C) 2003-2006, The amaroK Development Squad" ),
+-    I18N_NOOP( "IRC:\nirc.freenode.net - #amarok, #amarok.de\n\nFeedback:\namarok-devel at lists.sourceforge.net" ),
+-    I18N_NOOP( "http://amarok.kde.org" ) );
++    I18N_NOOP( "IRC:\nirc.freenode.net - #amarok, #amarok.de\n\nFeedback:\namarok-devel at lists.sourceforge.net\n\n(Build Date: " __DATE__ ")" ),
++             ( "http://amarok.kde.org" ) );
+ 
+ App::App()
+         : KApplication()
+@@ -239,7 +239,7 @@
+ #include <dcopref.h>
+ #include <qstringlist.h>
+ 
+-namespace { 
++namespace {
+ 
+ // grabbed from KsCD source, kompatctdisk.cpp
+ QString urlToDevice(const QString& device)
+@@ -319,7 +319,7 @@
+         EngineController::instance()->next();
+     else if ( args->isSet( "previous" ) )
+         EngineController::instance()->previous();
+-    else if (args->isSet("cdplay")) { 
++    else if (args->isSet("cdplay")) {
+         QString device = args->getOption("cdplay");
+         KURL::List urls;
+         if (EngineController::engine()->getAudioCDContents(device, urls)) {
+@@ -370,7 +370,7 @@
+             { "wizard", I18N_NOOP( "Run first-run wizard" ), 0 },
+             { "engine <name>", I18N_NOOP( "Use the <name> engine" ), 0 },
+             { "cwd <directory>", I18N_NOOP( "Base for relative filenames/URLs" ), 0 },
+-            { "cdplay <device>", I18N_NOOP("Play an AudioCD from <device>"), 0 }, 
++            { "cdplay <device>", I18N_NOOP("Play an AudioCD from <device>"), 0 },
+             { 0, 0, 0 }
+         };
+ 
+@@ -622,7 +622,7 @@
+ 
+         //Set the caption correctly.
+         if ( !EngineController::instance()->bundle().prettyTitle().isEmpty() )
+-            m_pPlaylistWindow->setCaption( "amaroK - " + EngineController::instance()->bundle().veryNiceTitle() );
++            m_pPlaylistWindow->setCaption( i18n("amaroK - %1").arg( EngineController::instance()->bundle().veryNiceTitle() ) );
+         else
+             m_pPlaylistWindow->setCaption( "amaroK" );
+ 
+@@ -920,7 +920,7 @@
+         if ( oldState == Engine::Paused )
+             amaroK::OSD::instance()->OSDWidget::show( i18n("Play" ) );
+         if ( !bundle.prettyTitle().isEmpty() )
+-            m_pPlaylistWindow->setCaption( "amaroK - " + bundle.veryNiceTitle() );
++            m_pPlaylistWindow->setCaption( i18n("amaroK - %1").arg( bundle.veryNiceTitle() ) );
+         break;
+ 
+     case Engine::Paused:
+@@ -942,7 +942,7 @@
+ {
+     amaroK::OSD::instance()->show( bundle );
+     if ( !bundle.prettyTitle().isEmpty() )
+-        m_pPlaylistWindow->setCaption( "amaroK - " + bundle.veryNiceTitle() );
++        m_pPlaylistWindow->setCaption( i18n("amaroK - %1").arg( bundle.veryNiceTitle() ) );
+ 
+     TrackToolTip::instance()->setTrack( bundle );
+ }
+Index: Makefile.am
+===================================================================
+--- amarok/src/Makefile.am	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/Makefile.am	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -84,6 +84,7 @@
+     fht.cpp \
+     filebrowser.cpp \
+     firstrunwizard.ui \
++    hintlineedit.cpp \
+     htmlview.cpp \
+     k3bexporter.cpp \
+     kbookmarkhandler.cpp \
+@@ -180,8 +181,10 @@
+     $(mysql_libs) \
+     $(postgresql_libs)
+ 
++amarokapp_LDFLAGS = \
++    $(all_libraries) \
++    $(KDE_RPATH)
+ 
+-
+ rcdir = \
+     $(kde_datadir)/amarok
+ 
+Index: tagdialog.cpp
+===================================================================
+--- amarok/src/tagdialog.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/tagdialog.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -364,6 +364,8 @@
+     kComboBox_album->completionObject()->setIgnoreCase( true );
+     kComboBox_album->setCompletionMode( KGlobalSettings::CompletionPopup );
+ 
++    kComboBox_rating->insertStringList( MetaBundle::ratingList() );
++
+ //    const QStringList genres = MetaBundle::genreList();
+     const QStringList genres = CollectionDB::instance()->genreList();
+     kComboBox_genre->insertStringList( genres );
+@@ -394,6 +396,8 @@
+     connect( kComboBox_album,  SIGNAL(textChanged( const QString& )), SLOT(checkModified()) );
+     connect( kComboBox_genre,  SIGNAL(activated( int )),              SLOT(checkModified()) );
+     connect( kComboBox_genre,  SIGNAL(textChanged( const QString& )), SLOT(checkModified()) );
++    connect( kComboBox_rating, SIGNAL(activated( int )),              SLOT(checkModified()) );
++    connect( kComboBox_rating, SIGNAL(textChanged( const QString& )), SLOT(checkModified()) );
+     connect( kIntSpinBox_track,SIGNAL(valueChanged( int )),           SLOT(checkModified()) );
+     connect( kIntSpinBox_year, SIGNAL(valueChanged( int )),           SLOT(checkModified()) );
+     connect( kIntSpinBox_score,SIGNAL(valueChanged( int )),           SLOT(checkModified()) );
+@@ -569,6 +573,7 @@
+     kComboBox_artist       ->setCurrentText( m_bundle.artist() );
+     kComboBox_album        ->setCurrentText( m_bundle.album() );
+     kComboBox_genre        ->setCurrentText( m_bundle.genre() );
++    kComboBox_rating       ->setCurrentItem( m_bundle.rating() );
+     kIntSpinBox_track      ->setValue( m_bundle.track() );
+     kLineEdit_composer     ->setText( m_bundle.composer() );
+     kIntSpinBox_year       ->setValue( m_bundle.year() );
+@@ -590,10 +595,12 @@
+     summaryText += body2cols.arg( i18n("Length"), unknownSafe( m_bundle.prettyLength() ) );
+     summaryText += body2cols.arg( i18n("Bitrate"), unknownSafe( m_bundle.prettyBitrate() ) );
+     summaryText += body2cols.arg( i18n("Samplerate"), unknownSafe( m_bundle.prettySampleRate() ) );
+-    summaryText += body2cols.arg( i18n("Filesize"), unknownSafe( QString::number( m_bundle.filesize() ) ) );
++    summaryText += body2cols.arg( i18n("Size"), unknownSafe( m_bundle.prettyFilesize()  ) );
++    summaryText += body2cols.arg( i18n("Format"), unknownSafe( m_bundle.type() ) );
+ 
+     summaryText += "</table></td><td width=50%><table>";
+     summaryText += body2cols.arg( i18n("Score"), QString::number( m_score ) );
++    summaryText += body2cols.arg( i18n("Rating"), m_bundle.prettyRating() );
+ 
+     summaryText += body2cols.arg( i18n("Playcount"), QString::number( m_playcount ) );
+     summaryText += body2cols.arg( i18n("First Played"), m_playcount ? KGlobal::locale()->formatDate( m_firstPlay.date() , true ) : i18n("Never") );
+@@ -626,6 +633,7 @@
+     kComboBox_artist->setEnabled( local );
+     kComboBox_album->setEnabled( local );
+     kComboBox_genre->setEnabled( local );
++    kComboBox_rating->setEnabled( local );
+     kIntSpinBox_track->setEnabled( local );
+     kIntSpinBox_year->setEnabled( local );
+     kIntSpinBox_score->setEnabled( local );
+@@ -818,6 +826,8 @@
+ 
+     if (kIntSpinBox_score->value() != m_score)
+         result |= TagDialog::SCORECHANGED;
++    if (kComboBox_rating->currentItem() != m_bundle.rating() )
++        result |= TagDialog::RATINGCHANGED;
+     if ( !equalString( kTextEdit_lyrics->text(), m_lyrics ) )
+         result |= TagDialog::LYRICSCHANGED;
+ 
+@@ -850,11 +860,12 @@
+         mb.setLength( m_bundle.length() );
+         mb.setBitrate( m_bundle.bitrate() );
+         mb.setSampleRate( m_bundle.sampleRate() );
+-
+         storedTags.replace( url, mb );
+     }
+     if( result & TagDialog::SCORECHANGED )
+         storedScores.replace( url, kIntSpinBox_score->value() );
++    if( result & TagDialog::RATINGCHANGED )
++        storedRatings.replace( url, kComboBox_rating->currentItem() );
+     if( result & TagDialog::LYRICSCHANGED ) {
+         if ( kTextEdit_lyrics->text().isEmpty() )
+             storedLyrics.replace( url, QString::null );
+@@ -884,6 +895,7 @@
+ {
+     m_bundle = bundleForURL( url.path() );
+     m_score = scoreForURL( url.path() );
++    m_bundle.setRating( ratingForURL( url.path() ) );
+ 
+     loadLyrics( url );
+ 
+@@ -922,7 +934,15 @@
+     return CollectionDB::instance()->getSongPercentage( url.path() );
+ }
+ 
++int
++TagDialog::ratingForURL( const KURL &url )
++{
++    if( storedRatings.find( url.path() ) != storedRatings.end() )
++        return storedRatings[ url.path() ];
+ 
++    return CollectionDB::instance()->getSongRating( url.path() );
++}
++
+ QString
+ TagDialog::lyricsForURL( const KURL &url )
+ {
+@@ -956,6 +976,10 @@
+     for(QMap<QString, int>::ConstIterator it = storedScores.begin(); it != endScore; ++it ) {
+         CollectionDB::instance()->setSongPercentage( it.key(), it.data() );
+     }
++    QMap<QString, int>::ConstIterator endRating( storedRatings.end() );
++    for(QMap<QString, int>::ConstIterator it = storedRatings.begin(); it != endRating; ++it ) {
++        CollectionDB::instance()->setSongRating( it.key(), it.data() );
++    }
+     QMap<QString, QString>::ConstIterator endLyrics( storedLyrics.end() );
+     for(QMap<QString, QString>::ConstIterator it = storedLyrics.begin(); it != endLyrics; ++it ) {
+         CollectionDB::instance()->setLyrics( it.key(), it.data() );
+Index: collectionbrowser.cpp
+===================================================================
+--- amarok/src/collectionbrowser.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/collectionbrowser.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -1499,7 +1499,8 @@
+ {
+     QStringList folders = AmarokConfig::collectionFolders();
+ 
+-    KDialogBase base( m_parent, "OrganizeFiles", true, caption, KDialogBase::Ok|KDialogBase::Cancel );
++    OrganizeCollectionDialogBase base( m_parent, "OrganizeFiles", true, caption,
++            KDialogBase::Ok|KDialogBase::Cancel|KDialogBase::Details );
+     QVBox* page = base.makeVBoxMainWidget();
+ 
+     OrganizeCollectionDialog dialog( page );
+@@ -1516,7 +1517,17 @@
+     dialog.formatEdit->setText( AmarokConfig::customScheme() );
+     dialog.regexpEdit->setText( AmarokConfig::replacementRegexp() );
+     dialog.replaceEdit->setText( AmarokConfig::replacementString() );
++    connect( &base, SIGNAL(detailsClicked()), &dialog, SLOT(slotDetails()) );
+ 
++    if( dialog.customschemeCheck->isChecked() )
++    {
++        base.setDetails( true );
++    }
++    else
++    {
++        dialog.slotDetails();
++    }
++
+     if( urls.count() )
+     {
+         dialog.setPreviewBundle( MetaBundle( urls.first() ) );
+@@ -1641,13 +1652,13 @@
+ void
+ CollectionView::contentsDragEnterEvent( QDragEnterEvent *e )
+ {
+-    e->accept( e->source() != viewport() && KURLDrag::canDecode( e ) );
++    e->accept( e->source() != viewport() && e->source() != this && KURLDrag::canDecode( e ) );
+ }
+ 
+ void
+ CollectionView::contentsDragMoveEvent( QDragMoveEvent *e )
+ {
+-    e->accept( e->source() != viewport() && KURLDrag::canDecode( e ) );
++    e->accept( e->source() != viewport() && e->source() != this && KURLDrag::canDecode( e ) );
+ }
+ 
+ void
+@@ -1656,7 +1667,24 @@
+     KURL::List list;
+     if( KURLDrag::decode( e, list ) )
+     {
+-        organizeFiles( list, i18n( "Copy Files To Collection" ), true /* copy */ );
++        KURL::List cleanList;
++        int dropped = 0;
++        for( KURL::List::iterator it = list.begin();
++                it != list.end();
++                ++it )
++        {
++            if( (*it).protocol() == "file" && !CollectionDB::instance()->isFileInCollection( (*it).path() ) )
++                cleanList += *it;
++            else
++                dropped++;
++
++        }
++        if( dropped > 0 )
++            amaroK::StatusBar::instance()->shortMessage(
++                    i18n( "One file already in collection",
++                        "%n files already in collection", dropped ) );
++        if( cleanList.count() > 0 )
++            organizeFiles( list, i18n( "Copy Files To Collection" ), true /* copy */ );
+     }
+ }
+ 
+@@ -1700,7 +1728,9 @@
+ void
+ CollectionView::startDrag()
+ {
+-    KURLDrag* d = new KURLDrag( listSelected(), this );
++    KURL::List urls = listSelected();
++    KURLDrag* d = new KURLDrag( urls, this );
++    d->setPixmap(CollectionDB::createDragPixmap(urls), QPoint(CollectionDB::DRAGPIXMAP_OFFSET_X,CollectionDB::DRAGPIXMAP_OFFSET_Y));
+     d->dragCopy();
+ }
+ 
+Index: atomicstring.cpp
+===================================================================
+--- amarok/src/atomicstring.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/atomicstring.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -20,7 +20,6 @@
+ #include <stdint.h>
+ #include <qdeepcopy.h>
+ #include <qstring.h>
+-#include "debug.h"
+ 
+ #include "atomicstring.h"
+ 
+@@ -33,7 +32,7 @@
+     // http://www.azillionmonkeys.com/qed/hash.html
+     struct AtomicString::SuperFastHash
+     {
+-        bool operator()( const QString *string ) const
++        uint32_t operator()( const QString *string ) const
+         {
+             unsigned l = string->length();
+             const QChar *s = string->unicode();
+@@ -96,43 +95,36 @@
+ 
+ #endif
+ 
+-AtomicString::set_type AtomicString::s_store;
+-
+-class AtomicString::Data: public QString, public KShared
++class AtomicString::Data: public QString
+ {
+ public:
+-    bool stored;
+-    Data(): stored( false ) { }
+-    Data( const QString &s ): QString( s ), stored( false ) { }
+-    virtual ~Data()
+-    {
+-        if( stored )
+-            AtomicString::s_store.erase( this );
+-    }
++    uint refcount;
++    Data(): refcount( 0 ) { }
++    Data( const QString &s ): QString( s ), refcount( 0 ) { }
+ };
+ 
+-AtomicString::AtomicString()
+-{
+-}
++AtomicString::AtomicString(): m_string( 0 ) { }
+ 
+-AtomicString::AtomicString( const AtomicString &other )
++AtomicString::AtomicString( const AtomicString &other ): m_string( other.m_string )
+ {
+-    m_string = other.m_string;
++    ref( m_string );
+ }
+ 
+-AtomicString::AtomicString( const QString &string )
++AtomicString::AtomicString( const QString &string ): m_string( 0 )
+ {
+     if( string.isEmpty() )
+         return;
+ 
+-    KSharedPtr<Data> s = new Data( string );
+-    const std::pair<set_type::iterator, bool> r = s_store.insert( s.data() );
+-    m_string = static_cast<Data*>( *r.first );
+-    m_string->stored = true;
++    Data *s = new Data( string );
++    m_string = static_cast<Data*>( *( s_store.insert( s ).first ) );
++    ref( m_string );
++    if( !s->refcount )
++        delete s;
+ }
+ 
+ AtomicString::~AtomicString()
+ {
++    deref( m_string );
+ }
+ 
+ QString AtomicString::string() const
+@@ -154,7 +146,7 @@
+     return QString::null;
+ }
+ 
+-bool AtomicString::isNull() const
++bool AtomicString::isEmpty() const
+ {
+     return !m_string;
+ }
+@@ -166,9 +158,20 @@
+     return &QString::null;
+ }
+ 
++uint AtomicString::refcount() const
++{
++    if( m_string )
++        return m_string->refcount;
++    return 0;
++}
++
+ AtomicString &AtomicString::operator=( const AtomicString &other )
+ {
++    if( m_string == other.m_string )
++        return *this;
++    deref( m_string );
+     m_string = other.m_string;
++    ref( m_string );
+     return *this;
+ }
+ 
+@@ -177,8 +180,21 @@
+     return m_string == other.m_string;
+ }
+ 
+-void AtomicString::listContents() //static
++void AtomicString::deref( Data *s )
+ {
+-    for( set_type::iterator it = s_store.begin(), end = s_store.end(); it != end; ++it )
+-        debug() << static_cast<Data*>((*it))->_KShared_count() << " " << (**it) << endl;
++    if( !s )
++        return;
++    if( !( --s->refcount ) )
++    {
++        s_store.erase( s );
++        delete s;
++    }
+ }
++
++void AtomicString::ref( Data *s )
++{
++    if( s )
++        s->refcount++;
++}
++
++AtomicString::set_type AtomicString::s_store;
+Index: playlist.h
+===================================================================
+--- amarok/src/playlist.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/playlist.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -99,8 +99,8 @@
+         /// Dynamic mode functions
+         void addSpecialTracks( uint songCount, const int type = Party::RANDOM );
+         void addSpecialCustomTracks( uint songCount );
+-        void adjustPartyUpcoming( uint songCount, const int type = Party::RANDOM );
+-        void adjustPartyPrevious( uint songCount );
++        void adjustPartyUpcoming( uint songCount, bool saveUndo = false, const int type = Party::RANDOM );
++        void adjustPartyPrevious( uint songCount, bool saveUndo = false );
+         void advancePartyTrack( PlaylistItem *item = 0 );
+         void alterHistoryItems( bool enable = false, bool entire = false );
+ 
+@@ -178,7 +178,6 @@
+         void appendMedia( const QString &path );
+         void clear();
+         void copyToClipboard( const QListViewItem* = 0 ) const;
+-        void playCountChanged( const QString &path );
+         void deleteSelectedFiles();
+         void ensureItemCentered( QListViewItem* item );
+         void playCurrentTrack();
+@@ -292,6 +291,11 @@
+         void viewportPaintEvent( QPaintEvent* );
+         void viewportResizeEvent( QResizeEvent* );
+ 
++        void appendToPreviousTracks( PlaylistItem *item );
++        void appendToPreviousAlbums( PlaylistAlbum *album );
++        void removeFromPreviousTracks( PlaylistItem *item = 0 );
++        void removeFromPreviousAlbums( PlaylistAlbum *album = 0 );
++
+         typedef QMap<MyAtomicString, PlaylistAlbum*> AlbumMap;
+         typedef QMap<MyAtomicString, AlbumMap> ArtistAlbumMap;
+         ArtistAlbumMap m_albums;
+Index: mydirlister.h
+===================================================================
+--- amarok/src/mydirlister.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/mydirlister.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -12,7 +12,7 @@
+ 
+ class MyDirLister : public KDirLister {
+ public:
+-    MyDirLister( bool delayedMimeTypes ) : KDirLister( delayedMimeTypes ) { setShowingDotFiles( true ); }
++    MyDirLister( bool delayedMimeTypes ) : KDirLister( delayedMimeTypes ) { }
+ 
+ protected:
+     virtual bool matchesMimeFilter( const KFileItem *item ) const {
+Index: firstrunwizard.ui.h
+===================================================================
+--- amarok/src/firstrunwizard.ui.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/firstrunwizard.ui.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -33,7 +33,6 @@
+     using namespace amaroK;
+ 
+     //aesthetics
+-    cancelButton()->setFixedSize( cancelButton()->sizeHint() );
+     helpButton()->hide();
+ 
+     //would be better as a KConfigXT key now
+Index: playlistloader.cpp
+===================================================================
+--- amarok/src/playlistloader.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/playlistloader.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -917,7 +917,7 @@
+ 
+     BundleList bundles;
+     uint x = 0;
+-    for( for_iterators( QStringList, values ); it != end || isAborted(); ++it ) {
++    for( for_iterators( QStringList, values ); it != end && !isAborted(); ++it ) {
+         setProgress( x += 11 );
+ 
+         MetaBundle b;
+Index: metadata/mp4/taglib_mp4filetyperesolver.cpp
+===================================================================
+--- amarok/src/metadata/mp4/taglib_mp4filetyperesolver.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/metadata/mp4/taglib_mp4filetyperesolver.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -13,7 +13,7 @@
+     const char *ext = strrchr(fileName, '.');
+     if(ext && (!strcasecmp(ext, ".m4a")
+                 || !strcasecmp(ext, ".m4b") || !strcasecmp(ext, ".m4p")
+-                || !strcasecmp(ext, ".aac") || !strcasecmp(ext, ".mp4")
++                || !strcasecmp(ext, ".mp4")
+                 || !strcasecmp(ext, ".m4v") || !strcasecmp(ext, ".mp4v")))
+     {
+         MP4FileHandle h = MP4Read(fileName, 0);
+Index: metadata/m4a/taglib_mp4filetyperesolver.cpp
+===================================================================
+--- amarok/src/metadata/m4a/taglib_mp4filetyperesolver.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/metadata/m4a/taglib_mp4filetyperesolver.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -12,7 +12,7 @@
+     const char *ext = strrchr(fileName, '.');
+     if(ext && (!strcasecmp(ext, ".m4a")
+                 || !strcasecmp(ext, ".m4b") || !strcasecmp(ext, ".m4p")
+-                || !strcasecmp(ext, ".aac") || !strcasecmp(ext, ".mp4")
++                || !strcasecmp(ext, ".mp4")
+                 || !strcasecmp(ext, ".m4v") || !strcasecmp(ext, ".mp4v")))
+     {
+         return new TagLib::MP4::File(fileName, readProperties, propertiesStyle);
+Index: metadata/m4a/mp4skipbox.h
+===================================================================
+--- amarok/src/metadata/m4a/mp4skipbox.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/metadata/m4a/mp4skipbox.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -11,7 +11,7 @@
+     class Mp4SkipBox: public Mp4IsoBox
+     {
+     public:
+-      Mp4SkipBox( File* file, MP4::Fourcc fourcc, uint size, long offset );
++      Mp4SkipBox( TagLib::File* file, MP4::Fourcc fourcc, uint size, long offset );
+       ~Mp4SkipBox();
+ 
+     private:
+Index: metadata/m4a/mp4audiosampleentry.h
+===================================================================
+--- amarok/src/metadata/m4a/mp4audiosampleentry.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/metadata/m4a/mp4audiosampleentry.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -11,7 +11,7 @@
+     class Mp4AudioSampleEntry: public Mp4SampleEntry
+     {
+     public:
+-      Mp4AudioSampleEntry( File* file, MP4::Fourcc fourcc, uint size, long offset );
++      Mp4AudioSampleEntry( TagLib::File* file, MP4::Fourcc fourcc, uint size, long offset );
+       ~Mp4AudioSampleEntry();
+ 
+       //! function to get the number of channels
+Index: metadata/m4a/mp4propsproxy.cpp
+===================================================================
+--- amarok/src/metadata/m4a/mp4propsproxy.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/metadata/m4a/mp4propsproxy.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -26,22 +26,34 @@
+ 
+ TagLib::uint MP4::Mp4PropsProxy::seconds() const
+ {
+-  return static_cast<TagLib::uint>( d->mvhdbox->duration() / d->mvhdbox->timescale() );
++  if( d->mvhdbox )
++    return static_cast<TagLib::uint>( d->mvhdbox->duration() / d->mvhdbox->timescale() );
++  else
++    return 0;
+ }
+ 
+ TagLib::uint MP4::Mp4PropsProxy::channels() const
+ {
+-  return d->audiosampleentry->channels();
++  if( d->audiosampleentry )
++    return d->audiosampleentry->channels();
++  else
++    return 0;
+ }
+ 
+ TagLib::uint MP4::Mp4PropsProxy::sampleRate() const
+ {
+-  return (d->audiosampleentry->samplerate()>>16);
++  if( d->audiosampleentry )
++    return (d->audiosampleentry->samplerate()>>16);
++  else
++    return 0;
+ }
+ 
+ TagLib::uint MP4::Mp4PropsProxy::bitRate() const
+ {
+-  return (d->audiosampleentry->bitrate());
++  if( d->audiosampleentry )
++    return (d->audiosampleentry->bitrate());
++  else
++    return 0;
+ }
+ 
+ void MP4::Mp4PropsProxy::registerMvhd( MP4::Mp4MvhdBox* mvhdbox )
+Index: metadata/m4a/mp4sampleentry.h
+===================================================================
+--- amarok/src/metadata/m4a/mp4sampleentry.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/metadata/m4a/mp4sampleentry.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -11,7 +11,7 @@
+     class Mp4SampleEntry: public Mp4IsoBox
+     {
+     public:
+-      Mp4SampleEntry( File* file, MP4::Fourcc fourcc, uint size, long offset );
++      Mp4SampleEntry( TagLib::File* file, MP4::Fourcc fourcc, uint size, long offset );
+       ~Mp4SampleEntry();
+ 
+     public:
+Index: metadata/aac/Makefile.am
+===================================================================
+--- amarok/src/metadata/aac/Makefile.am	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 0)
++++ amarok/src/metadata/aac/Makefile.am	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -0,0 +1,12 @@
++SUBDIRS =
++METASOURCES        = AUTO
++INCLUDES = $(all_includes) $(taglib_includes)
++
++libtagaac_la_LDFLAGS  = $(all_libraries)
++noinst_LTLIBRARIES = libtagaac.la
++
++libtagaac_la_SOURCES = \
++                       aacfiletyperesolver.cpp
++
++noinst_HEADERS = \
++                         aacfiletyperesolver.h
+Index: metadata/aac/aacfiletyperesolver.cpp
+===================================================================
+--- amarok/src/metadata/aac/aacfiletyperesolver.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 0)
++++ amarok/src/metadata/aac/aacfiletyperesolver.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -0,0 +1,18 @@
++// (c) 2006 Martin Aumueller <aumuell at reserv.at>
++// See COPYING file for licensing information
++
++#include "aacfiletyperesolver.h"
++#include <taglib/mpegfile.h>
++
++TagLib::File *AACFileTypeResolver::createFile(const char *fileName,
++        bool readProperties,
++        TagLib::AudioProperties::ReadStyle propertiesStyle) const
++{
++    const char *ext = strrchr(fileName, '.');
++    if(ext && !strcasecmp(ext, ".aac"))
++    {
++        return new TagLib::MPEG::File(fileName, readProperties, propertiesStyle);
++    }
++
++    return 0;
++}
+Index: metadata/aac/aacfiletyperesolver.h
+===================================================================
+--- amarok/src/metadata/aac/aacfiletyperesolver.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 0)
++++ amarok/src/metadata/aac/aacfiletyperesolver.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -0,0 +1,18 @@
++// (c) 2006 Martin Aumueller <aumuell at reserv.at>
++// See COPYING file for licensing information
++
++#ifndef TAGLIB_AACFILETYPERESOLVER_H
++#define TAGLIB_AACFILETYPERESOLVER_H
++
++#include <taglib/tfile.h>
++#include <taglib/fileref.h>
++
++
++class AACFileTypeResolver : public TagLib::FileRef::FileTypeResolver
++{
++    TagLib::File *createFile(const char *fileName,
++            bool readAudioProperties,
++            TagLib::AudioProperties::ReadStyle audioPropertiesStyle) const;
++};
++
++#endif
+
+Property changes on: metadata/aac
+___________________________________________________________________
+Name: svn:ignore
+   + Makefile
+Makefile.in
+.libs
+.deps
+
+
+Index: metadata/tplugins.cpp
+===================================================================
+--- amarok/src/metadata/tplugins.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/metadata/tplugins.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -15,6 +15,7 @@
+ #include "wma/taglib_wmafiletyperesolver.h"
+ #include "rmff/taglib_realmediafiletyperesolver.h"
+ #include "audible/taglib_audiblefiletyperesolver.h"
++#include "aac/aacfiletyperesolver.h"
+ 
+ void registerTaglibPlugins()
+ {
+@@ -22,4 +23,5 @@
+     TagLib::FileRef::addFileTypeResolver(new WMAFileTypeResolver);
+     TagLib::FileRef::addFileTypeResolver(new RealMediaFileTypeResolver);
+     TagLib::FileRef::addFileTypeResolver(new AudibleFileTypeResolver);
++    TagLib::FileRef::addFileTypeResolver(new AACFileTypeResolver);
+ }
+Index: metadata/Makefile.am
+===================================================================
+--- amarok/src/metadata/Makefile.am	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/metadata/Makefile.am	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -6,7 +6,7 @@
+ MP4_LDADD = m4a/libtagm4a.la
+ endif
+ 
+-SUBDIRS = wma audible rmff $(MP4_SUBDIR)
++SUBDIRS = wma audible rmff $(MP4_SUBDIR) aac
+ 
+ 
+ INCLUDES           = $(all_includes) $(taglib_includes)
+@@ -24,4 +24,5 @@
+                      wma/libtagwma.la \
+                      rmff/libtagrealmedia.la \
+                      $(MP4_LDADD) \
++                     aac/libtagaac.la \
+                      audible/libtagaudible.la
+Index: scriptmanager.h
+===================================================================
+--- amarok/src/scriptmanager.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/scriptmanager.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -85,9 +85,12 @@
+        /** Custom Menu Click */
+        void customMenuClicked( const QString& message );
+ 
+-       /** Return whether a lyrics script is currently running */
+-       bool lyricsScriptRunning() const;
++       /** Returns the path of the spec file of the given script */
++       QString specForScript( const QString& name );
+ 
++       /** Return name of the lyrics script currently running, or QString::null if none */
++       QString lyricsScriptRunning() const;
++
+        /** Returns a list of all lyrics scripts */
+        QStringList lyricsScripts() const;
+ 
+@@ -97,8 +100,8 @@
+        /** Sends a fetchLyrics notification to retrieve lyrics from a specific page */
+        void notifyFetchLyricsByUrl( const QString& url );
+ 
+-       /** Return whether a transcode script is currently running */
+-       bool transcodeScriptRunning() const;
++       /** Return name of the transcode script currently running, or QString::null if none */
++       QString transcodeScriptRunning() const;
+ 
+        /** Sends a transcode notification to all scripts */
+        void notifyTranscode( const QString& srcUrl, const QString& filetype );
+Index: transferdialog.cpp
+===================================================================
+--- amarok/src/transferdialog.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/transferdialog.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -19,6 +19,8 @@
+ #include "pluginmanager.h"
+ #include "transferdialog.h"
+ 
++#include <qcheckbox.h>
++#include <qgroupbox.h>
+ #include <qlabel.h>
+ #include <qlayout.h>
+ #include <qvbox.h>
+@@ -30,9 +32,10 @@
+ #include <klocale.h>
+ #include <kpushbutton.h>
+ 
+-TransferDialog::TransferDialog( MediaDevice * mdev )
++TransferDialog::TransferDialog( MediaDevice *mdev )
+         : KDialogBase( amaroK::mainWindow(), "transferdialog", true, QString::null, Ok|Cancel, Ok )
+ {
++    m_dev = mdev;
+     m_accepted = false;
+     m_sort1LastIndex = m_sort2LastIndex = -1;
+ 
+@@ -53,20 +56,28 @@
+     directoryBox = new KLineEdit( QString::null, vbox, "transferdir_lineedit" );
+     */
+ 
+-    new QLabel( i18n( "Your music will be transferred to\n%1" )
+-                    .arg( transferDir ), vbox );
++    QGroupBox *location = new QGroupBox( 1, Qt::Vertical, i18n( "Music Location" ), vbox );
+ 
++    new QLabel( i18n( "Your music will be transferred to:\n%1" )
++                    .arg( transferDir ), location );
+ 
++    QVBox *vbox2 = new QVBox( vbox );
++    QSpacerItem *spacer = new QSpacerItem( 0, 25 );
++    QLayout *vlayout = vbox2->layout();
++    if( vlayout )
++        vlayout->addItem( spacer );
++
+     new QLabel( i18n( "You can have your music automatically grouped in\n"
+                       "a variety of ways. Each grouping will create\n"
+                       "directories based upon the specified criteria.\n"), vbox );
+ 
+-    m_label1 = new QLabel( i18n( "Select first grouping:\n" ), vbox );
+-    m_sort1 = new KComboBox( vbox );
+-    m_label2 = new QLabel( i18n( "Select second grouping:\n" ), vbox );
+-    m_sort2 = new KComboBox( vbox );
+-    m_label3 = new QLabel( i18n( "Select third grouping:\n" ), vbox ); 
+-    m_sort3 = new KComboBox( vbox );
++    QGroupBox *sorting = new QGroupBox( 6, Qt::Vertical, i18n( "Groupings" ), vbox );
++    m_label1 = new QLabel( i18n( "Select first grouping:\n" ), sorting );
++    m_sort1 = new KComboBox( sorting );
++    m_label2 = new QLabel( i18n( "Select second grouping:\n" ), sorting );
++    m_sort2 = new KComboBox( sorting );
++    m_label3 = new QLabel( i18n( "Select third grouping:\n" ), sorting ); 
++    m_sort3 = new KComboBox( sorting );
+ 
+     m_label2->setDisabled(true);
+     m_sort2->setDisabled(true);
+@@ -88,9 +99,21 @@
+         comboTemp->setCurrentItem( 0 );
+     }
+ 
+-    connect( m_sort1, SIGNAL(activated(int)), SLOT(sort1_activated(int)));
+-    connect( m_sort2, SIGNAL(activated(int)), SLOT(sort2_activated(int)));
++    connect( m_sort1, SIGNAL( activated(int) ), SLOT( sort1_activated(int)) );
++    connect( m_sort2, SIGNAL( activated(int) ), SLOT( sort2_activated(int)) );
+ 
++    QVBox *vbox3 = new QVBox( vbox );
++    QSpacerItem *spacer2 = new QSpacerItem( 0, 25 );
++    QLayout *vlayout2 = vbox3->layout();
++    if( vlayout2 )
++        vlayout2->addItem( spacer2 );
++
++    QGroupBox *options = new QGroupBox( 6, Qt::Vertical, i18n( "Options" ), vbox );
++
++    QCheckBox *convertSpaces = new QCheckBox( i18n( "Convert spaces to underscores" ), options );
++    convertSpaces->setChecked( mdev->getSpacesToUnderscores() );
++
++    connect( convertSpaces, SIGNAL( toggled(bool) ), this, SLOT( convertSpaces_toggled(bool) ) );
+ }
+ 
+ void
+@@ -98,6 +121,10 @@
+ {
+     m_accepted = true;
+     KDialogBase::slotOk();
++
++    m_dev->setFirstSort( m_sort1->currentText() );
++    m_dev->setSecondSort( m_sort2->currentText() );
++    m_dev->setThirdSort( m_sort3->currentText() );
+ }
+ 
+ void
+@@ -151,4 +178,10 @@
+     m_sort2LastIndex = index;
+ }
+ 
++void
++TransferDialog::convertSpaces_toggled( bool on )
++{
++    m_dev->setSpacesToUnderscores( on );
++}
++
+ #include "transferdialog.moc"
+Index: amarok_append.desktop
+===================================================================
+--- amarok/src/amarok_append.desktop	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/amarok_append.desktop	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -2,10 +2,12 @@
+ ServiceTypes=application/asx,application/x-ogg,audio/*
+ Actions=appendToPlaylist;appendAndPlay;queueTrack;
+ X-KDE-Submenu=amaroK
++X-KDE-Submenu[bn]=আমারক
+ 
+ [Desktop Action appendToPlaylist]
+ Name=Append to Playlist
+ Name[bg]=Добавяне към списъка с песни
++Name[bn]=সঙ্গীত-তালিকাতে সংযোজন করো
+ Name[br]=Ouzhpennañ d'ar roll tonioù
+ Name[cs]=Přidat do seznamu skladeb
+ Name[da]=Tilføj til spilleliste
+@@ -14,16 +16,20 @@
+ Name[fi]=Lisää soittolistaan
+ Name[fr]=Ajouter à la liste de lecture
+ Name[ga]=Iarcheangail le Seinmliosta
++Name[it]=Aggiungi alla playlist
+ Name[ja]=プレイリストに追加
++Name[nl]=Toevoegen aanafspeellijst
+ Name[pt]=Adicionar à Lista do amaroK
+ Name[pt_BR]=Adicionar à Lista do amaroK
+ Name[sv]=Lägg till i spellistan
++Name[zh_CN]=追加到播放列表
+ Icon=amarok
+ Exec=amarok -e %U
+ 
+ [Desktop Action appendAndPlay]
+ Name=Append & Play
+ Name[bg]=Добавяне и възпроизвеждане
++Name[bn]=সংযোজন করো এবং বাজাও
+ Name[br]=Ouzhpennañ ha seniñ
+ Name[cs]=Připojit a hrát
+ Name[da]=Tilføj og spil
+@@ -32,16 +38,20 @@
+ Name[fi]=Lisää soittolistaan ja toista
+ Name[fr]=Ajouter & Écouter
+ Name[ga]=Iarcheangail & Seinn
++Name[it]=Aggiungi & Riproduci
+ Name[ja]=追加して再生
++Name[nl]=Toevoegen en afspelen
+ Name[pt]=Adicionar & Reproduzir
+ Name[pt_BR]=Adicionar & Reproduzir
+ Name[sv]=Lägg till och spela
++Name[zh_CN]=追加并播放
+ Icon=amarok
+ Exec=dcop amarok playlist playMedia %U
+ 
+ [Desktop Action queueTrack]
+ Name=Queue Track
+ Name[bg]=Добавяне и възпроизвеждане
++Name[bn]=গান সারিবদ্ধ করো
+ Name[cs]=Zařadit skladbu
+ Name[da]=Sæt spor i kø
+ Name[el]=Εισαγωγή του κομματιού στην ουρά
+@@ -49,9 +59,12 @@
+ Name[fi]=Lisää jonoon
+ Name[fr]=Ajouter à la file d'attente
+ Name[ga]=Ciúáil Amhrán
++Name[it]=Accoda traccia
+ Name[ja]=トラックをキュー
++Name[nl]=Track in wachtrij plaatsen
+ Name[pt]=Pôr a Faixa na Fila
+ Name[pt_BR]=Pôr a Faixa na Fila
+ Name[sv]=Köa spår
++Name[zh_CN]=音轨排队
+ Icon=amarok
+ Exec=amarok --queue %U
+Index: statistics.cpp
+===================================================================
+--- amarok/src/statistics.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/statistics.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -139,7 +139,7 @@
+         else if( item->itemType() == StatisticsDetailedItem::ALBUM )
+         {
+             qb.clear();
+-            qb.addReturnValue( QueryBuilder::tabSong, QueryBuilder::valURL );
++            qb.initSQLDrag();
+             qb.addMatch( QueryBuilder::tabSong, QueryBuilder::valArtistID, artist );
+             qb.addMatch( QueryBuilder::tabSong, QueryBuilder::valAlbumID, album );
+             qb.sortBy( QueryBuilder::tabSong, QueryBuilder::valTrack );
+@@ -155,7 +155,7 @@
+             const uint artist_id = CollectionDB::instance()->artistID( item->url() );
+ 
+             qb.clear();
+-            qb.addReturnValue( QueryBuilder::tabSong, QueryBuilder::valURL );
++            qb.initSQLDrag();
+             qb.addMatch( QueryBuilder::tabSong, QueryBuilder::valArtistID, QString::number( artist_id ) );
+             qb.sortBy( QueryBuilder::tabSong, QueryBuilder::valTrack );
+             QStringList values = qb.run();
+@@ -170,7 +170,7 @@
+             const uint genre_id = CollectionDB::instance()->genreID( item->url() );
+ 
+             qb.clear();
+-            qb.addReturnValue( QueryBuilder::tabSong, QueryBuilder::valURL );
++            qb.initSQLDrag();
+             qb.addMatch( QueryBuilder::tabSong, QueryBuilder::valGenreID, QString::number( genre_id ) );
+             qb.sortBy( QueryBuilder::tabSong, QueryBuilder::valTrack );
+             QStringList values = qb.run();
+@@ -184,6 +184,7 @@
+     clearSelection();
+ 
+     drag->addDragObject( new KURLDrag( list, viewport() ) );
++    drag->setPixmap(CollectionDB::createDragPixmap(list), QPoint(CollectionDB::DRAGPIXMAP_OFFSET_X,CollectionDB::DRAGPIXMAP_OFFSET_Y));
+     drag->dragCopy();
+ }
+ 
+Index: scriptmanager.cpp
+===================================================================
+--- amarok/src/scriptmanager.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/scriptmanager.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -242,6 +242,16 @@
+ }
+ 
+ 
++QString
++ScriptManager::specForScript( const QString& name )
++{
++    QFileInfo info( m_scripts[name].url.path() );
++    const QString specPath = info.dirPath() + "/" + info.baseName() + ".spec";
++
++    return specPath;
++}
++
++
+ void
+ ScriptManager::notifyFetchLyrics( const QString& artist, const QString& title )
+ {
+@@ -268,27 +278,28 @@
+     return scripts;
+ }
+ 
+-bool
++
++QString
+ ScriptManager::lyricsScriptRunning() const
+ {
+     foreachType( ScriptMap, m_scripts )
+         if( it.data().process )
+             if( it.data().type == "lyrics" )
+-                return true;
++                return it.key();
+ 
+-    return false;
++    return QString::null;
+ }
+ 
+ 
+-bool
++QString
+ ScriptManager::transcodeScriptRunning() const
+ {
+     foreachType( ScriptMap, m_scripts )
+         if( it.data().process )
+             if( it.data().type == "transcode" )
+-                return true;
++                return it.key();
+ 
+-    return false;
++    return QString::null;
+ }
+ 
+ 
+@@ -507,13 +518,13 @@
+     QListViewItem* const li = m_gui->listView->currentItem();
+     const QString name = li->text( 0 );
+ 
+-    if( m_scripts[name].type == "lyrics" && lyricsScriptRunning() ) {
++    if( m_scripts[name].type == "lyrics" && lyricsScriptRunning() != QString::null ) {
+         KMessageBox::sorry( 0, i18n( "Another lyrics script is already running. "
+                                      "You may only run one lyrics script at a time." ) );
+         return false;
+     }
+ 
+-    if( m_scripts[name].type == "transcode" && transcodeScriptRunning() ) {
++    if( m_scripts[name].type == "transcode" && transcodeScriptRunning() != QString::null ) {
+         KMessageBox::sorry( 0, i18n( "Another transcode script is already running. "
+                                      "You may only run one transcode script at a time." ) );
+         return false;
+Index: mediadevice/vfat/amarok_vfat-mediadevice.desktop
+===================================================================
+--- amarok/src/mediadevice/vfat/amarok_vfat-mediadevice.desktop	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/mediadevice/vfat/amarok_vfat-mediadevice.desktop	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -2,19 +2,25 @@
+ Type=Service
+ Name=Generic VFAT Media Device
+ Name[bg]=Устройство VFAT
++Name[bn]=জেনেরিক ভিফ্যাট মিডিয়া ডিভাইস
++Name[cs]=Obecné VFAT mediální zařízení
+ Name[da]=Generisk VFAT-medieenhed
+ Name[el]=Γενική συσκευή πολυμέσων VFAT
+ Name[et]=Ãœldine VFAT meediaseade
+ Name[fi]=Yleinen VFAT-medialaite
+ Name[fr]=Périphérique de média générique VFAT
+ Name[ga]=Gléas Meán Ginearálta VFAT
++Name[it]=Dispositivo multimediale VFAT generico
+ Name[ja]=汎用VFATメディアデバイス
++Name[nl]=Generiek VFAT-media-apparaat
+ Name[pt]=Dispositivo Multimédia VFAT Genérico
+ Name[pt_BR]=Dispositivo Multimédia VFAT Genérico
+ Name[sv]=Generell VFAT-mediaenhet
++Name[zh_CN]=通用 VFAT 媒体设备
+ X-KDE-Library=libamarok_vfat-mediadevice
+ Comment=Plugin for amaroK
+ Comment[bg]=Приставка за amaroK
++Comment[bn]=আমারক-এর জন্য প্লাগিন
+ Comment[br]=Lugent evit amaroK
+ Comment[cs]=Modul pro amaroK
+ Comment[de]=Modul für amaroK
+@@ -59,4 +65,4 @@
+ X-KDE-amaroK-email=kde-dev at emailgoeshere.com
+ X-KDE-amaroK-rank=100
+ X-KDE-amaroK-version=1
+-X-KDE-amaroK-framework-version=16
++X-KDE-amaroK-framework-version=18
+Index: mediadevice/vfat/vfatmediadevice.cpp
+===================================================================
+--- amarok/src/mediadevice/vfat/vfatmediadevice.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/mediadevice/vfat/vfatmediadevice.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -46,6 +46,7 @@
+ 
+ #include <qcstring.h>
+ #include <qfile.h>
++#include <qstringx.h>
+ 
+ namespace amaroK { extern KConfig *config( const QString& ); }
+ 
+@@ -119,7 +120,14 @@
+     m_dirLister = new KDirLister();
+     m_dirLister->setNameFilter( "*.mp3 *.wav *.asf *.flac *.wma *.ogg" );
+     m_dirLister->setAutoUpdate( false );
++    m_spacesToUnderscores = false;
++    m_isInCopyTrack = false;
++    m_stopDirLister = false;
++    m_firstSort = "None";
++    m_secondSort = "None";
++    m_thirdSort = "None";
+     connect( m_dirLister, SIGNAL( newItems(const KFileItemList &) ), this, SLOT( newItems(const KFileItemList &) ) );
++    connect( m_dirLister, SIGNAL( completed() ), this, SLOT( dirListerCompleted() ) );
+ }
+ 
+ void
+@@ -150,9 +158,10 @@
+     if( !m_medium )
+     {
+         amaroK::StatusBar::instance()->longMessage( i18n( "VFAT Devices cannot be manually configured.  Ensure DBUS and HAL are running\n"
+-                                                         "and your kioslaves were built with DBUS and HAL support.  The device should be\n"
+-                                                         "autodetected; click the \"Manage Device Plugins...\" button and choose the\n"
+-                                                         "VFAT plugin.  Then ensure the device is mounted and click \"Connect\" again." ),
++                                                          "and your kioslaves were built with DBUS and HAL support.  The device should be\n"
++                                                          "autodetected; click the \"Manage Plugins...\" suboption of the Configure button\n"
++                                                          "in the Media Device tab and choose the VFAT plugin for the detected device.  Then\n"
++                                                          "ensure the device is mounted and click \"Connect\" again." ),
+                                                     KDE::StatusBar::Sorry );
+         return false;
+     }
+@@ -163,6 +172,7 @@
+                                                     KDE::StatusBar::Sorry );
+         return false;
+     }
++    m_actuallyVfat = m_medium->fsType() == "vfat" ? true : false;
+     m_connected = true;
+     m_transferDir = m_medium->mountPoint();
+     listDir( m_medium->mountPoint() );
+@@ -207,7 +217,7 @@
+      //the rename line edit has already changed the QListViewItem text
+     QCString dest = QFile::encodeName( getFullPath( item ) );
+ 
+-    debug() << "Renaming " << src << " to: " << dest << endl;
++    debug() << "Renaming: " << src << " to: " << dest << endl;
+ 
+     //TODO: do we want a progress dialog?  If so, set last false to true
+     KIO::NetAccess::file_move( KURL(src), KURL(dest), -1, false, false, false );
+@@ -224,8 +234,26 @@
+     DEBUG_BLOCK
+     if( !m_connected || name.isEmpty() ) return 0;
+ 
+-    QString fullPath = getFullPath( parent );
+-    const QCString dirPath = QFile::encodeName( fullPath == QString::null ? m_medium->mountPoint() + "/" + name : fullPath + "/" + name );
++    debug() << "newDirectory called with name = " << name << ", and parent = " << parent << endl;
++
++    bool equal = name.startsWith( m_medium->mountPoint(), true );
++
++    debug() << "name.startsWith(m_medium->mountPoint() = " << (equal ? "true" : "false") << endl;
++
++    QString fullPath = getFullPath( parent, true, ( equal ? false : true ), false );
++
++    if( fullPath == QString::null )
++        fullPath += m_medium->mountPoint();
++
++    debug() << "fullPath = " << fullPath << endl;
++
++    QCString dirPath;
++
++    if( equal )
++        dirPath = QFile::encodeName( cleanPath(name) );
++    else
++        dirPath = QFile::encodeName( fullPath + "/" + cleanPath(name) );
++
+     debug() << "Creating directory: " << dirPath << endl;
+ 
+     const KURL url( dirPath );
+@@ -236,7 +264,9 @@
+         return NULL;
+     }
+ 
+-    m_tmpParent = parent;
++    if( m_isInCopyTrack )
++        addTrackToList( MediaItem::DIRECTORY, cleanPath(name) );
++
+     return m_last;
+ 
+ }
+@@ -247,34 +277,90 @@
+     DEBUG_BLOCK
+     if( !directory || items.isEmpty() ) return;
+ 
++    MediaItem *previousTmpParent = static_cast<MediaItem *>(m_tmpParent);
++
++    m_stopDirLister = true;
+     m_tmpParent = directory;
+     for( QPtrListIterator<MediaItem> it(items); *it; ++it )
+     {
+-        QCString src  = QFile::encodeName( getFullPath( *it ) );
+-        QCString dest = QFile::encodeName( getFullPath( directory ) + "/" + (*it)->text(0) );
++        QCString src  = QFile::encodeName( getFullPath( *it, true, true, false ) );
++        QCString dest = QFile::encodeName( getFullPath( directory, true, true, false ) + "/" + (*it)->text(0) );
+         debug() << "Moving: " << src << " to: " << dest << endl;
+ 
+         const KURL srcurl(src);
+         const KURL desturl(dest);
+ 
+-        if ( KIO::NetAccess::file_move( srcurl, desturl, -1, false, false, m_parent ) )
++        if ( !KIO::NetAccess::file_move( srcurl, desturl, -1, false, false, m_parent ) )
+             debug() << "Failed moving " << src << " to " << dest << endl;
+-
+-        m_view->takeItem( *it );
+-        directory->insertItem( *it );
++        else
++        {
++            addTrackToList( (*it)->type(), (*it)->text(0) );
++            delete *it;
++        }
+     }
++    m_stopDirLister = false;
++    m_tmpParent = previousTmpParent;
+ }
+ 
+ /// Uploading
+ 
++void
++VfatMediaDevice::copyTrackSortHelper( const MetaBundle& bundle, QString& sort, QString& temp, QString& base )
++{
++    QListViewItem *it;
++    if( sort != "None" )
++    {
++        debug() << "sort = " << sort << endl;
++        temp = bundle.prettyText( bundle.columnIndex(sort) );
++        temp = ( temp == QString::null ? "Unknown" : temp );
++        temp = cleanPath( temp );
++        base += temp + "/";
++
++        if( !KIO::NetAccess::stat( KURL(base), m_udsentry, m_parent ) )
++            m_tmpParent = static_cast<MediaItem *>(newDirectory( temp, static_cast<MediaItem*>(m_tmpParent) ));
++        else
++        {
++            debug() << "m_tmpParent (firstSort) " << m_tmpParent << endl;
++            if( m_tmpParent)
++                it = m_tmpParent->firstChild();
++            else
++                it = m_view->firstChild();
++            while( it && it->text(0) != temp )
++            {
++                it = it->nextSibling();
++                debug() << "Looking for next in firstSort, temp = " << temp << ", text(0) = " << it->text(0) << endl;
++            }
++            m_tmpParent = static_cast<MediaItem *>( it );
++        }
++    }
++}
++
++
+ MediaItem *
+ VfatMediaDevice::copyTrackToDevice( const MetaBundle& bundle, const PodcastInfo* /*info*/ )
+ {
+     DEBUG_BLOCK
++    debug() << "dirlister autoupdate = " << (m_dirLister->autoUpdate() ? "true" : "false") << endl;
+     if( !m_connected ) return 0;
+ 
+-    const QString  newFilenameSansMountpoint = bundle.prettyTitle().remove( "'" ) + "." + bundle.type();
+-    const QString  newFilename = m_medium->mountPoint() + "/" + newFilenameSansMountpoint;
++    m_isInCopyTrack = true;
++
++    //TODO: dirlister's autoupdate should be off, but it's running, setting m_tmpParent to null and generally fucking everything up
++    //what to do?  not have it return null?  figure out how to actually turn the dirlister's autoupdate off?
++
++    debug() << "m_tmpParent = " << m_tmpParent << endl;
++    MediaItem *previousTmpParent = static_cast<MediaItem *>(m_tmpParent);
++
++    QString  newFilenameSansMountpoint = cleanPath( bundle.prettyTitle().remove( "'" ) + "." + bundle.type() );
++    QString  base = m_transferDir + "/";
++    QString  temp;
++
++    copyTrackSortHelper( bundle, m_firstSort, temp, base);
++    copyTrackSortHelper( bundle, m_secondSort, temp, base);
++    copyTrackSortHelper( bundle, m_thirdSort, temp, base);
++
++    QString  newFilename = base + newFilenameSansMountpoint;
++
+     const QCString src  = QFile::encodeName( bundle.url().path() );
+     const QCString dest = QFile::encodeName( newFilename ); // TODO: add to directory
+ 
+@@ -286,9 +372,13 @@
+     if( KIO::NetAccess::file_copy( srcurl, desturl, -1, false, false, m_parent) ) //success
+     {
+         addTrackToList( MediaItem::TRACK, newFilenameSansMountpoint );
++        m_tmpParent = previousTmpParent;
++        m_isInCopyTrack = false;
+         return m_last;
+     }
+ 
++    m_tmpParent = previousTmpParent;
++    m_isInCopyTrack = false;
+     return 0;
+ }
+ 
+@@ -297,8 +387,33 @@
+ MediaItem *
+ VfatMediaDevice::trackExists( const MetaBundle& bundle )
+ {
+-    const QString newFilenameSansMountpoint = bundle.prettyTitle().remove( "'" ) + "." + bundle.type();
+-    const QString newFilename = m_medium->mountPoint() + "/" + newFilenameSansMountpoint;
++    QString  newFilenameSansMountpoint = cleanPath( bundle.prettyTitle().remove( "'" ) + "." + bundle.type() );
++    QString  base = m_transferDir + "/";
++    QString  temp;
++
++    debug() << "m_firstSort = " << m_firstSort << endl;
++    if( m_firstSort != "None")
++    {
++        temp = bundle.prettyText( bundle.columnIndex(m_firstSort) );
++        base += cleanPath( ( temp == QString::null ? "Unknown" : temp ) ) + "/";
++    }
++
++    debug() << "m_secondSort = " << m_secondSort << endl;
++    if( m_secondSort != "None")
++    {
++        temp = bundle.prettyText( bundle.columnIndex(m_secondSort) );
++        base += cleanPath( ( temp == QString::null ? "Unknown" : temp ) ) + "/";
++    }
++
++    debug() << "m_thirdSort = " << m_thirdSort << endl;
++    if( m_thirdSort != "None")
++    {
++        temp = bundle.prettyText( bundle.columnIndex(m_thirdSort) );
++        base += cleanPath( ( temp == QString::null ? "Unknown" : temp ) ) + "/";
++    }
++
++    QString  newFilename = base + newFilenameSansMountpoint;
++
+     if ( KIO::NetAccess::stat( KURL(newFilename), m_udsentry, m_parent ) )
+     {
+         QListViewItemIterator it( m_view );
+@@ -409,7 +524,6 @@
+ 
+     QString path = getFullPath( item );
+     listDir( path );
+-    //m_tmpParent = 0;
+ }
+ 
+ void
+@@ -438,18 +552,29 @@
+ {
+     DEBUG_BLOCK
+     //iterate over items, calling addTrackToList
++    if( m_stopDirLister || m_isInCopyTrack )
++        return;
++
+     QPtrListIterator<KFileItem> it( items );
+     KFileItem *kfi;
+     while ( (kfi = it.current()) != 0 ) {
+         ++it;
+         addTrackToList( kfi->isFile() ? MediaItem::TRACK : MediaItem::DIRECTORY, kfi->name(), 0 );
+     }
++}
+ 
++void
++VfatMediaDevice::dirListerCompleted()
++{
++    DEBUG_BLOCK
++    if( !m_stopDirLister && !m_isInCopyTrack)
++        m_tmpParent = NULL;
+ }
+ 
+ int
+ VfatMediaDevice::addTrackToList( int type, QString name, int /*size*/ )
+ {
++    DEBUG_BLOCK
+     m_tmpParent ?
+         m_last = new VfatMediaItem( m_tmpParent ):
+         m_last = new VfatMediaItem( m_view );
+@@ -497,9 +622,6 @@
+         usleep( 10000 );
+         kapp->processEvents( 100 );
+         count++;
+-        if (count % 30 == 0){
+-            debug() << "KDiskFreeSp taking a long time, perhaps something went wrong?" << endl;
+-        }
+         if (count > 120){
+             debug() << "KDiskFreeSp taking too long.  Returning false from getCapacity()" << endl;
+             return false;
+@@ -527,24 +649,33 @@
+ /// Helper functions
+ 
+ QString
+-VfatMediaDevice::getFullPath( const QListViewItem *item, const bool getFilename )
++VfatMediaDevice::getFullPath( const QListViewItem *item, const bool getFilename, const bool prependMount, const bool clean )
+ {
++    DEBUG_BLOCK
+     if( !item ) return QString::null;
+ 
+     QString path;
+ 
+-    if ( getFilename ) path = item->text(0);
++    if ( getFilename && clean )
++        path = cleanPath(item->text(0));
++    else if( getFilename )
++        path = item->text(0);
+ 
+     QListViewItem *parent = item->parent();
+ 
+     while( parent )
+     {
+         path.prepend( "/" );
+-        path.prepend( parent->text(0) );
++        path.prepend( ( clean ? cleanPath(parent->text(0)) : parent->text(0) ) );
+         parent = parent->parent();
+     }
+-    path.prepend( m_medium->mountPoint() + "/" );
+ 
++    debug() << "path before prependMount = " << path << endl;
++    if( prependMount )
++        path.prepend( m_medium->mountPoint() + "/" );
++
++    debug() << "path after prependMount = " << path << endl;
++
+     return path;
+ 
+ }
+@@ -593,6 +724,7 @@
+                 break;
+ 
+             case TRANSFER_HERE:
++                m_tmpParent = item;
+                 if( item->type() == MediaItem::DIRECTORY )
+                 {
+                     m_transferDir = getFullPath( item, true );
+@@ -603,7 +735,6 @@
+                     if (m_transferDir != QString::null)
+                         m_transferDir = m_transferDir.remove( m_transferDir.length() - 1, 1 );
+                 }
+-                debug() << "New transfer dir is: " << m_transferDir << endl;
+                 emit startTransfer();
+                 break;
+         }
+@@ -628,7 +759,7 @@
+ 
+             case TRANSFER_HERE:
+                 m_transferDir = m_medium->mountPoint();
+-                debug() << "New transfer dir is: " << m_transferDir << endl;
++                m_tmpParent = NULL;
+                 emit startTransfer();
+                 break;
+ 
+@@ -636,4 +767,69 @@
+     }
+ }
+ 
++//So what's better, keep instantiating a new OrganizeCollectionDialog, or duplicate code?
++//or maybe make this a static function somewhere?
++QString VfatMediaDevice::cleanPath( const QString &component )
++{
++    QString result = component;
++
++    if( m_actuallyVfat )
++    {
++        // german umlauts
++        result.replace( QChar(0x00e4), "ae" ).replace( QChar(0x00c4), "Ae" );
++        result.replace( QChar(0x00f6), "oe" ).replace( QChar(0x00d6), "Oe" );
++        result.replace( QChar(0x00dc), "ue" ).replace( QChar(0x00fc), "Ue" );
++        result.replace( QChar(0x00df), "ss" );
++
++        // some strange accents
++        result.replace( QChar(0x00e7), "c" ).replace( QChar(0x00c7), "C" );
++        result.replace( QChar(0x00fd), "y" ).replace( QChar(0x00dd), "Y" );
++        result.replace( QChar(0x00f1), "n" ).replace( QChar(0x00d1), "N" );
++
++        // accented vowels
++        QChar a[] = { 'a', 0xe0,0xe1,0xe2,0xe3,0xe5, 0 };
++        QChar A[] = { 'A', 0xc0,0xc1,0xc2,0xc3,0xc5, 0 };
++        QChar E[] = { 'e', 0xe8,0xe9,0xea,0xeb, 0 };
++        QChar e[] = { 'E', 0xc8,0xc9,0xca,0xcb, 0 };
++        QChar i[] = { 'i', 0xec,0xed,0xee,0xef, 0 };
++        QChar I[] = { 'I', 0xcc,0xcd,0xce,0xcf, 0 };
++        QChar o[] = { 'o', 0xf2,0xf3,0xf4,0xf5,0xf8, 0 };
++        QChar O[] = { 'O', 0xd2,0xd3,0xd4,0xd5,0xd8, 0 };
++        QChar u[] = { 'u', 0xf9,0xfa,0xfb, 0 };
++        QChar U[] = { 'U', 0xd9,0xda,0xdb, 0 };
++        QChar nul[] = { 0 };
++        QChar *replacements[] = { a, A, e, E, i, I, o, O, u, U, nul };
++
++        for( uint i = 0; i < result.length(); i++ )
++        {
++            QChar c = result.ref( i );
++            for( uint n = 0; replacements[n][0] != QChar(0); n++ )
++            {
++                for( uint k=0; replacements[n][k] != QChar(0); k++ )
++                {
++                    if( replacements[n][k] == c )
++                    {
++                        c = replacements[n][0];
++                    }
++                }
++            }
++            if( c > QChar(0x7f) || c == QChar(0) )
++            {
++                c = '_';
++            }
++            result.ref( i ) = c;
++        }
++    }
++
++    result.simplifyWhiteSpace();
++    if( m_spacesToUnderscores )
++        result.replace( QRegExp( "\\s" ), "_" );
++    if( m_actuallyVfat )
++        result.replace( "?", "_" ).replace( "\\", "_" ).replace( "*", "_" ).replace( ":", "_" );
++
++    result.replace( "/", "-" );
++
++    return result;
++}
++
+ #include "vfatmediadevice.moc"
+Index: mediadevice/vfat/vfatmediadevice.h
+===================================================================
+--- amarok/src/mediadevice/vfat/vfatmediadevice.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/mediadevice/vfat/vfatmediadevice.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -72,6 +72,7 @@
+         void              expandItem( QListViewItem *item );
+         void              foundMountPoint( const QString & mountPoint, unsigned long kBSize, unsigned long kBUsed, unsigned long kBAvail );
+         void              newItems( const KFileItemList &items );
++        void              dirListerCompleted();
+ 
+     private:
+         enum              Error { ERR_ACCESS_DENIED, ERR_CANNOT_RENAME, ERR_DISK_FULL, ERR_COULD_NOT_WRITE };
+@@ -82,6 +83,7 @@
+ 
+         // file transfer
+         void              downloadSelectedItems();
++        void              copyTrackSortHelper( const MetaBundle& bundle, QString& sort, QString& temp, QString& base );
+ 
+         // listDir
+         void              listDir( const QString &dir );
+@@ -93,8 +95,10 @@
+         //int               setProgressInfo( struct vfat_transfer_status *progress );
+         // Will iterate over parents and add directory name to the item.
+         // getFilename = false will return only parent structure, as opposed to returning the filename as well
+-        QString           getFullPath( const QListViewItem *item, const bool getFilename = true );
++        QString           getFullPath( const QListViewItem *item, const bool getFilename = true, const bool prependMount = true, const bool clean = true );
+ 
++        QString           cleanPath( const QString &component );
++
+         bool              m_connected;
+ 
+         VfatMediaItem     *m_last;
+@@ -108,6 +112,10 @@
+         KIO::UDSEntry     m_udsentry;
+ 
+         TransferDialog    *m_td;
++        bool              m_actuallyVfat;
++        bool              m_isInCopyTrack;
++        bool              m_stopDirLister;
++
+ };
+ 
+ #endif /*AMAROK_VFATMEDIADEVICE_H*/
+Index: mediadevice/fs/amarok_fs-mediadevice.desktop
+===================================================================
+--- amarok/src/mediadevice/fs/amarok_fs-mediadevice.desktop	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/mediadevice/fs/amarok_fs-mediadevice.desktop	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -3,11 +3,16 @@
+ Name=File System Media Device
+ Name[bg]=Устройство за файлова система
+ Name[da]=Filsystem-medieenhed
++Name[el]=Συσκευή πολυμέσων συστήματος αρχείων
+ Name[fr]=Système de fichiers du périphérique de média
+ Name[ga]=Gléas Meán Chóras Comhad
++Name[it]=Filesystem dispositivo multimediale
++Name[ja]=ファイルシステム メディアデバイス
++Name[nl]=Bestandssysteem media-apparaat
+ Name[pt]=Dispositivo Multimédia de Sistema de Ficheiros
+ Name[pt_BR]=Dispositivo Multimédia de Sistema de Ficheiros
+ Name[sv]=Mediaenhet med filsystem
++Name[zh_CN]=文件系统媒体设备
+ ServiceTypes=amaroK/Plugin
+ 
+ X-KDE-Library=libamarok_fs-mediadevice
+@@ -17,4 +22,4 @@
+ X-KDE-amaroK-email=amarok-devel at lists.sourceforge.net
+ X-KDE-amaroK-rank=100
+ X-KDE-amaroK-version=1
+-X-KDE-amaroK-framework-version=16
++X-KDE-amaroK-framework-version=18
+Index: mediadevice/ipod/amarok_ipod-mediadevice.desktop
+===================================================================
+--- amarok/src/mediadevice/ipod/amarok_ipod-mediadevice.desktop	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/mediadevice/ipod/amarok_ipod-mediadevice.desktop	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -2,6 +2,7 @@
+ Type=Service
+ Name=Apple iPod Media Device
+ Name[bg]=Устройство Apple iPod
++Name[bn]=অ্যাপেল আই-পড মিডিয়া ডিভাইস
+ Name[cs]=Mediální zařízení Apple iPod
+ Name[da]=Apple iPod-medieenhed
+ Name[el]=Συσκευή πολυμέσων Apple iPod
+@@ -9,16 +10,20 @@
+ Name[fi]=Apple iPod -medialaite
+ Name[fr]=Périphérique de média Apple iPod
+ Name[ga]=Gléas Meán iPod Apple
++Name[it]=Dispositivo multimediale Apple iPod
+ Name[ja]=Apple iPod メディアデバイス
++Name[nl]=Apple iPod media-apparaat
+ Name[pa]=Apple iPod ਮੀਡਿਆ ਜੰਤਰ
+ Name[pt]=Dispositivo Multimédia Apple iPod
+ Name[pt_BR]=Dispositivo Multimédia Apple iPod
+ Name[ru]=Мультимедиа-устройство Apple iPod
+ Name[sv]=Apple iPod-mediaenhet
+ Name[xx]=xxApple iPod Media Devicexx
++Name[zh_CN]=Apple iPod 媒体设备
+ X-KDE-Library=libamarok_ipod-mediadevice
+ Comment=Plugin for amaroK
+ Comment[bg]=Приставка за amaroK
++Comment[bn]=আমারক-এর জন্য প্লাগিন
+ Comment[br]=Lugent evit amaroK
+ Comment[cs]=Modul pro amaroK
+ Comment[de]=Modul für amaroK
+@@ -63,4 +68,4 @@
+ X-KDE-amaroK-email=aumuell at reserv.at
+ X-KDE-amaroK-rank=100
+ X-KDE-amaroK-version=1
+-X-KDE-amaroK-framework-version=16
++X-KDE-amaroK-framework-version=18
+Index: mediadevice/ipod/ipodmediadevice.cpp
+===================================================================
+--- amarok/src/mediadevice/ipod/ipodmediadevice.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/mediadevice/ipod/ipodmediadevice.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -20,6 +20,7 @@
+ #include <tagdialog.h>
+ #include <threadweaver.h>
+ #include <metadata/tplugins.h>
++#include <hintlineedit.h>
+ 
+ #include <kapplication.h>
+ #include <kmountpoint.h>
+@@ -279,21 +280,22 @@
+         track->podcastrss = g_strdup( podcastInfo->rss.utf8() );
+         //track->category = g_strdup( "Unknown" );
+         track->time_released = itdb_time_host_to_mac( podcastInfo->date.toTime_t() );
++        //track->compilation = 0x01; // this should have made the ipod play a sequence of podcasts
+     }
+     else
+     {
+         track->unk176 = 0x00010000; // for non-podcasts
+-    }
+ 
+-    uint albumID = CollectionDB::instance()->albumID( bundle.album(), false );
+-    if( CollectionDB::instance()->albumIsCompilation( QString::number( albumID ) ) )
+-    {
+-        track->compilation = 0x01;
++        uint albumID = CollectionDB::instance()->albumID( bundle.album(), false );
++        if( CollectionDB::instance()->albumIsCompilation( QString::number( albumID ) ) )
++        {
++            track->compilation = 0x01;
++        }
++        else
++        {
++            track->compilation = 0x00;
++        }
+     }
+-    else
+-    {
+-        track->compilation = 0x00;
+-    }
+ 
+     m_dbChanged = true;
+ 
+@@ -713,9 +715,10 @@
+     {
+         ok = false;
+         msg = i18n( "Media Device: iPod mounted at %1 already locked! " ).arg( mountpoint );
+-        msg += i18n( "A common problem is that your iPod is connected twice, "
++        msg += i18n( "This problem is common with subfs/submount.<br>"
++                     "But it could also be that your iPod is connected twice, "
+                      "once because of being manually connected "
+-                     "and a second time because of being auto-detected thereafter. " );
++                     "and a second time because of being auto-detected thereafter.<br>" );
+         msg += i18n( "If you are sure that this is an error, then remove the file %1 and try again." ).arg( mountpoint + "/amaroK.lock" );
+ 
+     }
+@@ -1993,13 +1996,14 @@
+ {
+     m_mntpntLabel = new QLabel( parent );
+     m_mntpntLabel->setText( i18n( "&Mount point:" ) );
+-    m_mntpntEdit = new QLineEdit( m_mntpnt, parent );
++    m_mntpntEdit = new HintLineEdit( m_mntpnt, parent );
++    static_cast<HintLineEdit *>(m_mntpntEdit)->setHint( i18n( "(Not used when device is auto-detected)" ) );
+     m_mntpntLabel->setBuddy( m_mntpntEdit );
+-    QToolTip::add( m_mntpntEdit, i18n( "Set the mount point of your device here, when empty autodetection is tried." ) );
++    QToolTip::add( m_mntpntEdit, i18n( "Set the mount point of your device here, if empty auto-detection is tried." ) );
+ 
+     m_autoDeletePodcastsCheck = new QCheckBox( parent );
+     m_autoDeletePodcastsCheck->setText( i18n( "&Automatically delete podcasts" ) );
+-    QToolTip::add( m_autoDeletePodcastsCheck, i18n( "Automatically delete podcast shows already played on connect" ) );
++    QToolTip::add( m_autoDeletePodcastsCheck, i18n( "Automatically delete podcast shows already played when connecting device" ) );
+     m_autoDeletePodcastsCheck->setChecked( m_autoDeletePodcasts );
+ 
+     m_syncStatsCheck = new QCheckBox( parent );
+Index: mediadevice/ifp/amarok_ifp-mediadevice.desktop
+===================================================================
+--- amarok/src/mediadevice/ifp/amarok_ifp-mediadevice.desktop	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/mediadevice/ifp/amarok_ifp-mediadevice.desktop	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -2,6 +2,7 @@
+ Type=Service
+ Name=iRiver iFP Media Device
+ Name[bg]=Устройство iRiver iFP
++Name[bn]=আই-রিভার আই-এফ-পি মিডিয়া ডিভাইস
+ Name[cs]=Mediální zařízení iRiver iFP
+ Name[da]=iRiver iFP-medieenhed
+ Name[el]=Συσκευή πολυμέσων iRiver iFP
+@@ -9,16 +10,20 @@
+ Name[fi]=iRiver iFP -medialaite
+ Name[fr]=Périphérique de média iRiver iFP
+ Name[ga]=Gléas Meán iFP iRiver
++Name[it]=Dispositivo multimediale iRiver iFP
+ Name[ja]=iRiver iFP メディアデバイス
++Name[nl]=iRiver iFP media-apparaat
+ Name[pa]=iRiver iFP ਮੀਡਿਆ ਜੰਤਰ
+ Name[pt]=Dispositivo Multimédia iRiver iFP
+ Name[pt_BR]=Dispositivo Multimédia iRiver iFP
+ Name[ru]=Мультимедиа-устройство iRiver iFP
+ Name[sv]=iRiver iFP-mediaenhet
+ Name[xx]=xxiRiver iFP Media Devicexx
++Name[zh_CN]=iRiver iFP 媒体设备
+ X-KDE-Library=libamarok_ifp-mediadevice
+ Comment=Plugin for amaroK
+ Comment[bg]=Приставка за amaroK
++Comment[bn]=আমারক-এর জন্য প্লাগিন
+ Comment[br]=Lugent evit amaroK
+ Comment[cs]=Modul pro amaroK
+ Comment[de]=Modul für amaroK
+@@ -63,4 +68,4 @@
+ X-KDE-amaroK-email=me at sebruiz.net
+ X-KDE-amaroK-rank=100
+ X-KDE-amaroK-version=1
+-X-KDE-amaroK-framework-version=16
++X-KDE-amaroK-framework-version=18
+Index: tagdialogbase.ui
+===================================================================
+--- amarok/src/tagdialogbase.ui	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/tagdialogbase.ui	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -609,38 +609,19 @@
+                     <property name="name">
+                         <cstring>unnamed</cstring>
+                     </property>
+-                    <widget class="KIntSpinBox" row="0" column="2">
++                    <widget class="QLabel" row="0" column="0">
+                         <property name="name">
+-                            <cstring>kIntSpinBox_score</cstring>
++                            <cstring>trackArtistAlbumLabel2</cstring>
+                         </property>
+-                        <property name="sizePolicy">
+-                            <sizepolicy>
+-                                <hsizetype>7</hsizetype>
+-                                <vsizetype>0</vsizetype>
+-                                <horstretch>0</horstretch>
+-                                <verstretch>0</verstretch>
+-                            </sizepolicy>
++                        <property name="text">
++                            <string>Track by Artist on Album</string>
+                         </property>
+-                        <property name="specialValueText">
+-                            <string></string>
++                        <property name="alignment">
++                            <set>WordBreak|AlignVCenter</set>
+                         </property>
+-                        <property name="maxValue">
+-                            <number>100</number>
+-                        </property>
+-                        <property name="value">
+-                            <number>0</number>
+-                        </property>
+                     </widget>
+-                    <widget class="QLabel" row="0" column="1">
++                    <spacer row="4" column="2">
+                         <property name="name">
+-                            <cstring>playcountLabel2</cstring>
+-                        </property>
+-                        <property name="text">
+-                            <string>Score:</string>
+-                        </property>
+-                    </widget>
+-                    <spacer row="3" column="2">
+-                        <property name="name">
+                             <cstring>spacer3_2</cstring>
+                         </property>
+                         <property name="orientation">
+@@ -656,7 +637,7 @@
+                             </size>
+                         </property>
+                     </spacer>
+-                    <widget class="QLabel" row="2" column="0" rowspan="1" colspan="3">
++                    <widget class="QLabel" row="3" column="0" rowspan="1" colspan="3">
+                         <property name="name">
+                             <cstring>statisticsLabel</cstring>
+                         </property>
+@@ -667,19 +648,8 @@
+                             <set>WordBreak|AlignTop</set>
+                         </property>
+                     </widget>
+-                    <widget class="QLabel" row="0" column="0">
++                    <spacer row="2" column="0">
+                         <property name="name">
+-                            <cstring>trackArtistAlbumLabel2</cstring>
+-                        </property>
+-                        <property name="text">
+-                            <string>Track by Artist on Album</string>
+-                        </property>
+-                        <property name="alignment">
+-                            <set>WordBreak|AlignVCenter</set>
+-                        </property>
+-                    </widget>
+-                    <spacer row="1" column="0">
+-                        <property name="name">
+                             <cstring>spacer5</cstring>
+                         </property>
+                         <property name="orientation">
+@@ -695,6 +665,49 @@
+                             </size>
+                         </property>
+                     </spacer>
++                    <widget class="QLabel" row="0" column="1">
++                        <property name="name">
++                            <cstring>scoreLabel</cstring>
++                        </property>
++                        <property name="text">
++                            <string>Score:</string>
++                        </property>
++                    </widget>
++                    <widget class="QLabel" row="1" column="1">
++                        <property name="name">
++                            <cstring>ratingLabel</cstring>
++                        </property>
++                        <property name="text">
++                            <string>Rating:</string>
++                        </property>
++                    </widget>
++                    <widget class="KIntSpinBox" row="0" column="2">
++                        <property name="name">
++                            <cstring>kIntSpinBox_score</cstring>
++                        </property>
++                        <property name="sizePolicy">
++                            <sizepolicy>
++                                <hsizetype>7</hsizetype>
++                                <vsizetype>0</vsizetype>
++                                <horstretch>0</horstretch>
++                                <verstretch>0</verstretch>
++                            </sizepolicy>
++                        </property>
++                        <property name="specialValueText">
++                            <string></string>
++                        </property>
++                        <property name="maxValue">
++                            <number>100</number>
++                        </property>
++                        <property name="value">
++                            <number>0</number>
++                        </property>
++                    </widget>
++                    <widget class="KComboBox" row="1" column="2">
++                        <property name="name">
++                            <cstring>kComboBox_rating</cstring>
++                        </property>
++                    </widget>
+                 </grid>
+             </widget>
+         </widget>
+Index: osd.cpp
+===================================================================
+--- amarok/src/osd.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/osd.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -508,7 +508,7 @@
+                 QString append = ( i == 0 ) ? ""
+                                : ( n > 1 && i == n / 2 ) ? "\n"
+                                : ( parens.contains( column ) || parens.contains( availableTags.at( i - 1 ) ) ) ? " "
+-                               : " - ";
++                               : i18n(" - ");
+                 append += ( parens.contains( column ) ? "(%1)" : "%1" );
+                 text += append.arg( tags.at( column + 1 ) );
+             }
+Index: statusbar/statusBarBase.cpp
+===================================================================
+--- amarok/src/statusbar/statusBarBase.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/statusbar/statusBarBase.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -251,7 +251,7 @@
+             }
+ 
+         if( count == 1 )
+-            m_mainTextLabel->setText( bar->description() + "..." );
++            m_mainTextLabel->setText( bar->description() + i18n("...") );
+         else
+             m_mainTextLabel->setText( i18n("Multiple background-tasks running") );
+     }
+Index: party.h
+===================================================================
+--- amarok/src/party.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/party.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -66,6 +66,7 @@
+ 
+     public slots:
+         void    repopulate();
++        void    disable();
+         void    editActiveParty();
+ 
+     signals:
+Index: organizecollectiondialog.ui
+===================================================================
+--- amarok/src/organizecollectiondialog.ui	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/organizecollectiondialog.ui	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -502,6 +502,7 @@
+ </includes>
+ <variables>
+     <variable>MetaBundle previewBundle;</variable>
++    <variable>bool detailed;</variable>
+ </variables>
+ <signals>
+     <signal>updatePreview( const QString &amp; )</signal>
+@@ -510,12 +511,14 @@
+     <slot>preview( const QString &amp; format )</slot>
+     <slot>update( int dummy )</slot>
+     <slot>update( const QString &amp; dummy )</slot>
++    <slot>slotDetails()</slot>
+ </slots>
+ <functions>
+     <function returnType="QString">buildDestination( const QString &amp; format, const MetaBundle &amp; mb )</function>
+     <function returnType="QString">buildFormatString()</function>
+     <function>setPreviewBundle( const MetaBundle &amp; bundle )</function>
+     <function returnType="QString">cleanPath( const QString &amp; component )</function>
++    <function>init()</function>
+ </functions>
+ <layoutdefaults spacing="6" margin="0"/>
+ <includehints>
+Index: database_refactor/sqlite/amarok_sqlite_dbengine_plugin.desktop
+===================================================================
+--- amarok/src/database_refactor/sqlite/amarok_sqlite_dbengine_plugin.desktop	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/database_refactor/sqlite/amarok_sqlite_dbengine_plugin.desktop	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -1,6 +1,7 @@
+ [Desktop Entry]
+ Type=Service
+ Name=SQLite DBEngine
++Name[bn]=এসকিউ-লাইট ডিবি-ইঞ্জিন
+ Name[br]=Keflusker DB SQLite
+ Name[da]=SQLite DB-motor
+ Name[de]=SQLite
+@@ -30,6 +31,7 @@
+ X-KDE-Library=libamarok_sqlite_dbengine_plugin
+ Comment=Plugin for amaroK
+ Comment[bg]=Приставка за amaroK
++Comment[bn]=আমারক-এর জন্য প্লাগিন
+ Comment[br]=Lugent evit amaroK
+ Comment[cs]=Modul pro amaroK
+ Comment[de]=Modul für amaroK
+Index: covermanager.cpp
+===================================================================
+--- amarok/src/covermanager.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/covermanager.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -248,7 +248,7 @@
+ {
+     KWin::setType( winId(), NET::Utility );
+     kapp->setTopWidget( this );
+-    setCaption( kapp->makeStdCaption( artist + i18n(" - ") + album ) );
++    setCaption( kapp->makeStdCaption( i18n("%1 - %2").arg( artist, album ) ) );
+ 
+     m_layout = new QHBoxLayout( this );
+     m_layout->setAutoAdd(true);
+@@ -769,9 +769,10 @@
+             QStringList values = QStringList::split( " @@@ ", m_fetchCovers[0], true );    //get artist and album name
+             if ( values.count() >= 2 )
+             {
+-                text = i18n( "Fetching cover for " );
+-        if ( !values[0].isEmpty() ) text += values[0] + i18n(" - ");
+-        text += values[1] + i18n("...");
++                if( values[0].isEmpty() )
++                    text = i18n( "Fetching cover for %1..." ).arg( values[1] );
++                else
++                    text = i18n( "Fetching cover for %1 - %2..." ).arg( values[0], values[1] );
+             }
+         }
+         else if( m_fetchingCovers ) {
+@@ -967,10 +968,10 @@
+         int i = 0;
+         while ( fm.width( nameJustify + str[ i ] ) < textRect().width() )
+             nameJustify += str[ i++ ];
+-        nameJustify.remove( 0, 3 );
++        nameJustify.remove( 0, i18n("...").length() );
+         if ( nameJustify.isEmpty() )
+             nameJustify = str.left( 1 );
+-    nameJustify += i18n("...");
++        nameJustify += i18n("...");
+         str = nameJustify;
+     }
+     p->setPen( cg.text() );
+Index: amarok_plugin.desktop
+===================================================================
+--- amarok/src/amarok_plugin.desktop	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/amarok_plugin.desktop	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -3,6 +3,7 @@
+ X-KDE-ServiceType=amaroK/Plugin
+ Comment=Plugin for amaroK
+ Comment[bg]=Приставка за amaroK
++Comment[bn]=আমারক-এর জন্য প্লাগিন
+ Comment[br]=Lugent evit amaroK
+ Comment[cs]=Modul pro amaroK
+ Comment[de]=Modul für amaroK
+Index: contextbrowser.cpp
+===================================================================
+--- amarok/src/contextbrowser.cpp	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/contextbrowser.cpp	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -1066,6 +1066,8 @@
+ 
+     const MetaBundle &currentTrack = EngineController::instance()->bundle();
+ 
++    const bool showRating = Playlist::instance()->visibleColumns().contains( MetaBundle::Rating );
++
+     QString artist;
+     if( b->m_browseArtists )
+     {
+@@ -1327,7 +1329,7 @@
+             const QString scoreBox =
+             "<div align='right'>"
+                 "<table class='scoreBox' border='0' cellspacing='0' cellpadding='0' title='"
+-                    + QString( true ? i18n( "Score:" ) + " %2, " + i18n( "Rating:" ) + " %4'>" : i18n( "Score" ) + " %2'>" ) +
++                    + ( showRating ? i18n( "Score: %2, Rating: %4" ) : i18n( "Score: %2" ) ) + "'>" +
+                     "<tr>"
+                         "<td nowrap>%1&nbsp;</td>"
+                         "<td>"
+@@ -1348,7 +1350,7 @@
+                         "<span>%4</span>"
+                         )
+                     .arg( i18n( "Track played once", "Track played %n times", playtimes ),
+-                        scoreBox.arg( score ).arg( score ).arg( true ? ( rating * 10 ) : ( score / 2 ) ).arg( rating ),
++                        scoreBox.arg( score ).arg( score ).arg( showRating ? ( rating * 10 ) : ( score / 2 ) ).arg( rating ),
+                         i18n( "Last played: %1" ).arg( amaroK::verboseTimeSince( lastPlay ) ),
+                         i18n( "First played: %1" ).arg( amaroK::verboseTimeSince( firstPlay ) ) ) );
+         }
+@@ -1521,12 +1523,12 @@
+                             + i18n("&#xa0;&#8211; ") +
+                             "</span><span class='album-song-title'>" + escapeHTML( values[i + 1] ) + "</span>"
+                             "</a>"
+-                            "</td>"
+-                            "<td class='sbtext' width='1' title='Score'>" + values[i + 3] + "</td>"
+-                            "<td class='rbtext' width='1' title='" + i18n( true ? "Rating" : "Score" ) + "'>"
++                            "</td>" +
++                            QString("<td class='sbtext' width='1' title='%1'>").arg( i18n( "Score" ) ) + values[i + 3] + "</td>"
++                            "<td class='rbtext' width='1' title='" + ( showRating ? i18n( "Rating" ) : i18n( "Score" ) ) + "'>"
+                             "<div class='sbouter'>"
+                             "<div class='sbinner' style='width: "
+-                                + QString::number( true ? values[i + 4].toInt() * 10 : values[i + 3].toInt() / 2 ) + "px;'></div>"
++                                + QString::number( showRating ? values[i + 4].toInt() * 10 : values[i + 3].toInt() / 2 ) + "px;'></div>"
+                             "</div>"
+                             "</td>"
+                             "<td width='1'></td>"
+@@ -1578,10 +1580,10 @@
+                             "</a>"
+                         "</td>"
+                         "<td class='sbtext' width='1' title='" + i18n( "Score" ) + "'>" + values[i + 2] + "</td>"
+-                        "<td class='rbtext' width='1' title='" + i18n( true ? "Rating" : "Score" ) + "'>"
++                        "<td class='rbtext' width='1' title='" + ( showRating ? i18n( "Rating" ) : i18n( "Score" ) ) + "'>"
+                             "<div class='sbouter'>"
+                                 "<div class='sbinner' style='width: "
+-                                    + QString::number( true ? values[i + 3].toInt() * 10 : values[i + 2].toInt() / 2 ) + "px;'></div>"
++                                    + QString::number( showRating ? values[i + 3].toInt() * 10 : values[i + 2].toInt() / 2 ) + "px;'></div>"
+                             "</div>"
+                         "</td>"
+                         "<td width='1'></td>"
+@@ -1855,7 +1857,7 @@
+ 
+                         QString tracktitle_formated;
+                         QString tracktitle;
+-                        tracktitle = escapeHTML( albumValues[j + 5] ) + i18n(" - ") + escapeHTML( albumValues[j] );
++                        tracktitle = escapeHTML( i18n("%1 - %2").arg( albumValues[j + 5], albumValues[j] ) );
+                         tracktitle_formated = "<span class='album-song-title'>";
+                         if ( artist == albumValues[j + 5] )
+                              tracktitle_formated += "<b>" + tracktitle + "</b>";
+@@ -2107,7 +2109,11 @@
+ 
+     QDomElement el = doc.documentElement();
+ 
+-    m_lyricAddUrl    = el.attribute( "add_url" );
++    ScriptManager* const sm = ScriptManager::instance();
++    KConfig spec( sm->specForScript( sm->lyricsScriptRunning() ), true, false );
++    spec.setGroup( "Lyrics" );
++
++    m_lyricAddUrl = spec.readPathEntry( "add_url" );
+     m_lyricAddUrl.replace( "MAGIC_ARTIST", KURL::encode_string_no_slash( EngineController::instance()->bundle().artist() ) );
+     m_lyricAddUrl.replace( "MAGIC_TITLE", KURL::encode_string_no_slash( EngineController::instance()->bundle().title() ) );
+     m_lyricAddUrl.replace( "MAGIC_ALBUM", KURL::encode_string_no_slash( EngineController::instance()->bundle().album() ) );
+@@ -2125,7 +2131,7 @@
+             const QString artist = l.item( i ).toElement().attribute( "artist" );
+             const QString title  = l.item( i ).toElement().attribute( "title" );
+ 
+-            lyrics += "<a href='show:suggestLyric-" + url + "'>" + artist + " - " + title;
++            lyrics += "<a href='show:suggestLyric-" + url + "'>" + i18n("%1 - %2").arg( artist, title );
+             lyrics += "</a><br/>";
+         }
+     }
+@@ -2135,15 +2141,15 @@
+ 
+         const QString title      = el.attribute( "title" );
+         const QString artist     = el.attribute( "artist" );
+-        const QString site       = el.attribute( "site" );
+-        const QString site_url   = el.attribute( "site_url" );
++        const QString site       = spec.readEntry( "site" );
++        const QString site_url   = spec.readEntry( "site_url" );
+ 
+         lyrics.prepend( "<font size='2'><b>" + title + "</b><br/><u>" + artist+ "</font></u></font><br/>" );
+-        if ( !site.isEmpty() )
++
++        if( !cached ) {
+             lyrics.append( "<br/><br/><i>" + i18n( "Powered by %1 (%2)" ).arg( site, site_url ) + "</i>" );
+-
+-        if( !cached )
+             CollectionDB::instance()->setLyrics( EngineController::instance()->bundle().url().path(), xmldoc );
++        }
+     }
+ 
+     m_HTMLSource="";
+@@ -2225,7 +2231,7 @@
+         m_wikiLocaleEdit->setText( "pl" );
+ 
+     else if( text == i18n("Japanese") )
+-        m_wikiLocaleEdit->setText( "jp" );
++        m_wikiLocaleEdit->setText( "ja" );
+ 
+     else if( text == i18n("Spanish") )
+         m_wikiLocaleEdit->setText( "es" );
+@@ -2267,7 +2273,7 @@
+         index = 2;
+     else if( wikiLocale() == "pl" )
+         index = 3;
+-    else if( wikiLocale() == "jp" )
++    else if( wikiLocale() == "ja" )
+         index = 4;
+     else if( wikiLocale() == "es" )
+         index = 5;
+Index: playlistbrowseritem.h
+===================================================================
+--- amarok/src/playlistbrowseritem.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/playlistbrowseritem.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -230,12 +230,14 @@
+         PodcastItem( QListViewItem *parent, QListViewItem *after, const QDomElement &xml, const int feedType );
+ 
+         void  downloadMedia();
+-        const bool hasDownloaded();
++        const bool isOnDisk();
+         const bool hasXml( const QDomNode &xml, const int feedType );
+         QListViewItem *itemChannel() { return m_parent; }
+ 
+         void setNew( bool n = true );
+         bool isNew() { return m_new; }
++        void setListened( bool n = true );
++        bool hasDownloaded() { return m_downloaded; }
+ 
+         const KURL    &url() { return m_url; }
+         const QString &title() { return m_title; }
+@@ -290,10 +292,12 @@
+         bool        m_fetching;
+         QTimer      m_animationTimer;
+         uint        m_iconCounter;
+-        bool        m_downloaded;
+ 
+         KIO::CopyJob* m_podcastItemJob;
+ 
++        QDomElement m_xml;
++        bool        m_downloaded;       //marked as downloaded in cached xml
++        bool        m_onDisk;
+         bool        m_new;
+ };
+ 
+@@ -317,6 +321,8 @@
+         void  configure();
+         void  fetch();
+         void  rescan();
++        void saveCache( const QDomDocument &doc );
++        void saveCache() { saveCache( m_doc ); }
+ 
+         const KURL &url() { return m_url; }
+         const KURL &link() { return m_link; }
+@@ -354,10 +360,12 @@
+         void removeChildren();
+         void startAnimation();
+         void stopAnimation();
++        void createSettings();
+ 
+         KURL        m_url;                         //remote xml url
+         KURL        m_link;                        //webpage
+         QString     m_title;
++        QDomDocument m_doc;     //xml to be stored in the cache-file
+         QString     m_cache;                       //filename for caching
+         QString     m_description;
+         QString     m_copyright;
+Index: organizecollectiondialog.ui.h
+===================================================================
+--- amarok/src/organizecollectiondialog.ui.h	(.../tags/amarok/1.4-beta1/multimedia/amarok/src)	(revision 511476)
++++ amarok/src/organizecollectiondialog.ui.h	(.../trunk/extragear/multimedia/amarok/src)	(revision 511476)
+@@ -2,6 +2,7 @@
+ #include <qstringx.h>
+ #include <collectiondb.h>
+ #include <collectionbrowser.h>
++#include "debug.h"
+ 
+ 
+ 
+@@ -159,3 +160,36 @@
+ 
+     update( 0 );
+ }
++
++
++
++void OrganizeCollectionDialog::slotDetails()
++{
++    detailed = !detailed;
++
++    if( detailed )
++    {
++        ignoreTheCheck->show();
++        customschemeCheck->show();
++        replacementGroup->show();
++        formatLabel->show();
++        formatEdit->show();
++    }
++    else
++    {
++        ignoreTheCheck->hide();
++        customschemeCheck->hide();
++        replacementGroup->hide();
++        formatLabel->hide();
++        formatEdit->hide();
++    }
++
++    if( dynamic_cast<QWidget *>(parent()) )
++        static_cast<QWidget *>(parent())->adjustSize();
++}
++
++
++void OrganizeCollectionDialog::init()
++{
++    detailed = true;
++}




More information about the pkg-kde-commits mailing list