From eed9a2216f1999154f46e22c871fc8b1733c6c10 Mon Sep 17 00:00:00 2001 From: tabuleiro Date: Thu, 21 Aug 2003 02:24:27 +0000 Subject: [PATCH] Initial import --- sqlitebrowser/sqlitebrowser/LICENSING | 37 + sqlitebrowser/sqlitebrowser/aboutform.ui | 83 + sqlitebrowser/sqlitebrowser/aboutform.ui.h | 14 + sqlitebrowser/sqlitebrowser/browsermain.cpp | 22 + sqlitebrowser/sqlitebrowser/building | 42 + .../sqlitebrowser/createindexform.ui | 294 + .../sqlitebrowser/createindexform.ui.h | 81 + .../sqlitebrowser/createtableform.ui | 268 + .../sqlitebrowser/createtableform.ui.h | 84 + .../sqlitebrowser/deleteindexform.ui | 155 + .../sqlitebrowser/deleteindexform.ui.h | 32 + .../sqlitebrowser/deletetableform.ui | 155 + .../sqlitebrowser/deletetableform.ui.h | 33 + sqlitebrowser/sqlitebrowser/findform.ui | 240 + sqlitebrowser/sqlitebrowser/findform.ui.h | 60 + sqlitebrowser/sqlitebrowser/form1.ui | 913 +++ sqlitebrowser/sqlitebrowser/form1.ui.h | 568 ++ sqlitebrowser/sqlitebrowser/iconwin.ico | Bin 0 -> 4846 bytes .../sqlitebrowser/images/editcopy.png | Bin 0 -> 306 bytes .../sqlitebrowser/images/editpaste.png | Bin 0 -> 328 bytes .../sqlitebrowser/images/filenew.png | Bin 0 -> 231 bytes .../sqlitebrowser/images/fileopen.png | Bin 0 -> 268 bytes .../sqlitebrowser/images/icone16.png | Bin 0 -> 486 bytes .../sqlitebrowser/images/searchfind.png | Bin 0 -> 662 bytes .../sqlitebrowser/images/whatsthis.png | Bin 0 -> 26167 bytes sqlitebrowser/sqlitebrowser/macapp.icns | Bin 0 -> 33668 bytes .../sqlitebrowser/sqlite_source/attach.c | 278 + .../sqlitebrowser/sqlite_source/auth.c | 225 + .../sqlitebrowser/sqlite_source/btree.c | 3585 +++++++++ .../sqlitebrowser/sqlite_source/btree.h | 156 + .../sqlitebrowser/sqlite_source/btree_rb.c | 1417 ++++ .../sqlitebrowser/sqlite_source/build.c | 2214 +++++ .../sqlitebrowser/sqlite_source/config.h | 1 + .../sqlitebrowser/sqlite_source/copy.c | 120 + .../sqlitebrowser/sqlite_source/delete.c | 396 + .../sqlitebrowser/sqlite_source/encode.c | 246 + .../sqlitebrowser/sqlite_source/encode.h | 18 + .../sqlitebrowser/sqlite_source/expr.c | 1623 ++++ .../sqlitebrowser/sqlite_source/func.c | 573 ++ .../sqlitebrowser/sqlite_source/hash.c | 354 + .../sqlitebrowser/sqlite_source/hash.h | 109 + .../sqlitebrowser/sqlite_source/insert.c | 891 +++ .../sqlitebrowser/sqlite_source/main.c | 1011 +++ .../sqlitebrowser/sqlite_source/opcodes.c | 132 + .../sqlitebrowser/sqlite_source/opcodes.h | 130 + .../sqlitebrowser/sqlite_source/os.c | 1544 ++++ .../sqlitebrowser/sqlite_source/os.h | 190 + .../sqlitebrowser/sqlite_source/pager.c | 2086 +++++ .../sqlitebrowser/sqlite_source/pager.h | 83 + .../sqlitebrowser/sqlite_source/parse.c | 7103 +++++++++++++++++ .../sqlitebrowser/sqlite_source/parse.h | 130 + .../sqlitebrowser/sqlite_source/pragma.c | 667 ++ .../sqlitebrowser/sqlite_source/printf.c | 834 ++ .../sqlitebrowser/sqlite_source/random.c | 113 + .../sqlitebrowser/sqlite_source/select.c | 2450 ++++++ .../sqlitebrowser/sqlite_source/sqlite.h | 706 ++ .../sqlitebrowser/sqlite_source/sqliteInt.h | 1195 +++ .../sqlite_source/sqlite_source.pro | 50 + .../sqlitebrowser/sqlite_source/table.c | 202 + .../sqlitebrowser/sqlite_source/tokenize.c | 684 ++ .../sqlitebrowser/sqlite_source/trigger.c | 760 ++ .../sqlitebrowser/sqlite_source/update.c | 452 ++ .../sqlitebrowser/sqlite_source/util.c | 1152 +++ .../sqlitebrowser/sqlite_source/vacuum.c | 315 + .../sqlitebrowser/sqlite_source/vdbe.c | 5929 ++++++++++++++ .../sqlitebrowser/sqlite_source/vdbe.h | 97 + .../sqlitebrowser/sqlite_source/where.c | 1198 +++ sqlitebrowser/sqlitebrowser/sqlitebrowser.pro | 37 + sqlitebrowser/sqlitebrowser/sqlitedb.cpp | 504 ++ sqlitebrowser/sqlitebrowser/sqlitedb.h | 128 + sqlitebrowser/sqlitebrowser/winapp.rc | 1 + sqlitebrowser/sqlitedbbrowser.pro | 5 + 72 files changed, 45175 insertions(+) create mode 100755 sqlitebrowser/sqlitebrowser/LICENSING create mode 100755 sqlitebrowser/sqlitebrowser/aboutform.ui create mode 100755 sqlitebrowser/sqlitebrowser/aboutform.ui.h create mode 100755 sqlitebrowser/sqlitebrowser/browsermain.cpp create mode 100755 sqlitebrowser/sqlitebrowser/building create mode 100755 sqlitebrowser/sqlitebrowser/createindexform.ui create mode 100755 sqlitebrowser/sqlitebrowser/createindexform.ui.h create mode 100755 sqlitebrowser/sqlitebrowser/createtableform.ui create mode 100755 sqlitebrowser/sqlitebrowser/createtableform.ui.h create mode 100755 sqlitebrowser/sqlitebrowser/deleteindexform.ui create mode 100755 sqlitebrowser/sqlitebrowser/deleteindexform.ui.h create mode 100755 sqlitebrowser/sqlitebrowser/deletetableform.ui create mode 100755 sqlitebrowser/sqlitebrowser/deletetableform.ui.h create mode 100755 sqlitebrowser/sqlitebrowser/findform.ui create mode 100755 sqlitebrowser/sqlitebrowser/findform.ui.h create mode 100755 sqlitebrowser/sqlitebrowser/form1.ui create mode 100755 sqlitebrowser/sqlitebrowser/form1.ui.h create mode 100755 sqlitebrowser/sqlitebrowser/iconwin.ico create mode 100755 sqlitebrowser/sqlitebrowser/images/editcopy.png create mode 100755 sqlitebrowser/sqlitebrowser/images/editpaste.png create mode 100755 sqlitebrowser/sqlitebrowser/images/filenew.png create mode 100755 sqlitebrowser/sqlitebrowser/images/fileopen.png create mode 100755 sqlitebrowser/sqlitebrowser/images/icone16.png create mode 100755 sqlitebrowser/sqlitebrowser/images/searchfind.png create mode 100755 sqlitebrowser/sqlitebrowser/images/whatsthis.png create mode 100755 sqlitebrowser/sqlitebrowser/macapp.icns create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/attach.c create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/auth.c create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/btree.c create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/btree.h create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/btree_rb.c create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/build.c create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/config.h create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/copy.c create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/delete.c create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/encode.c create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/encode.h create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/expr.c create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/func.c create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/hash.c create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/hash.h create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/insert.c create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/main.c create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/opcodes.c create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/opcodes.h create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/os.c create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/os.h create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/pager.c create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/pager.h create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/parse.c create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/parse.h create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/pragma.c create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/printf.c create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/random.c create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/select.c create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/sqlite.h create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/sqliteInt.h create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/sqlite_source.pro create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/table.c create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/tokenize.c create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/trigger.c create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/update.c create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/util.c create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/vacuum.c create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/vdbe.c create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/vdbe.h create mode 100755 sqlitebrowser/sqlitebrowser/sqlite_source/where.c create mode 100755 sqlitebrowser/sqlitebrowser/sqlitebrowser.pro create mode 100755 sqlitebrowser/sqlitebrowser/sqlitedb.cpp create mode 100755 sqlitebrowser/sqlitebrowser/sqlitedb.h create mode 100755 sqlitebrowser/sqlitebrowser/winapp.rc create mode 100755 sqlitebrowser/sqlitedbbrowser.pro diff --git a/sqlitebrowser/sqlitebrowser/LICENSING b/sqlitebrowser/sqlitebrowser/LICENSING new file mode 100755 index 00000000..4cf29e05 --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/LICENSING @@ -0,0 +1,37 @@ +LICENSING + +This code is in Public Domain. You may do whatever you want with it. + +However, the same is not true for the QT libraries needed to build +this software, and this places restrictions on how you can develop +and license derivative works. + +The original code was developed and built with licensed, commercial +versions of QT on Windows, MacOSX and Linux. Developers that wish to +produce derivative work and use it in commercial projects need to hold +a commercial QT license as well. + +If you are however working on a project licensed with the GPL you may +use the GPL version of QT. You may release derivative works of this +software with any license you want as long as we are concerned, including +GPL, Public Domain or Commercial, provided you abide to the licensing +terms of the version of QT you have installed on your machine. + +There are GPL versions of QT available at www.trolltech.com for X11 +and MacOSX, and QT/GPL is included in almost all Linux distributions +since it is required by KDE. Windows users however need to purchase +a commercial version of QT (there is no GPL version for QT 3.x for +Windows at this time.) Please consult www.trolltech.com/licensing +if you have any questions about QT licensing. + + +REDISTRIBUTION OF BINARIES + +The binaries available at sqlitebrowser.sourceforge.net were built with +fully licensed commercial versions of QT, and can be redistributed freely. +The Windows and MacOSX versions are standalone applications (QT has been +statically linked), while the Linux packages used a shared QT 3 library +for better compatibility. + + + diff --git a/sqlitebrowser/sqlitebrowser/aboutform.ui b/sqlitebrowser/sqlitebrowser/aboutform.ui new file mode 100755 index 00000000..8d790264 --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/aboutform.ui @@ -0,0 +1,83 @@ + +aboutForm + + + aboutForm + + + + 0 + 0 + 396 + 218 + + + + About + + + + unnamed + + + + aboutBrowser + + + NoFrame + + + Plain + + + Text + + + + + okButton + + + Close + + + true + + + + + spacer5 + + + Horizontal + + + Expanding + + + + 141 + 20 + + + + + + + + okButton + clicked() + aboutForm + close() + + + + sqlitedb.h + aboutform.ui.h + + + init() + + + + diff --git a/sqlitebrowser/sqlitebrowser/aboutform.ui.h b/sqlitebrowser/sqlitebrowser/aboutform.ui.h new file mode 100755 index 00000000..ba191ee2 --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/aboutform.ui.h @@ -0,0 +1,14 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you wish to add, delete or rename functions or slots use +** Qt Designer which will update this file, preserving your code. Create an +** init() function in place of a constructor, and a destroy() function in +** place of a destructor. +*****************************************************************************/ + +void aboutForm::init() +{ + this->setCaption(applicationName); + aboutBrowser->setText(aboutText); +} diff --git a/sqlitebrowser/sqlitebrowser/browsermain.cpp b/sqlitebrowser/sqlitebrowser/browsermain.cpp new file mode 100755 index 00000000..66ebff41 --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/browsermain.cpp @@ -0,0 +1,22 @@ +/* +** This file is part of SQLite Database Browser +** http://sqlitebrowser.sourceforge.net +** +** Originally developed by Mauricio Piacentini, Tabuleiro +** +** The author disclaims copyright to this source code. +** Consult the LICENSING file for known restrictions +** +*/ + +#include +#include "form1.h" + +int main( int argc, char ** argv ) +{ + QApplication a( argc, argv ); + mainForm w; + w.show(); + a.connect( &a, SIGNAL( lastWindowClosed() ), &a, SLOT( quit() ) ); + return a.exec(); +} diff --git a/sqlitebrowser/sqlitebrowser/building b/sqlitebrowser/sqlitebrowser/building new file mode 100755 index 00000000..0102e402 --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/building @@ -0,0 +1,42 @@ +BUILD INSTRUCTIONS AND REQUIREMENTS + +SQLite Database Browser requires Trolltech's QT. It has been tested +with versions 3.12 and 3.2 of QT. QT can be included as +a static or shared library, depending on the current QT configuration +in the building machine. For more information on QT please consult +http://www.trolltech.com. The GPL version of QT is available in almost +all Linux distributions as a default package. + +SQLite is not used as a shared library: it is built from source code +included in this package (sqlite_source directory), and linked as a +static library into the executable. + +SQLite is ideal for embedding, so the only requirement +for building this code is the presence of QT. QT can be included as +a static or shared library, depending on the current QT configuration +in the building machine. + +Provided you have QT installed and configured, simply run + +qmake + +followed by + +make + +in the main directory. This will generate the + +browser (or browser.exe, or browser.app) + +application in the browser subdirectory. + +The same process works for building the code +in any platform supported by QT (including other Unix systems with +X11.) + +You may want to rename the final executable or .app bundle from +"browser" to "SQLite Database Browser", to match the official binaries +released at http://sqlitebrowser.sourceforge.net. + +Please check the LICENSING file for additional information. + diff --git a/sqlitebrowser/sqlitebrowser/createindexform.ui b/sqlitebrowser/sqlitebrowser/createindexform.ui new file mode 100755 index 00000000..afc3603e --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/createindexform.ui @@ -0,0 +1,294 @@ + +createIndexForm + + + createIndexForm + + + + 0 + 0 + 300 + 258 + + + + Create Index + + + icone16.png + + + + unnamed + + + + layout15 + + + + unnamed + + + + textLabel2 + + + Index name: + + + + + indexLineEdit + + + LineEditPanel + + + Sunken + + + + + + Enter the name for the new index + + + This area contains the name of the index to be created + + + + + + + groupBox2 + + + Define properties: + + + + unnamed + + + + layout12 + + + + unnamed + + + + comboTables + + + Choose the table to index + + + This control is used to select the table to be indexed. Changing the selected table will automatically update the fields available in the control below + + + + + comboFields + + + Choose the field to be indexed + + + This control specifies the field to be used as an index + + + + + + Ascending + + + + + Descending + + + + comboOrder + + + Choose the index order + + + This option controls the ordering of the index. Ascending is the recommended ordering + + + + + + Allowed + + + + + Not allowed + + + + comboUnique + + + Allow duplicate values in the index field + + + This control determines if the indexed field allows duplicate values to be inserted into the database. Attempting to insert a duplicate value in an indexed fiield that does not allow this option will generate an error + + + + + + + layout13 + + + + unnamed + + + + textLabel3 + + + Table to index: + + + AlignVCenter|AlignRight + + + + + textLabel4 + + + Field to index: + + + AlignVCenter|AlignRight + + + + + textLabel5 + + + Indexing order: + + + AlignVCenter|AlignRight + + + + + textLabel6 + + + Duplicate values: + + + AlignVCenter|AlignRight + + + + + + + + + layout16 + + + + unnamed + + + + spacer8 + + + Horizontal + + + Expanding + + + + 51 + 20 + + + + + + buttonCreate + + + Create + + + Create Index + + + + + buttonCancel + + + Cancel + + + true + + + Cancel and close dialog box + + + + + + + + + buttonCreate + clicked() + createIndexForm + confirmCreate() + + + buttonCancel + clicked() + createIndexForm + reject() + + + comboTables + activated(const QString&) + createIndexForm + tableSelected(const QString&) + + + + qmessagebox.h + sqlitedb.h + createindexform.ui.h + + + tableMap mtablemap; + QString createStatement; + + + tableSelected( const QString & entry ) + confirmCreate() + populateTable( tableMap rmap ) + + + + diff --git a/sqlitebrowser/sqlitebrowser/createindexform.ui.h b/sqlitebrowser/sqlitebrowser/createindexform.ui.h new file mode 100755 index 00000000..6f348339 --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/createindexform.ui.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you wish to add, delete or rename functions or slots use +** Qt Designer which will update this file, preserving your code. Create an +** init() function in place of a constructor, and a destroy() function in +** place of a destructor. +*****************************************************************************/ + + +void createIndexForm::tableSelected( const QString & entry ) +{ + tableMap::Iterator it; + for ( it = mtablemap.begin(); it != mtablemap.end(); ++it ) { + QString tname = it.data().getname() ; + + //populate the fields with first table name + if ((tname.compare(entry)==0)){ + comboFields->clear(); + fieldMap::Iterator fit; + fieldMap fmap = it.data().fldmap; + for ( fit = fmap.begin(); fit != fmap.end(); ++fit ) { + comboFields->insertItem( fit.data().getname(), -1 ); + } + } + } +} + +void createIndexForm::confirmCreate() +{ + bool ok = true; + QString idxname = indexLineEdit->text(); + if (idxname.isEmpty()) { + ok = false; + QMessageBox::information( this, applicationName, "Please select a name for the index" ); + return; + } + if (idxname.contains(" ")>0) { + ok = false; + QMessageBox::warning( this, applicationName, "Spaces are not allowed in the index name" ); + return; + } + if (ok){ + createStatement = "CREATE "; + if (comboUnique->currentItem()==1){ + createStatement.append("UNIQUE "); + } + createStatement.append("INDEX "); + createStatement.append(indexLineEdit->text()); + createStatement.append(" ON "); + createStatement.append(comboTables->currentText()); + createStatement.append("("); + createStatement.append(comboFields->currentText()); + createStatement.append(" "); + if (comboOrder->currentItem()==0){ + createStatement.append("ASC"); + } else { + createStatement.append("DESC"); + } + createStatement.append(");"); + accept(); + } +} + +void createIndexForm::populateTable(tableMap rmap) +{ + mtablemap = rmap; + tableMap::Iterator it; + for ( it = mtablemap.begin(); it != mtablemap.end(); ++it ) { + comboTables->insertItem( it.data().getname() , -1); + + //populate the fields with first table name + if (it==mtablemap.begin()){ + fieldMap::Iterator fit; + fieldMap fmap = it.data().fldmap; + for ( fit = fmap.begin(); fit != fmap.end(); ++fit ) { + comboFields->insertItem( fit.data().getname(), -1 ); + } + } + } +} diff --git a/sqlitebrowser/sqlitebrowser/createtableform.ui b/sqlitebrowser/sqlitebrowser/createtableform.ui new file mode 100755 index 00000000..33122517 --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/createtableform.ui @@ -0,0 +1,268 @@ + +createTableForm + + + createTableForm + + + + 0 + 0 + 309 + 312 + + + + Create Table + + + icone16.png + + + + unnamed + + + + layout7 + + + + unnamed + + + + textLabel1 + + + Table name: + + + + + tablenameLineEdit + + + LineEditPanel + + + Sunken + + + + + + Enter the name for the new table + + + Use this control to enter the name of the table to be created. + + + + + + + groupBox1 + + + Define fields: + + + + unnamed + + + + + Field Name + + + + + Field Type + + + + fieldsTable + + + true + + + Default + + + 0 + + + 2 + + + true + + + SingleRow + + + FollowStyle + + + This area contains the definitions for the fields in your new table. Add a new field using the ADD button. You can type the name of the field and the field type directly. Suggested field types are text, numeric or blob (for images and binary data) + + + + + layout6 + + + + unnamed + + + + spacer4 + + + Horizontal + + + Expanding + + + + 111 + 20 + + + + + + buttonAddField + + + Add + + + Add a new field definition + + + This button is used to add a new field definition to your table + + + + + buttonDeleteField + + + Delete + + + Delete current field definition + + + This button is used to delete the currently selected field definition from your table + + + + + + + + + layout8 + + + + unnamed + + + + spacer6 + + + Horizontal + + + Expanding + + + + 91 + 20 + + + + + + buttonCreate + + + Create + + + Create the table + + + + + buttonCancel + + + Cancel + + + true + + + Cancel and close dialog box + + + + + + + + + buttonCancel + clicked() + createTableForm + reject() + + + buttonCreate + clicked() + createTableForm + confirmCreate() + + + buttonAddField + clicked() + createTableForm + addField() + + + buttonDeleteField + clicked() + createTableForm + deleteField() + + + + qmessagebox.h + sqlitedb.h + createtableform.ui.h + + + QString createStatement; + + + confirmCreate() + addField() + deleteField() + + + init() + + + + diff --git a/sqlitebrowser/sqlitebrowser/createtableform.ui.h b/sqlitebrowser/sqlitebrowser/createtableform.ui.h new file mode 100755 index 00000000..ae7b3f9b --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/createtableform.ui.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you wish to add, delete or rename functions or slots use +** Qt Designer which will update this file, preserving your code. Create an +** init() function in place of a constructor, and a destroy() function in +** place of a destructor. +*****************************************************************************/ +void createTableForm::init() +{ + fieldsTable->setNumRows(0); + // fieldsTable->setNumCols(0); +} + +void createTableForm::confirmCreate() +{ + bool ok = true; + QString tabname = tablenameLineEdit->text(); + if (tabname.isEmpty()) { + ok = false; + QMessageBox::information( this, applicationName, "Please select a name for the table" ); + return; + } + if (tabname.contains(" ")>0) { + ok = false; + QMessageBox::warning( this, applicationName, "Spaces are not allowed in the table name" ); + return; + } + + if (fieldsTable->numRows()==0) { + ok = false; + QMessageBox::information( this, applicationName, "No fields defined" ); + return; + } + + /*check field names for empty or illegal names*/ + + for (int r=0; rnumRows();r++){ + QString rowname = fieldsTable->text(r, 0); + if (rowname.isEmpty()) { + ok = false; + QMessageBox::warning( this, applicationName, "Empty field names are not allowed" ); + break; + } + if (rowname.contains(" ")>0) { + ok = false; + QMessageBox::warning( this, applicationName, "Spaces are not allowed in the field names" ); + break; + } + } + + if (!ok){ + return; + } + + if (ok){ + createStatement = "CREATE TABLE "; + createStatement.append(tabname); + createStatement.append(" ("); + for (int r=0; rnumRows();r++){ + createStatement.append(fieldsTable->text(r, 0)); + createStatement.append(" "); + createStatement.append(fieldsTable->text(r, 1)); + if (r<(fieldsTable->numRows() - 1)) + createStatement.append(", "); + } + createStatement.append(");"); + accept(); + } +} + + +void createTableForm::addField() +{ + fieldsTable->insertRows(fieldsTable->numRows()); +} + + +void createTableForm::deleteField() +{ + if (fieldsTable->currentRow()!=-1){ + fieldsTable->removeRow(fieldsTable->currentRow()); + } +} diff --git a/sqlitebrowser/sqlitebrowser/deleteindexform.ui b/sqlitebrowser/sqlitebrowser/deleteindexform.ui new file mode 100755 index 00000000..9fc99373 --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/deleteindexform.ui @@ -0,0 +1,155 @@ + +deleteIndexForm + + + deleteIndexForm + + + + 0 + 0 + 236 + 137 + + + + Delete Index + + + icone16.png + + + + unnamed + + + + layout21 + + + + unnamed + + + + textLabel2 + + + Index name: + + + + + comboOptions + + + Choose the index to delete + + + Use this control to select the name of the index to be deleted + + + + + + + spacer13 + + + Vertical + + + Expanding + + + + 20 + 41 + + + + + + layout19 + + + + unnamed + + + + spacer11 + + + Horizontal + + + Expanding + + + + 31 + 20 + + + + + + buttonDelete + + + Delete + + + Delete the selected index + + + + + buttonCancel + + + Cancel + + + true + + + Cancel and close dialog box + + + + + + + + + buttonDelete + clicked() + deleteIndexForm + confirmDelete() + + + buttonCancel + clicked() + deleteIndexForm + reject() + + + + qmessagebox.h + qstring.h + qstringlist.h + sqlitedb.h + deleteindexform.ui.h + + + QString option; + + + confirmDelete() + populateOptions( QStringList entries ) + + + + diff --git a/sqlitebrowser/sqlitebrowser/deleteindexform.ui.h b/sqlitebrowser/sqlitebrowser/deleteindexform.ui.h new file mode 100755 index 00000000..70f6ce5e --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/deleteindexform.ui.h @@ -0,0 +1,32 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you wish to add, delete or rename functions or slots use +** Qt Designer which will update this file, preserving your code. Create an +** init() function in place of a constructor, and a destroy() function in +** place of a destructor. +*****************************************************************************/ + +void deleteIndexForm::confirmDelete() +{ + QString msg = "Are you sure you want to delete index "; + msg.append(comboOptions->currentText()); + msg.append("?"); + + if (QMessageBox::warning( this, applicationName, + msg, + QMessageBox::Yes | QMessageBox::Default, + QMessageBox::No | QMessageBox::Escape ) + == QMessageBox::Yes ){ + option = comboOptions->currentText(); + accept(); + } +} + +void deleteIndexForm::populateOptions(QStringList entries) +{ + comboOptions->clear(); + for ( QStringList::Iterator ct = entries.begin(); ct != entries.end(); ++ct ) { + comboOptions->insertItem(*ct,-1); + } +} diff --git a/sqlitebrowser/sqlitebrowser/deletetableform.ui b/sqlitebrowser/sqlitebrowser/deletetableform.ui new file mode 100755 index 00000000..c48fc55f --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/deletetableform.ui @@ -0,0 +1,155 @@ + +deleteTableForm + + + deleteTableForm + + + + 0 + 0 + 236 + 137 + + + + Delete Table + + + icone16.png + + + + unnamed + + + + layout21 + + + + unnamed + + + + textLabel2 + + + Table name: + + + + + comboOptions + + + Choose the table to delete + + + Use this control to select the name of the table to be deleted + + + + + + + spacer13 + + + Vertical + + + Expanding + + + + 20 + 41 + + + + + + layout19 + + + + unnamed + + + + spacer11 + + + Horizontal + + + Expanding + + + + 31 + 20 + + + + + + buttonDelete + + + Delete + + + Delete the selected table + + + + + buttonCancel + + + Cancel + + + true + + + Cancel and close dialog box + + + + + + + + + buttonCancel + clicked() + deleteTableForm + reject() + + + buttonDelete + clicked() + deleteTableForm + confirmDelete() + + + + qmessagebox.h + qstringlist.h + qstring.h + sqlitedb.h + deletetableform.ui.h + + + QString option; + + + confirmDelete() + populateOptions( QStringList entries ) + + + + diff --git a/sqlitebrowser/sqlitebrowser/deletetableform.ui.h b/sqlitebrowser/sqlitebrowser/deletetableform.ui.h new file mode 100755 index 00000000..df1a28b6 --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/deletetableform.ui.h @@ -0,0 +1,33 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you wish to add, delete or rename functions or slots use +** Qt Designer which will update this file, preserving your code. Create an +** init() function in place of a constructor, and a destroy() function in +** place of a destructor. +*****************************************************************************/ + + +void deleteTableForm::confirmDelete() +{ + QString msg = "Are you sure you want to delete table "; + msg.append(comboOptions->currentText()); + msg.append("? \n All data in the table will be lost"); + + if (QMessageBox::warning( this, applicationName, + msg, + QMessageBox::Yes | QMessageBox::Default, + QMessageBox::No | QMessageBox::Escape ) + == QMessageBox::Yes ){ + option = comboOptions->currentText(); + accept(); + } +} + +void deleteTableForm::populateOptions(QStringList entries) +{ + comboOptions->clear(); + for ( QStringList::Iterator ct = entries.begin(); ct != entries.end(); ++ct ) { + comboOptions->insertItem(*ct,-1); + } +} diff --git a/sqlitebrowser/sqlitebrowser/findform.ui b/sqlitebrowser/sqlitebrowser/findform.ui new file mode 100755 index 00000000..20177d27 --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/findform.ui @@ -0,0 +1,240 @@ + +findForm + + + findForm + + + + 0 + 0 + 239 + 319 + + + + Find + + + icone16.png + + + + unnamed + + + + layout5 + + + + unnamed + + + + searchButton + + + Search + + + Perform the search + + + This button starts the search process + + + + + + user + + + + findFieldCombobox + + + Field to be searched + + + Use this control to select the field to be searched in the current table + + + + + searchLine + + + LineEditPanel + + + Sunken + + + Enter values or words to search + + + This is a place to enter the word or number to be searched in the database + + + + + + = + + + + + contains + + + + + > + + + + + >= + + + + + <= + + + + + < + + + + findOperatorComboBox + + + Search criteria: use 'contains' for partial matches + + + This control is used to select the search criteria used to look for the search term in the database. Use '=' or 'contains' to find words, and the comparison symbols to filter numeric data. + + + + + + + + Record + + + true + + + true + + + + + Data + + + true + + + true + + + + findListView + + + 30 + + + Manual + + + LastColumn + + + Results of the search will appear in this area. Click on a result to select the corresponding record in the database + + + + + layout18 + + + + unnamed + + + + resultsLabel + + + + 7 + 5 + 0 + 0 + + + + Found: + + + + + spacer10 + + + Horizontal + + + Expanding + + + + 40 + 20 + + + + + + + + + + searchButton + clicked() + findForm + find() + + + findListView + clicked(QListViewItem*) + findForm + recordSelected(QListViewItem*) + + + + sqlitedb.h + findform.ui.h + + + lookfor(const QString&, const QString&, const QString&); + showrecord(int); + goingAway(); + + + showResults( resultMap rmap ) + find() + resetFields( QStringList fieldlist ) + resetResults() + recordSelected( QListViewItem * witem ) + closeEvent( QCloseEvent * ) + + + + diff --git a/sqlitebrowser/sqlitebrowser/findform.ui.h b/sqlitebrowser/sqlitebrowser/findform.ui.h new file mode 100755 index 00000000..940a2c38 --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/findform.ui.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you wish to add, delete or rename functions or slots use +** Qt Designer which will update this file, preserving your code. Create an +** init() function in place of a constructor, and a destroy() function in +** place of a destructor. +*****************************************************************************/ + +void findForm::showResults(resultMap rmap) +{ + findListView->clear(); + findListView->setSorting(-1); + resultMap::Iterator it; + QListViewItem * lasttbitem = 0; + for ( it = rmap.begin(); it != rmap.end(); ++it ) { + QListViewItem * tbitem = new QListViewItem( findListView, lasttbitem ); + //tbitem->setOpen( TRUE ); + tbitem->setText( 0, QString::number(it.key() + 1,10) ); //increase from index 0 + tbitem->setText( 1, it.data() ); + lasttbitem = tbitem; + } + QString results = "Found: "; + results.append(QString::number(findListView->childCount())); + resultsLabel->setText(results); +} + + +void findForm::find() +{ + emit lookfor( findFieldCombobox->currentText(), findOperatorComboBox->currentText(),searchLine->text() ); +} + +void findForm::resetFields(QStringList fieldlist) +{ + findFieldCombobox->clear(); + for ( QStringList::Iterator ct = fieldlist.begin(); ct != fieldlist.end(); ++ct ) { + findFieldCombobox->insertItem(*ct,-1); + } +} + +void findForm::resetResults() +{ + findListView->clear(); + resultsLabel->setText("Found: 0"); +} + + +void findForm::recordSelected( QListViewItem * witem) +{ + if (witem) { + int recNum = (witem->text(0)).toInt() ; + emit showrecord(recNum); +} +} + +void findForm::closeEvent( QCloseEvent * ) +{ + emit goingAway(); +} diff --git a/sqlitebrowser/sqlitebrowser/form1.ui b/sqlitebrowser/sqlitebrowser/form1.ui new file mode 100755 index 00000000..c8e81ca3 --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/form1.ui @@ -0,0 +1,913 @@ + +mainForm + + + mainForm + + + + 0 + 0 + 668 + 476 + + + + Browser + + + icone16.png + + + + unnamed + + + + mainTab + + + + + + + tab + + + Database Structure + + + + unnamed + + + + layout14 + + + + unnamed + + + + + Name + + + false + + + true + + + + + Object + + + false + + + true + + + + + Type + + + false + + + true + + + + + Schema + + + false + + + true + + + + dblistView + + + Manual + + + NoSelection + + + true + + + This area shows the structure of your database, including all tables and indexes. It is not possible to modify an existing table or index directly. + + + + + layout13 + + + + unnamed + + + + buttonCreateTable + + + Create Table + + + Open the Create Table wizard + + + This button is used to open the Create Table wizard, where it is possible to define the name and fields for a new table in the database + + + + + buttonDeleteTable + + + Delete Table + + + Open the Delete Table wizard + + + This button opens the Delete Table wizard, where you can choose a table to be dropped from the database + + + + + spacer7 + + + Horizontal + + + Expanding + + + + 21 + 20 + + + + + + buttonCreateIndex + + + Create Index + + + Open the Create Index wizard + + + This button opens the Create Index wizard, where it is possible to define the characteristics and create a new index in the database + + + + + buttonDeleteIndex + + + Delete Index + + + Open the Delete Index wizard + + + This button opens the Delete Index wizard, where it is possible to select an index to be removed from the database. Removing an index does not affect the data stored in the tables. + + + + + + + + + + + tab + + + Browse Data + + + + unnamed + + + + layout2 + + + + unnamed + + + + textLabel1 + + + Table: + + + + + + select + + + + + users + + + + comboBrowseTable + + + + 115 + 0 + + + + Select a table to browse data + + + Use this list to select a table to be displayed in the database view + + + + + buttonFind + + + + + + searchfind.png + + + true + + + Open or close the floating find window + + + This button toggles the appearance of the Find window, used to search records in the database view + + + + + spacer1 + + + Horizontal + + + Expanding + + + + 51 + 20 + + + + + + buttonNewRecord + + + New Record + + + Insert a new record in the current table + + + This button creates a new, empty record in the database + + + + + buttonDeleteRecord + + + Delete Record + + + Delete the current record + + + This button deletes the record currently selected in the database + + + + + + + dataTable + + + AutoOneFit + + + 0 + + + 0 + + + false + + + SingleRow + + + SpreadSheet + + + + + + This is the database view. You can double-click any record to edit its contents. All changes are commited to the database when you press ENTER or deselect the record. To undo changes press ESC while editing the record + + + + + layout9 + + + + unnamed + + + + buttonPrevious + + + + 0 + 0 + 0 + 0 + + + + < + + + Go to previous record set page + + + This button is used to navigate to the previous set of 1000 records in the database view + + + + + labelRecordset + + + 1000 - 2000 of 100000 + + + + + buttonNext + + + + 0 + 0 + 0 + 0 + + + + > + + + Go to next record set page + + + This button is used to navigate to the next 1000 records set in the database view + + + + + spacer4 + + + Horizontal + + + Expanding + + + + 50 + 20 + + + + + + buttonGoto + + + Go to: + + + Click here to browse the specified record + + + This button is used to navigate to the record number specied in the Go to: area. + + + + + editGoto + + + + 0 + 0 + 0 + 0 + + + + LineEditPanel + + + Sunken + + + 0 + + + Enter record number to browse + + + Type a record number in this area and click the Go to: button to display the record in the database view + + + + + + + + + + + + menubar + + + + + + + + + + + + + + + + + + + + + + Toolbar + + + Toolbar + + + + + + + + + + + + + + fileNewAction + + + filenew.png + + + New Database + + + &New Database + + + Create a new database file + + + Ctrl+N + + + + + fileOpenAction + + + fileopen.png + + + Open Database + + + &Open Database + + + Open an existing database file + + + Ctrl+O + + + + + fileExitAction + + + Exit + + + E&xit + + + + + + + + editCopyAction + + + editcopy.png + + + Copy + + + &Copy + + + Copies the selected text to the clipboard + + + Ctrl+C + + + + + editPasteAction + + + editpaste.png + + + Paste + + + &Paste + + + Pastes text from the clipboard into the current text insertion point + + + Ctrl+V + + + + + editFindAction + + + + + + Find + + + &Find... + + + F + + + + + helpContentsAction + + + Contents + + + &Contents... + + + + + + + + helpIndexAction + + + Index + + + &Index... + + + + + + + + helpAboutAction + + + About + + + &About + + + + + + + + fileCloseAction + + + false + + + Close Database + + + + + newRecordAction + + + New Record + + + + + compactAction + + + false + + + Compact Database + + + Compact the database file, removing space wasted by deleted records. + + + Compact the database file, removing space wasted by deleted records. + + + + + helpWhatsThisAction + + + whatsthis.png + + + What's This? + + + Shift+F1 + + + + + + fileExitAction + activated() + mainForm + fileExit() + + + fileOpenAction + activated() + mainForm + fileOpen() + + + fileNewAction + activated() + mainForm + fileNew() + + + fileCloseAction + activated() + mainForm + fileClose() + + + comboBrowseTable + activated(const QString&) + mainForm + populateTable(const QString&) + + + buttonNewRecord + clicked() + mainForm + addRecord() + + + buttonDeleteRecord + clicked() + mainForm + deleteRecord() + + + buttonPrevious + clicked() + mainForm + navigatePrevious() + + + buttonNext + clicked() + mainForm + navigateNext() + + + editGoto + returnPressed() + mainForm + navigateGoto() + + + buttonGoto + clicked() + mainForm + navigateGoto() + + + buttonFind + toggled(bool) + mainForm + browseFind(bool) + + + buttonCreateTable + clicked() + mainForm + createTable() + + + buttonCreateIndex + clicked() + mainForm + createIndex() + + + compactAction + activated() + mainForm + compact() + + + buttonDeleteTable + clicked() + mainForm + deleteTable() + + + buttonDeleteIndex + clicked() + mainForm + deleteIndex() + + + editCopyAction + activated() + mainForm + copy() + + + editPasteAction + activated() + mainForm + paste() + + + dataTable + valueChanged(int,int) + mainForm + recordEdited(int,int) + + + helpWhatsThisAction + activated() + mainForm + helpWhatsThis() + + + helpAboutAction + activated() + mainForm + helpAbout() + + + + qvalidator.h + findform.h + qclipboard.h + sqlitedb.h + qmessagebox.h + qfiledialog.h + qfile.h + qapplication.h + createtableform.h + createindexform.h + deletetableform.h + deleteindexform.h + aboutform.h + form1.ui.h + + + QIntValidator * gotoValidator; + DBBrowserDB db; + int recsPerView; + int recAtTop; + findForm * findWin; + QClipboard * clipboard; + + + fileOpen() + fileNew() + populateStructure() + populateTable( const QString & tablename ) + resetBrowser() + fileClose() + fileExit() + closeEvent( QCloseEvent * ) + addRecord() + recordEdited( int wrow, int wcol ) + deleteRecord() + updateTableView( int lineToSelect ) + navigatePrevious() + navigateNext() + navigateGoto() + setRecordsetLabel() + browseFind( bool open ) + browseFindAway() + lookfor( const QString & wfield, const QString & woperator, const QString & wsearchterm ) + showrecord( int dec ) + createTable() + createIndex() + compact() + deleteTable() + deleteIndex() + copy() + paste() + helpWhatsThis() + helpAbout() + + + init() + destroy() + + + + diff --git a/sqlitebrowser/sqlitebrowser/form1.ui.h b/sqlitebrowser/sqlitebrowser/form1.ui.h new file mode 100755 index 00000000..5ef8d2e9 --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/form1.ui.h @@ -0,0 +1,568 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you wish to add, delete or rename functions or slots use +** Qt Designer which will update this file, preserving your code. Create an +** init() function in place of a constructor, and a destroy() function in +** place of a destructor. +*****************************************************************************/ + +void mainForm::init() +{ + clipboard = QApplication::clipboard(); + if ( clipboard->supportsSelection() ) + clipboard->setSelectionMode( TRUE ); + + findWin = 0; + recsPerView = 1000; + recAtTop = 0; + gotoValidator = new QIntValidator(0,0,this); + editGoto->setValidator(gotoValidator); + gotoValidator->setRange ( 0, 0); + resetBrowser(); + this->setCaption(applicationName); + +} + +void mainForm::destroy() +{ + if (gotoValidator) + delete gotoValidator; +} + +void mainForm::fileOpen() +{ + QString fileName = QFileDialog::getOpenFileName( + "", + "", + this, + "open file dialog" + "Choose a database file" ); + if (QFile::exists(fileName) ) + { + db.open(fileName); + populateStructure(); + resetBrowser(); + fileCloseAction->setEnabled(true); + compactAction->setEnabled(true); + } +} + + +void mainForm::fileNew() +{ + QString fileName = QFileDialog::getSaveFileName( + "", + "", + this, + "create file dialog" + "Choose a filename to save under" ); + if (QFile::exists(fileName) ) + { + QString err = "File "; + err.append(fileName); + err.append(" already exists. Please choose a different name"); + QMessageBox::information( this, applicationName ,err); + return; + } + if (!fileName.isNull()) + { + db.create(fileName); + populateStructure(); + resetBrowser(); + createTable(); + fileCloseAction->setEnabled(true); + compactAction->setEnabled(true); + } +} + +void mainForm::populateStructure() +{ + dblistView->clear(); + dblistView->setSorting(-1); + if (!db.isOpen()){ + return; + } + db.updateSchema(); + tableMap::Iterator it; + tableMap tmap = db.tbmap; + QListViewItem * lasttbitem = 0; + for ( it = tmap.begin(); it != tmap.end(); ++it ) { + QListViewItem * tbitem = new QListViewItem( dblistView, lasttbitem ); + //tbitem->setOpen( TRUE ); + tbitem->setText( 0, it.data().getname() ); + tbitem->setText( 1, "table" ); + tbitem->setText( 3, it.data().getsql() ); + fieldMap::Iterator fit; + fieldMap fmap = it.data().fldmap; + QListViewItem * lastflditem = 0; + for ( fit = fmap.begin(); fit != fmap.end(); ++fit ) { + QListViewItem * fielditem = new QListViewItem(tbitem, lastflditem); + fielditem->setText( 0, fit.data().getname() ); + fielditem->setText( 1, "field" ); + fielditem->setText( 2, fit.data().gettype() ); + lastflditem = fielditem; + } + lasttbitem = tbitem; + } + indexMap::Iterator it2; + indexMap imap = db.idxmap; + for ( it2 = imap.begin(); it2 != imap.end(); ++it2 ) { + QListViewItem * item = new QListViewItem( dblistView, lasttbitem ); + item->setText( 0, it2.data().getname()); + item->setText( 1, "index" ); + item->setText( 3, it2.data().getsql() ); + lasttbitem = item ; + } +} + +void mainForm::populateTable( const QString & tablename) +{ + bool mustreset = false; + QApplication::setOverrideCursor( waitCursor, TRUE ); + if (tablename.compare(db.curBrowseTableName)!=0) + mustreset = true; + + if (!db.browseTable(tablename)){ + dataTable->setNumRows( 0 ); + dataTable->setNumCols( 0 ); + QApplication::restoreOverrideCursor(); + if (findWin){ + findWin->resetFields(db.getTableFields("")); + findWin->resetResults(); + } + return; + } + + if (mustreset){ + recAtTop = 0; + updateTableView(0); + if (findWin) findWin->resetFields(db.getTableFields(db.curBrowseTableName)); + } else { + updateTableView(-1); + } + //got to keep findWin in synch + if (findWin){ + findWin->resetResults(); + } +} + +void mainForm::resetBrowser() +{ + recAtTop = 0; + comboBrowseTable->clear(); + QStringList tab = db.getTableNames(); + if (tab.isEmpty()){ + comboBrowseTable->insertItem("",-1); + } else { + for ( QStringList::Iterator ct = tab.begin(); ct != tab.end(); ++ct ) { + comboBrowseTable->insertItem(*ct,-1); + } + } + setRecordsetLabel(); + comboBrowseTable->setCurrentItem(0); + populateTable(comboBrowseTable->currentText()); +} + +void mainForm::fileClose() +{ + db.close(); + resetBrowser(); + populateStructure(); + fileCloseAction->setEnabled(false); + compactAction->setEnabled(false); +} + + +void mainForm::fileExit() +{ + db.close(); + QApplication::exit( 0 ); +} + +void mainForm::closeEvent( QCloseEvent * ) +{ + fileExit(); +} + +void mainForm::addRecord() +{ + if (db.addRecord()){ + //added record will be the last one in view + recAtTop = ((db.getRecordCount()-1)/recsPerView)*recsPerView; + updateTableView(db.getRecordCount()-recAtTop-1); + }else{ + QMessageBox::information( this, applicationName, + "Please select a table first" ); + } +} + + +void mainForm::recordEdited( int wrow, int wcol ) +{ + if (!db.updateRecord(wrow+recAtTop, wcol, dataTable->text(wrow, wcol))){ + //could not update + rowList tab = db.browseRecs; + rowList::iterator rt = tab.at(wrow+recAtTop); + QString rowid = (*rt).first(); + QStringList::Iterator cv = (*rt).at(wcol+1);//must account for rowid + dataTable->setText( wrow, wcol, *cv ); + QMessageBox::information( this, applicationName, "Data can not be edited" ); + } +} + + +void mainForm::deleteRecord() +{ + if (dataTable->currentRow()!=-1){ + db.deleteRecord(dataTable->currentRow()+recAtTop); + populateTable(db.curBrowseTableName); + } else { + QMessageBox::information( this, applicationName, "Please select a record first" ); } +} + +void mainForm::updateTableView(int lineToSelect) +{ + // qDebug("line to select value is %d, rowAttop = %d",lineToSelect, recAtTop); + QApplication::setOverrideCursor( waitCursor, TRUE ); + QStringList fields = db.browseFields; + + dataTable->setNumRows(0); + dataTable->setNumCols( fields.count() ); + int cheadnum = 0; + for ( QStringList::Iterator ct = fields.begin(); ct != fields.end(); ++ct ) { + dataTable->horizontalHeader()->setLabel( cheadnum, *ct ); + cheadnum++; + } + + rowList tab = db.browseRecs; + int maxRecs = db.getRecordCount(); + int recsThisView = maxRecs - recAtTop; + + if (recsThisView>recsPerView) + recsThisView = recsPerView; + + // qDebug("recsthisview= %d\n",recsThisView); + + dataTable->setNumRows( recsThisView); + rowList::iterator rt; + int rowNum = 0; + int colNum = 0; + //int dcols =0; + QString rowLabel; + for ( rt = tab.at(recAtTop); rt !=tab.end(); ++rt ) + { + rowLabel.setNum(recAtTop+rowNum+1); + dataTable->verticalHeader()->setLabel( rowNum, rowLabel ); + colNum = 0; + for ( QStringList::Iterator it = (*rt).begin(); it != (*rt).end(); ++it ) { + //skip first one (the rowid) + if (it!=(*rt).begin()){ + dataTable->setText( rowNum, colNum, *it ); + colNum++; + } + } + rowNum++; + if (rowNum==recsThisView) break; + } + + //dataTable->clearSelection(true); + if (lineToSelect!=-1){ + //qDebug("inside selection"); + dataTable->clearSelection(true); + dataTable->selectRow(lineToSelect); + dataTable->setCurrentCell(lineToSelect, 0); + dataTable->ensureCellVisible (lineToSelect, 0 ) ; + } + setRecordsetLabel(); + QApplication::restoreOverrideCursor(); +} + +void mainForm::navigatePrevious() +{ + int nextFirstRec = recAtTop - recsPerView; + if (nextFirstRec >= 0 ) { + recAtTop = nextFirstRec; + updateTableView(-1); + } +} + + +void mainForm::navigateNext() +{ + int nextFirstRec = recAtTop + recsPerView; + //qDebug("called navigatenext, nextFirstRec=%d\n",nextFirstRec); + if (nextFirstRec < db.getRecordCount() ) { + recAtTop = nextFirstRec; + updateTableView(-1); + } +} + + +void mainForm::navigateGoto() +{ + QString typed = editGoto->text(); + bool ok; + int dec = typed.toInt( &ok); + if (dec==0) dec=1; + if (dec>db.getRecordCount()) dec = db.getRecordCount(); + + recAtTop = ((dec-1)/recsPerView)*recsPerView; + updateTableView(dec-recAtTop-1); + editGoto->setText(QString::number(dec,10)); +} + +void mainForm::setRecordsetLabel() +{ + if (db.getRecordCount()==0){ + labelRecordset->setText("0 - 0 of 0"); + } else { + QString label = QString::number(recAtTop+1,10); + label.append(" - "); + int lastrec = db.getRecordCount(); + int lastthisview = recAtTop+recsPerView; + if (lastthisview > lastrec) lastthisview = lastrec; + label.append(QString::number(lastthisview,10)); + label.append(" of "); + label.append(QString::number(db.getRecordCount(),10)); + labelRecordset->setText(label); + } +} + +void mainForm::browseFind(bool open) +{ + if (open){ + if ( ! findWin ) { + findWin= new findForm( this ); + connect( findWin, SIGNAL( lookfor(const QString&, const QString&, const QString&) ), + this, SLOT( lookfor(const QString&, const QString&, const QString&) ) ); + connect( findWin, SIGNAL( showrecord(int) ),this, SLOT( showrecord(int) ) ); + connect( findWin, SIGNAL( goingAway() ),this, SLOT( browseFindAway() ) ); + } + findWin->resetFields(db.getTableFields(db.curBrowseTableName)); + findWin->show(); + } else { + if (findWin){ + findWin->hide(); + } + } +} + +void mainForm::browseFindAway() +{ + buttonFind->toggle(); +} + +void mainForm::lookfor( const QString & wfield, const QString & woperator, const QString & wsearchterm ) +{ + if (!db.isOpen()){ + QMessageBox::information( this, applicationName, "There is no database opened. Please open or create a new database file." ); + return; + } + + //we may need to modify woperator and wsearchterm, so use copies + QString * finaloperator = new QString(woperator); + QString * finalsearchterm = new QString(wsearchterm); + + //special case for CONTAINS operator: use LIKE and surround the search word with % characters + if (woperator.compare("contains")==0){ + finaloperator = new QString("LIKE"); + QString newsearchterm = "%"; + newsearchterm.append(wsearchterm); + newsearchterm.append("%"); + finalsearchterm = new QString( newsearchterm); + } + QApplication::setOverrideCursor( waitCursor, TRUE ); + QString statement = "SELECT rowid, "; + statement.append(wfield); + statement.append(" FROM "); + statement.append( db.curBrowseTableName); + statement.append(" WHERE "); + statement.append(wfield); + statement.append(" "); + statement.append(*finaloperator); + statement.append(" "); + //searchterm needs to be quoted if it is not a number + bool ok = false; + wsearchterm.toDouble(&ok); + if (!ok) wsearchterm.toInt(&ok, 10); + if (!ok) {//not a number, quote it + char * formSQL = sqlite_mprintf("%Q",(*finalsearchterm).latin1()); + statement.append(formSQL); + if (formSQL) sqlite_freemem(formSQL); + } else {//append the number, unquoted + statement.append(*finalsearchterm); + } + statement.append(" ORDER BY rowid; "); + resultMap res = db.getFindResults(statement); + findWin->showResults(res); + QApplication::restoreOverrideCursor(); +} + + +void mainForm::showrecord( int dec ) +{ + recAtTop = ((dec-1)/recsPerView)*recsPerView; + updateTableView(dec-recAtTop-1); +} + +void mainForm::createTable() +{ + if (!db.isOpen()){ + QMessageBox::information( this, applicationName, "There is no database opened. Please open or create a new database file." ); + return; + } + createTableForm * tableForm = new createTableForm( this, "createtable", TRUE ); + if ( tableForm->exec() ) { + if (!db.executeSQL(tableForm->createStatement)){ + QString error = "Error: could not create the table. Message from database engine: "; + error.append(db.lastErrorMessage); + QMessageBox::warning( this, applicationName, error ); + } else { + populateStructure(); + resetBrowser(); + } + } +} + + +void mainForm::createIndex() +{ + if (!db.isOpen()){ + QMessageBox::information( this, applicationName, "There is no database opened. Please open or create a new database file." ); + return; + } + createIndexForm * indexForm = new createIndexForm( this, "createindex", TRUE ); + tableMap tmap = db.tbmap; + indexForm->populateTable( tmap ); + if ( indexForm->exec() ) { + if (!db.executeSQL(indexForm->createStatement)){ + QString error = "Error: could not create the index. Message from database engine: "; + error.append(db.lastErrorMessage); + QMessageBox::warning( this, applicationName, error ); + } else { + populateStructure(); + resetBrowser(); + } + } +} + + +void mainForm::compact() +{ + QApplication::setOverrideCursor( waitCursor, TRUE ); + if (db.isOpen()){ + if (!db.compact()){ + QString error = "Error: could not compact the database file. Message from database engine: "; + error.append(db.lastErrorMessage); + QMessageBox::warning( this, applicationName, error ); + } else { + QMessageBox::warning( this, applicationName, "Database compacted" ); + } + } + db.open(db.curDBFilename); + populateStructure(); + resetBrowser(); + fileCloseAction->setEnabled(true); + compactAction->setEnabled(true); + QApplication::restoreOverrideCursor( ); +} + + +void mainForm::deleteTable() +{ + if (!db.isOpen()){ + QMessageBox::information( this, applicationName, "There is no database opened." ); + return; + } + deleteTableForm * tableForm = new deleteTableForm( this, "deletetable", TRUE ); + tableForm->populateOptions( db.getTableNames()); + if ( tableForm->exec() ) { + QString statement = "DROP TABLE "; + statement.append(tableForm->option); + statement.append(";"); + if (!db.executeSQL( statement)){ + QString error = "Error: could not delete the table. Message from database engine: "; + error.append(db.lastErrorMessage); + QMessageBox::warning( this, applicationName, error ); + } else { + populateStructure(); + resetBrowser(); + } + } +} + + +void mainForm::deleteIndex() +{ + if (!db.isOpen()){ + QMessageBox::information( this, applicationName, "There is no database opened." ); + return; + } + deleteIndexForm * indexForm = new deleteIndexForm( this, "deleteindex", TRUE ); + indexForm->populateOptions( db.getIndexNames()); + if ( indexForm->exec() ) { + QString statement = "DROP INDEX "; + statement.append(indexForm->option); + statement.append(";"); + if (!db.executeSQL( statement)){ + QString error = "Error: could not delete the index. Message from database engine: "; + error.append(db.lastErrorMessage); + QMessageBox::warning( this, applicationName, error ); + } else { + populateStructure(); + resetBrowser(); + } + } + +} + + +void mainForm::copy() +{ + QWidget * t =dataTable->cellWidget(dataTable->currentRow(), dataTable->currentColumn()); + if (t!=0){ + if (t->isA( "QLineEdit" )){ + /*we are in edit mode*/ + if (t->hasFocus()){ + QLineEdit * le = (QLineEdit *) t; + le->copy(); + } + } + } + if (editGoto->hasFocus()) + editGoto->copy(); +} + + +void mainForm::paste() +{ + QWidget * t =dataTable->cellWidget(dataTable->currentRow(), dataTable->currentColumn()); + if (t!=0){ + if (t->isA( "QLineEdit" )){ + /*we are in edit mode*/ + if (t->hasFocus()){ + QLineEdit * le = (QLineEdit *) t; + le->paste();} + } + } + if (editGoto->hasFocus()) + editGoto->paste(); +} + + +void mainForm::helpWhatsThis() +{ + QWhatsThis::enterWhatsThisMode (); +} + + +void mainForm::helpAbout() +{ + /*QString wcaption = "About "; + wcaption.append(applicationName); + QString wtext = "This text, etc..."; + QMessageBox::about ( this, wcaption, wtext);*/ + aboutForm * aForm = new aboutForm( this, "about", TRUE ); + aForm ->exec() ; +} diff --git a/sqlitebrowser/sqlitebrowser/iconwin.ico b/sqlitebrowser/sqlitebrowser/iconwin.ico new file mode 100755 index 0000000000000000000000000000000000000000..3c20f4757ad89aedd66f8e9ee6de27a40e0dafbb GIT binary patch literal 4846 zcmeH~J!m6G6o8*|1_@zoOSW8@#Bp`*4h90Q5^P9kxW=_pO($^YD+1oi=Q3Qtu-z3& zNQyMBRj5i4Pi;3b7+hRfOISY!2@*2--mG+5+49dNmjr^xo}GDb-p{vhW>=EPgglX@ zrCHJT>jxsAFwV}V^3w^C51)uUdlr`E`)QHSCqLGO#h%-XCgVcIHkjOUDlP`bT#~c7y0x?@V-LNxjqR?^ual= zF(2Qekmw&d=leSxtbNIK^>FQOi|z)SAEo;It@`vnuuuI1pdP|&Eq&hfnG-q7Vb!nb zU{v$#bF~}zX`S>H@dbTC(gaZfVQh0RL1)kz)p6r$V$oYB7QIDp(W_gGK1LrS#OP!64C2r`^bWm4;m~_zkL+E@Y`7YN z8v+@e4DYv)o{NFOz+hl7Fa#tR3=9Sa1A~DfV8UQvFfbSx3=9Ds1_OhE!N6c(FdiKo z1`eYfY!p<1!g95+SXeA9;g(^sB)2581hue)GO%cwSXeA9p)7D%I4m3%4hu&p6&w}@ z3xkD0OK0J*FjyE|c(c2-gyc#8kVAR3I#7{2#x9ha+%ZfsNn;YkFvaAKS&YdYlRGAN z*p84JJ^5qu$K=;7ipd{Sn;3=|hL}3&wo#RE_h=Zo>NZjXM?MFegTs+8Y^`!o0|$pw z4sI-LH%<-~2a5y3kuV$qSR9THBZtDl!atoj?1_WLX*~jqo(A0obTD`rJPaNN4}*sx z948nY3?2p#gM)!EbnId9FnAa|41}hmhrz?(VekNW@;icg96d&s7#7*W;X`b-vGTEe zD_dJz!iz@s_V(o9;6RR!j^yz0P)<%xE3lYI^ogI~J3RdN)^Xb*}V7?yA$O=DPKZq&%~p-1O{LgH``yePp<* zb}#0O8J9+LWPPmAY?S6xm&_Ngv6gR@xk{x_XuK7#I_*}o*{o(7Vym6rPB3d!raNKM zX^q%rT*9>3>YGhhh~G|abKOR-Qku`ybA7&4=`|>swr1P=Mx~G>ud39oS6ZJb-&)U7 zPn}*Rp|0gpsW^XeZ#_$;a$28q>4EhO_DSU(>Iu)g)wA$->UlZ7o|j|mncP*+BwNq< zO7f6;CYAnq`^)vb>U7#ST4#9Na+Rc@=ZD7GytDP4((`$b?H~|Gv@>03JkVObI*o9G z1_ACHyXko=6zaMAOxx{TeXf5#Q?L4E>o%v>WxZ0K<=Gu=GwXBuG_n0nJ_UI|bC>$W z&8^QAOQV)qsazbs-?HzVtj**6e_Mg@bm>oo(B9+N6ZuHv^4(T1h$#3ir=$L!({bci uvMPox(kbg_I$}Q;C|k7o&E%Ip#5q9 literal 0 HcmV?d00001 diff --git a/sqlitebrowser/sqlitebrowser/images/editcopy.png b/sqlitebrowser/sqlitebrowser/images/editcopy.png new file mode 100755 index 0000000000000000000000000000000000000000..b9cb0c4a402293ae3a1a4d6f0955d25160799137 GIT binary patch literal 306 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fY)RhkE)4%caKYZ?lYt_f1s;*b z3=G^tAk28_ZrvZCAbW|YuPggy4n7feSuI=L!$6_^o-U3d6?3jmcI0X{5OBTk(f3q# zPmlG=?k`#MR$p#4%-1(Y=NoLbmsyZB$|MGWvP$^@q%1VoQwfVvK{hyp!ZDjX~pZUO% zO$!Qjo~^wxJ92xPjP--5Gvd|6D&P6-IixeaBUJv`qSHsF&Fb_%ov-}POloz~qoAWj xQ||BICb0X{iRn9*|GY5qVgQu&X%Q~loCIFied;0(Y literal 0 HcmV?d00001 diff --git a/sqlitebrowser/sqlitebrowser/images/editpaste.png b/sqlitebrowser/sqlitebrowser/images/editpaste.png new file mode 100755 index 0000000000000000000000000000000000000000..b6c06b25d07c46d76550cf7a5edaec9ff1c7f487 GIT binary patch literal 328 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fY)RhkE)4%caKYZ?lYt_f1s;*b z3=G^tAk28_ZrvZCAbW|YuPggy4n7eb&db6Ir9h#po-U3d6?2YGjpb@F;Av5Rw32IH zPB*`|?aij^r|crG|MR)9E4Ivm$@f$0EiTqN70Z*ad*`j{a9nV5)r}KcoAu{7ML&GZ z$9taP05ivj&C3^*2&}v=qQ|gBCn|n*X7=>iGR^e|4vTGjA{L$Uy|*wqa^mbet_Anp z54aoMjf*~G`r%}G(z=RDvpeTYg~RJAzw~&kui_V0-{kOBu>SO8k5$Io9w>RU`m($2 zV2abTwktmS;I7Q{4|;t!FRYi{+^FPz-}v3L87oZ|d=uXi>TrSkyw8IE1NXnMJytz9 VV`FyuZ=eSmJYD@<);T3K0RZjWghl`W literal 0 HcmV?d00001 diff --git a/sqlitebrowser/sqlitebrowser/images/filenew.png b/sqlitebrowser/sqlitebrowser/images/filenew.png new file mode 100755 index 0000000000000000000000000000000000000000..816bde5fe199ac2a62b82a7273e46691d2a664d5 GIT binary patch literal 231 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fY)RhkE)4%caKYZ?lYt_f1s;*b z3=G^tAk28_ZrvZCAbW|YuPggy4n7f0%Z|NI<^Y9CJY5_^D(1YsdXV#g0uSqj{Fi2p zIs%*i-)+4V+`4V$L=S#edk(1&nnD6UG>)#kdF0--v)Z$6zGh%ZVrx!8h#MkdY`x!i4{an^LB{Ts5;hs~c literal 0 HcmV?d00001 diff --git a/sqlitebrowser/sqlitebrowser/images/fileopen.png b/sqlitebrowser/sqlitebrowser/images/fileopen.png new file mode 100755 index 0000000000000000000000000000000000000000..7fb9346b5a8aba04b44ff177f27bf099d4624d43 GIT binary patch literal 268 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fY)RhkE)4%caKYZ?lYt_f1s;*b z3=G^tAk28_ZrvZCAbW|YuPggy4n7eb-S+}VmH>rjdb&7@P)004R=004l4008;_004mK004C`008P>0026d000+nm#LZ50004T zNkl*6Rm?+W>1ONfV0wSubtM%T$e;@JY%^R!NuU{*_eECus$Y%fe z@gvv*et!OcA|fI`#l^+nii(Qf1+tF`3JR`hZEd{-5I~G6DJfIVo;@2YCnv{eXlTfw zrKQE7qN2heB_+iGR0OsKXgI^OXU`b!+_}SW?bo?m5QaZz3RdjIB6!ecHj|*j9B9_U<_+>1fq@Y;l$pX*s4|;X@ZgEvv0J7Bx1DB^ z)|s}`nf~Z*XXo30ckkeT)8fZV*LAaV4(~lt6#yfGwH9kFS65ey7b(92w{1HQhXc7S zSgzM#1OV?G+4s+7vG?5+frTERPVL`s47VliV`(4>^j6No6Y7`&M*4D zpNGRh{oy^!O^vFePDt(&#)3Eq!3UO`8j76b@%XAyTsY^*t);4K0K{JsoM+M_lZ=Sw z$Y9YJvDK2%Il8W!&x5ClWwl08G=Li&E+0unz~fK}WC-dNM3BPZy+7|*Q^MqipaGvv zg!P0NL4#tjK#q$e$s|w^lQB)xS@0Wxm=qBpB@{pv@s>;rycM1f$8ISXC@+}+*Hj)1A&LIOzW1cV4y@IC^NeR7m# z$+}wOMu#!xr=R5lV6|Fd0>th>rin~5^2-dd22m&!`1qN!EV;S4S-8>h`1nZEG_-B| z;+y_nt?&E!csw#XhZuqEv>*);QK;*h?RL8W7=~f)x{m#Rk1>YrcFStDdgA_B8(r7U z-g{zo-EMB02Jby}T|X)Q$LjljzP-Jjt+jJmmh=7n{rsZi-_^sz w!`w6t(=@T!Z2le?PGj8f_oS5mCiWlc3%pETS-7l;UH||907*qoM6N<$g4>-xr~m)} literal 0 HcmV?d00001 diff --git a/sqlitebrowser/sqlitebrowser/images/whatsthis.png b/sqlitebrowser/sqlitebrowser/images/whatsthis.png new file mode 100755 index 0000000000000000000000000000000000000000..5b8d78e3aadabd5d8d3039b3c6326e8bb5c53377 GIT binary patch literal 26167 zcmbSx19xRjuy%}zlZoxj#I`-LCbn&!oY=OF2__TUwr$&Xa&F%5e!t-MTHVjyy{dP2 zRj*ZDwVw`Gl$S*MhW8B&3=BzHN=*3+vHq)YFkfwdy$$adKsk#@tHOO1Z#a{%uXlI{ zDNScEuy5D@RdA6CwzRKK5*Kj|7ZrOm7k5J^Q!qJ0V<&rCQxi)=5(!HuQ+InOYiANU zjkfro6koEb4o<(-J+dwq$B=r35TUzWhsxq0EJBbqC{jLzz&S$GMHAKlwRE&kM;9}d zZV#LIUt_+?eAwyxE`*~jNyz@Y+BRXfF3Bq0HM~3n>YGxk;2*`bt=(~jsI4*1t(P}n zACsZ0WiB@oPS6t+#nF&b9tj8lc5?XfL#s>8Xd~wo0`sOApXr+_2p0T*Ki=)@3I3S_ zJK)hGDfZPPWos=W@wz$s`SlF-zY_oV_D2zGJ{TB|wXLXF+EG-Df9=IwYy(z^uXvESF&5Sk?8CcyVDdo|ayMJwGJW>z$L z3(bErOI78*YPuWfu=ZL_cQGxznbrt*O?@jmO|)~4eU*&zZ*7zB4UHa>#ho5)TW*J~ zoyQj_Wo%D$H27VrQNfmkdoTYObO!Tt2lBSMvYTM8t=-K%_|-X*YK&;FlKolK7!0ic zWHCOXpyZihSTW>DsOX7a$i862aOtOA6yE6Q*1P3NYiQJYnyzZpufDmI1VT1re6I%7 zTWA7Y;ui9G{z{7fRp8aOFJ0!}$6h|0c6XM7b=A86XRPcv?4}jC(ypmpA5!5oTq#h$ zEQh@Opi$Em_)o_K{a(-{;OE*X@_C2rl$HdXo+F%FvJC2j za*K#Cc))hNaLr$GswTYyCw$pUOQ}mGDLeMabt|_PNm)C&O0Th3AV<{#*5Wo?CU*eg zpL%P9qD5d`66_M#HjfJ;;CJdWr3rVurjNk$y&N_Ek0sV1Q7?y4_Q1o z6s8qp80-}E<~;t4O_S$s3Di7lf;_B;m~@A6Ng^qoMdE-<5R~eo6J1X$ndrLiLN}}6Dpy#pJDV>1fhM_=>g*ERF-iv5x`KVw1WN0^+^bDkX zWOB%4T$x4Ux)gi zgu*$MHO~TGp{LTmBW#zET0T(9$n-%(1Zkt40#2oUC4_U3RtY>s{gLdigC@bkudJzN z_hzkI>67*II$E>!H(-dFqq!iG!{aYeq3-Nk_Q2(HUmS5!p*M?4P@r@O$OAbYbnN{Y z7|H2~s2wzhZU5v47-&>>i76Yz%xwr|r5(9&dadWkdssSwSqh1V49e8y&TSKg8qf0O zq4)if$Tvx7QOb5Aj-)29VAE6ZTYzGFI7uQUSGHk+5Z`6uK2d}rCxX+S+B$2esVHY9 z!6B1|!D1uYi2p<47H;2_K>PzeH?+?=f))Xpqt1oCqvwNOyw);15)IKViZI_<3HAi- z=e!b2;ob6G7x{tl=yH8ewIz!UO%R+x;U*@2pkd#*&^P46IaES^d>*}kL2=lEOz&g9 z8y-}uN}B`YoXW%zkJ?~sr?Y&bpiiqT5z_wgc}E?OaT0OXS@|ZiR2!b8mjU5VRK=I^ z8n4M3D-1MX&?;mnyIN)KvKrBH{VCg6n#Sc(9W0NH7yNkgiAC3*PQMf2@;sLMwjO*>i*WwH+s}F(|UiB z$Y+0|N0M*%cyk2De8}-515T_txGJPpAwLp|kaxmkN}3Dtj(@{oici&N1 ze`Xwu!^mQ^l09Rm3T!l|MA7f+vPqvLMzDbDSjpVIFkCz&%rpJ+0OCoY+@0p#6?DIJ8u}37#6=JP3ZA2dy5I#5Y0slcC*OldewmVw>8pDdX>Te{5TkiHr`;}+i@a;Ffvq}(utDXxQ?s$ z4z2myuy+qjnpq8*5iS_Zs}^2MP#jl()bcY!M&N%SD9xJCw7^-&bH(I;{HDl>2ft19 z9_~+EU(u-0iyL53;*3qmj*lxpc*fa74adz-%1-S!%g-G_t(BG6e&;2Vgp)Wq!<9Uz zcP;xt>@cg^jLQ5(Gvu6^u!olLsn?un`v?mg!_A+)bW%EHHfi<@$?y$s1L=;&!1L~2r9)}6bWRh_E-pT$+Q*>!sdI!qMX2# z6Ia82LIxo%u}<+lx-|oM9XU&R7d(7NV}_0G!Mxz5C;&AP6-{t=KWCMGi%(3>h?y&q z3`&S#L56;hDsVL3CNpgD*>EWf9m6^B*4APuz>Y+baS=pG$oIPNA*QaLlKM%waYu z$dn{KL3#Czv24ITp16>n-BKE#{;=MyU7Pl!1GbYqC}D;ByozPQ$b_ZF0h<7yH2|AMy$3-Mi9cZ_1((Lq%k6 z_`Q+F_n!rf*jUcTUBJ#S`m=MACb6K}Y4RvdefA|)Py%YGL5 zKXOD1Iv0vWf;m-a-p4V|hN^O-KX}V^*)373^s|+S^R7oH{^ojN-M)#T3>o9k8RK$v z#!Emn##7vUEqrFG8hMoF!jPk5)84 ztgDCydqLrP&2L95Baid94#IH2(PZHHc)V!G&;eecc4C=|cguLmgc0;U#N|l8h=mak zEjsA%%GM&EWf4*-n#V>}8aJMx&Y8HfX=u6x7=taMcNP)u0rTm5GWM1;jBNc|E0>bg zr%~4c{U*IgCsfyQlMRx-9Jv<4O@_3@`GsvLMJ}z>U=KSCZO;NW?y$(4vHaiv%ubOh z7PqLqhcj0ILS0WcstPgNgS3MMv$yMu`j$AyX^J0%_pvd}obC$-F)Duiss2?~&G!v3 ziD?GG!XXv8ca9RUngbY(Cv?u*Ni!-ZNG=~Q9F?oOGR(m0i!>0rf>Lg_+i(=oWlqK| z9=$Ccf2t+-s$S4XJiI2zYXfna`7*Ps$*^N8&H44h^Ir3%^o2%Te(t4x49u%CE~tvh z5sH}X?(CHJZTS+^b){wC6=&R*p5Us_5&7C3uqtUzYxD0##1lGZd5JMoa>!5~D(xCq z_G3+S=>Y0jVw%7{N6*Z6H;um4%0M3|O^0AF8(%%k(uVgdrRkH$^uA{pjb;?B3k|G~Tvb29u&Q{F`6Fi6S^KX-2p|3$= zp^9*+-`QHaWD!Gtp&u)}{Oye0R~M!RjR`JFZzl4^%wSk+t^%K3?idWS3NnfssSU5v z#-o8rc9KUK-bsSvK+AL3LQ5nQZt!OBsJV?N~P zZF;Q9zrg^89|;~t8{wh}8(dVgrF~sdA=i1CU3Q`dXcqIWNk$Kf`6lj)pa`NxGS3-@^5aPOYpM4<>CJTwag>-(y-n;i`7e7 zob^<$JOkpL>Xz{}n(iJii9WqVIT}m2?&m2I#sz{pY~+4+2BA`GthP}*%s*xM`7uHs z2_R(ygsyCs)mPuMK)(-vWm{QCz!0m=BrjFl_7Sc30x`V8y&xYK@+FEDl4C0R?2)Xl z*T`I!kn|-?OTEPd_TAq(#gPbGaJg>j`DGjnvu=#L`mlmye6YAO=sAq+A^iOP+~sx4 zz8#$_>i2h^blzY;I3OLKG?t>Z>jN%B{_HKc9?)LV$#F&U|3#}+>|(vEBccUC^EfpV z23@^n<(Pd0!e&^^B@VyfJ9OebtA3a4u9f^A?+s0TjaGG?ROv7oF0uI8z0#YG#sA4h z`oqK=MvK9qX=p1N;WxyGhZsMN++(Tu_Q%bpq{Bbo8iBDXAk@Es_aWCJ-zF(*&Ut*g z+V)J1F^>a*#lhJ2hz57G zeNS{`no{)0usSH( zKToK0c52jfavNEpG_PVSM|N=g-^nfFtz|+Oa9d4|`4H)AKJ1+ivVYg!&91cQc&gVr zk4%#BzCC(lyL~?X-b_a9@D5>6|3Y1sdn=q*?Jp6h`&;hT|IlS*=I_q2z4d|a$mE#$ zk<))j$y>!SbaPSBPK)dHf~Z^hgpxIk^2lOsG@GSM%kiz4{fRCm@>o zA2Q&+G9Ye*6jl#G(RBmt$&4*PD7Nh=gsxpS{186YKViJ796AP-mw8q$#s3n*-)xuH zA6c332D#ODHDAbU?-25(bm%Rci->O5Y}Yt`6z2FDCQZ@$0oj`_T3E@}QGm{kzcFsb zePOk&_Z!)x0`GaX*PQKag%v0z3Kg0=3@5?(CboRC9mS`$z3G0&1Q7qC_}OT+5pU5l z`doz*ZY82XPd;P%no6Im(9;KX?+hElv4hMy+q0FK|M1@yeA#mxvmz-!_r<$h7M=T* z`N)DHKW>1(h}TEt9(34lV{&+4q`9tTXZDF~Qg*m|c-&lWa+HwWW$K3Yro+Q){nS0V z1+d8sj@-!7j8*KU^L&osqsyuDCW=|r9qFY+0BvYA$EOEJcYR0bg0u9@+&A-m;}{;z z%zrXyc6}O~;Q6>Xhhd`c2O1m=_wjhE#%4Ma69vvTb1aZ>xLaUB;d&|giQe7jKPPGa zrV2lU{~L}K1*qm}+4x@5{ck#Xkuy;Hz-NmzHr7#?PymKNfBoCtnKf>4?x0y`LebOIC< zvm{Tz)If4S5+z&b9ZF!`np>Fp#n>LkwK`_AbE-M1mHN--6_A&b@4L0~3BM8~ToWO; zmx^W@mmz`}&cX4`G~L2m;jHCP06%{O;o6wQ_t>66fw^V^`b%pOJu~t+fKax)5w4jU zIb3?@?TI(!Bgxcef*NBe^dBMwRU!g};e8}$9&yh3Erw*=hmA9FcQ8LU*uJ$FOJ8gd z!2|Dax_6*g!|3DgAeoa~7Et?;y~%s3ZT?Ka^V@)PVW2%{p?nJcPhn!1*aeb~Y9e!g>R+U)COoYll zJ(;Es-Sl_C_^)-}-@9l`xSfTDr#Ck;0+ViAOVtx~rMwOYQ)!tD-IK?dwAc9LI3pU|f-J;&vv|n#r$1zo$McS3>R~J@FC%g=}L4)Z(yh zKfnv=6Ws}$yHs1JD;e2pGiTQK8<%Pi`ghB*Bh`trux5)<8h5rv^kHM&Ivz0xT+`sQ z4f(rXV@YNh`x|a@S34{|m~+)S3m%NIH-8RXZ@y&&S%aqm0Kz; zKIC^|ZUU$~`xbC`KB{ipMH6pNAEXqVmmDh)KptgFCE?i9lL%TPgI0|l>`LP4jOV^l zu;;$BCi?NeA=E#@S;Bk}Hs`pGGd68&5ERn%jMNo)wb74$d&RddyhCeL!mxl|M=)HgYnr?G7|nV+YMss?4fclS&XaYFMs!~ zyVBqo3Ec{%ry2ngpT|i`;?FBoE+d|v47o%*oT-8F9kv)^wZkwwYQ-?8yvr`3qo$M#(Gq@fZ0Fjz+fF=|xhuxYi49}E% zuEs$d;^-rXR72~K0lm;~X9gTgJ8KRcOIU<;a-nHdf6okSaB>>$j?QCZ4JZcbo*?!; zoOykDxw0qlPYZ^|@*jA0;DT^3Mejo2Y@dJU%AQL@iWBF!rMMIiY@TepZF1unow>hJ zVFe1nGcS{RzlAP8ga7VXfD!$~WSYj}4HTfI`|0MUIrFDC;IHh?Fh|bxfOUDKK5W;- zp&A|i<3kuGWYFKWm7!gAgjihRmZ47M8>cQU`ha@DyfIDS`(jf}jYVC7J=$sLRVh1g zOyq}GA0%HsCxKpD6=6og$fqzRr2uvbq1EIGc!R42QPfJhMpmPHH5VU~-O;r*M-_dk zgGPRh2)U^DfA&H{Pr6s4W*IKjTFBA=Z5Q z;0{QnBV>*5oWg5EqR4J#7FUV=ZNU0_{`S>N{PnISK`>VCj7ZbFzd@!Q7OdzGK zzfm+^Y(;HIjX}xnOGH+#bY{E9%4fe=+s^QN!4@MA!fes9(`?lw+(iD_g`Kp7%ynOL zX|sDnA}4!C+46Eow0ncHcQrxNC(z_Ifdrx4BaI_W2^+0`krqu~RK^$WpesN2t(OUP zd}8YwLs@^JP|g~^RmoDzrei>oL_OG#?(K?7KxlpJeEgiQ@N|6d4;nJYsj$XATl)@) zb7bO6z|R#e*;#n@;6@xJcLo9zQ>m3HRK#tx#lWEo28EtWyf83rS4j?|ZbU#eZCeeq zjMPc$50W4;w8VlK5%AGM)#4$aCeLKgKK%wD@vD=(n$CE-7SN@6e}443Jh`Rsgfcr* zO|{eHQS|p?Dvtb?Cxo(=woM9=^cMs36aPyE)z`_~C5fOLCmtOC> zLVTT!L`fAxZq?;r%TBS{XAeXUJ<>bS%kDc-D1K8A8wQ&A&>DV_7Jiw1NZI9l*P2bk zZk-{j-pY2E`aXmBeoGGA1_5n&!*W}IonpwWGjKxr{K;x>%|>AAn41s`sy5?Q9`9ep z7Y-qPO!cEnzca{&6esKCYm|ao?Jps`vN$H0e4>Z5C7z#QF6F77-%-=|Lk48tfvs_%f%W$z1F|1o#nzF z9MhmEdC2Qw;_G!6dr%oTG^;x6sj33v6u|{sxH|yBfd<$4fXy=(}Mu12M%yWJv z#BQ2*rHMpy`*o7=8ia8T$(@VQ!N=`Vt0p^J(h zwrqT@x7Sxg@zf9wTq%#=JQDo_9QR5BGIJ`PPYjP#*lU2Bz%f3cu*p6ToD8P?d$J(Q zH3oJd2+@u;t9twKoRbb+fj~}No*WflO2Ru;NDlu?x4+y;Ze(?E`br59KR!HiogOttj0 z@2K#3AWj((QHa_-eE|L8+SyVi*Zty&feJk(x>iBI z-shpqP&*fdyC8K{Uz~2!_8Bm+Xr0dIzKr+tF*$`Q=d)+CUOn&afo!07zwPtmZR)r5 zJYLCQ3CO3O`MVgq89f_hic7F1o-jJ*?UcLDe zJwxOazC`1N+HrcC@9-z$3O{bk=F4(oNtsg$&)x2=DY3^eKU! z=W1P*UdC_zF*t+^JXSg`53jlZ?eJy{^H+#W`bt;r_%ozT%k9 z93?N28p7;u1jaQ+$U_m`B||WyJuka9=b{ZUOfhz!Efgmj@5LDT(t5~fs~w?Ara%KA zTWQbL0ov0K1L2FI5|~SmkH=T;A#r-`*nf6!&>=WHP1~}T|3rNVz*<8o^Wp)G^(Rv} zFilU>yL`;Q+D+mg{F+-#eM{YJ*Lf>cW0Cd*{#dS&wH}Y~OxcsHs@C*u z15c}^;3&(~+IIaT-{~nxLx7po{WN3Os=6taSGpmgN3fG`9xhJe#pi8Tts&VU5-?YOa9nh`Nz zgtKGUi2a2B8U=X#YSYAyZl-L|D#+N?@fofXolfe>>`+UR9$_(zU5h6yc=T(EsYZ8s zGGYoRAQtB5P&1?Eh2#Ne|9Cycz%}3n=0!yuyZhAHjbWe-|9|*M;#+Fzw zim=CnOs}O&>dC{ofNt%^CmfNd+RJx7+J@;nbVJ{lEyTOIc!+d}v%8pfufkt;x5sBu zeJ?t0y6&TH5~{R3VFHrGx%Rq8S-*vl0@1Vl->%b+Y&#>ec03C|{dyfAFHJ`rQ0uNR zpmcI-;rQh*OGufjSZHo99Te9BFBuxj4hOr`0(N`mnHw6|w|l8rpCiFLFJ%WtAI zrP(p`o^7&*rA4*_YUbw>r=NAaZ}kUO9Rl2@IP6|FcYgVuLa+81$-#Vnrx4PA0^P>U zG%w?uFF8|K&TQ1-mZDp{*Ef}MICAVQiXQCxkhSj<|yP*D|$+F-Go#xZ78N zJ4(XcgO(xyUr3;uE})bA0BaoLpb!gAW2NB=XK`Yk+3iV*of6e04Gm={KIqp|VdfqV zsGo2Mi=2Htg|$b8Ul|Dx)pSpLyl3s{MPb=WdAkbB+>Gc}ZYx~NL7bcNJ?*%&-evB< zxOz9X7)3dcIp>a{vOIwVHo}2R)7>xs*<$4ImDgQJ@7kry71NyIvgG!I zJpap#w}dQrH36G2=P9IhwB>}^4=!svVQ|qOYDDDv(>#E+pUI>VcAj4vc9p%UdmdO-xb#;G`*cuRLfr zQuOdq=E9W^@L^kezF62=Pt4hms4@y21%di_N4b0#2|s(2C!nIgO9H)l?Qp40v4FwX zKSxf;Y1pDIup&gJxK%BDk7Dw(o-5^t2O1A?cSD4NDa|em`|})9?5lFmk2f%~urs)e zpcgPebXRVBP9~6lQy}Imj_4eX#nK+G@aZ}6xA+m;#yR(XLlM8%r-zfE3%r-O8JIB- zh|mVy;Ufzge6I}Xnb<>HPEP$;I}==Jd!z031e1yTO=gdB`}&=uI~H8E$KkbqAVY1z zI_16`h)dS8-yOCAW<(G)bdx?3jeH2r`B_d#>M!+^l}5F|)!Rz4$a8LHpnPrhNxbyl zG@Y62hF+xgQFB4lBrniRdsy}*Mj)w@KRBB@kPVeA_Yjz^b3f-XwBJ&|f`Kf4^a!qS z)MNbi*UjU1zV{Kn++=s|YJQAJsWatp3DJDk^OqC)E~vJFLSeoDVB%ztiArB+ozku@ z;SaSixR-XtL+AXPeb3hz7}#bPV&_+B@$-8PQx`EC&i2qvw|>K3&3%fxNk&i-6!lgxdFF??luoV6tV9Ly=l#b`Z18d?B5!j8}}T}_o>xf z2c*slmvtN>E*elTXrb!Z5;9k=3ee*yjg3_ zD+Ws{-HD)=Q(RsputXi z94TB-1)}9u_RJyPSK{b8u!y2Ohs`Rz(g&^4%s3#g6K@g$331SD4Wz3L-!%Ql>xfde zGz2fNzXBu5fkMfr5AR{COJJ{0>%;h*ROROnu=@ALWomQ@(a;D2PmYG3zd!I%DRLOJ zQDOg;c$jBwMSt(^`o#ycB!?}Ed{3)%I|6%SPNb-To{GfT^%WH`Uv$egdgXbAaVQ=3w>oPGq`V-at!XsUs`9mlO?I?HH)AIt^`5s(YjovO#RX z_EAX4&Dzcnv9{`P2VrFU>!6zb4mK$TU+LNc1!PDkcaFQtSXXS(!Z}~e>RR+%KMF#F z@nAey*7moCrPHS^5QXSDOlzVZ*z3lk5|8-qwIe(HG1xaGBPv)>?wd7ybha+HvzdrNNq(9k(#>cUehlV z2Hpn4JeS^t8~jT1)$*+`kI#)Di#l}Sc zJ$g&c`-ldY3g9G7K_uqf#^Ojq{BWrv^|4amazn6vHbK^hLNElw6!6RWPyTBui8n-q z`Nv2C&n-?PQh8tVD3L3Uvb;(Ph|W0 z@}q5_FzEJfp5ii?W@Lm)CZ$`xIW6zNNOjoO7u|^kh6K`wMdG*042?82fh8AIm14dG zkzw4EH9ePfbJhtR4ssb~DhJ>{dx5&r_@kf1Y>i3AL?xE=7Y6)P+o$NWj@ORFVw-2= zSehoGdg_RFTlAOl`3u!;I@*LJAouJ4Y~ZYs&A}y68bSAagP^>pX`2HquD_kACD~Q@ zZh-t_kJ_-}XanxO3{b^T+#1toeDpN~7oEt-Xn!|esE;~B)<#m z8n1Ltf+{$+r){AT?E>)F-SPlYo@|~xp!$28&X*WItk?Wab`;MTG|?g_o-{B|Z9@4L-+B67w3GZQMIX8HE&e6F5=b(c3U><) z?Y7xC^*9A$zj-mYsAbkKfR&cT-4XTps9DBG4z-4m|`w+)>lMBCd zBl;k?CjqnyR;P$wQum$2e~f{Vvv{Z%(KLqM(87_+w)y#(f9U~GSs%B zcDGDYcz-r=bR%B%5%hgSsI04p;7qDL;`h!zs#pP%aZ99-K2b8beH$h=2SjFyJ4>dM zRtenw(B)|PCbsNadyd+6zeaeU56SO&B3#1=61+j8J9osQiS+B9B-`y{gq2mfUC|2p ze~EZ?g_^gxLW0q7EE_~^{ zLF{ZT7ynqJqKDZ#X5P=<&GqF4aJ7@l%ck#3tc^|J5E2r#g%sZqUgPUN0^C3=4 zIFz$fo+AK3OG5jd+`*E)txziN0JxUj&6vrHr9F_%y@JSj(PaKSTq<#{mw{cW0pTiiU3Q2-rN z{|a=isncimQ$=(j7X#1#^1PCJOYzXeo-r2r`FY2DSN~Ua6X#2Db$H9`^$KL&io4{2 zL8sYL!3Uebgl+Ar)~~jIX^|Q^_IB2zMr{?aEY}Y%7qxKWa0^jpE;> z!V$4}*n5faD%0lfrv(S|hckqJRS4n;x+A_tLxZfrduYCN)JJNn`>G!5`Pp6U73JQ5 zT+ji_@S-`^UHTk6(;WXTw3$AX+cC~jHZ=UrRpOA@t=!5or*ckwHm`JM%X@Sm>fD}q z&@ZLfuSIFTI>-Bc3zDDn?Eq=BNuBT2s4HU>asSO8Jxb+n?7JwQan|Rx7gBiH@8v{9 zLI(-O?_@hq3`cxL!9zM=_KZS zFM+dEi!e4V_2??H&)&bDt(d?@$WJ#k@bTFQr@9mGux#7lA^y`lfU$<#gn9=25Ehls2=TXQYCr(?ou`Z}IQ%RN0M4&S zXsyZNuRqLjW!cNEN$!A5EfU}dlC#yR9v}|SKBsu!hqsy5lM$nk_HSt^#Jms&ooB@0 zDVeT37@Kf?9{|^X(1$Rh3rZn3w#=*VHk!KdMF_}~j2*=4UY_zti2BDG$W6&)o-Pg; zBYu#O7N9L@?#3^YPXvms+L-4DTqLm>35d%)b+}tW0r{ZL z&{IeKDUjU2cuUP6iN~A5AF){+L;LRA@d^97KcT6816g<`cq)FzV6f>oFNYLgCm!?c z)}3d^7UtZQ69jv~2k0NSgPhHMYer@x_V)?`dt$|bO%2^0{BjR}!e|_>irGA-pR2Ck zKtzk-ws8?TpQ|&_=Lp_Z9t)IOy+Z$Jf&h?EPd;sbzdy+{*E?Po-mQCvW%h7MJPj#Y zA;*Z>bEsf~G)g`_Eu0ES9@4gRDtTUi1x1>_w}PIghdKi?_RZv}jNpzq=OX~!CY38P ze5+aRxMSp}yTm!pwX3aB%_HdY5OF{cwO*guH950$eG(RwlA>V{8=I%5#csTd8^KK2 zc==m-rvOOF822)b3o8G02%y;&Lt?*`=}qLi6?9&8R&dkA5p@Njo<>8TwbeQtU9d^s zj(}yin2|mr_q9x@t^nO5UnIF+2lAoab2!9_!HE@5pf4flqI{=E16c;q86ECjB|z;~ zpw%(?bi2Ep_KC5FjNp}koDS&q?k*ty}1T;5oB02oM zbrN2mO@Q-6y0R+=)Y);_3@!!9M#F&lOfGUmfV7;IwQiif;)Re!lSU3o!~?EU4&>Uw z$^C`+$Uzs)Zl+J@Nt{JW4;TRYf$%cCwWpdXIYJaop)Lh3*e=dKe3fsM?6qDIb)9(i zgw*UO?#u`6%*s|Suo+au6-0sPJn&p9O=~oJH?~kt zNpYf3o(u{LCVSm>8kdpmqN6u%{#93al9;3OSXY0xT^8`m@lQ}U;0#EB2A_$a>`Cjs zUYriMe=CQqX&4Ukl@wm1gvY=RIP|#5?7BRc{6ns3?1)hFTR(VjSDO#^AGFTuXen1Edws@{2sF|SfN)X zp=PLrUE9d}k2qig>O8h(wDqYEUgI`|e5f!=gWvQ2Bq4|vY&%Chij2xahX_eB-%j)% zpXc7aHYgdd(u55)bND0EeKDz!Yuj|fzWHch9kAgh?= z%%^0%i7!f>Ybok{ZtjCd;2DI6x_xq^q~8Tn1+XHshU6!VQxNTkPPv8dt{{=Guc&3t zlu7bUWLn-svJ7&=PUol;BD6aq7&sD&`c3s67Py2hcv5hp^yLvlI?9tR2dAA6yhov1 z9Y#kg9u$9tNn~Hto4{T4ly&TrjE=iB@??|_9NH^pMr`z)pGQ-kH0Q70v6X$$oe@oZ zVf5zkv1RTPjZ`FZ|7G#)c@rP?R&Hi1*6{-Ue9;fjQDga_fs7oUnyM+#Z^T~$N7v(- ztIJj>!o>A3s^<6bj3#B9dYTGQ#OF8lqE1_qJeF6+yer3|tD}DPt?Dmq)QBw$r}q}O za40i3zc^?0ou8C&k^^OfW>`rJM&#D2-h4T#I`Zm*WkNk+(*V2ewFHhNRUvtt9%Jnr z2HL2go(7uNdpzfG>$*KwHg2O{k3+OMPH)F{c-2t9llOHbuZ#PIQmN-z!PId2I@|s9 zAl8h@IJ_@*BquLY=3U6<%=`!TKa7pmWZaa8)#(q|ph_VmWvFzQG|OB$lZK`T6df;_ z(K`kjozdY+pB~Vbrd|_J_>>q?-IOf^A(v6(bEf!dY|kwhDg&Ti9YLoz5DgE z_;V>=+L2br$Z8;(2o-^;Iqw+AA=q9IX(+v6R4!A37ST*(a7QRKFkcv@e~F^mSDp;)>p&3W_i(~H;myeVMYWzwKCW}ZY#jWW> zs(XlU(A3_>=YkmNuBZl2M1ku~t=jWF7T|U2M2mp;_#@_ag0dVO!a1yTQ_WaAWt4`9 zz%a{?*;At*n5wo+F(DX2rHMeK8>}H<>Q^{{Fe}mPM;0BvsV07kMrZM433Z#BPyX!n zJ|$GlDdlDSF9n^^gC+g)>&_~tEiMyTK~B%b0+CrrROgNk({!K!x#6Sh*Fj?h$LbJoqp}G zZ`sOy`J5Uuh1jIuU?HHu3ktQQtV8(zi74lEkh3CxBDaBdyYsj$TqqC6K-@&YO|g$A zX2>UgOH$T*joX<6a{MAuqEKxXZ7HtgTA|T=WDab``S>6 zwy7&9(&eKEc`F}ae$cYpGqvNx&iE|i=U0Pj>lfpiP8ry^N~A(ki;BmmKW$dUkg_F5W=v>eJd4FKzXY83v-jT)o+c>d6NeDkF zel(e}3)jlh4Wm{~X4C3?v#*ouYFweDi$&F=X5j|as~ZqQvE~X_Y^XhFS^(Ry zkd5GL`|k5-BuH}6zR+1YG~IYah=9qHV3+`wtF`l53tyH!{VHE!$-fmsc7IOZk*n=~ zp5sX)`iK4EquR>7K)9Sc{slK~9b<6!$rF^8oL|N~RoZr(yG0HVqZL8rODElxd@0du zp7;z65iHo5I=OK45_}6(yg55#Z0?m5cphQN_9WJ^#5%5G*3%bfo}RLK6gFD^6cM%) zpF)b22wK-D5A9=$5%6CXNR(o3UZJj$qL8`M_BlkfsT#mw-#;(6gWBl@{D4;CMKp|)=@a!utUx z!tv4yF|kUxRF#cKqQaU#1tg`y)PnPVYg?e0R`~IF_Ms3thRMIV*cs^XLc4oz^FP?c z1HT;|L!i@h3X1G=AoBr!u#2X6JB*CU;0w1c;0L^T_Kmc6ACYl-IZ~nnRDLx982Z7+ zi`RoEW|xPSljNmyFE2zz@jFQEexrCz=a2R!(3&z2n$d)or}qq?OGahE_xcBH-hJK4 zq2FL^Xjx+|yL`0p|1m7he>a=in2SB7Mrf4qNEB767(C*U@F@`}m~bt3y|KWnInn5^ zYNeO#r4H43V<`o~*sT^eI_z{Nv^>eb|kHQ*SUlW4d_Z-ioWMC@3 zn<8V5n*@5K)*2hM7Wt{9qqxdzOJC0-596Kg*0lj2z>Iv|leMznCfaNm6a`P;=o)j>+czyj+41Q;DRk(1Y337-F~K@DmcA^M2wYy%7*WY` z_n@fXdn8K;uE@Dl0=7=8v`>=asMf(>3MWdHD9(}g9x>F2mzlbS>+4LmR)bzYIB9Jy zVUD{)Jrmd*-I#jAt)looODzy%${LsFT3m(qso!j@a^0I9swa0+Y=Inn*}07JJ$Z4W zKF8y5Q&qnvR{p1&?+j~lS=SaDx=^tpB25=6A_4-6^k4%O1QBV{R76w+1SAk3$+BS& z(nUz3BBGQ;dMCOlp@$wIK#&kZAS4h%dfxZ2&OU4J{pbAH-}&|Bn(NA3*SuxsdEU8a zo|$`YG}hwUx$h%ul^>q4vu>TNYbVCzNf6A`w2?l6 z*cnO7?Yq5n`86a;*hup5>i%Lse|5ih=f_g_QQP9*&TdrpuS@i*tPss#i%(X+UKKte>Bd}r;cT6?a=N3hr)3*)Vwiqc1LG_Ls~cW?IW*Pb z&rIBI+fnd7duHU+dQa*pDeI-4QX_1^78>qc)u-Y)RpkGns;pl$$AFB;Hcc#FI?a5* zk(z$$=VU*L^O1H~tn#bc6ahtgxNV&Ws~Qw|1Fhl?-PM}p9&Y1~o|Csu zZ=1ZOrW)#V?%6_%!}9@&jlUTYd?<>VQQP$3fqQ(G*3rYQdg@otM8nsIbn(?Jj`;S# zh_RPB5`lV1i4RL{qsqkLn%uj-X|gjGAGk_4IF(9A#mmg!PAEJ!F<$-h;P(?LO^4ym z(JL#f(`(anq~EcjKQqxBVQcwi)VS}>2LZ-ytFHeVIn@8AEfb(^fxM%>Pub4?)!Z#` z2kR#@zB9dBv|?hmPVa8FKCph%bLN#J4^>*eTwbA`2p=QsWI>(PJMX*t}}J=*PI9vb9rBuP4O!m;r2^O6+mAzgtPF#W}9;1(gh*R@KS8B zI#}7@(vd=B1$b^%zN+M#%ZTzN86J+?m^=8=OeQRF&>p?{+v9y*m$a2{+uuHM^oFor zmTt~aqTIWsqJ3j*kEgJ*5cVu6`b74H z9C|*Dp?_?Av*AYe%!Ld2{)ncd=o}L4#I(HPG6xSPWYL-uVidGW(Ppn=aY5^EpPVKW zQaulPs+@2H`&><=Y>~@u8^GU|{8)#57cXem8GrAv?;Ifh z`2tWkz7!O^zM0=csO1EQu5T6$5DNN`TLyrDIzSZ6H=v;S1aY+RI#^s+Mc_BwxKO_~ex7?Tk>1*-ytf}fx>Q}hxrj$4WG>3z9Q|6ObpC*snnB>j50gm1z5 zej;EkPhw}=FDb>OVw{!;Ps%zq+_ZvD9MR;63`2j}5x5zak!5x`jil zZLHh&K?F*!Xqo6Oshz3ma48be_QNqZzZD{G8$4Sh>h$&TOa(Rqee- z2GdJyg~?HT5R}vMN+P`Y159k@?9+xDtXXb;cC)%W+(^{wM?5Wl26BqOO3l;1@tD=> ze}5+Crh@b_WG6TDr&Z+>T~ocKWAG*l=1+fmV~z*uX4u2n8?M0Yuo8AK>|Mg2-@0%! zm6O4oefiDh`GJSK^0=C=-Z2$YFHx!8N&2AG4&Pke@W@4JY}uTH8+||uY-G6RKy*Mi z>%!jTrT8u#vBo+^^xLO#S!+C*1-%cOm1+Vt?jU)zEbk`Rol#%^X;*O{H}qHEVXJM~ z3O`EzT-vwP1~krJ*_B$-=b5vn3=)2e8wh}H8t->V+_Tan2HWb~)P_Su{mX~3Zo`^v z50Msqrxn;?+cGLc=B**+Cn3{yy*}>ApRna2nqceB<$F7%BmTR>T~58vvR~g;P1 zl@U-X82%OcTs}c*HgsZ7N)$fM<(4u|GWxR*n}XEE4l;F0D!MFGluKD1wsQ1cC8ZYT z(VHc6L#;%?q>jOJCzmb-Sn-^zIQg&I8;y4btZCD63ozD>!lf`01MLDcP*$7^0M7TH zee<`*`sbpoN0EDj-nkyhv)>UxQ3n_rLy5=#2+{DI#vKu?XWa0Jirs`p`bh#EXN zCSJ~vs2Jm%$te$ojs*+O0Z_8$#snYvulVMQYCb;D{~TW2j$x><@6@3MFJsy1ypEG! zj4@2!dE}C5Jn?o3H;UVKv!geX9M#^!t9$&In6+ykJ_$9w0N$XIsmobYES4V=$+)*o zB+hMDhIPwOq+S5iG+Dy6!lO%`xMmD2tHX?~Fnd+OR4<;1-@K%11T^+>mHD-^SsXQ9 z9vC$41LCKVJ|MaHAI~1Y3;u!9vyT6TeGtbK>Zad04&;x9fPY|q<#%BNtFLx?##t^K zI>MR?;?AA`g2ex5iQqeA88-;V7zAaGlC7sK-;+SAH(iNvM{Fm(X7|Icry`7;iqx7O zNq2`8-YjSc@EEvdPCezf7oRwwUae9Qy9Ruc%WWA&_N`d)& z|N217R|*|`Bi-W4KiI+Z~A3|4knvie?tX)|N?{*;kpJ`ozWH0LC<}ffmC$`pE^yiU;BfjV`TXh4ECJEHE zT7U3c;ErEpWB7ba<>YFoOClsIVG|$pU_?5te(Z2q3 zyyPRc^RlPqM3K_>hMvO8E!=!wnJ(?6g5}RPP)iqXKy!^UJ=JyjwjZgDGu0DUV{E)n zF*q&U`-H36>)=`Hq1dJ#^nG+jJv3mHzB;O#=_M%;N8{(V*nQ=cb%+Tlst-slf&^MD zA7O-0d+XMWghrWG``}7?$*BOIM7@C&fGunqL`-yYW7b-UDz6UvEp;`6>XK|N0yIDh z`85Nr>T>jRZwApND5bn*Lio6+!yj`ap%$pEqVL!)!;-*av-@tosdi-u>kKcymFp`V zohn=e>MB?zAS;ClCGD2n|3wdG8GJHC;8BlJIp6)KYHl z>W!Fcd@)7dTMqSW=N>24{Tvj2-Hl!KA^Q=#7T^W-TZo}EF{#G87kl1q4z{N$%;eLc zuFYM5k8jPLQpak=aeAe@`bmC`R;eHwHJ6glT%9<5m)iEAahav25T@{^#9Tg`KssyH zy*cK<;8SXtNawWw;((`I+1aL^`Oje)rMNcOWjmSPN8QLxhZOC-6(zR|F7<8G&KW)I zJM^)b;EQMB7sE!Zg11}2;_R2WLTFQdfb<2$TlOxz`z9%6i@eP~OB zlUM{VJNnv1k$TkEEG(N?y;_~Zqs8h?J`Uy8sg1g*-z2B{wPQG4d-b z^i5!VXIog=UH(`C$y&vPvhYQ_1}!WFyLhli6?;Q>CG2-(8>%u&pIezzb1t#nXi9RJ zNNl!cDRHmm!F(xU*4REDw&V1-%H0OaqGM^MsRL+q~tar8iwa-2iNOu~A*f@c6w@aOllYE-|hsxI8qoe6{vu z*bP?U{HMNG?d)*$wE!e*HsDqfsFW~c^4n4QulHh-un{N6{fcYzcYkLq_C}v58e~;u zA7;D4->?fW;|?sT=+;#dPUChINC^}_#>R>fEaJSk%$ZL{6a^ur>tWwWT7DJa-B5YN z8JH_w@dwT~PmH;C9L&bte_bt4-z5pEVm}KlgP4C-8)(PLT2B+VlvS~#hFj&4I4QP$ z&KlBZ4<*sfPnH8q@U!L>EnR;3A!@p@JwPPbV8y~O5oSljKa^w&!a9@dJ4$@4t-QwdX|_i zQD18HWeLV%9q?2|8V0Ei&5K-!+V57BR1mT!xd-}-d#E_PxcX195_cTMG5S{b+{MDZ z@>Lrc^xBVP-$P1SDl|Q1AV2mKeOokhmNf7|GhO?Y*=!U9X>ZXRZO)BWU8r7XnZ}B< zDOaTUmo$>I*P&g9q>hRnIYn`P|F0Llr~JhW20M8{GhEKpX$+6}69ZPmYaAG&$FiH$N2y z7|D+($#g>&J^7?*r0~>odUe8T?3J)5I2S3B46dmGwop@;mYEG4A+pfxAjwLKyal4X z;^IMp;<6y(dkp&$Lr2AKhCVa=GY=knmHf2JIKLz#5DJeTmQ&b&LLhɷ zh$4xoUc@@G#bd$KBJkQh$ls{>_aOIIJh347wJo-1Si(#EiP!-a@asy5z0^C~u7x`A zVNa|hL%%gp?|6s3VA(Il!NCojRlSOm6PQ*PXrx)EonU_P8w*eH|Fd3;Kg_hQI6}G` zx=_fCid`Ov7i(;NHmEvQ{LDeJR%DeQ>^?KgZ83`U`^-B1jqW<<3( z2sz$VEZd$A}+w@L$&n<6SeR zzHvCt8OyS8ZN8w6?ae?IYBQ1^WL@#BBt`LFcEsqPS<12cI_e(R*NOBKrp0)Ilb z@W5dr%f$p6cI`Ac-*H#%maNn`O{<+b`h6t`7%)@-ne*r7@qmxueKO;PY}xzwdH42? zaUc3pK^q`-vZy!Gwy9^)Y!DCZRJ)|+)%nsqMl5|S@?je=dqOVQ@Ria`hO-a#k~><{ zjj^KG<$^=eV|++CG1%S+O|&erl|nY|Zt{ULb|td&M#rL~dNI5)^O1Dx5!lNWuYX)r ze7^tgCr~HQdPS|Y?B7CMoBuU#{SONM5#mxzH`%(J+jD-O&i*%_-|kGZy?id@ZD!OG zTj5-*CtjTrZHyV1efD|7_D`$cibWB-Owa_?YqVWavFX2tMGLC1w$-`RGB!3|dsH!PP4TNeVadz&TW33U=p}~O*02{oA6!Vy5 zYACf{CgsxGk>XE$YeRc-!OhOFUMumErpMR7LGz@~hW`FeZFBjrbA9UiUJm{l{9 zR7_+;cf>`J7CFh)XU_VZpWxjOn9wtc2(8{nd9nPO?ibv6XA^iiauSFr)%5A~$O_iX z^$V2fczTZOD2jupeaNsQ>BR-XBYR`w4O?g5|Bo%B&+aBtlkL8fbHSxh1CA$mOswHO z8&qwwjEjEKJ~Mw;o-`eJ4!w}ZudhiHETN^Op~Zx_co;?yS>LE%mnsG0fu&vE0I%da zso@Li;z3yylhU9(6~xp+lirH=L%MuKYc4WEKfm@)khRnwp%~0lM{?4+6`GUI6q`0G z!bCFyq62@?b);&q>b-gvBa5dn6zH*6iv?ZBaAuS$Ci4R;)JHZ6PGK^3aoMcl4Bs|t zB=0NjAr4#vu`;EW)`UQBEB+rU{shf( z_+rV$`d12dO2`IjLttQF->h_EaO2Dt;uFT`51!sB-?^nAzd%R__XFM*l9gSOzZXm$ zBSVkI#SN|K5Dp=&h`Hwomzvp>Kt=?sf@VOxtvQsqcz!eSfov3^OpZ@=%k) zCXjKJ%ZWowRQVk+Agw#n#Y5ir{-eFM3fA>~rNp4Sm1$uR9j`q2t1Dtz>c?DPVFm%! z^DlLb;*XEjc+Y#)(O_}o!>e~UFqRwNn43}!l9ws!kF;3L~ z`1_*{(JxDVFc+_O9l0HHuTkK8nwCo41`R4K7^>64O{^FrK=PKY1C|2KV~>RlTmsoJRPf?htq#nZbSkB%h;@XxB!aLlv!m zPi~BP@OE3JFO)iEq=ST5xCb|fFCRxs)kCNJ`I;qI;Cu`VBCdazkm$q~#6$~T$5tI2 zBJPts4XBFI2fj&bWN2xha(~nBJ@}Q-0m<83HD)N?Ik+_SbI~r449>^u_9m>UNJ5e| z?n$C7&1Lk%a#qZF_4`wHgjA^lo@UQlRWO*<726p*+)52- z;V4Mn+od8C4UL#YN+F&UhR@Bo6B&FP z-xdUC7FKBOqN|kT1-&qXGzhh1(TXr@xvjkeQT{sfnU;(?JY5J5PuEzN_YKKZa4T_xWif=Y-7@4;LJvMcIDwqLA|2bU6PDHoA&hTzRj=vm}%-&azW|TvYl3&#-Yk|ix)CpnCG_fZkLOCiY8v-*C3C+`SKX6q`aA$M=}wOTH;% z+=(Pag}22{3Iqy-pwj1S_>3fzfR6ASYLAStgC8FoE_WK8=P1RU(f|u@ zN-jKCyNeIbGVFZ)P*@##ja}86x3^N>&YY!o5{4=EnUt9 z5@*?-8`%>hVLTL?8x{RRfptTmlT4UnSNgTt$E7ADLc5grj*l8LPy-ihO|}MY2*3vD z84)u%;^QK$S^APX#NHQmw)!*Tg&CJrXas z-dv(9BZApW#TR48-P1K>36cw*Rrsrd!nWD6PuC7qyxu(D`}v+(!qeLAjMRBdd4}2m zo}}eOa*ffQ`RNKmEZDLgq6idY^yYhn26S=4u_E)?88qX>VSP_VzN#+Nybl&&!4sOc z!@nSy;8@(#ielY{#PO$&fEhA-V(bSzHTG09M(e?PJo6nnn*EkGP#BTm(Mkxyzji6m zbeqqV8VoRMA}?5l&Tg`k5f&_84b(VjgW1JP4h39u#i=ts#U`V73vQt^xPcDu=GMlb z4e+`{bzZTk461r{_`=v}-bI`zIqVDK*Nj(sV(SKb_%t=D-IIo76 zIBwC$j^aGYFZzRMmR_(UrZpnQosc3qhs#=GExA3r9&HS+`tV4+x8?n~Y(X1Pu$Xb(&Nd=-Jf4Q*ot$Eq|WwzQ%9`+^i+`e`zeGP zkqCX%xp?S&(*E;FJSv01SftVXtNQ`MUJea&hpHvB%aaV>GwGw>H&vsKkJk?(m+B%k zQ^{U=L!lKE4!1H=oRGFiorglwE@LC9_}$1^K(`Tji$FyV$YIv?zY+UNzADGz;mfUy zW!T`7V{^s{894)_!btAh#eH>GTQo(xbIdLiUEdD?p2%q-xsHD7NDN3?VTqylgraN>$B^Br`nas0yUG0+G=ki0tGdtman{;upZkf_kyg@fN!@XnH5wr--)qX zAUFLu(9`(V_28jB8fJW zT)FEGU#bTiWDr(-<=a;`4Kp4i7^O=oQ>HCeZQl{9od`0I>XLpnwjM?G-*Wtxk!p#r z7L7_Y;YI;7C%|5h4YY%B*)}6=Hnb6Gd5emr^@(8J>$sD~us8Hei$Hp( z8zy+?*57wTl?1A{R=E$VGz56@H+GB_3{%_9mojKC%HAyAYJR^$#+~N~JSawmM{2|! z?~3jhN>K=h>$OSqpWD3!mofMrTGDcGKcEtnU67H$v0Wi*r!Q5Ob=&S{c$I+taA(9Y zV;MA=vRwPF{VPc=zoWSAn54{>P62oPG|ZmQ7AA1x-T+dFHUN{dWc%7*L{8rl?#GC* zua8Seb$Fno-AwL=Rdw#`lLlC+b&VTawbQuBiegM%8p*cwo7=U>SvsV&gPStpW{ z*S{9mLP0Y@leKs=U}vM^LikZqP9zA-%Rs$5>44N;?ZL<#h6M7*=k^4DP;37R&45!mI7X_E&F55)JQkGM>C*e+_) zMen0dPE)uTBWUS-t$Uk)zkArdFJwHKHca{XUdHmO#*Y%=3rCoXoq?j66T2CLC0p{W z0nvj7vxQ56&G>vL(vE+7-yg_d zrl<(2AU)o{I8lxykXT@L+lmYtWNbbCfHW)r1h8$+Z0?R&FhUfsun*!lU!Sj;H`d~_* z1yz6)A+h3wInjXeTVEL^H_cT%9yb4Q@HqDNvGUq(CF3@`o-&F{^eoM%azE_&!dOo_3v(NaoCyeCjI!XSG()>%gxo7v*_eQcifKejXkyCsA<(fDoIYy1{ryc9+2S`A z@qI4sgfCt4;RhQg2lKgMu`6F)G?T%Yx#-oEv0+@FBIT_gDpJY;QDN#g1c2#;*hV9Ra7>yALR+ew2n{f*9918ncAg~IKq&S?awkJLWGFcmpJ11`tUd}0N@-G^jdOm2I-ia{8~_q^O}T`?$(A3(!Qa!yCh-FtcDcm zHqhPC+T5sA$VpPJP&PKVc61M&rtk`rQhKJE^-whrz-yqJXK zBa-qeMNxu?)gXrULv701svFnKQ_JkjuivPuRkjU@5mA=tAyE-CD&!H-kSHcIoVy}6 z#1zqx*cIGiqUW-hXw%&aHru;!z0by@Sd!Zwo&Ic>5q4t=H}X;N*?2l9l4eD>H*~4 zk$)dh*H`B5c!TkfJKx=vT~zw$&{etH7XVga=je=)cxNH&-bl>U-D9#LtT$C_B(0u* zQ^)j3is7C1Cg1IABivz_3t`XKZpdw$3o>V~k68=ZCp{Z7%<7 zw-VzTqhlqHzb<40Prl7}U z$p8!idojX`qzBcM$2#iD5K~th!|OUKg`qD)pbQ($I)o{c8DbiQvPmeZ=K*{KsDF>c zixe+Y9qb__0ibLXxKP)2g1TywsjCqfrV@q&LEUKd*JSG6L`i)*LFHOdQqO~)AE4*$ zsWp(efr8!49EdO+1a)ARyC0Xw3k&q|bak||v9WV>_4El0tz{;O4y+_+3t-AQsUZ-rh->U9U zgVQb~ycq>N;ukMFSoH;Ttva}DaXd0z#}L7$xBQnT9V_oW2$%GhA4^*5|JEi!h$CS0 zR~{)VyL3ExCC5|n+bw%e6qeRDsr!e9`qfRfrG+QFq$opZIa7HVVp|7d-X2qd0 zdd1D!roI$NYn>s?N{7tu=DOPd{7_j@{xK?EQTfAvYU`T2(~*cm_Tq#KCn-@Dvw>3- z=aDF!C?~Y6<8YS$W|SzuS*lDfeSIR z;NZdm0+RQ&s>0x+pmg{sT-4^XC(wWm;S##O`!Qqingh(g|3z+NlJ&2;u4H1Zh z5rK1@7yLYW^~UYHKRcZ#E3LZQ(4y`gL>t1|!CrMs!`-SEZ-c5mOfI{N1eoaY2a z2t|UBx%5Kd;)ovbSR6cifoRQ#pPs#TulE#m>AiRD?57{D5iOVr-w?yt~&NYmfj-KlPW(5h-~YHX-iD(cW?Pb%q-Hhbz6%KC=Jre;;^gLZXi zcW=LD=&#VR?&8tEtO%XOC87cyPXhNDp`u8yi1qsl6==7uzenBHa=%e2KZ_brHr{V( zQ}^^E-=!$rw?4uvQWQGlC~)x=3cO$bFuPXU-`(EQq?DJCE^=j4OM7>}wl@32m%Rl- z-^0Msj|dM+{Ia@N-P)umCmj_{t?J(DFB5~p3BLot;b)8a!Aa+u+wLo>Ne9LKw&rt5 z!TiNP+XL+96M<__)TxyBNPDHK?!?+aV*XCRm`(V8@U2QwPcjs$Z$I!QW~T!>pYy@h zCKX9L6S#h|Gpm&NLN-*^#UU2zya2`^H`f8(7r&v`rss)kf7PhO`D&WOfR))pjDf zwoRQ{v`dv8DOjBfY1%G|JDNh(rA>wO)dEEBV@MlNQ-aWxD)qp}&>j&69>P?0I;3lQ zbfVLd=slWrNK>Z@J;Z?KDvB%K3GFlwwPvT&nr0`Y6~~EOQvr?7*;=_9+K*`7epvIn zA+2&NhmX{PRJHY526Qm&Oox%q%z*T3Taf~H0=xM{(ArZE4q0qOhoIeqQ)`2W`MUtq zGnBI`nv*2yyaSn?k|a*_Do&{9PT=GoIxqfkasKCjdU;Xemo?SUspiYXMKAy9^Zeq& z@$*965ud?+@khT&mDvAd+cGv~PS>G5Wj^d>+y0R%p?`BU-Y;0!slPl}yhGyfuLJML zEYO+h73iQd#|1I(ANbb}3BCB>FRAWkP~Ck;mbXjdm~$lgcOp;y5Gfoscu&#ql8@x< zlFZ1H-5D_mlKfGYw^!nl^Z6(5E$7cMIrir8m%sPP=Q(>N&UvyQNpi%1Qb^jZD+SUF zNz}O$nQ8CGzZT|Y$=LS_doBL`w9FIdG9)xgp7?BE+MhSC zU-|kk_#8iP4>zabS;)!F!`qL;|HbPo*KhuF+P=?DoINbDEs#~F8JTiANxN~mP+E;> z6kfiOKFY9nko20;k^<><30+!HQd+ZPjG_OHw7XsLUGaJ86^WhneDQY`xBq6s^mmht z+m+W!3iG9f5{5Ltu;g0h?cFAa!#xmsRzci*_fB$IT$ zU3LB6S1*+me^YQiKTj&%C2^KY^YYIZd{bO<>FU3)SKZDe@le7;2@fR`LkZ1`k35d$ zLy4vHO0na3CFE$Qz$*nlg;zpwVGm&F;05KA7|174z~TU4=m80GMGWMMC>U}W*bhUQ zhrWk`E=PgG2qYTzH9F{X(inU_@+^8Nl`|m#SNOCz@q5c~sim-YxO^K1&KNjj;7nrR z9EyQ62F|^B4T{&G&)XUl17{4JEr!7uIO82>yyJWp1LqYOIO82>H3rW3@aDNYyurX3 z1Lr3I&RcYkuZr;FtIzxMJ6L|K0jvS60jvS60jvS60jvS60jvS6fuEcPJc+lrXJua~ zt(G^pb@dHuhaSBtH8i9h?CWZ4mRFZv$j;jSHsLvm%rlAi4i(&}?;JG$Vvlj|U}yb} zf~#s*^D{R$29FVMf+Ew=kYBJGuI!hXn88ihTLdcDvqt6IZ+na zTMHBehSewMen3&M6@8}WF(K~MohhI_EWyB?Q*mY(Se4uKm~R;kH}vGc+NRu9CRtec zclo4sxOw(8^1m+}&BCh_e`(Ns;}gs6%s2X4QAEC(FJw)uMN3QdL4!n&Fjy|?~dj~bNx-OE}S;{ zj`iqbQx)$xO%X>5;BwbpnZWliCYO)CE9-RR=TTQKcjFcG2I{j5y;nBs>COZGx|>bU zn*JsoS$_bg1z1o20n-owuz$%~_VCa7C0J%2Ka3mnB7z#70Bz#70Bz#70Bz#70Bz#70B Mz#70BcoGf#56bG4>;M1& literal 0 HcmV?d00001 diff --git a/sqlitebrowser/sqlitebrowser/sqlite_source/attach.c b/sqlitebrowser/sqlitebrowser/sqlite_source/attach.c new file mode 100755 index 00000000..fac13835 --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/sqlite_source/attach.c @@ -0,0 +1,278 @@ +/* +** 2003 April 6 +** +** 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 code used to implement the ATTACH and DETACH commands. +** +** $Id: attach.c,v 1.1.1.1 2003-08-21 02:24:02 tabuleiro Exp $ +*/ +#include "sqliteInt.h" + +/* +** This routine is called by the parser to process an ATTACH statement: +** +** ATTACH DATABASE filename AS dbname +** +** The pFilename and pDbname arguments are the tokens that define the +** filename and dbname in the ATTACH statement. +*/ +void sqliteAttach(Parse *pParse, Token *pFilename, Token *pDbname){ + Db *aNew; + int rc, i; + char *zFile, *zName; + sqlite *db; + + if( pParse->explain ) return; + db = pParse->db; + if( db->file_format<4 ){ + sqliteErrorMsg(pParse, "cannot attach auxiliary databases to an " + "older format master database", 0); + pParse->rc = SQLITE_ERROR; + return; + } + if( db->nDb>=MAX_ATTACHED+2 ){ + sqliteErrorMsg(pParse, "too many attached databases - max %d", + MAX_ATTACHED); + pParse->rc = SQLITE_ERROR; + return; + } + + zFile = 0; + sqliteSetNString(&zFile, pFilename->z, pFilename->n, 0); + if( zFile==0 ) return; + sqliteDequote(zFile); +#ifndef SQLITE_OMIT_AUTHORIZATION + if( sqliteAuthCheck(pParse, SQLITE_ATTACH, zFile, 0, 0)!=SQLITE_OK ){ + sqliteFree(zFile); + return; + } +#endif /* SQLITE_OMIT_AUTHORIZATION */ + + zName = 0; + sqliteSetNString(&zName, pDbname->z, pDbname->n, 0); + if( zName==0 ) return; + sqliteDequote(zName); + for(i=0; inDb; i++){ + if( db->aDb[i].zName && sqliteStrICmp(db->aDb[i].zName, zName)==0 ){ + sqliteErrorMsg(pParse, "database %z is already in use", zName); + pParse->rc = SQLITE_ERROR; + sqliteFree(zFile); + return; + } + } + + if( db->aDb==db->aDbStatic ){ + aNew = sqliteMalloc( sizeof(db->aDb[0])*3 ); + if( aNew==0 ) 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 ) return; + } + db->aDb = aNew; + aNew = &db->aDb[db->nDb++]; + memset(aNew, 0, sizeof(*aNew)); + sqliteHashInit(&aNew->tblHash, SQLITE_HASH_STRING, 0); + sqliteHashInit(&aNew->idxHash, SQLITE_HASH_STRING, 0); + sqliteHashInit(&aNew->trigHash, SQLITE_HASH_STRING, 0); + sqliteHashInit(&aNew->aFKey, SQLITE_HASH_STRING, 1); + aNew->zName = zName; + rc = sqliteBtreeFactory(db, zFile, 0, MAX_PAGES, &aNew->pBt); + if( rc ){ + sqliteErrorMsg(pParse, "unable to open database: %s", zFile); + } + sqliteFree(zFile); + db->flags &= ~SQLITE_Initialized; + if( pParse->nErr ) return; + rc = sqliteInit(pParse->db, &pParse->zErrMsg); + if( rc ){ + sqliteResetInternalSchema(db, 0); + pParse->nErr++; + pParse->rc = SQLITE_ERROR; + } +} + +/* +** This routine is called by the parser to process a DETACH statement: +** +** DETACH DATABASE dbname +** +** The pDbname argument is the name of the database in the DETACH statement. +*/ +void sqliteDetach(Parse *pParse, Token *pDbname){ + int i; + sqlite *db; + + if( pParse->explain ) return; + db = pParse->db; + for(i=0; inDb; i++){ + if( db->aDb[i].pBt==0 || db->aDb[i].zName==0 ) continue; + if( strlen(db->aDb[i].zName)!=pDbname->n ) continue; + if( sqliteStrNICmp(db->aDb[i].zName, pDbname->z, pDbname->n)==0 ) break; + } + if( i>=db->nDb ){ + sqliteErrorMsg(pParse, "no such database: %T", pDbname); + return; + } + if( i<2 ){ + sqliteErrorMsg(pParse, "cannot detach database %T", pDbname); + return; + } +#ifndef SQLITE_OMIT_AUTHORIZATION + if( sqliteAuthCheck(pParse,SQLITE_DETACH,db->aDb[i].zName,0,0)!=SQLITE_OK ){ + return; + } +#endif /* SQLITE_OMIT_AUTHORIZATION */ + sqliteBtreeClose(db->aDb[i].pBt); + db->aDb[i].pBt = 0; + sqliteFree(db->aDb[i].zName); + sqliteResetInternalSchema(db, i); + db->nDb--; + if( inDb ){ + db->aDb[i] = db->aDb[db->nDb]; + memset(&db->aDb[db->nDb], 0, sizeof(db->aDb[0])); + sqliteResetInternalSchema(db, i); + } +} + +/* +** Initialize a DbFixer structure. This routine must be called prior +** to passing the structure to one of the sqliteFixAAAA() routines below. +** +** The return value indicates whether or not fixation is required. TRUE +** means we do need to fix the database references, FALSE means we do not. +*/ +int sqliteFixInit( + DbFixer *pFix, /* The fixer to be initialized */ + Parse *pParse, /* Error messages will be written here */ + int iDb, /* This is the database that must must be used */ + const char *zType, /* "view", "trigger", or "index" */ + const Token *pName /* Name of the view, trigger, or index */ +){ + sqlite *db; + + if( iDb<0 || iDb==1 ) return 0; + db = pParse->db; + assert( db->nDb>iDb ); + pFix->pParse = pParse; + pFix->zDb = db->aDb[iDb].zName; + pFix->zType = zType; + pFix->pName = pName; + return 1; +} + +/* +** The following set of routines walk through the parse tree and assign +** a specific database to all table references where the database name +** was left unspecified in the original SQL statement. The pFix structure +** must have been initialized by a prior call to sqliteFixInit(). +** +** These routines are used to make sure that an index, trigger, or +** view in one database does not refer to objects in a different database. +** (Exception: indices, triggers, and views in the TEMP database are +** allowed to refer to anything.) If a reference is explicitly made +** to an object in a different database, an error message is added to +** pParse->zErrMsg and these routines return non-zero. If everything +** checks out, these routines return 0. +*/ +int sqliteFixSrcList( + DbFixer *pFix, /* Context of the fixation */ + SrcList *pList /* The Source list to check and modify */ +){ + int i; + const char *zDb; + + if( pList==0 ) return 0; + zDb = pFix->zDb; + for(i=0; inSrc; i++){ + if( pList->a[i].zDatabase==0 ){ + pList->a[i].zDatabase = sqliteStrDup(zDb); + }else if( sqliteStrICmp(pList->a[i].zDatabase,zDb)!=0 ){ + sqliteErrorMsg(pFix->pParse, + "%s %z cannot reference objects in database %s", + pFix->zType, sqliteStrNDup(pFix->pName->z, pFix->pName->n), + pList->a[i].zDatabase); + return 1; + } + if( sqliteFixSelect(pFix, pList->a[i].pSelect) ) return 1; + if( sqliteFixExpr(pFix, pList->a[i].pOn) ) return 1; + } + return 0; +} +int sqliteFixSelect( + DbFixer *pFix, /* Context of the fixation */ + Select *pSelect /* The SELECT statement to be fixed to one database */ +){ + while( pSelect ){ + if( sqliteFixExprList(pFix, pSelect->pEList) ){ + return 1; + } + if( sqliteFixSrcList(pFix, pSelect->pSrc) ){ + return 1; + } + if( sqliteFixExpr(pFix, pSelect->pWhere) ){ + return 1; + } + if( sqliteFixExpr(pFix, pSelect->pHaving) ){ + return 1; + } + pSelect = pSelect->pPrior; + } + return 0; +} +int sqliteFixExpr( + DbFixer *pFix, /* Context of the fixation */ + Expr *pExpr /* The expression to be fixed to one database */ +){ + while( pExpr ){ + if( sqliteFixSelect(pFix, pExpr->pSelect) ){ + return 1; + } + if( sqliteFixExprList(pFix, pExpr->pList) ){ + return 1; + } + if( sqliteFixExpr(pFix, pExpr->pRight) ){ + return 1; + } + pExpr = pExpr->pLeft; + } + return 0; +} +int sqliteFixExprList( + DbFixer *pFix, /* Context of the fixation */ + ExprList *pList /* The expression to be fixed to one database */ +){ + int i; + if( pList==0 ) return 0; + for(i=0; inExpr; i++){ + if( sqliteFixExpr(pFix, pList->a[i].pExpr) ){ + return 1; + } + } + return 0; +} +int sqliteFixTriggerStep( + DbFixer *pFix, /* Context of the fixation */ + TriggerStep *pStep /* The trigger step be fixed to one database */ +){ + while( pStep ){ + if( sqliteFixSelect(pFix, pStep->pSelect) ){ + return 1; + } + if( sqliteFixExpr(pFix, pStep->pWhere) ){ + return 1; + } + if( sqliteFixExprList(pFix, pStep->pExprList) ){ + return 1; + } + pStep = pStep->pNext; + } + return 0; +} diff --git a/sqlitebrowser/sqlitebrowser/sqlite_source/auth.c b/sqlitebrowser/sqlitebrowser/sqlite_source/auth.c new file mode 100755 index 00000000..da1a3b8c --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/sqlite_source/auth.c @@ -0,0 +1,225 @@ +/* +** 2003 January 11 +** +** 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 code used to implement the sqlite_set_authorizer() +** API. This facility is an optional feature of the library. Embedded +** systems that do not need this facility may omit it by recompiling +** the library with -DSQLITE_OMIT_AUTHORIZATION=1 +** +** $Id: auth.c,v 1.1.1.1 2003-08-21 02:24:03 tabuleiro Exp $ +*/ +#include "sqliteInt.h" + +/* +** All of the code in this file may be omitted by defining a single +** macro. +*/ +#ifndef SQLITE_OMIT_AUTHORIZATION + +/* +** Set or clear the access authorization function. +** +** The access authorization function is be called during the compilation +** phase to verify that the user has read and/or write access permission on +** various fields of the database. The first argument to the auth function +** is a copy of the 3rd argument to this routine. The second argument +** to the auth function is one of these constants: +** +** SQLITE_COPY +** SQLITE_CREATE_INDEX +** SQLITE_CREATE_TABLE +** SQLITE_CREATE_TEMP_INDEX +** SQLITE_CREATE_TEMP_TABLE +** SQLITE_CREATE_TEMP_TRIGGER +** SQLITE_CREATE_TEMP_VIEW +** SQLITE_CREATE_TRIGGER +** SQLITE_CREATE_VIEW +** SQLITE_DELETE +** SQLITE_DROP_INDEX +** SQLITE_DROP_TABLE +** SQLITE_DROP_TEMP_INDEX +** SQLITE_DROP_TEMP_TABLE +** SQLITE_DROP_TEMP_TRIGGER +** SQLITE_DROP_TEMP_VIEW +** SQLITE_DROP_TRIGGER +** SQLITE_DROP_VIEW +** SQLITE_INSERT +** SQLITE_PRAGMA +** SQLITE_READ +** SQLITE_SELECT +** SQLITE_TRANSACTION +** SQLITE_UPDATE +** +** The third and fourth arguments to the auth function are the name of +** the table and the column that are being accessed. The auth function +** should return either SQLITE_OK, SQLITE_DENY, or SQLITE_IGNORE. If +** SQLITE_OK is returned, it means that access is allowed. SQLITE_DENY +** means that the SQL statement will never-run - the sqlite_exec() call +** will return with an error. SQLITE_IGNORE means that the SQL statement +** should run but attempts to read the specified column will return NULL +** and attempts to write the column will be ignored. +** +** Setting the auth function to NULL disables this hook. The default +** setting of the auth function is NULL. +*/ +int sqlite_set_authorizer( + sqlite *db, + int (*xAuth)(void*,int,const char*,const char*,const char*,const char*), + void *pArg +){ + db->xAuth = xAuth; + db->pAuthArg = pArg; + return SQLITE_OK; +} + +/* +** Write an error message into pParse->zErrMsg that explains that the +** user-supplied authorization function returned an illegal value. +*/ +static void sqliteAuthBadReturnCode(Parse *pParse, int rc){ + char zBuf[20]; + sprintf(zBuf, "(%d)", rc); + sqliteSetString(&pParse->zErrMsg, "illegal return value ", zBuf, + " from the authorization function - should be SQLITE_OK, " + "SQLITE_IGNORE, or SQLITE_DENY", 0); + pParse->nErr++; + pParse->rc = SQLITE_MISUSE; +} + +/* +** The pExpr should be a TK_COLUMN expression. The table referred to +** is in pTabList or else it is the NEW or OLD table of a trigger. +** Check to see if it is OK to read this particular column. +** +** If the auth function returns SQLITE_IGNORE, change the TK_COLUMN +** instruction into a TK_NULL. If the auth function returns SQLITE_DENY, +** then generate an error. +*/ +void sqliteAuthRead( + Parse *pParse, /* The parser context */ + Expr *pExpr, /* The expression to check authorization on */ + SrcList *pTabList /* All table that pExpr might refer to */ +){ + sqlite *db = pParse->db; + int rc; + Table *pTab; /* The table being read */ + const char *zCol; /* Name of the column of the table */ + int iSrc; /* Index in pTabList->a[] of table being read */ + const char *zDBase; /* Name of database being accessed */ + + if( db->xAuth==0 ) return; + assert( pExpr->op==TK_COLUMN ); + for(iSrc=0; iSrcnSrc; iSrc++){ + if( pExpr->iTable==pTabList->a[iSrc].iCursor ) break; + } + if( iSrc>=0 && iSrcnSrc ){ + pTab = pTabList->a[iSrc].pTab; + }else{ + /* This must be an attempt to read the NEW or OLD pseudo-tables + ** of a trigger. + */ + TriggerStack *pStack; /* The stack of current triggers */ + pStack = pParse->trigStack; + assert( pStack!=0 ); + assert( pExpr->iTable==pStack->newIdx || pExpr->iTable==pStack->oldIdx ); + pTab = pStack->pTab; + } + if( pTab==0 ) return; + if( pExpr->iColumn>=0 ){ + assert( pExpr->iColumnnCol ); + zCol = pTab->aCol[pExpr->iColumn].zName; + }else if( pTab->iPKey>=0 ){ + assert( pTab->iPKeynCol ); + zCol = pTab->aCol[pTab->iPKey].zName; + }else{ + zCol = "ROWID"; + } + assert( pExpr->iDbnDb ); + zDBase = db->aDb[pExpr->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 ){ + sqliteSetString(&pParse->zErrMsg,"access to ", zDBase, ".", + pTab->zName, ".", zCol, " is prohibited", 0); + }else{ + sqliteSetString(&pParse->zErrMsg,"access to ", pTab->zName, ".", + zCol, " is prohibited", 0); + } + pParse->nErr++; + pParse->rc = SQLITE_AUTH; + }else if( rc!=SQLITE_OK ){ + sqliteAuthBadReturnCode(pParse, rc); + } +} + +/* +** Do an authorization check using the code and arguments given. Return +** either SQLITE_OK (zero) or SQLITE_IGNORE or SQLITE_DENY. If SQLITE_DENY +** is returned, then the error count and error message in pParse are +** modified appropriately. +*/ +int sqliteAuthCheck( + Parse *pParse, + int code, + const char *zArg1, + const char *zArg2, + const char *zArg3 +){ + sqlite *db = pParse->db; + int rc; + + if( db->xAuth==0 ){ + return SQLITE_OK; + } + rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext); + if( rc==SQLITE_DENY ){ + sqliteSetString(&pParse->zErrMsg, "not authorized", 0); + pParse->rc = SQLITE_AUTH; + pParse->nErr++; + }else if( rc!=SQLITE_OK && rc!=SQLITE_IGNORE ){ + rc = SQLITE_DENY; + sqliteAuthBadReturnCode(pParse, rc); + } + return rc; +} + +/* +** Push an authorization context. After this routine is called, the +** zArg3 argument to authorization callbacks will be zContext until +** popped. Or if pParse==0, this routine is a no-op. +*/ +void sqliteAuthContextPush( + Parse *pParse, + AuthContext *pContext, + const char *zContext +){ + pContext->pParse = pParse; + if( pParse ){ + pContext->zAuthContext = pParse->zAuthContext; + pParse->zAuthContext = zContext; + } +} + +/* +** Pop an authorization context that was previously pushed +** by sqliteAuthContextPush +*/ +void sqliteAuthContextPop(AuthContext *pContext){ + if( pContext->pParse ){ + pContext->pParse->zAuthContext = pContext->zAuthContext; + pContext->pParse = 0; + } +} + +#endif /* SQLITE_OMIT_AUTHORIZATION */ diff --git a/sqlitebrowser/sqlitebrowser/sqlite_source/btree.c b/sqlitebrowser/sqlitebrowser/sqlite_source/btree.c new file mode 100755 index 00000000..20f5e214 --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/sqlite_source/btree.c @@ -0,0 +1,3585 @@ +/* +** 2001 September 15 +** +** 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. +** +************************************************************************* +** $Id: btree.c,v 1.1.1.1 2003-08-21 02:24:05 tabuleiro Exp $ +** +** This file implements a external (disk-based) database using BTrees. +** For a detailed discussion of BTrees, refer to +** +** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3: +** "Sorting And Searching", pages 473-480. Addison-Wesley +** Publishing Company, Reading, Massachusetts. +** +** The basic idea is that each page of the file contains N database +** entries and N+1 pointers to subpages. +** +** ---------------------------------------------------------------- +** | Ptr(0) | Key(0) | Ptr(1) | Key(1) | ... | Key(N) | Ptr(N+1) | +** ---------------------------------------------------------------- +** +** All of the keys on the page that Ptr(0) points to have values less +** than Key(0). All of the keys on page Ptr(1) and its subpages have +** values greater than Key(0) and less than Key(1). All of the keys +** on Ptr(N+1) and its subpages have values greater than Key(N). And +** so forth. +** +** Finding a particular key requires reading O(log(M)) pages from the +** disk where M is the number of entries in the tree. +** +** In this implementation, a single file can hold one or more separate +** BTrees. Each BTree is identified by the index of its root page. The +** key and data for any entry are combined to form the "payload". Up to +** MX_LOCAL_PAYLOAD bytes of payload can be carried directly on the +** database page. If the payload is larger than MX_LOCAL_PAYLOAD bytes +** then surplus bytes are stored on overflow pages. The payload for an +** entry and the preceding pointer are combined to form a "Cell". Each +** page has a small header which contains the Ptr(N+1) pointer. +** +** The first page of the file contains a magic string used to verify that +** the file really is a valid BTree database, a pointer to a list of unused +** pages in the file, and some meta information. The root of the first +** BTree begins on page 2 of the file. (Pages are numbered beginning with +** 1, not 0.) Thus a minimum database contains 2 pages. +*/ +#include "sqliteInt.h" +#include "pager.h" +#include "btree.h" +#include + +/* Forward declarations */ +static BtOps sqliteBtreeOps; +static BtCursorOps sqliteBtreeCursorOps; + +/* +** Macros used for byteswapping. B is a pointer to the Btree +** structure. This is needed to access the Btree.needSwab boolean +** in order to tell if byte swapping is needed or not. +** X is an unsigned integer. SWAB16 byte swaps a 16-bit integer. +** SWAB32 byteswaps a 32-bit integer. +*/ +#define SWAB16(B,X) ((B)->needSwab? swab16((u16)X) : ((u16)X)) +#define SWAB32(B,X) ((B)->needSwab? swab32(X) : (X)) +#define SWAB_ADD(B,X,A) \ + if((B)->needSwab){ X=swab32(swab32(X)+A); }else{ X += (A); } + +/* +** The following global variable - available only if SQLITE_TEST is +** defined - is used to determine whether new databases are created in +** native byte order or in non-native byte order. Non-native byte order +** databases are created for testing purposes only. Under normal operation, +** only native byte-order databases should be created, but we should be +** able to read or write existing databases regardless of the byteorder. +*/ +#ifdef SQLITE_TEST +int btree_native_byte_order = 1; +#else +# define btree_native_byte_order 1 +#endif + +/* +** Forward declarations of structures used only in this file. +*/ +typedef struct PageOne PageOne; +typedef struct MemPage MemPage; +typedef struct PageHdr PageHdr; +typedef struct Cell Cell; +typedef struct CellHdr CellHdr; +typedef struct FreeBlk FreeBlk; +typedef struct OverflowPage OverflowPage; +typedef struct FreelistInfo FreelistInfo; + +/* +** All structures on a database page are aligned to 4-byte boundries. +** This routine rounds up a number of bytes to the next multiple of 4. +** +** This might need to change for computer architectures that require +** and 8-byte alignment boundry for structures. +*/ +#define ROUNDUP(X) ((X+3) & ~3) + +/* +** This is a magic string that appears at the beginning of every +** SQLite database in order to identify the file as a real database. +*/ +static const char zMagicHeader[] = + "** This file contains an SQLite 2.1 database **"; +#define MAGIC_SIZE (sizeof(zMagicHeader)) + +/* +** This is a magic integer also used to test the integrity of the database +** file. This integer is used in addition to the string above so that +** if the file is written on a little-endian architecture and read +** on a big-endian architectures (or vice versa) we can detect the +** problem. +** +** The number used was obtained at random and has no special +** significance other than the fact that it represents a different +** integer on little-endian and big-endian machines. +*/ +#define MAGIC 0xdae37528 + +/* +** The first page of the database file contains a magic header string +** to identify the file as an SQLite database file. It also contains +** a pointer to the first free page of the file. Page 2 contains the +** root of the principle BTree. The file might contain other BTrees +** rooted on pages above 2. +** +** The first page also contains SQLITE_N_BTREE_META integers that +** can be used by higher-level routines. +** +** Remember that pages are numbered beginning with 1. (See pager.c +** for additional information.) Page 0 does not exist and a page +** number of 0 is used to mean "no such page". +*/ +struct PageOne { + char zMagic[MAGIC_SIZE]; /* String that identifies the file as a database */ + int iMagic; /* Integer to verify correct byte order */ + Pgno freeList; /* First free page in a list of all free pages */ + int nFree; /* Number of pages on the free list */ + int aMeta[SQLITE_N_BTREE_META-1]; /* User defined integers */ +}; + +/* +** Each database page has a header that is an instance of this +** structure. +** +** PageHdr.firstFree is 0 if there is no free space on this page. +** Otherwise, PageHdr.firstFree is the index in MemPage.u.aDisk[] of a +** FreeBlk structure that describes the first block of free space. +** All free space is defined by a linked list of FreeBlk structures. +** +** Data is stored in a linked list of Cell structures. PageHdr.firstCell +** is the index into MemPage.u.aDisk[] of the first cell on the page. The +** Cells are kept in sorted order. +** +** A Cell contains all information about a database entry and a pointer +** to a child page that contains other entries less than itself. In +** other words, the i-th Cell contains both Ptr(i) and Key(i). The +** right-most pointer of the page is contained in PageHdr.rightChild. +*/ +struct PageHdr { + Pgno rightChild; /* Child page that comes after all cells on this page */ + u16 firstCell; /* Index in MemPage.u.aDisk[] of the first cell */ + u16 firstFree; /* Index in MemPage.u.aDisk[] of the first free block */ +}; + +/* +** Entries on a page of the database are called "Cells". Each Cell +** has a header and data. This structure defines the header. The +** key and data (collectively the "payload") follow this header on +** the database page. +** +** A definition of the complete Cell structure is given below. The +** header for the cell must be defined first in order to do some +** of the sizing #defines that follow. +*/ +struct CellHdr { + Pgno leftChild; /* Child page that comes before this cell */ + u16 nKey; /* Number of bytes in the key */ + u16 iNext; /* Index in MemPage.u.aDisk[] of next cell in sorted order */ + u8 nKeyHi; /* Upper 8 bits of key size for keys larger than 64K bytes */ + u8 nDataHi; /* Upper 8 bits of data size when the size is more than 64K */ + u16 nData; /* Number of bytes of data */ +}; + +/* +** The key and data size are split into a lower 16-bit segment and an +** upper 8-bit segment in order to pack them together into a smaller +** space. The following macros reassembly a key or data size back +** into an integer. +*/ +#define NKEY(b,h) (SWAB16(b,h.nKey) + h.nKeyHi*65536) +#define NDATA(b,h) (SWAB16(b,h.nData) + h.nDataHi*65536) + +/* +** The minimum size of a complete Cell. The Cell must contain a header +** and at least 4 bytes of payload. +*/ +#define MIN_CELL_SIZE (sizeof(CellHdr)+4) + +/* +** The maximum number of database entries that can be held in a single +** page of the database. +*/ +#define MX_CELL ((SQLITE_PAGE_SIZE-sizeof(PageHdr))/MIN_CELL_SIZE) + +/* +** The amount of usable space on a single page of the BTree. This is the +** page size minus the overhead of the page header. +*/ +#define USABLE_SPACE (SQLITE_PAGE_SIZE - sizeof(PageHdr)) + +/* +** The maximum amount of payload (in bytes) that can be stored locally for +** a database entry. If the entry contains more data than this, the +** extra goes onto overflow pages. +** +** This number is chosen so that at least 4 cells will fit on every page. +*/ +#define MX_LOCAL_PAYLOAD ((USABLE_SPACE/4-(sizeof(CellHdr)+sizeof(Pgno)))&~3) + +/* +** Data on a database page is stored as a linked list of Cell structures. +** Both the key and the data are stored in aPayload[]. The key always comes +** first. The aPayload[] field grows as necessary to hold the key and data, +** up to a maximum of MX_LOCAL_PAYLOAD bytes. If the size of the key and +** data combined exceeds MX_LOCAL_PAYLOAD bytes, then Cell.ovfl is the +** page number of the first overflow page. +** +** Though this structure is fixed in size, the Cell on the database +** page varies in size. Every cell has a CellHdr and at least 4 bytes +** of payload space. Additional payload bytes (up to the maximum of +** MX_LOCAL_PAYLOAD) and the Cell.ovfl value are allocated only as +** needed. +*/ +struct Cell { + CellHdr h; /* The cell header */ + char aPayload[MX_LOCAL_PAYLOAD]; /* Key and data */ + Pgno ovfl; /* The first overflow page */ +}; + +/* +** Free space on a page is remembered using a linked list of the FreeBlk +** structures. Space on a database page is allocated in increments of +** at least 4 bytes and is always aligned to a 4-byte boundry. The +** linked list of FreeBlks is always kept in order by address. +*/ +struct FreeBlk { + u16 iSize; /* Number of bytes in this block of free space */ + u16 iNext; /* Index in MemPage.u.aDisk[] of the next free block */ +}; + +/* +** The number of bytes of payload that will fit on a single overflow page. +*/ +#define OVERFLOW_SIZE (SQLITE_PAGE_SIZE-sizeof(Pgno)) + +/* +** When the key and data for a single entry in the BTree will not fit in +** the MX_LOCAL_PAYLOAD bytes of space available on the database page, +** then all extra bytes are written to a linked list of overflow pages. +** Each overflow page is an instance of the following structure. +** +** Unused pages in the database are also represented by instances of +** the OverflowPage structure. The PageOne.freeList field is the +** page number of the first page in a linked list of unused database +** pages. +*/ +struct OverflowPage { + Pgno iNext; + char aPayload[OVERFLOW_SIZE]; +}; + +/* +** The PageOne.freeList field points to a linked list of overflow pages +** hold information about free pages. The aPayload section of each +** overflow page contains an instance of the following structure. The +** aFree[] array holds the page number of nFree unused pages in the disk +** file. +*/ +struct FreelistInfo { + int nFree; + Pgno aFree[(OVERFLOW_SIZE-sizeof(int))/sizeof(Pgno)]; +}; + +/* +** For every page in the database file, an instance of the following structure +** is stored in memory. The u.aDisk[] array contains the raw bits read from +** the disk. The rest is auxiliary information held in memory only. The +** auxiliary info is only valid for regular database pages - it is not +** used for overflow pages and pages on the freelist. +** +** Of particular interest in the auxiliary info is the apCell[] entry. Each +** apCell[] entry is a pointer to a Cell structure in u.aDisk[]. The cells are +** put in this array so that they can be accessed in constant time, rather +** than in linear time which would be needed if we had to walk the linked +** list on every access. +** +** Note that apCell[] contains enough space to hold up to two more Cells +** than can possibly fit on one page. In the steady state, every apCell[] +** points to memory inside u.aDisk[]. But in the middle of an insert +** operation, some apCell[] entries may temporarily point to data space +** outside of u.aDisk[]. This is a transient situation that is quickly +** resolved. But while it is happening, it is possible for a database +** page to hold as many as two more cells than it might otherwise hold. +** The extra two entries in apCell[] are an allowance for this situation. +** +** The pParent field points back to the parent page. This allows us to +** walk up the BTree from any leaf to the root. Care must be taken to +** unref() the parent page pointer when this page is no longer referenced. +** The pageDestructor() routine handles that chore. +*/ +struct MemPage { + union { + char aDisk[SQLITE_PAGE_SIZE]; /* Page data stored on disk */ + PageHdr hdr; /* Overlay page header */ + } u; + u8 isInit; /* True if auxiliary data is initialized */ + u8 idxShift; /* True if apCell[] indices have changed */ + u8 isOverfull; /* Some apCell[] points outside u.aDisk[] */ + MemPage *pParent; /* The parent of this page. NULL for root */ + int idxParent; /* Index in pParent->apCell[] of this node */ + int nFree; /* Number of free bytes in u.aDisk[] */ + int nCell; /* Number of entries on this page */ + Cell *apCell[MX_CELL+2]; /* All data entires in sorted order */ +}; + +/* +** The in-memory image of a disk page has the auxiliary information appended +** to the end. EXTRA_SIZE is the number of bytes of space needed to hold +** that extra information. +*/ +#define EXTRA_SIZE (sizeof(MemPage)-SQLITE_PAGE_SIZE) + +/* +** Everything we need to know about an open database +*/ +struct Btree { + BtOps *pOps; /* Function table */ + Pager *pPager; /* The page cache */ + BtCursor *pCursor; /* A list of all open cursors */ + PageOne *page1; /* First page of the database */ + u8 inTrans; /* True if a transaction is in progress */ + u8 inCkpt; /* True if there is a checkpoint on the transaction */ + u8 readOnly; /* True if the underlying file is readonly */ + u8 needSwab; /* Need to byte-swapping */ +}; +typedef Btree Bt; + +/* +** A cursor is a pointer to a particular entry in the BTree. +** The entry is identified by its MemPage and the index in +** MemPage.apCell[] of the entry. +*/ +struct BtCursor { + BtCursorOps *pOps; /* Function table */ + Btree *pBt; /* The Btree to which this cursor belongs */ + BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */ + BtCursor *pShared; /* Loop of cursors with the same root page */ + Pgno pgnoRoot; /* The root page of this tree */ + MemPage *pPage; /* Page that contains the entry */ + int idx; /* Index of the entry in pPage->apCell[] */ + u8 wrFlag; /* True if writable */ + u8 eSkip; /* Determines if next step operation is a no-op */ + u8 iMatch; /* compare result from last sqliteBtreeMoveto() */ +}; + +/* +** Legal values for BtCursor.eSkip. +*/ +#define SKIP_NONE 0 /* Always step the cursor */ +#define SKIP_NEXT 1 /* The next sqliteBtreeNext() is a no-op */ +#define SKIP_PREV 2 /* The next sqliteBtreePrevious() is a no-op */ +#define SKIP_INVALID 3 /* Calls to Next() and Previous() are invalid */ + +/* Forward declarations */ +static int fileBtreeCloseCursor(BtCursor *pCur); + +/* +** Routines for byte swapping. +*/ +u16 swab16(u16 x){ + return ((x & 0xff)<<8) | ((x>>8)&0xff); +} +u32 swab32(u32 x){ + return ((x & 0xff)<<24) | ((x & 0xff00)<<8) | + ((x>>8) & 0xff00) | ((x>>24)&0xff); +} + +/* +** Compute the total number of bytes that a Cell needs on the main +** database page. The number returned includes the Cell header, +** local payload storage, and the pointer to overflow pages (if +** applicable). Additional space allocated on overflow pages +** is NOT included in the value returned from this routine. +*/ +static int cellSize(Btree *pBt, Cell *pCell){ + int n = NKEY(pBt, pCell->h) + NDATA(pBt, pCell->h); + if( n>MX_LOCAL_PAYLOAD ){ + n = MX_LOCAL_PAYLOAD + sizeof(Pgno); + }else{ + n = ROUNDUP(n); + } + n += sizeof(CellHdr); + return n; +} + +/* +** 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. +*/ +static void defragmentPage(Btree *pBt, MemPage *pPage){ + int pc, i, n; + FreeBlk *pFBlk; + char newPage[SQLITE_PAGE_SIZE]; + + assert( sqlitepager_iswriteable(pPage) ); + assert( pPage->isInit ); + pc = sizeof(PageHdr); + pPage->u.hdr.firstCell = SWAB16(pBt, pc); + memcpy(newPage, pPage->u.aDisk, pc); + for(i=0; inCell; i++){ + Cell *pCell = pPage->apCell[i]; + + /* This routine should never be called on an overfull page. The + ** following asserts verify that constraint. */ + assert( Addr(pCell) > Addr(pPage) ); + assert( Addr(pCell) < Addr(pPage) + SQLITE_PAGE_SIZE ); + + n = cellSize(pBt, pCell); + pCell->h.iNext = SWAB16(pBt, pc + n); + memcpy(&newPage[pc], pCell, n); + pPage->apCell[i] = (Cell*)&pPage->u.aDisk[pc]; + pc += n; + } + assert( pPage->nFree==SQLITE_PAGE_SIZE-pc ); + memcpy(pPage->u.aDisk, newPage, pc); + if( pPage->nCell>0 ){ + pPage->apCell[pPage->nCell-1]->h.iNext = 0; + } + pFBlk = (FreeBlk*)&pPage->u.aDisk[pc]; + pFBlk->iSize = SWAB16(pBt, SQLITE_PAGE_SIZE - pc); + pFBlk->iNext = 0; + pPage->u.hdr.firstFree = SWAB16(pBt, pc); + memset(&pFBlk[1], 0, SQLITE_PAGE_SIZE - pc - sizeof(FreeBlk)); +} + +/* +** Allocate nByte bytes of space on a page. nByte must be a +** multiple of 4. +** +** Return the index into pPage->u.aDisk[] of the first byte of +** the new allocation. Or return 0 if there is not enough free +** space on the page to satisfy the allocation request. +** +** If the page contains nBytes of free space but does not contain +** nBytes of contiguous free space, then this routine automatically +** calls defragementPage() to consolidate all free space before +** allocating the new chunk. +*/ +static int allocateSpace(Btree *pBt, MemPage *pPage, int nByte){ + FreeBlk *p; + u16 *pIdx; + int start; + int iSize; +#ifndef NDEBUG + int cnt = 0; +#endif + + assert( sqlitepager_iswriteable(pPage) ); + assert( nByte==ROUNDUP(nByte) ); + assert( pPage->isInit ); + if( pPage->nFreeisOverfull ) return 0; + pIdx = &pPage->u.hdr.firstFree; + p = (FreeBlk*)&pPage->u.aDisk[SWAB16(pBt, *pIdx)]; + while( (iSize = SWAB16(pBt, p->iSize))iNext==0 ){ + defragmentPage(pBt, pPage); + pIdx = &pPage->u.hdr.firstFree; + }else{ + pIdx = &p->iNext; + } + p = (FreeBlk*)&pPage->u.aDisk[SWAB16(pBt, *pIdx)]; + } + if( iSize==nByte ){ + start = SWAB16(pBt, *pIdx); + *pIdx = p->iNext; + }else{ + FreeBlk *pNew; + start = SWAB16(pBt, *pIdx); + pNew = (FreeBlk*)&pPage->u.aDisk[start + nByte]; + pNew->iNext = p->iNext; + pNew->iSize = SWAB16(pBt, iSize - nByte); + *pIdx = SWAB16(pBt, start + nByte); + } + pPage->nFree -= nByte; + return start; +} + +/* +** Return a section of the MemPage.u.aDisk[] to the freelist. +** The first byte of the new free block is pPage->u.aDisk[start] +** and the size of the block is "size" bytes. Size must be +** a multiple of 4. +** +** Most of the effort here is involved in coalesing adjacent +** free blocks into a single big free block. +*/ +static void freeSpace(Btree *pBt, MemPage *pPage, int start, int size){ + int end = start + size; + u16 *pIdx, idx; + FreeBlk *pFBlk; + FreeBlk *pNew; + FreeBlk *pNext; + int iSize; + + assert( sqlitepager_iswriteable(pPage) ); + assert( size == ROUNDUP(size) ); + assert( start == ROUNDUP(start) ); + assert( pPage->isInit ); + pIdx = &pPage->u.hdr.firstFree; + idx = SWAB16(pBt, *pIdx); + while( idx!=0 && idxu.aDisk[idx]; + iSize = SWAB16(pBt, pFBlk->iSize); + if( idx + iSize == start ){ + pFBlk->iSize = SWAB16(pBt, iSize + size); + if( idx + iSize + size == SWAB16(pBt, pFBlk->iNext) ){ + pNext = (FreeBlk*)&pPage->u.aDisk[idx + iSize + size]; + if( pBt->needSwab ){ + pFBlk->iSize = swab16((u16)swab16(pNext->iSize)+iSize+size); + }else{ + pFBlk->iSize += pNext->iSize; + } + pFBlk->iNext = pNext->iNext; + } + pPage->nFree += size; + return; + } + pIdx = &pFBlk->iNext; + idx = SWAB16(pBt, *pIdx); + } + pNew = (FreeBlk*)&pPage->u.aDisk[start]; + if( idx != end ){ + pNew->iSize = SWAB16(pBt, size); + pNew->iNext = SWAB16(pBt, idx); + }else{ + pNext = (FreeBlk*)&pPage->u.aDisk[idx]; + pNew->iSize = SWAB16(pBt, size + SWAB16(pBt, pNext->iSize)); + pNew->iNext = pNext->iNext; + } + *pIdx = SWAB16(pBt, start); + pPage->nFree += size; +} + +/* +** Initialize the auxiliary information for a disk block. +** +** The pParent parameter must be a pointer to the MemPage which +** is the parent of the page being initialized. The root of the +** BTree (usually page 2) has no parent and so for that page, +** pParent==NULL. +** +** Return SQLITE_OK on success. If we see that the page does +** not contain a well-formed database page, then return +** SQLITE_CORRUPT. Note that a return of SQLITE_OK does not +** guarantee that the page is well-formed. It only shows that +** we failed to detect any corruption. +*/ +static int initPage(Bt *pBt, MemPage *pPage, Pgno pgnoThis, MemPage *pParent){ + int idx; /* An index into pPage->u.aDisk[] */ + Cell *pCell; /* A pointer to a Cell in pPage->u.aDisk[] */ + FreeBlk *pFBlk; /* A pointer to a free block in pPage->u.aDisk[] */ + int sz; /* The size of a Cell in bytes */ + int freeSpace; /* Amount of free space on the page */ + + if( pPage->pParent ){ + assert( pPage->pParent==pParent ); + return SQLITE_OK; + } + if( pParent ){ + pPage->pParent = pParent; + sqlitepager_ref(pParent); + } + if( pPage->isInit ) return SQLITE_OK; + pPage->isInit = 1; + pPage->nCell = 0; + freeSpace = USABLE_SPACE; + idx = SWAB16(pBt, pPage->u.hdr.firstCell); + while( idx!=0 ){ + if( idx>SQLITE_PAGE_SIZE-MIN_CELL_SIZE ) goto page_format_error; + if( idxu.aDisk[idx]; + sz = cellSize(pBt, pCell); + if( idx+sz > SQLITE_PAGE_SIZE ) goto page_format_error; + freeSpace -= sz; + pPage->apCell[pPage->nCell++] = pCell; + idx = SWAB16(pBt, pCell->h.iNext); + } + pPage->nFree = 0; + idx = SWAB16(pBt, pPage->u.hdr.firstFree); + while( idx!=0 ){ + int iNext; + if( idx>SQLITE_PAGE_SIZE-sizeof(FreeBlk) ) goto page_format_error; + if( idxu.aDisk[idx]; + pPage->nFree += SWAB16(pBt, pFBlk->iSize); + iNext = SWAB16(pBt, pFBlk->iNext); + if( iNext>0 && iNext <= idx ) goto page_format_error; + idx = iNext; + } + if( pPage->nCell==0 && pPage->nFree==0 ){ + /* As a special case, an uninitialized root page appears to be + ** an empty database */ + return SQLITE_OK; + } + if( pPage->nFree!=freeSpace ) goto page_format_error; + return SQLITE_OK; + +page_format_error: + return SQLITE_CORRUPT; +} + +/* +** Set up a raw page so that it looks like a database page holding +** no entries. +*/ +static void zeroPage(Btree *pBt, MemPage *pPage){ + PageHdr *pHdr; + FreeBlk *pFBlk; + assert( sqlitepager_iswriteable(pPage) ); + memset(pPage, 0, SQLITE_PAGE_SIZE); + pHdr = &pPage->u.hdr; + pHdr->firstCell = 0; + pHdr->firstFree = SWAB16(pBt, sizeof(*pHdr)); + pFBlk = (FreeBlk*)&pHdr[1]; + pFBlk->iNext = 0; + pPage->nFree = SQLITE_PAGE_SIZE - sizeof(*pHdr); + pFBlk->iSize = SWAB16(pBt, pPage->nFree); + pPage->nCell = 0; + pPage->isOverfull = 0; +} + +/* +** This routine is called when the reference count for a page +** reaches zero. We need to unref the pParent pointer when that +** happens. +*/ +static void pageDestructor(void *pData){ + MemPage *pPage = (MemPage*)pData; + if( pPage->pParent ){ + MemPage *pParent = pPage->pParent; + pPage->pParent = 0; + sqlitepager_unref(pParent); + } +} + +/* +** Open a new database. +** +** Actually, this routine just sets up the internal data structures +** for accessing the database. We do not open the database file +** until the first page is loaded. +** +** zFilename is the name of the database file. If zFilename is NULL +** a new database with a random name is created. This randomly named +** database file will be deleted when sqliteBtreeClose() is called. +*/ +int sqliteBtreeOpen( + const char *zFilename, /* Name of the file containing the BTree database */ + int omitJournal, /* if TRUE then do not journal this file */ + int nCache, /* How many pages in the page cache */ + Btree **ppBtree /* Pointer to new Btree object written here */ +){ + Btree *pBt; + int rc; + + /* + ** The following asserts make sure that structures used by the btree are + ** the right size. This is to guard against size changes that result + ** when compiling on a different architecture. + */ + assert( sizeof(u32)==4 ); + assert( sizeof(u16)==2 ); + assert( sizeof(Pgno)==4 ); + assert( sizeof(PageHdr)==8 ); + assert( sizeof(CellHdr)==12 ); + assert( sizeof(FreeBlk)==4 ); + assert( sizeof(OverflowPage)==SQLITE_PAGE_SIZE ); + assert( sizeof(FreelistInfo)==OVERFLOW_SIZE ); + assert( sizeof(ptr)==sizeof(char*) ); + assert( sizeof(uptr)==sizeof(ptr) ); + + pBt = sqliteMalloc( sizeof(*pBt) ); + if( pBt==0 ){ + *ppBtree = 0; + return SQLITE_NOMEM; + } + if( nCache<10 ) nCache = 10; + rc = sqlitepager_open(&pBt->pPager, zFilename, nCache, EXTRA_SIZE, + !omitJournal); + if( rc!=SQLITE_OK ){ + if( pBt->pPager ) sqlitepager_close(pBt->pPager); + sqliteFree(pBt); + *ppBtree = 0; + return rc; + } + sqlitepager_set_destructor(pBt->pPager, pageDestructor); + pBt->pCursor = 0; + pBt->page1 = 0; + pBt->readOnly = sqlitepager_isreadonly(pBt->pPager); + pBt->pOps = &sqliteBtreeOps; + *ppBtree = pBt; + return SQLITE_OK; +} + +/* +** Close an open database and invalidate all cursors. +*/ +static int fileBtreeClose(Btree *pBt){ + while( pBt->pCursor ){ + fileBtreeCloseCursor(pBt->pCursor); + } + sqlitepager_close(pBt->pPager); + sqliteFree(pBt); + return SQLITE_OK; +} + +/* +** Change the limit on the number of pages allowed in the cache. +** +** The maximum number of cache pages is set to the absolute +** value of mxPage. If mxPage is negative, the pager will +** operate asynchronously - it will not stop to do fsync()s +** to insure data is written to the disk surface before +** continuing. Transactions still work if synchronous is off, +** and the database cannot be corrupted if this program +** crashes. But if the operating system crashes or there is +** an abrupt power failure when synchronous is off, the database +** could be left in an inconsistent and unrecoverable state. +** Synchronous is on by default so database corruption is not +** normally a worry. +*/ +static int fileBtreeSetCacheSize(Btree *pBt, int mxPage){ + sqlitepager_set_cachesize(pBt->pPager, mxPage); + return SQLITE_OK; +} + +/* +** Change the way data is synced to disk in order to increase or decrease +** how well the database resists damage due to OS crashes and power +** failures. Level 1 is the same as asynchronous (no syncs() occur and +** there is a high probability of damage) Level 2 is the default. There +** is a very low but non-zero probability of damage. Level 3 reduces the +** probability of damage to near zero but with a write performance reduction. +*/ +static int fileBtreeSetSafetyLevel(Btree *pBt, int level){ + sqlitepager_set_safety_level(pBt->pPager, level); + return SQLITE_OK; +} + +/* +** Get a reference to page1 of the database file. This will +** also acquire a readlock on that file. +** +** SQLITE_OK is returned on success. If the file is not a +** well-formed database file, then SQLITE_CORRUPT is returned. +** SQLITE_BUSY is returned if the database is locked. SQLITE_NOMEM +** is returned if we run out of memory. SQLITE_PROTOCOL is returned +** if there is a locking protocol violation. +*/ +static int lockBtree(Btree *pBt){ + int rc; + if( pBt->page1 ) return SQLITE_OK; + rc = sqlitepager_get(pBt->pPager, 1, (void**)&pBt->page1); + if( rc!=SQLITE_OK ) return rc; + + /* Do some checking to help insure the file we opened really is + ** a valid database file. + */ + if( sqlitepager_pagecount(pBt->pPager)>0 ){ + PageOne *pP1 = pBt->page1; + if( strcmp(pP1->zMagic,zMagicHeader)!=0 || + (pP1->iMagic!=MAGIC && swab32(pP1->iMagic)!=MAGIC) ){ + rc = SQLITE_CORRUPT; + goto page1_init_failed; + } + pBt->needSwab = pP1->iMagic!=MAGIC; + } + return rc; + +page1_init_failed: + sqlitepager_unref(pBt->page1); + pBt->page1 = 0; + return rc; +} + +/* +** If there are no outstanding cursors and we are not in the middle +** of a transaction but there is a read lock on the database, then +** this routine unrefs the first page of the database file which +** has the effect of releasing the read lock. +** +** If there are any outstanding cursors, this routine is a no-op. +** +** If there is a transaction in progress, this routine is a no-op. +*/ +static void unlockBtreeIfUnused(Btree *pBt){ + if( pBt->inTrans==0 && pBt->pCursor==0 && pBt->page1!=0 ){ + sqlitepager_unref(pBt->page1); + pBt->page1 = 0; + pBt->inTrans = 0; + pBt->inCkpt = 0; + } +} + +/* +** Create a new database by initializing the first two pages of the +** file. +*/ +static int newDatabase(Btree *pBt){ + MemPage *pRoot; + PageOne *pP1; + int rc; + if( sqlitepager_pagecount(pBt->pPager)>1 ) return SQLITE_OK; + pP1 = pBt->page1; + rc = sqlitepager_write(pBt->page1); + if( rc ) return rc; + rc = sqlitepager_get(pBt->pPager, 2, (void**)&pRoot); + if( rc ) return rc; + rc = sqlitepager_write(pRoot); + if( rc ){ + sqlitepager_unref(pRoot); + return rc; + } + strcpy(pP1->zMagic, zMagicHeader); + if( btree_native_byte_order ){ + pP1->iMagic = MAGIC; + pBt->needSwab = 0; + }else{ + pP1->iMagic = swab32(MAGIC); + pBt->needSwab = 1; + } + zeroPage(pBt, pRoot); + sqlitepager_unref(pRoot); + return SQLITE_OK; +} + +/* +** Attempt to start a new transaction. +** +** A transaction must be started before attempting any changes +** to the database. None of the following routines will work +** unless a transaction is started first: +** +** sqliteBtreeCreateTable() +** sqliteBtreeCreateIndex() +** sqliteBtreeClearTable() +** sqliteBtreeDropTable() +** sqliteBtreeInsert() +** sqliteBtreeDelete() +** sqliteBtreeUpdateMeta() +*/ +static int fileBtreeBeginTrans(Btree *pBt){ + int rc; + if( pBt->inTrans ) return SQLITE_ERROR; + if( pBt->readOnly ) return SQLITE_READONLY; + if( pBt->page1==0 ){ + rc = lockBtree(pBt); + if( rc!=SQLITE_OK ){ + return rc; + } + } + rc = sqlitepager_begin(pBt->page1); + if( rc==SQLITE_OK ){ + rc = newDatabase(pBt); + } + if( rc==SQLITE_OK ){ + pBt->inTrans = 1; + pBt->inCkpt = 0; + }else{ + unlockBtreeIfUnused(pBt); + } + return rc; +} + +/* +** Commit the transaction currently in progress. +** +** This will release the write lock on the database file. If there +** are no active cursors, it also releases the read lock. +*/ +static int fileBtreeCommit(Btree *pBt){ + int rc; + rc = pBt->readOnly ? SQLITE_OK : sqlitepager_commit(pBt->pPager); + pBt->inTrans = 0; + pBt->inCkpt = 0; + unlockBtreeIfUnused(pBt); + return rc; +} + +/* +** Rollback the transaction in progress. All cursors will be +** invalided by this operation. Any attempt to use a cursor +** that was open at the beginning of this operation will result +** in an error. +** +** This will release the write lock on the database file. If there +** are no active cursors, it also releases the read lock. +*/ +static int fileBtreeRollback(Btree *pBt){ + int rc; + BtCursor *pCur; + if( pBt->inTrans==0 ) return SQLITE_OK; + pBt->inTrans = 0; + pBt->inCkpt = 0; + rc = pBt->readOnly ? SQLITE_OK : sqlitepager_rollback(pBt->pPager); + for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ + if( pCur->pPage && pCur->pPage->isInit==0 ){ + sqlitepager_unref(pCur->pPage); + pCur->pPage = 0; + } + } + unlockBtreeIfUnused(pBt); + return rc; +} + +/* +** Set the checkpoint for the current transaction. The checkpoint serves +** as a sub-transaction that can be rolled back independently of the +** main transaction. You must start a transaction before starting a +** checkpoint. The checkpoint is ended automatically if the transaction +** commits or rolls back. +** +** Only one checkpoint may be active at a time. It is an error to try +** to start a new checkpoint if another checkpoint is already active. +*/ +static int fileBtreeBeginCkpt(Btree *pBt){ + int rc; + if( !pBt->inTrans || pBt->inCkpt ){ + return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; + } + rc = pBt->readOnly ? SQLITE_OK : sqlitepager_ckpt_begin(pBt->pPager); + pBt->inCkpt = 1; + return rc; +} + + +/* +** Commit a checkpoint to transaction currently in progress. If no +** checkpoint is active, this is a no-op. +*/ +static int fileBtreeCommitCkpt(Btree *pBt){ + int rc; + if( pBt->inCkpt && !pBt->readOnly ){ + rc = sqlitepager_ckpt_commit(pBt->pPager); + }else{ + rc = SQLITE_OK; + } + pBt->inCkpt = 0; + return rc; +} + +/* +** Rollback the checkpoint to the current transaction. If there +** is no active checkpoint or transaction, this routine is a no-op. +** +** All cursors will be invalided by this operation. Any attempt +** to use a cursor that was open at the beginning of this operation +** will result in an error. +*/ +static int fileBtreeRollbackCkpt(Btree *pBt){ + int rc; + BtCursor *pCur; + if( pBt->inCkpt==0 || pBt->readOnly ) return SQLITE_OK; + rc = sqlitepager_ckpt_rollback(pBt->pPager); + for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ + if( pCur->pPage && pCur->pPage->isInit==0 ){ + sqlitepager_unref(pCur->pPage); + pCur->pPage = 0; + } + } + pBt->inCkpt = 0; + return rc; +} + +/* +** Create a new cursor for the BTree whose root is on the page +** iTable. The act of acquiring a cursor gets a read lock on +** the database file. +** +** If wrFlag==0, then the cursor can only be used for reading. +** If wrFlag==1, then the cursor can be used for reading or for +** writing if other conditions for writing are also met. These +** are the conditions that must be met in order for writing to +** be allowed: +** +** 1: The cursor must have been opened with wrFlag==1 +** +** 2: No other cursors may be open with wrFlag==0 on the same table +** +** 3: The database must be writable (not on read-only media) +** +** 4: There must be an active transaction. +** +** Condition 2 warrants further discussion. If any cursor is opened +** on a table with wrFlag==0, that prevents all other cursors from +** writing to that table. This is a kind of "read-lock". When a cursor +** is opened with wrFlag==0 it is guaranteed that the table will not +** change as long as the cursor is open. This allows the cursor to +** do a sequential scan of the table without having to worry about +** entries being inserted or deleted during the scan. Cursors should +** be opened with wrFlag==0 only if this read-lock property is needed. +** That is to say, cursors should be opened with wrFlag==0 only if they +** intend to use the sqliteBtreeNext() system call. All other cursors +** should be opened with wrFlag==1 even if they never really intend +** to write. +** +** No checking is done to make sure that page iTable really is the +** root page of a b-tree. If it is not, then the cursor acquired +** will not work correctly. +*/ +static int fileBtreeCursor(Btree *pBt, int iTable, int wrFlag, BtCursor **ppCur){ + int rc; + BtCursor *pCur, *pRing; + + if( pBt->page1==0 ){ + rc = lockBtree(pBt); + if( rc!=SQLITE_OK ){ + *ppCur = 0; + return rc; + } + } + pCur = sqliteMalloc( sizeof(*pCur) ); + if( pCur==0 ){ + rc = SQLITE_NOMEM; + goto create_cursor_exception; + } + pCur->pgnoRoot = (Pgno)iTable; + rc = sqlitepager_get(pBt->pPager, pCur->pgnoRoot, (void**)&pCur->pPage); + if( rc!=SQLITE_OK ){ + goto create_cursor_exception; + } + rc = initPage(pBt, pCur->pPage, pCur->pgnoRoot, 0); + if( rc!=SQLITE_OK ){ + goto create_cursor_exception; + } + pCur->pOps = &sqliteBtreeCursorOps; + pCur->pBt = pBt; + pCur->wrFlag = wrFlag; + pCur->idx = 0; + pCur->eSkip = SKIP_INVALID; + pCur->pNext = pBt->pCursor; + if( pCur->pNext ){ + pCur->pNext->pPrev = pCur; + } + pCur->pPrev = 0; + pRing = pBt->pCursor; + while( pRing && pRing->pgnoRoot!=pCur->pgnoRoot ){ pRing = pRing->pNext; } + if( pRing ){ + pCur->pShared = pRing->pShared; + pRing->pShared = pCur; + }else{ + pCur->pShared = pCur; + } + pBt->pCursor = pCur; + *ppCur = pCur; + return SQLITE_OK; + +create_cursor_exception: + *ppCur = 0; + if( pCur ){ + if( pCur->pPage ) sqlitepager_unref(pCur->pPage); + sqliteFree(pCur); + } + unlockBtreeIfUnused(pBt); + return rc; +} + +/* +** Close a cursor. The read lock on the database file is released +** when the last cursor is closed. +*/ +static int fileBtreeCloseCursor(BtCursor *pCur){ + Btree *pBt = pCur->pBt; + if( pCur->pPrev ){ + pCur->pPrev->pNext = pCur->pNext; + }else{ + pBt->pCursor = pCur->pNext; + } + if( pCur->pNext ){ + pCur->pNext->pPrev = pCur->pPrev; + } + if( pCur->pPage ){ + sqlitepager_unref(pCur->pPage); + } + if( pCur->pShared!=pCur ){ + BtCursor *pRing = pCur->pShared; + while( pRing->pShared!=pCur ){ pRing = pRing->pShared; } + pRing->pShared = pCur->pShared; + } + unlockBtreeIfUnused(pBt); + sqliteFree(pCur); + return SQLITE_OK; +} + +/* +** Make a temporary cursor by filling in the fields of pTempCur. +** The temporary cursor is not on the cursor list for the Btree. +*/ +static void getTempCursor(BtCursor *pCur, BtCursor *pTempCur){ + memcpy(pTempCur, pCur, sizeof(*pCur)); + pTempCur->pNext = 0; + pTempCur->pPrev = 0; + if( pTempCur->pPage ){ + sqlitepager_ref(pTempCur->pPage); + } +} + +/* +** Delete a temporary cursor such as was made by the CreateTemporaryCursor() +** function above. +*/ +static void releaseTempCursor(BtCursor *pCur){ + if( pCur->pPage ){ + sqlitepager_unref(pCur->pPage); + } +} + +/* +** Set *pSize to the number of bytes of key in the entry the +** cursor currently points to. Always return SQLITE_OK. +** Failure is not possible. If the cursor is not currently +** pointing to an entry (which can happen, for example, if +** the database is empty) then *pSize is set to 0. +*/ +static int fileBtreeKeySize(BtCursor *pCur, int *pSize){ + Cell *pCell; + MemPage *pPage; + + pPage = pCur->pPage; + assert( pPage!=0 ); + if( pCur->idx >= pPage->nCell ){ + *pSize = 0; + }else{ + pCell = pPage->apCell[pCur->idx]; + *pSize = NKEY(pCur->pBt, pCell->h); + } + return SQLITE_OK; +} + +/* +** Read payload information from the entry that the pCur cursor is +** pointing to. Begin reading the payload at "offset" and read +** a total of "amt" bytes. Put the result in zBuf. +** +** This routine does not make a distinction between key and data. +** It just reads bytes from the payload area. +*/ +static int getPayload(BtCursor *pCur, int offset, int amt, char *zBuf){ + char *aPayload; + Pgno nextPage; + int rc; + Btree *pBt = pCur->pBt; + assert( pCur!=0 && pCur->pPage!=0 ); + assert( pCur->idx>=0 && pCur->idxpPage->nCell ); + aPayload = pCur->pPage->apCell[pCur->idx]->aPayload; + if( offsetMX_LOCAL_PAYLOAD ){ + a = MX_LOCAL_PAYLOAD - offset; + } + memcpy(zBuf, &aPayload[offset], a); + if( a==amt ){ + return SQLITE_OK; + } + offset = 0; + zBuf += a; + amt -= a; + }else{ + offset -= MX_LOCAL_PAYLOAD; + } + if( amt>0 ){ + nextPage = SWAB32(pBt, pCur->pPage->apCell[pCur->idx]->ovfl); + } + while( amt>0 && nextPage ){ + OverflowPage *pOvfl; + rc = sqlitepager_get(pBt->pPager, nextPage, (void**)&pOvfl); + if( rc!=0 ){ + return rc; + } + nextPage = SWAB32(pBt, pOvfl->iNext); + if( offset OVERFLOW_SIZE ){ + a = OVERFLOW_SIZE - offset; + } + memcpy(zBuf, &pOvfl->aPayload[offset], a); + offset = 0; + amt -= a; + zBuf += a; + }else{ + offset -= OVERFLOW_SIZE; + } + sqlitepager_unref(pOvfl); + } + if( amt>0 ){ + return SQLITE_CORRUPT; + } + return SQLITE_OK; +} + +/* +** Read part of the key associated with cursor pCur. A maximum +** of "amt" bytes will be transfered into zBuf[]. The transfer +** begins at "offset". The number of bytes actually read is +** returned. +** +** Change: It used to be that the amount returned will be smaller +** than the amount requested if there are not enough bytes in the key +** to satisfy the request. But now, it must be the case that there +** is enough data available to satisfy the request. If not, an exception +** is raised. The change was made in an effort to boost performance +** by eliminating unneeded tests. +*/ +static int fileBtreeKey(BtCursor *pCur, int offset, int amt, char *zBuf){ + MemPage *pPage; + + assert( amt>=0 ); + assert( offset>=0 ); + assert( pCur->pPage!=0 ); + pPage = pCur->pPage; + if( pCur->idx >= pPage->nCell ){ + return 0; + } + assert( amt+offset <= NKEY(pCur->pBt, pPage->apCell[pCur->idx]->h) ); + getPayload(pCur, offset, amt, zBuf); + return amt; +} + +/* +** Set *pSize to the number of bytes of data in the entry the +** cursor currently points to. Always return SQLITE_OK. +** Failure is not possible. If the cursor is not currently +** pointing to an entry (which can happen, for example, if +** the database is empty) then *pSize is set to 0. +*/ +static int fileBtreeDataSize(BtCursor *pCur, int *pSize){ + Cell *pCell; + MemPage *pPage; + + pPage = pCur->pPage; + assert( pPage!=0 ); + if( pCur->idx >= pPage->nCell ){ + *pSize = 0; + }else{ + pCell = pPage->apCell[pCur->idx]; + *pSize = NDATA(pCur->pBt, pCell->h); + } + return SQLITE_OK; +} + +/* +** Read part of the data associated with cursor pCur. A maximum +** of "amt" bytes will be transfered into zBuf[]. The transfer +** begins at "offset". The number of bytes actually read is +** returned. The amount returned will be smaller than the +** amount requested if there are not enough bytes in the data +** to satisfy the request. +*/ +static int fileBtreeData(BtCursor *pCur, int offset, int amt, char *zBuf){ + Cell *pCell; + MemPage *pPage; + + assert( amt>=0 ); + assert( offset>=0 ); + assert( pCur->pPage!=0 ); + pPage = pCur->pPage; + if( pCur->idx >= pPage->nCell ){ + return 0; + } + pCell = pPage->apCell[pCur->idx]; + assert( amt+offset <= NDATA(pCur->pBt, pCell->h) ); + getPayload(pCur, offset + NKEY(pCur->pBt, pCell->h), amt, zBuf); + return amt; +} + +/* +** Compare an external key against the key on the entry that pCur points to. +** +** The external key is pKey and is nKey bytes long. The last nIgnore bytes +** of the key associated with pCur are ignored, as if they do not exist. +** (The normal case is for nIgnore to be zero in which case the entire +** internal key is used in the comparison.) +** +** The comparison result is written to *pRes as follows: +** +** *pRes<0 This means pCur0 This means pCur>pKey +** +** When one key is an exact prefix of the other, the shorter key is +** considered less than the longer one. In order to be equal the +** keys must be exactly the same length. (The length of the pCur key +** is the actual key length minus nIgnore bytes.) +*/ +static int fileBtreeKeyCompare( + BtCursor *pCur, /* Pointer to entry to compare against */ + const void *pKey, /* Key to compare against entry that pCur points to */ + int nKey, /* Number of bytes in pKey */ + int nIgnore, /* Ignore this many bytes at the end of pCur */ + int *pResult /* Write the result here */ +){ + Pgno nextPage; + int n, c, rc, nLocal; + Cell *pCell; + Btree *pBt = pCur->pBt; + const char *zKey = (const char*)pKey; + + assert( pCur->pPage ); + assert( pCur->idx>=0 && pCur->idxpPage->nCell ); + pCell = pCur->pPage->apCell[pCur->idx]; + nLocal = NKEY(pBt, pCell->h) - nIgnore; + if( nLocal<0 ) nLocal = 0; + n = nKeyMX_LOCAL_PAYLOAD ){ + n = MX_LOCAL_PAYLOAD; + } + c = memcmp(pCell->aPayload, zKey, n); + if( c!=0 ){ + *pResult = c; + return SQLITE_OK; + } + zKey += n; + nKey -= n; + nLocal -= n; + nextPage = SWAB32(pBt, pCell->ovfl); + while( nKey>0 && nLocal>0 ){ + OverflowPage *pOvfl; + if( nextPage==0 ){ + return SQLITE_CORRUPT; + } + rc = sqlitepager_get(pBt->pPager, nextPage, (void**)&pOvfl); + if( rc ){ + return rc; + } + nextPage = SWAB32(pBt, pOvfl->iNext); + n = nKeyOVERFLOW_SIZE ){ + n = OVERFLOW_SIZE; + } + c = memcmp(pOvfl->aPayload, zKey, n); + sqlitepager_unref(pOvfl); + if( c!=0 ){ + *pResult = c; + return SQLITE_OK; + } + nKey -= n; + nLocal -= n; + zKey += n; + } + if( c==0 ){ + c = nLocal - nKey; + } + *pResult = c; + return SQLITE_OK; +} + +/* +** Move the cursor down to a new child page. The newPgno argument is the +** page number of the child page in the byte order of the disk image. +*/ +static int moveToChild(BtCursor *pCur, int newPgno){ + int rc; + MemPage *pNewPage; + Btree *pBt = pCur->pBt; + + newPgno = SWAB32(pBt, newPgno); + rc = sqlitepager_get(pBt->pPager, newPgno, (void**)&pNewPage); + if( rc ) return rc; + rc = initPage(pBt, pNewPage, newPgno, pCur->pPage); + if( rc ) return rc; + assert( pCur->idx>=pCur->pPage->nCell + || pCur->pPage->apCell[pCur->idx]->h.leftChild==SWAB32(pBt,newPgno) ); + assert( pCur->idxpPage->nCell + || pCur->pPage->u.hdr.rightChild==SWAB32(pBt,newPgno) ); + pNewPage->idxParent = pCur->idx; + pCur->pPage->idxShift = 0; + sqlitepager_unref(pCur->pPage); + pCur->pPage = pNewPage; + pCur->idx = 0; + if( pNewPage->nCell<1 ) return SQLITE_CORRUPT; + return SQLITE_OK; +} + +/* +** Move the cursor up to the parent page. +** +** pCur->idx is set to the cell index that contains the pointer +** to the page we are coming from. If we are coming from the +** right-most child page then pCur->idx is set to one more than +** the largest cell index. +*/ +static void moveToParent(BtCursor *pCur){ + Pgno oldPgno; + MemPage *pParent; + MemPage *pPage; + int idxParent; + pPage = pCur->pPage; + assert( pPage!=0 ); + pParent = pPage->pParent; + assert( pParent!=0 ); + idxParent = pPage->idxParent; + sqlitepager_ref(pParent); + sqlitepager_unref(pPage); + pCur->pPage = pParent; + assert( pParent->idxShift==0 ); + if( pParent->idxShift==0 ){ + pCur->idx = idxParent; +#ifndef NDEBUG + /* Verify that pCur->idx is the correct index to point back to the child + ** page we just came from + */ + oldPgno = SWAB32(pCur->pBt, sqlitepager_pagenumber(pPage)); + if( pCur->idxnCell ){ + assert( pParent->apCell[idxParent]->h.leftChild==oldPgno ); + }else{ + assert( pParent->u.hdr.rightChild==oldPgno ); + } +#endif + }else{ + /* The MemPage.idxShift flag indicates that cell indices might have + ** changed since idxParent was set and hence idxParent might be out + ** of date. So recompute the parent cell index by scanning all cells + ** and locating the one that points to the child we just came from. + */ + int i; + pCur->idx = pParent->nCell; + oldPgno = SWAB32(pCur->pBt, sqlitepager_pagenumber(pPage)); + for(i=0; inCell; i++){ + if( pParent->apCell[i]->h.leftChild==oldPgno ){ + pCur->idx = i; + break; + } + } + } +} + +/* +** Move the cursor to the root page +*/ +static int moveToRoot(BtCursor *pCur){ + MemPage *pNew; + int rc; + Btree *pBt = pCur->pBt; + + rc = sqlitepager_get(pBt->pPager, pCur->pgnoRoot, (void**)&pNew); + if( rc ) return rc; + rc = initPage(pBt, pNew, pCur->pgnoRoot, 0); + if( rc ) return rc; + sqlitepager_unref(pCur->pPage); + pCur->pPage = pNew; + pCur->idx = 0; + return SQLITE_OK; +} + +/* +** Move the cursor down to the left-most leaf entry beneath the +** entry to which it is currently pointing. +*/ +static int moveToLeftmost(BtCursor *pCur){ + Pgno pgno; + int rc; + + while( (pgno = pCur->pPage->apCell[pCur->idx]->h.leftChild)!=0 ){ + rc = moveToChild(pCur, pgno); + if( rc ) return rc; + } + return SQLITE_OK; +} + +/* +** Move the cursor down to the right-most leaf entry beneath the +** page to which it is currently pointing. Notice the difference +** between moveToLeftmost() and moveToRightmost(). moveToLeftmost() +** finds the left-most entry beneath the *entry* whereas moveToRightmost() +** finds the right-most entry beneath the *page*. +*/ +static int moveToRightmost(BtCursor *pCur){ + Pgno pgno; + int rc; + + while( (pgno = pCur->pPage->u.hdr.rightChild)!=0 ){ + pCur->idx = pCur->pPage->nCell; + rc = moveToChild(pCur, pgno); + if( rc ) return rc; + } + pCur->idx = pCur->pPage->nCell - 1; + return SQLITE_OK; +} + +/* Move the cursor to the first entry in the table. Return SQLITE_OK +** on success. Set *pRes to 0 if the cursor actually points to something +** or set *pRes to 1 if the table is empty. +*/ +static int fileBtreeFirst(BtCursor *pCur, int *pRes){ + int rc; + if( pCur->pPage==0 ) return SQLITE_ABORT; + rc = moveToRoot(pCur); + if( rc ) return rc; + if( pCur->pPage->nCell==0 ){ + *pRes = 1; + return SQLITE_OK; + } + *pRes = 0; + rc = moveToLeftmost(pCur); + pCur->eSkip = SKIP_NONE; + return rc; +} + +/* Move the cursor to the last entry in the table. Return SQLITE_OK +** on success. Set *pRes to 0 if the cursor actually points to something +** or set *pRes to 1 if the table is empty. +*/ +static int fileBtreeLast(BtCursor *pCur, int *pRes){ + int rc; + if( pCur->pPage==0 ) return SQLITE_ABORT; + rc = moveToRoot(pCur); + if( rc ) return rc; + assert( pCur->pPage->isInit ); + if( pCur->pPage->nCell==0 ){ + *pRes = 1; + return SQLITE_OK; + } + *pRes = 0; + rc = moveToRightmost(pCur); + pCur->eSkip = SKIP_NONE; + return rc; +} + +/* Move the cursor so that it points to an entry near pKey. +** Return a success code. +** +** If an exact match is not found, then the cursor is always +** left pointing at a leaf page which would hold the entry if it +** were present. The cursor might point to an entry that comes +** before or after the key. +** +** The result of comparing the key with the entry to which the +** cursor is left pointing is stored in pCur->iMatch. The same +** value is also written to *pRes if pRes!=NULL. The meaning of +** this value is as follows: +** +** *pRes<0 The cursor is left pointing at an entry that +** is smaller than pKey or if the table is empty +** and the cursor is therefore left point to nothing. +** +** *pRes==0 The cursor is left pointing at an entry that +** exactly matches pKey. +** +** *pRes>0 The cursor is left pointing at an entry that +** is larger than pKey. +*/ +static +int fileBtreeMoveto(BtCursor *pCur, const void *pKey, int nKey, int *pRes){ + int rc; + if( pCur->pPage==0 ) return SQLITE_ABORT; + pCur->eSkip = SKIP_NONE; + rc = moveToRoot(pCur); + if( rc ) return rc; + for(;;){ + int lwr, upr; + Pgno chldPg; + MemPage *pPage = pCur->pPage; + int c = -1; /* pRes return if table is empty must be -1 */ + lwr = 0; + upr = pPage->nCell-1; + while( lwr<=upr ){ + pCur->idx = (lwr+upr)/2; + rc = fileBtreeKeyCompare(pCur, pKey, nKey, 0, &c); + if( rc ) return rc; + if( c==0 ){ + pCur->iMatch = c; + if( pRes ) *pRes = 0; + return SQLITE_OK; + } + if( c<0 ){ + lwr = pCur->idx+1; + }else{ + upr = pCur->idx-1; + } + } + assert( lwr==upr+1 ); + assert( pPage->isInit ); + if( lwr>=pPage->nCell ){ + chldPg = pPage->u.hdr.rightChild; + }else{ + chldPg = pPage->apCell[lwr]->h.leftChild; + } + if( chldPg==0 ){ + pCur->iMatch = c; + if( pRes ) *pRes = c; + return SQLITE_OK; + } + pCur->idx = lwr; + rc = moveToChild(pCur, chldPg); + if( rc ) return rc; + } + /* NOT REACHED */ +} + +/* +** Advance the cursor to the next entry in the database. If +** successful then set *pRes=0. If the cursor +** was already pointing to the last entry in the database before +** this routine was called, then set *pRes=1. +*/ +static int fileBtreeNext(BtCursor *pCur, int *pRes){ + int rc; + MemPage *pPage = pCur->pPage; + assert( pRes!=0 ); + if( pPage==0 ){ + *pRes = 1; + return SQLITE_ABORT; + } + assert( pPage->isInit ); + assert( pCur->eSkip!=SKIP_INVALID ); + if( pPage->nCell==0 ){ + *pRes = 1; + return SQLITE_OK; + } + assert( pCur->idxnCell ); + if( pCur->eSkip==SKIP_NEXT ){ + pCur->eSkip = SKIP_NONE; + *pRes = 0; + return SQLITE_OK; + } + pCur->eSkip = SKIP_NONE; + pCur->idx++; + if( pCur->idx>=pPage->nCell ){ + if( pPage->u.hdr.rightChild ){ + rc = moveToChild(pCur, pPage->u.hdr.rightChild); + if( rc ) return rc; + rc = moveToLeftmost(pCur); + *pRes = 0; + return rc; + } + do{ + if( pPage->pParent==0 ){ + *pRes = 1; + return SQLITE_OK; + } + moveToParent(pCur); + pPage = pCur->pPage; + }while( pCur->idx>=pPage->nCell ); + *pRes = 0; + return SQLITE_OK; + } + *pRes = 0; + if( pPage->u.hdr.rightChild==0 ){ + return SQLITE_OK; + } + rc = moveToLeftmost(pCur); + return rc; +} + +/* +** Step the cursor to the back to the previous entry in the database. If +** successful then set *pRes=0. If the cursor +** was already pointing to the first entry in the database before +** this routine was called, then set *pRes=1. +*/ +static int fileBtreePrevious(BtCursor *pCur, int *pRes){ + int rc; + Pgno pgno; + MemPage *pPage; + pPage = pCur->pPage; + if( pPage==0 ){ + *pRes = 1; + return SQLITE_ABORT; + } + assert( pPage->isInit ); + assert( pCur->eSkip!=SKIP_INVALID ); + if( pPage->nCell==0 ){ + *pRes = 1; + return SQLITE_OK; + } + if( pCur->eSkip==SKIP_PREV ){ + pCur->eSkip = SKIP_NONE; + *pRes = 0; + return SQLITE_OK; + } + pCur->eSkip = SKIP_NONE; + assert( pCur->idx>=0 ); + if( (pgno = pPage->apCell[pCur->idx]->h.leftChild)!=0 ){ + rc = moveToChild(pCur, pgno); + if( rc ) return rc; + rc = moveToRightmost(pCur); + }else{ + while( pCur->idx==0 ){ + if( pPage->pParent==0 ){ + if( pRes ) *pRes = 1; + return SQLITE_OK; + } + moveToParent(pCur); + pPage = pCur->pPage; + } + pCur->idx--; + rc = SQLITE_OK; + } + *pRes = 0; + return rc; +} + +/* +** Allocate a new page from the database file. +** +** The new page is marked as dirty. (In other words, sqlitepager_write() +** has already been called on the new page.) The new page has also +** been referenced and the calling routine is responsible for calling +** sqlitepager_unref() on the new page when it is done. +** +** SQLITE_OK is returned on success. Any other return value indicates +** an error. *ppPage and *pPgno are undefined in the event of an error. +** Do not invoke sqlitepager_unref() on *ppPage if an error is returned. +** +** If the "nearby" parameter is not 0, then a (feeble) effort is made to +** locate a page close to the page number "nearby". This can be used in an +** attempt to keep related pages close to each other in the database file, +** which in turn can make database access faster. +*/ +static int allocatePage(Btree *pBt, MemPage **ppPage, Pgno *pPgno, Pgno nearby){ + PageOne *pPage1 = pBt->page1; + int rc; + if( pPage1->freeList ){ + OverflowPage *pOvfl; + FreelistInfo *pInfo; + + rc = sqlitepager_write(pPage1); + if( rc ) return rc; + SWAB_ADD(pBt, pPage1->nFree, -1); + rc = sqlitepager_get(pBt->pPager, SWAB32(pBt, pPage1->freeList), + (void**)&pOvfl); + if( rc ) return rc; + rc = sqlitepager_write(pOvfl); + if( rc ){ + sqlitepager_unref(pOvfl); + return rc; + } + pInfo = (FreelistInfo*)pOvfl->aPayload; + if( pInfo->nFree==0 ){ + *pPgno = SWAB32(pBt, pPage1->freeList); + pPage1->freeList = pOvfl->iNext; + *ppPage = (MemPage*)pOvfl; + }else{ + int closest, n; + n = SWAB32(pBt, pInfo->nFree); + if( n>1 && nearby>0 ){ + int i, dist; + closest = 0; + dist = SWAB32(pBt, pInfo->aFree[0]) - nearby; + if( dist<0 ) dist = -dist; + for(i=1; iaFree[i]) - nearby; + if( d2<0 ) d2 = -d2; + if( d2nFree, -1); + *pPgno = SWAB32(pBt, pInfo->aFree[closest]); + pInfo->aFree[closest] = pInfo->aFree[n-1]; + rc = sqlitepager_get(pBt->pPager, *pPgno, (void**)ppPage); + sqlitepager_unref(pOvfl); + if( rc==SQLITE_OK ){ + sqlitepager_dont_rollback(*ppPage); + rc = sqlitepager_write(*ppPage); + } + } + }else{ + *pPgno = sqlitepager_pagecount(pBt->pPager) + 1; + rc = sqlitepager_get(pBt->pPager, *pPgno, (void**)ppPage); + if( rc ) return rc; + rc = sqlitepager_write(*ppPage); + } + return rc; +} + +/* +** Add a page of the database file to the freelist. Either pgno or +** pPage but not both may be 0. +** +** sqlitepager_unref() is NOT called for pPage. +*/ +static int freePage(Btree *pBt, void *pPage, Pgno pgno){ + PageOne *pPage1 = pBt->page1; + OverflowPage *pOvfl = (OverflowPage*)pPage; + int rc; + int needUnref = 0; + MemPage *pMemPage; + + if( pgno==0 ){ + assert( pOvfl!=0 ); + pgno = sqlitepager_pagenumber(pOvfl); + } + assert( pgno>2 ); + assert( sqlitepager_pagenumber(pOvfl)==pgno ); + pMemPage = (MemPage*)pPage; + pMemPage->isInit = 0; + if( pMemPage->pParent ){ + sqlitepager_unref(pMemPage->pParent); + pMemPage->pParent = 0; + } + rc = sqlitepager_write(pPage1); + if( rc ){ + return rc; + } + SWAB_ADD(pBt, pPage1->nFree, 1); + if( pPage1->nFree!=0 && pPage1->freeList!=0 ){ + OverflowPage *pFreeIdx; + rc = sqlitepager_get(pBt->pPager, SWAB32(pBt, pPage1->freeList), + (void**)&pFreeIdx); + if( rc==SQLITE_OK ){ + FreelistInfo *pInfo = (FreelistInfo*)pFreeIdx->aPayload; + int n = SWAB32(pBt, pInfo->nFree); + if( n<(sizeof(pInfo->aFree)/sizeof(pInfo->aFree[0])) ){ + rc = sqlitepager_write(pFreeIdx); + if( rc==SQLITE_OK ){ + pInfo->aFree[n] = SWAB32(pBt, pgno); + SWAB_ADD(pBt, pInfo->nFree, 1); + sqlitepager_unref(pFreeIdx); + sqlitepager_dont_write(pBt->pPager, pgno); + return rc; + } + } + sqlitepager_unref(pFreeIdx); + } + } + if( pOvfl==0 ){ + assert( pgno>0 ); + rc = sqlitepager_get(pBt->pPager, pgno, (void**)&pOvfl); + if( rc ) return rc; + needUnref = 1; + } + rc = sqlitepager_write(pOvfl); + if( rc ){ + if( needUnref ) sqlitepager_unref(pOvfl); + return rc; + } + pOvfl->iNext = pPage1->freeList; + pPage1->freeList = SWAB32(pBt, pgno); + memset(pOvfl->aPayload, 0, OVERFLOW_SIZE); + if( needUnref ) rc = sqlitepager_unref(pOvfl); + return rc; +} + +/* +** Erase all the data out of a cell. This involves returning overflow +** pages back the freelist. +*/ +static int clearCell(Btree *pBt, Cell *pCell){ + Pager *pPager = pBt->pPager; + OverflowPage *pOvfl; + Pgno ovfl, nextOvfl; + int rc; + + if( NKEY(pBt, pCell->h) + NDATA(pBt, pCell->h) <= MX_LOCAL_PAYLOAD ){ + return SQLITE_OK; + } + ovfl = SWAB32(pBt, pCell->ovfl); + pCell->ovfl = 0; + while( ovfl ){ + rc = sqlitepager_get(pPager, ovfl, (void**)&pOvfl); + if( rc ) return rc; + nextOvfl = SWAB32(pBt, pOvfl->iNext); + rc = freePage(pBt, pOvfl, ovfl); + if( rc ) return rc; + sqlitepager_unref(pOvfl); + ovfl = nextOvfl; + } + return SQLITE_OK; +} + +/* +** Create a new cell from key and data. Overflow pages are allocated as +** necessary and linked to this cell. +*/ +static int fillInCell( + Btree *pBt, /* The whole Btree. Needed to allocate pages */ + Cell *pCell, /* Populate this Cell structure */ + const void *pKey, int nKey, /* The key */ + const void *pData,int nData /* The data */ +){ + OverflowPage *pOvfl, *pPrior; + Pgno *pNext; + int spaceLeft; + int n, rc; + int nPayload; + const char *pPayload; + char *pSpace; + Pgno nearby = 0; + + pCell->h.leftChild = 0; + pCell->h.nKey = SWAB16(pBt, nKey & 0xffff); + pCell->h.nKeyHi = nKey >> 16; + pCell->h.nData = SWAB16(pBt, nData & 0xffff); + pCell->h.nDataHi = nData >> 16; + pCell->h.iNext = 0; + + pNext = &pCell->ovfl; + pSpace = pCell->aPayload; + spaceLeft = MX_LOCAL_PAYLOAD; + pPayload = pKey; + pKey = 0; + nPayload = nKey; + pPrior = 0; + while( nPayload>0 ){ + if( spaceLeft==0 ){ + rc = allocatePage(pBt, (MemPage**)&pOvfl, pNext, nearby); + if( rc ){ + *pNext = 0; + }else{ + nearby = *pNext; + } + if( pPrior ) sqlitepager_unref(pPrior); + if( rc ){ + clearCell(pBt, pCell); + return rc; + } + if( pBt->needSwab ) *pNext = swab32(*pNext); + pPrior = pOvfl; + spaceLeft = OVERFLOW_SIZE; + pSpace = pOvfl->aPayload; + pNext = &pOvfl->iNext; + } + n = nPayload; + if( n>spaceLeft ) n = spaceLeft; + memcpy(pSpace, pPayload, n); + nPayload -= n; + if( nPayload==0 && pData ){ + pPayload = pData; + nPayload = nData; + pData = 0; + }else{ + pPayload += n; + } + spaceLeft -= n; + pSpace += n; + } + *pNext = 0; + if( pPrior ){ + sqlitepager_unref(pPrior); + } + return SQLITE_OK; +} + +/* +** Change the MemPage.pParent pointer on the page whose number is +** given in the second argument so that MemPage.pParent holds the +** pointer in the third argument. +*/ +static void reparentPage(Pager *pPager, Pgno pgno, MemPage *pNewParent,int idx){ + MemPage *pThis; + + if( pgno==0 ) return; + assert( pPager!=0 ); + pThis = sqlitepager_lookup(pPager, pgno); + if( pThis && pThis->isInit ){ + if( pThis->pParent!=pNewParent ){ + if( pThis->pParent ) sqlitepager_unref(pThis->pParent); + pThis->pParent = pNewParent; + if( pNewParent ) sqlitepager_ref(pNewParent); + } + pThis->idxParent = idx; + sqlitepager_unref(pThis); + } +} + +/* +** Reparent all children of the given page to be the given page. +** In other words, for every child of pPage, invoke reparentPage() +** to make sure that each child knows that pPage is its parent. +** +** This routine gets called after you memcpy() one page into +** another. +*/ +static void reparentChildPages(Btree *pBt, MemPage *pPage){ + int i; + Pager *pPager = pBt->pPager; + for(i=0; inCell; i++){ + reparentPage(pPager, SWAB32(pBt, pPage->apCell[i]->h.leftChild), pPage, i); + } + reparentPage(pPager, SWAB32(pBt, pPage->u.hdr.rightChild), pPage, i); + pPage->idxShift = 0; +} + +/* +** Remove the i-th cell from pPage. This routine effects pPage only. +** The cell content is not freed or deallocated. It is assumed that +** the cell content has been copied someplace else. This routine just +** removes the reference to the cell from pPage. +** +** "sz" must be the number of bytes in the cell. +** +** Do not bother maintaining the integrity of the linked list of Cells. +** Only the pPage->apCell[] array is important. The relinkCellList() +** routine will be called soon after this routine in order to rebuild +** the linked list. +*/ +static void dropCell(Btree *pBt, MemPage *pPage, int idx, int sz){ + int j; + assert( idx>=0 && idxnCell ); + assert( sz==cellSize(pBt, pPage->apCell[idx]) ); + assert( sqlitepager_iswriteable(pPage) ); + freeSpace(pBt, pPage, Addr(pPage->apCell[idx]) - Addr(pPage), sz); + for(j=idx; jnCell-1; j++){ + pPage->apCell[j] = pPage->apCell[j+1]; + } + pPage->nCell--; + pPage->idxShift = 1; +} + +/* +** Insert a new cell on pPage at cell index "i". pCell points to the +** content of the cell. +** +** If the cell content will fit on the page, then put it there. If it +** will not fit, then just make pPage->apCell[i] point to the content +** and set pPage->isOverfull. +** +** Do not bother maintaining the integrity of the linked list of Cells. +** Only the pPage->apCell[] array is important. The relinkCellList() +** routine will be called soon after this routine in order to rebuild +** the linked list. +*/ +static void insertCell(Btree *pBt, MemPage *pPage, int i, Cell *pCell, int sz){ + int idx, j; + assert( i>=0 && i<=pPage->nCell ); + assert( sz==cellSize(pBt, pCell) ); + assert( sqlitepager_iswriteable(pPage) ); + idx = allocateSpace(pBt, pPage, sz); + for(j=pPage->nCell; j>i; j--){ + pPage->apCell[j] = pPage->apCell[j-1]; + } + pPage->nCell++; + if( idx<=0 ){ + pPage->isOverfull = 1; + pPage->apCell[i] = pCell; + }else{ + memcpy(&pPage->u.aDisk[idx], pCell, sz); + pPage->apCell[i] = (Cell*)&pPage->u.aDisk[idx]; + } + pPage->idxShift = 1; +} + +/* +** Rebuild the linked list of cells on a page so that the cells +** occur in the order specified by the pPage->apCell[] array. +** Invoke this routine once to repair damage after one or more +** invocations of either insertCell() or dropCell(). +*/ +static void relinkCellList(Btree *pBt, MemPage *pPage){ + int i; + u16 *pIdx; + assert( sqlitepager_iswriteable(pPage) ); + pIdx = &pPage->u.hdr.firstCell; + for(i=0; inCell; i++){ + int idx = Addr(pPage->apCell[i]) - Addr(pPage); + assert( idx>0 && idxapCell[i]->h.iNext; + } + *pIdx = 0; +} + +/* +** Make a copy of the contents of pFrom into pTo. The pFrom->apCell[] +** pointers that point into pFrom->u.aDisk[] must be adjusted to point +** into pTo->u.aDisk[] instead. But some pFrom->apCell[] entries might +** not point to pFrom->u.aDisk[]. Those are unchanged. +*/ +static void copyPage(MemPage *pTo, MemPage *pFrom){ + uptr from, to; + int i; + memcpy(pTo->u.aDisk, pFrom->u.aDisk, SQLITE_PAGE_SIZE); + pTo->pParent = 0; + pTo->isInit = 1; + pTo->nCell = pFrom->nCell; + pTo->nFree = pFrom->nFree; + pTo->isOverfull = pFrom->isOverfull; + to = Addr(pTo); + from = Addr(pFrom); + for(i=0; inCell; i++){ + uptr x = Addr(pFrom->apCell[i]); + if( x>from && xapCell[i]) = x + to - from; + }else{ + pTo->apCell[i] = pFrom->apCell[i]; + } + } +} + +/* +** The following parameters determine how many adjacent pages get involved +** in a balancing operation. NN is the number of neighbors on either side +** of the page that participate in the balancing operation. NB is the +** total number of pages that participate, including the target page and +** NN neighbors on either side. +** +** The minimum value of NN is 1 (of course). Increasing NN above 1 +** (to 2 or 3) gives a modest improvement in SELECT and DELETE performance +** in exchange for a larger degradation in INSERT and UPDATE performance. +** The value of NN appears to give the best results overall. +*/ +#define NN 1 /* Number of neighbors on either side of pPage */ +#define NB (NN*2+1) /* Total pages involved in the balance */ + +/* +** This routine redistributes Cells on pPage and up to two siblings +** of pPage so that all pages have about the same amount of free space. +** Usually one sibling on either side of pPage is used in the balancing, +** though both siblings might come from one side if pPage is the first +** or last child of its parent. If pPage has fewer than two siblings +** (something which can only happen if pPage is the root page or a +** child of root) then all available siblings participate in the balancing. +** +** The number of siblings of pPage might be increased or decreased by +** one in an effort to keep pages between 66% and 100% full. The root page +** is special and is allowed to be less than 66% full. If pPage is +** the root page, then the depth of the tree might be increased +** or decreased by one, as necessary, to keep the root page from being +** overfull or empty. +** +** This routine calls relinkCellList() on its input page regardless of +** whether or not it does any real balancing. Client routines will typically +** invoke insertCell() or dropCell() before calling this routine, so we +** need to call relinkCellList() to clean up the mess that those other +** routines left behind. +** +** pCur is left pointing to the same cell as when this routine was called +** even if that cell gets moved to a different page. pCur may be NULL. +** Set the pCur parameter to NULL if you do not care about keeping track +** of a cell as that will save this routine the work of keeping track of it. +** +** Note that when this routine is called, some of the Cells on pPage +** might not actually be stored in pPage->u.aDisk[]. This can happen +** if the page is overfull. Part of the job of this routine is to +** make sure all Cells for pPage once again fit in pPage->u.aDisk[]. +** +** In the course of balancing the siblings of pPage, the parent of pPage +** might become overfull or underfull. If that happens, then this routine +** is called recursively on the parent. +** +** If this routine fails for any reason, it might leave the database +** in a corrupted state. So if this routine fails, the database should +** be rolled back. +*/ +static int balance(Btree *pBt, MemPage *pPage, BtCursor *pCur){ + MemPage *pParent; /* The parent of pPage */ + int nCell; /* Number of cells in apCell[] */ + int nOld; /* Number of pages in apOld[] */ + int nNew; /* Number of pages in apNew[] */ + int nDiv; /* Number of cells in apDiv[] */ + int i, j, k; /* Loop counters */ + int idx; /* Index of pPage in pParent->apCell[] */ + int nxDiv; /* Next divider slot in pParent->apCell[] */ + int rc; /* The return code */ + int iCur; /* apCell[iCur] is the cell of the cursor */ + MemPage *pOldCurPage; /* The cursor originally points to this page */ + int subtotal; /* Subtotal of bytes in cells on one page */ + MemPage *extraUnref = 0; /* A page that needs to be unref-ed */ + MemPage *apOld[NB]; /* pPage and up to two siblings */ + Pgno pgnoOld[NB]; /* Page numbers for each page in apOld[] */ + MemPage *apNew[NB+1]; /* pPage and up to NB siblings after balancing */ + Pgno pgnoNew[NB+1]; /* Page numbers for each page in apNew[] */ + int idxDiv[NB]; /* Indices of divider cells in pParent */ + Cell *apDiv[NB]; /* Divider cells in pParent */ + Cell aTemp[NB]; /* Temporary holding area for apDiv[] */ + int cntNew[NB+1]; /* Index in apCell[] of cell after i-th page */ + int szNew[NB+1]; /* Combined size of cells place on i-th page */ + MemPage aOld[NB]; /* Temporary copies of pPage and its siblings */ + Cell *apCell[(MX_CELL+2)*NB]; /* All cells from pages being balanced */ + int szCell[(MX_CELL+2)*NB]; /* Local size of all cells */ + + /* + ** Return without doing any work if pPage is neither overfull nor + ** underfull. + */ + assert( sqlitepager_iswriteable(pPage) ); + if( !pPage->isOverfull && pPage->nFreenCell>=2){ + relinkCellList(pBt, pPage); + return SQLITE_OK; + } + + /* + ** Find the parent of the page to be balanceed. + ** If there is no parent, it means this page is the root page and + ** special rules apply. + */ + pParent = pPage->pParent; + if( pParent==0 ){ + Pgno pgnoChild; + MemPage *pChild; + assert( pPage->isInit ); + if( pPage->nCell==0 ){ + if( pPage->u.hdr.rightChild ){ + /* + ** The root page is empty. Copy the one child page + ** into the root page and return. This reduces the depth + ** of the BTree by one. + */ + pgnoChild = SWAB32(pBt, pPage->u.hdr.rightChild); + rc = sqlitepager_get(pBt->pPager, pgnoChild, (void**)&pChild); + if( rc ) return rc; + memcpy(pPage, pChild, SQLITE_PAGE_SIZE); + pPage->isInit = 0; + rc = initPage(pBt, pPage, sqlitepager_pagenumber(pPage), 0); + assert( rc==SQLITE_OK ); + reparentChildPages(pBt, pPage); + if( pCur && pCur->pPage==pChild ){ + sqlitepager_unref(pChild); + pCur->pPage = pPage; + sqlitepager_ref(pPage); + } + freePage(pBt, pChild, pgnoChild); + sqlitepager_unref(pChild); + }else{ + relinkCellList(pBt, pPage); + } + return SQLITE_OK; + } + if( !pPage->isOverfull ){ + /* It is OK for the root page to be less than half full. + */ + relinkCellList(pBt, pPage); + return SQLITE_OK; + } + /* + ** If we get to here, it means the root page is overfull. + ** When this happens, Create a new child page and copy the + ** contents of the root into the child. Then make the root + ** page an empty page with rightChild pointing to the new + ** child. Then fall thru to the code below which will cause + ** the overfull child page to be split. + */ + rc = sqlitepager_write(pPage); + if( rc ) return rc; + rc = allocatePage(pBt, &pChild, &pgnoChild, sqlitepager_pagenumber(pPage)); + if( rc ) return rc; + assert( sqlitepager_iswriteable(pChild) ); + copyPage(pChild, pPage); + pChild->pParent = pPage; + pChild->idxParent = 0; + sqlitepager_ref(pPage); + pChild->isOverfull = 1; + if( pCur && pCur->pPage==pPage ){ + sqlitepager_unref(pPage); + pCur->pPage = pChild; + }else{ + extraUnref = pChild; + } + zeroPage(pBt, pPage); + pPage->u.hdr.rightChild = SWAB32(pBt, pgnoChild); + pParent = pPage; + pPage = pChild; + } + rc = sqlitepager_write(pParent); + if( rc ) return rc; + assert( pParent->isInit ); + + /* + ** Find the Cell in the parent page whose h.leftChild points back + ** to pPage. The "idx" variable is the index of that cell. If pPage + ** is the rightmost child of pParent then set idx to pParent->nCell + */ + if( pParent->idxShift ){ + Pgno pgno, swabPgno; + pgno = sqlitepager_pagenumber(pPage); + swabPgno = SWAB32(pBt, pgno); + for(idx=0; idxnCell; idx++){ + if( pParent->apCell[idx]->h.leftChild==swabPgno ){ + break; + } + } + assert( idxnCell || pParent->u.hdr.rightChild==swabPgno ); + }else{ + idx = pPage->idxParent; + } + + /* + ** Initialize variables so that it will be safe to jump + ** directly to balance_cleanup at any moment. + */ + nOld = nNew = 0; + sqlitepager_ref(pParent); + + /* + ** Find sibling pages to pPage and the Cells in pParent that divide + ** the siblings. An attempt is made to find NN siblings on either + ** side of pPage. More siblings are taken from one side, however, if + ** pPage there are fewer than NN siblings on the other side. If pParent + ** has NB or fewer children then all children of pParent are taken. + */ + nxDiv = idx - NN; + if( nxDiv + NB > pParent->nCell ){ + nxDiv = pParent->nCell - NB + 1; + } + if( nxDiv<0 ){ + nxDiv = 0; + } + nDiv = 0; + for(i=0, k=nxDiv; inCell ){ + idxDiv[i] = k; + apDiv[i] = pParent->apCell[k]; + nDiv++; + pgnoOld[i] = SWAB32(pBt, apDiv[i]->h.leftChild); + }else if( k==pParent->nCell ){ + pgnoOld[i] = SWAB32(pBt, pParent->u.hdr.rightChild); + }else{ + break; + } + rc = sqlitepager_get(pBt->pPager, pgnoOld[i], (void**)&apOld[i]); + if( rc ) goto balance_cleanup; + rc = initPage(pBt, apOld[i], pgnoOld[i], pParent); + if( rc ) goto balance_cleanup; + apOld[i]->idxParent = k; + nOld++; + } + + /* + ** Set iCur to be the index in apCell[] of the cell that the cursor + ** is pointing to. We will need this later on in order to keep the + ** cursor pointing at the same cell. If pCur points to a page that + ** has no involvement with this rebalancing, then set iCur to a large + ** number so that the iCur==j tests always fail in the main cell + ** distribution loop below. + */ + if( pCur ){ + iCur = 0; + for(i=0; ipPage==apOld[i] ){ + iCur += pCur->idx; + break; + } + iCur += apOld[i]->nCell; + if( ipPage==pParent && pCur->idx==idxDiv[i] ){ + break; + } + iCur++; + } + pOldCurPage = pCur->pPage; + } + + /* + ** Make copies of the content of pPage and its siblings into aOld[]. + ** The rest of this function will use data from the copies rather + ** that the original pages since the original pages will be in the + ** process of being overwritten. + */ + for(i=0; inCell; j++){ + apCell[nCell] = pOld->apCell[j]; + szCell[nCell] = cellSize(pBt, apCell[nCell]); + nCell++; + } + if( ih.leftChild)==pgnoOld[i] ); + apCell[nCell]->h.leftChild = pOld->u.hdr.rightChild; + nCell++; + } + } + + /* + ** Figure out the number of pages needed to hold all nCell cells. + ** Store this number in "k". Also compute szNew[] which is the total + ** size of all cells on the i-th page and cntNew[] which is the index + ** in apCell[] of the cell that divides path i from path i+1. + ** cntNew[k] should equal nCell. + ** + ** This little patch of code is critical for keeping the tree + ** balanced. + */ + for(subtotal=k=i=0; i USABLE_SPACE ){ + szNew[k] = subtotal - szCell[i]; + cntNew[k] = i; + subtotal = 0; + k++; + } + } + szNew[k] = subtotal; + cntNew[k] = nCell; + k++; + for(i=k-1; i>0; i--){ + while( szNew[i]0 ); + szNew[i] += szCell[cntNew[i-1]]; + szNew[i-1] -= szCell[cntNew[i-1]-1]; + } + } + assert( cntNew[0]>0 ); + + /* + ** Allocate k new pages. Reuse old pages where possible. + */ + for(i=0; iisInit = 1; + } + + /* Free any old pages that were not reused as new pages. + */ + while( ii ){ + int t; + MemPage *pT; + t = pgnoNew[i]; + pT = apNew[i]; + pgnoNew[i] = pgnoNew[minI]; + apNew[i] = apNew[minI]; + pgnoNew[minI] = t; + apNew[minI] = pT; + } + } + + /* + ** Evenly distribute the data in apCell[] across the new pages. + ** Insert divider cells into pParent as necessary. + */ + j = 0; + for(i=0; inFree>=szCell[j] ); + if( pCur && iCur==j ){ pCur->pPage = pNew; pCur->idx = pNew->nCell; } + insertCell(pBt, pNew, pNew->nCell, apCell[j], szCell[j]); + j++; + } + assert( pNew->nCell>0 ); + assert( !pNew->isOverfull ); + relinkCellList(pBt, pNew); + if( iu.hdr.rightChild = apCell[j]->h.leftChild; + apCell[j]->h.leftChild = SWAB32(pBt, pgnoNew[i]); + if( pCur && iCur==j ){ pCur->pPage = pParent; pCur->idx = nxDiv; } + insertCell(pBt, pParent, nxDiv, apCell[j], szCell[j]); + j++; + nxDiv++; + } + } + assert( j==nCell ); + apNew[nNew-1]->u.hdr.rightChild = aOld[nOld-1].u.hdr.rightChild; + if( nxDiv==pParent->nCell ){ + pParent->u.hdr.rightChild = SWAB32(pBt, pgnoNew[nNew-1]); + }else{ + pParent->apCell[nxDiv]->h.leftChild = SWAB32(pBt, pgnoNew[nNew-1]); + } + if( pCur ){ + if( j<=iCur && pCur->pPage==pParent && pCur->idx>idxDiv[nOld-1] ){ + assert( pCur->pPage==pOldCurPage ); + pCur->idx += nNew - nOld; + }else{ + assert( pOldCurPage!=0 ); + sqlitepager_ref(pCur->pPage); + sqlitepager_unref(pOldCurPage); + } + } + + /* + ** Reparent children of all cells. + */ + for(i=0; ipPage==0 ){ + pCur->pPage = pParent; + pCur->idx = 0; + }else{ + sqlitepager_unref(pParent); + } + return rc; +} + +/* +** This routine checks all cursors that point to the same table +** as pCur points to. If any of those cursors were opened with +** wrFlag==0 then this routine returns SQLITE_LOCKED. If all +** cursors point to the same table were opened with wrFlag==1 +** then this routine returns SQLITE_OK. +** +** In addition to checking for read-locks (where a read-lock +** means a cursor opened with wrFlag==0) this routine also moves +** all cursors other than pCur so that they are pointing to the +** first Cell on root page. This is necessary because an insert +** or delete might change the number of cells on a page or delete +** a page entirely and we do not want to leave any cursors +** pointing to non-existant pages or cells. +*/ +static int checkReadLocks(BtCursor *pCur){ + BtCursor *p; + assert( pCur->wrFlag ); + for(p=pCur->pShared; p!=pCur; p=p->pShared){ + assert( p ); + assert( p->pgnoRoot==pCur->pgnoRoot ); + if( p->wrFlag==0 ) return SQLITE_LOCKED; + if( sqlitepager_pagenumber(p->pPage)!=p->pgnoRoot ){ + moveToRoot(p); + } + } + return SQLITE_OK; +} + +/* +** Insert a new record into the BTree. The key is given by (pKey,nKey) +** and the data is given by (pData,nData). The cursor is used only to +** define what database the record should be inserted into. The cursor +** is left pointing at the new record. +*/ +static int fileBtreeInsert( + BtCursor *pCur, /* Insert data into the table of this cursor */ + const void *pKey, int nKey, /* The key of the new record */ + const void *pData, int nData /* The data of the new record */ +){ + Cell newCell; + int rc; + int loc; + int szNew; + MemPage *pPage; + Btree *pBt = pCur->pBt; + + if( pCur->pPage==0 ){ + return SQLITE_ABORT; /* A rollback destroyed this cursor */ + } + if( !pBt->inTrans || nKey+nData==0 ){ + /* Must start a transaction before doing an insert */ + return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; + } + assert( !pBt->readOnly ); + if( !pCur->wrFlag ){ + return SQLITE_PERM; /* Cursor not open for writing */ + } + if( checkReadLocks(pCur) ){ + return SQLITE_LOCKED; /* The table pCur points to has a read lock */ + } + rc = fileBtreeMoveto(pCur, pKey, nKey, &loc); + if( rc ) return rc; + pPage = pCur->pPage; + assert( pPage->isInit ); + rc = sqlitepager_write(pPage); + if( rc ) return rc; + rc = fillInCell(pBt, &newCell, pKey, nKey, pData, nData); + if( rc ) return rc; + szNew = cellSize(pBt, &newCell); + if( loc==0 ){ + newCell.h.leftChild = pPage->apCell[pCur->idx]->h.leftChild; + rc = clearCell(pBt, pPage->apCell[pCur->idx]); + if( rc ) return rc; + dropCell(pBt, pPage, pCur->idx, cellSize(pBt, pPage->apCell[pCur->idx])); + }else if( loc<0 && pPage->nCell>0 ){ + assert( pPage->u.hdr.rightChild==0 ); /* Must be a leaf page */ + pCur->idx++; + }else{ + assert( pPage->u.hdr.rightChild==0 ); /* Must be a leaf page */ + } + insertCell(pBt, pPage, pCur->idx, &newCell, szNew); + rc = balance(pCur->pBt, pPage, pCur); + /* sqliteBtreePageDump(pCur->pBt, pCur->pgnoRoot, 1); */ + /* fflush(stdout); */ + pCur->eSkip = SKIP_INVALID; + return rc; +} + +/* +** Delete the entry that the cursor is pointing to. +** +** The cursor is left pointing at either the next or the previous +** entry. If the cursor is left pointing to the next entry, then +** the pCur->eSkip flag is set to SKIP_NEXT which forces the next call to +** sqliteBtreeNext() to be a no-op. That way, you can always call +** sqliteBtreeNext() after a delete and the cursor will be left +** pointing to the first entry after the deleted entry. Similarly, +** pCur->eSkip is set to SKIP_PREV is the cursor is left pointing to +** the entry prior to the deleted entry so that a subsequent call to +** sqliteBtreePrevious() will always leave the cursor pointing at the +** entry immediately before the one that was deleted. +*/ +static int fileBtreeDelete(BtCursor *pCur){ + MemPage *pPage = pCur->pPage; + Cell *pCell; + int rc; + Pgno pgnoChild; + Btree *pBt = pCur->pBt; + + assert( pPage->isInit ); + if( pCur->pPage==0 ){ + return SQLITE_ABORT; /* A rollback destroyed this cursor */ + } + if( !pBt->inTrans ){ + /* Must start a transaction before doing a delete */ + return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; + } + assert( !pBt->readOnly ); + if( pCur->idx >= pPage->nCell ){ + return SQLITE_ERROR; /* The cursor is not pointing to anything */ + } + if( !pCur->wrFlag ){ + return SQLITE_PERM; /* Did not open this cursor for writing */ + } + if( checkReadLocks(pCur) ){ + return SQLITE_LOCKED; /* The table pCur points to has a read lock */ + } + rc = sqlitepager_write(pPage); + if( rc ) return rc; + pCell = pPage->apCell[pCur->idx]; + pgnoChild = SWAB32(pBt, pCell->h.leftChild); + clearCell(pBt, pCell); + if( pgnoChild ){ + /* + ** The entry we are about to delete is not a leaf so if we do not + ** do something we will leave a hole on an internal page. + ** We have to fill the hole by moving in a cell from a leaf. The + ** next Cell after the one to be deleted is guaranteed to exist and + ** to be a leaf so we can use it. + */ + BtCursor leafCur; + Cell *pNext; + int szNext; + int notUsed; + getTempCursor(pCur, &leafCur); + rc = fileBtreeNext(&leafCur, ¬Used); + if( rc!=SQLITE_OK ){ + return SQLITE_CORRUPT; + } + rc = sqlitepager_write(leafCur.pPage); + if( rc ) return rc; + dropCell(pBt, pPage, pCur->idx, cellSize(pBt, pCell)); + pNext = leafCur.pPage->apCell[leafCur.idx]; + szNext = cellSize(pBt, pNext); + pNext->h.leftChild = SWAB32(pBt, pgnoChild); + insertCell(pBt, pPage, pCur->idx, pNext, szNext); + rc = balance(pBt, pPage, pCur); + if( rc ) return rc; + pCur->eSkip = SKIP_NEXT; + dropCell(pBt, leafCur.pPage, leafCur.idx, szNext); + rc = balance(pBt, leafCur.pPage, pCur); + releaseTempCursor(&leafCur); + }else{ + dropCell(pBt, pPage, pCur->idx, cellSize(pBt, pCell)); + if( pCur->idx>=pPage->nCell ){ + pCur->idx = pPage->nCell-1; + if( pCur->idx<0 ){ + pCur->idx = 0; + pCur->eSkip = SKIP_NEXT; + }else{ + pCur->eSkip = SKIP_PREV; + } + }else{ + pCur->eSkip = SKIP_NEXT; + } + rc = balance(pBt, pPage, pCur); + } + return rc; +} + +/* +** Create a new BTree table. Write into *piTable the page +** number for the root page of the new table. +** +** In the current implementation, BTree tables and BTree indices are the +** the same. In the future, we may change this so that BTree tables +** are restricted to having a 4-byte integer key and arbitrary data and +** BTree indices are restricted to having an arbitrary key and no data. +** But for now, this routine also serves to create indices. +*/ +static int fileBtreeCreateTable(Btree *pBt, int *piTable){ + MemPage *pRoot; + Pgno pgnoRoot; + int rc; + if( !pBt->inTrans ){ + /* Must start a transaction first */ + return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; + } + if( pBt->readOnly ){ + return SQLITE_READONLY; + } + rc = allocatePage(pBt, &pRoot, &pgnoRoot, 0); + if( rc ) return rc; + assert( sqlitepager_iswriteable(pRoot) ); + zeroPage(pBt, pRoot); + sqlitepager_unref(pRoot); + *piTable = (int)pgnoRoot; + return SQLITE_OK; +} + +/* +** Erase the given database page and all its children. Return +** the page to the freelist. +*/ +static int clearDatabasePage(Btree *pBt, Pgno pgno, int freePageFlag){ + MemPage *pPage; + int rc; + Cell *pCell; + int idx; + + rc = sqlitepager_get(pBt->pPager, pgno, (void**)&pPage); + if( rc ) return rc; + rc = sqlitepager_write(pPage); + if( rc ) return rc; + rc = initPage(pBt, pPage, pgno, 0); + if( rc ) return rc; + idx = SWAB16(pBt, pPage->u.hdr.firstCell); + while( idx>0 ){ + pCell = (Cell*)&pPage->u.aDisk[idx]; + idx = SWAB16(pBt, pCell->h.iNext); + if( pCell->h.leftChild ){ + rc = clearDatabasePage(pBt, SWAB32(pBt, pCell->h.leftChild), 1); + if( rc ) return rc; + } + rc = clearCell(pBt, pCell); + if( rc ) return rc; + } + if( pPage->u.hdr.rightChild ){ + rc = clearDatabasePage(pBt, SWAB32(pBt, pPage->u.hdr.rightChild), 1); + if( rc ) return rc; + } + if( freePageFlag ){ + rc = freePage(pBt, pPage, pgno); + }else{ + zeroPage(pBt, pPage); + } + sqlitepager_unref(pPage); + return rc; +} + +/* +** Delete all information from a single table in the database. +*/ +static int fileBtreeClearTable(Btree *pBt, int iTable){ + int rc; + BtCursor *pCur; + if( !pBt->inTrans ){ + 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); + } + } + rc = clearDatabasePage(pBt, (Pgno)iTable, 0); + if( rc ){ + fileBtreeRollback(pBt); + } + return rc; +} + +/* +** Erase all information in a table and add the root of the table to +** the freelist. Except, the root of the principle table (the one on +** page 2) is never added to the freelist. +*/ +static int fileBtreeDropTable(Btree *pBt, int iTable){ + int rc; + MemPage *pPage; + BtCursor *pCur; + if( !pBt->inTrans ){ + return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; + } + for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ + if( pCur->pgnoRoot==(Pgno)iTable ){ + return SQLITE_LOCKED; /* Cannot drop a table that has a cursor */ + } + } + rc = sqlitepager_get(pBt->pPager, (Pgno)iTable, (void**)&pPage); + if( rc ) return rc; + rc = fileBtreeClearTable(pBt, iTable); + if( rc ) return rc; + if( iTable>2 ){ + rc = freePage(pBt, pPage, iTable); + }else{ + zeroPage(pBt, pPage); + } + sqlitepager_unref(pPage); + return rc; +} + +#if 0 /* UNTESTED */ +/* +** Copy all cell data from one database file into another. +** pages back the freelist. +*/ +static int copyCell(Btree *pBtFrom, BTree *pBtTo, Cell *pCell){ + Pager *pFromPager = pBtFrom->pPager; + OverflowPage *pOvfl; + Pgno ovfl, nextOvfl; + Pgno *pPrev; + int rc = SQLITE_OK; + MemPage *pNew, *pPrevPg; + Pgno new; + + if( NKEY(pBtTo, pCell->h) + NDATA(pBtTo, pCell->h) <= MX_LOCAL_PAYLOAD ){ + return SQLITE_OK; + } + pPrev = &pCell->ovfl; + pPrevPg = 0; + ovfl = SWAB32(pBtTo, pCell->ovfl); + while( ovfl && rc==SQLITE_OK ){ + rc = sqlitepager_get(pFromPager, ovfl, (void**)&pOvfl); + if( rc ) return rc; + nextOvfl = SWAB32(pBtFrom, pOvfl->iNext); + rc = allocatePage(pBtTo, &pNew, &new, 0); + if( rc==SQLITE_OK ){ + rc = sqlitepager_write(pNew); + if( rc==SQLITE_OK ){ + memcpy(pNew, pOvfl, SQLITE_PAGE_SIZE); + *pPrev = SWAB32(pBtTo, new); + if( pPrevPg ){ + sqlitepager_unref(pPrevPg); + } + pPrev = &pOvfl->iNext; + pPrevPg = pNew; + } + } + sqlitepager_unref(pOvfl); + ovfl = nextOvfl; + } + if( pPrevPg ){ + sqlitepager_unref(pPrevPg); + } + return rc; +} +#endif + + +#if 0 /* UNTESTED */ +/* +** Copy a page of data from one database over to another. +*/ +static int copyDatabasePage( + Btree *pBtFrom, + Pgno pgnoFrom, + Btree *pBtTo, + Pgno *pTo +){ + MemPage *pPageFrom, *pPage; + Pgno to; + int rc; + Cell *pCell; + int idx; + + rc = sqlitepager_get(pBtFrom->pPager, pgno, (void**)&pPageFrom); + if( rc ) return rc; + rc = allocatePage(pBt, &pPage, pTo, 0); + if( rc==SQLITE_OK ){ + rc = sqlitepager_write(pPage); + } + if( rc==SQLITE_OK ){ + memcpy(pPage, pPageFrom, SQLITE_PAGE_SIZE); + idx = SWAB16(pBt, pPage->u.hdr.firstCell); + while( idx>0 ){ + pCell = (Cell*)&pPage->u.aDisk[idx]; + idx = SWAB16(pBt, pCell->h.iNext); + if( pCell->h.leftChild ){ + Pgno newChld; + rc = copyDatabasePage(pBtFrom, SWAB32(pBtFrom, pCell->h.leftChild), + pBtTo, &newChld); + if( rc ) return rc; + pCell->h.leftChild = SWAB32(pBtFrom, newChld); + } + rc = copyCell(pBtFrom, pBtTo, pCell); + if( rc ) return rc; + } + if( pPage->u.hdr.rightChild ){ + Pgno newChld; + rc = copyDatabasePage(pBtFrom, SWAB32(pBtFrom, pPage->u.hdr.rightChild), + pBtTo, &newChld); + if( rc ) return rc; + pPage->u.hdr.rightChild = SWAB32(pBtTo, newChild); + } + } + sqlitepager_unref(pPage); + return rc; +} +#endif + +/* +** Read the meta-information out of a database file. +*/ +static int fileBtreeGetMeta(Btree *pBt, int *aMeta){ + PageOne *pP1; + int rc; + int i; + + rc = sqlitepager_get(pBt->pPager, 1, (void**)&pP1); + if( rc ) return rc; + aMeta[0] = SWAB32(pBt, pP1->nFree); + for(i=0; iaMeta)/sizeof(pP1->aMeta[0]); i++){ + aMeta[i+1] = SWAB32(pBt, pP1->aMeta[i]); + } + sqlitepager_unref(pP1); + return SQLITE_OK; +} + +/* +** Write meta-information back into the database. +*/ +static int fileBtreeUpdateMeta(Btree *pBt, int *aMeta){ + PageOne *pP1; + int rc, i; + if( !pBt->inTrans ){ + return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; + } + pP1 = pBt->page1; + rc = sqlitepager_write(pP1); + if( rc ) return rc; + for(i=0; iaMeta)/sizeof(pP1->aMeta[0]); i++){ + pP1->aMeta[i] = SWAB32(pBt, aMeta[i+1]); + } + return SQLITE_OK; +} + +/****************************************************************************** +** The complete implementation of the BTree subsystem is above this line. +** All the code the follows is for testing and troubleshooting the BTree +** subsystem. None of the code that follows is used during normal operation. +******************************************************************************/ + +/* +** Print a disassembly of the given page on standard output. This routine +** is used for debugging and testing only. +*/ +#ifdef SQLITE_TEST +static int fileBtreePageDump(Btree *pBt, int pgno, int recursive){ + int rc; + MemPage *pPage; + int i, j; + int nFree; + u16 idx; + char range[20]; + unsigned char payload[20]; + rc = sqlitepager_get(pBt->pPager, (Pgno)pgno, (void**)&pPage); + if( rc ){ + return rc; + } + if( recursive ) printf("PAGE %d:\n", pgno); + i = 0; + idx = SWAB16(pBt, pPage->u.hdr.firstCell); + while( idx>0 && idx<=SQLITE_PAGE_SIZE-MIN_CELL_SIZE ){ + Cell *pCell = (Cell*)&pPage->u.aDisk[idx]; + int sz = cellSize(pBt, pCell); + sprintf(range,"%d..%d", idx, idx+sz-1); + sz = NKEY(pBt, pCell->h) + NDATA(pBt, pCell->h); + if( sz>sizeof(payload)-1 ) sz = sizeof(payload)-1; + memcpy(payload, pCell->aPayload, sz); + for(j=0; j0x7f ) payload[j] = '.'; + } + payload[sz] = 0; + printf( + "cell %2d: i=%-10s chld=%-4d nk=%-4d nd=%-4d payload=%s\n", + i, range, (int)pCell->h.leftChild, + NKEY(pBt, pCell->h), NDATA(pBt, pCell->h), + payload + ); + if( pPage->isInit && pPage->apCell[i]!=pCell ){ + printf("**** apCell[%d] does not match on prior entry ****\n", i); + } + i++; + idx = SWAB16(pBt, pCell->h.iNext); + } + if( idx!=0 ){ + printf("ERROR: next cell index out of range: %d\n", idx); + } + printf("right_child: %d\n", SWAB32(pBt, pPage->u.hdr.rightChild)); + nFree = 0; + i = 0; + idx = SWAB16(pBt, pPage->u.hdr.firstFree); + while( idx>0 && idxu.aDisk[idx]; + sprintf(range,"%d..%d", idx, idx+p->iSize-1); + nFree += SWAB16(pBt, p->iSize); + printf("freeblock %2d: i=%-10s size=%-4d total=%d\n", + i, range, SWAB16(pBt, p->iSize), nFree); + idx = SWAB16(pBt, p->iNext); + i++; + } + if( idx!=0 ){ + printf("ERROR: next freeblock index out of range: %d\n", idx); + } + if( recursive && pPage->u.hdr.rightChild!=0 ){ + idx = SWAB16(pBt, pPage->u.hdr.firstCell); + while( idx>0 && idxu.aDisk[idx]; + fileBtreePageDump(pBt, SWAB32(pBt, pCell->h.leftChild), 1); + idx = SWAB16(pBt, pCell->h.iNext); + } + fileBtreePageDump(pBt, SWAB32(pBt, pPage->u.hdr.rightChild), 1); + } + sqlitepager_unref(pPage); + return SQLITE_OK; +} +#endif + +#ifdef SQLITE_TEST +/* +** Fill aResult[] with information about the entry and page that the +** cursor is pointing to. +** +** aResult[0] = The page number +** aResult[1] = The entry number +** aResult[2] = Total number of entries on this page +** aResult[3] = Size of this entry +** aResult[4] = Number of free bytes on this page +** aResult[5] = Number of free blocks on the page +** aResult[6] = Page number of the left child of this entry +** aResult[7] = Page number of the right child for the whole page +** +** This routine is used for testing and debugging only. +*/ +static int fileBtreeCursorDump(BtCursor *pCur, int *aResult){ + int cnt, idx; + MemPage *pPage = pCur->pPage; + Btree *pBt = pCur->pBt; + aResult[0] = sqlitepager_pagenumber(pPage); + aResult[1] = pCur->idx; + aResult[2] = pPage->nCell; + if( pCur->idx>=0 && pCur->idxnCell ){ + aResult[3] = cellSize(pBt, pPage->apCell[pCur->idx]); + aResult[6] = SWAB32(pBt, pPage->apCell[pCur->idx]->h.leftChild); + }else{ + aResult[3] = 0; + aResult[6] = 0; + } + aResult[4] = pPage->nFree; + cnt = 0; + idx = SWAB16(pBt, pPage->u.hdr.firstFree); + while( idx>0 && idxu.aDisk[idx])->iNext); + } + aResult[5] = cnt; + aResult[7] = SWAB32(pBt, pPage->u.hdr.rightChild); + return SQLITE_OK; +} +#endif + +#ifdef SQLITE_TEST +/* +** Return the pager associated with a BTree. This routine is used for +** testing and debugging only. +*/ +static Pager *fileBtreePager(Btree *pBt){ + return pBt->pPager; +} +#endif + +/* +** This structure is passed around through all the sanity checking routines +** in order to keep track of some global state information. +*/ +typedef struct IntegrityCk IntegrityCk; +struct IntegrityCk { + Btree *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 */ + int nTreePage; /* Number of BTree pages */ + int nByte; /* Number of bytes of data stored on BTree pages */ + char *zErrMsg; /* An error message. NULL of no errors seen. */ +}; + +/* +** Append a message to the error message string. +*/ +static void checkAppendMsg(IntegrityCk *pCheck, char *zMsg1, char *zMsg2){ + if( pCheck->zErrMsg ){ + char *zOld = pCheck->zErrMsg; + pCheck->zErrMsg = 0; + sqliteSetString(&pCheck->zErrMsg, zOld, "\n", zMsg1, zMsg2, 0); + sqliteFree(zOld); + }else{ + sqliteSetString(&pCheck->zErrMsg, zMsg1, zMsg2, 0); + } +} + +/* +** Add 1 to the reference count for page iPage. If this is the second +** reference to the page, add an error message to pCheck->zErrMsg. +** Return 1 if there are 2 ore more references to the page and 0 if +** if this is the first reference to the page. +** +** Also check that the page number is in bounds. +*/ +static int checkRef(IntegrityCk *pCheck, int iPage, char *zContext){ + if( iPage==0 ) return 1; + if( iPage>pCheck->nPage || iPage<0 ){ + char zBuf[100]; + sprintf(zBuf, "invalid page number %d", iPage); + checkAppendMsg(pCheck, zContext, zBuf); + return 1; + } + if( pCheck->anRef[iPage]==1 ){ + char zBuf[100]; + sprintf(zBuf, "2nd reference to page %d", iPage); + checkAppendMsg(pCheck, zContext, zBuf); + return 1; + } + return (pCheck->anRef[iPage]++)>1; +} + +/* +** Check the integrity of the freelist or of an overflow page list. +** Verify that the number of pages on the list is N. +*/ +static void checkList( + IntegrityCk *pCheck, /* Integrity checking context */ + int isFreeList, /* True for a freelist. False for overflow page list */ + int iPage, /* Page number for first page in the list */ + int N, /* Expected number of pages in the list */ + char *zContext /* Context for error messages */ +){ + int i; + char zMsg[100]; + while( N-- > 0 ){ + OverflowPage *pOvfl; + if( iPage<1 ){ + sprintf(zMsg, "%d pages missing from overflow list", N+1); + checkAppendMsg(pCheck, zContext, zMsg); + break; + } + if( checkRef(pCheck, iPage, zContext) ) break; + if( sqlitepager_get(pCheck->pPager, (Pgno)iPage, (void**)&pOvfl) ){ + sprintf(zMsg, "failed to get page %d", iPage); + checkAppendMsg(pCheck, zContext, zMsg); + break; + } + if( isFreeList ){ + FreelistInfo *pInfo = (FreelistInfo*)pOvfl->aPayload; + int n = SWAB32(pCheck->pBt, pInfo->nFree); + for(i=0; ipBt, pInfo->aFree[i]), zContext); + } + N -= n; + } + iPage = SWAB32(pCheck->pBt, pOvfl->iNext); + sqlitepager_unref(pOvfl); + } +} + +/* +** Return negative if zKey1zKey2. +*/ +static int keyCompare( + const char *zKey1, int nKey1, + const char *zKey2, int nKey2 +){ + int min = nKey1>nKey2 ? nKey2 : nKey1; + int c = memcmp(zKey1, zKey2, min); + if( c==0 ){ + c = nKey1 - nKey2; + } + return c; +} + +/* +** Do various sanity checks on a single page of a tree. Return +** the tree depth. Root pages return 0. Parents of root pages +** return 1, and so forth. +** +** These checks are done: +** +** 1. Make sure that cells and freeblocks do not overlap +** but combine to completely cover the page. +** 2. Make sure cell keys are in order. +** 3. Make sure no key is less than or equal to zLowerBound. +** 4. Make sure no key is greater than or equal to zUpperBound. +** 5. Check the integrity of overflow pages. +** 6. Recursively call checkTreePage on all children. +** 7. Verify that the depth of all children is the same. +** 8. Make sure this page is at least 33% full or else it is +** the root of the tree. +*/ +static int checkTreePage( + IntegrityCk *pCheck, /* Context for the sanity check */ + int iPage, /* Page number of the page to check */ + MemPage *pParent, /* Parent page */ + char *zParentContext, /* Parent context */ + char *zLowerBound, /* All keys should be greater than this, if not NULL */ + int nLower, /* Number of characters in zLowerBound */ + char *zUpperBound, /* All keys should be less than this, if not NULL */ + int nUpper /* Number of characters in zUpperBound */ +){ + MemPage *pPage; + int i, rc, depth, d2, pgno; + char *zKey1, *zKey2; + int nKey1, nKey2; + BtCursor cur; + Btree *pBt; + char zMsg[100]; + char zContext[100]; + char hit[SQLITE_PAGE_SIZE]; + + /* Check that the page exists + */ + cur.pBt = pBt = pCheck->pBt; + if( iPage==0 ) return 0; + if( checkRef(pCheck, iPage, zParentContext) ) return 0; + sprintf(zContext, "On tree page %d: ", iPage); + if( (rc = sqlitepager_get(pCheck->pPager, (Pgno)iPage, (void**)&pPage))!=0 ){ + sprintf(zMsg, "unable to get the page. error code=%d", rc); + checkAppendMsg(pCheck, zContext, zMsg); + return 0; + } + if( (rc = initPage(pBt, pPage, (Pgno)iPage, pParent))!=0 ){ + sprintf(zMsg, "initPage() returns error code %d", rc); + checkAppendMsg(pCheck, zContext, zMsg); + sqlitepager_unref(pPage); + return 0; + } + + /* Check out all the cells. + */ + depth = 0; + if( zLowerBound ){ + zKey1 = sqliteMalloc( nLower+1 ); + memcpy(zKey1, zLowerBound, nLower); + zKey1[nLower] = 0; + }else{ + zKey1 = 0; + } + nKey1 = nLower; + cur.pPage = pPage; + for(i=0; inCell; i++){ + Cell *pCell = pPage->apCell[i]; + int sz; + + /* Check payload overflow pages + */ + nKey2 = NKEY(pBt, pCell->h); + sz = nKey2 + NDATA(pBt, pCell->h); + sprintf(zContext, "On page %d cell %d: ", iPage, i); + if( sz>MX_LOCAL_PAYLOAD ){ + int nPage = (sz - MX_LOCAL_PAYLOAD + OVERFLOW_SIZE - 1)/OVERFLOW_SIZE; + checkList(pCheck, 0, SWAB32(pBt, pCell->ovfl), nPage, zContext); + } + + /* Check that keys are in the right order + */ + cur.idx = i; + zKey2 = sqliteMallocRaw( nKey2+1 ); + getPayload(&cur, 0, nKey2, zKey2); + if( zKey1 && keyCompare(zKey1, nKey1, zKey2, nKey2)>=0 ){ + checkAppendMsg(pCheck, zContext, "Key is out of order"); + } + + /* Check sanity of left child page. + */ + pgno = SWAB32(pBt, pCell->h.leftChild); + d2 = checkTreePage(pCheck, pgno, pPage, zContext, zKey1,nKey1,zKey2,nKey2); + if( i>0 && d2!=depth ){ + checkAppendMsg(pCheck, zContext, "Child page depth differs"); + } + depth = d2; + sqliteFree(zKey1); + zKey1 = zKey2; + nKey1 = nKey2; + } + pgno = SWAB32(pBt, pPage->u.hdr.rightChild); + sprintf(zContext, "On page %d at right child: ", iPage); + checkTreePage(pCheck, pgno, pPage, zContext, zKey1,nKey1,zUpperBound,nUpper); + sqliteFree(zKey1); + + /* Check for complete coverage of the page + */ + memset(hit, 0, sizeof(hit)); + memset(hit, 1, sizeof(PageHdr)); + for(i=SWAB16(pBt, pPage->u.hdr.firstCell); i>0 && iu.aDisk[i]; + int j; + for(j=i+cellSize(pBt, pCell)-1; j>=i; j--) hit[j]++; + i = SWAB16(pBt, pCell->h.iNext); + } + for(i=SWAB16(pBt,pPage->u.hdr.firstFree); i>0 && iu.aDisk[i]; + int j; + for(j=i+SWAB16(pBt,pFBlk->iSize)-1; j>=i; j--) hit[j]++; + i = SWAB16(pBt,pFBlk->iNext); + } + for(i=0; i1 ){ + sprintf(zMsg, "Multiple uses for byte %d of page %d", i, iPage); + checkAppendMsg(pCheck, zMsg, 0); + break; + } + } + + /* Check that free space is kept to a minimum + */ +#if 0 + if( pParent && pParent->nCell>2 && pPage->nFree>3*SQLITE_PAGE_SIZE/4 ){ + sprintf(zMsg, "free space (%d) greater than max (%d)", pPage->nFree, + SQLITE_PAGE_SIZE/3); + checkAppendMsg(pCheck, zContext, zMsg); + } +#endif + + /* Update freespace totals. + */ + pCheck->nTreePage++; + pCheck->nByte += USABLE_SPACE - pPage->nFree; + + sqlitepager_unref(pPage); + return depth; +} + +/* +** This routine does a complete check of the given BTree file. aRoot[] is +** an array of pages numbers were each page number is the root page of +** a table. nRoot is the number of entries in aRoot. +** +** If everything checks out, this routine returns NULL. If something is +** amiss, an error message is written into memory obtained from malloc() +** and a pointer to that error message is returned. The calling function +** is responsible for freeing the error message when it is done. +*/ +char *fileBtreeIntegrityCheck(Btree *pBt, int *aRoot, int nRoot){ + int i; + int nRef; + IntegrityCk sCheck; + + nRef = *sqlitepager_stats(pBt->pPager); + if( lockBtree(pBt)!=SQLITE_OK ){ + return sqliteStrDup("Unable to acquire a read lock on the database"); + } + sCheck.pBt = pBt; + sCheck.pPager = pBt->pPager; + sCheck.nPage = sqlitepager_pagecount(sCheck.pPager); + if( sCheck.nPage==0 ){ + unlockBtreeIfUnused(pBt); + return 0; + } + sCheck.anRef = sqliteMallocRaw( (sCheck.nPage+1)*sizeof(sCheck.anRef[0]) ); + sCheck.anRef[1] = 1; + for(i=2; i<=sCheck.nPage; i++){ sCheck.anRef[i] = 0; } + sCheck.zErrMsg = 0; + + /* Check the integrity of the freelist + */ + checkList(&sCheck, 1, SWAB32(pBt, pBt->page1->freeList), + SWAB32(pBt, pBt->page1->nFree), "Main freelist: "); + + /* Check all the tables. + */ + for(i=0; ipPager) ){ + char zBuf[100]; + sprintf(zBuf, + "Outstanding page count goes from %d to %d during this analysis", + nRef, *sqlitepager_stats(pBt->pPager) + ); + checkAppendMsg(&sCheck, zBuf, 0); + } + + /* Clean up and report errors. + */ + sqliteFree(sCheck.anRef); + return sCheck.zErrMsg; +} + +/* +** Return the full pathname of the underlying database file. +*/ +static const char *fileBtreeGetFilename(Btree *pBt){ + assert( pBt->pPager!=0 ); + return sqlitepager_filename(pBt->pPager); +} + +/* +** Copy the complete content of pBtFrom into pBtTo. A transaction +** must be active for both files. +** +** The size of file pBtFrom may be reduced by this operation. +** If anything goes wrong, the transaction on pBtFrom is rolled back. +*/ +static int fileBtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){ + int rc = SQLITE_OK; + Pgno i, nPage, nToPage; + + if( !pBtTo->inTrans || !pBtFrom->inTrans ) return SQLITE_ERROR; + /*MAU if( pBtTo->needSwab!=pBtFrom->needSwab ) return SQLITE_ERROR;*/ + if( pBtTo->pCursor ) return SQLITE_BUSY; + memcpy(pBtTo->page1, pBtFrom->page1, SQLITE_PAGE_SIZE); + rc = sqlitepager_overwrite(pBtTo->pPager, 1, pBtFrom->page1); + nToPage = sqlitepager_pagecount(pBtTo->pPager); + nPage = sqlitepager_pagecount(pBtFrom->pPager); + for(i=2; rc==SQLITE_OK && i<=nPage; i++){ + void *pPage; + rc = sqlitepager_get(pBtFrom->pPager, i, &pPage); + if( rc ) break; + rc = sqlitepager_overwrite(pBtTo->pPager, i, pPage); + if( rc ) break; + sqlitepager_unref(pPage); + } + for(i=nPage+1; rc==SQLITE_OK && i<=nToPage; i++){ + void *pPage; + rc = sqlitepager_get(pBtTo->pPager, i, &pPage); + if( rc ) break; + rc = sqlitepager_write(pPage); + sqlitepager_unref(pPage); + sqlitepager_dont_write(pBtTo->pPager, i); + } + if( !rc && nPagepPager, nPage); + } + if( rc ){ + fileBtreeRollback(pBtTo); + } + return rc; +} + +/* +** The following tables contain pointers to all of the interface +** routines for this implementation of the B*Tree backend. To +** substitute a different implemention of the backend, one has merely +** to provide pointers to alternative functions in similar tables. +*/ +static BtOps sqliteBtreeOps = { + fileBtreeClose, + fileBtreeSetCacheSize, + fileBtreeSetSafetyLevel, + fileBtreeBeginTrans, + fileBtreeCommit, + fileBtreeRollback, + fileBtreeBeginCkpt, + fileBtreeCommitCkpt, + fileBtreeRollbackCkpt, + fileBtreeCreateTable, + fileBtreeCreateTable, /* Really sqliteBtreeCreateIndex() */ + fileBtreeDropTable, + fileBtreeClearTable, + fileBtreeCursor, + fileBtreeGetMeta, + fileBtreeUpdateMeta, + fileBtreeIntegrityCheck, + fileBtreeGetFilename, + fileBtreeCopyFile, +#ifdef SQLITE_TEST + fileBtreePageDump, + fileBtreePager +#endif +}; +static BtCursorOps sqliteBtreeCursorOps = { + fileBtreeMoveto, + fileBtreeDelete, + fileBtreeInsert, + fileBtreeFirst, + fileBtreeLast, + fileBtreeNext, + fileBtreePrevious, + fileBtreeKeySize, + fileBtreeKey, + fileBtreeKeyCompare, + fileBtreeDataSize, + fileBtreeData, + fileBtreeCloseCursor, +#ifdef SQLITE_TEST + fileBtreeCursorDump, +#endif +}; diff --git a/sqlitebrowser/sqlitebrowser/sqlite_source/btree.h b/sqlitebrowser/sqlitebrowser/sqlite_source/btree.h new file mode 100755 index 00000000..93c49cdc --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/sqlite_source/btree.h @@ -0,0 +1,156 @@ +/* +** 2001 September 15 +** +** 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 header file defines the interface that the sqlite B-Tree file +** subsystem. See comments in the source code for a detailed description +** of what each interface routine does. +** +** @(#) $Id: btree.h,v 1.1.1.1 2003-08-21 02:24:05 tabuleiro Exp $ +*/ +#ifndef _BTREE_H_ +#define _BTREE_H_ + +/* +** Forward declarations of structure +*/ +typedef struct Btree Btree; +typedef struct BtCursor BtCursor; +typedef struct BtOps BtOps; +typedef struct BtCursorOps BtCursorOps; + + +/* +** An instance of the following structure contains pointers to all +** methods against an open BTree. Alternative BTree implementations +** (examples: file based versus in-memory) can be created by substituting +** different methods. Users of the BTree cannot tell the difference. +** +** In C++ we could do this by defining a virtual base class and then +** creating subclasses for each different implementation. But this is +** C not C++ so we have to be a little more explicit. +*/ +struct BtOps { + int (*Close)(Btree*); + int (*SetCacheSize)(Btree*, int); + int (*SetSafetyLevel)(Btree*, int); + int (*BeginTrans)(Btree*); + int (*Commit)(Btree*); + int (*Rollback)(Btree*); + int (*BeginCkpt)(Btree*); + int (*CommitCkpt)(Btree*); + int (*RollbackCkpt)(Btree*); + int (*CreateTable)(Btree*, int*); + int (*CreateIndex)(Btree*, int*); + int (*DropTable)(Btree*, int); + int (*ClearTable)(Btree*, int); + int (*Cursor)(Btree*, int iTable, int wrFlag, BtCursor **ppCur); + int (*GetMeta)(Btree*, int*); + int (*UpdateMeta)(Btree*, int*); + char *(*IntegrityCheck)(Btree*, int*, int); + const char *(*GetFilename)(Btree*); + int (*Copyfile)(Btree*,Btree*); +#ifdef SQLITE_TEST + int (*PageDump)(Btree*, int, int); + struct Pager *(*Pager)(Btree*); +#endif +}; + +/* +** An instance of this structure defines all of the methods that can +** be executed against a cursor. +*/ +struct BtCursorOps { + int (*Moveto)(BtCursor*, const void *pKey, int nKey, int *pRes); + int (*Delete)(BtCursor*); + int (*Insert)(BtCursor*, const void *pKey, int nKey, + const void *pData, int nData); + int (*First)(BtCursor*, int *pRes); + int (*Last)(BtCursor*, int *pRes); + int (*Next)(BtCursor*, int *pRes); + int (*Previous)(BtCursor*, int *pRes); + int (*KeySize)(BtCursor*, int *pSize); + int (*Key)(BtCursor*, int offset, int amt, char *zBuf); + int (*KeyCompare)(BtCursor*, const void *pKey, int nKey, + int nIgnore, int *pRes); + int (*DataSize)(BtCursor*, int *pSize); + int (*Data)(BtCursor*, int offset, int amt, char *zBuf); + int (*CloseCursor)(BtCursor*); +#ifdef SQLITE_TEST + int (*CursorDump)(BtCursor*, int*); +#endif +}; + +/* +** The number of 4-byte "meta" values contained on the first page of each +** database file. +*/ +#define SQLITE_N_BTREE_META 10 + +int sqliteBtreeOpen(const char *zFilename, int mode, int nPg, Btree **ppBtree); +int sqliteRbtreeOpen(const char *zFilename, int mode, int nPg, Btree **ppBtree); + +#define btOps(pBt) (*((BtOps **)(pBt))) +#define btCOps(pCur) (*((BtCursorOps **)(pCur))) + +#define sqliteBtreeClose(pBt) (btOps(pBt)->Close(pBt)) +#define sqliteBtreeSetCacheSize(pBt, sz) (btOps(pBt)->SetCacheSize(pBt, sz)) +#define sqliteBtreeSetSafetyLevel(pBt, sl) (btOps(pBt)->SetSafetyLevel(pBt, sl)) +#define sqliteBtreeBeginTrans(pBt) (btOps(pBt)->BeginTrans(pBt)) +#define sqliteBtreeCommit(pBt) (btOps(pBt)->Commit(pBt)) +#define sqliteBtreeRollback(pBt) (btOps(pBt)->Rollback(pBt)) +#define sqliteBtreeBeginCkpt(pBt) (btOps(pBt)->BeginCkpt(pBt)) +#define sqliteBtreeCommitCkpt(pBt) (btOps(pBt)->CommitCkpt(pBt)) +#define sqliteBtreeRollbackCkpt(pBt) (btOps(pBt)->RollbackCkpt(pBt)) +#define sqliteBtreeCreateTable(pBt,piTable)\ + (btOps(pBt)->CreateTable(pBt,piTable)) +#define sqliteBtreeCreateIndex(pBt, piIndex)\ + (btOps(pBt)->CreateIndex(pBt, piIndex)) +#define sqliteBtreeDropTable(pBt, iTable) (btOps(pBt)->DropTable(pBt, iTable)) +#define sqliteBtreeClearTable(pBt, iTable)\ + (btOps(pBt)->ClearTable(pBt, iTable)) +#define sqliteBtreeCursor(pBt, iTable, wrFlag, ppCur)\ + (btOps(pBt)->Cursor(pBt, iTable, wrFlag, ppCur)) +#define sqliteBtreeMoveto(pCur, pKey, nKey, pRes)\ + (btCOps(pCur)->Moveto(pCur, pKey, nKey, pRes)) +#define sqliteBtreeDelete(pCur) (btCOps(pCur)->Delete(pCur)) +#define sqliteBtreeInsert(pCur, pKey, nKey, pData, nData) \ + (btCOps(pCur)->Insert(pCur, pKey, nKey, pData, nData)) +#define sqliteBtreeFirst(pCur, pRes) (btCOps(pCur)->First(pCur, pRes)) +#define sqliteBtreeLast(pCur, pRes) (btCOps(pCur)->Last(pCur, pRes)) +#define sqliteBtreeNext(pCur, pRes) (btCOps(pCur)->Next(pCur, pRes)) +#define sqliteBtreePrevious(pCur, pRes) (btCOps(pCur)->Previous(pCur, pRes)) +#define sqliteBtreeKeySize(pCur, pSize) (btCOps(pCur)->KeySize(pCur, pSize) ) +#define sqliteBtreeKey(pCur, offset, amt, zBuf)\ + (btCOps(pCur)->Key(pCur, offset, amt, zBuf)) +#define sqliteBtreeKeyCompare(pCur, pKey, nKey, nIgnore, pRes)\ + (btCOps(pCur)->KeyCompare(pCur, pKey, nKey, nIgnore, pRes)) +#define sqliteBtreeDataSize(pCur, pSize) (btCOps(pCur)->DataSize(pCur, pSize)) +#define sqliteBtreeData(pCur, offset, amt, zBuf)\ + (btCOps(pCur)->Data(pCur, offset, amt, zBuf)) +#define sqliteBtreeCloseCursor(pCur) (btCOps(pCur)->CloseCursor(pCur)) +#define sqliteBtreeGetMeta(pBt, aMeta) (btOps(pBt)->GetMeta(pBt, aMeta)) +#define sqliteBtreeUpdateMeta(pBt, aMeta) (btOps(pBt)->UpdateMeta(pBt, aMeta)) +#define sqliteBtreeIntegrityCheck(pBt, aRoot, nRoot)\ + (btOps(pBt)->IntegrityCheck(pBt, aRoot, nRoot)) +#define sqliteBtreeGetFilename(pBt) (btOps(pBt)->GetFilename(pBt)) +#define sqliteBtreeCopyFile(pBt1, pBt2) (btOps(pBt1)->Copyfile(pBt1, pBt2)) + +#ifdef SQLITE_TEST +#define sqliteBtreePageDump(pBt, pgno, recursive)\ + (btOps(pBt)->PageDump(pBt, pgno, recursive)) +#define sqliteBtreeCursorDump(pCur, aResult)\ + (btCOps(pCur)->CursorDump(pCur, aResult)) +#define sqliteBtreePager(pBt) (btOps(pBt)->Pager(pBt)) +int btree_native_byte_order; +#endif /* SQLITE_TEST */ + + +#endif /* _BTREE_H_ */ diff --git a/sqlitebrowser/sqlitebrowser/sqlite_source/btree_rb.c b/sqlitebrowser/sqlitebrowser/sqlite_source/btree_rb.c new file mode 100755 index 00000000..260ece36 --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/sqlite_source/btree_rb.c @@ -0,0 +1,1417 @@ +/* +** 2003 Feb 4 +** +** 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. +** +************************************************************************* +** $Id: btree_rb.c,v 1.1.1.1 2003-08-21 02:24:05 tabuleiro Exp $ +** +** This file implements an in-core database using Red-Black balanced +** binary trees. +** +** It was contributed to SQLite by anonymous on 2003-Feb-04 23:24:49 UTC. +*/ +#include "btree.h" +#include "sqliteInt.h" +#include + +/* +** Omit this whole file if the SQLITE_OMIT_INMEMORYDB macro is +** defined. This allows a lot of code to be omitted for installations +** that do not need it. +*/ +#ifndef SQLITE_OMIT_INMEMORYDB + + +typedef struct BtRbTree BtRbTree; +typedef struct BtRbNode BtRbNode; +typedef struct BtRollbackOp BtRollbackOp; +typedef struct Rbtree Rbtree; +typedef struct RbtCursor RbtCursor; + +/* Forward declarations */ +static BtOps sqliteRbtreeOps; +static BtCursorOps sqliteRbtreeCursorOps; + +/* + * During each transaction (or checkpoint), a linked-list of + * "rollback-operations" is accumulated. If the transaction is rolled back, + * then the list of operations must be executed (to restore the database to + * it's state before the transaction started). If the transaction is to be + * committed, just delete the list. + * + * Each operation is represented as follows, depending on the value of eOp: + * + * ROLLBACK_INSERT -> Need to insert (pKey, pData) into table iTab. + * ROLLBACK_DELETE -> Need to delete the record (pKey) into table iTab. + * ROLLBACK_CREATE -> Need to create table iTab. + * ROLLBACK_DROP -> Need to drop table iTab. + */ +struct BtRollbackOp { + u8 eOp; + int iTab; + int nKey; + void *pKey; + int nData; + void *pData; + BtRollbackOp *pNext; +}; + +/* +** Legal values for BtRollbackOp.eOp: +*/ +#define ROLLBACK_INSERT 1 /* Insert a record */ +#define ROLLBACK_DELETE 2 /* Delete a record */ +#define ROLLBACK_CREATE 3 /* Create a table */ +#define ROLLBACK_DROP 4 /* Drop a table */ + +struct Rbtree { + BtOps *pOps; /* Function table */ + int aMetaData[SQLITE_N_BTREE_META]; + + int next_idx; /* next available table index */ + Hash tblHash; /* All created tables, by index */ + u8 isAnonymous; /* True if this Rbtree is to be deleted when closed */ + u8 eTransState; /* State of this Rbtree wrt transactions */ + + BtRollbackOp *pTransRollback; + BtRollbackOp *pCheckRollback; + BtRollbackOp *pCheckRollbackTail; +}; + +/* +** Legal values for Rbtree.eTransState. +*/ +#define TRANS_NONE 0 /* No transaction is in progress */ +#define TRANS_INTRANSACTION 1 /* A transaction is in progress */ +#define TRANS_INCHECKPOINT 2 /* A checkpoint is in progress */ +#define TRANS_ROLLBACK 3 /* We are currently rolling back a checkpoint or + * transaction. */ + +struct RbtCursor { + BtCursorOps *pOps; /* Function table */ + Rbtree *pRbtree; + BtRbTree *pTree; + int iTree; /* Index of pTree in pRbtree */ + BtRbNode *pNode; + u8 eSkip; /* Determines if next step operation is a no-op */ +}; + +/* +** Legal values for RbtCursor.eSkip. +*/ +#define SKIP_NONE 0 /* Always step the cursor */ +#define SKIP_NEXT 1 /* The next sqliteRbtreeNext() is a no-op */ +#define SKIP_PREV 2 /* The next sqliteRbtreePrevious() is a no-op */ +#define SKIP_INVALID 3 /* Calls to Next() and Previous() are invalid */ + +struct BtRbTree { + BtRbNode *pHead; /* Head of the tree, or NULL */ +}; + +struct BtRbNode { + int nKey; + void *pKey; + int nData; + void *pData; + u8 isBlack; /* true for a black node, 0 for a red node */ + BtRbNode *pParent; /* Nodes parent node, NULL for the tree head */ + BtRbNode *pLeft; /* Nodes left child, or NULL */ + BtRbNode *pRight; /* Nodes right child, or NULL */ + + int nBlackHeight; /* Only used during the red-black integrity check */ +}; + +/* Forward declarations */ +static int memRbtreeMoveto( + RbtCursor* pCur, + const void *pKey, + int nKey, + int *pRes +); +static int memRbtreeClearTable(Rbtree* tree, int n); +static int memRbtreeNext(RbtCursor* pCur, int *pRes); +static int memRbtreeLast(RbtCursor* pCur, int *pRes); +static int memRbtreePrevious(RbtCursor* pCur, int *pRes); + +/* + * The key-compare function for the red-black trees. Returns as follows: + * + * (key1 < key2) -1 + * (key1 == key2) 0 + * (key1 > key2) 1 + * + * Keys are compared using memcmp(). If one key is an exact prefix of the + * other, then the shorter key is less than the longer key. + */ +static int key_compare(void const*pKey1, int nKey1, void const*pKey2, int nKey2) +{ + int mcmp = memcmp(pKey1, pKey2, (nKey1 <= nKey2)?nKey1:nKey2); + if( mcmp == 0){ + if( nKey1 == nKey2 ) return 0; + return ((nKey1 < nKey2)?-1:1); + } + return ((mcmp>0)?1:-1); +} + +/* + * Perform the LEFT-rotate transformation on node X of tree pTree. This + * transform is part of the red-black balancing code. + * + * | | + * X Y + * / \ / \ + * a Y X c + * / \ / \ + * b c a b + * + * BEFORE AFTER + */ +static void leftRotate(BtRbTree *pTree, BtRbNode *pX) +{ + BtRbNode *pY; + BtRbNode *pb; + pY = pX->pRight; + pb = pY->pLeft; + + pY->pParent = pX->pParent; + if( pX->pParent ){ + if( pX->pParent->pLeft == pX ) pX->pParent->pLeft = pY; + else pX->pParent->pRight = pY; + } + pY->pLeft = pX; + pX->pParent = pY; + pX->pRight = pb; + if( pb ) pb->pParent = pX; + if( pTree->pHead == pX ) pTree->pHead = pY; +} + +/* + * Perform the RIGHT-rotate transformation on node X of tree pTree. This + * transform is part of the red-black balancing code. + * + * | | + * X Y + * / \ / \ + * Y c a X + * / \ / \ + * a b b c + * + * BEFORE AFTER + */ +static void rightRotate(BtRbTree *pTree, BtRbNode *pX) +{ + BtRbNode *pY; + BtRbNode *pb; + pY = pX->pLeft; + pb = pY->pRight; + + pY->pParent = pX->pParent; + if( pX->pParent ){ + if( pX->pParent->pLeft == pX ) pX->pParent->pLeft = pY; + else pX->pParent->pRight = pY; + } + pY->pRight = pX; + pX->pParent = pY; + pX->pLeft = pb; + if( pb ) pb->pParent = pX; + if( pTree->pHead == pX ) pTree->pHead = pY; +} + +/* + * A string-manipulation helper function for check_redblack_tree(). If (orig == + * NULL) a copy of val is returned. If (orig != NULL) then a copy of the * + * concatenation of orig and val is returned. The original orig is deleted + * (using sqliteFree()). + */ +static char *append_val(char * orig, char const * val) +{ + if( !orig ){ + return sqliteStrDup( val ); + } else{ + char * ret = 0; + sqliteSetString(&ret, orig, val, 0); + sqliteFree( orig ); + return ret; + } + assert(0); +} + +/* + * Append a string representation of the entire node to orig and return it. + * This is used to produce debugging information if check_redblack_tree() finds + * a problem with a red-black binary tree. + */ +static char *append_node(char * orig, BtRbNode *pNode, int indent) +{ + char buf[128]; + int i; + + for( i=0; iisBlack ){ + orig = append_val(orig, " B \n"); + }else{ + orig = append_val(orig, " R \n"); + } + orig = append_node( orig, pNode->pLeft, indent ); + orig = append_node( orig, pNode->pRight, indent ); + }else{ + orig = append_val(orig, "\n"); + } + return orig; +} + +/* + * Print a representation of a node to stdout. This function is only included + * so you can call it from within a debugger if things get really bad. It + * is not called from anyplace in the code. + */ +static void print_node(BtRbNode *pNode) +{ + char * str = append_node(0, pNode, 0); + printf(str); + + /* Suppress a warning message about print_node() being unused */ + (void)print_node; +} + +/* + * Check the following properties of the red-black tree: + * (1) - If a node is red, both of it's children are black + * (2) - Each path from a given node to a leaf (NULL) node passes thru the + * same number of black nodes + * + * If there is a problem, append a description (using append_val() ) to *msg. + */ +static void check_redblack_tree(BtRbTree * tree, char ** msg) +{ + BtRbNode *pNode; + + /* 0 -> came from parent + * 1 -> came from left + * 2 -> came from right */ + int prev_step = 0; + + pNode = tree->pHead; + while( pNode ){ + switch( prev_step ){ + case 0: + if( pNode->pLeft ){ + pNode = pNode->pLeft; + }else{ + prev_step = 1; + } + break; + case 1: + if( pNode->pRight ){ + pNode = pNode->pRight; + prev_step = 0; + }else{ + prev_step = 2; + } + break; + case 2: + /* Check red-black property (1) */ + if( !pNode->isBlack && + ( (pNode->pLeft && !pNode->pLeft->isBlack) || + (pNode->pRight && !pNode->pRight->isBlack) ) + ){ + char buf[128]; + sprintf(buf, "Red node with red child at %p\n", pNode); + *msg = append_val(*msg, buf); + *msg = append_node(*msg, tree->pHead, 0); + *msg = append_val(*msg, "\n"); + } + + /* Check red-black property (2) */ + { + int leftHeight = 0; + int rightHeight = 0; + if( pNode->pLeft ){ + leftHeight += pNode->pLeft->nBlackHeight; + leftHeight += (pNode->pLeft->isBlack?1:0); + } + if( pNode->pRight ){ + rightHeight += pNode->pRight->nBlackHeight; + rightHeight += (pNode->pRight->isBlack?1:0); + } + if( leftHeight != rightHeight ){ + char buf[128]; + sprintf(buf, "Different black-heights at %p\n", pNode); + *msg = append_val(*msg, buf); + *msg = append_node(*msg, tree->pHead, 0); + *msg = append_val(*msg, "\n"); + } + pNode->nBlackHeight = leftHeight; + } + + if( pNode->pParent ){ + if( pNode == pNode->pParent->pLeft ) prev_step = 1; + else prev_step = 2; + } + pNode = pNode->pParent; + break; + default: assert(0); + } + } +} + +/* + * Node pX has just been inserted into pTree (by code in sqliteRbtreeInsert()). + * It is possible that pX is a red node with a red parent, which is a violation + * of the red-black tree properties. This function performs rotations and + * color changes to rebalance the tree + */ +static void do_insert_balancing(BtRbTree *pTree, BtRbNode *pX) +{ + /* In the first iteration of this loop, pX points to the red node just + * inserted in the tree. If the parent of pX exists (pX is not the root + * node) and is red, then the properties of the red-black tree are + * violated. + * + * At the start of any subsequent iterations, pX points to a red node + * with a red parent. In all other respects the tree is a legal red-black + * binary tree. */ + while( pX != pTree->pHead && !pX->pParent->isBlack ){ + BtRbNode *pUncle; + BtRbNode *pGrandparent; + + /* Grandparent of pX must exist and must be black. */ + pGrandparent = pX->pParent->pParent; + assert( pGrandparent ); + assert( pGrandparent->isBlack ); + + /* Uncle of pX may or may not exist. */ + if( pX->pParent == pGrandparent->pLeft ) + pUncle = pGrandparent->pRight; + else + pUncle = pGrandparent->pLeft; + + /* If the uncle of pX exists and is red, we do the following: + * | | + * G(b) G(r) + * / \ / \ + * U(r) P(r) U(b) P(b) + * \ \ + * X(r) X(r) + * + * BEFORE AFTER + * pX is then set to G. If the parent of G is red, then the while loop + * will run again. */ + if( pUncle && !pUncle->isBlack ){ + pGrandparent->isBlack = 0; + pUncle->isBlack = 1; + pX->pParent->isBlack = 1; + pX = pGrandparent; + }else{ + + if( pX->pParent == pGrandparent->pLeft ){ + if( pX == pX->pParent->pRight ){ + /* If pX is a right-child, do the following transform, essentially + * to change pX into a left-child: + * | | + * G(b) G(b) + * / \ / \ + * P(r) U(b) X(r) U(b) + * \ / + * X(r) P(r) <-- new X + * + * BEFORE AFTER + */ + pX = pX->pParent; + leftRotate(pTree, pX); + } + + /* Do the following transform, which balances the tree :) + * | | + * G(b) P(b) + * / \ / \ + * P(r) U(b) X(r) G(r) + * / \ + * X(r) U(b) + * + * BEFORE AFTER + */ + assert( pGrandparent == pX->pParent->pParent ); + pGrandparent->isBlack = 0; + pX->pParent->isBlack = 1; + rightRotate( pTree, pGrandparent ); + + }else{ + /* This code is symetric to the illustrated case above. */ + if( pX == pX->pParent->pLeft ){ + pX = pX->pParent; + rightRotate(pTree, pX); + } + assert( pGrandparent == pX->pParent->pParent ); + pGrandparent->isBlack = 0; + pX->pParent->isBlack = 1; + leftRotate( pTree, pGrandparent ); + } + } + } + pTree->pHead->isBlack = 1; +} + +/* + * A child of pParent, which in turn had child pX, has just been removed from + * pTree (the figure below depicts the operation, Z is being removed). pParent + * or pX, or both may be NULL. + * | | + * P P + * / \ / \ + * Z X + * / \ + * X nil + * + * This function is only called if Z was black. In this case the red-black tree + * properties have been violated, and pX has an "extra black". This function + * performs rotations and color-changes to re-balance the tree. + */ +static +void do_delete_balancing(BtRbTree *pTree, BtRbNode *pX, BtRbNode *pParent) +{ + BtRbNode *pSib; + + /* TODO: Comment this code! */ + while( pX != pTree->pHead && (!pX || pX->isBlack) ){ + if( pX == pParent->pLeft ){ + pSib = pParent->pRight; + if( pSib && !(pSib->isBlack) ){ + pSib->isBlack = 1; + pParent->isBlack = 0; + leftRotate(pTree, pParent); + pSib = pParent->pRight; + } + if( !pSib ){ + pX = pParent; + }else if( + (!pSib->pLeft || pSib->pLeft->isBlack) && + (!pSib->pRight || pSib->pRight->isBlack) ) { + pSib->isBlack = 0; + pX = pParent; + }else{ + if( (!pSib->pRight || pSib->pRight->isBlack) ){ + if( pSib->pLeft ) pSib->pLeft->isBlack = 1; + pSib->isBlack = 0; + rightRotate( pTree, pSib ); + pSib = pParent->pRight; + } + pSib->isBlack = pParent->isBlack; + pParent->isBlack = 1; + if( pSib->pRight ) pSib->pRight->isBlack = 1; + leftRotate(pTree, pParent); + pX = pTree->pHead; + } + }else{ + pSib = pParent->pLeft; + if( pSib && !(pSib->isBlack) ){ + pSib->isBlack = 1; + pParent->isBlack = 0; + rightRotate(pTree, pParent); + pSib = pParent->pLeft; + } + if( !pSib ){ + pX = pParent; + }else if( + (!pSib->pLeft || pSib->pLeft->isBlack) && + (!pSib->pRight || pSib->pRight->isBlack) ){ + pSib->isBlack = 0; + pX = pParent; + }else{ + if( (!pSib->pLeft || pSib->pLeft->isBlack) ){ + if( pSib->pRight ) pSib->pRight->isBlack = 1; + pSib->isBlack = 0; + leftRotate( pTree, pSib ); + pSib = pParent->pLeft; + } + pSib->isBlack = pParent->isBlack; + pParent->isBlack = 1; + if( pSib->pLeft ) pSib->pLeft->isBlack = 1; + rightRotate(pTree, pParent); + pX = pTree->pHead; + } + } + pParent = pX->pParent; + } + if( pX ) pX->isBlack = 1; +} + +/* + * Create table n in tree pRbtree. Table n must not exist. + */ +static void btreeCreateTable(Rbtree* pRbtree, int n) +{ + BtRbTree *pNewTbl = sqliteMalloc(sizeof(BtRbTree)); + sqliteHashInsert(&pRbtree->tblHash, 0, n, pNewTbl); +} + +/* + * Log a single "rollback-op" for the given Rbtree. See comments for struct + * BtRollbackOp. + */ +static void btreeLogRollbackOp(Rbtree* pRbtree, BtRollbackOp *pRollbackOp) +{ + assert( pRbtree->eTransState == TRANS_INCHECKPOINT || + pRbtree->eTransState == TRANS_INTRANSACTION ); + if( pRbtree->eTransState == TRANS_INTRANSACTION ){ + pRollbackOp->pNext = pRbtree->pTransRollback; + pRbtree->pTransRollback = pRollbackOp; + } + if( pRbtree->eTransState == TRANS_INCHECKPOINT ){ + if( !pRbtree->pCheckRollback ){ + pRbtree->pCheckRollbackTail = pRollbackOp; + } + pRollbackOp->pNext = pRbtree->pCheckRollback; + pRbtree->pCheckRollback = pRollbackOp; + } +} + +int sqliteRbtreeOpen( + const char *zFilename, + int mode, + int nPg, + Btree **ppBtree +){ + Rbtree **ppRbtree = (Rbtree**)ppBtree; + *ppRbtree = (Rbtree *)sqliteMalloc(sizeof(Rbtree)); + sqliteHashInit(&(*ppRbtree)->tblHash, SQLITE_HASH_INT, 0); + + /* Create a binary tree for the SQLITE_MASTER table at location 2 */ + btreeCreateTable(*ppRbtree, 2); + (*ppRbtree)->next_idx = 3; + (*ppRbtree)->pOps = &sqliteRbtreeOps; + /* Set file type to 4; this is so that "attach ':memory:' as ...." does not + ** think that the database in uninitialised and refuse to attach + */ + (*ppRbtree)->aMetaData[2] = 4; + + return SQLITE_OK; +} + +/* + * Create a new table in the supplied Rbtree. Set *n to the new table number. + * Return SQLITE_OK if the operation is a success. + */ +static int memRbtreeCreateTable(Rbtree* tree, int* n) +{ + assert( tree->eTransState != TRANS_NONE ); + + *n = tree->next_idx++; + btreeCreateTable(tree, *n); + + /* Set up the rollback structure (if we are not doing this as part of a + * rollback) */ + if( tree->eTransState != TRANS_ROLLBACK ){ + BtRollbackOp *pRollbackOp = sqliteMalloc(sizeof(BtRollbackOp)); + pRollbackOp->eOp = ROLLBACK_DROP; + pRollbackOp->iTab = *n; + btreeLogRollbackOp(tree, pRollbackOp); + } + + return SQLITE_OK; +} + +/* + * Delete table n from the supplied Rbtree. + */ +static int memRbtreeDropTable(Rbtree* tree, int n) +{ + BtRbTree *pTree; + assert( tree->eTransState != TRANS_NONE ); + + memRbtreeClearTable(tree, n); + pTree = sqliteHashInsert(&tree->tblHash, 0, n, 0); + assert(pTree); + sqliteFree(pTree); + + if( tree->eTransState != TRANS_ROLLBACK ){ + BtRollbackOp *pRollbackOp = sqliteMalloc(sizeof(BtRollbackOp)); + pRollbackOp->eOp = ROLLBACK_CREATE; + pRollbackOp->iTab = n; + btreeLogRollbackOp(tree, pRollbackOp); + } + + return SQLITE_OK; +} + +static int memRbtreeKeyCompare(RbtCursor* pCur, const void *pKey, int nKey, + int nIgnore, int *pRes) +{ + assert(pCur); + + if( !pCur->pNode ) { + *pRes = -1; + } else { + if( (pCur->pNode->nKey - nIgnore) < 0 ){ + *pRes = -1; + }else{ + *pRes = key_compare(pCur->pNode->pKey, pCur->pNode->nKey-nIgnore, + pKey, nKey); + } + } + return SQLITE_OK; +} + +/* + * Get a new cursor for table iTable of the supplied Rbtree. The wrFlag + * parameter is ignored, all cursors are capable of write-operations. + * + * Note that RbtCursor.eSkip and RbtCursor.pNode both initialize to 0. + */ +static int memRbtreeCursor( + Rbtree* tree, + int iTable, + int wrFlag, + RbtCursor **ppCur +){ + assert(tree); + *ppCur = sqliteMalloc(sizeof(RbtCursor)); + (*ppCur)->pTree = sqliteHashFind(&tree->tblHash, 0, iTable); + (*ppCur)->pRbtree = tree; + (*ppCur)->iTree = iTable; + (*ppCur)->pOps = &sqliteRbtreeCursorOps; + + assert( (*ppCur)->pTree ); + return SQLITE_OK; +} + +/* + * Insert a new record into the Rbtree. The key is given by (pKey,nKey) + * and the data is given by (pData,nData). The cursor is used only to + * define what database the record should be inserted into. The cursor + * is left pointing at the new record. + * + * If the key exists already in the tree, just replace the data. + */ +static int memRbtreeInsert( + RbtCursor* pCur, + const void *pKey, + int nKey, + const void *pDataInput, + int nData +){ + void * pData; + int match; + + /* It is illegal to call sqliteRbtreeInsert() if we are + ** not in a transaction */ + assert( pCur->pRbtree->eTransState != TRANS_NONE ); + + /* Take a copy of the input data now, in case we need it for the + * replace case */ + pData = sqliteMalloc(nData); + memcpy(pData, pDataInput, nData); + + /* Move the cursor to a node near the key to be inserted. If the key already + * exists in the table, then (match == 0). In this case we can just replace + * the data associated with the entry, we don't need to manipulate the tree. + * + * If there is no exact match, then the cursor points at what would be either + * the predecessor (match == -1) or successor (match == 1) of the + * searched-for key, were it to be inserted. The new node becomes a child of + * this node. + * + * The new node is initially red. + */ + memRbtreeMoveto( pCur, pKey, nKey, &match); + if( match ){ + BtRbNode *pNode = sqliteMalloc(sizeof(BtRbNode)); + pNode->nKey = nKey; + pNode->pKey = sqliteMalloc(nKey); + memcpy(pNode->pKey, pKey, nKey); + pNode->nData = nData; + pNode->pData = pData; + if( pCur->pNode ){ + switch( match ){ + case -1: + assert( !pCur->pNode->pRight ); + pNode->pParent = pCur->pNode; + pCur->pNode->pRight = pNode; + break; + case 1: + assert( !pCur->pNode->pLeft ); + pNode->pParent = pCur->pNode; + pCur->pNode->pLeft = pNode; + break; + default: + assert(0); + } + }else{ + pCur->pTree->pHead = pNode; + } + + /* Point the cursor at the node just inserted, as per SQLite requirements */ + pCur->pNode = pNode; + + /* A new node has just been inserted, so run the balancing code */ + do_insert_balancing(pCur->pTree, pNode); + + /* Set up a rollback-op in case we have to roll this operation back */ + if( pCur->pRbtree->eTransState != TRANS_ROLLBACK ){ + BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) ); + pOp->eOp = ROLLBACK_DELETE; + pOp->iTab = pCur->iTree; + pOp->nKey = pNode->nKey; + pOp->pKey = sqliteMalloc( pOp->nKey ); + memcpy( pOp->pKey, pNode->pKey, pOp->nKey ); + btreeLogRollbackOp(pCur->pRbtree, pOp); + } + + }else{ + /* No need to insert a new node in the tree, as the key already exists. + * Just clobber the current nodes data. */ + + /* Set up a rollback-op in case we have to roll this operation back */ + if( pCur->pRbtree->eTransState != TRANS_ROLLBACK ){ + BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) ); + pOp->iTab = pCur->iTree; + pOp->nKey = pCur->pNode->nKey; + pOp->pKey = sqliteMalloc( pOp->nKey ); + memcpy( pOp->pKey, pCur->pNode->pKey, pOp->nKey ); + pOp->nData = pCur->pNode->nData; + pOp->pData = pCur->pNode->pData; + pOp->eOp = ROLLBACK_INSERT; + btreeLogRollbackOp(pCur->pRbtree, pOp); + }else{ + sqliteFree( pCur->pNode->pData ); + } + + /* Actually clobber the nodes data */ + pCur->pNode->pData = pData; + pCur->pNode->nData = nData; + } + + return SQLITE_OK; +} + +/* Move the cursor so that it points to an entry near pKey. +** Return a success code. +** +** *pRes<0 The cursor is left pointing at an entry that +** is smaller than pKey or if the table is empty +** and the cursor is therefore left point to nothing. +** +** *pRes==0 The cursor is left pointing at an entry that +** exactly matches pKey. +** +** *pRes>0 The cursor is left pointing at an entry that +** is larger than pKey. +*/ +static int memRbtreeMoveto( + RbtCursor* pCur, + const void *pKey, + int nKey, + int *pRes +){ + BtRbNode *pTmp = 0; + + pCur->pNode = pCur->pTree->pHead; + *pRes = -1; + while( pCur->pNode && *pRes ) { + *pRes = key_compare(pCur->pNode->pKey, pCur->pNode->nKey, pKey, nKey); + pTmp = pCur->pNode; + switch( *pRes ){ + case 1: /* cursor > key */ + pCur->pNode = pCur->pNode->pLeft; + break; + case -1: /* cursor < key */ + pCur->pNode = pCur->pNode->pRight; + break; + } + } + + /* If (pCur->pNode == NULL), then we have failed to find a match. Set + * pCur->pNode to pTmp, which is either NULL (if the tree is empty) or the + * last node traversed in the search. In either case the relation ship + * between pTmp and the searched for key is already stored in *pRes. pTmp is + * either the successor or predecessor of the key we tried to move to. */ + if( !pCur->pNode ) pCur->pNode = pTmp; + pCur->eSkip = SKIP_NONE; + + return SQLITE_OK; +} + + +/* +** Delete the entry that the cursor is pointing to. +** +** The cursor is left pointing at either the next or the previous +** entry. If the cursor is left pointing to the next entry, then +** the pCur->eSkip flag is set to SKIP_NEXT which forces the next call to +** sqliteRbtreeNext() to be a no-op. That way, you can always call +** sqliteRbtreeNext() after a delete and the cursor will be left +** pointing to the first entry after the deleted entry. Similarly, +** pCur->eSkip is set to SKIP_PREV is the cursor is left pointing to +** the entry prior to the deleted entry so that a subsequent call to +** sqliteRbtreePrevious() will always leave the cursor pointing at the +** entry immediately before the one that was deleted. +*/ +static int memRbtreeDelete(RbtCursor* pCur) +{ + BtRbNode *pZ; /* The one being deleted */ + BtRbNode *pChild; /* The child of the spliced out node */ + + /* It is illegal to call sqliteRbtreeDelete() if we are + ** not in a transaction */ + assert( pCur->pRbtree->eTransState != TRANS_NONE ); + + pZ = pCur->pNode; + if( !pZ ){ + return SQLITE_OK; + } + + /* If we are not currently doing a rollback, set up a rollback op for this + * deletion */ + if( pCur->pRbtree->eTransState != TRANS_ROLLBACK ){ + BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) ); + pOp->iTab = pCur->iTree; + pOp->nKey = pZ->nKey; + pOp->pKey = pZ->pKey; + pOp->nData = pZ->nData; + pOp->pData = pZ->pData; + pOp->eOp = ROLLBACK_INSERT; + btreeLogRollbackOp(pCur->pRbtree, pOp); + } + + /* First do a standard binary-tree delete (node pZ is to be deleted). How + * to do this depends on how many children pZ has: + * + * If pZ has no children or one child, then splice out pZ. If pZ has two + * children, splice out the successor of pZ and replace the key and data of + * pZ with the key and data of the spliced out successor. */ + if( pZ->pLeft && pZ->pRight ){ + BtRbNode *pTmp; + int dummy; + pCur->eSkip = SKIP_NONE; + memRbtreeNext(pCur, &dummy); + assert( dummy == 0 ); + if( pCur->pRbtree->eTransState == TRANS_ROLLBACK ){ + sqliteFree(pZ->pKey); + sqliteFree(pZ->pData); + } + pZ->pData = pCur->pNode->pData; + pZ->nData = pCur->pNode->nData; + pZ->pKey = pCur->pNode->pKey; + pZ->nKey = pCur->pNode->nKey; + pTmp = pZ; + pZ = pCur->pNode; + pCur->pNode = pTmp; + pCur->eSkip = SKIP_NEXT; + }else{ + int res; + pCur->eSkip = SKIP_NONE; + memRbtreeNext(pCur, &res); + pCur->eSkip = SKIP_NEXT; + if( res ){ + memRbtreeLast(pCur, &res); + memRbtreePrevious(pCur, &res); + pCur->eSkip = SKIP_PREV; + } + if( pCur->pRbtree->eTransState == TRANS_ROLLBACK ){ + sqliteFree(pZ->pKey); + sqliteFree(pZ->pData); + } + } + + /* pZ now points at the node to be spliced out. This block does the + * splicing. */ + { + BtRbNode **ppParentSlot = 0; + assert( !pZ->pLeft || !pZ->pRight ); /* pZ has at most one child */ + pChild = ((pZ->pLeft)?pZ->pLeft:pZ->pRight); + if( pZ->pParent ){ + assert( pZ == pZ->pParent->pLeft || pZ == pZ->pParent->pRight ); + ppParentSlot = ((pZ == pZ->pParent->pLeft) + ?&pZ->pParent->pLeft:&pZ->pParent->pRight); + *ppParentSlot = pChild; + }else{ + pCur->pTree->pHead = pChild; + } + if( pChild ) pChild->pParent = pZ->pParent; + } + + /* pZ now points at the spliced out node. pChild is the only child of pZ, or + * NULL if pZ has no children. If pZ is black, and not the tree root, then we + * will have violated the "same number of black nodes in every path to a + * leaf" property of the red-black tree. The code in do_delete_balancing() + * repairs this. */ + if( pZ->isBlack ){ + do_delete_balancing(pCur->pTree, pChild, pZ->pParent); + } + + sqliteFree(pZ); + return SQLITE_OK; +} + +/* + * Empty table n of the Rbtree. + */ +static int memRbtreeClearTable(Rbtree* tree, int n) +{ + BtRbTree *pTree; + BtRbNode *pNode; + + pTree = sqliteHashFind(&tree->tblHash, 0, n); + assert(pTree); + + pNode = pTree->pHead; + while( pNode ){ + if( pNode->pLeft ){ + pNode = pNode->pLeft; + } + else if( pNode->pRight ){ + pNode = pNode->pRight; + } + else { + BtRbNode *pTmp = pNode->pParent; + if( tree->eTransState == TRANS_ROLLBACK ){ + sqliteFree( pNode->pKey ); + sqliteFree( pNode->pData ); + }else{ + BtRollbackOp *pRollbackOp = sqliteMalloc(sizeof(BtRollbackOp)); + pRollbackOp->eOp = ROLLBACK_INSERT; + pRollbackOp->iTab = n; + pRollbackOp->nKey = pNode->nKey; + pRollbackOp->pKey = pNode->pKey; + pRollbackOp->nData = pNode->nData; + pRollbackOp->pData = pNode->pData; + btreeLogRollbackOp(tree, pRollbackOp); + } + sqliteFree( pNode ); + if( pTmp ){ + if( pTmp->pLeft == pNode ) pTmp->pLeft = 0; + else if( pTmp->pRight == pNode ) pTmp->pRight = 0; + } + pNode = pTmp; + } + } + + pTree->pHead = 0; + return SQLITE_OK; +} + +static int memRbtreeFirst(RbtCursor* pCur, int *pRes) +{ + if( pCur->pTree->pHead ){ + pCur->pNode = pCur->pTree->pHead; + while( pCur->pNode->pLeft ){ + pCur->pNode = pCur->pNode->pLeft; + } + } + if( pCur->pNode ){ + *pRes = 0; + }else{ + *pRes = 1; + } + pCur->eSkip = SKIP_NONE; + return SQLITE_OK; +} + +static int memRbtreeLast(RbtCursor* pCur, int *pRes) +{ + if( pCur->pTree->pHead ){ + pCur->pNode = pCur->pTree->pHead; + while( pCur->pNode->pRight ){ + pCur->pNode = pCur->pNode->pRight; + } + } + if( pCur->pNode ){ + *pRes = 0; + }else{ + *pRes = 1; + } + pCur->eSkip = SKIP_NONE; + return SQLITE_OK; +} + +/* +** Advance the cursor to the next entry in the database. If +** successful then set *pRes=0. If the cursor +** was already pointing to the last entry in the database before +** this routine was called, then set *pRes=1. +*/ +static int memRbtreeNext(RbtCursor* pCur, int *pRes) +{ + if( pCur->pNode && pCur->eSkip != SKIP_NEXT ){ + if( pCur->pNode->pRight ){ + pCur->pNode = pCur->pNode->pRight; + while( pCur->pNode->pLeft ) + pCur->pNode = pCur->pNode->pLeft; + }else{ + BtRbNode * pX = pCur->pNode; + pCur->pNode = pX->pParent; + while( pCur->pNode && (pCur->pNode->pRight == pX) ){ + pX = pCur->pNode; + pCur->pNode = pX->pParent; + } + } + } + pCur->eSkip = SKIP_NONE; + + if( !pCur->pNode ){ + *pRes = 1; + }else{ + *pRes = 0; + } + + return SQLITE_OK; +} + +static int memRbtreePrevious(RbtCursor* pCur, int *pRes) +{ + if( pCur->pNode && pCur->eSkip != SKIP_PREV ){ + if( pCur->pNode->pLeft ){ + pCur->pNode = pCur->pNode->pLeft; + while( pCur->pNode->pRight ) + pCur->pNode = pCur->pNode->pRight; + }else{ + BtRbNode * pX = pCur->pNode; + pCur->pNode = pX->pParent; + while( pCur->pNode && (pCur->pNode->pLeft == pX) ){ + pX = pCur->pNode; + pCur->pNode = pX->pParent; + } + } + } + pCur->eSkip = SKIP_NONE; + + if( !pCur->pNode ){ + *pRes = 1; + }else{ + *pRes = 0; + } + + return SQLITE_OK; +} + +static int memRbtreeKeySize(RbtCursor* pCur, int *pSize) +{ + if( pCur->pNode ){ + *pSize = pCur->pNode->nKey; + }else{ + *pSize = 0; + } + return SQLITE_OK; +} + +static int memRbtreeKey(RbtCursor* pCur, int offset, int amt, char *zBuf) +{ + if( !pCur->pNode ) return 0; + if( !pCur->pNode->pKey || ((amt + offset) <= pCur->pNode->nKey) ){ + memcpy(zBuf, ((char*)pCur->pNode->pKey)+offset, amt); + return amt; + }else{ + memcpy(zBuf, ((char*)pCur->pNode->pKey)+offset, pCur->pNode->nKey-offset); + return pCur->pNode->nKey-offset; + } + assert(0); +} + +static int memRbtreeDataSize(RbtCursor* pCur, int *pSize) +{ + if( pCur->pNode ){ + *pSize = pCur->pNode->nData; + }else{ + *pSize = 0; + } + return SQLITE_OK; +} + +static int memRbtreeData(RbtCursor *pCur, int offset, int amt, char *zBuf) +{ + if( !pCur->pNode ) return 0; + if( (amt + offset) <= pCur->pNode->nData ){ + memcpy(zBuf, ((char*)pCur->pNode->pData)+offset, amt); + return amt; + }else{ + memcpy(zBuf, ((char*)pCur->pNode->pData)+offset ,pCur->pNode->nData-offset); + return pCur->pNode->nData-offset; + } + assert(0); +} + +static int memRbtreeCloseCursor(RbtCursor* pCur) +{ + sqliteFree(pCur); + return SQLITE_OK; +} + +static int memRbtreeGetMeta(Rbtree* tree, int* aMeta) +{ + memcpy( aMeta, tree->aMetaData, sizeof(int) * SQLITE_N_BTREE_META ); + return SQLITE_OK; +} + +static int memRbtreeUpdateMeta(Rbtree* tree, int* aMeta) +{ + memcpy( tree->aMetaData, aMeta, sizeof(int) * SQLITE_N_BTREE_META ); + return SQLITE_OK; +} + +/* + * Check that each table in the Rbtree meets the requirements for a red-black + * binary tree. If an error is found, return an explanation of the problem in + * memory obtained from sqliteMalloc(). Parameters aRoot and nRoot are ignored. + */ +static char *memRbtreeIntegrityCheck(Rbtree* tree, int* aRoot, int nRoot) +{ + char * msg = 0; + HashElem *p; + + for(p=sqliteHashFirst(&tree->tblHash); p; p=sqliteHashNext(p)){ + BtRbTree *pTree = sqliteHashData(p); + check_redblack_tree(pTree, &msg); + } + + return msg; +} + +static int memRbtreeSetCacheSize(Rbtree* tree, int sz) +{ + return SQLITE_OK; +} + +static int memRbtreeSetSafetyLevel(Rbtree *pBt, int level){ + return SQLITE_OK; +} + +static int memRbtreeBeginTrans(Rbtree* tree) +{ + if( tree->eTransState != TRANS_NONE ) + return SQLITE_ERROR; + + assert( tree->pTransRollback == 0 ); + tree->eTransState = TRANS_INTRANSACTION; + return SQLITE_OK; +} + +/* +** Delete a linked list of BtRollbackOp structures. +*/ +static void deleteRollbackList(BtRollbackOp *pOp){ + while( pOp ){ + BtRollbackOp *pTmp = pOp->pNext; + sqliteFree(pOp->pData); + sqliteFree(pOp->pKey); + sqliteFree(pOp); + pOp = pTmp; + } +} + +static int memRbtreeCommit(Rbtree* tree){ + /* Just delete pTransRollback and pCheckRollback */ + deleteRollbackList(tree->pCheckRollback); + deleteRollbackList(tree->pTransRollback); + tree->pTransRollback = 0; + tree->pCheckRollback = 0; + tree->pCheckRollbackTail = 0; + tree->eTransState = TRANS_NONE; + return SQLITE_OK; +} + +/* + * Close the supplied Rbtree. Delete everything associated with it. + */ +static int memRbtreeClose(Rbtree* tree) +{ + HashElem *p; + memRbtreeCommit(tree); + while( (p=sqliteHashFirst(&tree->tblHash))!=0 ){ + tree->eTransState = TRANS_ROLLBACK; + memRbtreeDropTable(tree, sqliteHashKeysize(p)); + } + sqliteHashClear(&tree->tblHash); + sqliteFree(tree); + return SQLITE_OK; +} + +/* + * Execute and delete the supplied rollback-list on pRbtree. + */ +static void execute_rollback_list(Rbtree *pRbtree, BtRollbackOp *pList) +{ + BtRollbackOp *pTmp; + RbtCursor cur; + int res; + + cur.pRbtree = pRbtree; + while( pList ){ + switch( pList->eOp ){ + case ROLLBACK_INSERT: + cur.pTree = sqliteHashFind( &pRbtree->tblHash, 0, pList->iTab ); + assert(cur.pTree); + cur.iTree = pList->iTab; + cur.eSkip = SKIP_NONE; + memRbtreeInsert( &cur, pList->pKey, + pList->nKey, pList->pData, pList->nData ); + break; + case ROLLBACK_DELETE: + cur.pTree = sqliteHashFind( &pRbtree->tblHash, 0, pList->iTab ); + assert(cur.pTree); + cur.iTree = pList->iTab; + cur.eSkip = SKIP_NONE; + memRbtreeMoveto(&cur, pList->pKey, pList->nKey, &res); + assert(res == 0); + memRbtreeDelete( &cur ); + break; + case ROLLBACK_CREATE: + btreeCreateTable(pRbtree, pList->iTab); + break; + case ROLLBACK_DROP: + memRbtreeDropTable(pRbtree, pList->iTab); + break; + default: + assert(0); + } + sqliteFree(pList->pKey); + sqliteFree(pList->pData); + pTmp = pList->pNext; + sqliteFree(pList); + pList = pTmp; + } +} + +static int memRbtreeRollback(Rbtree* tree) +{ + tree->eTransState = TRANS_ROLLBACK; + execute_rollback_list(tree, tree->pCheckRollback); + execute_rollback_list(tree, tree->pTransRollback); + tree->pTransRollback = 0; + tree->pCheckRollback = 0; + tree->pCheckRollbackTail = 0; + tree->eTransState = TRANS_NONE; + return SQLITE_OK; +} + +static int memRbtreeBeginCkpt(Rbtree* tree) +{ + if( tree->eTransState != TRANS_INTRANSACTION ) + return SQLITE_ERROR; + + assert( tree->pCheckRollback == 0 ); + assert( tree->pCheckRollbackTail == 0 ); + tree->eTransState = TRANS_INCHECKPOINT; + return SQLITE_OK; +} + +static int memRbtreeCommitCkpt(Rbtree* tree) +{ + if( tree->eTransState == TRANS_INCHECKPOINT ){ + if( tree->pCheckRollback ){ + tree->pCheckRollbackTail->pNext = tree->pTransRollback; + tree->pTransRollback = tree->pCheckRollback; + tree->pCheckRollback = 0; + tree->pCheckRollbackTail = 0; + } + tree->eTransState = TRANS_INTRANSACTION; + } + return SQLITE_OK; +} + +static int memRbtreeRollbackCkpt(Rbtree* tree) +{ + if( tree->eTransState != TRANS_INCHECKPOINT ) return SQLITE_OK; + tree->eTransState = TRANS_ROLLBACK; + execute_rollback_list(tree, tree->pCheckRollback); + tree->pCheckRollback = 0; + tree->pCheckRollbackTail = 0; + tree->eTransState = TRANS_INTRANSACTION; + return SQLITE_OK; +} + +#ifdef SQLITE_TEST +static int memRbtreePageDump(Rbtree* tree, int pgno, int rec) +{ + assert(!"Cannot call sqliteRbtreePageDump"); + return SQLITE_OK; +} + +static int memRbtreeCursorDump(RbtCursor* pCur, int* aRes) +{ + assert(!"Cannot call sqliteRbtreeCursorDump"); + return SQLITE_OK; +} + +static struct Pager *memRbtreePager(Rbtree* tree) +{ + assert(!"Cannot call sqliteRbtreePager"); + return SQLITE_OK; +} +#endif + +/* +** Return the full pathname of the underlying database file. +*/ +static const char *memRbtreeGetFilename(Rbtree *pBt){ + return 0; /* A NULL return indicates there is no underlying file */ +} + +/* +** The copy file function is not implemented for the in-memory database +*/ +static int memRbtreeCopyFile(Rbtree *pBt, Rbtree *pBt2){ + return SQLITE_INTERNAL; /* Not implemented */ +} + +static BtOps sqliteRbtreeOps = { + (int(*)(Btree*)) memRbtreeClose, + (int(*)(Btree*,int)) memRbtreeSetCacheSize, + (int(*)(Btree*,int)) memRbtreeSetSafetyLevel, + (int(*)(Btree*)) memRbtreeBeginTrans, + (int(*)(Btree*)) memRbtreeCommit, + (int(*)(Btree*)) memRbtreeRollback, + (int(*)(Btree*)) memRbtreeBeginCkpt, + (int(*)(Btree*)) memRbtreeCommitCkpt, + (int(*)(Btree*)) memRbtreeRollbackCkpt, + (int(*)(Btree*,int*)) memRbtreeCreateTable, + (int(*)(Btree*,int*)) memRbtreeCreateTable, + (int(*)(Btree*,int)) memRbtreeDropTable, + (int(*)(Btree*,int)) memRbtreeClearTable, + (int(*)(Btree*,int,int,BtCursor**)) memRbtreeCursor, + (int(*)(Btree*,int*)) memRbtreeGetMeta, + (int(*)(Btree*,int*)) memRbtreeUpdateMeta, + (char*(*)(Btree*,int*,int)) memRbtreeIntegrityCheck, + (const char*(*)(Btree*)) memRbtreeGetFilename, + (int(*)(Btree*,Btree*)) memRbtreeCopyFile, + +#ifdef SQLITE_TEST + (int(*)(Btree*,int,int)) memRbtreePageDump, + (struct Pager*(*)(Btree*)) memRbtreePager +#endif +}; + +static BtCursorOps sqliteRbtreeCursorOps = { + (int(*)(BtCursor*,const void*,int,int*)) memRbtreeMoveto, + (int(*)(BtCursor*)) memRbtreeDelete, + (int(*)(BtCursor*,const void*,int,const void*,int)) memRbtreeInsert, + (int(*)(BtCursor*,int*)) memRbtreeFirst, + (int(*)(BtCursor*,int*)) memRbtreeLast, + (int(*)(BtCursor*,int*)) memRbtreeNext, + (int(*)(BtCursor*,int*)) memRbtreePrevious, + (int(*)(BtCursor*,int*)) memRbtreeKeySize, + (int(*)(BtCursor*,int,int,char*)) memRbtreeKey, + (int(*)(BtCursor*,const void*,int,int,int*)) memRbtreeKeyCompare, + (int(*)(BtCursor*,int*)) memRbtreeDataSize, + (int(*)(BtCursor*,int,int,char*)) memRbtreeData, + (int(*)(BtCursor*)) memRbtreeCloseCursor, +#ifdef SQLITE_TEST + (int(*)(BtCursor*,int*)) memRbtreeCursorDump, +#endif + +}; + +#endif /* SQLITE_OMIT_INMEMORYDB */ diff --git a/sqlitebrowser/sqlitebrowser/sqlite_source/build.c b/sqlitebrowser/sqlitebrowser/sqlite_source/build.c new file mode 100755 index 00000000..146da835 --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/sqlite_source/build.c @@ -0,0 +1,2214 @@ +/* +** 2001 September 15 +** +** 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 C code routines that are called by the SQLite parser +** when syntax rules are reduced. The routines in this file handle the +** following kinds of SQL syntax: +** +** CREATE TABLE +** DROP TABLE +** CREATE INDEX +** DROP INDEX +** creating ID lists +** BEGIN TRANSACTION +** COMMIT +** ROLLBACK +** PRAGMA +** +** $Id: build.c,v 1.1.1.1 2003-08-21 02:24:07 tabuleiro Exp $ +*/ +#include "sqliteInt.h" +#include + +/* +** This routine is called when a new SQL statement is beginning to +** be parsed. Check to see if the schema for the database needs +** to be read from the SQLITE_MASTER and SQLITE_TEMP_MASTER tables. +** If it does, then read it. +*/ +void sqliteBeginParse(Parse *pParse, int explainFlag){ + sqlite *db = pParse->db; + int i; + pParse->explain = explainFlag; + if((db->flags & SQLITE_Initialized)==0 && pParse->initFlag==0 ){ + int rc = sqliteInit(db, &pParse->zErrMsg); + if( rc!=SQLITE_OK ){ + pParse->rc = rc; + pParse->nErr++; + } + } + for(i=0; inDb; i++){ + DbClearProperty(db, i, DB_Locked); + if( !db->aDb[i].inTrans ){ + DbClearProperty(db, i, DB_Cookie); + } + } +} + +/* +** This is a fake callback procedure used when sqlite_exec() is +** invoked with a NULL callback pointer. If we pass a NULL callback +** pointer into sqliteVdbeExec() it will return at every OP_Callback, +** which we do not want it to do. So we substitute a pointer to this +** procedure in place of the NULL. +*/ +static int fakeCallback(void *NotUsed, int n, char **az1, char **az2){ + return 0; +} + +/* +** This routine is called after a single SQL statement has been +** parsed and we want to execute the VDBE code to implement +** that statement. Prior action routines should have already +** constructed VDBE code to do the work of the SQL statement. +** This routine just has to execute the VDBE code. +** +** Note that if an error occurred, it might be the case that +** no VDBE code was generated. +*/ +void sqliteExec(Parse *pParse){ + int rc = SQLITE_OK; + sqlite *db = pParse->db; + Vdbe *v = pParse->pVdbe; + int (*xCallback)(void*,int,char**,char**); + + if( sqlite_malloc_failed ) return; + xCallback = pParse->xCallback; + if( xCallback==0 && pParse->useCallback ) xCallback = fakeCallback; + if( v && pParse->nErr==0 ){ + FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0; + sqliteVdbeTrace(v, trace); + sqliteVdbeMakeReady(v, xCallback, pParse->pArg, pParse->explain); + if( pParse->useCallback ){ + if( pParse->explain ){ + rc = sqliteVdbeList(v); + db->next_cookie = db->aDb[0].schema_cookie; + }else{ + sqliteVdbeExec(v); + } + rc = sqliteVdbeFinalize(v, &pParse->zErrMsg); + if( rc ) pParse->nErr++; + pParse->pVdbe = 0; + pParse->rc = rc; + if( rc ) pParse->nErr++; + }else{ + pParse->rc = pParse->nErr ? SQLITE_ERROR : SQLITE_DONE; + } + pParse->colNamesSet = 0; + }else if( pParse->useCallback==0 ){ + pParse->rc = SQLITE_ERROR; + } + pParse->nTab = 0; + pParse->nMem = 0; + pParse->nSet = 0; + pParse->nAgg = 0; +} + +/* +** Locate the in-memory structure that describes +** a particular database table given the name +** of that table and (optionally) the name of the database +** containing the table. Return NULL if not found. +** +** If zDatabase is 0, all databases are searched for the +** table and the first matching table is returned. (No checking +** for duplicate table names is done.) The search order is +** TEMP first, then MAIN, then any auxiliary databases added +** using the ATTACH command. +** +** See also sqliteLocateTable(). +*/ +Table *sqliteFindTable(sqlite *db, const char *zName, const char *zDatabase){ + Table *p = 0; + int i; + for(i=0; inDb; i++){ + int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ + if( zDatabase!=0 && sqliteStrICmp(zDatabase, db->aDb[j].zName) ) continue; + p = sqliteHashFind(&db->aDb[j].tblHash, zName, strlen(zName)+1); + if( p ) break; + } + return p; +} + +/* +** Locate the in-memory structure that describes +** a particular database table given the name +** of that table and (optionally) the name of the database +** containing the table. Return NULL if not found. +** Also leave an error message in pParse->zErrMsg. +** +** The difference between this routine and sqliteFindTable() +** is that this routine leaves an error message in pParse->zErrMsg +** where sqliteFindTable() does not. +*/ +Table *sqliteLocateTable(Parse *pParse, const char *zName, const char *zDbase){ + Table *p; + + p = sqliteFindTable(pParse->db, zName, zDbase); + if( p==0 ){ + if( zDbase ){ + sqliteErrorMsg(pParse, "no such table: %s.%s", zDbase, zName); + }else if( sqliteFindTable(pParse->db, zName, 0)!=0 ){ + sqliteErrorMsg(pParse, "table \"%s\" is not in database \"%s\"", + zName, zDbase); + }else{ + sqliteErrorMsg(pParse, "no such table: %s", zName); + } + } + return p; +} + +/* +** Locate the in-memory structure that describes +** a particular index given the name of that index +** and the name of the database that contains the index. +** Return NULL if not found. +** +** If zDatabase is 0, all databases are searched for the +** table and the first matching index is returned. (No checking +** for duplicate index names is done.) The search order is +** TEMP first, then MAIN, then any auxiliary databases added +** using the ATTACH command. +*/ +Index *sqliteFindIndex(sqlite *db, const char *zName, const char *zDb){ + Index *p = 0; + int i; + for(i=0; inDb; i++){ + int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ + if( zDb && sqliteStrICmp(zDb, db->aDb[j].zName) ) continue; + p = sqliteHashFind(&db->aDb[j].idxHash, zName, strlen(zName)+1); + if( p ) break; + } + return p; +} + +/* +** Remove the given index from the index hash table, and free +** its memory structures. +** +** The index is removed from the database hash tables but +** it is not unlinked from the Table that it indexes. +** Unlinking from the Table must be done by the calling function. +*/ +static void sqliteDeleteIndex(sqlite *db, Index *p){ + Index *pOld; + + assert( db!=0 && p->zName!=0 ); + pOld = sqliteHashInsert(&db->aDb[p->iDb].idxHash, p->zName, + strlen(p->zName)+1, 0); + if( pOld!=0 && pOld!=p ){ + sqliteHashInsert(&db->aDb[p->iDb].idxHash, pOld->zName, + strlen(pOld->zName)+1, pOld); + } + sqliteFree(p); +} + +/* +** Unlink the given index from its table, then remove +** the index from the index hash table and free its memory +** structures. +*/ +void sqliteUnlinkAndDeleteIndex(sqlite *db, Index *pIndex){ + if( pIndex->pTable->pIndex==pIndex ){ + pIndex->pTable->pIndex = pIndex->pNext; + }else{ + Index *p; + for(p=pIndex->pTable->pIndex; p && p->pNext!=pIndex; p=p->pNext){} + if( p && p->pNext==pIndex ){ + p->pNext = pIndex->pNext; + } + } + sqliteDeleteIndex(db, pIndex); +} + +/* +** Erase all schema information from the in-memory hash tables of +** database connection. This routine is called to reclaim memory +** before the connection closes. It is also called during a rollback +** if there were schema changes during the transaction. +** +** If iDb<=0 then reset the internal schema tables for all database +** files. If iDb>=2 then reset the internal schema for only the +** single file indicates. +*/ +void sqliteResetInternalSchema(sqlite *db, int iDb){ + HashElem *pElem; + Hash temp1; + Hash temp2; + int i, j; + + assert( iDb>=0 && iDbnDb ); + db->flags &= ~SQLITE_Initialized; + for(i=iDb; inDb; i++){ + Db *pDb = &db->aDb[i]; + temp1 = pDb->tblHash; + temp2 = pDb->trigHash; + sqliteHashInit(&pDb->trigHash, SQLITE_HASH_STRING, 0); + sqliteHashClear(&pDb->aFKey); + sqliteHashClear(&pDb->idxHash); + for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){ + Trigger *pTrigger = sqliteHashData(pElem); + sqliteDeleteTrigger(pTrigger); + } + sqliteHashClear(&temp2); + sqliteHashInit(&pDb->tblHash, SQLITE_HASH_STRING, 0); + for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){ + Table *pTab = sqliteHashData(pElem); + sqliteDeleteTable(db, pTab); + } + sqliteHashClear(&temp1); + 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 + ** 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. + */ + for(i=j=2; inDb; i++){ + if( db->aDb[i].pBt==0 ){ + sqliteFree(db->aDb[i].zName); + db->aDb[i].zName = 0; + continue; + } + if( jaDb[j] = db->aDb[i]; + } + j++; + } + memset(&db->aDb[j], 0, (db->nDb-j)*sizeof(db->aDb[j])); + db->nDb = j; + if( db->nDb<=2 && db->aDb!=db->aDbStatic ){ + memcpy(db->aDbStatic, db->aDb, 2*sizeof(db->aDb[0])); + sqliteFree(db->aDb); + db->aDb = db->aDbStatic; + } +} + +/* +** This routine is called whenever a rollback occurs. If there were +** schema changes during the transaction, then we have to reset the +** internal hash tables and reload them from disk. +*/ +void sqliteRollbackInternalChanges(sqlite *db){ + if( db->flags & SQLITE_InternChanges ){ + sqliteResetInternalSchema(db, 0); + } +} + +/* +** This routine is called when a commit occurs. +*/ +void sqliteCommitInternalChanges(sqlite *db){ + db->aDb[0].schema_cookie = db->next_cookie; + db->flags &= ~SQLITE_InternChanges; +} + +/* +** Remove the memory data structures associated with the given +** Table. No changes are made to disk by this routine. +** +** This routine just deletes the data structure. It does not unlink +** the table data structure from the hash table. Nor does it remove +** foreign keys from the sqlite.aFKey hash table. But it does destroy +** memory structures of the indices and foreign keys associated with +** the table. +** +** Indices associated with the table are unlinked from the "db" +** data structure if db!=NULL. If db==NULL, indices attached to +** the table are deleted, but it is assumed they have already been +** unlinked. +*/ +void sqliteDeleteTable(sqlite *db, Table *pTable){ + int i; + Index *pIndex, *pNext; + FKey *pFKey, *pNextFKey; + + if( pTable==0 ) return; + + /* Delete all indices associated with this table + */ + for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){ + pNext = pIndex->pNext; + assert( pIndex->iDb==pTable->iDb || (pTable->iDb==0 && pIndex->iDb==1) ); + sqliteDeleteIndex(db, pIndex); + } + + /* Delete all foreign keys associated with this table. The keys + ** should have already been unlinked from the db->aFKey hash table + */ + for(pFKey=pTable->pFKey; pFKey; pFKey=pNextFKey){ + pNextFKey = pFKey->pNextFrom; + assert( pTable->iDbnDb ); + assert( sqliteHashFind(&db->aDb[pTable->iDb].aFKey, + pFKey->zTo, strlen(pFKey->zTo)+1)!=pFKey ); + sqliteFree(pFKey); + } + + /* Delete the Table structure itself. + */ + for(i=0; inCol; i++){ + sqliteFree(pTable->aCol[i].zName); + sqliteFree(pTable->aCol[i].zDflt); + sqliteFree(pTable->aCol[i].zType); + } + sqliteFree(pTable->zName); + sqliteFree(pTable->aCol); + sqliteSelectDelete(pTable->pSelect); + sqliteFree(pTable); +} + +/* +** Unlink the given table from the hash tables and the delete the +** table structure with all its indices and foreign keys. +*/ +static void sqliteUnlinkAndDeleteTable(sqlite *db, Table *p){ + Table *pOld; + FKey *pF1, *pF2; + int i = p->iDb; + assert( db!=0 ); + pOld = sqliteHashInsert(&db->aDb[i].tblHash, p->zName, strlen(p->zName)+1, 0); + assert( pOld==0 || pOld==p ); + for(pF1=p->pFKey; pF1; pF1=pF1->pNextFrom){ + int nTo = strlen(pF1->zTo) + 1; + pF2 = sqliteHashFind(&db->aDb[i].aFKey, pF1->zTo, nTo); + if( pF2==pF1 ){ + sqliteHashInsert(&db->aDb[i].aFKey, pF1->zTo, nTo, pF1->pNextTo); + }else{ + while( pF2 && pF2->pNextTo!=pF1 ){ pF2=pF2->pNextTo; } + if( pF2 ){ + pF2->pNextTo = pF1->pNextTo; + } + } + } + sqliteDeleteTable(db, p); +} + +/* +** Construct the name of a user table or index from a token. +** +** Space to hold the name is obtained from sqliteMalloc() and must +** be freed by the calling function. +*/ +char *sqliteTableNameFromToken(Token *pName){ + char *zName = sqliteStrNDup(pName->z, pName->n); + sqliteDequote(zName); + return zName; +} + +/* +** Generate code to open the appropriate master table. The table +** opened will be SQLITE_MASTER for persistent tables and +** SQLITE_TEMP_MASTER for temporary tables. The table is opened +** on cursor 0. +*/ +void sqliteOpenMasterTable(Vdbe *v, int isTemp){ + sqliteVdbeAddOp(v, OP_Integer, isTemp, 0); + sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2); +} + +/* +** Begin constructing a new table representation in memory. This is +** the first of several action routines that get called in response +** to a CREATE TABLE statement. In particular, this routine is called +** after seeing tokens "CREATE" and "TABLE" and the table name. The +** pStart token is the CREATE and pName is the table name. The isTemp +** flag is true if the table should be stored in the auxiliary database +** file instead of in the main database file. This is normally the case +** when the "TEMP" or "TEMPORARY" keyword occurs in between +** CREATE and TABLE. +** +** The new table record is initialized and put in pParse->pNewTable. +** As more of the CREATE TABLE statement is parsed, additional action +** routines will be called to add more information to this record. +** At the end of the CREATE TABLE statement, the sqliteEndTable() routine +** is called to complete the construction of the new table record. +*/ +void sqliteStartTable( + Parse *pParse, /* Parser context */ + Token *pStart, /* The "CREATE" token */ + Token *pName, /* Name of table or view to create */ + int isTemp, /* True if this is a TEMP table */ + int isView /* True if this is a VIEW */ +){ + Table *pTable; + Index *pIdx; + char *zName; + sqlite *db = pParse->db; + Vdbe *v; + int iDb; + + pParse->sFirstToken = *pStart; + zName = sqliteTableNameFromToken(pName); + if( zName==0 ) return; + if( pParse->iDb==1 ) isTemp = 1; +#ifndef SQLITE_OMIT_AUTHORIZATION + assert( (isTemp & 1)==isTemp ); + { + int code; + char *zDb = isTemp ? "temp" : "main"; + if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){ + sqliteFree(zName); + return; + } + if( isView ){ + if( isTemp ){ + code = SQLITE_CREATE_TEMP_VIEW; + }else{ + code = SQLITE_CREATE_VIEW; + } + }else{ + if( isTemp ){ + code = SQLITE_CREATE_TEMP_TABLE; + }else{ + code = SQLITE_CREATE_TABLE; + } + } + if( sqliteAuthCheck(pParse, code, zName, 0, zDb) ){ + sqliteFree(zName); + return; + } + } +#endif + + + /* Before trying to create a temporary table, make sure the Btree for + ** holding temporary tables is open. + */ + if( isTemp && db->aDb[1].pBt==0 && !pParse->explain ){ + int rc = sqliteBtreeFactory(db, 0, 0, MAX_PAGES, &db->aDb[1].pBt); + if( rc!=SQLITE_OK ){ + sqliteSetString(&pParse->zErrMsg, "unable to open a temporary database " + "file for storing temporary tables", 0); + pParse->nErr++; + return; + } + if( db->flags & SQLITE_InTrans ){ + rc = sqliteBtreeBeginTrans(db->aDb[1].pBt); + if( rc!=SQLITE_OK ){ + sqliteSetNString(&pParse->zErrMsg, "unable to get a write lock on " + "the temporary database file", 0); + pParse->nErr++; + return; + } + } + } + + /* Make sure the new table name does not collide with an existing + ** index or table name. Issue an error message if it does. + ** + ** If we are re-reading the sqlite_master table because of a schema + ** change and a new permanent table is found whose name collides with + ** an existing temporary table, that is not an error. + */ + pTable = sqliteFindTable(db, zName, 0); + iDb = isTemp ? 1 : pParse->iDb; + if( pTable!=0 && (pTable->iDb==iDb || !pParse->initFlag) ){ + sqliteSetNString(&pParse->zErrMsg, "table ", 0, pName->z, pName->n, + " already exists", 0, 0); + sqliteFree(zName); + pParse->nErr++; + return; + } + if( (pIdx = sqliteFindIndex(db, zName, 0))!=0 && + (pIdx->iDb==0 || !pParse->initFlag) ){ + sqliteSetString(&pParse->zErrMsg, "there is already an index named ", + zName, 0); + sqliteFree(zName); + pParse->nErr++; + return; + } + pTable = sqliteMalloc( sizeof(Table) ); + if( pTable==0 ){ + sqliteFree(zName); + return; + } + pTable->zName = zName; + pTable->nCol = 0; + pTable->aCol = 0; + pTable->iPKey = -1; + pTable->pIndex = 0; + pTable->iDb = iDb; + if( pParse->pNewTable ) sqliteDeleteTable(db, pParse->pNewTable); + pParse->pNewTable = pTable; + + /* Begin generating the code that will insert the table record into + ** the SQLITE_MASTER table. Note in particular that we must go ahead + ** and allocate the record number for the table entry now. Before any + ** PRIMARY KEY or UNIQUE keywords are parsed. Those keywords will cause + ** indices to be created and the table record must come before the + ** indices. Hence, the record number for the table must be allocated + ** now. + */ + if( !pParse->initFlag && (v = sqliteGetVdbe(pParse))!=0 ){ + sqliteBeginWriteOperation(pParse, 0, isTemp); + if( !isTemp ){ + sqliteVdbeAddOp(v, OP_Integer, db->file_format, 0); + sqliteVdbeAddOp(v, OP_SetCookie, 0, 1); + } + sqliteOpenMasterTable(v, isTemp); + sqliteVdbeAddOp(v, OP_NewRecno, 0, 0); + sqliteVdbeAddOp(v, OP_Dup, 0, 0); + sqliteVdbeAddOp(v, OP_String, 0, 0); + sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0); + } +} + +/* +** Add a new column to the table currently being constructed. +** +** The parser calls this routine once for each column declaration +** in a CREATE TABLE statement. sqliteStartTable() gets called +** first to get things going. Then this routine is called for each +** column. +*/ +void sqliteAddColumn(Parse *pParse, Token *pName){ + Table *p; + int i; + char *z = 0; + Column *pCol; + if( (p = pParse->pNewTable)==0 ) return; + sqliteSetNString(&z, pName->z, pName->n, 0); + if( z==0 ) return; + sqliteDequote(z); + for(i=0; inCol; i++){ + if( sqliteStrICmp(z, p->aCol[i].zName)==0 ){ + sqliteSetString(&pParse->zErrMsg, "duplicate column name: ", z, 0); + pParse->nErr++; + sqliteFree(z); + return; + } + } + if( (p->nCol & 0x7)==0 ){ + Column *aNew; + aNew = sqliteRealloc( p->aCol, (p->nCol+8)*sizeof(p->aCol[0])); + if( aNew==0 ) return; + p->aCol = aNew; + } + pCol = &p->aCol[p->nCol]; + memset(pCol, 0, sizeof(p->aCol[0])); + pCol->zName = z; + pCol->sortOrder = SQLITE_SO_NUM; + p->nCol++; +} + +/* +** This routine is called by the parser while in the middle of +** parsing a CREATE TABLE statement. A "NOT NULL" constraint has +** been seen on a column. This routine sets the notNull flag on +** the column currently under construction. +*/ +void sqliteAddNotNull(Parse *pParse, int onError){ + Table *p; + int i; + if( (p = pParse->pNewTable)==0 ) return; + i = p->nCol-1; + if( i>=0 ) p->aCol[i].notNull = onError; +} + +/* +** This routine is called by the parser while in the middle of +** parsing a CREATE TABLE statement. The pFirst token is the first +** token in the sequence of tokens that describe the type of the +** column currently under construction. pLast is the last token +** in the sequence. Use this information to construct a string +** that contains the typename of the column and store that string +** in zType. +*/ +void sqliteAddColumnType(Parse *pParse, Token *pFirst, Token *pLast){ + Table *p; + int i, j; + int n; + char *z, **pz; + Column *pCol; + if( (p = pParse->pNewTable)==0 ) return; + i = p->nCol-1; + if( i<0 ) return; + pCol = &p->aCol[i]; + pz = &pCol->zType; + n = pLast->n + Addr(pLast->z) - Addr(pFirst->z); + sqliteSetNString(pz, pFirst->z, n, 0); + z = *pz; + if( z==0 ) return; + for(i=j=0; z[i]; i++){ + int c = z[i]; + if( isspace(c) ) continue; + z[j++] = c; + } + z[j] = 0; + if( pParse->db->file_format>=4 ){ + pCol->sortOrder = sqliteCollateType(z, n); + }else{ + pCol->sortOrder = SQLITE_SO_NUM; + } +} + +/* +** The given token is the default value for the last column added to +** the table currently under construction. If "minusFlag" is true, it +** means the value token was preceded by a minus sign. +** +** This routine is called by the parser while in the middle of +** parsing a CREATE TABLE statement. +*/ +void sqliteAddDefaultValue(Parse *pParse, Token *pVal, int minusFlag){ + Table *p; + int i; + char **pz; + if( (p = pParse->pNewTable)==0 ) return; + i = p->nCol-1; + if( i<0 ) return; + pz = &p->aCol[i].zDflt; + if( minusFlag ){ + sqliteSetNString(pz, "-", 1, pVal->z, pVal->n, 0); + }else{ + sqliteSetNString(pz, pVal->z, pVal->n, 0); + } + sqliteDequote(*pz); +} + +/* +** Designate the PRIMARY KEY for the table. pList is a list of names +** of columns that form the primary key. If pList is NULL, then the +** most recently added column of the table is the primary key. +** +** A table can have at most one primary key. If the table already has +** a primary key (and this is the second primary key) then create an +** error. +** +** If the PRIMARY KEY is on a single column whose datatype is INTEGER, +** then we will try to use that column as the row id. (Exception: +** For backwards compatibility with older databases, do not do this +** if the file format version number is less than 1.) Set the Table.iPKey +** field of the table under construction to be the index of the +** INTEGER PRIMARY KEY column. Table.iPKey is set to -1 if there is +** no INTEGER PRIMARY KEY. +** +** If the key is not an INTEGER PRIMARY KEY, then create a unique +** index for the key. No index is created for INTEGER PRIMARY KEYs. +*/ +void sqliteAddPrimaryKey(Parse *pParse, IdList *pList, int onError){ + Table *pTab = pParse->pNewTable; + char *zType = 0; + int iCol = -1; + if( pTab==0 ) goto primary_key_exit; + if( pTab->hasPrimKey ){ + sqliteSetString(&pParse->zErrMsg, "table \"", pTab->zName, + "\" has more than one primary key", 0); + pParse->nErr++; + goto primary_key_exit; + } + pTab->hasPrimKey = 1; + if( pList==0 ){ + iCol = pTab->nCol - 1; + }else if( pList->nId==1 ){ + for(iCol=0; iColnCol; iCol++){ + if( sqliteStrICmp(pList->a[0].zName, pTab->aCol[iCol].zName)==0 ) break; + } + } + if( iCol>=0 && iColnCol ){ + zType = pTab->aCol[iCol].zType; + } + if( pParse->db->file_format>=1 && + zType && sqliteStrICmp(zType, "INTEGER")==0 ){ + pTab->iPKey = iCol; + pTab->keyConf = onError; + }else{ + sqliteCreateIndex(pParse, 0, 0, pList, onError, 0, 0, 0); + pList = 0; + } + +primary_key_exit: + sqliteIdListDelete(pList); + return; +} + +/* +** Return the appropriate collating type given a type name. +** +** The collation type is text (SQLITE_SO_TEXT) if the type +** name contains the character stream "text" or "blob" or +** "clob". Any other type name is collated as numeric +** (SQLITE_SO_NUM). +*/ +int sqliteCollateType(const char *zType, int nType){ + int i; + for(i=0; i=2 && sqliteStrNICmp(&zType[i-2],"text",4)==0 ){ + return SQLITE_SO_TEXT; + } + break; + } + default: { + break; + } + } + } + return SQLITE_SO_NUM; +} + +/* +** This routine is called by the parser while in the middle of +** parsing a CREATE TABLE statement. A "COLLATE" clause has +** been seen on a column. This routine sets the Column.sortOrder on +** the column currently under construction. +*/ +void sqliteAddCollateType(Parse *pParse, int collType){ + Table *p; + int i; + if( (p = pParse->pNewTable)==0 ) return; + i = p->nCol-1; + if( i>=0 ) p->aCol[i].sortOrder = collType; +} + +/* +** Come up with a new random value for the schema cookie. Make sure +** the new value is different from the old. +** +** The schema cookie is used to determine when the schema for the +** database changes. After each schema change, the cookie value +** changes. When a process first reads the schema it records the +** cookie. Thereafter, whenever it goes to access the database, +** it checks the cookie to make sure the schema has not changed +** since it was last read. +** +** This plan is not completely bullet-proof. It is possible for +** the schema to change multiple times and for the cookie to be +** set back to prior value. But schema changes are infrequent +** and the probability of hitting the same cookie value is only +** 1 chance in 2^32. So we're safe enough. +*/ +void sqliteChangeCookie(sqlite *db, Vdbe *v){ + if( db->next_cookie==db->aDb[0].schema_cookie ){ + db->next_cookie = db->aDb[0].schema_cookie + sqliteRandomByte() + 1; + db->flags |= SQLITE_InternChanges; + sqliteVdbeAddOp(v, OP_Integer, db->next_cookie, 0); + sqliteVdbeAddOp(v, OP_SetCookie, 0, 0); + } +} + +/* +** Measure the number of characters needed to output the given +** identifier. The number returned includes any quotes used +** but does not include the null terminator. +*/ +static int identLength(const char *z){ + int n; + int needQuote = 0; + for(n=0; *z; n++, z++){ + if( *z=='\'' ){ n++; needQuote=1; } + } + return n + needQuote*2; +} + +/* +** Write an identifier onto the end of the given string. Add +** quote characters as needed. +*/ +static void identPut(char *z, int *pIdx, char *zIdent){ + int i, j, needQuote; + i = *pIdx; + for(j=0; zIdent[j]; j++){ + if( !isalnum(zIdent[j]) && zIdent[j]!='_' ) break; + } + needQuote = zIdent[j]!=0 || isdigit(zIdent[0]) + || sqliteKeywordCode(zIdent, j)!=TK_ID; + if( needQuote ) z[i++] = '\''; + for(j=0; zIdent[j]; j++){ + z[i++] = zIdent[j]; + if( zIdent[j]=='\'' ) z[i++] = '\''; + } + if( needQuote ) z[i++] = '\''; + z[i] = 0; + *pIdx = i; +} + +/* +** Generate a CREATE TABLE statement appropriate for the given +** 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){ + int i, k, n; + char *zStmt; + char *zSep, *zSep2, *zEnd; + n = 0; + for(i=0; inCol; i++){ + n += identLength(p->aCol[i].zName); + } + n += identLength(p->zName); + if( n<40 ){ + zSep = ""; + zSep2 = ","; + zEnd = ")"; + }else{ + zSep = "\n "; + zSep2 = ",\n "; + zEnd = "\n)"; + } + n += 35 + 6*p->nCol; + zStmt = sqliteMallocRaw( n ); + if( zStmt==0 ) return 0; + strcpy(zStmt, p->iDb==1 ? "CREATE TEMP TABLE " : "CREATE TABLE "); + k = strlen(zStmt); + identPut(zStmt, &k, p->zName); + zStmt[k++] = '('; + for(i=0; inCol; i++){ + strcpy(&zStmt[k], zSep); + k += strlen(&zStmt[k]); + zSep = zSep2; + identPut(zStmt, &k, p->aCol[i].zName); + } + strcpy(&zStmt[k], zEnd); + return zStmt; +} + +/* +** This routine is called to report the final ")" that terminates +** a CREATE TABLE statement. +** +** The table structure that other action routines have been building +** is added to the internal hash tables, assuming no errors have +** occurred. +** +** An entry for the table is made in the master table on disk, +** unless this is a temporary table or initFlag==1. When initFlag==1, +** it means we are reading the sqlite_master table because we just +** connected to the database or because the sqlite_master table has +** recently changes, so the entry for this table already exists in +** the sqlite_master table. We do not want to create it again. +** +** If the pSelect argument is not NULL, it means that this routine +** was called to create a table generated from a +** "CREATE TABLE ... AS SELECT ..." statement. The column names of +** the new table will match the result set of the SELECT. +*/ +void sqliteEndTable(Parse *pParse, Token *pEnd, Select *pSelect){ + Table *p; + sqlite *db = pParse->db; + + if( (pEnd==0 && pSelect==0) || pParse->nErr || sqlite_malloc_failed ) return; + p = pParse->pNewTable; + if( p==0 ) return; + + /* If the table is generated from a SELECT, then construct the + ** list of columns and the text of the table. + */ + if( pSelect ){ + Table *pSelTab = sqliteResultSetOfSelect(pParse, 0, pSelect); + if( pSelTab==0 ) return; + assert( p->aCol==0 ); + p->nCol = pSelTab->nCol; + p->aCol = pSelTab->aCol; + pSelTab->nCol = 0; + pSelTab->aCol = 0; + sqliteDeleteTable(0, pSelTab); + } + + /* If the initFlag 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 + ** for the table from the pParse->newTnum field. (The page number + ** should have been put there by the sqliteOpenCb routine.) + */ + if( pParse->initFlag ){ + p->tnum = pParse->newTnum; + } + + /* If not initializing, then create a record for the new table + ** in the SQLITE_MASTER table of the database. The record number + ** for the new table entry should already be on the stack. + ** + ** If this is a TEMPORARY table, write the entry into the auxiliary + ** file instead of into the main database file. + */ + if( !pParse->initFlag ){ + int n; + Vdbe *v; + + v = sqliteGetVdbe(pParse); + if( v==0 ) return; + if( p->pSelect==0 ){ + /* A regular table */ + sqliteVdbeAddOp(v, OP_CreateTable, 0, p->iDb); + sqliteVdbeChangeP3(v, -1, (char *)&p->tnum, P3_POINTER); + }else{ + /* A view */ + sqliteVdbeAddOp(v, OP_Integer, 0, 0); + } + p->tnum = 0; + sqliteVdbeAddOp(v, OP_Pull, 1, 0); + sqliteVdbeAddOp(v, OP_String, 0, 0); + if( p->pSelect==0 ){ + sqliteVdbeChangeP3(v, -1, "table", P3_STATIC); + }else{ + sqliteVdbeChangeP3(v, -1, "view", P3_STATIC); + } + sqliteVdbeAddOp(v, OP_String, 0, 0); + sqliteVdbeChangeP3(v, -1, p->zName, P3_STATIC); + sqliteVdbeAddOp(v, OP_String, 0, 0); + sqliteVdbeChangeP3(v, -1, p->zName, P3_STATIC); + sqliteVdbeAddOp(v, OP_Dup, 4, 0); + sqliteVdbeAddOp(v, OP_String, 0, 0); + if( pSelect ){ + char *z = createTableStmt(p); + n = z ? strlen(z) : 0; + sqliteVdbeChangeP3(v, -1, z, n); + sqliteFree(z); + }else{ + assert( pEnd!=0 ); + n = Addr(pEnd->z) - Addr(pParse->sFirstToken.z) + 1; + sqliteVdbeChangeP3(v, -1, pParse->sFirstToken.z, n); + } + sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0); + sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0); + if( !p->iDb ){ + sqliteChangeCookie(db, v); + } + sqliteVdbeAddOp(v, OP_Close, 0, 0); + if( pSelect ){ + sqliteVdbeAddOp(v, OP_Integer, p->iDb, 0); + sqliteVdbeAddOp(v, OP_OpenWrite, 1, 0); + pParse->nTab = 2; + sqliteSelect(pParse, pSelect, SRT_Table, 1, 0, 0, 0); + } + sqliteEndWriteOperation(pParse); + } + + /* Add the table to the in-memory representation of the database. + */ + if( pParse->explain==0 && pParse->nErr==0 ){ + Table *pOld; + FKey *pFKey; + pOld = sqliteHashInsert(&db->aDb[p->iDb].tblHash, + p->zName, strlen(p->zName)+1, p); + if( pOld ){ + assert( p==pOld ); /* Malloc must have failed inside HashInsert() */ + return; + } + for(pFKey=p->pFKey; pFKey; pFKey=pFKey->pNextFrom){ + int nTo = strlen(pFKey->zTo) + 1; + pFKey->pNextTo = sqliteHashFind(&db->aDb[p->iDb].aFKey, pFKey->zTo, nTo); + sqliteHashInsert(&db->aDb[p->iDb].aFKey, pFKey->zTo, nTo, pFKey); + } + pParse->pNewTable = 0; + db->nTable++; + db->flags |= SQLITE_InternChanges; + } +} + +/* +** The parser calls this routine in order to create a new VIEW +*/ +void sqliteCreateView( + Parse *pParse, /* The parsing context */ + Token *pBegin, /* The CREATE token that begins the statement */ + Token *pName, /* The token that holds the name of the view */ + Select *pSelect, /* A SELECT statement that will become the new view */ + int isTemp /* TRUE for a TEMPORARY view */ +){ + Table *p; + int n; + const char *z; + Token sEnd; + DbFixer sFix; + + sqliteStartTable(pParse, pBegin, pName, isTemp, 1); + p = pParse->pNewTable; + if( p==0 || pParse->nErr ){ + sqliteSelectDelete(pSelect); + return; + } + if( sqliteFixInit(&sFix, pParse, p->iDb, "view", pName) + && sqliteFixSelect(&sFix, pSelect) + ){ + sqliteSelectDelete(pSelect); + return; + } + + /* Make a copy of the entire SELECT statement that defines the view. + ** This will force all the Expr.token.z values to be dynamically + ** allocated rather than point to the input string - which means that + ** they will persist after the current sqlite_exec() call returns. + */ + p->pSelect = sqliteSelectDup(pSelect); + sqliteSelectDelete(pSelect); + if( !pParse->initFlag ){ + sqliteViewGetColumnNames(pParse, p); + } + + /* Locate the end of the CREATE VIEW statement. Make sEnd point to + ** the end. + */ + sEnd = pParse->sLastToken; + if( sEnd.z[0]!=0 && sEnd.z[0]!=';' ){ + sEnd.z += sEnd.n; + } + sEnd.n = 0; + n = ((int)sEnd.z) - (int)pBegin->z; + z = pBegin->z; + while( n>0 && (z[n-1]==';' || isspace(z[n-1])) ){ n--; } + sEnd.z = &z[n-1]; + sEnd.n = 1; + + /* Use sqliteEndTable() to add the view to the SQLITE_MASTER table */ + sqliteEndTable(pParse, &sEnd, 0); + return; +} + +/* +** The Table structure pTable is really a VIEW. Fill in the names of +** the columns of the view in the pTable structure. Return the number +** of errors. If an error is seen leave an error message in pPare->zErrMsg. +*/ +int sqliteViewGetColumnNames(Parse *pParse, Table *pTable){ + ExprList *pEList; + Select *pSel; + Table *pSelTab; + int nErr = 0; + + assert( pTable ); + + /* A positive nCol means the columns names for this view are + ** already known. + */ + if( pTable->nCol>0 ) return 0; + + /* A negative nCol is a special marker meaning that we are currently + ** trying to compute the column names. If we enter this routine with + ** a negative nCol, it means two or more views form a loop, like this: + ** + ** CREATE VIEW one AS SELECT * FROM two; + ** CREATE VIEW two AS SELECT * FROM one; + ** + ** 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( pTable->nCol<0 ){ + sqliteSetString(&pParse->zErrMsg, "view ", pTable->zName, + " is circularly defined", 0); + pParse->nErr++; + return 1; + } + + /* If we get this far, it means we need to compute the table names. + */ + assert( pTable->pSelect ); /* If nCol==0, then pTable must be a VIEW */ + pSel = pTable->pSelect; + + /* Note that the call to sqliteResultSetOfSelect() will expand any + ** "*" elements in this list. But we will need to restore the list + ** back to its original configuration afterwards, so we save a copy of + ** the original in pEList. + */ + pEList = pSel->pEList; + pSel->pEList = sqliteExprListDup(pEList); + if( pSel->pEList==0 ){ + pSel->pEList = pEList; + return 1; /* Malloc failed */ + } + pTable->nCol = -1; + pSelTab = sqliteResultSetOfSelect(pParse, 0, pSel); + if( pSelTab ){ + assert( pTable->aCol==0 ); + pTable->nCol = pSelTab->nCol; + pTable->aCol = pSelTab->aCol; + pSelTab->nCol = 0; + pSelTab->aCol = 0; + sqliteDeleteTable(0, pSelTab); + DbSetProperty(pParse->db, pTable->iDb, DB_UnresetViews); + }else{ + pTable->nCol = 0; + nErr++; + } + sqliteSelectUnbind(pSel); + sqliteExprListDelete(pSel->pEList); + pSel->pEList = pEList; + return nErr; +} + +/* +** Clear the column names from the VIEW pTable. +** +** This routine is called whenever any other table or view is modified. +** The view passed into this routine might depend directly or indirectly +** on the modified or deleted table so we need to clear the old column +** names so that they will be recomputed. +*/ +static void sqliteViewResetColumnNames(Table *pTable){ + int i; + if( pTable==0 || pTable->pSelect==0 ) return; + if( pTable->nCol==0 ) return; + for(i=0; inCol; i++){ + sqliteFree(pTable->aCol[i].zName); + sqliteFree(pTable->aCol[i].zDflt); + sqliteFree(pTable->aCol[i].zType); + } + sqliteFree(pTable->aCol); + pTable->aCol = 0; + pTable->nCol = 0; +} + +/* +** Clear the column names from every VIEW in database idx. +*/ +static void sqliteViewResetAll(sqlite *db, int idx){ + HashElem *i; + if( !DbHasProperty(db, idx, DB_UnresetViews) ) return; + for(i=sqliteHashFirst(&db->aDb[idx].tblHash); i; i=sqliteHashNext(i)){ + Table *pTab = sqliteHashData(i); + if( pTab->pSelect ){ + sqliteViewResetColumnNames(pTab); + } + } + DbClearProperty(db, idx, DB_UnresetViews); +} + +/* +** Given a token, look up a table with that name. If not found, leave +** an error for the parser to find and return NULL. +*/ +Table *sqliteTableFromToken(Parse *pParse, Token *pTok){ + char *zName; + Table *pTab; + zName = sqliteTableNameFromToken(pTok); + if( zName==0 ) return 0; + pTab = sqliteFindTable(pParse->db, zName, 0); + sqliteFree(zName); + if( pTab==0 ){ + sqliteSetNString(&pParse->zErrMsg, "no such table: ", 0, + pTok->z, pTok->n, 0); + pParse->nErr++; + } + return pTab; +} + +/* +** This routine is called to do the work of a DROP TABLE statement. +** pName is the name of the table to be dropped. +*/ +void sqliteDropTable(Parse *pParse, Token *pName, int isView){ + Table *pTable; + Vdbe *v; + int base; + sqlite *db = pParse->db; + int iDb; + + if( pParse->nErr || sqlite_malloc_failed ) return; + pTable = sqliteTableFromToken(pParse, pName); + if( pTable==0 ) return; + iDb = pTable->iDb; + assert( iDb>=0 && iDbnDb ); +#ifndef SQLITE_OMIT_AUTHORIZATION + { + int code; + const char *zTab = SCHEMA_TABLE(pTable->iDb); + const char *zDb = db->aDb[pTable->iDb].zName; + if( sqliteAuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){ + return; + } + if( isView ){ + if( iDb==1 ){ + code = SQLITE_DROP_TEMP_VIEW; + }else{ + code = SQLITE_DROP_VIEW; + } + }else{ + if( iDb==1 ){ + code = SQLITE_DROP_TEMP_TABLE; + }else{ + code = SQLITE_DROP_TABLE; + } + } + if( sqliteAuthCheck(pParse, code, pTable->zName, 0, zDb) ){ + return; + } + if( sqliteAuthCheck(pParse, SQLITE_DELETE, pTable->zName, 0, zDb) ){ + return; + } + } +#endif + if( pTable->readOnly ){ + sqliteSetString(&pParse->zErrMsg, "table ", pTable->zName, + " may not be dropped", 0); + pParse->nErr++; + return; + } + if( isView && pTable->pSelect==0 ){ + sqliteSetString(&pParse->zErrMsg, "use DROP TABLE to delete table ", + pTable->zName, 0); + pParse->nErr++; + return; + } + if( !isView && pTable->pSelect ){ + sqliteSetString(&pParse->zErrMsg, "use DROP VIEW to delete view ", + pTable->zName, 0); + pParse->nErr++; + return; + } + + /* Generate code to remove the table from the master table + ** on disk. + */ + v = sqliteGetVdbe(pParse); + if( v ){ + static VdbeOp dropTable[] = { + { OP_Rewind, 0, ADDR(8), 0}, + { OP_String, 0, 0, 0}, /* 1 */ + { OP_MemStore, 1, 1, 0}, + { OP_MemLoad, 1, 0, 0}, /* 3 */ + { OP_Column, 0, 2, 0}, + { OP_Ne, 0, ADDR(7), 0}, + { OP_Delete, 0, 0, 0}, + { OP_Next, 0, ADDR(3), 0}, /* 7 */ + }; + Index *pIdx; + Trigger *pTrigger; + sqliteBeginWriteOperation(pParse, 0, pTable->iDb); + + /* Drop all triggers associated with the table being dropped */ + pTrigger = pTable->pTrigger; + while( pTrigger ){ + assert( pTrigger->iDb==pTable->iDb || pTrigger->iDb==1 ); + sqliteDropTriggerPtr(pParse, pTrigger, 1); + if( pParse->explain ){ + pTrigger = pTrigger->pNext; + }else{ + pTrigger = pTable->pTrigger; + } + } + + /* Drop all SQLITE_MASTER entries that refer to the table */ + sqliteOpenMasterTable(v, pTable->iDb); + base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable); + sqliteVdbeChangeP3(v, base+1, pTable->zName, 0); + + /* Drop all SQLITE_TEMP_MASTER entries that refer to the table */ + if( pTable->iDb!=1 ){ + sqliteOpenMasterTable(v, 1); + base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable); + sqliteVdbeChangeP3(v, base+1, pTable->zName, 0); + } + + if( pTable->iDb==0 ){ + sqliteChangeCookie(db, v); + } + sqliteVdbeAddOp(v, OP_Close, 0, 0); + if( !isView ){ + sqliteVdbeAddOp(v, OP_Destroy, pTable->tnum, pTable->iDb); + for(pIdx=pTable->pIndex; pIdx; pIdx=pIdx->pNext){ + sqliteVdbeAddOp(v, OP_Destroy, pIdx->tnum, pIdx->iDb); + } + } + sqliteEndWriteOperation(pParse); + } + + /* Delete the in-memory description of the table. + ** + ** Exception: if the SQL statement began with the EXPLAIN keyword, + ** then no changes should be made. + */ + if( !pParse->explain ){ + sqliteUnlinkAndDeleteTable(db, pTable); + db->flags |= SQLITE_InternChanges; + } + sqliteViewResetAll(db, iDb); +} + +/* +** This routine constructs a P3 string suitable for an OP_MakeIdxKey +** opcode and adds that P3 string to the most recently inserted instruction +** in the virtual machine. The P3 string consists of a single character +** for each column in the index pIdx of table pTab. If the column uses +** a numeric sort order, then the P3 string character corresponding to +** that column is 'n'. If the column uses a text sort order, then the +** P3 string is 't'. See the OP_MakeIdxKey opcode documentation for +** additional information. See also the sqliteAddKeyType() routine. +*/ +void sqliteAddIdxKeyType(Vdbe *v, Index *pIdx){ + char *zType; + Table *pTab; + int i, n; + assert( pIdx!=0 && pIdx->pTable!=0 ); + pTab = pIdx->pTable; + n = pIdx->nColumn; + zType = sqliteMallocRaw( n+1 ); + if( zType==0 ) return; + for(i=0; iaiColumn[i]; + assert( iCol>=0 && iColnCol ); + if( (pTab->aCol[iCol].sortOrder & SQLITE_SO_TYPEMASK)==SQLITE_SO_TEXT ){ + zType[i] = 't'; + }else{ + zType[i] = 'n'; + } + } + zType[n] = 0; + sqliteVdbeChangeP3(v, -1, zType, n); + sqliteFree(zType); +} + +/* +** This routine is called to create a new foreign key on the table +** currently under construction. pFromCol determines which columns +** in the current table point to the foreign key. If pFromCol==0 then +** connect the key to the last column inserted. pTo is the name of +** the table referred to. pToCol is a list of tables in the other +** pTo table that the foreign key points to. flags contains all +** information about the conflict resolution algorithms specified +** in the ON DELETE, ON UPDATE and ON INSERT clauses. +** +** An FKey structure is created and added to the table currently +** under construction in the pParse->pNewTable field. The new FKey +** is not linked into db->aFKey at this point - that does not happen +** until sqliteEndTable(). +** +** The foreign key is set for IMMEDIATE processing. A subsequent call +** to sqliteDeferForeignKey() might change this to DEFERRED. +*/ +void sqliteCreateForeignKey( + Parse *pParse, /* Parsing context */ + IdList *pFromCol, /* Columns in this table that point to other table */ + Token *pTo, /* Name of the other table */ + IdList *pToCol, /* Columns in the other table */ + int flags /* Conflict resolution algorithms. */ +){ + Table *p = pParse->pNewTable; + int nByte; + int i; + int nCol; + char *z; + FKey *pFKey = 0; + + assert( pTo!=0 ); + if( p==0 || pParse->nErr ) goto fk_end; + if( pFromCol==0 ){ + int iCol = p->nCol-1; + if( iCol<0 ) goto fk_end; + if( pToCol && pToCol->nId!=1 ){ + sqliteSetNString(&pParse->zErrMsg, "foreign key on ", -1, + p->aCol[iCol].zName, -1, + " should reference only one column of table ", -1, + pTo->z, pTo->n, 0); + pParse->nErr++; + goto fk_end; + } + nCol = 1; + }else if( pToCol && pToCol->nId!=pFromCol->nId ){ + sqliteSetString(&pParse->zErrMsg, + "number of columns in foreign key does not match the number of " + "columns in the referenced table", 0); + pParse->nErr++; + goto fk_end; + }else{ + nCol = pFromCol->nId; + } + nByte = sizeof(*pFKey) + nCol*sizeof(pFKey->aCol[0]) + pTo->n + 1; + if( pToCol ){ + for(i=0; inId; i++){ + nByte += strlen(pToCol->a[i].zName) + 1; + } + } + pFKey = sqliteMalloc( nByte ); + if( pFKey==0 ) goto fk_end; + pFKey->pFrom = p; + pFKey->pNextFrom = p->pFKey; + z = (char*)&pFKey[1]; + pFKey->aCol = (struct sColMap*)z; + z += sizeof(struct sColMap)*nCol; + pFKey->zTo = z; + memcpy(z, pTo->z, pTo->n); + z[pTo->n] = 0; + z += pTo->n+1; + pFKey->pNextTo = 0; + pFKey->nCol = nCol; + if( pFromCol==0 ){ + pFKey->aCol[0].iFrom = p->nCol-1; + }else{ + for(i=0; inCol; j++){ + if( sqliteStrICmp(p->aCol[j].zName, pFromCol->a[i].zName)==0 ){ + pFKey->aCol[i].iFrom = j; + break; + } + } + if( j>=p->nCol ){ + sqliteSetString(&pParse->zErrMsg, "unknown column \"", + pFromCol->a[i].zName, "\" in foreign key definition", 0); + pParse->nErr++; + goto fk_end; + } + } + } + if( pToCol ){ + for(i=0; ia[i].zName); + pFKey->aCol[i].zCol = z; + memcpy(z, pToCol->a[i].zName, n); + z[n] = 0; + z += n+1; + } + } + pFKey->isDeferred = 0; + pFKey->deleteConf = flags & 0xff; + pFKey->updateConf = (flags >> 8 ) & 0xff; + pFKey->insertConf = (flags >> 16 ) & 0xff; + + /* Link the foreign key to the table as the last step. + */ + p->pFKey = pFKey; + pFKey = 0; + +fk_end: + sqliteFree(pFKey); + sqliteIdListDelete(pFromCol); + sqliteIdListDelete(pToCol); +} + +/* +** This routine is called when an INITIALLY IMMEDIATE or INITIALLY DEFERRED +** clause is seen as part of a foreign key definition. The isDeferred +** parameter is 1 for INITIALLY DEFERRED and 0 for INITIALLY IMMEDIATE. +** The behavior of the most recently created foreign key is adjusted +** accordingly. +*/ +void sqliteDeferForeignKey(Parse *pParse, int isDeferred){ + Table *pTab; + FKey *pFKey; + if( (pTab = pParse->pNewTable)==0 || (pFKey = pTab->pFKey)==0 ) return; + pFKey->isDeferred = isDeferred; +} + +/* +** Create a new index for an SQL table. pIndex is the name of the index +** and pTable is the name of the table that is to be indexed. Both will +** be NULL for a primary key or an index that is created to satisfy a +** UNIQUE constraint. If pTable and pIndex are NULL, use pParse->pNewTable +** as the table to be indexed. pParse->pNewTable is a table that is +** currently being constructed by a CREATE TABLE statement. +** +** pList is a list of columns to be indexed. pList will be NULL if this +** is a primary key or unique-constraint on the most recent column added +** to the table currently under construction. +*/ +void sqliteCreateIndex( + Parse *pParse, /* All information about this parse */ + Token *pName, /* Name of the index. May be NULL */ + SrcList *pTable, /* Name of the table to index. Use pParse->pNewTable if 0 */ + IdList *pList, /* A list of columns to be indexed */ + int onError, /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ + int isTemp, /* True if this is a temporary index */ + Token *pStart, /* The CREATE token that begins a CREATE TABLE statement */ + Token *pEnd /* The ")" that closes the CREATE INDEX statement */ +){ + Table *pTab; /* Table to be indexed */ + Index *pIndex; /* The index to be created */ + char *zName = 0; + int i, j; + Token nullId; /* Fake token for an empty ID list */ + DbFixer sFix; /* For assigning database names to pTable */ + sqlite *db = pParse->db; + + if( pParse->nErr || sqlite_malloc_failed ) goto exit_create_index; + if( !isTemp && pParse->initFlag + && sqliteFixInit(&sFix, pParse, pParse->iDb, "index", pName) + && sqliteFixSrcList(&sFix, pTable) + ){ + goto exit_create_index; + } + + /* + ** Find the table that is to be indexed. Return early if not found. + */ + if( pTable!=0 ){ + assert( pName!=0 ); + assert( pTable->nSrc==1 ); + pTab = sqliteSrcListLookup(pParse, pTable); + }else{ + assert( pName==0 ); + pTab = pParse->pNewTable; + } + if( pTab==0 || pParse->nErr ) goto exit_create_index; + if( pTab->readOnly ){ + sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName, + " may not be indexed", 0); + pParse->nErr++; + goto exit_create_index; + } + if( !isTemp && pTab->iDb>=2 && pParse->initFlag==0 ){ + sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName, + " may not have non-temporary indices added", 0); + pParse->nErr++; + goto exit_create_index; + } + if( pTab->pSelect ){ + sqliteSetString(&pParse->zErrMsg, "views may not be indexed", 0); + pParse->nErr++; + goto exit_create_index; + } + if( pTab->iDb==1 ){ + isTemp = 1; + } + + /* + ** Find the name of the index. Make sure there is not already another + ** index or table with the same name. + ** + ** Exception: If we are reading the names of permanent indices from the + ** sqlite_master table (because some other process changed the schema) and + ** one of the index names collides with the name of a temporary table or + ** index, then we will continue to process this index. + ** + ** If pName==0 it means that we are + ** dealing with a primary key or UNIQUE constraint. We have to invent our + ** own name. + */ + if( pName && !pParse->initFlag ){ + Index *pISameName; /* Another index with the same name */ + Table *pTSameName; /* A table with same name as the index */ + zName = sqliteStrNDup(pName->z, pName->n); + if( zName==0 ) goto exit_create_index; + if( (pISameName = sqliteFindIndex(db, zName, 0))!=0 ){ + sqliteSetString(&pParse->zErrMsg, "index ", zName, + " already exists", 0); + pParse->nErr++; + goto exit_create_index; + } + if( (pTSameName = sqliteFindTable(db, zName, 0))!=0 ){ + sqliteSetString(&pParse->zErrMsg, "there is already a table named ", + zName, 0); + pParse->nErr++; + goto exit_create_index; + } + }else if( pName==0 ){ + char zBuf[30]; + int n; + Index *pLoop; + for(pLoop=pTab->pIndex, n=1; pLoop; pLoop=pLoop->pNext, n++){} + sprintf(zBuf,"%d)",n); + zName = 0; + sqliteSetString(&zName, "(", pTab->zName, " autoindex ", zBuf, 0); + if( zName==0 ) goto exit_create_index; + }else{ + zName = sqliteStrNDup(pName->z, pName->n); + } + + /* Check for authorization to create an index. + */ +#ifndef SQLITE_OMIT_AUTHORIZATION + { + const char *zDb = db->aDb[pTab->iDb].zName; + + assert( isTemp==0 || isTemp==1 ); + assert( pTab->iDb==pParse->iDb || isTemp==1 ); + if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){ + goto exit_create_index; + } + i = SQLITE_CREATE_INDEX; + if( isTemp ) i = SQLITE_CREATE_TEMP_INDEX; + if( sqliteAuthCheck(pParse, i, zName, pTab->zName, zDb) ){ + goto exit_create_index; + } + } +#endif + + /* If pList==0, it means this routine was called to make a primary + ** key out of the last column added to the table under construction. + ** So create a fake list to simulate this. + */ + if( pList==0 ){ + nullId.z = pTab->aCol[pTab->nCol-1].zName; + nullId.n = strlen(nullId.z); + pList = sqliteIdListAppend(0, &nullId); + if( pList==0 ) goto exit_create_index; + } + + /* + ** Allocate the index structure. + */ + pIndex = sqliteMalloc( sizeof(Index) + strlen(zName) + 1 + + sizeof(int)*pList->nId ); + if( pIndex==0 ) goto exit_create_index; + pIndex->aiColumn = (int*)&pIndex[1]; + pIndex->zName = (char*)&pIndex->aiColumn[pList->nId]; + strcpy(pIndex->zName, zName); + pIndex->pTable = pTab; + pIndex->nColumn = pList->nId; + pIndex->onError = onError; + pIndex->autoIndex = pName==0; + pIndex->iDb = isTemp ? 1 : pParse->iDb; + + /* 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; inId; i++){ + for(j=0; jnCol; j++){ + if( sqliteStrICmp(pList->a[i].zName, pTab->aCol[j].zName)==0 ) break; + } + if( j>=pTab->nCol ){ + sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName, + " has no column named ", pList->a[i].zName, 0); + pParse->nErr++; + sqliteFree(pIndex); + goto exit_create_index; + } + pIndex->aiColumn[i] = j; + } + + /* Link the new Index structure to its table and to the other + ** in-memory database structures. + */ + if( !pParse->explain ){ + Index *p; + p = sqliteHashInsert(&db->aDb[pIndex->iDb].idxHash, + pIndex->zName, strlen(pIndex->zName)+1, pIndex); + if( p ){ + assert( p==pIndex ); /* Malloc must have failed */ + sqliteFree(pIndex); + goto exit_create_index; + } + db->flags |= SQLITE_InternChanges; + } + + /* When adding an index to the list of indices for a table, make + ** sure all indices labeled OE_Replace come after all those labeled + ** OE_Ignore. This is necessary for the correct operation of UPDATE + ** and INSERT. + */ + if( onError!=OE_Replace || pTab->pIndex==0 + || pTab->pIndex->onError==OE_Replace){ + pIndex->pNext = pTab->pIndex; + pTab->pIndex = pIndex; + }else{ + Index *pOther = pTab->pIndex; + while( pOther->pNext && pOther->pNext->onError!=OE_Replace ){ + pOther = pOther->pNext; + } + pIndex->pNext = pOther->pNext; + pOther->pNext = pIndex; + } + + /* If the initFlag is 1 it means we are reading the SQL off the + ** "sqlite_master" table on the disk. So do not write to the disk + ** again. Extract the table number from the pParse->newTnum field. + */ + if( pParse->initFlag && pTable!=0 ){ + pIndex->tnum = pParse->newTnum; + } + + /* If the initFlag is 0 then create the index on disk. This + ** involves writing the index into the master table and filling in the + ** index with the current table contents. + ** + ** The initFlag is 0 when the user first enters a CREATE INDEX + ** command. The initFlag is 1 when a database is opened and + ** CREATE INDEX statements are read out of the master table. In + ** the latter case the index already exists on disk, which is why + ** we don't want to recreate it. + ** + ** If pTable==0 it means this index is generated as a primary key + ** or UNIQUE constraint of a CREATE TABLE statement. Since the table + ** has just been created, it contains no data and the index initialization + ** step can be skipped. + */ + else if( pParse->initFlag==0 ){ + int n; + Vdbe *v; + int lbl1, lbl2; + int i; + int addr; + + v = sqliteGetVdbe(pParse); + if( v==0 ) goto exit_create_index; + if( pTable!=0 ){ + sqliteBeginWriteOperation(pParse, 0, isTemp); + sqliteOpenMasterTable(v, isTemp); + } + sqliteVdbeAddOp(v, OP_NewRecno, 0, 0); + sqliteVdbeAddOp(v, OP_String, 0, 0); + sqliteVdbeChangeP3(v, -1, "index", P3_STATIC); + sqliteVdbeAddOp(v, OP_String, 0, 0); + sqliteVdbeChangeP3(v, -1, pIndex->zName, P3_STATIC); + sqliteVdbeAddOp(v, OP_String, 0, 0); + sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC); + addr = sqliteVdbeAddOp(v, OP_CreateIndex, 0, isTemp); + sqliteVdbeChangeP3(v, addr, (char*)&pIndex->tnum, P3_POINTER); + pIndex->tnum = 0; + if( pTable ){ + sqliteVdbeAddOp(v, OP_Dup, 0, 0); + sqliteVdbeAddOp(v, OP_Integer, isTemp, 0); + sqliteVdbeAddOp(v, OP_OpenWrite, 1, 0); + } + addr = sqliteVdbeAddOp(v, OP_String, 0, 0); + if( pStart && pEnd ){ + n = Addr(pEnd->z) - Addr(pStart->z) + 1; + sqliteVdbeChangeP3(v, addr, pStart->z, n); + } + sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0); + sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0); + if( pTable ){ + sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0); + sqliteVdbeAddOp(v, OP_OpenRead, 2, pTab->tnum); + sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC); + lbl2 = sqliteVdbeMakeLabel(v); + sqliteVdbeAddOp(v, OP_Rewind, 2, lbl2); + lbl1 = sqliteVdbeAddOp(v, OP_Recno, 2, 0); + for(i=0; inColumn; i++){ + int iCol = pIndex->aiColumn[i]; + if( pTab->iPKey==iCol ){ + sqliteVdbeAddOp(v, OP_Dup, i, 0); + }else{ + sqliteVdbeAddOp(v, OP_Column, 2, iCol); + } + } + sqliteVdbeAddOp(v, OP_MakeIdxKey, pIndex->nColumn, 0); + if( db->file_format>=4 ) sqliteAddIdxKeyType(v, pIndex); + sqliteVdbeAddOp(v, OP_IdxPut, 1, pIndex->onError!=OE_None); + sqliteVdbeChangeP3(v, -1, "indexed columns are not unique", P3_STATIC); + sqliteVdbeAddOp(v, OP_Next, 2, lbl1); + sqliteVdbeResolveLabel(v, lbl2); + sqliteVdbeAddOp(v, OP_Close, 2, 0); + sqliteVdbeAddOp(v, OP_Close, 1, 0); + } + if( pTable!=0 ){ + if( !isTemp ){ + sqliteChangeCookie(db, v); + } + sqliteVdbeAddOp(v, OP_Close, 0, 0); + sqliteEndWriteOperation(pParse); + } + } + + /* Clean up before exiting */ +exit_create_index: + sqliteIdListDelete(pList); + sqliteSrcListDelete(pTable); + sqliteFree(zName); + return; +} + +/* +** This routine will drop an existing named index. This routine +** implements the DROP INDEX statement. +*/ +void sqliteDropIndex(Parse *pParse, SrcList *pName){ + Index *pIndex; + Vdbe *v; + sqlite *db = pParse->db; + + if( pParse->nErr || sqlite_malloc_failed ) return; + assert( pName->nSrc==1 ); + pIndex = sqliteFindIndex(db, pName->a[0].zName, pName->a[0].zDatabase); + if( pIndex==0 ){ + sqliteErrorMsg(pParse, "no such index: %S", pName, 0); + goto exit_drop_index; + } + if( pIndex->autoIndex ){ + sqliteErrorMsg(pParse, "index associated with UNIQUE " + "or PRIMARY KEY constraint cannot be dropped", 0); + goto exit_drop_index; + } + if( pIndex->iDb>1 ){ + sqliteErrorMsg(pParse, "cannot alter schema of attached " + "databases", 0); + goto exit_drop_index; + } +#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); + if( sqliteAuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){ + goto exit_drop_index; + } + if( pIndex->iDb ) code = SQLITE_DROP_TEMP_INDEX; + if( sqliteAuthCheck(pParse, code, pIndex->zName, pTab->zName, zDb) ){ + goto exit_drop_index; + } + } +#endif + + /* Generate code to remove the index and from the master table */ + v = sqliteGetVdbe(pParse); + if( v ){ + static VdbeOp dropIndex[] = { + { OP_Rewind, 0, ADDR(9), 0}, + { OP_String, 0, 0, 0}, /* 1 */ + { OP_MemStore, 1, 1, 0}, + { OP_MemLoad, 1, 0, 0}, /* 3 */ + { OP_Column, 0, 1, 0}, + { OP_Eq, 0, ADDR(8), 0}, + { OP_Next, 0, ADDR(3), 0}, + { OP_Goto, 0, ADDR(9), 0}, + { OP_Delete, 0, 0, 0}, /* 8 */ + }; + int base; + + sqliteBeginWriteOperation(pParse, 0, pIndex->iDb); + sqliteOpenMasterTable(v, pIndex->iDb); + base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex); + sqliteVdbeChangeP3(v, base+1, pIndex->zName, 0); + if( pIndex->iDb==0 ){ + sqliteChangeCookie(db, v); + } + sqliteVdbeAddOp(v, OP_Close, 0, 0); + sqliteVdbeAddOp(v, OP_Destroy, pIndex->tnum, pIndex->iDb); + sqliteEndWriteOperation(pParse); + } + + /* Delete the in-memory description of this index. + */ + if( !pParse->explain ){ + sqliteUnlinkAndDeleteIndex(db, pIndex); + db->flags |= SQLITE_InternChanges; + } + +exit_drop_index: + sqliteSrcListDelete(pName); +} + +/* +** Append a new element to the given IdList. Create a new IdList if +** need be. +** +** A new IdList is returned, or NULL if malloc() fails. +*/ +IdList *sqliteIdListAppend(IdList *pList, Token *pToken){ + if( pList==0 ){ + pList = sqliteMalloc( sizeof(IdList) ); + if( pList==0 ) return 0; + } + if( (pList->nId & 7)==0 ){ + struct IdList_item *a; + a = sqliteRealloc(pList->a, (pList->nId+8)*sizeof(pList->a[0]) ); + if( a==0 ){ + sqliteIdListDelete(pList); + return 0; + } + pList->a = a; + } + memset(&pList->a[pList->nId], 0, sizeof(pList->a[0])); + if( pToken ){ + char **pz = &pList->a[pList->nId].zName; + sqliteSetNString(pz, pToken->z, pToken->n, 0); + if( *pz==0 ){ + sqliteIdListDelete(pList); + return 0; + }else{ + sqliteDequote(*pz); + } + } + pList->nId++; + return pList; +} + +/* +** Append a new table name to the given SrcList. Create a new SrcList if +** need be. A new entry is created in the SrcList even if pToken is NULL. +** +** A new SrcList is returned, or NULL if malloc() fails. +** +** If pDatabase is not null, it means that the table has an optional +** database name prefix. Like this: "database.table". The pDatabase +** points to the table name and the pTable points to the database name. +** The SrcList.a[].zName field is filled with the table name which might +** come from pTable (if pDatabase is NULL) or from pDatabase. +** SrcList.a[].zDatabase is filled with the database name from pTable, +** or with NULL if no database is specified. +** +** In other words, if call like this: +** +** sqliteSrcListAppend(A,B,0); +** +** Then B is a table name and the database name is unspecified. If called +** like this: +** +** sqliteSrcListAppend(A,B,C); +** +** Then C is the table name and B is the database name. +*/ +SrcList *sqliteSrcListAppend(SrcList *pList, Token *pTable, Token *pDatabase){ + if( pList==0 ){ + pList = sqliteMalloc( sizeof(SrcList) ); + if( pList==0 ) return 0; + } + if( (pList->nSrc & 7)==1 ){ + SrcList *pNew; + pNew = sqliteRealloc(pList, + sizeof(*pList) + (pList->nSrc+8)*sizeof(pList->a[0]) ); + if( pNew==0 ){ + sqliteSrcListDelete(pList); + return 0; + } + pList = pNew; + } + memset(&pList->a[pList->nSrc], 0, sizeof(pList->a[0])); + if( pDatabase && pDatabase->z==0 ){ + pDatabase = 0; + } + if( pDatabase && pTable ){ + Token *pTemp = pDatabase; + pDatabase = pTable; + pTable = pTemp; + } + if( pTable ){ + char **pz = &pList->a[pList->nSrc].zName; + sqliteSetNString(pz, pTable->z, pTable->n, 0); + if( *pz==0 ){ + sqliteSrcListDelete(pList); + return 0; + }else{ + sqliteDequote(*pz); + } + } + if( pDatabase ){ + char **pz = &pList->a[pList->nSrc].zDatabase; + sqliteSetNString(pz, pDatabase->z, pDatabase->n, 0); + if( *pz==0 ){ + sqliteSrcListDelete(pList); + return 0; + }else{ + sqliteDequote(*pz); + } + } + pList->a[pList->nSrc].iCursor = -1; + pList->nSrc++; + return pList; +} + +/* +** Assign cursors to all tables in a SrcList +*/ +void sqliteSrcListAssignCursors(Parse *pParse, SrcList *pList){ + int i; + for(i=0; inSrc; i++){ + if( pList->a[i].iCursor<0 ){ + pList->a[i].iCursor = pParse->nTab++; + } + } +} + +/* +** Add an alias to the last identifier on the given identifier list. +*/ +void sqliteSrcListAddAlias(SrcList *pList, Token *pToken){ + if( pList && pList->nSrc>0 ){ + int i = pList->nSrc - 1; + sqliteSetNString(&pList->a[i].zAlias, pToken->z, pToken->n, 0); + sqliteDequote(pList->a[i].zAlias); + } +} + +/* +** Delete an IdList. +*/ +void sqliteIdListDelete(IdList *pList){ + int i; + if( pList==0 ) return; + for(i=0; inId; i++){ + sqliteFree(pList->a[i].zName); + } + sqliteFree(pList->a); + sqliteFree(pList); +} + +/* +** Return the index in pList of the identifier named zId. Return -1 +** if not found. +*/ +int sqliteIdListIndex(IdList *pList, const char *zName){ + int i; + if( pList==0 ) return -1; + for(i=0; inId; i++){ + if( sqliteStrICmp(pList->a[i].zName, zName)==0 ) return i; + } + return -1; +} + +/* +** Delete an entire SrcList including all its substructure. +*/ +void sqliteSrcListDelete(SrcList *pList){ + int i; + if( pList==0 ) return; + for(i=0; inSrc; i++){ + sqliteFree(pList->a[i].zDatabase); + sqliteFree(pList->a[i].zName); + sqliteFree(pList->a[i].zAlias); + if( pList->a[i].pTab && pList->a[i].pTab->isTransient ){ + sqliteDeleteTable(0, pList->a[i].pTab); + } + sqliteSelectDelete(pList->a[i].pSelect); + sqliteExprDelete(pList->a[i].pOn); + sqliteIdListDelete(pList->a[i].pUsing); + } + sqliteFree(pList); +} + +/* +** Begin a transaction +*/ +void sqliteBeginTransaction(Parse *pParse, int onError){ + sqlite *db; + + if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return; + if( pParse->nErr || sqlite_malloc_failed ) return; + if( sqliteAuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ) return; + if( db->flags & SQLITE_InTrans ){ + sqliteErrorMsg(pParse, "cannot start a transaction within a transaction"); + return; + } + sqliteBeginWriteOperation(pParse, 0, 0); + db->flags |= SQLITE_InTrans; + db->onError = onError; +} + +/* +** Commit a transaction +*/ +void sqliteCommitTransaction(Parse *pParse){ + sqlite *db; + + if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return; + if( pParse->nErr || sqlite_malloc_failed ) return; + if( sqliteAuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ) return; + if( (db->flags & SQLITE_InTrans)==0 ){ + sqliteErrorMsg(pParse, "cannot commit - no transaction is active"); + return; + } + db->flags &= ~SQLITE_InTrans; + sqliteEndWriteOperation(pParse); + db->onError = OE_Default; +} + +/* +** Rollback a transaction +*/ +void sqliteRollbackTransaction(Parse *pParse){ + sqlite *db; + Vdbe *v; + + if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return; + if( pParse->nErr || sqlite_malloc_failed ) return; + if( sqliteAuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ) return; + if( (db->flags & SQLITE_InTrans)==0 ){ + sqliteErrorMsg(pParse, "cannot rollback - no transaction is active"); + return; + } + v = sqliteGetVdbe(pParse); + if( v ){ + sqliteVdbeAddOp(v, OP_Rollback, 0, 0); + } + db->flags &= ~SQLITE_InTrans; + db->onError = OE_Default; +} + +/* +** Generate VDBE code that will verify the schema cookie for all +** named database files. +*/ +void sqliteCodeVerifySchema(Parse *pParse, int iDb){ + sqlite *db = pParse->db; + Vdbe *v = sqliteGetVdbe(pParse); + assert( iDb>=0 && iDbnDb ); + assert( db->aDb[iDb].pBt!=0 ); + if( iDb!=1 && !DbHasProperty(db, iDb, DB_Cookie) ){ + sqliteVdbeAddOp(v, OP_VerifyCookie, iDb, db->aDb[iDb].schema_cookie); + DbSetProperty(db, iDb, DB_Cookie); + } +} + +/* +** Generate VDBE code that prepares for doing an operation that +** might change the database. +** +** This routine starts a new transaction if we are not already within +** a transaction. If we are already within a transaction, then a checkpoint +** is set if the setCheckpoint parameter is true. A checkpoint should +** be set for operations that might fail (due to a constraint) part of +** the way through and which will need to undo some writes without having to +** rollback the whole transaction. For operations where all constraints +** can be checked before any changes are made to the database, it is never +** necessary to undo a write and the checkpoint should not be set. +** +** Only database iDb and the temp database are made writable by this call. +** If iDb==0, then the main and temp databases are made writable. If +** iDb==1 then only the temp database is made writable. If iDb>1 then the +** specified auxiliary database and the temp database are made writable. +*/ +void sqliteBeginWriteOperation(Parse *pParse, int setCheckpoint, int iDb){ + Vdbe *v; + sqlite *db = pParse->db; + if( DbHasProperty(db, iDb, DB_Locked) ) return; + v = sqliteGetVdbe(pParse); + if( v==0 ) return; + if( !db->aDb[iDb].inTrans ){ + sqliteVdbeAddOp(v, OP_Transaction, iDb, 0); + DbSetProperty(db, iDb, DB_Locked); + sqliteCodeVerifySchema(pParse, iDb); + if( iDb!=1 ){ + sqliteBeginWriteOperation(pParse, setCheckpoint, 1); + } + }else if( setCheckpoint ){ + sqliteVdbeAddOp(v, OP_Checkpoint, iDb, 0); + DbSetProperty(db, iDb, DB_Locked); + } +} + +/* +** Generate code that concludes an operation that may have changed +** the database. If a statement transaction was started, then emit +** an OP_Commit that will cause the changes to be committed to disk. +** +** Note that checkpoints are automatically committed at the end of +** a statement. Note also that there can be multiple calls to +** sqliteBeginWriteOperation() but there should only be a single +** call to sqliteEndWriteOperation() at the conclusion of the statement. +*/ +void sqliteEndWriteOperation(Parse *pParse){ + Vdbe *v; + sqlite *db = pParse->db; + if( pParse->trigStack ) return; /* if this is in a trigger */ + v = sqliteGetVdbe(pParse); + if( v==0 ) return; + if( db->flags & SQLITE_InTrans ){ + /* A BEGIN has executed. Do not commit until we see an explicit + ** COMMIT statement. */ + }else{ + sqliteVdbeAddOp(v, OP_Commit, 0, 0); + } +} diff --git a/sqlitebrowser/sqlitebrowser/sqlite_source/config.h b/sqlitebrowser/sqlitebrowser/sqlite_source/config.h new file mode 100755 index 00000000..673fb7fe --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/sqlite_source/config.h @@ -0,0 +1 @@ +#define SQLITE_PTR_SZ 4 diff --git a/sqlitebrowser/sqlitebrowser/sqlite_source/copy.c b/sqlitebrowser/sqlitebrowser/sqlite_source/copy.c new file mode 100755 index 00000000..281597da --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/sqlite_source/copy.c @@ -0,0 +1,120 @@ +/* +** 2003 April 6 +** +** 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 code used to implement the COPY command. +** +** $Id: copy.c,v 1.1.1.1 2003-08-21 02:24:07 tabuleiro Exp $ +*/ +#include "sqliteInt.h" + +/* +** The COPY command is for compatibility with PostgreSQL and specificially +** for the ability to read the output of pg_dump. The format is as +** follows: +** +** COPY table FROM file [USING DELIMITERS string] +** +** "table" is an existing table name. We will read lines of code from +** file to fill this table with data. File might be "stdin". The optional +** delimiter string identifies the field separators. The default is a tab. +*/ +void sqliteCopy( + Parse *pParse, /* The parser context */ + SrcList *pTableName, /* The name of the table into which we will insert */ + Token *pFilename, /* The file from which to obtain information */ + Token *pDelimiter, /* Use this as the field delimiter */ + int onError /* What to do if a constraint fails */ +){ + Table *pTab; + int i; + Vdbe *v; + int addr, end; + Index *pIdx; + char *zFile = 0; + const char *zDb; + sqlite *db = pParse->db; + + + if( sqlite_malloc_failed ) goto copy_cleanup; + assert( pTableName->nSrc==1 ); + pTab = sqliteSrcListLookup(pParse, pTableName); + if( pTab==0 || sqliteIsReadOnly(pParse, pTab, 0) ) goto copy_cleanup; + zFile = sqliteStrNDup(pFilename->z, pFilename->n); + sqliteDequote(zFile); + assert( pTab->iDbnDb ); + zDb = db->aDb[pTab->iDb].zName; + if( sqliteAuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb) + || sqliteAuthCheck(pParse, SQLITE_COPY, pTab->zName, zFile, zDb) ){ + goto copy_cleanup; + } + v = sqliteGetVdbe(pParse); + if( v ){ + sqliteBeginWriteOperation(pParse, 1, pTab->iDb); + addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0); + sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n); + sqliteVdbeDequoteP3(v, addr); + sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0); + sqliteVdbeAddOp(v, OP_OpenWrite, 0, pTab->tnum); + sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC); + for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ + assert( pIdx->iDb==1 || pIdx->iDb==pTab->iDb ); + sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0); + sqliteVdbeAddOp(v, OP_OpenWrite, i, pIdx->tnum); + sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC); + } + if( db->flags & SQLITE_CountRows ){ + sqliteVdbeAddOp(v, OP_Integer, 0, 0); /* Initialize the row count */ + } + end = sqliteVdbeMakeLabel(v); + addr = sqliteVdbeAddOp(v, OP_FileRead, pTab->nCol, end); + if( pDelimiter ){ + sqliteVdbeChangeP3(v, addr, pDelimiter->z, pDelimiter->n); + sqliteVdbeDequoteP3(v, addr); + }else{ + sqliteVdbeChangeP3(v, addr, "\t", 1); + } + if( pTab->iPKey>=0 ){ + sqliteVdbeAddOp(v, OP_FileColumn, pTab->iPKey, 0); + sqliteVdbeAddOp(v, OP_MustBeInt, 0, 0); + }else{ + sqliteVdbeAddOp(v, OP_NewRecno, 0, 0); + } + for(i=0; inCol; i++){ + if( i==pTab->iPKey ){ + /* The integer primary key column is filled with NULL since its + ** value is always pulled from the record number */ + sqliteVdbeAddOp(v, OP_String, 0, 0); + }else{ + sqliteVdbeAddOp(v, OP_FileColumn, i, 0); + } + } + sqliteGenerateConstraintChecks(pParse, pTab, 0, 0, pTab->iPKey>=0, + 0, onError, addr); + sqliteCompleteInsertion(pParse, pTab, 0, 0, 0, 0, -1); + if( (db->flags & SQLITE_CountRows)!=0 ){ + sqliteVdbeAddOp(v, OP_AddImm, 1, 0); /* Increment row count */ + } + sqliteVdbeAddOp(v, OP_Goto, 0, addr); + sqliteVdbeResolveLabel(v, end); + sqliteVdbeAddOp(v, OP_Noop, 0, 0); + sqliteEndWriteOperation(pParse); + if( db->flags & SQLITE_CountRows ){ + sqliteVdbeAddOp(v, OP_ColumnName, 0, 0); + sqliteVdbeChangeP3(v, -1, "rows inserted", P3_STATIC); + sqliteVdbeAddOp(v, OP_Callback, 1, 0); + } + } + +copy_cleanup: + sqliteSrcListDelete(pTableName); + sqliteFree(zFile); + return; +} diff --git a/sqlitebrowser/sqlitebrowser/sqlite_source/delete.c b/sqlitebrowser/sqlitebrowser/sqlite_source/delete.c new file mode 100755 index 00000000..7a62aa04 --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/sqlite_source/delete.c @@ -0,0 +1,396 @@ +/* +** 2001 September 15 +** +** 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 C code routines that are called by the parser +** to handle DELETE FROM statements. +** +** $Id: delete.c,v 1.1.1.1 2003-08-21 02:24:07 tabuleiro Exp $ +*/ +#include "sqliteInt.h" + +/* +** Look up every table that is named in pSrc. If any table is not found, +** add an error message to pParse->zErrMsg and return NULL. If all tables +** are found, return a pointer to the last table. +*/ +Table *sqliteSrcListLookup(Parse *pParse, SrcList *pSrc){ + Table *pTab = 0; + int i; + for(i=0; inSrc; i++){ + const char *zTab = pSrc->a[i].zName; + const char *zDb = pSrc->a[i].zDatabase; + pTab = sqliteLocateTable(pParse, zTab, zDb); + pSrc->a[i].pTab = pTab; + } + return pTab; +} + +/* +** Check to make sure the given table is writable. If it is not +** writable, generate an error message and return 1. If it is +** writable return 0; +*/ +int sqliteIsReadOnly(Parse *pParse, Table *pTab, int viewOk){ + if( pTab->readOnly ){ + sqliteErrorMsg(pParse, "table %s may not be modified", pTab->zName); + return 1; + } + if( !viewOk && pTab->pSelect ){ + sqliteErrorMsg(pParse, "cannot modify %s because it is a view",pTab->zName); + return 1; + } + return 0; +} + +/* +** Process a DELETE FROM statement. +*/ +void sqliteDeleteFrom( + Parse *pParse, /* The parser context */ + SrcList *pTabList, /* The table from which we should delete things */ + Expr *pWhere /* The WHERE clause. May be null */ +){ + Vdbe *v; /* The virtual database engine */ + Table *pTab; /* The table from which records will be deleted */ + const char *zDb; /* Name of database holding pTab */ + int end, addr; /* A couple addresses of generated code */ + int i; /* Loop counter */ + WhereInfo *pWInfo; /* Information about the WHERE clause */ + Index *pIdx; /* For looping over indices of the table */ + int iCur; /* VDBE Cursor number for pTab */ + sqlite *db; /* Main database structure */ + int isView; /* True if attempting to delete from a view */ + AuthContext sContext; /* Authorization context */ + + int row_triggers_exist = 0; /* True if any triggers exist */ + int before_triggers; /* True if there are BEFORE triggers */ + int after_triggers; /* True if there are AFTER triggers */ + int oldIdx = -1; /* Cursor for the OLD table of AFTER triggers */ + + sContext.pParse = 0; + if( pParse->nErr || sqlite_malloc_failed ){ + pTabList = 0; + goto delete_from_cleanup; + } + db = pParse->db; + assert( pTabList->nSrc==1 ); + + /* Locate the table which we want to delete. This table has to be + ** put in an SrcList structure because some of the subroutines we + ** will be calling are designed to work with multiple tables and expect + ** an SrcList* parameter instead of just a Table* parameter. + */ + pTab = sqliteSrcListLookup(pParse, pTabList); + if( pTab==0 ) goto delete_from_cleanup; + before_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, + TK_DELETE, TK_BEFORE, TK_ROW, 0); + after_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, + TK_DELETE, TK_AFTER, TK_ROW, 0); + row_triggers_exist = before_triggers || after_triggers; + isView = pTab->pSelect!=0; + if( sqliteIsReadOnly(pParse, pTab, before_triggers) ){ + goto delete_from_cleanup; + } + assert( pTab->iDbnDb ); + zDb = db->aDb[pTab->iDb].zName; + if( sqliteAuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){ + goto delete_from_cleanup; + } + + /* If pTab is really a view, make sure it has been initialized. + */ + if( isView && sqliteViewGetColumnNames(pParse, pTab) ){ + goto delete_from_cleanup; + } + + /* Allocate a cursor used to store the old.* data for a trigger. + */ + if( row_triggers_exist ){ + oldIdx = pParse->nTab++; + } + + /* Resolve the column names in all the expressions. + */ + assert( pTabList->nSrc==1 ); + iCur = pTabList->a[0].iCursor = pParse->nTab++; + if( pWhere ){ + if( sqliteExprResolveIds(pParse, pTabList, 0, pWhere) ){ + goto delete_from_cleanup; + } + if( sqliteExprCheck(pParse, pWhere, 0, 0) ){ + goto delete_from_cleanup; + } + } + + /* Start the view context + */ + if( isView ){ + sqliteAuthContextPush(pParse, &sContext, pTab->zName); + } + + /* Begin generating code. + */ + v = sqliteGetVdbe(pParse); + if( v==0 ){ + goto delete_from_cleanup; + } + sqliteBeginWriteOperation(pParse, row_triggers_exist, pTab->iDb); + + /* If we are trying to delete from a view, construct that view into + ** a temporary table. + */ + if( isView ){ + Select *pView = sqliteSelectDup(pTab->pSelect); + sqliteSelect(pParse, pView, SRT_TempTable, iCur, 0, 0, 0); + sqliteSelectDelete(pView); + } + + /* Initialize the counter of the number of rows deleted, if + ** we are counting rows. + */ + if( db->flags & SQLITE_CountRows ){ + sqliteVdbeAddOp(v, OP_Integer, 0, 0); + } + + /* Special case: A DELETE without a WHERE clause deletes everything. + ** It is easier just to erase the whole table. Note, however, that + ** this means that the row change count will be incorrect. + */ + if( pWhere==0 && !row_triggers_exist ){ + if( db->flags & SQLITE_CountRows ){ + /* If counting rows deleted, just count the total number of + ** entries in the table. */ + int endOfLoop = sqliteVdbeMakeLabel(v); + int addr; + if( !isView ){ + sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0); + sqliteVdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum); + } + sqliteVdbeAddOp(v, OP_Rewind, iCur, sqliteVdbeCurrentAddr(v)+2); + addr = sqliteVdbeAddOp(v, OP_AddImm, 1, 0); + sqliteVdbeAddOp(v, OP_Next, iCur, addr); + sqliteVdbeResolveLabel(v, endOfLoop); + sqliteVdbeAddOp(v, OP_Close, iCur, 0); + } + if( !isView ){ + sqliteVdbeAddOp(v, OP_Clear, pTab->tnum, pTab->iDb); + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + sqliteVdbeAddOp(v, OP_Clear, pIdx->tnum, pIdx->iDb); + } + } + } + + /* The usual case: There is a WHERE clause so we have to scan through + ** the table an pick which records to delete. + */ + else{ + /* Begin the database scan + */ + pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 1, 0); + if( pWInfo==0 ) goto delete_from_cleanup; + + /* Remember the key of every item to be deleted. + */ + sqliteVdbeAddOp(v, OP_ListWrite, 0, 0); + if( db->flags & SQLITE_CountRows ){ + sqliteVdbeAddOp(v, OP_AddImm, 1, 0); + } + + /* End the database scan loop. + */ + sqliteWhereEnd(pWInfo); + + /* Open the pseudo-table used to store OLD if there are triggers. + */ + if( row_triggers_exist ){ + sqliteVdbeAddOp(v, OP_OpenPseudo, oldIdx, 0); + } + + /* Delete every item whose key was written to the list during the + ** database scan. We have to delete items after the scan is complete + ** because deleting an item can change the scan order. + */ + sqliteVdbeAddOp(v, OP_ListRewind, 0, 0); + end = sqliteVdbeMakeLabel(v); + + /* This is the beginning of the delete loop when there are + ** row triggers. + */ + if( row_triggers_exist ){ + addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end); + sqliteVdbeAddOp(v, OP_Dup, 0, 0); + if( !isView ){ + sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0); + sqliteVdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum); + } + sqliteVdbeAddOp(v, OP_MoveTo, iCur, 0); + + sqliteVdbeAddOp(v, OP_Recno, iCur, 0); + sqliteVdbeAddOp(v, OP_RowData, iCur, 0); + sqliteVdbeAddOp(v, OP_PutIntKey, oldIdx, 0); + if( !isView ){ + sqliteVdbeAddOp(v, OP_Close, iCur, 0); + } + + sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1, + oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default, + addr); + } + + if( !isView ){ + /* Open cursors for the table we are deleting from and all its + ** indices. If there are row triggers, this happens inside the + ** OP_ListRead loop because the cursor have to all be closed + ** before the trigger fires. If there are no row triggers, the + ** cursors are opened only once on the outside the loop. + */ + pParse->nTab = iCur + 1; + sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0); + sqliteVdbeAddOp(v, OP_OpenWrite, iCur, pTab->tnum); + for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ + sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0); + sqliteVdbeAddOp(v, OP_OpenWrite, pParse->nTab++, pIdx->tnum); + } + + /* This is the beginning of the delete loop when there are no + ** row triggers */ + if( !row_triggers_exist ){ + addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end); + } + + /* Delete the row */ + sqliteGenerateRowDelete(db, v, pTab, iCur, pParse->trigStack==0); + } + + /* If there are row triggers, close all cursors then invoke + ** the AFTER triggers + */ + if( row_triggers_exist ){ + if( !isView ){ + for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ + sqliteVdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum); + } + sqliteVdbeAddOp(v, OP_Close, iCur, 0); + } + sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1, + oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default, + addr); + } + + /* End of the delete loop */ + sqliteVdbeAddOp(v, OP_Goto, 0, addr); + sqliteVdbeResolveLabel(v, end); + sqliteVdbeAddOp(v, OP_ListReset, 0, 0); + + /* Close the cursors after the loop if there are no row triggers */ + if( !row_triggers_exist ){ + for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ + sqliteVdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum); + } + sqliteVdbeAddOp(v, OP_Close, iCur, 0); + pParse->nTab = iCur; + } + } + sqliteEndWriteOperation(pParse); + + /* + ** Return the number of rows that were deleted. + */ + if( db->flags & SQLITE_CountRows ){ + sqliteVdbeAddOp(v, OP_ColumnName, 0, 0); + sqliteVdbeChangeP3(v, -1, "rows deleted", P3_STATIC); + sqliteVdbeAddOp(v, OP_Callback, 1, 0); + } + +delete_from_cleanup: + sqliteAuthContextPop(&sContext); + sqliteSrcListDelete(pTabList); + sqliteExprDelete(pWhere); + return; +} + +/* +** This routine generates VDBE code that causes a single row of a +** single table to be deleted. +** +** The VDBE must be in a particular state when this routine is called. +** These are the requirements: +** +** 1. A read/write cursor pointing to pTab, the table containing the row +** to be deleted, must be opened as cursor number "base". +** +** 2. Read/write cursors for all indices of pTab must be open as +** cursor number base+i for the i-th index. +** +** 3. The record number of the row to be deleted must be on the top +** of the stack. +** +** This routine pops the top of the stack to remove the record number +** and then generates code to remove both the table record and all index +** entries that point to that record. +*/ +void sqliteGenerateRowDelete( + sqlite *db, /* The database containing the index */ + Vdbe *v, /* Generate code into this VDBE */ + Table *pTab, /* Table containing the row to be deleted */ + int iCur, /* Cursor number for the table */ + int count /* Increment the row change counter */ +){ + int addr; + addr = sqliteVdbeAddOp(v, OP_NotExists, iCur, 0); + sqliteGenerateRowIndexDelete(db, v, pTab, iCur, 0); + sqliteVdbeAddOp(v, OP_Delete, iCur, count); + sqliteVdbeChangeP2(v, addr, sqliteVdbeCurrentAddr(v)); +} + +/* +** This routine generates VDBE code that causes the deletion of all +** index entries associated with a single row of a single table. +** +** The VDBE must be in a particular state when this routine is called. +** These are the requirements: +** +** 1. A read/write cursor pointing to pTab, the table containing the row +** to be deleted, must be opened as cursor number "iCur". +** +** 2. Read/write cursors for all indices of pTab must be open as +** cursor number iCur+i for the i-th index. +** +** 3. The "iCur" cursor must be pointing to the row that is to be +** deleted. +*/ +void sqliteGenerateRowIndexDelete( + sqlite *db, /* The database containing the index */ + Vdbe *v, /* Generate code into this VDBE */ + Table *pTab, /* Table containing the row to be deleted */ + int iCur, /* Cursor number for the table */ + char *aIdxUsed /* Only delete if aIdxUsed!=0 && aIdxUsed[i]!=0 */ +){ + int i; + Index *pIdx; + + for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ + int j; + if( aIdxUsed!=0 && aIdxUsed[i-1]==0 ) continue; + sqliteVdbeAddOp(v, OP_Recno, iCur, 0); + for(j=0; jnColumn; j++){ + int idx = pIdx->aiColumn[j]; + if( idx==pTab->iPKey ){ + sqliteVdbeAddOp(v, OP_Dup, j, 0); + }else{ + sqliteVdbeAddOp(v, OP_Column, iCur, idx); + } + } + sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0); + if( db->file_format>=4 ) sqliteAddIdxKeyType(v, pIdx); + sqliteVdbeAddOp(v, OP_IdxDelete, iCur+i, 0); + } +} diff --git a/sqlitebrowser/sqlitebrowser/sqlite_source/encode.c b/sqlitebrowser/sqlitebrowser/sqlite_source/encode.c new file mode 100755 index 00000000..c411bd0d --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/sqlite_source/encode.c @@ -0,0 +1,246 @@ +/* +** 2002 April 25 +** +** 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 helper routines used to translate binary data into +** a null-terminated string (suitable for use in SQLite) and back again. +** These are convenience routines for use by people who want to store binary +** data in an SQLite database. The code in this file is not used by any other +** part of the SQLite library. +** +** $Id: encode.c,v 1.1.1.1 2003-08-21 02:24:07 tabuleiro Exp $ +*/ +#include +#include "encode.h" + +/* +** How This Encoder Works +** +** The output is allowed to contain any character except 0x27 (') and +** 0x00. This is accomplished by using an escape character to encode +** 0x27 and 0x00 as a two-byte sequence. The escape character is always +** 0x01. An 0x00 is encoded as the two byte sequence 0x01 0x01. The +** 0x27 character is encoded as the two byte sequence 0x01 0x03. Finally, +** the escape character itself is encoded as the two-character sequence +** 0x01 0x02. +** +** To summarize, the encoder works by using an escape sequences as follows: +** +** 0x00 -> 0x01 0x01 +** 0x01 -> 0x01 0x02 +** 0x27 -> 0x01 0x03 +** +** If that were all the encoder did, it would work, but in certain cases +** it could double the size of the encoded string. For example, to +** encode a string of 100 0x27 character would require 100 instances of +** the 0x01 0x03 escape sequence resulting in a 200-character output. +** We would prefer to keep the size of the encoded string smaller than +** this. +** +** To minimize the encoding size, we first add a fixed offset value to each +** byte in the sequence. The addition is module 256. (That is to say, if +** the sum of the original character value and the offset exceeds 256, then +** the higher order bits are truncated.) The offset is chosen to minimize +** the number of characters in the string that need to be escaped. For +** example, in the case above where the string was composed of 100 0x27 +** characters, the offset might be 0x01. Each of the 0x27 characters would +** then be converted into an 0x28 character which would not need to be +** escaped at all and so the 100 character input string would be converted +** into just 100 characters of output. Actually 101 characters of output - +** we have to record the offset used as the first byte in the sequence so +** that the string can be decoded. Since the offset value is stored as +** part of the output string and the output string is not allowed to contain +** characters 0x00 or 0x27, the offset cannot be 0x00 or 0x27. +** +** Here, then, are the encoding steps: +** +** (1) Choose an offset value and make it the first character of +** output. +** +** (2) Copy each input character into the output buffer, one by +** one, adding the offset value as you copy. +** +** (3) If the value of an input character plus offset is 0x00, replace +** that one character by the two-character sequence 0x01 0x01. +** If the sum is 0x01, replace it with 0x01 0x02. If the sum +** is 0x27, replace it with 0x01 0x03. +** +** (4) Put a 0x00 terminator at the end of the output. +** +** Decoding is obvious: +** +** (5) Copy encoded characters except the first into the decode +** buffer. Set the first encoded character aside for use as +** the offset in step 7 below. +** +** (6) Convert each 0x01 0x01 sequence into a single character 0x00. +** Convert 0x01 0x02 into 0x01. Convert 0x01 0x03 into 0x27. +** +** (7) Subtract the offset value that was the first character of +** the encoded buffer from all characters in the output buffer. +** +** The only tricky part is step (1) - how to compute an offset value to +** minimize the size of the output buffer. This is accomplished to testing +** all offset values and picking the one that results in the fewest number +** of escapes. To do that, we first scan the entire input and count the +** number of occurances of each character value in the input. Suppose +** the number of 0x00 characters is N(0), the number of occurances of 0x01 +** is N(1), and so forth up to the number of occurances of 0xff is N(256). +** An offset of 0 is not allowed so we don't have to test it. The number +** of escapes required for an offset of 1 is N(1)+N(2)+N(40). The number +** of escapes required for an offset of 2 is N(2)+N(3)+N(41). And so forth. +** In this way we find the offset that gives the minimum number of escapes, +** and thus minimizes the length of the output string. +*/ + +/* +** Encode a binary buffer "in" of size n bytes so that it contains +** no instances of characters '\'' or '\000'. The output is +** null-terminated and can be used as a string value in an INSERT +** or UPDATE statement. Use sqlite_decode_binary() to convert the +** string back into its original binary. +** +** The result is written into a preallocated output buffer "out". +** "out" must be able to hold at least (256*n + 1262)/253 bytes. +** In other words, the output will be expanded by as much as 3 +** bytes for every 253 bytes of input plus 2 bytes of fixed overhead. +** (This is approximately 2 + 1.019*n or about a 2% size increase.) +** +** The return value is the number of characters in the encoded +** string, excluding the "\000" terminator. +*/ +int sqlite_encode_binary(const unsigned char *in, int n, unsigned char *out){ + int i, j, e, m; + int cnt[256]; + if( n<=0 ){ + out[0] = 'x'; + out[1] = 0; + return 1; + } + memset(cnt, 0, sizeof(cnt)); + for(i=n-1; i>=0; i--){ cnt[in[i]]++; } + m = n; + for(i=1; i<256; i++){ + int sum; + if( i=='\'' ) continue; + sum = cnt[i] + cnt[(i+1)&0xff] + cnt[(i+'\'')&0xff]; + if( sum%d (max %d)", n, strlen(out)+1, m); + if( strlen(out)+1>m ){ + printf(" ERROR output too big\n"); + exit(1); + } + for(j=0; out[j]; j++){ + if( out[j]=='\'' ){ + printf(" ERROR contains (')\n"); + exit(1); + } + } + j = sqlite_decode_binary(out, out); + if( j!=n ){ + printf(" ERROR decode size %d\n", j); + exit(1); + } + if( memcmp(in, out, n)!=0 ){ + printf(" ERROR decode mismatch\n"); + exit(1); + } + printf(" OK\n"); + } +} +#endif /* ENCODER_TEST */ diff --git a/sqlitebrowser/sqlitebrowser/sqlite_source/encode.h b/sqlitebrowser/sqlitebrowser/sqlite_source/encode.h new file mode 100755 index 00000000..655266b8 --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/sqlite_source/encode.h @@ -0,0 +1,18 @@ +#ifndef _ENCODE_H_ +#define _ENCODE_H_ + +/* +** Make sure we can call this stuff from C++. +*/ +#ifdef __cplusplus +extern "C" { +#endif + +int sqlite_encode_binary(const unsigned char *in, int n, unsigned char *out); +int sqlite_decode_binary(const unsigned char *in, unsigned char *out); + +#ifdef __cplusplus +} /* End of the 'extern "C"' block */ +#endif + +#endif /* _ENCODE_H_ */ diff --git a/sqlitebrowser/sqlitebrowser/sqlite_source/expr.c b/sqlitebrowser/sqlitebrowser/sqlite_source/expr.c new file mode 100755 index 00000000..2512868e --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/sqlite_source/expr.c @@ -0,0 +1,1623 @@ +/* +** 2001 September 15 +** +** 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 routines used for analyzing expressions and +** for generating VDBE code that evaluates expressions in SQLite. +** +** $Id: expr.c,v 1.1.1.1 2003-08-21 02:24:08 tabuleiro Exp $ +*/ +#include "sqliteInt.h" +#include + +/* +** Construct a new expression node and return a pointer to it. Memory +** for this node is obtained from sqliteMalloc(). The calling function +** is responsible for making sure the node eventually gets freed. +*/ +Expr *sqliteExpr(int op, Expr *pLeft, Expr *pRight, Token *pToken){ + Expr *pNew; + pNew = sqliteMalloc( sizeof(Expr) ); + if( pNew==0 ){ + sqliteExprDelete(pLeft); + sqliteExprDelete(pRight); + return 0; + } + pNew->op = op; + pNew->pLeft = pLeft; + pNew->pRight = pRight; + if( pToken ){ + assert( pToken->dyn==0 ); + pNew->token = *pToken; + pNew->span = *pToken; + }else{ + pNew->token.dyn = 0; + pNew->token.z = 0; + pNew->token.n = 0; + if( pLeft && pRight ){ + sqliteExprSpan(pNew, &pLeft->span, &pRight->span); + }else{ + pNew->span = pNew->token; + } + } + return pNew; +} + +/* +** Set the Expr.span field of the given expression to span all +** text between the two given tokens. +*/ +void sqliteExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){ + if( pExpr && pRight && pRight->z && pLeft && pLeft->z ){ + if( pLeft->dyn==0 && pRight->dyn==0 ){ + pExpr->span.z = pLeft->z; + pExpr->span.n = pRight->n + Addr(pRight->z) - Addr(pLeft->z); + }else{ + pExpr->span.z = 0; + pExpr->span.n = 0; + pExpr->span.dyn = 0; + } + } +} + +/* +** Construct a new expression node for a function with multiple +** arguments. +*/ +Expr *sqliteExprFunction(ExprList *pList, Token *pToken){ + Expr *pNew; + pNew = sqliteMalloc( sizeof(Expr) ); + if( pNew==0 ){ + sqliteExprListDelete(pList); + return 0; + } + pNew->op = TK_FUNCTION; + pNew->pList = pList; + pNew->token.dyn = 0; + if( pToken ){ + assert( pToken->dyn==0 ); + pNew->token = *pToken; + }else{ + pNew->token.z = 0; + pNew->token.n = 0; + } + pNew->span = pNew->token; + return pNew; +} + +/* +** Recursively delete an expression tree. +*/ +void sqliteExprDelete(Expr *p){ + if( p==0 ) return; + if( p->span.dyn && p->span.z ) sqliteFree((char*)p->span.z); + if( p->token.dyn && p->token.z ) sqliteFree((char*)p->token.z); + if( p->pLeft ) sqliteExprDelete(p->pLeft); + if( p->pRight ) sqliteExprDelete(p->pRight); + if( p->pList ) sqliteExprListDelete(p->pList); + if( p->pSelect ) sqliteSelectDelete(p->pSelect); + sqliteFree(p); +} + + +/* +** The following group of routines make deep copies of expressions, +** expression lists, ID lists, and select statements. The copies can +** be deleted (by being passed to their respective ...Delete() routines) +** without effecting the originals. +** +** The expression list, ID, and source lists return by sqliteExprListDup(), +** sqliteIdListDup(), and sqliteSrcListDup() can not be further expanded +** by subsequent calls to sqlite*ListAppend() routines. +** +** Any tables that the SrcList might point to are not duplicated. +*/ +Expr *sqliteExprDup(Expr *p){ + Expr *pNew; + if( p==0 ) return 0; + pNew = sqliteMallocRaw( sizeof(*p) ); + if( pNew==0 ) return 0; + memcpy(pNew, p, sizeof(*pNew)); + if( p->token.z!=0 ){ + pNew->token.z = sqliteStrDup(p->token.z); + pNew->token.dyn = 1; + }else{ + pNew->token.z = 0; + pNew->token.n = 0; + pNew->token.dyn = 0; + } + pNew->span.z = 0; + pNew->span.n = 0; + pNew->span.dyn = 0; + pNew->pLeft = sqliteExprDup(p->pLeft); + pNew->pRight = sqliteExprDup(p->pRight); + pNew->pList = sqliteExprListDup(p->pList); + pNew->pSelect = sqliteSelectDup(p->pSelect); + return pNew; +} +void sqliteTokenCopy(Token *pTo, Token *pFrom){ + if( pTo->dyn ) sqliteFree((char*)pTo->z); + if( pFrom->z ){ + pTo->n = pFrom->n; + pTo->z = sqliteStrNDup(pFrom->z, pFrom->n); + pTo->dyn = 1; + }else{ + pTo->n = 0; + pTo->z = 0; + pTo->dyn = 0; + } +} +ExprList *sqliteExprListDup(ExprList *p){ + ExprList *pNew; + int i; + if( p==0 ) return 0; + pNew = sqliteMalloc( sizeof(*pNew) ); + if( pNew==0 ) return 0; + pNew->nExpr = p->nExpr; + pNew->a = sqliteMalloc( p->nExpr*sizeof(p->a[0]) ); + if( pNew->a==0 ) return 0; + for(i=0; inExpr; i++){ + Expr *pNewExpr, *pOldExpr; + pNew->a[i].pExpr = pNewExpr = sqliteExprDup(pOldExpr = p->a[i].pExpr); + if( pOldExpr->span.z!=0 && pNewExpr ){ + /* Always make a copy of the span for top-level expressions in the + ** expression list. The logic in SELECT processing that determines + ** the names of columns in the result set needs this information */ + sqliteTokenCopy(&pNewExpr->span, &pOldExpr->span); + } + assert( pNewExpr==0 || pNewExpr->span.z!=0 + || pOldExpr->span.z==0 || sqlite_malloc_failed ); + pNew->a[i].zName = sqliteStrDup(p->a[i].zName); + pNew->a[i].sortOrder = p->a[i].sortOrder; + pNew->a[i].isAgg = p->a[i].isAgg; + pNew->a[i].done = 0; + } + return pNew; +} +SrcList *sqliteSrcListDup(SrcList *p){ + SrcList *pNew; + int i; + int nByte; + if( p==0 ) return 0; + nByte = sizeof(*p) + (p->nSrc>0 ? sizeof(p->a[0]) * (p->nSrc-1) : 0); + pNew = sqliteMalloc( nByte ); + if( pNew==0 ) return 0; + pNew->nSrc = p->nSrc; + for(i=0; inSrc; i++){ + pNew->a[i].zDatabase = sqliteStrDup(p->a[i].zDatabase); + pNew->a[i].zName = sqliteStrDup(p->a[i].zName); + pNew->a[i].zAlias = sqliteStrDup(p->a[i].zAlias); + pNew->a[i].jointype = p->a[i].jointype; + pNew->a[i].iCursor = p->a[i].iCursor; + pNew->a[i].pTab = 0; + pNew->a[i].pSelect = sqliteSelectDup(p->a[i].pSelect); + pNew->a[i].pOn = sqliteExprDup(p->a[i].pOn); + pNew->a[i].pUsing = sqliteIdListDup(p->a[i].pUsing); + } + return pNew; +} +IdList *sqliteIdListDup(IdList *p){ + IdList *pNew; + int i; + if( p==0 ) return 0; + pNew = sqliteMalloc( sizeof(*pNew) ); + if( pNew==0 ) return 0; + pNew->nId = p->nId; + pNew->a = sqliteMalloc( p->nId*sizeof(p->a[0]) ); + if( pNew->a==0 ) return 0; + for(i=0; inId; i++){ + pNew->a[i].zName = sqliteStrDup(p->a[i].zName); + pNew->a[i].idx = p->a[i].idx; + } + return pNew; +} +Select *sqliteSelectDup(Select *p){ + Select *pNew; + if( p==0 ) return 0; + pNew = sqliteMalloc( sizeof(*p) ); + if( pNew==0 ) return 0; + pNew->isDistinct = p->isDistinct; + pNew->pEList = sqliteExprListDup(p->pEList); + pNew->pSrc = sqliteSrcListDup(p->pSrc); + pNew->pWhere = sqliteExprDup(p->pWhere); + pNew->pGroupBy = sqliteExprListDup(p->pGroupBy); + pNew->pHaving = sqliteExprDup(p->pHaving); + pNew->pOrderBy = sqliteExprListDup(p->pOrderBy); + pNew->op = p->op; + pNew->pPrior = sqliteSelectDup(p->pPrior); + pNew->nLimit = p->nLimit; + pNew->nOffset = p->nOffset; + pNew->zSelect = 0; + pNew->iLimit = -1; + pNew->iOffset = -1; + return pNew; +} + + +/* +** Add a new element to the end of an expression list. If pList is +** initially NULL, then create a new expression list. +*/ +ExprList *sqliteExprListAppend(ExprList *pList, Expr *pExpr, Token *pName){ + int i; + if( pList==0 ){ + pList = sqliteMalloc( sizeof(ExprList) ); + if( pList==0 ){ + sqliteExprDelete(pExpr); + return 0; + } + } + if( (pList->nExpr & 7)==0 ){ + int n = pList->nExpr + 8; + struct ExprList_item *a; + a = sqliteRealloc(pList->a, n*sizeof(pList->a[0])); + if( a==0 ){ + sqliteExprDelete(pExpr); + return pList; + } + pList->a = a; + } + if( pExpr || pName ){ + i = pList->nExpr++; + pList->a[i].pExpr = pExpr; + pList->a[i].zName = 0; + if( pName ){ + sqliteSetNString(&pList->a[i].zName, pName->z, pName->n, 0); + sqliteDequote(pList->a[i].zName); + } + } + return pList; +} + +/* +** Delete an entire expression list. +*/ +void sqliteExprListDelete(ExprList *pList){ + int i; + if( pList==0 ) return; + for(i=0; inExpr; i++){ + sqliteExprDelete(pList->a[i].pExpr); + sqliteFree(pList->a[i].zName); + } + sqliteFree(pList->a); + sqliteFree(pList); +} + +/* +** Walk an expression tree. Return 1 if the expression is constant +** and 0 if it involves variables. +** +** For the purposes of this function, a double-quoted string (ex: "abc") +** is considered a variable but a single-quoted string (ex: 'abc') is +** a constant. +*/ +int sqliteExprIsConstant(Expr *p){ + switch( p->op ){ + case TK_ID: + case TK_COLUMN: + case TK_DOT: + case TK_FUNCTION: + return 0; + case TK_NULL: + case TK_STRING: + case TK_INTEGER: + case TK_FLOAT: + return 1; + default: { + if( p->pLeft && !sqliteExprIsConstant(p->pLeft) ) return 0; + if( p->pRight && !sqliteExprIsConstant(p->pRight) ) return 0; + if( p->pList ){ + int i; + for(i=0; ipList->nExpr; i++){ + if( !sqliteExprIsConstant(p->pList->a[i].pExpr) ) return 0; + } + } + return p->pLeft!=0 || p->pRight!=0 || (p->pList && p->pList->nExpr>0); + } + } + return 0; +} + +/* +** If the given expression codes a constant integer, return 1 and put +** the value of the integer in *pValue. If the expression is not an +** integer, return 0 and leave *pValue unchanged. +*/ +int sqliteExprIsInteger(Expr *p, int *pValue){ + switch( p->op ){ + case TK_INTEGER: { + *pValue = atoi(p->token.z); + return 1; + } + case TK_STRING: { + const char *z = p->token.z; + int n = p->token.n; + if( n>0 && z[0]=='-' ){ z++; n--; } + while( n>0 && *z && isdigit(*z) ){ z++; n--; } + if( n==0 ){ + *pValue = atoi(p->token.z); + return 1; + } + break; + } + case TK_UPLUS: { + return sqliteExprIsInteger(p->pLeft, pValue); + } + case TK_UMINUS: { + int v; + if( sqliteExprIsInteger(p->pLeft, &v) ){ + *pValue = -v; + return 1; + } + break; + } + default: break; + } + return 0; +} + +/* +** Return TRUE if the given string is a row-id column name. +*/ +int sqliteIsRowid(const char *z){ + if( sqliteStrICmp(z, "_ROWID_")==0 ) return 1; + if( sqliteStrICmp(z, "ROWID")==0 ) return 1; + if( sqliteStrICmp(z, "OID")==0 ) return 1; + return 0; +} + +/* +** This routine walks an expression tree and resolves references to +** table columns. Nodes of the form ID.ID or ID resolve into an +** index to the table in the table list and a column offset. The +** Expr.opcode for such nodes is changed to TK_COLUMN. The Expr.iTable +** value is changed to the index of the referenced table in pTabList +** plus the "base" value. The base value will ultimately become the +** VDBE cursor number for a cursor that is pointing into the referenced +** table. The Expr.iColumn value is changed to the index of the column +** of the referenced table. The Expr.iColumn value for the special +** ROWID column is -1. Any INTEGER PRIMARY KEY column is tried as an +** alias for ROWID. +** +** We also check for instances of the IN operator. IN comes in two +** forms: +** +** 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. +** +** This routine also looks for scalar SELECTs that are part of an expression. +** If it finds any, it generates code to write the value of that select +** into a memory cell. +** +** Unknown columns or tables provoke an error. The function returns +** the number of errors seen and leaves an error message on pParse->zErrMsg. +*/ +int sqliteExprResolveIds( + Parse *pParse, /* The parser context */ + SrcList *pTabList, /* List of tables used to resolve column names */ + ExprList *pEList, /* List of expressions used to resolve "AS" */ + Expr *pExpr /* The expression to be analyzed. */ +){ + int i; + + if( pExpr==0 || pTabList==0 ) return 0; + for(i=0; inSrc; i++){ + assert( pTabList->a[i].iCursor>=0 && pTabList->a[i].iCursornTab ); + } + switch( pExpr->op ){ + /* Double-quoted strings (ex: "abc") are used as identifiers if + ** possible. Otherwise they remain as strings. Single-quoted + ** strings (ex: 'abc') are always string literals. + */ + case TK_STRING: { + if( pExpr->token.z[0]=='\'' ) break; + /* Fall thru into the TK_ID case if this is a double-quoted string */ + } + /* A lone identifier. Try and match it as follows: + ** + ** 1. To the name of a column of one of the tables in pTabList + ** + ** 2. To the right side of an AS keyword in the column list of + ** a SELECT statement. (For example, match against 'x' in + ** "SELECT a+b AS 'x' FROM t1".) + ** + ** 3. One of the special names "ROWID", "OID", or "_ROWID_". + */ + case TK_ID: { + int cnt = 0; /* Number of matches */ + char *z; + int iDb = -1; + + assert( pExpr->token.z ); + z = sqliteStrNDup(pExpr->token.z, pExpr->token.n); + sqliteDequote(z); + if( z==0 ) return 1; + for(i=0; inSrc; i++){ + int j; + Table *pTab = pTabList->a[i].pTab; + if( pTab==0 ) continue; + iDb = pTab->iDb; + assert( pTab->nCol>0 ); + for(j=0; jnCol; j++){ + if( sqliteStrICmp(pTab->aCol[j].zName, z)==0 ){ + cnt++; + pExpr->iTable = pTabList->a[i].iCursor; + pExpr->iDb = pTab->iDb; + if( j==pTab->iPKey ){ + /* Substitute the record number for the INTEGER PRIMARY KEY */ + pExpr->iColumn = -1; + pExpr->dataType = SQLITE_SO_NUM; + }else{ + pExpr->iColumn = j; + pExpr->dataType = pTab->aCol[j].sortOrder & SQLITE_SO_TYPEMASK; + } + pExpr->op = TK_COLUMN; + } + } + } + if( cnt==0 && pEList!=0 ){ + int j; + for(j=0; jnExpr; j++){ + char *zAs = pEList->a[j].zName; + if( zAs!=0 && sqliteStrICmp(zAs, z)==0 ){ + cnt++; + assert( pExpr->pLeft==0 && pExpr->pRight==0 ); + pExpr->op = TK_AS; + pExpr->iColumn = j; + pExpr->pLeft = sqliteExprDup(pEList->a[j].pExpr); + } + } + } + if( cnt==0 && iDb>=0 && sqliteIsRowid(z) ){ + pExpr->iColumn = -1; + pExpr->iTable = pTabList->a[0].iCursor; + pExpr->iDb = iDb; + cnt = 1 + (pTabList->nSrc>1); + pExpr->op = TK_COLUMN; + pExpr->dataType = SQLITE_SO_NUM; + } + sqliteFree(z); + if( cnt==0 && pExpr->token.z[0]!='"' ){ + sqliteErrorMsg(pParse, "no such column: %T", &pExpr->token); + return 1; + }else if( cnt>1 ){ + sqliteErrorMsg(pParse, "ambiguous column name: %T", &pExpr->token); + return 1; + } + if( pExpr->op==TK_COLUMN ){ + sqliteAuthRead(pParse, pExpr, pTabList); + } + break; + } + + /* A table name and column name: ID.ID + ** Or a database, table and column: ID.ID.ID + */ + case TK_DOT: { + int cnt = 0; /* Number of matches */ + int cntTab = 0; /* Number of matching tables */ + int i; /* Loop counter */ + Expr *pLeft, *pRight; /* Left and right subbranches of the expr */ + char *zLeft, *zRight; /* Text of an identifier */ + char *zDb; /* Name of database holding table */ + sqlite *db = pParse->db; + + pRight = pExpr->pRight; + if( pRight->op==TK_ID ){ + pLeft = pExpr->pLeft; + zDb = 0; + }else{ + Expr *pDb = pExpr->pLeft; + assert( pDb && pDb->op==TK_ID && pDb->token.z ); + zDb = sqliteStrNDup(pDb->token.z, pDb->token.n); + pLeft = pRight->pLeft; + pRight = pRight->pRight; + } + assert( pLeft && pLeft->op==TK_ID && pLeft->token.z ); + assert( pRight && pRight->op==TK_ID && pRight->token.z ); + zLeft = sqliteStrNDup(pLeft->token.z, pLeft->token.n); + zRight = sqliteStrNDup(pRight->token.z, pRight->token.n); + if( zLeft==0 || zRight==0 ){ + sqliteFree(zLeft); + sqliteFree(zRight); + sqliteFree(zDb); + return 1; + } + sqliteDequote(zDb); + sqliteDequote(zLeft); + sqliteDequote(zRight); + pExpr->iTable = -1; + for(i=0; inSrc; i++){ + int j; + char *zTab; + Table *pTab = pTabList->a[i].pTab; + if( pTab==0 ) continue; + assert( pTab->nCol>0 ); + if( pTabList->a[i].zAlias ){ + zTab = pTabList->a[i].zAlias; + if( sqliteStrICmp(zTab, zLeft)!=0 ) continue; + }else{ + zTab = pTab->zName; + if( zTab==0 || sqliteStrICmp(zTab, zLeft)!=0 ) continue; + if( zDb!=0 && sqliteStrICmp(db->aDb[pTab->iDb].zName, zDb)!=0 ){ + continue; + } + } + if( 0==(cntTab++) ){ + pExpr->iTable = pTabList->a[i].iCursor; + pExpr->iDb = pTab->iDb; + } + for(j=0; jnCol; j++){ + if( sqliteStrICmp(pTab->aCol[j].zName, zRight)==0 ){ + cnt++; + pExpr->iTable = pTabList->a[i].iCursor; + pExpr->iDb = pTab->iDb; + /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */ + pExpr->iColumn = j==pTab->iPKey ? -1 : j; + pExpr->dataType = pTab->aCol[j].sortOrder & SQLITE_SO_TYPEMASK; + } + } + } + + /* If we have not already resolved this *.* expression, then maybe + * it is a new.* or old.* trigger argument reference */ + if( cnt == 0 && pParse->trigStack != 0 ){ + TriggerStack *pTriggerStack = pParse->trigStack; + int t = 0; + if( pTriggerStack->newIdx != -1 && sqliteStrICmp("new", zLeft) == 0 ){ + pExpr->iTable = pTriggerStack->newIdx; + assert( pTriggerStack->pTab ); + pExpr->iDb = pTriggerStack->pTab->iDb; + cntTab++; + t = 1; + } + if( pTriggerStack->oldIdx != -1 && sqliteStrICmp("old", zLeft) == 0 ){ + pExpr->iTable = pTriggerStack->oldIdx; + assert( pTriggerStack->pTab ); + pExpr->iDb = pTriggerStack->pTab->iDb; + cntTab++; + t = 1; + } + + if( t ){ + int j; + Table *pTab = pTriggerStack->pTab; + for(j=0; j < pTab->nCol; j++) { + if( sqliteStrICmp(pTab->aCol[j].zName, zRight)==0 ){ + cnt++; + pExpr->iColumn = j==pTab->iPKey ? -1 : j; + pExpr->dataType = pTab->aCol[j].sortOrder & SQLITE_SO_TYPEMASK; + } + } + } + } + + if( cnt==0 && cntTab==1 && sqliteIsRowid(zRight) ){ + cnt = 1; + pExpr->iColumn = -1; + pExpr->dataType = SQLITE_SO_NUM; + } + sqliteFree(zDb); + sqliteFree(zLeft); + sqliteFree(zRight); + if( cnt==0 ){ + sqliteErrorMsg(pParse, "no such column: %T.%T", + &pLeft->token, &pRight->token); + return 1; + }else if( cnt>1 ){ + sqliteErrorMsg(pParse, "ambiguous column name: %T.%T", + &pLeft->token, &pRight->token); + return 1; + } + sqliteExprDelete(pExpr->pLeft); + pExpr->pLeft = 0; + sqliteExprDelete(pExpr->pRight); + pExpr->pRight = 0; + pExpr->op = TK_COLUMN; + sqliteAuthRead(pParse, pExpr, pTabList); + break; + } + + case TK_IN: { + Vdbe *v = sqliteGetVdbe(pParse); + if( v==0 ) return 1; + if( sqliteExprResolveIds(pParse, pTabList, pEList, pExpr->pLeft) ){ + return 1; + } + if( pExpr->pSelect ){ + /* Case 1: expr IN (SELECT ...) + ** + ** Generate code to write the results of the select into a temporary + ** table. The cursor number of the temporary table has already + ** been put in iTable by sqliteExprResolveInSelect(). + */ + pExpr->iTable = pParse->nTab++; + sqliteVdbeAddOp(v, OP_OpenTemp, pExpr->iTable, 1); + sqliteSelect(pParse, pExpr->pSelect, SRT_Set, pExpr->iTable, 0,0,0); + }else if( pExpr->pList ){ + /* Case 2: expr IN (exprlist) + ** + ** Create a set to put the exprlist values in. The Set id is stored + ** in iTable. + */ + int i, iSet; + for(i=0; ipList->nExpr; i++){ + Expr *pE2 = pExpr->pList->a[i].pExpr; + if( !sqliteExprIsConstant(pE2) ){ + sqliteErrorMsg(pParse, + "right-hand side of IN operator must be constant"); + return 1; + } + if( sqliteExprCheck(pParse, pE2, 0, 0) ){ + return 1; + } + } + iSet = pExpr->iTable = pParse->nSet++; + for(i=0; ipList->nExpr; i++){ + Expr *pE2 = pExpr->pList->a[i].pExpr; + switch( pE2->op ){ + case TK_FLOAT: + case TK_INTEGER: + case TK_STRING: { + int addr = sqliteVdbeAddOp(v, OP_SetInsert, iSet, 0); + assert( pE2->token.z ); + sqliteVdbeChangeP3(v, addr, pE2->token.z, pE2->token.n); + sqliteVdbeDequoteP3(v, addr); + break; + } + default: { + sqliteExprCode(pParse, pE2); + sqliteVdbeAddOp(v, OP_SetInsert, iSet, 0); + break; + } + } + } + } + break; + } + + case TK_SELECT: { + /* This has to be a scalar SELECT. Generate code to put the + ** value of this select in a memory cell and record the number + ** of the memory cell in iColumn. + */ + pExpr->iColumn = pParse->nMem++; + if( sqliteSelect(pParse, pExpr->pSelect, SRT_Mem, pExpr->iColumn,0,0,0) ){ + return 1; + } + break; + } + + /* For all else, just recursively walk the tree */ + default: { + if( pExpr->pLeft + && sqliteExprResolveIds(pParse, pTabList, pEList, pExpr->pLeft) ){ + return 1; + } + if( pExpr->pRight + && sqliteExprResolveIds(pParse, pTabList, pEList, pExpr->pRight) ){ + return 1; + } + if( pExpr->pList ){ + int i; + ExprList *pList = pExpr->pList; + for(i=0; inExpr; i++){ + Expr *pArg = pList->a[i].pExpr; + if( sqliteExprResolveIds(pParse, pTabList, pEList, pArg) ){ + return 1; + } + } + } + } + } + return 0; +} + +/* +** pExpr is a node that defines a function of some kind. It might +** be a syntactic function like "count(x)" or it might be a function +** that implements an operator, like "a LIKE b". +** +** This routine makes *pzName point to the name of the function and +** *pnName hold the number of characters in the function name. +*/ +static void getFunctionName(Expr *pExpr, const char **pzName, int *pnName){ + switch( pExpr->op ){ + case TK_FUNCTION: { + *pzName = pExpr->token.z; + *pnName = pExpr->token.n; + break; + } + case TK_LIKE: { + *pzName = "like"; + *pnName = 4; + break; + } + case TK_GLOB: { + *pzName = "glob"; + *pnName = 4; + break; + } + default: { + *pzName = "can't happen"; + *pnName = 12; + break; + } + } +} + +/* +** Error check the functions in an expression. Make sure all +** function names are recognized and all functions have the correct +** number of arguments. Leave an error message in pParse->zErrMsg +** if anything is amiss. Return the number of errors. +** +** if pIsAgg is not null and this expression is an aggregate function +** (like count(*) or max(value)) then write a 1 into *pIsAgg. +*/ +int sqliteExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){ + int nErr = 0; + if( pExpr==0 ) return 0; + switch( pExpr->op ){ + case TK_GLOB: + case TK_LIKE: + case TK_FUNCTION: { + int n = pExpr->pList ? pExpr->pList->nExpr : 0; /* Number of arguments */ + int no_such_func = 0; /* True if no such function exists */ + int is_type_of = 0; /* True if is the special TypeOf() function */ + int wrong_num_args = 0; /* True if wrong number of arguments */ + int is_agg = 0; /* True if is an aggregate function */ + int i; + int nId; /* Number of characters in function name */ + const char *zId; /* The function name. */ + FuncDef *pDef; + + getFunctionName(pExpr, &zId, &nId); + pDef = sqliteFindFunction(pParse->db, zId, nId, n, 0); + if( pDef==0 ){ + pDef = sqliteFindFunction(pParse->db, zId, nId, -1, 0); + if( pDef==0 ){ + if( n==1 && nId==6 && sqliteStrNICmp(zId, "typeof", 6)==0 ){ + is_type_of = 1; + }else { + no_such_func = 1; + } + }else{ + wrong_num_args = 1; + } + }else{ + is_agg = pDef->xFunc==0; + } + if( is_agg && !allowAgg ){ + sqliteSetNString(&pParse->zErrMsg, "misuse of aggregate function ", -1, + zId, nId, "()", 2, 0); + pParse->nErr++; + nErr++; + is_agg = 0; + }else if( no_such_func ){ + sqliteSetNString(&pParse->zErrMsg, "no such function: ", -1, zId,nId,0); + pParse->nErr++; + nErr++; + }else if( wrong_num_args ){ + sqliteSetNString(&pParse->zErrMsg, + "wrong number of arguments to function ", -1, zId, nId, "()", 2, 0); + pParse->nErr++; + nErr++; + } + if( is_agg ) pExpr->op = TK_AGG_FUNCTION; + if( is_agg && pIsAgg ) *pIsAgg = 1; + for(i=0; nErr==0 && ipList->a[i].pExpr, + allowAgg && !is_agg, pIsAgg); + } + if( pDef==0 ){ + if( is_type_of ){ + pExpr->op = TK_STRING; + if( sqliteExprType(pExpr->pList->a[0].pExpr)==SQLITE_SO_NUM ){ + pExpr->token.z = "numeric"; + pExpr->token.n = 7; + }else{ + pExpr->token.z = "text"; + pExpr->token.n = 4; + } + } + }else if( pDef->dataType>=0 ){ + if( pDef->dataTypedataType = + sqliteExprType(pExpr->pList->a[pDef->dataType].pExpr); + }else{ + pExpr->dataType = SQLITE_SO_NUM; + } + }else if( pDef->dataType==SQLITE_ARGS ){ + pDef->dataType = SQLITE_SO_TEXT; + for(i=0; ipList->a[i].pExpr)==SQLITE_SO_NUM ){ + pExpr->dataType = SQLITE_SO_NUM; + break; + } + } + }else if( pDef->dataType==SQLITE_NUMERIC ){ + pExpr->dataType = SQLITE_SO_NUM; + }else{ + pExpr->dataType = SQLITE_SO_TEXT; + } + } + default: { + if( pExpr->pLeft ){ + nErr = sqliteExprCheck(pParse, pExpr->pLeft, allowAgg, pIsAgg); + } + if( nErr==0 && pExpr->pRight ){ + nErr = sqliteExprCheck(pParse, pExpr->pRight, allowAgg, pIsAgg); + } + if( nErr==0 && pExpr->pList ){ + int n = pExpr->pList->nExpr; + int i; + for(i=0; nErr==0 && ipList->a[i].pExpr; + nErr = sqliteExprCheck(pParse, pE2, allowAgg, pIsAgg); + } + } + break; + } + } + return nErr; +} + +/* +** Return either SQLITE_SO_NUM or SQLITE_SO_TEXT to indicate whether the +** given expression should sort as numeric values or as text. +** +** The sqliteExprResolveIds() and sqliteExprCheck() routines must have +** both been called on the expression before it is passed to this routine. +*/ +int sqliteExprType(Expr *p){ + if( p==0 ) return SQLITE_SO_NUM; + while( p ) switch( p->op ){ + case TK_PLUS: + case TK_MINUS: + case TK_STAR: + case TK_SLASH: + case TK_AND: + case TK_OR: + case TK_ISNULL: + case TK_NOTNULL: + case TK_NOT: + case TK_UMINUS: + case TK_UPLUS: + case TK_BITAND: + case TK_BITOR: + case TK_BITNOT: + case TK_LSHIFT: + case TK_RSHIFT: + case TK_REM: + case TK_INTEGER: + case TK_FLOAT: + case TK_IN: + case TK_BETWEEN: + case TK_GLOB: + case TK_LIKE: + return SQLITE_SO_NUM; + + case TK_STRING: + case TK_NULL: + case TK_CONCAT: + return SQLITE_SO_TEXT; + + case TK_LT: + case TK_LE: + case TK_GT: + case TK_GE: + case TK_NE: + case TK_EQ: + if( sqliteExprType(p->pLeft)==SQLITE_SO_NUM ){ + return SQLITE_SO_NUM; + } + p = p->pRight; + break; + + case TK_AS: + p = p->pLeft; + break; + + case TK_COLUMN: + case TK_FUNCTION: + case TK_AGG_FUNCTION: + return p->dataType; + + case TK_SELECT: + assert( p->pSelect ); + assert( p->pSelect->pEList ); + assert( p->pSelect->pEList->nExpr>0 ); + p = p->pSelect->pEList->a[0].pExpr; + break; + + case TK_CASE: { + if( p->pRight && sqliteExprType(p->pRight)==SQLITE_SO_NUM ){ + return SQLITE_SO_NUM; + } + if( p->pList ){ + int i; + ExprList *pList = p->pList; + for(i=1; inExpr; i+=2){ + if( sqliteExprType(pList->a[i].pExpr)==SQLITE_SO_NUM ){ + return SQLITE_SO_NUM; + } + } + } + return SQLITE_SO_TEXT; + } + + default: + assert( p->op==TK_ABORT ); /* Can't Happen */ + break; + } + return SQLITE_SO_NUM; +} + +/* +** Generate code into the current Vdbe to evaluate the given +** expression and leave the result on the top of stack. +*/ +void sqliteExprCode(Parse *pParse, Expr *pExpr){ + Vdbe *v = pParse->pVdbe; + int op; + if( v==0 || pExpr==0 ) return; + switch( pExpr->op ){ + case TK_PLUS: op = OP_Add; break; + case TK_MINUS: op = OP_Subtract; break; + case TK_STAR: op = OP_Multiply; break; + case TK_SLASH: op = OP_Divide; break; + case TK_AND: op = OP_And; break; + case TK_OR: op = OP_Or; break; + case TK_LT: op = OP_Lt; break; + case TK_LE: op = OP_Le; break; + case TK_GT: op = OP_Gt; break; + case TK_GE: op = OP_Ge; break; + case TK_NE: op = OP_Ne; break; + case TK_EQ: op = OP_Eq; break; + case TK_ISNULL: op = OP_IsNull; break; + case TK_NOTNULL: op = OP_NotNull; break; + case TK_NOT: op = OP_Not; break; + case TK_UMINUS: op = OP_Negative; break; + case TK_BITAND: op = OP_BitAnd; break; + case TK_BITOR: op = OP_BitOr; break; + case TK_BITNOT: op = OP_BitNot; break; + case TK_LSHIFT: op = OP_ShiftLeft; break; + case TK_RSHIFT: op = OP_ShiftRight; break; + case TK_REM: op = OP_Remainder; break; + default: break; + } + switch( pExpr->op ){ + case TK_COLUMN: { + if( pParse->useAgg ){ + sqliteVdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg); + }else if( pExpr->iColumn>=0 ){ + sqliteVdbeAddOp(v, OP_Column, pExpr->iTable, pExpr->iColumn); + }else{ + sqliteVdbeAddOp(v, OP_Recno, pExpr->iTable, 0); + } + break; + } + case TK_INTEGER: { + int iVal = atoi(pExpr->token.z); + char zBuf[30]; + sprintf(zBuf,"%d",iVal); + if( strlen(zBuf)!=pExpr->token.n + || strncmp(pExpr->token.z,zBuf,pExpr->token.n)!=0 ){ + /* If the integer value cannot be represented exactly in 32 bits, + ** then code it as a string instead. */ + sqliteVdbeAddOp(v, OP_String, 0, 0); + }else{ + sqliteVdbeAddOp(v, OP_Integer, iVal, 0); + } + sqliteVdbeChangeP3(v, -1, pExpr->token.z, pExpr->token.n); + break; + } + case TK_FLOAT: { + sqliteVdbeAddOp(v, OP_String, 0, 0); + assert( pExpr->token.z ); + sqliteVdbeChangeP3(v, -1, pExpr->token.z, pExpr->token.n); + break; + } + case TK_STRING: { + int addr = sqliteVdbeAddOp(v, OP_String, 0, 0); + assert( pExpr->token.z ); + sqliteVdbeChangeP3(v, addr, pExpr->token.z, pExpr->token.n); + sqliteVdbeDequoteP3(v, addr); + break; + } + case TK_NULL: { + sqliteVdbeAddOp(v, OP_String, 0, 0); + break; + } + case TK_LT: + case TK_LE: + case TK_GT: + case TK_GE: + case TK_NE: + case TK_EQ: { + if( pParse->db->file_format>=4 && sqliteExprType(pExpr)==SQLITE_SO_TEXT ){ + op += 6; /* Convert numeric opcodes to text opcodes */ + } + /* Fall through into the next case */ + } + case TK_AND: + case TK_OR: + case TK_PLUS: + case TK_STAR: + case TK_MINUS: + case TK_REM: + case TK_BITAND: + case TK_BITOR: + case TK_SLASH: { + sqliteExprCode(pParse, pExpr->pLeft); + sqliteExprCode(pParse, pExpr->pRight); + sqliteVdbeAddOp(v, op, 0, 0); + break; + } + case TK_LSHIFT: + case TK_RSHIFT: { + sqliteExprCode(pParse, pExpr->pRight); + sqliteExprCode(pParse, pExpr->pLeft); + sqliteVdbeAddOp(v, op, 0, 0); + break; + } + case TK_CONCAT: { + sqliteExprCode(pParse, pExpr->pLeft); + sqliteExprCode(pParse, pExpr->pRight); + sqliteVdbeAddOp(v, OP_Concat, 2, 0); + break; + } + case TK_UPLUS: { + Expr *pLeft = pExpr->pLeft; + if( pLeft && pLeft->op==TK_INTEGER ){ + sqliteVdbeAddOp(v, OP_Integer, atoi(pLeft->token.z), 0); + sqliteVdbeChangeP3(v, -1, pLeft->token.z, pLeft->token.n); + }else if( pLeft && pLeft->op==TK_FLOAT ){ + sqliteVdbeAddOp(v, OP_String, 0, 0); + sqliteVdbeChangeP3(v, -1, pLeft->token.z, pLeft->token.n); + }else{ + sqliteExprCode(pParse, pExpr->pLeft); + } + break; + } + case TK_UMINUS: { + assert( pExpr->pLeft ); + if( pExpr->pLeft->op==TK_FLOAT || pExpr->pLeft->op==TK_INTEGER ){ + Token *p = &pExpr->pLeft->token; + char *z = sqliteMalloc( p->n + 2 ); + sprintf(z, "-%.*s", p->n, p->z); + if( pExpr->pLeft->op==TK_INTEGER ){ + sqliteVdbeAddOp(v, OP_Integer, atoi(z), 0); + }else{ + sqliteVdbeAddOp(v, OP_String, 0, 0); + } + sqliteVdbeChangeP3(v, -1, z, p->n+1); + sqliteFree(z); + break; + } + /* Fall through into TK_NOT */ + } + case TK_BITNOT: + case TK_NOT: { + sqliteExprCode(pParse, pExpr->pLeft); + sqliteVdbeAddOp(v, op, 0, 0); + break; + } + case TK_ISNULL: + case TK_NOTNULL: { + int dest; + sqliteVdbeAddOp(v, OP_Integer, 1, 0); + sqliteExprCode(pParse, pExpr->pLeft); + dest = sqliteVdbeCurrentAddr(v) + 2; + sqliteVdbeAddOp(v, op, 1, dest); + sqliteVdbeAddOp(v, OP_AddImm, -1, 0); + break; + } + case TK_AGG_FUNCTION: { + sqliteVdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg); + break; + } + case TK_GLOB: + case TK_LIKE: + case TK_FUNCTION: { + int i; + ExprList *pList = pExpr->pList; + int nExpr = pList ? pList->nExpr : 0; + FuncDef *pDef; + int nId; + const char *zId; + getFunctionName(pExpr, &zId, &nId); + pDef = sqliteFindFunction(pParse->db, zId, nId, nExpr, 0); + assert( pDef!=0 ); + for(i=0; ia[i].pExpr); + } + sqliteVdbeAddOp(v, OP_Function, nExpr, 0); + sqliteVdbeChangeP3(v, -1, (char*)pDef, P3_POINTER); + break; + } + case TK_SELECT: { + sqliteVdbeAddOp(v, OP_MemLoad, pExpr->iColumn, 0); + break; + } + case TK_IN: { + int addr; + sqliteVdbeAddOp(v, OP_Integer, 1, 0); + sqliteExprCode(pParse, pExpr->pLeft); + addr = sqliteVdbeCurrentAddr(v); + sqliteVdbeAddOp(v, OP_NotNull, -1, addr+4); + sqliteVdbeAddOp(v, OP_Pop, 1, 0); + sqliteVdbeAddOp(v, OP_String, 0, 0); + sqliteVdbeAddOp(v, OP_Goto, 0, addr+6); + if( pExpr->pSelect ){ + sqliteVdbeAddOp(v, OP_Found, pExpr->iTable, addr+6); + }else{ + sqliteVdbeAddOp(v, OP_SetFound, pExpr->iTable, addr+6); + } + sqliteVdbeAddOp(v, OP_AddImm, -1, 0); + break; + } + case TK_BETWEEN: { + sqliteExprCode(pParse, pExpr->pLeft); + sqliteVdbeAddOp(v, OP_Dup, 0, 0); + sqliteExprCode(pParse, pExpr->pList->a[0].pExpr); + sqliteVdbeAddOp(v, OP_Ge, 0, 0); + sqliteVdbeAddOp(v, OP_Pull, 1, 0); + sqliteExprCode(pParse, pExpr->pList->a[1].pExpr); + sqliteVdbeAddOp(v, OP_Le, 0, 0); + sqliteVdbeAddOp(v, OP_And, 0, 0); + break; + } + case TK_AS: { + sqliteExprCode(pParse, pExpr->pLeft); + break; + } + case TK_CASE: { + int expr_end_label; + int jumpInst; + int addr; + int nExpr; + int i; + + assert(pExpr->pList); + assert((pExpr->pList->nExpr % 2) == 0); + assert(pExpr->pList->nExpr > 0); + nExpr = pExpr->pList->nExpr; + expr_end_label = sqliteVdbeMakeLabel(v); + if( pExpr->pLeft ){ + sqliteExprCode(pParse, pExpr->pLeft); + } + for(i=0; ipList->a[i].pExpr); + if( pExpr->pLeft ){ + sqliteVdbeAddOp(v, OP_Dup, 1, 1); + jumpInst = sqliteVdbeAddOp(v, OP_Ne, 1, 0); + sqliteVdbeAddOp(v, OP_Pop, 1, 0); + }else{ + jumpInst = sqliteVdbeAddOp(v, OP_IfNot, 1, 0); + } + sqliteExprCode(pParse, pExpr->pList->a[i+1].pExpr); + sqliteVdbeAddOp(v, OP_Goto, 0, expr_end_label); + addr = sqliteVdbeCurrentAddr(v); + sqliteVdbeChangeP2(v, jumpInst, addr); + } + if( pExpr->pLeft ){ + sqliteVdbeAddOp(v, OP_Pop, 1, 0); + } + if( pExpr->pRight ){ + sqliteExprCode(pParse, pExpr->pRight); + }else{ + sqliteVdbeAddOp(v, OP_String, 0, 0); + } + sqliteVdbeResolveLabel(v, expr_end_label); + break; + } + case TK_RAISE: { + if( !pParse->trigStack ){ + sqliteErrorMsg(pParse, + "RAISE() may only be used within a trigger-program"); + pParse->nErr++; + return; + } + if( pExpr->iColumn == OE_Rollback || + pExpr->iColumn == OE_Abort || + pExpr->iColumn == OE_Fail ){ + char * msg = sqliteStrNDup(pExpr->token.z, pExpr->token.n); + sqliteVdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, pExpr->iColumn); + sqliteDequote(msg); + sqliteVdbeChangeP3(v, -1, msg, 0); + sqliteFree(msg); + } else { + assert( pExpr->iColumn == OE_Ignore ); + sqliteVdbeAddOp(v, OP_Goto, 0, pParse->trigStack->ignoreJump); + sqliteVdbeChangeP3(v, -1, "(IGNORE jump)", 0); + } + } + break; + } +} + +/* +** Generate code for a boolean expression such that a jump is made +** to the label "dest" if the expression is true but execution +** continues straight thru if the expression is false. +** +** If the expression evaluates to NULL (neither true nor false), then +** take the jump if the jumpIfNull flag is true. +*/ +void sqliteExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ + Vdbe *v = pParse->pVdbe; + int op = 0; + if( v==0 || pExpr==0 ) return; + switch( pExpr->op ){ + case TK_LT: op = OP_Lt; break; + case TK_LE: op = OP_Le; break; + case TK_GT: op = OP_Gt; break; + case TK_GE: op = OP_Ge; break; + case TK_NE: op = OP_Ne; break; + case TK_EQ: op = OP_Eq; break; + case TK_ISNULL: op = OP_IsNull; break; + case TK_NOTNULL: op = OP_NotNull; break; + default: break; + } + switch( pExpr->op ){ + case TK_AND: { + int d2 = sqliteVdbeMakeLabel(v); + sqliteExprIfFalse(pParse, pExpr->pLeft, d2, !jumpIfNull); + sqliteExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); + sqliteVdbeResolveLabel(v, d2); + break; + } + case TK_OR: { + sqliteExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); + sqliteExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); + break; + } + case TK_NOT: { + sqliteExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); + break; + } + case TK_LT: + case TK_LE: + case TK_GT: + case TK_GE: + case TK_NE: + case TK_EQ: { + sqliteExprCode(pParse, pExpr->pLeft); + sqliteExprCode(pParse, pExpr->pRight); + if( pParse->db->file_format>=4 && sqliteExprType(pExpr)==SQLITE_SO_TEXT ){ + op += 6; /* Convert numeric opcodes to text opcodes */ + } + sqliteVdbeAddOp(v, op, jumpIfNull, dest); + break; + } + case TK_ISNULL: + case TK_NOTNULL: { + sqliteExprCode(pParse, pExpr->pLeft); + sqliteVdbeAddOp(v, op, 1, dest); + break; + } + case TK_IN: { + int addr; + sqliteExprCode(pParse, pExpr->pLeft); + addr = sqliteVdbeCurrentAddr(v); + sqliteVdbeAddOp(v, OP_NotNull, -1, addr+3); + sqliteVdbeAddOp(v, OP_Pop, 1, 0); + sqliteVdbeAddOp(v, OP_Goto, 0, jumpIfNull ? dest : addr+4); + if( pExpr->pSelect ){ + sqliteVdbeAddOp(v, OP_Found, pExpr->iTable, dest); + }else{ + sqliteVdbeAddOp(v, OP_SetFound, pExpr->iTable, dest); + } + break; + } + case TK_BETWEEN: { + int addr; + sqliteExprCode(pParse, pExpr->pLeft); + sqliteVdbeAddOp(v, OP_Dup, 0, 0); + sqliteExprCode(pParse, pExpr->pList->a[0].pExpr); + addr = sqliteVdbeAddOp(v, OP_Lt, !jumpIfNull, 0); + sqliteExprCode(pParse, pExpr->pList->a[1].pExpr); + sqliteVdbeAddOp(v, OP_Le, jumpIfNull, dest); + sqliteVdbeAddOp(v, OP_Integer, 0, 0); + sqliteVdbeChangeP2(v, addr, sqliteVdbeCurrentAddr(v)); + sqliteVdbeAddOp(v, OP_Pop, 1, 0); + break; + } + default: { + sqliteExprCode(pParse, pExpr); + sqliteVdbeAddOp(v, OP_If, jumpIfNull, dest); + break; + } + } +} + +/* +** Generate code for a boolean expression such that a jump is made +** to the label "dest" if the expression is false but execution +** continues straight thru if the expression is true. +** +** If the expression evaluates to NULL (neither true nor false) then +** jump if jumpIfNull is true or fall through if jumpIfNull is false. +*/ +void sqliteExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ + Vdbe *v = pParse->pVdbe; + int op = 0; + if( v==0 || pExpr==0 ) return; + switch( pExpr->op ){ + case TK_LT: op = OP_Ge; break; + case TK_LE: op = OP_Gt; break; + case TK_GT: op = OP_Le; break; + case TK_GE: op = OP_Lt; break; + case TK_NE: op = OP_Eq; break; + case TK_EQ: op = OP_Ne; break; + case TK_ISNULL: op = OP_NotNull; break; + case TK_NOTNULL: op = OP_IsNull; break; + default: break; + } + switch( pExpr->op ){ + case TK_AND: { + sqliteExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); + sqliteExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); + break; + } + case TK_OR: { + int d2 = sqliteVdbeMakeLabel(v); + sqliteExprIfTrue(pParse, pExpr->pLeft, d2, !jumpIfNull); + sqliteExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); + sqliteVdbeResolveLabel(v, d2); + break; + } + case TK_NOT: { + sqliteExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); + break; + } + case TK_LT: + case TK_LE: + case TK_GT: + case TK_GE: + case TK_NE: + case TK_EQ: { + if( pParse->db->file_format>=4 && sqliteExprType(pExpr)==SQLITE_SO_TEXT ){ + /* Convert numeric comparison opcodes into text comparison opcodes. + ** This step depends on the fact that the text comparision opcodes are + ** always 6 greater than their corresponding numeric comparison + ** opcodes. + */ + assert( OP_Eq+6 == OP_StrEq ); + op += 6; + } + sqliteExprCode(pParse, pExpr->pLeft); + sqliteExprCode(pParse, pExpr->pRight); + sqliteVdbeAddOp(v, op, jumpIfNull, dest); + break; + } + case TK_ISNULL: + case TK_NOTNULL: { + sqliteExprCode(pParse, pExpr->pLeft); + sqliteVdbeAddOp(v, op, 1, dest); + break; + } + case TK_IN: { + int addr; + sqliteExprCode(pParse, pExpr->pLeft); + addr = sqliteVdbeCurrentAddr(v); + sqliteVdbeAddOp(v, OP_NotNull, -1, addr+3); + sqliteVdbeAddOp(v, OP_Pop, 1, 0); + sqliteVdbeAddOp(v, OP_Goto, 0, jumpIfNull ? dest : addr+4); + if( pExpr->pSelect ){ + sqliteVdbeAddOp(v, OP_NotFound, pExpr->iTable, dest); + }else{ + sqliteVdbeAddOp(v, OP_SetNotFound, pExpr->iTable, dest); + } + break; + } + case TK_BETWEEN: { + int addr; + sqliteExprCode(pParse, pExpr->pLeft); + sqliteVdbeAddOp(v, OP_Dup, 0, 0); + sqliteExprCode(pParse, pExpr->pList->a[0].pExpr); + addr = sqliteVdbeCurrentAddr(v); + sqliteVdbeAddOp(v, OP_Ge, !jumpIfNull, addr+3); + sqliteVdbeAddOp(v, OP_Pop, 1, 0); + sqliteVdbeAddOp(v, OP_Goto, 0, dest); + sqliteExprCode(pParse, pExpr->pList->a[1].pExpr); + sqliteVdbeAddOp(v, OP_Gt, jumpIfNull, dest); + break; + } + default: { + sqliteExprCode(pParse, pExpr); + sqliteVdbeAddOp(v, OP_IfNot, jumpIfNull, dest); + break; + } + } +} + +/* +** Do a deep comparison of two expression trees. Return TRUE (non-zero) +** if they are identical and return FALSE if they differ in any way. +*/ +int sqliteExprCompare(Expr *pA, Expr *pB){ + int i; + if( pA==0 ){ + return pB==0; + }else if( pB==0 ){ + return 0; + } + if( pA->op!=pB->op ) return 0; + if( !sqliteExprCompare(pA->pLeft, pB->pLeft) ) return 0; + if( !sqliteExprCompare(pA->pRight, pB->pRight) ) return 0; + if( pA->pList ){ + if( pB->pList==0 ) return 0; + if( pA->pList->nExpr!=pB->pList->nExpr ) return 0; + for(i=0; ipList->nExpr; i++){ + if( !sqliteExprCompare(pA->pList->a[i].pExpr, pB->pList->a[i].pExpr) ){ + return 0; + } + } + }else if( pB->pList ){ + return 0; + } + if( pA->pSelect || pB->pSelect ) return 0; + if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 0; + if( pA->token.z ){ + if( pB->token.z==0 ) return 0; + if( pB->token.n!=pA->token.n ) return 0; + if( sqliteStrNICmp(pA->token.z, pB->token.z, pB->token.n)!=0 ) return 0; + } + return 1; +} + +/* +** Add a new element to the pParse->aAgg[] array and return its index. +*/ +static int appendAggInfo(Parse *pParse){ + if( (pParse->nAgg & 0x7)==0 ){ + int amt = pParse->nAgg + 8; + AggExpr *aAgg = sqliteRealloc(pParse->aAgg, amt*sizeof(pParse->aAgg[0])); + if( aAgg==0 ){ + return -1; + } + pParse->aAgg = aAgg; + } + memset(&pParse->aAgg[pParse->nAgg], 0, sizeof(pParse->aAgg[0])); + return pParse->nAgg++; +} + +/* +** Analyze the given expression looking for aggregate functions and +** for variables that need to be added to the pParse->aAgg[] array. +** Make additional entries to the pParse->aAgg[] array as necessary. +** +** This routine should only be called after the expression has been +** analyzed by sqliteExprResolveIds() and sqliteExprCheck(). +** +** If errors are seen, leave an error message in zErrMsg and return +** the number of errors. +*/ +int sqliteExprAnalyzeAggregates(Parse *pParse, Expr *pExpr){ + int i; + AggExpr *aAgg; + int nErr = 0; + + if( pExpr==0 ) return 0; + switch( pExpr->op ){ + case TK_COLUMN: { + aAgg = pParse->aAgg; + for(i=0; inAgg; i++){ + if( aAgg[i].isAgg ) continue; + if( aAgg[i].pExpr->iTable==pExpr->iTable + && aAgg[i].pExpr->iColumn==pExpr->iColumn ){ + break; + } + } + if( i>=pParse->nAgg ){ + i = appendAggInfo(pParse); + if( i<0 ) return 1; + pParse->aAgg[i].isAgg = 0; + pParse->aAgg[i].pExpr = pExpr; + } + pExpr->iAgg = i; + break; + } + case TK_AGG_FUNCTION: { + aAgg = pParse->aAgg; + for(i=0; inAgg; i++){ + if( !aAgg[i].isAgg ) continue; + if( sqliteExprCompare(aAgg[i].pExpr, pExpr) ){ + break; + } + } + if( i>=pParse->nAgg ){ + i = appendAggInfo(pParse); + if( i<0 ) return 1; + pParse->aAgg[i].isAgg = 1; + pParse->aAgg[i].pExpr = pExpr; + pParse->aAgg[i].pFunc = sqliteFindFunction(pParse->db, + pExpr->token.z, pExpr->token.n, + pExpr->pList ? pExpr->pList->nExpr : 0, 0); + } + pExpr->iAgg = i; + break; + } + default: { + if( pExpr->pLeft ){ + nErr = sqliteExprAnalyzeAggregates(pParse, pExpr->pLeft); + } + if( nErr==0 && pExpr->pRight ){ + nErr = sqliteExprAnalyzeAggregates(pParse, pExpr->pRight); + } + if( nErr==0 && pExpr->pList ){ + int n = pExpr->pList->nExpr; + int i; + for(i=0; nErr==0 && ipList->a[i].pExpr); + } + } + break; + } + } + return nErr; +} + +/* +** Locate a user function given a name and a number of arguments. +** Return a pointer to the FuncDef structure that defines that +** function, or return NULL if the function does not exist. +** +** If the createFlag argument is true, then a new (blank) FuncDef +** structure is created and liked into the "db" structure if a +** no matching function previously existed. When createFlag is true +** and the nArg parameter is -1, then only a function that accepts +** any number of arguments will be returned. +** +** If createFlag is false and nArg is -1, then the first valid +** function found is returned. A function is valid if either xFunc +** or xStep is non-zero. +*/ +FuncDef *sqliteFindFunction( + sqlite *db, /* An open database */ + const char *zName, /* Name of the function. Not null-terminated */ + int nName, /* Number of characters in the name */ + int nArg, /* Number of arguments. -1 means any number */ + int createFlag /* Create new entry if true and does not otherwise exist */ +){ + FuncDef *pFirst, *p, *pMaybe; + pFirst = p = (FuncDef*)sqliteHashFind(&db->aFunc, zName, nName); + if( p && !createFlag && nArg<0 ){ + while( p && p->xFunc==0 && p->xStep==0 ){ p = p->pNext; } + return p; + } + pMaybe = 0; + while( p && p->nArg!=nArg ){ + if( p->nArg<0 && !createFlag && (p->xFunc || p->xStep) ) pMaybe = p; + p = p->pNext; + } + if( p && !createFlag && p->xFunc==0 && p->xStep==0 ){ + return 0; + } + if( p==0 && pMaybe ){ + assert( createFlag==0 ); + return pMaybe; + } + if( p==0 && createFlag && (p = sqliteMalloc(sizeof(*p)))!=0 ){ + p->nArg = nArg; + p->pNext = pFirst; + p->dataType = pFirst ? pFirst->dataType : SQLITE_NUMERIC; + sqliteHashInsert(&db->aFunc, zName, nName, (void*)p); + } + return p; +} diff --git a/sqlitebrowser/sqlitebrowser/sqlite_source/func.c b/sqlitebrowser/sqlitebrowser/sqlite_source/func.c new file mode 100755 index 00000000..3a58a5c0 --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/sqlite_source/func.c @@ -0,0 +1,573 @@ +/* +** 2002 February 23 +** +** 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 the C functions that implement various SQL +** functions of SQLite. +** +** There is only one exported symbol in this file - the function +** sqliteRegisterBuildinFunctions() found at the bottom of the file. +** All other code has file scope. +** +** $Id: func.c,v 1.1.1.1 2003-08-21 02:24:08 tabuleiro Exp $ +*/ +#include +#include +#include +#include +#include "sqliteInt.h" + +/* +** Implementation of the non-aggregate min() and max() functions +*/ +static void minFunc(sqlite_func *context, int argc, const char **argv){ + const char *zBest; + int i; + + if( argc==0 ) return; + zBest = argv[0]; + if( zBest==0 ) return; + for(i=1; i0 ){ + zBest = argv[i]; + } + } + sqlite_set_result_string(context, zBest, -1); +} + +/* +** Implementation of the length() function +*/ +static void lengthFunc(sqlite_func *context, int argc, const char **argv){ + const char *z; + int len; + + assert( argc==1 ); + z = argv[0]; + if( z==0 ) return; +#ifdef SQLITE_UTF8 + for(len=0; *z; z++){ if( (0xc0&*z)!=0x80 ) len++; } +#else + len = strlen(z); +#endif + sqlite_set_result_int(context, len); +} + +/* +** Implementation of the abs() function +*/ +static void absFunc(sqlite_func *context, int argc, const char **argv){ + const char *z; + assert( argc==1 ); + z = argv[0]; + if( z==0 ) return; + if( z[0]=='-' && isdigit(z[1]) ) z++; + sqlite_set_result_string(context, z, -1); +} + +/* +** Implementation of the substr() function +*/ +static void substrFunc(sqlite_func *context, int argc, const char **argv){ + const char *z; +#ifdef SQLITE_UTF8 + const char *z2; + int i; +#endif + int p1, p2, len; + assert( argc==3 ); + z = argv[0]; + if( z==0 ) return; + p1 = atoi(argv[1]?argv[1]:0); + p2 = atoi(argv[2]?argv[2]:0); +#ifdef SQLITE_UTF8 + for(len=0, z2=z; *z2; z2++){ if( (0xc0&*z2)!=0x80 ) len++; } +#else + len = strlen(z); +#endif + if( p1<0 ){ + p1 += len; + if( p1<0 ){ + p2 += p1; + p1 = 0; + } + }else if( p1>0 ){ + p1--; + } + if( p1+p2>len ){ + p2 = len-p1; + } +#ifdef SQLITE_UTF8 + for(i=0; i30 ) n = 30; + if( n<0 ) n = 0; + r = atof(argv[0]); + sprintf(zBuf,"%.*f",n,r); + sqlite_set_result_string(context, zBuf, -1); +} + +/* +** Implementation of the upper() and lower() SQL functions. +*/ +static void upperFunc(sqlite_func *context, int argc, const char **argv){ + char *z; + int i; + if( argc<1 || argv[0]==0 ) return; + z = sqlite_set_result_string(context, argv[0], -1); + if( z==0 ) return; + for(i=0; z[i]; i++){ + if( islower(z[i]) ) z[i] = toupper(z[i]); + } +} +static void lowerFunc(sqlite_func *context, int argc, const char **argv){ + char *z; + int i; + if( argc<1 || argv[0]==0 ) return; + z = sqlite_set_result_string(context, argv[0], -1); + if( z==0 ) return; + for(i=0; z[i]; i++){ + if( isupper(z[i]) ) z[i] = tolower(z[i]); + } +} + +/* +** Implementation of the IFNULL(), NVL(), and COALESCE() functions. +** All three do the same thing. They return the first argument +** non-NULL argument. +*/ +static void ifnullFunc(sqlite_func *context, int argc, const char **argv){ + int i; + for(i=0; i0 ){ + zResult[j++] = code + '0'; + } + } + while( j<4 ){ + zResult[j++] = '0'; + } + zResult[j] = 0; + sqlite_set_result_string(context, zResult, 4); + }else{ + sqlite_set_result_string(context, "?000", 4); + } +} +#endif + +#ifdef SQLITE_TEST +/* +** This function generates a string of random characters. Used for +** generating test data. +*/ +static void randStr(sqlite_func *context, int argc, const char **argv){ + static const char zSrc[] = + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" + ".-!,:*^+=_|?/<> "; + int iMin, iMax, n, r, i; + char zBuf[1000]; + if( argc>=1 ){ + iMin = atoi(argv[0]); + if( iMin<0 ) iMin = 0; + if( iMin>=sizeof(zBuf) ) iMin = sizeof(zBuf)-1; + }else{ + iMin = 1; + } + if( argc>=2 ){ + iMax = atoi(argv[1]); + if( iMax=sizeof(zBuf) ) iMax = sizeof(zBuf); + }else{ + iMax = 50; + } + n = iMin; + if( iMax>iMin ){ + r = sqliteRandomInteger() & 0x7fffffff; + n += r%(iMax + 1 - iMin); + } + r = 0; + for(i=0; isum += atof(argv[0]); + p->cnt++; + } +} +static void sumFinalize(sqlite_func *context){ + SumCtx *p; + p = sqlite_aggregate_context(context, sizeof(*p)); + sqlite_set_result_double(context, p ? p->sum : 0.0); +} +static void avgFinalize(sqlite_func *context){ + SumCtx *p; + p = sqlite_aggregate_context(context, sizeof(*p)); + if( p && p->cnt>0 ){ + sqlite_set_result_double(context, p->sum/(double)p->cnt); + } +} + +/* +** 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 */ +}; + +#if 0 /* Omit because math library is required */ +/* +** Routines used to compute the standard deviation as an aggregate. +*/ +static void stdDevStep(sqlite_func *context, int argc, const char **argv){ + StdDevCtx *p; + double x; + if( argc<1 ) return; + p = sqlite_aggregate_context(context, sizeof(*p)); + if( p && argv[0] ){ + x = atof(argv[0]); + p->sum += x; + p->sum2 += x*x; + p->cnt++; + } +} +static void stdDevFinalize(sqlite_func *context){ + double rN = sqlite_aggregate_count(context); + StdDevCtx *p = sqlite_aggregate_context(context, sizeof(*p)); + if( p && p->cnt>1 ){ + double rCnt = cnt; + sqlite_set_result_double(context, + sqrt((p->sum2 - p->sum*p->sum/rCnt)/(rCnt-1.0))); + } +} +#endif + +/* +** The following structure keeps track of state information for the +** count() aggregate function. +*/ +typedef struct CountCtx CountCtx; +struct CountCtx { + int n; +}; + +/* +** Routines to implement the count() aggregate function. +*/ +static void countStep(sqlite_func *context, int argc, const char **argv){ + CountCtx *p; + p = sqlite_aggregate_context(context, sizeof(*p)); + if( (argc==0 || argv[0]) && p ){ + p->n++; + } +} +static void countFinalize(sqlite_func *context){ + CountCtx *p; + p = sqlite_aggregate_context(context, sizeof(*p)); + sqlite_set_result_int(context, p ? p->n : 0); +} + +/* +** This function tracks state information for the min() and max() +** aggregate functions. +*/ +typedef struct MinMaxCtx MinMaxCtx; +struct MinMaxCtx { + char *z; /* The best so far */ + char zBuf[28]; /* Space that can be used for storage */ +}; + +/* +** Routines to implement min() and max() aggregate functions. +*/ +static void minStep(sqlite_func *context, int argc, const char **argv){ + MinMaxCtx *p; + p = sqlite_aggregate_context(context, sizeof(*p)); + if( p==0 || argc<1 || argv[0]==0 ) return; + if( p->z==0 || sqliteCompare(argv[0],p->z)<0 ){ + int len; + if( p->z && p->z!=p->zBuf ){ + sqliteFree(p->z); + } + len = strlen(argv[0]); + if( len < sizeof(p->zBuf) ){ + p->z = p->zBuf; + }else{ + p->z = sqliteMalloc( len+1 ); + if( p->z==0 ) return; + } + strcpy(p->z, argv[0]); + } +} +static void maxStep(sqlite_func *context, int argc, const char **argv){ + MinMaxCtx *p; + p = sqlite_aggregate_context(context, sizeof(*p)); + if( p==0 || argc<1 || argv[0]==0 ) return; + if( p->z==0 || sqliteCompare(argv[0],p->z)>0 ){ + int len; + if( p->z && p->z!=p->zBuf ){ + sqliteFree(p->z); + } + len = strlen(argv[0]); + if( len < sizeof(p->zBuf) ){ + p->z = p->zBuf; + }else{ + p->z = sqliteMalloc( len+1 ); + if( p->z==0 ) return; + } + strcpy(p->z, argv[0]); + } +} +static void minMaxFinalize(sqlite_func *context){ + MinMaxCtx *p; + p = sqlite_aggregate_context(context, sizeof(*p)); + if( p && p->z ){ + sqlite_set_result_string(context, p->z, strlen(p->z)); + } + if( p && p->z && p->z!=p->zBuf ){ + sqliteFree(p->z); + } +} + +/* +** This function registered all of the above C functions as SQL +** functions. This should be the only routine in this file with +** external linkage. +*/ +void sqliteRegisterBuiltinFunctions(sqlite *db){ + static struct { + char *zName; + int nArg; + int dataType; + void (*xFunc)(sqlite_func*,int,const char**); + } aFuncs[] = { + { "min", -1, SQLITE_ARGS, minFunc }, + { "min", 0, 0, 0 }, + { "max", -1, SQLITE_ARGS, maxFunc }, + { "max", 0, 0, 0 }, + { "length", 1, SQLITE_NUMERIC, lengthFunc }, + { "substr", 3, SQLITE_TEXT, substrFunc }, + { "abs", 1, SQLITE_NUMERIC, absFunc }, + { "round", 1, SQLITE_NUMERIC, roundFunc }, + { "round", 2, SQLITE_NUMERIC, roundFunc }, + { "upper", 1, SQLITE_TEXT, upperFunc }, + { "lower", 1, SQLITE_TEXT, lowerFunc }, + { "coalesce", -1, SQLITE_ARGS, ifnullFunc }, + { "coalesce", 0, 0, 0 }, + { "coalesce", 1, 0, 0 }, + { "ifnull", 2, SQLITE_ARGS, ifnullFunc }, + { "random", -1, SQLITE_NUMERIC, randomFunc }, + { "like", 2, SQLITE_NUMERIC, likeFunc }, + { "glob", 2, SQLITE_NUMERIC, globFunc }, + { "nullif", 2, SQLITE_ARGS, nullifFunc }, + { "sqlite_version",0,SQLITE_TEXT, versionFunc}, +#ifdef SQLITE_SOUNDEX + { "soundex", 1, SQLITE_TEXT, soundexFunc}, +#endif +#ifdef SQLITE_TEST + { "randstr", 2, SQLITE_TEXT, randStr }, +#endif + }; + static struct { + char *zName; + int nArg; + int dataType; + void (*xStep)(sqlite_func*,int,const char**); + void (*xFinalize)(sqlite_func*); + } aAggs[] = { + { "min", 1, 0, minStep, minMaxFinalize }, + { "max", 1, 0, maxStep, minMaxFinalize }, + { "sum", 1, SQLITE_NUMERIC, sumStep, sumFinalize }, + { "avg", 1, SQLITE_NUMERIC, sumStep, avgFinalize }, + { "count", 0, SQLITE_NUMERIC, countStep, countFinalize }, + { "count", 1, SQLITE_NUMERIC, countStep, countFinalize }, +#if 0 + { "stddev", 1, SQLITE_NUMERIC, stdDevStep, stdDevFinalize }, +#endif + }; + int i; + + for(i=0; i + +/* Turn bulk memory into a hash table object by initializing the +** fields of the Hash structure. +** +** "new" is a pointer to the hash table that is to be initialized. +** keyClass is one of the constants SQLITE_HASH_INT, SQLITE_HASH_POINTER, +** SQLITE_HASH_BINARY, or SQLITE_HASH_STRING. The value of keyClass +** determines what kind of key the hash table will use. "copyKey" is +** true if the hash table should make its own private copy of keys and +** false if it should just use the supplied pointer. CopyKey only makes +** sense for SQLITE_HASH_STRING and SQLITE_HASH_BINARY and is ignored +** for other key classes. +*/ +void sqliteHashInit(Hash *new, int keyClass, int copyKey){ + assert( new!=0 ); + assert( keyClass>=SQLITE_HASH_INT && keyClass<=SQLITE_HASH_BINARY ); + new->keyClass = keyClass; + new->copyKey = copyKey && + (keyClass==SQLITE_HASH_STRING || keyClass==SQLITE_HASH_BINARY); + new->first = 0; + new->count = 0; + new->htsize = 0; + new->ht = 0; +} + +/* Remove all entries from a hash table. Reclaim all memory. +** Call this routine to delete a hash table or to reset a hash table +** to the empty state. +*/ +void sqliteHashClear(Hash *pH){ + HashElem *elem; /* For looping over all elements of the table */ + + assert( pH!=0 ); + elem = pH->first; + pH->first = 0; + if( pH->ht ) sqliteFree(pH->ht); + pH->ht = 0; + pH->htsize = 0; + while( elem ){ + HashElem *next_elem = elem->next; + if( pH->copyKey && elem->pKey ){ + sqliteFree(elem->pKey); + } + sqliteFree(elem); + elem = next_elem; + } + pH->count = 0; +} + +/* +** Hash and comparison functions when the mode is SQLITE_HASH_INT +*/ +static int intHash(const void *pKey, int nKey){ + return nKey ^ (nKey<<8) ^ (nKey>>8); +} +static int intCompare(const void *pKey1, int n1, const void *pKey2, int n2){ + return n2 - n1; +} + +/* +** Hash and comparison functions when the mode is SQLITE_HASH_POINTER +*/ +static int ptrHash(const void *pKey, int nKey){ + uptr x = Addr(pKey); + return x ^ (x<<8) ^ (x>>8); +} +static int ptrCompare(const void *pKey1, int n1, const void *pKey2, int n2){ + if( pKey1==pKey2 ) return 0; + if( pKey1 0 ){ + h = (h<<3) ^ h ^ *(z++); + } + return h & 0x7fffffff; +} +static int binCompare(const void *pKey1, int n1, const void *pKey2, int n2){ + if( n1!=n2 ) return n2-n1; + return memcmp(pKey1,pKey2,n1); +} + +/* +** Return a pointer to the appropriate hash function given the key class. +** +** The C syntax in this function definition may be unfamilar to some +** programmers, so we provide the following additional explanation: +** +** The name of the function is "hashFunction". The function takes a +** single parameter "keyClass". The return value of hashFunction() +** is a pointer to another function. Specifically, the return value +** of hashFunction() is a pointer to a function that takes two parameters +** with types "const void*" and "int" and returns an "int". +*/ +static int (*hashFunction(int keyClass))(const void*,int){ + switch( keyClass ){ + case SQLITE_HASH_INT: return &intHash; + case SQLITE_HASH_POINTER: return &ptrHash; + case SQLITE_HASH_STRING: return &strHash; + case SQLITE_HASH_BINARY: return &binHash;; + default: break; + } + return 0; +} + +/* +** Return a pointer to the appropriate hash function given the key class. +** +** For help in interpreted the obscure C code in the function definition, +** see the header comment on the previous function. +*/ +static int (*compareFunction(int keyClass))(const void*,int,const void*,int){ + switch( keyClass ){ + case SQLITE_HASH_INT: return &intCompare; + case SQLITE_HASH_POINTER: return &ptrCompare; + case SQLITE_HASH_STRING: return &strCompare; + case SQLITE_HASH_BINARY: return &binCompare; + default: break; + } + return 0; +} + + +/* Resize the hash table so that it cantains "new_size" buckets. +** "new_size" must be a power of 2. The hash table might fail +** to resize if sqliteMalloc() fails. +*/ +static void rehash(Hash *pH, int new_size){ + struct _ht *new_ht; /* The new hash table */ + HashElem *elem, *next_elem; /* For looping over existing elements */ + HashElem *x; /* Element being copied to new hash table */ + int (*xHash)(const void*,int); /* The hash function */ + + assert( (new_size & (new_size-1))==0 ); + new_ht = (struct _ht *)sqliteMalloc( new_size*sizeof(struct _ht) ); + if( new_ht==0 ) return; + if( pH->ht ) sqliteFree(pH->ht); + pH->ht = new_ht; + pH->htsize = new_size; + xHash = hashFunction(pH->keyClass); + for(elem=pH->first, pH->first=0; elem; elem = next_elem){ + int h = (*xHash)(elem->pKey, elem->nKey) & (new_size-1); + next_elem = elem->next; + x = new_ht[h].chain; + if( x ){ + elem->next = x; + elem->prev = x->prev; + if( x->prev ) x->prev->next = elem; + else pH->first = elem; + x->prev = elem; + }else{ + elem->next = pH->first; + if( pH->first ) pH->first->prev = elem; + elem->prev = 0; + pH->first = elem; + } + new_ht[h].chain = elem; + new_ht[h].count++; + } +} + +/* This function (for internal use only) locates an element in an +** hash table that matches the given key. The hash for this key has +** already been computed and is passed as the 4th parameter. +*/ +static HashElem *findElementGivenHash( + const Hash *pH, /* The pH to be searched */ + const void *pKey, /* The key we are searching for */ + int nKey, + int h /* The hash for this key. */ +){ + HashElem *elem; /* Used to loop thru the element list */ + int count; /* Number of elements left to test */ + int (*xCompare)(const void*,int,const void*,int); /* comparison function */ + + if( pH->ht ){ + elem = pH->ht[h].chain; + count = pH->ht[h].count; + xCompare = compareFunction(pH->keyClass); + while( count-- && elem ){ + if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){ + return elem; + } + elem = elem->next; + } + } + return 0; +} + +/* Remove a single entry from the hash table given a pointer to that +** element and a hash on the element's key. +*/ +static void removeElementGivenHash( + Hash *pH, /* The pH containing "elem" */ + HashElem* elem, /* The element to be removed from the pH */ + int h /* Hash value for the element */ +){ + if( elem->prev ){ + elem->prev->next = elem->next; + }else{ + pH->first = elem->next; + } + if( elem->next ){ + elem->next->prev = elem->prev; + } + if( pH->ht[h].chain==elem ){ + pH->ht[h].chain = elem->next; + } + pH->ht[h].count--; + if( pH->ht[h].count<=0 ){ + pH->ht[h].chain = 0; + } + if( pH->copyKey && elem->pKey ){ + sqliteFree(elem->pKey); + } + sqliteFree( elem ); + pH->count--; +} + +/* Attempt to locate an element of the hash table pH with a key +** that matches pKey,nKey. Return the data for this element if it is +** found, or NULL if there is no match. +*/ +void *sqliteHashFind(const Hash *pH, const void *pKey, int nKey){ + int h; /* A hash on key */ + HashElem *elem; /* The element that matches key */ + int (*xHash)(const void*,int); /* The hash function */ + + if( pH==0 || pH->ht==0 ) return 0; + xHash = hashFunction(pH->keyClass); + assert( xHash!=0 ); + h = (*xHash)(pKey,nKey); + assert( (pH->htsize & (pH->htsize-1))==0 ); + elem = findElementGivenHash(pH,pKey,nKey, h & (pH->htsize-1)); + return elem ? elem->data : 0; +} + +/* Insert an element into the hash table pH. The key is pKey,nKey +** and the data is "data". +** +** If no element exists with a matching key, then a new +** element is created. A copy of the key is made if the copyKey +** flag is set. NULL is returned. +** +** If another element already exists with the same key, then the +** new data replaces the old data and the old data is returned. +** The key is not copied in this instance. If a malloc fails, then +** the new data is returned and the hash table is unchanged. +** +** If the "data" parameter to this function is NULL, then the +** element corresponding to "key" is removed from the hash table. +*/ +void *sqliteHashInsert(Hash *pH, const void *pKey, int nKey, void *data){ + int hraw; /* Raw hash value of the key */ + int h; /* the hash of the key modulo hash table size */ + HashElem *elem; /* Used to loop thru the element list */ + HashElem *new_elem; /* New element added to the pH */ + int (*xHash)(const void*,int); /* The hash function */ + + assert( pH!=0 ); + xHash = hashFunction(pH->keyClass); + assert( xHash!=0 ); + hraw = (*xHash)(pKey, nKey); + assert( (pH->htsize & (pH->htsize-1))==0 ); + h = hraw & (pH->htsize-1); + elem = findElementGivenHash(pH,pKey,nKey,h); + if( elem ){ + void *old_data = elem->data; + if( data==0 ){ + removeElementGivenHash(pH,elem,h); + }else{ + elem->data = data; + } + return old_data; + } + if( data==0 ) return 0; + new_elem = (HashElem*)sqliteMalloc( sizeof(HashElem) ); + if( new_elem==0 ) return data; + if( pH->copyKey && pKey!=0 ){ + new_elem->pKey = sqliteMallocRaw( nKey ); + if( new_elem->pKey==0 ){ + sqliteFree(new_elem); + return data; + } + memcpy((void*)new_elem->pKey, pKey, nKey); + }else{ + new_elem->pKey = (void*)pKey; + } + new_elem->nKey = nKey; + pH->count++; + if( pH->htsize==0 ) rehash(pH,8); + if( pH->htsize==0 ){ + pH->count = 0; + sqliteFree(new_elem); + return data; + } + if( pH->count > pH->htsize ){ + rehash(pH,pH->htsize*2); + } + assert( (pH->htsize & (pH->htsize-1))==0 ); + h = hraw & (pH->htsize-1); + elem = pH->ht[h].chain; + if( elem ){ + new_elem->next = elem; + new_elem->prev = elem->prev; + if( elem->prev ){ elem->prev->next = new_elem; } + else { pH->first = new_elem; } + elem->prev = new_elem; + }else{ + new_elem->next = pH->first; + new_elem->prev = 0; + if( pH->first ){ pH->first->prev = new_elem; } + pH->first = new_elem; + } + pH->ht[h].count++; + pH->ht[h].chain = new_elem; + new_elem->data = data; + return 0; +} diff --git a/sqlitebrowser/sqlitebrowser/sqlite_source/hash.h b/sqlitebrowser/sqlitebrowser/sqlite_source/hash.h new file mode 100755 index 00000000..7124d2d6 --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/sqlite_source/hash.h @@ -0,0 +1,109 @@ +/* +** 2001 September 22 +** +** 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 is the header file for the generic hash-table implemenation +** used in SQLite. +** +** $Id: hash.h,v 1.1.1.1 2003-08-21 02:24:08 tabuleiro Exp $ +*/ +#ifndef _SQLITE_HASH_H_ +#define _SQLITE_HASH_H_ + +/* Forward declarations of structures. */ +typedef struct Hash Hash; +typedef struct HashElem HashElem; + +/* A complete hash table is an instance of the following structure. +** The internals of this structure are intended to be opaque -- client +** code should not attempt to access or modify the fields of this structure +** directly. Change this structure only by using the routines below. +** However, many of the "procedures" and "functions" for modifying and +** accessing this structure are really macros, so we can't really make +** this structure opaque. +*/ +struct Hash { + char keyClass; /* SQLITE_HASH_INT, _POINTER, _STRING, _BINARY */ + char copyKey; /* True if copy of key made on insert */ + int count; /* Number of entries in this table */ + HashElem *first; /* The first element of the array */ + int htsize; /* Number of buckets in the hash table */ + struct _ht { /* the hash table */ + int count; /* Number of entries with this hash */ + HashElem *chain; /* Pointer to first entry with this hash */ + } *ht; +}; + +/* Each element in the hash table is an instance of the following +** structure. All elements are stored on a single doubly-linked list. +** +** Again, this structure is intended to be opaque, but it can't really +** be opaque because it is used by macros. +*/ +struct HashElem { + HashElem *next, *prev; /* Next and previous elements in the table */ + void *data; /* Data associated with this element */ + void *pKey; int nKey; /* Key associated with this element */ +}; + +/* +** There are 4 different modes of operation for a hash table: +** +** SQLITE_HASH_INT nKey is used as the key and pKey is ignored. +** +** SQLITE_HASH_POINTER pKey is used as the key and nKey is ignored. +** +** SQLITE_HASH_STRING pKey points to a string that is nKey bytes long +** (including the null-terminator, if any). Case +** is ignored in comparisons. +** +** SQLITE_HASH_BINARY pKey points to binary data nKey bytes long. +** memcmp() is used to compare keys. +** +** A copy of the key is made for SQLITE_HASH_STRING and SQLITE_HASH_BINARY +** if the copyKey parameter to HashInit is 1. +*/ +#define SQLITE_HASH_INT 1 +#define SQLITE_HASH_POINTER 2 +#define SQLITE_HASH_STRING 3 +#define SQLITE_HASH_BINARY 4 + +/* +** Access routines. To delete, insert a NULL pointer. +*/ +void sqliteHashInit(Hash*, int keytype, int copyKey); +void *sqliteHashInsert(Hash*, const void *pKey, int nKey, void *pData); +void *sqliteHashFind(const Hash*, const void *pKey, int nKey); +void sqliteHashClear(Hash*); + +/* +** Macros for looping over all elements of a hash table. The idiom is +** like this: +** +** Hash h; +** HashElem *p; +** ... +** for(p=sqliteHashFirst(&h); p; p=sqliteHashNext(p)){ +** SomeStructure *pData = sqliteHashData(p); +** // do something with pData +** } +*/ +#define sqliteHashFirst(H) ((H)->first) +#define sqliteHashNext(E) ((E)->next) +#define sqliteHashData(E) ((E)->data) +#define sqliteHashKey(E) ((E)->pKey) +#define sqliteHashKeysize(E) ((E)->nKey) + +/* +** Number of entries in a hash table +*/ +#define sqliteHashCount(H) ((H)->count) + +#endif /* _SQLITE_HASH_H_ */ diff --git a/sqlitebrowser/sqlitebrowser/sqlite_source/insert.c b/sqlitebrowser/sqlitebrowser/sqlite_source/insert.c new file mode 100755 index 00000000..cd01364e --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/sqlite_source/insert.c @@ -0,0 +1,891 @@ +/* +** 2001 September 15 +** +** 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 C code routines that are called by the parser +** to handle INSERT statements in SQLite. +** +** $Id: insert.c,v 1.1.1.1 2003-08-21 02:24:09 tabuleiro Exp $ +*/ +#include "sqliteInt.h" + +/* +** This routine is call to handle SQL of the following forms: +** +** insert into TABLE (IDLIST) values(EXPRLIST) +** insert into TABLE (IDLIST) select +** +** The IDLIST following the table name is always optional. If omitted, +** then a list of all columns for the table is substituted. The IDLIST +** appears in the pColumn parameter. pColumn is NULL if IDLIST is omitted. +** +** The pList parameter holds EXPRLIST in the first form of the INSERT +** statement above, and pSelect is NULL. For the second form, pList is +** NULL and pSelect is a pointer to the select statement used to generate +** data for the insert. +** +** The code generated follows one of three templates. For a simple +** select with data coming from a VALUES clause, the code executes +** once straight down through. The template looks like this: +** +** open write cursor to and its indices +** puts VALUES clause expressions onto the stack +** write the resulting record into
+** cleanup +** +** If the statement is of the form +** +** INSERT INTO
SELECT ... +** +** And the SELECT clause does not read from
at any time, then +** the generated code follows this template: +** +** goto B +** A: setup for the SELECT +** loop over the tables in the SELECT +** gosub C +** end loop +** cleanup after the SELECT +** goto D +** B: open write cursor to
and its indices +** goto A +** C: insert the select result into
+** return +** D: cleanup +** +** The third template is used if the insert statement takes its +** values from a SELECT but the data is being inserted into a table +** that is also read as part of the SELECT. In the third form, +** we have to use a intermediate table to store the results of +** the select. The template is like this: +** +** goto B +** A: setup for the SELECT +** loop over the tables in the SELECT +** gosub C +** end loop +** cleanup after the SELECT +** goto D +** C: insert the select result into the intermediate table +** return +** B: open a cursor to an intermediate table +** goto A +** D: open write cursor to
and its indices +** loop over the intermediate table +** transfer values form intermediate table into
+** end the loop +** cleanup +*/ +void sqliteInsert( + Parse *pParse, /* Parser context */ + SrcList *pTabList, /* Name of table into which we are inserting */ + ExprList *pList, /* List of values to be inserted */ + Select *pSelect, /* A SELECT statement to use as the data source */ + IdList *pColumn, /* Column names corresponding to IDLIST. */ + int onError /* How to handle constraint errors */ +){ + Table *pTab; /* The table to insert into */ + char *zTab; /* Name of the table into which we are inserting */ + const char *zDb; /* Name of the database holding this table */ + int i, j, idx; /* Loop counters */ + Vdbe *v; /* Generate code into this virtual machine */ + Index *pIdx; /* For looping over indices of the table */ + int nColumn; /* Number of columns in the data */ + int base; /* VDBE Cursor number for pTab */ + int iCont, iBreak; /* Beginning and end of the loop over srcTab */ + sqlite *db; /* The main database structure */ + int keyColumn = -1; /* Column that is the INTEGER PRIMARY KEY */ + int endOfLoop; /* Label for the end of the insertion loop */ + int useTempTable; /* Store SELECT results in intermediate table */ + int srcTab; /* Data comes from this temporary cursor if >=0 */ + int iSelectLoop; /* Address of code that implements the SELECT */ + int iCleanup; /* Address of the cleanup code */ + int iInsertBlock; /* Address of the subroutine used to insert data */ + int iCntMem; /* Memory cell used for the row counter */ + int isView; /* True if attempting to insert into a view */ + + int row_triggers_exist = 0; /* True if there are FOR EACH ROW triggers */ + int before_triggers; /* True if there are BEFORE triggers */ + int after_triggers; /* True if there are AFTER triggers */ + int newIdx = -1; /* Cursor for the NEW table */ + + if( pParse->nErr || sqlite_malloc_failed ) goto insert_cleanup; + db = pParse->db; + + /* Locate the table into which we will be inserting new information. + */ + assert( pTabList->nSrc==1 ); + zTab = pTabList->a[0].zName; + if( zTab==0 ) goto insert_cleanup; + pTab = sqliteSrcListLookup(pParse, pTabList); + if( pTab==0 ){ + goto insert_cleanup; + } + assert( pTab->iDbnDb ); + zDb = db->aDb[pTab->iDb].zName; + if( sqliteAuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb) ){ + goto insert_cleanup; + } + + /* Ensure that: + * (a) the table is not read-only, + * (b) that if it is a view then ON INSERT triggers exist + */ + before_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, TK_INSERT, + TK_BEFORE, TK_ROW, 0); + after_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, TK_INSERT, + TK_AFTER, TK_ROW, 0); + row_triggers_exist = before_triggers || after_triggers; + isView = pTab->pSelect!=0; + if( sqliteIsReadOnly(pParse, pTab, before_triggers) ){ + goto insert_cleanup; + } + if( pTab==0 ) goto insert_cleanup; + + /* If pTab is really a view, make sure it has been initialized. + */ + if( isView && sqliteViewGetColumnNames(pParse, pTab) ){ + goto insert_cleanup; + } + + /* Allocate a VDBE + */ + v = sqliteGetVdbe(pParse); + if( v==0 ) goto insert_cleanup; + sqliteBeginWriteOperation(pParse, pSelect || row_triggers_exist, pTab->iDb); + + /* if there are row triggers, allocate a temp table for new.* references. */ + if( row_triggers_exist ){ + newIdx = pParse->nTab++; + } + + /* Figure out how many columns of data are supplied. If the data + ** is coming from a SELECT statement, then this step also generates + ** all the code to implement the SELECT statement and invoke a subroutine + ** to process each row of the result. (Template 2.) If the SELECT + ** statement uses the the table that is being inserted into, then the + ** subroutine is also coded here. That subroutine stores the SELECT + ** results in a temporary table. (Template 3.) + */ + if( pSelect ){ + /* Data is coming from a SELECT. Generate code to implement that SELECT + */ + int rc, iInitCode; + iInitCode = sqliteVdbeAddOp(v, OP_Goto, 0, 0); + iSelectLoop = sqliteVdbeCurrentAddr(v); + iInsertBlock = sqliteVdbeMakeLabel(v); + rc = sqliteSelect(pParse, pSelect, SRT_Subroutine, iInsertBlock, 0,0,0); + if( rc || pParse->nErr || sqlite_malloc_failed ) goto insert_cleanup; + iCleanup = sqliteVdbeMakeLabel(v); + sqliteVdbeAddOp(v, OP_Goto, 0, iCleanup); + assert( pSelect->pEList ); + nColumn = pSelect->pEList->nExpr; + + /* Set useTempTable to TRUE if the result of the SELECT statement + ** should be written into a temporary table. Set to FALSE if each + ** row of the SELECT can be written directly into the result table. + ** + ** A temp table must be used if the table being updated is also one + ** of the tables being read by the SELECT statement. Also use a + ** temp table in the case of row triggers. + */ + if( row_triggers_exist ){ + useTempTable = 1; + }else{ + int addr = sqliteVdbeFindOp(v, OP_OpenRead, pTab->tnum); + useTempTable = 0; + if( addr>0 ){ + VdbeOp *pOp = sqliteVdbeGetOp(v, addr-2); + if( pOp->opcode==OP_Integer && pOp->p1==pTab->iDb ){ + useTempTable = 1; + } + } + } + + if( useTempTable ){ + /* Generate the subroutine that SELECT calls to process each row of + ** the result. Store the result in a temporary table + */ + srcTab = pParse->nTab++; + sqliteVdbeResolveLabel(v, iInsertBlock); + sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, 0); + sqliteVdbeAddOp(v, OP_NewRecno, srcTab, 0); + sqliteVdbeAddOp(v, OP_Pull, 1, 0); + sqliteVdbeAddOp(v, OP_PutIntKey, srcTab, 0); + sqliteVdbeAddOp(v, OP_Return, 0, 0); + + /* The following code runs first because the GOTO at the very top + ** of the program jumps to it. Create the temporary table, then jump + ** back up and execute the SELECT code above. + */ + sqliteVdbeChangeP2(v, iInitCode, sqliteVdbeCurrentAddr(v)); + sqliteVdbeAddOp(v, OP_OpenTemp, srcTab, 0); + sqliteVdbeAddOp(v, OP_Goto, 0, iSelectLoop); + sqliteVdbeResolveLabel(v, iCleanup); + }else{ + sqliteVdbeChangeP2(v, iInitCode, sqliteVdbeCurrentAddr(v)); + } + }else{ + /* This is the case if the data for the INSERT is coming from a VALUES + ** clause + */ + SrcList dummy; + assert( pList!=0 ); + srcTab = -1; + useTempTable = 0; + assert( pList ); + nColumn = pList->nExpr; + dummy.nSrc = 0; + for(i=0; ia[i].pExpr) ){ + goto insert_cleanup; + } + if( sqliteExprCheck(pParse, pList->a[i].pExpr, 0, 0) ){ + goto insert_cleanup; + } + } + } + + /* Make sure the number of columns in the source data matches the number + ** of columns to be inserted into the table. + */ + if( pColumn==0 && nColumn!=pTab->nCol ){ + sqliteErrorMsg(pParse, + "table %S has %d columns but %d values were supplied", + pTabList, 0, pTab->nCol, nColumn); + goto insert_cleanup; + } + if( pColumn!=0 && nColumn!=pColumn->nId ){ + sqliteErrorMsg(pParse, "%d values for %d columns", nColumn, pColumn->nId); + goto insert_cleanup; + } + + /* If the INSERT statement included an IDLIST term, then make sure + ** all elements of the IDLIST really are columns of the table and + ** remember the column indices. + ** + ** If the table has an INTEGER PRIMARY KEY column and that column + ** is named in the IDLIST, then record in the keyColumn variable + ** the index into IDLIST of the primary key column. keyColumn is + ** the index of the primary key as it appears in IDLIST, not as + ** is appears in the original table. (The index of the primary + ** key in the original table is pTab->iPKey.) + */ + if( pColumn ){ + for(i=0; inId; i++){ + pColumn->a[i].idx = -1; + } + for(i=0; inId; i++){ + for(j=0; jnCol; j++){ + if( sqliteStrICmp(pColumn->a[i].zName, pTab->aCol[j].zName)==0 ){ + pColumn->a[i].idx = j; + if( j==pTab->iPKey ){ + keyColumn = i; + } + break; + } + } + if( j>=pTab->nCol ){ + if( sqliteIsRowid(pColumn->a[i].zName) ){ + keyColumn = i; + }else{ + sqliteErrorMsg(pParse, "table %S has no column named %s", + pTabList, 0, pColumn->a[i].zName); + pParse->nErr++; + goto insert_cleanup; + } + } + } + } + + /* If there is no IDLIST term but the table has an integer primary + ** key, the set the keyColumn variable to the primary key column index + ** in the original table definition. + */ + if( pColumn==0 ){ + keyColumn = pTab->iPKey; + } + + /* Open the temp table for FOR EACH ROW triggers + */ + if( row_triggers_exist ){ + sqliteVdbeAddOp(v, OP_OpenPseudo, newIdx, 0); + } + + /* Initialize the count of rows to be inserted + */ + if( db->flags & SQLITE_CountRows ){ + iCntMem = pParse->nMem++; + sqliteVdbeAddOp(v, OP_Integer, 0, 0); + sqliteVdbeAddOp(v, OP_MemStore, iCntMem, 1); + } + + /* Open tables and indices if there are no row triggers */ + if( !row_triggers_exist ){ + base = pParse->nTab; + sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0); + sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum); + sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC); + for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){ + sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0); + sqliteVdbeAddOp(v, OP_OpenWrite, idx+base, pIdx->tnum); + sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC); + } + pParse->nTab += idx; + } + + /* If the data source is a temporary table, then we have to create + ** a loop because there might be multiple rows of data. If the data + ** source is a subroutine call from the SELECT statement, then we need + ** to launch the SELECT statement processing. + */ + if( useTempTable ){ + iBreak = sqliteVdbeMakeLabel(v); + sqliteVdbeAddOp(v, OP_Rewind, srcTab, iBreak); + iCont = sqliteVdbeCurrentAddr(v); + }else if( pSelect ){ + sqliteVdbeAddOp(v, OP_Goto, 0, iSelectLoop); + sqliteVdbeResolveLabel(v, iInsertBlock); + } + + /* Run the BEFORE and INSTEAD OF triggers, if there are any + */ + endOfLoop = sqliteVdbeMakeLabel(v); + if( before_triggers ){ + + /* build the NEW.* reference row. Note that if there is an INTEGER + ** PRIMARY KEY into which a NULL is being inserted, that NULL will be + ** translated into a unique ID for the row. But on a BEFORE trigger, + ** we do not know what the unique ID will be (because the insert has + ** not happened yet) so we substitute a rowid of -1 + */ + if( keyColumn<0 ){ + sqliteVdbeAddOp(v, OP_Integer, -1, 0); + }else if( useTempTable ){ + sqliteVdbeAddOp(v, OP_Column, srcTab, keyColumn); + }else if( pSelect ){ + sqliteVdbeAddOp(v, OP_Dup, nColumn - keyColumn - 1, 1); + }else{ + sqliteExprCode(pParse, pList->a[keyColumn].pExpr); + sqliteVdbeAddOp(v, OP_NotNull, -1, sqliteVdbeCurrentAddr(v)+3); + sqliteVdbeAddOp(v, OP_Pop, 1, 0); + sqliteVdbeAddOp(v, OP_Integer, -1, 0); + sqliteVdbeAddOp(v, OP_MustBeInt, 0, 0); + } + + /* Create the new column data + */ + for(i=0; inCol; i++){ + if( pColumn==0 ){ + j = i; + }else{ + for(j=0; jnId; j++){ + if( pColumn->a[j].idx==i ) break; + } + } + if( pColumn && j>=pColumn->nId ){ + sqliteVdbeAddOp(v, OP_String, 0, 0); + sqliteVdbeChangeP3(v, -1, pTab->aCol[i].zDflt, P3_STATIC); + }else if( useTempTable ){ + sqliteVdbeAddOp(v, OP_Column, srcTab, j); + }else if( pSelect ){ + sqliteVdbeAddOp(v, OP_Dup, nColumn-j-1, 1); + }else{ + sqliteExprCode(pParse, pList->a[j].pExpr); + } + } + sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0); + sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0); + + /* Fire BEFORE or INSTEAD OF triggers */ + if( sqliteCodeRowTrigger(pParse, TK_INSERT, 0, TK_BEFORE, pTab, + newIdx, -1, onError, endOfLoop) ){ + goto insert_cleanup; + } + } + + /* If any triggers exists, the opening of tables and indices is deferred + ** until now. + */ + if( row_triggers_exist && !isView ){ + base = pParse->nTab; + sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0); + sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum); + sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC); + for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){ + sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0); + sqliteVdbeAddOp(v, OP_OpenWrite, idx+base, pIdx->tnum); + sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC); + } + pParse->nTab += idx; + } + + /* Push the record number for the new entry onto the stack. The + ** record number is a randomly generate integer created by NewRecno + ** except when the table has an INTEGER PRIMARY KEY column, in which + ** case the record number is the same as that column. + */ + if( !isView ){ + if( keyColumn>=0 ){ + if( useTempTable ){ + sqliteVdbeAddOp(v, OP_Column, srcTab, keyColumn); + }else if( pSelect ){ + sqliteVdbeAddOp(v, OP_Dup, nColumn - keyColumn - 1, 1); + }else{ + sqliteExprCode(pParse, pList->a[keyColumn].pExpr); + } + /* If the PRIMARY KEY expression is NULL, then use OP_NewRecno + ** to generate a unique primary key value. + */ + sqliteVdbeAddOp(v, OP_NotNull, -1, sqliteVdbeCurrentAddr(v)+3); + sqliteVdbeAddOp(v, OP_Pop, 1, 0); + sqliteVdbeAddOp(v, OP_NewRecno, base, 0); + sqliteVdbeAddOp(v, OP_MustBeInt, 0, 0); + }else{ + sqliteVdbeAddOp(v, OP_NewRecno, base, 0); + } + + /* Push onto the stack, data for all columns of the new entry, beginning + ** with the first column. + */ + for(i=0; inCol; i++){ + if( i==pTab->iPKey ){ + /* The value of the INTEGER PRIMARY KEY column is always a NULL. + ** Whenever this column is read, the record number will be substituted + ** in its place. So will fill this column with a NULL to avoid + ** taking up data space with information that will never be used. */ + sqliteVdbeAddOp(v, OP_String, 0, 0); + continue; + } + if( pColumn==0 ){ + j = i; + }else{ + for(j=0; jnId; j++){ + if( pColumn->a[j].idx==i ) break; + } + } + if( pColumn && j>=pColumn->nId ){ + sqliteVdbeAddOp(v, OP_String, 0, 0); + sqliteVdbeChangeP3(v, -1, pTab->aCol[i].zDflt, P3_STATIC); + }else if( useTempTable ){ + sqliteVdbeAddOp(v, OP_Column, srcTab, j); + }else if( pSelect ){ + sqliteVdbeAddOp(v, OP_Dup, i+nColumn-j, 1); + }else{ + sqliteExprCode(pParse, pList->a[j].pExpr); + } + } + + /* Generate code to check constraints and generate index keys and + ** do the insertion. + */ + sqliteGenerateConstraintChecks(pParse, pTab, base, 0, keyColumn>=0, + 0, onError, endOfLoop); + sqliteCompleteInsertion(pParse, pTab, base, 0,0,0, + after_triggers ? newIdx : -1); + } + + /* Update the count of rows that are inserted + */ + if( (db->flags & SQLITE_CountRows)!=0 ){ + sqliteVdbeAddOp(v, OP_MemIncr, iCntMem, 0); + } + + if( row_triggers_exist ){ + /* Close all tables opened */ + if( !isView ){ + sqliteVdbeAddOp(v, OP_Close, base, 0); + for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){ + sqliteVdbeAddOp(v, OP_Close, idx+base, 0); + } + } + + /* Code AFTER triggers */ + if( sqliteCodeRowTrigger(pParse, TK_INSERT, 0, TK_AFTER, pTab, newIdx, -1, + onError, endOfLoop) ){ + goto insert_cleanup; + } + } + + /* The bottom of the loop, if the data source is a SELECT statement + */ + sqliteVdbeResolveLabel(v, endOfLoop); + if( useTempTable ){ + sqliteVdbeAddOp(v, OP_Next, srcTab, iCont); + sqliteVdbeResolveLabel(v, iBreak); + sqliteVdbeAddOp(v, OP_Close, srcTab, 0); + }else if( pSelect ){ + sqliteVdbeAddOp(v, OP_Pop, nColumn, 0); + sqliteVdbeAddOp(v, OP_Return, 0, 0); + sqliteVdbeResolveLabel(v, iCleanup); + } + + if( !row_triggers_exist ){ + /* Close all tables opened */ + sqliteVdbeAddOp(v, OP_Close, base, 0); + for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){ + sqliteVdbeAddOp(v, OP_Close, idx+base, 0); + } + } + + sqliteEndWriteOperation(pParse); + + /* + ** Return the number of rows inserted. + */ + if( db->flags & SQLITE_CountRows ){ + sqliteVdbeAddOp(v, OP_ColumnName, 0, 0); + sqliteVdbeChangeP3(v, -1, "rows inserted", P3_STATIC); + sqliteVdbeAddOp(v, OP_MemLoad, iCntMem, 0); + sqliteVdbeAddOp(v, OP_Callback, 1, 0); + } + +insert_cleanup: + sqliteSrcListDelete(pTabList); + if( pList ) sqliteExprListDelete(pList); + if( pSelect ) sqliteSelectDelete(pSelect); + sqliteIdListDelete(pColumn); +} + +/* +** Generate code to do a constraint check prior to an INSERT or an UPDATE. +** +** When this routine is called, the stack contains (from bottom to top) +** the following values: +** +** 1. The recno of the row to be updated before the update. This +** value is omitted unless we are doing an UPDATE that involves a +** change to the record number. +** +** 2. The recno of the row after the update. +** +** 3. The data in the first column of the entry after the update. +** +** i. Data from middle columns... +** +** N. The data in the last column of the entry after the update. +** +** The old recno shown as entry (1) above is omitted unless both isUpdate +** and recnoChng are 1. isUpdate is true for UPDATEs and false for +** INSERTs and recnoChng is true if the record number is being changed. +** +** The code generated by this routine pushes additional entries onto +** the stack which are the keys for new index entries for the new record. +** The order of index keys is the same as the order of the indices on +** the pTable->pIndex list. A key is only created for index i if +** aIdxUsed!=0 and aIdxUsed[i]!=0. +** +** This routine also generates code to check constraints. NOT NULL, +** CHECK, and UNIQUE constraints are all checked. If a constraint fails, +** then the appropriate action is performed. There are five possible +** actions: ROLLBACK, ABORT, FAIL, REPLACE, and IGNORE. +** +** Constraint type Action What Happens +** --------------- ---------- ---------------------------------------- +** any ROLLBACK The current transaction is rolled back and +** sqlite_exec() returns immediately with a +** return code of SQLITE_CONSTRAINT. +** +** any ABORT Back out changes from the current command +** only (do not do a complete rollback) then +** cause sqlite_exec() to return immediately +** with SQLITE_CONSTRAINT. +** +** any FAIL Sqlite_exec() returns immediately with a +** return code of SQLITE_CONSTRAINT. The +** transaction is not rolled back and any +** prior changes are retained. +** +** any IGNORE The record number and data is popped from +** the stack and there is an immediate jump +** to label ignoreDest. +** +** NOT NULL REPLACE The NULL value is replace by the default +** value for that column. If the default value +** is NULL, the action is the same as ABORT. +** +** UNIQUE REPLACE The other row that conflicts with the row +** being inserted is removed. +** +** CHECK REPLACE Illegal. The results in an exception. +** +** Which action to take is determined by the overrideError parameter. +** Or if overrideError==OE_Default, then the pParse->onError parameter +** is used. Or if pParse->onError==OE_Default then the onError value +** for the constraint is used. +** +** The calling routine must open a read/write cursor for pTab with +** cursor number "base". All indices of pTab must also have open +** read/write cursors with cursor number base+i for the i-th cursor. +** Except, if there is no possibility of a REPLACE action then +** cursors do not need to be open for indices where aIdxUsed[i]==0. +** +** If the isUpdate flag is true, it means that the "base" cursor is +** initially pointing to an entry that is being updated. The isUpdate +** flag causes extra code to be generated so that the "base" cursor +** is still pointing at the same entry after the routine returns. +** Without the isUpdate flag, the "base" cursor might be moved. +*/ +void sqliteGenerateConstraintChecks( + Parse *pParse, /* The parser context */ + Table *pTab, /* the table into which we are inserting */ + int base, /* Index of a read/write cursor pointing at pTab */ + char *aIdxUsed, /* Which indices are used. NULL means all are used */ + int recnoChng, /* True if the record number will change */ + int isUpdate, /* True for UPDATE, False for INSERT */ + int overrideError, /* Override onError to this if not OE_Default */ + int ignoreDest /* Jump to this label on an OE_Ignore resolution */ +){ + int i; + Vdbe *v; + int nCol; + int onError; + int addr; + int extra; + int iCur; + Index *pIdx; + int seenReplace = 0; + int jumpInst1, jumpInst2; + int contAddr; + int hasTwoRecnos = (isUpdate && recnoChng); + + v = sqliteGetVdbe(pParse); + assert( v!=0 ); + assert( pTab->pSelect==0 ); /* This table is not a VIEW */ + nCol = pTab->nCol; + + /* Test all NOT NULL constraints. + */ + for(i=0; iiPKey ){ + continue; + } + onError = pTab->aCol[i].notNull; + if( onError==OE_None ) continue; + if( overrideError!=OE_Default ){ + onError = overrideError; + }else if( pParse->db->onError!=OE_Default ){ + onError = pParse->db->onError; + }else if( onError==OE_Default ){ + onError = OE_Abort; + } + if( onError==OE_Replace && pTab->aCol[i].zDflt==0 ){ + onError = OE_Abort; + } + sqliteVdbeAddOp(v, OP_Dup, nCol-1-i, 1); + addr = sqliteVdbeAddOp(v, OP_NotNull, 1, 0); + switch( onError ){ + case OE_Rollback: + case OE_Abort: + case OE_Fail: { + char *zMsg = 0; + sqliteVdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, onError); + sqliteSetString(&zMsg, pTab->zName, ".", pTab->aCol[i].zName, + " may not be NULL", 0); + sqliteVdbeChangeP3(v, -1, zMsg, P3_DYNAMIC); + break; + } + case OE_Ignore: { + sqliteVdbeAddOp(v, OP_Pop, nCol+1+hasTwoRecnos, 0); + sqliteVdbeAddOp(v, OP_Goto, 0, ignoreDest); + break; + } + case OE_Replace: { + sqliteVdbeAddOp(v, OP_String, 0, 0); + sqliteVdbeChangeP3(v, -1, pTab->aCol[i].zDflt, P3_STATIC); + sqliteVdbeAddOp(v, OP_Push, nCol-i, 0); + break; + } + default: assert(0); + } + sqliteVdbeChangeP2(v, addr, sqliteVdbeCurrentAddr(v)); + } + + /* Test all CHECK constraints + */ + /**** TBD ****/ + + /* If we have an INTEGER PRIMARY KEY, make sure the primary key + ** of the new record does not previously exist. Except, if this + ** is an UPDATE and the primary key is not changing, that is OK. + */ + if( recnoChng ){ + onError = pTab->keyConf; + if( overrideError!=OE_Default ){ + onError = overrideError; + }else if( pParse->db->onError!=OE_Default ){ + onError = pParse->db->onError; + }else if( onError==OE_Default ){ + onError = OE_Abort; + } + + if( isUpdate ){ + sqliteVdbeAddOp(v, OP_Dup, nCol+1, 1); + sqliteVdbeAddOp(v, OP_Dup, nCol+1, 1); + jumpInst1 = sqliteVdbeAddOp(v, OP_Eq, 0, 0); + } + sqliteVdbeAddOp(v, OP_Dup, nCol, 1); + jumpInst2 = sqliteVdbeAddOp(v, OP_NotExists, base, 0); + switch( onError ){ + default: { + onError = OE_Abort; + /* Fall thru into the next case */ + } + case OE_Rollback: + case OE_Abort: + case OE_Fail: { + sqliteVdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, onError); + sqliteVdbeChangeP3(v, -1, "PRIMARY KEY must be unique", P3_STATIC); + break; + } + case OE_Replace: { + sqliteGenerateRowIndexDelete(pParse->db, v, pTab, base, 0); + if( isUpdate ){ + sqliteVdbeAddOp(v, OP_Dup, nCol+hasTwoRecnos, 1); + sqliteVdbeAddOp(v, OP_MoveTo, base, 0); + } + seenReplace = 1; + break; + } + case OE_Ignore: { + assert( seenReplace==0 ); + sqliteVdbeAddOp(v, OP_Pop, nCol+1+hasTwoRecnos, 0); + sqliteVdbeAddOp(v, OP_Goto, 0, ignoreDest); + break; + } + } + contAddr = sqliteVdbeCurrentAddr(v); + sqliteVdbeChangeP2(v, jumpInst2, contAddr); + if( isUpdate ){ + sqliteVdbeChangeP2(v, jumpInst1, contAddr); + sqliteVdbeAddOp(v, OP_Dup, nCol+1, 1); + sqliteVdbeAddOp(v, OP_MoveTo, base, 0); + } + } + + /* Test all UNIQUE constraints by creating entries for each UNIQUE + ** index and making sure that duplicate entries do not already exist. + ** Add the new records to the indices as we go. + */ + extra = -1; + for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){ + if( aIdxUsed && aIdxUsed[iCur]==0 ) continue; /* Skip unused indices */ + extra++; + + /* Create a key for accessing the index entry */ + sqliteVdbeAddOp(v, OP_Dup, nCol+extra, 1); + for(i=0; inColumn; i++){ + int idx = pIdx->aiColumn[i]; + if( idx==pTab->iPKey ){ + sqliteVdbeAddOp(v, OP_Dup, i+extra+nCol+1, 1); + }else{ + sqliteVdbeAddOp(v, OP_Dup, i+extra+nCol-idx, 1); + } + } + jumpInst1 = sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0); + if( pParse->db->file_format>=4 ) sqliteAddIdxKeyType(v, pIdx); + + /* Find out what action to take in case there is an indexing conflict */ + onError = pIdx->onError; + if( onError==OE_None ) continue; /* pIdx is not a UNIQUE index */ + if( overrideError!=OE_Default ){ + onError = overrideError; + }else if( pParse->db->onError!=OE_Default ){ + onError = pParse->db->onError; + }else if( onError==OE_Default ){ + onError = OE_Abort; + } + if( seenReplace ){ + if( onError==OE_Ignore ) onError = OE_Replace; + else if( onError==OE_Fail ) onError = OE_Abort; + } + + + /* Check to see if the new index entry will be unique */ + sqliteVdbeAddOp(v, OP_Dup, extra+nCol+1+hasTwoRecnos, 1); + jumpInst2 = sqliteVdbeAddOp(v, OP_IsUnique, base+iCur+1, 0); + + /* Generate code that executes if the new index entry is not unique */ + switch( onError ){ + case OE_Rollback: + case OE_Abort: + case OE_Fail: { + sqliteVdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, onError); + sqliteVdbeChangeP3(v, -1, "uniqueness constraint failed", P3_STATIC); + break; + } + case OE_Ignore: { + assert( seenReplace==0 ); + sqliteVdbeAddOp(v, OP_Pop, nCol+extra+3+hasTwoRecnos, 0); + sqliteVdbeAddOp(v, OP_Goto, 0, ignoreDest); + break; + } + case OE_Replace: { + sqliteGenerateRowDelete(pParse->db, v, pTab, base, 0); + if( isUpdate ){ + sqliteVdbeAddOp(v, OP_Dup, nCol+extra+1+hasTwoRecnos, 1); + sqliteVdbeAddOp(v, OP_MoveTo, base, 0); + } + seenReplace = 1; + break; + } + default: assert(0); + } + contAddr = sqliteVdbeCurrentAddr(v); +#if NULL_DISTINCT_FOR_UNIQUE + sqliteVdbeChangeP2(v, jumpInst1, contAddr); +#endif + sqliteVdbeChangeP2(v, jumpInst2, contAddr); + } +} + +/* +** This routine generates code to finish the INSERT or UPDATE operation +** that was started by a prior call to sqliteGenerateConstraintChecks. +** The stack must contain keys for all active indices followed by data +** and the recno for the new entry. This routine creates the new +** entries in all indices and in the main table. +** +** The arguments to this routine should be the same as the first six +** arguments to sqliteGenerateConstraintChecks. +*/ +void sqliteCompleteInsertion( + Parse *pParse, /* The parser context */ + Table *pTab, /* the table into which we are inserting */ + int base, /* Index of a read/write cursor pointing at pTab */ + char *aIdxUsed, /* Which indices are used. NULL means all are used */ + int recnoChng, /* True if the record number will change */ + int isUpdate, /* True for UPDATE, False for INSERT */ + int newIdx /* Index of NEW table for triggers. -1 if none */ +){ + int i; + Vdbe *v; + int nIdx; + Index *pIdx; + + v = sqliteGetVdbe(pParse); + assert( v!=0 ); + assert( pTab->pSelect==0 ); /* This table is not a VIEW */ + for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){} + for(i=nIdx-1; i>=0; i--){ + if( aIdxUsed && aIdxUsed[i]==0 ) continue; + sqliteVdbeAddOp(v, OP_IdxPut, base+i+1, 0); + } + sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0); + if( newIdx>=0 ){ + sqliteVdbeAddOp(v, OP_Dup, 1, 0); + sqliteVdbeAddOp(v, OP_Dup, 1, 0); + sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0); + } + sqliteVdbeAddOp(v, OP_PutIntKey, base, pParse->trigStack?0:1); + if( isUpdate && recnoChng ){ + sqliteVdbeAddOp(v, OP_Pop, 1, 0); + } +} diff --git a/sqlitebrowser/sqlitebrowser/sqlite_source/main.c b/sqlitebrowser/sqlitebrowser/sqlite_source/main.c new file mode 100755 index 00000000..c435d96d --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/sqlite_source/main.c @@ -0,0 +1,1011 @@ +/* +** 2001 September 15 +** +** 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. +** +************************************************************************* +** Main file for the SQLite library. The routines in this file +** implement the programmer interface to the library. Routines in +** other files are for internal use by SQLite and should not be +** accessed by users of the library. +** +** $Id: main.c,v 1.1.1.1 2003-08-21 02:24:10 tabuleiro Exp $ +*/ +#include "sqliteInt.h" +#include "os.h" +#include + +/* +** A pointer to this structure is used to communicate information +** from sqliteInit into the sqliteInitCallback. +*/ +typedef struct { + sqlite *db; /* The database being initialized */ + char **pzErrMsg; /* Error message stored here */ +} InitData; + +/* +** Fill the InitData structure with an error message that indicates +** that the database is corrupt. +*/ +static void corruptSchema(InitData *pData){ + sqliteSetString(pData->pzErrMsg, "malformed database schema", 0); +} + +/* +** This is the callback routine for the code that initializes the +** database. See sqliteInit() below for additional information. +** +** Each callback contains the following information: +** +** argv[0] = "file-format" or "schema-cookie" or "table" or "index" +** argv[1] = table or index name or meta statement type. +** argv[2] = root page number for table or index. NULL for meta. +** argv[3] = SQL text for a CREATE TABLE or CREATE INDEX statement. +** argv[4] = "1" for temporary files, "0" for main database, "2" or more +** for auxiliary database files. +** +*/ +static +int sqliteInitCallback(void *pInit, int argc, char **argv, char **azColName){ + InitData *pData = (InitData*)pInit; + Parse sParse; + int nErr = 0; + + assert( argc==5 ); + if( argv == 0 ){ + corruptSchema(pData); + return 1; + } + if( argv[0]==0 ){ + corruptSchema(pData); + return 1; + } + switch( argv[0][0] ){ + case 'v': + case 'i': + case 't': { /* CREATE TABLE, CREATE INDEX, or CREATE VIEW statements */ + if( argv[2]==0 || argv[4]==0 ){ + corruptSchema(pData); + return 1; + } + if( argv[3] && argv[3][0] ){ + /* Call the parser to process a CREATE TABLE, INDEX or VIEW. + ** But because sParse.initFlag is set to 1, no VDBE code is generated + ** or executed. All the parser does is build the internal data + ** structures that describe the table, index, or view. + */ + memset(&sParse, 0, sizeof(sParse)); + sParse.db = pData->db; + sParse.initFlag = 1; + sParse.iDb = atoi(argv[4]); + sParse.newTnum = atoi(argv[2]); + sParse.useCallback = 1; + sqliteRunParser(&sParse, argv[3], pData->pzErrMsg); + }else{ + /* If the SQL column is blank it means this is an index that + ** was created to be the PRIMARY KEY or to fulfill a UNIQUE + ** constraint for a CREATE TABLE. The index should have already + ** been created when we processed the CREATE TABLE. All we have + ** to do here is record the root page number for that index. + */ + int iDb; + Index *pIndex; + + iDb = atoi(argv[4]); + assert( iDb>=0 && iDbdb->nDb ); + pIndex = sqliteFindIndex(pData->db, argv[1], pData->db->aDb[iDb].zName); + if( pIndex==0 || pIndex->tnum!=0 ){ + /* This can occur if there exists an index on a TEMP table which + ** has the same name as another index on a permanent index. Since + ** the permanent table is hidden by the TEMP table, we can also + ** safely ignore the index on the permanent table. + */ + /* Do Nothing */; + }else{ + pIndex->tnum = atoi(argv[2]); + } + } + break; + } + default: { + /* This can not happen! */ + nErr = 1; + assert( nErr==0 ); + } + } + return nErr; +} + +/* +** This is a callback procedure used to reconstruct a table. The +** name of the table to be reconstructed is passed in as argv[0]. +** +** This routine is used to automatically upgrade a database from +** format version 1 or 2 to version 3. The correct operation of +** this routine relys on the fact that no indices are used when +** copying a table out to a temporary file. +*/ +static +int upgrade_3_callback(void *pInit, int argc, char **argv, char **NotUsed){ + InitData *pData = (InitData*)pInit; + int rc; + Table *pTab; + Trigger *pTrig; + char *zErr = 0; + + pTab = sqliteFindTable(pData->db, argv[0], 0); + assert( pTab!=0 ); + assert( sqliteStrICmp(pTab->zName, argv[0])==0 ); + if( pTab ){ + pTrig = pTab->pTrigger; + pTab->pTrigger = 0; /* Disable all triggers before rebuilding the table */ + } + rc = sqlite_exec_printf(pData->db, + "CREATE TEMP TABLE sqlite_x AS SELECT * FROM '%q'; " + "DELETE FROM '%q'; " + "INSERT INTO '%q' SELECT * FROM sqlite_x; " + "DROP TABLE sqlite_x;", + 0, 0, &zErr, argv[0], argv[0], argv[0]); + if( zErr ){ + sqliteSetString(pData->pzErrMsg, zErr, 0); + sqlite_freemem(zErr); + } + + /* If an error occurred in the SQL above, then the transaction will + ** rollback which will delete the internal symbol tables. This will + ** cause the structure that pTab points to be deleted. In case that + ** happened, we need to refetch pTab. + */ + pTab = sqliteFindTable(pData->db, argv[0], 0); + if( pTab ){ + assert( sqliteStrICmp(pTab->zName, argv[0])==0 ); + pTab->pTrigger = pTrig; /* Re-enable triggers */ + } + return rc!=SQLITE_OK; +} + + + +/* +** Attempt to read the database schema and initialize internal +** data structures for a single database file. The index of the +** database file is given by iDb. iDb==0 is used for the main +** database. iDb==1 should never be used. iDb>=2 is used for +** auxiliary databases. Return one of the SQLITE_ error codes to +** indicate success or failure. +*/ +static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){ + int rc; + BtCursor *curMain; + int size; + Table *pTab; + char *azArg[6]; + char zDbNum[30]; + int meta[SQLITE_N_BTREE_META]; + Parse sParse; + InitData initData; + + /* + ** The master database table has a structure like this + */ + static char master_schema[] = + "CREATE TABLE sqlite_master(\n" + " type text,\n" + " name text,\n" + " tbl_name text,\n" + " rootpage integer,\n" + " sql text\n" + ")" + ; + static char temp_master_schema[] = + "CREATE TEMP TABLE sqlite_temp_master(\n" + " type text,\n" + " name text,\n" + " tbl_name text,\n" + " rootpage integer,\n" + " sql text\n" + ")" + ; + + /* The following SQL will read the schema from the master tables. + ** The first version works with SQLite file formats 2 or greater. + ** The second version is for format 1 files. + ** + ** Beginning with file format 2, the rowid for new table entries + ** (including entries in sqlite_master) is an increasing integer. + ** So for file format 2 and later, we can play back sqlite_master + ** and all the CREATE statements will appear in the right order. + ** But with file format 1, table entries were random and so we + ** have to make sure the CREATE TABLEs occur before their corresponding + ** CREATE INDEXs. (We don't have to deal with CREATE VIEW or + ** CREATE TRIGGER in file format 1 because those constructs did + ** not exist then.) + */ + static char init_script[] = + "SELECT type, name, rootpage, sql, 1 FROM sqlite_temp_master " + "UNION ALL " + "SELECT type, name, rootpage, sql, 0 FROM sqlite_master"; + static char older_init_script[] = + "SELECT type, name, rootpage, sql, 1 FROM sqlite_temp_master " + "UNION ALL " + "SELECT type, name, rootpage, sql, 0 FROM sqlite_master " + "WHERE type='table' " + "UNION ALL " + "SELECT type, name, rootpage, sql, 0 FROM sqlite_master " + "WHERE type='index'"; + + + assert( iDb>=0 && iDb!=1 && iDbnDb ); + + /* Construct the schema tables: sqlite_master and sqlite_temp_master + */ + azArg[0] = "table"; + azArg[1] = MASTER_NAME; + azArg[2] = "2"; + azArg[3] = master_schema; + sprintf(zDbNum, "%d", iDb); + azArg[4] = zDbNum; + azArg[5] = 0; + initData.db = db; + initData.pzErrMsg = pzErrMsg; + sqliteInitCallback(&initData, 5, azArg, 0); + pTab = sqliteFindTable(db, MASTER_NAME, "main"); + if( pTab ){ + pTab->readOnly = 1; + } + if( iDb==0 ){ + azArg[1] = TEMP_MASTER_NAME; + azArg[3] = temp_master_schema; + azArg[4] = "1"; + sqliteInitCallback(&initData, 5, azArg, 0); + pTab = sqliteFindTable(db, TEMP_MASTER_NAME, "temp"); + if( pTab ){ + pTab->readOnly = 1; + } + } + + /* Create a cursor to hold the database open + */ + if( db->aDb[iDb].pBt==0 ) return SQLITE_OK; + rc = sqliteBtreeCursor(db->aDb[iDb].pBt, 2, 0, &curMain); + if( rc ){ + sqliteSetString(pzErrMsg, sqlite_error_string(rc), 0); + return rc; + } + + /* Get the database meta information + */ + rc = sqliteBtreeGetMeta(db->aDb[iDb].pBt, meta); + if( rc ){ + sqliteSetString(pzErrMsg, sqlite_error_string(rc), 0); + sqliteBtreeCloseCursor(curMain); + return rc; + } + db->aDb[iDb].schema_cookie = meta[1]; + if( iDb==0 ){ + db->next_cookie = meta[1]; + db->file_format = meta[2]; + size = meta[3]; + if( size==0 ){ size = MAX_PAGES; } + db->cache_size = size; + db->safety_level = meta[4]; + if( db->safety_level==0 ) db->safety_level = 2; + + /* + ** file_format==1 Version 2.1.0. + ** file_format==2 Version 2.2.0. Add support for INTEGER PRIMARY KEY. + ** file_format==3 Version 2.6.0. Fix empty-string index bug. + ** file_format==4 Version 2.7.0. Add support for separate numeric and + ** text datatypes. + */ + if( db->file_format==0 ){ + /* This happens if the database was initially empty */ + db->file_format = 4; + }else if( db->file_format>4 ){ + sqliteBtreeCloseCursor(curMain); + sqliteSetString(pzErrMsg, "unsupported file format", 0); + return SQLITE_ERROR; + } + }else if( db->file_format!=meta[2] || db->file_format<4 ){ + assert( db->file_format>=4 ); + if( meta[2]==0 ){ + sqliteSetString(pzErrMsg, "cannot attach empty database: ", + db->aDb[iDb].zName, 0); + }else{ + sqliteSetString(pzErrMsg, "incompatible file format in auxiliary " + "database: ", db->aDb[iDb].zName, 0); + } + sqliteBtreeClose(db->aDb[iDb].pBt); + db->aDb[iDb].pBt = 0; + return SQLITE_FORMAT; + } + sqliteBtreeSetCacheSize(db->aDb[iDb].pBt, db->cache_size); + sqliteBtreeSetSafetyLevel(db->aDb[iDb].pBt, meta[4]==0 ? 2 : meta[4]); + + /* Read the schema information out of the schema tables + */ + memset(&sParse, 0, sizeof(sParse)); + sParse.db = db; + sParse.xCallback = sqliteInitCallback; + sParse.pArg = (void*)&initData; + sParse.initFlag = 1; + sParse.useCallback = 1; + if( iDb==0 ){ + sqliteRunParser(&sParse, + db->file_format>=2 ? init_script : older_init_script, + pzErrMsg); + }else{ + char *zSql = 0; + sqliteSetString(&zSql, + "SELECT type, name, rootpage, sql, ", zDbNum, " FROM \"", + db->aDb[iDb].zName, "\".sqlite_master", 0); + sqliteRunParser(&sParse, zSql, pzErrMsg); + sqliteFree(zSql); + } + sqliteBtreeCloseCursor(curMain); + if( sqlite_malloc_failed ){ + sqliteSetString(pzErrMsg, "out of memory", 0); + sParse.rc = SQLITE_NOMEM; + sqliteResetInternalSchema(db, 0); + } + if( sParse.rc==SQLITE_OK ){ + DbSetProperty(db, iDb, DB_SchemaLoaded); + if( iDb==0 ){ + DbSetProperty(db, 1, DB_SchemaLoaded); + } + }else{ + sqliteResetInternalSchema(db, iDb); + } + return sParse.rc; +} + +/* +** Initialize all database files - the main database file, the file +** used to store temporary tables, and any additional database files +** 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. An +** attempt is made to initialize the database as soon as it +** is opened. If that fails (perhaps because another process +** has the sqlite_master table locked) than another attempt +** is made the first time the database is accessed. +*/ +int sqliteInit(sqlite *db, char **pzErrMsg){ + int i, rc; + + assert( (db->flags & SQLITE_Initialized)==0 ); + rc = SQLITE_OK; + for(i=0; rc==SQLITE_OK && inDb; i++){ + if( DbHasProperty(db, i, DB_SchemaLoaded) ) continue; + assert( i!=1 ); /* Should have been initialized together with 0 */ + rc = sqliteInitOne(db, i, pzErrMsg); + } + if( rc==SQLITE_OK ){ + db->flags |= SQLITE_Initialized; + sqliteCommitInternalChanges(db); + }else{ + db->flags &= ~SQLITE_Initialized; + } + return rc; +} + +/* +** The version of the library +*/ +const char rcsid[] = "@(#) \044Id: SQLite version " SQLITE_VERSION " $"; +const char sqlite_version[] = SQLITE_VERSION; + +/* +** Does the library expect data to be encoded as UTF-8 or iso8859? The +** following global constant always lets us know. +*/ +#ifdef SQLITE_UTF8 +const char sqlite_encoding[] = "UTF-8"; +#else +const char sqlite_encoding[] = "iso8859"; +#endif + +/* +** Open a new SQLite database. Construct an "sqlite" structure to define +** the state of this database and return a pointer to that structure. +** +** An attempt is made to initialize the in-memory data structures that +** hold the database schema. But if this fails (because the schema file +** is locked) then that step is deferred until the first call to +** sqlite_exec(). +*/ +sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){ + sqlite *db; + int rc, i; + + /* Allocate the sqlite data structure */ + db = sqliteMalloc( sizeof(sqlite) ); + if( pzErrMsg ) *pzErrMsg = 0; + if( db==0 ) goto no_mem_on_open; + db->onError = OE_Default; + db->priorNewRowid = 0; + db->magic = SQLITE_MAGIC_BUSY; + db->nDb = 2; + db->aDb = db->aDbStatic; + sqliteHashInit(&db->aFunc, SQLITE_HASH_STRING, 1); + for(i=0; inDb; i++){ + sqliteHashInit(&db->aDb[i].tblHash, SQLITE_HASH_STRING, 0); + sqliteHashInit(&db->aDb[i].idxHash, SQLITE_HASH_STRING, 0); + sqliteHashInit(&db->aDb[i].trigHash, SQLITE_HASH_STRING, 0); + sqliteHashInit(&db->aDb[i].aFKey, SQLITE_HASH_STRING, 1); + } + + /* Open the backend database driver */ + if( zFilename[0]==':' && strcmp(zFilename,":memory:")==0 ){ + db->temp_store = 2; + } + rc = sqliteBtreeFactory(db, zFilename, 0, MAX_PAGES, &db->aDb[0].pBt); + if( rc!=SQLITE_OK ){ + switch( rc ){ + default: { + sqliteSetString(pzErrMsg, "unable to open database: ", zFilename, 0); + } + } + sqliteFree(db); + sqliteStrRealloc(pzErrMsg); + return 0; + } + db->aDb[0].zName = "main"; + db->aDb[1].zName = "temp"; + + /* Attempt to read the schema */ + sqliteRegisterBuiltinFunctions(db); + rc = sqliteInit(db, pzErrMsg); + db->magic = SQLITE_MAGIC_OPEN; + if( sqlite_malloc_failed ){ + sqlite_close(db); + goto no_mem_on_open; + }else if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){ + sqlite_close(db); + sqliteStrRealloc(pzErrMsg); + return 0; + }else if( pzErrMsg ){ + sqliteFree(*pzErrMsg); + *pzErrMsg = 0; + } + + /* If the database is in formats 1 or 2, then upgrade it to + ** version 3. This will reconstruct all indices. If the + ** upgrade fails for any reason (ex: out of disk space, database + ** is read only, interrupt received, etc.) then refuse to open. + */ + if( rc==SQLITE_OK && db->file_format<3 ){ + char *zErr = 0; + InitData initData; + int meta[SQLITE_N_BTREE_META]; + + initData.db = db; + initData.pzErrMsg = &zErr; + db->file_format = 3; + rc = sqlite_exec(db, + "BEGIN; SELECT name FROM sqlite_master WHERE type='table';", + upgrade_3_callback, + &initData, + &zErr); + if( rc==SQLITE_OK ){ + sqliteBtreeGetMeta(db->aDb[0].pBt, meta); + meta[2] = 4; + sqliteBtreeUpdateMeta(db->aDb[0].pBt, meta); + sqlite_exec(db, "COMMIT", 0, 0, 0); + } + if( rc!=SQLITE_OK ){ + sqliteSetString(pzErrMsg, + "unable to upgrade database to the version 2.6 format", + zErr ? ": " : 0, zErr, 0); + sqlite_freemem(zErr); + sqliteStrRealloc(pzErrMsg); + sqlite_close(db); + return 0; + } + sqlite_freemem(zErr); + } + + /* Return a pointer to the newly opened database structure */ + return db; + +no_mem_on_open: + sqliteSetString(pzErrMsg, "out of memory", 0); + sqliteStrRealloc(pzErrMsg); + return 0; +} + +/* +** Return the ROWID of the most recent insert +*/ +int sqlite_last_insert_rowid(sqlite *db){ + return db->lastRowid; +} + +/* +** Return the number of changes in the most recent call to sqlite_exec(). +*/ +int sqlite_changes(sqlite *db){ + return db->nChange; +} + +/* +** Close an existing SQLite database +*/ +void sqlite_close(sqlite *db){ + HashElem *i; + int j; + db->want_to_close = 1; + if( sqliteSafetyCheck(db) || sqliteSafetyOn(db) ){ + /* printf("DID NOT CLOSE\n"); fflush(stdout); */ + return; + } + db->magic = SQLITE_MAGIC_CLOSED; + for(j=0; jnDb; j++){ + if( db->aDb[j].pBt ){ + sqliteBtreeClose(db->aDb[j].pBt); + db->aDb[j].pBt = 0; + } + if( j>=2 ){ + sqliteFree(db->aDb[j].zName); + db->aDb[j].zName = 0; + } + } + sqliteResetInternalSchema(db, 0); + assert( db->nDb<=2 ); + assert( db->aDb==db->aDbStatic ); + for(i=sqliteHashFirst(&db->aFunc); i; i=sqliteHashNext(i)){ + FuncDef *pFunc, *pNext; + for(pFunc = (FuncDef*)sqliteHashData(i); pFunc; pFunc=pNext){ + pNext = pFunc->pNext; + sqliteFree(pFunc); + } + } + sqliteHashClear(&db->aFunc); + sqliteFree(db); +} + +/* +** Rollback all database files. +*/ +void sqliteRollbackAll(sqlite *db){ + int i; + for(i=0; inDb; i++){ + if( db->aDb[i].pBt ){ + sqliteBtreeRollback(db->aDb[i].pBt); + db->aDb[i].inTrans = 0; + } + } + sqliteRollbackInternalChanges(db); +} + +/* +** This routine does the work of either sqlite_exec() or sqlite_compile(). +** It works like sqlite_exec() if pVm==NULL and it works like sqlite_compile() +** otherwise. +*/ +static int sqliteMain( + sqlite *db, /* The database on which the SQL executes */ + const char *zSql, /* The SQL to be executed */ + sqlite_callback xCallback, /* Invoke this callback routine */ + void *pArg, /* First argument to xCallback() */ + const char **pzTail, /* OUT: Next statement after the first */ + sqlite_vm **ppVm, /* OUT: The virtual machine */ + char **pzErrMsg /* OUT: Write error messages here */ +){ + Parse sParse; + + if( pzErrMsg ) *pzErrMsg = 0; + if( sqliteSafetyOn(db) ) goto exec_misuse; + if( (db->flags & SQLITE_Initialized)==0 ){ + int rc, cnt = 1; + while( (rc = sqliteInit(db, pzErrMsg))==SQLITE_BUSY + && db->xBusyCallback && db->xBusyCallback(db->pBusyArg, "", cnt++)!=0 ){} + if( rc!=SQLITE_OK ){ + sqliteStrRealloc(pzErrMsg); + sqliteSafetyOff(db); + return rc; + } + if( pzErrMsg ){ + sqliteFree(*pzErrMsg); + *pzErrMsg = 0; + } + } + if( db->file_format<3 ){ + sqliteSafetyOff(db); + sqliteSetString(pzErrMsg, "obsolete database file format", 0); + return SQLITE_ERROR; + } + if( db->pVdbe==0 ){ db->nChange = 0; } + memset(&sParse, 0, sizeof(sParse)); + sParse.db = db; + sParse.xCallback = xCallback; + sParse.pArg = pArg; + sParse.useCallback = ppVm==0; + if( db->xTrace ) db->xTrace(db->pTraceArg, zSql); + sqliteRunParser(&sParse, zSql, pzErrMsg); + if( sqlite_malloc_failed ){ + sqliteSetString(pzErrMsg, "out of memory", 0); + sParse.rc = SQLITE_NOMEM; + sqliteRollbackAll(db); + sqliteResetInternalSchema(db, 0); + db->flags &= ~SQLITE_InTrans; + } + if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK; + if( sParse.rc!=SQLITE_OK && pzErrMsg && *pzErrMsg==0 ){ + sqliteSetString(pzErrMsg, sqlite_error_string(sParse.rc), 0); + } + sqliteStrRealloc(pzErrMsg); + if( sParse.rc==SQLITE_SCHEMA ){ + sqliteResetInternalSchema(db, 0); + } + if( sParse.useCallback==0 ){ + assert( ppVm ); + *ppVm = (sqlite_vm*)sParse.pVdbe; + if( pzTail ) *pzTail = sParse.zTail; + } + if( sqliteSafetyOff(db) ) goto exec_misuse; + return sParse.rc; + +exec_misuse: + if( pzErrMsg ){ + *pzErrMsg = 0; + sqliteSetString(pzErrMsg, sqlite_error_string(SQLITE_MISUSE), 0); + sqliteStrRealloc(pzErrMsg); + } + return SQLITE_MISUSE; +} + +/* +** Execute SQL code. Return one of the SQLITE_ success/failure +** codes. Also write an error message into memory obtained from +** malloc() and make *pzErrMsg point to that message. +** +** If the SQL is a query, then for each row in the query result +** the xCallback() function is called. pArg becomes the first +** argument to xCallback(). If xCallback=NULL then no callback +** is invoked, even for queries. +*/ +int sqlite_exec( + sqlite *db, /* The database on which the SQL executes */ + const char *zSql, /* The SQL to be executed */ + sqlite_callback xCallback, /* Invoke this callback routine */ + void *pArg, /* First argument to xCallback() */ + char **pzErrMsg /* Write error messages here */ +){ + return sqliteMain(db, zSql, xCallback, pArg, 0, 0, pzErrMsg); +} + +/* +** Compile a single statement of SQL into a virtual machine. Return one +** of the SQLITE_ success/failure codes. Also write an error message into +** memory obtained from malloc() and make *pzErrMsg point to that message. +*/ +int sqlite_compile( + sqlite *db, /* The database on which the SQL executes */ + const char *zSql, /* The SQL to be executed */ + const char **pzTail, /* OUT: Next statement after the first */ + sqlite_vm **ppVm, /* OUT: The virtual machine */ + char **pzErrMsg /* OUT: Write error messages here */ +){ + return sqliteMain(db, zSql, 0, 0, pzTail, ppVm, pzErrMsg); +} + +/* +** The following routine destroys a virtual machine that is created by +** the sqlite_compile() routine. +** +** The integer returned is an SQLITE_ success/failure code that describes +** the result of executing the virtual machine. An error message is +** written into memory obtained from malloc and *pzErrMsg is made to +** point to that error if pzErrMsg is not NULL. The calling routine +** should use sqlite_freemem() to delete the message when it has finished +** with it. +*/ +int sqlite_finalize( + sqlite_vm *pVm, /* The virtual machine to be destroyed */ + char **pzErrMsg /* OUT: Write error messages here */ +){ + int rc = sqliteVdbeFinalize((Vdbe*)pVm, pzErrMsg); + sqliteStrRealloc(pzErrMsg); + return rc; +} + +/* +** Destroy a virtual machine in the same manner as sqlite_finalize(). If +** possible, leave *ppVm pointing at a new virtual machine which may be +** used to re-execute the query. +*/ +int sqlite_reset( + sqlite_vm *pVm, /* The virtual machine to be destroyed */ + char **pzErrMsg, /* OUT: Write error messages here */ + sqlite_vm **ppVm /* OUT: The new virtual machine */ +){ + int rc = sqliteVdbeReset((Vdbe*)pVm, pzErrMsg, (Vdbe **)ppVm); + sqliteStrRealloc(pzErrMsg); + return rc; +} + +/* +** Return a static string that describes the kind of error specified in the +** argument. +*/ +const char *sqlite_error_string(int rc){ + const char *z; + switch( rc ){ + case SQLITE_OK: z = "not an error"; break; + case SQLITE_ERROR: z = "SQL logic error or missing database"; break; + case SQLITE_INTERNAL: z = "internal SQLite implementation flaw"; break; + case SQLITE_PERM: z = "access permission denied"; break; + case SQLITE_ABORT: z = "callback requested query abort"; break; + case SQLITE_BUSY: z = "database is locked"; break; + case SQLITE_LOCKED: z = "database table is locked"; break; + case SQLITE_NOMEM: z = "out of memory"; break; + case SQLITE_READONLY: z = "attempt to write a readonly database"; break; + case SQLITE_INTERRUPT: z = "interrupted"; break; + case SQLITE_IOERR: z = "disk I/O error"; break; + case SQLITE_CORRUPT: z = "database disk image is malformed"; break; + case SQLITE_NOTFOUND: z = "table or record not found"; break; + case SQLITE_FULL: z = "database is full"; break; + case SQLITE_CANTOPEN: z = "unable to open database file"; break; + case SQLITE_PROTOCOL: z = "database locking protocol failure"; break; + case SQLITE_EMPTY: z = "table contains no data"; break; + case SQLITE_SCHEMA: z = "database schema has changed"; break; + case SQLITE_TOOBIG: z = "too much data for one table row"; break; + case SQLITE_CONSTRAINT: z = "constraint failed"; break; + case SQLITE_MISMATCH: z = "datatype mismatch"; break; + case SQLITE_MISUSE: z = "library routine called out of sequence";break; + case SQLITE_NOLFS: z = "kernel lacks large file support"; break; + case SQLITE_AUTH: z = "authorization denied"; break; + case SQLITE_FORMAT: z = "auxiliary database format error"; break; + default: z = "unknown error"; break; + } + return z; +} + +/* +** This routine implements a busy callback that sleeps and tries +** again until a timeout value is reached. The timeout value is +** an integer number of milliseconds passed in as the first +** argument. +*/ +static int sqliteDefaultBusyCallback( + void *Timeout, /* Maximum amount of time to wait */ + const char *NotUsed, /* The name of the table that is busy */ + int count /* Number of times table has been busy */ +){ +#if SQLITE_MIN_SLEEP_MS==1 + int delay = 10; + int prior_delay = 0; + int timeout = (int)Timeout; + int i; + + for(i=1; i=1000 ){ + delay = 1000; + prior_delay += 1000*(count - i - 1); + break; + } + } + if( prior_delay + delay > timeout ){ + delay = timeout - prior_delay; + if( delay<=0 ) return 0; + } + sqliteOsSleep(delay); + return 1; +#else + int timeout = (int)Timeout; + if( (count+1)*1000 > timeout ){ + return 0; + } + sqliteOsSleep(1000); + return 1; +#endif +} + +/* +** This routine sets the busy callback for an Sqlite database to the +** given callback function with the given argument. +*/ +void sqlite_busy_handler( + sqlite *db, + int (*xBusy)(void*,const char*,int), + void *pArg +){ + db->xBusyCallback = xBusy; + db->pBusyArg = pArg; +} + +/* +** This routine installs a default busy handler that waits for the +** specified number of milliseconds before returning 0. +*/ +void sqlite_busy_timeout(sqlite *db, int ms){ + if( ms>0 ){ + sqlite_busy_handler(db, sqliteDefaultBusyCallback, (void*)ms); + }else{ + sqlite_busy_handler(db, 0, 0); + } +} + +/* +** Cause any pending operation to stop at its earliest opportunity. +*/ +void sqlite_interrupt(sqlite *db){ + db->flags |= SQLITE_Interrupt; +} + +/* +** Windows systems should call this routine to free memory that +** is returned in the in the errmsg parameter of sqlite_open() when +** SQLite is a DLL. For some reason, it does not work to call free() +** directly. +** +** Note that we need to call free() not sqliteFree() here, since every +** string that is exported from SQLite should have already passed through +** sqliteStrRealloc(). +*/ +void sqlite_freemem(void *p){ free(p); } + +/* +** Windows systems need functions to call to return the sqlite_version +** and sqlite_encoding strings since they are unable to access constants +** within DLLs. +*/ +const char *sqlite_libversion(void){ return sqlite_version; } +const char *sqlite_libencoding(void){ return sqlite_encoding; } + +/* +** Create new user-defined functions. The sqlite_create_function() +** routine creates a regular function and sqlite_create_aggregate() +** creates an aggregate function. +** +** Passing a NULL xFunc argument or NULL xStep and xFinalize arguments +** disables the function. Calling sqlite_create_function() with the +** same name and number of arguments as a prior call to +** sqlite_create_aggregate() disables the prior call to +** sqlite_create_aggregate(), and vice versa. +** +** If nArg is -1 it means that this function will accept any number +** of arguments, including 0. +*/ +int sqlite_create_function( + sqlite *db, /* Add the function to this database connection */ + const char *zName, /* Name of the function to add */ + int nArg, /* Number of arguments */ + void (*xFunc)(sqlite_func*,int,const char**), /* The implementation */ + void *pUserData /* User data */ +){ + FuncDef *p; + int nName; + if( db==0 || zName==0 || sqliteSafetyCheck(db) ) return 1; + nName = strlen(zName); + if( nName>255 ) return 1; + p = sqliteFindFunction(db, zName, nName, nArg, 1); + if( p==0 ) return 1; + p->xFunc = xFunc; + p->xStep = 0; + p->xFinalize = 0; + p->pUserData = pUserData; + return 0; +} +int sqlite_create_aggregate( + sqlite *db, /* Add the function to this database connection */ + const char *zName, /* Name of the function to add */ + int nArg, /* Number of arguments */ + void (*xStep)(sqlite_func*,int,const char**), /* The step function */ + void (*xFinalize)(sqlite_func*), /* The finalizer */ + void *pUserData /* User data */ +){ + FuncDef *p; + int nName; + if( db==0 || zName==0 || sqliteSafetyCheck(db) ) return 1; + nName = strlen(zName); + if( nName>255 ) return 1; + p = sqliteFindFunction(db, zName, nName, nArg, 1); + if( p==0 ) return 1; + p->xFunc = 0; + p->xStep = xStep; + p->xFinalize = xFinalize; + p->pUserData = pUserData; + return 0; +} + +/* +** Change the datatype for all functions with a given name. See the +** header comment for the prototype of this function in sqlite.h for +** additional information. +*/ +int sqlite_function_type(sqlite *db, const char *zName, int dataType){ + FuncDef *p = (FuncDef*)sqliteHashFind(&db->aFunc, zName, strlen(zName)); + while( p ){ + p->dataType = dataType; + p = p->pNext; + } + return SQLITE_OK; +} + +/* +** Register a trace function. The pArg from the previously registered trace +** is returned. +** +** A NULL trace function means that no tracing is executes. A non-NULL +** trace is a pointer to a function that is invoked at the start of each +** sqlite_exec(). +*/ +void *sqlite_trace(sqlite *db, void (*xTrace)(void*,const char*), void *pArg){ + void *pOld = db->pTraceArg; + db->xTrace = xTrace; + db->pTraceArg = pArg; + return pOld; +} + +/* +** 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 +** the database is stored in memory (and is thus forgotten as soon as +** the connection is closed.) If zFilename is NULL then the database +** is for temporary use only and is deleted as soon as the connection +** is closed. +** +** A temporary database can be either a disk file (that is automatically +** deleted when the file is closed) or a set of red-black trees held in memory, +** depending on the values of the TEMP_STORE compile-time macro and the +** db->temp_store variable, according to the following chart: +** +** TEMP_STORE db->temp_store Location of temporary database +** ---------- -------------- ------------------------------ +** 0 any file +** 1 1 file +** 1 2 memory +** 1 0 file +** 2 1 file +** 2 2 memory +** 2 0 memory +** 3 any memory +*/ +int sqliteBtreeFactory( + const sqlite *db, /* Main database when opening aux otherwise 0 */ + const char *zFilename, /* Name of the file containing the BTree database */ + int omitJournal, /* if TRUE then do not journal this file */ + int nCache, /* How many pages in the page cache */ + Btree **ppBtree){ /* Pointer to new Btree object written here */ + + assert( ppBtree != 0); + +#ifndef SQLITE_OMIT_INMEMORYDB + if( zFilename==0 ){ + if (TEMP_STORE == 0) { + /* Always use file based temporary DB */ + return sqliteBtreeOpen(0, omitJournal, nCache, ppBtree); + } else if (TEMP_STORE == 1 || TEMP_STORE == 2) { + /* Switch depending on compile-time and/or runtime settings. */ + int location = db->temp_store==0 ? TEMP_STORE : db->temp_store; + + if (location == 1) { + return sqliteBtreeOpen(zFilename, omitJournal, nCache, ppBtree); + } else { + return sqliteRbtreeOpen(0, 0, 0, ppBtree); + } + } else { + /* Always use in-core DB */ + return sqliteRbtreeOpen(0, 0, 0, ppBtree); + } + }else if( zFilename[0]==':' && strcmp(zFilename,":memory:")==0 ){ + return sqliteRbtreeOpen(0, 0, 0, ppBtree); + }else +#endif + { + return sqliteBtreeOpen(zFilename, omitJournal, nCache, ppBtree); + } +} diff --git a/sqlitebrowser/sqlitebrowser/sqlite_source/opcodes.c b/sqlitebrowser/sqlitebrowser/sqlite_source/opcodes.c new file mode 100755 index 00000000..3cdf016b --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/sqlite_source/opcodes.c @@ -0,0 +1,132 @@ +/* Automatically generated file. Do not edit */ +char *sqliteOpcodeNames[] = { "???", + "Goto", + "Gosub", + "Return", + "Halt", + "Integer", + "String", + "Pop", + "Dup", + "Pull", + "Push", + "ColumnName", + "Callback", + "NullCallback", + "Concat", + "Add", + "Subtract", + "Multiply", + "Divide", + "Remainder", + "Function", + "BitAnd", + "BitOr", + "ShiftLeft", + "ShiftRight", + "AddImm", + "IsNumeric", + "MustBeInt", + "Eq", + "Ne", + "Lt", + "Le", + "Gt", + "Ge", + "StrEq", + "StrNe", + "StrLt", + "StrLe", + "StrGt", + "StrGe", + "And", + "Or", + "Negative", + "AbsValue", + "Not", + "BitNot", + "Noop", + "If", + "IfNot", + "IsNull", + "NotNull", + "MakeRecord", + "MakeIdxKey", + "MakeKey", + "IncrKey", + "Checkpoint", + "Transaction", + "Commit", + "Rollback", + "ReadCookie", + "SetCookie", + "VerifyCookie", + "OpenRead", + "OpenWrite", + "OpenTemp", + "OpenPseudo", + "Close", + "MoveLt", + "MoveTo", + "Distinct", + "NotFound", + "Found", + "IsUnique", + "NotExists", + "NewRecno", + "PutIntKey", + "PutStrKey", + "Delete", + "KeyAsData", + "RowData", + "Column", + "Recno", + "FullKey", + "NullRow", + "Last", + "Rewind", + "Prev", + "Next", + "IdxPut", + "IdxDelete", + "IdxRecno", + "IdxLT", + "IdxGT", + "IdxGE", + "Destroy", + "Clear", + "CreateIndex", + "CreateTable", + "IntegrityCk", + "ListWrite", + "ListRewind", + "ListRead", + "ListReset", + "ListPush", + "ListPop", + "SortPut", + "SortMakeRec", + "SortMakeKey", + "Sort", + "SortNext", + "SortCallback", + "SortReset", + "FileOpen", + "FileRead", + "FileColumn", + "MemStore", + "MemLoad", + "MemIncr", + "AggReset", + "AggInit", + "AggFunc", + "AggFocus", + "AggSet", + "AggGet", + "AggNext", + "SetInsert", + "SetFound", + "SetNotFound", + "SetFirst", + "SetNext", +}; diff --git a/sqlitebrowser/sqlitebrowser/sqlite_source/opcodes.h b/sqlitebrowser/sqlitebrowser/sqlite_source/opcodes.h new file mode 100755 index 00000000..0e4a5faa --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/sqlite_source/opcodes.h @@ -0,0 +1,130 @@ +/* Automatically generated file. Do not edit */ +#define OP_Goto 1 +#define OP_Gosub 2 +#define OP_Return 3 +#define OP_Halt 4 +#define OP_Integer 5 +#define OP_String 6 +#define OP_Pop 7 +#define OP_Dup 8 +#define OP_Pull 9 +#define OP_Push 10 +#define OP_ColumnName 11 +#define OP_Callback 12 +#define OP_NullCallback 13 +#define OP_Concat 14 +#define OP_Add 15 +#define OP_Subtract 16 +#define OP_Multiply 17 +#define OP_Divide 18 +#define OP_Remainder 19 +#define OP_Function 20 +#define OP_BitAnd 21 +#define OP_BitOr 22 +#define OP_ShiftLeft 23 +#define OP_ShiftRight 24 +#define OP_AddImm 25 +#define OP_IsNumeric 26 +#define OP_MustBeInt 27 +#define OP_Eq 28 +#define OP_Ne 29 +#define OP_Lt 30 +#define OP_Le 31 +#define OP_Gt 32 +#define OP_Ge 33 +#define OP_StrEq 34 +#define OP_StrNe 35 +#define OP_StrLt 36 +#define OP_StrLe 37 +#define OP_StrGt 38 +#define OP_StrGe 39 +#define OP_And 40 +#define OP_Or 41 +#define OP_Negative 42 +#define OP_AbsValue 43 +#define OP_Not 44 +#define OP_BitNot 45 +#define OP_Noop 46 +#define OP_If 47 +#define OP_IfNot 48 +#define OP_IsNull 49 +#define OP_NotNull 50 +#define OP_MakeRecord 51 +#define OP_MakeIdxKey 52 +#define OP_MakeKey 53 +#define OP_IncrKey 54 +#define OP_Checkpoint 55 +#define OP_Transaction 56 +#define OP_Commit 57 +#define OP_Rollback 58 +#define OP_ReadCookie 59 +#define OP_SetCookie 60 +#define OP_VerifyCookie 61 +#define OP_OpenRead 62 +#define OP_OpenWrite 63 +#define OP_OpenTemp 64 +#define OP_OpenPseudo 65 +#define OP_Close 66 +#define OP_MoveLt 67 +#define OP_MoveTo 68 +#define OP_Distinct 69 +#define OP_NotFound 70 +#define OP_Found 71 +#define OP_IsUnique 72 +#define OP_NotExists 73 +#define OP_NewRecno 74 +#define OP_PutIntKey 75 +#define OP_PutStrKey 76 +#define OP_Delete 77 +#define OP_KeyAsData 78 +#define OP_RowData 79 +#define OP_Column 80 +#define OP_Recno 81 +#define OP_FullKey 82 +#define OP_NullRow 83 +#define OP_Last 84 +#define OP_Rewind 85 +#define OP_Prev 86 +#define OP_Next 87 +#define OP_IdxPut 88 +#define OP_IdxDelete 89 +#define OP_IdxRecno 90 +#define OP_IdxLT 91 +#define OP_IdxGT 92 +#define OP_IdxGE 93 +#define OP_Destroy 94 +#define OP_Clear 95 +#define OP_CreateIndex 96 +#define OP_CreateTable 97 +#define OP_IntegrityCk 98 +#define OP_ListWrite 99 +#define OP_ListRewind 100 +#define OP_ListRead 101 +#define OP_ListReset 102 +#define OP_ListPush 103 +#define OP_ListPop 104 +#define OP_SortPut 105 +#define OP_SortMakeRec 106 +#define OP_SortMakeKey 107 +#define OP_Sort 108 +#define OP_SortNext 109 +#define OP_SortCallback 110 +#define OP_SortReset 111 +#define OP_FileOpen 112 +#define OP_FileRead 113 +#define OP_FileColumn 114 +#define OP_MemStore 115 +#define OP_MemLoad 116 +#define OP_MemIncr 117 +#define OP_AggReset 118 +#define OP_AggInit 119 +#define OP_AggFunc 120 +#define OP_AggFocus 121 +#define OP_AggSet 122 +#define OP_AggGet 123 +#define OP_AggNext 124 +#define OP_SetInsert 125 +#define OP_SetFound 126 +#define OP_SetNotFound 127 +#define OP_SetFirst 128 +#define OP_SetNext 129 diff --git a/sqlitebrowser/sqlitebrowser/sqlite_source/os.c b/sqlitebrowser/sqlitebrowser/sqlite_source/os.c new file mode 100755 index 00000000..6d317192 --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/sqlite_source/os.c @@ -0,0 +1,1544 @@ +/* +** 2001 September 16 +** +** 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 code that is specific to particular operating +** systems. The purpose of this file is to provide a uniform abstraction +** on which the rest of SQLite can operate. +*/ +#include "os.h" /* Must be first to enable large file support */ +#include "sqliteInt.h" + +#if OS_UNIX +# include +# include +# include +# ifndef O_LARGEFILE +# define O_LARGEFILE 0 +# endif +# ifdef SQLITE_DISABLE_LFS +# undef O_LARGEFILE +# define O_LARGEFILE 0 +# endif +# ifndef O_NOFOLLOW +# define O_NOFOLLOW 0 +# endif +# ifndef O_BINARY +# define O_BINARY 0 +# endif +#endif + + +#if OS_WIN +# include +#endif + +#if OS_MAC +# include +# include +# include +# include +# include +# include +# include +#endif + +/* +** 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? +*/ +#ifdef __DJGPP__ +# define fcntl(A,B,C) 0 +#endif + +/* +** Macros for performance tracing. Normally turned off +*/ +#if 0 +static int last_page = 0; +__inline__ unsigned long long int hwtime(void){ + unsigned long long int x; + __asm__("rdtsc\n\t" + "mov %%edx, %%ecx\n\t" + :"=A" (x)); + return x; +} +static unsigned long long int g_start; +static unsigned int elapse; +#define TIMER_START g_start=hwtime() +#define TIMER_END elapse=hwtime()-g_start +#define SEEK(X) last_page=(X) +#define TRACE1(X) fprintf(stderr,X) +#define TRACE2(X,Y) fprintf(stderr,X,Y) +#define TRACE3(X,Y,Z) fprintf(stderr,X,Y,Z) +#define TRACE4(X,Y,Z,A) fprintf(stderr,X,Y,Z,A) +#define TRACE5(X,Y,Z,A,B) fprintf(stderr,X,Y,Z,A,B) +#else +#define TIMER_START +#define TIMER_END +#define SEEK(X) +#define TRACE1(X) +#define TRACE2(X,Y) +#define TRACE3(X,Y,Z) +#define TRACE4(X,Y,Z,A) +#define TRACE5(X,Y,Z,A,B) +#endif + + +#if OS_UNIX +/* +** Here is the dirt on POSIX advisory locks: ANSI STD 1003.1 (1996) +** section 6.5.2.2 lines 483 through 490 specify that when a process +** sets or clears a lock, that operation overrides any prior locks set +** by the same process. It does not explicitly say so, but this implies +** that it overrides locks set by the same process using a different +** file descriptor. Consider this test case: +** +** int fd1 = open("./file1", O_RDWR|O_CREAT, 0644); +** int fd2 = open("./file2", O_RDWR|O_CREAT, 0644); +** +** Suppose ./file1 and ./file2 are really the same file (because +** one is a hard or symbolic link to the other) then if you set +** an exclusive lock on fd1, then try to get an exclusive lock +** on fd2, it works. I would have expected the second lock to +** fail since there was already a lock on the file due to fd1. +** But not so. Since both locks came from the same process, the +** second overrides the first, even though they were on different +** file descriptors opened on different file names. +** +** Bummer. If you ask me, this is broken. Badly broken. It means +** that we cannot use POSIX locks to synchronize file access among +** competing threads of the same process. POSIX locks will work fine +** to synchronize access for threads in separate processes, but not +** threads within the same process. +** +** To work around the problem, SQLite has to manage file locks internally +** on its own. Whenever a new database is opened, we have to find the +** specific inode of the database file (the inode is determined by the +** st_dev and st_ino fields of the stat structure that fstat() fills in) +** and check for locks already existing on that inode. When locks are +** created or removed, we have to look at our own internal record of the +** locks to see if another thread has previously set a lock on that same +** inode. +** +** The OsFile structure for POSIX is no longer just an integer file +** descriptor. It is now a structure that holds the integer file +** descriptor and a pointer to a structure that describes the internal +** locks on the corresponding inode. There is one locking structure +** per inode, so if the same inode is opened twice, both OsFile structures +** point to the same locking structure. The locking structure keeps +** a reference count (so we will know when to delete it) and a "cnt" +** field that tells us its internal lock status. cnt==0 means the +** file is unlocked. cnt==-1 means the file has an exclusive lock. +** cnt>0 means there are cnt shared locks on the file. +** +** Any attempt to lock or unlock a file first checks the locking +** structure. The fcntl() system call is only invoked to set a +** POSIX lock if the internal lock structure transitions between +** a locked and an unlocked state. +*/ + +/* +** An instance of the following structure serves as the key used +** to locate a particular lockInfo structure given its inode. +*/ +struct inodeKey { + dev_t dev; /* Device number */ + ino_t ino; /* Inode number */ +}; + +/* +** An instance of the following structure is allocated for each inode. +** A single inode can have multiple file descriptors, so each OsFile +** structure contains a pointer to an instance of this object and this +** object keeps a count of the number of OsFiles pointing to it. +*/ +struct lockInfo { + struct inodeKey key; /* The lookup key */ + int cnt; /* 0: unlocked. -1: write lock. 1...: read lock. */ + int nRef; /* Number of pointers to this structure */ +}; + +/* +** This hash table maps inodes (in the form of inodeKey structures) into +** pointers to lockInfo structures. +*/ +static Hash lockHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 }; + +/* +** Given a file descriptor, locate a lockInfo structure that describes +** that file descriptor. Create a new one if necessary. NULL might +** be returned if malloc() fails. +*/ +static struct lockInfo *findLockInfo(int fd){ + int rc; + struct inodeKey key; + struct stat statbuf; + struct lockInfo *pInfo; + rc = fstat(fd, &statbuf); + if( rc!=0 ) return 0; + memset(&key, 0, sizeof(key)); + key.dev = statbuf.st_dev; + key.ino = statbuf.st_ino; + pInfo = (struct lockInfo*)sqliteHashFind(&lockHash, &key, sizeof(key)); + if( pInfo==0 ){ + struct lockInfo *pOld; + pInfo = sqliteMalloc( sizeof(*pInfo) ); + if( pInfo==0 ) return 0; + pInfo->key = key; + pInfo->nRef = 1; + pInfo->cnt = 0; + pOld = sqliteHashInsert(&lockHash, &pInfo->key, sizeof(key), pInfo); + if( pOld!=0 ){ + assert( pOld==pInfo ); + sqliteFree(pInfo); + pInfo = 0; + } + }else{ + pInfo->nRef++; + } + return pInfo; +} + +/* +** Release a lockInfo structure previously allocated by findLockInfo(). +*/ +static void releaseLockInfo(struct lockInfo *pInfo){ + pInfo->nRef--; + if( pInfo->nRef==0 ){ + sqliteHashInsert(&lockHash, &pInfo->key, sizeof(pInfo->key), 0); + sqliteFree(pInfo); + } +} +#endif /** POSIX advisory lock work-around **/ + +/* +** If we compile with the SQLITE_TEST macro set, then the following block +** of code will give us the ability to simulate a disk I/O error. This +** is used for testing the I/O recovery logic. +*/ +#ifdef SQLITE_TEST +int sqlite_io_error_pending = 0; +#define SimulateIOError(A) \ + if( sqlite_io_error_pending ) \ + if( sqlite_io_error_pending-- == 1 ){ local_ioerr(); return A; } +static void local_ioerr(){ + sqlite_io_error_pending = 0; /* Really just a place to set a breakpoint */ +} +#else +#define SimulateIOError(A) +#endif + +/* +** When testing, keep a count of the number of open files. +*/ +#ifdef SQLITE_TEST +int sqlite_open_file_count = 0; +#define OpenCounter(X) sqlite_open_file_count+=(X) +#else +#define OpenCounter(X) +#endif + + +/* +** Delete the named file +*/ +int sqliteOsDelete(const char *zFilename){ +#if OS_UNIX + unlink(zFilename); +#endif +#if OS_WIN + DeleteFile(zFilename); +#endif +#if OS_MAC + unlink(zFilename); +#endif + return SQLITE_OK; +} + +/* +** Return TRUE if the named file exists. +*/ +int sqliteOsFileExists(const char *zFilename){ +#if OS_UNIX + return access(zFilename, 0)==0; +#endif +#if OS_WIN + return GetFileAttributes(zFilename) != 0xffffffff; +#endif +#if OS_MAC + return access(zFilename, 0)==0; +#endif +} + + +#if 0 /* NOT USED */ +/* +** Change the name of an existing file. +*/ +int sqliteOsFileRename(const char *zOldName, const char *zNewName){ +#if OS_UNIX + if( link(zOldName, zNewName) ){ + return SQLITE_ERROR; + } + unlink(zOldName); + return SQLITE_OK; +#endif +#if OS_WIN + if( !MoveFile(zOldName, zNewName) ){ + return SQLITE_ERROR; + } + return SQLITE_OK; +#endif +#if OS_MAC + /**** FIX ME ***/ + return SQLITE_ERROR; +#endif +} +#endif /* NOT USED */ + +/* +** Attempt to open a file for both reading and writing. If that +** fails, try opening it read-only. If the file does not exist, +** try to create it. +** +** On success, a handle for the open file is written to *id +** and *pReadonly is set to 0 if the file was opened for reading and +** writing or 1 if the file was opened read-only. The function returns +** SQLITE_OK. +** +** On failure, the function returns SQLITE_CANTOPEN and leaves +** *id and *pReadonly unchanged. +*/ +int sqliteOsOpenReadWrite( + const char *zFilename, + OsFile *id, + int *pReadonly +){ +#if OS_UNIX + id->fd = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY, 0644); + if( id->fd<0 ){ + id->fd = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY); + if( id->fd<0 ){ + return SQLITE_CANTOPEN; + } + *pReadonly = 1; + }else{ + *pReadonly = 0; + } + sqliteOsEnterMutex(); + id->pLock = findLockInfo(id->fd); + sqliteOsLeaveMutex(); + if( id->pLock==0 ){ + close(id->fd); + return SQLITE_NOMEM; + } + id->locked = 0; + TRACE3("OPEN %-3d %s\n", id->fd, zFilename); + OpenCounter(+1); + return SQLITE_OK; +#endif +#if OS_WIN + HANDLE h = CreateFile(zFilename, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, + NULL + ); + if( h==INVALID_HANDLE_VALUE ){ + h = CreateFile(zFilename, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, + NULL + ); + if( h==INVALID_HANDLE_VALUE ){ + return SQLITE_CANTOPEN; + } + *pReadonly = 1; + }else{ + *pReadonly = 0; + } + id->h = h; + id->locked = 0; + OpenCounter(+1); + return SQLITE_OK; +#endif +#if OS_MAC + FSSpec fsSpec; +# ifdef _LARGE_FILE + HFSUniStr255 dfName; + FSRef fsRef; + if( __path2fss(zFilename, &fsSpec) != noErr ){ + if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr ) + return SQLITE_CANTOPEN; + } + if( FSpMakeFSRef(&fsSpec, &fsRef) != noErr ) + return SQLITE_CANTOPEN; + FSGetDataForkName(&dfName); + if( FSOpenFork(&fsRef, dfName.length, dfName.unicode, + fsRdWrShPerm, &(id->refNum)) != noErr ){ + if( FSOpenFork(&fsRef, dfName.length, dfName.unicode, + fsRdWrPerm, &(id->refNum)) != noErr ){ + if (FSOpenFork(&fsRef, dfName.length, dfName.unicode, + fsRdPerm, &(id->refNum)) != noErr ) + return SQLITE_CANTOPEN; + else + *pReadonly = 1; + } else + *pReadonly = 0; + } else + *pReadonly = 0; +# else + __path2fss(zFilename, &fsSpec); + if( !sqliteOsFileExists(zFilename) ){ + if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr ) + return SQLITE_CANTOPEN; + } + if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrShPerm, &(id->refNum)) != noErr ){ + if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrPerm, &(id->refNum)) != noErr ){ + if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdPerm, &(id->refNum)) != noErr ) + return SQLITE_CANTOPEN; + else + *pReadonly = 1; + } else + *pReadonly = 0; + } else + *pReadonly = 0; +# endif + if( HOpenRF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrShPerm, &(id->refNumRF)) != noErr){ + id->refNumRF = -1; + } + id->locked = 0; + id->delOnClose = 0; + OpenCounter(+1); + return SQLITE_OK; +#endif +} + + +/* +** Attempt to open a new file for exclusive access by this process. +** The file will be opened for both reading and writing. To avoid +** a potential security problem, we do not allow the file to have +** previously existed. Nor do we allow the file to be a symbolic +** link. +** +** If delFlag is true, then make arrangements to automatically delete +** the file when it is closed. +** +** On success, write the file handle into *id and return SQLITE_OK. +** +** On failure, return SQLITE_CANTOPEN. +*/ +int sqliteOsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){ +#if OS_UNIX + if( access(zFilename, 0)==0 ){ + return SQLITE_CANTOPEN; + } + id->fd = open(zFilename, + O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_LARGEFILE|O_BINARY, 0600); + if( id->fd<0 ){ + return SQLITE_CANTOPEN; + } + sqliteOsEnterMutex(); + id->pLock = findLockInfo(id->fd); + sqliteOsLeaveMutex(); + if( id->pLock==0 ){ + close(id->fd); + unlink(zFilename); + return SQLITE_NOMEM; + } + id->locked = 0; + if( delFlag ){ + unlink(zFilename); + } + TRACE3("OPEN-EX %-3d %s\n", id->fd, zFilename); + OpenCounter(+1); + return SQLITE_OK; +#endif +#if OS_WIN + HANDLE h; + int fileflags; + if( delFlag ){ + fileflags = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_RANDOM_ACCESS + | FILE_FLAG_DELETE_ON_CLOSE; + }else{ + fileflags = FILE_FLAG_RANDOM_ACCESS; + } + h = CreateFile(zFilename, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + CREATE_ALWAYS, + fileflags, + NULL + ); + if( h==INVALID_HANDLE_VALUE ){ + return SQLITE_CANTOPEN; + } + id->h = h; + id->locked = 0; + OpenCounter(+1); + return SQLITE_OK; +#endif +#if OS_MAC + FSSpec fsSpec; +# ifdef _LARGE_FILE + HFSUniStr255 dfName; + FSRef fsRef; + __path2fss(zFilename, &fsSpec); + if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr ) + return SQLITE_CANTOPEN; + if( FSpMakeFSRef(&fsSpec, &fsRef) != noErr ) + return SQLITE_CANTOPEN; + FSGetDataForkName(&dfName); + if( FSOpenFork(&fsRef, dfName.length, dfName.unicode, + fsRdWrPerm, &(id->refNum)) != noErr ) + return SQLITE_CANTOPEN; +# else + __path2fss(zFilename, &fsSpec); + if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr ) + return SQLITE_CANTOPEN; + if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrPerm, &(id->refNum)) != noErr ) + return SQLITE_CANTOPEN; +# endif + id->refNumRF = -1; + id->locked = 0; + id->delOnClose = delFlag; + if (delFlag) + id->pathToDel = sqliteOsFullPathname(zFilename); + OpenCounter(+1); + return SQLITE_OK; +#endif +} + +/* +** Attempt to open a new file for read-only access. +** +** On success, write the file handle into *id and return SQLITE_OK. +** +** On failure, return SQLITE_CANTOPEN. +*/ +int sqliteOsOpenReadOnly(const char *zFilename, OsFile *id){ +#if OS_UNIX + id->fd = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY); + if( id->fd<0 ){ + return SQLITE_CANTOPEN; + } + sqliteOsEnterMutex(); + id->pLock = findLockInfo(id->fd); + sqliteOsLeaveMutex(); + if( id->pLock==0 ){ + close(id->fd); + return SQLITE_NOMEM; + } + id->locked = 0; + TRACE3("OPEN-RO %-3d %s\n", id->fd, zFilename); + OpenCounter(+1); + return SQLITE_OK; +#endif +#if OS_WIN + HANDLE h = CreateFile(zFilename, + GENERIC_READ, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, + NULL + ); + if( h==INVALID_HANDLE_VALUE ){ + return SQLITE_CANTOPEN; + } + id->h = h; + id->locked = 0; + OpenCounter(+1); + return SQLITE_OK; +#endif +#if OS_MAC + FSSpec fsSpec; +# ifdef _LARGE_FILE + HFSUniStr255 dfName; + FSRef fsRef; + if( __path2fss(zFilename, &fsSpec) != noErr ) + return SQLITE_CANTOPEN; + if( FSpMakeFSRef(&fsSpec, &fsRef) != noErr ) + return SQLITE_CANTOPEN; + FSGetDataForkName(&dfName); + if( FSOpenFork(&fsRef, dfName.length, dfName.unicode, + fsRdPerm, &(id->refNum)) != noErr ) + return SQLITE_CANTOPEN; +# else + __path2fss(zFilename, &fsSpec); + if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdPerm, &(id->refNum)) != noErr ) + return SQLITE_CANTOPEN; +# endif + if( HOpenRF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrShPerm, &(id->refNumRF)) != noErr){ + id->refNumRF = -1; + } + id->locked = 0; + id->delOnClose = 0; + OpenCounter(+1); + return SQLITE_OK; +#endif +} + +/* +** Create a temporary file name in zBuf. zBuf must be big enough to +** hold at least SQLITE_TEMPNAME_SIZE characters. +*/ +int sqliteOsTempFileName(char *zBuf){ +#if OS_UNIX + static const char *azDirs[] = { + "/var/tmp", + "/usr/tmp", + "/tmp", + ".", + }; + static char zChars[] = + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789"; + int i, j; + struct stat buf; + const char *zDir = "."; + for(i=0; i0 && zTempPath[i-1]=='\\'; i--){} + zTempPath[i] = 0; + for(;;){ + sprintf(zBuf, "%s\\"TEMP_FILE_PREFIX, zTempPath); + j = strlen(zBuf); + for(i=0; i<15; i++){ + int n = sqliteRandomByte() % (sizeof(zChars) - 1); + zBuf[j++] = zChars[n]; + } + zBuf[j] = 0; + if( !sqliteOsFileExists(zBuf) ) break; + } +#endif +#if OS_MAC + static char zChars[] = + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789"; + int i, j; + char zTempPath[SQLITE_TEMPNAME_SIZE]; + char zdirName[32]; + CInfoPBRec infoRec; + Str31 dirName; + memset(&infoRec, 0, sizeof(infoRec)); + memset(zTempPath, 0, SQLITE_TEMPNAME_SIZE); + if( FindFolder(kOnSystemDisk, kTemporaryFolderType, kCreateFolder, + &(infoRec.dirInfo.ioVRefNum), &(infoRec.dirInfo.ioDrParID)) == noErr ){ + infoRec.dirInfo.ioNamePtr = dirName; + do{ + infoRec.dirInfo.ioFDirIndex = -1; + infoRec.dirInfo.ioDrDirID = infoRec.dirInfo.ioDrParID; + if( PBGetCatInfoSync(&infoRec) == noErr ){ + CopyPascalStringToC(dirName, zdirName); + i = strlen(zdirName); + memmove(&(zTempPath[i+1]), zTempPath, strlen(zTempPath)); + strcpy(zTempPath, zdirName); + zTempPath[i] = ':'; + }else{ + *zTempPath = 0; + break; + } + } while( infoRec.dirInfo.ioDrDirID != fsRtDirID ); + } + if( *zTempPath == 0 ) + getcwd(zTempPath, SQLITE_TEMPNAME_SIZE-24); + for(;;){ + sprintf(zBuf, "%s"TEMP_FILE_PREFIX, zTempPath); + j = strlen(zBuf); + for(i=0; i<15; i++){ + int n = sqliteRandomByte() % sizeof(zChars); + zBuf[j++] = zChars[n]; + } + zBuf[j] = 0; + if( !sqliteOsFileExists(zBuf) ) break; + } +#endif + return SQLITE_OK; +} + +/* +** Close a file +*/ +int sqliteOsClose(OsFile *id){ +#if OS_UNIX + close(id->fd); + sqliteOsEnterMutex(); + releaseLockInfo(id->pLock); + sqliteOsLeaveMutex(); + TRACE2("CLOSE %-3d\n", id->fd); + OpenCounter(-1); + return SQLITE_OK; +#endif +#if OS_WIN + CloseHandle(id->h); + OpenCounter(-1); + return SQLITE_OK; +#endif +#if OS_MAC + if( id->refNumRF!=-1 ) + FSClose(id->refNumRF); +# ifdef _LARGE_FILE + FSCloseFork(id->refNum); +# else + FSClose(id->refNum); +# endif + if( id->delOnClose ){ + unlink(id->pathToDel); + sqliteFree(id->pathToDel); + } + OpenCounter(-1); + return SQLITE_OK; +#endif +} + +/* +** 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 sqliteOsRead(OsFile *id, void *pBuf, int amt){ +#if OS_UNIX + int got; + SimulateIOError(SQLITE_IOERR); + TIMER_START; + got = read(id->fd, pBuf, amt); + TIMER_END; + TRACE4("READ %-3d %7d %d\n", id->fd, last_page, elapse); + SEEK(0); + /* if( got<0 ) got = 0; */ + if( got==amt ){ + return SQLITE_OK; + }else{ + return SQLITE_IOERR; + } +#endif +#if OS_WIN + DWORD got; + SimulateIOError(SQLITE_IOERR); + TRACE2("READ %d\n", last_page); + if( !ReadFile(id->h, pBuf, amt, &got, 0) ){ + got = 0; + } + if( got==(DWORD)amt ){ + return SQLITE_OK; + }else{ + return SQLITE_IOERR; + } +#endif +#if OS_MAC + int got; + SimulateIOError(SQLITE_IOERR); + TRACE2("READ %d\n", last_page); +# ifdef _LARGE_FILE + FSReadFork(id->refNum, fsAtMark, 0, (ByteCount)amt, pBuf, (ByteCount*)&got); +# else + got = amt; + FSRead(id->refNum, &got, pBuf); +# endif + if( got==amt ){ + return SQLITE_OK; + }else{ + return SQLITE_IOERR; + } +#endif +} + +/* +** Write data from a buffer into a file. Return SQLITE_OK on success +** or some other error code on failure. +*/ +int sqliteOsWrite(OsFile *id, const void *pBuf, int amt){ +#if OS_UNIX + int wrote = 0; + SimulateIOError(SQLITE_IOERR); + TIMER_START; + while( amt>0 && (wrote = write(id->fd, pBuf, amt))>0 ){ + amt -= wrote; + pBuf = &((char*)pBuf)[wrote]; + } + TIMER_END; + TRACE4("WRITE %-3d %7d %d\n", id->fd, last_page, elapse); + SEEK(0); + if( amt>0 ){ + return SQLITE_FULL; + } + return SQLITE_OK; +#endif +#if OS_WIN + int rc; + DWORD wrote; + SimulateIOError(SQLITE_IOERR); + TRACE2("WRITE %d\n", last_page); + while( amt>0 && (rc = WriteFile(id->h, pBuf, amt, &wrote, 0))!=0 && wrote>0 ){ + amt -= wrote; + pBuf = &((char*)pBuf)[wrote]; + } + if( !rc || amt>(int)wrote ){ + return SQLITE_FULL; + } + return SQLITE_OK; +#endif +#if OS_MAC + OSErr oserr; + int wrote = 0; + SimulateIOError(SQLITE_IOERR); + TRACE2("WRITE %d\n", last_page); + while( amt>0 ){ +# ifdef _LARGE_FILE + oserr = FSWriteFork(id->refNum, fsAtMark, 0, + (ByteCount)amt, pBuf, (ByteCount*)&wrote); +# else + wrote = amt; + oserr = FSWrite(id->refNum, &wrote, pBuf); +# endif + if( wrote == 0 || oserr != noErr) + break; + amt -= wrote; + pBuf = &((char*)pBuf)[wrote]; + } + if( oserr != noErr || amt>wrote ){ + return SQLITE_FULL; + } + return SQLITE_OK; +#endif +} + +/* +** Move the read/write pointer in a file. +*/ +int sqliteOsSeek(OsFile *id, off_t offset){ + SEEK(offset/1024 + 1); +#if OS_UNIX + lseek(id->fd, offset, SEEK_SET); + return SQLITE_OK; +#endif +#if OS_WIN + { + LONG upperBits = offset>>32; + LONG lowerBits = offset & 0xffffffff; + DWORD rc; + rc = SetFilePointer(id->h, lowerBits, &upperBits, FILE_BEGIN); + /* TRACE3("SEEK rc=0x%x upper=0x%x\n", rc, upperBits); */ + } + return SQLITE_OK; +#endif +#if OS_MAC + { + off_t curSize; + if( sqliteOsFileSize(id, &curSize) != SQLITE_OK ){ + return SQLITE_IOERR; + } + if( offset >= curSize ){ + if( sqliteOsTruncate(id, offset+1) != SQLITE_OK ){ + return SQLITE_IOERR; + } + } +# ifdef _LARGE_FILE + if( FSSetForkPosition(id->refNum, fsFromStart, offset) != noErr ){ +# else + if( SetFPos(id->refNum, fsFromStart, offset) != noErr ){ +# endif + return SQLITE_IOERR; + }else{ + return SQLITE_OK; + } + } +#endif +} + +/* +** Make sure all writes to a particular file are committed to disk. +*/ +int sqliteOsSync(OsFile *id){ +#if OS_UNIX + SimulateIOError(SQLITE_IOERR); + TRACE2("SYNC %-3d\n", id->fd); + if( fsync(id->fd) ){ + return SQLITE_IOERR; + }else{ + return SQLITE_OK; + } +#endif +#if OS_WIN + if( FlushFileBuffers(id->h) ){ + return SQLITE_OK; + }else{ + return SQLITE_IOERR; + } +#endif +#if OS_MAC +# ifdef _LARGE_FILE + if( FSFlushFork(id->refNum) != noErr ){ +# else + ParamBlockRec params; + memset(¶ms, 0, sizeof(ParamBlockRec)); + params.ioParam.ioRefNum = id->refNum; + if( PBFlushFileSync(¶ms) != noErr ){ +# endif + return SQLITE_IOERR; + }else{ + return SQLITE_OK; + } +#endif +} + +/* +** Truncate an open file to a specified size +*/ +int sqliteOsTruncate(OsFile *id, off_t nByte){ + SimulateIOError(SQLITE_IOERR); +#if OS_UNIX + return ftruncate(id->fd, nByte)==0 ? SQLITE_OK : SQLITE_IOERR; +#endif +#if OS_WIN + { + LONG upperBits = nByte>>32; + SetFilePointer(id->h, nByte, &upperBits, FILE_BEGIN); + SetEndOfFile(id->h); + } + return SQLITE_OK; +#endif +#if OS_MAC +# ifdef _LARGE_FILE + if( FSSetForkSize(id->refNum, fsFromStart, nByte) != noErr){ +# else + if( SetEOF(id->refNum, nByte) != noErr ){ +# endif + return SQLITE_IOERR; + }else{ + return SQLITE_OK; + } +#endif +} + +/* +** Determine the current size of a file in bytes +*/ +int sqliteOsFileSize(OsFile *id, off_t *pSize){ +#if OS_UNIX + struct stat buf; + SimulateIOError(SQLITE_IOERR); + if( fstat(id->fd, &buf)!=0 ){ + return SQLITE_IOERR; + } + *pSize = buf.st_size; + return SQLITE_OK; +#endif +#if OS_WIN + DWORD upperBits, lowerBits; + SimulateIOError(SQLITE_IOERR); + lowerBits = GetFileSize(id->h, &upperBits); + *pSize = (((off_t)upperBits)<<32) + lowerBits; + return SQLITE_OK; +#endif +#if OS_MAC +# ifdef _LARGE_FILE + if( FSGetForkSize(id->refNum, pSize) != noErr){ +# else + if( GetEOF(id->refNum, pSize) != noErr ){ +# endif + return SQLITE_IOERR; + }else{ + return SQLITE_OK; + } +#endif +} + +#if OS_WIN +/* +** Return true (non-zero) if we are running under WinNT, Win2K or WinXP. +** 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 +** API as long as we don't call it win running Win95/98/ME. A call to +** this routine is used to determine if the host is Win95/98/ME or +** WinNT/2K/XP so that we will know whether or not we can safely call +** the LockFileEx() API. +*/ +int isNT(void){ + static osType = 0; /* 0=unknown 1=win95 2=winNT */ + if( osType==0 ){ + OSVERSIONINFO sInfo; + sInfo.dwOSVersionInfoSize = sizeof(sInfo); + GetVersionEx(&sInfo); + osType = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1; + } + return osType==2; +} +#endif + +/* +** Windows file locking notes: [similar issues apply to MacOS] +** +** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because +** those functions are not available. So we use only LockFile() and +** UnlockFile(). +** +** LockFile() prevents not just writing but also reading by other processes. +** (This is a design error on the part of Windows, but there is nothing +** we can do about that.) So the region used for locking is at the +** end of the file where it is unlikely to ever interfere with an +** actual read attempt. +** +** A database read lock is obtained by locking a single randomly-chosen +** byte out of a specific range of bytes. The lock byte is obtained at +** random so two separate readers can probably access the file at the +** same time, unless they are unlucky and choose the same lock byte. +** A database write lock is obtained by locking all bytes in the range. +** There can only be one writer. +** +** A lock is obtained on the first byte of the lock range before acquiring +** either a read lock or a write lock. This prevents two processes from +** attempting to get a lock at a same time. The semantics of +** sqliteOsReadLock() require that if there is already a write lock, that +** lock is converted into a read lock atomically. The lock on the first +** byte allows us to drop the old write lock and get the read lock without +** another process jumping into the middle and messing us up. The same +** argument applies to sqliteOsWriteLock(). +** +** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available, +** which means we can use reader/writer locks. When reader writer locks +** are used, the lock is placed on the same range of bytes that is used +** for probabilistic locking in Win95/98/ME. Hence, the locking scheme +** will support two or more Win95 readers or two or more WinNT readers. +** But a single Win95 reader will lock out all WinNT readers and a single +** WinNT reader will lock out all other Win95 readers. +** +** Note: On MacOS we use the resource fork for locking. +** +** The following #defines specify the range of bytes used for locking. +** N_LOCKBYTE is the number of bytes available for doing the locking. +** The first byte used to hold the lock while the lock is changing does +** not count toward this number. FIRST_LOCKBYTE is the address of +** the first byte in the range of bytes used for locking. +*/ +#define N_LOCKBYTE 10239 +#if OS_MAC +# define FIRST_LOCKBYTE (0x000fffff - N_LOCKBYTE) +#else +# define FIRST_LOCKBYTE (0xffffffff - N_LOCKBYTE) +#endif + +/* +** Change the status of the lock on the file "id" to be a readlock. +** If the file was write locked, then this reduces the lock to a read. +** If the file was read locked, then this acquires a new read lock. +** +** Return SQLITE_OK on success and SQLITE_BUSY on failure. If this +** library was compiled with large file support (LFS) but LFS is not +** available on the host, then an SQLITE_NOLFS is returned. +*/ +int sqliteOsReadLock(OsFile *id){ +#if OS_UNIX + int rc; + sqliteOsEnterMutex(); + if( id->pLock->cnt>0 ){ + if( !id->locked ){ + id->pLock->cnt++; + id->locked = 1; + } + rc = SQLITE_OK; + }else if( id->locked || id->pLock->cnt==0 ){ + struct flock lock; + int s; + lock.l_type = F_RDLCK; + lock.l_whence = SEEK_SET; + lock.l_start = lock.l_len = 0L; + s = fcntl(id->fd, F_SETLK, &lock); + if( s!=0 ){ + rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY; + }else{ + rc = SQLITE_OK; + id->pLock->cnt = 1; + id->locked = 1; + } + }else{ + rc = SQLITE_BUSY; + } + sqliteOsLeaveMutex(); + return rc; +#endif +#if OS_WIN + int rc; + if( id->locked>0 ){ + rc = SQLITE_OK; + }else{ + int lk = (sqliteRandomInteger() & 0x7ffffff)%N_LOCKBYTE+1; + int res; + int cnt = 100; + while( cnt-->0 && (res = LockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0))==0 ){ + Sleep(1); + } + if( res ){ + UnlockFile(id->h, FIRST_LOCKBYTE+1, 0, N_LOCKBYTE, 0); + if( isNT() ){ + OVERLAPPED ovlp; + ovlp.Offset = FIRST_LOCKBYTE+1; + ovlp.OffsetHigh = 0; + ovlp.hEvent = 0; + res = LockFileEx(id->h, LOCKFILE_FAIL_IMMEDIATELY, + 0, N_LOCKBYTE, 0, &ovlp); + }else{ + res = LockFile(id->h, FIRST_LOCKBYTE+lk, 0, 1, 0); + } + UnlockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0); + } + if( res ){ + id->locked = lk; + rc = SQLITE_OK; + }else{ + rc = SQLITE_BUSY; + } + } + return rc; +#endif +#if OS_MAC + int rc; + if( id->locked>0 || id->refNumRF == -1 ){ + rc = SQLITE_OK; + }else{ + int lk = (sqliteRandomInteger() & 0x7ffffff)%N_LOCKBYTE+1; + OSErr res; + int cnt = 5; + ParamBlockRec params; + memset(¶ms, 0, sizeof(params)); + params.ioParam.ioRefNum = id->refNumRF; + params.ioParam.ioPosMode = fsFromStart; + params.ioParam.ioPosOffset = FIRST_LOCKBYTE; + params.ioParam.ioReqCount = 1; + while( cnt-->0 && (res = PBLockRangeSync(¶ms))!=noErr ){ + UInt32 finalTicks; + Delay(1, &finalTicks); /* 1/60 sec */ + } + if( res == noErr ){ + params.ioParam.ioPosOffset = FIRST_LOCKBYTE+1; + params.ioParam.ioReqCount = N_LOCKBYTE; + PBUnlockRangeSync(¶ms); + params.ioParam.ioPosOffset = FIRST_LOCKBYTE+lk; + params.ioParam.ioReqCount = 1; + res = PBLockRangeSync(¶ms); + params.ioParam.ioPosOffset = FIRST_LOCKBYTE; + params.ioParam.ioReqCount = 1; + PBUnlockRangeSync(¶ms); + } + if( res == noErr ){ + id->locked = lk; + rc = SQLITE_OK; + }else{ + rc = SQLITE_BUSY; + } + } + return rc; +#endif +} + +/* +** Change the lock status to be an exclusive or write lock. Return +** SQLITE_OK on success and SQLITE_BUSY on a failure. If this +** library was compiled with large file support (LFS) but LFS is not +** available on the host, then an SQLITE_NOLFS is returned. +*/ +int sqliteOsWriteLock(OsFile *id){ +#if OS_UNIX + int rc; + sqliteOsEnterMutex(); + if( id->pLock->cnt==0 || (id->pLock->cnt==1 && id->locked==1) ){ + struct flock lock; + int s; + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = lock.l_len = 0L; + s = fcntl(id->fd, F_SETLK, &lock); + if( s!=0 ){ + rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY; + }else{ + rc = SQLITE_OK; + id->pLock->cnt = -1; + id->locked = 1; + } + }else{ + rc = SQLITE_BUSY; + } + sqliteOsLeaveMutex(); + return rc; +#endif +#if OS_WIN + int rc; + if( id->locked<0 ){ + rc = SQLITE_OK; + }else{ + int res; + int cnt = 100; + while( cnt-->0 && (res = LockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0))==0 ){ + Sleep(1); + } + if( res ){ + if( id->locked>0 ){ + if( isNT() ){ + UnlockFile(id->h, FIRST_LOCKBYTE+1, 0, N_LOCKBYTE, 0); + }else{ + res = UnlockFile(id->h, FIRST_LOCKBYTE + id->locked, 0, 1, 0); + } + } + if( res ){ + res = LockFile(id->h, FIRST_LOCKBYTE+1, 0, N_LOCKBYTE, 0); + }else{ + res = 0; + } + UnlockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0); + } + if( res ){ + id->locked = -1; + rc = SQLITE_OK; + }else{ + rc = SQLITE_BUSY; + } + } + return rc; +#endif +#if OS_MAC + int rc; + if( id->locked<0 || id->refNumRF == -1 ){ + rc = SQLITE_OK; + }else{ + OSErr res; + int cnt = 5; + ParamBlockRec params; + memset(¶ms, 0, sizeof(params)); + params.ioParam.ioRefNum = id->refNumRF; + params.ioParam.ioPosMode = fsFromStart; + params.ioParam.ioPosOffset = FIRST_LOCKBYTE; + params.ioParam.ioReqCount = 1; + while( cnt-->0 && (res = PBLockRangeSync(¶ms))!=noErr ){ + UInt32 finalTicks; + Delay(1, &finalTicks); /* 1/60 sec */ + } + if( res == noErr ){ + params.ioParam.ioPosOffset = FIRST_LOCKBYTE + id->locked; + params.ioParam.ioReqCount = 1; + if( id->locked==0 + || PBUnlockRangeSync(¶ms)==noErr ){ + params.ioParam.ioPosOffset = FIRST_LOCKBYTE+1; + params.ioParam.ioReqCount = N_LOCKBYTE; + res = PBLockRangeSync(¶ms); + }else{ + res = afpRangeNotLocked; + } + params.ioParam.ioPosOffset = FIRST_LOCKBYTE; + params.ioParam.ioReqCount = 1; + PBUnlockRangeSync(¶ms); + } + if( res == noErr ){ + id->locked = -1; + rc = SQLITE_OK; + }else{ + rc = SQLITE_BUSY; + } + } + return rc; +#endif +} + +/* +** Unlock the given file descriptor. If the file descriptor was +** not previously locked, then this routine is a no-op. If this +** library was compiled with large file support (LFS) but LFS is not +** available on the host, then an SQLITE_NOLFS is returned. +*/ +int sqliteOsUnlock(OsFile *id){ +#if OS_UNIX + int rc; + if( !id->locked ) return SQLITE_OK; + sqliteOsEnterMutex(); + assert( id->pLock->cnt!=0 ); + if( id->pLock->cnt>1 ){ + id->pLock->cnt--; + rc = SQLITE_OK; + }else{ + struct flock lock; + int s; + lock.l_type = F_UNLCK; + lock.l_whence = SEEK_SET; + lock.l_start = lock.l_len = 0L; + s = fcntl(id->fd, F_SETLK, &lock); + if( s!=0 ){ + rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY; + }else{ + rc = SQLITE_OK; + id->pLock->cnt = 0; + } + } + sqliteOsLeaveMutex(); + id->locked = 0; + return rc; +#endif +#if OS_WIN + int rc; + if( id->locked==0 ){ + rc = SQLITE_OK; + }else if( isNT() || id->locked<0 ){ + UnlockFile(id->h, FIRST_LOCKBYTE+1, 0, N_LOCKBYTE, 0); + rc = SQLITE_OK; + id->locked = 0; + }else{ + UnlockFile(id->h, FIRST_LOCKBYTE+id->locked, 0, 1, 0); + rc = SQLITE_OK; + id->locked = 0; + } + return rc; +#endif +#if OS_MAC + int rc; + ParamBlockRec params; + memset(¶ms, 0, sizeof(params)); + params.ioParam.ioRefNum = id->refNumRF; + params.ioParam.ioPosMode = fsFromStart; + if( id->locked==0 || id->refNumRF == -1 ){ + rc = SQLITE_OK; + }else if( id->locked<0 ){ + params.ioParam.ioPosOffset = FIRST_LOCKBYTE+1; + params.ioParam.ioReqCount = N_LOCKBYTE; + PBUnlockRangeSync(¶ms); + rc = SQLITE_OK; + id->locked = 0; + }else{ + params.ioParam.ioPosOffset = FIRST_LOCKBYTE+id->locked; + params.ioParam.ioReqCount = 1; + PBUnlockRangeSync(¶ms); + rc = SQLITE_OK; + id->locked = 0; + } + return rc; +#endif +} + +/* +** Get information to seed the random number generator. The seed +** is written into the buffer zBuf[256]. The calling function must +** supply a sufficiently large buffer. +*/ +int sqliteOsRandomSeed(char *zBuf){ +#ifdef SQLITE_TEST + /* When testing, always use the same random number sequence. + ** This makes the tests repeatable. + */ + memset(zBuf, 0, 256); +#endif +#if OS_UNIX && !defined(SQLITE_TEST) + int pid; + time((time_t*)zBuf); + pid = getpid(); + memcpy(&zBuf[sizeof(time_t)], &pid, sizeof(pid)); +#endif +#if OS_WIN && !defined(SQLITE_TEST) + GetSystemTime((LPSYSTEMTIME)zBuf); +#endif +#if OS_MAC + int pid; + Microseconds((UnsignedWide*)zBuf); + pid = getpid(); + memcpy(&zBuf[sizeof(UnsignedWide)], &pid, sizeof(pid)); +#endif + return SQLITE_OK; +} + +/* +** Sleep for a little while. Return the amount of time slept. +*/ +int sqliteOsSleep(int ms){ +#if OS_UNIX +#if defined(HAVE_USLEEP) && HAVE_USLEEP + usleep(ms*1000); + return ms; +#else + sleep((ms+999)/1000); + return 1000*((ms+999)/1000); +#endif +#endif +#if OS_WIN + Sleep(ms); + return ms; +#endif +#if OS_MAC + UInt32 finalTicks; + UInt32 ticks = (((UInt32)ms+16)*3)/50; /* 1/60 sec per tick */ + Delay(ticks, &finalTicks); + return (int)((ticks*50)/3); +#endif +} + +/* +** Macros used to determine whether or not to use threads. The +** SQLITE_UNIX_THREADS macro is defined if we are synchronizing for +** Posix threads and SQLITE_W32_THREADS is defined if we are +** synchronizing using Win32 threads. +*/ +#if OS_UNIX && defined(THREADSAFE) && THREADSAFE +# include +# define SQLITE_UNIX_THREADS 1 +#endif +#if OS_WIN && defined(THREADSAFE) && THREADSAFE +# define SQLITE_W32_THREADS 1 +#endif +#if OS_MAC && defined(THREADSAFE) && THREADSAFE +# include +# define SQLITE_MACOS_MULTITASKING 1 +#endif + +/* +** Static variables used for thread synchronization +*/ +static int inMutex = 0; +#ifdef SQLITE_UNIX_THREADS + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +#endif +#ifdef SQLITE_W32_THREADS + static CRITICAL_SECTION cs; +#endif +#ifdef SQLITE_MACOS_MULTITASKING + static MPCriticalRegionID criticalRegion; +#endif + +/* +** The following pair of routine 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. +*/ +void sqliteOsEnterMutex(){ +#ifdef SQLITE_UNIX_THREADS + pthread_mutex_lock(&mutex); +#endif +#ifdef SQLITE_W32_THREADS + static int isInit = 0; + while( !isInit ){ + static long lock = 0; + if( InterlockedIncrement(&lock)==1 ){ + InitializeCriticalSection(&cs); + isInit = 1; + }else{ + Sleep(1); + } + } + EnterCriticalSection(&cs); +#endif +#ifdef SQLITE_MACOS_MULTITASKING + static volatile int notInit = 1; + if( notInit ){ + if( notInit == 2 ) /* as close as you can get to thread safe init */ + MPYield(); + else{ + notInit = 2; + MPCreateCriticalRegion(&criticalRegion); + notInit = 0; + } + } + MPEnterCriticalRegion(criticalRegion, kDurationForever); +#endif + assert( !inMutex ); + inMutex = 1; +} +void sqliteOsLeaveMutex(){ + assert( inMutex ); + inMutex = 0; +#ifdef SQLITE_UNIX_THREADS + pthread_mutex_unlock(&mutex); +#endif +#ifdef SQLITE_W32_THREADS + LeaveCriticalSection(&cs); +#endif +#ifdef SQLITE_MACOS_MULTITASKING + MPExitCriticalRegion(criticalRegion); +#endif +} + +/* +** Turn a relative pathname into a full pathname. Return a pointer +** to the full pathname stored in space obtained from sqliteMalloc(). +** The calling function is responsible for freeing this space once it +** is no longer needed. +*/ +char *sqliteOsFullPathname(const char *zRelative){ +#if OS_UNIX + char *zFull = 0; + if( zRelative[0]=='/' ){ + sqliteSetString(&zFull, zRelative, 0); + }else{ + char zBuf[5000]; + sqliteSetString(&zFull, getcwd(zBuf, sizeof(zBuf)), "/", zRelative, 0); + } + return zFull; +#endif +#if OS_WIN + char *zNotUsed; + char *zFull; + int nByte; + nByte = GetFullPathName(zRelative, 0, 0, &zNotUsed) + 1; + zFull = sqliteMalloc( nByte ); + if( zFull==0 ) return 0; + GetFullPathName(zRelative, nByte, zFull, &zNotUsed); + return zFull; +#endif +#if OS_MAC + char *zFull = 0; + if( zRelative[0]==':' ){ + char zBuf[_MAX_PATH+1]; + sqliteSetString(&zFull, getcwd(zBuf, sizeof(zBuf)), &(zRelative[1]), 0); + }else{ + if( strchr(zRelative, ':') ){ + sqliteSetString(&zFull, zRelative, 0); + }else{ + char zBuf[_MAX_PATH+1]; + sqliteSetString(&zFull, getcwd(zBuf, sizeof(zBuf)), zRelative, 0); + } + } + return zFull; +#endif +} diff --git a/sqlitebrowser/sqlitebrowser/sqlite_source/os.h b/sqlitebrowser/sqlitebrowser/sqlite_source/os.h new file mode 100755 index 00000000..7cc2639f --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/sqlite_source/os.h @@ -0,0 +1,190 @@ +/* +** 2001 September 16 +** +** 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 header file (together with is companion C source-code file +** "os.c") attempt to abstract the underlying operating system so that +** the SQLite library will work on both POSIX and windows systems. +*/ +#ifndef _SQLITE_OS_H_ +#define _SQLITE_OS_H_ + +/* +** Make sure we can call this stuff from C++. +*/ +#ifdef __cplusplus +extern "C" { +#endif + +/* +** Helpful hint: To get this to compile on HP/UX, add -D_INCLUDE_POSIX_SOURCE +** to the compiler command line. +*/ + +/* +** These #defines should enable >2GB file support on Posix if the +** underlying operating system supports it. If the OS lacks +** large file support, or if the OS is windows, 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. +** +** Similar is true for MacOS. LFS is only supported on MacOS 9 and later. +*/ +#ifndef SQLITE_DISABLE_LFS +# define _LARGE_FILE 1 +# define _FILE_OFFSET_BITS 64 +# define _LARGEFILE_SOURCE 1 +#endif + +/* +** Temporary files are named starting with this prefix followed by 16 random +** alphanumeric characters, and no file extension. They are stored in the +** OS's standard temporary file directory, and are deleted prior to exit. +** If sqlite is being embedded in another program, you may wish to change the +** prefix to reflect your program's name, so that if your program exits +** prematurely, old temporary files can be easily identified. This can be done +** using -DTEMP_FILE_PREFIX=myprefix_ on the compiler command line. +*/ +#ifndef TEMP_FILE_PREFIX +# define TEMP_FILE_PREFIX "sqlite_" +#endif + +/* +** 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) +*/ +#ifndef OS_UNIX +# ifndef OS_WIN +# ifndef OS_MAC +# if defined(__MACOS__) +# define OS_MAC 1 +# define OS_WIN 0 +# define OS_UNIX 0 +# elif defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__) +# define OS_MAC 0 +# define OS_WIN 1 +# define OS_UNIX 0 +# else +# define OS_MAC 0 +# define OS_WIN 0 +# define OS_UNIX 1 +# endif +# else +# define OS_WIN 0 +# define OS_UNIX 0 +# endif +# else +# define OS_MAC 0 +# define OS_UNIX 0 +# endif +#else +# define OS_MAC 0 +# define OS_WIN 0 +#endif + +/* +** A handle for an open file is stored in an OsFile object. +*/ +#if OS_UNIX +# include +# include +# include +# include + typedef struct OsFile OsFile; + struct OsFile { + struct lockInfo *pLock; /* Information about locks on this inode */ + int fd; /* The file descriptor */ + int locked; /* True if this user holds the lock */ + }; +# define SQLITE_TEMPNAME_SIZE 200 +# if defined(HAVE_USLEEP) && HAVE_USLEEP +# define SQLITE_MIN_SLEEP_MS 1 +# else +# define SQLITE_MIN_SLEEP_MS 1000 +# endif +#endif + +#if OS_WIN +#include +#include + typedef struct OsFile OsFile; + struct OsFile { + HANDLE h; /* Handle for accessing the file */ + int locked; /* 0: unlocked, <0: write lock, >0: read lock */ + }; + +#ifndef _OFF_T_DEFINED +# if defined(_MSC_VER) || defined(__BORLANDC__) + typedef __int64 off_t; +# else + typedef long long off_t; +# endif +#endif +# define SQLITE_TEMPNAME_SIZE (MAX_PATH+50) +# define SQLITE_MIN_SLEEP_MS 1 +#endif + +#if OS_MAC +# include +# include + typedef struct OsFile OsFile; + struct OsFile { + SInt16 refNum; /* Data fork/file reference number */ + SInt16 refNumRF; /* Resource fork reference number (for locking) */ + int locked; /* 0: unlocked, <0: write lock, >0: read lock */ + int delOnClose; /* True if file is to be deleted on close */ + char *pathToDel; /* Name of file to delete on close */ + }; +# ifdef _LARGE_FILE + typedef SInt64 off_t; +# else + typedef SInt32 off_t; +# endif +# define SQLITE_TEMPNAME_SIZE _MAX_PATH +# define SQLITE_MIN_SLEEP_MS 17 +#endif + +int sqliteOsDelete(const char*); +int sqliteOsFileExists(const char*); +int sqliteOsFileRename(const char*, const char*); +int sqliteOsOpenReadWrite(const char*, OsFile*, int*); +int sqliteOsOpenExclusive(const char*, OsFile*, int); +int sqliteOsOpenReadOnly(const char*, OsFile*); +int sqliteOsTempFileName(char*); +int sqliteOsClose(OsFile*); +int sqliteOsRead(OsFile*, void*, int amt); +int sqliteOsWrite(OsFile*, const void*, int amt); +int sqliteOsSeek(OsFile*, off_t offset); +int sqliteOsSync(OsFile*); +int sqliteOsTruncate(OsFile*, off_t size); +int sqliteOsFileSize(OsFile*, off_t *pSize); +int sqliteOsReadLock(OsFile*); +int sqliteOsWriteLock(OsFile*); +int sqliteOsUnlock(OsFile*); +int sqliteOsRandomSeed(char*); +int sqliteOsSleep(int ms); +void sqliteOsEnterMutex(void); +void sqliteOsLeaveMutex(void); +char *sqliteOsFullPathname(const char*); + +#ifdef __cplusplus +} /* End of the 'extern "C"' block */ +#endif + +#endif /* _SQLITE_OS_H_ */ diff --git a/sqlitebrowser/sqlitebrowser/sqlite_source/pager.c b/sqlitebrowser/sqlitebrowser/sqlite_source/pager.c new file mode 100755 index 00000000..5258fbe4 --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/sqlite_source/pager.c @@ -0,0 +1,2086 @@ +/* +** 2001 September 15 +** +** 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 is the implementation of the page cache subsystem or "pager". +** +** The pager is used to access a database disk file. It implements +** atomic commit and rollback through the use of a journal file that +** is separate from the database file. The pager also implements file +** locking to prevent two processes from writing the same database +** file simultaneously, or one process from reading the database while +** another is writing. +** +** @(#) $Id: pager.c,v 1.1.1.1 2003-08-21 02:24:12 tabuleiro Exp $ +*/ +#include "os.h" /* Must be first to enable large file support */ +#include "sqliteInt.h" +#include "pager.h" +#include +#include + +/* +** Macros for troubleshooting. Normally turned off +*/ +#if 0 +static Pager *mainPager = 0; +#define SET_PAGER(X) if( mainPager==0 ) mainPager = (X) +#define CLR_PAGER(X) if( mainPager==(X) ) mainPager = 0 +#define TRACE1(X) if( pPager==mainPager ) fprintf(stderr,X) +#define TRACE2(X,Y) if( pPager==mainPager ) fprintf(stderr,X,Y) +#define TRACE3(X,Y,Z) if( pPager==mainPager ) fprintf(stderr,X,Y,Z) +#else +#define SET_PAGER(X) +#define CLR_PAGER(X) +#define TRACE1(X) +#define TRACE2(X,Y) +#define TRACE3(X,Y,Z) +#endif + + +/* +** The page cache as a whole is always in one of the following +** states: +** +** SQLITE_UNLOCK The page cache is not currently reading or +** writing the database file. There is no +** data held in memory. This is the initial +** state. +** +** SQLITE_READLOCK The page cache is reading the database. +** Writing is not permitted. There can be +** multiple readers accessing the same database +** file at the same time. +** +** SQLITE_WRITELOCK The page cache is writing the database. +** Access is exclusive. No other processes or +** threads can be reading or writing while one +** process is writing. +** +** The page cache comes up in SQLITE_UNLOCK. The first time a +** sqlite_page_get() occurs, the state transitions to SQLITE_READLOCK. +** After all pages have been released using sqlite_page_unref(), +** the state transitions back to SQLITE_UNLOCK. The first time +** that sqlite_page_write() is called, the state transitions to +** SQLITE_WRITELOCK. (Note that sqlite_page_write() can only be +** called on an outstanding page which means that the pager must +** be in SQLITE_READLOCK before it transitions to SQLITE_WRITELOCK.) +** The sqlite_page_rollback() and sqlite_page_commit() functions +** transition the state from SQLITE_WRITELOCK back to SQLITE_READLOCK. +*/ +#define SQLITE_UNLOCK 0 +#define SQLITE_READLOCK 1 +#define SQLITE_WRITELOCK 2 + + +/* +** Each in-memory image of a page begins with the following header. +** This header is only visible to this pager module. The client +** code that calls pager sees only the data that follows the header. +*/ +typedef struct PgHdr PgHdr; +struct PgHdr { + Pager *pPager; /* The pager to which this page belongs */ + Pgno pgno; /* The page number for this page */ + PgHdr *pNextHash, *pPrevHash; /* Hash collision chain for PgHdr.pgno */ + int nRef; /* Number of users of this page */ + PgHdr *pNextFree, *pPrevFree; /* Freelist of pages where nRef==0 */ + PgHdr *pNextAll, *pPrevAll; /* A list of all pages */ + PgHdr *pNextCkpt, *pPrevCkpt; /* List of pages in the checkpoint journal */ + u8 inJournal; /* TRUE if has been written to journal */ + u8 inCkpt; /* TRUE if written to the checkpoint journal */ + u8 dirty; /* TRUE if we need to write back changes */ + u8 needSync; /* Sync journal before writing this page */ + u8 alwaysRollback; /* Disable dont_rollback() for this page */ + PgHdr *pDirty; /* Dirty pages sorted by PgHdr.pgno */ + /* SQLITE_PAGE_SIZE bytes of page data follow this header */ + /* Pager.nExtra bytes of local data follow the page data */ +}; + +/* +** Convert a pointer to a PgHdr into a pointer to its data +** and back again. +*/ +#define PGHDR_TO_DATA(P) ((void*)(&(P)[1])) +#define DATA_TO_PGHDR(D) (&((PgHdr*)(D))[-1]) +#define PGHDR_TO_EXTRA(P) ((void*)&((char*)(&(P)[1]))[SQLITE_PAGE_SIZE]) + +/* +** How big to make the hash table used for locating in-memory pages +** by page number. +*/ +#define N_PG_HASH 2048 + +/* +** Hash a page number +*/ +#define pager_hash(PN) ((PN)&(N_PG_HASH-1)) + +/* +** A open page cache is an instance of the following structure. +*/ +struct Pager { + char *zFilename; /* Name of the database file */ + char *zJournal; /* Name of the journal file */ + OsFile fd, jfd; /* File descriptors for database and journal */ + OsFile cpfd; /* File descriptor for the checkpoint journal */ + int dbSize; /* Number of pages in the file */ + int origDbSize; /* dbSize before the current change */ + int ckptSize; /* Size of database (in pages) at ckpt_begin() */ + off_t ckptJSize; /* Size of journal at ckpt_begin() */ + int nRec; /* Number of pages written to the journal */ + u32 cksumInit; /* Quasi-random value added to every checksum */ + int ckptNRec; /* Number of records in the checkpoint journal */ + int nExtra; /* Add this many bytes to each in-memory page */ + void (*xDestructor)(void*); /* Call this routine when freeing pages */ + int nPage; /* Total number of in-memory pages */ + int nRef; /* Number of in-memory pages with PgHdr.nRef>0 */ + int mxPage; /* Maximum number of pages to hold in cache */ + int nHit, nMiss, nOvfl; /* Cache hits, missing, and LRU overflows */ + u8 journalOpen; /* True if journal file descriptors is valid */ + u8 journalStarted; /* True if initial magic of journal is synced */ + u8 useJournal; /* Do not use a rollback journal on this file */ + u8 ckptOpen; /* True if the checkpoint journal is open */ + u8 ckptInUse; /* True we are in a checkpoint */ + u8 ckptAutoopen; /* Open ckpt 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 state; /* SQLITE_UNLOCK, _READLOCK or _WRITELOCK */ + u8 errMask; /* 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 */ + u8 dirtyFile; /* True if database file has changed in any way */ + u8 alwaysRollback; /* Disable dont_rollback() for all pages */ + u8 *aInJournal; /* One bit for each page in the database file */ + u8 *aInCkpt; /* One bit for each page in the database */ + PgHdr *pFirst, *pLast; /* List of free pages */ + PgHdr *pFirstSynced; /* First free page with PgHdr.needSync==0 */ + PgHdr *pAll; /* List of all pages */ + PgHdr *pCkpt; /* List of pages in the checkpoint journal */ + PgHdr *aHash[N_PG_HASH]; /* Hash table to map page number of PgHdr */ +}; + +/* +** 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? */ + +/* +** The journal file contains page records in the following +** format. +** +** Actually, this structure is the complete page record for pager +** formats less than 3. Beginning with format 3, this record is surrounded +** by two checksums. +*/ +typedef struct PageRecord PageRecord; +struct PageRecord { + Pgno pgno; /* The page number */ + char aData[SQLITE_PAGE_SIZE]; /* Original data for page pgno */ +}; + +/* +** Journal files begin with the following magic string. The data +** was obtained from /dev/random. It is used only as a sanity check. +** +** There are three journal formats (so far). The 1st journal format writes +** 32-bit integers in the byte-order of the host machine. New +** formats writes integers as big-endian. All new journals use the +** new format, but we have to be able to read an older journal in order +** to rollback journals created by older versions of the library. +** +** The 3rd journal format (added for 2.8.0) adds additional sanity +** checking information to the journal. If the power fails while the +** journal is being written, semi-random garbage data might appear in +** the journal file after power is restored. If an attempt is then made +** to roll the journal back, the database could be corrupted. The additional +** sanity checking data is an attempt to discover the garbage in the +** journal and ignore it. +** +** The sanity checking information for the 3rd journal format consists +** of a 32-bit checksum on each page of data. The checksum covers both +** the page number and the SQLITE_PAGE_SIZE bytes of data for the page. +** This cksum is initialized to a 32-bit random value that appears in the +** journal file right after the header. The random initializer is important, +** because garbage data that appears at the end of a journal is likely +** data that was once in other files that have now been deleted. If the +** garbage data came from an obsolete journal file, the checksums might +** be correct. But by initializing the checksum to random value which +** is different for every journal, we minimize that risk. +*/ +static const unsigned char aJournalMagic1[] = { + 0xd9, 0xd5, 0x05, 0xf9, 0x20, 0xa1, 0x63, 0xd4, +}; +static const unsigned char aJournalMagic2[] = { + 0xd9, 0xd5, 0x05, 0xf9, 0x20, 0xa1, 0x63, 0xd5, +}; +static const unsigned char aJournalMagic3[] = { + 0xd9, 0xd5, 0x05, 0xf9, 0x20, 0xa1, 0x63, 0xd6, +}; +#define JOURNAL_FORMAT_1 1 +#define JOURNAL_FORMAT_2 2 +#define JOURNAL_FORMAT_3 3 + +/* +** The following integer determines what format to use when creating +** new primary journal files. By default we always use format 3. +** When testing, we can set this value to older journal formats in order to +** make sure that newer versions of the library are able to rollback older +** journal files. +** +** Note that checkpoint journals always use format 2 and omit the header. +*/ +#ifdef SQLITE_TEST +int journal_format = 3; +#else +# define journal_format 3 +#endif + +/* +** The size of the header and of each page in the journal varies according +** to which journal format is being used. The following macros figure out +** the sizes based on format numbers. +*/ +#define JOURNAL_HDR_SZ(X) \ + (sizeof(aJournalMagic1) + sizeof(Pgno) + ((X)>=3)*2*sizeof(u32)) +#define JOURNAL_PG_SZ(X) \ + (SQLITE_PAGE_SIZE + sizeof(Pgno) + ((X)>=3)*sizeof(u32)) + +/* +** Enable reference count tracking here: +*/ +#ifdef SQLITE_TEST + int pager_refinfo_enable = 0; + static void pager_refinfo(PgHdr *p){ + static int cnt = 0; + if( !pager_refinfo_enable ) return; + printf( + "REFCNT: %4d addr=0x%08x nRef=%d\n", + p->pgno, (int)PGHDR_TO_DATA(p), p->nRef + ); + cnt++; /* Something to set a breakpoint on */ + } +# define REFINFO(X) pager_refinfo(X) +#else +# define REFINFO(X) +#endif + +/* +** Read a 32-bit integer from the given file descriptor +*/ +static int read32bits(int format, OsFile *fd, u32 *pRes){ + u32 res; + int rc; + rc = sqliteOsRead(fd, &res, sizeof(res)); + if( rc==SQLITE_OK && format>JOURNAL_FORMAT_1 ){ + unsigned char ac[4]; + memcpy(ac, &res, 4); + res = (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. Writing +** is always done using the new journal format. +*/ +static int write32bits(OsFile *fd, u32 val){ + unsigned char ac[4]; + if( journal_format<=1 ){ + return sqliteOsWrite(fd, &val, 4); + } + ac[0] = (val>>24) & 0xff; + ac[1] = (val>>16) & 0xff; + ac[2] = (val>>8) & 0xff; + ac[3] = val & 0xff; + return sqliteOsWrite(fd, ac, 4); +} + +/* +** Write a 32-bit integer into a page header right before the +** page data. This will overwrite the PgHdr.pDirty pointer. +*/ +static void store32bits(u32 val, PgHdr *p, int offset){ + unsigned char *ac; + ac = (unsigned char *)&((char*)PGHDR_TO_DATA(p))[offset]; + if( journal_format<=1 ){ + memcpy(ac, &val, 4); + }else{ + ac[0] = (val>>24) & 0xff; + ac[1] = (val>>16) & 0xff; + ac[2] = (val>>8) & 0xff; + ac[3] = val & 0xff; + } +} + + +/* +** Convert the bits in the pPager->errMask into an approprate +** return 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; + return rc; +} + +/* +** Add or remove a page from the list of all pages that are in the +** checkpoint journal. +** +** The Pager keeps a separate list of pages that are currently in +** the checkpoint journal. This helps the sqlitepager_ckpt_commit() +** routine run MUCH faster for the common case where there are many +** pages in memory but only a few are in the checkpoint journal. +*/ +static void page_add_to_ckpt_list(PgHdr *pPg){ + Pager *pPager = pPg->pPager; + if( pPg->inCkpt ) return; + assert( pPg->pPrevCkpt==0 && pPg->pNextCkpt==0 ); + pPg->pPrevCkpt = 0; + if( pPager->pCkpt ){ + pPager->pCkpt->pPrevCkpt = pPg; + } + pPg->pNextCkpt = pPager->pCkpt; + pPager->pCkpt = pPg; + pPg->inCkpt = 1; +} +static void page_remove_from_ckpt_list(PgHdr *pPg){ + if( !pPg->inCkpt ) return; + if( pPg->pPrevCkpt ){ + assert( pPg->pPrevCkpt->pNextCkpt==pPg ); + pPg->pPrevCkpt->pNextCkpt = pPg->pNextCkpt; + }else{ + assert( pPg->pPager->pCkpt==pPg ); + pPg->pPager->pCkpt = pPg->pNextCkpt; + } + if( pPg->pNextCkpt ){ + assert( pPg->pNextCkpt->pPrevCkpt==pPg ); + pPg->pNextCkpt->pPrevCkpt = pPg->pPrevCkpt; + } + pPg->pNextCkpt = 0; + pPg->pPrevCkpt = 0; + pPg->inCkpt = 0; +} + +/* +** Find a page in the hash table given its page number. Return +** a pointer to the page or NULL if not found. +*/ +static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){ + PgHdr *p = pPager->aHash[pager_hash(pgno)]; + while( p && p->pgno!=pgno ){ + p = p->pNextHash; + } + return p; +} + +/* +** Unlock the database and clear the in-memory cache. This routine +** sets the state of the pager back to what it was when it was first +** opened. Any outstanding pages are invalidated and subsequent attempts +** to access those pages will likely result in a coredump. +*/ +static void pager_reset(Pager *pPager){ + PgHdr *pPg, *pNext; + for(pPg=pPager->pAll; pPg; pPg=pNext){ + pNext = pPg->pNextAll; + sqliteFree(pPg); + } + pPager->pFirst = 0; + pPager->pFirstSynced = 0; + pPager->pLast = 0; + pPager->pAll = 0; + memset(pPager->aHash, 0, sizeof(pPager->aHash)); + pPager->nPage = 0; + if( pPager->state>=SQLITE_WRITELOCK ){ + sqlitepager_rollback(pPager); + } + sqliteOsUnlock(&pPager->fd); + pPager->state = SQLITE_UNLOCK; + pPager->dbSize = -1; + pPager->nRef = 0; + assert( pPager->journalOpen==0 ); +} + +/* +** When this routine is called, the pager has the journal file open and +** a write lock on the database. This routine releases the database +** write lock and acquires a read lock in its place. The journal file +** is deleted and closed. +*/ +static int pager_unwritelock(Pager *pPager){ + int rc; + PgHdr *pPg; + if( pPager->stateckptOpen ){ + sqliteOsClose(&pPager->cpfd); + pPager->ckptOpen = 0; + } + if( pPager->journalOpen ){ + sqliteOsClose(&pPager->jfd); + pPager->journalOpen = 0; + sqliteOsDelete(pPager->zJournal); + sqliteFree( pPager->aInJournal ); + pPager->aInJournal = 0; + for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ + pPg->inJournal = 0; + pPg->dirty = 0; + pPg->needSync = 0; + } + }else{ + assert( pPager->dirtyFile==0 || pPager->useJournal==0 ); + } + rc = sqliteOsReadLock(&pPager->fd); + if( rc==SQLITE_OK ){ + pPager->state = SQLITE_READLOCK; + }else{ + /* This can only happen if a process does a BEGIN, then forks and the + ** child process does the COMMIT. Because of the semantics of unix + ** file locking, the unlock will fail. + */ + pPager->state = SQLITE_UNLOCK; + } + return rc; +} + +/* +** Compute and return a checksum for the page of data. +*/ +static u32 pager_cksum(Pager *pPager, Pgno pgno, const char *aData){ + u32 cksum = pPager->cksumInit + pgno; + return cksum; +} + +/* +** Read a single page from the journal file opened on file descriptor +** jfd. Playback this one page. +** +** There are three different journal formats. The format parameter determines +** which format is used by the journal that is played back. +*/ +static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int format){ + int rc; + PgHdr *pPg; /* An existing page in the cache */ + PageRecord pgRec; + u32 cksum; + + rc = read32bits(format, jfd, &pgRec.pgno); + if( rc!=SQLITE_OK ) return rc; + rc = sqliteOsRead(jfd, &pgRec.aData, sizeof(pgRec.aData)); + if( rc!=SQLITE_OK ) return rc; + + /* Sanity checking on the page. This is more important that I originally + ** thought. If a power failure occurs while the journal is being written, + ** it could cause invalid data to be written into the journal. We need to + ** detect this invalid data (with high probability) and ignore it. + */ + if( pgRec.pgno==0 ){ + return SQLITE_DONE; + } + if( pgRec.pgno>(unsigned)pPager->dbSize ){ + return SQLITE_OK; + } + if( format>=JOURNAL_FORMAT_3 ){ + rc = read32bits(format, jfd, &cksum); + if( rc ) return rc; + if( pager_cksum(pPager, pgRec.pgno, pgRec.aData)!=cksum ){ + return SQLITE_DONE; + } + } + + /* Playback the page. Update the in-memory copy of the page + ** at the same time, if there is one. + */ + pPg = pager_lookup(pPager, pgRec.pgno); + TRACE2("PLAYBACK %d\n", pgRec.pgno); + sqliteOsSeek(&pPager->fd, (pgRec.pgno-1)*(off_t)SQLITE_PAGE_SIZE); + rc = sqliteOsWrite(&pPager->fd, pgRec.aData, SQLITE_PAGE_SIZE); + if( pPg ){ + if( pPg->nRef==0 || + memcmp(PGHDR_TO_DATA(pPg), pgRec.aData, SQLITE_PAGE_SIZE)==0 + ){ + /* Do not update the data on this page if the page is in use + ** and the page has never been modified. This avoids resetting + ** the "extra" data. That in turn avoids invalidating BTree cursors + ** in trees that have never been modified. The end result is that + ** you can have a SELECT going on in one table and ROLLBACK changes + ** to a different table and the SELECT is unaffected by the ROLLBACK. + */ + memcpy(PGHDR_TO_DATA(pPg), pgRec.aData, SQLITE_PAGE_SIZE); + memset(PGHDR_TO_EXTRA(pPg), 0, pPager->nExtra); + } + pPg->dirty = 0; + pPg->needSync = 0; + } + return rc; +} + +/* +** Playback the journal and thus restore the database file to +** the state it was in before we started making changes. +** +** The journal file format is as follows: There is an initial +** file-type string for sanity checking. Then there is a single +** Pgno number which is the number of pages in the database before +** changes were made. The database is truncated to this size. +** Next come zero or more page records where each page record +** consists of a Pgno and SQLITE_PAGE_SIZE bytes of data. See +** the PageRecord structure for details. +** +** If the file opened as the journal file is not a well-formed +** journal file (as determined by looking at the magic number +** at the beginning) then this routine returns SQLITE_PROTOCOL. +** If any other errors occur during playback, the database will +** likely be corrupted, so the PAGER_ERR_CORRUPT bit is set in +** pPager->errMask and SQLITE_CORRUPT is returned. If it all +** works, then this routine returns SQLITE_OK. +*/ +static int pager_playback(Pager *pPager, int useJournalSize){ + off_t szJ; /* Size of the journal file in bytes */ + int nRec; /* Number of Records in the journal */ + int i; /* Loop counter */ + Pgno mxPg = 0; /* Size of the original file in pages */ + int format; /* Format of the journal file. */ + unsigned char aMagic[sizeof(aJournalMagic1)]; + int rc; + + /* Figure out how many records are in the journal. Abort early if + ** the journal is empty. + */ + assert( pPager->journalOpen ); + sqliteOsSeek(&pPager->jfd, 0); + rc = sqliteOsFileSize(&pPager->jfd, &szJ); + if( rc!=SQLITE_OK ){ + goto end_playback; + } + if( szJ < sizeof(aMagic)+sizeof(Pgno) ){ + goto end_playback; + } + + /* Read the beginning of the journal and truncate the + ** database file back to its original size. + */ + rc = sqliteOsRead(&pPager->jfd, aMagic, sizeof(aMagic)); + if( rc!=SQLITE_OK ){ + rc = SQLITE_PROTOCOL; + goto end_playback; + } + if( memcmp(aMagic, aJournalMagic3, sizeof(aMagic))==0 ){ + format = JOURNAL_FORMAT_3; + }else if( memcmp(aMagic, aJournalMagic2, sizeof(aMagic))==0 ){ + format = JOURNAL_FORMAT_2; + }else if( memcmp(aMagic, aJournalMagic1, sizeof(aMagic))==0 ){ + format = JOURNAL_FORMAT_1; + }else{ + rc = SQLITE_PROTOCOL; + goto end_playback; + } + if( format>=JOURNAL_FORMAT_3 ){ + rc = read32bits(format, &pPager->jfd, (unsigned int *)&nRec); + if( rc ) goto end_playback; + rc = read32bits(format, &pPager->jfd, &pPager->cksumInit); + if( rc ) goto end_playback; + if( nRec==0xffffffff || useJournalSize ){ + nRec = (szJ - JOURNAL_HDR_SZ(3))/JOURNAL_PG_SZ(3); + } + }else{ + nRec = (szJ - JOURNAL_HDR_SZ(2))/JOURNAL_PG_SZ(2); + assert( nRec*JOURNAL_PG_SZ(2)+JOURNAL_HDR_SZ(2)==szJ ); + } + rc = read32bits(format, &pPager->jfd, &mxPg); + if( rc!=SQLITE_OK ){ + goto end_playback; + } + assert( pPager->origDbSize==0 || pPager->origDbSize==mxPg ); + rc = sqliteOsTruncate(&pPager->fd, SQLITE_PAGE_SIZE*(off_t)mxPg); + if( rc!=SQLITE_OK ){ + goto end_playback; + } + pPager->dbSize = mxPg; + + /* Copy original pages out of the journal and back into the database file. + */ + for(i=0; ijfd, format); + if( rc!=SQLITE_OK ){ + if( rc==SQLITE_DONE ){ + rc = SQLITE_OK; + } + break; + } + } + + /* Pages that have been written to the journal but never synced + ** where not restored by the loop above. We have to restore those + ** pages by reading the back from the original database. + */ + if( rc==SQLITE_OK ){ + PgHdr *pPg; + for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ + char zBuf[SQLITE_PAGE_SIZE]; + if( !pPg->dirty ) continue; + if( (int)pPg->pgno <= pPager->origDbSize ){ + sqliteOsSeek(&pPager->fd, SQLITE_PAGE_SIZE*(off_t)(pPg->pgno-1)); + rc = sqliteOsRead(&pPager->fd, zBuf, SQLITE_PAGE_SIZE); + if( rc ) break; + }else{ + memset(zBuf, 0, SQLITE_PAGE_SIZE); + } + if( pPg->nRef==0 || memcmp(zBuf, PGHDR_TO_DATA(pPg), SQLITE_PAGE_SIZE) ){ + memcpy(PGHDR_TO_DATA(pPg), zBuf, SQLITE_PAGE_SIZE); + memset(PGHDR_TO_EXTRA(pPg), 0, pPager->nExtra); + } + pPg->needSync = 0; + pPg->dirty = 0; + } + } + +end_playback: + if( rc!=SQLITE_OK ){ + pager_unwritelock(pPager); + pPager->errMask |= PAGER_ERR_CORRUPT; + rc = SQLITE_CORRUPT; + }else{ + rc = pager_unwritelock(pPager); + } + return rc; +} + +/* +** Playback the checkpoint journal. +** +** This is similar to playing back the transaction journal but with +** a few extra twists. +** +** (1) The number of pages in the database file at the start of +** the checkpoint is stored in pPager->ckptSize, not in the +** journal file itself. +** +** (2) In addition to playing back the checkpoint journal, also +** playback all pages of the transaction journal beginning +** at offset pPager->ckptJSize. +*/ +static int pager_ckpt_playback(Pager *pPager){ + off_t szJ; /* Size of the full journal */ + int nRec; /* Number of Records */ + int i; /* Loop counter */ + int rc; + + /* Truncate the database back to its original size. + */ + rc = sqliteOsTruncate(&pPager->fd, SQLITE_PAGE_SIZE*(off_t)pPager->ckptSize); + pPager->dbSize = pPager->ckptSize; + + /* Figure out how many records are in the checkpoint journal. + */ + assert( pPager->ckptInUse && pPager->journalOpen ); + sqliteOsSeek(&pPager->cpfd, 0); + nRec = pPager->ckptNRec; + + /* Copy original pages out of the checkpoint journal and back into the + ** database file. Note that the checkpoint journal always uses format + ** 2 instead of format 3 since it does not need to be concerned with + ** power failures corrupting the journal and can thus omit the checksums. + */ + for(i=nRec-1; i>=0; i--){ + rc = pager_playback_one_page(pPager, &pPager->cpfd, 2); + assert( rc!=SQLITE_DONE ); + if( rc!=SQLITE_OK ) goto end_ckpt_playback; + } + + /* Figure out how many pages need to be copied out of the transaction + ** journal. + */ + rc = sqliteOsSeek(&pPager->jfd, pPager->ckptJSize); + if( rc!=SQLITE_OK ){ + goto end_ckpt_playback; + } + rc = sqliteOsFileSize(&pPager->jfd, &szJ); + if( rc!=SQLITE_OK ){ + goto end_ckpt_playback; + } + nRec = (szJ - pPager->ckptJSize)/JOURNAL_PG_SZ(journal_format); + for(i=nRec-1; i>=0; i--){ + rc = pager_playback_one_page(pPager, &pPager->jfd, journal_format); + if( rc!=SQLITE_OK ){ + assert( rc!=SQLITE_DONE ); + goto end_ckpt_playback; + } + } + +end_ckpt_playback: + if( rc!=SQLITE_OK ){ + pPager->errMask |= PAGER_ERR_CORRUPT; + rc = SQLITE_CORRUPT; + } + return rc; +} + +/* +** Change the maximum number of in-memory pages that are allowed. +** +** The maximum number is the absolute value of the mxPage parameter. +** If mxPage is negative, the noSync flag is also set. noSync bypasses +** calls to sqliteOsSync(). The pager runs much faster with noSync on, +** but if the operating system crashes or there is an abrupt power +** failure, the database file might be left in an inconsistent and +** unrepairable state. +*/ +void sqlitepager_set_cachesize(Pager *pPager, int mxPage){ + if( mxPage>=0 ){ + pPager->noSync = pPager->tempFile; + }else{ + pPager->noSync = 1; + mxPage = -mxPage; + } + if( mxPage>10 ){ + pPager->mxPage = mxPage; + } +} + +/* +** Adjust the robustness of the database to damage due to OS crashes +** or power failures by changing the number of syncs()s when writing +** the rollback journal. There are three levels: +** +** OFF sqliteOsSync() is never called. This is the default +** for temporary and transient files. +** +** NORMAL The journal is synced once before writes begin on the +** database. This is normally adequate protection, but +** it is theoretically possible, though very unlikely, +** that an inopertune power failure could leave the journal +** in a state which would cause damage to the database +** when it is rolled back. +** +** FULL The journal is synced twice before writes begin on the +** database (with some additional information being written +** in between the two syncs. If we assume that writing a +** single disk sector is atomic, then this mode provides +** assurance that the journal will not be corrupted to the +** point of causing damage to the database during rollback. +** +** Numeric values associated with these states are OFF==1, NORMAL=2, +** and FULL=3. +*/ +void sqlitepager_set_safety_level(Pager *pPager, int level){ + pPager->noSync = level==1 || pPager->tempFile; + pPager->fullSync = level==3 && !pPager->tempFile; +} + +/* +** Open a temporary file. Write the name of the file into zName +** (zName must be at least SQLITE_TEMPNAME_SIZE bytes long.) Write +** the file descriptor into *fd. Return SQLITE_OK on success or some +** other error code if we fail. +** +** The OS will automatically delete the temporary file when it is +** closed. +*/ +static int sqlitepager_opentemp(char *zFile, OsFile *fd){ + int cnt = 8; + int rc; + do{ + cnt--; + sqliteOsTempFileName(zFile); + rc = sqliteOsOpenExclusive(zFile, fd, 1); + }while( cnt>0 && rc!=SQLITE_OK ); + return rc; +} + +/* +** Create a new page cache and put a pointer to the page cache in *ppPager. +** The file to be cached need not exist. The file is not locked until +** the first call to sqlitepager_get() and is only held open until the +** last page is released using sqlitepager_unref(). +** +** If zFilename is NULL then a randomly-named temporary file is created +** and used as the file to be cached. The file will be deleted +** automatically when it is closed. +*/ +int sqlitepager_open( + Pager **ppPager, /* Return the Pager structure here */ + const char *zFilename, /* Name of the database file to open */ + int mxPage, /* Max number of in-memory cache pages */ + int nExtra, /* Extra bytes append to each in-memory page */ + int useJournal /* TRUE to use a rollback journal on this file */ +){ + Pager *pPager; + char *zFullPathname; + int nameLen; + OsFile fd; + int rc; + int tempFile; + int readOnly = 0; + char zTemp[SQLITE_TEMPNAME_SIZE]; + + *ppPager = 0; + if( sqlite_malloc_failed ){ + return SQLITE_NOMEM; + } + if( zFilename ){ + zFullPathname = sqliteOsFullPathname(zFilename); + rc = sqliteOsOpenReadWrite(zFullPathname, &fd, &readOnly); + tempFile = 0; + }else{ + rc = sqlitepager_opentemp(zTemp, &fd); + zFilename = zTemp; + zFullPathname = sqliteOsFullPathname(zFilename); + tempFile = 1; + } + if( sqlite_malloc_failed ){ + return SQLITE_NOMEM; + } + if( rc!=SQLITE_OK ){ + sqliteFree(zFullPathname); + return SQLITE_CANTOPEN; + } + nameLen = strlen(zFullPathname); + pPager = sqliteMalloc( sizeof(*pPager) + nameLen*2 + 30 ); + if( pPager==0 ){ + sqliteOsClose(&fd); + sqliteFree(zFullPathname); + return SQLITE_NOMEM; + } + SET_PAGER(pPager); + pPager->zFilename = (char*)&pPager[1]; + pPager->zJournal = &pPager->zFilename[nameLen+1]; + strcpy(pPager->zFilename, zFullPathname); + strcpy(pPager->zJournal, zFullPathname); + sqliteFree(zFullPathname); + strcpy(&pPager->zJournal[nameLen], "-journal"); + pPager->fd = fd; + pPager->journalOpen = 0; + pPager->useJournal = useJournal; + pPager->ckptOpen = 0; + pPager->ckptInUse = 0; + pPager->nRef = 0; + pPager->dbSize = -1; + pPager->ckptSize = 0; + pPager->ckptJSize = 0; + pPager->nPage = 0; + pPager->mxPage = mxPage>5 ? mxPage : 10; + pPager->state = SQLITE_UNLOCK; + pPager->errMask = 0; + pPager->tempFile = tempFile; + pPager->readOnly = readOnly; + pPager->needSync = 0; + pPager->noSync = pPager->tempFile || !useJournal; + pPager->pFirst = 0; + pPager->pFirstSynced = 0; + pPager->pLast = 0; + pPager->nExtra = nExtra; + memset(pPager->aHash, 0, sizeof(pPager->aHash)); + *ppPager = pPager; + return SQLITE_OK; +} + +/* +** Set the destructor for this pager. If not NULL, the destructor is called +** when the reference count on each page reaches zero. The destructor can +** be used to clean up information in the extra segment appended to each page. +** +** The destructor is not called as a result sqlitepager_close(). +** Destructors are only called by sqlitepager_unref(). +*/ +void sqlitepager_set_destructor(Pager *pPager, void (*xDesc)(void*)){ + pPager->xDestructor = xDesc; +} + +/* +** Return the total number of pages in the disk file associated with +** pPager. +*/ +int sqlitepager_pagecount(Pager *pPager){ + off_t n; + assert( pPager!=0 ); + if( pPager->dbSize>=0 ){ + return pPager->dbSize; + } + if( sqliteOsFileSize(&pPager->fd, &n)!=SQLITE_OK ){ + pPager->errMask |= PAGER_ERR_DISK; + return 0; + } + n /= SQLITE_PAGE_SIZE; + if( pPager->state!=SQLITE_UNLOCK ){ + pPager->dbSize = n; + } + return n; +} + +/* +** Forward declaration +*/ +static int syncAllPages(Pager*); + +/* +** Truncate the file to the number of pages specified. +*/ +int sqlitepager_truncate(Pager *pPager, Pgno nPage){ + int rc; + if( pPager->dbSize<0 ){ + sqlitepager_pagecount(pPager); + } + if( pPager->errMask!=0 ){ + rc = pager_errcode(pPager); + return rc; + } + if( nPage>=(unsigned)pPager->dbSize ){ + return SQLITE_OK; + } + syncAllPages(pPager); + rc = sqliteOsTruncate(&pPager->fd, SQLITE_PAGE_SIZE*(off_t)nPage); + if( rc==SQLITE_OK ){ + pPager->dbSize = nPage; + } + return rc; +} + +/* +** Shutdown the page cache. Free all memory and close all files. +** +** If a transaction was in progress when this routine is called, that +** transaction is rolled back. All outstanding pages are invalidated +** 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. +*/ +int sqlitepager_close(Pager *pPager){ + PgHdr *pPg, *pNext; + switch( pPager->state ){ + case SQLITE_WRITELOCK: { + sqlitepager_rollback(pPager); + sqliteOsUnlock(&pPager->fd); + assert( pPager->journalOpen==0 ); + break; + } + case SQLITE_READLOCK: { + sqliteOsUnlock(&pPager->fd); + break; + } + default: { + /* Do nothing */ + break; + } + } + for(pPg=pPager->pAll; pPg; pPg=pNext){ + pNext = pPg->pNextAll; + sqliteFree(pPg); + } + sqliteOsClose(&pPager->fd); + assert( pPager->journalOpen==0 ); + /* Temp files are automatically deleted by the OS + ** if( pPager->tempFile ){ + ** sqliteOsDelete(pPager->zFilename); + ** } + */ + CLR_PAGER(pPager); + if( pPager->zFilename!=(char*)&pPager[1] ){ + sqliteFree(pPager->zFilename); + sqliteFree(pPager->zJournal); + } + sqliteFree(pPager); + return SQLITE_OK; +} + +/* +** Return the page number for the given page data. +*/ +Pgno sqlitepager_pagenumber(void *pData){ + PgHdr *p = DATA_TO_PGHDR(pData); + return p->pgno; +} + +/* +** Increment the reference count for a page. If the page is +** currently on the freelist (the reference count is zero) then +** remove it from the freelist. +*/ +#define page_ref(P) ((P)->nRef==0?_page_ref(P):(void)(P)->nRef++) +static void _page_ref(PgHdr *pPg){ + if( pPg->nRef==0 ){ + /* The page is currently on the freelist. Remove it. */ + if( pPg==pPg->pPager->pFirstSynced ){ + PgHdr *p = pPg->pNextFree; + while( p && p->needSync ){ p = p->pNextFree; } + pPg->pPager->pFirstSynced = p; + } + if( pPg->pPrevFree ){ + pPg->pPrevFree->pNextFree = pPg->pNextFree; + }else{ + pPg->pPager->pFirst = pPg->pNextFree; + } + if( pPg->pNextFree ){ + pPg->pNextFree->pPrevFree = pPg->pPrevFree; + }else{ + pPg->pPager->pLast = pPg->pPrevFree; + } + pPg->pPager->nRef++; + } + pPg->nRef++; + REFINFO(pPg); +} + +/* +** Increment the reference count for a page. The input pointer is +** a reference to the page data. +*/ +int sqlitepager_ref(void *pData){ + PgHdr *pPg = DATA_TO_PGHDR(pData); + page_ref(pPg); + return SQLITE_OK; +} + +/* +** Sync the journal and then write all free dirty pages to the database +** file. +** +** Writing all free dirty pages to the database after the sync is a +** non-obvious optimization. fsync() is an expensive operation so we +** want to minimize the number ot times it is called. After an fsync() call, +** we are free to write dirty pages back to the database. It is best +** to go ahead and write as many dirty pages as possible to minimize +** the risk of having to do another fsync() later on. Writing dirty +** free pages in this way was observed to make database operations go +** up to 10 times faster. +** +** If we are writing to temporary database, there is no need to preserve +** the integrity of the journal file, so we can save time and skip the +** fsync(). +*/ +static int syncAllPages(Pager *pPager){ + PgHdr *pPg; + int rc = SQLITE_OK; + + /* Sync the journal before modifying the main database + ** (assuming there is a journal and it needs to be synced.) + */ + if( pPager->needSync ){ + if( !pPager->tempFile ){ + assert( pPager->journalOpen ); + assert( !pPager->noSync ); +#ifndef NDEBUG + { + off_t hdrSz, pgSz, jSz; + hdrSz = JOURNAL_HDR_SZ(journal_format); + pgSz = JOURNAL_PG_SZ(journal_format); + rc = sqliteOsFileSize(&pPager->jfd, &jSz); + if( rc!=0 ) return rc; + assert( pPager->nRec*pgSz+hdrSz==jSz ); + } +#endif + if( journal_format>=3 ){ + off_t szJ; + if( pPager->fullSync ){ + TRACE1("SYNC\n"); + rc = sqliteOsSync(&pPager->jfd); + if( rc!=0 ) return rc; + } + sqliteOsSeek(&pPager->jfd, sizeof(aJournalMagic1)); + rc = write32bits(&pPager->jfd, pPager->nRec); + if( rc ) return rc; + szJ = JOURNAL_HDR_SZ(journal_format) + + pPager->nRec*JOURNAL_PG_SZ(journal_format); + sqliteOsSeek(&pPager->jfd, szJ); + } + TRACE1("SYNC\n"); + rc = sqliteOsSync(&pPager->jfd); + if( rc!=0 ) return rc; + pPager->journalStarted = 1; + } + pPager->needSync = 0; + + /* Erase the needSync flag from every page. + */ + for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ + pPg->needSync = 0; + } + pPager->pFirstSynced = pPager->pFirst; + } + +#ifndef NDEBUG + /* If the Pager.needSync flag is clear then the PgHdr.needSync + ** flag must also be clear for all pages. Verify that this + ** invariant is true. + */ + else{ + for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ + assert( pPg->needSync==0 ); + } + assert( pPager->pFirstSynced==pPager->pFirst ); + } +#endif + + return rc; +} + +/* +** Given a list of pages (connected by the PgHdr.pDirty pointer) write +** every one of those pages out to the database file and mark them all +** as clean. +*/ +static int pager_write_pagelist(PgHdr *pList){ + Pager *pPager; + int rc; + + if( pList==0 ) return SQLITE_OK; + pPager = pList->pPager; + while( pList ){ + assert( pList->dirty ); + sqliteOsSeek(&pPager->fd, (pList->pgno-1)*(off_t)SQLITE_PAGE_SIZE); + rc = sqliteOsWrite(&pPager->fd, PGHDR_TO_DATA(pList), SQLITE_PAGE_SIZE); + if( rc ) return rc; + pList->dirty = 0; + pList = pList->pDirty; + } + return SQLITE_OK; +} + +/* +** Collect every dirty page into a dirty list and +** return a pointer to the head of that list. All pages are +** collected even if they are still in use. +*/ +static PgHdr *pager_get_all_dirty_pages(Pager *pPager){ + PgHdr *p, *pList; + pList = 0; + for(p=pPager->pAll; p; p=p->pNextAll){ + if( p->dirty ){ + p->pDirty = pList; + pList = p; + } + } + return pList; +} + +/* +** Acquire a page. +** +** A read lock on the disk file is obtained when the first page is acquired. +** This read lock is dropped when the last page is released. +** +** A _get works for any page number greater than 0. If the database +** file is smaller than the requested page, then no actual disk +** read occurs and the memory image of the page is initialized to +** all zeros. The extra data appended to a page is always initialized +** to zeros the first time a page is loaded into memory. +** +** The acquisition might fail for several reasons. In all cases, +** an appropriate error code is returned and *ppPage is set to NULL. +** +** See also sqlitepager_lookup(). Both this routine and _lookup() attempt +** to find a page in the in-memory cache first. If the page is not already +** in memory, this routine goes to disk to read it in whereas _lookup() +** just returns 0. This routine acquires a read-lock the first time it +** has to go to disk, and could also playback an old journal if necessary. +** Since _lookup() never goes to disk, it never has to deal with locks +** or journal files. +*/ +int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){ + PgHdr *pPg; + int rc; + + /* Make sure we have not hit any critical errors. + */ + assert( pPager!=0 ); + assert( pgno!=0 ); + *ppPage = 0; + if( pPager->errMask & ~(PAGER_ERR_FULL) ){ + return pager_errcode(pPager); + } + + /* If this is the first page accessed, then get a read lock + ** on the database file. + */ + if( pPager->nRef==0 ){ + rc = sqliteOsReadLock(&pPager->fd); + if( rc!=SQLITE_OK ){ + return rc; + } + pPager->state = SQLITE_READLOCK; + + /* If a journal file exists, try to play it back. + */ + if( pPager->useJournal && sqliteOsFileExists(pPager->zJournal) ){ + int rc; + + /* Get a write lock on the database + */ + rc = sqliteOsWriteLock(&pPager->fd); + if( rc!=SQLITE_OK ){ + if( sqliteOsUnlock(&pPager->fd)!=SQLITE_OK ){ + /* This should never happen! */ + rc = SQLITE_INTERNAL; + } + return rc; + } + pPager->state = SQLITE_WRITELOCK; + + /* Open the journal for reading only. Return SQLITE_BUSY if + ** we are unable to open the journal file. + ** + ** The journal file does not need to be locked itself. The + ** journal file is never open unless the main database file holds + ** a write lock, so there is never any chance of two or more + ** processes opening the journal at the same time. + */ + rc = sqliteOsOpenReadOnly(pPager->zJournal, &pPager->jfd); + if( rc!=SQLITE_OK ){ + rc = sqliteOsUnlock(&pPager->fd); + assert( rc==SQLITE_OK ); + return SQLITE_BUSY; + } + pPager->journalOpen = 1; + pPager->journalStarted = 0; + + /* Playback and delete the journal. Drop the database write + ** lock and reacquire the read lock. + */ + rc = pager_playback(pPager, 0); + if( rc!=SQLITE_OK ){ + return rc; + } + } + pPg = 0; + }else{ + /* Search for page in cache */ + pPg = pager_lookup(pPager, pgno); + } + if( pPg==0 ){ + /* The requested page is not in the page cache. */ + int h; + pPager->nMiss++; + if( pPager->nPagemxPage || pPager->pFirst==0 ){ + /* Create a new page */ + pPg = sqliteMallocRaw( sizeof(*pPg) + SQLITE_PAGE_SIZE + + sizeof(u32) + pPager->nExtra ); + if( pPg==0 ){ + pager_unwritelock(pPager); + pPager->errMask |= PAGER_ERR_MEM; + return SQLITE_NOMEM; + } + memset(pPg, 0, sizeof(*pPg)); + pPg->pPager = pPager; + pPg->pNextAll = pPager->pAll; + if( pPager->pAll ){ + pPager->pAll->pPrevAll = pPg; + } + pPg->pPrevAll = 0; + pPager->pAll = pPg; + pPager->nPage++; + }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 = syncAllPages(pPager); + if( rc!=0 ){ + sqlitepager_rollback(pPager); + return SQLITE_IOERR; + } + pPg = pPager->pFirst; + } + 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 ){ + sqlitepager_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 + */ + if( pPg==pPager->pFirstSynced ){ + PgHdr *p = pPg->pNextFree; + while( p && p->needSync ){ p = p->pNextFree; } + pPager->pFirstSynced = p; + } + if( pPg->pPrevFree ){ + pPg->pPrevFree->pNextFree = pPg->pNextFree; + }else{ + assert( pPager->pFirst==pPg ); + pPager->pFirst = pPg->pNextFree; + } + if( pPg->pNextFree ){ + pPg->pNextFree->pPrevFree = pPg->pPrevFree; + }else{ + assert( pPager->pLast==pPg ); + pPager->pLast = pPg->pPrevFree; + } + pPg->pNextFree = pPg->pPrevFree = 0; + if( pPg->pNextHash ){ + pPg->pNextHash->pPrevHash = pPg->pPrevHash; + } + if( pPg->pPrevHash ){ + pPg->pPrevHash->pNextHash = pPg->pNextHash; + }else{ + h = pager_hash(pPg->pgno); + assert( pPager->aHash[h]==pPg ); + pPager->aHash[h] = pPg->pNextHash; + } + pPg->pNextHash = pPg->pPrevHash = 0; + pPager->nOvfl++; + } + pPg->pgno = pgno; + if( pPager->aInJournal && (int)pgno<=pPager->origDbSize ){ + sqliteCheckMemory(pPager->aInJournal, pgno/8); + assert( pPager->journalOpen ); + pPg->inJournal = (pPager->aInJournal[pgno/8] & (1<<(pgno&7)))!=0; + pPg->needSync = 0; + }else{ + pPg->inJournal = 0; + pPg->needSync = 0; + } + if( pPager->aInCkpt && (int)pgno<=pPager->ckptSize + && (pPager->aInCkpt[pgno/8] & (1<<(pgno&7)))!=0 ){ + page_add_to_ckpt_list(pPg); + }else{ + page_remove_from_ckpt_list(pPg); + } + 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), 0, pPager->nExtra); + } + if( pPager->dbSize<0 ) sqlitepager_pagecount(pPager); + if( pPager->errMask!=0 ){ + sqlitepager_unref(PGHDR_TO_DATA(pPg)); + rc = pager_errcode(pPager); + return rc; + } + if( pPager->dbSize<(int)pgno ){ + memset(PGHDR_TO_DATA(pPg), 0, SQLITE_PAGE_SIZE); + }else{ + int rc; + sqliteOsSeek(&pPager->fd, (pgno-1)*(off_t)SQLITE_PAGE_SIZE); + rc = sqliteOsRead(&pPager->fd, PGHDR_TO_DATA(pPg), SQLITE_PAGE_SIZE); + if( rc!=SQLITE_OK ){ + off_t fileSize; + if( sqliteOsFileSize(&pPager->fd,&fileSize)!=SQLITE_OK + || fileSize>=pgno*SQLITE_PAGE_SIZE ){ + sqlitepager_unref(PGHDR_TO_DATA(pPg)); + return rc; + }else{ + memset(PGHDR_TO_DATA(pPg), 0, SQLITE_PAGE_SIZE); + } + } + } + }else{ + /* The requested page is in the page cache. */ + pPager->nHit++; + page_ref(pPg); + } + *ppPage = PGHDR_TO_DATA(pPg); + return SQLITE_OK; +} + +/* +** Acquire a page if it is already in the in-memory cache. Do +** not read the page from disk. Return a pointer to the page, +** or 0 if the page is not in cache. +** +** See also sqlitepager_get(). The difference between this routine +** and sqlitepager_get() is that _get() will go to the disk and read +** in the page if the page is not already in cache. This routine +** returns NULL if the page is not in cache or if a disk I/O error +** has ever happened. +*/ +void *sqlitepager_lookup(Pager *pPager, Pgno pgno){ + PgHdr *pPg; + + assert( pPager!=0 ); + assert( pgno!=0 ); + if( pPager->errMask & ~(PAGER_ERR_FULL) ){ + return 0; + } + /* if( pPager->nRef==0 ){ + ** return 0; + ** } + */ + pPg = pager_lookup(pPager, pgno); + if( pPg==0 ) return 0; + page_ref(pPg); + return PGHDR_TO_DATA(pPg); +} + +/* +** Release a page. +** +** If the number of references to the page drop to zero, then the +** page is added to the LRU list. When all references to all pages +** are released, a rollback occurs and the lock on the database is +** removed. +*/ +int sqlitepager_unref(void *pData){ + PgHdr *pPg; + + /* Decrement the reference count for this page + */ + pPg = DATA_TO_PGHDR(pData); + assert( pPg->nRef>0 ); + pPg->nRef--; + REFINFO(pPg); + + /* When the number of references to a page reach 0, call the + ** destructor and add the page to the freelist. + */ + if( pPg->nRef==0 ){ + Pager *pPager; + pPager = pPg->pPager; + pPg->pNextFree = 0; + pPg->pPrevFree = pPager->pLast; + pPager->pLast = pPg; + if( pPg->pPrevFree ){ + pPg->pPrevFree->pNextFree = pPg; + }else{ + pPager->pFirst = pPg; + } + if( pPg->needSync==0 && pPager->pFirstSynced==0 ){ + pPager->pFirstSynced = pPg; + } + if( pPager->xDestructor ){ + pPager->xDestructor(pData); + } + + /* When all pages reach the freelist, drop the read lock from + ** the database file. + */ + pPager->nRef--; + assert( pPager->nRef>=0 ); + if( pPager->nRef==0 ){ + pager_reset(pPager); + } + } + return SQLITE_OK; +} + +/* +** Create a journal file for pPager. There should already be a write +** lock on the database file when this routine is called. +** +** Return SQLITE_OK if everything. Return an error code and release the +** write lock if anything goes wrong. +*/ +static int pager_open_journal(Pager *pPager){ + int rc; + assert( pPager->state==SQLITE_WRITELOCK ); + assert( pPager->journalOpen==0 ); + assert( pPager->useJournal ); + sqlitepager_pagecount(pPager); + pPager->aInJournal = sqliteMalloc( pPager->dbSize/8 + 1 ); + if( pPager->aInJournal==0 ){ + sqliteOsReadLock(&pPager->fd); + pPager->state = SQLITE_READLOCK; + return SQLITE_NOMEM; + } + rc = sqliteOsOpenExclusive(pPager->zJournal, &pPager->jfd,pPager->tempFile); + if( rc!=SQLITE_OK ){ + sqliteFree(pPager->aInJournal); + pPager->aInJournal = 0; + sqliteOsReadLock(&pPager->fd); + pPager->state = SQLITE_READLOCK; + return SQLITE_CANTOPEN; + } + pPager->journalOpen = 1; + pPager->journalStarted = 0; + pPager->needSync = 0; + pPager->alwaysRollback = 0; + pPager->nRec = 0; + if( pPager->errMask!=0 ){ + rc = pager_errcode(pPager); + return rc; + } + pPager->origDbSize = pPager->dbSize; + if( journal_format==JOURNAL_FORMAT_3 ){ + rc = sqliteOsWrite(&pPager->jfd, aJournalMagic3, sizeof(aJournalMagic3)); + if( rc==SQLITE_OK ){ + rc = write32bits(&pPager->jfd, pPager->noSync ? 0xffffffff : 0); + } + if( rc==SQLITE_OK ){ + pPager->cksumInit = (u32)sqliteRandomInteger(); + rc = write32bits(&pPager->jfd, pPager->cksumInit); + } + }else if( journal_format==JOURNAL_FORMAT_2 ){ + rc = sqliteOsWrite(&pPager->jfd, aJournalMagic2, sizeof(aJournalMagic2)); + }else{ + assert( journal_format==JOURNAL_FORMAT_1 ); + rc = sqliteOsWrite(&pPager->jfd, aJournalMagic1, sizeof(aJournalMagic1)); + } + if( rc==SQLITE_OK ){ + rc = write32bits(&pPager->jfd, pPager->dbSize); + } + if( pPager->ckptAutoopen && rc==SQLITE_OK ){ + rc = sqlitepager_ckpt_begin(pPager); + } + if( rc!=SQLITE_OK ){ + rc = pager_unwritelock(pPager); + if( rc==SQLITE_OK ){ + rc = SQLITE_FULL; + } + } + return rc; +} + +/* +** Acquire a write-lock on the database. The lock is removed when +** the any of the following happen: +** +** * sqlitepager_commit() is called. +** * sqlitepager_rollback() is called. +** * sqlitepager_close() is called. +** * sqlitepager_unref() is called to on every outstanding page. +** +** The parameter to this routine is a pointer to any open page of the +** database file. Nothing changes about the page - it is used merely +** to acquire a pointer to the Pager structure and as proof that there +** is already a read-lock on the database. +** +** A journal file is opened if this is not a temporary file. For +** temporary files, the opening of the journal file is deferred until +** there is an actual need to write to the journal. +** +** If the database is already write-locked, this routine is a no-op. +*/ +int sqlitepager_begin(void *pData){ + PgHdr *pPg = DATA_TO_PGHDR(pData); + Pager *pPager = pPg->pPager; + int rc = SQLITE_OK; + assert( pPg->nRef>0 ); + assert( pPager->state!=SQLITE_UNLOCK ); + if( pPager->state==SQLITE_READLOCK ){ + assert( pPager->aInJournal==0 ); + rc = sqliteOsWriteLock(&pPager->fd); + if( rc!=SQLITE_OK ){ + return rc; + } + pPager->state = SQLITE_WRITELOCK; + pPager->dirtyFile = 0; + TRACE1("TRANSACTION\n"); + if( pPager->useJournal && !pPager->tempFile ){ + rc = pager_open_journal(pPager); + } + } + return rc; +} + +/* +** Mark a data page as writeable. The page is written into the journal +** if it is not there already. This routine must be called before making +** changes to a page. +** +** The first time this routine is called, the pager creates a new +** journal and acquires a write lock on the database. If the write +** lock could not be acquired, this routine returns SQLITE_BUSY. The +** calling routine must check for that return value and be careful not to +** change any page data until this routine returns SQLITE_OK. +** +** If the journal file could not be written because the disk is full, +** then this routine returns SQLITE_FULL and does an immediate rollback. +** All subsequent write attempts also return SQLITE_FULL until there +** is a call to sqlitepager_commit() or sqlitepager_rollback() to +** reset. +*/ +int sqlitepager_write(void *pData){ + PgHdr *pPg = DATA_TO_PGHDR(pData); + Pager *pPager = pPg->pPager; + int rc = SQLITE_OK; + + /* Check for errors + */ + if( pPager->errMask ){ + return pager_errcode(pPager); + } + if( pPager->readOnly ){ + return SQLITE_PERM; + } + + /* Mark the page as dirty. If the page has already been written + ** to the journal then we can return right away. + */ + pPg->dirty = 1; + if( pPg->inJournal && (pPg->inCkpt || pPager->ckptInUse==0) ){ + pPager->dirtyFile = 1; + return SQLITE_OK; + } + + /* If we get this far, it means that the page needs to be + ** written to the transaction journal or the ckeckpoint journal + ** or both. + ** + ** First check to see that the transaction journal exists and + ** create it if it does not. + */ + assert( pPager->state!=SQLITE_UNLOCK ); + rc = sqlitepager_begin(pData); + if( rc!=SQLITE_OK ){ + return rc; + } + assert( pPager->state==SQLITE_WRITELOCK ); + if( !pPager->journalOpen && pPager->useJournal ){ + rc = pager_open_journal(pPager); + if( rc!=SQLITE_OK ) return rc; + } + assert( pPager->journalOpen || !pPager->useJournal ); + pPager->dirtyFile = 1; + + /* The transaction journal now exists and we have a write lock on the + ** main database file. Write the current page to the transaction + ** journal if it is not there already. + */ + if( !pPg->inJournal && pPager->useJournal ){ + if( (int)pPg->pgno <= pPager->origDbSize ){ + int szPg; + u32 saved; + if( journal_format>=JOURNAL_FORMAT_3 ){ + u32 cksum = pager_cksum(pPager, pPg->pgno, pData); + saved = *(u32*)PGHDR_TO_EXTRA(pPg); + store32bits(cksum, pPg, SQLITE_PAGE_SIZE); + szPg = SQLITE_PAGE_SIZE+8; + }else{ + szPg = SQLITE_PAGE_SIZE+4; + } + store32bits(pPg->pgno, pPg, -4); + rc = sqliteOsWrite(&pPager->jfd, &((char*)pData)[-4], szPg); + if( journal_format>=JOURNAL_FORMAT_3 ){ + *(u32*)PGHDR_TO_EXTRA(pPg) = saved; + } + if( rc!=SQLITE_OK ){ + sqlitepager_rollback(pPager); + pPager->errMask |= PAGER_ERR_FULL; + return rc; + } + pPager->nRec++; + assert( pPager->aInJournal!=0 ); + pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7); + pPg->needSync = !pPager->noSync; + pPg->inJournal = 1; + if( pPager->ckptInUse ){ + pPager->aInCkpt[pPg->pgno/8] |= 1<<(pPg->pgno&7); + page_add_to_ckpt_list(pPg); + } + TRACE3("JOURNAL %d %d\n", pPg->pgno, pPg->needSync); + }else{ + pPg->needSync = !pPager->journalStarted && !pPager->noSync; + TRACE3("APPEND %d %d\n", pPg->pgno, pPg->needSync); + } + if( pPg->needSync ){ + pPager->needSync = 1; + } + } + + /* If the checkpoint journal is open and the page is not in it, + ** then write the current page to the checkpoint journal. Note that + ** the checkpoint journal always uses the simplier format 2 that lacks + ** checksums. The header is also omitted from the checkpoint journal. + */ + if( pPager->ckptInUse && !pPg->inCkpt && (int)pPg->pgno<=pPager->ckptSize ){ + assert( pPg->inJournal || (int)pPg->pgno>pPager->origDbSize ); + store32bits(pPg->pgno, pPg, -4); + rc = sqliteOsWrite(&pPager->cpfd, &((char*)pData)[-4], SQLITE_PAGE_SIZE+4); + if( rc!=SQLITE_OK ){ + sqlitepager_rollback(pPager); + pPager->errMask |= PAGER_ERR_FULL; + return rc; + } + pPager->ckptNRec++; + assert( pPager->aInCkpt!=0 ); + pPager->aInCkpt[pPg->pgno/8] |= 1<<(pPg->pgno&7); + page_add_to_ckpt_list(pPg); + } + + /* Update the database size and return. + */ + if( pPager->dbSize<(int)pPg->pgno ){ + pPager->dbSize = pPg->pgno; + } + return rc; +} + +/* +** Return TRUE if the page given in the argument was previously passed +** to sqlitepager_write(). In other words, return TRUE if it is ok +** to change the content of the page. +*/ +int sqlitepager_iswriteable(void *pData){ + PgHdr *pPg = DATA_TO_PGHDR(pData); + return pPg->dirty; +} + +/* +** Replace the content of a single page with the information in the third +** argument. +*/ +int sqlitepager_overwrite(Pager *pPager, Pgno pgno, void *pData){ + void *pPage; + int rc; + + rc = sqlitepager_get(pPager, pgno, &pPage); + if( rc==SQLITE_OK ){ + rc = sqlitepager_write(pPage); + if( rc==SQLITE_OK ){ + memcpy(pPage, pData, SQLITE_PAGE_SIZE); + } + sqlitepager_unref(pPage); + } + return rc; +} + +/* +** A call to this routine tells the pager that it is not necessary to +** write the information on page "pgno" back to the disk, even though +** that page might be marked as dirty. +** +** The overlying software layer calls this routine when all of the data +** on the given page is unused. The pager marks the page as clean so +** that it does not get written to disk. +** +** Tests show that this optimization, together with the +** sqlitepager_dont_rollback() below, more than double the speed +** of large INSERT operations and quadruple the speed of large DELETEs. +** +** When this routine is called, set the alwaysRollback flag to true. +** Subsequent calls to sqlitepager_dont_rollback() for the same page +** will thereafter be ignored. This is necessary to avoid a problem +** where a page with data is added to the freelist during one part of +** a transaction then removed from the freelist during a later part +** of the same transaction and reused for some other purpose. When it +** is first added to the freelist, this routine is called. When reused, +** the dont_rollback() routine is called. But because the page contains +** critical data, we still need to be sure it gets rolled back in spite +** of the dont_rollback() call. +*/ +void sqlitepager_dont_write(Pager *pPager, Pgno pgno){ + PgHdr *pPg; + + pPg = pager_lookup(pPager, pgno); + pPg->alwaysRollback = 1; + if( pPg && pPg->dirty ){ + if( pPager->dbSize==(int)pPg->pgno && pPager->origDbSizedbSize ){ + /* 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. + ** When the database file grows, we must make sure that the last page + ** gets written at least once so that the disk file will be the correct + ** size. If you do not write this page and the size of the file + ** on the disk ends up being too small, that can lead to database + ** corruption during the next transaction. + */ + }else{ + TRACE2("DONT_WRITE %d\n", pgno); + pPg->dirty = 0; + } + } +} + +/* +** A call to this routine tells the pager that if a rollback occurs, +** it is not necessary to restore the data on the given page. This +** means that the pager does not have to record the given page in the +** rollback journal. +*/ +void sqlitepager_dont_rollback(void *pData){ + PgHdr *pPg = DATA_TO_PGHDR(pData); + Pager *pPager = pPg->pPager; + + if( pPager->state!=SQLITE_WRITELOCK || pPager->journalOpen==0 ) return; + if( pPg->alwaysRollback || pPager->alwaysRollback ) return; + if( !pPg->inJournal && (int)pPg->pgno <= pPager->origDbSize ){ + assert( pPager->aInJournal!=0 ); + pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7); + pPg->inJournal = 1; + if( pPager->ckptInUse ){ + pPager->aInCkpt[pPg->pgno/8] |= 1<<(pPg->pgno&7); + page_add_to_ckpt_list(pPg); + } + TRACE2("DONT_ROLLBACK %d\n", pPg->pgno); + } + if( pPager->ckptInUse && !pPg->inCkpt && (int)pPg->pgno<=pPager->ckptSize ){ + assert( pPg->inJournal || (int)pPg->pgno>pPager->origDbSize ); + assert( pPager->aInCkpt!=0 ); + pPager->aInCkpt[pPg->pgno/8] |= 1<<(pPg->pgno&7); + page_add_to_ckpt_list(pPg); + } +} + +/* +** Commit all changes to the database and release the write lock. +** +** If the commit fails for any reason, a rollback attempt is made +** and an error code is returned. If the commit worked, SQLITE_OK +** is returned. +*/ +int sqlitepager_commit(Pager *pPager){ + int rc; + PgHdr *pPg; + + if( pPager->errMask==PAGER_ERR_FULL ){ + rc = sqlitepager_rollback(pPager); + if( rc==SQLITE_OK ){ + rc = SQLITE_FULL; + } + return rc; + } + if( pPager->errMask!=0 ){ + rc = pager_errcode(pPager); + return rc; + } + if( pPager->state!=SQLITE_WRITELOCK ){ + return SQLITE_ERROR; + } + TRACE1("COMMIT\n"); + if( pPager->dirtyFile==0 ){ + /* Exit early (without doing the time-consuming sqliteOsSync() calls) + ** if there have been no changes to the database file. */ + assert( pPager->needSync==0 ); + rc = pager_unwritelock(pPager); + pPager->dbSize = -1; + return rc; + } + assert( pPager->journalOpen ); + if( pPager->needSync && sqliteOsSync(&pPager->jfd)!=SQLITE_OK ){ + goto commit_abort; + } + pPg = pager_get_all_dirty_pages(pPager); + if( pPg ){ + rc = pager_write_pagelist(pPg); + if( rc || (!pPager->noSync && sqliteOsSync(&pPager->fd)!=SQLITE_OK) ){ + goto commit_abort; + } + } + rc = pager_unwritelock(pPager); + pPager->dbSize = -1; + return rc; + + /* Jump here if anything goes wrong during the commit process. + */ +commit_abort: + rc = sqlitepager_rollback(pPager); + if( rc==SQLITE_OK ){ + rc = SQLITE_FULL; + } + return rc; +} + +/* +** Rollback all changes. The database falls back to read-only mode. +** All in-memory cache pages revert to their original data contents. +** The journal is deleted. +** +** This routine cannot fail unless some other process is not following +** the correct locking protocol (SQLITE_PROTOCOL) or unless some other +** process is writing trash into the journal file (SQLITE_CORRUPT) or +** unless a prior malloc() failed (SQLITE_NOMEM). Appropriate error +** codes are returned for all these occasions. Otherwise, +** SQLITE_OK is returned. +*/ +int sqlitepager_rollback(Pager *pPager){ + int rc; + TRACE1("ROLLBACK\n"); + if( !pPager->dirtyFile || !pPager->journalOpen ){ + rc = pager_unwritelock(pPager); + pPager->dbSize = -1; + return rc; + } + + if( pPager->errMask!=0 && pPager->errMask!=PAGER_ERR_FULL ){ + if( pPager->state>=SQLITE_WRITELOCK ){ + pager_playback(pPager, 1); + } + return pager_errcode(pPager); + } + if( pPager->state!=SQLITE_WRITELOCK ){ + return SQLITE_OK; + } + rc = pager_playback(pPager, 1); + if( rc!=SQLITE_OK ){ + rc = SQLITE_CORRUPT; + pPager->errMask |= PAGER_ERR_CORRUPT; + } + pPager->dbSize = -1; + return rc; +} + +/* +** Return TRUE if the database file is opened read-only. Return FALSE +** if the database is (in theory) writable. +*/ +int sqlitepager_isreadonly(Pager *pPager){ + return pPager->readOnly; +} + +/* +** This routine is used for testing and analysis only. +*/ +int *sqlitepager_stats(Pager *pPager){ + static int a[9]; + a[0] = pPager->nRef; + a[1] = pPager->nPage; + a[2] = pPager->mxPage; + a[3] = pPager->dbSize; + a[4] = pPager->state; + a[5] = pPager->errMask; + a[6] = pPager->nHit; + a[7] = pPager->nMiss; + a[8] = pPager->nOvfl; + return a; +} + +/* +** Set the checkpoint. +** +** This routine should be called with the transaction journal already +** open. A new checkpoint journal is created that can be used to rollback +** changes of a single SQL command within a larger transaction. +*/ +int sqlitepager_ckpt_begin(Pager *pPager){ + int rc; + char zTemp[SQLITE_TEMPNAME_SIZE]; + if( !pPager->journalOpen ){ + pPager->ckptAutoopen = 1; + return SQLITE_OK; + } + assert( pPager->journalOpen ); + assert( !pPager->ckptInUse ); + pPager->aInCkpt = sqliteMalloc( pPager->dbSize/8 + 1 ); + if( pPager->aInCkpt==0 ){ + sqliteOsReadLock(&pPager->fd); + return SQLITE_NOMEM; + } +#ifndef NDEBUG + rc = sqliteOsFileSize(&pPager->jfd, &pPager->ckptJSize); + if( rc ) goto ckpt_begin_failed; + assert( pPager->ckptJSize == + pPager->nRec*JOURNAL_PG_SZ(journal_format)+JOURNAL_HDR_SZ(journal_format) ); +#endif + pPager->ckptJSize = pPager->nRec*JOURNAL_PG_SZ(journal_format) + + JOURNAL_HDR_SZ(journal_format); + pPager->ckptSize = pPager->dbSize; + if( !pPager->ckptOpen ){ + rc = sqlitepager_opentemp(zTemp, &pPager->cpfd); + if( rc ) goto ckpt_begin_failed; + pPager->ckptOpen = 1; + pPager->ckptNRec = 0; + } + pPager->ckptInUse = 1; + return SQLITE_OK; + +ckpt_begin_failed: + if( pPager->aInCkpt ){ + sqliteFree(pPager->aInCkpt); + pPager->aInCkpt = 0; + } + return rc; +} + +/* +** Commit a checkpoint. +*/ +int sqlitepager_ckpt_commit(Pager *pPager){ + if( pPager->ckptInUse ){ + PgHdr *pPg, *pNext; + sqliteOsSeek(&pPager->cpfd, 0); + /* sqliteOsTruncate(&pPager->cpfd, 0); */ + pPager->ckptNRec = 0; + pPager->ckptInUse = 0; + sqliteFree( pPager->aInCkpt ); + pPager->aInCkpt = 0; + for(pPg=pPager->pCkpt; pPg; pPg=pNext){ + pNext = pPg->pNextCkpt; + assert( pPg->inCkpt ); + pPg->inCkpt = 0; + pPg->pPrevCkpt = pPg->pNextCkpt = 0; + } + pPager->pCkpt = 0; + } + pPager->ckptAutoopen = 0; + return SQLITE_OK; +} + +/* +** Rollback a checkpoint. +*/ +int sqlitepager_ckpt_rollback(Pager *pPager){ + int rc; + if( pPager->ckptInUse ){ + rc = pager_ckpt_playback(pPager); + sqlitepager_ckpt_commit(pPager); + }else{ + rc = SQLITE_OK; + } + pPager->ckptAutoopen = 0; + return rc; +} + +/* +** Return the full pathname of the database file. +*/ +const char *sqlitepager_filename(Pager *pPager){ + return pPager->zFilename; +} + +#ifdef SQLITE_TEST +/* +** Print a listing of all referenced pages and their ref count. +*/ +void sqlitepager_refdump(Pager *pPager){ + PgHdr *pPg; + for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ + if( pPg->nRef<=0 ) continue; + printf("PAGE %3d addr=0x%08x nRef=%d\n", + pPg->pgno, (int)PGHDR_TO_DATA(pPg), pPg->nRef); + } +} +#endif diff --git a/sqlitebrowser/sqlitebrowser/sqlite_source/pager.h b/sqlitebrowser/sqlitebrowser/sqlite_source/pager.h new file mode 100755 index 00000000..ebdf394f --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/sqlite_source/pager.h @@ -0,0 +1,83 @@ +/* +** 2001 September 15 +** +** 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 header file defines the interface that the sqlite page cache +** subsystem. The page cache subsystem reads and writes a file a page +** at a time and provides a journal for rollback. +** +** @(#) $Id: pager.h,v 1.1.1.1 2003-08-21 02:24:12 tabuleiro Exp $ +*/ + +/* +** The size of one page +** +** You can change this value to another (reasonable) power of two +** such as 512, 2048, 4096, or 8192 and things will still work. But +** experiments show that a page size of 1024 gives the best speed. +** (The speed differences are minimal.) +*/ +#define SQLITE_PAGE_SIZE 1024 + +/* +** Maximum number of pages in one database. (This is a limitation of +** imposed by 4GB files size limits.) +*/ +#define SQLITE_MAX_PAGE 1073741823 + +/* +** The type used to represent a page number. The first page in a file +** is called page 1. 0 is used to represent "not a page". +*/ +typedef unsigned int Pgno; + +/* +** Each open file is managed by a separate instance of the "Pager" structure. +*/ +typedef struct Pager Pager; + +/* +** See source code comments for a detailed description of the following +** routines: +*/ +int sqlitepager_open(Pager **ppPager, const char *zFilename, + int nPage, int nExtra, int useJournal); +void sqlitepager_set_destructor(Pager*, void(*)(void*)); +void sqlitepager_set_cachesize(Pager*, int); +int sqlitepager_close(Pager *pPager); +int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage); +void *sqlitepager_lookup(Pager *pPager, Pgno pgno); +int sqlitepager_ref(void*); +int sqlitepager_unref(void*); +Pgno sqlitepager_pagenumber(void*); +int sqlitepager_write(void*); +int sqlitepager_iswriteable(void*); +int sqlitepager_overwrite(Pager *pPager, Pgno pgno, void*); +int sqlitepager_pagecount(Pager*); +int sqlitepager_truncate(Pager*,Pgno); +int sqlitepager_begin(void*); +int sqlitepager_commit(Pager*); +int sqlitepager_rollback(Pager*); +int sqlitepager_isreadonly(Pager*); +int sqlitepager_ckpt_begin(Pager*); +int sqlitepager_ckpt_commit(Pager*); +int sqlitepager_ckpt_rollback(Pager*); +void sqlitepager_dont_rollback(void*); +void sqlitepager_dont_write(Pager*, Pgno); +int *sqlitepager_stats(Pager*); +void sqlitepager_set_safety_level(Pager*,int); +const char *sqlitepager_filename(Pager*); +int sqlitepager_rename(Pager*, const char *zNewName); + +#ifdef SQLITE_TEST +void sqlitepager_refdump(Pager*); +int pager_refinfo_enable; +int journal_format; +#endif diff --git a/sqlitebrowser/sqlitebrowser/sqlite_source/parse.c b/sqlitebrowser/sqlitebrowser/sqlite_source/parse.c new file mode 100755 index 00000000..c015169d --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/sqlite_source/parse.c @@ -0,0 +1,7103 @@ +/* Driver template for the LEMON parser generator. +** The author disclaims copyright to this source code. +*/ +/* First off, code is include which follows the "include" declaration +** in the input file. */ +#include +#line 35 "parse.y" + +#include "sqliteInt.h" +#include "parse.h" + +/* +** An instance of this structure holds information about the +** LIMIT clause of a SELECT statement. +*/ +struct LimitVal { + int limit; /* The LIMIT value. -1 if there is no limit */ + int offset; /* The OFFSET. 0 if there is none */ +}; + +/* +** An instance of the following structure describes the event of a +** TRIGGER. "a" is the event type, one of TK_UPDATE, TK_INSERT, +** TK_DELETE, or TK_INSTEAD. If the event is of the form +** +** UPDATE ON (a,b,c) +** +** Then the "b" IdList records the list "a,b,c". +*/ +struct TrigEvent { int a; IdList * b; }; + + +#line 34 "parse.c" +/* Next is all token values, in a form suitable for use by makeheaders. +** This section will be null unless lemon is run with the -m switch. +*/ +/* +** These constants (all generated automatically by the parser generator) +** specify the various kinds of tokens (terminals) that the parser +** understands. +** +** Each symbol here is a terminal symbol in the grammar. +*/ +/* Make sure the INTERFACE macro is defined. +*/ +#ifndef INTERFACE +# define INTERFACE 1 +#endif +/* The next thing included is series of defines which control +** various aspects of the generated parser. +** YYCODETYPE is the data type used for storing terminal +** and nonterminal numbers. "unsigned char" is +** used if there are fewer than 250 terminals +** and nonterminals. "int" is used otherwise. +** YYNOCODE is a number of type YYCODETYPE which corresponds +** to no legal terminal or nonterminal number. This +** number is used to fill in empty slots of the hash +** table. +** YYFALLBACK If defined, this indicates that one or more tokens +** have fall-back values which should be used if the +** original value of the token will not parse. +** YYACTIONTYPE is the data type used for storing terminal +** and nonterminal numbers. "unsigned char" is +** used if there are fewer than 250 rules and +** states combined. "int" is used otherwise. +** sqliteParserTOKENTYPE is the data type used for minor tokens given +** directly to the parser from the tokenizer. +** YYMINORTYPE is the data type used for all minor tokens. +** This is typically a union of many types, one of +** which is sqliteParserTOKENTYPE. The entry in the union +** for base tokens is called "yy0". +** YYSTACKDEPTH is the maximum depth of the parser's stack. +** sqliteParserARG_SDECL A static variable declaration for the %extra_argument +** sqliteParserARG_PDECL A parameter declaration for the %extra_argument +** sqliteParserARG_STORE Code to store %extra_argument into yypParser +** sqliteParserARG_FETCH Code to extract %extra_argument from yypParser +** YYNSTATE the combined number of states. +** YYNRULE the number of rules in the grammar +** YYERRORSYMBOL is the code number of the error symbol. If not +** defined, then do no error processing. +*/ +/*  */ +#define YYCODETYPE unsigned char +#define YYNOCODE 219 +#define YYACTIONTYPE unsigned short int +#define sqliteParserTOKENTYPE Token +typedef union { + sqliteParserTOKENTYPE yy0; + Select* yy11; + int yy52; + ExprList* yy62; + IdList* yy92; + Token yy210; + struct TrigEvent yy234; + Expr * yy270; + struct {int value; int mask;} yy279; + struct LimitVal yy280; + Expr* yy334; + SrcList* yy335; + TriggerStep * yy347; + int yy437; +} YYMINORTYPE; +#define YYSTACKDEPTH 100 +#define sqliteParserARG_SDECL Parse *pParse; +#define sqliteParserARG_PDECL ,Parse *pParse +#define sqliteParserARG_FETCH Parse *pParse = yypParser->pParse +#define sqliteParserARG_STORE yypParser->pParse = pParse +#define YYNSTATE 555 +#define YYNRULE 287 +#define YYERRORSYMBOL 155 +#define YYERRSYMDT yy437 +#define YYFALLBACK 1 +#define YY_NO_ACTION (YYNSTATE+YYNRULE+2) +#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1) +#define YY_ERROR_ACTION (YYNSTATE+YYNRULE) +/* Next is the action table. Each entry in this table contains +** +** + An integer which is the number representing the look-ahead +** token +** +** + An integer indicating what action to take. Number (N) between +** 0 and YYNSTATE-1 mean shift the look-ahead and go to state N. +** Numbers between YYNSTATE and YYNSTATE+YYNRULE-1 mean reduce by +** rule N-YYNSTATE. Number YYNSTATE+YYNRULE means that a syntax +** error has occurred. Number YYNSTATE+YYNRULE+1 means the parser +** accepts its input. +** +** + A pointer to the next entry with the same hash value. +** +** The action table is really a series of hash tables. Each hash +** table contains a number of entries which is a power of two. The +** "state" table (which follows) contains information about the starting +** point and size of each hash table. +*/ +struct yyActionEntry { + YYCODETYPE lookahead; /* The value of the look-ahead token */ + YYCODETYPE next; /* Next entry + 1. Zero at end of collision chain */ + YYACTIONTYPE action; /* Action to take for this look-ahead */ +}; +typedef struct yyActionEntry yyActionEntry; +static const yyActionEntry yyActionTable[] = { +/* State 0 */ + { 156, 0, 3}, /* 1: explain shift 3 */ + { 139, 0, 1}, /* 2: cmdlist shift 1 */ + { 170, 0, 843}, /* 3: input accept */ + { 47, 0, 553}, /* 4: EXPLAIN shift 553 */ + { 154, 0, 554}, /* 5: ecmd shift 554 */ + { 107, 4, 552}, /* 6: SEMI shift 552 */ +/* State 1 */ + { 0, 0, 555}, /* 1: $ reduce 0 */ + { 156, 0, 3}, /* 2: explain shift 3 */ + { 107, 4, 552}, /* 3: SEMI shift 552 */ + { 47, 0, 553}, /* 4: EXPLAIN shift 553 */ + { 154, 0, 2}, /* 5: ecmd shift 2 */ +/* State 3 */ + { 66, 0, 512}, /* 1: INSERT shift 512 */ + { 28, 0, 515}, /* 2: COPY shift 515 */ + { 24, 0, 23}, /* 3: COMMIT shift 23 */ + { 29, 0, 388}, /* 4: CREATE shift 388 */ + { 8, 0, 543}, /* 5: ATTACH shift 543 */ + { 34, 0, 490}, /* 6: DELETE shift 490 */ + { 138, 2, 6}, /* 7: cmd shift 6 */ + { 95, 4, 526}, /* 8: PRAGMA shift 526 */ + { 140, 5, 4}, /* 9: cmdx shift 4 */ + { 185, 0, 69}, /* 10: oneselect shift 69 */ + { 10, 0, 7}, /* 11: BEGIN shift 7 */ + { 37, 0, 549}, /* 12: DETACH shift 549 */ + { 100, 6, 514}, /* 13: REPLACE shift 514 */ + { 123, 0, 495}, /* 14: UPDATE shift 495 */ + { 102, 0, 27}, /* 15: ROLLBACK shift 27 */ + { 147, 12, 29}, /* 16: create_table shift 29 */ + { 126, 0, 524}, /* 17: VACUUM shift 524 */ + { 40, 0, 478}, /* 18: DROP shift 478 */ + { 106, 18, 73}, /* 19: SELECT shift 73 */ + { 173, 0, 502}, /* 20: insert_cmd shift 502 */ + { 196, 0, 489}, /* 21: select shift 489 */ + { 43, 0, 25}, /* 22: END shift 25 */ +/* State 4 */ + { 107, 0, 5}, /* 1: SEMI shift 5 */ +/* State 6 */ + { 107, 0, 560}, /* 1: SEMI reduce 5 */ +/* State 7 */ + { 206, 0, 8}, /* 1: trans_opt shift 8 */ + { 117, 0, 18}, /* 2: TRANSACTION shift 18 */ +/* State 8 */ + { 90, 0, 10}, /* 1: ON shift 10 */ + { 184, 0, 9}, /* 2: onconf shift 9 */ + { 107, 0, 643}, /* 3: SEMI reduce 88 */ +/* State 9 */ + { 107, 0, 563}, /* 1: SEMI reduce 8 */ +/* State 10 */ + { 26, 0, 11}, /* 1: CONFLICT shift 11 */ +/* State 11 */ + { 102, 3, 13}, /* 1: ROLLBACK shift 13 */ + { 193, 4, 12}, /* 2: resolvetype shift 12 */ + { 60, 6, 16}, /* 3: IGNORE shift 16 */ + { 1, 0, 14}, /* 4: ABORT shift 14 */ + { 100, 0, 17}, /* 5: REPLACE shift 17 */ + { 48, 0, 15}, /* 6: FAIL shift 15 */ +/* State 18 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 19}, /* 2: nm shift 19 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 23 */ + { 117, 0, 18}, /* 1: TRANSACTION shift 18 */ + { 107, 0, 564}, /* 2: SEMI reduce 9 */ + { 206, 2, 24}, /* 3: trans_opt shift 24 */ +/* State 24 */ + { 107, 0, 567}, /* 1: SEMI reduce 12 */ +/* State 25 */ + { 117, 0, 18}, /* 1: TRANSACTION shift 18 */ + { 107, 0, 564}, /* 2: SEMI reduce 9 */ + { 206, 2, 26}, /* 3: trans_opt shift 26 */ +/* State 26 */ + { 107, 0, 568}, /* 1: SEMI reduce 13 */ +/* State 27 */ + { 117, 0, 18}, /* 1: TRANSACTION shift 18 */ + { 107, 0, 564}, /* 2: SEMI reduce 9 */ + { 206, 2, 28}, /* 3: trans_opt shift 28 */ +/* State 28 */ + { 107, 0, 569}, /* 1: SEMI reduce 14 */ +/* State 29 */ + { 6, 0, 386}, /* 1: AS shift 386 */ + { 148, 3, 30}, /* 2: create_table_args shift 30 */ + { 79, 0, 31}, /* 3: LP shift 31 */ +/* State 30 */ + { 107, 0, 570}, /* 1: SEMI reduce 15 */ +/* State 31 */ + { 59, 0, 20}, /* 1: ID shift 20 */ + { 113, 0, 21}, /* 2: STRING shift 21 */ + { 142, 0, 385}, /* 3: column shift 385 */ + { 143, 1, 37}, /* 4: columnid shift 37 */ + { 144, 6, 32}, /* 5: columnlist shift 32 */ + { 74, 0, 22}, /* 6: JOIN_KW shift 22 */ + { 181, 0, 351}, /* 7: nm shift 351 */ +/* State 32 */ + { 104, 0, 631}, /* 1: RP reduce 76 */ + { 22, 0, 35}, /* 2: COMMA shift 35 */ + { 146, 1, 33}, /* 3: conslist_opt shift 33 */ +/* State 33 */ + { 104, 0, 34}, /* 1: RP shift 34 */ +/* State 34 */ + { 107, 0, 574}, /* 1: SEMI reduce 19 */ +/* State 35 */ + { 143, 0, 37}, /* 1: columnid shift 37 */ + { 27, 0, 355}, /* 2: CONSTRAINT shift 355 */ + { 145, 0, 352}, /* 3: conslist shift 352 */ + { 96, 5, 357}, /* 4: PRIMARY shift 357 */ + { 18, 0, 368}, /* 5: CHECK shift 368 */ + { 122, 4, 363}, /* 6: UNIQUE shift 363 */ + { 113, 9, 21}, /* 7: STRING shift 21 */ + { 59, 0, 20}, /* 8: ID shift 20 */ + { 74, 0, 22}, /* 9: JOIN_KW shift 22 */ + { 204, 7, 384}, /* 10: tcons shift 384 */ + { 142, 12, 36}, /* 11: column shift 36 */ + { 51, 0, 371}, /* 12: FOREIGN shift 371 */ + { 181, 11, 351}, /* 13: nm shift 351 */ +/* State 37 */ + { 165, 0, 350}, /* 1: ids shift 350 */ + { 113, 0, 257}, /* 2: STRING shift 257 */ + { 212, 0, 38}, /* 3: type shift 38 */ + { 213, 2, 342}, /* 4: typename shift 342 */ + { 59, 0, 256}, /* 5: ID shift 256 */ +/* State 38 */ + { 133, 0, 39}, /* 1: carglist shift 39 */ +/* State 39 */ + { 96, 4, 54}, /* 1: PRIMARY shift 54 */ + { 27, 0, 41}, /* 2: CONSTRAINT shift 41 */ + { 132, 0, 40}, /* 3: carg shift 40 */ + { 31, 5, 330}, /* 4: DEFAULT shift 330 */ + { 18, 0, 62}, /* 5: CHECK shift 62 */ + { 122, 1, 60}, /* 6: UNIQUE shift 60 */ + { 32, 0, 327}, /* 7: DEFERRABLE shift 327 */ + { 137, 11, 329}, /* 8: ccons shift 329 */ + { 151, 0, 324}, /* 9: defer_subclause shift 324 */ + { 87, 0, 44}, /* 10: NULL shift 44 */ + { 98, 12, 302}, /* 11: REFERENCES shift 302 */ + { 85, 13, 46}, /* 12: NOT shift 46 */ + { 20, 0, 325}, /* 13: COLLATE shift 325 */ +/* State 41 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 42}, /* 2: nm shift 42 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 42 */ + { 20, 0, 325}, /* 1: COLLATE shift 325 */ + { 151, 0, 324}, /* 2: defer_subclause shift 324 */ + { 122, 4, 60}, /* 3: UNIQUE shift 60 */ + { 32, 0, 327}, /* 4: DEFERRABLE shift 327 */ + { 87, 0, 44}, /* 5: NULL shift 44 */ + { 85, 0, 46}, /* 6: NOT shift 46 */ + { 96, 0, 54}, /* 7: PRIMARY shift 54 */ + { 137, 5, 43}, /* 8: ccons shift 43 */ + { 98, 10, 302}, /* 9: REFERENCES shift 302 */ + { 18, 0, 62}, /* 10: CHECK shift 62 */ +/* State 44 */ + { 184, 2, 45}, /* 1: onconf shift 45 */ + { 90, 0, 10}, /* 2: ON shift 10 */ +/* State 46 */ + { 32, 0, 49}, /* 1: DEFERRABLE shift 49 */ + { 87, 0, 47}, /* 2: NULL shift 47 */ +/* State 47 */ + { 184, 2, 48}, /* 1: onconf shift 48 */ + { 90, 0, 10}, /* 2: ON shift 10 */ +/* State 49 */ + { 65, 0, 51}, /* 1: INITIALLY shift 51 */ + { 169, 1, 50}, /* 2: init_deferred_pred_opt shift 50 */ +/* State 51 */ + { 62, 0, 53}, /* 1: IMMEDIATE shift 53 */ + { 33, 0, 52}, /* 2: DEFERRED shift 52 */ +/* State 54 */ + { 75, 0, 55}, /* 1: KEY shift 55 */ +/* State 55 */ + { 36, 0, 59}, /* 1: DESC shift 59 */ + { 202, 3, 56}, /* 2: sortorder shift 56 */ + { 7, 0, 58}, /* 3: ASC shift 58 */ +/* State 56 */ + { 184, 2, 57}, /* 1: onconf shift 57 */ + { 90, 0, 10}, /* 2: ON shift 10 */ +/* State 60 */ + { 184, 2, 61}, /* 1: onconf shift 61 */ + { 90, 0, 10}, /* 2: ON shift 10 */ +/* State 62 */ + { 79, 0, 63}, /* 1: LP shift 63 */ +/* State 63 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 299}, /* 8: expr shift 299 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 64 */ + { 39, 0, 583}, /* 1: DOT reduce 28 */ + { 79, 1, 65}, /* 2: LP shift 65 */ +/* State 65 */ + { 59, 0, 64}, /* 1: ID shift 64 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 74, 0, 67}, /* 3: JOIN_KW shift 67 */ + { 111, 0, 297}, /* 4: STAR shift 297 */ + { 94, 0, 181}, /* 5: PLUS shift 181 */ + { 113, 1, 66}, /* 6: STRING shift 66 */ + { 79, 0, 68}, /* 7: LP shift 68 */ + { 97, 7, 193}, /* 8: RAISE shift 193 */ + { 85, 10, 175}, /* 9: NOT shift 175 */ + { 49, 11, 174}, /* 10: FLOAT shift 174 */ + { 13, 0, 177}, /* 11: BITNOT shift 177 */ + { 83, 0, 179}, /* 12: MINUS shift 179 */ + { 68, 0, 173}, /* 13: INTEGER shift 173 */ + { 157, 9, 172}, /* 14: expr shift 172 */ + { 158, 13, 219}, /* 15: expritem shift 219 */ + { 159, 17, 295}, /* 16: exprlist shift 295 */ + { 87, 0, 106}, /* 17: NULL shift 106 */ + { 17, 0, 183}, /* 18: CASE shift 183 */ +/* State 66 */ + { 39, 0, 584}, /* 1: DOT reduce 29 */ +/* State 67 */ + { 39, 0, 585}, /* 1: DOT reduce 30 */ +/* State 68 */ + { 113, 4, 66}, /* 1: STRING shift 66 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 74, 0, 67}, /* 3: JOIN_KW shift 67 */ + { 59, 0, 64}, /* 4: ID shift 64 */ + { 94, 0, 181}, /* 5: PLUS shift 181 */ + { 185, 1, 69}, /* 6: oneselect shift 69 */ + { 79, 0, 68}, /* 7: LP shift 68 */ + { 97, 7, 193}, /* 8: RAISE shift 193 */ + { 85, 10, 175}, /* 9: NOT shift 175 */ + { 49, 11, 174}, /* 10: FLOAT shift 174 */ + { 13, 0, 177}, /* 11: BITNOT shift 177 */ + { 83, 0, 179}, /* 12: MINUS shift 179 */ + { 106, 0, 73}, /* 13: SELECT shift 73 */ + { 157, 9, 293}, /* 14: expr shift 293 */ + { 68, 0, 173}, /* 15: INTEGER shift 173 */ + { 87, 0, 106}, /* 16: NULL shift 106 */ + { 196, 13, 70}, /* 17: select shift 70 */ + { 17, 0, 183}, /* 18: CASE shift 183 */ +/* State 70 */ + { 180, 0, 71}, /* 1: multiselect_op shift 71 */ + { 121, 3, 167}, /* 2: UNION shift 167 */ + { 46, 0, 170}, /* 3: EXCEPT shift 170 */ + { 69, 0, 169}, /* 4: INTERSECT shift 169 */ + { 104, 4, 292}, /* 5: RP shift 292 */ +/* State 71 */ + { 106, 0, 73}, /* 1: SELECT shift 73 */ + { 185, 0, 72}, /* 2: oneselect shift 72 */ +/* State 73 */ + { 153, 0, 74}, /* 1: distinct shift 74 */ + { 4, 0, 291}, /* 2: ALL shift 291 */ + { 38, 0, 290}, /* 3: DISTINCT shift 290 */ +/* State 74 */ + { 194, 0, 283}, /* 1: sclp shift 283 */ + { 195, 0, 75}, /* 2: selcollist shift 75 */ +/* State 75 */ + { 22, 0, 241}, /* 1: COMMA shift 241 */ + { 52, 1, 242}, /* 2: FROM shift 242 */ + { 161, 0, 76}, /* 3: from shift 76 */ +/* State 76 */ + { 130, 0, 239}, /* 1: WHERE shift 239 */ + { 217, 0, 77}, /* 2: where_opt shift 77 */ +/* State 77 */ + { 162, 2, 78}, /* 1: groupby_opt shift 78 */ + { 56, 0, 236}, /* 2: GROUP shift 236 */ +/* State 78 */ + { 58, 0, 234}, /* 1: HAVING shift 234 */ + { 163, 0, 79}, /* 2: having_opt shift 79 */ +/* State 79 */ + { 93, 0, 93}, /* 1: ORDER shift 93 */ + { 187, 1, 80}, /* 2: orderby_opt shift 80 */ +/* State 80 */ + { 178, 2, 81}, /* 1: limit_opt shift 81 */ + { 78, 0, 82}, /* 2: LIMIT shift 82 */ +/* State 82 */ + { 68, 0, 83}, /* 1: INTEGER shift 83 */ + { 83, 0, 86}, /* 2: MINUS shift 86 */ + { 94, 0, 84}, /* 3: PLUS shift 84 */ + { 199, 2, 88}, /* 4: signed shift 88 */ +/* State 84 */ + { 68, 0, 85}, /* 1: INTEGER shift 85 */ +/* State 86 */ + { 68, 0, 87}, /* 1: INTEGER shift 87 */ +/* State 88 */ + { 22, 0, 91}, /* 1: COMMA shift 91 */ + { 89, 0, 89}, /* 2: OFFSET shift 89 */ +/* State 89 */ + { 68, 0, 83}, /* 1: INTEGER shift 83 */ + { 83, 0, 86}, /* 2: MINUS shift 86 */ + { 94, 0, 84}, /* 3: PLUS shift 84 */ + { 199, 2, 90}, /* 4: signed shift 90 */ +/* State 91 */ + { 68, 0, 83}, /* 1: INTEGER shift 83 */ + { 83, 0, 86}, /* 2: MINUS shift 86 */ + { 94, 0, 84}, /* 3: PLUS shift 84 */ + { 199, 2, 92}, /* 4: signed shift 92 */ +/* State 93 */ + { 15, 0, 94}, /* 1: BY shift 94 */ +/* State 94 */ + { 85, 2, 175}, /* 1: NOT shift 175 */ + { 68, 4, 173}, /* 2: INTEGER shift 173 */ + { 87, 0, 106}, /* 3: NULL shift 106 */ + { 17, 0, 183}, /* 4: CASE shift 183 */ + { 157, 0, 103}, /* 5: expr shift 103 */ + { 113, 8, 66}, /* 6: STRING shift 66 */ + { 74, 0, 67}, /* 7: JOIN_KW shift 67 */ + { 79, 0, 68}, /* 8: LP shift 68 */ + { 59, 0, 64}, /* 9: ID shift 64 */ + { 94, 0, 181}, /* 10: PLUS shift 181 */ + { 13, 0, 177}, /* 11: BITNOT shift 177 */ + { 181, 6, 107}, /* 12: nm shift 107 */ + { 97, 0, 193}, /* 13: RAISE shift 193 */ + { 200, 11, 231}, /* 14: sortitem shift 231 */ + { 201, 0, 95}, /* 15: sortlist shift 95 */ + { 83, 17, 179}, /* 16: MINUS shift 179 */ + { 49, 0, 174}, /* 17: FLOAT shift 174 */ +/* State 95 */ + { 22, 0, 96}, /* 1: COMMA shift 96 */ +/* State 96 */ + { 97, 3, 193}, /* 1: RAISE shift 193 */ + { 113, 1, 66}, /* 2: STRING shift 66 */ + { 49, 7, 174}, /* 3: FLOAT shift 174 */ + { 83, 0, 179}, /* 4: MINUS shift 179 */ + { 68, 0, 173}, /* 5: INTEGER shift 173 */ + { 181, 10, 107}, /* 6: nm shift 107 */ + { 17, 0, 183}, /* 7: CASE shift 183 */ + { 87, 0, 106}, /* 8: NULL shift 106 */ + { 200, 0, 97}, /* 9: sortitem shift 97 */ + { 85, 0, 175}, /* 10: NOT shift 175 */ + { 74, 0, 67}, /* 11: JOIN_KW shift 67 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 13, 0, 177}, /* 13: BITNOT shift 177 */ + { 157, 13, 103}, /* 14: expr shift 103 */ + { 94, 0, 181}, /* 15: PLUS shift 181 */ + { 79, 0, 68}, /* 16: LP shift 68 */ +/* State 97 */ + { 20, 0, 100}, /* 1: COLLATE shift 100 */ + { 141, 0, 98}, /* 2: collate shift 98 */ +/* State 98 */ + { 36, 0, 59}, /* 1: DESC shift 59 */ + { 202, 3, 99}, /* 2: sortorder shift 99 */ + { 7, 0, 58}, /* 3: ASC shift 58 */ +/* State 100 */ + { 164, 0, 102}, /* 1: id shift 102 */ + { 59, 0, 101}, /* 2: ID shift 101 */ +/* State 103 */ + { 84, 0, 123}, /* 1: NE shift 123 */ + { 85, 4, 137}, /* 2: NOT shift 137 */ + { 86, 0, 159}, /* 3: NOTNULL shift 159 */ + { 57, 0, 117}, /* 4: GT shift 117 */ + { 63, 0, 164}, /* 5: IN shift 164 */ + { 5, 0, 105}, /* 6: AND shift 105 */ + { 71, 0, 155}, /* 7: IS shift 155 */ + { 91, 5, 113}, /* 8: OR shift 113 */ + { 92, 0, 104}, /* 9: ORACLE_OUTER_JOIN shift 104 */ + { 177, 0, 135}, /* 10: likeop shift 135 */ + { 94, 0, 142}, /* 11: PLUS shift 142 */ + { 11, 0, 160}, /* 12: BETWEEN shift 160 */ + { 12, 0, 127}, /* 13: BITAND shift 127 */ + { 77, 0, 140}, /* 14: LIKE shift 140 */ + { 14, 0, 129}, /* 15: BITOR shift 129 */ + { 99, 7, 150}, /* 16: REM shift 150 */ + { 72, 0, 154}, /* 17: ISNULL shift 154 */ + { 45, 0, 125}, /* 18: EQ shift 125 */ + { 81, 20, 115}, /* 19: LT shift 115 */ + { 25, 0, 152}, /* 20: CONCAT shift 152 */ + { 76, 0, 119}, /* 21: LE shift 119 */ + { 105, 14, 133}, /* 22: RSHIFT shift 133 */ + { 83, 24, 144}, /* 23: MINUS shift 144 */ + { 55, 0, 141}, /* 24: GLOB shift 141 */ + { 80, 0, 131}, /* 25: LSHIFT shift 131 */ + { 109, 19, 148}, /* 26: SLASH shift 148 */ + { 54, 0, 121}, /* 27: GE shift 121 */ + { 111, 23, 146}, /* 28: STAR shift 146 */ +/* State 105 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 112}, /* 8: expr shift 112 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 107 */ + { 39, 0, 108}, /* 1: DOT shift 108 */ +/* State 108 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 109}, /* 2: nm shift 109 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 109 */ + { 39, 0, 110}, /* 1: DOT shift 110 */ +/* State 110 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 111}, /* 2: nm shift 111 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 112 */ + { 54, 0, 121}, /* 1: GE shift 121 */ + { 105, 0, 133}, /* 2: RSHIFT shift 133 */ + { 80, 1, 131}, /* 3: LSHIFT shift 131 */ + { 81, 5, 115}, /* 4: LT shift 115 */ + { 55, 0, 141}, /* 5: GLOB shift 141 */ + { 109, 10, 148}, /* 6: SLASH shift 148 */ + { 84, 0, 123}, /* 7: NE shift 123 */ + { 111, 11, 146}, /* 8: STAR shift 146 */ + { 86, 0, 159}, /* 9: NOTNULL shift 159 */ + { 83, 14, 144}, /* 10: MINUS shift 144 */ + { 85, 0, 137}, /* 11: NOT shift 137 */ + { 63, 16, 164}, /* 12: IN shift 164 */ + { 12, 0, 127}, /* 13: BITAND shift 127 */ + { 57, 0, 117}, /* 14: GT shift 117 */ + { 92, 18, 104}, /* 15: ORACLE_OUTER_JOIN shift 104 */ + { 11, 0, 160}, /* 16: BETWEEN shift 160 */ + { 94, 0, 142}, /* 17: PLUS shift 142 */ + { 14, 0, 129}, /* 18: BITOR shift 129 */ + { 45, 0, 125}, /* 19: EQ shift 125 */ + { 71, 19, 155}, /* 20: IS shift 155 */ + { 72, 0, 154}, /* 21: ISNULL shift 154 */ + { 177, 23, 135}, /* 22: likeop shift 135 */ + { 99, 0, 150}, /* 23: REM shift 150 */ + { 25, 0, 152}, /* 24: CONCAT shift 152 */ + { 76, 0, 119}, /* 25: LE shift 119 */ + { 77, 24, 140}, /* 26: LIKE shift 140 */ +/* State 113 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 114}, /* 8: expr shift 114 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 114 */ + { 81, 7, 115}, /* 1: LT shift 115 */ + { 109, 8, 148}, /* 2: SLASH shift 148 */ + { 83, 0, 144}, /* 3: MINUS shift 144 */ + { 111, 9, 146}, /* 4: STAR shift 146 */ + { 85, 0, 137}, /* 5: NOT shift 137 */ + { 86, 11, 159}, /* 6: NOTNULL shift 159 */ + { 54, 0, 121}, /* 7: GE shift 121 */ + { 55, 0, 141}, /* 8: GLOB shift 141 */ + { 84, 17, 123}, /* 9: NE shift 123 */ + { 63, 0, 164}, /* 10: IN shift 164 */ + { 5, 0, 105}, /* 11: AND shift 105 */ + { 92, 20, 104}, /* 12: ORACLE_OUTER_JOIN shift 104 */ + { 12, 0, 127}, /* 13: BITAND shift 127 */ + { 94, 0, 142}, /* 14: PLUS shift 142 */ + { 14, 0, 129}, /* 15: BITOR shift 129 */ + { 177, 0, 135}, /* 16: likeop shift 135 */ + { 57, 0, 117}, /* 17: GT shift 117 */ + { 71, 0, 155}, /* 18: IS shift 155 */ + { 99, 21, 150}, /* 19: REM shift 150 */ + { 11, 0, 160}, /* 20: BETWEEN shift 160 */ + { 72, 22, 154}, /* 21: ISNULL shift 154 */ + { 45, 0, 125}, /* 22: EQ shift 125 */ + { 76, 0, 119}, /* 23: LE shift 119 */ + { 77, 0, 140}, /* 24: LIKE shift 140 */ + { 105, 0, 133}, /* 25: RSHIFT shift 133 */ + { 25, 0, 152}, /* 26: CONCAT shift 152 */ + { 80, 0, 131}, /* 27: LSHIFT shift 131 */ +/* State 115 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 116}, /* 8: expr shift 116 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 116 */ + { 12, 0, 127}, /* 1: BITAND shift 127 */ + { 109, 5, 148}, /* 2: SLASH shift 148 */ + { 14, 0, 129}, /* 3: BITOR shift 129 */ + { 111, 6, 146}, /* 4: STAR shift 146 */ + { 25, 0, 152}, /* 5: CONCAT shift 152 */ + { 99, 0, 150}, /* 6: REM shift 150 */ + { 80, 0, 131}, /* 7: LSHIFT shift 131 */ + { 105, 0, 133}, /* 8: RSHIFT shift 133 */ + { 92, 7, 104}, /* 9: ORACLE_OUTER_JOIN shift 104 */ + { 177, 8, 135}, /* 10: likeop shift 135 */ + { 94, 0, 142}, /* 11: PLUS shift 142 */ + { 83, 0, 144}, /* 12: MINUS shift 144 */ +/* State 117 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 118}, /* 8: expr shift 118 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 118 */ + { 12, 0, 127}, /* 1: BITAND shift 127 */ + { 109, 5, 148}, /* 2: SLASH shift 148 */ + { 14, 0, 129}, /* 3: BITOR shift 129 */ + { 111, 6, 146}, /* 4: STAR shift 146 */ + { 25, 0, 152}, /* 5: CONCAT shift 152 */ + { 99, 0, 150}, /* 6: REM shift 150 */ + { 80, 0, 131}, /* 7: LSHIFT shift 131 */ + { 105, 0, 133}, /* 8: RSHIFT shift 133 */ + { 92, 7, 104}, /* 9: ORACLE_OUTER_JOIN shift 104 */ + { 177, 8, 135}, /* 10: likeop shift 135 */ + { 94, 0, 142}, /* 11: PLUS shift 142 */ + { 83, 0, 144}, /* 12: MINUS shift 144 */ +/* State 119 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 120}, /* 8: expr shift 120 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 120 */ + { 12, 0, 127}, /* 1: BITAND shift 127 */ + { 109, 5, 148}, /* 2: SLASH shift 148 */ + { 14, 0, 129}, /* 3: BITOR shift 129 */ + { 111, 6, 146}, /* 4: STAR shift 146 */ + { 25, 0, 152}, /* 5: CONCAT shift 152 */ + { 99, 0, 150}, /* 6: REM shift 150 */ + { 80, 0, 131}, /* 7: LSHIFT shift 131 */ + { 105, 0, 133}, /* 8: RSHIFT shift 133 */ + { 92, 7, 104}, /* 9: ORACLE_OUTER_JOIN shift 104 */ + { 177, 8, 135}, /* 10: likeop shift 135 */ + { 94, 0, 142}, /* 11: PLUS shift 142 */ + { 83, 0, 144}, /* 12: MINUS shift 144 */ +/* State 121 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 122}, /* 8: expr shift 122 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 122 */ + { 12, 0, 127}, /* 1: BITAND shift 127 */ + { 109, 5, 148}, /* 2: SLASH shift 148 */ + { 14, 0, 129}, /* 3: BITOR shift 129 */ + { 111, 6, 146}, /* 4: STAR shift 146 */ + { 25, 0, 152}, /* 5: CONCAT shift 152 */ + { 99, 0, 150}, /* 6: REM shift 150 */ + { 80, 0, 131}, /* 7: LSHIFT shift 131 */ + { 105, 0, 133}, /* 8: RSHIFT shift 133 */ + { 92, 7, 104}, /* 9: ORACLE_OUTER_JOIN shift 104 */ + { 177, 8, 135}, /* 10: likeop shift 135 */ + { 94, 0, 142}, /* 11: PLUS shift 142 */ + { 83, 0, 144}, /* 12: MINUS shift 144 */ +/* State 123 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 124}, /* 8: expr shift 124 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 124 */ + { 80, 0, 131}, /* 1: LSHIFT shift 131 */ + { 177, 3, 135}, /* 2: likeop shift 135 */ + { 81, 0, 115}, /* 3: LT shift 115 */ + { 99, 5, 150}, /* 4: REM shift 150 */ + { 83, 0, 144}, /* 5: MINUS shift 144 */ + { 57, 8, 117}, /* 6: GT shift 117 */ + { 54, 0, 121}, /* 7: GE shift 121 */ + { 25, 0, 152}, /* 8: CONCAT shift 152 */ + { 76, 11, 119}, /* 9: LE shift 119 */ + { 105, 6, 133}, /* 10: RSHIFT shift 133 */ + { 12, 0, 127}, /* 11: BITAND shift 127 */ + { 14, 0, 129}, /* 12: BITOR shift 129 */ + { 92, 9, 104}, /* 13: ORACLE_OUTER_JOIN shift 104 */ + { 109, 0, 148}, /* 14: SLASH shift 148 */ + { 94, 12, 142}, /* 15: PLUS shift 142 */ + { 111, 0, 146}, /* 16: STAR shift 146 */ +/* State 125 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 126}, /* 8: expr shift 126 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 126 */ + { 80, 0, 131}, /* 1: LSHIFT shift 131 */ + { 177, 3, 135}, /* 2: likeop shift 135 */ + { 81, 0, 115}, /* 3: LT shift 115 */ + { 99, 5, 150}, /* 4: REM shift 150 */ + { 83, 0, 144}, /* 5: MINUS shift 144 */ + { 57, 8, 117}, /* 6: GT shift 117 */ + { 54, 0, 121}, /* 7: GE shift 121 */ + { 25, 0, 152}, /* 8: CONCAT shift 152 */ + { 76, 11, 119}, /* 9: LE shift 119 */ + { 105, 6, 133}, /* 10: RSHIFT shift 133 */ + { 12, 0, 127}, /* 11: BITAND shift 127 */ + { 14, 0, 129}, /* 12: BITOR shift 129 */ + { 92, 9, 104}, /* 13: ORACLE_OUTER_JOIN shift 104 */ + { 109, 0, 148}, /* 14: SLASH shift 148 */ + { 94, 12, 142}, /* 15: PLUS shift 142 */ + { 111, 0, 146}, /* 16: STAR shift 146 */ +/* State 127 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 128}, /* 8: expr shift 128 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 128 */ + { 25, 0, 152}, /* 1: CONCAT shift 152 */ + { 177, 1, 135}, /* 2: likeop shift 135 */ + { 83, 0, 144}, /* 3: MINUS shift 144 */ + { 99, 3, 150}, /* 4: REM shift 150 */ + { 92, 0, 104}, /* 5: ORACLE_OUTER_JOIN shift 104 */ + { 109, 0, 148}, /* 6: SLASH shift 148 */ + { 94, 0, 142}, /* 7: PLUS shift 142 */ + { 111, 0, 146}, /* 8: STAR shift 146 */ +/* State 129 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 130}, /* 8: expr shift 130 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 130 */ + { 25, 0, 152}, /* 1: CONCAT shift 152 */ + { 177, 1, 135}, /* 2: likeop shift 135 */ + { 83, 0, 144}, /* 3: MINUS shift 144 */ + { 99, 3, 150}, /* 4: REM shift 150 */ + { 92, 0, 104}, /* 5: ORACLE_OUTER_JOIN shift 104 */ + { 109, 0, 148}, /* 6: SLASH shift 148 */ + { 94, 0, 142}, /* 7: PLUS shift 142 */ + { 111, 0, 146}, /* 8: STAR shift 146 */ +/* State 131 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 132}, /* 8: expr shift 132 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 132 */ + { 25, 0, 152}, /* 1: CONCAT shift 152 */ + { 177, 1, 135}, /* 2: likeop shift 135 */ + { 83, 0, 144}, /* 3: MINUS shift 144 */ + { 99, 3, 150}, /* 4: REM shift 150 */ + { 92, 0, 104}, /* 5: ORACLE_OUTER_JOIN shift 104 */ + { 109, 0, 148}, /* 6: SLASH shift 148 */ + { 94, 0, 142}, /* 7: PLUS shift 142 */ + { 111, 0, 146}, /* 8: STAR shift 146 */ +/* State 133 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 134}, /* 8: expr shift 134 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 134 */ + { 25, 0, 152}, /* 1: CONCAT shift 152 */ + { 177, 1, 135}, /* 2: likeop shift 135 */ + { 83, 0, 144}, /* 3: MINUS shift 144 */ + { 99, 3, 150}, /* 4: REM shift 150 */ + { 92, 0, 104}, /* 5: ORACLE_OUTER_JOIN shift 104 */ + { 109, 0, 148}, /* 6: SLASH shift 148 */ + { 94, 0, 142}, /* 7: PLUS shift 142 */ + { 111, 0, 146}, /* 8: STAR shift 146 */ +/* State 135 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 136}, /* 8: expr shift 136 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 136 */ + { 80, 0, 131}, /* 1: LSHIFT shift 131 */ + { 177, 3, 135}, /* 2: likeop shift 135 */ + { 81, 0, 115}, /* 3: LT shift 115 */ + { 99, 5, 150}, /* 4: REM shift 150 */ + { 83, 0, 144}, /* 5: MINUS shift 144 */ + { 57, 8, 117}, /* 6: GT shift 117 */ + { 54, 0, 121}, /* 7: GE shift 121 */ + { 25, 0, 152}, /* 8: CONCAT shift 152 */ + { 76, 11, 119}, /* 9: LE shift 119 */ + { 105, 6, 133}, /* 10: RSHIFT shift 133 */ + { 12, 0, 127}, /* 11: BITAND shift 127 */ + { 14, 0, 129}, /* 12: BITOR shift 129 */ + { 92, 9, 104}, /* 13: ORACLE_OUTER_JOIN shift 104 */ + { 109, 0, 148}, /* 14: SLASH shift 148 */ + { 94, 12, 142}, /* 15: PLUS shift 142 */ + { 111, 0, 146}, /* 16: STAR shift 146 */ +/* State 137 */ + { 87, 3, 220}, /* 1: NULL shift 220 */ + { 55, 0, 141}, /* 2: GLOB shift 141 */ + { 63, 0, 225}, /* 3: IN shift 225 */ + { 177, 1, 138}, /* 4: likeop shift 138 */ + { 11, 0, 221}, /* 5: BETWEEN shift 221 */ + { 77, 5, 140}, /* 6: LIKE shift 140 */ +/* State 138 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 139}, /* 8: expr shift 139 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 139 */ + { 80, 0, 131}, /* 1: LSHIFT shift 131 */ + { 177, 3, 135}, /* 2: likeop shift 135 */ + { 81, 0, 115}, /* 3: LT shift 115 */ + { 99, 5, 150}, /* 4: REM shift 150 */ + { 83, 0, 144}, /* 5: MINUS shift 144 */ + { 57, 8, 117}, /* 6: GT shift 117 */ + { 54, 0, 121}, /* 7: GE shift 121 */ + { 25, 0, 152}, /* 8: CONCAT shift 152 */ + { 76, 11, 119}, /* 9: LE shift 119 */ + { 105, 6, 133}, /* 10: RSHIFT shift 133 */ + { 12, 0, 127}, /* 11: BITAND shift 127 */ + { 14, 0, 129}, /* 12: BITOR shift 129 */ + { 92, 9, 104}, /* 13: ORACLE_OUTER_JOIN shift 104 */ + { 109, 0, 148}, /* 14: SLASH shift 148 */ + { 94, 12, 142}, /* 15: PLUS shift 142 */ + { 111, 0, 146}, /* 16: STAR shift 146 */ +/* State 142 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 143}, /* 8: expr shift 143 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 143 */ + { 25, 0, 152}, /* 1: CONCAT shift 152 */ + { 109, 1, 148}, /* 2: SLASH shift 148 */ + { 92, 0, 104}, /* 3: ORACLE_OUTER_JOIN shift 104 */ + { 177, 5, 135}, /* 4: likeop shift 135 */ + { 111, 6, 146}, /* 5: STAR shift 146 */ + { 99, 0, 150}, /* 6: REM shift 150 */ +/* State 144 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 145}, /* 8: expr shift 145 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 145 */ + { 25, 0, 152}, /* 1: CONCAT shift 152 */ + { 109, 1, 148}, /* 2: SLASH shift 148 */ + { 92, 0, 104}, /* 3: ORACLE_OUTER_JOIN shift 104 */ + { 177, 5, 135}, /* 4: likeop shift 135 */ + { 111, 6, 146}, /* 5: STAR shift 146 */ + { 99, 0, 150}, /* 6: REM shift 150 */ +/* State 146 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 147}, /* 8: expr shift 147 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 147 */ + { 177, 0, 135}, /* 1: likeop shift 135 */ + { 25, 0, 152}, /* 2: CONCAT shift 152 */ + { 92, 0, 104}, /* 3: ORACLE_OUTER_JOIN shift 104 */ +/* State 148 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 149}, /* 8: expr shift 149 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 149 */ + { 177, 0, 135}, /* 1: likeop shift 135 */ + { 25, 0, 152}, /* 2: CONCAT shift 152 */ + { 92, 0, 104}, /* 3: ORACLE_OUTER_JOIN shift 104 */ +/* State 150 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 151}, /* 8: expr shift 151 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 151 */ + { 177, 0, 135}, /* 1: likeop shift 135 */ + { 25, 0, 152}, /* 2: CONCAT shift 152 */ + { 92, 0, 104}, /* 3: ORACLE_OUTER_JOIN shift 104 */ +/* State 152 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 153}, /* 8: expr shift 153 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 153 */ + { 92, 0, 104}, /* 1: ORACLE_OUTER_JOIN shift 104 */ + { 177, 0, 135}, /* 2: likeop shift 135 */ +/* State 155 */ + { 85, 0, 157}, /* 1: NOT shift 157 */ + { 87, 1, 156}, /* 2: NULL shift 156 */ +/* State 157 */ + { 87, 0, 158}, /* 1: NULL shift 158 */ +/* State 160 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 161}, /* 8: expr shift 161 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 161 */ + { 84, 0, 123}, /* 1: NE shift 123 */ + { 85, 4, 137}, /* 2: NOT shift 137 */ + { 86, 0, 159}, /* 3: NOTNULL shift 159 */ + { 57, 0, 117}, /* 4: GT shift 117 */ + { 63, 0, 164}, /* 5: IN shift 164 */ + { 5, 0, 162}, /* 6: AND shift 162 */ + { 71, 0, 155}, /* 7: IS shift 155 */ + { 91, 5, 113}, /* 8: OR shift 113 */ + { 92, 0, 104}, /* 9: ORACLE_OUTER_JOIN shift 104 */ + { 177, 0, 135}, /* 10: likeop shift 135 */ + { 94, 0, 142}, /* 11: PLUS shift 142 */ + { 11, 0, 160}, /* 12: BETWEEN shift 160 */ + { 12, 0, 127}, /* 13: BITAND shift 127 */ + { 77, 0, 140}, /* 14: LIKE shift 140 */ + { 14, 0, 129}, /* 15: BITOR shift 129 */ + { 99, 7, 150}, /* 16: REM shift 150 */ + { 72, 0, 154}, /* 17: ISNULL shift 154 */ + { 45, 0, 125}, /* 18: EQ shift 125 */ + { 81, 20, 115}, /* 19: LT shift 115 */ + { 25, 0, 152}, /* 20: CONCAT shift 152 */ + { 76, 0, 119}, /* 21: LE shift 119 */ + { 105, 14, 133}, /* 22: RSHIFT shift 133 */ + { 83, 24, 144}, /* 23: MINUS shift 144 */ + { 55, 0, 141}, /* 24: GLOB shift 141 */ + { 80, 0, 131}, /* 25: LSHIFT shift 131 */ + { 109, 19, 148}, /* 26: SLASH shift 148 */ + { 54, 0, 121}, /* 27: GE shift 121 */ + { 111, 23, 146}, /* 28: STAR shift 146 */ +/* State 162 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 163}, /* 8: expr shift 163 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 163 */ + { 80, 0, 131}, /* 1: LSHIFT shift 131 */ + { 177, 3, 135}, /* 2: likeop shift 135 */ + { 81, 0, 115}, /* 3: LT shift 115 */ + { 99, 5, 150}, /* 4: REM shift 150 */ + { 83, 0, 144}, /* 5: MINUS shift 144 */ + { 57, 8, 117}, /* 6: GT shift 117 */ + { 54, 0, 121}, /* 7: GE shift 121 */ + { 25, 0, 152}, /* 8: CONCAT shift 152 */ + { 76, 11, 119}, /* 9: LE shift 119 */ + { 105, 6, 133}, /* 10: RSHIFT shift 133 */ + { 12, 0, 127}, /* 11: BITAND shift 127 */ + { 14, 0, 129}, /* 12: BITOR shift 129 */ + { 92, 9, 104}, /* 13: ORACLE_OUTER_JOIN shift 104 */ + { 109, 0, 148}, /* 14: SLASH shift 148 */ + { 94, 12, 142}, /* 15: PLUS shift 142 */ + { 111, 0, 146}, /* 16: STAR shift 146 */ +/* State 164 */ + { 79, 0, 165}, /* 1: LP shift 165 */ +/* State 165 */ + { 85, 0, 175}, /* 1: NOT shift 175 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 13, 0, 177}, /* 3: BITNOT shift 177 */ + { 83, 0, 179}, /* 4: MINUS shift 179 */ + { 74, 0, 67}, /* 5: JOIN_KW shift 67 */ + { 185, 1, 69}, /* 6: oneselect shift 69 */ + { 106, 0, 73}, /* 7: SELECT shift 73 */ + { 87, 0, 106}, /* 8: NULL shift 106 */ + { 68, 0, 173}, /* 9: INTEGER shift 173 */ + { 49, 0, 174}, /* 10: FLOAT shift 174 */ + { 97, 12, 193}, /* 11: RAISE shift 193 */ + { 17, 0, 183}, /* 12: CASE shift 183 */ + { 79, 16, 68}, /* 13: LP shift 68 */ + { 113, 3, 66}, /* 14: STRING shift 66 */ + { 94, 5, 181}, /* 15: PLUS shift 181 */ + { 59, 0, 64}, /* 16: ID shift 64 */ + { 196, 0, 166}, /* 17: select shift 166 */ + { 157, 11, 172}, /* 18: expr shift 172 */ + { 158, 0, 219}, /* 19: expritem shift 219 */ + { 159, 13, 215}, /* 20: exprlist shift 215 */ +/* State 166 */ + { 180, 0, 71}, /* 1: multiselect_op shift 71 */ + { 121, 3, 167}, /* 2: UNION shift 167 */ + { 46, 0, 170}, /* 3: EXCEPT shift 170 */ + { 69, 0, 169}, /* 4: INTERSECT shift 169 */ + { 104, 4, 171}, /* 5: RP shift 171 */ +/* State 167 */ + { 106, 2, 658}, /* 1: SELECT reduce 103 */ + { 4, 0, 168}, /* 2: ALL shift 168 */ +/* State 168 */ + { 106, 0, 659}, /* 1: SELECT reduce 104 */ +/* State 169 */ + { 106, 0, 660}, /* 1: SELECT reduce 105 */ +/* State 170 */ + { 106, 0, 661}, /* 1: SELECT reduce 106 */ +/* State 172 */ + { 84, 0, 123}, /* 1: NE shift 123 */ + { 85, 4, 137}, /* 2: NOT shift 137 */ + { 86, 0, 159}, /* 3: NOTNULL shift 159 */ + { 57, 0, 117}, /* 4: GT shift 117 */ + { 63, 0, 164}, /* 5: IN shift 164 */ + { 5, 0, 105}, /* 6: AND shift 105 */ + { 71, 0, 155}, /* 7: IS shift 155 */ + { 91, 5, 113}, /* 8: OR shift 113 */ + { 92, 0, 104}, /* 9: ORACLE_OUTER_JOIN shift 104 */ + { 177, 0, 135}, /* 10: likeop shift 135 */ + { 94, 0, 142}, /* 11: PLUS shift 142 */ + { 11, 0, 160}, /* 12: BETWEEN shift 160 */ + { 12, 0, 127}, /* 13: BITAND shift 127 */ + { 77, 0, 140}, /* 14: LIKE shift 140 */ + { 14, 0, 129}, /* 15: BITOR shift 129 */ + { 99, 7, 150}, /* 16: REM shift 150 */ + { 72, 0, 154}, /* 17: ISNULL shift 154 */ + { 45, 0, 125}, /* 18: EQ shift 125 */ + { 81, 20, 115}, /* 19: LT shift 115 */ + { 25, 0, 152}, /* 20: CONCAT shift 152 */ + { 76, 0, 119}, /* 21: LE shift 119 */ + { 105, 14, 133}, /* 22: RSHIFT shift 133 */ + { 83, 24, 144}, /* 23: MINUS shift 144 */ + { 55, 0, 141}, /* 24: GLOB shift 141 */ + { 80, 0, 131}, /* 25: LSHIFT shift 131 */ + { 109, 19, 148}, /* 26: SLASH shift 148 */ + { 54, 0, 121}, /* 27: GE shift 121 */ + { 111, 23, 146}, /* 28: STAR shift 146 */ +/* State 175 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 176}, /* 8: expr shift 176 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 176 */ + { 54, 0, 121}, /* 1: GE shift 121 */ + { 105, 0, 133}, /* 2: RSHIFT shift 133 */ + { 80, 1, 131}, /* 3: LSHIFT shift 131 */ + { 81, 5, 115}, /* 4: LT shift 115 */ + { 55, 0, 141}, /* 5: GLOB shift 141 */ + { 109, 10, 148}, /* 6: SLASH shift 148 */ + { 84, 0, 123}, /* 7: NE shift 123 */ + { 111, 11, 146}, /* 8: STAR shift 146 */ + { 86, 0, 159}, /* 9: NOTNULL shift 159 */ + { 83, 14, 144}, /* 10: MINUS shift 144 */ + { 85, 0, 137}, /* 11: NOT shift 137 */ + { 63, 16, 164}, /* 12: IN shift 164 */ + { 12, 0, 127}, /* 13: BITAND shift 127 */ + { 57, 0, 117}, /* 14: GT shift 117 */ + { 92, 18, 104}, /* 15: ORACLE_OUTER_JOIN shift 104 */ + { 11, 0, 160}, /* 16: BETWEEN shift 160 */ + { 94, 0, 142}, /* 17: PLUS shift 142 */ + { 14, 0, 129}, /* 18: BITOR shift 129 */ + { 45, 0, 125}, /* 19: EQ shift 125 */ + { 71, 19, 155}, /* 20: IS shift 155 */ + { 72, 0, 154}, /* 21: ISNULL shift 154 */ + { 177, 23, 135}, /* 22: likeop shift 135 */ + { 99, 0, 150}, /* 23: REM shift 150 */ + { 25, 0, 152}, /* 24: CONCAT shift 152 */ + { 76, 0, 119}, /* 25: LE shift 119 */ + { 77, 24, 140}, /* 26: LIKE shift 140 */ +/* State 177 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 178}, /* 8: expr shift 178 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 178 */ + { 92, 0, 104}, /* 1: ORACLE_OUTER_JOIN shift 104 */ + { 177, 0, 135}, /* 2: likeop shift 135 */ +/* State 179 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 180}, /* 8: expr shift 180 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 180 */ + { 92, 0, 104}, /* 1: ORACLE_OUTER_JOIN shift 104 */ + { 177, 0, 135}, /* 2: likeop shift 135 */ +/* State 181 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 182}, /* 8: expr shift 182 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 182 */ + { 92, 0, 104}, /* 1: ORACLE_OUTER_JOIN shift 104 */ + { 177, 0, 135}, /* 2: likeop shift 135 */ +/* State 183 */ + { 136, 2, 185}, /* 1: case_operand shift 185 */ + { 85, 4, 175}, /* 2: NOT shift 175 */ + { 87, 0, 106}, /* 3: NULL shift 106 */ + { 68, 6, 173}, /* 4: INTEGER shift 173 */ + { 157, 0, 184}, /* 5: expr shift 184 */ + { 17, 0, 183}, /* 6: CASE shift 183 */ + { 74, 0, 67}, /* 7: JOIN_KW shift 67 */ + { 113, 15, 66}, /* 8: STRING shift 66 */ + { 59, 0, 64}, /* 9: ID shift 64 */ + { 94, 0, 181}, /* 10: PLUS shift 181 */ + { 129, 0, 781}, /* 11: WHEN reduce 226 */ + { 181, 8, 107}, /* 12: nm shift 107 */ + { 97, 0, 193}, /* 13: RAISE shift 193 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 79, 0, 68}, /* 15: LP shift 68 */ + { 83, 17, 179}, /* 16: MINUS shift 179 */ + { 49, 0, 174}, /* 17: FLOAT shift 174 */ +/* State 184 */ + { 63, 2, 164}, /* 1: IN shift 164 */ + { 5, 0, 105}, /* 2: AND shift 105 */ + { 12, 0, 127}, /* 3: BITAND shift 127 */ + { 177, 0, 135}, /* 4: likeop shift 135 */ + { 91, 0, 113}, /* 5: OR shift 113 */ + { 92, 1, 104}, /* 6: ORACLE_OUTER_JOIN shift 104 */ + { 71, 0, 155}, /* 7: IS shift 155 */ + { 94, 0, 142}, /* 8: PLUS shift 142 */ + { 14, 0, 129}, /* 9: BITOR shift 129 */ + { 76, 0, 119}, /* 10: LE shift 119 */ + { 80, 0, 131}, /* 11: LSHIFT shift 131 */ + { 11, 0, 160}, /* 12: BETWEEN shift 160 */ + { 99, 3, 150}, /* 13: REM shift 150 */ + { 129, 7, 780}, /* 14: WHEN reduce 225 */ + { 72, 9, 154}, /* 15: ISNULL shift 154 */ + { 54, 18, 121}, /* 16: GE shift 121 */ + { 45, 0, 125}, /* 17: EQ shift 125 */ + { 25, 0, 152}, /* 18: CONCAT shift 152 */ + { 105, 10, 133}, /* 19: RSHIFT shift 133 */ + { 77, 0, 140}, /* 20: LIKE shift 140 */ + { 55, 0, 141}, /* 21: GLOB shift 141 */ + { 57, 0, 117}, /* 22: GT shift 117 */ + { 109, 11, 148}, /* 23: SLASH shift 148 */ + { 81, 0, 115}, /* 24: LT shift 115 */ + { 111, 0, 146}, /* 25: STAR shift 146 */ + { 83, 16, 144}, /* 26: MINUS shift 144 */ + { 84, 21, 123}, /* 27: NE shift 123 */ + { 85, 0, 137}, /* 28: NOT shift 137 */ + { 86, 22, 159}, /* 29: NOTNULL shift 159 */ +/* State 185 */ + { 129, 0, 211}, /* 1: WHEN shift 211 */ + { 135, 1, 186}, /* 2: case_exprlist shift 186 */ +/* State 186 */ + { 42, 0, 209}, /* 1: ELSE shift 209 */ + { 129, 0, 189}, /* 2: WHEN shift 189 */ + { 134, 1, 187}, /* 3: case_else shift 187 */ + { 43, 0, 779}, /* 4: END reduce 224 */ +/* State 187 */ + { 43, 0, 188}, /* 1: END shift 188 */ +/* State 189 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 190}, /* 8: expr shift 190 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 190 */ + { 116, 0, 191}, /* 1: THEN shift 191 */ + { 63, 3, 164}, /* 2: IN shift 164 */ + { 5, 0, 105}, /* 3: AND shift 105 */ + { 177, 0, 135}, /* 4: likeop shift 135 */ + { 91, 0, 113}, /* 5: OR shift 113 */ + { 92, 2, 104}, /* 6: ORACLE_OUTER_JOIN shift 104 */ + { 12, 0, 127}, /* 7: BITAND shift 127 */ + { 94, 0, 142}, /* 8: PLUS shift 142 */ + { 14, 0, 129}, /* 9: BITOR shift 129 */ + { 76, 0, 119}, /* 10: LE shift 119 */ + { 80, 0, 131}, /* 11: LSHIFT shift 131 */ + { 11, 0, 160}, /* 12: BETWEEN shift 160 */ + { 99, 7, 150}, /* 13: REM shift 150 */ + { 71, 0, 155}, /* 14: IS shift 155 */ + { 72, 9, 154}, /* 15: ISNULL shift 154 */ + { 54, 18, 121}, /* 16: GE shift 121 */ + { 45, 0, 125}, /* 17: EQ shift 125 */ + { 25, 0, 152}, /* 18: CONCAT shift 152 */ + { 105, 10, 133}, /* 19: RSHIFT shift 133 */ + { 77, 0, 140}, /* 20: LIKE shift 140 */ + { 55, 0, 141}, /* 21: GLOB shift 141 */ + { 57, 0, 117}, /* 22: GT shift 117 */ + { 109, 11, 148}, /* 23: SLASH shift 148 */ + { 81, 0, 115}, /* 24: LT shift 115 */ + { 111, 0, 146}, /* 25: STAR shift 146 */ + { 83, 16, 144}, /* 26: MINUS shift 144 */ + { 84, 21, 123}, /* 27: NE shift 123 */ + { 85, 0, 137}, /* 28: NOT shift 137 */ + { 86, 22, 159}, /* 29: NOTNULL shift 159 */ +/* State 191 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 192}, /* 8: expr shift 192 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 192 */ + { 84, 0, 123}, /* 1: NE shift 123 */ + { 85, 4, 137}, /* 2: NOT shift 137 */ + { 86, 0, 159}, /* 3: NOTNULL shift 159 */ + { 57, 0, 117}, /* 4: GT shift 117 */ + { 63, 0, 164}, /* 5: IN shift 164 */ + { 5, 0, 105}, /* 6: AND shift 105 */ + { 71, 0, 155}, /* 7: IS shift 155 */ + { 91, 5, 113}, /* 8: OR shift 113 */ + { 92, 0, 104}, /* 9: ORACLE_OUTER_JOIN shift 104 */ + { 177, 0, 135}, /* 10: likeop shift 135 */ + { 94, 0, 142}, /* 11: PLUS shift 142 */ + { 11, 0, 160}, /* 12: BETWEEN shift 160 */ + { 12, 0, 127}, /* 13: BITAND shift 127 */ + { 77, 0, 140}, /* 14: LIKE shift 140 */ + { 14, 0, 129}, /* 15: BITOR shift 129 */ + { 99, 7, 150}, /* 16: REM shift 150 */ + { 72, 0, 154}, /* 17: ISNULL shift 154 */ + { 45, 0, 125}, /* 18: EQ shift 125 */ + { 81, 20, 115}, /* 19: LT shift 115 */ + { 25, 0, 152}, /* 20: CONCAT shift 152 */ + { 76, 0, 119}, /* 21: LE shift 119 */ + { 105, 14, 133}, /* 22: RSHIFT shift 133 */ + { 83, 24, 144}, /* 23: MINUS shift 144 */ + { 55, 0, 141}, /* 24: GLOB shift 141 */ + { 80, 0, 131}, /* 25: LSHIFT shift 131 */ + { 109, 19, 148}, /* 26: SLASH shift 148 */ + { 54, 0, 121}, /* 27: GE shift 121 */ + { 111, 23, 146}, /* 28: STAR shift 146 */ +/* State 193 */ + { 79, 0, 194}, /* 1: LP shift 194 */ +/* State 194 */ + { 60, 4, 195}, /* 1: IGNORE shift 195 */ + { 1, 0, 201}, /* 2: ABORT shift 201 */ + { 102, 0, 197}, /* 3: ROLLBACK shift 197 */ + { 48, 0, 205}, /* 4: FAIL shift 205 */ +/* State 195 */ + { 104, 0, 196}, /* 1: RP shift 196 */ +/* State 197 */ + { 22, 0, 198}, /* 1: COMMA shift 198 */ +/* State 198 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 199}, /* 2: nm shift 199 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 199 */ + { 104, 0, 200}, /* 1: RP shift 200 */ +/* State 201 */ + { 22, 0, 202}, /* 1: COMMA shift 202 */ +/* State 202 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 203}, /* 2: nm shift 203 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 203 */ + { 104, 0, 204}, /* 1: RP shift 204 */ +/* State 205 */ + { 22, 0, 206}, /* 1: COMMA shift 206 */ +/* State 206 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 207}, /* 2: nm shift 207 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 207 */ + { 104, 0, 208}, /* 1: RP shift 208 */ +/* State 209 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 210}, /* 8: expr shift 210 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 210 */ + { 63, 2, 164}, /* 1: IN shift 164 */ + { 5, 0, 105}, /* 2: AND shift 105 */ + { 12, 0, 127}, /* 3: BITAND shift 127 */ + { 177, 0, 135}, /* 4: likeop shift 135 */ + { 91, 0, 113}, /* 5: OR shift 113 */ + { 92, 1, 104}, /* 6: ORACLE_OUTER_JOIN shift 104 */ + { 43, 9, 778}, /* 7: END reduce 223 */ + { 94, 0, 142}, /* 8: PLUS shift 142 */ + { 14, 0, 129}, /* 9: BITOR shift 129 */ + { 76, 0, 119}, /* 10: LE shift 119 */ + { 80, 0, 131}, /* 11: LSHIFT shift 131 */ + { 11, 0, 160}, /* 12: BETWEEN shift 160 */ + { 99, 3, 150}, /* 13: REM shift 150 */ + { 71, 0, 155}, /* 14: IS shift 155 */ + { 72, 7, 154}, /* 15: ISNULL shift 154 */ + { 54, 18, 121}, /* 16: GE shift 121 */ + { 45, 0, 125}, /* 17: EQ shift 125 */ + { 25, 0, 152}, /* 18: CONCAT shift 152 */ + { 105, 10, 133}, /* 19: RSHIFT shift 133 */ + { 77, 0, 140}, /* 20: LIKE shift 140 */ + { 55, 0, 141}, /* 21: GLOB shift 141 */ + { 57, 0, 117}, /* 22: GT shift 117 */ + { 109, 11, 148}, /* 23: SLASH shift 148 */ + { 81, 0, 115}, /* 24: LT shift 115 */ + { 111, 0, 146}, /* 25: STAR shift 146 */ + { 83, 16, 144}, /* 26: MINUS shift 144 */ + { 84, 21, 123}, /* 27: NE shift 123 */ + { 85, 0, 137}, /* 28: NOT shift 137 */ + { 86, 22, 159}, /* 29: NOTNULL shift 159 */ +/* State 211 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 212}, /* 8: expr shift 212 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 212 */ + { 116, 0, 213}, /* 1: THEN shift 213 */ + { 63, 3, 164}, /* 2: IN shift 164 */ + { 5, 0, 105}, /* 3: AND shift 105 */ + { 177, 0, 135}, /* 4: likeop shift 135 */ + { 91, 0, 113}, /* 5: OR shift 113 */ + { 92, 2, 104}, /* 6: ORACLE_OUTER_JOIN shift 104 */ + { 12, 0, 127}, /* 7: BITAND shift 127 */ + { 94, 0, 142}, /* 8: PLUS shift 142 */ + { 14, 0, 129}, /* 9: BITOR shift 129 */ + { 76, 0, 119}, /* 10: LE shift 119 */ + { 80, 0, 131}, /* 11: LSHIFT shift 131 */ + { 11, 0, 160}, /* 12: BETWEEN shift 160 */ + { 99, 7, 150}, /* 13: REM shift 150 */ + { 71, 0, 155}, /* 14: IS shift 155 */ + { 72, 9, 154}, /* 15: ISNULL shift 154 */ + { 54, 18, 121}, /* 16: GE shift 121 */ + { 45, 0, 125}, /* 17: EQ shift 125 */ + { 25, 0, 152}, /* 18: CONCAT shift 152 */ + { 105, 10, 133}, /* 19: RSHIFT shift 133 */ + { 77, 0, 140}, /* 20: LIKE shift 140 */ + { 55, 0, 141}, /* 21: GLOB shift 141 */ + { 57, 0, 117}, /* 22: GT shift 117 */ + { 109, 11, 148}, /* 23: SLASH shift 148 */ + { 81, 0, 115}, /* 24: LT shift 115 */ + { 111, 0, 146}, /* 25: STAR shift 146 */ + { 83, 16, 144}, /* 26: MINUS shift 144 */ + { 84, 21, 123}, /* 27: NE shift 123 */ + { 85, 0, 137}, /* 28: NOT shift 137 */ + { 86, 22, 159}, /* 29: NOTNULL shift 159 */ +/* State 213 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 214}, /* 8: expr shift 214 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 214 */ + { 84, 0, 123}, /* 1: NE shift 123 */ + { 85, 4, 137}, /* 2: NOT shift 137 */ + { 86, 0, 159}, /* 3: NOTNULL shift 159 */ + { 57, 0, 117}, /* 4: GT shift 117 */ + { 63, 0, 164}, /* 5: IN shift 164 */ + { 5, 0, 105}, /* 6: AND shift 105 */ + { 71, 0, 155}, /* 7: IS shift 155 */ + { 91, 5, 113}, /* 8: OR shift 113 */ + { 92, 0, 104}, /* 9: ORACLE_OUTER_JOIN shift 104 */ + { 177, 0, 135}, /* 10: likeop shift 135 */ + { 94, 0, 142}, /* 11: PLUS shift 142 */ + { 11, 0, 160}, /* 12: BETWEEN shift 160 */ + { 12, 0, 127}, /* 13: BITAND shift 127 */ + { 77, 0, 140}, /* 14: LIKE shift 140 */ + { 14, 0, 129}, /* 15: BITOR shift 129 */ + { 99, 7, 150}, /* 16: REM shift 150 */ + { 72, 0, 154}, /* 17: ISNULL shift 154 */ + { 45, 0, 125}, /* 18: EQ shift 125 */ + { 81, 20, 115}, /* 19: LT shift 115 */ + { 25, 0, 152}, /* 20: CONCAT shift 152 */ + { 76, 0, 119}, /* 21: LE shift 119 */ + { 105, 14, 133}, /* 22: RSHIFT shift 133 */ + { 83, 24, 144}, /* 23: MINUS shift 144 */ + { 55, 0, 141}, /* 24: GLOB shift 141 */ + { 80, 0, 131}, /* 25: LSHIFT shift 131 */ + { 109, 19, 148}, /* 26: SLASH shift 148 */ + { 54, 0, 121}, /* 27: GE shift 121 */ + { 111, 23, 146}, /* 28: STAR shift 146 */ +/* State 215 */ + { 104, 2, 216}, /* 1: RP shift 216 */ + { 22, 0, 217}, /* 2: COMMA shift 217 */ +/* State 217 */ + { 97, 3, 193}, /* 1: RAISE shift 193 */ + { 113, 1, 66}, /* 2: STRING shift 66 */ + { 49, 7, 174}, /* 3: FLOAT shift 174 */ + { 83, 0, 179}, /* 4: MINUS shift 179 */ + { 68, 0, 173}, /* 5: INTEGER shift 173 */ + { 181, 9, 107}, /* 6: nm shift 107 */ + { 17, 0, 183}, /* 7: CASE shift 183 */ + { 87, 0, 106}, /* 8: NULL shift 106 */ + { 85, 0, 175}, /* 9: NOT shift 175 */ + { 13, 0, 177}, /* 10: BITNOT shift 177 */ + { 74, 0, 67}, /* 11: JOIN_KW shift 67 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 94, 0, 181}, /* 13: PLUS shift 181 */ + { 157, 10, 172}, /* 14: expr shift 172 */ + { 158, 13, 218}, /* 15: expritem shift 218 */ + { 79, 0, 68}, /* 16: LP shift 68 */ +/* State 221 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 222}, /* 8: expr shift 222 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 222 */ + { 84, 0, 123}, /* 1: NE shift 123 */ + { 85, 4, 137}, /* 2: NOT shift 137 */ + { 86, 0, 159}, /* 3: NOTNULL shift 159 */ + { 57, 0, 117}, /* 4: GT shift 117 */ + { 63, 0, 164}, /* 5: IN shift 164 */ + { 5, 0, 223}, /* 6: AND shift 223 */ + { 71, 0, 155}, /* 7: IS shift 155 */ + { 91, 5, 113}, /* 8: OR shift 113 */ + { 92, 0, 104}, /* 9: ORACLE_OUTER_JOIN shift 104 */ + { 177, 0, 135}, /* 10: likeop shift 135 */ + { 94, 0, 142}, /* 11: PLUS shift 142 */ + { 11, 0, 160}, /* 12: BETWEEN shift 160 */ + { 12, 0, 127}, /* 13: BITAND shift 127 */ + { 77, 0, 140}, /* 14: LIKE shift 140 */ + { 14, 0, 129}, /* 15: BITOR shift 129 */ + { 99, 7, 150}, /* 16: REM shift 150 */ + { 72, 0, 154}, /* 17: ISNULL shift 154 */ + { 45, 0, 125}, /* 18: EQ shift 125 */ + { 81, 20, 115}, /* 19: LT shift 115 */ + { 25, 0, 152}, /* 20: CONCAT shift 152 */ + { 76, 0, 119}, /* 21: LE shift 119 */ + { 105, 14, 133}, /* 22: RSHIFT shift 133 */ + { 83, 24, 144}, /* 23: MINUS shift 144 */ + { 55, 0, 141}, /* 24: GLOB shift 141 */ + { 80, 0, 131}, /* 25: LSHIFT shift 131 */ + { 109, 19, 148}, /* 26: SLASH shift 148 */ + { 54, 0, 121}, /* 27: GE shift 121 */ + { 111, 23, 146}, /* 28: STAR shift 146 */ +/* State 223 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 224}, /* 8: expr shift 224 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 224 */ + { 54, 0, 121}, /* 1: GE shift 121 */ + { 105, 0, 133}, /* 2: RSHIFT shift 133 */ + { 80, 1, 131}, /* 3: LSHIFT shift 131 */ + { 81, 5, 115}, /* 4: LT shift 115 */ + { 55, 0, 141}, /* 5: GLOB shift 141 */ + { 109, 10, 148}, /* 6: SLASH shift 148 */ + { 84, 0, 123}, /* 7: NE shift 123 */ + { 111, 11, 146}, /* 8: STAR shift 146 */ + { 86, 0, 159}, /* 9: NOTNULL shift 159 */ + { 83, 14, 144}, /* 10: MINUS shift 144 */ + { 85, 0, 137}, /* 11: NOT shift 137 */ + { 63, 16, 164}, /* 12: IN shift 164 */ + { 12, 0, 127}, /* 13: BITAND shift 127 */ + { 57, 0, 117}, /* 14: GT shift 117 */ + { 92, 18, 104}, /* 15: ORACLE_OUTER_JOIN shift 104 */ + { 11, 0, 160}, /* 16: BETWEEN shift 160 */ + { 94, 0, 142}, /* 17: PLUS shift 142 */ + { 14, 0, 129}, /* 18: BITOR shift 129 */ + { 45, 0, 125}, /* 19: EQ shift 125 */ + { 71, 19, 155}, /* 20: IS shift 155 */ + { 72, 0, 154}, /* 21: ISNULL shift 154 */ + { 177, 23, 135}, /* 22: likeop shift 135 */ + { 99, 0, 150}, /* 23: REM shift 150 */ + { 25, 0, 152}, /* 24: CONCAT shift 152 */ + { 76, 0, 119}, /* 25: LE shift 119 */ + { 77, 24, 140}, /* 26: LIKE shift 140 */ +/* State 225 */ + { 79, 0, 226}, /* 1: LP shift 226 */ +/* State 226 */ + { 85, 0, 175}, /* 1: NOT shift 175 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 13, 0, 177}, /* 3: BITNOT shift 177 */ + { 83, 0, 179}, /* 4: MINUS shift 179 */ + { 74, 0, 67}, /* 5: JOIN_KW shift 67 */ + { 185, 1, 69}, /* 6: oneselect shift 69 */ + { 106, 0, 73}, /* 7: SELECT shift 73 */ + { 87, 0, 106}, /* 8: NULL shift 106 */ + { 68, 0, 173}, /* 9: INTEGER shift 173 */ + { 49, 0, 174}, /* 10: FLOAT shift 174 */ + { 97, 12, 193}, /* 11: RAISE shift 193 */ + { 17, 0, 183}, /* 12: CASE shift 183 */ + { 79, 16, 68}, /* 13: LP shift 68 */ + { 113, 3, 66}, /* 14: STRING shift 66 */ + { 94, 5, 181}, /* 15: PLUS shift 181 */ + { 59, 0, 64}, /* 16: ID shift 64 */ + { 196, 0, 227}, /* 17: select shift 227 */ + { 157, 11, 172}, /* 18: expr shift 172 */ + { 158, 0, 219}, /* 19: expritem shift 219 */ + { 159, 13, 229}, /* 20: exprlist shift 229 */ +/* State 227 */ + { 180, 0, 71}, /* 1: multiselect_op shift 71 */ + { 121, 3, 167}, /* 2: UNION shift 167 */ + { 46, 0, 170}, /* 3: EXCEPT shift 170 */ + { 69, 0, 169}, /* 4: INTERSECT shift 169 */ + { 104, 4, 228}, /* 5: RP shift 228 */ +/* State 229 */ + { 104, 2, 230}, /* 1: RP shift 230 */ + { 22, 0, 217}, /* 2: COMMA shift 217 */ +/* State 231 */ + { 20, 0, 100}, /* 1: COLLATE shift 100 */ + { 141, 0, 232}, /* 2: collate shift 232 */ +/* State 232 */ + { 36, 0, 59}, /* 1: DESC shift 59 */ + { 202, 3, 233}, /* 2: sortorder shift 233 */ + { 7, 0, 58}, /* 3: ASC shift 58 */ +/* State 234 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 235}, /* 8: expr shift 235 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 235 */ + { 84, 0, 123}, /* 1: NE shift 123 */ + { 85, 4, 137}, /* 2: NOT shift 137 */ + { 86, 0, 159}, /* 3: NOTNULL shift 159 */ + { 57, 0, 117}, /* 4: GT shift 117 */ + { 63, 0, 164}, /* 5: IN shift 164 */ + { 5, 0, 105}, /* 6: AND shift 105 */ + { 71, 0, 155}, /* 7: IS shift 155 */ + { 91, 5, 113}, /* 8: OR shift 113 */ + { 92, 0, 104}, /* 9: ORACLE_OUTER_JOIN shift 104 */ + { 177, 0, 135}, /* 10: likeop shift 135 */ + { 94, 0, 142}, /* 11: PLUS shift 142 */ + { 11, 0, 160}, /* 12: BETWEEN shift 160 */ + { 12, 0, 127}, /* 13: BITAND shift 127 */ + { 77, 0, 140}, /* 14: LIKE shift 140 */ + { 14, 0, 129}, /* 15: BITOR shift 129 */ + { 99, 7, 150}, /* 16: REM shift 150 */ + { 72, 0, 154}, /* 17: ISNULL shift 154 */ + { 45, 0, 125}, /* 18: EQ shift 125 */ + { 81, 20, 115}, /* 19: LT shift 115 */ + { 25, 0, 152}, /* 20: CONCAT shift 152 */ + { 76, 0, 119}, /* 21: LE shift 119 */ + { 105, 14, 133}, /* 22: RSHIFT shift 133 */ + { 83, 24, 144}, /* 23: MINUS shift 144 */ + { 55, 0, 141}, /* 24: GLOB shift 141 */ + { 80, 0, 131}, /* 25: LSHIFT shift 131 */ + { 109, 19, 148}, /* 26: SLASH shift 148 */ + { 54, 0, 121}, /* 27: GE shift 121 */ + { 111, 23, 146}, /* 28: STAR shift 146 */ +/* State 236 */ + { 15, 0, 237}, /* 1: BY shift 237 */ +/* State 237 */ + { 85, 2, 175}, /* 1: NOT shift 175 */ + { 68, 4, 173}, /* 2: INTEGER shift 173 */ + { 87, 0, 106}, /* 3: NULL shift 106 */ + { 17, 0, 183}, /* 4: CASE shift 183 */ + { 157, 0, 172}, /* 5: expr shift 172 */ + { 158, 0, 219}, /* 6: expritem shift 219 */ + { 159, 8, 238}, /* 7: exprlist shift 238 */ + { 74, 0, 67}, /* 8: JOIN_KW shift 67 */ + { 59, 0, 64}, /* 9: ID shift 64 */ + { 94, 0, 181}, /* 10: PLUS shift 181 */ + { 113, 15, 66}, /* 11: STRING shift 66 */ + { 181, 11, 107}, /* 12: nm shift 107 */ + { 97, 0, 193}, /* 13: RAISE shift 193 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 79, 0, 68}, /* 15: LP shift 68 */ + { 83, 17, 179}, /* 16: MINUS shift 179 */ + { 49, 0, 174}, /* 17: FLOAT shift 174 */ +/* State 238 */ + { 22, 0, 217}, /* 1: COMMA shift 217 */ +/* State 239 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 240}, /* 8: expr shift 240 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 240 */ + { 84, 0, 123}, /* 1: NE shift 123 */ + { 85, 4, 137}, /* 2: NOT shift 137 */ + { 86, 0, 159}, /* 3: NOTNULL shift 159 */ + { 57, 0, 117}, /* 4: GT shift 117 */ + { 63, 0, 164}, /* 5: IN shift 164 */ + { 5, 0, 105}, /* 6: AND shift 105 */ + { 71, 0, 155}, /* 7: IS shift 155 */ + { 91, 5, 113}, /* 8: OR shift 113 */ + { 92, 0, 104}, /* 9: ORACLE_OUTER_JOIN shift 104 */ + { 177, 0, 135}, /* 10: likeop shift 135 */ + { 94, 0, 142}, /* 11: PLUS shift 142 */ + { 11, 0, 160}, /* 12: BETWEEN shift 160 */ + { 12, 0, 127}, /* 13: BITAND shift 127 */ + { 77, 0, 140}, /* 14: LIKE shift 140 */ + { 14, 0, 129}, /* 15: BITOR shift 129 */ + { 99, 7, 150}, /* 16: REM shift 150 */ + { 72, 0, 154}, /* 17: ISNULL shift 154 */ + { 45, 0, 125}, /* 18: EQ shift 125 */ + { 81, 20, 115}, /* 19: LT shift 115 */ + { 25, 0, 152}, /* 20: CONCAT shift 152 */ + { 76, 0, 119}, /* 21: LE shift 119 */ + { 105, 14, 133}, /* 22: RSHIFT shift 133 */ + { 83, 24, 144}, /* 23: MINUS shift 144 */ + { 55, 0, 141}, /* 24: GLOB shift 141 */ + { 80, 0, 131}, /* 25: LSHIFT shift 131 */ + { 109, 19, 148}, /* 26: SLASH shift 148 */ + { 54, 0, 121}, /* 27: GE shift 121 */ + { 111, 23, 146}, /* 28: STAR shift 146 */ +/* State 242 */ + { 197, 0, 243}, /* 1: seltablist shift 243 */ + { 203, 1, 253}, /* 2: stl_prefix shift 253 */ +/* State 243 */ + { 22, 0, 245}, /* 1: COMMA shift 245 */ + { 73, 0, 246}, /* 2: JOIN shift 246 */ + { 74, 1, 247}, /* 3: JOIN_KW shift 247 */ + { 175, 0, 244}, /* 4: joinop shift 244 */ +/* State 247 */ + { 73, 0, 248}, /* 1: JOIN shift 248 */ + { 181, 0, 249}, /* 2: nm shift 249 */ + { 59, 0, 20}, /* 3: ID shift 20 */ + { 113, 1, 21}, /* 4: STRING shift 21 */ + { 74, 3, 22}, /* 5: JOIN_KW shift 22 */ +/* State 249 */ + { 73, 0, 250}, /* 1: JOIN shift 250 */ + { 181, 0, 251}, /* 2: nm shift 251 */ + { 59, 0, 20}, /* 3: ID shift 20 */ + { 113, 1, 21}, /* 4: STRING shift 21 */ + { 74, 3, 22}, /* 5: JOIN_KW shift 22 */ +/* State 251 */ + { 73, 0, 252}, /* 1: JOIN shift 252 */ +/* State 253 */ + { 74, 3, 22}, /* 1: JOIN_KW shift 22 */ + { 181, 0, 254}, /* 2: nm shift 254 */ + { 59, 0, 20}, /* 3: ID shift 20 */ + { 113, 0, 21}, /* 4: STRING shift 21 */ + { 79, 1, 277}, /* 5: LP shift 277 */ +/* State 254 */ + { 150, 0, 255}, /* 1: dbnm shift 255 */ + { 39, 0, 275}, /* 2: DOT shift 275 */ +/* State 255 */ + { 165, 0, 260}, /* 1: ids shift 260 */ + { 131, 3, 261}, /* 2: as shift 261 */ + { 6, 0, 258}, /* 3: AS shift 258 */ + { 113, 0, 257}, /* 4: STRING shift 257 */ + { 59, 0, 256}, /* 5: ID shift 256 */ +/* State 258 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 259}, /* 2: nm shift 259 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 261 */ + { 90, 0, 273}, /* 1: ON shift 273 */ + { 183, 0, 262}, /* 2: on_opt shift 262 */ +/* State 262 */ + { 125, 0, 264}, /* 1: USING shift 264 */ + { 215, 1, 263}, /* 2: using_opt shift 263 */ +/* State 264 */ + { 79, 0, 265}, /* 1: LP shift 265 */ +/* State 265 */ + { 113, 4, 21}, /* 1: STRING shift 21 */ + { 181, 0, 270}, /* 2: nm shift 270 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ + { 166, 0, 272}, /* 5: idxitem shift 272 */ + { 167, 1, 266}, /* 6: idxlist shift 266 */ +/* State 266 */ + { 104, 2, 267}, /* 1: RP shift 267 */ + { 22, 0, 268}, /* 2: COMMA shift 268 */ +/* State 268 */ + { 166, 0, 269}, /* 1: idxitem shift 269 */ + { 181, 1, 270}, /* 2: nm shift 270 */ + { 59, 0, 20}, /* 3: ID shift 20 */ + { 113, 0, 21}, /* 4: STRING shift 21 */ + { 74, 3, 22}, /* 5: JOIN_KW shift 22 */ +/* State 270 */ + { 36, 0, 59}, /* 1: DESC shift 59 */ + { 202, 3, 271}, /* 2: sortorder shift 271 */ + { 7, 0, 58}, /* 3: ASC shift 58 */ +/* State 273 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 274}, /* 8: expr shift 274 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 274 */ + { 84, 0, 123}, /* 1: NE shift 123 */ + { 85, 4, 137}, /* 2: NOT shift 137 */ + { 86, 0, 159}, /* 3: NOTNULL shift 159 */ + { 57, 0, 117}, /* 4: GT shift 117 */ + { 63, 0, 164}, /* 5: IN shift 164 */ + { 5, 0, 105}, /* 6: AND shift 105 */ + { 71, 0, 155}, /* 7: IS shift 155 */ + { 91, 5, 113}, /* 8: OR shift 113 */ + { 92, 0, 104}, /* 9: ORACLE_OUTER_JOIN shift 104 */ + { 177, 0, 135}, /* 10: likeop shift 135 */ + { 94, 0, 142}, /* 11: PLUS shift 142 */ + { 11, 0, 160}, /* 12: BETWEEN shift 160 */ + { 12, 0, 127}, /* 13: BITAND shift 127 */ + { 77, 0, 140}, /* 14: LIKE shift 140 */ + { 14, 0, 129}, /* 15: BITOR shift 129 */ + { 99, 7, 150}, /* 16: REM shift 150 */ + { 72, 0, 154}, /* 17: ISNULL shift 154 */ + { 45, 0, 125}, /* 18: EQ shift 125 */ + { 81, 20, 115}, /* 19: LT shift 115 */ + { 25, 0, 152}, /* 20: CONCAT shift 152 */ + { 76, 0, 119}, /* 21: LE shift 119 */ + { 105, 14, 133}, /* 22: RSHIFT shift 133 */ + { 83, 24, 144}, /* 23: MINUS shift 144 */ + { 55, 0, 141}, /* 24: GLOB shift 141 */ + { 80, 0, 131}, /* 25: LSHIFT shift 131 */ + { 109, 19, 148}, /* 26: SLASH shift 148 */ + { 54, 0, 121}, /* 27: GE shift 121 */ + { 111, 23, 146}, /* 28: STAR shift 146 */ +/* State 275 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 276}, /* 2: nm shift 276 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 277 */ + { 106, 0, 73}, /* 1: SELECT shift 73 */ + { 196, 1, 278}, /* 2: select shift 278 */ + { 185, 0, 69}, /* 3: oneselect shift 69 */ +/* State 278 */ + { 180, 0, 71}, /* 1: multiselect_op shift 71 */ + { 121, 3, 167}, /* 2: UNION shift 167 */ + { 46, 0, 170}, /* 3: EXCEPT shift 170 */ + { 69, 0, 169}, /* 4: INTERSECT shift 169 */ + { 104, 4, 279}, /* 5: RP shift 279 */ +/* State 279 */ + { 165, 0, 260}, /* 1: ids shift 260 */ + { 131, 3, 280}, /* 2: as shift 280 */ + { 6, 0, 258}, /* 3: AS shift 258 */ + { 113, 0, 257}, /* 4: STRING shift 257 */ + { 59, 0, 256}, /* 5: ID shift 256 */ +/* State 280 */ + { 90, 0, 273}, /* 1: ON shift 273 */ + { 183, 0, 281}, /* 2: on_opt shift 281 */ +/* State 281 */ + { 125, 0, 264}, /* 1: USING shift 264 */ + { 215, 1, 282}, /* 2: using_opt shift 282 */ +/* State 283 */ + { 97, 3, 193}, /* 1: RAISE shift 193 */ + { 113, 1, 66}, /* 2: STRING shift 66 */ + { 49, 7, 174}, /* 3: FLOAT shift 174 */ + { 83, 0, 179}, /* 4: MINUS shift 179 */ + { 68, 0, 173}, /* 5: INTEGER shift 173 */ + { 181, 9, 287}, /* 6: nm shift 287 */ + { 17, 0, 183}, /* 7: CASE shift 183 */ + { 87, 0, 106}, /* 8: NULL shift 106 */ + { 85, 0, 175}, /* 9: NOT shift 175 */ + { 13, 0, 177}, /* 10: BITNOT shift 177 */ + { 74, 0, 67}, /* 11: JOIN_KW shift 67 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 79, 0, 68}, /* 13: LP shift 68 */ + { 157, 10, 284}, /* 14: expr shift 284 */ + { 94, 0, 181}, /* 15: PLUS shift 181 */ + { 111, 13, 286}, /* 16: STAR shift 286 */ +/* State 284 */ + { 165, 2, 260}, /* 1: ids shift 260 */ + { 99, 0, 150}, /* 2: REM shift 150 */ + { 5, 0, 105}, /* 3: AND shift 105 */ + { 72, 5, 154}, /* 4: ISNULL shift 154 */ + { 6, 0, 258}, /* 5: AS shift 258 */ + { 71, 3, 155}, /* 6: IS shift 155 */ + { 105, 4, 133}, /* 7: RSHIFT shift 133 */ + { 76, 0, 119}, /* 8: LE shift 119 */ + { 11, 0, 160}, /* 9: BETWEEN shift 160 */ + { 111, 14, 146}, /* 10: STAR shift 146 */ + { 109, 8, 148}, /* 11: SLASH shift 148 */ + { 77, 9, 140}, /* 12: LIKE shift 140 */ + { 177, 10, 135}, /* 13: likeop shift 135 */ + { 45, 17, 125}, /* 14: EQ shift 125 */ + { 113, 24, 257}, /* 15: STRING shift 257 */ + { 81, 0, 115}, /* 16: LT shift 115 */ + { 12, 0, 127}, /* 17: BITAND shift 127 */ + { 83, 0, 144}, /* 18: MINUS shift 144 */ + { 84, 0, 123}, /* 19: NE shift 123 */ + { 85, 0, 137}, /* 20: NOT shift 137 */ + { 86, 0, 159}, /* 21: NOTNULL shift 159 */ + { 54, 0, 121}, /* 22: GE shift 121 */ + { 55, 0, 141}, /* 23: GLOB shift 141 */ + { 80, 28, 131}, /* 24: LSHIFT shift 131 */ + { 57, 0, 117}, /* 25: GT shift 117 */ + { 91, 30, 113}, /* 26: OR shift 113 */ + { 92, 32, 104}, /* 27: ORACLE_OUTER_JOIN shift 104 */ + { 14, 0, 129}, /* 28: BITOR shift 129 */ + { 94, 0, 142}, /* 29: PLUS shift 142 */ + { 25, 0, 152}, /* 30: CONCAT shift 152 */ + { 63, 0, 164}, /* 31: IN shift 164 */ + { 59, 0, 256}, /* 32: ID shift 256 */ + { 131, 0, 285}, /* 33: as shift 285 */ +/* State 287 */ + { 39, 0, 288}, /* 1: DOT shift 288 */ +/* State 288 */ + { 111, 0, 289}, /* 1: STAR shift 289 */ + { 181, 1, 109}, /* 2: nm shift 109 */ + { 59, 0, 20}, /* 3: ID shift 20 */ + { 113, 0, 21}, /* 4: STRING shift 21 */ + { 74, 3, 22}, /* 5: JOIN_KW shift 22 */ +/* State 293 */ + { 63, 2, 164}, /* 1: IN shift 164 */ + { 5, 0, 105}, /* 2: AND shift 105 */ + { 12, 0, 127}, /* 3: BITAND shift 127 */ + { 177, 0, 135}, /* 4: likeop shift 135 */ + { 91, 0, 113}, /* 5: OR shift 113 */ + { 92, 1, 104}, /* 6: ORACLE_OUTER_JOIN shift 104 */ + { 14, 0, 129}, /* 7: BITOR shift 129 */ + { 94, 0, 142}, /* 8: PLUS shift 142 */ + { 76, 0, 119}, /* 9: LE shift 119 */ + { 80, 0, 131}, /* 10: LSHIFT shift 131 */ + { 54, 16, 121}, /* 11: GE shift 121 */ + { 11, 0, 160}, /* 12: BETWEEN shift 160 */ + { 99, 3, 150}, /* 13: REM shift 150 */ + { 71, 0, 155}, /* 14: IS shift 155 */ + { 72, 7, 154}, /* 15: ISNULL shift 154 */ + { 25, 0, 152}, /* 16: CONCAT shift 152 */ + { 45, 0, 125}, /* 17: EQ shift 125 */ + { 104, 0, 294}, /* 18: RP shift 294 */ + { 105, 9, 133}, /* 19: RSHIFT shift 133 */ + { 77, 0, 140}, /* 20: LIKE shift 140 */ + { 55, 0, 141}, /* 21: GLOB shift 141 */ + { 57, 0, 117}, /* 22: GT shift 117 */ + { 109, 10, 148}, /* 23: SLASH shift 148 */ + { 81, 0, 115}, /* 24: LT shift 115 */ + { 111, 0, 146}, /* 25: STAR shift 146 */ + { 83, 11, 144}, /* 26: MINUS shift 144 */ + { 84, 21, 123}, /* 27: NE shift 123 */ + { 85, 0, 137}, /* 28: NOT shift 137 */ + { 86, 22, 159}, /* 29: NOTNULL shift 159 */ +/* State 295 */ + { 104, 2, 296}, /* 1: RP shift 296 */ + { 22, 0, 217}, /* 2: COMMA shift 217 */ +/* State 297 */ + { 104, 0, 298}, /* 1: RP shift 298 */ +/* State 299 */ + { 63, 2, 164}, /* 1: IN shift 164 */ + { 5, 0, 105}, /* 2: AND shift 105 */ + { 12, 0, 127}, /* 3: BITAND shift 127 */ + { 177, 0, 135}, /* 4: likeop shift 135 */ + { 91, 0, 113}, /* 5: OR shift 113 */ + { 92, 1, 104}, /* 6: ORACLE_OUTER_JOIN shift 104 */ + { 14, 0, 129}, /* 7: BITOR shift 129 */ + { 94, 0, 142}, /* 8: PLUS shift 142 */ + { 76, 0, 119}, /* 9: LE shift 119 */ + { 80, 0, 131}, /* 10: LSHIFT shift 131 */ + { 54, 16, 121}, /* 11: GE shift 121 */ + { 11, 0, 160}, /* 12: BETWEEN shift 160 */ + { 99, 3, 150}, /* 13: REM shift 150 */ + { 71, 0, 155}, /* 14: IS shift 155 */ + { 72, 7, 154}, /* 15: ISNULL shift 154 */ + { 25, 0, 152}, /* 16: CONCAT shift 152 */ + { 45, 0, 125}, /* 17: EQ shift 125 */ + { 104, 0, 300}, /* 18: RP shift 300 */ + { 105, 9, 133}, /* 19: RSHIFT shift 133 */ + { 77, 0, 140}, /* 20: LIKE shift 140 */ + { 55, 0, 141}, /* 21: GLOB shift 141 */ + { 57, 0, 117}, /* 22: GT shift 117 */ + { 109, 10, 148}, /* 23: SLASH shift 148 */ + { 81, 0, 115}, /* 24: LT shift 115 */ + { 111, 0, 146}, /* 25: STAR shift 146 */ + { 83, 11, 144}, /* 26: MINUS shift 144 */ + { 84, 21, 123}, /* 27: NE shift 123 */ + { 85, 0, 137}, /* 28: NOT shift 137 */ + { 86, 22, 159}, /* 29: NOTNULL shift 159 */ +/* State 300 */ + { 184, 2, 301}, /* 1: onconf shift 301 */ + { 90, 0, 10}, /* 2: ON shift 10 */ +/* State 302 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 303}, /* 2: nm shift 303 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 303 */ + { 168, 0, 304}, /* 1: idxlist_opt shift 304 */ + { 79, 0, 321}, /* 2: LP shift 321 */ +/* State 304 */ + { 192, 0, 305}, /* 1: refargs shift 305 */ +/* State 305 */ + { 90, 0, 309}, /* 1: ON shift 309 */ + { 82, 0, 307}, /* 2: MATCH shift 307 */ + { 191, 0, 306}, /* 3: refarg shift 306 */ +/* State 307 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 308}, /* 2: nm shift 308 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 309 */ + { 123, 3, 317}, /* 1: UPDATE shift 317 */ + { 34, 0, 310}, /* 2: DELETE shift 310 */ + { 66, 0, 319}, /* 3: INSERT shift 319 */ +/* State 310 */ + { 108, 4, 312}, /* 1: SET shift 312 */ + { 101, 0, 316}, /* 2: RESTRICT shift 316 */ + { 190, 0, 311}, /* 3: refact shift 311 */ + { 16, 0, 315}, /* 4: CASCADE shift 315 */ +/* State 312 */ + { 31, 0, 314}, /* 1: DEFAULT shift 314 */ + { 87, 1, 313}, /* 2: NULL shift 313 */ +/* State 317 */ + { 108, 4, 312}, /* 1: SET shift 312 */ + { 101, 0, 316}, /* 2: RESTRICT shift 316 */ + { 190, 0, 318}, /* 3: refact shift 318 */ + { 16, 0, 315}, /* 4: CASCADE shift 315 */ +/* State 319 */ + { 108, 4, 312}, /* 1: SET shift 312 */ + { 101, 0, 316}, /* 2: RESTRICT shift 316 */ + { 190, 0, 320}, /* 3: refact shift 320 */ + { 16, 0, 315}, /* 4: CASCADE shift 315 */ +/* State 321 */ + { 113, 4, 21}, /* 1: STRING shift 21 */ + { 181, 0, 270}, /* 2: nm shift 270 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ + { 166, 0, 272}, /* 5: idxitem shift 272 */ + { 167, 1, 322}, /* 6: idxlist shift 322 */ +/* State 322 */ + { 104, 2, 323}, /* 1: RP shift 323 */ + { 22, 0, 268}, /* 2: COMMA shift 268 */ +/* State 325 */ + { 164, 0, 326}, /* 1: id shift 326 */ + { 59, 0, 101}, /* 2: ID shift 101 */ +/* State 327 */ + { 65, 0, 51}, /* 1: INITIALLY shift 51 */ + { 169, 1, 328}, /* 2: init_deferred_pred_opt shift 328 */ +/* State 330 */ + { 49, 0, 340}, /* 1: FLOAT shift 340 */ + { 113, 0, 331}, /* 2: STRING shift 331 */ + { 87, 5, 341}, /* 3: NULL shift 341 */ + { 94, 3, 334}, /* 4: PLUS shift 334 */ + { 59, 0, 332}, /* 5: ID shift 332 */ + { 68, 0, 333}, /* 6: INTEGER shift 333 */ + { 83, 0, 337}, /* 7: MINUS shift 337 */ +/* State 334 */ + { 68, 0, 335}, /* 1: INTEGER shift 335 */ + { 49, 0, 336}, /* 2: FLOAT shift 336 */ +/* State 337 */ + { 68, 0, 338}, /* 1: INTEGER shift 338 */ + { 49, 0, 339}, /* 2: FLOAT shift 339 */ +/* State 342 */ + { 113, 0, 257}, /* 1: STRING shift 257 */ + { 165, 1, 349}, /* 2: ids shift 349 */ + { 59, 0, 256}, /* 3: ID shift 256 */ + { 79, 3, 343}, /* 4: LP shift 343 */ +/* State 343 */ + { 68, 0, 83}, /* 1: INTEGER shift 83 */ + { 83, 0, 86}, /* 2: MINUS shift 86 */ + { 94, 0, 84}, /* 3: PLUS shift 84 */ + { 199, 2, 344}, /* 4: signed shift 344 */ +/* State 344 */ + { 104, 2, 345}, /* 1: RP shift 345 */ + { 22, 0, 346}, /* 2: COMMA shift 346 */ +/* State 346 */ + { 68, 0, 83}, /* 1: INTEGER shift 83 */ + { 83, 0, 86}, /* 2: MINUS shift 86 */ + { 94, 0, 84}, /* 3: PLUS shift 84 */ + { 199, 2, 347}, /* 4: signed shift 347 */ +/* State 347 */ + { 104, 0, 348}, /* 1: RP shift 348 */ +/* State 352 */ + { 104, 2, 632}, /* 1: RP reduce 77 */ + { 96, 0, 357}, /* 2: PRIMARY shift 357 */ + { 122, 6, 363}, /* 3: UNIQUE shift 363 */ + { 51, 8, 371}, /* 4: FOREIGN shift 371 */ + { 204, 0, 383}, /* 5: tcons shift 383 */ + { 18, 0, 368}, /* 6: CHECK shift 368 */ + { 22, 0, 353}, /* 7: COMMA shift 353 */ + { 27, 0, 355}, /* 8: CONSTRAINT shift 355 */ +/* State 353 */ + { 204, 2, 354}, /* 1: tcons shift 354 */ + { 96, 5, 357}, /* 2: PRIMARY shift 357 */ + { 122, 0, 363}, /* 3: UNIQUE shift 363 */ + { 51, 6, 371}, /* 4: FOREIGN shift 371 */ + { 18, 0, 368}, /* 5: CHECK shift 368 */ + { 27, 0, 355}, /* 6: CONSTRAINT shift 355 */ +/* State 355 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 356}, /* 2: nm shift 356 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 357 */ + { 75, 0, 358}, /* 1: KEY shift 358 */ +/* State 358 */ + { 79, 0, 359}, /* 1: LP shift 359 */ +/* State 359 */ + { 113, 4, 21}, /* 1: STRING shift 21 */ + { 181, 0, 270}, /* 2: nm shift 270 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ + { 166, 0, 272}, /* 5: idxitem shift 272 */ + { 167, 1, 360}, /* 6: idxlist shift 360 */ +/* State 360 */ + { 104, 2, 361}, /* 1: RP shift 361 */ + { 22, 0, 268}, /* 2: COMMA shift 268 */ +/* State 361 */ + { 184, 2, 362}, /* 1: onconf shift 362 */ + { 90, 0, 10}, /* 2: ON shift 10 */ +/* State 363 */ + { 79, 0, 364}, /* 1: LP shift 364 */ +/* State 364 */ + { 113, 4, 21}, /* 1: STRING shift 21 */ + { 181, 0, 270}, /* 2: nm shift 270 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ + { 166, 0, 272}, /* 5: idxitem shift 272 */ + { 167, 1, 365}, /* 6: idxlist shift 365 */ +/* State 365 */ + { 104, 2, 366}, /* 1: RP shift 366 */ + { 22, 0, 268}, /* 2: COMMA shift 268 */ +/* State 366 */ + { 184, 2, 367}, /* 1: onconf shift 367 */ + { 90, 0, 10}, /* 2: ON shift 10 */ +/* State 368 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 369}, /* 8: expr shift 369 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 369 */ + { 90, 0, 10}, /* 1: ON shift 10 */ + { 91, 0, 113}, /* 2: OR shift 113 */ + { 92, 0, 104}, /* 3: ORACLE_OUTER_JOIN shift 104 */ + { 63, 0, 164}, /* 4: IN shift 164 */ + { 184, 7, 370}, /* 5: onconf shift 370 */ + { 5, 0, 105}, /* 6: AND shift 105 */ + { 94, 0, 142}, /* 7: PLUS shift 142 */ + { 11, 0, 160}, /* 8: BETWEEN shift 160 */ + { 12, 0, 127}, /* 9: BITAND shift 127 */ + { 99, 0, 150}, /* 10: REM shift 150 */ + { 45, 0, 125}, /* 11: EQ shift 125 */ + { 71, 8, 155}, /* 12: IS shift 155 */ + { 72, 9, 154}, /* 13: ISNULL shift 154 */ + { 81, 0, 115}, /* 14: LT shift 115 */ + { 14, 0, 129}, /* 15: BITOR shift 129 */ + { 105, 11, 133}, /* 16: RSHIFT shift 133 */ + { 76, 0, 119}, /* 17: LE shift 119 */ + { 77, 0, 140}, /* 18: LIKE shift 140 */ + { 54, 0, 121}, /* 19: GE shift 121 */ + { 109, 0, 148}, /* 20: SLASH shift 148 */ + { 80, 0, 131}, /* 21: LSHIFT shift 131 */ + { 111, 14, 146}, /* 22: STAR shift 146 */ + { 55, 29, 141}, /* 23: GLOB shift 141 */ + { 83, 0, 144}, /* 24: MINUS shift 144 */ + { 84, 19, 123}, /* 25: NE shift 123 */ + { 85, 23, 137}, /* 26: NOT shift 137 */ + { 86, 0, 159}, /* 27: NOTNULL shift 159 */ + { 177, 30, 135}, /* 28: likeop shift 135 */ + { 25, 0, 152}, /* 29: CONCAT shift 152 */ + { 57, 0, 117}, /* 30: GT shift 117 */ +/* State 371 */ + { 75, 0, 372}, /* 1: KEY shift 372 */ +/* State 372 */ + { 79, 0, 373}, /* 1: LP shift 373 */ +/* State 373 */ + { 113, 4, 21}, /* 1: STRING shift 21 */ + { 181, 0, 270}, /* 2: nm shift 270 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ + { 166, 0, 272}, /* 5: idxitem shift 272 */ + { 167, 1, 374}, /* 6: idxlist shift 374 */ +/* State 374 */ + { 104, 2, 375}, /* 1: RP shift 375 */ + { 22, 0, 268}, /* 2: COMMA shift 268 */ +/* State 375 */ + { 98, 0, 376}, /* 1: REFERENCES shift 376 */ +/* State 376 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 377}, /* 2: nm shift 377 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 377 */ + { 168, 0, 378}, /* 1: idxlist_opt shift 378 */ + { 79, 0, 321}, /* 2: LP shift 321 */ +/* State 378 */ + { 192, 0, 379}, /* 1: refargs shift 379 */ +/* State 379 */ + { 32, 0, 327}, /* 1: DEFERRABLE shift 327 */ + { 85, 0, 380}, /* 2: NOT shift 380 */ + { 191, 0, 306}, /* 3: refarg shift 306 */ + { 82, 0, 307}, /* 4: MATCH shift 307 */ + { 151, 1, 382}, /* 5: defer_subclause shift 382 */ + { 152, 4, 381}, /* 6: defer_subclause_opt shift 381 */ + { 90, 0, 309}, /* 7: ON shift 309 */ +/* State 380 */ + { 32, 0, 49}, /* 1: DEFERRABLE shift 49 */ +/* State 386 */ + { 106, 0, 73}, /* 1: SELECT shift 73 */ + { 196, 1, 387}, /* 2: select shift 387 */ + { 185, 0, 69}, /* 3: oneselect shift 69 */ +/* State 387 */ + { 180, 0, 71}, /* 1: multiselect_op shift 71 */ + { 121, 4, 167}, /* 2: UNION shift 167 */ + { 107, 0, 575}, /* 3: SEMI reduce 20 */ + { 46, 0, 170}, /* 4: EXCEPT shift 170 */ + { 69, 0, 169}, /* 5: INTERSECT shift 169 */ +/* State 388 */ + { 115, 0, 434}, /* 1: TEMP shift 434 */ + { 205, 1, 389}, /* 2: temp shift 389 */ + { 209, 0, 435}, /* 3: trigger_decl shift 435 */ +/* State 389 */ + { 114, 0, 390}, /* 1: TABLE shift 390 */ + { 122, 0, 406}, /* 2: UNIQUE shift 406 */ + { 128, 2, 392}, /* 3: VIEW shift 392 */ + { 118, 6, 407}, /* 4: TRIGGER shift 407 */ + { 214, 4, 396}, /* 5: uniqueflag shift 396 */ + { 64, 0, 788}, /* 6: INDEX reduce 233 */ +/* State 390 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 391}, /* 2: nm shift 391 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 392 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 393}, /* 2: nm shift 393 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 393 */ + { 6, 0, 394}, /* 1: AS shift 394 */ +/* State 394 */ + { 106, 0, 73}, /* 1: SELECT shift 73 */ + { 196, 1, 395}, /* 2: select shift 395 */ + { 185, 0, 69}, /* 3: oneselect shift 69 */ +/* State 395 */ + { 180, 0, 71}, /* 1: multiselect_op shift 71 */ + { 121, 4, 167}, /* 2: UNION shift 167 */ + { 107, 0, 653}, /* 3: SEMI reduce 98 */ + { 46, 0, 170}, /* 4: EXCEPT shift 170 */ + { 69, 0, 169}, /* 5: INTERSECT shift 169 */ +/* State 396 */ + { 64, 0, 397}, /* 1: INDEX shift 397 */ +/* State 397 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 398}, /* 2: nm shift 398 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 398 */ + { 90, 0, 399}, /* 1: ON shift 399 */ +/* State 399 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 400}, /* 2: nm shift 400 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 400 */ + { 150, 3, 401}, /* 1: dbnm shift 401 */ + { 79, 0, 680}, /* 2: LP reduce 125 */ + { 39, 0, 275}, /* 3: DOT shift 275 */ +/* State 401 */ + { 79, 0, 402}, /* 1: LP shift 402 */ +/* State 402 */ + { 113, 4, 21}, /* 1: STRING shift 21 */ + { 181, 0, 270}, /* 2: nm shift 270 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ + { 166, 0, 272}, /* 5: idxitem shift 272 */ + { 167, 1, 403}, /* 6: idxlist shift 403 */ +/* State 403 */ + { 104, 2, 404}, /* 1: RP shift 404 */ + { 22, 0, 268}, /* 2: COMMA shift 268 */ +/* State 404 */ + { 90, 0, 10}, /* 1: ON shift 10 */ + { 184, 0, 405}, /* 2: onconf shift 405 */ + { 107, 0, 643}, /* 3: SEMI reduce 88 */ +/* State 405 */ + { 107, 0, 786}, /* 1: SEMI reduce 231 */ +/* State 406 */ + { 64, 0, 787}, /* 1: INDEX reduce 232 */ +/* State 407 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 408}, /* 2: nm shift 408 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 408 */ + { 67, 0, 432}, /* 1: INSTEAD shift 432 */ + { 9, 0, 430}, /* 2: BEFORE shift 430 */ + { 2, 0, 431}, /* 3: AFTER shift 431 */ + { 211, 1, 409}, /* 4: trigger_time shift 409 */ +/* State 409 */ + { 66, 2, 423}, /* 1: INSERT shift 423 */ + { 34, 0, 422}, /* 2: DELETE shift 422 */ + { 210, 1, 410}, /* 3: trigger_event shift 410 */ + { 123, 0, 424}, /* 4: UPDATE shift 424 */ +/* State 410 */ + { 90, 0, 411}, /* 1: ON shift 411 */ +/* State 411 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 412}, /* 2: nm shift 412 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 412 */ + { 150, 0, 413}, /* 1: dbnm shift 413 */ + { 39, 0, 275}, /* 2: DOT shift 275 */ +/* State 413 */ + { 160, 2, 414}, /* 1: foreach_clause shift 414 */ + { 50, 0, 418}, /* 2: FOR shift 418 */ +/* State 414 */ + { 216, 3, 415}, /* 1: when_clause shift 415 */ + { 10, 0, 824}, /* 2: BEGIN reduce 269 */ + { 129, 0, 416}, /* 3: WHEN shift 416 */ +/* State 415 */ + { 10, 0, 812}, /* 1: BEGIN reduce 257 */ +/* State 416 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 417}, /* 8: expr shift 417 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 417 */ + { 63, 2, 164}, /* 1: IN shift 164 */ + { 5, 0, 105}, /* 2: AND shift 105 */ + { 12, 0, 127}, /* 3: BITAND shift 127 */ + { 177, 0, 135}, /* 4: likeop shift 135 */ + { 91, 0, 113}, /* 5: OR shift 113 */ + { 92, 1, 104}, /* 6: ORACLE_OUTER_JOIN shift 104 */ + { 14, 0, 129}, /* 7: BITOR shift 129 */ + { 94, 0, 142}, /* 8: PLUS shift 142 */ + { 76, 0, 119}, /* 9: LE shift 119 */ + { 80, 0, 131}, /* 10: LSHIFT shift 131 */ + { 10, 0, 825}, /* 11: BEGIN reduce 270 */ + { 11, 0, 160}, /* 12: BETWEEN shift 160 */ + { 99, 3, 150}, /* 13: REM shift 150 */ + { 71, 0, 155}, /* 14: IS shift 155 */ + { 72, 7, 154}, /* 15: ISNULL shift 154 */ + { 54, 18, 121}, /* 16: GE shift 121 */ + { 45, 0, 125}, /* 17: EQ shift 125 */ + { 25, 0, 152}, /* 18: CONCAT shift 152 */ + { 105, 9, 133}, /* 19: RSHIFT shift 133 */ + { 77, 0, 140}, /* 20: LIKE shift 140 */ + { 55, 0, 141}, /* 21: GLOB shift 141 */ + { 57, 0, 117}, /* 22: GT shift 117 */ + { 109, 10, 148}, /* 23: SLASH shift 148 */ + { 81, 0, 115}, /* 24: LT shift 115 */ + { 111, 0, 146}, /* 25: STAR shift 146 */ + { 83, 16, 144}, /* 26: MINUS shift 144 */ + { 84, 21, 123}, /* 27: NE shift 123 */ + { 85, 0, 137}, /* 28: NOT shift 137 */ + { 86, 22, 159}, /* 29: NOTNULL shift 159 */ +/* State 418 */ + { 41, 0, 419}, /* 1: EACH shift 419 */ +/* State 419 */ + { 112, 0, 421}, /* 1: STATEMENT shift 421 */ + { 103, 0, 420}, /* 2: ROW shift 420 */ +/* State 422 */ + { 90, 0, 817}, /* 1: ON reduce 262 */ +/* State 423 */ + { 90, 0, 818}, /* 1: ON reduce 263 */ +/* State 424 */ + { 90, 2, 819}, /* 1: ON reduce 264 */ + { 88, 0, 425}, /* 2: OF shift 425 */ +/* State 425 */ + { 171, 0, 426}, /* 1: inscollist shift 426 */ + { 181, 1, 429}, /* 2: nm shift 429 */ + { 59, 0, 20}, /* 3: ID shift 20 */ + { 113, 0, 21}, /* 4: STRING shift 21 */ + { 74, 3, 22}, /* 5: JOIN_KW shift 22 */ +/* State 426 */ + { 90, 2, 820}, /* 1: ON reduce 265 */ + { 22, 0, 427}, /* 2: COMMA shift 427 */ +/* State 427 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 428}, /* 2: nm shift 428 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 432 */ + { 88, 0, 433}, /* 1: OF shift 433 */ +/* State 435 */ + { 10, 0, 436}, /* 1: BEGIN shift 436 */ +/* State 436 */ + { 207, 0, 440}, /* 1: trigger_cmd shift 440 */ + { 208, 0, 438}, /* 2: trigger_cmd_list shift 438 */ + { 106, 5, 73}, /* 3: SELECT shift 73 */ + { 66, 0, 458}, /* 4: INSERT shift 458 */ + { 43, 9, 827}, /* 5: END reduce 272 */ + { 185, 0, 69}, /* 6: oneselect shift 69 */ + { 123, 0, 443}, /* 7: UPDATE shift 443 */ + { 196, 3, 437}, /* 8: select shift 437 */ + { 34, 0, 474}, /* 9: DELETE shift 474 */ +/* State 437 */ + { 180, 0, 71}, /* 1: multiselect_op shift 71 */ + { 121, 4, 167}, /* 2: UNION shift 167 */ + { 107, 0, 832}, /* 3: SEMI reduce 277 */ + { 46, 0, 170}, /* 4: EXCEPT shift 170 */ + { 69, 0, 169}, /* 5: INTERSECT shift 169 */ +/* State 438 */ + { 43, 0, 439}, /* 1: END shift 439 */ +/* State 439 */ + { 107, 0, 811}, /* 1: SEMI reduce 256 */ +/* State 440 */ + { 107, 0, 441}, /* 1: SEMI shift 441 */ +/* State 441 */ + { 207, 0, 440}, /* 1: trigger_cmd shift 440 */ + { 208, 0, 442}, /* 2: trigger_cmd_list shift 442 */ + { 106, 5, 73}, /* 3: SELECT shift 73 */ + { 66, 0, 458}, /* 4: INSERT shift 458 */ + { 43, 9, 827}, /* 5: END reduce 272 */ + { 185, 0, 69}, /* 6: oneselect shift 69 */ + { 123, 0, 443}, /* 7: UPDATE shift 443 */ + { 196, 3, 437}, /* 8: select shift 437 */ + { 34, 0, 474}, /* 9: DELETE shift 474 */ +/* State 442 */ + { 43, 0, 826}, /* 1: END reduce 271 */ +/* State 443 */ + { 186, 0, 446}, /* 1: orconf shift 446 */ + { 91, 0, 444}, /* 2: OR shift 444 */ +/* State 444 */ + { 102, 3, 13}, /* 1: ROLLBACK shift 13 */ + { 193, 4, 445}, /* 2: resolvetype shift 445 */ + { 60, 6, 16}, /* 3: IGNORE shift 16 */ + { 1, 0, 14}, /* 4: ABORT shift 14 */ + { 100, 0, 17}, /* 5: REPLACE shift 17 */ + { 48, 0, 15}, /* 6: FAIL shift 15 */ +/* State 446 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 447}, /* 2: nm shift 447 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 447 */ + { 108, 0, 448}, /* 1: SET shift 448 */ +/* State 448 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 0, 455}, /* 2: nm shift 455 */ + { 59, 0, 20}, /* 3: ID shift 20 */ + { 198, 1, 449}, /* 4: setlist shift 449 */ + { 74, 3, 22}, /* 5: JOIN_KW shift 22 */ +/* State 449 */ + { 22, 0, 450}, /* 1: COMMA shift 450 */ + { 217, 0, 454}, /* 2: where_opt shift 454 */ + { 130, 1, 239}, /* 3: WHERE shift 239 */ + { 107, 0, 710}, /* 4: SEMI reduce 155 */ +/* State 450 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 451}, /* 2: nm shift 451 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 451 */ + { 45, 0, 452}, /* 1: EQ shift 452 */ +/* State 452 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 453}, /* 8: expr shift 453 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 453 */ + { 84, 0, 123}, /* 1: NE shift 123 */ + { 85, 4, 137}, /* 2: NOT shift 137 */ + { 86, 0, 159}, /* 3: NOTNULL shift 159 */ + { 57, 0, 117}, /* 4: GT shift 117 */ + { 63, 0, 164}, /* 5: IN shift 164 */ + { 5, 0, 105}, /* 6: AND shift 105 */ + { 71, 0, 155}, /* 7: IS shift 155 */ + { 91, 5, 113}, /* 8: OR shift 113 */ + { 92, 0, 104}, /* 9: ORACLE_OUTER_JOIN shift 104 */ + { 177, 0, 135}, /* 10: likeop shift 135 */ + { 94, 0, 142}, /* 11: PLUS shift 142 */ + { 11, 0, 160}, /* 12: BETWEEN shift 160 */ + { 12, 0, 127}, /* 13: BITAND shift 127 */ + { 77, 0, 140}, /* 14: LIKE shift 140 */ + { 14, 0, 129}, /* 15: BITOR shift 129 */ + { 99, 7, 150}, /* 16: REM shift 150 */ + { 72, 0, 154}, /* 17: ISNULL shift 154 */ + { 45, 0, 125}, /* 18: EQ shift 125 */ + { 81, 20, 115}, /* 19: LT shift 115 */ + { 25, 0, 152}, /* 20: CONCAT shift 152 */ + { 76, 0, 119}, /* 21: LE shift 119 */ + { 105, 14, 133}, /* 22: RSHIFT shift 133 */ + { 83, 24, 144}, /* 23: MINUS shift 144 */ + { 55, 0, 141}, /* 24: GLOB shift 141 */ + { 80, 0, 131}, /* 25: LSHIFT shift 131 */ + { 109, 19, 148}, /* 26: SLASH shift 148 */ + { 54, 0, 121}, /* 27: GE shift 121 */ + { 111, 23, 146}, /* 28: STAR shift 146 */ +/* State 454 */ + { 107, 0, 828}, /* 1: SEMI reduce 273 */ +/* State 455 */ + { 45, 0, 456}, /* 1: EQ shift 456 */ +/* State 456 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 457}, /* 8: expr shift 457 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 457 */ + { 84, 0, 123}, /* 1: NE shift 123 */ + { 85, 4, 137}, /* 2: NOT shift 137 */ + { 86, 0, 159}, /* 3: NOTNULL shift 159 */ + { 57, 0, 117}, /* 4: GT shift 117 */ + { 63, 0, 164}, /* 5: IN shift 164 */ + { 5, 0, 105}, /* 6: AND shift 105 */ + { 71, 0, 155}, /* 7: IS shift 155 */ + { 91, 5, 113}, /* 8: OR shift 113 */ + { 92, 0, 104}, /* 9: ORACLE_OUTER_JOIN shift 104 */ + { 177, 0, 135}, /* 10: likeop shift 135 */ + { 94, 0, 142}, /* 11: PLUS shift 142 */ + { 11, 0, 160}, /* 12: BETWEEN shift 160 */ + { 12, 0, 127}, /* 13: BITAND shift 127 */ + { 77, 0, 140}, /* 14: LIKE shift 140 */ + { 14, 0, 129}, /* 15: BITOR shift 129 */ + { 99, 7, 150}, /* 16: REM shift 150 */ + { 72, 0, 154}, /* 17: ISNULL shift 154 */ + { 45, 0, 125}, /* 18: EQ shift 125 */ + { 81, 20, 115}, /* 19: LT shift 115 */ + { 25, 0, 152}, /* 20: CONCAT shift 152 */ + { 76, 0, 119}, /* 21: LE shift 119 */ + { 105, 14, 133}, /* 22: RSHIFT shift 133 */ + { 83, 24, 144}, /* 23: MINUS shift 144 */ + { 55, 0, 141}, /* 24: GLOB shift 141 */ + { 80, 0, 131}, /* 25: LSHIFT shift 131 */ + { 109, 19, 148}, /* 26: SLASH shift 148 */ + { 54, 0, 121}, /* 27: GE shift 121 */ + { 111, 23, 146}, /* 28: STAR shift 146 */ +/* State 458 */ + { 186, 0, 459}, /* 1: orconf shift 459 */ + { 91, 3, 444}, /* 2: OR shift 444 */ + { 70, 0, 645}, /* 3: INTO reduce 90 */ +/* State 459 */ + { 70, 0, 460}, /* 1: INTO shift 460 */ +/* State 460 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 461}, /* 2: nm shift 461 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 461 */ + { 172, 0, 465}, /* 1: inscollist_opt shift 465 */ + { 79, 0, 462}, /* 2: LP shift 462 */ +/* State 462 */ + { 171, 0, 463}, /* 1: inscollist shift 463 */ + { 181, 1, 429}, /* 2: nm shift 429 */ + { 59, 0, 20}, /* 3: ID shift 20 */ + { 113, 0, 21}, /* 4: STRING shift 21 */ + { 74, 3, 22}, /* 5: JOIN_KW shift 22 */ +/* State 463 */ + { 104, 2, 464}, /* 1: RP shift 464 */ + { 22, 0, 427}, /* 2: COMMA shift 427 */ +/* State 465 */ + { 196, 0, 466}, /* 1: select shift 466 */ + { 185, 0, 69}, /* 2: oneselect shift 69 */ + { 106, 0, 73}, /* 3: SELECT shift 73 */ + { 127, 0, 467}, /* 4: VALUES shift 467 */ +/* State 466 */ + { 180, 0, 71}, /* 1: multiselect_op shift 71 */ + { 121, 4, 167}, /* 2: UNION shift 167 */ + { 107, 0, 830}, /* 3: SEMI reduce 275 */ + { 46, 0, 170}, /* 4: EXCEPT shift 170 */ + { 69, 0, 169}, /* 5: INTERSECT shift 169 */ +/* State 467 */ + { 79, 0, 468}, /* 1: LP shift 468 */ +/* State 468 */ + { 97, 3, 193}, /* 1: RAISE shift 193 */ + { 113, 1, 66}, /* 2: STRING shift 66 */ + { 49, 7, 174}, /* 3: FLOAT shift 174 */ + { 83, 0, 179}, /* 4: MINUS shift 179 */ + { 68, 0, 173}, /* 5: INTEGER shift 173 */ + { 181, 9, 107}, /* 6: nm shift 107 */ + { 17, 0, 183}, /* 7: CASE shift 183 */ + { 87, 0, 106}, /* 8: NULL shift 106 */ + { 85, 0, 175}, /* 9: NOT shift 175 */ + { 13, 0, 177}, /* 10: BITNOT shift 177 */ + { 74, 0, 67}, /* 11: JOIN_KW shift 67 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 94, 0, 181}, /* 13: PLUS shift 181 */ + { 157, 10, 473}, /* 14: expr shift 473 */ + { 174, 13, 469}, /* 15: itemlist shift 469 */ + { 79, 0, 68}, /* 16: LP shift 68 */ +/* State 469 */ + { 104, 2, 472}, /* 1: RP shift 472 */ + { 22, 0, 470}, /* 2: COMMA shift 470 */ +/* State 470 */ + { 79, 4, 68}, /* 1: LP shift 68 */ + { 181, 0, 107}, /* 2: nm shift 107 */ + { 17, 0, 183}, /* 3: CASE shift 183 */ + { 49, 0, 174}, /* 4: FLOAT shift 174 */ + { 94, 1, 181}, /* 5: PLUS shift 181 */ + { 97, 0, 193}, /* 6: RAISE shift 193 */ + { 83, 10, 179}, /* 7: MINUS shift 179 */ + { 157, 6, 471}, /* 8: expr shift 471 */ + { 113, 7, 66}, /* 9: STRING shift 66 */ + { 68, 0, 173}, /* 10: INTEGER shift 173 */ + { 85, 0, 175}, /* 11: NOT shift 175 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 87, 0, 106}, /* 13: NULL shift 106 */ + { 13, 0, 177}, /* 14: BITNOT shift 177 */ + { 74, 12, 67}, /* 15: JOIN_KW shift 67 */ +/* State 471 */ + { 84, 0, 123}, /* 1: NE shift 123 */ + { 85, 4, 137}, /* 2: NOT shift 137 */ + { 86, 0, 159}, /* 3: NOTNULL shift 159 */ + { 57, 0, 117}, /* 4: GT shift 117 */ + { 63, 0, 164}, /* 5: IN shift 164 */ + { 5, 0, 105}, /* 6: AND shift 105 */ + { 71, 0, 155}, /* 7: IS shift 155 */ + { 91, 5, 113}, /* 8: OR shift 113 */ + { 92, 0, 104}, /* 9: ORACLE_OUTER_JOIN shift 104 */ + { 177, 0, 135}, /* 10: likeop shift 135 */ + { 94, 0, 142}, /* 11: PLUS shift 142 */ + { 11, 0, 160}, /* 12: BETWEEN shift 160 */ + { 12, 0, 127}, /* 13: BITAND shift 127 */ + { 77, 0, 140}, /* 14: LIKE shift 140 */ + { 14, 0, 129}, /* 15: BITOR shift 129 */ + { 99, 7, 150}, /* 16: REM shift 150 */ + { 72, 0, 154}, /* 17: ISNULL shift 154 */ + { 45, 0, 125}, /* 18: EQ shift 125 */ + { 81, 20, 115}, /* 19: LT shift 115 */ + { 25, 0, 152}, /* 20: CONCAT shift 152 */ + { 76, 0, 119}, /* 21: LE shift 119 */ + { 105, 14, 133}, /* 22: RSHIFT shift 133 */ + { 83, 24, 144}, /* 23: MINUS shift 144 */ + { 55, 0, 141}, /* 24: GLOB shift 141 */ + { 80, 0, 131}, /* 25: LSHIFT shift 131 */ + { 109, 19, 148}, /* 26: SLASH shift 148 */ + { 54, 0, 121}, /* 27: GE shift 121 */ + { 111, 23, 146}, /* 28: STAR shift 146 */ +/* State 472 */ + { 107, 0, 829}, /* 1: SEMI reduce 274 */ +/* State 473 */ + { 84, 0, 123}, /* 1: NE shift 123 */ + { 85, 4, 137}, /* 2: NOT shift 137 */ + { 86, 0, 159}, /* 3: NOTNULL shift 159 */ + { 57, 0, 117}, /* 4: GT shift 117 */ + { 63, 0, 164}, /* 5: IN shift 164 */ + { 5, 0, 105}, /* 6: AND shift 105 */ + { 71, 0, 155}, /* 7: IS shift 155 */ + { 91, 5, 113}, /* 8: OR shift 113 */ + { 92, 0, 104}, /* 9: ORACLE_OUTER_JOIN shift 104 */ + { 177, 0, 135}, /* 10: likeop shift 135 */ + { 94, 0, 142}, /* 11: PLUS shift 142 */ + { 11, 0, 160}, /* 12: BETWEEN shift 160 */ + { 12, 0, 127}, /* 13: BITAND shift 127 */ + { 77, 0, 140}, /* 14: LIKE shift 140 */ + { 14, 0, 129}, /* 15: BITOR shift 129 */ + { 99, 7, 150}, /* 16: REM shift 150 */ + { 72, 0, 154}, /* 17: ISNULL shift 154 */ + { 45, 0, 125}, /* 18: EQ shift 125 */ + { 81, 20, 115}, /* 19: LT shift 115 */ + { 25, 0, 152}, /* 20: CONCAT shift 152 */ + { 76, 0, 119}, /* 21: LE shift 119 */ + { 105, 14, 133}, /* 22: RSHIFT shift 133 */ + { 83, 24, 144}, /* 23: MINUS shift 144 */ + { 55, 0, 141}, /* 24: GLOB shift 141 */ + { 80, 0, 131}, /* 25: LSHIFT shift 131 */ + { 109, 19, 148}, /* 26: SLASH shift 148 */ + { 54, 0, 121}, /* 27: GE shift 121 */ + { 111, 23, 146}, /* 28: STAR shift 146 */ +/* State 474 */ + { 52, 0, 475}, /* 1: FROM shift 475 */ +/* State 475 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 476}, /* 2: nm shift 476 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 476 */ + { 130, 0, 239}, /* 1: WHERE shift 239 */ + { 217, 1, 477}, /* 2: where_opt shift 477 */ + { 107, 0, 710}, /* 3: SEMI reduce 155 */ +/* State 477 */ + { 107, 0, 831}, /* 1: SEMI reduce 276 */ +/* State 478 */ + { 128, 2, 481}, /* 1: VIEW shift 481 */ + { 64, 0, 483}, /* 2: INDEX shift 483 */ + { 118, 4, 486}, /* 3: TRIGGER shift 486 */ + { 114, 0, 479}, /* 4: TABLE shift 479 */ +/* State 479 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 480}, /* 2: nm shift 480 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 480 */ + { 107, 0, 652}, /* 1: SEMI reduce 97 */ +/* State 481 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 482}, /* 2: nm shift 482 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 482 */ + { 107, 0, 654}, /* 1: SEMI reduce 99 */ +/* State 483 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 484}, /* 2: nm shift 484 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 484 */ + { 150, 2, 485}, /* 1: dbnm shift 485 */ + { 39, 0, 275}, /* 2: DOT shift 275 */ + { 107, 0, 680}, /* 3: SEMI reduce 125 */ +/* State 485 */ + { 107, 0, 794}, /* 1: SEMI reduce 239 */ +/* State 486 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 487}, /* 2: nm shift 487 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 487 */ + { 150, 2, 488}, /* 1: dbnm shift 488 */ + { 39, 0, 275}, /* 2: DOT shift 275 */ + { 107, 0, 680}, /* 3: SEMI reduce 125 */ +/* State 488 */ + { 107, 0, 837}, /* 1: SEMI reduce 282 */ +/* State 489 */ + { 180, 0, 71}, /* 1: multiselect_op shift 71 */ + { 121, 4, 167}, /* 2: UNION shift 167 */ + { 107, 0, 655}, /* 3: SEMI reduce 100 */ + { 46, 0, 170}, /* 4: EXCEPT shift 170 */ + { 69, 0, 169}, /* 5: INTERSECT shift 169 */ +/* State 490 */ + { 52, 0, 491}, /* 1: FROM shift 491 */ +/* State 491 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 492}, /* 2: nm shift 492 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 492 */ + { 150, 0, 493}, /* 1: dbnm shift 493 */ + { 39, 0, 275}, /* 2: DOT shift 275 */ +/* State 493 */ + { 130, 0, 239}, /* 1: WHERE shift 239 */ + { 217, 1, 494}, /* 2: where_opt shift 494 */ + { 107, 0, 710}, /* 3: SEMI reduce 155 */ +/* State 494 */ + { 107, 0, 709}, /* 1: SEMI reduce 154 */ +/* State 495 */ + { 186, 0, 496}, /* 1: orconf shift 496 */ + { 91, 0, 444}, /* 2: OR shift 444 */ +/* State 496 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 497}, /* 2: nm shift 497 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 497 */ + { 150, 2, 498}, /* 1: dbnm shift 498 */ + { 108, 3, 680}, /* 2: SET reduce 125 */ + { 39, 0, 275}, /* 3: DOT shift 275 */ +/* State 498 */ + { 108, 0, 499}, /* 1: SET shift 499 */ +/* State 499 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 0, 455}, /* 2: nm shift 455 */ + { 59, 0, 20}, /* 3: ID shift 20 */ + { 198, 1, 500}, /* 4: setlist shift 500 */ + { 74, 3, 22}, /* 5: JOIN_KW shift 22 */ +/* State 500 */ + { 22, 0, 450}, /* 1: COMMA shift 450 */ + { 217, 0, 501}, /* 2: where_opt shift 501 */ + { 130, 1, 239}, /* 3: WHERE shift 239 */ + { 107, 0, 710}, /* 4: SEMI reduce 155 */ +/* State 501 */ + { 107, 0, 712}, /* 1: SEMI reduce 157 */ +/* State 502 */ + { 70, 0, 503}, /* 1: INTO shift 503 */ +/* State 503 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 504}, /* 2: nm shift 504 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 504 */ + { 150, 0, 505}, /* 1: dbnm shift 505 */ + { 39, 0, 275}, /* 2: DOT shift 275 */ +/* State 505 */ + { 172, 0, 506}, /* 1: inscollist_opt shift 506 */ + { 79, 0, 462}, /* 2: LP shift 462 */ +/* State 506 */ + { 196, 0, 507}, /* 1: select shift 507 */ + { 185, 0, 69}, /* 2: oneselect shift 69 */ + { 106, 0, 73}, /* 3: SELECT shift 73 */ + { 127, 0, 508}, /* 4: VALUES shift 508 */ +/* State 507 */ + { 180, 0, 71}, /* 1: multiselect_op shift 71 */ + { 121, 4, 167}, /* 2: UNION shift 167 */ + { 107, 0, 716}, /* 3: SEMI reduce 161 */ + { 46, 0, 170}, /* 4: EXCEPT shift 170 */ + { 69, 0, 169}, /* 5: INTERSECT shift 169 */ +/* State 508 */ + { 79, 0, 509}, /* 1: LP shift 509 */ +/* State 509 */ + { 97, 3, 193}, /* 1: RAISE shift 193 */ + { 113, 1, 66}, /* 2: STRING shift 66 */ + { 49, 7, 174}, /* 3: FLOAT shift 174 */ + { 83, 0, 179}, /* 4: MINUS shift 179 */ + { 68, 0, 173}, /* 5: INTEGER shift 173 */ + { 181, 9, 107}, /* 6: nm shift 107 */ + { 17, 0, 183}, /* 7: CASE shift 183 */ + { 87, 0, 106}, /* 8: NULL shift 106 */ + { 85, 0, 175}, /* 9: NOT shift 175 */ + { 13, 0, 177}, /* 10: BITNOT shift 177 */ + { 74, 0, 67}, /* 11: JOIN_KW shift 67 */ + { 59, 0, 64}, /* 12: ID shift 64 */ + { 94, 0, 181}, /* 13: PLUS shift 181 */ + { 157, 10, 473}, /* 14: expr shift 473 */ + { 174, 13, 510}, /* 15: itemlist shift 510 */ + { 79, 0, 68}, /* 16: LP shift 68 */ +/* State 510 */ + { 104, 2, 511}, /* 1: RP shift 511 */ + { 22, 0, 470}, /* 2: COMMA shift 470 */ +/* State 511 */ + { 107, 0, 715}, /* 1: SEMI reduce 160 */ +/* State 512 */ + { 186, 0, 513}, /* 1: orconf shift 513 */ + { 91, 3, 444}, /* 2: OR shift 444 */ + { 70, 0, 645}, /* 3: INTO reduce 90 */ +/* State 513 */ + { 70, 0, 717}, /* 1: INTO reduce 162 */ +/* State 514 */ + { 70, 0, 718}, /* 1: INTO reduce 163 */ +/* State 515 */ + { 186, 0, 516}, /* 1: orconf shift 516 */ + { 91, 0, 444}, /* 2: OR shift 444 */ +/* State 516 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 517}, /* 2: nm shift 517 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 517 */ + { 150, 3, 518}, /* 1: dbnm shift 518 */ + { 52, 0, 680}, /* 2: FROM reduce 125 */ + { 39, 0, 275}, /* 3: DOT shift 275 */ +/* State 518 */ + { 52, 0, 519}, /* 1: FROM shift 519 */ +/* State 519 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 520}, /* 2: nm shift 520 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 520 */ + { 107, 0, 796}, /* 1: SEMI reduce 241 */ + { 125, 1, 521}, /* 2: USING shift 521 */ +/* State 521 */ + { 35, 0, 522}, /* 1: DELIMITERS shift 522 */ +/* State 522 */ + { 113, 0, 523}, /* 1: STRING shift 523 */ +/* State 523 */ + { 107, 0, 795}, /* 1: SEMI reduce 240 */ +/* State 524 */ + { 59, 0, 20}, /* 1: ID shift 20 */ + { 181, 0, 525}, /* 2: nm shift 525 */ + { 107, 0, 797}, /* 3: SEMI reduce 242 */ + { 113, 0, 21}, /* 4: STRING shift 21 */ + { 74, 1, 22}, /* 5: JOIN_KW shift 22 */ +/* State 525 */ + { 107, 0, 798}, /* 1: SEMI reduce 243 */ +/* State 526 */ + { 165, 0, 527}, /* 1: ids shift 527 */ + { 59, 0, 256}, /* 2: ID shift 256 */ + { 113, 2, 257}, /* 3: STRING shift 257 */ +/* State 527 */ + { 45, 0, 528}, /* 1: EQ shift 528 */ + { 79, 0, 540}, /* 2: LP shift 540 */ + { 107, 0, 804}, /* 3: SEMI reduce 249 */ +/* State 528 */ + { 90, 0, 530}, /* 1: ON shift 530 */ + { 181, 0, 529}, /* 2: nm shift 529 */ + { 83, 0, 537}, /* 3: MINUS shift 537 */ + { 113, 3, 21}, /* 4: STRING shift 21 */ + { 94, 6, 539}, /* 5: PLUS shift 539 */ + { 74, 0, 22}, /* 6: JOIN_KW shift 22 */ + { 179, 8, 532}, /* 7: minus_num shift 532 */ + { 59, 0, 20}, /* 8: ID shift 20 */ + { 188, 0, 531}, /* 9: plus_num shift 531 */ + { 189, 7, 533}, /* 10: plus_opt shift 533 */ +/* State 529 */ + { 107, 0, 799}, /* 1: SEMI reduce 244 */ +/* State 530 */ + { 107, 0, 800}, /* 1: SEMI reduce 245 */ +/* State 531 */ + { 107, 0, 801}, /* 1: SEMI reduce 246 */ +/* State 532 */ + { 107, 0, 802}, /* 1: SEMI reduce 247 */ +/* State 533 */ + { 68, 0, 535}, /* 1: INTEGER shift 535 */ + { 49, 0, 536}, /* 2: FLOAT shift 536 */ + { 182, 1, 534}, /* 3: number shift 534 */ +/* State 534 */ + { 107, 0, 805}, /* 1: SEMI reduce 250 */ +/* State 535 */ + { 107, 0, 807}, /* 1: SEMI reduce 252 */ +/* State 536 */ + { 107, 0, 808}, /* 1: SEMI reduce 253 */ +/* State 537 */ + { 68, 0, 535}, /* 1: INTEGER shift 535 */ + { 49, 0, 536}, /* 2: FLOAT shift 536 */ + { 182, 1, 538}, /* 3: number shift 538 */ +/* State 538 */ + { 107, 0, 806}, /* 1: SEMI reduce 251 */ +/* State 540 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 541}, /* 2: nm shift 541 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 541 */ + { 104, 0, 542}, /* 1: RP shift 542 */ +/* State 542 */ + { 107, 0, 803}, /* 1: SEMI reduce 248 */ +/* State 543 */ + { 30, 0, 548}, /* 1: DATABASE shift 548 */ + { 149, 0, 544}, /* 2: database_kw_opt shift 544 */ +/* State 544 */ + { 165, 0, 545}, /* 1: ids shift 545 */ + { 59, 0, 256}, /* 2: ID shift 256 */ + { 113, 2, 257}, /* 3: STRING shift 257 */ +/* State 545 */ + { 6, 0, 546}, /* 1: AS shift 546 */ +/* State 546 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 547}, /* 2: nm shift 547 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 547 */ + { 107, 0, 838}, /* 1: SEMI reduce 283 */ +/* State 549 */ + { 30, 0, 548}, /* 1: DATABASE shift 548 */ + { 149, 0, 550}, /* 2: database_kw_opt shift 550 */ +/* State 550 */ + { 113, 0, 21}, /* 1: STRING shift 21 */ + { 181, 1, 551}, /* 2: nm shift 551 */ + { 74, 0, 22}, /* 3: JOIN_KW shift 22 */ + { 59, 0, 20}, /* 4: ID shift 20 */ +/* State 551 */ + { 107, 0, 841}, /* 1: SEMI reduce 286 */ +}; + +/* The state table contains information needed to look up the correct +** action in the action table, given the current state of the parser. +** Information needed includes: +** +** + A pointer to the start of the action hash table in yyActionTable. +** +** + The number of entries in the action hash table. +** +** + The default action. This is the action to take if no entry for +** the given look-ahead is found in the action hash table. +*/ +struct yyStateEntry { + const yyActionEntry *hashtbl; /* Start of the hash table in yyActionTable */ + YYCODETYPE nEntry; /* Number of entries in action hash table */ + YYACTIONTYPE actionDefault; /* Default action if look-ahead not found */ +}; +typedef struct yyStateEntry yyStateEntry; +static const yyStateEntry yyStateTable[] = { + { &yyActionTable[0], 6, 562 }, + { &yyActionTable[6], 5, 562 }, + { &yyActionTable[11], 0, 557 }, + { &yyActionTable[11], 22, 842 }, + { &yyActionTable[33], 1, 842 }, + { &yyActionTable[34], 0, 558 }, + { &yyActionTable[34], 1, 842 }, + { &yyActionTable[35], 2, 564 }, + { &yyActionTable[37], 3, 842 }, + { &yyActionTable[40], 1, 842 }, + { &yyActionTable[41], 1, 842 }, + { &yyActionTable[42], 6, 842 }, + { &yyActionTable[48], 0, 644 }, + { &yyActionTable[48], 0, 647 }, + { &yyActionTable[48], 0, 648 }, + { &yyActionTable[48], 0, 649 }, + { &yyActionTable[48], 0, 650 }, + { &yyActionTable[48], 0, 651 }, + { &yyActionTable[48], 4, 565 }, + { &yyActionTable[52], 0, 566 }, + { &yyActionTable[52], 0, 583 }, + { &yyActionTable[52], 0, 584 }, + { &yyActionTable[52], 0, 585 }, + { &yyActionTable[52], 3, 842 }, + { &yyActionTable[55], 1, 842 }, + { &yyActionTable[56], 3, 842 }, + { &yyActionTable[59], 1, 842 }, + { &yyActionTable[60], 3, 842 }, + { &yyActionTable[63], 1, 842 }, + { &yyActionTable[64], 3, 842 }, + { &yyActionTable[67], 1, 842 }, + { &yyActionTable[68], 7, 842 }, + { &yyActionTable[75], 3, 842 }, + { &yyActionTable[78], 1, 842 }, + { &yyActionTable[79], 1, 842 }, + { &yyActionTable[80], 13, 842 }, + { &yyActionTable[93], 0, 576 }, + { &yyActionTable[93], 5, 586 }, + { &yyActionTable[98], 1, 596 }, + { &yyActionTable[99], 13, 578 }, + { &yyActionTable[112], 0, 595 }, + { &yyActionTable[112], 4, 842 }, + { &yyActionTable[116], 10, 842 }, + { &yyActionTable[126], 0, 597 }, + { &yyActionTable[126], 2, 643 }, + { &yyActionTable[128], 0, 608 }, + { &yyActionTable[128], 2, 842 }, + { &yyActionTable[130], 2, 643 }, + { &yyActionTable[132], 0, 609 }, + { &yyActionTable[132], 2, 628 }, + { &yyActionTable[134], 0, 626 }, + { &yyActionTable[134], 2, 842 }, + { &yyActionTable[136], 0, 629 }, + { &yyActionTable[136], 0, 630 }, + { &yyActionTable[136], 1, 842 }, + { &yyActionTable[137], 3, 698 }, + { &yyActionTable[140], 2, 643 }, + { &yyActionTable[142], 0, 610 }, + { &yyActionTable[142], 0, 696 }, + { &yyActionTable[142], 0, 697 }, + { &yyActionTable[142], 2, 643 }, + { &yyActionTable[144], 0, 611 }, + { &yyActionTable[144], 1, 842 }, + { &yyActionTable[145], 15, 842 }, + { &yyActionTable[160], 2, 727 }, + { &yyActionTable[162], 18, 785 }, + { &yyActionTable[180], 1, 734 }, + { &yyActionTable[181], 1, 728 }, + { &yyActionTable[182], 18, 842 }, + { &yyActionTable[200], 0, 656 }, + { &yyActionTable[200], 5, 842 }, + { &yyActionTable[205], 2, 842 }, + { &yyActionTable[207], 0, 657 }, + { &yyActionTable[207], 3, 665 }, + { &yyActionTable[210], 2, 667 }, + { &yyActionTable[212], 3, 674 }, + { &yyActionTable[215], 2, 710 }, + { &yyActionTable[217], 2, 701 }, + { &yyActionTable[219], 2, 703 }, + { &yyActionTable[221], 2, 691 }, + { &yyActionTable[223], 2, 705 }, + { &yyActionTable[225], 0, 662 }, + { &yyActionTable[225], 4, 842 }, + { &yyActionTable[229], 0, 592 }, + { &yyActionTable[229], 1, 842 }, + { &yyActionTable[230], 0, 593 }, + { &yyActionTable[230], 1, 842 }, + { &yyActionTable[231], 0, 594 }, + { &yyActionTable[231], 2, 706 }, + { &yyActionTable[233], 4, 842 }, + { &yyActionTable[237], 0, 707 }, + { &yyActionTable[237], 4, 842 }, + { &yyActionTable[241], 0, 708 }, + { &yyActionTable[241], 1, 842 }, + { &yyActionTable[242], 17, 842 }, + { &yyActionTable[259], 1, 692 }, + { &yyActionTable[260], 16, 842 }, + { &yyActionTable[276], 2, 699 }, + { &yyActionTable[278], 3, 698 }, + { &yyActionTable[281], 0, 693 }, + { &yyActionTable[281], 2, 842 }, + { &yyActionTable[283], 0, 580 }, + { &yyActionTable[283], 0, 700 }, + { &yyActionTable[283], 28, 695 }, + { &yyActionTable[311], 0, 731 }, + { &yyActionTable[311], 15, 842 }, + { &yyActionTable[326], 0, 726 }, + { &yyActionTable[326], 1, 842 }, + { &yyActionTable[327], 4, 842 }, + { &yyActionTable[331], 1, 729 }, + { &yyActionTable[332], 4, 842 }, + { &yyActionTable[336], 0, 730 }, + { &yyActionTable[336], 26, 737 }, + { &yyActionTable[362], 15, 842 }, + { &yyActionTable[377], 27, 738 }, + { &yyActionTable[404], 15, 842 }, + { &yyActionTable[419], 12, 739 }, + { &yyActionTable[431], 15, 842 }, + { &yyActionTable[446], 12, 740 }, + { &yyActionTable[458], 15, 842 }, + { &yyActionTable[473], 12, 741 }, + { &yyActionTable[485], 15, 842 }, + { &yyActionTable[500], 12, 742 }, + { &yyActionTable[512], 15, 842 }, + { &yyActionTable[527], 16, 743 }, + { &yyActionTable[543], 15, 842 }, + { &yyActionTable[558], 16, 744 }, + { &yyActionTable[574], 15, 842 }, + { &yyActionTable[589], 8, 745 }, + { &yyActionTable[597], 15, 842 }, + { &yyActionTable[612], 8, 746 }, + { &yyActionTable[620], 15, 842 }, + { &yyActionTable[635], 8, 747 }, + { &yyActionTable[643], 15, 842 }, + { &yyActionTable[658], 8, 748 }, + { &yyActionTable[666], 15, 842 }, + { &yyActionTable[681], 16, 749 }, + { &yyActionTable[697], 6, 842 }, + { &yyActionTable[703], 15, 842 }, + { &yyActionTable[718], 16, 750 }, + { &yyActionTable[734], 0, 751 }, + { &yyActionTable[734], 0, 752 }, + { &yyActionTable[734], 15, 842 }, + { &yyActionTable[749], 6, 753 }, + { &yyActionTable[755], 15, 842 }, + { &yyActionTable[770], 6, 754 }, + { &yyActionTable[776], 15, 842 }, + { &yyActionTable[791], 3, 755 }, + { &yyActionTable[794], 15, 842 }, + { &yyActionTable[809], 3, 756 }, + { &yyActionTable[812], 15, 842 }, + { &yyActionTable[827], 3, 757 }, + { &yyActionTable[830], 15, 842 }, + { &yyActionTable[845], 2, 758 }, + { &yyActionTable[847], 0, 759 }, + { &yyActionTable[847], 2, 842 }, + { &yyActionTable[849], 0, 760 }, + { &yyActionTable[849], 1, 842 }, + { &yyActionTable[850], 0, 763 }, + { &yyActionTable[850], 0, 761 }, + { &yyActionTable[850], 15, 842 }, + { &yyActionTable[865], 28, 842 }, + { &yyActionTable[893], 15, 842 }, + { &yyActionTable[908], 16, 769 }, + { &yyActionTable[924], 1, 842 }, + { &yyActionTable[925], 20, 785 }, + { &yyActionTable[945], 5, 842 }, + { &yyActionTable[950], 2, 842 }, + { &yyActionTable[952], 1, 842 }, + { &yyActionTable[953], 1, 842 }, + { &yyActionTable[954], 1, 842 }, + { &yyActionTable[955], 0, 772 }, + { &yyActionTable[955], 28, 784 }, + { &yyActionTable[983], 0, 732 }, + { &yyActionTable[983], 0, 733 }, + { &yyActionTable[983], 15, 842 }, + { &yyActionTable[998], 26, 764 }, + { &yyActionTable[1024], 15, 842 }, + { &yyActionTable[1039], 2, 765 }, + { &yyActionTable[1041], 15, 842 }, + { &yyActionTable[1056], 2, 766 }, + { &yyActionTable[1058], 15, 842 }, + { &yyActionTable[1073], 2, 767 }, + { &yyActionTable[1075], 17, 842 }, + { &yyActionTable[1092], 29, 842 }, + { &yyActionTable[1121], 2, 842 }, + { &yyActionTable[1123], 4, 842 }, + { &yyActionTable[1127], 1, 842 }, + { &yyActionTable[1128], 0, 775 }, + { &yyActionTable[1128], 15, 842 }, + { &yyActionTable[1143], 29, 842 }, + { &yyActionTable[1172], 15, 842 }, + { &yyActionTable[1187], 28, 776 }, + { &yyActionTable[1215], 1, 842 }, + { &yyActionTable[1216], 4, 842 }, + { &yyActionTable[1220], 1, 842 }, + { &yyActionTable[1221], 0, 833 }, + { &yyActionTable[1221], 1, 842 }, + { &yyActionTable[1222], 4, 842 }, + { &yyActionTable[1226], 1, 842 }, + { &yyActionTable[1227], 0, 834 }, + { &yyActionTable[1227], 1, 842 }, + { &yyActionTable[1228], 4, 842 }, + { &yyActionTable[1232], 1, 842 }, + { &yyActionTable[1233], 0, 835 }, + { &yyActionTable[1233], 1, 842 }, + { &yyActionTable[1234], 4, 842 }, + { &yyActionTable[1238], 1, 842 }, + { &yyActionTable[1239], 0, 836 }, + { &yyActionTable[1239], 15, 842 }, + { &yyActionTable[1254], 29, 842 }, + { &yyActionTable[1283], 15, 842 }, + { &yyActionTable[1298], 29, 842 }, + { &yyActionTable[1327], 15, 842 }, + { &yyActionTable[1342], 28, 777 }, + { &yyActionTable[1370], 2, 842 }, + { &yyActionTable[1372], 0, 771 }, + { &yyActionTable[1372], 16, 785 }, + { &yyActionTable[1388], 0, 782 }, + { &yyActionTable[1388], 0, 783 }, + { &yyActionTable[1388], 0, 762 }, + { &yyActionTable[1388], 15, 842 }, + { &yyActionTable[1403], 28, 842 }, + { &yyActionTable[1431], 15, 842 }, + { &yyActionTable[1446], 26, 770 }, + { &yyActionTable[1472], 1, 842 }, + { &yyActionTable[1473], 20, 785 }, + { &yyActionTable[1493], 5, 842 }, + { &yyActionTable[1498], 0, 774 }, + { &yyActionTable[1498], 2, 842 }, + { &yyActionTable[1500], 0, 773 }, + { &yyActionTable[1500], 2, 699 }, + { &yyActionTable[1502], 3, 698 }, + { &yyActionTable[1505], 0, 694 }, + { &yyActionTable[1505], 15, 842 }, + { &yyActionTable[1520], 28, 704 }, + { &yyActionTable[1548], 1, 842 }, + { &yyActionTable[1549], 17, 785 }, + { &yyActionTable[1566], 1, 702 }, + { &yyActionTable[1567], 15, 842 }, + { &yyActionTable[1582], 28, 711 }, + { &yyActionTable[1610], 0, 666 }, + { &yyActionTable[1610], 2, 677 }, + { &yyActionTable[1612], 4, 675 }, + { &yyActionTable[1616], 0, 676 }, + { &yyActionTable[1616], 0, 682 }, + { &yyActionTable[1616], 0, 683 }, + { &yyActionTable[1616], 5, 842 }, + { &yyActionTable[1621], 0, 684 }, + { &yyActionTable[1621], 5, 842 }, + { &yyActionTable[1626], 0, 685 }, + { &yyActionTable[1626], 1, 842 }, + { &yyActionTable[1627], 0, 686 }, + { &yyActionTable[1627], 5, 842 }, + { &yyActionTable[1632], 2, 680 }, + { &yyActionTable[1634], 5, 673 }, + { &yyActionTable[1639], 0, 581 }, + { &yyActionTable[1639], 0, 582 }, + { &yyActionTable[1639], 4, 842 }, + { &yyActionTable[1643], 0, 671 }, + { &yyActionTable[1643], 0, 672 }, + { &yyActionTable[1643], 2, 688 }, + { &yyActionTable[1645], 2, 690 }, + { &yyActionTable[1647], 0, 678 }, + { &yyActionTable[1647], 1, 842 }, + { &yyActionTable[1648], 6, 842 }, + { &yyActionTable[1654], 2, 842 }, + { &yyActionTable[1656], 0, 689 }, + { &yyActionTable[1656], 5, 842 }, + { &yyActionTable[1661], 0, 791 }, + { &yyActionTable[1661], 3, 698 }, + { &yyActionTable[1664], 0, 793 }, + { &yyActionTable[1664], 0, 792 }, + { &yyActionTable[1664], 15, 842 }, + { &yyActionTable[1679], 28, 687 }, + { &yyActionTable[1707], 4, 842 }, + { &yyActionTable[1711], 0, 681 }, + { &yyActionTable[1711], 3, 842 }, + { &yyActionTable[1714], 5, 842 }, + { &yyActionTable[1719], 5, 673 }, + { &yyActionTable[1724], 2, 688 }, + { &yyActionTable[1726], 2, 690 }, + { &yyActionTable[1728], 0, 679 }, + { &yyActionTable[1728], 16, 842 }, + { &yyActionTable[1744], 33, 673 }, + { &yyActionTable[1777], 0, 668 }, + { &yyActionTable[1777], 0, 669 }, + { &yyActionTable[1777], 1, 842 }, + { &yyActionTable[1778], 5, 842 }, + { &yyActionTable[1783], 0, 670 }, + { &yyActionTable[1783], 0, 663 }, + { &yyActionTable[1783], 0, 664 }, + { &yyActionTable[1783], 0, 768 }, + { &yyActionTable[1783], 29, 842 }, + { &yyActionTable[1812], 0, 725 }, + { &yyActionTable[1812], 2, 842 }, + { &yyActionTable[1814], 0, 735 }, + { &yyActionTable[1814], 1, 842 }, + { &yyActionTable[1815], 0, 736 }, + { &yyActionTable[1815], 29, 842 }, + { &yyActionTable[1844], 2, 643 }, + { &yyActionTable[1846], 0, 612 }, + { &yyActionTable[1846], 4, 842 }, + { &yyActionTable[1850], 2, 789 }, + { &yyActionTable[1852], 1, 616 }, + { &yyActionTable[1853], 3, 613 }, + { &yyActionTable[1856], 0, 617 }, + { &yyActionTable[1856], 4, 842 }, + { &yyActionTable[1860], 0, 618 }, + { &yyActionTable[1860], 3, 842 }, + { &yyActionTable[1863], 4, 842 }, + { &yyActionTable[1867], 0, 619 }, + { &yyActionTable[1867], 2, 842 }, + { &yyActionTable[1869], 0, 622 }, + { &yyActionTable[1869], 0, 623 }, + { &yyActionTable[1869], 0, 624 }, + { &yyActionTable[1869], 0, 625 }, + { &yyActionTable[1869], 4, 842 }, + { &yyActionTable[1873], 0, 620 }, + { &yyActionTable[1873], 4, 842 }, + { &yyActionTable[1877], 0, 621 }, + { &yyActionTable[1877], 6, 842 }, + { &yyActionTable[1883], 2, 842 }, + { &yyActionTable[1885], 0, 790 }, + { &yyActionTable[1885], 0, 614 }, + { &yyActionTable[1885], 2, 842 }, + { &yyActionTable[1887], 0, 615 }, + { &yyActionTable[1887], 2, 628 }, + { &yyActionTable[1889], 0, 627 }, + { &yyActionTable[1889], 0, 598 }, + { &yyActionTable[1889], 7, 842 }, + { &yyActionTable[1896], 0, 599 }, + { &yyActionTable[1896], 0, 600 }, + { &yyActionTable[1896], 0, 601 }, + { &yyActionTable[1896], 2, 842 }, + { &yyActionTable[1898], 0, 602 }, + { &yyActionTable[1898], 0, 605 }, + { &yyActionTable[1898], 2, 842 }, + { &yyActionTable[1900], 0, 603 }, + { &yyActionTable[1900], 0, 606 }, + { &yyActionTable[1900], 0, 604 }, + { &yyActionTable[1900], 0, 607 }, + { &yyActionTable[1900], 4, 587 }, + { &yyActionTable[1904], 4, 842 }, + { &yyActionTable[1908], 2, 842 }, + { &yyActionTable[1910], 0, 588 }, + { &yyActionTable[1910], 4, 842 }, + { &yyActionTable[1914], 1, 842 }, + { &yyActionTable[1915], 0, 589 }, + { &yyActionTable[1915], 0, 591 }, + { &yyActionTable[1915], 0, 590 }, + { &yyActionTable[1915], 0, 579 }, + { &yyActionTable[1915], 8, 842 }, + { &yyActionTable[1923], 6, 842 }, + { &yyActionTable[1929], 0, 633 }, + { &yyActionTable[1929], 4, 842 }, + { &yyActionTable[1933], 0, 636 }, + { &yyActionTable[1933], 1, 842 }, + { &yyActionTable[1934], 1, 842 }, + { &yyActionTable[1935], 6, 842 }, + { &yyActionTable[1941], 2, 842 }, + { &yyActionTable[1943], 2, 643 }, + { &yyActionTable[1945], 0, 637 }, + { &yyActionTable[1945], 1, 842 }, + { &yyActionTable[1946], 6, 842 }, + { &yyActionTable[1952], 2, 842 }, + { &yyActionTable[1954], 2, 643 }, + { &yyActionTable[1956], 0, 638 }, + { &yyActionTable[1956], 15, 842 }, + { &yyActionTable[1971], 30, 643 }, + { &yyActionTable[2001], 0, 639 }, + { &yyActionTable[2001], 1, 842 }, + { &yyActionTable[2002], 1, 842 }, + { &yyActionTable[2003], 6, 842 }, + { &yyActionTable[2009], 2, 842 }, + { &yyActionTable[2011], 1, 842 }, + { &yyActionTable[2012], 4, 842 }, + { &yyActionTable[2016], 2, 789 }, + { &yyActionTable[2018], 1, 616 }, + { &yyActionTable[2019], 7, 641 }, + { &yyActionTable[2026], 1, 842 }, + { &yyActionTable[2027], 0, 640 }, + { &yyActionTable[2027], 0, 642 }, + { &yyActionTable[2027], 0, 634 }, + { &yyActionTable[2027], 0, 635 }, + { &yyActionTable[2027], 0, 577 }, + { &yyActionTable[2027], 3, 842 }, + { &yyActionTable[2030], 5, 842 }, + { &yyActionTable[2035], 3, 573 }, + { &yyActionTable[2038], 6, 842 }, + { &yyActionTable[2044], 4, 842 }, + { &yyActionTable[2048], 0, 571 }, + { &yyActionTable[2048], 4, 842 }, + { &yyActionTable[2052], 1, 842 }, + { &yyActionTable[2053], 3, 842 }, + { &yyActionTable[2056], 5, 842 }, + { &yyActionTable[2061], 1, 842 }, + { &yyActionTable[2062], 4, 842 }, + { &yyActionTable[2066], 1, 842 }, + { &yyActionTable[2067], 4, 842 }, + { &yyActionTable[2071], 3, 842 }, + { &yyActionTable[2074], 1, 842 }, + { &yyActionTable[2075], 6, 842 }, + { &yyActionTable[2081], 2, 842 }, + { &yyActionTable[2083], 3, 842 }, + { &yyActionTable[2086], 1, 842 }, + { &yyActionTable[2087], 1, 842 }, + { &yyActionTable[2088], 4, 842 }, + { &yyActionTable[2092], 4, 816 }, + { &yyActionTable[2096], 4, 842 }, + { &yyActionTable[2100], 1, 842 }, + { &yyActionTable[2101], 4, 842 }, + { &yyActionTable[2105], 2, 680 }, + { &yyActionTable[2107], 2, 821 }, + { &yyActionTable[2109], 3, 842 }, + { &yyActionTable[2112], 1, 842 }, + { &yyActionTable[2113], 15, 842 }, + { &yyActionTable[2128], 29, 842 }, + { &yyActionTable[2157], 1, 842 }, + { &yyActionTable[2158], 2, 842 }, + { &yyActionTable[2160], 0, 822 }, + { &yyActionTable[2160], 0, 823 }, + { &yyActionTable[2160], 1, 842 }, + { &yyActionTable[2161], 1, 842 }, + { &yyActionTable[2162], 2, 842 }, + { &yyActionTable[2164], 5, 842 }, + { &yyActionTable[2169], 2, 842 }, + { &yyActionTable[2171], 4, 842 }, + { &yyActionTable[2175], 0, 723 }, + { &yyActionTable[2175], 0, 724 }, + { &yyActionTable[2175], 0, 813 }, + { &yyActionTable[2175], 0, 814 }, + { &yyActionTable[2175], 1, 842 }, + { &yyActionTable[2176], 0, 815 }, + { &yyActionTable[2176], 0, 572 }, + { &yyActionTable[2176], 1, 842 }, + { &yyActionTable[2177], 9, 842 }, + { &yyActionTable[2186], 5, 842 }, + { &yyActionTable[2191], 1, 842 }, + { &yyActionTable[2192], 1, 842 }, + { &yyActionTable[2193], 1, 842 }, + { &yyActionTable[2194], 9, 842 }, + { &yyActionTable[2203], 1, 842 }, + { &yyActionTable[2204], 2, 645 }, + { &yyActionTable[2206], 6, 842 }, + { &yyActionTable[2212], 0, 646 }, + { &yyActionTable[2212], 4, 842 }, + { &yyActionTable[2216], 1, 842 }, + { &yyActionTable[2217], 5, 842 }, + { &yyActionTable[2222], 4, 842 }, + { &yyActionTable[2226], 4, 842 }, + { &yyActionTable[2230], 1, 842 }, + { &yyActionTable[2231], 15, 842 }, + { &yyActionTable[2246], 28, 713 }, + { &yyActionTable[2274], 1, 842 }, + { &yyActionTable[2275], 1, 842 }, + { &yyActionTable[2276], 15, 842 }, + { &yyActionTable[2291], 28, 714 }, + { &yyActionTable[2319], 3, 842 }, + { &yyActionTable[2322], 1, 842 }, + { &yyActionTable[2323], 4, 842 }, + { &yyActionTable[2327], 2, 721 }, + { &yyActionTable[2329], 5, 842 }, + { &yyActionTable[2334], 2, 842 }, + { &yyActionTable[2336], 0, 722 }, + { &yyActionTable[2336], 4, 842 }, + { &yyActionTable[2340], 5, 842 }, + { &yyActionTable[2345], 1, 842 }, + { &yyActionTable[2346], 16, 842 }, + { &yyActionTable[2362], 2, 842 }, + { &yyActionTable[2364], 15, 842 }, + { &yyActionTable[2379], 28, 719 }, + { &yyActionTable[2407], 1, 842 }, + { &yyActionTable[2408], 28, 720 }, + { &yyActionTable[2436], 1, 842 }, + { &yyActionTable[2437], 4, 842 }, + { &yyActionTable[2441], 3, 842 }, + { &yyActionTable[2444], 1, 842 }, + { &yyActionTable[2445], 4, 842 }, + { &yyActionTable[2449], 4, 842 }, + { &yyActionTable[2453], 1, 842 }, + { &yyActionTable[2454], 4, 842 }, + { &yyActionTable[2458], 1, 842 }, + { &yyActionTable[2459], 4, 842 }, + { &yyActionTable[2463], 3, 842 }, + { &yyActionTable[2466], 1, 842 }, + { &yyActionTable[2467], 4, 842 }, + { &yyActionTable[2471], 3, 842 }, + { &yyActionTable[2474], 1, 842 }, + { &yyActionTable[2475], 5, 842 }, + { &yyActionTable[2480], 1, 842 }, + { &yyActionTable[2481], 4, 842 }, + { &yyActionTable[2485], 2, 680 }, + { &yyActionTable[2487], 3, 842 }, + { &yyActionTable[2490], 1, 842 }, + { &yyActionTable[2491], 2, 645 }, + { &yyActionTable[2493], 4, 842 }, + { &yyActionTable[2497], 3, 842 }, + { &yyActionTable[2500], 1, 842 }, + { &yyActionTable[2501], 5, 842 }, + { &yyActionTable[2506], 4, 842 }, + { &yyActionTable[2510], 1, 842 }, + { &yyActionTable[2511], 1, 842 }, + { &yyActionTable[2512], 4, 842 }, + { &yyActionTable[2516], 2, 680 }, + { &yyActionTable[2518], 2, 721 }, + { &yyActionTable[2520], 4, 842 }, + { &yyActionTable[2524], 5, 842 }, + { &yyActionTable[2529], 1, 842 }, + { &yyActionTable[2530], 16, 842 }, + { &yyActionTable[2546], 2, 842 }, + { &yyActionTable[2548], 1, 842 }, + { &yyActionTable[2549], 3, 842 }, + { &yyActionTable[2552], 1, 842 }, + { &yyActionTable[2553], 1, 842 }, + { &yyActionTable[2554], 2, 645 }, + { &yyActionTable[2556], 4, 842 }, + { &yyActionTable[2560], 3, 842 }, + { &yyActionTable[2563], 1, 842 }, + { &yyActionTable[2564], 4, 842 }, + { &yyActionTable[2568], 2, 842 }, + { &yyActionTable[2570], 1, 842 }, + { &yyActionTable[2571], 1, 842 }, + { &yyActionTable[2572], 1, 842 }, + { &yyActionTable[2573], 5, 842 }, + { &yyActionTable[2578], 1, 842 }, + { &yyActionTable[2579], 3, 842 }, + { &yyActionTable[2582], 3, 842 }, + { &yyActionTable[2585], 10, 810 }, + { &yyActionTable[2595], 1, 842 }, + { &yyActionTable[2596], 1, 842 }, + { &yyActionTable[2597], 1, 842 }, + { &yyActionTable[2598], 1, 842 }, + { &yyActionTable[2599], 3, 842 }, + { &yyActionTable[2602], 1, 842 }, + { &yyActionTable[2603], 1, 842 }, + { &yyActionTable[2604], 1, 842 }, + { &yyActionTable[2605], 3, 842 }, + { &yyActionTable[2608], 1, 842 }, + { &yyActionTable[2609], 0, 809 }, + { &yyActionTable[2609], 4, 842 }, + { &yyActionTable[2613], 1, 842 }, + { &yyActionTable[2614], 1, 842 }, + { &yyActionTable[2615], 2, 840 }, + { &yyActionTable[2617], 3, 842 }, + { &yyActionTable[2620], 1, 842 }, + { &yyActionTable[2621], 4, 842 }, + { &yyActionTable[2625], 1, 842 }, + { &yyActionTable[2626], 0, 839 }, + { &yyActionTable[2626], 2, 840 }, + { &yyActionTable[2628], 4, 842 }, + { &yyActionTable[2632], 1, 842 }, + { &yyActionTable[2633], 0, 559 }, + { &yyActionTable[2633], 0, 561 }, + { &yyActionTable[2633], 0, 556 }, +}; + +/* The next table maps tokens into fallback tokens. If a construct +** like the following: +** +** %fallback ID X Y Z. +** +** appears in the grammer, then ID becomes a fallback token for X, Y, +** and Z. Whenever one of the tokens X, Y, or Z is input to the parser +** but it does not parse, the type of the token is changed to ID and +** the parse is retried before an error is thrown. +*/ +#ifdef YYFALLBACK +static const YYCODETYPE yyFallback[] = { + 0, /* $ => nothing */ + 59, /* ABORT => ID */ + 59, /* AFTER => ID */ + 0, /* AGG_FUNCTION => nothing */ + 0, /* ALL => nothing */ + 0, /* AND => nothing */ + 0, /* AS => nothing */ + 59, /* ASC => ID */ + 59, /* ATTACH => ID */ + 59, /* BEFORE => ID */ + 59, /* BEGIN => ID */ + 0, /* BETWEEN => nothing */ + 0, /* BITAND => nothing */ + 0, /* BITNOT => nothing */ + 0, /* BITOR => nothing */ + 0, /* BY => nothing */ + 59, /* CASCADE => ID */ + 0, /* CASE => nothing */ + 0, /* CHECK => nothing */ + 59, /* CLUSTER => ID */ + 0, /* COLLATE => nothing */ + 0, /* COLUMN => nothing */ + 0, /* COMMA => nothing */ + 0, /* COMMENT => nothing */ + 0, /* COMMIT => nothing */ + 0, /* CONCAT => nothing */ + 59, /* CONFLICT => ID */ + 0, /* CONSTRAINT => nothing */ + 59, /* COPY => ID */ + 0, /* CREATE => nothing */ + 59, /* DATABASE => ID */ + 0, /* DEFAULT => nothing */ + 0, /* DEFERRABLE => nothing */ + 59, /* DEFERRED => ID */ + 0, /* DELETE => nothing */ + 59, /* DELIMITERS => ID */ + 59, /* DESC => ID */ + 59, /* DETACH => ID */ + 0, /* DISTINCT => nothing */ + 0, /* DOT => nothing */ + 0, /* DROP => nothing */ + 59, /* EACH => ID */ + 0, /* ELSE => nothing */ + 59, /* END => ID */ + 0, /* END_OF_FILE => nothing */ + 0, /* EQ => nothing */ + 0, /* EXCEPT => nothing */ + 59, /* EXPLAIN => ID */ + 59, /* FAIL => ID */ + 0, /* FLOAT => nothing */ + 59, /* FOR => ID */ + 0, /* FOREIGN => nothing */ + 0, /* FROM => nothing */ + 0, /* FUNCTION => nothing */ + 0, /* GE => nothing */ + 0, /* GLOB => nothing */ + 0, /* GROUP => nothing */ + 0, /* GT => nothing */ + 0, /* HAVING => nothing */ + 0, /* ID => nothing */ + 59, /* IGNORE => ID */ + 0, /* ILLEGAL => nothing */ + 59, /* IMMEDIATE => ID */ + 0, /* IN => nothing */ + 0, /* INDEX => nothing */ + 59, /* INITIALLY => ID */ + 0, /* INSERT => nothing */ + 59, /* INSTEAD => ID */ + 0, /* INTEGER => nothing */ + 0, /* INTERSECT => nothing */ + 0, /* INTO => nothing */ + 0, /* IS => nothing */ + 0, /* ISNULL => nothing */ + 0, /* JOIN => nothing */ + 0, /* JOIN_KW => nothing */ + 59, /* KEY => ID */ + 0, /* LE => nothing */ + 0, /* LIKE => nothing */ + 0, /* LIMIT => nothing */ + 0, /* LP => nothing */ + 0, /* LSHIFT => nothing */ + 0, /* LT => nothing */ + 59, /* MATCH => ID */ + 0, /* MINUS => nothing */ + 0, /* NE => nothing */ + 0, /* NOT => nothing */ + 0, /* NOTNULL => nothing */ + 0, /* NULL => nothing */ + 59, /* OF => ID */ + 59, /* OFFSET => ID */ + 0, /* ON => nothing */ + 0, /* OR => nothing */ + 0, /* ORACLE_OUTER_JOIN => nothing */ + 0, /* ORDER => nothing */ + 0, /* PLUS => nothing */ + 59, /* PRAGMA => ID */ + 0, /* PRIMARY => nothing */ + 59, /* RAISE => ID */ + 0, /* REFERENCES => nothing */ + 0, /* REM => nothing */ + 59, /* REPLACE => ID */ + 59, /* RESTRICT => ID */ + 0, /* ROLLBACK => nothing */ + 59, /* ROW => ID */ + 0, /* RP => nothing */ + 0, /* RSHIFT => nothing */ + 0, /* SELECT => nothing */ + 0, /* SEMI => nothing */ + 0, /* SET => nothing */ + 0, /* SLASH => nothing */ + 0, /* SPACE => nothing */ + 0, /* STAR => nothing */ + 59, /* STATEMENT => ID */ + 0, /* STRING => nothing */ + 0, /* TABLE => nothing */ + 59, /* TEMP => ID */ + 0, /* THEN => nothing */ + 0, /* TRANSACTION => nothing */ + 59, /* TRIGGER => ID */ + 0, /* UMINUS => nothing */ + 0, /* UNCLOSED_STRING => nothing */ + 0, /* UNION => nothing */ + 0, /* UNIQUE => nothing */ + 0, /* UPDATE => nothing */ + 0, /* UPLUS => nothing */ + 0, /* USING => nothing */ + 59, /* VACUUM => ID */ + 0, /* VALUES => nothing */ + 59, /* VIEW => ID */ + 0, /* WHEN => nothing */ + 0, /* WHERE => nothing */ +}; +#endif /* YYFALLBACK */ + +/* The following structure represents a single element of the +** parser's stack. Information stored includes: +** +** + The state number for the parser at this level of the stack. +** +** + The value of the token stored at this level of the stack. +** (In other words, the "major" token.) +** +** + The semantic value stored at this level of the stack. This is +** the information used by the action routines in the grammar. +** It is sometimes called the "minor" token. +*/ +struct yyStackEntry { + int stateno; /* The state-number */ + int major; /* The major token value. This is the code + ** number for the token at this stack level */ + YYMINORTYPE minor; /* The user-supplied minor token value. This + ** is the value of the token */ +}; +typedef struct yyStackEntry yyStackEntry; + +/* The state of the parser is completely contained in an instance of +** the following structure */ +struct yyParser { + int yyidx; /* Index of top element in stack */ + int yyerrcnt; /* Shifts left before out of the error */ + yyStackEntry *yytop; /* Pointer to the top stack element */ + sqliteParserARG_SDECL /* A place to hold %extra_argument */ + yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ +}; +typedef struct yyParser yyParser; + +#ifndef NDEBUG +#include +static FILE *yyTraceFILE = 0; +static char *yyTracePrompt = 0; +#endif /* NDEBUG */ + +#ifndef NDEBUG +/* +** Turn parser tracing on by giving a stream to which to write the trace +** and a prompt to preface each trace message. Tracing is turned off +** by making either argument NULL +** +** Inputs: +**
    +**
  • A FILE* to which trace output should be written. +** If NULL, then tracing is turned off. +**
  • A prefix string written at the beginning of every +** line of trace output. If NULL, then tracing is +** turned off. +**
+** +** Outputs: +** None. +*/ +void sqliteParserTrace(FILE *TraceFILE, char *zTracePrompt){ + yyTraceFILE = TraceFILE; + yyTracePrompt = zTracePrompt; + if( yyTraceFILE==0 ) yyTracePrompt = 0; + else if( yyTracePrompt==0 ) yyTraceFILE = 0; +} +#endif /* NDEBUG */ + +#ifndef NDEBUG +/* For tracing shifts, the names of all terminals and nonterminals +** are required. The following table supplies these names */ +static const char *yyTokenName[] = { + "$", "ABORT", "AFTER", "AGG_FUNCTION", + "ALL", "AND", "AS", "ASC", + "ATTACH", "BEFORE", "BEGIN", "BETWEEN", + "BITAND", "BITNOT", "BITOR", "BY", + "CASCADE", "CASE", "CHECK", "CLUSTER", + "COLLATE", "COLUMN", "COMMA", "COMMENT", + "COMMIT", "CONCAT", "CONFLICT", "CONSTRAINT", + "COPY", "CREATE", "DATABASE", "DEFAULT", + "DEFERRABLE", "DEFERRED", "DELETE", "DELIMITERS", + "DESC", "DETACH", "DISTINCT", "DOT", + "DROP", "EACH", "ELSE", "END", + "END_OF_FILE", "EQ", "EXCEPT", "EXPLAIN", + "FAIL", "FLOAT", "FOR", "FOREIGN", + "FROM", "FUNCTION", "GE", "GLOB", + "GROUP", "GT", "HAVING", "ID", + "IGNORE", "ILLEGAL", "IMMEDIATE", "IN", + "INDEX", "INITIALLY", "INSERT", "INSTEAD", + "INTEGER", "INTERSECT", "INTO", "IS", + "ISNULL", "JOIN", "JOIN_KW", "KEY", + "LE", "LIKE", "LIMIT", "LP", + "LSHIFT", "LT", "MATCH", "MINUS", + "NE", "NOT", "NOTNULL", "NULL", + "OF", "OFFSET", "ON", "OR", + "ORACLE_OUTER_JOIN", "ORDER", "PLUS", "PRAGMA", + "PRIMARY", "RAISE", "REFERENCES", "REM", + "REPLACE", "RESTRICT", "ROLLBACK", "ROW", + "RP", "RSHIFT", "SELECT", "SEMI", + "SET", "SLASH", "SPACE", "STAR", + "STATEMENT", "STRING", "TABLE", "TEMP", + "THEN", "TRANSACTION", "TRIGGER", "UMINUS", + "UNCLOSED_STRING", "UNION", "UNIQUE", "UPDATE", + "UPLUS", "USING", "VACUUM", "VALUES", + "VIEW", "WHEN", "WHERE", "as", + "carg", "carglist", "case_else", "case_exprlist", + "case_operand", "ccons", "cmd", "cmdlist", + "cmdx", "collate", "column", "columnid", + "columnlist", "conslist", "conslist_opt", "create_table", + "create_table_args", "database_kw_opt", "dbnm", "defer_subclause", + "defer_subclause_opt", "distinct", "ecmd", "error", + "explain", "expr", "expritem", "exprlist", + "foreach_clause", "from", "groupby_opt", "having_opt", + "id", "ids", "idxitem", "idxlist", + "idxlist_opt", "init_deferred_pred_opt", "input", "inscollist", + "inscollist_opt", "insert_cmd", "itemlist", "joinop", + "joinop2", "likeop", "limit_opt", "minus_num", + "multiselect_op", "nm", "number", "on_opt", + "onconf", "oneselect", "orconf", "orderby_opt", + "plus_num", "plus_opt", "refact", "refarg", + "refargs", "resolvetype", "sclp", "selcollist", + "select", "seltablist", "setlist", "signed", + "sortitem", "sortlist", "sortorder", "stl_prefix", + "tcons", "temp", "trans_opt", "trigger_cmd", + "trigger_cmd_list", "trigger_decl", "trigger_event", "trigger_time", + "type", "typename", "uniqueflag", "using_opt", + "when_clause", "where_opt", +}; +#endif /* NDEBUG */ + +#ifndef NDEBUG +/* For tracing reduce actions, the names of all rules are required. +*/ +static const char *yyRuleName[] = { + /* 0 */ "input ::= cmdlist", + /* 1 */ "cmdlist ::= ecmd", + /* 2 */ "cmdlist ::= cmdlist ecmd", + /* 3 */ "ecmd ::= explain cmdx SEMI", + /* 4 */ "ecmd ::= SEMI", + /* 5 */ "cmdx ::= cmd", + /* 6 */ "explain ::= EXPLAIN", + /* 7 */ "explain ::=", + /* 8 */ "cmd ::= BEGIN trans_opt onconf", + /* 9 */ "trans_opt ::=", + /* 10 */ "trans_opt ::= TRANSACTION", + /* 11 */ "trans_opt ::= TRANSACTION nm", + /* 12 */ "cmd ::= COMMIT trans_opt", + /* 13 */ "cmd ::= END trans_opt", + /* 14 */ "cmd ::= ROLLBACK trans_opt", + /* 15 */ "cmd ::= create_table create_table_args", + /* 16 */ "create_table ::= CREATE temp TABLE nm", + /* 17 */ "temp ::= TEMP", + /* 18 */ "temp ::=", + /* 19 */ "create_table_args ::= LP columnlist conslist_opt RP", + /* 20 */ "create_table_args ::= AS select", + /* 21 */ "columnlist ::= columnlist COMMA column", + /* 22 */ "columnlist ::= column", + /* 23 */ "column ::= columnid type carglist", + /* 24 */ "columnid ::= nm", + /* 25 */ "id ::= ID", + /* 26 */ "ids ::= ID", + /* 27 */ "ids ::= STRING", + /* 28 */ "nm ::= ID", + /* 29 */ "nm ::= STRING", + /* 30 */ "nm ::= JOIN_KW", + /* 31 */ "type ::=", + /* 32 */ "type ::= typename", + /* 33 */ "type ::= typename LP signed RP", + /* 34 */ "type ::= typename LP signed COMMA signed RP", + /* 35 */ "typename ::= ids", + /* 36 */ "typename ::= typename ids", + /* 37 */ "signed ::= INTEGER", + /* 38 */ "signed ::= PLUS INTEGER", + /* 39 */ "signed ::= MINUS INTEGER", + /* 40 */ "carglist ::= carglist carg", + /* 41 */ "carglist ::=", + /* 42 */ "carg ::= CONSTRAINT nm ccons", + /* 43 */ "carg ::= ccons", + /* 44 */ "carg ::= DEFAULT STRING", + /* 45 */ "carg ::= DEFAULT ID", + /* 46 */ "carg ::= DEFAULT INTEGER", + /* 47 */ "carg ::= DEFAULT PLUS INTEGER", + /* 48 */ "carg ::= DEFAULT MINUS INTEGER", + /* 49 */ "carg ::= DEFAULT FLOAT", + /* 50 */ "carg ::= DEFAULT PLUS FLOAT", + /* 51 */ "carg ::= DEFAULT MINUS FLOAT", + /* 52 */ "carg ::= DEFAULT NULL", + /* 53 */ "ccons ::= NULL onconf", + /* 54 */ "ccons ::= NOT NULL onconf", + /* 55 */ "ccons ::= PRIMARY KEY sortorder onconf", + /* 56 */ "ccons ::= UNIQUE onconf", + /* 57 */ "ccons ::= CHECK LP expr RP onconf", + /* 58 */ "ccons ::= REFERENCES nm idxlist_opt refargs", + /* 59 */ "ccons ::= defer_subclause", + /* 60 */ "ccons ::= COLLATE id", + /* 61 */ "refargs ::=", + /* 62 */ "refargs ::= refargs refarg", + /* 63 */ "refarg ::= MATCH nm", + /* 64 */ "refarg ::= ON DELETE refact", + /* 65 */ "refarg ::= ON UPDATE refact", + /* 66 */ "refarg ::= ON INSERT refact", + /* 67 */ "refact ::= SET NULL", + /* 68 */ "refact ::= SET DEFAULT", + /* 69 */ "refact ::= CASCADE", + /* 70 */ "refact ::= RESTRICT", + /* 71 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt", + /* 72 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt", + /* 73 */ "init_deferred_pred_opt ::=", + /* 74 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED", + /* 75 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE", + /* 76 */ "conslist_opt ::=", + /* 77 */ "conslist_opt ::= COMMA conslist", + /* 78 */ "conslist ::= conslist COMMA tcons", + /* 79 */ "conslist ::= conslist tcons", + /* 80 */ "conslist ::= tcons", + /* 81 */ "tcons ::= CONSTRAINT nm", + /* 82 */ "tcons ::= PRIMARY KEY LP idxlist RP onconf", + /* 83 */ "tcons ::= UNIQUE LP idxlist RP onconf", + /* 84 */ "tcons ::= CHECK expr onconf", + /* 85 */ "tcons ::= FOREIGN KEY LP idxlist RP REFERENCES nm idxlist_opt refargs defer_subclause_opt", + /* 86 */ "defer_subclause_opt ::=", + /* 87 */ "defer_subclause_opt ::= defer_subclause", + /* 88 */ "onconf ::=", + /* 89 */ "onconf ::= ON CONFLICT resolvetype", + /* 90 */ "orconf ::=", + /* 91 */ "orconf ::= OR resolvetype", + /* 92 */ "resolvetype ::= ROLLBACK", + /* 93 */ "resolvetype ::= ABORT", + /* 94 */ "resolvetype ::= FAIL", + /* 95 */ "resolvetype ::= IGNORE", + /* 96 */ "resolvetype ::= REPLACE", + /* 97 */ "cmd ::= DROP TABLE nm", + /* 98 */ "cmd ::= CREATE temp VIEW nm AS select", + /* 99 */ "cmd ::= DROP VIEW nm", + /* 100 */ "cmd ::= select", + /* 101 */ "select ::= oneselect", + /* 102 */ "select ::= select multiselect_op oneselect", + /* 103 */ "multiselect_op ::= UNION", + /* 104 */ "multiselect_op ::= UNION ALL", + /* 105 */ "multiselect_op ::= INTERSECT", + /* 106 */ "multiselect_op ::= EXCEPT", + /* 107 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", + /* 108 */ "distinct ::= DISTINCT", + /* 109 */ "distinct ::= ALL", + /* 110 */ "distinct ::=", + /* 111 */ "sclp ::= selcollist COMMA", + /* 112 */ "sclp ::=", + /* 113 */ "selcollist ::= sclp expr as", + /* 114 */ "selcollist ::= sclp STAR", + /* 115 */ "selcollist ::= sclp nm DOT STAR", + /* 116 */ "as ::= AS nm", + /* 117 */ "as ::= ids", + /* 118 */ "as ::=", + /* 119 */ "from ::=", + /* 120 */ "from ::= FROM seltablist", + /* 121 */ "stl_prefix ::= seltablist joinop", + /* 122 */ "stl_prefix ::=", + /* 123 */ "seltablist ::= stl_prefix nm dbnm as on_opt using_opt", + /* 124 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt", + /* 125 */ "dbnm ::=", + /* 126 */ "dbnm ::= DOT nm", + /* 127 */ "joinop ::= COMMA", + /* 128 */ "joinop ::= JOIN", + /* 129 */ "joinop ::= JOIN_KW JOIN", + /* 130 */ "joinop ::= JOIN_KW nm JOIN", + /* 131 */ "joinop ::= JOIN_KW nm nm JOIN", + /* 132 */ "on_opt ::= ON expr", + /* 133 */ "on_opt ::=", + /* 134 */ "using_opt ::= USING LP idxlist RP", + /* 135 */ "using_opt ::=", + /* 136 */ "orderby_opt ::=", + /* 137 */ "orderby_opt ::= ORDER BY sortlist", + /* 138 */ "sortlist ::= sortlist COMMA sortitem collate sortorder", + /* 139 */ "sortlist ::= sortitem collate sortorder", + /* 140 */ "sortitem ::= expr", + /* 141 */ "sortorder ::= ASC", + /* 142 */ "sortorder ::= DESC", + /* 143 */ "sortorder ::=", + /* 144 */ "collate ::=", + /* 145 */ "collate ::= COLLATE id", + /* 146 */ "groupby_opt ::=", + /* 147 */ "groupby_opt ::= GROUP BY exprlist", + /* 148 */ "having_opt ::=", + /* 149 */ "having_opt ::= HAVING expr", + /* 150 */ "limit_opt ::=", + /* 151 */ "limit_opt ::= LIMIT signed", + /* 152 */ "limit_opt ::= LIMIT signed OFFSET signed", + /* 153 */ "limit_opt ::= LIMIT signed COMMA signed", + /* 154 */ "cmd ::= DELETE FROM nm dbnm where_opt", + /* 155 */ "where_opt ::=", + /* 156 */ "where_opt ::= WHERE expr", + /* 157 */ "cmd ::= UPDATE orconf nm dbnm SET setlist where_opt", + /* 158 */ "setlist ::= setlist COMMA nm EQ expr", + /* 159 */ "setlist ::= nm EQ expr", + /* 160 */ "cmd ::= insert_cmd INTO nm dbnm inscollist_opt VALUES LP itemlist RP", + /* 161 */ "cmd ::= insert_cmd INTO nm dbnm inscollist_opt select", + /* 162 */ "insert_cmd ::= INSERT orconf", + /* 163 */ "insert_cmd ::= REPLACE", + /* 164 */ "itemlist ::= itemlist COMMA expr", + /* 165 */ "itemlist ::= expr", + /* 166 */ "inscollist_opt ::=", + /* 167 */ "inscollist_opt ::= LP inscollist RP", + /* 168 */ "inscollist ::= inscollist COMMA nm", + /* 169 */ "inscollist ::= nm", + /* 170 */ "expr ::= LP expr RP", + /* 171 */ "expr ::= NULL", + /* 172 */ "expr ::= ID", + /* 173 */ "expr ::= JOIN_KW", + /* 174 */ "expr ::= nm DOT nm", + /* 175 */ "expr ::= nm DOT nm DOT nm", + /* 176 */ "expr ::= expr ORACLE_OUTER_JOIN", + /* 177 */ "expr ::= INTEGER", + /* 178 */ "expr ::= FLOAT", + /* 179 */ "expr ::= STRING", + /* 180 */ "expr ::= ID LP exprlist RP", + /* 181 */ "expr ::= ID LP STAR RP", + /* 182 */ "expr ::= expr AND expr", + /* 183 */ "expr ::= expr OR expr", + /* 184 */ "expr ::= expr LT expr", + /* 185 */ "expr ::= expr GT expr", + /* 186 */ "expr ::= expr LE expr", + /* 187 */ "expr ::= expr GE expr", + /* 188 */ "expr ::= expr NE expr", + /* 189 */ "expr ::= expr EQ expr", + /* 190 */ "expr ::= expr BITAND expr", + /* 191 */ "expr ::= expr BITOR expr", + /* 192 */ "expr ::= expr LSHIFT expr", + /* 193 */ "expr ::= expr RSHIFT expr", + /* 194 */ "expr ::= expr likeop expr", + /* 195 */ "expr ::= expr NOT likeop expr", + /* 196 */ "likeop ::= LIKE", + /* 197 */ "likeop ::= GLOB", + /* 198 */ "expr ::= expr PLUS expr", + /* 199 */ "expr ::= expr MINUS expr", + /* 200 */ "expr ::= expr STAR expr", + /* 201 */ "expr ::= expr SLASH expr", + /* 202 */ "expr ::= expr REM expr", + /* 203 */ "expr ::= expr CONCAT expr", + /* 204 */ "expr ::= expr ISNULL", + /* 205 */ "expr ::= expr IS NULL", + /* 206 */ "expr ::= expr NOTNULL", + /* 207 */ "expr ::= expr NOT NULL", + /* 208 */ "expr ::= expr IS NOT NULL", + /* 209 */ "expr ::= NOT expr", + /* 210 */ "expr ::= BITNOT expr", + /* 211 */ "expr ::= MINUS expr", + /* 212 */ "expr ::= PLUS expr", + /* 213 */ "expr ::= LP select RP", + /* 214 */ "expr ::= expr BETWEEN expr AND expr", + /* 215 */ "expr ::= expr NOT BETWEEN expr AND expr", + /* 216 */ "expr ::= expr IN LP exprlist RP", + /* 217 */ "expr ::= expr IN LP select RP", + /* 218 */ "expr ::= expr NOT IN LP exprlist RP", + /* 219 */ "expr ::= expr NOT IN 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 temp uniqueflag INDEX nm ON nm dbnm LP idxlist RP onconf", + /* 232 */ "uniqueflag ::= UNIQUE", + /* 233 */ "uniqueflag ::=", + /* 234 */ "idxlist_opt ::=", + /* 235 */ "idxlist_opt ::= LP idxlist RP", + /* 236 */ "idxlist ::= idxlist COMMA idxitem", + /* 237 */ "idxlist ::= idxitem", + /* 238 */ "idxitem ::= nm sortorder", + /* 239 */ "cmd ::= DROP INDEX nm dbnm", + /* 240 */ "cmd ::= COPY orconf nm dbnm FROM nm USING DELIMITERS STRING", + /* 241 */ "cmd ::= COPY orconf nm dbnm FROM nm", + /* 242 */ "cmd ::= VACUUM", + /* 243 */ "cmd ::= VACUUM nm", + /* 244 */ "cmd ::= PRAGMA ids EQ nm", + /* 245 */ "cmd ::= PRAGMA ids EQ ON", + /* 246 */ "cmd ::= PRAGMA ids EQ plus_num", + /* 247 */ "cmd ::= PRAGMA ids EQ minus_num", + /* 248 */ "cmd ::= PRAGMA ids LP nm RP", + /* 249 */ "cmd ::= PRAGMA ids", + /* 250 */ "plus_num ::= plus_opt number", + /* 251 */ "minus_num ::= MINUS number", + /* 252 */ "number ::= INTEGER", + /* 253 */ "number ::= FLOAT", + /* 254 */ "plus_opt ::= PLUS", + /* 255 */ "plus_opt ::=", + /* 256 */ "cmd ::= CREATE trigger_decl BEGIN trigger_cmd_list END", + /* 257 */ "trigger_decl ::= temp TRIGGER nm trigger_time trigger_event ON nm dbnm foreach_clause when_clause", + /* 258 */ "trigger_time ::= BEFORE", + /* 259 */ "trigger_time ::= AFTER", + /* 260 */ "trigger_time ::= INSTEAD OF", + /* 261 */ "trigger_time ::=", + /* 262 */ "trigger_event ::= DELETE", + /* 263 */ "trigger_event ::= INSERT", + /* 264 */ "trigger_event ::= UPDATE", + /* 265 */ "trigger_event ::= UPDATE OF inscollist", + /* 266 */ "foreach_clause ::=", + /* 267 */ "foreach_clause ::= FOR EACH ROW", + /* 268 */ "foreach_clause ::= FOR EACH STATEMENT", + /* 269 */ "when_clause ::=", + /* 270 */ "when_clause ::= WHEN expr", + /* 271 */ "trigger_cmd_list ::= trigger_cmd SEMI trigger_cmd_list", + /* 272 */ "trigger_cmd_list ::=", + /* 273 */ "trigger_cmd ::= UPDATE orconf nm SET setlist where_opt", + /* 274 */ "trigger_cmd ::= INSERT orconf INTO nm inscollist_opt VALUES LP itemlist RP", + /* 275 */ "trigger_cmd ::= INSERT orconf INTO nm inscollist_opt select", + /* 276 */ "trigger_cmd ::= DELETE FROM nm where_opt", + /* 277 */ "trigger_cmd ::= select", + /* 278 */ "expr ::= RAISE LP IGNORE RP", + /* 279 */ "expr ::= RAISE LP ROLLBACK COMMA nm RP", + /* 280 */ "expr ::= RAISE LP ABORT COMMA nm RP", + /* 281 */ "expr ::= RAISE LP FAIL COMMA nm RP", + /* 282 */ "cmd ::= DROP TRIGGER nm dbnm", + /* 283 */ "cmd ::= ATTACH database_kw_opt ids AS nm", + /* 284 */ "database_kw_opt ::= DATABASE", + /* 285 */ "database_kw_opt ::=", + /* 286 */ "cmd ::= DETACH database_kw_opt nm", +}; +#endif /* NDEBUG */ + +/* +** This function returns the symbolic name associated with a token +** value. +*/ +const char *sqliteParserTokenName(int tokenType){ +#ifndef NDEBUG + if( tokenType>0 && tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){ + return yyTokenName[tokenType]; + }else{ + return "Unknown"; + } +#else + return ""; +#endif +} + +/* +** This function allocates a new parser. +** The only argument is a pointer to a function which works like +** malloc. +** +** Inputs: +** A pointer to the function used to allocate memory. +** +** Outputs: +** A pointer to a parser. This pointer is used in subsequent calls +** to sqliteParser and sqliteParserFree. +*/ +void *sqliteParserAlloc(void *(*mallocProc)(size_t)){ + yyParser *pParser; + pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) ); + if( pParser ){ + pParser->yyidx = -1; + } + return pParser; +} + +/* The following function deletes the value associated with a +** symbol. The symbol can be either a terminal or nonterminal. +** "yymajor" is the symbol code, and "yypminor" is a pointer to +** the value. +*/ +static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){ + switch( yymajor ){ + /* Here is inserted the actions which take place when a + ** terminal or non-terminal is destroyed. This can happen + ** when the symbol is popped from the stack during a + ** reduce or during error processing or when a parser is + ** being destroyed before it is finished parsing. + ** + ** Note: during a reduce, the only symbols destroyed are those + ** which appear on the RHS of the rule, but which are not used + ** inside the C code. + */ + case 135: +#line 674 "parse.y" +{sqliteExprListDelete((yypminor->yy62));} +#line 4389 "parse.c" + break; + case 157: +#line 521 "parse.y" +{sqliteExprDelete((yypminor->yy334));} +#line 4394 "parse.c" + break; + case 158: +#line 693 "parse.y" +{sqliteExprDelete((yypminor->yy334));} +#line 4399 "parse.c" + break; + case 159: +#line 691 "parse.y" +{sqliteExprListDelete((yypminor->yy62));} +#line 4404 "parse.c" + break; + case 161: +#line 342 "parse.y" +{sqliteSrcListDelete((yypminor->yy335));} +#line 4409 "parse.c" + break; + case 162: +#line 436 "parse.y" +{sqliteExprListDelete((yypminor->yy62));} +#line 4414 "parse.c" + break; + case 163: +#line 441 "parse.y" +{sqliteExprDelete((yypminor->yy334));} +#line 4419 "parse.c" + break; + case 167: +#line 716 "parse.y" +{sqliteIdListDelete((yypminor->yy92));} +#line 4424 "parse.c" + break; + case 168: +#line 718 "parse.y" +{sqliteIdListDelete((yypminor->yy92));} +#line 4429 "parse.c" + break; + case 171: +#line 499 "parse.y" +{sqliteIdListDelete((yypminor->yy92));} +#line 4434 "parse.c" + break; + case 172: +#line 497 "parse.y" +{sqliteIdListDelete((yypminor->yy92));} +#line 4439 "parse.c" + break; + case 174: +#line 491 "parse.y" +{sqliteExprListDelete((yypminor->yy62));} +#line 4444 "parse.c" + break; + case 183: +#line 397 "parse.y" +{sqliteExprDelete((yypminor->yy334));} +#line 4449 "parse.c" + break; + case 185: +#line 277 "parse.y" +{sqliteSelectDelete((yypminor->yy11));} +#line 4454 "parse.c" + break; + case 187: +#line 408 "parse.y" +{sqliteExprListDelete((yypminor->yy62));} +#line 4459 "parse.c" + break; + case 194: +#line 313 "parse.y" +{sqliteExprListDelete((yypminor->yy62));} +#line 4464 "parse.c" + break; + case 195: +#line 311 "parse.y" +{sqliteExprListDelete((yypminor->yy62));} +#line 4469 "parse.c" + break; + case 196: +#line 275 "parse.y" +{sqliteSelectDelete((yypminor->yy11));} +#line 4474 "parse.c" + break; + case 197: +#line 338 "parse.y" +{sqliteSrcListDelete((yypminor->yy335));} +#line 4479 "parse.c" + break; + case 198: +#line 466 "parse.y" +{sqliteExprListDelete((yypminor->yy62));} +#line 4484 "parse.c" + break; + case 200: +#line 412 "parse.y" +{sqliteExprDelete((yypminor->yy334));} +#line 4489 "parse.c" + break; + case 201: +#line 410 "parse.y" +{sqliteExprListDelete((yypminor->yy62));} +#line 4494 "parse.c" + break; + case 203: +#line 340 "parse.y" +{sqliteSrcListDelete((yypminor->yy335));} +#line 4499 "parse.c" + break; + case 207: +#line 808 "parse.y" +{sqliteDeleteTriggerStep((yypminor->yy347));} +#line 4504 "parse.c" + break; + case 208: +#line 800 "parse.y" +{sqliteDeleteTriggerStep((yypminor->yy347));} +#line 4509 "parse.c" + break; + case 210: +#line 784 "parse.y" +{sqliteIdListDelete((yypminor->yy234).b);} +#line 4514 "parse.c" + break; + case 215: +#line 402 "parse.y" +{sqliteIdListDelete((yypminor->yy92));} +#line 4519 "parse.c" + break; + case 217: +#line 460 "parse.y" +{sqliteExprDelete((yypminor->yy334));} +#line 4524 "parse.c" + break; + default: break; /* If no destructor action specified: do nothing */ + } +} + +/* +** Pop the parser's stack once. +** +** If there is a destructor routine associated with the token which +** is popped from the stack, then call it. +** +** Return the major token number for the symbol popped. +*/ +static int yy_pop_parser_stack(yyParser *pParser){ + YYCODETYPE yymajor; + + if( pParser->yyidx<0 ) return 0; +#ifndef NDEBUG + if( yyTraceFILE && pParser->yyidx>=0 ){ + fprintf(yyTraceFILE,"%sPopping %s\n", + yyTracePrompt, + yyTokenName[pParser->yytop->major]); + } +#endif + yymajor = pParser->yytop->major; + yy_destructor( yymajor, &pParser->yytop->minor); + pParser->yyidx--; + pParser->yytop--; + return yymajor; +} + +/* +** Deallocate and destroy a parser. Destructors are all called for +** all stack elements before shutting the parser down. +** +** Inputs: +**
    +**
  • A pointer to the parser. This should be a pointer +** obtained from sqliteParserAlloc. +**
  • A pointer to a function used to reclaim memory obtained +** from malloc. +**
+*/ +void sqliteParserFree( + void *p, /* The parser to be deleted */ + void (*freeProc)(void*) /* Function used to reclaim memory */ +){ + yyParser *pParser = (yyParser*)p; + if( pParser==0 ) return; + while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser); + (*freeProc)((void*)pParser); +} + +/* +** Find the appropriate action for a parser given the look-ahead token. +** +** If the look-ahead token is YYNOCODE, then check to see if the action is +** independent of the look-ahead. If it is, return the action, otherwise +** return YY_NO_ACTION. +*/ +static int yy_find_parser_action( + yyParser *pParser, /* The parser */ + int iLookAhead /* The look-ahead token */ +){ + const yyStateEntry *pState; /* Appropriate entry in the state table */ + const yyActionEntry *pAction; /* Action appropriate for the look-ahead */ + int iFallback; /* Fallback token */ + + /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */ + pState = &yyStateTable[pParser->yytop->stateno]; + if( pState->nEntry==0 ){ + return pState->actionDefault; + }else if( iLookAhead!=YYNOCODE ){ + pAction = &pState->hashtbl[iLookAhead % pState->nEntry]; + while( 1 ){ + if( pAction->lookahead==iLookAhead ) return pAction->action; + if( pAction->next==0 ) break; + pAction = &pState->hashtbl[pAction->next-1]; + } +#ifdef YYFALLBACK + if( iLookAhead %s\n", + yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); + } +#endif + return yy_find_parser_action(pParser, iFallback); + } +#endif + }else if( pState->hashtbl->lookahead!=YYNOCODE ){ + return YY_NO_ACTION; + } + return pState->actionDefault; +} + +/* +** Perform a shift action. +*/ +static void yy_shift( + yyParser *yypParser, /* The parser to be shifted */ + int yyNewState, /* The new state to shift in */ + int yyMajor, /* The major token to shift in */ + YYMINORTYPE *yypMinor /* Pointer ot the minor token to shift in */ +){ + yypParser->yyidx++; + yypParser->yytop++; + if( yypParser->yyidx>=YYSTACKDEPTH ){ + sqliteParserARG_FETCH; + yypParser->yyidx--; + yypParser->yytop--; +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt); + } +#endif + while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); + /* Here code is inserted which will execute if the parser + ** stack every overflows */ + sqliteParserARG_STORE; /* Suppress warning about unused %extra_argument var */ + return; + } + yypParser->yytop->stateno = yyNewState; + yypParser->yytop->major = yyMajor; + yypParser->yytop->minor = *yypMinor; +#ifndef NDEBUG + if( yyTraceFILE && yypParser->yyidx>0 ){ + int i; + fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState); + fprintf(yyTraceFILE,"%sStack:",yyTracePrompt); + for(i=1; i<=yypParser->yyidx; i++) + fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]); + fprintf(yyTraceFILE,"\n"); + } +#endif +} + +/* The following table contains information about every rule that +** is used during the reduce. +*/ +static struct { + YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ + unsigned char nrhs; /* Number of right-hand side symbols in the rule */ +} yyRuleInfo[] = { + { 170, 1 }, + { 139, 1 }, + { 139, 2 }, + { 154, 3 }, + { 154, 1 }, + { 140, 1 }, + { 156, 1 }, + { 156, 0 }, + { 138, 3 }, + { 206, 0 }, + { 206, 1 }, + { 206, 2 }, + { 138, 2 }, + { 138, 2 }, + { 138, 2 }, + { 138, 2 }, + { 147, 4 }, + { 205, 1 }, + { 205, 0 }, + { 148, 4 }, + { 148, 2 }, + { 144, 3 }, + { 144, 1 }, + { 142, 3 }, + { 143, 1 }, + { 164, 1 }, + { 165, 1 }, + { 165, 1 }, + { 181, 1 }, + { 181, 1 }, + { 181, 1 }, + { 212, 0 }, + { 212, 1 }, + { 212, 4 }, + { 212, 6 }, + { 213, 1 }, + { 213, 2 }, + { 199, 1 }, + { 199, 2 }, + { 199, 2 }, + { 133, 2 }, + { 133, 0 }, + { 132, 3 }, + { 132, 1 }, + { 132, 2 }, + { 132, 2 }, + { 132, 2 }, + { 132, 3 }, + { 132, 3 }, + { 132, 2 }, + { 132, 3 }, + { 132, 3 }, + { 132, 2 }, + { 137, 2 }, + { 137, 3 }, + { 137, 4 }, + { 137, 2 }, + { 137, 5 }, + { 137, 4 }, + { 137, 1 }, + { 137, 2 }, + { 192, 0 }, + { 192, 2 }, + { 191, 2 }, + { 191, 3 }, + { 191, 3 }, + { 191, 3 }, + { 190, 2 }, + { 190, 2 }, + { 190, 1 }, + { 190, 1 }, + { 151, 3 }, + { 151, 2 }, + { 169, 0 }, + { 169, 2 }, + { 169, 2 }, + { 146, 0 }, + { 146, 2 }, + { 145, 3 }, + { 145, 2 }, + { 145, 1 }, + { 204, 2 }, + { 204, 6 }, + { 204, 5 }, + { 204, 3 }, + { 204, 10 }, + { 152, 0 }, + { 152, 1 }, + { 184, 0 }, + { 184, 3 }, + { 186, 0 }, + { 186, 2 }, + { 193, 1 }, + { 193, 1 }, + { 193, 1 }, + { 193, 1 }, + { 193, 1 }, + { 138, 3 }, + { 138, 6 }, + { 138, 3 }, + { 138, 1 }, + { 196, 1 }, + { 196, 3 }, + { 180, 1 }, + { 180, 2 }, + { 180, 1 }, + { 180, 1 }, + { 185, 9 }, + { 153, 1 }, + { 153, 1 }, + { 153, 0 }, + { 194, 2 }, + { 194, 0 }, + { 195, 3 }, + { 195, 2 }, + { 195, 4 }, + { 131, 2 }, + { 131, 1 }, + { 131, 0 }, + { 161, 0 }, + { 161, 2 }, + { 203, 2 }, + { 203, 0 }, + { 197, 6 }, + { 197, 7 }, + { 150, 0 }, + { 150, 2 }, + { 175, 1 }, + { 175, 1 }, + { 175, 2 }, + { 175, 3 }, + { 175, 4 }, + { 183, 2 }, + { 183, 0 }, + { 215, 4 }, + { 215, 0 }, + { 187, 0 }, + { 187, 3 }, + { 201, 5 }, + { 201, 3 }, + { 200, 1 }, + { 202, 1 }, + { 202, 1 }, + { 202, 0 }, + { 141, 0 }, + { 141, 2 }, + { 162, 0 }, + { 162, 3 }, + { 163, 0 }, + { 163, 2 }, + { 178, 0 }, + { 178, 2 }, + { 178, 4 }, + { 178, 4 }, + { 138, 5 }, + { 217, 0 }, + { 217, 2 }, + { 138, 7 }, + { 198, 5 }, + { 198, 3 }, + { 138, 9 }, + { 138, 6 }, + { 173, 2 }, + { 173, 1 }, + { 174, 3 }, + { 174, 1 }, + { 172, 0 }, + { 172, 3 }, + { 171, 3 }, + { 171, 1 }, + { 157, 3 }, + { 157, 1 }, + { 157, 1 }, + { 157, 1 }, + { 157, 3 }, + { 157, 5 }, + { 157, 2 }, + { 157, 1 }, + { 157, 1 }, + { 157, 1 }, + { 157, 4 }, + { 157, 4 }, + { 157, 3 }, + { 157, 3 }, + { 157, 3 }, + { 157, 3 }, + { 157, 3 }, + { 157, 3 }, + { 157, 3 }, + { 157, 3 }, + { 157, 3 }, + { 157, 3 }, + { 157, 3 }, + { 157, 3 }, + { 157, 3 }, + { 157, 4 }, + { 177, 1 }, + { 177, 1 }, + { 157, 3 }, + { 157, 3 }, + { 157, 3 }, + { 157, 3 }, + { 157, 3 }, + { 157, 3 }, + { 157, 2 }, + { 157, 3 }, + { 157, 2 }, + { 157, 3 }, + { 157, 4 }, + { 157, 2 }, + { 157, 2 }, + { 157, 2 }, + { 157, 2 }, + { 157, 3 }, + { 157, 5 }, + { 157, 6 }, + { 157, 5 }, + { 157, 5 }, + { 157, 6 }, + { 157, 6 }, + { 157, 5 }, + { 135, 5 }, + { 135, 4 }, + { 134, 2 }, + { 134, 0 }, + { 136, 1 }, + { 136, 0 }, + { 159, 3 }, + { 159, 1 }, + { 158, 1 }, + { 158, 0 }, + { 138, 12 }, + { 214, 1 }, + { 214, 0 }, + { 168, 0 }, + { 168, 3 }, + { 167, 3 }, + { 167, 1 }, + { 166, 2 }, + { 138, 4 }, + { 138, 9 }, + { 138, 6 }, + { 138, 1 }, + { 138, 2 }, + { 138, 4 }, + { 138, 4 }, + { 138, 4 }, + { 138, 4 }, + { 138, 5 }, + { 138, 2 }, + { 188, 2 }, + { 179, 2 }, + { 182, 1 }, + { 182, 1 }, + { 189, 1 }, + { 189, 0 }, + { 138, 5 }, + { 209, 10 }, + { 211, 1 }, + { 211, 1 }, + { 211, 2 }, + { 211, 0 }, + { 210, 1 }, + { 210, 1 }, + { 210, 1 }, + { 210, 3 }, + { 160, 0 }, + { 160, 3 }, + { 160, 3 }, + { 216, 0 }, + { 216, 2 }, + { 208, 3 }, + { 208, 0 }, + { 207, 6 }, + { 207, 9 }, + { 207, 6 }, + { 207, 4 }, + { 207, 1 }, + { 157, 4 }, + { 157, 6 }, + { 157, 6 }, + { 157, 6 }, + { 138, 4 }, + { 138, 5 }, + { 149, 1 }, + { 149, 0 }, + { 138, 3 }, +}; + +static void yy_accept(yyParser*); /* Forward Declaration */ + +/* +** Perform a reduce action and the shift that must immediately +** follow the reduce. +*/ +static void yy_reduce( + yyParser *yypParser, /* The parser */ + int yyruleno /* Number of the rule by which to reduce */ +){ + int yygoto; /* The next state */ + int yyact; /* The next action */ + YYMINORTYPE yygotominor; /* The LHS of the rule reduced */ + yyStackEntry *yymsp; /* The top of the parser's stack */ + int yysize; /* Amount to pop the stack */ + sqliteParserARG_FETCH; + yymsp = yypParser->yytop; +#ifndef NDEBUG + if( yyTraceFILE && yyruleno>=0 + && yyruleno + ** { ... } // User supplied code + ** #line + ** break; + */ + case 0: + /* No destructor defined for cmdlist */ + break; + case 1: + /* No destructor defined for ecmd */ + break; + case 2: + /* No destructor defined for cmdlist */ + /* No destructor defined for ecmd */ + break; + case 3: + /* No destructor defined for explain */ + /* No destructor defined for cmdx */ + /* No destructor defined for SEMI */ + break; + case 4: + /* No destructor defined for SEMI */ + break; + case 5: +#line 77 "parse.y" +{ sqliteExec(pParse); } +#line 5014 "parse.c" + /* No destructor defined for cmd */ + break; + case 6: +#line 78 "parse.y" +{ sqliteBeginParse(pParse, 1); } +#line 5020 "parse.c" + /* No destructor defined for EXPLAIN */ + break; + case 7: +#line 79 "parse.y" +{ sqliteBeginParse(pParse, 0); } +#line 5026 "parse.c" + break; + case 8: +#line 84 "parse.y" +{sqliteBeginTransaction(pParse,yymsp[0].minor.yy52);} +#line 5031 "parse.c" + /* No destructor defined for BEGIN */ + /* No destructor defined for trans_opt */ + break; + case 9: + break; + case 10: + /* No destructor defined for TRANSACTION */ + break; + case 11: + /* No destructor defined for TRANSACTION */ + /* No destructor defined for nm */ + break; + case 12: +#line 88 "parse.y" +{sqliteCommitTransaction(pParse);} +#line 5047 "parse.c" + /* No destructor defined for COMMIT */ + /* No destructor defined for trans_opt */ + break; + case 13: +#line 89 "parse.y" +{sqliteCommitTransaction(pParse);} +#line 5054 "parse.c" + /* No destructor defined for END */ + /* No destructor defined for trans_opt */ + break; + case 14: +#line 90 "parse.y" +{sqliteRollbackTransaction(pParse);} +#line 5061 "parse.c" + /* No destructor defined for ROLLBACK */ + /* No destructor defined for trans_opt */ + break; + case 15: + /* No destructor defined for create_table */ + /* No destructor defined for create_table_args */ + break; + case 16: +#line 95 "parse.y" +{ + sqliteStartTable(pParse,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy210,yymsp[-2].minor.yy52,0); +} +#line 5074 "parse.c" + /* No destructor defined for TABLE */ + break; + case 17: +#line 99 "parse.y" +{yygotominor.yy52 = 1;} +#line 5080 "parse.c" + /* No destructor defined for TEMP */ + break; + case 18: +#line 100 "parse.y" +{yygotominor.yy52 = 0;} +#line 5086 "parse.c" + break; + case 19: +#line 101 "parse.y" +{ + sqliteEndTable(pParse,&yymsp[0].minor.yy0,0); +} +#line 5093 "parse.c" + /* No destructor defined for LP */ + /* No destructor defined for columnlist */ + /* No destructor defined for conslist_opt */ + break; + case 20: +#line 104 "parse.y" +{ + sqliteEndTable(pParse,0,yymsp[0].minor.yy11); + sqliteSelectDelete(yymsp[0].minor.yy11); +} +#line 5104 "parse.c" + /* No destructor defined for AS */ + break; + case 21: + /* No destructor defined for columnlist */ + /* No destructor defined for COMMA */ + /* No destructor defined for column */ + break; + case 22: + /* No destructor defined for column */ + break; + case 23: + /* No destructor defined for columnid */ + /* No destructor defined for type */ + /* No destructor defined for carglist */ + break; + case 24: +#line 116 "parse.y" +{sqliteAddColumn(pParse,&yymsp[0].minor.yy210);} +#line 5123 "parse.c" + break; + case 25: +#line 122 "parse.y" +{yygotominor.yy210 = yymsp[0].minor.yy0;} +#line 5128 "parse.c" + break; + case 26: +#line 138 "parse.y" +{yygotominor.yy210 = yymsp[0].minor.yy0;} +#line 5133 "parse.c" + break; + case 27: +#line 139 "parse.y" +{yygotominor.yy210 = yymsp[0].minor.yy0;} +#line 5138 "parse.c" + break; + case 28: +#line 144 "parse.y" +{yygotominor.yy210 = yymsp[0].minor.yy0;} +#line 5143 "parse.c" + break; + case 29: +#line 145 "parse.y" +{yygotominor.yy210 = yymsp[0].minor.yy0;} +#line 5148 "parse.c" + break; + case 30: +#line 146 "parse.y" +{yygotominor.yy210 = yymsp[0].minor.yy0;} +#line 5153 "parse.c" + break; + case 31: + break; + case 32: +#line 149 "parse.y" +{sqliteAddColumnType(pParse,&yymsp[0].minor.yy210,&yymsp[0].minor.yy210);} +#line 5160 "parse.c" + break; + case 33: +#line 150 "parse.y" +{sqliteAddColumnType(pParse,&yymsp[-3].minor.yy210,&yymsp[0].minor.yy0);} +#line 5165 "parse.c" + /* No destructor defined for LP */ + /* No destructor defined for signed */ + break; + case 34: +#line 152 "parse.y" +{sqliteAddColumnType(pParse,&yymsp[-5].minor.yy210,&yymsp[0].minor.yy0);} +#line 5172 "parse.c" + /* No destructor defined for LP */ + /* No destructor defined for signed */ + /* No destructor defined for COMMA */ + /* No destructor defined for signed */ + break; + case 35: +#line 154 "parse.y" +{yygotominor.yy210 = yymsp[0].minor.yy210;} +#line 5181 "parse.c" + break; + case 36: +#line 155 "parse.y" +{yygotominor.yy210 = yymsp[-1].minor.yy210;} +#line 5186 "parse.c" + /* No destructor defined for ids */ + break; + case 37: +#line 157 "parse.y" +{ yygotominor.yy52 = atoi(yymsp[0].minor.yy0.z); } +#line 5192 "parse.c" + break; + case 38: +#line 158 "parse.y" +{ yygotominor.yy52 = atoi(yymsp[0].minor.yy0.z); } +#line 5197 "parse.c" + /* No destructor defined for PLUS */ + break; + case 39: +#line 159 "parse.y" +{ yygotominor.yy52 = -atoi(yymsp[0].minor.yy0.z); } +#line 5203 "parse.c" + /* No destructor defined for MINUS */ + break; + case 40: + /* No destructor defined for carglist */ + /* No destructor defined for carg */ + break; + case 41: + break; + case 42: + /* No destructor defined for CONSTRAINT */ + /* No destructor defined for nm */ + /* No destructor defined for ccons */ + break; + case 43: + /* No destructor defined for ccons */ + break; + case 44: +#line 164 "parse.y" +{sqliteAddDefaultValue(pParse,&yymsp[0].minor.yy0,0);} +#line 5223 "parse.c" + /* No destructor defined for DEFAULT */ + break; + case 45: +#line 165 "parse.y" +{sqliteAddDefaultValue(pParse,&yymsp[0].minor.yy0,0);} +#line 5229 "parse.c" + /* No destructor defined for DEFAULT */ + break; + case 46: +#line 166 "parse.y" +{sqliteAddDefaultValue(pParse,&yymsp[0].minor.yy0,0);} +#line 5235 "parse.c" + /* No destructor defined for DEFAULT */ + break; + case 47: +#line 167 "parse.y" +{sqliteAddDefaultValue(pParse,&yymsp[0].minor.yy0,0);} +#line 5241 "parse.c" + /* No destructor defined for DEFAULT */ + /* No destructor defined for PLUS */ + break; + case 48: +#line 168 "parse.y" +{sqliteAddDefaultValue(pParse,&yymsp[0].minor.yy0,1);} +#line 5248 "parse.c" + /* No destructor defined for DEFAULT */ + /* No destructor defined for MINUS */ + break; + case 49: +#line 169 "parse.y" +{sqliteAddDefaultValue(pParse,&yymsp[0].minor.yy0,0);} +#line 5255 "parse.c" + /* No destructor defined for DEFAULT */ + break; + case 50: +#line 170 "parse.y" +{sqliteAddDefaultValue(pParse,&yymsp[0].minor.yy0,0);} +#line 5261 "parse.c" + /* No destructor defined for DEFAULT */ + /* No destructor defined for PLUS */ + break; + case 51: +#line 171 "parse.y" +{sqliteAddDefaultValue(pParse,&yymsp[0].minor.yy0,1);} +#line 5268 "parse.c" + /* No destructor defined for DEFAULT */ + /* No destructor defined for MINUS */ + break; + case 52: + /* No destructor defined for DEFAULT */ + /* No destructor defined for NULL */ + break; + case 53: + /* No destructor defined for NULL */ + /* No destructor defined for onconf */ + break; + case 54: +#line 178 "parse.y" +{sqliteAddNotNull(pParse, yymsp[0].minor.yy52);} +#line 5283 "parse.c" + /* No destructor defined for NOT */ + /* No destructor defined for NULL */ + break; + case 55: +#line 179 "parse.y" +{sqliteAddPrimaryKey(pParse,0,yymsp[0].minor.yy52);} +#line 5290 "parse.c" + /* No destructor defined for PRIMARY */ + /* No destructor defined for KEY */ + /* No destructor defined for sortorder */ + break; + case 56: +#line 180 "parse.y" +{sqliteCreateIndex(pParse,0,0,0,yymsp[0].minor.yy52,0,0,0);} +#line 5298 "parse.c" + /* No destructor defined for UNIQUE */ + break; + case 57: + /* No destructor defined for CHECK */ + /* No destructor defined for LP */ + yy_destructor(157,&yymsp[-2].minor); + /* No destructor defined for RP */ + /* No destructor defined for onconf */ + break; + case 58: +#line 183 "parse.y" +{sqliteCreateForeignKey(pParse,0,&yymsp[-2].minor.yy210,yymsp[-1].minor.yy92,yymsp[0].minor.yy52);} +#line 5311 "parse.c" + /* No destructor defined for REFERENCES */ + break; + case 59: +#line 184 "parse.y" +{sqliteDeferForeignKey(pParse,yymsp[0].minor.yy52);} +#line 5317 "parse.c" + break; + case 60: +#line 185 "parse.y" +{ + sqliteAddCollateType(pParse, sqliteCollateType(yymsp[0].minor.yy210.z, yymsp[0].minor.yy210.n)); +} +#line 5324 "parse.c" + /* No destructor defined for COLLATE */ + break; + case 61: +#line 195 "parse.y" +{ yygotominor.yy52 = OE_Restrict * 0x010101; } +#line 5330 "parse.c" + break; + case 62: +#line 196 "parse.y" +{ yygotominor.yy52 = (yymsp[-1].minor.yy52 & yymsp[0].minor.yy279.mask) | yymsp[0].minor.yy279.value; } +#line 5335 "parse.c" + break; + case 63: +#line 198 "parse.y" +{ yygotominor.yy279.value = 0; yygotominor.yy279.mask = 0x000000; } +#line 5340 "parse.c" + /* No destructor defined for MATCH */ + /* No destructor defined for nm */ + break; + case 64: +#line 199 "parse.y" +{ yygotominor.yy279.value = yymsp[0].minor.yy52; yygotominor.yy279.mask = 0x0000ff; } +#line 5347 "parse.c" + /* No destructor defined for ON */ + /* No destructor defined for DELETE */ + break; + case 65: +#line 200 "parse.y" +{ yygotominor.yy279.value = yymsp[0].minor.yy52<<8; yygotominor.yy279.mask = 0x00ff00; } +#line 5354 "parse.c" + /* No destructor defined for ON */ + /* No destructor defined for UPDATE */ + break; + case 66: +#line 201 "parse.y" +{ yygotominor.yy279.value = yymsp[0].minor.yy52<<16; yygotominor.yy279.mask = 0xff0000; } +#line 5361 "parse.c" + /* No destructor defined for ON */ + /* No destructor defined for INSERT */ + break; + case 67: +#line 203 "parse.y" +{ yygotominor.yy52 = OE_SetNull; } +#line 5368 "parse.c" + /* No destructor defined for SET */ + /* No destructor defined for NULL */ + break; + case 68: +#line 204 "parse.y" +{ yygotominor.yy52 = OE_SetDflt; } +#line 5375 "parse.c" + /* No destructor defined for SET */ + /* No destructor defined for DEFAULT */ + break; + case 69: +#line 205 "parse.y" +{ yygotominor.yy52 = OE_Cascade; } +#line 5382 "parse.c" + /* No destructor defined for CASCADE */ + break; + case 70: +#line 206 "parse.y" +{ yygotominor.yy52 = OE_Restrict; } +#line 5388 "parse.c" + /* No destructor defined for RESTRICT */ + break; + case 71: +#line 208 "parse.y" +{yygotominor.yy52 = yymsp[0].minor.yy52;} +#line 5394 "parse.c" + /* No destructor defined for NOT */ + /* No destructor defined for DEFERRABLE */ + break; + case 72: +#line 209 "parse.y" +{yygotominor.yy52 = yymsp[0].minor.yy52;} +#line 5401 "parse.c" + /* No destructor defined for DEFERRABLE */ + break; + case 73: +#line 211 "parse.y" +{yygotominor.yy52 = 0;} +#line 5407 "parse.c" + break; + case 74: +#line 212 "parse.y" +{yygotominor.yy52 = 1;} +#line 5412 "parse.c" + /* No destructor defined for INITIALLY */ + /* No destructor defined for DEFERRED */ + break; + case 75: +#line 213 "parse.y" +{yygotominor.yy52 = 0;} +#line 5419 "parse.c" + /* No destructor defined for INITIALLY */ + /* No destructor defined for IMMEDIATE */ + break; + case 76: + break; + case 77: + /* No destructor defined for COMMA */ + /* No destructor defined for conslist */ + break; + case 78: + /* No destructor defined for conslist */ + /* No destructor defined for COMMA */ + /* No destructor defined for tcons */ + break; + case 79: + /* No destructor defined for conslist */ + /* No destructor defined for tcons */ + break; + case 80: + /* No destructor defined for tcons */ + break; + case 81: + /* No destructor defined for CONSTRAINT */ + /* No destructor defined for nm */ + break; + case 82: +#line 225 "parse.y" +{sqliteAddPrimaryKey(pParse,yymsp[-2].minor.yy92,yymsp[0].minor.yy52);} +#line 5448 "parse.c" + /* No destructor defined for PRIMARY */ + /* No destructor defined for KEY */ + /* No destructor defined for LP */ + /* No destructor defined for RP */ + break; + case 83: +#line 227 "parse.y" +{sqliteCreateIndex(pParse,0,0,yymsp[-2].minor.yy92,yymsp[0].minor.yy52,0,0,0);} +#line 5457 "parse.c" + /* No destructor defined for UNIQUE */ + /* No destructor defined for LP */ + /* No destructor defined for RP */ + break; + case 84: + /* No destructor defined for CHECK */ + yy_destructor(157,&yymsp[-1].minor); + /* No destructor defined for onconf */ + break; + case 85: +#line 230 "parse.y" +{ + sqliteCreateForeignKey(pParse, yymsp[-6].minor.yy92, &yymsp[-3].minor.yy210, yymsp[-2].minor.yy92, yymsp[-1].minor.yy52); + sqliteDeferForeignKey(pParse, yymsp[0].minor.yy52); +} +#line 5473 "parse.c" + /* No destructor defined for FOREIGN */ + /* No destructor defined for KEY */ + /* No destructor defined for LP */ + /* No destructor defined for RP */ + /* No destructor defined for REFERENCES */ + break; + case 86: +#line 235 "parse.y" +{yygotominor.yy52 = 0;} +#line 5483 "parse.c" + break; + case 87: +#line 236 "parse.y" +{yygotominor.yy52 = yymsp[0].minor.yy52;} +#line 5488 "parse.c" + break; + case 88: +#line 244 "parse.y" +{ yygotominor.yy52 = OE_Default; } +#line 5493 "parse.c" + break; + case 89: +#line 245 "parse.y" +{ yygotominor.yy52 = yymsp[0].minor.yy52; } +#line 5498 "parse.c" + /* No destructor defined for ON */ + /* No destructor defined for CONFLICT */ + break; + case 90: +#line 246 "parse.y" +{ yygotominor.yy52 = OE_Default; } +#line 5505 "parse.c" + break; + case 91: +#line 247 "parse.y" +{ yygotominor.yy52 = yymsp[0].minor.yy52; } +#line 5510 "parse.c" + /* No destructor defined for OR */ + break; + case 92: +#line 248 "parse.y" +{ yygotominor.yy52 = OE_Rollback; } +#line 5516 "parse.c" + /* No destructor defined for ROLLBACK */ + break; + case 93: +#line 249 "parse.y" +{ yygotominor.yy52 = OE_Abort; } +#line 5522 "parse.c" + /* No destructor defined for ABORT */ + break; + case 94: +#line 250 "parse.y" +{ yygotominor.yy52 = OE_Fail; } +#line 5528 "parse.c" + /* No destructor defined for FAIL */ + break; + case 95: +#line 251 "parse.y" +{ yygotominor.yy52 = OE_Ignore; } +#line 5534 "parse.c" + /* No destructor defined for IGNORE */ + break; + case 96: +#line 252 "parse.y" +{ yygotominor.yy52 = OE_Replace; } +#line 5540 "parse.c" + /* No destructor defined for REPLACE */ + break; + case 97: +#line 256 "parse.y" +{sqliteDropTable(pParse,&yymsp[0].minor.yy210,0);} +#line 5546 "parse.c" + /* No destructor defined for DROP */ + /* No destructor defined for TABLE */ + break; + case 98: +#line 260 "parse.y" +{ + sqliteCreateView(pParse, &yymsp[-5].minor.yy0, &yymsp[-2].minor.yy210, yymsp[0].minor.yy11, yymsp[-4].minor.yy52); +} +#line 5555 "parse.c" + /* No destructor defined for VIEW */ + /* No destructor defined for AS */ + break; + case 99: +#line 263 "parse.y" +{ + sqliteDropTable(pParse, &yymsp[0].minor.yy210, 1); +} +#line 5564 "parse.c" + /* No destructor defined for DROP */ + /* No destructor defined for VIEW */ + break; + case 100: +#line 269 "parse.y" +{ + sqliteSelect(pParse, yymsp[0].minor.yy11, SRT_Callback, 0, 0, 0, 0); + sqliteSelectDelete(yymsp[0].minor.yy11); +} +#line 5574 "parse.c" + break; + case 101: +#line 279 "parse.y" +{yygotominor.yy11 = yymsp[0].minor.yy11;} +#line 5579 "parse.c" + break; + case 102: +#line 280 "parse.y" +{ + if( yymsp[0].minor.yy11 ){ + yymsp[0].minor.yy11->op = yymsp[-1].minor.yy52; + yymsp[0].minor.yy11->pPrior = yymsp[-2].minor.yy11; + } + yygotominor.yy11 = yymsp[0].minor.yy11; +} +#line 5590 "parse.c" + break; + case 103: +#line 288 "parse.y" +{yygotominor.yy52 = TK_UNION;} +#line 5595 "parse.c" + /* No destructor defined for UNION */ + break; + case 104: +#line 289 "parse.y" +{yygotominor.yy52 = TK_ALL;} +#line 5601 "parse.c" + /* No destructor defined for UNION */ + /* No destructor defined for ALL */ + break; + case 105: +#line 290 "parse.y" +{yygotominor.yy52 = TK_INTERSECT;} +#line 5608 "parse.c" + /* No destructor defined for INTERSECT */ + break; + case 106: +#line 291 "parse.y" +{yygotominor.yy52 = TK_EXCEPT;} +#line 5614 "parse.c" + /* No destructor defined for EXCEPT */ + break; + case 107: +#line 293 "parse.y" +{ + yygotominor.yy11 = sqliteSelectNew(yymsp[-6].minor.yy62,yymsp[-5].minor.yy335,yymsp[-4].minor.yy334,yymsp[-3].minor.yy62,yymsp[-2].minor.yy334,yymsp[-1].minor.yy62,yymsp[-7].minor.yy52,yymsp[0].minor.yy280.limit,yymsp[0].minor.yy280.offset); +} +#line 5622 "parse.c" + /* No destructor defined for SELECT */ + break; + case 108: +#line 301 "parse.y" +{yygotominor.yy52 = 1;} +#line 5628 "parse.c" + /* No destructor defined for DISTINCT */ + break; + case 109: +#line 302 "parse.y" +{yygotominor.yy52 = 0;} +#line 5634 "parse.c" + /* No destructor defined for ALL */ + break; + case 110: +#line 303 "parse.y" +{yygotominor.yy52 = 0;} +#line 5640 "parse.c" + break; + case 111: +#line 314 "parse.y" +{yygotominor.yy62 = yymsp[-1].minor.yy62;} +#line 5645 "parse.c" + /* No destructor defined for COMMA */ + break; + case 112: +#line 315 "parse.y" +{yygotominor.yy62 = 0;} +#line 5651 "parse.c" + break; + case 113: +#line 316 "parse.y" +{ + yygotominor.yy62 = sqliteExprListAppend(yymsp[-2].minor.yy62,yymsp[-1].minor.yy334,yymsp[0].minor.yy210.n?&yymsp[0].minor.yy210:0); +} +#line 5658 "parse.c" + break; + case 114: +#line 319 "parse.y" +{ + yygotominor.yy62 = sqliteExprListAppend(yymsp[-1].minor.yy62, sqliteExpr(TK_ALL, 0, 0, 0), 0); +} +#line 5665 "parse.c" + /* No destructor defined for STAR */ + break; + case 115: +#line 322 "parse.y" +{ + Expr *pRight = sqliteExpr(TK_ALL, 0, 0, 0); + Expr *pLeft = sqliteExpr(TK_ID, 0, 0, &yymsp[-2].minor.yy210); + yygotominor.yy62 = sqliteExprListAppend(yymsp[-3].minor.yy62, sqliteExpr(TK_DOT, pLeft, pRight, 0), 0); +} +#line 5675 "parse.c" + /* No destructor defined for DOT */ + /* No destructor defined for STAR */ + break; + case 116: +#line 332 "parse.y" +{ yygotominor.yy210 = yymsp[0].minor.yy210; } +#line 5682 "parse.c" + /* No destructor defined for AS */ + break; + case 117: +#line 333 "parse.y" +{ yygotominor.yy210 = yymsp[0].minor.yy210; } +#line 5688 "parse.c" + break; + case 118: +#line 334 "parse.y" +{ yygotominor.yy210.n = 0; } +#line 5693 "parse.c" + break; + case 119: +#line 346 "parse.y" +{yygotominor.yy335 = sqliteMalloc(sizeof(*yygotominor.yy335));} +#line 5698 "parse.c" + break; + case 120: +#line 347 "parse.y" +{yygotominor.yy335 = yymsp[0].minor.yy335;} +#line 5703 "parse.c" + /* No destructor defined for FROM */ + break; + case 121: +#line 352 "parse.y" +{ + yygotominor.yy335 = yymsp[-1].minor.yy335; + if( yygotominor.yy335 && yygotominor.yy335->nSrc>0 ) yygotominor.yy335->a[yygotominor.yy335->nSrc-1].jointype = yymsp[0].minor.yy52; +} +#line 5712 "parse.c" + break; + case 122: +#line 356 "parse.y" +{yygotominor.yy335 = 0;} +#line 5717 "parse.c" + break; + case 123: +#line 357 "parse.y" +{ + yygotominor.yy335 = sqliteSrcListAppend(yymsp[-5].minor.yy335,&yymsp[-4].minor.yy210,&yymsp[-3].minor.yy210); + if( yymsp[-2].minor.yy210.n ) sqliteSrcListAddAlias(yygotominor.yy335,&yymsp[-2].minor.yy210); + if( yymsp[-1].minor.yy334 ){ + if( yygotominor.yy335 && yygotominor.yy335->nSrc>1 ){ yygotominor.yy335->a[yygotominor.yy335->nSrc-2].pOn = yymsp[-1].minor.yy334; } + else { sqliteExprDelete(yymsp[-1].minor.yy334); } + } + if( yymsp[0].minor.yy92 ){ + if( yygotominor.yy335 && yygotominor.yy335->nSrc>1 ){ yygotominor.yy335->a[yygotominor.yy335->nSrc-2].pUsing = yymsp[0].minor.yy92; } + else { sqliteIdListDelete(yymsp[0].minor.yy92); } + } +} +#line 5733 "parse.c" + break; + case 124: +#line 369 "parse.y" +{ + yygotominor.yy335 = sqliteSrcListAppend(yymsp[-6].minor.yy335,0,0); + yygotominor.yy335->a[yygotominor.yy335->nSrc-1].pSelect = yymsp[-4].minor.yy11; + if( yymsp[-2].minor.yy210.n ) sqliteSrcListAddAlias(yygotominor.yy335,&yymsp[-2].minor.yy210); + if( yymsp[-1].minor.yy334 ){ + if( yygotominor.yy335 && yygotominor.yy335->nSrc>1 ){ yygotominor.yy335->a[yygotominor.yy335->nSrc-2].pOn = yymsp[-1].minor.yy334; } + else { sqliteExprDelete(yymsp[-1].minor.yy334); } + } + if( yymsp[0].minor.yy92 ){ + if( yygotominor.yy335 && yygotominor.yy335->nSrc>1 ){ yygotominor.yy335->a[yygotominor.yy335->nSrc-2].pUsing = yymsp[0].minor.yy92; } + else { sqliteIdListDelete(yymsp[0].minor.yy92); } + } +} +#line 5750 "parse.c" + /* No destructor defined for LP */ + /* No destructor defined for RP */ + break; + case 125: +#line 384 "parse.y" +{yygotominor.yy210.z=0; yygotominor.yy210.n=0;} +#line 5757 "parse.c" + break; + case 126: +#line 385 "parse.y" +{yygotominor.yy210 = yymsp[0].minor.yy210;} +#line 5762 "parse.c" + /* No destructor defined for DOT */ + break; + case 127: +#line 389 "parse.y" +{ yygotominor.yy52 = JT_INNER; } +#line 5768 "parse.c" + /* No destructor defined for COMMA */ + break; + case 128: +#line 390 "parse.y" +{ yygotominor.yy52 = JT_INNER; } +#line 5774 "parse.c" + /* No destructor defined for JOIN */ + break; + case 129: +#line 391 "parse.y" +{ yygotominor.yy52 = sqliteJoinType(pParse,&yymsp[-1].minor.yy0,0,0); } +#line 5780 "parse.c" + /* No destructor defined for JOIN */ + break; + case 130: +#line 392 "parse.y" +{ yygotominor.yy52 = sqliteJoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy210,0); } +#line 5786 "parse.c" + /* No destructor defined for JOIN */ + break; + case 131: +#line 394 "parse.y" +{ yygotominor.yy52 = sqliteJoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy210,&yymsp[-1].minor.yy210); } +#line 5792 "parse.c" + /* No destructor defined for JOIN */ + break; + case 132: +#line 398 "parse.y" +{yygotominor.yy334 = yymsp[0].minor.yy334;} +#line 5798 "parse.c" + /* No destructor defined for ON */ + break; + case 133: +#line 399 "parse.y" +{yygotominor.yy334 = 0;} +#line 5804 "parse.c" + break; + case 134: +#line 403 "parse.y" +{yygotominor.yy92 = yymsp[-1].minor.yy92;} +#line 5809 "parse.c" + /* No destructor defined for USING */ + /* No destructor defined for LP */ + /* No destructor defined for RP */ + break; + case 135: +#line 404 "parse.y" +{yygotominor.yy92 = 0;} +#line 5817 "parse.c" + break; + case 136: +#line 414 "parse.y" +{yygotominor.yy62 = 0;} +#line 5822 "parse.c" + break; + case 137: +#line 415 "parse.y" +{yygotominor.yy62 = yymsp[0].minor.yy62;} +#line 5827 "parse.c" + /* No destructor defined for ORDER */ + /* No destructor defined for BY */ + break; + case 138: +#line 416 "parse.y" +{ + yygotominor.yy62 = sqliteExprListAppend(yymsp[-4].minor.yy62,yymsp[-2].minor.yy334,0); + if( yygotominor.yy62 ) yygotominor.yy62->a[yygotominor.yy62->nExpr-1].sortOrder = yymsp[-1].minor.yy52+yymsp[0].minor.yy52; +} +#line 5837 "parse.c" + /* No destructor defined for COMMA */ + break; + case 139: +#line 420 "parse.y" +{ + yygotominor.yy62 = sqliteExprListAppend(0,yymsp[-2].minor.yy334,0); + if( yygotominor.yy62 ) yygotominor.yy62->a[0].sortOrder = yymsp[-1].minor.yy52+yymsp[0].minor.yy52; +} +#line 5846 "parse.c" + break; + case 140: +#line 424 "parse.y" +{yygotominor.yy334 = yymsp[0].minor.yy334;} +#line 5851 "parse.c" + break; + case 141: +#line 429 "parse.y" +{yygotominor.yy52 = SQLITE_SO_ASC;} +#line 5856 "parse.c" + /* No destructor defined for ASC */ + break; + case 142: +#line 430 "parse.y" +{yygotominor.yy52 = SQLITE_SO_DESC;} +#line 5862 "parse.c" + /* No destructor defined for DESC */ + break; + case 143: +#line 431 "parse.y" +{yygotominor.yy52 = SQLITE_SO_ASC;} +#line 5868 "parse.c" + break; + case 144: +#line 432 "parse.y" +{yygotominor.yy52 = SQLITE_SO_UNK;} +#line 5873 "parse.c" + break; + case 145: +#line 433 "parse.y" +{yygotominor.yy52 = sqliteCollateType(yymsp[0].minor.yy210.z, yymsp[0].minor.yy210.n);} +#line 5878 "parse.c" + /* No destructor defined for COLLATE */ + break; + case 146: +#line 437 "parse.y" +{yygotominor.yy62 = 0;} +#line 5884 "parse.c" + break; + case 147: +#line 438 "parse.y" +{yygotominor.yy62 = yymsp[0].minor.yy62;} +#line 5889 "parse.c" + /* No destructor defined for GROUP */ + /* No destructor defined for BY */ + break; + case 148: +#line 442 "parse.y" +{yygotominor.yy334 = 0;} +#line 5896 "parse.c" + break; + case 149: +#line 443 "parse.y" +{yygotominor.yy334 = yymsp[0].minor.yy334;} +#line 5901 "parse.c" + /* No destructor defined for HAVING */ + break; + case 150: +#line 446 "parse.y" +{yygotominor.yy280.limit = -1; yygotominor.yy280.offset = 0;} +#line 5907 "parse.c" + break; + case 151: +#line 447 "parse.y" +{yygotominor.yy280.limit = yymsp[0].minor.yy52; yygotominor.yy280.offset = 0;} +#line 5912 "parse.c" + /* No destructor defined for LIMIT */ + break; + case 152: +#line 449 "parse.y" +{yygotominor.yy280.limit = yymsp[-2].minor.yy52; yygotominor.yy280.offset = yymsp[0].minor.yy52;} +#line 5918 "parse.c" + /* No destructor defined for LIMIT */ + /* No destructor defined for OFFSET */ + break; + case 153: +#line 451 "parse.y" +{yygotominor.yy280.limit = yymsp[0].minor.yy52; yygotominor.yy280.offset = yymsp[-2].minor.yy52;} +#line 5925 "parse.c" + /* No destructor defined for LIMIT */ + /* No destructor defined for COMMA */ + break; + case 154: +#line 455 "parse.y" +{ + sqliteDeleteFrom(pParse, sqliteSrcListAppend(0,&yymsp[-2].minor.yy210,&yymsp[-1].minor.yy210), yymsp[0].minor.yy334); +} +#line 5934 "parse.c" + /* No destructor defined for DELETE */ + /* No destructor defined for FROM */ + break; + case 155: +#line 462 "parse.y" +{yygotominor.yy334 = 0;} +#line 5941 "parse.c" + break; + case 156: +#line 463 "parse.y" +{yygotominor.yy334 = yymsp[0].minor.yy334;} +#line 5946 "parse.c" + /* No destructor defined for WHERE */ + break; + case 157: +#line 471 "parse.y" +{sqliteUpdate(pParse,sqliteSrcListAppend(0,&yymsp[-4].minor.yy210,&yymsp[-3].minor.yy210),yymsp[-1].minor.yy62,yymsp[0].minor.yy334,yymsp[-5].minor.yy52);} +#line 5952 "parse.c" + /* No destructor defined for UPDATE */ + /* No destructor defined for SET */ + break; + case 158: +#line 474 "parse.y" +{yygotominor.yy62 = sqliteExprListAppend(yymsp[-4].minor.yy62,yymsp[0].minor.yy334,&yymsp[-2].minor.yy210);} +#line 5959 "parse.c" + /* No destructor defined for COMMA */ + /* No destructor defined for EQ */ + break; + case 159: +#line 475 "parse.y" +{yygotominor.yy62 = sqliteExprListAppend(0,yymsp[0].minor.yy334,&yymsp[-2].minor.yy210);} +#line 5966 "parse.c" + /* No destructor defined for EQ */ + break; + case 160: +#line 481 "parse.y" +{sqliteInsert(pParse, sqliteSrcListAppend(0,&yymsp[-6].minor.yy210,&yymsp[-5].minor.yy210), yymsp[-1].minor.yy62, 0, yymsp[-4].minor.yy92, yymsp[-8].minor.yy52);} +#line 5972 "parse.c" + /* No destructor defined for INTO */ + /* No destructor defined for VALUES */ + /* No destructor defined for LP */ + /* No destructor defined for RP */ + break; + case 161: +#line 483 "parse.y" +{sqliteInsert(pParse, sqliteSrcListAppend(0,&yymsp[-3].minor.yy210,&yymsp[-2].minor.yy210), 0, yymsp[0].minor.yy11, yymsp[-1].minor.yy92, yymsp[-5].minor.yy52);} +#line 5981 "parse.c" + /* No destructor defined for INTO */ + break; + case 162: +#line 486 "parse.y" +{yygotominor.yy52 = yymsp[0].minor.yy52;} +#line 5987 "parse.c" + /* No destructor defined for INSERT */ + break; + case 163: +#line 487 "parse.y" +{yygotominor.yy52 = OE_Replace;} +#line 5993 "parse.c" + /* No destructor defined for REPLACE */ + break; + case 164: +#line 493 "parse.y" +{yygotominor.yy62 = sqliteExprListAppend(yymsp[-2].minor.yy62,yymsp[0].minor.yy334,0);} +#line 5999 "parse.c" + /* No destructor defined for COMMA */ + break; + case 165: +#line 494 "parse.y" +{yygotominor.yy62 = sqliteExprListAppend(0,yymsp[0].minor.yy334,0);} +#line 6005 "parse.c" + break; + case 166: +#line 501 "parse.y" +{yygotominor.yy92 = 0;} +#line 6010 "parse.c" + break; + case 167: +#line 502 "parse.y" +{yygotominor.yy92 = yymsp[-1].minor.yy92;} +#line 6015 "parse.c" + /* No destructor defined for LP */ + /* No destructor defined for RP */ + break; + case 168: +#line 503 "parse.y" +{yygotominor.yy92 = sqliteIdListAppend(yymsp[-2].minor.yy92,&yymsp[0].minor.yy210);} +#line 6022 "parse.c" + /* No destructor defined for COMMA */ + break; + case 169: +#line 504 "parse.y" +{yygotominor.yy92 = sqliteIdListAppend(0,&yymsp[0].minor.yy210);} +#line 6028 "parse.c" + break; + case 170: +#line 523 "parse.y" +{yygotominor.yy334 = yymsp[-1].minor.yy334; sqliteExprSpan(yygotominor.yy334,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); } +#line 6033 "parse.c" + break; + case 171: +#line 524 "parse.y" +{yygotominor.yy334 = sqliteExpr(TK_NULL, 0, 0, &yymsp[0].minor.yy0);} +#line 6038 "parse.c" + break; + case 172: +#line 525 "parse.y" +{yygotominor.yy334 = sqliteExpr(TK_ID, 0, 0, &yymsp[0].minor.yy0);} +#line 6043 "parse.c" + break; + case 173: +#line 526 "parse.y" +{yygotominor.yy334 = sqliteExpr(TK_ID, 0, 0, &yymsp[0].minor.yy0);} +#line 6048 "parse.c" + break; + case 174: +#line 527 "parse.y" +{ + Expr *temp1 = sqliteExpr(TK_ID, 0, 0, &yymsp[-2].minor.yy210); + Expr *temp2 = sqliteExpr(TK_ID, 0, 0, &yymsp[0].minor.yy210); + yygotominor.yy334 = sqliteExpr(TK_DOT, temp1, temp2, 0); +} +#line 6057 "parse.c" + /* No destructor defined for DOT */ + break; + case 175: +#line 532 "parse.y" +{ + Expr *temp1 = sqliteExpr(TK_ID, 0, 0, &yymsp[-4].minor.yy210); + Expr *temp2 = sqliteExpr(TK_ID, 0, 0, &yymsp[-2].minor.yy210); + Expr *temp3 = sqliteExpr(TK_ID, 0, 0, &yymsp[0].minor.yy210); + Expr *temp4 = sqliteExpr(TK_DOT, temp2, temp3, 0); + yygotominor.yy334 = sqliteExpr(TK_DOT, temp1, temp4, 0); +} +#line 6069 "parse.c" + /* No destructor defined for DOT */ + /* No destructor defined for DOT */ + break; + case 176: +#line 540 "parse.y" +{yygotominor.yy334 = yymsp[-1].minor.yy334; ExprSetProperty(yygotominor.yy334,EP_Oracle8Join);} +#line 6076 "parse.c" + /* No destructor defined for ORACLE_OUTER_JOIN */ + break; + case 177: +#line 541 "parse.y" +{yygotominor.yy334 = sqliteExpr(TK_INTEGER, 0, 0, &yymsp[0].minor.yy0);} +#line 6082 "parse.c" + break; + case 178: +#line 542 "parse.y" +{yygotominor.yy334 = sqliteExpr(TK_FLOAT, 0, 0, &yymsp[0].minor.yy0);} +#line 6087 "parse.c" + break; + case 179: +#line 543 "parse.y" +{yygotominor.yy334 = sqliteExpr(TK_STRING, 0, 0, &yymsp[0].minor.yy0);} +#line 6092 "parse.c" + break; + case 180: +#line 544 "parse.y" +{ + yygotominor.yy334 = sqliteExprFunction(yymsp[-1].minor.yy62, &yymsp[-3].minor.yy0); + sqliteExprSpan(yygotominor.yy334,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); +} +#line 6100 "parse.c" + /* No destructor defined for LP */ + break; + case 181: +#line 548 "parse.y" +{ + yygotominor.yy334 = sqliteExprFunction(0, &yymsp[-3].minor.yy0); + sqliteExprSpan(yygotominor.yy334,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); +} +#line 6109 "parse.c" + /* No destructor defined for LP */ + /* No destructor defined for STAR */ + break; + case 182: +#line 552 "parse.y" +{yygotominor.yy334 = sqliteExpr(TK_AND, yymsp[-2].minor.yy334, yymsp[0].minor.yy334, 0);} +#line 6116 "parse.c" + /* No destructor defined for AND */ + break; + case 183: +#line 553 "parse.y" +{yygotominor.yy334 = sqliteExpr(TK_OR, yymsp[-2].minor.yy334, yymsp[0].minor.yy334, 0);} +#line 6122 "parse.c" + /* No destructor defined for OR */ + break; + case 184: +#line 554 "parse.y" +{yygotominor.yy334 = sqliteExpr(TK_LT, yymsp[-2].minor.yy334, yymsp[0].minor.yy334, 0);} +#line 6128 "parse.c" + /* No destructor defined for LT */ + break; + case 185: +#line 555 "parse.y" +{yygotominor.yy334 = sqliteExpr(TK_GT, yymsp[-2].minor.yy334, yymsp[0].minor.yy334, 0);} +#line 6134 "parse.c" + /* No destructor defined for GT */ + break; + case 186: +#line 556 "parse.y" +{yygotominor.yy334 = sqliteExpr(TK_LE, yymsp[-2].minor.yy334, yymsp[0].minor.yy334, 0);} +#line 6140 "parse.c" + /* No destructor defined for LE */ + break; + case 187: +#line 557 "parse.y" +{yygotominor.yy334 = sqliteExpr(TK_GE, yymsp[-2].minor.yy334, yymsp[0].minor.yy334, 0);} +#line 6146 "parse.c" + /* No destructor defined for GE */ + break; + case 188: +#line 558 "parse.y" +{yygotominor.yy334 = sqliteExpr(TK_NE, yymsp[-2].minor.yy334, yymsp[0].minor.yy334, 0);} +#line 6152 "parse.c" + /* No destructor defined for NE */ + break; + case 189: +#line 559 "parse.y" +{yygotominor.yy334 = sqliteExpr(TK_EQ, yymsp[-2].minor.yy334, yymsp[0].minor.yy334, 0);} +#line 6158 "parse.c" + /* No destructor defined for EQ */ + break; + case 190: +#line 560 "parse.y" +{yygotominor.yy334 = sqliteExpr(TK_BITAND, yymsp[-2].minor.yy334, yymsp[0].minor.yy334, 0);} +#line 6164 "parse.c" + /* No destructor defined for BITAND */ + break; + case 191: +#line 561 "parse.y" +{yygotominor.yy334 = sqliteExpr(TK_BITOR, yymsp[-2].minor.yy334, yymsp[0].minor.yy334, 0);} +#line 6170 "parse.c" + /* No destructor defined for BITOR */ + break; + case 192: +#line 562 "parse.y" +{yygotominor.yy334 = sqliteExpr(TK_LSHIFT, yymsp[-2].minor.yy334, yymsp[0].minor.yy334, 0);} +#line 6176 "parse.c" + /* No destructor defined for LSHIFT */ + break; + case 193: +#line 563 "parse.y" +{yygotominor.yy334 = sqliteExpr(TK_RSHIFT, yymsp[-2].minor.yy334, yymsp[0].minor.yy334, 0);} +#line 6182 "parse.c" + /* No destructor defined for RSHIFT */ + break; + case 194: +#line 564 "parse.y" +{ + ExprList *pList = sqliteExprListAppend(0, yymsp[0].minor.yy334, 0); + pList = sqliteExprListAppend(pList, yymsp[-2].minor.yy334, 0); + yygotominor.yy334 = sqliteExprFunction(pList, 0); + if( yygotominor.yy334 ) yygotominor.yy334->op = yymsp[-1].minor.yy52; + sqliteExprSpan(yygotominor.yy334, &yymsp[-2].minor.yy334->span, &yymsp[0].minor.yy334->span); +} +#line 6194 "parse.c" + break; + case 195: +#line 571 "parse.y" +{ + ExprList *pList = sqliteExprListAppend(0, yymsp[0].minor.yy334, 0); + pList = sqliteExprListAppend(pList, yymsp[-3].minor.yy334, 0); + yygotominor.yy334 = sqliteExprFunction(pList, 0); + if( yygotominor.yy334 ) yygotominor.yy334->op = yymsp[-1].minor.yy52; + yygotominor.yy334 = sqliteExpr(TK_NOT, yygotominor.yy334, 0, 0); + sqliteExprSpan(yygotominor.yy334,&yymsp[-3].minor.yy334->span,&yymsp[0].minor.yy334->span); +} +#line 6206 "parse.c" + /* No destructor defined for NOT */ + break; + case 196: +#line 580 "parse.y" +{yygotominor.yy52 = TK_LIKE;} +#line 6212 "parse.c" + /* No destructor defined for LIKE */ + break; + case 197: +#line 581 "parse.y" +{yygotominor.yy52 = TK_GLOB;} +#line 6218 "parse.c" + /* No destructor defined for GLOB */ + break; + case 198: +#line 582 "parse.y" +{yygotominor.yy334 = sqliteExpr(TK_PLUS, yymsp[-2].minor.yy334, yymsp[0].minor.yy334, 0);} +#line 6224 "parse.c" + /* No destructor defined for PLUS */ + break; + case 199: +#line 583 "parse.y" +{yygotominor.yy334 = sqliteExpr(TK_MINUS, yymsp[-2].minor.yy334, yymsp[0].minor.yy334, 0);} +#line 6230 "parse.c" + /* No destructor defined for MINUS */ + break; + case 200: +#line 584 "parse.y" +{yygotominor.yy334 = sqliteExpr(TK_STAR, yymsp[-2].minor.yy334, yymsp[0].minor.yy334, 0);} +#line 6236 "parse.c" + /* No destructor defined for STAR */ + break; + case 201: +#line 585 "parse.y" +{yygotominor.yy334 = sqliteExpr(TK_SLASH, yymsp[-2].minor.yy334, yymsp[0].minor.yy334, 0);} +#line 6242 "parse.c" + /* No destructor defined for SLASH */ + break; + case 202: +#line 586 "parse.y" +{yygotominor.yy334 = sqliteExpr(TK_REM, yymsp[-2].minor.yy334, yymsp[0].minor.yy334, 0);} +#line 6248 "parse.c" + /* No destructor defined for REM */ + break; + case 203: +#line 587 "parse.y" +{yygotominor.yy334 = sqliteExpr(TK_CONCAT, yymsp[-2].minor.yy334, yymsp[0].minor.yy334, 0);} +#line 6254 "parse.c" + /* No destructor defined for CONCAT */ + break; + case 204: +#line 588 "parse.y" +{ + yygotominor.yy334 = sqliteExpr(TK_ISNULL, yymsp[-1].minor.yy334, 0, 0); + sqliteExprSpan(yygotominor.yy334,&yymsp[-1].minor.yy334->span,&yymsp[0].minor.yy0); +} +#line 6263 "parse.c" + break; + case 205: +#line 592 "parse.y" +{ + yygotominor.yy334 = sqliteExpr(TK_ISNULL, yymsp[-2].minor.yy334, 0, 0); + sqliteExprSpan(yygotominor.yy334,&yymsp[-2].minor.yy334->span,&yymsp[0].minor.yy0); +} +#line 6271 "parse.c" + /* No destructor defined for IS */ + break; + case 206: +#line 596 "parse.y" +{ + yygotominor.yy334 = sqliteExpr(TK_NOTNULL, yymsp[-1].minor.yy334, 0, 0); + sqliteExprSpan(yygotominor.yy334,&yymsp[-1].minor.yy334->span,&yymsp[0].minor.yy0); +} +#line 6280 "parse.c" + break; + case 207: +#line 600 "parse.y" +{ + yygotominor.yy334 = sqliteExpr(TK_NOTNULL, yymsp[-2].minor.yy334, 0, 0); + sqliteExprSpan(yygotominor.yy334,&yymsp[-2].minor.yy334->span,&yymsp[0].minor.yy0); +} +#line 6288 "parse.c" + /* No destructor defined for NOT */ + break; + case 208: +#line 604 "parse.y" +{ + yygotominor.yy334 = sqliteExpr(TK_NOTNULL, yymsp[-3].minor.yy334, 0, 0); + sqliteExprSpan(yygotominor.yy334,&yymsp[-3].minor.yy334->span,&yymsp[0].minor.yy0); +} +#line 6297 "parse.c" + /* No destructor defined for IS */ + /* No destructor defined for NOT */ + break; + case 209: +#line 608 "parse.y" +{ + yygotominor.yy334 = sqliteExpr(TK_NOT, yymsp[0].minor.yy334, 0, 0); + sqliteExprSpan(yygotominor.yy334,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy334->span); +} +#line 6307 "parse.c" + break; + case 210: +#line 612 "parse.y" +{ + yygotominor.yy334 = sqliteExpr(TK_BITNOT, yymsp[0].minor.yy334, 0, 0); + sqliteExprSpan(yygotominor.yy334,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy334->span); +} +#line 6315 "parse.c" + break; + case 211: +#line 616 "parse.y" +{ + yygotominor.yy334 = sqliteExpr(TK_UMINUS, yymsp[0].minor.yy334, 0, 0); + sqliteExprSpan(yygotominor.yy334,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy334->span); +} +#line 6323 "parse.c" + break; + case 212: +#line 620 "parse.y" +{ + yygotominor.yy334 = sqliteExpr(TK_UPLUS, yymsp[0].minor.yy334, 0, 0); + sqliteExprSpan(yygotominor.yy334,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy334->span); +} +#line 6331 "parse.c" + break; + case 213: +#line 624 "parse.y" +{ + yygotominor.yy334 = sqliteExpr(TK_SELECT, 0, 0, 0); + if( yygotominor.yy334 ) yygotominor.yy334->pSelect = yymsp[-1].minor.yy11; + sqliteExprSpan(yygotominor.yy334,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); +} +#line 6340 "parse.c" + break; + case 214: +#line 629 "parse.y" +{ + ExprList *pList = sqliteExprListAppend(0, yymsp[-2].minor.yy334, 0); + pList = sqliteExprListAppend(pList, yymsp[0].minor.yy334, 0); + yygotominor.yy334 = sqliteExpr(TK_BETWEEN, yymsp[-4].minor.yy334, 0, 0); + if( yygotominor.yy334 ) yygotominor.yy334->pList = pList; + sqliteExprSpan(yygotominor.yy334,&yymsp[-4].minor.yy334->span,&yymsp[0].minor.yy334->span); +} +#line 6351 "parse.c" + /* No destructor defined for BETWEEN */ + /* No destructor defined for AND */ + break; + case 215: +#line 636 "parse.y" +{ + ExprList *pList = sqliteExprListAppend(0, yymsp[-2].minor.yy334, 0); + pList = sqliteExprListAppend(pList, yymsp[0].minor.yy334, 0); + yygotominor.yy334 = sqliteExpr(TK_BETWEEN, yymsp[-5].minor.yy334, 0, 0); + if( yygotominor.yy334 ) yygotominor.yy334->pList = pList; + yygotominor.yy334 = sqliteExpr(TK_NOT, yygotominor.yy334, 0, 0); + sqliteExprSpan(yygotominor.yy334,&yymsp[-5].minor.yy334->span,&yymsp[0].minor.yy334->span); +} +#line 6365 "parse.c" + /* No destructor defined for NOT */ + /* No destructor defined for BETWEEN */ + /* No destructor defined for AND */ + break; + case 216: +#line 644 "parse.y" +{ + yygotominor.yy334 = sqliteExpr(TK_IN, yymsp[-4].minor.yy334, 0, 0); + if( yygotominor.yy334 ) yygotominor.yy334->pList = yymsp[-1].minor.yy62; + sqliteExprSpan(yygotominor.yy334,&yymsp[-4].minor.yy334->span,&yymsp[0].minor.yy0); +} +#line 6377 "parse.c" + /* No destructor defined for IN */ + /* No destructor defined for LP */ + break; + case 217: +#line 649 "parse.y" +{ + yygotominor.yy334 = sqliteExpr(TK_IN, yymsp[-4].minor.yy334, 0, 0); + if( yygotominor.yy334 ) yygotominor.yy334->pSelect = yymsp[-1].minor.yy11; + sqliteExprSpan(yygotominor.yy334,&yymsp[-4].minor.yy334->span,&yymsp[0].minor.yy0); +} +#line 6388 "parse.c" + /* No destructor defined for IN */ + /* No destructor defined for LP */ + break; + case 218: +#line 654 "parse.y" +{ + yygotominor.yy334 = sqliteExpr(TK_IN, yymsp[-5].minor.yy334, 0, 0); + if( yygotominor.yy334 ) yygotominor.yy334->pList = yymsp[-1].minor.yy62; + yygotominor.yy334 = sqliteExpr(TK_NOT, yygotominor.yy334, 0, 0); + sqliteExprSpan(yygotominor.yy334,&yymsp[-5].minor.yy334->span,&yymsp[0].minor.yy0); +} +#line 6400 "parse.c" + /* No destructor defined for NOT */ + /* No destructor defined for IN */ + /* No destructor defined for LP */ + break; + case 219: +#line 660 "parse.y" +{ + yygotominor.yy334 = sqliteExpr(TK_IN, yymsp[-5].minor.yy334, 0, 0); + if( yygotominor.yy334 ) yygotominor.yy334->pSelect = yymsp[-1].minor.yy11; + yygotominor.yy334 = sqliteExpr(TK_NOT, yygotominor.yy334, 0, 0); + sqliteExprSpan(yygotominor.yy334,&yymsp[-5].minor.yy334->span,&yymsp[0].minor.yy0); +} +#line 6413 "parse.c" + /* No destructor defined for NOT */ + /* No destructor defined for IN */ + /* No destructor defined for LP */ + break; + case 220: +#line 668 "parse.y" +{ + yygotominor.yy334 = sqliteExpr(TK_CASE, yymsp[-3].minor.yy334, yymsp[-1].minor.yy334, 0); + if( yygotominor.yy334 ) yygotominor.yy334->pList = yymsp[-2].minor.yy62; + sqliteExprSpan(yygotominor.yy334, &yymsp[-4].minor.yy0, &yymsp[0].minor.yy0); +} +#line 6425 "parse.c" + break; + case 221: +#line 675 "parse.y" +{ + yygotominor.yy62 = sqliteExprListAppend(yymsp[-4].minor.yy62, yymsp[-2].minor.yy334, 0); + yygotominor.yy62 = sqliteExprListAppend(yygotominor.yy62, yymsp[0].minor.yy334, 0); +} +#line 6433 "parse.c" + /* No destructor defined for WHEN */ + /* No destructor defined for THEN */ + break; + case 222: +#line 679 "parse.y" +{ + yygotominor.yy62 = sqliteExprListAppend(0, yymsp[-2].minor.yy334, 0); + yygotominor.yy62 = sqliteExprListAppend(yygotominor.yy62, yymsp[0].minor.yy334, 0); +} +#line 6443 "parse.c" + /* No destructor defined for WHEN */ + /* No destructor defined for THEN */ + break; + case 223: +#line 684 "parse.y" +{yygotominor.yy334 = yymsp[0].minor.yy334;} +#line 6450 "parse.c" + /* No destructor defined for ELSE */ + break; + case 224: +#line 685 "parse.y" +{yygotominor.yy334 = 0;} +#line 6456 "parse.c" + break; + case 225: +#line 687 "parse.y" +{yygotominor.yy334 = yymsp[0].minor.yy334;} +#line 6461 "parse.c" + break; + case 226: +#line 688 "parse.y" +{yygotominor.yy334 = 0;} +#line 6466 "parse.c" + break; + case 227: +#line 696 "parse.y" +{yygotominor.yy62 = sqliteExprListAppend(yymsp[-2].minor.yy62,yymsp[0].minor.yy334,0);} +#line 6471 "parse.c" + /* No destructor defined for COMMA */ + break; + case 228: +#line 697 "parse.y" +{yygotominor.yy62 = sqliteExprListAppend(0,yymsp[0].minor.yy334,0);} +#line 6477 "parse.c" + break; + case 229: +#line 698 "parse.y" +{yygotominor.yy334 = yymsp[0].minor.yy334;} +#line 6482 "parse.c" + break; + case 230: +#line 699 "parse.y" +{yygotominor.yy334 = 0;} +#line 6487 "parse.c" + break; + case 231: +#line 704 "parse.y" +{ + SrcList *pSrc = sqliteSrcListAppend(0, &yymsp[-5].minor.yy210, &yymsp[-4].minor.yy210); + if( yymsp[-9].minor.yy52!=OE_None ) yymsp[-9].minor.yy52 = yymsp[0].minor.yy52; + if( yymsp[-9].minor.yy52==OE_Default) yymsp[-9].minor.yy52 = OE_Abort; + sqliteCreateIndex(pParse, &yymsp[-7].minor.yy210, pSrc, yymsp[-2].minor.yy92, yymsp[-9].minor.yy52, yymsp[-10].minor.yy52, &yymsp[-11].minor.yy0, &yymsp[-1].minor.yy0); +} +#line 6497 "parse.c" + /* No destructor defined for INDEX */ + /* No destructor defined for ON */ + /* No destructor defined for LP */ + break; + case 232: +#line 712 "parse.y" +{ yygotominor.yy52 = OE_Abort; } +#line 6505 "parse.c" + /* No destructor defined for UNIQUE */ + break; + case 233: +#line 713 "parse.y" +{ yygotominor.yy52 = OE_None; } +#line 6511 "parse.c" + break; + case 234: +#line 721 "parse.y" +{yygotominor.yy92 = 0;} +#line 6516 "parse.c" + break; + case 235: +#line 722 "parse.y" +{yygotominor.yy92 = yymsp[-1].minor.yy92;} +#line 6521 "parse.c" + /* No destructor defined for LP */ + /* No destructor defined for RP */ + break; + case 236: +#line 723 "parse.y" +{yygotominor.yy92 = sqliteIdListAppend(yymsp[-2].minor.yy92,&yymsp[0].minor.yy210);} +#line 6528 "parse.c" + /* No destructor defined for COMMA */ + break; + case 237: +#line 724 "parse.y" +{yygotominor.yy92 = sqliteIdListAppend(0,&yymsp[0].minor.yy210);} +#line 6534 "parse.c" + break; + case 238: +#line 725 "parse.y" +{yygotominor.yy210 = yymsp[-1].minor.yy210;} +#line 6539 "parse.c" + /* No destructor defined for sortorder */ + break; + case 239: +#line 730 "parse.y" +{ + sqliteDropIndex(pParse, sqliteSrcListAppend(0,&yymsp[-1].minor.yy210,&yymsp[0].minor.yy210)); +} +#line 6547 "parse.c" + /* No destructor defined for DROP */ + /* No destructor defined for INDEX */ + break; + case 240: +#line 738 "parse.y" +{sqliteCopy(pParse,sqliteSrcListAppend(0,&yymsp[-6].minor.yy210,&yymsp[-5].minor.yy210),&yymsp[-3].minor.yy210,&yymsp[0].minor.yy0,yymsp[-7].minor.yy52);} +#line 6554 "parse.c" + /* No destructor defined for COPY */ + /* No destructor defined for FROM */ + /* No destructor defined for USING */ + /* No destructor defined for DELIMITERS */ + break; + case 241: +#line 740 "parse.y" +{sqliteCopy(pParse,sqliteSrcListAppend(0,&yymsp[-3].minor.yy210,&yymsp[-2].minor.yy210),&yymsp[0].minor.yy210,0,yymsp[-4].minor.yy52);} +#line 6563 "parse.c" + /* No destructor defined for COPY */ + /* No destructor defined for FROM */ + break; + case 242: +#line 744 "parse.y" +{sqliteVacuum(pParse,0);} +#line 6570 "parse.c" + /* No destructor defined for VACUUM */ + break; + case 243: +#line 745 "parse.y" +{sqliteVacuum(pParse,&yymsp[0].minor.yy210);} +#line 6576 "parse.c" + /* No destructor defined for VACUUM */ + break; + case 244: +#line 749 "parse.y" +{sqlitePragma(pParse,&yymsp[-2].minor.yy210,&yymsp[0].minor.yy210,0);} +#line 6582 "parse.c" + /* No destructor defined for PRAGMA */ + /* No destructor defined for EQ */ + break; + case 245: +#line 750 "parse.y" +{sqlitePragma(pParse,&yymsp[-2].minor.yy210,&yymsp[0].minor.yy0,0);} +#line 6589 "parse.c" + /* No destructor defined for PRAGMA */ + /* No destructor defined for EQ */ + break; + case 246: +#line 751 "parse.y" +{sqlitePragma(pParse,&yymsp[-2].minor.yy210,&yymsp[0].minor.yy210,0);} +#line 6596 "parse.c" + /* No destructor defined for PRAGMA */ + /* No destructor defined for EQ */ + break; + case 247: +#line 752 "parse.y" +{sqlitePragma(pParse,&yymsp[-2].minor.yy210,&yymsp[0].minor.yy210,1);} +#line 6603 "parse.c" + /* No destructor defined for PRAGMA */ + /* No destructor defined for EQ */ + break; + case 248: +#line 753 "parse.y" +{sqlitePragma(pParse,&yymsp[-3].minor.yy210,&yymsp[-1].minor.yy210,0);} +#line 6610 "parse.c" + /* No destructor defined for PRAGMA */ + /* No destructor defined for LP */ + /* No destructor defined for RP */ + break; + case 249: +#line 754 "parse.y" +{sqlitePragma(pParse,&yymsp[0].minor.yy210,&yymsp[0].minor.yy210,0);} +#line 6618 "parse.c" + /* No destructor defined for PRAGMA */ + break; + case 250: +#line 755 "parse.y" +{yygotominor.yy210 = yymsp[0].minor.yy210;} +#line 6624 "parse.c" + /* No destructor defined for plus_opt */ + break; + case 251: +#line 756 "parse.y" +{yygotominor.yy210 = yymsp[0].minor.yy210;} +#line 6630 "parse.c" + /* No destructor defined for MINUS */ + break; + case 252: +#line 757 "parse.y" +{yygotominor.yy210 = yymsp[0].minor.yy0;} +#line 6636 "parse.c" + break; + case 253: +#line 758 "parse.y" +{yygotominor.yy210 = yymsp[0].minor.yy0;} +#line 6641 "parse.c" + break; + case 254: + /* No destructor defined for PLUS */ + break; + case 255: + break; + case 256: +#line 764 "parse.y" +{ + Token all; + all.z = yymsp[-4].minor.yy0.z; + all.n = (yymsp[0].minor.yy0.z - yymsp[-4].minor.yy0.z) + yymsp[0].minor.yy0.n; + sqliteFinishTrigger(pParse, yymsp[-1].minor.yy347, &all); +} +#line 6656 "parse.c" + /* No destructor defined for trigger_decl */ + /* No destructor defined for BEGIN */ + break; + case 257: +#line 772 "parse.y" +{ + SrcList *pTab = sqliteSrcListAppend(0, &yymsp[-3].minor.yy210, &yymsp[-2].minor.yy210); + sqliteBeginTrigger(pParse, &yymsp[-7].minor.yy210, yymsp[-6].minor.yy52, yymsp[-5].minor.yy234.a, yymsp[-5].minor.yy234.b, pTab, yymsp[-1].minor.yy52, yymsp[0].minor.yy270, yymsp[-9].minor.yy52); +} +#line 6666 "parse.c" + /* No destructor defined for TRIGGER */ + /* No destructor defined for ON */ + break; + case 258: +#line 778 "parse.y" +{ yygotominor.yy52 = TK_BEFORE; } +#line 6673 "parse.c" + /* No destructor defined for BEFORE */ + break; + case 259: +#line 779 "parse.y" +{ yygotominor.yy52 = TK_AFTER; } +#line 6679 "parse.c" + /* No destructor defined for AFTER */ + break; + case 260: +#line 780 "parse.y" +{ yygotominor.yy52 = TK_INSTEAD;} +#line 6685 "parse.c" + /* No destructor defined for INSTEAD */ + /* No destructor defined for OF */ + break; + case 261: +#line 781 "parse.y" +{ yygotominor.yy52 = TK_BEFORE; } +#line 6692 "parse.c" + break; + case 262: +#line 785 "parse.y" +{ yygotominor.yy234.a = TK_DELETE; yygotominor.yy234.b = 0; } +#line 6697 "parse.c" + /* No destructor defined for DELETE */ + break; + case 263: +#line 786 "parse.y" +{ yygotominor.yy234.a = TK_INSERT; yygotominor.yy234.b = 0; } +#line 6703 "parse.c" + /* No destructor defined for INSERT */ + break; + case 264: +#line 787 "parse.y" +{ yygotominor.yy234.a = TK_UPDATE; yygotominor.yy234.b = 0;} +#line 6709 "parse.c" + /* No destructor defined for UPDATE */ + break; + case 265: +#line 788 "parse.y" +{yygotominor.yy234.a = TK_UPDATE; yygotominor.yy234.b = yymsp[0].minor.yy92; } +#line 6715 "parse.c" + /* No destructor defined for UPDATE */ + /* No destructor defined for OF */ + break; + case 266: +#line 791 "parse.y" +{ yygotominor.yy52 = TK_ROW; } +#line 6722 "parse.c" + break; + case 267: +#line 792 "parse.y" +{ yygotominor.yy52 = TK_ROW; } +#line 6727 "parse.c" + /* No destructor defined for FOR */ + /* No destructor defined for EACH */ + /* No destructor defined for ROW */ + break; + case 268: +#line 793 "parse.y" +{ yygotominor.yy52 = TK_STATEMENT; } +#line 6735 "parse.c" + /* No destructor defined for FOR */ + /* No destructor defined for EACH */ + /* No destructor defined for STATEMENT */ + break; + case 269: +#line 796 "parse.y" +{ yygotominor.yy270 = 0; } +#line 6743 "parse.c" + break; + case 270: +#line 797 "parse.y" +{ yygotominor.yy270 = yymsp[0].minor.yy334; } +#line 6748 "parse.c" + /* No destructor defined for WHEN */ + break; + case 271: +#line 801 "parse.y" +{ + yymsp[-2].minor.yy347->pNext = yymsp[0].minor.yy347; + yygotominor.yy347 = yymsp[-2].minor.yy347; +} +#line 6757 "parse.c" + /* No destructor defined for SEMI */ + break; + case 272: +#line 805 "parse.y" +{ yygotominor.yy347 = 0; } +#line 6763 "parse.c" + break; + case 273: +#line 811 "parse.y" +{ yygotominor.yy347 = sqliteTriggerUpdateStep(&yymsp[-3].minor.yy210, yymsp[-1].minor.yy62, yymsp[0].minor.yy334, yymsp[-4].minor.yy52); } +#line 6768 "parse.c" + /* No destructor defined for UPDATE */ + /* No destructor defined for SET */ + break; + case 274: +#line 816 "parse.y" +{yygotominor.yy347 = sqliteTriggerInsertStep(&yymsp[-5].minor.yy210, yymsp[-4].minor.yy92, yymsp[-1].minor.yy62, 0, yymsp[-7].minor.yy52);} +#line 6775 "parse.c" + /* No destructor defined for INSERT */ + /* No destructor defined for INTO */ + /* No destructor defined for VALUES */ + /* No destructor defined for LP */ + /* No destructor defined for RP */ + break; + case 275: +#line 819 "parse.y" +{yygotominor.yy347 = sqliteTriggerInsertStep(&yymsp[-2].minor.yy210, yymsp[-1].minor.yy92, 0, yymsp[0].minor.yy11, yymsp[-4].minor.yy52);} +#line 6785 "parse.c" + /* No destructor defined for INSERT */ + /* No destructor defined for INTO */ + break; + case 276: +#line 823 "parse.y" +{yygotominor.yy347 = sqliteTriggerDeleteStep(&yymsp[-1].minor.yy210, yymsp[0].minor.yy334);} +#line 6792 "parse.c" + /* No destructor defined for DELETE */ + /* No destructor defined for FROM */ + break; + case 277: +#line 826 "parse.y" +{yygotominor.yy347 = sqliteTriggerSelectStep(yymsp[0].minor.yy11); } +#line 6799 "parse.c" + break; + case 278: +#line 829 "parse.y" +{ + yygotominor.yy334 = sqliteExpr(TK_RAISE, 0, 0, 0); + yygotominor.yy334->iColumn = OE_Ignore; + sqliteExprSpan(yygotominor.yy334, &yymsp[-3].minor.yy0, &yymsp[0].minor.yy0); +} +#line 6808 "parse.c" + /* No destructor defined for LP */ + /* No destructor defined for IGNORE */ + break; + case 279: +#line 834 "parse.y" +{ + yygotominor.yy334 = sqliteExpr(TK_RAISE, 0, 0, &yymsp[-1].minor.yy210); + yygotominor.yy334->iColumn = OE_Rollback; + sqliteExprSpan(yygotominor.yy334, &yymsp[-5].minor.yy0, &yymsp[0].minor.yy0); +} +#line 6819 "parse.c" + /* No destructor defined for LP */ + /* No destructor defined for ROLLBACK */ + /* No destructor defined for COMMA */ + break; + case 280: +#line 839 "parse.y" +{ + yygotominor.yy334 = sqliteExpr(TK_RAISE, 0, 0, &yymsp[-1].minor.yy210); + yygotominor.yy334->iColumn = OE_Abort; + sqliteExprSpan(yygotominor.yy334, &yymsp[-5].minor.yy0, &yymsp[0].minor.yy0); +} +#line 6831 "parse.c" + /* No destructor defined for LP */ + /* No destructor defined for ABORT */ + /* No destructor defined for COMMA */ + break; + case 281: +#line 844 "parse.y" +{ + yygotominor.yy334 = sqliteExpr(TK_RAISE, 0, 0, &yymsp[-1].minor.yy210); + yygotominor.yy334->iColumn = OE_Fail; + sqliteExprSpan(yygotominor.yy334, &yymsp[-5].minor.yy0, &yymsp[0].minor.yy0); +} +#line 6843 "parse.c" + /* No destructor defined for LP */ + /* No destructor defined for FAIL */ + /* No destructor defined for COMMA */ + break; + case 282: +#line 851 "parse.y" +{ + sqliteDropTrigger(pParse,sqliteSrcListAppend(0,&yymsp[-1].minor.yy210,&yymsp[0].minor.yy210)); +} +#line 6853 "parse.c" + /* No destructor defined for DROP */ + /* No destructor defined for TRIGGER */ + break; + case 283: +#line 856 "parse.y" +{ + sqliteAttach(pParse, &yymsp[-2].minor.yy210, &yymsp[0].minor.yy210); +} +#line 6862 "parse.c" + /* No destructor defined for ATTACH */ + /* No destructor defined for database_kw_opt */ + /* No destructor defined for AS */ + break; + case 284: + /* No destructor defined for DATABASE */ + break; + case 285: + break; + case 286: +#line 864 "parse.y" +{ + sqliteDetach(pParse, &yymsp[0].minor.yy210); +} +#line 6877 "parse.c" + /* No destructor defined for DETACH */ + /* No destructor defined for database_kw_opt */ + break; + }; + yygoto = yyRuleInfo[yyruleno].lhs; + yysize = yyRuleInfo[yyruleno].nrhs; + yypParser->yyidx -= yysize; + yypParser->yytop -= yysize; + yyact = yy_find_parser_action(yypParser,yygoto); + if( yyact < YYNSTATE ){ + yy_shift(yypParser,yyact,yygoto,&yygotominor); + }else if( yyact == YYNSTATE + YYNRULE + 1 ){ + yy_accept(yypParser); + } +} + +/* +** The following code executes when the parse fails +*/ +static void yy_parse_failed( + yyParser *yypParser /* The parser */ +){ + sqliteParserARG_FETCH; +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt); + } +#endif + while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); + /* Here code is inserted which will be executed whenever the + ** parser fails */ + sqliteParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ +} + +/* +** The following code executes when a syntax error first occurs. +*/ +static void yy_syntax_error( + yyParser *yypParser, /* The parser */ + int yymajor, /* The major type of the error token */ + YYMINORTYPE yyminor /* The minor type of the error token */ +){ + sqliteParserARG_FETCH; +#define TOKEN (yyminor.yy0) +#line 23 "parse.y" + + if( pParse->zErrMsg==0 ){ + if( TOKEN.z[0] ){ + sqliteSetNString(&pParse->zErrMsg, + "near \"", -1, TOKEN.z, TOKEN.n, "\": syntax error", -1, 0); + }else{ + sqliteSetString(&pParse->zErrMsg, "incomplete SQL statement", 0); + } + } + pParse->nErr++; + +#line 6934 "parse.c" + sqliteParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ +} + +/* +** The following is executed when the parser accepts +*/ +static void yy_accept( + yyParser *yypParser /* The parser */ +){ + sqliteParserARG_FETCH; +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt); + } +#endif + while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); + /* Here code is inserted which will be executed whenever the + ** parser accepts */ + sqliteParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ +} + +/* The main parser program. +** The first argument is a pointer to a structure obtained from +** "sqliteParserAlloc" which describes the current state of the parser. +** The second argument is the major token number. The third is +** the minor token. The fourth optional argument is whatever the +** user wants (and specified in the grammar) and is available for +** use by the action routines. +** +** Inputs: +**
    +**
  • A pointer to the parser (an opaque structure.) +**
  • The major token number. +**
  • The minor token number. +**
  • An option argument of a grammar-specified type. +**
+** +** Outputs: +** None. +*/ +void sqliteParser( + void *yyp, /* The parser */ + int yymajor, /* The major token code number */ + sqliteParserTOKENTYPE yyminor /* The value for the token */ + sqliteParserARG_PDECL /* Optional %extra_argument parameter */ +){ + YYMINORTYPE yyminorunion; + int yyact; /* The parser action. */ + int yyendofinput; /* True if we are at the end of input */ + int yyerrorhit = 0; /* True if yymajor has invoked an error */ + yyParser *yypParser; /* The parser */ + + /* (re)initialize the parser, if necessary */ + yypParser = (yyParser*)yyp; + if( yypParser->yyidx<0 ){ + if( yymajor==0 ) return; + yypParser->yyidx = 0; + yypParser->yyerrcnt = -1; + yypParser->yytop = &yypParser->yystack[0]; + yypParser->yytop->stateno = 0; + yypParser->yytop->major = 0; + } + yyminorunion.yy0 = yyminor; + yyendofinput = (yymajor==0); + sqliteParserARG_STORE; + +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]); + } +#endif + + do{ + yyact = yy_find_parser_action(yypParser,yymajor); + if( yyactyyerrcnt--; + if( yyendofinput && yypParser->yyidx>=0 ){ + yymajor = 0; + }else{ + yymajor = YYNOCODE; + } + }else if( yyact < YYNSTATE + YYNRULE ){ + yy_reduce(yypParser,yyact-YYNSTATE); + }else if( yyact == YY_ERROR_ACTION ){ +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt); + } +#endif +#ifdef YYERRORSYMBOL + /* A syntax error has occurred. + ** The response to an error depends upon whether or not the + ** grammar defines an error token "ERROR". + ** + ** This is what we do if the grammar does define ERROR: + ** + ** * Call the %syntax_error function. + ** + ** * Begin popping the stack until we enter a state where + ** it is legal to shift the error symbol, then shift + ** the error symbol. + ** + ** * Set the error count to three. + ** + ** * Begin accepting and shifting new tokens. No new error + ** processing will occur until three tokens have been + ** shifted successfully. + ** + */ + if( yypParser->yyerrcnt<0 ){ + yy_syntax_error(yypParser,yymajor,yyminorunion); + } + if( yypParser->yytop->major==YYERRORSYMBOL || yyerrorhit ){ +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sDiscard input token %s\n", + yyTracePrompt,yyTokenName[yymajor]); + } +#endif + yy_destructor(yymajor,&yyminorunion); + yymajor = YYNOCODE; + }else{ + while( + yypParser->yyidx >= 0 && + yypParser->yytop->major != YYERRORSYMBOL && + (yyact = yy_find_parser_action(yypParser,YYERRORSYMBOL)) >= YYNSTATE + ){ + yy_pop_parser_stack(yypParser); + } + if( yypParser->yyidx < 0 || yymajor==0 ){ + yy_destructor(yymajor,&yyminorunion); + yy_parse_failed(yypParser); + yymajor = YYNOCODE; + }else if( yypParser->yytop->major!=YYERRORSYMBOL ){ + YYMINORTYPE u2; + u2.YYERRSYMDT = 0; + yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2); + } + } + yypParser->yyerrcnt = 3; + yyerrorhit = 1; +#else /* YYERRORSYMBOL is not defined */ + /* This is what we do if the grammar does not define ERROR: + ** + ** * Report an error message, and throw away the input token. + ** + ** * If the input token is $, then fail the parse. + ** + ** As before, subsequent error messages are suppressed until + ** three input tokens have been successfully shifted. + */ + if( yypParser->yyerrcnt<=0 ){ + yy_syntax_error(yypParser,yymajor,yyminorunion); + } + yypParser->yyerrcnt = 3; + yy_destructor(yymajor,&yyminorunion); + if( yyendofinput ){ + yy_parse_failed(yypParser); + } + yymajor = YYNOCODE; +#endif + }else{ + yy_accept(yypParser); + yymajor = YYNOCODE; + } + }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 ); + return; +} diff --git a/sqlitebrowser/sqlitebrowser/sqlite_source/parse.h b/sqlitebrowser/sqlitebrowser/sqlite_source/parse.h new file mode 100755 index 00000000..a9a45b08 --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/sqlite_source/parse.h @@ -0,0 +1,130 @@ +#define TK_ABORT 1 +#define TK_AFTER 2 +#define TK_AGG_FUNCTION 3 +#define TK_ALL 4 +#define TK_AND 5 +#define TK_AS 6 +#define TK_ASC 7 +#define TK_ATTACH 8 +#define TK_BEFORE 9 +#define TK_BEGIN 10 +#define TK_BETWEEN 11 +#define TK_BITAND 12 +#define TK_BITNOT 13 +#define TK_BITOR 14 +#define TK_BY 15 +#define TK_CASCADE 16 +#define TK_CASE 17 +#define TK_CHECK 18 +#define TK_CLUSTER 19 +#define TK_COLLATE 20 +#define TK_COLUMN 21 +#define TK_COMMA 22 +#define TK_COMMENT 23 +#define TK_COMMIT 24 +#define TK_CONCAT 25 +#define TK_CONFLICT 26 +#define TK_CONSTRAINT 27 +#define TK_COPY 28 +#define TK_CREATE 29 +#define TK_DATABASE 30 +#define TK_DEFAULT 31 +#define TK_DEFERRABLE 32 +#define TK_DEFERRED 33 +#define TK_DELETE 34 +#define TK_DELIMITERS 35 +#define TK_DESC 36 +#define TK_DETACH 37 +#define TK_DISTINCT 38 +#define TK_DOT 39 +#define TK_DROP 40 +#define TK_EACH 41 +#define TK_ELSE 42 +#define TK_END 43 +#define TK_END_OF_FILE 44 +#define TK_EQ 45 +#define TK_EXCEPT 46 +#define TK_EXPLAIN 47 +#define TK_FAIL 48 +#define TK_FLOAT 49 +#define TK_FOR 50 +#define TK_FOREIGN 51 +#define TK_FROM 52 +#define TK_FUNCTION 53 +#define TK_GE 54 +#define TK_GLOB 55 +#define TK_GROUP 56 +#define TK_GT 57 +#define TK_HAVING 58 +#define TK_ID 59 +#define TK_IGNORE 60 +#define TK_ILLEGAL 61 +#define TK_IMMEDIATE 62 +#define TK_IN 63 +#define TK_INDEX 64 +#define TK_INITIALLY 65 +#define TK_INSERT 66 +#define TK_INSTEAD 67 +#define TK_INTEGER 68 +#define TK_INTERSECT 69 +#define TK_INTO 70 +#define TK_IS 71 +#define TK_ISNULL 72 +#define TK_JOIN 73 +#define TK_JOIN_KW 74 +#define TK_KEY 75 +#define TK_LE 76 +#define TK_LIKE 77 +#define TK_LIMIT 78 +#define TK_LP 79 +#define TK_LSHIFT 80 +#define TK_LT 81 +#define TK_MATCH 82 +#define TK_MINUS 83 +#define TK_NE 84 +#define TK_NOT 85 +#define TK_NOTNULL 86 +#define TK_NULL 87 +#define TK_OF 88 +#define TK_OFFSET 89 +#define TK_ON 90 +#define TK_OR 91 +#define TK_ORACLE_OUTER_JOIN 92 +#define TK_ORDER 93 +#define TK_PLUS 94 +#define TK_PRAGMA 95 +#define TK_PRIMARY 96 +#define TK_RAISE 97 +#define TK_REFERENCES 98 +#define TK_REM 99 +#define TK_REPLACE 100 +#define TK_RESTRICT 101 +#define TK_ROLLBACK 102 +#define TK_ROW 103 +#define TK_RP 104 +#define TK_RSHIFT 105 +#define TK_SELECT 106 +#define TK_SEMI 107 +#define TK_SET 108 +#define TK_SLASH 109 +#define TK_SPACE 110 +#define TK_STAR 111 +#define TK_STATEMENT 112 +#define TK_STRING 113 +#define TK_TABLE 114 +#define TK_TEMP 115 +#define TK_THEN 116 +#define TK_TRANSACTION 117 +#define TK_TRIGGER 118 +#define TK_UMINUS 119 +#define TK_UNCLOSED_STRING 120 +#define TK_UNION 121 +#define TK_UNIQUE 122 +#define TK_UPDATE 123 +#define TK_UPLUS 124 +#define TK_USING 125 +#define TK_VACUUM 126 +#define TK_VALUES 127 +#define TK_VIEW 128 +#define TK_WHEN 129 +#define TK_WHERE 130 diff --git a/sqlitebrowser/sqlitebrowser/sqlite_source/pragma.c b/sqlitebrowser/sqlitebrowser/sqlite_source/pragma.c new file mode 100755 index 00000000..67594126 --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/sqlite_source/pragma.c @@ -0,0 +1,667 @@ +/* +** 2003 April 6 +** +** 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 code used to implement the PRAGMA command. +** +** $Id: pragma.c,v 1.1.1.1 2003-08-21 02:24:17 tabuleiro Exp $ +*/ +#include "sqliteInt.h" +#include + +/* +** Interpret the given string as a boolean value. +*/ +static int getBoolean(char *z){ + static char *azTrue[] = { "yes", "on", "true" }; + int i; + if( z[0]==0 ) return 0; + if( isdigit(z[0]) || (z[0]=='-' && isdigit(z[1])) ){ + return atoi(z); + } + for(i=0; i='0' || z[0]<='2' ){ + return z[0] - '0'; + }else if( sqliteStrICmp(z, "file")==0 ){ + return 1; + }else if( sqliteStrICmp(z, "memory")==0 ){ + return 2; + }else{ + return 0; + } +} + +/* +** Process a pragma statement. +** +** Pragmas are of this form: +** +** PRAGMA id = value +** +** The identifier might also be a string. The value is a string, and +** identifier, or a number. If minusFlag is true, then the value is +** a number that was preceded by a minus sign. +*/ +void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){ + char *zLeft = 0; + char *zRight = 0; + sqlite *db = pParse->db; + Vdbe *v = sqliteGetVdbe(pParse); + if( v==0 ) return; + + zLeft = sqliteStrNDup(pLeft->z, pLeft->n); + sqliteDequote(zLeft); + if( minusFlag ){ + zRight = 0; + sqliteSetNString(&zRight, "-", 1, pRight->z, pRight->n, 0); + }else{ + zRight = sqliteStrNDup(pRight->z, pRight->n); + sqliteDequote(zRight); + } + if( sqliteAuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight, 0) ){ + sqliteFree(zLeft); + sqliteFree(zRight); + return; + } + + /* + ** PRAGMA default_cache_size + ** PRAGMA default_cache_size=N + ** + ** The first form reports the current persistent setting for the + ** page cache size. The value returned is the maximum number of + ** pages in the page cache. The second form sets both the current + ** page cache size value and the persistent page cache size value + ** stored in the database file. + ** + ** The default cache size is stored in meta-value 2 of page 1 of the + ** database file. The cache size is actually the absolute value of + ** this memory location. The sign of meta-value 2 determines the + ** synchronous setting. A negative value means synchronous is off + ** and a positive value means synchronous is on. + */ + if( sqliteStrICmp(zLeft,"default_cache_size")==0 ){ + static VdbeOp getCacheSize[] = { + { OP_ReadCookie, 0, 2, 0}, + { OP_AbsValue, 0, 0, 0}, + { OP_Dup, 0, 0, 0}, + { OP_Integer, 0, 0, 0}, + { OP_Ne, 0, 6, 0}, + { OP_Integer, MAX_PAGES,0, 0}, + { OP_ColumnName, 0, 0, "cache_size"}, + { OP_Callback, 1, 0, 0}, + }; + if( pRight->z==pLeft->z ){ + sqliteVdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize); + }else{ + int addr; + int size = atoi(zRight); + if( size<0 ) size = -size; + sqliteBeginWriteOperation(pParse, 0, 0); + sqliteVdbeAddOp(v, OP_Integer, size, 0); + sqliteVdbeAddOp(v, OP_ReadCookie, 0, 2); + addr = sqliteVdbeAddOp(v, OP_Integer, 0, 0); + sqliteVdbeAddOp(v, OP_Ge, 0, addr+3); + sqliteVdbeAddOp(v, OP_Negative, 0, 0); + sqliteVdbeAddOp(v, OP_SetCookie, 0, 2); + sqliteEndWriteOperation(pParse); + db->cache_size = db->cache_size<0 ? -size : size; + sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size); + } + }else + + /* + ** PRAGMA cache_size + ** PRAGMA cache_size=N + ** + ** The first form reports the current local setting for the + ** page cache size. The local setting can be different from + ** the persistent cache size value that is stored in the database + ** file itself. The value returned is the maximum number of + ** pages in the page cache. The second form sets the local + ** page cache size value. It does not change the persistent + ** cache size stored on the disk so the cache size will revert + ** to its default value when the database is closed and reopened. + ** N should be a positive integer. + */ + if( sqliteStrICmp(zLeft,"cache_size")==0 ){ + static VdbeOp getCacheSize[] = { + { OP_ColumnName, 0, 0, "cache_size"}, + { OP_Callback, 1, 0, 0}, + }; + if( pRight->z==pLeft->z ){ + int size = db->cache_size;; + if( size<0 ) size = -size; + sqliteVdbeAddOp(v, OP_Integer, size, 0); + sqliteVdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize); + }else{ + int size = atoi(zRight); + if( size<0 ) size = -size; + if( db->cache_size<0 ) size = -size; + db->cache_size = size; + sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size); + } + }else + + /* + ** PRAGMA default_synchronous + ** PRAGMA default_synchronous=ON|OFF|NORMAL|FULL + ** + ** The first form returns the persistent value of the "synchronous" setting + ** that is stored in the database. This is the synchronous setting that + ** is used whenever the database is opened unless overridden by a separate + ** "synchronous" pragma. The second form changes the persistent and the + ** local synchronous setting to the value given. + ** + ** If synchronous is OFF, SQLite does not attempt any fsync() systems calls + ** to make sure data is committed to disk. Write operations are very fast, + ** but a power failure can leave the database in an inconsistent state. + ** If synchronous is ON or NORMAL, SQLite will do an fsync() system call to + ** make sure data is being written to disk. The risk of corruption due to + ** a power loss in this mode is negligible but non-zero. If synchronous + ** is FULL, extra fsync()s occur to reduce the risk of corruption to near + ** zero, but with a write performance penalty. The default mode is NORMAL. + */ + if( sqliteStrICmp(zLeft,"default_synchronous")==0 ){ + static VdbeOp getSync[] = { + { OP_ColumnName, 0, 0, "synchronous"}, + { OP_ReadCookie, 0, 3, 0}, + { OP_Dup, 0, 0, 0}, + { OP_If, 0, 0, 0}, /* 3 */ + { OP_ReadCookie, 0, 2, 0}, + { OP_Integer, 0, 0, 0}, + { OP_Lt, 0, 5, 0}, + { OP_AddImm, 1, 0, 0}, + { OP_Callback, 1, 0, 0}, + { OP_Halt, 0, 0, 0}, + { OP_AddImm, -1, 0, 0}, /* 10 */ + { OP_Callback, 1, 0, 0} + }; + if( pRight->z==pLeft->z ){ + int addr = sqliteVdbeAddOpList(v, ArraySize(getSync), getSync); + sqliteVdbeChangeP2(v, addr+3, addr+10); + }else{ + int addr; + int size = db->cache_size; + if( size<0 ) size = -size; + sqliteBeginWriteOperation(pParse, 0, 0); + sqliteVdbeAddOp(v, OP_ReadCookie, 0, 2); + sqliteVdbeAddOp(v, OP_Dup, 0, 0); + addr = sqliteVdbeAddOp(v, OP_Integer, 0, 0); + sqliteVdbeAddOp(v, OP_Ne, 0, addr+3); + sqliteVdbeAddOp(v, OP_AddImm, MAX_PAGES, 0); + sqliteVdbeAddOp(v, OP_AbsValue, 0, 0); + db->safety_level = getSafetyLevel(zRight)+1; + if( db->safety_level==1 ){ + sqliteVdbeAddOp(v, OP_Negative, 0, 0); + size = -size; + } + sqliteVdbeAddOp(v, OP_SetCookie, 0, 2); + sqliteVdbeAddOp(v, OP_Integer, db->safety_level, 0); + sqliteVdbeAddOp(v, OP_SetCookie, 0, 3); + sqliteEndWriteOperation(pParse); + db->cache_size = size; + sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size); + sqliteBtreeSetSafetyLevel(db->aDb[0].pBt, db->safety_level); + } + }else + + /* + ** PRAGMA synchronous + ** PRAGMA synchronous=OFF|ON|NORMAL|FULL + ** + ** Return or set the local value of the synchronous flag. Changing + ** the local value does not make changes to the disk file and the + ** default value will be restored the next time the database is + ** opened. + */ + if( sqliteStrICmp(zLeft,"synchronous")==0 ){ + static VdbeOp getSync[] = { + { OP_ColumnName, 0, 0, "synchronous"}, + { OP_Callback, 1, 0, 0}, + }; + if( pRight->z==pLeft->z ){ + sqliteVdbeAddOp(v, OP_Integer, db->safety_level-1, 0); + sqliteVdbeAddOpList(v, ArraySize(getSync), getSync); + }else{ + int size = db->cache_size; + if( size<0 ) size = -size; + db->safety_level = getSafetyLevel(zRight)+1; + if( db->safety_level==1 ) size = -size; + db->cache_size = size; + sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size); + sqliteBtreeSetSafetyLevel(db->aDb[0].pBt, db->safety_level); + } + }else + + if( sqliteStrICmp(zLeft, "trigger_overhead_test")==0 ){ + if( getBoolean(zRight) ){ + always_code_trigger_setup = 1; + }else{ + always_code_trigger_setup = 0; + } + }else + + if( sqliteStrICmp(zLeft, "vdbe_trace")==0 ){ + if( getBoolean(zRight) ){ + db->flags |= SQLITE_VdbeTrace; + }else{ + db->flags &= ~SQLITE_VdbeTrace; + } + }else + + if( sqliteStrICmp(zLeft, "full_column_names")==0 ){ + if( getBoolean(zRight) ){ + db->flags |= SQLITE_FullColNames; + }else{ + db->flags &= ~SQLITE_FullColNames; + } + }else + + if( sqliteStrICmp(zLeft, "show_datatypes")==0 ){ + if( getBoolean(zRight) ){ + db->flags |= SQLITE_ReportTypes; + }else{ + db->flags &= ~SQLITE_ReportTypes; + } + }else + + if( sqliteStrICmp(zLeft, "count_changes")==0 ){ + if( getBoolean(zRight) ){ + db->flags |= SQLITE_CountRows; + }else{ + db->flags &= ~SQLITE_CountRows; + } + }else + + if( sqliteStrICmp(zLeft, "empty_result_callbacks")==0 ){ + if( getBoolean(zRight) ){ + db->flags |= SQLITE_NullCallback; + }else{ + db->flags &= ~SQLITE_NullCallback; + } + }else + + if( sqliteStrICmp(zLeft, "table_info")==0 ){ + Table *pTab; + pTab = sqliteFindTable(db, zRight, 0); + if( pTab ){ + static VdbeOp tableInfoPreface[] = { + { OP_ColumnName, 0, 0, "cid"}, + { OP_ColumnName, 1, 0, "name"}, + { OP_ColumnName, 2, 0, "type"}, + { OP_ColumnName, 3, 0, "notnull"}, + { OP_ColumnName, 4, 0, "dflt_value"}, + }; + int i; + sqliteVdbeAddOpList(v, ArraySize(tableInfoPreface), tableInfoPreface); + sqliteViewGetColumnNames(pParse, pTab); + for(i=0; inCol; i++){ + sqliteVdbeAddOp(v, OP_Integer, i, 0); + sqliteVdbeAddOp(v, OP_String, 0, 0); + sqliteVdbeChangeP3(v, -1, pTab->aCol[i].zName, P3_STATIC); + sqliteVdbeAddOp(v, OP_String, 0, 0); + sqliteVdbeChangeP3(v, -1, + pTab->aCol[i].zType ? pTab->aCol[i].zType : "numeric", P3_STATIC); + sqliteVdbeAddOp(v, OP_Integer, pTab->aCol[i].notNull, 0); + sqliteVdbeAddOp(v, OP_String, 0, 0); + sqliteVdbeChangeP3(v, -1, pTab->aCol[i].zDflt, P3_STATIC); + sqliteVdbeAddOp(v, OP_Callback, 5, 0); + } + } + }else + + if( sqliteStrICmp(zLeft, "index_info")==0 ){ + Index *pIdx; + Table *pTab; + pIdx = sqliteFindIndex(db, zRight, 0); + if( pIdx ){ + static VdbeOp tableInfoPreface[] = { + { OP_ColumnName, 0, 0, "seqno"}, + { OP_ColumnName, 1, 0, "cid"}, + { OP_ColumnName, 2, 0, "name"}, + }; + int i; + pTab = pIdx->pTable; + sqliteVdbeAddOpList(v, ArraySize(tableInfoPreface), tableInfoPreface); + for(i=0; inColumn; i++){ + int cnum = pIdx->aiColumn[i]; + sqliteVdbeAddOp(v, OP_Integer, i, 0); + sqliteVdbeAddOp(v, OP_Integer, cnum, 0); + sqliteVdbeAddOp(v, OP_String, 0, 0); + assert( pTab->nCol>cnum ); + sqliteVdbeChangeP3(v, -1, pTab->aCol[cnum].zName, P3_STATIC); + sqliteVdbeAddOp(v, OP_Callback, 3, 0); + } + } + }else + + if( sqliteStrICmp(zLeft, "index_list")==0 ){ + Index *pIdx; + Table *pTab; + pTab = sqliteFindTable(db, zRight, 0); + if( pTab ){ + v = sqliteGetVdbe(pParse); + pIdx = pTab->pIndex; + } + if( pTab && pIdx ){ + int i = 0; + static VdbeOp indexListPreface[] = { + { OP_ColumnName, 0, 0, "seq"}, + { OP_ColumnName, 1, 0, "name"}, + { OP_ColumnName, 2, 0, "unique"}, + }; + + sqliteVdbeAddOpList(v, ArraySize(indexListPreface), indexListPreface); + while(pIdx){ + sqliteVdbeAddOp(v, OP_Integer, i, 0); + sqliteVdbeAddOp(v, OP_String, 0, 0); + sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC); + sqliteVdbeAddOp(v, OP_Integer, pIdx->onError!=OE_None, 0); + sqliteVdbeAddOp(v, OP_Callback, 3, 0); + ++i; + pIdx = pIdx->pNext; + } + } + }else + + if( sqliteStrICmp(zLeft, "database_list")==0 ){ + int i; + static VdbeOp indexListPreface[] = { + { OP_ColumnName, 0, 0, "seq"}, + { OP_ColumnName, 1, 0, "name"}, + { OP_ColumnName, 2, 0, "file"}, + }; + + sqliteVdbeAddOpList(v, ArraySize(indexListPreface), indexListPreface); + for(i=0; inDb; i++){ + if( db->aDb[i].pBt==0 ) continue; + assert( db->aDb[i].zName!=0 ); + sqliteVdbeAddOp(v, OP_Integer, i, 0); + sqliteVdbeAddOp(v, OP_String, 0, 0); + sqliteVdbeChangeP3(v, -1, db->aDb[i].zName, P3_STATIC); + sqliteVdbeAddOp(v, OP_String, 0, 0); + sqliteVdbeChangeP3(v, -1, sqliteBtreeGetFilename(db->aDb[i].pBt), + P3_STATIC); + sqliteVdbeAddOp(v, OP_Callback, 3, 0); + } + }else + /* + ** PRAGMA temp_store + ** PRAGMA temp_store = "default"|"memory"|"file" + ** + ** Return or set the local value of the temp_store flag. Changing + ** the local value does not make changes to the disk file and the default + ** value will be restored the next time the database is opened. + ** + ** Note that it is possible for the library compile-time options to + ** override this setting + */ + if( sqliteStrICmp(zLeft, "temp_store")==0 ){ + static VdbeOp getTmpDbLoc[] = { + { OP_ColumnName, 0, 0, "temp_store"}, + { OP_Callback, 1, 0, 0}, + }; + if( pRight->z==pLeft->z ){ + sqliteVdbeAddOp(v, OP_Integer, db->temp_store, 0); + sqliteVdbeAddOpList(v, ArraySize(getTmpDbLoc), getTmpDbLoc); + }else{ + if (&db->aDb[1].pBt != 0) { + sqliteErrorMsg(pParse, "The temporary database already exists - " + "its location cannot now be changed"); + } else { + db->temp_store = getTempStore(zRight); + } + } + }else + + /* + ** PRAGMA default_temp_store + ** PRAGMA default_temp_store = "default"|"memory"|"file" + ** + ** Return or set the value of the persistent temp_store flag (as + ** well as the value currently in force). + ** + ** Note that it is possible for the library compile-time options to + ** override this setting + */ + if( sqliteStrICmp(zLeft, "default_temp_store")==0 ){ + static VdbeOp getTmpDbLoc[] = { + { OP_ColumnName, 0, 0, "temp_store"}, + { OP_ReadCookie, 0, 5, 0}, + { OP_Callback, 1, 0, 0}}; + if( pRight->z==pLeft->z ){ + sqliteVdbeAddOpList(v, ArraySize(getTmpDbLoc), getTmpDbLoc); + }else{ + if (&db->aDb[1].pBt != 0) { + sqliteErrorMsg(pParse, "The temporary database already exists - " + "its location cannot now be changed"); + } else { + sqliteBeginWriteOperation(pParse, 0, 0); + db->temp_store = getTempStore(zRight); + sqliteVdbeAddOp(v, OP_Integer, db->temp_store, 0); + sqliteVdbeAddOp(v, OP_SetCookie, 0, 5); + sqliteEndWriteOperation(pParse); + } + } + }else + +#ifndef NDEBUG + if( sqliteStrICmp(zLeft, "parser_trace")==0 ){ + extern void sqliteParserTrace(FILE*, char *); + if( getBoolean(zRight) ){ + sqliteParserTrace(stdout, "parser: "); + }else{ + sqliteParserTrace(0, 0); + } + }else +#endif + + if( sqliteStrICmp(zLeft, "integrity_check")==0 ){ + int i, j, addr; + + /* Code that initializes the integrity check program. Set the + ** error message to an empty string and register the callback + ** column name. + */ + static VdbeOp initCode[] = { + { OP_String, 0, 0, ""}, + { OP_MemStore, 0, 1, 0}, + { OP_ColumnName, 0, 0, "integrity_check"}, + }; + + /* Code to do an BTree integrity check on a single database file. + */ + static VdbeOp checkDb[] = { + { OP_SetInsert, 0, 0, "2"}, + { OP_Integer, 0, 0, 0}, /* 1 */ + { OP_OpenRead, 0, 2, 0}, + { OP_Rewind, 0, 7, 0}, /* 3 */ + { OP_Column, 0, 3, 0}, /* 4 */ + { OP_SetInsert, 0, 0, 0}, + { OP_Next, 0, 4, 0}, /* 6 */ + { OP_IntegrityCk, 0, 0, 0}, /* 7 */ + { OP_Dup, 0, 1, 0}, + { OP_String, 0, 0, "ok"}, + { OP_StrEq, 0, 12, 0}, /* 10 */ + { OP_MemLoad, 0, 0, 0}, + { OP_String, 0, 0, "*** in database "}, + { OP_String, 0, 0, 0}, /* 13 */ + { OP_String, 0, 0, " ***\n"}, + { OP_Pull, 4, 0, 0}, + { OP_Concat, 5, 1, 0}, + { OP_MemStore, 0, 1, 0}, + { OP_Integer, 0, 0, 0}, + { OP_Pop, 1, 0, 0}, + }; + + /* Code that appears at the end of the integrity check. If no error + ** messages have been generated, output OK. Otherwise output the + ** error message + */ + static VdbeOp endCode[] = { + { OP_MemLoad, 0, 0, 0}, + { OP_Dup, 0, 1, 0}, + { OP_String, 0, 0, ""}, + { OP_StrNe, 0, 0, 0}, /* 3 */ + { OP_Pop, 1, 0, 0}, + { OP_String, 0, 0, "ok"}, + { OP_Callback, 1, 0, 0}, + }; + + /* Initialize the VDBE program */ + sqliteVdbeAddOpList(v, ArraySize(initCode), initCode); + + /* Do an integrity check on each database file */ + for(i=0; inDb; i++){ + HashElem *x; + + /* Do an integrity check of the B-Tree + */ + addr = sqliteVdbeAddOpList(v, ArraySize(checkDb), checkDb); + sqliteVdbeChangeP1(v, addr+1, i); + sqliteVdbeChangeP2(v, addr+3, addr+7); + sqliteVdbeChangeP2(v, addr+6, addr+4); + sqliteVdbeChangeP2(v, addr+7, i); + sqliteVdbeChangeP2(v, addr+10, addr+ArraySize(checkDb)-1); + sqliteVdbeChangeP3(v, addr+13, db->aDb[i].zName, P3_STATIC); + + /* Make sure all the indices are constructed correctly. + */ + sqliteCodeVerifySchema(pParse, i); + for(x=sqliteHashFirst(&db->aDb[i].tblHash); x; x=sqliteHashNext(x)){ + Table *pTab = sqliteHashData(x); + Index *pIdx; + int loopTop; + + if( pTab->pIndex==0 ) continue; + sqliteVdbeAddOp(v, OP_Integer, i, 0); + sqliteVdbeAddOp(v, OP_OpenRead, 1, pTab->tnum); + sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC); + for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ + if( pIdx->tnum==0 ) continue; + sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0); + sqliteVdbeAddOp(v, OP_OpenRead, j+2, pIdx->tnum); + sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC); + } + sqliteVdbeAddOp(v, OP_Integer, 0, 0); + sqliteVdbeAddOp(v, OP_MemStore, 1, 1); + loopTop = sqliteVdbeAddOp(v, OP_Rewind, 1, 0); + sqliteVdbeAddOp(v, OP_MemIncr, 1, 0); + for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ + int k, jmp2; + static VdbeOp idxErr[] = { + { OP_MemLoad, 0, 0, 0}, + { OP_String, 0, 0, "rowid "}, + { OP_Recno, 1, 0, 0}, + { OP_String, 0, 0, " missing from index "}, + { OP_String, 0, 0, 0}, /* 4 */ + { OP_String, 0, 0, "\n"}, + { OP_Concat, 6, 0, 0}, + { OP_MemStore, 0, 1, 0}, + }; + sqliteVdbeAddOp(v, OP_Recno, 1, 0); + for(k=0; knColumn; k++){ + int idx = pIdx->aiColumn[k]; + if( idx==pTab->iPKey ){ + sqliteVdbeAddOp(v, OP_Recno, 1, 0); + }else{ + sqliteVdbeAddOp(v, OP_Column, 1, idx); + } + } + sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0); + if( db->file_format>=4 ) sqliteAddIdxKeyType(v, pIdx); + jmp2 = sqliteVdbeAddOp(v, OP_Found, j+2, 0); + addr = sqliteVdbeAddOpList(v, ArraySize(idxErr), idxErr); + sqliteVdbeChangeP3(v, addr+4, pIdx->zName, P3_STATIC); + sqliteVdbeChangeP2(v, jmp2, sqliteVdbeCurrentAddr(v)); + } + sqliteVdbeAddOp(v, OP_Next, 1, loopTop+1); + sqliteVdbeChangeP2(v, loopTop, sqliteVdbeCurrentAddr(v)); + for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ + static VdbeOp cntIdx[] = { + { OP_Integer, 0, 0, 0}, + { OP_MemStore, 2, 1, 0}, + { OP_Rewind, 0, 0, 0}, /* 2 */ + { OP_MemIncr, 2, 0, 0}, + { OP_Next, 0, 0, 0}, /* 4 */ + { OP_MemLoad, 1, 0, 0}, + { OP_MemLoad, 2, 0, 0}, + { OP_Eq, 0, 0, 0}, /* 7 */ + { OP_MemLoad, 0, 0, 0}, + { OP_String, 0, 0, "wrong # of entries in index "}, + { OP_String, 0, 0, 0}, /* 10 */ + { OP_String, 0, 0, "\n"}, + { OP_Concat, 4, 0, 0}, + { OP_MemStore, 0, 1, 0}, + }; + if( pIdx->tnum==0 ) continue; + addr = sqliteVdbeAddOpList(v, ArraySize(cntIdx), cntIdx); + sqliteVdbeChangeP1(v, addr+2, j+2); + sqliteVdbeChangeP2(v, addr+2, addr+5); + sqliteVdbeChangeP1(v, addr+4, j+2); + sqliteVdbeChangeP2(v, addr+4, addr+3); + sqliteVdbeChangeP2(v, addr+7, addr+ArraySize(cntIdx)); + sqliteVdbeChangeP3(v, addr+10, pIdx->zName, P3_STATIC); + } + } + } + addr = sqliteVdbeAddOpList(v, ArraySize(endCode), endCode); + sqliteVdbeChangeP2(v, addr+3, addr+ArraySize(endCode)-1); + }else + + {} + sqliteFree(zLeft); + sqliteFree(zRight); +} diff --git a/sqlitebrowser/sqlitebrowser/sqlite_source/printf.c b/sqlitebrowser/sqlitebrowser/sqlite_source/printf.c new file mode 100755 index 00000000..622608b2 --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/sqlite_source/printf.c @@ -0,0 +1,834 @@ +/* +** The "printf" code that follows dates from the 1980's. It is in +** the public domain. The original comments are included here for +** completeness. They are slightly out-of-date. +** +** The following modules is an enhanced replacement for the "printf" subroutines +** found in the standard C library. The following enhancements are +** supported: +** +** + Additional functions. The standard set of "printf" functions +** includes printf, fprintf, sprintf, vprintf, vfprintf, and +** vsprintf. This module adds the following: +** +** * snprintf -- Works like sprintf, but has an extra argument +** which is the size of the buffer written to. +** +** * mprintf -- Similar to sprintf. Writes output to memory +** obtained from malloc. +** +** * xprintf -- Calls a function to dispose of output. +** +** * nprintf -- No output, but returns the number of characters +** that would have been output by printf. +** +** * A v- version (ex: vsnprintf) of every function is also +** supplied. +** +** + A few extensions to the formatting notation are supported: +** +** * The "=" flag (similar to "-") causes the output to be +** be centered in the appropriately sized field. +** +** * The %b field outputs an integer in binary notation. +** +** * The %c field now accepts a precision. The character output +** is repeated by the number of times the precision specifies. +** +** * The %' field works like %c, but takes as its character the +** next character of the format string, instead of the next +** argument. For example, printf("%.78'-") prints 78 minus +** signs, the same as printf("%.78c",'-'). +** +** + When compiled using GCC on a SPARC, this version of printf is +** faster than the library printf for SUN OS 4.1. +** +** + All functions are fully reentrant. +** +*/ +#include "sqliteInt.h" + +/* +** Undefine COMPATIBILITY to make some slight changes in the way things +** work. I think the changes are an improvement, but they are not +** backwards compatible. +*/ +/* #define COMPATIBILITY / * Compatible with SUN OS 4.1 */ + +/* +** Conversion types fall into various categories as defined by the +** following enumeration. +*/ +enum et_type { /* The type of the format field */ + etRADIX, /* Integer types. %d, %x, %o, and so forth */ + etFLOAT, /* Floating point. %f */ + etEXP, /* Exponentional notation. %e and %E */ + etGENERIC, /* Floating or exponential, depending on exponent. %g */ + etSIZE, /* Return number of characters processed so far. %n */ + etSTRING, /* Strings. %s */ + etDYNSTRING, /* Dynamically allocated strings. %z */ + etPERCENT, /* Percent symbol. %% */ + etCHARX, /* Characters. %c */ + etERROR, /* Used to indicate no such conversion type */ +/* The rest are extensions, not normally found in printf() */ + etCHARLIT, /* Literal characters. %' */ + etSQLESCAPE, /* Strings with '\'' doubled. %q */ + etSQLESCAPE2, /* Strings with '\'' doubled and enclosed in '', + NULL pointers replaced by SQL NULL. %Q */ + etORDINAL /* 1st, 2nd, 3rd and so forth */ +}; + +/* +** Each builtin conversion character (ex: the 'd' in "%d") is described +** by an instance of the following structure +*/ +typedef struct et_info { /* Information about each format field */ + int fmttype; /* The format field code letter */ + int base; /* The base for radix conversion */ + char *charset; /* The character set for conversion */ + int flag_signed; /* Is the quantity signed? */ + char *prefix; /* Prefix on non-zero values in alt format */ + enum et_type type; /* Conversion paradigm */ +} et_info; + +/* +** The following table is searched linearly, so it is good to put the +** most frequently used conversion types first. +*/ +static et_info fmtinfo[] = { + { 'd', 10, "0123456789", 1, 0, etRADIX, }, + { 's', 0, 0, 0, 0, etSTRING, }, + { 'z', 0, 0, 0, 0, etDYNSTRING, }, + { 'q', 0, 0, 0, 0, etSQLESCAPE, }, + { 'Q', 0, 0, 0, 0, etSQLESCAPE2, }, + { 'c', 0, 0, 0, 0, etCHARX, }, + { 'o', 8, "01234567", 0, "0", etRADIX, }, + { 'u', 10, "0123456789", 0, 0, etRADIX, }, + { 'x', 16, "0123456789abcdef", 0, "x0", etRADIX, }, + { 'X', 16, "0123456789ABCDEF", 0, "X0", etRADIX, }, + { 'r', 10, "0123456789", 0, 0, etORDINAL, }, + { 'f', 0, 0, 1, 0, etFLOAT, }, + { 'e', 0, "e", 1, 0, etEXP, }, + { 'E', 0, "E", 1, 0, etEXP, }, + { 'g', 0, "e", 1, 0, etGENERIC, }, + { 'G', 0, "E", 1, 0, etGENERIC, }, + { 'i', 10, "0123456789", 1, 0, etRADIX, }, + { 'n', 0, 0, 0, 0, etSIZE, }, + { '%', 0, 0, 0, 0, etPERCENT, }, + { 'b', 2, "01", 0, "b0", etRADIX, }, /* Binary */ + { 'p', 10, "0123456789", 0, 0, etRADIX, }, /* Pointers */ + { '\'', 0, 0, 0, 0, etCHARLIT, }, /* Literal char */ +}; +#define etNINFO (sizeof(fmtinfo)/sizeof(fmtinfo[0])) + +/* +** If NOFLOATINGPOINT is defined, then none of the floating point +** conversions will work. +*/ +#ifndef etNOFLOATINGPOINT +/* +** "*val" is a double such that 0.1 <= *val < 10.0 +** Return the ascii code for the leading digit of *val, then +** multiply "*val" by 10.0 to renormalize. +** +** Example: +** input: *val = 3.14159 +** output: *val = 1.4159 function return = '3' +** +** The counter *cnt is incremented each time. After counter exceeds +** 16 (the number of significant digits in a 64-bit float) '0' is +** always returned. +*/ +static int et_getdigit(double *val, int *cnt){ + int digit; + double d; + if( (*cnt)++ >= 16 ) return '0'; + digit = (int)*val; + d = digit; + digit += '0'; + *val = (*val - d)*10.0; + return digit; +} +#endif + +#define etBUFSIZE 1000 /* Size of the output buffer */ + +/* +** The root program. All variations call this core. +** +** INPUTS: +** func This is a pointer to a function taking three arguments +** 1. A pointer to anything. Same as the "arg" parameter. +** 2. A pointer to the list of characters to be output +** (Note, this list is NOT null terminated.) +** 3. An integer number of characters to be output. +** (Note: This number might be zero.) +** +** arg This is the pointer to anything which will be passed as the +** first argument to "func". Use it for whatever you like. +** +** fmt This is the format string, as in the usual print. +** +** ap This is a pointer to a list of arguments. Same as in +** vfprint. +** +** OUTPUTS: +** The return value is the total number of characters sent to +** the function "func". Returns -1 on a error. +** +** Note that the order in which automatic variables are declared below +** seems to make a big difference in determining how fast this beast +** will run. +*/ +static int vxprintf( + void (*func)(void*,char*,int), + void *arg, + const char *format, + va_list ap +){ + register const char *fmt; /* The format string. */ + register int c; /* Next character in the format string */ + register char *bufpt; /* Pointer to the conversion buffer */ + register int precision; /* Precision of the current field */ + register int length; /* Length of the field */ + register int idx; /* A general purpose loop counter */ + int count; /* Total number of characters output */ + int width; /* Width of the current field */ + int flag_leftjustify; /* True if "-" flag is present */ + int flag_plussign; /* True if "+" flag is present */ + int flag_blanksign; /* True if " " flag is present */ + int flag_alternateform; /* True if "#" flag is present */ + int flag_zeropad; /* True if field width constant starts with zero */ + int flag_long; /* True if "l" flag is present */ + int flag_center; /* True if "=" flag is present */ + unsigned long longvalue; /* Value for integer types */ + double realvalue; /* Value for real types */ + et_info *infop; /* Pointer to the appropriate info structure */ + char buf[etBUFSIZE]; /* Conversion buffer */ + char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */ + int errorflag = 0; /* True if an error is encountered */ + enum et_type xtype; /* Conversion paradigm */ + char *zExtra; /* Extra memory used for etTCLESCAPE conversions */ + static char spaces[] = " " + " "; +#define etSPACESIZE (sizeof(spaces)-1) +#ifndef etNOFLOATINGPOINT + int exp; /* exponent of real numbers */ + double rounder; /* Used for rounding floating point values */ + int flag_dp; /* True if decimal point should be shown */ + int flag_rtz; /* True if trailing zeros should be removed */ + int flag_exp; /* True to force display of the exponent */ + int nsd; /* Number of significant digits returned */ +#endif + + fmt = format; /* Put in a register for speed */ + count = length = 0; + bufpt = 0; + for(; (c=(*fmt))!=0; ++fmt){ + if( c!='%' ){ + register int amt; + bufpt = (char *)fmt; + amt = 1; + while( (c=(*++fmt))!='%' && c!=0 ) amt++; + (*func)(arg,bufpt,amt); + count += amt; + if( c==0 ) break; + } + if( (c=(*++fmt))==0 ){ + errorflag = 1; + (*func)(arg,"%",1); + count++; + break; + } + /* Find out what flags are present */ + flag_leftjustify = flag_plussign = flag_blanksign = + flag_alternateform = flag_zeropad = flag_center = 0; + do{ + switch( c ){ + case '-': flag_leftjustify = 1; c = 0; break; + case '+': flag_plussign = 1; c = 0; break; + case ' ': flag_blanksign = 1; c = 0; break; + case '#': flag_alternateform = 1; c = 0; break; + case '0': flag_zeropad = 1; c = 0; break; + case '=': flag_center = 1; c = 0; break; + default: break; + } + }while( c==0 && (c=(*++fmt))!=0 ); + if( flag_center ) flag_leftjustify = 0; + /* Get the field width */ + width = 0; + if( c=='*' ){ + width = va_arg(ap,int); + if( width<0 ){ + flag_leftjustify = 1; + width = -width; + } + c = *++fmt; + }else{ + while( c>='0' && c<='9' ){ + width = width*10 + c - '0'; + c = *++fmt; + } + } + if( width > etBUFSIZE-10 ){ + width = etBUFSIZE-10; + } + /* Get the precision */ + if( c=='.' ){ + precision = 0; + c = *++fmt; + if( c=='*' ){ + precision = va_arg(ap,int); +#ifndef etCOMPATIBILITY + /* This is sensible, but SUN OS 4.1 doesn't do it. */ + if( precision<0 ) precision = -precision; +#endif + c = *++fmt; + }else{ + while( c>='0' && c<='9' ){ + precision = precision*10 + c - '0'; + c = *++fmt; + } + } + /* Limit the precision to prevent overflowing buf[] during conversion */ + if( precision>etBUFSIZE-40 ) precision = etBUFSIZE-40; + }else{ + precision = -1; + } + /* Get the conversion type modifier */ + if( c=='l' ){ + flag_long = 1; + c = *++fmt; + }else{ + flag_long = 0; + } + /* Fetch the info entry for the field */ + infop = 0; + for(idx=0; idxtype; + } + zExtra = 0; + + /* + ** At this point, variables are initialized as follows: + ** + ** flag_alternateform TRUE if a '#' is present. + ** flag_plussign TRUE if a '+' is present. + ** flag_leftjustify TRUE if a '-' is present or if the + ** field width was negative. + ** flag_zeropad TRUE if the width began with 0. + ** flag_long TRUE if the letter 'l' (ell) prefixed + ** the conversion character. + ** flag_blanksign TRUE if a ' ' is present. + ** width The specified field width. This is + ** always non-negative. Zero is the default. + ** precision The specified precision. The default + ** is -1. + ** xtype The class of the conversion. + ** infop Pointer to the appropriate info struct. + */ + switch( xtype ){ + case etORDINAL: + case etRADIX: + if( flag_long ) longvalue = va_arg(ap,long); + else longvalue = va_arg(ap,int); +#ifdef etCOMPATIBILITY + /* For the format %#x, the value zero is printed "0" not "0x0". + ** I think this is stupid. */ + if( longvalue==0 ) flag_alternateform = 0; +#else + /* More sensible: turn off the prefix for octal (to prevent "00"), + ** but leave the prefix for hex. */ + if( longvalue==0 && infop->base==8 ) flag_alternateform = 0; +#endif + if( infop->flag_signed ){ + if( *(long*)&longvalue<0 ){ + longvalue = -*(long*)&longvalue; + prefix = '-'; + }else if( flag_plussign ) prefix = '+'; + else if( flag_blanksign ) prefix = ' '; + else prefix = 0; + }else prefix = 0; + if( flag_zeropad && precision3 || (b>10 && b<14) ){ + bufpt[0] = 't'; + bufpt[1] = 'h'; + }else if( a==1 ){ + bufpt[0] = 's'; + bufpt[1] = 't'; + }else if( a==2 ){ + bufpt[0] = 'n'; + bufpt[1] = 'd'; + }else if( a==3 ){ + bufpt[0] = 'r'; + bufpt[1] = 'd'; + } + } + { + register char *cset; /* Use registers for speed */ + register int base; + cset = infop->charset; + base = infop->base; + do{ /* Convert to ascii */ + *(--bufpt) = cset[longvalue%base]; + longvalue = longvalue/base; + }while( longvalue>0 ); + } + length = &buf[etBUFSIZE]-bufpt; + for(idx=precision-length; idx>0; idx--){ + *(--bufpt) = '0'; /* Zero pad */ + } + if( prefix ) *(--bufpt) = prefix; /* Add sign */ + if( flag_alternateform && infop->prefix ){ /* Add "0" or "0x" */ + char *pre, x; + pre = infop->prefix; + if( *bufpt!=pre[0] ){ + for(pre=infop->prefix; (x=(*pre))!=0; pre++) *(--bufpt) = x; + } + } + length = &buf[etBUFSIZE]-bufpt; + break; + case etFLOAT: + case etEXP: + case etGENERIC: + realvalue = va_arg(ap,double); +#ifndef etNOFLOATINGPOINT + if( precision<0 ) precision = 6; /* Set default precision */ + if( precision>etBUFSIZE-10 ) precision = etBUFSIZE-10; + if( realvalue<0.0 ){ + realvalue = -realvalue; + prefix = '-'; + }else{ + if( flag_plussign ) prefix = '+'; + else if( flag_blanksign ) prefix = ' '; + else prefix = 0; + } + if( infop->type==etGENERIC && precision>0 ) precision--; + rounder = 0.0; +#ifdef COMPATIBILITY + /* Rounding works like BSD when the constant 0.4999 is used. Wierd! */ + for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1); +#else + /* It makes more sense to use 0.5 */ + for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1); +#endif + if( infop->type==etFLOAT ) realvalue += rounder; + /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */ + exp = 0; + if( realvalue>0.0 ){ + int k = 0; + while( realvalue>=1e8 && k++<100 ){ realvalue *= 1e-8; exp+=8; } + while( realvalue>=10.0 && k++<100 ){ realvalue *= 0.1; exp++; } + while( realvalue<1e-8 && k++<100 ){ realvalue *= 1e8; exp-=8; } + while( realvalue<1.0 && k++<100 ){ realvalue *= 10.0; exp--; } + if( k>=100 ){ + bufpt = "NaN"; + length = 3; + break; + } + } + bufpt = buf; + /* + ** If the field type is etGENERIC, then convert to either etEXP + ** or etFLOAT, as appropriate. + */ + flag_exp = xtype==etEXP; + if( xtype!=etFLOAT ){ + realvalue += rounder; + if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; } + } + if( xtype==etGENERIC ){ + flag_rtz = !flag_alternateform; + if( exp<-4 || exp>precision ){ + xtype = etEXP; + }else{ + precision = precision - exp; + xtype = etFLOAT; + } + }else{ + flag_rtz = 0; + } + /* + ** The "exp+precision" test causes output to be of type etEXP if + ** the precision is too large to fit in buf[]. + */ + nsd = 0; + if( xtype==etFLOAT && exp+precision0 || flag_alternateform); + if( prefix ) *(bufpt++) = prefix; /* Sign */ + if( exp<0 ) *(bufpt++) = '0'; /* Digits before "." */ + else for(; exp>=0; exp--) *(bufpt++) = et_getdigit(&realvalue,&nsd); + if( flag_dp ) *(bufpt++) = '.'; /* The decimal point */ + for(exp++; exp<0 && precision>0; precision--, exp++){ + *(bufpt++) = '0'; + } + while( (precision--)>0 ) *(bufpt++) = et_getdigit(&realvalue,&nsd); + *(bufpt--) = 0; /* Null terminate */ + if( flag_rtz && flag_dp ){ /* Remove trailing zeros and "." */ + while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0; + if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0; + } + bufpt++; /* point to next free slot */ + }else{ /* etEXP or etGENERIC */ + flag_dp = (precision>0 || flag_alternateform); + if( prefix ) *(bufpt++) = prefix; /* Sign */ + *(bufpt++) = et_getdigit(&realvalue,&nsd); /* First digit */ + if( flag_dp ) *(bufpt++) = '.'; /* Decimal point */ + while( (precision--)>0 ) *(bufpt++) = et_getdigit(&realvalue,&nsd); + bufpt--; /* point to last digit */ + if( flag_rtz && flag_dp ){ /* Remove tail zeros */ + while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0; + if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0; + } + bufpt++; /* point to next free slot */ + if( exp || flag_exp ){ + *(bufpt++) = infop->charset[0]; + if( exp<0 ){ *(bufpt++) = '-'; exp = -exp; } /* sign of exp */ + else { *(bufpt++) = '+'; } + if( exp>=100 ){ + *(bufpt++) = (exp/100)+'0'; /* 100's digit */ + exp %= 100; + } + *(bufpt++) = exp/10+'0'; /* 10's digit */ + *(bufpt++) = exp%10+'0'; /* 1's digit */ + } + } + /* The converted number is in buf[] and zero terminated. Output it. + ** Note that the number is in the usual order, not reversed as with + ** integer conversions. */ + length = bufpt-buf; + bufpt = buf; + + /* Special case: Add leading zeros if the flag_zeropad flag is + ** set and we are not left justified */ + if( flag_zeropad && !flag_leftjustify && length < width){ + int i; + int nPad = width - length; + for(i=width; i>=nPad; i--){ + bufpt[i] = bufpt[i-nPad]; + } + i = prefix!=0; + while( nPad-- ) bufpt[i++] = '0'; + length = width; + } +#endif + break; + case etSIZE: + *(va_arg(ap,int*)) = count; + length = width = 0; + break; + case etPERCENT: + buf[0] = '%'; + bufpt = buf; + length = 1; + break; + case etCHARLIT: + case etCHARX: + c = buf[0] = (xtype==etCHARX ? va_arg(ap,int) : *++fmt); + if( precision>=0 ){ + for(idx=1; idx=0 && precisionetBUFSIZE ){ + bufpt = zExtra = sqliteMalloc( n ); + if( bufpt==0 ) return -1; + }else{ + bufpt = buf; + } + j = 0; + if( !isnull && xtype==etSQLESCAPE2 ) bufpt[j++] = '\''; + for(i=0; (c=arg[i])!=0; i++){ + bufpt[j++] = c; + if( c=='\'' ) bufpt[j++] = c; + } + if( !isnull && xtype==etSQLESCAPE2 ) bufpt[j++] = '\''; + bufpt[j] = 0; + length = j; + if( precision>=0 && precision0 ){ + if( flag_center ){ + nspace = nspace/2; + width -= nspace; + flag_leftjustify = 1; + } + count += nspace; + while( nspace>=etSPACESIZE ){ + (*func)(arg,spaces,etSPACESIZE); + nspace -= etSPACESIZE; + } + if( nspace>0 ) (*func)(arg,spaces,nspace); + } + } + if( length>0 ){ + (*func)(arg,bufpt,length); + count += length; + } + if( flag_leftjustify ){ + register int nspace; + nspace = width-length; + if( nspace>0 ){ + count += nspace; + while( nspace>=etSPACESIZE ){ + (*func)(arg,spaces,etSPACESIZE); + nspace -= etSPACESIZE; + } + if( nspace>0 ) (*func)(arg,spaces,nspace); + } + } + if( zExtra ){ + if( xtype==etDYNSTRING ){ + free(zExtra); + }else{ + sqliteFree(zExtra); + } + } + }/* End for loop over the format string */ + return errorflag ? -1 : count; +} /* End of function */ + + +/* This structure is used to store state information about the +** write to memory that is currently in progress. +*/ +struct sgMprintf { + char *zBase; /* A base allocation */ + char *zText; /* The string collected so far */ + int nChar; /* Length of the string so far */ + int nAlloc; /* Amount of space allocated in zText */ +}; + +/* +** This function implements the callback from vxprintf. +** +** This routine add nNewChar characters of text in zNewText to +** the sgMprintf structure pointed to by "arg". +*/ +static void mout(void *arg, char *zNewText, int nNewChar){ + struct sgMprintf *pM = (struct sgMprintf*)arg; + if( pM->nChar + nNewChar + 1 > pM->nAlloc ){ + pM->nAlloc = pM->nChar + nNewChar*2 + 1; + if( pM->zText==pM->zBase ){ + pM->zText = sqliteMalloc(pM->nAlloc); + if( pM->zText && pM->nChar ) memcpy(pM->zText,pM->zBase,pM->nChar); + }else{ + char *z = sqliteRealloc(pM->zText, pM->nAlloc); + if( z==0 ){ + sqliteFree(pM->zText); + pM->nChar = 0; + pM->nAlloc = 0; + } + pM->zText = z; + } + } + if( pM->zText ){ + memcpy(&pM->zText[pM->nChar], zNewText, nNewChar); + pM->nChar += nNewChar; + pM->zText[pM->nChar] = 0; + } +} + +/* +** sqlite_mprintf() works like printf(), but allocations memory to hold the +** resulting string and returns a pointer to the allocated memory. Use +** sqliteFree() to release the memory allocated. +*/ +char *sqliteMPrintf(const char *zFormat, ...){ + va_list ap; + struct sgMprintf sMprintf; + char zBuf[200]; + + sMprintf.nChar = 0; + sMprintf.nAlloc = sizeof(zBuf); + sMprintf.zText = zBuf; + sMprintf.zBase = zBuf; + va_start(ap,zFormat); + vxprintf(mout,&sMprintf,zFormat,ap); + va_end(ap); + sMprintf.zText[sMprintf.nChar] = 0; + return sqliteRealloc(sMprintf.zText, sMprintf.nChar+1); +} + +/* +** sqlite_mprintf() works like printf(), but allocations memory to hold the +** resulting string and returns a pointer to the allocated memory. Use +** sqliteFree() to release the memory allocated. +*/ +char *sqlite_mprintf(const char *zFormat, ...){ + va_list ap; + struct sgMprintf sMprintf; + char *zNew; + char zBuf[200]; + + sMprintf.nChar = 0; + sMprintf.nAlloc = sizeof(zBuf); + sMprintf.zText = zBuf; + sMprintf.zBase = zBuf; + va_start(ap,zFormat); + vxprintf(mout,&sMprintf,zFormat,ap); + va_end(ap); + sMprintf.zText[sMprintf.nChar] = 0; + zNew = malloc( sMprintf.nChar+1 ); + if( zNew ) strcpy(zNew,sMprintf.zText); + if( sMprintf.zText!=sMprintf.zBase ){ + sqliteFree(sMprintf.zText); + } + return zNew; +} + +/* This is the varargs version of sqlite_mprintf. +*/ +char *sqlite_vmprintf(const char *zFormat, va_list ap){ + struct sgMprintf sMprintf; + char *zNew; + char zBuf[200]; + sMprintf.nChar = 0; + sMprintf.zText = zBuf; + sMprintf.nAlloc = sizeof(zBuf); + sMprintf.zBase = zBuf; + vxprintf(mout,&sMprintf,zFormat,ap); + sMprintf.zText[sMprintf.nChar] = 0; + zNew = malloc( sMprintf.nChar+1 ); + if( zNew ) strcpy(zNew,sMprintf.zText); + if( sMprintf.zText!=sMprintf.zBase ){ + sqliteFree(sMprintf.zText); + } + return zNew; +} + +/* +** The following four routines implement the varargs versions of the +** sqlite_exec() and sqlite_get_table() interfaces. See the sqlite.h +** header files for a more detailed description of how these interfaces +** work. +** +** These routines are all just simple wrappers. +*/ +int sqlite_exec_printf( + sqlite *db, /* An open database */ + const char *sqlFormat, /* printf-style format string for the SQL */ + sqlite_callback xCallback, /* Callback function */ + void *pArg, /* 1st argument to callback function */ + char **errmsg, /* Error msg written here */ + ... /* Arguments to the format string. */ +){ + va_list ap; + int rc; + + va_start(ap, errmsg); + rc = sqlite_exec_vprintf(db, sqlFormat, xCallback, pArg, errmsg, ap); + va_end(ap); + return rc; +} +int sqlite_exec_vprintf( + sqlite *db, /* An open database */ + const char *sqlFormat, /* printf-style format string for the SQL */ + sqlite_callback xCallback, /* Callback function */ + void *pArg, /* 1st argument to callback function */ + char **errmsg, /* Error msg written here */ + va_list ap /* Arguments to the format string. */ +){ + char *zSql; + int rc; + + zSql = sqlite_vmprintf(sqlFormat, ap); + rc = sqlite_exec(db, zSql, xCallback, pArg, errmsg); + free(zSql); + return rc; +} +int sqlite_get_table_printf( + sqlite *db, /* An open database */ + const char *sqlFormat, /* printf-style format string for the SQL */ + char ***resultp, /* Result written to a char *[] that this points to */ + int *nrow, /* Number of result rows written here */ + int *ncol, /* Number of result columns written here */ + char **errmsg, /* Error msg written here */ + ... /* Arguments to the format string */ +){ + va_list ap; + int rc; + + va_start(ap, errmsg); + rc = sqlite_get_table_vprintf(db, sqlFormat, resultp, nrow, ncol, errmsg, ap); + va_end(ap); + return rc; +} +int sqlite_get_table_vprintf( + sqlite *db, /* An open database */ + const char *sqlFormat, /* printf-style format string for the SQL */ + char ***resultp, /* Result written to a char *[] that this points to */ + int *nrow, /* Number of result rows written here */ + int *ncolumn, /* Number of result columns written here */ + char **errmsg, /* Error msg written here */ + va_list ap /* Arguments to the format string */ +){ + char *zSql; + int rc; + + zSql = sqlite_vmprintf(sqlFormat, ap); + rc = sqlite_get_table(db, zSql, resultp, nrow, ncolumn, errmsg); + free(zSql); + return rc; +} diff --git a/sqlitebrowser/sqlitebrowser/sqlite_source/random.c b/sqlitebrowser/sqlitebrowser/sqlite_source/random.c new file mode 100755 index 00000000..3a1f6dad --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/sqlite_source/random.c @@ -0,0 +1,113 @@ +/* +** 2001 September 15 +** +** 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 code to implement a pseudo-random number +** generator (PRNG) for SQLite. +** +** Random numbers are used by some of the database backends in order +** to generate random integer keys for tables or random filenames. +** +** $Id: random.c,v 1.1.1.1 2003-08-21 02:24:18 tabuleiro Exp $ +*/ +#include "sqliteInt.h" +#include "os.h" + + +/* +** Get a single 8-bit random value from the RC4 PRNG. The Mutex +** must be held while executing this routine. +** +** Why not just use a library random generator like lrand48() for this? +** Because the OP_NewRecno opcode in the VDBE depends on having a very +** good source of random numbers. The lrand48() library function may +** well be good enough. But maybe not. Or maybe lrand48() has some +** subtle problems on some systems that could cause problems. It is hard +** to know. To minimize the risk of problems due to bad lrand48() +** implementations, SQLite uses this random number generator based +** on RC4, which we know works very well. +*/ +static int randomByte(){ + int t; + + /* All threads share a single random number generator. + ** This structure is the current state of the generator. + */ + static struct { + int isInit; /* True if initialized */ + int i, j; /* State variables */ + int s[256]; /* State variables */ + } prng; + + /* Initialize the state of the random number generator once, + ** the first time this routine is called. The seed value does + ** not need to contain a lot of randomness since we are not + ** trying to do secure encryption or anything like that... + ** + ** Nothing in this file or anywhere else in SQLite does any kind of + ** encryption. The RC4 algorithm is being used as a PRNG (pseudo-random + ** number generator) not as an encryption device. + */ + if( !prng.isInit ){ + int i; + char k[256]; + prng.j = 0; + prng.i = 0; + sqliteOsRandomSeed(k); + for(i=0; i<256; i++){ + prng.s[i] = i; + } + for(i=0; i<256; i++){ + int t; + prng.j = (prng.j + prng.s[i] + k[i]) & 0xff; + t = prng.s[prng.j]; + prng.s[prng.j] = prng.s[i]; + prng.s[i] = t; + } + prng.isInit = 1; + } + + /* Generate and return single random byte + */ + prng.i = (prng.i + 1) & 0xff; + prng.j = (prng.j + prng.s[prng.i]) & 0xff; + t = prng.s[prng.i]; + prng.s[prng.i] = prng.s[prng.j]; + prng.s[prng.j] = t; + t = prng.s[prng.i] + prng.s[prng.j]; + return prng.s[t & 0xff]; +} + +/* +** Return an random 8-bit integer. +*/ +int sqliteRandomByte(){ + int r; + sqliteOsEnterMutex(); + r = randomByte(); + sqliteOsLeaveMutex(); + return r; +} + +/* +** Return a random 32-bit integer. The integer is generated by making +** 4 calls to sqliteRandomByte(). +*/ +int sqliteRandomInteger(){ + int r; + int i; + sqliteOsEnterMutex(); + r = randomByte(); + for(i=1; i<4; i++){ + r = (r<<8) + randomByte(); + } + sqliteOsLeaveMutex(); + return r; +} diff --git a/sqlitebrowser/sqlitebrowser/sqlite_source/select.c b/sqlitebrowser/sqlitebrowser/sqlite_source/select.c new file mode 100755 index 00000000..fd397914 --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/sqlite_source/select.c @@ -0,0 +1,2450 @@ +/* +** 2001 September 15 +** +** 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 C code routines that are called by the parser +** to handle SELECT statements in SQLite. +** +** $Id: select.c,v 1.1.1.1 2003-08-21 02:24:19 tabuleiro Exp $ +*/ +#include "sqliteInt.h" + + +/* +** Allocate a new Select structure and return a pointer to that +** structure. +*/ +Select *sqliteSelectNew( + ExprList *pEList, /* which columns to include in the result */ + SrcList *pSrc, /* the FROM clause -- which tables to scan */ + Expr *pWhere, /* the WHERE clause */ + ExprList *pGroupBy, /* the GROUP BY clause */ + Expr *pHaving, /* the HAVING clause */ + ExprList *pOrderBy, /* the ORDER BY clause */ + int isDistinct, /* true if the DISTINCT keyword is present */ + int nLimit, /* LIMIT value. -1 means not used */ + int nOffset /* OFFSET value. 0 means no offset */ +){ + Select *pNew; + pNew = sqliteMalloc( sizeof(*pNew) ); + if( pNew==0 ){ + sqliteExprListDelete(pEList); + sqliteSrcListDelete(pSrc); + sqliteExprDelete(pWhere); + sqliteExprListDelete(pGroupBy); + sqliteExprDelete(pHaving); + sqliteExprListDelete(pOrderBy); + }else{ + 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->nLimit = nLimit; + pNew->nOffset = nOffset; + pNew->iLimit = -1; + pNew->iOffset = -1; + } + return pNew; +} + +/* +** 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: +** +** JT_INNER +** JT_OUTER +** JT_NATURAL +** JT_LEFT +** JT_RIGHT +** +** A full outer join is the combination of JT_LEFT and JT_RIGHT. +** +** If an illegal or unsupported join type is seen, then still return +** a join type, but put an error in the pParse structure. +*/ +int sqliteJoinType(Parse *pParse, Token *pA, Token *pB, Token *pC){ + int jointype = 0; + Token *apAll[3]; + Token *p; + static struct { + const char *zKeyword; + int nChar; + int code; + } keywords[] = { + { "natural", 7, JT_NATURAL }, + { "left", 4, JT_LEFT|JT_OUTER }, + { "right", 5, JT_RIGHT|JT_OUTER }, + { "full", 4, JT_LEFT|JT_RIGHT|JT_OUTER }, + { "outer", 5, JT_OUTER }, + { "inner", 5, JT_INNER }, + { "cross", 5, JT_INNER }, + }; + int i, j; + apAll[0] = pA; + apAll[1] = pB; + apAll[2] = pC; + for(i=0; i<3 && apAll[i]; i++){ + p = apAll[i]; + for(j=0; jn==keywords[j].nChar + && sqliteStrNICmp(p->z, keywords[j].zKeyword, p->n)==0 ){ + jointype |= keywords[j].code; + break; + } + } + if( j>=sizeof(keywords)/sizeof(keywords[0]) ){ + jointype |= JT_ERROR; + break; + } + } + if( + (jointype & (JT_INNER|JT_OUTER))==(JT_INNER|JT_OUTER) || + (jointype & JT_ERROR)!=0 + ){ + static Token dummy = { 0, 0 }; + char *zSp1 = " ", *zSp2 = " "; + if( pB==0 ){ pB = &dummy; zSp1 = 0; } + if( pC==0 ){ pC = &dummy; zSp2 = 0; } + sqliteSetNString(&pParse->zErrMsg, "unknown or unsupported join type: ", 0, + pA->z, pA->n, zSp1, 1, pB->z, pB->n, zSp2, 1, pC->z, pC->n, 0); + pParse->nErr++; + jointype = JT_INNER; + }else if( jointype & JT_RIGHT ){ + sqliteErrorMsg(pParse, + "RIGHT and FULL OUTER JOINs are not currently supported"); + jointype = JT_INNER; + } + return jointype; +} + +/* +** Return the index of a column in a table. Return -1 if the column +** is not contained in the table. +*/ +static int columnIndex(Table *pTab, const char *zCol){ + int i; + for(i=0; inCol; i++){ + if( sqliteStrICmp(pTab->aCol[i].zName, zCol)==0 ) return i; + } + return -1; +} + +/* +** Add a term to the WHERE expression in *ppExpr that requires the +** zCol column to be equal in the two tables pTab1 and pTab2. +*/ +static void addWhereTerm( + const char *zCol, /* Name of the column */ + const Table *pTab1, /* First table */ + const Table *pTab2, /* Second table */ + Expr **ppExpr /* Add the equality term to this expression */ +){ + Token dummy; + Expr *pE1a, *pE1b, *pE1c; + Expr *pE2a, *pE2b, *pE2c; + Expr *pE; + + dummy.z = zCol; + dummy.n = strlen(zCol); + dummy.dyn = 0; + pE1a = sqliteExpr(TK_ID, 0, 0, &dummy); + pE2a = sqliteExpr(TK_ID, 0, 0, &dummy); + dummy.z = pTab1->zName; + dummy.n = strlen(dummy.z); + pE1b = sqliteExpr(TK_ID, 0, 0, &dummy); + dummy.z = pTab2->zName; + dummy.n = strlen(dummy.z); + pE2b = sqliteExpr(TK_ID, 0, 0, &dummy); + pE1c = sqliteExpr(TK_DOT, pE1b, pE1a, 0); + pE2c = sqliteExpr(TK_DOT, pE2b, pE2a, 0); + pE = sqliteExpr(TK_EQ, pE1c, pE2c, 0); + ExprSetProperty(pE, EP_FromJoin); + if( *ppExpr ){ + *ppExpr = sqliteExpr(TK_AND, *ppExpr, pE, 0); + }else{ + *ppExpr = pE; + } +} + +/* +** Set the EP_FromJoin property on all terms of the given expression. +** +** The EP_FromJoin property is used on terms of an expression to tell +** the LEFT OUTER JOIN processing logic that this term is part of the +** join restriction specified in the ON or USING clause and not a part +** of the more general WHERE clause. These terms are moved over to the +** WHERE clause during join processing but we need to remember that they +** originated in the ON or USING clause. +*/ +static void setJoinExpr(Expr *p){ + while( p ){ + ExprSetProperty(p, EP_FromJoin); + setJoinExpr(p->pLeft); + p = p->pRight; + } +} + +/* +** This routine processes the join information for a SELECT statement. +** ON and USING clauses are converted into extra terms of the WHERE clause. +** NATURAL joins also create extra WHERE clause terms. +** +** This routine returns the number of errors encountered. +*/ +static int sqliteProcessJoin(Parse *pParse, Select *p){ + SrcList *pSrc; + int i, j; + pSrc = p->pSrc; + for(i=0; inSrc-1; i++){ + struct SrcList_item *pTerm = &pSrc->a[i]; + struct SrcList_item *pOther = &pSrc->a[i+1]; + + if( pTerm->pTab==0 || pOther->pTab==0 ) continue; + + /* When the NATURAL keyword is present, add WHERE clause terms for + ** every column that the two tables have in common. + */ + if( pTerm->jointype & JT_NATURAL ){ + Table *pTab; + if( pTerm->pOn || pTerm->pUsing ){ + sqliteErrorMsg(pParse, "a NATURAL join may not have " + "an ON or USING clause", 0); + return 1; + } + pTab = pTerm->pTab; + for(j=0; jnCol; j++){ + if( columnIndex(pOther->pTab, pTab->aCol[j].zName)>=0 ){ + addWhereTerm(pTab->aCol[j].zName, pTab, pOther->pTab, &p->pWhere); + } + } + } + + /* Disallow both ON and USING clauses in the same join + */ + if( pTerm->pOn && pTerm->pUsing ){ + sqliteErrorMsg(pParse, "cannot have both ON and USING " + "clauses in the same join"); + return 1; + } + + /* Add the ON clause to the end of the WHERE clause, connected by + ** and AND operator. + */ + if( pTerm->pOn ){ + setJoinExpr(pTerm->pOn); + if( p->pWhere==0 ){ + p->pWhere = pTerm->pOn; + }else{ + p->pWhere = sqliteExpr(TK_AND, p->pWhere, pTerm->pOn, 0); + } + pTerm->pOn = 0; + } + + /* Create extra terms on the WHERE clause for each column named + ** in the USING clause. Example: If the two tables to be joined are + ** A and B and the USING clause names X, Y, and Z, then add this + ** to the WHERE clause: A.X=B.X AND A.Y=B.Y AND A.Z=B.Z + ** Report an error if any column mentioned in the USING clause is + ** not contained in both tables to be joined. + */ + if( pTerm->pUsing ){ + IdList *pList; + int j; + assert( inSrc-1 ); + pList = pTerm->pUsing; + for(j=0; jnId; j++){ + if( columnIndex(pTerm->pTab, pList->a[j].zName)<0 || + columnIndex(pOther->pTab, pList->a[j].zName)<0 ){ + sqliteErrorMsg(pParse, "cannot join using column %s - column " + "not present in both tables", pList->a[j].zName); + return 1; + } + addWhereTerm(pList->a[j].zName, pTerm->pTab, pOther->pTab, &p->pWhere); + } + } + } + return 0; +} + +/* +** This routine implements a minimal Oracle8 join syntax immulation. +** The precise oracle8 syntax is not implemented - it is easy enough +** to get this routine confused. But this routine does make it possible +** to write a single SQL statement that does a left outer join in both +** oracle8 and in SQLite. +** +** This routine looks for TK_COLUMN expression nodes that are marked +** with the EP_Oracle8Join property. Such nodes are generated by a +** column name (either "column" or "table.column") that is followed by +** the special "(+)" operator. If the table of the column marked with +** the (+) operator is the second are subsequent table in a join, then +** that table becomes the left table in a LEFT OUTER JOIN. The expression +** that uses that table becomes part of the ON clause for the join. +** +** It is important to enphasize that this is not exactly how oracle8 +** works. But it is close enough so that one can construct queries that +** will work correctly for both SQLite and Oracle8. +*/ +static int sqliteOracle8JoinFixup( + SrcList *pSrc, /* List of tables being joined */ + Expr *pWhere /* The WHERE clause of the SELECT statement */ +){ + int rc = 0; + if( ExprHasProperty(pWhere, EP_Oracle8Join) && pWhere->op==TK_COLUMN ){ + int idx; + for(idx=0; idxnSrc; idx++){ + if( pSrc->a[idx].iCursor==pWhere->iTable ) break; + } + assert( idx>=0 && idxnSrc ); + if( idx>0 ){ + pSrc->a[idx-1].jointype &= ~JT_INNER; + pSrc->a[idx-1].jointype |= JT_OUTER|JT_LEFT; + return 1; + } + } + if( pWhere->pRight ){ + rc = sqliteOracle8JoinFixup(pSrc, pWhere->pRight); + } + if( pWhere->pLeft ){ + rc |= sqliteOracle8JoinFixup(pSrc, pWhere->pLeft); + } + if( pWhere->pList ){ + int i; + ExprList *pList = pWhere->pList; + for(i=0; inExpr && rc==0; i++){ + rc |= sqliteOracle8JoinFixup(pSrc, pList->a[i].pExpr); + } + } + if( rc==1 && (pWhere->op==TK_AND || pWhere->op==TK_EQ) ){ + setJoinExpr(pWhere); + rc = 0; + } + return rc; +} + +/* +** Delete the given Select structure and all of its substructures. +*/ +void sqliteSelectDelete(Select *p){ + if( p==0 ) return; + sqliteExprListDelete(p->pEList); + sqliteSrcListDelete(p->pSrc); + sqliteExprDelete(p->pWhere); + sqliteExprListDelete(p->pGroupBy); + sqliteExprDelete(p->pHaving); + sqliteExprListDelete(p->pOrderBy); + sqliteSelectDelete(p->pPrior); + sqliteFree(p->zSelect); + sqliteFree(p); +} + +/* +** Delete the aggregate information from the parse structure. +*/ +static void sqliteAggregateInfoReset(Parse *pParse){ + sqliteFree(pParse->aAgg); + pParse->aAgg = 0; + pParse->nAgg = 0; + pParse->useAgg = 0; +} + +/* +** 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){ + char *zSortOrder; + int i; + zSortOrder = sqliteMalloc( pOrderBy->nExpr + 1 ); + if( zSortOrder==0 ) return; + for(i=0; inExpr; i++){ + int order = pOrderBy->a[i].sortOrder; + int type; + int c; + if( (order & SQLITE_SO_TYPEMASK)==SQLITE_SO_TEXT ){ + type = SQLITE_SO_TEXT; + }else if( (order & SQLITE_SO_TYPEMASK)==SQLITE_SO_NUM ){ + type = SQLITE_SO_NUM; + }else if( pParse->db->file_format>=4 ){ + type = sqliteExprType(pOrderBy->a[i].pExpr); + }else{ + type = SQLITE_SO_NUM; + } + if( (order & SQLITE_SO_DIRMASK)==SQLITE_SO_ASC ){ + c = type==SQLITE_SO_TEXT ? 'A' : '+'; + }else{ + c = type==SQLITE_SO_TEXT ? 'D' : '-'; + } + zSortOrder[i] = c; + sqliteExprCode(pParse, pOrderBy->a[i].pExpr); + } + zSortOrder[pOrderBy->nExpr] = 0; + sqliteVdbeAddOp(v, OP_SortMakeKey, pOrderBy->nExpr, 0); + sqliteVdbeChangeP3(v, -1, zSortOrder, strlen(zSortOrder)); + sqliteFree(zSortOrder); + sqliteVdbeAddOp(v, OP_SortPut, 0, 0); +} + +/* +** This routine adds a P3 argument to the last VDBE opcode that was +** inserted. The P3 argument added is a string suitable for the +** OP_MakeKey or OP_MakeIdxKey opcodes. The string consists of +** characters 't' or 'n' depending on whether or not the various +** fields of the key to be generated should be treated as numeric +** or as text. See the OP_MakeKey and OP_MakeIdxKey opcode +** documentation for additional information about the P3 string. +** See also the sqliteAddIdxKeyType() routine. +*/ +void sqliteAddKeyType(Vdbe *v, ExprList *pEList){ + int nColumn = pEList->nExpr; + char *zType = sqliteMalloc( nColumn+1 ); + int i; + if( zType==0 ) return; + for(i=0; ia[i].pExpr)==SQLITE_SO_NUM ? 'n' : 't'; + } + zType[i] = 0; + sqliteVdbeChangeP3(v, -1, zType, nColumn); + sqliteFree(zType); +} + +/* +** This routine generates the code for the inside of the inner loop +** of a SELECT. +** +** If srcTab and nColumn are both zero, then the pEList expressions +** are evaluated in order to get the data for this row. If nColumn>0 +** then data is pulled from srcTab and pEList is used only to get the +** datatypes for each column. +*/ +static int selectInnerLoop( + Parse *pParse, /* The parser context */ + Select *p, /* The complete select statement being coded */ + ExprList *pEList, /* List of values being extracted */ + int srcTab, /* Pull data from this table */ + int nColumn, /* Number of columns in the source table */ + ExprList *pOrderBy, /* If not NULL, sort results using this key */ + int distinct, /* If >=0, make sure results are distinct */ + int eDest, /* How to dispose of the results */ + int iParm, /* An argument to the disposal method */ + int iContinue, /* Jump here to continue with next row */ + int iBreak /* Jump here to break out of the inner loop */ +){ + Vdbe *v = pParse->pVdbe; + int i; + + if( v==0 ) return 0; + assert( pEList!=0 ); + + /* If there was a LIMIT clause on the SELECT statement, then do the check + ** to see if this row should be output. + */ + if( pOrderBy==0 ){ + if( p->iOffset>=0 ){ + int addr = sqliteVdbeCurrentAddr(v); + sqliteVdbeAddOp(v, OP_MemIncr, p->iOffset, addr+2); + sqliteVdbeAddOp(v, OP_Goto, 0, iContinue); + } + if( p->iLimit>=0 ){ + sqliteVdbeAddOp(v, OP_MemIncr, p->iLimit, iBreak); + } + } + + /* Pull the requested columns. + */ + if( nColumn>0 ){ + for(i=0; inExpr; + for(i=0; inExpr; i++){ + sqliteExprCode(pParse, pEList->a[i].pExpr); + } + } + + /* If the DISTINCT keyword was present on the SELECT statement + ** and this row has been seen before, then do not make this row + ** part of the result. + */ + if( distinct>=0 && pEList && pEList->nExpr>0 ){ +#if NULL_ALWAYS_DISTINCT + sqliteVdbeAddOp(v, OP_IsNull, -pEList->nExpr, sqliteVdbeCurrentAddr(v)+7); +#endif + sqliteVdbeAddOp(v, OP_MakeKey, pEList->nExpr, 1); + if( pParse->db->file_format>=4 ) sqliteAddKeyType(v, pEList); + sqliteVdbeAddOp(v, OP_Distinct, distinct, sqliteVdbeCurrentAddr(v)+3); + sqliteVdbeAddOp(v, OP_Pop, pEList->nExpr+1, 0); + sqliteVdbeAddOp(v, OP_Goto, 0, iContinue); + sqliteVdbeAddOp(v, OP_String, 0, 0); + sqliteVdbeAddOp(v, OP_PutStrKey, distinct, 0); + } + + switch( eDest ){ + /* In this mode, write each query result to the key of the temporary + ** table iParm. + */ + case SRT_Union: { + sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, NULL_ALWAYS_DISTINCT); + sqliteVdbeAddOp(v, OP_String, 0, 0); + sqliteVdbeAddOp(v, OP_PutStrKey, iParm, 0); + break; + } + + /* Store the result as data using a unique key. + */ + case SRT_Table: + case SRT_TempTable: { + sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, 0); + if( pOrderBy ){ + pushOntoSorter(pParse, v, pOrderBy); + }else{ + sqliteVdbeAddOp(v, OP_NewRecno, iParm, 0); + sqliteVdbeAddOp(v, OP_Pull, 1, 0); + sqliteVdbeAddOp(v, OP_PutIntKey, iParm, 0); + } + break; + } + + /* Construct a record from the query result, but instead of + ** saving that record, use it as a key to delete elements from + ** the temporary table iParm. + */ + case SRT_Except: { + int addr; + addr = sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, NULL_ALWAYS_DISTINCT); + sqliteVdbeAddOp(v, OP_NotFound, iParm, addr+3); + sqliteVdbeAddOp(v, OP_Delete, iParm, 0); + break; + } + + /* If we are creating a set for an "expr IN (SELECT ...)" construct, + ** then there should be a single item on the stack. Write this + ** item into the set table with bogus data. + */ + case SRT_Set: { + int lbl = sqliteVdbeMakeLabel(v); + assert( nColumn==1 ); + sqliteVdbeAddOp(v, OP_IsNull, -1, lbl); + if( pOrderBy ){ + pushOntoSorter(pParse, v, pOrderBy); + }else{ + sqliteVdbeAddOp(v, OP_String, 0, 0); + sqliteVdbeAddOp(v, OP_PutStrKey, iParm, 0); + } + sqliteVdbeResolveLabel(v, lbl); + 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_Mem: { + assert( nColumn==1 ); + if( pOrderBy ){ + pushOntoSorter(pParse, v, pOrderBy); + }else{ + sqliteVdbeAddOp(v, OP_MemStore, iParm, 1); + sqliteVdbeAddOp(v, OP_Goto, 0, iBreak); + } + break; + } + + /* Send the data to the callback function. + */ + case SRT_Callback: + case SRT_Sorter: { + if( pOrderBy ){ + sqliteVdbeAddOp(v, OP_SortMakeRec, nColumn, 0); + pushOntoSorter(pParse, v, pOrderBy); + }else{ + assert( eDest==SRT_Callback ); + sqliteVdbeAddOp(v, OP_Callback, nColumn, 0); + } + break; + } + + /* Invoke a subroutine to handle the results. The subroutine itself + ** is responsible for popping the results off of the stack. + */ + case SRT_Subroutine: { + if( pOrderBy ){ + sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, 0); + pushOntoSorter(pParse, v, pOrderBy); + }else{ + sqliteVdbeAddOp(v, OP_Gosub, 0, iParm); + } + break; + } + + /* Discard the results. This is used for SELECT statements inside + ** the body of a TRIGGER. The purpose of such selects is to call + ** user-defined functions that have side effects. We do not care + ** about the actual results of the select. + */ + default: { + assert( eDest==SRT_Discard ); + sqliteVdbeAddOp(v, OP_Pop, nColumn, 0); + break; + } + } + return 0; +} + +/* +** If the inner loop was generated using a non-null pOrderBy argument, +** then the results were placed in a sorter. After the loop is terminated +** we need to run the sorter and output the results. The following +** routine generates the code needed to do that. +*/ +static void generateSortTail( + Select *p, /* The SELECT statement */ + Vdbe *v, /* Generate code into this VDBE */ + int nColumn, /* Number of columns of data */ + int eDest, /* Write the sorted results here */ + int iParm /* Optional parameter associated with eDest */ +){ + int end = sqliteVdbeMakeLabel(v); + int addr; + if( eDest==SRT_Sorter ) return; + sqliteVdbeAddOp(v, OP_Sort, 0, 0); + addr = sqliteVdbeAddOp(v, OP_SortNext, 0, end); + if( p->iOffset>=0 ){ + sqliteVdbeAddOp(v, OP_MemIncr, p->iOffset, addr+4); + sqliteVdbeAddOp(v, OP_Pop, 1, 0); + sqliteVdbeAddOp(v, OP_Goto, 0, addr); + } + if( p->iLimit>=0 ){ + sqliteVdbeAddOp(v, OP_MemIncr, p->iLimit, end); + } + switch( eDest ){ + case SRT_Callback: { + sqliteVdbeAddOp(v, OP_SortCallback, nColumn, 0); + break; + } + case SRT_Table: + case SRT_TempTable: { + sqliteVdbeAddOp(v, OP_NewRecno, iParm, 0); + sqliteVdbeAddOp(v, OP_Pull, 1, 0); + sqliteVdbeAddOp(v, OP_PutIntKey, iParm, 0); + break; + } + case SRT_Set: { + assert( nColumn==1 ); + sqliteVdbeAddOp(v, OP_IsNull, -1, sqliteVdbeCurrentAddr(v)+3); + sqliteVdbeAddOp(v, OP_String, 0, 0); + sqliteVdbeAddOp(v, OP_PutStrKey, iParm, 0); + break; + } + case SRT_Mem: { + assert( nColumn==1 ); + sqliteVdbeAddOp(v, OP_MemStore, iParm, 1); + sqliteVdbeAddOp(v, OP_Goto, 0, end); + break; + } + case SRT_Subroutine: { + int i; + for(i=0; ipVdbe; + int i, j; + if( pParse->useCallback && (pParse->db->flags & SQLITE_ReportTypes)==0 ){ + return; + } + for(i=0; inExpr; i++){ + Expr *p = pEList->a[i].pExpr; + char *zType = 0; + if( p==0 ) continue; + if( p->op==TK_COLUMN && pTabList ){ + Table *pTab; + int iCol = p->iColumn; + for(j=0; jnSrc && pTabList->a[j].iCursor!=p->iTable; j++){} + assert( jnSrc ); + pTab = pTabList->a[j].pTab; + if( iCol<0 ) iCol = pTab->iPKey; + assert( iCol==-1 || (iCol>=0 && iColnCol) ); + if( iCol<0 ){ + zType = "INTEGER"; + }else{ + zType = pTab->aCol[iCol].zType; + } + }else{ + if( sqliteExprType(p)==SQLITE_SO_TEXT ){ + zType = "TEXT"; + }else{ + zType = "NUMERIC"; + } + } + sqliteVdbeAddOp(v, OP_ColumnName, i + pEList->nExpr, 0); + sqliteVdbeChangeP3(v, -1, zType, P3_STATIC); + } +} + +/* +** Generate code that will tell the VDBE the names of columns +** in the result set. This information is used to provide the +** azCol[] vaolues in the callback. +*/ +static void generateColumnNames( + Parse *pParse, /* Parser context */ + SrcList *pTabList, /* List of tables */ + ExprList *pEList /* Expressions defining the result set */ +){ + Vdbe *v = pParse->pVdbe; + int i, j; + if( pParse->colNamesSet || v==0 || sqlite_malloc_failed ) return; + pParse->colNamesSet = 1; + for(i=0; inExpr; i++){ + Expr *p; + char *zType = 0; + int showFullNames; + p = pEList->a[i].pExpr; + if( p==0 ) continue; + if( pEList->a[i].zName ){ + char *zName = pEList->a[i].zName; + sqliteVdbeAddOp(v, OP_ColumnName, i, 0); + sqliteVdbeChangeP3(v, -1, zName, strlen(zName)); + continue; + } + showFullNames = (pParse->db->flags & SQLITE_FullColNames)!=0; + if( p->op==TK_COLUMN && pTabList ){ + Table *pTab; + char *zCol; + int iCol = p->iColumn; + for(j=0; jnSrc && pTabList->a[j].iCursor!=p->iTable; j++){} + assert( jnSrc ); + pTab = pTabList->a[j].pTab; + if( iCol<0 ) iCol = pTab->iPKey; + assert( iCol==-1 || (iCol>=0 && iColnCol) ); + if( iCol<0 ){ + zCol = "_ROWID_"; + zType = "INTEGER"; + }else{ + zCol = pTab->aCol[iCol].zName; + zType = pTab->aCol[iCol].zType; + } + if( p->span.z && p->span.z[0] && !showFullNames ){ + int addr = sqliteVdbeAddOp(v,OP_ColumnName, i, 0); + sqliteVdbeChangeP3(v, -1, p->span.z, p->span.n); + sqliteVdbeCompressSpace(v, addr); + }else if( pTabList->nSrc>1 || showFullNames ){ + char *zName = 0; + char *zTab; + + zTab = pTabList->a[j].zAlias; + if( showFullNames || zTab==0 ) zTab = pTab->zName; + sqliteSetString(&zName, zTab, ".", zCol, 0); + sqliteVdbeAddOp(v, OP_ColumnName, i, 0); + sqliteVdbeChangeP3(v, -1, zName, strlen(zName)); + sqliteFree(zName); + }else{ + sqliteVdbeAddOp(v, OP_ColumnName, i, 0); + sqliteVdbeChangeP3(v, -1, zCol, 0); + } + }else if( p->span.z && p->span.z[0] ){ + int addr = sqliteVdbeAddOp(v,OP_ColumnName, i, 0); + sqliteVdbeChangeP3(v, -1, p->span.z, p->span.n); + sqliteVdbeCompressSpace(v, addr); + }else{ + char zName[30]; + assert( p->op!=TK_COLUMN || pTabList==0 ); + sprintf(zName, "column%d", i+1); + sqliteVdbeAddOp(v, OP_ColumnName, i, 0); + sqliteVdbeChangeP3(v, -1, zName, strlen(zName)); + } + } +} + +/* +** Name of the connection operator, used for error messages. +*/ +static const char *selectOpName(int id){ + char *z; + switch( id ){ + case TK_ALL: z = "UNION ALL"; break; + case TK_INTERSECT: z = "INTERSECT"; break; + case TK_EXCEPT: z = "EXCEPT"; break; + default: z = "UNION"; break; + } + return z; +} + +/* +** Forward declaration +*/ +static int fillInColumnList(Parse*, Select*); + +/* +** Given a SELECT statement, generate a Table structure that describes +** the result set of that SELECT. +*/ +Table *sqliteResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){ + Table *pTab; + int i; + ExprList *pEList; + + if( fillInColumnList(pParse, pSelect) ){ + return 0; + } + pTab = sqliteMalloc( sizeof(Table) ); + if( pTab==0 ){ + return 0; + } + pTab->zName = zTabName ? sqliteStrDup(zTabName) : 0; + pEList = pSelect->pEList; + pTab->nCol = pEList->nExpr; + assert( pTab->nCol>0 ); + pTab->aCol = sqliteMalloc( sizeof(pTab->aCol[0])*pTab->nCol ); + for(i=0; inCol; i++){ + Expr *p; + if( pEList->a[i].zName ){ + pTab->aCol[i].zName = sqliteStrDup(pEList->a[i].zName); + }else if( (p=pEList->a[i].pExpr)->span.z && p->span.z[0] ){ + sqliteSetNString(&pTab->aCol[i].zName, p->span.z, p->span.n, 0); + }else if( p->op==TK_DOT && p->pRight && p->pRight->token.z && + p->pRight->token.z[0] ){ + sqliteSetNString(&pTab->aCol[i].zName, + p->pRight->token.z, p->pRight->token.n, 0); + }else{ + char zBuf[30]; + sprintf(zBuf, "column%d", i+1); + pTab->aCol[i].zName = sqliteStrDup(zBuf); + } + } + pTab->iPKey = -1; + return pTab; +} + +/* +** For the given SELECT statement, do three things. +** +** (1) Fill in the pTabList->a[].pTab fields in the SrcList that +** defines the set of tables that should be scanned. For views, +** fill pTabList->a[].pSelect with a copy of the SELECT statement +** that implements the view. A copy is made of the view's SELECT +** statement so that we can freely modify or delete that statement +** without worrying about messing up the presistent representation +** of the view. +** +** (2) Add terms to the WHERE clause to accomodate the NATURAL keyword +** on joins and the ON and USING clause of joins. +** +** (3) Scan the list of columns in the result set (pEList) looking +** for instances of the "*" operator or the TABLE.* operator. +** If found, expand each "*" to be every column in every table +** and TABLE.* to be every column in TABLE. +** +** Return 0 on success. If there are problems, leave an error message +** in pParse and return non-zero. +*/ +static int fillInColumnList(Parse *pParse, Select *p){ + int i, j, k, rc; + SrcList *pTabList; + ExprList *pEList; + Table *pTab; + + if( p==0 || p->pSrc==0 ) return 1; + pTabList = p->pSrc; + pEList = p->pEList; + + /* Look up every table in the table list. + */ + for(i=0; inSrc; i++){ + if( pTabList->a[i].pTab ){ + /* This routine has run before! No need to continue */ + return 0; + } + if( pTabList->a[i].zName==0 ){ + /* A sub-query in the FROM clause of a SELECT */ + assert( pTabList->a[i].pSelect!=0 ); + if( pTabList->a[i].zAlias==0 ){ + char zFakeName[60]; + sprintf(zFakeName, "sqlite_subquery_%p_", + (void*)pTabList->a[i].pSelect); + sqliteSetString(&pTabList->a[i].zAlias, zFakeName, 0); + } + pTabList->a[i].pTab = pTab = + sqliteResultSetOfSelect(pParse, pTabList->a[i].zAlias, + pTabList->a[i].pSelect); + if( pTab==0 ){ + return 1; + } + /* The isTransient flag indicates that the Table structure has been + ** dynamically allocated and may be freed at any time. In other words, + ** pTab is not pointing to a persistent table structure that defines + ** part of the schema. */ + pTab->isTransient = 1; + }else{ + /* An ordinary table or view name in the FROM clause */ + pTabList->a[i].pTab = pTab = + sqliteLocateTable(pParse,pTabList->a[i].zName,pTabList->a[i].zDatabase); + if( pTab==0 ){ + return 1; + } + if( pTab->pSelect ){ + /* We reach here if the named table is a really a view */ + if( sqliteViewGetColumnNames(pParse, pTab) ){ + return 1; + } + /* If pTabList->a[i].pSelect!=0 it means we are dealing with a + ** view within a view. The SELECT structure has already been + ** copied by the outer view so we can skip the copy step here + ** in the inner view. + */ + if( pTabList->a[i].pSelect==0 ){ + pTabList->a[i].pSelect = sqliteSelectDup(pTab->pSelect); + } + } + } + } + + /* Process NATURAL keywords, and ON and USING clauses of joins. + */ + if( sqliteProcessJoin(pParse, p) ) return 1; + + /* For every "*" that occurs in the column list, insert the names of + ** all columns in all tables. And for every TABLE.* insert the names + ** of all columns in TABLE. The parser inserted a special expression + ** with the TK_ALL operator for each "*" that it found in the column list. + ** The following code just has to locate the TK_ALL expressions and expand + ** each one to the list of all columns in all tables. + ** + ** The first loop just checks to see if there are any "*" operators + ** that need expanding. + */ + for(k=0; knExpr; k++){ + Expr *pE = pEList->a[k].pExpr; + if( pE->op==TK_ALL ) break; + if( pE->op==TK_DOT && pE->pRight && pE->pRight->op==TK_ALL + && pE->pLeft && pE->pLeft->op==TK_ID ) break; + } + rc = 0; + if( knExpr ){ + /* + ** If we get here it means the result set contains one or more "*" + ** operators that need to be expanded. Loop through each expression + ** in the result set and expand them one by one. + */ + struct ExprList_item *a = pEList->a; + ExprList *pNew = 0; + for(k=0; knExpr; k++){ + Expr *pE = a[k].pExpr; + if( pE->op!=TK_ALL && + (pE->op!=TK_DOT || pE->pRight==0 || pE->pRight->op!=TK_ALL) ){ + /* This particular expression does not need to be expanded. + */ + pNew = sqliteExprListAppend(pNew, a[k].pExpr, 0); + pNew->a[pNew->nExpr-1].zName = a[k].zName; + a[k].pExpr = 0; + a[k].zName = 0; + }else{ + /* This expression is a "*" or a "TABLE.*" and needs to be + ** expanded. */ + int tableSeen = 0; /* Set to 1 when TABLE matches */ + Token *pName; /* text of name of TABLE */ + if( pE->op==TK_DOT && pE->pLeft ){ + pName = &pE->pLeft->token; + }else{ + pName = 0; + } + for(i=0; inSrc; i++){ + Table *pTab = pTabList->a[i].pTab; + char *zTabName = pTabList->a[i].zAlias; + if( zTabName==0 || zTabName[0]==0 ){ + zTabName = pTab->zName; + } + if( pName && (zTabName==0 || zTabName[0]==0 || + sqliteStrNICmp(pName->z, zTabName, pName->n)!=0 || + zTabName[pName->n]!=0) ){ + continue; + } + tableSeen = 1; + for(j=0; jnCol; j++){ + Expr *pExpr, *pLeft, *pRight; + char *zName = pTab->aCol[j].zName; + + if( i>0 && (pTabList->a[i-1].jointype & JT_NATURAL)!=0 && + columnIndex(pTabList->a[i-1].pTab, zName)>=0 ){ + /* In a NATURAL join, omit the join columns from the + ** table on the right */ + continue; + } + if( i>0 && sqliteIdListIndex(pTabList->a[i-1].pUsing, zName)>=0 ){ + /* In a join with a USING clause, omit columns in the + ** using clause from the table on the right. */ + continue; + } + pRight = sqliteExpr(TK_ID, 0, 0, 0); + if( pRight==0 ) break; + pRight->token.z = zName; + pRight->token.n = strlen(zName); + pRight->token.dyn = 0; + if( zTabName && pTabList->nSrc>1 ){ + pLeft = sqliteExpr(TK_ID, 0, 0, 0); + pExpr = sqliteExpr(TK_DOT, pLeft, pRight, 0); + if( pExpr==0 ) break; + pLeft->token.z = zTabName; + pLeft->token.n = strlen(zTabName); + pLeft->token.dyn = 0; + sqliteSetString((char**)&pExpr->span.z, zTabName, ".", zName, 0); + pExpr->span.n = strlen(pExpr->span.z); + pExpr->span.dyn = 1; + pExpr->token.z = 0; + pExpr->token.n = 0; + pExpr->token.dyn = 0; + }else{ + pExpr = pRight; + pExpr->span = pExpr->token; + } + pNew = sqliteExprListAppend(pNew, pExpr, 0); + } + } + if( !tableSeen ){ + if( pName ){ + sqliteErrorMsg(pParse, "no such table: %T", pName); + }else{ + sqliteErrorMsg(pParse, "no tables specified"); + } + rc = 1; + } + } + } + sqliteExprListDelete(pEList); + p->pEList = pNew; + } + return rc; +} + +/* +** This routine recursively unlinks the Select.pSrc.a[].pTab pointers +** in a select structure. It just sets the pointers to NULL. This +** routine is recursive in the sense that if the Select.pSrc.a[].pSelect +** pointer is not NULL, this routine is called recursively on that pointer. +** +** This routine is called on the Select structure that defines a +** VIEW in order to undo any bindings to tables. This is necessary +** because those tables might be DROPed by a subsequent SQL command. +** If the bindings are not removed, then the Select.pSrc->a[].pTab field +** will be left pointing to a deallocated Table structure after the +** DROP and a coredump will occur the next time the VIEW is used. +*/ +void sqliteSelectUnbind(Select *p){ + int i; + SrcList *pSrc = p->pSrc; + Table *pTab; + if( p==0 ) return; + for(i=0; inSrc; i++){ + if( (pTab = pSrc->a[i].pTab)!=0 ){ + if( pTab->isTransient ){ + sqliteDeleteTable(0, pTab); + } + pSrc->a[i].pTab = 0; + if( pSrc->a[i].pSelect ){ + sqliteSelectUnbind(pSrc->a[i].pSelect); + } + } + } +} + +/* +** This routine associates entries in an ORDER BY expression list with +** columns in a result. For each ORDER BY expression, the opcode of +** the top-level node is changed to TK_COLUMN and the iColumn value of +** the top-level node is filled in with column number and the iTable +** value of the top-level node is filled with iTable parameter. +** +** If there are prior SELECT clauses, they are processed first. A match +** in an earlier SELECT takes precedence over a later SELECT. +** +** Any entry that does not match is flagged as an error. The number +** of errors is returned. +** +** This routine does NOT correctly initialize the Expr.dataType field +** of the ORDER BY expressions. The multiSelectSortOrder() routine +** must be called to do that after the individual select statements +** have all been analyzed. This routine is unable to compute Expr.dataType +** because it must be called before the individual select statements +** have been analyzed. +*/ +static int matchOrderbyToColumn( + Parse *pParse, /* A place to leave error messages */ + Select *pSelect, /* Match to result columns of this SELECT */ + ExprList *pOrderBy, /* The ORDER BY values to match against columns */ + int iTable, /* Insert this value in iTable */ + int mustComplete /* If TRUE all ORDER BYs must match */ +){ + int nErr = 0; + int i, j; + ExprList *pEList; + + if( pSelect==0 || pOrderBy==0 ) return 1; + if( mustComplete ){ + for(i=0; inExpr; i++){ pOrderBy->a[i].done = 0; } + } + if( fillInColumnList(pParse, pSelect) ){ + return 1; + } + if( pSelect->pPrior ){ + if( matchOrderbyToColumn(pParse, pSelect->pPrior, pOrderBy, iTable, 0) ){ + return 1; + } + } + pEList = pSelect->pEList; + for(i=0; inExpr; i++){ + Expr *pE = pOrderBy->a[i].pExpr; + int iCol = -1; + if( pOrderBy->a[i].done ) continue; + if( sqliteExprIsInteger(pE, &iCol) ){ + if( iCol<=0 || iCol>pEList->nExpr ){ + sqliteErrorMsg(pParse, + "ORDER BY position %d should be between 1 and %d", + iCol, pEList->nExpr); + nErr++; + break; + } + if( !mustComplete ) continue; + iCol--; + } + for(j=0; iCol<0 && jnExpr; j++){ + if( pEList->a[j].zName && (pE->op==TK_ID || pE->op==TK_STRING) ){ + char *zName, *zLabel; + zName = pEList->a[j].zName; + assert( pE->token.z ); + zLabel = sqliteStrNDup(pE->token.z, pE->token.n); + sqliteDequote(zLabel); + if( sqliteStrICmp(zName, zLabel)==0 ){ + iCol = j; + } + sqliteFree(zLabel); + } + if( iCol<0 && sqliteExprCompare(pE, pEList->a[j].pExpr) ){ + iCol = j; + } + } + if( iCol>=0 ){ + pE->op = TK_COLUMN; + pE->iColumn = iCol; + pE->iTable = iTable; + pOrderBy->a[i].done = 1; + } + if( iCol<0 && mustComplete ){ + sqliteErrorMsg(pParse, + "ORDER BY term number %d does not match any result column", i+1); + nErr++; + break; + } + } + return nErr; +} + +/* +** Get a VDBE for the given parser context. Create a new one if necessary. +** If an error occurs, return NULL and leave a message in pParse. +*/ +Vdbe *sqliteGetVdbe(Parse *pParse){ + Vdbe *v = pParse->pVdbe; + if( v==0 ){ + v = pParse->pVdbe = sqliteVdbeCreate(pParse->db); + } + return v; +} + +/* +** This routine sets the Expr.dataType field on all elements of +** the pOrderBy expression list. The pOrderBy list will have been +** set up by matchOrderbyToColumn(). Hence each expression has +** a TK_COLUMN as its root node. The Expr.iColumn refers to a +** column in the result set. The datatype is set to SQLITE_SO_TEXT +** if the corresponding column in p and every SELECT to the left of +** p has a datatype of SQLITE_SO_TEXT. If the cooressponding column +** in p or any of the left SELECTs is SQLITE_SO_NUM, then the datatype +** of the order-by expression is set to SQLITE_SO_NUM. +** +** Examples: +** +** CREATE TABLE one(a INTEGER, b TEXT); +** CREATE TABLE two(c VARCHAR(5), d FLOAT); +** +** SELECT b, b FROM one UNION SELECT d, c FROM two ORDER BY 1, 2; +** +** The primary sort key will use SQLITE_SO_NUM because the "d" in +** the second SELECT is numeric. The 1st column of the first SELECT +** is text but that does not matter because a numeric always overrides +** a text. +** +** The secondary key will use the SQLITE_SO_TEXT sort order because +** both the (second) "b" in the first SELECT and the "c" in the second +** SELECT have a datatype of text. +*/ +static void multiSelectSortOrder(Select *p, ExprList *pOrderBy){ + int i; + ExprList *pEList; + if( pOrderBy==0 ) return; + if( p==0 ){ + for(i=0; inExpr; i++){ + pOrderBy->a[i].pExpr->dataType = SQLITE_SO_TEXT; + } + return; + } + multiSelectSortOrder(p->pPrior, pOrderBy); + pEList = p->pEList; + for(i=0; inExpr; i++){ + Expr *pE = pOrderBy->a[i].pExpr; + if( pE->dataType==SQLITE_SO_NUM ) continue; + assert( pE->iColumn>=0 ); + if( pEList->nExpr>pE->iColumn ){ + pE->dataType = sqliteExprType(pEList->a[pE->iColumn].pExpr); + } + } +} + +/* +** Compute the iLimit and iOffset fields of the SELECT based on the +** nLimit and nOffset fields. nLimit and nOffset hold the integers +** that appear in the original SQL statement after the LIMIT and OFFSET +** keywords. Or that hold -1 and 0 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 +** 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 +** 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){ + /* + ** If the comparison is p->nLimit>0 then "LIMIT 0" shows + ** all rows. It is the same as no limit. If the comparision is + ** p->nLimit>=0 then "LIMIT 0" show no rows at all. + ** "LIMIT -1" always shows all rows. There is some + ** contraversy about what the correct behavior should be. + ** The current implementation interprets "LIMIT 0" to mean + ** no rows. + */ + if( p->nLimit>=0 ){ + int iMem = pParse->nMem++; + Vdbe *v = sqliteGetVdbe(pParse); + if( v==0 ) return; + sqliteVdbeAddOp(v, OP_Integer, -p->nLimit, 0); + sqliteVdbeAddOp(v, OP_MemStore, iMem, 1); + p->iLimit = iMem; + } + if( p->nOffset>0 ){ + int iMem = pParse->nMem++; + Vdbe *v = sqliteGetVdbe(pParse); + if( v==0 ) return; + sqliteVdbeAddOp(v, OP_Integer, -p->nOffset, 0); + sqliteVdbeAddOp(v, OP_MemStore, iMem, 1); + p->iOffset = iMem; + } +} + +/* +** This routine is called to process a query that is really the union +** or intersection of two or more separate queries. +** +** "p" points to the right-most of the two queries. the query on the +** left is p->pPrior. The left query could also be a compound query +** in which case this routine will be called recursively. +** +** The results of the total query are to be written into a destination +** of type eDest with parameter iParm. +** +** Example 1: Consider a three-way compound SQL statement. +** +** SELECT a FROM t1 UNION SELECT b FROM t2 UNION SELECT c FROM t3 +** +** This statement is parsed up as follows: +** +** SELECT c FROM t3 +** | +** `-----> SELECT b FROM t2 +** | +** `------> SELECT c FROM t1 +** +** The arrows in the diagram above represent the Select.pPrior pointer. +** So if this routine is called with p equal to the t3 query, then +** pPrior will be the t2 query. p->op will be TK_UNION in this case. +** +** Notice that because of the way SQLite parses compound SELECTs, the +** individual selects always group from left to right. +*/ +static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){ + int rc; /* Success code from a subroutine */ + Select *pPrior; /* Another SELECT immediately to our left */ + Vdbe *v; /* Generate code to this VDBE */ + + /* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs. Only + ** the last SELECT in the series may have an ORDER BY or LIMIT. + */ + if( p==0 || p->pPrior==0 ) return 1; + pPrior = p->pPrior; + if( pPrior->pOrderBy ){ + sqliteErrorMsg(pParse,"ORDER BY clause should come after %s not before", + selectOpName(p->op)); + return 1; + } + if( pPrior->nLimit>=0 || pPrior->nOffset>0 ){ + sqliteErrorMsg(pParse,"LIMIT clause should come after %s not before", + selectOpName(p->op)); + return 1; + } + + /* Make sure we have a valid query engine. If not, create a new one. + */ + v = sqliteGetVdbe(pParse); + if( v==0 ) return 1; + + /* Create the destination temporary table if necessary + */ + if( eDest==SRT_TempTable ){ + sqliteVdbeAddOp(v, OP_OpenTemp, iParm, 0); + eDest = SRT_Table; + } + + /* Generate code for the left and right SELECT statements. + */ + switch( p->op ){ + case TK_ALL: { + if( p->pOrderBy==0 ){ + pPrior->nLimit = p->nLimit; + pPrior->nOffset = p->nOffset; + rc = sqliteSelect(pParse, pPrior, eDest, iParm, 0, 0, 0); + if( rc ) return rc; + p->pPrior = 0; + p->iLimit = pPrior->iLimit; + p->iOffset = pPrior->iOffset; + p->nLimit = -1; + p->nOffset = 0; + rc = sqliteSelect(pParse, p, eDest, iParm, 0, 0, 0); + p->pPrior = pPrior; + if( rc ) return rc; + break; + } + /* For UNION ALL ... ORDER BY fall through to the next case */ + } + case TK_EXCEPT: + case TK_UNION: { + int unionTab; /* Cursor number of the temporary table holding result */ + int op; /* One of the SRT_ operations to apply to self */ + int priorOp; /* The SRT_ operation to apply to prior selects */ + int nLimit, nOffset; /* Saved values of p->nLimit and p->nOffset */ + ExprList *pOrderBy; /* The ORDER BY clause for the right SELECT */ + + priorOp = p->op==TK_ALL ? SRT_Table : SRT_Union; + if( eDest==priorOp && p->pOrderBy==0 && p->nLimit<0 && p->nOffset==0 ){ + /* We can reuse a temporary table generated by a SELECT to our + ** right. + */ + unionTab = iParm; + }else{ + /* We will need to create our own temporary table to hold the + ** intermediate results. + */ + unionTab = pParse->nTab++; + if( p->pOrderBy + && matchOrderbyToColumn(pParse, p, p->pOrderBy, unionTab, 1) ){ + return 1; + } + if( p->op!=TK_ALL ){ + sqliteVdbeAddOp(v, OP_OpenTemp, unionTab, 1); + sqliteVdbeAddOp(v, OP_KeyAsData, unionTab, 1); + }else{ + sqliteVdbeAddOp(v, OP_OpenTemp, unionTab, 0); + } + } + + /* Code the SELECT statements to our left + */ + rc = sqliteSelect(pParse, pPrior, priorOp, unionTab, 0, 0, 0); + if( rc ) return rc; + + /* Code the current SELECT statement + */ + switch( p->op ){ + case TK_EXCEPT: op = SRT_Except; break; + case TK_UNION: op = SRT_Union; break; + case TK_ALL: op = SRT_Table; break; + } + p->pPrior = 0; + pOrderBy = p->pOrderBy; + p->pOrderBy = 0; + nLimit = p->nLimit; + p->nLimit = -1; + nOffset = p->nOffset; + p->nOffset = 0; + rc = sqliteSelect(pParse, p, op, unionTab, 0, 0, 0); + p->pPrior = pPrior; + p->pOrderBy = pOrderBy; + p->nLimit = nLimit; + p->nOffset = nOffset; + if( rc ) return rc; + + /* Convert the data in the temporary table into whatever form + ** it is that we currently need. + */ + if( eDest!=priorOp || unionTab!=iParm ){ + int iCont, iBreak, iStart; + assert( p->pEList ); + if( eDest==SRT_Callback ){ + generateColumnNames(pParse, 0, p->pEList); + generateColumnTypes(pParse, p->pSrc, p->pEList); + } + iBreak = sqliteVdbeMakeLabel(v); + iCont = sqliteVdbeMakeLabel(v); + sqliteVdbeAddOp(v, OP_Rewind, unionTab, iBreak); + computeLimitRegisters(pParse, p); + iStart = sqliteVdbeCurrentAddr(v); + multiSelectSortOrder(p, p->pOrderBy); + rc = selectInnerLoop(pParse, p, p->pEList, unionTab, p->pEList->nExpr, + p->pOrderBy, -1, eDest, iParm, + iCont, iBreak); + if( rc ) return 1; + sqliteVdbeResolveLabel(v, iCont); + sqliteVdbeAddOp(v, OP_Next, unionTab, iStart); + sqliteVdbeResolveLabel(v, iBreak); + sqliteVdbeAddOp(v, OP_Close, unionTab, 0); + if( p->pOrderBy ){ + generateSortTail(p, v, p->pEList->nExpr, eDest, iParm); + } + } + break; + } + case TK_INTERSECT: { + int tab1, tab2; + int iCont, iBreak, iStart; + int nLimit, nOffset; + + /* INTERSECT is different from the others since it requires + ** two temporary tables. Hence it has its own case. Begin + ** by allocating the tables we will need. + */ + tab1 = pParse->nTab++; + tab2 = pParse->nTab++; + if( p->pOrderBy && matchOrderbyToColumn(pParse,p,p->pOrderBy,tab1,1) ){ + return 1; + } + sqliteVdbeAddOp(v, OP_OpenTemp, tab1, 1); + sqliteVdbeAddOp(v, OP_KeyAsData, tab1, 1); + + /* Code the SELECTs to our left into temporary table "tab1". + */ + rc = sqliteSelect(pParse, pPrior, SRT_Union, tab1, 0, 0, 0); + if( rc ) return rc; + + /* Code the current SELECT into temporary table "tab2" + */ + sqliteVdbeAddOp(v, OP_OpenTemp, tab2, 1); + sqliteVdbeAddOp(v, OP_KeyAsData, tab2, 1); + p->pPrior = 0; + nLimit = p->nLimit; + p->nLimit = -1; + nOffset = p->nOffset; + p->nOffset = 0; + rc = sqliteSelect(pParse, p, SRT_Union, tab2, 0, 0, 0); + p->pPrior = pPrior; + p->nLimit = nLimit; + p->nOffset = nOffset; + if( rc ) return rc; + + /* Generate code to take the intersection of the two temporary + ** tables. + */ + assert( p->pEList ); + if( eDest==SRT_Callback ){ + generateColumnNames(pParse, 0, p->pEList); + generateColumnTypes(pParse, p->pSrc, p->pEList); + } + iBreak = sqliteVdbeMakeLabel(v); + iCont = sqliteVdbeMakeLabel(v); + sqliteVdbeAddOp(v, OP_Rewind, tab1, iBreak); + computeLimitRegisters(pParse, p); + iStart = sqliteVdbeAddOp(v, OP_FullKey, tab1, 0); + sqliteVdbeAddOp(v, OP_NotFound, tab2, iCont); + multiSelectSortOrder(p, p->pOrderBy); + rc = selectInnerLoop(pParse, p, p->pEList, tab1, p->pEList->nExpr, + p->pOrderBy, -1, eDest, iParm, + iCont, iBreak); + if( rc ) return 1; + sqliteVdbeResolveLabel(v, iCont); + sqliteVdbeAddOp(v, OP_Next, tab1, iStart); + sqliteVdbeResolveLabel(v, iBreak); + sqliteVdbeAddOp(v, OP_Close, tab2, 0); + sqliteVdbeAddOp(v, OP_Close, tab1, 0); + if( p->pOrderBy ){ + generateSortTail(p, v, p->pEList->nExpr, eDest, iParm); + } + break; + } + } + assert( p->pEList && pPrior->pEList ); + if( p->pEList->nExpr!=pPrior->pEList->nExpr ){ + sqliteErrorMsg(pParse, "SELECTs to the left and right of %s" + " do not have the same number of result columns", selectOpName(p->op)); + return 1; + } + + /* Issue a null callback if that is what the user wants. + */ + if( eDest==SRT_Callback && + (pParse->useCallback==0 || (pParse->db->flags & SQLITE_NullCallback)!=0) + ){ + sqliteVdbeAddOp(v, OP_NullCallback, p->pEList->nExpr, 0); + } + return 0; +} + +/* +** Scan through the expression pExpr. Replace every reference to +** a column in table number iTable with a copy of the iColumn-th +** entry in pEList. (But leave references to the ROWID column +** unchanged.) +** +** This routine is part of the flattening procedure. A subquery +** whose result set is defined by pEList appears as entry in the +** FROM clause of a SELECT such that the VDBE cursor assigned to that +** FORM clause entry is iTable. This routine make the necessary +** changes to pExpr so that it refers directly to the source table +** of the subquery rather the result set of the subquery. +*/ +static void substExprList(ExprList*,int,ExprList*); /* Forward Decl */ +static void substExpr(Expr *pExpr, int iTable, ExprList *pEList){ + if( pExpr==0 ) return; + if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable && pExpr->iColumn>=0 ){ + Expr *pNew; + assert( pEList!=0 && pExpr->iColumnnExpr ); + assert( pExpr->pLeft==0 && pExpr->pRight==0 && pExpr->pList==0 ); + pNew = pEList->a[pExpr->iColumn].pExpr; + assert( pNew!=0 ); + pExpr->op = pNew->op; + pExpr->dataType = pNew->dataType; + assert( pExpr->pLeft==0 ); + pExpr->pLeft = sqliteExprDup(pNew->pLeft); + assert( pExpr->pRight==0 ); + pExpr->pRight = sqliteExprDup(pNew->pRight); + assert( pExpr->pList==0 ); + pExpr->pList = sqliteExprListDup(pNew->pList); + pExpr->iTable = pNew->iTable; + pExpr->iColumn = pNew->iColumn; + pExpr->iAgg = pNew->iAgg; + sqliteTokenCopy(&pExpr->token, &pNew->token); + sqliteTokenCopy(&pExpr->span, &pNew->span); + }else{ + substExpr(pExpr->pLeft, iTable, pEList); + substExpr(pExpr->pRight, iTable, pEList); + substExprList(pExpr->pList, iTable, pEList); + } +} +static void +substExprList(ExprList *pList, int iTable, ExprList *pEList){ + int i; + if( pList==0 ) return; + for(i=0; inExpr; i++){ + substExpr(pList->a[i].pExpr, iTable, pEList); + } +} + +/* +** This routine attempts to flatten subqueries in order to speed +** execution. It returns 1 if it makes changes and 0 if no flattening +** occurs. +** +** To understand the concept of flattening, consider the following +** query: +** +** SELECT a FROM (SELECT x+y AS a FROM t1 WHERE z<100) WHERE a>5 +** +** The default way of implementing this query is to execute the +** subquery first and store the results in a temporary table, then +** run the outer query on that temporary table. This requires two +** passes over the data. Furthermore, because the temporary table +** has no indices, the WHERE clause on the outer query cannot be +** optimized. +** +** This routine attempts to rewrite queries such as the above into +** a single flat select, like this: +** +** SELECT x+y AS a FROM t1 WHERE z<100 AND a>5 +** +** The code generated for this simpification gives the same result +** but only has to scan the data once. And because indices might +** exist on the table t1, a complete scan of the data might be +** avoided. +** +** Flattening is only attempted if all of the following are true: +** +** (1) The subquery and the outer query do not both use aggregates. +** +** (2) The subquery is not an aggregate or the outer query is not a join. +** +** (3) The subquery is not the right operand of a left outer join, or +** the subquery is not itself a join. (Ticket #306) +** +** (4) The subquery is not DISTINCT or the outer query is not a join. +** +** (5) The subquery is not DISTINCT or the outer query does not use +** aggregates. +** +** (6) The subquery does not use aggregates or the outer query is not +** DISTINCT. +** +** (7) The subquery has a FROM clause. +** +** (8) The subquery does not use LIMIT or the outer query is not a join. +** +** (9) The subquery does not use LIMIT or the outer query does not use +** aggregates. +** +** (10) The subquery does not use aggregates or the outer query does not +** use LIMIT. +** +** (11) The subquery and the outer query do not both have ORDER BY clauses. +** +** (12) The subquery is not the right term of a LEFT OUTER JOIN or the +** subquery has no WHERE clause. (added by ticket #350) +** +** 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. +** +** If flattening is not attempted, this routine is a no-op and returns 0. +** If flattening is attempted this routine returns 1. +** +** All of the expression analysis must occur on both the outer query and +** the subquery before this routine runs. +*/ +static int flattenSubquery( + Parse *pParse, /* The parsing context */ + Select *p, /* The parent or outer SELECT statement */ + int iFrom, /* Index in p->pSrc->a[] of the inner subquery */ + int isAgg, /* True if outer SELECT uses aggregate functions */ + int subqueryIsAgg /* True if the subquery uses aggregate functions */ +){ + Select *pSub; /* The inner query or "subquery" */ + SrcList *pSrc; /* The FROM clause of the outer query */ + SrcList *pSubSrc; /* The FROM clause of the subquery */ + ExprList *pList; /* The result set of the outer query */ + int iParent; /* VDBE cursor number of the pSub result set temp table */ + int i; + Expr *pWhere; + + /* Check to see if flattening is permitted. Return 0 if not. + */ + if( p==0 ) return 0; + pSrc = p->pSrc; + assert( pSrc && iFrom>=0 && iFromnSrc ); + pSub = pSrc->a[iFrom].pSelect; + assert( pSub!=0 ); + if( isAgg && subqueryIsAgg ) return 0; + if( subqueryIsAgg && pSrc->nSrc>1 ) return 0; + pSubSrc = pSub->pSrc; + assert( pSubSrc ); + if( pSubSrc->nSrc==0 ) return 0; + if( (pSub->isDistinct || pSub->nLimit>=0) && (pSrc->nSrc>1 || isAgg) ){ + return 0; + } + if( (p->isDistinct || p->nLimit>=0) && subqueryIsAgg ) return 0; + if( p->pOrderBy && pSub->pOrderBy ) return 0; + + /* 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 + ** is not allowed: + ** + ** t1 LEFT OUTER JOIN (t2 JOIN t3) + ** + ** If we flatten the above, we would get + ** + ** (t1 LEFT OUTER JOIN t2) JOIN t3 + ** + ** which is not at all the same thing. + */ + if( pSubSrc->nSrc>1 && iFrom>0 && (pSrc->a[iFrom-1].jointype & JT_OUTER)!=0 ){ + return 0; + } + + /* Restriction 12: If the subquery is the right operand of a left outer + ** join, make sure the subquery has no WHERE clause. + ** An examples of why this is not allowed: + ** + ** t1 LEFT OUTER JOIN (SELECT * FROM t2 WHERE t2.x>0) + ** + ** If we flatten the above, we would get + ** + ** (t1 LEFT OUTER JOIN t2) WHERE t2.x>0 + ** + ** But the t2.x>0 test will always fail on a NULL row of t2, which + ** effectively converts the OUTER JOIN into an INNER JOIN. + */ + if( iFrom>0 && (pSrc->a[iFrom-1].jointype & JT_OUTER)!=0 + && pSub->pWhere!=0 ){ + return 0; + } + + /* If we reach this point, it means flattening is permitted for the + ** iFrom-th entry of the FROM clause in the outer query. + */ + + /* Move all of the FROM elements of the subquery into the + ** the FROM clause of the outer query. Before doing this, remember + ** the cursor number for the original outer query FROM element in + ** iParent. The iParent cursor will never be used. Subsequent code + ** will scan expressions looking for iParent references and replace + ** those references with expressions that resolve to the subquery FROM + ** elements we are now copying in. + */ + iParent = pSrc->a[iFrom].iCursor; + { + int nSubSrc = pSubSrc->nSrc; + int jointype = pSrc->a[iFrom].jointype; + + if( pSrc->a[iFrom].pTab && pSrc->a[iFrom].pTab->isTransient ){ + sqliteDeleteTable(0, pSrc->a[iFrom].pTab); + } + sqliteFree(pSrc->a[iFrom].zDatabase); + sqliteFree(pSrc->a[iFrom].zName); + sqliteFree(pSrc->a[iFrom].zAlias); + if( nSubSrc>1 ){ + int extra = nSubSrc - 1; + for(i=1; ipSrc = pSrc; + for(i=pSrc->nSrc-1; i-extra>=iFrom; i--){ + pSrc->a[i] = pSrc->a[i-extra]; + } + } + for(i=0; ia[i+iFrom] = pSubSrc->a[i]; + memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i])); + } + pSrc->a[iFrom+nSubSrc-1].jointype = jointype; + } + + /* Now begin substituting subquery result set expressions for + ** references to the iParent in the outer query. + ** + ** Example: + ** + ** SELECT a+5, b*10 FROM (SELECT x*3 AS a, y+10 AS b FROM t1) WHERE a>b; + ** \ \_____________ subquery __________/ / + ** \_____________________ outer query ______________________________/ + ** + ** We look at every expression in the outer query and every place we see + ** "a" we substitute "x*3" and every place we see "b" we substitute "y+10". + */ + substExprList(p->pEList, iParent, pSub->pEList); + pList = p->pEList; + for(i=0; inExpr; 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); + } + } + if( isAgg ){ + substExprList(p->pGroupBy, iParent, pSub->pEList); + substExpr(p->pHaving, iParent, pSub->pEList); + } + if( pSub->pOrderBy ){ + assert( p->pOrderBy==0 ); + p->pOrderBy = pSub->pOrderBy; + pSub->pOrderBy = 0; + }else if( p->pOrderBy ){ + substExprList(p->pOrderBy, iParent, pSub->pEList); + } + if( pSub->pWhere ){ + pWhere = sqliteExprDup(pSub->pWhere); + }else{ + pWhere = 0; + } + if( subqueryIsAgg ){ + assert( p->pHaving==0 ); + p->pHaving = p->pWhere; + p->pWhere = pWhere; + substExpr(p->pHaving, iParent, pSub->pEList); + if( pSub->pHaving ){ + Expr *pHaving = sqliteExprDup(pSub->pHaving); + if( p->pHaving ){ + p->pHaving = sqliteExpr(TK_AND, p->pHaving, pHaving, 0); + }else{ + p->pHaving = pHaving; + } + } + assert( p->pGroupBy==0 ); + p->pGroupBy = sqliteExprListDup(pSub->pGroupBy); + }else if( p->pWhere==0 ){ + p->pWhere = pWhere; + }else{ + substExpr(p->pWhere, iParent, pSub->pEList); + if( pWhere ){ + p->pWhere = sqliteExpr(TK_AND, p->pWhere, pWhere, 0); + } + } + + /* The flattened query is distinct if either the inner or the + ** outer query is distinct. + */ + p->isDistinct = p->isDistinct || pSub->isDistinct; + + /* Transfer the limit expression from the subquery to the outer + ** query. + */ + if( pSub->nLimit>=0 ){ + if( p->nLimit<0 ){ + p->nLimit = pSub->nLimit; + }else if( p->nLimit+p->nOffset > pSub->nLimit+pSub->nOffset ){ + p->nLimit = pSub->nLimit + pSub->nOffset - p->nOffset; + } + } + p->nOffset += pSub->nOffset; + + /* Finially, delete what is left of the subquery and return + ** success. + */ + sqliteSelectDelete(pSub); + return 1; +} + +/* +** Analyze the SELECT statement passed in as an argument to see if it +** is a simple min() or max() query. If it is and this query can be +** satisfied using a single seek to the beginning or end of an index, +** then generate the code for this SELECT and return 1. If this is not a +** simple min() or max() query, then return 0; +** +** A simply min() or max() query looks like this: +** +** SELECT min(a) FROM table; +** SELECT max(a) FROM table; +** +** The query may have only a single table in its FROM argument. There +** can be no GROUP BY or HAVING or WHERE clauses. The result set must +** be the min() or max() of a single column of the table. The column +** in the min() or max() function must be indexed. +** +** The parameters to this routine are the same as for sqliteSelect(). +** See the header comment on that routine for additional information. +*/ +static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){ + Expr *pExpr; + int iCol; + Table *pTab; + Index *pIdx; + int base; + Vdbe *v; + int seekOp; + int cont; + ExprList eList; + struct ExprList_item eListItem; + + /* Check to see if this query is a simple min() or max() query. Return + ** zero if it is not. + */ + if( p->pGroupBy || p->pHaving || p->pWhere ) return 0; + if( p->pSrc->nSrc!=1 ) return 0; + if( p->pEList->nExpr!=1 ) return 0; + pExpr = p->pEList->a[0].pExpr; + if( pExpr->op!=TK_AGG_FUNCTION ) return 0; + if( pExpr->pList==0 || pExpr->pList->nExpr!=1 ) return 0; + if( pExpr->token.n!=3 ) return 0; + if( sqliteStrNICmp(pExpr->token.z,"min",3)==0 ){ + seekOp = OP_Rewind; + }else if( sqliteStrNICmp(pExpr->token.z,"max",3)==0 ){ + seekOp = OP_Last; + }else{ + return 0; + } + pExpr = pExpr->pList->a[0].pExpr; + if( pExpr->op!=TK_COLUMN ) return 0; + iCol = pExpr->iColumn; + pTab = p->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 + ** key column, no index is necessary so set pIdx to NULL. If no + ** usable index is found, return 0. + */ + if( iCol<0 ){ + pIdx = 0; + }else{ + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + assert( pIdx->nColumn>=1 ); + if( pIdx->aiColumn[0]==iCol ) break; + } + if( pIdx==0 ) return 0; + } + + /* Identify column types if we will be using the callback. This + ** step is skipped if the output is going to a table or a memory cell. + ** The column names have already been generated in the calling function. + */ + v = sqliteGetVdbe(pParse); + if( v==0 ) return 0; + if( eDest==SRT_Callback ){ + generateColumnTypes(pParse, p->pSrc, p->pEList); + } + + /* Generating code to find the min or the max. Basically all we have + ** to do is find the first or the last entry in the chosen index. If + ** the min() or max() is on the INTEGER PRIMARY KEY, then find the first + ** or last entry in the main table. + */ + sqliteCodeVerifySchema(pParse, pTab->iDb); + base = p->pSrc->a[0].iCursor; + computeLimitRegisters(pParse, p); + sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0); + sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum); + sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC); + cont = sqliteVdbeMakeLabel(v); + if( pIdx==0 ){ + sqliteVdbeAddOp(v, seekOp, base, 0); + }else{ + sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0); + sqliteVdbeAddOp(v, OP_OpenRead, base+1, pIdx->tnum); + sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC); + sqliteVdbeAddOp(v, seekOp, base+1, 0); + sqliteVdbeAddOp(v, OP_IdxRecno, base+1, 0); + sqliteVdbeAddOp(v, OP_Close, base+1, 0); + sqliteVdbeAddOp(v, OP_MoveTo, base, 0); + } + eList.nExpr = 1; + 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); + sqliteVdbeResolveLabel(v, cont); + sqliteVdbeAddOp(v, OP_Close, base, 0); + return 1; +} + +/* +** Generate code for the given SELECT statement. +** +** The results are distributed in various ways depending on the +** value of eDest and iParm. +** +** eDest Value Result +** ------------ ------------------------------------------- +** SRT_Callback Invoke the callback for each row of the result. +** +** SRT_Mem Store first result in memory cell iParm +** +** SRT_Set Store results as keys of a table with cursor iParm +** +** SRT_Union Store results as a key in a temporary table iParm +** +** SRT_Except Remove results form the temporary table iParm. +** +** SRT_Table Store results in temporary table iParm +** +** The table above is incomplete. Additional eDist value have be added +** since this comment was written. See the selectInnerLoop() function for +** a complete listing of the allowed values of eDest and their meanings. +** +** This routine returns the number of errors. If any errors are +** encountered, then an appropriate error message is left in +** pParse->zErrMsg. +** +** This routine does NOT free the Select structure passed in. The +** calling function needs to do that. +** +** The pParent, parentTab, and *pParentAgg fields are filled in if this +** SELECT is a subquery. This routine may try to combine this SELECT +** with its parent to form a single flat query. In so doing, it might +** change the parent query from a non-aggregate to an aggregate query. +** For that reason, the pParentAgg flag is passed as a pointer, so it +** can be changed. +** +** Example 1: The meaning of the pParent parameter. +** +** SELECT * FROM t1 JOIN (SELECT x, count(*) FROM t2) JOIN t3; +** \ \_______ subquery _______/ / +** \ / +** \____________________ outer query ___________________/ +** +** This routine is called for the outer query first. For that call, +** pParent will be NULL. During the processing of the outer query, this +** routine is called recursively to handle the subquery. For the recursive +** call, pParent will point to the outer query. Because the subquery is +** the second element in a three-way join, the parentTab parameter will +** be 1 (the 2nd value of a 0-indexed array.) +*/ +int sqliteSelect( + Parse *pParse, /* The parser context */ + Select *p, /* The SELECT statement being coded. */ + int eDest, /* How to dispose of the results */ + int iParm, /* A parameter used by the eDest disposal method */ + Select *pParent, /* Another SELECT for which this is a sub-query */ + int parentTab, /* Index in pParent->pSrc of this query */ + int *pParentAgg /* True if pParent uses aggregate functions */ +){ + int i; + WhereInfo *pWInfo; + Vdbe *v; + int isAgg = 0; /* True for select lists like "count(*)" */ + ExprList *pEList; /* List of columns to extract. */ + SrcList *pTabList; /* List of tables to select from */ + Expr *pWhere; /* The WHERE clause. May be NULL */ + ExprList *pOrderBy; /* The ORDER BY clause. May be NULL */ + ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */ + Expr *pHaving; /* The HAVING clause. May be NULL */ + int isDistinct; /* True if the DISTINCT keyword is present */ + int distinct; /* Table to use for the distinct set */ + int rc = 1; /* Value to return from this function */ + + if( sqlite_malloc_failed || pParse->nErr || p==0 ) return 1; + if( sqliteAuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1; + + /* If there is are a sequence of queries, do the earlier ones first. + */ + if( p->pPrior ){ + return multiSelect(pParse, p, eDest, iParm); + } + + /* Make local copies of the parameters for this query. + */ + pTabList = p->pSrc; + pWhere = p->pWhere; + pOrderBy = p->pOrderBy; + pGroupBy = p->pGroupBy; + pHaving = p->pHaving; + isDistinct = p->isDistinct; + + /* Allocate VDBE cursors for each table in the FROM clause + */ + sqliteSrcListAssignCursors(pParse, pTabList); + + /* + ** Do not even attempt to generate any code if we have already seen + ** errors before this routine starts. + */ + if( pParse->nErr>0 ) goto select_end; + + /* Expand any "*" terms in the result set. (For example the "*" in + ** "SELECT * FROM t1") The fillInColumnlist() routine also does some + ** other housekeeping - see the header comment for details. + */ + if( fillInColumnList(pParse, p) ){ + goto select_end; + } + pWhere = p->pWhere; + pEList = p->pEList; + if( pEList==0 ) goto select_end; + + /* If writing to memory or generating a set + ** only a single column may be output. + */ + if( (eDest==SRT_Mem || eDest==SRT_Set) && pEList->nExpr>1 ){ + sqliteErrorMsg(pParse, "only a single result allowed for " + "a SELECT that is part of an expression"); + goto select_end; + } + + /* ORDER BY is ignored for some destinations. + */ + switch( eDest ){ + case SRT_Union: + case SRT_Except: + case SRT_Discard: + pOrderBy = 0; + break; + default: + break; + } + + /* At this point, we should have allocated all the cursors that we + ** need to handle subquerys and temporary tables. + ** + ** Resolve the column names and do a semantics check on all the expressions. + */ + for(i=0; inExpr; i++){ + if( sqliteExprResolveIds(pParse, pTabList, 0, pEList->a[i].pExpr) ){ + goto select_end; + } + if( sqliteExprCheck(pParse, pEList->a[i].pExpr, 1, &isAgg) ){ + goto select_end; + } + } + if( pWhere ){ + if( sqliteExprResolveIds(pParse, pTabList, pEList, pWhere) ){ + goto select_end; + } + if( sqliteExprCheck(pParse, pWhere, 0, 0) ){ + goto select_end; + } + sqliteOracle8JoinFixup(pTabList, pWhere); + } + if( pHaving ){ + if( pGroupBy==0 ){ + sqliteErrorMsg(pParse, "a GROUP BY clause is required before HAVING"); + goto select_end; + } + if( sqliteExprResolveIds(pParse, pTabList, pEList, pHaving) ){ + goto select_end; + } + if( sqliteExprCheck(pParse, pHaving, 1, &isAgg) ){ + goto select_end; + } + } + if( pOrderBy ){ + for(i=0; inExpr; i++){ + int iCol; + Expr *pE = pOrderBy->a[i].pExpr; + if( sqliteExprIsInteger(pE, &iCol) && iCol>0 && iCol<=pEList->nExpr ){ + sqliteExprDelete(pE); + pE = pOrderBy->a[i].pExpr = sqliteExprDup(pEList->a[iCol-1].pExpr); + } + if( sqliteExprResolveIds(pParse, pTabList, pEList, pE) ){ + goto select_end; + } + if( sqliteExprCheck(pParse, pE, isAgg, 0) ){ + goto select_end; + } + if( sqliteExprIsConstant(pE) ){ + if( sqliteExprIsInteger(pE, &iCol)==0 ){ + sqliteErrorMsg(pParse, + "ORDER BY terms must not be non-integer constants"); + goto select_end; + }else if( iCol<=0 || iCol>pEList->nExpr ){ + sqliteErrorMsg(pParse, + "ORDER BY column number %d out of range - should be " + "between 1 and %d", iCol, pEList->nExpr); + goto select_end; + } + } + } + } + if( pGroupBy ){ + for(i=0; inExpr; i++){ + int iCol; + Expr *pE = pGroupBy->a[i].pExpr; + if( sqliteExprIsInteger(pE, &iCol) && iCol>0 && iCol<=pEList->nExpr ){ + sqliteExprDelete(pE); + pE = pGroupBy->a[i].pExpr = sqliteExprDup(pEList->a[iCol-1].pExpr); + } + if( sqliteExprResolveIds(pParse, pTabList, pEList, pE) ){ + goto select_end; + } + if( sqliteExprCheck(pParse, pE, isAgg, 0) ){ + goto select_end; + } + if( sqliteExprIsConstant(pE) ){ + if( sqliteExprIsInteger(pE, &iCol)==0 ){ + sqliteErrorMsg(pParse, + "GROUP BY terms must not be non-integer constants"); + goto select_end; + }else if( iCol<=0 || iCol>pEList->nExpr ){ + sqliteErrorMsg(pParse, + "GROUP BY column number %d out of range - should be " + "between 1 and %d", iCol, pEList->nExpr); + goto select_end; + } + } + } + } + + /* Begin generating code. + */ + v = sqliteGetVdbe(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); + } + + /* Check for the special case of a min() or max() function by itself + ** in the result set. + */ + if( simpleMinMaxQuery(pParse, p, eDest, iParm) ){ + rc = 0; + goto select_end; + } + + /* Generate code for all sub-queries in the FROM clause + */ + for(i=0; inSrc; i++){ + const char *zSavedAuthContext; + int needRestoreContext; + + if( pTabList->a[i].pSelect==0 ) continue; + if( pTabList->a[i].zName!=0 ){ + zSavedAuthContext = pParse->zAuthContext; + pParse->zAuthContext = pTabList->a[i].zName; + needRestoreContext = 1; + }else{ + needRestoreContext = 0; + } + sqliteSelect(pParse, pTabList->a[i].pSelect, SRT_TempTable, + pTabList->a[i].iCursor, p, i, &isAgg); + if( needRestoreContext ){ + pParse->zAuthContext = zSavedAuthContext; + } + pTabList = p->pSrc; + pWhere = p->pWhere; + if( eDest!=SRT_Union && eDest!=SRT_Except && eDest!=SRT_Discard ){ + pOrderBy = p->pOrderBy; + } + pGroupBy = p->pGroupBy; + pHaving = p->pHaving; + isDistinct = p->isDistinct; + } + + /* Check to see if this is a subquery that can be "flattened" into its parent. + ** If flattening is a possiblity, do so and return immediately. + */ + if( pParent && pParentAgg && + flattenSubquery(pParse, pParent, parentTab, *pParentAgg, isAgg) ){ + if( isAgg ) *pParentAgg = 1; + return rc; + } + + /* Set the limiter. + */ + computeLimitRegisters(pParse, p); + + /* Identify column types if we will be using a callback. This + ** step is skipped if the output is going to a destination other + ** than a callback. + ** + ** We have to do this separately from the creation of column names + ** above because if the pTabList contains views then they will not + ** have been resolved and we will not know the column types until + ** now. + */ + if( eDest==SRT_Callback ){ + generateColumnTypes(pParse, pTabList, pEList); + } + + /* If the output is destined for a temporary table, open that table. + */ + if( eDest==SRT_TempTable ){ + sqliteVdbeAddOp(v, OP_OpenTemp, iParm, 0); + } + + /* Do an analysis of aggregate expressions. + */ + sqliteAggregateInfoReset(pParse); + if( isAgg || pGroupBy ){ + assert( pParse->nAgg==0 ); + isAgg = 1; + for(i=0; inExpr; i++){ + if( sqliteExprAnalyzeAggregates(pParse, pEList->a[i].pExpr) ){ + goto select_end; + } + } + if( pGroupBy ){ + for(i=0; inExpr; i++){ + if( sqliteExprAnalyzeAggregates(pParse, pGroupBy->a[i].pExpr) ){ + goto select_end; + } + } + } + if( pHaving && sqliteExprAnalyzeAggregates(pParse, pHaving) ){ + goto select_end; + } + if( pOrderBy ){ + for(i=0; inExpr; i++){ + if( sqliteExprAnalyzeAggregates(pParse, pOrderBy->a[i].pExpr) ){ + goto select_end; + } + } + } + } + + /* Reset the aggregator + */ + if( isAgg ){ + sqliteVdbeAddOp(v, OP_AggReset, 0, pParse->nAgg); + for(i=0; inAgg; i++){ + FuncDef *pFunc; + if( (pFunc = pParse->aAgg[i].pFunc)!=0 && pFunc->xFinalize!=0 ){ + sqliteVdbeAddOp(v, OP_AggInit, 0, i); + sqliteVdbeChangeP3(v, -1, (char*)pFunc, P3_POINTER); + } + } + if( pGroupBy==0 ){ + sqliteVdbeAddOp(v, OP_String, 0, 0); + sqliteVdbeAddOp(v, OP_AggFocus, 0, 0); + } + } + + /* Initialize the memory cell to NULL + */ + if( eDest==SRT_Mem ){ + sqliteVdbeAddOp(v, OP_String, 0, 0); + sqliteVdbeAddOp(v, OP_MemStore, iParm, 1); + } + + /* Open a temporary table to use for the distinct set. + */ + if( isDistinct ){ + distinct = pParse->nTab++; + sqliteVdbeAddOp(v, OP_OpenTemp, distinct, 1); + }else{ + distinct = -1; + } + + /* Begin the database scan + */ + pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 0, + pGroupBy ? 0 : &pOrderBy); + if( pWInfo==0 ) goto select_end; + + /* Use the standard inner loop if we are not dealing with + ** aggregates + */ + if( !isAgg ){ + if( selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, distinct, eDest, + iParm, pWInfo->iContinue, pWInfo->iBreak) ){ + goto select_end; + } + } + + /* If we are dealing with aggregates, then do the special aggregate + ** processing. + */ + else{ + if( pGroupBy ){ + int lbl1; + for(i=0; inExpr; i++){ + sqliteExprCode(pParse, pGroupBy->a[i].pExpr); + } + sqliteVdbeAddOp(v, OP_MakeKey, pGroupBy->nExpr, 0); + if( pParse->db->file_format>=4 ) sqliteAddKeyType(v, pGroupBy); + lbl1 = sqliteVdbeMakeLabel(v); + sqliteVdbeAddOp(v, OP_AggFocus, 0, lbl1); + for(i=0; inAgg; i++){ + if( pParse->aAgg[i].isAgg ) continue; + sqliteExprCode(pParse, pParse->aAgg[i].pExpr); + sqliteVdbeAddOp(v, OP_AggSet, 0, i); + } + sqliteVdbeResolveLabel(v, lbl1); + } + for(i=0; inAgg; i++){ + Expr *pE; + int j; + if( !pParse->aAgg[i].isAgg ) continue; + pE = pParse->aAgg[i].pExpr; + assert( pE->op==TK_AGG_FUNCTION ); + if( pE->pList ){ + for(j=0; jpList->nExpr; j++){ + sqliteExprCode(pParse, pE->pList->a[j].pExpr); + } + } + sqliteVdbeAddOp(v, OP_Integer, i, 0); + sqliteVdbeAddOp(v, OP_AggFunc, 0, pE->pList ? pE->pList->nExpr : 0); + assert( pParse->aAgg[i].pFunc!=0 ); + assert( pParse->aAgg[i].pFunc->xStep!=0 ); + sqliteVdbeChangeP3(v, -1, (char*)pParse->aAgg[i].pFunc, P3_POINTER); + } + } + + /* End the database scan loop. + */ + sqliteWhereEnd(pWInfo); + + /* If we are processing aggregates, we need to set up a second loop + ** over all of the aggregate values and process them. + */ + if( isAgg ){ + int endagg = sqliteVdbeMakeLabel(v); + int startagg; + startagg = sqliteVdbeAddOp(v, OP_AggNext, 0, endagg); + pParse->useAgg = 1; + if( pHaving ){ + sqliteExprIfFalse(pParse, pHaving, startagg, 1); + } + if( selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, distinct, eDest, + iParm, startagg, endagg) ){ + goto select_end; + } + sqliteVdbeAddOp(v, OP_Goto, 0, startagg); + sqliteVdbeResolveLabel(v, endagg); + sqliteVdbeAddOp(v, OP_Noop, 0, 0); + pParse->useAgg = 0; + } + + /* If there is an ORDER BY clause, then we need to sort the results + ** and send them to the callback one by one. + */ + if( pOrderBy ){ + generateSortTail(p, v, pEList->nExpr, eDest, iParm); + } + + + /* Issue a null callback if that is what the user wants. + */ + if( eDest==SRT_Callback && + (pParse->useCallback==0 || (pParse->db->flags & SQLITE_NullCallback)!=0) + ){ + sqliteVdbeAddOp(v, OP_NullCallback, pEList->nExpr, 0); + } + + /* The SELECT was successfully coded. Set the return code to 0 + ** to indicate no errors. + */ + rc = 0; + + /* Control jumps to here if an error is encountered above, or upon + ** successful coding of the SELECT. + */ +select_end: + sqliteAggregateInfoReset(pParse); + return rc; +} diff --git a/sqlitebrowser/sqlitebrowser/sqlite_source/sqlite.h b/sqlitebrowser/sqlitebrowser/sqlite_source/sqlite.h new file mode 100755 index 00000000..a60e3f69 --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/sqlite_source/sqlite.h @@ -0,0 +1,706 @@ +/* +** 2001 September 15 +** +** 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 header file defines the interface that the SQLite library +** presents to client programs. +** +** @(#) $Id: sqlite.h,v 1.1.1.1 2003-08-21 02:24:20 tabuleiro Exp $ +*/ +#ifndef _SQLITE_H_ +#define _SQLITE_H_ +#include /* Needed for the definition of va_list */ + +/* +** Make sure we can call this stuff from C++. +*/ +#ifdef __cplusplus +extern "C" { +#endif + +/* +** The version of the SQLite library. +*/ +#define SQLITE_VERSION "2.8.5" + +/* +** The version string is also compiled into the library so that a program +** can check to make sure that the lib*.a file and the *.h file are from +** the same version. +*/ +extern const char sqlite_version[]; + +/* +** The SQLITE_UTF8 macro is defined if the library expects to see +** UTF-8 encoded data. The SQLITE_ISO8859 macro is defined if the +** iso8859 encoded should be used. +*/ +#define SQLITE_ISO8859 1 + +/* +** The following constant holds one of two strings, "UTF-8" or "iso8859", +** depending on which character encoding the SQLite library expects to +** see. The character encoding makes a difference for the LIKE and GLOB +** operators and for the LENGTH() and SUBSTR() functions. +*/ +extern const char sqlite_encoding[]; + +/* +** Each open sqlite database is represented by an instance of the +** following opaque structure. +*/ +typedef struct sqlite sqlite; + +/* +** A function to open a new sqlite database. +** +** If the database does not exist and mode indicates write +** permission, then a new database is created. If the database +** does not exist and mode does not indicate write permission, +** then the open fails, an error message generated (if errmsg!=0) +** and the function returns 0. +** +** If mode does not indicates user write permission, then the +** database is opened read-only. +** +** The Truth: As currently implemented, all databases are opened +** for writing all the time. Maybe someday we will provide the +** ability to open a database readonly. The mode parameters is +** provided in anticipation of that enhancement. +*/ +sqlite *sqlite_open(const char *filename, int mode, char **errmsg); + +/* +** A function to close the database. +** +** Call this function with a pointer to a structure that was previously +** returned from sqlite_open() and the corresponding database will by closed. +*/ +void sqlite_close(sqlite *); + +/* +** The type for a callback function. +*/ +typedef int (*sqlite_callback)(void*,int,char**, char**); + +/* +** A function to executes one or more statements of SQL. +** +** If one or more of the SQL statements are queries, then +** the callback function specified by the 3rd parameter is +** invoked once for each row of the query result. This callback +** should normally return 0. If the callback returns a non-zero +** value then the query is aborted, all subsequent SQL statements +** are skipped and the sqlite_exec() function returns the SQLITE_ABORT. +** +** The 4th parameter is an arbitrary pointer that is passed +** to the callback function as its first parameter. +** +** The 2nd parameter to the callback function is the number of +** columns in the query result. The 3rd parameter to the callback +** is an array of strings holding the values for each column. +** The 4th parameter to the callback is an array of strings holding +** the names of each column. +** +** The callback function may be NULL, even for queries. A NULL +** callback is not an error. It just means that no callback +** will be invoked. +** +** If an error occurs while parsing or evaluating the SQL (but +** not while executing the callback) then an appropriate error +** message is written into memory obtained from malloc() and +** *errmsg is made to point to that message. The calling function +** is responsible for freeing the memory that holds the error +** message. Use sqlite_freemem() for this. If errmsg==NULL, +** then no error message is ever written. +** +** The return value is is SQLITE_OK if there are no errors and +** some other return code if there is an error. The particular +** return value depends on the type of error. +** +** If the query could not be executed because a database file is +** locked or busy, then this function returns SQLITE_BUSY. (This +** behavior can be modified somewhat using the sqlite_busy_handler() +** and sqlite_busy_timeout() functions below.) +*/ +int sqlite_exec( + sqlite*, /* An open database */ + const char *sql, /* SQL to be executed */ + sqlite_callback, /* Callback function */ + void *, /* 1st argument to callback function */ + char **errmsg /* Error msg written here */ +); + +/* +** Return values for sqlite_exec() and sqlite_step() +*/ +#define SQLITE_OK 0 /* Successful result */ +#define SQLITE_ERROR 1 /* SQL error or missing database */ +#define SQLITE_INTERNAL 2 /* An internal logic error in SQLite */ +#define SQLITE_PERM 3 /* Access permission denied */ +#define SQLITE_ABORT 4 /* Callback routine requested an abort */ +#define SQLITE_BUSY 5 /* The database file is locked */ +#define SQLITE_LOCKED 6 /* A table in the database is locked */ +#define SQLITE_NOMEM 7 /* A malloc() failed */ +#define SQLITE_READONLY 8 /* Attempt to write a readonly database */ +#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite_interrupt() */ +#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */ +#define SQLITE_CORRUPT 11 /* The database disk image is malformed */ +#define SQLITE_NOTFOUND 12 /* (Internal Only) Table or record not found */ +#define SQLITE_FULL 13 /* Insertion failed because database is full */ +#define SQLITE_CANTOPEN 14 /* Unable to open the database file */ +#define SQLITE_PROTOCOL 15 /* Database lock protocol error */ +#define SQLITE_EMPTY 16 /* (Internal Only) Database table is empty */ +#define SQLITE_SCHEMA 17 /* The database schema changed */ +#define SQLITE_TOOBIG 18 /* Too much data for one row of a table */ +#define SQLITE_CONSTRAINT 19 /* Abort due to contraint violation */ +#define SQLITE_MISMATCH 20 /* Data type mismatch */ +#define SQLITE_MISUSE 21 /* Library used incorrectly */ +#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */ +#define SQLITE_AUTH 23 /* Authorization denied */ +#define SQLITE_FORMAT 24 /* Auxiliary database format error */ +#define SQLITE_ROW 100 /* sqlite_step() has another row ready */ +#define SQLITE_DONE 101 /* sqlite_step() has finished executing */ + +/* +** Each entry in an SQLite table has a unique integer key. (The key is +** the value of the INTEGER PRIMARY KEY column if there is such a column, +** otherwise the key is generated at random. The unique key is always +** available as the ROWID, OID, or _ROWID_ column.) The following routine +** returns the integer key of the most recent insert in the database. +** +** This function is similar to the mysql_insert_id() function from MySQL. +*/ +int sqlite_last_insert_rowid(sqlite*); + +/* +** This function returns the number of database rows that were changed +** (or inserted or deleted) by the most recent called sqlite_exec(). +** +** All changes are counted, even if they were later undone by a +** ROLLBACK or ABORT. Except, changes associated with creating and +** dropping tables are not counted. +** +** If a callback invokes sqlite_exec() recursively, then the changes +** in the inner, recursive call are counted together with the changes +** in the outer call. +** +** SQLite implements the command "DELETE FROM table" without a WHERE clause +** by dropping and recreating the table. (This is much faster than going +** through and deleting individual elements form the table.) Because of +** this optimization, the change count for "DELETE FROM table" will be +** zero regardless of the number of elements that were originally in the +** table. To get an accurate count of the number of rows deleted, use +** "DELETE FROM table WHERE 1" instead. +*/ +int sqlite_changes(sqlite*); + +/* If the parameter to this routine is one of the return value constants +** defined above, then this routine returns a constant text string which +** descripts (in English) the meaning of the return value. +*/ +const char *sqlite_error_string(int); +#define sqliteErrStr sqlite_error_string /* Legacy. Do not use in new code. */ + +/* This function causes any pending database operation to abort and +** return at its earliest opportunity. This routine is typically +** called in response to a user action such as pressing "Cancel" +** or Ctrl-C where the user wants a long query operation to halt +** immediately. +*/ +void sqlite_interrupt(sqlite*); + + +/* This function returns true if the given input string comprises +** one or more complete SQL statements. +** +** The algorithm is simple. If the last token other than spaces +** and comments is a semicolon, then return true. otherwise return +** false. +*/ +int sqlite_complete(const char *sql); + +/* +** This routine identifies a callback function that is invoked +** whenever an attempt is made to open a database table that is +** currently locked by another process or thread. If the busy callback +** is NULL, then sqlite_exec() returns SQLITE_BUSY immediately if +** it finds a locked table. If the busy callback is not NULL, then +** sqlite_exec() invokes the callback with three arguments. The +** second argument is the name of the locked table and the third +** argument is the number of times the table has been busy. If the +** busy callback returns 0, then sqlite_exec() immediately returns +** SQLITE_BUSY. If the callback returns non-zero, then sqlite_exec() +** tries to open the table again and the cycle repeats. +** +** The default busy callback is NULL. +** +** Sqlite is re-entrant, so the busy handler may start a new query. +** (It is not clear why anyone would every want to do this, but it +** is allowed, in theory.) But the busy handler may not close the +** database. Closing the database from a busy handler will delete +** data structures out from under the executing query and will +** probably result in a coredump. +*/ +void sqlite_busy_handler(sqlite*, int(*)(void*,const char*,int), void*); + +/* +** This routine sets a busy handler that sleeps for a while when a +** table is locked. The handler will sleep multiple times until +** at least "ms" milleseconds of sleeping have been done. After +** "ms" milleseconds of sleeping, the handler returns 0 which +** causes sqlite_exec() to return SQLITE_BUSY. +** +** Calling this routine with an argument less than or equal to zero +** turns off all busy handlers. +*/ +void sqlite_busy_timeout(sqlite*, int ms); + +/* +** This next routine is really just a wrapper around sqlite_exec(). +** Instead of invoking a user-supplied callback for each row of the +** result, this routine remembers each row of the result in memory +** obtained from malloc(), then returns all of the result after the +** query has finished. +** +** As an example, suppose the query result where this table: +** +** Name | Age +** ----------------------- +** Alice | 43 +** Bob | 28 +** Cindy | 21 +** +** If the 3rd argument were &azResult then after the function returns +** azResult will contain the following data: +** +** azResult[0] = "Name"; +** azResult[1] = "Age"; +** azResult[2] = "Alice"; +** azResult[3] = "43"; +** azResult[4] = "Bob"; +** azResult[5] = "28"; +** azResult[6] = "Cindy"; +** azResult[7] = "21"; +** +** Notice that there is an extra row of data containing the column +** headers. But the *nrow return value is still 3. *ncolumn is +** set to 2. In general, the number of values inserted into azResult +** will be ((*nrow) + 1)*(*ncolumn). +** +** After the calling function has finished using the result, it should +** pass the result data pointer to sqlite_free_table() in order to +** release the memory that was malloc-ed. Because of the way the +** malloc() happens, the calling function must not try to call +** malloc() directly. Only sqlite_free_table() is able to release +** the memory properly and safely. +** +** The return value of this routine is the same as from sqlite_exec(). +*/ +int sqlite_get_table( + sqlite*, /* An open database */ + const char *sql, /* SQL to be executed */ + char ***resultp, /* Result written to a char *[] that this points to */ + int *nrow, /* Number of result rows written here */ + int *ncolumn, /* Number of result columns written here */ + char **errmsg /* Error msg written here */ +); + +/* +** Call this routine to free the memory that sqlite_get_table() allocated. +*/ +void sqlite_free_table(char **result); + +/* +** The following routines are wrappers around sqlite_exec() and +** sqlite_get_table(). The only difference between the routines that +** follow and the originals is that the second argument to the +** routines that follow is really a printf()-style format +** string describing the SQL to be executed. Arguments to the format +** string appear at the end of the argument list. +** +** All of the usual printf formatting options apply. In addition, there +** is a "%q" option. %q works like %s in that it substitutes a null-terminated +** string from the argument list. But %q also doubles every '\'' character. +** %q is designed for use inside a string literal. By doubling each '\'' +** character it escapes that character and allows it to be inserted into +** the string. +** +** For example, so some string variable contains text as follows: +** +** char *zText = "It's a happy day!"; +** +** We can use this text in an SQL statement as follows: +** +** sqlite_exec_printf(db, "INSERT INTO table VALUES('%q')", +** callback1, 0, 0, zText); +** +** Because the %q format string is used, the '\'' character in zText +** is escaped and the SQL generated is as follows: +** +** INSERT INTO table1 VALUES('It''s a happy day!') +** +** This is correct. Had we used %s instead of %q, the generated SQL +** would have looked like this: +** +** INSERT INTO table1 VALUES('It's a happy day!'); +** +** This second example is an SQL syntax error. As a general rule you +** should always use %q instead of %s when inserting text into a string +** literal. +*/ +int sqlite_exec_printf( + sqlite*, /* An open database */ + const char *sqlFormat, /* printf-style format string for the SQL */ + sqlite_callback, /* Callback function */ + void *, /* 1st argument to callback function */ + char **errmsg, /* Error msg written here */ + ... /* Arguments to the format string. */ +); +int sqlite_exec_vprintf( + sqlite*, /* An open database */ + const char *sqlFormat, /* printf-style format string for the SQL */ + sqlite_callback, /* Callback function */ + void *, /* 1st argument to callback function */ + char **errmsg, /* Error msg written here */ + va_list ap /* Arguments to the format string. */ +); +int sqlite_get_table_printf( + sqlite*, /* An open database */ + const char *sqlFormat, /* printf-style format string for the SQL */ + char ***resultp, /* Result written to a char *[] that this points to */ + int *nrow, /* Number of result rows written here */ + int *ncolumn, /* Number of result columns written here */ + char **errmsg, /* Error msg written here */ + ... /* Arguments to the format string */ +); +int sqlite_get_table_vprintf( + sqlite*, /* An open database */ + const char *sqlFormat, /* printf-style format string for the SQL */ + char ***resultp, /* Result written to a char *[] that this points to */ + int *nrow, /* Number of result rows written here */ + int *ncolumn, /* Number of result columns written here */ + char **errmsg, /* Error msg written here */ + va_list ap /* Arguments to the format string */ +); +char *sqlite_mprintf(const char*,...); +char *sqlite_vmprintf(const char*, va_list); + +/* +** Windows systems should call this routine to free memory that +** is returned in the in the errmsg parameter of sqlite_open() when +** SQLite is a DLL. For some reason, it does not work to call free() +** directly. +*/ +void sqlite_freemem(void *p); + +/* +** Windows systems need functions to call to return the sqlite_version +** and sqlite_encoding strings. +*/ +const char *sqlite_libversion(void); +const char *sqlite_libencoding(void); + +/* +** A pointer to the following structure is used to communicate with +** the implementations of user-defined functions. +*/ +typedef struct sqlite_func sqlite_func; + +/* +** Use the following routines to create new user-defined functions. See +** the documentation for details. +*/ +int sqlite_create_function( + sqlite*, /* Database where the new function is registered */ + const char *zName, /* Name of the new function */ + int nArg, /* Number of arguments. -1 means any number */ + void (*xFunc)(sqlite_func*,int,const char**), /* C code to implement */ + void *pUserData /* Available via the sqlite_user_data() call */ +); +int sqlite_create_aggregate( + sqlite*, /* Database where the new function is registered */ + const char *zName, /* Name of the function */ + int nArg, /* Number of arguments */ + void (*xStep)(sqlite_func*,int,const char**), /* Called for each row */ + void (*xFinalize)(sqlite_func*), /* Called once to get final result */ + void *pUserData /* Available via the sqlite_user_data() call */ +); + +/* +** Use the following routine to define the datatype returned by a +** user-defined function. The second argument can be one of the +** constants SQLITE_NUMERIC, SQLITE_TEXT, or SQLITE_ARGS or it +** can be an integer greater than or equal to zero. The datatype +** will be numeric or text (the only two types supported) if the +** argument is SQLITE_NUMERIC or SQLITE_TEXT. If the argument is +** SQLITE_ARGS, then the datatype is numeric if any argument to the +** function is numeric and is text otherwise. If the second argument +** is an integer, then the datatype of the result is the same as the +** parameter to the function that corresponds to that integer. +*/ +int sqlite_function_type( + sqlite *db, /* The database there the function is registered */ + const char *zName, /* Name of the function */ + int datatype /* The datatype for this function */ +); +#define SQLITE_NUMERIC (-1) +#define SQLITE_TEXT (-2) +#define SQLITE_ARGS (-3) + +/* +** The user function implementations call one of the following four routines +** in order to return their results. The first parameter to each of these +** routines is a copy of the first argument to xFunc() or xFinialize(). +** The second parameter to these routines is the result to be returned. +** A NULL can be passed as the second parameter to sqlite_set_result_string() +** in order to return a NULL result. +** +** The 3rd argument to _string and _error is the number of characters to +** take from the string. If this argument is negative, then all characters +** up to and including the first '\000' are used. +** +** The sqlite_set_result_string() function allocates a buffer to hold the +** result and returns a pointer to this buffer. The calling routine +** (that is, the implmentation of a user function) can alter the content +** of this buffer if desired. +*/ +char *sqlite_set_result_string(sqlite_func*,const char*,int); +void sqlite_set_result_int(sqlite_func*,int); +void sqlite_set_result_double(sqlite_func*,double); +void sqlite_set_result_error(sqlite_func*,const char*,int); + +/* +** The pUserData parameter to the sqlite_create_function() and +** sqlite_create_aggregate() routines used to register user functions +** is available to the implementation of the function using this +** call. +*/ +void *sqlite_user_data(sqlite_func*); + +/* +** Aggregate functions use the following routine to allocate +** a structure for storing their state. The first time this routine +** is called for a particular aggregate, a new structure of size nBytes +** is allocated, zeroed, and returned. On subsequent calls (for the +** same aggregate instance) the same buffer is returned. The implementation +** of the aggregate can use the returned buffer to accumulate data. +** +** The buffer allocated is freed automatically be SQLite. +*/ +void *sqlite_aggregate_context(sqlite_func*, int nBytes); + +/* +** 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. +*/ +int sqlite_aggregate_count(sqlite_func*); + +/* +** This routine registers a callback with the SQLite library. The +** callback is invoked (at compile-time, not at run-time) for each +** attempt to access a column of a table in the database. The callback +** returns SQLITE_OK if access is allowed, SQLITE_DENY if the entire +** SQL statement should be aborted with an error and SQLITE_IGNORE +** if the column should be treated as a NULL value. +*/ +int sqlite_set_authorizer( + sqlite*, + int (*xAuth)(void*,int,const char*,const char*,const char*,const char*), + void *pUserData +); + +/* +** The second parameter to the access authorization function above will +** be one of the values below. These values signify what kind of operation +** is to be authorized. The 3rd and 4th parameters to the authorization +** function will be parameters or NULL depending on which of the following +** codes is used as the second parameter. The 5th parameter is the name +** of the database ("main", "temp", etc.) if applicable. The 6th parameter +** is the name of the inner-most trigger or view that is responsible for +** the access attempt or NULL if this access attempt is directly from +** input SQL code. +** +** Arg-3 Arg-4 +*/ +#define SQLITE_COPY 0 /* Table Name File Name */ +#define SQLITE_CREATE_INDEX 1 /* Index Name Table Name */ +#define SQLITE_CREATE_TABLE 2 /* Table Name NULL */ +#define SQLITE_CREATE_TEMP_INDEX 3 /* Index Name Table Name */ +#define SQLITE_CREATE_TEMP_TABLE 4 /* Table Name NULL */ +#define SQLITE_CREATE_TEMP_TRIGGER 5 /* Trigger Name Table Name */ +#define SQLITE_CREATE_TEMP_VIEW 6 /* View Name NULL */ +#define SQLITE_CREATE_TRIGGER 7 /* Trigger Name Table Name */ +#define SQLITE_CREATE_VIEW 8 /* View Name NULL */ +#define SQLITE_DELETE 9 /* Table Name NULL */ +#define SQLITE_DROP_INDEX 10 /* Index Name Table Name */ +#define SQLITE_DROP_TABLE 11 /* Table Name NULL */ +#define SQLITE_DROP_TEMP_INDEX 12 /* Index Name Table Name */ +#define SQLITE_DROP_TEMP_TABLE 13 /* Table Name NULL */ +#define SQLITE_DROP_TEMP_TRIGGER 14 /* Trigger Name Table Name */ +#define SQLITE_DROP_TEMP_VIEW 15 /* View Name NULL */ +#define SQLITE_DROP_TRIGGER 16 /* Trigger Name Table Name */ +#define SQLITE_DROP_VIEW 17 /* View Name NULL */ +#define SQLITE_INSERT 18 /* Table Name NULL */ +#define SQLITE_PRAGMA 19 /* Pragma Name 1st arg or NULL */ +#define SQLITE_READ 20 /* Table Name Column Name */ +#define SQLITE_SELECT 21 /* NULL NULL */ +#define SQLITE_TRANSACTION 22 /* NULL NULL */ +#define SQLITE_UPDATE 23 /* Table Name Column Name */ +#define SQLITE_ATTACH 24 /* Filename NULL */ +#define SQLITE_DETACH 25 /* Database Name NULL */ + + +/* +** The return value of the authorization function should be one of the +** following constants: +*/ +/* #define SQLITE_OK 0 // Allow access (This is actually defined above) */ +#define SQLITE_DENY 1 /* Abort the SQL statement with an error */ +#define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */ + +/* +** Register a function that is called at every invocation of sqlite_exec() +** or sqlite_compile(). This function can be used (for example) to generate +** a log file of all SQL executed against a database. +*/ +void *sqlite_trace(sqlite*, void(*xTrace)(void*,const char*), void*); + +/*** The Callback-Free API +** +** The following routines implement a new way to access SQLite that does not +** involve the use of callbacks. +** +** An sqlite_vm is an opaque object that represents a single SQL statement +** that is ready to be executed. +*/ +typedef struct sqlite_vm sqlite_vm; + +/* +** To execute an SQLite query without the use of callbacks, you first have +** to compile the SQL using this routine. The 1st parameter "db" is a pointer +** to an sqlite object obtained from sqlite_open(). The 2nd parameter +** "zSql" is the text of the SQL to be compiled. The remaining parameters +** are all outputs. +** +** *pzTail is made to point to the first character past the end of the first +** SQL statement in zSql. This routine only compiles the first statement +** in zSql, so *pzTail is left pointing to what remains uncompiled. +** +** *ppVm is left pointing to a "virtual machine" that can be used to execute +** the compiled statement. Or if there is an error, *ppVm may be set to NULL. +** If the input text contained no SQL (if the input is and empty string or +** a comment) then *ppVm is set to NULL. +** +** If any errors are detected during compilation, an error message is written +** into space obtained from malloc() and *pzErrMsg is made to point to that +** error message. The calling routine is responsible for freeing the text +** of this message when it has finished with it. Use sqlite_freemem() to +** free the message. pzErrMsg may be NULL in which case no error message +** will be generated. +** +** On success, SQLITE_OK is returned. Otherwise and error code is returned. +*/ +int sqlite_compile( + sqlite *db, /* The open database */ + const char *zSql, /* SQL statement to be compiled */ + const char **pzTail, /* OUT: uncompiled tail of zSql */ + sqlite_vm **ppVm, /* OUT: the virtual machine to execute zSql */ + char **pzErrmsg /* OUT: Error message. */ +); + +/* +** After an SQL statement has been compiled, it is handed to this routine +** to be executed. This routine executes the statement as far as it can +** go then returns. The return value will be one of SQLITE_DONE, +** SQLITE_ERROR, SQLITE_BUSY, SQLITE_ROW, or SQLITE_MISUSE. +** +** SQLITE_DONE means that the execute of the SQL statement is complete +** an no errors have occurred. sqlite_step() should not be called again +** for the same virtual machine. *pN is set to the number of columns in +** the result set and *pazColName is set to an array of strings that +** describe the column names and datatypes. The name of the i-th column +** is (*pazColName)[i] and the datatype of the i-th column is +** (*pazColName)[i+*pN]. *pazValue is set to NULL. +** +** SQLITE_ERROR means that the virtual machine encountered a run-time +** error. sqlite_step() should not be called again for the same +** virtual machine. *pN is set to 0 and *pazColName and *pazValue are set +** to NULL. Use sqlite_finalize() to obtain the specific error code +** and the error message text for the error. +** +** SQLITE_BUSY means that an attempt to open the database failed because +** another thread or process is holding a lock. The calling routine +** can try again to open the database by calling sqlite_step() again. +** The return code will only be SQLITE_BUSY if no busy handler is registered +** using the sqlite_busy_handler() or sqlite_busy_timeout() routines. If +** a busy handler callback has been registered but returns 0, then this +** routine will return SQLITE_ERROR and sqltie_finalize() will return +** SQLITE_BUSY when it is called. +** +** SQLITE_ROW means that a single row of the result is now available. +** The data is contained in *pazValue. The value of the i-th column is +** (*azValue)[i]. *pN and *pazColName are set as described in SQLITE_DONE. +** Invoke sqlite_step() again to advance to the next row. +** +** SQLITE_MISUSE is returned if sqlite_step() is called incorrectly. +** For example, if you call sqlite_step() after the virtual machine +** has halted (after a prior call to sqlite_step() has returned SQLITE_DONE) +** or if you call sqlite_step() with an incorrectly initialized virtual +** machine or a virtual machine that has been deleted or that is associated +** with an sqlite structure that has been closed. +*/ +int sqlite_step( + sqlite_vm *pVm, /* The virtual machine to execute */ + int *pN, /* OUT: Number of columns in result */ + const char ***pazValue, /* OUT: Column data */ + const char ***pazColName /* OUT: Column names and datatypes */ +); + +/* +** This routine is called to delete a virtual machine after it has finished +** executing. The return value is the result code. SQLITE_OK is returned +** if the statement executed successfully and some other value is returned if +** there was any kind of error. If an error occurred and pzErrMsg is not +** NULL, then an error message is written into memory obtained from malloc() +** and *pzErrMsg is made to point to that error message. The calling routine +** should use sqlite_freemem() to delete this message when it has finished +** with it. +** +** This routine can be called at any point during the execution of the +** virtual machine. If the virtual machine has not completed execution +** when this routine is called, that is like encountering an error or +** an interrupt. (See sqlite_interrupt().) Incomplete updates may be +** rolled back and transactions cancelled, depending on the circumstances, +** and the result code returned will be SQLITE_ABORT. +*/ +int sqlite_finalize(sqlite_vm*, char **pzErrMsg); + +/* +** This routine deletes the virtual machine, writes any error message to +** *pzErrMsg and returns an SQLite return code in the same way as the +** sqlite_finalize() function. +** +** Additionally, if ppVm is not NULL, *ppVm is left pointing to a new virtual +** machine loaded with the compiled version of the original query ready for +** execution. +** +** If sqlite_reset() returns SQLITE_SCHEMA, then *ppVm is set to NULL. +** +******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ****** +*/ +int sqlite_reset(sqlite_vm *, char **pzErrMsg, sqlite_vm **ppVm); + +#ifdef __cplusplus +} /* End of the 'extern "C"' block */ +#endif + +#endif /* _SQLITE_H_ */ diff --git a/sqlitebrowser/sqlitebrowser/sqlite_source/sqliteInt.h b/sqlitebrowser/sqlitebrowser/sqlite_source/sqliteInt.h new file mode 100755 index 00000000..eb6a207d --- /dev/null +++ b/sqlitebrowser/sqlitebrowser/sqlite_source/sqliteInt.h @@ -0,0 +1,1195 @@ +/* +** 2001 September 15 +** +** 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. +** +************************************************************************* +** Internal interface definitions for SQLite. +** +** @(#) $Id: sqliteInt.h,v 1.1.1.1 2003-08-21 02:24:21 tabuleiro Exp $ +*/ +#include "config.h" +#include "sqlite.h" +#include "hash.h" +#include "vdbe.h" +#include "parse.h" +#include "btree.h" +#include +#include +#include +#include + +/* +** The maximum number of in-memory pages to use for the main database +** table and for temporary tables. +*/ +#define MAX_PAGES 2000 +#define TEMP_PAGES 500 + +/* +** If the following macro is set to 1, then NULL values are considered +** distinct for the SELECT DISTINCT statement and for UNION or EXCEPT +** compound queries. No other SQL database engine (among those tested) +** works this way except for OCELOT. But the SQL92 spec implies that +** this is how things should work. +** +** If the following macro is set to 0, then NULLs are indistinct for +** SELECT DISTINCT and for UNION. +*/ +#define NULL_ALWAYS_DISTINCT 0 + +/* +** If the following macro is set to 1, then NULL values are considered +** distinct when determining whether or not two entries are the same +** in a UNIQUE index. This is the way PostgreSQL, Oracle, DB2, MySQL, +** OCELOT, and Firebird all work. The SQL92 spec explicitly says this +** is the way things are suppose to work. +** +** If the following macro is set to 0, the NULLs are indistinct for +** a UNIQUE index. In this mode, you can only have a single NULL entry +** for a column declared UNIQUE. This is the way Informix and SQL Server +** work. +*/ +#define NULL_DISTINCT_FOR_UNIQUE 1 + +/* +** The maximum number of attached databases. This must be at least 2 +** in order to support the main database file (0) and the file used to +** hold temporary tables (1). And it must be less than 256 because +** an unsigned character is used to stored the database index. +*/ +#define MAX_ATTACHED 10 + +/* +** The next macro is used to determine where TEMP tables and indices +** are stored. Possible values: +** +** 0 Always use a temporary files +** 1 Use a file unless overridden by "PRAGMA temp_store" +** 2 Use memory unless overridden by "PRAGMA temp_store" +** 3 Always use memory +*/ +#ifndef TEMP_STORE +# define TEMP_STORE 2 +#endif + +#ifndef NDEBUG +# define NDEBUG 1 +#endif + +/* +** 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. +*/ +#define SQLITE_OMIT_AUTHORIZATION 1 +/* #define SQLITE_OMIT_INMEMORYDB 1 */ +/* #define SQLITE_OMIT_VACUUM 1 */ + +/* +** Integers of known sizes. These typedefs might change for architectures +** where the sizes very. Preprocessor macros are available so that the +** types can be conveniently redefined at compile-type. Like this: +** +** cc '-DUINTPTR_TYPE=long long int' ... +*/ +#ifndef UINT32_TYPE +# define UINT32_TYPE unsigned int +#endif +#ifndef UINT16_TYPE +# define UINT16_TYPE unsigned short int +#endif +#ifndef UINT8_TYPE +# define UINT8_TYPE unsigned char +#endif +#ifndef INTPTR_TYPE +# if SQLITE_PTR_SZ==4 +# define INTPTR_TYPE int +# else +# define INTPTR_TYPE long long +# endif +#endif +typedef UINT32_TYPE u32; /* 4-byte unsigned integer */ +typedef UINT16_TYPE u16; /* 2-byte unsigned integer */ +typedef UINT8_TYPE u8; /* 1-byte unsigned integer */ +typedef INTPTR_TYPE ptr; /* Big enough to hold a pointer */ +typedef unsigned INTPTR_TYPE uptr; /* Big enough to hold a pointer */ + +/* +** This macro casts a pointer to an integer. Useful for doing +** pointer arithmetic. +*/ +#define Addr(X) ((uptr)X) + +/* +** The maximum number of bytes of data that can be put into a single +** row of a single table. The upper bound on this limit is 16777215 +** bytes (or 16MB-1). We have arbitrarily set the limit to just 1MB +** here because the overflow page chain is inefficient for really big +** records and we want to discourage people from thinking that +** multi-megabyte records are OK. If your needs are different, you can +** change this define and recompile to increase or decrease the record +** size. +** +** The 16777198 is computed as follows: 238 bytes of payload on the +** original pages plus 16448 overflow pages each holding 1020 bytes of +** data. +*/ +/*#define MAX_BYTES_PER_ROW 1048576*/ +#define MAX_BYTES_PER_ROW 16777198 + +/* +** If memory allocation problems are found, recompile with +** +** -DMEMORY_DEBUG=1 +** +** to enable some sanity checking on malloc() and free(). To +** check for memory leaks, recompile with +** +** -DMEMORY_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 MEMORY_DEBUG +# define sqliteMalloc(X) sqliteMalloc_(X,1,__FILE__,__LINE__) +# define sqliteMallocRaw(X) sqliteMalloc_(X,0,__FILE__,__LINE__) +# define sqliteFree(X) sqliteFree_(X,__FILE__,__LINE__) +# define sqliteRealloc(X,Y) sqliteRealloc_(X,Y,__FILE__,__LINE__) +# define sqliteStrDup(X) sqliteStrDup_(X,__FILE__,__LINE__) +# define sqliteStrNDup(X,Y) sqliteStrNDup_(X,Y,__FILE__,__LINE__) + void sqliteStrRealloc(char**); +#else +# define sqliteStrRealloc(X) +#endif + +/* +** This variable gets set if malloc() ever fails. After it gets set, +** the SQLite library shuts down permanently. +*/ +extern int sqlite_malloc_failed; + +/* +** The following global variables are used for testing and debugging +** only. They only work if MEMORY_DEBUG is defined. +*/ +#ifdef MEMORY_DEBUG +extern int sqlite_nMalloc; /* Number of sqliteMalloc() calls */ +extern int sqlite_nFree; /* Number of sqliteFree() calls */ +extern int sqlite_iMallocFail; /* Fail sqliteMalloc() after this many calls */ +#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. +*/ +#define MASTER_NAME "sqlite_master" +#define TEMP_MASTER_NAME "sqlite_temp_master" + +/* +** The name of the schema table. +*/ +#define SCHEMA_TABLE(x) (x?TEMP_MASTER_NAME:MASTER_NAME) + +/* +** A convenience macro that returns the number of elements in +** an array. +*/ +#define ArraySize(X) (sizeof(X)/sizeof(X[0])) + +/* +** Forward references to structures +*/ +typedef struct Column Column; +typedef struct Table Table; +typedef struct Index Index; +typedef struct Instruction Instruction; +typedef struct Expr Expr; +typedef struct ExprList ExprList; +typedef struct Parse Parse; +typedef struct Token Token; +typedef struct IdList IdList; +typedef struct SrcList SrcList; +typedef struct WhereInfo WhereInfo; +typedef struct WhereLevel WhereLevel; +typedef struct Select Select; +typedef struct AggExpr AggExpr; +typedef struct FuncDef FuncDef; +typedef struct Trigger Trigger; +typedef struct TriggerStep TriggerStep; +typedef struct TriggerStack TriggerStack; +typedef struct FKey FKey; +typedef struct Db Db; +typedef struct AuthContext AuthContext; + +/* +** Each database file to be accessed by the system is an instance +** of the following structure. There are normally two of these structures +** in the sqlite.aDb[] array. aDb[0] is the main database file and +** aDb[1] is the database file used to hold temporary tables. Additional +** databases may be attached. +*/ +struct Db { + char *zName; /* Name of this database */ + Btree *pBt; /* The B*Tree structure for this database file */ + 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 */ + u8 inTrans; /* 0: not writable. 1: Transaction. 2: Checkpoint */ + u16 flags; /* Flags associated with this database */ +}; + +/* +** 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) + +/* +** Allowed values for the DB.flags field. +** +** The DB_Locked flag is set when the first OP_Transaction or OP_Checkpoint +** opcode is emitted for a database. This prevents multiple occurances +** of those opcodes for the same database in the same program. Similarly, +** the DB_Cookie flag is set when the OP_VerifyCookie opcode is emitted, +** and prevents duplicate OP_VerifyCookies from taking up space and slowing +** down execution. +** +** The DB_SchemaLoaded flag is set after the database schema has been +** read into internal hash tables. +** +** DB_UnresetViews means that one or more views have column names that +** have been filled out. If the schema changes, these column names might +** changes and so the view will need to be reset. +*/ +#define DB_Locked 0x0001 /* OP_Transaction opcode has been emitted */ +#define DB_Cookie 0x0002 /* OP_VerifyCookie opcode has been emiited */ +#define DB_SchemaLoaded 0x0004 /* The schema has been loaded */ +#define DB_UnresetViews 0x0008 /* Some views have defined column names */ + + +/* +** Each database is an instance of the following structure. +** +** The sqlite.file_format is initialized by the database file +** and helps determines how the data in the database file is +** represented. This field allows newer versions of the library +** to read and write older databases. The various file formats +** are as follows: +** +** file_format==1 Version 2.1.0. +** file_format==2 Version 2.2.0. Add support for INTEGER PRIMARY KEY. +** file_format==3 Version 2.6.0. Fix empty-string index bug. +** file_format==4 Version 2.7.0. Add support for separate numeric and +** text datatypes. +** +** The sqlite.temp_store determines where temporary database files +** are stored. If 1, then a file is created to hold those tables. If +** 2, then they are held in memory. 0 means use the default value in +** the TEMP_STORE macro. +*/ +struct sqlite { + int nDb; /* Number of backends currently in use */ + Db *aDb; /* All backends */ + Db aDbStatic[2]; /* Static space for the 2 default backends */ + int flags; /* Miscellanous flags. See below */ + u8 file_format; /* What file format version is this database? */ + u8 safety_level; /* How aggressive at synching data to disk */ + u8 want_to_close; /* Close after all VDBEs are deallocated */ + int next_cookie; /* Next value of aDb[0].schema_cookie */ + int cache_size; /* Number of pages to use in the cache */ + int temp_store; /* 1=file, 2=memory, 0=compile-time default */ + int nTable; /* Number of tables in the database */ + void *pBusyArg; /* 1st Argument to the busy callback */ + int (*xBusyCallback)(void *,const char*,int); /* The busy callback */ + Hash aFunc; /* All functions that can be in SQL exprs */ + int lastRowid; /* ROWID of most recent insert */ + int priorNewRowid; /* Last randomly generated ROWID */ + int onError; /* Default conflict algorithm */ + int magic; /* Magic number for detect library misuse */ + int nChange; /* Number of rows changed */ + struct Vdbe *pVdbe; /* List of active virtual machines */ + void (*xTrace)(void*,const char*); /* Trace function */ + void *pTraceArg; /* Argument to the trace function */ +#ifndef SQLITE_OMIT_AUTHORIZATION + int (*xAuth)(void*,int,const char*,const char*,const char*,const char*); + /* Access authorization function */ + void *pAuthArg; /* 1st argument to the access auth function */ +#endif +}; + +/* +** Possible values for the sqlite.flags and or Db.flags fields. +** +** On sqlite.flags, the SQLITE_InTrans value means that we have +** executed a BEGIN. On Db.flags, SQLITE_InTrans means a statement +** 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 */ +#define SQLITE_FullColNames 0x00000020 /* Show full column names on SELECT */ +#define SQLITE_CountRows 0x00000040 /* Count rows changed by INSERT, */ + /* DELETE, or UPDATE and return */ + /* the count using a callback. */ +#define SQLITE_NullCallback 0x00000080 /* Invoke the callback once if the */ + /* result set is empty */ +#define SQLITE_ReportTypes 0x00000200 /* Include information on datatypes */ + /* in 4th argument of callback */ + +/* +** Possible values for the sqlite.magic field. +** The numbers are obtained at random and have no special meaning, other +** than being distinct from one another. +*/ +#define SQLITE_MAGIC_OPEN 0xa029a697 /* Database is open */ +#define SQLITE_MAGIC_CLOSED 0x9f3c2d33 /* Database is closed */ +#define SQLITE_MAGIC_BUSY 0xf03b7906 /* Database currently in use */ +#define SQLITE_MAGIC_ERROR 0xb5357930 /* An SQLITE_MISUSE error occurred */ + +/* +** Each SQL function is defined by an instance of the following +** structure. A pointer to this structure is stored in the sqlite.aFunc +** hash table. When multiple functions have the same name, the hash table +** points to a linked list of these structures. +*/ +struct FuncDef { + void (*xFunc)(sqlite_func*,int,const char**); /* Regular function */ + void (*xStep)(sqlite_func*,int,const char**); /* Aggregate function step */ + void (*xFinalize)(sqlite_func*); /* Aggregate function finializer */ + int nArg; /* Number of arguments */ + int dataType; /* Datatype of the result */ + void *pUserData; /* User data parameter */ + FuncDef *pNext; /* Next function with same name */ +}; + +/* +** information about each column of an SQL table is held in an instance +** of this structure. +*/ +struct Column { + char *zName; /* Name of this column */ + char *zDflt; /* Default value of this column */ + char *zType; /* Data type for this column */ + u8 notNull; /* True if there is a NOT NULL constraint */ + u8 isPrimKey; /* True if this column is an INTEGER PRIMARY KEY */ + u8 sortOrder; /* Some combination of SQLITE_SO_... values */ +}; + +/* +** The allowed sort orders. +** +** The TEXT and NUM values use bits that do not overlap with DESC and ASC. +** That way the two can be combined into a single number. +*/ +#define SQLITE_SO_UNK 0 /* Use the default collating type. (SCT_NUM) */ +#define SQLITE_SO_TEXT 2 /* Sort using memcmp() */ +#define SQLITE_SO_NUM 4 /* Sort using sqliteCompare() */ +#define SQLITE_SO_TYPEMASK 6 /* Mask to extract the collating sequence */ +#define SQLITE_SO_ASC 0 /* Sort in ascending order */ +#define SQLITE_SO_DESC 1 /* Sort in descending order */ +#define SQLITE_SO_DIRMASK 1 /* Mask to extract the sort direction */ + +/* +** Each SQL table is represented in memory by an instance of the +** following structure. +** +** Table.zName is the name of the table. The case of the original +** CREATE TABLE statement is stored, but case is not significant for +** comparisons. +** +** Table.nCol is the number of columns in this table. Table.aCol is a +** pointer to an array of Column structures, one for each column. +** +** If the table has an INTEGER PRIMARY KEY, then Table.iPKey is the index of +** the column that is that key. Otherwise Table.iPKey is negative. Note +** that the datatype of the PRIMARY KEY must be INTEGER for this field to +** be set. An INTEGER PRIMARY KEY is used as the rowid for each row of +** the table. If a table has no INTEGER PRIMARY KEY, then a random rowid +** is generated for each row of the table. Table.hasPrimKey is true if +** the table has any PRIMARY KEY, INTEGER or otherwise. +** +** Table.tnum is the page number for the root BTree page of the table in the +** database file. If Table.iDb is the index of the database table backend +** in sqlite.aDb[]. 0 is for the main database and 1 is for the file that +** holds temporary tables and indices. If Table.isTransient +** is true, then the table is stored in a file that is automatically deleted +** when the VDBE cursor to the table is closed. In this case Table.tnum +** refers VDBE cursor number that holds the table open, not to the root +** page number. Transient tables are used to hold the results of a +** sub-query that appears instead of a real table name in the FROM clause +** of a SELECT statement. +*/ +struct Table { + char *zName; /* Name of the table */ + int nCol; /* Number of columns in this table */ + Column *aCol; /* Information about each column */ + int iPKey; /* If not less then 0, use aCol[iPKey] as the primary key */ + Index *pIndex; /* List of SQL indexes on this table. */ + 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 */ + Trigger *pTrigger; /* List of SQL triggers on this table */ + FKey *pFKey; /* Linked list of all foreign keys in this table */ +}; + +/* +** Each foreign key constraint is an instance of the following structure. +** +** A foreign key is associated with two tables. The "from" table is +** the table that contains the REFERENCES clause that creates the foreign +** key. The "to" table is the table that is named in the REFERENCES clause. +** Consider this example: +** +** CREATE TABLE ex1( +** a INTEGER PRIMARY KEY, +** b INTEGER CONSTRAINT fk1 REFERENCES ex2(x) +** ); +** +** For foreign key "fk1", the from-table is "ex1" and the to-table is "ex2". +** +** Each REFERENCES clause generates an instance of the following structure +** which is attached to the from-table. The to-table need not exist when +** the from-table is created. The existance of the to-table is not checked +** until an attempt is made to insert data into the from-table. +** +** The sqlite.aFKey hash table stores pointers to this structure +** given the name of a to-table. For each to-table, all foreign keys +** associated with that table are on a linked list using the FKey.pNextTo +** field. +*/ +struct FKey { + Table *pFrom; /* The table that constains the REFERENCES clause */ + FKey *pNextFrom; /* Next foreign key in pFrom */ + char *zTo; /* Name of table that the key points to */ + FKey *pNextTo; /* Next foreign key that points to zTo */ + int nCol; /* Number of columns in this key */ + struct sColMap { /* Mapping of columns in pFrom to columns in zTo */ + int iFrom; /* Index of column in pFrom */ + char *zCol; /* Name of column in zTo. If 0 use PRIMARY KEY */ + } *aCol; /* One entry for each of nCol column s */ + u8 isDeferred; /* True if constraint checking is deferred till COMMIT */ + u8 updateConf; /* How to resolve conflicts that occur on UPDATE */ + u8 deleteConf; /* How to resolve conflicts that occur on DELETE */ + u8 insertConf; /* How to resolve conflicts that occur on INSERT */ +}; + +/* +** SQLite supports many different ways to resolve a contraint +** error. ROLLBACK processing means that a constraint violation +** causes the operation in process to fail and for the current transaction +** to be rolled back. ABORT processing means the operation in process +** fails and any prior changes from that one operation are backed out, +** but the transaction is not rolled back. FAIL processing means that +** the operation in progress stops and returns an error code. But prior +** changes due to the same operation are not backed out and no rollback +** occurs. IGNORE means that the particular row that caused the constraint +** error is not inserted or updated. Processing continues and no error +** is returned. REPLACE means that preexisting database rows that caused +** a UNIQUE constraint violation are removed so that the new insert or +** update can proceed. Processing continues and no error is reported. +** +** RESTRICT, SETNULL, and CASCADE actions apply only to foreign keys. +** RESTRICT is the same as ABORT for IMMEDIATE foreign keys and the +** same as ROLLBACK for DEFERRED keys. SETNULL means that the foreign +** key is set to NULL. CASCADE means that a DELETE or UPDATE of the +** referenced table row is propagated into the row that holds the +** foreign key. +** +** The following symbolic values are used to record which type +** of action to take. +*/ +#define OE_None 0 /* There is no constraint to check */ +#define OE_Rollback 1 /* Fail the operation and rollback the transaction */ +#define OE_Abort 2 /* Back out changes but do no rollback transaction */ +#define OE_Fail 3 /* Stop the operation but leave all prior changes */ +#define OE_Ignore 4 /* Ignore the error. Do not do the INSERT or UPDATE */ +#define OE_Replace 5 /* Delete existing record, then do INSERT or UPDATE */ + +#define OE_Restrict 6 /* OE_Abort for IMMEDIATE, OE_Rollback for DEFERRED */ +#define OE_SetNull 7 /* Set the foreign key value to NULL */ +#define OE_SetDflt 8 /* Set the foreign key value to its default */ +#define OE_Cascade 9 /* Cascade the changes */ + +#define OE_Default 99 /* Do whatever the default action is */ + +/* +** Each SQL index is represented in memory by an +** instance of the following structure. +** +** The columns of the table that are to be indexed are described +** by the aiColumn[] field of this structure. For example, suppose +** we have the following table and index: +** +** CREATE TABLE Ex1(c1 int, c2 int, c3 text); +** CREATE INDEX Ex2 ON Ex1(c3,c1); +** +** In the Table structure describing Ex1, nCol==3 because there are +** three columns in the table. In the Index structure describing +** Ex2, nColumn==2 since 2 of the 3 columns of Ex1 are indexed. +** The value of aiColumn is {2, 0}. aiColumn[0]==2 because the +** first column to be indexed (c3) has an index of 2 in Ex1.aCol[]. +** The second column to be indexed (c1) has an index of 0 in +** Ex1.aCol[], hence Ex2.aiColumn[1]==0. +** +** The Index.onError field determines whether or not the indexed columns +** must be unique and what to do if they are not. When Index.onError=OE_None, +** it means this is not a unique index. Otherwise it is a unique index +** and the value of Index.onError indicate the which conflict resolution +** algorithm to employ whenever an attempt is made to insert a non-unique +** element. +*/ +struct Index { + char *zName; /* Name of this index */ + int nColumn; /* Number of columns in the table used by this index */ + int *aiColumn; /* Which columns are used by this index. 1st is 0 */ + Table *pTable; /* The SQL table being indexed */ + 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 */ + Index *pNext; /* The next index associated with the same table */ +}; + +/* +** Each token coming out of the lexer is an instance of +** this structure. Tokens are also used as part of an expression. +*/ +struct Token { + const char *z; /* Text of the token. Not NULL-terminated! */ + unsigned dyn : 1; /* True for malloced memory, false for static */ + unsigned n : 31; /* Number of characters in this token */ +}; + +/* +** Each node of an expression in the parse tree is an instance +** of this structure. +** +** Expr.op is the opcode. The integer parser token codes are reused +** as opcodes here. For example, the parser defines TK_GE to be an integer +** code representing the ">=" operator. This same integer code is reused +** to represent the greater-than-or-equal-to operator in the expression +** tree. +** +** Expr.pRight and Expr.pLeft are subexpressions. Expr.pList is a list +** of argument if the expression is a function. +** +** Expr.token is the operator token for this node. For some expressions +** that have subexpressions, Expr.token can be the complete text that gave +** rise to the Expr. In the latter case, the token is marked as being +** a compound token. +** +** An expression of the form ID or ID.ID refers to a column in a table. +** For such expressions, Expr.op is set to TK_COLUMN and Expr.iTable is +** the integer cursor number of a VDBE cursor pointing to that table and +** Expr.iColumn is the column number for the specific column. If the +** expression is used as a result in an aggregate SELECT, then the +** value is also stored in the Expr.iAgg column in the aggregate so that +** it can be accessed after all aggregates are computed. +** +** If the expression is a function, the Expr.iTable is an integer code +** representing which function. +** +** The Expr.pSelect field points to a SELECT statement. The SELECT might +** be the right operand of an IN operator. Or, if a scalar SELECT appears +** in an expression the opcode is TK_SELECT and Expr.pSelect is the only +** operand. +*/ +struct Expr { + u8 op; /* Operation performed by this node */ + u8 dataType; /* Either SQLITE_SO_TEXT or SQLITE_SO_NUM */ + u8 iDb; /* Database referenced by this expression */ + u8 flags; /* Various flags. See below */ + Expr *pLeft, *pRight; /* Left and right subnodes */ + ExprList *pList; /* A list of expressions used as function arguments + ** or in " IN (useAgg==TRUE, pull + ** result from the iAgg-th element of the aggregator */ + Select *pSelect; /* When the expression is a sub-select. Also the + ** right side of " IN (