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 & )</signal>
+@@ -510,12 +511,14 @@
+ <slot>preview( const QString & format )</slot>
+ <slot>update( int dummy )</slot>
+ <slot>update( const QString & dummy )</slot>
++ <slot>slotDetails()</slot>
+ </slots>
+ <functions>
+ <function returnType="QString">buildDestination( const QString & format, const MetaBundle & mb )</function>
+ <function returnType="QString">buildFormatString()</function>
+ <function>setPreviewBundle( const MetaBundle & bundle )</function>
+ <function returnType="QString">cleanPath( const QString & 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 ¤tTrack = 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 </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(" – ") +
+ "</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