[libgda] Merged GTK3 branch into master



commit 667c1901bb4d709938c467d79feced6b2dac44df
Author: Vivien Malerba <malerba gnome-db org>
Date:   Tue Mar 15 19:11:37 2011 +0100

    Merged GTK3 branch into master

 NEWS                                               |   12 +
 README                                             |    2 +-
 configure.ac                                       |   93 +-
 control-center/.gitignore                          |    4 +-
 control-center/Makefile.am                         |   21 +-
 control-center/cc-gray-bar.c                       |  122 +-
 control-center/cc-gray-bar.h                       |   18 +-
 control-center/cc-utility.c                        |    4 +-
 control-center/cc-utility.h                        |    4 +-
 control-center/data/Makefile.am                    |   10 +-
 control-center/dsn-config.c                        |   60 +-
 control-center/dsn-config.h                        |    2 +-
 control-center/dsn-properties-dialog.c             |   53 +-
 control-center/dsn-properties-dialog.h             |    2 +-
 ...esktop.in => gda-control-center-5.0.desktop.in} |    2 +-
 control-center/gdaui-dsn-assistant.c               |    4 +-
 control-center/gdaui-dsn-assistant.h               |    4 +-
 control-center/gdaui-dsn-editor.c                  |    8 +-
 control-center/gdaui-dsn-editor.h                  |    4 +-
 control-center/gdaui-login-dialog.c                |   12 +-
 control-center/gdaui-login-dialog.h                |    4 +-
 control-center/main.c                              |   88 +-
 control-center/provider-config.c                   |   47 +-
 control-center/provider-config.h                   |    2 +-
 data/Makefile.am                                   |    2 +-
 doc/C/.gitignore                                   |   34 +-
 doc/C/Makefile.am                                  |   18 +-
 doc/C/data_select.xml                              |    3 +
 doc/C/data_validation.xml                          |    5 +
 doc/C/examples/blobtest.c                          |    5 +
 doc/C/examples/full_example.c                      |   13 +-
 doc/C/fdl-appendix.sgml                            |    7 +-
 doc/C/gda-sql-manual.xml                           |   10 +-
 doc/C/gettingstarted.xml                           |   15 +-
 doc/C/howto.xml                                    |    7 +-
 doc/C/installation.xml                             |   17 +-
 .../{libgda-4.0-docs.sgml => libgda-5.0-docs.sgml} |  505 +-
 doc/C/libgda-sections.txt                          |   36 +-
 doc/C/libgda.types.in                              |    3 +-
 doc/C/limitations.xml                              |    5 +
 doc/C/migration.xml                                |    3 +
 doc/C/migration2.xml                               |    7 +-
 doc/C/packaging.xml                                |   85 +-
 doc/C/packaging_ui.xml                             |   41 +-
 doc/C/prov-notes.xml                               |    3 +
 doc/C/prov-writing-assembly.xml                    |  110 +
 doc/C/prov-writing-blobs.xml                       |   87 +
 doc/C/prov-writing-parser.xml                      |  147 +
 doc/C/prov-writing-recordsets.xml                  |   96 +
 doc/C/prov-writing-virtual-methods.xml             |  596 ++
 doc/C/prov-writing.xml                             | 1016 ---
 doc/C/server-operation.xml                         |    5 +
 doc/C/tmpl/.gitignore                              |   93 -
 doc/C/tmpl/gda-attributes-manager.sgml             |  194 -
 doc/C/tmpl/gda-batch.sgml                          |  115 -
 doc/C/tmpl/gda-blob-op.sgml                        |  148 -
 doc/C/tmpl/gda-column.sgml                         |  179 -
 doc/C/tmpl/gda-config.sgml                         |  262 -
 doc/C/tmpl/gda-connection-event.sgml               |  128 -
 doc/C/tmpl/gda-connection.sgml                     |  806 --
 doc/C/tmpl/gda-convenient.sgml                     |  191 -
 doc/C/tmpl/gda-data-access-wrapper.sgml            |   60 -
 doc/C/tmpl/gda-data-comparator.sgml                |  131 -
 doc/C/tmpl/gda-data-handler.sgml                   |  122 -
 doc/C/tmpl/gda-data-model-array.sgml               |  118 -
 doc/C/tmpl/gda-data-model-bdb.sgml                 |   95 -
 doc/C/tmpl/gda-data-model-dir.sgml                 |   90 -
 doc/C/tmpl/gda-data-model-hash.sgml                |   80 -
 doc/C/tmpl/gda-data-model-import.sgml              |  142 -
 doc/C/tmpl/gda-data-model-iter.sgml                |  203 -
 doc/C/tmpl/gda-data-model.sgml                     |  514 --
 doc/C/tmpl/gda-data-proxy.sgml                     |  512 --
 doc/C/tmpl/gda-data-select-priv.sgml               |  220 -
 doc/C/tmpl/gda-data-select.sgml                    |  199 -
 doc/C/tmpl/gda-enum-types.sgml                     |  904 --
 doc/C/tmpl/gda-export.sgml                         |   16 -
 doc/C/tmpl/gda-field.sgml                          |  323 -
 doc/C/tmpl/gda-handler-bin.sgml                    |   52 -
 doc/C/tmpl/gda-handler-boolean.sgml                |   52 -
 doc/C/tmpl/gda-handler-numerical.sgml              |   52 -
 doc/C/tmpl/gda-handler-string.sgml                 |   62 -
 doc/C/tmpl/gda-handler-time.sgml                   |   84 -
 doc/C/tmpl/gda-handler-type.sgml                   |   54 -
 doc/C/tmpl/gda-holder.sgml                         |  393 -
 doc/C/tmpl/gda-lockable.sgml                       |   53 -
 doc/C/tmpl/gda-log.sgml                            |   65 -
 doc/C/tmpl/gda-meta-store.sgml                     |  275 -
 doc/C/tmpl/gda-meta-struct.sgml                    |  460 -
 doc/C/tmpl/gda-mutex.sgml                          |   77 -
 doc/C/tmpl/gda-pstmt.sgml                          |   77 -
 doc/C/tmpl/gda-quark-list.sgml                     |  111 -
 doc/C/tmpl/gda-repetitive-statement.sgml           |   74 -
 doc/C/tmpl/gda-report-docbook-document.sgml        |   57 -
 doc/C/tmpl/gda-report-document.sgml                |   70 -
 doc/C/tmpl/gda-report-engine.sgml                  |  249 -
 doc/C/tmpl/gda-report-rml-document.sgml            |   44 -
 doc/C/tmpl/gda-row.sgml                            |   66 -
 doc/C/tmpl/gda-server-operation-nodes.sgml         |  117 -
 doc/C/tmpl/gda-server-operation-sequences.sgml     |   96 -
 doc/C/tmpl/gda-server-operation.sgml               |  315 -
 doc/C/tmpl/gda-server-provider.sgml                |  368 -
 doc/C/tmpl/gda-set.sgml                            |  335 -
 doc/C/tmpl/gda-sql-builder.sgml                    |  430 -
 doc/C/tmpl/gda-sql-parser.sgml                     |  233 -
 doc/C/tmpl/gda-sql-statement.sgml                  | 1409 ---
 doc/C/tmpl/gda-statement.sgml                      |  214 -
 doc/C/tmpl/gda-thread-connection.sgml              |   45 -
 doc/C/tmpl/gda-thread-wrapper.sgml                 |  212 -
 doc/C/tmpl/gda-transaction-status.sgml             |   80 -
 doc/C/tmpl/gda-transaction.sgml                    |   81 -
 doc/C/tmpl/gda-tree-manager.sgml                   |  140 -
 doc/C/tmpl/gda-tree-mgr-columns.sgml               |   71 -
 doc/C/tmpl/gda-tree-mgr-label.sgml                 |   43 -
 doc/C/tmpl/gda-tree-mgr-schemas.sgml               |   55 -
 doc/C/tmpl/gda-tree-mgr-select.sgml                |   69 -
 doc/C/tmpl/gda-tree-mgr-tables.sgml                |   65 -
 doc/C/tmpl/gda-tree-node-dbio.sgml                 |   61 -
 doc/C/tmpl/gda-tree-node.sgml                      |  149 -
 doc/C/tmpl/gda-tree.sgml                           |  181 -
 doc/C/tmpl/gda-util.sgml                           |  160 -
 doc/C/tmpl/gda-value.sgml                          |  646 --
 doc/C/tmpl/gda-vconnection-data-model.sgml         |  136 -
 doc/C/tmpl/gda-vconnection-hub.sgml                |   92 -
 doc/C/tmpl/gda-virtual-connection.sgml             |   68 -
 doc/C/tmpl/gda-virtual-provider.sgml               |   28 -
 doc/C/tmpl/gda-vprovider-data-model.sgml           |   39 -
 doc/C/tmpl/gda-vprovider-hub.sgml                  |   43 -
 doc/C/tmpl/gda-xa-transaction.sgml                 |  166 -
 doc/C/tmpl/gdaui-basic-form.sgml                   |  345 -
 doc/C/tmpl/gdaui-cloud.sgml                        |  126 -
 doc/C/tmpl/gdaui-combo.sgml                        |   87 -
 doc/C/tmpl/gdaui-data-entry.sgml                   |  229 -
 doc/C/tmpl/gdaui-data-filter.sgml                  |   43 -
 doc/C/tmpl/gdaui-data-proxy-info.sgml              |   64 -
 doc/C/tmpl/gdaui-data-proxy.sgml                   |  149 -
 doc/C/tmpl/gdaui-data-selector.sgml                |  110 -
 doc/C/tmpl/gdaui-data-store.sgml                   |  125 -
 doc/C/tmpl/gdaui-data-widget-filter.sgml           |   39 -
 doc/C/tmpl/gdaui-data-widget-info.sgml             |   57 -
 doc/C/tmpl/gdaui-data-widget.sgml                  |  192 -
 doc/C/tmpl/gdaui-easy.sgml                         |   32 -
 doc/C/tmpl/gdaui-form.sgml                         |   57 -
 doc/C/tmpl/gdaui-grid.sgml                         |   66 -
 doc/C/tmpl/gdaui-login.sgml                        |  112 -
 doc/C/tmpl/gdaui-plugins.sgml                      |   66 -
 doc/C/tmpl/gdaui-provider-selector.sgml            |   65 -
 doc/C/tmpl/gdaui-raw-form.sgml                     |   43 -
 doc/C/tmpl/gdaui-raw-grid.sgml                     |  102 -
 doc/C/tmpl/gdaui-rt-editor.sgml                    |  103 -
 doc/C/tmpl/gdaui-server-operation.sgml             |   62 -
 doc/C/tmpl/gdaui-set.sgml                          |   68 -
 doc/C/tmpl/gdaui-tree-store.sgml                   |  105 -
 doc/C/tmpl/libgda.sgml                             |   47 -
 doc/C/tmpl/provider-support-sql.sgml               |  133 -
 doc/C/tmpl/provider-support.sgml                   |  480 -
 doc/C/virtual.xml                                  |    9 +-
 installers/Windows/make-zip-setup.sh               |  206 +-
 .../icons/hicolor/index.theme                      |    0
 libgda-4.0.pc.in => libgda-5.0.pc.in               |    0
 libgda-report-4.0.pc.in => libgda-report-5.0.pc.in |    0
 libgda-report/DocBook/Makefile.am                  |    8 +-
 .../DocBook/gda-report-docbook-document.h          |   16 +-
 libgda-report/Makefile.am                          |   16 +-
 libgda-report/RML/Makefile.am                      |    8 +-
 libgda-report/RML/gda-report-rml-document.h        |   21 +-
 libgda-report/engine/Makefile.am                   |   12 +-
 libgda-report/engine/gda-report-engine.h           |  153 +-
 libgda-report/engine/rt-parser.c                   |    2 +-
 libgda-report/gda-report-document.h                |   16 +-
 libgda-ui-4.0.pc.in => libgda-ui-5.0.pc.in         |    3 +-
 libgda-ui/.gitignore                               |    4 +-
 libgda-ui/Makefile.am                              |   28 +-
 libgda-ui/data-entries/Makefile.am                 |    2 +-
 .../data-entries/gdaui-data-cell-renderer-bin.c    |   35 +-
 .../gdaui-data-cell-renderer-boolean.c             |   33 +-
 .../data-entries/gdaui-data-cell-renderer-combo.c  |   36 +-
 .../data-entries/gdaui-data-cell-renderer-info.c   |   70 +-
 .../gdaui-data-cell-renderer-textual.c             |   33 +-
 .../data-entries/gdaui-data-cell-renderer-util.c   |    6 +-
 .../data-entries/gdaui-data-cell-renderer-util.h   |    2 +-
 libgda-ui/data-entries/gdaui-entry-bin.c           |    9 +-
 libgda-ui/data-entries/gdaui-entry-combo.c         |    3 -
 libgda-ui/data-entries/gdaui-entry-common-time.c   |   31 +-
 libgda-ui/data-entries/gdaui-entry-number.c        |   22 +-
 libgda-ui/data-entries/gdaui-entry-shell.c         |   23 +-
 libgda-ui/data-entries/gdaui-entry-string.c        |   10 +-
 libgda-ui/data-entries/gdaui-entry.h               |    4 +-
 libgda-ui/data-entries/plugins/Makefile.am         |    4 +-
 libgda-ui/data-entries/plugins/common-pict.c       |   29 +-
 .../plugins/gdaui-data-cell-renderer-password.c    |   33 +-
 .../plugins/gdaui-data-cell-renderer-pict.c        |   33 +-
 libgda-ui/data-entries/plugins/gdaui-entry-pict.c  |   16 +-
 libgda-ui/data-entries/widget-embedder.c           |  122 +-
 libgda-ui/data-entries/widget-embedder.h           |    2 -
 libgda-ui/demos/.gitignore                         |    2 +-
 libgda-ui/demos/Makefile.am                        |   14 +-
 libgda-ui/demos/basic_form.c                       |    4 -
 libgda-ui/demos/cloud.c                            |    4 -
 libgda-ui/demos/combo.c                            |    4 -
 libgda-ui/demos/data_model_dir.c                   |    4 -
 libgda-ui/demos/ddl_queries.c                      |   20 +-
 libgda-ui/demos/form.c                             |    4 -
 libgda-ui/demos/form_data_layout.c                 |    4 -
 libgda-ui/demos/form_pict.c                        |    4 -
 libgda-ui/demos/form_rw.c                          |    4 -
 libgda-ui/demos/grid.c                             |    4 -
 libgda-ui/demos/grid_data_layout.c                 |    4 -
 libgda-ui/demos/grid_pict.c                        |    4 -
 libgda-ui/demos/grid_rw.c                          |    4 -
 libgda-ui/demos/linked_grid_form.c                 |    4 -
 libgda-ui/demos/linked_model_param.c               |    4 -
 libgda-ui/demos/login.c                            |    4 -
 libgda-ui/demos/provider_sel.c                     |    5 -
 libgda-ui/demos/tree.c                             |    8 -
 libgda-ui/gdaui-basic-form.c                       |   10 -
 libgda-ui/gdaui-basic-form.h                       |  102 +-
 libgda-ui/gdaui-cloud.c                            |   32 +-
 libgda-ui/gdaui-cloud.h                            |   22 +-
 libgda-ui/gdaui-combo.h                            |   14 +-
 libgda-ui/gdaui-data-entry.h                       |   32 +-
 libgda-ui/gdaui-data-filter.c                      |    8 -
 libgda-ui/gdaui-data-filter.h                      |   18 +-
 libgda-ui/gdaui-data-proxy-info.h                  |   30 +-
 libgda-ui/gdaui-data-proxy.h                       |   36 +-
 libgda-ui/gdaui-data-selector.h                    |   24 +-
 libgda-ui/gdaui-data-store.h                       |   17 +-
 libgda-ui/gdaui-easy.h                             |   13 +-
 libgda-ui/gdaui-form.h                             |   15 +-
 libgda-ui/gdaui-grid.h                             |   15 +-
 libgda-ui/gdaui-init.c                             |    3 +-
 libgda-ui/gdaui-login.c                            |   47 +-
 libgda-ui/gdaui-login.h                            |   30 +-
 libgda-ui/gdaui-plugin.h                           |   35 +-
 libgda-ui/gdaui-provider-selector.h                |   13 +-
 libgda-ui/gdaui-raw-form.c                         |   41 +-
 libgda-ui/gdaui-raw-form.h                         |   18 +-
 libgda-ui/gdaui-raw-grid.c                         |   64 +-
 libgda-ui/gdaui-raw-grid.h                         |   18 +-
 libgda-ui/gdaui-rt-editor.c                        |    2 +
 libgda-ui/gdaui-rt-editor.h                        |   32 +-
 libgda-ui/gdaui-server-operation.c                 |    6 +-
 libgda-ui/gdaui-server-operation.h                 |   22 +-
 libgda-ui/gdaui-tree-store.h                       |   14 +-
 libgda-ui/internal/popup-container.c               |   17 +-
 libgda-ui/internal/utility.c                       |   28 -
 libgda-xslt-4.0.pc.in => libgda-xslt-5.0.pc.in     |    0
 libgda-xslt/Makefile.am                            |   10 +-
 libgda/.gitignore                                  |    4 +-
 libgda/Makefile.am                                 |   40 +-
 libgda/binreloc/Makefile.am                        |    4 +-
 libgda/gda-attributes-manager.h                    |   72 +-
 libgda/gda-batch.h                                 |   19 +-
 libgda/gda-blob-op.h                               |   73 +-
 libgda/gda-column.h                                |   17 +-
 libgda/gda-config.c                                |    2 +-
 libgda/gda-config.h                                |   44 +
 libgda/gda-connection-event.c                      |   24 +-
 libgda/gda-connection-event.h                      |   18 +-
 libgda/gda-connection.c                            |   24 +-
 libgda/gda-connection.h                            |   70 +-
 libgda/gda-data-access-wrapper.h                   |   16 +-
 libgda/gda-data-comparator.h                       |   27 +-
 libgda/gda-data-handler.h                          |   27 +-
 libgda/gda-data-meta-wrapper.c                     |    8 +-
 libgda/gda-data-model-array.h                      |   19 +-
 libgda/gda-data-model-bdb.h                        |   25 +-
 libgda/gda-data-model-dir.c                        |    6 +-
 libgda/gda-data-model-dir.h                        |   27 +-
 libgda/gda-data-model-import.h                     |   35 +-
 libgda/gda-data-model-iter.h                       |   50 +-
 libgda/gda-data-model.c                            |   10 +-
 libgda/gda-data-model.h                            |   43 +-
 libgda/gda-data-proxy.c                            |    2 +-
 libgda/gda-data-proxy.h                            |  108 +-
 libgda/gda-data-select.c                           |    2 +-
 libgda/gda-data-select.h                           |   39 +-
 libgda/gda-easy.c                                  |  637 --
 libgda/gda-easy.h                                  |  105 -
 libgda/gda-enums.h                                 |    7 +
 libgda/gda-holder.h                                |   19 +-
 libgda/gda-init.c                                  |    6 +-
 libgda/gda-lockable.h                              |   16 +-
 libgda/gda-log.h                                   |   14 +-
 libgda/gda-meta-store.c                            |    4 +-
 libgda/gda-meta-store.h                            |   36 +-
 libgda/gda-meta-struct.c                           |   22 +-
 libgda/gda-meta-struct.h                           |  110 +-
 libgda/gda-mutex.h                                 |   18 +-
 libgda/gda-quark-list.h                            |   15 +-
 libgda/gda-repetitive-statement.h                  |   25 +-
 libgda/gda-row.h                                   |   21 +-
 libgda/gda-server-operation.c                      |   12 +-
 libgda/gda-server-operation.h                      |   66 +-
 libgda/gda-server-provider-extra.c                 |  311 +-
 libgda/gda-server-provider-extra.h                 |   24 +-
 libgda/gda-server-provider.h                       |   98 +-
 libgda/gda-set.h                                   |   23 +-
 libgda/gda-sql-builder.c                           |   17 +-
 libgda/gda-sql-builder.h                           |   41 +-
 libgda/gda-statement-extra.h                       |  101 +-
 libgda/gda-statement.c                             |   15 +-
 libgda/gda-statement.h                             |   62 +-
 libgda/gda-transaction-status.h                    |   45 +-
 libgda/gda-tree-manager.h                          |   28 +-
 libgda/gda-tree-mgr-columns.h                      |   24 +-
 libgda/gda-tree-mgr-label.h                        |   15 +-
 libgda/gda-tree-mgr-schemas.h                      |   20 +-
 libgda/gda-tree-mgr-select.h                       |   26 +-
 libgda/gda-tree-mgr-tables.h                       |   24 +-
 libgda/gda-tree-node.h                             |   19 +-
 libgda/gda-tree.h                                  |   19 +-
 libgda/gda-util.c                                  |   10 +-
 libgda/gda-util.h                                  |   14 +-
 libgda/gda-value.c                                 |  175 +-
 libgda/gda-value.h                                 |   89 +-
 libgda/gda-xa-transaction.h                        |   50 +-
 libgda/handlers/Makefile.am                        |    4 +-
 libgda/handlers/gda-handler-bin.h                  |   16 +-
 libgda/handlers/gda-handler-boolean.h              |   16 +-
 libgda/handlers/gda-handler-numerical.h            |   16 +-
 libgda/handlers/gda-handler-string.h               |   16 +-
 libgda/handlers/gda-handler-time.h                 |   16 +-
 libgda/handlers/gda-handler-type.h                 |   16 +-
 libgda/libgda.h.in                                 |   13 +-
 libgda/libgda.symbols                              |   31 +-
 libgda/providers-support/gda-data-select-priv.h    |   25 +-
 libgda/providers-support/gda-pstmt.h               |   33 +-
 libgda/sql-parser/Makefile.am                      |   11 +-
 .../sql-parser/gda-sql-parser-enum-types.c.KEEPAPI |    7 -
 .../sql-parser/gda-sql-parser-enum-types.h.KEEPAPI |   19 -
 libgda/sql-parser/gda-sql-parser.h                 |   87 +-
 libgda/sql-parser/gda-sql-statement.h              |   33 +-
 libgda/sql-parser/gda-statement-struct-compound.h  |   18 +-
 libgda/sql-parser/gda-statement-struct-decl.h      |   69 +-
 libgda/sql-parser/gda-statement-struct-delete.h    |    9 +-
 libgda/sql-parser/gda-statement-struct-insert.h    |   38 +-
 libgda/sql-parser/gda-statement-struct-parts.c     |    4 +-
 libgda/sql-parser/gda-statement-struct-parts.h     |  155 +-
 libgda/sql-parser/gda-statement-struct-select.h    |   17 +-
 libgda/sql-parser/gda-statement-struct-trans.h     |   15 +-
 libgda/sql-parser/gda-statement-struct-unknown.h   |   12 +-
 libgda/sql-parser/gda-statement-struct-update.h    |   12 +-
 libgda/sql-parser/gda-statement-struct-util.c      |   86 +-
 libgda/sql-parser/gda-statement-struct-util.h      |   14 +-
 libgda/sql-parser/gda-statement-struct.h           |   12 +-
 libgda/sqlite/Makefile.am                          |    2 +-
 libgda/sqlite/gda-sqlite-provider.c                |    5 +-
 libgda/sqlite/gda-sqlite-util.c                    |    6 +-
 libgda/sqlite/sqlite-src/PragmasPatch              |    6 +-
 libgda/sqlite/sqlite-src/sqlite3.c                 | 9319 ++++++++++++++------
 libgda/sqlite/sqlite-src/sqlite3.h                 |  922 ++-
 libgda/sqlite/virtual/Makefile.am                  |    6 +-
 libgda/sqlite/virtual/gda-vconnection-data-model.h |   59 +-
 libgda/sqlite/virtual/gda-vconnection-hub.h        |   23 +-
 libgda/sqlite/virtual/gda-virtual-connection.h     |   14 +-
 libgda/sqlite/virtual/gda-virtual-provider.h       |   15 +-
 libgda/sqlite/virtual/gda-vprovider-data-model.h   |   18 +-
 libgda/sqlite/virtual/gda-vprovider-hub.h          |   21 +-
 ...-virtual-4.0.pc.in => libgda-virtual-5.0.pc.in} |    0
 libgda/thread-wrapper/Makefile.am                  |    4 +-
 libgda/thread-wrapper/gda-thread-wrapper.h         |   80 +-
 po/POTFILES.in                                     |    5 +-
 po/POTFILES.skip                                   |    2 +-
 providers/bdb/Makefile.am                          |   10 +-
 .../{libgda-bdb-4.0.pc.in => libgda-bdb-5.0.pc.in} |    0
 providers/bdbsql/Makefile.am                       |    6 +-
 ...da-bdbsql-4.0.pc.in => libgda-bdbsql-5.0.pc.in} |    0
 providers/firebird/Makefile.am                     |    8 +-
 providers/firebird/gda-firebird-provider.c         |    1 -
 ...irebird-4.0.pc.in => libgda-firebird-5.0.pc.in} |    0
 providers/jdbc/.gitignore                          |    2 +-
 providers/jdbc/Makefile.am                         |   20 +-
 providers/jdbc/gda-jdbc-provider.c                 |    1 -
 providers/jdbc/gda-jdbc-util.c                     |    3 +-
 ...libgda-jdbc-4.0.pc.in => libgda-jdbc-5.0.pc.in} |    0
 providers/jdbc/libmain.c                           |    2 +-
 providers/mdb/Makefile.am                          |   10 +-
 .../{libgda-mdb-4.0.pc.in => libgda-mdb-5.0.pc.in} |    0
 providers/mysql/Makefile.am                        |    8 +-
 providers/mysql/gda-mysql-provider.c               |   20 +-
 ...bgda-mysql-4.0.pc.in => libgda-mysql-5.0.pc.in} |    0
 providers/oracle/Makefile.am                       |    8 +-
 providers/oracle/gda-oracle-meta.c                 |    4 +-
 providers/oracle/gda-oracle-provider.c             |   17 +-
 ...da-oracle-4.0.pc.in => libgda-oracle-5.0.pc.in} |    0
 providers/postgres/Makefile.am                     |    8 +-
 providers/postgres/gda-postgres-provider.c         |   10 +-
 ...ostgres-4.0.pc.in => libgda-postgres-5.0.pc.in} |    0
 providers/reuseable/mysql/Makefile.am              |    2 +-
 providers/reuseable/postgres/Makefile.am           |    2 +-
 providers/skel-implementation/capi/Makefile.am     |   10 +-
 .../skel-implementation/capi/gda-capi-provider.c   |    1 -
 ...libgda-capi-4.0.pc.in => libgda-capi-5.0.pc.in} |    0
 providers/skel-implementation/models/Makefile.am   |   10 +-
 ...da-models-4.0.pc.in => libgda-models-5.0.pc.in} |    0
 providers/sqlcipher/Makefile.am                    |    6 +-
 ...cipher-4.0.pc.in => libgda-sqlcipher-5.0.pc.in} |    0
 providers/sqlcipher/sqlcipher.patch                |  405 +-
 providers/sqlite/Makefile.am                       |    8 +-
 ...da-sqlite-4.0.pc.in => libgda-sqlite-5.0.pc.in} |    0
 providers/web/Makefile.am                          |   10 +-
 providers/web/gda-web-provider.c                   |    2 -
 .../{libgda-web-4.0.pc.in => libgda-web-5.0.pc.in} |    0
 providers/web/php/gda-config.php.HOME              |   32 +
 samples/SimpleExample/example.c                    |    8 +-
 testing/.gitignore                                 |    2 +-
 testing/Makefile.am                                |   34 +-
 testing/gdaui-test-data-entries.c                  |   11 +-
 tests/Makefile.am                                  |   30 +-
 tests/data-models/Makefile.am                      |   20 +-
 tests/meta-store/Makefile.am                       |    8 +-
 tests/multi-threading/Makefile.am                  |   10 +-
 tests/parser/Makefile.am                           |   12 +-
 tests/providers/Makefile.am                        |   28 +-
 tests/test-cnc-utils.c                             |    4 +-
 tests/test-sql-identifier.c                        |   36 +-
 tests/value-holders/Makefile.am                    |    6 +-
 tools/.gitignore                                   |    8 +-
 tools/Makefile.am                                  |   46 +-
 tools/browser/.gitignore                           |    4 +-
 tools/browser/Makefile.am                          |   24 +-
 tools/browser/auth-dialog.c                        |   18 +-
 tools/browser/auth-dialog.h                        |    4 +-
 tools/browser/browser-connection-priv.h            |    4 +-
 tools/browser/browser-connection.c                 |    4 +-
 tools/browser/browser-connection.h                 |   18 +-
 tools/browser/browser-connections-list.c           |    4 +-
 tools/browser/browser-connections-list.h           |    4 +-
 tools/browser/browser-core.c                       |    4 +-
 tools/browser/browser-core.h                       |   17 +-
 tools/browser/browser-favorites.c                  |    4 +-
 tools/browser/browser-favorites.h                  |   18 +-
 tools/browser/browser-page.c                       |    4 +-
 tools/browser/browser-page.h                       |   19 +-
 tools/browser/browser-perspective.c                |    4 +-
 tools/browser/browser-perspective.h                |   17 +-
 tools/browser/browser-spinner.c                    |  909 +--
 tools/browser/browser-spinner.h                    |   74 +-
 tools/browser/browser-variable.c                   |    4 +-
 tools/browser/browser-variable.h                   |    4 +-
 tools/browser/browser-virtual-connection.c         |    4 +-
 tools/browser/browser-virtual-connection.h         |    4 +-
 tools/browser/browser-window.c                     |   45 +-
 tools/browser/browser-window.h                     |   17 +-
 tools/browser/canvas-example.c                     |    8 -
 tools/browser/canvas/Makefile.am                   |    2 +-
 tools/browser/canvas/browser-canvas-column.c       |   14 +-
 tools/browser/canvas/browser-canvas-column.h       |    8 +-
 tools/browser/canvas/browser-canvas-db-relations.c |   12 +-
 tools/browser/canvas/browser-canvas-db-relations.h |    8 +-
 tools/browser/canvas/browser-canvas-decl.h         |    8 +-
 tools/browser/canvas/browser-canvas-fkey.c         |    8 +-
 tools/browser/canvas/browser-canvas-fkey.h         |    8 +-
 tools/browser/canvas/browser-canvas-item.c         |    8 +-
 tools/browser/canvas/browser-canvas-item.h         |    8 +-
 tools/browser/canvas/browser-canvas-print.c        |    8 +-
 tools/browser/canvas/browser-canvas-priv.h         |    8 +-
 tools/browser/canvas/browser-canvas-table.c        |   16 +-
 tools/browser/canvas/browser-canvas-table.h        |    8 +-
 tools/browser/canvas/browser-canvas-text.c         |   10 +-
 tools/browser/canvas/browser-canvas-text.h         |    8 +-
 tools/browser/canvas/browser-canvas-utility.c      |   18 +-
 tools/browser/canvas/browser-canvas.c              |   43 +-
 tools/browser/canvas/browser-canvas.h              |    8 +-
 tools/browser/common/Makefile.am                   |    4 +-
 tools/browser/common/fk-declare.c                  |   11 +-
 tools/browser/common/fk-declare.h                  |    4 +-
 tools/browser/common/gdaui-data-import.c           |    8 +-
 tools/browser/common/gdaui-data-import.h           |    8 +-
 tools/browser/common/gdaui-entry-import.c          |   12 +-
 tools/browser/common/gdaui-entry-import.h          |    8 +-
 tools/browser/common/objects-cloud.c               |   16 +-
 tools/browser/common/objects-cloud.h               |    4 +-
 tools/browser/common/ui-formgrid.c                 |    6 +-
 tools/browser/common/ui-formgrid.h                 |    9 +-
 tools/browser/connection-binding-properties.c      |   11 +-
 tools/browser/connection-binding-properties.h      |    4 +-
 tools/browser/data-manager/analyser.c              |    4 +-
 tools/browser/data-manager/data-console.c          |    6 +-
 tools/browser/data-manager/data-console.h          |    4 +-
 .../browser/data-manager/data-favorite-selector.c  |   19 +-
 .../browser/data-manager/data-favorite-selector.h  |    4 +-
 .../data-manager/data-manager-perspective.c        |    6 +-
 .../data-manager/data-manager-perspective.h        |   14 +-
 tools/browser/data-manager/data-source-editor.c    |    4 +-
 tools/browser/data-manager/data-source-editor.h    |    4 +-
 tools/browser/data-manager/data-source-manager.c   |    4 +-
 tools/browser/data-manager/data-source-manager.h   |    4 +-
 tools/browser/data-manager/data-source.c           |    4 +-
 tools/browser/data-manager/data-source.h           |    4 +-
 tools/browser/data-manager/data-widget.c           |   13 +-
 tools/browser/data-manager/data-widget.h           |    4 +-
 tools/browser/data-manager/ui-spec-editor.c        |    6 +-
 tools/browser/data-manager/ui-spec-editor.h        |    4 +-
 tools/browser/data-manager/xml-spec-editor.c       |    9 +-
 tools/browser/data-manager/xml-spec-editor.h       |    4 +-
 tools/browser/data/Makefile.am                     |   10 +-
 tools/browser/dnd.c                                |    4 +-
 tools/browser/doc/Makefile.am                      |    4 +-
 tools/browser/doc/gda-browser-docs.sgml            |   56 +-
 tools/browser/doc/tmpl/browser-connection.sgml     |  433 -
 tools/browser/doc/tmpl/browser-core.sgml           |  180 -
 tools/browser/doc/tmpl/browser-favorites.sgml      |  200 -
 tools/browser/doc/tmpl/browser-page.sgml           |  112 -
 tools/browser/doc/tmpl/browser-perspective.sgml    |  106 -
 tools/browser/doc/tmpl/browser-window.sgml         |  145 -
 tools/browser/doc/tmpl/cc-gray-bar.sgml            |  117 -
 .../browser/doc/tmpl/data-manager-perspective.sgml |   62 -
 tools/browser/doc/tmpl/mgr-favorites.sgml          |   79 -
 tools/browser/doc/tmpl/popup-container.sgml        |   22 -
 tools/browser/doc/tmpl/query-exec-perspective.sgml |   44 -
 .../doc/tmpl/schema-browser-perspective.sgml       |   64 -
 tools/browser/doc/tmpl/support.sgml                |  166 -
 tools/browser/doc/tmpl/ui-formgrid.sgml            |  117 -
 .../browser/dummy-perspective/dummy-perspective.c  |    4 +-
 .../browser/dummy-perspective/dummy-perspective.h  |    4 +-
 tools/browser/favorites-test.c                     |    2 +-
 ...r-4.0.desktop.in => gda-browser-5.0.desktop.in} |    4 +-
 .../{gda-browser-4.0.png => gda-browser-5.0.png}   |    0
 tools/browser/login-dialog.c                       |   17 +-
 tools/browser/login-dialog.h                       |    4 +-
 tools/browser/main.c                               |    2 +-
 tools/browser/mgr-favorites.c                      |    4 +-
 tools/browser/mgr-favorites.h                      |   14 +-
 tools/browser/query-exec/query-console.c           |   11 +-
 tools/browser/query-exec/query-console.h           |    4 +-
 tools/browser/query-exec/query-editor.c            |   55 +-
 tools/browser/query-exec/query-editor.h            |    4 +-
 tools/browser/query-exec/query-exec-perspective.c  |    6 +-
 tools/browser/query-exec/query-exec-perspective.h  |   14 +-
 tools/browser/query-exec/query-favorite-selector.c |   19 +-
 tools/browser/query-exec/query-favorite-selector.h |    4 +-
 tools/browser/query-exec/query-result.c            |    4 +-
 tools/browser/query-exec/query-result.h            |    4 +-
 tools/browser/schema-browser/favorite-selector.c   |   15 +-
 tools/browser/schema-browser/favorite-selector.h   |    4 +-
 tools/browser/schema-browser/mgr-columns.c         |    4 +-
 tools/browser/schema-browser/mgr-columns.h         |    4 +-
 tools/browser/schema-browser/objects-index.c       |    4 +-
 tools/browser/schema-browser/objects-index.h       |    4 +-
 tools/browser/schema-browser/relations-diagram.c   |    4 +-
 tools/browser/schema-browser/relations-diagram.h   |    4 +-
 .../schema-browser/schema-browser-perspective.c    |    8 +-
 .../schema-browser/schema-browser-perspective.h    |   14 +-
 tools/browser/schema-browser/table-columns.c       |   16 +-
 tools/browser/schema-browser/table-columns.h       |    4 +-
 tools/browser/schema-browser/table-info.c          |   17 +-
 tools/browser/schema-browser/table-info.h          |    4 +-
 tools/browser/schema-browser/table-preferences.c   |    4 +-
 tools/browser/schema-browser/table-preferences.h   |    4 +-
 tools/browser/schema-browser/table-relations.c     |    4 +-
 tools/browser/schema-browser/table-relations.h     |    4 +-
 tools/browser/support.c                            |   13 +-
 tools/browser/support.h                            |    8 +
 tools/command-exec.c                               |    2 +-
 tools/config-info.c                                |    2 -
 tools/gda-list-server-op.c                         |    2 +-
 tools/gda-threader.c                               |    4 +-
 tools/gda-threader.h                               |    4 +-
 tools/gda-tree-mgr-xml.c                           |    4 +-
 tools/gda-tree-mgr-xml.h                           |    4 +-
 tools/web-server.c                                 |   12 +-
 tools/web-server.h                                 |    4 +-
 563 files changed, 13537 insertions(+), 28822 deletions(-)
---
diff --git a/NEWS b/NEWS
index 8e914d5..cf5b9d9 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,15 @@
+libgda 4.99.0, 2011-03-05
+
+ - Adaptations to the GTK3 environment (requires gtk+-3.0 >= 3.0.0):
+        - API is preserved but ABI has changed
+	- Deprecated API has been removed
+ - Embedded SQLite version 3.7.5
+ - Embedded SQLCipher version is 2.0Beta
+
+WARNING: this is a beta version and should not be used in a production environment, and the
+	 SQLCipher database provider is itself in a beta state, so again don't use it on production data,
+	 as you may lose your data!
+
 libgda 4.2.5, 2011-02-22
 
  - corrected regression which prevented correct execution of SELECT statements
diff --git a/README b/README
index de8f353..4497be6 100644
--- a/README
+++ b/README
@@ -22,7 +22,7 @@ developed based on it.
 
 The libgda library is released under the terms of the LGPL license,  which
 allows for commercial applications to be developed based on libgda. Its 
-command-line tools are under the GPL.
+command-line and UI tools are under the GPL.
 
 See COPYING for the GPL license.
 See COPYING.LIB for the LGPL license.
diff --git a/configure.ac b/configure.ac
index 4ae2f0a..6686d8b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
 m4_define(major, 4)
-m4_define(minor, 2)
-m4_define(micro, 6)
+m4_define(minor, 99)
+m4_define(micro, 1)
 m4_define([gda_stable],
 	m4_if(m4_eval(minor % 2), [0], [yes], [no]))
 AC_CONFIG_MACRO_DIR([m4])
@@ -25,7 +25,7 @@ AC_SUBST(GDA_VERSION, major.minor.micro)
 # ABI version:
 # Careful. Changing these will break ABI, because it is used for the library name and header install path:
 # This allows us to do a 3.2 version that is ABI-compatible with 3.0, but with API additions.
-AC_SUBST(GDA_ABI_MAJOR_VERSION, 4)
+AC_SUBST(GDA_ABI_MAJOR_VERSION, 5)
 AC_SUBST(GDA_ABI_MINOR_VERSION, 0)
 #AC_SUBST(GDA_MICRO_VERSION, micro)
 LIBGDA_ABI_VERSION=$GDA_ABI_MAJOR_VERSION.$GDA_ABI_MINOR_VERSION
@@ -40,7 +40,7 @@ m4_undefine([minor])
 m4_undefine([micro])
 
 dnl required versions of other tools.
-m4_define([req_ver_glib],[2.12.11])
+m4_define([req_ver_glib],[2.28.0])
 
 #
 # Making releases:
@@ -171,7 +171,7 @@ AC_ARG_WITH(ui,
 
 if test "$with_ui" = "auto" -o "$with_ui" = "yes"
 then
-	GTK_MODULES="gtk+-2.0 >= 2.12.0"
+	GTK_MODULES="gtk+-3.0 >= 3.0.0"
 	PKG_CHECK_MODULES(GTK, $GTK_MODULES, [
 		AC_DEFINE(HAVE_UI, [1], [GTK+ support enabled])
 		have_ui=yes], [
@@ -208,7 +208,7 @@ then
 
 	if test "$with_sourceview" = "auto" -o "$with_sourceview" = "yes"
 	then
-		PKG_CHECK_MODULES(GTKSOURCEVIEW, "gtksourceview-2.0", [
+		PKG_CHECK_MODULES(GTKSOURCEVIEW, "gtksourceview-3.0", [
 			AC_DEFINE(HAVE_GTKSOURCEVIEW, [1], [GtkSourceView support enabled])
 			have_sourceview=yes], [
 			if test "$with_sourceview" = "yes"
@@ -220,7 +220,7 @@ then
 
 	if test "$with_goo" = "auto" -o "$with_goo" = "yes"
 	then
-		PKG_CHECK_MODULES(GOOCANVAS, "goocanvas", [
+		PKG_CHECK_MODULES(GOOCANVAS, "goocanvas-2.0", [
 			AC_DEFINE(HAVE_GOOCANVAS, [1], [GooCanvas support enabled])
 			have_goocanvas=yes], [
 			if test "$with_goo" = "yes"
@@ -262,29 +262,6 @@ AC_SUBST(GRAPHVIZ_LIBS)
 
 
 dnl ******************************
-dnl Checks for LibUnique
-dnl ******************************
-have_unique=no
-AC_ARG_WITH(unique,
-	AS_HELP_STRING([--with-unique], [Use LibUnique to have only one control center]),
-	,with_unique=auto)
-
-if test "$with_unique" = "auto" -o "$with_unique" = "yes"
-then
-	PKG_CHECK_MODULES(UNIQUE, "unique-1.0", [
-		AC_DEFINE(HAVE_UNIQUE, [1], [LibUnique support enabled])
-		have_unique=yes], [
-		if test "$with_unique" = "yes"
-		then
-			AC_MSG_ERROR([LibUnique support requested but not found.])
-		fi
-		have_unique=no])
-fi
-AM_CONDITIONAL(HAVE_UNIQUE, test x"$have_unique" = "xyes")
-AC_SUBST(UNIQUE_CFLAGS)
-AC_SUBST(UNIQUE_LIBS)
-
-dnl ******************************
 dnl Checks for iso codes
 dnl ******************************
 
@@ -499,7 +476,7 @@ dnl ******************************
 dnl gtk-doc
 dnl ******************************
 
-GTK_DOC_CHECK([1.0])
+GTK_DOC_CHECK([1.14],[--flavour no-tmpl])
 
 dnl ******************************
 dnl Checks for providers
@@ -604,7 +581,7 @@ else
 		if test x"$have_sqlite" = "xyes"
 		then
 			AC_CHECK_LIB(sqlite3, sqlite3_table_column_metadata,[sqlite3_api=1], [sqlite3_api=0], $SQLITE_CFLAGS $SQLITE_LIBS)
-	
+
 			if test $sqlite3_api = 0
         		then
 				AC_MSG_RESULT([Installed SQLite was not compiled with the SQLITE_ENABLE_COLUMN_METADATA, using embedded SQLite])
@@ -624,7 +601,6 @@ else
 	AM_CONDITIONAL(HAVE_SQLITE, test x"$have_sqlite" = "xyes")
 fi
 
-
 dnl ************************
 dnl Check for libsoup
 dnl ************************
@@ -788,10 +764,10 @@ AC_SUBST(LIBGDA_LIBS)
 AC_OUTPUT([
 Makefile
 libgda.spec
-libgda-4.0.pc
-libgda-ui-4.0.pc
-libgda-report-4.0.pc
-libgda-xslt-4.0.pc
+libgda-5.0.pc
+libgda-ui-5.0.pc
+libgda-report-5.0.pc
+libgda-xslt-5.0.pc
 po/Makefile.in
 libgda/Makefile
 libgda/libgda.h
@@ -808,31 +784,31 @@ providers/reuseable/Makefile
 providers/reuseable/postgres/Makefile
 providers/reuseable/mysql/Makefile
 providers/bdb/Makefile
-providers/bdb/libgda-bdb-4.0.pc
+providers/bdb/libgda-bdb-5.0.pc
 providers/bdbsql/Makefile
-providers/bdbsql/libgda-bdbsql-4.0.pc
+providers/bdbsql/libgda-bdbsql-5.0.pc
 providers/mdb/Makefile
 providers/mdb/libmdb-src/Makefile
-providers/mdb/libgda-mdb-4.0.pc
+providers/mdb/libgda-mdb-5.0.pc
 providers/mysql/Makefile
-providers/mysql/libgda-mysql-4.0.pc
+providers/mysql/libgda-mysql-5.0.pc
 providers/oracle/Makefile
-providers/oracle/libgda-oracle-4.0.pc
+providers/oracle/libgda-oracle-5.0.pc
 providers/postgres/Makefile
-providers/postgres/libgda-postgres-4.0.pc
+providers/postgres/libgda-postgres-5.0.pc
 providers/sqlite/Makefile
-providers/sqlite/libgda-sqlite-4.0.pc
+providers/sqlite/libgda-sqlite-5.0.pc
 providers/jdbc/Makefile
-providers/jdbc/libgda-jdbc-4.0.pc
+providers/jdbc/libgda-jdbc-5.0.pc
 providers/web/Makefile
-providers/web/libgda-web-4.0.pc
+providers/web/libgda-web-5.0.pc
 providers/skel-implementation/Makefile
 providers/skel-implementation/capi/Makefile
-providers/skel-implementation/capi/libgda-capi-4.0.pc
+providers/skel-implementation/capi/libgda-capi-5.0.pc
 providers/skel-implementation/models/Makefile
-providers/skel-implementation/models/libgda-models-4.0.pc
+providers/skel-implementation/models/libgda-models-5.0.pc
 providers/sqlcipher/Makefile
-providers/sqlcipher/libgda-sqlcipher-4.0.pc
+providers/sqlcipher/libgda-sqlcipher-5.0.pc
 libgda-report/Makefile
 libgda-report/engine/Makefile
 libgda-report/DocBook/Makefile
@@ -851,7 +827,7 @@ libgda-ui/demos/geninclude.pl
 control-center/Makefile
 control-center/data/Makefile
 tools/Makefile
-tools/gda-sql-4.0.1:tools/gda-sql.1.in
+tools/gda-sql-5.0.1:tools/gda-sql.1.in
 tools/browser/Makefile
 tools/browser/data/Makefile
 tools/browser/common/Makefile
@@ -888,17 +864,17 @@ mv ${srcdir}/doc/C/version.xml.tmp ${srcdir}/doc/C/version.xml
 cp doc/C/builddate.xml ${srcdir}/doc/C/builddate.xml.tmp
 mv ${srcdir}/doc/C/builddate.xml.tmp ${srcdir}/doc/C/builddate.xml
 
-cp ${srcdir}/doc/C/libgda-sections.txt doc/C/libgda-4.0-sections.txt
-echo "" >> doc/C/libgda-4.0-sections.txt
-cat ${srcdir}/doc/C/libgda-ui-sections.txt >> doc/C/libgda-4.0-sections.txt
-cp doc/C/libgda-4.0-sections.txt ${srcdir}/doc/C/libgda-4.0-sections.txt.tmp
-mv ${srcdir}/doc/C/libgda-4.0-sections.txt.tmp ${srcdir}/doc/C/libgda-4.0-sections.txt
+cp ${srcdir}/doc/C/libgda-sections.txt doc/C/libgda-5.0-sections.txt
+echo "" >> doc/C/libgda-5.0-sections.txt
+cat ${srcdir}/doc/C/libgda-ui-sections.txt >> doc/C/libgda-5.0-sections.txt
+cp doc/C/libgda-5.0-sections.txt ${srcdir}/doc/C/libgda-5.0-sections.txt.tmp
+mv ${srcdir}/doc/C/libgda-5.0-sections.txt.tmp ${srcdir}/doc/C/libgda-5.0-sections.txt
 
-cp doc/C/libgda.types doc/C/libgda-4.0.types
+cp doc/C/libgda.types doc/C/libgda-5.0.types
 if test x$have_ui != xno
 then
-	echo "" >> doc/C/libgda-4.0.types
-	cat ${srcdir}/doc/C/libgda-ui.types >> doc/C/libgda-4.0.types
+	echo "" >> doc/C/libgda-5.0.types
+	cat ${srcdir}/doc/C/libgda-ui.types >> doc/C/libgda-5.0.types
 fi
 
 
@@ -925,4 +901,3 @@ then
        echo "   Binreloc support is disabled: Libgda will not be relocatable. To enable binreloc support re-run with --enable-binreloc (see http://autopackage.org/docs/binreloc for more information)"
 fi
 echo ""
-
diff --git a/control-center/.gitignore b/control-center/.gitignore
index cfbff4d..e56ffcb 100644
--- a/control-center/.gitignore
+++ b/control-center/.gitignore
@@ -1,2 +1,2 @@
-gda-control-center-4.0
-gda-control-center-4.*.desktop
+gda-control-center-5.0
+gda-control-center-5.*.desktop
diff --git a/control-center/Makefile.am b/control-center/Makefile.am
index 522fab2..4a709f9 100644
--- a/control-center/Makefile.am
+++ b/control-center/Makefile.am
@@ -1,4 +1,4 @@
-bin_PROGRAMS=gda-control-center-4.0
+bin_PROGRAMS=gda-control-center-5.0
 
 SUBDIRS = data
 
@@ -9,7 +9,6 @@ AM_CPPFLAGS = \
         $(LIBGDA_CFLAGS) \
 	$(LIBGDA_WFLAGS) \
         $(GTK_CFLAGS) \
-        $(UNIQUE_CFLAGS) \
         -DPREFIX=\""$(prefix)"\" \
         -DSYSCONFDIR=\""$(sysconfdir)"\" \
         -DDATADIR=\""$(datadir)"\" \
@@ -17,7 +16,7 @@ AM_CPPFLAGS = \
 	-DGDA_ABI_VERSION=\""$(GDA_ABI_VERSION)"\"
 
 # rename gdaui-dsn-editor as dsn-properties-editor
-gda_control_center_4_0_SOURCES=\
+gda_control_center_5_0_SOURCES=\
 	gdaui-login-dialog.c \
 	gdaui-login-dialog.h \
 	cc-gray-bar.c \
@@ -38,7 +37,7 @@ gda_control_center_4_0_SOURCES=\
 
 if PLATFORM_WIN32
 EXTRALDFLAGS=-mwindows
-gda_control_center_4_0_SOURCES += control-center-res.rc
+gda_control_center_5_0_SOURCES += control-center-res.rc
 else
 EXTRALDFLAGS=
 endif
@@ -49,21 +48,21 @@ endif
 control-center-res.o: control-center-res.rc
 	$(WINDRES) $^ -o $@
 
-gda_control_center_4_0_LDFLAGS = $(EXTRALDFLAGS)
-gda_control_center_4_0_LDADD=\
+gda_control_center_5_0_LDFLAGS = $(EXTRALDFLAGS)
+gda_control_center_5_0_LDADD=\
 	$(top_builddir)/libgda-ui/internal/libgda-ui-internal.la \
-	$(top_builddir)/libgda/libgda-4.0.la \
-	$(top_builddir)/libgda-ui/libgda-ui-4.0.la \
-	$(LIBGDA_LIBS) $(GTK_LIBS) $(UNIQUE_LIBS)
+	$(top_builddir)/libgda/libgda-5.0.la \
+	$(top_builddir)/libgda-ui/libgda-ui-5.0.la \
+	$(LIBGDA_LIBS) $(GTK_LIBS)
 
 @INTLTOOL_DESKTOP_RULE@
 
 desktopdir=$(datadir)/applications
-Desktop_in_files = gda-control-center-4.0.desktop.in
+Desktop_in_files = gda-control-center-5.0.desktop.in
 desktop_DATA = $(Desktop_in_files:.desktop.in=.desktop)
 
 # icons
-iconsdir=$(datadir)/libgda-4.0/pixmaps
+iconsdir=$(datadir)/libgda-5.0/pixmaps
 icons_DATA= \
 	gda-control-center.png \
 	gda-control-center-newcnc.png
diff --git a/control-center/cc-gray-bar.c b/control-center/cc-gray-bar.c
index 0997a25..3fa340d 100644
--- a/control-center/cc-gray-bar.c
+++ b/control-center/cc-gray-bar.c
@@ -1,13 +1,13 @@
 /* GNOME DB library
  *
- * Copyright (C) 1999 - 2009 The GNOME Foundation.
+ * Copyright (C) 1999 - 2010 The GNOME Foundation.
  *
  * AUTHORS:
  *      Rodrigo Moya <rodrigo gnome-db org>
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -36,14 +36,18 @@ static void cc_gray_bar_class_init   (CcGrayBarClass *klass);
 static void cc_gray_bar_init         (CcGrayBar      *bar,
 				      CcGrayBarClass *klass);
 static void cc_gray_bar_realize      (GtkWidget           *widget);
-static void cc_gray_bar_size_request (GtkWidget           *widget,
-				      GtkRequisition      *requisition);
+static void cc_gray_bar_get_preferred_width  (GtkWidget *widget,
+					      gint      *minimum,
+					      gint      *natural);
+static void cc_gray_bar_get_preferred_height (GtkWidget *widget,
+					      gint      *minimum,
+					      gint      *natural);
 static void cc_gray_bar_allocate     (GtkWidget           *widget,
 				      GtkAllocation       *allocation);
 static void cc_gray_bar_paint        (GtkWidget           *widget,
 				      GdkRectangle        *area);
-static gint cc_gray_bar_expose       (GtkWidget           *widget,
-				      GdkEventExpose      *event);
+static gboolean cc_gray_bar_draw     (GtkWidget           *widget,
+				      cairo_t             *cr);
 static void cc_gray_bar_style_set    (GtkWidget           *w,
 				      GtkStyle            *previous_style);
 static void cc_gray_bar_set_property (GObject *object,
@@ -75,31 +79,19 @@ cc_gray_bar_realize (GtkWidget *widget)
 {
 	gint border_width;
 
-#if GTK_CHECK_VERSION (2,19,5)
 	gtk_widget_set_realized (widget, TRUE);
-#else
-	GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
-#endif
 	border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
 	GdkWindowAttr attributes;
 	gint attributes_mask;
-#if GTK_CHECK_VERSION(2,18,0)
 	GtkAllocation alloc;
         gtk_widget_get_allocation (widget, &alloc);
 	attributes.x = alloc.x + border_width;
 	attributes.y = alloc.y + border_width;
 	attributes.width = alloc.width - 2*border_width;
 	attributes.height = alloc.height - 2*border_width;
-#else
-	attributes.x = widget->allocation.x + border_width;
-	attributes.y = widget->allocation.y + border_width;
-	attributes.width = widget->allocation.width - 2*border_width;
-	attributes.height = widget->allocation.height - 2*border_width;
-#endif
 	attributes.window_type = GDK_WINDOW_CHILD;
 	attributes.wclass = GDK_INPUT_OUTPUT;
 	attributes.visual = gtk_widget_get_visual (widget);
-	attributes.colormap = gtk_widget_get_colormap (widget);
 	attributes.event_mask = gtk_widget_get_events (widget)
 		| GDK_BUTTON_MOTION_MASK
 		| GDK_BUTTON_PRESS_MASK
@@ -108,15 +100,11 @@ cc_gray_bar_realize (GtkWidget *widget)
 		| GDK_ENTER_NOTIFY_MASK
 		| GDK_LEAVE_NOTIFY_MASK;
 
-	attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+	attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
 
 	GdkWindow *win;
 	win = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
-#if GTK_CHECK_VERSION(2,18,0)
 	gtk_widget_set_window (widget, win);
-#else
-	widget->window = win;
-#endif
 	gdk_window_set_user_data (win, widget);
 
 	GtkStyle *style;
@@ -143,14 +131,34 @@ cc_gray_bar_size_request (GtkWidget *widget, GtkRequisition *requisition)
 	if (child)
 		g_object_get ((GObject*) child, "visible", &visible, NULL);
 	if (visible) {
-		gtk_widget_size_request (child, &child_requisition);
-
+		gtk_widget_get_preferred_size (child, &child_requisition, NULL);
 		requisition->width += child_requisition.width;
 		requisition->height += child_requisition.height;
 	}
 }
 
 static void
+cc_gray_bar_get_preferred_width (GtkWidget *widget,
+				 gint      *minimum,
+				 gint      *natural)
+{
+	GtkRequisition requisition;
+	cc_gray_bar_size_request (widget, &requisition);
+	*minimum = *natural = requisition.width;
+}
+
+static void
+cc_gray_bar_get_preferred_height (GtkWidget *widget,
+				  gint      *minimum,
+				  gint      *natural)
+{
+	GtkRequisition requisition;
+	cc_gray_bar_size_request (widget, &requisition);
+	*minimum = *natural = requisition.height;
+}
+
+
+static void
 cc_gray_bar_allocate (GtkWidget *widget, GtkAllocation *allocation)
 {
 	GtkBin *bin;
@@ -158,11 +166,7 @@ cc_gray_bar_allocate (GtkWidget *widget, GtkAllocation *allocation)
 	guint bw;
 	GdkWindow *win;
 
-#if GTK_CHECK_VERSION(2,18,0)
 	gtk_widget_set_allocation (widget, allocation);
-#else
-	widget->allocation = *allocation;
-#endif
 
 	bin = GTK_BIN (widget);
 
@@ -172,11 +176,7 @@ cc_gray_bar_allocate (GtkWidget *widget, GtkAllocation *allocation)
 	child_allocation.width = MAX (allocation->width - bw * 2, 0);
 	child_allocation.height = MAX (allocation->height - bw * 2, 0);
 
-#if GTK_CHECK_VERSION(2,18,0)
 	win = gtk_widget_get_window (widget);
-#else
-	win = widget->window;
-#endif
 	if (win) {
 		gdk_window_move_resize (win,
 					allocation->x + bw,
@@ -210,63 +210,28 @@ cc_gray_bar_style_set (GtkWidget *w, GtkStyle *previous_style)
 	GTK_WIDGET_CLASS (parent_class)->style_set (w, previous_style);
 }
 
-static void
-cc_gray_bar_paint (GtkWidget *widget, GdkRectangle *area)
+static gboolean
+cc_gray_bar_draw (GtkWidget *widget, cairo_t *cr)
 {
 	gboolean paintable;
 
-#if GTK_CHECK_VERSION(2,18,0)
 	paintable = gtk_widget_get_app_paintable (widget);
-#else
-	paintable = GTK_WIDGET_APP_PAINTABLE (widget);
-#endif
 	if (!paintable) {
 		GtkStyle *style;
-		GdkWindow *win;
 		GtkAllocation alloc;
 		GtkStateType state;
 
 		style = gtk_widget_get_style (widget);
-#if GTK_CHECK_VERSION(2,18,0)
 		state = gtk_widget_get_state (widget);
-		win = gtk_widget_get_window (widget);
 		gtk_widget_get_allocation (widget, &alloc);
-#else
-		state = widget->state;
-		win = widget->window;
-		alloc = widget->allocation;
-#endif
-		gtk_paint_flat_box (style, win,
+		gtk_paint_flat_box (style, cr,
 				    state, GTK_SHADOW_NONE,
-				    area, widget, "gnomedbgraybar",
+				    widget, "gnomedbgraybar",
 				    1, 1,
 				    alloc.width - 2,
 				    alloc.height - 2);
 	}
-}
-
-static gboolean
-cc_gray_bar_expose (GtkWidget *widget, GdkEventExpose *event)
-{
-	gboolean drawable;
-	g_return_val_if_fail (widget != NULL, FALSE);
-	g_return_val_if_fail (CC_IS_GRAY_BAR (widget), FALSE);
-	g_return_val_if_fail (event != NULL, FALSE);
-
-	if (event->count > 0)
-		return FALSE;
-#if GTK_CHECK_VERSION(2,18,0)
-	drawable = gtk_widget_is_drawable (widget);
-#else
-	drawable = GTK_WIDGET_DRAWABLE (widget);
-#endif
-	if (drawable) {
-		cc_gray_bar_paint (widget, &event->area);
-
-		(* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
-	}
-
-	return FALSE;
+	return (* GTK_WIDGET_CLASS (parent_class)->draw) (widget, cr);
 }
 
 static void
@@ -291,9 +256,10 @@ cc_gray_bar_class_init (CcGrayBarClass *klass)
 	object_class->finalize      = cc_gray_bar_finalize;
 	widget_class->style_set     = cc_gray_bar_style_set;
 	widget_class->realize       = cc_gray_bar_realize;
-	widget_class->size_request  = cc_gray_bar_size_request;
+	widget_class->get_preferred_width = cc_gray_bar_get_preferred_width;
+	widget_class->get_preferred_height = cc_gray_bar_get_preferred_height;
 	widget_class->size_allocate = cc_gray_bar_allocate;
-	widget_class->expose_event  = cc_gray_bar_expose;
+	widget_class->draw          = cc_gray_bar_draw;
 	widget_class->show_all      = cc_gray_bar_show_all;
 
 	/* add class properties */
@@ -311,11 +277,7 @@ cc_gray_bar_class_init (CcGrayBarClass *klass)
 static void
 cc_gray_bar_init (CcGrayBar *bar, G_GNUC_UNUSED CcGrayBarClass *klass)
 {
-#if GTK_CHECK_VERSION(2,18,0)
 	gtk_widget_set_has_window (GTK_WIDGET (bar), TRUE);
-#else
-	GTK_WIDGET_UNSET_FLAGS (bar, GTK_NO_WINDOW);
-#endif
 
 	bar->priv = g_new0 (CcGrayBarPrivate, 1);
 
diff --git a/control-center/cc-gray-bar.h b/control-center/cc-gray-bar.h
index d135dce..413b6c3 100644
--- a/control-center/cc-gray-bar.h
+++ b/control-center/cc-gray-bar.h
@@ -1,12 +1,12 @@
-/* GNOME DB library
- * Copyright (C) 1999 - 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 1999 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Rodrigo Moya <rodrigo gnome-db org>
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -47,6 +47,16 @@ struct _CcGrayBarClass {
 	GtkBinClass parent_class;
 };
 
+/**
+ * SECTION:cc-gray-bar
+ * @short_description: A title bar
+ * @title: CcGrayBar
+ * @stability: Stable
+ * @see_also:
+ *
+ * The #CcGrayBar widget is a styled title bar
+ */
+
 GType        cc_gray_bar_get_type (void) G_GNUC_CONST;
 GtkWidget   *cc_gray_bar_new (const gchar *label);
 const gchar *cc_gray_bar_get_text (CcGrayBar *bar);
diff --git a/control-center/cc-utility.c b/control-center/cc-utility.c
index 41791fa..804ea9e 100644
--- a/control-center/cc-utility.c
+++ b/control-center/cc-utility.c
@@ -6,8 +6,8 @@
  *      Carlos Perelló Marín <carlos gnome-db org>
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/control-center/cc-utility.h b/control-center/cc-utility.h
index e42b2b9..ee08651 100644
--- a/control-center/cc-utility.h
+++ b/control-center/cc-utility.h
@@ -5,8 +5,8 @@
  * 	Rodrigo Moya <rodrigo gnome-db org>
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/control-center/data/Makefile.am b/control-center/data/Makefile.am
index 31246ed..03fa362 100644
--- a/control-center/data/Makefile.am
+++ b/control-center/data/Makefile.am
@@ -33,12 +33,12 @@ update-icon-cache:
 	@-if test -z "$(DESTDIR)"; then \
 		echo "Updating Gtk icon cache."; \
 		for theme in $(public_icons_themes); do \
-			$(gtk_update_icon_cache) $(datadir)/libgda-4.0/icons/$$theme; \
+			$(gtk_update_icon_cache) $(datadir)/libgda-5.0/icons/$$theme; \
 		done; \
 	else \
 		echo "*** Icon cache not updated.  After (un)install, run this:"; \
 		for theme in $(public_icons_themes); do \
-			echo "***   $(gtk_update_icon_cache) $(datadir)/libgda-4.0/icons/$$theme"; \
+			echo "***   $(gtk_update_icon_cache) $(datadir)/libgda-5.0/icons/$$theme"; \
 		done; \
 	fi
 
@@ -56,8 +56,8 @@ install-icons:
 		CONTEXT=`echo $$icon | cut -d_ -f2`; \
 		SIZE=`echo $$icon | cut -d_ -f3`; \
 		ICONFILE=`echo $$icon | cut -d_ -f4`; \
-		mkdir -p $(DESTDIR)$(datadir)/libgda-4.0/icons/$$THEME/$$SIZE/$$CONTEXT; \
-		$(INSTALL_DATA) $(srcdir)/$$icon $(DESTDIR)$(datadir)/libgda-4.0/icons/$$THEME/$$SIZE/$$CONTEXT/$$ICONFILE; \
+		mkdir -p $(DESTDIR)$(datadir)/libgda-5.0/icons/$$THEME/$$SIZE/$$CONTEXT; \
+		$(INSTALL_DATA) $(srcdir)/$$icon $(DESTDIR)$(datadir)/libgda-5.0/icons/$$THEME/$$SIZE/$$CONTEXT/$$ICONFILE; \
 	done
 
 uninstall-icons:
@@ -73,7 +73,7 @@ uninstall-icons:
 		CONTEXT=`echo $$icon | cut -d_ -f2`; \
 		SIZE=`echo $$icon | cut -d_ -f3`; \
 		ICONFILE=`echo $$icon | cut -d_ -f4`; \
-		rm -f $(DESTDIR)$(datadir)/libgda-4.0/icons/$$THEME/$$SIZE/$$CONTEXT/$$ICONFILE; \
+		rm -f $(DESTDIR)$(datadir)/libgda-5.0/icons/$$THEME/$$SIZE/$$CONTEXT/$$ICONFILE; \
 	done
 
 install-data-local: install-icons update-icon-cache
diff --git a/control-center/dsn-config.c b/control-center/dsn-config.c
index 59b954d..b0249ae 100644
--- a/control-center/dsn-config.c
+++ b/control-center/dsn-config.c
@@ -1,6 +1,5 @@
-/* GNOME-DB Components
- *
- * Copyright (C) 2000 - 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 2000 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Rodrigo Moya <rodrigo gnome-db org>
@@ -14,7 +13,7 @@
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
+ * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
@@ -103,9 +102,8 @@ dsn_config_new (void)
 {
 	DsnConfigPrivate *priv;
 	GtkWidget *dsn;
-	GtkWidget *table;
 	GtkWidget *box;
-	GtkWidget *button;
+	GtkWidget *image;
 	GtkWidget *label;
 	GtkWidget *sw;
 	gchar *title;
@@ -117,10 +115,6 @@ dsn_config_new (void)
 	g_object_set_data_full (G_OBJECT (dsn), DSN_CONFIG_DATA, priv,
 				(GDestroyNotify) free_private_data);
 
-	/* create the main table */
-	table = cc_new_table_widget (3, 1, FALSE);
-	gtk_box_pack_start (GTK_BOX (dsn), table, TRUE, TRUE, 0);
-
 	/* title */
 	title = g_strdup_printf ("<b>%s</b>\n%s", _("Data Sources"),
 				 _("Configured data sources in the system"));
@@ -131,20 +125,14 @@ dsn_config_new (void)
 	path = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, "pixmaps", "gdaui-generic.png", NULL);
 	cc_gray_bar_set_icon_from_file (CC_GRAY_BAR (priv->title), path);
 	g_free (path);
-	gtk_table_attach (GTK_TABLE (table), priv->title, 0, 1, 0, 1,
-			  GTK_FILL | GTK_SHRINK,
-			  GTK_FILL | GTK_SHRINK,
-			  0, 0);
+	gtk_box_pack_start (GTK_BOX (dsn), priv->title, FALSE, FALSE, 0);
 	gtk_widget_show (priv->title);
 
 	/* create the data source list */
 	sw = gtk_scrolled_window_new (NULL, NULL);
 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC,
 					GTK_POLICY_AUTOMATIC);
-	gtk_table_attach (GTK_TABLE (table), sw, 0, 1, 1, 2,
-			  GTK_FILL | GTK_SHRINK | GTK_EXPAND,
-			  GTK_FILL | GTK_SHRINK | GTK_EXPAND,
-			  0, 0);
+	gtk_box_pack_start (GTK_BOX (dsn), sw, TRUE, TRUE, 0);
 	
 	model = gda_config_list_dsn ();
 	priv->dsn_list = gdaui_raw_grid_new (model);
@@ -168,29 +156,25 @@ dsn_config_new (void)
 			  G_CALLBACK (list_popup_cb), dsn);
 
 	/* add tip */
-	box = cc_new_hbox_widget (FALSE, 6);
+	box = gtk_hbox_new (FALSE, 6);
         gtk_container_set_border_width (GTK_CONTAINER (box), 6);
-	gtk_table_attach (GTK_TABLE (table), box, 0, 1, 2, 3,
-			  GTK_FILL,
-			  GTK_FILL,
-                          0, 0);
-
-	button = gtk_image_new_from_stock (GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_DIALOG);
-        gtk_misc_set_alignment (GTK_MISC (button), 0.5, 0.0);
-	gtk_widget_show (button);
-	gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
-
-	label = cc_new_label_widget (
-		_("Data sources are the means by which database "
-		  "connections are identified: all "
-		  "the information needed to open a connection to "
-		  "a specific database using a 'provider' is referenced using "
-		  "a unique name."));
+	gtk_box_pack_start (GTK_BOX (dsn), box, FALSE, FALSE, 0);
+	gtk_widget_show (box);
+
+	image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_DIALOG);
+        gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0);
+	gtk_widget_show (image);
+	gtk_box_pack_start (GTK_BOX (box), image, FALSE, FALSE, 0);
+
+	label = gtk_label_new (_("Data sources are the means by which database "
+				 "connections are identified: all "
+				 "the information needed to open a connection to "
+				 "a specific database using a 'provider' is referenced using "
+				 "a unique name."));
 	gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
-        gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);
-        gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
 	gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
-	
+	gtk_widget_show (label);
+
 	return dsn;
 }
 
diff --git a/control-center/dsn-config.h b/control-center/dsn-config.h
index cd49a84..3ccc3c4 100644
--- a/control-center/dsn-config.h
+++ b/control-center/dsn-config.h
@@ -13,7 +13,7 @@
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
+ * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
diff --git a/control-center/dsn-properties-dialog.c b/control-center/dsn-properties-dialog.c
index 69e7c2a..8bee6a3 100644
--- a/control-center/dsn-properties-dialog.c
+++ b/control-center/dsn-properties-dialog.c
@@ -1,5 +1,5 @@
-/* GNOME-DB Components
- * Copyright (C) 2000 - 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 2000 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Rodrigo Moya <rodrigo gnome-db org>
@@ -13,7 +13,7 @@
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
+ * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
@@ -113,8 +113,7 @@ dsn_properties_dialog (GtkWindow *parent, const gchar *dsn)
 					      GTK_STOCK_REVERT_TO_SAVED, REVERT_BUTTON,
 					      GTK_STOCK_CLOSE, GTK_RESPONSE_OK,
 					      NULL);
-	gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
-	gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+	gtk_window_set_default_size (GTK_WINDOW (dialog), 450, 300);
 	gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), TEST_BUTTON, pinfo ? TRUE : FALSE);
 	gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), BROWSE_BUTTON, pinfo ? TRUE : FALSE);
 	gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), REVERT_BUTTON, FALSE);
@@ -161,11 +160,7 @@ dsn_properties_dialog (GtkWindow *parent, const gchar *dsn)
         g_free (str);
 
 	GtkWidget *dcontents;
-#if GTK_CHECK_VERSION(2,18,0)
 	dcontents = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
-#else
-	dcontents = GTK_DIALOG (dialog)->vbox;
-#endif
 	gtk_container_set_border_width (GTK_CONTAINER (dcontents), 5);
 	gtk_box_pack_start (GTK_BOX (dcontents), label, FALSE, FALSE, 0);
 	gtk_widget_show (label);
@@ -250,30 +245,40 @@ dsn_properties_dialog (GtkWindow *parent, const gchar *dsn)
 		break;
 		case BROWSE_BUTTON:
 		{
-			char *argv[3];
+			GAppInfo *appinfo;
+			GdkAppLaunchContext *context;
+			GdkScreen *screen;
 			gboolean sresult;
 			GError *lerror = NULL;
+			gchar *cmd;
 #ifdef G_OS_WIN32
 #define EXENAME "gda-browser-" GDA_ABI_VERSION ".exe"
 #else
 #define EXENAME "gda-browser-" GDA_ABI_VERSION
 #endif
 			/* run the gda-browser tool */
-			argv[0] = gda_gbr_get_file_path (GDA_BIN_DIR, (gchar *) EXENAME, NULL);
-			argv[1] = (char *) dsn;
-			argv[2] = NULL;
-
-			sresult = gdk_spawn_on_screen (gtk_widget_get_screen (GTK_WIDGET (dialog)),
-						       NULL, argv, NULL, 0,
-						       NULL, NULL, NULL, &lerror);
-			if (!sresult && lerror && (lerror->domain == G_SPAWN_ERROR) && (lerror->code == G_SPAWN_ERROR_NOENT)) {
-				g_error_free (lerror);
-				g_free (argv[0]);
-				argv[0] = g_strdup (EXENAME);
-				sresult = g_spawn_async (NULL, argv, NULL, G_SPAWN_SEARCH_PATH,
-							 NULL, NULL, NULL, &lerror);
+			cmd = gda_gbr_get_file_path (GDA_BIN_DIR, (char *) EXENAME, NULL);
+			appinfo = g_app_info_create_from_commandline (cmd,
+								      "Gda browser",
+								      G_APP_INFO_CREATE_NONE,
+								      NULL);
+			g_free (cmd);
+			
+			screen = gtk_widget_get_screen (GTK_WIDGET (parent));
+			context = gdk_display_get_app_launch_context (gdk_screen_get_display (screen));
+			gdk_app_launch_context_set_screen (context, screen);
+			sresult = g_app_info_launch (appinfo, NULL, G_APP_LAUNCH_CONTEXT (context), NULL);
+			if (! sresult) {
+				g_object_unref (appinfo);
+				appinfo = g_app_info_create_from_commandline (EXENAME,
+									      "Gda Control center",
+									      G_APP_INFO_CREATE_NONE,
+									      NULL);
+				sresult = g_app_info_launch (appinfo, NULL, G_APP_LAUNCH_CONTEXT (context), &lerror);
 			}
-			g_free (argv [0]);
+			g_object_unref (context);
+			g_object_unref (appinfo);
+
 			if (!sresult) {
 				GtkWidget *msgdialog;
 				msgdialog = gtk_message_dialog_new_with_markup (GTK_WINDOW (dialog), GTK_DIALOG_MODAL,
diff --git a/control-center/dsn-properties-dialog.h b/control-center/dsn-properties-dialog.h
index 53cf31a..b9f0096 100644
--- a/control-center/dsn-properties-dialog.h
+++ b/control-center/dsn-properties-dialog.h
@@ -12,7 +12,7 @@
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
+ * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
diff --git a/control-center/gda-control-center-4.0.desktop.in b/control-center/gda-control-center-5.0.desktop.in
similarity index 88%
rename from control-center/gda-control-center-4.0.desktop.in
rename to control-center/gda-control-center-5.0.desktop.in
index ab68756..6fd5b58 100644
--- a/control-center/gda-control-center-4.0.desktop.in
+++ b/control-center/gda-control-center-5.0.desktop.in
@@ -2,7 +2,7 @@
 _Name=Database access control center
 _Comment=Configure your database access environment
 Icon=gda-control-center
-Exec=gda-control-center-4.0
+Exec=gda-control-center-5.0
 Terminal=false
 Type=Application
 Categories=Settings;DesktopSettings;
diff --git a/control-center/gdaui-dsn-assistant.c b/control-center/gdaui-dsn-assistant.c
index 0fe390f..71affdc 100644
--- a/control-center/gdaui-dsn-assistant.c
+++ b/control-center/gdaui-dsn-assistant.c
@@ -5,8 +5,8 @@
  *      Rodrigo Moya <rodrigo gnome-db org>
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/control-center/gdaui-dsn-assistant.h b/control-center/gdaui-dsn-assistant.h
index 02080c8..432617c 100644
--- a/control-center/gdaui-dsn-assistant.h
+++ b/control-center/gdaui-dsn-assistant.h
@@ -5,8 +5,8 @@
  *      Rodrigo Moya <rodrigo gnome-db org>
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/control-center/gdaui-dsn-editor.c b/control-center/gdaui-dsn-editor.c
index 9ed69ec..92b6b2a 100644
--- a/control-center/gdaui-dsn-editor.c
+++ b/control-center/gdaui-dsn-editor.c
@@ -1,12 +1,12 @@
-/* GNOME DB library
+/*
  * Copyright (C) 1999 - 2009 The GNOME Foundation
  *
  * AUTHORS:
  *      Rodrigo Moya <rodrigo gnome-db org>
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -177,7 +177,7 @@ gdaui_dsn_editor_init (GdauiDsnEditor *config, G_GNUC_UNUSED GdauiDsnEditorClass
 	g_signal_connect (G_OBJECT (config->priv->wprovider), "changed",
 			  G_CALLBACK (field_changed_cb), config);
 	gtk_table_attach (GTK_TABLE (table), config->priv->wprovider, 1, 2, 2, 3,
-			  GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
+			  GTK_FILL|GTK_EXPAND, 0, 0, 0);
 
 	label = gtk_label_new_with_mnemonic (_("_Description:"));
 	gtk_misc_set_alignment (GTK_MISC (label), 0, -1.);
diff --git a/control-center/gdaui-dsn-editor.h b/control-center/gdaui-dsn-editor.h
index 18b4b68..ab98cab 100644
--- a/control-center/gdaui-dsn-editor.h
+++ b/control-center/gdaui-dsn-editor.h
@@ -5,8 +5,8 @@
  *      Rodrigo Moya <rodrigo gnome-db org>
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/control-center/gdaui-login-dialog.c b/control-center/gdaui-login-dialog.c
index a4977b3..527620d 100644
--- a/control-center/gdaui-login-dialog.c
+++ b/control-center/gdaui-login-dialog.c
@@ -1,12 +1,12 @@
 /* GNOME DB library
- * Copyright (C) 1999 - 2009 The GNOME Foundation.
+ * Copyright (C) 1999 - 2010 The GNOME Foundation.
  *
  * AUTHORS:
  *      Rodrigo Moya <rodrigo gnome-db org>
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -103,12 +103,7 @@ gdaui_login_dialog_init (GdauiLoginDialog *dialog, G_GNUC_UNUSED GdauiLoginDialo
 
 	g_return_if_fail (GDAUI_IS_LOGIN_DIALOG (dialog));
 
-#if GTK_CHECK_VERSION(2,18,0)
 	dcontents = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
-#else
-	dcontents = GTK_DIALOG (dialog)->vbox;
-#endif
-
 	dialog->priv = g_new0 (GdauiLoginDialogPrivate, 1);
         
 	gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
@@ -117,7 +112,6 @@ gdaui_login_dialog_init (GdauiLoginDialog *dialog, G_GNUC_UNUSED GdauiLoginDialo
 
 	gtk_container_set_border_width (GTK_CONTAINER (dialog), 6);
         gtk_box_set_spacing (GTK_BOX (dcontents), 12);
-        gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
         gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
 
 	hbox = gtk_hbox_new (FALSE, 12);
diff --git a/control-center/gdaui-login-dialog.h b/control-center/gdaui-login-dialog.h
index 9449e8f..29478b5 100644
--- a/control-center/gdaui-login-dialog.h
+++ b/control-center/gdaui-login-dialog.h
@@ -5,8 +5,8 @@
  *      Rodrigo Moya <rodrigo gnome-db org>
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/control-center/main.c b/control-center/main.c
index 813ee4f..0a0dfd0 100644
--- a/control-center/main.c
+++ b/control-center/main.c
@@ -13,7 +13,7 @@
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
+ * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
@@ -28,9 +28,6 @@
 #include "dsn-config.h"
 #include "provider-config.h"
 #include "gdaui-dsn-assistant.h"
-#ifdef HAVE_UNIQUE
-#include <unique/unique.h>
-#endif
 
 GtkWindow *main_window;
 GtkActionGroup *actions;
@@ -180,7 +177,7 @@ about_cb (G_GNUC_UNUSED GtkAction *action, G_GNUC_UNUSED gpointer user_data)
 	dialog = gtk_about_dialog_new ();
 	gtk_about_dialog_set_program_name (GTK_ABOUT_DIALOG (dialog), _("Database access control center"));
 	gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (dialog), PACKAGE_VERSION);
-	gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG (dialog), "(C) 1998 - 2010 GNOME Foundation");
+	gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG (dialog), "(C) 1998 - 2011 GNOME Foundation");
 	gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG (dialog), _("Database access services for the GNOME Desktop"));
 	gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (dialog), "GNU Lesser General Public License");
 	gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (dialog), "http://www.gnome-db.org";);
@@ -300,75 +297,33 @@ create_main_window (void)
 	return window;
 }
 
-#ifdef HAVE_UNIQUE
-static UniqueResponse
-message_received_cb (G_GNUC_UNUSED UniqueApp         *app,
-                     UniqueCommand      command,
-                     UniqueMessageData *message,
-                     G_GNUC_UNUSED guint              time_,
-                     gpointer           user_data)
+static void
+activate (GtkApplication *app)
 {
-	UniqueResponse res = UNIQUE_RESPONSE_OK;
-	switch (command) {
-	case UNIQUE_ACTIVATE:
-		/* move the main window to the screen that sent us the command */
-		gtk_window_set_screen (GTK_WINDOW (user_data), unique_message_data_get_screen (message));
-		gtk_window_present (GTK_WINDOW (user_data));
-		res = UNIQUE_RESPONSE_OK;
-		break;
-	default:
-		TO_IMPLEMENT;
+	static GtkWidget *window = NULL;
+
+	if (! window) {
+		gdaui_init ();
+		window = create_main_window ();
+		gtk_window_set_application (GTK_WINDOW (window), app);
+		gtk_widget_show (window);
 	}
-	return res;
 }
-#endif
 
 int
 main (int argc, char *argv[])
 {
-#ifdef HAVE_UNIQUE
-	UniqueApp *app;
-#endif
-	/*
-	str = gnome_db_gbr_get_locale_dir_path ();
-	bindtextdomain (GETTEXT_PACKAGE, str);
-	g_free (str);
-
-	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
-	textdomain (GETTEXT_PACKAGE);
-	*/
-	gdaui_init ();
-	gtk_init (&argc, &argv);
-
-#ifdef HAVE_UNIQUE
-	app = unique_app_new ("org.gnome-db.gda-browser", NULL);
-	if (unique_app_is_running (app)) {
-		UniqueResponse response;
-		response = unique_app_send_message (app, UNIQUE_ACTIVATE, NULL);
-		if (response != UNIQUE_RESPONSE_OK)
-			TO_IMPLEMENT;
-		g_object_unref (app);
-		return 0;
-	}
-	else {
-		GtkWidget *main_window;
-		main_window = create_main_window ();
-		unique_app_watch_window (app, GTK_WINDOW (main_window));
-		g_signal_connect (app, "message-received", G_CALLBACK (message_received_cb), main_window);
-	}
-#else	
-	create_main_window ();
-#endif
+	GtkApplication *app;
+	gint status;
+	
+	app = gtk_application_new ("org.GnomeDb.GdaBrowser", G_APPLICATION_FLAGS_NONE);
+	g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
+	
+	status = g_application_run (G_APPLICATION (app), argc, argv);
 	
-
-	/* application loop */
-	gtk_main ();
-
-#ifdef HAVE_UNIQUE
 	g_object_unref (app);
-#endif
 
-	return 0;
+	return status;
 }
 
 static void
@@ -377,10 +332,11 @@ dsn_selection_changed_cb (GdauiRawGrid *dbrawgrid, gboolean row_selected, G_GNUC
 	GtkAction *action;
 	GArray *selection;
 
+	selection = gdaui_data_selector_get_selected_rows (GDAUI_DATA_SELECTOR (dbrawgrid));
+
 	action = gtk_action_group_get_action (actions, "DatabaseProperties");
-	g_object_set (G_OBJECT (action), "sensitive", row_selected, NULL);
+	g_object_set (G_OBJECT (action), "sensitive", selection ? TRUE : FALSE, NULL);
 
-	selection = gdaui_data_selector_get_selected_rows (GDAUI_DATA_SELECTOR (dbrawgrid));
 	action = gtk_action_group_get_action (actions, "DatabaseDelete");
 	g_object_set (G_OBJECT (action), "sensitive", selection ? TRUE : FALSE, NULL);
 	if (selection)
diff --git a/control-center/provider-config.c b/control-center/provider-config.c
index b577a69..8aa1485 100644
--- a/control-center/provider-config.c
+++ b/control-center/provider-config.c
@@ -1,6 +1,5 @@
-/* GNOME-DB Configurator
- *
- * Copyright (C) 2000 - 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 2000 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Rodrigo Moya <rodrigo gnome-db org>
@@ -14,7 +13,7 @@
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
+ * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
@@ -46,25 +45,20 @@ provider_config_new (void)
 {
 	ProviderConfigPrivate *priv;
 	GtkWidget *provider;
-	GtkWidget *table;
 	GtkWidget *box;
-	GtkWidget *button;
+	GtkWidget *image;
 	GtkWidget *label;
 	GtkWidget *sw;
 	gchar *title;
 	GdaDataModel *model;
 
 	priv = g_new0 (ProviderConfigPrivate, 1);
-	provider = gtk_vbox_new (FALSE, 6);
+	provider = gtk_vbox_new (FALSE, 0);
 	gtk_widget_show (provider);
         gtk_container_set_border_width (GTK_CONTAINER (provider), 6);
 	g_object_set_data_full (G_OBJECT (provider), PROVIDER_CONFIG_DATA, priv,
 				(GDestroyNotify) g_free);
 
-	table = gtk_table_new (3, 1, FALSE);
-	gtk_box_pack_start (GTK_BOX (provider), table, TRUE, TRUE, 0);
-	gtk_widget_show (table);
-
 	/* title */
 	title = g_strdup_printf ("<b>%s</b>\n%s", _("Providers"),
 				 _("Installed providers"));
@@ -76,20 +70,14 @@ provider_config_new (void)
 	cc_gray_bar_set_icon_from_file (CC_GRAY_BAR (priv->title), path);
 	g_free (path);
 
-	gtk_table_attach (GTK_TABLE (table), priv->title, 0, 1, 0, 1,
-			  GTK_FILL | GTK_SHRINK,
-			  GTK_FILL | GTK_SHRINK,
-			  0, 0);
+	gtk_box_pack_start (GTK_BOX (provider), priv->title, FALSE, FALSE, 0);
 	gtk_widget_show (priv->title);
 
 	/* create the provider list */
 	sw = gtk_scrolled_window_new (NULL, NULL);
 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC,
-					GTK_POLICY_AUTOMATIC);	
-	gtk_table_attach (GTK_TABLE (table), sw, 0, 1, 1, 2,
-			  GTK_FILL | GTK_SHRINK | GTK_EXPAND,
-			  GTK_FILL | GTK_SHRINK | GTK_EXPAND,
-			  0, 0);
+					GTK_POLICY_AUTOMATIC);
+	gtk_box_pack_start (GTK_BOX (provider), sw, TRUE, TRUE, 0);
 
 	model = gda_config_list_providers ();
 	priv->provider_list = gdaui_raw_grid_new (model);
@@ -105,22 +93,17 @@ provider_config_new (void)
 	box = gtk_hbox_new (FALSE, 6);
 	gtk_widget_show (box);
         gtk_container_set_border_width (GTK_CONTAINER (box), 6);
-	gtk_table_attach (GTK_TABLE (table), box, 0, 1, 2, 3,
-			  GTK_FILL, GTK_FILL, 0, 0);
+	gtk_box_pack_start (GTK_BOX (provider), box, FALSE, FALSE, 0);
 
-	button = gtk_image_new_from_stock (GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_DIALOG);
-        gtk_misc_set_alignment (GTK_MISC (button), 0.5, 0.0);
-	gtk_widget_show (button);
-	gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
+	image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_DIALOG);
+	gtk_widget_show (image);
+	gtk_box_pack_start (GTK_BOX (box), image, FALSE, FALSE, 0);
 
-	label = gtk_label_new_with_mnemonic (
-		_("Providers are addons that actually implement the access "
-		  "to each database using the means provided by each database vendor."));
+	label = gtk_label_new (_("Providers are addons that actually implement the access "
+				 "to each database using the means provided by each database vendor."));
 	gtk_widget_show (label);
 	gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
-        gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);
-        gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
-	gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
+	gtk_box_pack_start (GTK_BOX (box), label, TRUE, FALSE, 0);
 
 	return provider;
 }
diff --git a/control-center/provider-config.h b/control-center/provider-config.h
index f91d10d..8bda99e 100644
--- a/control-center/provider-config.h
+++ b/control-center/provider-config.h
@@ -13,7 +13,7 @@
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
+ * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
diff --git a/data/Makefile.am b/data/Makefile.am
index 54a25b8..5e63481 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -1,5 +1,5 @@
 # Default global configuration file
-configdir   = $(sysconfdir)/libgda-4.0
+configdir   = $(sysconfdir)/libgda-5.0
 config_DATA = config sales_test.db
 
 EXTRA_DIST = \
diff --git a/doc/C/.gitignore b/doc/C/.gitignore
index 8955943..d37bb35 100644
--- a/doc/C/.gitignore
+++ b/doc/C/.gitignore
@@ -2,31 +2,31 @@ html
 xml
 html-build.stamp
 html.stamp
-libgda-4.0-decl-list.txt
-libgda-4.0-decl.txt
-libgda-4.0-undocumented.txt
-libgda-4.0-unused.txt
-libgda-4.0.args
-libgda-4.0.hierarchy
-libgda-4.0.signals
+libgda-5.0-decl-list.txt
+libgda-5.0-decl.txt
+libgda-5.0-undocumented.txt
+libgda-5.0-unused.txt
+libgda-5.0.args
+libgda-5.0.hierarchy
+libgda-5.0.signals
 scan-build.stamp
 sgml-build.stamp
 sgml.stamp
 tmpl-build.stamp
 tmpl.stamp
 .libs
-libgda-4.0.prerequisites
-libgda-4.0-decl.txt.bak
-libgda-4.0.interfaces
-libgda-4.0-decl-list.txt.bak
+libgda-5.0.prerequisites
+libgda-5.0-decl.txt.bak
+libgda-5.0.interfaces
+libgda-5.0-decl-list.txt.bak
 libgda.types
-libgda-4.0.types
-libgda-4.0-overrides.txt
-libgda-4.0-doc.pdf
+libgda-5.0.types
+libgda-5.0-overrides.txt
+libgda-5.0-doc.pdf
 pdf-build.stamp
-libgda-4.0-undeclared.txt
-libgda-4.0-unused.sgml
+libgda-5.0-undeclared.txt
+libgda-5.0-unused.sgml
 version.xml
 builddate.xml
 *.bak
-libgda-4.0-sections.txt
+libgda-5.0-sections.txt
diff --git a/doc/C/Makefile.am b/doc/C/Makefile.am
index 8100b4e..2011500 100644
--- a/doc/C/Makefile.am
+++ b/doc/C/Makefile.am
@@ -3,7 +3,7 @@
 AUTOMAKE_OPTIONS = 1.6
 
 # The name of the module.
-DOC_MODULE=libgda-4.0
+DOC_MODULE=libgda-5.0
 
 # The top-level SGML file.
 DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
@@ -17,6 +17,9 @@ SCANGOBJ_OPTIONS=
 # The directory containing the source code. Relative to $(srcdir)
 DOC_SOURCE_DIR=../..
 
+# Add the builddir to the HTML path so that version.xml is found
+MKHTML_OPTIONS=--path="$(abs_srcdir)"
+
 # Used for dependencies.
 HFILE_GLOB=
 CFILE_GLOB=
@@ -24,7 +27,7 @@ CFILE_GLOB=
 # Header files to ignore when scanning
 IGNORE_HFILES= gda-marshal.h gda-custom-marshal.h gda-enum-types.h sqlite3.h csv.h md5.h \
 	jni-wrapper.h gda-jdbc-recordset.h gda-jdbc-blob-op.h gda-jdbc-provider.h gda-jdbc-pstmt.h \
-	popup-container.h providers tools control-center tests samples plugins
+	popup-container.h providers tools control-center tests samples plugins tmp
 
 # CFLAGS and LDFLAGS for compiling scan program. Only needed
 # if $(DOC_MODULE).types is non-empty.
@@ -37,14 +40,14 @@ GTKDOC_CFLAGS = -I$(top_srcdir) \
         $(LIBGDA_CFLAGS) \
 	-DGETTEXT_PACKAGE=\""$(GETTEXT_PACKAGE)"\"
 
-GTKDOC_LIBS =  $(top_builddir)/libgda/libgda-4.0.la \
-	$(top_builddir)/libgda-report/libgda-report-4.0.la \
+GTKDOC_LIBS =  $(top_builddir)/libgda/libgda-5.0.la \
+	$(top_builddir)/libgda-report/libgda-report-5.0.la \
 	$(LIBGDA_LIBS)
 
 if HAVE_UI
 GTKDOC_CFLAGS += $(GTK_CFLAGS)
 GTKDOC_LIBS += $(GTK_LIBS) \
-	$(top_builddir)/libgda-ui/libgda-ui-4.0.la
+	$(top_builddir)/libgda-ui/libgda-ui-5.0.la
 endif
 
 # Extra options to supply to gtkdoc-mkdb
@@ -77,7 +80,8 @@ include $(top_srcdir)/gtk-doc.make
 # Other files to distribute
 EXTRA_DIST += examples/full_example.c installation.xml limitations.xml migration.xml migration2.xml \
 	server-operation.xml gettingstarted.xml virtual.xml virtual-notice.xml store-meta-type.xml \
-	prov-writing.xml packaging.xml packaging_ui.xml i_s_doc.xml howto.xml gda-sql-manual.xml data_validation.xml data_select.xml \
+	prov-writing-virtual-methods.xml prov-writing-recordsets.xml prov-writing-blobs.xml prov-writing-parser.xml prov-writing-assembly.xml \
+	packaging.xml packaging_ui.xml i_s_doc.xml howto.xml gda-sql-manual.xml data_validation.xml data_select.xml \
 	DataModels.svg \
 	architecture.svg parts.svg stmt-unknown.svg stmt-select.svg stmt-insert1.svg stmt-insert2.svg \
 	stmt-update.svg stmt-compound.svg information_schema.svg howto-exec.svg thread-wrapper.svg \
@@ -89,7 +93,7 @@ EXTRA_DIST += examples/full_example.c installation.xml limitations.xml migration
 # Files not to distribute
 # for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
 # for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
-DISTCLEANFILES = $(DOC_MODULE)-doc.pdf libgda-4.0.types libgda-4.0-sections.txt
+DISTCLEANFILES = $(DOC_MODULE)-doc.pdf libgda-5.0.types libgda-5.0-sections.txt
 
 DOC_STAMPS += pdf-build.stamp
 CLEANFILES += $(DOC_STAMPS)
diff --git a/doc/C/data_select.xml b/doc/C/data_select.xml
index 2c1a7d7..20ed086 100644
--- a/doc/C/data_select.xml
+++ b/doc/C/data_select.xml
@@ -1,3 +1,6 @@
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+          "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd";>
 <sect1 id="data-select">
   <title>Advanced GdaDataSelect usage</title>
   <para>
diff --git a/doc/C/data_validation.xml b/doc/C/data_validation.xml
index 7203c9e..194fa7b 100644
--- a/doc/C/data_validation.xml
+++ b/doc/C/data_validation.xml
@@ -1,3 +1,8 @@
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+          "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd";[
+<!ENTITY LIBGDA          "<application>Libgda</application>">
+]>
 <sect1 id="data-validation">
   <title>Custom data validation</title>
   <para>
diff --git a/doc/C/examples/blobtest.c b/doc/C/examples/blobtest.c
index b92a74a..df7fcb4 100644
--- a/doc/C/examples/blobtest.c
+++ b/doc/C/examples/blobtest.c
@@ -1,3 +1,7 @@
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+          "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd";>
+<programlisting>
 <![CDATA[#include <libgda/libgda.h>
 #include <libgda/sql-parser/gda-sql-parser.h>
 #include <libgda/gda-blob-op.h>
@@ -190,3 +194,4 @@ do_fetch (GdaConnection *cnc, gint id, GError **error)
 	return result;
 }
 ]]>
+</programlisting>
diff --git a/doc/C/examples/full_example.c b/doc/C/examples/full_example.c
index 2fd2ad9..6e8e925 100644
--- a/doc/C/examples/full_example.c
+++ b/doc/C/examples/full_example.c
@@ -1,3 +1,7 @@
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+          "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd";>
+<programlisting>
 <![CDATA[#include <libgda/libgda.h>
 #include <sql-parser/gda-sql-parser.h>
 
@@ -116,7 +120,7 @@ insert_data (GdaConnection *cnc)
 			g_value_set_float (v3, data[i].price);
 		}
 		
-		res = gda_insert_row_into_table (cnc, "products", &error, "ref", v1, "name", v2, "price", v3, NULL);
+		res = gda_connection_insert_row_into_table (cnc, "products", &error, "ref", v1, "name", v2, "price", v3, NULL);
 
 		if (!res) {
 			g_error ("Could not INSERT data into the 'products' table: %s\n",
@@ -145,7 +149,7 @@ update_data (GdaConnection *cnc)
 	v3 = gda_value_new (G_TYPE_FLOAT);
 	g_value_set_float (v3, 1.99);
 		
-	res = gda_update_row_in_table (cnc, "products", "ref", v1, &error, "name", v2, "price", v3, NULL);
+	res = gda_connection_update_row_in_table (cnc, "products", "ref", v1, &error, "name", v2, "price", v3, NULL);
 
 	if (!res) {
 		g_error ("Could not UPDATE data in the 'products' table: %s\n",
@@ -168,7 +172,7 @@ delete_data (GdaConnection *cnc)
 
 	/* delete data where name is 'table' */
 	v = gda_value_new_from_string ("table", G_TYPE_STRING);
-	res = gda_delete_row_from_table (cnc, "products", "name", v, &error);
+	res = gda_connection_delete_row_from_table (cnc, "products", "name", v, &error);
 	if (!res) {
 		g_error ("Could not DELETE data from the 'products' table: %s\n",
 			 error && error->message ? error->message : "No detail");
@@ -176,7 +180,7 @@ delete_data (GdaConnection *cnc)
 	gda_value_free (v);
 
 	/* delete data where price is NULL */
-	res = gda_delete_row_from_table (cnc, "products", "price", NULL, &error);
+	res = gda_connection_delete_row_from_table (cnc, "products", "price", NULL, &error);
 	if (!res) {
 		g_error ("Could not DELETE data from the 'products' table: %s\n",
 			 error && error->message ? error->message : "No detail");
@@ -229,3 +233,4 @@ run_sql_non_select (GdaConnection *cnc, const gchar *sql)
 	g_object_unref (stmt);
 }
 ]]>
+</programlisting>
diff --git a/doc/C/fdl-appendix.sgml b/doc/C/fdl-appendix.sgml
index 6ab4128..6301540 100644
--- a/doc/C/fdl-appendix.sgml
+++ b/doc/C/fdl-appendix.sgml
@@ -1,3 +1,8 @@
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+          "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd";[
+<!ENTITY copy          "The GNOME Foundation">
+]>
 <!--  
      The GNU Free Documentation License 1.1 in DocBook
      Markup by Eric Baudais <baudais okstate edu>
@@ -627,7 +632,7 @@
     
     <blockquote>
       <para>
-	Copyright &copy; YEAR YOUR NAME.
+	Copyright &copy; 1999 - 2011.
       </para>
       <para>
 	Permission is granted to copy, distribute and/or modify this
diff --git a/doc/C/gda-sql-manual.xml b/doc/C/gda-sql-manual.xml
index df81fe8..0bb7258 100644
--- a/doc/C/gda-sql-manual.xml
+++ b/doc/C/gda-sql-manual.xml
@@ -1,3 +1,10 @@
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+          "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd";[
+<!ENTITY LIBGDA          "<application>Libgda</application>">
+]>
+<part id="gda-sql">
+  <title>Gda SQL console's user manual</title>
 <para>
   The &LIBGDA;'s console tool allow one to send SQL commands to a database server, and
   to easily browse the meta data associated to the database (ie. get information about
@@ -773,5 +780,4 @@ SalesTest>
   </sect1>
 
 </chapter>
-
-
+</part>
diff --git a/doc/C/gettingstarted.xml b/doc/C/gettingstarted.xml
index 8ad2b87..b4af31e 100644
--- a/doc/C/gettingstarted.xml
+++ b/doc/C/gettingstarted.xml
@@ -1,4 +1,9 @@
-<chapter id="getting_started">
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+          "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd";[
+<!ENTITY LIBGDA          "<application>Libgda</application>">
+]>
+<chapter id="getting_started" xmlns:xi="http://www.w3.org/2003/XInclude";>
   <title>Code examples</title>
   <sect1 id="initializing">
     <title>Initializing</title>
@@ -342,9 +347,7 @@ cc -o example example.c `pkg-config --cflags --libs libgda-3.0`
     </para>
     <para>
       The code is:
-      <programlisting>
-&fullexample;
-      </programlisting>
+<xi:include href="examples/full_example.c"/>
       and executing should output something like:
       <programlisting>> ./example 
 ref   | name  | price   
@@ -461,9 +464,7 @@ create_table (GdaConnection *cnc)
     </para>
     <para>
       The code is:
-      <programlisting>
-&blobsexample;
-      </programlisting>
+<xi:include href="examples/blobtest.c"/>
     </para>
   </sect1>
 
diff --git a/doc/C/howto.xml b/doc/C/howto.xml
index 31b35aa..4be53ee 100644
--- a/doc/C/howto.xml
+++ b/doc/C/howto.xml
@@ -1,3 +1,8 @@
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+          "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd";[
+<!ENTITY LIBGDA          "<application>Libgda</application>">
+]>
 <chapter id="howto">
   <title>HOWTO for common tasks</title>
   <para>
@@ -349,7 +354,7 @@ g_object_unref (b);
     </para>
     <para>
       However when one only wants to run a simple SQL statement, &LIBGDA; provides the
-      <link linkend="gda-execute-select-command">gda_execute_select_command()</link> function which does
+      <link linkend="gda-connection-statement-execute-select-command">gda_connection_statement_execute_select_command()</link> function which does
       everything in one step. The following codes illustrates parsing and executing a SELECT statement:
     </para>
     <para>
diff --git a/doc/C/installation.xml b/doc/C/installation.xml
index 2c2d4ab..e84075d 100644
--- a/doc/C/installation.xml
+++ b/doc/C/installation.xml
@@ -1,3 +1,10 @@
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+          "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd";[
+<!ENTITY LIBGDA          "<application>Libgda</application>">
+<!ENTITY GNOMEDB         "<acronym>Gnome-Db</acronym>">
+<!ENTITY RPM             "<acronym>RPM</acronym>">
+]>
 <chapter id="installation">
   <title>Installation</title>
   <sect1 id="installation-introduction">
@@ -113,8 +120,8 @@
       to use the <command>pkg-config</command> command.
     </para>
     <programlisting>
-<systemitem class="prompt">$ </systemitem>gcc -c full_example.c `pkg-config --cflags libgda-4.0`
-<systemitem class="prompt">$ </systemitem>gcc -o full_example `pkg-config --libs libgda-4.0` full_example.o
+<systemitem class="prompt">$ </systemitem>gcc -c full_example.c `pkg-config --cflags libgda-5.0`
+<systemitem class="prompt">$ </systemitem>gcc -o full_example `pkg-config --libs libgda-5.0` full_example.o
     </programlisting>
     <para>
       or more simply:
@@ -180,8 +187,8 @@
 	To access a database, it must have a database provider (if &LIBGDA; does not
 	support the type of database to access, make a bug report in 
 	<ulink url="http://bugzilla.gnome.org/";>bugzilla</ulink>), and that database provider
-	must be compiled an installed: the <command>gda-list-config-4.0</command> or 
-	<command>gda-sql-4.0 -L</command> commands will
+	must be compiled an installed: the <command>gda-list-config-5.0</command> or 
+	<command>gda-sql-5.0 -L</command> commands will
 	show a list of the installed and configured database providers.
       </para>
       <para>
@@ -203,7 +210,7 @@
 	(which
 	is created the first time &LIBGDA; is used within an application. System wide DSN are defined in the
 	<filename>&lt;prefix&gt;/etc/libgda/config</filename>. Rather than editing that
-	file manually, it is possible to use the <command>gda-control-center-4.0</command> tool
+	file manually, it is possible to use the <command>gda-control-center-5.0</command> tool
 	(part of &LIBGDA;).
 	Note: if the <filename>$HOME/.libgda/config</filename> already exists from a previous use
 	of &LIBGDA;, then that file is used instead of
diff --git a/doc/C/libgda-4.0-docs.sgml b/doc/C/libgda-5.0-docs.sgml
similarity index 81%
rename from doc/C/libgda-4.0-docs.sgml
rename to doc/C/libgda-5.0-docs.sgml
index 55c17b6..58fc7cf 100644
--- a/doc/C/libgda-4.0-docs.sgml
+++ b/doc/C/libgda-5.0-docs.sgml
@@ -1,164 +1,25 @@
 <?xml version="1.0"?>
 <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
      "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd"; [
-<!ENTITY nbsp            " ">
+<!ENTITY copy           "The GNOME Foundation">
 <!ENTITY version SYSTEM "version.xml">
 <!ENTITY builddate SYSTEM "builddate.xml">
 <!ENTITY LIBGDA          "<application>Libgda</application>">
-<!ENTITY GNOMEDB         "<application>GNOME-DB</application>">
 <!ENTITY igalia          '<emphasis><ulink url="http://www.igalia.com";>Igalia, S.L.</ulink></emphasis>'>
 <!ENTITY xobas           '<emphasis><ulink url="http://www.xobas.com";>Xobas Software</ulink></emphasis>'>
 <!ENTITY API             "<acronym>API</acronym>">
-<!ENTITY DBMS            "<acronym>DBMS</acronym>">
-<!ENTITY DSN             "<acronym>DSN</acronym>">
 <!ENTITY ODBC            "<acronym>ODBC</acronym>">
 <!ENTITY GDA             "<acronym>GDA</acronym>">
 <!ENTITY LDAP            "<acronym>LDAP</acronym>">
-<!ENTITY CORBA           "<acronym>CORBA</acronym>">
-<!ENTITY IDL             "<acronym>IDL</acronym>">
-<!ENTITY ORB             "<acronym>ORB</acronym>">
 <!ENTITY SQL             "<acronym>SQL</acronym>">
-<!ENTITY RPM             "<acronym>RPM</acronym>">
-<!ENTITY XML             "<acronym>XML</acronym>">
-<!ENTITY PGSQL           "<application>PostgreSQL</application>">
-<!ENTITY MYSQL           "<application>MySQL</application>">
-<!ENTITY ORAC            "<application>Oracle</application>">
-<!ENTITY INTERB          "<application>Interbase</application>">
-<!ENTITY SYBASE          "<application>Sybase</application>">
-<!ENTITY MSACC           "<application>MS Access</application>">
-<!ENTITY INFOR           "<application>Informix</application>">
-<!ENTITY GDASERVERPROVIDER "<link linkend='GdaServerProvider'>GdaServerProvider</link>">
-<!ENTITY GDADATAMODEL    "<link linkend='GdaDataModel'>GdaDataModel</link>">
-<!ENTITY GDADATAMODELARRAY "<link linkend='GdaDataModelArray'>GdaDataModelArray</link>">
-<!ENTITY GDADATAMODELHASH "<link linkend='GdaDataModelHash'>GdaDataModelHash</link>">
-<!ENTITY gda-list-server-op "<command>gda-list-server-op-4.0</command>">
-<!ENTITY gda-list-config "<command>gda-list-config-4.0</command>">
-<!ENTITY gda-sql "<command>gda-sql</command>">
-<!ENTITY gda-test-connection "<command>gda-test-connection-4.0</command>">
-<!ENTITY fullexample SYSTEM "examples/full_example.c">
-<!ENTITY blobsexample SYSTEM "examples/blobtest.c">
-<!ENTITY install SYSTEM "installation.xml">
-<!ENTITY examples SYSTEM "gettingstarted.xml">
-<!ENTITY migration SYSTEM "migration.xml">
-<!ENTITY migration2 SYSTEM "migration2.xml">
-<!ENTITY data-validation SYSTEM "data_validation.xml">
-<!ENTITY data-select SYSTEM "data_select.xml">
-<!ENTITY limitations SYSTEM "limitations.xml">
-<!ENTITY provnotes SYSTEM "prov-notes.xml">
-<!ENTITY libgda-GdaCommand SYSTEM "xml/gda-command.xml">
-<!ENTITY libgda-config SYSTEM "xml/gda-config.xml">
-<!ENTITY libgda-GdaConnection SYSTEM "xml/gda-connection.xml">
-<!ENTITY libgda-GdaMutex SYSTEM "xml/gda-mutex.xml">
-<!ENTITY libgda-GdaLockable SYSTEM "xml/gda-lockable.xml">
-<!ENTITY libgda-GdaRow SYSTEM "xml/gda-row.xml">
-<!ENTITY libgda-GdaDataModelArray SYSTEM "xml/gda-data-model-array.xml">
-<!ENTITY libgda-GdaDataModelBdb SYSTEM "xml/gda-data-model-bdb.xml">
-<!ENTITY libgda-GdaDataModelDir SYSTEM "xml/gda-data-model-dir.xml">
-<!ENTITY libgda-GdaDataModel SYSTEM "xml/gda-data-model.xml">
-<!ENTITY libgda-GdaDataModelIter SYSTEM "xml/gda-data-model-iter.xml">
-<!ENTITY libgda-GdaDataModelImport SYSTEM "xml/gda-data-model-import.xml">
-<!ENTITY libgda-GdaDataAccessWrapper SYSTEM "xml/gda-data-access-wrapper.xml">
-<!ENTITY libgda-GdaDataProxy SYSTEM "xml/gda-data-proxy.xml">
-<!ENTITY libgda-GdaConnection-event SYSTEM "xml/gda-connection-event.xml">
-<!ENTITY libgda-GdaColumn SYSTEM "xml/gda-column.xml">
-<!ENTITY libgda-init SYSTEM "xml/libgda.xml">
-<!ENTITY libgdaui-init SYSTEM "xml/libgdaui.xml">
-<!ENTITY libgda-log SYSTEM "xml/gda-log.xml">
-<!ENTITY libgda-quark-list SYSTEM "xml/gda-quark-list.xml">
-<!ENTITY libgda-GdaServerProvider SYSTEM "xml/gda-server-provider.xml">
-<!ENTITY libgda-GdaVirtualProvider SYSTEM "xml/gda-virtual-provider.xml">
-<!ENTITY libgda-GdaVproviderDataModel SYSTEM "xml/gda-vprovider-data-model.xml">
-<!ENTITY libgda-GdaVproviderHub SYSTEM "xml/gda-vprovider-hub.xml">
-<!ENTITY libgda-GdaVirtualConnection SYSTEM "xml/gda-virtual-connection.xml">
-<!ENTITY libgda-GdaVconnectionDataModel SYSTEM "xml/gda-vconnection-data-model.xml">
-<!ENTITY libgda-GdaVconnectionHub SYSTEM "xml/gda-vconnection-hub.xml">
-<!ENTITY libgda-GdaServerOperation SYSTEM "xml/gda-server-operation.xml">
-<!ENTITY libgda-GdaServerOperationNodes SYSTEM "xml/gda-server-operation-nodes.xml">
-<!ENTITY libgda-GdaServerOperationSequences SYSTEM "xml/gda-server-operation-sequences.xml">
-<!ENTITY libgda-serverop-intro SYSTEM "server-operation.xml">
-<!ENTITY libgda-virtual SYSTEM "virtual.xml">
-<!ENTITY libgda-virtual-notice SYSTEM "virtual-notice.xml">
-<!ENTITY libgda-xa-transaction SYSTEM "xml/gda-xa-transaction.xml">
-<!ENTITY libgda-transaction-status SYSTEM "xml/gda-transaction-status.xml">
-<!ENTITY libgda-util SYSTEM "xml/gda-util.xml">
-<!ENTITY libgda-GValue SYSTEM "xml/gda-value.xml">
-<!ENTITY libgda-GdaConnection SYSTEM "xml/gda-connection.xml">
-<!ENTITY GdaStoreMetaType SYSTEM "store-meta-type.xml">
-<!ENTITY libgda-GdaDataHandler SYSTEM "xml/gda-data-handler.xml">
-<!ENTITY libgda-GdaHandlerString SYSTEM "xml/gda-handler-string.xml">
-<!ENTITY libgda-GdaHandlerBoolean SYSTEM "xml/gda-handler-boolean.xml">
-<!ENTITY libgda-GdaHandlerTime SYSTEM "xml/gda-handler-time.xml">
-<!ENTITY libgda-GdaHandlerNumerical SYSTEM "xml/gda-handler-numerical.xml">
-<!ENTITY libgda-GdaHandlerBin SYSTEM "xml/gda-handler-bin.xml">
-<!ENTITY libgda-GdaHandlerType SYSTEM "xml/gda-handler-type.xml">
-<!ENTITY libgda-GdaBlobOp SYSTEM "xml/gda-blob-op.xml">
-<!ENTITY libgda-GdaReportEngine SYSTEM "xml/gda-report-engine.xml">
-<!ENTITY libgda-GdaReportDocument SYSTEM "xml/gda-report-document.xml">
-<!ENTITY libgda-GdaReportDocbookDocument SYSTEM "xml/gda-report-docbook-document.xml">
-<!ENTITY libgda-GdaReportRmlDocument SYSTEM "xml/gda-report-rml-document.xml">
-<!ENTITY libgda-GdaHolder SYSTEM "xml/gda-holder.xml">
-<!ENTITY libgda-GdaSet SYSTEM "xml/gda-set.xml">
-<!ENTITY libgda-GdaStatement SYSTEM "xml/gda-statement.xml">
-<!ENTITY libgda-GdaRepetitiveStatement SYSTEM "xml/gda-repetitive-statement.xml">
-<!ENTITY libgda-GdaSqlStatement SYSTEM "xml/gda-sql-statement.xml">
-<!ENTITY libgda-GdaBatch SYSTEM "xml/gda-batch.xml">
-<!ENTITY libgda-GdaSqlParser SYSTEM "xml/gda-sql-parser.xml">
-<!ENTITY libgda-GdaMetaStore SYSTEM "xml/gda-meta-store.xml">
-<!ENTITY libgda-GdaMetaStruct SYSTEM "xml/gda-meta-struct.xml">
-<!ENTITY libgda-GdaDataSelect SYSTEM "xml/gda-data-select.xml">
-<!ENTITY libgda-GdaDataSelectPriv SYSTEM "xml/gda-data-select-priv.xml">
-<!ENTITY libgda-PStmt SYSTEM "xml/gda-pstmt.xml">
-<!ENTITY libgda-Enums SYSTEM "xml/gda-enums.xml">
-<!ENTITY libgda-convenient SYSTEM "xml/gda-convenient.xml">
-<!ENTITY libgda-GdaDataComparator SYSTEM "xml/gda-data-comparator.xml">
-<!ENTITY provider-writing SYSTEM "prov-writing.xml">
-<!ENTITY packaging SYSTEM "packaging.xml">
-<!ENTITY packaging-ui SYSTEM "packaging_ui.xml">
-<!ENTITY provider-support SYSTEM "xml/provider-support.xml">
-<!ENTITY provider-support-sql SYSTEM "xml/provider-support-sql.xml">
-<!ENTITY i-s-doc SYSTEM "i_s_doc.xml">
-<!ENTITY fdl-appendix SYSTEM "fdl-appendix.sgml">
-<!ENTITY howto SYSTEM "howto.xml">
-<!ENTITY libgda-TreeIndex SYSTEM "xml/tree_index.sgml">
-<!ENTITY GdaSqlManual SYSTEM "gda-sql-manual.xml">
-<!ENTITY GdaAttributesManager SYSTEM "xml/gda-attributes-manager.xml">
-<!ENTITY libgda-GdaTree SYSTEM "xml/gda-tree.xml">
-<!ENTITY libgda-GdaTreeManager SYSTEM "xml/gda-tree-manager.xml">
-<!ENTITY libgda-GdaTreeNode SYSTEM "xml/gda-tree-node.xml">
-<!ENTITY libgda-GdaTreeMgrLabel SYSTEM "xml/gda-tree-mgr-label.xml">
-<!ENTITY libgda-GdaTreeMgrSelect SYSTEM "xml/gda-tree-mgr-select.xml">
-<!ENTITY libgda-GdaTreeMgrSchemas SYSTEM "xml/gda-tree-mgr-schemas.xml">
-<!ENTITY libgda-GdaTreeMgrTables SYSTEM "xml/gda-tree-mgr-tables.xml">
-<!ENTITY libgda-GdaTreeMgrColumns SYSTEM "xml/gda-tree-mgr-columns.xml">
-<!ENTITY libgda-GdaSqlBuilder SYSTEM "xml/gda-sql-builder.xml">
-<!ENTITY libgda-GdaThreadWrapper SYSTEM "xml/gda-thread-wrapper.xml">
-
-<!ENTITY visual-index SYSTEM "visual_index.xml">
-<!ENTITY libgdaui-GdauiBasicForm SYSTEM "xml/gdaui-basic-form.xml">
-<!ENTITY libgdaui-GdauiCombo SYSTEM "xml/gdaui-combo.xml">
-<!ENTITY libgdaui-GdauiDataEntry SYSTEM "xml/gdaui-data-entry.xml">
-<!ENTITY libgdaui-gdaui-easy SYSTEM "xml/gdaui-easy.xml">
-<!ENTITY libgdaui-gdaui-plugins SYSTEM "xml/gdaui-plugins.xml">
-<!ENTITY libgdaui-GdauiDataStore SYSTEM "xml/gdaui-data-store.xml">
-<!ENTITY libgdaui-GdauiDataFilter SYSTEM "xml/gdaui-data-filter.xml">
-<!ENTITY libgdaui-GdauiDataProxy SYSTEM "xml/gdaui-data-proxy.xml">
-<!ENTITY libgdaui-GdauiDataProxyInfo SYSTEM "xml/gdaui-data-proxy-info.xml">
-<!ENTITY libgdaui-GdauiForm SYSTEM "xml/gdaui-form.xml">
-<!ENTITY libgdaui-GdauiGrid SYSTEM "xml/gdaui-grid.xml">
-<!ENTITY libgdaui-GdauiLogin SYSTEM "xml/gdaui-login.xml">
-<!ENTITY libgdaui-GdauiProviderSelector SYSTEM "xml/gdaui-provider-selector.xml">
-<!ENTITY libgdaui-GdauiRawForm SYSTEM "xml/gdaui-raw-form.xml">
-<!ENTITY libgdaui-GdauiRawGrid SYSTEM "xml/gdaui-raw-grid.xml">
-<!ENTITY libgdaui-GdauiServerOperation SYSTEM "xml/gdaui-server-operation.xml">
-<!ENTITY libgdaui-GdauiTreeStore SYSTEM "xml/gdaui-tree-store.xml">
-<!ENTITY libgdaui-GdauiCloud SYSTEM "xml/gdaui-cloud.xml">
-<!ENTITY libgdaui-GdauiDataSelector SYSTEM "xml/gdaui-data-selector.xml">
-<!ENTITY libgdaui-GdauiRtEditor SYSTEM "xml/gdaui-rt-editor.xml">
+<!ENTITY gda-list-server-op "<command>gda-list-server-op-5.0</command>">
+<!ENTITY gda-list-config "<command>gda-list-config-5.0</command>">
+<!ENTITY gda-sql         "<command>gda-sql</command>">
+<!ENTITY gda-test-connection "<command>gda-test-connection-5.0</command>">
 ]>
-
-<book id="index">
+<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude";>
   <bookinfo>
-    <title>GNOME Data Access 4 manual</title>
+    <title>GNOME Data Access 5 manual</title>
     <releaseinfo>for version &version;</releaseinfo>
     <authorgroup>
       <author>
@@ -237,7 +98,7 @@
     <date>&builddate;</date>
     <copyright>
       <year>1999 - 2011</year>
-      <holder>The GNOME Foundation</holder>
+      <holder>&copy;</holder>
     </copyright>
     <abstract>
       <para>
@@ -325,7 +186,7 @@
     <chapter id="features">
       <title>Features</title>
       <para>
-	This section presents the main features of the 4.0 version of Libgda.
+	This section presents the main features of the 5.0 version of Libgda.
       </para>
       <para>
 	Libgda is a low-level database abstraction layer built on top of each database C API. In terms of abstraction, 
@@ -443,12 +304,12 @@
       </mediaobject>
     </chapter>
 
-    &install;
-    &examples;
-    &migration;
-    &migration2;
-    &provnotes;
-    &limitations;
+    <xi:include href="installation.xml"/>
+    <xi:include href="gettingstarted.xml"/>
+    <xi:include href="migration.xml"/>
+    <xi:include href="migration2.xml"/>
+    <xi:include href="prov-notes.xml"/>
+    <xi:include href="limitations.xml"/>
   </part>  
   <part id="part_libgda_api">
     <title>API reference</title>
@@ -543,17 +404,17 @@
 
     </chapter>
 
-    &howto;
+    <xi:include href="howto.xml"/>
     <chapter>
       <title>Object Hierarchy</title>
-      &libgda-TreeIndex;
+      <xi:include href="xml/tree_index.sgml"/>
     </chapter>
 
     <chapter id="init_config">
       <title>Initialization and configuration</title>
       <para>Configuration examples are given in <link linkend="installation-configuring">this introduction section</link></para>
-      &libgda-init;
-      &libgda-config;
+      <xi:include href="xml/libgda.xml"/>
+      <xi:include href="xml/gda-config.xml"/>
       <sect1 id="libgda_env_variables">
 	<title>Configuring &LIBGDA; with environment variables</title>
 	<para>Some functional aspects of &LIBGDA; can be configured using environment variables which are
@@ -670,30 +531,29 @@
 	  </textobject>
 	</mediaobject>
       </para>
-      &libgda-convenient;
-      &libgda-GdaConnection;
-      &libgda-GdaSqlParser;
-      &libgda-GdaSqlBuilder;
-      &libgda-GdaStatement;
-      &libgda-GdaRepetitiveStatement;
-      &libgda-GdaBatch;
-      &libgda-GdaHolder;
-      &libgda-GdaSet;
-      &libgda-GdaConnection-event;
-      &libgda-transaction-status;
-      &libgda-xa-transaction;
-      &GdaStoreMetaType;
+      <xi:include href="xml/gda-connection.xml"/>
+      <xi:include href="xml/gda-sql-parser.xml"/>
+      <xi:include href="xml/gda-sql-builder.xml"/>
+      <xi:include href="xml/gda-statement.xml"/>
+      <xi:include href="xml/gda-repetitive-statement.xml"/>
+      <xi:include href="xml/gda-batch.xml"/>
+      <xi:include href="xml/gda-holder.xml"/>
+      <xi:include href="xml/gda-set.xml"/>
+      <xi:include href="xml/gda-connection-event.xml"/>
+      <xi:include href="xml/gda-transaction-status.xml"/>
+      <xi:include href="xml/gda-xa-transaction.xml"/>
+      <xi:include href="store-meta-type.xml"/>
     </chapter>
 
     <chapter id="virtual_connection">
       <title>Virtual connections</title>
-      &libgda-virtual;
-      &libgda-GdaVirtualProvider;
-      &libgda-GdaVproviderDataModel;
-      &libgda-GdaVproviderHub;
-      &libgda-GdaVirtualConnection;
-      &libgda-GdaVconnectionDataModel;
-      &libgda-GdaVconnectionHub;
+      <xi:include href="virtual.xml"/>
+      <xi:include href="xml/gda-virtual-provider.xml"/>
+      <xi:include href="xml/gda-vprovider-data-model.xml"/>
+      <xi:include href="xml/gda-vprovider-hub.xml"/>
+      <xi:include href="xml/gda-virtual-connection.xml"/>
+      <xi:include href="xml/gda-vconnection-data-model.xml"/>
+      <xi:include href="xml/gda-vconnection-hub.xml"/>
     </chapter>
 
     <chapter id="data_models">
@@ -738,22 +598,22 @@
 	  </listitem>
 	</itemizedlist>
       </para>
-      &libgda-GValue;
-      &data-validation;
-      &data-select;
-      &libgda-GdaBlobOp;
-      &libgda-GdaDataModel;
-      &libgda-GdaDataSelect;
-      &libgda-GdaColumn;
-      &libgda-GdaDataModelIter;
-      &libgda-GdaDataModelImport;
-      &libgda-GdaDataAccessWrapper;
-      &libgda-GdaDataModelArray;
-      &libgda-GdaRow;
-      &libgda-GdaDataModelBdb;
-      &libgda-GdaDataModelDir;
-      &libgda-GdaDataProxy;
-      &libgda-GdaDataComparator;
+      <xi:include href="xml/gda-value.xml"/>
+      <xi:include href="data_validation.xml"/>
+      <xi:include href="data_select.xml"/>
+      <xi:include href="xml/gda-blob-op.xml"/>
+      <xi:include href="xml/gda-data-model.xml"/>
+      <xi:include href="xml/gda-data-select.xml"/>
+      <xi:include href="xml/gda-column.xml"/>
+      <xi:include href="xml/gda-data-model-iter.xml"/>
+      <xi:include href="xml/gda-data-model-import.xml"/>
+      <xi:include href="xml/gda-data-access-wrapper.xml"/>
+      <xi:include href="xml/gda-data-model-array.xml"/>
+      <xi:include href="xml/gda-row.xml"/>
+      <xi:include href="xml/gda-data-model-bdb.xml"/>
+      <xi:include href="xml/gda-data-model-dir.xml"/>
+      <xi:include href="xml/gda-data-proxy.xml"/>
+      <xi:include href="xml/gda-data-comparator.xml"/>
     </chapter>
 
     <chapter id="trees">
@@ -910,14 +770,14 @@ else {
 g_object_unref (tree);
 	</programlisting>
       </para>
-      &libgda-GdaTree;
-      &libgda-GdaTreeManager;
-      &libgda-GdaTreeNode;
-      &libgda-GdaTreeMgrLabel;
-      &libgda-GdaTreeMgrSelect;
-      &libgda-GdaTreeMgrSchemas;
-      &libgda-GdaTreeMgrTables;
-      &libgda-GdaTreeMgrColumns;
+      <xi:include href="xml/gda-tree.xml"/>
+      <xi:include href="xml/gda-tree-manager.xml"/>
+      <xi:include href="xml/gda-tree-node.xml"/>
+      <xi:include href="xml/gda-tree-mgr-label.xml"/>
+      <xi:include href="xml/gda-tree-mgr-select.xml"/>
+      <xi:include href="xml/gda-tree-mgr-schemas.xml"/>
+      <xi:include href="xml/gda-tree-mgr-tables.xml"/>
+      <xi:include href="xml/gda-tree-mgr-columns.xml"/>
     </chapter>
 
     <chapter id="data_conv">
@@ -936,7 +796,7 @@ g_object_unref (tree);
 	need to unref() it after usage, data handler objects are stateless), and so to obtain such a pointer one can:
 	<itemizedlist>
 	  <listitem>
-	    <para>Use the <link linkend="gda-get-default-handler">gda_get_default_handler()</link>: the returned data handler
+	    <para>Use the <link linkend="gda-data-handlet-get-default">gda_data_handler_get_default()</link>: the returned data handler
 	      is a generic one and should not be used to convert data to use with any connection, but only to have
 	      a portable way of storing and loading data in a locale independent fashion (for serialization purposes).</para>
 	  </listitem>
@@ -949,13 +809,13 @@ g_object_unref (tree);
 	  </listitem>
 	</itemizedlist>
       </para>
-      &libgda-GdaDataHandler;
-      &libgda-GdaHandlerString;
-      &libgda-GdaHandlerBoolean;
-      &libgda-GdaHandlerTime;
-      &libgda-GdaHandlerNumerical;
-      &libgda-GdaHandlerBin;
-      &libgda-GdaHandlerType;
+      <xi:include href="xml/gda-data-handler.xml"/>
+      <xi:include href="xml/gda-handler-string.xml"/>
+      <xi:include href="xml/gda-handler-boolean.xml"/>
+      <xi:include href="xml/gda-handler-time.xml"/>
+      <xi:include href="xml/gda-handler-numerical.xml"/>
+      <xi:include href="xml/gda-handler-bin.xml"/>
+      <xi:include href="xml/gda-handler-type.xml"/>
     </chapter>
 
     <chapter id="gda-dict">
@@ -1272,64 +1132,64 @@ g_object_unref (store);
 	</sect2>
 
 	<!-- tables and views documentation -->
-	&i-s-doc;
+	<xi:include href="i_s_doc.xml"/>
       </sect1>
 
-      &libgda-GdaMetaStore;
-      &libgda-GdaMetaStruct;
+      <xi:include href="xml/gda-meta-store.xml"/>
+      <xi:include href="xml/gda-meta-struct.xml"/>
     </chapter>
 
     <chapter>
       <title>Data definition (DDL) queries</title>
-      &libgda-serverop-intro;
-      &libgda-GdaServerOperation;
-      &libgda-GdaServerOperationNodes;
-      &libgda-GdaServerOperationSequences;
+      <xi:include href="server-operation.xml"/>
+      <xi:include href="xml/gda-server-operation.xml"/>
+      <xi:include href="xml/gda-server-operation-nodes.xml"/>
+      <xi:include href="xml/gda-server-operation-sequences.xml"/>
     </chapter>
 
     <chapter>
       <title>User interface API reference</title>
-      &visual-index;
-
-      &libgdaui-init;
-      &libgdaui-GdauiLogin;
-      &libgdaui-GdauiProviderSelector;
-
-      &libgdaui-GdauiDataSelector;
-      &libgdaui-GdauiDataProxy;
-      &libgdaui-GdauiBasicForm;
-      &libgdaui-GdauiForm;
-      &libgdaui-GdauiRawForm;
-      &libgdaui-GdauiGrid;
-      &libgdaui-GdauiRawGrid;
-      &libgdaui-GdauiCombo;
-      &libgdaui-GdauiCloud;
-      &libgdaui-GdauiRtEditor;
-
-      &libgdaui-gdaui-plugins;
-
-      &libgdaui-GdauiDataEntry;
-      &libgdaui-GdauiDataStore;
-      &libgdaui-GdauiDataFilter;
-      &libgdaui-GdauiDataProxyInfo;
-      &libgdaui-GdauiServerOperation;
-      &libgdaui-GdauiTreeStore;
-
-      &libgdaui-gdaui-easy;
+      <xi:include href="visual_index.xml"/>
+
+      <xi:include href="xml/libgdaui.xml"/>
+
+      <xi:include href="xml/gdaui-login.xml"/>
+      <xi:include href="xml/gdaui-provider-selector.xml"/>
+
+      <xi:include href="xml/gdaui-data-selector.xml"/>
+      <xi:include href="xml/gdaui-data-proxy.xml"/>
+      <xi:include href="xml/gdaui-basic-form.xml"/>
+      <xi:include href="xml/gdaui-form.xml"/>
+      <xi:include href="xml/gdaui-raw-form.xml"/>
+      <xi:include href="xml/gdaui-grid.xml"/>
+      <xi:include href="xml/gdaui-raw-grid.xml"/>
+      <xi:include href="xml/gdaui-combo.xml"/>
+      <xi:include href="xml/gdaui-cloud.xml"/>
+      <xi:include href="xml/gdaui-rt-editor.xml"/>
+      <xi:include href="xml/gdaui-plugins.xml"/>
+
+      <xi:include href="xml/gdaui-data-entry.xml"/>
+      <xi:include href="xml/gdaui-data-store.xml"/>
+      <xi:include href="xml/gdaui-data-filter.xml"/>
+      <xi:include href="xml/gdaui-data-proxy-info.xml"/>
+      <xi:include href="xml/gdaui-server-operation.xml"/>
+      <xi:include href="xml/gdaui-tree-store.xml"/>
+
+      <xi:include href="xml/gdaui-easy.xml"/>
     </chapter>
 
     <chapter id="multi-threading">
       <title>Multi threading</title>
-      &libgda-GdaMutex;
-      &libgda-GdaLockable;
-      &libgda-GdaThreadWrapper;      
+      <xi:include href="xml/gda-mutex.xml"/>
+      <xi:include href="xml/gda-lockable.xml"/>
+      <xi:include href="xml/gda-thread-wrapper.xml"/>
     </chapter>
 
     <chapter id="misc">
       <title>Miscellaneous</title>
-      &libgda-util;
-      &libgda-log;
-      &GdaAttributesManager;
+      <xi:include href="xml/gda-util.xml"/>
+      <xi:include href="xml/gda-log.xml"/>
+      <xi:include href="xml/gda-attributes-manager.xml"/>
     </chapter>
   </part>
 
@@ -1356,19 +1216,19 @@ g_object_unref (store);
       <para>
 	For example to list the installed providers, do:
 	<programlisting>
-[prompt]> gda-sql-4.0 -L
+[prompt]> gda-sql-5.0 -L
 Provider    | Description                       | DSN parameters     | File                                          
 ------------+-----------------------------------+--------------------+-----------------------------------------------
-SQLite      | Provider for SQLite databases     | DB_NAME,           | /usr/lib/libgda-4.0/providers/libgda-sqlite.so  
+SQLite      | Provider for SQLite databases     | DB_NAME,           | /usr/lib/libgda-5.0/providers/libgda-sqlite.so  
                                                   DB_DIR,                                                            
                                                   LOAD_GDA_FUNCTIONS                                                       
-Berkeley-DB | Provider for Berkeley databases   | FILE,              | /usr/lib/libgda-4.0/providers/libgda-bdb.so 
+Berkeley-DB | Provider for Berkeley databases   | FILE,              | /usr/lib/libgda-5.0/providers/libgda-bdb.so 
                                                   DATABASE                                                                
 [...]
 	</programlisting>
 	To list the configured data sources (DSN):
 	<programlisting>
-[prompt]> gda-sql-4.0 -l
+[prompt]> gda-sql-5.0 -l
 DSN      | Provider   | Description  | Connection string      | Username
 ---------+------------+--------------+------------------------+---------
 Sales    | PostgreSQL | Sales        | DB_NAME=sales          |
@@ -1380,7 +1240,7 @@ Sales    | PostgreSQL | Sales        | DB_NAME=sales          |
 	the GDA_SQL_CNC environment variable to contain that string, and run the command without any argument, 
 	for example:
 	<programlisting>
-[prompt]> gda-sql-4.0 PostgreSQL://DB_NAME=sales
+[prompt]> gda-sql-5.0 PostgreSQL://DB_NAME=sales
 Welcome to the GDA SQL console, version 3.99.3
 
 Type: .copyright to show usage and distribution terms
@@ -1403,7 +1263,7 @@ c0>
 	DSN, and one for the "PostgreSQL://DB_NAME=sales" connection string, and shows the usage of the ".c" command
 	to list the opened connections:
 	<programlisting>
-[prompt]> gda-sql-4.0 pgsales PostgreSQL://DB_NAME=sales
+[prompt]> gda-sql-5.0 pgsales PostgreSQL://DB_NAME=sales
 Welcome to the GDA SQL console, version 3.99.3
 
 Type: .copyright to show usage and distribution terms
@@ -1429,7 +1289,7 @@ c1>
       <para>
 	Here is another sample session showing how to use variables in statements:
 	<programlisting><![CDATA[
-[prompt]> gda-sql-4.0 -p SQLite -c "DB_DIR=.;DB_NAME=sales_test"
+[prompt]> gda-sql-5.0 -p SQLite -c "DB_DIR=.;DB_NAME=sales_test"
 Welcome to the GDA SQL console, version 3.1.2
 
 Type: \copyright to show usage and distribution terms
@@ -1467,11 +1327,11 @@ c0> ]]>
       <para>
 	An example output will be:
 	<programlisting>
-[prompt]> gda-list-config-4.0
+[prompt]> gda-list-config-5.0
 === Installed providers ===
 Provider: SQLite
 Description: Provider for SQLite databases
-Location: /usr/lib/libgda-4.0/providers/libgda-sqlite.so
+Location: /usr/lib/libgda-5.0/providers/libgda-sqlite.so
 Data source's parameters (Name / Type / Description):
   DB_NAME / gchararray / Database name
   DB_DIR / gchararray / Directory
@@ -1479,7 +1339,7 @@ Data source's parameters (Name / Type / Description):
 
 Provider: Berkeley-DB
 Description: Provider for Berkeley databases
-Location: /usr/lib/libgda-4.0/providers/libgda-bdb.so
+Location: /usr/lib/libgda-5.0/providers/libgda-bdb.so
 Data source's parameters (Name / Type / Description):
   FILE / gchararray / Database file
   DATABASE / gchararray / Database name
@@ -1519,8 +1379,8 @@ Data source: Sales
       <para>
 	For example listing all the possible operations (for all the providers) is:
 	<programlisting>
-[prompt]> gda-list-server-op-4.0 -l
-Using XML descriptions in /usr/share/libgda-4.0
+[prompt]> gda-list-server-op-5.0 -l
+Using XML descriptions in /usr/share/libgda-5.0
 Existing operation types:
 CREATE_DB
 DROP_DB
@@ -1535,8 +1395,8 @@ DROP_INDEX
 	Listing all the operations supported by the SQLite provider (notice that the SQLite provider does not support the
 	DROP_COLUMN operation as SQLite does not support it):
 	<programlisting>
-[prompt]> gda-list-server-op-4.0 -l -p SQLite
-Using XML descriptions in /usr/share/libgda-4.0
+[prompt]> gda-list-server-op-5.0 -l -p SQLite
+Using XML descriptions in /usr/share/libgda-5.0
 For provider SQLite
 Existing operation types for provider 'SQLite':
 CREATE_DB
@@ -1550,8 +1410,8 @@ DROP_INDEX
 	</programlisting>
 	Listing all the possible parameters for the MySQL provider and for the DROP_COLUMN operation:
 	<programlisting><![CDATA[
-[prompt]> gda-list-server-op-4.0 -o DROP_COLUMN -p MySQL
-Using XML descriptions in /usr/share/libgda-4.0
+[prompt]> gda-list-server-op-5.0 -o DROP_COLUMN -p MySQL
+Using XML descriptions in /usr/share/libgda-5.0
 For provider MySQL
 Description for type: DROP_COLUMN
 <?xml version="1.0"?>
@@ -1563,8 +1423,8 @@ Description for type: DROP_COLUMN
 	</programlisting>
 	Listing all the possible parameters for the all the installed providers and for the DROP_COLUMN operation:
 	<programlisting><![CDATA[
-[prompt]> gda-list-server-op-4.0 -o DROP_COLUMN 
-Using XML descriptions in /usr/share/libgda-4.0
+[prompt]> gda-list-server-op-5.0 -o DROP_COLUMN 
+Using XML descriptions in /usr/share/libgda-5.0
 Description for type: DROP_COLUMN
 <?xml version="1.0"?>
 <server_op>
@@ -1701,10 +1561,10 @@ g_object_unref (eng);
     </chapter>
     <chapter>
       <title>API reference</title>
-      &libgda-GdaReportEngine;
-      &libgda-GdaReportDocument;
-      &libgda-GdaReportDocbookDocument;
-      &libgda-GdaReportRmlDocument;
+      <xi:include href="xml/gda-report-engine.xml"/>
+      <xi:include href="xml/gda-report-document.xml"/>
+      <xi:include href="xml/gda-report-docbook-document.xml"/>
+      <xi:include href="xml/gda-report-rml-document.xml"/>
     </chapter>
   </part>
 
@@ -1726,10 +1586,7 @@ g_object_unref (eng);
     </chapter>
   </part>
 
-  <part id="gda-sql">
-    <title>Gda SQL console's user manual</title>
-    &GdaSqlManual;
-  </part>
+  <xi:include href="gda-sql-manual.xml"/>
 
   <part id="part_providers">
     <title>Databases providers for developers</title>
@@ -1765,57 +1622,62 @@ g_object_unref (eng);
       <link linkend="psupport">Providers' support API</link> section.
     </para>
 
+    <chapter>
+      <title>Getting started</title>
+      <para>
+	&LIBGDA;'s sources contain templates to get started in creating a new database provider. The following templates
+	are available:
+	<itemizedlist>
+	  <listitem><para>the template in the <filename class="directory">providers/skel-implementation/capi</filename>
+	      directory which can be used when writing a provider using the database's C or C++ API (for example
+	      the PostgreSQL or MySQL providers)</para></listitem>
+	  <listitem><para>the template in the <filename class="directory">providers/skel-implementation/models</filename>
+	      directory which can be used when writing a provider for a system which is not a relational database (or
+	      does offer a very limited API, such as for the MS Access or Berkeley DB systems).</para></listitem>
+	</itemizedlist>
+      </para>
+      <para>
+	In any case, for example to create a DummyDb provider, follow these steps:
+	<itemizedlist>
+	  <listitem><para>copy one of the template's directory into a new directory named
+	      <filename class="directory">dummydb</filename></para></listitem>
+	  <listitem><para>From inside that new directory, run the
+	      <filename class="directory">providers/prepare_provider_sources.sh</filename> script with the name
+	      of the provider as sole argument ("dummydb" here), which replaces
+	      all the class and object names with the name of the provider and renames the files correctly. These
+	      new sources should be compilable without any modification.</para></listitem>
+	  <listitem><para>Edit the <filename>Makefile.am</filename> to add provider specific compilation and link
+	      flags</para></listitem>
+	  <listitem><para>Integrate the provider's new code into a compilation unit: either &LIBGDA;'s sources in
+	      the <filename class="directory">providers</filename>directory or in your own application (this step usually involves
+	      modifying the <filename>configure.ac</filename> or <filename>configure.in</filename> files).</para></listitem>
+	  <listitem><para>Implement the missing parts (it is usually a good idea to look how other provider's
+	      implementations are done to get ideas).</para></listitem>
+	</itemizedlist>
+      </para>
+    </chapter>
+
+    <xi:include href="prov-writing-virtual-methods.xml"/>
+    <xi:include href="prov-writing-recordsets.xml"/>
+    <xi:include href="prov-writing-blobs.xml"/>
+    <xi:include href="prov-writing-parser.xml"/>
+    <xi:include href="prov-writing-assembly.xml"/>
 
     <chapter id="psupport">
       <title>Providers' support API</title>
-      &libgda-GdaServerProvider;
-      &libgda-GdaDataSelectPriv;
-      &libgda-PStmt;
-      &libgda-quark-list;
-      &provider-support-sql;
-      &provider-support;
+      <xi:include href="xml/gda-server-provider.xml"/>
+      <xi:include href="xml/gda-data-select-priv.xml"/>
+      <xi:include href="xml/gda-pstmt.xml"/>
+      <xi:include href="xml/gda-quark-list.xml"/>
+      <xi:include href="xml/provider-support-sql.xml"/>
+      <xi:include href="xml/provider-support.xml"/>
     </chapter>
-<sect1>
-    <title>Getting started</title>
-    <para>
-      &LIBGDA;'s sources contain templates to get started in creating a new database provider. The following templates
-      are available:
-      <itemizedlist>
-	<listitem><para>the template in the <filename class="directory">providers/skel-implementation/capi</filename>
-	    directory which can be used when writing a provider using the database's C or C++ API (for example
-	    the PostgreSQL or MySQL providers)</para></listitem>
-	<listitem><para>the template in the <filename class="directory">providers/skel-implementation/models</filename>
-	    directory which can be used when writing a provider for a system which is not a relational database (or
-	    does offer a very limited API, such as for the MS Access or Berkeley DB systems).</para></listitem>
-      </itemizedlist>
-    </para>
-    <para>
-      In any case, for example to create a DummyDb provider, follow these steps:
-      <itemizedlist>
-	<listitem><para>copy one of the template's directory into a new directory named
-	    <filename class="directory">dummydb</filename></para></listitem>
-	<listitem><para>From inside that new directory, run the
-	    <filename class="directory">providers/prepare_provider_sources.sh</filename> script with the name
-	    of the provider as sole argument ("dummydb" here), which replaces
-	    all the class and object names with the name of the provider and renames the files correctly. These
-	    new sources should be compilable without any modification.</para></listitem>
-	<listitem><para>Edit the <filename>Makefile.am</filename> to add provider specific compilation and link
-	    flags</para></listitem>
-	<listitem><para>Integrate the provider's new code into a compilation unit: either &LIBGDA;'s sources in
-	    the <filename class="directory">providers</filename>directory or in your own application (this step usually involves
-	    modifying the <filename>configure.ac</filename> or <filename>configure.in</filename> files).</para></listitem>
-	<listitem><para>Implement the missing parts (it is usually a good idea to look how other provider's
-	    implementations are done to get ideas).</para></listitem>
-      </itemizedlist>
-    </para>
-  </sect1>
-    &provider-writing;
   </part>
 
   <part>
     <title>Packaging</title>
-    &packaging;
-    &packaging-ui;
+    <xi:include href="packaging.xml"/>
+    <xi:include href="packaging_ui.xml"/>
   </part>
 
   <part id="part_index">
@@ -1838,10 +1700,13 @@ g_object_unref (eng);
     <index id="index-4-2-4" role="4.2.4">
       <title>Index of new symbols in 4.2.4</title>
     </index>
+    <index id="index-5-0" role="5.0">
+      <title>Index of new symbols in 5.0</title>
+    </index>
     <index id="index-deprecated" role="deprecated">
       <title>Index of deprecated symbols</title>
     </index>
-    &fdl-appendix;
+    <xi:include href="fdl-appendix.sgml"/>
   </part>
 </book>
 
diff --git a/doc/C/libgda-sections.txt b/doc/C/libgda-sections.txt
index a98e8b4..837d53f 100644
--- a/doc/C/libgda-sections.txt
+++ b/doc/C/libgda-sections.txt
@@ -603,8 +603,11 @@ gda_virtual_connection_get_type
 GdaVconnectionDataModel
 GdaVconnectionDataModelFunc
 GdaVconnectionDataModelSpec
+GdaVconnectionDataModelFilter
 GdaVconnectionDataModelCreateColumnsFunc
 GdaVconnectionDataModelCreateModelFunc
+GdaVconnectionDataModelParseFilterFunc
+GdaVconnectionDataModelCreateFModelFunc
 gda_vconnection_data_model_add
 gda_vconnection_data_model_add_model
 gda_vconnection_data_model_remove
@@ -813,7 +816,6 @@ gda_value_set_ushort
 <SUBSECTION Standard>
 gda_binary_get_type
 gda_geometricpoint_get_type
-gda_value_list_get_type
 gda_numeric_get_type
 gda_time_get_type
 gda_timestamp_get_type
@@ -929,31 +931,6 @@ gda_handler_type_get_type
 </SECTION>
 
 <SECTION>
-<FILE>gda-convenient</FILE>
-<TITLE>Convenience functions</TITLE>
-gda_prepare_create_database
-gda_perform_create_database
-gda_prepare_drop_database
-gda_perform_drop_database
-<SUBSECTION>
-gda_execute_select_command
-gda_execute_non_select_command
-<SUBSECTION>
-gda_prepare_create_table
-gda_perform_create_table
-gda_prepare_drop_table
-gda_perform_drop_table
-<SUBSECTION>
-gda_insert_row_into_table
-gda_update_row_in_table
-gda_delete_row_from_table
-<SUBSECTION>
-gda_parse_sql_string
-<SUBSECTION>
-gda_get_default_handler
-</SECTION>
-
-<SECTION>
 <FILE>gda-report-engine</FILE>
 <TITLE>GdaReportEngine</TITLE>
 <INCLUDE>libgda-report/gda-report-engine.h</INCLUDE>
@@ -1153,9 +1130,6 @@ gda_sql_parser_parse_string_as_batch
 gda_sql_parser_parse_file_as_batch
 <SUBSECTION>
 gda_sql_identifier_quote
-gda_sql_identifier_needs_quotes
-gda_sql_identifier_add_quotes
-gda_sql_identifier_remove_quotes
 gda_sql_identifier_split
 <SUBSECTION Standard>
 GDA_IS_SQL_PARSER
@@ -1486,7 +1460,6 @@ gda_connection_internal_get_provider_data
 gda_connection_add_event
 gda_connection_add_event_string
 gda_connection_clear_events_list
-gda_connection_event_new
 gda_connection_event_set_event_type
 gda_connection_event_set_description
 gda_connection_event_set_code
@@ -1525,6 +1498,9 @@ gda_compute_unique_table_row_condition_with_cnc
 gda_sql_any_part_check_structure
 <SUBSECTION>
 gda_statement_rewrite_for_default_values
+<SUBSECTION>
+gda_sql_identifier_force_quotes
+gda_sql_identifier_prepare_for_compare
 </SECTION>
 
 <SECTION>
diff --git a/doc/C/libgda.types.in b/doc/C/libgda.types.in
index 448e17c..421edb3 100644
--- a/doc/C/libgda.types.in
+++ b/doc/C/libgda.types.in
@@ -34,7 +34,6 @@ gda_server_provider_get_type
 gda_transaction_status_get_type
 gda_binary_get_type
 gda_geometricpoint_get_type
-gda_value_list_get_type
 gda_numeric_get_type
 gda_time_get_type
 gda_timestamp_get_type
@@ -65,4 +64,4 @@ gda_tree_mgr_select_get_type
 gda_tree_mgr_tables_get_type
 gda_tree_node_get_type
 gda_sql_builder_get_type
-gda_thread_wrapper_get_type
\ No newline at end of file
+gda_thread_wrapper_get_type
diff --git a/doc/C/limitations.xml b/doc/C/limitations.xml
index e510951..066a7a4 100644
--- a/doc/C/limitations.xml
+++ b/doc/C/limitations.xml
@@ -1,3 +1,8 @@
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+          "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd";[
+<!ENTITY LIBGDA          "<application>Libgda</application>">
+]>
 <chapter id="limitations">
   <title>Limitations</title>
 
diff --git a/doc/C/migration.xml b/doc/C/migration.xml
index f5e38d7..cdd17a8 100644
--- a/doc/C/migration.xml
+++ b/doc/C/migration.xml
@@ -1,3 +1,6 @@
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+          "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd";>
 <chapter id="migration-1">
   <title>Migration from 1.X versions</title>
   <sect1><title>GdaValue and GdaDataModel changes</title>
diff --git a/doc/C/migration2.xml b/doc/C/migration2.xml
index 9db3d90..a1a893c 100644
--- a/doc/C/migration2.xml
+++ b/doc/C/migration2.xml
@@ -1,4 +1,9 @@
-<chapter id="migration-2">
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+          "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd";[
+<!ENTITY LIBGDA          "<application>Libgda</application>">
+]>
+<chapter id="migration-2" xmlns:xi="http://www.w3.org/2003/XInclude";>
   <title>Migration from 3.X versions</title>
   <sect1><title>Overview</title>
     <para>Version 4.0 of &LIBGDA; is a major rework of the library for the following benefits:
diff --git a/doc/C/packaging.xml b/doc/C/packaging.xml
index 26e2d05..ba79090 100644
--- a/doc/C/packaging.xml
+++ b/doc/C/packaging.xml
@@ -1,3 +1,8 @@
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+          "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd";[
+<!ENTITY LIBGDA          "<application>Libgda</application>">
+]>
 <chapter id="libgda-packaging">
   <title>Packaging &LIBGDA;</title>
   <para>
@@ -62,21 +67,21 @@
 |       |-- trml2pdf.py
 |       `-- utils.py
 |-- etc
-|   `-- libgda-4.0
+|   `-- libgda-5.0
 |       |-- config
 |       `-- sales_test.db
 |-- lib
-|   |-- libgda-4.0.so -> libgda-4.0.so.4.1.0
-|   |-- libgda-4.0.so.4 -> libgda-4.0.so.4.1.0
-|   |-- libgda-4.0.so.4.1.0
-|   |-- libgda-report-4.0.so -> libgda-report-4.0.so.4.1.0
-|   |-- libgda-report-4.0.so.4 -> libgda-report-4.0.so.4.1.0
-|   |-- libgda-report-4.0.so.4.1.0
-|   |-- libgda-xslt-4.0.so -> libgda-xslt-4.0.so.4.1.0
-|   |-- libgda-xslt-4.0.so.4 -> libgda-xslt-4.0.so.4.1.0
-|   |-- libgda-xslt-4.0.so.4.1.0
+|   |-- libgda-5.0.so -> libgda-5.0.so.4.1.0
+|   |-- libgda-5.0.so.4 -> libgda-5.0.so.4.1.0
+|   |-- libgda-5.0.so.4.1.0
+|   |-- libgda-report-5.0.so -> libgda-report-5.0.so.4.1.0
+|   |-- libgda-report-5.0.so.4 -> libgda-report-5.0.so.4.1.0
+|   |-- libgda-report-5.0.so.4.1.0
+|   |-- libgda-xslt-5.0.so -> libgda-xslt-5.0.so.4.1.0
+|   |-- libgda-xslt-5.0.so.4 -> libgda-xslt-5.0.so.4.1.0
+|   |-- libgda-xslt-5.0.so.4.1.0
 `-- share
-    `-- libgda-4.0
+    `-- libgda-5.0
         |-- dtd
         |   |-- libgda-array.dtd
         |   |-- libgda-paramlist.dtd
@@ -103,10 +108,10 @@
       <programlisting>
 |-- share
 |   `-- gir-1.0
-|       `-- Gda-4.0.gir
+|       `-- Gda-5.0.gir
 `-- lib
     `-- girepository-1.0
-        `-- Gda-4.0.typelib
+        `-- Gda-5.0.typelib
       </programlisting>
     </para>
   </sect1>
@@ -124,12 +129,12 @@
 	<programlisting>
 .
 `-- bin
-    |-- gda-list-config -> gda-list-config-4.0
-    |-- gda-list-config-4.0
-    |-- gda-list-jdbc-providers-4.0
-    |-- gda-list-server-op -> gda-list-server-op-4.0
-    |-- gda-list-server-op-4.0
-    `-- gda-test-connection-4.0
+    |-- gda-list-config -> gda-list-config-5.0
+    |-- gda-list-config-5.0
+    |-- gda-list-jdbc-providers-5.0
+    |-- gda-list-server-op -> gda-list-server-op-5.0
+    |-- gda-list-server-op-5.0
+    `-- gda-test-connection-5.0
       </programlisting>
       </para>
       <para>
@@ -142,7 +147,7 @@
 	<programlisting>
 .
 |-- bin
-|   `-- gda-sql-4.0
+|   `-- gda-sql-5.0
  `-- share
     |   `-- web
     |       |-- cnc.js
@@ -156,8 +161,8 @@
     |       `-- mouseirb_2.js
     `-- man
         `-- man1
-            |-- gda-sql-4.0.1
-            `-- gda-sql.1 -> gda-sql-4.0.1
+            |-- gda-sql-5.0.1
+            `-- gda-sql.1 -> gda-sql-5.0.1
 	</programlisting>
       </para>
       <para>
@@ -183,13 +188,13 @@
 	<programlisting>
 .
 |-- lib
-|   |-- libgda-4.0
+|   |-- libgda-5.0
 |   |   `-- providers
 |   |       `-- libgda-postgres.so
 |   `-- pkgconfig
-|       `-- libgda-postgres-4.0.pc
+|       `-- libgda-postgres-5.0.pc
  `-- share
-    `-- libgda-4.0
+    `-- libgda-5.0
         |-- postgres_specs_add_column.xml
         |-- postgres_specs_create_db.xml
         |-- postgres_specs_create_index.xml
@@ -226,14 +231,14 @@
 	<programlisting>
 .
 |-- lib
-|   |-- libgda-4.0
+|   |-- libgda-5.0
 |   |   `-- providers
-|   |       |-- gdaprovider-4.0.jar
+|   |       |-- gdaprovider-5.0.jar
 |   |       `-- libgda-jdbc.so
 |   `-- pkgconfig
-|       `-- libgda-jdbc-4.0.pc
+|       `-- libgda-jdbc-5.0.pc
  `-- share
-    `-- libgda-4.0
+    `-- libgda-5.0
         |-- jdbc_specs_create_table.xml
         `-- jdbc_specs_dsn.xml
 	</programlisting>
@@ -251,20 +256,20 @@
       the static libraries.
       <programlisting>
 |-- include
-|   `-- libgda-4.0
+|   `-- libgda-5.0
 |     [... except the libgdaui/ directory ...]
 `-- lib
-    |-- libgda-4.0
-    |-- libgda-4.0.a
-    |-- libgda-4.0.la
-    |-- libgda-report-4.0.a
-    |-- libgda-report-4.0.la
-    |-- libgda-xslt-4.0.a
-    |-- libgda-xslt-4.0.la
+    |-- libgda-5.0
+    |-- libgda-5.0.a
+    |-- libgda-5.0.la
+    |-- libgda-report-5.0.a
+    |-- libgda-report-5.0.la
+    |-- libgda-xslt-5.0.a
+    |-- libgda-xslt-5.0.la
     `-- pkgconfig
-        |-- libgda-4.0.pc
-        |-- libgda-report-4.0.pc
-        `-- libgda-xslt-4.0.pc
+        |-- libgda-5.0.pc
+        |-- libgda-report-5.0.pc
+        `-- libgda-xslt-5.0.pc
       </programlisting>
     </para>
   </sect1>
diff --git a/doc/C/packaging_ui.xml b/doc/C/packaging_ui.xml
index 242880e..3683eda 100644
--- a/doc/C/packaging_ui.xml
+++ b/doc/C/packaging_ui.xml
@@ -1,3 +1,8 @@
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+          "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd";[
+<!ENTITY LIBGDA          "<application>Libgda</application>">
+]>
 <chapter id="libgdaui-packaging">
   <title>Packaging &LIBGDA; UI extension</title>
   <para>
@@ -53,7 +58,7 @@
       <programlisting>
 .
 |-- lib
-|   |-- libgda-4.0
+|   |-- libgda-5.0
 |   |   |-- plugins
 |   |   |   |-- gdaui-entry-filesel-spec.xml
 |   |   |   |-- gdaui-entry-password.xml
@@ -61,11 +66,11 @@
 |   |   |   |-- gdaui-entry-pict-spec_string.xml
 |   |   |   |-- gdaui-entry-text-spec.xml
 |   |   |   `-- libgdaui-plugins.so
-|   |-- libgdaui-4.0.so -> libgdaui-4.0.so.4.1.0
-|   |-- libgdaui-4.0.so.4 -> libgdaui-4.0.so.4.1.0
-|   `-- libgdaui-4.0.so.4.1.0
+|   |-- libgdaui-5.0.so -> libgdaui-5.0.so.4.1.0
+|   |-- libgdaui-5.0.so.4 -> libgdaui-5.0.so.4.1.0
+|   `-- libgdaui-5.0.so.4.1.0
 `-- share
-    `-- libgda-4.0
+    `-- libgda-5.0
         |-- language-specs
         |   `-- gda-sql.lang
         |-- server_operation.glade
@@ -86,10 +91,10 @@
       <programlisting>
 |-- share
 |   `-- gir-1.0
-|       `-- Gdaui-4.0.gir
+|       `-- Gdaui-5.0.gir
 `-- lib
     `-- girepository-1.0
-        `-- Gdaui-4.0.typelib
+        `-- Gdaui-5.0.typelib
       </programlisting>
     </para>
   </sect1>
@@ -103,11 +108,11 @@
 	<programlisting>
 .
 |-- bin
-|   `-- gda-control-center-4.0
+|   `-- gda-control-center-5.0
 `-- share
     |-- applications
-    |   `-- gda-control-center-4.0.desktop
-    |-- libgda-4.0
+    |   `-- gda-control-center-5.0.desktop
+    |-- libgda-5.0
     |   `-- pixmaps
     |       `-- gdaui-generic.png
     `-- pixmaps
@@ -125,10 +130,10 @@
 	<programlisting>
 .
 |-- bin
-|   `-- gda-browser-4.0
+|   `-- gda-browser-5.0
 `-- share
     |-- applications
-    |   `-- gda-browser-4.0.desktop
+    |   `-- gda-browser-5.0.desktop
     |-- gnome
     |   `-- help
     |       `-- gda-browser
@@ -157,18 +162,18 @@
       <programlisting>
 .
 |-- bin
-|   `-- gdaui-demo-4.0
+|   `-- gdaui-demo-5.0
 |-- include
-|   `-- libgda-4.0
+|   `-- libgda-5.0
 |       `-- libgdaui
 |           [...]
 `-- lib
-|   |-- libgdaui-4.0.a
-|   |-- libgdaui-4.0.la
+|   |-- libgdaui-5.0.a
+|   |-- libgdaui-5.0.la
 |   `-- pkgconfig
-|       `-- libgdaui-4.0.pc
+|       `-- libgdaui-5.0.pc
 `-- share
-    `-- libgda-4.0
+    `-- libgda-5.0
         `-- demo
             [...]
       </programlisting>
diff --git a/doc/C/prov-notes.xml b/doc/C/prov-notes.xml
index 91f1292..9fda183 100644
--- a/doc/C/prov-notes.xml
+++ b/doc/C/prov-notes.xml
@@ -1,3 +1,6 @@
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+          "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd";>
 <chapter id="provider-notes">
   <title>Provider's notes</title>
 
diff --git a/doc/C/prov-writing-assembly.xml b/doc/C/prov-writing-assembly.xml
new file mode 100644
index 0000000..cdb37c7
--- /dev/null
+++ b/doc/C/prov-writing-assembly.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+          "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd";[
+<!ENTITY LIBGDA          "<application>Libgda</application>">
+]>
+<chapter id="libgda-provider-pack">
+  <title>Assembling all the parts</title>
+  <para>
+    A database provider is in fact a shared library which is loaded when &LIBGDA; is initialized. The skeleton implementations
+    in <filename class="directory">providers/skel-implementation</filename> propose the following files layout (some of the files
+    are not required for virtual providers).
+  </para>
+  <para> Of course this files layout is not required, but make it easy for maintenance. In the following list,
+    the filenames here are the one for the "Capi" provider, and each provider should rename them:
+    <itemizedlist>
+      <listitem><para><filename>gda-capi.h</filename>: contains the provider name, the include files necessary to use the API and the
+	  declaration of the provider's specific connection data</para></listitem>
+      <listitem><para><filename>gda-capi-provider.[ch]</filename>: are the header and implementation files for the object
+	  inheriting the <link linkend="GdaServerProvider">GdaServerProvider</link> object. This object must implement its
+	  <link linkend="libgda-provider-class">virtual methods</link>.</para></listitem>
+      <listitem><para><filename>gda-capi-recordset.[ch]</filename>: are the header and implementation files for the object
+	  inheriting the <link linkend="GdaDataSelect">GdaDataSelect</link> object. This object must implement its
+	  <link linkend="libgda-provider-recordset">virtual methods</link>.</para></listitem>
+      <listitem><para><filename>gda-capi-ddl.[ch]</filename>: are the files implementing the DDL queries</para></listitem>
+      <listitem><para><filename>gda-capi-parser.[ch]</filename>: are the header and implementation files 
+	  for the object implementing a specific parser,
+	  inheriting <link linkend="GdaSqlParser">GdaSqlParser</link>, see the PostgreSQL provider's implementation for 
+	  example.</para></listitem>
+      <listitem><para><filename>gda-capi-pstmt.[ch]</filename>: are the header and implementation files for the object
+      representing prepared statement and inheriting <link linkend="GdaPStmt">GdaPStmt</link></para></listitem>
+      <listitem><para><filename>gda-capi-blob-op.[ch]</filename>: are the header and implementation files for the object
+	  inheriting the <link linkend="GdaBlobOp">GdaBlopOp</link> object. This object must implement its
+	  <link linkend="libgda-provider-blobop">virtual methods</link>.</para></listitem>
+      <listitem><para><filename>gda-capi-meta.[ch]</filename>: are the files where the meta-data information extraction
+      is implemented.</para></listitem>
+      <listitem><para><filename>libmain.c</filename>: file to make it possible for &LIBGDA; to identify the provider.</para></listitem>
+      <listitem><para><filename>capi_specs_dsn.xml.in</filename>: file where the connection parameters are described, 
+	  before being translated</para></listitem>
+      <listitem><para><filename>libgda-capi-5.0.pc.in</filename>: file to be used by <command>pkg-config</command> to identify
+	  the provider, before being computed by the <command>configure</command> script.</para></listitem>
+      <listitem><para>other .xml.in files: DDL queries' parameters, before translation</para></listitem>
+    </itemizedlist>
+  </para>
+
+  <sect1>
+    <title>libmain.c</title>
+    <para>
+      Once the shared library implementing the provider is loaded (and
+      all the necessary dependencies are also loaded), &LIBGDA; tries to locate some functions to identify the provider (if any of
+      these function is missing, then the DLL is unloaded and the provider is not availaibe).
+    </para>
+    <para>
+      The skeleton implementations in <filename class="directory">providers/skel-implementation</filename> propose to implement those
+      functions in a <filename>libmain.c</filename> file. The functions are the following ones:
+    </para>
+    <sect2>
+      <title>plugin_init()</title>
+      <para>This function initializes the plugin; it has a single argument which is the path where the provider is.
+	As the module can be unloaded, any static data allocated here must be freed when the module is unloaded,
+	in a <link linkend="GModuleUnload">g_module_unload()</link> function. If the module must not be
+	unloaded, it must be made resident using <link linkend="g-module-make-resident">g_module_make_resident()</link>, 
+	in a <link linkend="GModuleCheckInit">g_module_check_init()</link> function</para>
+      <para>Note that after a <link linkend="GdaServerProvider">GdaServerProvider</link> object has been 
+	created (ie after plugin_create_provider() has
+	been called once), the module will not be unloaded anymore.</para>
+    </sect2>
+    <sect2>
+      <title>plugin_get_name()</title>
+      <para>This funtion returns the name of the provider, it <emphasis>must</emphasis> return the same string as what the
+	<link linkend="prov-get-name">get_name()</link>'s provider's virtual method returns.</para>
+    </sect2>
+    <sect2>
+      <title>plugin_get_description()</title>
+      <para>This funtion returns a description of the provider.</para>
+    </sect2>
+    <sect2>
+      <title>plugin_get_dsn_spec()</title>
+      <para>This function returns a description of the parameters which have or can be set when opening a connection. This
+	description uses an XML syntax and is usually stored in a separate XML file (for easier translation).</para>
+      <para>Here is an example, when only one "DB_NAME" parameter is required:
+	<programlisting>
+&lt;?xml version="1.0"?&gt;
+&lt;data-set-spec&gt;
+  &lt;parameters&gt;
+    &lt;parameter id="DB_NAME" _name="Database name" _descr="The name of a database to use" gdatype="gchararray" nullok="FALSE"/&gt;
+  &lt;/parameters&gt;
+&lt;/data-set-spec&gt;
+	</programlisting>
+	Note that the the attributes which have a name starting with an underscore should be translated (see the
+	<filename>Makefile.am</filename> file for some example on ho this is done).
+      </para>
+    </sect2>
+    <sect2>
+      <title>plugin_get_auth_spec()</title>
+      <para>
+	This function returns a description of the authentication information required by the provider. If the
+	only information is a username/password pair, then it is not necessary to implement that function.
+      </para>
+      <para>
+	However, if a username is required, then it must be name "USERNAME", and if a password is required,
+	it must be named "PASSWORD".
+      </para>
+    </sect2>
+    <sect2>
+      <title>plugin_create_provider()</title>
+      <para>This function actually instantiates a provider object and returns it.</para>
+    </sect2>
+  </sect1>
+
+</chapter>
diff --git a/doc/C/prov-writing-blobs.xml b/doc/C/prov-writing-blobs.xml
new file mode 100644
index 0000000..25808cf
--- /dev/null
+++ b/doc/C/prov-writing-blobs.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+          "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd";[
+<!ENTITY LIBGDA          "<application>Libgda</application>">
+]>
+<chapter id="libgda-provider-blobop">
+  <title>Virtual methods for Blob operations</title>
+  <para>
+    Blobs are a special feature of databases because they allow one to access the contents of a "cell" from the
+    API without using SQL (usually no SQL can be used to manipulate a blob's contents: an SQL statement is used to
+    create, delete or retrieve a blob, but the contents is accessed through the API).
+  </para>
+  <para>
+    &LIBGDA; encapsulates all blob operations in objects which must be implemented by each provider if they want to support
+    blobs; otherwise binary data may still be used if supported by the database, but the whole binary data is transferred in
+    the SQL statement which is not suitable for large data.
+  </para>
+  <para>
+    &LIBGDA; defines <link linkend="GdaBlop">GdaBlob</link> structure which is an extension of the
+    <link linkend="GdaBinary">GdaBinary</link> structure (which contains a pointer to some data and the size of the pointed
+    data). The extension simply adds a pointer to a <link linkend="GdaBlopOp">GdaBlobOp</link> object which has
+    to be implemented by each provider which supports blobs. The following documents the
+    <link linkend="GdaBlopOp">GdaBlobOp</link>'s virtual methods which actually implement the reading from and
+    writing to a blob contained in the database.
+  </para>
+  <para>
+    When reading from a blob in the database or writing to a blob in the database, data read or written is the stored in
+    the <link linkend="GdaBinary">GdaBinary</link> part of the <link linkend="GdaBlopOp">GdaBlobOp</link>.
+  </para>
+  <sect2>
+    <title>get_length()</title>
+    <para>
+      This method returns the total length of a blob in bytes. In case of error, -1 is returned and the
+      provider should have added an error (a <link linkend="GdaConnectionEvent">GdaConnectionEvent</link>) to the connection.
+    </para>
+  </sect2>
+
+  <sect2>
+    <title>read()</title>
+    <para>
+      This method requests that some data be read from the blob. The data read must be stored in the
+      <link linkend="GdaBinary">GdaBinary</link> part of the <parameter>blob</parameter> parameter. The data to read is
+      the data starting at the <parameter>offset</parameter> offset from the beginning of the blob, and
+      of the <parameter>size</parameter> length.
+    </para>
+    <para>
+      Note that in this method, the <structfield>op</structfield> attribute of the <parameter>blob</parameter>
+      parameter is not used.
+    </para>
+    <para>
+      The returned value is the number of bytes read, or -1 if an error
+      occured (then the provider should have added an error to the connection).
+    </para>
+  </sect2>
+
+  <sect2>
+    <title>write()</title>
+    <para>
+      This method requests the some data be written to the blob. The data has to be written
+      in the blob starting at the <parameter>offset</parameter> offset from the beginning of the blob.
+    </para>
+    <para>
+      If the <structfield>op</structfield> attribute of the <parameter>blob</parameter> parameter is not NULL and is different
+      than the <parameter>op</parameter>, then the data to be written is the complete contents of the data stored in the
+      blob represented by the <structfield>op</structfield> attribute of the <parameter>blob</parameter> parameter. Otherwise
+      The data to be written is stored in the
+      <link linkend="GdaBinary">GdaBinary</link> part of the <parameter>blob</parameter>.
+    </para>
+    <para>
+      The returned value is the number of bytes written, or -1 if an error
+      occured (then the provider should have added an error to the connection).
+    </para>
+  </sect2>
+
+  <sect2>
+    <title>write_all()</title>
+    <para>
+      This method requests that all the contents of the blob be replaced by some data (if necessary the
+      blob is truncated from its previous length). The data to be written is the same as for the write() method, and
+      the returned value is also the same.
+    </para>
+    <para>
+      If this virtual method is not implemented, then the write() virtual method is used with an <parameter>offset</parameter>
+      parameter of 0.
+    </para>
+  </sect2>
+</chapter>
diff --git a/doc/C/prov-writing-parser.xml b/doc/C/prov-writing-parser.xml
new file mode 100644
index 0000000..3fe1e0e
--- /dev/null
+++ b/doc/C/prov-writing-parser.xml
@@ -0,0 +1,147 @@
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+          "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd";[
+<!ENTITY LIBGDA          "<application>Libgda</application>">
+]>
+<chapter id="libgda-provider-parser" xmlns:xi="http://www.w3.org/2003/XInclude";>
+  <title>SQL parser</title>
+  <para>
+    &LIBGDA; implements a generic SQL parser which creates <link linkend="GdaStatement">GdaStatement</link> objects from
+    an SQL string. If the database provider needs to implement its own parser because the generic one does not handle
+    the database specific SQL syntax, it can be done using instructions in this chapter. Otherwise, the provider's sources
+    can be cleared of any code related to the parser.
+  </para>
+  <sect1>
+    <title>Implementation overview</title>
+    <para>
+      This section describes how the generic SQL parser and a provider specific parser are built regarding the files
+      and programs which are involved.
+    </para>
+    <sect2>
+      <title>Generic SQL parser</title>
+      <para>
+	The <link linkend="GdaSqlParser">GdaSqlParser</link> object can parse any SQL string of any SQL dialect,
+	while always identifying the variables (which have a &LIBGDA;'s specific syntax) in the string. If the parser
+	can identify a structure in the SQL string it understands, then it internally builds a
+	<link linkend="GdaSqlStatement">GdaSqlStatement</link> structure of the correct type, and if it cannot then is simply
+	delimits parts in the SQL string to identify variables and also builds a
+	<link linkend="GdaSqlStatement">GdaSqlStatement</link> structure but of 
+	<link linkend="GDA-SQL-STATEMENT-UNKNOWN:CAPS">GDA_SQL_STATEMENT_UNKNOWN</link>. If the string
+	cannot be delimited and variables identified, then it returns an error (usually there is a quotes mismatch problem
+	within the SQL string).
+      </para>
+      <para>
+	Failing to identify a known structure in the SQL string can have several reasons:
+	<itemizedlist>
+	   <listitem><para>the SQL string is not one of the known types of statements (see 
+	       <link linkend="GdaSqlStatementType">GdaSqlStatementType</link>)</para></listitem>
+	   <listitem><para>the SQL uses some database specific extensions</para></listitem>
+	</itemizedlist>
+      </para>
+      <para>
+	The generic SQL parser implementation has its source files in the 
+	<filename class="directory">libgda/sql-parser</filename> directory; the files which actually implement
+	the parser itself are the <filename>parser.y</filename>, <filename>delimiter.y</filename> and
+	 <filename>parser_tokens.h</filename> files:
+	 <itemizedlist>
+	   <listitem><para>The <filename>parser.y</filename> file contains the grammar used by the parser</para></listitem>
+	   <listitem><para>The <filename>delimiter.y</filename> file contains the grammar used by the parser when it 
+	       is operating as a delimiter</para></listitem>
+	   <listitem><para>The <filename>parser_tokens.h</filename> defines some hard coded tokens</para></listitem>
+	 </itemizedlist>
+      </para>
+      <para>
+	The parser grammar files use the <ulink url="http://www.hwaci.com/sw/lemon/";>Lemon parser generator</ulink> syntax
+	which is a LALR parser similar to <application>YACC</application> or <application>bison</application>. The lexer part
+	however is not <application>LEX</application> but is a custom one integrated in the
+	<filename>gda-sql-parser.c</filename> file (this allows a better integration between the lexer and parser parts).
+      </para>
+      <para>
+	The following figure illustrates the files involved and how they are produced and used to create
+	the generic SQL parser.
+	<mediaobject>
+          <imageobject role="html">
+            <imagedata fileref="parser_gen.png" format="PNG"/>
+          </imageobject>
+          <textobject> 
+            <phrase>Generic SQL parser's implementation</phrase>
+          </textobject>
+	</mediaobject>
+	<itemizedlist>
+	   <listitem><para>The white background indicate files which are sources
+	       (part of &LIBGDA;'s distribution)</para></listitem>
+	   <listitem><para>The blue background indicate files that they are produced dynamically</para></listitem>
+	   <listitem><para>The pink background indicate programs that are compiled and used themselves in
+	       the compilation process to generate files. These programs are:
+	       <itemizedlist>
+		 <listitem><para><application>lemon</application>: the lemon parser itself</para></listitem>
+		 <listitem><para><application>gen_def</application>: generated the "converters" arrays (see blow)</para>
+		 </listitem>
+	       </itemizedlist>
+	       Note that none of these programs gets installed (and when cross compiling, they are compiled as programs
+	       executing on the host actually making the compilation).
+	   </para></listitem>
+	   <listitem><para>The green background identifies components which are reused when implementing provider specific
+	       parsers</para></listitem>
+	 </itemizedlist>
+      </para>
+      <para>
+	The tokenizer (AKA lexer) generates values identified by the "L_" prefix (for example "L_BEGIN"). Because
+	the GdaSqlParser object uses the same lexer with at least two different parsers (namely the parser and delimiter
+	mentioned earlier), and because the Lemon parser generator generates its own value identifiers for tokens, there
+	is a conversion step (the "converter" block in the diagram) which converts the "L_" prefixed tokens with the ones
+	usable by each parser (both converters are defined as arrays in the <filename>token_types.h</filename> file.
+      </para>
+    </sect2>
+    <sect2>
+      <title>Provider specific SQL parser</title>
+      <para>
+	One wants to write a database specific SQL parser when:
+	<itemizedlist>
+	  <listitem><para>the SQL understood by the database differs from the generic SQL. For example
+	      PostgreSQL associates priorities to the compound statement in a different way as the generic SQL.
+	      In this case it is strongly recommended to write a custom SQL parser</para></listitem>
+	  <listitem><para>the SQL understood by the database has specific extensions</para></listitem>
+	</itemizedlist>
+      </para>
+      <para>
+	Using the same background color conventions as the previous diagram, the following diagram illustrates
+	the files involved and how they are produced and used to create a provider specific SQL parser:
+      </para>
+      <para>
+	<mediaobject>
+          <imageobject role="html">
+            <imagedata fileref="parser_prov.png" format="PNG"/>
+          </imageobject>
+          <textobject> 
+            <phrase>Provider specific SQL parser's implementation</phrase>
+          </textobject>
+	</mediaobject>
+      </para>
+      <para>
+	The key differences are:
+	<itemizedlist>
+	  <listitem><para>The delimiter part of the <link linkend="GdaSqlParser">GdaSqlParser</link> object
+	      is the same as for the generic SQL parser implementation</para></listitem>
+	  <listitem><para>While the <application>lemon</application> program is the same as for the generic SQL parser,
+	      the <application>gen_def</application> is different, and takes as its input the ".h" file produced by
+	      the <application>lemon</application> program and the <filename>libgda/sql-parser/token_types.h</filename>.
+	  </para></listitem>
+	</itemizedlist>
+      </para>
+    </sect2>
+  </sect1>
+  <sect1>
+    <title>Tips to write a custom parser</title>
+    <para>
+      <itemizedlist>
+	<listitem><para>Write a new <filename>parser.y</filename> file (better to copy and adapt 
+	    it than starting from scratch)</para></listitem>
+	<listitem><para>Sub class the <link linkend="GdaSqlParser">GdaSqlParser</link> class and "connect" the
+	    class's virtual methods to the new generated parser</para></listitem>
+	<listitem><para>Start from the skeleton implementation</para></listitem>
+      </itemizedlist>
+    </para>
+  </sect1>
+  <xi:include href="xml/gda-sql-statement.xml"/>
+</chapter>
diff --git a/doc/C/prov-writing-recordsets.xml b/doc/C/prov-writing-recordsets.xml
new file mode 100644
index 0000000..04bbd40
--- /dev/null
+++ b/doc/C/prov-writing-recordsets.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+          "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd";[
+<!ENTITY LIBGDA          "<application>Libgda</application>">
+]>
+<chapter id="libgda-provider-recordset">
+  <title>Virtual methods for recordsets</title>
+  <para>
+    This section explains how to write virtual methods for the <link linkend="GdaDataSelect">GdaDataSelect</link> subclasses
+    implementations, which should be done when implementing a database provider.
+  </para>
+  <para>
+    That data model implementation simplifies the implementation of provider's recordsets by having them implement only a
+    few virtual methods, and offering some services.
+  </para>
+  <para>
+    The data model represents each row in a separate <link linkend="GdaRow">GdaRow</link> object, and virtual
+    methods to retrieve rows have to return new (and correctly initialized) objects of that class. The referencing
+    of these new objects is left up to the implementation which:
+    <itemizedlist>
+      <listitem>
+	<para>can rely on the <link linkend="GdaRow">GdaRow</link> implementation to keep them, using
+	  the <link linkend="gda-data-select-take-row">gda_data_select_take_row ()</link> method for each row object created which
+	  is the easiest, the fastest as once created, the rows are available for further usage, 
+	  but will consume more memory with each row read from the model.</para>
+      </listitem>
+      <listitem>
+	<para>can keep the references to these objects to the subclass implementation which will consume less memory but
+	  will make it necessary to create a new row object each time a row is read which is slower</para>
+      </listitem>
+      <listitem>
+	<para>can do a mix of the two solutions above: monitor the memory usage for the data model to 
+	  enable to "cache" some rows and discard some when memory is needed</para>
+      </listitem>
+    </itemizedlist>
+    Note that the methods mentioned in the 1st and 3rd items should be reserved for random data access mode, 
+    and that cursor based access mode should implement the method mentioned in th 2nd item.
+  </para>
+  <sect2>
+    <title>fetch_nb_rows()</title>
+    <para>
+      This method is called when the user calls <link linkend="gda-data-model-get-n-rows">gda_data_model_get_n_rows ()</link>.
+    </para>
+    <para>
+      Note that the number of rows of the data model may not be known until the cursor has reached the last row of
+      the recordset.
+      Once known, the number of rows can be stored in the <structfield>advertized_nrows</structfield>'s member of the
+      <link linkend="GdaDataSelect">GdaDataSelect</link> object.
+    </para>
+  </sect2>
+
+  <sect2>
+    <title>fetch_random()</title>
+    <para>
+      This method is called when the user calls <link linkend="gda-data-model-get-value-at">gda_data_model_get_value_at ()</link>,
+      and in available only when the data access mode for the data model is random (that is not cursor based). When data
+      access is cursor based, this method will not be called.
+    </para>
+  </sect2>
+
+  <sect2>
+    <title>store_all()</title>
+    <para>
+      This method is called when the user sets the "store-all-rows" to TRUE. It has the effect of forcing the creation
+      of a <link linkend="GdaRow">GdaRow</link> object for each row of the data model (thus increasing the memory consumption
+      but reducing further access times). It is available only when the data access mode for the data model is random 
+      (that is not cursor based). When data access is cursor based, this method will not be called.
+    </para>
+  </sect2>
+
+  <sect2>
+    <title>fetch_next()</title>
+    <para>
+      This method is called when data access is cursor based and a data model iterator is moved one position forward. The
+      <parameter>rownum</parameter> is an indication of what the row number will be once the next row has been fetched (it can 
+      safely be discarded if that information is not necessary).
+    </para>
+  </sect2>
+
+  <sect2>
+    <title>fetch_prev()</title>
+    <para>
+      This method is called when data access is cursor based and a data model iterator is moved one position backward. The
+      <parameter>rownum</parameter> is an indication of what the row number will be once the previous row has been fetched (it can 
+      safely be discarded if that information is not necessary).
+    </para>
+  </sect2>
+
+  <sect2>
+    <title>fetch_at()</title>
+    <para>
+      This method can be implemented when data access is cursor based and there is a shorter way of getting to a
+      specific row than having to call the fetch_next() or fetch_prev() methods several times.
+    </para>
+  </sect2>
+</chapter>
diff --git a/doc/C/prov-writing-virtual-methods.xml b/doc/C/prov-writing-virtual-methods.xml
new file mode 100644
index 0000000..9329dc0
--- /dev/null
+++ b/doc/C/prov-writing-virtual-methods.xml
@@ -0,0 +1,596 @@
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+          "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd";[
+<!ENTITY LIBGDA          "<application>Libgda</application>">
+]>
+<chapter id="libgda-provider-class">
+  <title>Virtual methods for providers</title>
+  <para>
+    Database providers usually (that is except for <emphasis>virtual</emphasis> providers explained later) subclass
+    the <link linkend="GdaServerProvider">GdaServerProvider</link> class and implement at least the mandatory
+    virtual methods.
+  </para>
+  <para>
+    Virtual providers are database providers when the database engine accessed does not support SQL (or
+    supports it poorly), such as Berkeley databases or MDB (or even LDAP). These provider's implementation's
+    design is to create <link linkend="GdaDataModel">GdaDataModel</link> data model objects and make
+    each of them appear as a named table once the connection is opened. For example the MDB provider creates
+    a read-only data model for each table in an MDB file and make it appear using the original table
+    name used in MS Access (the tables cannot be modified but it is possible to use all SQLite's SQL
+    to make SELECT queries).
+  </para>
+  <para>
+    Virtual providers inherit the <link linkend="GdaVproviderDataModel">GdaVproviderDataModel</link> class
+    and not the <link linkend="GdaServerProvider">GdaServerProvider</link> as "normal" providers do,
+    and the number of virtual methods to implement is very limited: only the <link linkend="prov-get-name">get_name()</link>,
+    <link linkend="prov-get-version">get_version()</link>, <link linkend="prov-get-server-version">get_server_version()</link>, 
+    <link linkend="prov-open-connection">open_connection()</link> and <link linkend="prov-get-database">get_database()</link>
+    should be implemented, optionnally the <link linkend="prov-close-connection">close_connection()</link> can
+    also be implemented.
+  </para>
+
+  <sect1>
+    <title>Synchronous / asynchronous mode</title>
+    <para>
+      All the provider's commands are executed in a synchronous mode (the caller is blocked until the provider's
+      method terminates). However some virtual methods have the a <parameter>task_id</parameter> parameter, 
+      an <parameter>async_cb</parameter> or <parameter>exec_cb</parameter> callback function pointer and 
+      a <parameter>cb_data</parameter> parameter which can be set when an asynchronous mode 
+      is required; asynchronous mode is requested if and only if the <parameter>async_cb</parameter> or
+      <parameter>exec_cb</parameter> parmeter is not NULL.
+    </para>
+    <para>
+      When an asynchronous mode is requested, the method should return TRUE if it returns a boolean or NULL if it returns a
+      pointer and set a task identifier
+      into the <parameter>task_id</parameter> parameter if not NULL. The task identifier is passed again when
+      the <parameter>async_cb</parameter> or <parameter>exec_cb</parameter> callback functions are called by the
+      provider when the execution is finished.
+    </para>
+    <para>
+      When the provider's method terminates, it then should call the function passed as <parameter>async_cb</parameter>
+      with the <parameter>cb_data</parameter> as last parameters.
+    </para>
+  </sect1>
+
+  <sect1>
+    <title>Multi threaded environment</title>
+    <para>
+      Each database provider should be usable in a multi threaded environment, even if they impose some restrictions
+      as to how they can be used in such an environment. The &LIBGDA;'s framework provides some locking mechanism which
+      is:
+      <itemizedlist>
+	<listitem><para>if multi threading cannot be supported at all (for example if the client library internally
+	    used by the provider does not support it), then  the provider's
+	    class implementation should set the class's <structfield>limiting_thread</structfield> attribute to:
+	    the GDA_SERVER_PROVIDER_UNDEFINED_LIMITING_THREAD constant.
+	    This constant will be resolved at run time as the thread which creates the 1st connection using that
+	    provider.</para>
+	</listitem>
+	<listitem><para>if multi threading is supported but any connection (or related object) can only be 
+	    used by the thread in which it was created, then for each opened connection, the 
+	    &quot;<link linkend="GdaConnection--thread-owner">thread-owner</link>&quot; connection's property
+	    must be set to the current thread (and other related objects must be locked in a similar way)</para>
+	</listitem>
+	<listitem><para>if no locking is done, then the provider is assumed to support full multi threading access,
+	  in this case make sure to set class's <structfield>limiting_thread</structfield> attribute to the NULL constant.</para>
+	</listitem>
+      </itemizedlist>
+    </para>
+    <para>
+      Note that the default provider's class value for the <structfield>limiting_thread</structfield> is safely set to the
+      GDA_SERVER_PROVIDER_UNDEFINED_LIMITING_THREAD constant.
+    </para>
+  </sect1>
+
+  <sect1>
+    <title>Methods - provider's information</title>
+    <sect2 id="prov-get-name">
+      <title>get_name() - mandatory</title>
+      <para>This method returns the name of the provider; it should only contain alphanumeric characters.</para>
+    </sect2>
+    <sect2 id="prov-get-version">
+      <title>get_version() - mandatory</title>
+      <para>This method returns the version of the provider (providers built as part of &LIBGDA; have the same
+	version as &LIBGDA;).</para>
+    </sect2>
+    <sect2 id="prov-get-server-version">
+      <title>get_server_version() - mandatory</title>
+      <para>This method returns the version of the database server to which a connection is opened</para>
+    </sect2>
+    <sect2>
+      <title>supports_feature()</title>
+      <para>This method allows one to ask the provider if some specific features are available</para>
+    </sect2>
+  </sect1>
+
+  <sect1>
+    <title>Methods - connection management</title>
+    <sect2 id="prov-open-connection">
+      <title>open_connection() - mandatory</title>
+      <para>
+	This method actually opens a connection to the database.
+      </para>
+      <para>
+	Any data specific to the connection (such as 
+	a database handle created by the database API when opening the connection) must be stored in a private structure
+	(which should be defined in the <filename>gda-&lt;providername&gt;.h</filename> file as a 
+	<classname>&lt;Providername&gt;ConnectionData</classname>); this private structure's adress should be
+	"attached" to the <link linkend="GdaConnection">GdaConnection</link> object using the
+	<link linkend="gda-connection-internal-set-provider-data">gda_connection_internal_set_provider_data()</link>.
+      </para>
+    </sect2>
+    <sect2 id="prov-close-connection">
+      <title>close_connection() - mandatory</title>
+      <para>
+	This method actually closes a connection previously opened by the 
+	<link linkend="prov-open-connection">open_connection()</link> virtual method. This method is not mandatory for
+	virtual providers.
+      </para>
+      <para>
+	The connection specific data for the database API can be retrieved using the
+	<link linkend="gda-connection-internal-get-provider-data">gda_connection_internal_get_provider_data()</link> method.
+      </para>
+    </sect2>
+    <sect2>
+      <title>get_database()</title>
+      <para>This method returns the name of the database to which a connection is opened.</para>
+    </sect2>
+  </sect1>
+
+  <sect1>
+    <title>Methods - DDL queries</title>
+    <para>
+      This group of virtual methods is composed of virtual methods which make it possible to handle DDL (data definition) queries
+      to be executed using descriptions of the data required for each kind of DDL query, rather than using SQL directly (because
+      DDL SQL is usually very database specific and must thus be adapted when migrating to another database type). For more
+      information, see the <link linkend="DDLIntro">global introduction to DDL queries</link>.
+    </para>
+    <para>
+      Implementing these methods is not mandatory, and virtual provider's implementation should not implement them.
+    </para>
+    <sect2>
+      <title>supports_operation()</title>
+      <para>
+	This virtual method tells if a particular DDL query type is supported (DDL query types are identified as 
+      <link linkend="GdaServerOperationType">GdaServerOperationType</link> enums).
+      </para>
+    </sect2>
+    <sect2>
+      <title>create_operation()</title>
+      <para>
+	This virtual method is used to create and initialize a <link linkend="GdaServerOperation">GdaServerOperation</link>
+	object.
+      </para>
+    </sect2>
+    <sect2>
+      <title>render_operation()</title>
+      <para>
+	This virtual method uses the information stored in a <link linkend="GdaServerOperation">GdaServerOperation</link> object
+	to create the SQL statement(s) which would be executed if the operation was performed.
+      </para>
+      <para>
+	Note: more than one SQL statement may be returned by this method
+      </para>
+      <para>
+	Note: some operations don't return any SQL at all, if the operation can only be done using an API (and not through SQL)
+      </para>
+    </sect2>
+    <sect2>
+      <title>perform_operation()</title>
+      <para>
+	This virtual method "performs" (execute) a <link linkend="GdaServerOperation">GdaServerOperation</link> object.
+      </para>
+    </sect2>
+  </sect1>
+
+  <sect1>
+    <title>Methods - transactions management</title>
+    <para>
+      When a connection has been opened and no transaction has been started, then the provider should execute queries in
+      auto commit mode.
+    </para>
+    <sect2>
+      <title>begin_transaction()</title>
+      <para>
+	This method starts a new transaction.
+      </para>
+    </sect2>
+    <sect2>
+      <title>commit_transaction()</title>
+      <para>
+	This method commits the current transaction.
+      </para>
+    </sect2>
+    <sect2>
+      <title>rollback_transaction()</title>
+      <para>
+	This method cancels the current transaction.
+      </para>
+    </sect2>
+    <sect2>
+      <title>add_savepoint()</title>
+      <para>
+	This method adds a save point to the current transaction, which allows for partial rollbacks within transactions.
+      </para>
+    </sect2>
+    <sect2>
+      <title>rollback_savepoint()</title>
+      <para>
+	This method rolls back to a previously defined save point within the current transaction.
+      </para>
+    </sect2>
+    <sect2>
+      <title>delete_savepoint()</title>
+      <para>
+	This method deletes a previously defined save point within the current transaction, it does not affect the
+	transaction but it simply won't be possible to roll back to the savepoint afterwards.
+      </para>
+    </sect2>
+  </sect1>
+
+  <sect1>
+    <title>Methods - DML queries</title>
+    <para>
+      This group of virtual methods is related to executing SQL queries of any kind. &LIBGDA; imposes that SQL
+      statements be converted to one or more <link linkend="GdaStatement">GdaStatement</link> object(s), each
+      GdaStatement object containing exactly one SQL statement (usually terminated
+      by a semi colon). Each GdaStatement can then be prepared and/or executed individually.
+    </para>
+    <para>
+      Creating a <link linkend="GdaStatement">GdaStatement</link> object from some SQL is the job of a
+      <link linkend="GdaSqlParser">GdaSqlParser</link> object.
+    </para>
+    <sect2>
+      <title>create_parser()</title>
+      <para>
+	This method instantiates a <link linkend="GdaSqlParser">GdaSqlParser</link> object which is
+	adapted to the database's specific SQL dialect. If the provider does not implement its own parser,
+	then this method should not be implemented.
+      </para>
+    </sect2>
+    <sect2>
+      <title>statement_to_sql()</title>
+      <para>
+	This method converts a <link linkend="GdaStatement">GdaStatement</link> object to its SQL representation. It should be
+	implemented only if the default rendering is incorrect (to support some SQL specific dialect). The rendering process
+	is decomposed into several rendering methods, and it is possible to override only some of the methods (see the
+	PostgreSQL's implementation as an example).
+      </para>
+    </sect2>
+    <sect2>
+      <title>statement_prepare()</title>
+      <para>
+	This method requests that a <link linkend="GdaStatement">GdaStatement</link> object be prepared for a future execution.
+	It is called when <link linkend="gda-connection-statement-prepare">gda_connection_statement_prepare()</link> is called.
+      </para>
+    </sect2>
+    <sect2>
+      <title>statement_execute() - mandatory</title>
+      <para>
+	This method actually executes a query represented by a <link linkend="GdaStatement">GdaStatement</link> object. See
+	<link linkend="gda-connection-statement-execute">gda_connection_statement_execute()</link> for more information, note that
+	this method is also always the one called when any of the gda_connection_statement_execute*() methods are called.
+      </para>
+      <para>
+	A non NULL <parameter>exec_cb</parameter> parameter specifies that the user requests an asynchronous execution: the
+	function has to return the NULL value immediately (it must not be blocking), and the <parameter>task_id</parameter>
+	parameter must be set to contain a provider specific task ID.
+	The <parameter>exec_cb</parameter> parameter points to a callback function (specified by the
+	<link linkend="GdaConnection">GdaConnection</link>) which the provider has to call once the statement has been
+	executed, using the same task ID which was defined when the statement_execute() function was called, and
+	the <parameter>cb_data</parameter> specified when the statement_execute() function was called.
+      </para>
+      <para>
+	Note that if an asynchronous execution is requested, then the <parameter>stmt</parameter>, <parameter>params</parameter>,
+	<parameter>col_types</parameter>, <parameter>last_inserted_row</parameter>, and <parameter>cb_data</parameter>
+	parameters are supposed to exist and not be altered during the time the statement is executed (the
+	<link linkend="GdaConnection">GdaConnection</link> ensures this) which means it's not necessary to make copies
+	of them during the execution.
+      </para>
+    </sect2>
+    <sect2>
+      <title>handle_async()</title>
+      <para>
+	This method, if implemented, is called to give the database provider a chance to execute some code in case an
+	asynchronous statement's execution has been requested. Often providers will send some data over the network to the
+	database server when the statement_execute() is called, and implement this virtual function as a way to get
+	some data from the database server to see if the execution is terminated.
+      </para>
+    </sect2>
+  </sect1>
+
+  <sect1>
+    <title>Methods - data representation</title>
+    <para>
+      This group of virtual methods is related to converting some data between the three representations which are the 
+      SQL representation (to be directly included in a SQL statement), the human readable representation, and the 
+      <link linkend="GValue">GValue</link> representation. For each type of data (identified as a 
+      <link linkend="GType">GType</link> type) which the provider can handle, a <link linkend="GdaDataHandler">GdaDataHandler</link>
+      object is responsible of the conversions.
+    </para>
+    <sect2>
+      <title>get_data_handler()</title>
+      <para>
+	This method returns a <link linkend="GdaDataHandler">GdaDataHandler</link> for the requested data type. It should
+	only instantiate each <link linkend="GdaDataHandler">GdaDataHandler</link> once and reuse it if the same request happens 
+	(the returned object will not be modified).
+      </para>
+      <para>
+	This method is called by both
+	<link linkend="gda-server-provider-get-data-handler-g-type">gda_server_provider_get_data_handler_g_type()</link> and
+	<link linkend="gda-server-provider-get-data-handler-dbms">gda_server_provider_get_data_handler_dbms()</link> methods.
+      </para>
+    </sect2>
+    <sect2>
+      <title>get_def_dbms_type()</title>
+      <para>
+	This method returns the name of the most common (database specific) data type which has the requested type.
+      </para>
+    </sect2>
+    <sect2>
+      <title>escape_string()</title>
+      <para>
+	This method adds escape characters to a string, to be able to safely add it into an SQL statement.
+      </para>
+    </sect2>
+    <sect2>
+      <title>unescape_string()</title>
+      <para>
+	This method does the reverse of the escape_string() method.
+      </para>
+    </sect2>
+  </sect1>
+
+  <sect1 id="prov-metadata">
+    <title>Methods - metadata</title>
+    <para>
+      The <link linkend="GdaServerProviderMeta">GdaServerProviderMeta</link> structure defines all the methods
+      which database providers must implement for the meta data extraction feature to work. Each method is
+      used internally by the <link linkend="GdaConnection">GdaConnection</link> object when one calls the
+      <link linkend="gda-connection-update-meta-store">gda_connection_update_meta_store()</link> method (where the
+      connection object itself computes the list and order of methods to call).
+      Each method must update the contents of one table in the connection's associated metadata
+      (in its associated <link linkend="GdaMetaStore">GdaMetaStore</link> object), each has the same
+      "base" arguments and some have extra arguments further specifying what needs to be updated. 
+    </para>
+    <para>
+      For each table to update, there are two methods, which differ in their name only by the fact that one is starting 
+      with an underscore '_'. The method starting with an underscore must update the whole contents of the meta data
+      table, and the other one must accept some more parameters to refine what gets updated. There are exception 
+      to this rule (such as the
+      "tables_views()" method which must update both the <link linkend="is:_tables">"_tables"</link> and 
+      <link linkend="is:_views">"_views"</link> tables, or the for the
+      tables which have no foreign key (no dependency) to any other table).
+    </para>
+    <para> 
+      Also, by convetion, the arguments can't be NULL unless the argument name has the "_n" suffix. For example
+      the signature of the "tables_views()" method has the following signature (as defined in the 
+      <filename>gda-server-provider.h</filename> file) 
+      <programlisting>
+gboolean (*tables_views) (GdaServerProvider *, GdaConnection *, GdaMetaStore *, 
+                          GdaMetaContext *, GError **,
+                          const GValue *table_catalog, const GValue *table_schema, 
+                          const GValue *table_name_n);
+      </programlisting>
+      which means that the <parameter>table_catalog</parameter> and <parameter>table_schema</parameter>
+      arguments can't be NULL, whereas the <parameter>table_name</parameter> can be NULL (and in this case the 
+      "tables_views()" method must update the <link linkend="is:_tables">"_tables"</link> and 
+      <link linkend="is:_views">"_views"</link> tables regarding all the tables which
+      are in the specified catalog and schema.
+    </para>
+    <para>
+      Make sure you read the information about the meta data's database structure in the
+      <link linkend="information_schema">Database structure</link>, and specifically the
+      <link linkend="information_schema:data_types">data types</link> section and the 
+      <link linkend="information_schema:sql_identifiers">SQL identifiers</link> section.
+    </para>
+    <sect2>
+      <title>Important note about SQL identifiers</title>
+      <para>
+	As mentioned in the <link linkend="information_schema:sql_identifiers">SQL identifiers</link> section,
+	any SQL identifier in the meta store is represented either:
+	<itemizedlist>
+	  <listitem><para>between double quotes if the SQL identifier is case sensitive</para></listitem>
+	  <listitem><para>all in lower case if the SQL identifier is not case sensitive</para></listitem>
+	</itemizedlist>
+      </para>
+      <para>
+	For database engines which internally store case insensitive SQL identifiers in lower case
+	(such as PostgreSQL),
+	the meta data reported by the database engine can be used almost AS IS, but for database
+	engines which internally store case insensitive SQL identifiers in upper case (such as Oracle),
+	the upper case needs to be converted to lower case. Also case sensitive SQL identifiers also need
+	to be double quoted.
+      </para>
+      <para>
+	To minimize the work required to implement a database provider, &LIBGDA; allows the database
+	provider to specifiy how case insensitive SQL identifiers are represented using 
+	<link linkend="gda-meta-store-set-identifiers-style">gda_meta_store_set_identifiers_style()</link>
+	and the <link linkend="GdaMetaStore">GdaMetaStore</link> object will perform the work itself (the
+	default being GDA_SQL_IDENTIFIERS_LOWER_CASE in <link linkend="GdaSqlIdentifierStyle">GdaSqlIdentifierStyle</link>.
+      </para>
+      <para>
+	Also note that the extra arguments for each virtual method listed below, when they are present
+	and when they represent an SQL identifier, will be represented:
+	<itemizedlist>
+	  <listitem><para>for case insensitive SQL identifiers: using all lower or all upper case (depending on the setting
+	      set using <link linkend="gda-meta-store-set-identifiers-style">gda_meta_store_set_identifiers_style()</link>
+	  </para></listitem>
+	  <listitem><para>for case sensitive SQL identifiers: without the double quotes, but possibily with
+	      mixed or not lower and upper characters</para></listitem>
+	</itemizedlist>
+      </para>
+    </sect2>
+    <sect2>
+      <title>Reserved SQL keywords</title>
+      <para>
+	Every database engine reserves some keywords for its own usage or because they are part of the SQL
+	language. Reserved keywords can be used as SQL identifiers if they are put between double quotes.
+      </para>
+      <para>
+	As Each database engine has its own set of reserved keywords, the database provider has to tell the
+	<link linkend="GdaMetaStore">GdaMetaStore</link> object what its keywords are, which is done using
+	<link linkend="gda-meta-store-set-reserved-keywords-func">gda_meta_store_set_reserved_keywords_func()</link>
+	and passing a function which determines if a specific string is a reserved keyword. The usage of
+	this function is similar to the usage of the
+	<link linkend="gda-meta-store-set-identifiers-style">gda_meta_store_set_identifiers_style()</link>
+	mentioned above.
+      </para>
+      <para>
+	Writing a function which tests if a string is a reserved keyword is a non complicated but error
+	prone and not optimized, in the same way as writing a parser/lexer directly, so &LIBGDA; has a tool
+	which generates a static hash table from a list of reserved keywords, which is in the
+	<filename>keywords.list</filename> (several keywords can appear on the same line, separated by spaces or commas
+	but the last line must remain empty).
+      </para>
+    </sect2>
+    <sect2>
+      <title>_info()</title>
+      <para>
+	<programlisting>
+gboolean (*_info) (GdaServerProvider *, GdaConnection *, GdaMetaStore *, 
+                   GdaMetaContext *, GError **);
+	</programlisting>
+	This method must update the contents of the 
+	<link linkend="is:_information_schema_catalog_name">"_information_schema_catalog_name"</link>
+	table, which must contain exactly
+	one row describing the catalog name for the connection.
+      </para>
+    </sect2>
+    
+    <sect2>
+      <title>_btypes()</title>
+      <para>
+	<programlisting>
+gboolean (*_btypes) (GdaServerProvider *, GdaConnection *, GdaMetaStore *, 
+                     GdaMetaContext *, GError **);
+	</programlisting>
+	This method must update the contents of the <link linkend="is:_builtin_data_types">"_builtin_data_types"</link>
+	table which lists all the
+	database's built in data types. There is no specific parameter.
+      </para>
+    </sect2>
+    
+    <sect2>
+      <title>schemata() and _schemata()</title>
+      <para>
+	<programlisting>
+gboolean (*_schemata) (GdaServerProvider *, GdaConnection *, GdaMetaStore *, 
+                       GdaMetaContext *, GError **);
+gboolean (*schemata)  (GdaServerProvider *, GdaConnection *, GdaMetaStore *, 
+                       GdaMetaContext *, GError **,
+                       const GValue *catalog_name, const GValue *schema_name_n);
+	</programlisting>
+        This method must update the contents of the <link linkend="is:_schemata">"_schemata"</link> table, 
+	which lists all the schemas (namespaces). 
+      </para>
+    </sect2>
+    <sect2>
+      <title>tables_views() and _tables_views()</title>
+      <para>
+	<programlisting>
+gboolean (*_tables_views) (GdaServerProvider *, GdaConnection *, GdaMetaStore *, 
+                           GdaMetaContext *, GError **);
+gboolean (*tables_views)  (GdaServerProvider *, GdaConnection *, GdaMetaStore *, 
+                           GdaMetaContext *, GError **,
+                           const GValue *table_catalog, const GValue *table_schema, 
+                           const GValue *table_name_n);
+	</programlisting>
+	This method must update the contents of the <link linkend="is:_tables">"_tables"</link> and 
+	<link linkend="is:_views">"_views"</link> tables which list all the
+	tables and views.
+      </para>
+    </sect2>
+
+    <sect2>
+      <title>columns() and _columns()</title>
+      <para>
+	<programlisting>
+gboolean (*_columns) (GdaServerProvider *, GdaConnection *, GdaMetaStore *, 
+                      GdaMetaContext *, GError **);
+gboolean (*columns)  (GdaServerProvider *, GdaConnection *, GdaMetaStore *, 
+                      GdaMetaContext *, GError **,
+                      const GValue *table_catalog, const GValue *table_schema, 
+                      const GValue *table_name);
+	</programlisting>
+	This method must update the contents of the <link linkend="is:_columns">"_columns"</link> table which lists all the
+	columns of all the tables and views.
+      </para>
+    </sect2>
+
+    <sect2>
+      <title>constraints_tab() and _constraints_tab()</title>
+      <para>
+	<programlisting>
+gboolean (*_constraints_tab) (GdaServerProvider *, GdaConnection *, GdaMetaStore *, 
+                              GdaMetaContext *, GError **);
+gboolean (*constraints_tab)  (GdaServerProvider *, GdaConnection *, GdaMetaStore *, 
+                              GdaMetaContext *, GError **,
+                              const GValue *table_catalog, const GValue *table_schema, 
+                              const GValue *table_name, const GValue *constraint_name_n);
+	</programlisting>
+	This method must update the contents of the <link linkend="is:_table_constraints">"_table_constraints"</link>
+	table which lists all the
+	constraints (primary key, foreign key, unique or check constraints) for each table.
+      </para>
+    </sect2>
+
+    <sect2>
+      <title>constraints_ref() and _constraints_ref()</title>
+      <para>
+	<programlisting>
+gboolean (*_constraints_ref) (GdaServerProvider *, GdaConnection *, GdaMetaStore *, 
+                              GdaMetaContext *, GError **);
+gboolean (*constraints_ref)  (GdaServerProvider *, GdaConnection *, GdaMetaStore *, 
+                              GdaMetaContext *, GError **,
+                              const GValue *table_catalog, const GValue *table_schema, 
+                              const GValue *table_name, const GValue *constraint_name);
+	</programlisting>
+	This method must update the contents of the 
+	<link linkend="is:_referential_constraints">"_referential_constraints"</link> table which lists all the
+	referential constraints (which are also listed in the 
+	<link linkend="is:_table_constraints">"_table_constraints"</link> table).
+      </para>
+    </sect2>
+
+    <sect2>
+      <title>key_columns() and _key_columns()</title>
+      <para>
+	<programlisting>
+gboolean (*_key_columns) (GdaServerProvider *, GdaConnection *, GdaMetaStore *, 
+                          GdaMetaContext *, GError **);
+gboolean (*key_columns)  (GdaServerProvider *, GdaConnection *, GdaMetaStore *, 
+                          GdaMetaContext *, GError **,
+                          const GValue *table_catalog, const GValue *table_schema,
+                          const GValue *table_name, const GValue *constraint_name);
+	</programlisting>
+	This method must update the contents of the <link linkend="is:_key_column_usage">"_key_column_usage"</link>
+	table which lists all the
+	columns involved in each table constraint (as listed in the 
+	<link linkend="is:_table_constraints">"_table_constraints"</link> table).
+      </para>
+    </sect2>
+  </sect1>
+
+  <sect1>
+    <title>Methods - misc.</title>
+    <sect2>
+      <title>cancel()</title>
+      <para>
+	This method cancels an asynchronous task.
+      </para>
+    </sect2>
+    <sect2>
+      <title>create_connection()</title>
+      <para>
+	Reserved for internal implementation.
+      </para>
+    </sect2>
+    <sect2>
+      <title>is_busy()</title>
+      <para>
+	This method tests if a connection is already busy in a, asynchronous task.
+      </para>
+    </sect2>
+  </sect1>
+</chapter>
diff --git a/doc/C/server-operation.xml b/doc/C/server-operation.xml
index 2524d0e..b076491 100644
--- a/doc/C/server-operation.xml
+++ b/doc/C/server-operation.xml
@@ -1,3 +1,8 @@
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+          "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd";[
+<!ENTITY LIBGDA          "<application>Libgda</application>">
+]>
 <sect2 id="DDLIntro">
   <title>General words about DDL queries</title>
   <para>
diff --git a/doc/C/virtual.xml b/doc/C/virtual.xml
index 551a690..6dfc036 100644
--- a/doc/C/virtual.xml
+++ b/doc/C/virtual.xml
@@ -1,4 +1,9 @@
-<sect2 id="VirtualIntro">
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+          "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd";[
+<!ENTITY LIBGDA          "<application>Libgda</application>">
+]>
+<sect2 id="VirtualIntro" xmlns:xi="http://www.w3.org/2003/XInclude";>
   <title>Introduction to virtual connections</title>
   <para>
     &LIBGDA; implements so called virtual connections which are used like normal 
@@ -36,5 +41,5 @@ cnc = gda_virtual_connection_open (provider, NULL);
       <listitem><para><filename class="directory">testing/virtual-test-2.c</filename></para></listitem>
     </itemizedlist>
   </para>
-  &libgda-virtual-notice;
+<xi:include href="virtual-notice.xml"/>
 </sect2>
diff --git a/installers/Windows/make-zip-setup.sh b/installers/Windows/make-zip-setup.sh
index a2c595e..af46d38 100755
--- a/installers/Windows/make-zip-setup.sh
+++ b/installers/Windows/make-zip-setup.sh
@@ -20,7 +20,7 @@
 cross_path=/local/Win32/gtk
 depend_path=/local/Win32
 prefix=/local/Win32/Libgda
-version=4.2.6
+version=4.99.1
 
 
 
@@ -166,8 +166,8 @@ Section "GdaBrowser & Libgda" SEC01
   SetOverwrite try
   SectionIn 1 RO
   CreateDirectory "\$SMPROGRAMS\GdaBrowser"
-  CreateShortCut "\$SMPROGRAMS\GdaBrowser\GdaBrowser.lnk" "\$INSTDIR\bin\gda-browser-4.0.exe"
-  CreateShortCut "\$DESKTOP\GdaBrowser.lnk" "\$INSTDIR\bin\gda-browser-4.0.exe"
+  CreateShortCut "\$SMPROGRAMS\GdaBrowser\GdaBrowser.lnk" "\$INSTDIR\bin\gda-browser-5.0.exe"
+  CreateShortCut "\$DESKTOP\GdaBrowser.lnk" "\$INSTDIR\bin\gda-browser-5.0.exe"
 EOF
 
 cat > prov_mysql.nsh <<EOF
@@ -267,111 +267,111 @@ add_files_to_nsh prov_postgresql ${depend_path}/pgsql bin $files
 # Libgda's files
 #
 files=(information_schema.xml import_encodings.xml)
-add_files_to_zip $archive $prefix share/libgda-4.0 $files
-add_files_to_nsh core $prefix share/libgda-4.0 $files
+add_files_to_zip $archive $prefix share/libgda-5.0 $files
+add_files_to_nsh core $prefix share/libgda-5.0 $files
 
 files=(bdb_specs_dsn.xml)
-add_files_to_zip $archive $prefix share/libgda-4.0 $files
-add_files_to_nsh prov_bdb $prefix share/libgda-4.0 $files
+add_files_to_zip $archive $prefix share/libgda-5.0 $files
+add_files_to_nsh prov_bdb $prefix share/libgda-5.0 $files
 
 files=(mdb_specs_dsn.xml)
-add_files_to_zip $archive $prefix share/libgda-4.0 $files
-add_files_to_nsh prov_mdb $prefix share/libgda-4.0 $files
+add_files_to_zip $archive $prefix share/libgda-5.0 $files
+add_files_to_nsh prov_mdb $prefix share/libgda-5.0 $files
 
 files=(mysql_specs_add_column.xml mysql_specs_create_db.xml mysql_specs_create_index.xml mysql_specs_create_table.xml mysql_specs_create_view.xml mysql_specs_drop_column.xml mysql_specs_drop_db.xml mysql_specs_drop_index.xml mysql_specs_drop_table.xml mysql_specs_drop_view.xml mysql_specs_dsn.xml mysql_specs_rename_table.xml)
-add_files_to_zip $archive $prefix share/libgda-4.0 $files
-add_files_to_nsh prov_mysql $prefix share/libgda-4.0 $files
+add_files_to_zip $archive $prefix share/libgda-5.0 $files
+add_files_to_nsh prov_mysql $prefix share/libgda-5.0 $files
 
 files=(postgres_specs_add_column.xml postgres_specs_create_db.xml postgres_specs_create_index.xml postgres_specs_create_table.xml postgres_specs_create_view.xml postgres_specs_drop_column.xml postgres_specs_drop_db.xml postgres_specs_drop_index.xml postgres_specs_drop_table.xml postgres_specs_drop_view.xml postgres_specs_dsn.xml postgres_specs_rename_table.xml)
-add_files_to_zip $archive $prefix share/libgda-4.0 $files
-add_files_to_nsh prov_postgresql $prefix share/libgda-4.0 $files
+add_files_to_zip $archive $prefix share/libgda-5.0 $files
+add_files_to_nsh prov_postgresql $prefix share/libgda-5.0 $files
 
 files=(sqlite_specs_add_column.xml sqlite_specs_create_db.xml sqlite_specs_create_index.xml sqlite_specs_create_table.xml sqlite_specs_create_view.xml sqlite_specs_drop_db.xml sqlite_specs_drop_index.xml sqlite_specs_drop_table.xml sqlite_specs_drop_view.xml sqlite_specs_dsn.xml sqlite_specs_rename_table.xml)
-add_files_to_zip $archive $prefix share/libgda-4.0 $files
-add_files_to_nsh prov_sqlite $prefix share/libgda-4.0 $files
+add_files_to_zip $archive $prefix share/libgda-5.0 $files
+add_files_to_nsh prov_sqlite $prefix share/libgda-5.0 $files
 
 files=(web_specs_auth.xml web_specs_dsn.xml)
-add_files_to_zip $archive $prefix share/libgda-4.0 $files
-add_files_to_nsh prov_web $prefix share/libgda-4.0 $files
+add_files_to_zip $archive $prefix share/libgda-5.0 $files
+add_files_to_nsh prov_web $prefix share/libgda-5.0 $files
 
 files=(oracle_specs_dsn.xml oracle_specs_create_table.xml)
-add_files_to_zip $archive $prefix share/libgda-4.0 $files
-add_files_to_nsh prov_oracle $prefix share/libgda-4.0 $files
+add_files_to_zip $archive $prefix share/libgda-5.0 $files
+add_files_to_nsh prov_oracle $prefix share/libgda-5.0 $files
 
 
 files=(gdaui-generic.png)
-add_files_to_zip $archive $prefix share/libgda-4.0/pixmaps $files
-add_files_to_nsh core $prefix share/libgda-4.0/pixmaps $files
+add_files_to_zip $archive $prefix share/libgda-5.0/pixmaps $files
+add_files_to_nsh core $prefix share/libgda-5.0/pixmaps $files
 
 
 #
 #copy some Gnome files to be installed on Windows
 #
-cp /usr/share/icons/gnome/16x16/actions/bookmark-new.png $prefix/share/libgda-4.0/icons/hicolor/16x16/actions
-cp /usr/share/icons/gnome/22x22/actions/bookmark-new.png $prefix/share/libgda-4.0/icons/hicolor/22x22/actions
-cp /usr/share/icons/gnome/24x24/actions/bookmark-new.png $prefix/share/libgda-4.0/icons/hicolor/24x24/actions
-cp /usr/share/icons/gnome/32x32/actions/bookmark-new.png $prefix/share/libgda-4.0/icons/hicolor/32x32/actions
-cp /usr/share/icons/gnome/16x16/actions/window-new.png $prefix/share/libgda-4.0/icons/hicolor/16x16/actions
-cp /usr/share/icons/gnome/22x22/actions/window-new.png $prefix/share/libgda-4.0/icons/hicolor/22x22/actions
-cp /usr/share/icons/gnome/24x24/actions/window-new.png $prefix/share/libgda-4.0/icons/hicolor/24x24/actions
-cp /usr/share/icons/gnome/32x32/actions/window-new.png $prefix/share/libgda-4.0/icons/hicolor/32x32/actions
-mkdir -p $prefix/share/libgda-4.0/icons/hicolor/16x16/apps
-mkdir -p $prefix/share/libgda-4.0/icons/hicolor/22x22/apps
-mkdir -p $prefix/share/libgda-4.0/icons/hicolor/24x24/apps
-mkdir -p $prefix/share/libgda-4.0/icons/hicolor/32x32/apps
-cp /usr/share/icons/gnome/16x16/apps/accessories-text-editor.png $prefix/share/libgda-4.0/icons/hicolor/16x16/apps
-cp /usr/share/icons/gnome/22x22/apps/accessories-text-editor.png $prefix/share/libgda-4.0/icons/hicolor/22x22/apps
-cp /usr/share/icons/gnome/24x24/apps/accessories-text-editor.png $prefix/share/libgda-4.0/icons/hicolor/24x24/apps
-cp /usr/share/icons/gnome/32x32/apps/accessories-text-editor.png $prefix/share/libgda-4.0/icons/hicolor/32x32/apps
-
-add_all_files_to_zip $archive $prefix share/libgda-4.0/pixmaps
-add_all_files_to_nsh core $prefix share/libgda-4.0/pixmaps
-add_all_files_to_zip $archive $prefix share/libgda-4.0/icons/hicolor/16x16/actions
-add_all_files_to_nsh core $prefix share/libgda-4.0/icons/hicolor/16x16/actions
-add_all_files_to_zip $archive $prefix share/libgda-4.0/icons/hicolor/22x22/actions
-add_all_files_to_nsh core $prefix share/libgda-4.0/icons/hicolor/22x22/actions
-add_all_files_to_zip $archive $prefix share/libgda-4.0/icons/hicolor/24x24/actions
-add_all_files_to_nsh core $prefix share/libgda-4.0/icons/hicolor/24x24/actions
-add_all_files_to_zip $archive $prefix share/libgda-4.0/icons/hicolor/32x32/actions
-add_all_files_to_nsh core $prefix share/libgda-4.0/icons/hicolor/32x32/actions
-add_all_files_to_zip $archive $prefix share/libgda-4.0/icons/hicolor/scalable/actions
-add_all_files_to_nsh core $prefix share/libgda-4.0/icons/hicolor/scalable/actions
-add_all_files_to_zip $archive $prefix share/libgda-4.0/icons/hicolor/16x16/apps
-add_all_files_to_nsh core $prefix share/libgda-4.0/icons/hicolor/16x16/apps
-add_all_files_to_zip $archive $prefix share/libgda-4.0/icons/hicolor/22x22/apps
-add_all_files_to_nsh core $prefix share/libgda-4.0/icons/hicolor/22x22/apps
-add_all_files_to_zip $archive $prefix share/libgda-4.0/icons/hicolor/24x24/apps
-add_all_files_to_nsh core $prefix share/libgda-4.0/icons/hicolor/24x24/apps
-add_all_files_to_zip $archive $prefix share/libgda-4.0/icons/hicolor/32x32/apps
-add_all_files_to_nsh core $prefix share/libgda-4.0/icons/hicolor/32x32/apps
+cp /usr/share/icons/gnome/16x16/actions/bookmark-new.png $prefix/share/libgda-5.0/icons/hicolor/16x16/actions
+cp /usr/share/icons/gnome/22x22/actions/bookmark-new.png $prefix/share/libgda-5.0/icons/hicolor/22x22/actions
+cp /usr/share/icons/gnome/24x24/actions/bookmark-new.png $prefix/share/libgda-5.0/icons/hicolor/24x24/actions
+cp /usr/share/icons/gnome/32x32/actions/bookmark-new.png $prefix/share/libgda-5.0/icons/hicolor/32x32/actions
+cp /usr/share/icons/gnome/16x16/actions/window-new.png $prefix/share/libgda-5.0/icons/hicolor/16x16/actions
+cp /usr/share/icons/gnome/22x22/actions/window-new.png $prefix/share/libgda-5.0/icons/hicolor/22x22/actions
+cp /usr/share/icons/gnome/24x24/actions/window-new.png $prefix/share/libgda-5.0/icons/hicolor/24x24/actions
+cp /usr/share/icons/gnome/32x32/actions/window-new.png $prefix/share/libgda-5.0/icons/hicolor/32x32/actions
+mkdir -p $prefix/share/libgda-5.0/icons/hicolor/16x16/apps
+mkdir -p $prefix/share/libgda-5.0/icons/hicolor/22x22/apps
+mkdir -p $prefix/share/libgda-5.0/icons/hicolor/24x24/apps
+mkdir -p $prefix/share/libgda-5.0/icons/hicolor/32x32/apps
+cp /usr/share/icons/gnome/16x16/apps/accessories-text-editor.png $prefix/share/libgda-5.0/icons/hicolor/16x16/apps
+cp /usr/share/icons/gnome/22x22/apps/accessories-text-editor.png $prefix/share/libgda-5.0/icons/hicolor/22x22/apps
+cp /usr/share/icons/gnome/24x24/apps/accessories-text-editor.png $prefix/share/libgda-5.0/icons/hicolor/24x24/apps
+cp /usr/share/icons/gnome/32x32/apps/accessories-text-editor.png $prefix/share/libgda-5.0/icons/hicolor/32x32/apps
+
+add_all_files_to_zip $archive $prefix share/libgda-5.0/pixmaps
+add_all_files_to_nsh core $prefix share/libgda-5.0/pixmaps
+add_all_files_to_zip $archive $prefix share/libgda-5.0/icons/hicolor/16x16/actions
+add_all_files_to_nsh core $prefix share/libgda-5.0/icons/hicolor/16x16/actions
+add_all_files_to_zip $archive $prefix share/libgda-5.0/icons/hicolor/22x22/actions
+add_all_files_to_nsh core $prefix share/libgda-5.0/icons/hicolor/22x22/actions
+add_all_files_to_zip $archive $prefix share/libgda-5.0/icons/hicolor/24x24/actions
+add_all_files_to_nsh core $prefix share/libgda-5.0/icons/hicolor/24x24/actions
+add_all_files_to_zip $archive $prefix share/libgda-5.0/icons/hicolor/32x32/actions
+add_all_files_to_nsh core $prefix share/libgda-5.0/icons/hicolor/32x32/actions
+add_all_files_to_zip $archive $prefix share/libgda-5.0/icons/hicolor/scalable/actions
+add_all_files_to_nsh core $prefix share/libgda-5.0/icons/hicolor/scalable/actions
+add_all_files_to_zip $archive $prefix share/libgda-5.0/icons/hicolor/16x16/apps
+add_all_files_to_nsh core $prefix share/libgda-5.0/icons/hicolor/16x16/apps
+add_all_files_to_zip $archive $prefix share/libgda-5.0/icons/hicolor/22x22/apps
+add_all_files_to_nsh core $prefix share/libgda-5.0/icons/hicolor/22x22/apps
+add_all_files_to_zip $archive $prefix share/libgda-5.0/icons/hicolor/24x24/apps
+add_all_files_to_nsh core $prefix share/libgda-5.0/icons/hicolor/24x24/apps
+add_all_files_to_zip $archive $prefix share/libgda-5.0/icons/hicolor/32x32/apps
+add_all_files_to_nsh core $prefix share/libgda-5.0/icons/hicolor/32x32/apps
 
 files=(index.theme)
-add_files_to_zip $archive . share/libgda-4.0/icons/hicolor $files
-add_files_to_nsh core . share/libgda-4.0/icons/hicolor $files
+add_files_to_zip $archive . share/libgda-5.0/icons/hicolor $files
+add_files_to_nsh core . share/libgda-5.0/icons/hicolor $files
 
-files=(gda-browser-4.0.png)
+files=(gda-browser-5.0.png)
 add_files_to_zip $archive $prefix share/pixmaps $files
 add_files_to_nsh core $prefix share/pixmaps $files
 
 files=(gda-control-center.png)
-add_files_to_zip $archive $prefix share/libgda-4.0/pixmaps $files
-add_files_to_nsh core $prefix share/libgda-4.0/pixmaps $files
+add_files_to_zip $archive $prefix share/libgda-5.0/pixmaps $files
+add_files_to_nsh core $prefix share/libgda-5.0/pixmaps $files
 
 files=(gdaui-entry-number.xml gdaui-entry-string.xml)
-add_files_to_zip $archive $prefix share/libgda-4.0/ui $files
-add_files_to_nsh core $prefix share/libgda-4.0/ui $files
+add_files_to_zip $archive $prefix share/libgda-5.0/ui $files
+add_files_to_nsh core $prefix share/libgda-5.0/ui $files
 
 files=(cnc.js md5.js jquery.js mouseapp_2.js mouseirb_2.js irb.js gda.css gda-print.css irb.css)
-add_files_to_zip $archive $prefix share/libgda-4.0/web $files
-add_files_to_nsh core $prefix share/libgda-4.0/web $files
+add_files_to_zip $archive $prefix share/libgda-5.0/web $files
+add_files_to_nsh core $prefix share/libgda-5.0/web $files
 
 files=(libgda-paramlist.dtd libgda-array.dtd libgda-server-operation.dtd gdaui-layout.dtd)
-add_files_to_zip $archive $prefix share/libgda-4.0/dtd $files
-add_files_to_nsh core $prefix share/libgda-4.0/dtd $files
+add_files_to_zip $archive $prefix share/libgda-5.0/dtd $files
+add_files_to_nsh core $prefix share/libgda-5.0/dtd $files
 
 files=(config sales_test.db)
-add_files_to_zip $archive $prefix etc/libgda-4.0 $files
-add_files_to_nsh core $prefix etc/libgda-4.0 $files
+add_files_to_zip $archive $prefix etc/libgda-5.0 $files
+add_files_to_nsh core $prefix etc/libgda-5.0 $files
 
 files=(gdk-pixbuf.loaders gtk.immodules)
 add_files_to_zip $archive_ext $cross_path etc/gtk-2.0 $files
@@ -385,51 +385,51 @@ files=(pango.modules)
 add_files_to_zip $archive_ext $cross_path etc/pango $files
 add_files_to_nsh core $cross_path etc/pango $files
 
-files=(gda-sql-4.0.exe libgda-4.0-4.dll libgda-report-4.0-4.dll libgda-ui-4.0-4.dll gda-browser-4.0.exe gda-control-center-4.0.exe)
+files=(gda-sql-5.0.exe libgda-5.0-4.dll libgda-report-5.0-4.dll libgda-ui-5.0-4.dll gda-browser-5.0.exe gda-control-center-5.0.exe)
 add_files_to_zip $archive $prefix bin $files
 add_files_to_nsh core $prefix bin $files
 
-files=(gda-test-connection-4.0.exe)
+files=(gda-test-connection-5.0.exe)
 add_files_to_zip $archive $prefix bin $files
 
 files=(gspawn-win32-helper.exe)
 add_files_to_zip $archive $cross_path bin $files
 add_files_to_nsh core $cross_path bin $files
 
-files=(gdaui-demo-4.0.exe)
+files=(gdaui-demo-5.0.exe)
 add_files_to_zip $archive_dev $prefix bin $files
 
 files=(libgda-bdb.dll)
-add_files_to_zip $archive $prefix lib/libgda-4.0/providers $files
-add_files_to_nsh prov_bdb $prefix lib/libgda-4.0/providers $files
+add_files_to_zip $archive $prefix lib/libgda-5.0/providers $files
+add_files_to_nsh prov_bdb $prefix lib/libgda-5.0/providers $files
 
 files=(libgda-mdb.dll)
-add_files_to_zip $archive $prefix lib/libgda-4.0/providers $files
-add_files_to_nsh prov_mdb $prefix lib/libgda-4.0/providers $files
+add_files_to_zip $archive $prefix lib/libgda-5.0/providers $files
+add_files_to_nsh prov_mdb $prefix lib/libgda-5.0/providers $files
 
 files=(libgda-mysql.dll)
-add_files_to_zip $archive $prefix lib/libgda-4.0/providers $files
-add_files_to_nsh prov_mysql $prefix lib/libgda-4.0/providers $files
+add_files_to_zip $archive $prefix lib/libgda-5.0/providers $files
+add_files_to_nsh prov_mysql $prefix lib/libgda-5.0/providers $files
 
 files=(libgda-postgres.dll)
-add_files_to_zip $archive $prefix lib/libgda-4.0/providers $files
-add_files_to_nsh prov_postgresql $prefix lib/libgda-4.0/providers $files
+add_files_to_zip $archive $prefix lib/libgda-5.0/providers $files
+add_files_to_nsh prov_postgresql $prefix lib/libgda-5.0/providers $files
 
 files=(libgda-sqlite.dll)
-add_files_to_zip $archive $prefix lib/libgda-4.0/providers $files
-add_files_to_nsh prov_sqlite $prefix lib/libgda-4.0/providers $files
+add_files_to_zip $archive $prefix lib/libgda-5.0/providers $files
+add_files_to_nsh prov_sqlite $prefix lib/libgda-5.0/providers $files
 
 files=(libgda-web.dll)
-add_files_to_zip $archive $prefix lib/libgda-4.0/providers $files
-add_files_to_nsh prov_web $prefix lib/libgda-4.0/providers $files
+add_files_to_zip $archive $prefix lib/libgda-5.0/providers $files
+add_files_to_nsh prov_web $prefix lib/libgda-5.0/providers $files
 
 files=(libgda-oracle.dll)
-add_files_to_zip $archive $prefix lib/libgda-4.0/providers $files
-add_files_to_nsh prov_oracle $prefix lib/libgda-4.0/providers $files
+add_files_to_zip $archive $prefix lib/libgda-5.0/providers $files
+add_files_to_nsh prov_oracle $prefix lib/libgda-5.0/providers $files
 
 files=(gdaui-entry-filesel-spec.xml gdaui-entry-password.xml gdaui-entry-pict-spec.xml gdaui-entry-pict-spec_string.xml libgda-ui-plugins.dll)
-add_files_to_zip $archive $prefix lib/libgda-4.0/plugins $files
-add_files_to_nsh core $prefix lib/libgda-4.0/plugins $files
+add_files_to_zip $archive $prefix lib/libgda-5.0/plugins $files
+add_files_to_nsh core $prefix lib/libgda-5.0/plugins $files
 
 files=(libpixmap.dll libwimp.dll)
 add_files_to_zip $archive_ext $cross_path lib/gtk-2.0/2.10.0/engines $files
@@ -438,32 +438,32 @@ add_files_to_nsh core $cross_path lib/gtk-2.0/2.10.0/engines $files
 #
 # includes
 #
-files=(gda-attributes-manager.h gda-batch.h gda-binreloc.h gda-blob-op.h gda-column.h gda-config.h gda-connection-event.h gda-connection.h gda-connection-private.h gda-data-access-wrapper.h gda-data-comparator.h gda-data-handler.h gda-data-model-array.h gda-data-model-bdb.h gda-data-model-dir.h gda-data-model-extra.h gda-data-model.h gda-data-model-import.h gda-data-model-iter-extra.h gda-data-model-iter.h gda-data-model-private.h gda-data-proxy.h gda-data-select.h gda-debug-macros.h gda-decl.h gda-easy.h gda-enums.h gda-enum-types.h gda-holder.h gda-lockable.h gda-log.h gda-marshal.h gda-meta-store.h gda-meta-struct.h gda-mutex.h gda-quark-list.h gda-row.h gda-server-operation.h gda-server-provider-extra.h gda-server-provider.h gda-server-provider-private.h gda-set.h gda-statement-extra.h gda-statement.h gda-transaction-status.h gda-transaction-status-private.h gda-util.h gda-value.h gda-xa-transaction.h libgda.h libgda-global-variables.h gda-repetitive-statement.h gda-sql-
 builder.h gda-tree.h gda-tree-manager.h gda-tree-mgr-columns.h gda-tree-mgr-label.h gda-tree-mgr-schemas.h gda-tree-mgr-select.h gda-tree-mgr-tables.h gda-tree-node.h)
-add_files_to_zip $archive_dev $prefix include/libgda-4.0/libgda $files
+files=(gda-attributes-manager.h gda-batch.h gda-binreloc.h gda-blob-op.h gda-column.h gda-config.h gda-connection-event.h gda-connection.h gda-connection-private.h gda-data-access-wrapper.h gda-data-comparator.h gda-data-handler.h gda-data-model-array.h gda-data-model-bdb.h gda-data-model-dir.h gda-data-model-extra.h gda-data-model.h gda-data-model-import.h gda-data-model-iter-extra.h gda-data-model-iter.h gda-data-model-private.h gda-data-proxy.h gda-data-select.h gda-debug-macros.h gda-decl.h gda-enums.h gda-enum-types.h gda-holder.h gda-lockable.h gda-log.h gda-marshal.h gda-meta-store.h gda-meta-struct.h gda-mutex.h gda-quark-list.h gda-row.h gda-server-operation.h gda-server-provider-extra.h gda-server-provider.h gda-server-provider-private.h gda-set.h gda-statement-extra.h gda-statement.h gda-transaction-status.h gda-transaction-status-private.h gda-util.h gda-value.h gda-xa-transaction.h libgda.h libgda-global-variables.h gda-repetitive-statement.h gda-sql-builder.h g
 da-tree.h gda-tree-manager.h gda-tree-mgr-columns.h gda-tree-mgr-label.h gda-tree-mgr-schemas.h gda-tree-mgr-select.h gda-tree-mgr-tables.h gda-tree-node.h)
+add_files_to_zip $archive_dev $prefix include/libgda-5.0/libgda $files
 
 files=(gda-sqlite-provider.h)
-add_files_to_zip $archive_dev $prefix include/libgda-4.0/libgda/sqlite $files
+add_files_to_zip $archive_dev $prefix include/libgda-5.0/libgda/sqlite $files
 
 files=(gda-thread-wrapper.h)
-add_files_to_zip $archive_dev $prefix include/libgda-4.0/libgda/thread-wrapper $files
+add_files_to_zip $archive_dev $prefix include/libgda-5.0/libgda/thread-wrapper $files
 
 files=(gda-handler-bin.h gda-handler-boolean.h gda-handler-numerical.h gda-handler-string.h gda-handler-time.h gda-handler-type.h)
-add_files_to_zip $archive_dev $prefix include/libgda-4.0/libgda/handlers $files
+add_files_to_zip $archive_dev $prefix include/libgda-5.0/libgda/handlers $files
 
 files=(gda-report-docbook-document.h gda-report-document.h gda-report-engine.h gda-report-rml-document.h libgda-report.h)
-add_files_to_zip $archive_dev $prefix include/libgda-4.0/libgda-report $files
+add_files_to_zip $archive_dev $prefix include/libgda-5.0/libgda-report $files
 
 files=(gda-data-select-priv.h gda-pstmt.h gda-meta-column-types.h)
-add_files_to_zip $archive_dev $prefix include/libgda-4.0/libgda/providers-support $files
+add_files_to_zip $archive_dev $prefix include/libgda-5.0/libgda/providers-support $files
 
 files=(gda-sql-parser-enum-types.h gda-sql-parser.h gda-sql-statement.h gda-statement-struct-compound.h gda-statement-struct-decl.h gda-statement-struct-delete.h gda-statement-struct.h gda-statement-struct-insert.h gda-statement-struct-parts.h gda-statement-struct-pspec.h gda-statement-struct-select.h gda-statement-struct-trans.h gda-statement-struct-unknown.h gda-statement-struct-update.h gda-statement-struct-util.h)
-add_files_to_zip $archive_dev $prefix include/libgda-4.0/libgda/sql-parser $files
+add_files_to_zip $archive_dev $prefix include/libgda-5.0/libgda/sql-parser $files
 
 files=(gda-vconnection-data-model.h gda-vconnection-hub.h gda-virtual-connection.h gda-virtual-provider.h gda-vprovider-data-model.h gda-vprovider-hub.h libgda-virtual.h)
-add_files_to_zip $archive_dev $prefix include/libgda-4.0/libgda/virtual $files
+add_files_to_zip $archive_dev $prefix include/libgda-5.0/libgda/virtual $files
 
 files=(gdaui-basic-form.h gdaui-data-entry.h gdaui-data-selector.h gdaui-enums.h gdaui-login.h gdaui-raw-grid.h gdaui-cloud.h gdaui-data-filter.h gdaui-data-store.h gdaui-enum-types.h gdaui-plugin.h gdaui-server-operation.h gdaui-combo.h gdaui-data-proxy.h gdaui-decl.h gdaui-form.h gdaui-provider-selector.h gdaui-tree-store.h gdaui-data-cell-renderer-util.h gdaui-data-proxy-info.h gdaui-easy.h gdaui-grid.h gdaui-raw-form.h gdaui-rt-editor.h libgda-ui.h)
-add_files_to_zip $archive_dev $prefix include/libgda-4.0/libgda-ui $files
+add_files_to_zip $archive_dev $prefix include/libgda-5.0/libgda-ui $files
 
 #
 # PC files
@@ -473,19 +473,19 @@ add_all_files_to_zip $archive_dev $prefix lib/pkgconfig
 #
 # static libs
 #
-files=(libgda-4.0.a libgda-4.0.dll.a libgda-4.0.lib libgda-4.0.def libgda-report-4.0.a libgda-report-4.0.dll.a libgda-report-4.0.lib libgda-report-4.0.def libgda-ui-4.0.a libgda-ui-4.0.dll.a libgda-ui-4.0.lib libgda-ui-4.0.def)
+files=(libgda-5.0.a libgda-5.0.dll.a libgda-5.0.lib libgda-5.0.def libgda-report-5.0.a libgda-report-5.0.dll.a libgda-report-5.0.lib libgda-report-5.0.def libgda-ui-5.0.a libgda-ui-5.0.dll.a libgda-ui-5.0.lib libgda-ui-5.0.def)
 add_files_to_zip $archive_dev $prefix lib $files
 
 #
 # demo
 #
 files=(basic_form.c cloud.c combo.c custom_layout.xml data_model_dir.c ddl_queries.c demo_db.db form.c form_data_layout.c form_pict.c form_rw.c grid.c grid_data_layout.c grid_pict.c grid_rw.c linked_grid_form.c linked_model_param.c login.c provider_sel.c tree.c)
-add_files_to_zip $archive_dev $prefix share/libgda-4.0/demo $files
+add_files_to_zip $archive_dev $prefix share/libgda-5.0/demo $files
 
 #
 # doc
 #
-add_all_files_to_zip $archive_dev $prefix share/gtk-doc/html/libgda-4.0
+add_all_files_to_zip $archive_dev $prefix share/gtk-doc/html/libgda-5.0
 
 #
 # translations
diff --git a/installers/Windows/share/libgda-4.0/icons/hicolor/index.theme b/installers/Windows/share/libgda-5.0/icons/hicolor/index.theme
similarity index 100%
rename from installers/Windows/share/libgda-4.0/icons/hicolor/index.theme
rename to installers/Windows/share/libgda-5.0/icons/hicolor/index.theme
diff --git a/libgda-4.0.pc.in b/libgda-5.0.pc.in
similarity index 100%
rename from libgda-4.0.pc.in
rename to libgda-5.0.pc.in
diff --git a/libgda-report-4.0.pc.in b/libgda-report-5.0.pc.in
similarity index 100%
rename from libgda-report-4.0.pc.in
rename to libgda-report-5.0.pc.in
diff --git a/libgda-report/DocBook/Makefile.am b/libgda-report/DocBook/Makefile.am
index 7628d7c..3b6523e 100644
--- a/libgda-report/DocBook/Makefile.am
+++ b/libgda-report/DocBook/Makefile.am
@@ -1,4 +1,4 @@
-noinst_LTLIBRARIES = libgda-report-docbook-4.0.la
+noinst_LTLIBRARIES = libgda-report-docbook-5.0.la
 
 AM_CPPFLAGS = \
 	-I$(top_builddir)/libgda-report \
@@ -12,12 +12,12 @@ AM_CPPFLAGS = \
 gda_report_headers = \
 	gda-report-docbook-document.h
 
-libgda_report_docbook_4_0_la_SOURCES =	\
+libgda_report_docbook_5_0_la_SOURCES =	\
 	$(gda_report_headers)	\
 	gda-report-docbook-document.c	
 
-libgda_report_docbook_4_0_la_LIBADD = $(LIBGDA_LIBS) \
-	$(top_builddir)/libgda/libgda-4.0.la
+libgda_report_docbook_5_0_la_LIBADD = $(LIBGDA_LIBS) \
+	$(top_builddir)/libgda/libgda-5.0.la
 
 gdareportincludedir=$(includedir)/libgda-$(GDA_ABI_MAJOR_VERSION).$(GDA_ABI_MINOR_VERSION)/libgda-report
 gdareportinclude_HEADERS=$(gda_report_headers)
diff --git a/libgda-report/DocBook/gda-report-docbook-document.h b/libgda-report/DocBook/gda-report-docbook-document.h
index 942c6e7..e8244e9 100644
--- a/libgda-report/DocBook/gda-report-docbook-document.h
+++ b/libgda-report/DocBook/gda-report-docbook-document.h
@@ -1,5 +1,5 @@
-/* GDA 
- * Copyright (C) 2007 - 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 2007 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -45,6 +45,7 @@ struct _GdaReportDocbookDocument {
 struct _GdaReportDocbookDocumentClass {
 	GdaReportDocumentClass       parent_class;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
@@ -52,8 +53,17 @@ struct _GdaReportDocbookDocumentClass {
 	void (*_gda_reserved4) (void);
 };
 
-GType              gda_report_docbook_document_get_type        (void) G_GNUC_CONST;
+/**
+ * SECTION:gda-report-docbook-document
+ * @short_description: Report document based on the DocBook dialect
+ * @title: GdaReportDocbookDocument
+ * @stability: Stable
+ * @see_also: #GdaReportDocument
+ *
+ *
+ */
 
+GType              gda_report_docbook_document_get_type        (void) G_GNUC_CONST;
 GdaReportDocument *gda_report_docbook_document_new             (GdaReportEngine *engine);
 
 G_END_DECLS
diff --git a/libgda-report/Makefile.am b/libgda-report/Makefile.am
index 3ddd36a..89957ad 100644
--- a/libgda-report/Makefile.am
+++ b/libgda-report/Makefile.am
@@ -1,4 +1,4 @@
-lib_LTLIBRARIES = libgda-report-4.0.la
+lib_LTLIBRARIES = libgda-report-5.0.la
 
 SUBDIRS = engine DocBook RML
 
@@ -14,22 +14,22 @@ AM_CPPFLAGS = \
 report_headers = \
 	gda-report-document.h
 
-libgda_report_4_0_la_SOURCES = \
+libgda_report_5_0_la_SOURCES = \
 	$(report_headers) \
 	gda-report-document-private.h \
 	gda-report-document.c
 
-libgda_report_4_0_la_LDFLAGS = -version-info $(GDA_CURRENT):$(GDA_REVISION):$(GDA_AGE) \
+libgda_report_5_0_la_LDFLAGS = -version-info $(GDA_CURRENT):$(GDA_REVISION):$(GDA_AGE) \
 	$(NO_UNDEFINED) $(LIBTOOL_EXPORT_OPTIONS)
-libgda_report_4_0_la_LIBADD = engine/libgda-report-engine-4.0.la \
-	DocBook/libgda-report-docbook-4.0.la \
-	RML/libgda-report-rml-4.0.la \
+libgda_report_5_0_la_LIBADD = engine/libgda-report-engine-5.0.la \
+	DocBook/libgda-report-docbook-5.0.la \
+	RML/libgda-report-rml-5.0.la \
 	$(LIBGDA_LIBS) \
 	$(GDKPIXBUF_LIBS)
 
 if PLATFORM_WIN32
-libgda_report_4_0_la_LDFLAGS += -export-symbols $(builddir)/libgda-report.def
-libgda_report_4_0_la_DEPENDENCIES = libgda-report.def
+libgda_report_5_0_la_LDFLAGS += -export-symbols $(builddir)/libgda-report.def
+libgda_report_5_0_la_DEPENDENCIES = libgda-report.def
 
 libgda-report.def: libgda-report.symbols
 	(echo -e EXPORTS; $(CPP) -P - <$(srcdir)/libgda-report.symbols | sed -e '/^$$/d' -e 's/^/ /' -e 's/G_GNUC_[^ ]*//g' | sort) > libgda-report.def.tmp && mv libgda-report.def.tmp libgda-report.def
diff --git a/libgda-report/RML/Makefile.am b/libgda-report/RML/Makefile.am
index 154d484..354d8f7 100644
--- a/libgda-report/RML/Makefile.am
+++ b/libgda-report/RML/Makefile.am
@@ -1,4 +1,4 @@
-noinst_LTLIBRARIES = libgda-report-rml-4.0.la
+noinst_LTLIBRARIES = libgda-report-rml-5.0.la
 
 SUBDIRS = trml2html trml2pdf
 
@@ -14,12 +14,12 @@ AM_CPPFLAGS = \
 gda_report_headers = \
 	gda-report-rml-document.h
 
-libgda_report_rml_4_0_la_SOURCES =	\
+libgda_report_rml_5_0_la_SOURCES =	\
 	$(gda_report_headers)	\
 	gda-report-rml-document.c	
 
-libgda_report_rml_4_0_la_LIBADD = $(LIBGDA_LIBS) \
-	$(top_builddir)/libgda/libgda-4.0.la
+libgda_report_rml_5_0_la_LIBADD = $(LIBGDA_LIBS) \
+	$(top_builddir)/libgda/libgda-5.0.la
 
 gdareportincludedir=$(includedir)/libgda-$(GDA_ABI_MAJOR_VERSION).$(GDA_ABI_MINOR_VERSION)/libgda-report
 gdareportinclude_HEADERS=$(gda_report_headers)
diff --git a/libgda-report/RML/gda-report-rml-document.h b/libgda-report/RML/gda-report-rml-document.h
index 0a85bed..ec4ac71 100644
--- a/libgda-report/RML/gda-report-rml-document.h
+++ b/libgda-report/RML/gda-report-rml-document.h
@@ -1,5 +1,5 @@
-/* GDA 
- * Copyright (C) 2007 - 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 2007 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -45,6 +45,7 @@ struct _GdaReportRmlDocument {
 struct _GdaReportRmlDocumentClass {
 	GdaReportDocumentClass       parent_class;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
@@ -52,6 +53,22 @@ struct _GdaReportRmlDocumentClass {
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-report-rml-document
+ * @short_description: Report document based on the RML dialect
+ * @title: GdaReportRmlDocument
+ * @stability: Stable
+ * @see_also: #GdaReportDocument
+ *
+ * The #GdaReportRmlDocument makes it easy to create reports based on a RML
+ * template file. 
+ *
+ * RML (Report Markup Language) is an XML dialect which allows one to describe in a very precise way
+ * layouts which can then be converted to PDF. For more information, see the
+ * <ulink url="http://www.reportlab.org/";>ReportLab</ulink> or
+ * <ulink url="http://en.openreport.org/index.py/static/page/trml2pdf";>OpenReport</ulink> web pages.
+ */
+
 GType              gda_report_rml_document_get_type        (void) G_GNUC_CONST;
 
 GdaReportDocument *gda_report_rml_document_new             (GdaReportEngine *engine);
diff --git a/libgda-report/engine/Makefile.am b/libgda-report/engine/Makefile.am
index ce341c2..2d231a5 100644
--- a/libgda-report/engine/Makefile.am
+++ b/libgda-report/engine/Makefile.am
@@ -1,4 +1,4 @@
-noinst_LTLIBRARIES = libgda-report-engine-4.0.la
+noinst_LTLIBRARIES = libgda-report-engine-5.0.la
 noinst_PROGRAMS = test-rt-parser
 
 AM_CPPFLAGS = \
@@ -15,19 +15,19 @@ AM_CPPFLAGS = \
 gda_report_headers = \
 	gda-report-engine.h
 
-libgda_report_engine_4_0_la_SOURCES =	\
-	$(gda_report_headers) \
+libgda_report_engine_5_0_la_SOURCES =	\
+	$(gda_report_headers)	\
 	rt-parser.h \
 	rt-parser.c \
 	gda-report-engine.c	
 
-libgda_report_engine_4_0_la_LIBADD = $(LIBGDA_LIBS) \
-	$(top_builddir)/libgda/libgda-4.0.la 
+libgda_report_engine_5_0_la_LIBADD = $(LIBGDA_LIBS) \
+	$(top_builddir)/libgda/libgda-5.0.la 
 
 test_rt_parser_SOURCES = \
 	test-rt-parser.c
 
-test_rt_parser_LDADD = libgda-report-engine-4.0.la $(GDKPIXBUF_LIBS)
+test_rt_parser_LDADD = libgda-report-engine-5.0.la $(GDKPIXBUF_LIBS)
 
 gdareportincludedir=$(includedir)/libgda-$(GDA_ABI_MAJOR_VERSION).$(GDA_ABI_MINOR_VERSION)/libgda-report
 gdareportinclude_HEADERS=$(gda_report_headers)
diff --git a/libgda-report/engine/gda-report-engine.h b/libgda-report/engine/gda-report-engine.h
index d02d61b..3a29d39 100644
--- a/libgda-report/engine/gda-report-engine.h
+++ b/libgda-report/engine/gda-report-engine.h
@@ -1,5 +1,5 @@
-/* GDA 
- * Copyright (C) 2007 - 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 2007 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -48,6 +48,7 @@ struct _GdaReportEngine {
 struct _GdaReportEngineClass {
 	GObjectClass            parent_class;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
@@ -55,6 +56,154 @@ struct _GdaReportEngineClass {
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-report-engine
+ * @short_description: Low level report generator based on XML
+ * @title: GdaReportEngine
+ * @stability: Stable
+ * @see_also:
+ *
+ * The #GdaReportEngine object generates a report based on a specifications file in any XML format. It browses
+ * through the XML file and replaces the parts of it which are &lt;gda_report...&gt; action nodes. The generated
+ * XML file may then need to be processed using other post-processor tools depending on the XML file format.
+ *
+ * The following "action" tags known are:
+ * <table frame="all">
+ *   <tgroup cols="4" colsep="1" rowsep="1" align="justify">
+ *     <thead>
+ *       <row>
+ *         <entry>Node name</entry>
+ *         <entry>Description</entry>
+ *         <entry>Attributes</entry>
+ *         <entry>&lt;gda_report...&gt; sub nodes</entry>
+ *       </row>
+ *     </thead>
+ *     <tbody>
+ *       <row>
+ *         <entry>&lt;gda_report_section&gt;</entry>
+ *         <entry>
+ *	    <para>Starts a section which runs a SELECT query to generate a data model (#GdaDataModel).
+ *	    </para>
+ *	    <para>
+ *	      A parameter named &quot;&lt;query_name&gt;|?nrows&quot; is created and is available in any sub node
+ *	      of the &lt;gda_report_section&gt; node, which contains the number of rows in the section's data model.
+ *	    </para>
+ *	  </entry>
+ *         <entry>
+ *	    <itemizedlist>
+ *	      <listitem><para>"query_name": the name of a SELECT #GdaStatement to be run; using this attribute
+ *		  implies that a GdaStatement has
+ *		  already been created and that the query has been declared to the GdaReportEngine object
+ *		  with the "query_name "name. 
+ *		  To define a query within the report spec., add a &lt;gda_report_query&gt;
+ *		  sub node instead
+ *	      </para></listitem>
+ *	      <listitem><para>"cnc_name": name of the connection to use (the #GdaConnection object has
+ *		  already been created and has been declared to the GdaReportEngine object with the "cnc_name" name)
+ *	      </para></listitem>
+ *	    </itemizedlist>
+ *	  </entry>
+ *         <entry>
+ *	    <itemizedlist>
+ *	      <listitem><para>&lt;gda_report_query&gt; to define the SELECT query which will be run. It is also
+ *	      possible to use a named query using the "query_name" attribute of the &lt;gda_report_section&gt; node
+ *	      </para></listitem>
+ *	      <listitem><para>&lt;gda_report_if_empty_section&gt; to define the contents by which the &lt;gda_report_section&gt; 
+ *		  node is replaced if the data model for the section contains no row.
+ *	      </para></listitem>
+ *	    </itemizedlist>
+ *	  </entry>
+ *       </row>
+ *       <row>
+ *         <entry>&lt;gda_report_iter&gt;</entry>
+ *         <entry>
+ *	    <para>Repeats is list of children nodes for each row in the section's data model. Note that is that data
+ *	      model has no row, then the contents of the &lt;gda_report_iter&gt; node will not appear at all in the
+ *	      final result.
+ *	    </para>
+ *	    <para>
+ *	      For each column of the data model, several parameters are created, named 
+ *	      &lt;query_name&gt;|@&lt;column_name&gt; (such as &quot;customers|@@name&quot; for the &quot;name&quot; column)
+ *	      and &lt;query_name&gt;|#&lt;column_number&gt;,
+ *	      (such as &quot;customers|##0&quot; for the first column). 
+ *	      Those parameters can be used in any child node (recursively),
+ *	      and have their value updated for each row of the data model.
+ *	      For more information about the parameter's syntax, 
+ *	      see the <link linkend="SQL_queries">GDA SQL query syntax</link>.
+ *	    </para>
+ *	  </entry>
+ *         <entry/>
+ *         <entry/>
+ *       </row>
+ *       <row>
+ *         <entry>&lt;gda_report_query&gt;</entry>
+ *         <entry>Specifies the SQL of the SELECT query in a &lt;gda_report_section&gt; section. The SQL should be
+ *	  in the contents of that node</entry>
+ *         <entry><itemizedlist>
+ *	      <listitem><para>"query_name": name of the query</para></listitem>
+ *	      <listitem><para>"cnc_name": name of the connection to use (the #GdaConnection object has
+ *		  already been created and has been declared to the GdaReportEngine object with the "cnc_name" name)
+ *	      </para></listitem>
+ *	    </itemizedlist>
+ *	  </entry>
+ *         <entry></entry>
+ *       </row>
+ *       <row>
+ *         <entry>&lt;gda_report_param_value&gt;</entry>
+ *         <entry>Replace the node with the value of a parameter. The parameter can either by defined globally
+ *	  (and declared to the GdaReportEngine), or defined as part of a section</entry>
+ *         <entry>
+ *	    <itemizedlist>
+ *	      <listitem><para>"param_name" specifies the name of the parameter</para></listitem>
+ *	      <listitem><para>"converter" optionnally specifies a conversion to apply to the parameter's
+ *		  contents (for now only "richtext::docbook" to convert text
+ *		  in <ulink url="http://txt2tags.org/";>rich text format</ulink> to
+ *		  the DocBook syntax)</para></listitem>
+ *	    </itemizedlist>
+ *	  </entry>
+ *         <entry></entry>
+ *       </row>
+ *       <row>
+ *         <entry>&lt;gda_report_expr&gt;</entry>
+ *         <entry>Replace the node with the evaluation of an expression. The expression can be any SQLite valid expression,
+ *	  and can contain any reference to any parameter. For example the node:
+ *	    <programlisting><![CDATA[
+ *<gda_report_expr>
+ *##customers|@col IS NULL
+ *</gda_report_expr>]]></programlisting>
+ *	    will return a TRUE value if the parameter named &quot;customers|@@col&quot; is not NULL. For more
+ *	    information about the parameter's syntax, see the <link linkend="SQL_queries">GDA SQL query syntax</link>.
+ *	  </entry>
+ *         <entry></entry>
+ *         <entry></entry>
+ *       </row>
+ *       <row>
+ *         <entry>&lt;gda_report_if&gt;</entry>
+ *         <entry>Creates an "IF THEN ELSE" flow control, based on the evaluation of an expression (in the same way as for the
+ *	  &lt;gda_report_expr&gt; node). If the expression evaluates as TRUE, then the &lt;gda_report_if&gt; node will
+ *	  be replaced by the children nodes of the &lt;gda_report_if_true&gt; node if it exists, and otherwise by 
+ *	    the children nodes of the &lt;gda_report_if_false&gt; node if it exists.</entry>
+ *         <entry>"expr" to define the expression to evaluate</entry>
+ *         <entry>&lt;gda_report_if_true&gt; and &lt;gda_report_if_false&gt;</entry>
+ *       </row>
+ *       <row>
+ *         <entry>&lt;gda_report_if_true&gt;</entry>
+ *         <entry>Defines the contents to use when the expression of a &lt;gda_report_if&gt; is evaluated as TRUE</entry>
+ *         <entry></entry>
+ *         <entry></entry>
+ *       </row>
+ *       <row>
+ *         <entry>&lt;gda_report_if_false&gt;</entry>
+ *         <entry>Defines the contents to use when the expression of a &lt;gda_report_if&gt; is evaluated as FALSE</entry>
+ *         <entry></entry>
+ *         <entry></entry>
+ *       </row>
+ *     </tbody>
+ *   </tgroup>
+ * </table>
+ */
+
+
 GType            gda_report_engine_get_type        (void) G_GNUC_CONST;
 
 GdaReportEngine *gda_report_engine_new             (xmlNodePtr spec_node);
diff --git a/libgda-report/engine/rt-parser.c b/libgda-report/engine/rt-parser.c
index 14b52ad..d4a4c69 100644
--- a/libgda-report/engine/rt-parser.c
+++ b/libgda-report/engine/rt-parser.c
@@ -343,7 +343,7 @@ get_markup_token (const gchar *alltext, const gchar *start, gint *out_nb_spaces_
 	return MARKUP_NONE;
 }
 
-/**
+/*
  * steals @base64
  */
 static gchar *
diff --git a/libgda-report/gda-report-document.h b/libgda-report/gda-report-document.h
index 16a9227..14961ee 100644
--- a/libgda-report/gda-report-document.h
+++ b/libgda-report/gda-report-document.h
@@ -1,5 +1,5 @@
-/* GDA 
- * Copyright (C) 2007 - 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 2007 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -50,6 +50,7 @@ struct _GdaReportDocumentClass {
 	gboolean                (*run_as_html) (GdaReportDocument *doc, const gchar *filename, GError **error);
 	gboolean                (*run_as_pdf) (GdaReportDocument *doc, const gchar *filename, GError **error);
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
@@ -57,6 +58,17 @@ struct _GdaReportDocumentClass {
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-report-document
+ * @short_description: Report document
+ * @title: GdaReportDocument
+ * @stability: Stable
+ * @see_also:
+ *
+ * The #GdaReportDocument wraps the usage of a #GdaReportEngine for specific HTML or PDF targets. This class is
+ * abstract (no instance be created directly), and one of its subclasses has to be used.
+ */
+
 GType                 gda_report_document_get_type        (void) G_GNUC_CONST;
 
 void                  gda_report_document_set_template    (GdaReportDocument *doc, const gchar *file);
diff --git a/libgda-ui-4.0.pc.in b/libgda-ui-5.0.pc.in
similarity index 92%
rename from libgda-ui-4.0.pc.in
rename to libgda-ui-5.0.pc.in
index bfdcf31..91fd9dc 100644
--- a/libgda-ui-4.0.pc.in
+++ b/libgda-ui-5.0.pc.in
@@ -5,7 +5,8 @@ includedir= includedir@
 
 Name: libgda- GDA_ABI_MAJOR_VERSION@  GDA_ABI_MINOR_VERSION@
 Description: GDA (GNOME Data Access) library, UI extension
-Requires: libgda-4.0 gtk+-2.0
+
+Requires: libgda-4.0 gtk+-3.0
 Version: @VERSION@
 Libs: -L${libdir} -lgda-ui- GDA_ABI_MAJOR_VERSION@  GDA_ABI_MINOR_VERSION@
 Cflags: -I${includedir}/libgda- GDA_ABI_MAJOR_VERSION@  GDA_ABI_MINOR_VERSION@ @GDA_DEBUG_FLAGS@
diff --git a/libgda-ui/.gitignore b/libgda-ui/.gitignore
index a9fa5a2..ded2312 100644
--- a/libgda-ui/.gitignore
+++ b/libgda-ui/.gitignore
@@ -5,5 +5,5 @@ s-enum-types-h
 gdaui-enum-types.c
 gdaui-enum-types.h
 libgdaui.def
-Gdaui-4.0.gir
-Gdaui-4.0.typelib
+Gdaui-5.0.gir
+Gdaui-5.0.typelib
diff --git a/libgda-ui/Makefile.am b/libgda-ui/Makefile.am
index 8bdc52a..4b3b107 100644
--- a/libgda-ui/Makefile.am
+++ b/libgda-ui/Makefile.am
@@ -1,6 +1,6 @@
 QUIET_GEN = $(Q:@= echo ' GEN '$@;)
 
-lib_LTLIBRARIES = libgda-ui-4.0.la
+lib_LTLIBRARIES = libgda-ui-5.0.la
 
 SUBDIRS = marshallers data-entries internal data . data-entries/plugins demos
 
@@ -70,7 +70,7 @@ ui_sources = \
 	gdaui-tree-store.c \
 	gdaui-init.c
 
-libgda_ui_4_0_la_SOURCES = \
+libgda_ui_5_0_la_SOURCES = \
 	$(libgda_ui_built_cfiles) \
 	$(ui_sources)
 
@@ -110,22 +110,22 @@ s-enum-types-c: @REBUILD@ $(ui_headers) Makefile
 libgda_ui_built_headers = gdaui-enum-types.h
 libgda_ui_built_cfiles = gdaui-enum-types.c
 
-$(OBJECTS) $(libgda_ui_4_0_la_OBJECTS): $(libgda_ui_built_headers) $(libgda_ui_built_cfiles)
+$(OBJECTS) $(libgda_ui_5_0_la_OBJECTS): $(libgda_ui_built_headers) $(libgda_ui_built_cfiles)
 
-libgda_ui_4_0_la_LDFLAGS = -version-info $(GDA_CURRENT):$(GDA_REVISION):$(GDA_AGE) \
+libgda_ui_5_0_la_LDFLAGS = -version-info $(GDA_CURRENT):$(GDA_REVISION):$(GDA_AGE) \
 	$(NO_UNDEFINED) $(LIBTOOL_UI_EXPORT_OPTIONS)
-libgda_ui_4_0_la_LIBADD = \
+libgda_ui_5_0_la_LIBADD = \
 	marshallers/libgda-ui-marshallers.la \
 	internal/libgda-ui-internal.la \
 	data-entries/libgda-ui-data-entries.la \
-	../libgda/libgda-4.0.la \
+	../libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS) \
 	$(GTK_LIBS) \
 	$(GIO_LIBS)
 
 if PLATFORM_WIN32
-libgda_ui_4_0_la_LDFLAGS += -export-symbols $(builddir)/libgda-ui.def
-libgda_ui_4_0_la_DEPENDENCIES = libgda-ui.def
+libgda_ui_5_0_la_LDFLAGS += -export-symbols $(builddir)/libgda-ui.def
+libgda_ui_5_0_la_DEPENDENCIES = libgda-ui.def
 
 libgda-ui.def: libgda-ui.symbols
 	(echo -e EXPORTS; $(CPP) -P - <$(srcdir)/libgda-ui.symbols | sed -e '/^$$/d' -e 's/^/ /' -e 's/G_GNUC_[^ ]*//g' | sort) > libgda-ui.def.tmp && mv libgda-ui.def.tmp libgda-ui.def
@@ -215,13 +215,13 @@ introspection_sources = \
 	$(ui_sources) \
 	$(ui_data_entries_sources)
 
-Gdaui-4.0.gir: $(lib_LTLIBRARIES)
-Gdaui_4_0_gir_INCLUDES = Gtk-2.0 Gda-4.0
-Gdaui_4_0_gir_CFLAGS = $(GLOBAL_CFLAGS)
-Gdaui_4_0_gir_LIBS = $(lib_LTLIBRARIES) ../libgda/libgda-4.0.la
-Gdaui_4_0_gir_FILES = $(addprefix $(srcdir)/,$(introspection_sources))
+Gdaui-5.0.gir: $(lib_LTLIBRARIES)
+Gdaui_5_0_gir_INCLUDES = Gtk-3.0 Gda-5.0
+Gdaui_5_0_gir_CFLAGS = $(GLOBAL_CFLAGS)
+Gdaui_5_0_gir_LIBS = $(lib_LTLIBRARIES) ../libgda/libgda-5.0.la
+Gdaui_5_0_gir_FILES = $(addprefix $(srcdir)/,$(introspection_sources))
 INTROSPECTION_COMPILER_ARGS = --includedir=$(top_builddir)/libgda
-INTROSPECTION_GIRS += Gdaui-4.0.gir
+INTROSPECTION_GIRS += Gdaui-5.0.gir
 
 girdir = $(datadir)/gir-1.0
 gir_DATA = $(INTROSPECTION_GIRS)
diff --git a/libgda-ui/data-entries/Makefile.am b/libgda-ui/data-entries/Makefile.am
index 58cbb3a..db7a942 100644
--- a/libgda-ui/data-entries/Makefile.am
+++ b/libgda-ui/data-entries/Makefile.am
@@ -70,7 +70,7 @@ libgda_ui_data_entries_la_SOURCES = \
 	gdaui-formatted-entry.c \
 	gdaui-numeric-entry.c
 
-xmldir   = $(datadir)/libgda-4.0/ui
+xmldir   = $(datadir)/libgda-5.0/ui
 xml_in_files = \
 	gdaui-entry-string.xml.in \
 	gdaui-entry-number.xml.in
diff --git a/libgda-ui/data-entries/gdaui-data-cell-renderer-bin.c b/libgda-ui/data-entries/gdaui-data-cell-renderer-bin.c
index 088aaee..39be074 100644
--- a/libgda-ui/data-entries/gdaui-data-cell-renderer-bin.c
+++ b/libgda-ui/data-entries/gdaui-data-cell-renderer-bin.c
@@ -41,15 +41,14 @@ static void gdaui_data_cell_renderer_bin_class_init (GdauiDataCellRendererBinCla
 static void gdaui_data_cell_renderer_bin_dispose    (GObject *object);
 static void gdaui_data_cell_renderer_bin_finalize   (GObject *object);
 static void gdaui_data_cell_renderer_bin_render     (GtkCellRenderer            *cell,
-						     GdkWindow                  *window,
+						     cairo_t                    *cr,
 						     GtkWidget                  *widget,
-						     GdkRectangle               *background_area,
-						     GdkRectangle               *cell_area,
-						     GdkRectangle               *expose_area,
+						     const GdkRectangle         *background_area,
+						     const GdkRectangle         *cell_area,
 						     GtkCellRendererState        flags);
 static void gdaui_data_cell_renderer_bin_get_size   (GtkCellRenderer            *cell,
 						     GtkWidget                  *widget,
-						     GdkRectangle               *cell_area,
+						     const GdkRectangle         *cell_area,
 						     gint                       *x_offset,
 						     gint                       *y_offset,
 						     gint                       *width,
@@ -58,8 +57,8 @@ static gboolean gdaui_data_cell_renderer_bin_activate  (GtkCellRenderer
 							GdkEvent                   *event,
 							GtkWidget                  *widget,
 							const gchar                *path,
-							GdkRectangle               *background_area,
-							GdkRectangle               *cell_area,
+							const GdkRectangle         *background_area,
+							const GdkRectangle         *cell_area,
 							GtkCellRendererState        flags);
 
 enum {
@@ -346,7 +345,7 @@ gdaui_data_cell_renderer_bin_new (GdaDataHandler *dh, GType type)
 static void
 gdaui_data_cell_renderer_bin_get_size (GtkCellRenderer *cell,
 				       GtkWidget       *widget,
-				       GdkRectangle    *cell_area,
+				       const GdkRectangle *cell_area,
 				       gint            *x_offset,
 				       gint            *y_offset,
 				       gint            *width,
@@ -359,17 +358,16 @@ gdaui_data_cell_renderer_bin_get_size (GtkCellRenderer *cell,
 
 static void
 gdaui_data_cell_renderer_bin_render (GtkCellRenderer      *cell,
-				     GdkWindow            *window,
+				     cairo_t              *cr,
 				     GtkWidget            *widget,
-				     GdkRectangle         *background_area,
-				     GdkRectangle         *cell_area,
-				     GdkRectangle         *expose_area,
+				     const GdkRectangle   *background_area,
+				     const GdkRectangle   *cell_area,
 				     GtkCellRendererState  flags)
 {
 	GdauiDataCellRendererBin *datacell = (GdauiDataCellRendererBin*) cell;
 	GtkCellRendererClass *pixbuf_class = g_type_class_peek (GTK_TYPE_CELL_RENDERER_PIXBUF);
 
-	(pixbuf_class->render) (cell, window, widget, background_area, cell_area, expose_area, flags);
+	(pixbuf_class->render) (cell, cr, widget, background_area, cell_area, flags);
 	
 	if (datacell->priv->to_be_deleted) {
 		GtkStyle *style;
@@ -379,8 +377,7 @@ gdaui_data_cell_renderer_bin_render (GtkCellRenderer      *cell,
 		g_object_get ((GObject*) cell, "xpad", &xpad, NULL);
 
 		gtk_paint_hline (style,
-				 window, GTK_STATE_SELECTED,
-				 cell_area, 
+				 cr, GTK_STATE_SELECTED,
 				 widget,
 				 "hline",
 				 cell_area->x + xpad, cell_area->x + cell_area->width - xpad,
@@ -388,7 +385,7 @@ gdaui_data_cell_renderer_bin_render (GtkCellRenderer      *cell,
 		g_object_unref (style);
 	}
 	if (datacell->priv->invalid)
-		gdaui_data_cell_renderer_draw_invalid_area (window, cell_area);
+		gdaui_data_cell_renderer_draw_invalid_area (cr, cell_area);
 }
 
 static void
@@ -439,9 +436,9 @@ gdaui_data_cell_renderer_bin_activate  (GtkCellRenderer            *cell,
 					GdkEvent                   *event,
 					GtkWidget                  *widget,
 					const gchar                *path,
-					G_GNUC_UNUSED GdkRectangle               *background_area,
-					GdkRectangle               *cell_area,
-					G_GNUC_UNUSED GtkCellRendererState        flags)
+					G_GNUC_UNUSED const GdkRectangle *background_area,
+					const GdkRectangle         *cell_area,
+					G_GNUC_UNUSED GtkCellRendererState flags)
 {
 	GdauiDataCellRendererBin *bincell;
 	GtkTreeModel *model;
diff --git a/libgda-ui/data-entries/gdaui-data-cell-renderer-boolean.c b/libgda-ui/data-entries/gdaui-data-cell-renderer-boolean.c
index 60ece1d..03616ae 100644
--- a/libgda-ui/data-entries/gdaui-data-cell-renderer-boolean.c
+++ b/libgda-ui/data-entries/gdaui-data-cell-renderer-boolean.c
@@ -40,15 +40,14 @@ static void gdaui_data_cell_renderer_boolean_class_init (GdauiDataCellRendererBo
 static void gdaui_data_cell_renderer_boolean_dispose    (GObject *object);
 static void gdaui_data_cell_renderer_boolean_finalize   (GObject *object);
 static void gdaui_data_cell_renderer_boolean_render     (GtkCellRenderer            *cell,
-							 GdkWindow                  *window,
+							 cairo_t                    *cr,
 							 GtkWidget                  *widget,
-							 GdkRectangle               *background_area,
-							 GdkRectangle               *cell_area,
-							 GdkRectangle               *expose_area,
+							 const GdkRectangle         *background_area,
+							 const GdkRectangle         *cell_area,
 							 GtkCellRendererState        flags);
 static void gdaui_data_cell_renderer_boolean_get_size   (GtkCellRenderer            *cell,
 							 GtkWidget                  *widget,
-							 GdkRectangle               *cell_area,
+							 const GdkRectangle         *cell_area,
 							 gint                       *x_offset,
 							 gint                       *y_offset,
 							 gint                       *width,
@@ -57,8 +56,8 @@ static gboolean gdaui_data_cell_renderer_boolean_activate  (GtkCellRenderer
 							    GdkEvent                   *event,
 							    GtkWidget                  *widget,
 							    const gchar                *path,
-							    GdkRectangle               *background_area,
-							    GdkRectangle               *cell_area,
+							    const GdkRectangle         *background_area,
+							    const GdkRectangle         *cell_area,
 							    GtkCellRendererState        flags);
 
 enum {
@@ -353,7 +352,7 @@ gdaui_data_cell_renderer_boolean_new (GdaDataHandler *dh, GType type)
 static void
 gdaui_data_cell_renderer_boolean_get_size (GtkCellRenderer *cell,
 					   GtkWidget       *widget,
-					   GdkRectangle    *cell_area,
+					   const GdkRectangle *cell_area,
 					   gint            *x_offset,
 					   gint            *y_offset,
 					   gint            *width,
@@ -366,17 +365,16 @@ gdaui_data_cell_renderer_boolean_get_size (GtkCellRenderer *cell,
 
 static void
 gdaui_data_cell_renderer_boolean_render (GtkCellRenderer      *cell,
-					 GdkWindow            *window,
+					 cairo_t              *cr,
 					 GtkWidget            *widget,
-					 GdkRectangle         *background_area,
-					 GdkRectangle         *cell_area,
-					 GdkRectangle         *expose_area,
+					 const GdkRectangle   *background_area,
+					 const GdkRectangle   *cell_area,
 					 GtkCellRendererState  flags)
 {
 	GdauiDataCellRendererBoolean *datacell = GDAUI_DATA_CELL_RENDERER_BOOLEAN (cell);
 	GtkCellRendererClass *toggle_class = g_type_class_peek (GTK_TYPE_CELL_RENDERER_TOGGLE);
 
-	(toggle_class->render) (cell, window, widget, background_area, cell_area, expose_area, flags);
+	(toggle_class->render) (cell, cr, widget, background_area, cell_area, flags);
 
 	if (datacell->priv->to_be_deleted) {
 		GtkStyle *style;
@@ -384,8 +382,7 @@ gdaui_data_cell_renderer_boolean_render (GtkCellRenderer      *cell,
 
 		g_object_get (G_OBJECT(widget), "style", &style, "xpad", &xpad, NULL);
 		gtk_paint_hline (style,
-				 window, GTK_STATE_SELECTED,
-				 cell_area,
+				 cr, GTK_STATE_SELECTED,
 				 widget,
 				 "hline",
 				 cell_area->x + xpad, cell_area->x + cell_area->width - xpad,
@@ -393,7 +390,7 @@ gdaui_data_cell_renderer_boolean_render (GtkCellRenderer      *cell,
 
 	}
 	if (datacell->priv->invalid)
-		gdaui_data_cell_renderer_draw_invalid_area (window, cell_area);
+		gdaui_data_cell_renderer_draw_invalid_area (cr, cell_area);
 }
 
 static gboolean
@@ -401,8 +398,8 @@ gdaui_data_cell_renderer_boolean_activate  (GtkCellRenderer            *cell,
 					    GdkEvent                   *event,
 					    GtkWidget                  *widget,
 					    const gchar                *path,
-					    GdkRectangle               *background_area,
-					    GdkRectangle               *cell_area,
+					    const GdkRectangle         *background_area,
+					    const GdkRectangle         *cell_area,
 					    GtkCellRendererState        flags)
 {
 	gboolean editable;
diff --git a/libgda-ui/data-entries/gdaui-data-cell-renderer-combo.c b/libgda-ui/data-entries/gdaui-data-cell-renderer-combo.c
index 1bb04b2..6e2231a 100644
--- a/libgda-ui/data-entries/gdaui-data-cell-renderer-combo.c
+++ b/libgda-ui/data-entries/gdaui-data-cell-renderer-combo.c
@@ -47,25 +47,24 @@ static void gdaui_data_cell_renderer_combo_set_property  (GObject *object,
 							  GParamSpec *pspec);
 static void gdaui_data_cell_renderer_combo_get_size   (GtkCellRenderer          *cell,
 						       GtkWidget                *widget,
-						       GdkRectangle             *cell_area,
+						       const GdkRectangle       *cell_area,
 						       gint                     *x_offset,
 						       gint                     *y_offset,
 						       gint                     *width,
 						       gint                     *height);
 static void gdaui_data_cell_renderer_combo_render     (GtkCellRenderer          *cell,
-						       GdkWindow                *window,
+						       cairo_t                  *cr,
 						       GtkWidget                *widget,
-						       GdkRectangle             *background_area,
-						       GdkRectangle             *cell_area,
-						       GdkRectangle             *expose_area,
+						       const GdkRectangle       *background_area,
+						       const GdkRectangle       *cell_area,
 						       GtkCellRendererState      flags);
 
 static GtkCellEditable *gdaui_data_cell_renderer_combo_start_editing (GtkCellRenderer     *cell,
 								      GdkEvent            *event,
 								      GtkWidget           *widget,
 								      const gchar         *path,
-								      GdkRectangle        *background_area,
-								      GdkRectangle        *cell_area,
+								      const GdkRectangle  *background_area,
+								      const GdkRectangle  *cell_area,
 								      GtkCellRendererState flags);
 
 enum {
@@ -458,7 +457,7 @@ gdaui_data_cell_renderer_combo_new (GdauiSet *paramlist, GdauiSetSource *source)
 static void
 gdaui_data_cell_renderer_combo_get_size (GtkCellRenderer *cell,
 					 GtkWidget       *widget,
-					 GdkRectangle    *cell_area,
+					 const GdkRectangle *cell_area,
 					 gint            *x_offset,
 					 gint            *y_offset,
 					 gint            *width,
@@ -490,11 +489,10 @@ gdaui_data_cell_renderer_combo_get_size (GtkCellRenderer *cell,
 
 static void
 gdaui_data_cell_renderer_combo_render (GtkCellRenderer      *cell,
-				       GdkWindow            *window,
+				       cairo_t              *cr,
 				       GtkWidget            *widget,
-				       GdkRectangle         *background_area,
-				       GdkRectangle         *cell_area,
-				       GdkRectangle         *expose_area,
+				       const GdkRectangle   *background_area,
+				       const GdkRectangle   *cell_area,
 				       GtkCellRendererState  flags)
 	
 {
@@ -503,7 +501,7 @@ gdaui_data_cell_renderer_combo_render (GtkCellRenderer      *cell,
 
 	/* render the text as for the GtkCellRendererText */
 	GtkCellRendererClass *text_class = g_type_class_peek (GTK_TYPE_CELL_RENDERER_TEXT);
-	(text_class->render) (cell, window, widget, background_area, cell_area, expose_area, flags);
+	(text_class->render) (cell, cr, widget, background_area, cell_area, flags);
 
 	/* render the popdown menu symbol */
 	if ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED)	{
@@ -533,8 +531,7 @@ gdaui_data_cell_renderer_combo_render (GtkCellRenderer      *cell,
 		g_object_get ((GObject*) cell, "xpad", &xpad, "ypad", &ypad, NULL);
 		
 		gtk_paint_expander (style,
-				    window, state,
-				    cell_area, 
+				    cr, state,
 				    widget,
 				    "expander",
 				    cell_area->x + cell_area->width - xpad - expander_size/2.,
@@ -551,8 +548,7 @@ gdaui_data_cell_renderer_combo_render (GtkCellRenderer      *cell,
 		g_object_get ((GObject*) cell, "xpad", &xpad, NULL);
 
 		gtk_paint_hline (style,
-				 window, GTK_STATE_SELECTED,
-				 cell_area, 
+				 cr, GTK_STATE_SELECTED,
 				 widget,
 				 "hline",
 				 cell_area->x + xpad, cell_area->x + cell_area->width - xpad,
@@ -561,7 +557,7 @@ gdaui_data_cell_renderer_combo_render (GtkCellRenderer      *cell,
 	}
 
 	if (combocell->priv->invalid)
-		gdaui_data_cell_renderer_draw_invalid_area (window, cell_area);
+		gdaui_data_cell_renderer_draw_invalid_area (cr, cell_area);
 }
 
 static void gdaui_data_cell_renderer_combo_editing_done (GtkCellEditable *combo, GdauiDataCellRendererCombo *datacell);
@@ -573,8 +569,8 @@ gdaui_data_cell_renderer_combo_start_editing (GtkCellRenderer     *cell,
 					      G_GNUC_UNUSED GdkEvent            *event,
 					      G_GNUC_UNUSED GtkWidget           *widget,
 					      const gchar         *path,
-					      G_GNUC_UNUSED GdkRectangle        *background_area,
-					      G_GNUC_UNUSED GdkRectangle        *cell_area,
+					      G_GNUC_UNUSED const GdkRectangle        *background_area,
+					      G_GNUC_UNUSED const GdkRectangle        *cell_area,
 					      G_GNUC_UNUSED GtkCellRendererState flags)
 {
 	GdauiDataCellRendererCombo *datacell;
diff --git a/libgda-ui/data-entries/gdaui-data-cell-renderer-info.c b/libgda-ui/data-entries/gdaui-data-cell-renderer-info.c
index 9943583..fdb6cbc 100644
--- a/libgda-ui/data-entries/gdaui-data-cell-renderer-info.c
+++ b/libgda-ui/data-entries/gdaui-data-cell-renderer-info.c
@@ -42,25 +42,24 @@ static void gdaui_data_cell_renderer_info_dispose    (GObject *object);
 static void gdaui_data_cell_renderer_info_finalize   (GObject *object);
 
 static void gdaui_data_cell_renderer_info_get_size   (GtkCellRenderer            *cell,
-							 GtkWidget                  *widget,
-							 GdkRectangle               *cell_area,
-							 gint                       *x_offset,
-							 gint                       *y_offset,
-							 gint                       *width,
-							 gint                       *height);
+						      GtkWidget                  *widget,
+						      const GdkRectangle         *cell_area,
+						      gint                       *x_offset,
+						      gint                       *y_offset,
+						      gint                       *width,
+						      gint                       *height);
 static void gdaui_data_cell_renderer_info_render     (GtkCellRenderer            *cell,
-							 GdkWindow                  *window,
-							 GtkWidget                  *widget,
-							 GdkRectangle               *background_area,
-							 GdkRectangle               *cell_area,
-							 GdkRectangle               *expose_area,
-							 GtkCellRendererState        flags);
+						      cairo_t                    *cr,
+						      GtkWidget                  *widget,
+						      const GdkRectangle         *background_area,
+						      const GdkRectangle         *cell_area,
+						      GtkCellRendererState        flags);
 static gboolean gdaui_data_cell_renderer_info_activate  (GtkCellRenderer            *cell,
 							    GdkEvent                   *event,
 							    GtkWidget                  *widget,
 							    const gchar                *path,
-							    GdkRectangle               *background_area,
-							    GdkRectangle               *cell_area,
+							    const GdkRectangle         *background_area,
+							    const GdkRectangle         *cell_area,
 							    GtkCellRendererState        flags);
 
 
@@ -327,12 +326,12 @@ gdaui_data_cell_renderer_info_new (GdauiDataStore *store,
 
 static void
 gdaui_data_cell_renderer_info_get_size (GtkCellRenderer *cell,
-					   G_GNUC_UNUSED GtkWidget       *widget,
-					   GdkRectangle    *cell_area,
-					   gint            *x_offset,
-					   gint            *y_offset,
-					   gint            *width,
-					   gint            *height)
+					G_GNUC_UNUSED GtkWidget *widget,
+					const GdkRectangle *cell_area,
+					gint            *x_offset,
+					gint            *y_offset,
+					gint            *width,
+					gint            *height)
 {
 	gint calc_width;
 	gint calc_height;
@@ -367,12 +366,11 @@ gdaui_data_cell_renderer_info_get_size (GtkCellRenderer *cell,
 
 static void
 gdaui_data_cell_renderer_info_render (GtkCellRenderer      *cell,
-					 GdkWindow            *window,
-					 GtkWidget            *widget,
-					 G_GNUC_UNUSED GdkRectangle         *background_area,
-					 GdkRectangle         *cell_area,
-					 G_GNUC_UNUSED GdkRectangle         *expose_area,
-					 G_GNUC_UNUSED GtkCellRendererState  flags)
+				      cairo_t              *cr,
+				      GtkWidget            *widget,
+				      G_GNUC_UNUSED const GdkRectangle *background_area,
+				      const GdkRectangle   *cell_area,
+				      G_GNUC_UNUSED GtkCellRendererState  flags)
 {
 	GdauiDataCellRendererInfo *cellinfo = (GdauiDataCellRendererInfo *) cell;
 	gint width, height;
@@ -417,7 +415,7 @@ gdaui_data_cell_renderer_info_render (GtkCellRenderer      *cell,
 	style->bg[GTK_STATE_NORMAL] = *normal;
 	style->bg[GTK_STATE_ACTIVE] = *normal;
 	style->bg[GTK_STATE_PRELIGHT] = *prelight;
-	style = gtk_style_attach (style, window); /* Note that we must use the return value, because this function is documented as sometimes returning a new object. */
+
 	gdaui_data_cell_renderer_info_get_size (cell, widget, cell_area,
 						&x_offset, &y_offset,
 						&width, &height);
@@ -433,13 +431,13 @@ gdaui_data_cell_renderer_info_render (GtkCellRenderer      *cell,
 	state = GTK_STATE_NORMAL;
 
 	gtk_paint_box (style,
-		       window,
+		       cr,
 		       state, GTK_SHADOW_NONE,
-		       cell_area, widget, "cellcheck",
+		       widget, "cellcheck",
 		       cell_area->x + x_offset + xpad,
 		       cell_area->y + y_offset + ypad,
 		       width - 1, height - 1);
-	gtk_style_detach (style);
+
 	g_object_unref (G_OBJECT (style));
 }
 
@@ -447,12 +445,12 @@ gdaui_data_cell_renderer_info_render (GtkCellRenderer      *cell,
 static void mitem_activated_cb (GtkWidget *mitem, GdauiDataCellRendererInfo *cellinfo);
 static gint
 gdaui_data_cell_renderer_info_activate (GtkCellRenderer      *cell,
-					   G_GNUC_UNUSED GdkEvent             *event,
-					   G_GNUC_UNUSED GtkWidget            *widget,
-					   const gchar          *path,
-					   G_GNUC_UNUSED GdkRectangle         *background_area,
-					   G_GNUC_UNUSED GdkRectangle         *cell_area,
-					   G_GNUC_UNUSED GtkCellRendererState  flags)
+					G_GNUC_UNUSED GdkEvent             *event,
+					G_GNUC_UNUSED GtkWidget            *widget,
+					const gchar          *path,
+					G_GNUC_UNUSED const GdkRectangle *background_area,
+					G_GNUC_UNUSED const GdkRectangle *cell_area,
+					G_GNUC_UNUSED GtkCellRendererState  flags)
 {
 	GdauiDataCellRendererInfo *cellinfo;
 	gchar *tmp;
diff --git a/libgda-ui/data-entries/gdaui-data-cell-renderer-textual.c b/libgda-ui/data-entries/gdaui-data-cell-renderer-textual.c
index 3dd7ecd..f9e47c1 100644
--- a/libgda-ui/data-entries/gdaui-data-cell-renderer-textual.c
+++ b/libgda-ui/data-entries/gdaui-data-cell-renderer-textual.c
@@ -54,25 +54,24 @@ static void gdaui_data_cell_renderer_textual_set_property  (GObject *object,
 							    GParamSpec *pspec);
 static void gdaui_data_cell_renderer_textual_get_size   (GtkCellRenderer          *cell,
 							 GtkWidget                *widget,
-							 GdkRectangle             *cell_area,
+							 const GdkRectangle       *cell_area,
 							 gint                     *x_offset,
 							 gint                     *y_offset,
 							 gint                     *width,
 							 gint                     *height);
 static void gdaui_data_cell_renderer_textual_render     (GtkCellRenderer          *cell,
-							 GdkWindow                *window,
+							 cairo_t                  *cr,
 							 GtkWidget                *widget,
-							 GdkRectangle             *background_area,
-							 GdkRectangle             *cell_area,
-							 GdkRectangle             *expose_area,
+							 const GdkRectangle       *background_area,
+							 const GdkRectangle       *cell_area,
 							 GtkCellRendererState      flags);
 
 static GtkCellEditable *gdaui_data_cell_renderer_textual_start_editing (GtkCellRenderer      *cell,
 									GdkEvent             *event,
 									GtkWidget            *widget,
 									const gchar          *path,
-									GdkRectangle         *background_area,
-									GdkRectangle         *cell_area,
+									const GdkRectangle   *background_area,
+									const GdkRectangle   *cell_area,
 									GtkCellRendererState  flags);
 
 enum {
@@ -604,7 +603,7 @@ gdaui_data_cell_renderer_textual_new (GdaDataHandler *dh, GType type, const gcha
 static void
 gdaui_data_cell_renderer_textual_get_size (GtkCellRenderer *cell,
 					   GtkWidget       *widget,
-					   GdkRectangle    *cell_area,
+					   const GdkRectangle *cell_area,
 					   gint            *x_offset,
 					   gint            *y_offset,
 					   gint            *width,
@@ -616,17 +615,16 @@ gdaui_data_cell_renderer_textual_get_size (GtkCellRenderer *cell,
 
 static void
 gdaui_data_cell_renderer_textual_render (GtkCellRenderer      *cell,
-					 GdkWindow            *window,
+					 cairo_t              *cr,
 					 GtkWidget            *widget,
-					 GdkRectangle         *background_area,
-					 GdkRectangle         *cell_area,
-					 GdkRectangle         *expose_area,
+					 const GdkRectangle   *background_area,
+					 const GdkRectangle   *cell_area,
 					 GtkCellRendererState  flags)
 
 {
 	GdauiDataCellRendererTextual *datacell = (GdauiDataCellRendererTextual*) cell;
 	GtkCellRendererClass *text_class = g_type_class_peek (GTK_TYPE_CELL_RENDERER_TEXT);
-	(text_class->render) (cell, window, widget, background_area, cell_area, expose_area, flags);
+	(text_class->render) (cell, cr, widget, background_area, cell_area, flags);
 
 	if (datacell->priv->to_be_deleted) {
 		GtkStyle *style;
@@ -636,8 +634,7 @@ gdaui_data_cell_renderer_textual_render (GtkCellRenderer      *cell,
 		g_object_get ((GObject*) cell, "xpad", &xpad, NULL);
 
 		gtk_paint_hline (style,
-				 window, GTK_STATE_SELECTED,
-				 cell_area,
+				 cr, GTK_STATE_SELECTED,
 				 widget,
 				 "hline",
 				 cell_area->x + xpad, cell_area->x + cell_area->width - xpad,
@@ -645,7 +642,7 @@ gdaui_data_cell_renderer_textual_render (GtkCellRenderer      *cell,
 		g_object_unref (style);
 	}
 	if (datacell->priv->invalid)
-		gdaui_data_cell_renderer_draw_invalid_area (window, cell_area);
+		gdaui_data_cell_renderer_draw_invalid_area (cr, cell_area);
 }
 
 static void
@@ -695,8 +692,8 @@ gdaui_data_cell_renderer_textual_start_editing (GtkCellRenderer      *cell,
 						G_GNUC_UNUSED GdkEvent             *event,
 						G_GNUC_UNUSED GtkWidget            *widget,
 						const gchar          *path,
-						G_GNUC_UNUSED GdkRectangle         *background_area,
-						G_GNUC_UNUSED GdkRectangle         *cell_area,
+						G_GNUC_UNUSED const GdkRectangle *background_area,
+						G_GNUC_UNUSED const GdkRectangle *cell_area,
 						G_GNUC_UNUSED GtkCellRendererState  flags)
 {
 	GdauiDataCellRendererTextual *datacell;
diff --git a/libgda-ui/data-entries/gdaui-data-cell-renderer-util.c b/libgda-ui/data-entries/gdaui-data-cell-renderer-util.c
index 29ac45b..14e0823 100644
--- a/libgda-ui/data-entries/gdaui-data-cell-renderer-util.c
+++ b/libgda-ui/data-entries/gdaui-data-cell-renderer-util.c
@@ -20,10 +20,8 @@
 #include "gdaui-data-cell-renderer-util.h"
 
 void
-gdaui_data_cell_renderer_draw_invalid_area (GdkWindow *window, GdkRectangle *cell_area)
+gdaui_data_cell_renderer_draw_invalid_area (cairo_t *cr, const GdkRectangle *cell_area)
 {
-	cairo_t *cr;
-	cr = gdk_cairo_create (window);
 	cairo_set_source_rgba (cr, .5, .5, .5, .4);
 	cairo_rectangle (cr, cell_area->x, cell_area->y, cell_area->width,  cell_area->height);
 	cairo_clip (cr);
@@ -32,6 +30,4 @@ gdaui_data_cell_renderer_draw_invalid_area (GdkWindow *window, GdkRectangle *cel
 	cairo_rectangle (cr, cell_area->x, cell_area->y,
 			 cell_area->width, cell_area->height);
 	cairo_fill (cr);
-	
-	cairo_destroy (cr);
 }
diff --git a/libgda-ui/data-entries/gdaui-data-cell-renderer-util.h b/libgda-ui/data-entries/gdaui-data-cell-renderer-util.h
index 5723e25..bf21e10 100644
--- a/libgda-ui/data-entries/gdaui-data-cell-renderer-util.h
+++ b/libgda-ui/data-entries/gdaui-data-cell-renderer-util.h
@@ -22,6 +22,6 @@
 
 #include <gtk/gtk.h>
 
-void gdaui_data_cell_renderer_draw_invalid_area (GdkWindow *window, GdkRectangle *cell_area);
+void gdaui_data_cell_renderer_draw_invalid_area (cairo_t *cr, const GdkRectangle *cell_area);
 
 #endif
diff --git a/libgda-ui/data-entries/gdaui-entry-bin.c b/libgda-ui/data-entries/gdaui-entry-bin.c
index 366a176..e560981 100644
--- a/libgda-ui/data-entries/gdaui-entry-bin.c
+++ b/libgda-ui/data-entries/gdaui-entry-bin.c
@@ -1,6 +1,6 @@
 /* gdaui-entry-bin.c
  *
- * Copyright (C) 2009 Vivien Malerba
+ * Copyright (C) 2009 - 2010 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -333,19 +333,12 @@ popup_position (PopupContainer *container, gint *out_x, gint *out_y)
 
         gtk_widget_size_request (poswidget, &req);
 
-#if GTK_CHECK_VERSION(2,18,0)
         gdk_window_get_origin (gtk_widget_get_window (poswidget), &x, &y);
 	GtkAllocation alloc;
 	gtk_widget_get_allocation (poswidget, &alloc);
         x += alloc.x;
         y += alloc.y;
         y += alloc.height;
-#else
-	gdk_window_get_origin (poswidget->window, &x, &y);
-	x += poswidget->allocation.x;
-        y += poswidget->allocation.y;
-	y += poswidget->allocation.height;
-#endif
 
         if (x < 0)
                 x = 0;
diff --git a/libgda-ui/data-entries/gdaui-entry-combo.c b/libgda-ui/data-entries/gdaui-entry-combo.c
index 88d8de2..5d9b69a 100644
--- a/libgda-ui/data-entries/gdaui-entry-combo.c
+++ b/libgda-ui/data-entries/gdaui-entry-combo.c
@@ -726,9 +726,6 @@ gdaui_entry_combo_set_value (GdauiDataEntry *iface, const GValue *value)
         g_return_if_fail (iface && GDAUI_IS_ENTRY_COMBO (iface));
         combo = GDAUI_ENTRY_COMBO (iface);
         g_return_if_fail (combo->priv);
-        g_return_if_fail (!value ||
-                          (value && (gda_value_isa ((GValue*) value, GDA_TYPE_LIST) ||
-                                     gda_value_isa ((GValue*) value, GDA_TYPE_LIST))));
 
 	TO_IMPLEMENT;
 }
diff --git a/libgda-ui/data-entries/gdaui-entry-common-time.c b/libgda-ui/data-entries/gdaui-entry-common-time.c
index 7da3307..579b7d6 100644
--- a/libgda-ui/data-entries/gdaui-entry-common-time.c
+++ b/libgda-ui/data-entries/gdaui-entry-common-time.c
@@ -1,6 +1,6 @@
 /* gdaui-entry-common-time.c
  *
- * Copyright (C) 2003 - 2010 Vivien Malerba
+ * Copyright (C) 2003 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -147,7 +147,8 @@ gdaui_entry_common_time_class_init (GdauiEntryCommonTimeClass * class)
 	object_class->get_property = gdaui_entry_common_time_get_property;
 
 	g_object_class_install_property (object_class, PROP_EDITING_CANCELED,
-					 g_param_spec_boolean ("editing-canceled", NULL, NULL, FALSE, G_PARAM_READABLE));
+					 g_param_spec_boolean ("editing-canceled", NULL, NULL, FALSE,
+							       G_PARAM_READABLE | G_PARAM_WRITABLE));
 	g_object_class_install_property (object_class, PROP_TYPE,
 					 g_param_spec_uint ("type", NULL, NULL, 0, G_MAXUINT, GDA_TYPE_TIME, 
 							    G_PARAM_WRITABLE | G_PARAM_READABLE));
@@ -156,7 +157,7 @@ gdaui_entry_common_time_class_init (GdauiEntryCommonTimeClass * class)
 static gboolean
 key_press_event_cb (GdauiEntryCommonTime *mgtim, GdkEventKey *key_event, G_GNUC_UNUSED gpointer data)
 {
-	if (key_event->keyval == GDK_Escape)
+	if (key_event->keyval == GDK_KEY_Escape)
 		mgtim->priv->editing_canceled = TRUE;
 	return FALSE;
 }
@@ -259,6 +260,9 @@ gdaui_entry_common_time_set_property (GObject *object,
 		case PROP_TYPE:
 			gdaui_data_entry_set_value_type (GDAUI_DATA_ENTRY (object), g_value_get_uint (value));
 			break;
+		case PROP_EDITING_CANCELED:
+			TO_IMPLEMENT;
+			break;
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
 			break;
@@ -771,7 +775,7 @@ date_delete_popup (G_GNUC_UNUSED GtkWidget *widget, GdauiEntryCommonTime *mgtim)
 static gint
 date_key_press_popup (GtkWidget *widget, GdkEventKey *event, GdauiEntryCommonTime *mgtim)
 {
-	if (event->keyval != GDK_Escape)
+	if (event->keyval != GDK_KEY_Escape)
                 return FALSE;
 
         g_signal_stop_emission_by_name (widget, "key-press-event");
@@ -903,13 +907,8 @@ date_calendar_choose_cb (GtkWidget *button, GdauiEntryCommonTime *mgtim)
 
         /* popup window */
         /* Temporarily grab pointer and keyboard, copied from GnomeDateEdit */
-#if GTK_CHECK_VERSION(2,18,0)
         if (!popup_grab_on_window (gtk_widget_get_window (button), gtk_get_current_event_time ()))
                 return;
-#else
-	if (!popup_grab_on_window (button->window, gtk_get_current_event_time ()))
-		return;
-#endif
 
         position_popup (mgtim);
         gtk_grab_add (mgtim->priv->window);
@@ -951,13 +950,8 @@ date_calendar_choose_cb (GtkWidget *button, GdauiEntryCommonTime *mgtim)
 		gtk_window_move (GTK_WINDOW (mgtim->priv->window), root_x, root_y);
 
         gtk_widget_grab_focus (mgtim->priv->date);
-#if GTK_CHECK_VERSION(2,18,0)
         popup_grab_on_window (gtk_widget_get_window (mgtim->priv->window),
                               gtk_get_current_event_time ());
-#else
-	popup_grab_on_window (mgtim->priv->window->window,
-			      gtk_get_current_event_time ());
-#endif
 }
 
 static gboolean
@@ -987,7 +981,6 @@ position_popup (GdauiEntryCommonTime *mgtim)
 
         gtk_widget_size_request (mgtim->priv->window, &req);
 
-#if GTK_CHECK_VERSION(2,18,0)
         gdk_window_get_origin (gtk_widget_get_window (mgtim->priv->date_button), &x, &y);
 	GtkAllocation alloc;
 	gtk_widget_get_allocation (mgtim->priv->date_button, &alloc);
@@ -995,14 +988,6 @@ position_popup (GdauiEntryCommonTime *mgtim)
         y += alloc.y;
         bwidth = alloc.width;
         bheight = alloc.height;
-#else
-	gdk_window_get_origin (mgtim->priv->date_button->window, &x, &y);
-	
-        x += mgtim->priv->date_button->allocation.x;
-        y += mgtim->priv->date_button->allocation.y;
-        bwidth = mgtim->priv->date_button->allocation.width;
-	bheight = mgtim->priv->date_button->allocation.height;
-#endif
 
         x += bwidth - req.width;
         y += bheight;
diff --git a/libgda-ui/data-entries/gdaui-entry-number.c b/libgda-ui/data-entries/gdaui-entry-number.c
index 3e00090..6bfa916 100644
--- a/libgda-ui/data-entries/gdaui-entry-number.c
+++ b/libgda-ui/data-entries/gdaui-entry-number.c
@@ -1,6 +1,6 @@
 /* gdaui-entry-number.c
  *
- * Copyright (C) 2009 - 2010 Vivien Malerba
+ * Copyright (C) 2009 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -142,7 +142,8 @@ gdaui_entry_number_class_init (GdauiEntryNumberClass * klass)
 	object_class->get_property = gdaui_entry_number_get_property;
 
 	g_object_class_install_property (object_class, PROP_EDITING_CANCELED,
-					 g_param_spec_boolean ("editing-canceled", NULL, NULL, FALSE, G_PARAM_READABLE));
+					 g_param_spec_boolean ("editing-canceled", NULL, NULL, FALSE,
+							       G_PARAM_READABLE | G_PARAM_WRITABLE));
 	g_object_class_install_property (object_class, PROP_OPTIONS,
 					 g_param_spec_string ("options", NULL, NULL, NULL, G_PARAM_WRITABLE));
 }
@@ -150,7 +151,7 @@ gdaui_entry_number_class_init (GdauiEntryNumberClass * klass)
 static gboolean
 key_press_event_cb (GdauiEntryNumber *mgstr, GdkEventKey *key_event, G_GNUC_UNUSED gpointer data)
 {
-	if (key_event->keyval == GDK_Escape)
+	if (key_event->keyval == GDK_KEY_Escape)
 		mgstr->priv->editing_canceled = TRUE;
 	return FALSE;
 }
@@ -255,9 +256,9 @@ gdaui_entry_number_finalize (GObject   * object)
 
 static void
 gdaui_entry_number_set_property (GObject *object,
-				    guint param_id,
-				    const GValue *value,
-				    GParamSpec *pspec)
+				 guint param_id,
+				 const GValue *value,
+				 GParamSpec *pspec)
 {
 	GdauiEntryNumber *mgstr;
 
@@ -267,6 +268,9 @@ gdaui_entry_number_set_property (GObject *object,
 		case PROP_OPTIONS:
 			set_entry_options (mgstr, g_value_get_string (value));
 			break;
+		case PROP_EDITING_CANCELED:
+			TO_IMPLEMENT;
+			break;
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
 			break;
@@ -276,9 +280,9 @@ gdaui_entry_number_set_property (GObject *object,
 
 static void
 gdaui_entry_number_get_property (GObject *object,
-			     guint param_id,
-			     GValue *value,
-			     GParamSpec *pspec)
+				 guint param_id,
+				 GValue *value,
+				 GParamSpec *pspec)
 {
 	GdauiEntryNumber *mgstr;
 
diff --git a/libgda-ui/data-entries/gdaui-entry-shell.c b/libgda-ui/data-entries/gdaui-entry-shell.c
index 3b0940a..7b5cc23 100644
--- a/libgda-ui/data-entries/gdaui-entry-shell.c
+++ b/libgda-ui/data-entries/gdaui-entry-shell.c
@@ -24,9 +24,7 @@
 #include <libgda/gda-data-handler.h>
 #include <libgda-ui/internal/utility.h>
 #include <glib/gi18n-lib.h>
-#if GTK_CHECK_VERSION (2,20,0)
 #include "widget-embedder.h"
-#endif
 static void gdaui_entry_shell_class_init (GdauiEntryShellClass *class);
 static void gdaui_entry_shell_init (GdauiEntryShell *wid);
 static void gdaui_entry_shell_dispose (GObject *object);
@@ -170,11 +168,7 @@ gdaui_entry_shell_init (GdauiEntryShell * shell)
 	shell->priv->hbox = hbox;
 
 	/* vbox to insert the real widget to edit data */
-#if GTK_CHECK_VERSION (2,20,0)
 	shell->priv->embedder = widget_embedder_new ();
-#else
-	shell->priv->embedder = gtk_vbox_new (FALSE, 0);
-#endif
 	gtk_box_pack_start (GTK_BOX (hbox), shell->priv->embedder, TRUE, TRUE, 0);
 	gtk_widget_show (shell->priv->embedder);	
 
@@ -307,11 +301,7 @@ gdaui_entry_shell_pack_entry (GdauiEntryShell *shell, GtkWidget *main_widget)
 {
 	g_return_if_fail (GDAUI_IS_ENTRY_SHELL (shell));
 	g_return_if_fail (main_widget && GTK_IS_WIDGET (main_widget));
-#if GTK_CHECK_VERSION (2,18,0)
 	gtk_container_add (GTK_CONTAINER (shell->priv->embedder), main_widget);
-#else
-	gtk_box_pack_start (GTK_BOX (shell->priv->embedder), main_widget, TRUE, TRUE, 0);
-#endif
 
 	/* signals */
 	g_signal_connect (G_OBJECT (shell), "contents-modified",
@@ -356,7 +346,7 @@ event_cb (G_GNUC_UNUSED GtkWidget *widget, GdkEvent *event, GdauiEntryShell *she
 		GtkWidget *menu;
 		GdkEventKey *kevent = (GdkEventKey *) event;
 
-		if (kevent->keyval == GDK_space) {
+		if (kevent->keyval == GDK_KEY_space) {
 			guint attributes;
 
 			attributes = gdaui_entry_shell_refresh_attributes (shell);
@@ -368,7 +358,7 @@ event_cb (G_GNUC_UNUSED GtkWidget *widget, GdkEvent *event, GdauiEntryShell *she
 			done = TRUE;
 		}
 		else {
-			if (kevent->keyval == GDK_Tab)
+			if (kevent->keyval == GDK_KEY_Tab)
 				done = FALSE;
 			else
 				done = TRUE;
@@ -471,14 +461,5 @@ gdaui_entry_shell_set_unknown (GdauiEntryShell *shell, gboolean unknown)
 {
 	g_return_if_fail (GDAUI_IS_ENTRY_SHELL (shell));
 
-#if GTK_CHECK_VERSION (2,20,0)
 	widget_embedder_set_valid ((WidgetEmbedder*) shell->priv->embedder, !unknown);
-#else
-	/*
-	if (unknown)
-		gtk_widget_hide (shell->priv->embedder);
-	else
-		gtk_widget_show (shell->priv->embedder);
-	*/
-#endif
 }
diff --git a/libgda-ui/data-entries/gdaui-entry-string.c b/libgda-ui/data-entries/gdaui-entry-string.c
index 37f3c48..4ce2d68 100644
--- a/libgda-ui/data-entries/gdaui-entry-string.c
+++ b/libgda-ui/data-entries/gdaui-entry-string.c
@@ -1,6 +1,6 @@
 /* gdaui-entry-string.c
  *
- * Copyright (C) 2003 - 2010 Vivien Malerba
+ * Copyright (C) 2003 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -153,7 +153,8 @@ gdaui_entry_string_class_init (GdauiEntryStringClass * klass)
 					 g_param_spec_boolean ("multiline", NULL, NULL, FALSE, 
 							       G_PARAM_READABLE | G_PARAM_WRITABLE));
 	g_object_class_install_property (object_class, PROP_EDITING_CANCELED,
-					 g_param_spec_boolean ("editing-canceled", NULL, NULL, FALSE, G_PARAM_READABLE));
+					 g_param_spec_boolean ("editing-canceled", NULL, NULL, FALSE,
+							       G_PARAM_READABLE | G_PARAM_WRITABLE));
 	g_object_class_install_property (object_class, PROP_OPTIONS,
 					 g_param_spec_string ("options", NULL, NULL, NULL, G_PARAM_WRITABLE));
 }
@@ -161,7 +162,7 @@ gdaui_entry_string_class_init (GdauiEntryStringClass * klass)
 static gboolean
 key_press_event_cb (GdauiEntryString *mgstr, GdkEventKey *key_event, G_GNUC_UNUSED gpointer data)
 {
-	if (key_event->keyval == GDK_Escape)
+	if (key_event->keyval == GDK_KEY_Escape)
 		mgstr->priv->editing_canceled = TRUE;
 	return FALSE;
 }
@@ -290,6 +291,9 @@ gdaui_entry_string_set_property (GObject *object,
 		case PROP_OPTIONS:
 			set_entry_options (mgstr, g_value_get_string (value));
 			break;
+		case PROP_EDITING_CANCELED:
+			TO_IMPLEMENT;
+			break;
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
 			break;
diff --git a/libgda-ui/data-entries/gdaui-entry.h b/libgda-ui/data-entries/gdaui-entry.h
index 69e1143..dd5214b 100644
--- a/libgda-ui/data-entries/gdaui-entry.h
+++ b/libgda-ui/data-entries/gdaui-entry.h
@@ -38,13 +38,13 @@ typedef struct _GdauiEntryPrivate GdauiEntryPrivate;
 
 struct _GdauiEntry
 {
-	GtkEntry                   entry;
+	GtkEntry           entry;
 	GdauiEntryPrivate *priv;
 };
 
 struct _GdauiEntryClass
 {
-	GtkEntryClass              parent_class;
+	GtkEntryClass           parent_class;
 
 	/* virtual methods */
 	/**
diff --git a/libgda-ui/data-entries/plugins/Makefile.am b/libgda-ui/data-entries/plugins/Makefile.am
index cbdf36d..a05ba33 100644
--- a/libgda-ui/data-entries/plugins/Makefile.am
+++ b/libgda-ui/data-entries/plugins/Makefile.am
@@ -52,8 +52,8 @@ libgda_ui_plugins_la_SOURCES = \
 
 libgda_ui_plugins_la_LDFLAGS = -export-dynamic -module -avoid-version $(NO_UNDEFINED)
 libgda_ui_plugins_la_LIBADD = \
-        $(top_builddir)/libgda-ui/libgda-ui-4.0.la \
-	$(top_builddir)/libgda/libgda-4.0.la \
+        $(top_builddir)/libgda-ui/libgda-ui-5.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGCRYPT_LIBS) \
 	$(LIBGDA_LIBS) \
         $(GTK_LIBS) \
diff --git a/libgda-ui/data-entries/plugins/common-pict.c b/libgda-ui/data-entries/plugins/common-pict.c
index 23cd2bd..2aeb1a2 100644
--- a/libgda-ui/data-entries/plugins/common-pict.c
+++ b/libgda-ui/data-entries/plugins/common-pict.c
@@ -1,5 +1,5 @@
 /* common-pict.c
- * Copyright (C) 2006 - 2007 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2006 - 2011 Vivien Malerba <malerba gnome-db org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -83,7 +83,6 @@ common_pict_load_data (PictOptions *options, const GValue *value, PictBinData *b
 						bindata->data_length = strlen ((gchar *) bindata->data);
 						break;
 					case ENCODING_BASE64: {
-#if (GLIB_MINOR_VERSION >= 12)
 						gsize out_len;
 						bindata->data = g_base64_decode (str, &out_len);
 						if (out_len > 0)
@@ -93,12 +92,6 @@ common_pict_load_data (PictOptions *options, const GValue *value, PictBinData *b
 							bindata->data = NULL;
 							bindata->data_length = 0;
 						}
-#else
-						g_warning ("Base64 enoding/decoding is not supported in the "
-							   "GLib version %d.%d.%d",
-							   glib_major_version, glib_minor_version, glib_micro_version);
-#endif
-
 						break;
 					}
 					}
@@ -263,13 +256,10 @@ common_pict_make_pixbuf (PictOptions *options, PictBinData *bindata, PictAllocat
 				gchar *notice_msg;
 				notice_msg = g_strdup_printf (_("Error while interpreting data as an image:\n%s"),
 							      loc_error && loc_error->message ? loc_error->message : _("No detail"));
-				g_error_free (loc_error);
 				*stock = GTK_STOCK_DIALOG_WARNING;
-#if GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 18
-				g_set_error (error, 0, 0, "%s", notice_msg);
-#else
-				g_set_error_literal (error, 0, 0, notice_msg);
-#endif
+				g_set_error_literal (error, loc_error ? loc_error->domain : 0,
+						     loc_error ? loc_error->code : 0, notice_msg);
+				g_error_free (loc_error);
 				g_free (notice_msg);
 			}
 			
@@ -426,7 +416,7 @@ add_if_writable (GdkPixbufFormat *data, PictFormat *format)
 
 		str= g_strdup_printf ("%s (%s)", gdk_pixbuf_format_get_name (data),
 				      gdk_pixbuf_format_get_description (data));
-		gtk_combo_box_append_text (format->combo, str);
+		gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (format->combo), str);
 		g_free (str);
 		format->formats = g_slist_append (format->formats, g_strdup (gdk_pixbuf_format_get_name (data)));
 	}
@@ -447,7 +437,7 @@ file_save_cb (GtkWidget *button, PictMenuData *menudata)
 
 	label = gtk_label_new (_("Format image as:"));
 	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
-	combo = gtk_combo_box_new_text ();
+	combo = gtk_combo_box_text_new ();
 	gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0);
 	gtk_widget_show_all (hbox);
 
@@ -457,7 +447,7 @@ file_save_cb (GtkWidget *button, PictMenuData *menudata)
 	g_slist_foreach (formats, (GFunc) add_if_writable, &pictformat);
 	g_slist_free (formats);
 
-	gtk_combo_box_prepend_text (GTK_COMBO_BOX (combo), _("Current format"));
+	gtk_combo_box_text_prepend_text (GTK_COMBO_BOX_TEXT (combo), _("Current format"));
 	gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
 
 	dlg = gtk_file_chooser_dialog_new (_("Select a file to save the image to"), 
@@ -693,12 +683,7 @@ common_pict_get_value (PictBinData *bindata, PictOptions *options, GType gtype)
 						 bindata->data_length);
 				break;
 			case ENCODING_BASE64: 
-#if (GLIB_MINOR_VERSION >= 12)
 				str = g_base64_encode (bindata->data, bindata->data_length);
-#else
-				g_warning ("Base64 enoding/decoding is not supported in the GLib version %d.%d.%d",
-					   glib_major_version, glib_minor_version, glib_micro_version);
-#endif
 				break;
 			}
 			
diff --git a/libgda-ui/data-entries/plugins/gdaui-data-cell-renderer-password.c b/libgda-ui/data-entries/plugins/gdaui-data-cell-renderer-password.c
index 18d3e72..092438c 100644
--- a/libgda-ui/data-entries/plugins/gdaui-data-cell-renderer-password.c
+++ b/libgda-ui/data-entries/plugins/gdaui-data-cell-renderer-password.c
@@ -43,25 +43,24 @@ static void gdaui_data_cell_renderer_password_set_property  (GObject *object,
 							     GParamSpec *pspec);
 static void gdaui_data_cell_renderer_password_get_size   (GtkCellRenderer          *cell,
 							  GtkWidget                *widget,
-							  GdkRectangle             *cell_area,
+							  const GdkRectangle       *cell_area,
 							  gint                     *x_offset,
 							  gint                     *y_offset,
 							  gint                     *width,
 							  gint                     *height);
 static void gdaui_data_cell_renderer_password_render     (GtkCellRenderer          *cell,
-							  GdkWindow                *window,
+							  cairo_t                  *cr,
 							  GtkWidget                *widget,
-							  GdkRectangle             *background_area,
-							  GdkRectangle             *cell_area,
-							  GdkRectangle             *expose_area,
+							  const GdkRectangle       *background_area,
+							  const GdkRectangle       *cell_area,
 							  GtkCellRendererState      flags);
 
 static GtkCellEditable *gdaui_data_cell_renderer_password_start_editing (GtkCellRenderer      *cell,
 									 GdkEvent             *event,
 									 GtkWidget            *widget,
 									 const gchar          *path,
-									 GdkRectangle         *background_area,
-									 GdkRectangle         *cell_area,
+									 const GdkRectangle   *background_area,
+									 const GdkRectangle   *cell_area,
 									 GtkCellRendererState  flags);
 
 enum {
@@ -363,7 +362,7 @@ gdaui_data_cell_renderer_password_new (GdaDataHandler *dh, GType type, const gch
 static void
 gdaui_data_cell_renderer_password_get_size (GtkCellRenderer *cell,
 					    GtkWidget       *widget,
-					    GdkRectangle    *cell_area,
+					    const GdkRectangle *cell_area,
 					    gint            *x_offset,
 					    gint            *y_offset,
 					    gint            *width,
@@ -375,17 +374,16 @@ gdaui_data_cell_renderer_password_get_size (GtkCellRenderer *cell,
 
 static void
 gdaui_data_cell_renderer_password_render (GtkCellRenderer      *cell,
-					  GdkWindow            *window,
+					  cairo_t              *cr,
 					  GtkWidget            *widget,
-					  GdkRectangle         *background_area,
-					  GdkRectangle         *cell_area,
-					  GdkRectangle         *expose_area,
+					  const GdkRectangle   *background_area,
+					  const GdkRectangle   *cell_area,
 					  GtkCellRendererState  flags)
 
 {
 	GdauiDataCellRendererPassword *datacell = GDAUI_DATA_CELL_RENDERER_PASSWORD (cell);
 	GtkCellRendererClass *text_class = g_type_class_peek (GTK_TYPE_CELL_RENDERER_TEXT);
-	(text_class->render) (cell, window, widget, background_area, cell_area, expose_area, flags);
+	(text_class->render) (cell, cr, widget, background_area, cell_area, flags);
 
 	if (datacell->priv->to_be_deleted) {
 		GtkStyle *style;
@@ -395,8 +393,7 @@ gdaui_data_cell_renderer_password_render (GtkCellRenderer      *cell,
 		g_object_get ((GObject*) cell, "xpad", &xpad, NULL);
 
 		gtk_paint_hline (style,
-				 window, GTK_STATE_SELECTED,
-				 cell_area,
+				 cr, GTK_STATE_SELECTED,
 				 widget,
 				 "hline",
 				 cell_area->x + xpad, cell_area->x + cell_area->width - xpad,
@@ -404,7 +401,7 @@ gdaui_data_cell_renderer_password_render (GtkCellRenderer      *cell,
 		g_object_unref (style);
 	}
 	if (datacell->priv->invalid)
-		gdaui_data_cell_renderer_draw_invalid_area (window, cell_area);
+		gdaui_data_cell_renderer_draw_invalid_area (cr, cell_area);
 }
 
 static void
@@ -454,8 +451,8 @@ gdaui_data_cell_renderer_password_start_editing (GtkCellRenderer      *cell,
 						 G_GNUC_UNUSED GdkEvent             *event,
 						 G_GNUC_UNUSED GtkWidget            *widget,
 						 const gchar          *path,
-						 G_GNUC_UNUSED GdkRectangle         *background_area,
-						 G_GNUC_UNUSED GdkRectangle         *cell_area,
+						 G_GNUC_UNUSED const GdkRectangle   *background_area,
+						 G_GNUC_UNUSED const GdkRectangle   *cell_area,
 						 G_GNUC_UNUSED GtkCellRendererState  flags)
 {
 	GdauiDataCellRendererPassword *datacell;
diff --git a/libgda-ui/data-entries/plugins/gdaui-data-cell-renderer-pict.c b/libgda-ui/data-entries/plugins/gdaui-data-cell-renderer-pict.c
index 1493f4b..a524bdb 100644
--- a/libgda-ui/data-entries/plugins/gdaui-data-cell-renderer-pict.c
+++ b/libgda-ui/data-entries/plugins/gdaui-data-cell-renderer-pict.c
@@ -41,15 +41,14 @@ static void gdaui_data_cell_renderer_pict_dispose       (GObject *object);
 static void gdaui_data_cell_renderer_pict_init       (GdauiDataCellRendererPict      *celltext);
 static void gdaui_data_cell_renderer_pict_class_init (GdauiDataCellRendererPictClass *class);
 static void gdaui_data_cell_renderer_pict_render     (GtkCellRenderer            *cell,
-						      GdkWindow                  *window,
+						      cairo_t                    *cr,
 						      GtkWidget                  *widget,
-						      GdkRectangle               *background_area,
-						      GdkRectangle               *cell_area,
-						      GdkRectangle               *expose_area,
+						      const GdkRectangle         *background_area,
+						      const GdkRectangle         *cell_area,
 						      GtkCellRendererState        flags);
 static void gdaui_data_cell_renderer_pict_get_size   (GtkCellRenderer            *cell,
 						      GtkWidget                  *widget,
-						      GdkRectangle               *cell_area,
+						      const GdkRectangle        *cell_area,
 						      gint                       *x_offset,
 						      gint                       *y_offset,
 						      gint                       *width,
@@ -58,8 +57,8 @@ static gboolean gdaui_data_cell_renderer_pict_activate  (GtkCellRenderer
 							 GdkEvent                   *event,
 							 GtkWidget                  *widget,
 							 const gchar                *path,
-							 GdkRectangle               *background_area,
-							 GdkRectangle               *cell_area,
+							 const GdkRectangle         *background_area,
+							 const GdkRectangle         *cell_area,
 							 GtkCellRendererState        flags);
 
 /* get a pointer to the parents to be able to call their destructor */
@@ -379,7 +378,7 @@ gdaui_data_cell_renderer_pict_new (GdaDataHandler *dh, GType type, const gchar *
 static void
 gdaui_data_cell_renderer_pict_get_size (GtkCellRenderer *cell,
 					GtkWidget       *widget,
-					GdkRectangle    *cell_area,
+					const GdkRectangle *cell_area,
 					gint            *x_offset,
 					gint            *y_offset,
 					gint            *width,
@@ -394,17 +393,16 @@ gdaui_data_cell_renderer_pict_get_size (GtkCellRenderer *cell,
 
 static void
 gdaui_data_cell_renderer_pict_render (GtkCellRenderer      *cell,
-				      GdkWindow            *window,
+				      cairo_t              *cr,
 				      GtkWidget            *widget,
-				      GdkRectangle         *background_area,
-				      GdkRectangle         *cell_area,
-				      GdkRectangle         *expose_area,
+				      const GdkRectangle   *background_area,
+				      const GdkRectangle   *cell_area,
 				      GtkCellRendererState  flags)
 {
 	GdauiDataCellRendererPict *datacell = GDAUI_DATA_CELL_RENDERER_PICT (cell);
 	GtkCellRendererClass *pixbuf_class = g_type_class_peek (GTK_TYPE_CELL_RENDERER_PIXBUF);
 
-	(pixbuf_class->render) (cell, window, widget, background_area, cell_area, expose_area, flags);
+	(pixbuf_class->render) (cell, cr, widget, background_area, cell_area, flags);
 
 	if (datacell->priv->to_be_deleted) {
 		GtkStyle *style;
@@ -414,8 +412,7 @@ gdaui_data_cell_renderer_pict_render (GtkCellRenderer      *cell,
 		g_object_get ((GObject*) cell, "xpad", &xpad, NULL);
 
 		gtk_paint_hline (style,
-				 window, GTK_STATE_SELECTED,
-				 cell_area,
+				 cr, GTK_STATE_SELECTED,
 				 widget,
 				 "hline",
 				 cell_area->x + xpad, cell_area->x + cell_area->width - xpad,
@@ -423,7 +420,7 @@ gdaui_data_cell_renderer_pict_render (GtkCellRenderer      *cell,
 		g_object_unref (style);
 	}
 	if (datacell->priv->invalid)
-		gdaui_data_cell_renderer_draw_invalid_area (window, cell_area);
+		gdaui_data_cell_renderer_draw_invalid_area (cr, cell_area);
 }
 
 static void
@@ -443,8 +440,8 @@ gdaui_data_cell_renderer_pict_activate  (GtkCellRenderer            *cell,
 					 G_GNUC_UNUSED GdkEvent                   *event,
 					 GtkWidget                  *widget,
 					 const gchar                *path,
-					 G_GNUC_UNUSED GdkRectangle               *background_area,
-					 G_GNUC_UNUSED GdkRectangle               *cell_area,
+					 G_GNUC_UNUSED const GdkRectangle *background_area,
+					 G_GNUC_UNUSED const GdkRectangle *cell_area,
 					 G_GNUC_UNUSED GtkCellRendererState        flags)
 {
 	GdauiDataCellRendererPict *pictcell;
diff --git a/libgda-ui/data-entries/plugins/gdaui-entry-pict.c b/libgda-ui/data-entries/plugins/gdaui-entry-pict.c
index 396dbde..0fa2d09 100644
--- a/libgda-ui/data-entries/plugins/gdaui-entry-pict.c
+++ b/libgda-ui/data-entries/plugins/gdaui-entry-pict.c
@@ -1,6 +1,6 @@
 /* gdaui-entry-pict.c
  *
- * Copyright (C) 2006 - 2009 Vivien Malerba
+ * Copyright (C) 2006 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -379,16 +379,10 @@ display_image (GdauiEntryPict *mgpict, const GValue *value, const gchar *error_s
 	PictAllocation alloc;
 	GError *error = NULL;
 
-#if GTK_CHECK_VERSION(2,18,0)
 	GtkAllocation walloc;
 	gtk_widget_get_allocation (mgpict->priv->sw, &walloc);
 	alloc.width = walloc.width;
 	alloc.height = walloc.height;
-#else
-	alloc.width = mgpict->priv->sw->allocation.width;
-	alloc.height = mgpict->priv->sw->allocation.height;
-#endif
-
 	alloc.width = MAX (alloc.width, 10);
 	alloc.height = MAX (alloc.height, 10);
 
@@ -515,12 +509,8 @@ value_is_equal_to (GdauiEntryWrapper *mgwrap, const GValue *value)
 						    mgpict->priv->bindata.data_length);
 				break;
 			case ENCODING_BASE64: 
-#if (GLIB_MINOR_VERSION >= 12)
-				curstr = g_base64_encode (mgpict->priv->bindata.data, mgpict->priv->bindata.data_length);
-#else
-				g_warning ("Base64 enoding/decoding is not supported in the GLib version %d.%d.%d",
-					   glib_major_version, glib_minor_version, glib_micro_version);
-#endif
+				curstr = g_base64_encode (mgpict->priv->bindata.data,
+							  mgpict->priv->bindata.data_length);
 				break;
 			default:
 				g_assert_not_reached ();
diff --git a/libgda-ui/data-entries/widget-embedder.c b/libgda-ui/data-entries/widget-embedder.c
index 9c08831..595db96 100644
--- a/libgda-ui/data-entries/widget-embedder.c
+++ b/libgda-ui/data-entries/widget-embedder.c
@@ -18,18 +18,20 @@
  * USA
  */
 #include "widget-embedder.h"
-#if GTK_CHECK_VERSION (2,20,0)
 static void     widget_embedder_realize       (GtkWidget       *widget);
 static void     widget_embedder_unrealize     (GtkWidget       *widget);
-static void     widget_embedder_size_request  (GtkWidget       *widget,
-                                               GtkRequisition  *requisition);
+static void     widget_embedder_get_preferred_width  (GtkWidget *widget,
+						      gint      *minimum,
+						      gint      *natural);
+static void     widget_embedder_get_preferred_height (GtkWidget *widget,
+						      gint      *minimum,
+						      gint      *natural);
 static void     widget_embedder_size_allocate (GtkWidget       *widget,
                                                GtkAllocation   *allocation);
 static gboolean widget_embedder_damage        (GtkWidget       *widget,
                                                GdkEventExpose  *event);
-static gboolean widget_embedder_expose        (GtkWidget       *widget,
-                                               GdkEventExpose  *offscreen);
-
+static gboolean widget_embedder_draw          (GtkWidget       *widget,
+					       cairo_t         *cr);
 static void     widget_embedder_add           (GtkContainer    *container,
                                                GtkWidget       *child);
 static void     widget_embedder_remove        (GtkContainer    *container,
@@ -72,9 +74,10 @@ widget_embedder_class_init (WidgetEmbedderClass *klass)
 
 	widget_class->realize = widget_embedder_realize;
 	widget_class->unrealize = widget_embedder_unrealize;
-	widget_class->size_request = widget_embedder_size_request;
+	widget_class->get_preferred_width = widget_embedder_get_preferred_width;
+	widget_class->get_preferred_height = widget_embedder_get_preferred_height;
 	widget_class->size_allocate = widget_embedder_size_allocate;
-	widget_class->expose_event = widget_embedder_expose;
+	widget_class->draw = widget_embedder_draw;
 
 	g_signal_override_class_closure (g_signal_lookup ("damage-event", GTK_TYPE_WIDGET),
 					 WIDGET_EMBEDDER_TYPE,
@@ -173,10 +176,9 @@ widget_embedder_realize (GtkWidget *widget)
 		| GDK_LEAVE_NOTIFY_MASK;
 
 	attributes.visual = gtk_widget_get_visual (widget);
-	attributes.colormap = gtk_widget_get_colormap (widget);
 	attributes.wclass = GDK_INPUT_OUTPUT;
 
-	attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+	attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
 
 	GdkWindow *win;
 	win = gdk_window_new (gtk_widget_get_parent_window (widget),
@@ -298,7 +300,7 @@ widget_embedder_size_request (GtkWidget      *widget,
 	child_requisition.height = 0;
 
 	if (bin->child && gtk_widget_get_visible (bin->child))
-		gtk_widget_size_request (bin->child, &child_requisition);
+		gtk_widget_get_preferred_size (bin->child, &child_requisition, NULL);
 
 	guint border_width;
 	border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
@@ -307,6 +309,26 @@ widget_embedder_size_request (GtkWidget      *widget,
 }
 
 static void
+widget_embedder_get_preferred_width (GtkWidget *widget,
+				     gint      *minimum,
+				     gint      *natural)
+{
+	GtkRequisition requisition;
+	widget_embedder_size_request (widget, &requisition);
+	*minimum = *natural = requisition.width;
+}
+
+static void
+widget_embedder_get_preferred_height (GtkWidget *widget,
+				      gint      *minimum,
+				      gint      *natural)
+{
+	GtkRequisition requisition;
+	widget_embedder_size_request (widget, &requisition);
+	*minimum = *natural = requisition.height;
+}
+
+static void
 widget_embedder_size_allocate (GtkWidget     *widget,
                                GtkAllocation *allocation)
 {
@@ -362,57 +384,43 @@ widget_embedder_damage (GtkWidget      *widget,
 }
 
 static gboolean
-widget_embedder_expose (GtkWidget      *widget,
-                        GdkEventExpose *event)
+widget_embedder_draw (GtkWidget *widget, cairo_t *cr)
 {
 	WidgetEmbedder *bin = WIDGET_EMBEDDER (widget);
-	gint width, height;
+	GdkWindow *window;
 
-	if (gtk_widget_is_drawable (widget)) {
-		GdkWindow *win;
-		win = gtk_widget_get_window (widget);
-		if (event->window == win) {
-			GdkPixmap *pixmap;
-			cairo_t *cr;
-
-			if (bin->child && gtk_widget_get_visible (bin->child)) {
-				GtkAllocation child_area;
-				pixmap = gdk_offscreen_window_get_pixmap (bin->offscreen_window);
-
-				gtk_widget_get_allocation (bin->child, &child_area);
-				cr = gdk_cairo_create (win);
-				
-				/* clip */
-				gdk_drawable_get_size (pixmap, &width, &height);
-				cairo_rectangle (cr, 0, 0, width, height);
-				cairo_clip (cr);
-
-				/* paint */
-				gdk_cairo_set_source_pixmap (cr, pixmap, 0, 0);
-				cairo_paint (cr);
-
-				if (! bin->valid) {
-					cairo_set_source_rgba (cr, .8, .1, .1, .2);
-					cairo_rectangle (cr, child_area.x, child_area.y,
-							 child_area.width, child_area.height);
-					cairo_fill (cr);
-				}
-				cairo_destroy (cr);
+	window = gtk_widget_get_window (widget);
+	if (gtk_cairo_should_draw_window (cr, window)) {
+		cairo_surface_t *surface;
+		GtkAllocation child_area;
+		
+		if (bin->child && gtk_widget_get_visible (bin->child)) {
+			surface = gdk_offscreen_window_get_surface (bin->offscreen_window);
+			gtk_widget_get_allocation (bin->child, &child_area);
+			cairo_set_source_surface (cr, surface, 0, 0);
+			cairo_paint (cr);
+
+			if (! bin->valid) {
+				cairo_set_source_rgba (cr, .8, .1, .1, .2);
+				cairo_rectangle (cr, child_area.x, child_area.y,
+						 child_area.width, child_area.height);
+				cairo_fill (cr);
 			}
 		}
-		else if (event->window == bin->offscreen_window) {
-			gtk_paint_flat_box (gtk_widget_get_style (widget), event->window,
-					    GTK_STATE_NORMAL, GTK_SHADOW_NONE,
-					    &event->area, widget, "blah",
-					    0, 0, -1, -1);
-			
-			if (bin->child)
-				gtk_container_propagate_expose (GTK_CONTAINER (widget),
-								bin->child,
-								event);
-		}
 	}
-
+	if (gtk_cairo_should_draw_window (cr, bin->offscreen_window)) {
+		gtk_paint_flat_box (gtk_widget_get_style (widget), cr,
+				    GTK_STATE_NORMAL, GTK_SHADOW_NONE,
+				    widget, "blah",
+				    0, 0,
+				    gdk_window_get_width (bin->offscreen_window),
+				    gdk_window_get_height (bin->offscreen_window));
+
+		if (bin->child)
+			gtk_container_propagate_draw (GTK_CONTAINER (widget),
+						      bin->child,
+						      cr);
+	}
 	return FALSE;
 }
 
@@ -429,5 +437,3 @@ widget_embedder_set_valid (WidgetEmbedder *bin, gboolean valid)
 	bin->valid = valid;
 	gtk_widget_queue_draw (GTK_WIDGET (bin));
 }
-
-#endif
diff --git a/libgda-ui/data-entries/widget-embedder.h b/libgda-ui/data-entries/widget-embedder.h
index 36af425..25de788 100644
--- a/libgda-ui/data-entries/widget-embedder.h
+++ b/libgda-ui/data-entries/widget-embedder.h
@@ -19,7 +19,6 @@
  */
 #include <gtk/gtk.h>
 
-#if GTK_CHECK_VERSION(2,20,0)
 #define WIDGET_EMBEDDER_TYPE              (widget_embedder_get_type ())
 #define WIDGET_EMBEDDER(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), WIDGET_EMBEDDER_TYPE, WidgetEmbedder))
 #define WIDGET_EMBEDDER_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), WIDGET_EMBEDDER_TYPE, WidgetEmbedderClass))
@@ -48,4 +47,3 @@ GType      widget_embedder_get_type  (void) G_GNUC_CONST;
 GtkWidget* widget_embedder_new       (void);
 void       widget_embedder_set_valid (WidgetEmbedder *bin, gboolean valid);
 
-#endif
diff --git a/libgda-ui/demos/.gitignore b/libgda-ui/demos/.gitignore
index 9a9e900..44cc7a7 100644
--- a/libgda-ui/demos/.gitignore
+++ b/libgda-ui/demos/.gitignore
@@ -1,3 +1,3 @@
 geninclude.pl
 demos.h
-gdaui-demo-4.*
+gdaui-demo-5.*
diff --git a/libgda-ui/demos/Makefile.am b/libgda-ui/demos/Makefile.am
index 9019b43..00f409c 100644
--- a/libgda-ui/demos/Makefile.am
+++ b/libgda-ui/demos/Makefile.am
@@ -45,24 +45,24 @@ AM_CPPFLAGS = \
         -DDATADIR=\""$(datadir)"\" \
         -DLIBDIR=\""$(libdir)"\"
 
-bin_PROGRAMS = gdaui-demo-4.0
+bin_PROGRAMS = gdaui-demo-5.0
 
 BUILT_SOURCES = demos.h
 
 demos.h: $(demos) geninclude.pl
 	(here=`pwd` ; cd $(srcdir) && $(PERL) $$here/geninclude.pl $(demos)) > demos.h
 
-gdaui_demo_4_0_SOURCES = 		\
+gdaui_demo_5_0_SOURCES = 		\
 	$(demos)		\
 	demo-common.h		\
 	main.c			\
 	demos.h
 
-gdaui_demo_4_0_DEPENDENCIES = $(DEPS)
-gdaui_demo_4_0_LDFLAGS =  $(EXTRALDFLAGS)
-gdaui_demo_4_0_LDADD =  \
-	$(top_builddir)/libgda/libgda-4.0.la \
-	$(top_builddir)/libgda-ui/libgda-ui-4.0.la \
+gdaui_demo_5_0_DEPENDENCIES = $(DEPS)
+gdaui_demo_5_0_LDFLAGS =  $(EXTRALDFLAGS)
+gdaui_demo_5_0_LDADD =  \
+	$(top_builddir)/libgda/libgda-5.0.la \
+	$(top_builddir)/libgda-ui/libgda-ui-5.0.la \
 	$(LIBGDA_LIBS) $(GTK_LIBS)
 
 democode_DATA = $(demos) $(demofiles)
diff --git a/libgda-ui/demos/basic_form.c b/libgda-ui/demos/basic_form.c
index eae99cd..92e76b5 100644
--- a/libgda-ui/demos/basic_form.c
+++ b/libgda-ui/demos/basic_form.c
@@ -30,12 +30,8 @@ do_basic_form (GtkWidget *do_widget)
 				  G_CALLBACK (gtk_widget_destroyed), &window);
 		
 		vbox = gtk_vbox_new (FALSE, 5);
-#if GTK_CHECK_VERSION(2,18,0)
 		gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (window))),
 				    vbox, TRUE, TRUE, 0);
-#else
-		gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), vbox, TRUE, TRUE, 0);
-#endif
 		gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
 		
 		label = gtk_label_new ("This example shows 2 GdauiBasicForm widgets operating on the\n"
diff --git a/libgda-ui/demos/cloud.c b/libgda-ui/demos/cloud.c
index 1101780..8dbd4aa 100644
--- a/libgda-ui/demos/cloud.c
+++ b/libgda-ui/demos/cloud.c
@@ -86,12 +86,8 @@ do_cloud (GtkWidget *do_widget)
 				  G_CALLBACK (gtk_widget_destroyed), &window);
 		
 		vbox = gtk_vbox_new (FALSE, 5);
-#if GTK_CHECK_VERSION(2,18,0)
 		gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (window))),
 				    vbox, TRUE, TRUE, 0);
-#else
-		gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), vbox, TRUE, TRUE, 0);
-#endif
 		gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
 		
 		label = gtk_label_new ("The following GdauiCloud widget displays customers,\n"
diff --git a/libgda-ui/demos/combo.c b/libgda-ui/demos/combo.c
index efa0ac8..cbf1c8c 100644
--- a/libgda-ui/demos/combo.c
+++ b/libgda-ui/demos/combo.c
@@ -99,12 +99,8 @@ do_combo (GtkWidget *do_widget)
 				  G_CALLBACK (gtk_widget_destroyed), &window);
 		
 		vbox = gtk_vbox_new (FALSE, 5);
-#if GTK_CHECK_VERSION(2,18,0)
 		gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (window))),
 				    vbox, TRUE, TRUE, 0);
-#else
-		gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), vbox, TRUE, TRUE, 0);
-#endif
 		gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
 		
 		label = gtk_label_new ("The following GdauiCombo widget displays customers");
diff --git a/libgda-ui/demos/data_model_dir.c b/libgda-ui/demos/data_model_dir.c
index 8aba369..2b0c150 100644
--- a/libgda-ui/demos/data_model_dir.c
+++ b/libgda-ui/demos/data_model_dir.c
@@ -61,12 +61,8 @@ do_data_model_dir (GtkWidget *do_widget)
 				  G_CALLBACK (gtk_widget_destroyed), &window);
 		
 		vbox = gtk_vbox_new (FALSE, 5);
-#if GTK_CHECK_VERSION(2,18,0)
 		gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (window))),
 				    vbox, TRUE, TRUE, 0);
-#else
-		gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), vbox, TRUE, TRUE, 0);
-#endif
 		gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
 		
 		label = gtk_label_new ("The following GdauiForm widget displays data from a GdaDataModelDir "
diff --git a/libgda-ui/demos/ddl_queries.c b/libgda-ui/demos/ddl_queries.c
index 5834aaf..ee48419 100644
--- a/libgda-ui/demos/ddl_queries.c
+++ b/libgda-ui/demos/ddl_queries.c
@@ -74,12 +74,8 @@ do_ddl_queries (GtkWidget *do_widget)
 				  G_CALLBACK (gtk_widget_destroyed), &window);
 		
 		table = gtk_table_new (3, 2, FALSE);
-#if GTK_CHECK_VERSION(2,18,0)
 		gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (window))),
 				    table, TRUE, TRUE, 0);
-#else
-		gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), table, TRUE, TRUE, 0);
-#endif
 		gtk_container_set_border_width (GTK_CONTAINER (table), 5);
 		
 		label = gtk_label_new ("<b>Tested provider and operation:</b>");
@@ -417,12 +413,8 @@ show_named_parameters (G_GNUC_UNUSED GtkButton *button, DemoData *data)
 	label = gtk_label_new ("<b>Named parameters:</b>\n");
 	gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
 	gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
-#if GTK_CHECK_VERSION(2,18,0)
-		gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
-				    label, FALSE, FALSE, 0);
-#else
-		gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), label, FALSE, FALSE, 0);
-#endif
+	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
+			    label, FALSE, FALSE, 0);
 	gtk_widget_show (label);
 	
 	/* text area */
@@ -448,12 +440,8 @@ show_named_parameters (G_GNUC_UNUSED GtkButton *button, DemoData *data)
 	gtk_container_add (GTK_CONTAINER (sw), view);
 	gtk_widget_show_all (sw);
 
-#if GTK_CHECK_VERSION(2,18,0)
-		gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
-				    sw, TRUE, TRUE, 0);
-#else
-		gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), sw, TRUE, TRUE, 0);
-#endif
+	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
+			    sw, TRUE, TRUE, 0);
 	gtk_widget_set_size_request (dlg, 530, 350);
 
 	gtk_dialog_run (GTK_DIALOG (dlg));
diff --git a/libgda-ui/demos/form.c b/libgda-ui/demos/form.c
index 6d63e7f..15532dd 100644
--- a/libgda-ui/demos/form.c
+++ b/libgda-ui/demos/form.c
@@ -33,12 +33,8 @@ do_form (GtkWidget *do_widget)
 				  G_CALLBACK (gtk_widget_destroyed), &window);
 		
 		vbox = gtk_vbox_new (FALSE, 5);
-#if GTK_CHECK_VERSION(2,18,0)
 		gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (window))),
 				    vbox, TRUE, TRUE, 0);
-#else
-		gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), vbox, TRUE, TRUE, 0);
-#endif
 		gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
 		
 		label = gtk_label_new ("The following GdauiForm widget displays data from the 'products' table.\n\n"
diff --git a/libgda-ui/demos/form_data_layout.c b/libgda-ui/demos/form_data_layout.c
index 032fe0b..d4995a2 100644
--- a/libgda-ui/demos/form_data_layout.c
+++ b/libgda-ui/demos/form_data_layout.c
@@ -35,12 +35,8 @@ do_form_data_layout (GtkWidget *do_widget)
 				  G_CALLBACK (gtk_widget_destroyed), &window);
 		
 		vbox = gtk_vbox_new (FALSE, 5);
-#if GTK_CHECK_VERSION(2,18,0)
 		gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (window))),
 				    vbox, TRUE, TRUE, 0);
-#else
-		gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), vbox, TRUE, TRUE, 0);
-#endif
 		gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
 		
 		label = gtk_label_new ("The following GdauiForm widget displays information about customers,\n"
diff --git a/libgda-ui/demos/form_pict.c b/libgda-ui/demos/form_pict.c
index e4cc1f2..64462a2 100644
--- a/libgda-ui/demos/form_pict.c
+++ b/libgda-ui/demos/form_pict.c
@@ -37,12 +37,8 @@ do_form_pict (GtkWidget *do_widget)
 				  G_CALLBACK (gtk_widget_destroyed), &window);
 		
 		vbox = gtk_vbox_new (FALSE, 5);
-#if GTK_CHECK_VERSION(2,18,0)
 		gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (window))),
 				    vbox, TRUE, TRUE, 0);
-#else
-		gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), vbox, TRUE, TRUE, 0);
-#endif
 		gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
 		
 		label = gtk_label_new ("The following GdauiForm widget displays data from the 'pictures' table.\n\n"
diff --git a/libgda-ui/demos/form_rw.c b/libgda-ui/demos/form_rw.c
index aa15f9c..b90f258 100644
--- a/libgda-ui/demos/form_rw.c
+++ b/libgda-ui/demos/form_rw.c
@@ -33,12 +33,8 @@ do_form_rw (GtkWidget *do_widget)
 				  G_CALLBACK (gtk_widget_destroyed), &window);
 		
 		vbox = gtk_vbox_new (FALSE, 5);
-#if GTK_CHECK_VERSION(2,18,0)
 		gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (window))),
 				    vbox, TRUE, TRUE, 0);
-#else
-		gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), vbox, TRUE, TRUE, 0);
-#endif
 		gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
 		
 		label = gtk_label_new ("The following GdauiForm widget displays data from the 'products' table.\n\n"
diff --git a/libgda-ui/demos/grid.c b/libgda-ui/demos/grid.c
index 69fe21f..cd9ee43 100644
--- a/libgda-ui/demos/grid.c
+++ b/libgda-ui/demos/grid.c
@@ -33,12 +33,8 @@ do_grid (GtkWidget *do_widget)
 				  G_CALLBACK (gtk_widget_destroyed), &window);
 		
 		vbox = gtk_vbox_new (FALSE, 5);
-#if GTK_CHECK_VERSION(2,18,0)
 		gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (window))),
 				    vbox, TRUE, TRUE, 0);
-#else
-		gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), vbox, TRUE, TRUE, 0);
-#endif
 		gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
 		
 		label = gtk_label_new ("The following GdauiGrid widget displays data from the 'products' table.\n\n"
diff --git a/libgda-ui/demos/grid_data_layout.c b/libgda-ui/demos/grid_data_layout.c
index 2c55387..f775653 100644
--- a/libgda-ui/demos/grid_data_layout.c
+++ b/libgda-ui/demos/grid_data_layout.c
@@ -36,12 +36,8 @@ do_grid_data_layout (GtkWidget *do_widget)
 				  G_CALLBACK (gtk_widget_destroyed), &window);
 		
 		vbox = gtk_vbox_new (FALSE, 5);
-#if GTK_CHECK_VERSION(2,18,0)
 		gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (window))),
 				    vbox, TRUE, TRUE, 0);
-#else
-		gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), vbox, TRUE, TRUE, 0);
-#endif
 		gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
 		
 		label = gtk_label_new ("The following GdauiGrid widget displays information about customers,\n"
diff --git a/libgda-ui/demos/grid_pict.c b/libgda-ui/demos/grid_pict.c
index 3eb305b..1e30c5c 100644
--- a/libgda-ui/demos/grid_pict.c
+++ b/libgda-ui/demos/grid_pict.c
@@ -37,12 +37,8 @@ do_grid_pict (GtkWidget *do_widget)
 				  G_CALLBACK (gtk_widget_destroyed), &window);
 		
 		vbox = gtk_vbox_new (FALSE, 5);
-#if GTK_CHECK_VERSION(2,18,0)
 		gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (window))),
 				    vbox, TRUE, TRUE, 0);
-#else
-		gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), vbox, TRUE, TRUE, 0);
-#endif
 		gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
 		
 		label = gtk_label_new ("The following GdauiGrid widget displays data from the 'pictures' table.\n\n"
diff --git a/libgda-ui/demos/grid_rw.c b/libgda-ui/demos/grid_rw.c
index 459d417..309526e 100644
--- a/libgda-ui/demos/grid_rw.c
+++ b/libgda-ui/demos/grid_rw.c
@@ -33,12 +33,8 @@ do_grid_rw (GtkWidget *do_widget)
 				  G_CALLBACK (gtk_widget_destroyed), &window);
 		
 		vbox = gtk_vbox_new (FALSE, 5);
-#if GTK_CHECK_VERSION(2,18,0)
 		gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (window))),
 				    vbox, TRUE, TRUE, 0);
-#else
-		gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), vbox, TRUE, TRUE, 0);
-#endif
 		gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
 		
 		label = gtk_label_new ("The following GdauiGrid widget displays data from the 'products' table.\n\n"
diff --git a/libgda-ui/demos/linked_grid_form.c b/libgda-ui/demos/linked_grid_form.c
index 4cae576..fc23096 100644
--- a/libgda-ui/demos/linked_grid_form.c
+++ b/libgda-ui/demos/linked_grid_form.c
@@ -90,12 +90,8 @@ do_linked_grid_form (GtkWidget *do_widget)
 		g_object_set_data_full (G_OBJECT (window), "demodata", data, g_free);
 		
 		vbox = gtk_vbox_new (FALSE, 5);
-#if GTK_CHECK_VERSION(2,18,0)
 		gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (window))),
 				    vbox, TRUE, TRUE, 0);
-#else
-		gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), vbox, TRUE, TRUE, 0);
-#endif
 		gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
 		
 		label = gtk_label_new ("The following GdauiForm and GdauiGrid widgets\n"
diff --git a/libgda-ui/demos/linked_model_param.c b/libgda-ui/demos/linked_model_param.c
index 8011968..618a72b 100644
--- a/libgda-ui/demos/linked_model_param.c
+++ b/libgda-ui/demos/linked_model_param.c
@@ -45,12 +45,8 @@ do_linked_model_param (GtkWidget *do_widget)
 				  G_CALLBACK (gtk_widget_destroyed), &window);
 		
 		vbox = gtk_vbox_new (FALSE, 5);
-#if GTK_CHECK_VERSION(2,18,0)
 		gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (window))),
 				    vbox, TRUE, TRUE, 0);
-#else
-		gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), vbox, TRUE, TRUE, 0);
-#endif
 		gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
 		
 		label = gtk_label_new ("");
diff --git a/libgda-ui/demos/login.c b/libgda-ui/demos/login.c
index a6577df..5499274 100644
--- a/libgda-ui/demos/login.c
+++ b/libgda-ui/demos/login.c
@@ -78,12 +78,8 @@ do_login (GtkWidget *do_widget)
 		
 
 		table = gtk_table_new (3, 2, FALSE);
-#if GTK_CHECK_VERSION(2,18,0)
 		gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (window))),
 				    table, TRUE, TRUE, 0);
-#else
-		gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), table, TRUE, TRUE, 0);
-#endif
 		gtk_container_set_border_width (GTK_CONTAINER (table), 5);
 
 		/* Create the login widget */
diff --git a/libgda-ui/demos/provider_sel.c b/libgda-ui/demos/provider_sel.c
index 0b80d93..b3f3a69 100644
--- a/libgda-ui/demos/provider_sel.c
+++ b/libgda-ui/demos/provider_sel.c
@@ -32,12 +32,7 @@ do_provider_sel (GtkWidget *do_widget)
 		g_signal_connect (window, "destroy",
 				  G_CALLBACK (gtk_widget_destroyed), &window);
 		
-
-#if GTK_CHECK_VERSION(2,18,0)
 		vbox = gtk_dialog_get_content_area (GTK_DIALOG (window));
-#else
-		vbox = GTK_DIALOG (window)->vbox;
-#endif
 
 		/* Create the widget */
 		label = gtk_label_new ("Provider selector:");
diff --git a/libgda-ui/demos/tree.c b/libgda-ui/demos/tree.c
index 9d7e672..715885d 100644
--- a/libgda-ui/demos/tree.c
+++ b/libgda-ui/demos/tree.c
@@ -126,12 +126,8 @@ do_tree (GtkWidget *do_widget)
 				       "feeds it to a GdauiTreeStore (which implements the GtkTreeModel\n"
 				       "interface, and creates a GtkTreeView to display the contents\n"
 				       "of the GdaTree");
-#if GTK_CHECK_VERSION(2,18,0)
 		gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (window))),
 				    label, TRUE, TRUE, 0);
-#else
-		gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), label, TRUE, TRUE, 0);
-#endif
 
 		/* create GdaTree */
 		tree = gda_tree_new ();
@@ -152,12 +148,8 @@ do_tree (GtkWidget *do_widget)
 					      G_TYPE_BOOLEAN, "scale-set");
 		treeview = gtk_tree_view_new_with_model (model);
 		g_object_unref (model);
-#if GTK_CHECK_VERSION(2,18,0)
 		gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (window))),
 				    treeview, TRUE, TRUE, 0);
-#else
-		gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), treeview, TRUE, TRUE, 0);
-#endif
 
 		/* create GtkTreeView's column */
 		enum {
diff --git a/libgda-ui/gdaui-basic-form.c b/libgda-ui/gdaui-basic-form.c
index 708eb68..2c034c2 100644
--- a/libgda-ui/gdaui-basic-form.c
+++ b/libgda-ui/gdaui-basic-form.c
@@ -2143,27 +2143,17 @@ gdaui_basic_form_new_in_dialog (GdaSet *data_set, GtkWindow *parent,
 		str = g_markup_printf_escaped ("<b>%s:</b>", header);
 		gtk_label_set_markup (GTK_LABEL (label), str);
 		g_free (str);
-#if GTK_CHECK_VERSION(2,18,0)
 		gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
 				    label, FALSE, FALSE, SPACING);
-#else
-		gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), label, FALSE, FALSE, SPACING);
-#endif
 		gtk_widget_show (label);
 	}
 
 
 	gboolean can_expand;
 	g_object_get ((GObject*) form, "can-expand-v", &can_expand, NULL);
-#if GTK_CHECK_VERSION(2,18,0)
 	gtk_container_set_border_width (GTK_CONTAINER (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg)))), 4);
 	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), form,
 			    can_expand, can_expand, 10);
-#else
-	gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dlg)->vbox), 4);
-	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), form,
-			    can_expand, can_expand, 10);
-#endif
 
 	g_signal_connect (G_OBJECT (form), "holder-changed",
 			  G_CALLBACK (form_holder_changed), dlg);
diff --git a/libgda-ui/gdaui-basic-form.h b/libgda-ui/gdaui-basic-form.h
index 3ed16dd..4f336fc 100644
--- a/libgda-ui/gdaui-basic-form.h
+++ b/libgda-ui/gdaui-basic-form.h
@@ -1,6 +1,5 @@
-/* gdaui-basic-form.h
- *
- * Copyright (C) 2002 - 2009 Vivien Malerba <malerba gnome-db org>
+/*
+ * Copyright (C) 2002 - 2011 Vivien Malerba <malerba gnome-db org>
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -57,9 +56,100 @@ struct _GdauiBasicFormClass
 	void       (*layout_changed) (GdauiBasicForm *form);
 };
 
-/* 
- * Generic widget's methods 
-*/
+/**
+ * SECTION:gdaui-basic-form
+ * @short_description: Form widget mapping the values contained in a #GdaSet
+ * @title: GdauiBasicForm
+ * @stability: Stable
+ * @Image: vi-basic-form.png
+ * @see_also:
+ *
+ * The #GdauiBasicForm widget is a form containing an entry for each #GdaHolder object
+ * contained in a #GdaSet (specified when the form is created). A typical usage is when the
+ * user is requested to enter a value which will be used in a statement (without any error checking for clarity):
+ * <programlisting>
+ * GdaStatement *stmt;
+ * GdaSet *params;
+ * stmt = gda_sql_parser_parse_string (parser, "SELECT * FROM customers where name LIKE ##name::string", NULL, NULL);
+ * gda_statement_get_parameters (stmt, &amp;params, NULL);
+ * 
+ * GtkWidget *form;
+ * gint result;
+ * form = gdaui_basic_form_new_in_dialog (params, NULL, "Customer search", "Enter Customer search expression");
+ * result = gtk_dialog_run (GTK_DIALOG (form));
+ * gtk_widget_destroy (form);
+ * if (result == GTK_RESPONSE_ACCEPT) {
+ *    // execute statement
+ *    GdaDataModel *model;
+ *    model = gda_connection_statement_execute_select (cnc, stmt, params, NULL);
+ *    [...]
+ * }
+ * g_object_unref (params);
+ * g_object_unref (stmt);
+ * </programlisting>
+ *
+ * The default layout within a #GdauiBasicForm is a vertical column: all the data entry widgets are aligned
+ * in a single column. This behaviour can be changed using the gdaui_basic_form_set_layout_from_file() method or
+ * setting the <link linkend="GdauiBasicForm--xml-layout">xml-layout</link> property.
+ * 
+ * <anchor id="GdauiBasicFormXMLLayout"/>
+ * The #GdauiBasicForm class parses textual descriptions of XML layout which
+ * which can be described by the following DTD. 
+ *
+ * <programlisting><![CDATA[
+ * <!ELEMENT gdaui_layouts (gdaui_form | gdaui_grid)>
+ * 
+ * <!ELEMENT gdaui_form (gdaui_section | gdaui_column | gdaui_notebook)*>
+ * <!ATTLIST gdaui_form
+ *          name CDATA #REQUIRED
+ * 	  container (columns|rows|hpaned|vpaned) #IMPLIED>
+ * 
+ * <!ELEMENT gdaui_section (gdaui_section | gdaui_column | gdaui_notebook)*>
+ * <!ATTLIST gdaui_section
+ *          title CDATA #IMPLIED >
+ * 
+ * <!ELEMENT gdaui_notebook (gdaui_section | gdaui_column | gdaui_notebook)*>
+ * 
+ * <!ELEMENT gdaui_column (gdaui_entry | gdaui_placeholder)*>
+ * 
+ * <!ELEMENT gdaui_entry EMPTY>
+ * <!ATTLIST gdaui_entry
+ *          name CDATA #REQUIRED
+ * 	  editable (true|false) #IMPLIED
+ * 	  label CDATA #IMPLIED
+ * 	  plugin CDATA #IMPLIED>
+ * 
+ * <!ELEMENT gdaui_placeholder EMPTY>
+ * <!ATTLIST gdaui_placeholder
+ * 	  id CDATA #REQUIRED
+ * 	  label CDATA #IMPLIED>
+ * ]]></programlisting>
+ *
+ * <example>
+ *  <title>A GdauiBasicForm layout example</title>
+ *  <programlisting><![CDATA[
+ * <?xml version="1.0" encoding="UTF-8"?>
+ * <gdaui_layouts>
+ *  <gdaui_form name="customers" container="hpaned">
+ *    <gdaui_section title="Summary">
+ *      <gdaui_column>
+ * 	<gdaui_entry name="id" editable="no"/>
+ * 	<gdaui_entry name="name"/>
+ * 	<gdaui_entry name="comments" plugin="text"/>
+ * 	<gdaui_entry name="total_orders" label="Total ordered" plugin="number:NB_DECIMALS=2;CURRENCY=â?¬"/>
+ *      </gdaui_column>
+ *    </gdaui_section>
+ *    <gdaui_section title="Photo">
+ *      <gdaui_column>
+ * 	<gdaui_entry name="photo" plugin="picture"/>
+ *      </gdaui_column>
+ *    </gdaui_section>
+ *  </gdaui_form>
+ * </gdaui_layouts>
+ * ]]></programlisting>
+ * </example>
+ */
+
 GType             gdaui_basic_form_get_type                 (void) G_GNUC_CONST;
 GtkWidget        *gdaui_basic_form_new                      (GdaSet *data_set);
 GtkWidget        *gdaui_basic_form_new_in_dialog            (GdaSet *data_set, GtkWindow *parent,
diff --git a/libgda-ui/gdaui-cloud.c b/libgda-ui/gdaui-cloud.c
index f822a54..5e1608a 100644
--- a/libgda-ui/gdaui-cloud.c
+++ b/libgda-ui/gdaui-cloud.c
@@ -728,11 +728,7 @@ visibility_notify_event (GtkWidget *text_view, G_GNUC_UNUSED GdkEventVisibility
 {
 	gint wx, wy, bx, by;
 
-#if GTK_CHECK_VERSION(2,18,0)
 	gdk_window_get_pointer (gtk_widget_get_window (text_view), &wx, &wy, NULL);
-#else
-	gdk_window_get_pointer (text_view->window, &wx, &wy, NULL);
-#endif
 	
 	gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view), 
 					       GTK_TEXT_WINDOW_WIDGET,
@@ -757,11 +753,7 @@ motion_notify_event (GtkWidget *text_view, GdkEventMotion *event, GdauiCloud *cl
 	
 	set_cursor_if_appropriate (GTK_TEXT_VIEW (text_view), x, y, cloud);
 	
-#if GTK_CHECK_VERSION(2,18,0)
 	gdk_window_get_pointer (gtk_widget_get_window (text_view), NULL, NULL, NULL);
-#else
-	gdk_window_get_pointer (text_view->window, NULL, NULL, NULL);
-#endif
 	return FALSE;
 }
 
@@ -836,18 +828,18 @@ key_press_event (GtkWidget *text_view, GdkEventKey *event, GdauiCloud *cloud)
         GtkTextBuffer *buffer;
 
         switch (event->keyval) {
-        case GDK_Return:
-        case GDK_space:
-        case GDK_KP_Enter:
+        case GDK_KEY_Return:
+        case GDK_KEY_space:
+        case GDK_KEY_KP_Enter:
                 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
                 gtk_text_buffer_get_iter_at_mark (buffer, &iter,
                                                   gtk_text_buffer_get_insert (buffer));
                 follow_if_link (text_view, &iter, cloud);
 		return TRUE;
-	case GDK_Up:
-	case GDK_Down:
-	case GDK_Left:
-	case GDK_Right:
+	case GDK_KEY_Up:
+	case GDK_KEY_Down:
+	case GDK_KEY_Left:
+	case GDK_KEY_Right:
 		if ((cloud->priv->selection_mode == GTK_SELECTION_SINGLE) ||
 		    (cloud->priv->selection_mode == GTK_SELECTION_BROWSE)) {
 			GtkTextIter iter;
@@ -856,7 +848,7 @@ key_press_event (GtkWidget *text_view, GdkEventKey *event, GdauiCloud *cloud)
 				mark = gtk_text_buffer_get_insert (cloud->priv->tbuffer);
 				gtk_text_buffer_get_iter_at_mark (cloud->priv->tbuffer, &iter, mark);
 			}
-			else if ((event->keyval == GDK_Right) || (event->keyval == GDK_Down))
+			else if ((event->keyval == GDK_KEY_Right) || (event->keyval == GDK_KEY_Down))
 				gtk_text_buffer_get_start_iter (cloud->priv->tbuffer, &iter);
 			else
 				gtk_text_buffer_get_end_iter (cloud->priv->tbuffer, &iter);
@@ -867,22 +859,22 @@ key_press_event (GtkWidget *text_view, GdkEventKey *event, GdauiCloud *cloud)
 				GtkMovementStep mvt_type;
 				gint mvt_amount;
 				switch (event->keyval) {
-				case GDK_Up:
+				case GDK_KEY_Up:
 					done = ! gtk_text_view_backward_display_line ((GtkTextView*)cloud->priv->tview, &iter);
 					mvt_type = GTK_MOVEMENT_DISPLAY_LINES;
 					mvt_amount = -1;
 					break;
-				case GDK_Down:
+				case GDK_KEY_Down:
 					done = ! gtk_text_view_forward_display_line ((GtkTextView*)cloud->priv->tview, &iter);
 					mvt_type = GTK_MOVEMENT_DISPLAY_LINES;
 					mvt_amount = 1;
 					break;
-				case GDK_Left:
+				case GDK_KEY_Left:
 					done = ! gtk_text_iter_backward_char (&iter);
 					mvt_type = GTK_MOVEMENT_VISUAL_POSITIONS;
 					mvt_amount = -1;
 					break;
-				case GDK_Right:
+				case GDK_KEY_Right:
 					done = ! gtk_text_iter_forward_char (&iter);
 					mvt_type = GTK_MOVEMENT_VISUAL_POSITIONS;
 					mvt_amount = 1;
diff --git a/libgda-ui/gdaui-cloud.h b/libgda-ui/gdaui-cloud.h
index 9797996..8cdf006 100644
--- a/libgda-ui/gdaui-cloud.h
+++ b/libgda-ui/gdaui-cloud.h
@@ -1,6 +1,5 @@
-/* gdaui-cloud.h
- *
- * Copyright (C) 2009 Vivien Malerba <malerba gnome-db org>
+/*
+ * Copyright (C) 2009 - 2011 Vivien Malerba <malerba gnome-db org>
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -50,9 +49,22 @@ struct _GdauiCloudClass
 	void            (* activate) (GdauiCloud *cloud, gint row);
 };
 
-/* 
- * Generic widget's methods 
+/**
+ * SECTION:gdaui-cloud
+ * @short_description: Cloud widget
+ * @title: GdauiCloud
+ * @stability: Stable
+ * @Image: vi-cloud.png
+ * @see_also:
+ *
+ * The #GdauiCloud widget displays a string for each row in a #GdaDataModel for which the size
+ * is variable (determined either by some data in the data model, or by a function provided by
+ * the programmer).
+ *
+ * Depending on the selection mode of the widget, each string can be selected by the user and
+ * the "selection-changed" signal is emitted.
  */
+
 GType             gdaui_cloud_get_type             (void) G_GNUC_CONST;
 
 GtkWidget        *gdaui_cloud_new                  (GdaDataModel *model, gint label_column, gint weight_column);
diff --git a/libgda-ui/gdaui-combo.h b/libgda-ui/gdaui-combo.h
index fcb4ff2..3f63cf6 100644
--- a/libgda-ui/gdaui-combo.h
+++ b/libgda-ui/gdaui-combo.h
@@ -1,6 +1,5 @@
-/* GNOME DB library
- *
- * Copyright (C) 1999 - 2009 The Free Software Foundation
+/*
+ * Copyright (C) 1999 - 2011 The Free Software Foundation
  *
  * AUTHORS:
  *      Rodrigo Moya <rodrigo gnome-db org>
@@ -49,6 +48,15 @@ struct _GdauiComboClass {
 	GtkComboBoxClass     parent_class;
 };
 
+/**
+ * SECTION:gdaui-combo
+ * @short_description: Combo box to choose from the contents of a #GdaDataModel
+ * @title: GdauiCombo
+ * @stability: Stable
+ * @Image: vi-combo.png
+ * @see_also:
+ */
+
 GType         gdaui_combo_get_type         (void) G_GNUC_CONST;
 
 GtkWidget    *gdaui_combo_new              (void);
diff --git a/libgda-ui/gdaui-data-entry.h b/libgda-ui/gdaui-data-entry.h
index 534ad2e..c2aba1a 100644
--- a/libgda-ui/gdaui-data-entry.h
+++ b/libgda-ui/gdaui-data-entry.h
@@ -1,6 +1,5 @@
-/* gdaui-data-entry.h
- *
- * Copyright (C) 2009 - 2010 Vivien Malerba
+/*
+ * Copyright (C) 2009 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -68,11 +67,38 @@ struct _GdauiDataEntryIface
 
 	/*< private >*/
 	/* Padding for future expansion */
+        void (*_gdaui_reserved1) (void);
         void (*_gdaui_reserved2) (void);
         void (*_gdaui_reserved3) (void);
         void (*_gdaui_reserved4) (void);
 };
 
+/**
+ * SECTION:gdaui-data-entry
+ * @short_description: Data entry widget
+ * @title: GdauiDataEntry
+ * @stability: Stable
+ * @Image: vi-data-entry.png
+ * @see_also:
+ *
+ * The #GdaUiDataEntry is an interface for widgets (simple or complex)
+ * which lets the user view and/or modify a #GValue.
+ *
+ * This interface is implemented by widgets which feature data editing (usually composed of an editing
+ * area and a button to have some more control on the value being edited).
+ * The interface allows to control how the widget works and to query the value and the attributes
+ * of the data held by the widget.
+ *
+ * The widget can store the original value (to be able to tell if the value has been changed
+ * by the user) and a default value (which will be returned if the user explicitly forces the widget
+ * to be set to the default value).
+ * Control methods allow to set the type of value to be edited (the requested type must be
+ * compatible with what the widget can handle), set the value (which replaces the currently edited
+ * value), set the value and the original value (the value passed as argument is set and is also
+ * considered to be the original value).
+ *
+ * #GdaUiDataEntry widgets are normally created using the gdaui_new_data_entry() function.
+ */
 
 
 
diff --git a/libgda-ui/gdaui-data-filter.c b/libgda-ui/gdaui-data-filter.c
index 31041f1..c578fd7 100644
--- a/libgda-ui/gdaui-data-filter.c
+++ b/libgda-ui/gdaui-data-filter.c
@@ -118,11 +118,7 @@ set_wait_cursor (GtkWidget *w)
 	if (parent) {
 		GdkCursor* cursor;
 		cursor = gdk_cursor_new (GDK_WATCH);
-#if GTK_CHECK_VERSION(2,18,0)
 		gdk_window_set_cursor (gtk_widget_get_window (parent), cursor);
-#else
-		gdk_window_set_cursor (parent->window, cursor);
-#endif
 		gdk_cursor_unref (cursor);
 	}
 }
@@ -134,11 +130,7 @@ unset_wait_cursor (GtkWidget *w)
 
 	parent = gtk_widget_get_toplevel (w);
 	if (parent)
-#if GTK_CHECK_VERSION(2,18,0)
 		gdk_window_set_cursor (gtk_widget_get_window (parent), NULL);
-#else
-	gdk_window_set_cursor (parent->window, NULL);
-#endif
 }
 
 static void
diff --git a/libgda-ui/gdaui-data-filter.h b/libgda-ui/gdaui-data-filter.h
index a7bd160..1d86e8b 100644
--- a/libgda-ui/gdaui-data-filter.h
+++ b/libgda-ui/gdaui-data-filter.h
@@ -1,6 +1,5 @@
-/* gdaui-data-filter.h
- *
- * Copyright (C) 2007 - 2009 Vivien Malerba
+/*
+ * Copyright (C) 2007 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -51,9 +50,18 @@ struct _GdauiDataFilterClass
 	GtkVBoxClass                 parent_class;
 };
 
-/* 
- * Generic widget's methods 
+/**
+ * SECTION:gdaui-data-filter
+ * @short_description: Entrer rules to filter the rows in a #GdauiDataProxy
+ * @title: GdauiDataFilter
+ * @stability: Stable
+ * @Image: vi-filter.png
+ * @see_also:
+ *
+ * The #GdauiDataFilter widget can be used as a standalone widget, but is also
+ * used internally by the #GdauiDataProxyInfo widget for its search option.
  */
+
 GType             gdaui_data_filter_get_type                  (void) G_GNUC_CONST;
 
 GtkWidget        *gdaui_data_filter_new                       (GdauiDataProxy *data_widget);
diff --git a/libgda-ui/gdaui-data-proxy-info.h b/libgda-ui/gdaui-data-proxy-info.h
index ddf146e..1529f60 100644
--- a/libgda-ui/gdaui-data-proxy-info.h
+++ b/libgda-ui/gdaui-data-proxy-info.h
@@ -1,6 +1,5 @@
-/* gdaui-data-proxy-info.h
- *
- * Copyright (C) 2006 Vivien Malerba
+/*
+ * Copyright (C) 2006 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -37,6 +36,15 @@ typedef struct _GdauiDataProxyInfo      GdauiDataProxyInfo;
 typedef struct _GdauiDataProxyInfoClass GdauiDataProxyInfoClass;
 typedef struct _GdauiDataProxyInfoPriv  GdauiDataProxyInfoPriv;
 
+/**
+ * GdauiDataProxyInfoFlag:
+ * @GDAUI_DATA_PROXY_INFO_NONE: 
+ * @GDAUI_DATA_PROXY_INFO_CURRENT_ROW: 
+ * @GDAUI_DATA_PROXY_INFO_ROW_MODIFY_BUTTONS: 
+ * @GDAUI_DATA_PROXY_INFO_ROW_MOVE_BUTTONS: 
+ * @GDAUI_DATA_PROXY_INFO_CHUNCK_CHANGE_BUTTONS: 
+ * @GDAUI_DATA_PROXY_INFO_NO_FILTER: 
+ */
 typedef enum 
 {
 	GDAUI_DATA_PROXY_INFO_NONE = 0,
@@ -61,9 +69,21 @@ struct _GdauiDataProxyInfoClass
 	GtkHBoxClass            parent_class;
 };
 
-/* 
- * Generic widget's methods 
+/**
+ * SECTION:gdaui-data-proxy-info
+ * @short_description: Shows information &amp; actions about a #GdauiDataProxy widget
+ * @title: GdauiDataProxyInfo
+ * @stability: Stable
+ * @Image: vi-info.png
+ * @see_also:
+ *
+ * The #GdauiDataProxyInfo widget is a container widget which, depending on how it is configured:
+ * <itemizedlist>
+ *   <listitem><para>proposes action buttons to change the currently displayed row, add new row, ...</para></listitem>
+ *   <listitem><para>displays information about the number of rows in a #GdauiDataProxy</para></listitem>
+ * </itemizedlist>
  */
+
 GType             gdaui_data_proxy_info_get_type (void) G_GNUC_CONST;
 GtkWidget        *gdaui_data_proxy_info_new      (GdauiDataProxy *data_proxy, GdauiDataProxyInfoFlag flags);
 
diff --git a/libgda-ui/gdaui-data-proxy.h b/libgda-ui/gdaui-data-proxy.h
index 961e817..dba8957 100644
--- a/libgda-ui/gdaui-data-proxy.h
+++ b/libgda-ui/gdaui-data-proxy.h
@@ -1,6 +1,5 @@
-/* gdaui-data-proxy.h
- *
- * Copyright (C) 2004 - 2009 Vivien Malerba <malerba gnome-db org>
+/*
+ * Copyright (C) 2004 - 2011 Vivien Malerba <malerba gnome-db org>
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -35,11 +34,21 @@ G_BEGIN_DECLS
 #define GDAUI_IS_DATA_PROXY(obj)       G_TYPE_CHECK_INSTANCE_TYPE (obj, GDAUI_TYPE_DATA_PROXY)
 #define GDAUI_DATA_PROXY_GET_IFACE(obj)  (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GDAUI_TYPE_DATA_PROXY, GdauiDataProxyIface))
 
+/**
+ * GdauiDataProxyWriteMode:
+ * @GDAUI_DATA_PROXY_WRITE_ON_DEMAND: write only when explicitly requested 
+ * @GDAUI_DATA_PROXY_WRITE_ON_ROW_CHANGE: write when the current selected row changes
+ * @GDAUI_DATA_PROXY_WRITE_ON_VALUE_ACTIVATED: write when user activates a value change
+ * @GDAUI_DATA_PROXY_WRITE_ON_VALUE_CHANGE: write when a parameters's value changes
+ *
+ * Defines when the data modifications held in the underlying #GdaDataProxy are written to the
+ * data model being proxied (using gda_data_proxy_apply_row_changes()).
+ */
 typedef enum {
-	GDAUI_DATA_PROXY_WRITE_ON_DEMAND           = 0, /* write only when explicitly requested */
-	GDAUI_DATA_PROXY_WRITE_ON_ROW_CHANGE       = 1, /* write when the current selected row changes */
-	GDAUI_DATA_PROXY_WRITE_ON_VALUE_ACTIVATED  = 2, /* write when user activates a value change */
-	GDAUI_DATA_PROXY_WRITE_ON_VALUE_CHANGE     = 3  /* write when a parameters's value changes */
+	GDAUI_DATA_PROXY_WRITE_ON_DEMAND           = 0,
+	GDAUI_DATA_PROXY_WRITE_ON_ROW_CHANGE       = 1,
+	GDAUI_DATA_PROXY_WRITE_ON_VALUE_ACTIVATED  = 2,
+	GDAUI_DATA_PROXY_WRITE_ON_VALUE_CHANGE     = 3 
 } GdauiDataProxyWriteMode;
 
 /* struct for the interface */
@@ -59,6 +68,19 @@ struct _GdauiDataProxyIface
 	void                 (* proxy_changed)       (GdauiDataProxy *iface, GdaDataProxy *proxy);
 };
 
+/**
+ * SECTION:gdaui-data-proxy
+ * @short_description: Displaying and modifying data in a #GdaDataProxy
+ * @title: GdauiDataProxy
+ * @stability: Stable
+ * @Image:
+ * @see_also: The #GdauiDataSelector interface which is usually also implemented by the widgets which implement the #GdauiDataProxy interface.
+ *
+ * The #GdauiDataProxy interface is implemented by widgets which allow modifications
+ * to a #GdaDataModel (through a #GdaDataProxy to actually proxy the changes before they
+ * are written to the data model).
+ */
+
 GType             gdaui_data_proxy_get_type                  (void) G_GNUC_CONST;
 
 GdaDataProxy     *gdaui_data_proxy_get_proxy                 (GdauiDataProxy *iface);
diff --git a/libgda-ui/gdaui-data-selector.h b/libgda-ui/gdaui-data-selector.h
index 27ebe65..988d7eb 100644
--- a/libgda-ui/gdaui-data-selector.h
+++ b/libgda-ui/gdaui-data-selector.h
@@ -1,6 +1,5 @@
-/* gdaui-data-selector.h
- *
- * Copyright (C) 2009 Vivien Malerba <malerba gnome-db org>
+/*
+ * Copyright (C) 2009 - 2011 Vivien Malerba <malerba gnome-db org>
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -55,6 +54,25 @@ struct _GdauiDataSelectorIface
 	void              (* selection_changed)    (GdauiDataSelector *iface);
 };
 
+/**
+ * SECTION:gdaui-data-selector
+ * @short_description: Selecting data in a #GdaDataModel
+ * @title: GdauiDataSelector
+ * @stability: Stable
+ * @Image:
+ * @see_also:
+ *
+ * The #GdauiDataSelector interface is implemented by widgets which allow the user
+ * to select some data from a #GdaDataModel. Depending on the actual widget, the selection
+ * can be a single row or more than one row.
+ *
+ * This interface allows one to set and get the #GdaDataModel from which data is to be selected
+ * and offers a few other common behaviours.
+ *
+ * Please note that any row number in this interface is in reference to the #GdaDataModel returned by
+ * the gdaui_data_selector_get_model() method.
+ */
+
 GType             gdaui_data_selector_get_type              (void) G_GNUC_CONST;
 
 GdaDataModel     *gdaui_data_selector_get_model             (GdauiDataSelector *iface);
diff --git a/libgda-ui/gdaui-data-store.h b/libgda-ui/gdaui-data-store.h
index 52d6f19..af98431 100644
--- a/libgda-ui/gdaui-data-store.h
+++ b/libgda-ui/gdaui-data-store.h
@@ -1,6 +1,5 @@
-/* gdaui-data-store.h
- *
- * Copyright (C) 2005 - 2009 Vivien Malerba <malerba gnome-db org>
+/*
+ * Copyright (C) 2005 - 2011 Vivien Malerba <malerba gnome-db org>
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -58,6 +57,18 @@ struct _GdauiDataStoreClass
 	GObjectClass           parent_class;
 };
 
+/**
+ * SECTION:gdaui-data-store
+ * @short_description: Bridge between a #GdaDataModel and a #GtkTreeModel
+ * @title: GdauiDataStore
+ * @stability: Stable
+ * @Image:
+ * @see_also:
+ *
+ * The #GdauiDataStore object implements the #GtkTreeModel interface
+ * on top of a #GdaDataModel to be able to display its contents
+ * in a #GtkTreeView.
+ */
 
 GType           gdaui_data_store_get_type             (void) G_GNUC_CONST;
 GtkTreeModel   *gdaui_data_store_new                  (GdaDataModel *model);
diff --git a/libgda-ui/gdaui-easy.h b/libgda-ui/gdaui-easy.h
index fe457b3..c4109c1 100644
--- a/libgda-ui/gdaui-easy.h
+++ b/libgda-ui/gdaui-easy.h
@@ -1,5 +1,5 @@
-/* GDA library
- * Copyright (C) 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 2009 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -27,6 +27,15 @@
 
 G_BEGIN_DECLS
 
+/**
+ * SECTION:gdaui-easy
+ * @short_description: Set of UI related functions
+ * @title: UI Utility functions
+ * @stability: Stable
+ * @Image:
+ * @see_also:
+ */
+
 GdauiDataEntry  *gdaui_new_data_entry    (GType type, const gchar *plugin_name);
 GtkCellRenderer *_gdaui_new_cell_renderer (GType type, const gchar *plugin_name);
 
diff --git a/libgda-ui/gdaui-form.h b/libgda-ui/gdaui-form.h
index 895e378..1036e4f 100644
--- a/libgda-ui/gdaui-form.h
+++ b/libgda-ui/gdaui-form.h
@@ -1,6 +1,5 @@
-/* gdaui-form.h
- *
- * Copyright (C) 2002 - 2006 Vivien Malerba
+/*
+ * Copyright (C) 2002 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -50,9 +49,15 @@ struct _GdauiFormClass
 	GtkVBoxClass       parent_class;
 };
 
-/* 
- * Generic widget's methods 
+/**
+ * SECTION:gdaui-form
+ * @short_description: Form widget to manipulate data in a #GdaDataModel, with decorations
+ * @title: GdauiForm
+ * @stability: Stable
+ * @Image:
+ * @see_also: The #GdauiRawForm widget which is used by the #GdaForm widget.
  */
+
 GType             gdaui_form_get_type            (void) G_GNUC_CONST;
 
 GtkWidget        *gdaui_form_new                 (GdaDataModel *model);
diff --git a/libgda-ui/gdaui-grid.h b/libgda-ui/gdaui-grid.h
index 5bfd585..5ab4152 100644
--- a/libgda-ui/gdaui-grid.h
+++ b/libgda-ui/gdaui-grid.h
@@ -1,6 +1,5 @@
-/* gdaui-grid.h
- *
- * Copyright (C) 2002 - 2009 Vivien Malerba <malerba gnome-db org>
+/*
+ * Copyright (C) 2002 - 2011 Vivien Malerba <malerba gnome-db org>
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -49,9 +48,15 @@ struct _GdauiGridClass
 	GtkVBoxClass       parent_class;
 };
 
-/* 
- * Generic widget's methods 
+/**
+ * SECTION:gdaui-grid
+ * @short_description: Grid widget to manipulate data in a #GdaDataModel, with decorations
+ * @title: GdauiGrid
+ * @stability: Stable
+ * @Image:
+ * @see_also: The #GdauiRawGrid widget which is used by the #GdaGrid widget.
  */
+
 GType             gdaui_grid_get_type            (void) G_GNUC_CONST;
 
 GtkWidget        *gdaui_grid_new                 (GdaDataModel *model);
diff --git a/libgda-ui/gdaui-init.c b/libgda-ui/gdaui-init.c
index 60290a2..32086ec 100644
--- a/libgda-ui/gdaui-init.c
+++ b/libgda-ui/gdaui-init.c
@@ -174,8 +174,7 @@ gdaui_new_data_entry (GType type, const gchar *plugin_name)
 			 (type == GDA_TYPE_BINARY))
 			entry = (GdauiDataEntry *) gdaui_entry_bin_new (dh, type);
 		else if	((type == GDA_TYPE_GEOMETRIC_POINT) ||
-			 (type == G_TYPE_OBJECT) ||
-			 (type == GDA_TYPE_LIST))
+			 (type == G_TYPE_OBJECT))
 			entry = (GdauiDataEntry *) gdaui_entry_none_new (type);
 		else if	(type == GDA_TYPE_TIME)
 			entry = (GdauiDataEntry *) gdaui_entry_time_new (dh);
diff --git a/libgda-ui/gdaui-login.c b/libgda-ui/gdaui-login.c
index 936f705..cb790e4 100644
--- a/libgda-ui/gdaui-login.c
+++ b/libgda-ui/gdaui-login.c
@@ -384,40 +384,45 @@ radio_button_use_dsn_toggled_cb (GtkToggleButton *button, GdauiLogin *login)
 static void
 run_cc_cb (G_GNUC_UNUSED GtkButton *button, GdauiLogin *login)
 {
-	char *argv[2];
+	GAppInfo *appinfo;
+	GdkAppLaunchContext *context;
+	GdkScreen *screen;
 	gboolean sresult;
 	GError *lerror = NULL;
+	gchar *cmd;
 	
 #ifdef G_OS_WIN32
 #define EXENAME "gda-control-center-" GDA_ABI_VERSION ".exe"
 #else
 #define EXENAME "gda-control-center-" GDA_ABI_VERSION
 #endif
-	/* run gnome-database-properties dictig tool */
-	argv[0] = gda_gbr_get_file_path (GDA_BIN_DIR, (char *) EXENAME, NULL);
-	argv[1] = NULL;
-        
-	sresult = gdk_spawn_on_screen (gtk_widget_get_screen (GTK_WIDGET (login)),
-				       NULL, argv, NULL, 0,
-				       NULL, NULL, NULL, &lerror);
-	if (!sresult && lerror && (lerror->domain == G_SPAWN_ERROR) && (lerror->code == G_SPAWN_ERROR_NOENT)) {
-		g_error_free (lerror);
-		lerror = NULL;
-		g_free (argv [0]);
-		argv[0] = g_strdup ((char *) EXENAME);
-		sresult = gdk_spawn_on_screen (gtk_widget_get_screen (GTK_WIDGET (login)),
-					       NULL, argv, NULL, G_SPAWN_SEARCH_PATH,
-					       NULL, NULL, NULL, &lerror);
+	/* run gnome-database-properties tool */
+	cmd = gda_gbr_get_file_path (GDA_BIN_DIR, (char *) EXENAME, NULL);
+	appinfo = g_app_info_create_from_commandline (cmd,
+						      "Gda Control center",
+						      G_APP_INFO_CREATE_NONE,
+						      NULL);
+	g_free (cmd);
+
+	screen = gtk_widget_get_screen (GTK_WIDGET (login));
+	context = gdk_display_get_app_launch_context (gdk_screen_get_display (screen));
+	gdk_app_launch_context_set_screen (context, screen);
+	sresult = g_app_info_launch (appinfo, NULL, G_APP_LAUNCH_CONTEXT (context), NULL);
+	if (! sresult) {
+		g_object_unref (appinfo);
+		appinfo = g_app_info_create_from_commandline (EXENAME,
+							      "Gda Control center",
+							      G_APP_INFO_CREATE_NONE,
+							      NULL);
+		sresult = g_app_info_launch (appinfo, NULL, G_APP_LAUNCH_CONTEXT (context), &lerror);
 	}
-	g_free (argv [0]);
+	g_object_unref (context);
+	g_object_unref (appinfo);
+
 	if (!sresult) {
 		GtkWidget *msgdialog;
 		GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (login));
-#if GTK_CHECK_VERSION(2,18,0)
 		if (!gtk_widget_is_toplevel (toplevel))
-#else
-		if (!GTK_WIDGET_TOPLEVEL (toplevel))
-#endif
 			toplevel = NULL;
 		msgdialog = gtk_message_dialog_new_with_markup (GTK_WINDOW (toplevel), GTK_DIALOG_MODAL,
 								GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
diff --git a/libgda-ui/gdaui-login.h b/libgda-ui/gdaui-login.h
index dc38783..7145f9f 100644
--- a/libgda-ui/gdaui-login.h
+++ b/libgda-ui/gdaui-login.h
@@ -1,5 +1,5 @@
-/* GNOME DB library
- * Copyright (C) 1999 - 2008 The GNOME Foundation.
+/*
+ * Copyright (C) 1999 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Rodrigo Moya <rodrigo gnome-db org>
@@ -50,12 +50,38 @@ struct _GdauiLoginClass {
 	void               (*changed) (GdauiLogin *login, gboolean is_valid);
 };
 
+/**
+ * GdauiLoginMode:
+ * @GDA_UI_LOGIN_ENABLE_CONTROL_CENTRE_MODE: 
+ * @GDA_UI_LOGIN_HIDE_DSN_SELECTION_MODE: 
+ * @GDA_UI_LOGIN_HIDE_DIRECT_CONNECTION_MODE: 
+ *
+ * Defines the aspect of the #GdauiLogin widget
+ */
 typedef enum {
 	GDA_UI_LOGIN_ENABLE_CONTROL_CENTRE_MODE = 1 << 0,
 	GDA_UI_LOGIN_HIDE_DSN_SELECTION_MODE = 1 << 1,
 	GDA_UI_LOGIN_HIDE_DIRECT_CONNECTION_MODE = 1 << 2
 } GdauiLoginMode;
 
+/**
+ * SECTION:gdaui-login
+ * @short_description: Connection opening widget
+ * @title: GdauiLogin
+ * @stability: Stable
+ * @Image: vi-login.png
+ * @see_also:
+ *
+ * The #GdauiLogin widget can be used when the user needs to enter
+ * data to open a connection. It can be customized in several ways:
+ * <itemizedlist>
+ *   <listitem><para>data source (DSN) selection can be shown or hidden</para></listitem>
+ *   <listitem><para>the button to launch the control center to declare new data sources can be
+ *	shown or hidden</para></listitem>
+ *   <listitem><para>the form to open a connection not using a DSN can be shown or hidden</para></listitem>
+ * </itemizedlist>
+ */
+
 GType             gdaui_login_get_type                   (void) G_GNUC_CONST;
 GtkWidget        *gdaui_login_new                        (const gchar *dsn);
 void              gdaui_login_set_mode                   (GdauiLogin *login, GdauiLoginMode mode);
diff --git a/libgda-ui/gdaui-plugin.h b/libgda-ui/gdaui-plugin.h
index 0bd60f2..321c6ff 100644
--- a/libgda-ui/gdaui-plugin.h
+++ b/libgda-ui/gdaui-plugin.h
@@ -1,6 +1,5 @@
-/* gdaui-plugin.h
- *
- * Copyright (C) 2006 - 2009 Vivien Malerba <malerba gnome-db org>
+/*
+ * Copyright (C) 2006 - 2011 Vivien Malerba <malerba gnome-db org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -26,7 +25,26 @@
 #include <libgda-ui/gdaui-data-entry.h>
 #include "gdaui-decl.h"
 
+/**
+ * GdauiEntryCreateFunc:
+ * @Param1: 
+ * @Param2: 
+ * @Param3: 
+ * @Returns:
+ *
+ * Defines a function which creates a #GdauiDataEntry widget
+ */
 typedef GdauiDataEntry   *(*GdauiEntryCreateFunc)(GdaDataHandler *, GType, const gchar *);
+
+/**
+ * GdauiCellCreateFunc:
+ * @Param1: 
+ * @Param2: 
+ * @Param3: 
+ * @Returns:
+ *
+ * Defines a function which creates a #GtkCellRenderer object
+ */
 typedef GtkCellRenderer  *(*GdauiCellCreateFunc) (GdaDataHandler *, GType, const gchar *);
 
 
@@ -61,6 +79,17 @@ typedef struct {
 	GdauiCellCreateFunc   cell_create_func;
 } GdauiPlugin;
 
+/**
+ * SECTION:gdaui-plugins
+ * @short_description: 
+ * @title: UI plugins
+ * @stability: Stable
+ * @Image:
+ * @see_also:
+ *
+ * This section describes the functions used to declare UI plugins: data entry and cell renderers.
+ */
+
 void gdaui_plugin_declare (const GdauiPlugin *plugin);
 
 #endif
diff --git a/libgda-ui/gdaui-provider-selector.h b/libgda-ui/gdaui-provider-selector.h
index 5383a5a..d8f2fa8 100644
--- a/libgda-ui/gdaui-provider-selector.h
+++ b/libgda-ui/gdaui-provider-selector.h
@@ -1,5 +1,5 @@
-/* GNOME DB library
- * Copyright (C) 1999 - 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 1999 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Rodrigo Moya <rodrigo gnome-db org>
@@ -47,6 +47,15 @@ struct _GdauiProviderSelectorClass {
 	GdauiComboClass               parent_class;
 };
 
+/**
+ * SECTION:gdaui-provider-selector
+ * @short_description: Select a database provider from a combo box
+ * @title: GdauiProviderSelector
+ * @stability: Stable
+ * @Image: vi-provider-selector.png
+ * @see_also:
+ */
+
 GType              gdaui_provider_selector_get_type         (void) G_GNUC_CONST;
 GtkWidget         *gdaui_provider_selector_new              (void);
 
diff --git a/libgda-ui/gdaui-raw-form.c b/libgda-ui/gdaui-raw-form.c
index 0a68587..21acb45 100644
--- a/libgda-ui/gdaui-raw-form.c
+++ b/libgda-ui/gdaui-raw-form.c
@@ -761,10 +761,10 @@ filter_event (G_GNUC_UNUSED GtkWidget *widget, G_GNUC_UNUSED GdkEventAny *event,
 static gboolean
 key_press_filter_event (G_GNUC_UNUSED GtkWidget *widget, GdkEventKey *event, GdauiRawForm *form)
 {
-	if (event->keyval == GDK_Escape ||
-	    event->keyval == GDK_Tab ||
-            event->keyval == GDK_KP_Tab ||
-            event->keyval == GDK_ISO_Left_Tab) {
+	if (event->keyval == GDK_KEY_Escape ||
+	    event->keyval == GDK_KEY_Tab ||
+            event->keyval == GDK_KEY_KP_Tab ||
+            event->keyval == GDK_KEY_ISO_Left_Tab) {
 		hide_filter_window (form);
 		return TRUE;
 	}
@@ -785,21 +785,16 @@ filter_position_func (GtkWidget *widget,
 	gint monitor_num;
 	GdkRectangle monitor;
 
-#if GTK_CHECK_VERSION(2,18,0)
 	window = gtk_widget_get_window (widget);
-#else
-	window = widget->window;
-#endif
-	screen = gdk_drawable_get_screen (window);
+	screen = gdk_window_get_screen (window);
 	monitor_num = gdk_screen_get_monitor_at_window (screen, window);
 	gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
 
 	gtk_widget_realize (search_dialog);
 
 	gdk_window_get_origin (window, &tree_x, &tree_y);
-	gdk_drawable_get_size (window,
-			       &tree_width,
-			       &tree_height);
+	tree_width = gdk_window_get_width (window);
+	tree_height = gdk_window_get_height (window);
 	gtk_widget_size_request (search_dialog, &requisition);
 
 	if (tree_x + tree_width > gdk_screen_get_width (screen))
@@ -854,15 +849,9 @@ action_filter_cb (G_GNUC_UNUSED GtkAction *action, GdauiRawForm *form)
 		gtk_widget_set_events (form->priv->filter_window,
 				       gtk_widget_get_events (form->priv->filter_window) | GDK_KEY_PRESS_MASK);
 
-#if GTK_CHECK_VERSION(2,18,0)
 		if (gtk_widget_is_toplevel (toplevel) && gtk_window_get_group ((GtkWindow*) toplevel))
 			gtk_window_group_add_window (gtk_window_get_group ((GtkWindow*) toplevel),
 						     GTK_WINDOW (form->priv->filter_window));
-#else
-		if (GTK_WIDGET_TOPLEVEL (toplevel) && GTK_WINDOW (toplevel)->group)
-			gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
-						     GTK_WINDOW (form->priv->filter_window));
-#endif
 
 		g_signal_connect (form->priv->filter_window, "delete-event",
 				  G_CALLBACK (filter_event), form);
@@ -887,7 +876,6 @@ action_filter_cb (G_GNUC_UNUSED GtkAction *action, GdauiRawForm *form)
 		}
 		gtk_container_add (GTK_CONTAINER (vbox), form->priv->filter);
 	}
-#if GTK_CHECK_VERSION(2,18,0)
 	else if (gtk_widget_is_toplevel (toplevel)) {
 		if (gtk_window_get_group ((GtkWindow*) toplevel))
 			gtk_window_group_add_window (gtk_window_get_group ((GtkWindow*) toplevel),
@@ -896,29 +884,14 @@ action_filter_cb (G_GNUC_UNUSED GtkAction *action, GdauiRawForm *form)
 			gtk_window_group_remove_window (gtk_window_get_group ((GtkWindow*) form->priv->filter_window),
 							GTK_WINDOW (form->priv->filter_window));
 	}
-#else
-	else if (GTK_WIDGET_TOPLEVEL (toplevel)) {
-		if (GTK_WINDOW (toplevel)->group)
-			gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
-						     GTK_WINDOW (form->priv->filter_window));
-		else if (GTK_WINDOW (form->priv->filter_window)->group)
-			gtk_window_group_remove_window (GTK_WINDOW (form->priv->filter_window)->group,
-							GTK_WINDOW (form->priv->filter_window));
-	}
-#endif
 
 	/* move the filter window to a correct location */
 	/* FIXME: let the user specify the position function like GtkTreeView -> search_position_func() */
 	gtk_grab_add (form->priv->filter_window);
 	filter_position_func (GTK_WIDGET (form), form->priv->filter_window, NULL);
 	gtk_widget_show (form->priv->filter_window);
-#if GTK_CHECK_VERSION(2,18,0)
 	popup_grab_on_window (gtk_widget_get_window (form->priv->filter_window),
 			      gtk_get_current_event_time ());
-#else
-	popup_grab_on_window (form->priv->filter_window->window,
-			      gtk_get_current_event_time ());
-#endif
 }
 
 
diff --git a/libgda-ui/gdaui-raw-form.h b/libgda-ui/gdaui-raw-form.h
index bc1a5e0..8840d82 100644
--- a/libgda-ui/gdaui-raw-form.h
+++ b/libgda-ui/gdaui-raw-form.h
@@ -1,6 +1,5 @@
-/* gdaui-raw-form.h
- *
- * Copyright (C) 2002 - 2009 Vivien Malerba <malerba gnome-db org>
+/*
+ * Copyright (C) 2002 - 2011 Vivien Malerba <malerba gnome-db org>
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -51,9 +50,18 @@ struct _GdauiRawFormClass
 	GdauiBasicFormClass parent_class;
 };
 
-/* 
- * Generic widget's methods 
+/**
+ * SECTION:gdaui-raw-form
+ * @short_description: Form widget to manipulate data in a #GdaDataModel
+ * @title: GdauiRawForm
+ * @stability: Stable
+ * @Image:
+ * @see_also: the #GdauiForm widget which uses the #GdauiRawForm and adds decorations such as information about data model size, and features searching.
+ *
+ * The #GdauiForm widget which uses the #GdauiRawForm and adds decorations such as
+ * information about data model size, and features searching.
  */
+
 GType        gdaui_raw_form_get_type              (void) G_GNUC_CONST;
 GtkWidget   *gdaui_raw_form_new                   (GdaDataModel *model);
 
diff --git a/libgda-ui/gdaui-raw-grid.c b/libgda-ui/gdaui-raw-grid.c
index 3f66213..f7eb345 100644
--- a/libgda-ui/gdaui-raw-grid.c
+++ b/libgda-ui/gdaui-raw-grid.c
@@ -1496,10 +1496,10 @@ filter_event (G_GNUC_UNUSED GtkWidget *widget, G_GNUC_UNUSED GdkEventAny *event,
 static gboolean
 key_press_filter_event (G_GNUC_UNUSED GtkWidget *widget, GdkEventKey *event, GdauiRawGrid *grid)
 {
-	if (event->keyval == GDK_Escape ||
-	    event->keyval == GDK_Tab ||
-            event->keyval == GDK_KP_Tab ||
-            event->keyval == GDK_ISO_Left_Tab) {
+	if (event->keyval == GDK_KEY_Escape ||
+	    event->keyval == GDK_KEY_Tab ||
+            event->keyval == GDK_KEY_KP_Tab ||
+            event->keyval == GDK_KEY_ISO_Left_Tab) {
 		hide_filter_window (grid);
 		return TRUE;
 	}
@@ -1520,12 +1520,8 @@ filter_position_func (GtkWidget *widget,
 	gint monitor_num;
 	GdkRectangle monitor;
 
-#if GTK_CHECK_VERSION(2,18,0)
 	window = gtk_widget_get_window (widget);
-#else
-	window = widget->window;
-#endif
-	screen = gdk_drawable_get_screen (window);
+	screen = gdk_window_get_screen (window);
 
 	monitor_num = gdk_screen_get_monitor_at_window (screen, window);
 	gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
@@ -1533,9 +1529,8 @@ filter_position_func (GtkWidget *widget,
 	gtk_widget_realize (search_dialog);
 
 	gdk_window_get_origin (window, &tree_x, &tree_y);
-	gdk_drawable_get_size (window,
-			       &tree_width,
-			       &tree_height);
+	tree_width = gdk_window_get_width (window);
+	tree_height = gdk_window_get_height (window);
 	gtk_widget_size_request (search_dialog, &requisition);
 
 	if (tree_x + tree_width > gdk_screen_get_width (screen))
@@ -1590,15 +1585,9 @@ action_filter_cb (G_GNUC_UNUSED GtkAction *action, GdauiRawGrid *grid)
 		gtk_widget_set_events (grid->priv->filter_window,
 				       gtk_widget_get_events (grid->priv->filter_window) | GDK_KEY_PRESS_MASK);
 
-#if GTK_CHECK_VERSION(2,18,0)
 		if (gtk_widget_is_toplevel (toplevel) && gtk_window_get_group (GTK_WINDOW (toplevel)))
 			gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
 						     GTK_WINDOW (grid->priv->filter_window));
-#else
-		if (GTK_WIDGET_TOPLEVEL (toplevel) && GTK_WINDOW (toplevel)->group)
-			gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
-						     GTK_WINDOW (grid->priv->filter_window));
-#endif
 
 		g_signal_connect (grid->priv->filter_window, "delete-event",
 				  G_CALLBACK (filter_event), grid);
@@ -1623,7 +1612,6 @@ action_filter_cb (G_GNUC_UNUSED GtkAction *action, GdauiRawGrid *grid)
 		}
 		gtk_container_add (GTK_CONTAINER (vbox), grid->priv->filter);
 	}
-#if GTK_CHECK_VERSION(2,18,0)
 	else if (gtk_widget_is_toplevel (toplevel)) {
 		if (gtk_window_get_group ((GtkWindow*) toplevel))
 			gtk_window_group_add_window (gtk_window_get_group ((GtkWindow*) toplevel),
@@ -1632,30 +1620,14 @@ action_filter_cb (G_GNUC_UNUSED GtkAction *action, GdauiRawGrid *grid)
 			gtk_window_group_remove_window (gtk_window_get_group (GTK_WINDOW (grid->priv->filter_window)),
 							GTK_WINDOW (grid->priv->filter_window));
 	}
-#else
-	else if (GTK_WIDGET_TOPLEVEL (toplevel)) {
-		if (GTK_WINDOW (toplevel)->group)
-			gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
-						     GTK_WINDOW (grid->priv->filter_window));
-		else if (GTK_WINDOW (grid->priv->filter_window)->group)
-			gtk_window_group_remove_window (GTK_WINDOW (grid->priv->filter_window)->group,
-							GTK_WINDOW (grid->priv->filter_window));
-	}
-#endif
 
 	/* move the filter window to a correct location */
 	/* FIXME: let the user specify the position function like GtkTreeView -> search_position_func() */
 	gtk_grab_add (grid->priv->filter_window);
 	filter_position_func (GTK_WIDGET (grid), grid->priv->filter_window, NULL);
 	gtk_widget_show (grid->priv->filter_window);
-#if GTK_CHECK_VERSION(2,18,0)
 	popup_grab_on_window (gtk_widget_get_window (grid->priv->filter_window),
-			      gtk_get_current_event_time ());
-#else
-	popup_grab_on_window (grid->priv->filter_window->window,
-			      gtk_get_current_event_time ());
-#endif
-	
+			      gtk_get_current_event_time ());	
 }
 
 /*
@@ -1671,7 +1643,7 @@ tree_view_event_cb (GtkWidget *treeview, GdkEvent *event, GdauiRawGrid *grid)
 		guint modifiers = gtk_accelerator_get_default_mod_mask ();
 
 		/* Tab to move one column left or right */
-		if (ekey->keyval == GDK_Tab) {
+		if (ekey->keyval == GDK_KEY_Tab) {
 			GtkTreeViewColumn *column;
 			GtkTreePath *path;
 
@@ -1706,7 +1678,7 @@ tree_view_event_cb (GtkWidget *treeview, GdkEvent *event, GdauiRawGrid *grid)
 		}
 
 		/* DELETE to delete the selected row */
-		if (ekey->keyval == GDK_Delete) {
+		if (ekey->keyval == GDK_KEY_Delete) {
 			GtkTreeIter iter;
 			GtkTreeSelection *selection;
 			GtkTreeModel *model;
@@ -1934,11 +1906,7 @@ menu_save_as_cb (G_GNUC_UNUSED GtkWidget *widget, GdauiRawGrid *grid)
 	gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
 	g_free (str);
 
-#if GTK_CHECK_VERSION(2,18,0)
 	dbox = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
-#else
-	dbox = GTK_DIALOG (dialog)->vbox;
-#endif
 	gtk_box_pack_start (GTK_BOX (dbox), label, FALSE, TRUE, 2);
 
 	str = g_strdup_printf ("<b>%s:</b>", _("File name"));
@@ -1986,14 +1954,14 @@ menu_save_as_cb (G_GNUC_UNUSED GtkWidget *widget, GdauiRawGrid *grid)
 	gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
 	gtk_widget_show (label);
 
-	types = gtk_combo_box_new_text ();
+	types = gtk_combo_box_text_new ();
 	gtk_table_attach_defaults (GTK_TABLE (table), types, 1, 2, 0, 1);
 	gtk_widget_show (label);
 	g_object_set_data (G_OBJECT (dialog), "types", types);
 
-	gtk_combo_box_append_text (GTK_COMBO_BOX (types), _("Tab-delimited"));
-	gtk_combo_box_append_text (GTK_COMBO_BOX (types), _("Comma-delimited"));
-	gtk_combo_box_append_text (GTK_COMBO_BOX (types), _("XML"));
+	gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (types), _("Tab-delimited"));
+	gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (types), _("Comma-delimited"));
+	gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (types), _("XML"));
 	gtk_combo_box_set_active (GTK_COMBO_BOX (types), grid->priv->export_type);
 
 	g_signal_connect (types, "changed",
@@ -2264,11 +2232,7 @@ confirm_file_overwrite (GtkWindow *parent, const gchar *path)
 	g_free (msg);
 
 	button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
-#if GTK_CHECK_VERSION(2,18,0)
 	gtk_widget_set_can_default (button, TRUE);
-#else
-	GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
-#endif
 	gtk_dialog_set_default_response (GTK_DIALOG (dialog),
 					 GTK_RESPONSE_NO);
 
diff --git a/libgda-ui/gdaui-raw-grid.h b/libgda-ui/gdaui-raw-grid.h
index f751ecc..f3f7da2 100644
--- a/libgda-ui/gdaui-raw-grid.h
+++ b/libgda-ui/gdaui-raw-grid.h
@@ -1,6 +1,5 @@
-/* gdaui-raw-grid.h
- *
- * Copyright (C) 2002 - 2009 Vivien Malerba <malerba gnome-db org>
+/*
+ * Copyright (C) 2002 - 2011 Vivien Malerba <malerba gnome-db org>
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -52,9 +51,18 @@ struct _GdauiRawGridClass
         void             (* populate_popup)    (GdauiRawGrid *grid, GtkMenu *menu);
 };
 
-/* 
- * Generic widget's methods 
+/**
+ * SECTION:gdaui-raw-grid
+ * @short_description: Grid widget to manipulate data in a #GdaDataModel
+ * @title: GdauiRawGrid
+ * @stability: Stable
+ * @Image: vi-raw-grid.png
+ * @see_also: the #GdauiGrid widget which uses the #GdauiRawGrid and adds decorations such as information about data model size, and features searching.
+ *
+ * The #GdauiGrid widget which uses the #GdauiRawGrid and adds decorations such as
+ * information about data model size, and features searching.
  */
+
 GType      gdaui_raw_grid_get_type              (void) G_GNUC_CONST;
 
 GtkWidget *gdaui_raw_grid_new                   (GdaDataModel *model);
diff --git a/libgda-ui/gdaui-rt-editor.c b/libgda-ui/gdaui-rt-editor.c
index f8ddee1..c89357d 100644
--- a/libgda-ui/gdaui-rt-editor.c
+++ b/libgda-ui/gdaui-rt-editor.c
@@ -1185,6 +1185,8 @@ text_buffer_changed_cb (GtkTextBuffer *textbuffer, GdauiRtEditor *rte)
  *
  * returns the token type starting from @iter, and positions @out_end to the last used position
  * position.
+ *
+ * Returns: a #MarkupTag
  */
 static MarkupTag
 get_token (GtkTextIter *iter, gint *out_nb_spaces_before, GtkTextIter *out_end,
diff --git a/libgda-ui/gdaui-rt-editor.h b/libgda-ui/gdaui-rt-editor.h
index 89926cb..b231e1b 100644
--- a/libgda-ui/gdaui-rt-editor.h
+++ b/libgda-ui/gdaui-rt-editor.h
@@ -1,6 +1,5 @@
-/* gdaui-rt-editor.h
- *
- * Copyright (C) 2010 Vivien Malerba <malerba gnome-db org>
+/*
+ * Copyright (C) 2010 - 2011 Vivien Malerba <malerba gnome-db org>
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -52,9 +51,32 @@ struct _GdauiRtEditorClass
         void (* changed) (GdauiRtEditor *editor);
 };
 
-/* 
- * Generic widget's methods 
+/**
+ * SECTION:gdaui-rt-editor
+ * @short_description: Rich text editor which uses a subset of the <ulink url="http://www.txt2tags.org/markup.html";>txt2tags</ulink> markup.
+ * @title: GdauiRtEditor
+ * @stability: Stable
+ * @Image: vi-rte.png
+ * @see_also: 
+ *
+ * The text entered in the editor can be formatted using bold, underline, title, ... attributes
+ * and then extracted using a subset of the <ulink url="http://www.txt2tags.org/markup.html";>txt2tags</ulink>
+ * markup. Use this widget to edit textual fields where some markup is desirable to organize the text.
+ *
+ * For example the real text used to obtain the formatting in the figure is:
+ * <programlisting>
+ *blah //italic// blah.
+ *and ** BOLD!//both italic and bold// Bold!**
+ *Nice Picture: [[[R2RrUAA...y8vLy8tYQwAA]]] Yes
+ *- List item --One--
+ *- List item **Two**
+ * - sub1
+ * - sub2</programlisting>
+ * where the picture's serialized data has been truncated here for readability
+ * (between the [[[ and ]]] markers). Pictures are usually inserted using the incorporated
+ * tollbar and not y hand (even though it's possible).
  */
+
 GType      gdaui_rt_editor_get_type              (void) G_GNUC_CONST;
 
 GtkWidget *gdaui_rt_editor_new                   (void);
diff --git a/libgda-ui/gdaui-server-operation.c b/libgda-ui/gdaui-server-operation.c
index 42ead07..7732770 100644
--- a/libgda-ui/gdaui-server-operation.c
+++ b/libgda-ui/gdaui-server-operation.c
@@ -1,6 +1,6 @@
 /* gdaui-server-operation.c
  *
- * Copyright (C) 2006 - 2009 Vivien Malerba
+ * Copyright (C) 2006 - 2010 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -1120,11 +1120,7 @@ gdaui_server_operation_new_in_dialog (GdaServerOperation *op, GtkWindow *parent,
 					   GTK_STOCK_CANCEL,
 					   GTK_RESPONSE_REJECT,
 					   NULL);
-#if GTK_CHECK_VERSION(2,18,0)
 	dcontents = gtk_dialog_get_content_area (GTK_DIALOG (dlg));
-#else
-	dcontents = GTK_DIALOG (dlg)->vbox;
-#endif
 
 	if (header && *header) {
 		GtkWidget *label;
diff --git a/libgda-ui/gdaui-server-operation.h b/libgda-ui/gdaui-server-operation.h
index 1e5ba01..63422ab 100644
--- a/libgda-ui/gdaui-server-operation.h
+++ b/libgda-ui/gdaui-server-operation.h
@@ -1,6 +1,5 @@
-/* gdaui-server-operation.h
- *
- * Copyright (C) 2006 Vivien Malerba
+/*
+ * Copyright (C) 2006 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -52,9 +51,20 @@ struct _GdauiServerOperationClass
 	GtkVBoxClass                parent_class;
 };
 
-/* 
- * Generic widget's methods 
-*/
+/**
+ * SECTION:gdaui-server-operation
+ * @short_description: Enter information to perform a DDL query
+ * @title: GdauiServerOperation
+ * @stability: Stable
+ * @Image:
+ * @see_also: See the #GdaServerOperation which actually holds the information to perform the action
+ *
+ * The #GdauiServerOperation widget allows the user to enter information to perform
+ * Data Definition queries (all queries which are not SELECT, INSERT, UPDATE or DELETE).
+ * For example the figure shows a #GdauiServerOperation widget set to create an index in an
+ * SQLite database.
+ */
+
 GType             gdaui_server_operation_get_type      (void) G_GNUC_CONST;
 GtkWidget        *gdaui_server_operation_new           (GdaServerOperation *op);
 GtkWidget        *gdaui_server_operation_new_in_dialog (GdaServerOperation *op, GtkWindow *parent,
diff --git a/libgda-ui/gdaui-tree-store.h b/libgda-ui/gdaui-tree-store.h
index ac15664..0a536d6 100644
--- a/libgda-ui/gdaui-tree-store.h
+++ b/libgda-ui/gdaui-tree-store.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2009 - 2011 Vivien Malerba <malerba gnome-db org>
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -56,6 +56,18 @@ struct _GdauiTreeStoreClass
 	gboolean           (*drag_delete)   (GdauiTreeStore *store, const gchar *path);
 };
 
+/**
+ * SECTION:gdaui-tree-store
+ * @short_description: Bridge between a #GdaTree and a #GtkTreeModel
+ * @title: GdauiTreeStore
+ * @stability: Stable
+ * @Image:
+ * @see_also: #GdaTree
+ *
+ * The #GdauiTreeStore implements the #GtkTreeModel interface required
+ * to display data from a #GdaTree in a #GtkTreeView widget.
+ */
+
 GType           gdaui_tree_store_get_type             (void) G_GNUC_CONST;
 
 GtkTreeModel   *gdaui_tree_store_new                  (GdaTree *tree, guint n_columns, ...);
diff --git a/libgda-ui/internal/popup-container.c b/libgda-ui/internal/popup-container.c
index d1420e9..475d0f8 100644
--- a/libgda-ui/internal/popup-container.c
+++ b/libgda-ui/internal/popup-container.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The GNOME Foundation
+ * Copyright (C) 2009 - 2010 The GNOME Foundation
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -66,7 +66,7 @@ delete_popup (G_GNUC_UNUSED GtkWidget *widget, PopupContainer *container)
 static gboolean
 key_press_popup (GtkWidget *widget, GdkEventKey *event, PopupContainer *container)
 {
-        if (event->keyval != GDK_Escape)
+        if (event->keyval != GDK_KEY_Escape)
                 return FALSE;
 
         g_signal_stop_emission_by_name (widget, "key-press-event");
@@ -215,13 +215,8 @@ popup_container_show (GtkWidget *widget)
         if (do_move)
                 gtk_window_move (GTK_WINDOW (widget), root_x, root_y);
 
-#if GTK_CHECK_VERSION(2,18,0)
 	popup_grab_on_window (gtk_widget_get_window (widget),
                               gtk_get_current_event_time ());
-#else
-	popup_grab_on_window (widget->window,
-                              gtk_get_current_event_time ());
-#endif
 }
 
 static void
@@ -269,20 +264,12 @@ popup_position (PopupContainer *container, gint *out_x, gint *out_y)
 
         gtk_widget_size_request (poswidget, &req);
 
-#if GTK_CHECK_VERSION(2,18,0)
 	GtkAllocation alloc;
         gdk_window_get_origin (gtk_widget_get_window (poswidget), &x, &y);
 	gtk_widget_get_allocation (poswidget, &alloc);
         x += alloc.x;
         y += alloc.y;
         y += alloc.height;
-#else
-        gdk_window_get_origin (poswidget->window, &x, &y);
-
-        x += poswidget->allocation.x;
-        y += poswidget->allocation.y;
-        y += poswidget->allocation.height;
-#endif
 
         if (x < 0)
                 x = 0;
diff --git a/libgda-ui/internal/utility.c b/libgda-ui/internal/utility.c
index 5a09d8e..72ca15e 100644
--- a/libgda-ui/internal/utility.c
+++ b/libgda-ui/internal/utility.c
@@ -142,54 +142,30 @@ _gdaui_utility_entry_build_info_colors_array (void)
 	/* Green color */
 	color = g_new0 (GdkColor, 1);
 	gdk_color_parse (GDAUI_COLOR_NORMAL_NULL, color);
-	if (!gdk_colormap_alloc_color (gtk_widget_get_default_colormap (), color, FALSE, TRUE)) {
-		g_free (color);
-		color = NULL;
-	}
 	colors[0] = color;
 	
 	color = g_new0 (GdkColor, 1);
 	gdk_color_parse (GDAUI_COLOR_PRELIGHT_NULL, color);
-	if (!gdk_colormap_alloc_color (gtk_widget_get_default_colormap (), color, FALSE, TRUE)) {
-		g_free (color);
-		color = NULL;
-	}
 	colors[1] = color;
 	
 	
 	/* Blue color */
 	color = g_new0 (GdkColor, 1);
 	gdk_color_parse (GDAUI_COLOR_NORMAL_DEFAULT, color);
-	if (!gdk_colormap_alloc_color (gtk_widget_get_default_colormap (), color, FALSE, TRUE)) {
-		g_free (color);
-		color = NULL;
-	}
 	colors[2] = color;
 	
 	color = g_new0 (GdkColor, 1);
 	gdk_color_parse (GDAUI_COLOR_PRELIGHT_DEFAULT, color);
-	if (!gdk_colormap_alloc_color (gtk_widget_get_default_colormap (), color, FALSE, TRUE)) {
-		g_free (color);
-		color = NULL;
-	}
 	colors[3] = color;
 	
 	
 	/* Red color */
 	color = g_new0 (GdkColor, 1);
 	gdk_color_parse (GDAUI_COLOR_NORMAL_INVALID, color);
-	if (!gdk_colormap_alloc_color (gtk_widget_get_default_colormap (), color, FALSE, TRUE)) {
-		g_free (color);
-		color = NULL;
-	}
 	colors[4] = color;
 	
 	color = g_new0 (GdkColor, 1);
 	gdk_color_parse (GDAUI_COLOR_PRELIGHT_INVALID, color);
-	if (!gdk_colormap_alloc_color (gtk_widget_get_default_colormap (), color, FALSE, TRUE)) {
-		g_free (color);
-		color = NULL;
-	}
 	colors[5] = color;
 
 	return colors;
@@ -440,12 +416,8 @@ create_data_error_dialog (GdauiDataProxy *form, gboolean with_question, gboolean
 		
 		gtk_container_add (GTK_CONTAINER (sw), view);
 		gtk_container_add (GTK_CONTAINER (exp), sw);
-#if GTK_CHECK_VERSION(2,18,0)
 		gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
 				    exp, TRUE, TRUE, 0);
-#else
-		gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), exp, TRUE, TRUE, 0);
-#endif
 		gtk_widget_show_all (exp);
 
 		gtk_window_set_resizable (GTK_WINDOW (dlg), TRUE);
diff --git a/libgda-xslt-4.0.pc.in b/libgda-xslt-5.0.pc.in
similarity index 100%
rename from libgda-xslt-4.0.pc.in
rename to libgda-xslt-5.0.pc.in
diff --git a/libgda-xslt/Makefile.am b/libgda-xslt/Makefile.am
index 53ef962..e5f8589 100644
--- a/libgda-xslt/Makefile.am
+++ b/libgda-xslt/Makefile.am
@@ -1,4 +1,4 @@
-lib_LTLIBRARIES = libgda-xslt-4.0.la
+lib_LTLIBRARIES = libgda-xslt-5.0.la
 
 AM_CPPFLAGS = \
         -I$(top_builddir)/libgda-report \
@@ -12,16 +12,16 @@ AM_CPPFLAGS = \
 gda_xslt_headers = \
         libgda-xslt.h
 
-libgda_xslt_4_0_la_SOURCES =   \
+libgda_xslt_5_0_la_SOURCES =   \
         $(gda_xslt_headers)   \
 	sql_backend.h \
         sqlexslt.c \
 	sql_exslt_internal.c \
 	sql_backend.c
 
-libgda_xslt_4_0_la_LDFLAGS = -version-info $(GDA_CURRENT):$(GDA_REVISION):$(GDA_AGE) $(NO_UNDEFINED)
-libgda_xslt_4_0_la_LIBADD = $(LIBGDA_LIBS) $(LIBXSLT_LIBS)\
-        $(top_builddir)/libgda/libgda-4.0.la
+libgda_xslt_5_0_la_LDFLAGS = -version-info $(GDA_CURRENT):$(GDA_REVISION):$(GDA_AGE) $(NO_UNDEFINED)
+libgda_xslt_5_0_la_LIBADD = $(LIBGDA_LIBS) $(LIBXSLT_LIBS)\
+        $(top_builddir)/libgda/libgda-5.0.la
 
 gdaxsltincludedir=$(includedir)/libgda-$(GDA_ABI_MAJOR_VERSION).$(GDA_ABI_MINOR_VERSION)/libgda-xslt
 gdaxsltinclude_HEADERS=$(gda_xslt_headers)
diff --git a/libgda/.gitignore b/libgda/.gitignore
index 2dba251..47187cf 100644
--- a/libgda/.gitignore
+++ b/libgda/.gitignore
@@ -6,5 +6,5 @@ s-enum-types-h
 gda-enum-types.c
 gda-enum-types.h
 libgda.def
-Gda-4.0.gir
-Gda-4.0.typelib
+Gda-5.0.gir
+Gda-5.0.typelib
diff --git a/libgda/Makefile.am b/libgda/Makefile.am
index 72c7157..8fe6529 100644
--- a/libgda/Makefile.am
+++ b/libgda/Makefile.am
@@ -1,6 +1,6 @@
 QUIET_GEN = $(Q:@= echo ' GEN '$@;)
 
-lib_LTLIBRARIES = libgda-4.0.la
+lib_LTLIBRARIES = libgda-5.0.la
 
 SUBDIRS = sqlite handlers binreloc sql-parser providers-support thread-wrapper
 
@@ -63,7 +63,6 @@ gda_headers = \
 	gda-data-select.h \
 	gda-debug-macros.h \
 	gda-decl.h \
-	gda-easy.h \
 	gda-enums.h \
 	gda-holder.h \
 	gda-lockable.h \
@@ -122,7 +121,6 @@ gda_sources= \
 	gda-data-meta-wrapper.h \
 	gda-data-proxy.c \
 	gda-data-select.c \
-	gda-easy.c \
 	gda-holder.c \
 	gda-init.c \
 	gda-lockable.c \
@@ -215,30 +213,30 @@ libgda_built_headers = gda-marshal.h gda-enum-types.h
 libgda_built_cfiles = gda-enum-types.c
 
 # Don't build the library until we have built the headers that it needs:
-$(OBJECTS) $(libgda_4_0_la_OBJECTS): gda-marshal.c $(libgda_built_headers) $(libgda_built_cfiles) keywords_hash.c
+$(OBJECTS) $(libgda_5_0_la_OBJECTS): gda-marshal.c $(libgda_built_headers) $(libgda_built_cfiles) keywords_hash.c
 
-libgda_4_0_la_SOURCES = \
+libgda_5_0_la_SOURCES = \
 	$(libgda_built_cfiles) \
 	$(libgda_sources)
 
-libgda_4_0_la_LDFLAGS = \
+libgda_5_0_la_LDFLAGS = \
 	-version-info $(GDA_CURRENT):$(GDA_REVISION):$(GDA_AGE) \
 	-export-dynamic $(NO_UNDEFINED) $(LIBTOOL_EXPORT_OPTIONS) \
 	$(GDA_DEBUG_LDFLAGS)
 
-libgda_4_0_la_LIBADD = \
-	sql-parser/libgda_sql_parser-4.0.la \
+libgda_5_0_la_LIBADD = \
+	sql-parser/libgda_sql_parser-5.0.la \
 	providers-support/libgda-psupport.la \
-	handlers/libgda_handlers-4.0.la \
-	binreloc/libgda_binreloc-4.0.la \
+	handlers/libgda_handlers-5.0.la \
+	binreloc/libgda_binreloc-5.0.la \
 	sqlite/libgda-sqlite.la \
-	thread-wrapper/libgda_threadwrapper-4.0.la \
+	thread-wrapper/libgda_threadwrapper-5.0.la \
 	$(LIBGDA_LIBS) \
 	$(GIO_LIBS) $(GNOME_KEYRING_LIBS)
 
 if PLATFORM_WIN32
-libgda_4_0_la_LDFLAGS += -export-symbols $(builddir)/libgda.def
-libgda_4_0_la_DEPENDENCIES = libgda.def
+libgda_5_0_la_LDFLAGS += -export-symbols $(builddir)/libgda.def
+libgda_5_0_la_DEPENDENCIES = libgda.def
 
 libgda.def: libgda.symbols
 	(echo -e EXPORTS; $(CPP) -P $(DEF_FLAGS) - <$(srcdir)/libgda.symbols | sed -e '/^$$/d' -e 's/^/ /' -e 's/G_GNUC_[^ ]*//g' | sort) > libgda.def.tmp && mv libgda.def.tmp libgda.def
@@ -274,7 +272,7 @@ CLEANFILES = $(libgda_built_headers) $(libgda_built_cfiles) \
 dist-hook:
 	cd $(distdir); rm -f $(libgda_built_headers) $(libgda_built_cfiles)
 
-xmldir   = $(datadir)/libgda-4.0
+xmldir   = $(datadir)/libgda-5.0
 xml_DATA = information_schema.xml
 
 DTD_FILES = libgda-array.dtd libgda-paramlist.dtd  libgda-server-operation.dtd
@@ -346,20 +344,18 @@ handlers = \
 	handlers/gda-handler-type.c
 
 introspection_sources = $(gda_sources) \
-	gda-types.c \
-	gda-types.h \
 	$(gda_headers) \
 	$(psupport) \
 	$(threadwrapper) \
 	$(sqlparser) \
 	$(handlers)
-Gda-4.0.gir: $(lib_LTLIBRARIES)
-Gda_4_0_gir_INCLUDES = GObject-2.0 libxml2-2.0
-Gda_4_0_gir_CFLAGS = $(GLOBAL_CFLAGS)
+Gda-5.0.gir: $(lib_LTLIBRARIES)
+Gda_5_0_gir_INCLUDES = GObject-2.0 libxml2-2.0
+Gda_5_0_gir_CFLAGS = $(GLOBAL_CFLAGS)
 
-Gda_4_0_gir_LIBS = $(lib_LTLIBRARIES)
-Gda_4_0_gir_FILES = $(addprefix $(srcdir)/,$(introspection_sources))
-INTROSPECTION_GIRS += Gda-4.0.gir
+Gda_5_0_gir_LIBS = $(lib_LTLIBRARIES)
+Gda_5_0_gir_FILES = $(addprefix $(srcdir)/,$(introspection_sources))
+INTROSPECTION_GIRS += Gda-5.0.gir
 
 girdir = $(datadir)/gir-1.0
 gir_DATA = $(INTROSPECTION_GIRS)
diff --git a/libgda/binreloc/Makefile.am b/libgda/binreloc/Makefile.am
index 1b7b631..c5e5aa3 100644
--- a/libgda/binreloc/Makefile.am
+++ b/libgda/binreloc/Makefile.am
@@ -14,7 +14,7 @@ AM_CPPFLAGS = \
 	-DLIBGDASBIN=\""$(sbindir)"\" \
 	-DLIBGDASYSCONF=\""$(sysconfdir)"\"
 
-noinst_LTLIBRARIES = libgda_binreloc-4.0.la
+noinst_LTLIBRARIES = libgda_binreloc-5.0.la
 
 binreloc_headers = \
 	gda-binreloc.h 
@@ -22,7 +22,7 @@ binreloc_headers = \
 binrelocincludedir=$(includedir)/libgda-$(GDA_ABI_MAJOR_VERSION).$(GDA_ABI_MINOR_VERSION)/libgda
 binrelocinclude_HEADERS=$(binreloc_headers)
 
-libgda_binreloc_4_0_la_SOURCES = \
+libgda_binreloc_5_0_la_SOURCES = \
 	gda-binreloc.c \
 	$(binreloc_headers)
 
diff --git a/libgda/gda-attributes-manager.h b/libgda/gda-attributes-manager.h
index ee6e564..55a30a1 100644
--- a/libgda/gda-attributes-manager.h
+++ b/libgda/gda-attributes-manager.h
@@ -1,5 +1,5 @@
-/* GDA common library
- * Copyright (C) 2008 The GNOME Foundation.
+/*
+ * Copyright (C) 2008 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -49,12 +49,68 @@ void                  gda_attributes_manager_foreach     (GdaAttributesManager *
 
 
 /* possible predefined attribute names for gda_holder_get_attribute() or gda_column_get_attribute() */
-#define GDA_ATTRIBUTE_DESCRIPTION "__gda_attr_descr" /* G_TYPE_STRING */
-#define GDA_ATTRIBUTE_NAME "__gda_attr_name" /* G_TYPE_STRING */
-#define GDA_ATTRIBUTE_NUMERIC_PRECISION "__gda_attr_numeric_precision" /* G_TYPE_INT */
-#define GDA_ATTRIBUTE_NUMERIC_SCALE "__gda_attr_numeric_scale" /* G_TYPE_INT */
-#define GDA_ATTRIBUTE_AUTO_INCREMENT "__gda_attr_autoinc" /* G_TYPE_BOOLEAN */
-#define GDA_ATTRIBUTE_IS_DEFAULT "__gda_attr_is_default" /* G_TYPE_BOOLEAN */
+/**
+ * GDA_ATTRIBUTE_DESCRIPTION:
+ * The corresponding attribute is the description of the object it refers to (value has a G_TYPE_STRING type).
+ */
+#define GDA_ATTRIBUTE_DESCRIPTION "__gda_attr_descr"
+
+/**
+ * GDA_ATTRIBUTE_NAME:
+ * The corresponding attribute is the name of the object it refers to (value has a G_TYPE_STRING type).
+ */
+#define GDA_ATTRIBUTE_NAME "__gda_attr_name"
+
+/**
+ * GDA_ATTRIBUTE_NUMERIC_PRECISION:
+ * The corresponding attribute is the number of significant digits of the object it refers to (value has a G_TYPE_INT type).
+ */
+#define GDA_ATTRIBUTE_NUMERIC_PRECISION "__gda_attr_numeric_precision"
+
+/**
+ * GDA_ATTRIBUTE_NUMERIC_SCALE:
+ * The corresponding attribute is the number of significant digits to the right of the decimal point of the object it refers to (value has a G_TYPE_INT type).
+ */
+#define GDA_ATTRIBUTE_NUMERIC_SCALE "__gda_attr_numeric_scale"
+
+/**
+ * GDA_ATTRIBUTE_AUTO_INCREMENT:
+ * The corresponding attribute specifies if the object it refers to is auto incremented (value has a G_TYPE_BOOLEAN type).
+ */
+#define GDA_ATTRIBUTE_AUTO_INCREMENT "__gda_attr_autoinc"
+
+/**
+ * GDA_ATTRIBUTE_IS_DEFAULT:
+ * The corresponding attribute specifies if the object it refers to has its value to default (value has a G_TYPE_BOOLEAN type).
+ */
+#define GDA_ATTRIBUTE_IS_DEFAULT "__gda_attr_is_default"
+
+
+/**
+ * SECTION:gda-attributes-manager
+ * @short_description: Manager for lists of attributes
+ * @title: Attributes manager
+ * @stability: Stable
+ *
+ * he #GdaAttributesManager manages lists of named values (attributes) for the benefit of
+ * others (objects or resources for which only a pointer is known). It is used internally by &LIBGDA;
+ * whenever an object or a simple structure may have several attributes.
+ *
+ * The features are similar to those of the <link linkend="g-object-set-data">g_object_set_data()</link> and similar
+ * but with the following major differences:
+ * <itemizedlist>
+ *  <listitem><para>it works with GObject objects and also with simple pointers to data</para></listitem>
+ *  <listitem><para>attributes names are considered static (they are not copied) and so they must either be static strings or allocated strings which exist (unchanged) while an attribute uses it as name</para></listitem>
+ *  <listitem><para>it is possible to iterate through the attributes</para></listitem>
+ *  <listitem><para>the associated values are expected to be #GValue values</para></listitem>
+ * </itemizedlist>
+ *
+ * Attibute names can be any string, but &LIBGDA; reserves some for its own usage, see below.
+ *
+ * The #GdaAttributesManager implements its own locking mechanism so it is thread-safe.
+ *
+ * 
+ */
 
 G_END_DECLS
 
diff --git a/libgda/gda-batch.h b/libgda/gda-batch.h
index 8462336..8617476 100644
--- a/libgda/gda-batch.h
+++ b/libgda/gda-batch.h
@@ -1,6 +1,5 @@
-/* gda-batch.h
- *
- * Copyright (C) 2007 - 2009 Vivien Malerba
+/*
+ * Copyright (C) 2007 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -55,6 +54,7 @@ struct _GdaBatchClass
 	/* signals */
 	void   (*changed) (GdaBatch *batch, GdaStatement *changed_stmt);
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
@@ -62,6 +62,19 @@ struct _GdaBatchClass
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-batch
+ * @short_description: Multiple SQL statements grouped together.
+ * @title: GdaBatch
+ * @stability: Stable
+ * @see_also: #GdaStatement
+ *
+ * The #GdaBatch object represents one or more SQL statements (as #GdaStatement objects) in a single object.
+ *
+ * A #GdaBatch can either be built "manually" by assembling together several #GdaStatement objects,
+ * or from an SQL string using a #GdaSqlParser object.
+ */
+
 GType              gda_batch_get_type               (void) G_GNUC_CONST;
 GdaBatch          *gda_batch_new                    (void);
 GdaBatch          *gda_batch_copy                   (GdaBatch *orig);
diff --git a/libgda/gda-blob-op.h b/libgda/gda-blob-op.h
index 01b2e2c..57b38bf 100644
--- a/libgda/gda-blob-op.h
+++ b/libgda/gda-blob-op.h
@@ -1,5 +1,5 @@
-/* GDA Common Library
- * Copyright (C) 2007 - 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 2007 - 2011 The GNOME Foundation.
  *
  * Authors:
  *      Vivien Malerba <malerba gnome-db org>
@@ -52,6 +52,7 @@ struct _GdaBlobOpClass {
 	glong    (* write)      (GdaBlobOp *op, GdaBlob *blob, glong offset);
 	gboolean (* write_all)  (GdaBlobOp *op, GdaBlob *blob);
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
@@ -59,6 +60,74 @@ struct _GdaBlobOpClass {
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-blob-op
+ * @short_description: Binary data and BLOBs handling
+ * @title: Blobs
+ * @stability: Stable
+ * @see_also:
+ *
+ * This object is a base class for individual database providers which support BLOB types. It supports
+ * operations to read and write data in a BLOB value (of type GDA_BLOB_TYPE).
+ *
+ * Libgda offers two methods to manipulate binary values as two containers: <link linkend="GdaBinary">GdaBinary</link>
+ * and <link linkend="GdaBlob">GdaBlob</link>:
+ * <itemizedlist>
+ *  <listitem><para>When reading from a data model returned by &LIBGDA; binary data will often be in a GdaBlob
+ *   object, and the associated <link linkend="GdaBlobOp">GdaBlobOp</link> object can be used to manipulate the
+ *   binary object (in a database for example)</para></listitem>
+ *  <listitem><para>When the binary value is created by the user, then there is no point in using a GdaBlob as
+ *   there can not be any <link linkend="GdaBlobOp">GdaBlobOp</link> object, so the GdaBinary container is
+ *   enough.</para></listitem>
+ * </itemizedlist>
+ *
+ * Note that a <link linkend="GdaBlob">GdaBlob</link> value (the "data" attribute) will often not contain any data
+ * (or only some part of the actual BLOB)
+ * and that it's up to the user to use the associated <link linkend="GdaBlobOp">GdaBlobOp</link> object to
+ * "load" the data into the container (into the actual process heap).
+ *
+ * For example to load the 1st 40 bytes of a blob:
+ *  <programlisting>
+ *GValue *blob_value = ...
+ *GdaBlob *blob;
+ *
+ *blob = (GdaBlob*) gda_value_get_blob (blob_value);
+ *gda_blob_op_read (blob->op, blob, 0, 40);
+ *  </programlisting>
+ *
+ * Another example is to write the contents of a blob to a file on disk, using a special
+ *  <link linkend="GdaBlobOp">GdaBlobOp</link> object (internal to &LIBGDA; which interfaces
+ *  with a file in a filesystem):
+ *  <programlisting>
+ *GValue *blob_value; // value to copy from
+ *GValue *tmp_value;
+ *GdaBlob *file_blob;
+ *
+ *GValue *blob_value = ...
+ *tmp_value = gda_value_new_blob_from_file ("MyFile.bin");
+ *file_blob = (GdaBlob*) gda_value_get_blob (tmp_value);
+ *
+ *if (! gda_blob_op_write_all (file_blob->op, gda_value_get_blob (blob_value))) {
+ *       // error
+ *}
+ *else {
+ *       gsize size;
+ *       size = gda_blob_op_get_length (file_blob->op);
+ *       g_print ("Wrote %s, size = %d\n", filename, size);
+ *}
+ *gda_value_free (tmp_value);
+ *  </programlisting>
+ *
+ * For further information, see:
+ *  <itemizedlist>
+ *    <listitem><para>the section about <link linkend="gen_blobs">Binary large objects (BLOBs)</link>'s
+ *        abstraction</para></listitem>
+ *    <listitem><para><link linkend="libgda-provider-blobop">Virtual methods for Blob operations</link>
+ *        section for more information
+ *        about how to implement the virtual methods when creating a database provider</para></listitem>
+ *  </itemizedlist>
+ */
+
 GType    gda_blob_op_get_type  (void) G_GNUC_CONST;
 
 glong    gda_blob_op_get_length (GdaBlobOp *op);
diff --git a/libgda/gda-column.h b/libgda/gda-column.h
index 175189c..6764127 100644
--- a/libgda/gda-column.h
+++ b/libgda/gda-column.h
@@ -1,5 +1,5 @@
-/* GDA library
- * Copyright (C) 1998 - 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 1998 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Michael Lausch <michael lausch at>
@@ -51,6 +51,7 @@ struct _GdaColumnClass {
 	void (* name_changed)   (GdaColumn *column, const gchar *old_name);
 	void (* g_type_changed) (GdaColumn *column, GType old_type, GType new_type);
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
@@ -58,6 +59,16 @@ struct _GdaColumnClass {
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-column
+ * @short_description: Management of #GdaDataModel column attributes
+ * @title: GdaDataModel columns
+ * @stability: Stable
+ * @see_also: #GdaDataModel
+ *
+ * The #GdaColumn object represents a #GdaDataModel's column and handle all its properties.
+ */
+
 GType           gda_column_get_type           (void) G_GNUC_CONST;
 GdaColumn      *gda_column_new                (void);
 GdaColumn      *gda_column_copy               (GdaColumn *column);
@@ -91,7 +102,7 @@ void            gda_column_set_attribute      (GdaColumn *column, const gchar *a
 					       GDestroyNotify destroy);
 
 /**
- * gda_column_set_attribute_static
+ * gda_column_set_attribute_static:
  * @holder: a #GdaHolder
  * @attribute: attribute's name
  * @value: the value to set the attribute to, or %NULL
diff --git a/libgda/gda-config.c b/libgda/gda-config.c
index 86c03e0..e758d89 100644
--- a/libgda/gda-config.c
+++ b/libgda/gda-config.c
@@ -228,7 +228,7 @@ gda_config_class_init (GdaConfigClass *klass)
 	 *
 	 * File to use for system-wide DSN list. When changed, the whole list of DSN will be reloaded.
 	 */
-	/* To translators: DSN stands for Data Source Name, it's a named connection string defined in $PREFIX/etc/libgda-4.0/config */
+	/* To translators: DSN stands for Data Source Name, it's a named connection string defined in $PREFIX/etc/libgda-5.0/config */
 	g_object_class_install_property (object_class, PROP_USER_FILE,
                                          g_param_spec_string ("system-filename", NULL,
 							      "File to use for system-wide DSN list", 
diff --git a/libgda/gda-config.h b/libgda/gda-config.h
index cf5e86d..55b8d77 100644
--- a/libgda/gda-config.h
+++ b/libgda/gda-config.h
@@ -123,6 +123,50 @@ struct _GdaConfigClass {
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-config
+ * @short_description: Access/Management of libgda configuration
+ * @title: Configuration
+ * @stability: Stable
+ * @see_also:
+ *
+ * The functions in this section allow applications an easy access to libgda's
+ * configuration (the list of data sources and database providers).
+ *
+ * As soon as a <link linkend="GdaConfig">GdaConfig</link> is needed (for example when requesting information
+ * about a data source or about a server provider), a single instance object is created,
+ * and no other will need to be created. A pointer to this object can be obtained with
+ * <link linkend="gda-config-get">gda_config_get()</link>. Of course one can (right after having called
+ * <link linkend="gda-init">gda_init()</link>) force the creation of a GdaConfig object with some
+ * specific properties set, using a simple call like:
+ * <programlisting>
+ *g_object_new (GDA_TYPE_CONFIG, "user-filename", "my_file", NULL);
+ * </programlisting>
+ * Please note that after that call, the caller has a reference to the newly created object, and should technically
+ * call <link linkend="g-object-unref">g_object_unref()</link> when finished using it. It is safe to do this
+ * but also pointless since that object should not be destroyed (as no other will be created) as &LIBGDA; also
+ * keeps a reference for itself.
+ * 
+ *Data sources are defined in a per-user configuration file which is by default <filename>${HOME}/.libgda/config</filename> and
+ * in a system wide configuration file which is by default <filename>${prefix}/etc/libgda-4.0/config</filename>. Those
+ * filenames can be modified by setting the <link linkend="GdaConfig--user-file">user-file</link> and
+ * <link linkend="GdaConfig--system-file">system-file</link> properties for the single <link linkend="GdaConfig">GdaConfig</link>
+ * instance. Note that setting either of these properties to <literal>NULL</literal> will disable using the corresponding
+ * configuration file (DSN will exist only in memory and their definition will be lost when the application finishes).
+ *
+ * The #GdaConfig object implements its own locking mechanism so it is thread-safe.
+ *
+ * Note about localization: when the #GdaConfig loads configuration files, it filters the
+ * contents based on the current locale, so for example if your current locale is "de" then
+ * all the loaded strings (for the ones which are translated) will be in the German language.
+ * Changing the locale afterwards will have no effect on the #GdaConfig and the already loaded
+ * configuration.
+ * The consequence is that you should first call setlocale() youself in your code before using
+ * a #GdaConfig object. As a side note you should also call gtk_init() before gdaui_init() because
+ * gtk_init() calls setlocale().
+ */
+
+
 GType              gda_config_get_type                 (void) G_GNUC_CONST;
 GdaConfig*         gda_config_get                      (void);
 
diff --git a/libgda/gda-connection-event.c b/libgda/gda-connection-event.c
index 24a15e3..3dfc12b 100644
--- a/libgda/gda-connection-event.c
+++ b/libgda/gda-connection-event.c
@@ -1,5 +1,5 @@
-/* GDA server library
- * Copyright (C) 1998 - 2010 The GNOME Foundation.
+/*
+ * Copyright (C) 1998 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Michael Lausch <michael lausch at>
@@ -110,26 +110,6 @@ gda_connection_event_init (GdaConnectionEvent *event, G_GNUC_UNUSED GdaConnectio
 	event->priv->gda_code = GDA_CONNECTION_EVENT_CODE_UNKNOWN;
 }
 
-/**
- * gda_connection_event_new:
- * @type: the type of event
- *
- * Creates a new uninitialized event object. This class is used for communicating
- * events from the different providers to the clients.
- *
- * Returns: the event object.
- *
- * Deprecated: 4.2: use gda_connection_point_available_event() instead
- */
-GdaConnectionEvent *
-gda_connection_event_new (GdaConnectionEventType type)
-{
-	GdaConnectionEvent *event;
-
-	event = GDA_CONNECTION_EVENT (g_object_new (GDA_TYPE_CONNECTION_EVENT, "type", (int)type, NULL));
-	return event;
-}
-
 static void
 gda_connection_event_finalize (GObject *object)
 {
diff --git a/libgda/gda-connection-event.h b/libgda/gda-connection-event.h
index 7b8a1f6..31706f0 100644
--- a/libgda/gda-connection-event.h
+++ b/libgda/gda-connection-event.h
@@ -1,5 +1,5 @@
-/* GDA server library
- * Copyright (C) 1998 - 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 1998 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Michael Lausch <michael lausch at>
@@ -44,6 +44,7 @@ struct _GdaConnectionEvent {
 struct _GdaConnectionEventClass {
 	GObjectClass parent_class;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
@@ -85,8 +86,19 @@ typedef enum
 #define GDA_SQLSTATE_NO_ERROR "00000"
 #define GDA_SQLSTATE_GENERAL_ERROR "HY000"
 
+/**
+ * SECTION:gda-connection-event
+ * @short_description: Any event which has occurred on a #GdaConnection
+ * @title: GdaConnectionEvent
+ * @stability: Stable
+ * @see_also: #GdaConnection
+ *
+ * Events occurring on a connection are each represented as a #GdaConnectionEvent object. Each #GdaConnection
+ * is responsible for keeping a list of past events; that list can be consulted using the 
+ * gda_connection_get_events() function.
+ */
+
 GType                   gda_connection_event_get_type (void) G_GNUC_CONST;
-GdaConnectionEvent     *gda_connection_event_new (GdaConnectionEventType type);
 
 void                    gda_connection_event_set_event_type (GdaConnectionEvent *event, GdaConnectionEventType type);
 GdaConnectionEventType  gda_connection_event_get_event_type (GdaConnectionEvent *event);
diff --git a/libgda/gda-connection.c b/libgda/gda-connection.c
index 48de177..956e714 100644
--- a/libgda/gda-connection.c
+++ b/libgda/gda-connection.c
@@ -1,4 +1,4 @@
-/* GDA library
+/*
  * Copyright (C) 1998 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
@@ -946,7 +946,7 @@ _gda_connection_get_internal_thread_provider (void)
  *
  * The actual named parameters required depend on the provider being used, and that list is available
  * as the <parameter>auth_params</parameter> member of the #GdaProviderInfo structure for each installed
- * provider (use gda_config_get_provider_info() to get it). Also one can use the "gda-sql-4.0 -L" command to 
+ * provider (use gda_config_get_provider_info() to get it). Also one can use the "gda-sql-5.0 -L" command to 
  * list the possible named parameters.
  *
  * This method may fail with a GDA_CONNECTION_ERROR domain error (see the #GdaConnectionError error codes) 
@@ -1075,7 +1075,7 @@ gda_connection_open_from_dsn (const gchar *dsn, const gchar *auth_string,
  * series of &lt;key&gt;=&lt;value&gt; pairs, where each key and value are encoded as per RFC 1738, 
  * see gda_rfc1738_encode() for more information.
  *
- * The possible keys depend on the provider, the "gda-sql-4.0 -L" command
+ * The possible keys depend on the provider, the "gda-sql-5.0 -L" command
  * can be used to list the actual keys for each installed database provider.
  *
  * For example the connection string to open an SQLite connection to a database
@@ -1096,7 +1096,7 @@ gda_connection_open_from_dsn (const gchar *dsn, const gchar *auth_string,
  * The actual named parameters required depend on the provider being used, and that list is available
  * as the <parameter>auth_params</parameter> member of the #GdaProviderInfo structure for each installed
  * provider (use gda_config_get_provider_info() to get it). Similarly to the format of the connection
- * string, use the "gda-sql-4.0 -L" command to list the possible named parameters.
+ * string, use the "gda-sql-5.0 -L" command to list the possible named parameters.
  *
  * Additionally, it is possible to have the connection string
  * respect the "&lt;provider_name&gt;://&lt;real cnc string&gt;" format, in which case the provider name
@@ -1534,7 +1534,8 @@ add_connection_event_from_error (GdaConnection *cnc, GError **error)
 {
 	GdaConnectionEvent *event;
 	gchar *str;
-	event = gda_connection_event_new (GDA_CONNECTION_EVENT_WARNING);
+	event = GDA_CONNECTION_EVENT (g_object_new (GDA_TYPE_CONNECTION_EVENT,
+							  "type", (int)GDA_CONNECTION_EVENT_WARNING, NULL));
 	str = g_strdup_printf (_("Error while maintaining the meta data up to date: %s"),
 			       error && *error && (*error)->message ? (*error)->message : _("No detail"));
 	gda_connection_event_set_description (event, str);
@@ -2264,9 +2265,7 @@ gda_connection_parse_sql_string (GdaConnection *cnc, const gchar *sql, GdaSet **
  * @type: a #GdaConnectionEventType
  *
  * Use this method to get a pointer to the next available connection event which can then be customized
- * and taken into account using gda_connection_add_event(). This method is a drop-in replacament
- * for gda_connection_event_new() which improves performances by reusing as much as possible
- * #GdaConnectionEvent objects. Newly written database providers should use this method.
+ * and taken into account using gda_connection_add_event().
  *
  * Returns: (transfer full) (allow-none): a pointer to the next available connection event, or %NULL if event should
  * be ignored
@@ -2283,7 +2282,8 @@ gda_connection_point_available_event (GdaConnection *cnc, GdaConnectionEventType
 	GdaConnectionEvent *eev;
 	eev = cnc->priv->events_array [cnc->priv->events_array_next];
 	if (!eev)
-		eev = gda_connection_event_new (type);
+		eev = GDA_CONNECTION_EVENT (g_object_new (GDA_TYPE_CONNECTION_EVENT,
+							  "type", (int)type, NULL));
 	else {
 		gda_connection_event_set_event_type (eev, type);
 		cnc->priv->events_array [cnc->priv->events_array_next] = NULL;
@@ -3305,8 +3305,7 @@ gda_connection_statement_execute (GdaConnection *cnc, GdaStatement *stmt, GdaSet
  * @last_insert_row: (out) (transfer full) (allow-none): a place to store a new #GdaSet object which contains the values of the last inserted row, or %NULL
  * @error: a place to store an error, or %NULL
  *
- * Executes a non-selection statement on the given connection. The gda_execute_non_select_command() method can be easier
- * to use if one prefers to use some SQL directly.
+ * Executes a non-selection statement on the given connection.
  *
  * This function returns the number of rows affected by the execution of @stmt, or -1
  * if an error occurred, or -2 if the connection's provider does not return the number of rows affected.
@@ -3375,8 +3374,7 @@ gda_connection_statement_execute_non_select (GdaConnection *cnc, GdaStatement *s
  * @params: (allow-none): a #GdaSet object (which can be obtained using gda_statement_get_parameters()), or %NULL
  * @error: a place to store an error, or %NULL
  *
- * Executes a selection command on the given connection. The gda_execute_select_command() method can be easier
- * to use if one prefers to use some SQL directly.
+ * Executes a selection command on the given connection.
  *
  * This function returns a #GdaDataModel resulting from the SELECT statement, or %NULL
  * if an error occurred.
diff --git a/libgda/gda-connection.h b/libgda/gda-connection.h
index 9a4b75e..cd7c76f 100644
--- a/libgda/gda-connection.h
+++ b/libgda/gda-connection.h
@@ -1,5 +1,5 @@
-/* GDA library
- * Copyright (C) 1998 - 2010 The GNOME Foundation.
+/*
+ * Copyright (C) 1998 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Michael Lausch <michael lausch at>
@@ -62,6 +62,47 @@ typedef enum {
 
 #define GDA_CONNECTION_NONEXIST_DSN_ERROR GDA_CONNECTION_DSN_NOT_FOUND_ERROR
 
+/**
+ * SECTION:gda-connection
+ * @short_description: A connection to a database
+ * @title: GdaConnection
+ * @stability: Stable
+ *
+ * Each connection to a database is represented by a #GdaConnection object. A connection is created (and opened)
+ * using gda_connection_open_from_dsn() if a data source has been defined, or gda_connection_open_from_string()
+ * otherwise. It is not recommended to create a #GdaConnection object using g_object_new() as the results are
+ * unpredictable (some parts won't correctly be initialized).
+ *
+ * Use the connection object to execute statements, use transactions, get meta data information, ...
+ *
+ * If supported by the database provider being used, statements can be executed asynchronously instead of
+ * blocking the execution thread untill the execution of a statement is finished. Each database provider
+ * is free to implement this feature as it wishes (using the API or using threads). The steps involved to
+ * execute a statement are then:
+ * <itemizedlist>
+ *   <listitem><para>Request the statement execution using
+ *	<link linkend="gda-connection-async-statement-execute">gda_connection_async_statement_execute() which returns an
+ *	  execution ID to be used to identify a specific request</link></para></listitem>
+ *   <listitem><para>Do some useful things (that is why async. statements' excution are for)</para></listitem>
+ *   <listitem><para>Use one or more times 
+ *	<link linkend="gda-connection-async-fetch-result">gda_connection_async_fetch_result()</link> to see
+ *	if the execution is finished, using the request ID</para></listitem>
+ *   <listitem><para>Use <link linkend="gda-connection-async-cancel">gda_connection_async_cancel()</link> to cancel
+ * the execution of a statement</para></listitem>
+ * </itemizedlist>
+ *
+ * The #GdaConnection object implements its own locking mechanism so it is thread-safe. However ad some database
+ * providers rely on an API which does not support threads or supports it only partially, the connections
+ * opened using those providers will only be accessible from the thread which created them (any other thread will
+ * be blocked trying to access the connection, use the
+ * <link linkend="gda-lockable-try-lock">gda_lockable_try_lock()</link> method to check it the connection
+ * is usable from a thread).
+ *
+ * If a connection really needs to be accessed by several threads at once, then it is possible to pass the
+ * #GDA_CONNECTION_OPTIONS_THREAD_SAFE flag when opening it. This flag requests that the real connection
+ * be created and really accessed in a <emphasis>private</emphasis> sub thread.
+ */
+
 struct _GdaConnection {
 	GObject               object;
 	GdaConnectionPrivate *priv;
@@ -199,31 +240,6 @@ typedef enum {
 	GDA_CONNECTION_FEATURE_LAST
 } GdaConnectionFeature;
 
-
-/**
- * GdaConnectionSchema
- *
- * Deprecated: 4.2: This was a leftover from the pre 4.0 area
- */
-typedef enum {
-	GDA_CONNECTION_SCHEMA_AGGREGATES,
-	GDA_CONNECTION_SCHEMA_DATABASES,
-	GDA_CONNECTION_SCHEMA_FIELDS,
-	GDA_CONNECTION_SCHEMA_INDEXES,
-	GDA_CONNECTION_SCHEMA_LANGUAGES,
-	GDA_CONNECTION_SCHEMA_NAMESPACES,
-	GDA_CONNECTION_SCHEMA_PARENT_TABLES,
-	GDA_CONNECTION_SCHEMA_PROCEDURES,
-	GDA_CONNECTION_SCHEMA_SEQUENCES,
-	GDA_CONNECTION_SCHEMA_TABLES,
-	GDA_CONNECTION_SCHEMA_TRIGGERS,
-	GDA_CONNECTION_SCHEMA_TYPES,
-	GDA_CONNECTION_SCHEMA_USERS,
-	GDA_CONNECTION_SCHEMA_VIEWS,
-	GDA_CONNECTION_SCHEMA_CONSTRAINTS,
-	GDA_CONNECTION_SCHEMA_TABLE_CONTENTS
-} GdaConnectionSchema;
-
 /**
  * GdaConnectionMetaType:
  * @GDA_CONNECTION_META_NAMESPACES: lists the <link linkend="GdaConnectionMetaTypeGDA_CONNECTION_META_NAMESPACES">namespaces</link> (or schemas for PostgreSQL)
diff --git a/libgda/gda-data-access-wrapper.h b/libgda/gda-data-access-wrapper.h
index 2b55a64..7aee7d1 100644
--- a/libgda/gda-data-access-wrapper.h
+++ b/libgda/gda-data-access-wrapper.h
@@ -1,5 +1,5 @@
-/* GDA common library
- * Copyright (C) 2006 - 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 2006 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -45,6 +45,7 @@ struct _GdaDataAccessWrapper {
 struct _GdaDataAccessWrapperClass {
 	GObjectClass                   parent_class;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
@@ -52,6 +53,17 @@ struct _GdaDataAccessWrapperClass {
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-data-access-wrapper
+ * @short_description: Offers a random access on top of a cursor-only access data model
+ * @title: GdaDataAccessWrapper
+ * @stability: Stable
+ * @see_also: #GdaDataModel
+ *
+ * The #GdaDataAccessWrapper object simply wraps around another #GdaDataModel data model object
+ * and allows data to be accessed in a random way while remaining memory efficient as much as possible.
+ */
+
 GType         gda_data_access_wrapper_get_type    (void) G_GNUC_CONST;
 GdaDataModel *gda_data_access_wrapper_new         (GdaDataModel *model);
 
diff --git a/libgda/gda-data-comparator.h b/libgda/gda-data-comparator.h
index 0001530..2b22f72 100644
--- a/libgda/gda-data-comparator.h
+++ b/libgda/gda-data-comparator.h
@@ -1,6 +1,5 @@
-/* gda-data-comparator.h
- *
- * Copyright (C) 2008 - 2009 Vivien Malerba
+/*
+ * Copyright (C) 2008 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -75,6 +74,7 @@ struct _GdaDataComparatorClass
 	GObjectClass              parent_class;
 	gboolean               (* diff_computed)  (GdaDataComparator *comp, GdaDiff *diff);
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
@@ -82,6 +82,27 @@ struct _GdaDataComparatorClass
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-data-comparator
+ * @short_description: Simple data model's contents comparison
+ * @title: GdaDataComparator
+ * @stability: Stable
+ * @see_also: #GdaDataModel
+ *
+ * The #GdaDataComparator is a simple object which takes two #GdaDataModel objects and compare them.
+ * Actual comparison is performed when the gda_data_comparator_compute_diff() is called; for each
+ * difference found, the <link linkend="GdaDataComparator-diff-computed">diff-computed</link> signal
+ * is emitted (any user installed signal handler which returns FALSE stops the computing process).
+ *
+ * There are some limitations to this object:
+ * <itemizedlist>
+ *   <listitem><para>The data models compared must have the same number and type of columns</para></listitem>
+ *   <listitem><para>The comparison is done column-for-column: one cannot omit columns in the comparison, nor compare
+ *   columns with different positions</para></listitem>
+ * </itemizedlist>
+ */
+
+
 GType             gda_data_comparator_get_type        (void) G_GNUC_CONST;
 GObject          *gda_data_comparator_new             (GdaDataModel *old_model, GdaDataModel *new_model);
 void              gda_data_comparator_set_key_columns (GdaDataComparator *comp, const gint *col_numbers, gint nb_cols);
diff --git a/libgda/gda-data-handler.h b/libgda/gda-data-handler.h
index 6d38061..b1cad67 100644
--- a/libgda/gda-data-handler.h
+++ b/libgda/gda-data-handler.h
@@ -1,6 +1,5 @@
-/* gda-data-handler.h
- *
- * Copyright (C) 2003 - 2006 Vivien Malerba
+/*
+ * Copyright (C) 2003 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -51,6 +50,28 @@ struct _GdaDataHandlerIface
 };
 
 
+/**
+ * SECTION:gda-data-handler
+ * @short_description: Interface which provides data handling (conversions) capabilities
+ * @title: GdaDataHandler
+ * @stability: Stable
+ * @see_also:
+ *
+ * Because data types vary a lot from a DBMS to another, the #GdaDataHandler interface helps
+ * managing data in its various representations, and converting from one to another:
+ * <itemizedlist>
+ *   <listitem><para>as a #GValue which is a generic value container for the C language</para></listitem>
+ *   <listitem><para>as a human readable string</para></listitem>
+ *   <listitem><para>as an SQL string (a string which can be used in SQL statements)</para></listitem>
+ * </itemizedlist>
+ *
+ * For each data type, a corresponding #GdaDataHandler object can be requested using the
+ * <link linkend="gda-data-handler-get-default">gda_data_handler_get_default()</link> function. However, when working
+ * with a specific database provider, it's better to use a #GdaDataHandler which may be specific to the
+ * database provider which will correctly handle each database specifics using
+ * <link linkend="gda-server-provider-get-data-handler-g-type">gda_server_provider_get_data_handler_g_type()</link> or
+ * <link linkend="gda-server-provider-get-data-handler-dbms">gda_server_provider_get_data_handler_dbms()</link>.
+ */
 
 
 GType        gda_data_handler_get_type               (void) G_GNUC_CONST;
diff --git a/libgda/gda-data-meta-wrapper.c b/libgda/gda-data-meta-wrapper.c
index 02b9894..aba4810 100644
--- a/libgda/gda-data-meta-wrapper.c
+++ b/libgda/gda-data-meta-wrapper.c
@@ -494,7 +494,7 @@ _gda_data_meta_wrapper_compute_value (const GValue *value, GdaSqlIdentifierStyle
 		gboolean onechanged = FALSE;
 		for (i = 0; sa[i]; i++) {
 			if (identifier_needs_quotes (sa[i], mode)) {
-				gchar *tmp = gda_sql_identifier_add_quotes (sa[i]);
+				gchar *tmp = gda_sql_identifier_force_quotes (sa[i]);
 				g_free (sa[i]);
 				sa[i] = tmp;
 				onechanged = TRUE;
@@ -507,7 +507,7 @@ _gda_data_meta_wrapper_compute_value (const GValue *value, GdaSqlIdentifierStyle
 
 				if ((reserved_keyword_func && reserved_keyword_func (sa[i])) ||
 				    (! reserved_keyword_func && is_keyword (sa[i]))) {
-					gchar *tmp = gda_sql_identifier_add_quotes (sa[i]);
+					gchar *tmp = gda_sql_identifier_force_quotes (sa[i]);
 					g_free (sa[i]);
 					sa[i] = tmp;
 					onechanged = TRUE;
@@ -522,7 +522,7 @@ _gda_data_meta_wrapper_compute_value (const GValue *value, GdaSqlIdentifierStyle
 	else {
 		if (identifier_needs_quotes (str, mode)) {
 			retval = gda_value_new (G_TYPE_STRING);
-			g_value_take_string (retval, gda_sql_identifier_add_quotes (str));
+			g_value_take_string (retval, gda_sql_identifier_force_quotes (str));
 		}
 		else {
 			gchar *tmp = NULL;
@@ -531,7 +531,7 @@ _gda_data_meta_wrapper_compute_value (const GValue *value, GdaSqlIdentifierStyle
 
 			if ((reserved_keyword_func && reserved_keyword_func (tmp ? tmp : str)) ||
 			    (! reserved_keyword_func && is_keyword (tmp ? tmp : str))) {
-				gchar *tmp2 = gda_sql_identifier_add_quotes (tmp ? tmp : str);
+				gchar *tmp2 = gda_sql_identifier_force_quotes (tmp ? tmp : str);
 				if (tmp)
 					g_free (tmp);
 				tmp = tmp2;
diff --git a/libgda/gda-data-model-array.h b/libgda/gda-data-model-array.h
index 38f0a79..c57839f 100644
--- a/libgda/gda-data-model-array.h
+++ b/libgda/gda-data-model-array.h
@@ -1,5 +1,5 @@
-/* GDA common library
- * Copyright (C) 1998 - 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 1998 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *	Rodrigo Moya <rodrigo gnome-db org>
@@ -47,6 +47,7 @@ struct _GdaDataModelArray {
 struct _GdaDataModelArrayClass {
 	GObjectClass              parent_class;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
@@ -54,6 +55,20 @@ struct _GdaDataModelArrayClass {
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-data-model-array
+ * @short_description: An implementation of #GdaDataModel based on a #GArray
+ * @title: GdaDataModelArray
+ * @stability: Stable
+ * @see_also: #GdaDataModel
+ *
+ * The #GdaDataModelArray object is a data model which internally uses a #GArray to index all its rows (represented
+ * as #GdaRow objects). In this data model, all the data is stored in memory, which can be a memory limitation if the number
+ * of rows is huge.
+ * This type of data model is easy to use to store some temporary data, and has a random access mode (any value can be accessed
+ * at any time without the need for an iterator).
+ */
+
 GType              gda_data_model_array_get_type          (void) G_GNUC_CONST;
 GdaDataModel      *gda_data_model_array_new_with_g_types  (gint cols, ...);
 GdaDataModel      *gda_data_model_array_new               (gint cols);
diff --git a/libgda/gda-data-model-bdb.h b/libgda/gda-data-model-bdb.h
index 49e191f..6591b06 100644
--- a/libgda/gda-data-model-bdb.h
+++ b/libgda/gda-data-model-bdb.h
@@ -1,5 +1,5 @@
-/* GDA common library
- * Copyright (C) 2007 - 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 2007 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -49,6 +49,7 @@ struct _GdaDataModelBdbClass {
 	GSList                *(*create_key_columns)  (GdaDataModelBdb *model);
 	GSList                *(*create_data_columns) (GdaDataModelBdb *model);
 	GValue                *(*get_key_part)        (GdaDataModelBdb *model, 
+
 						       gpointer data, gint length, gint part);
 	GValue                *(*get_data_part)       (GdaDataModelBdb *model,
 						       gpointer data, gint length, gint part);
@@ -58,7 +59,7 @@ struct _GdaDataModelBdbClass {
 	gboolean               (*update_data_part)    (GdaDataModelBdb *model,
 						       gpointer data, gint length, gint part, 
 						       const GValue *value, GError **error);
-
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
@@ -66,6 +67,24 @@ struct _GdaDataModelBdbClass {
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-data-model-bdb
+ * @short_description: GdaDataModel to access Berkeley DB database contents
+ * @title: GdaDataModelBdb
+ * @stability: Stable
+ * @see_also: #GdaDataModel
+ *
+ * The #GdaDataModelBdb object allows to access the contents of a Berkeley DB database as a
+ * #GdaDataModel object.
+ *
+ * By default the resulting GdaDataModel contains only two columns (named "key" and "data") of type
+ * GDA_TYPE_BINARY, but this object can be subclassed to convert the key or data part of a BDB record
+ * into several columns (implement the create_key_columns(), create_data_columns(), get_key_part(), and get_data_part() 
+ * virtual methods).
+ *
+ * Note: this type of data model is available only if the Berkeley DB library was found at compilation time.
+ */
+
 GType         gda_data_model_bdb_get_type     (void) G_GNUC_CONST;
 GdaDataModel *gda_data_model_bdb_new          (const gchar *filename, const gchar *db_name);
 
diff --git a/libgda/gda-data-model-dir.c b/libgda/gda-data-model-dir.c
index 6dd9f4b..36f094c 100644
--- a/libgda/gda-data-model-dir.c
+++ b/libgda/gda-data-model-dir.c
@@ -1,5 +1,5 @@
 /* GDA common library
- * Copyright (C) 2007 - 2010 The GNOME Foundation
+ * Copyright (C) 2007 - 2011 The GNOME Foundation
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -1043,11 +1043,7 @@ gda_data_model_dir_set_values (GdaDataModel *model, gint row, GList *values, GEr
 											   new_filename);
 						}
 					}
-#if GLIB_CHECK_VERSION(2,22,0)
 					g_mapped_file_unref (old_file);
-#else
-					g_mapped_file_free (old_file);
-#endif
 				}
 				if (!allok) {
 					gchar *str;
diff --git a/libgda/gda-data-model-dir.h b/libgda/gda-data-model-dir.h
index b3290a5..60fe792 100644
--- a/libgda/gda-data-model-dir.h
+++ b/libgda/gda-data-model-dir.h
@@ -1,5 +1,5 @@
-/* GDA common library
- * Copyright (C) 2007 - 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 2007 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -45,6 +45,7 @@ struct _GdaDataModelDir {
 struct _GdaDataModelDirClass {
 	GObjectClass            parent_class;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
@@ -52,6 +53,28 @@ struct _GdaDataModelDirClass {
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-data-model-dir
+ * @short_description: GdaDataModel to list files in filesystem
+ * @title: GdaDataModelDir
+ * @stability: Stable
+ * @see_also: #GdaDataModel
+ *
+ * The #GdaDataModelDir object lists files on a filesystem which are located
+ * below a "basedir" directory, one file per row. The data model has the following columns:
+ * <itemizedlist>
+ *   <listitem><para>the "dir_name" column (G_TYPE_STRING): contains the dirname part of the file</para></listitem>
+ *   <listitem><para>the "file_name" column (G_TYPE_STRING): contains the file name part of the file</para></listitem>
+ *   <listitem><para>the "size" column (G_TYPE_UINT): contains the size in bytes of the file</para></listitem>
+ *   <listitem><para>the "mime_type" column (G_TYPE_STRING): contains the mime type of the file (if GnomeVFS has been found, and NULL otherwise)</para></listitem>
+ *   <listitem><para>the "md5sum" column (G_TYPE_STRING): contains the MD5 hash of each file (if LibGCrypt has been found, and NULL otherwise)</para></listitem>
+ *   <listitem><para>the "data" column (GDA_TYPE_BLOB): contains the contents of each file</para></listitem>
+ * </itemizedlist>
+ *
+ * Note that the actual values of the "mime_type", "md5sum" and "data" columns are computed only when they
+ *  are requested to help with performances.
+ */
+
 GType         gda_data_model_dir_get_type     (void) G_GNUC_CONST;
 GdaDataModel *gda_data_model_dir_new          (const gchar *basedir);
 
diff --git a/libgda/gda-data-model-import.h b/libgda/gda-data-model-import.h
index 2334213..6c13b7a 100644
--- a/libgda/gda-data-model-import.h
+++ b/libgda/gda-data-model-import.h
@@ -1,5 +1,5 @@
-/* GDA common library
- * Copyright (C) 2006 - 2010 The GNOME Foundation.
+/*
+ * Copyright (C) 2006 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -55,6 +55,37 @@ struct _GdaDataModelImportClass {
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-data-model-import
+ * @short_description: Importing data from a string or a file
+ * @title: GdaDataModelImport
+ * @stability: Stable
+ * @see_also: #GdaDataModel
+ *
+ * The #GdaDataModelImport data model imports data from a string or a file. The data can either be
+ * in a CSV (comma separated values) format or in an XML format as described by the libgda-array.dtd DTD (as a side
+ * way it is also possible to import data from an already-build XML tree validated against that DTD).
+ *
+ * The caller must decide, upon construction, if the new #GdaDataModelImport must support random access or simply
+ * a cursor based access. Random access makes it easier to use the resulting data model but consumes more memory as
+ * all the data is copied in memory, and is thus not suitable for large data sets. Note that importing from an 
+ * already-build XML tree will always result in a random access data model.
+ *
+ * Various import options can be specified using parameters in a #GdaParameterList object. The available options
+ * depend on the format of the imported data listed here:
+ * <itemizedlist>
+ *   <listitem><para>"SEPARATOR" (string, CVS import only): specifies the separator to consider</para></listitem>
+ *   <listitem><para>"ESCAPE_CHAR" (string, CVS import only): specifies the character used to "escape" the strings
+ *       contained between two separators</para></listitem>
+ *   <listitem><para>"ENCODING" (string, CVS import only): specifies the character set used in the imported data</para></listitem>
+ *   <listitem><para>"TITLE_AS_FIRST_LINE" (boolean, CVS import only): TRUE to specify that the first line of the 
+ *       imported data contains the column names</para></listitem>
+ *   <listitem><para>"G_TYPE_&lt;col number&gt;" (GType, CVS import only): specifies the requested GType type for the column
+ * 	numbered "col number"</para></listitem>
+ * </itemizedlist>
+ */
+
+
 GType         gda_data_model_import_get_type     (void) G_GNUC_CONST;
 GdaDataModel *gda_data_model_import_new_file     (const gchar *filename, gboolean random_access, GdaSet *options);
 GdaDataModel *gda_data_model_import_new_mem      (const gchar *data, gboolean random_access, GdaSet *options);
diff --git a/libgda/gda-data-model-iter.h b/libgda/gda-data-model-iter.h
index cf19457..dfae94d 100644
--- a/libgda/gda-data-model-iter.h
+++ b/libgda/gda-data-model-iter.h
@@ -1,6 +1,5 @@
-/* gda-data-model-iter.h
- *
- * Copyright (C) 2005 - 2009 Vivien Malerba
+/*
+ * Copyright (C) 2005 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -58,6 +57,7 @@ struct _GdaDataModelIterClass
 	void                    (* row_changed)      (GdaDataModelIter *iter, gint row);
 	void                    (* end_of_data)      (GdaDataModelIter *iter);
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
@@ -65,6 +65,50 @@ struct _GdaDataModelIterClass
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-data-model-iter
+ * @short_description: Data model iterator
+ * @title: GdaDataModelIter
+ * @stability: Stable
+ * @see_also: #GdaDataModel
+ *
+ * A #GdaDataModelIter object is used to iterate through the rows of a #GdaDataModel. If the data model is accessible
+ * in a random access way then any number of #GdaDataModelIter objects can be created on the same data model, and
+ * if the data model only supports a cursor based access then only one #GdaDataModelIter can be created. In any case
+ * creating a #GdaDataModelIter should be done using the gda_data_model_create_iter() method. Note that if 
+ * the data model only supports a cursor based access, then calling this method several times will always return
+ * the same #GdaDataModelIter, but with its reference count increased by 1 (so you should call g_object_unref() when
+ * finished with it).
+ *
+ * When a #GdaDataModelIter is valid (that is when it points to an existing row in the data model it iterates through),
+ * the individual values (corresponding to each column of the data model, at the pointer row) can be accessed 
+ * using the gda_data_model_iter_get_value_at() or gda_data_model_iter_get_value_for_field() methods
+ * (or in the same way #GdaSet's values are accessed as #GdaDataModelIter inherits the #GdaSet).
+ *
+ * Right after being created, a #GdaDataModelIter is invalid (does not point to any row of its data model). To read the
+ * first row of the data model, use the gda_data_model_iter_move_next() method. Calling this method several times will
+ * move the iterator forward, up to when the data model has no more rows and the #GdaDataModelIter will be declared invalid
+ * (and gda_data_model_iter_move_next() has returned FALSE). Note that at this point, the number of rows in the data
+ * model will be known.
+ *
+ * If the data model supports it, a #GdaDataModelIter can be moved backwards using the gda_data_model_iter_move_prev()
+ * method. However if the iterator is invalid, moving backwards will not be possible (on the contrary to 
+ * gda_data_model_iter_move_next() which moves to the first row).
+ *
+ * The gda_data_model_iter_move_to_row() method, if the iterator can be moved both forward and backwards, can move the 
+ * iterator to a specific row (sometimes faster than moving it forward or backwards a number of times).
+ *
+ * The following figure illustrates the #GdaDataModelIter usage:
+ * <mediaobject>
+ *   <imageobject role="html">
+ *     <imagedata fileref="GdaDataModelIter.png" format="PNG" contentwidth="190mm"/>
+ *   </imageobject>
+ *   <textobject>
+ *     <phrase>GdaDataModelIter's usage</phrase>
+ *   </textobject>
+ * </mediaobject>
+ */
+
 GType             gda_data_model_iter_get_type             (void) G_GNUC_CONST;
 
 const GValue     *gda_data_model_iter_get_value_at         (GdaDataModelIter *iter, gint col);
diff --git a/libgda/gda-data-model.c b/libgda/gda-data-model.c
index 2f7c4b2..ce01fa0 100644
--- a/libgda/gda-data-model.c
+++ b/libgda/gda-data-model.c
@@ -2199,14 +2199,13 @@ real_gda_data_model_dump_as_string (GdaDataModel *model, gboolean dump_attribute
 #ifndef G_OS_WIN32
 	char *current_locale;
 	int utf8_mode;
-	current_locale = setlocale (LC_ALL, "");
-	utf8_mode = (strcmp (nl_langinfo(CODESET), "UTF-8") == 0);
+	current_locale = setlocale (LC_ALL, NULL);
+	utf8_mode = (strcmp (nl_langinfo (CODESET), "UTF-8") == 0);
 	if (utf8_mode) {
 		sep_col = " â?? ";
 		sep_fill = "â??";
 		sep_row = "â??â?¼â??";
 	}
-	setlocale (LC_ALL, current_locale);
 #endif
 #endif
 
@@ -2475,10 +2474,7 @@ real_gda_data_model_dump_as_string (GdaDataModel *model, gboolean dump_attribute
 			g_strfreev (cols_str [i]);
 		g_free (cols_str);
 	}
-	if (n_rows < 0)
-		g_string_append_printf (string, _("(error getting data)\n"));
-	else
-		g_string_append_printf (string, ngettext("(%d row)\n", "(%d rows)\n", n_rows), n_rows);
+	g_string_append_printf (string, ngettext("(%d row)\n", "(%d rows)\n", n_rows), n_rows);
 
  out:
 	if (ramodel)
diff --git a/libgda/gda-data-model.h b/libgda/gda-data-model.h
index 2695fdc..b7622b7 100644
--- a/libgda/gda-data-model.h
+++ b/libgda/gda-data-model.h
@@ -1,5 +1,5 @@
-/* GDA common library
- * Copyright (C) 1998 - 2008 The GNOME Foundation.
+/*
+ * Copyright (C) 1998 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *	Rodrigo Moya <rodrigo gnome-db org>
@@ -119,6 +119,45 @@ struct _GdaDataModelIface {
 	void                 (* reset)              (GdaDataModel *model);
 };
 
+/**
+ * SECTION:gda-data-model
+ * @short_description: Data model interface
+ * @title: GdaDataModel
+ * @stability: Stable
+ * @see_also: #GdaDataModelIter
+ *
+ * A #GdaDataModel represents an array of values organized in rows and columns. All the data in the same 
+ * column have the same type, and all the data in each row have the same semantic meaning. The #GdaDataModel is
+ * actually an interface implemented by other objects to support various kinds of data storage and operations.
+ *
+ * Depending on the real implementation, the contents of data models may be modified by the user using functions
+ * provided by the model. The actual operations a data model permits can be known using the 
+ * gda_data_model_get_access_flags() method.
+ *
+ * Again, depending on the real implementation, data retrieving can be done either accessing direct random
+ * values located by their row and column, or using a cursor, or both. Use the gda_data_model_get_access_flags() 
+ * method to know how the data model can be accessed. 
+ * <itemizedlist>
+ *   <listitem><para>Random access to a data model's contents is done using gda_data_model_get_value_at(), or using
+ *       one or more #GdaDataModelIter object(s);</para></listitem>
+ *   <listitem><para>Cursor access to a data model's contents is done using a #GdaDataModelIter object (only one can be created),
+ *       it is <emphasis>not possible</emphasis> to use gda_data_model_get_value_at() in this mode.</para></listitem>
+ * </itemizedlist>
+ *
+ * Random access data models are easier to use since picking a value is very simple using the gda_data_model_get_value_at(),
+ * but consume more memory since all the accessible values must generally be present in memory even if they are not used.
+ * Thus if a data model must handle large quantities of data, it is generally wiser to use a data model which can be 
+ * only accessed using a cursor.
+ *
+ * As a side note there are also data models which wrap other data models such as:
+ * <itemizedlist>
+ *     <listitem><para>The #GdaDataProxy data model which stores temporary modifications and shows only some
+ * 	parts of the wrapped data model</para></listitem>
+ *     <listitem><para>The #GdaDataAccessWrapper data model which offers a memory efficient random access on top of a
+ * 	wrapped cursor based access data model</para></listitem>
+ * </itemizedlist>
+ */
+
 GType               gda_data_model_get_type               (void) G_GNUC_CONST;
 
 GdaDataModelAccessFlags gda_data_model_get_access_flags   (GdaDataModel *model);
diff --git a/libgda/gda-data-proxy.c b/libgda/gda-data-proxy.c
index c38eba7..3c1b8cd 100644
--- a/libgda/gda-data-proxy.c
+++ b/libgda/gda-data-proxy.c
@@ -144,7 +144,7 @@ typedef struct
 {
 	RowModif      *row_modif;    /* RowModif in which this structure instance appears */
 	gint           model_column; /* column index in the GdaDataModel */
-        GValue        *value;        /* can also be GDA_TYPE_LIST for multiple values; values are owned here */
+        GValue        *value;        /* values are owned here */
         GValue        *attributes;   /* holds flags of GdaValueAttribute */
 } RowValue;
 #define ROW_VALUE(x) ((RowValue *)(x))
diff --git a/libgda/gda-data-proxy.h b/libgda/gda-data-proxy.h
index f1c7fe2..516a62d 100644
--- a/libgda/gda-data-proxy.h
+++ b/libgda/gda-data-proxy.h
@@ -1,6 +1,5 @@
-/* gda-data-proxy.h
- *
- * Copyright (C) 2005 - 2009 Vivien Malerba
+/*
+ * Copyright (C) 2005 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -70,6 +69,7 @@ struct _GdaDataProxyClass
 
 	void                 (* filter_changed)       (GdaDataProxy *proxy);
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
@@ -77,6 +77,108 @@ struct _GdaDataProxyClass
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-data-proxy
+ * @short_description: Proxy to hold modifications for any #GdaDataModel, providing the #GdaDataModel interface itself
+ * @title: GdaDataProxy
+ * @stability: Stable
+ * @see_also: #GdaDataModel
+ *
+ * This object stores modifications to be made to a #GdaDataModel object which is proxied until the modifications are actually
+ *  written to the #GdaDataModel, it can also filter the proxied data model to show only a subset (a defined number of continuous
+ *  rows or by a filter to apply).
+ *
+ *  Specifically, for a proxied data model having <varname>nb_cols</varname> columns and <varname>nb_rows</varname> rows, 
+ *  the #GdaDataProxy object has the following attributes:
+ *  <itemizedlist>
+ *    <listitem>
+ *      <para><varname>2 * nb_cols</varname> columns:
+ *	<itemizedlist>
+ *	  <listitem><para>the first (&gt;= 0) <varname>nb_cols</varname> columns are the current values stored in the 
+ *	      proxy (which correspond to the values of the proxied data model if the considered row has not been 
+ *	      changed). The associated values are writable.</para></listitem>
+ *	  <listitem><para>the last <varname>nb_cols</varname> columns are the values stored in the proxied data model, 
+ *	      at column <varname>col - nb_cols</varname></para></listitem>
+ *	</itemizedlist>
+ *      </para>
+ *    </listitem>
+ *    <listitem><para>a variable number of rows depending on the following attributes:
+ *	<itemizedlist>
+ *	  <listitem><para>if the proxy is configured to have an empty row as the first row</para></listitem>
+ *	  <listitem><para>if the proxy only displays parts of the proxied data model</para></listitem>
+ *	  <listitem><para>if new rows have been added to the proxy</para></listitem>
+ *	</itemizedlist>
+ *    </para></listitem>
+ *  </itemizedlist>
+ *  This situation is illustrated in the following schema, where there is a direct mapping between the proxy's
+ *  rows and the proxied data model's rows:
+ *  <mediaobject>
+ *    <imageobject role="html">
+ *      <imagedata fileref="data_proxy1.png" format="PNG" contentwidth="170mm"/>
+ *    </imageobject>
+ *    <textobject>
+ *      <phrase>GdaDataProxy's values mapping regarding the proxied data model</phrase>
+ *    </textobject>
+ *  </mediaobject>
+ *
+ *  Note that unless explicitly mentioned, the columns are read-only.
+ *
+ *  The following figures illustrate row mappings between the data proxy and the proxied data model in 
+ *  several situations (which can be combined, but are shown alone for simplicity):
+ *  <itemizedlist>
+ *    <listitem><para>situation where rows 1 and 5 have been marked as deleted from the data proxy, using
+ *	<link linkend="gda-data-proxy-delete">gda_data_proxy_delete()</link> method, the data
+ *	proxy has 2 rows less than the proxied data model:
+ *	<mediaobject>
+ *	  <imageobject role="html">
+ *	    <imagedata fileref="data_proxy2.png" format="PNG" contentwidth="100mm"/>
+ *	  </imageobject>
+ *	  <textobject>
+ *	    <phrase>GdaDataProxy with 2 rows marked as deleted</phrase>
+ *	  </textobject>
+ *	</mediaobject>
+ *    </para></listitem>
+ *    <listitem><para>situation where the data proxy only shows a sample of the proxied data model
+ *	at any given time, using the 
+ *	<link linkend="gda-data-proxy-set-sample-size">gda_data_proxy_set_sample_size()</link> method
+ *	(the sample here is 4 rows wide, and starts at row 3):
+ *	<mediaobject>
+ *	  <imageobject role="html">
+ *	    <imagedata fileref="data_proxy3.png" format="PNG" contentwidth="100mm"/>
+ *	  </imageobject>
+ *	  <textobject>
+ *	    <phrase>GdaDataProxy with a sample size of 4</phrase>
+ *	  </textobject>
+ *	</mediaobject>
+ *    </para></listitem>
+ *    <listitem><para>situation where the data proxy shows a row of NULL values, using the
+ *	<link linkend="GdaDataproxy-prepend-null-entry">"prepend-null-entry"</link> property:
+ *	<mediaobject>
+ *	  <imageobject role="html">
+ *	    <imagedata fileref="data_proxy4.png" format="PNG" contentwidth="100mm"/>
+ *	  </imageobject>
+ *	  <textobject>
+ *	    <phrase>GdaDataProxy with an extra row of NULL values</phrase>
+ *	  </textobject>
+ *	</mediaobject>
+ *    </para></listitem>
+ *    <listitem><para>situation where a row has been added to the data proxy, using for example the
+ *	<link linkend="gda-data-model-append-row">gda_data_model_append_row()</link> method:
+ *	<mediaobject>
+ *	  <imageobject role="html">
+ *	    <imagedata fileref="data_proxy5.png" format="PNG" contentwidth="100mm"/>
+ *	  </imageobject>
+ *	  <textobject>
+ *	    <phrase>GdaDataProxy where a row has been added</phrase>
+ *	  </textobject>
+ *	</mediaobject>
+ *    </para></listitem>
+ *  </itemizedlist>
+ *
+ *  The #GdaDataProxy objects are thread safe, which means any proxy object can be used from
+ *  any thread at the same time as they implement their own locking mechanisms.
+ */
+
 GType             gda_data_proxy_get_type                 (void) G_GNUC_CONST;
 GObject          *gda_data_proxy_new                      (GdaDataModel *model);
 
diff --git a/libgda/gda-data-select.c b/libgda/gda-data-select.c
index f14357d..ae8dca6 100644
--- a/libgda/gda-data-select.c
+++ b/libgda/gda-data-select.c
@@ -3178,7 +3178,7 @@ compute_insert_select_params_mapping (GdaSet *sel_params, GdaSet *ins_values, Gd
 		}
 		g_assert (cdata.colid);
 		if ((*(cdata.colid) == '"') || (*(cdata.colid) == '`'))
-			gda_sql_identifier_remove_quotes ((gchar*) cdata.colid);
+			gda_sql_identifier_prepare_for_compare ((gchar*) cdata.colid);
 		/*g_print ("SEL param '%s' <=> column named '%s'\n", cdata.hid, cdata.colid);*/
 		
 		GSList *ins_list;
diff --git a/libgda/gda-data-select.h b/libgda/gda-data-select.h
index a25f65a..d748b4a 100644
--- a/libgda/gda-data-select.h
+++ b/libgda/gda-data-select.h
@@ -1,5 +1,5 @@
-/* GDA common library
- * Copyright (C) 2008 - 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 2008 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -62,6 +62,7 @@ struct _GdaDataSelect {
 	gint              nb_stored_rows; /* number of GdaRow objects currently stored */
 	gint              advertized_nrows; /* set when the number of rows becomes known, -1 untill then */
 
+	/*< private >*/
 	/* Padding for future expansion */
 	gpointer _gda_reserved1;
 	gpointer _gda_reserved2;
@@ -94,6 +95,7 @@ struct _GdaDataSelectClass {
 	gboolean         (*fetch_prev)    (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error);
 	gboolean         (*fetch_at)      (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error);
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
@@ -101,6 +103,39 @@ struct _GdaDataSelectClass {
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-data-select
+ * @short_description: Base class for data models returned by the execution of a SELECT statement
+ * @title: GdaDataSelect
+ * @stability: Stable
+ * @see_also: #GdaDataModel and the <link linkend="data-select">Advanced GdaDataSelect usage</link> section.
+ *
+ * This data model implements the <link linkend="GdaDataModel">GdaDataModel</link> interface and is the required
+ *  base object when database providers implement a data model returned when a SELECT statement has been executed.
+ *  As the <link linkend="GdaDataModel">GdaDataModel</link> interface is implemented, consult the API
+ *  to access and modify the data held in a <link linkend="GdaDataSelect">GdaDataSelect</link> object.
+ *
+ *  The default behaviour however is to disallow modifications, and this section documents how to characterize
+ *  a <link linkend="GdaDataSelect">GdaDataSelect</link> to allow modifications. Once this is done, any modification
+ *  done to the data model will be propagated to the modified table in the database using INSERT, UPDATE or DELETE
+ *  statements.
+ *
+ *  After any modification, it is still possible to read values from the data model (even values for rows which have
+ *  been modified or inserted). The data model might then execute some SELECT statement to fetch some actualized values.
+ *  Note: there is a corner case where a modification made to a row would make the row not selected at first in the data model
+ *  (for example is the original SELECT statement included a clause <![CDATA["WHERE id < 100"]]> and the modification sets the 
+ *  <![CDATA["id"]]> value to 110), then the row will still be in the data model even though it would not be if the SELECT statement
+ *  which execution created the data model in the first place was re-run. This is illustrated in the schema below:
+ *  <mediaobject>
+ *    <imageobject role="html">
+ *      <imagedata fileref="writable_data_model.png" format="PNG" contentwidth="100mm"/>
+ *    </imageobject>
+ *    <textobject>
+ *      <phrase>GdaDataSelect data model's contents after some modifications</phrase>
+ *    </textobject>
+ *  </mediaobject>
+ */
+
 GType          gda_data_select_get_type                     (void) G_GNUC_CONST;
 
 gboolean       gda_data_select_set_row_selection_condition     (GdaDataSelect *model, GdaSqlExpr *expr, GError **error);
diff --git a/libgda/gda-enums.h b/libgda/gda-enums.h
index 543f817..0765f98 100644
--- a/libgda/gda-enums.h
+++ b/libgda/gda-enums.h
@@ -46,6 +46,13 @@ typedef enum  {
 } GdaValueAttribute;
 
 /* how SQL identifiers are represented */
+/**
+ * GdaSqlIdentifierStyle
+ * @GDA_SQL_IDENTIFIERS_LOWER_CASE: case insensitive SQL identifiers are represented in lower case (meaning that any SQL identifier which has a non lower case character is case sensitive)
+ * @GDA_SQL_IDENTIFIERS_UPPER_CASE: case insensitive SQL identifiers are represented in upper case (meaning that any SQL identifier which has a non upper case character is case sensitive)
+ *
+ * Specifies how SQL identifiers are represented by a specific database
+ */
 typedef enum {
 	GDA_SQL_IDENTIFIERS_LOWER_CASE = 1 << 0,
 	GDA_SQL_IDENTIFIERS_UPPER_CASE = 1 << 1
diff --git a/libgda/gda-holder.h b/libgda/gda-holder.h
index 3ead1a6..b78dc3a 100644
--- a/libgda/gda-holder.h
+++ b/libgda/gda-holder.h
@@ -1,6 +1,5 @@
-/* gda-holder.h
- *
- * Copyright (C) 2003 - 2009 Vivien Malerba
+/*
+ * Copyright (C) 2003 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -67,6 +66,20 @@ struct _GdaHolderClass
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-holder
+ * @short_description: Container for a single #GValue
+ * @title: GdaHolder
+ * @stability: Stable
+ * @see_also: The #GdaSet object which "groups" several #GdaHolder objects 
+ *
+ * The #GdaHolder is a container for a single #GValue value. It also specifies various attributes
+ * of the contained value (default value, ...)
+ *
+ * The type of a #GdaHolder has to be set and cannot be modified, except if it's initialized
+ * with a GDA_TYPE_NULL GType (representing NULL values) where it can be changed once to a real GType.
+ */
+
 GType               gda_holder_get_type                (void) G_GNUC_CONST;
 GdaHolder          *gda_holder_new                     (GType type);
 GdaHolder          *gda_holder_new_inline              (GType type, const gchar *id, ...);
diff --git a/libgda/gda-init.c b/libgda/gda-init.c
index ef89a35..1e537f8 100644
--- a/libgda/gda-init.c
+++ b/libgda/gda-init.c
@@ -154,8 +154,6 @@ gda_init (void)
 	g_assert (type);
 	type = GDA_TYPE_GEOMETRIC_POINT;
 	g_assert (type);
-	type = GDA_TYPE_LIST;
-	g_assert (type);
 	type = GDA_TYPE_NUMERIC;
 	g_assert (type);
 	type = GDA_TYPE_SHORT;
@@ -251,8 +249,8 @@ gda_init (void)
  *
  * Find the path to the application identified by @app_name. For example if the application
  * is "gda-sql", then calling this function will return
- * "/your/prefix/bin/gda-sql-4.0" if Libgda is installed in
- * the "/your/prefix" prefix (which would usually be "/usr"), and for the ABI version 4.0.
+ * "/your/prefix/bin/gda-sql-5.0" if Libgda is installed in
+ * the "/your/prefix" prefix (which would usually be "/usr"), and for the ABI version 5.0.
  *
  * Returns: the path as a new string, or %NULL if the application cannot be found
  */
diff --git a/libgda/gda-lockable.h b/libgda/gda-lockable.h
index a803729..da82d06 100644
--- a/libgda/gda-lockable.h
+++ b/libgda/gda-lockable.h
@@ -1,5 +1,5 @@
-/* GDA common library
- * Copyright (C) 2008 The GNOME Foundation.
+/*
+ * Copyright (C) 2008 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -45,6 +45,18 @@ struct _GdaLockableIface {
 	void                 (* i_unlock)     (GdaLockable *lock);
 };
 
+/**
+ * SECTION:gda-lockable
+ * @short_description: Interface for locking objects in a multi threaded environment
+ * @title: GdaLockable
+ * @stability: Stable
+ * @see_also: #GdaMutex and #GMutex
+ *
+ * This interface is implemented by objects which are thread safe (ie. can be used by several threads at
+ * the same time). Before using an object from a thread, one has to call gda_lockable_lock() or
+ * gda_lockable_trylock() and call gda_lockable_unlock() when the object is not used anymore.
+ */
+
 GType      gda_lockable_get_type   (void) G_GNUC_CONST;
 
 void       gda_lockable_lock       (GdaLockable *lockable);
diff --git a/libgda/gda-log.h b/libgda/gda-log.h
index 87c9e04..f9711cf 100644
--- a/libgda/gda-log.h
+++ b/libgda/gda-log.h
@@ -1,5 +1,5 @@
-/* GDA Common Library
- * Copyright (C) 1998 - 2002 The GNOME Foundation.
+/*
+ * Copyright (C) 1998 - 2011 The GNOME Foundation.
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -25,6 +25,16 @@
 
 G_BEGIN_DECLS
 
+/**
+ * SECTION:gda-log
+ * @short_description: Log functions
+ * @title: Logging
+ * @stability: Stable
+ * @see_also:
+ *
+ * Logging functions.
+ */
+
 /*
  * For application generating logs
  */
diff --git a/libgda/gda-meta-store.c b/libgda/gda-meta-store.c
index a4b0b91..420b2e0 100644
--- a/libgda/gda-meta-store.c
+++ b/libgda/gda-meta-store.c
@@ -3916,7 +3916,7 @@ gda_meta_store_schema_remove_custom_object (GdaMetaStore *store, const gchar *ob
 }
 
 /*
- * Makes sure @context is well formed, and call gda_sql_identifier_remove_quotes() on SQL
+ * Makes sure @context is well formed, and call gda_sql_identifier_prepare_for_compare() on SQL
  * identifiers's values
  *
  * Returns: a new #GdaMetaContext
@@ -3983,7 +3983,7 @@ _gda_meta_store_validate_context (GdaMetaStore *store, GdaMetaContext *context,
 							else if (G_VALUE_TYPE (context->column_values [i]) == G_TYPE_STRING) {
 								gchar *id;
 								id = g_value_dup_string (context->column_values [i]);
-								gda_sql_identifier_remove_quotes (id);
+								gda_sql_identifier_prepare_for_compare (id);
 								if (store->priv->ident_style == GDA_SQL_IDENTIFIERS_UPPER_CASE) {
 									/* move to upper case */
 									gchar *ptr;
diff --git a/libgda/gda-meta-store.h b/libgda/gda-meta-store.h
index 8523e48..816d9a4 100644
--- a/libgda/gda-meta-store.h
+++ b/libgda/gda-meta-store.h
@@ -1,5 +1,4 @@
-/* gda-meta-store.h
- *
+/*
  * Copyright (C) 2008 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
@@ -69,7 +68,17 @@ typedef struct {
 	                               * value = a GValue pointer */
 } GdaMetaStoreChange;
 
-/* suggestion */
+/**
+ * GdaMetaContext:
+ * @table_name: the name of the table <emphasis>in the GdaMetaStore's internal database</emphasis>
+ * @size: the size of the @column_names and @column_values arrays
+ * @column_names: an array of column names (columns of the @table_name table)
+ * @column_values: an array of values, one for each column named in @column_names
+ *
+ * The <structname>GdaMetaContext</structname> represents a meta data modification
+ * context: the <emphasis>how</emphasis> when used with gda_meta_store_modify_with_context(),
+ * and the <emphasis>what</emphasis> when used with gda_connection_update_meta_store().
+ */
 typedef struct {
 	gchar                  *table_name;
 	gint                    size;
@@ -103,6 +112,27 @@ struct _GdaMetaStoreClass
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-meta-store
+ * @short_description: Dictionary object
+ * @title: GdaMetaStore
+ * @stability: Stable
+ * @see_also: #GdaMetaStruct
+ *
+ * Previous versions of &LIBGDA; relied on an XML based file to store dictionary information, such as
+ * the database's schema (tables, views, etc) and various other information. The problems were that it was
+ * difficult for an application to integrate its own data into the dictionary and that there were some
+ * performances problems as the XML file needed to be parsed (and converted into its own in-memory structure)
+ * before any data could be read out of it.
+ *
+ * The new dictionary now relies on a database structure to store its data (see the 
+ * <link linkend="information_schema">database schema</link> section for a detailed description). The actual database can be a
+ * single file (using an SQLite database), an entirely in memory database (also using an SQLite database), or
+ * a more conventional backend such as a PostgreSQL database for a shared dictionary on a server.
+ *
+ * The #GdaMetaStore object is thread safe.
+ */
+
 GType             gda_meta_store_get_type                 (void) G_GNUC_CONST;
 GdaMetaStore     *gda_meta_store_new_with_file            (const gchar *file_name);
 GdaMetaStore     *gda_meta_store_new                      (const gchar *cnc_string);
diff --git a/libgda/gda-meta-struct.c b/libgda/gda-meta-struct.c
index cccd3cc..996f7a8 100644
--- a/libgda/gda-meta-struct.c
+++ b/libgda/gda-meta-struct.c
@@ -1,6 +1,8 @@
-/* gda-meta-struct.c
+/*
+ * Copyright (C) 2008 - 2011 The GNOME Foundation.
  *
- * Copyright (C) 2008 - 2011 Vivien Malerba
+ * AUTHORS:
+ *      Vivien Malerba <malerba gnome-db org>
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -697,10 +699,10 @@ add_declared_foreign_keys (GdaMetaStruct *mstruct, GdaMetaTable *mt, GError **er
 		/* create new FK structure */
 		tfk = g_new0 (GdaMetaTableForeignKey, 1);
 		tfk->meta_table = dbo;
-		tfk->declared = (gpointer) 0x01;
+		tfk->declared = TRUE;
 		tfk->fk_name = g_value_dup_string (fk_name);
-		tfk->on_update_policy = GINT_TO_POINTER (GDA_META_FOREIGN_KEY_NONE);
-		tfk->on_delete_policy = GINT_TO_POINTER (GDA_META_FOREIGN_KEY_NONE);
+		tfk->on_update_policy = GDA_META_FOREIGN_KEY_NONE;
+		tfk->on_delete_policy = GDA_META_FOREIGN_KEY_NONE;
 		
 		/* ignore if some columns are not found in the schema
 		 * (maybe wrong or outdated FK decl) */
@@ -1137,16 +1139,16 @@ _meta_struct_complement (GdaMetaStruct *mstruct, GdaMetaDbObjectType type,
 				dbo->depend_list = g_slist_append (dbo->depend_list, tfk->depend_on);
 
 				if (G_VALUE_TYPE (upd_policy) == G_TYPE_STRING)
-					tfk->on_update_policy = GINT_TO_POINTER (policy_string_to_value (g_value_get_string (upd_policy)));
+					tfk->on_update_policy = policy_string_to_value (g_value_get_string (upd_policy));
 				else
-					tfk->on_update_policy = GINT_TO_POINTER (GDA_META_FOREIGN_KEY_UNKNOWN);
+					tfk->on_update_policy = GDA_META_FOREIGN_KEY_UNKNOWN;
 
 				if (G_VALUE_TYPE (upd_policy) == G_TYPE_STRING)
-					tfk->on_delete_policy = GINT_TO_POINTER (policy_string_to_value (g_value_get_string (del_policy)));
+					tfk->on_delete_policy = policy_string_to_value (g_value_get_string (del_policy));
 				else
-					tfk->on_delete_policy = GINT_TO_POINTER (GDA_META_FOREIGN_KEY_UNKNOWN);
+					tfk->on_delete_policy = GDA_META_FOREIGN_KEY_UNKNOWN;
 
-				tfk->declared = NULL;
+				tfk->declared = FALSE;
 
 				/* FIXME: compute @cols_nb, and all the @*_array members (ref_pk_cols_array must be
 				 * initialized with -1 values everywhere */
diff --git a/libgda/gda-meta-struct.h b/libgda/gda-meta-struct.h
index e82af8c..59d768b 100644
--- a/libgda/gda-meta-struct.h
+++ b/libgda/gda-meta-struct.h
@@ -1,5 +1,4 @@
-/* gda-meta-struct.h
- *
+/*
  * Copyright (C) 2008 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
@@ -82,6 +81,15 @@ typedef enum {
 /*
  * Controls which features are computed about database objects
  */
+/**
+ * GdaMetaStructFeature:
+ * @GDA_META_STRUCT_FEATURE_NONE: database objects only have their own attributes
+ * @GDA_META_STRUCT_FEATURE_FOREIGN_KEYS: foreign keys are computed for tables
+ * @GDA_META_STRUCT_FEATURE_VIEW_DEPENDENCIES: for views, the tables they use are also computed
+ * @GDA_META_STRUCT_FEATURE_ALL: all the features are computed
+ *
+ * Controls which features are computed about database objects.
+ */
 typedef enum {
 	GDA_META_STRUCT_FEATURE_NONE              = 0,
 	GDA_META_STRUCT_FEATURE_FOREIGN_KEYS      = 1 << 0,
@@ -338,17 +346,24 @@ typedef struct {
 	gchar           **ref_pk_names_array; /* Ref PK fields names */
 
 	/*< private >*/
-	gpointer          on_update_policy; /* pointer containing the GdaMetaForeignKeyPolicy integer
+	GdaMetaForeignKeyPolicy on_update_policy; /* pointer containing the GdaMetaForeignKeyPolicy integer
 					     * to keep ABI from 4.0, use GINT_TO_POINTER and
 					     * GPOINTER_TO_INT */
-	gpointer          on_delete_policy; /* pointer containing the GdaMetaForeignKeyPolicy integer
+	GdaMetaForeignKeyPolicy on_delete_policy; /* pointer containing the GdaMetaForeignKeyPolicy integer
 					     * to keep ABI from 4.0, use GINT_TO_POINTER and
 					     * GPOINTER_TO_INT */
-	gpointer          declared; /* pointer to a boolean to keep ABI from 4.0.
+	gboolean          declared; /* pointer to a boolean to keep ABI from 4.0.
 				     * Any non NULL if FK has been declared in meta data */
 
 	/*< public >*/
 	gchar            *fk_name;
+
+	/*< private >*/
+	/* Padding for future expansion */
+	gpointer _gda_reserved1;
+	gpointer _gda_reserved2;
+	gpointer _gda_reserved3;
+	gpointer _gda_reserved4;
 } GdaMetaTableForeignKey;
 /**
  * GDA_META_TABLE_FOREIGN_KEY
@@ -368,7 +383,7 @@ typedef struct {
  *
  * Returns: the policy as a #GdaMetaForeignKeyPolicy
  */
-#define GDA_META_TABLE_FOREIGN_KEY_ON_UPDATE_POLICY(fk) ((GdaMetaForeignKeyPolicy) GPOINTER_TO_INT ((GdaMetaTableForeignKey*)(fk)->on_update_policy))
+#define GDA_META_TABLE_FOREIGN_KEY_ON_UPDATE_POLICY(fk) (((GdaMetaTableForeignKey*)(fk))->on_update_policy)
 
 /**
  * GDA_META_TABLE_FOREIGN_KEY_ON_DELETE_POLICY:
@@ -378,7 +393,7 @@ typedef struct {
  *
  * Returns: the policy as a #GdaMetaForeignKeyPolicy
  */
-#define GDA_META_TABLE_FOREIGN_KEY_ON_DELETE_POLICY(fk) ((GdaMetaForeignKeyPolicy) GPOINTER_TO_INT ((GdaMetaTableForeignKey*)(fk)->on_delete_policy))
+#define GDA_META_TABLE_FOREIGN_KEY_ON_DELETE_POLICY(fk) (((GdaMetaTableForeignKey*)(fk))->on_delete_policy)
 
 /**
  * GDA_META_TABLE_FOREIGN_KEY_IS_DECLARED
@@ -389,7 +404,86 @@ typedef struct {
  *
  * Returns: %TRUE if @fk has been declared in the database's meta data and %FALSE if @fk is an actual foreign key defined in the database's schema
  */
-#define GDA_META_TABLE_FOREIGN_KEY_IS_DECLARED(fk) ((((GdaMetaTableForeignKey*)(fk))->declared) ? TRUE : FALSE)
+#define GDA_META_TABLE_FOREIGN_KEY_IS_DECLARED(fk) (((GdaMetaTableForeignKey*)(fk))->declared)
+
+/**
+ * SECTION:gda-meta-struct
+ * @short_description: In memory representation of some database objects
+ * @title: GdaMetaStruct
+ * @stability: Stable
+ * @see_also: #GdaMetaStore
+ *
+ * The #GdaMetaStruct object reads data from a #GdaMetaStore object and
+ *  creates an easy to use in memory representation for some database objects. For example one can easily
+ *  analyze the columns of a table (or its foreign keys) using a #GdaMetaStruct.
+ *
+ *  When created, the new #GdaMetaStruct object is empty (it does not have any information about any database object).
+ *  Information about database objects is computed upon request using the gda_meta_struct_complement() method. Information
+ *  about individual database objects is represented by #GdaMetaDbObject structures, which can be obtained using
+ *  gda_meta_struct_get_db_object() or gda_meta_struct_get_all_db_objects().
+ *
+ *  Note that the #GdaMetaDbObject structures may change or may be removed or replaced by others, so it not
+ *  advised to keep pointers to these structures: pointers to these structures should be considered valid
+ *  as long as gda_meta_struct_complement() and other similar functions have not been called.
+ *
+ *  In the following code sample, one prints the columns names and types of a table:
+ *  <programlisting>
+ *GdaMetaStruct *mstruct;
+ *GdaMetaDbObject *dbo;
+ *GValue *catalog, *schema, *name;
+ *
+ * // Define name (and optionnally catalog and schema)
+ *[...]
+ *
+ *mstruct = gda_meta_struct_new ();
+ *gda_meta_struct_complement (mstruct, store, GDA_META_DB_TABLE, catalog, schema, name, NULL);
+ *dbo = gda_meta_struct_get_db_object (mstruct, catalog, schema, name);
+ *if (!dbo)
+ *        g_print ("Table not found\n");
+ *else {
+ *        GSList *list;
+ *        for (list = GDA_META_TABLE (dbo)->columns; list; list = list->next) {
+ *                GdaMetaTableColumn *tcol = GDA_META_TABLE_COLUMN (list->data);
+ *                g_print ("COLUMN: %s (%s)\n", tcol->column_name, tcol->column_type);
+ *        }
+ *}
+ *gda_meta_struct_free (mstruct);
+ *  </programlisting>
+ *  If now the database object type is not known, one can use the following code:
+ *  <programlisting>
+ *GdaMetaStruct *mstruct;
+ *GdaMetaDbObject *dbo;
+ *GValue *catalog, *schema, *name;
+ *
+ * // Define name (and optionnally catalog and schema)
+ *[...]
+ *
+ *mstruct = gda_meta_struct_new ();
+ *gda_meta_struct_complement (mstruct, store, GDA_META_DB_UNKNOWN, catalog, schema, name, NULL);
+ *dbo = gda_meta_struct_get_db_object (mstruct, catalog, schema, name);
+ *if (!dbo)
+ *        g_print ("Object not found\n");
+ *else {
+ *        if ((dbo->obj_type == GDA_META_DB_TABLE) || (dbo->obj_type == GDA_META_DB_VIEW)) {
+ *                if (dbo->obj_type == GDA_META_DB_TABLE)
+ *                        g_print ("Is a table\n");
+ *                else if (dbo->obj_type == GDA_META_DB_VIEW) {
+ *                        g_print ("Is a view, definition is:\n");
+ *                        g_print ("%s\n", GDA_META_VIEW (dbo)->view_def);
+ *                }
+ *
+ *                GSList *list;
+ *                for (list = GDA_META_TABLE (dbo)->columns; list; list = list->next) {
+ *                        GdaMetaTableColumn *tcol = GDA_META_TABLE_COLUMN (list->data);
+ *                        g_print ("COLUMN: %s (%s)\n", tcol->column_name, tcol->column_type);
+ *                }
+ *        }
+ *        else 
+ *                g_print ("Not a table or a view\n");
+ *}
+ *gda_meta_struct_free (mstruct);
+ *  </programlisting>
+ */
 
 GType               gda_meta_struct_get_type           (void) G_GNUC_CONST;
 GdaMetaStruct      *gda_meta_struct_new                (GdaMetaStore *store, GdaMetaStructFeature features);
diff --git a/libgda/gda-mutex.h b/libgda/gda-mutex.h
index 402c3f5..65ec6e7 100644
--- a/libgda/gda-mutex.h
+++ b/libgda/gda-mutex.h
@@ -1,4 +1,4 @@
-/* GDA library
+/*
  * Copyright (C) 2008 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
@@ -29,6 +29,22 @@ G_BEGIN_DECLS
 
 typedef struct _GdaMutex GdaMutex;
 
+/**
+ * SECTION:gda-mutex
+ * @short_description: Recursive mutex implementation
+ * @title: GdaMutex
+ * @stability: Stable
+ * @see_also: #GdaLockable and #GMutex
+ *
+ * #GdaMutex implements a recursive mutex (unlike the #GMutex implementation which offers no
+ * guarantee about recursiveness). A recursive mutex is a mutex which can be locked several
+ * times by the same thread (and needs to be unlocked the same number of times before
+ * another thread can lock it).
+ *
+ * A #GdaMutex can safely be used even in a non multi-threaded environment in which case
+ * it does nothing.
+ */
+
 GdaMutex*   gda_mutex_new       (void);
 void        gda_mutex_lock      (GdaMutex *mutex);
 gboolean    gda_mutex_trylock   (GdaMutex *mutex);
diff --git a/libgda/gda-quark-list.h b/libgda/gda-quark-list.h
index 8ea2757..2c7b302 100644
--- a/libgda/gda-quark-list.h
+++ b/libgda/gda-quark-list.h
@@ -1,5 +1,5 @@
-/* GDA Common Library
- * Copyright (C) 1998 - 2006 The GNOME Foundation.
+/*
+ * Copyright (C) 1998 - 2011 The GNOME Foundation.
  *
  * Authors:
  *	Rodrigo Moya <rodrigo gnome-db org>
@@ -33,6 +33,17 @@ typedef struct _GdaQuarkList GdaQuarkList;
 
 #define GDA_TYPE_QUARK_LIST (gda_quark_list_get_type())
 
+/**
+ * SECTION:gda-quark-list
+ * @short_description: Manages lists of KEY=VALUE pairs
+ * @title: Quark list
+ * @stability: Stable
+ * @see_also:
+ *
+ * This object is used mainly by database provider's implementation to parse connection
+ * strings into lists of KEY=VALUE pairs.
+ */
+
 GType         gda_quark_list_get_type        (void) G_GNUC_CONST;
 GdaQuarkList *gda_quark_list_new             (void);
 GdaQuarkList *gda_quark_list_new_from_string (const gchar *string);
diff --git a/libgda/gda-repetitive-statement.h b/libgda/gda-repetitive-statement.h
index 355362f..a6fac0c 100644
--- a/libgda/gda-repetitive-statement.h
+++ b/libgda/gda-repetitive-statement.h
@@ -1,6 +1,9 @@
-/* GDA library
- * 
- * Copyright (C) Daniel Espinosa Ortiz 2008 <esodan gmail com>
+/*
+ * Copyright (C) 2008 - 2011 The GNOME Foundation.
+ *
+ * Authors:
+ *      Daniel Espinosa Ortiz <esodan gmail com>
+ *      Vivien Malerba <malerba gnome-db org>
  * 
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -43,6 +46,20 @@ struct _GdaRepetitiveStatement
 	GObject parent_instance;
 };
 
+/**
+ * SECTION:gda-repetitive-statement
+ * @short_description: Execute the same statement several times with different values
+ * @title: GdaRepetitiveStatement
+ * @stability: Stable
+ * @see_also: #GdaStatement, #GdaBatch and #GdaConnection
+ *
+ * The #GdaRepetitiveStatement object allows one to specify a statement to be executed
+ * several times using different variables' values sets for each execution. Using the object
+ * has almost no interrest at all if the statement to be executed several times has no parameter.
+ *
+ * Use the gda_connection_repetitive_statement_execute() method to execute the repetitive statement.
+ */
+
 GType                   gda_repetitive_statement_get_type         (void) G_GNUC_CONST;
 
 GdaRepetitiveStatement* gda_repetitive_statement_new              (GdaStatement *stmt);
@@ -52,4 +69,4 @@ gboolean                gda_repetitive_statement_append_set       (GdaRepetitive
 
 G_END_DECLS
 
-#endif /* _GDA_REPETITIVE_STATEMENT_H_ */
+#endif
diff --git a/libgda/gda-row.h b/libgda/gda-row.h
index 0857228..86349f6 100644
--- a/libgda/gda-row.h
+++ b/libgda/gda-row.h
@@ -1,5 +1,5 @@
-/* GDA library
- * Copyright (C) 1998 - 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 1998 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Michael Lausch <michael lausch at>
@@ -48,6 +48,7 @@ struct _GdaRow {
 struct _GdaRowClass {
 	GObjectClass   parent_class;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
@@ -55,6 +56,20 @@ struct _GdaRowClass {
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-row
+ * @short_description: Individual row of a #GdaDataModelArray object
+ * @title: GdaRow
+ * @stability: Stable
+ * @see_also: #GdaDataModelArray
+ *
+ * The #GdaDataModelArray object uses #GdaRow to store each row of data. Each #GdaRow has the same
+ * number of #GValue values (equal to the number of columns of the data model).
+ *
+ * As a side note, the #GdaRow object is also used internally by the implementation of the data models returned
+ * when executing a SELECT statement.
+ */
+
 GType         gda_row_get_type       (void) G_GNUC_CONST;
 
 GdaRow       *gda_row_new            (gint count);
@@ -65,8 +80,6 @@ GValue       *gda_row_get_value      (GdaRow *row, gint num);
 void          gda_row_invalidate_value (GdaRow *row, GValue *value);
 gboolean      gda_row_value_is_valid (GdaRow *row, GValue *value);
 
-
-
 G_END_DECLS
 
 #endif
diff --git a/libgda/gda-server-operation.c b/libgda/gda-server-operation.c
index 80c4b08..ec7bade 100644
--- a/libgda/gda-server-operation.c
+++ b/libgda/gda-server-operation.c
@@ -1,5 +1,5 @@
-/* GDA library
- * Copyright (C) 2006 - 2010 The GNOME Foundation.
+/*
+ * Copyright (C) 2006 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -2087,7 +2087,7 @@ gda_server_operation_get_value_at (GdaServerOperation *op, const gchar *path_for
  * if the @path is not defined or @path does not hold any value, or if the value held is not a string
  * (in that last case a warning is shown).
  *
- * Since: 4.0.3
+ * Since: 5.0.3
  */
 gchar *
 gda_server_operation_get_sql_identifier_at (GdaServerOperation *op, GdaConnection *cnc, GdaServerProvider *prov,
@@ -2496,7 +2496,7 @@ gda_server_operation_prepare_drop_database (const gchar *provider, const gchar *
 /**
  * gda_server_operation_perform_drop_database:
  * @provider: the database provider to use, or %NULL if @op has been created using gda_server_operation_prepare_drop_database()
- * @op: a #GdaServerOperation object obtained using gda_prepare_drop_database()
+ * @op: a #GdaServerOperation object obtained using gda_server_operation_prepare_drop_database()
  * @error: a place to store en error, or %NULL
  *
  * Destroys an existing database using the specifications in @op. @op can be obtained using
@@ -2531,7 +2531,7 @@ gda_server_operation_perform_drop_database (GdaServerOperation *op, const gchar
  * @table_name: name of the table to create
  * @error: a place to store errors, or %NULL
  * @...: group of three arguments for column's name, column's #GType
- * and a #GdaEasyCreateTableFlag flag, finished with %NULL
+ * and a #GdaServerOperationCreateTableFlag flag, finished with %NULL
  *
  * Add more arguments if the flag needs them:
  *
@@ -2548,7 +2548,7 @@ gda_server_operation_perform_drop_database (GdaServerOperation *op, const gchar
  * </itemizedlist>
  *
  * Create a #GdaServerOperation object using an opened connection, taking three
- * arguments, a column's name the column's GType and #GdaEasyCreateTableFlag
+ * arguments, a column's name the column's GType and #GdaServerOperationCreateTableFlag
  * flag, you need to finish the list using %NULL.
  *
  * You'll be able to modify the #GdaServerOperation object to add custom options * to the operation. When finished call #gda_server_operation_perform_create_table
diff --git a/libgda/gda-server-operation.h b/libgda/gda-server-operation.h
index 934b5b5..86c0f94 100644
--- a/libgda/gda-server-operation.h
+++ b/libgda/gda-server-operation.h
@@ -1,5 +1,5 @@
-/* GDA library
- * Copyright (C) 2006 - 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 2006 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -104,6 +104,38 @@ typedef enum {
 	GDA_SERVER_OPERATION_STATUS_UNKNOWN
 } GdaServerOperationNodeStatus;
 
+/**
+ * SECTION:gda-server-operation-sequences
+ * @short_description: Manipulating sequences
+ * @title: GdaServerOperation: sequences
+ * @stability: Stable
+ * @see_also: #GdaServerOperation
+ *
+ * The #GdaServerOperation object can contain sequences of templates. For example when creating a table,
+ * one can specify several foreign keys where for each foreign key, one must define the column(s) on which the
+ * foreign key applies, the referenced table and the corresponding columns of the referenced table (plus some
+ * additional information). In this case the foreign keys are defined as a sequence of templates (the foreign key
+ * definition): there can be zero or more foreign keys.
+ */
+
+/**
+ * SECTION:gda-server-operation-nodes
+ * @short_description: Getting information about parts (nodes) composing a path
+ * @title: GdaServerOperation: individual nodes
+ * @stability: Stable
+ * @see_also: #GdaServerOperation
+ *
+ * To each part of a path is associated a node (as a #GdaServerOperationNode structure). For example the
+ * "/TABLE_DEF_P/TABLE_NAME" path has two nodes, one associated to "/TABLE_DEF_P" and one to
+ * "/TABLE_DEF_P/TABLE_NAME". For more information about the path's format, see the
+ * gda_server_operation_set_value_at()'s documentation.
+ *
+ * This API is designed to get information about all the nodes present in a #GdaServerOperation object (refer to the
+ * gda_server_operation_get_root_nodes() function) and about each node of a path, and allows inspection
+ * of its contents. It is mainly reserved for database provider's implementations but can have its purpose
+ * outside of this scope.
+ */
+
 typedef struct _GdaServerOperationNode {
 	GdaServerOperationNodeType    type;
 	GdaServerOperationNodeStatus  status;
@@ -127,6 +159,7 @@ struct _GdaServerOperationClass {
 	void                     (*seq_item_added) (GdaServerOperation *op, const gchar *seq_path, gint item_index);
 	void                     (*seq_item_remove) (GdaServerOperation *op, const gchar *seq_path, gint item_index);
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
@@ -134,6 +167,35 @@ struct _GdaServerOperationClass {
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-server-operation
+ * @short_description: Handles any DDL query in an abstract way
+ * @title: GdaServerOperation
+ * @stability: Stable
+ * @see_also:
+ *
+ * This object is basically just a data store: it can store named values, the values being
+ * organized hierarchically by their name which are similar to a Unix file path. For example a value can be read from its path
+ * using the gda_server_operation_get_value_at() method, or set using the gda_server_operation_set_value_at() method.
+ *
+ * Each #GdaServerOperation contains some structure which is usually defined by a database provider to implement
+ * a specific operation. The structure is composed of the following building blocks:
+ * <itemizedlist>
+ *   <listitem><para>Named values (internally represented as a #GdaHolder object)</para></listitem>
+ *   <listitem><para>Named values in a vector (internally represented as a #GdaSet object)</para></listitem>
+ *   <listitem><para>Values in an array (internally represented as a #GdaDataModel object)</para></listitem>
+ *   <listitem><para>Sequences of one or more of the previous blocks. A sequence can contain any number of
+ *   instances of the template block (there may be lower and upper boundaries to the number of instances)</para></listitem>
+ * </itemizedlist>
+ *
+ * <emphasis>Important note:</emphasis> #GdaServerOperation objects are usually not created 
+ * manually using gda_server_operation_new(), but
+ * using a #GdaServerProvider object with gda_server_provider_create_operation().
+ * See the <link linkend="DDLIntro">global introduction about DDL</link> for more information.
+ * Alternatively one can use the <link linkend="libgda-40-Convenience-functions">Convenience functions</link>
+ * which internally manipulate #GdaServerOperation objects.
+ */
+
 GType                      gda_server_operation_get_type                (void) G_GNUC_CONST;
 GdaServerOperation        *gda_server_operation_new                     (GdaServerOperationType op_type, const gchar *xml_file);
 GdaServerOperationType     gda_server_operation_get_op_type             (GdaServerOperation *op);
diff --git a/libgda/gda-server-provider-extra.c b/libgda/gda-server-provider-extra.c
index 3b90ec8..fdf7cae 100644
--- a/libgda/gda-server-provider-extra.c
+++ b/libgda/gda-server-provider-extra.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005 - 2010 The GNOME Foundation.
+ * Copyright (C) 2005 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -260,313 +260,6 @@ gda_select_alter_select_for_empty (GdaStatement *stmt, G_GNUC_UNUSED GError **er
 }
 
 /**
- * gda_server_provider_get_schema_nb_columns:
- * @schema: a #GdaConnectionSchema
- *
- * Returns: the number of columns the #GdaDataModel for the requested schema
- * must have
- *
- * Deprecated: 4.2: This was a leftover from the pre 4.0 area
- */
-gint
-gda_server_provider_get_schema_nb_columns (GdaConnectionSchema schema)
-{
-	switch (schema) {
-	case GDA_CONNECTION_SCHEMA_AGGREGATES:
-		return 7;
-	case GDA_CONNECTION_SCHEMA_DATABASES:
-		return 1;
-	case GDA_CONNECTION_SCHEMA_FIELDS:
-		return 10;
-        case GDA_CONNECTION_SCHEMA_INDEXES:
-		return 1;
-        case GDA_CONNECTION_SCHEMA_LANGUAGES:
-		return 1;
-        case GDA_CONNECTION_SCHEMA_NAMESPACES:
-		return 1;
-        case GDA_CONNECTION_SCHEMA_PARENT_TABLES:
-		return 2;
-        case GDA_CONNECTION_SCHEMA_PROCEDURES:
-		return 8;
-        case GDA_CONNECTION_SCHEMA_SEQUENCES:
-		return 4;
-        case GDA_CONNECTION_SCHEMA_TABLES:
-		return 4;
-        case GDA_CONNECTION_SCHEMA_TRIGGERS:
-		return 1;
-        case GDA_CONNECTION_SCHEMA_TYPES:
-		return 5;
-        case GDA_CONNECTION_SCHEMA_USERS:
-		return 1;
-        case GDA_CONNECTION_SCHEMA_VIEWS:
-		return 4;
-	case GDA_CONNECTION_SCHEMA_CONSTRAINTS:
-		return 5;
-	default:
-		g_assert_not_reached ();
-	}
-}
-
-typedef struct {
-        gchar        *col_name;
-        GType  data_type;
-} GdaSchemaColData;
-
-GdaSchemaColData aggs_spec [] = {
-	/* To translators: "Aggregate": the noun */
-	{ N_("Aggregate"), G_TYPE_STRING},
-	{ N_("Id"), G_TYPE_STRING},
-	{ N_("Owner"), G_TYPE_STRING},
-	{ N_("Comments"), G_TYPE_STRING},
-	{ N_("OutType"), G_TYPE_STRING},
-	{ N_("InType"), G_TYPE_STRING},
-	{ N_("Definition"), G_TYPE_STRING}
-};
-
-GdaSchemaColData dbs_spec [] = {
-	{ N_("Database"), G_TYPE_STRING}
-};
-
-GdaSchemaColData fields_spec [] = {
-	{ N_("Field name"), G_TYPE_STRING},
-	{ N_("Data type"), G_TYPE_STRING},
-	{ N_("Size"), G_TYPE_INT},
-	{ N_("Scale"), G_TYPE_INT},
-	{ N_("Not null?"), G_TYPE_BOOLEAN},
-	{ N_("Primary key?"), G_TYPE_BOOLEAN},
-	{ N_("Unique index?"), G_TYPE_BOOLEAN},
-	{ N_("References"), G_TYPE_STRING},
-	{ N_("Default value"), G_TYPE_STRING},
-	{ N_("Extra attributes"), G_TYPE_STRING}
-};
-
-GdaSchemaColData indexes_spec [] = {
-	{ N_("Index"), G_TYPE_STRING}
-};
-
-GdaSchemaColData lang_spec [] = {
-	{ N_("Language"), G_TYPE_STRING}
-};
-
-GdaSchemaColData ns_spec [] = {
-	{ N_("Namespace"), G_TYPE_STRING}
-};
-
-GdaSchemaColData parent_spec [] = {
-	{ N_("Table"), G_TYPE_STRING},
-	{ N_("Sequence"), G_TYPE_INT}
-};
-
-GdaSchemaColData procs_spec [] = {
-	{ N_("Procedure"), G_TYPE_STRING},
-	{ N_("Id"), G_TYPE_STRING},
-	{ N_("Owner"), G_TYPE_STRING},
-	{ N_("Comments"), G_TYPE_STRING},
-	{ N_("Return type"), G_TYPE_STRING},
-	/* To translators: "Nb args": the procedure's number of arguments */
-	{ N_("Nb args"), G_TYPE_INT},
-	{ N_("Args types"), G_TYPE_STRING},
-	{ N_("Definition"), G_TYPE_STRING}
-};
-
-GdaSchemaColData seq_spec [] = {
-	{ N_("Sequence"), G_TYPE_STRING},
-	{ N_("Owner"), G_TYPE_STRING},
-	{ N_("Comments"), G_TYPE_STRING},
-	{ N_("Definition"), G_TYPE_STRING}
-};
-
-GdaSchemaColData table_spec [] = {
-	{ N_("Table"), G_TYPE_STRING},
-	{ N_("Owner"), G_TYPE_STRING},
-	{ N_("Description"), G_TYPE_STRING},
-	{ N_("Definition"), G_TYPE_STRING}
-};
-
-GdaSchemaColData trigger_spec [] = {
-	{ N_("Trigger"), G_TYPE_STRING}
-};
-
-GdaSchemaColData types_spec [] = {
-	{ N_("Type"), G_TYPE_STRING},
-	{ N_("Owner"), G_TYPE_STRING},
-	{ N_("Comments"), G_TYPE_STRING},
-	{ N_("GDA type"), G_TYPE_ULONG},
-	{ N_("Synonyms"), G_TYPE_STRING}
-};
-
-GdaSchemaColData user_spec [] = {
-	{ N_("User"), G_TYPE_STRING}
-};
-
-GdaSchemaColData view_spec [] = {
-	{ N_("View"), G_TYPE_STRING},
-	{ N_("Owner"), G_TYPE_STRING},
-	{ N_("Description"), G_TYPE_STRING},
-	{ N_("Definition"), G_TYPE_STRING}
-};
-
-GdaSchemaColData constraint_spec [] = {
-	{ N_("Name"), G_TYPE_STRING},
-	{ N_("Type"), G_TYPE_STRING},
-	{ N_("Fields"), G_TYPE_STRING},
-	{ N_("Definition"), G_TYPE_STRING},
-	{ N_("Options"), G_TYPE_STRING}
-};
-
-static GdaSchemaColData *
-schema_get_spec (GdaConnectionSchema schema)
-{
-	GdaSchemaColData *spec = NULL;
-
-	switch (schema) {
-	case GDA_CONNECTION_SCHEMA_AGGREGATES:
-		spec = aggs_spec;
-		break;
-	case GDA_CONNECTION_SCHEMA_DATABASES:
-		spec = dbs_spec;
-		break;
-	case GDA_CONNECTION_SCHEMA_FIELDS:
-		spec = fields_spec;
- 		break;
-	case GDA_CONNECTION_SCHEMA_INDEXES:
-		spec = indexes_spec;
- 		break;
-	case GDA_CONNECTION_SCHEMA_LANGUAGES:
-		spec = lang_spec;
- 		break;
-	case GDA_CONNECTION_SCHEMA_NAMESPACES:
-		spec = ns_spec;
- 		break;
-	case GDA_CONNECTION_SCHEMA_PARENT_TABLES:
-		spec = parent_spec;
- 		break;
-	case GDA_CONNECTION_SCHEMA_PROCEDURES:
-		spec = procs_spec;
- 		break;
-	case GDA_CONNECTION_SCHEMA_SEQUENCES:
-		spec = seq_spec;
- 		break;
-	case GDA_CONNECTION_SCHEMA_TABLES:
-		spec = table_spec;
- 		break;
-	case GDA_CONNECTION_SCHEMA_TRIGGERS:
-		spec = trigger_spec;
-  		break;
-	case GDA_CONNECTION_SCHEMA_TYPES:
-		spec = types_spec;
-   		break;
-	case GDA_CONNECTION_SCHEMA_USERS:
-		spec = user_spec;
-   		break;
-	case GDA_CONNECTION_SCHEMA_VIEWS:
-		spec = view_spec;
-		break;
-	case GDA_CONNECTION_SCHEMA_CONSTRAINTS:
-		spec = constraint_spec;
-		break;
-	default:
-		g_assert_not_reached ();
-	}
-
-	return spec;
-}
-
-/**
- * gda_server_provider_init_schema_model:
- * @model: a #GdaDataModel
- * @schema: a #GdaConnectionSchema
- *
- * Sets the column attributes of @model for the requested schema
- *
- * Returns: %TRUE if there was no error
- *
- * Deprecated: 4.2: This was a leftover from the pre 4.0 area
- */
-gboolean
-gda_server_provider_init_schema_model (GdaDataModel *model, GdaConnectionSchema schema)
-{
-	GdaSchemaColData *spec = NULL;
-	gint nbcols, i;
-	GdaColumn *column;
-
-	g_return_val_if_fail (model && GDA_IS_DATA_MODEL (model), FALSE);
-	spec = schema_get_spec (schema);
-
-	nbcols = gda_server_provider_get_schema_nb_columns (schema);
-	if (gda_data_model_get_n_columns (model) != nbcols)
-		return FALSE;
-
-	for (i = 0; i < nbcols; i++) {
-                column = gda_data_model_describe_column (GDA_DATA_MODEL (model), i);
-
-                gda_column_set_description (column, spec[i].col_name);
-                gda_column_set_name (column, spec[i].col_name);
-                gda_column_set_g_type (column, spec[i].data_type);
-        }
-
-	return TRUE;
-}
-
-/**
- * gda_server_provider_test_schema_model:
- * @model: a #GdaDataModel to test
- * @schema:
- * @error:
- *
- * Test that the structure of @model is correct in regard with @schema
- *
- * Returns: %TRUE if @model has the correct structure
- *
- * Deprecated: 4.2: This was a leftover from the pre 4.0 area
- */
-gboolean
-gda_server_provider_test_schema_model (GdaDataModel *model, GdaConnectionSchema schema, GError **error)
-{
-	gint i, nbcols;
-	GdaSchemaColData *spec = NULL;
-
-	g_return_val_if_fail (model && GDA_IS_DATA_MODEL (model), FALSE);
-
-	nbcols = gda_data_model_get_n_columns (model);
-	if (nbcols < gda_server_provider_get_schema_nb_columns (schema)) {
-		g_set_error (error, 0, 0, "%s", 
-			     _("Data model for schema has a wrong number of columns"));
-		return FALSE;
-	}
-
-	spec = schema_get_spec (schema);
-	for (i = 0; i < nbcols; i++) {
-		GdaColumn *column;
-
-                column = gda_data_model_describe_column (GDA_DATA_MODEL (model), i);
-
-		if (strcmp (gda_column_get_description (column), spec[i].col_name)) {
-			g_set_error (error, 0, 0,
-				     _("Data model for schema has a wrong column title: '%s' instead of '%s'"),
-				     gda_column_get_description (column), spec[i].col_name);
-			return FALSE;
-		}
-
-		if (strcmp (gda_column_get_name (column), spec[i].col_name)) {
-			g_set_error (error, 0, 0,
-				     _("Data model for schema has a wrong column name: '%s' instead of '%s'"),
-				     gda_column_get_name (column), spec[i].col_name);
-			return FALSE;
-		}
-
-		if (gda_column_get_g_type (column) != spec[i].data_type) {
-			g_set_error (error, 0, 0,
-				     _("Data model for schema has a wrong gda type: %s instead of %s"),
-				     gda_g_type_to_string (gda_column_get_g_type (column)), 
-				     gda_g_type_to_string (spec[i].data_type));
-			return FALSE;
-		}
-        }
-	return TRUE;
-}
-
-/**
  * gda_server_provider_handler_find:
  *
  * Returns: (transfer none):
@@ -679,7 +372,7 @@ gda_server_provider_load_file_contents (const gchar *inst_dir, const gchar *data
 		goto theend;
 	
 	g_free (file);
-	file = g_build_filename (inst_dir, "..", "..", "..", "share", "libgda-4.0", filename, NULL);
+	file = g_build_filename (inst_dir, "..", "..", "..", "share", "libgda-5.0", filename, NULL);
 	if (g_file_get_contents (file, &contents, NULL, NULL))
 		goto theend;
 	contents = NULL;
diff --git a/libgda/gda-server-provider-extra.h b/libgda/gda-server-provider-extra.h
index c146ad7..622a1fd 100644
--- a/libgda/gda-server-provider-extra.h
+++ b/libgda/gda-server-provider-extra.h
@@ -1,6 +1,5 @@
-/* gda-server-provider-extra.h
- *
- * Copyright (C) 2005 - 2008 Vivien Malerba
+/*
+ * Copyright (C) 2005 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -27,18 +26,21 @@
 
 G_BEGIN_DECLS
 
-/*
- * GdaSqlParser associated to each provider
+/**
+ * SECTION:provider-support
+ * @short_description: Methods dedicated to implementing providers
+ * @title: Misc API for database providers
+ * @stability: Stable
+ * @see_also:
+ *
+ * The methods mentioned in this section are reserved for database providers implementations and should
+ * not bu used by developers outside that scope.
  */
-GdaSqlParser *gda_server_provider_internal_get_parser (GdaServerProvider *prov);
 
 /*
- * Help to implement providers, so the schemas return the same
- * number of columns and column titles across the providers.
+ * GdaSqlParser associated to each provider
  */
-gint      gda_server_provider_get_schema_nb_columns (GdaConnectionSchema schema);
-gboolean  gda_server_provider_init_schema_model     (GdaDataModel *model, GdaConnectionSchema schema);
-gboolean  gda_server_provider_test_schema_model     (GdaDataModel *model, GdaConnectionSchema schema, GError **error);
+GdaSqlParser *gda_server_provider_internal_get_parser (GdaServerProvider *prov);
 
 /*
  * Default perform operation
diff --git a/libgda/gda-server-provider.h b/libgda/gda-server-provider.h
index 81d4a44..3c31f31 100644
--- a/libgda/gda-server-provider.h
+++ b/libgda/gda-server-provider.h
@@ -1,5 +1,5 @@
-/* GDA library
- * Copyright (C) 1998 - 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 1998 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *	Rodrigo Moya <rodrigo gnome-db org>
@@ -66,6 +66,60 @@ struct _GdaServerProvider {
 	GdaServerProviderPrivate *priv;
 };
 
+
+/**
+ * GdaServerProviderMeta:
+ * @_info: 
+ * @_btypes: 
+ * @_udt: 
+ * @udt: 
+ * @_udt_cols: 
+ * @udt_cols: 
+ * @_enums: 
+ * @enums: 
+ * @_domains: 
+ * @domains: 
+ * @_constraints_dom: 
+ * @constraints_dom: 
+ * @_el_types: 
+ * @el_types: 
+ * @_collations: 
+ * @collations: 
+ * @_character_sets: 
+ * @character_sets: 
+ * @_schemata: 
+ * @schemata: 
+ * @_tables_views: 
+ * @tables_views: 
+ * @_columns: 
+ * @columns: 
+ * @_view_cols: 
+ * @view_cols: 
+ * @_constraints_tab: 
+ * @constraints_tab: 
+ * @_constraints_ref: 
+ * @constraints_ref: 
+ * @_key_columns: 
+ * @key_columns: 
+ * @_check_columns: 
+ * @check_columns: 
+ * @_triggers: 
+ * @triggers: 
+ * @_routines: 
+ * @routines: 
+ * @_routine_col: 
+ * @routine_col: 
+ * @_routine_par: 
+ * @routine_par: 
+ * @_indexes_tab: 
+ * @indexes_tab: 
+ * @_index_cols: 
+ * @index_cols:
+ *
+ * These methods must be implemented by providers to update a connection's associated metadata (in a 
+ * #GdaMetaStore object), see the <link linkend="prov-metadata">Virtual methods for providers/Methods - metadata</link>
+ * for more information.
+ */
 typedef struct {
 	/* _information_schema_catalog_name */
 	gboolean (*_info)            (GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *, GError **);
@@ -189,6 +243,7 @@ typedef struct {
 	gboolean (*index_cols)       (GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *, GError **,
 				      const GValue *table_catalog, const GValue *table_schema, const GValue *table_name, const GValue *index_name);
 	
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved5) (void);
 	void (*_gda_reserved6) (void);
@@ -218,8 +273,30 @@ typedef struct {
 	GList   *(*xa_recover)  (GdaServerProvider *, GdaConnection *, GError **);
 } GdaServerProviderXa;
 
+/**
+ * GdaServerProviderAsyncCallback:
+ * @provider: 
+ * @cnc: 
+ * @task_id: 
+ * @result_status: 
+ * @error: 
+ * @data: 
+ *
+ * Function to be called by Libgda when the associated asynchronous method invoked finishes.
+ */
 typedef void (*GdaServerProviderAsyncCallback) (GdaServerProvider *provider, GdaConnection *cnc, guint task_id, 
 						gboolean result_status, const GError *error, gpointer data);
+/**
+ * GdaServerProviderExecCallback:
+ * @provider: 
+ * @cnc: 
+ * @task_id: 
+ * @result_obj: 
+ * @error: 
+ * @data: 
+ *
+ * Function to be called by Libgda when the associated asynchronous method invoked finishes
+ */
 typedef void (*GdaServerProviderExecCallback) (GdaServerProvider *provider, GdaConnection *cnc, guint task_id, 
 					       GObject *result_obj, const GError *error, gpointer data);
 
@@ -314,11 +391,28 @@ struct _GdaServerProviderClass {
 							 GdaStatement *stmt, GdaSet *params, GError **error);
 	/*< private >*/
 	/* Padding for future expansion */
+	void                    (*_gda_reserved1)        (void);
+	void                    (*_gda_reserved2)        (void);
+	void                    (*_gda_reserved3)        (void);
 	void                    (*_gda_reserved4)        (void);
 	void                    (*_gda_reserved5)        (void);
 	void                    (*_gda_reserved6)        (void);
 };
 
+/**
+ * SECTION:gda-server-provider
+ * @short_description: Base class for all the DBMS providers
+ * @title: GdaServerProvider
+ * @stability: Stable
+ * @see_also: #GdaConnection
+ *
+ * The #GdaServerProvider class is a virtual class which all the DBMS providers
+ * must inherit, and implement its virtual methods.
+ *
+ * See the <link linkend="libgda-provider-class">Virtual methods for providers</link> section for more information
+ * about how to implement the virtual methods.
+ */
+
 GType                  gda_server_provider_get_type (void) G_GNUC_CONST;
 
 /* provider information */
diff --git a/libgda/gda-set.h b/libgda/gda-set.h
index 8ac4599..08cf7d3 100644
--- a/libgda/gda-set.h
+++ b/libgda/gda-set.h
@@ -1,6 +1,5 @@
-/* gda-set.h
- *
- * Copyright (C) 2003 - 2009 Vivien Malerba
+/*
+ * Copyright (C) 2003 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -111,10 +110,28 @@ struct _GdaSetClass
 
 	/*< private >*/
 	/* Padding for future expansion */
+	void (*_gda_reserved1) (void);
+	void (*_gda_reserved2) (void);
 	void (*_gda_reserved3) (void);
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-set
+ * @short_description: Container for several values
+ * @title: GdaSet
+ * @stability: Stable
+ * @see_also: #GdaHolder
+ *
+ * The #GdaSet object is a container for several values (as #GdaHolder objects). The list of #GdaHolder objects is
+ * publicly accessible (and should not be modified), using the "holders" attribute. Each #GdaSet object also
+ * maintains some publicly accessible information about the #GdaHolder objects, through the #GdaSetNode, #GdaSetSource and
+ * #GdaSetGroup structures (see gda_set_get_node(), gda_set_get_source() and gda_set_get_group()).
+ *
+ * It is possible to control the values a #GdaHolder can have in the #GdaSet by connecting to the 
+ * <link linkend="GdaSet-before-holder-change">"before-holder-change"</link> signal.
+ */
+
 GType         gda_set_get_type                 (void) G_GNUC_CONST;
 GdaSet       *gda_set_new                      (GSList *holders);
 GdaSet       *gda_set_copy                     (GdaSet *set);
diff --git a/libgda/gda-sql-builder.c b/libgda/gda-sql-builder.c
index ec2ac95..64e56c4 100644
--- a/libgda/gda-sql-builder.c
+++ b/libgda/gda-sql-builder.c
@@ -1,6 +1,5 @@
-/* gda-sql-builder.c
- *
- * Copyright (C) 2008 - 2010 Vivien Malerba
+/*
+ * Copyright (C) 2008 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -123,7 +122,7 @@ gda_sql_builder_class_init (GdaSqlBuilderClass *klass)
 	 */
 	g_object_class_install_property (object_class, PROP_TYPE,
 					 g_param_spec_enum ("stmt-type", NULL, "Statement Type",
-							    GDA_SQL_PARSER_TYPE_SQL_STATEMENT_TYPE,
+							    GDA_TYPE_SQL_STATEMENT_TYPE,
 							    GDA_SQL_STATEMENT_UNKNOWN,
 							    (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)));
 }
@@ -511,12 +510,12 @@ gda_sql_builder_select_add_field (GdaSqlBuilder *builder, const gchar *field_nam
 	const GdaSqlBuilderId field_id = gda_sql_builder_add_id (builder, tmp);
 	if (alias && *alias)
 		gda_sql_builder_add_field_value_id (builder,
-					      field_id,
-					      gda_sql_builder_add_id (builder, alias));
+						    field_id,
+						    gda_sql_builder_add_id (builder, alias));
 	else
 		gda_sql_builder_add_field_value_id (builder,
-					      field_id,
-					      0);
+						    field_id,
+						    0);
 	if (table_name)
 		g_free (tmp);
 
@@ -942,7 +941,7 @@ gda_sql_builder_add_id (GdaSqlBuilder *builder, const gchar *string)
 	if (string) {
 		expr->value = gda_value_new (G_TYPE_STRING);
 		g_value_set_string (expr->value, string);
-		expr->value_is_ident = (gpointer) 0x1;
+		expr->value_is_ident = TRUE;
 	}
 
 	return add_part (builder, (GdaSqlAnyPart *) expr);
diff --git a/libgda/gda-sql-builder.h b/libgda/gda-sql-builder.h
index 90d6eb3..8d0bdd5 100644
--- a/libgda/gda-sql-builder.h
+++ b/libgda/gda-sql-builder.h
@@ -1,6 +1,5 @@
-/* gda-sql-builder.h
- *
- * Copyright (C) 2009 - 2010 Vivien Malerba
+/*
+ * Copyright (C) 2009 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -68,6 +67,42 @@ struct _GdaSqlBuilderClass
 
 typedef guint GdaSqlBuilderId;
 
+/**
+ * SECTION:gda-sql-builder
+ * @short_description: Factory object for statements
+ * @title: GdaSqlBuilder
+ * @stability: Stable
+ * @see_also: #GdaSqlParser, #GdaSqlStatement and #GdaStatement
+ *
+ * The #GdaSqlBuilder can be used to build a #GdaStatement from its structural description,
+ * much in the same way a #GdaSqlParser can be used to build a #GdaStatement from an SQL
+ * string.
+ *
+ * The #GdaSqlBuilder internally constructs a #GdaSqlStatement and uses it when requested to produce
+ * a #GdaStatement (see gda_sql_builder_get_statement()), or a #GdaSqlStatement (see
+ * gda_sql_builder_get_sql_statement()).
+ *
+ * During the building process, some pieces of the statement are constructed, and assembled into the
+ * final statement. Each of these pieces can be reused anytime in the same #GdaSqlBuilder object, and each
+ * is identified using a single unsigned integer ID. That ID is dynamically allocated by the object.
+ *
+ * The following example builds the equivalent of the <![CDATA["name='joe' AND age >= ##ageparam::int"]]> expression:
+ * <programlisting><![CDATA[
+ *GdaSqlBuilder *b=...
+ *guint id_field = gda_sql_builder_add_id (b, "name"); // build the "name" SQL identifier
+ *guint id_value = gda_sql_builder_add_expr (b, NULL, G_TYPE_STRING, "joe"); // 'joe' expression
+ *guint id_cond1 = gda_sql_builder_add_cond (b, GDA_SQL_OPERATOR_TYPE_EQ, id_field, id_value, 0); // "name='joe'"
+ *
+ *guint id_cond2 = gda_sql_builder_add_cond (b, GDA_SQL_OPERATOR_TYPE_GT,
+ *      gda_sql_builder_add_id (b, "age"), // build the "age" SQL identifier
+ *      gda_sql_builder_add_param (b, "ageparam", G_TYPE_INT, FALSE), // parameter
+ *      0);
+ *guint id_cond_and = gda_sql_builder_add_cond (b, GDA_SQL_OPERATOR_TYPE_AND, id_cond1, id_cond2, 0); // whole expression
+ *]]></programlisting>
+ *
+ * For more examples, see the <link linkend="howto-sqlbuilder">Build statements without using a parser</link> section.
+ */
+
 GType             gda_sql_builder_get_type       (void) G_GNUC_CONST;
 GdaSqlBuilder    *gda_sql_builder_new            (GdaSqlStatementType stmt_type);
 GdaStatement     *gda_sql_builder_get_statement (GdaSqlBuilder *builder, GError **error);
diff --git a/libgda/gda-statement-extra.h b/libgda/gda-statement-extra.h
index 53e6790..6307d57 100644
--- a/libgda/gda-statement-extra.h
+++ b/libgda/gda-statement-extra.h
@@ -1,6 +1,5 @@
-/* gda-statement-extra.h
- *
- * Copyright (C) 2005 - 2009 Vivien Malerba
+/*
+ * Copyright (C) 2005 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -28,17 +27,94 @@ G_BEGIN_DECLS
 /* private information to implement custom 
  * SQL renderers for GdaStatement objects
  */
-
 typedef struct _GdaSqlRenderingContext GdaSqlRenderingContext;
+
+/**
+ * GdaSqlRenderingFunc:
+ * @node: a #GdaSqlAnyPart pointer, to be cast to the correct type depending on which part the function has to render
+ * @context: the rendering context
+ * @error: a place to store errors, or %NULL
+ * @Returns: a new string, or %NULL if an error occurred
+ *
+ * Function to render any #GdaSqlAnyPart.
+ */
 typedef gchar *(*GdaSqlRenderingFunc)      (GdaSqlAnyPart *node, GdaSqlRenderingContext *context, GError **error);
+
+/**
+ * GdaSqlRenderingExpr:
+ * @expr: #GdaSqlExpr to render
+ * @context: the rendering context
+ * @is_default: pointer to a #gboolean which is set to TRUE if value should be considered as a default value
+ * @is_null: pointer to a #gboolean which is set to TRUE if value should be considered as NULL
+ * @error: a place to store errors, or %NULL
+ * @Returns: a new string, or %NULL if an error occurred
+ *
+ * Rendering function type to render a #GdaSqlExpr
+ */
 typedef gchar *(*GdaSqlRenderingExpr)      (GdaSqlExpr *expr, GdaSqlRenderingContext *context, 
 					    gboolean *is_default, gboolean *is_null, 
 					    GError **error);
+
+/**
+ * GdaSqlRenderingPSpecFunc:
+ * @pspec: #GdaSqlParamSpec to render
+ * @expr: #GdaSqlExpr which may hold the default value for the parameter, or %NULL
+ * @context: the rendering context
+ * @is_default: pointer to a #gboolean which is set to TRUE if value should be considered as a default value
+ * @is_null: pointer to a #gboolean which is set to TRUE if value should be considered as NULL
+ * @error: a place to store errors, or %NULL
+ * @Returns: a new string, or %NULL if an error occurred
+ *
+ * Rendering function type to render a #GdaSqlParamSpec
+ */
 typedef gchar *(*GdaSqlRenderingPSpecFunc) (GdaSqlParamSpec *pspec, GdaSqlExpr *expr, GdaSqlRenderingContext *context, 
 					    gboolean *is_default, gboolean *is_null, 
 					    GError **error);
+
+/**
+ * GdaSqlRenderingValue:
+ * @value: the #GValue to render
+ * @context: the rendering context
+ * @error: a place to store errors, or %NULL
+ * @Returns: a new string, or %NULL if an error occurred
+ *
+ * Rendering function type to render a #GValue
+ */
 typedef gchar *(*GdaSqlRenderingValue)     (const GValue *value, GdaSqlRenderingContext *context, GError **error);
 
+/**
+ * GdaSqlRenderingContext:
+ * @flags: Global rendering options
+ * @params: Parameters to be used while doing the rendering
+ * @params_used: When rendering is complete, contains the ordered list of parameters which have been used while doing the rendering
+ * @provider: Pointer to the server provider to be used
+ * @cnc: Pointer to the connection to be used
+ * @render_value: function to render a #GValue
+ * @render_param_spec: function to render a #GdaSqlParamSpec
+ * @render_expr: function to render a #GdaSqlExpr
+ * @render_unknown: function to render a #GdaSqlStatementUnknown
+ * @render_begin: function to render a BEGIN #GdaSqlStatementTransaction
+ * @render_rollback: function to render a ROLLBACK #GdaSqlStatementTransaction
+ * @render_commit: function to render a COMMIT #GdaSqlStatementTransaction
+ * @render_savepoint: function to render a ADD SAVEPOINT #GdaSqlStatementTransaction
+ * @render_rollback_savepoint: function to render a ROLBACK SAVEPOINT #GdaSqlStatementTransaction
+ * @render_delete_savepoint: function to render a DELETE SAVEPOINT #GdaSqlStatementTransaction
+ * @render_select: function to render a #GdaSqlStatementSelect
+ * @render_insert: function to render a #GdaSqlStatementInsert
+ * @render_delete: function to render a #GdaSqlStatementDelete
+ * @render_update: function to render a #GdaSqlStatementUpdate
+ * @render_compound: function to render a #GdaSqlStatementCompound
+ * @render_field: function to render a #GdaSqlField
+ * @render_table: function to render a #GdaSqlTable
+ * @render_function: function to render a #GdaSqlFunction
+ * @render_operation: function to render a #GdaSqlOperation
+ * @render_case: function to render a #GdaSqlCase
+ * @render_select_field: function to render a #GdaSqlSelectField
+ * @render_select_target: function to render a #GdaSqlSelectTarget
+ * @render_select_join: function to render a #GdaSqlSelectJoin
+ * @render_select_from: function to render a #GdaSqlSelectFrom
+ * @render_select_order: function to render a #GdaSqlSelectOrder
+ */
 struct _GdaSqlRenderingContext {
 	GdaStatementSqlFlag      flags;
 	GdaSet                  *params;
@@ -77,6 +153,7 @@ struct _GdaSqlRenderingContext {
 	GdaSqlRenderingFunc      render_select_from;
 	GdaSqlRenderingFunc      render_select_order;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
@@ -88,6 +165,22 @@ struct _GdaSqlRenderingContext {
 	void (*_gda_reserved8) (void);
 };
 
+/**
+ * SECTION:provider-support-sql
+ * @short_description: Adapting the SQL to the database's own SQL dialect
+ * @title: SQL rendering API
+ * @stability: Stable
+ * @see_also:
+ *
+ * &LIBGDA; is able to render a #GdaStatement statement to SQL in a generic way (as close as possible to the SQL
+ * standard). However as each database has ultimately its own SQL dialect, some parts of the rendering has
+ * to be specialized.
+ *
+ * Customization is achieved by providing custom implementations of SQL rendering functions for each kind of
+ * part in a #GdaSqlStatement structure, all packed in a #GdaSqlRenderingContext context structure. Functions
+ * which are not customized will be implemented by the default ones.
+ */
+
 gchar *gda_statement_to_sql_real (GdaStatement *stmt, GdaSqlRenderingContext *context, GError **error);
 
 G_END_DECLS
diff --git a/libgda/gda-statement.c b/libgda/gda-statement.c
index bf67838..792e2ed 100644
--- a/libgda/gda-statement.c
+++ b/libgda/gda-statement.c
@@ -1,6 +1,5 @@
-/* gda-statement.c
- *
- * Copyright (C) 2007 - 2010 Vivien Malerba
+/*
+ * Copyright (C) 2007 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -1290,7 +1289,7 @@ default_render_param_spec (GdaSqlParamSpec *pspec, GdaSqlExpr *expr, GdaSqlRende
 				     "%s", _("Unnamed parameter"));
 			goto err;
 		}
-		quoted_pname = gda_sql_identifier_add_quotes (pspec->name);
+		quoted_pname = gda_sql_identifier_force_quotes (pspec->name);
 
 		if (! (flag & (GDA_STATEMENT_SQL_PARAMS_LONG | GDA_STATEMENT_SQL_PARAMS_SHORT))) {
 			if (!expr->value || gda_value_is_null (expr->value) || strcmp (quoted_pname, pspec->name))
@@ -1315,12 +1314,12 @@ default_render_param_spec (GdaSqlParamSpec *pspec, GdaSqlExpr *expr, GdaSqlRende
 			g_string_append (string, " /* ");
 			g_string_append_printf (string, "name:%s", quoted_pname);
 			if (pspec->g_type) {
-				str = gda_sql_identifier_add_quotes (gda_g_type_to_string (pspec->g_type));
+				str = gda_sql_identifier_force_quotes (gda_g_type_to_string (pspec->g_type));
 				g_string_append_printf (string, " type:%s", str);
 				g_free (str);
 			}
 			if (pspec->descr) {
-				str = gda_sql_identifier_add_quotes (pspec->descr);
+				str = gda_sql_identifier_force_quotes (pspec->descr);
 				g_string_append_printf (string, " descr:%s", str);
 				g_free (str);
 			}
@@ -1864,7 +1863,6 @@ default_render_select_target (GdaSqlSelectTarget *target, GdaSqlRenderingContext
 {
 	GString *string;
 	gchar *str;
-	gpointer tmp;
 
 	g_return_val_if_fail (target, NULL);
 	g_return_val_if_fail (GDA_SQL_ANY_PART (target)->type == GDA_SQL_ANY_SQL_SELECT_TARGET, NULL);
@@ -1880,8 +1878,9 @@ default_render_select_target (GdaSqlSelectTarget *target, GdaSqlRenderingContext
 		g_free (str);
 	}
 	else {
+		gboolean tmp;
 		tmp = target->expr->value_is_ident;
-		target->expr->value_is_ident = (gpointer) 0x1;
+		target->expr->value_is_ident = TRUE;
 		str = context->render_expr (target->expr, context, NULL, NULL, error);
 		target->expr->value_is_ident = tmp;
 		string = g_string_new (str);
diff --git a/libgda/gda-statement.h b/libgda/gda-statement.h
index 1612d75..167eadf 100644
--- a/libgda/gda-statement.h
+++ b/libgda/gda-statement.h
@@ -1,6 +1,5 @@
-/* gda-statement.h
- *
- * Copyright (C) 2007 - 2009 Vivien Malerba
+/*
+ * Copyright (C) 2007 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -36,6 +35,16 @@ G_BEGIN_DECLS
 extern GQuark gda_statement_error_quark (void);
 #define GDA_STATEMENT_ERROR gda_statement_error_quark ()
 
+/**
+ * GdaStatementError:
+ * @GDA_STATEMENT_PARSE_ERROR: 
+ * @GDA_STATEMENT_SYNTAX_ERROR: 
+ * @GDA_STATEMENT_NO_CNC_ERROR: 
+ * @GDA_STATEMENT_CNC_CLOSED_ERROR: 
+ * @GDA_STATEMENT_EXEC_ERROR: 
+ * @GDA_STATEMENT_PARAM_TYPE_ERROR: 
+ * @GDA_STATEMENT_PARAM_ERROR: 
+ */
 typedef enum
 {
 	GDA_STATEMENT_PARSE_ERROR,
@@ -47,6 +56,16 @@ typedef enum
 	GDA_STATEMENT_PARAM_ERROR
 } GdaStatementError;
 
+/**
+ * GdaStatementModelUsage:
+ * @GDA_STATEMENT_MODEL_RANDOM_ACCESS: access to the data model will be random (usually this will result in a data model completely stored in memory)
+ * @GDA_STATEMENT_MODEL_CURSOR_FORWARD: access to the data model will be done using a cursor moving forward
+ * @GDA_STATEMENT_MODEL_CURSOR_BACKWARD: access to the data model will be done using a cursor moving backward
+ * @GDA_STATEMENT_MODEL_CURSOR: access to the data model will be done using a cursor (moving both forward and backward)
+ * @GDA_STATEMENT_MODEL_ALLOW_NOPARAM: specifies that the data model should be executed even if some parameters required to execute it are invalid (in this case the data model will have no row, and will automatically be re-run when the missing parameters are once again valid)
+ *
+ * These flags specify how the #GdaDataModel returned when executing a #GdaStatement will be used
+ */
 typedef enum {
 	GDA_STATEMENT_MODEL_RANDOM_ACCESS   = 1 << 0,
 	GDA_STATEMENT_MODEL_CURSOR_FORWARD  = 1 << 1,
@@ -55,6 +74,19 @@ typedef enum {
 	GDA_STATEMENT_MODEL_ALLOW_NOPARAM   = 1 << 3
 } GdaStatementModelUsage;
 
+/**
+ * GdaStatementSqlFlag:
+ * @GDA_STATEMENT_SQL_PARAMS_AS_VALUES: rendering will replace parameters with their values
+ * @GDA_STATEMENT_SQL_PRETTY: rendering will include newlines and indentation to make it easy to read
+ * @GDA_STATEMENT_SQL_PARAMS_LONG: parameters will be rendered using the "/&ast; name:&lt;param_name&gt; ... &ast;/" syntax
+ * @GDA_STATEMENT_SQL_PARAMS_SHORT: parameters will be rendered using the "##&lt;param_name&gt;..." syntax
+ * @GDA_STATEMENT_SQL_PARAMS_AS_COLON: parameters will be rendered using the ":&lt;param_name&gt;" syntax
+ * @GDA_STATEMENT_SQL_PARAMS_AS_DOLLAR: parameters will be rendered using the "$&lt;param_number&gt;" syntax where parameters are numbered starting from 1
+ * @GDA_STATEMENT_SQL_PARAMS_AS_QMARK: parameters will be rendered using the "?&lt;param_number&gt;" syntax where parameters are numbered starting from 1
+ * @GDA_STATEMENT_SQL_PARAMS_AS_UQMARK: parameters will be rendered using the "?" syntax
+ *
+ * Specifies rendering options
+ */
 typedef enum {
 	GDA_STATEMENT_SQL_PARAMS_AS_VALUES   = 0,
         GDA_STATEMENT_SQL_PRETTY             = 1 << 0,
@@ -82,6 +114,7 @@ struct _GdaStatementClass
 	void   (*checked)   (GdaStatement *stmt, GdaConnection *cnc, gboolean checked);
 	void   (*reset)     (GdaStatement *stmt);
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
@@ -89,6 +122,29 @@ struct _GdaStatementClass
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-statement
+ * @short_description: Single SQL statement
+ * @title: GdaStatement
+ * @stability: Stable
+ * @see_also: #GdaBatch
+ *
+ * The #GdaStatement represents a single SQL statement (multiple statements can be grouped in a #GdaBatch object).
+ *
+ *  A #GdaStatement can either be built by describing its constituing parts using a #GdaSqlBuilder object,
+ *  or from an SQL statement using a #GdaSqlParser object.
+ *
+ *  A #GdaConnection can use a #GdaStatement to:
+ *  <itemizedlist>
+ *    <listitem><para>prepare it for a future execution, the preparation step involves converting the #GdaStatement
+ *	object into a structure used by the database's own API, see gda_connection_statement_prepare()</para></listitem>
+ *    <listitem><para>execute it using gda_connection_statement_execute_select() if it is known that the statement is a
+ *	selection statement, gda_connection_statement_execute_non_select() if it is not a selection statement, or
+ *	gda_connection_statement_execute() when the type of expected result is unknown.</para></listitem>
+ *  </itemizedlist>
+ *  Note that it is possible to use the same #GdaStatement object at the same time with several #GdaConnection objects.
+ */
+
 GType               gda_statement_get_type               (void) G_GNUC_CONST;
 GdaStatement       *gda_statement_new                    (void);
 GdaStatement       *gda_statement_copy                   (GdaStatement *orig);
diff --git a/libgda/gda-transaction-status.h b/libgda/gda-transaction-status.h
index 5cda17e..56ca211 100644
--- a/libgda/gda-transaction-status.h
+++ b/libgda/gda-transaction-status.h
@@ -1,5 +1,5 @@
-/* GDA client library
- * Copyright (C) 1998 - 2006 The GNOME Foundation.
+/*
+ * Copyright (C) 1998 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Michael Lausch <michael lausch at>
@@ -41,17 +41,34 @@ typedef struct _GdaTransactionStatus        GdaTransactionStatus;
 typedef struct _GdaTransactionStatusClass   GdaTransactionStatusClass;
 typedef struct _GdaTransactionStatusEvent   GdaTransactionStatusEvent;
 
+/**
+ * GdaTransactionStatusEventType:
+ * @GDA_TRANSACTION_STATUS_EVENT_SAVEPOINT: 
+ * @GDA_TRANSACTION_STATUS_EVENT_SQL: 
+ * @GDA_TRANSACTION_STATUS_EVENT_SUB_TRANSACTION:
+ */
 typedef enum {
 	GDA_TRANSACTION_STATUS_EVENT_SAVEPOINT,
 	GDA_TRANSACTION_STATUS_EVENT_SQL,
 	GDA_TRANSACTION_STATUS_EVENT_SUB_TRANSACTION
 } GdaTransactionStatusEventType;
 
+/**
+ * GdaTransactionStatusState:
+ * @GDA_TRANSACTION_STATUS_STATE_OK:
+ * @GDA_TRANSACTION_STATUS_STATE_FAILED:
+ */
 typedef enum {
 	GDA_TRANSACTION_STATUS_STATE_OK,
 	GDA_TRANSACTION_STATUS_STATE_FAILED
 } GdaTransactionStatusState;
 
+/**
+ * GdaTransactionStatusEvent:
+ * @trans: 
+ * @type: 
+ * @conn_event:
+ */
 struct _GdaTransactionStatusEvent {
 	GdaTransactionStatus         *trans;
 	GdaTransactionStatusEventType type;
@@ -62,6 +79,7 @@ struct _GdaTransactionStatusEvent {
 	} pl;
 	GdaConnectionEvent           *conn_event;
 
+	/*< private >*/
 	gpointer  _gda_reserved1;
 	gpointer  _gda_reserved2;
 };
@@ -74,6 +92,7 @@ struct _GdaTransactionStatus {
 	GdaTransactionStatusState  state;
 	GList                     *events;
 
+	/*< private >*/
 	gpointer  _gda_reserved1;
 	gpointer  _gda_reserved2;
 };
@@ -81,6 +100,7 @@ struct _GdaTransactionStatus {
 struct _GdaTransactionStatusClass {
 	GObjectClass             parent_class;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
@@ -88,6 +108,27 @@ struct _GdaTransactionStatusClass {
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-transaction-status
+ * @short_description: Keeps track of the transaction status of a connection
+ * @title: GdaTransactionStatus
+ * @stability: Stable
+ * @see_also: #GdaConnection
+ *
+ * On any connection (as a #GdaConnection object), if the database provider used by the connection
+ * supports it, transactions may be started, committed or rolledback, or savepoints added, removed or rolledback.
+ * These operations can be performed using Libgda's API (such as gda_connection_begin_transaction()), or directly
+ * using some SQL on the connection (usually a "BEGIN;" command). The #GdaTransactionStatus's aim is to 
+ * make it easy to keep track of all the commands which have been issued on a connection regarding transactions.
+ *
+ * One #GdaTransactionStatus object is automatically attached to a #GdaConnection when a transaction is started, and
+ * is destroyed when the transaction is finished. A pointer to this object can be fetched using
+ * gda_connection_get_transaction_status() (beware that it should then not be modified). The end user is not
+ * supposed to instantiate #GdaTransactionStatus objects
+ *
+ * #GdaTransactionStatus's attributes are directly accessible using the public members of the object.
+ */
+
 GType                 gda_transaction_status_get_type (void) G_GNUC_CONST;
 GdaTransactionStatus *gda_transaction_status_new      (const gchar *name);
 
diff --git a/libgda/gda-tree-manager.h b/libgda/gda-tree-manager.h
index 921ac9e..06d1143 100644
--- a/libgda/gda-tree-manager.h
+++ b/libgda/gda-tree-manager.h
@@ -1,5 +1,5 @@
-/* GDA library
- * Copyright (C) 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 2009 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -63,8 +63,8 @@ struct _GdaTreeManagerClass {
 	 * Returns: NULL if an error occurred, and @out_error is set to TRUE
 	 */
 	GSList *(*update_children) (GdaTreeManager *manager, GdaTreeNode *node,
-                                const GSList *children_nodes,
-                                gboolean *out_error, GError **error);
+				    const GSList *children_nodes,
+				    gboolean *out_error, GError **error);
 
 	/*< private >*/
 	/* Padding for future expansion */
@@ -74,6 +74,26 @@ struct _GdaTreeManagerClass {
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-tree-manager
+ * @short_description: Base class for all the tree managers
+ * @title: GdaTreeManager
+ * @stability: Stable
+ * @see_also:
+ *
+ * A #GdaTreeManager object is responsible for creating nodes in the tree(s) for which it
+ * operates.
+ *
+ * When creating nodes, a #GdaTreeManager object can (depending on its implementation), get some
+ * named attributes from the node below which it has to create nodes, using the gda_tree_node_fetch_attribute()
+ * or gda_tree_node_get_node_attribute(). For example the #GdaTreeMgrColumns manager (which creates a node for each column
+ * of a table) needs the table name and the schema in which the table is; both can be specified using an
+ * object's property, or, if not specified that way, are fetched as attributes.
+ *
+ * The #GdaTreeManager itself is an abstract type (which can't be instantiated). Use an existing sub class or subclass
+ * it yourself.
+ */
+
 GType                  gda_tree_manager_get_type                 (void) G_GNUC_CONST;
 
 GdaTreeManager        *gda_tree_manager_new_with_func            (GdaTreeManagerNodesFunc update_func);
diff --git a/libgda/gda-tree-mgr-columns.h b/libgda/gda-tree-mgr-columns.h
index a9ccbd3..c31749e 100644
--- a/libgda/gda-tree-mgr-columns.h
+++ b/libgda/gda-tree-mgr-columns.h
@@ -1,5 +1,5 @@
-/* GDA library
- * Copyright (C) 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 2009 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -48,6 +48,26 @@ struct _GdaTreeMgrColumnsClass {
 	GdaTreeManagerClass   object_class;
 };
 
+/**
+ * SECTION:gda-tree-mgr-columns
+ * @short_description: A tree manager which creates a node for each column of a table
+ * @title: GdaTreeMgrColumns
+ * @stability: Stable
+ * @see_also:
+ *
+ * The #GdaTreeMgrColumns is a #GdaTreeManager object which creates a node for
+ * each column in a table.
+ *
+ * It uses the #GdaMetaStore associated to a #GdaConnection to get the columns list
+ * for a table designated by its name and the database schema it is in; it's up to the
+ * caller to make sure the data in the #GdaMetaStore is up to date.
+ *
+ * The #GdaConnection to be used needs to be specified when the object is created. The table
+ * name and schema can however be specified when the object is created, and if not, are
+ * fetched from the #GdaTreeNode below which the nodes will be placed (using
+ * gda_tree_node_fetch_attribute()).
+ */
+
 GType              gda_tree_mgr_columns_get_type                 (void) G_GNUC_CONST;
 GdaTreeManager*    gda_tree_mgr_columns_new                      (GdaConnection *cnc, const gchar *schema,
 								  const gchar *table_name);
diff --git a/libgda/gda-tree-mgr-label.h b/libgda/gda-tree-mgr-label.h
index c54e2ab..6445163 100644
--- a/libgda/gda-tree-mgr-label.h
+++ b/libgda/gda-tree-mgr-label.h
@@ -1,5 +1,5 @@
-/* GDA library
- * Copyright (C) 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 2009 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -48,6 +48,17 @@ struct _GdaTreeMgrLabelClass {
 	GdaTreeManagerClass   object_class;
 };
 
+/**
+ * SECTION:gda-tree-mgr-label
+ * @short_description: A tree manager which creates a single node
+ * @title: GdaTreeMgrLabel
+ * @stability: Stable
+ * @see_also:
+ *
+ * The #GdaTreeMgrLabel is a #GdaTreeManager object which creates a single node. This tree manager
+ * is useful to create "sections" in a #GdaTree hierarchy.
+ */
+
 GType              gda_tree_mgr_label_get_type                 (void) G_GNUC_CONST;
 GdaTreeManager*    gda_tree_mgr_label_new                      (const gchar *label);
 
diff --git a/libgda/gda-tree-mgr-schemas.h b/libgda/gda-tree-mgr-schemas.h
index d0a0ad9..3fbaa9b 100644
--- a/libgda/gda-tree-mgr-schemas.h
+++ b/libgda/gda-tree-mgr-schemas.h
@@ -1,5 +1,5 @@
-/* GDA library
- * Copyright (C) 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 2009 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -48,6 +48,22 @@ struct _GdaTreeMgrSchemasClass {
 	GdaTreeManagerClass   object_class;
 };
 
+/**
+ * SECTION:gda-tree-mgr-schemas
+ * @short_description: A tree manager which creates a node for each schema in a database
+ * @title: GdaTreeMgrSchemas
+ * @stability: Stable
+ * @see_also:
+ *
+ * The #GdaTreeMgrSchemas is a #GdaTreeManager object which creates a node for
+ * each schema in a database.
+ *
+ * It uses the #GdaMetaStore associated to a #GdaConnection to get the schemas list; it's up to the
+ * caller to make sure the data in the #GdaMetaStore is up to date.
+ *
+ * The #GdaConnection to be used needs to be specified when the object is created.
+ */
+
 GType              gda_tree_mgr_schemas_get_type                 (void) G_GNUC_CONST;
 GdaTreeManager*    gda_tree_mgr_schemas_new                      (GdaConnection *cnc);
 
diff --git a/libgda/gda-tree-mgr-select.h b/libgda/gda-tree-mgr-select.h
index 811eb5d..a83df28 100644
--- a/libgda/gda-tree-mgr-select.h
+++ b/libgda/gda-tree-mgr-select.h
@@ -1,5 +1,5 @@
-/* GDA library
- * Copyright (C) 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 2009 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -48,6 +48,28 @@ struct _GdaTreeMgrSelectClass {
 	GdaTreeManagerClass   object_class;
 };
 
+/**
+ * SECTION:gda-tree-mgr-select
+ * @short_description: A tree manager which creates a node for each row resulting from the execution of a SELECT statement
+ * @title: GdaTreeMgrSelect
+ * @stability: Stable
+ * @see_also:
+ *
+ * The #GdaTreeMgrSelect is a #GdaTreeManager object which executes a SELECT statement and
+ * creates a node for each row in the result.
+ *
+ * The #GdaConnection and SELECT #GdaStatement to be used need to be specified when the object is created.
+ * If the SELECT statement to be used needs some parameters, then it is possible to give values to some of them
+ * when constructing the object, but not necessary.
+ *
+ * If the SELECT statement needs some parameters which have not been provided during the construction, then
+ * these parameters will be fetched from the #GdaTreeNode below which the nodes will be placed (using
+ * gda_tree_node_fetch_attribute()).
+ *
+ * For each node created, an attribute is set for each column in the SELECT statement: the attribute name is
+ * the column name and the attribute value is the value if that column.
+ */
+
 GType              gda_tree_mgr_select_get_type                 (void) G_GNUC_CONST;
 GdaTreeManager*    gda_tree_mgr_select_new                      (GdaConnection *cnc, GdaStatement *stmt, GdaSet *params);
 
diff --git a/libgda/gda-tree-mgr-tables.h b/libgda/gda-tree-mgr-tables.h
index f22e0da..c0534ce 100644
--- a/libgda/gda-tree-mgr-tables.h
+++ b/libgda/gda-tree-mgr-tables.h
@@ -1,5 +1,5 @@
-/* GDA library
- * Copyright (C) 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 2009 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -48,6 +48,26 @@ struct _GdaTreeMgrTablesClass {
 	GdaTreeManagerClass   object_class;
 };
 
+/**
+ * SECTION:gda-tree-mgr-tables
+ * @short_description: A tree manager which creates a node for each table in a schema
+ * @title: GdaTreeMgrTables
+ * @stability: Stable
+ * @see_also:
+ *
+ * The #GdaTreeMgrTables is a #GdaTreeManager object which creates a node for
+ * each table in a database schema.
+ *
+ * It uses the #GdaMetaStore associated to a #GdaConnection to get the tables list
+ * in database schema; it's up to the
+ * caller to make sure the data in the #GdaMetaStore is up to date.
+ *
+ * The #GdaConnection to be used needs to be specified when the object is created. The
+ * schema can however be specified when the object is created, and if not, is
+ * fetched from the #GdaTreeNode below which the nodes will be placed (using
+ * gda_tree_node_fetch_attribute()).
+ */
+
 GType              gda_tree_mgr_tables_get_type                 (void) G_GNUC_CONST;
 GdaTreeManager*    gda_tree_mgr_tables_new                      (GdaConnection *cnc, const gchar *schema);
 
diff --git a/libgda/gda-tree-node.h b/libgda/gda-tree-node.h
index 970cc9d..f44a60f 100644
--- a/libgda/gda-tree-node.h
+++ b/libgda/gda-tree-node.h
@@ -1,5 +1,5 @@
-/* GDA library
- * Copyright (C) 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 2009 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -69,6 +69,21 @@ struct _GdaTreeNodeClass {
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-tree-node
+ * @short_description: A node in a #GdaTree
+ * @title: GdaTreeNode
+ * @stability: Stable
+ * @see_also:
+ *
+ * Every node in a #GdaTree tree is represented by a single #GdaTreeNode object. There is no distinction
+ * between nodes which have children and those which don't (leaf nodes).
+ *
+ * The #GdaTreeNode is very basic as it only has a "name" attribute: users are encouraged to subclass it to
+ * add more features if needed (and make use of them by defining a #GdaTreeManagerNodeFunc function and 
+ * calling gda_tree_manager_set_node_create_func()).
+ */
+
 GType              gda_tree_node_get_type          (void) G_GNUC_CONST;
 GdaTreeNode*       gda_tree_node_new               (const gchar *name);
 
diff --git a/libgda/gda-tree.h b/libgda/gda-tree.h
index d10efde..fa792db 100644
--- a/libgda/gda-tree.h
+++ b/libgda/gda-tree.h
@@ -1,5 +1,5 @@
-/* GDA library
- * Copyright (C) 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 2009 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -66,6 +66,21 @@ struct _GdaTreeClass {
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-tree
+ * @short_description: A tree-structure
+ * @title: GdaTree
+ * @stability: Stable
+ * @see_also:
+ *
+ * The #GdaTree is the top level object representing hierarchically structured data. From this object it
+ * is also possible (depending on the tree managers it uses), to clean (remove all the nodes) the whole tree,
+ * or to request a complete or partial update of the nodes.
+ *
+ * It is also possible to set attributes to the tree itself (as it is possible to do for tree nodes),
+ * or to dump the whole or part of a tree in an indented and easy to read fashion.
+ */
+
 GType              gda_tree_get_type      (void) G_GNUC_CONST;
 GdaTree*           gda_tree_new           (void);
 void               gda_tree_add_manager   (GdaTree *tree, GdaTreeManager *manager);
diff --git a/libgda/gda-util.c b/libgda/gda-util.c
index 9645950..16b1a06 100644
--- a/libgda/gda-util.c
+++ b/libgda/gda-util.c
@@ -2105,7 +2105,7 @@ gda_sql_identifier_quote (const gchar *id, GdaConnection *cnc, GdaServerProvider
 		gchar *tmp, *ptr;
 		tmp = _remove_quotes (g_strdup (id));
 		if (is_keyword (tmp)) {
-			ptr = gda_sql_identifier_add_quotes (tmp);
+			ptr = gda_sql_identifier_force_quotes (tmp);
 			g_free (tmp);
 			return ptr;
 		}
@@ -2117,7 +2117,7 @@ gda_sql_identifier_quote (const gchar *id, GdaConnection *cnc, GdaServerProvider
 				    (*ptr == '_'))
 					continue;
 				else {
-					ptr = gda_sql_identifier_add_quotes (tmp);
+					ptr = gda_sql_identifier_force_quotes (tmp);
 					g_free (tmp);
 					return ptr;
 				}
@@ -2132,7 +2132,7 @@ gda_sql_identifier_quote (const gchar *id, GdaConnection *cnc, GdaServerProvider
 					    (*ptr == '_'))
 						continue;
 					else {
-						ptr = gda_sql_identifier_add_quotes (tmp);
+						ptr = gda_sql_identifier_force_quotes (tmp);
 						g_free (tmp);
 						return ptr;
 					}
@@ -2140,7 +2140,7 @@ gda_sql_identifier_quote (const gchar *id, GdaConnection *cnc, GdaServerProvider
 				else if ((*ptr >= 'A') && (*ptr <= 'Z'))
 					*ptr += 'a' - 'A';
 				else if ((*ptr >= '0') && (*ptr <= '9') && (ptr == tmp)) {
-					ptr = gda_sql_identifier_add_quotes (tmp);
+					ptr = gda_sql_identifier_force_quotes (tmp);
 					g_free (tmp);
 					return ptr;
 				}
@@ -2155,7 +2155,7 @@ gda_sql_identifier_quote (const gchar *id, GdaConnection *cnc, GdaServerProvider
 			return g_strdup (id);
 		}
 		if (is_keyword (id) || _sql_identifier_needs_quotes (id) || force_quotes)
-			return gda_sql_identifier_add_quotes (id);
+			return gda_sql_identifier_force_quotes (id);
 		
 		/* nothing to do */
 		return g_strdup (id);
diff --git a/libgda/gda-util.h b/libgda/gda-util.h
index cd4fec1..1440896 100644
--- a/libgda/gda-util.h
+++ b/libgda/gda-util.h
@@ -1,5 +1,5 @@
-/* GDA common library
- * Copyright (C) 1998 - 2010 The GNOME Foundation.
+/*
+ * Copyright (C) 1998 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *	Rodrigo Moya <rodrigo gnome-db org>
@@ -33,6 +33,16 @@
 
 G_BEGIN_DECLS
 
+/**
+ * SECTION:gda-util
+ * @short_description: Utility functions
+ * @title: Utility functions
+ * @stability: Stable
+ * @see_also:
+ *
+ * Some usefull functions.
+ */
+
 /*
  * Type utilities
  */
diff --git a/libgda/gda-value.c b/libgda/gda-value.c
index 17f2046..3dfacd2 100644
--- a/libgda/gda-value.c
+++ b/libgda/gda-value.c
@@ -1,4 +1,4 @@
-/* GDA library
+/*
  * Copyright (C) 1998 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
@@ -569,97 +569,6 @@ gda_geometricpoint_free (gpointer boxed)
 }
 
 
-
-
-/* 
- * Register the GdaValueList type in the GType system 
- */
-static gpointer gda_value_list_copy (gpointer boxed);
-static void gda_value_list_free (gpointer boxed);
-
-static void 
-list_to_string (const GValue *src, GValue *dest) 
-{
-	gchar *str;
-	const GdaValueList *list;
-	GList *l;
-	GString *gstr = NULL;
-	
-	g_return_if_fail (G_VALUE_HOLDS_STRING (dest) &&
-			  GDA_VALUE_HOLDS_LIST (src));
-	
-	list = gda_value_get_list ((GValue *) src);
-	
-	for (l = (GList *) list; l != NULL; l = l->next) {
-		str = gda_value_stringify ((GValue *) l->data);
-		if (!gstr) {
-			gstr = g_string_new ("{ ");
-			gstr = g_string_append (gstr, str);
-		}
-		else {
-			gstr = g_string_append (gstr, ", ");
-			gstr = g_string_append (gstr, str);
-		}
-		g_free (str);
-	}
-
-	if (gstr) {
-		g_string_append (gstr, " }");
-		str = gstr->str;
-		g_string_free (gstr, FALSE);
-	}
-	else
-		str = g_strdup ("");
-	
-	g_value_take_string (dest, str);
-}
-
-GType
-gda_value_list_get_type(void)
-{
-	static GType type = 0;
-	
-	if (G_UNLIKELY (type == 0)) {
-		type = g_boxed_type_register_static ("GdaValueList",
-						     (GBoxedCopyFunc) gda_value_list_copy,
-						     (GBoxedFreeFunc) gda_value_list_free);
-		
-		g_value_register_transform_func (type, 
-						 G_TYPE_STRING,
-						 list_to_string);
-		/* FIXME: No function to transform from string to a GdaValueList */
-	}
-
-	return type;
-}
-
-static gpointer 
-gda_value_list_copy (gpointer boxed)
-{
-	GList *list = NULL;
-	const GList *values;
-	
-	values = (GList*) boxed;
-	
-	while (values) {
-		list = g_list_append (list, gda_value_copy ((GValue *) (values->data)));
-		values = values->next;
-	}
-
-	return list;
-}
-
-static void
-gda_value_list_free (gpointer boxed)
-{
-	GList *l = (GList*) boxed;
-	g_list_free (l);
-}
-
-
-
-
-
 /* 
  * Register the GdaNumeric type in the GType system 
  */
@@ -1597,41 +1506,7 @@ gda_value_set_geometric_point (GValue *value, const GdaGeometricPoint *val)
 }
 
 /**
- * gda_value_get_list:
- * @value: a #GValue whose value we want to get.
- *
- * Returns: (transfer none): the value stored in @value.
- */
-G_CONST_RETURN GdaValueList *
-gda_value_get_list (const GValue *value)
-{
-	g_return_val_if_fail (value && G_IS_VALUE (value), NULL);
-	g_return_val_if_fail (gda_value_isa (value, GDA_TYPE_LIST), NULL);
-	return (const GdaValueList *) g_value_get_boxed(value);
-}
-
-/**
- * gda_value_set_list:
- * @value: a #GValue that will store @val.
- * @val: value to be stored in @value.
- *
- * Stores @val into @value.
- */
-void
-gda_value_set_list (GValue *value, const GdaValueList *val)
-{
-	g_return_if_fail (value);
-	g_return_if_fail (val);
-
-	l_g_value_unset (value);
-	g_value_init (value, GDA_TYPE_LIST);
-	
-	/* See the implementation of GdaValueList as a GBoxed for the Copy function used by GValue*/
-	g_value_set_boxed (value, val);
-}
-
-/**
- * gda_value_set_null:
+ * gda_value_set_null
  * @value: a #GValue that will store a value of type #GDA_TYPE_NULL.
  *
  * Sets the type of @value to #GDA_TYPE_NULL.
@@ -1919,26 +1794,6 @@ gda_value_stringify (const GValue *value)
 				else
 					return g_strdup ("0000-00-00");
 			}
-			else if (type == GDA_TYPE_LIST) {
-				const GdaValueList *list;
-				const GList *ptr;
-				GString *string;
-				gchar *tmp;
-
-				string = g_string_new ("[");
-				list = gda_value_get_list (value);
-				for (ptr = list; ptr; ptr = ptr->next) {
-					tmp = gda_value_stringify ((GValue *) ptr->data);
-					if (ptr != list)
-						g_string_append_c (string, ',');
-					g_string_append (string, tmp);
-					g_free (tmp);
-				}
-				g_string_append_c (string, ']');
-				tmp = string->str;
-				g_string_free (string, FALSE);
-				return tmp;
-			}
 			else
 				return g_strdup ("");
 		}
@@ -2037,16 +1892,6 @@ gda_value_differ (const GValue *value1, const GValue *value2)
 			return -1;
 	}
 
-	else if (type == GDA_TYPE_LIST) {
-		GList *l1, *l2;
-		for (l1 = (GList*) gda_value_get_list (value1), l2 = (GList*) gda_value_get_list (value2); 
-		     l1 != NULL && l2 != NULL; l1 = l1->next, l2 = l2->next){
-			if (gda_value_differ ((GValue *) l1->data, (GValue *) l2->data))
-				return 1;
-		}
-		return 0;
-	}
-
 	else if (type == GDA_TYPE_NUMERIC) {
 		const GdaNumeric *num1, *num2;
 		num1= gda_value_get_numeric (value1);
@@ -2134,7 +1979,6 @@ gda_value_differ (const GValue *value1, const GValue *value2)
 gint
 gda_value_compare (const GValue *value1, const GValue *value2)
 {
-	GList *l1, *l2;
 	gint retval;
 	GType type;
 
@@ -2252,21 +2096,6 @@ gda_value_compare (const GValue *value1, const GValue *value2)
 	else if (type == G_TYPE_INT)
 		return g_value_get_int (value1) - g_value_get_int (value2);
 
-	else if (type == GDA_TYPE_LIST) {
-		retval = 0;
-		for (l1 = (GList*) gda_value_get_list (value1), l2 = (GList*) gda_value_get_list (value2); 
-		     l1 != NULL && l2 != NULL; l1 = l1->next, l2 = l2->next){
-			retval = gda_value_compare ((GValue *) l1->data,
-						    (GValue *) l2->data);
-			if (retval != 0) 
-				return retval;
-		}
-		if (retval == 0 && (l1 == NULL || l2 == NULL) && l1 != l2)
-			retval = (l1 == NULL) ? -1 : 1;
-		
-		return retval;
-	}
-
 	else if (type == GDA_TYPE_NUMERIC) {
 		const GdaNumeric *num1, *num2;
 		num1= gda_value_get_numeric (value1);
diff --git a/libgda/gda-value.h b/libgda/gda-value.h
index ac1d5d5..5b2cbc2 100644
--- a/libgda/gda-value.h
+++ b/libgda/gda-value.h
@@ -1,5 +1,5 @@
-/* GDA library
- * Copyright (C) 1998 - 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 1998 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *	Michael Lausch <michael lausch at>
@@ -41,7 +41,6 @@ G_BEGIN_DECLS
 #define	GDA_TYPE_BINARY (gda_binary_get_type())
 #define GDA_TYPE_BLOB (gda_blob_get_type())
 #define	GDA_TYPE_GEOMETRIC_POINT (gda_geometricpoint_get_type())
-#define	GDA_TYPE_LIST (gda_value_list_get_type())
 #define	GDA_TYPE_NUMERIC (gda_numeric_get_type())
 #define	GDA_TYPE_SHORT (gda_short_get_type()) 
 #define	GDA_TYPE_USHORT (gda_ushort_get_type())
@@ -53,25 +52,45 @@ G_BEGIN_DECLS
 #define GDA_VALUE_HOLDS_BINARY(value)          G_VALUE_HOLDS(value, GDA_TYPE_BINARY)
 #define GDA_VALUE_HOLDS_BLOB(value)            G_VALUE_HOLDS(value, GDA_TYPE_BLOB)
 #define GDA_VALUE_HOLDS_GEOMETRIC_POINT(value) G_VALUE_HOLDS(value, GDA_TYPE_GEOMETRIC_POINT)
-#define GDA_VALUE_HOLDS_LIST(value)            G_VALUE_HOLDS(value, GDA_TYPE_LIST)
 #define GDA_VALUE_HOLDS_NUMERIC(value)         G_VALUE_HOLDS(value, GDA_TYPE_NUMERIC)
 #define GDA_VALUE_HOLDS_SHORT(value)           G_VALUE_HOLDS(value, GDA_TYPE_SHORT)
 #define GDA_VALUE_HOLDS_USHORT(value)          G_VALUE_HOLDS(value, GDA_TYPE_USHORT)
 #define GDA_VALUE_HOLDS_TIME(value)            G_VALUE_HOLDS(value, GDA_TYPE_TIME)
 #define GDA_VALUE_HOLDS_TIMESTAMP(value)       G_VALUE_HOLDS(value, GDA_TYPE_TIMESTAMP)
 
+/**
+ * GdaGeometricPoint:
+ * @x:
+ * @y:
+ */
 typedef struct {
 	gdouble x;
 	gdouble y;
 } GdaGeometricPoint;
 
+/**
+ * GdaNumeric:
+ * @number:
+ * @precision:
+ * @width:
+ */
 typedef struct {
 	gchar   *number;
 	glong    precision;
 	glong    width;
+	
+	/*< private >*/
 	gpointer reserved; /* reserved for future usage with GMP (http://gmplib.org/) */
 } GdaNumeric;
 
+/**
+ * GdaTime:
+ * @hour: 
+ * @minute: 
+ * @second: 
+ * @fraction: 
+ * @timezone: 
+ */
 typedef struct {
 	gushort hour;
 	gushort minute;
@@ -80,6 +99,17 @@ typedef struct {
 	glong   timezone;	/* # of seconds to the east UTC */
 } GdaTime;
 
+/**
+ * GdaTimestamp:
+ * @year: representation of the date
+ * @month: month representation of the date, as a number between 1 and 12
+ * @day: day representation of the date, as a number between 1 and 31
+ * @hour: 
+ * @minute: 
+ * @second: 
+ * @fraction: 
+ * @timezone:
+ */
 typedef struct {
 	gshort  year;
 	gushort month;
@@ -91,6 +121,11 @@ typedef struct {
 	glong   timezone;	/* # of seconds to the east UTC */
 } GdaTimestamp;
 
+/**
+ * GdaBinary:
+ * @data:
+ * @binary_length:
+ */
 typedef struct {
 	guchar *data;
 	glong   binary_length;
@@ -110,10 +145,42 @@ typedef struct {
 	GdaBlobOp *op;
 } GdaBlob;
 
-typedef GList GdaValueList;
-
 #define gda_value_isa(value, type) (G_VALUE_HOLDS(value, type))
 
+/**
+ * SECTION:gda-value
+ * @short_description: Assorted functions for dealing with #GValue values
+ * @title: A single Value
+ * @stability: Stable
+ * @see_also: #GValue and #GdaBlobOp
+ *
+ * &LIBGDA; manages each individual value within an opaque #GValue structure. Any GValue type can be used,
+ * and &LIBGDA; adds a few more data types usually found in DBMS such as NUMERIC, TIME, TIMESTAMP, GEOMETRIC POINT, BINARY and BLOB.
+ *
+ * Libgda makes a distinction between binary and blob types
+ * <itemizedlist>
+ *   <listitem><para>binary data can be inserted into an SQL statement using a
+ *	(DBMS dependent) syntax, such as "X'ABCD'" syntax for SQLite or the binary strings syntax for PostgreSQL. Binary data
+ *	is manipulated using a #GdaBinary structure (which is basically a bytes buffer and a length attribute).
+ *   </para></listitem>
+ *   <listitem><para>blob data are a special feature that some DBMS have which requires some non SQL code to manipulate them.
+ *	Usually only a reference is stored in each table containing a blob, and the actual blob data resides somewhere on the disk
+ *	(while still being managed transparently by the database). For example PotsgreSQL stores blobs as files on the disk and
+ *	references them using object identifiers (Oid). Blob data
+ *	is manipulated using a #GdaBlob structure which encapsulates a #GdaBinary structure and adds a reference to a
+ *	#GdaBlobOp object used to read and write data from and to the blob.
+ *   </para></listitem>
+ * </itemizedlist>
+ * Please note that is distinction between binary data and blobs is Libgda only and does not reflect the DBMS's documentations; 
+ * for instance MySQL has several BLOB types but Libgda interprets them as binary types.
+ *
+ * Each provider or connection can be queried about its blob support using the gda_server_provider_supports_feature() or
+ * gda_connection_supports_feature() methods.
+ *
+ * The NULL value is a special case value: it is represented by to a zero-filled (uninitialized) #GValue and has a type equal
+ * to %GDA_TYPE_NULL.
+ */
+
 GValue                           *gda_value_new (GType type);
 
 GValue                           *gda_value_new_binary (const guchar *val, glong size);
@@ -142,8 +209,6 @@ void                              gda_value_take_blob (GValue *value, GdaBlob *b
 
 G_CONST_RETURN GdaGeometricPoint *gda_value_get_geometric_point (const GValue *value);
 void                              gda_value_set_geometric_point (GValue *value, const GdaGeometricPoint *val);
-G_CONST_RETURN GdaValueList      *gda_value_get_list (const GValue *value);
-void                              gda_value_set_list (GValue *value, const GdaValueList *val);
 void                              gda_value_set_null (GValue *value);
 G_CONST_RETURN GdaNumeric        *gda_value_get_numeric (const GValue *value);
 void                              gda_value_set_numeric (GValue *value, const GdaNumeric *val);
@@ -206,11 +271,17 @@ gpointer                          gda_blob_copy (gpointer boxed);
 void                              gda_blob_free (gpointer boxed);
 void                              gda_blob_set_op (GdaBlob *blob, GdaBlobOp *op);
 
-GType                             gda_value_list_get_type (void) G_GNUC_CONST;
 GType                             gda_short_get_type (void) G_GNUC_CONST;
 GType                             gda_ushort_get_type (void) G_GNUC_CONST;
 
 /* Helper macros */
+/**
+ * gda_value_new_null:
+ * 
+ * Creates a new #GValue of type %GDA_TYPE_NULL representing a NULL value
+ *
+ * Returns: (transfer full): a new #GValue
+ */
 #define                           gda_value_new_null() (g_new0 (GValue, 1))
 
 G_END_DECLS
diff --git a/libgda/gda-xa-transaction.h b/libgda/gda-xa-transaction.h
index 8ba5698..e5ea3e8 100644
--- a/libgda/gda-xa-transaction.h
+++ b/libgda/gda-xa-transaction.h
@@ -1,5 +1,5 @@
-/* GDA library
- * Copyright (C) 2008 - 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 2008 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -67,13 +67,53 @@ struct _GdaXaTransactionClass {
 	void (*_gda_reserved4) (void);
 };
 
+
+/**
+ * GdaXaTransactionId:
+ * @format: any number
+ * @gtrid_length: number between 1 and 64
+ * @bqual_length: number between 1 and 64
+ * @data:
+ */
 struct _GdaXaTransactionId {
-	guint32  format;       /* any number */
-	gushort  gtrid_length; /* 1-64 */
-	gushort  bqual_length; /* 1-64 */
+	guint32  format;
+	gushort  gtrid_length;
+	gushort  bqual_length;
 	char     data [128];
 };
 
+/**
+ * SECTION:gda-xa-transaction
+ * @short_description: Distributed transaction manager
+ * @title: GdaXaTransaction
+ * @stability: Stable
+ * @see_also:
+ *
+ * The #GdaXaTransaction object acts as a distributed transaction manager: to make sure local transactions on several
+ * connections (to possibly different databases and database types) either all succeed or all fail. For more information,
+ * see the X/Open CAE document Distributed Transaction Processing: The XA Specification. 
+ * This document is published by The Open Group and available at 
+ * <ulink url="http://www.opengroup.org/public/pubs/catalog/c193.htm";>http://www.opengroup.org/public/pubs/catalog/c193.htm</ulink>.
+ *
+ * The two phases commit protocol is implemented during the execution of a distributed transaction: modifications
+ * made on any connection are first <emphasis>prepared</emphasis> (which means that they are store in the database), and
+ * if that phase succeeded for all the involved connections, then the <emphasis>commit</emphasis> phase is executed
+ * (where all the data previously stored during the <emphasis>prepare</emphasis> phase are actually committed).
+ * That second phase may actually fail, but the distributed transaction will still be considered as sucessfull
+ * as the data stored during the <emphasis>prepare</emphasis> phase can be committed afterwards.
+ *
+ * A distributed transaction involves the following steps:
+ * <orderedlist>
+ *   <listitem><para>Create a #GdaXaTransaction object</para></listitem>
+ *   <listitem><para>Register the connections which will be part of the distributed transaction with that object
+ *	using gda_xa_transaction_register_connection()</para></listitem>
+ *   <listitem><para>Beging the distributed transaction using gda_xa_transaction_begin()</para></listitem>
+ *   <listitem><para>Work individually on each connection as normally (make modifications)</para></listitem>
+ *   <listitem><para>Commit the distributed transaction using gda_xa_transaction_commit()</para></listitem>
+ *   <listitem><para>Discard the #GdaXaTransaction object using g_object_unref()</para></listitem>
+ * </orderedlist>
+ */
+
 GType                     gda_xa_transaction_get_type             (void) G_GNUC_CONST;
 GdaXaTransaction         *gda_xa_transaction_new                  (guint32 format, const gchar *global_transaction_id);
 
diff --git a/libgda/handlers/Makefile.am b/libgda/handlers/Makefile.am
index 72dc315..eaf040d 100644
--- a/libgda/handlers/Makefile.am
+++ b/libgda/handlers/Makefile.am
@@ -1,4 +1,4 @@
-noinst_LTLIBRARIES = libgda_handlers-4.0.la
+noinst_LTLIBRARIES = libgda_handlers-5.0.la
 
 AM_CPPFLAGS = \
         -I$(top_srcdir) -I$(srcdir)/.. \
@@ -17,7 +17,7 @@ libgda_handlers_headers = \
 libgda_handlersincludedir=$(includedir)/libgda-$(GDA_ABI_MAJOR_VERSION).$(GDA_ABI_MINOR_VERSION)/libgda/handlers
 libgda_handlersinclude_HEADERS=$(libgda_handlers_headers)
 
-libgda_handlers_4_0_la_SOURCES = \
+libgda_handlers_5_0_la_SOURCES = \
 	$(libgda_handlers_headers) \
 	gda-handler-bin.c \
 	gda-handler-boolean.c \
diff --git a/libgda/handlers/gda-handler-bin.h b/libgda/handlers/gda-handler-bin.h
index 6785486..25dc8ed 100644
--- a/libgda/handlers/gda-handler-bin.h
+++ b/libgda/handlers/gda-handler-bin.h
@@ -1,6 +1,5 @@
-/* gda-handler-bin.h
- *
- * Copyright (C) 2005 - 2009 Vivien Malerba
+/*
+ * Copyright (C) 2005 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -47,11 +46,22 @@ struct _GdaHandlerBinClass
 {
 	GObjectClass        parent_class;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
 };
 
+/**
+ * SECTION:gda-handler-bin
+ * @short_description: Default handler for binary values
+ * @title: GdaHanderBin
+ * @stability: Stable
+ * @see_also: #GdaDataHandler interface
+ *
+ * You should normally not need to use this API, refer to the #GdaDataHandler
+ * interface documentation for more information.
+ */
 
 GType           gda_handler_bin_get_type      (void) G_GNUC_CONST;
 GdaDataHandler *gda_handler_bin_new           (void);
diff --git a/libgda/handlers/gda-handler-boolean.h b/libgda/handlers/gda-handler-boolean.h
index 3c8e1c9..a036fcf 100644
--- a/libgda/handlers/gda-handler-boolean.h
+++ b/libgda/handlers/gda-handler-boolean.h
@@ -1,6 +1,5 @@
-/* gda-handler-boolean.h
- *
- * Copyright (C) 2003 - 2009 Vivien Malerba
+/*
+ * Copyright (C) 2003 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -47,11 +46,22 @@ struct _GdaHandlerBooleanClass
 {
 	GObjectClass           parent_class;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
 };
 
+/**
+ * SECTION:gda-handler-boolean
+ * @short_description: Default handler for boolean values
+ * @title: GdaHanderBoolean
+ * @stability: Stable
+ * @see_also: #GdaDataHandler interface
+ *
+ * You should normally not need to use this API, refer to the #GdaDataHandler
+ * interface documentation for more information.
+ */
 
 GType           gda_handler_boolean_get_type      (void) G_GNUC_CONST;
 GdaDataHandler *gda_handler_boolean_new           (void);
diff --git a/libgda/handlers/gda-handler-numerical.h b/libgda/handlers/gda-handler-numerical.h
index 4fc7b66..ce85021 100644
--- a/libgda/handlers/gda-handler-numerical.h
+++ b/libgda/handlers/gda-handler-numerical.h
@@ -1,6 +1,5 @@
-/* gda-handler-numerical.h
- *
- * Copyright (C) 2003 - 2009 Vivien Malerba
+/*
+ * Copyright (C) 2003 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -48,11 +47,22 @@ struct _GdaHandlerNumericalClass
 {
 	GObjectClass              parent_class;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
 };
 
+/**
+ * SECTION:gda-handler-numerical
+ * @short_description: Default handler for numeric values
+ * @title: GdaHanderNumerical
+ * @stability: Stable
+ * @see_also: #GdaDataHandler interface
+ *
+ * You should normally not need to use this API, refer to the #GdaDataHandler
+ * interface documentation for more information.
+ */
 
 GType           gda_handler_numerical_get_type      (void) G_GNUC_CONST;
 GdaDataHandler *gda_handler_numerical_new           (void);
diff --git a/libgda/handlers/gda-handler-string.h b/libgda/handlers/gda-handler-string.h
index 4b0082f..da79d75 100644
--- a/libgda/handlers/gda-handler-string.h
+++ b/libgda/handlers/gda-handler-string.h
@@ -1,6 +1,5 @@
-/* gda-handler-string.h
- *
- * Copyright (C) 2003 - 2009 Vivien Malerba
+/*
+ * Copyright (C) 2003 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -47,11 +46,22 @@ struct _GdaHandlerStringClass
 {
 	GObjectClass           parent_class;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
 };
 
+/**
+ * SECTION:gda-handler-string
+ * @short_description: Default handler for string values
+ * @title: GdaHanderString
+ * @stability: Stable
+ * @see_also: #GdaDataHandler interface
+ *
+ * You should normally not need to use this API, refer to the #GdaDataHandler
+ * interface documentation for more information.
+ */
 
 GType           gda_handler_string_get_type          (void) G_GNUC_CONST;
 GdaDataHandler *gda_handler_string_new               (void);
diff --git a/libgda/handlers/gda-handler-time.h b/libgda/handlers/gda-handler-time.h
index 2afd2c1..8702004 100644
--- a/libgda/handlers/gda-handler-time.h
+++ b/libgda/handlers/gda-handler-time.h
@@ -1,6 +1,5 @@
-/* gda-handler-time.h
- *
- * Copyright (C) 2003 - 2009 Vivien Malerba
+/*
+ * Copyright (C) 2003 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -47,11 +46,22 @@ struct _GdaHandlerTimeClass
 {
 	GObjectClass         parent_class;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
 };
 
+/**
+ * SECTION:gda-handler-time
+ * @short_description: Default handler for time values
+ * @title: GdaHanderTime
+ * @stability: Stable
+ * @see_also: #GdaDataHandler interface
+ *
+ * You should normally not need to use this API, refer to the #GdaDataHandler
+ * interface documentation for more information.
+ */
 
 GType           gda_handler_time_get_type      (void) G_GNUC_CONST;
 GdaDataHandler *gda_handler_time_new           (void);
diff --git a/libgda/handlers/gda-handler-type.h b/libgda/handlers/gda-handler-type.h
index d453584..aaa09bb 100644
--- a/libgda/handlers/gda-handler-type.h
+++ b/libgda/handlers/gda-handler-type.h
@@ -1,6 +1,5 @@
-/* gda-handler-type.h
- *
- * Copyright (C) 2005 - 2009 Vivien Malerba
+/*
+ * Copyright (C) 2005 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -47,11 +46,22 @@ struct _GdaHandlerTypeClass
 {
 	GObjectClass        parent_class;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
 };
 
+/**
+ * SECTION:gda-handler-type
+ * @short_description: Default handler for GType values
+ * @title: GdaHanderType
+ * @stability: Stable
+ * @see_also: #GdaDataHandler interface
+ *
+ * You should normally not need to use this API, refer to the #GdaDataHandler
+ * interface documentation for more information.
+ */
 
 GType           gda_handler_type_get_type      (void) G_GNUC_CONST;
 GdaDataHandler *gda_handler_type_new           (void);
diff --git a/libgda/libgda.h.in b/libgda/libgda.h.in
index 2e384d4..c90f9b0 100644
--- a/libgda/libgda.h.in
+++ b/libgda/libgda.h.in
@@ -1,5 +1,5 @@
-/* GDA library
- * Copyright (C) 1998 - 2008 The GNOME Foundation.
+/*
+ * Copyright (C) 1998 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Michael Lausch <michael lausch at>
@@ -27,7 +27,6 @@
 #define __LIBGDA_H__
 
 #include <libgda/gda-attributes-manager.h>
-#include <libgda/gda-easy.h>
 #include <libgda/gda-column.h>
 #include <libgda/gda-config.h>
 #include <libgda/gda-connection-event.h>
@@ -88,6 +87,14 @@
 
 G_BEGIN_DECLS
 
+/**
+ * SECTION:libgda
+ * @short_description: Library initialization and information
+ * @title: Library initialization
+ * @stability: Stable
+ * @see_also:
+ */
+
 void gda_init (void);
 void gda_locale_changed (void);
 gchar *gda_get_application_exec_path (const gchar *app_name);
diff --git a/libgda/libgda.symbols b/libgda/libgda.symbols
index ba28244..60a7624 100644
--- a/libgda/libgda.symbols
+++ b/libgda/libgda.symbols
@@ -113,7 +113,6 @@
 	gda_connection_event_get_source
 	gda_connection_event_get_sqlstate
 	gda_connection_event_get_type
-	gda_connection_event_new
 	gda_connection_event_set_code
 	gda_connection_event_set_description
 	gda_connection_event_set_event_type
@@ -327,25 +326,18 @@
 	gda_data_select_take_row
 	gda_default_escape_string
 	gda_default_unescape_string
-	gda_delete_row_from_table
 	gda_diff_type_get_type
 	gda_dir_blob_get_filename
 	gda_dir_blob_op_get_type
 	gda_dir_blob_op_new
 	gda_dir_blob_set_filename
 	gda_dsn_split
-	gda_easy_create_table_flag_get_type
-	gda_easy_error_get_type
-	gda_easy_error_quark
-	gda_execute_non_select_command
-	gda_execute_select_command
 	gda_gbr_get_file_path
 	gda_gbr_init
 	gda_geometricpoint_copy
 	gda_geometricpoint_free
 	gda_geometricpoint_get_type
 	gda_get_application_exec_path
-	gda_get_default_handler
 	gda_g_type_from_string
 	gda_g_type_to_string
 	gda_handler_bin_get_type
@@ -399,8 +391,6 @@
 	gda_identifier_equal
 	gda_identifier_hash
 	gda_init
-	gda_insert_row_into_table
-	gda_insert_row_into_table_v
 	gda_lang_locale
 	gda_locale_changed
 	gda_lockable_get_type
@@ -472,15 +462,6 @@
 	gda_parse_iso8601_date
 	gda_parse_iso8601_time
 	gda_parse_iso8601_timestamp
-	gda_parse_sql_string
-	gda_perform_create_database
-	gda_perform_create_table
-	gda_perform_drop_database
-	gda_perform_drop_table
-	gda_prepare_create_database
-	gda_prepare_create_table
-	gda_prepare_drop_database
-	gda_prepare_drop_table
 	gda_pstmt_copy_contents
 	gda_pstmt_get_gda_statement
 	gda_pstmt_get_type
@@ -556,13 +537,11 @@
 	gda_server_provider_get_data_handler_g_type
 	gda_server_provider_get_default_dbms_type
 	gda_server_provider_get_name
-	gda_server_provider_get_schema_nb_columns
 	gda_server_provider_get_server_version
 	gda_server_provider_get_type
 	gda_server_provider_get_version
 	gda_server_provider_handler_declare
 	gda_server_provider_handler_find
-	gda_server_provider_init_schema_model
 	gda_server_provider_internal_get_parser
 	gda_server_provider_load_file_contents
 	gda_server_provider_perform_operation
@@ -571,7 +550,6 @@
 	gda_server_provider_string_to_value
 	gda_server_provider_supports_feature
 	gda_server_provider_supports_operation
-	gda_server_provider_test_schema_model
 	gda_server_provider_unescape_string
 	gda_server_provider_value_to_sql_string
 	gda_set_add_holder
@@ -647,7 +625,6 @@
 	gda_sql_delimiterTrace
 	gda_sql_error_get_type
 	gda_sql_error_quark
-	gda_sql_error_type_get_type
 	gda_sql_expr_copy
 	gda_sql_expr_free
 	gda_sql_expr_get_type
@@ -665,10 +642,9 @@
 	gda_sql_function_serialize
 	gda_sql_function_take_args_list
 	gda_sql_function_take_name
-	gda_sql_identifier_add_quotes
-	gda_sql_identifier_needs_quotes
+	gda_sql_identifier_force_quotes
+	gda_sql_identifier_prepare_for_compare
 	gda_sql_identifier_quote
-	gda_sql_identifier_remove_quotes
 	gda_sql_identifier_split
 	gda_sql_identifier_style_get_type
 	gda_sqlite_provider_get_type
@@ -876,8 +852,6 @@
 	gda_tree_set_attribute
 	gda_tree_update_all
 	gda_tree_update_part
-	gda_update_row_in_table
-	gda_update_row_in_table_v
 	gda_ushort_get_type
 	gda_utility_check_data_model
 	gda_utility_data_model_dump_data_to_xml
@@ -899,7 +873,6 @@
 	gda_value_get_ushort
 	gda_value_is_null
 	gda_value_is_number
-	gda_value_list_get_type
 	gda_value_new
 	gda_value_new_binary
 	gda_value_new_blob
diff --git a/libgda/providers-support/gda-data-select-priv.h b/libgda/providers-support/gda-data-select-priv.h
index a05501b..d22c695 100644
--- a/libgda/providers-support/gda-data-select-priv.h
+++ b/libgda/providers-support/gda-data-select-priv.h
@@ -1,5 +1,5 @@
-/* GDA common library
- * Copyright (C) 2008 The GNOME Foundation.
+/*
+ * Copyright (C) 2008 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -31,6 +31,27 @@
 
 G_BEGIN_DECLS
 
+/**
+ * SECTION:gda-data-select-priv
+ * @short_description: Base class for all the data models returned by DBMS providers when a SELECT statement is executed
+ * @title: Subclassing GdaDataSelect
+ * @stability: Stable
+ * @see_also: #GdaDataModel and #GdaDataSelect
+ *
+ * All database providers should subclass this class when returning a data model after the execution of a SELECT
+ *  statement. Specifically it has the following features:
+ *  <itemizedlist>
+ *    <listitem><para>Manages its list of <link linkend="GdaColumn">GdaColumn</link> using the list exported by the prepared statement object (<link linkend="GdaPStmt">GdaPStmt</link>)</para></listitem>
+ *    <listitem><para>Allows random or cursor based access</para></listitem>
+ *    <listitem><para>Allows for efficient memory usage allowing the subclass to finely tune its memory usage</para></listitem>
+ *    <listitem><para>Provides a generic mechanism for writable data models</para></listitem>
+ *  </itemizedlist>
+ *
+ *  See the <link linkend="libgda-provider-recordset">Virtual methods for recordsets</link> section for more information
+ *  about how to implement the virtual methods of the subclassed object.
+ *
+ *  This section documents the methods available for the database provider's implementations.
+ */
 
 GType          gda_data_select_get_type                     (void) G_GNUC_CONST;
 
diff --git a/libgda/providers-support/gda-pstmt.h b/libgda/providers-support/gda-pstmt.h
index c0c91a3..6e87cbc 100644
--- a/libgda/providers-support/gda-pstmt.h
+++ b/libgda/providers-support/gda-pstmt.h
@@ -1,5 +1,5 @@
-/* GDA common library
- * Copyright (C) 2008 The GNOME Foundation.
+/*
+ * Copyright (C) 2008 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -59,6 +59,7 @@ struct _GdaPStmt {
 struct _GdaPStmtClass {
 	GObjectClass  parent_class;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
@@ -66,6 +67,34 @@ struct _GdaPStmtClass {
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-pstmt
+ * @short_description: Base class for prepared statement's
+ * @title: GdaPstmt
+ * @stability: Stable
+ * @see_also:
+ *
+ * The #GdaPStmt represents the association between a #GdaStatement statement and a <emphasis>prepared statement</emphasis>
+ * which is database dependent and is an in-memory representation of a statement. Using prepared statement has the
+ * following advantages:
+ * <itemizedlist>
+ *   <listitem><para>the parsing of the SQL has to be done only once, which improves performances if the statement
+ *	has to be executed more than once</para></listitem>
+ *   <listitem><para>if a statement has been prepared, then it means it is syntactically correct and has been
+ *	<emphasis>understood</emphasis> by the database's API</para></listitem>
+ *   <listitem><para>it is possible to use variables in prepared statement which eliminates the risk
+ *	of SQL code injection</para></listitem>
+ * </itemizedlist>
+ *
+ * The #GdaPStmt is not intended to be instantiated, but subclassed by database provider's implementation.
+ * Once created, the database provider's implementation can decide to associate (for future lookup) to
+ * a #GdaStatement object in a connection using gda_connection_add_prepared_statement().
+ *
+ * The #GdaPStmt object can keep a reference to the #GdaStatement object (which can be set and get using
+ * the gda_pstmt_set_gda_statement() and gda_pstmt_get_gda_statement()), however that reference
+ * if a weak one (which means it will be lost if the #GdaStatement object is destroyed).
+ */
+
 GType         gda_pstmt_get_type          (void) G_GNUC_CONST;
 void          gda_pstmt_set_gda_statement (GdaPStmt *pstmt, GdaStatement *stmt);
 void          gda_pstmt_copy_contents     (GdaPStmt *src, GdaPStmt *dest);
diff --git a/libgda/sql-parser/Makefile.am b/libgda/sql-parser/Makefile.am
index af398fb..12aee64 100644
--- a/libgda/sql-parser/Makefile.am
+++ b/libgda/sql-parser/Makefile.am
@@ -1,4 +1,4 @@
-noinst_LTLIBRARIES = libgda_sql_parser-4.0.la
+noinst_LTLIBRARIES = libgda_sql_parser-5.0.la
 noinst_PROGRAMS = 
 
 AM_CPPFLAGS = \
@@ -50,7 +50,6 @@ s-enum-types-h: @REBUILD@ $(libgda_sql_parser_headers) Makefile
 		$(libgda_sql_parser_headers)) > tmp-gda-enum-types.h \
 	&& (cmp -s tmp-gda-enum-types.h gda-sql-parser-enum-types.h || cp tmp-gda-enum-types.h gda-sql-parser-enum-types.h ) \
 	&& rm -f tmp-gda-enum-types.h	\
-	&& cat $(srcdir)/gda-sql-parser-enum-types.h.KEEPAPI >> gda-sql-parser-enum-types.h \
 	&& echo timestamp > $(@F)
 
 gda-sql-parser-enum-types.c: s-enum-types-c
@@ -68,7 +67,6 @@ s-enum-types-c: @REBUILD@ $(libgda_sql_parser_headers) Makefile
 		$(libgda_sql_parser_headers)) > tmp-gda-enum-types.c \
 	&& (cmp -s tmp-gda-enum-types.c gda-sql-parser-enum-types.c || cp tmp-gda-enum-types.c gda-sql-parser-enum-types.c ) \
 	&& rm -f tmp-gda-enum-types.c \
-	&& cat $(srcdir)/gda-sql-parser-enum-types.c.KEEPAPI >> gda-sql-parser-enum-types.c \
 	&& echo timestamp > $(@F)
 
 # Generate the enums source code, with glib-mkenums:
@@ -76,11 +74,11 @@ s-enum-types-c: @REBUILD@ $(libgda_sql_parser_headers) Makefile
 libgda_sql_parser_built_headers = gda-sql-parser-enum-types.h
 libgda_sql_parser_built_cfiles = gda-sql-parser-enum-types.c
 
-$(OBJECTS) $(libgda_sql_parser_4_0_la_OBJECTS): token_types.h
+$(OBJECTS) $(libgda_sql_parser_5_0_la_OBJECTS): token_types.h
 libgda_sql_parserincludedir=$(includedir)/libgda-$(GDA_ABI_MAJOR_VERSION).$(GDA_ABI_MINOR_VERSION)/libgda/sql-parser
 libgda_sql_parserinclude_HEADERS=$(libgda_sql_parser_headers) $(libgda_sql_parser_built_headers)
 
-libgda_sql_parser_4_0_la_SOURCES = \
+libgda_sql_parser_5_0_la_SOURCES = \
 	$(libgda_sql_parser_headers) \
 	$(libgda_sql_parser_built_headers) \
 	$(libgda_sql_parser_built_cfiles) \
@@ -103,8 +101,7 @@ libgda_sql_parser_4_0_la_SOURCES = \
         gda-statement-struct-unknown.c \
         gda-statement-struct-util.c
 
-EXTRA_DIST= parser.y delimiter.y lemon.c lempar.c gen_def.c parser_tokens.h \
-	gda-sql-parser-enum-types.c.KEEPAPI gda-sql-parser-enum-types.h.KEEPAPI
+EXTRA_DIST= parser.y delimiter.y lemon.c lempar.c gen_def.c parser_tokens.h
 
 CLEANFILES = parser.h parser.c parser.out delimiter.h delimiter.c delimiter.out token_types.h \
 	lemon$(EXEEXT_FOR_BUILD) gen_def$(EXEEXT_FOR_BUILD) \
diff --git a/libgda/sql-parser/gda-sql-parser.h b/libgda/sql-parser/gda-sql-parser.h
index a970177..380ad8b 100644
--- a/libgda/sql-parser/gda-sql-parser.h
+++ b/libgda/sql-parser/gda-sql-parser.h
@@ -1,6 +1,5 @@
-/* gda-sql-parser.h
- *
- * Copyright (C) 2007 Vivien Malerba
+/*
+ * Copyright (C) 2007 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -72,6 +71,7 @@ typedef struct _GdaSqlParserIface
 	GdaSqlParser    *parser;
 	GdaSqlStatement *parsed_statement;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	gpointer         _gda_reserved1;
 	gpointer         _gda_reserved2;
@@ -95,6 +95,7 @@ struct _GdaSqlParserClass
 	void (*parser_parse) (void*, int, GValue *, GdaSqlParserIface *);	
 	gint *parser_tokens_trans;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
@@ -102,6 +103,86 @@ struct _GdaSqlParserClass
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-sql-parser
+ * @short_description: SQL parser
+ * @title: GdaSqlParser
+ * @stability: Stable
+ * @see_also: #GdaSqlBuilder, #GdaSqlStatement and #GdaStatement
+ *
+ * The #GdaSqlParser is an object dedicated to creating #GdaStatement and #GdaBatch objects from SQL strings. The actual contents
+ * of the parsed statements is represented as #GdaSqlStatement structures (which can be obtained from any #GdaStatement through the
+ * "structure" property).
+ *
+ * #GdaSqlParser parsers can be created by calling gda_server_provider_create_parser() for a provider adapted SQL parser, or using
+ * gda_sql_parser_new() for a general purpose SQL parser.
+ *
+ * The #GdaSqlParser can either work in "parse" mode where it will try to parse the SQL string, or in "delimiter" mode where it will
+ * only attempt at delimiting SQL statements in a string which may contain several SQL statements (usually separated by a semi column).
+ * If operating in "parser" mode, and the parser can't correctly parse the string, then it will switch to the "delimiter" mode
+ * for the next statement in the string to parse (and create a GDA_SQL_STATEMENT_UNKNOWN statement).
+ *
+ * The #GdaSqlParser object parses and analyzes SQL statements and reports the following statement types:
+ * <itemizedlist>
+ * <listitem><para>SELECT (and COMPOUND select), 
+ *     INSERT, UPDATE and DELETE SQL statements should be completely parsed. 
+ * </para></listitem>
+ * <listitem><para>Transaction related statements (corresponding to the BEGIN, COMMIT, ROLLBACK,
+ * SAVEPOINT, ROLLBACK SAVEPOINT and DELETE SAVEPOINT) are parsed and a minimalist structure is created to 
+ * extract some information (that structure is not enough per-se to re-create the complete SQL statement).
+ * </para></listitem>
+ * <listitem><para>Any other type of SQL statement (CREATE TABLE, ...) creates a #GdaStatement of type 
+ *     GDA_SQL_STATEMENT_UNKNOWN, and it only able to locate place holders (variables) and end of statement
+ *     marks.</para></listitem>
+ * </itemizedlist>
+ *
+ * NOTE: Any SQL of a type which should be parsed which but which creates a #GdaStatement of type GDA_SQL_STATEMENT_UNKNOWN
+ * (check with gda_statement_get_statement_type()) should be reported as a bug.
+ *
+ * The #GdaSqlParser object recognizes place holders (variables), which can later be queried and valued using
+ * gda_statement_get_parameters(). The following syntax are recognized (other syntaxes might be 
+ * recognized for specific database providers if the #GdaSqlParser is created using gda_server_provider_create_parser()
+ * but for portability reasons it's better to avoid them):
+ * <itemizedlist>
+ * <listitem><para><programlisting>##NAME[::TYPE[::NULL]]]</programlisting>: 
+ *     for a variable named NAME with the optional type TYPE (which can be a GType
+ *     name or a custom database type name), and with the optional "::NULL" to instruct that the variable can
+ *     be NULL.
+ * </para></listitem>
+ * <listitem><para>
+ *  <programlisting>## /&ast; name:NAME [type:TYPE] [nullok:[TRUE|FALSE]] [descr:DESCR] &ast;/</programlisting>
+ *     for a variable named NAME with the optional type TYPE (which can be a GType
+ *     name or a custom database type name), with the optional "nullok" attribute and an optional
+ *     description DESCR. Note that the NAME, TYPE and DESCR literals here must be quoted (simple or double quotes) if
+ *     they include non alphanumeric characters, and that there must always be at least a space between the 
+ *     <![CDATA[##]]> and the opening and closing comments (C style).
+ * </para></listitem>
+ * </itemizedlist>
+ * Note that the type string must be a type recognized by the
+ * <link linkend="gda-g-type-from-string">gda_g_type_from_string()</link> function (all valid GType names
+ * plus a few synonyms). Examples of correct place holders definitions are:
+ * <programlisting>
+ *## /&ast; name:"+0" type:gchararray &ast;/
+ *## /&ast; name:'-5' type:string &ast;/
+ *## /&ast;name:myvar type:gint descr:ToBeDefined nullok:FALSE&ast;/
+ *## /&ast;name:myvar type:int descr:"A long description"&ast;/
+ *##+0::gchararray
+ *##-5::timestamp
+ *</programlisting>
+ *
+ * Also note that variables should not be used when an SQL identifier is expected. For example the following
+ * examples <emphasis>should be avoided</emphasis> because they may not work properly (depending on the database being used):
+ *<programlisting>
+ *SELECT * FROM ##tablename::string;
+ *DELETE FROM mytable WHERE ##tcol::string = 5;
+ *ALTER GROUP mygroup ADD USER ##name::gchararray;
+ *</programlisting>
+ *
+ * The #GdaSqlParser object internally uses a LEMON generated parser (the same as the one used by SQLite).
+ *
+ * The #GdaSqlParser object implements its own locking mechanism so it is thread-safe.
+ */
+
 GType               gda_sql_parser_get_type               (void) G_GNUC_CONST;
 GdaSqlParser       *gda_sql_parser_new                    (void);
 
diff --git a/libgda/sql-parser/gda-sql-statement.h b/libgda/sql-parser/gda-sql-statement.h
index 17f13fa..8fc9b36 100644
--- a/libgda/sql-parser/gda-sql-statement.h
+++ b/libgda/sql-parser/gda-sql-statement.h
@@ -1,5 +1,5 @@
-/* GDA library
- * Copyright (C) 2008 The GNOME Foundation.
+/*
+ * Copyright (C) 2008 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -25,6 +25,35 @@
 
 G_BEGIN_DECLS
 
+/**
+ * SECTION:gda-sql-statement
+ * @short_description: SQL parser
+ * @title: GdaSqlParser
+ * @stability: Stable
+ * @see_also: The #GdaSqlBuilder object which features some easy to use API to build #GdaSqlStatement structures or #GdaStatement objects without having to worry about the details of #GdaSqlStatement's contents.
+ *
+ * Please note that it is not advised to build #GdaSqlStatement structures directly, but rather
+ * it is recommended to use the #GdaSqlBuilder object and its associated API.
+ *
+ * Every SQL statement can be decomposed in a #GdaSqlStatement structure. This is not a #GObject, but rather just a C structure
+ * which can be manipulated directly. The structure is a tree composed of several key structures which are show in the following diagram
+ * (even though it does not show, all structures "inherit" the #GdaSqlAnyPart structure which holds some basic information).
+ *<mediaobject>
+ *  <imageobject role="html">
+ *    <imagedata fileref="parts.png" format="PNG"/>
+ *  </imageobject>
+ *  <caption>
+ *    <para>
+ *      Main parts of the #GdaSqlStatement structure.
+ *    </para>
+ *  </caption>
+ *</mediaobject>
+ *
+ * The samples/SqlParserConsole directory of &LIBGDA;'s sources contains a small utility
+ * to display statements' structures as a graph (using the GraphViz language). It has been used to
+ * provide the examples in this section of the documentation.
+ */
+
 #include <sql-parser/gda-statement-struct-select.h>
 #include <sql-parser/gda-statement-struct-insert.h>
 #include <sql-parser/gda-statement-struct-update.h>
diff --git a/libgda/sql-parser/gda-statement-struct-compound.h b/libgda/sql-parser/gda-statement-struct-compound.h
index 3b522f0..89d5cb7 100644
--- a/libgda/sql-parser/gda-statement-struct-compound.h
+++ b/libgda/sql-parser/gda-statement-struct-compound.h
@@ -1,5 +1,5 @@
 /* 
- * Copyright (C) 2007 - 2009 Vivien Malerba
+ * Copyright (C) 2007 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -30,6 +30,15 @@ G_BEGIN_DECLS
 /*
  * Kinds
  */
+/**
+ * GdaSqlStatementCompoundType:
+ * @GDA_SQL_STATEMENT_COMPOUND_UNION: 
+ * @GDA_SQL_STATEMENT_COMPOUND_UNION_ALL: 
+ * @GDA_SQL_STATEMENT_COMPOUND_INTERSECT: 
+ * @GDA_SQL_STATEMENT_COMPOUND_INTERSECT_ALL: 
+ * @GDA_SQL_STATEMENT_COMPOUND_EXCEPT: 
+ * @GDA_SQL_STATEMENT_COMPOUND_EXCEPT_ALL: 
+ */
 typedef enum {
 	GDA_SQL_STATEMENT_COMPOUND_UNION,
 	GDA_SQL_STATEMENT_COMPOUND_UNION_ALL,
@@ -42,11 +51,18 @@ typedef enum {
 /*
  * Structure definition
  */
+/**
+ * GdaSqlStatementCompound:
+ * @any: 
+ * @compound_type: 
+ * @stmt_list:
+ */
 struct _GdaSqlStatementCompound {
 	GdaSqlAnyPart                any;
 	GdaSqlStatementCompoundType  compound_type;
 	GSList                      *stmt_list; /* list of SELECT or COMPOUND statements */
 
+	/*< private >*/
 	/* Padding for future expansion */
 	gpointer         _gda_reserved1;
 	gpointer         _gda_reserved2;
diff --git a/libgda/sql-parser/gda-statement-struct-decl.h b/libgda/sql-parser/gda-statement-struct-decl.h
index 2863bba..098949a 100644
--- a/libgda/sql-parser/gda-statement-struct-decl.h
+++ b/libgda/sql-parser/gda-statement-struct-decl.h
@@ -1,5 +1,5 @@
 /* 
- * Copyright (C) 2007 - 2008 Vivien Malerba
+ * Copyright (C) 2007 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -56,6 +56,24 @@ typedef struct _GdaSqlStatementCompound GdaSqlStatementCompound;
 /*
  * Statement type
  */
+/**
+ * GdaSqlStatementType:
+ * @GDA_SQL_STATEMENT_SELECT: a SELECT statement
+ * @GDA_SQL_STATEMENT_INSERT: an INSERT statement
+ * @GDA_SQL_STATEMENT_UPDATE: an UPDATE statement
+ * @GDA_SQL_STATEMENT_DELETE: a DELETE statement
+ * @GDA_SQL_STATEMENT_COMPOUND: a compound statement: multiple SELECT statements grouped together using an operator
+ * @GDA_SQL_STATEMENT_BEGIN: start of transaction statement
+ * @GDA_SQL_STATEMENT_ROLLBACK: transaction abort statement
+ * @GDA_SQL_STATEMENT_COMMIT: transaction commit statement
+ * @GDA_SQL_STATEMENT_SAVEPOINT: new savepoint definition statement
+ * @GDA_SQL_STATEMENT_ROLLBACK_SAVEPOINT: return to savepoint statement
+ * @GDA_SQL_STATEMENT_DELETE_SAVEPOINT: savepoint deletion statement
+ * @GDA_SQL_STATEMENT_UNKNOWN: unknown statement, only identifies variables
+ * @GDA_SQL_STATEMENT_NONE: not used
+ *
+ * Known types of statements
+ */
 typedef enum {
 	GDA_SQL_STATEMENT_SELECT,
 	GDA_SQL_STATEMENT_INSERT,
@@ -79,6 +97,34 @@ typedef enum {
 /*
  * Structures identification
  */
+/**
+ * GdaSqlAnyPartType:
+ * @GDA_SQL_ANY_STMT_SELECT: structure is a #GdaSqlStatementSelect
+ * @GDA_SQL_ANY_STMT_INSERT: structure is a #GdaSqlStatementInsert
+ * @GDA_SQL_ANY_STMT_UPDATE: structure is a #GdaSqlStatementUpdate
+ * @GDA_SQL_ANY_STMT_DELETE: structure is a #GdaSqlStatementDelete
+ * @GDA_SQL_ANY_STMT_COMPOUND: structure is a #GdaSqlStatementCompound
+ * @GDA_SQL_ANY_STMT_BEGIN: structure is a #GdaSqlStatementTransaction
+ * @GDA_SQL_ANY_STMT_ROLLBACK: structure is a #GdaSqlStatementTransaction
+ * @GDA_SQL_ANY_STMT_COMMIT: structure is a #GdaSqlStatementTransaction
+ * @GDA_SQL_ANY_STMT_SAVEPOINT: structure is a #GdaSqlStatementTransaction
+ * @GDA_SQL_ANY_STMT_ROLLBACK_SAVEPOINT: structure is a #GdaSqlStatementTransaction
+ * @GDA_SQL_ANY_STMT_DELETE_SAVEPOINT: structure is a #GdaSqlStatementTransaction
+ * @GDA_SQL_ANY_STMT_UNKNOWN: structure is a #GdaSqlStatementUnknown
+ * @GDA_SQL_ANY_EXPR: structure is a #GdaSqlExpr
+ * @GDA_SQL_ANY_SQL_FIELD: structure is a #GdaSqlField
+ * @GDA_SQL_ANY_SQL_TABLE: structure is a #GdaSqlTable
+ * @GDA_SQL_ANY_SQL_FUNCTION: structure is a #GdaSqlFunction
+ * @GDA_SQL_ANY_SQL_OPERATION: structure is a #GdaSqlOperation
+ * @GDA_SQL_ANY_SQL_CASE: structure is a #GdaSqlCase
+ * @GDA_SQL_ANY_SQL_SELECT_FIELD: structure is a #GdaSqlSelectField
+ * @GDA_SQL_ANY_SQL_SELECT_TARGET: structure is a #GdaSqlSelectTarget
+ * @GDA_SQL_ANY_SQL_SELECT_JOIN: structure is a #GdaSqlSelectJoin
+ * @GDA_SQL_ANY_SQL_SELECT_FROM: structure is a #GdaSqlSelectFrom
+ * @GDA_SQL_ANY_SQL_SELECT_ORDER: structure is a #GdaSqlSelectOrder
+ *
+ * Type of part.
+ */
 typedef enum {
 	/* complete statements */
 	GDA_SQL_ANY_STMT_SELECT = GDA_SQL_STATEMENT_SELECT,
@@ -108,6 +154,15 @@ typedef enum {
 	GDA_SQL_ANY_SQL_SELECT_ORDER
 } GdaSqlAnyPartType;
 
+
+/**
+ * GdaSqlAnyPart:
+ * @type: type of structure, as a #GdaSqlAnyPartType enum.
+ * @parent: pointer to the parent #GdaSqlAnyPart structure
+ *
+ * Base structure of which all structures (except #GdaSqlStatement) "inherit". It identifies, for each structure,
+ * its type and its parent in the structure hierarchy.
+ */
 struct _GdaSqlAnyPart {
 	GdaSqlAnyPartType  type;
 	GdaSqlAnyPart     *parent;
@@ -122,6 +177,15 @@ struct _GdaSqlAnyPart {
  */
 
 /* returns FALSE if a recursive walking should be stopped (mandatory is @error is set) */
+/**
+ * GdaSqlForeachFunc:
+ * @Param1: the current #GdaSqlAnyPart node
+ * @Param2: user data passed to gda_sql_any_part_foreach().
+ * @Param3: pointer to a place to store errors
+ * @Returns: FALSE if the gda_sql_any_part_foreach() should stop at this point and fail
+ *
+ * Specifies the type of functions passed to gda_sql_any_part_foreach().
+ */
 typedef gboolean (*GdaSqlForeachFunc) (GdaSqlAnyPart *, gpointer, GError **);
 
 gboolean gda_sql_any_part_foreach (GdaSqlAnyPart *node, GdaSqlForeachFunc func, gpointer data, GError **error);
@@ -146,6 +210,7 @@ typedef struct {
 	GdaSqlForeachFunc     check_structure_func;
 	GdaSqlForeachFunc     check_validity_func;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	gpointer         _gda_reserved1;
 	gpointer         _gda_reserved2;
@@ -156,12 +221,12 @@ typedef struct {
 /*
  * Validation against a dictionary
  */
-
 typedef struct {
 	GdaConnection *cnc;
 	GdaMetaStore  *store;
 	GdaMetaStruct *mstruct;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	gpointer         _gda_reserved1;
 	gpointer         _gda_reserved2;
diff --git a/libgda/sql-parser/gda-statement-struct-delete.h b/libgda/sql-parser/gda-statement-struct-delete.h
index bb3ee42..acc3e0b 100644
--- a/libgda/sql-parser/gda-statement-struct-delete.h
+++ b/libgda/sql-parser/gda-statement-struct-delete.h
@@ -1,5 +1,5 @@
 /* 
- * Copyright (C) 2007 - 2009 Vivien Malerba
+ * Copyright (C) 2007 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -31,11 +31,18 @@ G_BEGIN_DECLS
 /*
  * Structure definition
  */
+/**
+ * GdaSqlStatementDelete:
+ * @any: 
+ * @table: 
+ * @cond:
+ */
 struct _GdaSqlStatementDelete {
 	GdaSqlAnyPart any;
 	GdaSqlTable  *table;
 	GdaSqlExpr   *cond;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	gpointer         _gda_reserved1;
 	gpointer         _gda_reserved2;
diff --git a/libgda/sql-parser/gda-statement-struct-insert.h b/libgda/sql-parser/gda-statement-struct-insert.h
index 8c1de64..a7941da 100644
--- a/libgda/sql-parser/gda-statement-struct-insert.h
+++ b/libgda/sql-parser/gda-statement-struct-insert.h
@@ -1,5 +1,5 @@
 /* 
- * Copyright (C) 2007 - 2009 Vivien Malerba
+ * Copyright (C) 2007 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -31,6 +31,41 @@ G_BEGIN_DECLS
 /*
  * Structure definition
  */
+/**
+ * GdaSqlStatementInsert:
+ * @any: inheritance structure
+ * @on_conflict: conflict resolution clause if there is one (such as "OR REPLACE")
+ * @table: name of the table to which data is inserted
+ * @fields_list: list of #GdaSqlField fields which are valued for insertion
+ * @values_list: list of list of #GdaSqlExpr expressions (this is a list of list, not a simple list)
+ * @select: a #GdaSqlStatementSelect or #GdaSqlStatementCompound structure representing the values to insert
+ *
+ * The statement is an INSERT statement, any kind of INSERT statement can be represented using this structure 
+ * (if this is not the case
+ * then report a bug).
+ * <mediaobject>
+ *   <imageobject role="html">
+ *     <imagedata fileref="stmt-insert1.png" format="PNG"/>
+ *   </imageobject>
+ *   <caption>
+ *     <para>
+ *	Example of a #GdaSqlStatement having a #GdaSqlStatementInsert as its contents with 2 lists of values
+ *	to insert.
+ *     </para>
+ *   </caption>
+ * </mediaobject>
+ * <mediaobject>
+ *   <imageobject role="html">
+ *     <imagedata fileref="stmt-insert2.png" format="PNG"/>
+ *   </imageobject>
+ *   <caption>
+ *     <para>
+ *	Another example of a #GdaSqlStatement having a #GdaSqlStatementInsert as its contents, using a SELECT
+ *	to express the values to insert.
+ *     </para>
+ *   </caption>
+ * </mediaobject>
+ */
 struct _GdaSqlStatementInsert {
 	GdaSqlAnyPart           any;
 	gchar                  *on_conflict; /* conflict resolution clause */
@@ -39,6 +74,7 @@ struct _GdaSqlStatementInsert {
 	GSList                 *values_list; /* list of list of GdaSqlExpr */
 	GdaSqlAnyPart          *select; /* SELECT OR COMPOUND statements: GdaSqlStatementSelect or GdaSqlStatementCompound */
 
+	/*< private >*/
 	/* Padding for future expansion */
 	gpointer         _gda_reserved1;
 	gpointer         _gda_reserved2;
diff --git a/libgda/sql-parser/gda-statement-struct-parts.c b/libgda/sql-parser/gda-statement-struct-parts.c
index 9d2696d..fb15c4e 100644
--- a/libgda/sql-parser/gda-statement-struct-parts.c
+++ b/libgda/sql-parser/gda-statement-struct-parts.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 - 2009 Vivien Malerba
+ * Copyright (C) 2007 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -94,7 +94,7 @@ gda_sql_expr_free (GdaSqlExpr *expr)
 	}
 	gda_sql_case_free (expr->case_s);
 	g_free (expr->cast_as);
-	expr->value_is_ident = (gpointer) 0x1;
+	expr->value_is_ident = TRUE;
 	g_free (expr);
 }
 
diff --git a/libgda/sql-parser/gda-statement-struct-parts.h b/libgda/sql-parser/gda-statement-struct-parts.h
index 0325623..8a03be6 100644
--- a/libgda/sql-parser/gda-statement-struct-parts.h
+++ b/libgda/sql-parser/gda-statement-struct-parts.h
@@ -1,5 +1,8 @@
 /*
- * Copyright (C) 2007 - 2008 Vivien Malerba
+ * Copyright (C) 2007 - 2011 The GNOME Foundation.
+ *
+ * AUTHORS:
+ *      Vivien Malerba <malerba gnome-db org>
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -66,7 +69,7 @@ typedef struct _GdaSqlSelectOrder GdaSqlSelectOrder;
  * <userinput>"'joe'"</userinput> and not <userinput>"joe"</userinput>.
  *
  * Note 2 about the @value field: if the expression represents an SQL identifier (such as a table
- * or field name), then the @value_is_ident should be set to %0x01, and @value should be a string
+ * or field name), then the @value_is_ident should be set to %TRUE, and @value should be a string
  * which may contain double quotes around SQL identifiers which also are reserved keywords or which
  * are case sensitive.
  */
@@ -81,14 +84,14 @@ struct _GdaSqlExpr {
 
 	gchar           *cast_as;
 
-	gpointer         value_is_ident; /* pointer to a boolean to keep ABI from 4.0.
-					  * Non NULL if @value represents an SQL identifier
-					  * Mem in _NOT_ allocated!
-					  */
+	gboolean         value_is_ident;
 
 	/*< private >*/
 	/* Padding for future expansion */
+	gpointer         _gda_reserved1;
 	gpointer         _gda_reserved2;
+	gpointer         _gda_reserved3;
+	gpointer         _gda_reserved4;
 };
 
 #define GDA_TYPE_SQL_EXPR (gda_sql_expr_get_type())
@@ -105,6 +108,14 @@ void             gda_sql_expr_take_select    (GdaSqlExpr *expr, GdaSqlStatement
 /*
  * Any Table's field
  */
+/**
+ * GdaSqlField:
+ * any: 
+ * @field_name: 
+ * @validity_meta_table_column: 
+ *
+ * This structure represents the name of a table's field.
+ */
 struct _GdaSqlField {
 	GdaSqlAnyPart       any;
 	gchar              *field_name;
@@ -129,6 +140,14 @@ void             gda_sql_field_take_name      (GdaSqlField *field, GValue *value
 /*
  * Any table
  */
+/**
+ * GdaSqlTable:
+ * @any: 
+ * @table_name: 
+ * @validity_meta_object: 
+ *
+ * This structure represents the name of a table.
+ */
 struct _GdaSqlTable
 {
 	GdaSqlAnyPart       any;
@@ -154,6 +173,14 @@ void             gda_sql_table_take_name      (GdaSqlTable *table, GValue *value
 /*
  * A function with any number of arguments
  */
+/**
+ * GdaSqlFunction:
+ * @any: inheritance structure
+ * @function_name: name of the function , in the form [[catalog.]schema.]function_name
+ * @args_list: list of #GdaSqlExpr expressions, one for each argument
+ *
+ * This structure represents a function or an aggregate with zero or more arguments.
+ */
 struct _GdaSqlFunction {
 	GdaSqlAnyPart       any;
 	gchar              *function_name;
@@ -177,6 +204,39 @@ void             gda_sql_function_take_args_list (GdaSqlFunction *function, GSLi
 /*
  * An operation on one or more expressions
  */
+/**
+ * GdaSqlOperatorType:
+ * @GDA_SQL_OPERATOR_TYPE_AND: 
+ * @GDA_SQL_OPERATOR_TYPE_OR: 
+ * @GDA_SQL_OPERATOR_TYPE_EQ: 
+ * @GDA_SQL_OPERATOR_TYPE_IS: 
+ * @GDA_SQL_OPERATOR_TYPE_LIKE: 
+ * @GDA_SQL_OPERATOR_TYPE_BETWEEN: 
+ * @GDA_SQL_OPERATOR_TYPE_GT: 
+ * @GDA_SQL_OPERATOR_TYPE_LT: 
+ * @GDA_SQL_OPERATOR_TYPE_GEQ: 
+ * @GDA_SQL_OPERATOR_TYPE_LEQ: 
+ * @GDA_SQL_OPERATOR_TYPE_DIFF: 
+ * @GDA_SQL_OPERATOR_TYPE_REGEXP: 
+ * @GDA_SQL_OPERATOR_TYPE_REGEXP_CI: 
+ * @GDA_SQL_OPERATOR_TYPE_NOT_REGEXP: 
+ * @GDA_SQL_OPERATOR_TYPE_NOT_REGEXP_CI: 
+ * @GDA_SQL_OPERATOR_TYPE_SIMILAR: 
+ * @GDA_SQL_OPERATOR_TYPE_ISNULL: 
+ * @GDA_SQL_OPERATOR_TYPE_ISNOTNULL: 
+ * @GDA_SQL_OPERATOR_TYPE_NOT: 
+ * @GDA_SQL_OPERATOR_TYPE_IN: 
+ * @GDA_SQL_OPERATOR_TYPE_NOTIN: 
+ * @GDA_SQL_OPERATOR_TYPE_CONCAT: 
+ * @GDA_SQL_OPERATOR_TYPE_PLUS: 
+ * @GDA_SQL_OPERATOR_TYPE_MINUS: 
+ * @GDA_SQL_OPERATOR_TYPE_STAR: 
+ * @GDA_SQL_OPERATOR_TYPE_DIV: 
+ * @GDA_SQL_OPERATOR_TYPE_REM: 
+ * @GDA_SQL_OPERATOR_TYPE_BITAND: 
+ * @GDA_SQL_OPERATOR_TYPE_BITOR: 
+ * @GDA_SQL_OPERATOR_TYPE_BITNOT:
+ */
 typedef enum {
 	GDA_SQL_OPERATOR_TYPE_AND,
 	GDA_SQL_OPERATOR_TYPE_OR,
@@ -212,6 +272,14 @@ typedef enum {
 	GDA_SQL_OPERATOR_TYPE_BITNOT
 } GdaSqlOperatorType;
 
+/**
+ * GdaSqlOperation:
+ * @any: inheritance structure
+ * @operator_type: 
+ * @operands: list of #GdaSqlExpr operands
+ *
+ * This structure represents an operation between one or more operands.
+ */
 struct _GdaSqlOperation {
 	GdaSqlAnyPart       any;
 	GdaSqlOperatorType  operator_type;
@@ -233,6 +301,16 @@ GdaSqlOperatorType    gda_sql_operation_operator_from_string (const gchar *op);
 /*
  * A CASE expression
  */
+/**
+ * GdaSqlCase:
+ * @any: inheritance structure
+ * @base_expr: expression to test
+ * @when_expr_list: list of #GdaSqlExpr, one for each WHEN clause
+ * @then_expr_list: list of #GdaSqlExpr, one for each THEN clause
+ * @else_expr: default expression for the CASE
+ *
+ * This structure represents a CASE WHEN... construct
+ */
 struct _GdaSqlCase
 {
 	GdaSqlAnyPart    any;
@@ -255,6 +333,21 @@ gchar             *gda_sql_case_serialize      (GdaSqlCase *sc);
 /*
  * Any expression in a SELECT ... before the FROM clause
  */
+/**
+ * GdaSqlSelectField:
+ * @any: inheritance structure
+ * @expr: expression
+ * @field_name: field name part of @expr if @expr represents a field
+ * @table_name: table name part of @expr if @expr represents a field
+ * @as: alias
+ * @validity_meta_object: 
+ * @validity_meta_table_column: 
+ *
+ * This structure represents a selected item in a SELECT statement (when executed, the returned data set
+ * will have one column per selected item). Note that the @table_name and 
+ * @field_name field parts <emphasis>will be</emphasis> overwritten by &LIBGDA;,
+ * set the value of @expr->value instead.
+ */
 struct _GdaSqlSelectField
 {
 	GdaSqlAnyPart       any;
@@ -286,6 +379,19 @@ void               gda_sql_select_field_take_alias     (GdaSqlSelectField *field
 /*
  * Any TARGET ... in a SELECT statement
  */
+/**
+ * GdaSqlSelectTarget:
+ * @any: inheritance structure
+ * @expr: expression
+ * @table_name: table name part of @expr if @expr represents a table
+ * @as: alias
+ * @validity_meta_object: 
+ *
+ * This structure represents a target used to fetch data from in a SELECT statement; it can represent a table or
+ * a sub select. Note that the @table_name
+ * part <emphasis>will be</emphasis> overwritten by &LIBGDA;,
+ * set the value of @expr->value instead.
+ */
 struct _GdaSqlSelectTarget
 {
 	GdaSqlAnyPart       any;
@@ -315,6 +421,15 @@ void                gda_sql_select_target_take_alias (GdaSqlSelectTarget *target
 /*
  * Any JOIN ... in a SELECT statement
  */
+/**
+ * GdaSqlSelectJoinType:
+ * @GDA_SQL_SELECT_JOIN_CROSS: 
+ * @GDA_SQL_SELECT_JOIN_NATURAL: 
+ * @GDA_SQL_SELECT_JOIN_INNER: 
+ * @GDA_SQL_SELECT_JOIN_LEFT: 
+ * @GDA_SQL_SELECT_JOIN_RIGHT: 
+ * @GDA_SQL_SELECT_JOIN_FULL:
+ */
 typedef enum {
 	GDA_SQL_SELECT_JOIN_CROSS,
 	GDA_SQL_SELECT_JOIN_NATURAL,
@@ -323,6 +438,17 @@ typedef enum {
 	GDA_SQL_SELECT_JOIN_RIGHT,
 	GDA_SQL_SELECT_JOIN_FULL
 } GdaSqlSelectJoinType;
+
+/**
+ * GdaSqlSelectJoin:
+ * @any: inheritance structure
+ * @type: type of join
+ * @position: represents a join between a target at (pos &lt; @position) and the one at @position
+ * @expr: joining expression, or %NULL
+ * @use: list of #GdaSqlField pointers to use when joining, or %NULL
+ *
+ * This structure represents a join between two targets in a SELECT statement.
+ */
 struct _GdaSqlSelectJoin
 {
 	GdaSqlAnyPart         any;
@@ -348,6 +474,14 @@ const gchar       *gda_sql_select_join_type_to_string (GdaSqlSelectJoinType type
 /*
  * Any FROM ... in a SELECT statement
  */
+/**
+ * GdaSqlSelectFrom:
+ * @any: inheritance structure
+ * @targets: list of #GdaSqlSelectTarget
+ * @joins: list of #GdaSqlSelectJoin
+ *
+ * This structure represents the FROM clause of a SELECT statement, it lists targets and joins
+ */
 struct _GdaSqlSelectFrom
 {
 	GdaSqlAnyPart    any;
@@ -371,6 +505,15 @@ void               gda_sql_select_from_take_new_join  (GdaSqlSelectFrom *from, G
 /*
  * Any expression in a SELECT ... after the ORDER BY
  */
+/**
+ * GdaSqlSelectOrder:
+ * @any: inheritance structure
+ * @expr: expression to order on
+ * @asc: TRUE is ordering is ascending
+ * @collation_name: name of the collation to use for ordering
+ *
+ * This structure represents the ordering of a SELECT statement.
+ */
 struct _GdaSqlSelectOrder
 {
 	GdaSqlAnyPart    any;
diff --git a/libgda/sql-parser/gda-statement-struct-select.h b/libgda/sql-parser/gda-statement-struct-select.h
index 61af908..9c765d4 100644
--- a/libgda/sql-parser/gda-statement-struct-select.h
+++ b/libgda/sql-parser/gda-statement-struct-select.h
@@ -1,5 +1,5 @@
 /* 
- * Copyright (C) 2007 - 2009 Vivien Malerba
+ * Copyright (C) 2007 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -30,6 +30,20 @@ G_BEGIN_DECLS
 /*
  * Structure definition
  */
+/**
+ * GdaSqlStatementSelect:
+ * @any: 
+ * @distinct: 
+ * @distinct_expr: 
+ * @expr_list: 
+ * @from: 
+ * @where_cond: 
+ * @group_by: 
+ * @having_cond: 
+ * @order_by: 
+ * @limit_count: 
+ * @limit_offset: 
+ */
 struct _GdaSqlStatementSelect {
 	GdaSqlAnyPart     any;
 	gboolean          distinct;
@@ -46,6 +60,7 @@ struct _GdaSqlStatementSelect {
 	GdaSqlExpr       *limit_count;
 	GdaSqlExpr       *limit_offset;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	gpointer         _gda_reserved1;
 	gpointer         _gda_reserved2;
diff --git a/libgda/sql-parser/gda-statement-struct-trans.h b/libgda/sql-parser/gda-statement-struct-trans.h
index e0c5105..73e8e31 100644
--- a/libgda/sql-parser/gda-statement-struct-trans.h
+++ b/libgda/sql-parser/gda-statement-struct-trans.h
@@ -1,5 +1,5 @@
 /* 
- * Copyright (C) 2007 - 2009 Vivien Malerba
+ * Copyright (C) 2007 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -31,12 +31,25 @@ G_BEGIN_DECLS
 /*
  * Structure definition
  */
+/**
+ * GdaSqlStatementTransaction:
+ * @any: inheritance structure
+ * @isolation_level: isolation level as a #GdaTransactionIsolation
+ * @trans_mode: transaction mode (DEFERRED, IMMEDIATE, EXCLUSIVE, READ_WRITE, READ_ONLY)
+ * @trans_name: transaction name
+ *
+ * The statement is a transaction management related statement (BEGIN, ROLLBACK, etc). The #GdaSqlStatementTransaction structure
+ * does not hold enough information to reconstruct the complete SQL statement (some information may be missing) - the aim of this
+ * structure is to identify a minimum set of information in the transaction statement. Note that the complete SQL which created the
+ * statement should be available in the #GdaSqlStatement structure which encapsulates this structure.
+ */
 struct _GdaSqlStatementTransaction {
 	GdaSqlAnyPart           any;
 	GdaTransactionIsolation isolation_level;
 	gchar                  *trans_mode; /* DEFERRED, IMMEDIATE, EXCLUSIVE, READ_WRITE, READ_ONLY */
 	gchar                  *trans_name;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	gpointer         _gda_reserved1;
 	gpointer         _gda_reserved2;
diff --git a/libgda/sql-parser/gda-statement-struct-unknown.h b/libgda/sql-parser/gda-statement-struct-unknown.h
index 4692b54..9033ba4 100644
--- a/libgda/sql-parser/gda-statement-struct-unknown.h
+++ b/libgda/sql-parser/gda-statement-struct-unknown.h
@@ -1,5 +1,5 @@
 /* 
- * Copyright (C) 2007 - 2009 Vivien Malerba
+ * Copyright (C) 2007 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -30,10 +30,18 @@ G_BEGIN_DECLS
 /*
  * Structure definition
  */
+/**
+ * GdaSqlStatementUnknown:
+ * @any:
+ * @expressions: a list of #GdaSqlExpr pointers
+ *
+ * Represents any statement which type is not identified (any DDL statement or database specific dialect)
+ */
 struct _GdaSqlStatementUnknown {
 	GdaSqlAnyPart  any;
-	GSList        *expressions; /* list of GdaSqlExpr pointers */
+	GSList        *expressions;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	gpointer         _gda_reserved1;
 	gpointer         _gda_reserved2;
diff --git a/libgda/sql-parser/gda-statement-struct-update.h b/libgda/sql-parser/gda-statement-struct-update.h
index 584d786..d46800e 100644
--- a/libgda/sql-parser/gda-statement-struct-update.h
+++ b/libgda/sql-parser/gda-statement-struct-update.h
@@ -1,5 +1,5 @@
 /* 
- * Copyright (C) 2007 - 2009  Vivien Malerba
+ * Copyright (C) 2007 - 2011  Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -31,6 +31,15 @@ G_BEGIN_DECLS
 /*
  * Structure definition
  */
+/**
+ * GdaSqlStatementUpdate:
+ * @any: 
+ * @on_conflict: 
+ * @table: 
+ * @fields_list: 
+ * @expr_list: 
+ * @cond:
+ */
 struct _GdaSqlStatementUpdate {
 	GdaSqlAnyPart     any;
 	gchar            *on_conflict; /* conflict resolution clause */
@@ -39,6 +48,7 @@ struct _GdaSqlStatementUpdate {
 	GSList           *expr_list;   /* list of GdaSqlExpr pointers */
 	GdaSqlExpr       *cond;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	gpointer         _gda_reserved1;
 	gpointer         _gda_reserved2;
diff --git a/libgda/sql-parser/gda-statement-struct-util.c b/libgda/sql-parser/gda-statement-struct-util.c
index fd65987..6bb8554 100644
--- a/libgda/sql-parser/gda-statement-struct-util.c
+++ b/libgda/sql-parser/gda-statement-struct-util.c
@@ -1,5 +1,8 @@
 /* 
- * Copyright (C) 2007 Vivien Malerba
+ * Copyright (C) 2007 - 2011 The GNOME Foundation.
+ *
+ * AUTHORS:
+ *      Vivien Malerba <malerba gnome-db org>
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -138,18 +141,18 @@ _remove_quotes (gchar *str)
 }
 
 /**
- * gda_sql_identifier_add_quotes
+ * gda_sql_identifier_force_quotes
  * @str: an SQL identifier
  *
- * Add double quotes around the @str identifier. Use the gda_sql_identifier_needs_quotes()
- * function to tell if an identifier needs to be quoted.
+ * Add double quotes around the @str identifier. This function is normally used only by database provider's
+ * implementation.
  *
- * Returns: a new string
+ * For other uses, see gda_sql_identifier_quote().
  *
- * Deprecated: 4.0.3: Use gda_sql_identifier_quote() instead.
+ * Since: 5.0
  */
 gchar *
-gda_sql_identifier_add_quotes (const gchar *str)
+gda_sql_identifier_force_quotes (const gchar *str)
 {
 	gchar *retval, *rptr;
 	const gchar *sptr;
@@ -292,65 +295,14 @@ _string_is_identifier (const gchar *str)
 }
 
 /**
- * gda_sql_identifier_needs_quotes
- * @str: an SQL identifier
- *
- * Tells if @str needs to be quoted before using it in an SQL statement. To actually add quotes,
- * use gda_sql_identifier_add_quotes().
- *
- * To determine if quotes are needed: the following rules are applied:
- * <itemizedlist>
- *  <listitem><para>If the 1st character is a digit, then %TRUE is returned</para></listitem>
- *  <listitem><para>If there are mixed lower and upper case letters, then %TRUE is returned</para></listitem>
- *  <listitem><para>If there are other characters than digits, letters and the '_', '$' and '#', then %TRUE is returned</para></listitem>
- *  <listitem><para>Otherwise %FALSE is returned</para></listitem>
- * </itemizedlist>
- *
- * Returns: TRUE if @str needs some quotes
- *
- * Deprecated: 4.0.3: Not needed anymore because of the gda_sql_identifier_quote() function.
- */
-gboolean
-gda_sql_identifier_needs_quotes (const gchar *str)
-{
-	const gchar *ptr;
-	gchar icase = 0;
-
-	g_return_val_if_fail (str, FALSE);
-	for (ptr = str; *ptr; ptr++) {
-		/* quote if 1st char is a number */
-		if ((*ptr <= '9') && (*ptr >= '0')) {
-			if (ptr == str)
-				return TRUE;
-			continue;
-		}
-		if ((*ptr >= 'A') && (*ptr <= 'Z')) {
-			if (icase == 0) /* first alpha char encountered */
-				icase = 'U';
-			else if (icase == 'L') /* @str has mixed case */
-				return TRUE;
-			continue;
-		}
-		if ((*ptr >= 'a') && (*ptr <= 'z')) {
-			if (icase == 0) /* first alpha char encountered */
-				icase = 'L';
-			else if (icase == 'U')
-				return TRUE; /* @str has mixed case */
-			continue;
-		}
-		if ((*ptr != '$') && (*ptr != '_') && (*ptr != '#'))
-			return TRUE;
-	}
-	return FALSE;
-}
-
-/**
- * gda_sql_identifier_remove_quotes
+ * gda_sql_identifier_prepare_for_compare
  * @str: a quoted string
  *
  * Prepares @str to be compared:
- * - if surrounded by double quotes or single quotes, then just remove the quotes
- * - otherwise convert to lower case
+ * <itemizedlist>
+ * <listitem><para>if surrounded by double quotes or single quotes, then just remove the quotes</para></listitem>
+ * <listitem><para>otherwise convert to lower case</para></listitem>
+ * </itemizedlist>
  *
  * The quoted string:
  * <itemizedlist>
@@ -359,14 +311,16 @@ gda_sql_identifier_needs_quotes (const gchar *str)
  *     of it is preceeded with a backslash character or with the delimiter character itself</para></listitem>
  * </itemizedlist>
  *
+ * This function is normally used only by database provider's implementation.
+ *
  * WARNING: @str must NOT be a composed identifier (&lt;part1&gt;."&lt;part2&gt;" for example)
  * 
  * Returns: @str
- * 
- * Deprecated: 4.0.3: Not needed anymore because of the gda_sql_identifier_quote() function.
+ *
+ * Since: 5.0
  */
 gchar *
-gda_sql_identifier_remove_quotes (gchar *str)
+gda_sql_identifier_prepare_for_compare (gchar *str)
 {
 	if (!str)
 		return NULL;
diff --git a/libgda/sql-parser/gda-statement-struct-util.h b/libgda/sql-parser/gda-statement-struct-util.h
index 08e68cf..fb1596e 100644
--- a/libgda/sql-parser/gda-statement-struct-util.h
+++ b/libgda/sql-parser/gda-statement-struct-util.h
@@ -1,5 +1,8 @@
-/* 
- * Copyright (C) 2007 - 2008 Vivien Malerba
+/*
+ * Copyright (C) 2007 - 2011 The GNOME Foundation.
+ *
+ * AUTHORS:
+ *      Vivien Malerba <malerba gnome-db org>
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -31,11 +34,8 @@ gchar    *_json_quote_string (const gchar *str);
 gboolean  _string_is_identifier (const gchar *str);
 gboolean  _split_identifier_string (gchar *str, gchar **remain, gchar **last);
 
-#ifndef GDA_DISABLE_DEPRECATED
-gboolean  gda_sql_identifier_needs_quotes (const gchar *str);
-gchar    *gda_sql_identifier_add_quotes (const gchar *str);
-gchar    *gda_sql_identifier_remove_quotes (gchar *str);
-#endif
+gchar    *gda_sql_identifier_force_quotes (const gchar *str);
+gchar    *gda_sql_identifier_prepare_for_compare (gchar *str);
 
 /* to be removed, only here for debug */
 gchar    *gda_sql_value_stringify (const GValue *value);
diff --git a/libgda/sql-parser/gda-statement-struct.h b/libgda/sql-parser/gda-statement-struct.h
index 4a45003..7a19ff9 100644
--- a/libgda/sql-parser/gda-statement-struct.h
+++ b/libgda/sql-parser/gda-statement-struct.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 - 2009 Vivien Malerba
+ * Copyright (C) 2007 - 2011 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -27,12 +27,22 @@
 
 G_BEGIN_DECLS
 
+/**
+ * GdaSqlStatement:
+ * @sql: 
+ * @stmt_type: type of statement 
+ * @contents: contents, cast it depending on @stmt_type (for example to a #GdaSqlStatementSelect).
+ * @validity_meta_struct:
+ *
+ * This structure is the top level structure encapsulating several type of statements.
+ */
 struct _GdaSqlStatement {
 	gchar               *sql;
 	GdaSqlStatementType  stmt_type;
 	gpointer             contents; /* depends on stmt_type */
 	GdaMetaStruct       *validity_meta_struct; /* set when gda_sql_statement_check_validity() was last called */
 
+	/*< private >*/
 	/* Padding for future expansion */
 	gpointer         _gda_reserved1;
 	gpointer         _gda_reserved2;
diff --git a/libgda/sqlite/Makefile.am b/libgda/sqlite/Makefile.am
index a701209..cfa6d96 100644
--- a/libgda/sqlite/Makefile.am
+++ b/libgda/sqlite/Makefile.am
@@ -67,7 +67,7 @@ libgda_sqlite_la_SOURCES = $(sqlitesources)
 libgda_sqlite_la_CFLAGS = -DPNAME=\""SQLite"\" -DCLASS_PREFIX=\""GdaSqlite"\" -DSEARCH_LIB_PATH=\""$(SQLITE_PATH)"\"
 libgda_sqlite_la_LDFLAGS = -export-dynamic -module -avoid-version $(NO_UNDEFINED)
 libgda_sqlite_la_LIBADD = \
-	virtual/libgda-virtual-4.0.la \
+	virtual/libgda-virtual-5.0.la \
 	$(sqlitelibs) \
 	$(LIBGDA_LIBS)
 
diff --git a/libgda/sqlite/gda-sqlite-provider.c b/libgda/sqlite/gda-sqlite-provider.c
index ebc0f93..a99a297 100644
--- a/libgda/sqlite/gda-sqlite-provider.c
+++ b/libgda/sqlite/gda-sqlite-provider.c
@@ -1472,7 +1472,6 @@ gda_sqlite_provider_get_default_dbms_type (G_GNUC_UNUSED GdaServerProvider *prov
 	
 	if ((type == GDA_TYPE_GEOMETRIC_POINT) ||
 	    (type == G_TYPE_OBJECT) ||
-	    (type == GDA_TYPE_LIST) ||
 	    (type == G_TYPE_STRING) ||
 	    (type == G_TYPE_INVALID) ||
 	    (type == G_TYPE_GTYPE))
@@ -1988,11 +1987,11 @@ add_oid_columns (GdaStatement *stmt, GHashTable **out_hash, gint *out_nb_cols_ad
 		
 		/* add to hash table */
 		add_index++;
-		g_hash_table_insert (hash, gda_sql_identifier_remove_quotes (g_strdup (name)),
+		g_hash_table_insert (hash, gda_sql_identifier_prepare_for_compare (g_strdup (name)),
 				     GINT_TO_POINTER (add_index)); /* ADDED 1 to column number,
 								    * don't forget to remove 1 when using */
 		if (target->as)
-			g_hash_table_insert (hash, gda_sql_identifier_remove_quotes (g_strdup (target->table_name)),
+			g_hash_table_insert (hash, gda_sql_identifier_prepare_for_compare (g_strdup (target->table_name)),
 					     GINT_TO_POINTER (add_index)); /* ADDED 1 to column number,
 									    * don't forget to remove 1 when using */
 		nb_cols_added ++;
diff --git a/libgda/sqlite/gda-sqlite-util.c b/libgda/sqlite/gda-sqlite-util.c
index 822b33a..128b207 100644
--- a/libgda/sqlite/gda-sqlite-util.c
+++ b/libgda/sqlite/gda-sqlite-util.c
@@ -255,7 +255,7 @@ _gda_sqlite_identifier_quote (G_GNUC_UNUSED GdaServerProvider *provider, GdaConn
 		gchar *tmp, *ptr;
 		tmp = sqlite_remove_quotes (g_strdup (id));
 		if (kwfunc (tmp)) {
-			ptr = gda_sql_identifier_add_quotes (tmp);
+			ptr = gda_sql_identifier_force_quotes (tmp);
 			g_free (tmp);
 			return ptr;
 		}
@@ -269,7 +269,7 @@ _gda_sqlite_identifier_quote (G_GNUC_UNUSED GdaServerProvider *provider, GdaConn
 				    (*ptr >= '_'))
 					continue;
 				else {
-					ptr = gda_sql_identifier_add_quotes (tmp);
+					ptr = gda_sql_identifier_force_quotes (tmp);
 					g_free (tmp);
 					return ptr;
 				}
@@ -286,7 +286,7 @@ _gda_sqlite_identifier_quote (G_GNUC_UNUSED GdaServerProvider *provider, GdaConn
 			/* there are already some quotes */
 			gchar *tmp, *ptr;
 			tmp = sqlite_remove_quotes (g_strdup (id));
-			ptr = gda_sql_identifier_add_quotes (tmp);
+			ptr = gda_sql_identifier_force_quotes (tmp);
 			g_free (tmp);
 			return ptr;
 		}
diff --git a/libgda/sqlite/sqlite-src/PragmasPatch b/libgda/sqlite/sqlite-src/PragmasPatch
index e39d49c..01af38f 100644
--- a/libgda/sqlite/sqlite-src/PragmasPatch
+++ b/libgda/sqlite/sqlite-src/PragmasPatch
@@ -1,6 +1,6 @@
---- sqlite3.c.orig	2010-08-24 00:56:03.000000000 +0200
-+++ sqlite3.c	2010-09-01 15:59:28.000000000 +0200
-@@ -85120,6 +85120,60 @@
+--- sqlite3.c.orig	2011-01-31 16:31:52.000000000 +0100
++++ sqlite3.c	2011-02-21 15:53:15.000000000 +0100
+@@ -86518,6 +86518,60 @@
  
  #ifndef SQLITE_OMIT_SCHEMA_PRAGMAS
    /*
diff --git a/libgda/sqlite/sqlite-src/sqlite3.c b/libgda/sqlite/sqlite-src/sqlite3.c
index ac21c1a..0bc9094 100644
--- a/libgda/sqlite/sqlite-src/sqlite3.c
+++ b/libgda/sqlite/sqlite-src/sqlite3.c
@@ -1,10 +1,10 @@
 /******************************************************************************
 ** This file is an amalgamation of many separate C source files from SQLite
-** version 3.7.2.  By combining all the individual C code files into this 
+** version 3.7.5.  By combining all the individual C code files into this 
 ** single large file, the entire code can be compiled as a one translation
 ** unit.  This allows many compilers to do optimizations that would not be
 ** possible if the files were compiled separately.  Performance improvements
-** of 5% are more are commonly seen when SQLite is compiled as a single
+** of 5% or more are commonly seen when SQLite is compiled as a single
 ** translation unit.
 **
 ** This file is all you need to compile SQLite.  To use SQLite in other
@@ -354,15 +354,21 @@
 #endif
 
 /*
-** The SQLITE_THREADSAFE macro must be defined as either 0 or 1.
+** The SQLITE_THREADSAFE macro must be defined as 0, 1, or 2.
+** 0 means mutexes are permanently disable and the library is never
+** threadsafe.  1 means the library is serialized which is the highest
+** level of threadsafety.  2 means the libary is multithreaded - multiple
+** threads can use SQLite as long as no two threads try to use the same
+** database connection at the same time.
+**
 ** Older versions of SQLite used an optional THREADSAFE macro.
-** We support that for legacy
+** We support that for legacy.
 */
 #if !defined(SQLITE_THREADSAFE)
 #if defined(THREADSAFE)
 # define SQLITE_THREADSAFE THREADSAFE
 #else
-# define SQLITE_THREADSAFE 1
+# define SQLITE_THREADSAFE 1 /* IMP: R-07272-22309 */
 #endif
 #endif
 
@@ -644,9 +650,9 @@ extern "C" {
 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
 ** [sqlite_version()] and [sqlite_source_id()].
 */
-#define SQLITE_VERSION        "3.7.2"
-#define SQLITE_VERSION_NUMBER 3007002
-#define SQLITE_SOURCE_ID      "2010-08-23 18:52:01 42537b60566f288167f1b5864a5435986838e3a3"
+#define SQLITE_VERSION        "3.7.5"
+#define SQLITE_VERSION_NUMBER 3007005
+#define SQLITE_SOURCE_ID      "2011-01-28 17:03:50 ed759d5a9edb3bba5f48f243df47be29e3fe8cd7"
 
 /*
 ** CAPI3REF: Run-Time Library Version Numbers
@@ -927,7 +933,7 @@ SQLITE_API int sqlite3_exec(
 #define SQLITE_INTERRUPT    9   /* Operation terminated by sqlite3_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   /* NOT USED. Table or record not found */
+#define SQLITE_NOTFOUND    12   /* Unknown opcode in sqlite3_file_control() */
 #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 */
@@ -1079,6 +1085,18 @@ SQLITE_API int sqlite3_exec(
 ** equal SQLITE_SYNC_NORMAL, that means to use normal fsync() semantics.
 ** If the lower four bits equal SQLITE_SYNC_FULL, that means
 ** to use Mac OS X style fullsync instead of fsync().
+**
+** Do not confuse the SQLITE_SYNC_NORMAL and SQLITE_SYNC_FULL flags
+** with the [PRAGMA synchronous]=NORMAL and [PRAGMA synchronous]=FULL
+** settings.  The [synchronous pragma] determines when calls to the
+** xSync VFS method occur and applies uniformly across all platforms.
+** The SQLITE_SYNC_NORMAL and SQLITE_SYNC_FULL flags determine how
+** energetic or rigorous or forceful the sync operations are and
+** only make a difference on Mac OSX for the default SQLite code.
+** (Third-party VFS implementations might also make the distinction
+** between SQLITE_SYNC_NORMAL and SQLITE_SYNC_FULL, but among the
+** operating systems natively supported by SQLite, only Mac OSX
+** cares about the difference.)
 */
 #define SQLITE_SYNC_NORMAL        0x00002
 #define SQLITE_SYNC_FULL          0x00003
@@ -1147,7 +1165,9 @@ struct sqlite3_file {
 ** core reserves all opcodes less than 100 for its own use.
 ** A [SQLITE_FCNTL_LOCKSTATE | list of opcodes] less than 100 is available.
 ** Applications that define a custom xFileControl method should use opcodes
-** greater than 100 to avoid conflicts.
+** greater than 100 to avoid conflicts.  VFS implementations should
+** return [SQLITE_NOTFOUND] for file control opcodes that they do not
+** recognize.
 **
 ** The xSectorSize() method returns the sector size of the
 ** device that underlies the file.  The sector size is the
@@ -1240,6 +1260,21 @@ struct sqlite3_io_methods {
 ** for the nominated database. Allocating database file space in large
 ** chunks (say 1MB at a time), may reduce file-system fragmentation and
 ** improve performance on some systems.
+**
+** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer
+** to the [sqlite3_file] object associated with a particular database
+** connection.  See the [sqlite3_file_control()] documentation for
+** additional information.
+**
+** ^(The [SQLITE_FCNTL_SYNC_OMITTED] opcode is generated internally by
+** SQLite and sent to all VFSes in place of a call to the xSync method
+** when the database connection has [PRAGMA synchronous] set to OFF.)^
+** Some specialized VFSes need this signal in order to operate correctly
+** when [PRAGMA synchronous | PRAGMA synchronous=OFF] is set, but most 
+** VFSes do not need this signal and should silently ignore this opcode.
+** Applications should not call [sqlite3_file_control()] with this
+** opcode as doing so may disrupt the operation of the specilized VFSes
+** that do require it.  
 */
 #define SQLITE_FCNTL_LOCKSTATE        1
 #define SQLITE_GET_LOCKPROXYFILE      2
@@ -1247,6 +1282,9 @@ struct sqlite3_io_methods {
 #define SQLITE_LAST_ERRNO             4
 #define SQLITE_FCNTL_SIZE_HINT        5
 #define SQLITE_FCNTL_CHUNK_SIZE       6
+#define SQLITE_FCNTL_FILE_POINTER     7
+#define SQLITE_FCNTL_SYNC_OMITTED     8
+
 
 /*
 ** CAPI3REF: Mutex Handle
@@ -1294,15 +1332,19 @@ typedef struct sqlite3_mutex sqlite3_mutex;
 ** The zName field holds the name of the VFS module.  The name must
 ** be unique across all VFS modules.
 **
-** SQLite will guarantee that the zFilename parameter to xOpen
+** ^SQLite guarantees that the zFilename parameter to xOpen
 ** is either a NULL pointer or string obtained
-** from xFullPathname().  SQLite further guarantees that
+** from xFullPathname() with an optional suffix added.
+** ^If a suffix is added to the zFilename parameter, it will
+** consist of a single "-" character followed by no more than
+** 10 alphanumeric and/or "-" characters.
+** ^SQLite further guarantees that
 ** the string will be valid and unchanged until xClose() is
 ** called. Because of the previous sentence,
 ** the [sqlite3_file] can safely store a pointer to the
 ** filename if it needs to remember the filename for some reason.
-** If the zFilename parameter is xOpen is a NULL pointer then xOpen
-** must invent its own temporary name for the file.  Whenever the 
+** If the zFilename parameter to xOpen is a NULL pointer then xOpen
+** must invent its own temporary name for the file.  ^Whenever the 
 ** xFilename parameter is NULL it will also be the case that the
 ** flags parameter will include [SQLITE_OPEN_DELETEONCLOSE].
 **
@@ -1313,7 +1355,7 @@ typedef struct sqlite3_mutex sqlite3_mutex;
 ** If xOpen() opens a file read-only then it sets *pOutFlags to
 ** include [SQLITE_OPEN_READONLY].  Other bits in *pOutFlags may be set.
 **
-** SQLite will also add one of the following flags to the xOpen()
+** ^(SQLite will also add one of the following flags to the xOpen()
 ** call, depending on the object being opened:
 **
 ** <ul>
@@ -1324,7 +1366,8 @@ typedef struct sqlite3_mutex sqlite3_mutex;
 ** <li>  [SQLITE_OPEN_TRANSIENT_DB]
 ** <li>  [SQLITE_OPEN_SUBJOURNAL]
 ** <li>  [SQLITE_OPEN_MASTER_JOURNAL]
-** </ul>
+** <li>  [SQLITE_OPEN_WAL]
+** </ul>)^
 **
 ** The file I/O implementation can use the object type flags to
 ** change the way it deals with files.  For example, an application
@@ -1343,10 +1386,11 @@ typedef struct sqlite3_mutex sqlite3_mutex;
 ** </ul>
 **
 ** The [SQLITE_OPEN_DELETEONCLOSE] flag means the file should be
-** deleted when it is closed.  The [SQLITE_OPEN_DELETEONCLOSE]
-** will be set for TEMP  databases, journals and for subjournals.
+** deleted when it is closed.  ^The [SQLITE_OPEN_DELETEONCLOSE]
+** will be set for TEMP databases and their journals, transient
+** databases, and subjournals.
 **
-** The [SQLITE_OPEN_EXCLUSIVE] flag is always used in conjunction
+** ^The [SQLITE_OPEN_EXCLUSIVE] flag is always used in conjunction
 ** with the [SQLITE_OPEN_CREATE] flag, which are both directly
 ** analogous to the O_EXCL and O_CREAT flags of the POSIX open()
 ** API.  The SQLITE_OPEN_EXCLUSIVE flag, when paired with the 
@@ -1355,7 +1399,7 @@ typedef struct sqlite3_mutex sqlite3_mutex;
 ** It is <i>not</i> used to indicate the file should be opened 
 ** for exclusive access.
 **
-** At least szOsFile bytes of memory are allocated by SQLite
+** ^At least szOsFile bytes of memory are allocated by SQLite
 ** to hold the  [sqlite3_file] structure passed as the third
 ** argument to xOpen.  The xOpen method does not have to
 ** allocate the structure; it should just fill it in.  Note that
@@ -1365,13 +1409,13 @@ typedef struct sqlite3_mutex sqlite3_mutex;
 ** element will be valid after xOpen returns regardless of the success
 ** or failure of the xOpen call.
 **
-** The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS]
+** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS]
 ** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to
 ** test whether a file is readable and writable, or [SQLITE_ACCESS_READ]
 ** to test whether a file is at least readable.   The file can be a
 ** directory.
 **
-** SQLite will always allocate at least mxPathname+1 bytes for the
+** ^SQLite will always allocate at least mxPathname+1 bytes for the
 ** output buffer xFullPathname.  The exact size of the output buffer
 ** is also passed as a parameter to both  methods. If the output buffer
 ** is not large enough, [SQLITE_CANTOPEN] should be returned. Since this is
@@ -1385,10 +1429,10 @@ typedef struct sqlite3_mutex sqlite3_mutex;
 ** of good-quality randomness into zOut.  The return value is
 ** the actual number of bytes of randomness obtained.
 ** The xSleep() method causes the calling thread to sleep for at
-** least the number of microseconds given.  The xCurrentTime()
+** least the number of microseconds given.  ^The xCurrentTime()
 ** method returns a Julian Day Number for the current date and time as
 ** a floating point value.
-** The xCurrentTimeInt64() method returns, as an integer, the Julian
+** ^The xCurrentTimeInt64() method returns, as an integer, the Julian
 ** Day Number multipled by 86400000 (the number of milliseconds in 
 ** a 24-hour day).  
 ** ^SQLite will use the xCurrentTimeInt64() method to get the current
@@ -1785,7 +1829,7 @@ struct sqlite3_mem_methods {
 **   <ul>
 **   <li> [sqlite3_memory_used()]
 **   <li> [sqlite3_memory_highwater()]
-**   <li> [sqlite3_soft_heap_limit()]
+**   <li> [sqlite3_soft_heap_limit64()]
 **   <li> [sqlite3_status()]
 **   </ul>)^
 ** ^Memory allocation statistics are enabled by default unless SQLite is
@@ -1799,15 +1843,14 @@ struct sqlite3_mem_methods {
 ** aligned memory buffer from which the scrach allocations will be
 ** drawn, the size of each scratch allocation (sz),
 ** and the maximum number of scratch allocations (N).  The sz
-** argument must be a multiple of 16. The sz parameter should be a few bytes
-** larger than the actual scratch space required due to internal overhead.
+** argument must be a multiple of 16.
 ** The first argument must be a pointer to an 8-byte aligned buffer
 ** of at least sz*N bytes of memory.
-** ^SQLite will use no more than one scratch buffer per thread.  So
-** N should be set to the expected maximum number of threads.  ^SQLite will
-** never require a scratch buffer that is more than 6 times the database
-** page size. ^If SQLite needs needs additional scratch memory beyond 
-** what is provided by this configuration option, then 
+** ^SQLite will use no more than two scratch buffers per thread.  So
+** N should be set to twice the expected maximum number of threads.
+** ^SQLite will never require a scratch buffer that is more than 6
+** times the database page size. ^If SQLite needs needs additional
+** scratch memory beyond what is provided by this configuration option, then 
 ** [sqlite3_malloc()] will be used to obtain the memory needed.</dd>
 **
 ** <dt>SQLITE_CONFIG_PAGECACHE</dt>
@@ -1827,8 +1870,7 @@ struct sqlite3_mem_methods {
 ** memory needs for the first N pages that it adds to cache.  ^If additional
 ** page cache memory is needed beyond what is provided by this option, then
 ** SQLite goes to [sqlite3_malloc()] for the additional storage space.
-** ^The implementation might use one or more of the N buffers to hold 
-** memory accounting information. The pointer in the first argument must
+** The pointer in the first argument must
 ** be aligned to an 8-byte boundary or subsequent behavior of SQLite
 ** will be undefined.</dd>
 **
@@ -1957,8 +1999,14 @@ struct sqlite3_mem_methods {
 ** or equal to the product of the second and third arguments.  The buffer
 ** must be aligned to an 8-byte boundary.  ^If the second argument to
 ** SQLITE_DBCONFIG_LOOKASIDE is not a multiple of 8, it is internally
-** rounded down to the next smaller
-** multiple of 8.  See also: [SQLITE_CONFIG_LOOKASIDE]</dd>
+** rounded down to the next smaller multiple of 8.  ^(The lookaside memory
+** configuration for a database connection can only be changed when that
+** connection is not currently using lookaside memory, or in other words
+** when the "current value" returned by
+** [sqlite3_db_status](D,[SQLITE_CONFIG_LOOKASIDE],...) is zero.
+** Any attempt to change the lookaside memory configuration when lookaside
+** memory is in use leaves the configuration unchanged and returns 
+** [SQLITE_BUSY].)^</dd>
 **
 ** </dl>
 */
@@ -2263,6 +2311,9 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
 /*
 ** CAPI3REF: Convenience Routines For Running Queries
 **
+** This is a legacy interface that is preserved for backwards compatibility.
+** Use of this interface is not recommended.
+**
 ** Definition: A <b>result table</b> is memory data structure created by the
 ** [sqlite3_get_table()] interface.  A result table records the
 ** complete query results from one or more queries.
@@ -2283,7 +2334,7 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
 ** It is not safe to pass a result table directly to [sqlite3_free()].
 ** A result table should be deallocated using [sqlite3_free_table()].
 **
-** As an example of the result table format, suppose a query result
+** ^(As an example of the result table format, suppose a query result
 ** is as follows:
 **
 ** <blockquote><pre>
@@ -2307,7 +2358,7 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
 **        azResult&#91;5] = "28";
 **        azResult&#91;6] = "Cindy";
 **        azResult&#91;7] = "21";
-** </pre></blockquote>
+** </pre></blockquote>)^
 **
 ** ^The sqlite3_get_table() function evaluates one or more
 ** semicolon-separated SQL statements in the zero-terminated UTF-8
@@ -2315,19 +2366,19 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
 ** pointer given in its 3rd parameter.
 **
 ** After the application has finished with the result from sqlite3_get_table(),
-** it should pass the result table pointer to sqlite3_free_table() in order to
+** it must pass the result table pointer to sqlite3_free_table() in order to
 ** release the memory that was malloced.  Because of the way the
 ** [sqlite3_malloc()] happens within sqlite3_get_table(), the calling
 ** function must not try to call [sqlite3_free()] directly.  Only
 ** [sqlite3_free_table()] is able to release the memory properly and safely.
 **
-** ^(The sqlite3_get_table() interface is implemented as a wrapper around
+** The sqlite3_get_table() interface is implemented as a wrapper around
 ** [sqlite3_exec()].  The sqlite3_get_table() routine does not have access
 ** to any internal data structures of SQLite.  It uses only the public
 ** interface defined here.  As a consequence, errors that occur in the
 ** wrapper layer outside of the internal [sqlite3_exec()] call are not
 ** reflected in subsequent calls to [sqlite3_errcode()] or
-** [sqlite3_errmsg()].)^
+** [sqlite3_errmsg()].
 */
 SQLITE_API int sqlite3_get_table(
   sqlite3 *db,          /* An open database */
@@ -2352,7 +2403,7 @@ SQLITE_API void sqlite3_free_table(char **result);
 ** NULL pointer if [sqlite3_malloc()] is unable to allocate enough
 ** memory to hold the resulting string.
 **
-** ^(In sqlite3_snprintf() routine is similar to "snprintf()" from
+** ^(The sqlite3_snprintf() routine is similar to "snprintf()" from
 ** the standard C library.  The result is written into the
 ** buffer supplied as the second parameter whose size is given by
 ** the first parameter. Note that the order of the
@@ -2371,6 +2422,8 @@ SQLITE_API void sqlite3_free_table(char **result);
 ** the zero terminator.  So the longest string that can be completely
 ** written will be n-1 characters.
 **
+** ^The sqlite3_vsnprintf() routine is a varargs version of sqlite3_snprintf().
+**
 ** These routines all implement some additional formatting
 ** options that are useful for constructing SQL statements.
 ** All of the usual printf() formatting options apply.  In addition, there
@@ -2434,6 +2487,7 @@ SQLITE_API void sqlite3_free_table(char **result);
 SQLITE_API char *sqlite3_mprintf(const char*,...);
 SQLITE_API char *sqlite3_vmprintf(const char*, va_list);
 SQLITE_API char *sqlite3_snprintf(int,char*,const char*, ...);
+SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
 
 /*
 ** CAPI3REF: Memory Allocation Subsystem
@@ -2479,7 +2533,9 @@ SQLITE_API char *sqlite3_snprintf(int,char*,const char*, ...);
 ** is not freed.
 **
 ** ^The memory returned by sqlite3_malloc() and sqlite3_realloc()
-** is always aligned to at least an 8 byte boundary.
+** is always aligned to at least an 8 byte boundary, or to a
+** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time
+** option is used.
 **
 ** In SQLite version 3.5.0 and 3.5.1, it was possible to define
 ** the SQLITE_OMIT_MEMORY_ALLOCATION which would cause the built-in
@@ -2737,17 +2793,28 @@ SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*,
 /*
 ** CAPI3REF: Query Progress Callbacks
 **
-** ^This routine configures a callback function - the
-** progress callback - that is invoked periodically during long
-** running calls to [sqlite3_exec()], [sqlite3_step()] and
-** [sqlite3_get_table()].  An example use for this
+** ^The sqlite3_progress_handler(D,N,X,P) interface causes the callback
+** function X to be invoked periodically during long running calls to
+** [sqlite3_exec()], [sqlite3_step()] and [sqlite3_get_table()] for
+** database connection D.  An example use for this
 ** interface is to keep a GUI updated during a large query.
 **
+** ^The parameter P is passed through as the only parameter to the 
+** callback function X.  ^The parameter N is the number of 
+** [virtual machine instructions] that are evaluated between successive
+** invocations of the callback X.
+**
+** ^Only a single progress handler may be defined at one time per
+** [database connection]; setting a new progress handler cancels the
+** old one.  ^Setting parameter X to NULL disables the progress handler.
+** ^The progress handler is also disabled by setting N to a value less
+** than 1.
+**
 ** ^If the progress callback returns non-zero, the operation is
 ** interrupted.  This feature can be used to implement a
 ** "Cancel" button on a GUI progress dialog box.
 **
-** The progress handler must not do anything that will modify
+** The progress handler callback must not do anything that will modify
 ** the database connection that invoked the progress handler.
 ** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their
 ** database connections for the meaning of "modify" in this paragraph.
@@ -2798,7 +2865,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
 ** case the database must already exist, otherwise an error is returned.</dd>)^
 **
 ** ^(<dt>[SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]</dt>
-** <dd>The database is opened for reading and writing, and is creates it if
+** <dd>The database is opened for reading and writing, and is created if
 ** it does not already exist. This is the behavior that is always used for
 ** sqlite3_open() and sqlite3_open16().</dd>)^
 ** </dl>
@@ -2806,7 +2873,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
 ** If the 3rd parameter to sqlite3_open_v2() is not one of the
 ** combinations shown above or one of the combinations shown above combined
 ** with the [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX],
-** [SQLITE_OPEN_SHAREDCACHE] and/or [SQLITE_OPEN_SHAREDCACHE] flags,
+** [SQLITE_OPEN_SHAREDCACHE] and/or [SQLITE_OPEN_PRIVATECACHE] flags,
 ** then the behavior is undefined.
 **
 ** ^If the [SQLITE_OPEN_NOMUTEX] flag is set, then the database connection
@@ -2931,17 +2998,22 @@ typedef struct sqlite3_stmt sqlite3_stmt;
 ** [database connection] whose limit is to be set or queried.  The
 ** second parameter is one of the [limit categories] that define a
 ** class of constructs to be size limited.  The third parameter is the
-** new limit for that construct.  The function returns the old limit.)^
+** new limit for that construct.)^
 **
 ** ^If the new limit is a negative number, the limit is unchanged.
-** ^(For the limit category of SQLITE_LIMIT_XYZ there is a 
+** ^(For each limit category SQLITE_LIMIT_<i>NAME</i> there is a 
 ** [limits | hard upper bound]
-** set by a compile-time C preprocessor macro named 
-** [limits | SQLITE_MAX_XYZ].
+** set at compile-time by a C preprocessor macro called
+** [limits | SQLITE_MAX_<i>NAME</i>].
 ** (The "_LIMIT_" in the name is changed to "_MAX_".))^
 ** ^Attempts to increase a limit above its hard upper bound are
 ** silently truncated to the hard upper bound.
 **
+** ^Regardless of whether or not the limit was changed, the 
+** [sqlite3_limit()] interface returns the prior value of the limit.
+** ^Hence, to find the current value of a limit without changing it,
+** simply invoke this interface with the third parameter set to -1.
+**
 ** Run-time limits are intended for use in applications that manage
 ** both their own internal database and also databases that are controlled
 ** by untrusted external sources.  An example application might be a
@@ -2970,7 +3042,7 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
 **
 ** <dl>
 ** ^(<dt>SQLITE_LIMIT_LENGTH</dt>
-** <dd>The maximum size of any string or BLOB or table row.<dd>)^
+** <dd>The maximum size of any string or BLOB or table row, in bytes.<dd>)^
 **
 ** ^(<dt>SQLITE_LIMIT_SQL_LENGTH</dt>
 ** <dd>The maximum length of an SQL statement, in bytes.</dd>)^
@@ -2988,7 +3060,9 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
 **
 ** ^(<dt>SQLITE_LIMIT_VDBE_OP</dt>
 ** <dd>The maximum number of instructions in a virtual machine program
-** used to implement an SQL statement.</dd>)^
+** used to implement an SQL statement.  This limit is not currently
+** enforced, though that might be added in some future release of
+** SQLite.</dd>)^
 **
 ** ^(<dt>SQLITE_LIMIT_FUNCTION_ARG</dt>
 ** <dd>The maximum number of arguments on a function.</dd>)^
@@ -3001,8 +3075,7 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
 ** [GLOB] operators.</dd>)^
 **
 ** ^(<dt>SQLITE_LIMIT_VARIABLE_NUMBER</dt>
-** <dd>The maximum number of variables in an SQL statement that can
-** be bound.</dd>)^
+** <dd>The maximum index number of any [parameter] in an SQL statement.)^
 **
 ** ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt>
 ** <dd>The maximum depth of recursion for triggers.</dd>)^
@@ -3074,12 +3147,7 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
 ** <li>
 ** ^If the database schema changes, instead of returning [SQLITE_SCHEMA] as it
 ** always used to do, [sqlite3_step()] will automatically recompile the SQL
-** statement and try to run it again.  ^If the schema has changed in
-** a way that makes the statement no longer valid, [sqlite3_step()] will still
-** return [SQLITE_SCHEMA].  But unlike the legacy behavior, [SQLITE_SCHEMA] is
-** now a fatal error.  Calling [sqlite3_prepare_v2()] again will not make the
-** error go away.  Note: use [sqlite3_errmsg()] to find the text
-** of the parsing error that results in an [SQLITE_SCHEMA] return.
+** statement and try to run it again.
 ** </li>
 **
 ** <li>
@@ -3092,11 +3160,16 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
 ** </li>
 **
 ** <li>
-** ^If the value of a [parameter | host parameter] in the WHERE clause might
-** change the query plan for a statement, then the statement may be
-** automatically recompiled (as if there had been a schema change) on the first 
-** [sqlite3_step()] call following any change to the 
-** [sqlite3_bind_text | bindings] of the [parameter]. 
+** ^If the specific value bound to [parameter | host parameter] in the 
+** WHERE clause might influence the choice of query plan for a statement,
+** then the statement will be automatically recompiled, as if there had been 
+** a schema change, on the first  [sqlite3_step()] call following any change
+** to the [sqlite3_bind_text | bindings] of that [parameter]. 
+** ^The specific value of WHERE-clause [parameter] might influence the 
+** choice of query plan if the parameter is the left-hand side of a [LIKE]
+** or [GLOB] operator or if the parameter is compared to an indexed column
+** and the [SQLITE_ENABLE_STAT2] compile-time option is enabled.
+** the 
 ** </li>
 ** </ol>
 */
@@ -3139,6 +3212,37 @@ SQLITE_API int sqlite3_prepare16_v2(
 SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
 
 /*
+** CAPI3REF: Determine If An SQL Statement Writes The Database
+**
+** ^The sqlite3_stmt_readonly(X) interface returns true (non-zero) if 
+** and only if the [prepared statement] X makes no direct changes to
+** the content of the database file.
+**
+** Note that [application-defined SQL functions] or
+** [virtual tables] might change the database indirectly as a side effect.  
+** ^(For example, if an application defines a function "eval()" that 
+** calls [sqlite3_exec()], then the following SQL statement would
+** change the database file through side-effects:
+**
+** <blockquote><pre>
+**    SELECT eval('DELETE FROM t1') FROM t2;
+** </pre></blockquote>
+**
+** But because the [SELECT] statement does not change the database file
+** directly, sqlite3_stmt_readonly() would still return true.)^
+**
+** ^Transaction control statements such as [BEGIN], [COMMIT], [ROLLBACK],
+** [SAVEPOINT], and [RELEASE] cause sqlite3_stmt_readonly() to return true,
+** since the statements themselves do not actually modify the database but
+** rather they control the timing of when other statements modify the 
+** database.  ^The [ATTACH] and [DETACH] statements also cause
+** sqlite3_stmt_readonly() to return true since, while those statements
+** change the configuration of a database connection, they do not make 
+** changes to the content of the database files on disk.
+*/
+SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
+
+/*
 ** CAPI3REF: Dynamically Typed Value Object
 ** KEYWORDS: {protected sqlite3_value} {unprotected sqlite3_value}
 **
@@ -3163,7 +3267,7 @@ SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
 ** then there is no distinction between protected and unprotected
 ** sqlite3_value objects and they can be used interchangeably.  However,
 ** for maximum code portability it is recommended that applications
-** still make the distinction between between protected and unprotected
+** still make the distinction between protected and unprotected
 ** sqlite3_value objects even when not strictly required.
 **
 ** ^The sqlite3_value objects that are passed as parameters into the
@@ -3237,7 +3341,10 @@ typedef struct sqlite3_context sqlite3_context;
 **
 ** ^The fifth argument to sqlite3_bind_blob(), sqlite3_bind_text(), and
 ** sqlite3_bind_text16() is a destructor used to dispose of the BLOB or
-** string after SQLite has finished with it. ^If the fifth argument is
+** string after SQLite has finished with it.  ^The destructor is called
+** to dispose of the BLOB or string even if the call to sqlite3_bind_blob(),
+** sqlite3_bind_text(), or sqlite3_bind_text16() fails.  
+** ^If the fifth argument is
 ** the special value [SQLITE_STATIC], then SQLite assumes that the
 ** information is in static, unmanaged space and does not need to be freed.
 ** ^If the fifth argument has the value [SQLITE_TRANSIENT], then
@@ -3358,6 +3465,8 @@ SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*);
 ** ^Return the number of columns in the result set returned by the
 ** [prepared statement]. ^This routine returns 0 if pStmt is an SQL
 ** statement that does not return data (for example an [UPDATE]).
+**
+** See also: [sqlite3_data_count()]
 */
 SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt);
 
@@ -3523,13 +3632,17 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
 ** be the case that the same database connection is being used by two or
 ** more threads at the same moment in time.
 **
-** For all versions of SQLite up to and including 3.6.23.1, it was required
-** after sqlite3_step() returned anything other than [SQLITE_ROW] that
-** [sqlite3_reset()] be called before any subsequent invocation of
-** sqlite3_step().  Failure to invoke [sqlite3_reset()] in this way would
-** result in an [SQLITE_MISUSE] return from sqlite3_step().  But after
-** version 3.6.23.1, sqlite3_step() began calling [sqlite3_reset()] 
-** automatically in this circumstance rather than returning [SQLITE_MISUSE].  
+** For all versions of SQLite up to and including 3.6.23.1, a call to
+** [sqlite3_reset()] was required after sqlite3_step() returned anything
+** other than [SQLITE_ROW] before any subsequent invocation of
+** sqlite3_step().  Failure to reset the prepared statement using 
+** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from
+** sqlite3_step().  But after version 3.6.23.1, sqlite3_step() began
+** calling [sqlite3_reset()] automatically in this circumstance rather
+** than returning [SQLITE_MISUSE].  This is not considered a compatibility
+** break because any application that ever receives an SQLITE_MISUSE error
+** is broken by definition.  The [SQLITE_OMIT_AUTORESET] compile-time option
+** can be used to restore the legacy behavior.
 **
 ** <b>Goofy Interface Alert:</b> In the legacy interface, the sqlite3_step()
 ** API always returns a generic error code, [SQLITE_ERROR], following any
@@ -3548,8 +3661,14 @@ SQLITE_API int sqlite3_step(sqlite3_stmt*);
 /*
 ** CAPI3REF: Number of columns in a result set
 **
-** ^The sqlite3_data_count(P) the number of columns in the
-** of the result set of [prepared statement] P.
+** ^The sqlite3_data_count(P) interface returns the number of columns in the
+** current row of the result set of [prepared statement] P.
+** ^If prepared statement P does not have results ready to return
+** (via calls to the [sqlite3_column_int | sqlite3_column_*()] of
+** interfaces) then sqlite3_data_count(P) returns 0.
+** ^The sqlite3_data_count(P) routine also returns 0 if P is a NULL pointer.
+**
+** See also: [sqlite3_column_count()]
 */
 SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
 
@@ -3629,18 +3748,26 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
 ** ^If the result is a numeric value then sqlite3_column_bytes() uses
 ** [sqlite3_snprintf()] to convert that value to a UTF-8 string and returns
 ** the number of bytes in that string.
-** ^The value returned does not include the zero terminator at the end
-** of the string.  ^For clarity: the value returned is the number of
+** ^If the result is NULL, then sqlite3_column_bytes() returns zero.
+**
+** ^If the result is a BLOB or UTF-16 string then the sqlite3_column_bytes16()
+** routine returns the number of bytes in that BLOB or string.
+** ^If the result is a UTF-8 string, then sqlite3_column_bytes16() converts
+** the string to UTF-16 and then returns the number of bytes.
+** ^If the result is a numeric value then sqlite3_column_bytes16() uses
+** [sqlite3_snprintf()] to convert that value to a UTF-16 string and returns
+** the number of bytes in that string.
+** ^If the result is NULL, then sqlite3_column_bytes16() returns zero.
+**
+** ^The values returned by [sqlite3_column_bytes()] and 
+** [sqlite3_column_bytes16()] do not include the zero terminators at the end
+** of the string.  ^For clarity: the values returned by
+** [sqlite3_column_bytes()] and [sqlite3_column_bytes16()] are the number of
 ** bytes in the string, not the number of characters.
 **
 ** ^Strings returned by sqlite3_column_text() and sqlite3_column_text16(),
 ** even empty strings, are always zero terminated.  ^The return
-** value from sqlite3_column_blob() for a zero-length BLOB is an arbitrary
-** pointer, possibly even a NULL pointer.
-**
-** ^The sqlite3_column_bytes16() routine is similar to sqlite3_column_bytes()
-** but leaves the result in UTF-16 in native byte order instead of UTF-8.
-** ^The zero terminator is not included in this count.
+** value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer.
 **
 ** ^The object returned by [sqlite3_column_value()] is an
 ** [unprotected sqlite3_value] object.  An unprotected sqlite3_value object
@@ -3685,10 +3812,10 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
 ** used in the table for brevity and because they are familiar to most
 ** C programmers.
 **
-** ^Note that when type conversions occur, pointers returned by prior
+** Note that when type conversions occur, pointers returned by prior
 ** calls to sqlite3_column_blob(), sqlite3_column_text(), and/or
 ** sqlite3_column_text16() may be invalidated.
-** ^(Type conversions and pointer invalidations might occur
+** Type conversions and pointer invalidations might occur
 ** in the following cases:
 **
 ** <ul>
@@ -3701,22 +3828,22 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
 ** <li> The initial content is UTF-16 text and sqlite3_column_bytes() or
 **      sqlite3_column_text() is called.  The content must be converted
 **      to UTF-8.</li>
-** </ul>)^
+** </ul>
 **
 ** ^Conversions between UTF-16be and UTF-16le are always done in place and do
 ** not invalidate a prior pointer, though of course the content of the buffer
-** that the prior pointer points to will have been modified.  Other kinds
+** that the prior pointer references will have been modified.  Other kinds
 ** of conversion are done in place when it is possible, but sometimes they
 ** are not possible and in those cases prior pointers are invalidated.
 **
-** ^(The safest and easiest to remember policy is to invoke these routines
+** The safest and easiest to remember policy is to invoke these routines
 ** in one of the following ways:
 **
 ** <ul>
 **  <li>sqlite3_column_text() followed by sqlite3_column_bytes()</li>
 **  <li>sqlite3_column_blob() followed by sqlite3_column_bytes()</li>
 **  <li>sqlite3_column_text16() followed by sqlite3_column_bytes16()</li>
-** </ul>)^
+** </ul>
 **
 ** In other words, you should call sqlite3_column_text(),
 ** sqlite3_column_blob(), or sqlite3_column_text16() first to force the result
@@ -3754,17 +3881,26 @@ SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
 ** CAPI3REF: Destroy A Prepared Statement Object
 **
 ** ^The sqlite3_finalize() function is called to delete a [prepared statement].
-** ^If the statement was executed successfully or not executed at all, then
-** SQLITE_OK is returned. ^If execution of the statement failed then an
-** [error code] or [extended error code] is returned.
-**
-** ^This routine can be called at any point during the execution of the
-** [prepared statement].  ^If the virtual machine has not
-** completed execution when this routine is called, that is like
-** encountering an error or an [sqlite3_interrupt | interrupt].
-** ^Incomplete updates may be rolled back and transactions canceled,
-** depending on the circumstances, and the
-** [error code] returned will be [SQLITE_ABORT].
+** ^If the most recent evaluation of the statement encountered no errors or
+** or if the statement is never been evaluated, then sqlite3_finalize() returns
+** SQLITE_OK.  ^If the most recent evaluation of statement S failed, then
+** sqlite3_finalize(S) returns the appropriate [error code] or
+** [extended error code].
+**
+** ^The sqlite3_finalize(S) routine can be called at any point during
+** the life cycle of [prepared statement] S:
+** before statement S is ever evaluated, after
+** one or more calls to [sqlite3_reset()], or after any call
+** to [sqlite3_step()] regardless of whether or not the statement has
+** completed execution.
+**
+** ^Invoking sqlite3_finalize() on a NULL pointer is a harmless no-op.
+**
+** The application must finalize every [prepared statement] in order to avoid
+** resource leaks.  It is a grievous error for the application to try to use
+** a prepared statement after it has been finalized.  Any use of a prepared
+** statement after it has been finalized can result in undefined and
+** undesirable behavior such as segfaults and heap corruption.
 */
 SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt);
 
@@ -3800,23 +3936,25 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
 ** KEYWORDS: {application-defined SQL function}
 ** KEYWORDS: {application-defined SQL functions}
 **
-** ^These two functions (collectively known as "function creation routines")
+** ^These functions (collectively known as "function creation routines")
 ** are used to add SQL functions or aggregates or to redefine the behavior
-** of existing SQL functions or aggregates.  The only difference between the
-** two is that the second parameter, the name of the (scalar) function or
-** aggregate, is encoded in UTF-8 for sqlite3_create_function() and UTF-16
-** for sqlite3_create_function16().
+** of existing SQL functions or aggregates.  The only differences between
+** these routines are the text encoding expected for
+** the the second parameter (the name of the function being created)
+** and the presence or absence of a destructor callback for
+** the application data pointer.
 **
 ** ^The first parameter is the [database connection] to which the SQL
 ** function is to be added.  ^If an application uses more than one database
 ** connection then application-defined SQL functions must be added
 ** to each database connection separately.
 **
-** The second parameter is the name of the SQL function to be created or
-** redefined.  ^The length of the name is limited to 255 bytes, exclusive of
-** the zero-terminator.  Note that the name length limit is in bytes, not
-** characters.  ^Any attempt to create a function with a longer name
-** will result in [SQLITE_ERROR] being returned.
+** ^The second parameter is the name of the SQL function to be created or
+** redefined.  ^The length of the name is limited to 255 bytes in a UTF-8
+** representation, exclusive of the zero-terminator.  ^Note that the name
+** length limit is in UTF-8 bytes, not characters nor UTF-16 bytes.  
+** ^Any attempt to create a function with a longer name
+** will result in [SQLITE_MISUSE] being returned.
 **
 ** ^The third parameter (nArg)
 ** is the number of arguments that the SQL function or
@@ -3826,10 +3964,10 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
 ** parameter is less than -1 or greater than 127 then the behavior is
 ** undefined.
 **
-** The fourth parameter, eTextRep, specifies what
+** ^The fourth parameter, eTextRep, specifies what
 ** [SQLITE_UTF8 | text encoding] this SQL function prefers for
-** its parameters.  Any SQL function implementation should be able to work
-** work with UTF-8, UTF-16le, or UTF-16be.  But some implementations may be
+** its parameters.  Every SQL function implementation must be able to work
+** with UTF-8, UTF-16le, or UTF-16be.  But some implementations may be
 ** more efficient with one encoding than another.  ^An application may
 ** invoke sqlite3_create_function() or sqlite3_create_function16() multiple
 ** times with the same function but with different values of eTextRep.
@@ -3841,13 +3979,24 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
 ** ^(The fifth parameter is an arbitrary pointer.  The implementation of the
 ** function can gain access to this pointer using [sqlite3_user_data()].)^
 **
-** The seventh, eighth and ninth parameters, xFunc, xStep and xFinal, are
+** ^The sixth, seventh and eighth parameters, xFunc, xStep and xFinal, are
 ** pointers to C-language functions that implement the SQL function or
 ** aggregate. ^A scalar SQL function requires an implementation of the xFunc
-** callback only; NULL pointers should be passed as the xStep and xFinal
+** callback only; NULL pointers must be passed as the xStep and xFinal
 ** parameters. ^An aggregate SQL function requires an implementation of xStep
-** and xFinal and NULL should be passed for xFunc. ^To delete an existing
-** SQL function or aggregate, pass NULL for all three function callbacks.
+** and xFinal and NULL pointer must be passed for xFunc. ^To delete an existing
+** SQL function or aggregate, pass NULL poiners for all three function
+** callbacks.
+**
+** ^(If the ninth parameter to sqlite3_create_function_v2() is not NULL,
+** then it is destructor for the application data pointer. 
+** The destructor is invoked when the function is deleted, either by being
+** overloaded or when the database connection closes.)^
+** ^The destructor is also invoked if the call to
+** sqlite3_create_function_v2() fails.
+** ^When the destructor callback of the tenth parameter is invoked, it
+** is passed a single argument which is a copy of the application data 
+** pointer which was the fifth parameter to sqlite3_create_function_v2().
 **
 ** ^It is permitted to register multiple implementations of the same
 ** functions with the same name but with either differing numbers of
@@ -3863,11 +4012,6 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
 ** between UTF8 and UTF16.
 **
 ** ^Built-in functions may be overloaded by new application-defined functions.
-** ^The first application-defined function with a given name overrides all
-** built-in functions in the same [database connection] with the same name.
-** ^Subsequent application-defined functions of the same name only override 
-** prior application-defined functions that are an exact match for the
-** number of parameters and preferred encoding.
 **
 ** ^An application-defined function is permitted to call other
 ** SQLite interfaces.  However, such calls must not
@@ -3894,6 +4038,17 @@ SQLITE_API int sqlite3_create_function16(
   void (*xStep)(sqlite3_context*,int,sqlite3_value**),
   void (*xFinal)(sqlite3_context*)
 );
+SQLITE_API int sqlite3_create_function_v2(
+  sqlite3 *db,
+  const char *zFunctionName,
+  int nArg,
+  int eTextRep,
+  void *pApp,
+  void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
+  void (*xStep)(sqlite3_context*,int,sqlite3_value**),
+  void (*xFinal)(sqlite3_context*),
+  void(*xDestroy)(void*)
+);
 
 /*
 ** CAPI3REF: Text Encodings
@@ -3937,7 +4092,7 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6
 ** The xFunc (for scalar functions) or xStep (for aggregates) parameters
 ** to [sqlite3_create_function()] and [sqlite3_create_function16()]
 ** define callbacks that implement the SQL functions and aggregates.
-** The 4th parameter to these callbacks is an array of pointers to
+** The 3rd parameter to these callbacks is an array of pointers to
 ** [protected sqlite3_value] objects.  There is one [sqlite3_value] object for
 ** each parameter to the SQL function.  These routines are used to
 ** extract values from the [sqlite3_value] objects.
@@ -4240,46 +4395,79 @@ SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n);
 /*
 ** CAPI3REF: Define New Collating Sequences
 **
-** These functions are used to add new collation sequences to the
-** [database connection] specified as the first argument.
+** ^These functions add, remove, or modify a [collation] associated
+** with the [database connection] specified as the first argument.
 **
-** ^The name of the new collation sequence is specified as a UTF-8 string
+** ^The name of the collation is a UTF-8 string
 ** for sqlite3_create_collation() and sqlite3_create_collation_v2()
-** and a UTF-16 string for sqlite3_create_collation16(). ^In all cases
-** the name is passed as the second function argument.
-**
-** ^The third argument may be one of the constants [SQLITE_UTF8],
-** [SQLITE_UTF16LE], or [SQLITE_UTF16BE], indicating that the user-supplied
-** routine expects to be passed pointers to strings encoded using UTF-8,
-** UTF-16 little-endian, or UTF-16 big-endian, respectively. ^The
-** third argument might also be [SQLITE_UTF16] to indicate that the routine
-** expects pointers to be UTF-16 strings in the native byte order, or the
-** argument can be [SQLITE_UTF16_ALIGNED] if the
-** the routine expects pointers to 16-bit word aligned strings
-** of UTF-16 in the native byte order.
-**
-** A pointer to the user supplied routine must be passed as the fifth
-** argument.  ^If it is NULL, this is the same as deleting the collation
-** sequence (so that SQLite cannot call it any more).
-** ^Each time the application supplied function is invoked, it is passed
-** as its first parameter a copy of the void* passed as the fourth argument
-** to sqlite3_create_collation() or sqlite3_create_collation16().
-**
-** ^The remaining arguments to the application-supplied routine are two strings,
-** each represented by a (length, data) pair and encoded in the encoding
-** that was passed as the third argument when the collation sequence was
-** registered.  The application defined collation routine should
-** return negative, zero or positive if the first string is less than,
-** equal to, or greater than the second string. i.e. (STRING1 - STRING2).
+** and a UTF-16 string in native byte order for sqlite3_create_collation16().
+** ^Collation names that compare equal according to [sqlite3_strnicmp()] are
+** considered to be the same name.
+**
+** ^(The third argument (eTextRep) must be one of the constants:
+** <ul>
+** <li> [SQLITE_UTF8],
+** <li> [SQLITE_UTF16LE],
+** <li> [SQLITE_UTF16BE],
+** <li> [SQLITE_UTF16], or
+** <li> [SQLITE_UTF16_ALIGNED].
+** </ul>)^
+** ^The eTextRep argument determines the encoding of strings passed
+** to the collating function callback, xCallback.
+** ^The [SQLITE_UTF16] and [SQLITE_UTF16_ALIGNED] values for eTextRep
+** force strings to be UTF16 with native byte order.
+** ^The [SQLITE_UTF16_ALIGNED] value for eTextRep forces strings to begin
+** on an even byte address.
+**
+** ^The fourth argument, pArg, is a application data pointer that is passed
+** through as the first argument to the collating function callback.
+**
+** ^The fifth argument, xCallback, is a pointer to the collating function.
+** ^Multiple collating functions can be registered using the same name but
+** with different eTextRep parameters and SQLite will use whichever
+** function requires the least amount of data transformation.
+** ^If the xCallback argument is NULL then the collating function is
+** deleted.  ^When all collating functions having the same name are deleted,
+** that collation is no longer usable.
+**
+** ^The collating function callback is invoked with a copy of the pArg 
+** application data pointer and with two strings in the encoding specified
+** by the eTextRep argument.  The collating function must return an
+** integer that is negative, zero, or positive
+** if the first string is less than, equal to, or greater than the second,
+** respectively.  A collating function must alway return the same answer
+** given the same inputs.  If two or more collating functions are registered
+** to the same collation name (using different eTextRep values) then all
+** must give an equivalent answer when invoked with equivalent strings.
+** The collating function must obey the following properties for all
+** strings A, B, and C:
+**
+** <ol>
+** <li> If A==B then B==A.
+** <li> If A==B and B==C then A==C.
+** <li> If A&lt;B THEN B&gt;A.
+** <li> If A&lt;B and B&lt;C then A&lt;C.
+** </ol>
+**
+** If a collating function fails any of the above constraints and that
+** collating function is  registered and used, then the behavior of SQLite
+** is undefined.
 **
 ** ^The sqlite3_create_collation_v2() works like sqlite3_create_collation()
-** except that it takes an extra argument which is a destructor for
-** the collation.  ^The destructor is called when the collation is
-** destroyed and is passed a copy of the fourth parameter void* pointer
-** of the sqlite3_create_collation_v2().
-** ^Collations are destroyed when they are overridden by later calls to the
-** collation creation functions or when the [database connection] is closed
-** using [sqlite3_close()].
+** with the addition that the xDestroy callback is invoked on pArg when
+** the collating function is deleted.
+** ^Collating functions are deleted when they are overridden by later
+** calls to the collation creation functions or when the
+** [database connection] is closed using [sqlite3_close()].
+**
+** ^The xDestroy callback is <u>not</u> called if the 
+** sqlite3_create_collation_v2() function fails.  Applications that invoke
+** sqlite3_create_collation_v2() with a non-NULL xDestroy argument should 
+** check the return code and dispose of the application data pointer
+** themselves rather than expecting SQLite to deal with it for them.
+** This is different from every other SQLite interface.  The inconsistency 
+** is unfortunate but cannot be changed without breaking backwards 
+** compatibility.
 **
 ** See also:  [sqlite3_collation_needed()] and [sqlite3_collation_needed16()].
 */
@@ -4287,14 +4475,14 @@ SQLITE_API int sqlite3_create_collation(
   sqlite3*, 
   const char *zName, 
   int eTextRep, 
-  void*,
+  void *pArg,
   int(*xCompare)(void*,int,const void*,int,const void*)
 );
 SQLITE_API int sqlite3_create_collation_v2(
   sqlite3*, 
   const char *zName, 
   int eTextRep, 
-  void*,
+  void *pArg,
   int(*xCompare)(void*,int,const void*,int,const void*),
   void(*xDestroy)(void*)
 );
@@ -4302,7 +4490,7 @@ SQLITE_API int sqlite3_create_collation16(
   sqlite3*, 
   const void *zName,
   int eTextRep, 
-  void*,
+  void *pArg,
   int(*xCompare)(void*,int,const void*,int,const void*)
 );
 
@@ -4391,16 +4579,19 @@ SQLITE_API void sqlite3_activate_cerod(
 /*
 ** CAPI3REF: Suspend Execution For A Short Time
 **
-** ^The sqlite3_sleep() function causes the current thread to suspend execution
+** The sqlite3_sleep() function causes the current thread to suspend execution
 ** for at least a number of milliseconds specified in its parameter.
 **
-** ^If the operating system does not support sleep requests with
+** If the operating system does not support sleep requests with
 ** millisecond time resolution, then the time will be rounded up to
-** the nearest second. ^The number of milliseconds of sleep actually
+** the nearest second. The number of milliseconds of sleep actually
 ** requested from the operating system is returned.
 **
 ** ^SQLite implements this interface by calling the xSleep()
-** method of the default [sqlite3_vfs] object.
+** method of the default [sqlite3_vfs] object.  If the xSleep() method
+** of the default VFS is not implemented correctly, or not implemented at
+** all, then the behavior of sqlite3_sleep() may deviate from the description
+** in the previous paragraphs.
 */
 SQLITE_API int sqlite3_sleep(int);
 
@@ -4622,40 +4813,73 @@ SQLITE_API int sqlite3_enable_shared_cache(int);
 ** pages to improve performance is an example of non-essential memory.
 ** ^sqlite3_release_memory() returns the number of bytes actually freed,
 ** which might be more or less than the amount requested.
+** ^The sqlite3_release_memory() routine is a no-op returning zero
+** if SQLite is not compiled with [SQLITE_ENABLE_MEMORY_MANAGEMENT].
 */
 SQLITE_API int sqlite3_release_memory(int);
 
 /*
 ** CAPI3REF: Impose A Limit On Heap Size
 **
-** ^The sqlite3_soft_heap_limit() interface places a "soft" limit
-** on the amount of heap memory that may be allocated by SQLite.
-** ^If an internal allocation is requested that would exceed the
-** soft heap limit, [sqlite3_release_memory()] is invoked one or
-** more times to free up some space before the allocation is performed.
+** ^The sqlite3_soft_heap_limit64() interface sets and/or queries the
+** soft limit on the amount of heap memory that may be allocated by SQLite.
+** ^SQLite strives to keep heap memory utilization below the soft heap
+** limit by reducing the number of pages held in the page cache
+** as heap memory usages approaches the limit.
+** ^The soft heap limit is "soft" because even though SQLite strives to stay
+** below the limit, it will exceed the limit rather than generate
+** an [SQLITE_NOMEM] error.  In other words, the soft heap limit 
+** is advisory only.
+**
+** ^The return value from sqlite3_soft_heap_limit64() is the size of
+** the soft heap limit prior to the call.  ^If the argument N is negative
+** then no change is made to the soft heap limit.  Hence, the current
+** size of the soft heap limit can be determined by invoking
+** sqlite3_soft_heap_limit64() with a negative argument.
+**
+** ^If the argument N is zero then the soft heap limit is disabled.
 **
-** ^The limit is called "soft" because if [sqlite3_release_memory()]
-** cannot free sufficient memory to prevent the limit from being exceeded,
-** the memory is allocated anyway and the current operation proceeds.
+** ^(The soft heap limit is not enforced in the current implementation
+** if one or more of following conditions are true:
+**
+** <ul>
+** <li> The soft heap limit is set to zero.
+** <li> Memory accounting is disabled using a combination of the
+**      [sqlite3_config]([SQLITE_CONFIG_MEMSTATUS],...) start-time option and
+**      the [SQLITE_DEFAULT_MEMSTATUS] compile-time option.
+** <li> An alternative page cache implementation is specifed using
+**      [sqlite3_config]([SQLITE_CONFIG_PCACHE],...).
+** <li> The page cache allocates from its own memory pool supplied
+**      by [sqlite3_config]([SQLITE_CONFIG_PAGECACHE],...) rather than
+**      from the heap.
+** </ul>)^
 **
-** ^A negative or zero value for N means that there is no soft heap limit and
-** [sqlite3_release_memory()] will only be called when memory is exhausted.
-** ^The default value for the soft heap limit is zero.
+** Beginning with SQLite version 3.7.3, the soft heap limit is enforced
+** regardless of whether or not the [SQLITE_ENABLE_MEMORY_MANAGEMENT]
+** compile-time option is invoked.  With [SQLITE_ENABLE_MEMORY_MANAGEMENT],
+** the soft heap limit is enforced on every memory allocation.  Without
+** [SQLITE_ENABLE_MEMORY_MANAGEMENT], the soft heap limit is only enforced
+** when memory is allocated by the page cache.  Testing suggests that because
+** the page cache is the predominate memory user in SQLite, most
+** applications will achieve adequate soft heap limit enforcement without
+** the use of [SQLITE_ENABLE_MEMORY_MANAGEMENT].
 **
-** ^(SQLite makes a best effort to honor the soft heap limit.
-** But if the soft heap limit cannot be honored, execution will
-** continue without error or notification.)^  This is why the limit is
-** called a "soft" limit.  It is advisory only.
+** The circumstances under which SQLite will enforce the soft heap limit may
+** changes in future releases of SQLite.
+*/
+SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N);
+
+/*
+** CAPI3REF: Deprecated Soft Heap Limit Interface
+** DEPRECATED
 **
-** Prior to SQLite version 3.5.0, this routine only constrained the memory
-** allocated by a single thread - the same thread in which this routine
-** runs.  Beginning with SQLite version 3.5.0, the soft heap limit is
-** applied to all threads. The value specified for the soft heap limit
-** is an upper bound on the total memory allocation for all threads. In
-** version 3.5.0 there is no mechanism for limiting the heap usage for
-** individual threads.
+** This is a deprecated version of the [sqlite3_soft_heap_limit64()]
+** interface.  This routine is provided for historical compatibility
+** only.  All new applications should use the
+** [sqlite3_soft_heap_limit64()] interface rather than this one.
 */
-SQLITE_API void sqlite3_soft_heap_limit(int);
+SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
+
 
 /*
 ** CAPI3REF: Extract Metadata About A Column Of A Table
@@ -4779,34 +5003,47 @@ SQLITE_API int sqlite3_load_extension(
 SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
 
 /*
-** CAPI3REF: Automatically Load An Extensions
+** CAPI3REF: Automatically Load Statically Linked Extensions
+**
+** ^This interface causes the xEntryPoint() function to be invoked for
+** each new [database connection] that is created.  The idea here is that
+** xEntryPoint() is the entry point for a statically linked SQLite extension
+** that is to be automatically loaded into all new database connections.
 **
-** ^This API can be invoked at program startup in order to register
-** one or more statically linked extensions that will be available
-** to all new [database connections].
+** ^(Even though the function prototype shows that xEntryPoint() takes
+** no arguments and returns void, SQLite invokes xEntryPoint() with three
+** arguments and expects and integer result as if the signature of the
+** entry point where as follows:
 **
-** ^(This routine stores a pointer to the extension entry point
-** in an array that is obtained from [sqlite3_malloc()].  That memory
-** is deallocated by [sqlite3_reset_auto_extension()].)^
+** <blockquote><pre>
+** &nbsp;  int xEntryPoint(
+** &nbsp;    sqlite3 *db,
+** &nbsp;    const char **pzErrMsg,
+** &nbsp;    const struct sqlite3_api_routines *pThunk
+** &nbsp;  );
+** </pre></blockquote>)^
+**
+** If the xEntryPoint routine encounters an error, it should make *pzErrMsg
+** point to an appropriate error message (obtained from [sqlite3_mprintf()])
+** and return an appropriate [error code].  ^SQLite ensures that *pzErrMsg
+** is NULL before calling the xEntryPoint().  ^SQLite will invoke
+** [sqlite3_free()] on *pzErrMsg after xEntryPoint() returns.  ^If any
+** xEntryPoint() returns an error, the [sqlite3_open()], [sqlite3_open16()],
+** or [sqlite3_open_v2()] call that provoked the xEntryPoint() will fail.
 **
-** ^This function registers an extension entry point that is
-** automatically invoked whenever a new [database connection]
-** is opened using [sqlite3_open()], [sqlite3_open16()],
-** or [sqlite3_open_v2()].
-** ^Duplicate extensions are detected so calling this routine
-** multiple times with the same extension is harmless.
-** ^Automatic extensions apply across all threads.
+** ^Calling sqlite3_auto_extension(X) with an entry point X that is already
+** on the list of automatic extensions is a harmless no-op. ^No entry point
+** will be called more than once for each database connection that is opened.
+**
+** See also: [sqlite3_reset_auto_extension()].
 */
 SQLITE_API int sqlite3_auto_extension(void (*xEntryPoint)(void));
 
 /*
 ** CAPI3REF: Reset Automatic Extension Loading
 **
-** ^(This function disables all previously registered automatic
-** extensions. It undoes the effect of all prior
-** [sqlite3_auto_extension()] calls.)^
-**
-** ^This function disables automatic extensions in all threads.
+** ^This interface disables all automatic extensions previously
+** registered using [sqlite3_auto_extension()].
 */
 SQLITE_API void sqlite3_reset_auto_extension(void);
 
@@ -4986,7 +5223,9 @@ struct sqlite3_index_info {
 ** ^The sqlite3_create_module_v2() interface has a fifth parameter which
 ** is a pointer to a destructor for the pClientData.  ^SQLite will
 ** invoke the destructor function (if it is not NULL) when SQLite
-** no longer needs the pClientData pointer.  ^The sqlite3_create_module()
+** no longer needs the pClientData pointer.  ^The destructor will also
+** be invoked if the call to sqlite3_create_module_v2() fails.
+** ^The sqlite3_create_module()
 ** interface is equivalent to sqlite3_create_module_v2() with a NULL
 ** destructor.
 */
@@ -5170,6 +5409,30 @@ SQLITE_API int sqlite3_blob_open(
 );
 
 /*
+** CAPI3REF: Move a BLOB Handle to a New Row
+**
+** ^This function is used to move an existing blob handle so that it points
+** to a different row of the same database table. ^The new row is identified
+** by the rowid value passed as the second argument. Only the row can be
+** changed. ^The database, table and column on which the blob handle is open
+** remain the same. Moving an existing blob handle to a new row can be
+** faster than closing the existing handle and opening a new one.
+**
+** ^(The new row must meet the same criteria as for [sqlite3_blob_open()] -
+** it must exist and there must be either a blob or text value stored in
+** the nominated column.)^ ^If the new row is not present in the table, or if
+** it does not contain a blob or text value, or if another error occurs, an
+** SQLite error code is returned and the blob handle is considered aborted.
+** ^All subsequent calls to [sqlite3_blob_read()], [sqlite3_blob_write()] or
+** [sqlite3_blob_reopen()] on an aborted blob handle immediately return
+** SQLITE_ABORT. ^Calling [sqlite3_blob_bytes()] on an aborted blob handle
+** always returns zero.
+**
+** ^This function sets the database handle error code and message.
+*/
+SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
+
+/*
 ** CAPI3REF: Close A BLOB Handle
 **
 ** ^Closes an open [BLOB handle].
@@ -5445,7 +5708,7 @@ SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*);
 **
 ** ^The xMutexInit method defined by this structure is invoked as
 ** part of system initialization by the sqlite3_initialize() function.
-** ^The xMutexInit routine is calle by SQLite exactly once for each
+** ^The xMutexInit routine is called by SQLite exactly once for each
 ** effective call to [sqlite3_initialize()].
 **
 ** ^The xMutexEnd method defined by this structure is invoked as
@@ -5557,7 +5820,8 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
 #define SQLITE_MUTEX_STATIC_OPEN      4  /* sqlite3BtreeOpen() */
 #define SQLITE_MUTEX_STATIC_PRNG      5  /* sqlite3_random() */
 #define SQLITE_MUTEX_STATIC_LRU       6  /* lru page list */
-#define SQLITE_MUTEX_STATIC_LRU2      7  /* lru page list */
+#define SQLITE_MUTEX_STATIC_LRU2      7  /* NOT USED */
+#define SQLITE_MUTEX_STATIC_PMEM      7  /* sqlite3PageMalloc() */
 
 /*
 ** CAPI3REF: Retrieve the mutex for a database connection
@@ -5576,7 +5840,7 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
 ** ^The [sqlite3_file_control()] interface makes a direct call to the
 ** xFileControl method for the [sqlite3_io_methods] object associated
 ** with a particular database identified by the second argument. ^The
-** name of the database "main" for the main database or "temp" for the
+** name of the database is "main" for the main database or "temp" for the
 ** TEMP database, or the name that appears after the AS keyword for
 ** databases that are added using the [ATTACH] SQL command.
 ** ^A NULL pointer can be used in place of "main" to refer to the
@@ -5586,6 +5850,12 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
 ** the xFileControl method.  ^The return value of the xFileControl
 ** method becomes the return value of this routine.
 **
+** ^The SQLITE_FCNTL_FILE_POINTER value for the op parameter causes
+** a pointer to the underlying [sqlite3_file] object to be written into
+** the space pointed to by the 4th parameter.  ^The SQLITE_FCNTL_FILE_POINTER
+** case is a short-circuit path which does not actually invoke the
+** underlying sqlite3_io_methods.xFileControl method.
+**
 ** ^If the second parameter (zDbName) does not match the name of any
 ** open database file, then SQLITE_ERROR is returned.  ^This error
 ** code is not remembered and will not be recalled by [sqlite3_errcode()]
@@ -5642,7 +5912,8 @@ SQLITE_API int sqlite3_test_control(int op, ...);
 #define SQLITE_TESTCTRL_OPTIMIZATIONS           15
 #define SQLITE_TESTCTRL_ISKEYWORD               16
 #define SQLITE_TESTCTRL_PGHDRSZ                 17
-#define SQLITE_TESTCTRL_LAST                    17
+#define SQLITE_TESTCTRL_SCRATCHMALLOC           18
+#define SQLITE_TESTCTRL_LAST                    18
 
 /*
 ** CAPI3REF: SQLite Runtime Status
@@ -5661,7 +5932,7 @@ SQLITE_API int sqlite3_test_control(int op, ...);
 ** ^(Other parameters record only the highwater mark and not the current
 ** value.  For these latter parameters nothing is written into *pCurrent.)^
 **
-** ^The sqlite3_db_status() routine returns SQLITE_OK on success and a
+** ^The sqlite3_status() routine returns SQLITE_OK on success and a
 ** non-zero [error code] on failure.
 **
 ** This routine is threadsafe but is not atomic.  This routine can be
@@ -5701,7 +5972,8 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
 ** The value written into the *pCurrent parameter is undefined.</dd>)^
 **
 ** ^(<dt>SQLITE_STATUS_MALLOC_COUNT</dt>
-** <dd>This parameter records the number of separate memory allocations.</dd>)^
+** <dd>This parameter records the number of separate memory allocations
+** currently checked out.</dd>)^
 **
 ** ^(<dt>SQLITE_STATUS_PAGECACHE_USED</dt>
 ** <dd>This parameter returns the number of pages used out of the
@@ -5711,7 +5983,7 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
 **
 ** ^(<dt>SQLITE_STATUS_PAGECACHE_OVERFLOW</dt>
 ** <dd>This parameter returns the number of bytes of page cache
-** allocation which could not be statisfied by the [SQLITE_CONFIG_PAGECACHE]
+** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE]
 ** buffer and where forced to overflow to [sqlite3_malloc()].  The
 ** returned value includes allocations that overflowed because they
 ** where too large (they were larger than the "sz" parameter to
@@ -5734,7 +6006,7 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
 **
 ** ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt>
 ** <dd>This parameter returns the number of bytes of scratch memory
-** allocation which could not be statisfied by the [SQLITE_CONFIG_SCRATCH]
+** allocation which could not be satisfied by the [SQLITE_CONFIG_SCRATCH]
 ** buffer and where forced to overflow to [sqlite3_malloc()].  The values
 ** returned include overflows because the requested allocation was too
 ** larger (that is, because the requested allocation was larger than the
@@ -5783,6 +6055,9 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
 ** the resetFlg is true, then the highest instantaneous value is
 ** reset back down to the current value.
 **
+** ^The sqlite3_db_status() routine returns SQLITE_OK on success and a
+** non-zero [error code] on failure.
+**
 ** See also: [sqlite3_status()] and [sqlite3_stmt_status()].
 */
 SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
@@ -5804,6 +6079,28 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
 ** <dd>This parameter returns the number of lookaside memory slots currently
 ** checked out.</dd>)^
 **
+** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt>
+** <dd>This parameter returns the number malloc attempts that were 
+** satisfied using lookaside memory. Only the high-water value is meaningful;
+** the current value is always zero.
+** checked out.</dd>)^
+**
+** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE</dt>
+** <dd>This parameter returns the number malloc attempts that might have
+** been satisfied using lookaside memory but failed due to the amount of
+** memory requested being larger than the lookaside slot size.
+** Only the high-water value is meaningful;
+** the current value is always zero.
+** checked out.</dd>)^
+**
+** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL</dt>
+** <dd>This parameter returns the number malloc attempts that might have
+** been satisfied using lookaside memory but failed due to all lookaside
+** memory already being in use.
+** Only the high-water value is meaningful;
+** the current value is always zero.
+** checked out.</dd>)^
+**
 ** ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt>
 ** <dd>This parameter returns the approximate number of of bytes of heap
 ** memory used by all pager caches associated with the database connection.)^
@@ -5826,11 +6123,14 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
 ** </dd>
 ** </dl>
 */
-#define SQLITE_DBSTATUS_LOOKASIDE_USED     0
-#define SQLITE_DBSTATUS_CACHE_USED         1
-#define SQLITE_DBSTATUS_SCHEMA_USED        2
-#define SQLITE_DBSTATUS_STMT_USED          3
-#define SQLITE_DBSTATUS_MAX                3   /* Largest defined DBSTATUS */
+#define SQLITE_DBSTATUS_LOOKASIDE_USED       0
+#define SQLITE_DBSTATUS_CACHE_USED           1
+#define SQLITE_DBSTATUS_SCHEMA_USED          2
+#define SQLITE_DBSTATUS_STMT_USED            3
+#define SQLITE_DBSTATUS_LOOKASIDE_HIT        4
+#define SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE  5
+#define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL  6
+#define SQLITE_DBSTATUS_MAX                  6   /* Largest defined DBSTATUS */
 
 
 /*
@@ -5909,32 +6209,42 @@ typedef struct sqlite3_pcache sqlite3_pcache;
 **
 ** ^(The [sqlite3_config]([SQLITE_CONFIG_PCACHE], ...) interface can
 ** register an alternative page cache implementation by passing in an 
-** instance of the sqlite3_pcache_methods structure.)^ The majority of the 
-** heap memory used by SQLite is used by the page cache to cache data read 
-** from, or ready to be written to, the database file. By implementing a 
-** custom page cache using this API, an application can control more 
-** precisely the amount of memory consumed by SQLite, the way in which 
+** instance of the sqlite3_pcache_methods structure.)^
+** In many applications, most of the heap memory allocated by 
+** SQLite is used for the page cache.
+** By implementing a 
+** custom page cache using this API, an application can better control
+** the amount of memory consumed by SQLite, the way in which 
 ** that memory is allocated and released, and the policies used to 
 ** determine exactly which parts of a database file are cached and for 
 ** how long.
 **
+** The alternative page cache mechanism is an
+** extreme measure that is only needed by the most demanding applications.
+** The built-in page cache is recommended for most uses.
+**
 ** ^(The contents of the sqlite3_pcache_methods structure are copied to an
 ** internal buffer by SQLite within the call to [sqlite3_config].  Hence
 ** the application may discard the parameter after the call to
 ** [sqlite3_config()] returns.)^
 **
-** ^The xInit() method is called once for each call to [sqlite3_initialize()]
+** ^(The xInit() method is called once for each effective 
+** call to [sqlite3_initialize()])^
 ** (usually only once during the lifetime of the process). ^(The xInit()
 ** method is passed a copy of the sqlite3_pcache_methods.pArg value.)^
-** ^The xInit() method can set up up global structures and/or any mutexes
+** The intent of the xInit() method is to set up global data structures 
 ** required by the custom page cache implementation. 
+** ^(If the xInit() method is NULL, then the 
+** built-in default page cache is used instead of the application defined
+** page cache.)^
 **
-** ^The xShutdown() method is called from within [sqlite3_shutdown()], 
-** if the application invokes this API. It can be used to clean up 
+** ^The xShutdown() method is called by [sqlite3_shutdown()].
+** It can be used to clean up 
 ** any outstanding resources before process shutdown, if required.
+** ^The xShutdown() method may be NULL.
 **
-** ^SQLite holds a [SQLITE_MUTEX_RECURSIVE] mutex when it invokes
-** the xInit method, so the xInit method need not be threadsafe.  ^The
+** ^SQLite automatically serializes calls to the xInit method,
+** so the xInit method need not be threadsafe.  ^The
 ** xShutdown method is only called from [sqlite3_shutdown()] so it does
 ** not need to be threadsafe either.  All other methods must be threadsafe
 ** in multithreaded applications.
@@ -5942,47 +6252,52 @@ typedef struct sqlite3_pcache sqlite3_pcache;
 ** ^SQLite will never invoke xInit() more than once without an intervening
 ** call to xShutdown().
 **
-** ^The xCreate() method is used to construct a new cache instance.  SQLite
-** will typically create one cache instance for each open database file,
+** ^SQLite invokes the xCreate() method to construct a new cache instance.
+** SQLite will typically create one cache instance for each open database file,
 ** though this is not guaranteed. ^The
 ** first parameter, szPage, is the size in bytes of the pages that must
 ** be allocated by the cache.  ^szPage will not be a power of two.  ^szPage
 ** will the page size of the database file that is to be cached plus an
-** increment (here called "R") of about 100 or 200.  ^SQLite will use the
+** increment (here called "R") of less than 250.  SQLite will use the
 ** extra R bytes on each page to store metadata about the underlying
 ** database page on disk.  The value of R depends
 ** on the SQLite version, the target platform, and how SQLite was compiled.
-** ^R is constant for a particular build of SQLite.  ^The second argument to
+** ^(R is constant for a particular build of SQLite. Except, there are two
+** distinct values of R when SQLite is compiled with the proprietary
+** ZIPVFS extension.)^  ^The second argument to
 ** xCreate(), bPurgeable, is true if the cache being created will
 ** be used to cache database pages of a file stored on disk, or
-** false if it is used for an in-memory database. ^The cache implementation
+** false if it is used for an in-memory database. The cache implementation
 ** does not have to do anything special based with the value of bPurgeable;
 ** it is purely advisory.  ^On a cache where bPurgeable is false, SQLite will
 ** never invoke xUnpin() except to deliberately delete a page.
-** ^In other words, a cache created with bPurgeable set to false will
+** ^In other words, calls to xUnpin() on a cache with bPurgeable set to
+** false will always have the "discard" flag set to true.  
+** ^Hence, a cache created with bPurgeable false will
 ** never contain any unpinned pages.
 **
 ** ^(The xCachesize() method may be called at any time by SQLite to set the
 ** suggested maximum cache-size (number of pages stored by) the cache
 ** instance passed as the first argument. This is the value configured using
-** the SQLite "[PRAGMA cache_size]" command.)^  ^As with the bPurgeable
+** the SQLite "[PRAGMA cache_size]" command.)^  As with the bPurgeable
 ** parameter, the implementation is not required to do anything with this
 ** value; it is advisory only.
 **
-** ^The xPagecount() method should return the number of pages currently
-** stored in the cache.
+** The xPagecount() method must return the number of pages currently
+** stored in the cache, both pinned and unpinned.
 ** 
-** ^The xFetch() method is used to fetch a page and return a pointer to it. 
-** ^A 'page', in this context, is a buffer of szPage bytes aligned at an
-** 8-byte boundary. ^The page to be fetched is determined by the key. ^The
-** mimimum key value is 1. After it has been retrieved using xFetch, the page 
+** The xFetch() method locates a page in the cache and returns a pointer to 
+** the page, or a NULL pointer.
+** A "page", in this context, means a buffer of szPage bytes aligned at an
+** 8-byte boundary. The page to be fetched is determined by the key. ^The
+** mimimum key value is 1.  After it has been retrieved using xFetch, the page 
 ** is considered to be "pinned".
 **
-** ^If the requested page is already in the page cache, then the page cache
+** If the requested page is already in the page cache, then the page cache
 ** implementation must return a pointer to the page buffer with its content
-** intact.  ^(If the requested page is not already in the cache, then the
-** behavior of the cache implementation is determined by the value of the
-** createFlag parameter passed to xFetch, according to the following table:
+** intact.  If the requested page is not already in the cache, then the
+** cache implementation should use the value of the createFlag
+** parameter to help it determined what action to take:
 **
 ** <table border=1 width=85% align=center>
 ** <tr><th> createFlag <th> Behaviour when page is not already in cache
@@ -5991,36 +6306,35 @@ typedef struct sqlite3_pcache sqlite3_pcache;
 **                 Otherwise return NULL.
 ** <tr><td> 2 <td> Make every effort to allocate a new page.  Only return
 **                 NULL if allocating a new page is effectively impossible.
-** </table>)^
+** </table>
 **
-** SQLite will normally invoke xFetch() with a createFlag of 0 or 1.  If
-** a call to xFetch() with createFlag==1 returns NULL, then SQLite will
+** ^(SQLite will normally invoke xFetch() with a createFlag of 0 or 1.  SQLite
+** will only use a createFlag of 2 after a prior call with a createFlag of 1
+** failed.)^  In between the to xFetch() calls, SQLite may
 ** attempt to unpin one or more cache pages by spilling the content of
-** pinned pages to disk and synching the operating system disk cache. After
-** attempting to unpin pages, the xFetch() method will be invoked again with
-** a createFlag of 2.
+** pinned pages to disk and synching the operating system disk cache.
 **
 ** ^xUnpin() is called by SQLite with a pointer to a currently pinned page
-** as its second argument. ^(If the third parameter, discard, is non-zero,
-** then the page should be evicted from the cache. In this case SQLite 
-** assumes that the next time the page is retrieved from the cache using
-** the xFetch() method, it will be zeroed.)^ ^If the discard parameter is
-** zero, then the page is considered to be unpinned. ^The cache implementation
+** as its second argument.  If the third parameter, discard, is non-zero,
+** then the page must be evicted from the cache.
+** ^If the discard parameter is
+** zero, then the page may be discarded or retained at the discretion of
+** page cache implementation. ^The page cache implementation
 ** may choose to evict unpinned pages at any time.
 **
-** ^(The cache is not required to perform any reference counting. A single 
+** The cache must not perform any reference counting. A single 
 ** call to xUnpin() unpins the page regardless of the number of prior calls 
-** to xFetch().)^
+** to xFetch().
 **
-** ^The xRekey() method is used to change the key value associated with the
-** page passed as the second argument from oldKey to newKey. ^If the cache
-** previously contains an entry associated with newKey, it should be
+** The xRekey() method is used to change the key value associated with the
+** page passed as the second argument. If the cache
+** previously contains an entry associated with newKey, it must be
 ** discarded. ^Any prior cache entry associated with newKey is guaranteed not
 ** to be pinned.
 **
-** ^When SQLite calls the xTruncate() method, the cache must discard all
+** When SQLite calls the xTruncate() method, the cache must discard all
 ** existing cache entries with page numbers (keys) greater than or equal
-** to the value of the iLimit parameter passed to xTruncate(). ^If any
+** to the value of the iLimit parameter passed to xTruncate(). If any
 ** of these pages are pinned, they are implicitly unpinned, meaning that
 ** they can be safely discarded.
 **
@@ -6066,11 +6380,12 @@ typedef struct sqlite3_backup sqlite3_backup;
 **
 ** See Also: [Using the SQLite Online Backup API]
 **
-** ^Exclusive access is required to the destination database for the 
-** duration of the operation. ^However the source database is only
-** read-locked while it is actually being read; it is not locked
-** continuously for the entire backup operation. ^Thus, the backup may be
-** performed on a live source database without preventing other users from
+** ^SQLite holds a write transaction open on the destination database file
+** for the duration of the backup operation.
+** ^The source database is read-locked only while it is being read;
+** it is not locked continuously for the entire backup operation.
+** ^Thus, the backup may be performed on a live source database without
+** preventing other database connections from
 ** reading or writing to the source database while the backup is underway.
 ** 
 ** ^(To perform a backup operation: 
@@ -6097,11 +6412,11 @@ typedef struct sqlite3_backup sqlite3_backup;
 ** sqlite3_backup_init(D,N,S,M) identify the [database connection]
 ** and database name of the source database, respectively.
 ** ^The source and destination [database connections] (parameters S and D)
-** must be different or else sqlite3_backup_init(D,N,S,M) will file with
+** must be different or else sqlite3_backup_init(D,N,S,M) will fail with
 ** an error.
 **
 ** ^If an error occurs within sqlite3_backup_init(D,N,S,M), then NULL is
-** returned and an error code and error message are store3d in the
+** returned and an error code and error message are stored in the
 ** destination [database connection] D.
 ** ^The error code and message for the failed call to sqlite3_backup_init()
 ** can be retrieved using the [sqlite3_errcode()], [sqlite3_errmsg()], and/or
@@ -6118,7 +6433,7 @@ typedef struct sqlite3_backup sqlite3_backup;
 ** the source and destination databases specified by [sqlite3_backup] object B.
 ** ^If N is negative, all remaining source pages are copied. 
 ** ^If sqlite3_backup_step(B,N) successfully copies N pages and there
-** are still more pages to be copied, then the function resturns [SQLITE_OK].
+** are still more pages to be copied, then the function returns [SQLITE_OK].
 ** ^If sqlite3_backup_step(B,N) successfully finishes copying all pages
 ** from source to destination, then it returns [SQLITE_DONE].
 ** ^If an error occurs while running sqlite3_backup_step(B,N),
@@ -6132,7 +6447,7 @@ typedef struct sqlite3_backup sqlite3_backup;
 ** <li> the destination database was opened read-only, or
 ** <li> the destination database is using write-ahead-log journaling
 ** and the destination and source page sizes differ, or
-** <li> The destination database is an in-memory database and the
+** <li> the destination database is an in-memory database and the
 ** destination and source page sizes differ.
 ** </ol>)^
 **
@@ -6463,7 +6778,8 @@ SQLITE_API void *sqlite3_wal_hook(
 ** from SQL.
 **
 ** ^Every new [database connection] defaults to having the auto-checkpoint
-** enabled with a threshold of 1000 pages.  The use of this interface
+** enabled with a threshold of 1000 or [SQLITE_DEFAULT_WAL_AUTOCHECKPOINT]
+** pages.  The use of this interface
 ** is only necessary if the default setting is found to be suboptimal
 ** for a particular application.
 */
@@ -6498,6 +6814,62 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
 #endif
 #endif
 
+/*
+** 2010 August 30
+**
+** 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.
+**
+*************************************************************************
+*/
+
+#ifndef _SQLITE3RTREE_H_
+#define _SQLITE3RTREE_H_
+
+
+#if 0
+extern "C" {
+#endif
+
+typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry;
+
+/*
+** Register a geometry callback named zGeom that can be used as part of an
+** R-Tree geometry query as follows:
+**
+**   SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zGeom(... params ...)
+*/
+SQLITE_API int sqlite3_rtree_geometry_callback(
+  sqlite3 *db,
+  const char *zGeom,
+  int (*xGeom)(sqlite3_rtree_geometry *, int nCoord, double *aCoord, int *pRes),
+  void *pContext
+);
+
+
+/*
+** A pointer to a structure of the following type is passed as the first
+** argument to callbacks registered using rtree_geometry_callback().
+*/
+struct sqlite3_rtree_geometry {
+  void *pContext;                 /* Copy of pContext passed to s_r_g_c() */
+  int nParam;                     /* Size of array aParam[] */
+  double *aParam;                 /* Parameters passed to SQL geom function */
+  void *pUser;                    /* Callback implementation user data */
+  void (*xDelUser)(void *);       /* Called by SQLite to clean up pUser */
+};
+
+
+#if 0
+}  /* end of the 'extern "C"' block */
+#endif
+
+#endif  /* ifndef _SQLITE3RTREE_H_ */
+
 
 /************** End of sqlite3.h *********************************************/
 /************** Continuing where we left off in sqliteInt.h ******************/
@@ -7068,6 +7440,7 @@ typedef struct Expr Expr;
 typedef struct ExprList ExprList;
 typedef struct ExprSpan ExprSpan;
 typedef struct FKey FKey;
+typedef struct FuncDestructor FuncDestructor;
 typedef struct FuncDef FuncDef;
 typedef struct FuncDefHash FuncDefHash;
 typedef struct IdList IdList;
@@ -7174,16 +7547,15 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
 ** NOTE:  These values must match the corresponding PAGER_ values in
 ** pager.h.
 */
-#define BTREE_OMIT_JOURNAL  1  /* Do not use journal.  No argument */
+#define BTREE_OMIT_JOURNAL  1  /* Do not create or use a rollback journal */
 #define BTREE_NO_READLOCK   2  /* Omit readlocks on readonly files */
-#define BTREE_MEMORY        4  /* In-memory DB.  No argument */
-#define BTREE_READONLY      8  /* Open the database in read-only mode */
-#define BTREE_READWRITE    16  /* Open for both reading and writing */
-#define BTREE_CREATE       32  /* Create the database if it does not exist */
+#define BTREE_MEMORY        4  /* This is an in-memory DB */
+#define BTREE_SINGLE        8  /* The file contains at most 1 b-tree */
+#define BTREE_UNORDERED    16  /* Use of a hash implementation is OK */
 
 SQLITE_PRIVATE int sqlite3BtreeClose(Btree*);
 SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree*,int);
-SQLITE_PRIVATE int sqlite3BtreeSetSafetyLevel(Btree*,int,int);
+SQLITE_PRIVATE int sqlite3BtreeSetSafetyLevel(Btree*,int,int,int);
 SQLITE_PRIVATE int sqlite3BtreeSyncDisabled(Btree*);
 SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
 SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*);
@@ -7215,11 +7587,17 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *, Btree *);
 SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *);
 
 /* The flags parameter to sqlite3BtreeCreateTable can be the bitwise OR
-** of the following flags:
+** of the flags shown below.
+**
+** Every SQLite table must have either BTREE_INTKEY or BTREE_BLOBKEY set.
+** With BTREE_INTKEY, the table key is a 64-bit integer and arbitrary data
+** is stored in the leaves.  (BTREE_INTKEY is used for SQL tables.)  With
+** BTREE_BLOBKEY, the key is an arbitrary BLOB and no content is stored
+** anywhere - the key is the content.  (BTREE_BLOBKEY is used for SQL
+** indices.)
 */
 #define BTREE_INTKEY     1    /* Table has only 64-bit signed integer keys */
-#define BTREE_ZERODATA   2    /* Table has keys only - no data */
-#define BTREE_LEAFDATA   4    /* Data stored in leaves only.  Implies INTKEY */
+#define BTREE_BLOBKEY    2    /* Table has keys only - no data */
 
 SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree*, int, int*);
 SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree*, int, int*);
@@ -7661,12 +8039,12 @@ typedef struct VdbeOpList VdbeOpList;
 #define OP_VRename                            132
 #define OP_VUpdate                            133
 #define OP_Pagecount                          134
-#define OP_Trace                              135
-#define OP_Noop                               136
-#define OP_Explain                            137
+#define OP_MaxPgcnt                           135
+#define OP_Trace                              136
+#define OP_Noop                               137
+#define OP_Explain                            138
 
 /* The following opcode values are never used */
-#define OP_NotUsed_138                        138
 #define OP_NotUsed_139                        139
 #define OP_NotUsed_140                        140
 
@@ -7699,7 +8077,7 @@ typedef struct VdbeOpList VdbeOpList;
 /* 104 */ 0x00, 0x0c, 0x45, 0x15, 0x01, 0x02, 0x00, 0x01,\
 /* 112 */ 0x08, 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x02,\
 /* 120 */ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
-/* 128 */ 0x01, 0x00, 0x02, 0x01, 0x00, 0x00, 0x02, 0x00,\
+/* 128 */ 0x01, 0x00, 0x02, 0x01, 0x00, 0x00, 0x02, 0x02,\
 /* 136 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04,\
 /* 144 */ 0x04, 0x04,}
 
@@ -7840,6 +8218,7 @@ typedef struct PgHdr DbPage;
 */
 #define PAGER_OMIT_JOURNAL  0x0001    /* Do not use a rollback journal */
 #define PAGER_NO_READLOCK   0x0002    /* Omit readlocks on readonly files */
+#define PAGER_MEMORY        0x0004    /* In-memory database */
 
 /*
 ** Valid values for the second argument to sqlite3PagerLockingMode().
@@ -7883,7 +8262,7 @@ SQLITE_PRIVATE void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *);
 SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int);
 SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager*, int);
 SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int);
-SQLITE_PRIVATE void sqlite3PagerSetSafetyLevel(Pager*,int,int);
+SQLITE_PRIVATE void sqlite3PagerSetSafetyLevel(Pager*,int,int,int);
 SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *, int);
 SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *, int);
 SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager*);
@@ -8474,8 +8853,8 @@ SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *);
 #define sqlite3_mutex_enter(X)
 #define sqlite3_mutex_try(X)      SQLITE_OK
 #define sqlite3_mutex_leave(X)
-#define sqlite3_mutex_held(X)     1
-#define sqlite3_mutex_notheld(X)  1
+#define sqlite3_mutex_held(X)     ((void)(X),1)
+#define sqlite3_mutex_notheld(X)  ((void)(X),1)
 #define sqlite3MutexAlloc(X)      ((sqlite3_mutex*)8)
 #define sqlite3MutexInit()        SQLITE_OK
 #define sqlite3MutexEnd()
@@ -8571,6 +8950,7 @@ struct Lookaside {
   u8 bMalloced;           /* True if pStart obtained from sqlite3_malloc() */
   int nOut;               /* Number of buffers currently checked out */
   int mxOut;              /* Highwater mark for nOut */
+  int anStat[3];          /* 0: hits.  1: size misses.  2: full misses */
   LookasideSlot *pFree;   /* List of available buffers */
   void *pStart;           /* First byte of available memory space */
   void *pEnd;             /* First byte past end of available space */
@@ -8649,6 +9029,7 @@ struct sqlite3 {
   struct Vdbe *pVdbe;           /* List of active virtual machines */
   int activeVdbeCnt;            /* Number of VDBEs currently executing */
   int writeVdbeCnt;             /* Number of active VDBEs that are writing */
+  int vdbeExecCnt;              /* Number of nested calls to VdbeExec() */
   void (*xTrace)(void*,const char*);        /* Trace function */
   void *pTraceArg;                          /* Argument to the trace function */
   void (*xProfile)(void*,const char*,u64);  /* Profiling function */
@@ -8748,13 +9129,14 @@ struct sqlite3 {
 #define SQLITE_ReadUncommitted 0x0080000  /* For shared-cache mode */
 #define SQLITE_LegacyFileFmt  0x00100000  /* Create new databases in format 1 */
 #define SQLITE_FullFSync      0x00200000  /* Use full fsync on the backend */
-#define SQLITE_LoadExtension  0x00400000  /* Enable load_extension */
+#define SQLITE_CkptFullFSync  0x00400000  /* Use full fsync for checkpoint */
 #define SQLITE_RecoveryMode   0x00800000  /* Ignore schema errors */
 #define SQLITE_ReverseOrder   0x01000000  /* Reverse unordered SELECTs */
 #define SQLITE_RecTriggers    0x02000000  /* Enable recursive triggers */
 #define SQLITE_ForeignKeys    0x04000000  /* Enforce foreign key constraints  */
 #define SQLITE_AutoIndex      0x08000000  /* Enable automatic indexes */
 #define SQLITE_PreferBuiltin  0x10000000  /* Preference to built-in funcs */
+#define SQLITE_LoadExtension  0x20000000  /* Enable load_extension */
 
 /*
 ** Bits of the sqlite3.flags field that are used by the
@@ -8767,6 +9149,7 @@ struct sqlite3 {
 #define SQLITE_IndexSearch    0x08        /* Disable indexes for searching */
 #define SQLITE_IndexCover     0x10        /* Disable index covering table */
 #define SQLITE_GroupByOrder   0x20        /* Disable GROUPBY cover of ORDERBY */
+#define SQLITE_FactorOutConst 0x40        /* Disable factoring out constants */
 #define SQLITE_OptMask        0xff        /* Mask of all disablable opts */
 
 /*
@@ -8797,6 +9180,27 @@ struct FuncDef {
   void (*xFinalize)(sqlite3_context*);                /* Aggregate finalizer */
   char *zName;         /* SQL name of the function. */
   FuncDef *pHash;      /* Next with a different name but the same hash */
+  FuncDestructor *pDestructor;   /* Reference counted destructor function */
+};
+
+/*
+** This structure encapsulates a user-function destructor callback (as
+** configured using create_function_v2()) and a reference counter. When
+** create_function_v2() is called to create a function with a destructor,
+** a single object of this type is allocated. FuncDestructor.nRef is set to 
+** the number of FuncDef objects created (either 1 or 3, depending on whether
+** or not the specified encoding is SQLITE_ANY). The FuncDef.pDestructor
+** member of each of the new FuncDef objects is set to point to the allocated
+** FuncDestructor.
+**
+** Thereafter, when one of the FuncDef objects is deleted, the reference
+** count on this object is decremented. When it reaches 0, the destructor
+** is invoked and the FuncDestructor structure freed.
+*/
+struct FuncDestructor {
+  int nRef;
+  void (*xDestroy)(void *);
+  void *pUserData;
 };
 
 /*
@@ -8837,15 +9241,15 @@ struct FuncDef {
 */
 #define FUNCTION(zName, nArg, iArg, bNC, xFunc) \
   {nArg, SQLITE_UTF8, bNC*SQLITE_FUNC_NEEDCOLL, \
-   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0}
+   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
 #define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \
   {nArg, SQLITE_UTF8, bNC*SQLITE_FUNC_NEEDCOLL, \
-   pArg, 0, xFunc, 0, 0, #zName, 0}
+   pArg, 0, xFunc, 0, 0, #zName, 0, 0}
 #define LIKEFUNC(zName, nArg, arg, flags) \
-  {nArg, SQLITE_UTF8, flags, (void *)arg, 0, likeFunc, 0, 0, #zName, 0}
+  {nArg, SQLITE_UTF8, flags, (void *)arg, 0, likeFunc, 0, 0, #zName, 0, 0}
 #define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \
   {nArg, SQLITE_UTF8, nc*SQLITE_FUNC_NEEDCOLL, \
-   SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0}
+   SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0}
 
 /*
 ** All current savepoints are stored in a linked list starting at
@@ -8992,7 +9396,7 @@ struct CollSeq {
 ** connection handle passed to it via the xConnect() or xCreate() method
 ** during initialization internally. This database connection handle may
 ** then used by the virtual table implementation to access real tables 
-** within the database. So that they appear as part of the caller's 
+** within the database. So that they appear as part of the callers 
 ** transaction, these accesses need to be made via the same database 
 ** connection as that used to execute SQL operations on the virtual table.
 **
@@ -9065,6 +9469,7 @@ struct Table {
   Column *aCol;        /* Information about each column */
   Index *pIndex;       /* List of SQL indexes on this table. */
   int tnum;            /* Root BTree node for this table (see note above) */
+  unsigned nRowEst;    /* Estimated rows in table - from sqlite_stat1 table */
   Select *pSelect;     /* NULL for tables.  Points to definition if a view. */
   u16 nRef;            /* Number of pointers to this Table */
   u8 tabFlags;         /* Mask of TF_* values */
@@ -9633,6 +10038,9 @@ struct SrcList {
     u8 isPopulated;   /* Temporary table associated with SELECT is populated */
     u8 jointype;      /* Type of join between this able and the previous */
     u8 notIndexed;    /* True if there is a NOT INDEXED clause */
+#ifndef SQLITE_OMIT_EXPLAIN
+    u8 iSelectId;     /* If pSelect!=0, the id of the sub-select in EQP */
+#endif
     int iCursor;      /* The VDBE cursor number used to access this table */
     Expr *pOn;        /* The ON clause of a join */
     IdList *pUsing;   /* The USING clause of a join */
@@ -9671,6 +10079,7 @@ struct SrcList {
 struct WherePlan {
   u32 wsFlags;                   /* WHERE_* flags that describe the strategy */
   u32 nEq;                       /* Number of == constraints */
+  double nRow;                   /* Estimated number of rows (for EQP) */
   union {
     Index *pIdx;                   /* Index when WHERE_INDEXED is true */
     struct WhereTerm *pTerm;       /* WHERE clause term for OR-search */
@@ -9755,6 +10164,7 @@ struct WhereInfo {
   int nLevel;                    /* Number of nested loop */
   struct WhereClause *pWC;       /* Decomposition of the WHERE clause */
   double savedNQueryLoop;        /* pParse->nQueryLoop outside the WHERE loop */
+  double nRowOut;                /* Estimated number of output rows */
   WhereLevel a[1];               /* Information about each nest loop in WHERE */
 };
 
@@ -9830,6 +10240,7 @@ struct Select {
   Expr *pOffset;         /* OFFSET expression. NULL means not used. */
   int iLimit, iOffset;   /* Memory registers holding LIMIT & OFFSET counters */
   int addrOpenEphm[3];   /* OP_OpenEphem opcodes related to this select */
+  double nSelectRow;     /* Estimated number of result rows */
 };
 
 /*
@@ -10025,6 +10436,11 @@ struct Parse {
   int nHeight;            /* Expression tree height of current sub-select */
   Table *pZombieTab;      /* List of Table objects to delete after code gen */
   TriggerPrg *pTriggerPrg;    /* Linked list of coded triggers */
+
+#ifndef SQLITE_OMIT_EXPLAIN
+  int iSelectId;
+  int iNextSelectId;
+#endif
 };
 
 #ifdef SQLITE_OMIT_VIRTUALTABLE
@@ -10319,7 +10735,6 @@ SQLITE_PRIVATE int sqlite3CantopenError(int);
 ** Internal function prototypes
 */
 SQLITE_PRIVATE int sqlite3StrICmp(const char *, const char *);
-SQLITE_PRIVATE int sqlite3IsNumber(const char*, int*, u8);
 SQLITE_PRIVATE int sqlite3Strlen30(const char*);
 #define sqlite3StrNICmp sqlite3_strnicmp
 
@@ -10343,7 +10758,7 @@ SQLITE_PRIVATE void *sqlite3PageMalloc(int);
 SQLITE_PRIVATE void sqlite3PageFree(void*);
 SQLITE_PRIVATE void sqlite3MemSetDefault(void);
 SQLITE_PRIVATE void sqlite3BenignMallocHooks(void (*)(void), void (*)(void));
-SQLITE_PRIVATE int sqlite3MemoryAlarm(void (*)(void*, sqlite3_int64, int), void*, sqlite3_int64);
+SQLITE_PRIVATE int sqlite3HeapNearlyFull(void);
 
 /*
 ** On systems with ample stack space and that support alloca(), make
@@ -10514,7 +10929,6 @@ SQLITE_PRIVATE void sqlite3ExprCachePop(Parse*, int);
 SQLITE_PRIVATE void sqlite3ExprCacheRemove(Parse*, int, int);
 SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse*);
 SQLITE_PRIVATE void sqlite3ExprCacheAffinityChange(Parse*, int, int);
-SQLITE_PRIVATE void sqlite3ExprHardCopy(Parse*,int,int);
 SQLITE_PRIVATE int sqlite3ExprCode(Parse*, Expr*, int);
 SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse*, Expr*, int*);
 SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse*, Expr*, int);
@@ -10634,17 +11048,15 @@ SQLITE_PRIVATE   int sqlite3AuthReadCol(Parse*, const char *, const char *, int)
 #endif
 SQLITE_PRIVATE void sqlite3Attach(Parse*, Expr*, Expr*, Expr*);
 SQLITE_PRIVATE void sqlite3Detach(Parse*, Expr*);
-SQLITE_PRIVATE int sqlite3BtreeFactory(sqlite3 *db, const char *zFilename,
-                       int omitJournal, int nCache, int flags, Btree **ppBtree);
 SQLITE_PRIVATE int sqlite3FixInit(DbFixer*, Parse*, int, const char*, const Token*);
 SQLITE_PRIVATE int sqlite3FixSrcList(DbFixer*, SrcList*);
 SQLITE_PRIVATE int sqlite3FixSelect(DbFixer*, Select*);
 SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*);
 SQLITE_PRIVATE int sqlite3FixExprList(DbFixer*, ExprList*);
 SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
-SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*);
+SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*, int, u8);
 SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*);
-SQLITE_PRIVATE int sqlite3FitsIn64Bits(const char *, int);
+SQLITE_PRIVATE int sqlite3Atoi(const char*);
 SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar);
 SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte);
 SQLITE_PRIVATE int sqlite3Utf8Read(const u8*, const u8**);
@@ -10690,7 +11102,7 @@ SQLITE_PRIVATE void sqlite3TableAffinityStr(Vdbe *, Table *);
 SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2);
 SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity);
 SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr);
-SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*);
+SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8);
 SQLITE_PRIVATE void sqlite3Error(sqlite3*, int, const char*,...);
 SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
 SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
@@ -10761,7 +11173,9 @@ SQLITE_PRIVATE int sqlite3SchemaToIndex(sqlite3 *db, Schema *);
 SQLITE_PRIVATE KeyInfo *sqlite3IndexKeyinfo(Parse *, Index *);
 SQLITE_PRIVATE int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *, 
   void (*)(sqlite3_context*,int,sqlite3_value **),
-  void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*));
+  void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*),
+  FuncDestructor *pDestructor
+);
 SQLITE_PRIVATE int sqlite3ApiExit(sqlite3 *db, int);
 SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *);
 
@@ -11388,6 +11802,9 @@ static const char * const azCompileOpt[] = {
 #ifdef SQLITE_OMIT_AUTOMATIC_INDEX
   "OMIT_AUTOMATIC_INDEX",
 #endif
+#ifdef SQLITE_OMIT_AUTORESET
+  "OMIT_AUTORESET",
+#endif
 #ifdef SQLITE_OMIT_AUTOVACUUM
   "OMIT_AUTOVACUUM",
 #endif
@@ -11663,16 +12080,14 @@ typedef unsigned char Bool;
 ** 
 ** Every cursor that the virtual machine has open is represented by an
 ** instance of the following structure.
-**
-** If the VdbeCursor.isTriggerRow flag is set it means that this cursor is
-** really a single row that represents the NEW or OLD pseudo-table of
-** a row trigger.  The data for the row is stored in VdbeCursor.pData and
-** the rowid is in VdbeCursor.iKey.
 */
 struct VdbeCursor {
   BtCursor *pCursor;    /* The cursor structure of the backend */
+  Btree *pBt;           /* Separate file holding temporary table */
+  KeyInfo *pKeyInfo;    /* Info about index keys needed by index cursors */
   int iDb;              /* Index of cursor database in db->aDb[] (or -1) */
-  i64 lastRowid;        /* Last rowid from a Next or NextIdx operation */
+  int pseudoTableReg;   /* Register holding pseudotable content. */
+  int nField;           /* Number of fields in the header */
   Bool zeroed;          /* True if zeroed out and ready for reuse */
   Bool rowidIsValid;    /* True if lastRowid is valid */
   Bool atFirst;         /* True if pointing to first entry */
@@ -11681,14 +12096,12 @@ struct VdbeCursor {
   Bool deferredMoveto;  /* A call to sqlite3BtreeMoveto() is needed */
   Bool isTable;         /* True if a table requiring integer keys */
   Bool isIndex;         /* True if an index containing keys only - no data */
-  i64 movetoTarget;     /* Argument to the deferred sqlite3BtreeMoveto() */
-  Btree *pBt;           /* Separate file holding temporary table */
-  int pseudoTableReg;   /* Register holding pseudotable content. */
-  KeyInfo *pKeyInfo;    /* Info about index keys needed by index cursors */
-  int nField;           /* Number of fields in the header */
-  i64 seqCount;         /* Sequence counter */
+  Bool isOrdered;       /* True if the underlying table is BTREE_UNORDERED */
   sqlite3_vtab_cursor *pVtabCursor;  /* The cursor for a virtual table */
   const sqlite3_module *pModule;     /* Module for cursor pVtabCursor */
+  i64 seqCount;         /* Sequence counter */
+  i64 movetoTarget;     /* Argument to the deferred sqlite3BtreeMoveto() */
+  i64 lastRowid;        /* Last rowid from a Next or NextIdx operation */
 
   /* Result of last sqlite3BtreeMoveto() done by an OP_NotExists or 
   ** OP_IsUnique opcode on this cursor. */
@@ -11720,26 +12133,34 @@ typedef struct VdbeCursor VdbeCursor;
 ** restoring the state of the VM to as it was before the sub-program
 ** began executing.
 **
-** Frames are stored in a linked list headed at Vdbe.pParent. Vdbe.pParent
-** is the parent of the current frame, or zero if the current frame
-** is the main Vdbe program.
+** The memory for a VdbeFrame object is allocated and managed by a memory
+** cell in the parent (calling) frame. When the memory cell is deleted or
+** overwritten, the VdbeFrame object is not freed immediately. Instead, it
+** is linked into the Vdbe.pDelFrame list. The contents of the Vdbe.pDelFrame
+** list is deleted when the VM is reset in VdbeHalt(). The reason for doing
+** this instead of deleting the VdbeFrame immediately is to avoid recursive
+** calls to sqlite3VdbeMemRelease() when the memory cells belonging to the
+** child frame are released.
+**
+** The currently executing frame is stored in Vdbe.pFrame. Vdbe.pFrame is
+** set to NULL if the currently executing frame is the main program.
 */
 typedef struct VdbeFrame VdbeFrame;
 struct VdbeFrame {
   Vdbe *v;                /* VM this frame belongs to */
-  int pc;                 /* Program Counter */
-  Op *aOp;                /* Program instructions */
+  int pc;                 /* Program Counter in parent (calling) frame */
+  Op *aOp;                /* Program instructions for parent frame */
   int nOp;                /* Size of aOp array */
-  Mem *aMem;              /* Array of memory cells */
+  Mem *aMem;              /* Array of memory cells for parent frame */
   int nMem;               /* Number of entries in aMem */
-  VdbeCursor **apCsr;     /* Element of Vdbe cursors */
+  VdbeCursor **apCsr;     /* Array of Vdbe cursors for parent frame */
   u16 nCursor;            /* Number of entries in apCsr */
   void *token;            /* Copy of SubProgram.token */
   int nChildMem;          /* Number of memory cells for child frame */
   int nChildCsr;          /* Number of cursors for child frame */
   i64 lastRowid;          /* Last insert rowid (sqlite3.lastRowid) */
   int nChange;            /* Statement changes (Vdbe.nChanges)     */
-  VdbeFrame *pParent;     /* Parent of this frame */
+  VdbeFrame *pParent;     /* Parent of this frame, or NULL if parent is main */
 };
 
 #define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])
@@ -11752,29 +12173,27 @@ struct VdbeFrame {
 /*
 ** Internally, the vdbe manipulates nearly all SQL values as Mem
 ** structures. Each Mem struct may cache multiple representations (string,
-** integer etc.) of the same value.  A value (and therefore Mem structure)
-** has the following properties:
-**
-** Each value has a manifest type. The manifest type of the value stored
-** in a Mem struct is returned by the MemType(Mem*) macro. The type is
-** one of SQLITE_NULL, SQLITE_INTEGER, SQLITE_REAL, SQLITE_TEXT or
-** SQLITE_BLOB.
+** integer etc.) of the same value.
 */
 struct Mem {
+  sqlite3 *db;        /* The associated database connection */
+  char *z;            /* String or BLOB value */
+  double r;           /* Real value */
   union {
-    i64 i;              /* Integer value. */
+    i64 i;              /* Integer value used when MEM_Int is set in flags */
     int nZero;          /* Used when bit MEM_Zero is set in flags */
     FuncDef *pDef;      /* Used only when flags==MEM_Agg */
     RowSet *pRowSet;    /* Used only when flags==MEM_RowSet */
     VdbeFrame *pFrame;  /* Used when flags==MEM_Frame */
   } u;
-  double r;           /* Real value */
-  sqlite3 *db;        /* The associated database connection */
-  char *z;            /* String or BLOB value */
   int n;              /* Number of characters in string value, excluding '\0' */
   u16 flags;          /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
   u8  type;           /* One of SQLITE_NULL, SQLITE_TEXT, SQLITE_INTEGER, etc */
   u8  enc;            /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
+#ifdef SQLITE_DEBUG
+  Mem *pScopyFrom;    /* This Mem is a shallow copy of pScopyFrom */
+  void *pFiller;      /* So that sizeof(Mem) is a multiple of 8 */
+#endif
   void (*xDel)(void *);  /* If not null, call this function to delete Mem.z */
   char *zMalloc;      /* Dynamic buffer allocated by sqlite3_malloc() */
 };
@@ -11790,9 +12209,6 @@ struct Mem {
 ** database (see below for exceptions). If the MEM_Term flag is also
 ** set, then the string is nul terminated. The MEM_Int and MEM_Real 
 ** flags may coexist with the MEM_Str flag.
-**
-** Multiple of these values can appear in Mem.flags.  But only one
-** at a time can appear in Mem.type.
 */
 #define MEM_Null      0x0001   /* Value is NULL */
 #define MEM_Str       0x0002   /* Value is a string */
@@ -11801,6 +12217,7 @@ struct Mem {
 #define MEM_Blob      0x0010   /* Value is a BLOB */
 #define MEM_RowSet    0x0020   /* Value is a RowSet object */
 #define MEM_Frame     0x0040   /* Value is a VdbeFrame object */
+#define MEM_Invalid   0x0080   /* Value is undefined */
 #define MEM_TypeMask  0x00ff   /* Mask of type bits */
 
 /* Whenever Mem contains a valid string or blob representation, one of
@@ -11814,19 +12231,25 @@ struct Mem {
 #define MEM_Ephem     0x1000   /* Mem.z points to an ephemeral string */
 #define MEM_Agg       0x2000   /* Mem.z points to an agg function context */
 #define MEM_Zero      0x4000   /* Mem.i contains count of 0s appended to blob */
-
 #ifdef SQLITE_OMIT_INCRBLOB
   #undef MEM_Zero
   #define MEM_Zero 0x0000
 #endif
 
-
 /*
 ** Clear any existing type flags from a Mem and replace them with f
 */
 #define MemSetTypeFlag(p, f) \
    ((p)->flags = ((p)->flags&~(MEM_TypeMask|MEM_Zero))|f)
 
+/*
+** Return true if a memory cell is not marked as invalid.  This macro
+** is for use inside assert() statements only.
+*/
+#ifdef SQLITE_DEBUG
+#define memIsValid(M)  ((M)->flags & MEM_Invalid)==0
+#endif
+
 
 /* A VdbeFunc is just a FuncDef (defined in sqliteInt.h) that contains
 ** additional information about auxiliary information bound to arguments
@@ -11869,22 +12292,10 @@ struct sqlite3_context {
 };
 
 /*
-** A Set structure is used for quick testing to see if a value
-** is part of a small set.  Sets are used to implement code like
-** this:
-**            x.y IN ('hi','hoo','hum')
-*/
-typedef struct Set Set;
-struct Set {
-  Hash hash;             /* A set is just a hash table */
-  HashElem *prev;        /* Previously accessed hash elemen */
-};
-
-/*
 ** An instance of the virtual machine.  This structure contains the complete
 ** state of the virtual machine.
 **
-** The "sqlite3_stmt" structure pointer that is returned by sqlite3_compile()
+** The "sqlite3_stmt" structure pointer that is returned by sqlite3_prepare()
 ** is really a pointer to an instance of this structure.
 **
 ** The Vdbe.inVtabMethod variable is set to non-zero for the duration of
@@ -11897,31 +12308,31 @@ struct Set {
 */
 struct Vdbe {
   sqlite3 *db;            /* The database connection that owns this statement */
-  Vdbe *pPrev,*pNext;     /* Linked list of VDBEs with the same Vdbe.db */
+  Op *aOp;                /* Space to hold the virtual machine's program */
+  Mem *aMem;              /* The memory locations */
+  Mem **apArg;            /* Arguments to currently executing user function */
+  Mem *aColName;          /* Column names to return */
+  Mem *pResultSet;        /* Pointer to an array of results */
+  int nMem;               /* Number of memory locations currently allocated */
   int nOp;                /* Number of instructions in the program */
   int nOpAlloc;           /* Number of slots allocated for aOp[] */
-  Op *aOp;                /* Space to hold the virtual machine's program */
   int nLabel;             /* Number of labels used */
   int nLabelAlloc;        /* Number of slots allocated in aLabel[] */
   int *aLabel;            /* Space to hold the labels */
-  Mem **apArg;            /* Arguments to currently executing user function */
-  Mem *aColName;          /* Column names to return */
-  Mem *pResultSet;        /* Pointer to an array of results */
   u16 nResColumn;         /* Number of columns in one row of the result set */
   u16 nCursor;            /* Number of slots in apCsr[] */
+  u32 magic;              /* Magic number for sanity checking */
+  char *zErrMsg;          /* Error message written here */
+  Vdbe *pPrev,*pNext;     /* Linked list of VDBEs with the same Vdbe.db */
   VdbeCursor **apCsr;     /* One element of this array for each open cursor */
-  u8 errorAction;         /* Recovery action to do in case of an error */
-  u8 okVar;               /* True if azVar[] has been initialized */
-  ynVar nVar;             /* Number of entries in aVar[] */
   Mem *aVar;              /* Values for the OP_Variable opcode. */
   char **azVar;           /* Name of variables */
-  u32 magic;              /* Magic number for sanity checking */
-  int nMem;               /* Number of memory locations currently allocated */
-  Mem *aMem;              /* The memory locations */
+  ynVar nVar;             /* Number of entries in aVar[] */
   u32 cacheCtr;           /* VdbeCursor row cache generation counter */
   int pc;                 /* The program counter */
   int rc;                 /* Value to return */
-  char *zErrMsg;          /* Error message written here */
+  u8 errorAction;         /* Recovery action to do in case of an error */
+  u8 okVar;               /* True if azVar[] has been initialized */
   u8 explain;             /* True if EXPLAIN present on SQL command */
   u8 changeCntOn;         /* True to update the change-counter */
   u8 expired;             /* True if the VM needs to be recompiled */
@@ -11933,18 +12344,21 @@ struct Vdbe {
   u8 isPrepareV2;         /* True if prepared with prepare_v2() */
   int nChange;            /* Number of db changes made since last reset */
   int btreeMask;          /* Bitmask of db->aDb[] entries referenced */
-  i64 startTime;          /* Time when query started - used for profiling */
-  BtreeMutexArray aMutex; /* An array of Btree used here and needing locks */
+  int iStatement;         /* Statement number (or 0 if has not opened stmt) */
   int aCounter[3];        /* Counters used by sqlite3_stmt_status() */
-  char *zSql;             /* Text of the SQL statement that generated this */
-  void *pFree;            /* Free this when deleting the vdbe */
+  BtreeMutexArray aMutex; /* An array of Btree used here and needing locks */
+#ifndef SQLITE_OMIT_TRACE
+  i64 startTime;          /* Time when query started - used for profiling */
+#endif
   i64 nFkConstraint;      /* Number of imm. FK constraints this VM */
   i64 nStmtDefCons;       /* Number of def. constraints when stmt started */
-  int iStatement;         /* Statement number (or 0 if has not opened stmt) */
+  char *zSql;             /* Text of the SQL statement that generated this */
+  void *pFree;            /* Free this when deleting the vdbe */
 #ifdef SQLITE_DEBUG
   FILE *trace;            /* Write an execution trace here, if not NULL */
 #endif
   VdbeFrame *pFrame;      /* Parent frame */
+  VdbeFrame *pDelFrame;   /* List of frame objects to free on VM reset */
   int nFrame;             /* Number of frames in pFrame list */
   u32 expmask;            /* Binding to these vars invalidates VM */
   SubProgram *pProgram;   /* Linked list of all sub-programs used by VM */
@@ -12015,6 +12429,10 @@ SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*);
 SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *);
 SQLITE_PRIVATE void sqlite3VdbeMemStoreType(Mem *pMem);
 
+#ifdef SQLITE_DEBUG
+SQLITE_PRIVATE void sqlite3VdbeMemPrepareToChange(Vdbe*,Mem*);
+#endif
+
 #ifndef SQLITE_OMIT_FOREIGN_KEY
 SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *, int);
 #else
@@ -12145,6 +12563,22 @@ SQLITE_API int sqlite3_db_status(
       break;
     }
 
+    case SQLITE_DBSTATUS_LOOKASIDE_HIT:
+    case SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE:
+    case SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL: {
+      testcase( op==SQLITE_DBSTATUS_LOOKASIDE_HIT );
+      testcase( op==SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE );
+      testcase( op==SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL );
+      assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)>=0 );
+      assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)<3 );
+      *pCurrent = 0;
+      *pHighwater = db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT];
+      if( resetFlag ){
+        db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT] = 0;
+      }
+      break;
+    }
+
     /* 
     ** Return an approximation for the amount of memory currently used
     ** by all pagers associated with the given database connection.  The
@@ -12372,12 +12806,6 @@ end_getDigits:
 }
 
 /*
-** Read text from z[] and convert into a floating point number.  Return
-** the number of digits converted.
-*/
-#define getValue sqlite3AtoF
-
-/*
 ** Parse a timezone extension on the end of a date-time.
 ** The extension is of the form:
 **
@@ -12578,7 +13006,7 @@ static int parseDateOrTime(
   const char *zDate, 
   DateTime *p
 ){
-  int isRealNum;    /* Return from sqlite3IsNumber().  Not used */
+  double r;
   if( parseYyyyMmDd(zDate,p)==0 ){
     return 0;
   }else if( parseHhMmSs(zDate, p)==0 ){
@@ -12586,9 +13014,7 @@ static int parseDateOrTime(
   }else if( sqlite3StrICmp(zDate,"now")==0){
     setDateTimeToCurrent(context, p);
     return 0;
-  }else if( sqlite3IsNumber(zDate, &isRealNum, SQLITE_UTF8) ){
-    double r;
-    getValue(zDate, &r);
+  }else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8) ){
     p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5);
     p->validJD = 1;
     return 0;
@@ -12809,8 +13235,9 @@ static int parseModifier(const char *zMod, DateTime *p){
       ** weekday N where 0==Sunday, 1==Monday, and so forth.  If the
       ** date is already on the appropriate weekday, this is a no-op.
       */
-      if( strncmp(z, "weekday ", 8)==0 && getValue(&z[8],&r)>0
-                 && (n=(int)r)==r && n>=0 && r<7 ){
+      if( strncmp(z, "weekday ", 8)==0
+               && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)
+               && (n=(int)r)==r && n>=0 && r<7 ){
         sqlite3_int64 Z;
         computeYMD_HMS(p);
         p->validTZ = 0;
@@ -12865,8 +13292,11 @@ static int parseModifier(const char *zMod, DateTime *p){
     case '8':
     case '9': {
       double rRounder;
-      n = getValue(z, &r);
-      assert( n>=1 );
+      for(n=1; z[n] && z[n]!=':' && !sqlite3Isspace(z[n]); n++){}
+      if( !sqlite3AtoF(z, &r, n, SQLITE_UTF8) ){
+        rc = 1;
+        break;
+      }
       if( z[n]==':' ){
         /* A modifier of the form (+|-)HH:MM:SS.FFF adds (or subtracts) the
         ** specified number of hours, minutes, seconds, and fractional seconds
@@ -13520,6 +13950,12 @@ SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){
 }
 SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
   int rc;
+  /* IMPLEMENTATION-OF: R-49045-42493 SQLite will use the xCurrentTimeInt64()
+  ** method to get the current date and time if that method is available
+  ** (if iVersion is 2 or greater and the function pointer is not NULL) and
+  ** will fall back to xCurrentTime() if xCurrentTimeInt64() is
+  ** unavailable.
+  */
   if( pVfs->iVersion>=2 && pVfs->xCurrentTimeInt64 ){
     rc = pVfs->xCurrentTimeInt64(pVfs, pTimeOut);
   }else{
@@ -13903,7 +14339,7 @@ static int sqlite3MemSize(void *pPrior){
 static void *sqlite3MemRealloc(void *pPrior, int nByte){
   sqlite3_int64 *p = (sqlite3_int64*)pPrior;
   assert( pPrior!=0 && nByte>0 );
-  nByte = ROUND8(nByte);
+  assert( nByte==ROUND8(nByte) ); /* EV: R-46199-30249 */
   p--;
   p = realloc(p, nByte+8 );
   if( p ){
@@ -14309,6 +14745,7 @@ static void *sqlite3MemRealloc(void *pPrior, int nByte){
   struct MemBlockHdr *pOldHdr;
   void *pNew;
   assert( mem.disallow==0 );
+  assert( (nByte & 7)==0 );     /* EV: R-46199-30249 */
   pOldHdr = sqlite3MemsysGetHeader(pPrior);
   pNew = sqlite3MemMalloc(nByte);
   if( pNew ){
@@ -15578,7 +16015,7 @@ static void *memsys5Realloc(void *pPrior, int nBytes){
   int nOld;
   void *p;
   assert( pPrior!=0 );
-  assert( (nBytes&(nBytes-1))==0 );
+  assert( (nBytes&(nBytes-1))==0 );  /* EV: R-46199-30249 */
   assert( nBytes>=0 );
   if( nBytes==0 ){
     return 0;
@@ -16500,7 +16937,7 @@ static int pthreadMutexEnd(void){ return SQLITE_OK; }
 ** <li>  SQLITE_MUTEX_STATIC_MEM2
 ** <li>  SQLITE_MUTEX_STATIC_PRNG
 ** <li>  SQLITE_MUTEX_STATIC_LRU
-** <li>  SQLITE_MUTEX_STATIC_LRU2
+** <li>  SQLITE_MUTEX_STATIC_PMEM
 ** </ul>
 **
 ** The first two constants cause sqlite3_mutex_alloc() to create
@@ -16910,7 +17347,7 @@ static int winMutexEnd(void){
 ** <li>  SQLITE_MUTEX_STATIC_MEM2
 ** <li>  SQLITE_MUTEX_STATIC_PRNG
 ** <li>  SQLITE_MUTEX_STATIC_LRU
-** <li>  SQLITE_MUTEX_STATIC_LRU2
+** <li>  SQLITE_MUTEX_STATIC_PMEM
 ** </ul>
 **
 ** The first two constants cause sqlite3_mutex_alloc() to create
@@ -17103,69 +17540,34 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
 */
 
 /*
-** This routine runs when the memory allocator sees that the
-** total memory allocation is about to exceed the soft heap
-** limit.
-*/
-static void softHeapLimitEnforcer(
-  void *NotUsed, 
-  sqlite3_int64 NotUsed2,
-  int allocSize
-){
-  UNUSED_PARAMETER2(NotUsed, NotUsed2);
-  sqlite3_release_memory(allocSize);
-}
-
-/*
-** Set the soft heap-size limit for the library. Passing a zero or 
-** negative value indicates no limit.
-*/
-SQLITE_API void sqlite3_soft_heap_limit(int n){
-  sqlite3_uint64 iLimit;
-  int overage;
-  if( n<0 ){
-    iLimit = 0;
-  }else{
-    iLimit = n;
-  }
-#ifndef SQLITE_OMIT_AUTOINIT
-  sqlite3_initialize();
-#endif
-  if( iLimit>0 ){
-    sqlite3MemoryAlarm(softHeapLimitEnforcer, 0, iLimit);
-  }else{
-    sqlite3MemoryAlarm(0, 0, 0);
-  }
-  overage = (int)(sqlite3_memory_used() - (i64)n);
-  if( overage>0 ){
-    sqlite3_release_memory(overage);
-  }
-}
-
-/*
 ** Attempt to release up to n bytes of non-essential memory currently
 ** held by SQLite. An example of non-essential memory is memory used to
 ** cache database pages that are not currently in use.
 */
 SQLITE_API int sqlite3_release_memory(int n){
 #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
-  int nRet = 0;
-  nRet += sqlite3PcacheReleaseMemory(n-nRet);
-  return nRet;
+  return sqlite3PcacheReleaseMemory(n);
 #else
+  /* IMPLEMENTATION-OF: R-34391-24921 The sqlite3_release_memory() routine
+  ** is a no-op returning zero if SQLite is not compiled with
+  ** SQLITE_ENABLE_MEMORY_MANAGEMENT. */
   UNUSED_PARAMETER(n);
-  return SQLITE_OK;
+  return 0;
 #endif
 }
 
 /*
+** An instance of the following object records the location of
+** each unused scratch buffer.
+*/
+typedef struct ScratchFreeslot {
+  struct ScratchFreeslot *pNext;   /* Next unused scratch buffer */
+} ScratchFreeslot;
+
+/*
 ** State information local to the memory allocation subsystem.
 */
 static SQLITE_WSD struct Mem0Global {
-  /* Number of free pages for scratch and page-cache memory */
-  u32 nScratchFree;
-  u32 nPageFree;
-
   sqlite3_mutex *mutex;         /* Mutex to serialize access */
 
   /*
@@ -17179,17 +17581,100 @@ static SQLITE_WSD struct Mem0Global {
   void *alarmArg;
 
   /*
-  ** Pointers to the end of sqlite3GlobalConfig.pScratch and
-  ** sqlite3GlobalConfig.pPage to a block of memory that records
-  ** which pages are available.
+  ** Pointers to the end of sqlite3GlobalConfig.pScratch memory
+  ** (so that a range test can be used to determine if an allocation
+  ** being freed came from pScratch) and a pointer to the list of
+  ** unused scratch allocations.
+  */
+  void *pScratchEnd;
+  ScratchFreeslot *pScratchFree;
+  u32 nScratchFree;
+
+  /*
+  ** True if heap is nearly "full" where "full" is defined by the
+  ** sqlite3_soft_heap_limit() setting.
   */
-  u32 *aScratchFree;
-  u32 *aPageFree;
+  int nearlyFull;
 } mem0 = { 0, 0, 0, 0, 0, 0, 0, 0 };
 
 #define mem0 GLOBAL(struct Mem0Global, mem0)
 
 /*
+** This routine runs when the memory allocator sees that the
+** total memory allocation is about to exceed the soft heap
+** limit.
+*/
+static void softHeapLimitEnforcer(
+  void *NotUsed, 
+  sqlite3_int64 NotUsed2,
+  int allocSize
+){
+  UNUSED_PARAMETER2(NotUsed, NotUsed2);
+  sqlite3_release_memory(allocSize);
+}
+
+/*
+** Change the alarm callback
+*/
+static int sqlite3MemoryAlarm(
+  void(*xCallback)(void *pArg, sqlite3_int64 used,int N),
+  void *pArg,
+  sqlite3_int64 iThreshold
+){
+  int nUsed;
+  sqlite3_mutex_enter(mem0.mutex);
+  mem0.alarmCallback = xCallback;
+  mem0.alarmArg = pArg;
+  mem0.alarmThreshold = iThreshold;
+  nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
+  mem0.nearlyFull = (iThreshold>0 && iThreshold<=nUsed);
+  sqlite3_mutex_leave(mem0.mutex);
+  return SQLITE_OK;
+}
+
+#ifndef SQLITE_OMIT_DEPRECATED
+/*
+** Deprecated external interface.  Internal/core SQLite code
+** should call sqlite3MemoryAlarm.
+*/
+SQLITE_API int sqlite3_memory_alarm(
+  void(*xCallback)(void *pArg, sqlite3_int64 used,int N),
+  void *pArg,
+  sqlite3_int64 iThreshold
+){
+  return sqlite3MemoryAlarm(xCallback, pArg, iThreshold);
+}
+#endif
+
+/*
+** Set the soft heap-size limit for the library. Passing a zero or 
+** negative value indicates no limit.
+*/
+SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 n){
+  sqlite3_int64 priorLimit;
+  sqlite3_int64 excess;
+#ifndef SQLITE_OMIT_AUTOINIT
+  sqlite3_initialize();
+#endif
+  sqlite3_mutex_enter(mem0.mutex);
+  priorLimit = mem0.alarmThreshold;
+  sqlite3_mutex_leave(mem0.mutex);
+  if( n<0 ) return priorLimit;
+  if( n>0 ){
+    sqlite3MemoryAlarm(softHeapLimitEnforcer, 0, n);
+  }else{
+    sqlite3MemoryAlarm(0, 0, 0);
+  }
+  excess = sqlite3_memory_used() - n;
+  if( excess>0 ) sqlite3_release_memory((int)(excess & 0x7fffffff));
+  return priorLimit;
+}
+SQLITE_API void sqlite3_soft_heap_limit(int n){
+  if( n<0 ) n = 0;
+  sqlite3_soft_heap_limit64(n);
+}
+
+/*
 ** Initialize the memory allocation subsystem.
 */
 SQLITE_PRIVATE int sqlite3MallocInit(void){
@@ -17201,37 +17686,46 @@ SQLITE_PRIVATE int sqlite3MallocInit(void){
     mem0.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
   }
   if( sqlite3GlobalConfig.pScratch && sqlite3GlobalConfig.szScratch>=100
-      && sqlite3GlobalConfig.nScratch>=0 ){
-    int i;
-    sqlite3GlobalConfig.szScratch = ROUNDDOWN8(sqlite3GlobalConfig.szScratch-4);
-    mem0.aScratchFree = (u32*)&((char*)sqlite3GlobalConfig.pScratch)
-                  [sqlite3GlobalConfig.szScratch*sqlite3GlobalConfig.nScratch];
-    for(i=0; i<sqlite3GlobalConfig.nScratch; i++){ mem0.aScratchFree[i] = i; }
-    mem0.nScratchFree = sqlite3GlobalConfig.nScratch;
+      && sqlite3GlobalConfig.nScratch>0 ){
+    int i, n, sz;
+    ScratchFreeslot *pSlot;
+    sz = ROUNDDOWN8(sqlite3GlobalConfig.szScratch);
+    sqlite3GlobalConfig.szScratch = sz;
+    pSlot = (ScratchFreeslot*)sqlite3GlobalConfig.pScratch;
+    n = sqlite3GlobalConfig.nScratch;
+    mem0.pScratchFree = pSlot;
+    mem0.nScratchFree = n;
+    for(i=0; i<n-1; i++){
+      pSlot->pNext = (ScratchFreeslot*)(sz+(char*)pSlot);
+      pSlot = pSlot->pNext;
+    }
+    pSlot->pNext = 0;
+    mem0.pScratchEnd = (void*)&pSlot[1];
   }else{
+    mem0.pScratchEnd = 0;
     sqlite3GlobalConfig.pScratch = 0;
     sqlite3GlobalConfig.szScratch = 0;
+    sqlite3GlobalConfig.nScratch = 0;
   }
-  if( sqlite3GlobalConfig.pPage && sqlite3GlobalConfig.szPage>=512
-      && sqlite3GlobalConfig.nPage>=1 ){
-    int i;
-    int overhead;
-    int sz = ROUNDDOWN8(sqlite3GlobalConfig.szPage);
-    int n = sqlite3GlobalConfig.nPage;
-    overhead = (4*n + sz - 1)/sz;
-    sqlite3GlobalConfig.nPage -= overhead;
-    mem0.aPageFree = (u32*)&((char*)sqlite3GlobalConfig.pPage)
-                  [sqlite3GlobalConfig.szPage*sqlite3GlobalConfig.nPage];
-    for(i=0; i<sqlite3GlobalConfig.nPage; i++){ mem0.aPageFree[i] = i; }
-    mem0.nPageFree = sqlite3GlobalConfig.nPage;
-  }else{
+  if( sqlite3GlobalConfig.pPage==0 || sqlite3GlobalConfig.szPage<512
+      || sqlite3GlobalConfig.nPage<1 ){
     sqlite3GlobalConfig.pPage = 0;
     sqlite3GlobalConfig.szPage = 0;
+    sqlite3GlobalConfig.nPage = 0;
   }
   return sqlite3GlobalConfig.m.xInit(sqlite3GlobalConfig.m.pAppData);
 }
 
 /*
+** Return true if the heap is currently under memory pressure - in other
+** words if the amount of heap used is close to the limit set by
+** sqlite3_soft_heap_limit().
+*/
+SQLITE_PRIVATE int sqlite3HeapNearlyFull(void){
+  return mem0.nearlyFull;
+}
+
+/*
 ** Deinitialize the memory allocation subsystem.
 */
 SQLITE_PRIVATE void sqlite3MallocEnd(void){
@@ -17266,36 +17760,6 @@ SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag){
 }
 
 /*
-** Change the alarm callback
-*/
-SQLITE_PRIVATE int sqlite3MemoryAlarm(
-  void(*xCallback)(void *pArg, sqlite3_int64 used,int N),
-  void *pArg,
-  sqlite3_int64 iThreshold
-){
-  sqlite3_mutex_enter(mem0.mutex);
-  mem0.alarmCallback = xCallback;
-  mem0.alarmArg = pArg;
-  mem0.alarmThreshold = iThreshold;
-  sqlite3_mutex_leave(mem0.mutex);
-  return SQLITE_OK;
-}
-
-#ifndef SQLITE_OMIT_DEPRECATED
-/*
-** Deprecated external interface.  Internal/core SQLite code
-** should call sqlite3MemoryAlarm.
-*/
-SQLITE_API int sqlite3_memory_alarm(
-  void(*xCallback)(void *pArg, sqlite3_int64 used,int N),
-  void *pArg,
-  sqlite3_int64 iThreshold
-){
-  return sqlite3MemoryAlarm(xCallback, pArg, iThreshold);
-}
-#endif
-
-/*
 ** Trigger the alarm 
 */
 static void sqlite3MallocAlarm(int nByte){
@@ -17327,14 +17791,19 @@ static int mallocWithAlarm(int n, void **pp){
   if( mem0.alarmCallback!=0 ){
     int nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
     if( nUsed+nFull >= mem0.alarmThreshold ){
+      mem0.nearlyFull = 1;
       sqlite3MallocAlarm(nFull);
+    }else{
+      mem0.nearlyFull = 0;
     }
   }
   p = sqlite3GlobalConfig.m.xMalloc(nFull);
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
   if( p==0 && mem0.alarmCallback ){
     sqlite3MallocAlarm(nFull);
     p = sqlite3GlobalConfig.m.xMalloc(nFull);
   }
+#endif
   if( p ){
     nFull = sqlite3MallocSize(p);
     sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nFull);
@@ -17350,7 +17819,9 @@ static int mallocWithAlarm(int n, void **pp){
 */
 SQLITE_PRIVATE void *sqlite3Malloc(int n){
   void *p;
-  if( n<=0 || n>=0x7fffff00 ){
+  if( n<=0               /* IMP: R-65312-04917 */ 
+   || n>=0x7fffff00
+  ){
     /* A memory allocation of a number of bytes which is near the maximum
     ** signed integer value might cause an integer overflow inside of the
     ** xMalloc().  Hence we limit the maximum size to 0x7fffff00, giving
@@ -17364,6 +17835,7 @@ SQLITE_PRIVATE void *sqlite3Malloc(int n){
   }else{
     p = sqlite3GlobalConfig.m.xMalloc(n);
   }
+  assert( EIGHT_BYTE_ALIGNMENT(p) );  /* IMP: R-04675-44850 */
   return p;
 }
 
@@ -17402,59 +17874,65 @@ SQLITE_PRIVATE void *sqlite3ScratchMalloc(int n){
   void *p;
   assert( n>0 );
 
-#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
-  /* Verify that no more than two scratch allocation per thread
-  ** is outstanding at one time.  (This is only checked in the
-  ** single-threaded case since checking in the multi-threaded case
-  ** would be much more complicated.) */
-  assert( scratchAllocOut<=1 );
-#endif
-
-  if( sqlite3GlobalConfig.szScratch<n ){
-    goto scratch_overflow;
-  }else{  
-    sqlite3_mutex_enter(mem0.mutex);
-    if( mem0.nScratchFree==0 ){
+  sqlite3_mutex_enter(mem0.mutex);
+  if( mem0.nScratchFree && sqlite3GlobalConfig.szScratch>=n ){
+    p = mem0.pScratchFree;
+    mem0.pScratchFree = mem0.pScratchFree->pNext;
+    mem0.nScratchFree--;
+    sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_USED, 1);
+    sqlite3StatusSet(SQLITE_STATUS_SCRATCH_SIZE, n);
+    sqlite3_mutex_leave(mem0.mutex);
+  }else{
+    if( sqlite3GlobalConfig.bMemstat ){
+      sqlite3StatusSet(SQLITE_STATUS_SCRATCH_SIZE, n);
+      n = mallocWithAlarm(n, &p);
+      if( p ) sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_OVERFLOW, n);
       sqlite3_mutex_leave(mem0.mutex);
-      goto scratch_overflow;
     }else{
-      int i;
-      i = mem0.aScratchFree[--mem0.nScratchFree];
-      i *= sqlite3GlobalConfig.szScratch;
-      sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_USED, 1);
-      sqlite3StatusSet(SQLITE_STATUS_SCRATCH_SIZE, n);
       sqlite3_mutex_leave(mem0.mutex);
-      p = (void*)&((char*)sqlite3GlobalConfig.pScratch)[i];
-      assert(  (((u8*)p - (u8*)0) & 7)==0 );
+      p = sqlite3GlobalConfig.m.xMalloc(n);
     }
+    sqlite3MemdebugSetType(p, MEMTYPE_SCRATCH);
   }
-#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
-  scratchAllocOut = p!=0;
-#endif
+  assert( sqlite3_mutex_notheld(mem0.mutex) );
 
-  return p;
 
-scratch_overflow:
-  if( sqlite3GlobalConfig.bMemstat ){
-    sqlite3_mutex_enter(mem0.mutex);
-    sqlite3StatusSet(SQLITE_STATUS_SCRATCH_SIZE, n);
-    n = mallocWithAlarm(n, &p);
-    if( p ) sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_OVERFLOW, n);
-    sqlite3_mutex_leave(mem0.mutex);
-  }else{
-    p = sqlite3GlobalConfig.m.xMalloc(n);
-  }
-  sqlite3MemdebugSetType(p, MEMTYPE_SCRATCH);
 #if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
-  scratchAllocOut = p!=0;
+  /* Verify that no more than two scratch allocations per thread
+  ** are outstanding at one time.  (This is only checked in the
+  ** single-threaded case since checking in the multi-threaded case
+  ** would be much more complicated.) */
+  assert( scratchAllocOut<=1 );
+  if( p ) scratchAllocOut++;
 #endif
-  return p;    
+
+  return p;
 }
 SQLITE_PRIVATE void sqlite3ScratchFree(void *p){
   if( p ){
-    if( sqlite3GlobalConfig.pScratch==0
-           || p<sqlite3GlobalConfig.pScratch
-           || p>=(void*)mem0.aScratchFree ){
+
+#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
+    /* Verify that no more than two scratch allocation per thread
+    ** is outstanding at one time.  (This is only checked in the
+    ** single-threaded case since checking in the multi-threaded case
+    ** would be much more complicated.) */
+    assert( scratchAllocOut>=1 && scratchAllocOut<=2 );
+    scratchAllocOut--;
+#endif
+
+    if( p>=sqlite3GlobalConfig.pScratch && p<mem0.pScratchEnd ){
+      /* Release memory from the SQLITE_CONFIG_SCRATCH allocation */
+      ScratchFreeslot *pSlot;
+      pSlot = (ScratchFreeslot*)p;
+      sqlite3_mutex_enter(mem0.mutex);
+      pSlot->pNext = mem0.pScratchFree;
+      mem0.pScratchFree = pSlot;
+      mem0.nScratchFree++;
+      assert( mem0.nScratchFree<=sqlite3GlobalConfig.nScratch );
+      sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_USED, -1);
+      sqlite3_mutex_leave(mem0.mutex);
+    }else{
+      /* Release memory back to the heap */
       assert( sqlite3MemdebugHasType(p, MEMTYPE_SCRATCH) );
       assert( sqlite3MemdebugNoType(p, ~MEMTYPE_SCRATCH) );
       sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
@@ -17469,26 +17947,6 @@ SQLITE_PRIVATE void sqlite3ScratchFree(void *p){
       }else{
         sqlite3GlobalConfig.m.xFree(p);
       }
-    }else{
-      int i;
-      i = (int)((u8*)p - (u8*)sqlite3GlobalConfig.pScratch);
-      i /= sqlite3GlobalConfig.szScratch;
-      assert( i>=0 && i<sqlite3GlobalConfig.nScratch );
-      sqlite3_mutex_enter(mem0.mutex);
-      assert( mem0.nScratchFree<(u32)sqlite3GlobalConfig.nScratch );
-      mem0.aScratchFree[mem0.nScratchFree++] = i;
-      sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_USED, -1);
-      sqlite3_mutex_leave(mem0.mutex);
-
-#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
-    /* Verify that no more than two scratch allocation per thread
-    ** is outstanding at one time.  (This is only checked in the
-    ** single-threaded case since checking in the multi-threaded case
-    ** would be much more complicated.) */
-    assert( scratchAllocOut>=1 && scratchAllocOut<=2 );
-    scratchAllocOut = 0;
-#endif
-
     }
   }
 }
@@ -17529,7 +17987,7 @@ SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){
 ** Free memory previously obtained from sqlite3Malloc().
 */
 SQLITE_API void sqlite3_free(void *p){
-  if( p==0 ) return;
+  if( p==0 ) return;  /* IMP: R-49053-54554 */
   assert( sqlite3MemdebugNoType(p, MEMTYPE_DB) );
   assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
   if( sqlite3GlobalConfig.bMemstat ){
@@ -17576,10 +18034,10 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, int nBytes){
   int nOld, nNew;
   void *pNew;
   if( pOld==0 ){
-    return sqlite3Malloc(nBytes);
+    return sqlite3Malloc(nBytes); /* IMP: R-28354-25769 */
   }
   if( nBytes<=0 ){
-    sqlite3_free(pOld);
+    sqlite3_free(pOld); /* IMP: R-31593-10574 */
     return 0;
   }
   if( nBytes>=0x7fffff00 ){
@@ -17587,6 +18045,9 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, int nBytes){
     return 0;
   }
   nOld = sqlite3MallocSize(pOld);
+  /* IMPLEMENTATION-OF: R-46199-30249 SQLite guarantees that the second
+  ** argument to xRealloc is always a value returned by a prior call to
+  ** xRoundup. */
   nNew = sqlite3GlobalConfig.m.xRoundup(nBytes);
   if( nOld==nNew ){
     pNew = pOld;
@@ -17612,6 +18073,7 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, int nBytes){
   }else{
     pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
   }
+  assert( EIGHT_BYTE_ALIGNMENT(pNew) ); /* IMP: R-04675-44850 */
   return pNew;
 }
 
@@ -17678,14 +18140,20 @@ SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3 *db, int n){
     if( db->mallocFailed ){
       return 0;
     }
-    if( db->lookaside.bEnabled && n<=db->lookaside.sz
-         && (pBuf = db->lookaside.pFree)!=0 ){
-      db->lookaside.pFree = pBuf->pNext;
-      db->lookaside.nOut++;
-      if( db->lookaside.nOut>db->lookaside.mxOut ){
-        db->lookaside.mxOut = db->lookaside.nOut;
+    if( db->lookaside.bEnabled ){
+      if( n>db->lookaside.sz ){
+        db->lookaside.anStat[1]++;
+      }else if( (pBuf = db->lookaside.pFree)==0 ){
+        db->lookaside.anStat[2]++;
+      }else{
+        db->lookaside.pFree = pBuf->pNext;
+        db->lookaside.nOut++;
+        db->lookaside.anStat[0]++;
+        if( db->lookaside.nOut>db->lookaside.mxOut ){
+          db->lookaside.mxOut = db->lookaside.nOut;
+        }
+        return (void*)pBuf;
       }
-      return (void*)pBuf;
     }
   }
 #else
@@ -18597,6 +19065,7 @@ SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
         return;
       }
     }else{
+      char *zOld = (p->zText==p->zBase ? 0 : p->zText);
       i64 szNew = p->nChar;
       szNew += N + 1;
       if( szNew > p->mxAlloc ){
@@ -18607,13 +19076,12 @@ SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
         p->nAlloc = (int)szNew;
       }
       if( p->useMalloc==1 ){
-        zNew = sqlite3DbMallocRaw(p->db, p->nAlloc );
+        zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc);
       }else{
-        zNew = sqlite3_malloc(p->nAlloc);
+        zNew = sqlite3_realloc(zOld, p->nAlloc);
       }
       if( zNew ){
-        memcpy(zNew, p->zText, p->nChar);
-        sqlite3StrAccumReset(p);
+        if( zOld==0 ) memcpy(zNew, p->zText, p->nChar);
         p->zText = zNew;
       }else{
         p->mallocFailed = 1;
@@ -18768,21 +19236,28 @@ SQLITE_API char *sqlite3_mprintf(const char *zFormat, ...){
 ** current locale settings.  This is important for SQLite because we
 ** are not able to use a "," as the decimal point in place of "." as
 ** specified by some locales.
+**
+** Oops:  The first two arguments of sqlite3_snprintf() are backwards
+** from the snprintf() standard.  Unfortunately, it is too late to change
+** this without breaking compatibility, so we just have to live with the
+** mistake.
+**
+** sqlite3_vsnprintf() is the varargs version.
 */
-SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
-  char *z;
-  va_list ap;
+SQLITE_API char *sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_list ap){
   StrAccum acc;
-
-  if( n<=0 ){
-    return zBuf;
-  }
+  if( n<=0 ) return zBuf;
   sqlite3StrAccumInit(&acc, zBuf, n, 0);
   acc.useMalloc = 0;
-  va_start(ap,zFormat);
   sqlite3VXPrintf(&acc, 0, zFormat, ap);
+  return sqlite3StrAccumFinish(&acc);
+}
+SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
+  char *z;
+  va_list ap;
+  va_start(ap,zFormat);
+  z = sqlite3_vsnprintf(n, zBuf, zFormat, ap);
   va_end(ap);
-  z = sqlite3StrAccumFinish(&acc);
   return z;
 }
 
@@ -19775,6 +20250,12 @@ SQLITE_PRIVATE int sqlite3Dequote(char *z){
 /*
 ** Some systems have stricmp().  Others have strcasecmp().  Because
 ** there is no consistency, we will define our own.
+**
+** IMPLEMENTATION-OF: R-20522-24639 The sqlite3_strnicmp() API allows
+** applications and extensions to compare the contents of two buffers
+** containing UTF-8 strings in a case-independent fashion, using the same
+** definition of case independence that SQLite uses internally when
+** comparing identifiers.
 */
 SQLITE_PRIVATE int sqlite3StrICmp(const char *zLeft, const char *zRight){
   register unsigned char *a, *b;
@@ -19792,121 +20273,111 @@ SQLITE_API int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){
 }
 
 /*
-** Return TRUE if z is a pure numeric string.  Return FALSE and leave
-** *realnum unchanged if the string contains any character which is not
-** part of a number.
+** The string z[] is an text representation of a real number.
+** Convert this string to a double and write it into *pResult.
 **
-** If the string is pure numeric, set *realnum to TRUE if the string
-** contains the '.' character or an "E+000" style exponentiation suffix.
-** Otherwise set *realnum to FALSE.  Note that just becaue *realnum is
-** false does not mean that the number can be successfully converted into
-** an integer - it might be too big.
+** The string z[] is length bytes in length (bytes, not characters) and
+** uses the encoding enc.  The string is not necessarily zero-terminated.
 **
-** An empty string is considered non-numeric.
-*/
-SQLITE_PRIVATE int sqlite3IsNumber(const char *z, int *realnum, u8 enc){
-  int incr = (enc==SQLITE_UTF8?1:2);
-  if( enc==SQLITE_UTF16BE ) z++;
-  if( *z=='-' || *z=='+' ) z += incr;
-  if( !sqlite3Isdigit(*z) ){
-    return 0;
-  }
-  z += incr;
-  *realnum = 0;
-  while( sqlite3Isdigit(*z) ){ z += incr; }
-#ifndef SQLITE_OMIT_FLOATING_POINT
-  if( *z=='.' ){
-    z += incr;
-    if( !sqlite3Isdigit(*z) ) return 0;
-    while( sqlite3Isdigit(*z) ){ z += incr; }
-    *realnum = 1;
-  }
-  if( *z=='e' || *z=='E' ){
-    z += incr;
-    if( *z=='+' || *z=='-' ) z += incr;
-    if( !sqlite3Isdigit(*z) ) return 0;
-    while( sqlite3Isdigit(*z) ){ z += incr; }
-    *realnum = 1;
-  }
-#endif
-  return *z==0;
-}
-
-/*
-** The string z[] is an ASCII representation of a real number.
-** Convert this string to a double.
+** Return TRUE if the result is a valid real number (or integer) and FALSE
+** if the string is empty or contains extraneous text.  Valid numbers
+** are in one of these formats:
+**
+**    [+-]digits[E[+-]digits]
+**    [+-]digits.[digits][E[+-]digits]
+**    [+-].digits[E[+-]digits]
 **
-** This routine assumes that z[] really is a valid number.  If it
-** is not, the result is undefined.
+** Leading and trailing whitespace is ignored for the purpose of determining
+** validity.
 **
-** This routine is used instead of the library atof() function because
-** the library atof() might want to use "," as the decimal point instead
-** of "." depending on how locale is set.  But that would cause problems
-** for SQL.  So this routine always uses "." regardless of locale.
+** If some prefix of the input string is a valid number, this routine
+** returns FALSE but it still converts the prefix and writes the result
+** into *pResult.
 */
-SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult){
+SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){
 #ifndef SQLITE_OMIT_FLOATING_POINT
-  const char *zBegin = z;
+  int incr = (enc==SQLITE_UTF8?1:2);
+  const char *zEnd = z + length;
   /* sign * significand * (10 ^ (esign * exponent)) */
-  int sign = 1;   /* sign of significand */
-  i64 s = 0;      /* significand */
-  int d = 0;      /* adjust exponent for shifting decimal point */
-  int esign = 1;  /* sign of exponent */
-  int e = 0;      /* exponent */
+  int sign = 1;    /* sign of significand */
+  i64 s = 0;       /* significand */
+  int d = 0;       /* adjust exponent for shifting decimal point */
+  int esign = 1;   /* sign of exponent */
+  int e = 0;       /* exponent */
+  int eValid = 1;  /* True exponent is either not used or is well-formed */
   double result;
   int nDigits = 0;
 
+  *pResult = 0.0;   /* Default return value, in case of an error */
+
+  if( enc==SQLITE_UTF16BE ) z++;
+
   /* skip leading spaces */
-  while( sqlite3Isspace(*z) ) z++;
+  while( z<zEnd && sqlite3Isspace(*z) ) z+=incr;
+  if( z>=zEnd ) return 0;
+
   /* get sign of significand */
   if( *z=='-' ){
     sign = -1;
-    z++;
+    z+=incr;
   }else if( *z=='+' ){
-    z++;
+    z+=incr;
   }
+
   /* skip leading zeroes */
-  while( z[0]=='0' ) z++, nDigits++;
+  while( z<zEnd && z[0]=='0' ) z+=incr, nDigits++;
 
   /* copy max significant digits to significand */
-  while( sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){
+  while( z<zEnd && sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){
     s = s*10 + (*z - '0');
-    z++, nDigits++;
+    z+=incr, nDigits++;
   }
+
   /* skip non-significant significand digits
   ** (increase exponent by d to shift decimal left) */
-  while( sqlite3Isdigit(*z) ) z++, nDigits++, d++;
+  while( z<zEnd && sqlite3Isdigit(*z) ) z+=incr, nDigits++, d++;
+  if( z>=zEnd ) goto do_atof_calc;
 
   /* if decimal point is present */
   if( *z=='.' ){
-    z++;
+    z+=incr;
     /* copy digits from after decimal to significand
     ** (decrease exponent by d to shift decimal right) */
-    while( sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){
+    while( z<zEnd && sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){
       s = s*10 + (*z - '0');
-      z++, nDigits++, d--;
+      z+=incr, nDigits++, d--;
     }
     /* skip non-significant digits */
-    while( sqlite3Isdigit(*z) ) z++, nDigits++;
+    while( z<zEnd && sqlite3Isdigit(*z) ) z+=incr, nDigits++;
   }
+  if( z>=zEnd ) goto do_atof_calc;
 
   /* if exponent is present */
   if( *z=='e' || *z=='E' ){
-    z++;
+    z+=incr;
+    eValid = 0;
+    if( z>=zEnd ) goto do_atof_calc;
     /* get sign of exponent */
     if( *z=='-' ){
       esign = -1;
-      z++;
+      z+=incr;
     }else if( *z=='+' ){
-      z++;
+      z+=incr;
     }
     /* copy digits to exponent */
-    while( sqlite3Isdigit(*z) ){
+    while( z<zEnd && sqlite3Isdigit(*z) ){
       e = e*10 + (*z - '0');
-      z++;
+      z+=incr;
+      eValid = 1;
     }
   }
 
+  /* skip trailing spaces */
+  if( nDigits && eValid ){
+    while( z<zEnd && sqlite3Isspace(*z) ) z+=incr;
+  }
+
+do_atof_calc:
   /* adjust exponent by d, and update sign */
   e = (e*esign) + d;
   if( e<0 ) {
@@ -19965,10 +20436,10 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult){
   /* store the result */
   *pResult = result;
 
-  /* return number of characters used */
-  return (int)(z - zBegin);
+  /* return true if number and no extra non-whitespace chracters after */
+  return z>=zEnd && nDigits>0 && eValid;
 #else
-  return sqlite3Atoi64(z, pResult);
+  return !sqlite3Atoi64(z, pResult, length, enc);
 #endif /* SQLITE_OMIT_FLOATING_POINT */
 }
 
@@ -19976,20 +20447,26 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult){
 ** Compare the 19-character string zNum against the text representation
 ** value 2^63:  9223372036854775808.  Return negative, zero, or positive
 ** if zNum is less than, equal to, or greater than the string.
+** Note that zNum must contain exactly 19 characters.
 **
 ** Unlike memcmp() this routine is guaranteed to return the difference
 ** in the values of the last digit if the only difference is in the
 ** last digit.  So, for example,
 **
-**      compare2pow63("9223372036854775800")
+**      compare2pow63("9223372036854775800", 1)
 **
 ** will return -8.
 */
-static int compare2pow63(const char *zNum){
-  int c;
-  c = memcmp(zNum,"922337203685477580",18)*10;
+static int compare2pow63(const char *zNum, int incr){
+  int c = 0;
+  int i;
+                    /* 012345678901234567 */
+  const char *pow63 = "922337203685477580";
+  for(i=0; c==0 && i<18; i++){
+    c = (zNum[i*incr]-pow63[i])*10;
+  }
   if( c==0 ){
-    c = zNum[18] - '8';
+    c = zNum[18*incr] - '8';
     testcase( c==(-1) );
     testcase( c==0 );
     testcase( c==(+1) );
@@ -19999,94 +20476,60 @@ static int compare2pow63(const char *zNum){
 
 
 /*
-** Return TRUE if zNum is a 64-bit signed integer and write
-** the value of the integer into *pNum.  If zNum is not an integer
-** or is an integer that is too large to be expressed with 64 bits,
-** then return false.
+** Convert zNum to a 64-bit signed integer and write
+** the value of the integer into *pNum.
+** If zNum is exactly 9223372036854665808, return 2.
+** This is a special case as the context will determine
+** if it is too big (used as a negative).
+** If zNum is not an integer or is an integer that 
+** is too large to be expressed with 64 bits,
+** then return 1.  Otherwise return 0.
 **
-** When this routine was originally written it dealt with only
-** 32-bit numbers.  At that time, it was much faster than the
-** atoi() library routine in RedHat 7.2.
+** length is the number of bytes in the string (bytes, not characters).
+** The string is not necessarily zero-terminated.  The encoding is
+** given by enc.
 */
-SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum){
+SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
+  int incr = (enc==SQLITE_UTF8?1:2);
   i64 v = 0;
-  int neg;
-  int i, c;
+  int neg = 0; /* assume positive */
+  int i;
+  int c = 0;
   const char *zStart;
-  while( sqlite3Isspace(*zNum) ) zNum++;
+  const char *zEnd = zNum + length;
+  if( enc==SQLITE_UTF16BE ) zNum++;
+  while( zNum<zEnd && sqlite3Isspace(*zNum) ) zNum+=incr;
+  if( zNum>=zEnd ) goto do_atoi_calc;
   if( *zNum=='-' ){
     neg = 1;
-    zNum++;
+    zNum+=incr;
   }else if( *zNum=='+' ){
-    neg = 0;
-    zNum++;
-  }else{
-    neg = 0;
+    zNum+=incr;
   }
+do_atoi_calc:
   zStart = zNum;
-  while( zNum[0]=='0' ){ zNum++; } /* Skip over leading zeros. Ticket #2454 */
-  for(i=0; (c=zNum[i])>='0' && c<='9'; i++){
+  while( zNum<zEnd && zNum[0]=='0' ){ zNum+=incr; } /* Skip leading zeros. */
+  for(i=0; &zNum[i]<zEnd && (c=zNum[i])>='0' && c<='9'; i+=incr){
     v = v*10 + c - '0';
   }
   *pNum = neg ? -v : v;
   testcase( i==18 );
   testcase( i==19 );
   testcase( i==20 );
-  if( c!=0 || (i==0 && zStart==zNum) || i>19 ){
+  if( (c!=0 && &zNum[i]<zEnd) || (i==0 && zStart==zNum) || i>19*incr ){
     /* zNum is empty or contains non-numeric text or is longer
-    ** than 19 digits (thus guaranting that it is too large) */
-    return 0;
-  }else if( i<19 ){
-    /* Less than 19 digits, so we know that it fits in 64 bits */
+    ** than 19 digits (thus guaranteeing that it is too large) */
     return 1;
+  }else if( i<19*incr ){
+    /* Less than 19 digits, so we know that it fits in 64 bits */
+    return 0;
   }else{
     /* 19-digit numbers must be no larger than 9223372036854775807 if positive
     ** or 9223372036854775808 if negative.  Note that 9223372036854665808
-    ** is 2^63. */
-    return compare2pow63(zNum)<neg;
-  }
-}
-
-/*
-** The string zNum represents an unsigned integer.  The zNum string
-** consists of one or more digit characters and is terminated by
-** a zero character.  Any stray characters in zNum result in undefined
-** behavior.
-**
-** If the unsigned integer that zNum represents will fit in a
-** 64-bit signed integer, return TRUE.  Otherwise return FALSE.
-**
-** If the negFlag parameter is true, that means that zNum really represents
-** a negative number.  (The leading "-" is omitted from zNum.)  This
-** parameter is needed to determine a boundary case.  A string
-** of "9223373036854775808" returns false if negFlag is false or true
-** if negFlag is true.
-**
-** Leading zeros are ignored.
-*/
-SQLITE_PRIVATE int sqlite3FitsIn64Bits(const char *zNum, int negFlag){
-  int i;
-  int neg = 0;
-
-  assert( zNum[0]>='0' && zNum[0]<='9' ); /* zNum is an unsigned number */
-
-  if( negFlag ) neg = 1-neg;
-  while( *zNum=='0' ){
-    zNum++;   /* Skip leading zeros.  Ticket #2454 */
-  }
-  for(i=0; zNum[i]; i++){ assert( zNum[i]>='0' && zNum[i]<='9' ); }
-  testcase( i==18 );
-  testcase( i==19 );
-  testcase( i==20 );
-  if( i<19 ){
-    /* Guaranteed to fit if less than 19 digits */
-    return 1;
-  }else if( i>19 ){
-    /* Guaranteed to be too big if greater than 19 digits */
-    return 0;
-  }else{
-    /* Compare against 2^63. */
-    return compare2pow63(zNum)<neg;
+    ** is 2^63. Return 1 if to large */
+    c=compare2pow63(zNum, incr);
+    if( c==0 && neg==0 ) return 2; /* too big, exactly 9223372036854665808 */
+    return c<neg ? 0 : 1;
   }
 }
 
@@ -20134,6 +20577,16 @@ SQLITE_PRIVATE int sqlite3GetInt32(const char *zNum, int *pValue){
 }
 
 /*
+** Return a 32-bit integer value extracted from a string.  If the
+** string is not an integer, just return 0.
+*/
+SQLITE_PRIVATE int sqlite3Atoi(const char *z){
+  int x = 0;
+  if( z ) sqlite3GetInt32(z, &x);
+  return x;
+}
+
+/*
 ** The variable-length integer encoding is as follows:
 **
 ** KEY:
@@ -21062,10 +21515,10 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
      /* 132 */ "VRename",
      /* 133 */ "VUpdate",
      /* 134 */ "Pagecount",
-     /* 135 */ "Trace",
-     /* 136 */ "Noop",
-     /* 137 */ "Explain",
-     /* 138 */ "NotUsed_138",
+     /* 135 */ "MaxPgcnt",
+     /* 136 */ "Trace",
+     /* 137 */ "Noop",
+     /* 138 */ "Explain",
      /* 139 */ "NotUsed_139",
      /* 140 */ "NotUsed_140",
      /* 141 */ "ToText",
@@ -21819,7 +22272,7 @@ static int os2FileControl(sqlite3_file *id, int op, void *pArg){
       return SQLITE_OK;
     }
   }
-  return SQLITE_ERROR;
+  return SQLITE_NOTFOUND;
 }
 
 /*
@@ -22535,7 +22988,9 @@ SQLITE_API int sqlite3_os_end(void){
 #include <unistd.h>
 #include <sys/time.h>
 #include <errno.h>
+#ifndef SQLITE_OMIT_WAL
 #include <sys/mman.h>
+#endif
 
 #if SQLITE_ENABLE_LOCKING_STYLE
 # include <sys/ioctl.h>
@@ -25753,8 +26208,11 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
       return proxyFileControl(id,op,pArg);
     }
 #endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */
+    case SQLITE_FCNTL_SYNC_OMITTED: {
+      return SQLITE_OK;  /* A no-op */
+    }
   }
-  return SQLITE_ERROR;
+  return SQLITE_NOTFOUND;
 }
 
 /*
@@ -26179,7 +26637,7 @@ static int unixShmMap(
     pShmNode->apRegion = apNew;
     while(pShmNode->nRegion<=iRegion){
       void *pMem = mmap(0, szRegion, PROT_READ|PROT_WRITE, 
-          MAP_SHARED, pShmNode->h, iRegion*szRegion
+          MAP_SHARED, pShmNode->h, pShmNode->nRegion*szRegion
       );
       if( pMem==MAP_FAILED ){
         rc = SQLITE_IOERR;
@@ -26697,11 +27155,21 @@ static int fillInUnixFile(
   */
   UNUSED_PARAMETER(isDelete);
 
+  /* Usually the path zFilename should not be a relative pathname. The
+  ** exception is when opening the proxy "conch" file in builds that
+  ** include the special Apple locking styles.
+  */
+#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
+  assert( zFilename==0 || zFilename[0]=='/' 
+    || pVfs->pAppData==(void*)&autolockIoFinder );
+#else
+  assert( zFilename==0 || zFilename[0]=='/' );
+#endif
+
   OSTRACE(("OPEN    %-3d %s\n", h, zFilename));
   pNew->h = h;
   pNew->dirfd = dirfd;
   pNew->fileFlags = 0;
-  assert( zFilename==0 || zFilename[0]=='/' );  /* Never a relative pathname */
   pNew->zPath = zFilename;
 
 #if OS_VXWORKS
@@ -27041,9 +27509,24 @@ static int findCreateFileMode(
     int nDb;                      /* Number of valid bytes in zDb */
     struct stat sStat;            /* Output of stat() on database file */
 
-    nDb = sqlite3Strlen30(zPath) - ((flags & SQLITE_OPEN_WAL) ? 4 : 8);
+    /* zPath is a path to a WAL or journal file. The following block derives
+    ** the path to the associated database file from zPath. This block handles
+    ** the following naming conventions:
+    **
+    **   "<path to db>-journal"
+    **   "<path to db>-wal"
+    **   "<path to db>-journal-NNNN"
+    **   "<path to db>-wal-NNNN"
+    **
+    ** where NNNN is a 4 digit decimal number. The NNNN naming schemes are 
+    ** used by the test_multiplex.c module.
+    */
+    nDb = sqlite3Strlen30(zPath) - 1; 
+    while( nDb>0 && zPath[nDb]!='l' ) nDb--;
+    nDb -= ((flags & SQLITE_OPEN_WAL) ? 3 : 7);
     memcpy(zDb, zPath, nDb);
     zDb[nDb] = '\0';
+
     if( 0==stat(zDb, &sStat) ){
       *pMode = sStat.st_mode & 0777;
     }else{
@@ -27458,7 +27941,7 @@ static void *unixDlOpen(sqlite3_vfs *NotUsed, const char *zFilename){
 ** error message.
 */
 static void unixDlError(sqlite3_vfs *NotUsed, int nBuf, char *zBufOut){
-  char *zErr;
+  const char *zErr;
   UNUSED_PARAMETER(NotUsed);
   unixEnterMutex();
   zErr = dlerror();
@@ -27595,7 +28078,7 @@ static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){
 #if defined(NO_GETTOD)
   time_t t;
   time(&t);
-  *piNow = ((sqlite3_int64)i)*1000 + unixEpoch;
+  *piNow = ((sqlite3_int64)t)*1000 + unixEpoch;
 #elif OS_VXWORKS
   struct timespec sNow;
   clock_gettime(CLOCK_REALTIME, &sNow);
@@ -27998,17 +28481,21 @@ extern int gethostuuid(uuid_t id, const struct timespec *wait);
 ** bytes of writable memory.
 */
 static int proxyGetHostID(unsigned char *pHostID, int *pError){
-  struct timespec timeout = {1, 0}; /* 1 sec timeout */
-  
   assert(PROXY_HOSTIDLEN == sizeof(uuid_t));
   memset(pHostID, 0, PROXY_HOSTIDLEN);
-  if( gethostuuid(pHostID, &timeout) ){
-    int err = errno;
-    if( pError ){
-      *pError = err;
+#if defined(__MAX_OS_X_VERSION_MIN_REQUIRED)\
+               && __MAC_OS_X_VERSION_MIN_REQUIRED<1050
+  {
+    static const struct timespec timeout = {1, 0}; /* 1 sec timeout */
+    if( gethostuuid(pHostID, &timeout) ){
+      int err = errno;
+      if( pError ){
+        *pError = err;
+      }
+      return SQLITE_IOERR;
     }
-    return SQLITE_IOERR;
   }
+#endif
 #ifdef SQLITE_TEST
   /* simulate multiple hosts by creating unique hostid file paths */
   if( sqlite3_hostid_num != 0){
@@ -28049,27 +28536,27 @@ static int proxyBreakConchLock(unixFile *pFile, uuid_t myHostID){
   pathLen = strlcpy(tPath, cPath, MAXPATHLEN);
   if( pathLen>MAXPATHLEN || pathLen<6 || 
      (strlcpy(&tPath[pathLen-5], "break", 6) != 5) ){
-    sprintf(errmsg, "path error (len %d)", (int)pathLen);
+    sqlite3_snprintf(sizeof(errmsg),errmsg,"path error (len %d)",(int)pathLen);
     goto end_breaklock;
   }
   /* read the conch content */
   readLen = pread(conchFile->h, buf, PROXY_MAXCONCHLEN, 0);
   if( readLen<PROXY_PATHINDEX ){
-    sprintf(errmsg, "read error (len %d)", (int)readLen);
+    sqlite3_snprintf(sizeof(errmsg),errmsg,"read error (len %d)",(int)readLen);
     goto end_breaklock;
   }
   /* write it out to the temporary break file */
   fd = open(tPath, (O_RDWR|O_CREAT|O_EXCL), SQLITE_DEFAULT_FILE_PERMISSIONS);
   if( fd<0 ){
-    sprintf(errmsg, "create failed (%d)", errno);
+    sqlite3_snprintf(sizeof(errmsg), errmsg, "create failed (%d)", errno);
     goto end_breaklock;
   }
   if( pwrite(fd, buf, readLen, 0) != (ssize_t)readLen ){
-    sprintf(errmsg, "write failed (%d)", errno);
+    sqlite3_snprintf(sizeof(errmsg), errmsg, "write failed (%d)", errno);
     goto end_breaklock;
   }
   if( rename(tPath, cPath) ){
-    sprintf(errmsg, "rename failed (%d)", errno);
+    sqlite3_snprintf(sizeof(errmsg), errmsg, "rename failed (%d)", errno);
     goto end_breaklock;
   }
   rc = 0;
@@ -30312,8 +30799,11 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
       SimulateIOErrorBenign(0);
       return SQLITE_OK;
     }
+    case SQLITE_FCNTL_SYNC_OMITTED: {
+      return SQLITE_OK;
+    }
   }
-  return SQLITE_ERROR;
+  return SQLITE_NOTFOUND;
 }
 
 /*
@@ -30341,6 +30831,14 @@ static int winDeviceCharacteristics(sqlite3_file *id){
 
 #ifndef SQLITE_OMIT_WAL
 
+/* 
+** Windows will only let you create file view mappings
+** on allocation size granularity boundaries.
+** During sqlite3_os_init() we do a GetSystemInfo()
+** to get the granularity size.
+*/
+SYSTEM_INFO winSysInfo;
+
 /*
 ** Helper functions to obtain and relinquish the global mutex. The
 ** global mutex is used to protect the winLockInfo objects used by 
@@ -30509,6 +31007,7 @@ static int winDelete(sqlite3_vfs *,const char*,int);
 static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
   winShmNode **pp;
   winShmNode *p;
+  BOOL bRc;
   assert( winShmMutexHeld() );
   pp = &winShmNodeList;
   while( (p = *pp)!=0 ){
@@ -30516,8 +31015,14 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
       int i;
       if( p->mutex ) sqlite3_mutex_free(p->mutex);
       for(i=0; i<p->nRegion; i++){
-        UnmapViewOfFile(p->aRegion[i].pMap);
-        CloseHandle(p->aRegion[i].hMap);
+        bRc = UnmapViewOfFile(p->aRegion[i].pMap);
+        OSTRACE(("SHM-PURGE pid-%d unmap region=%d %s\n",
+                 (int)GetCurrentProcessId(), i,
+                 bRc ? "ok" : "failed"));
+        bRc = CloseHandle(p->aRegion[i].hMap);
+        OSTRACE(("SHM-PURGE pid-%d close region=%d %s\n",
+                 (int)GetCurrentProcessId(), i,
+                 bRc ? "ok" : "failed"));
       }
       if( p->hFile.h != INVALID_HANDLE_VALUE ){
         SimulateIOErrorBenign(1);
@@ -30594,10 +31099,11 @@ static int winOpenSharedMemory(winFile *pDbFd){
       rc = SQLITE_NOMEM;
       goto shm_open_err;
     }
+
     rc = winOpen(pDbFd->pVfs,
                  pShmNode->zFilename,             /* Name of the file (UTF-8) */
                  (sqlite3_file*)&pShmNode->hFile,  /* File handle here */
-                 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, /* Mode flags */
+                 SQLITE_OPEN_WAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, /* Mode flags */
                  0);
     if( SQLITE_OK!=rc ){
       rc = SQLITE_CANTOPEN_BKPT;
@@ -30905,10 +31411,18 @@ static int winShmMap(
       hMap = CreateFileMapping(pShmNode->hFile.h, 
           NULL, PAGE_READWRITE, 0, nByte, NULL
       );
+      OSTRACE(("SHM-MAP pid-%d create region=%d nbyte=%d %s\n",
+               (int)GetCurrentProcessId(), pShmNode->nRegion, nByte,
+               hMap ? "ok" : "failed"));
       if( hMap ){
+        int iOffset = pShmNode->nRegion*szRegion;
+        int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity;
         pMap = MapViewOfFile(hMap, FILE_MAP_WRITE | FILE_MAP_READ,
-            0, 0, nByte
+            0, iOffset - iOffsetShift, szRegion + iOffsetShift
         );
+        OSTRACE(("SHM-MAP pid-%d map region=%d offset=%d size=%d %s\n",
+                 (int)GetCurrentProcessId(), pShmNode->nRegion, iOffset, szRegion,
+                 pMap ? "ok" : "failed"));
       }
       if( !pMap ){
         pShmNode->lastErrno = GetLastError();
@@ -30925,8 +31439,10 @@ static int winShmMap(
 
 shmpage_out:
   if( pShmNode->nRegion>iRegion ){
+    int iOffset = iRegion*szRegion;
+    int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity;
     char *p = (char *)pShmNode->aRegion[iRegion].pMap;
-    *pp = (void *)&p[iRegion*szRegion];
+    *pp = (void *)&p[iOffsetShift];
   }else{
     *pp = 0;
   }
@@ -31153,9 +31669,60 @@ static int winOpen(
   int isTemp = 0;
 #endif
   winFile *pFile = (winFile*)id;
-  void *zConverted;                 /* Filename in OS encoding */
-  const char *zUtf8Name = zName;    /* Filename in UTF-8 encoding */
-  char zTmpname[MAX_PATH+1];        /* Buffer used to create temp filename */
+  void *zConverted;              /* Filename in OS encoding */
+  const char *zUtf8Name = zName; /* Filename in UTF-8 encoding */
+
+  /* If argument zPath is a NULL pointer, this function is required to open
+  ** a temporary file. Use this buffer to store the file name in.
+  */
+  char zTmpname[MAX_PATH+1];     /* Buffer used to create temp filename */
+
+  int rc = SQLITE_OK;            /* Function Return Code */
+#if !defined(NDEBUG) || SQLITE_OS_WINCE
+  int eType = flags&0xFFFFFF00;  /* Type of file to open */
+#endif
+
+  int isExclusive  = (flags & SQLITE_OPEN_EXCLUSIVE);
+  int isDelete     = (flags & SQLITE_OPEN_DELETEONCLOSE);
+  int isCreate     = (flags & SQLITE_OPEN_CREATE);
+#ifndef NDEBUG
+  int isReadonly   = (flags & SQLITE_OPEN_READONLY);
+#endif
+  int isReadWrite  = (flags & SQLITE_OPEN_READWRITE);
+
+#ifndef NDEBUG
+  int isOpenJournal = (isCreate && (
+        eType==SQLITE_OPEN_MASTER_JOURNAL 
+     || eType==SQLITE_OPEN_MAIN_JOURNAL 
+     || eType==SQLITE_OPEN_WAL
+  ));
+#endif
+
+  /* Check the following statements are true: 
+  **
+  **   (a) Exactly one of the READWRITE and READONLY flags must be set, and 
+  **   (b) if CREATE is set, then READWRITE must also be set, and
+  **   (c) if EXCLUSIVE is set, then CREATE must also be set.
+  **   (d) if DELETEONCLOSE is set, then CREATE must also be set.
+  */
+  assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly));
+  assert(isCreate==0 || isReadWrite);
+  assert(isExclusive==0 || isCreate);
+  assert(isDelete==0 || isCreate);
+
+  /* The main DB, main journal, WAL file and master journal are never 
+  ** automatically deleted. Nor are they ever temporary files.  */
+  assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB );
+  assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
+  assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL );
+  assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL );
+
+  /* Assert that the upper layer has set one of the "file-type" flags. */
+  assert( eType==SQLITE_OPEN_MAIN_DB      || eType==SQLITE_OPEN_TEMP_DB 
+       || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL 
+       || eType==SQLITE_OPEN_SUBJOURNAL   || eType==SQLITE_OPEN_MASTER_JOURNAL 
+       || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
+  );
 
   assert( id!=0 );
   UNUSED_PARAMETER(pVfs);
@@ -31166,7 +31733,8 @@ static int winOpen(
   ** temporary file name to use 
   */
   if( !zUtf8Name ){
-    int rc = getTempname(MAX_PATH+1, zTmpname);
+    assert(isDelete && !isOpenJournal);
+    rc = getTempname(MAX_PATH+1, zTmpname);
     if( rc!=SQLITE_OK ){
       return rc;
     }
@@ -31179,29 +31747,31 @@ static int winOpen(
     return SQLITE_NOMEM;
   }
 
-  if( flags & SQLITE_OPEN_READWRITE ){
+  if( isReadWrite ){
     dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
   }else{
     dwDesiredAccess = GENERIC_READ;
   }
+
   /* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is 
   ** created. SQLite doesn't use it to indicate "exclusive access" 
   ** as it is usually understood.
   */
-  assert(!(flags & SQLITE_OPEN_EXCLUSIVE) || (flags & SQLITE_OPEN_CREATE));
-  if( flags & SQLITE_OPEN_EXCLUSIVE ){
+  if( isExclusive ){
     /* Creates a new file, only if it does not already exist. */
     /* If the file exists, it fails. */
     dwCreationDisposition = CREATE_NEW;
-  }else if( flags & SQLITE_OPEN_CREATE ){
+  }else if( isCreate ){
     /* Open existing file, or create if it doesn't exist */
     dwCreationDisposition = OPEN_ALWAYS;
   }else{
     /* Opens a file, only if it exists. */
     dwCreationDisposition = OPEN_EXISTING;
   }
+
   dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
-  if( flags & SQLITE_OPEN_DELETEONCLOSE ){
+
+  if( isDelete ){
 #if SQLITE_OS_WINCE
     dwFlagsAndAttributes = FILE_ATTRIBUTE_HIDDEN;
     isTemp = 1;
@@ -31218,6 +31788,7 @@ static int winOpen(
 #if SQLITE_OS_WINCE
   dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS;
 #endif
+
   if( isNT() ){
     h = CreateFileW((WCHAR*)zConverted,
        dwDesiredAccess,
@@ -31243,26 +31814,30 @@ static int winOpen(
     );
 #endif
   }
+
   OSTRACE(("OPEN %d %s 0x%lx %s\n", 
            h, zName, dwDesiredAccess, 
            h==INVALID_HANDLE_VALUE ? "failed" : "ok"));
+
   if( h==INVALID_HANDLE_VALUE ){
     pFile->lastErrno = GetLastError();
     free(zConverted);
-    if( flags & SQLITE_OPEN_READWRITE ){
+    if( isReadWrite ){
       return winOpen(pVfs, zName, id, 
-             ((flags|SQLITE_OPEN_READONLY)&~SQLITE_OPEN_READWRITE), pOutFlags);
+             ((flags|SQLITE_OPEN_READONLY)&~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), pOutFlags);
     }else{
       return SQLITE_CANTOPEN_BKPT;
     }
   }
+
   if( pOutFlags ){
-    if( flags & SQLITE_OPEN_READWRITE ){
+    if( isReadWrite ){
       *pOutFlags = SQLITE_OPEN_READWRITE;
     }else{
       *pOutFlags = SQLITE_OPEN_READONLY;
     }
   }
+
   memset(pFile, 0, sizeof(*pFile));
   pFile->pMethod = &winIoMethod;
   pFile->h = h;
@@ -31271,9 +31846,9 @@ static int winOpen(
   pFile->pShm = 0;
   pFile->zPath = zName;
   pFile->sectorSize = getSectorSize(pVfs, zUtf8Name);
+
 #if SQLITE_OS_WINCE
-  if( (flags & (SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB)) ==
-               (SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB)
+  if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB
        && !winceCreateLock(zName, pFile)
   ){
     CloseHandle(h);
@@ -31287,8 +31862,9 @@ static int winOpen(
   {
     free(zConverted);
   }
+
   OpenCounter(+1);
-  return SQLITE_OK;
+  return rc;
 }
 
 /*
@@ -31807,6 +32383,13 @@ SQLITE_API int sqlite3_os_init(void){
     winCurrentTimeInt64, /* xCurrentTimeInt64 */
   };
 
+#ifndef SQLITE_OMIT_WAL
+  /* get memory map allocation granularity */
+  memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
+  GetSystemInfo(&winSysInfo);
+  assert(winSysInfo.dwAllocationGranularity > 0);
+#endif
+
   sqlite3_vfs_register(&winVfs, 1);
   return SQLITE_OK; 
 }
@@ -32371,12 +32954,16 @@ static void pcacheUnpin(PgHdr *p){
 */
 SQLITE_PRIVATE int sqlite3PcacheInitialize(void){
   if( sqlite3GlobalConfig.pcache.xInit==0 ){
+    /* IMPLEMENTATION-OF: R-26801-64137 If the xInit() method is NULL, then the
+    ** built-in default page cache is used instead of the application defined
+    ** page cache. */
     sqlite3PCacheSetDefault();
   }
   return sqlite3GlobalConfig.pcache.xInit(sqlite3GlobalConfig.pcache.pArg);
 }
 SQLITE_PRIVATE void sqlite3PcacheShutdown(void){
   if( sqlite3GlobalConfig.pcache.xShutdown ){
+    /* IMPLEMENTATION-OF: R-26000-56589 The xShutdown() method may be NULL. */
     sqlite3GlobalConfig.pcache.xShutdown(sqlite3GlobalConfig.pcache.pArg);
   }
 }
@@ -32836,24 +33423,62 @@ SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHd
 typedef struct PCache1 PCache1;
 typedef struct PgHdr1 PgHdr1;
 typedef struct PgFreeslot PgFreeslot;
+typedef struct PGroup PGroup;
 
-/* Pointers to structures of this type are cast and returned as 
-** opaque sqlite3_pcache* handles
+/* Each page cache (or PCache) belongs to a PGroup.  A PGroup is a set 
+** of one or more PCaches that are able to recycle each others unpinned
+** pages when they are under memory pressure.  A PGroup is an instance of
+** the following object.
+**
+** This page cache implementation works in one of two modes:
+**
+**   (1)  Every PCache is the sole member of its own PGroup.  There is
+**        one PGroup per PCache.
+**
+**   (2)  There is a single global PGroup that all PCaches are a member
+**        of.
+**
+** Mode 1 uses more memory (since PCache instances are not able to rob
+** unused pages from other PCaches) but it also operates without a mutex,
+** and is therefore often faster.  Mode 2 requires a mutex in order to be
+** threadsafe, but is able recycle pages more efficient.
+**
+** For mode (1), PGroup.mutex is NULL.  For mode (2) there is only a single
+** PGroup which is the pcache1.grp global variable and its mutex is
+** SQLITE_MUTEX_STATIC_LRU.
+*/
+struct PGroup {
+  sqlite3_mutex *mutex;          /* MUTEX_STATIC_LRU or NULL */
+  int nMaxPage;                  /* Sum of nMax for purgeable caches */
+  int nMinPage;                  /* Sum of nMin for purgeable caches */
+  int mxPinned;                  /* nMaxpage + 10 - nMinPage */
+  int nCurrentPage;              /* Number of purgeable pages allocated */
+  PgHdr1 *pLruHead, *pLruTail;   /* LRU list of unpinned pages */
+};
+
+/* Each page cache is an instance of the following object.  Every
+** open database file (including each in-memory database and each
+** temporary or transient database) has a single page cache which
+** is an instance of this object.
+**
+** Pointers to structures of this type are cast and returned as 
+** opaque sqlite3_pcache* handles.
 */
 struct PCache1 {
   /* Cache configuration parameters. Page size (szPage) and the purgeable
   ** flag (bPurgeable) are set when the cache is created. nMax may be 
   ** modified at any time by a call to the pcache1CacheSize() method.
-  ** The global mutex must be held when accessing nMax.
+  ** The PGroup mutex must be held when accessing nMax.
   */
+  PGroup *pGroup;                     /* PGroup this cache belongs to */
   int szPage;                         /* Size of allocated pages in bytes */
   int bPurgeable;                     /* True if cache is purgeable */
   unsigned int nMin;                  /* Minimum number of pages reserved */
   unsigned int nMax;                  /* Configured "cache_size" value */
+  unsigned int n90pct;                /* nMax*9/10 */
 
   /* Hash table of all pages. The following variables may only be accessed
-  ** when the accessor is holding the global mutex (see pcache1EnterMutex() 
-  ** and pcache1LeaveMutex()).
+  ** when the accessor is holding the PGroup mutex.
   */
   unsigned int nRecyclable;           /* Number of pages in the LRU list */
   unsigned int nPage;                 /* Total number of pages in apHash */
@@ -32889,18 +33514,27 @@ struct PgFreeslot {
 ** Global data used by this cache.
 */
 static SQLITE_WSD struct PCacheGlobal {
-  sqlite3_mutex *mutex;               /* static mutex MUTEX_STATIC_LRU */
-
-  int nMaxPage;                       /* Sum of nMaxPage for purgeable caches */
-  int nMinPage;                       /* Sum of nMinPage for purgeable caches */
-  int nCurrentPage;                   /* Number of purgeable pages allocated */
-  PgHdr1 *pLruHead, *pLruTail;        /* LRU list of unpinned pages */
-
-  /* Variables related to SQLITE_CONFIG_PAGECACHE settings. */
-  int szSlot;                         /* Size of each free slot */
-  void *pStart, *pEnd;                /* Bounds of pagecache malloc range */
-  PgFreeslot *pFree;                  /* Free page blocks */
-  int isInit;                         /* True if initialized */
+  PGroup grp;                    /* The global PGroup for mode (2) */
+
+  /* Variables related to SQLITE_CONFIG_PAGECACHE settings.  The
+  ** szSlot, nSlot, pStart, pEnd, nReserve, and isInit values are all
+  ** fixed at sqlite3_initialize() time and do not require mutex protection.
+  ** The nFreeSlot and pFree values do require mutex protection.
+  */
+  int isInit;                    /* True if initialized */
+  int szSlot;                    /* Size of each free slot */
+  int nSlot;                     /* The number of pcache slots */
+  int nReserve;                  /* Try to keep nFreeSlot above this */
+  void *pStart, *pEnd;           /* Bounds of pagecache malloc range */
+  /* Above requires no mutex.  Use mutex below for variable that follow. */
+  sqlite3_mutex *mutex;          /* Mutex for accessing the following: */
+  int nFreeSlot;                 /* Number of unused pcache slots */
+  PgFreeslot *pFree;             /* Free page blocks */
+  /* The following value requires a mutex to change.  We skip the mutex on
+  ** reading because (1) most platforms read a 32-bit integer atomically and
+  ** (2) even if an incorrect value is read, no great harm is done since this
+  ** is really just an optimization. */
+  int bUnderPressure;            /* True if low on PAGECACHE memory */
 } pcache1_g;
 
 /*
@@ -32926,10 +33560,10 @@ static SQLITE_WSD struct PCacheGlobal {
 #define PAGE_TO_PGHDR1(c, p) (PgHdr1*)(((char*)p) + c->szPage)
 
 /*
-** Macros to enter and leave the global LRU mutex.
+** Macros to enter and leave the PCache LRU mutex.
 */
-#define pcache1EnterMutex() sqlite3_mutex_enter(pcache1.mutex)
-#define pcache1LeaveMutex() sqlite3_mutex_leave(pcache1.mutex)
+#define pcache1EnterMutex(X) sqlite3_mutex_enter((X)->mutex)
+#define pcache1LeaveMutex(X) sqlite3_mutex_leave((X)->mutex)
 
 /******************************************************************************/
 /******** Page Allocation/SQLITE_CONFIG_PCACHE Related Functions **************/
@@ -32939,14 +33573,20 @@ static SQLITE_WSD struct PCacheGlobal {
 ** supplied to use for the page-cache by passing the SQLITE_CONFIG_PAGECACHE
 ** verb to sqlite3_config(). Parameter pBuf points to an allocation large
 ** enough to contain 'n' buffers of 'sz' bytes each.
+**
+** This routine is called from sqlite3_initialize() and so it is guaranteed
+** to be serialized already.  There is no need for further mutexing.
 */
 SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
   if( pcache1.isInit ){
     PgFreeslot *p;
     sz = ROUNDDOWN8(sz);
     pcache1.szSlot = sz;
+    pcache1.nSlot = pcache1.nFreeSlot = n;
+    pcache1.nReserve = n>90 ? 10 : (n/10 + 1);
     pcache1.pStart = pBuf;
     pcache1.pFree = 0;
+    pcache1.bUnderPressure = 0;
     while( n-- ){
       p = (PgFreeslot*)pBuf;
       p->pNext = pcache1.pFree;
@@ -32962,30 +33602,36 @@ SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
 ** configured using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no 
 ** such buffer exists or there is no space left in it, this function falls 
 ** back to sqlite3Malloc().
+**
+** Multiple threads can run this routine at the same time.  Global variables
+** in pcache1 need to be protected via mutex.
 */
 static void *pcache1Alloc(int nByte){
-  void *p;
-  assert( sqlite3_mutex_held(pcache1.mutex) );
+  void *p = 0;
+  assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
   sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
-  if( nByte<=pcache1.szSlot && pcache1.pFree ){
-    assert( pcache1.isInit );
+  if( nByte<=pcache1.szSlot ){
+    sqlite3_mutex_enter(pcache1.mutex);
     p = (PgHdr1 *)pcache1.pFree;
-    pcache1.pFree = pcache1.pFree->pNext;
-    sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, 1);
-  }else{
-
-    /* Allocate a new buffer using sqlite3Malloc. Before doing so, exit the
-    ** global pcache mutex and unlock the pager-cache object pCache. This is 
-    ** so that if the attempt to allocate a new buffer causes the the 
-    ** configured soft-heap-limit to be breached, it will be possible to
-    ** reclaim memory from this pager-cache.
+    if( p ){
+      pcache1.pFree = pcache1.pFree->pNext;
+      pcache1.nFreeSlot--;
+      pcache1.bUnderPressure = pcache1.nFreeSlot<pcache1.nReserve;
+      assert( pcache1.nFreeSlot>=0 );
+      sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, 1);
+    }
+    sqlite3_mutex_leave(pcache1.mutex);
+  }
+  if( p==0 ){
+    /* Memory is not available in the SQLITE_CONFIG_PAGECACHE pool.  Get
+    ** it from sqlite3Malloc instead.
     */
-    pcache1LeaveMutex();
     p = sqlite3Malloc(nByte);
-    pcache1EnterMutex();
     if( p ){
       int sz = sqlite3MallocSize(p);
+      sqlite3_mutex_enter(pcache1.mutex);
       sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);
+      sqlite3_mutex_leave(pcache1.mutex);
     }
     sqlite3MemdebugSetType(p, MEMTYPE_PCACHE);
   }
@@ -32996,30 +33642,35 @@ static void *pcache1Alloc(int nByte){
 ** Free an allocated buffer obtained from pcache1Alloc().
 */
 static void pcache1Free(void *p){
-  assert( sqlite3_mutex_held(pcache1.mutex) );
   if( p==0 ) return;
   if( p>=pcache1.pStart && p<pcache1.pEnd ){
     PgFreeslot *pSlot;
+    sqlite3_mutex_enter(pcache1.mutex);
     sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, -1);
     pSlot = (PgFreeslot*)p;
     pSlot->pNext = pcache1.pFree;
     pcache1.pFree = pSlot;
+    pcache1.nFreeSlot++;
+    pcache1.bUnderPressure = pcache1.nFreeSlot<pcache1.nReserve;
+    assert( pcache1.nFreeSlot<=pcache1.nSlot );
+    sqlite3_mutex_leave(pcache1.mutex);
   }else{
     int iSize;
     assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
     sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
     iSize = sqlite3MallocSize(p);
+    sqlite3_mutex_enter(pcache1.mutex);
     sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -iSize);
+    sqlite3_mutex_leave(pcache1.mutex);
     sqlite3_free(p);
   }
 }
 
 #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
 /*
-** Return the size of a pache allocation
+** Return the size of a pcache allocation
 */
 static int pcache1MemSize(void *p){
-  assert( sqlite3_mutex_held(pcache1.mutex) );
   if( p>=pcache1.pStart && p<pcache1.pEnd ){
     return pcache1.szSlot;
   }else{
@@ -33043,7 +33694,7 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
   if( pPg ){
     p = PAGE_TO_PGHDR1(pCache, pPg);
     if( pCache->bPurgeable ){
-      pcache1.nCurrentPage++;
+      pCache->pGroup->nCurrentPage++;
     }
   }else{
     p = 0;
@@ -33060,8 +33711,9 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
 */
 static void pcache1FreePage(PgHdr1 *p){
   if( ALWAYS(p) ){
-    if( p->pCache->bPurgeable ){
-      pcache1.nCurrentPage--;
+    PCache1 *pCache = p->pCache;
+    if( pCache->bPurgeable ){
+      pCache->pGroup->nCurrentPage--;
     }
     pcache1Free(PGHDR1_TO_PAGE(p));
   }
@@ -33073,20 +33725,39 @@ static void pcache1FreePage(PgHdr1 *p){
 ** exists, this function falls back to sqlite3Malloc().
 */
 SQLITE_PRIVATE void *sqlite3PageMalloc(int sz){
-  void *p;
-  pcache1EnterMutex();
-  p = pcache1Alloc(sz);
-  pcache1LeaveMutex();
-  return p;
+  return pcache1Alloc(sz);
 }
 
 /*
 ** Free an allocated buffer obtained from sqlite3PageMalloc().
 */
 SQLITE_PRIVATE void sqlite3PageFree(void *p){
-  pcache1EnterMutex();
   pcache1Free(p);
-  pcache1LeaveMutex();
+}
+
+
+/*
+** Return true if it desirable to avoid allocating a new page cache
+** entry.
+**
+** If memory was allocated specifically to the page cache using
+** SQLITE_CONFIG_PAGECACHE but that memory has all been used, then
+** it is desirable to avoid allocating a new page cache entry because
+** presumably SQLITE_CONFIG_PAGECACHE was suppose to be sufficient
+** for all page cache needs and we should not need to spill the
+** allocation onto the heap.
+**
+** Or, the heap is used for all page cache memory put the heap is
+** under memory pressure, then again it is desirable to avoid
+** allocating a new page cache entry in order to avoid stressing
+** the heap even further.
+*/
+static int pcache1UnderMemoryPressure(PCache1 *pCache){
+  if( pcache1.nSlot && pCache->szPage<=pcache1.szSlot ){
+    return pcache1.bUnderPressure;
+  }else{
+    return sqlite3HeapNearlyFull();
+  }
 }
 
 /******************************************************************************/
@@ -33096,25 +33767,25 @@ SQLITE_PRIVATE void sqlite3PageFree(void *p){
 ** This function is used to resize the hash table used by the cache passed
 ** as the first argument.
 **
-** The global mutex must be held when this function is called.
+** The PCache mutex must be held when this function is called.
 */
 static int pcache1ResizeHash(PCache1 *p){
   PgHdr1 **apNew;
   unsigned int nNew;
   unsigned int i;
 
-  assert( sqlite3_mutex_held(pcache1.mutex) );
+  assert( sqlite3_mutex_held(p->pGroup->mutex) );
 
   nNew = p->nHash*2;
   if( nNew<256 ){
     nNew = 256;
   }
 
-  pcache1LeaveMutex();
+  pcache1LeaveMutex(p->pGroup);
   if( p->nHash ){ sqlite3BeginBenignMalloc(); }
   apNew = (PgHdr1 **)sqlite3_malloc(sizeof(PgHdr1 *)*nNew);
   if( p->nHash ){ sqlite3EndBenignMalloc(); }
-  pcache1EnterMutex();
+  pcache1EnterMutex(p->pGroup);
   if( apNew ){
     memset(apNew, 0, sizeof(PgHdr1 *)*nNew);
     for(i=0; i<p->nHash; i++){
@@ -33137,25 +33808,33 @@ static int pcache1ResizeHash(PCache1 *p){
 
 /*
 ** This function is used internally to remove the page pPage from the 
-** global LRU list, if is part of it. If pPage is not part of the global
+** PGroup LRU list, if is part of it. If pPage is not part of the PGroup
 ** LRU list, then this function is a no-op.
 **
-** The global mutex must be held when this function is called.
+** The PGroup mutex must be held when this function is called.
+**
+** If pPage is NULL then this routine is a no-op.
 */
 static void pcache1PinPage(PgHdr1 *pPage){
-  assert( sqlite3_mutex_held(pcache1.mutex) );
-  if( pPage && (pPage->pLruNext || pPage==pcache1.pLruTail) ){
+  PCache1 *pCache;
+  PGroup *pGroup;
+
+  if( pPage==0 ) return;
+  pCache = pPage->pCache;
+  pGroup = pCache->pGroup;
+  assert( sqlite3_mutex_held(pGroup->mutex) );
+  if( pPage->pLruNext || pPage==pGroup->pLruTail ){
     if( pPage->pLruPrev ){
       pPage->pLruPrev->pLruNext = pPage->pLruNext;
     }
     if( pPage->pLruNext ){
       pPage->pLruNext->pLruPrev = pPage->pLruPrev;
     }
-    if( pcache1.pLruHead==pPage ){
-      pcache1.pLruHead = pPage->pLruNext;
+    if( pGroup->pLruHead==pPage ){
+      pGroup->pLruHead = pPage->pLruNext;
     }
-    if( pcache1.pLruTail==pPage ){
-      pcache1.pLruTail = pPage->pLruPrev;
+    if( pGroup->pLruTail==pPage ){
+      pGroup->pLruTail = pPage->pLruPrev;
     }
     pPage->pLruNext = 0;
     pPage->pLruPrev = 0;
@@ -33168,13 +33847,14 @@ static void pcache1PinPage(PgHdr1 *pPage){
 ** Remove the page supplied as an argument from the hash table 
 ** (PCache1.apHash structure) that it is currently stored in.
 **
-** The global mutex must be held when this function is called.
+** The PGroup mutex must be held when this function is called.
 */
 static void pcache1RemoveFromHash(PgHdr1 *pPage){
   unsigned int h;
   PCache1 *pCache = pPage->pCache;
   PgHdr1 **pp;
 
+  assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
   h = pPage->iKey % pCache->nHash;
   for(pp=&pCache->apHash[h]; (*pp)!=pPage; pp=&(*pp)->pNext);
   *pp = (*pp)->pNext;
@@ -33183,13 +33863,14 @@ static void pcache1RemoveFromHash(PgHdr1 *pPage){
 }
 
 /*
-** If there are currently more than pcache.nMaxPage pages allocated, try
-** to recycle pages to reduce the number allocated to pcache.nMaxPage.
+** If there are currently more than nMaxPage pages allocated, try
+** to recycle pages to reduce the number allocated to nMaxPage.
 */
-static void pcache1EnforceMaxPage(void){
-  assert( sqlite3_mutex_held(pcache1.mutex) );
-  while( pcache1.nCurrentPage>pcache1.nMaxPage && pcache1.pLruTail ){
-    PgHdr1 *p = pcache1.pLruTail;
+static void pcache1EnforceMaxPage(PGroup *pGroup){
+  assert( sqlite3_mutex_held(pGroup->mutex) );
+  while( pGroup->nCurrentPage>pGroup->nMaxPage && pGroup->pLruTail ){
+    PgHdr1 *p = pGroup->pLruTail;
+    assert( p->pCache->pGroup==pGroup );
     pcache1PinPage(p);
     pcache1RemoveFromHash(p);
     pcache1FreePage(p);
@@ -33201,15 +33882,15 @@ static void pcache1EnforceMaxPage(void){
 ** greater than or equal to iLimit. Any pinned pages that meet this 
 ** criteria are unpinned before they are discarded.
 **
-** The global mutex must be held when this function is called.
+** The PCache mutex must be held when this function is called.
 */
 static void pcache1TruncateUnsafe(
-  PCache1 *pCache, 
-  unsigned int iLimit 
+  PCache1 *pCache,             /* The cache to truncate */
+  unsigned int iLimit          /* Drop pages with this pgno or larger */
 ){
-  TESTONLY( unsigned int nPage = 0; )      /* Used to assert pCache->nPage is correct */
+  TESTONLY( unsigned int nPage = 0; )  /* To assert pCache->nPage is correct */
   unsigned int h;
-  assert( sqlite3_mutex_held(pcache1.mutex) );
+  assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
   for(h=0; h<pCache->nHash; h++){
     PgHdr1 **pp = &pCache->apHash[h]; 
     PgHdr1 *pPage;
@@ -33239,8 +33920,10 @@ static int pcache1Init(void *NotUsed){
   assert( pcache1.isInit==0 );
   memset(&pcache1, 0, sizeof(pcache1));
   if( sqlite3GlobalConfig.bCoreMutex ){
-    pcache1.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU);
+    pcache1.grp.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU);
+    pcache1.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PMEM);
   }
+  pcache1.grp.mxPinned = 10;
   pcache1.isInit = 1;
   return SQLITE_OK;
 }
@@ -33262,18 +33945,47 @@ static void pcache1Shutdown(void *NotUsed){
 ** Allocate a new cache.
 */
 static sqlite3_pcache *pcache1Create(int szPage, int bPurgeable){
-  PCache1 *pCache;
+  PCache1 *pCache;      /* The newly created page cache */
+  PGroup *pGroup;       /* The group the new page cache will belong to */
+  int sz;               /* Bytes of memory required to allocate the new cache */
+
+  /*
+  ** The seperateCache variable is true if each PCache has its own private
+  ** PGroup.  In other words, separateCache is true for mode (1) where no
+  ** mutexing is required.
+  **
+  **   *  Always use a unified cache (mode-2) if ENABLE_MEMORY_MANAGEMENT
+  **
+  **   *  Always use a unified cache in single-threaded applications
+  **
+  **   *  Otherwise (if multi-threaded and ENABLE_MEMORY_MANAGEMENT is off)
+  **      use separate caches (mode-1)
+  */
+#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) || SQLITE_THREADSAFE==0
+  const int separateCache = 0;
+#else
+  int separateCache = sqlite3GlobalConfig.bCoreMutex>0;
+#endif
 
-  pCache = (PCache1 *)sqlite3_malloc(sizeof(PCache1));
+  sz = sizeof(PCache1) + sizeof(PGroup)*separateCache;
+  pCache = (PCache1 *)sqlite3_malloc(sz);
   if( pCache ){
-    memset(pCache, 0, sizeof(PCache1));
+    memset(pCache, 0, sz);
+    if( separateCache ){
+      pGroup = (PGroup*)&pCache[1];
+      pGroup->mxPinned = 10;
+    }else{
+      pGroup = &pcache1_g.grp;
+    }
+    pCache->pGroup = pGroup;
     pCache->szPage = szPage;
     pCache->bPurgeable = (bPurgeable ? 1 : 0);
     if( bPurgeable ){
       pCache->nMin = 10;
-      pcache1EnterMutex();
-      pcache1.nMinPage += pCache->nMin;
-      pcache1LeaveMutex();
+      pcache1EnterMutex(pGroup);
+      pGroup->nMinPage += pCache->nMin;
+      pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
+      pcache1LeaveMutex(pGroup);
     }
   }
   return (sqlite3_pcache *)pCache;
@@ -33287,11 +33999,14 @@ static sqlite3_pcache *pcache1Create(int szPage, int bPurgeable){
 static void pcache1Cachesize(sqlite3_pcache *p, int nMax){
   PCache1 *pCache = (PCache1 *)p;
   if( pCache->bPurgeable ){
-    pcache1EnterMutex();
-    pcache1.nMaxPage += (nMax - pCache->nMax);
+    PGroup *pGroup = pCache->pGroup;
+    pcache1EnterMutex(pGroup);
+    pGroup->nMaxPage += (nMax - pCache->nMax);
+    pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
     pCache->nMax = nMax;
-    pcache1EnforceMaxPage();
-    pcache1LeaveMutex();
+    pCache->n90pct = pCache->nMax*9/10;
+    pcache1EnforceMaxPage(pGroup);
+    pcache1LeaveMutex(pGroup);
   }
 }
 
@@ -33300,9 +34015,10 @@ static void pcache1Cachesize(sqlite3_pcache *p, int nMax){
 */
 static int pcache1Pagecount(sqlite3_pcache *p){
   int n;
-  pcache1EnterMutex();
-  n = ((PCache1 *)p)->nPage;
-  pcache1LeaveMutex();
+  PCache1 *pCache = (PCache1*)p;
+  pcache1EnterMutex(pCache->pGroup);
+  n = pCache->nPage;
+  pcache1LeaveMutex(pCache->pGroup);
   return n;
 }
 
@@ -33330,14 +34046,16 @@ static int pcache1Pagecount(sqlite3_pcache *p){
 **   2. If createFlag==0 and the page is not already in the cache, NULL is
 **      returned.
 **
-**   3. If createFlag is 1, and the page is not already in the cache,
-**      and if either of the following are true, return NULL:
+**   3. If createFlag is 1, and the page is not already in the cache, then
+**      return NULL (do not allocate a new page) if any of the following
+**      conditions are true:
 **
 **       (a) the number of pages pinned by the cache is greater than
 **           PCache1.nMax, or
+**
 **       (b) the number of pages pinned by the cache is greater than
 **           the sum of nMax for all purgeable caches, less the sum of 
-**           nMin for all other purgeable caches. 
+**           nMin for all other purgeable caches, or
 **
 **   4. If none of the first three conditions apply and the cache is marked
 **      as purgeable, and if one of the following is true:
@@ -33349,6 +34067,9 @@ static int pcache1Pagecount(sqlite3_pcache *p){
 **           already equal to or greater than the sum of nMax for all
 **           purgeable caches,
 **
+**       (c) The system is under memory pressure and wants to avoid
+**           unnecessary pages cache entry allocations
+**
 **      then attempt to recycle a page from the LRU list. If it is the right
 **      size, return the recycled buffer. Otherwise, free the buffer and
 **      proceed to step 5. 
@@ -33356,30 +34077,50 @@ static int pcache1Pagecount(sqlite3_pcache *p){
 **   5. Otherwise, allocate and return a new page buffer.
 */
 static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){
-  unsigned int nPinned;
+  int nPinned;
   PCache1 *pCache = (PCache1 *)p;
+  PGroup *pGroup;
   PgHdr1 *pPage = 0;
 
   assert( pCache->bPurgeable || createFlag!=1 );
-  pcache1EnterMutex();
-  if( createFlag==1 ) sqlite3BeginBenignMalloc();
+  assert( pCache->bPurgeable || pCache->nMin==0 );
+  assert( pCache->bPurgeable==0 || pCache->nMin==10 );
+  assert( pCache->nMin==0 || pCache->bPurgeable );
+  pcache1EnterMutex(pGroup = pCache->pGroup);
 
-  /* Search the hash table for an existing entry. */
+  /* Step 1: Search the hash table for an existing entry. */
   if( pCache->nHash>0 ){
     unsigned int h = iKey % pCache->nHash;
     for(pPage=pCache->apHash[h]; pPage&&pPage->iKey!=iKey; pPage=pPage->pNext);
   }
 
+  /* Step 2: Abort if no existing page is found and createFlag is 0 */
   if( pPage || createFlag==0 ){
     pcache1PinPage(pPage);
     goto fetch_out;
   }
 
-  /* Step 3 of header comment. */
+  /* The pGroup local variable will normally be initialized by the
+  ** pcache1EnterMutex() macro above.  But if SQLITE_MUTEX_OMIT is defined,
+  ** then pcache1EnterMutex() is a no-op, so we have to initialize the
+  ** local variable here.  Delaying the initialization of pGroup is an
+  ** optimization:  The common case is to exit the module before reaching
+  ** this point.
+  */
+#ifdef SQLITE_MUTEX_OMIT
+  pGroup = pCache->pGroup;
+#endif
+
+
+  /* Step 3: Abort if createFlag is 1 but the cache is nearly full */
   nPinned = pCache->nPage - pCache->nRecyclable;
+  assert( nPinned>=0 );
+  assert( pGroup->mxPinned == pGroup->nMaxPage + 10 - pGroup->nMinPage );
+  assert( pCache->n90pct == pCache->nMax*9/10 );
   if( createFlag==1 && (
-        nPinned>=(pcache1.nMaxPage+pCache->nMin-pcache1.nMinPage)
-     || nPinned>=(pCache->nMax * 9 / 10)
+        nPinned>=pGroup->mxPinned
+     || nPinned>=(int)pCache->n90pct
+     || pcache1UnderMemoryPressure(pCache)
   )){
     goto fetch_out;
   }
@@ -33388,18 +34129,22 @@ static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){
     goto fetch_out;
   }
 
-  /* Step 4. Try to recycle a page buffer if appropriate. */
-  if( pCache->bPurgeable && pcache1.pLruTail && (
-     (pCache->nPage+1>=pCache->nMax) || pcache1.nCurrentPage>=pcache1.nMaxPage
+  /* Step 4. Try to recycle a page. */
+  if( pCache->bPurgeable && pGroup->pLruTail && (
+         (pCache->nPage+1>=pCache->nMax)
+      || pGroup->nCurrentPage>=pGroup->nMaxPage
+      || pcache1UnderMemoryPressure(pCache)
   )){
-    pPage = pcache1.pLruTail;
+    PCache1 *pOtherCache;
+    pPage = pGroup->pLruTail;
     pcache1RemoveFromHash(pPage);
     pcache1PinPage(pPage);
-    if( pPage->pCache->szPage!=pCache->szPage ){
+    if( (pOtherCache = pPage->pCache)->szPage!=pCache->szPage ){
       pcache1FreePage(pPage);
       pPage = 0;
     }else{
-      pcache1.nCurrentPage -= (pPage->pCache->bPurgeable - pCache->bPurgeable);
+      pGroup->nCurrentPage -= 
+               (pOtherCache->bPurgeable - pCache->bPurgeable);
     }
   }
 
@@ -33407,7 +34152,11 @@ static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){
   ** attempt to allocate a new one. 
   */
   if( !pPage ){
+    if( createFlag==1 ) sqlite3BeginBenignMalloc();
+    pcache1LeaveMutex(pGroup);
     pPage = pcache1AllocPage(pCache);
+    pcache1EnterMutex(pGroup);
+    if( createFlag==1 ) sqlite3EndBenignMalloc();
   }
 
   if( pPage ){
@@ -33426,8 +34175,7 @@ fetch_out:
   if( pPage && iKey>pCache->iMaxKey ){
     pCache->iMaxKey = iKey;
   }
-  if( createFlag==1 ) sqlite3EndBenignMalloc();
-  pcache1LeaveMutex();
+  pcache1LeaveMutex(pGroup);
   return (pPage ? PGHDR1_TO_PAGE(pPage) : 0);
 }
 
@@ -33440,37 +34188,34 @@ fetch_out:
 static void pcache1Unpin(sqlite3_pcache *p, void *pPg, int reuseUnlikely){
   PCache1 *pCache = (PCache1 *)p;
   PgHdr1 *pPage = PAGE_TO_PGHDR1(pCache, pPg);
+  PGroup *pGroup = pCache->pGroup;
  
   assert( pPage->pCache==pCache );
-  pcache1EnterMutex();
+  pcache1EnterMutex(pGroup);
 
   /* It is an error to call this function if the page is already 
-  ** part of the global LRU list.
+  ** part of the PGroup LRU list.
   */
   assert( pPage->pLruPrev==0 && pPage->pLruNext==0 );
-  assert( pcache1.pLruHead!=pPage && pcache1.pLruTail!=pPage );
+  assert( pGroup->pLruHead!=pPage && pGroup->pLruTail!=pPage );
 
-  if( reuseUnlikely || pcache1.nCurrentPage>pcache1.nMaxPage ){
+  if( reuseUnlikely || pGroup->nCurrentPage>pGroup->nMaxPage ){
     pcache1RemoveFromHash(pPage);
     pcache1FreePage(pPage);
   }else{
-    /* Add the page to the global LRU list. Normally, the page is added to
-    ** the head of the list (last page to be recycled). However, if the 
-    ** reuseUnlikely flag passed to this function is true, the page is added
-    ** to the tail of the list (first page to be recycled).
-    */
-    if( pcache1.pLruHead ){
-      pcache1.pLruHead->pLruPrev = pPage;
-      pPage->pLruNext = pcache1.pLruHead;
-      pcache1.pLruHead = pPage;
+    /* Add the page to the PGroup LRU list. */
+    if( pGroup->pLruHead ){
+      pGroup->pLruHead->pLruPrev = pPage;
+      pPage->pLruNext = pGroup->pLruHead;
+      pGroup->pLruHead = pPage;
     }else{
-      pcache1.pLruTail = pPage;
-      pcache1.pLruHead = pPage;
+      pGroup->pLruTail = pPage;
+      pGroup->pLruHead = pPage;
     }
     pCache->nRecyclable++;
   }
 
-  pcache1LeaveMutex();
+  pcache1LeaveMutex(pCache->pGroup);
 }
 
 /*
@@ -33489,7 +34234,7 @@ static void pcache1Rekey(
   assert( pPage->iKey==iOld );
   assert( pPage->pCache==pCache );
 
-  pcache1EnterMutex();
+  pcache1EnterMutex(pCache->pGroup);
 
   h = iOld%pCache->nHash;
   pp = &pCache->apHash[h];
@@ -33506,7 +34251,7 @@ static void pcache1Rekey(
     pCache->iMaxKey = iNew;
   }
 
-  pcache1LeaveMutex();
+  pcache1LeaveMutex(pCache->pGroup);
 }
 
 /*
@@ -33518,12 +34263,12 @@ static void pcache1Rekey(
 */
 static void pcache1Truncate(sqlite3_pcache *p, unsigned int iLimit){
   PCache1 *pCache = (PCache1 *)p;
-  pcache1EnterMutex();
+  pcache1EnterMutex(pCache->pGroup);
   if( iLimit<=pCache->iMaxKey ){
     pcache1TruncateUnsafe(pCache, iLimit);
     pCache->iMaxKey = iLimit-1;
   }
-  pcache1LeaveMutex();
+  pcache1LeaveMutex(pCache->pGroup);
 }
 
 /*
@@ -33533,12 +34278,15 @@ static void pcache1Truncate(sqlite3_pcache *p, unsigned int iLimit){
 */
 static void pcache1Destroy(sqlite3_pcache *p){
   PCache1 *pCache = (PCache1 *)p;
-  pcache1EnterMutex();
+  PGroup *pGroup = pCache->pGroup;
+  assert( pCache->bPurgeable || (pCache->nMax==0 && pCache->nMin==0) );
+  pcache1EnterMutex(pGroup);
   pcache1TruncateUnsafe(pCache, 0);
-  pcache1.nMaxPage -= pCache->nMax;
-  pcache1.nMinPage -= pCache->nMin;
-  pcache1EnforceMaxPage();
-  pcache1LeaveMutex();
+  pGroup->nMaxPage -= pCache->nMax;
+  pGroup->nMinPage -= pCache->nMin;
+  pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
+  pcache1EnforceMaxPage(pGroup);
+  pcache1LeaveMutex(pGroup);
   sqlite3_free(pCache->apHash);
   sqlite3_free(pCache);
 }
@@ -33577,16 +34325,18 @@ SQLITE_PRIVATE void sqlite3PCacheSetDefault(void){
 */
 SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){
   int nFree = 0;
+  assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
+  assert( sqlite3_mutex_notheld(pcache1.mutex) );
   if( pcache1.pStart==0 ){
     PgHdr1 *p;
-    pcache1EnterMutex();
-    while( (nReq<0 || nFree<nReq) && (p=pcache1.pLruTail) ){
+    pcache1EnterMutex(&pcache1.grp);
+    while( (nReq<0 || nFree<nReq) && ((p=pcache1.grp.pLruTail)!=0) ){
       nFree += pcache1MemSize(PGHDR1_TO_PAGE(p));
       pcache1PinPage(p);
       pcache1RemoveFromHash(p);
       pcache1FreePage(p);
     }
-    pcache1LeaveMutex();
+    pcache1LeaveMutex(&pcache1.grp);
   }
   return nFree;
 }
@@ -33605,12 +34355,12 @@ SQLITE_PRIVATE void sqlite3PcacheStats(
 ){
   PgHdr1 *p;
   int nRecyclable = 0;
-  for(p=pcache1.pLruHead; p; p=p->pLruNext){
+  for(p=pcache1.grp.pLruHead; p; p=p->pLruNext){
     nRecyclable++;
   }
-  *pnCurrent = pcache1.nCurrentPage;
-  *pnMax = pcache1.nMaxPage;
-  *pnMin = pcache1.nMinPage;
+  *pnCurrent = pcache1.grp.nCurrentPage;
+  *pnMax = pcache1.grp.nMaxPage;
+  *pnMin = pcache1.grp.nMinPage;
   *pnRecyclable = nRecyclable;
 }
 #endif
@@ -34100,6 +34850,7 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, u8 iBatch, sqlite3_int64 i
 # define sqlite3WalCheckpoint(u,v,w,x)         0
 # define sqlite3WalCallback(z)                 0
 # define sqlite3WalExclusiveMode(y,z)          0
+# define sqlite3WalHeapMemory(z)               0
 #else
 
 #define WAL_SAVEPOINT_NDATA 4
@@ -34110,7 +34861,7 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, u8 iBatch, sqlite3_int64 i
 typedef struct Wal Wal;
 
 /* Open and close a connection to a write-ahead log. */
-SQLITE_PRIVATE int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *zName, Wal**);
+SQLITE_PRIVATE int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *zName, int, Wal**);
 SQLITE_PRIVATE int sqlite3WalClose(Wal *pWal, int sync_flags, int, u8 *);
 
 /* Used by readers to open (lock) and close (unlock) a snapshot.  A 
@@ -34167,6 +34918,12 @@ SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal);
 */
 SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op);
 
+/* Return true if the argument is non-NULL and the WAL module is using
+** heap-memory for the wal-index. Otherwise, if the argument is NULL or the
+** WAL module is using shared-memory, return false. 
+*/
+SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal);
+
 #endif /* ifndef SQLITE_OMIT_WAL */
 #endif /* _WAL_H_ */
 
@@ -34766,7 +35523,8 @@ struct Pager {
   u8 noReadlock;              /* Do not bother to obtain readlocks */
   u8 noSync;                  /* Do not sync the journal if true */
   u8 fullSync;                /* Do extra syncs of the journal for robustness */
-  u8 sync_flags;              /* One of SYNC_NORMAL or SYNC_FULL */
+  u8 ckptSyncFlags;           /* SYNC_NORMAL or SYNC_FULL for checkpoint */
+  u8 syncFlags;               /* SYNC_NORMAL or SYNC_FULL otherwise */
   u8 tempFile;                /* zFilename is a temporary file */
   u8 readOnly;                /* True for a read-only database */
   u8 memDb;                   /* True to inhibit all file I/O */
@@ -35077,7 +35835,9 @@ static int assert_pager_state(Pager *p){
 
   return 1;
 }
+#endif /* ifndef NDEBUG */
 
+#ifdef SQLITE_DEBUG 
 /*
 ** Return a pointer to a human readable string in a static buffer
 ** containing the state of the Pager object passed as an argument. This
@@ -35201,7 +35961,7 @@ static int write32bits(sqlite3_file *fd, i64 offset, u32 val){
 static int pagerUnlockDb(Pager *pPager, int eLock){
   int rc = SQLITE_OK;
 
-  assert( !pPager->exclusiveMode );
+  assert( !pPager->exclusiveMode || pPager->eLock==eLock );
   assert( eLock==NO_LOCK || eLock==SHARED_LOCK );
   assert( eLock!=NO_LOCK || pagerUseWal(pPager)==0 );
   if( isOpen(pPager->fd) ){
@@ -35448,7 +36208,7 @@ static int zeroJournalHdr(Pager *pPager, int doTruncate){
       rc = sqlite3OsWrite(pPager->jfd, zeroHdr, sizeof(zeroHdr), 0);
     }
     if( rc==SQLITE_OK && !pPager->noSync ){
-      rc = sqlite3OsSync(pPager->jfd, SQLITE_SYNC_DATAONLY|pPager->sync_flags);
+      rc = sqlite3OsSync(pPager->jfd, SQLITE_SYNC_DATAONLY|pPager->syncFlags);
     }
 
     /* At this point the transaction is committed but the write lock 
@@ -36625,15 +37385,21 @@ static int pager_truncate(Pager *pPager, Pgno nPage){
    && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN) 
   ){
     i64 currentSize, newSize;
+    int szPage = pPager->pageSize;
     assert( pPager->eLock==EXCLUSIVE_LOCK );
     /* TODO: Is it safe to use Pager.dbFileSize here? */
     rc = sqlite3OsFileSize(pPager->fd, &currentSize);
-    newSize = pPager->pageSize*(i64)nPage;
+    newSize = szPage*(i64)nPage;
     if( rc==SQLITE_OK && currentSize!=newSize ){
       if( currentSize>newSize ){
         rc = sqlite3OsTruncate(pPager->fd, newSize);
       }else{
-        rc = sqlite3OsWrite(pPager->fd, "", 1, newSize-1);
+        char *pTmp = pPager->pTmpSpace;
+        memset(pTmp, 0, szPage);
+        testcase( (newSize-szPage) <  currentSize );
+        testcase( (newSize-szPage) == currentSize );
+        testcase( (newSize-szPage) >  currentSize );
+        rc = sqlite3OsWrite(pPager->fd, pTmp, szPage, newSize-szPage);
       }
       if( rc==SQLITE_OK ){
         pPager->dbFileSize = nPage;
@@ -36897,10 +37663,10 @@ end_playback:
     rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1);
     testcase( rc!=SQLITE_OK );
   }
-  if( rc==SQLITE_OK && !pPager->noSync 
+  if( rc==SQLITE_OK
    && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
   ){
-    rc = sqlite3OsSync(pPager->fd, pPager->sync_flags);
+    rc = sqlite3PagerSync(pPager);
   }
   if( rc==SQLITE_OK ){
     rc = pager_end_transaction(pPager, zMaster[0]!='\0');
@@ -37063,24 +37829,61 @@ static int pagerRollbackWal(Pager *pPager){
   return rc;
 }
 
+
+/*
+** Update the value of the change-counter at offsets 24 and 92 in
+** the header and the sqlite version number at offset 96.
+**
+** This is an unconditional update.  See also the pager_incr_changecounter()
+** routine which only updates the change-counter if the update is actually
+** needed, as determined by the pPager->changeCountDone state variable.
+*/
+static void pager_write_changecounter(PgHdr *pPg){
+  u32 change_counter;
+
+  /* Increment the value just read and write it back to byte 24. */
+  change_counter = sqlite3Get4byte((u8*)pPg->pPager->dbFileVers)+1;
+  put32bits(((char*)pPg->pData)+24, change_counter);
+
+  /* Also store the SQLite version number in bytes 96..99 and in
+  ** bytes 92..95 store the change counter for which the version number
+  ** is valid. */
+  put32bits(((char*)pPg->pData)+92, change_counter);
+  put32bits(((char*)pPg->pData)+96, SQLITE_VERSION_NUMBER);
+}
+
 /*
 ** This function is a wrapper around sqlite3WalFrames(). As well as logging
 ** the contents of the list of pages headed by pList (connected by pDirty),
 ** this function notifies any active backup processes that the pages have
-** changed. 
+** changed.
+**
+** The list of pages passed into this routine is always sorted by page number.
+** Hence, if page 1 appears anywhere on the list, it will be the first page.
 */ 
 static int pagerWalFrames(
   Pager *pPager,                  /* Pager object */
   PgHdr *pList,                   /* List of frames to log */
   Pgno nTruncate,                 /* Database size after this commit */
   int isCommit,                   /* True if this is a commit */
-  int sync_flags                  /* Flags to pass to OsSync() (or 0) */
+  int syncFlags                   /* Flags to pass to OsSync() (or 0) */
 ){
   int rc;                         /* Return code */
+#if defined(SQLITE_DEBUG) || defined(SQLITE_CHECK_PAGES)
+  PgHdr *p;                       /* For looping over pages */
+#endif
 
   assert( pPager->pWal );
+#ifdef SQLITE_DEBUG
+  /* Verify that the page list is in accending order */
+  for(p=pList; p && p->pDirty; p=p->pDirty){
+    assert( p->pgno < p->pDirty->pgno );
+  }
+#endif
+
+  if( pList->pgno==1 ) pager_write_changecounter(pList);
   rc = sqlite3WalFrames(pPager->pWal, 
-      pPager->pageSize, pList, nTruncate, isCommit, sync_flags
+      pPager->pageSize, pList, nTruncate, isCommit, syncFlags
   );
   if( rc==SQLITE_OK && pPager->pBackup ){
     PgHdr *p;
@@ -37090,9 +37893,8 @@ static int pagerWalFrames(
   }
 
 #ifdef SQLITE_CHECK_PAGES
-  {
-    PgHdr *p;
-    for(p=pList; p; p=p->pDirty) pager_set_pagehash(p);
+  for(p=pList; p; p=p->pDirty){
+    pager_set_pagehash(p);
   }
 #endif
 
@@ -37122,12 +37924,13 @@ static int pagerBeginReadTransaction(Pager *pPager){
   sqlite3WalEndReadTransaction(pPager->pWal);
 
   rc = sqlite3WalBeginReadTransaction(pPager->pWal, &changed);
-  if( rc==SQLITE_OK && changed ){
+  if( rc!=SQLITE_OK || changed ){
     pager_reset(pPager);
   }
 
   return rc;
 }
+#endif
 
 /*
 ** This function is called as part of the transition from PAGER_OPEN
@@ -37184,7 +37987,7 @@ static int pagerPagecount(Pager *pPager, Pgno *pnPage){
   return SQLITE_OK;
 }
 
-
+#ifndef SQLITE_OMIT_WAL
 /*
 ** Check if the *-wal file that corresponds to the database opened by pPager
 ** exists if the database is not empy, or verify that the *-wal file does
@@ -37409,14 +38212,49 @@ SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){
 **              assurance that the journal will not be corrupted to the
 **              point of causing damage to the database during rollback.
 **
+** The above is for a rollback-journal mode.  For WAL mode, OFF continues
+** to mean that no syncs ever occur.  NORMAL means that the WAL is synced
+** prior to the start of checkpoint and that the database file is synced
+** at the conclusion of the checkpoint if the entire content of the WAL
+** was written back into the database.  But no sync operations occur for
+** an ordinary commit in NORMAL mode with WAL.  FULL means that the WAL
+** file is synced following each commit operation, in addition to the
+** syncs associated with NORMAL.
+**
+** Do not confuse synchronous=FULL with SQLITE_SYNC_FULL.  The
+** SQLITE_SYNC_FULL macro means to use the MacOSX-style full-fsync
+** using fcntl(F_FULLFSYNC).  SQLITE_SYNC_NORMAL means to do an
+** ordinary fsync() call.  There is no difference between SQLITE_SYNC_FULL
+** and SQLITE_SYNC_NORMAL on platforms other than MacOSX.  But the
+** synchronous=FULL versus synchronous=NORMAL setting determines when
+** the xSync primitive is called and is relevant to all platforms.
+**
 ** Numeric values associated with these states are OFF==1, NORMAL=2,
 ** and FULL=3.
 */
 #ifndef SQLITE_OMIT_PAGER_PRAGMAS
-SQLITE_PRIVATE void sqlite3PagerSetSafetyLevel(Pager *pPager, int level, int bFullFsync){
+SQLITE_PRIVATE void sqlite3PagerSetSafetyLevel(
+  Pager *pPager,        /* The pager to set safety level for */
+  int level,            /* PRAGMA synchronous.  1=OFF, 2=NORMAL, 3=FULL */  
+  int bFullFsync,       /* PRAGMA fullfsync */
+  int bCkptFullFsync    /* PRAGMA checkpoint_fullfsync */
+){
+  assert( level>=1 && level<=3 );
   pPager->noSync =  (level==1 || pPager->tempFile) ?1:0;
   pPager->fullSync = (level==3 && !pPager->tempFile) ?1:0;
-  pPager->sync_flags = (bFullFsync?SQLITE_SYNC_FULL:SQLITE_SYNC_NORMAL);
+  if( pPager->noSync ){
+    pPager->syncFlags = 0;
+    pPager->ckptSyncFlags = 0;
+  }else if( bFullFsync ){
+    pPager->syncFlags = SQLITE_SYNC_FULL;
+    pPager->ckptSyncFlags = SQLITE_SYNC_FULL;
+  }else if( bCkptFullFsync ){
+    pPager->syncFlags = SQLITE_SYNC_NORMAL;
+    pPager->ckptSyncFlags = SQLITE_SYNC_FULL;
+  }else{
+    pPager->syncFlags = SQLITE_SYNC_NORMAL;
+    pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL;
+  }
 }
 #endif
 
@@ -37595,9 +38433,8 @@ SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager *pPager, int mxPage){
   if( mxPage>0 ){
     pPager->mxPgno = mxPage;
   }
-  if( pPager->eState!=PAGER_OPEN && pPager->mxPgno<pPager->dbSize ){
-    pPager->mxPgno = pPager->dbSize;
-  }
+  assert( pPager->eState!=PAGER_OPEN );      /* Called only by OP_MaxPgcnt */
+  assert( pPager->mxPgno>=pPager->dbSize );  /* OP_MaxPgcnt enforces this */
   return pPager->mxPgno;
 }
 
@@ -37802,10 +38639,7 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager){
   /* pPager->errCode = 0; */
   pPager->exclusiveMode = 0;
 #ifndef SQLITE_OMIT_WAL
-  sqlite3WalClose(pPager->pWal,
-    (pPager->noSync ? 0 : pPager->sync_flags), 
-    pPager->pageSize, pTmp
-  );
+  sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags, pPager->pageSize, pTmp);
   pPager->pWal = 0;
 #endif
   pager_reset(pPager);
@@ -37971,7 +38805,7 @@ static int syncJournal(Pager *pPager, int newHdr){
         if( pPager->fullSync && 0==(iDc&SQLITE_IOCAP_SEQUENTIAL) ){
           PAGERTRACE(("SYNC journal of %d\n", PAGERID(pPager)));
           IOTRACE(("JSYNC %p\n", pPager))
-          rc = sqlite3OsSync(pPager->jfd, pPager->sync_flags);
+          rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags);
           if( rc!=SQLITE_OK ) return rc;
         }
         IOTRACE(("JHDR %p %lld\n", pPager, pPager->journalHdr));
@@ -37983,8 +38817,8 @@ static int syncJournal(Pager *pPager, int newHdr){
       if( 0==(iDc&SQLITE_IOCAP_SEQUENTIAL) ){
         PAGERTRACE(("SYNC journal of %d\n", PAGERID(pPager)));
         IOTRACE(("JSYNC %p\n", pPager))
-        rc = sqlite3OsSync(pPager->jfd, pPager->sync_flags| 
-          (pPager->sync_flags==SQLITE_SYNC_FULL?SQLITE_SYNC_DATAONLY:0)
+        rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags| 
+          (pPager->syncFlags==SQLITE_SYNC_FULL?SQLITE_SYNC_DATAONLY:0)
         );
         if( rc!=SQLITE_OK ) return rc;
       }
@@ -38085,6 +38919,7 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
       char *pData;                                   /* Data to write */    
 
       assert( (pList->flags&PGHDR_NEED_SYNC)==0 );
+      if( pList->pgno==1 ) pager_write_changecounter(pList);
 
       /* Encode the database */
       CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM, pData);
@@ -38143,7 +38978,7 @@ static int openSubJournal(Pager *pPager){
 
 /*
 ** Append a record of the current state of page pPg to the sub-journal. 
-** It is the caller's responsibility to use subjRequiresPage() to check 
+** It is the callers responsibility to use subjRequiresPage() to check 
 ** that it is really required before calling this function.
 **
 ** If successful, set the bit corresponding to pPg->pgno in the bitvecs
@@ -38377,6 +39212,13 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
   /* Set the output variable to NULL in case an error occurs. */
   *ppPager = 0;
 
+#ifndef SQLITE_OMIT_MEMORYDB
+  if( flags & PAGER_MEMORY ){
+    memDb = 1;
+    zFilename = 0;
+  }
+#endif
+
   /* Compute and store the full pathname in an allocated buffer pointed
   ** to by zPathname, length nPathname. Or, if this is a temporary file,
   ** leave both nPathname and zPathname set to 0.
@@ -38387,17 +39229,8 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
     if( zPathname==0 ){
       return SQLITE_NOMEM;
     }
-#ifndef SQLITE_OMIT_MEMORYDB
-    if( strcmp(zFilename,":memory:")==0 ){
-      memDb = 1;
-      zPathname[0] = 0;
-    }else
-#endif
-    {
-      zPathname[0] = 0; /* Make sure initialized even if FullPathname() fails */
-      rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname);
-    }
-
+    zPathname[0] = 0; /* Make sure initialized even if FullPathname() fails */
+    rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname);
     nPathname = sqlite3Strlen30(zPathname);
     if( rc==SQLITE_OK && nPathname+8>pVfs->mxPathname ){
       /* This branch is taken when the journal path required by
@@ -38452,19 +39285,15 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
 
   /* Fill in the Pager.zFilename and Pager.zJournal buffers, if required. */
   if( zPathname ){
+    assert( nPathname>0 );
     pPager->zJournal =   (char*)(pPtr += nPathname + 1);
     memcpy(pPager->zFilename, zPathname, nPathname);
     memcpy(pPager->zJournal, zPathname, nPathname);
     memcpy(&pPager->zJournal[nPathname], "-journal", 8);
-    if( pPager->zFilename[0]==0 ){
-      pPager->zJournal[0] = 0;
-    }
 #ifndef SQLITE_OMIT_WAL
-    else{
-      pPager->zWal = &pPager->zJournal[nPathname+8+1];
-      memcpy(pPager->zWal, zPathname, nPathname);
-      memcpy(&pPager->zWal[nPathname], "-wal", 4);
-    }
+    pPager->zWal = &pPager->zJournal[nPathname+8+1];
+    memcpy(pPager->zWal, zPathname, nPathname);
+    memcpy(&pPager->zWal[nPathname], "-wal", 4);
 #endif
     sqlite3_free(zPathname);
   }
@@ -38473,9 +39302,10 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
 
   /* Open the pager file.
   */
-  if( zFilename && zFilename[0] && !memDb ){
+  if( zFilename && zFilename[0] ){
     int fout = 0;                    /* VFS flags returned by xOpen() */
     rc = sqlite3OsOpen(pVfs, pPager->zFilename, pPager->fd, vfsFlags, &fout);
+    assert( !memDb );
     readOnly = (fout&SQLITE_OPEN_READONLY);
 
     /* If the file was successfully opened for read/write access,
@@ -38579,7 +39409,8 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
   assert( useJournal || pPager->tempFile );
   pPager->noSync = pPager->tempFile;
   pPager->fullSync = pPager->noSync ?0:1;
-  pPager->sync_flags = SQLITE_SYNC_NORMAL;
+  pPager->syncFlags = pPager->noSync ? 0 : SQLITE_SYNC_NORMAL;
+  pPager->ckptSyncFlags = pPager->syncFlags;
   /* pPager->pFirst = 0; */
   /* pPager->pFirstSynced = 0; */
   /* pPager->pLast = 0; */
@@ -38679,7 +39510,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){
           sqlite3BeginBenignMalloc();
           if( pagerLockDb(pPager, RESERVED_LOCK)==SQLITE_OK ){
             sqlite3OsDelete(pVfs, pPager->zJournal, 0);
-            pagerUnlockDb(pPager, SHARED_LOCK);
+            if( !pPager->exclusiveMode ) pagerUnlockDb(pPager, SHARED_LOCK);
           }
           sqlite3EndBenignMalloc();
         }else{
@@ -38929,7 +39760,9 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
     ** mode. Otherwise, the following function call is a no-op.
     */
     rc = pagerOpenWalIfPresent(pPager);
+#ifndef SQLITE_OMIT_WAL
     assert( pPager->pWal==0 || rc==SQLITE_OK );
+#endif
   }
 
   if( pagerUseWal(pPager) ){
@@ -39358,29 +40191,29 @@ static int pager_write(PgHdr *pPg){
 
   CHECK_PAGE(pPg);
 
+  /* The journal file needs to be opened. Higher level routines have already
+  ** obtained the necessary locks to begin the write-transaction, but the
+  ** rollback journal might not yet be open. Open it now if this is the case.
+  **
+  ** This is done before calling sqlite3PcacheMakeDirty() on the page. 
+  ** Otherwise, if it were done after calling sqlite3PcacheMakeDirty(), then
+  ** an error might occur and the pager would end up in WRITER_LOCKED state
+  ** with pages marked as dirty in the cache.
+  */
+  if( pPager->eState==PAGER_WRITER_LOCKED ){
+    rc = pager_open_journal(pPager);
+    if( rc!=SQLITE_OK ) return rc;
+  }
+  assert( pPager->eState>=PAGER_WRITER_CACHEMOD );
+  assert( assert_pager_state(pPager) );
+
   /* Mark the page as dirty.  If the page has already been written
   ** to the journal then we can return right away.
   */
   sqlite3PcacheMakeDirty(pPg);
   if( pageInJournal(pPg) && !subjRequiresPage(pPg) ){
     assert( !pagerUseWal(pPager) );
-    assert( pPager->eState>=PAGER_WRITER_CACHEMOD );
   }else{
-
-    /* If we get this far, it means that the page needs to be
-    ** written to the transaction journal or the checkpoint journal
-    ** or both.
-    **
-    ** Higher level routines have already obtained the necessary locks
-    ** to begin the write-transaction, but the rollback journal might not 
-    ** yet be open. Open it now if this is the case.
-    */
-    if( pPager->eState==PAGER_WRITER_LOCKED ){
-      rc = pager_open_journal(pPager);
-      if( rc!=SQLITE_OK ) return rc;
-    }
-    assert( pPager->eState>=PAGER_WRITER_CACHEMOD );
-    assert( assert_pager_state(pPager) );
   
     /* The transaction journal now exists and we have a RESERVED or an
     ** EXCLUSIVE lock on the main database file.  Write the current page to
@@ -39607,7 +40440,13 @@ SQLITE_PRIVATE void sqlite3PagerDontWrite(PgHdr *pPg){
 /*
 ** This routine is called to increment the value of the database file 
 ** change-counter, stored as a 4-byte big-endian integer starting at 
-** byte offset 24 of the pager file.
+** byte offset 24 of the pager file.  The secondary change counter at
+** 92 is also updated, as is the SQLite version number at offset 96.
+**
+** But this only happens if the pPager->changeCountDone flag is false.
+** To avoid excess churning of page 1, the update only happens once.
+** See also the pager_write_changecounter() routine that does an 
+** unconditional update of the change counters.
 **
 ** If the isDirectMode flag is zero, then this is done by calling 
 ** sqlite3PagerWrite() on page 1, then modifying the contents of the
@@ -39648,7 +40487,6 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
 
   if( !pPager->changeCountDone && pPager->dbSize>0 ){
     PgHdr *pPgHdr;                /* Reference to page 1 */
-    u32 change_counter;           /* Initial value of change-counter field */
 
     assert( !pPager->tempFile && isOpen(pPager->fd) );
 
@@ -39666,16 +40504,8 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
     }
 
     if( rc==SQLITE_OK ){
-      /* Increment the value just read and write it back to byte 24. */
-      change_counter = sqlite3Get4byte((u8*)pPager->dbFileVers);
-      change_counter++;
-      put32bits(((char*)pPgHdr->pData)+24, change_counter);
-
-      /* Also store the SQLite version number in bytes 96..99 and in
-      ** bytes 92..95 store the change counter for which the version number
-      ** is valid. */
-      put32bits(((char*)pPgHdr->pData)+92, change_counter);
-      put32bits(((char*)pPgHdr->pData)+96, SQLITE_VERSION_NUMBER);
+      /* Actually do the update of the change counter */
+      pager_write_changecounter(pPgHdr);
 
       /* If running in direct mode, write the contents of page 1 to the file. */
       if( DIRECT_MODE ){
@@ -39700,19 +40530,20 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
 }
 
 /*
-** Sync the pager file to disk. This is a no-op for in-memory files
+** Sync the database file to disk. This is a no-op for in-memory databases
 ** or pages with the Pager.noSync flag set.
 **
-** If successful, or called on a pager for which it is a no-op, this
+** If successful, or if called on a pager for which it is a no-op, this
 ** function returns SQLITE_OK. Otherwise, an IO error code is returned.
 */
 SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager){
-  int rc;                              /* Return code */
-  assert( !MEMDB );
-  if( pPager->noSync ){
-    rc = SQLITE_OK;
-  }else{
-    rc = sqlite3OsSync(pPager->fd, pPager->sync_flags);
+  int rc = SQLITE_OK;
+  if( !pPager->noSync ){
+    assert( !MEMDB );
+    rc = sqlite3OsSync(pPager->fd, pPager->syncFlags);
+  }else if( isOpen(pPager->fd) ){
+    assert( !MEMDB );
+    sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SYNC_OMITTED, (void *)&rc);
   }
   return rc;
 }
@@ -39801,7 +40632,7 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
       PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache);
       if( pList ){
         rc = pagerWalFrames(pPager, pList, pPager->dbSize, 1, 
-            (pPager->fullSync ? pPager->sync_flags : 0)
+            (pPager->fullSync ? pPager->syncFlags : 0)
         );
       }
       if( rc==SQLITE_OK ){
@@ -39931,8 +40762,8 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
       }
   
       /* Finally, sync the database file. */
-      if( !pPager->noSync && !noSync ){
-        rc = sqlite3OsSync(pPager->fd, pPager->sync_flags);
+      if( !noSync ){
+        rc = sqlite3PagerSync(pPager);
       }
       IOTRACE(("DBSYNC %p\n", pPager))
     }
@@ -40044,7 +40875,17 @@ SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){
     rc2 = pager_end_transaction(pPager, pPager->setMaster);
     if( rc==SQLITE_OK ) rc = rc2;
   }else if( !isOpen(pPager->jfd) || pPager->eState==PAGER_WRITER_LOCKED ){
+    int eState = pPager->eState;
     rc = pager_end_transaction(pPager, 0);
+    if( !MEMDB && eState>PAGER_WRITER_LOCKED ){
+      /* This can happen using journal_mode=off. Move the pager to the error 
+      ** state to indicate that the contents of the cache may not be trusted.
+      ** Any active readers will get SQLITE_ABORT.
+      */
+      pPager->errCode = SQLITE_ABORT;
+      pPager->eState = PAGER_ERROR;
+      return rc;
+    }
   }else{
     rc = pager_playback(pPager, 0);
   }
@@ -40503,7 +41344,8 @@ SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *pPager, int eMode){
             || eMode==PAGER_LOCKINGMODE_EXCLUSIVE );
   assert( PAGER_LOCKINGMODE_QUERY<0 );
   assert( PAGER_LOCKINGMODE_NORMAL>=0 && PAGER_LOCKINGMODE_EXCLUSIVE>=0 );
-  if( eMode>=0 && !pPager->tempFile ){
+  assert( pPager->exclusiveMode || 0==sqlite3WalHeapMemory(pPager->pWal) );
+  if( eMode>=0 && !pPager->tempFile && !sqlite3WalHeapMemory(pPager->pWal) ){
     pPager->exclusiveMode = (u8)eMode;
   }
   return (int)pPager->exclusiveMode;
@@ -40672,10 +41514,8 @@ SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager){
   int rc = SQLITE_OK;
   if( pPager->pWal ){
     u8 *zBuf = (u8 *)pPager->pTmpSpace;
-    rc = sqlite3WalCheckpoint(pPager->pWal,
-        (pPager->noSync ? 0 : pPager->sync_flags),
-        pPager->pageSize, zBuf
-    );
+    rc = sqlite3WalCheckpoint(pPager->pWal, pPager->ckptSyncFlags,
+                              pPager->pageSize, zBuf);
   }
   return rc;
 }
@@ -40690,10 +41530,62 @@ SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager){
 */
 SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager){
   const sqlite3_io_methods *pMethods = pPager->fd->pMethods;
-  return pMethods->iVersion>=2 && pMethods->xShmMap!=0;
+  return pPager->exclusiveMode || (pMethods->iVersion>=2 && pMethods->xShmMap);
+}
+
+/*
+** Attempt to take an exclusive lock on the database file. If a PENDING lock
+** is obtained instead, immediately release it.
+*/
+static int pagerExclusiveLock(Pager *pPager){
+  int rc;                         /* Return code */
+
+  assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK );
+  rc = pagerLockDb(pPager, EXCLUSIVE_LOCK);
+  if( rc!=SQLITE_OK ){
+    /* If the attempt to grab the pending lock failed, release the 
+    ** exclusive lock that may have been obtained instead.  */
+    pagerUnlockDb(pPager, SHARED_LOCK);
+  }
+
+  return rc;
 }
 
 /*
+** Call sqlite3WalOpen() to open the WAL handle. If the pager is in 
+** exclusive-locking mode when this function is called, take an EXCLUSIVE
+** lock on the database file and use heap-memory to store the wal-index
+** in. Otherwise, use the normal shared-memory.
+*/
+static int pagerOpenWal(Pager *pPager){
+  int rc = SQLITE_OK;
+
+  assert( pPager->pWal==0 && pPager->tempFile==0 );
+  assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK || pPager->noReadlock);
+
+  /* If the pager is already in exclusive-mode, the WAL module will use 
+  ** heap-memory for the wal-index instead of the VFS shared-memory 
+  ** implementation. Take the exclusive lock now, before opening the WAL
+  ** file, to make sure this is safe.
+  */
+  if( pPager->exclusiveMode ){
+    rc = pagerExclusiveLock(pPager);
+  }
+
+  /* Open the connection to the log file. If this operation fails, 
+  ** (e.g. due to malloc() failure), return an error code.
+  */
+  if( rc==SQLITE_OK ){
+    rc = sqlite3WalOpen(pPager->pVfs, 
+        pPager->fd, pPager->zWal, pPager->exclusiveMode, &pPager->pWal
+    );
+  }
+
+  return rc;
+}
+
+
+/*
 ** The caller must be holding a SHARED lock on the database file to call
 ** this function.
 **
@@ -40726,11 +41618,7 @@ SQLITE_PRIVATE int sqlite3PagerOpenWal(
     /* Close any rollback journal previously open */
     sqlite3OsClose(pPager->jfd);
 
-    /* Open the connection to the log file. If this operation fails, 
-    ** (e.g. due to malloc() failure), unlock the database file and 
-    ** return an error code.
-    */
-    rc = sqlite3WalOpen(pPager->pVfs, pPager->fd, pPager->zWal, &pPager->pWal);
+    rc = pagerOpenWal(pPager);
     if( rc==SQLITE_OK ){
       pPager->journalMode = PAGER_JOURNALMODE_WAL;
       pPager->eState = PAGER_OPEN;
@@ -40769,8 +41657,7 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager){
       );
     }
     if( rc==SQLITE_OK && logexists ){
-      rc = sqlite3WalOpen(pPager->pVfs, pPager->fd,
-                          pPager->zWal, &pPager->pWal);
+      rc = pagerOpenWal(pPager);
     }
   }
     
@@ -40778,17 +41665,11 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager){
   ** the database file, the log and log-summary files will be deleted.
   */
   if( rc==SQLITE_OK && pPager->pWal ){
-    rc = pagerLockDb(pPager, EXCLUSIVE_LOCK);
+    rc = pagerExclusiveLock(pPager);
     if( rc==SQLITE_OK ){
-      rc = sqlite3WalClose(pPager->pWal,
-                           (pPager->noSync ? 0 : pPager->sync_flags), 
-        pPager->pageSize, (u8*)pPager->pTmpSpace
-      );
+      rc = sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags,
+                           pPager->pageSize, (u8*)pPager->pTmpSpace);
       pPager->pWal = 0;
-    }else{
-      /* If we cannot get an EXCLUSIVE lock, downgrade the PENDING lock
-      ** that we did get back to SHARED. */
-      pagerUnlockDb(pPager, SQLITE_LOCK_SHARED);
     }
   }
   return rc;
@@ -41245,6 +42126,13 @@ struct Wal {
 };
 
 /*
+** Candidate values for Wal.exclusiveMode.
+*/
+#define WAL_NORMAL_MODE     0
+#define WAL_EXCLUSIVE_MODE  1     
+#define WAL_HEAPMEMORY_MODE 2
+
+/*
 ** Each page of the wal-index mapping contains a hash-table made up of
 ** an array of HASHTABLE_NSLOT elements of the following type.
 */
@@ -41267,14 +42155,14 @@ typedef u16 ht_slot;
 */
 struct WalIterator {
   int iPrior;                     /* Last result returned from the iterator */
-  int nSegment;                   /* Size of the aSegment[] array */
+  int nSegment;                   /* Number of entries in aSegment[] */
   struct WalSegment {
     int iNext;                    /* Next slot in aIndex[] not yet returned */
     ht_slot *aIndex;              /* i0, i1, i2... such that aPgno[iN] ascend */
     u32 *aPgno;                   /* Array of page numbers. */
-    int nEntry;                   /* Max size of aPgno[] and aIndex[] arrays */
+    int nEntry;                   /* Nr. of entries in aPgno[] and aIndex[] */
     int iZero;                    /* Frame number associated with aPgno[0] */
-  } aSegment[1];                  /* One for every 32KB page in the WAL */
+  } aSegment[1];                  /* One for every 32KB page in the wal-index */
 };
 
 /*
@@ -41330,9 +42218,14 @@ static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){
 
   /* Request a pointer to the required page from the VFS */
   if( pWal->apWiData[iPage]==0 ){
-    rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ, 
-        pWal->writeLock, (void volatile **)&pWal->apWiData[iPage]
-    );
+    if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){
+      pWal->apWiData[iPage] = (u32 volatile *)sqlite3MallocZero(WALINDEX_PGSZ);
+      if( !pWal->apWiData[iPage] ) rc = SQLITE_NOMEM;
+    }else{
+      rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ, 
+          pWal->writeLock, (void volatile **)&pWal->apWiData[iPage]
+      );
+    }
   }
 
   *ppPage = pWal->apWiData[iPage];
@@ -41415,6 +42308,12 @@ static void walChecksumBytes(
   aOut[1] = s2;
 }
 
+static void walShmBarrier(Wal *pWal){
+  if( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE ){
+    sqlite3OsShmBarrier(pWal->pDbFd);
+  }
+}
+
 /*
 ** Write the header information in pWal->hdr into the wal-index.
 **
@@ -41429,7 +42328,7 @@ static void walIndexWriteHdr(Wal *pWal){
   pWal->hdr.iVersion = WALINDEX_MAX_VERSION;
   walChecksumBytes(1, (u8*)&pWal->hdr, nCksum, 0, pWal->hdr.aCksum);
   memcpy((void *)&aHdr[1], (void *)&pWal->hdr, sizeof(WalIndexHdr));
-  sqlite3OsShmBarrier(pWal->pDbFd);
+  walShmBarrier(pWal);
   memcpy((void *)&aHdr[0], (void *)&pWal->hdr, sizeof(WalIndexHdr));
 }
 
@@ -42001,7 +42900,15 @@ recovery_error:
 ** Close an open wal-index.
 */
 static void walIndexClose(Wal *pWal, int isDelete){
-  sqlite3OsShmUnmap(pWal->pDbFd, isDelete);
+  if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){
+    int i;
+    for(i=0; i<pWal->nWiData; i++){
+      sqlite3_free((void *)pWal->apWiData[i]);
+      pWal->apWiData[i] = 0;
+    }
+  }else{
+    sqlite3OsShmUnmap(pWal->pDbFd, isDelete);
+  }
 }
 
 /* 
@@ -42023,6 +42930,7 @@ SQLITE_PRIVATE int sqlite3WalOpen(
   sqlite3_vfs *pVfs,              /* vfs module to open wal and wal-index */
   sqlite3_file *pDbFd,            /* The open database file */
   const char *zWalName,           /* Name of the WAL file */
+  int bNoShm,                     /* True to run in heap-memory mode */
   Wal **ppWal                     /* OUT: Allocated Wal handle */
 ){
   int rc;                         /* Return Code */
@@ -42056,6 +42964,7 @@ SQLITE_PRIVATE int sqlite3WalOpen(
   pRet->pDbFd = pDbFd;
   pRet->readLock = -1;
   pRet->zWalName = zWalName;
+  pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE);
 
   /* Open file handle on the write-ahead log file. */
   flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL);
@@ -42117,9 +43026,29 @@ static int walIteratorNext(
 
 /*
 ** This function merges two sorted lists into a single sorted list.
+**
+** aLeft[] and aRight[] are arrays of indices.  The sort key is
+** aContent[aLeft[]] and aContent[aRight[]].  Upon entry, the following
+** is guaranteed for all J<K:
+**
+**        aContent[aLeft[J]] < aContent[aLeft[K]]
+**        aContent[aRight[J]] < aContent[aRight[K]]
+**
+** This routine overwrites aRight[] with a new (probably longer) sequence
+** of indices such that the aRight[] contains every index that appears in
+** either aLeft[] or the old aRight[] and such that the second condition
+** above is still met.
+**
+** The aContent[aLeft[X]] values will be unique for all X.  And the
+** aContent[aRight[X]] values will be unique too.  But there might be
+** one or more combinations of X and Y such that
+**
+**      aLeft[X]!=aRight[Y]  &&  aContent[aLeft[X]] == aContent[aRight[Y]]
+**
+** When that happens, omit the aLeft[X] and use the aRight[Y] index.
 */
 static void walMerge(
-  u32 *aContent,                  /* Pages in wal */
+  const u32 *aContent,            /* Pages in wal - keys for the sort */
   ht_slot *aLeft,                 /* IN: Left hand input list */
   int nLeft,                      /* IN: Elements in array *paLeft */
   ht_slot **paRight,              /* IN/OUT: Right hand input list */
@@ -42159,10 +43088,24 @@ static void walMerge(
 }
 
 /*
-** Sort the elements in list aList, removing any duplicates.
+** Sort the elements in list aList using aContent[] as the sort key.
+** Remove elements with duplicate keys, preferring to keep the
+** larger aList[] values.
+**
+** The aList[] entries are indices into aContent[].  The values in
+** aList[] are to be sorted so that for all J<K:
+**
+**      aContent[aList[J]] < aContent[aList[K]]
+**
+** For any X and Y such that
+**
+**      aContent[aList[X]] == aContent[aList[Y]]
+**
+** Keep the larger of the two values aList[X] and aList[Y] and discard
+** the smaller.
 */
 static void walMergesort(
-  u32 *aContent,                  /* Pages in wal */
+  const u32 *aContent,            /* Pages in wal */
   ht_slot *aBuffer,               /* Buffer of at least *pnList items to use */
   ht_slot *aList,                 /* IN/OUT: List to sort */
   int *pnList                     /* IN/OUT: Number of elements in aList[] */
@@ -42227,6 +43170,7 @@ static void walIteratorFree(WalIterator *p){
 /*
 ** Construct a WalInterator object that can be used to loop over all 
 ** pages in the WAL in ascending order. The caller must hold the checkpoint
+** lock.
 **
 ** On success, make *pp point to the newly allocated WalInterator object
 ** return SQLITE_OK. Otherwise, return an error code. If this routine
@@ -42361,7 +43305,8 @@ static int walCheckpoint(
   szPage = (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16);
   testcase( szPage<=32768 );
   testcase( szPage>=65536 );
-  if( pWal->hdr.mxFrame==0 ) return SQLITE_OK;
+  pInfo = walCkptInfo(pWal);
+  if( pInfo->nBackfill>=pWal->hdr.mxFrame ) return SQLITE_OK;
 
   /* Allocate the iterator */
   rc = walIteratorInit(pWal, &pIter);
@@ -42383,7 +43328,6 @@ static int walCheckpoint(
   */
   mxSafeFrame = pWal->hdr.mxFrame;
   mxPage = pWal->hdr.nPage;
-  pInfo = walCkptInfo(pWal);
   for(i=1; i<WAL_NREADER; i++){
     u32 y = pInfo->aReadMark[i];
     if( mxSafeFrame>=y ){
@@ -42489,7 +43433,9 @@ SQLITE_PRIVATE int sqlite3WalClose(
     */
     rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE);
     if( rc==SQLITE_OK ){
-      pWal->exclusiveMode = 1;
+      if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
+        pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
+      }
       rc = sqlite3WalCheckpoint(pWal, sync_flags, nBuf, zBuf);
       if( rc==SQLITE_OK ){
         isDelete = 1;
@@ -42545,7 +43491,7 @@ static int walIndexTryHdr(Wal *pWal, int *pChanged){
   */
   aHdr = walIndexHdr(pWal);
   memcpy(&h1, (void *)&aHdr[0], sizeof(h1));
-  sqlite3OsShmBarrier(pWal->pDbFd);
+  walShmBarrier(pWal);
   memcpy(&h2, (void *)&aHdr[1], sizeof(h2));
 
   if( memcmp(&h1, &h2, sizeof(h1))!=0 ){
@@ -42746,7 +43692,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
     ** and can be safely ignored.
     */
     rc = walLockShared(pWal, WAL_READ_LOCK(0));
-    sqlite3OsShmBarrier(pWal->pDbFd);
+    walShmBarrier(pWal);
     if( rc==SQLITE_OK ){
       if( memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){
         /* It is not safe to allow the reader to continue here if frames
@@ -42840,7 +43786,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
     ** log-wrap (either of which would require an exclusive lock on
     ** WAL_READ_LOCK(mxI)) has not occurred since the snapshot was valid.
     */
-    sqlite3OsShmBarrier(pWal->pDbFd);
+    walShmBarrier(pWal);
     if( pInfo->aReadMark[mxI]!=mxReadMark
      || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr))
     ){
@@ -43182,7 +44128,7 @@ SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){
 **
 ** SQLITE_OK is returned if no error is encountered (regardless of whether
 ** or not pWal->hdr.mxFrame is modified). An SQLite error code is returned
-** if some error 
+** if an error occurs.
 */
 static int walRestartLog(Wal *pWal){
   int rc = SQLITE_OK;
@@ -43215,6 +44161,8 @@ static int walRestartLog(Wal *pWal){
         for(i=1; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
         assert( pInfo->aReadMark[0]==0 );
         walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
+      }else if( rc!=SQLITE_BUSY ){
+        return rc;
       }
     }
     walUnlockShared(pWal, WAL_READ_LOCK(0));
@@ -43294,7 +44242,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(
       return rc;
     }
   }
-  assert( pWal->szPage==szPage );
+  assert( (int)pWal->szPage==szPage );
 
   /* Write the log file. */
   for(p=pList; p; p=p->pDirty){
@@ -43481,13 +44429,14 @@ SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal){
 ** on the main database file before invoking this operation.
 **
 ** If op is negative, then do a dry-run of the op==1 case but do
-** not actually change anything.  The pager uses this to see if it
+** not actually change anything. The pager uses this to see if it
 ** should acquire the database exclusive lock prior to invoking
 ** the op==1 case.
 */
 SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op){
   int rc;
   assert( pWal->writeLock==0 );
+  assert( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE || op==-1 );
 
   /* pWal->readLock is usually set, but might be -1 if there was a 
   ** prior error while attempting to acquire are read-lock. This cannot 
@@ -43521,6 +44470,15 @@ SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op){
   return rc;
 }
 
+/* 
+** Return true if the argument is non-NULL and the WAL module is using
+** heap-memory for the wal-index. Otherwise, if the argument is NULL or the
+** WAL module is using shared-memory, return false. 
+*/
+SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal){
+  return (pWal && pWal->exclusiveMode==WAL_HEAPMEMORY_MODE );
+}
+
 #endif /* #ifndef SQLITE_OMIT_WAL */
 
 /************** End of wal.c *************************************************/
@@ -43954,16 +44912,17 @@ struct BtShared {
   u8 pageSizeFixed;     /* True if the page size can no longer be changed */
   u8 secureDelete;      /* True if secure_delete is enabled */
   u8 initiallyEmpty;    /* Database is empty at start of transaction */
+  u8 openFlags;         /* Flags to sqlite3BtreeOpen() */
 #ifndef SQLITE_OMIT_AUTOVACUUM
   u8 autoVacuum;        /* True if auto-vacuum is enabled */
   u8 incrVacuum;        /* True if incr-vacuum is enabled */
 #endif
+  u8 inTransaction;     /* Transaction state */
+  u8 doNotUseWAL;       /* If true, do not open write-ahead-log file */
   u16 maxLocal;         /* Maximum local payload in non-LEAFDATA tables */
   u16 minLocal;         /* Minimum local payload in non-LEAFDATA tables */
   u16 maxLeaf;          /* Maximum local payload in a LEAFDATA table */
   u16 minLeaf;          /* Minimum local payload in a LEAFDATA table */
-  u8 inTransaction;     /* Transaction state */
-  u8 doNotUseWAL;       /* If true, do not open write-ahead-log file */
   u32 pageSize;         /* Total number of bytes on a page */
   u32 usableSize;       /* Number of usable bytes on each page */
   int nTransaction;     /* Number of open transactions (read + write) */
@@ -43990,8 +44949,8 @@ struct BtShared {
 */
 typedef struct CellInfo CellInfo;
 struct CellInfo {
-  u8 *pCell;     /* Pointer to the start of cell content */
   i64 nKey;      /* The key for INTKEY tables, or number of bytes in key */
+  u8 *pCell;     /* Pointer to the start of cell content */
   u32 nData;     /* Number of bytes of data */
   u32 nPayload;  /* Total amount of payload */
   u16 nHeader;   /* Size of the cell content header in bytes */
@@ -44033,20 +44992,20 @@ struct BtCursor {
   Pgno pgnoRoot;            /* The root page of this tree */
   sqlite3_int64 cachedRowid; /* Next rowid cache.  0 means not valid */
   CellInfo info;            /* A parse of the cell we are pointing at */
+  i64 nKey;        /* Size of pKey, or last integer key */
+  void *pKey;      /* Saved key that was cursor's last known position */
+  int skipNext;    /* Prev() is noop if negative. Next() is noop if positive */
   u8 wrFlag;                /* True if writable */
   u8 atLast;                /* Cursor pointing to the last entry */
   u8 validNKey;             /* True if info.nKey is valid */
   u8 eState;                /* One of the CURSOR_XXX constants (see below) */
-  void *pKey;      /* Saved key that was cursor's last known position */
-  i64 nKey;        /* Size of pKey, or last integer key */
-  int skipNext;    /* Prev() is noop if negative. Next() is noop if positive */
 #ifndef SQLITE_OMIT_INCRBLOB
-  u8 isIncrblobHandle;      /* True if this cursor is an incr. io handle */
   Pgno *aOverflow;          /* Cache of overflow page locations */
+  u8 isIncrblobHandle;      /* True if this cursor is an incr. io handle */
 #endif
   i16 iPage;                            /* Index of current page in apPage */
-  MemPage *apPage[BTCURSOR_MAX_DEPTH];  /* Pages from root to current page */
   u16 aiIdx[BTCURSOR_MAX_DEPTH];        /* Current index in apPage[i] */
+  MemPage *apPage[BTCURSOR_MAX_DEPTH];  /* Pages from root to current page */
 };
 
 /*
@@ -45450,14 +46409,9 @@ static void btreeParseCellPtr(
     /* This is the (easy) common case where the entire payload fits
     ** on the local page.  No overflow is required.
     */
-    int nSize;          /* Total size of cell content in bytes */
-    nSize = nPayload + n;
+    if( (pInfo->nSize = (u16)(n+nPayload))<4 ) pInfo->nSize = 4;
     pInfo->nLocal = (u16)nPayload;
     pInfo->iOverflow = 0;
-    if( (nSize & ~3)==0 ){
-      nSize = 4;        /* Minimum cell size is 4 */
-    }
-    pInfo->nSize = (u16)nSize;
   }else{
     /* If the payload will not fit completely on the local page, we have
     ** to decide how much to store locally and how much to spill onto
@@ -46204,11 +47158,20 @@ static int btreeInvokeBusyHandler(void *pArg){
 ** Open a database file.
 ** 
 ** 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 sqlite3BtreeClose() is called.
+** then an ephemeral database is created.  The ephemeral database might
+** be exclusively in memory, or it might use a disk-based memory cache.
+** Either way, the ephemeral database will be automatically deleted 
+** when sqlite3BtreeClose() is called.
+**
 ** If zFilename is ":memory:" then an in-memory database is created
 ** that is automatically destroyed when it is closed.
 **
+** The "flags" parameter is a bitmask that might contain bits
+** BTREE_OMIT_JOURNAL and/or BTREE_NO_READLOCK.  The BTREE_NO_READLOCK
+** bit is also set if the SQLITE_NoReadlock flags is set in db->flags.
+** These flags are passed through into sqlite3PagerOpen() and must
+** be the same values as PAGER_OMIT_JOURNAL and PAGER_NO_READLOCK.
+**
 ** If the database is already opened in the same database connection
 ** and we are in shared cache mode, then the open will fail with an
 ** SQLITE_CONSTRAINT error.  We cannot allow two or more BtShared
@@ -46230,22 +47193,38 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
   u8 nReserve;                   /* Byte of unused space on each page */
   unsigned char zDbHeader[100];  /* Database header content */
 
+  /* True if opening an ephemeral, temporary database */
+  const int isTempDb = zFilename==0 || zFilename[0]==0;
+
   /* Set the variable isMemdb to true for an in-memory database, or 
-  ** false for a file-based database. This symbol is only required if
-  ** either of the shared-data or autovacuum features are compiled 
-  ** into the library.
+  ** false for a file-based database.
   */
-#if !defined(SQLITE_OMIT_SHARED_CACHE) || !defined(SQLITE_OMIT_AUTOVACUUM)
-  #ifdef SQLITE_OMIT_MEMORYDB
-    const int isMemdb = 0;
-  #else
-    const int isMemdb = zFilename && !strcmp(zFilename, ":memory:");
-  #endif
+#ifdef SQLITE_OMIT_MEMORYDB
+  const int isMemdb = 0;
+#else
+  const int isMemdb = (zFilename && strcmp(zFilename, ":memory:")==0)
+                       || (isTempDb && sqlite3TempInMemory(db));
 #endif
 
   assert( db!=0 );
   assert( sqlite3_mutex_held(db->mutex) );
+  assert( (flags&0xff)==flags );   /* flags fit in 8 bits */
 
+  /* Only a BTREE_SINGLE database can be BTREE_UNORDERED */
+  assert( (flags & BTREE_UNORDERED)==0 || (flags & BTREE_SINGLE)!=0 );
+
+  /* A BTREE_SINGLE database is always a temporary and/or ephemeral */
+  assert( (flags & BTREE_SINGLE)==0 || isTempDb );
+
+  if( db->flags & SQLITE_NoReadlock ){
+    flags |= BTREE_NO_READLOCK;
+  }
+  if( isMemdb ){
+    flags |= BTREE_MEMORY;
+  }
+  if( (vfsFlags & SQLITE_OPEN_MAIN_DB)!=0 && (isMemdb || isTempDb) ){
+    vfsFlags = (vfsFlags & ~SQLITE_OPEN_MAIN_DB) | SQLITE_OPEN_TEMP_DB;
+  }
   pVfs = db->pVfs;
   p = sqlite3MallocZero(sizeof(Btree));
   if( !p ){
@@ -46263,7 +47242,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
   ** If this Btree is a candidate for shared cache, try to find an
   ** existing BtShared object that we can share with
   */
-  if( isMemdb==0 && zFilename && zFilename[0] ){
+  if( isMemdb==0 && isTempDb==0 ){
     if( vfsFlags & SQLITE_OPEN_SHAREDCACHE ){
       int nFullPathname = pVfs->mxPathname+1;
       char *zFullPathname = sqlite3Malloc(nFullPathname);
@@ -46338,6 +47317,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
     if( rc!=SQLITE_OK ){
       goto btree_open_out;
     }
+    pBt->openFlags = (u8)flags;
     pBt->db = db;
     sqlite3PagerSetBusyhandler(pBt->pPager, btreeInvokeBusyHandler, pBt);
     p->pBt = pBt;
@@ -46442,6 +47422,14 @@ btree_open_out:
     sqlite3_free(pBt);
     sqlite3_free(p);
     *ppBtree = 0;
+  }else{
+    /* If the B-Tree was successfully opened, set the pager-cache size to the
+    ** default value. Except, when opening on an existing shared pager-cache,
+    ** do not change the pager-cache size.
+    */
+    if( sqlite3BtreeSchema(p, 0, 0)==0 ){
+      sqlite3PagerSetCachesize(p->pBt->pPager, SQLITE_DEFAULT_CACHE_SIZE);
+    }
   }
   if( mutexOpen ){
     assert( sqlite3_mutex_held(mutexOpen) );
@@ -46599,11 +47587,17 @@ SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){
 ** probability of damage to near zero but with a write performance reduction.
 */
 #ifndef SQLITE_OMIT_PAGER_PRAGMAS
-SQLITE_PRIVATE int sqlite3BtreeSetSafetyLevel(Btree *p, int level, int fullSync){
+SQLITE_PRIVATE int sqlite3BtreeSetSafetyLevel(
+  Btree *p,              /* The btree to set the safety level on */
+  int level,             /* PRAGMA synchronous.  1=OFF, 2=NORMAL, 3=FULL */
+  int fullSync,          /* PRAGMA fullfsync. */
+  int ckptFullSync       /* PRAGMA checkpoint_fullfync */
+){
   BtShared *pBt = p->pBt;
   assert( sqlite3_mutex_held(p->db->mutex) );
+  assert( level>=1 && level<=3 );
   sqlite3BtreeEnter(p);
-  sqlite3PagerSetSafetyLevel(pBt->pPager, level, fullSync);
+  sqlite3PagerSetSafetyLevel(pBt->pPager, level, fullSync, ckptFullSync);
   sqlite3BtreeLeave(p);
   return SQLITE_OK;
 }
@@ -46878,7 +47872,7 @@ static int lockBtree(BtShared *pBt){
                                    pageSize-usableSize);
       return rc;
     }
-    if( nPageHeader>nPageFile ){
+    if( (pBt->db->flags & SQLITE_RecoveryMode)==0 && nPageHeader>nPageFile ){
       rc = SQLITE_CORRUPT_BKPT;
       goto page1_init_failed;
     }
@@ -47661,8 +48655,8 @@ static void btreeEndTransaction(Btree *p){
 ** are no active cursors, it also releases the read lock.
 */
 SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree *p){
-  BtShared *pBt = p->pBt;
 
+  if( p->inTrans==TRANS_NONE ) return SQLITE_OK;
   sqlite3BtreeEnter(p);
   btreeIntegrity(p);
 
@@ -47671,6 +48665,7 @@ SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree *p){
   */
   if( p->inTrans==TRANS_WRITE ){
     int rc;
+    BtShared *pBt = p->pBt;
     assert( pBt->inTransaction==TRANS_WRITE );
     assert( pBt->nTransaction>0 );
     rc = sqlite3PagerCommitPhaseTwo(pBt->pPager);
@@ -51392,11 +52387,12 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur){
 **     BTREE_INTKEY|BTREE_LEAFDATA     Used for SQL tables with rowid keys
 **     BTREE_ZERODATA                  Used for SQL indices
 */
-static int btreeCreateTable(Btree *p, int *piTable, int flags){
+static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
   BtShared *pBt = p->pBt;
   MemPage *pRoot;
   Pgno pgnoRoot;
   int rc;
+  int ptfFlags;          /* Page-type flage for the root page of new table */
 
   assert( sqlite3BtreeHoldsMutex(p) );
   assert( pBt->inTransaction==TRANS_WRITE );
@@ -51515,8 +52511,14 @@ static int btreeCreateTable(Btree *p, int *piTable, int flags){
   }
 #endif
   assert( sqlite3PagerIswriteable(pRoot->pDbPage) );
-  zeroPage(pRoot, flags | PTF_LEAF);
+  if( createTabFlags & BTREE_INTKEY ){
+    ptfFlags = PTF_INTKEY | PTF_LEAFDATA | PTF_LEAF;
+  }else{
+    ptfFlags = PTF_ZERODATA | PTF_LEAF;
+  }
+  zeroPage(pRoot, ptfFlags);
   sqlite3PagerUnref(pRoot->pDbPage);
+  assert( (pBt->openFlags & BTREE_SINGLE)==0 || pgnoRoot==2 );
   *piTable = (int)pgnoRoot;
   return SQLITE_OK;
 }
@@ -52582,8 +53584,7 @@ SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void
 SQLITE_PRIVATE void sqlite3BtreeCacheOverflow(BtCursor *pCur){
   assert( cursorHoldsMutex(pCur) );
   assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
-  assert(!pCur->isIncrblobHandle);
-  assert(!pCur->aOverflow);
+  invalidateOverflowCache(pCur);
   pCur->isIncrblobHandle = 1;
 }
 #endif
@@ -52744,6 +53745,16 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
 }
 
 /*
+** Attempt to set the page size of the destination to match the page size
+** of the source.
+*/
+static int setDestPgsz(sqlite3_backup *p){
+  int rc;
+  rc = sqlite3BtreeSetPageSize(p->pDest,sqlite3BtreeGetPageSize(p->pSrc),-1,0);
+  return rc;
+}
+
+/*
 ** Create an sqlite3_backup process to copy the contents of zSrcDb from
 ** connection handle pSrcDb to zDestDb in pDestDb. If successful, return
 ** a pointer to the new sqlite3_backup object.
@@ -52776,7 +53787,10 @@ SQLITE_API sqlite3_backup *sqlite3_backup_init(
     );
     p = 0;
   }else {
-    /* Allocate space for a new sqlite3_backup object */
+    /* Allocate space for a new sqlite3_backup object...
+    ** EVIDENCE-OF: R-64852-21591 The sqlite3_backup object is created by a
+    ** call to sqlite3_backup_init() and is destroyed by a call to
+    ** sqlite3_backup_finish(). */
     p = (sqlite3_backup *)sqlite3_malloc(sizeof(sqlite3_backup));
     if( !p ){
       sqlite3Error(pDestDb, SQLITE_NOMEM, 0);
@@ -52793,10 +53807,11 @@ SQLITE_API sqlite3_backup *sqlite3_backup_init(
     p->iNext = 1;
     p->isAttached = 0;
 
-    if( 0==p->pSrc || 0==p->pDest ){
-      /* One (or both) of the named databases did not exist. An error has
-      ** already been written into the pDestDb handle. All that is left
-      ** to do here is free the sqlite3_backup structure.
+    if( 0==p->pSrc || 0==p->pDest || setDestPgsz(p)==SQLITE_NOMEM ){
+      /* One (or both) of the named databases did not exist or an OOM
+      ** error was hit.  The error has already been written into the
+      ** pDestDb handle.  All that is left to do here is free the
+      ** sqlite3_backup structure.
       */
       sqlite3_free(p);
       p = 0;
@@ -53053,32 +54068,46 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
         */
         const i64 iSize = (i64)pgszSrc * (i64)nSrcPage;
         sqlite3_file * const pFile = sqlite3PagerFile(pDestPager);
+        i64 iOff;
+        i64 iEnd;
 
         assert( pFile );
         assert( (i64)nDestTruncate*(i64)pgszDest >= iSize || (
               nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1)
            && iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest
         ));
-        if( SQLITE_OK==(rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1))
-         && SQLITE_OK==(rc = backupTruncateFile(pFile, iSize))
-         && SQLITE_OK==(rc = sqlite3PagerSync(pDestPager))
+
+        /* This call ensures that all data required to recreate the original
+        ** database has been stored in the journal for pDestPager and the
+        ** journal synced to disk. So at this point we may safely modify
+        ** the database file in any way, knowing that if a power failure
+        ** occurs, the original database will be reconstructed from the 
+        ** journal file.  */
+        rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1);
+
+        /* Write the extra pages and truncate the database file as required. */
+        iEnd = MIN(PENDING_BYTE + pgszDest, iSize);
+        for(
+          iOff=PENDING_BYTE+pgszSrc; 
+          rc==SQLITE_OK && iOff<iEnd; 
+          iOff+=pgszSrc
         ){
-          i64 iOff;
-          i64 iEnd = MIN(PENDING_BYTE + pgszDest, iSize);
-          for(
-            iOff=PENDING_BYTE+pgszSrc; 
-            rc==SQLITE_OK && iOff<iEnd; 
-            iOff+=pgszSrc
-          ){
-            PgHdr *pSrcPg = 0;
-            const Pgno iSrcPg = (Pgno)((iOff/pgszSrc)+1);
-            rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg);
-            if( rc==SQLITE_OK ){
-              u8 *zData = sqlite3PagerGetData(pSrcPg);
-              rc = sqlite3OsWrite(pFile, zData, pgszSrc, iOff);
-            }
-            sqlite3PagerUnref(pSrcPg);
+          PgHdr *pSrcPg = 0;
+          const Pgno iSrcPg = (Pgno)((iOff/pgszSrc)+1);
+          rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg);
+          if( rc==SQLITE_OK ){
+            u8 *zData = sqlite3PagerGetData(pSrcPg);
+            rc = sqlite3OsWrite(pFile, zData, pgszSrc, iOff);
           }
+          sqlite3PagerUnref(pSrcPg);
+        }
+        if( rc==SQLITE_OK ){
+          rc = backupTruncateFile(pFile, iSize);
+        }
+
+        /* Sync the database file to disk. */
+        if( rc==SQLITE_OK ){
+          rc = sqlite3PagerSync(pDestPager);
         }
       }else{
         rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 0);
@@ -53159,6 +54188,9 @@ SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p){
   }
   sqlite3BtreeLeave(p->pSrc);
   if( p->pDestDb ){
+    /* EVIDENCE-OF: R-64852-21591 The sqlite3_backup object is created by a
+    ** call to sqlite3_backup_init() and is destroyed by a call to
+    ** sqlite3_backup_finish(). */
     sqlite3_free(p);
   }
   sqlite3_mutex_leave(mutex);
@@ -53410,6 +54442,9 @@ SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){
     pMem->z[pMem->n] = 0;
     pMem->z[pMem->n+1] = 0;
     pMem->flags |= MEM_Term;
+#ifdef SQLITE_DEBUG
+    pMem->pScopyFrom = 0;
+#endif
   }
 
   return SQLITE_OK;
@@ -53530,7 +54565,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
     ctx.s.db = pMem->db;
     ctx.pMem = pMem;
     ctx.pFunc = pFunc;
-    pFunc->xFinalize(&ctx);
+    pFunc->xFinalize(&ctx); /* IMP: R-24505-23230 */
     assert( 0==(pMem->flags&MEM_Dyn) && !pMem->xDel );
     sqlite3DbFree(pMem->db, pMem->zMalloc);
     memcpy(pMem, &ctx.s, sizeof(ctx.s));
@@ -53643,13 +54678,9 @@ SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem *pMem){
     return doubleToInt64(pMem->r);
   }else if( flags & (MEM_Str|MEM_Blob) ){
     i64 value;
-    pMem->flags |= MEM_Str;
-    if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8)
-       || sqlite3VdbeMemNulTerminate(pMem) ){
-      return 0;
-    }
-    assert( pMem->z );
-    sqlite3Atoi64(pMem->z, &value);
+    assert( pMem->z || pMem->n==0 );
+    testcase( pMem->z==0 );
+    sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc);
     return value;
   }else{
     return 0;
@@ -53672,14 +54703,7 @@ SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){
   }else if( pMem->flags & (MEM_Str|MEM_Blob) ){
     /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
     double val = (double)0;
-    pMem->flags |= MEM_Str;
-    if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8)
-       || sqlite3VdbeMemNulTerminate(pMem) ){
-      /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
-      return (double)0;
-    }
-    assert( pMem->z );
-    sqlite3AtoF(pMem->z, &val);
+    sqlite3AtoF(pMem->z, &val, pMem->n, pMem->enc);
     return val;
   }else{
     /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
@@ -53752,21 +54776,19 @@ SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem *pMem){
 ** as much of the string as we can and ignore the rest.
 */
 SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){
-  int rc;
-  assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 );
-  assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
-  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
-  rc = sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8);
-  if( rc ) return rc;
-  rc = sqlite3VdbeMemNulTerminate(pMem);
-  if( rc ) return rc;
-  if( sqlite3Atoi64(pMem->z, &pMem->u.i) ){
-    MemSetTypeFlag(pMem, MEM_Int);
-  }else{
-    pMem->r = sqlite3VdbeRealValue(pMem);
-    MemSetTypeFlag(pMem, MEM_Real);
-    sqlite3VdbeIntegerAffinity(pMem);
+  if( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 ){
+    assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
+    assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
+    if( 0==sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc) ){
+      MemSetTypeFlag(pMem, MEM_Int);
+    }else{
+      pMem->r = sqlite3VdbeRealValue(pMem);
+      MemSetTypeFlag(pMem, MEM_Real);
+      sqlite3VdbeIntegerAffinity(pMem);
+    }
   }
+  assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))!=0 );
+  pMem->flags &= ~(MEM_Str|MEM_Blob);
   return SQLITE_OK;
 }
 
@@ -53775,7 +54797,9 @@ SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){
 */
 SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem *pMem){
   if( pMem->flags & MEM_Frame ){
-    sqlite3VdbeFrameDelete(pMem->u.pFrame);
+    VdbeFrame *pFrame = pMem->u.pFrame;
+    pFrame->pParent = pFrame->v->pDelFrame;
+    pFrame->v->pDelFrame = pFrame;
   }
   if( pMem->flags & MEM_RowSet ){
     sqlite3RowSetClear(pMem->u.pRowSet);
@@ -53871,6 +54895,28 @@ SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem *p){
   return 0; 
 }
 
+#ifdef SQLITE_DEBUG
+/*
+** This routine prepares a memory cell for modication by breaking
+** its link to a shallow copy and by marking any current shallow
+** copies of this cell as invalid.
+**
+** This is used for testing and debugging only - to make sure shallow
+** copies are not misused.
+*/
+SQLITE_PRIVATE void sqlite3VdbeMemPrepareToChange(Vdbe *pVdbe, Mem *pMem){
+  int i;
+  Mem *pX;
+  for(i=1, pX=&pVdbe->aMem[1]; i<=pVdbe->nMem; i++, pX++){
+    if( pX->pScopyFrom==pMem ){
+      pX->flags |= MEM_Invalid;
+      pX->pScopyFrom = 0;
+    }
+  }
+  pMem->pScopyFrom = 0;
+}
+#endif /* SQLITE_DEBUG */
+
 /*
 ** Size of struct Mem not including the Mem.zMalloc member.
 */
@@ -54239,7 +55285,7 @@ SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
         return 0;
       }
     }
-    sqlite3VdbeMemNulTerminate(pVal);
+    sqlite3VdbeMemNulTerminate(pVal); /* IMP: R-59893-45467 */
   }else{
     assert( (pVal->flags&MEM_Blob)==0 );
     sqlite3VdbeMemStringify(pVal, enc);
@@ -54287,6 +55333,8 @@ SQLITE_PRIVATE int sqlite3ValueFromExpr(
   int op;
   char *zVal = 0;
   sqlite3_value *pVal = 0;
+  int negInt = 1;
+  const char *zNeg = "";
 
   if( !pExpr ){
     *ppVal = 0;
@@ -54304,13 +55352,24 @@ SQLITE_PRIVATE int sqlite3ValueFromExpr(
   if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;
 #endif
 
+  /* Handle negative integers in a single step.  This is needed in the
+  ** case when the value is -9223372036854775808.
+  */
+  if( op==TK_UMINUS
+   && (pExpr->pLeft->op==TK_INTEGER || pExpr->pLeft->op==TK_FLOAT) ){
+    pExpr = pExpr->pLeft;
+    op = pExpr->op;
+    negInt = -1;
+    zNeg = "-";
+  }
+
   if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){
     pVal = sqlite3ValueNew(db);
     if( pVal==0 ) goto no_mem;
     if( ExprHasProperty(pExpr, EP_IntValue) ){
-      sqlite3VdbeMemSetInt64(pVal, (i64)pExpr->u.iValue);
+      sqlite3VdbeMemSetInt64(pVal, (i64)pExpr->u.iValue*negInt);
     }else{
-      zVal = sqlite3DbStrDup(db, pExpr->u.zToken);
+      zVal = sqlite3MPrintf(db, "%s%s", zNeg, pExpr->u.zToken);
       if( zVal==0 ) goto no_mem;
       sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC);
       if( op==TK_FLOAT ) pVal->type = SQLITE_FLOAT;
@@ -54320,14 +55379,18 @@ SQLITE_PRIVATE int sqlite3ValueFromExpr(
     }else{
       sqlite3ValueApplyAffinity(pVal, affinity, SQLITE_UTF8);
     }
+    if( pVal->flags & (MEM_Int|MEM_Real) ) pVal->flags &= ~MEM_Str;
     if( enc!=SQLITE_UTF8 ){
       sqlite3VdbeChangeEncoding(pVal, enc);
     }
   }else if( op==TK_UMINUS ) {
+    /* This branch happens for multiple negative signs.  Ex: -(-5) */
     if( SQLITE_OK==sqlite3ValueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal) ){
+      sqlite3VdbeMemNumerify(pVal);
       pVal->u.i = -1 * pVal->u.i;
       /* (double)-1 In case of SQLITE_OMIT_FLOATING_POINT... */
       pVal->r = (double)-1 * pVal->r;
+      sqlite3ValueApplyAffinity(pVal, affinity, enc);
     }
   }
 #ifndef SQLITE_OMIT_BLOB_LITERAL
@@ -54776,7 +55839,7 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
   /* Return true if hasAbort==mayAbort. Or if a malloc failure occured.
   ** If malloc failed, then the while() loop above may not have iterated
   ** through all opcodes and hasAbort may be set incorrectly. Return
-  ** true for this case to prevent the assert() in the caller's frame
+  ** true for this case to prevent the assert() in the callers frame
   ** from failing.  */
   return ( v->db->mallocFailed || hasAbort==mayAbort );
 }
@@ -54807,7 +55870,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
     pOp->opflags = sqlite3OpcodeProperty[opcode];
     if( opcode==OP_Function || opcode==OP_AggStep ){
       if( pOp->p5>nMaxArgs ) nMaxArgs = pOp->p5;
-    }else if( opcode==OP_Transaction && pOp->p2!=0 ){
+    }else if( (opcode==OP_Transaction && pOp->p2!=0) || opcode==OP_Vacuum ){
       p->readOnly = 0;
 #ifndef SQLITE_OMIT_VIRTUALTABLE
     }else if( opcode==OP_VUpdate ){
@@ -54842,7 +55905,7 @@ SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe *p){
 
 /*
 ** This function returns a pointer to the array of opcodes associated with
-** the Vdbe passed as the first argument. It is the caller's responsibility
+** the Vdbe passed as the first argument. It is the callers responsibility
 ** to arrange for the returned array to be eventually freed using the 
 ** vdbeFreeOpArray() function.
 **
@@ -55581,12 +56644,10 @@ SQLITE_PRIVATE int sqlite3VdbeList(
     pMem->type = SQLITE_INTEGER;
     pMem++;
 
-    if( p->explain==1 ){
-      pMem->flags = MEM_Int;
-      pMem->u.i = pOp->p3;                          /* P3 */
-      pMem->type = SQLITE_INTEGER;
-      pMem++;
-    }
+    pMem->flags = MEM_Int;
+    pMem->u.i = pOp->p3;                          /* P3 */
+    pMem->type = SQLITE_INTEGER;
+    pMem++;
 
     if( sqlite3VdbeMemGrow(pMem, 32, 0) ){            /* P4 */
       assert( p->db->mallocFailed );
@@ -55631,7 +56692,7 @@ SQLITE_PRIVATE int sqlite3VdbeList(
       }
     }
 
-    p->nResColumn = 8 - 5*(p->explain-1);
+    p->nResColumn = 8 - 4*(p->explain-1);
     p->rc = SQLITE_OK;
     rc = SQLITE_ROW;
   }
@@ -55938,6 +56999,11 @@ static void closeAllCursors(Vdbe *p){
   if( p->aMem ){
     releaseMemArray(&p->aMem[1], p->nMem);
   }
+  while( p->pDelFrame ){
+    VdbeFrame *pDel = p->pDelFrame;
+    p->pDelFrame = pDel->pParent;
+    sqlite3VdbeFrameDelete(pDel);
+  }
 }
 
 /*
@@ -56154,9 +57220,10 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
       Btree *pBt = db->aDb[i].pBt;
       if( sqlite3BtreeIsInTrans(pBt) ){
         char const *zFile = sqlite3BtreeGetJournalname(pBt);
-        if( zFile==0 || zFile[0]==0 ){
+        if( zFile==0 ){
           continue;  /* Ignore TEMP and :memory: databases */
         }
+        assert( zFile[0]!=0 );
         if( !needSync && !sqlite3BtreeSyncDisabled(pBt) ){
           needSync = 1;
         }
@@ -57620,6 +58687,8 @@ static int vdbeSafetyNotNull(Vdbe *p){
 SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt){
   int rc;
   if( pStmt==0 ){
+    /* IMPLEMENTATION-OF: R-57228-12904 Invoking sqlite3_finalize() on a NULL
+    ** pointer is a harmless no-op. */
     rc = SQLITE_OK;
   }else{
     Vdbe *v = (Vdbe*)pStmt;
@@ -57696,7 +58765,7 @@ SQLITE_API const void *sqlite3_value_blob(sqlite3_value *pVal){
     sqlite3VdbeMemExpandBlob(p);
     p->flags &= ~MEM_Str;
     p->flags |= MEM_Blob;
-    return p->z;
+    return p->n ? p->z : 0;
   }else{
     return sqlite3_value_text(pVal);
   }
@@ -57898,11 +58967,30 @@ static int sqlite3Step(Vdbe *p){
   assert(p);
   if( p->magic!=VDBE_MAGIC_RUN ){
     /* We used to require that sqlite3_reset() be called before retrying
-    ** sqlite3_step() after any error.  But after 3.6.23, we changed this
-    ** so that sqlite3_reset() would be called automatically instead of
-    ** throwing the error.
+    ** sqlite3_step() after any error or after SQLITE_DONE.  But beginning
+    ** with version 3.7.0, we changed this so that sqlite3_reset() would
+    ** be called automatically instead of throwing the SQLITE_MISUSE error.
+    ** This "automatic-reset" change is not technically an incompatibility, 
+    ** since any application that receives an SQLITE_MISUSE is broken by
+    ** definition.
+    **
+    ** Nevertheless, some published applications that were originally written
+    ** for version 3.6.23 or earlier do in fact depend on SQLITE_MISUSE 
+    ** returns, and the so were broken by the automatic-reset change.  As a
+    ** a work-around, the SQLITE_OMIT_AUTORESET compile-time restores the
+    ** legacy behavior of returning SQLITE_MISUSE for cases where the 
+    ** previous sqlite3_step() returned something other than a SQLITE_LOCKED
+    ** or SQLITE_BUSY error.
     */
+#ifdef SQLITE_OMIT_AUTORESET
+    if( p->rc==SQLITE_BUSY || p->rc==SQLITE_LOCKED ){
+      sqlite3_reset((sqlite3_stmt*)p);
+    }else{
+      return SQLITE_MISUSE_BKPT;
+    }
+#else
     sqlite3_reset((sqlite3_stmt*)p);
+#endif
   }
 
   /* Check that malloc() has not failed. If it has, return early. */
@@ -57944,7 +59032,9 @@ static int sqlite3Step(Vdbe *p){
   }else
 #endif /* SQLITE_OMIT_EXPLAIN */
   {
+    db->vdbeExecCnt++;
     rc = sqlite3VdbeExec(p);
+    db->vdbeExecCnt--;
   }
 
 #ifndef SQLITE_OMIT_TRACE
@@ -58050,6 +59140,12 @@ SQLITE_API void *sqlite3_user_data(sqlite3_context *p){
 /*
 ** Extract the user data from a sqlite3_context structure and return a
 ** pointer to it.
+**
+** IMPLEMENTATION-OF: R-46798-50301 The sqlite3_context_db_handle() interface
+** returns a copy of the pointer to the database connection (the 1st
+** parameter) of the sqlite3_create_function() and
+** sqlite3_create_function16() routines that originally registered the
+** application defined function.
 */
 SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){
   assert( p && p->pFunc );
@@ -58232,7 +59328,7 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
 #if defined(SQLITE_DEBUG) && defined(__GNUC__)
       __attribute__((aligned(8))) 
 #endif
-      = {{0}, (double)0, 0, "", 0, MEM_Null, SQLITE_NULL, 0, 0, 0 };
+      = {0, "", (double)0, {0}, 0, MEM_Null, SQLITE_NULL, 0, 0, 0 };
 
     if( pVm && ALWAYS(pVm->db) ){
       sqlite3_mutex_enter(pVm->db->mutex);
@@ -58259,8 +59355,7 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
 **     sqlite3_column_real()
 **     sqlite3_column_bytes()
 **     sqlite3_column_bytes16()
-**
-** But not for sqlite3_column_blob(), which never calls malloc().
+**     sqiite3_column_blob()
 */
 static void columnMallocFailure(sqlite3_stmt *pStmt)
 {
@@ -58528,6 +59623,12 @@ static int vdbeUnbind(Vdbe *p, int i){
 
   /* If the bit corresponding to this variable in Vdbe.expmask is set, then 
   ** binding a new value to this variable invalidates the current query plan.
+  **
+  ** IMPLEMENTATION-OF: R-48440-37595 If the specific value bound to host
+  ** parameter in the WHERE clause might influence the choice of query plan
+  ** for a statement, then the statement will be automatically recompiled,
+  ** as if there had been a schema change, on the first sqlite3_step() call
+  ** following any change to the bindings of that parameter.
   */
   if( p->isPrepareV2 &&
      ((i<32 && p->expmask & ((u32)1 << i)) || p->expmask==0xffffffff)
@@ -58564,6 +59665,8 @@ static int bindText(
       rc = sqlite3ApiExit(p->db, rc);
     }
     sqlite3_mutex_leave(p->db->mutex);
+  }else if( xDel!=SQLITE_STATIC && xDel!=SQLITE_TRANSIENT ){
+    xDel((void*)zData);
   }
   return rc;
 }
@@ -58807,6 +59910,14 @@ SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt *pStmt){
 }
 
 /*
+** Return true if the prepared statement is guaranteed to not modify the
+** database.
+*/
+SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt){
+  return pStmt ? ((Vdbe*)pStmt)->readOnly : 1;
+}
+
+/*
 ** Return a pointer to the next prepared statement after pStmt associated
 ** with database connection pDb.  If pStmt is NULL, return the first
 ** prepared statement for the database connection.  Return NULL if there
@@ -58880,9 +59991,12 @@ static int findNextHostParameter(const char *zSql, int *pnToken){
 }
 
 /*
-** Return a pointer to a string in memory obtained form sqlite3DbMalloc() which
-** holds a copy of zRawSql but with host parameters expanded to their
-** current bindings.
+** This function returns a pointer to a nul-terminated string in memory
+** obtained from sqlite3DbMalloc(). If sqlite3.vdbeExecCnt is 1, then the
+** string contains a copy of zRawSql but with host parameters expanded to 
+** their current bindings. Or, if sqlite3.vdbeExecCnt is greater than 1, 
+** then the returned string holds a copy of zRawSql with "-- " prepended
+** to each line of text.
 **
 ** The calling function is responsible for making sure the memory returned
 ** is eventually freed.
@@ -58913,63 +60027,72 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
   sqlite3StrAccumInit(&out, zBase, sizeof(zBase), 
                       db->aLimit[SQLITE_LIMIT_LENGTH]);
   out.db = db;
-  while( zRawSql[0] ){
-    n = findNextHostParameter(zRawSql, &nToken);
-    assert( n>0 );
-    sqlite3StrAccumAppend(&out, zRawSql, n);
-    zRawSql += n;
-    assert( zRawSql[0] || nToken==0 );
-    if( nToken==0 ) break;
-    if( zRawSql[0]=='?' ){
-      if( nToken>1 ){
-        assert( sqlite3Isdigit(zRawSql[1]) );
-        sqlite3GetInt32(&zRawSql[1], &idx);
+  if( db->vdbeExecCnt>1 ){
+    while( *zRawSql ){
+      const char *zStart = zRawSql;
+      while( *(zRawSql++)!='\n' && *zRawSql );
+      sqlite3StrAccumAppend(&out, "-- ", 3);
+      sqlite3StrAccumAppend(&out, zStart, zRawSql-zStart);
+    }
+  }else{
+    while( zRawSql[0] ){
+      n = findNextHostParameter(zRawSql, &nToken);
+      assert( n>0 );
+      sqlite3StrAccumAppend(&out, zRawSql, n);
+      zRawSql += n;
+      assert( zRawSql[0] || nToken==0 );
+      if( nToken==0 ) break;
+      if( zRawSql[0]=='?' ){
+        if( nToken>1 ){
+          assert( sqlite3Isdigit(zRawSql[1]) );
+          sqlite3GetInt32(&zRawSql[1], &idx);
+        }else{
+          idx = nextIndex;
+        }
       }else{
-        idx = nextIndex;
-      }
-    }else{
-      assert( zRawSql[0]==':' || zRawSql[0]=='$' || zRawSql[0]=='@' );
-      testcase( zRawSql[0]==':' );
-      testcase( zRawSql[0]=='$' );
-      testcase( zRawSql[0]=='@' );
-      idx = sqlite3VdbeParameterIndex(p, zRawSql, nToken);
-      assert( idx>0 );
-    }
-    zRawSql += nToken;
-    nextIndex = idx + 1;
-    assert( idx>0 && idx<=p->nVar );
-    pVar = &p->aVar[idx-1];
-    if( pVar->flags & MEM_Null ){
-      sqlite3StrAccumAppend(&out, "NULL", 4);
-    }else if( pVar->flags & MEM_Int ){
-      sqlite3XPrintf(&out, "%lld", pVar->u.i);
-    }else if( pVar->flags & MEM_Real ){
-      sqlite3XPrintf(&out, "%!.15g", pVar->r);
-    }else if( pVar->flags & MEM_Str ){
+        assert( zRawSql[0]==':' || zRawSql[0]=='$' || zRawSql[0]=='@' );
+        testcase( zRawSql[0]==':' );
+        testcase( zRawSql[0]=='$' );
+        testcase( zRawSql[0]=='@' );
+        idx = sqlite3VdbeParameterIndex(p, zRawSql, nToken);
+        assert( idx>0 );
+      }
+      zRawSql += nToken;
+      nextIndex = idx + 1;
+      assert( idx>0 && idx<=p->nVar );
+      pVar = &p->aVar[idx-1];
+      if( pVar->flags & MEM_Null ){
+        sqlite3StrAccumAppend(&out, "NULL", 4);
+      }else if( pVar->flags & MEM_Int ){
+        sqlite3XPrintf(&out, "%lld", pVar->u.i);
+      }else if( pVar->flags & MEM_Real ){
+        sqlite3XPrintf(&out, "%!.15g", pVar->r);
+      }else if( pVar->flags & MEM_Str ){
 #ifndef SQLITE_OMIT_UTF16
-      u8 enc = ENC(db);
-      if( enc!=SQLITE_UTF8 ){
-        Mem utf8;
-        memset(&utf8, 0, sizeof(utf8));
-        utf8.db = db;
-        sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, enc, SQLITE_STATIC);
-        sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8);
-        sqlite3XPrintf(&out, "'%.*q'", utf8.n, utf8.z);
-        sqlite3VdbeMemRelease(&utf8);
-      }else
+        u8 enc = ENC(db);
+        if( enc!=SQLITE_UTF8 ){
+          Mem utf8;
+          memset(&utf8, 0, sizeof(utf8));
+          utf8.db = db;
+          sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, enc, SQLITE_STATIC);
+          sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8);
+          sqlite3XPrintf(&out, "'%.*q'", utf8.n, utf8.z);
+          sqlite3VdbeMemRelease(&utf8);
+        }else
 #endif
-      {
-        sqlite3XPrintf(&out, "'%.*q'", pVar->n, pVar->z);
-      }
-    }else if( pVar->flags & MEM_Zero ){
-      sqlite3XPrintf(&out, "zeroblob(%d)", pVar->u.nZero);
-    }else{
-      assert( pVar->flags & MEM_Blob );
-      sqlite3StrAccumAppend(&out, "x'", 2);
-      for(i=0; i<pVar->n; i++){
-        sqlite3XPrintf(&out, "%02x", pVar->z[i]&0xff);
+        {
+          sqlite3XPrintf(&out, "'%.*q'", pVar->n, pVar->z);
+        }
+      }else if( pVar->flags & MEM_Zero ){
+        sqlite3XPrintf(&out, "zeroblob(%d)", pVar->u.nZero);
+      }else{
+        assert( pVar->flags & MEM_Blob );
+        sqlite3StrAccumAppend(&out, "x'", 2);
+        for(i=0; i<pVar->n; i++){
+          sqlite3XPrintf(&out, "%02x", pVar->z[i]&0xff);
+        }
+        sqlite3StrAccumAppend(&out, "'", 1);
       }
-      sqlite3StrAccumAppend(&out, "'", 1);
     }
   }
   return sqlite3StrAccumFinish(&out);
@@ -59026,6 +60149,17 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
 */
 
 /*
+** Invoke this macro on memory cells just prior to changing the
+** value of the cell.  This macro verifies that shallow copies are
+** not misused.
+*/
+#ifdef SQLITE_DEBUG
+# define memAboutToChange(P,M) sqlite3VdbeMemPrepareToChange(P,M)
+#else
+# define memAboutToChange(P,M)
+#endif
+
+/*
 ** The following global variable is incremented every time a cursor
 ** moves, either by the OP_SeekXX, OP_Next, or OP_Prev opcodes.  The test
 ** procedures use this information to make sure that indices are
@@ -59217,31 +60351,17 @@ static VdbeCursor *allocateCursor(
 */
 static void applyNumericAffinity(Mem *pRec){
   if( (pRec->flags & (MEM_Real|MEM_Int))==0 ){
-    int realnum;
+    double rValue;
+    i64 iValue;
     u8 enc = pRec->enc;
-    sqlite3VdbeMemNulTerminate(pRec);
-    if( (pRec->flags&MEM_Str) && sqlite3IsNumber(pRec->z, &realnum, enc) ){
-      i64 value;
-      char *zUtf8 = pRec->z;
-#ifndef SQLITE_OMIT_UTF16
-      if( enc!=SQLITE_UTF8 ){
-        assert( pRec->db );
-        zUtf8 = sqlite3Utf16to8(pRec->db, pRec->z, pRec->n, enc);
-        if( !zUtf8 ) return;
-      }
-#endif
-      if( !realnum && sqlite3Atoi64(zUtf8, &value) ){
-        pRec->u.i = value;
-        MemSetTypeFlag(pRec, MEM_Int);
-      }else{
-        sqlite3AtoF(zUtf8, &pRec->r);
-        MemSetTypeFlag(pRec, MEM_Real);
-      }
-#ifndef SQLITE_OMIT_UTF16
-      if( enc!=SQLITE_UTF8 ){
-        sqlite3DbFree(pRec->db, zUtf8);
-      }
-#endif
+    if( (pRec->flags&MEM_Str)==0 ) return;
+    if( sqlite3AtoF(pRec->z, &rValue, pRec->n, enc)==0 ) return;
+    if( 0==sqlite3Atoi64(pRec->z, &iValue, pRec->n, enc) ){
+      pRec->u.i = iValue;
+      pRec->flags |= MEM_Int;
+    }else{
+      pRec->r = rValue;
+      pRec->flags |= MEM_Real;
     }
   }
 }
@@ -59293,13 +60413,13 @@ static void applyAffinity(
 ** into a numeric representation.  Use either INTEGER or REAL whichever
 ** is appropriate.  But only do the conversion if it is possible without
 ** loss of information and return the revised type of the argument.
-**
-** This is an EXPERIMENTAL api and is subject to change or removal.
 */
 SQLITE_API int sqlite3_value_numeric_type(sqlite3_value *pVal){
   Mem *pMem = (Mem*)pVal;
-  applyNumericAffinity(pMem);
-  sqlite3VdbeMemStoreType(pMem);
+  if( pMem->type==SQLITE_TEXT ){
+    applyNumericAffinity(pMem);
+    sqlite3VdbeMemStoreType(pMem);
+  }
   return pMem->type;
 }
 
@@ -60134,6 +61254,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
       assert( pOp->p2>0 );
       assert( pOp->p2<=p->nMem );
       pOut = &aMem[pOp->p2];
+      memAboutToChange(p, pOut);
       sqlite3VdbeMemReleaseExternal(pOut);
       pOut->flags = MEM_Int;
     }
@@ -60143,25 +61264,30 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
     if( (pOp->opflags & OPFLG_IN1)!=0 ){
       assert( pOp->p1>0 );
       assert( pOp->p1<=p->nMem );
+      assert( memIsValid(&aMem[pOp->p1]) );
       REGISTER_TRACE(pOp->p1, &aMem[pOp->p1]);
     }
     if( (pOp->opflags & OPFLG_IN2)!=0 ){
       assert( pOp->p2>0 );
       assert( pOp->p2<=p->nMem );
+      assert( memIsValid(&aMem[pOp->p2]) );
       REGISTER_TRACE(pOp->p2, &aMem[pOp->p2]);
     }
     if( (pOp->opflags & OPFLG_IN3)!=0 ){
       assert( pOp->p3>0 );
       assert( pOp->p3<=p->nMem );
+      assert( memIsValid(&aMem[pOp->p3]) );
       REGISTER_TRACE(pOp->p3, &aMem[pOp->p3]);
     }
     if( (pOp->opflags & OPFLG_OUT2)!=0 ){
       assert( pOp->p2>0 );
       assert( pOp->p2<=p->nMem );
+      memAboutToChange(p, &aMem[pOp->p2]);
     }
     if( (pOp->opflags & OPFLG_OUT3)!=0 ){
       assert( pOp->p3>0 );
       assert( pOp->p3<=p->nMem );
+      memAboutToChange(p, &aMem[pOp->p3]);
     }
 #endif
   
@@ -60223,6 +61349,7 @@ case OP_Goto: {             /* jump */
 case OP_Gosub: {            /* jump, in1 */
   pIn1 = &aMem[pOp->p1];
   assert( (pIn1->flags & MEM_Dyn)==0 );
+  memAboutToChange(p, pIn1);
   pIn1->flags = MEM_Int;
   pIn1->u.i = pc;
   REGISTER_TRACE(pOp->p1, pIn1);
@@ -60430,11 +61557,7 @@ case OP_Null: {           /* out2-prerelease */
 /* Opcode: Blob P1 P2 * P4
 **
 ** P4 points to a blob of data P1 bytes long.  Store this
-** blob in register P2. This instruction is not coded directly
-** by the compiler. Instead, the compiler layer specifies
-** an OP_HexBlob opcode, with the hex string representation of
-** the blob as P4. This opcode is transformed to an OP_Blob
-** the first time it is executed.
+** blob in register P2.
 */
 case OP_Blob: {                /* out2-prerelease */
   assert( pOp->p1 <= SQLITE_MAX_LENGTH );
@@ -60492,6 +61615,8 @@ case OP_Move: {
   while( u.ac.n-- ){
     assert( pOut<=&aMem[p->nMem] );
     assert( pIn1<=&aMem[p->nMem] );
+    assert( memIsValid(pIn1) );
+    memAboutToChange(p, pOut);
     u.ac.zMalloc = pOut->zMalloc;
     pOut->zMalloc = 0;
     sqlite3VdbeMemMove(pOut, pIn1);
@@ -60537,6 +61662,9 @@ case OP_SCopy: {            /* in1, out2 */
   pOut = &aMem[pOp->p2];
   assert( pOut!=pIn1 );
   sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem);
+#ifdef SQLITE_DEBUG
+  if( pOut->pScopyFrom==0 ) pOut->pScopyFrom = pIn1;
+#endif
   REGISTER_TRACE(pOp->p2, pOut);
   break;
 }
@@ -60597,6 +61725,10 @@ case OP_ResultRow: {
   */
   u.ad.pMem = p->pResultSet = &aMem[pOp->p1];
   for(u.ad.i=0; u.ad.i<pOp->p2; u.ad.i++){
+    assert( memIsValid(&u.ad.pMem[u.ad.i]) );
+    Deephemeralize(&u.ad.pMem[u.ad.i]);
+    assert( (u.ad.pMem[u.ad.i].flags & MEM_Ephem)==0
+            || (u.ad.pMem[u.ad.i].flags & (MEM_Str|MEM_Blob))==0 );
     sqlite3VdbeMemNulTerminate(&u.ad.pMem[u.ad.i]);
     sqlite3VdbeMemStoreType(&u.ad.pMem[u.ad.i]);
     REGISTER_TRACE(pOp->p1+u.ad.i, &u.ad.pMem[u.ad.i]);
@@ -60828,12 +61960,17 @@ case OP_Function: {
   u.ag.n = pOp->p5;
   u.ag.apVal = p->apArg;
   assert( u.ag.apVal || u.ag.n==0 );
+  assert( pOp->p3>0 && pOp->p3<=p->nMem );
+  pOut = &aMem[pOp->p3];
+  memAboutToChange(p, pOut);
 
   assert( u.ag.n==0 || (pOp->p2>0 && pOp->p2+u.ag.n<=p->nMem+1) );
   assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+u.ag.n );
   u.ag.pArg = &aMem[pOp->p2];
   for(u.ag.i=0; u.ag.i<u.ag.n; u.ag.i++, u.ag.pArg++){
+    assert( memIsValid(u.ag.pArg) );
     u.ag.apVal[u.ag.i] = u.ag.pArg;
+    Deephemeralize(u.ag.pArg);
     sqlite3VdbeMemStoreType(u.ag.pArg);
     REGISTER_TRACE(pOp->p2+u.ag.i, u.ag.pArg);
   }
@@ -60847,8 +61984,6 @@ case OP_Function: {
     u.ag.ctx.pFunc = u.ag.ctx.pVdbeFunc->pFunc;
   }
 
-  assert( pOp->p3>0 && pOp->p3<=p->nMem );
-  pOut = &aMem[pOp->p3];
   u.ag.ctx.s.flags = MEM_Null;
   u.ag.ctx.s.db = db;
   u.ag.ctx.s.xDel = 0;
@@ -60868,7 +62003,7 @@ case OP_Function: {
     assert( pOp[-1].opcode==OP_CollSeq );
     u.ag.ctx.pColl = pOp[-1].p4.pColl;
   }
-  (*u.ag.ctx.pFunc->xFunc)(&u.ag.ctx, u.ag.n, u.ag.apVal);
+  (*u.ag.ctx.pFunc->xFunc)(&u.ag.ctx, u.ag.n, u.ag.apVal); /* IMP: R-24505-23230 */
   if( db->mallocFailed ){
     /* Even though a malloc() has failed, the implementation of the
     ** user function may have called an sqlite3_result_XXX() function
@@ -60920,7 +62055,7 @@ case OP_Function: {
 /* Opcode: ShiftLeft P1 P2 P3 * *
 **
 ** Shift the integer value in register P2 to the left by the
-** number of bits specified by the integer in regiser P1.
+** number of bits specified by the integer in register P1.
 ** Store the result in register P3.
 ** If either input is NULL, the result is NULL.
 */
@@ -60970,6 +62105,7 @@ case OP_ShiftRight: {           /* same as TK_RSHIFT, in1, in2, out3 */
 */
 case OP_AddImm: {            /* in1 */
   pIn1 = &aMem[pOp->p1];
+  memAboutToChange(p, pIn1);
   sqlite3VdbeMemIntegerify(pIn1);
   pIn1->u.i += pOp->p2;
   break;
@@ -61029,6 +62165,7 @@ case OP_RealAffinity: {                  /* in1 */
 */
 case OP_ToText: {                  /* same as TK_TO_TEXT, in1 */
   pIn1 = &aMem[pOp->p1];
+  memAboutToChange(p, pIn1);
   if( pIn1->flags & MEM_Null ) break;
   assert( MEM_Str==(MEM_Blob>>3) );
   pIn1->flags |= (pIn1->flags&MEM_Blob)>>3;
@@ -61075,16 +62212,14 @@ case OP_ToBlob: {                  /* same as TK_TO_BLOB, in1 */
 */
 case OP_ToNumeric: {                  /* same as TK_TO_NUMERIC, in1 */
   pIn1 = &aMem[pOp->p1];
-  if( (pIn1->flags & (MEM_Null|MEM_Int|MEM_Real))==0 ){
-    sqlite3VdbeMemNumerify(pIn1);
-  }
+  sqlite3VdbeMemNumerify(pIn1);
   break;
 }
 #endif /* SQLITE_OMIT_CAST */
 
 /* Opcode: ToInt P1 * * * *
 **
-** Force the value in register P1 be an integer.  If
+** Force the value in register P1 to be an integer.  If
 ** The value is currently a real number, drop its fractional part.
 ** If the value is text or blob, try to convert it to an integer using the
 ** equivalent of atoi() and store 0 if no such conversion is possible.
@@ -61111,6 +62246,7 @@ case OP_ToInt: {                  /* same as TK_TO_INT, in1 */
 */
 case OP_ToReal: {                  /* same as TK_TO_REAL, in1 */
   pIn1 = &aMem[pOp->p1];
+  memAboutToChange(p, pIn1);
   if( (pIn1->flags & MEM_Null)==0 ){
     sqlite3VdbeMemRealify(pIn1);
   }
@@ -61125,7 +62261,7 @@ case OP_ToReal: {                  /* same as TK_TO_REAL, in1 */
 **
 ** If the SQLITE_JUMPIFNULL bit of P5 is set and either reg(P1) or
 ** reg(P3) is NULL then take the jump.  If the SQLITE_JUMPIFNULL 
-** bit is clear then fall thru if either operand is NULL.
+** bit is clear then fall through if either operand is NULL.
 **
 ** The SQLITE_AFF_MASK portion of P5 must be an affinity character -
 ** SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER, and so forth. An attempt is made 
@@ -61255,6 +62391,7 @@ case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
 
   if( pOp->p5 & SQLITE_STOREP2 ){
     pOut = &aMem[pOp->p2];
+    memAboutToChange(p, pOut);
     MemSetTypeFlag(pOut, MEM_Int);
     pOut->u.i = u.ai.res;
     REGISTER_TRACE(pOp->p2, pOut);
@@ -61286,8 +62423,8 @@ case OP_Permutation: {
 
 /* Opcode: Compare P1 P2 P3 P4 *
 **
-** Compare to vectors of registers in reg(P1)..reg(P1+P3-1) (all this
-** one "A") and in reg(P2)..reg(P2+P3-1) ("B").  Save the result of
+** Compare two vectors of registers in reg(P1)..reg(P1+P3-1) (call this
+** vector "A") and in reg(P2)..reg(P2+P3-1) ("B").  Save the result of
 ** the comparison for use by the next OP_Jump instruct.
 **
 ** P4 is a KeyInfo structure that defines collating sequences and sort
@@ -61329,6 +62466,8 @@ case OP_Compare: {
 #endif /* SQLITE_DEBUG */
   for(u.aj.i=0; u.aj.i<u.aj.n; u.aj.i++){
     u.aj.idx = aPermute ? aPermute[u.aj.i] : u.aj.i;
+    assert( memIsValid(&aMem[u.aj.p1+u.aj.idx]) );
+    assert( memIsValid(&aMem[u.aj.p2+u.aj.idx]) );
     REGISTER_TRACE(u.aj.p1+u.aj.idx, &aMem[u.aj.p1+u.aj.idx]);
     REGISTER_TRACE(u.aj.p2+u.aj.idx, &aMem[u.aj.p2+u.aj.idx]);
     assert( u.aj.i<u.aj.pKeyInfo->nField );
@@ -61560,6 +62699,7 @@ case OP_Column: {
   assert( u.am.p1<p->nCursor );
   assert( pOp->p3>0 && pOp->p3<=p->nMem );
   u.am.pDest = &aMem[pOp->p3];
+  memAboutToChange(p, u.am.pDest);
   MemSetTypeFlag(u.am.pDest, MEM_Null);
   u.am.zRec = 0;
 
@@ -61607,6 +62747,7 @@ case OP_Column: {
   }else if( u.am.pC->pseudoTableReg>0 ){
     u.am.pReg = &aMem[u.am.pC->pseudoTableReg];
     assert( u.am.pReg->flags & MEM_Blob );
+    assert( memIsValid(u.am.pReg) );
     u.am.payloadSize = u.am.pReg->n;
     u.am.zRec = u.am.pReg->z;
     u.am.pC->cacheStatus = (pOp->p5&OPFLAG_CLEARCACHE) ? CACHE_STALE : p->cacheCtr;
@@ -61831,6 +62972,7 @@ case OP_Affinity: {
   pIn1 = &aMem[pOp->p1];
   while( (u.an.cAff = *(u.an.zAffinity++))!=0 ){
     assert( pIn1 <= &p->aMem[p->nMem] );
+    assert( memIsValid(pIn1) );
     ExpandBlob(pIn1);
     applyAffinity(pIn1, u.an.cAff, encoding);
     pIn1++;
@@ -61840,12 +62982,9 @@ case OP_Affinity: {
 
 /* Opcode: MakeRecord P1 P2 P3 P4 *
 **
-** Convert P2 registers beginning with P1 into a single entry
-** suitable for use as a data record in a database table or as a key
-** in an index.  The details of the format are irrelevant as long as
-** the OP_Column opcode can decode the record later.
-** Refer to source code comments for the details of the record
-** format.
+** Convert P2 registers beginning with P1 into the [record format]
+** use as a data record in a database table or as a key
+** in an index.  The OP_Column opcode can decode the record later.
 **
 ** P4 may be a string that is P2 characters long.  The nth character of the
 ** string indicates the column affinity that should be used for the nth
@@ -61902,10 +63041,16 @@ case OP_MakeRecord: {
   u.ao.pLast = &u.ao.pData0[u.ao.nField-1];
   u.ao.file_format = p->minWriteFileFormat;
 
+  /* Identify the output register */
+  assert( pOp->p3<pOp->p1 || pOp->p3>=pOp->p1+pOp->p2 );
+  pOut = &aMem[pOp->p3];
+  memAboutToChange(p, pOut);
+
   /* Loop through the elements that will make up the record to figure
   ** out how much space is required for the new record.
   */
   for(u.ao.pRec=u.ao.pData0; u.ao.pRec<=u.ao.pLast; u.ao.pRec++){
+    assert( memIsValid(u.ao.pRec) );
     if( u.ao.zAffinity ){
       applyAffinity(u.ao.pRec, u.ao.zAffinity[u.ao.pRec-u.ao.pData0], encoding);
     }
@@ -61940,8 +63085,6 @@ case OP_MakeRecord: {
   ** be one of the input registers (because the following call to
   ** sqlite3VdbeMemGrow() could clobber the value before it is used).
   */
-  assert( pOp->p3<pOp->p1 || pOp->p3>=pOp->p1+pOp->p2 );
-  pOut = &aMem[pOp->p3];
   if( sqlite3VdbeMemGrow(pOut, (int)u.ao.nByte, 0) ){
     goto no_mem;
   }
@@ -62114,6 +63257,7 @@ case OP_Savepoint: {
         if( u.aq.p1==SAVEPOINT_ROLLBACK && (db->flags&SQLITE_InternChanges)!=0 ){
           sqlite3ExpirePreparedStatements(db);
           sqlite3ResetInternalSchema(db, 0);
+          db->flags = (db->flags | SQLITE_InternChanges);
         }
       }
 
@@ -62504,6 +63648,8 @@ case OP_OpenWrite: {
     assert( u.aw.p2>0 );
     assert( u.aw.p2<=p->nMem );
     pIn2 = &aMem[u.aw.p2];
+    assert( memIsValid(pIn2) );
+    assert( (pIn2->flags & MEM_Int)!=0 );
     sqlite3VdbeMemIntegerify(pIn2);
     u.aw.p2 = (int)pIn2->u.i;
     /* The u.aw.p2 value always comes from a prior OP_CreateTable opcode and
@@ -62526,6 +63672,7 @@ case OP_OpenWrite: {
   u.aw.pCur = allocateCursor(p, pOp->p1, u.aw.nField, u.aw.iDb, 1);
   if( u.aw.pCur==0 ) goto no_mem;
   u.aw.pCur->nullRow = 1;
+  u.aw.pCur->isOrdered = 1;
   rc = sqlite3BtreeCursor(u.aw.pX, u.aw.p2, u.aw.wrFlag, u.aw.pKeyInfo, u.aw.pCur->pCursor);
   u.aw.pCur->pKeyInfo = u.aw.pKeyInfo;
 
@@ -62578,7 +63725,7 @@ case OP_OpenEphemeral: {
 #if 0  /* local variables moved into u.ax */
   VdbeCursor *pCx;
 #endif /* local variables moved into u.ax */
-  static const int openFlags =
+  static const int vfsFlags =
       SQLITE_OPEN_READWRITE |
       SQLITE_OPEN_CREATE |
       SQLITE_OPEN_EXCLUSIVE |
@@ -62589,21 +63736,21 @@ case OP_OpenEphemeral: {
   u.ax.pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
   if( u.ax.pCx==0 ) goto no_mem;
   u.ax.pCx->nullRow = 1;
-  rc = sqlite3BtreeFactory(db, 0, 1, SQLITE_DEFAULT_TEMP_CACHE_SIZE, openFlags,
-                           &u.ax.pCx->pBt);
+  rc = sqlite3BtreeOpen(0, db, &u.ax.pCx->pBt,
+                        BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags);
   if( rc==SQLITE_OK ){
     rc = sqlite3BtreeBeginTrans(u.ax.pCx->pBt, 1);
   }
   if( rc==SQLITE_OK ){
     /* If a transient index is required, create it by calling
-    ** sqlite3BtreeCreateTable() with the BTREE_ZERODATA flag before
+    ** sqlite3BtreeCreateTable() with the BTREE_BLOBKEY flag before
     ** opening it. If a transient table is required, just use the
-    ** automatically created table with root-page 1 (an INTKEY table).
+    ** automatically created table with root-page 1 (an BLOB_INTKEY table).
     */
     if( pOp->p4.pKeyInfo ){
       int pgno;
       assert( pOp->p4type==P4_KEYINFO );
-      rc = sqlite3BtreeCreateTable(u.ax.pCx->pBt, &pgno, BTREE_ZERODATA);
+      rc = sqlite3BtreeCreateTable(u.ax.pCx->pBt, &pgno, BTREE_BLOBKEY);
       if( rc==SQLITE_OK ){
         assert( pgno==MASTER_ROOT+1 );
         rc = sqlite3BtreeCursor(u.ax.pCx->pBt, pgno, 1,
@@ -62617,6 +63764,7 @@ case OP_OpenEphemeral: {
       u.ax.pCx->isTable = 1;
     }
   }
+  u.ax.pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
   u.ax.pCx->isIndex = !u.ax.pCx->isTable;
   break;
 }
@@ -62736,6 +63884,7 @@ case OP_SeekGt: {       /* jump, in3 */
   assert( OP_SeekLe == OP_SeekLt+1 );
   assert( OP_SeekGe == OP_SeekLt+2 );
   assert( OP_SeekGt == OP_SeekLt+3 );
+  assert( u.az.pC->isOrdered );
   if( u.az.pC->pCursor!=0 ){
     u.az.oc = pOp->opcode;
     u.az.pC->nullRow = 0;
@@ -62818,6 +63967,9 @@ case OP_SeekGt: {       /* jump, in3 */
       assert( u.az.oc!=OP_SeekLt || u.az.r.flags==0 );
 
       u.az.r.aMem = &aMem[pOp->p3];
+#ifdef SQLITE_DEBUG
+      { int i; for(i=0; i<u.az.r.nField; i++) assert( memIsValid(&u.az.r.aMem[i]) ); }
+#endif
       ExpandBlob(u.az.r.aMem);
       rc = sqlite3BtreeMovetoUnpacked(u.az.pC->pCursor, &u.az.r, 0, 0, &u.az.res);
       if( rc!=SQLITE_OK ){
@@ -62946,11 +64098,14 @@ case OP_Found: {        /* jump, in3 */
       u.bb.r.pKeyInfo = u.bb.pC->pKeyInfo;
       u.bb.r.nField = (u16)pOp->p4.i;
       u.bb.r.aMem = pIn3;
+#ifdef SQLITE_DEBUG
+      { int i; for(i=0; i<u.bb.r.nField; i++) assert( memIsValid(&u.bb.r.aMem[i]) ); }
+#endif
       u.bb.r.flags = UNPACKED_PREFIX_MATCH;
       u.bb.pIdxKey = &u.bb.r;
     }else{
       assert( pIn3->flags & MEM_Blob );
-      ExpandBlob(pIn3);
+      assert( (pIn3->flags & MEM_Zero)==0 );  /* zeroblobs already expanded */
       u.bb.pIdxKey = sqlite3VdbeRecordUnpack(u.bb.pC->pKeyInfo, pIn3->n, pIn3->z,
                                         u.bb.aTempRec, sizeof(u.bb.aTempRec));
       if( u.bb.pIdxKey==0 ){
@@ -63045,6 +64200,9 @@ case OP_IsUnique: {        /* jump, in3 */
     u.bc.r.nField = u.bc.nField + 1;
     u.bc.r.flags = UNPACKED_PREFIX_SEARCH;
     u.bc.r.aMem = u.bc.aMx;
+#ifdef SQLITE_DEBUG
+    { int i; for(i=0; i<u.bc.r.nField; i++) assert( memIsValid(&u.bc.r.aMem[i]) ); }
+#endif
 
     /* Extract the value of u.bc.R from register P3. */
     sqlite3VdbeMemIntegerify(pIn3);
@@ -63067,7 +64225,7 @@ case OP_IsUnique: {        /* jump, in3 */
 **
 ** Use the content of register P3 as a integer key.  If a record 
 ** with that key does not exist in table of P1, then jump to P2. 
-** If the record does exist, then fall thru.  The cursor is left 
+** If the record does exist, then fall through.  The cursor is left 
 ** pointing to the record if it exists.
 **
 ** The difference between this operation and NotFound is that this
@@ -63225,7 +64383,9 @@ case OP_NewRowid: {           /* out2-prerelease */
           /* Assert that P3 is a valid memory cell. */
           assert( pOp->p3<=p->nMem );
           u.be.pMem = &aMem[pOp->p3];
+          memAboutToChange(p, u.be.pMem);
         }
+        assert( memIsValid(u.be.pMem) );
 
         REGISTER_TRACE(pOp->p3, u.be.pMem);
         sqlite3VdbeMemIntegerify(u.be.pMem);
@@ -63244,29 +64404,36 @@ case OP_NewRowid: {           /* out2-prerelease */
       sqlite3BtreeSetCachedRowid(u.be.pC->pCursor, u.be.v<MAX_ROWID ? u.be.v+1 : 0);
     }
     if( u.be.pC->useRandomRowid ){
-      /* IMPLEMENTATION-OF: R-48598-02938 If the largest ROWID is equal to the
+      /* IMPLEMENTATION-OF: R-07677-41881 If the largest ROWID is equal to the
       ** largest possible integer (9223372036854775807) then the database
-      ** engine starts picking candidate ROWIDs at random until it finds one
-      ** that is not previously used.
-      */
+      ** engine starts picking positive candidate ROWIDs at random until
+      ** it finds one that is not previously used. */
       assert( pOp->p3==0 );  /* We cannot be in random rowid mode if this is
                              ** an AUTOINCREMENT table. */
+      /* on the first attempt, simply do one more than previous */
       u.be.v = db->lastRowid;
+      u.be.v &= (MAX_ROWID>>1); /* ensure doesn't go negative */
+      u.be.v++; /* ensure non-zero */
       u.be.cnt = 0;
-      do{
-        if( u.be.cnt==0 && (u.be.v&0xffffff)==u.be.v ){
-          u.be.v++;
+      while(   ((rc = sqlite3BtreeMovetoUnpacked(u.be.pC->pCursor, 0, (u64)u.be.v,
+                                                 0, &u.be.res))==SQLITE_OK)
+            && (u.be.res==0)
+            && (++u.be.cnt<100)){
+        /* collision - try another random rowid */
+        sqlite3_randomness(sizeof(u.be.v), &u.be.v);
+        if( u.be.cnt<5 ){
+          /* try "small" random rowids for the initial attempts */
+          u.be.v &= 0xffffff;
         }else{
-          sqlite3_randomness(sizeof(u.be.v), &u.be.v);
-          if( u.be.cnt<5 ) u.be.v &= 0xffffff;
+          u.be.v &= (MAX_ROWID>>1); /* ensure doesn't go negative */
         }
-        rc = sqlite3BtreeMovetoUnpacked(u.be.pC->pCursor, 0, (u64)u.be.v, 0, &u.be.res);
-        u.be.cnt++;
-      }while( u.be.cnt<100 && rc==SQLITE_OK && u.be.res==0 );
+        u.be.v++; /* ensure non-zero */
+      }
       if( rc==SQLITE_OK && u.be.res==0 ){
         rc = SQLITE_FULL;   /* IMP: R-38219-53002 */
         goto abort_due_to_error;
       }
+      assert( u.be.v>0 );  /* EV: R-40812-03570 */
     }
     u.be.pC->rowidIsValid = 0;
     u.be.pC->deferredMoveto = 0;
@@ -63336,6 +64503,7 @@ case OP_InsertInt: {
 
   u.bf.pData = &aMem[pOp->p2];
   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+  assert( memIsValid(u.bf.pData) );
   u.bf.pC = p->apCsr[pOp->p1];
   assert( u.bf.pC!=0 );
   assert( u.bf.pC->pCursor!=0 );
@@ -63346,6 +64514,7 @@ case OP_InsertInt: {
   if( pOp->opcode==OP_Insert ){
     u.bf.pKey = &aMem[pOp->p3];
     assert( u.bf.pKey->flags & MEM_Int );
+    assert( memIsValid(u.bf.pKey) );
     REGISTER_TRACE(pOp->p3, u.bf.pKey);
     u.bf.iKey = u.bf.pKey->u.i;
   }else{
@@ -63497,6 +64666,7 @@ case OP_RowData: {
 #endif /* local variables moved into u.bh */
 
   pOut = &aMem[pOp->p2];
+  memAboutToChange(p, pOut);
 
   /* Note that RowKey and RowData are really exactly the same instruction */
   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
@@ -63839,6 +65009,9 @@ case OP_IdxDelete: {
     u.bo.r.nField = (u16)pOp->p3;
     u.bo.r.flags = 0;
     u.bo.r.aMem = &aMem[pOp->p2];
+#ifdef SQLITE_DEBUG
+    { int i; for(i=0; i<u.bo.r.nField; i++) assert( memIsValid(&u.bo.r.aMem[i]) ); }
+#endif
     rc = sqlite3BtreeMovetoUnpacked(u.bo.pCrsr, &u.bo.r, 0, 0, &u.bo.res);
     if( rc==SQLITE_OK && u.bo.res==0 ){
       rc = sqlite3BtreeDelete(u.bo.pCrsr);
@@ -63923,6 +65096,7 @@ case OP_IdxGE: {        /* jump */
   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
   u.bq.pC = p->apCsr[pOp->p1];
   assert( u.bq.pC!=0 );
+  assert( u.bq.pC->isOrdered );
   if( ALWAYS(u.bq.pC->pCursor!=0) ){
     assert( u.bq.pC->deferredMoveto==0 );
     assert( pOp->p5==0 || pOp->p5==1 );
@@ -63935,6 +65109,9 @@ case OP_IdxGE: {        /* jump */
       u.bq.r.flags = UNPACKED_IGNORE_ROWID;
     }
     u.bq.r.aMem = &aMem[pOp->p3];
+#ifdef SQLITE_DEBUG
+    { int i; for(i=0; i<u.bq.r.nField; i++) assert( memIsValid(&u.bq.r.aMem[i]) ); }
+#endif
     rc = sqlite3VdbeIdxKeyCompare(u.bq.pC, &u.bq.r, &u.bq.res);
     if( pOp->opcode==OP_IdxLT ){
       u.bq.res = -u.bq.res;
@@ -64038,6 +65215,8 @@ case OP_Clear: {
   if( pOp->p3 ){
     p->nChange += u.bs.nChange;
     if( pOp->p3>0 ){
+      assert( memIsValid(&aMem[pOp->p3]) );
+      memAboutToChange(p, &aMem[pOp->p3]);
       aMem[pOp->p3].u.i += u.bs.nChange;
     }
   }
@@ -64081,9 +65260,9 @@ case OP_CreateTable: {          /* out2-prerelease */
   assert( u.bt.pDb->pBt!=0 );
   if( pOp->opcode==OP_CreateTable ){
     /* u.bt.flags = BTREE_INTKEY; */
-    u.bt.flags = BTREE_LEAFDATA|BTREE_INTKEY;
+    u.bt.flags = BTREE_INTKEY;
   }else{
-    u.bt.flags = BTREE_ZERODATA;
+    u.bt.flags = BTREE_BLOBKEY;
   }
   rc = sqlite3BtreeCreateTable(u.bt.pDb->pBt, &u.bt.pgno, u.bt.flags);
   pOut->u.i = u.bt.pgno;
@@ -64412,6 +65591,7 @@ case OP_Program: {        /* jump */
 
   u.by.pProgram = pOp->p4.pProgram;
   u.by.pRt = &aMem[pOp->p3];
+  assert( memIsValid(u.by.pRt) );
   assert( u.by.pProgram->nOp>0 );
 
   /* If the p5 flag is clear, then recursive invocation of triggers is
@@ -64585,6 +65765,7 @@ case OP_MemMax: {        /* in2 */
   }else{
     u.ca.pIn1 = &aMem[pOp->p1];
   }
+  assert( memIsValid(u.ca.pIn1) );
   sqlite3VdbeMemIntegerify(u.ca.pIn1);
   pIn2 = &aMem[pOp->p2];
   sqlite3VdbeMemIntegerify(pIn2);
@@ -64671,7 +65852,9 @@ case OP_AggStep: {
   u.cb.apVal = p->apArg;
   assert( u.cb.apVal || u.cb.n==0 );
   for(u.cb.i=0; u.cb.i<u.cb.n; u.cb.i++, u.cb.pRec++){
+    assert( memIsValid(u.cb.pRec) );
     u.cb.apVal[u.cb.i] = u.cb.pRec;
+    memAboutToChange(p, u.cb.pRec);
     sqlite3VdbeMemStoreType(u.cb.pRec);
   }
   u.cb.ctx.pFunc = pOp->p4.pFunc;
@@ -64691,7 +65874,7 @@ case OP_AggStep: {
     assert( pOp[-1].opcode==OP_CollSeq );
     u.cb.ctx.pColl = pOp[-1].p4.pColl;
   }
-  (u.cb.ctx.pFunc->xStep)(&u.cb.ctx, u.cb.n, u.cb.apVal);
+  (u.cb.ctx.pFunc->xStep)(&u.cb.ctx, u.cb.n, u.cb.apVal); /* IMP: R-24505-23230 */
   if( u.cb.ctx.isError ){
     sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&u.cb.ctx.s));
     rc = u.cb.ctx.isError;
@@ -65078,6 +66261,7 @@ case OP_VFilter: {   /* jump */
   u.ch.pQuery = &aMem[pOp->p3];
   u.ch.pArgc = &u.ch.pQuery[1];
   u.ch.pCur = p->apCsr[pOp->p1];
+  assert( memIsValid(u.ch.pQuery) );
   REGISTER_TRACE(pOp->p3, u.ch.pQuery);
   assert( u.ch.pCur->pVtabCursor );
   u.ch.pVtabCursor = u.ch.pCur->pVtabCursor;
@@ -65135,6 +66319,7 @@ case OP_VColumn: {
   assert( pCur->pVtabCursor );
   assert( pOp->p3>0 && pOp->p3<=p->nMem );
   u.ci.pDest = &aMem[pOp->p3];
+  memAboutToChange(p, u.ci.pDest);
   if( pCur->nullRow ){
     sqlite3VdbeMemSetNull(u.ci.pDest);
     break;
@@ -65237,10 +66422,12 @@ case OP_VRename: {
   u.ck.pVtab = pOp->p4.pVtab->pVtab;
   u.ck.pName = &aMem[pOp->p1];
   assert( u.ck.pVtab->pModule->xRename );
+  assert( memIsValid(u.ck.pName) );
   REGISTER_TRACE(pOp->p1, u.ck.pName);
   assert( u.ck.pName->flags & MEM_Str );
   rc = u.ck.pVtab->pModule->xRename(u.ck.pVtab, u.ck.pName->z);
   importVtabErrMsg(p, u.ck.pVtab);
+  p->expired = 0;
 
   break;
 }
@@ -65289,6 +66476,8 @@ case OP_VUpdate: {
     u.cl.apArg = p->apArg;
     u.cl.pX = &aMem[pOp->p3];
     for(u.cl.i=0; u.cl.i<u.cl.nArg; u.cl.i++){
+      assert( memIsValid(u.cl.pX) );
+      memAboutToChange(p, u.cl.pX);
       sqlite3VdbeMemStoreType(u.cl.pX);
       u.cl.apArg[u.cl.i] = u.cl.pX;
       u.cl.pX++;
@@ -65316,6 +66505,32 @@ case OP_Pagecount: {            /* out2-prerelease */
 }
 #endif
 
+
+#ifndef  SQLITE_OMIT_PAGER_PRAGMAS
+/* Opcode: MaxPgcnt P1 P2 P3 * *
+**
+** Try to set the maximum page count for database P1 to the value in P3.
+** Do not let the maximum page count fall below the current page count and
+** do not change the maximum page count value if P3==0.
+**
+** Store the maximum page count after the change in register P2.
+*/
+case OP_MaxPgcnt: {            /* out2-prerelease */
+  unsigned int newMax;
+  Btree *pBt;
+
+  pBt = db->aDb[pOp->p1].pBt;
+  newMax = 0;
+  if( pOp->p3 ){
+    newMax = sqlite3BtreeLastPage(pBt);
+    if( newMax < (unsigned)pOp->p3 ) newMax = (unsigned)pOp->p3;
+  }
+  pOut->u.i = sqlite3BtreeMaxPageCount(pBt, newMax);
+  break;
+}
+#endif
+
+
 #ifndef SQLITE_OMIT_TRACE
 /* Opcode: Trace * * * P4 *
 **
@@ -65490,11 +66705,82 @@ struct Incrblob {
   int flags;              /* Copy of "flags" passed to sqlite3_blob_open() */
   int nByte;              /* Size of open blob, in bytes */
   int iOffset;            /* Byte offset of blob in cursor data */
+  int iCol;               /* Table column this handle is open on */
   BtCursor *pCsr;         /* Cursor pointing at blob row */
   sqlite3_stmt *pStmt;    /* Statement holding cursor open */
   sqlite3 *db;            /* The associated database */
 };
 
+
+/*
+** This function is used by both blob_open() and blob_reopen(). It seeks
+** the b-tree cursor associated with blob handle p to point to row iRow.
+** If successful, SQLITE_OK is returned and subsequent calls to
+** sqlite3_blob_read() or sqlite3_blob_write() access the specified row.
+**
+** If an error occurs, or if the specified row does not exist or does not
+** contain a value of type TEXT or BLOB in the column nominated when the
+** blob handle was opened, then an error code is returned and *pzErr may
+** be set to point to a buffer containing an error message. It is the
+** responsibility of the caller to free the error message buffer using
+** sqlite3DbFree().
+**
+** If an error does occur, then the b-tree cursor is closed. All subsequent
+** calls to sqlite3_blob_read(), blob_write() or blob_reopen() will 
+** immediately return SQLITE_ABORT.
+*/
+static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
+  int rc;                         /* Error code */
+  char *zErr = 0;                 /* Error message */
+  Vdbe *v = (Vdbe *)p->pStmt;
+
+  /* Set the value of the SQL statements only variable to integer iRow. 
+  ** This is done directly instead of using sqlite3_bind_int64() to avoid 
+  ** triggering asserts related to mutexes.
+  */
+  assert( v->aVar[0].flags&MEM_Int );
+  v->aVar[0].u.i = iRow;
+
+  rc = sqlite3_step(p->pStmt);
+  if( rc==SQLITE_ROW ){
+    u32 type = v->apCsr[0]->aType[p->iCol];
+    if( type<12 ){
+      zErr = sqlite3MPrintf(p->db, "cannot open value of type %s",
+          type==0?"null": type==7?"real": "integer"
+      );
+      rc = SQLITE_ERROR;
+      sqlite3_finalize(p->pStmt);
+      p->pStmt = 0;
+    }else{
+      p->iOffset = v->apCsr[0]->aOffset[p->iCol];
+      p->nByte = sqlite3VdbeSerialTypeLen(type);
+      p->pCsr =  v->apCsr[0]->pCursor;
+      sqlite3BtreeEnterCursor(p->pCsr);
+      sqlite3BtreeCacheOverflow(p->pCsr);
+      sqlite3BtreeLeaveCursor(p->pCsr);
+    }
+  }
+
+  if( rc==SQLITE_ROW ){
+    rc = SQLITE_OK;
+  }else if( p->pStmt ){
+    rc = sqlite3_finalize(p->pStmt);
+    p->pStmt = 0;
+    if( rc==SQLITE_OK ){
+      zErr = sqlite3MPrintf(p->db, "no such rowid: %lld", iRow);
+      rc = SQLITE_ERROR;
+    }else{
+      zErr = sqlite3MPrintf(p->db, "%s", sqlite3_errmsg(p->db));
+    }
+  }
+
+  assert( rc!=SQLITE_OK || zErr==0 );
+  assert( rc!=SQLITE_ROW && rc!=SQLITE_DONE );
+
+  *pzErr = zErr;
+  return rc;
+}
+
 /*
 ** Open a blob handle.
 */
@@ -65535,29 +66821,35 @@ SQLITE_API int sqlite3_blob_open(
     {OP_OpenWrite, 0, 0, 0},       /* 4: Open cursor 0 for read/write */
 
     {OP_Variable, 1, 1, 1},        /* 5: Push the rowid to the stack */
-    {OP_NotExists, 0, 9, 1},       /* 6: Seek the cursor */
+    {OP_NotExists, 0, 10, 1},      /* 6: Seek the cursor */
     {OP_Column, 0, 0, 1},          /* 7  */
     {OP_ResultRow, 1, 0, 0},       /* 8  */
-    {OP_Close, 0, 0, 0},           /* 9  */
-    {OP_Halt, 0, 0, 0},            /* 10 */
+    {OP_Goto, 0, 5, 0},            /* 9  */
+    {OP_Close, 0, 0, 0},           /* 10 */
+    {OP_Halt, 0, 0, 0},            /* 11 */
   };
 
-  Vdbe *v = 0;
   int rc = SQLITE_OK;
   char *zErr = 0;
   Table *pTab;
-  Parse *pParse;
+  Parse *pParse = 0;
+  Incrblob *pBlob = 0;
 
+  flags = !!flags;                /* flags = (flags ? 1 : 0); */
   *ppBlob = 0;
+
   sqlite3_mutex_enter(db->mutex);
+
+  pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob));
+  if( !pBlob ) goto blob_open_out;
   pParse = sqlite3StackAllocRaw(db, sizeof(*pParse));
-  if( pParse==0 ){
-    rc = SQLITE_NOMEM;
-    goto blob_open_out;
-  }
+  if( !pParse ) goto blob_open_out;
+
   do {
     memset(pParse, 0, sizeof(Parse));
     pParse->db = db;
+    sqlite3DbFree(db, zErr);
+    zErr = 0;
 
     sqlite3BtreeEnterAll(db);
     pTab = sqlite3LocateTable(pParse, 0, zTable, zDb);
@@ -65583,7 +66875,7 @@ SQLITE_API int sqlite3_blob_open(
     }
 
     /* Now search pTab for the exact column. */
-    for(iCol=0; iCol < pTab->nCol; iCol++) {
+    for(iCol=0; iCol<pTab->nCol; iCol++) {
       if( sqlite3StrICmp(pTab->aCol[iCol].zName, zColumn)==0 ){
         break;
       }
@@ -65637,11 +66929,14 @@ SQLITE_API int sqlite3_blob_open(
       }
     }
 
-    v = sqlite3VdbeCreate(db);
-    if( v ){
+    pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(db);
+    assert( pBlob->pStmt || db->mallocFailed );
+    if( pBlob->pStmt ){
+      Vdbe *v = (Vdbe *)pBlob->pStmt;
       int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
+
       sqlite3VdbeAddOpList(v, sizeof(openBlob)/sizeof(VdbeOpList), openBlob);
-      flags = !!flags;                 /* flags = (flags ? 1 : 0); */
+
 
       /* Configure the OP_Transaction */
       sqlite3VdbeChangeP1(v, 0, iDb);
@@ -65684,65 +66979,25 @@ SQLITE_API int sqlite3_blob_open(
       }
     }
    
+    pBlob->flags = flags;
+    pBlob->iCol = iCol;
+    pBlob->db = db;
     sqlite3BtreeLeaveAll(db);
     if( db->mallocFailed ){
       goto blob_open_out;
     }
-
-    sqlite3_bind_int64((sqlite3_stmt *)v, 1, iRow);
-    rc = sqlite3_step((sqlite3_stmt *)v);
-    if( rc!=SQLITE_ROW ){
-      nAttempt++;
-      rc = sqlite3_finalize((sqlite3_stmt *)v);
-      sqlite3DbFree(db, zErr);
-      zErr = sqlite3MPrintf(db, sqlite3_errmsg(db));
-      v = 0;
-    }
-  } while( nAttempt<5 && rc==SQLITE_SCHEMA );
-
-  if( rc==SQLITE_ROW ){
-    /* The row-record has been opened successfully. Check that the
-    ** column in question contains text or a blob. If it contains
-    ** text, it is up to the caller to get the encoding right.
-    */
-    Incrblob *pBlob;
-    u32 type = v->apCsr[0]->aType[iCol];
-
-    if( type<12 ){
-      sqlite3DbFree(db, zErr);
-      zErr = sqlite3MPrintf(db, "cannot open value of type %s",
-          type==0?"null": type==7?"real": "integer"
-      );
-      rc = SQLITE_ERROR;
-      goto blob_open_out;
-    }
-    pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob));
-    if( db->mallocFailed ){
-      sqlite3DbFree(db, pBlob);
-      goto blob_open_out;
-    }
-    pBlob->flags = flags;
-    pBlob->pCsr =  v->apCsr[0]->pCursor;
-    sqlite3BtreeEnterCursor(pBlob->pCsr);
-    sqlite3BtreeCacheOverflow(pBlob->pCsr);
-    sqlite3BtreeLeaveCursor(pBlob->pCsr);
-    pBlob->pStmt = (sqlite3_stmt *)v;
-    pBlob->iOffset = v->apCsr[0]->aOffset[iCol];
-    pBlob->nByte = sqlite3VdbeSerialTypeLen(type);
-    pBlob->db = db;
-    *ppBlob = (sqlite3_blob *)pBlob;
-    rc = SQLITE_OK;
-  }else if( rc==SQLITE_OK ){
-    sqlite3DbFree(db, zErr);
-    zErr = sqlite3MPrintf(db, "no such rowid: %lld", iRow);
-    rc = SQLITE_ERROR;
-  }
+    sqlite3_bind_int64(pBlob->pStmt, 1, iRow);
+    rc = blobSeekToRow(pBlob, iRow, &zErr);
+  } while( (++nAttempt)<5 && rc==SQLITE_SCHEMA );
 
 blob_open_out:
-  if( v && (rc!=SQLITE_OK || db->mallocFailed) ){
-    sqlite3VdbeFinalize(v);
+  if( rc==SQLITE_OK && db->mallocFailed==0 ){
+    *ppBlob = (sqlite3_blob *)pBlob;
+  }else{
+    if( pBlob && pBlob->pStmt ) sqlite3VdbeFinalize((Vdbe *)pBlob->pStmt);
+    sqlite3DbFree(db, pBlob);
   }
-  sqlite3Error(db, rc, zErr);
+  sqlite3Error(db, rc, (zErr ? "%s" : 0), zErr);
   sqlite3DbFree(db, zErr);
   sqlite3StackFree(db, pParse);
   rc = sqlite3ApiExit(db, rc);
@@ -65795,7 +67050,7 @@ static int blobReadWrite(
     /* Request is out of range. Return a transient error. */
     rc = SQLITE_ERROR;
     sqlite3Error(db, SQLITE_ERROR, 0);
-  } else if( v==0 ){
+  }else if( v==0 ){
     /* If there is no statement handle, then the blob-handle has
     ** already been invalidated. Return SQLITE_ABORT in this case.
     */
@@ -65843,7 +67098,47 @@ SQLITE_API int sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int
 */
 SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *pBlob){
   Incrblob *p = (Incrblob *)pBlob;
-  return p ? p->nByte : 0;
+  return (p && p->pStmt) ? p->nByte : 0;
+}
+
+/*
+** Move an existing blob handle to point to a different row of the same
+** database table.
+**
+** If an error occurs, or if the specified row does not exist or does not
+** contain a blob or text value, then an error code is returned and the
+** database handle error code and message set. If this happens, then all 
+** subsequent calls to sqlite3_blob_xxx() functions (except blob_close()) 
+** immediately return SQLITE_ABORT.
+*/
+SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
+  int rc;
+  Incrblob *p = (Incrblob *)pBlob;
+  sqlite3 *db;
+
+  if( p==0 ) return SQLITE_MISUSE_BKPT;
+  db = p->db;
+  sqlite3_mutex_enter(db->mutex);
+
+  if( p->pStmt==0 ){
+    /* If there is no statement handle, then the blob-handle has
+    ** already been invalidated. Return SQLITE_ABORT in this case.
+    */
+    rc = SQLITE_ABORT;
+  }else{
+    char *zErr;
+    rc = blobSeekToRow(p, iRow, &zErr);
+    if( rc!=SQLITE_OK ){
+      sqlite3Error(db, rc, (zErr ? "%s" : 0), zErr);
+      sqlite3DbFree(db, zErr);
+    }
+    assert( rc!=SQLITE_SCHEMA );
+  }
+
+  rc = sqlite3ApiExit(db, rc);
+  assert( rc==SQLITE_OK || p->pStmt==0 );
+  sqlite3_mutex_leave(db->mutex);
+  return rc;
 }
 
 #endif /* #ifndef SQLITE_OMIT_INCRBLOB */
@@ -66343,8 +67638,7 @@ SQLITE_PRIVATE int sqlite3IsMemJournal(sqlite3_file *pJfd){
 }
 
 /* 
-** Return the number of bytes required to store a MemJournal that uses vfs
-** pVfs to create the underlying on-disk files.
+** Return the number of bytes required to store a MemJournal file descriptor.
 */
 SQLITE_PRIVATE int sqlite3MemJournalSize(void){
   return sizeof(MemJournal);
@@ -68177,6 +69471,9 @@ SQLITE_PRIVATE Expr *sqlite3PExpr(
 ){
   Expr *p = sqlite3ExprAlloc(pParse->db, op, pToken, 1);
   sqlite3ExprAttachSubtrees(pParse->db, p, pLeft, pRight);
+  if( p ) {
+    sqlite3ExprCheckHeight(pParse, p->nHeight);
+  }
   return p;
 }
 
@@ -68248,7 +69545,7 @@ SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
     /* Wildcard of the form "?nnn".  Convert "nnn" to an integer and
     ** use it as the variable number */
     i64 i;
-    int bOk = sqlite3Atoi64(&z[1], &i);
+    int bOk = 0==sqlite3Atoi64(&z[1], &i, sqlite3Strlen30(&z[1]), SQLITE_UTF8);
     pExpr->iColumn = (ynVar)i;
     testcase( i==0 );
     testcase( i==1 );
@@ -69228,8 +70525,8 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
 #endif
 
 /*
-** Generate code for scalar subqueries used as an expression
-** and IN operators.  Examples:
+** Generate code for scalar subqueries used as a subquery expression, EXISTS,
+** or IN operators.  Examples:
 **
 **     (SELECT a FROM b)          -- subquery
 **     EXISTS (SELECT a FROM b)   -- EXISTS subquery
@@ -69290,12 +70587,22 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
     assert( testAddr>0 || pParse->db->mallocFailed );
   }
 
+#ifndef SQLITE_OMIT_EXPLAIN
+  if( pParse->explain==2 ){
+    char *zMsg = sqlite3MPrintf(
+        pParse->db, "EXECUTE %s%s SUBQUERY %d", testAddr?"":"CORRELATED ",
+        pExpr->op==TK_IN?"LIST":"SCALAR", pParse->iNextSelectId
+    );
+    sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC);
+  }
+#endif
+
   switch( pExpr->op ){
     case TK_IN: {
-      char affinity;
-      KeyInfo keyInfo;
-      int addr;        /* Address of OP_OpenEphemeral instruction */
-      Expr *pLeft = pExpr->pLeft;
+      char affinity;              /* Affinity of the LHS of the IN */
+      KeyInfo keyInfo;            /* Keyinfo for the generated table */
+      int addr;                   /* Address of OP_OpenEphemeral instruction */
+      Expr *pLeft = pExpr->pLeft; /* the LHS of the IN operator */
 
       if( rMayHaveNull ){
         sqlite3VdbeAddOp2(v, OP_Null, 0, rMayHaveNull);
@@ -69318,6 +70625,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
       */
       pExpr->iTable = pParse->nTab++;
       addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pExpr->iTable, !isRowid);
+      if( rMayHaveNull==0 ) sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
       memset(&keyInfo, 0, sizeof(keyInfo));
       keyInfo.nField = 1;
 
@@ -69334,6 +70642,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
         sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
         dest.affinity = (u8)affinity;
         assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
+        pExpr->x.pSelect->iLimit = 0;
         if( sqlite3Select(pParse, pExpr->x.pSelect, &dest) ){
           return 0;
         }
@@ -69434,6 +70743,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
       sqlite3ExprDelete(pParse->db, pSel->pLimit);
       pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0,
                                   &sqlite3IntTokens[1]);
+      pSel->iLimit = 0;
       if( sqlite3Select(pParse, pSel, &dest) ){
         return 0;
       }
@@ -69610,7 +70920,7 @@ static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){
   if( ALWAYS(z!=0) ){
     double value;
     char *zV;
-    sqlite3AtoF(z, &value);
+    sqlite3AtoF(z, &value, sqlite3Strlen30(z), SQLITE_UTF8);
     assert( !sqlite3IsNaN(value) ); /* The new AtoF never returns NaN */
     if( negateFlag ) value = -value;
     zV = dup8bytes(v, (char*)&value);
@@ -69624,9 +70934,7 @@ static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){
 ** Generate an instruction that will put the integer describe by
 ** text z[0..n-1] into register iMem.
 **
-** The z[] string will probably not be zero-terminated.  But the 
-** z[n] character is guaranteed to be something that does not look
-** like the continuation of the number.
+** Expr.u.zToken is always UTF8 and zero-terminated.
 */
 static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
   Vdbe *v = pParse->pVdbe;
@@ -69635,13 +70943,14 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
     if( negFlag ) i = -i;
     sqlite3VdbeAddOp2(v, OP_Integer, i, iMem);
   }else{
+    int c;
+    i64 value;
     const char *z = pExpr->u.zToken;
     assert( z!=0 );
-    if( sqlite3FitsIn64Bits(z, negFlag) ){
-      i64 value;
+    c = sqlite3Atoi64(z, &value, sqlite3Strlen30(z), SQLITE_UTF8);
+    if( c==0 || (c==2 && negFlag) ){
       char *zV;
-      sqlite3Atoi64(z, &value);
-      if( negFlag ) value = -value;
+      if( negFlag ){ value = -value; }
       zV = dup8bytes(v, (char*)&value);
       sqlite3VdbeAddOp4(v, OP_Int64, 0, iMem, 0, zV, P4_INT64);
     }else{
@@ -69927,73 +71236,6 @@ static int usedAsColumnCache(Parse *pParse, int iFrom, int iTo){
 #endif /* SQLITE_DEBUG || SQLITE_COVERAGE_TEST */
 
 /*
-** If the last instruction coded is an ephemeral copy of any of
-** the registers in the nReg registers beginning with iReg, then
-** convert the last instruction from OP_SCopy to OP_Copy.
-*/
-SQLITE_PRIVATE void sqlite3ExprHardCopy(Parse *pParse, int iReg, int nReg){
-  VdbeOp *pOp;
-  Vdbe *v;
-
-  assert( pParse->db->mallocFailed==0 );
-  v = pParse->pVdbe;
-  assert( v!=0 );
-  pOp = sqlite3VdbeGetOp(v, -1);
-  assert( pOp!=0 );
-  if( pOp->opcode==OP_SCopy && pOp->p1>=iReg && pOp->p1<iReg+nReg ){
-    pOp->opcode = OP_Copy;
-  }
-}
-
-/*
-** Generate code to store the value of the iAlias-th alias in register
-** target.  The first time this is called, pExpr is evaluated to compute
-** the value of the alias.  The value is stored in an auxiliary register
-** and the number of that register is returned.  On subsequent calls,
-** the register number is returned without generating any code.
-**
-** Note that in order for this to work, code must be generated in the
-** same order that it is executed.
-**
-** Aliases are numbered starting with 1.  So iAlias is in the range
-** of 1 to pParse->nAlias inclusive.  
-**
-** pParse->aAlias[iAlias-1] records the register number where the value
-** of the iAlias-th alias is stored.  If zero, that means that the
-** alias has not yet been computed.
-*/
-static int codeAlias(Parse *pParse, int iAlias, Expr *pExpr, int target){
-#if 0
-  sqlite3 *db = pParse->db;
-  int iReg;
-  if( pParse->nAliasAlloc<pParse->nAlias ){
-    pParse->aAlias = sqlite3DbReallocOrFree(db, pParse->aAlias,
-                                 sizeof(pParse->aAlias[0])*pParse->nAlias );
-    testcase( db->mallocFailed && pParse->nAliasAlloc>0 );
-    if( db->mallocFailed ) return 0;
-    memset(&pParse->aAlias[pParse->nAliasAlloc], 0,
-           (pParse->nAlias-pParse->nAliasAlloc)*sizeof(pParse->aAlias[0]));
-    pParse->nAliasAlloc = pParse->nAlias;
-  }
-  assert( iAlias>0 && iAlias<=pParse->nAlias );
-  iReg = pParse->aAlias[iAlias-1];
-  if( iReg==0 ){
-    if( pParse->iCacheLevel>0 ){
-      iReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
-    }else{
-      iReg = ++pParse->nMem;
-      sqlite3ExprCode(pParse, pExpr, iReg);
-      pParse->aAlias[iAlias-1] = iReg;
-    }
-  }
-  return iReg;
-#else
-  UNUSED_PARAMETER(iAlias);
-  return sqlite3ExprCodeTarget(pParse, pExpr, target);
-#endif
-}
-
-/*
 ** Generate code into the current Vdbe to evaluate the given
 ** expression.  Attempt to store the results in register "target".
 ** Return the register where results are stored.
@@ -70101,7 +71343,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
       break;
     }
     case TK_AS: {
-      inReg = codeAlias(pParse, pExpr->iTable, pExpr->pLeft, target);
+      inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
       break;
     }
 #ifndef SQLITE_OMIT_CAST
@@ -70533,6 +71775,11 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
         opCompare.op = TK_EQ;
         opCompare.pLeft = &cacheX;
         pTest = &opCompare;
+        /* Ticket b351d95f9cd5ef17e9d9dbae18f5ca8611190001:
+        ** The value in regFree1 might get SCopy-ed into the file result.
+        ** So make sure that the regFree1 register is not reused for other
+        ** purposes and possibly overwritten.  */
+        regFree1 = 0;
       }
       for(i=0; i<nExpr; i=i+2){
         sqlite3ExprCachePush(pParse);
@@ -70626,10 +71873,14 @@ SQLITE_PRIVATE int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
   int inReg;
 
   assert( target>0 && target<=pParse->nMem );
-  inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
-  assert( pParse->pVdbe || pParse->db->mallocFailed );
-  if( inReg!=target && pParse->pVdbe ){
-    sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, inReg, target);
+  if( pExpr && pExpr->op==TK_REGISTER ){
+    sqlite3VdbeAddOp2(pParse->pVdbe, OP_Copy, pExpr->iTable, target);
+  }else{
+    inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
+    assert( pParse->pVdbe || pParse->db->mallocFailed );
+    if( inReg!=target && pParse->pVdbe ){
+      sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, inReg, target);
+    }
   }
   return target;
 }
@@ -70776,9 +72027,22 @@ static int evalConstExpr(Walker *pWalker, Expr *pExpr){
 ** Preevaluate constant subexpressions within pExpr and store the
 ** results in registers.  Modify pExpr so that the constant subexpresions
 ** are TK_REGISTER opcodes that refer to the precomputed values.
+**
+** This routine is a no-op if the jump to the cookie-check code has
+** already occur.  Since the cookie-check jump is generated prior to
+** any other serious processing, this check ensures that there is no
+** way to accidently bypass the constant initializations.
+**
+** This routine is also a no-op if the SQLITE_FactorOutConst optimization
+** is disabled via the sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS)
+** interface.  This allows test logic to verify that the same answer is
+** obtained for queries regardless of whether or not constants are
+** precomputed into registers or if they are inserted in-line.
 */
 SQLITE_PRIVATE void sqlite3ExprCodeConstants(Parse *pParse, Expr *pExpr){
   Walker w;
+  if( pParse->cookieGoto ) return;
+  if( (pParse->db->flags & SQLITE_FactorOutConst)!=0 ) return;
   w.xExprCallback = evalConstExpr;
   w.xSelectCallback = 0;
   w.pParse = pParse;
@@ -70802,19 +72066,14 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList(
   int i, n;
   assert( pList!=0 );
   assert( target>0 );
+  assert( pParse->pVdbe!=0 );  /* Never gets this far otherwise */
   n = pList->nExpr;
   for(pItem=pList->a, i=0; i<n; i++, pItem++){
-    if( pItem->iAlias ){
-      int iReg = codeAlias(pParse, pItem->iAlias, pItem->pExpr, target+i);
-      Vdbe *v = sqlite3GetVdbe(pParse);
-      if( iReg!=target+i ){
-        sqlite3VdbeAddOp2(v, OP_SCopy, iReg, target+i);
-      }
-    }else{
-      sqlite3ExprCode(pParse, pItem->pExpr, target+i);
-    }
-    if( doHardCopy && !pParse->db->mallocFailed ){
-      sqlite3ExprHardCopy(pParse, target, n);
+    Expr *pExpr = pItem->pExpr;
+    int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i);
+    if( inReg!=target+i ){
+      sqlite3VdbeAddOp2(pParse->pVdbe, doHardCopy ? OP_Copy : OP_SCopy,
+                        inReg, target+i);
     }
   }
   return n;
@@ -71796,6 +73055,11 @@ static char *whereTempTriggers(Parse *pParse, Table *pTab){
       }
     }
   }
+  if( zWhere ){
+    char *zNew = sqlite3MPrintf(pParse->db, "type='trigger' AND (%s)", zWhere);
+    sqlite3DbFree(pParse->db, zWhere);
+    zWhere = zNew;
+  }
   return zWhere;
 }
 
@@ -72403,7 +73667,8 @@ static void analyzeOneTable(
   int i;                       /* Loop counter */
   int topOfLoop;               /* The top of the loop */
   int endOfLoop;               /* The end of the loop */
-  int addr;                    /* The address of an instruction */
+  int addr = 0;                /* The address of an instruction */
+  int jZeroRows = 0;           /* Jump from here if number of rows is zero */
   int iDb;                     /* Index of database containing pTab */
   int regTabname = iMem++;     /* Register containing table name */
   int regIdxname = iMem++;     /* Register containing index name */
@@ -72422,8 +73687,15 @@ static void analyzeOneTable(
 #endif
 
   v = sqlite3GetVdbe(pParse);
-  if( v==0 || NEVER(pTab==0) || pTab->pIndex==0 ){
-    /* Do no analysis for tables that have no indices */
+  if( v==0 || NEVER(pTab==0) ){
+    return;
+  }
+  if( pTab->tnum==0 ){
+    /* Do not gather statistics on views or virtual tables */
+    return;
+  }
+  if( memcmp(pTab->zName, "sqlite_", 7)==0 ){
+    /* Do not gather statistics on system tables */
     return;
   }
   assert( sqlite3BtreeHoldsAllMutexes(db) );
@@ -72440,6 +73712,7 @@ static void analyzeOneTable(
   sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
 
   iIdxCur = pParse->nTab++;
+  sqlite3VdbeAddOp4(v, OP_String8, 0, regTabname, 0, pTab->zName, 0);
   for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
     int nCol = pIdx->nColumn;
     KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
@@ -72454,10 +73727,7 @@ static void analyzeOneTable(
         (char *)pKey, P4_KEYINFO_HANDOFF);
     VdbeComment((v, "%s", pIdx->zName));
 
-    /* Populate the registers containing the table and index names. */
-    if( pTab->pIndex==pIdx ){
-      sqlite3VdbeAddOp4(v, OP_String8, 0, regTabname, 0, pTab->zName, 0);
-    }
+    /* Populate the register containing the index name. */
     sqlite3VdbeAddOp4(v, OP_String8, 0, regIdxname, 0, pIdx->zName, 0);
 
 #ifdef SQLITE_ENABLE_STAT2
@@ -72517,9 +73787,10 @@ static void analyzeOneTable(
     sqlite3VdbeAddOp2(v, OP_AddImm, iMem, 1);
 
     for(i=0; i<nCol; i++){
+      CollSeq *pColl;
       sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regCol);
-#ifdef SQLITE_ENABLE_STAT2
       if( i==0 ){
+#ifdef SQLITE_ENABLE_STAT2
         /* Check if the record that cursor iIdxCur points to contains a
         ** value that should be stored in the sqlite_stat2 table. If so,
         ** store it.  */
@@ -72548,12 +73819,17 @@ static void analyzeOneTable(
 
         sqlite3VdbeJumpHere(v, ne);
         sqlite3VdbeAddOp2(v, OP_AddImm, regRecno, 1);
-      }
 #endif
 
-      sqlite3VdbeAddOp3(v, OP_Ne, regCol, 0, iMem+nCol+i+1);
-      /**** TODO:  add collating sequence *****/
-      sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL);
+        /* Always record the very first row */
+        sqlite3VdbeAddOp1(v, OP_IfNot, iMem+1);
+      }
+      assert( pIdx->azColl!=0 );
+      assert( pIdx->azColl[i]!=0 );
+      pColl = sqlite3LocateCollSeq(pParse, pIdx->azColl[i]);
+      sqlite3VdbeAddOp4(v, OP_Ne, regCol, 0, iMem+nCol+i+1,
+                       (char*)pColl, P4_COLLSEQ);
+      sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
     }
     if( db->mallocFailed ){
       /* If a malloc failure has occurred, then the result of the expression 
@@ -72564,7 +73840,11 @@ static void analyzeOneTable(
     }
     sqlite3VdbeAddOp2(v, OP_Goto, 0, endOfLoop);
     for(i=0; i<nCol; i++){
-      sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-(nCol*2));
+      int addr2 = sqlite3VdbeCurrentAddr(v) - (nCol*2);
+      if( i==0 ){
+        sqlite3VdbeJumpHere(v, addr2-1);  /* Set jump dest for the OP_IfNot */
+      }
+      sqlite3VdbeJumpHere(v, addr2);      /* Set jump dest for the OP_Ne */
       sqlite3VdbeAddOp2(v, OP_AddImm, iMem+i+1, 1);
       sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, iMem+nCol+i+1);
     }
@@ -72592,8 +73872,10 @@ static void analyzeOneTable(
     ** If K>0 then it is always the case the D>0 so division by zero
     ** is never possible.
     */
-    addr = sqlite3VdbeAddOp1(v, OP_IfNot, iMem);
     sqlite3VdbeAddOp2(v, OP_SCopy, iMem, regSampleno);
+    if( jZeroRows==0 ){
+      jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, iMem);
+    }
     for(i=0; i<nCol; i++){
       sqlite3VdbeAddOp4(v, OP_String8, 0, regTemp, 0, " ", 0);
       sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regSampleno, regSampleno);
@@ -72607,13 +73889,35 @@ static void analyzeOneTable(
     sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regRowid);
     sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regRowid);
     sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
+  }
+
+  /* If the table has no indices, create a single sqlite_stat1 entry
+  ** containing NULL as the index name and the row count as the content.
+  */
+  if( pTab->pIndex==0 ){
+    sqlite3VdbeAddOp3(v, OP_OpenRead, iIdxCur, pTab->tnum, iDb);
+    VdbeComment((v, "%s", pTab->zName));
+    sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regSampleno);
+    sqlite3VdbeAddOp1(v, OP_Close, iIdxCur);
+  }else{
+    assert( jZeroRows>0 );
+    addr = sqlite3VdbeAddOp0(v, OP_Goto);
+    sqlite3VdbeJumpHere(v, jZeroRows);
+  }
+  sqlite3VdbeAddOp2(v, OP_Null, 0, regIdxname);
+  sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regRec, "aaa", 0);
+  sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regRowid);
+  sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regRowid);
+  sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
+  if( pParse->nMem<regRec ) pParse->nMem = regRec;
+  if( jZeroRows ){
     sqlite3VdbeJumpHere(v, addr);
   }
 }
 
 /*
 ** Generate code that will cause the most recent index analysis to
-** be laoded into internal hash tables where is can be used.
+** be loaded into internal hash tables where is can be used.
 */
 static void loadAnalysis(Parse *pParse, int iDb){
   Vdbe *v = sqlite3GetVdbe(pParse);
@@ -72743,33 +74047,46 @@ struct analysisInfo {
 ** This callback is invoked once for each index when reading the
 ** sqlite_stat1 table.  
 **
-**     argv[0] = name of the index
-**     argv[1] = results of analysis - on integer for each column
+**     argv[0] = name of the table
+**     argv[1] = name of the index (might be NULL)
+**     argv[2] = results of analysis - on integer for each column
+**
+** Entries for which argv[1]==NULL simply record the number of rows in
+** the table.
 */
 static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
   analysisInfo *pInfo = (analysisInfo*)pData;
   Index *pIndex;
-  int i, c;
+  Table *pTable;
+  int i, c, n;
   unsigned int v;
   const char *z;
 
-  assert( argc==2 );
+  assert( argc==3 );
   UNUSED_PARAMETER2(NotUsed, argc);
 
-  if( argv==0 || argv[0]==0 || argv[1]==0 ){
+  if( argv==0 || argv[0]==0 || argv[2]==0 ){
     return 0;
   }
-  pIndex = sqlite3FindIndex(pInfo->db, argv[0], pInfo->zDatabase);
-  if( pIndex==0 ){
+  pTable = sqlite3FindTable(pInfo->db, argv[0], pInfo->zDatabase);
+  if( pTable==0 ){
     return 0;
   }
-  z = argv[1];
-  for(i=0; *z && i<=pIndex->nColumn; i++){
+  if( argv[1] ){
+    pIndex = sqlite3FindIndex(pInfo->db, argv[1], pInfo->zDatabase);
+  }else{
+    pIndex = 0;
+  }
+  n = pIndex ? pIndex->nColumn : 0;
+  z = argv[2];
+  for(i=0; *z && i<=n; i++){
     v = 0;
     while( (c=z[0])>='0' && c<='9' ){
       v = v*10 + c - '0';
       z++;
     }
+    if( i==0 ) pTable->nRowEst = v;
+    if( pIndex==0 ) break;
     pIndex->aiRowEst[i] = v;
     if( *z==' ' ) z++;
   }
@@ -72845,7 +74162,7 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
 
   /* Load new statistics out of the sqlite_stat1 table */
   zSql = sqlite3MPrintf(db, 
-      "SELECT idx, stat FROM %Q.sqlite_stat1", sInfo.zDatabase);
+      "SELECT tbl, idx, stat FROM %Q.sqlite_stat1", sInfo.zDatabase);
   if( zSql==0 ){
     rc = SQLITE_NOMEM;
   }else{
@@ -72873,8 +74190,11 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
 
     if( rc==SQLITE_OK ){
       while( sqlite3_step(pStmt)==SQLITE_ROW ){
-        char *zIndex = (char *)sqlite3_column_text(pStmt, 0);
-        Index *pIdx = sqlite3FindIndex(db, zIndex, sInfo.zDatabase);
+        char *zIndex;   /* Index name */
+        Index *pIdx;    /* Pointer to the index object */
+
+        zIndex = (char *)sqlite3_column_text(pStmt, 0);
+        pIdx = zIndex ? sqlite3FindIndex(db, zIndex, sInfo.zDatabase) : 0;
         if( pIdx ){
           int iSample = sqlite3_column_int(pStmt, 1);
           if( iSample<SQLITE_INDEX_SAMPLES && iSample>=0 ){
@@ -73062,9 +74382,8 @@ static void attachFunc(
   ** it to obtain the database schema. At this point the schema may
   ** or may not be initialised.
   */
-  rc = sqlite3BtreeFactory(db, zFile, 0, SQLITE_DEFAULT_CACHE_SIZE,
-                           db->openFlags | SQLITE_OPEN_MAIN_DB,
-                           &aNew->pBt);
+  rc = sqlite3BtreeOpen(zFile, db, &aNew->pBt, 0,
+                        db->openFlags | SQLITE_OPEN_MAIN_DB);
   db->nDb++;
   if( rc==SQLITE_CONSTRAINT ){
     rc = SQLITE_ERROR;
@@ -73305,7 +74624,8 @@ SQLITE_PRIVATE void sqlite3Detach(Parse *pParse, Expr *pDbname){
     0,                /* xStep */
     0,                /* xFinalize */
     "sqlite_detach",  /* zName */
-    0                 /* pHash */
+    0,                /* pHash */
+    0                 /* pDestructor */
   };
   codeAttach(pParse, SQLITE_DETACH, &detach_func, pDbname, 0, 0, pDbname);
 }
@@ -73326,7 +74646,8 @@ SQLITE_PRIVATE void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *p
     0,                /* xStep */
     0,                /* xFinalize */
     "sqlite_attach",  /* zName */
-    0                 /* pHash */
+    0,                /* pHash */
+    0                 /* pDestructor */
   };
   codeAttach(pParse, SQLITE_ATTACH, &attach_func, p, p, pDbname, pKey);
 }
@@ -74455,8 +75776,9 @@ SQLITE_PRIVATE void sqlite3StartTable(
   */
   iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName);
   if( iDb<0 ) return;
-  if( !OMIT_TEMPDB && isTemp && iDb>1 ){
-    /* If creating a temp table, the name may not be qualified */
+  if( !OMIT_TEMPDB && isTemp && pName2->n>0 && iDb!=1 ){
+    /* If creating a temp table, the name may not be qualified. Unless 
+    ** the database name is "temp" anyway.  */
     sqlite3ErrorMsg(pParse, "temporary table name must be unqualified");
     return;
   }
@@ -74504,17 +75826,18 @@ SQLITE_PRIVATE void sqlite3StartTable(
   ** collisions.
   */
   if( !IN_DECLARE_VTAB ){
+    char *zDb = db->aDb[iDb].zName;
     if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
       goto begin_table_error;
     }
-    pTable = sqlite3FindTable(db, zName, db->aDb[iDb].zName);
+    pTable = sqlite3FindTable(db, zName, zDb);
     if( pTable ){
       if( !noErr ){
         sqlite3ErrorMsg(pParse, "table %T already exists", pName);
       }
       goto begin_table_error;
     }
-    if( sqlite3FindIndex(db, zName, 0)!=0 && (iDb==0 || !db->init.busy) ){
+    if( sqlite3FindIndex(db, zName, zDb)!=0 ){
       sqlite3ErrorMsg(pParse, "there is already an index named %s", zName);
       goto begin_table_error;
     }
@@ -74531,6 +75854,7 @@ SQLITE_PRIVATE void sqlite3StartTable(
   pTable->iPKey = -1;
   pTable->pSchema = db->aDb[iDb].pSchema;
   pTable->nRef = 1;
+  pTable->nRowEst = 1000000;
   assert( pParse->pNewTable==0 );
   pParse->pNewTable = pTable;
 
@@ -75377,12 +76701,10 @@ SQLITE_PRIVATE void sqlite3CreateView(
   }
   sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, noErr);
   p = pParse->pNewTable;
-  if( p==0 ){
+  if( p==0 || pParse->nErr ){
     sqlite3SelectDelete(db, pSelect);
     return;
   }
-  assert( pParse->nErr==0 ); /* If sqlite3StartTable return non-NULL then
-                             ** there could not have been an error */
   sqlite3TwoPartName(pParse, pName1, pName2, &pName);
   iDb = sqlite3SchemaToIndex(db, p->pSchema);
   if( sqlite3FixInit(&sFix, pParse, iDb, "view", pName)
@@ -76500,7 +77822,8 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
       sqlite3RefillIndex(pParse, pIndex, iMem);
       sqlite3ChangeCookie(pParse, iDb);
       sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0,
-         sqlite3MPrintf(db, "name='%q'", pIndex->zName), P4_DYNAMIC);
+         sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName), 
+         P4_DYNAMIC);
       sqlite3VdbeAddOp1(v, OP_Expire, 0);
     }
   }
@@ -76561,14 +77884,14 @@ exit_create_index:
 SQLITE_PRIVATE void sqlite3DefaultRowEst(Index *pIdx){
   unsigned *a = pIdx->aiRowEst;
   int i;
+  unsigned n;
   assert( a!=0 );
-  a[0] = 1000000;
-  for(i=pIdx->nColumn; i>=5; i--){
-    a[i] = 5;
-  }
-  while( i>=1 ){
-    a[i] = 11 - i;
-    i--;
+  a[0] = pIdx->pTable->nRowEst;
+  if( a[0]<10 ) a[0] = 10;
+  n = 10;
+  for(i=1; i<=pIdx->nColumn; i++){
+    a[i] = n;
+    if( n>5 ) n--;
   }
   if( pIdx->onError!=OE_None ){
     a[pIdx->nColumn] = 1;
@@ -76628,7 +77951,7 @@ SQLITE_PRIVATE void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists
   if( v ){
     sqlite3BeginWriteOperation(pParse, 1, iDb);
     sqlite3NestedParse(pParse,
-       "DELETE FROM %Q.%s WHERE name=%Q",
+       "DELETE FROM %Q.%s WHERE name=%Q AND type='index'",
        db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
        pIndex->zName
     );
@@ -77120,7 +78443,7 @@ SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *pParse){
           SQLITE_OPEN_DELETEONCLOSE |
           SQLITE_OPEN_TEMP_DB;
 
-    rc = sqlite3BtreeFactory(db, 0, 0, SQLITE_DEFAULT_CACHE_SIZE, flags, &pBt);
+    rc = sqlite3BtreeOpen(0, db, &pBt, 0, flags);
     if( rc!=SQLITE_OK ){
       sqlite3ErrorMsg(pParse, "unable to open a temporary database "
         "file for storing temporary tables");
@@ -77777,7 +79100,7 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
   ** priority to built-in functions.
   **
   ** Except, if createFlag is true, that means that we are trying to
-  ** install a new function.  Whatever FuncDef structure is returned will
+  ** install a new function.  Whatever FuncDef structure is returned it will
   ** have fields overwritten with new information appropriate for the
   ** new function.  But the FuncDefs for built-in functions are read-only.
   ** So we must not search for built-ins when creating a new function.
@@ -78793,7 +80116,7 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
       sqlite3_result_error_nomem(context);
       return;
     }
-    sqlite3AtoF(zBuf, &r);
+    sqlite3AtoF(zBuf, &r, sqlite3Strlen30(zBuf), SQLITE_UTF8);
     sqlite3_free(zBuf);
   }
   sqlite3_result_double(context, r);
@@ -79958,10 +81281,10 @@ SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive)
   }else{
     pInfo = (struct compareInfo*)&likeInfoNorm;
   }
-  sqlite3CreateFunc(db, "like", 2, SQLITE_ANY, pInfo, likeFunc, 0, 0);
-  sqlite3CreateFunc(db, "like", 3, SQLITE_ANY, pInfo, likeFunc, 0, 0);
-  sqlite3CreateFunc(db, "glob", 2, SQLITE_ANY, 
-      (struct compareInfo*)&globInfo, likeFunc, 0,0);
+  sqlite3CreateFunc(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0);
+  sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0);
+  sqlite3CreateFunc(db, "glob", 2, SQLITE_UTF8, 
+      (struct compareInfo*)&globInfo, likeFunc, 0, 0, 0);
   setLikeOptFlag(db, "glob", SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE);
   setLikeOptFlag(db, "like", 
       caseSensitive ? (SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE) : SQLITE_FUNC_LIKE);
@@ -80045,10 +81368,10 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
     FUNCTION(coalesce,           1, 0, 0, 0                ),
     FUNCTION(coalesce,           0, 0, 0, 0                ),
 /*  FUNCTION(coalesce,          -1, 0, 0, ifnullFunc       ), */
-    {-1,SQLITE_UTF8,SQLITE_FUNC_COALESCE,0,0,ifnullFunc,0,0,"coalesce",0},
+    {-1,SQLITE_UTF8,SQLITE_FUNC_COALESCE,0,0,ifnullFunc,0,0,"coalesce",0,0},
     FUNCTION(hex,                1, 0, 0, hexFunc          ),
 /*  FUNCTION(ifnull,             2, 0, 0, ifnullFunc       ), */
-    {2,SQLITE_UTF8,SQLITE_FUNC_COALESCE,0,0,ifnullFunc,0,0,"ifnull",0},
+    {2,SQLITE_UTF8,SQLITE_FUNC_COALESCE,0,0,ifnullFunc,0,0,"ifnull",0,0},
     FUNCTION(random,             0, 0, 0, randomFunc       ),
     FUNCTION(randomblob,         1, 0, 0, randomBlob       ),
     FUNCTION(nullif,             2, 0, 1, nullifFunc       ),
@@ -80075,7 +81398,7 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
     AGGREGATE(total,             1, 0, 0, sumStep,         totalFinalize    ),
     AGGREGATE(avg,               1, 0, 0, sumStep,         avgFinalize    ),
  /* AGGREGATE(count,             0, 0, 0, countStep,       countFinalize  ), */
-    {0,SQLITE_UTF8,SQLITE_FUNC_COUNT,0,0,0,countStep,countFinalize,"count",0},
+    {0,SQLITE_UTF8,SQLITE_FUNC_COUNT,0,0,0,countStep,countFinalize,"count",0,0},
     AGGREGATE(count,             1, 0, 0, countStep,       countFinalize  ),
     AGGREGATE(group_concat,      1, 0, 0, groupConcatStep, groupConcatFinalize),
     AGGREGATE(group_concat,      2, 0, 0, groupConcatStep, groupConcatFinalize),
@@ -80486,7 +81809,7 @@ static void fkLookupParent(
       sqlite3VdbeAddOp3(v, OP_OpenRead, iCur, pIdx->tnum, iDb);
       sqlite3VdbeChangeP4(v, -1, (char*)pKey, P4_KEYINFO_HANDOFF);
       for(i=0; i<nCol; i++){
-        sqlite3VdbeAddOp2(v, OP_SCopy, aiCol[i]+1+regData, regTemp+i);
+        sqlite3VdbeAddOp2(v, OP_Copy, aiCol[i]+1+regData, regTemp+i);
       }
   
       /* If the parent table is the same as the child table, and we are about
@@ -83488,6 +84811,27 @@ struct sqlite3_api_routines {
   sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*);
   const char *(*sql)(sqlite3_stmt*);
   int (*status)(int,int*,int*,int);
+  int (*backup_finish)(sqlite3_backup*);
+  sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*);
+  int (*backup_pagecount)(sqlite3_backup*);
+  int (*backup_remaining)(sqlite3_backup*);
+  int (*backup_step)(sqlite3_backup*,int);
+  const char *(*compileoption_get)(int);
+  int (*compileoption_used)(const char*);
+  int (*create_function_v2)(sqlite3*,const char*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*),void(*xDestroy)(void*));
+  int (*db_config)(sqlite3*,int,...);
+  sqlite3_mutex *(*db_mutex)(sqlite3*);
+  int (*db_status)(sqlite3*,int,int*,int*,int);
+  int (*extended_errcode)(sqlite3*);
+  void (*log)(int,const char*,...);
+  sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64);
+  const char *(*sourceid)(void);
+  int (*stmt_status)(sqlite3_stmt*,int,int);
+  int (*strnicmp)(const char*,const char*,int);
+  int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*);
+  int (*wal_autocheckpoint)(sqlite3*,int);
+  int (*wal_checkpoint)(sqlite3*,const char*);
+  void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*);
 };
 
 /*
@@ -83667,6 +85011,27 @@ struct sqlite3_api_routines {
 #define sqlite3_next_stmt              sqlite3_api->next_stmt
 #define sqlite3_sql                    sqlite3_api->sql
 #define sqlite3_status                 sqlite3_api->status
+#define sqlite3_backup_finish          sqlite3_api->backup_finish
+#define sqlite3_backup_init            sqlite3_api->backup_init
+#define sqlite3_backup_pagecount       sqlite3_api->backup_pagecount
+#define sqlite3_backup_remaining       sqlite3_api->backup_remaining
+#define sqlite3_backup_step            sqlite3_api->backup_step
+#define sqlite3_compileoption_get      sqlite3_api->compileoption_get
+#define sqlite3_compileoption_used     sqlite3_api->compileoption_used
+#define sqlite3_create_function_v2     sqlite3_api->create_function_v2
+#define sqlite3_db_config              sqlite3_api->db_config
+#define sqlite3_db_mutex               sqlite3_api->db_mutex
+#define sqlite3_db_status              sqlite3_api->db_status
+#define sqlite3_extended_errcode       sqlite3_api->extended_errcode
+#define sqlite3_log                    sqlite3_api->log
+#define sqlite3_soft_heap_limit64      sqlite3_api->soft_heap_limit64
+#define sqlite3_sourceid               sqlite3_api->sourceid
+#define sqlite3_stmt_status            sqlite3_api->stmt_status
+#define sqlite3_strnicmp               sqlite3_api->strnicmp
+#define sqlite3_unlock_notify          sqlite3_api->unlock_notify
+#define sqlite3_wal_autocheckpoint     sqlite3_api->wal_autocheckpoint
+#define sqlite3_wal_checkpoint         sqlite3_api->wal_checkpoint
+#define sqlite3_wal_hook               sqlite3_api->wal_hook
 #endif /* SQLITE_CORE */
 
 #define SQLITE_EXTENSION_INIT1     const sqlite3_api_routines *sqlite3_api = 0;
@@ -83984,6 +85349,46 @@ static const sqlite3_api_routines sqlite3Apis = {
   sqlite3_next_stmt,
   sqlite3_sql,
   sqlite3_status,
+
+  /*
+  ** Added for 3.7.4
+  */
+  sqlite3_backup_finish,
+  sqlite3_backup_init,
+  sqlite3_backup_pagecount,
+  sqlite3_backup_remaining,
+  sqlite3_backup_step,
+#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
+  sqlite3_compileoption_get,
+  sqlite3_compileoption_used,
+#else
+  0,
+  0,
+#endif
+  sqlite3_create_function_v2,
+  sqlite3_db_config,
+  sqlite3_db_mutex,
+  sqlite3_db_status,
+  sqlite3_extended_errcode,
+  sqlite3_log,
+  sqlite3_soft_heap_limit64,
+  sqlite3_sourceid,
+  sqlite3_stmt_status,
+  sqlite3_strnicmp,
+#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
+  sqlite3_unlock_notify,
+#else
+  0,
+#endif
+#ifndef SQLITE_OMIT_WAL
+  sqlite3_wal_autocheckpoint,
+  sqlite3_wal_checkpoint,
+  sqlite3_wal_hook,
+#else
+  0,
+  0,
+  0,
+#endif
 };
 
 /*
@@ -84299,7 +85704,7 @@ static u8 getSafetyLevel(const char *z){
   static const u8 iValue[] =  {1, 0, 0, 0, 1, 1, 2};
   int i, n;
   if( sqlite3Isdigit(*z) ){
-    return (u8)atoi(z);
+    return (u8)sqlite3Atoi(z);
   }
   n = sqlite3Strlen30(z);
   for(i=0; i<ArraySize(iLength); i++){
@@ -84340,7 +85745,7 @@ static int getAutoVacuum(const char *z){
   if( 0==sqlite3StrICmp(z, "none") ) return BTREE_AUTOVACUUM_NONE;
   if( 0==sqlite3StrICmp(z, "full") ) return BTREE_AUTOVACUUM_FULL;
   if( 0==sqlite3StrICmp(z, "incremental") ) return BTREE_AUTOVACUUM_INCR;
-  i = atoi(z);
+  i = sqlite3Atoi(z);
   return (u8)((i>=0&&i<=2)?i:0);
 }
 #endif /* ifndef SQLITE_OMIT_AUTOVACUUM */
@@ -84436,6 +85841,7 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
     { "empty_result_callbacks",   SQLITE_NullCallback  },
     { "legacy_file_format",       SQLITE_LegacyFileFmt },
     { "fullfsync",                SQLITE_FullFSync     },
+    { "checkpoint_fullfsync",     SQLITE_CkptFullFSync },
     { "reverse_unordered_selects", SQLITE_ReverseOrder  },
 #ifndef SQLITE_OMIT_AUTOMATIC_INDEX
     { "automatic_index",          SQLITE_AutoIndex     },
@@ -84647,7 +86053,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
       sqlite3VdbeChangeP1(v, addr+1, iDb);
       sqlite3VdbeChangeP1(v, addr+6, SQLITE_DEFAULT_CACHE_SIZE);
     }else{
-      int size = atoi(zRight);
+      int size = sqlite3Atoi(zRight);
       if( size<0 ) size = -size;
       sqlite3BeginWriteOperation(pParse, 0, iDb);
       sqlite3VdbeAddOp2(v, OP_Integer, size, 1);
@@ -84676,7 +86082,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
       /* Malloc may fail when setting the page-size, as there is an internal
       ** buffer that the pager module resizes using sqlite3_realloc().
       */
-      db->nextPagesize = atoi(zRight);
+      db->nextPagesize = sqlite3Atoi(zRight);
       if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1, 0) ){
         db->mallocFailed = 1;
       }
@@ -84684,28 +86090,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
   }else
 
   /*
-  **  PRAGMA [database.]max_page_count
-  **  PRAGMA [database.]max_page_count=N
-  **
-  ** The first form reports the current setting for the
-  ** maximum number of pages in the database file.  The 
-  ** second form attempts to change this setting.  Both
-  ** forms return the current setting.
-  */
-  if( sqlite3StrICmp(zLeft,"max_page_count")==0 ){
-    Btree *pBt = pDb->pBt;
-    int newMax = 0;
-    assert( pBt!=0 );
-    if( zRight ){
-      newMax = atoi(zRight);
-    }
-    if( ALWAYS(pBt) ){
-      newMax = sqlite3BtreeMaxPageCount(pBt, newMax);
-    }
-    returnSingleInt(pParse, "max_page_count", newMax);
-  }else
-
-  /*
   **  PRAGMA [database.]secure_delete
   **  PRAGMA [database.]secure_delete=ON/OFF
   **
@@ -84731,19 +86115,33 @@ SQLITE_PRIVATE void sqlite3Pragma(
   }else
 
   /*
+  **  PRAGMA [database.]max_page_count
+  **  PRAGMA [database.]max_page_count=N
+  **
+  ** The first form reports the current setting for the
+  ** maximum number of pages in the database file.  The 
+  ** second form attempts to change this setting.  Both
+  ** forms return the current setting.
+  **
   **  PRAGMA [database.]page_count
   **
   ** Return the number of pages in the specified database.
   */
-  if( sqlite3StrICmp(zLeft,"page_count")==0 ){
+  if( sqlite3StrICmp(zLeft,"page_count")==0
+   || sqlite3StrICmp(zLeft,"max_page_count")==0
+  ){
     int iReg;
     if( sqlite3ReadSchema(pParse) ) goto pragma_out;
     sqlite3CodeVerifySchema(pParse, iDb);
     iReg = ++pParse->nMem;
-    sqlite3VdbeAddOp2(v, OP_Pagecount, iDb, iReg);
+    if( zLeft[0]=='p' ){
+      sqlite3VdbeAddOp2(v, OP_Pagecount, iDb, iReg);
+    }else{
+      sqlite3VdbeAddOp3(v, OP_MaxPgcnt, iDb, iReg, sqlite3Atoi(zRight));
+    }
     sqlite3VdbeAddOp2(v, OP_ResultRow, iReg, 1);
     sqlite3VdbeSetNumCols(v, 1);
-    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "page_count", SQLITE_STATIC);
+    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, SQLITE_TRANSIENT);
   }else
 
   /*
@@ -84851,7 +86249,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
     Pager *pPager = sqlite3BtreePager(pDb->pBt);
     i64 iLimit = -2;
     if( zRight ){
-      sqlite3Atoi64(zRight, &iLimit);
+      sqlite3Atoi64(zRight, &iLimit, 1000000, SQLITE_UTF8);
       if( iLimit<-1 ) iLimit = -1;
     }
     iLimit = sqlite3PagerJournalSizeLimit(pPager, iLimit);
@@ -84965,7 +86363,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
     if( !zRight ){
       returnSingleInt(pParse, "cache_size", pDb->pSchema->cache_size);
     }else{
-      int size = atoi(zRight);
+      int size = sqlite3Atoi(zRight);
       if( size<0 ) size = -size;
       pDb->pSchema->cache_size = size;
       sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
@@ -85412,7 +86810,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
     /* Set the maximum error count */
     mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
     if( zRight ){
-      mxErr = atoi(zRight);
+      sqlite3GetInt32(zRight, &mxErr);
       if( mxErr<=0 ){
         mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
       }
@@ -85669,7 +87067,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
       };
       int addr = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie);
       sqlite3VdbeChangeP1(v, addr, iDb);
-      sqlite3VdbeChangeP1(v, addr+1, atoi(zRight));
+      sqlite3VdbeChangeP1(v, addr+1, sqlite3Atoi(zRight));
       sqlite3VdbeChangeP1(v, addr+2, iDb);
       sqlite3VdbeChangeP2(v, addr+2, iCookie);
     }else{
@@ -85730,8 +87128,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
   */
   if( sqlite3StrICmp(zLeft, "wal_autocheckpoint")==0 ){
     if( zRight ){
-      int nAuto = atoi(zRight);
-      sqlite3_wal_autocheckpoint(db, nAuto);
+      sqlite3_wal_autocheckpoint(db, sqlite3Atoi(zRight));
     }
     returnSingleInt(pParse, "wal_autocheckpoint", 
        db->xWalCallback==sqlite3WalDefaultHook ? 
@@ -85821,7 +87218,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
 #ifndef SQLITE_OMIT_PAGER_PRAGMAS
   if( db->autoCommit ){
     sqlite3BtreeSetSafetyLevel(pDb->pBt, pDb->safety_level,
-               (db->flags&SQLITE_FullFSync)!=0);
+               (db->flags&SQLITE_FullFSync)!=0,
+               (db->flags&SQLITE_CkptFullFSync)!=0);
   }
 #endif
 pragma_out:
@@ -85913,7 +87311,7 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char
 
     assert( db->init.busy );
     db->init.iDb = iDb;
-    db->init.newTnum = atoi(argv[1]);
+    db->init.newTnum = sqlite3Atoi(argv[1]);
     db->init.orphanTrigger = 0;
     TESTONLY(rcp = ) sqlite3_prepare(db, argv[2], -1, &pStmt, 0);
     rc = db->errCode;
@@ -86462,13 +87860,13 @@ static int sqlite3Prepare(
   if( rc==SQLITE_OK && pParse->pVdbe && pParse->explain ){
     static const char * const azColName[] = {
        "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
-       "order", "from", "detail"
+       "selectid", "order", "from", "detail"
     };
     int iFirst, mx;
     if( pParse->explain==2 ){
-      sqlite3VdbeSetNumCols(pParse->pVdbe, 3);
+      sqlite3VdbeSetNumCols(pParse->pVdbe, 4);
       iFirst = 8;
-      mx = 11;
+      mx = 12;
     }else{
       sqlite3VdbeSetNumCols(pParse->pVdbe, 8);
       iFirst = 0;
@@ -86618,7 +88016,7 @@ SQLITE_API int sqlite3_prepare_v2(
 */
 static int sqlite3Prepare16(
   sqlite3 *db,              /* Database handle. */ 
-  const void *zSql,         /* UTF-8 encoded SQL statement. */
+  const void *zSql,         /* UTF-16 encoded SQL statement. */
   int nBytes,               /* Length of zSql in bytes. */
   int saveSqlFlag,          /* True to save SQL text into the sqlite3_stmt */
   sqlite3_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */
@@ -86668,7 +88066,7 @@ static int sqlite3Prepare16(
 */
 SQLITE_API int sqlite3_prepare16(
   sqlite3 *db,              /* Database handle. */ 
-  const void *zSql,         /* UTF-8 encoded SQL statement. */
+  const void *zSql,         /* UTF-16 encoded SQL statement. */
   int nBytes,               /* Length of zSql in bytes. */
   sqlite3_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */
   const void **pzTail       /* OUT: End of parsed string */
@@ -86680,7 +88078,7 @@ SQLITE_API int sqlite3_prepare16(
 }
 SQLITE_API int sqlite3_prepare16_v2(
   sqlite3 *db,              /* Database handle. */ 
-  const void *zSql,         /* UTF-8 encoded SQL statement. */
+  const void *zSql,         /* UTF-16 encoded SQL statement. */
   int nBytes,               /* Length of zSql in bytes. */
   sqlite3_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */
   const void **pzTail       /* OUT: End of parsed string */
@@ -87138,7 +88536,6 @@ static void pushOntoSorter(
     sqlite3VdbeAddOp1(v, OP_Last, pOrderBy->iECursor);
     sqlite3VdbeAddOp1(v, OP_Delete, pOrderBy->iECursor);
     sqlite3VdbeJumpHere(v, addr2);
-    pSelect->iLimit = 0;
   }
 }
 
@@ -87187,11 +88584,13 @@ static void codeDistinct(
   sqlite3ReleaseTempReg(pParse, r1);
 }
 
+#ifndef SQLITE_OMIT_SUBQUERY
 /*
 ** Generate an error message when a SELECT is used within a subexpression
 ** (example:  "a IN (SELECT * FROM table)") but it has more than 1 result
-** column.  We do this in a subroutine because the error occurs in multiple
-** places.
+** column.  We do this in a subroutine because the error used to occur
+** in multiple places.  (The error only occurs in one place now, but we
+** retain the subroutine to minimize code disruption.)
 */
 static int checkForMultiColumnSelectError(
   Parse *pParse,       /* Parse context. */
@@ -87207,6 +88606,7 @@ static int checkForMultiColumnSelectError(
     return 0;
   }
 }
+#endif
 
 /*
 ** This routine generates the code for the inside of the inner loop
@@ -87286,10 +88686,6 @@ static void selectInnerLoop(
     }
   }
 
-  if( checkForMultiColumnSelectError(pParse, pDest, pEList->nExpr) ){
-    return;
-  }
-
   switch( eDest ){
     /* In this mode, write each query result to the key of the temporary
     ** table iParm.
@@ -87418,11 +88814,11 @@ static void selectInnerLoop(
 #endif
   }
 
-  /* Jump to the end of the loop if the LIMIT is reached.
+  /* Jump to the end of the loop if the LIMIT is reached.  Except, if
+  ** there is a sorter, in which case the sorter has already limited
+  ** the output for us.
   */
-  if( p->iLimit ){
-    assert( pOrderBy==0 );  /* If there is an ORDER BY, the call to
-                            ** pushOntoSorter() would have cleared p->iLimit */
+  if( pOrderBy==0 && p->iLimit ){
     sqlite3VdbeAddOp3(v, OP_IfZero, p->iLimit, iBreak, -1);
   }
 }
@@ -87469,6 +88865,88 @@ static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList){
   return pInfo;
 }
 
+#ifndef SQLITE_OMIT_COMPOUND_SELECT
+/*
+** 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;
+}
+#endif /* SQLITE_OMIT_COMPOUND_SELECT */
+
+#ifndef SQLITE_OMIT_EXPLAIN
+/*
+** Unless an "EXPLAIN QUERY PLAN" command is being processed, this function
+** is a no-op. Otherwise, it adds a single row of output to the EQP result,
+** where the caption is of the form:
+**
+**   "USE TEMP B-TREE FOR xxx"
+**
+** where xxx is one of "DISTINCT", "ORDER BY" or "GROUP BY". Exactly which
+** is determined by the zUsage argument.
+*/
+static void explainTempTable(Parse *pParse, const char *zUsage){
+  if( pParse->explain==2 ){
+    Vdbe *v = pParse->pVdbe;
+    char *zMsg = sqlite3MPrintf(pParse->db, "USE TEMP B-TREE FOR %s", zUsage);
+    sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC);
+  }
+}
+
+/*
+** Unless an "EXPLAIN QUERY PLAN" command is being processed, this function
+** is a no-op. Otherwise, it adds a single row of output to the EQP result,
+** where the caption is of one of the two forms:
+**
+**   "COMPOSITE SUBQUERIES iSub1 and iSub2 (op)"
+**   "COMPOSITE SUBQUERIES iSub1 and iSub2 USING TEMP B-TREE (op)"
+**
+** where iSub1 and iSub2 are the integers passed as the corresponding
+** function parameters, and op is the text representation of the parameter
+** of the same name. The parameter "op" must be one of TK_UNION, TK_EXCEPT,
+** TK_INTERSECT or TK_ALL. The first form is used if argument bUseTmp is 
+** false, or the second form if it is true.
+*/
+static void explainComposite(
+  Parse *pParse,                  /* Parse context */
+  int op,                         /* One of TK_UNION, TK_EXCEPT etc. */
+  int iSub1,                      /* Subquery id 1 */
+  int iSub2,                      /* Subquery id 2 */
+  int bUseTmp                     /* True if a temp table was used */
+){
+  assert( op==TK_UNION || op==TK_EXCEPT || op==TK_INTERSECT || op==TK_ALL );
+  if( pParse->explain==2 ){
+    Vdbe *v = pParse->pVdbe;
+    char *zMsg = sqlite3MPrintf(
+        pParse->db, "COMPOUND SUBQUERIES %d AND %d %s(%s)", iSub1, iSub2,
+        bUseTmp?"USING TEMP B-TREE ":"", selectOpName(op)
+    );
+    sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC);
+  }
+}
+
+/*
+** Assign expression b to lvalue a. A second, no-op, version of this macro
+** is provided when SQLITE_OMIT_EXPLAIN is defined. This allows the code
+** in sqlite3Select() to assign values to structure member variables that
+** only exist if SQLITE_OMIT_EXPLAIN is not defined without polluting the
+** code with #ifndef directives.
+*/
+# define explainSetInteger(a, b) a = b
+
+#else
+/* No-op versions of the explainXXX() functions and macros. */
+# define explainTempTable(y,z)
+# define explainComposite(v,w,x,y,z)
+# define explainSetInteger(y,z)
+#endif
 
 /*
 ** If the inner loop was generated using a non-null pOrderBy argument,
@@ -87557,10 +89035,6 @@ static void generateSortTail(
   sqlite3ReleaseTempReg(pParse, regRow);
   sqlite3ReleaseTempReg(pParse, regRowid);
 
-  /* LIMIT has been implemented by the pushOntoSorter() routine.
-  */
-  assert( p->iLimit==0 );
-
   /* The bottom of the loop
   */
   sqlite3VdbeResolveLabel(v, addrContinue);
@@ -87820,22 +89294,6 @@ static void generateColumnNames(
   generateColumnTypes(pParse, pTabList, pEList);
 }
 
-#ifndef SQLITE_OMIT_COMPOUND_SELECT
-/*
-** 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;
-}
-#endif /* SQLITE_OMIT_COMPOUND_SELECT */
-
 /*
 ** Given a an expression list (which is really the list of expressions
 ** that form the result set of a SELECT statement) compute appropriate
@@ -87998,6 +89456,7 @@ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
   assert( db->lookaside.bEnabled==0 );
   pTab->nRef = 1;
   pTab->zName = 0;
+  pTab->nRowEst = 1000000;
   selectColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
   selectAddColumnTypeAndCollation(pParse, pTab->nCol, pTab->aCol, pSelect);
   pTab->iPKey = -1;
@@ -88068,6 +89527,8 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
       VdbeComment((v, "LIMIT counter"));
       if( n==0 ){
         sqlite3VdbeAddOp2(v, OP_Goto, 0, iBreak);
+      }else{
+        if( p->nSelectRow > (double)n ) p->nSelectRow = (double)n;
       }
     }else{
       sqlite3ExprCode(pParse, p->pLimit, iLimit);
@@ -88168,6 +89629,10 @@ static int multiSelect(
   SelectDest dest;      /* Alternative data destination */
   Select *pDelete = 0;  /* Chain of simple selects to delete */
   sqlite3 *db;          /* Database connection */
+#ifndef SQLITE_OMIT_EXPLAIN
+  int iSub1;            /* EQP id of left-hand query */
+  int iSub2;            /* EQP id of right-hand query */
+#endif
 
   /* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs.  Only
   ** the last (right-most) SELECT in the series may have an ORDER BY or LIMIT.
@@ -88199,6 +89664,7 @@ static int multiSelect(
   if( dest.eDest==SRT_EphemTab ){
     assert( p->pEList );
     sqlite3VdbeAddOp2(v, OP_OpenEphemeral, dest.iParm, p->pEList->nExpr);
+    sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
     dest.eDest = SRT_Table;
   }
 
@@ -88224,9 +89690,11 @@ static int multiSelect(
   switch( p->op ){
     case TK_ALL: {
       int addr = 0;
+      int nLimit;
       assert( !pPrior->pLimit );
       pPrior->pLimit = p->pLimit;
       pPrior->pOffset = p->pOffset;
+      explainSetInteger(iSub1, pParse->iNextSelectId);
       rc = sqlite3Select(pParse, pPrior, &dest);
       p->pLimit = 0;
       p->pOffset = 0;
@@ -88240,10 +89708,18 @@ static int multiSelect(
         addr = sqlite3VdbeAddOp1(v, OP_IfZero, p->iLimit);
         VdbeComment((v, "Jump ahead if LIMIT reached"));
       }
+      explainSetInteger(iSub2, pParse->iNextSelectId);
       rc = sqlite3Select(pParse, p, &dest);
       testcase( rc!=SQLITE_OK );
       pDelete = p->pPrior;
       p->pPrior = pPrior;
+      p->nSelectRow += pPrior->nSelectRow;
+      if( pPrior->pLimit
+       && sqlite3ExprIsInteger(pPrior->pLimit, &nLimit)
+       && p->nSelectRow > (double)nLimit 
+      ){
+        p->nSelectRow = (double)nLimit;
+      }
       if( addr ){
         sqlite3VdbeJumpHere(v, addr);
       }
@@ -88287,6 +89763,7 @@ static int multiSelect(
       */
       assert( !pPrior->pOrderBy );
       sqlite3SelectDestInit(&uniondest, priorOp, unionTab);
+      explainSetInteger(iSub1, pParse->iNextSelectId);
       rc = sqlite3Select(pParse, pPrior, &uniondest);
       if( rc ){
         goto multi_select_end;
@@ -88306,6 +89783,7 @@ static int multiSelect(
       pOffset = p->pOffset;
       p->pOffset = 0;
       uniondest.eDest = op;
+      explainSetInteger(iSub2, pParse->iNextSelectId);
       rc = sqlite3Select(pParse, p, &uniondest);
       testcase( rc!=SQLITE_OK );
       /* Query flattening in sqlite3Select() might refill p->pOrderBy.
@@ -88314,6 +89792,7 @@ static int multiSelect(
       pDelete = p->pPrior;
       p->pPrior = pPrior;
       p->pOrderBy = 0;
+      if( p->op==TK_UNION ) p->nSelectRow += pPrior->nSelectRow;
       sqlite3ExprDelete(db, p->pLimit);
       p->pLimit = pLimit;
       p->pOffset = pOffset;
@@ -88371,6 +89850,7 @@ static int multiSelect(
       /* Code the SELECTs to our left into temporary table "tab1".
       */
       sqlite3SelectDestInit(&intersectdest, SRT_Union, tab1);
+      explainSetInteger(iSub1, pParse->iNextSelectId);
       rc = sqlite3Select(pParse, pPrior, &intersectdest);
       if( rc ){
         goto multi_select_end;
@@ -88387,10 +89867,12 @@ static int multiSelect(
       pOffset = p->pOffset;
       p->pOffset = 0;
       intersectdest.iParm = tab2;
+      explainSetInteger(iSub2, pParse->iNextSelectId);
       rc = sqlite3Select(pParse, p, &intersectdest);
       testcase( rc!=SQLITE_OK );
       pDelete = p->pPrior;
       p->pPrior = pPrior;
+      if( p->nSelectRow>pPrior->nSelectRow ) p->nSelectRow = pPrior->nSelectRow;
       sqlite3ExprDelete(db, p->pLimit);
       p->pLimit = pLimit;
       p->pOffset = pOffset;
@@ -88423,6 +89905,8 @@ static int multiSelect(
     }
   }
 
+  explainComposite(pParse, p->op, iSub1, iSub2, p->op!=TK_ALL);
+
   /* Compute collating sequences used by 
   ** temporary tables needed to implement the compound select.
   ** Attach the KeyInfo structure to all temporary tables.
@@ -88766,6 +90250,10 @@ static int multiSelectOrderBy(
   ExprList *pOrderBy;   /* The ORDER BY clause */
   int nOrderBy;         /* Number of terms in the ORDER BY clause */
   int *aPermute;        /* Mapping from ORDER BY terms to result set columns */
+#ifndef SQLITE_OMIT_EXPLAIN
+  int iSub1;            /* EQP id of left-hand query */
+  int iSub2;            /* EQP id of right-hand query */
+#endif
 
   assert( p->pOrderBy!=0 );
   assert( pKeyDup==0 ); /* "Managed" code needs this.  Ticket #3382. */
@@ -88877,7 +90365,6 @@ static int multiSelectOrderBy(
   /* Separate the left and the right query from one another
   */
   p->pPrior = 0;
-  pPrior->pRightmost = 0;
   sqlite3ResolveOrderGroupBy(pParse, p, p->pOrderBy, "ORDER");
   if( pPrior->pPrior==0 ){
     sqlite3ResolveOrderGroupBy(pParse, pPrior, pPrior->pOrderBy, "ORDER");
@@ -88920,6 +90407,7 @@ static int multiSelectOrderBy(
   */
   VdbeNoopComment((v, "Begin coroutine for left SELECT"));
   pPrior->iLimit = regLimitA;
+  explainSetInteger(iSub1, pParse->iNextSelectId);
   sqlite3Select(pParse, pPrior, &destA);
   sqlite3VdbeAddOp2(v, OP_Integer, 1, regEofA);
   sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
@@ -88934,6 +90422,7 @@ static int multiSelectOrderBy(
   savedOffset = p->iOffset;
   p->iLimit = regLimitB;
   p->iOffset = 0;  
+  explainSetInteger(iSub2, pParse->iNextSelectId);
   sqlite3Select(pParse, p, &destB);
   p->iLimit = savedLimit;
   p->iOffset = savedOffset;
@@ -88970,6 +90459,7 @@ static int multiSelectOrderBy(
     sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
     sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
     sqlite3VdbeAddOp2(v, OP_Goto, 0, addrEofA);
+    p->nSelectRow += pPrior->nSelectRow;
   }
 
   /* Generate a subroutine to run when the results from select B
@@ -88977,6 +90467,7 @@ static int multiSelectOrderBy(
   */
   if( op==TK_INTERSECT ){
     addrEofB = addrEofA;
+    if( p->nSelectRow > pPrior->nSelectRow ) p->nSelectRow = pPrior->nSelectRow;
   }else{  
     VdbeNoopComment((v, "eof-B subroutine"));
     addrEofB = sqlite3VdbeAddOp2(v, OP_If, regEofA, labelEnd);
@@ -89064,6 +90555,7 @@ static int multiSelectOrderBy(
 
   /*** TBD:  Insert subroutine calls to close cursors on incomplete
   **** subqueries ****/
+  explainComposite(pParse, p->op, iSub1, iSub2, 0);
   return SQLITE_OK;
 }
 #endif
@@ -89797,6 +91289,7 @@ static int selectExpander(Walker *pWalker, Select *p){
       while( pSel->pPrior ){ pSel = pSel->pPrior; }
       selectColumnsFromExprList(pParse, pSel->pEList, &pTab->nCol, &pTab->aCol);
       pTab->iPKey = -1;
+      pTab->nRowEst = 1000000;
       pTab->tabFlags |= TF_Ephemeral;
 #endif
     }else{
@@ -90161,7 +91654,7 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
     if( pList ){
       nArg = pList->nExpr;
       regAgg = sqlite3GetTempRange(pParse, nArg);
-      sqlite3ExprCodeExprList(pParse, pList, regAgg, 0);
+      sqlite3ExprCodeExprList(pParse, pList, regAgg, 1);
     }else{
       nArg = 0;
       regAgg = 0;
@@ -90290,6 +91783,11 @@ SQLITE_PRIVATE int sqlite3Select(
   int iEnd;              /* Address of the end of the query */
   sqlite3 *db;           /* The database connection */
 
+#ifndef SQLITE_OMIT_EXPLAIN
+  int iRestoreSelectId = pParse->iSelectId;
+  pParse->iSelectId = pParse->iNextSelectId++;
+#endif
+
   db = pParse->db;
   if( p==0 || db->mallocFailed || pParse->nErr ){
     return 1;
@@ -90321,6 +91819,15 @@ SQLITE_PRIVATE int sqlite3Select(
   v = sqlite3GetVdbe(pParse);
   if( v==0 ) goto select_end;
 
+  /* If writing to memory or generating a set
+  ** only a single column may be output.
+  */
+#ifndef SQLITE_OMIT_SUBQUERY
+  if( checkForMultiColumnSelectError(pParse, pDest, pEList->nExpr) ){
+    goto select_end;
+  }
+#endif
+
   /* Generate code for all sub-queries in the FROM clause
   */
 #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
@@ -90352,8 +91859,10 @@ SQLITE_PRIVATE int sqlite3Select(
     }else{
       sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
       assert( pItem->isPopulated==0 );
+      explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
       sqlite3Select(pParse, pSub, &dest);
       pItem->isPopulated = 1;
+      pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow;
     }
     if( /*pParse->nErr ||*/ db->mallocFailed ){
       goto select_end;
@@ -90387,19 +91896,12 @@ SQLITE_PRIVATE int sqlite3Select(
       mxSelect = db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT];
       if( mxSelect && cnt>mxSelect ){
         sqlite3ErrorMsg(pParse, "too many terms in compound SELECT");
-        return 1;
+        goto select_end;
       }
     }
-    return multiSelect(pParse, p, pDest);
-  }
-#endif
-
-  /* If writing to memory or generating a set
-  ** only a single column may be output.
-  */
-#ifndef SQLITE_OMIT_SUBQUERY
-  if( checkForMultiColumnSelectError(pParse, pDest, pEList->nExpr) ){
-    goto select_end;
+    rc = multiSelect(pParse, p, pDest);
+    explainSetInteger(pParse->iSelectId, iRestoreSelectId);
+    return rc;
   }
 #endif
 
@@ -90411,7 +91913,6 @@ SQLITE_PRIVATE int sqlite3Select(
     p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0);
     pGroupBy = p->pGroupBy;
     p->selFlags &= ~SF_Distinct;
-    isDistinct = 0;
   }
 
   /* If there is both a GROUP BY and an ORDER BY clause and they are
@@ -90454,17 +91955,19 @@ SQLITE_PRIVATE int sqlite3Select(
   /* Set the limiter.
   */
   iEnd = sqlite3VdbeMakeLabel(v);
+  p->nSelectRow = (double)LARGEST_INT64;
   computeLimitRegisters(pParse, p, iEnd);
 
   /* Open a virtual index to use for the distinct set.
   */
-  if( isDistinct ){
+  if( p->selFlags & SF_Distinct ){
     KeyInfo *pKeyInfo;
     assert( isAgg || pGroupBy );
     distinct = pParse->nTab++;
     pKeyInfo = keyInfoFromExprList(pParse, p->pEList);
     sqlite3VdbeAddOp4(v, OP_OpenEphemeral, distinct, 0, 0,
                         (char*)pKeyInfo, P4_KEYINFO_HANDOFF);
+    sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
   }else{
     distinct = -1;
   }
@@ -90476,6 +91979,7 @@ SQLITE_PRIVATE int sqlite3Select(
     */
     pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy, 0);
     if( pWInfo==0 ) goto select_end;
+    if( pWInfo->nRowOut < p->nSelectRow ) p->nSelectRow = pWInfo->nRowOut;
 
     /* If sorting index that was created by a prior OP_OpenEphemeral 
     ** instruction ended up not being needed, then change the OP_OpenEphemeral
@@ -90520,6 +92024,9 @@ SQLITE_PRIVATE int sqlite3Select(
       for(k=pGroupBy->nExpr, pItem=pGroupBy->a; k>0; k--, pItem++){
         pItem->iAlias = 0;
       }
+      if( p->nSelectRow>(double)100 ) p->nSelectRow = (double)100;
+    }else{
+      p->nSelectRow = (double)1;
     }
 
  
@@ -90616,6 +92123,9 @@ SQLITE_PRIVATE int sqlite3Select(
         int nCol;
         int nGroupBy;
 
+        explainTempTable(pParse, 
+            isDistinct && !(p->selFlags&SF_Distinct)?"DISTINCT":"GROUP BY");
+
         groupBySort = 1;
         nGroupBy = pGroupBy->nExpr;
         nCol = nGroupBy + 1;
@@ -90877,10 +92387,15 @@ SQLITE_PRIVATE int sqlite3Select(
     
   } /* endif aggregate query */
 
+  if( distinct>=0 ){
+    explainTempTable(pParse, "DISTINCT");
+  }
+
   /* 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 ){
+    explainTempTable(pParse, "ORDER BY");
     generateSortTail(pParse, p, v, pEList->nExpr, pDest);
   }
 
@@ -90897,6 +92412,7 @@ SQLITE_PRIVATE int sqlite3Select(
   ** successful coding of the SELECT.
   */
 select_end:
+  explainSetInteger(pParse->iSelectId, iRestoreSelectId);
 
   /* Identify column names if results of the SELECT are to be output.
   */
@@ -92940,6 +94456,7 @@ static void updateVirtualTable(
   assert( v );
   ephemTab = pParse->nTab++;
   sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, pTab->nCol+1+(pRowid!=0));
+  sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
 
   /* fill the ephemeral table 
   */
@@ -93079,6 +94596,10 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
     sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
     return SQLITE_ERROR;
   }
+  if( db->activeVdbeCnt>1 ){
+    sqlite3SetString(pzErrMsg, db,"cannot VACUUM - SQL statements in progress");
+    return SQLITE_ERROR;
+  }
 
   /* Save the current value of the database flags so that it can be 
   ** restored before returning. Then set the writable-schema flag, and
@@ -93680,7 +95201,7 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
     sqlite3ChangeCookie(pParse, iDb);
 
     sqlite3VdbeAddOp2(v, OP_Expire, 0, 0);
-    zWhere = sqlite3MPrintf(db, "name='%q'", pTab->zName);
+    zWhere = sqlite3MPrintf(db, "name='%q' AND type='table'", pTab->zName);
     sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 1, 0, zWhere, P4_DYNAMIC);
     sqlite3VdbeAddOp4(v, OP_VCreate, iDb, 0, 0, 
                          pTab->zName, sqlite3Strlen30(pTab->zName) + 1);
@@ -93981,7 +95502,7 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
       }
       db->pVTab = 0;
     }else{
-      sqlite3Error(db, SQLITE_ERROR, zErr);
+      sqlite3Error(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr);
       sqlite3DbFree(db, zErr);
       rc = SQLITE_ERROR;
     }
@@ -94443,7 +95964,6 @@ struct WhereMaskSet {
 struct WhereCost {
   WherePlan plan;    /* The lookup strategy */
   double rCost;      /* Overall cost of pursuing this search strategy */
-  double nRow;       /* Estimated number of output rows */
   Bitmask used;      /* Bitmask of cursors used by this plan */
 };
 
@@ -94486,10 +96006,11 @@ struct WhereCost {
 #define WHERE_COLUMN_IN    0x00040000  /* x IN (...) */
 #define WHERE_COLUMN_NULL  0x00080000  /* x IS NULL */
 #define WHERE_INDEXED      0x000f0000  /* Anything that uses an index */
-#define WHERE_NOT_FULLSCAN 0x000f3000  /* Does not do a full table scan */
+#define WHERE_NOT_FULLSCAN 0x100f3000  /* Does not do a full table scan */
 #define WHERE_IN_ABLE      0x000f1000  /* Able to support an IN operator */
 #define WHERE_TOP_LIMIT    0x00100000  /* x<EXPR or x<=EXPR constraint */
 #define WHERE_BTM_LIMIT    0x00200000  /* x>EXPR or x>=EXPR constraint */
+#define WHERE_BOTH_LIMIT   0x00300000  /* Both x>EXPR and x<EXPR */
 #define WHERE_IDX_ONLY     0x00800000  /* Use index only - omit table */
 #define WHERE_ORDERBY      0x01000000  /* Output will appear in correct order */
 #define WHERE_REVERSE      0x02000000  /* Scan in reverse order */
@@ -94920,11 +96441,12 @@ static int isLikeOrGlob(
   }
   if( op==TK_VARIABLE ){
     Vdbe *pReprepare = pParse->pReprepare;
-    pVal = sqlite3VdbeGetValue(pReprepare, pRight->iColumn, SQLITE_AFF_NONE);
+    int iCol = pRight->iColumn;
+    pVal = sqlite3VdbeGetValue(pReprepare, iCol, SQLITE_AFF_NONE);
     if( pVal && sqlite3_value_type(pVal)==SQLITE_TEXT ){
       z = (char *)sqlite3_value_text(pVal);
     }
-    sqlite3VdbeSetVarmask(pParse->pVdbe, pRight->iColumn);
+    sqlite3VdbeSetVarmask(pParse->pVdbe, iCol); /* IMP: R-23257-02778 */
     assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER );
   }else if( op==TK_STRING ){
     z = pRight->u.zToken;
@@ -94942,7 +96464,7 @@ static int isLikeOrGlob(
       *ppPrefix = pPrefix;
       if( op==TK_VARIABLE ){
         Vdbe *v = pParse->pVdbe;
-        sqlite3VdbeSetVarmask(v, pRight->iColumn);
+        sqlite3VdbeSetVarmask(v, pRight->iColumn); /* IMP: R-23257-02778 */
         if( *pisComplete && pRight->u.zToken[1] ){
           /* If the rhs of the LIKE expression is a variable, and the current
           ** value of the variable means there is no need to invoke the LIKE
@@ -95806,7 +97328,8 @@ static void TRACE_IDX_OUTPUTS(sqlite3_index_info *p){
 ** Required because bestIndex() is called by bestOrClauseIndex() 
 */
 static void bestIndex(
-    Parse*, WhereClause*, struct SrcList_item*, Bitmask, ExprList*, WhereCost*);
+    Parse*, WhereClause*, struct SrcList_item*,
+    Bitmask, Bitmask, ExprList*, WhereCost*);
 
 /*
 ** This routine attempts to find an scanning strategy that can be used 
@@ -95819,7 +97342,8 @@ static void bestOrClauseIndex(
   Parse *pParse,              /* The parsing context */
   WhereClause *pWC,           /* The WHERE clause */
   struct SrcList_item *pSrc,  /* The FROM clause term to search */
-  Bitmask notReady,           /* Mask of cursors that are not available */
+  Bitmask notReady,           /* Mask of cursors not available for indexing */
+  Bitmask notValid,           /* Cursors not available for any purpose */
   ExprList *pOrderBy,         /* The ORDER BY clause */
   WhereCost *pCost            /* Lowest cost query plan */
 ){
@@ -95829,8 +97353,9 @@ static void bestOrClauseIndex(
   WhereTerm * const pWCEnd = &pWC->a[pWC->nTerm];        /* End of pWC->a[] */
   WhereTerm *pTerm;                 /* A single term of the WHERE clause */
 
-  /* No OR-clause optimization allowed if the NOT INDEXED clause is used */
-  if( pSrc->notIndexed ){
+  /* No OR-clause optimization allowed if the INDEXED BY or NOT INDEXED clauses
+  ** are used */
+  if( pSrc->notIndexed || pSrc->pIndex!=0 ){
     return;
   }
 
@@ -95855,7 +97380,7 @@ static void bestOrClauseIndex(
         ));
         if( pOrTerm->eOperator==WO_AND ){
           WhereClause *pAndWC = &pOrTerm->u.pAndInfo->wc;
-          bestIndex(pParse, pAndWC, pSrc, notReady, 0, &sTermCost);
+          bestIndex(pParse, pAndWC, pSrc, notReady, notValid, 0, &sTermCost);
         }else if( pOrTerm->leftCursor==iCur ){
           WhereClause tempWC;
           tempWC.pParse = pWC->pParse;
@@ -95863,12 +97388,12 @@ static void bestOrClauseIndex(
           tempWC.op = TK_AND;
           tempWC.a = pOrTerm;
           tempWC.nTerm = 1;
-          bestIndex(pParse, &tempWC, pSrc, notReady, 0, &sTermCost);
+          bestIndex(pParse, &tempWC, pSrc, notReady, notValid, 0, &sTermCost);
         }else{
           continue;
         }
         rTotal += sTermCost.rCost;
-        nRow += sTermCost.nRow;
+        nRow += sTermCost.plan.nRow;
         used |= sTermCost.used;
         if( rTotal>=pCost->rCost ) break;
       }
@@ -95887,8 +97412,8 @@ static void bestOrClauseIndex(
       WHERETRACE(("... multi-index OR cost=%.9g nrow=%.9g\n", rTotal, nRow));
       if( rTotal<pCost->rCost ){
         pCost->rCost = rTotal;
-        pCost->nRow = nRow;
         pCost->used = used;
+        pCost->plan.nRow = nRow;
         pCost->plan.wsFlags = flags;
         pCost->plan.u.pTerm = pTerm;
       }
@@ -95956,7 +97481,7 @@ static void bestAutomaticIndex(
 
   assert( pParse->nQueryLoop >= (double)1 );
   pTable = pSrc->pTab;
-  nTableRow = pTable->pIndex ? pTable->pIndex->aiRowEst[0] : 1000000;
+  nTableRow = pTable->nRowEst;
   logN = estLog(nTableRow);
   costTempIdx = 2*logN*(nTableRow/pParse->nQueryLoop + 1);
   if( costTempIdx>=pCost->rCost ){
@@ -95972,7 +97497,7 @@ static void bestAutomaticIndex(
       WHERETRACE(("auto-index reduces cost from %.2f to %.2f\n",
                     pCost->rCost, costTempIdx));
       pCost->rCost = costTempIdx;
-      pCost->nRow = logN + 1;
+      pCost->plan.nRow = logN + 1;
       pCost->plan.wsFlags = WHERE_TEMP_INDEX;
       pCost->used = pTerm->prereqRight;
       break;
@@ -96310,7 +97835,8 @@ static void bestVirtualIndex(
   Parse *pParse,                  /* The parsing context */
   WhereClause *pWC,               /* The WHERE clause */
   struct SrcList_item *pSrc,      /* The FROM clause term to search */
-  Bitmask notReady,               /* Mask of cursors that are not available */
+  Bitmask notReady,               /* Mask of cursors not available for index */
+  Bitmask notValid,               /* Cursors not valid for any purpose */
   ExprList *pOrderBy,             /* The order by clause */
   WhereCost *pCost,               /* Lowest cost query plan */
   sqlite3_index_info **ppIdxInfo  /* Index information passed to xBestIndex */
@@ -96440,7 +97966,7 @@ static void bestVirtualIndex(
   /* Try to find a more efficient access pattern by using multiple indexes
   ** to optimize an OR expression within the WHERE clause. 
   */
-  bestOrClauseIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost);
+  bestOrClauseIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost);
 }
 #endif /* SQLITE_OMIT_VIRTUALTABLE */
 
@@ -96561,12 +98087,11 @@ static int valueFromExpr(
   u8 aff, 
   sqlite3_value **pp
 ){
-  /* The evalConstExpr() function will have already converted any TK_VARIABLE
-  ** expression involved in an comparison into a TK_REGISTER. */
-  assert( pExpr->op!=TK_VARIABLE );
-  if( pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE ){
+  if( pExpr->op==TK_VARIABLE
+   || (pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE)
+  ){
     int iVar = pExpr->iColumn;
-    sqlite3VdbeSetVarmask(pParse->pVdbe, iVar);
+    sqlite3VdbeSetVarmask(pParse->pVdbe, iVar); /* IMP: R-23257-02778 */
     *pp = sqlite3VdbeGetValue(pParse->pReprepare, iVar, aff);
     return SQLITE_OK;
   }
@@ -96721,7 +98246,8 @@ static void bestBtreeIndex(
   Parse *pParse,              /* The parsing context */
   WhereClause *pWC,           /* The WHERE clause */
   struct SrcList_item *pSrc,  /* The FROM clause term to search */
-  Bitmask notReady,           /* Mask of cursors that are not available */
+  Bitmask notReady,           /* Mask of cursors not available for indexing */
+  Bitmask notValid,           /* Cursors not available for any purpose */
   ExprList *pOrderBy,         /* The ORDER BY clause */
   WhereCost *pCost            /* Lowest cost query plan */
 ){
@@ -96763,23 +98289,14 @@ static void bestBtreeIndex(
     sPk.nColumn = 1;
     sPk.aiColumn = &aiColumnPk;
     sPk.aiRowEst = aiRowEstPk;
-    aiRowEstPk[1] = 1;
     sPk.onError = OE_Replace;
     sPk.pTable = pSrc->pTab;
+    aiRowEstPk[0] = pSrc->pTab->nRowEst;
+    aiRowEstPk[1] = 1;
     pFirst = pSrc->pTab->pIndex;
     if( pSrc->notIndexed==0 ){
       sPk.pNext = pFirst;
     }
-    /* The aiRowEstPk[0] is an estimate of the total number of rows in the
-    ** table.  Get this information from the ANALYZE information if it is
-    ** available.  If not available, assume the table 1 million rows in size.
-    */
-    if( pFirst ){
-      assert( pFirst->aiRowEst!=0 ); /* Allocated together with pFirst */
-      aiRowEstPk[0] = pFirst->aiRowEst[0];
-    }else{
-      aiRowEstPk[0] = 1000000;
-    }
     pProbe = &sPk;
     wsFlagMask = ~(
         WHERE_COLUMN_IN|WHERE_COLUMN_EQ|WHERE_COLUMN_NULL|WHERE_COLUMN_RANGE
@@ -96992,16 +98509,16 @@ static void bestBtreeIndex(
     ** with this step if we already know this index will not be chosen.
     ** Also, never reduce the output row count below 2 using this step.
     **
-    ** Do not reduce the output row count if pSrc is the only table that
-    ** is notReady; if notReady is a power of two.  This will be the case
-    ** when the main sqlite3WhereBegin() loop is scanning for a table with
-    ** and "optimal" index, and on such a scan the output row count
-    ** reduction is not valid because it does not update the "pCost->used"
-    ** bitmap.  The notReady bitmap will also be a power of two when we
-    ** are scanning for the last table in a 64-way join.  We are willing
-    ** to bypass this optimization in that corner case.
+    ** It is critical that the notValid mask be used here instead of
+    ** the notReady mask.  When computing an "optimal" index, the notReady
+    ** mask will only have one bit set - the bit for the current table.
+    ** The notValid mask, on the other hand, always has all bits set for
+    ** tables that are not in outer loops.  If notReady is used here instead
+    ** of notValid, then a optimal index that depends on inner joins loops
+    ** might be selected even when there exists an optimal index that has
+    ** no such dependency.
     */
-    if( nRow>2 && cost<=pCost->rCost && (notReady & (notReady-1))!=0 ){
+    if( nRow>2 && cost<=pCost->rCost ){
       int k;                       /* Loop counter */
       int nSkipEq = nEq;           /* Number of == constraints to skip */
       int nSkipRange = nBound;     /* Number of < constraints to skip */
@@ -97010,7 +98527,7 @@ static void bestBtreeIndex(
       thisTab = getMask(pWC->pMaskSet, iCur);
       for(pTerm=pWC->a, k=pWC->nTerm; nRow>2 && k; k--, pTerm++){
         if( pTerm->wtFlags & TERM_VIRTUAL ) continue;
-        if( (pTerm->prereqAll & notReady)!=thisTab ) continue;
+        if( (pTerm->prereqAll & notValid)!=thisTab ) continue;
         if( pTerm->eOperator & (WO_EQ|WO_IN|WO_ISNULL) ){
           if( nSkipEq ){
             /* Ignore the first nEq equality matches since the index
@@ -97052,11 +98569,11 @@ static void bestBtreeIndex(
     ** index and its cost in the pCost structure.
     */
     if( (!pIdx || wsFlags)
-     && (cost<pCost->rCost || (cost<=pCost->rCost && nRow<pCost->nRow))
+     && (cost<pCost->rCost || (cost<=pCost->rCost && nRow<pCost->plan.nRow))
     ){
       pCost->rCost = cost;
-      pCost->nRow = nRow;
       pCost->used = used;
+      pCost->plan.nRow = nRow;
       pCost->plan.wsFlags = (wsFlags&wsFlagMask);
       pCost->plan.nEq = nEq;
       pCost->plan.u.pIdx = pIdx;
@@ -97092,7 +98609,7 @@ static void bestBtreeIndex(
          pCost->plan.u.pIdx ? pCost->plan.u.pIdx->zName : "ipk")
   ));
   
-  bestOrClauseIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost);
+  bestOrClauseIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost);
   bestAutomaticIndex(pParse, pWC, pSrc, notReady, pCost);
   pCost->plan.wsFlags |= eqTermMask;
 }
@@ -97107,14 +98624,15 @@ static void bestIndex(
   Parse *pParse,              /* The parsing context */
   WhereClause *pWC,           /* The WHERE clause */
   struct SrcList_item *pSrc,  /* The FROM clause term to search */
-  Bitmask notReady,           /* Mask of cursors that are not available */
+  Bitmask notReady,           /* Mask of cursors not available for indexing */
+  Bitmask notValid,           /* Cursors not available for any purpose */
   ExprList *pOrderBy,         /* The ORDER BY clause */
   WhereCost *pCost            /* Lowest cost query plan */
 ){
 #ifndef SQLITE_OMIT_VIRTUALTABLE
   if( IsVirtual(pSrc->pTab) ){
     sqlite3_index_info *p = 0;
-    bestVirtualIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost, &p);
+    bestVirtualIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost,&p);
     if( p->needToFreeIdxStr ){
       sqlite3_free(p->idxStr);
     }
@@ -97122,7 +98640,7 @@ static void bestIndex(
   }else
 #endif
   {
-    bestBtreeIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost);
+    bestBtreeIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost);
   }
 }
 
@@ -97384,6 +98902,161 @@ static int codeAllEqualityTerms(
   return regBase;
 }
 
+#ifndef SQLITE_OMIT_EXPLAIN
+/*
+** This routine is a helper for explainIndexRange() below
+**
+** pStr holds the text of an expression that we are building up one term
+** at a time.  This routine adds a new term to the end of the expression.
+** Terms are separated by AND so add the "AND" text for second and subsequent
+** terms only.
+*/
+static void explainAppendTerm(
+  StrAccum *pStr,             /* The text expression being built */
+  int iTerm,                  /* Index of this term.  First is zero */
+  const char *zColumn,        /* Name of the column */
+  const char *zOp             /* Name of the operator */
+){
+  if( iTerm ) sqlite3StrAccumAppend(pStr, " AND ", 5);
+  sqlite3StrAccumAppend(pStr, zColumn, -1);
+  sqlite3StrAccumAppend(pStr, zOp, 1);
+  sqlite3StrAccumAppend(pStr, "?", 1);
+}
+
+/*
+** Argument pLevel describes a strategy for scanning table pTab. This 
+** function returns a pointer to a string buffer containing a description
+** of the subset of table rows scanned by the strategy in the form of an
+** SQL expression. Or, if all rows are scanned, NULL is returned.
+**
+** For example, if the query:
+**
+**   SELECT * FROM t1 WHERE a=1 AND b>2;
+**
+** is run and there is an index on (a, b), then this function returns a
+** string similar to:
+**
+**   "a=? AND b>?"
+**
+** The returned pointer points to memory obtained from sqlite3DbMalloc().
+** It is the responsibility of the caller to free the buffer when it is
+** no longer required.
+*/
+static char *explainIndexRange(sqlite3 *db, WhereLevel *pLevel, Table *pTab){
+  WherePlan *pPlan = &pLevel->plan;
+  Index *pIndex = pPlan->u.pIdx;
+  int nEq = pPlan->nEq;
+  int i, j;
+  Column *aCol = pTab->aCol;
+  int *aiColumn = pIndex->aiColumn;
+  StrAccum txt;
+
+  if( nEq==0 && (pPlan->wsFlags & (WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ){
+    return 0;
+  }
+  sqlite3StrAccumInit(&txt, 0, 0, SQLITE_MAX_LENGTH);
+  txt.db = db;
+  sqlite3StrAccumAppend(&txt, " (", 2);
+  for(i=0; i<nEq; i++){
+    explainAppendTerm(&txt, i, aCol[aiColumn[i]].zName, "=");
+  }
+
+  j = i;
+  if( pPlan->wsFlags&WHERE_BTM_LIMIT ){
+    explainAppendTerm(&txt, i++, aCol[aiColumn[j]].zName, ">");
+  }
+  if( pPlan->wsFlags&WHERE_TOP_LIMIT ){
+    explainAppendTerm(&txt, i, aCol[aiColumn[j]].zName, "<");
+  }
+  sqlite3StrAccumAppend(&txt, ")", 1);
+  return sqlite3StrAccumFinish(&txt);
+}
+
+/*
+** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN
+** command. If the query being compiled is an EXPLAIN QUERY PLAN, a single
+** record is added to the output to describe the table scan strategy in 
+** pLevel.
+*/
+static void explainOneScan(
+  Parse *pParse,                  /* Parse context */
+  SrcList *pTabList,              /* Table list this loop refers to */
+  WhereLevel *pLevel,             /* Scan to write OP_Explain opcode for */
+  int iLevel,                     /* Value for "level" column of output */
+  int iFrom,                      /* Value for "from" column of output */
+  u16 wctrlFlags                  /* Flags passed to sqlite3WhereBegin() */
+){
+  if( pParse->explain==2 ){
+    u32 flags = pLevel->plan.wsFlags;
+    struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom];
+    Vdbe *v = pParse->pVdbe;      /* VM being constructed */
+    sqlite3 *db = pParse->db;     /* Database handle */
+    char *zMsg;                   /* Text to add to EQP output */
+    sqlite3_int64 nRow;           /* Expected number of rows visited by scan */
+    int iId = pParse->iSelectId;  /* Select id (left-most output column) */
+    int isSearch;                 /* True for a SEARCH. False for SCAN. */
+
+    if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return;
+
+    isSearch = (pLevel->plan.nEq>0)
+             || (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0
+             || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX));
+
+    zMsg = sqlite3MPrintf(db, "%s", isSearch?"SEARCH":"SCAN");
+    if( pItem->pSelect ){
+      zMsg = sqlite3MAppendf(db, zMsg, "%s SUBQUERY %d", zMsg,pItem->iSelectId);
+    }else{
+      zMsg = sqlite3MAppendf(db, zMsg, "%s TABLE %s", zMsg, pItem->zName);
+    }
+
+    if( pItem->zAlias ){
+      zMsg = sqlite3MAppendf(db, zMsg, "%s AS %s", zMsg, pItem->zAlias);
+    }
+    if( (flags & WHERE_INDEXED)!=0 ){
+      char *zWhere = explainIndexRange(db, pLevel, pItem->pTab);
+      zMsg = sqlite3MAppendf(db, zMsg, "%s USING %s%sINDEX%s%s%s", zMsg, 
+          ((flags & WHERE_TEMP_INDEX)?"AUTOMATIC ":""),
+          ((flags & WHERE_IDX_ONLY)?"COVERING ":""),
+          ((flags & WHERE_TEMP_INDEX)?"":" "),
+          ((flags & WHERE_TEMP_INDEX)?"": pLevel->plan.u.pIdx->zName),
+          zWhere
+      );
+      sqlite3DbFree(db, zWhere);
+    }else if( flags & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){
+      zMsg = sqlite3MAppendf(db, zMsg, "%s USING INTEGER PRIMARY KEY", zMsg);
+
+      if( flags&WHERE_ROWID_EQ ){
+        zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid=?)", zMsg);
+      }else if( (flags&WHERE_BOTH_LIMIT)==WHERE_BOTH_LIMIT ){
+        zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid>? AND rowid<?)", zMsg);
+      }else if( flags&WHERE_BTM_LIMIT ){
+        zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid>?)", zMsg);
+      }else if( flags&WHERE_TOP_LIMIT ){
+        zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid<?)", zMsg);
+      }
+    }
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+    else if( (flags & WHERE_VIRTUALTABLE)!=0 ){
+      sqlite3_index_info *pVtabIdx = pLevel->plan.u.pVtabIdx;
+      zMsg = sqlite3MAppendf(db, zMsg, "%s VIRTUAL TABLE INDEX %d:%s", zMsg,
+                  pVtabIdx->idxNum, pVtabIdx->idxStr);
+    }
+#endif
+    if( wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX) ){
+      testcase( wctrlFlags & WHERE_ORDERBY_MIN );
+      nRow = 1;
+    }else{
+      nRow = (sqlite3_int64)pLevel->plan.nRow;
+    }
+    zMsg = sqlite3MAppendf(db, zMsg, "%s (~%lld rows)", zMsg, nRow);
+    sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg, P4_DYNAMIC);
+  }
+}
+#else
+# define explainOneScan(u,v,w,x,y,z)
+#endif /* SQLITE_OMIT_EXPLAIN */
+
+
 /*
 ** Generate code for the start of the iLevel-th loop in the WHERE clause
 ** implementation described by pWInfo.
@@ -97791,7 +99464,7 @@ static Bitmask codeOneLoopStart(
     r1 = sqlite3GetTempReg(pParse);
     testcase( pLevel->plan.wsFlags & WHERE_BTM_LIMIT );
     testcase( pLevel->plan.wsFlags & WHERE_TOP_LIMIT );
-    if( pLevel->plan.wsFlags & (WHERE_BTM_LIMIT|WHERE_TOP_LIMIT) ){
+    if( (pLevel->plan.wsFlags & (WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0 ){
       sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, nEq, r1);
       sqlite3VdbeAddOp2(v, OP_IsNull, r1, addrCont);
     }
@@ -97925,6 +99598,9 @@ static Bitmask codeOneLoopStart(
                         WHERE_OMIT_OPEN | WHERE_OMIT_CLOSE |
                         WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY);
         if( pSubWInfo ){
+          explainOneScan(
+              pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0
+          );
           if( (wctrlFlags & WHERE_DUPLICATES_OK)==0 ){
             int iSet = ((ii==pOrWc->nTerm-1)?-1:ii);
             int r;
@@ -98320,6 +99996,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
 
     memset(&bestPlan, 0, sizeof(bestPlan));
     bestPlan.rCost = SQLITE_BIG_DBL;
+    WHERETRACE(("*** Begin search for loop %d ***\n", i));
 
     /* Loop through the remaining entries in the FROM clause to find the
     ** next nested loop. The loop tests all FROM clause entries
@@ -98338,9 +100015,15 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
     ** other FROM clause terms that are notReady.  If no notReady terms are
     ** used then the "optimal" query plan works.
     **
+    ** Note that the WhereCost.nRow parameter for an optimal scan might
+    ** not be as small as it would be if the table really were the innermost
+    ** join.  The nRow value can be reduced by WHERE clause constraints
+    ** that do not use indices.  But this nRow reduction only happens if the
+    ** table really is the innermost join.  
+    **
     ** The second loop iteration is only performed if no optimal scan
-    ** strategies were found by the first loop. This 2nd iteration is used to
-    ** search for the lowest cost scan overall.
+    ** strategies were found by the first iteration. This second iteration
+    ** is used to search for the lowest cost scan overall.
     **
     ** Previous versions of SQLite performed only the second iteration -
     ** the next outermost loop was always that with the lowest overall
@@ -98353,14 +100036,14 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
     **
     ** The best strategy is to iterate through table t1 first. However it
     ** is not possible to determine this with a simple greedy algorithm.
-    ** However, since the cost of a linear scan through table t2 is the same 
+    ** Since the cost of a linear scan through table t2 is the same 
     ** as the cost of a linear scan through table t1, a simple greedy 
     ** algorithm may choose to use t2 for the outer loop, which is a much
     ** costlier approach.
     */
     nUnconstrained = 0;
     notIndexed = 0;
-    for(isOptimal=(iFrom<nTabList-1); isOptimal>=0; isOptimal--){
+    for(isOptimal=(iFrom<nTabList-1); isOptimal>=0 && bestJ<0; isOptimal--){
       Bitmask mask;             /* Mask of tables not yet ready */
       for(j=iFrom, pTabItem=&pTabList->a[j]; j<nTabList; j++, pTabItem++){
         int doNotReorder;    /* True if this table should not be reordered */
@@ -98378,15 +100061,19 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
         pOrderBy = ((i==0 && ppOrderBy )?*ppOrderBy:0);
         if( pTabItem->pIndex==0 ) nUnconstrained++;
   
+        WHERETRACE(("=== trying table %d with isOptimal=%d ===\n",
+                    j, isOptimal));
         assert( pTabItem->pTab );
 #ifndef SQLITE_OMIT_VIRTUALTABLE
         if( IsVirtual(pTabItem->pTab) ){
           sqlite3_index_info **pp = &pWInfo->a[j].pIdxInfo;
-          bestVirtualIndex(pParse, pWC, pTabItem, mask, pOrderBy, &sCost, pp);
+          bestVirtualIndex(pParse, pWC, pTabItem, mask, notReady, pOrderBy,
+                           &sCost, pp);
         }else 
 #endif
         {
-          bestBtreeIndex(pParse, pWC, pTabItem, mask, pOrderBy, &sCost);
+          bestBtreeIndex(pParse, pWC, pTabItem, mask, notReady, pOrderBy,
+                         &sCost);
         }
         assert( isOptimal || (sCost.used&notReady)==0 );
 
@@ -98426,10 +100113,12 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
             && (nUnconstrained==0 || pTabItem->pIndex==0   /* (3) */
                 || NEVER((sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0))
             && (bestJ<0 || sCost.rCost<bestPlan.rCost      /* (4) */
-                || (sCost.rCost<=bestPlan.rCost && sCost.nRow<bestPlan.nRow))
+                || (sCost.rCost<=bestPlan.rCost 
+                 && sCost.plan.nRow<bestPlan.plan.nRow))
         ){
-          WHERETRACE(("... best so far with cost=%g and nRow=%g\n",
-                      sCost.rCost, sCost.nRow));
+          WHERETRACE(("=== table %d is best so far"
+                      " with cost=%g and nRow=%g\n",
+                      j, sCost.rCost, sCost.plan.nRow));
           bestPlan = sCost;
           bestJ = j;
         }
@@ -98438,8 +100127,9 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
     }
     assert( bestJ>=0 );
     assert( notReady & getMask(pMaskSet, pTabList->a[bestJ].iCursor) );
-    WHERETRACE(("*** Optimizer selects table %d for loop %d\n", bestJ,
-           pLevel-pWInfo->a));
+    WHERETRACE(("*** Optimizer selects table %d for loop %d"
+                " with cost=%g and nRow=%g\n",
+                bestJ, pLevel-pWInfo->a, bestPlan.rCost, bestPlan.plan.nRow));
     if( (bestPlan.plan.wsFlags & WHERE_ORDERBY)!=0 ){
       *ppOrderBy = 0;
     }
@@ -98454,7 +100144,9 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
     }
     notReady &= ~getMask(pMaskSet, pTabList->a[bestJ].iCursor);
     pLevel->iFrom = (u8)bestJ;
-    if( bestPlan.nRow>=(double)1 ) pParse->nQueryLoop *= bestPlan.nRow;
+    if( bestPlan.plan.nRow>=(double)1 ){
+      pParse->nQueryLoop *= bestPlan.plan.nRow;
+    }
 
     /* Check that if the table scanned by this loop iteration had an
     ** INDEXED BY clause attached to it, that the named index is being
@@ -98502,44 +100194,15 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
   */
   sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */
   notReady = ~(Bitmask)0;
+  pWInfo->nRowOut = (double)1;
   for(i=0, pLevel=pWInfo->a; i<nTabList; i++, pLevel++){
     Table *pTab;     /* Table to open */
     int iDb;         /* Index of database containing table/index */
 
-#ifndef SQLITE_OMIT_EXPLAIN
-    if( pParse->explain==2 ){
-      char *zMsg;
-      struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom];
-      zMsg = sqlite3MPrintf(db, "TABLE %s", pItem->zName);
-      if( pItem->zAlias ){
-        zMsg = sqlite3MAppendf(db, zMsg, "%s AS %s", zMsg, pItem->zAlias);
-      }
-      if( (pLevel->plan.wsFlags & WHERE_TEMP_INDEX)!=0 ){
-        zMsg = sqlite3MAppendf(db, zMsg, "%s WITH AUTOMATIC INDEX", zMsg);
-      }else if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){
-        zMsg = sqlite3MAppendf(db, zMsg, "%s WITH INDEX %s",
-           zMsg, pLevel->plan.u.pIdx->zName);
-      }else if( pLevel->plan.wsFlags & WHERE_MULTI_OR ){
-        zMsg = sqlite3MAppendf(db, zMsg, "%s VIA MULTI-INDEX UNION", zMsg);
-      }else if( pLevel->plan.wsFlags & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){
-        zMsg = sqlite3MAppendf(db, zMsg, "%s USING PRIMARY KEY", zMsg);
-      }
-#ifndef SQLITE_OMIT_VIRTUALTABLE
-      else if( (pLevel->plan.wsFlags & WHERE_VIRTUALTABLE)!=0 ){
-        sqlite3_index_info *pVtabIdx = pLevel->plan.u.pVtabIdx;
-        zMsg = sqlite3MAppendf(db, zMsg, "%s VIRTUAL TABLE INDEX %d:%s", zMsg,
-                    pVtabIdx->idxNum, pVtabIdx->idxStr);
-      }
-#endif
-      if( pLevel->plan.wsFlags & WHERE_ORDERBY ){
-        zMsg = sqlite3MAppendf(db, zMsg, "%s ORDER BY", zMsg);
-      }
-      sqlite3VdbeAddOp4(v, OP_Explain, i, pLevel->iFrom, 0, zMsg, P4_DYNAMIC);
-    }
-#endif /* SQLITE_OMIT_EXPLAIN */
     pTabItem = &pTabList->a[pLevel->iFrom];
     pTab = pTabItem->pTab;
     pLevel->iTabCur = pTabItem->iCursor;
+    pWInfo->nRowOut *= pLevel->plan.nRow;
     iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
     if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ){
       /* Do nothing */
@@ -98595,8 +100258,10 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
   */
   notReady = ~(Bitmask)0;
   for(i=0; i<nTabList; i++){
+    pLevel = &pWInfo->a[i];
+    explainOneScan(pParse, pTabList, pLevel, i, pLevel->iFrom, wctrlFlags);
     notReady = codeOneLoopStart(pWInfo, i, wctrlFlags, notReady);
-    pWInfo->iContinue = pWInfo->a[i].addrCont;
+    pWInfo->iContinue = pLevel->addrCont;
   }
 
 #ifdef SQLITE_TEST  /* For testing and debugging use only */
@@ -103422,15 +105087,33 @@ SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db);
 /************** Continuing where we left off in main.c ***********************/
 #endif
 
-/*
-** The version of the library
-*/
 #ifndef SQLITE_AMALGAMATION
+/* IMPLEMENTATION-OF: R-46656-45156 The sqlite3_version[] string constant
+** contains the text of SQLITE_VERSION macro. 
+*/
 SQLITE_API const char sqlite3_version[] = SQLITE_VERSION;
 #endif
+
+/* IMPLEMENTATION-OF: R-53536-42575 The sqlite3_libversion() function returns
+** a pointer to the to the sqlite3_version[] string constant. 
+*/
 SQLITE_API const char *sqlite3_libversion(void){ return sqlite3_version; }
+
+/* IMPLEMENTATION-OF: R-63124-39300 The sqlite3_sourceid() function returns a
+** pointer to a string constant whose value is the same as the
+** SQLITE_SOURCE_ID C preprocessor macro. 
+*/
 SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
+
+/* IMPLEMENTATION-OF: R-35210-63508 The sqlite3_libversion_number() function
+** returns an integer equal to SQLITE_VERSION_NUMBER.
+*/
 SQLITE_API int sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; }
+
+/* IMPLEMENTATION-OF: R-54823-41343 The sqlite3_threadsafe() function returns
+** zero if and only if SQLite was compiled mutexing code omitted due to
+** the SQLITE_THREADSAFE compile-time option being set to 0.
+*/
 SQLITE_API int sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; }
 
 #if !defined(SQLITE_OMIT_TRACE) && defined(SQLITE_ENABLE_IOTRACE)
@@ -103551,6 +105234,13 @@ SQLITE_API int sqlite3_initialize(void){
   ** sqlite3_initialize().  The recursive calls normally come through
   ** sqlite3_os_init() when it invokes sqlite3_vfs_register(), but other
   ** recursive calls might also be possible.
+  **
+  ** IMPLEMENTATION-OF: R-00140-37445 SQLite automatically serializes calls
+  ** to the xInit method, so the xInit method need not be threadsafe.
+  **
+  ** The following mutex is what serializes access to the appdef pcache xInit
+  ** methods.  The sqlite3_pcache_methods.xInit() all is embedded in the
+  ** call to sqlite3PcacheInitialize().
   */
   sqlite3_mutex_enter(sqlite3GlobalConfig.pInitMutex);
   if( sqlite3GlobalConfig.isInit==0 && sqlite3GlobalConfig.inProgress==0 ){
@@ -103831,12 +105521,12 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
     sz = 0;
     pStart = 0;
   }else if( pBuf==0 ){
-    sz = ROUND8(sz);
+    sz = ROUNDDOWN8(sz); /* IMP: R-33038-09382 */
     sqlite3BeginBenignMalloc();
-    pStart = sqlite3Malloc( sz*cnt );
+    pStart = sqlite3Malloc( sz*cnt );  /* IMP: R-61949-35727 */
     sqlite3EndBenignMalloc();
   }else{
-    sz = ROUNDDOWN8(sz);
+    sz = ROUNDDOWN8(sz); /* IMP: R-33038-09382 */
     pStart = pBuf;
   }
   db->lookaside.pStart = pStart;
@@ -103879,14 +105569,14 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){
   va_start(ap, op);
   switch( op ){
     case SQLITE_DBCONFIG_LOOKASIDE: {
-      void *pBuf = va_arg(ap, void*);
-      int sz = va_arg(ap, int);
-      int cnt = va_arg(ap, int);
+      void *pBuf = va_arg(ap, void*); /* IMP: R-21112-12275 */
+      int sz = va_arg(ap, int);       /* IMP: R-47871-25994 */
+      int cnt = va_arg(ap, int);      /* IMP: R-04460-53386 */
       rc = setupLookaside(db, pBuf, sz, cnt);
       break;
     }
     default: {
-      rc = SQLITE_ERROR;
+      rc = SQLITE_ERROR; /* IMP: R-42790-23372 */
       break;
     }
   }
@@ -103992,10 +105682,27 @@ SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *db){
 }
 
 /*
+** Invoke the destructor function associated with FuncDef p, if any. Except,
+** if this is not the last copy of the function, do not invoke it. Multiple
+** copies of a single function are created when create_function() is called
+** with SQLITE_ANY as the encoding.
+*/
+static void functionDestroy(sqlite3 *db, FuncDef *p){
+  FuncDestructor *pDestructor = p->pDestructor;
+  if( pDestructor ){
+    pDestructor->nRef--;
+    if( pDestructor->nRef==0 ){
+      pDestructor->xDestroy(pDestructor->pUserData);
+      sqlite3DbFree(db, pDestructor);
+    }
+  }
+}
+
+/*
 ** Close an existing SQLite database
 */
 SQLITE_API int sqlite3_close(sqlite3 *db){
-  HashElem *i;
+  HashElem *i;                    /* Hash table iterator */
   int j;
 
   if( !db ){
@@ -104063,6 +105770,7 @@ SQLITE_API int sqlite3_close(sqlite3 *db){
     for(p=db->aFunc.a[j]; p; p=pHash){
       pHash = p->pHash;
       while( p ){
+        functionDestroy(db, p);
         pNext = p->pNext;
         sqlite3DbFree(db, p);
         p = pNext;
@@ -104169,7 +105877,7 @@ SQLITE_PRIVATE const char *sqlite3ErrStr(int rc){
     /* SQLITE_INTERRUPT   */ "interrupted",
     /* SQLITE_IOERR       */ "disk I/O error",
     /* SQLITE_CORRUPT     */ "database disk image is malformed",
-    /* SQLITE_NOTFOUND    */ 0,
+    /* SQLITE_NOTFOUND    */ "unknown operation",
     /* SQLITE_FULL        */ "database or disk is full",
     /* SQLITE_CANTOPEN    */ "unable to open database file",
     /* SQLITE_PROTOCOL    */ "locking protocol",
@@ -104337,7 +106045,8 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
   void *pUserData,
   void (*xFunc)(sqlite3_context*,int,sqlite3_value **),
   void (*xStep)(sqlite3_context*,int,sqlite3_value **),
-  void (*xFinal)(sqlite3_context*)
+  void (*xFinal)(sqlite3_context*),
+  FuncDestructor *pDestructor
 ){
   FuncDef *p;
   int nName;
@@ -104365,10 +106074,10 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
   }else if( enc==SQLITE_ANY ){
     int rc;
     rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8,
-         pUserData, xFunc, xStep, xFinal);
+         pUserData, xFunc, xStep, xFinal, pDestructor);
     if( rc==SQLITE_OK ){
       rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE,
-          pUserData, xFunc, xStep, xFinal);
+          pUserData, xFunc, xStep, xFinal, pDestructor);
     }
     if( rc!=SQLITE_OK ){
       return rc;
@@ -104401,6 +106110,15 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
   if( !p ){
     return SQLITE_NOMEM;
   }
+
+  /* If an older version of the function with a configured destructor is
+  ** being replaced invoke the destructor function here. */
+  functionDestroy(db, p);
+
+  if( pDestructor ){
+    pDestructor->nRef++;
+  }
+  p->pDestructor = pDestructor;
   p->flags = 0;
   p->xFunc = xFunc;
   p->xStep = xStep;
@@ -104415,7 +106133,7 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
 */
 SQLITE_API int sqlite3_create_function(
   sqlite3 *db,
-  const char *zFunctionName,
+  const char *zFunc,
   int nArg,
   int enc,
   void *p,
@@ -104423,9 +106141,41 @@ SQLITE_API int sqlite3_create_function(
   void (*xStep)(sqlite3_context*,int,sqlite3_value **),
   void (*xFinal)(sqlite3_context*)
 ){
-  int rc;
+  return sqlite3_create_function_v2(db, zFunc, nArg, enc, p, xFunc, xStep,
+                                    xFinal, 0);
+}
+
+SQLITE_API int sqlite3_create_function_v2(
+  sqlite3 *db,
+  const char *zFunc,
+  int nArg,
+  int enc,
+  void *p,
+  void (*xFunc)(sqlite3_context*,int,sqlite3_value **),
+  void (*xStep)(sqlite3_context*,int,sqlite3_value **),
+  void (*xFinal)(sqlite3_context*),
+  void (*xDestroy)(void *)
+){
+  int rc = SQLITE_ERROR;
+  FuncDestructor *pArg = 0;
   sqlite3_mutex_enter(db->mutex);
-  rc = sqlite3CreateFunc(db, zFunctionName, nArg, enc, p, xFunc, xStep, xFinal);
+  if( xDestroy ){
+    pArg = (FuncDestructor *)sqlite3DbMallocZero(db, sizeof(FuncDestructor));
+    if( !pArg ){
+      xDestroy(p);
+      goto out;
+    }
+    pArg->xDestroy = xDestroy;
+    pArg->pUserData = p;
+  }
+  rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, xFunc, xStep, xFinal, pArg);
+  if( pArg && pArg->nRef==0 ){
+    assert( rc!=SQLITE_OK );
+    xDestroy(p);
+    sqlite3DbFree(db, pArg);
+  }
+
+ out:
   rc = sqlite3ApiExit(db, rc);
   sqlite3_mutex_leave(db->mutex);
   return rc;
@@ -104447,7 +106197,7 @@ SQLITE_API int sqlite3_create_function16(
   sqlite3_mutex_enter(db->mutex);
   assert( !db->mallocFailed );
   zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1, SQLITE_UTF16NATIVE);
-  rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xFunc, xStep, xFinal);
+  rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xFunc, xStep, xFinal,0);
   sqlite3DbFree(db, zFunc8);
   rc = sqlite3ApiExit(db, rc);
   sqlite3_mutex_leave(db->mutex);
@@ -104478,7 +106228,7 @@ SQLITE_API int sqlite3_overload_function(
   sqlite3_mutex_enter(db->mutex);
   if( sqlite3FindFunction(db, zName, nName, nArg, SQLITE_UTF8, 0)==0 ){
     sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8,
-                      0, sqlite3InvalidFunction, 0, 0);
+                      0, sqlite3InvalidFunction, 0, 0, 0);
   }
   rc = sqlite3ApiExit(db, SQLITE_OK);
   sqlite3_mutex_leave(db->mutex);
@@ -104616,7 +106366,10 @@ SQLITE_PRIVATE int sqlite3WalDefaultHook(
 ** configured by this function.
 */
 SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame){
-#ifndef SQLITE_OMIT_WAL
+#ifdef SQLITE_OMIT_WAL
+  UNUSED_PARAMETER(db);
+  UNUSED_PARAMETER(nFrame);
+#else
   if( nFrame>0 ){
     sqlite3_wal_hook(db, sqlite3WalDefaultHook, SQLITE_INT_TO_PTR(nFrame));
   }else{
@@ -104747,60 +106500,6 @@ SQLITE_PRIVATE int sqlite3TempInMemory(const sqlite3 *db){
 }
 
 /*
-** 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 a "virtual" database for transient use only and is deleted as
-** soon as the connection is closed.
-**
-** A virtual database can be either a disk file (that is automatically
-** deleted when the file is closed) or it an be held entirely in memory.
-** The sqlite3TempInMemory() function is used to determine which.
-*/
-SQLITE_PRIVATE int sqlite3BtreeFactory(
-  sqlite3 *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 */
-  int vfsFlags,             /* Flags passed through to vfsOpen */
-  Btree **ppBtree           /* Pointer to new Btree object written here */
-){
-  int btFlags = 0;
-  int rc;
-  
-  assert( sqlite3_mutex_held(db->mutex) );
-  assert( ppBtree != 0);
-  if( omitJournal ){
-    btFlags |= BTREE_OMIT_JOURNAL;
-  }
-  if( db->flags & SQLITE_NoReadlock ){
-    btFlags |= BTREE_NO_READLOCK;
-  }
-#ifndef SQLITE_OMIT_MEMORYDB
-  if( zFilename==0 && sqlite3TempInMemory(db) ){
-    zFilename = ":memory:";
-  }
-#endif
-
-  if( (vfsFlags & SQLITE_OPEN_MAIN_DB)!=0 && (zFilename==0 || *zFilename==0) ){
-    vfsFlags = (vfsFlags & ~SQLITE_OPEN_MAIN_DB) | SQLITE_OPEN_TEMP_DB;
-  }
-  rc = sqlite3BtreeOpen(zFilename, (sqlite3 *)db, ppBtree, btFlags, vfsFlags);
-
-  /* If the B-Tree was successfully opened, set the pager-cache size to the
-  ** default value. Except, if the call to BtreeOpen() returned a handle
-  ** open on an existing shared pager-cache, do not change the pager-cache 
-  ** size.
-  */
-  if( rc==SQLITE_OK && 0==sqlite3BtreeSchema(*ppBtree, 0, 0) ){
-    sqlite3BtreeSetCacheSize(*ppBtree, nCache);
-  }
-  return rc;
-}
-
-/*
 ** Return UTF-8 encoded English language explanation of the most recent
 ** error.
 */
@@ -104964,13 +106663,12 @@ static int createCollation(
   }
 
   pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, 1);
-  if( pColl ){
-    pColl->xCmp = xCompare;
-    pColl->pUser = pCtx;
-    pColl->xDel = xDel;
-    pColl->enc = (u8)(enc2 | (enc & SQLITE_UTF16_ALIGNED));
-    pColl->type = collType;
-  }
+  if( pColl==0 ) return SQLITE_NOMEM;
+  pColl->xCmp = xCompare;
+  pColl->pUser = pCtx;
+  pColl->xDel = xDel;
+  pColl->enc = (u8)(enc2 | (enc & SQLITE_UTF16_ALIGNED));
+  pColl->type = collType;
   sqlite3Error(db, SQLITE_OK, 0);
   return SQLITE_OK;
 }
@@ -105042,17 +106740,39 @@ static const int aHardLimit[] = {
 */
 SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
   int oldLimit;
+
+
+  /* EVIDENCE-OF: R-30189-54097 For each limit category SQLITE_LIMIT_NAME
+  ** there is a hard upper bound set at compile-time by a C preprocessor
+  ** macro called SQLITE_MAX_NAME. (The "_LIMIT_" in the name is changed to
+  ** "_MAX_".)
+  */
+  assert( aHardLimit[SQLITE_LIMIT_LENGTH]==SQLITE_MAX_LENGTH );
+  assert( aHardLimit[SQLITE_LIMIT_SQL_LENGTH]==SQLITE_MAX_SQL_LENGTH );
+  assert( aHardLimit[SQLITE_LIMIT_COLUMN]==SQLITE_MAX_COLUMN );
+  assert( aHardLimit[SQLITE_LIMIT_EXPR_DEPTH]==SQLITE_MAX_EXPR_DEPTH );
+  assert( aHardLimit[SQLITE_LIMIT_COMPOUND_SELECT]==SQLITE_MAX_COMPOUND_SELECT);
+  assert( aHardLimit[SQLITE_LIMIT_VDBE_OP]==SQLITE_MAX_VDBE_OP );
+  assert( aHardLimit[SQLITE_LIMIT_FUNCTION_ARG]==SQLITE_MAX_FUNCTION_ARG );
+  assert( aHardLimit[SQLITE_LIMIT_ATTACHED]==SQLITE_MAX_ATTACHED );
+  assert( aHardLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]==
+                                               SQLITE_MAX_LIKE_PATTERN_LENGTH );
+  assert( aHardLimit[SQLITE_LIMIT_VARIABLE_NUMBER]==SQLITE_MAX_VARIABLE_NUMBER);
+  assert( aHardLimit[SQLITE_LIMIT_TRIGGER_DEPTH]==SQLITE_MAX_TRIGGER_DEPTH );
+  assert( SQLITE_LIMIT_TRIGGER_DEPTH==(SQLITE_N_LIMIT-1) );
+
+
   if( limitId<0 || limitId>=SQLITE_N_LIMIT ){
     return -1;
   }
   oldLimit = db->aLimit[limitId];
-  if( newLimit>=0 ){
+  if( newLimit>=0 ){                   /* IMP: R-52476-28732 */
     if( newLimit>aHardLimit[limitId] ){
-      newLimit = aHardLimit[limitId];
+      newLimit = aHardLimit[limitId];  /* IMP: R-51463-25634 */
     }
     db->aLimit[limitId] = newLimit;
   }
-  return oldLimit;
+  return oldLimit;                     /* IMP: R-53341-35419 */
 }
 
 /*
@@ -105076,6 +106796,24 @@ static int openDatabase(
   if( rc ) return rc;
 #endif
 
+  /* Only allow sensible combinations of bits in the flags argument.  
+  ** Throw an error if any non-sense combination is used.  If we
+  ** do not block illegal combinations here, it could trigger
+  ** assert() statements in deeper layers.  Sensible combinations
+  ** are:
+  **
+  **  1:  SQLITE_OPEN_READONLY
+  **  2:  SQLITE_OPEN_READWRITE
+  **  6:  SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE
+  */
+  assert( SQLITE_OPEN_READONLY  == 0x01 );
+  assert( SQLITE_OPEN_READWRITE == 0x02 );
+  assert( SQLITE_OPEN_CREATE    == 0x04 );
+  testcase( (1<<(flags&7))==0x02 ); /* READONLY */
+  testcase( (1<<(flags&7))==0x04 ); /* READWRITE */
+  testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */
+  if( ((1<<(flags&7)) & 0x46)==0 ) return SQLITE_MISUSE;
+
   if( sqlite3GlobalConfig.bCoreMutex==0 ){
     isThreadsafe = 0;
   }else if( flags & SQLITE_OPEN_NOMUTEX ){
@@ -105109,7 +106847,8 @@ static int openDatabase(
                SQLITE_OPEN_SUBJOURNAL | 
                SQLITE_OPEN_MASTER_JOURNAL |
                SQLITE_OPEN_NOMUTEX |
-               SQLITE_OPEN_FULLMUTEX
+               SQLITE_OPEN_FULLMUTEX |
+               SQLITE_OPEN_WAL
              );
 
   /* Allocate the sqlite data structure */
@@ -105144,6 +106883,9 @@ static int openDatabase(
 #if SQLITE_DEFAULT_RECURSIVE_TRIGGERS
                  | SQLITE_RecTriggers
 #endif
+#if defined(SQLITE_DEFAULT_FOREIGN_KEYS) && SQLITE_DEFAULT_FOREIGN_KEYS
+                 | SQLITE_ForeignKeys
+#endif
       ;
   sqlite3HashInit(&db->aCollSeq);
 #ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -105181,9 +106923,8 @@ static int openDatabase(
 
   /* Open the backend database driver */
   db->openFlags = flags;
-  rc = sqlite3BtreeFactory(db, zFilename, 0, SQLITE_DEFAULT_CACHE_SIZE, 
-                           flags | SQLITE_OPEN_MAIN_DB,
-                           &db->aDb[0].pBt);
+  rc = sqlite3BtreeOpen(zFilename, db, &db->aDb[0].pBt, 0,
+                        flags | SQLITE_OPEN_MAIN_DB);
   if( rc!=SQLITE_OK ){
     if( rc==SQLITE_IOERR_NOMEM ){
       rc = SQLITE_NOMEM;
@@ -105679,8 +107420,13 @@ SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, vo
       assert( pPager!=0 );
       fd = sqlite3PagerFile(pPager);
       assert( fd!=0 );
-      if( fd->pMethods ){
+      if( op==SQLITE_FCNTL_FILE_POINTER ){
+        *(sqlite3_file**)pArg = fd;
+        rc = SQLITE_OK;
+      }else if( fd->pMethods ){
         rc = sqlite3OsFileControl(fd, op, pArg);
+      }else{
+        rc = SQLITE_NOTFOUND;
       }
       sqlite3BtreeLeave(pBtree);
     }
@@ -105890,6 +107636,22 @@ SQLITE_API int sqlite3_test_control(int op, ...){
       break;
     }
 
+    /* sqlite3_test_control(SQLITE_TESTCTRL_SCRATCHMALLOC, sz, &pNew, pFree);
+    **
+    ** Pass pFree into sqlite3ScratchFree(). 
+    ** If sz>0 then allocate a scratch buffer into pNew.  
+    */
+    case SQLITE_TESTCTRL_SCRATCHMALLOC: {
+      void *pFree, **ppNew;
+      int sz;
+      sz = va_arg(ap, int);
+      ppNew = va_arg(ap, void**);
+      pFree = va_arg(ap, void*);
+      if( sz ) *ppNew = sqlite3ScratchMalloc(sz);
+      sqlite3ScratchFree(pFree);
+      break;
+    }
+
   }
   va_end(ap);
 #endif /* SQLITE_OMIT_BUILTIN_TEST */
@@ -106882,8 +108644,14 @@ SQLITE_PRIVATE Fts3HashElem *sqlite3Fts3HashFindElem(const Fts3Hash *, const voi
 ** Macros indicating that conditional expressions are always true or
 ** false.
 */
+#ifdef SQLITE_COVERAGE_TEST
+# define ALWAYS(x) (1)
+# define NEVER(X)  (0)
+#else
 # define ALWAYS(x) (x)
 # define NEVER(X)  (x)
+#endif
+
 /*
 ** Internal types used by SQLite.
 */
@@ -106901,8 +108669,12 @@ typedef struct Fts3Table Fts3Table;
 typedef struct Fts3Cursor Fts3Cursor;
 typedef struct Fts3Expr Fts3Expr;
 typedef struct Fts3Phrase Fts3Phrase;
-typedef struct Fts3SegReader Fts3SegReader;
+typedef struct Fts3PhraseToken Fts3PhraseToken;
+
 typedef struct Fts3SegFilter Fts3SegFilter;
+typedef struct Fts3DeferredToken Fts3DeferredToken;
+typedef struct Fts3SegReader Fts3SegReader;
+typedef struct Fts3SegReaderArray Fts3SegReaderArray;
 
 /*
 ** A connection to a fulltext index is an instance of the following
@@ -106923,22 +108695,14 @@ struct Fts3Table {
   /* Precompiled statements used by the implementation. Each of these 
   ** statements is run and reset within a single virtual table API call. 
   */
-  sqlite3_stmt *aStmt[25];
-
-  /* Pointer to string containing the SQL:
-  **
-  ** "SELECT block FROM %_segments WHERE blockid BETWEEN ? AND ? 
-  **    ORDER BY blockid"
-  */
-  char *zSelectLeaves;
-  int nLeavesStmt;                /* Valid statements in aLeavesStmt */
-  int nLeavesTotal;               /* Total number of prepared leaves stmts */
-  int nLeavesAlloc;               /* Allocated size of aLeavesStmt */
-  sqlite3_stmt **aLeavesStmt;     /* Array of prepared zSelectLeaves stmts */
+  sqlite3_stmt *aStmt[24];
 
   int nNodeSize;                  /* Soft limit for node size */
-  u8 bHasContent;                 /* True if %_content table exists */
+  u8 bHasStat;                    /* True if %_stat table exists */
   u8 bHasDocsize;                 /* True if %_docsize table exists */
+  int nPgsz;                      /* Page size for host database */
+  char *zSegmentsTbl;             /* Name of %_segments table */
+  sqlite3_blob *pSegments;        /* Blob handle open on %_segments table */
 
   /* The following hash table is used to buffer pending index updates during
   ** transactions. Variable nPendingData estimates the memory size of the 
@@ -106965,14 +108729,25 @@ struct Fts3Cursor {
   u8 isRequireSeek;               /* True if must seek pStmt to %_content row */
   sqlite3_stmt *pStmt;            /* Prepared statement in use by the cursor */
   Fts3Expr *pExpr;                /* Parsed MATCH query string */
+  int nPhrase;                    /* Number of matchable phrases in query */
+  Fts3DeferredToken *pDeferred;   /* Deferred search tokens, if any */
   sqlite3_int64 iPrevId;          /* Previous id read from aDoclist */
   char *pNextId;                  /* Pointer into the body of aDoclist */
   char *aDoclist;                 /* List of docids for full-text queries */
   int nDoclist;                   /* Size of buffer at aDoclist */
+  int eEvalmode;                  /* An FTS3_EVAL_XX constant */
+  int nRowAvg;                    /* Average size of database rows, in pages */
+
   int isMatchinfoNeeded;          /* True when aMatchinfo[] needs filling in */
   u32 *aMatchinfo;                /* Information about most recent match */
+  int nMatchinfo;                 /* Number of elements in aMatchinfo[] */
+  char *zMatchinfo;               /* Matchinfo specification */
 };
 
+#define FTS3_EVAL_FILTER    0
+#define FTS3_EVAL_NEXT      1
+#define FTS3_EVAL_MATCHINFO 2
+
 /*
 ** The Fts3Cursor.eSearch member is always set to one of the following.
 ** Actualy, Fts3Cursor.eSearch can be greater than or equal to
@@ -106995,18 +108770,30 @@ struct Fts3Cursor {
 /*
 ** A "phrase" is a sequence of one or more tokens that must match in
 ** sequence.  A single token is the base case and the most common case.
-** For a sequence of tokens contained in "...", nToken will be the number
-** of tokens in the string.
-*/
+** For a sequence of tokens contained in double-quotes (i.e. "one two three")
+** nToken will be the number of tokens in the string.
+**
+** The nDocMatch and nMatch variables contain data that may be used by the
+** matchinfo() function. They are populated when the full-text index is 
+** queried for hits on the phrase. If one or more tokens in the phrase
+** are deferred, the nDocMatch and nMatch variables are populated based
+** on the assumption that the 
+*/
+struct Fts3PhraseToken {
+  char *z;                        /* Text of the token */
+  int n;                          /* Number of bytes in buffer z */
+  int isPrefix;                   /* True if token ends with a "*" character */
+  int bFulltext;                  /* True if full-text index was used */
+  Fts3SegReaderArray *pArray;     /* Segment-reader for this token */
+  Fts3DeferredToken *pDeferred;   /* Deferred token object for this token */
+};
+
 struct Fts3Phrase {
+  /* Variables populated by fts3_expr.c when parsing a MATCH expression */
   int nToken;                /* Number of tokens in the phrase */
   int iColumn;               /* Index of column this phrase must match */
   int isNot;                 /* Phrase prefixed by unary not (-) operator */
-  struct PhraseToken {
-    char *z;                 /* Text of the token */
-    int n;                   /* Number of bytes in buffer pointed to by z */
-    int isPrefix;            /* True if token ends in with a "*" character */
-  } aToken[1];               /* One entry for each token in the phrase */
+  Fts3PhraseToken aToken[1]; /* One entry for each token in the phrase */
 };
 
 /*
@@ -107056,28 +108843,34 @@ struct Fts3Expr {
 #define FTSQUERY_PHRASE 5
 
 
-/* fts3_init.c */
-SQLITE_PRIVATE int sqlite3Fts3DeleteVtab(int, sqlite3_vtab *);
-SQLITE_PRIVATE int sqlite3Fts3InitVtab(int, sqlite3*, void*, int, const char*const*, 
-                        sqlite3_vtab **, char **);
-
 /* fts3_write.c */
 SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(sqlite3_vtab*,int,sqlite3_value**,sqlite3_int64*);
 SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *);
 SQLITE_PRIVATE void sqlite3Fts3PendingTermsClear(Fts3Table *);
 SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *);
-SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(Fts3Table *,int, sqlite3_int64,
+SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(int, sqlite3_int64,
   sqlite3_int64, sqlite3_int64, const char *, int, Fts3SegReader**);
 SQLITE_PRIVATE int sqlite3Fts3SegReaderPending(Fts3Table*,const char*,int,int,Fts3SegReader**);
-SQLITE_PRIVATE void sqlite3Fts3SegReaderFree(Fts3Table *, Fts3SegReader *);
+SQLITE_PRIVATE void sqlite3Fts3SegReaderFree(Fts3SegReader *);
 SQLITE_PRIVATE int sqlite3Fts3SegReaderIterate(
   Fts3Table *, Fts3SegReader **, int, Fts3SegFilter *,
   int (*)(Fts3Table *, void *, char *, int, char *, int),  void *
 );
-SQLITE_PRIVATE int sqlite3Fts3ReadBlock(Fts3Table*, sqlite3_int64, char const**, int*);
+SQLITE_PRIVATE int sqlite3Fts3SegReaderCost(Fts3Cursor *, Fts3SegReader *, int *);
 SQLITE_PRIVATE int sqlite3Fts3AllSegdirs(Fts3Table*, sqlite3_stmt **);
-SQLITE_PRIVATE int sqlite3Fts3MatchinfoDocsizeLocal(Fts3Cursor*, u32*);
-SQLITE_PRIVATE int sqlite3Fts3MatchinfoDocsizeGlobal(Fts3Cursor*, u32*);
+SQLITE_PRIVATE int sqlite3Fts3ReadLock(Fts3Table *);
+SQLITE_PRIVATE int sqlite3Fts3ReadBlock(Fts3Table*, sqlite3_int64, char **, int*);
+
+SQLITE_PRIVATE int sqlite3Fts3SelectDoctotal(Fts3Table *, sqlite3_stmt **);
+SQLITE_PRIVATE int sqlite3Fts3SelectDocsize(Fts3Table *, sqlite3_int64, sqlite3_stmt **);
+
+SQLITE_PRIVATE void sqlite3Fts3FreeDeferredTokens(Fts3Cursor *);
+SQLITE_PRIVATE int sqlite3Fts3DeferToken(Fts3Cursor *, Fts3PhraseToken *, int);
+SQLITE_PRIVATE int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *);
+SQLITE_PRIVATE void sqlite3Fts3FreeDeferredDoclists(Fts3Cursor *);
+SQLITE_PRIVATE char *sqlite3Fts3DeferredDoclist(Fts3DeferredToken *, int *);
+
+SQLITE_PRIVATE void sqlite3Fts3SegmentsClose(Fts3Table *);
 
 /* Flags allowed as part of the 4th argument to SegmentReaderIterate() */
 #define FTS3_SEGMENT_REQUIRE_POS   0x00000001
@@ -107101,22 +108894,24 @@ SQLITE_PRIVATE int sqlite3Fts3VarintLen(sqlite3_uint64);
 SQLITE_PRIVATE void sqlite3Fts3Dequote(char *);
 
 SQLITE_PRIVATE char *sqlite3Fts3FindPositions(Fts3Expr *, sqlite3_int64, int);
-SQLITE_PRIVATE int sqlite3Fts3ExprLoadDoclist(Fts3Table *, Fts3Expr *);
+SQLITE_PRIVATE int sqlite3Fts3ExprLoadDoclist(Fts3Cursor *, Fts3Expr *);
+SQLITE_PRIVATE int sqlite3Fts3ExprLoadFtDoclist(Fts3Cursor *, Fts3Expr *, char **, int *);
 SQLITE_PRIVATE int sqlite3Fts3ExprNearTrim(Fts3Expr *, Fts3Expr *, int);
 
 /* fts3_tokenizer.c */
 SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *, int *);
 SQLITE_PRIVATE int sqlite3Fts3InitHashTable(sqlite3 *, Fts3Hash *, const char *);
-SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(Fts3Hash *pHash, 
-  const char *, sqlite3_tokenizer **, const char **, char **
+SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(Fts3Hash *pHash, const char *, 
+    sqlite3_tokenizer **, char **
 );
+SQLITE_PRIVATE int sqlite3Fts3IsIdChar(char);
 
 /* fts3_snippet.c */
 SQLITE_PRIVATE void sqlite3Fts3Offsets(sqlite3_context*, Fts3Cursor*);
 SQLITE_PRIVATE void sqlite3Fts3Snippet(sqlite3_context *, Fts3Cursor *, const char *,
   const char *, const char *, int, int
 );
-SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *);
+SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *, const char *);
 
 /* fts3_expr.c */
 SQLITE_PRIVATE int sqlite3Fts3ExprParse(sqlite3_tokenizer *, 
@@ -107265,16 +109060,13 @@ static int fts3DisconnectMethod(sqlite3_vtab *pVtab){
   int i;
 
   assert( p->nPendingData==0 );
+  assert( p->pSegments==0 );
 
   /* Free any prepared statements held */
   for(i=0; i<SizeofArray(p->aStmt); i++){
     sqlite3_finalize(p->aStmt[i]);
   }
-  for(i=0; i<p->nLeavesStmt; i++){
-    sqlite3_finalize(p->aLeavesStmt[i]);
-  }
-  sqlite3_free(p->zSelectLeaves);
-  sqlite3_free(p->aLeavesStmt);
+  sqlite3_free(p->zSegmentsTbl);
 
   /* Invoke the tokenizer destructor to free the tokenizer. */
   p->pTokenizer->pModule->xDestroy(p->pTokenizer);
@@ -107285,7 +109077,7 @@ static int fts3DisconnectMethod(sqlite3_vtab *pVtab){
 
 /*
 ** Construct one or more SQL statements from the format string given
-** and then evaluate those statements.  The success code is writting
+** and then evaluate those statements. The success code is written
 ** into *pRc.
 **
 ** If *pRc is initially non-zero then this routine is a no-op.
@@ -107337,33 +109129,38 @@ static int fts3DestroyMethod(sqlite3_vtab *pVtab){
 ** Invoke sqlite3_declare_vtab() to declare the schema for the FTS3 table
 ** passed as the first argument. This is done as part of the xConnect()
 ** and xCreate() methods.
+**
+** If *pRc is non-zero when this function is called, it is a no-op. 
+** Otherwise, if an error occurs, an SQLite error code is stored in *pRc
+** before returning.
 */
-static int fts3DeclareVtab(Fts3Table *p){
-  int i;                          /* Iterator variable */
-  int rc;                         /* Return code */
-  char *zSql;                     /* SQL statement passed to declare_vtab() */
-  char *zCols;                    /* List of user defined columns */
+static void fts3DeclareVtab(int *pRc, Fts3Table *p){
+  if( *pRc==SQLITE_OK ){
+    int i;                        /* Iterator variable */
+    int rc;                       /* Return code */
+    char *zSql;                   /* SQL statement passed to declare_vtab() */
+    char *zCols;                  /* List of user defined columns */
 
-  /* Create a list of user columns for the virtual table */
-  zCols = sqlite3_mprintf("%Q, ", p->azColumn[0]);
-  for(i=1; zCols && i<p->nColumn; i++){
-    zCols = sqlite3_mprintf("%z%Q, ", zCols, p->azColumn[i]);
-  }
+    /* Create a list of user columns for the virtual table */
+    zCols = sqlite3_mprintf("%Q, ", p->azColumn[0]);
+    for(i=1; zCols && i<p->nColumn; i++){
+      zCols = sqlite3_mprintf("%z%Q, ", zCols, p->azColumn[i]);
+    }
 
-  /* Create the whole "CREATE TABLE" statement to pass to SQLite */
-  zSql = sqlite3_mprintf(
-      "CREATE TABLE x(%s %Q HIDDEN, docid HIDDEN)", zCols, p->zName
-  );
+    /* Create the whole "CREATE TABLE" statement to pass to SQLite */
+    zSql = sqlite3_mprintf(
+        "CREATE TABLE x(%s %Q HIDDEN, docid HIDDEN)", zCols, p->zName
+    );
+    if( !zCols || !zSql ){
+      rc = SQLITE_NOMEM;
+    }else{
+      rc = sqlite3_declare_vtab(p->db, zSql);
+    }
 
-  if( !zCols || !zSql ){
-    rc = SQLITE_NOMEM;
-  }else{
-    rc = sqlite3_declare_vtab(p->db, zSql);
+    sqlite3_free(zSql);
+    sqlite3_free(zCols);
+    *pRc = rc;
   }
-
-  sqlite3_free(zSql);
-  sqlite3_free(zCols);
-  return rc;
 }
 
 /*
@@ -107382,21 +109179,19 @@ static int fts3CreateTables(Fts3Table *p){
   sqlite3 *db = p->db;            /* The database connection */
 
   /* Create a list of user columns for the content table */
-  if( p->bHasContent ){
-    zContentCols = sqlite3_mprintf("docid INTEGER PRIMARY KEY");
-    for(i=0; zContentCols && i<p->nColumn; i++){
-      char *z = p->azColumn[i];
-      zContentCols = sqlite3_mprintf("%z, 'c%d%q'", zContentCols, i, z);
-    }
-    if( zContentCols==0 ) rc = SQLITE_NOMEM;
-
-    /* Create the content table */
-    fts3DbExec(&rc, db, 
-       "CREATE TABLE %Q.'%q_content'(%s)",
-       p->zDb, p->zName, zContentCols
-    );
-    sqlite3_free(zContentCols);
+  zContentCols = sqlite3_mprintf("docid INTEGER PRIMARY KEY");
+  for(i=0; zContentCols && i<p->nColumn; i++){
+    char *z = p->azColumn[i];
+    zContentCols = sqlite3_mprintf("%z, 'c%d%q'", zContentCols, i, z);
   }
+  if( zContentCols==0 ) rc = SQLITE_NOMEM;
+
+  /* Create the content table */
+  fts3DbExec(&rc, db, 
+     "CREATE TABLE %Q.'%q_content'(%s)",
+     p->zDb, p->zName, zContentCols
+  );
+  sqlite3_free(zContentCols);
   /* Create other tables */
   fts3DbExec(&rc, db, 
       "CREATE TABLE %Q.'%q_segments'(blockid INTEGER PRIMARY KEY, block BLOB);",
@@ -107419,6 +109214,8 @@ static int fts3CreateTables(Fts3Table *p){
         "CREATE TABLE %Q.'%q_docsize'(docid INTEGER PRIMARY KEY, size BLOB);",
         p->zDb, p->zName
     );
+  }
+  if( p->bHasStat ){
     fts3DbExec(&rc, db, 
         "CREATE TABLE %Q.'%q_stat'(id INTEGER PRIMARY KEY, value BLOB);",
         p->zDb, p->zName
@@ -107428,39 +109225,63 @@ static int fts3CreateTables(Fts3Table *p){
 }
 
 /*
-** An sqlite3_exec() callback for fts3TableExists.
+** Store the current database page-size in bytes in p->nPgsz.
+**
+** If *pRc is non-zero when this function is called, it is a no-op. 
+** Otherwise, if an error occurs, an SQLite error code is stored in *pRc
+** before returning.
 */
-static int fts3TableExistsCallback(void *pArg, int n, char **pp1, char **pp2){
-  UNUSED_PARAMETER(n);
-  UNUSED_PARAMETER(pp1);
-  UNUSED_PARAMETER(pp2);
-  *(int*)pArg = 1;
-  return 1;
+static void fts3DatabasePageSize(int *pRc, Fts3Table *p){
+  if( *pRc==SQLITE_OK ){
+    int rc;                       /* Return code */
+    char *zSql;                   /* SQL text "PRAGMA %Q.page_size" */
+    sqlite3_stmt *pStmt;          /* Compiled "PRAGMA %Q.page_size" statement */
+  
+    zSql = sqlite3_mprintf("PRAGMA %Q.page_size", p->zDb);
+    if( !zSql ){
+      rc = SQLITE_NOMEM;
+    }else{
+      rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);
+      if( rc==SQLITE_OK ){
+        sqlite3_step(pStmt);
+        p->nPgsz = sqlite3_column_int(pStmt, 0);
+        rc = sqlite3_finalize(pStmt);
+      }
+    }
+    assert( p->nPgsz>0 || rc!=SQLITE_OK );
+    sqlite3_free(zSql);
+    *pRc = rc;
+  }
 }
 
 /*
-** Determine if a table currently exists in the database.
+** "Special" FTS4 arguments are column specifications of the following form:
+**
+**   <key> = <value>
+**
+** There may not be whitespace surrounding the "=" character. The <value> 
+** term may be quoted, but the <key> may not.
 */
-static void fts3TableExists(
-  int *pRc,             /* Success code */
-  sqlite3 *db,          /* The database connection to test */
-  const char *zDb,      /* ATTACHed database within the connection */
-  const char *zName,    /* Name of the FTS3 table */
-  const char *zSuffix,  /* Shadow table extension */
-  u8 *pResult           /* Write results here */
+static int fts3IsSpecialColumn(
+  const char *z, 
+  int *pnKey,
+  char **pzValue
 ){
-  int rc = SQLITE_OK;
-  int res = 0;
-  char *zSql;
-  if( *pRc ) return;
-  zSql = sqlite3_mprintf(
-    "SELECT 1 FROM %Q.sqlite_master WHERE name='%q%s'",
-    zDb, zName, zSuffix
-  );    
-  rc = sqlite3_exec(db, zSql, fts3TableExistsCallback, &res, 0);
-  sqlite3_free(zSql);
-  *pResult = (u8)(res & 0xff);
-  if( rc!=SQLITE_ABORT ) *pRc = rc;
+  char *zValue;
+  const char *zCsr = z;
+
+  while( *zCsr!='=' ){
+    if( *zCsr=='\0' ) return 0;
+    zCsr++;
+  }
+
+  *pnKey = (int)(zCsr-z);
+  zValue = sqlite3_mprintf("%s", &zCsr[1]);
+  if( zValue ){
+    sqlite3Fts3Dequote(zValue);
+  }
+  *pzValue = zValue;
+  return 1;
 }
 
 /*
@@ -107484,8 +109305,8 @@ static int fts3InitVtab(
   char **pzErr                    /* Write any error message here */
 ){
   Fts3Hash *pHash = (Fts3Hash *)pAux;
-  Fts3Table *p;                   /* Pointer to allocated vtab */
-  int rc;                         /* Return code */
+  Fts3Table *p = 0;               /* Pointer to allocated vtab */
+  int rc = SQLITE_OK;             /* Return code */
   int i;                          /* Iterator variable */
   int nByte;                      /* Size of allocation used for *p */
   int iCol;                       /* Column index */
@@ -107494,35 +109315,90 @@ static int fts3InitVtab(
   char *zCsr;                     /* Space for holding column names */
   int nDb;                        /* Bytes required to hold database name */
   int nName;                      /* Bytes required to hold table name */
-
-  const char *zTokenizer = 0;               /* Name of tokenizer to use */
+  int isFts4 = (argv[0][3]=='4'); /* True for FTS4, false for FTS3 */
+  int bNoDocsize = 0;             /* True to omit %_docsize table */
+  const char **aCol;              /* Array of column names */
   sqlite3_tokenizer *pTokenizer = 0;        /* Tokenizer for this table */
 
+  assert( strlen(argv[0])==4 );
+  assert( (sqlite3_strnicmp(argv[0], "fts4", 4)==0 && isFts4)
+       || (sqlite3_strnicmp(argv[0], "fts3", 4)==0 && !isFts4)
+  );
+
   nDb = (int)strlen(argv[1]) + 1;
   nName = (int)strlen(argv[2]) + 1;
-  for(i=3; i<argc; i++){
+
+  aCol = (const char **)sqlite3_malloc(sizeof(const char *) * (argc-2) );
+  if( !aCol ) return SQLITE_NOMEM;
+  memset((void *)aCol, 0, sizeof(const char *) * (argc-2));
+
+  /* Loop through all of the arguments passed by the user to the FTS3/4
+  ** module (i.e. all the column names and special arguments). This loop
+  ** does the following:
+  **
+  **   + Figures out the number of columns the FTSX table will have, and
+  **     the number of bytes of space that must be allocated to store copies
+  **     of the column names.
+  **
+  **   + If there is a tokenizer specification included in the arguments,
+  **     initializes the tokenizer pTokenizer.
+  */
+  for(i=3; rc==SQLITE_OK && i<argc; i++){
     char const *z = argv[i];
-    rc = sqlite3Fts3InitTokenizer(pHash, z, &pTokenizer, &zTokenizer, pzErr);
-    if( rc!=SQLITE_OK ){
-      return rc;
+    int nKey;
+    char *zVal;
+
+    /* Check if this is a tokenizer specification */
+    if( !pTokenizer 
+     && strlen(z)>8
+     && 0==sqlite3_strnicmp(z, "tokenize", 8) 
+     && 0==sqlite3Fts3IsIdChar(z[8])
+    ){
+      rc = sqlite3Fts3InitTokenizer(pHash, &z[9], &pTokenizer, pzErr);
     }
-    if( z!=zTokenizer ){
-      nString += (int)(strlen(z) + 1);
+
+    /* Check if it is an FTS4 special argument. */
+    else if( isFts4 && fts3IsSpecialColumn(z, &nKey, &zVal) ){
+      if( !zVal ){
+        rc = SQLITE_NOMEM;
+        goto fts3_init_out;
+      }
+      if( nKey==9 && 0==sqlite3_strnicmp(z, "matchinfo", 9) ){
+        if( strlen(zVal)==4 && 0==sqlite3_strnicmp(zVal, "fts3", 4) ){
+          bNoDocsize = 1;
+        }else{
+          *pzErr = sqlite3_mprintf("unrecognized matchinfo: %s", zVal);
+          rc = SQLITE_ERROR;
+        }
+      }else{
+        *pzErr = sqlite3_mprintf("unrecognized parameter: %s", z);
+        rc = SQLITE_ERROR;
+      }
+      sqlite3_free(zVal);
     }
-  }
-  nCol = argc - 3 - (zTokenizer!=0);
-  if( zTokenizer==0 ){
-    rc = sqlite3Fts3InitTokenizer(pHash, 0, &pTokenizer, 0, pzErr);
-    if( rc!=SQLITE_OK ){
-      return rc;
+
+    /* Otherwise, the argument is a column name. */
+    else {
+      nString += (int)(strlen(z) + 1);
+      aCol[nCol++] = z;
     }
-    assert( pTokenizer );
   }
+  if( rc!=SQLITE_OK ) goto fts3_init_out;
 
   if( nCol==0 ){
+    assert( nString==0 );
+    aCol[0] = "content";
+    nString = 8;
     nCol = 1;
   }
 
+  if( pTokenizer==0 ){
+    rc = sqlite3Fts3InitTokenizer(pHash, "simple", &pTokenizer, pzErr);
+    if( rc!=SQLITE_OK ) goto fts3_init_out;
+  }
+  assert( pTokenizer );
+
+
   /* Allocate and populate the Fts3Table structure. */
   nByte = sizeof(Fts3Table) +              /* Fts3Table */
           nCol * sizeof(char *) +              /* azColumn */
@@ -107535,7 +109411,6 @@ static int fts3InitVtab(
     goto fts3_init_out;
   }
   memset(p, 0, nByte);
-
   p->db = db;
   p->nColumn = nCol;
   p->nPendingData = 0;
@@ -107543,11 +109418,12 @@ static int fts3InitVtab(
   p->pTokenizer = pTokenizer;
   p->nNodeSize = 1000;
   p->nMaxPendingData = FTS3_MAX_PENDING_DATA;
-  zCsr = (char *)&p->azColumn[nCol];
-
+  p->bHasDocsize = (isFts4 && bNoDocsize==0);
+  p->bHasStat = isFts4;
   fts3HashInit(&p->pendingTerms, FTS3_HASH_STRING, 1);
 
   /* Fill in the zName and zDb fields of the vtab structure. */
+  zCsr = (char *)&p->azColumn[nCol];
   p->zName = zCsr;
   memcpy(zCsr, argv[2], nName);
   zCsr += nName;
@@ -107556,52 +109432,45 @@ static int fts3InitVtab(
   zCsr += nDb;
 
   /* Fill in the azColumn array */
-  iCol = 0;
-  for(i=3; i<argc; i++){
-    if( argv[i]!=zTokenizer ){
-      char *z; 
-      int n;
-      z = (char *)sqlite3Fts3NextToken(argv[i], &n);
-      memcpy(zCsr, z, n);
-      zCsr[n] = '\0';
-      sqlite3Fts3Dequote(zCsr);
-      p->azColumn[iCol++] = zCsr;
-      zCsr += n+1;
-      assert( zCsr <= &((char *)p)[nByte] );
-    }
-  }
-  if( iCol==0 ){
-    assert( nCol==1 );
-    p->azColumn[0] = "content";
+  for(iCol=0; iCol<nCol; iCol++){
+    char *z; 
+    int n;
+    z = (char *)sqlite3Fts3NextToken(aCol[iCol], &n);
+    memcpy(zCsr, z, n);
+    zCsr[n] = '\0';
+    sqlite3Fts3Dequote(zCsr);
+    p->azColumn[iCol] = zCsr;
+    zCsr += n+1;
+    assert( zCsr <= &((char *)p)[nByte] );
   }
 
   /* If this is an xCreate call, create the underlying tables in the 
   ** database. TODO: For xConnect(), it could verify that said tables exist.
   */
   if( isCreate ){
-    p->bHasContent = 1;
-    p->bHasDocsize = argv[0][3]=='4';
     rc = fts3CreateTables(p);
-  }else{
-    rc = SQLITE_OK;
-    fts3TableExists(&rc, db, argv[1], argv[2], "_content", &p->bHasContent);
-    fts3TableExists(&rc, db, argv[1], argv[2], "_docsize", &p->bHasDocsize);
   }
-  if( rc!=SQLITE_OK ) goto fts3_init_out;
 
-  rc = fts3DeclareVtab(p);
-  if( rc!=SQLITE_OK ) goto fts3_init_out;
+  /* Figure out the page-size for the database. This is required in order to
+  ** estimate the cost of loading large doclists from the database (see 
+  ** function sqlite3Fts3SegReaderCost() for details).
+  */
+  fts3DatabasePageSize(&rc, p);
 
-  *ppVTab = &p->base;
+  /* Declare the table schema to SQLite. */
+  fts3DeclareVtab(&rc, p);
 
 fts3_init_out:
-  assert( p || (pTokenizer && rc!=SQLITE_OK) );
+
+  sqlite3_free((void *)aCol);
   if( rc!=SQLITE_OK ){
     if( p ){
       fts3DisconnectMethod((sqlite3_vtab *)p);
-    }else{
+    }else if( pTokenizer ){
       pTokenizer->pModule->xDestroy(pTokenizer);
     }
+  }else{
+    *ppVTab = &p->base;
   }
   return rc;
 }
@@ -107713,10 +109582,12 @@ static int fts3OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
 ** Close the cursor.  For additional information see the documentation
 ** on the xClose method of the virtual table interface.
 */
-static int fulltextClose(sqlite3_vtab_cursor *pCursor){
+static int fts3CloseMethod(sqlite3_vtab_cursor *pCursor){
   Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
+  assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
   sqlite3_finalize(pCsr->pStmt);
   sqlite3Fts3ExprFree(pCsr->pExpr);
+  sqlite3Fts3FreeDeferredTokens(pCsr);
   sqlite3_free(pCsr->aDoclist);
   sqlite3_free(pCsr->aMatchinfo);
   sqlite3_free(pCsr);
@@ -107755,50 +109626,137 @@ static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){
 }
 
 /*
-** Advance the cursor to the next row in the %_content table that
-** matches the search criteria.  For a MATCH search, this will be
-** the next row that matches.  For a full-table scan, this will be
-** simply the next row in the %_content table.  For a docid lookup,
-** this routine simply sets the EOF flag.
+** This function is used to process a single interior node when searching
+** a b-tree for a term or term prefix. The node data is passed to this 
+** function via the zNode/nNode parameters. The term to search for is
+** passed in zTerm/nTerm.
 **
-** Return SQLITE_OK if nothing goes wrong.  SQLITE_OK is returned
-** even if we reach end-of-file.  The fts3EofMethod() will be called
-** subsequently to determine whether or not an EOF was hit.
+** If piFirst is not NULL, then this function sets *piFirst to the blockid
+** of the child node that heads the sub-tree that may contain the term.
+**
+** If piLast is not NULL, then *piLast is set to the right-most child node
+** that heads a sub-tree that may contain a term for which zTerm/nTerm is
+** a prefix.
+**
+** If an OOM error occurs, SQLITE_NOMEM is returned. Otherwise, SQLITE_OK.
 */
-static int fts3NextMethod(sqlite3_vtab_cursor *pCursor){
+static int fts3ScanInteriorNode(
+  const char *zTerm,              /* Term to select leaves for */
+  int nTerm,                      /* Size of term zTerm in bytes */
+  const char *zNode,              /* Buffer containing segment interior node */
+  int nNode,                      /* Size of buffer at zNode */
+  sqlite3_int64 *piFirst,         /* OUT: Selected child node */
+  sqlite3_int64 *piLast           /* OUT: Selected child node */
+){
   int rc = SQLITE_OK;             /* Return code */
-  Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
+  const char *zCsr = zNode;       /* Cursor to iterate through node */
+  const char *zEnd = &zCsr[nNode];/* End of interior node buffer */
+  char *zBuffer = 0;              /* Buffer to load terms into */
+  int nAlloc = 0;                 /* Size of allocated buffer */
+  int isFirstTerm = 1;            /* True when processing first term on page */
+  sqlite3_int64 iChild;           /* Block id of child node to descend to */
 
-  if( pCsr->aDoclist==0 ){
-    if( SQLITE_ROW!=sqlite3_step(pCsr->pStmt) ){
-      pCsr->isEof = 1;
-      rc = sqlite3_reset(pCsr->pStmt);
-    }
-  }else if( pCsr->pNextId>=&pCsr->aDoclist[pCsr->nDoclist] ){
-    pCsr->isEof = 1;
-  }else{
-    sqlite3_reset(pCsr->pStmt);
-    fts3GetDeltaVarint(&pCsr->pNextId, &pCsr->iPrevId);
-    pCsr->isRequireSeek = 1;
-    pCsr->isMatchinfoNeeded = 1;
+  /* Skip over the 'height' varint that occurs at the start of every 
+  ** interior node. Then load the blockid of the left-child of the b-tree
+  ** node into variable iChild.  
+  **
+  ** Even if the data structure on disk is corrupted, this (reading two
+  ** varints from the buffer) does not risk an overread. If zNode is a
+  ** root node, then the buffer comes from a SELECT statement. SQLite does
+  ** not make this guarantee explicitly, but in practice there are always
+  ** either more than 20 bytes of allocated space following the nNode bytes of
+  ** contents, or two zero bytes. Or, if the node is read from the %_segments
+  ** table, then there are always 20 bytes of zeroed padding following the
+  ** nNode bytes of content (see sqlite3Fts3ReadBlock() for details).
+  */
+  zCsr += sqlite3Fts3GetVarint(zCsr, &iChild);
+  zCsr += sqlite3Fts3GetVarint(zCsr, &iChild);
+  if( zCsr>zEnd ){
+    return SQLITE_CORRUPT;
   }
+  
+  while( zCsr<zEnd && (piFirst || piLast) ){
+    int cmp;                      /* memcmp() result */
+    int nSuffix;                  /* Size of term suffix */
+    int nPrefix = 0;              /* Size of term prefix */
+    int nBuffer;                  /* Total term size */
+  
+    /* Load the next term on the node into zBuffer. Use realloc() to expand
+    ** the size of zBuffer if required.  */
+    if( !isFirstTerm ){
+      zCsr += sqlite3Fts3GetVarint32(zCsr, &nPrefix);
+    }
+    isFirstTerm = 0;
+    zCsr += sqlite3Fts3GetVarint32(zCsr, &nSuffix);
+    
+    if( nPrefix<0 || nSuffix<0 || &zCsr[nSuffix]>zEnd ){
+      rc = SQLITE_CORRUPT;
+      goto finish_scan;
+    }
+    if( nPrefix+nSuffix>nAlloc ){
+      char *zNew;
+      nAlloc = (nPrefix+nSuffix) * 2;
+      zNew = (char *)sqlite3_realloc(zBuffer, nAlloc);
+      if( !zNew ){
+        rc = SQLITE_NOMEM;
+        goto finish_scan;
+      }
+      zBuffer = zNew;
+    }
+    memcpy(&zBuffer[nPrefix], zCsr, nSuffix);
+    nBuffer = nPrefix + nSuffix;
+    zCsr += nSuffix;
+
+    /* Compare the term we are searching for with the term just loaded from
+    ** the interior node. If the specified term is greater than or equal
+    ** to the term from the interior node, then all terms on the sub-tree 
+    ** headed by node iChild are smaller than zTerm. No need to search 
+    ** iChild.
+    **
+    ** If the interior node term is larger than the specified term, then
+    ** the tree headed by iChild may contain the specified term.
+    */
+    cmp = memcmp(zTerm, zBuffer, (nBuffer>nTerm ? nTerm : nBuffer));
+    if( piFirst && (cmp<0 || (cmp==0 && nBuffer>nTerm)) ){
+      *piFirst = iChild;
+      piFirst = 0;
+    }
+
+    if( piLast && cmp<0 ){
+      *piLast = iChild;
+      piLast = 0;
+    }
+
+    iChild++;
+  };
+
+  if( piFirst ) *piFirst = iChild;
+  if( piLast ) *piLast = iChild;
+
+ finish_scan:
+  sqlite3_free(zBuffer);
   return rc;
 }
 
 
 /*
-** The buffer pointed to by argument zNode (size nNode bytes) contains the
-** root node of a b-tree segment. The segment is guaranteed to be at least
-** one level high (i.e. the root node is not also a leaf). If successful,
-** this function locates the leaf node of the segment that may contain the 
-** term specified by arguments zTerm and nTerm and writes its block number 
-** to *piLeaf.
+** The buffer pointed to by argument zNode (size nNode bytes) contains an
+** interior node of a b-tree segment. The zTerm buffer (size nTerm bytes)
+** contains a term. This function searches the sub-tree headed by the zNode
+** node for the range of leaf nodes that may contain the specified term
+** or terms for which the specified term is a prefix.
 **
-** It is possible that the returned leaf node does not contain the specified
-** term. However, if the segment does contain said term, it is stored on
-** the identified leaf node. Because this function only inspects interior
-** segment nodes (and never loads leaf nodes into memory), it is not possible
-** to be sure.
+** If piLeaf is not NULL, then *piLeaf is set to the blockid of the 
+** left-most leaf node in the tree that may contain the specified term.
+** If piLeaf2 is not NULL, then *piLeaf2 is set to the blockid of the
+** right-most leaf node that may contain a term for which the specified
+** term is a prefix.
+**
+** It is possible that the range of returned leaf nodes does not contain 
+** the specified term or any terms for which it is a prefix. However, if the 
+** segment does contain any such terms, they are stored within the identified
+** range. Because this function only inspects interior segment nodes (and
+** never loads leaf nodes into memory), it is not possible to be sure.
 **
 ** If an error occurs, an error code other than SQLITE_OK is returned.
 */ 
@@ -107808,77 +109766,41 @@ static int fts3SelectLeaf(
   int nTerm,                      /* Size of term zTerm in bytes */
   const char *zNode,              /* Buffer containing segment interior node */
   int nNode,                      /* Size of buffer at zNode */
-  sqlite3_int64 *piLeaf           /* Selected leaf node */
+  sqlite3_int64 *piLeaf,          /* Selected leaf node */
+  sqlite3_int64 *piLeaf2          /* Selected leaf node */
 ){
-  int rc = SQLITE_OK;             /* Return code */
-  const char *zCsr = zNode;       /* Cursor to iterate through node */
-  const char *zEnd = &zCsr[nNode];/* End of interior node buffer */
-  char *zBuffer = 0;              /* Buffer to load terms into */
-  int nAlloc = 0;                 /* Size of allocated buffer */
+  int rc;                         /* Return code */
+  int iHeight;                    /* Height of this node in tree */
 
-  while( 1 ){
-    int isFirstTerm = 1;          /* True when processing first term on page */
-    int iHeight;                  /* Height of this node in tree */
-    sqlite3_int64 iChild;         /* Block id of child node to descend to */
-    int nBlock;                   /* Size of child node in bytes */
+  assert( piLeaf || piLeaf2 );
 
-    zCsr += sqlite3Fts3GetVarint32(zCsr, &iHeight);
-    zCsr += sqlite3Fts3GetVarint(zCsr, &iChild);
-  
-    while( zCsr<zEnd ){
-      int cmp;                    /* memcmp() result */
-      int nSuffix;                /* Size of term suffix */
-      int nPrefix = 0;            /* Size of term prefix */
-      int nBuffer;                /* Total term size */
-  
-      /* Load the next term on the node into zBuffer */
-      if( !isFirstTerm ){
-        zCsr += sqlite3Fts3GetVarint32(zCsr, &nPrefix);
-      }
-      isFirstTerm = 0;
-      zCsr += sqlite3Fts3GetVarint32(zCsr, &nSuffix);
-      if( nPrefix+nSuffix>nAlloc ){
-        char *zNew;
-        nAlloc = (nPrefix+nSuffix) * 2;
-        zNew = (char *)sqlite3_realloc(zBuffer, nAlloc);
-        if( !zNew ){
-          sqlite3_free(zBuffer);
-          return SQLITE_NOMEM;
-        }
-        zBuffer = zNew;
-      }
-      memcpy(&zBuffer[nPrefix], zCsr, nSuffix);
-      nBuffer = nPrefix + nSuffix;
-      zCsr += nSuffix;
-  
-      /* Compare the term we are searching for with the term just loaded from
-      ** the interior node. If the specified term is greater than or equal
-      ** to the term from the interior node, then all terms on the sub-tree 
-      ** headed by node iChild are smaller than zTerm. No need to search 
-      ** iChild.
-      **
-      ** If the interior node term is larger than the specified term, then
-      ** the tree headed by iChild may contain the specified term.
-      */
-      cmp = memcmp(zTerm, zBuffer, (nBuffer>nTerm ? nTerm : nBuffer));
-      if( cmp<0 || (cmp==0 && nBuffer>nTerm) ) break;
-      iChild++;
-    };
+  sqlite3Fts3GetVarint32(zNode, &iHeight);
+  rc = fts3ScanInteriorNode(zTerm, nTerm, zNode, nNode, piLeaf, piLeaf2);
+  assert( !piLeaf2 || !piLeaf || rc!=SQLITE_OK || (*piLeaf<=*piLeaf2) );
 
-    /* If (iHeight==1), the children of this interior node are leaves. The
-    ** specified term may be present on leaf node iChild.
-    */
-    if( iHeight==1 ){
-      *piLeaf = iChild;
-      break;
+  if( rc==SQLITE_OK && iHeight>1 ){
+    char *zBlob = 0;              /* Blob read from %_segments table */
+    int nBlob;                    /* Size of zBlob in bytes */
+
+    if( piLeaf && piLeaf2 && (*piLeaf!=*piLeaf2) ){
+      rc = sqlite3Fts3ReadBlock(p, *piLeaf, &zBlob, &nBlob);
+      if( rc==SQLITE_OK ){
+        rc = fts3SelectLeaf(p, zTerm, nTerm, zBlob, nBlob, piLeaf, 0);
+      }
+      sqlite3_free(zBlob);
+      piLeaf = 0;
+      zBlob = 0;
     }
 
-    /* Descend to interior node iChild. */
-    rc = sqlite3Fts3ReadBlock(p, iChild, &zCsr, &nBlock);
-    if( rc!=SQLITE_OK ) break;
-    zEnd = &zCsr[nBlock];
+    if( rc==SQLITE_OK ){
+      rc = sqlite3Fts3ReadBlock(p, piLeaf ? *piLeaf : *piLeaf2, &zBlob, &nBlob);
+    }
+    if( rc==SQLITE_OK ){
+      rc = fts3SelectLeaf(p, zTerm, nTerm, zBlob, nBlob, piLeaf, piLeaf2);
+    }
+    sqlite3_free(zBlob);
   }
-  sqlite3_free(zBuffer);
+
   return rc;
 }
 
@@ -108110,20 +110032,44 @@ static void fts3PoslistMerge(
 
 /*
 ** nToken==1 searches for adjacent positions.
+**
+** This function is used to merge two position lists into one. When it is
+** called, *pp1 and *pp2 must both point to position lists. A position-list is
+** the part of a doclist that follows each document id. For example, if a row
+** contains:
+**
+**     'a b c'|'x y z'|'a b b a'
+**
+** Then the position list for this row for token 'b' would consist of:
+**
+**     0x02 0x01 0x02 0x03 0x03 0x00
+**
+** When this function returns, both *pp1 and *pp2 are left pointing to the
+** byte following the 0x00 terminator of their respective position lists.
+**
+** If isSaveLeft is 0, an entry is added to the output position list for 
+** each position in *pp2 for which there exists one or more positions in
+** *pp1 so that (pos(*pp2)>pos(*pp1) && pos(*pp2)-pos(*pp1)<=nToken). i.e.
+** when the *pp1 token appears before the *pp2 token, but not more than nToken
+** slots before it.
 */
 static int fts3PoslistPhraseMerge(
-  char **pp,                      /* Output buffer */
+  char **pp,                      /* IN/OUT: Preallocated output buffer */
   int nToken,                     /* Maximum difference in token positions */
   int isSaveLeft,                 /* Save the left position */
-  char **pp1,                     /* Left input list */
-  char **pp2                      /* Right input list */
+  int isExact,                    /* If *pp1 is exactly nTokens before *pp2 */
+  char **pp1,                     /* IN/OUT: Left input list */
+  char **pp2                      /* IN/OUT: Right input list */
 ){
   char *p = (pp ? *pp : 0);
   char *p1 = *pp1;
   char *p2 = *pp2;
-
   int iCol1 = 0;
   int iCol2 = 0;
+
+  /* Never set both isSaveLeft and isExact for the same invocation. */
+  assert( isSaveLeft==0 || isExact==0 );
+
   assert( *p1!=0 && *p2!=0 );
   if( *p1==POS_COLUMN ){ 
     p1++;
@@ -108152,7 +110098,9 @@ static int fts3PoslistPhraseMerge(
       fts3GetDeltaVarint(&p2, &iPos2); iPos2 -= 2;
 
       while( 1 ){
-        if( iPos2>iPos1 && iPos2<=iPos1+nToken ){
+        if( iPos2==iPos1+nToken 
+         || (isExact==0 && iPos2>iPos1 && iPos2<=iPos1+nToken) 
+        ){
           sqlite3_int64 iSave;
           if( !pp ){
             fts3PoslistCopy(0, &p2);
@@ -108235,21 +110183,21 @@ static int fts3PoslistNearMerge(
   char *p2 = *pp2;
 
   if( !pp ){
-    if( fts3PoslistPhraseMerge(0, nRight, 0, pp1, pp2) ) return 1;
+    if( fts3PoslistPhraseMerge(0, nRight, 0, 0, pp1, pp2) ) return 1;
     *pp1 = p1;
     *pp2 = p2;
-    return fts3PoslistPhraseMerge(0, nLeft, 0, pp2, pp1);
+    return fts3PoslistPhraseMerge(0, nLeft, 0, 0, pp2, pp1);
   }else{
     char *pTmp1 = aTmp;
     char *pTmp2;
     char *aTmp2;
     int res = 1;
 
-    fts3PoslistPhraseMerge(&pTmp1, nRight, 0, pp1, pp2);
+    fts3PoslistPhraseMerge(&pTmp1, nRight, 0, 0, pp1, pp2);
     aTmp2 = pTmp2 = pTmp1;
     *pp1 = p1;
     *pp2 = p2;
-    fts3PoslistPhraseMerge(&pTmp2, nLeft, 1, pp2, pp1);
+    fts3PoslistPhraseMerge(&pTmp2, nLeft, 1, 0, pp2, pp1);
     if( pTmp1!=aTmp && pTmp2!=aTmp2 ){
       fts3PoslistMerge(pp, &aTmp, &aTmp2);
     }else if( pTmp1!=aTmp ){
@@ -108295,7 +110243,8 @@ static int fts3DoclistMerge(
   char *a1,                       /* Buffer containing first doclist */
   int n1,                         /* Size of buffer a1 */
   char *a2,                       /* Buffer containing second doclist */
-  int n2                          /* Size of buffer a2 */
+  int n2,                         /* Size of buffer a2 */
+  int *pnDoc                      /* OUT: Number of docids in output */
 ){
   sqlite3_int64 i1 = 0;
   sqlite3_int64 i2 = 0;
@@ -108306,6 +110255,7 @@ static int fts3DoclistMerge(
   char *p2 = a2;
   char *pEnd1 = &a1[n1];
   char *pEnd2 = &a2[n2];
+  int nDoc = 0;
 
   assert( mergetype==MERGE_OR     || mergetype==MERGE_POS_OR 
        || mergetype==MERGE_AND    || mergetype==MERGE_NOT
@@ -108349,6 +110299,7 @@ static int fts3DoclistMerge(
           fts3PutDeltaVarint(&p, &iPrev, i1);
           fts3GetDeltaVarint2(&p1, pEnd1, &i1);
           fts3GetDeltaVarint2(&p2, pEnd2, &i2);
+          nDoc++;
         }else if( i1<i2 ){
           fts3GetDeltaVarint2(&p1, pEnd1, &i1);
         }else{
@@ -108379,9 +110330,11 @@ static int fts3DoclistMerge(
           char *pSave = p;
           sqlite3_int64 iPrevSave = iPrev;
           fts3PutDeltaVarint(&p, &iPrev, i1);
-          if( 0==fts3PoslistPhraseMerge(ppPos, 1, 0, &p1, &p2) ){
+          if( 0==fts3PoslistPhraseMerge(ppPos, nParam1, 0, 1, &p1, &p2) ){
             p = pSave;
             iPrev = iPrevSave;
+          }else{
+            nDoc++;
           }
           fts3GetDeltaVarint2(&p1, pEnd1, &i1);
           fts3GetDeltaVarint2(&p2, pEnd2, &i2);
@@ -108434,6 +110387,7 @@ static int fts3DoclistMerge(
     }
   }
 
+  if( pnDoc ) *pnDoc = nDoc;
   *pnBuffer = (int)(p-aBuffer);
   return SQLITE_OK;
 }
@@ -108472,7 +110426,7 @@ static int fts3TermSelectMerge(TermSelect *pTS){
       if( !aOut ){
         aOut = pTS->aaOutput[i];
         nOut = pTS->anOutput[i];
-        pTS->aaOutput[0] = 0;
+        pTS->aaOutput[i] = 0;
       }else{
         int nNew = nOut + pTS->anOutput[i];
         char *aNew = sqlite3_malloc(nNew);
@@ -108481,7 +110435,7 @@ static int fts3TermSelectMerge(TermSelect *pTS){
           return SQLITE_NOMEM;
         }
         fts3DoclistMerge(mergetype, 0, 0,
-            aNew, &nNew, pTS->aaOutput[i], pTS->anOutput[i], aOut, nOut
+            aNew, &nNew, pTS->aaOutput[i], pTS->anOutput[i], aOut, nOut, 0
         );
         sqlite3_free(pTS->aaOutput[i]);
         sqlite3_free(aOut);
@@ -108552,8 +110506,8 @@ static int fts3TermSelectCb(
         }
         return SQLITE_NOMEM;
       }
-      fts3DoclistMerge(mergetype, 0, 0,
-          aNew, &nNew, pTS->aaOutput[iOut], pTS->anOutput[iOut], aMerge, nMerge
+      fts3DoclistMerge(mergetype, 0, 0, aNew, &nNew, 
+          pTS->aaOutput[iOut], pTS->anOutput[iOut], aMerge, nMerge, 0
       );
 
       if( iOut>0 ) sqlite3_free(aMerge);
@@ -108571,43 +110525,106 @@ static int fts3TermSelectCb(
   return SQLITE_OK;
 }
 
+static int fts3DeferredTermSelect(
+  Fts3DeferredToken *pToken,      /* Phrase token */
+  int isTermPos,                  /* True to include positions */
+  int *pnOut,                     /* OUT: Size of list */
+  char **ppOut                    /* OUT: Body of list */
+){
+  char *aSource;
+  int nSource;
+
+  aSource = sqlite3Fts3DeferredDoclist(pToken, &nSource);
+  if( !aSource ){
+    *pnOut = 0;
+    *ppOut = 0;
+  }else if( isTermPos ){
+    *ppOut = sqlite3_malloc(nSource);
+    if( !*ppOut ) return SQLITE_NOMEM;
+    memcpy(*ppOut, aSource, nSource);
+    *pnOut = nSource;
+  }else{
+    sqlite3_int64 docid;
+    *pnOut = sqlite3Fts3GetVarint(aSource, &docid);
+    *ppOut = sqlite3_malloc(*pnOut);
+    if( !*ppOut ) return SQLITE_NOMEM;
+    sqlite3Fts3PutVarint(*ppOut, docid);
+  }
+
+  return SQLITE_OK;
+}
+
 /*
-** This function retreives the doclist for the specified term (or term
-** prefix) from the database. 
-**
-** The returned doclist may be in one of two formats, depending on the 
-** value of parameter isReqPos. If isReqPos is zero, then the doclist is
-** a sorted list of delta-compressed docids (a bare doclist). If isReqPos
-** is non-zero, then the returned list is in the same format as is stored 
-** in the database without the found length specifier at the start of on-disk
-** doclists.
+** An Fts3SegReaderArray is used to store an array of Fts3SegReader objects.
+** Elements are added to the array using fts3SegReaderArrayAdd(). 
 */
-static int fts3TermSelect(
-  Fts3Table *p,                   /* Virtual table handle */
-  int iColumn,                    /* Column to query (or -ve for all columns) */
+struct Fts3SegReaderArray {
+  int nSegment;                   /* Number of valid entries in apSegment[] */
+  int nAlloc;                     /* Allocated size of apSegment[] */
+  int nCost;                      /* The cost of executing SegReaderIterate() */
+  Fts3SegReader *apSegment[1];    /* Array of seg-reader objects */
+};
+
+
+/*
+** Free an Fts3SegReaderArray object. Also free all seg-readers in the
+** array (using sqlite3Fts3SegReaderFree()).
+*/
+static void fts3SegReaderArrayFree(Fts3SegReaderArray *pArray){
+  if( pArray ){
+    int i;
+    for(i=0; i<pArray->nSegment; i++){
+      sqlite3Fts3SegReaderFree(pArray->apSegment[i]);
+    }
+    sqlite3_free(pArray);
+  }
+}
+
+static int fts3SegReaderArrayAdd(
+  Fts3SegReaderArray **ppArray, 
+  Fts3SegReader *pNew
+){
+  Fts3SegReaderArray *pArray = *ppArray;
+
+  if( !pArray || pArray->nAlloc==pArray->nSegment ){
+    int nNew = (pArray ? pArray->nAlloc+16 : 16);
+    pArray = (Fts3SegReaderArray *)sqlite3_realloc(pArray, 
+        sizeof(Fts3SegReaderArray) + (nNew-1) * sizeof(Fts3SegReader*)
+    );
+    if( !pArray ){
+      sqlite3Fts3SegReaderFree(pNew);
+      return SQLITE_NOMEM;
+    }
+    if( nNew==16 ){
+      pArray->nSegment = 0;
+      pArray->nCost = 0;
+    }
+    pArray->nAlloc = nNew;
+    *ppArray = pArray;
+  }
+
+  pArray->apSegment[pArray->nSegment++] = pNew;
+  return SQLITE_OK;
+}
+
+static int fts3TermSegReaderArray(
+  Fts3Cursor *pCsr,               /* Virtual table cursor handle */
   const char *zTerm,              /* Term to query for */
   int nTerm,                      /* Size of zTerm in bytes */
   int isPrefix,                   /* True for a prefix search */
-  int isReqPos,                   /* True to include position lists in output */
-  int *pnOut,                     /* OUT: Size of buffer at *ppOut */
-  char **ppOut                    /* OUT: Malloced result buffer */
+  Fts3SegReaderArray **ppArray    /* OUT: Allocated seg-reader array */
 ){
-  int i;
-  TermSelect tsc;
-  Fts3SegFilter filter;           /* Segment term filter configuration */
-  Fts3SegReader **apSegment;      /* Array of segments to read data from */
-  int nSegment = 0;               /* Size of apSegment array */
-  int nAlloc = 16;                /* Allocated size of segment array */
+  Fts3Table *p = (Fts3Table *)pCsr->base.pVtab;
   int rc;                         /* Return code */
+  Fts3SegReaderArray *pArray = 0; /* Array object to build */
+  Fts3SegReader *pReader = 0;     /* Seg-reader to add to pArray */ 
   sqlite3_stmt *pStmt = 0;        /* SQL statement to scan %_segdir table */
   int iAge = 0;                   /* Used to assign ages to segments */
 
-  apSegment = (Fts3SegReader **)sqlite3_malloc(sizeof(Fts3SegReader*)*nAlloc);
-  if( !apSegment ) return SQLITE_NOMEM;
-  rc = sqlite3Fts3SegReaderPending(p, zTerm, nTerm, isPrefix, &apSegment[0]);
-  if( rc!=SQLITE_OK ) goto finished;
-  if( apSegment[0] ){
-    nSegment = 1;
+  /* Allocate a seg-reader to scan the pending terms, if any. */
+  rc = sqlite3Fts3SegReaderPending(p, zTerm, nTerm, isPrefix, &pReader);
+  if( rc==SQLITE_OK && pReader ) {
+    rc = fts3SegReaderArrayAdd(&pArray, pReader);
   }
 
   /* Loop through the entire %_segdir table. For each segment, create a
@@ -108615,12 +110632,10 @@ static int fts3TermSelect(
   ** that may contain a term that matches zTerm/nTerm. For non-prefix
   ** searches, this is always a single leaf. For prefix searches, this
   ** may be a contiguous block of leaves.
-  **
-  ** The code in this loop does not actually load any leaves into memory
-  ** (unless the root node happens to be a leaf). It simply examines the
-  ** b-tree structure to determine which leaves need to be inspected.
   */
-  rc = sqlite3Fts3AllSegdirs(p, &pStmt);
+  if( rc==SQLITE_OK ){
+    rc = sqlite3Fts3AllSegdirs(p, &pStmt);
+  }
   while( rc==SQLITE_OK && SQLITE_ROW==(rc = sqlite3_step(pStmt)) ){
     Fts3SegReader *pNew = 0;
     int nRoot = sqlite3_column_bytes(pStmt, 4);
@@ -108630,66 +110645,79 @@ static int fts3TermSelect(
       ** leaf). Do not bother inspecting any data in this case, just
       ** create a Fts3SegReader to scan the single leaf. 
       */
-      rc = sqlite3Fts3SegReaderNew(p, iAge, 0, 0, 0, zRoot, nRoot, &pNew);
+      rc = sqlite3Fts3SegReaderNew(iAge, 0, 0, 0, zRoot, nRoot, &pNew);
     }else{
-      int rc2;                    /* Return value of sqlite3Fts3ReadBlock() */
-      sqlite3_int64 i1;           /* Blockid of leaf that may contain zTerm */
-      rc = fts3SelectLeaf(p, zTerm, nTerm, zRoot, nRoot, &i1);
+      sqlite3_int64 i1;           /* First leaf that may contain zTerm */
+      sqlite3_int64 i2;           /* Final leaf that may contain zTerm */
+      rc = fts3SelectLeaf(p, zTerm, nTerm, zRoot, nRoot, &i1, (isPrefix?&i2:0));
+      if( isPrefix==0 ) i2 = i1;
       if( rc==SQLITE_OK ){
-        sqlite3_int64 i2 = sqlite3_column_int64(pStmt, 2);
-        rc = sqlite3Fts3SegReaderNew(p, iAge, i1, i2, 0, 0, 0, &pNew);
+        rc = sqlite3Fts3SegReaderNew(iAge, i1, i2, 0, 0, 0, &pNew);
       }
+    }
+    assert( (pNew==0)==(rc!=SQLITE_OK) );
 
-      /* The following call to ReadBlock() serves to reset the SQL statement
-      ** used to retrieve blocks of data from the %_segments table. If it is
-      ** not reset here, then it may remain classified as an active statement 
-      ** by SQLite, which may lead to "DROP TABLE" or "DETACH" commands 
-      ** failing.
-      */ 
-      rc2 = sqlite3Fts3ReadBlock(p, 0, 0, 0);
-      if( rc==SQLITE_OK ){
-        rc = rc2;
-      }
+    /* If a new Fts3SegReader was allocated, add it to the array. */
+    if( rc==SQLITE_OK ){
+      rc = fts3SegReaderArrayAdd(&pArray, pNew);
+    }
+    if( rc==SQLITE_OK ){
+      rc = sqlite3Fts3SegReaderCost(pCsr, pNew, &pArray->nCost);
     }
     iAge++;
+  }
 
-    /* If a new Fts3SegReader was allocated, add it to the apSegment array. */
-    assert( pNew!=0 || rc!=SQLITE_OK );
-    if( pNew ){
-      if( nSegment==nAlloc ){
-        Fts3SegReader **pArray;
-        nAlloc += 16;
-        pArray = (Fts3SegReader **)sqlite3_realloc(
-            apSegment, nAlloc*sizeof(Fts3SegReader *)
-        );
-        if( !pArray ){
-          sqlite3Fts3SegReaderFree(p, pNew);
-          rc = SQLITE_NOMEM;
-          goto finished;
-        }
-        apSegment = pArray;
-      }
-      apSegment[nSegment++] = pNew;
-    }
+  if( rc==SQLITE_DONE ){
+    rc = sqlite3_reset(pStmt);
+  }else{
+    sqlite3_reset(pStmt);
   }
-  if( rc!=SQLITE_DONE ){
-    assert( rc!=SQLITE_OK );
-    goto finished;
+  if( rc!=SQLITE_OK ){
+    fts3SegReaderArrayFree(pArray);
+    pArray = 0;
   }
+  *ppArray = pArray;
+  return rc;
+}
+
+/*
+** This function retreives the doclist for the specified term (or term
+** prefix) from the database. 
+**
+** The returned doclist may be in one of two formats, depending on the 
+** value of parameter isReqPos. If isReqPos is zero, then the doclist is
+** a sorted list of delta-compressed docids (a bare doclist). If isReqPos
+** is non-zero, then the returned list is in the same format as is stored 
+** in the database without the found length specifier at the start of on-disk
+** doclists.
+*/
+static int fts3TermSelect(
+  Fts3Table *p,                   /* Virtual table handle */
+  Fts3PhraseToken *pTok,          /* Token to query for */
+  int iColumn,                    /* Column to query (or -ve for all columns) */
+  int isReqPos,                   /* True to include position lists in output */
+  int *pnOut,                     /* OUT: Size of buffer at *ppOut */
+  char **ppOut                    /* OUT: Malloced result buffer */
+){
+  int rc;                         /* Return code */
+  Fts3SegReaderArray *pArray;     /* Seg-reader array for this term */
+  TermSelect tsc;               /* Context object for fts3TermSelectCb() */
+  Fts3SegFilter filter;         /* Segment term filter configuration */
 
+  pArray = pTok->pArray;
   memset(&tsc, 0, sizeof(TermSelect));
   tsc.isReqPos = isReqPos;
 
   filter.flags = FTS3_SEGMENT_IGNORE_EMPTY 
-        | (isPrefix ? FTS3_SEGMENT_PREFIX : 0)
+        | (pTok->isPrefix ? FTS3_SEGMENT_PREFIX : 0)
         | (isReqPos ? FTS3_SEGMENT_REQUIRE_POS : 0)
         | (iColumn<p->nColumn ? FTS3_SEGMENT_COLUMN_FILTER : 0);
   filter.iCol = iColumn;
-  filter.zTerm = zTerm;
-  filter.nTerm = nTerm;
+  filter.zTerm = pTok->z;
+  filter.nTerm = pTok->n;
 
-  rc = sqlite3Fts3SegReaderIterate(p, apSegment, nSegment, &filter,
-      fts3TermSelectCb, (void *)&tsc
+  rc = sqlite3Fts3SegReaderIterate(p, pArray->apSegment, pArray->nSegment, 
+      &filter, fts3TermSelectCb, (void *)&tsc
   );
   if( rc==SQLITE_OK ){
     rc = fts3TermSelectMerge(&tsc);
@@ -108699,26 +110727,112 @@ static int fts3TermSelect(
     *ppOut = tsc.aaOutput[0];
     *pnOut = tsc.anOutput[0];
   }else{
+    int i;
     for(i=0; i<SizeofArray(tsc.aaOutput); i++){
       sqlite3_free(tsc.aaOutput[i]);
     }
   }
 
-finished:
-  sqlite3_reset(pStmt);
-  for(i=0; i<nSegment; i++){
-    sqlite3Fts3SegReaderFree(p, apSegment[i]);
+  fts3SegReaderArrayFree(pArray);
+  pTok->pArray = 0;
+  return rc;
+}
+
+/*
+** This function counts the total number of docids in the doclist stored
+** in buffer aList[], size nList bytes.
+**
+** If the isPoslist argument is true, then it is assumed that the doclist
+** contains a position-list following each docid. Otherwise, it is assumed
+** that the doclist is simply a list of docids stored as delta encoded 
+** varints.
+*/
+static int fts3DoclistCountDocids(int isPoslist, char *aList, int nList){
+  int nDoc = 0;                   /* Return value */
+  if( aList ){
+    char *aEnd = &aList[nList];   /* Pointer to one byte after EOF */
+    char *p = aList;              /* Cursor */
+    if( !isPoslist ){
+      /* The number of docids in the list is the same as the number of 
+      ** varints. In FTS3 a varint consists of a single byte with the 0x80 
+      ** bit cleared and zero or more bytes with the 0x80 bit set. So to
+      ** count the varints in the buffer, just count the number of bytes
+      ** with the 0x80 bit clear.  */
+      while( p<aEnd ) nDoc += (((*p++)&0x80)==0);
+    }else{
+      while( p<aEnd ){
+        nDoc++;
+        while( (*p++)&0x80 );     /* Skip docid varint */
+        fts3PoslistCopy(0, &p);   /* Skip over position list */
+      }
+    }
+  }
+
+  return nDoc;
+}
+
+/*
+** Call sqlite3Fts3DeferToken() for each token in the expression pExpr.
+*/
+static int fts3DeferExpression(Fts3Cursor *pCsr, Fts3Expr *pExpr){
+  int rc = SQLITE_OK;
+  if( pExpr ){
+    rc = fts3DeferExpression(pCsr, pExpr->pLeft);
+    if( rc==SQLITE_OK ){
+      rc = fts3DeferExpression(pCsr, pExpr->pRight);
+    }
+    if( pExpr->eType==FTSQUERY_PHRASE ){
+      int iCol = pExpr->pPhrase->iColumn;
+      int i;
+      for(i=0; rc==SQLITE_OK && i<pExpr->pPhrase->nToken; i++){
+        Fts3PhraseToken *pToken = &pExpr->pPhrase->aToken[i];
+        if( pToken->pDeferred==0 ){
+          rc = sqlite3Fts3DeferToken(pCsr, pToken, iCol);
+        }
+      }
+    }
   }
-  sqlite3_free(apSegment);
   return rc;
 }
 
+/*
+** This function removes the position information from a doclist. When
+** called, buffer aList (size *pnList bytes) contains a doclist that includes
+** position information. This function removes the position information so
+** that aList contains only docids, and adjusts *pnList to reflect the new
+** (possibly reduced) size of the doclist.
+*/
+static void fts3DoclistStripPositions(
+  char *aList,                    /* IN/OUT: Buffer containing doclist */
+  int *pnList                     /* IN/OUT: Size of doclist in bytes */
+){
+  if( aList ){
+    char *aEnd = &aList[*pnList]; /* Pointer to one byte after EOF */
+    char *p = aList;              /* Input cursor */
+    char *pOut = aList;           /* Output cursor */
+  
+    while( p<aEnd ){
+      sqlite3_int64 delta;
+      p += sqlite3Fts3GetVarint(p, &delta);
+      fts3PoslistCopy(0, &p);
+      pOut += sqlite3Fts3PutVarint(pOut, delta);
+    }
+
+    *pnList = (int)(pOut - aList);
+  }
+}
 
 /* 
 ** Return a DocList corresponding to the phrase *pPhrase.
+**
+** If this function returns SQLITE_OK, but *pnOut is set to a negative value,
+** then no tokens in the phrase were looked up in the full-text index. This
+** is only possible when this function is called from within xFilter(). The
+** caller should assume that all documents match the phrase. The actual
+** filtering will take place in xNext().
 */
 static int fts3PhraseSelect(
-  Fts3Table *p,                   /* Virtual table handle */
+  Fts3Cursor *pCsr,               /* Virtual table cursor handle */
   Fts3Phrase *pPhrase,            /* Phrase to return a doclist for */
   int isReqPos,                   /* True if output should contain positions */
   char **paOut,                   /* OUT: Pointer to malloc'd result buffer */
@@ -108730,42 +110844,137 @@ static int fts3PhraseSelect(
   int ii;
   int iCol = pPhrase->iColumn;
   int isTermPos = (pPhrase->nToken>1 || isReqPos);
+  Fts3Table *p = (Fts3Table *)pCsr->base.pVtab;
+  int isFirst = 1;
 
+  int iPrevTok = 0;
+  int nDoc = 0;
+
+  /* If this is an xFilter() evaluation, create a segment-reader for each
+  ** phrase token. Or, if this is an xNext() or snippet/offsets/matchinfo
+  ** evaluation, only create segment-readers if there are no Fts3DeferredToken
+  ** objects attached to the phrase-tokens.
+  */
   for(ii=0; ii<pPhrase->nToken; ii++){
-    struct PhraseToken *pTok = &pPhrase->aToken[ii];
-    char *z = pTok->z;            /* Next token of the phrase */
-    int n = pTok->n;              /* Size of z in bytes */
-    int isPrefix = pTok->isPrefix;/* True if token is a prefix */
-    char *pList;                  /* Pointer to token doclist */
-    int nList;                    /* Size of buffer at pList */
-
-    rc = fts3TermSelect(p, iCol, z, n, isPrefix, isTermPos, &nList, &pList);
+    Fts3PhraseToken *pTok = &pPhrase->aToken[ii];
+    if( pTok->pArray==0 ){
+      if( (pCsr->eEvalmode==FTS3_EVAL_FILTER)
+       || (pCsr->eEvalmode==FTS3_EVAL_NEXT && pCsr->pDeferred==0) 
+       || (pCsr->eEvalmode==FTS3_EVAL_MATCHINFO && pTok->bFulltext) 
+      ){
+        rc = fts3TermSegReaderArray(
+            pCsr, pTok->z, pTok->n, pTok->isPrefix, &pTok->pArray
+        );
+        if( rc!=SQLITE_OK ) return rc;
+      }
+    }
+  }
+
+  for(ii=0; ii<pPhrase->nToken; ii++){
+    Fts3PhraseToken *pTok;        /* Token to find doclist for */
+    int iTok = 0;                 /* The token being queried this iteration */
+    char *pList = 0;              /* Pointer to token doclist */
+    int nList = 0;                /* Size of buffer at pList */
+
+    /* Select a token to process. If this is an xFilter() call, then tokens 
+    ** are processed in order from least to most costly. Otherwise, tokens 
+    ** are processed in the order in which they occur in the phrase.
+    */
+    if( pCsr->eEvalmode==FTS3_EVAL_MATCHINFO ){
+      assert( isReqPos );
+      iTok = ii;
+      pTok = &pPhrase->aToken[iTok];
+      if( pTok->bFulltext==0 ) continue;
+    }else if( pCsr->eEvalmode==FTS3_EVAL_NEXT || isReqPos ){
+      iTok = ii;
+      pTok = &pPhrase->aToken[iTok];
+    }else{
+      int nMinCost = 0x7FFFFFFF;
+      int jj;
+
+      /* Find the remaining token with the lowest cost. */
+      for(jj=0; jj<pPhrase->nToken; jj++){
+        Fts3SegReaderArray *pArray = pPhrase->aToken[jj].pArray;
+        if( pArray && pArray->nCost<nMinCost ){
+          iTok = jj;
+          nMinCost = pArray->nCost;
+        }
+      }
+      pTok = &pPhrase->aToken[iTok];
+
+      /* This branch is taken if it is determined that loading the doclist
+      ** for the next token would require more IO than loading all documents
+      ** currently identified by doclist pOut/nOut. No further doclists will
+      ** be loaded from the full-text index for this phrase.
+      */
+      if( nMinCost>nDoc && ii>0 ){
+        rc = fts3DeferExpression(pCsr, pCsr->pExpr);
+        break;
+      }
+    }
+
+    if( pCsr->eEvalmode==FTS3_EVAL_NEXT && pTok->pDeferred ){
+      rc = fts3DeferredTermSelect(pTok->pDeferred, isTermPos, &nList, &pList);
+    }else{
+      if( pTok->pArray ){
+        rc = fts3TermSelect(p, pTok, iCol, isTermPos, &nList, &pList);
+      }
+      pTok->bFulltext = 1;
+    }
+    assert( rc!=SQLITE_OK || pCsr->eEvalmode || pTok->pArray==0 );
     if( rc!=SQLITE_OK ) break;
 
-    if( ii==0 ){
+    if( isFirst ){
       pOut = pList;
       nOut = nList;
+      if( pCsr->eEvalmode==FTS3_EVAL_FILTER && pPhrase->nToken>1 ){
+        nDoc = fts3DoclistCountDocids(1, pOut, nOut);
+      }
+      isFirst = 0;
+      iPrevTok = iTok;
     }else{
-      /* Merge the new term list and the current output. If this is the
-      ** last term in the phrase, and positions are not required in the
-      ** output of this function, the positions can be dropped as part
-      ** of this merge. Either way, the result of this merge will be
-      ** smaller than nList bytes. The code in fts3DoclistMerge() is written
-      ** so that it is safe to use pList as the output as well as an input
-      ** in this case.
+      /* Merge the new term list and the current output. */
+      char *aLeft, *aRight;
+      int nLeft, nRight;
+      int nDist;
+      int mt;
+
+      /* If this is the final token of the phrase, and positions were not
+      ** requested by the caller, use MERGE_PHRASE instead of POS_PHRASE.
+      ** This drops the position information from the output list.
       */
-      int mergetype = MERGE_POS_PHRASE;
-      if( ii==pPhrase->nToken-1 && !isReqPos ){
-        mergetype = MERGE_PHRASE;
-      }
-      fts3DoclistMerge(mergetype, 0, 0, pList, &nOut, pOut, nOut, pList, nList);
-      sqlite3_free(pOut);
-      pOut = pList;
+      mt = MERGE_POS_PHRASE;
+      if( ii==pPhrase->nToken-1 && !isReqPos ) mt = MERGE_PHRASE;
+
+      assert( iPrevTok!=iTok );
+      if( iPrevTok<iTok ){
+        aLeft = pOut;
+        nLeft = nOut;
+        aRight = pList;
+        nRight = nList;
+        nDist = iTok-iPrevTok;
+        iPrevTok = iTok;
+      }else{
+        aRight = pOut;
+        nRight = nOut;
+        aLeft = pList;
+        nLeft = nList;
+        nDist = iPrevTok-iTok;
+      }
+      pOut = aRight;
+      fts3DoclistMerge(
+          mt, nDist, 0, pOut, &nOut, aLeft, nLeft, aRight, nRight, &nDoc
+      );
+      sqlite3_free(aLeft);
     }
     assert( nOut==0 || pOut!=0 );
   }
 
   if( rc==SQLITE_OK ){
+    if( ii!=pPhrase->nToken ){
+      assert( pCsr->eEvalmode==FTS3_EVAL_FILTER && isReqPos==0 );
+      fts3DoclistStripPositions(pOut, &nOut);
+    }
     *paOut = pOut;
     *pnOut = nOut;
   }else{
@@ -108774,6 +110983,14 @@ static int fts3PhraseSelect(
   return rc;
 }
 
+/*
+** This function merges two doclists according to the requirements of a
+** NEAR operator.
+**
+** Both input doclists must include position information. The output doclist 
+** includes position information if the first argument to this function
+** is MERGE_POS_NEAR, or does not if it is MERGE_NEAR.
+*/
 static int fts3NearMerge(
   int mergetype,                  /* MERGE_POS_NEAR or MERGE_NEAR */
   int nNear,                      /* Parameter to NEAR operator */
@@ -108786,8 +111003,8 @@ static int fts3NearMerge(
   char **paOut,                   /* OUT: Results of merge (malloced) */
   int *pnOut                      /* OUT: Sized of output buffer */
 ){
-  char *aOut;
-  int rc;
+  char *aOut;                     /* Buffer to write output doclist to */
+  int rc;                         /* Return code */
 
   assert( mergetype==MERGE_POS_NEAR || MERGE_NEAR );
 
@@ -108796,7 +111013,7 @@ static int fts3NearMerge(
     rc = SQLITE_NOMEM;
   }else{
     rc = fts3DoclistMerge(mergetype, nNear+nTokenRight, nNear+nTokenLeft, 
-      aOut, pnOut, aLeft, nLeft, aRight, nRight
+      aOut, pnOut, aLeft, nLeft, aRight, nRight, 0
     );
     if( rc!=SQLITE_OK ){
       sqlite3_free(aOut);
@@ -108808,8 +111025,23 @@ static int fts3NearMerge(
   return rc;
 }
 
+/*
+** This function is used as part of the processing for the snippet() and
+** offsets() functions.
+**
+** Both pLeft and pRight are expression nodes of type FTSQUERY_PHRASE. Both
+** have their respective doclists (including position information) loaded
+** in Fts3Expr.aDoclist/nDoclist. This function removes all entries from
+** each doclist that are not within nNear tokens of a corresponding entry
+** in the other doclist.
+*/
 SQLITE_PRIVATE int sqlite3Fts3ExprNearTrim(Fts3Expr *pLeft, Fts3Expr *pRight, int nNear){
-  int rc;
+  int rc;                         /* Return code */
+
+  assert( pLeft->eType==FTSQUERY_PHRASE );
+  assert( pRight->eType==FTSQUERY_PHRASE );
+  assert( pLeft->isLoaded && pRight->isLoaded );
+
   if( pLeft->aDoclist==0 || pRight->aDoclist==0 ){
     sqlite3_free(pLeft->aDoclist);
     sqlite3_free(pRight->aDoclist);
@@ -108817,8 +111049,8 @@ SQLITE_PRIVATE int sqlite3Fts3ExprNearTrim(Fts3Expr *pLeft, Fts3Expr *pRight, in
     pLeft->aDoclist = 0;
     rc = SQLITE_OK;
   }else{
-    char *aOut;
-    int nOut;
+    char *aOut;                   /* Buffer in which to assemble new doclist */
+    int nOut;                     /* Size of buffer aOut in bytes */
 
     rc = fts3NearMerge(MERGE_POS_NEAR, nNear, 
         pLeft->pPhrase->nToken, pLeft->aDoclist, pLeft->nDoclist,
@@ -108842,14 +111074,156 @@ SQLITE_PRIVATE int sqlite3Fts3ExprNearTrim(Fts3Expr *pLeft, Fts3Expr *pRight, in
   return rc;
 }
 
+
 /*
-** Evaluate the full-text expression pExpr against fts3 table pTab. Store
-** the resulting doclist in *paOut and *pnOut.  This routine mallocs for
-** the space needed to store the output.  The caller is responsible for
-** freeing the space when it has finished.
+** Allocate an Fts3SegReaderArray for each token in the expression pExpr. 
+** The allocated objects are stored in the Fts3PhraseToken.pArray member
+** variables of each token structure.
 */
-static int evalFts3Expr(
-  Fts3Table *p,                   /* Virtual table handle */
+static int fts3ExprAllocateSegReaders(
+  Fts3Cursor *pCsr,               /* FTS3 table */
+  Fts3Expr *pExpr,                /* Expression to create seg-readers for */
+  int *pnExpr                     /* OUT: Number of AND'd expressions */
+){
+  int rc = SQLITE_OK;             /* Return code */
+
+  assert( pCsr->eEvalmode==FTS3_EVAL_FILTER );
+  if( pnExpr && pExpr->eType!=FTSQUERY_AND ){
+    (*pnExpr)++;
+    pnExpr = 0;
+  }
+
+  if( pExpr->eType==FTSQUERY_PHRASE ){
+    Fts3Phrase *pPhrase = pExpr->pPhrase;
+    int ii;
+
+    for(ii=0; rc==SQLITE_OK && ii<pPhrase->nToken; ii++){
+      Fts3PhraseToken *pTok = &pPhrase->aToken[ii];
+      if( pTok->pArray==0 ){
+        rc = fts3TermSegReaderArray(
+            pCsr, pTok->z, pTok->n, pTok->isPrefix, &pTok->pArray
+        );
+      }
+    }
+  }else{ 
+    rc = fts3ExprAllocateSegReaders(pCsr, pExpr->pLeft, pnExpr);
+    if( rc==SQLITE_OK ){
+      rc = fts3ExprAllocateSegReaders(pCsr, pExpr->pRight, pnExpr);
+    }
+  }
+  return rc;
+}
+
+/*
+** Free the Fts3SegReaderArray objects associated with each token in the
+** expression pExpr. In other words, this function frees the resources
+** allocated by fts3ExprAllocateSegReaders().
+*/
+static void fts3ExprFreeSegReaders(Fts3Expr *pExpr){
+  if( pExpr ){
+    Fts3Phrase *pPhrase = pExpr->pPhrase;
+    if( pPhrase ){
+      int kk;
+      for(kk=0; kk<pPhrase->nToken; kk++){
+        fts3SegReaderArrayFree(pPhrase->aToken[kk].pArray);
+        pPhrase->aToken[kk].pArray = 0;
+      }
+    }
+    fts3ExprFreeSegReaders(pExpr->pLeft);
+    fts3ExprFreeSegReaders(pExpr->pRight);
+  }
+}
+
+/*
+** Return the sum of the costs of all tokens in the expression pExpr. This
+** function must be called after Fts3SegReaderArrays have been allocated
+** for all tokens using fts3ExprAllocateSegReaders().
+*/
+static int fts3ExprCost(Fts3Expr *pExpr){
+  int nCost;                      /* Return value */
+  if( pExpr->eType==FTSQUERY_PHRASE ){
+    Fts3Phrase *pPhrase = pExpr->pPhrase;
+    int ii;
+    nCost = 0;
+    for(ii=0; ii<pPhrase->nToken; ii++){
+      Fts3SegReaderArray *pArray = pPhrase->aToken[ii].pArray;
+      if( pArray ){
+        nCost += pPhrase->aToken[ii].pArray->nCost;
+      }
+    }
+  }else{
+    nCost = fts3ExprCost(pExpr->pLeft) + fts3ExprCost(pExpr->pRight);
+  }
+  return nCost;
+}
+
+/*
+** The following is a helper function (and type) for fts3EvalExpr(). It
+** must be called after Fts3SegReaders have been allocated for every token
+** in the expression. See the context it is called from in fts3EvalExpr()
+** for further explanation.
+*/
+typedef struct ExprAndCost ExprAndCost;
+struct ExprAndCost {
+  Fts3Expr *pExpr;
+  int nCost;
+};
+static void fts3ExprAssignCosts(
+  Fts3Expr *pExpr,                /* Expression to create seg-readers for */
+  ExprAndCost **ppExprCost        /* OUT: Write to *ppExprCost */
+){
+  if( pExpr->eType==FTSQUERY_AND ){
+    fts3ExprAssignCosts(pExpr->pLeft, ppExprCost);
+    fts3ExprAssignCosts(pExpr->pRight, ppExprCost);
+  }else{
+    (*ppExprCost)->pExpr = pExpr;
+    (*ppExprCost)->nCost = fts3ExprCost(pExpr);
+    (*ppExprCost)++;
+  }
+}
+
+/*
+** Evaluate the full-text expression pExpr against FTS3 table pTab. Store
+** the resulting doclist in *paOut and *pnOut. This routine mallocs for
+** the space needed to store the output. The caller is responsible for
+** freeing the space when it has finished.
+**
+** This function is called in two distinct contexts:
+**
+**   * From within the virtual table xFilter() method. In this case, the
+**     output doclist contains entries for all rows in the table, based on
+**     data read from the full-text index.
+**
+**     In this case, if the query expression contains one or more tokens that 
+**     are very common, then the returned doclist may contain a superset of 
+**     the documents that actually match the expression.
+**
+**   * From within the virtual table xNext() method. This call is only made
+**     if the call from within xFilter() found that there were very common 
+**     tokens in the query expression and did return a superset of the 
+**     matching documents. In this case the returned doclist contains only
+**     entries that correspond to the current row of the table. Instead of
+**     reading the data for each token from the full-text index, the data is
+**     already available in-memory in the Fts3PhraseToken.pDeferred structures.
+**     See fts3EvalDeferred() for how it gets there.
+**
+** In the first case above, Fts3Cursor.doDeferred==0. In the second (if it is
+** required) Fts3Cursor.doDeferred==1.
+**
+** If the SQLite invokes the snippet(), offsets() or matchinfo() function
+** as part of a SELECT on an FTS3 table, this function is called on each
+** individual phrase expression in the query. If there were very common tokens
+** found in the xFilter() call, then this function is called once for phrase
+** for each row visited, and the returned doclist contains entries for the
+** current row only. Otherwise, if there were no very common tokens, then this
+** function is called once only for each phrase in the query and the returned
+** doclist contains entries for all rows of the table.
+**
+** Fts3Cursor.doDeferred==1 when this function is called on phrases as a
+** result of a snippet(), offsets() or matchinfo() invocation.
+*/
+static int fts3EvalExpr(
+  Fts3Cursor *p,                  /* Virtual table cursor handle */
   Fts3Expr *pExpr,                /* Parsed fts3 expression */
   char **paOut,                   /* OUT: Pointer to malloc'd result buffer */
   int *pnOut,                     /* OUT: Size of buffer at *paOut */
@@ -108862,33 +111236,102 @@ static int evalFts3Expr(
   *pnOut = 0;
 
   if( pExpr ){
-    assert( pExpr->eType==FTSQUERY_PHRASE 
-         || pExpr->eType==FTSQUERY_NEAR 
-         || isReqPos==0
+    assert( pExpr->eType==FTSQUERY_NEAR   || pExpr->eType==FTSQUERY_OR     
+         || pExpr->eType==FTSQUERY_AND    || pExpr->eType==FTSQUERY_NOT
+         || pExpr->eType==FTSQUERY_PHRASE
     );
+    assert( pExpr->eType==FTSQUERY_PHRASE || isReqPos==0 );
+
     if( pExpr->eType==FTSQUERY_PHRASE ){
-      rc = fts3PhraseSelect(p, pExpr->pPhrase, 
+      rc = fts3PhraseSelect(p, pExpr->pPhrase,
           isReqPos || (pExpr->pParent && pExpr->pParent->eType==FTSQUERY_NEAR),
           paOut, pnOut
       );
+      fts3ExprFreeSegReaders(pExpr);
+    }else if( p->eEvalmode==FTS3_EVAL_FILTER && pExpr->eType==FTSQUERY_AND ){
+      ExprAndCost *aExpr = 0;     /* Array of AND'd expressions and costs */
+      int nExpr = 0;              /* Size of aExpr[] */
+      char *aRet = 0;             /* Doclist to return to caller */
+      int nRet = 0;               /* Length of aRet[] in bytes */
+      int nDoc = 0x7FFFFFFF;
+
+      assert( !isReqPos );
+
+      rc = fts3ExprAllocateSegReaders(p, pExpr, &nExpr);
+      if( rc==SQLITE_OK ){
+        assert( nExpr>1 );
+        aExpr = sqlite3_malloc(sizeof(ExprAndCost) * nExpr);
+        if( !aExpr ) rc = SQLITE_NOMEM;
+      }
+      if( rc==SQLITE_OK ){
+        int ii;                   /* Used to iterate through expressions */
+
+        fts3ExprAssignCosts(pExpr, &aExpr);
+        aExpr -= nExpr;
+        for(ii=0; ii<nExpr; ii++){
+          char *aNew;
+          int nNew;
+          int jj;
+          ExprAndCost *pBest = 0;
+  
+          for(jj=0; jj<nExpr; jj++){
+            ExprAndCost *pCand = &aExpr[jj];
+            if( pCand->pExpr && (pBest==0 || pCand->nCost<pBest->nCost) ){
+              pBest = pCand;
+            }
+          }
+  
+          if( pBest->nCost>nDoc ){
+            rc = fts3DeferExpression(p, p->pExpr);
+            break;
+          }else{
+            rc = fts3EvalExpr(p, pBest->pExpr, &aNew, &nNew, 0);
+            if( rc!=SQLITE_OK ) break;
+            pBest->pExpr = 0;
+            if( ii==0 ){
+              aRet = aNew;
+              nRet = nNew;
+              nDoc = fts3DoclistCountDocids(0, aRet, nRet);
+            }else{
+              fts3DoclistMerge(
+                  MERGE_AND, 0, 0, aRet, &nRet, aRet, nRet, aNew, nNew, &nDoc
+              );
+              sqlite3_free(aNew);
+            }
+          }
+        }
+      }
+
+      if( rc==SQLITE_OK ){
+        *paOut = aRet;
+        *pnOut = nRet;
+      }else{
+        assert( *paOut==0 );
+        sqlite3_free(aRet);
+      }
+      sqlite3_free(aExpr);
+      fts3ExprFreeSegReaders(pExpr);
+
     }else{
       char *aLeft;
       char *aRight;
       int nLeft;
       int nRight;
 
-      if( 0==(rc = evalFts3Expr(p, pExpr->pRight, &aRight, &nRight, isReqPos))
-       && 0==(rc = evalFts3Expr(p, pExpr->pLeft, &aLeft, &nLeft, isReqPos))
+      assert( pExpr->eType==FTSQUERY_NEAR 
+           || pExpr->eType==FTSQUERY_OR
+           || pExpr->eType==FTSQUERY_NOT
+           || (pExpr->eType==FTSQUERY_AND && p->eEvalmode==FTS3_EVAL_NEXT)
+      );
+
+      if( 0==(rc = fts3EvalExpr(p, pExpr->pRight, &aRight, &nRight, isReqPos))
+       && 0==(rc = fts3EvalExpr(p, pExpr->pLeft, &aLeft, &nLeft, isReqPos))
       ){
-        assert( pExpr->eType==FTSQUERY_NEAR || pExpr->eType==FTSQUERY_OR     
-            || pExpr->eType==FTSQUERY_AND  || pExpr->eType==FTSQUERY_NOT
-        );
         switch( pExpr->eType ){
           case FTSQUERY_NEAR: {
             Fts3Expr *pLeft;
             Fts3Expr *pRight;
-            int mergetype = isReqPos ? MERGE_POS_NEAR : MERGE_NEAR;
-           
+            int mergetype = MERGE_NEAR;
             if( pExpr->pParent && pExpr->pParent->eType==FTSQUERY_NEAR ){
               mergetype = MERGE_POS_NEAR;
             }
@@ -108917,7 +111360,7 @@ static int evalFts3Expr(
             */
             char *aBuffer = sqlite3_malloc(nRight+nLeft+1);
             rc = fts3DoclistMerge(MERGE_OR, 0, 0, aBuffer, pnOut,
-                aLeft, nLeft, aRight, nRight
+                aLeft, nLeft, aRight, nRight, 0
             );
             *paOut = aBuffer;
             sqlite3_free(aLeft);
@@ -108927,7 +111370,7 @@ static int evalFts3Expr(
           default: {
             assert( FTSQUERY_NOT==MERGE_NOT && FTSQUERY_AND==MERGE_AND );
             fts3DoclistMerge(pExpr->eType, 0, 0, aLeft, pnOut,
-                aLeft, nLeft, aRight, nRight
+                aLeft, nLeft, aRight, nRight, 0
             );
             *paOut = aLeft;
             break;
@@ -108938,6 +111381,89 @@ static int evalFts3Expr(
     }
   }
 
+  assert( rc==SQLITE_OK || *paOut==0 );
+  return rc;
+}
+
+/*
+** This function is called from within xNext() for each row visited by
+** an FTS3 query. If evaluating the FTS3 query expression within xFilter()
+** was able to determine the exact set of matching rows, this function sets
+** *pbRes to true and returns SQLITE_IO immediately.
+**
+** Otherwise, if evaluating the query expression within xFilter() returned a
+** superset of the matching documents instead of an exact set (this happens
+** when the query includes very common tokens and it is deemed too expensive to
+** load their doclists from disk), this function tests if the current row
+** really does match the FTS3 query.
+**
+** If an error occurs, an SQLite error code is returned. Otherwise, SQLITE_OK
+** is returned and *pbRes is set to true if the current row matches the
+** FTS3 query (and should be included in the results returned to SQLite), or
+** false otherwise.
+*/
+static int fts3EvalDeferred(
+  Fts3Cursor *pCsr,               /* FTS3 cursor pointing at row to test */
+  int *pbRes                      /* OUT: Set to true if row is a match */
+){
+  int rc = SQLITE_OK;
+  if( pCsr->pDeferred==0 ){
+    *pbRes = 1;
+  }else{
+    rc = fts3CursorSeek(0, pCsr);
+    if( rc==SQLITE_OK ){
+      sqlite3Fts3FreeDeferredDoclists(pCsr);
+      rc = sqlite3Fts3CacheDeferredDoclists(pCsr);
+    }
+    if( rc==SQLITE_OK ){
+      char *a = 0;
+      int n = 0;
+      rc = fts3EvalExpr(pCsr, pCsr->pExpr, &a, &n, 0);
+      assert( n>=0 );
+      *pbRes = (n>0);
+      sqlite3_free(a);
+    }
+  }
+  return rc;
+}
+
+/*
+** Advance the cursor to the next row in the %_content table that
+** matches the search criteria.  For a MATCH search, this will be
+** the next row that matches. For a full-table scan, this will be
+** simply the next row in the %_content table.  For a docid lookup,
+** this routine simply sets the EOF flag.
+**
+** Return SQLITE_OK if nothing goes wrong.  SQLITE_OK is returned
+** even if we reach end-of-file.  The fts3EofMethod() will be called
+** subsequently to determine whether or not an EOF was hit.
+*/
+static int fts3NextMethod(sqlite3_vtab_cursor *pCursor){
+  int res;
+  int rc = SQLITE_OK;             /* Return code */
+  Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
+
+  pCsr->eEvalmode = FTS3_EVAL_NEXT;
+  do {
+    if( pCsr->aDoclist==0 ){
+      if( SQLITE_ROW!=sqlite3_step(pCsr->pStmt) ){
+        pCsr->isEof = 1;
+        rc = sqlite3_reset(pCsr->pStmt);
+        break;
+      }
+      pCsr->iPrevId = sqlite3_column_int64(pCsr->pStmt, 0);
+    }else{
+      if( pCsr->pNextId>=&pCsr->aDoclist[pCsr->nDoclist] ){
+        pCsr->isEof = 1;
+        break;
+      }
+      sqlite3_reset(pCsr->pStmt);
+      fts3GetDeltaVarint(&pCsr->pNextId, &pCsr->iPrevId);
+      pCsr->isRequireSeek = 1;
+      pCsr->isMatchinfoNeeded = 1;
+    }
+  }while( SQLITE_OK==(rc = fts3EvalDeferred(pCsr, &res)) && res==0 );
+
   return rc;
 }
 
@@ -108957,11 +111483,6 @@ static int evalFts3Expr(
 ** number idxNum-FTS3_FULLTEXT_SEARCH, 0 indexed.  argv[0] is the right-hand
 ** side of the MATCH operator.
 */
-/* TODO(shess) Upgrade the cursor initialization and destruction to
-** account for fts3FilterMethod() being called multiple times on the
-** same cursor. The current solution is very fragile. Apply fix to
-** fts3 as appropriate.
-*/
 static int fts3FilterMethod(
   sqlite3_vtab_cursor *pCursor,   /* The cursor used for this query */
   int idxNum,                     /* Strategy index */
@@ -108984,6 +111505,7 @@ static int fts3FilterMethod(
   assert( idxNum>=0 && idxNum<=(FTS3_FULLTEXT_SEARCH+p->nColumn) );
   assert( nVal==0 || nVal==1 );
   assert( (nVal==0)==(idxNum==FTS3_FULLSCAN_SEARCH) );
+  assert( p->pSegments==0 );
 
   /* In case the cursor has been used before, clear it now. */
   sqlite3_finalize(pCsr->pStmt);
@@ -108991,24 +111513,7 @@ static int fts3FilterMethod(
   sqlite3Fts3ExprFree(pCsr->pExpr);
   memset(&pCursor[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor));
 
-  /* Compile a SELECT statement for this cursor. For a full-table-scan, the
-  ** statement loops through all rows of the %_content table. For a
-  ** full-text query or docid lookup, the statement retrieves a single
-  ** row by docid.
-  */
-  zSql = sqlite3_mprintf(azSql[idxNum==FTS3_FULLSCAN_SEARCH], p->zDb, p->zName);
-  if( !zSql ){
-    rc = SQLITE_NOMEM;
-  }else{
-    rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0);
-    sqlite3_free(zSql);
-  }
-  if( rc!=SQLITE_OK ) return rc;
-  pCsr->eSearch = (i16)idxNum;
-
-  if( idxNum==FTS3_DOCID_SEARCH ){
-    rc = sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]);
-  }else if( idxNum!=FTS3_FULLSCAN_SEARCH ){
+  if( idxNum!=FTS3_DOCID_SEARCH && idxNum!=FTS3_FULLSCAN_SEARCH ){
     int iCol = idxNum-FTS3_FULLTEXT_SEARCH;
     const char *zQuery = (const char *)sqlite3_value_text(apVal[0]);
 
@@ -109027,11 +111532,33 @@ static int fts3FilterMethod(
       return rc;
     }
 
-    rc = evalFts3Expr(p, pCsr->pExpr, &pCsr->aDoclist, &pCsr->nDoclist, 0);
+    rc = sqlite3Fts3ReadLock(p);
+    if( rc!=SQLITE_OK ) return rc;
+
+    rc = fts3EvalExpr(pCsr, pCsr->pExpr, &pCsr->aDoclist, &pCsr->nDoclist, 0);
+    sqlite3Fts3SegmentsClose(p);
+    if( rc!=SQLITE_OK ) return rc;
     pCsr->pNextId = pCsr->aDoclist;
     pCsr->iPrevId = 0;
   }
 
+  /* Compile a SELECT statement for this cursor. For a full-table-scan, the
+  ** statement loops through all rows of the %_content table. For a
+  ** full-text query or docid lookup, the statement retrieves a single
+  ** row by docid.
+  */
+  zSql = sqlite3_mprintf(azSql[idxNum==FTS3_FULLSCAN_SEARCH], p->zDb, p->zName);
+  if( !zSql ){
+    rc = SQLITE_NOMEM;
+  }else{
+    rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0);
+    sqlite3_free(zSql);
+  }
+  if( rc==SQLITE_OK && idxNum==FTS3_DOCID_SEARCH ){
+    rc = sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]);
+  }
+  pCsr->eSearch = (i16)idxNum;
+
   if( rc!=SQLITE_OK ) return rc;
   return fts3NextMethod(pCursor);
 }
@@ -109055,6 +111582,11 @@ static int fts3RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
   if( pCsr->aDoclist ){
     *pRowid = pCsr->iPrevId;
   }else{
+    /* This branch runs if the query is implemented using a full-table scan
+    ** (not using the full-text index). In this case grab the rowid from the
+    ** SELECT statement.
+    */
+    assert( pCsr->isRequireSeek==0 );
     *pRowid = sqlite3_column_int64(pCsr->pStmt, 0);
   }
   return SQLITE_OK;
@@ -109117,7 +111649,9 @@ static int fts3UpdateMethod(
 ** hash-table to the database.
 */
 static int fts3SyncMethod(sqlite3_vtab *pVtab){
-  return sqlite3Fts3PendingTermsFlush((Fts3Table *)pVtab);
+  int rc = sqlite3Fts3PendingTermsFlush((Fts3Table *)pVtab);
+  sqlite3Fts3SegmentsClose((Fts3Table *)pVtab);
+  return rc;
 }
 
 /*
@@ -109155,8 +111689,27 @@ static int fts3RollbackMethod(sqlite3_vtab *pVtab){
 ** This is used by the matchinfo(), snippet() and offsets() auxillary
 ** functions.
 */
-SQLITE_PRIVATE int sqlite3Fts3ExprLoadDoclist(Fts3Table *pTab, Fts3Expr *pExpr){
-  return evalFts3Expr(pTab, pExpr, &pExpr->aDoclist, &pExpr->nDoclist, 1);
+SQLITE_PRIVATE int sqlite3Fts3ExprLoadDoclist(Fts3Cursor *pCsr, Fts3Expr *pExpr){
+  int rc;
+  assert( pExpr->eType==FTSQUERY_PHRASE && pExpr->pPhrase );
+  assert( pCsr->eEvalmode==FTS3_EVAL_NEXT );
+  rc = fts3EvalExpr(pCsr, pExpr, &pExpr->aDoclist, &pExpr->nDoclist, 1);
+  return rc;
+}
+
+SQLITE_PRIVATE int sqlite3Fts3ExprLoadFtDoclist(
+  Fts3Cursor *pCsr, 
+  Fts3Expr *pExpr,
+  char **paDoclist,
+  int *pnDoclist
+){
+  int rc;
+  assert( pCsr->eEvalmode==FTS3_EVAL_NEXT );
+  assert( pExpr->eType==FTSQUERY_PHRASE && pExpr->pPhrase );
+  pCsr->eEvalmode = FTS3_EVAL_MATCHINFO;
+  rc = fts3EvalExpr(pCsr, pExpr, paDoclist, pnDoclist, 1);
+  pCsr->eEvalmode = FTS3_EVAL_NEXT;
+  return rc;
 }
 
 /*
@@ -109172,9 +111725,16 @@ SQLITE_PRIVATE char *sqlite3Fts3FindPositions(
   assert( pExpr->isLoaded );
   if( pExpr->aDoclist ){
     char *pEnd = &pExpr->aDoclist[pExpr->nDoclist];
-    char *pCsr = pExpr->pCurrent;
+    char *pCsr;
 
+    if( pExpr->pCurrent==0 ){
+      pExpr->pCurrent = pExpr->aDoclist;
+      pExpr->iCurrent = 0;
+      pExpr->pCurrent += sqlite3Fts3GetVarint(pExpr->pCurrent,&pExpr->iCurrent);
+    }
+    pCsr = pExpr->pCurrent;
     assert( pCsr );
+
     while( pCsr<pEnd ){
       if( pExpr->iCurrent<iDocid ){
         fts3PoslistCopy(0, &pCsr);
@@ -109222,7 +111782,7 @@ static int fts3FunctionArg(
   sqlite3_context *pContext,      /* SQL function call context */
   const char *zFunc,              /* Function name */
   sqlite3_value *pVal,            /* argv[0] passed to function */
-  Fts3Cursor **ppCsr         /* OUT: Store cursor handle here */
+  Fts3Cursor **ppCsr              /* OUT: Store cursor handle here */
 ){
   Fts3Cursor *pRet;
   if( sqlite3_value_type(pVal)!=SQLITE_BLOB 
@@ -109348,15 +111908,13 @@ static void fts3MatchinfoFunc(
   sqlite3_value **apVal           /* Array of arguments */
 ){
   Fts3Cursor *pCsr;               /* Cursor handle passed through apVal[0] */
-
-  if( nVal!=1 ){
-    sqlite3_result_error(pContext,
-        "wrong number of arguments to function matchinfo()", -1);
-    return;
-  }
-
+  assert( nVal==1 || nVal==2 );
   if( SQLITE_OK==fts3FunctionArg(pContext, "matchinfo", apVal[0], &pCsr) ){
-    sqlite3Fts3Matchinfo(pContext, pCsr);
+    const char *zArg = 0;
+    if( nVal>1 ){
+      zArg = (const char *)sqlite3_value_text(apVal[1]);
+    }
+    sqlite3Fts3Matchinfo(pContext, pCsr, zArg);
   }
 }
 
@@ -109405,21 +111963,25 @@ static int fts3RenameMethod(
   const char *zName               /* New name of table */
 ){
   Fts3Table *p = (Fts3Table *)pVtab;
-  sqlite3 *db;                    /* Database connection */
+  sqlite3 *db = p->db;            /* Database connection */
   int rc;                         /* Return Code */
- 
-  db = p->db;
-  rc = SQLITE_OK;
+
+  rc = sqlite3Fts3PendingTermsFlush(p);
+  if( rc!=SQLITE_OK ){
+    return rc;
+  }
+
   fts3DbExec(&rc, db,
     "ALTER TABLE %Q.'%q_content'  RENAME TO '%q_content';",
     p->zDb, p->zName, zName
   );
-  if( rc==SQLITE_ERROR ) rc = SQLITE_OK;
   if( p->bHasDocsize ){
     fts3DbExec(&rc, db,
       "ALTER TABLE %Q.'%q_docsize'  RENAME TO '%q_docsize';",
       p->zDb, p->zName, zName
     );
+  }
+  if( p->bHasStat ){
     fts3DbExec(&rc, db,
       "ALTER TABLE %Q.'%q_stat'  RENAME TO '%q_stat';",
       p->zDb, p->zName, zName
@@ -109444,7 +112006,7 @@ static const sqlite3_module fts3Module = {
   /* xDisconnect   */ fts3DisconnectMethod,
   /* xDestroy      */ fts3DestroyMethod,
   /* xOpen         */ fts3OpenMethod,
-  /* xClose        */ fulltextClose,
+  /* xClose        */ fts3CloseMethod,
   /* xFilter       */ fts3FilterMethod,
   /* xNext         */ fts3NextMethod,
   /* xEof          */ fts3EofMethod,
@@ -109471,19 +112033,20 @@ static void hashDestroy(void *p){
 }
 
 /*
-** The fts3 built-in tokenizers - "simple" and "porter" - are implemented
-** in files fts3_tokenizer1.c and fts3_porter.c respectively. The following
-** two forward declarations are for functions declared in these files
-** used to retrieve the respective implementations.
+** The fts3 built-in tokenizers - "simple", "porter" and "icu"- are 
+** implemented in files fts3_tokenizer1.c, fts3_porter.c and fts3_icu.c
+** respectively. The following three forward declarations are for functions
+** declared in these files used to retrieve the respective implementations.
 **
 ** Calling sqlite3Fts3SimpleTokenizerModule() sets the value pointed
 ** to by the argument to point to the "simple" tokenizer implementation.
-** Function ...PorterTokenizerModule() sets *pModule to point to the
-** porter tokenizer/stemmer implementation.
+** And so on.
 */
 SQLITE_PRIVATE void sqlite3Fts3SimpleTokenizerModule(sqlite3_tokenizer_module const**ppModule);
 SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule(sqlite3_tokenizer_module const**ppModule);
+#ifdef SQLITE_ENABLE_ICU
 SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(sqlite3_tokenizer_module const**ppModule);
+#endif
 
 /*
 ** Initialise the fts3 extension. If this extension is built as part
@@ -109539,7 +112102,8 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){
    && SQLITE_OK==(rc = sqlite3Fts3InitHashTable(db, pHash, "fts3_tokenizer"))
    && SQLITE_OK==(rc = sqlite3_overload_function(db, "snippet", -1))
    && SQLITE_OK==(rc = sqlite3_overload_function(db, "offsets", 1))
-   && SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", -1))
+   && SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", 1))
+   && SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", 2))
    && SQLITE_OK==(rc = sqlite3_overload_function(db, "optimize", 1))
   ){
     rc = sqlite3_create_module_v2(
@@ -109683,6 +112247,18 @@ static int fts3isspace(char c){
 }
 
 /*
+** Allocate nByte bytes of memory using sqlite3_malloc(). If successful,
+** zero the memory before returning a pointer to it. If unsuccessful, 
+** return NULL.
+*/
+static void *fts3MallocZero(int nByte){
+  void *pRet = sqlite3_malloc(nByte);
+  if( pRet ) memset(pRet, 0, nByte);
+  return pRet;
+}
+
+
+/*
 ** Extract the next token from buffer z (length n) using the tokenizer
 ** and other information (column names etc.) in pParse. Create an Fts3Expr
 ** structure of type FTSQUERY_PHRASE containing a phrase consisting of this
@@ -109719,11 +112295,10 @@ static int getNextToken(
 
     if( rc==SQLITE_OK ){
       nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase) + nToken;
-      pRet = (Fts3Expr *)sqlite3_malloc(nByte);
+      pRet = (Fts3Expr *)fts3MallocZero(nByte);
       if( !pRet ){
         rc = SQLITE_NOMEM;
       }else{
-        memset(pRet, 0, nByte);
         pRet->eType = FTSQUERY_PHRASE;
         pRet->pPhrase = (Fts3Phrase *)&pRet[1];
         pRet->pPhrase->nToken = 1;
@@ -109799,7 +112374,7 @@ static int getNextString(
       rc = pModule->xNext(pCursor, &zToken, &nToken, &iBegin, &iEnd, &iPos);
       if( rc==SQLITE_OK ){
         int nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase);
-        p = fts3ReallocOrFree(p, nByte+ii*sizeof(struct PhraseToken));
+        p = fts3ReallocOrFree(p, nByte+ii*sizeof(Fts3PhraseToken));
         zTemp = fts3ReallocOrFree(zTemp, nTemp + nToken);
         if( !p || !zTemp ){
           goto no_mem;
@@ -109809,6 +112384,7 @@ static int getNextString(
           p->pPhrase = (Fts3Phrase *)&p[1];
         }
         p->pPhrase = (Fts3Phrase *)&p[1];
+        memset(&p->pPhrase->aToken[ii], 0, sizeof(Fts3PhraseToken));
         p->pPhrase->nToken = ii+1;
         p->pPhrase->aToken[ii].n = nToken;
         memcpy(&zTemp[nTemp], zToken, nToken);
@@ -109830,7 +112406,7 @@ static int getNextString(
     char *zNew = NULL;
     int nNew = 0;
     int nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase);
-    nByte += (p?(p->pPhrase->nToken-1):0) * sizeof(struct PhraseToken);
+    nByte += (p?(p->pPhrase->nToken-1):0) * sizeof(Fts3PhraseToken);
     p = fts3ReallocOrFree(p, nByte + nTemp);
     if( !p ){
       goto no_mem;
@@ -109948,11 +112524,10 @@ static int getNextNode(
       if( fts3isspace(cNext) 
        || cNext=='"' || cNext=='(' || cNext==')' || cNext==0
       ){
-        pRet = (Fts3Expr *)sqlite3_malloc(sizeof(Fts3Expr));
+        pRet = (Fts3Expr *)fts3MallocZero(sizeof(Fts3Expr));
         if( !pRet ){
           return SQLITE_NOMEM;
         }
-        memset(pRet, 0, sizeof(Fts3Expr));
         pRet->eType = pKey->eType;
         pRet->nNear = nNear;
         *ppExpr = pRet;
@@ -109970,7 +112545,6 @@ static int getNextNode(
   if( sqlite3_fts3_enable_parentheses ){
     if( *zInput=='(' ){
       int nConsumed;
-      int rc;
       pParse->nNest++;
       rc = fts3ExprParse(pParse, &zInput[1], nInput-1, ppExpr, &nConsumed);
       if( rc==SQLITE_OK && !*ppExpr ){
@@ -110128,13 +112702,12 @@ static int fts3ExprParse(
        && p->eType==FTSQUERY_PHRASE && p->pPhrase->isNot 
       ){
         /* Create an implicit NOT operator. */
-        Fts3Expr *pNot = sqlite3_malloc(sizeof(Fts3Expr));
+        Fts3Expr *pNot = fts3MallocZero(sizeof(Fts3Expr));
         if( !pNot ){
           sqlite3Fts3ExprFree(p);
           rc = SQLITE_NOMEM;
           goto exprparse_out;
         }
-        memset(pNot, 0, sizeof(Fts3Expr));
         pNot->eType = FTSQUERY_NOT;
         pNot->pRight = p;
         if( pNotBranch ){
@@ -110162,13 +112735,12 @@ static int fts3ExprParse(
           /* Insert an implicit AND operator. */
           Fts3Expr *pAnd;
           assert( pRet && pPrev );
-          pAnd = sqlite3_malloc(sizeof(Fts3Expr));
+          pAnd = fts3MallocZero(sizeof(Fts3Expr));
           if( !pAnd ){
             sqlite3Fts3ExprFree(p);
             rc = SQLITE_NOMEM;
             goto exprparse_out;
           }
-          memset(pAnd, 0, sizeof(Fts3Expr));
           pAnd->eType = FTSQUERY_AND;
           insertBinaryOperator(&pRet, pPrev, pAnd);
           pPrev = pAnd;
@@ -110352,47 +112924,53 @@ static int queryTestTokenizer(
 }
 
 /*
-** This function is part of the test interface for the query parser. It
-** writes a text representation of the query expression pExpr into the
-** buffer pointed to by argument zBuf. It is assumed that zBuf is large 
-** enough to store the required text representation.
+** Return a pointer to a buffer containing a text representation of the
+** expression passed as the first argument. The buffer is obtained from
+** sqlite3_malloc(). It is the responsibility of the caller to use 
+** sqlite3_free() to release the memory. If an OOM condition is encountered,
+** NULL is returned.
+**
+** If the second argument is not NULL, then its contents are prepended to 
+** the returned expression text and then freed using sqlite3_free().
 */
-static void exprToString(Fts3Expr *pExpr, char *zBuf){
+static char *exprToString(Fts3Expr *pExpr, char *zBuf){
   switch( pExpr->eType ){
     case FTSQUERY_PHRASE: {
       Fts3Phrase *pPhrase = pExpr->pPhrase;
       int i;
-      zBuf += sprintf(zBuf, "PHRASE %d %d", pPhrase->iColumn, pPhrase->isNot);
-      for(i=0; i<pPhrase->nToken; i++){
-        zBuf += sprintf(zBuf," %.*s",pPhrase->aToken[i].n,pPhrase->aToken[i].z);
-        zBuf += sprintf(zBuf,"%s", (pPhrase->aToken[i].isPrefix?"+":""));
+      zBuf = sqlite3_mprintf(
+          "%zPHRASE %d %d", zBuf, pPhrase->iColumn, pPhrase->isNot);
+      for(i=0; zBuf && i<pPhrase->nToken; i++){
+        zBuf = sqlite3_mprintf("%z %.*s%s", zBuf, 
+            pPhrase->aToken[i].n, pPhrase->aToken[i].z,
+            (pPhrase->aToken[i].isPrefix?"+":"")
+        );
       }
-      return;
+      return zBuf;
     }
 
     case FTSQUERY_NEAR:
-      zBuf += sprintf(zBuf, "NEAR/%d ", pExpr->nNear);
+      zBuf = sqlite3_mprintf("%zNEAR/%d ", zBuf, pExpr->nNear);
       break;
     case FTSQUERY_NOT:
-      zBuf += sprintf(zBuf, "NOT ");
+      zBuf = sqlite3_mprintf("%zNOT ", zBuf);
       break;
     case FTSQUERY_AND:
-      zBuf += sprintf(zBuf, "AND ");
+      zBuf = sqlite3_mprintf("%zAND ", zBuf);
       break;
     case FTSQUERY_OR:
-      zBuf += sprintf(zBuf, "OR ");
+      zBuf = sqlite3_mprintf("%zOR ", zBuf);
       break;
   }
 
-  zBuf += sprintf(zBuf, "{");
-  exprToString(pExpr->pLeft, zBuf);
-  zBuf += strlen(zBuf);
-  zBuf += sprintf(zBuf, "} ");
+  if( zBuf ) zBuf = sqlite3_mprintf("%z{", zBuf);
+  if( zBuf ) zBuf = exprToString(pExpr->pLeft, zBuf);
+  if( zBuf ) zBuf = sqlite3_mprintf("%z} {", zBuf);
+
+  if( zBuf ) zBuf = exprToString(pExpr->pRight, zBuf);
+  if( zBuf ) zBuf = sqlite3_mprintf("%z}", zBuf);
 
-  zBuf += sprintf(zBuf, "{");
-  exprToString(pExpr->pRight, zBuf);
-  zBuf += strlen(zBuf);
-  zBuf += sprintf(zBuf, "}");
+  return zBuf;
 }
 
 /*
@@ -110423,6 +113001,7 @@ static void fts3ExprTest(
   int nCol;
   int ii;
   Fts3Expr *pExpr;
+  char *zBuf = 0;
   sqlite3 *db = sqlite3_context_db_handle(context);
 
   if( argc<3 ){
@@ -110465,18 +113044,17 @@ static void fts3ExprTest(
   rc = sqlite3Fts3ExprParse(
       pTokenizer, azCol, nCol, nCol, zExpr, nExpr, &pExpr
   );
-  if( rc==SQLITE_NOMEM ){
+  if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){
+    sqlite3_result_error(context, "Error parsing expression", -1);
+  }else if( rc==SQLITE_NOMEM || !(zBuf = exprToString(pExpr, 0)) ){
     sqlite3_result_error_nomem(context);
-    goto exprtest_out;
-  }else if( rc==SQLITE_OK ){
-    char zBuf[4096];
-    exprToString(pExpr, zBuf);
-    sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
-    sqlite3Fts3ExprFree(pExpr);
   }else{
-    sqlite3_result_error(context, "Error parsing expression", -1);
+    sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
+    sqlite3_free(zBuf);
   }
 
+  sqlite3Fts3ExprFree(pExpr);
+
 exprtest_out:
   if( pModule && pTokenizer ){
     rc = pModule->xDestroy(pTokenizer);
@@ -111219,7 +113797,7 @@ static void porter_stemmer(const char *zIn, int nIn, char *zOut, int *pnOut){
   int i, j;
   char zReverse[28];
   char *z, *z2;
-  if( nIn<3 || nIn>=sizeof(zReverse)-7 ){
+  if( nIn<3 || nIn>=(int)sizeof(zReverse)-7 ){
     /* The word is too big or too small for the porter stemmer.
     ** Fallback to the copy stemmer */
     copy_stemmer(zIn, nIn, zOut, pnOut);
@@ -111618,7 +114196,7 @@ static void scalarFunc(
   sqlite3_result_blob(context, (void *)&pPtr, sizeof(pPtr), SQLITE_TRANSIENT);
 }
 
-static int fts3IsIdChar(char c){
+SQLITE_PRIVATE int sqlite3Fts3IsIdChar(char c){
   static const char isFtsIdChar[] = {
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x */
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 1x */
@@ -111656,9 +114234,9 @@ SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *zStr, int *pn){
         break;
 
       default:
-        if( fts3IsIdChar(*z1) ){
+        if( sqlite3Fts3IsIdChar(*z1) ){
           z2 = &z1[1];
-          while( fts3IsIdChar(*z2) ) z2++;
+          while( sqlite3Fts3IsIdChar(*z2) ) z2++;
         }else{
           z1++;
         }
@@ -111671,9 +114249,8 @@ SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *zStr, int *pn){
 
 SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(
   Fts3Hash *pHash,                /* Tokenizer hash table */
-  const char *zArg,               /* Possible tokenizer specification */
+  const char *zArg,               /* Tokenizer name */
   sqlite3_tokenizer **ppTok,      /* OUT: Tokenizer (if applicable) */
-  const char **pzTokenizer,       /* OUT: Set to zArg if is tokenizer */
   char **pzErr                    /* OUT: Set to malloced error message */
 ){
   int rc;
@@ -111683,26 +114260,15 @@ SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(
   char *zEnd;                     /* Pointer to nul-term of zCopy */
   sqlite3_tokenizer_module *m;
 
-  if( !z ){
-    zCopy = sqlite3_mprintf("simple");
-  }else{
-    if( sqlite3_strnicmp(z, "tokenize", 8) || fts3IsIdChar(z[8])){
-      return SQLITE_OK;
-    }
-    zCopy = sqlite3_mprintf("%s", &z[8]);
-    *pzTokenizer = zArg;
-  }
-  if( !zCopy ){
-    return SQLITE_NOMEM;
-  }
-
+  zCopy = sqlite3_mprintf("%s", zArg);
+  if( !zCopy ) return SQLITE_NOMEM;
   zEnd = &zCopy[strlen(zCopy)];
 
   z = (char *)sqlite3Fts3NextToken(zCopy, &n);
   z[n] = '\0';
   sqlite3Fts3Dequote(z);
 
-  m = (sqlite3_tokenizer_module *)sqlite3Fts3HashFind(pHash, z, (int)strlen(z)+1);
+  m = (sqlite3_tokenizer_module *)sqlite3Fts3HashFind(pHash,z,(int)strlen(z)+1);
   if( !m ){
     *pzErr = sqlite3_mprintf("unknown tokenizer: %s", z);
     rc = SQLITE_ERROR;
@@ -111996,15 +114562,23 @@ SQLITE_PRIVATE int sqlite3Fts3InitHashTable(
   }
 #endif
 
-  if( SQLITE_OK!=rc
-   || SQLITE_OK!=(rc = sqlite3_create_function(db, zName, 1, any, p, scalarFunc, 0, 0))
-   || SQLITE_OK!=(rc = sqlite3_create_function(db, zName, 2, any, p, scalarFunc, 0, 0))
+  if( SQLITE_OK==rc ){
+    rc = sqlite3_create_function(db, zName, 1, any, p, scalarFunc, 0, 0);
+  }
+  if( SQLITE_OK==rc ){
+    rc = sqlite3_create_function(db, zName, 2, any, p, scalarFunc, 0, 0);
+  }
 #ifdef SQLITE_TEST
-   || SQLITE_OK!=(rc = sqlite3_create_function(db, zTest, 2, any, p, testFunc, 0, 0))
-   || SQLITE_OK!=(rc = sqlite3_create_function(db, zTest, 3, any, p, testFunc, 0, 0))
-   || SQLITE_OK!=(rc = sqlite3_create_function(db, zTest2, 0, any, pdb, intTestFunc, 0, 0))
+  if( SQLITE_OK==rc ){
+    rc = sqlite3_create_function(db, zTest, 2, any, p, testFunc, 0, 0);
+  }
+  if( SQLITE_OK==rc ){
+    rc = sqlite3_create_function(db, zTest, 3, any, p, testFunc, 0, 0);
+  }
+  if( SQLITE_OK==rc ){
+    rc = sqlite3_create_function(db, zTest2, 0, any, pdb, intTestFunc, 0, 0);
+  }
 #endif
-   );
 
 #ifdef SQLITE_TEST
   sqlite3_free(zTest);
@@ -112271,6 +114845,18 @@ SQLITE_PRIVATE void sqlite3Fts3SimpleTokenizerModule(
 #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
 
 
+/*
+** When full-text index nodes are loaded from disk, the buffer that they
+** are loaded into has the following number of bytes of padding at the end 
+** of it. i.e. if a full-text index node is 900 bytes in size, then a buffer
+** of 920 bytes is allocated for it.
+**
+** This means that if we have a pointer into a buffer containing node data,
+** it is always safe to read up to two varints from it without risking an
+** overread, even if the node data is corrupted.
+*/
+#define FTS3_NODE_PADDING (FTS3_VARINT_MAX*2)
+
 typedef struct PendingList PendingList;
 typedef struct SegmentNode SegmentNode;
 typedef struct SegmentWriter SegmentWriter;
@@ -112289,6 +114875,17 @@ struct PendingList {
   sqlite3_int64 iLastPos;
 };
 
+
+/*
+** Each cursor has a (possibly empty) linked list of the following objects.
+*/
+struct Fts3DeferredToken {
+  Fts3PhraseToken *pToken;        /* Pointer to corresponding expr token */
+  int iCol;                       /* Column token must occur in */
+  Fts3DeferredToken *pNext;       /* Next in list of deferred tokens */
+  PendingList *pList;             /* Doclist is assembled here */
+};
+
 /*
 ** An instance of this structure is used to iterate through the terms on
 ** a contiguous set of segment b-tree leaf nodes. Although the details of
@@ -112298,6 +114895,7 @@ struct PendingList {
 **
 **   sqlite3Fts3SegReaderNew()
 **   sqlite3Fts3SegReaderFree()
+**   sqlite3Fts3SegReaderCost()
 **   sqlite3Fts3SegReaderIterate()
 **
 ** Methods used to manipulate Fts3SegReader structures:
@@ -112308,12 +114906,14 @@ struct PendingList {
 */
 struct Fts3SegReader {
   int iIdx;                       /* Index within level, or 0x7FFFFFFF for PT */
-  sqlite3_int64 iStartBlock;
-  sqlite3_int64 iEndBlock;
-  sqlite3_stmt *pStmt;            /* SQL Statement to access leaf nodes */
+
+  sqlite3_int64 iStartBlock;      /* Rowid of first leaf block to traverse */
+  sqlite3_int64 iLeafEndBlock;    /* Rowid of final leaf block to traverse */
+  sqlite3_int64 iEndBlock;        /* Rowid of final block in segment (or 0) */
+  sqlite3_int64 iCurrentBlock;    /* Current leaf block (or 0) */
+
   char *aNode;                    /* Pointer to node data (or NULL) */
   int nNode;                      /* Size of buffer at aNode (or 0) */
-  int nTermAlloc;                 /* Allocated size of zTerm buffer */
   Fts3HashElem **ppNextElem;
 
   /* Variables set by fts3SegReaderNext(). These may be read directly
@@ -112323,6 +114923,7 @@ struct Fts3SegReader {
   */
   int nTerm;                      /* Number of bytes in current term */
   char *zTerm;                    /* Pointer to current term */
+  int nTermAlloc;                 /* Allocated size of zTerm buffer */
   char *aDoclist;                 /* Pointer to doclist of current entry */
   int nDoclist;                   /* Size of doclist in current entry */
 
@@ -112332,6 +114933,7 @@ struct Fts3SegReader {
 };
 
 #define fts3SegReaderIsPending(p) ((p)->ppNextElem!=0)
+#define fts3SegReaderIsRootOnly(p) ((p)->aNode==(char *)&(p)[1])
 
 /*
 ** An instance of this structure is used to create a segment b-tree in the
@@ -112400,12 +115002,11 @@ struct SegmentNode {
 #define SQL_DELETE_SEGDIR_BY_LEVEL    16
 #define SQL_DELETE_SEGMENTS_RANGE     17
 #define SQL_CONTENT_INSERT            18
-#define SQL_GET_BLOCK                 19
-#define SQL_DELETE_DOCSIZE            20
-#define SQL_REPLACE_DOCSIZE           21
-#define SQL_SELECT_DOCSIZE            22
-#define SQL_SELECT_DOCTOTAL           23
-#define SQL_REPLACE_DOCTOTAL          24
+#define SQL_DELETE_DOCSIZE            19
+#define SQL_REPLACE_DOCSIZE           20
+#define SQL_SELECT_DOCSIZE            21
+#define SQL_SELECT_DOCTOTAL           22
+#define SQL_REPLACE_DOCTOTAL          23
 
 /*
 ** This function is used to obtain an SQLite prepared statement handle
@@ -112450,12 +115051,11 @@ static int fts3SqlStmt(
 /* 16 */  "DELETE FROM %Q.'%q_segdir' WHERE level = ?",
 /* 17 */  "DELETE FROM %Q.'%q_segments' WHERE blockid BETWEEN ? AND ?",
 /* 18 */  "INSERT INTO %Q.'%q_content' VALUES(%z)",
-/* 19 */  "SELECT block FROM %Q.'%q_segments' WHERE blockid = ?",
-/* 20 */  "DELETE FROM %Q.'%q_docsize' WHERE docid = ?",
-/* 21 */  "REPLACE INTO %Q.'%q_docsize' VALUES(?,?)",
-/* 22 */  "SELECT size FROM %Q.'%q_docsize' WHERE docid=?",
-/* 23 */  "SELECT value FROM %Q.'%q_stat' WHERE id=0",
-/* 24 */  "REPLACE INTO %Q.'%q_stat' VALUES(0,?)",
+/* 19 */  "DELETE FROM %Q.'%q_docsize' WHERE docid = ?",
+/* 20 */  "REPLACE INTO %Q.'%q_docsize' VALUES(?,?)",
+/* 21 */  "SELECT size FROM %Q.'%q_docsize' WHERE docid=?",
+/* 22 */  "SELECT value FROM %Q.'%q_stat' WHERE id=0",
+/* 23 */  "REPLACE INTO %Q.'%q_stat' VALUES(0,?)",
   };
   int rc = SQLITE_OK;
   sqlite3_stmt *pStmt;
@@ -112504,6 +115104,51 @@ static int fts3SqlStmt(
   return rc;
 }
 
+static int fts3SelectDocsize(
+  Fts3Table *pTab,                /* FTS3 table handle */
+  int eStmt,                      /* Either SQL_SELECT_DOCSIZE or DOCTOTAL */
+  sqlite3_int64 iDocid,           /* Docid to bind for SQL_SELECT_DOCSIZE */
+  sqlite3_stmt **ppStmt           /* OUT: Statement handle */
+){
+  sqlite3_stmt *pStmt = 0;        /* Statement requested from fts3SqlStmt() */
+  int rc;                         /* Return code */
+
+  assert( eStmt==SQL_SELECT_DOCSIZE || eStmt==SQL_SELECT_DOCTOTAL );
+
+  rc = fts3SqlStmt(pTab, eStmt, &pStmt, 0);
+  if( rc==SQLITE_OK ){
+    if( eStmt==SQL_SELECT_DOCSIZE ){
+      sqlite3_bind_int64(pStmt, 1, iDocid);
+    }
+    rc = sqlite3_step(pStmt);
+    if( rc!=SQLITE_ROW ){
+      rc = sqlite3_reset(pStmt);
+      if( rc==SQLITE_OK ) rc = SQLITE_CORRUPT;
+      pStmt = 0;
+    }else{
+      rc = SQLITE_OK;
+    }
+  }
+
+  *ppStmt = pStmt;
+  return rc;
+}
+
+SQLITE_PRIVATE int sqlite3Fts3SelectDoctotal(
+  Fts3Table *pTab,                /* Fts3 table handle */
+  sqlite3_stmt **ppStmt           /* OUT: Statement handle */
+){
+  return fts3SelectDocsize(pTab, SQL_SELECT_DOCTOTAL, 0, ppStmt);
+}
+
+SQLITE_PRIVATE int sqlite3Fts3SelectDocsize(
+  Fts3Table *pTab,                /* Fts3 table handle */
+  sqlite3_int64 iDocid,           /* Docid to read size data for */
+  sqlite3_stmt **ppStmt           /* OUT: Statement handle */
+){
+  return fts3SelectDocsize(pTab, SQL_SELECT_DOCSIZE, iDocid, ppStmt);
+}
+
 /*
 ** Similar to fts3SqlStmt(). Except, after binding the parameters in
 ** array apVal[] to the SQL statement identified by eStmt, the statement
@@ -112531,42 +115176,33 @@ static void fts3SqlExec(
 
 
 /*
-** Read a single block from the %_segments table. If the specified block
-** does not exist, return SQLITE_CORRUPT. If some other error (malloc, IO 
-** etc.) occurs, return the appropriate SQLite error code.
+** This function ensures that the caller has obtained a shared-cache
+** table-lock on the %_content table. This is required before reading
+** data from the fts3 table. If this lock is not acquired first, then
+** the caller may end up holding read-locks on the %_segments and %_segdir
+** tables, but no read-lock on the %_content table. If this happens 
+** a second connection will be able to write to the fts3 table, but
+** attempting to commit those writes might return SQLITE_LOCKED or
+** SQLITE_LOCKED_SHAREDCACHE (because the commit attempts to obtain 
+** write-locks on the %_segments and %_segdir ** tables). 
 **
-** Otherwise, if successful, set *pzBlock to point to a buffer containing
-** the block read from the database, and *pnBlock to the size of the read
-** block in bytes.
-**
-** WARNING: The returned buffer is only valid until the next call to 
-** sqlite3Fts3ReadBlock().
+** We try to avoid this because if FTS3 returns any error when committing
+** a transaction, the whole transaction will be rolled back. And this is
+** not what users expect when they get SQLITE_LOCKED_SHAREDCACHE. It can
+** still happen if the user reads data directly from the %_segments or
+** %_segdir tables instead of going through FTS3 though.
 */
-SQLITE_PRIVATE int sqlite3Fts3ReadBlock(
-  Fts3Table *p,
-  sqlite3_int64 iBlock,
-  char const **pzBlock,
-  int *pnBlock
-){
-  sqlite3_stmt *pStmt;
-  int rc = fts3SqlStmt(p, SQL_GET_BLOCK, &pStmt, 0);
-  if( rc!=SQLITE_OK ) return rc;
-  sqlite3_reset(pStmt);
+SQLITE_PRIVATE int sqlite3Fts3ReadLock(Fts3Table *p){
+  int rc;                         /* Return code */
+  sqlite3_stmt *pStmt;            /* Statement used to obtain lock */
 
-  if( pzBlock ){
-    sqlite3_bind_int64(pStmt, 1, iBlock);
-    rc = sqlite3_step(pStmt); 
-    if( rc!=SQLITE_ROW ){
-      return (rc==SQLITE_DONE ? SQLITE_CORRUPT : rc);
-    }
-  
-    *pnBlock = sqlite3_column_bytes(pStmt, 0);
-    *pzBlock = (char *)sqlite3_column_blob(pStmt, 0);
-    if( sqlite3_column_type(pStmt, 0)!=SQLITE_BLOB ){
-      return SQLITE_CORRUPT;
-    }
+  rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pStmt, 0);
+  if( rc==SQLITE_OK ){
+    sqlite3_bind_null(pStmt, 1);
+    sqlite3_step(pStmt);
+    rc = sqlite3_reset(pStmt);
   }
-  return SQLITE_OK;
+  return rc;
 }
 
 /*
@@ -112707,10 +115343,10 @@ static int fts3PendingListAppend(
 ** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code.
 */
 static int fts3PendingTermsAdd(
-  Fts3Table *p,          /* FTS table into which text will be inserted */
-  const char *zText,     /* Text of document to be inseted */
-  int iCol,              /* Column number into which text is inserted */
-  u32 *pnWord            /* OUT: Number of tokens inserted */
+  Fts3Table *p,                   /* Table into which text will be inserted */
+  const char *zText,              /* Text of document to be inserted */
+  int iCol,                       /* Column into which text is being inserted */
+  u32 *pnWord                     /* OUT: Number of tokens inserted */
 ){
   int rc;
   int iStart;
@@ -112795,6 +115431,9 @@ static int fts3PendingTermsDocid(Fts3Table *p, sqlite_int64 iDocid){
   return SQLITE_OK;
 }
 
+/*
+** Discard the contents of the pending-terms hash table. 
+*/
 SQLITE_PRIVATE void sqlite3Fts3PendingTermsClear(Fts3Table *p){
   Fts3HashElem *pElem;
   for(pElem=fts3HashFirst(&p->pendingTerms); pElem; pElem=fts3HashNext(pElem)){
@@ -112822,6 +115461,7 @@ static int fts3InsertTerms(Fts3Table *p, sqlite3_value **apVal, u32 *aSz){
         return rc;
       }
     }
+    aSz[p->nColumn] += sqlite3_value_bytes(apVal[i]);
   }
   return SQLITE_OK;
 }
@@ -112909,6 +115549,8 @@ static int fts3DeleteAll(Fts3Table *p){
   fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGDIR, 0);
   if( p->bHasDocsize ){
     fts3SqlExec(&rc, p, SQL_DELETE_ALL_DOCSIZE, 0);
+  }
+  if( p->bHasStat ){
     fts3SqlExec(&rc, p, SQL_DELETE_ALL_STAT, 0);
   }
   return rc;
@@ -112919,7 +115561,7 @@ static int fts3DeleteAll(Fts3Table *p){
 ** (an integer) of a row about to be deleted. Remove all terms from the
 ** full-text index.
 */
-static void fts3DeleteTerms(
+static void fts3DeleteTerms( 
   int *pRC,               /* Result code */
   Fts3Table *p,           /* The FTS table to delete from */
   sqlite3_value **apVal,  /* apVal[] contains the docid to be deleted */
@@ -112941,6 +115583,7 @@ static void fts3DeleteTerms(
           *pRC = rc;
           return;
         }
+        aSz[p->nColumn] += sqlite3_column_bytes(pSelect, i);
       }
     }
     rc = sqlite3_reset(pSelect);
@@ -113004,11 +115647,92 @@ static int fts3AllocateSegdirIdx(Fts3Table *p, int iLevel, int *piIdx){
 }
 
 /*
+** The %_segments table is declared as follows:
+**
+**   CREATE TABLE %_segments(blockid INTEGER PRIMARY KEY, block BLOB)
+**
+** This function reads data from a single row of the %_segments table. The
+** specific row is identified by the iBlockid parameter. If paBlob is not
+** NULL, then a buffer is allocated using sqlite3_malloc() and populated
+** with the contents of the blob stored in the "block" column of the 
+** identified table row is. Whether or not paBlob is NULL, *pnBlob is set
+** to the size of the blob in bytes before returning.
+**
+** If an error occurs, or the table does not contain the specified row,
+** an SQLite error code is returned. Otherwise, SQLITE_OK is returned. If
+** paBlob is non-NULL, then it is the responsibility of the caller to
+** eventually free the returned buffer.
+**
+** This function may leave an open sqlite3_blob* handle in the
+** Fts3Table.pSegments variable. This handle is reused by subsequent calls
+** to this function. The handle may be closed by calling the
+** sqlite3Fts3SegmentsClose() function. Reusing a blob handle is a handy
+** performance improvement, but the blob handle should always be closed
+** before control is returned to the user (to prevent a lock being held
+** on the database file for longer than necessary). Thus, any virtual table
+** method (xFilter etc.) that may directly or indirectly call this function
+** must call sqlite3Fts3SegmentsClose() before returning.
+*/
+SQLITE_PRIVATE int sqlite3Fts3ReadBlock(
+  Fts3Table *p,                   /* FTS3 table handle */
+  sqlite3_int64 iBlockid,         /* Access the row with blockid=$iBlockid */
+  char **paBlob,                  /* OUT: Blob data in malloc'd buffer */
+  int *pnBlob                     /* OUT: Size of blob data */
+){
+  int rc;                         /* Return code */
+
+  /* pnBlob must be non-NULL. paBlob may be NULL or non-NULL. */
+  assert( pnBlob);
+
+  if( p->pSegments ){
+    rc = sqlite3_blob_reopen(p->pSegments, iBlockid);
+  }else{
+    if( 0==p->zSegmentsTbl ){
+      p->zSegmentsTbl = sqlite3_mprintf("%s_segments", p->zName);
+      if( 0==p->zSegmentsTbl ) return SQLITE_NOMEM;
+    }
+    rc = sqlite3_blob_open(
+       p->db, p->zDb, p->zSegmentsTbl, "block", iBlockid, 0, &p->pSegments
+    );
+  }
+
+  if( rc==SQLITE_OK ){
+    int nByte = sqlite3_blob_bytes(p->pSegments);
+    if( paBlob ){
+      char *aByte = sqlite3_malloc(nByte + FTS3_NODE_PADDING);
+      if( !aByte ){
+        rc = SQLITE_NOMEM;
+      }else{
+        rc = sqlite3_blob_read(p->pSegments, aByte, nByte, 0);
+        memset(&aByte[nByte], 0, FTS3_NODE_PADDING);
+        if( rc!=SQLITE_OK ){
+          sqlite3_free(aByte);
+          aByte = 0;
+        }
+      }
+      *paBlob = aByte;
+    }
+    *pnBlob = nByte;
+  }
+
+  return rc;
+}
+
+/*
+** Close the blob handle at p->pSegments, if it is open. See comments above
+** the sqlite3Fts3ReadBlock() function for details.
+*/
+SQLITE_PRIVATE void sqlite3Fts3SegmentsClose(Fts3Table *p){
+  sqlite3_blob_close(p->pSegments);
+  p->pSegments = 0;
+}
+
+/*
 ** Move the iterator passed as the first argument to the next term in the
 ** segment. If successful, SQLITE_OK is returned. If there is no next term,
 ** SQLITE_DONE. Otherwise, an SQLite error code.
 */
-static int fts3SegReaderNext(Fts3SegReader *pReader){
+static int fts3SegReaderNext(Fts3Table *p, Fts3SegReader *pReader){
   char *pNext;                    /* Cursor variable */
   int nPrefix;                    /* Number of bytes in term prefix */
   int nSuffix;                    /* Number of bytes in term suffix */
@@ -113020,7 +115744,8 @@ static int fts3SegReaderNext(Fts3SegReader *pReader){
   }
 
   if( !pNext || pNext>=&pReader->aNode[pReader->nNode] ){
-    int rc;
+    int rc;                       /* Return code from Fts3ReadBlock() */
+
     if( fts3SegReaderIsPending(pReader) ){
       Fts3HashElem *pElem = *(pReader->ppNextElem);
       if( pElem==0 ){
@@ -113036,22 +115761,36 @@ static int fts3SegReaderNext(Fts3SegReader *pReader){
       }
       return SQLITE_OK;
     }
-    if( !pReader->pStmt ){
-      pReader->aNode = 0;
-      return SQLITE_OK;
+
+    if( !fts3SegReaderIsRootOnly(pReader) ){
+      sqlite3_free(pReader->aNode);
     }
-    rc = sqlite3_step(pReader->pStmt);
-    if( rc!=SQLITE_ROW ){
-      pReader->aNode = 0;
-      return (rc==SQLITE_DONE ? SQLITE_OK : rc);
+    pReader->aNode = 0;
+
+    /* If iCurrentBlock>=iLeafEndBlock, this is an EOF condition. All leaf 
+    ** blocks have already been traversed.  */
+    assert( pReader->iCurrentBlock<=pReader->iLeafEndBlock );
+    if( pReader->iCurrentBlock>=pReader->iLeafEndBlock ){
+      return SQLITE_OK;
     }
-    pReader->nNode = sqlite3_column_bytes(pReader->pStmt, 0);
-    pReader->aNode = (char *)sqlite3_column_blob(pReader->pStmt, 0);
+
+    rc = sqlite3Fts3ReadBlock(
+        p, ++pReader->iCurrentBlock, &pReader->aNode, &pReader->nNode
+    );
+    if( rc!=SQLITE_OK ) return rc;
     pNext = pReader->aNode;
   }
   
+  /* Because of the FTS3_NODE_PADDING bytes of padding, the following is 
+  ** safe (no risk of overread) even if the node data is corrupted.  
+  */
   pNext += sqlite3Fts3GetVarint32(pNext, &nPrefix);
   pNext += sqlite3Fts3GetVarint32(pNext, &nSuffix);
+  if( nPrefix<0 || nSuffix<=0 
+   || &pNext[nSuffix]>&pReader->aNode[pReader->nNode] 
+  ){
+    return SQLITE_CORRUPT;
+  }
 
   if( nPrefix+nSuffix>pReader->nTermAlloc ){
     int nNew = (nPrefix+nSuffix)*2;
@@ -113066,9 +115805,18 @@ static int fts3SegReaderNext(Fts3SegReader *pReader){
   pReader->nTerm = nPrefix+nSuffix;
   pNext += nSuffix;
   pNext += sqlite3Fts3GetVarint32(pNext, &pReader->nDoclist);
-  assert( pNext<&pReader->aNode[pReader->nNode] );
   pReader->aDoclist = pNext;
   pReader->pOffsetList = 0;
+
+  /* Check that the doclist does not appear to extend past the end of the
+  ** b-tree node. And that the final byte of the doclist is 0x00. If either 
+  ** of these statements is untrue, then the data structure is corrupt.
+  */
+  if( &pReader->aDoclist[pReader->nDoclist]>&pReader->aNode[pReader->nNode] 
+   || pReader->aDoclist[pReader->nDoclist-1]
+  ){
+    return SQLITE_CORRUPT;
+  }
   return SQLITE_OK;
 }
 
@@ -113132,31 +115880,109 @@ static void fts3SegReaderNextDocid(
 }
 
 /*
-** Free all allocations associated with the iterator passed as the 
-** second argument.
+** This function is called to estimate the amount of data that will be 
+** loaded from the disk If SegReaderIterate() is called on this seg-reader,
+** in units of average document size.
+** 
+** This can be used as follows: If the caller has a small doclist that 
+** contains references to N documents, and is considering merging it with
+** a large doclist (size X "average documents"), it may opt not to load
+** the large doclist if X>N.
 */
-SQLITE_PRIVATE void sqlite3Fts3SegReaderFree(Fts3Table *p, Fts3SegReader *pReader){
-  if( pReader ){
-    if( pReader->pStmt ){
-      /* Move the leaf-range SELECT statement to the aLeavesStmt[] array,
-      ** so that it can be reused when required by another query.
+SQLITE_PRIVATE int sqlite3Fts3SegReaderCost(
+  Fts3Cursor *pCsr,               /* FTS3 cursor handle */
+  Fts3SegReader *pReader,         /* Segment-reader handle */
+  int *pnCost                     /* IN/OUT: Number of bytes read */
+){
+  Fts3Table *p = (Fts3Table*)pCsr->base.pVtab;
+  int rc = SQLITE_OK;             /* Return code */
+  int nCost = 0;                  /* Cost in bytes to return */
+  int pgsz = p->nPgsz;            /* Database page size */
+
+  /* If this seg-reader is reading the pending-terms table, or if all data
+  ** for the segment is stored on the root page of the b-tree, then the cost
+  ** is zero. In this case all required data is already in main memory.
+  */
+  if( p->bHasStat 
+   && !fts3SegReaderIsPending(pReader) 
+   && !fts3SegReaderIsRootOnly(pReader) 
+  ){
+    int nBlob = 0;
+    sqlite3_int64 iBlock;
+
+    if( pCsr->nRowAvg==0 ){
+      /* The average document size, which is required to calculate the cost
+      ** of each doclist, has not yet been determined. Read the required 
+      ** data from the %_stat table to calculate it.
+      **
+      ** Entry 0 of the %_stat table is a blob containing (nCol+1) FTS3 
+      ** varints, where nCol is the number of columns in the FTS3 table.
+      ** The first varint is the number of documents currently stored in
+      ** the table. The following nCol varints contain the total amount of
+      ** data stored in all rows of each column of the table, from left
+      ** to right.
       */
-      assert( p->nLeavesStmt<p->nLeavesTotal );
-      sqlite3_reset(pReader->pStmt);
-      p->aLeavesStmt[p->nLeavesStmt++] = pReader->pStmt;
+      sqlite3_stmt *pStmt;
+      sqlite3_int64 nDoc = 0;
+      sqlite3_int64 nByte = 0;
+      const char *a;
+      rc = sqlite3Fts3SelectDoctotal(p, &pStmt);
+      if( rc ) return rc;
+      a = sqlite3_column_blob(pStmt, 0);
+      if( a ){
+        const char *pEnd = &a[sqlite3_column_bytes(pStmt, 0)];
+        a += sqlite3Fts3GetVarint(a, &nDoc);
+        while( a<pEnd ){
+          a += sqlite3Fts3GetVarint(a, &nByte);
+        }
+      }
+      if( nDoc==0 || nByte==0 ){
+        sqlite3_reset(pStmt);
+        return SQLITE_CORRUPT;
+      }
+
+      pCsr->nRowAvg = (int)(((nByte / nDoc) + pgsz) / pgsz);
+      assert( pCsr->nRowAvg>0 ); 
+      rc = sqlite3_reset(pStmt);
+      if( rc!=SQLITE_OK ) return rc;
+    }
+
+    /* Assume that a blob flows over onto overflow pages if it is larger
+    ** than (pgsz-35) bytes in size (the file-format documentation
+    ** confirms this).
+    */
+    for(iBlock=pReader->iStartBlock; iBlock<=pReader->iLeafEndBlock; iBlock++){
+      rc = sqlite3Fts3ReadBlock(p, iBlock, 0, &nBlob);
+      if( rc!=SQLITE_OK ) break;
+      if( (nBlob+35)>pgsz ){
+        int nOvfl = (nBlob + 34)/pgsz;
+        nCost += ((nOvfl + pCsr->nRowAvg - 1)/pCsr->nRowAvg);
+      }
     }
-    if( !fts3SegReaderIsPending(pReader) ){
-      sqlite3_free(pReader->zTerm);
+  }
+
+  *pnCost += nCost;
+  return rc;
+}
+
+/*
+** Free all allocations associated with the iterator passed as the 
+** second argument.
+*/
+SQLITE_PRIVATE void sqlite3Fts3SegReaderFree(Fts3SegReader *pReader){
+  if( pReader && !fts3SegReaderIsPending(pReader) ){
+    sqlite3_free(pReader->zTerm);
+    if( !fts3SegReaderIsRootOnly(pReader) ){
+      sqlite3_free(pReader->aNode);
     }
-    sqlite3_free(pReader);
   }
+  sqlite3_free(pReader);
 }
 
 /*
 ** Allocate a new SegReader object.
 */
 SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(
-  Fts3Table *p,                   /* Virtual table handle */
   int iAge,                       /* Segment "age". */
   sqlite3_int64 iStartLeaf,       /* First leaf to traverse */
   sqlite3_int64 iEndLeaf,         /* Final leaf to traverse */
@@ -113169,8 +115995,9 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(
   Fts3SegReader *pReader;         /* Newly allocated SegReader object */
   int nExtra = 0;                 /* Bytes to allocate segment root node */
 
+  assert( iStartLeaf<=iEndLeaf );
   if( iStartLeaf==0 ){
-    nExtra = nRoot;
+    nExtra = nRoot + FTS3_NODE_PADDING;
   }
 
   pReader = (Fts3SegReader *)sqlite3_malloc(sizeof(Fts3SegReader) + nExtra);
@@ -113178,8 +116005,9 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(
     return SQLITE_NOMEM;
   }
   memset(pReader, 0, sizeof(Fts3SegReader));
-  pReader->iStartBlock = iStartLeaf;
   pReader->iIdx = iAge;
+  pReader->iStartBlock = iStartLeaf;
+  pReader->iLeafEndBlock = iEndLeaf;
   pReader->iEndBlock = iEndBlock;
 
   if( nExtra ){
@@ -113187,59 +116015,15 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(
     pReader->aNode = (char *)&pReader[1];
     pReader->nNode = nRoot;
     memcpy(pReader->aNode, zRoot, nRoot);
+    memset(&pReader->aNode[nRoot], 0, FTS3_NODE_PADDING);
   }else{
-    /* If the text of the SQL statement to iterate through a contiguous
-    ** set of entries in the %_segments table has not yet been composed,
-    ** compose it now.
-    */
-    if( !p->zSelectLeaves ){
-      p->zSelectLeaves = sqlite3_mprintf(
-          "SELECT block FROM %Q.'%q_segments' WHERE blockid BETWEEN ? AND ? "
-          "ORDER BY blockid", p->zDb, p->zName
-      );
-      if( !p->zSelectLeaves ){
-        rc = SQLITE_NOMEM;
-        goto finished;
-      }
-    }
-
-    /* If there are no free statements in the aLeavesStmt[] array, prepare
-    ** a new statement now. Otherwise, reuse a prepared statement from
-    ** aLeavesStmt[].
-    */
-    if( p->nLeavesStmt==0 ){
-      if( p->nLeavesTotal==p->nLeavesAlloc ){
-        int nNew = p->nLeavesAlloc + 16;
-        sqlite3_stmt **aNew = (sqlite3_stmt **)sqlite3_realloc(
-            p->aLeavesStmt, nNew*sizeof(sqlite3_stmt *)
-        );
-        if( !aNew ){
-          rc = SQLITE_NOMEM;
-          goto finished;
-        }
-        p->nLeavesAlloc = nNew;
-        p->aLeavesStmt = aNew;
-      }
-      rc = sqlite3_prepare_v2(p->db, p->zSelectLeaves, -1, &pReader->pStmt, 0);
-      if( rc!=SQLITE_OK ){
-        goto finished;
-      }
-      p->nLeavesTotal++;
-    }else{
-      pReader->pStmt = p->aLeavesStmt[--p->nLeavesStmt];
-    }
-
-    /* Bind the start and end leaf blockids to the prepared SQL statement. */
-    sqlite3_bind_int64(pReader->pStmt, 1, iStartLeaf);
-    sqlite3_bind_int64(pReader->pStmt, 2, iEndLeaf);
+    pReader->iCurrentBlock = iStartLeaf-1;
   }
-  rc = fts3SegReaderNext(pReader);
 
- finished:
   if( rc==SQLITE_OK ){
     *ppReader = pReader;
   }else{
-    sqlite3Fts3SegReaderFree(p, pReader);
+    sqlite3Fts3SegReaderFree(pReader);
   }
   return rc;
 }
@@ -113330,7 +116114,6 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderPending(
       pReader->iIdx = 0x7FFFFFFF;
       pReader->ppNextElem = (Fts3HashElem **)&pReader[1];
       memcpy(pReader->ppNextElem, aElem, nElem*sizeof(Fts3HashElem *));
-      fts3SegReaderNext(pReader);
     }
   }
 
@@ -113363,12 +116146,11 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderPending(
 ** code is returned.
 */
 static int fts3SegReaderNew(
-  Fts3Table *p,                   /* Virtual table handle */
   sqlite3_stmt *pStmt,            /* See above */
   int iAge,                       /* Segment "age". */
   Fts3SegReader **ppReader        /* OUT: Allocated Fts3SegReader */
 ){
-  return sqlite3Fts3SegReaderNew(p, iAge, 
+  return sqlite3Fts3SegReaderNew(iAge, 
       sqlite3_column_int64(pStmt, 1),
       sqlite3_column_int64(pStmt, 2),
       sqlite3_column_int64(pStmt, 3),
@@ -113572,7 +116354,7 @@ static int fts3PrefixCompress(
 ** (according to memcmp) than the previous term.
 */
 static int fts3NodeAddTerm(
-  Fts3Table *p,               /* Virtual table handle */
+  Fts3Table *p,                   /* Virtual table handle */
   SegmentNode **ppTree,           /* IN/OUT: SegmentNode handle */ 
   int isCopyTerm,                 /* True if zTerm/nTerm is transient */
   const char *zTerm,              /* Pointer to buffer containing term */
@@ -114202,15 +116984,14 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderIterate(
   ** unnecessary merge/sort operations for the case where single segment
   ** b-tree leaf nodes contain more than one term.
   */
-  if( pFilter->zTerm ){
+  for(i=0; i<nSegment; i++){
     int nTerm = pFilter->nTerm;
     const char *zTerm = pFilter->zTerm;
-    for(i=0; i<nSegment; i++){
-      Fts3SegReader *pSeg = apSegment[i];
-      while( fts3SegReaderTermCmp(pSeg, zTerm, nTerm)<0 ){
-        rc = fts3SegReaderNext(pSeg);
-        if( rc!=SQLITE_OK ) goto finished; }
-    }
+    Fts3SegReader *pSeg = apSegment[i];
+    do {
+      rc = fts3SegReaderNext(p, pSeg);
+      if( rc!=SQLITE_OK ) goto finished;
+    }while( zTerm && fts3SegReaderTermCmp(pSeg, zTerm, nTerm)<0 );
   }
 
   fts3SegReaderSort(apSegment, nSegment, nSegment, fts3SegReaderCmp);
@@ -114284,7 +117065,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderIterate(
           nByte = sqlite3Fts3VarintLen(iDocid-iPrev) + (isRequirePos?nList+1:0);
           if( nDoclist+nByte>nAlloc ){
             char *aNew;
-            nAlloc = nDoclist+nByte*2;
+            nAlloc = (nDoclist+nByte)*2;
             aNew = sqlite3_realloc(aBuffer, nAlloc);
             if( !aNew ){
               rc = SQLITE_NOMEM;
@@ -114319,7 +117100,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderIterate(
     }
 
     for(i=0; i<nMerge; i++){
-      rc = fts3SegReaderNext(apSegment[i]);
+      rc = fts3SegReaderNext(p, apSegment[i]);
       if( rc!=SQLITE_OK ) goto finished;
     }
     fts3SegReaderSort(apSegment, nSegment, nMerge, fts3SegReaderCmp);
@@ -114345,7 +117126,7 @@ static int fts3SegmentMerge(Fts3Table *p, int iLevel){
   int i;                          /* Iterator variable */
   int rc;                         /* Return code */
   int iIdx;                       /* Index of new segment */
-  int iNewLevel;                  /* Level to create new segment at */
+  int iNewLevel = 0;              /* Level to create new segment at */
   sqlite3_stmt *pStmt = 0;
   SegmentWriter *pWriter = 0;
   int nSegment = 0;               /* Number of segments being merged */
@@ -114400,7 +117181,7 @@ static int fts3SegmentMerge(Fts3Table *p, int iLevel){
   if( rc!=SQLITE_OK ) goto finished;
   sqlite3_bind_int(pStmt, 1, iLevel);
   for(i=0; SQLITE_ROW==(sqlite3_step(pStmt)); i++){
-    rc = fts3SegReaderNew(p, pStmt, i, &apSegment[i]);
+    rc = fts3SegReaderNew(pStmt, i, &apSegment[i]);
     if( rc!=SQLITE_OK ){
       goto finished;
     }
@@ -114430,11 +117211,11 @@ static int fts3SegmentMerge(Fts3Table *p, int iLevel){
   fts3SegWriterFree(pWriter);
   if( apSegment ){
     for(i=0; i<nSegment; i++){
-      sqlite3Fts3SegReaderFree(p, apSegment[i]);
+      sqlite3Fts3SegReaderFree(apSegment[i]);
     }
     sqlite3_free(apSegment);
   }
-  sqlite3Fts3SegReaderFree(p, pPending);
+  sqlite3Fts3SegReaderFree(pPending);
   sqlite3_reset(pStmt);
   return rc;
 }
@@ -114487,7 +117268,7 @@ SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *p){
     rc = fts3SegWriterFlush(p, pWriter, 0, idx);
   }
   fts3SegWriterFree(pWriter);
-  sqlite3Fts3SegReaderFree(p, pReader);
+  sqlite3Fts3SegReaderFree(pReader);
 
   if( rc==SQLITE_OK ){
     sqlite3Fts3PendingTermsClear(p);
@@ -114531,75 +117312,6 @@ static void fts3DecodeIntArray(
 }
 
 /*
-** Fill in the document size auxiliary information for the matchinfo
-** structure.  The auxiliary information is:
-**
-**    N     Total number of documents in the full-text index
-**    a0    Average length of column 0 over the whole index
-**    n0    Length of column 0 on the matching row
-**    ...
-**    aM    Average length of column M over the whole index
-**    nM    Length of column M on the matching row
-**
-** The fts3MatchinfoDocsizeLocal() routine fills in the nX values.
-** The fts3MatchinfoDocsizeGlobal() routine fills in N and the aX values.
-*/
-SQLITE_PRIVATE int sqlite3Fts3MatchinfoDocsizeLocal(Fts3Cursor *pCur, u32 *a){
-  const char *pBlob;       /* The BLOB holding %_docsize info */
-  int nBlob;               /* Size of the BLOB */
-  sqlite3_stmt *pStmt;     /* Statement for reading and writing */
-  int i, j;                /* Loop counters */
-  sqlite3_int64 x;         /* Varint value */
-  int rc;                  /* Result code from subfunctions */
-  Fts3Table *p;            /* The FTS table */
-
-  p = (Fts3Table*)pCur->base.pVtab;
-  rc = fts3SqlStmt(p, SQL_SELECT_DOCSIZE, &pStmt, 0);
-  if( rc ){
-    return rc;
-  }
-  sqlite3_bind_int64(pStmt, 1, pCur->iPrevId);
-  if( sqlite3_step(pStmt)==SQLITE_ROW ){
-    nBlob = sqlite3_column_bytes(pStmt, 0);
-    pBlob = (const char*)sqlite3_column_blob(pStmt, 0);
-    for(i=j=0; i<p->nColumn && j<nBlob; i++){
-      j = sqlite3Fts3GetVarint(&pBlob[j], &x);
-      a[2+i*2] = (u32)(x & 0xffffffff);
-    }
-  }
-  sqlite3_reset(pStmt);
-  return SQLITE_OK; 
-}
-SQLITE_PRIVATE int sqlite3Fts3MatchinfoDocsizeGlobal(Fts3Cursor *pCur, u32 *a){
-  const char *pBlob;       /* The BLOB holding %_stat info */
-  int nBlob;               /* Size of the BLOB */
-  sqlite3_stmt *pStmt;     /* Statement for reading and writing */
-  int i, j;                /* Loop counters */
-  sqlite3_int64 x;         /* Varint value */
-  int nDoc;                /* Number of documents */
-  int rc;                  /* Result code from subfunctions */
-  Fts3Table *p;            /* The FTS table */
-
-  p = (Fts3Table*)pCur->base.pVtab;
-  rc = fts3SqlStmt(p, SQL_SELECT_DOCTOTAL, &pStmt, 0);
-  if( rc ){
-    return rc;
-  }
-  if( sqlite3_step(pStmt)==SQLITE_ROW ){
-    nBlob = sqlite3_column_bytes(pStmt, 0);
-    pBlob = (const char*)sqlite3_column_blob(pStmt, 0);
-    j = sqlite3Fts3GetVarint(pBlob, &x);
-    a[0] = nDoc = (u32)(x & 0xffffffff);
-    for(i=0; i<p->nColumn && j<nBlob; i++){
-      j = sqlite3Fts3GetVarint(&pBlob[j], &x);
-      a[1+i*2] = ((u32)(x & 0xffffffff) + nDoc/2)/nDoc;
-    }
-  }
-  sqlite3_reset(pStmt);
-  return SQLITE_OK; 
-}
-
-/*
 ** Insert the sizes (in tokens) for each column of the document
 ** with docid equal to p->iPrevDocid.  The sizes are encoded as
 ** a blob of varints.
@@ -114634,16 +117346,26 @@ static void fts3InsertDocsize(
 }
 
 /*
-** Update the 0 record of the %_stat table so that it holds a blob
-** which contains the document count followed by the cumulative
-** document sizes for all columns.
+** Record 0 of the %_stat table contains a blob consisting of N varints,
+** where N is the number of user defined columns in the fts3 table plus
+** two. If nCol is the number of user defined columns, then values of the 
+** varints are set as follows:
+**
+**   Varint 0:       Total number of rows in the table.
+**
+**   Varint 1..nCol: For each column, the total number of tokens stored in
+**                   the column for all rows of the table.
+**
+**   Varint 1+nCol:  The total size, in bytes, of all text values in all
+**                   columns of all rows of the table.
+**
 */
 static void fts3UpdateDocTotals(
-  int *pRC,       /* The result code */
-  Fts3Table *p,   /* Table being updated */
-  u32 *aSzIns,    /* Size increases */
-  u32 *aSzDel,    /* Size decreases */
-  int nChng       /* Change in the number of documents */
+  int *pRC,                       /* The result code */
+  Fts3Table *p,                   /* Table being updated */
+  u32 *aSzIns,                    /* Size increases */
+  u32 *aSzDel,                    /* Size decreases */
+  int nChng                       /* Change in the number of documents */
 ){
   char *pBlob;             /* Storage for BLOB written into %_stat */
   int nBlob;               /* Size of BLOB written into %_stat */
@@ -114652,13 +117374,15 @@ static void fts3UpdateDocTotals(
   int i;                   /* Loop counter */
   int rc;                  /* Result code from subfunctions */
 
+  const int nStat = p->nColumn+2;
+
   if( *pRC ) return;
-  a = sqlite3_malloc( (sizeof(u32)+10)*(p->nColumn+1) );
+  a = sqlite3_malloc( (sizeof(u32)+10)*nStat );
   if( a==0 ){
     *pRC = SQLITE_NOMEM;
     return;
   }
-  pBlob = (char*)&a[p->nColumn+1];
+  pBlob = (char*)&a[nStat];
   rc = fts3SqlStmt(p, SQL_SELECT_DOCTOTAL, &pStmt, 0);
   if( rc ){
     sqlite3_free(a);
@@ -114666,11 +117390,11 @@ static void fts3UpdateDocTotals(
     return;
   }
   if( sqlite3_step(pStmt)==SQLITE_ROW ){
-    fts3DecodeIntArray(p->nColumn+1, a,
+    fts3DecodeIntArray(nStat, a,
          sqlite3_column_blob(pStmt, 0),
          sqlite3_column_bytes(pStmt, 0));
   }else{
-    memset(a, 0, sizeof(u32)*(p->nColumn+1) );
+    memset(a, 0, sizeof(u32)*(nStat) );
   }
   sqlite3_reset(pStmt);
   if( nChng<0 && a[0]<(u32)(-nChng) ){
@@ -114678,7 +117402,7 @@ static void fts3UpdateDocTotals(
   }else{
     a[0] += nChng;
   }
-  for(i=0; i<p->nColumn; i++){
+  for(i=0; i<p->nColumn+1; i++){
     u32 x = a[i+1];
     if( x+aSzIns[i] < aSzDel[i] ){
       x = 0;
@@ -114687,7 +117411,7 @@ static void fts3UpdateDocTotals(
     }
     a[i+1] = x;
   }
-  fts3EncodeIntArray(p->nColumn+1, a, pBlob, &nBlob);
+  fts3EncodeIntArray(nStat, a, pBlob, &nBlob);
   rc = fts3SqlStmt(p, SQL_REPLACE_DOCTOTAL, &pStmt, 0);
   if( rc ){
     sqlite3_free(a);
@@ -114734,10 +117458,160 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){
     rc = SQLITE_ERROR;
   }
 
+  sqlite3Fts3SegmentsClose(p);
   return rc;
 }
 
 /*
+** Return the deferred doclist associated with deferred token pDeferred.
+** This function assumes that sqlite3Fts3CacheDeferredDoclists() has already
+** been called to allocate and populate the doclist.
+*/
+SQLITE_PRIVATE char *sqlite3Fts3DeferredDoclist(Fts3DeferredToken *pDeferred, int *pnByte){
+  if( pDeferred->pList ){
+    *pnByte = pDeferred->pList->nData;
+    return pDeferred->pList->aData;
+  }
+  *pnByte = 0;
+  return 0;
+}
+
+/*
+** Helper fucntion for FreeDeferredDoclists(). This function removes all
+** references to deferred doclists from within the tree of Fts3Expr 
+** structures headed by 
+*/
+static void fts3DeferredDoclistClear(Fts3Expr *pExpr){
+  if( pExpr ){
+    fts3DeferredDoclistClear(pExpr->pLeft);
+    fts3DeferredDoclistClear(pExpr->pRight);
+    if( pExpr->isLoaded ){
+      sqlite3_free(pExpr->aDoclist);
+      pExpr->isLoaded = 0;
+      pExpr->aDoclist = 0;
+      pExpr->nDoclist = 0;
+      pExpr->pCurrent = 0;
+      pExpr->iCurrent = 0;
+    }
+  }
+}
+
+/*
+** Delete all cached deferred doclists. Deferred doclists are cached
+** (allocated) by the sqlite3Fts3CacheDeferredDoclists() function.
+*/
+SQLITE_PRIVATE void sqlite3Fts3FreeDeferredDoclists(Fts3Cursor *pCsr){
+  Fts3DeferredToken *pDef;
+  for(pDef=pCsr->pDeferred; pDef; pDef=pDef->pNext){
+    sqlite3_free(pDef->pList);
+    pDef->pList = 0;
+  }
+  if( pCsr->pDeferred ){
+    fts3DeferredDoclistClear(pCsr->pExpr);
+  }
+}
+
+/*
+** Free all entries in the pCsr->pDeffered list. Entries are added to 
+** this list using sqlite3Fts3DeferToken().
+*/
+SQLITE_PRIVATE void sqlite3Fts3FreeDeferredTokens(Fts3Cursor *pCsr){
+  Fts3DeferredToken *pDef;
+  Fts3DeferredToken *pNext;
+  for(pDef=pCsr->pDeferred; pDef; pDef=pNext){
+    pNext = pDef->pNext;
+    sqlite3_free(pDef->pList);
+    sqlite3_free(pDef);
+  }
+  pCsr->pDeferred = 0;
+}
+
+/*
+** Generate deferred-doclists for all tokens in the pCsr->pDeferred list
+** based on the row that pCsr currently points to.
+**
+** A deferred-doclist is like any other doclist with position information
+** included, except that it only contains entries for a single row of the
+** table, not for all rows.
+*/
+SQLITE_PRIVATE int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *pCsr){
+  int rc = SQLITE_OK;             /* Return code */
+  if( pCsr->pDeferred ){
+    int i;                        /* Used to iterate through table columns */
+    sqlite3_int64 iDocid;         /* Docid of the row pCsr points to */
+    Fts3DeferredToken *pDef;      /* Used to iterate through deferred tokens */
+  
+    Fts3Table *p = (Fts3Table *)pCsr->base.pVtab;
+    sqlite3_tokenizer *pT = p->pTokenizer;
+    sqlite3_tokenizer_module const *pModule = pT->pModule;
+   
+    assert( pCsr->isRequireSeek==0 );
+    iDocid = sqlite3_column_int64(pCsr->pStmt, 0);
+  
+    for(i=0; i<p->nColumn && rc==SQLITE_OK; i++){
+      const char *zText = (const char *)sqlite3_column_text(pCsr->pStmt, i+1);
+      sqlite3_tokenizer_cursor *pTC = 0;
+  
+      rc = pModule->xOpen(pT, zText, -1, &pTC);
+      while( rc==SQLITE_OK ){
+        char const *zToken;       /* Buffer containing token */
+        int nToken;               /* Number of bytes in token */
+        int iDum1, iDum2;         /* Dummy variables */
+        int iPos;                 /* Position of token in zText */
+  
+        pTC->pTokenizer = pT;
+        rc = pModule->xNext(pTC, &zToken, &nToken, &iDum1, &iDum2, &iPos);
+        for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){
+          Fts3PhraseToken *pPT = pDef->pToken;
+          if( (pDef->iCol>=p->nColumn || pDef->iCol==i)
+           && (pPT->n==nToken || (pPT->isPrefix && pPT->n<nToken))
+           && (0==memcmp(zToken, pPT->z, pPT->n))
+          ){
+            fts3PendingListAppend(&pDef->pList, iDocid, i, iPos, &rc);
+          }
+        }
+      }
+      if( pTC ) pModule->xClose(pTC);
+      if( rc==SQLITE_DONE ) rc = SQLITE_OK;
+    }
+  
+    for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){
+      if( pDef->pList ){
+        rc = fts3PendingListAppendVarint(&pDef->pList, 0);
+      }
+    }
+  }
+
+  return rc;
+}
+
+/*
+** Add an entry for token pToken to the pCsr->pDeferred list.
+*/
+SQLITE_PRIVATE int sqlite3Fts3DeferToken(
+  Fts3Cursor *pCsr,               /* Fts3 table cursor */
+  Fts3PhraseToken *pToken,        /* Token to defer */
+  int iCol                        /* Column that token must appear in (or -1) */
+){
+  Fts3DeferredToken *pDeferred;
+  pDeferred = sqlite3_malloc(sizeof(*pDeferred));
+  if( !pDeferred ){
+    return SQLITE_NOMEM;
+  }
+  memset(pDeferred, 0, sizeof(*pDeferred));
+  pDeferred->pToken = pToken;
+  pDeferred->pNext = pCsr->pDeferred; 
+  pDeferred->iCol = iCol;
+  pCsr->pDeferred = pDeferred;
+
+  assert( pToken->pDeferred==0 );
+  pToken->pDeferred = pDeferred;
+
+  return SQLITE_OK;
+}
+
+
+/*
 ** This function does the work for the xUpdate method of FTS3 virtual
 ** tables.
 */
@@ -114755,16 +117629,17 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
   u32 *aSzDel;                    /* Sizes of deleted documents */
   int nChng = 0;                  /* Net change in number of documents */
 
+  assert( p->pSegments==0 );
 
   /* Allocate space to hold the change in document sizes */
-  aSzIns = sqlite3_malloc( sizeof(aSzIns[0])*p->nColumn*2 );
+  aSzIns = sqlite3_malloc( sizeof(aSzIns[0])*(p->nColumn+1)*2 );
   if( aSzIns==0 ) return SQLITE_NOMEM;
-  aSzDel = &aSzIns[p->nColumn];
-  memset(aSzIns, 0, sizeof(aSzIns[0])*p->nColumn*2);
+  aSzDel = &aSzIns[p->nColumn+1];
+  memset(aSzIns, 0, sizeof(aSzIns[0])*(p->nColumn+1)*2);
 
   /* If this is a DELETE or UPDATE operation, remove the old record. */
   if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){
-    int isEmpty;
+    int isEmpty = 0;
     rc = fts3IsEmpty(p, apVal, &isEmpty);
     if( rc==SQLITE_OK ){
       if( isEmpty ){
@@ -114781,8 +117656,8 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
         fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, apVal);
         if( p->bHasDocsize ){
           fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, apVal);
-          nChng--;
         }
+        nChng--;
       }
     }
   }else if( sqlite3_value_type(apVal[p->nColumn+2])!=SQLITE_NULL ){
@@ -114800,16 +117675,17 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
       rc = fts3InsertTerms(p, apVal, aSzIns);
     }
     if( p->bHasDocsize ){
-      nChng++;
       fts3InsertDocsize(&rc, p, aSzIns);
     }
+    nChng++;
   }
 
-  if( p->bHasDocsize ){
+  if( p->bHasStat ){
     fts3UpdateDocTotals(&rc, p, aSzIns, aSzDel, nChng);
   }
 
   sqlite3_free(aSzIns);
+  sqlite3Fts3SegmentsClose(p);
   return rc;
 }
 
@@ -114833,6 +117709,7 @@ SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *p){
       sqlite3_exec(p->db, "RELEASE fts3", 0, 0, 0);
     }
   }
+  sqlite3Fts3SegmentsClose(p);
   return rc;
 }
 
@@ -114856,6 +117733,22 @@ SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *p){
 #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
 
 
+/*
+** Characters that may appear in the second argument to matchinfo().
+*/
+#define FTS3_MATCHINFO_NPHRASE   'p'        /* 1 value */
+#define FTS3_MATCHINFO_NCOL      'c'        /* 1 value */
+#define FTS3_MATCHINFO_NDOC      'n'        /* 1 value */
+#define FTS3_MATCHINFO_AVGLENGTH 'a'        /* nCol values */
+#define FTS3_MATCHINFO_LENGTH    'l'        /* nCol values */
+#define FTS3_MATCHINFO_LCS       's'        /* nCol values */
+#define FTS3_MATCHINFO_HITS      'x'        /* 3*nCol*nPhrase values */
+
+/*
+** The default value for the second argument to matchinfo(). 
+*/
+#define FTS3_MATCHINFO_DEFAULT   "pcx"
+
 
 /*
 ** Used as an fts3ExprIterate() context when loading phrase doclists to
@@ -114863,7 +117756,7 @@ SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *p){
 */
 typedef struct LoadDoclistCtx LoadDoclistCtx;
 struct LoadDoclistCtx {
-  Fts3Table *pTab;                /* FTS3 Table */
+  Fts3Cursor *pCsr;               /* FTS3 Cursor */
   int nPhrase;                    /* Number of phrases seen so far */
   int nToken;                     /* Number of tokens seen so far */
 };
@@ -114909,6 +117802,8 @@ typedef struct MatchInfo MatchInfo;
 struct MatchInfo {
   Fts3Cursor *pCursor;            /* FTS3 Cursor */
   int nCol;                       /* Number of columns in table */
+  int nPhrase;                    /* Number of matchable phrases in query */
+  sqlite3_int64 nDoc;             /* Number of docs in database */
   u32 *aMatchinfo;                /* Pre-allocated buffer */
 };
 
@@ -115047,7 +117942,7 @@ static int fts3ExprNearTrim(Fts3Expr *pExpr){
 ** for each phrase into Fts3Expr.aDoclist[]/nDoclist. See also
 ** fts3ExprLoadDoclists().
 */
-static int fts3ExprLoadDoclistsCb1(Fts3Expr *pExpr, int iPhrase, void *ctx){
+static int fts3ExprLoadDoclistsCb(Fts3Expr *pExpr, int iPhrase, void *ctx){
   int rc = SQLITE_OK;
   LoadDoclistCtx *p = (LoadDoclistCtx *)ctx;
 
@@ -115057,7 +117952,7 @@ static int fts3ExprLoadDoclistsCb1(Fts3Expr *pExpr, int iPhrase, void *ctx){
   p->nToken += pExpr->pPhrase->nToken;
 
   if( pExpr->isLoaded==0 ){
-    rc = sqlite3Fts3ExprLoadDoclist(p->pTab, pExpr);
+    rc = sqlite3Fts3ExprLoadDoclist(p->pCsr, pExpr);
     pExpr->isLoaded = 1;
     if( rc==SQLITE_OK ){
       rc = fts3ExprNearTrim(pExpr);
@@ -115068,22 +117963,6 @@ static int fts3ExprLoadDoclistsCb1(Fts3Expr *pExpr, int iPhrase, void *ctx){
 }
 
 /*
-** This is an fts3ExprIterate() callback used while loading the doclists
-** for each phrase into Fts3Expr.aDoclist[]/nDoclist. See also
-** fts3ExprLoadDoclists().
-*/
-static int fts3ExprLoadDoclistsCb2(Fts3Expr *pExpr, int iPhrase, void *ctx){
-  UNUSED_PARAMETER(iPhrase);
-  UNUSED_PARAMETER(ctx);
-  if( pExpr->aDoclist ){
-    pExpr->pCurrent = pExpr->aDoclist;
-    pExpr->iCurrent = 0;
-    pExpr->pCurrent += sqlite3Fts3GetVarint(pExpr->pCurrent, &pExpr->iCurrent);
-  }
-  return SQLITE_OK;
-}
-
-/*
 ** Load the doclists for each phrase in the query associated with FTS3 cursor
 ** pCsr. 
 **
@@ -115100,16 +117979,25 @@ static int fts3ExprLoadDoclists(
 ){
   int rc;                         /* Return Code */
   LoadDoclistCtx sCtx = {0,0,0};  /* Context for fts3ExprIterate() */
-  sCtx.pTab = (Fts3Table *)pCsr->base.pVtab;
-  rc = fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb1, (void *)&sCtx);
-  if( rc==SQLITE_OK ){
-    (void)fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb2, 0);
-  }
+  sCtx.pCsr = pCsr;
+  rc = fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb, (void *)&sCtx);
   if( pnPhrase ) *pnPhrase = sCtx.nPhrase;
   if( pnToken ) *pnToken = sCtx.nToken;
   return rc;
 }
 
+static int fts3ExprPhraseCountCb(Fts3Expr *pExpr, int iPhrase, void *ctx){
+  (*(int *)ctx)++;
+  UNUSED_PARAMETER(pExpr);
+  UNUSED_PARAMETER(iPhrase);
+  return SQLITE_OK;
+}
+static int fts3ExprPhraseCount(Fts3Expr *pExpr){
+  int nPhrase = 0;
+  (void)fts3ExprIterate(pExpr, fts3ExprPhraseCountCb, (void *)&nPhrase);
+  return nPhrase;
+}
+
 /*
 ** Advance the position list iterator specified by the first two 
 ** arguments so that it points to the first element with a value greater
@@ -115622,38 +118510,87 @@ static void fts3LoadColumnlistCounts(char **pp, u32 *aOut, int isGlobal){
 
 /*
 ** fts3ExprIterate() callback used to collect the "global" matchinfo stats
-** for a single query. The "global" stats are those elements of the matchinfo
-** array that are constant for all rows returned by the current query.
+** for a single query. 
+**
+** fts3ExprIterate() callback to load the 'global' elements of a
+** FTS3_MATCHINFO_HITS matchinfo array. The global stats are those elements 
+** of the matchinfo array that are constant for all rows returned by the 
+** current query.
+**
+** Argument pCtx is actually a pointer to a struct of type MatchInfo. This
+** function populates Matchinfo.aMatchinfo[] as follows:
+**
+**   for(iCol=0; iCol<nCol; iCol++){
+**     aMatchinfo[3*iPhrase*nCol + 3*iCol + 1] = X;
+**     aMatchinfo[3*iPhrase*nCol + 3*iCol + 2] = Y;
+**   }
+**
+** where X is the number of matches for phrase iPhrase is column iCol of all
+** rows of the table. Y is the number of rows for which column iCol contains
+** at least one instance of phrase iPhrase.
+**
+** If the phrase pExpr consists entirely of deferred tokens, then all X and
+** Y values are set to nDoc, where nDoc is the number of documents in the 
+** file system. This is done because the full-text index doclist is required
+** to calculate these values properly, and the full-text index doclist is
+** not available for deferred tokens.
 */
-static int fts3ExprGlobalMatchinfoCb(
+static int fts3ExprGlobalHitsCb(
   Fts3Expr *pExpr,                /* Phrase expression node */
   int iPhrase,                    /* Phrase number (numbered from zero) */
   void *pCtx                      /* Pointer to MatchInfo structure */
 ){
   MatchInfo *p = (MatchInfo *)pCtx;
-  char *pCsr;
+  Fts3Cursor *pCsr = p->pCursor;
+  char *pIter;
   char *pEnd;
-  const int iStart = 2 + (iPhrase * p->nCol * 3) + 1;
+  char *pFree = 0;
+  u32 *aOut = &p->aMatchinfo[3*iPhrase*p->nCol];
 
   assert( pExpr->isLoaded );
+  assert( pExpr->eType==FTSQUERY_PHRASE );
+
+  if( pCsr->pDeferred ){
+    Fts3Phrase *pPhrase = pExpr->pPhrase;
+    int ii;
+    for(ii=0; ii<pPhrase->nToken; ii++){
+      if( pPhrase->aToken[ii].bFulltext ) break;
+    }
+    if( ii<pPhrase->nToken ){
+      int nFree = 0;
+      int rc = sqlite3Fts3ExprLoadFtDoclist(pCsr, pExpr, &pFree, &nFree);
+      if( rc!=SQLITE_OK ) return rc;
+      pIter = pFree;
+      pEnd = &pFree[nFree];
+    }else{
+      int iCol;                   /* Column index */
+      for(iCol=0; iCol<p->nCol; iCol++){
+        aOut[iCol*3 + 1] = (u32)p->nDoc;
+        aOut[iCol*3 + 2] = (u32)p->nDoc;
+      }
+      return SQLITE_OK;
+    }
+  }else{
+    pIter = pExpr->aDoclist;
+    pEnd = &pExpr->aDoclist[pExpr->nDoclist];
+  }
 
   /* Fill in the global hit count matrix row for this phrase. */
-  pCsr = pExpr->aDoclist;
-  pEnd = &pExpr->aDoclist[pExpr->nDoclist];
-  while( pCsr<pEnd ){
-    while( *pCsr++ & 0x80 );      /* Skip past docid. */
-    fts3LoadColumnlistCounts(&pCsr, &p->aMatchinfo[iStart], 1);
+  while( pIter<pEnd ){
+    while( *pIter++ & 0x80 );      /* Skip past docid. */
+    fts3LoadColumnlistCounts(&pIter, &aOut[1], 1);
   }
 
+  sqlite3_free(pFree);
   return SQLITE_OK;
 }
 
 /*
-** fts3ExprIterate() callback used to collect the "local" matchinfo stats
-** for a single query. The "local" stats are those elements of the matchinfo
+** fts3ExprIterate() callback used to collect the "local" part of the
+** FTS3_MATCHINFO_HITS array. The local stats are those elements of the 
 ** array that are different for each row returned by the query.
 */
-static int fts3ExprLocalMatchinfoCb(
+static int fts3ExprLocalHitsCb(
   Fts3Expr *pExpr,                /* Phrase expression node */
   int iPhrase,                    /* Phrase number */
   void *pCtx                      /* Pointer to MatchInfo structure */
@@ -115662,7 +118599,7 @@ static int fts3ExprLocalMatchinfoCb(
 
   if( pExpr->aDoclist ){
     char *pCsr;
-    int iStart = 2 + (iPhrase * p->nCol * 3);
+    int iStart = iPhrase * p->nCol * 3;
     int i;
 
     for(i=0; i<p->nCol; i++) p->aMatchinfo[iStart+i*3] = 0;
@@ -115676,67 +118613,400 @@ static int fts3ExprLocalMatchinfoCb(
   return SQLITE_OK;
 }
 
+static int fts3MatchinfoCheck(
+  Fts3Table *pTab, 
+  char cArg,
+  char **pzErr
+){
+  if( (cArg==FTS3_MATCHINFO_NPHRASE)
+   || (cArg==FTS3_MATCHINFO_NCOL)
+   || (cArg==FTS3_MATCHINFO_NDOC && pTab->bHasStat)
+   || (cArg==FTS3_MATCHINFO_AVGLENGTH && pTab->bHasStat)
+   || (cArg==FTS3_MATCHINFO_LENGTH && pTab->bHasDocsize)
+   || (cArg==FTS3_MATCHINFO_LCS)
+   || (cArg==FTS3_MATCHINFO_HITS)
+  ){
+    return SQLITE_OK;
+  }
+  *pzErr = sqlite3_mprintf("unrecognized matchinfo request: %c", cArg);
+  return SQLITE_ERROR;
+}
+
+static int fts3MatchinfoSize(MatchInfo *pInfo, char cArg){
+  int nVal;                       /* Number of integers output by cArg */
+
+  switch( cArg ){
+    case FTS3_MATCHINFO_NDOC:
+    case FTS3_MATCHINFO_NPHRASE: 
+    case FTS3_MATCHINFO_NCOL: 
+      nVal = 1;
+      break;
+
+    case FTS3_MATCHINFO_AVGLENGTH:
+    case FTS3_MATCHINFO_LENGTH:
+    case FTS3_MATCHINFO_LCS:
+      nVal = pInfo->nCol;
+      break;
+
+    default:
+      assert( cArg==FTS3_MATCHINFO_HITS );
+      nVal = pInfo->nCol * pInfo->nPhrase * 3;
+      break;
+  }
+
+  return nVal;
+}
+
+static int fts3MatchinfoSelectDoctotal(
+  Fts3Table *pTab,
+  sqlite3_stmt **ppStmt,
+  sqlite3_int64 *pnDoc,
+  const char **paLen
+){
+  sqlite3_stmt *pStmt;
+  const char *a;
+  sqlite3_int64 nDoc;
+
+  if( !*ppStmt ){
+    int rc = sqlite3Fts3SelectDoctotal(pTab, ppStmt);
+    if( rc!=SQLITE_OK ) return rc;
+  }
+  pStmt = *ppStmt;
+  assert( sqlite3_data_count(pStmt)==1 );
+
+  a = sqlite3_column_blob(pStmt, 0);
+  a += sqlite3Fts3GetVarint(a, &nDoc);
+  *pnDoc = (u32)nDoc;
+
+  if( paLen ) *paLen = a;
+  return SQLITE_OK;
+}
+
+/*
+** An instance of the following structure is used to store state while 
+** iterating through a multi-column position-list corresponding to the
+** hits for a single phrase on a single row in order to calculate the
+** values for a matchinfo() FTS3_MATCHINFO_LCS request.
+*/
+typedef struct LcsIterator LcsIterator;
+struct LcsIterator {
+  Fts3Expr *pExpr;                /* Pointer to phrase expression */
+  char *pRead;                    /* Cursor used to iterate through aDoclist */
+  int iPosOffset;                 /* Tokens count up to end of this phrase */
+  int iCol;                       /* Current column number */
+  int iPos;                       /* Current position */
+};
+
+/* 
+** If LcsIterator.iCol is set to the following value, the iterator has
+** finished iterating through all offsets for all columns.
+*/
+#define LCS_ITERATOR_FINISHED 0x7FFFFFFF;
+
+static int fts3MatchinfoLcsCb(
+  Fts3Expr *pExpr,                /* Phrase expression node */
+  int iPhrase,                    /* Phrase number (numbered from zero) */
+  void *pCtx                      /* Pointer to MatchInfo structure */
+){
+  LcsIterator *aIter = (LcsIterator *)pCtx;
+  aIter[iPhrase].pExpr = pExpr;
+  return SQLITE_OK;
+}
+
+/*
+** Advance the iterator passed as an argument to the next position. Return
+** 1 if the iterator is at EOF or if it now points to the start of the
+** position list for the next column.
+*/
+static int fts3LcsIteratorAdvance(LcsIterator *pIter){
+  char *pRead = pIter->pRead;
+  sqlite3_int64 iRead;
+  int rc = 0;
+
+  pRead += sqlite3Fts3GetVarint(pRead, &iRead);
+  if( iRead==0 ){
+    pIter->iCol = LCS_ITERATOR_FINISHED;
+    rc = 1;
+  }else{
+    if( iRead==1 ){
+      pRead += sqlite3Fts3GetVarint(pRead, &iRead);
+      pIter->iCol = (int)iRead;
+      pIter->iPos = pIter->iPosOffset;
+      pRead += sqlite3Fts3GetVarint(pRead, &iRead);
+      rc = 1;
+    }
+    pIter->iPos += (int)(iRead-2);
+  }
+
+  pIter->pRead = pRead;
+  return rc;
+}
+  
+/*
+** This function implements the FTS3_MATCHINFO_LCS matchinfo() flag. 
+**
+** If the call is successful, the longest-common-substring lengths for each
+** column are written into the first nCol elements of the pInfo->aMatchinfo[] 
+** array before returning. SQLITE_OK is returned in this case.
+**
+** Otherwise, if an error occurs, an SQLite error code is returned and the
+** data written to the first nCol elements of pInfo->aMatchinfo[] is 
+** undefined.
+*/
+static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){
+  LcsIterator *aIter;
+  int i;
+  int iCol;
+  int nToken = 0;
+
+  /* Allocate and populate the array of LcsIterator objects. The array
+  ** contains one element for each matchable phrase in the query.
+  **/
+  aIter = sqlite3_malloc(sizeof(LcsIterator) * pCsr->nPhrase);
+  if( !aIter ) return SQLITE_NOMEM;
+  memset(aIter, 0, sizeof(LcsIterator) * pCsr->nPhrase);
+  (void)fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter);
+  for(i=0; i<pInfo->nPhrase; i++){
+    LcsIterator *pIter = &aIter[i];
+    nToken -= pIter->pExpr->pPhrase->nToken;
+    pIter->iPosOffset = nToken;
+    pIter->pRead = sqlite3Fts3FindPositions(pIter->pExpr, pCsr->iPrevId, -1);
+    if( pIter->pRead ){
+      pIter->iPos = pIter->iPosOffset;
+      fts3LcsIteratorAdvance(&aIter[i]);
+    }else{
+      pIter->iCol = LCS_ITERATOR_FINISHED;
+    }
+  }
+
+  for(iCol=0; iCol<pInfo->nCol; iCol++){
+    int nLcs = 0;                 /* LCS value for this column */
+    int nLive = 0;                /* Number of iterators in aIter not at EOF */
+
+    /* Loop through the iterators in aIter[]. Set nLive to the number of
+    ** iterators that point to a position-list corresponding to column iCol.
+    */
+    for(i=0; i<pInfo->nPhrase; i++){
+      assert( aIter[i].iCol>=iCol );
+      if( aIter[i].iCol==iCol ) nLive++;
+    }
+
+    /* The following loop runs until all iterators in aIter[] have finished
+    ** iterating through positions in column iCol. Exactly one of the 
+    ** iterators is advanced each time the body of the loop is run.
+    */
+    while( nLive>0 ){
+      LcsIterator *pAdv = 0;      /* The iterator to advance by one position */
+      int nThisLcs = 0;           /* LCS for the current iterator positions */
+
+      for(i=0; i<pInfo->nPhrase; i++){
+        LcsIterator *pIter = &aIter[i];
+        if( iCol!=pIter->iCol ){  
+          /* This iterator is already at EOF for this column. */
+          nThisLcs = 0;
+        }else{
+          if( pAdv==0 || pIter->iPos<pAdv->iPos ){
+            pAdv = pIter;
+          }
+          if( nThisLcs==0 || pIter->iPos==pIter[-1].iPos ){
+            nThisLcs++;
+          }else{
+            nThisLcs = 1;
+          }
+          if( nThisLcs>nLcs ) nLcs = nThisLcs;
+        }
+      }
+      if( fts3LcsIteratorAdvance(pAdv) ) nLive--;
+    }
+
+    pInfo->aMatchinfo[iCol] = nLcs;
+  }
+
+  sqlite3_free(aIter);
+  return SQLITE_OK;
+}
+
+/*
+** Populate the buffer pInfo->aMatchinfo[] with an array of integers to
+** be returned by the matchinfo() function. Argument zArg contains the 
+** format string passed as the second argument to matchinfo (or the
+** default value "pcx" if no second argument was specified). The format
+** string has already been validated and the pInfo->aMatchinfo[] array
+** is guaranteed to be large enough for the output.
+**
+** If bGlobal is true, then populate all fields of the matchinfo() output.
+** If it is false, then assume that those fields that do not change between
+** rows (i.e. FTS3_MATCHINFO_NPHRASE, NCOL, NDOC, AVGLENGTH and part of HITS)
+** have already been populated.
+**
+** Return SQLITE_OK if successful, or an SQLite error code if an error 
+** occurs. If a value other than SQLITE_OK is returned, the state the
+** pInfo->aMatchinfo[] buffer is left in is undefined.
+*/
+static int fts3MatchinfoValues(
+  Fts3Cursor *pCsr,               /* FTS3 cursor object */
+  int bGlobal,                    /* True to grab the global stats */
+  MatchInfo *pInfo,               /* Matchinfo context object */
+  const char *zArg                /* Matchinfo format string */
+){
+  int rc = SQLITE_OK;
+  int i;
+  Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
+  sqlite3_stmt *pSelect = 0;
+
+  for(i=0; rc==SQLITE_OK && zArg[i]; i++){
+
+    switch( zArg[i] ){
+      case FTS3_MATCHINFO_NPHRASE:
+        if( bGlobal ) pInfo->aMatchinfo[0] = pInfo->nPhrase;
+        break;
+
+      case FTS3_MATCHINFO_NCOL:
+        if( bGlobal ) pInfo->aMatchinfo[0] = pInfo->nCol;
+        break;
+        
+      case FTS3_MATCHINFO_NDOC:
+        if( bGlobal ){
+          sqlite3_int64 nDoc;
+          rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, 0);
+          pInfo->aMatchinfo[0] = (u32)nDoc;
+        }
+        break;
+
+      case FTS3_MATCHINFO_AVGLENGTH: 
+        if( bGlobal ){
+          sqlite3_int64 nDoc;     /* Number of rows in table */
+          const char *a;          /* Aggregate column length array */
+
+          rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, &a);
+          if( rc==SQLITE_OK ){
+            int iCol;
+            for(iCol=0; iCol<pInfo->nCol; iCol++){
+              sqlite3_int64 nToken;
+              a += sqlite3Fts3GetVarint(a, &nToken);
+              pInfo->aMatchinfo[iCol] = (u32)(((u32)(nToken&0xffffffff)+nDoc/2)/nDoc);
+            }
+          }
+        }
+        break;
+
+      case FTS3_MATCHINFO_LENGTH: {
+        sqlite3_stmt *pSelectDocsize = 0;
+        rc = sqlite3Fts3SelectDocsize(pTab, pCsr->iPrevId, &pSelectDocsize);
+        if( rc==SQLITE_OK ){
+          int iCol;
+          const char *a = sqlite3_column_blob(pSelectDocsize, 0);
+          for(iCol=0; iCol<pInfo->nCol; iCol++){
+            sqlite3_int64 nToken;
+            a += sqlite3Fts3GetVarint(a, &nToken);
+            pInfo->aMatchinfo[iCol] = (u32)nToken;
+          }
+        }
+        sqlite3_reset(pSelectDocsize);
+        break;
+      }
+
+      case FTS3_MATCHINFO_LCS:
+        rc = fts3ExprLoadDoclists(pCsr, 0, 0);
+        if( rc==SQLITE_OK ){
+          rc = fts3MatchinfoLcs(pCsr, pInfo);
+        }
+        break;
+
+      default: {
+        Fts3Expr *pExpr;
+        assert( zArg[i]==FTS3_MATCHINFO_HITS );
+        pExpr = pCsr->pExpr;
+        rc = fts3ExprLoadDoclists(pCsr, 0, 0);
+        if( rc!=SQLITE_OK ) break;
+        if( bGlobal ){
+          if( pCsr->pDeferred ){
+            rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &pInfo->nDoc, 0);
+            if( rc!=SQLITE_OK ) break;
+          }
+          rc = fts3ExprIterate(pExpr, fts3ExprGlobalHitsCb,(void*)pInfo);
+          if( rc!=SQLITE_OK ) break;
+        }
+        (void)fts3ExprIterate(pExpr, fts3ExprLocalHitsCb,(void*)pInfo);
+        break;
+      }
+    }
+
+    pInfo->aMatchinfo += fts3MatchinfoSize(pInfo, zArg[i]);
+  }
+
+  sqlite3_reset(pSelect);
+  return rc;
+}
+
+
 /*
 ** Populate pCsr->aMatchinfo[] with data for the current row. The 
 ** 'matchinfo' data is an array of 32-bit unsigned integers (C type u32).
 */
-static int fts3GetMatchinfo(Fts3Cursor *pCsr){
+static int fts3GetMatchinfo(
+  Fts3Cursor *pCsr,               /* FTS3 Cursor object */
+  const char *zArg                /* Second argument to matchinfo() function */
+){
   MatchInfo sInfo;
   Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
   int rc = SQLITE_OK;
+  int bGlobal = 0;                /* Collect 'global' stats as well as local */
 
+  memset(&sInfo, 0, sizeof(MatchInfo));
   sInfo.pCursor = pCsr;
   sInfo.nCol = pTab->nColumn;
 
+  /* If there is cached matchinfo() data, but the format string for the 
+  ** cache does not match the format string for this request, discard 
+  ** the cached data. */
+  if( pCsr->zMatchinfo && strcmp(pCsr->zMatchinfo, zArg) ){
+    assert( pCsr->aMatchinfo );
+    sqlite3_free(pCsr->aMatchinfo);
+    pCsr->zMatchinfo = 0;
+    pCsr->aMatchinfo = 0;
+  }
+
+  /* If Fts3Cursor.aMatchinfo[] is NULL, then this is the first time the
+  ** matchinfo function has been called for this query. In this case 
+  ** allocate the array used to accumulate the matchinfo data and
+  ** initialize those elements that are constant for every row.
+  */
   if( pCsr->aMatchinfo==0 ){
-    /* If Fts3Cursor.aMatchinfo[] is NULL, then this is the first time the
-    ** matchinfo function has been called for this query. In this case 
-    ** allocate the array used to accumulate the matchinfo data and
-    ** initialize those elements that are constant for every row.
-    */
-    int nPhrase;                  /* Number of phrases */
-    int nMatchinfo;               /* Number of u32 elements in match-info */
+    int nMatchinfo = 0;           /* Number of u32 elements in match-info */
+    int nArg;                     /* Bytes in zArg */
+    int i;                        /* Used to iterate through zArg */
 
-    /* Load doclists for each phrase in the query. */
-    rc = fts3ExprLoadDoclists(pCsr, &nPhrase, 0);
-    if( rc!=SQLITE_OK ){
-      return rc;
-    }
-    nMatchinfo = 2 + 3*sInfo.nCol*nPhrase;
-    if( pTab->bHasDocsize ){
-      nMatchinfo += 1 + 2*pTab->nColumn;
-    }
+    /* Determine the number of phrases in the query */
+    pCsr->nPhrase = fts3ExprPhraseCount(pCsr->pExpr);
+    sInfo.nPhrase = pCsr->nPhrase;
 
-    sInfo.aMatchinfo = (u32 *)sqlite3_malloc(sizeof(u32)*nMatchinfo);
-    if( !sInfo.aMatchinfo ){ 
-      return SQLITE_NOMEM;
+    /* Determine the number of integers in the buffer returned by this call. */
+    for(i=0; zArg[i]; i++){
+      nMatchinfo += fts3MatchinfoSize(&sInfo, zArg[i]);
     }
-    memset(sInfo.aMatchinfo, 0, sizeof(u32)*nMatchinfo);
 
+    /* Allocate space for Fts3Cursor.aMatchinfo[] and Fts3Cursor.zMatchinfo. */
+    nArg = (int)strlen(zArg);
+    pCsr->aMatchinfo = (u32 *)sqlite3_malloc(sizeof(u32)*nMatchinfo + nArg + 1);
+    if( !pCsr->aMatchinfo ) return SQLITE_NOMEM;
 
-    /* First element of match-info is the number of phrases in the query */
-    sInfo.aMatchinfo[0] = nPhrase;
-    sInfo.aMatchinfo[1] = sInfo.nCol;
-    (void)fts3ExprIterate(pCsr->pExpr, fts3ExprGlobalMatchinfoCb,(void*)&sInfo);
-    if( pTab->bHasDocsize ){
-      int ofst = 2 + 3*sInfo.aMatchinfo[0]*sInfo.aMatchinfo[1];
-      rc = sqlite3Fts3MatchinfoDocsizeGlobal(pCsr, &sInfo.aMatchinfo[ofst]);
-    }
-    pCsr->aMatchinfo = sInfo.aMatchinfo;
+    pCsr->zMatchinfo = (char *)&pCsr->aMatchinfo[nMatchinfo];
+    pCsr->nMatchinfo = nMatchinfo;
+    memcpy(pCsr->zMatchinfo, zArg, nArg+1);
+    memset(pCsr->aMatchinfo, 0, sizeof(u32)*nMatchinfo);
     pCsr->isMatchinfoNeeded = 1;
+    bGlobal = 1;
   }
 
   sInfo.aMatchinfo = pCsr->aMatchinfo;
-  if( rc==SQLITE_OK && pCsr->isMatchinfoNeeded ){
-    (void)fts3ExprIterate(pCsr->pExpr, fts3ExprLocalMatchinfoCb, (void*)&sInfo);
-    if( pTab->bHasDocsize ){
-      int ofst = 2 + 3*sInfo.aMatchinfo[0]*sInfo.aMatchinfo[1];
-      rc = sqlite3Fts3MatchinfoDocsizeLocal(pCsr, &sInfo.aMatchinfo[ofst]);
-    }
+  sInfo.nPhrase = pCsr->nPhrase;
+  if( pCsr->isMatchinfoNeeded ){
+    rc = fts3MatchinfoValues(pCsr, bGlobal, &sInfo, zArg);
     pCsr->isMatchinfoNeeded = 0;
   }
 
-  return SQLITE_OK;
+  return rc;
 }
 
 /*
@@ -115797,7 +119067,7 @@ SQLITE_PRIVATE void sqlite3Fts3Snippet(
       ** columns of the FTS3 table. Otherwise, only column iCol is considered.
       */
       for(iRead=0; iRead<pTab->nColumn; iRead++){
-        SnippetFragment sF;
+        SnippetFragment sF = {0, 0, 0, 0};
         int iS;
         if( iCol>=0 && iRead!=iCol ) continue;
 
@@ -115831,6 +119101,7 @@ SQLITE_PRIVATE void sqlite3Fts3Snippet(
   }
 
  snippet_out:
+  sqlite3Fts3SegmentsClose(pTab);
   if( rc!=SQLITE_OK ){
     sqlite3_result_error_code(pCtx, rc);
     sqlite3_free(res.z);
@@ -116010,6 +119281,7 @@ SQLITE_PRIVATE void sqlite3Fts3Offsets(
  offsets_out:
   sqlite3_free(sCtx.aTerm);
   assert( rc!=SQLITE_DONE );
+  sqlite3Fts3SegmentsClose(pTab);
   if( rc!=SQLITE_OK ){
     sqlite3_result_error_code(pCtx,  rc);
     sqlite3_free(res.z);
@@ -116022,21 +119294,43 @@ SQLITE_PRIVATE void sqlite3Fts3Offsets(
 /*
 ** Implementation of matchinfo() function.
 */
-SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *pContext, Fts3Cursor *pCsr){
+SQLITE_PRIVATE void sqlite3Fts3Matchinfo(
+  sqlite3_context *pContext,      /* Function call context */
+  Fts3Cursor *pCsr,               /* FTS3 table cursor */
+  const char *zArg                /* Second arg to matchinfo() function */
+){
+  Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
   int rc;
+  int i;
+  const char *zFormat;
+
+  if( zArg ){
+    for(i=0; zArg[i]; i++){
+      char *zErr = 0;
+      if( fts3MatchinfoCheck(pTab, zArg[i], &zErr) ){
+        sqlite3_result_error(pContext, zErr, -1);
+        sqlite3_free(zErr);
+        return;
+      }
+    }
+    zFormat = zArg;
+  }else{
+    zFormat = FTS3_MATCHINFO_DEFAULT;
+  }
+
   if( !pCsr->pExpr ){
     sqlite3_result_blob(pContext, "", 0, SQLITE_STATIC);
     return;
   }
-  rc = fts3GetMatchinfo(pCsr);
+
+  /* Retrieve matchinfo() data. */
+  rc = fts3GetMatchinfo(pCsr, zFormat);
+  sqlite3Fts3SegmentsClose(pTab);
+
   if( rc!=SQLITE_OK ){
     sqlite3_result_error_code(pContext, rc);
   }else{
-    Fts3Table *pTab = (Fts3Table*)pCsr->base.pVtab;
-    int n = sizeof(u32)*(2+pCsr->aMatchinfo[0]*pCsr->aMatchinfo[1]*3);
-    if( pTab->bHasDocsize ){
-      n += sizeof(u32)*(1 + 2*pTab->nColumn);
-    }
+    int n = pCsr->nMatchinfo * sizeof(u32);
     sqlite3_result_blob(pContext, pCsr->aMatchinfo, n, SQLITE_TRANSIENT);
   }
 }
@@ -116060,6 +119354,45 @@ SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *pContext, Fts3Cursor *
 ** algorithms packaged as an SQLite virtual table module.
 */
 
+/*
+** Database Format of R-Tree Tables
+** --------------------------------
+**
+** The data structure for a single virtual r-tree table is stored in three 
+** native SQLite tables declared as follows. In each case, the '%' character
+** in the table name is replaced with the user-supplied name of the r-tree
+** table.
+**
+**   CREATE TABLE %_node(nodeno INTEGER PRIMARY KEY, data BLOB)
+**   CREATE TABLE %_parent(nodeno INTEGER PRIMARY KEY, parentnode INTEGER)
+**   CREATE TABLE %_rowid(rowid INTEGER PRIMARY KEY, nodeno INTEGER)
+**
+** The data for each node of the r-tree structure is stored in the %_node
+** table. For each node that is not the root node of the r-tree, there is
+** an entry in the %_parent table associating the node with its parent.
+** And for each row of data in the table, there is an entry in the %_rowid
+** table that maps from the entries rowid to the id of the node that it
+** is stored on.
+**
+** The root node of an r-tree always exists, even if the r-tree table is
+** empty. The nodeno of the root node is always 1. All other nodes in the
+** table must be the same size as the root node. The content of each node
+** is formatted as follows:
+**
+**   1. If the node is the root node (node 1), then the first 2 bytes
+**      of the node contain the tree depth as a big-endian integer.
+**      For non-root nodes, the first 2 bytes are left unused.
+**
+**   2. The next 2 bytes contain the number of entries currently 
+**      stored in the node.
+**
+**   3. The remainder of the node contains the node entries. Each entry
+**      consists of a single 8-byte integer followed by an even number
+**      of 4-byte coordinates. For leaf nodes the integer is the rowid
+**      of a record. For internal nodes it is the node number of a
+**      child page.
+*/
+
 #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RTREE)
 
 /*
@@ -116100,6 +119433,9 @@ SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *pContext, Fts3Cursor *
   #define AssignCells splitNodeStartree
 #endif
 
+#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) 
+# define NDEBUG 1
+#endif
 
 #ifndef SQLITE_CORE
   SQLITE_EXTENSION_INIT1
@@ -116108,16 +119444,25 @@ SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *pContext, Fts3Cursor *
 
 
 #ifndef SQLITE_AMALGAMATION
+#include "sqlite3rtree.h"
 typedef sqlite3_int64 i64;
 typedef unsigned char u8;
 typedef unsigned int u32;
 #endif
 
+/*  The following macro is used to suppress compiler warnings.
+*/
+#ifndef UNUSED_PARAMETER
+# define UNUSED_PARAMETER(x) (void)(x)
+#endif
+
 typedef struct Rtree Rtree;
 typedef struct RtreeCursor RtreeCursor;
 typedef struct RtreeNode RtreeNode;
 typedef struct RtreeCell RtreeCell;
 typedef struct RtreeConstraint RtreeConstraint;
+typedef struct RtreeMatchArg RtreeMatchArg;
+typedef struct RtreeGeomCallback RtreeGeomCallback;
 typedef union RtreeCoord RtreeCoord;
 
 /* The rtree may have between 1 and RTREE_MAX_DIMENSIONS dimensions. */
@@ -116187,6 +119532,15 @@ struct Rtree {
 #define RTREE_REINSERT(p) RTREE_MINCELLS(p)
 #define RTREE_MAXCELLS 51
 
+/*
+** The smallest possible node-size is (512-64)==448 bytes. And the largest
+** supported cell size is 48 bytes (8 byte rowid + ten 4 byte coordinates).
+** Therefore all non-root nodes must contain at least 3 entries. Since 
+** 2^40 is greater than 2^64, an r-tree structure always has a depth of
+** 40 or less.
+*/
+#define RTREE_MAX_DEPTH 40
+
 /* 
 ** An rtree cursor object.
 */
@@ -116219,35 +119573,23 @@ union RtreeCoord {
 ** A search constraint.
 */
 struct RtreeConstraint {
-  int iCoord;                       /* Index of constrained coordinate */
-  int op;                           /* Constraining operation */
-  double rValue;                    /* Constraint value. */
+  int iCoord;                     /* Index of constrained coordinate */
+  int op;                         /* Constraining operation */
+  double rValue;                  /* Constraint value. */
+  int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *);
+  sqlite3_rtree_geometry *pGeom;  /* Constraint callback argument for a MATCH */
 };
 
 /* Possible values for RtreeConstraint.op */
-#define RTREE_EQ 0x41
-#define RTREE_LE 0x42
-#define RTREE_LT 0x43
-#define RTREE_GE 0x44
-#define RTREE_GT 0x45
+#define RTREE_EQ    0x41
+#define RTREE_LE    0x42
+#define RTREE_LT    0x43
+#define RTREE_GE    0x44
+#define RTREE_GT    0x45
+#define RTREE_MATCH 0x46
 
 /* 
 ** An rtree structure node.
-**
-** Data format (RtreeNode.zData):
-**
-**   1. If the node is the root node (node 1), then the first 2 bytes
-**      of the node contain the tree depth as a big-endian integer.
-**      For non-root nodes, the first 2 bytes are left unused.
-**
-**   2. The next 2 bytes contain the number of entries currently 
-**      stored in the node.
-**
-**   3. The remainder of the node contains the node entries. Each entry
-**      consists of a single 8-byte integer followed by an even number
-**      of 4-byte coordinates. For leaf nodes the integer is the rowid
-**      of a record. For internal nodes it is the node number of a
-**      child page.
 */
 struct RtreeNode {
   RtreeNode *pParent;               /* Parent node */
@@ -116267,6 +119609,40 @@ struct RtreeCell {
   RtreeCoord aCoord[RTREE_MAX_DIMENSIONS*2];
 };
 
+
+/*
+** Value for the first field of every RtreeMatchArg object. The MATCH
+** operator tests that the first field of a blob operand matches this
+** value to avoid operating on invalid blobs (which could cause a segfault).
+*/
+#define RTREE_GEOMETRY_MAGIC 0x891245AB
+
+/*
+** An instance of this structure must be supplied as a blob argument to
+** the right-hand-side of an SQL MATCH operator used to constrain an
+** r-tree query.
+*/
+struct RtreeMatchArg {
+  u32 magic;                      /* Always RTREE_GEOMETRY_MAGIC */
+  int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *);
+  void *pContext;
+  int nParam;
+  double aParam[1];
+};
+
+/*
+** When a geometry callback is created (see sqlite3_rtree_geometry_callback),
+** a single instance of the following structure is allocated. It is used
+** as the context for the user-function created by by s_r_g_c(). The object
+** is eventually deleted by the destructor mechanism provided by
+** sqlite3_create_function_v2() (which is called by s_r_g_c() to create
+** the geometry callback function).
+*/
+struct RtreeGeomCallback {
+  int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *);
+  void *pContext;
+};
+
 #ifndef MAX
 # define MAX(x,y) ((x) < (y) ? (y) : (x))
 #endif
@@ -116349,10 +119725,8 @@ static void nodeReference(RtreeNode *p){
 ** Clear the content of node p (set all bytes to 0x00).
 */
 static void nodeZero(Rtree *pRtree, RtreeNode *p){
-  if( p ){
-    memset(&p->zData[2], 0, pRtree->iNodeSize-2);
-    p->isDirty = 1;
-  }
+  memset(&p->zData[2], 0, pRtree->iNodeSize-2);
+  p->isDirty = 1;
 }
 
 /*
@@ -116372,7 +119746,6 @@ static int nodeHash(i64 iNode){
 */
 static RtreeNode *nodeHashLookup(Rtree *pRtree, i64 iNode){
   RtreeNode *p;
-  assert( iNode!=0 );
   for(p=pRtree->aHash[nodeHash(iNode)]; p && p->iNode!=iNode; p=p->pNext);
   return p;
 }
@@ -116381,13 +119754,11 @@ static RtreeNode *nodeHashLookup(Rtree *pRtree, i64 iNode){
 ** Add node pNode to the node hash table.
 */
 static void nodeHashInsert(Rtree *pRtree, RtreeNode *pNode){
-  if( pNode ){
-    int iHash;
-    assert( pNode->pNext==0 );
-    iHash = nodeHash(pNode->iNode);
-    pNode->pNext = pRtree->aHash[iHash];
-    pRtree->aHash[iHash] = pNode;
-  }
+  int iHash;
+  assert( pNode->pNext==0 );
+  iHash = nodeHash(pNode->iNode);
+  pNode->pNext = pRtree->aHash[iHash];
+  pRtree->aHash[iHash] = pNode;
 }
 
 /*
@@ -116409,11 +119780,11 @@ static void nodeHashDelete(Rtree *pRtree, RtreeNode *pNode){
 ** assigned a node number when nodeWrite() is called to write the
 ** node contents out to the database.
 */
-static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent, int zero){
+static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){
   RtreeNode *pNode;
   pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode) + pRtree->iNodeSize);
   if( pNode ){
-    memset(pNode, 0, sizeof(RtreeNode) + (zero?pRtree->iNodeSize:0));
+    memset(pNode, 0, sizeof(RtreeNode) + pRtree->iNodeSize);
     pNode->zData = (u8 *)&pNode[1];
     pNode->nRef = 1;
     pNode->pParent = pParent;
@@ -116434,6 +119805,7 @@ nodeAcquire(
   RtreeNode **ppNode         /* OUT: Acquired node */
 ){
   int rc;
+  int rc2 = SQLITE_OK;
   RtreeNode *pNode;
 
   /* Check if the requested node is already in the hash table. If so,
@@ -116450,39 +119822,63 @@ nodeAcquire(
     return SQLITE_OK;
   }
 
-  pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode) + pRtree->iNodeSize);
-  if( !pNode ){
-    *ppNode = 0;
-    return SQLITE_NOMEM;
-  }
-  pNode->pParent = pParent;
-  pNode->zData = (u8 *)&pNode[1];
-  pNode->nRef = 1;
-  pNode->iNode = iNode;
-  pNode->isDirty = 0;
-  pNode->pNext = 0;
-
   sqlite3_bind_int64(pRtree->pReadNode, 1, iNode);
   rc = sqlite3_step(pRtree->pReadNode);
   if( rc==SQLITE_ROW ){
     const u8 *zBlob = sqlite3_column_blob(pRtree->pReadNode, 0);
-    assert( sqlite3_column_bytes(pRtree->pReadNode, 0)==pRtree->iNodeSize );
-    memcpy(pNode->zData, zBlob, pRtree->iNodeSize);
-    nodeReference(pParent);
-  }else{
-    sqlite3_free(pNode);
-    pNode = 0;
+    if( pRtree->iNodeSize==sqlite3_column_bytes(pRtree->pReadNode, 0) ){
+      pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode)+pRtree->iNodeSize);
+      if( !pNode ){
+        rc2 = SQLITE_NOMEM;
+      }else{
+        pNode->pParent = pParent;
+        pNode->zData = (u8 *)&pNode[1];
+        pNode->nRef = 1;
+        pNode->iNode = iNode;
+        pNode->isDirty = 0;
+        pNode->pNext = 0;
+        memcpy(pNode->zData, zBlob, pRtree->iNodeSize);
+        nodeReference(pParent);
+      }
+    }
   }
-
-  *ppNode = pNode;
   rc = sqlite3_reset(pRtree->pReadNode);
+  if( rc==SQLITE_OK ) rc = rc2;
 
-  if( rc==SQLITE_OK && iNode==1 ){
+  /* If the root node was just loaded, set pRtree->iDepth to the height
+  ** of the r-tree structure. A height of zero means all data is stored on
+  ** the root node. A height of one means the children of the root node
+  ** are the leaves, and so on. If the depth as specified on the root node
+  ** is greater than RTREE_MAX_DEPTH, the r-tree structure must be corrupt.
+  */
+  if( pNode && iNode==1 ){
     pRtree->iDepth = readInt16(pNode->zData);
+    if( pRtree->iDepth>RTREE_MAX_DEPTH ){
+      rc = SQLITE_CORRUPT;
+    }
+  }
+
+  /* If no error has occurred so far, check if the "number of entries"
+  ** field on the node is too large. If so, set the return code to 
+  ** SQLITE_CORRUPT.
+  */
+  if( pNode && rc==SQLITE_OK ){
+    if( NCELL(pNode)>((pRtree->iNodeSize-4)/pRtree->nBytesPerCell) ){
+      rc = SQLITE_CORRUPT;
+    }
   }
 
-  assert( (rc==SQLITE_OK && pNode) || (pNode==0 && rc!=SQLITE_OK) );
-  nodeHashInsert(pRtree, pNode);
+  if( rc==SQLITE_OK ){
+    if( pNode!=0 ){
+      nodeHashInsert(pRtree, pNode);
+    }else{
+      rc = SQLITE_CORRUPT;
+    }
+    *ppNode = pNode;
+  }else{
+    sqlite3_free(pNode);
+    *ppNode = 0;
+  }
 
   return rc;
 }
@@ -116535,8 +119931,7 @@ nodeInsertCell(
   nMaxCell = (pRtree->iNodeSize-4)/pRtree->nBytesPerCell;
   nCell = NCELL(pNode);
 
-  assert(nCell<=nMaxCell);
-
+  assert( nCell<=nMaxCell );
   if( nCell<nMaxCell ){
     nodeOverwriteCell(pRtree, pNode, pCell, nCell);
     writeInt16(&pNode->zData[2], nCell+1);
@@ -116756,6 +120151,25 @@ static int rtreeOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
   return rc;
 }
 
+
+/*
+** Free the RtreeCursor.aConstraint[] array and its contents.
+*/
+static void freeCursorConstraints(RtreeCursor *pCsr){
+  if( pCsr->aConstraint ){
+    int i;                        /* Used to iterate through constraint array */
+    for(i=0; i<pCsr->nConstraint; i++){
+      sqlite3_rtree_geometry *pGeom = pCsr->aConstraint[i].pGeom;
+      if( pGeom ){
+        if( pGeom->xDelUser ) pGeom->xDelUser(pGeom->pUser);
+        sqlite3_free(pGeom);
+      }
+    }
+    sqlite3_free(pCsr->aConstraint);
+    pCsr->aConstraint = 0;
+  }
+}
+
 /* 
 ** Rtree virtual table module xClose method.
 */
@@ -116763,7 +120177,7 @@ static int rtreeClose(sqlite3_vtab_cursor *cur){
   Rtree *pRtree = (Rtree *)(cur->pVtab);
   int rc;
   RtreeCursor *pCsr = (RtreeCursor *)cur;
-  sqlite3_free(pCsr->aConstraint);
+  freeCursorConstraints(pCsr);
   rc = nodeRelease(pRtree, pCsr->pNode);
   sqlite3_free(pCsr);
   return rc;
@@ -116780,16 +120194,43 @@ static int rtreeEof(sqlite3_vtab_cursor *cur){
   return (pCsr->pNode==0);
 }
 
+/*
+** The r-tree constraint passed as the second argument to this function is
+** guaranteed to be a MATCH constraint.
+*/
+static int testRtreeGeom(
+  Rtree *pRtree,                  /* R-Tree object */
+  RtreeConstraint *pConstraint,   /* MATCH constraint to test */
+  RtreeCell *pCell,               /* Cell to test */
+  int *pbRes                      /* OUT: Test result */
+){
+  int i;
+  double aCoord[RTREE_MAX_DIMENSIONS*2];
+  int nCoord = pRtree->nDim*2;
+
+  assert( pConstraint->op==RTREE_MATCH );
+  assert( pConstraint->pGeom );
+
+  for(i=0; i<nCoord; i++){
+    aCoord[i] = DCOORD(pCell->aCoord[i]);
+  }
+  return pConstraint->xGeom(pConstraint->pGeom, nCoord, aCoord, pbRes);
+}
+
 /* 
 ** Cursor pCursor currently points to a cell in a non-leaf page.
-** Return true if the sub-tree headed by the cell is filtered
+** Set *pbEof to true if the sub-tree headed by the cell is filtered
 ** (excluded) by the constraints in the pCursor->aConstraint[] 
 ** array, or false otherwise.
+**
+** Return SQLITE_OK if successful or an SQLite error code if an error
+** occurs within a geometry callback.
 */
-static int testRtreeCell(Rtree *pRtree, RtreeCursor *pCursor){
+static int testRtreeCell(Rtree *pRtree, RtreeCursor *pCursor, int *pbEof){
   RtreeCell cell;
   int ii;
   int bRes = 0;
+  int rc = SQLITE_OK;
 
   nodeGetCell(pRtree, pCursor->pNode, pCursor->iCell, &cell);
   for(ii=0; bRes==0 && ii<pCursor->nConstraint; ii++){
@@ -116798,31 +120239,51 @@ static int testRtreeCell(Rtree *pRtree, RtreeCursor *pCursor){
     double cell_max = DCOORD(cell.aCoord[(p->iCoord>>1)*2+1]);
 
     assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE 
-        || p->op==RTREE_GT || p->op==RTREE_EQ
+        || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_MATCH
     );
 
     switch( p->op ){
-      case RTREE_LE: case RTREE_LT: bRes = p->rValue<cell_min; break;
-      case RTREE_GE: case RTREE_GT: bRes = p->rValue>cell_max; break;
-      case RTREE_EQ: 
+      case RTREE_LE: case RTREE_LT: 
+        bRes = p->rValue<cell_min; 
+        break;
+
+      case RTREE_GE: case RTREE_GT: 
+        bRes = p->rValue>cell_max; 
+        break;
+
+      case RTREE_EQ:
         bRes = (p->rValue>cell_max || p->rValue<cell_min);
         break;
+
+      default: {
+        assert( p->op==RTREE_MATCH );
+        rc = testRtreeGeom(pRtree, p, &cell, &bRes);
+        bRes = !bRes;
+        break;
+      }
     }
   }
 
-  return bRes;
+  *pbEof = bRes;
+  return rc;
 }
 
 /* 
-** Return true if the cell that cursor pCursor currently points to
+** Test if the cell that cursor pCursor currently points to
 ** would be filtered (excluded) by the constraints in the 
-** pCursor->aConstraint[] array, or false otherwise.
+** pCursor->aConstraint[] array. If so, set *pbEof to true before
+** returning. If the cell is not filtered (excluded) by the constraints,
+** set pbEof to zero.
+**
+** Return SQLITE_OK if successful or an SQLite error code if an error
+** occurs within a geometry callback.
 **
 ** This function assumes that the cell is part of a leaf node.
 */
-static int testRtreeEntry(Rtree *pRtree, RtreeCursor *pCursor){
+static int testRtreeEntry(Rtree *pRtree, RtreeCursor *pCursor, int *pbEof){
   RtreeCell cell;
   int ii;
+  *pbEof = 0;
 
   nodeGetCell(pRtree, pCursor->pNode, pCursor->iCell, &cell);
   for(ii=0; ii<pCursor->nConstraint; ii++){
@@ -116830,7 +120291,7 @@ static int testRtreeEntry(Rtree *pRtree, RtreeCursor *pCursor){
     double coord = DCOORD(cell.aCoord[p->iCoord]);
     int res;
     assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE 
-        || p->op==RTREE_GT || p->op==RTREE_EQ
+        || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_MATCH
     );
     switch( p->op ){
       case RTREE_LE: res = (coord<=p->rValue); break;
@@ -116838,12 +120299,24 @@ static int testRtreeEntry(Rtree *pRtree, RtreeCursor *pCursor){
       case RTREE_GE: res = (coord>=p->rValue); break;
       case RTREE_GT: res = (coord>p->rValue);  break;
       case RTREE_EQ: res = (coord==p->rValue); break;
+      default: {
+        int rc;
+        assert( p->op==RTREE_MATCH );
+        rc = testRtreeGeom(pRtree, p, &cell, &res);
+        if( rc!=SQLITE_OK ){
+          return rc;
+        }
+        break;
+      }
     }
 
-    if( !res ) return 1;
+    if( !res ){
+      *pbEof = 1;
+      return SQLITE_OK;
+    }
   }
 
-  return 0;
+  return SQLITE_OK;
 }
 
 /*
@@ -116870,19 +120343,18 @@ static int descendToCell(
   assert( iHeight>=0 );
 
   if( iHeight==0 ){
-    isEof = testRtreeEntry(pRtree, pCursor);
+    rc = testRtreeEntry(pRtree, pCursor, &isEof);
   }else{
-    isEof = testRtreeCell(pRtree, pCursor);
+    rc = testRtreeCell(pRtree, pCursor, &isEof);
   }
-  if( isEof || iHeight==0 ){
-    *pEof = isEof;
-    return SQLITE_OK;
+  if( rc!=SQLITE_OK || isEof || iHeight==0 ){
+    goto descend_to_cell_out;
   }
 
   iRowid = nodeGetRowid(pRtree, pCursor->pNode, pCursor->iCell);
   rc = nodeAcquire(pRtree, iRowid, pCursor->pNode, &pChild);
   if( rc!=SQLITE_OK ){
-    return rc;
+    goto descend_to_cell_out;
   }
 
   nodeRelease(pRtree, pCursor->pNode);
@@ -116892,7 +120364,7 @@ static int descendToCell(
     pCursor->iCell = ii;
     rc = descendToCell(pRtree, pCursor, iHeight-1, &isEof);
     if( rc!=SQLITE_OK ){
-      return rc;
+      goto descend_to_cell_out;
     }
   }
 
@@ -116904,32 +120376,43 @@ static int descendToCell(
     pCursor->iCell = iSavedCell;
   }
 
+descend_to_cell_out:
   *pEof = isEof;
-  return SQLITE_OK;
+  return rc;
 }
 
 /*
 ** One of the cells in node pNode is guaranteed to have a 64-bit 
 ** integer value equal to iRowid. Return the index of this cell.
 */
-static int nodeRowidIndex(Rtree *pRtree, RtreeNode *pNode, i64 iRowid){
+static int nodeRowidIndex(
+  Rtree *pRtree, 
+  RtreeNode *pNode, 
+  i64 iRowid,
+  int *piIndex
+){
   int ii;
-  for(ii=0; nodeGetRowid(pRtree, pNode, ii)!=iRowid; ii++){
-    assert( ii<(NCELL(pNode)-1) );
+  int nCell = NCELL(pNode);
+  for(ii=0; ii<nCell; ii++){
+    if( nodeGetRowid(pRtree, pNode, ii)==iRowid ){
+      *piIndex = ii;
+      return SQLITE_OK;
+    }
   }
-  return ii;
+  return SQLITE_CORRUPT;
 }
 
 /*
 ** Return the index of the cell containing a pointer to node pNode
 ** in its parent. If pNode is the root node, return -1.
 */
-static int nodeParentIndex(Rtree *pRtree, RtreeNode *pNode){
+static int nodeParentIndex(Rtree *pRtree, RtreeNode *pNode, int *piIndex){
   RtreeNode *pParent = pNode->pParent;
   if( pParent ){
-    return nodeRowidIndex(pRtree, pParent, pNode->iNode);
+    return nodeRowidIndex(pRtree, pParent, pNode->iNode, piIndex);
   }
-  return -1;
+  *piIndex = -1;
+  return SQLITE_OK;
 }
 
 /* 
@@ -116940,13 +120423,17 @@ static int rtreeNext(sqlite3_vtab_cursor *pVtabCursor){
   RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor;
   int rc = SQLITE_OK;
 
+  /* RtreeCursor.pNode must not be NULL. If is is NULL, then this cursor is
+  ** already at EOF. It is against the rules to call the xNext() method of
+  ** a cursor that has already reached EOF.
+  */
+  assert( pCsr->pNode );
+
   if( pCsr->iStrategy==1 ){
     /* This "scan" is a direct lookup by rowid. There is no next entry. */
     nodeRelease(pRtree, pCsr->pNode);
     pCsr->pNode = 0;
-  }
-
-  else if( pCsr->pNode ){
+  }else{
     /* Move to the next entry that matches the configured constraints. */
     int iHeight = 0;
     while( pCsr->pNode ){
@@ -116960,7 +120447,10 @@ static int rtreeNext(sqlite3_vtab_cursor *pVtabCursor){
         }
       }
       pCsr->pNode = pNode->pParent;
-      pCsr->iCell = nodeParentIndex(pRtree, pNode);
+      rc = nodeParentIndex(pRtree, pNode, &pCsr->iCell);
+      if( rc!=SQLITE_OK ){
+        return rc;
+      }
       nodeReference(pCsr->pNode);
       nodeRelease(pRtree, pNode);
       iHeight++;
@@ -117028,6 +120518,51 @@ static int findLeafNode(Rtree *pRtree, i64 iRowid, RtreeNode **ppLeaf){
   return rc;
 }
 
+/*
+** This function is called to configure the RtreeConstraint object passed
+** as the second argument for a MATCH constraint. The value passed as the
+** first argument to this function is the right-hand operand to the MATCH
+** operator.
+*/
+static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){
+  RtreeMatchArg *p;
+  sqlite3_rtree_geometry *pGeom;
+  int nBlob;
+
+  /* Check that value is actually a blob. */
+  if( !sqlite3_value_type(pValue)==SQLITE_BLOB ) return SQLITE_ERROR;
+
+  /* Check that the blob is roughly the right size. */
+  nBlob = sqlite3_value_bytes(pValue);
+  if( nBlob<(int)sizeof(RtreeMatchArg) 
+   || ((nBlob-sizeof(RtreeMatchArg))%sizeof(double))!=0
+  ){
+    return SQLITE_ERROR;
+  }
+
+  pGeom = (sqlite3_rtree_geometry *)sqlite3_malloc(
+      sizeof(sqlite3_rtree_geometry) + nBlob
+  );
+  if( !pGeom ) return SQLITE_NOMEM;
+  memset(pGeom, 0, sizeof(sqlite3_rtree_geometry));
+  p = (RtreeMatchArg *)&pGeom[1];
+
+  memcpy(p, sqlite3_value_blob(pValue), nBlob);
+  if( p->magic!=RTREE_GEOMETRY_MAGIC 
+   || nBlob!=(int)(sizeof(RtreeMatchArg) + (p->nParam-1)*sizeof(double))
+  ){
+    sqlite3_free(pGeom);
+    return SQLITE_ERROR;
+  }
+
+  pGeom->pContext = p->pContext;
+  pGeom->nParam = p->nParam;
+  pGeom->aParam = p->aParam;
+
+  pCons->xGeom = p->xGeom;
+  pCons->pGeom = pGeom;
+  return SQLITE_OK;
+}
 
 /* 
 ** Rtree virtual table module xFilter method.
@@ -117046,8 +120581,7 @@ static int rtreeFilter(
 
   rtreeReference(pRtree);
 
-  sqlite3_free(pCsr->aConstraint);
-  pCsr->aConstraint = 0;
+  freeCursorConstraints(pCsr);
   pCsr->iStrategy = idxNum;
 
   if( idxNum==1 ){
@@ -117056,8 +120590,9 @@ static int rtreeFilter(
     i64 iRowid = sqlite3_value_int64(argv[0]);
     rc = findLeafNode(pRtree, iRowid, &pLeaf);
     pCsr->pNode = pLeaf; 
-    if( pLeaf && rc==SQLITE_OK ){
-      pCsr->iCell = nodeRowidIndex(pRtree, pLeaf, iRowid);
+    if( pLeaf ){
+      assert( rc==SQLITE_OK );
+      rc = nodeRowidIndex(pRtree, pLeaf, iRowid, &pCsr->iCell);
     }
   }else{
     /* Normal case - r-tree scan. Set up the RtreeCursor.aConstraint array 
@@ -117069,12 +120604,24 @@ static int rtreeFilter(
       if( !pCsr->aConstraint ){
         rc = SQLITE_NOMEM;
       }else{
+        memset(pCsr->aConstraint, 0, sizeof(RtreeConstraint)*argc);
         assert( (idxStr==0 && argc==0) || strlen(idxStr)==argc*2 );
         for(ii=0; ii<argc; ii++){
           RtreeConstraint *p = &pCsr->aConstraint[ii];
           p->op = idxStr[ii*2];
           p->iCoord = idxStr[ii*2+1]-'a';
-          p->rValue = sqlite3_value_double(argv[ii]);
+          if( p->op==RTREE_MATCH ){
+            /* A MATCH operator. The right-hand-side must be a blob that
+            ** can be cast into an RtreeMatchArg object. One created using
+            ** an sqlite3_rtree_geometry_callback() SQL user function.
+            */
+            rc = deserializeGeometry(argv[ii], p);
+            if( rc!=SQLITE_OK ){
+              break;
+            }
+          }else{
+            p->rValue = sqlite3_value_double(argv[ii]);
+          }
         }
       }
     }
@@ -117134,6 +120681,7 @@ static int rtreeFilter(
 **      <        0x43 ('C')
 **     >=        0x44 ('D')
 **      >        0x45 ('E')
+**   MATCH       0x46 ('F')
 **   ----------------------
 **
 ** The second of each pair of bytes identifies the coordinate column
@@ -117147,6 +120695,7 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
   int iIdx = 0;
   char zIdxStr[RTREE_MAX_DIMENSIONS*8+1];
   memset(zIdxStr, 0, sizeof(zIdxStr));
+  UNUSED_PARAMETER(tab);
 
   assert( pIdxInfo->idxStr==0 );
   for(ii=0; ii<pIdxInfo->nConstraint; ii++){
@@ -117172,7 +120721,9 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
       return SQLITE_OK;
     }
 
-    if( p->usable && p->iColumn>0 ){
+    if( p->usable && (p->iColumn>0 || p->op==SQLITE_INDEX_CONSTRAINT_MATCH) ){
+      int j, opmsk;
+      static const unsigned char compatible[] = { 0, 0, 1, 1, 2, 2 };
       u8 op = 0;
       switch( p->op ){
         case SQLITE_INDEX_CONSTRAINT_EQ: op = RTREE_EQ; break;
@@ -117180,31 +120731,33 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
         case SQLITE_INDEX_CONSTRAINT_LE: op = RTREE_LE; break;
         case SQLITE_INDEX_CONSTRAINT_LT: op = RTREE_LT; break;
         case SQLITE_INDEX_CONSTRAINT_GE: op = RTREE_GE; break;
+        default:
+          assert( p->op==SQLITE_INDEX_CONSTRAINT_MATCH );
+          op = RTREE_MATCH; 
+          break;
       }
-      if( op ){
-        /* Make sure this particular constraint has not been used before.
-        ** If it has been used before, ignore it.
-        **
-        ** A <= or < can be used if there is a prior >= or >.
-        ** A >= or > can be used if there is a prior < or <=.
-        ** A <= or < is disqualified if there is a prior <=, <, or ==.
-        ** A >= or > is disqualified if there is a prior >=, >, or ==.
-        ** A == is disqualifed if there is any prior constraint.
-        */
-        int j, opmsk;
-        static const unsigned char compatible[] = { 0, 0, 1, 1, 2, 2 };
-        assert( compatible[RTREE_EQ & 7]==0 );
-        assert( compatible[RTREE_LT & 7]==1 );
-        assert( compatible[RTREE_LE & 7]==1 );
-        assert( compatible[RTREE_GT & 7]==2 );
-        assert( compatible[RTREE_GE & 7]==2 );
-        cCol = p->iColumn - 1 + 'a';
-        opmsk = compatible[op & 7];
-        for(j=0; j<iIdx; j+=2){
-          if( zIdxStr[j+1]==cCol && (compatible[zIdxStr[j] & 7] & opmsk)!=0 ){
-            op = 0;
-            break;
-          }
+      assert( op!=0 );
+
+      /* Make sure this particular constraint has not been used before.
+      ** If it has been used before, ignore it.
+      **
+      ** A <= or < can be used if there is a prior >= or >.
+      ** A >= or > can be used if there is a prior < or <=.
+      ** A <= or < is disqualified if there is a prior <=, <, or ==.
+      ** A >= or > is disqualified if there is a prior >=, >, or ==.
+      ** A == is disqualifed if there is any prior constraint.
+      */
+      assert( compatible[RTREE_EQ & 7]==0 );
+      assert( compatible[RTREE_LT & 7]==1 );
+      assert( compatible[RTREE_LE & 7]==1 );
+      assert( compatible[RTREE_GT & 7]==2 );
+      assert( compatible[RTREE_GE & 7]==2 );
+      cCol = p->iColumn - 1 + 'a';
+      opmsk = compatible[op & 7];
+      for(j=0; j<iIdx; j+=2){
+        if( zIdxStr[j+1]==cCol && (compatible[zIdxStr[j] & 7] & opmsk)!=0 ){
+          op = 0;
+          break;
         }
       }
       if( op ){
@@ -117312,7 +120865,13 @@ static float cellOverlap(
   int ii;
   float overlap = 0.0;
   for(ii=0; ii<nCell; ii++){
-    if( ii!=iExclude ){
+#if VARIANT_RSTARTREE_CHOOSESUBTREE
+    if( ii!=iExclude )
+#else
+    assert( iExclude==-1 );
+    UNUSED_PARAMETER(iExclude);
+#endif
+    {
       int jj;
       float o = 1.0;
       for(jj=0; jj<(pRtree->nDim*2); jj+=2){
@@ -117405,22 +120964,31 @@ static int ChooseLeaf(
     ** the smallest area.
     */
     for(iCell=0; iCell<nCell; iCell++){
+      int bBest = 0;
       float growth;
       float area;
       float overlap = 0.0;
       nodeGetCell(pRtree, pNode, iCell, &cell);
       growth = cellGrowth(pRtree, &cell, pCell);
       area = cellArea(pRtree, &cell);
+
 #if VARIANT_RSTARTREE_CHOOSESUBTREE
       if( ii==(pRtree->iDepth-1) ){
         overlap = cellOverlapEnlargement(pRtree,&cell,pCell,aCell,nCell,iCell);
       }
-#endif
       if( (iCell==0) 
        || (overlap<fMinOverlap) 
        || (overlap==fMinOverlap && growth<fMinGrowth)
        || (overlap==fMinOverlap && growth==fMinGrowth && area<fMinArea)
       ){
+        bBest = 1;
+      }
+#else
+      if( iCell==0||growth<fMinGrowth||(growth==fMinGrowth && area<fMinArea) ){
+        bBest = 1;
+      }
+#endif
+      if( bBest ){
         fMinOverlap = overlap;
         fMinGrowth = growth;
         fMinArea = area;
@@ -117443,16 +121011,20 @@ static int ChooseLeaf(
 ** the node pNode. This function updates the bounding box cells in
 ** all ancestor elements.
 */
-static void AdjustTree(
+static int AdjustTree(
   Rtree *pRtree,                    /* Rtree table */
   RtreeNode *pNode,                 /* Adjust ancestry of this node. */
   RtreeCell *pCell                  /* This cell was just inserted */
 ){
   RtreeNode *p = pNode;
   while( p->pParent ){
-    RtreeCell cell;
     RtreeNode *pParent = p->pParent;
-    int iCell = nodeParentIndex(pRtree, p);
+    RtreeCell cell;
+    int iCell;
+
+    if( nodeParentIndex(pRtree, p, &iCell) ){
+      return SQLITE_CORRUPT;
+    }
 
     nodeGetCell(pRtree, pParent, iCell, &cell);
     if( !cellContains(pRtree, &cell, pCell) ){
@@ -117462,6 +121034,7 @@ static void AdjustTree(
  
     p = pParent;
   }
+  return SQLITE_OK;
 }
 
 /*
@@ -117990,14 +121563,14 @@ static int SplitNode(
   nCell++;
 
   if( pNode->iNode==1 ){
-    pRight = nodeNew(pRtree, pNode, 1);
-    pLeft = nodeNew(pRtree, pNode, 1);
+    pRight = nodeNew(pRtree, pNode);
+    pLeft = nodeNew(pRtree, pNode);
     pRtree->iDepth++;
     pNode->isDirty = 1;
     writeInt16(pNode->zData, pRtree->iDepth);
   }else{
     pLeft = pNode;
-    pRight = nodeNew(pRtree, pLeft->pParent, 1);
+    pRight = nodeNew(pRtree, pLeft->pParent);
     nodeReference(pLeft);
   }
 
@@ -118014,8 +121587,12 @@ static int SplitNode(
     goto splitnode_out;
   }
 
-  /* Ensure both child nodes have node numbers assigned to them. */
-  if( (0==pRight->iNode && SQLITE_OK!=(rc = nodeWrite(pRtree, pRight)))
+  /* Ensure both child nodes have node numbers assigned to them by calling
+  ** nodeWrite(). Node pRight always needs a node number, as it was created
+  ** by nodeNew() above. But node pLeft sometimes already has a node number.
+  ** In this case avoid the all to nodeWrite().
+  */
+  if( SQLITE_OK!=(rc = nodeWrite(pRtree, pRight))
    || (0==pLeft->iNode && SQLITE_OK!=(rc = nodeWrite(pRtree, pLeft)))
   ){
     goto splitnode_out;
@@ -118031,9 +121608,15 @@ static int SplitNode(
     }
   }else{
     RtreeNode *pParent = pLeft->pParent;
-    int iCell = nodeParentIndex(pRtree, pLeft);
-    nodeOverwriteCell(pRtree, pParent, &leftbbox, iCell);
-    AdjustTree(pRtree, pParent, &leftbbox);
+    int iCell;
+    rc = nodeParentIndex(pRtree, pLeft, &iCell);
+    if( rc==SQLITE_OK ){
+      nodeOverwriteCell(pRtree, pParent, &leftbbox, iCell);
+      rc = AdjustTree(pRtree, pParent, &leftbbox);
+    }
+    if( rc!=SQLITE_OK ){
+      goto splitnode_out;
+    }
   }
   if( (rc = rtreeInsertCell(pRtree, pRight->pParent, &rightbbox, iHeight+1)) ){
     goto splitnode_out;
@@ -118077,20 +121660,43 @@ splitnode_out:
   return rc;
 }
 
+/*
+** If node pLeaf is not the root of the r-tree and its pParent pointer is 
+** still NULL, load all ancestor nodes of pLeaf into memory and populate
+** the pLeaf->pParent chain all the way up to the root node.
+**
+** This operation is required when a row is deleted (or updated - an update
+** is implemented as a delete followed by an insert). SQLite provides the
+** rowid of the row to delete, which can be used to find the leaf on which
+** the entry resides (argument pLeaf). Once the leaf is located, this 
+** function is called to determine its ancestry.
+*/
 static int fixLeafParent(Rtree *pRtree, RtreeNode *pLeaf){
   int rc = SQLITE_OK;
-  if( pLeaf->iNode!=1 && pLeaf->pParent==0 ){
-    sqlite3_bind_int64(pRtree->pReadParent, 1, pLeaf->iNode);
-    if( sqlite3_step(pRtree->pReadParent)==SQLITE_ROW ){
-      i64 iNode = sqlite3_column_int64(pRtree->pReadParent, 0);
-      rc = nodeAcquire(pRtree, iNode, 0, &pLeaf->pParent);
-    }else{
-      rc = SQLITE_ERROR;
-    }
-    sqlite3_reset(pRtree->pReadParent);
-    if( rc==SQLITE_OK ){
-      rc = fixLeafParent(pRtree, pLeaf->pParent);
+  RtreeNode *pChild = pLeaf;
+  while( rc==SQLITE_OK && pChild->iNode!=1 && pChild->pParent==0 ){
+    int rc2 = SQLITE_OK;          /* sqlite3_reset() return code */
+    sqlite3_bind_int64(pRtree->pReadParent, 1, pChild->iNode);
+    rc = sqlite3_step(pRtree->pReadParent);
+    if( rc==SQLITE_ROW ){
+      RtreeNode *pTest;           /* Used to test for reference loops */
+      i64 iNode;                  /* Node number of parent node */
+
+      /* Before setting pChild->pParent, test that we are not creating a
+      ** loop of references (as we would if, say, pChild==pParent). We don't
+      ** want to do this as it leads to a memory leak when trying to delete
+      ** the referenced counted node structures.
+      */
+      iNode = sqlite3_column_int64(pRtree->pReadParent, 0);
+      for(pTest=pLeaf; pTest && pTest->iNode!=iNode; pTest=pTest->pParent);
+      if( !pTest ){
+        rc2 = nodeAcquire(pRtree, iNode, 0, &pChild->pParent);
+      }
     }
+    rc = sqlite3_reset(pRtree->pReadParent);
+    if( rc==SQLITE_OK ) rc = rc2;
+    if( rc==SQLITE_OK && !pChild->pParent ) rc = SQLITE_CORRUPT;
+    pChild = pChild->pParent;
   }
   return rc;
 }
@@ -118099,18 +121705,24 @@ static int deleteCell(Rtree *, RtreeNode *, int, int);
 
 static int removeNode(Rtree *pRtree, RtreeNode *pNode, int iHeight){
   int rc;
+  int rc2;
   RtreeNode *pParent;
   int iCell;
 
   assert( pNode->nRef==1 );
 
   /* Remove the entry in the parent cell. */
-  iCell = nodeParentIndex(pRtree, pNode);
-  pParent = pNode->pParent;
-  pNode->pParent = 0;
-  if( SQLITE_OK!=(rc = deleteCell(pRtree, pParent, iCell, iHeight+1)) 
-   || SQLITE_OK!=(rc = nodeRelease(pRtree, pParent))
-  ){
+  rc = nodeParentIndex(pRtree, pNode, &iCell);
+  if( rc==SQLITE_OK ){
+    pParent = pNode->pParent;
+    pNode->pParent = 0;
+    rc = deleteCell(pRtree, pParent, iCell, iHeight+1);
+  }
+  rc2 = nodeRelease(pRtree, pParent);
+  if( rc==SQLITE_OK ){
+    rc = rc2;
+  }
+  if( rc!=SQLITE_OK ){
     return rc;
   }
 
@@ -118140,8 +121752,9 @@ static int removeNode(Rtree *pRtree, RtreeNode *pNode, int iHeight){
   return SQLITE_OK;
 }
 
-static void fixBoundingBox(Rtree *pRtree, RtreeNode *pNode){
+static int fixBoundingBox(Rtree *pRtree, RtreeNode *pNode){
   RtreeNode *pParent = pNode->pParent;
+  int rc = SQLITE_OK; 
   if( pParent ){
     int ii; 
     int nCell = NCELL(pNode);
@@ -118153,10 +121766,13 @@ static void fixBoundingBox(Rtree *pRtree, RtreeNode *pNode){
       cellUnion(pRtree, &box, &cell);
     }
     box.iRowid = pNode->iNode;
-    ii = nodeParentIndex(pRtree, pNode);
-    nodeOverwriteCell(pRtree, pParent, &box, ii);
-    fixBoundingBox(pRtree, pParent);
+    rc = nodeParentIndex(pRtree, pNode, &ii);
+    if( rc==SQLITE_OK ){
+      nodeOverwriteCell(pRtree, pParent, &box, ii);
+      rc = fixBoundingBox(pRtree, pParent);
+    }
   }
+  return rc;
 }
 
 /*
@@ -118164,6 +121780,7 @@ static void fixBoundingBox(Rtree *pRtree, RtreeNode *pNode){
 ** cell, adjust the r-tree data structure if required.
 */
 static int deleteCell(Rtree *pRtree, RtreeNode *pNode, int iCell, int iHeight){
+  RtreeNode *pParent;
   int rc;
 
   if( SQLITE_OK!=(rc = fixLeafParent(pRtree, pNode)) ){
@@ -118180,14 +121797,13 @@ static int deleteCell(Rtree *pRtree, RtreeNode *pNode, int iCell, int iHeight){
   ** cell in the parent node so that it tightly contains the updated
   ** node.
   */
-  if( pNode->iNode!=1 ){
-    RtreeNode *pParent = pNode->pParent;
-    if( (pParent->iNode!=1 || NCELL(pParent)!=1) 
-     && (NCELL(pNode)<RTREE_MINCELLS(pRtree))
-    ){
+  pParent = pNode->pParent;
+  assert( pParent || pNode->iNode==1 );
+  if( pParent ){
+    if( NCELL(pNode)<RTREE_MINCELLS(pRtree) ){
       rc = removeNode(pRtree, pNode, iHeight);
     }else{
-      fixBoundingBox(pRtree, pNode);
+      rc = fixBoundingBox(pRtree, pNode);
     }
   }
 
@@ -118270,7 +121886,7 @@ static int Reinsert(
     }
   }
   if( rc==SQLITE_OK ){
-    fixBoundingBox(pRtree, pNode);
+    rc = fixBoundingBox(pRtree, pNode);
   }
   for(; rc==SQLITE_OK && ii<nCell; ii++){
     /* Find a node to store this cell in. pNode->iNode currently contains
@@ -118324,11 +121940,13 @@ static int rtreeInsertCell(
     rc = SplitNode(pRtree, pNode, pCell, iHeight);
 #endif
   }else{
-    AdjustTree(pRtree, pNode, pCell);
-    if( iHeight==0 ){
-      rc = rowidWrite(pRtree, pCell->iRowid, pNode->iNode);
-    }else{
-      rc = parentWrite(pRtree, pCell->iRowid, pNode->iNode);
+    rc = AdjustTree(pRtree, pNode, pCell);
+    if( rc==SQLITE_OK ){
+      if( iHeight==0 ){
+        rc = rowidWrite(pRtree, pCell->iRowid, pNode->iNode);
+      }else{
+        rc = parentWrite(pRtree, pCell->iRowid, pNode->iNode);
+      }
     }
   }
   return rc;
@@ -118373,16 +121991,6 @@ static int newRowid(Rtree *pRtree, i64 *piRowid){
   return rc;
 }
 
-#ifndef NDEBUG
-static int hashIsEmpty(Rtree *pRtree){
-  int ii;
-  for(ii=0; ii<HASHSIZE; ii++){
-    assert( !pRtree->aHash[ii] );
-  }
-  return 1;
-}
-#endif
-
 /*
 ** The xUpdate method for rtree module virtual tables.
 */
@@ -118398,7 +122006,6 @@ static int rtreeUpdate(
   rtreeReference(pRtree);
 
   assert(nData>=1);
-  assert(hashIsEmpty(pRtree));
 
   /* If azData[0] is not an SQL NULL value, it is the rowid of a
   ** record to delete from the r-tree table. The following block does
@@ -118424,8 +122031,10 @@ static int rtreeUpdate(
     /* Delete the cell in question from the leaf node. */
     if( rc==SQLITE_OK ){
       int rc2;
-      iCell = nodeRowidIndex(pRtree, pLeaf, iDelete);
-      rc = deleteCell(pRtree, pLeaf, iCell, 0);
+      rc = nodeRowidIndex(pRtree, pLeaf, iDelete, &iCell);
+      if( rc==SQLITE_OK ){
+        rc = deleteCell(pRtree, pLeaf, iCell, 0);
+      }
       rc2 = nodeRelease(pRtree, pLeaf);
       if( rc==SQLITE_OK ){
         rc = rc2;
@@ -118447,19 +122056,20 @@ static int rtreeUpdate(
     ** the root node (the operation that Gutman's paper says to perform 
     ** in this scenario).
     */
-    if( rc==SQLITE_OK && pRtree->iDepth>0 ){
-      if( rc==SQLITE_OK && NCELL(pRoot)==1 ){
-        RtreeNode *pChild;
-        i64 iChild = nodeGetRowid(pRtree, pRoot, 0);
-        rc = nodeAcquire(pRtree, iChild, pRoot, &pChild);
-        if( rc==SQLITE_OK ){
-          rc = removeNode(pRtree, pChild, pRtree->iDepth-1);
-        }
-        if( rc==SQLITE_OK ){
-          pRtree->iDepth--;
-          writeInt16(pRoot->zData, pRtree->iDepth);
-          pRoot->isDirty = 1;
-        }
+    if( rc==SQLITE_OK && pRtree->iDepth>0 && NCELL(pRoot)==1 ){
+      int rc2;
+      RtreeNode *pChild;
+      i64 iChild = nodeGetRowid(pRtree, pRoot, 0);
+      rc = nodeAcquire(pRtree, iChild, pRoot, &pChild);
+      if( rc==SQLITE_OK ){
+        rc = removeNode(pRtree, pChild, pRtree->iDepth-1);
+      }
+      rc2 = nodeRelease(pRtree, pChild);
+      if( rc==SQLITE_OK ) rc = rc2;
+      if( rc==SQLITE_OK ){
+        pRtree->iDepth--;
+        writeInt16(pRoot->zData, pRtree->iDepth);
+        pRoot->isDirty = 1;
       }
     }
 
@@ -118749,7 +122359,7 @@ static int rtreeInit(
   Rtree *pRtree;
   int nDb;              /* Length of string argv[1] */
   int nName;            /* Length of string argv[2] */
-  int eCoordType = (int)pAux;
+  int eCoordType = (pAux ? RTREE_COORD_INT32 : RTREE_COORD_REAL32);
 
   const char *aErrMsg[] = {
     0,                                                    /* 0 */
@@ -118846,6 +122456,7 @@ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
   Rtree tree;
   int ii;
 
+  UNUSED_PARAMETER(nArg);
   memset(&node, 0, sizeof(RtreeNode));
   memset(&tree, 0, sizeof(Rtree));
   tree.nDim = sqlite3_value_int(apArg[0]);
@@ -118879,6 +122490,7 @@ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
 }
 
 static void rtreedepth(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
+  UNUSED_PARAMETER(nArg);
   if( sqlite3_value_type(apArg[0])!=SQLITE_BLOB 
    || sqlite3_value_bytes(apArg[0])<2
   ){
@@ -118895,14 +122507,11 @@ static void rtreedepth(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
 ** function "rtreenode".
 */
 SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db){
-  int rc = SQLITE_OK;
+  const int utf8 = SQLITE_UTF8;
+  int rc;
 
+  rc = sqlite3_create_function(db, "rtreenode", 2, utf8, 0, rtreenode, 0, 0);
   if( rc==SQLITE_OK ){
-    int utf8 = SQLITE_UTF8;
-    rc = sqlite3_create_function(db, "rtreenode", 2, utf8, 0, rtreenode, 0, 0);
-  }
-  if( rc==SQLITE_OK ){
-    int utf8 = SQLITE_UTF8;
     rc = sqlite3_create_function(db, "rtreedepth", 1, utf8, 0,rtreedepth, 0, 0);
   }
   if( rc==SQLITE_OK ){
@@ -118917,6 +122526,70 @@ SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db){
   return rc;
 }
 
+/*
+** A version of sqlite3_free() that can be used as a callback. This is used
+** in two places - as the destructor for the blob value returned by the
+** invocation of a geometry function, and as the destructor for the geometry
+** functions themselves.
+*/
+static void doSqlite3Free(void *p){
+  sqlite3_free(p);
+}
+
+/*
+** Each call to sqlite3_rtree_geometry_callback() creates an ordinary SQLite
+** scalar user function. This C function is the callback used for all such
+** registered SQL functions.
+**
+** The scalar user functions return a blob that is interpreted by r-tree
+** table MATCH operators.
+*/
+static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
+  RtreeGeomCallback *pGeomCtx = (RtreeGeomCallback *)sqlite3_user_data(ctx);
+  RtreeMatchArg *pBlob;
+  int nBlob;
+
+  nBlob = sizeof(RtreeMatchArg) + (nArg-1)*sizeof(double);
+  pBlob = (RtreeMatchArg *)sqlite3_malloc(nBlob);
+  if( !pBlob ){
+    sqlite3_result_error_nomem(ctx);
+  }else{
+    int i;
+    pBlob->magic = RTREE_GEOMETRY_MAGIC;
+    pBlob->xGeom = pGeomCtx->xGeom;
+    pBlob->pContext = pGeomCtx->pContext;
+    pBlob->nParam = nArg;
+    for(i=0; i<nArg; i++){
+      pBlob->aParam[i] = sqlite3_value_double(aArg[i]);
+    }
+    sqlite3_result_blob(ctx, pBlob, nBlob, doSqlite3Free);
+  }
+}
+
+/*
+** Register a new geometry function for use with the r-tree MATCH operator.
+*/
+SQLITE_API int sqlite3_rtree_geometry_callback(
+  sqlite3 *db,
+  const char *zGeom,
+  int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *),
+  void *pContext
+){
+  RtreeGeomCallback *pGeomCtx;      /* Context object for new user-function */
+
+  /* Allocate and populate the context object. */
+  pGeomCtx = (RtreeGeomCallback *)sqlite3_malloc(sizeof(RtreeGeomCallback));
+  if( !pGeomCtx ) return SQLITE_NOMEM;
+  pGeomCtx->xGeom = xGeom;
+  pGeomCtx->pContext = pContext;
+
+  /* Create the new user-function. Register a destructor function to delete
+  ** the context object when it is no longer required.  */
+  return sqlite3_create_function_v2(db, zGeom, -1, SQLITE_ANY, 
+      (void *)pGeomCtx, geomCallback, 0, 0, doSqlite3Free
+  );
+}
+
 #if !SQLITE_CORE
 SQLITE_API int sqlite3_extension_init(
   sqlite3 *db,
diff --git a/libgda/sqlite/sqlite-src/sqlite3.h b/libgda/sqlite/sqlite-src/sqlite3.h
index ceca47a..75f96dd 100644
--- a/libgda/sqlite/sqlite-src/sqlite3.h
+++ b/libgda/sqlite/sqlite-src/sqlite3.h
@@ -107,9 +107,9 @@ extern "C" {
 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
 ** [sqlite_version()] and [sqlite_source_id()].
 */
-#define SQLITE_VERSION        "3.7.2"
-#define SQLITE_VERSION_NUMBER 3007002
-#define SQLITE_SOURCE_ID      "2010-08-23 18:52:01 42537b60566f288167f1b5864a5435986838e3a3"
+#define SQLITE_VERSION        "3.7.5"
+#define SQLITE_VERSION_NUMBER 3007005
+#define SQLITE_SOURCE_ID      "2011-01-28 17:03:50 ed759d5a9edb3bba5f48f243df47be29e3fe8cd7"
 
 /*
 ** CAPI3REF: Run-Time Library Version Numbers
@@ -390,7 +390,7 @@ SQLITE_API int sqlite3_exec(
 #define SQLITE_INTERRUPT    9   /* Operation terminated by sqlite3_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   /* NOT USED. Table or record not found */
+#define SQLITE_NOTFOUND    12   /* Unknown opcode in sqlite3_file_control() */
 #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 */
@@ -542,6 +542,18 @@ SQLITE_API int sqlite3_exec(
 ** equal SQLITE_SYNC_NORMAL, that means to use normal fsync() semantics.
 ** If the lower four bits equal SQLITE_SYNC_FULL, that means
 ** to use Mac OS X style fullsync instead of fsync().
+**
+** Do not confuse the SQLITE_SYNC_NORMAL and SQLITE_SYNC_FULL flags
+** with the [PRAGMA synchronous]=NORMAL and [PRAGMA synchronous]=FULL
+** settings.  The [synchronous pragma] determines when calls to the
+** xSync VFS method occur and applies uniformly across all platforms.
+** The SQLITE_SYNC_NORMAL and SQLITE_SYNC_FULL flags determine how
+** energetic or rigorous or forceful the sync operations are and
+** only make a difference on Mac OSX for the default SQLite code.
+** (Third-party VFS implementations might also make the distinction
+** between SQLITE_SYNC_NORMAL and SQLITE_SYNC_FULL, but among the
+** operating systems natively supported by SQLite, only Mac OSX
+** cares about the difference.)
 */
 #define SQLITE_SYNC_NORMAL        0x00002
 #define SQLITE_SYNC_FULL          0x00003
@@ -610,7 +622,9 @@ struct sqlite3_file {
 ** core reserves all opcodes less than 100 for its own use.
 ** A [SQLITE_FCNTL_LOCKSTATE | list of opcodes] less than 100 is available.
 ** Applications that define a custom xFileControl method should use opcodes
-** greater than 100 to avoid conflicts.
+** greater than 100 to avoid conflicts.  VFS implementations should
+** return [SQLITE_NOTFOUND] for file control opcodes that they do not
+** recognize.
 **
 ** The xSectorSize() method returns the sector size of the
 ** device that underlies the file.  The sector size is the
@@ -703,6 +717,21 @@ struct sqlite3_io_methods {
 ** for the nominated database. Allocating database file space in large
 ** chunks (say 1MB at a time), may reduce file-system fragmentation and
 ** improve performance on some systems.
+**
+** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer
+** to the [sqlite3_file] object associated with a particular database
+** connection.  See the [sqlite3_file_control()] documentation for
+** additional information.
+**
+** ^(The [SQLITE_FCNTL_SYNC_OMITTED] opcode is generated internally by
+** SQLite and sent to all VFSes in place of a call to the xSync method
+** when the database connection has [PRAGMA synchronous] set to OFF.)^
+** Some specialized VFSes need this signal in order to operate correctly
+** when [PRAGMA synchronous | PRAGMA synchronous=OFF] is set, but most 
+** VFSes do not need this signal and should silently ignore this opcode.
+** Applications should not call [sqlite3_file_control()] with this
+** opcode as doing so may disrupt the operation of the specilized VFSes
+** that do require it.  
 */
 #define SQLITE_FCNTL_LOCKSTATE        1
 #define SQLITE_GET_LOCKPROXYFILE      2
@@ -710,6 +739,9 @@ struct sqlite3_io_methods {
 #define SQLITE_LAST_ERRNO             4
 #define SQLITE_FCNTL_SIZE_HINT        5
 #define SQLITE_FCNTL_CHUNK_SIZE       6
+#define SQLITE_FCNTL_FILE_POINTER     7
+#define SQLITE_FCNTL_SYNC_OMITTED     8
+
 
 /*
 ** CAPI3REF: Mutex Handle
@@ -757,15 +789,19 @@ typedef struct sqlite3_mutex sqlite3_mutex;
 ** The zName field holds the name of the VFS module.  The name must
 ** be unique across all VFS modules.
 **
-** SQLite will guarantee that the zFilename parameter to xOpen
+** ^SQLite guarantees that the zFilename parameter to xOpen
 ** is either a NULL pointer or string obtained
-** from xFullPathname().  SQLite further guarantees that
+** from xFullPathname() with an optional suffix added.
+** ^If a suffix is added to the zFilename parameter, it will
+** consist of a single "-" character followed by no more than
+** 10 alphanumeric and/or "-" characters.
+** ^SQLite further guarantees that
 ** the string will be valid and unchanged until xClose() is
 ** called. Because of the previous sentence,
 ** the [sqlite3_file] can safely store a pointer to the
 ** filename if it needs to remember the filename for some reason.
-** If the zFilename parameter is xOpen is a NULL pointer then xOpen
-** must invent its own temporary name for the file.  Whenever the 
+** If the zFilename parameter to xOpen is a NULL pointer then xOpen
+** must invent its own temporary name for the file.  ^Whenever the 
 ** xFilename parameter is NULL it will also be the case that the
 ** flags parameter will include [SQLITE_OPEN_DELETEONCLOSE].
 **
@@ -776,7 +812,7 @@ typedef struct sqlite3_mutex sqlite3_mutex;
 ** If xOpen() opens a file read-only then it sets *pOutFlags to
 ** include [SQLITE_OPEN_READONLY].  Other bits in *pOutFlags may be set.
 **
-** SQLite will also add one of the following flags to the xOpen()
+** ^(SQLite will also add one of the following flags to the xOpen()
 ** call, depending on the object being opened:
 **
 ** <ul>
@@ -787,7 +823,8 @@ typedef struct sqlite3_mutex sqlite3_mutex;
 ** <li>  [SQLITE_OPEN_TRANSIENT_DB]
 ** <li>  [SQLITE_OPEN_SUBJOURNAL]
 ** <li>  [SQLITE_OPEN_MASTER_JOURNAL]
-** </ul>
+** <li>  [SQLITE_OPEN_WAL]
+** </ul>)^
 **
 ** The file I/O implementation can use the object type flags to
 ** change the way it deals with files.  For example, an application
@@ -806,10 +843,11 @@ typedef struct sqlite3_mutex sqlite3_mutex;
 ** </ul>
 **
 ** The [SQLITE_OPEN_DELETEONCLOSE] flag means the file should be
-** deleted when it is closed.  The [SQLITE_OPEN_DELETEONCLOSE]
-** will be set for TEMP  databases, journals and for subjournals.
+** deleted when it is closed.  ^The [SQLITE_OPEN_DELETEONCLOSE]
+** will be set for TEMP databases and their journals, transient
+** databases, and subjournals.
 **
-** The [SQLITE_OPEN_EXCLUSIVE] flag is always used in conjunction
+** ^The [SQLITE_OPEN_EXCLUSIVE] flag is always used in conjunction
 ** with the [SQLITE_OPEN_CREATE] flag, which are both directly
 ** analogous to the O_EXCL and O_CREAT flags of the POSIX open()
 ** API.  The SQLITE_OPEN_EXCLUSIVE flag, when paired with the 
@@ -818,7 +856,7 @@ typedef struct sqlite3_mutex sqlite3_mutex;
 ** It is <i>not</i> used to indicate the file should be opened 
 ** for exclusive access.
 **
-** At least szOsFile bytes of memory are allocated by SQLite
+** ^At least szOsFile bytes of memory are allocated by SQLite
 ** to hold the  [sqlite3_file] structure passed as the third
 ** argument to xOpen.  The xOpen method does not have to
 ** allocate the structure; it should just fill it in.  Note that
@@ -828,13 +866,13 @@ typedef struct sqlite3_mutex sqlite3_mutex;
 ** element will be valid after xOpen returns regardless of the success
 ** or failure of the xOpen call.
 **
-** The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS]
+** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS]
 ** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to
 ** test whether a file is readable and writable, or [SQLITE_ACCESS_READ]
 ** to test whether a file is at least readable.   The file can be a
 ** directory.
 **
-** SQLite will always allocate at least mxPathname+1 bytes for the
+** ^SQLite will always allocate at least mxPathname+1 bytes for the
 ** output buffer xFullPathname.  The exact size of the output buffer
 ** is also passed as a parameter to both  methods. If the output buffer
 ** is not large enough, [SQLITE_CANTOPEN] should be returned. Since this is
@@ -848,10 +886,10 @@ typedef struct sqlite3_mutex sqlite3_mutex;
 ** of good-quality randomness into zOut.  The return value is
 ** the actual number of bytes of randomness obtained.
 ** The xSleep() method causes the calling thread to sleep for at
-** least the number of microseconds given.  The xCurrentTime()
+** least the number of microseconds given.  ^The xCurrentTime()
 ** method returns a Julian Day Number for the current date and time as
 ** a floating point value.
-** The xCurrentTimeInt64() method returns, as an integer, the Julian
+** ^The xCurrentTimeInt64() method returns, as an integer, the Julian
 ** Day Number multipled by 86400000 (the number of milliseconds in 
 ** a 24-hour day).  
 ** ^SQLite will use the xCurrentTimeInt64() method to get the current
@@ -1248,7 +1286,7 @@ struct sqlite3_mem_methods {
 **   <ul>
 **   <li> [sqlite3_memory_used()]
 **   <li> [sqlite3_memory_highwater()]
-**   <li> [sqlite3_soft_heap_limit()]
+**   <li> [sqlite3_soft_heap_limit64()]
 **   <li> [sqlite3_status()]
 **   </ul>)^
 ** ^Memory allocation statistics are enabled by default unless SQLite is
@@ -1262,15 +1300,14 @@ struct sqlite3_mem_methods {
 ** aligned memory buffer from which the scrach allocations will be
 ** drawn, the size of each scratch allocation (sz),
 ** and the maximum number of scratch allocations (N).  The sz
-** argument must be a multiple of 16. The sz parameter should be a few bytes
-** larger than the actual scratch space required due to internal overhead.
+** argument must be a multiple of 16.
 ** The first argument must be a pointer to an 8-byte aligned buffer
 ** of at least sz*N bytes of memory.
-** ^SQLite will use no more than one scratch buffer per thread.  So
-** N should be set to the expected maximum number of threads.  ^SQLite will
-** never require a scratch buffer that is more than 6 times the database
-** page size. ^If SQLite needs needs additional scratch memory beyond 
-** what is provided by this configuration option, then 
+** ^SQLite will use no more than two scratch buffers per thread.  So
+** N should be set to twice the expected maximum number of threads.
+** ^SQLite will never require a scratch buffer that is more than 6
+** times the database page size. ^If SQLite needs needs additional
+** scratch memory beyond what is provided by this configuration option, then 
 ** [sqlite3_malloc()] will be used to obtain the memory needed.</dd>
 **
 ** <dt>SQLITE_CONFIG_PAGECACHE</dt>
@@ -1290,8 +1327,7 @@ struct sqlite3_mem_methods {
 ** memory needs for the first N pages that it adds to cache.  ^If additional
 ** page cache memory is needed beyond what is provided by this option, then
 ** SQLite goes to [sqlite3_malloc()] for the additional storage space.
-** ^The implementation might use one or more of the N buffers to hold 
-** memory accounting information. The pointer in the first argument must
+** The pointer in the first argument must
 ** be aligned to an 8-byte boundary or subsequent behavior of SQLite
 ** will be undefined.</dd>
 **
@@ -1420,8 +1456,14 @@ struct sqlite3_mem_methods {
 ** or equal to the product of the second and third arguments.  The buffer
 ** must be aligned to an 8-byte boundary.  ^If the second argument to
 ** SQLITE_DBCONFIG_LOOKASIDE is not a multiple of 8, it is internally
-** rounded down to the next smaller
-** multiple of 8.  See also: [SQLITE_CONFIG_LOOKASIDE]</dd>
+** rounded down to the next smaller multiple of 8.  ^(The lookaside memory
+** configuration for a database connection can only be changed when that
+** connection is not currently using lookaside memory, or in other words
+** when the "current value" returned by
+** [sqlite3_db_status](D,[SQLITE_CONFIG_LOOKASIDE],...) is zero.
+** Any attempt to change the lookaside memory configuration when lookaside
+** memory is in use leaves the configuration unchanged and returns 
+** [SQLITE_BUSY].)^</dd>
 **
 ** </dl>
 */
@@ -1726,6 +1768,9 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
 /*
 ** CAPI3REF: Convenience Routines For Running Queries
 **
+** This is a legacy interface that is preserved for backwards compatibility.
+** Use of this interface is not recommended.
+**
 ** Definition: A <b>result table</b> is memory data structure created by the
 ** [sqlite3_get_table()] interface.  A result table records the
 ** complete query results from one or more queries.
@@ -1746,7 +1791,7 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
 ** It is not safe to pass a result table directly to [sqlite3_free()].
 ** A result table should be deallocated using [sqlite3_free_table()].
 **
-** As an example of the result table format, suppose a query result
+** ^(As an example of the result table format, suppose a query result
 ** is as follows:
 **
 ** <blockquote><pre>
@@ -1770,7 +1815,7 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
 **        azResult&#91;5] = "28";
 **        azResult&#91;6] = "Cindy";
 **        azResult&#91;7] = "21";
-** </pre></blockquote>
+** </pre></blockquote>)^
 **
 ** ^The sqlite3_get_table() function evaluates one or more
 ** semicolon-separated SQL statements in the zero-terminated UTF-8
@@ -1778,19 +1823,19 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
 ** pointer given in its 3rd parameter.
 **
 ** After the application has finished with the result from sqlite3_get_table(),
-** it should pass the result table pointer to sqlite3_free_table() in order to
+** it must pass the result table pointer to sqlite3_free_table() in order to
 ** release the memory that was malloced.  Because of the way the
 ** [sqlite3_malloc()] happens within sqlite3_get_table(), the calling
 ** function must not try to call [sqlite3_free()] directly.  Only
 ** [sqlite3_free_table()] is able to release the memory properly and safely.
 **
-** ^(The sqlite3_get_table() interface is implemented as a wrapper around
+** The sqlite3_get_table() interface is implemented as a wrapper around
 ** [sqlite3_exec()].  The sqlite3_get_table() routine does not have access
 ** to any internal data structures of SQLite.  It uses only the public
 ** interface defined here.  As a consequence, errors that occur in the
 ** wrapper layer outside of the internal [sqlite3_exec()] call are not
 ** reflected in subsequent calls to [sqlite3_errcode()] or
-** [sqlite3_errmsg()].)^
+** [sqlite3_errmsg()].
 */
 SQLITE_API int sqlite3_get_table(
   sqlite3 *db,          /* An open database */
@@ -1815,7 +1860,7 @@ SQLITE_API void sqlite3_free_table(char **result);
 ** NULL pointer if [sqlite3_malloc()] is unable to allocate enough
 ** memory to hold the resulting string.
 **
-** ^(In sqlite3_snprintf() routine is similar to "snprintf()" from
+** ^(The sqlite3_snprintf() routine is similar to "snprintf()" from
 ** the standard C library.  The result is written into the
 ** buffer supplied as the second parameter whose size is given by
 ** the first parameter. Note that the order of the
@@ -1834,6 +1879,8 @@ SQLITE_API void sqlite3_free_table(char **result);
 ** the zero terminator.  So the longest string that can be completely
 ** written will be n-1 characters.
 **
+** ^The sqlite3_vsnprintf() routine is a varargs version of sqlite3_snprintf().
+**
 ** These routines all implement some additional formatting
 ** options that are useful for constructing SQL statements.
 ** All of the usual printf() formatting options apply.  In addition, there
@@ -1897,6 +1944,7 @@ SQLITE_API void sqlite3_free_table(char **result);
 SQLITE_API char *sqlite3_mprintf(const char*,...);
 SQLITE_API char *sqlite3_vmprintf(const char*, va_list);
 SQLITE_API char *sqlite3_snprintf(int,char*,const char*, ...);
+SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
 
 /*
 ** CAPI3REF: Memory Allocation Subsystem
@@ -1942,7 +1990,9 @@ SQLITE_API char *sqlite3_snprintf(int,char*,const char*, ...);
 ** is not freed.
 **
 ** ^The memory returned by sqlite3_malloc() and sqlite3_realloc()
-** is always aligned to at least an 8 byte boundary.
+** is always aligned to at least an 8 byte boundary, or to a
+** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time
+** option is used.
 **
 ** In SQLite version 3.5.0 and 3.5.1, it was possible to define
 ** the SQLITE_OMIT_MEMORY_ALLOCATION which would cause the built-in
@@ -2200,17 +2250,28 @@ SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*,
 /*
 ** CAPI3REF: Query Progress Callbacks
 **
-** ^This routine configures a callback function - the
-** progress callback - that is invoked periodically during long
-** running calls to [sqlite3_exec()], [sqlite3_step()] and
-** [sqlite3_get_table()].  An example use for this
+** ^The sqlite3_progress_handler(D,N,X,P) interface causes the callback
+** function X to be invoked periodically during long running calls to
+** [sqlite3_exec()], [sqlite3_step()] and [sqlite3_get_table()] for
+** database connection D.  An example use for this
 ** interface is to keep a GUI updated during a large query.
 **
+** ^The parameter P is passed through as the only parameter to the 
+** callback function X.  ^The parameter N is the number of 
+** [virtual machine instructions] that are evaluated between successive
+** invocations of the callback X.
+**
+** ^Only a single progress handler may be defined at one time per
+** [database connection]; setting a new progress handler cancels the
+** old one.  ^Setting parameter X to NULL disables the progress handler.
+** ^The progress handler is also disabled by setting N to a value less
+** than 1.
+**
 ** ^If the progress callback returns non-zero, the operation is
 ** interrupted.  This feature can be used to implement a
 ** "Cancel" button on a GUI progress dialog box.
 **
-** The progress handler must not do anything that will modify
+** The progress handler callback must not do anything that will modify
 ** the database connection that invoked the progress handler.
 ** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their
 ** database connections for the meaning of "modify" in this paragraph.
@@ -2261,7 +2322,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
 ** case the database must already exist, otherwise an error is returned.</dd>)^
 **
 ** ^(<dt>[SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]</dt>
-** <dd>The database is opened for reading and writing, and is creates it if
+** <dd>The database is opened for reading and writing, and is created if
 ** it does not already exist. This is the behavior that is always used for
 ** sqlite3_open() and sqlite3_open16().</dd>)^
 ** </dl>
@@ -2269,7 +2330,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
 ** If the 3rd parameter to sqlite3_open_v2() is not one of the
 ** combinations shown above or one of the combinations shown above combined
 ** with the [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX],
-** [SQLITE_OPEN_SHAREDCACHE] and/or [SQLITE_OPEN_SHAREDCACHE] flags,
+** [SQLITE_OPEN_SHAREDCACHE] and/or [SQLITE_OPEN_PRIVATECACHE] flags,
 ** then the behavior is undefined.
 **
 ** ^If the [SQLITE_OPEN_NOMUTEX] flag is set, then the database connection
@@ -2394,17 +2455,22 @@ typedef struct sqlite3_stmt sqlite3_stmt;
 ** [database connection] whose limit is to be set or queried.  The
 ** second parameter is one of the [limit categories] that define a
 ** class of constructs to be size limited.  The third parameter is the
-** new limit for that construct.  The function returns the old limit.)^
+** new limit for that construct.)^
 **
 ** ^If the new limit is a negative number, the limit is unchanged.
-** ^(For the limit category of SQLITE_LIMIT_XYZ there is a 
+** ^(For each limit category SQLITE_LIMIT_<i>NAME</i> there is a 
 ** [limits | hard upper bound]
-** set by a compile-time C preprocessor macro named 
-** [limits | SQLITE_MAX_XYZ].
+** set at compile-time by a C preprocessor macro called
+** [limits | SQLITE_MAX_<i>NAME</i>].
 ** (The "_LIMIT_" in the name is changed to "_MAX_".))^
 ** ^Attempts to increase a limit above its hard upper bound are
 ** silently truncated to the hard upper bound.
 **
+** ^Regardless of whether or not the limit was changed, the 
+** [sqlite3_limit()] interface returns the prior value of the limit.
+** ^Hence, to find the current value of a limit without changing it,
+** simply invoke this interface with the third parameter set to -1.
+**
 ** Run-time limits are intended for use in applications that manage
 ** both their own internal database and also databases that are controlled
 ** by untrusted external sources.  An example application might be a
@@ -2433,7 +2499,7 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
 **
 ** <dl>
 ** ^(<dt>SQLITE_LIMIT_LENGTH</dt>
-** <dd>The maximum size of any string or BLOB or table row.<dd>)^
+** <dd>The maximum size of any string or BLOB or table row, in bytes.<dd>)^
 **
 ** ^(<dt>SQLITE_LIMIT_SQL_LENGTH</dt>
 ** <dd>The maximum length of an SQL statement, in bytes.</dd>)^
@@ -2451,7 +2517,9 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
 **
 ** ^(<dt>SQLITE_LIMIT_VDBE_OP</dt>
 ** <dd>The maximum number of instructions in a virtual machine program
-** used to implement an SQL statement.</dd>)^
+** used to implement an SQL statement.  This limit is not currently
+** enforced, though that might be added in some future release of
+** SQLite.</dd>)^
 **
 ** ^(<dt>SQLITE_LIMIT_FUNCTION_ARG</dt>
 ** <dd>The maximum number of arguments on a function.</dd>)^
@@ -2464,8 +2532,7 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
 ** [GLOB] operators.</dd>)^
 **
 ** ^(<dt>SQLITE_LIMIT_VARIABLE_NUMBER</dt>
-** <dd>The maximum number of variables in an SQL statement that can
-** be bound.</dd>)^
+** <dd>The maximum index number of any [parameter] in an SQL statement.)^
 **
 ** ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt>
 ** <dd>The maximum depth of recursion for triggers.</dd>)^
@@ -2537,12 +2604,7 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
 ** <li>
 ** ^If the database schema changes, instead of returning [SQLITE_SCHEMA] as it
 ** always used to do, [sqlite3_step()] will automatically recompile the SQL
-** statement and try to run it again.  ^If the schema has changed in
-** a way that makes the statement no longer valid, [sqlite3_step()] will still
-** return [SQLITE_SCHEMA].  But unlike the legacy behavior, [SQLITE_SCHEMA] is
-** now a fatal error.  Calling [sqlite3_prepare_v2()] again will not make the
-** error go away.  Note: use [sqlite3_errmsg()] to find the text
-** of the parsing error that results in an [SQLITE_SCHEMA] return.
+** statement and try to run it again.
 ** </li>
 **
 ** <li>
@@ -2555,11 +2617,16 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
 ** </li>
 **
 ** <li>
-** ^If the value of a [parameter | host parameter] in the WHERE clause might
-** change the query plan for a statement, then the statement may be
-** automatically recompiled (as if there had been a schema change) on the first 
-** [sqlite3_step()] call following any change to the 
-** [sqlite3_bind_text | bindings] of the [parameter]. 
+** ^If the specific value bound to [parameter | host parameter] in the 
+** WHERE clause might influence the choice of query plan for a statement,
+** then the statement will be automatically recompiled, as if there had been 
+** a schema change, on the first  [sqlite3_step()] call following any change
+** to the [sqlite3_bind_text | bindings] of that [parameter]. 
+** ^The specific value of WHERE-clause [parameter] might influence the 
+** choice of query plan if the parameter is the left-hand side of a [LIKE]
+** or [GLOB] operator or if the parameter is compared to an indexed column
+** and the [SQLITE_ENABLE_STAT2] compile-time option is enabled.
+** the 
 ** </li>
 ** </ol>
 */
@@ -2602,6 +2669,37 @@ SQLITE_API int sqlite3_prepare16_v2(
 SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
 
 /*
+** CAPI3REF: Determine If An SQL Statement Writes The Database
+**
+** ^The sqlite3_stmt_readonly(X) interface returns true (non-zero) if 
+** and only if the [prepared statement] X makes no direct changes to
+** the content of the database file.
+**
+** Note that [application-defined SQL functions] or
+** [virtual tables] might change the database indirectly as a side effect.  
+** ^(For example, if an application defines a function "eval()" that 
+** calls [sqlite3_exec()], then the following SQL statement would
+** change the database file through side-effects:
+**
+** <blockquote><pre>
+**    SELECT eval('DELETE FROM t1') FROM t2;
+** </pre></blockquote>
+**
+** But because the [SELECT] statement does not change the database file
+** directly, sqlite3_stmt_readonly() would still return true.)^
+**
+** ^Transaction control statements such as [BEGIN], [COMMIT], [ROLLBACK],
+** [SAVEPOINT], and [RELEASE] cause sqlite3_stmt_readonly() to return true,
+** since the statements themselves do not actually modify the database but
+** rather they control the timing of when other statements modify the 
+** database.  ^The [ATTACH] and [DETACH] statements also cause
+** sqlite3_stmt_readonly() to return true since, while those statements
+** change the configuration of a database connection, they do not make 
+** changes to the content of the database files on disk.
+*/
+SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
+
+/*
 ** CAPI3REF: Dynamically Typed Value Object
 ** KEYWORDS: {protected sqlite3_value} {unprotected sqlite3_value}
 **
@@ -2626,7 +2724,7 @@ SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
 ** then there is no distinction between protected and unprotected
 ** sqlite3_value objects and they can be used interchangeably.  However,
 ** for maximum code portability it is recommended that applications
-** still make the distinction between between protected and unprotected
+** still make the distinction between protected and unprotected
 ** sqlite3_value objects even when not strictly required.
 **
 ** ^The sqlite3_value objects that are passed as parameters into the
@@ -2700,7 +2798,10 @@ typedef struct sqlite3_context sqlite3_context;
 **
 ** ^The fifth argument to sqlite3_bind_blob(), sqlite3_bind_text(), and
 ** sqlite3_bind_text16() is a destructor used to dispose of the BLOB or
-** string after SQLite has finished with it. ^If the fifth argument is
+** string after SQLite has finished with it.  ^The destructor is called
+** to dispose of the BLOB or string even if the call to sqlite3_bind_blob(),
+** sqlite3_bind_text(), or sqlite3_bind_text16() fails.  
+** ^If the fifth argument is
 ** the special value [SQLITE_STATIC], then SQLite assumes that the
 ** information is in static, unmanaged space and does not need to be freed.
 ** ^If the fifth argument has the value [SQLITE_TRANSIENT], then
@@ -2821,6 +2922,8 @@ SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*);
 ** ^Return the number of columns in the result set returned by the
 ** [prepared statement]. ^This routine returns 0 if pStmt is an SQL
 ** statement that does not return data (for example an [UPDATE]).
+**
+** See also: [sqlite3_data_count()]
 */
 SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt);
 
@@ -2986,13 +3089,17 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
 ** be the case that the same database connection is being used by two or
 ** more threads at the same moment in time.
 **
-** For all versions of SQLite up to and including 3.6.23.1, it was required
-** after sqlite3_step() returned anything other than [SQLITE_ROW] that
-** [sqlite3_reset()] be called before any subsequent invocation of
-** sqlite3_step().  Failure to invoke [sqlite3_reset()] in this way would
-** result in an [SQLITE_MISUSE] return from sqlite3_step().  But after
-** version 3.6.23.1, sqlite3_step() began calling [sqlite3_reset()] 
-** automatically in this circumstance rather than returning [SQLITE_MISUSE].  
+** For all versions of SQLite up to and including 3.6.23.1, a call to
+** [sqlite3_reset()] was required after sqlite3_step() returned anything
+** other than [SQLITE_ROW] before any subsequent invocation of
+** sqlite3_step().  Failure to reset the prepared statement using 
+** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from
+** sqlite3_step().  But after version 3.6.23.1, sqlite3_step() began
+** calling [sqlite3_reset()] automatically in this circumstance rather
+** than returning [SQLITE_MISUSE].  This is not considered a compatibility
+** break because any application that ever receives an SQLITE_MISUSE error
+** is broken by definition.  The [SQLITE_OMIT_AUTORESET] compile-time option
+** can be used to restore the legacy behavior.
 **
 ** <b>Goofy Interface Alert:</b> In the legacy interface, the sqlite3_step()
 ** API always returns a generic error code, [SQLITE_ERROR], following any
@@ -3011,8 +3118,14 @@ SQLITE_API int sqlite3_step(sqlite3_stmt*);
 /*
 ** CAPI3REF: Number of columns in a result set
 **
-** ^The sqlite3_data_count(P) the number of columns in the
-** of the result set of [prepared statement] P.
+** ^The sqlite3_data_count(P) interface returns the number of columns in the
+** current row of the result set of [prepared statement] P.
+** ^If prepared statement P does not have results ready to return
+** (via calls to the [sqlite3_column_int | sqlite3_column_*()] of
+** interfaces) then sqlite3_data_count(P) returns 0.
+** ^The sqlite3_data_count(P) routine also returns 0 if P is a NULL pointer.
+**
+** See also: [sqlite3_column_count()]
 */
 SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
 
@@ -3092,18 +3205,26 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
 ** ^If the result is a numeric value then sqlite3_column_bytes() uses
 ** [sqlite3_snprintf()] to convert that value to a UTF-8 string and returns
 ** the number of bytes in that string.
-** ^The value returned does not include the zero terminator at the end
-** of the string.  ^For clarity: the value returned is the number of
+** ^If the result is NULL, then sqlite3_column_bytes() returns zero.
+**
+** ^If the result is a BLOB or UTF-16 string then the sqlite3_column_bytes16()
+** routine returns the number of bytes in that BLOB or string.
+** ^If the result is a UTF-8 string, then sqlite3_column_bytes16() converts
+** the string to UTF-16 and then returns the number of bytes.
+** ^If the result is a numeric value then sqlite3_column_bytes16() uses
+** [sqlite3_snprintf()] to convert that value to a UTF-16 string and returns
+** the number of bytes in that string.
+** ^If the result is NULL, then sqlite3_column_bytes16() returns zero.
+**
+** ^The values returned by [sqlite3_column_bytes()] and 
+** [sqlite3_column_bytes16()] do not include the zero terminators at the end
+** of the string.  ^For clarity: the values returned by
+** [sqlite3_column_bytes()] and [sqlite3_column_bytes16()] are the number of
 ** bytes in the string, not the number of characters.
 **
 ** ^Strings returned by sqlite3_column_text() and sqlite3_column_text16(),
 ** even empty strings, are always zero terminated.  ^The return
-** value from sqlite3_column_blob() for a zero-length BLOB is an arbitrary
-** pointer, possibly even a NULL pointer.
-**
-** ^The sqlite3_column_bytes16() routine is similar to sqlite3_column_bytes()
-** but leaves the result in UTF-16 in native byte order instead of UTF-8.
-** ^The zero terminator is not included in this count.
+** value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer.
 **
 ** ^The object returned by [sqlite3_column_value()] is an
 ** [unprotected sqlite3_value] object.  An unprotected sqlite3_value object
@@ -3148,10 +3269,10 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
 ** used in the table for brevity and because they are familiar to most
 ** C programmers.
 **
-** ^Note that when type conversions occur, pointers returned by prior
+** Note that when type conversions occur, pointers returned by prior
 ** calls to sqlite3_column_blob(), sqlite3_column_text(), and/or
 ** sqlite3_column_text16() may be invalidated.
-** ^(Type conversions and pointer invalidations might occur
+** Type conversions and pointer invalidations might occur
 ** in the following cases:
 **
 ** <ul>
@@ -3164,22 +3285,22 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
 ** <li> The initial content is UTF-16 text and sqlite3_column_bytes() or
 **      sqlite3_column_text() is called.  The content must be converted
 **      to UTF-8.</li>
-** </ul>)^
+** </ul>
 **
 ** ^Conversions between UTF-16be and UTF-16le are always done in place and do
 ** not invalidate a prior pointer, though of course the content of the buffer
-** that the prior pointer points to will have been modified.  Other kinds
+** that the prior pointer references will have been modified.  Other kinds
 ** of conversion are done in place when it is possible, but sometimes they
 ** are not possible and in those cases prior pointers are invalidated.
 **
-** ^(The safest and easiest to remember policy is to invoke these routines
+** The safest and easiest to remember policy is to invoke these routines
 ** in one of the following ways:
 **
 ** <ul>
 **  <li>sqlite3_column_text() followed by sqlite3_column_bytes()</li>
 **  <li>sqlite3_column_blob() followed by sqlite3_column_bytes()</li>
 **  <li>sqlite3_column_text16() followed by sqlite3_column_bytes16()</li>
-** </ul>)^
+** </ul>
 **
 ** In other words, you should call sqlite3_column_text(),
 ** sqlite3_column_blob(), or sqlite3_column_text16() first to force the result
@@ -3217,17 +3338,26 @@ SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
 ** CAPI3REF: Destroy A Prepared Statement Object
 **
 ** ^The sqlite3_finalize() function is called to delete a [prepared statement].
-** ^If the statement was executed successfully or not executed at all, then
-** SQLITE_OK is returned. ^If execution of the statement failed then an
-** [error code] or [extended error code] is returned.
-**
-** ^This routine can be called at any point during the execution of the
-** [prepared statement].  ^If the virtual machine has not
-** completed execution when this routine is called, that is like
-** encountering an error or an [sqlite3_interrupt | interrupt].
-** ^Incomplete updates may be rolled back and transactions canceled,
-** depending on the circumstances, and the
-** [error code] returned will be [SQLITE_ABORT].
+** ^If the most recent evaluation of the statement encountered no errors or
+** or if the statement is never been evaluated, then sqlite3_finalize() returns
+** SQLITE_OK.  ^If the most recent evaluation of statement S failed, then
+** sqlite3_finalize(S) returns the appropriate [error code] or
+** [extended error code].
+**
+** ^The sqlite3_finalize(S) routine can be called at any point during
+** the life cycle of [prepared statement] S:
+** before statement S is ever evaluated, after
+** one or more calls to [sqlite3_reset()], or after any call
+** to [sqlite3_step()] regardless of whether or not the statement has
+** completed execution.
+**
+** ^Invoking sqlite3_finalize() on a NULL pointer is a harmless no-op.
+**
+** The application must finalize every [prepared statement] in order to avoid
+** resource leaks.  It is a grievous error for the application to try to use
+** a prepared statement after it has been finalized.  Any use of a prepared
+** statement after it has been finalized can result in undefined and
+** undesirable behavior such as segfaults and heap corruption.
 */
 SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt);
 
@@ -3263,23 +3393,25 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
 ** KEYWORDS: {application-defined SQL function}
 ** KEYWORDS: {application-defined SQL functions}
 **
-** ^These two functions (collectively known as "function creation routines")
+** ^These functions (collectively known as "function creation routines")
 ** are used to add SQL functions or aggregates or to redefine the behavior
-** of existing SQL functions or aggregates.  The only difference between the
-** two is that the second parameter, the name of the (scalar) function or
-** aggregate, is encoded in UTF-8 for sqlite3_create_function() and UTF-16
-** for sqlite3_create_function16().
+** of existing SQL functions or aggregates.  The only differences between
+** these routines are the text encoding expected for
+** the the second parameter (the name of the function being created)
+** and the presence or absence of a destructor callback for
+** the application data pointer.
 **
 ** ^The first parameter is the [database connection] to which the SQL
 ** function is to be added.  ^If an application uses more than one database
 ** connection then application-defined SQL functions must be added
 ** to each database connection separately.
 **
-** The second parameter is the name of the SQL function to be created or
-** redefined.  ^The length of the name is limited to 255 bytes, exclusive of
-** the zero-terminator.  Note that the name length limit is in bytes, not
-** characters.  ^Any attempt to create a function with a longer name
-** will result in [SQLITE_ERROR] being returned.
+** ^The second parameter is the name of the SQL function to be created or
+** redefined.  ^The length of the name is limited to 255 bytes in a UTF-8
+** representation, exclusive of the zero-terminator.  ^Note that the name
+** length limit is in UTF-8 bytes, not characters nor UTF-16 bytes.  
+** ^Any attempt to create a function with a longer name
+** will result in [SQLITE_MISUSE] being returned.
 **
 ** ^The third parameter (nArg)
 ** is the number of arguments that the SQL function or
@@ -3289,10 +3421,10 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
 ** parameter is less than -1 or greater than 127 then the behavior is
 ** undefined.
 **
-** The fourth parameter, eTextRep, specifies what
+** ^The fourth parameter, eTextRep, specifies what
 ** [SQLITE_UTF8 | text encoding] this SQL function prefers for
-** its parameters.  Any SQL function implementation should be able to work
-** work with UTF-8, UTF-16le, or UTF-16be.  But some implementations may be
+** its parameters.  Every SQL function implementation must be able to work
+** with UTF-8, UTF-16le, or UTF-16be.  But some implementations may be
 ** more efficient with one encoding than another.  ^An application may
 ** invoke sqlite3_create_function() or sqlite3_create_function16() multiple
 ** times with the same function but with different values of eTextRep.
@@ -3304,13 +3436,24 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
 ** ^(The fifth parameter is an arbitrary pointer.  The implementation of the
 ** function can gain access to this pointer using [sqlite3_user_data()].)^
 **
-** The seventh, eighth and ninth parameters, xFunc, xStep and xFinal, are
+** ^The sixth, seventh and eighth parameters, xFunc, xStep and xFinal, are
 ** pointers to C-language functions that implement the SQL function or
 ** aggregate. ^A scalar SQL function requires an implementation of the xFunc
-** callback only; NULL pointers should be passed as the xStep and xFinal
+** callback only; NULL pointers must be passed as the xStep and xFinal
 ** parameters. ^An aggregate SQL function requires an implementation of xStep
-** and xFinal and NULL should be passed for xFunc. ^To delete an existing
-** SQL function or aggregate, pass NULL for all three function callbacks.
+** and xFinal and NULL pointer must be passed for xFunc. ^To delete an existing
+** SQL function or aggregate, pass NULL poiners for all three function
+** callbacks.
+**
+** ^(If the ninth parameter to sqlite3_create_function_v2() is not NULL,
+** then it is destructor for the application data pointer. 
+** The destructor is invoked when the function is deleted, either by being
+** overloaded or when the database connection closes.)^
+** ^The destructor is also invoked if the call to
+** sqlite3_create_function_v2() fails.
+** ^When the destructor callback of the tenth parameter is invoked, it
+** is passed a single argument which is a copy of the application data 
+** pointer which was the fifth parameter to sqlite3_create_function_v2().
 **
 ** ^It is permitted to register multiple implementations of the same
 ** functions with the same name but with either differing numbers of
@@ -3326,11 +3469,6 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
 ** between UTF8 and UTF16.
 **
 ** ^Built-in functions may be overloaded by new application-defined functions.
-** ^The first application-defined function with a given name overrides all
-** built-in functions in the same [database connection] with the same name.
-** ^Subsequent application-defined functions of the same name only override 
-** prior application-defined functions that are an exact match for the
-** number of parameters and preferred encoding.
 **
 ** ^An application-defined function is permitted to call other
 ** SQLite interfaces.  However, such calls must not
@@ -3357,6 +3495,17 @@ SQLITE_API int sqlite3_create_function16(
   void (*xStep)(sqlite3_context*,int,sqlite3_value**),
   void (*xFinal)(sqlite3_context*)
 );
+SQLITE_API int sqlite3_create_function_v2(
+  sqlite3 *db,
+  const char *zFunctionName,
+  int nArg,
+  int eTextRep,
+  void *pApp,
+  void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
+  void (*xStep)(sqlite3_context*,int,sqlite3_value**),
+  void (*xFinal)(sqlite3_context*),
+  void(*xDestroy)(void*)
+);
 
 /*
 ** CAPI3REF: Text Encodings
@@ -3400,7 +3549,7 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6
 ** The xFunc (for scalar functions) or xStep (for aggregates) parameters
 ** to [sqlite3_create_function()] and [sqlite3_create_function16()]
 ** define callbacks that implement the SQL functions and aggregates.
-** The 4th parameter to these callbacks is an array of pointers to
+** The 3rd parameter to these callbacks is an array of pointers to
 ** [protected sqlite3_value] objects.  There is one [sqlite3_value] object for
 ** each parameter to the SQL function.  These routines are used to
 ** extract values from the [sqlite3_value] objects.
@@ -3703,46 +3852,79 @@ SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n);
 /*
 ** CAPI3REF: Define New Collating Sequences
 **
-** These functions are used to add new collation sequences to the
-** [database connection] specified as the first argument.
+** ^These functions add, remove, or modify a [collation] associated
+** with the [database connection] specified as the first argument.
 **
-** ^The name of the new collation sequence is specified as a UTF-8 string
+** ^The name of the collation is a UTF-8 string
 ** for sqlite3_create_collation() and sqlite3_create_collation_v2()
-** and a UTF-16 string for sqlite3_create_collation16(). ^In all cases
-** the name is passed as the second function argument.
-**
-** ^The third argument may be one of the constants [SQLITE_UTF8],
-** [SQLITE_UTF16LE], or [SQLITE_UTF16BE], indicating that the user-supplied
-** routine expects to be passed pointers to strings encoded using UTF-8,
-** UTF-16 little-endian, or UTF-16 big-endian, respectively. ^The
-** third argument might also be [SQLITE_UTF16] to indicate that the routine
-** expects pointers to be UTF-16 strings in the native byte order, or the
-** argument can be [SQLITE_UTF16_ALIGNED] if the
-** the routine expects pointers to 16-bit word aligned strings
-** of UTF-16 in the native byte order.
-**
-** A pointer to the user supplied routine must be passed as the fifth
-** argument.  ^If it is NULL, this is the same as deleting the collation
-** sequence (so that SQLite cannot call it any more).
-** ^Each time the application supplied function is invoked, it is passed
-** as its first parameter a copy of the void* passed as the fourth argument
-** to sqlite3_create_collation() or sqlite3_create_collation16().
-**
-** ^The remaining arguments to the application-supplied routine are two strings,
-** each represented by a (length, data) pair and encoded in the encoding
-** that was passed as the third argument when the collation sequence was
-** registered.  The application defined collation routine should
-** return negative, zero or positive if the first string is less than,
-** equal to, or greater than the second string. i.e. (STRING1 - STRING2).
+** and a UTF-16 string in native byte order for sqlite3_create_collation16().
+** ^Collation names that compare equal according to [sqlite3_strnicmp()] are
+** considered to be the same name.
+**
+** ^(The third argument (eTextRep) must be one of the constants:
+** <ul>
+** <li> [SQLITE_UTF8],
+** <li> [SQLITE_UTF16LE],
+** <li> [SQLITE_UTF16BE],
+** <li> [SQLITE_UTF16], or
+** <li> [SQLITE_UTF16_ALIGNED].
+** </ul>)^
+** ^The eTextRep argument determines the encoding of strings passed
+** to the collating function callback, xCallback.
+** ^The [SQLITE_UTF16] and [SQLITE_UTF16_ALIGNED] values for eTextRep
+** force strings to be UTF16 with native byte order.
+** ^The [SQLITE_UTF16_ALIGNED] value for eTextRep forces strings to begin
+** on an even byte address.
+**
+** ^The fourth argument, pArg, is a application data pointer that is passed
+** through as the first argument to the collating function callback.
+**
+** ^The fifth argument, xCallback, is a pointer to the collating function.
+** ^Multiple collating functions can be registered using the same name but
+** with different eTextRep parameters and SQLite will use whichever
+** function requires the least amount of data transformation.
+** ^If the xCallback argument is NULL then the collating function is
+** deleted.  ^When all collating functions having the same name are deleted,
+** that collation is no longer usable.
+**
+** ^The collating function callback is invoked with a copy of the pArg 
+** application data pointer and with two strings in the encoding specified
+** by the eTextRep argument.  The collating function must return an
+** integer that is negative, zero, or positive
+** if the first string is less than, equal to, or greater than the second,
+** respectively.  A collating function must alway return the same answer
+** given the same inputs.  If two or more collating functions are registered
+** to the same collation name (using different eTextRep values) then all
+** must give an equivalent answer when invoked with equivalent strings.
+** The collating function must obey the following properties for all
+** strings A, B, and C:
+**
+** <ol>
+** <li> If A==B then B==A.
+** <li> If A==B and B==C then A==C.
+** <li> If A&lt;B THEN B&gt;A.
+** <li> If A&lt;B and B&lt;C then A&lt;C.
+** </ol>
+**
+** If a collating function fails any of the above constraints and that
+** collating function is  registered and used, then the behavior of SQLite
+** is undefined.
 **
 ** ^The sqlite3_create_collation_v2() works like sqlite3_create_collation()
-** except that it takes an extra argument which is a destructor for
-** the collation.  ^The destructor is called when the collation is
-** destroyed and is passed a copy of the fourth parameter void* pointer
-** of the sqlite3_create_collation_v2().
-** ^Collations are destroyed when they are overridden by later calls to the
-** collation creation functions or when the [database connection] is closed
-** using [sqlite3_close()].
+** with the addition that the xDestroy callback is invoked on pArg when
+** the collating function is deleted.
+** ^Collating functions are deleted when they are overridden by later
+** calls to the collation creation functions or when the
+** [database connection] is closed using [sqlite3_close()].
+**
+** ^The xDestroy callback is <u>not</u> called if the 
+** sqlite3_create_collation_v2() function fails.  Applications that invoke
+** sqlite3_create_collation_v2() with a non-NULL xDestroy argument should 
+** check the return code and dispose of the application data pointer
+** themselves rather than expecting SQLite to deal with it for them.
+** This is different from every other SQLite interface.  The inconsistency 
+** is unfortunate but cannot be changed without breaking backwards 
+** compatibility.
 **
 ** See also:  [sqlite3_collation_needed()] and [sqlite3_collation_needed16()].
 */
@@ -3750,14 +3932,14 @@ SQLITE_API int sqlite3_create_collation(
   sqlite3*, 
   const char *zName, 
   int eTextRep, 
-  void*,
+  void *pArg,
   int(*xCompare)(void*,int,const void*,int,const void*)
 );
 SQLITE_API int sqlite3_create_collation_v2(
   sqlite3*, 
   const char *zName, 
   int eTextRep, 
-  void*,
+  void *pArg,
   int(*xCompare)(void*,int,const void*,int,const void*),
   void(*xDestroy)(void*)
 );
@@ -3765,7 +3947,7 @@ SQLITE_API int sqlite3_create_collation16(
   sqlite3*, 
   const void *zName,
   int eTextRep, 
-  void*,
+  void *pArg,
   int(*xCompare)(void*,int,const void*,int,const void*)
 );
 
@@ -3854,16 +4036,19 @@ SQLITE_API void sqlite3_activate_cerod(
 /*
 ** CAPI3REF: Suspend Execution For A Short Time
 **
-** ^The sqlite3_sleep() function causes the current thread to suspend execution
+** The sqlite3_sleep() function causes the current thread to suspend execution
 ** for at least a number of milliseconds specified in its parameter.
 **
-** ^If the operating system does not support sleep requests with
+** If the operating system does not support sleep requests with
 ** millisecond time resolution, then the time will be rounded up to
-** the nearest second. ^The number of milliseconds of sleep actually
+** the nearest second. The number of milliseconds of sleep actually
 ** requested from the operating system is returned.
 **
 ** ^SQLite implements this interface by calling the xSleep()
-** method of the default [sqlite3_vfs] object.
+** method of the default [sqlite3_vfs] object.  If the xSleep() method
+** of the default VFS is not implemented correctly, or not implemented at
+** all, then the behavior of sqlite3_sleep() may deviate from the description
+** in the previous paragraphs.
 */
 SQLITE_API int sqlite3_sleep(int);
 
@@ -4085,40 +4270,73 @@ SQLITE_API int sqlite3_enable_shared_cache(int);
 ** pages to improve performance is an example of non-essential memory.
 ** ^sqlite3_release_memory() returns the number of bytes actually freed,
 ** which might be more or less than the amount requested.
+** ^The sqlite3_release_memory() routine is a no-op returning zero
+** if SQLite is not compiled with [SQLITE_ENABLE_MEMORY_MANAGEMENT].
 */
 SQLITE_API int sqlite3_release_memory(int);
 
 /*
 ** CAPI3REF: Impose A Limit On Heap Size
 **
-** ^The sqlite3_soft_heap_limit() interface places a "soft" limit
-** on the amount of heap memory that may be allocated by SQLite.
-** ^If an internal allocation is requested that would exceed the
-** soft heap limit, [sqlite3_release_memory()] is invoked one or
-** more times to free up some space before the allocation is performed.
+** ^The sqlite3_soft_heap_limit64() interface sets and/or queries the
+** soft limit on the amount of heap memory that may be allocated by SQLite.
+** ^SQLite strives to keep heap memory utilization below the soft heap
+** limit by reducing the number of pages held in the page cache
+** as heap memory usages approaches the limit.
+** ^The soft heap limit is "soft" because even though SQLite strives to stay
+** below the limit, it will exceed the limit rather than generate
+** an [SQLITE_NOMEM] error.  In other words, the soft heap limit 
+** is advisory only.
 **
-** ^The limit is called "soft" because if [sqlite3_release_memory()]
-** cannot free sufficient memory to prevent the limit from being exceeded,
-** the memory is allocated anyway and the current operation proceeds.
+** ^The return value from sqlite3_soft_heap_limit64() is the size of
+** the soft heap limit prior to the call.  ^If the argument N is negative
+** then no change is made to the soft heap limit.  Hence, the current
+** size of the soft heap limit can be determined by invoking
+** sqlite3_soft_heap_limit64() with a negative argument.
 **
-** ^A negative or zero value for N means that there is no soft heap limit and
-** [sqlite3_release_memory()] will only be called when memory is exhausted.
-** ^The default value for the soft heap limit is zero.
+** ^If the argument N is zero then the soft heap limit is disabled.
 **
-** ^(SQLite makes a best effort to honor the soft heap limit.
-** But if the soft heap limit cannot be honored, execution will
-** continue without error or notification.)^  This is why the limit is
-** called a "soft" limit.  It is advisory only.
+** ^(The soft heap limit is not enforced in the current implementation
+** if one or more of following conditions are true:
 **
-** Prior to SQLite version 3.5.0, this routine only constrained the memory
-** allocated by a single thread - the same thread in which this routine
-** runs.  Beginning with SQLite version 3.5.0, the soft heap limit is
-** applied to all threads. The value specified for the soft heap limit
-** is an upper bound on the total memory allocation for all threads. In
-** version 3.5.0 there is no mechanism for limiting the heap usage for
-** individual threads.
+** <ul>
+** <li> The soft heap limit is set to zero.
+** <li> Memory accounting is disabled using a combination of the
+**      [sqlite3_config]([SQLITE_CONFIG_MEMSTATUS],...) start-time option and
+**      the [SQLITE_DEFAULT_MEMSTATUS] compile-time option.
+** <li> An alternative page cache implementation is specifed using
+**      [sqlite3_config]([SQLITE_CONFIG_PCACHE],...).
+** <li> The page cache allocates from its own memory pool supplied
+**      by [sqlite3_config]([SQLITE_CONFIG_PAGECACHE],...) rather than
+**      from the heap.
+** </ul>)^
+**
+** Beginning with SQLite version 3.7.3, the soft heap limit is enforced
+** regardless of whether or not the [SQLITE_ENABLE_MEMORY_MANAGEMENT]
+** compile-time option is invoked.  With [SQLITE_ENABLE_MEMORY_MANAGEMENT],
+** the soft heap limit is enforced on every memory allocation.  Without
+** [SQLITE_ENABLE_MEMORY_MANAGEMENT], the soft heap limit is only enforced
+** when memory is allocated by the page cache.  Testing suggests that because
+** the page cache is the predominate memory user in SQLite, most
+** applications will achieve adequate soft heap limit enforcement without
+** the use of [SQLITE_ENABLE_MEMORY_MANAGEMENT].
+**
+** The circumstances under which SQLite will enforce the soft heap limit may
+** changes in future releases of SQLite.
 */
-SQLITE_API void sqlite3_soft_heap_limit(int);
+SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N);
+
+/*
+** CAPI3REF: Deprecated Soft Heap Limit Interface
+** DEPRECATED
+**
+** This is a deprecated version of the [sqlite3_soft_heap_limit64()]
+** interface.  This routine is provided for historical compatibility
+** only.  All new applications should use the
+** [sqlite3_soft_heap_limit64()] interface rather than this one.
+*/
+SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
+
 
 /*
 ** CAPI3REF: Extract Metadata About A Column Of A Table
@@ -4242,34 +4460,47 @@ SQLITE_API int sqlite3_load_extension(
 SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
 
 /*
-** CAPI3REF: Automatically Load An Extensions
+** CAPI3REF: Automatically Load Statically Linked Extensions
+**
+** ^This interface causes the xEntryPoint() function to be invoked for
+** each new [database connection] that is created.  The idea here is that
+** xEntryPoint() is the entry point for a statically linked SQLite extension
+** that is to be automatically loaded into all new database connections.
+**
+** ^(Even though the function prototype shows that xEntryPoint() takes
+** no arguments and returns void, SQLite invokes xEntryPoint() with three
+** arguments and expects and integer result as if the signature of the
+** entry point where as follows:
+**
+** <blockquote><pre>
+** &nbsp;  int xEntryPoint(
+** &nbsp;    sqlite3 *db,
+** &nbsp;    const char **pzErrMsg,
+** &nbsp;    const struct sqlite3_api_routines *pThunk
+** &nbsp;  );
+** </pre></blockquote>)^
 **
-** ^This API can be invoked at program startup in order to register
-** one or more statically linked extensions that will be available
-** to all new [database connections].
+** If the xEntryPoint routine encounters an error, it should make *pzErrMsg
+** point to an appropriate error message (obtained from [sqlite3_mprintf()])
+** and return an appropriate [error code].  ^SQLite ensures that *pzErrMsg
+** is NULL before calling the xEntryPoint().  ^SQLite will invoke
+** [sqlite3_free()] on *pzErrMsg after xEntryPoint() returns.  ^If any
+** xEntryPoint() returns an error, the [sqlite3_open()], [sqlite3_open16()],
+** or [sqlite3_open_v2()] call that provoked the xEntryPoint() will fail.
 **
-** ^(This routine stores a pointer to the extension entry point
-** in an array that is obtained from [sqlite3_malloc()].  That memory
-** is deallocated by [sqlite3_reset_auto_extension()].)^
+** ^Calling sqlite3_auto_extension(X) with an entry point X that is already
+** on the list of automatic extensions is a harmless no-op. ^No entry point
+** will be called more than once for each database connection that is opened.
 **
-** ^This function registers an extension entry point that is
-** automatically invoked whenever a new [database connection]
-** is opened using [sqlite3_open()], [sqlite3_open16()],
-** or [sqlite3_open_v2()].
-** ^Duplicate extensions are detected so calling this routine
-** multiple times with the same extension is harmless.
-** ^Automatic extensions apply across all threads.
+** See also: [sqlite3_reset_auto_extension()].
 */
 SQLITE_API int sqlite3_auto_extension(void (*xEntryPoint)(void));
 
 /*
 ** CAPI3REF: Reset Automatic Extension Loading
 **
-** ^(This function disables all previously registered automatic
-** extensions. It undoes the effect of all prior
-** [sqlite3_auto_extension()] calls.)^
-**
-** ^This function disables automatic extensions in all threads.
+** ^This interface disables all automatic extensions previously
+** registered using [sqlite3_auto_extension()].
 */
 SQLITE_API void sqlite3_reset_auto_extension(void);
 
@@ -4449,7 +4680,9 @@ struct sqlite3_index_info {
 ** ^The sqlite3_create_module_v2() interface has a fifth parameter which
 ** is a pointer to a destructor for the pClientData.  ^SQLite will
 ** invoke the destructor function (if it is not NULL) when SQLite
-** no longer needs the pClientData pointer.  ^The sqlite3_create_module()
+** no longer needs the pClientData pointer.  ^The destructor will also
+** be invoked if the call to sqlite3_create_module_v2() fails.
+** ^The sqlite3_create_module()
 ** interface is equivalent to sqlite3_create_module_v2() with a NULL
 ** destructor.
 */
@@ -4633,6 +4866,30 @@ SQLITE_API int sqlite3_blob_open(
 );
 
 /*
+** CAPI3REF: Move a BLOB Handle to a New Row
+**
+** ^This function is used to move an existing blob handle so that it points
+** to a different row of the same database table. ^The new row is identified
+** by the rowid value passed as the second argument. Only the row can be
+** changed. ^The database, table and column on which the blob handle is open
+** remain the same. Moving an existing blob handle to a new row can be
+** faster than closing the existing handle and opening a new one.
+**
+** ^(The new row must meet the same criteria as for [sqlite3_blob_open()] -
+** it must exist and there must be either a blob or text value stored in
+** the nominated column.)^ ^If the new row is not present in the table, or if
+** it does not contain a blob or text value, or if another error occurs, an
+** SQLite error code is returned and the blob handle is considered aborted.
+** ^All subsequent calls to [sqlite3_blob_read()], [sqlite3_blob_write()] or
+** [sqlite3_blob_reopen()] on an aborted blob handle immediately return
+** SQLITE_ABORT. ^Calling [sqlite3_blob_bytes()] on an aborted blob handle
+** always returns zero.
+**
+** ^This function sets the database handle error code and message.
+*/
+SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
+
+/*
 ** CAPI3REF: Close A BLOB Handle
 **
 ** ^Closes an open [BLOB handle].
@@ -4908,7 +5165,7 @@ SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*);
 **
 ** ^The xMutexInit method defined by this structure is invoked as
 ** part of system initialization by the sqlite3_initialize() function.
-** ^The xMutexInit routine is calle by SQLite exactly once for each
+** ^The xMutexInit routine is called by SQLite exactly once for each
 ** effective call to [sqlite3_initialize()].
 **
 ** ^The xMutexEnd method defined by this structure is invoked as
@@ -5020,7 +5277,8 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
 #define SQLITE_MUTEX_STATIC_OPEN      4  /* sqlite3BtreeOpen() */
 #define SQLITE_MUTEX_STATIC_PRNG      5  /* sqlite3_random() */
 #define SQLITE_MUTEX_STATIC_LRU       6  /* lru page list */
-#define SQLITE_MUTEX_STATIC_LRU2      7  /* lru page list */
+#define SQLITE_MUTEX_STATIC_LRU2      7  /* NOT USED */
+#define SQLITE_MUTEX_STATIC_PMEM      7  /* sqlite3PageMalloc() */
 
 /*
 ** CAPI3REF: Retrieve the mutex for a database connection
@@ -5039,7 +5297,7 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
 ** ^The [sqlite3_file_control()] interface makes a direct call to the
 ** xFileControl method for the [sqlite3_io_methods] object associated
 ** with a particular database identified by the second argument. ^The
-** name of the database "main" for the main database or "temp" for the
+** name of the database is "main" for the main database or "temp" for the
 ** TEMP database, or the name that appears after the AS keyword for
 ** databases that are added using the [ATTACH] SQL command.
 ** ^A NULL pointer can be used in place of "main" to refer to the
@@ -5049,6 +5307,12 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
 ** the xFileControl method.  ^The return value of the xFileControl
 ** method becomes the return value of this routine.
 **
+** ^The SQLITE_FCNTL_FILE_POINTER value for the op parameter causes
+** a pointer to the underlying [sqlite3_file] object to be written into
+** the space pointed to by the 4th parameter.  ^The SQLITE_FCNTL_FILE_POINTER
+** case is a short-circuit path which does not actually invoke the
+** underlying sqlite3_io_methods.xFileControl method.
+**
 ** ^If the second parameter (zDbName) does not match the name of any
 ** open database file, then SQLITE_ERROR is returned.  ^This error
 ** code is not remembered and will not be recalled by [sqlite3_errcode()]
@@ -5105,7 +5369,8 @@ SQLITE_API int sqlite3_test_control(int op, ...);
 #define SQLITE_TESTCTRL_OPTIMIZATIONS           15
 #define SQLITE_TESTCTRL_ISKEYWORD               16
 #define SQLITE_TESTCTRL_PGHDRSZ                 17
-#define SQLITE_TESTCTRL_LAST                    17
+#define SQLITE_TESTCTRL_SCRATCHMALLOC           18
+#define SQLITE_TESTCTRL_LAST                    18
 
 /*
 ** CAPI3REF: SQLite Runtime Status
@@ -5124,7 +5389,7 @@ SQLITE_API int sqlite3_test_control(int op, ...);
 ** ^(Other parameters record only the highwater mark and not the current
 ** value.  For these latter parameters nothing is written into *pCurrent.)^
 **
-** ^The sqlite3_db_status() routine returns SQLITE_OK on success and a
+** ^The sqlite3_status() routine returns SQLITE_OK on success and a
 ** non-zero [error code] on failure.
 **
 ** This routine is threadsafe but is not atomic.  This routine can be
@@ -5164,7 +5429,8 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
 ** The value written into the *pCurrent parameter is undefined.</dd>)^
 **
 ** ^(<dt>SQLITE_STATUS_MALLOC_COUNT</dt>
-** <dd>This parameter records the number of separate memory allocations.</dd>)^
+** <dd>This parameter records the number of separate memory allocations
+** currently checked out.</dd>)^
 **
 ** ^(<dt>SQLITE_STATUS_PAGECACHE_USED</dt>
 ** <dd>This parameter returns the number of pages used out of the
@@ -5174,7 +5440,7 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
 **
 ** ^(<dt>SQLITE_STATUS_PAGECACHE_OVERFLOW</dt>
 ** <dd>This parameter returns the number of bytes of page cache
-** allocation which could not be statisfied by the [SQLITE_CONFIG_PAGECACHE]
+** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE]
 ** buffer and where forced to overflow to [sqlite3_malloc()].  The
 ** returned value includes allocations that overflowed because they
 ** where too large (they were larger than the "sz" parameter to
@@ -5197,7 +5463,7 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
 **
 ** ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt>
 ** <dd>This parameter returns the number of bytes of scratch memory
-** allocation which could not be statisfied by the [SQLITE_CONFIG_SCRATCH]
+** allocation which could not be satisfied by the [SQLITE_CONFIG_SCRATCH]
 ** buffer and where forced to overflow to [sqlite3_malloc()].  The values
 ** returned include overflows because the requested allocation was too
 ** larger (that is, because the requested allocation was larger than the
@@ -5246,6 +5512,9 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
 ** the resetFlg is true, then the highest instantaneous value is
 ** reset back down to the current value.
 **
+** ^The sqlite3_db_status() routine returns SQLITE_OK on success and a
+** non-zero [error code] on failure.
+**
 ** See also: [sqlite3_status()] and [sqlite3_stmt_status()].
 */
 SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
@@ -5267,6 +5536,28 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
 ** <dd>This parameter returns the number of lookaside memory slots currently
 ** checked out.</dd>)^
 **
+** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt>
+** <dd>This parameter returns the number malloc attempts that were 
+** satisfied using lookaside memory. Only the high-water value is meaningful;
+** the current value is always zero.
+** checked out.</dd>)^
+**
+** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE</dt>
+** <dd>This parameter returns the number malloc attempts that might have
+** been satisfied using lookaside memory but failed due to the amount of
+** memory requested being larger than the lookaside slot size.
+** Only the high-water value is meaningful;
+** the current value is always zero.
+** checked out.</dd>)^
+**
+** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL</dt>
+** <dd>This parameter returns the number malloc attempts that might have
+** been satisfied using lookaside memory but failed due to all lookaside
+** memory already being in use.
+** Only the high-water value is meaningful;
+** the current value is always zero.
+** checked out.</dd>)^
+**
 ** ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt>
 ** <dd>This parameter returns the approximate number of of bytes of heap
 ** memory used by all pager caches associated with the database connection.)^
@@ -5289,11 +5580,14 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
 ** </dd>
 ** </dl>
 */
-#define SQLITE_DBSTATUS_LOOKASIDE_USED     0
-#define SQLITE_DBSTATUS_CACHE_USED         1
-#define SQLITE_DBSTATUS_SCHEMA_USED        2
-#define SQLITE_DBSTATUS_STMT_USED          3
-#define SQLITE_DBSTATUS_MAX                3   /* Largest defined DBSTATUS */
+#define SQLITE_DBSTATUS_LOOKASIDE_USED       0
+#define SQLITE_DBSTATUS_CACHE_USED           1
+#define SQLITE_DBSTATUS_SCHEMA_USED          2
+#define SQLITE_DBSTATUS_STMT_USED            3
+#define SQLITE_DBSTATUS_LOOKASIDE_HIT        4
+#define SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE  5
+#define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL  6
+#define SQLITE_DBSTATUS_MAX                  6   /* Largest defined DBSTATUS */
 
 
 /*
@@ -5372,32 +5666,42 @@ typedef struct sqlite3_pcache sqlite3_pcache;
 **
 ** ^(The [sqlite3_config]([SQLITE_CONFIG_PCACHE], ...) interface can
 ** register an alternative page cache implementation by passing in an 
-** instance of the sqlite3_pcache_methods structure.)^ The majority of the 
-** heap memory used by SQLite is used by the page cache to cache data read 
-** from, or ready to be written to, the database file. By implementing a 
-** custom page cache using this API, an application can control more 
-** precisely the amount of memory consumed by SQLite, the way in which 
+** instance of the sqlite3_pcache_methods structure.)^
+** In many applications, most of the heap memory allocated by 
+** SQLite is used for the page cache.
+** By implementing a 
+** custom page cache using this API, an application can better control
+** the amount of memory consumed by SQLite, the way in which 
 ** that memory is allocated and released, and the policies used to 
 ** determine exactly which parts of a database file are cached and for 
 ** how long.
 **
+** The alternative page cache mechanism is an
+** extreme measure that is only needed by the most demanding applications.
+** The built-in page cache is recommended for most uses.
+**
 ** ^(The contents of the sqlite3_pcache_methods structure are copied to an
 ** internal buffer by SQLite within the call to [sqlite3_config].  Hence
 ** the application may discard the parameter after the call to
 ** [sqlite3_config()] returns.)^
 **
-** ^The xInit() method is called once for each call to [sqlite3_initialize()]
+** ^(The xInit() method is called once for each effective 
+** call to [sqlite3_initialize()])^
 ** (usually only once during the lifetime of the process). ^(The xInit()
 ** method is passed a copy of the sqlite3_pcache_methods.pArg value.)^
-** ^The xInit() method can set up up global structures and/or any mutexes
+** The intent of the xInit() method is to set up global data structures 
 ** required by the custom page cache implementation. 
+** ^(If the xInit() method is NULL, then the 
+** built-in default page cache is used instead of the application defined
+** page cache.)^
 **
-** ^The xShutdown() method is called from within [sqlite3_shutdown()], 
-** if the application invokes this API. It can be used to clean up 
+** ^The xShutdown() method is called by [sqlite3_shutdown()].
+** It can be used to clean up 
 ** any outstanding resources before process shutdown, if required.
+** ^The xShutdown() method may be NULL.
 **
-** ^SQLite holds a [SQLITE_MUTEX_RECURSIVE] mutex when it invokes
-** the xInit method, so the xInit method need not be threadsafe.  ^The
+** ^SQLite automatically serializes calls to the xInit method,
+** so the xInit method need not be threadsafe.  ^The
 ** xShutdown method is only called from [sqlite3_shutdown()] so it does
 ** not need to be threadsafe either.  All other methods must be threadsafe
 ** in multithreaded applications.
@@ -5405,47 +5709,52 @@ typedef struct sqlite3_pcache sqlite3_pcache;
 ** ^SQLite will never invoke xInit() more than once without an intervening
 ** call to xShutdown().
 **
-** ^The xCreate() method is used to construct a new cache instance.  SQLite
-** will typically create one cache instance for each open database file,
+** ^SQLite invokes the xCreate() method to construct a new cache instance.
+** SQLite will typically create one cache instance for each open database file,
 ** though this is not guaranteed. ^The
 ** first parameter, szPage, is the size in bytes of the pages that must
 ** be allocated by the cache.  ^szPage will not be a power of two.  ^szPage
 ** will the page size of the database file that is to be cached plus an
-** increment (here called "R") of about 100 or 200.  ^SQLite will use the
+** increment (here called "R") of less than 250.  SQLite will use the
 ** extra R bytes on each page to store metadata about the underlying
 ** database page on disk.  The value of R depends
 ** on the SQLite version, the target platform, and how SQLite was compiled.
-** ^R is constant for a particular build of SQLite.  ^The second argument to
+** ^(R is constant for a particular build of SQLite. Except, there are two
+** distinct values of R when SQLite is compiled with the proprietary
+** ZIPVFS extension.)^  ^The second argument to
 ** xCreate(), bPurgeable, is true if the cache being created will
 ** be used to cache database pages of a file stored on disk, or
-** false if it is used for an in-memory database. ^The cache implementation
+** false if it is used for an in-memory database. The cache implementation
 ** does not have to do anything special based with the value of bPurgeable;
 ** it is purely advisory.  ^On a cache where bPurgeable is false, SQLite will
 ** never invoke xUnpin() except to deliberately delete a page.
-** ^In other words, a cache created with bPurgeable set to false will
+** ^In other words, calls to xUnpin() on a cache with bPurgeable set to
+** false will always have the "discard" flag set to true.  
+** ^Hence, a cache created with bPurgeable false will
 ** never contain any unpinned pages.
 **
 ** ^(The xCachesize() method may be called at any time by SQLite to set the
 ** suggested maximum cache-size (number of pages stored by) the cache
 ** instance passed as the first argument. This is the value configured using
-** the SQLite "[PRAGMA cache_size]" command.)^  ^As with the bPurgeable
+** the SQLite "[PRAGMA cache_size]" command.)^  As with the bPurgeable
 ** parameter, the implementation is not required to do anything with this
 ** value; it is advisory only.
 **
-** ^The xPagecount() method should return the number of pages currently
-** stored in the cache.
+** The xPagecount() method must return the number of pages currently
+** stored in the cache, both pinned and unpinned.
 ** 
-** ^The xFetch() method is used to fetch a page and return a pointer to it. 
-** ^A 'page', in this context, is a buffer of szPage bytes aligned at an
-** 8-byte boundary. ^The page to be fetched is determined by the key. ^The
-** mimimum key value is 1. After it has been retrieved using xFetch, the page 
+** The xFetch() method locates a page in the cache and returns a pointer to 
+** the page, or a NULL pointer.
+** A "page", in this context, means a buffer of szPage bytes aligned at an
+** 8-byte boundary. The page to be fetched is determined by the key. ^The
+** mimimum key value is 1.  After it has been retrieved using xFetch, the page 
 ** is considered to be "pinned".
 **
-** ^If the requested page is already in the page cache, then the page cache
+** If the requested page is already in the page cache, then the page cache
 ** implementation must return a pointer to the page buffer with its content
-** intact.  ^(If the requested page is not already in the cache, then the
-** behavior of the cache implementation is determined by the value of the
-** createFlag parameter passed to xFetch, according to the following table:
+** intact.  If the requested page is not already in the cache, then the
+** cache implementation should use the value of the createFlag
+** parameter to help it determined what action to take:
 **
 ** <table border=1 width=85% align=center>
 ** <tr><th> createFlag <th> Behaviour when page is not already in cache
@@ -5454,36 +5763,35 @@ typedef struct sqlite3_pcache sqlite3_pcache;
 **                 Otherwise return NULL.
 ** <tr><td> 2 <td> Make every effort to allocate a new page.  Only return
 **                 NULL if allocating a new page is effectively impossible.
-** </table>)^
+** </table>
 **
-** SQLite will normally invoke xFetch() with a createFlag of 0 or 1.  If
-** a call to xFetch() with createFlag==1 returns NULL, then SQLite will
+** ^(SQLite will normally invoke xFetch() with a createFlag of 0 or 1.  SQLite
+** will only use a createFlag of 2 after a prior call with a createFlag of 1
+** failed.)^  In between the to xFetch() calls, SQLite may
 ** attempt to unpin one or more cache pages by spilling the content of
-** pinned pages to disk and synching the operating system disk cache. After
-** attempting to unpin pages, the xFetch() method will be invoked again with
-** a createFlag of 2.
+** pinned pages to disk and synching the operating system disk cache.
 **
 ** ^xUnpin() is called by SQLite with a pointer to a currently pinned page
-** as its second argument. ^(If the third parameter, discard, is non-zero,
-** then the page should be evicted from the cache. In this case SQLite 
-** assumes that the next time the page is retrieved from the cache using
-** the xFetch() method, it will be zeroed.)^ ^If the discard parameter is
-** zero, then the page is considered to be unpinned. ^The cache implementation
+** as its second argument.  If the third parameter, discard, is non-zero,
+** then the page must be evicted from the cache.
+** ^If the discard parameter is
+** zero, then the page may be discarded or retained at the discretion of
+** page cache implementation. ^The page cache implementation
 ** may choose to evict unpinned pages at any time.
 **
-** ^(The cache is not required to perform any reference counting. A single 
+** The cache must not perform any reference counting. A single 
 ** call to xUnpin() unpins the page regardless of the number of prior calls 
-** to xFetch().)^
+** to xFetch().
 **
-** ^The xRekey() method is used to change the key value associated with the
-** page passed as the second argument from oldKey to newKey. ^If the cache
-** previously contains an entry associated with newKey, it should be
+** The xRekey() method is used to change the key value associated with the
+** page passed as the second argument. If the cache
+** previously contains an entry associated with newKey, it must be
 ** discarded. ^Any prior cache entry associated with newKey is guaranteed not
 ** to be pinned.
 **
-** ^When SQLite calls the xTruncate() method, the cache must discard all
+** When SQLite calls the xTruncate() method, the cache must discard all
 ** existing cache entries with page numbers (keys) greater than or equal
-** to the value of the iLimit parameter passed to xTruncate(). ^If any
+** to the value of the iLimit parameter passed to xTruncate(). If any
 ** of these pages are pinned, they are implicitly unpinned, meaning that
 ** they can be safely discarded.
 **
@@ -5529,11 +5837,12 @@ typedef struct sqlite3_backup sqlite3_backup;
 **
 ** See Also: [Using the SQLite Online Backup API]
 **
-** ^Exclusive access is required to the destination database for the 
-** duration of the operation. ^However the source database is only
-** read-locked while it is actually being read; it is not locked
-** continuously for the entire backup operation. ^Thus, the backup may be
-** performed on a live source database without preventing other users from
+** ^SQLite holds a write transaction open on the destination database file
+** for the duration of the backup operation.
+** ^The source database is read-locked only while it is being read;
+** it is not locked continuously for the entire backup operation.
+** ^Thus, the backup may be performed on a live source database without
+** preventing other database connections from
 ** reading or writing to the source database while the backup is underway.
 ** 
 ** ^(To perform a backup operation: 
@@ -5560,11 +5869,11 @@ typedef struct sqlite3_backup sqlite3_backup;
 ** sqlite3_backup_init(D,N,S,M) identify the [database connection]
 ** and database name of the source database, respectively.
 ** ^The source and destination [database connections] (parameters S and D)
-** must be different or else sqlite3_backup_init(D,N,S,M) will file with
+** must be different or else sqlite3_backup_init(D,N,S,M) will fail with
 ** an error.
 **
 ** ^If an error occurs within sqlite3_backup_init(D,N,S,M), then NULL is
-** returned and an error code and error message are store3d in the
+** returned and an error code and error message are stored in the
 ** destination [database connection] D.
 ** ^The error code and message for the failed call to sqlite3_backup_init()
 ** can be retrieved using the [sqlite3_errcode()], [sqlite3_errmsg()], and/or
@@ -5581,7 +5890,7 @@ typedef struct sqlite3_backup sqlite3_backup;
 ** the source and destination databases specified by [sqlite3_backup] object B.
 ** ^If N is negative, all remaining source pages are copied. 
 ** ^If sqlite3_backup_step(B,N) successfully copies N pages and there
-** are still more pages to be copied, then the function resturns [SQLITE_OK].
+** are still more pages to be copied, then the function returns [SQLITE_OK].
 ** ^If sqlite3_backup_step(B,N) successfully finishes copying all pages
 ** from source to destination, then it returns [SQLITE_DONE].
 ** ^If an error occurs while running sqlite3_backup_step(B,N),
@@ -5595,7 +5904,7 @@ typedef struct sqlite3_backup sqlite3_backup;
 ** <li> the destination database was opened read-only, or
 ** <li> the destination database is using write-ahead-log journaling
 ** and the destination and source page sizes differ, or
-** <li> The destination database is an in-memory database and the
+** <li> the destination database is an in-memory database and the
 ** destination and source page sizes differ.
 ** </ol>)^
 **
@@ -5926,7 +6235,8 @@ SQLITE_API void *sqlite3_wal_hook(
 ** from SQL.
 **
 ** ^Every new [database connection] defaults to having the auto-checkpoint
-** enabled with a threshold of 1000 pages.  The use of this interface
+** enabled with a threshold of 1000 or [SQLITE_DEFAULT_WAL_AUTOCHECKPOINT]
+** pages.  The use of this interface
 ** is only necessary if the default setting is found to be suboptimal
 ** for a particular application.
 */
@@ -5961,3 +6271,59 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
 #endif
 #endif
 
+/*
+** 2010 August 30
+**
+** 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.
+**
+*************************************************************************
+*/
+
+#ifndef _SQLITE3RTREE_H_
+#define _SQLITE3RTREE_H_
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry;
+
+/*
+** Register a geometry callback named zGeom that can be used as part of an
+** R-Tree geometry query as follows:
+**
+**   SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zGeom(... params ...)
+*/
+SQLITE_API int sqlite3_rtree_geometry_callback(
+  sqlite3 *db,
+  const char *zGeom,
+  int (*xGeom)(sqlite3_rtree_geometry *, int nCoord, double *aCoord, int *pRes),
+  void *pContext
+);
+
+
+/*
+** A pointer to a structure of the following type is passed as the first
+** argument to callbacks registered using rtree_geometry_callback().
+*/
+struct sqlite3_rtree_geometry {
+  void *pContext;                 /* Copy of pContext passed to s_r_g_c() */
+  int nParam;                     /* Size of array aParam[] */
+  double *aParam;                 /* Parameters passed to SQL geom function */
+  void *pUser;                    /* Callback implementation user data */
+  void (*xDelUser)(void *);       /* Called by SQLite to clean up pUser */
+};
+
+
+#ifdef __cplusplus
+}  /* end of the 'extern "C"' block */
+#endif
+
+#endif  /* ifndef _SQLITE3RTREE_H_ */
+
diff --git a/libgda/sqlite/virtual/Makefile.am b/libgda/sqlite/virtual/Makefile.am
index 1864efd..8b6a90a 100644
--- a/libgda/sqlite/virtual/Makefile.am
+++ b/libgda/sqlite/virtual/Makefile.am
@@ -7,7 +7,7 @@ sqliteinc= -I$(top_srcdir)/libgda/sqlite/sqlite-src \
 	-I$(top_builddir)/libgda/sqlite/sqlite-src 
 endif
 
-noinst_LTLIBRARIES = libgda-virtual-4.0.la
+noinst_LTLIBRARIES = libgda-virtual-5.0.la
 
 AM_CPPFLAGS = \
 	-I$(top_srcdir) \
@@ -29,7 +29,7 @@ virtual_headers = \
 	gda-virtual-provider.h \
 	libgda-virtual.h
 
-libgda_virtual_4_0_la_SOURCES = \
+libgda_virtual_5_0_la_SOURCES = \
 	$(virtual_headers) \
 	gda-vconnection-data-model.c \
 	gda-vconnection-data-model-private.h \
@@ -42,7 +42,7 @@ libgda_virtual_4_0_la_SOURCES = \
 gdaincludedir=$(includedir)/libgda-$(GDA_ABI_MAJOR_VERSION).$(GDA_ABI_MINOR_VERSION)/libgda/virtual
 gdainclude_HEADERS=$(virtual_headers)
 
-xmldir   = $(datadir)/libgda-4.0
+xmldir   = $(datadir)/libgda-5.0
 xml_in_files = 
 
 @INTLTOOL_XML_RULE@
diff --git a/libgda/sqlite/virtual/gda-vconnection-data-model.h b/libgda/sqlite/virtual/gda-vconnection-data-model.h
index 0eb7727..90f8153 100644
--- a/libgda/sqlite/virtual/gda-vconnection-data-model.h
+++ b/libgda/sqlite/virtual/gda-vconnection-data-model.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 - 2010 The GNOME Foundation.
+ * Copyright (C) 2007 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -40,11 +40,33 @@ typedef struct _GdaVconnectionDataModelPrivate GdaVconnectionDataModelPrivate;
 typedef struct _GdaVconnectionDataModelSpec  GdaVconnectionDataModelSpec;
 typedef struct _GdaVconnectionDataModelFilter GdaVconnectionDataModelFilter;
 
+/**
+ * GdaVconnectionDataModelCreateColumnsFunc:
+ * @Param1: 
+ * @Param2: 
+ * @Returns: 
+ */
 typedef GList        *(*GdaVconnectionDataModelCreateColumnsFunc) (GdaVconnectionDataModelSpec *, GError **);
+
+/**
+ * GdaVconnectionDataModelCreateModelFunc:
+ * @Param1: 
+ * @Returns: 
+ */
 typedef GdaDataModel *(*GdaVconnectionDataModelCreateModelFunc)   (GdaVconnectionDataModelSpec *);
+
+/**
+ * GdaVconnectionDataModelFunc:
+ * @Param1: 
+ * @Param2: 
+ * @Param3: 
+ */
+
 typedef void (*GdaVconnectionDataModelFunc) (GdaDataModel *, const gchar *, gpointer );
 
-/* 
+/**
+ * GdaVconnectionDataModelFilter:
+ *
  * Enabling pre-filtering when creating a data model to be used as a table,
  * (structure closely mapped with SQLite's sqlite3_index_info type), to enable
  * the data model to perform some filter tasks itself.
@@ -82,10 +104,29 @@ struct _GdaVconnectionDataModelFilter {
 	double estimatedCost;      /* Estimated cost of using this index */
 };
 
+/**
+ * GdaVconnectionDataModelParseFilterFunc:
+ * @Param1:
+ * @Param2:
+ */
 typedef void          (*GdaVconnectionDataModelParseFilterFunc)   (GdaVconnectionDataModelSpec *, GdaVconnectionDataModelFilter *); 
+
+/**
+ * GdaVconnectionDataModelCreateFModelFunc:
+ * @Param1: 
+ * @Returns: 
+ */
 typedef GdaDataModel *(*GdaVconnectionDataModelCreateFModelFunc)  (GdaVconnectionDataModelSpec *,
 								   int, const char *, int, GValue **);
-
+/**
+ * GdaVconnectionDataModelSpec:
+ * @data_model: 
+ * @create_columns_func: 
+ * @create_model_func: 
+ * @create_filter_func: 
+ * @create_filtered_model_func:
+ *
+ */
 struct _GdaVconnectionDataModelSpec {
 	GdaDataModel                             *data_model;
 	GdaVconnectionDataModelCreateColumnsFunc  create_columns_func;
@@ -104,11 +145,23 @@ struct _GdaVconnectionDataModel {
 struct _GdaVconnectionDataModelClass {
 	GdaVirtualConnectionClass       parent_class;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
 };
 
+/**
+ * SECTION:gda-vconnection-data-model
+ * @short_description: Virtual connection based on a list of GdaDataModel
+ * @title: GdaVconnectionDataModel
+ * @stability: Stable
+ * @see_also: The #GdaVproviderDataModel provider to use to create such connection objects.
+ *
+ * The #GdaVconnectionDataModel is a virtual connection in which #GdaDataModel data models can be added
+ * or removed, each representing a table in the connection.
+ */
+
 GType               gda_vconnection_data_model_get_type  (void) G_GNUC_CONST;
 
 gboolean            gda_vconnection_data_model_add       (GdaVconnectionDataModel *cnc, GdaVconnectionDataModelSpec *spec, 
diff --git a/libgda/sqlite/virtual/gda-vconnection-hub.h b/libgda/sqlite/virtual/gda-vconnection-hub.h
index cf6cb87..e3da934 100644
--- a/libgda/sqlite/virtual/gda-vconnection-hub.h
+++ b/libgda/sqlite/virtual/gda-vconnection-hub.h
@@ -1,5 +1,5 @@
-/* GDA
- * Copyright (C) 2007 - 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 2007 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -47,6 +47,7 @@ struct _GdaVconnectionHub {
 struct _GdaVconnectionHubClass {
 	GdaVconnectionDataModelClass parent_class;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
@@ -54,6 +55,24 @@ struct _GdaVconnectionHubClass {
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-vconnection-hub
+ * @short_description: Virtual connection which bind together connections
+ * @title: GdaVconnectionHub
+ * @stability: Stable
+ * @see_also: 
+ *
+ * The #GdaVconnectionHub object "binds" together the tables from other (opened) connections to make it possible to run
+ * SQL queries on data from several connections at once.
+ *
+ * A #GdaVconnectionHub connection can bind several other connections, each separated in its own namespace (which is specified
+ * when adding a connection using gda_vconnection_hub_add()).
+ *
+ * For example if a connection A has two tables 'table_1' and 'table_2', then after gda_vconnection_hub_add() has been called
+ * with A as connection argument and with a "c1" namespace, then in the corresponding #GdaVconnectionHub connection, table 
+ * 'table_1' must be referred to as 'c1.table_1' and 'table_2' must be referred to as 'c1.table_2'.
+ */
+
 GType               gda_vconnection_hub_get_type       (void) G_GNUC_CONST;
 
 gboolean            gda_vconnection_hub_add            (GdaVconnectionHub *hub, 
diff --git a/libgda/sqlite/virtual/gda-virtual-connection.h b/libgda/sqlite/virtual/gda-virtual-connection.h
index d0d9976..7f80f43 100644
--- a/libgda/sqlite/virtual/gda-virtual-connection.h
+++ b/libgda/sqlite/virtual/gda-virtual-connection.h
@@ -1,5 +1,5 @@
-/* GDA virtual connection
- * Copyright (C) 2007 - 2010 The GNOME Foundation.
+/*
+ * Copyright (C) 2007 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -54,6 +54,16 @@ struct _GdaVirtualConnectionClass {
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-virtual-connection
+ * @short_description: Base class for all virtual connection objects
+ * @title: GdaVirtualConnection
+ * @stability: Stable
+ * @see_also: 
+ *
+ * This is a base virtual class for all virtual connection implementations.
+ */
+
 GType          gda_virtual_connection_get_type                   (void) G_GNUC_CONST;
 GdaConnection *gda_virtual_connection_open                       (GdaVirtualProvider *virtual_provider, GError **error);
 GdaConnection *gda_virtual_connection_open_extended              (GdaVirtualProvider *virtual_provider,
diff --git a/libgda/sqlite/virtual/gda-virtual-provider.h b/libgda/sqlite/virtual/gda-virtual-provider.h
index 2f4ac31..1e21d04 100644
--- a/libgda/sqlite/virtual/gda-virtual-provider.h
+++ b/libgda/sqlite/virtual/gda-virtual-provider.h
@@ -1,5 +1,5 @@
-/* GDA virtual provider (based on SQLite)
- * Copyright (C) 2007 - 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 2007 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -47,11 +47,22 @@ struct _GdaVirtualProvider {
 struct _GdaVirtualProviderClass {
 	GdaSqliteProviderClass      parent_class;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
 };
 
+/**
+ * SECTION:gda-virtual-provider
+ * @short_description: Base class for all virtual provider objects
+ * @title: GdaVirtualProvider
+ * @stability: Stable
+ * @see_also: #GdaVirtualConnection
+ *
+ * This is a base virtual class for all virtual providers implementations.
+ */
+
 GType          gda_virtual_provider_get_type          (void) G_GNUC_CONST;
 
 G_END_DECLS
diff --git a/libgda/sqlite/virtual/gda-vprovider-data-model.h b/libgda/sqlite/virtual/gda-vprovider-data-model.h
index cc06031..3665511 100644
--- a/libgda/sqlite/virtual/gda-vprovider-data-model.h
+++ b/libgda/sqlite/virtual/gda-vprovider-data-model.h
@@ -1,5 +1,5 @@
-/* GDA SQLite vprovider for GdaDataModel
- * Copyright (C) 2007 - 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 2007 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -45,6 +45,7 @@ struct _GdaVproviderDataModel {
 struct _GdaVproviderDataModelClass {
 	GdaVirtualProviderClass       parent_class;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
@@ -52,6 +53,19 @@ struct _GdaVproviderDataModelClass {
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-vprovider-data-model
+ * @short_description: Virtual provider for connections based on a list of GdaDataModel
+ * @title: GdaVproviderDataModel
+ * @stability: Stable
+ * @see_also: See also the <link linkend="VirtualIntro">introduction to virtual connections</link>
+ *
+ * This provider is used to create virtual connections in which each #GdaDataModel data model can be
+ * added as a table in the connection. Using gda_virtual_connection_open() with this provider as argument
+ * will generate a #GdaVconnectionDataModel connection object, from which data models can be added.
+ */
+
+
 GType               gda_vprovider_data_model_get_type (void) G_GNUC_CONST;
 GdaVirtualProvider *gda_vprovider_data_model_new      (void);
 
diff --git a/libgda/sqlite/virtual/gda-vprovider-hub.h b/libgda/sqlite/virtual/gda-vprovider-hub.h
index bfa04f8..13d949e 100644
--- a/libgda/sqlite/virtual/gda-vprovider-hub.h
+++ b/libgda/sqlite/virtual/gda-vprovider-hub.h
@@ -1,5 +1,5 @@
-/* GDA SQLite vprovider for Hub of connections
- * Copyright (C) 2007 - 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 2007 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -45,6 +45,7 @@ struct _GdaVproviderHub {
 struct _GdaVproviderHubClass {
 	GdaVproviderDataModelClass parent_class;
 
+	/*< private >*/
 	/* Padding for future expansion */
 	void (*_gda_reserved1) (void);
 	void (*_gda_reserved2) (void);
@@ -52,6 +53,22 @@ struct _GdaVproviderHubClass {
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * SECTION:gda-vprovider-hub
+ * @short_description: Virtual provider for connections based on other connection
+ * @title: GdaVproviderHub
+ * @stability: Stable
+ * @see_also: See also the <link linkend="VirtualIntro">introduction to virtual connections</link>
+ *
+ * This provider is used to create virtual connections which "incorporate" tables from other connections. This is typically
+ * used when one need to compare or migrate data from one database to the other by creating two connections for each database,
+ * and "binding" them into a third virtual connection using this provider.
+ *
+ * Using gda_virtual_connection_open() with this provider as argument
+ * will generate a #GdaVconnectionHub connection object, from which connections can be added.
+ */
+
+
 GType               gda_vprovider_hub_get_type (void) G_GNUC_CONST;
 GdaVirtualProvider *gda_vprovider_hub_new      (void);
 
diff --git a/libgda/sqlite/virtual/libgda-virtual-4.0.pc.in b/libgda/sqlite/virtual/libgda-virtual-5.0.pc.in
similarity index 100%
rename from libgda/sqlite/virtual/libgda-virtual-4.0.pc.in
rename to libgda/sqlite/virtual/libgda-virtual-5.0.pc.in
diff --git a/libgda/thread-wrapper/Makefile.am b/libgda/thread-wrapper/Makefile.am
index 2c3c452..25b8a65 100644
--- a/libgda/thread-wrapper/Makefile.am
+++ b/libgda/thread-wrapper/Makefile.am
@@ -1,4 +1,4 @@
-noinst_LTLIBRARIES = libgda_threadwrapper-4.0.la
+noinst_LTLIBRARIES = libgda_threadwrapper-5.0.la
 
 AM_CPPFLAGS = \
         -I$(top_srcdir) -I$(srcdir)/.. \
@@ -13,7 +13,7 @@ libgda_threadwrapper_headers = \
 libgda_threadwrapperincludedir=$(includedir)/libgda-$(GDA_ABI_MAJOR_VERSION).$(GDA_ABI_MINOR_VERSION)/libgda/thread-wrapper
 libgda_threadwrapperinclude_HEADERS=$(libgda_threadwrapper_headers)
 
-libgda_threadwrapper_4_0_la_SOURCES = \
+libgda_threadwrapper_5_0_la_SOURCES = \
 	$(libgda_threadwrapper_headers) \
 	gda-thread-blob-op.h \
 	gda-thread-blob-op.c \
diff --git a/libgda/thread-wrapper/gda-thread-wrapper.h b/libgda/thread-wrapper/gda-thread-wrapper.h
index 7b98312..1c02026 100644
--- a/libgda/thread-wrapper/gda-thread-wrapper.h
+++ b/libgda/thread-wrapper/gda-thread-wrapper.h
@@ -1,5 +1,5 @@
-/* GDA library
- * Copyright (C) 2009 The GNOME Foundation.
+/*
+ * Copyright (C) 2009 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -62,12 +62,88 @@ struct _GdaThreadWrapperClass {
 	void (*_gda_reserved4) (void);
 };
 
+/**
+ * GdaThreadWrapperFunc:
+ * @arg: pointer to the data (which is the @arg argument passed to gda_thread_wrapper_execute_void())
+ * @error: a place to store errors
+ * @Returns: a pointer to some data which will be returned by gda_thread_wrapper_fetch_result()
+ *
+ * Specifies the type of function to be passed to gda_thread_wrapper_execute().
+ */
 typedef gpointer (*GdaThreadWrapperFunc) (gpointer arg, GError **error);
+
+/**
+ * GdaThreadWrapperVoidFunc:
+ * @arg: a pointer to the data (which is the @arg argument passed to gda_thread_wrapper_execute_void())
+ * @error: a place to store errors
+ *
+ * Specifies the type of function to be passed to gda_thread_wrapper_execute_void().
+ */
 typedef void (*GdaThreadWrapperVoidFunc) (gpointer arg, GError **error);
+
+/**
+ * GdaThreadWrapperCallback:
+ * @wrapper: the #GdaThreadWrapper
+ * @instance: a pointer to the instance which emitted the signal
+ * @signame: the name of the signal being emitted
+ * @n_param_values: number of GValue in @param_values
+ * @param_values: array of @n_param_values GValue
+ * @gda_reserved: reserved
+ * @data: a pointer to the data (which is the @data argument passed to gda_thread_wrapper_connect_raw())
+ *
+ * Specifies the type of function to be passed to gda_thread_wrapper_connect_raw()
+ */
 typedef void (*GdaThreadWrapperCallback) (GdaThreadWrapper *wrapper, gpointer instance, const gchar *signame,
 					  gint n_param_values, const GValue *param_values, gpointer gda_reserved,
 					  gpointer data);
 
+/**
+ * SECTION:gda-thread-wrapper
+ * @short_description: Execute functions in a sub thread
+ * @title: GdaThreadWrapper
+ * @stability: Stable
+ * @see_also:
+ *
+ * The purpose of the #GdaThreadWrapper object is to execute functions in an isolated sub thread. As the
+ * #GdaThreadWrapper is thread safe, one is able to isolate some code's execution is a <emphasis>private</emphasis>
+ * <emphasis>worker</emphasis> thread, and make a non thread safe code thread safe.
+ *
+ * The downside of this is that the actual execution of the code will be slower as it requires
+ * threads to be synchronized.
+ *
+ * The #GdaThreadWrapper implements its own locking mechanism and can safely be used from multiple
+ * threads at once without needing further locking.
+ *
+ * Each thread using a #GdaThreadWrapper object can use it as if it was the only user: the #GdaThreadWrapper will
+ * simply dispatch all the execution requests to its private <emphasis>worker</emphasis> thread and report the
+ * execution's status only to the thread which made the request.
+ *
+ * The user can also specify a callback function to be called when an object exmits a signal while being
+ * used by the worker thread, see the gda_thread_wrapper_connect_raw() method.
+ *
+ * The following diagram illustrates the conceptual working of the #GdaThreadWrapper object: here two user threads
+ * are represented (assigned a red and green colors), both using a single #GdaThreadWrapper, so in this diagram, 3 threads
+ * are present. The communication between the threads are handled by some #GAsyncQueue objects (in a transparent way for
+ * the user, presented here only for illustration purposes). The queue represented in yellow is where jobs are
+ * pushed by each user thread (step 1), and popped by the worker thread (step 2). Once the user thread has finished
+ * with a job, it stores the result along with the job and pushes it to the queue dedicated to the user thread
+ * (step 3) in this example the red queue (because the job was issued from the thread represented in red). The last
+ * step is when the user fetches the result (in its user thread), step 4.
+ *
+ * If, when the worker thread is busy with a job, a signal is emitted, and if the user has set up a signal handler
+ * using gda_thread_wrapper_connect_raw(),
+ * then a "job as signal" is created by the worker thread and pushed to the user thread as illustrated
+ * at the bottom of the diagram.
+ * <mediaobject>
+ *   <imageobject role="html">
+ *     <imagedata fileref="thread-wrapper.png" format="PNG" contentwidth="170mm"/>
+ *   </imageobject>
+ *   <textobject>
+ *     <phrase>GdaThreadWrapper's conceptual working</phrase>
+ *   </textobject>
+ * </mediaobject>
+ */
+
 GType                  gda_thread_wrapper_get_type          (void) G_GNUC_CONST;
 GdaThreadWrapper      *gda_thread_wrapper_new               (void);
 
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 1ec1c64..3ed1fe0 100755
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,6 +1,6 @@
 control-center/dsn-config.c
 control-center/dsn-properties-dialog.c
-control-center/gda-control-center-4.0.desktop.in
+control-center/gda-control-center-5.0.desktop.in
 control-center/gdaui-dsn-assistant.c
 control-center/gdaui-dsn-editor.c
 control-center/gdaui-login-dialog.c
@@ -22,7 +22,6 @@ libgda/gda-data-model-import.c
 libgda/gda-data-model-iter.c
 libgda/gda-data-proxy.c
 libgda/gda-data-select.c
-libgda/gda-easy.c
 libgda/gda-holder.c
 libgda/gda-init.c
 libgda/gda-log.c
@@ -250,7 +249,7 @@ tools/browser/browser-stock-icons.c
 tools/browser/browser-virtual-connection.c
 tools/browser/browser-window.c
 tools/browser/connection-binding-properties.c
-tools/browser/gda-browser-4.0.desktop.in
+tools/browser/gda-browser-5.0.desktop.in
 tools/browser/login-dialog.c
 tools/browser/main.c
 tools/browser/mgr-favorites.c
diff --git a/po/POTFILES.skip b/po/POTFILES.skip
index de79439..a1951b6 100755
--- a/po/POTFILES.skip
+++ b/po/POTFILES.skip
@@ -1,4 +1,4 @@
-doc/C/prov-writing.xml
+doc/C/prov-writing-assembly.xml
 libgda/sqlite/sql-parser.c/lemon.c
 libgda/sqlite/sql-parser.c/lempar.c
 libgda/sqlite/sqlite-src/sqlite3.c
diff --git a/providers/bdb/Makefile.am b/providers/bdb/Makefile.am
index b132443..6b7200f 100644
--- a/providers/bdb/Makefile.am
+++ b/providers/bdb/Makefile.am
@@ -18,7 +18,7 @@ libgda_bdb_la_SOURCES = \
 
 libgda_bdb_la_LDFLAGS = -export-dynamic -module -avoid-version $(NO_UNDEFINED) $(LIBTOOL_PROV_EXPORT_OPTIONS)
 libgda_bdb_la_LIBADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS) 
 
 noinst_PROGRAMS = gda-bdb-test
@@ -27,9 +27,9 @@ gda_bdb_test_SOURCES = gda-bdb-test.c
 gda_bdb_test_LDADD = \
 	$(LIBGDA_LIBS) \
 	$(BDB_LIBS) \
-	$(top_builddir)/libgda/libgda-4.0.la 
+	$(top_builddir)/libgda/libgda-5.0.la 
 
-xmldir   = $(datadir)/libgda-4.0
+xmldir   = $(datadir)/libgda-5.0
 xml_in_files = bdb_specs_dsn.xml.in
 
 @INTLTOOL_XML_RULE@
@@ -37,8 +37,8 @@ xml_in_files = bdb_specs_dsn.xml.in
 xml_DATA = $(xml_in_files:.xml.in=.xml)
 
 pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = libgda-bdb-4.0.pc
+pkgconfig_DATA = libgda-bdb-5.0.pc
 
-EXTRA_DIST = $(xml_in_files) libgda-bdb-4.0.pc.in
+EXTRA_DIST = $(xml_in_files) libgda-bdb-5.0.pc.in
 DISTCLEANFILES = $(xml_DATA)
 
diff --git a/providers/bdb/libgda-bdb-4.0.pc.in b/providers/bdb/libgda-bdb-5.0.pc.in
similarity index 100%
rename from providers/bdb/libgda-bdb-4.0.pc.in
rename to providers/bdb/libgda-bdb-5.0.pc.in
diff --git a/providers/bdbsql/Makefile.am b/providers/bdbsql/Makefile.am
index ddac536..884a664 100644
--- a/providers/bdbsql/Makefile.am
+++ b/providers/bdbsql/Makefile.am
@@ -19,7 +19,7 @@ libgda_bdbsql_la_LDFLAGS = -export-dynamic -module -avoid-version $(LIBTOOL_PROV
 libgda_bdbsql_la_LIBADD = \
 	$(top_builddir)/libgda/sqlite/libgda-bdbsqlite.la
 
-xmldir   = $(datadir)/libgda-4.0
+xmldir   = $(datadir)/libgda-5.0
 xml_in_files = \
 	bdbsql_specs_dsn.xml.in \
 	bdbsql_specs_create_db.xml.in \
@@ -38,7 +38,7 @@ xml_in_files = \
 xml_DATA = $(xml_in_files:.xml.in=.xml)
 
 pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = libgda-bdbsql-4.0.pc
+pkgconfig_DATA = libgda-bdbsql-5.0.pc
 
-EXTRA_DIST = $(xml_in_files) libgda-bdbsql-4.0.pc.in
+EXTRA_DIST = $(xml_in_files) libgda-bdbsql-5.0.pc.in
 DISTCLEANFILES = $(xml_DATA)
diff --git a/providers/bdbsql/libgda-bdbsql-4.0.pc.in b/providers/bdbsql/libgda-bdbsql-5.0.pc.in
similarity index 100%
rename from providers/bdbsql/libgda-bdbsql-4.0.pc.in
rename to providers/bdbsql/libgda-bdbsql-5.0.pc.in
diff --git a/providers/firebird/Makefile.am b/providers/firebird/Makefile.am
index 5af4c8d..db6fc4a 100644
--- a/providers/firebird/Makefile.am
+++ b/providers/firebird/Makefile.am
@@ -47,10 +47,10 @@ libgda_firebird_la_SOURCES = \
 
 libgda_firebird_la_LDFLAGS = -export-dynamic -module -avoid-version $(NO_UNDEFINED) $(LIBTOOL_PROV_EXPORT_OPTIONS)
 libgda_firebird_la_LIBADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS) #$(FIREBIRD_LIBS)
 
-xmldir   = $(datadir)/libgda-4.0
+xmldir   = $(datadir)/libgda-5.0
 xml_in_files = \
 	firebird_specs_dsn.xml.in \
 	firebird_specs_create_table.xml.in 
@@ -60,9 +60,9 @@ xml_in_files = \
 xml_DATA = $(xml_in_files:.xml.in=.xml) 
 
 pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = libgda-firebird-4.0.pc
+pkgconfig_DATA = libgda-firebird-5.0.pc
 
-EXTRA_DIST = $(xml_in_files) libgda-firebird-4.0.pc.in parser.y gen_def.c
+EXTRA_DIST = $(xml_in_files) libgda-firebird-5.0.pc.in parser.y gen_def.c
 DISTCLEANFILES = $(xml_DATA)
 
 CLEANFILES = parser.h parser.c parser.out firebird_token_types.h gen_def$(EXEEXT_FOR_BUILD)
diff --git a/providers/firebird/gda-firebird-provider.c b/providers/firebird/gda-firebird-provider.c
index aff7785..219ffcf 100644
--- a/providers/firebird/gda-firebird-provider.c
+++ b/providers/firebird/gda-firebird-provider.c
@@ -921,7 +921,6 @@ gda_firebird_provider_get_default_dbms_type (GdaServerProvider *provider, GdaCon
 	if ((type == G_TYPE_DATE) || 
 	    (type == GDA_TYPE_GEOMETRIC_POINT) ||
 	    (type == G_TYPE_OBJECT) ||
-	    (type == GDA_TYPE_LIST) ||
 	    (type == G_TYPE_STRING) ||
 	    (type == GDA_TYPE_TIME) ||
 	    (type == GDA_TYPE_TIMESTAMP) ||
diff --git a/providers/firebird/libgda-firebird-4.0.pc.in b/providers/firebird/libgda-firebird-5.0.pc.in
similarity index 100%
rename from providers/firebird/libgda-firebird-4.0.pc.in
rename to providers/firebird/libgda-firebird-5.0.pc.in
diff --git a/providers/jdbc/.gitignore b/providers/jdbc/.gitignore
index bfc0d68..2d0d7ec 100644
--- a/providers/jdbc/.gitignore
+++ b/providers/jdbc/.gitignore
@@ -1,5 +1,5 @@
 *.class
 *.jar
-gda-list-jdbc-providers-4.*
+gda-list-jdbc-providers-5.*
 gda-jdbc-test
 Gda*.h
diff --git a/providers/jdbc/Makefile.am b/providers/jdbc/Makefile.am
index d5c55ae..c8d4943 100644
--- a/providers/jdbc/Makefile.am
+++ b/providers/jdbc/Makefile.am
@@ -1,7 +1,7 @@
 providerdir=$(libdir)/libgda-$(GDA_ABI_MAJOR_VERSION).$(GDA_ABI_MINOR_VERSION)/providers
 provider_LTLIBRARIES = libgda-jdbc.la
 noinst_PROGRAMS = gda-jdbc-test
-bin_PROGRAMS = gda-list-jdbc-providers-4.0
+bin_PROGRAMS = gda-list-jdbc-providers-5.0
 
 #Rem: JDBC_CFLAGS and JDBC_LIBS are the compile and link flags necessary to use the
 # C API. It is specific to the API and should be computed in the configure.in script.
@@ -58,7 +58,7 @@ libgda_jdbc_la_SOURCES = \
 
 libgda_jdbc_la_LDFLAGS = -export-dynamic -module -avoid-version $(NO_UNDEFINED) $(LIBTOOL_PROV_EXPORT_OPTIONS)
 libgda_jdbc_la_LIBADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS)
 # rem: don't link with JAVA_LIBS because we don't want the dependency on it
 # (JVM runtime will be loaded when running)
@@ -73,7 +73,7 @@ endif
 $(jni_headers): $(jdbcprov_classes)
 	$(JAVAH) -classpath . -force `basename $@ | sed -e 's/\.h$$//'`
 
-jdbcprov_jar = gdaprovider-4.0.jar
+jdbcprov_jar = gdaprovider-5.0.jar
 jdbcprov_sources = \
 	provider.java \
 	meta.java \
@@ -95,7 +95,7 @@ clean-local:
 	rm -f $(jni_headers)
 	rm -f *.class
 
-xmldir   = $(datadir)/libgda-4.0
+xmldir   = $(datadir)/libgda-5.0
 xml_in_files = \
 	jdbc_specs_dsn.xml.in \
 	jdbc_specs_create_table.xml.in 
@@ -105,12 +105,12 @@ xml_in_files = \
 xml_DATA = $(xml_in_files:.xml.in=.xml) 
 
 pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = libgda-jdbc-4.0.pc
+pkgconfig_DATA = libgda-jdbc-5.0.pc
 
 doc_files = \
 	doc/structure.dia
 
-EXTRA_DIST = $(xml_in_files) libgda-jdbc-4.0.pc.in \
+EXTRA_DIST = $(xml_in_files) libgda-jdbc-5.0.pc.in \
 	$(jdbcprov_sources) \
 	$(doc_files) \
 	MANIFEST.MF
@@ -121,11 +121,11 @@ DISTCLEANFILES = $(xml_DATA)
 gda_jdbc_test_SOURCES = gda-jdbc-test.c
 gda_jdbc_test_LDADD = \
         $(LIBGDA_LIBS) \
-        $(top_builddir)/libgda/libgda-4.0.la
+        $(top_builddir)/libgda/libgda-5.0.la
 
 
-gda_list_jdbc_providers_4_0_SOURCES = gda-list-jdbc-providers.c
-gda_list_jdbc_providers_4_0_LDADD = \
+gda_list_jdbc_providers_5_0_SOURCES = gda-list-jdbc-providers.c
+gda_list_jdbc_providers_5_0_LDADD = \
         $(LIBGDA_LIBS) \
-        $(top_builddir)/libgda/libgda-4.0.la
+        $(top_builddir)/libgda/libgda-5.0.la
 
diff --git a/providers/jdbc/gda-jdbc-provider.c b/providers/jdbc/gda-jdbc-provider.c
index 919dd04..2818b25 100644
--- a/providers/jdbc/gda-jdbc-provider.c
+++ b/providers/jdbc/gda-jdbc-provider.c
@@ -989,7 +989,6 @@ gda_jdbc_provider_get_default_dbms_type (GdaServerProvider *provider, GdaConnect
 	if ((type == G_TYPE_DATE) || 
 	    (type == GDA_TYPE_GEOMETRIC_POINT) ||
 	    (type == G_TYPE_OBJECT) ||
-	    (type == GDA_TYPE_LIST) ||
 	    (type == G_TYPE_STRING) ||
 	    (type == GDA_TYPE_TIME) ||
 	    (type == GDA_TYPE_TIMESTAMP) ||
diff --git a/providers/jdbc/gda-jdbc-util.c b/providers/jdbc/gda-jdbc-util.c
index 4f44c30..cdf1408 100644
--- a/providers/jdbc/gda-jdbc-util.c
+++ b/providers/jdbc/gda-jdbc-util.c
@@ -40,7 +40,8 @@ _gda_jdbc_make_error (GdaConnection *cnc, gint error_code, gchar *sql_state, GEr
         GdaConnectionEventCode gda_code = GDA_CONNECTION_EVENT_CODE_UNKNOWN;
         GdaTransactionStatus *trans;
 
-        error_ev = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+        error_ev = GDA_CONNECTION_EVENT (g_object_new (GDA_TYPE_CONNECTION_EVENT, "type",
+						       (gint) GDA_CONNECTION_EVENT_ERROR, NULL));
 	if (error) {
 		gda_connection_event_set_description (error_ev,
 						      error->message ? error->message : _("No detail"));
diff --git a/providers/jdbc/libgda-jdbc-4.0.pc.in b/providers/jdbc/libgda-jdbc-5.0.pc.in
similarity index 100%
rename from providers/jdbc/libgda-jdbc-4.0.pc.in
rename to providers/jdbc/libgda-jdbc-5.0.pc.in
diff --git a/providers/jdbc/libmain.c b/providers/jdbc/libmain.c
index 30a95af..06cb39a 100644
--- a/providers/jdbc/libmain.c
+++ b/providers/jdbc/libmain.c
@@ -470,7 +470,7 @@ load_jvm ()
 	if (jvm_found) {
 		gchar *path;
 		GError *error = NULL;
-		path = g_build_filename (module_path, "gdaprovider-4.0.jar", NULL);
+		path = g_build_filename (module_path, "gdaprovider-5.0.jar", NULL);
 		jni_wrapper_create_vm (&_jdbc_provider_java_vm, __CreateJavaVM, module_path, path, &error);
 		if (!_jdbc_provider_java_vm) {
 			if (g_getenv ("GDA_SHOW_PROVIDER_LOADING_ERROR"))
diff --git a/providers/mdb/Makefile.am b/providers/mdb/Makefile.am
index b5bcfdb..2fb39e6 100644
--- a/providers/mdb/Makefile.am
+++ b/providers/mdb/Makefile.am
@@ -24,7 +24,7 @@ AM_CPPFLAGS = \
 	$(LIBGDA_CFLAGS) \
 	$(LIBGDA_WFLAGS) \
 	$(extra_mdb_cflags) \
-	-DLIBGDA_DATA_DIR=\""$(datadir)/libgda-4.0"\"
+	-DLIBGDA_DATA_DIR=\""$(datadir)/libgda-5.0"\"
 
 libgda_mdb_la_SOURCES = \
 	gda-mdb-provider.c \
@@ -34,11 +34,11 @@ libgda_mdb_la_SOURCES = \
 
 libgda_mdb_la_LDFLAGS = -export-dynamic -module -avoid-version $(NO_UNDEFINED) $(LIBTOOL_PROV_EXPORT_OPTIONS)
 libgda_mdb_la_LIBADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS) \
 	$(extra_mdb_ldflags)
 
-xmldir   = $(datadir)/libgda-4.0
+xmldir   = $(datadir)/libgda-5.0
 xml_in_files = mdb_specs_dsn.xml.in
 
 @INTLTOOL_XML_RULE@
@@ -46,9 +46,9 @@ xml_in_files = mdb_specs_dsn.xml.in
 xml_DATA = $(xml_in_files:.xml.in=.xml)
 
 pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = libgda-mdb-4.0.pc
+pkgconfig_DATA = libgda-mdb-5.0.pc
 
-EXTRA_DIST = $(xml_in_files) libgda-mdb-4.0.pc.in
+EXTRA_DIST = $(xml_in_files) libgda-mdb-5.0.pc.in
 DISTCLEANFILES = $(xml_DATA)
 
 
diff --git a/providers/mdb/libgda-mdb-4.0.pc.in b/providers/mdb/libgda-mdb-5.0.pc.in
similarity index 100%
rename from providers/mdb/libgda-mdb-4.0.pc.in
rename to providers/mdb/libgda-mdb-5.0.pc.in
diff --git a/providers/mysql/Makefile.am b/providers/mysql/Makefile.am
index 9a0a4c6..73d5f6a 100644
--- a/providers/mysql/Makefile.am
+++ b/providers/mysql/Makefile.am
@@ -31,11 +31,11 @@ libgda_mysql_la_SOURCES = \
 
 libgda_mysql_la_LDFLAGS = -export-dynamic -module -avoid-version $(NO_UNDEFINED) $(LIBTOOL_PROV_EXPORT_OPTIONS)
 libgda_mysql_la_LIBADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(top_builddir)/providers/reuseable/mysql/libgda-mysql.la \
 	$(LIBGDA_LIBS) $(MYSQL_LIBS)
 
-xmldir   = $(datadir)/libgda-4.0
+xmldir   = $(datadir)/libgda-5.0
 xml_in_files = \
 	mysql_specs_create_db.xml.in \
 	mysql_specs_drop_db.xml.in \
@@ -57,7 +57,7 @@ xml_in_files = \
 xml_DATA = $(xml_in_files:.xml.in=.xml) 
 
 pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = libgda-mysql-4.0.pc
+pkgconfig_DATA = libgda-mysql-5.0.pc
 
-EXTRA_DIST = $(xml_in_files) libgda-mysql-4.0.pc.in
+EXTRA_DIST = $(xml_in_files) libgda-mysql-5.0.pc.in
 DISTCLEANFILES = $(xml_DATA)
diff --git a/providers/mysql/gda-mysql-provider.c b/providers/mysql/gda-mysql-provider.c
index 76c36bc..162a966 100644
--- a/providers/mysql/gda-mysql-provider.c
+++ b/providers/mysql/gda-mysql-provider.c
@@ -1,5 +1,5 @@
 /* GDA Mysql provider
- * Copyright (C) 2008 - 2010 The GNOME Foundation.
+ * Copyright (C) 2008 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Carlos Savoretti <csavoretti gmail com>
@@ -506,11 +506,7 @@ real_open_connection (const gchar  *host,
 						  (port > 0) ? port : 0,
 						  socket, flags);
 	if (!return_mysql || mysql != return_mysql) {
-#if GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 18
-		g_set_error (error, 0, 0, "%s", mysql_error (mysql));
-#else
 		g_set_error_literal (error, GDA_SERVER_PROVIDER_ERROR, 0, mysql_error (mysql));
-#endif
 		g_free (mysql);
 		mysql = NULL;
 	}
@@ -1346,8 +1342,6 @@ gda_mysql_provider_get_default_dbms_type (GdaServerProvider  *provider,
 		return "text";
 	if (type == G_TYPE_INT)
 		return "int";
-	if (type == GDA_TYPE_LIST)
-		return "text";
 	if (type == GDA_TYPE_NUMERIC)
 		return "numeric";
 	if (type == G_TYPE_FLOAT)
@@ -2886,7 +2880,7 @@ gda_mysql_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
 			gchar *tmp, *ptr;
 			tmp = my_remove_quotes (g_strdup (id));
 			if (kwfunc (tmp)) {
-				ptr = gda_sql_identifier_add_quotes (tmp);
+				ptr = gda_sql_identifier_force_quotes (tmp);
 				g_free (tmp);
 				return ptr;
 			}
@@ -2896,13 +2890,13 @@ gda_mysql_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
 				    (*ptr == '_'))
 					continue;
 				else {
-					ptr = gda_sql_identifier_add_quotes (tmp);
+					ptr = gda_sql_identifier_force_quotes (tmp);
 					g_free (tmp);
 					return ptr;
 				}
 			}
 			return tmp;
-			/*			ptr = gda_sql_identifier_add_quotes (tmp);
+			/*			ptr = gda_sql_identifier_force_quotes (tmp);
 			g_free (tmp);
 			return ptr;*/
 		}
@@ -2926,7 +2920,7 @@ gda_mysql_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
 			gchar *tmp, *ptr;
 			tmp = my_remove_quotes (g_strdup (id));
 			if (kwfunc (tmp)) {
-				ptr = gda_sql_identifier_add_quotes (tmp);
+				ptr = gda_sql_identifier_force_quotes (tmp);
 				g_free (tmp);
 				return ptr;
 			}
@@ -2938,7 +2932,7 @@ gda_mysql_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
 					    (*ptr == '_'))
 						continue;
 					else {
-						ptr = gda_sql_identifier_add_quotes (tmp);
+						ptr = gda_sql_identifier_force_quotes (tmp);
 						g_free (tmp);
 						return ptr;
 					}
@@ -2954,7 +2948,7 @@ gda_mysql_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
 					    (*ptr == '_'))
 						continue;
 					else {
-						ptr = gda_sql_identifier_add_quotes (tmp);
+						ptr = gda_sql_identifier_force_quotes (tmp);
 						g_free (tmp);
 						return ptr;
 					}
diff --git a/providers/mysql/libgda-mysql-4.0.pc.in b/providers/mysql/libgda-mysql-5.0.pc.in
similarity index 100%
rename from providers/mysql/libgda-mysql-4.0.pc.in
rename to providers/mysql/libgda-mysql-5.0.pc.in
diff --git a/providers/oracle/Makefile.am b/providers/oracle/Makefile.am
index 2710dbc..c65e162 100644
--- a/providers/oracle/Makefile.am
+++ b/providers/oracle/Makefile.am
@@ -58,10 +58,10 @@ libgda_oracle_la_SOURCES = \
 
 libgda_oracle_la_LDFLAGS = -export-dynamic -module -avoid-version $(NO_UNDEFINED) $(LIBTOOL_PROV_EXPORT_OPTIONS)
 libgda_oracle_la_LIBADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS) $(ORACLE_LIBS)
 
-xmldir   = $(datadir)/libgda-4.0
+xmldir   = $(datadir)/libgda-5.0
 xml_in_files = \
 	oracle_specs_dsn.xml.in \
 	oracle_specs_create_table.xml.in 
@@ -71,9 +71,9 @@ xml_in_files = \
 xml_DATA = $(xml_in_files:.xml.in=.xml) 
 
 pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = libgda-oracle-4.0.pc
+pkgconfig_DATA = libgda-oracle-5.0.pc
 
-EXTRA_DIST = $(xml_in_files) libgda-oracle-4.0.pc.in parser.y gen_def.c $(keyword_files)
+EXTRA_DIST = $(xml_in_files) libgda-oracle-5.0.pc.in parser.y gen_def.c $(keyword_files)
 DISTCLEANFILES = $(xml_DATA)
 
 CLEANFILES = parser.h parser.c parser.out oracle_token_types.h gen_def$(EXEEXT_FOR_BUILD) \
diff --git a/providers/oracle/gda-oracle-meta.c b/providers/oracle/gda-oracle-meta.c
index 06c3315..3293610 100644
--- a/providers/oracle/gda-oracle-meta.c
+++ b/providers/oracle/gda-oracle-meta.c
@@ -501,7 +501,7 @@ oracle_identifier_to_value (const gchar *sqlid)
 		for (ptr = sqlid; *ptr; ptr++) {
 			if ((*ptr == ' ') || (*ptr != g_ascii_toupper (*ptr))) {
 				/* add quotes */
-				g_value_take_string (v, gda_sql_identifier_add_quotes (sqlid));
+				g_value_take_string (v, gda_sql_identifier_force_quotes (sqlid));
 				return v;
 			}
 		}
@@ -509,7 +509,7 @@ oracle_identifier_to_value (const gchar *sqlid)
 		g_value_set_string (v, sqlid);
 	}
 	else
-		g_value_take_string (v, gda_sql_identifier_add_quotes (sqlid));
+		g_value_take_string (v, gda_sql_identifier_force_quotes (sqlid));
 	return v;
 }
 
diff --git a/providers/oracle/gda-oracle-provider.c b/providers/oracle/gda-oracle-provider.c
index 653ac12..52c9c4c 100644
--- a/providers/oracle/gda-oracle-provider.c
+++ b/providers/oracle/gda-oracle-provider.c
@@ -1,5 +1,5 @@
-/* GDA Oracle provider
- * Copyright (C) 2009 - 2010 The GNOME Foundation.
+/*
+ * Copyright (C) 2009 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Rodrigo Moya <rodrigo gnome-db org>
@@ -1198,7 +1198,6 @@ gda_oracle_provider_get_default_dbms_type (GdaServerProvider *provider, GdaConne
 	if ((type == G_TYPE_DATE) || 
 	    (type == GDA_TYPE_GEOMETRIC_POINT) ||
 	    (type == G_TYPE_OBJECT) ||
-	    (type == GDA_TYPE_LIST) ||
 	    (type == G_TYPE_STRING) ||
 	    (type == GDA_TYPE_TIME) ||
 	    (type == GDA_TYPE_TIMESTAMP) ||
@@ -1294,7 +1293,6 @@ oracle_render_select_target (GdaSqlSelectTarget *target, GdaSqlRenderingContext
 {
         GString *string;
         gchar *str;
-	gpointer tmp;
 
         g_return_val_if_fail (target, NULL);
         g_return_val_if_fail (GDA_SQL_ANY_PART (target)->type == GDA_SQL_ANY_SQL_SELECT_TARGET, NULL);
@@ -1310,8 +1308,9 @@ oracle_render_select_target (GdaSqlSelectTarget *target, GdaSqlRenderingContext
 		g_free (str);
 	}
 	else {
+		gboolean tmp;
 		tmp = target->expr->value_is_ident;
-		target->expr->value_is_ident = (gpointer) 0x1;
+		target->expr->value_is_ident = TRUE;
 		str = context->render_expr (target->expr, context, NULL, NULL, error);
 		target->expr->value_is_ident = tmp;
 		string = g_string_new (str);
@@ -2372,7 +2371,7 @@ gda_oracle_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
 		gchar *tmp, *ptr;
 		tmp = ora_remove_quotes (g_strdup (id));
 		if (kwfunc (tmp)) {
-			ptr = gda_sql_identifier_add_quotes (tmp);
+			ptr = gda_sql_identifier_force_quotes (tmp);
 			g_free (tmp);
 			return ptr;
 		}
@@ -2384,7 +2383,7 @@ gda_oracle_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
 				    (*ptr == '_'))
 					continue;
 				else {
-					ptr = gda_sql_identifier_add_quotes (tmp);
+					ptr = gda_sql_identifier_force_quotes (tmp);
 					g_free (tmp);
 					return ptr;
 				}
@@ -2403,7 +2402,7 @@ gda_oracle_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
 					    (*ptr == '_'))
 						continue;
 					else {
-						ptr = gda_sql_identifier_add_quotes (tmp);
+						ptr = gda_sql_identifier_force_quotes (tmp);
 						g_free (tmp);
 						return ptr;
 					}
@@ -2411,7 +2410,7 @@ gda_oracle_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
 				else if ((*ptr >= 'A') && (*ptr <= 'Z'))
 					*ptr += 'a' - 'A';
 				else if ((*ptr >= '0') && (*ptr <= '9') && (ptr == tmp)) {
-					ptr = gda_sql_identifier_add_quotes (tmp);
+					ptr = gda_sql_identifier_force_quotes (tmp);
 					g_free (tmp);
 					return ptr;
 				}
diff --git a/providers/oracle/libgda-oracle-4.0.pc.in b/providers/oracle/libgda-oracle-5.0.pc.in
similarity index 100%
rename from providers/oracle/libgda-oracle-4.0.pc.in
rename to providers/oracle/libgda-oracle-5.0.pc.in
diff --git a/providers/postgres/Makefile.am b/providers/postgres/Makefile.am
index 4cb0a5a..88e54c8 100644
--- a/providers/postgres/Makefile.am
+++ b/providers/postgres/Makefile.am
@@ -28,11 +28,11 @@ libgda_postgres_la_SOURCES = \
 
 libgda_postgres_la_LDFLAGS = -export-dynamic -module -avoid-version $(NO_UNDEFINED) $(LIBTOOL_PROV_EXPORT_OPTIONS)
 libgda_postgres_la_LIBADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(top_builddir)/providers/reuseable/postgres/libgda-postgres.la \
 	$(LIBGDA_LIBS) $(POSTGRES_LIBS)
 
-xmldir   = $(datadir)/libgda-4.0
+xmldir   = $(datadir)/libgda-5.0
 xml_in_files = \
 	postgres_specs_create_db.xml.in \
         postgres_specs_drop_db.xml.in \
@@ -56,7 +56,7 @@ xml_in_files = \
 xml_DATA = $(xml_in_files:.xml.in=.xml) 
 
 pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = libgda-postgres-4.0.pc
+pkgconfig_DATA = libgda-postgres-5.0.pc
 
-EXTRA_DIST = $(xml_in_files) libgda-postgres-4.0.pc.in
+EXTRA_DIST = $(xml_in_files) libgda-postgres-5.0.pc.in
 DISTCLEANFILES = $(xml_DATA)
diff --git a/providers/postgres/gda-postgres-provider.c b/providers/postgres/gda-postgres-provider.c
index b307651..8f8feb7 100644
--- a/providers/postgres/gda-postgres-provider.c
+++ b/providers/postgres/gda-postgres-provider.c
@@ -1389,8 +1389,6 @@ gda_postgres_provider_get_default_dbms_type (GdaServerProvider *provider, GdaCon
                 return "text";
         if (type == G_TYPE_INT)
                 return "int4";
-        if (type == GDA_TYPE_LIST)
-                return "text";
         if (type == GDA_TYPE_NUMERIC)
                 return "numeric";
         if (type == G_TYPE_FLOAT)
@@ -2480,7 +2478,7 @@ gda_postgresql_identifier_quote (G_GNUC_UNUSED GdaServerProvider *provider, GdaC
 		gchar *tmp, *ptr;
 		tmp = pg_remove_quotes (g_strdup (id));
 		if (kwfunc (tmp)) {
-			ptr = gda_sql_identifier_add_quotes (tmp);
+			ptr = gda_sql_identifier_force_quotes (tmp);
 			g_free (tmp);
 			return ptr;
 		}
@@ -2492,7 +2490,7 @@ gda_postgresql_identifier_quote (G_GNUC_UNUSED GdaServerProvider *provider, GdaC
 				    (*ptr == '_'))
 					continue;
 				else {
-					ptr = gda_sql_identifier_add_quotes (tmp);
+					ptr = gda_sql_identifier_force_quotes (tmp);
 					g_free (tmp);
 					return ptr;
 				}
@@ -2507,7 +2505,7 @@ gda_postgresql_identifier_quote (G_GNUC_UNUSED GdaServerProvider *provider, GdaC
 					    (*ptr == '_'))
 						continue;
 					else {
-						ptr = gda_sql_identifier_add_quotes (tmp);
+						ptr = gda_sql_identifier_force_quotes (tmp);
 						g_free (tmp);
 						return ptr;
 					}
@@ -2515,7 +2513,7 @@ gda_postgresql_identifier_quote (G_GNUC_UNUSED GdaServerProvider *provider, GdaC
 				else if ((*ptr >= 'A') && (*ptr <= 'Z'))
 					*ptr += 'a' - 'A';
 				else if ((*ptr >= '0') && (*ptr <= '9') && (ptr == tmp)) {
-					ptr = gda_sql_identifier_add_quotes (tmp);
+					ptr = gda_sql_identifier_force_quotes (tmp);
 					g_free (tmp);
 					return ptr;
 				}
diff --git a/providers/postgres/libgda-postgres-4.0.pc.in b/providers/postgres/libgda-postgres-5.0.pc.in
similarity index 100%
rename from providers/postgres/libgda-postgres-4.0.pc.in
rename to providers/postgres/libgda-postgres-5.0.pc.in
diff --git a/providers/reuseable/mysql/Makefile.am b/providers/reuseable/mysql/Makefile.am
index bff3c12..acb7c26 100644
--- a/providers/reuseable/mysql/Makefile.am
+++ b/providers/reuseable/mysql/Makefile.am
@@ -42,7 +42,7 @@ libgda_mysql_la_SOURCES = \
         mysql_token_types.h
 
 libgda_mysql_la_LIBADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS)
 
 EXTRA_DIST = $(xml_in_files) parser.y gen_def.c $(keyword_files)
diff --git a/providers/reuseable/postgres/Makefile.am b/providers/reuseable/postgres/Makefile.am
index 09bcbd4..146a4a3 100644
--- a/providers/reuseable/postgres/Makefile.am
+++ b/providers/reuseable/postgres/Makefile.am
@@ -41,7 +41,7 @@ libgda_postgres_la_SOURCES = \
         postgres_token_types.h
 
 libgda_postgres_la_LIBADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS)
 
 EXTRA_DIST = parser.y gen_def.c $(keyword_files)
diff --git a/providers/skel-implementation/capi/Makefile.am b/providers/skel-implementation/capi/Makefile.am
index 96b0348..b11f156 100644
--- a/providers/skel-implementation/capi/Makefile.am
+++ b/providers/skel-implementation/capi/Makefile.am
@@ -56,10 +56,10 @@ libgda_capi_la_SOURCES = \
 
 libgda_capi_la_LDFLAGS = -export-dynamic -module -avoid-version $(NO_UNDEFINED) $(LIBTOOL_PROV_EXPORT_OPTIONS)
 libgda_capi_la_LIBADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS) #$(CAPI_LIBS)
 
-xmldir   = $(datadir)/libgda-4.0
+xmldir   = $(datadir)/libgda-5.0
 xml_in_files = \
 	capi_specs_dsn.xml.in \
 	capi_specs_create_table.xml.in 
@@ -70,10 +70,10 @@ xml_in_files = \
 noinst_DATA = $(xml_in_files:.xml.in=.xml)
 
 pkgconfigdir = $(libdir)/pkgconfig
-#pkgconfig_DATA = libgda-capi-4.0.pc
-noinst_DATA += libgda-capi-4.0.pc
+#pkgconfig_DATA = libgda-capi-5.0.pc
+noinst_DATA += libgda-capi-5.0.pc
 
-EXTRA_DIST = $(xml_in_files) libgda-capi-4.0.pc.in parser.y gen_def.c $(keyword_files)
+EXTRA_DIST = $(xml_in_files) libgda-capi-5.0.pc.in parser.y gen_def.c $(keyword_files)
 DISTCLEANFILES = $(noinst_DATA)
 
 CLEANFILES = parser.h parser.c parser.out capi_token_types.h gen_def$(EXEEXT_FOR_BUILD) \
diff --git a/providers/skel-implementation/capi/gda-capi-provider.c b/providers/skel-implementation/capi/gda-capi-provider.c
index 2732b89..00ec576 100644
--- a/providers/skel-implementation/capi/gda-capi-provider.c
+++ b/providers/skel-implementation/capi/gda-capi-provider.c
@@ -855,7 +855,6 @@ gda_capi_provider_get_default_dbms_type (GdaServerProvider *provider, GdaConnect
 	if ((type == G_TYPE_DATE) || 
 	    (type == GDA_TYPE_GEOMETRIC_POINT) ||
 	    (type == G_TYPE_OBJECT) ||
-	    (type == GDA_TYPE_LIST) ||
 	    (type == G_TYPE_STRING) ||
 	    (type == GDA_TYPE_TIME) ||
 	    (type == GDA_TYPE_TIMESTAMP) ||
diff --git a/providers/skel-implementation/capi/libgda-capi-4.0.pc.in b/providers/skel-implementation/capi/libgda-capi-5.0.pc.in
similarity index 100%
rename from providers/skel-implementation/capi/libgda-capi-4.0.pc.in
rename to providers/skel-implementation/capi/libgda-capi-5.0.pc.in
diff --git a/providers/skel-implementation/models/Makefile.am b/providers/skel-implementation/models/Makefile.am
index 0ff2d21..f0e3031 100644
--- a/providers/skel-implementation/models/Makefile.am
+++ b/providers/skel-implementation/models/Makefile.am
@@ -18,10 +18,10 @@ libgda_models_la_SOURCES = \
 
 libgda_models_la_LDFLAGS = -export-dynamic -module -avoid-version $(NO_UNDEFINED) $(LIBTOOL_PROV_EXPORT_OPTIONS)
 libgda_models_la_LIBADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS) 
 
-xmldir   = $(datadir)/libgda-4.0
+xmldir   = $(datadir)/libgda-5.0
 xml_in_files = models_specs_dsn.xml.in
 
 @INTLTOOL_XML_RULE@
@@ -30,9 +30,9 @@ xml_in_files = models_specs_dsn.xml.in
 noinst_DATA = $(xml_in_files:.xml.in=.xml)
 
 pkgconfigdir = $(libdir)/pkgconfig
-#pkgconfig_DATA = libgda-models-4.0.pc
-noinst_DATA += libgda-models-4.0.pc
+#pkgconfig_DATA = libgda-models-5.0.pc
+noinst_DATA += libgda-models-5.0.pc
 
-EXTRA_DIST = $(xml_in_files) libgda-models-4.0.pc.in
+EXTRA_DIST = $(xml_in_files) libgda-models-5.0.pc.in
 DISTCLEANFILES = $(noinst_DATA)
 
diff --git a/providers/skel-implementation/models/libgda-models-4.0.pc.in b/providers/skel-implementation/models/libgda-models-5.0.pc.in
similarity index 100%
rename from providers/skel-implementation/models/libgda-models-4.0.pc.in
rename to providers/skel-implementation/models/libgda-models-5.0.pc.in
diff --git a/providers/sqlcipher/Makefile.am b/providers/sqlcipher/Makefile.am
index 6fb9a3d..30e060d 100644
--- a/providers/sqlcipher/Makefile.am
+++ b/providers/sqlcipher/Makefile.am
@@ -25,7 +25,7 @@ libgda_sqlcipher_la_LIBADD = \
 	$(top_builddir)/libgda/sqlite/libgda-sqlcipher.la \
 	$(LIBCRYPTO_LIBS)
 
-xmldir   = $(datadir)/libgda-4.0
+xmldir   = $(datadir)/libgda-5.0
 xml_in_files = \
 	sqlcipher_specs_auth.xml.in \
 	sqlcipher_specs_dsn.xml.in \
@@ -45,10 +45,10 @@ xml_in_files = \
 xml_DATA = $(xml_in_files:.xml.in=.xml)
 
 pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = libgda-sqlcipher-4.0.pc
+pkgconfig_DATA = libgda-sqlcipher-5.0.pc
 
 EXTRA_DIST = $(xml_in_files) \
-	libgda-sqlcipher-4.0.pc.in \
+	libgda-sqlcipher-5.0.pc.in \
 	sqlcipher.patch \
 	COPYING.sqlcipher
 
diff --git a/providers/sqlcipher/libgda-sqlcipher-4.0.pc.in b/providers/sqlcipher/libgda-sqlcipher-5.0.pc.in
similarity index 100%
rename from providers/sqlcipher/libgda-sqlcipher-4.0.pc.in
rename to providers/sqlcipher/libgda-sqlcipher-5.0.pc.in
diff --git a/providers/sqlcipher/sqlcipher.patch b/providers/sqlcipher/sqlcipher.patch
index 1bc56f3..6e3f249 100644
--- a/providers/sqlcipher/sqlcipher.patch
+++ b/providers/sqlcipher/sqlcipher.patch
@@ -1,6 +1,6 @@
---- sqlite3.c.sqlite	2010-10-05 08:59:19.000000000 +0200
-+++ sqlite3.c	2010-10-05 08:58:35.000000000 +0200
-@@ -10994,6 +10994,1343 @@
+--- sqlite3.c.sqlite	2011-02-21 15:58:43.000000000 +0100
++++ sqlite3.c	2011-02-21 15:58:21.000000000 +0100
+@@ -11408,6 +11408,1483 @@
  #endif /* _SQLITEINT_H_ */
  
  /************** End of sqliteInt.h *******************************************/
@@ -455,16 +455,17 @@
 +  u8 pageSizeFixed;     /* True if the page size can no longer be changed */
 +  u8 secureDelete;      /* True if secure_delete is enabled */
 +  u8 initiallyEmpty;    /* Database is empty at start of transaction */
++  u8 openFlags;         /* Flags to sqlite3BtreeOpen() */
 +#ifndef SQLITE_OMIT_AUTOVACUUM
 +  u8 autoVacuum;        /* True if auto-vacuum is enabled */
 +  u8 incrVacuum;        /* True if incr-vacuum is enabled */
 +#endif
++  u8 inTransaction;     /* Transaction state */
++  u8 doNotUseWAL;       /* If true, do not open write-ahead-log file */
 +  u16 maxLocal;         /* Maximum local payload in non-LEAFDATA tables */
 +  u16 minLocal;         /* Minimum local payload in non-LEAFDATA tables */
 +  u16 maxLeaf;          /* Maximum local payload in a LEAFDATA table */
 +  u16 minLeaf;          /* Minimum local payload in a LEAFDATA table */
-+  u8 inTransaction;     /* Transaction state */
-+  u8 doNotUseWAL;       /* If true, do not open write-ahead-log file */
 +  u32 pageSize;         /* Total number of bytes on a page */
 +  u32 usableSize;       /* Number of usable bytes on each page */
 +  int nTransaction;     /* Number of open transactions (read + write) */
@@ -491,8 +492,8 @@
 +*/
 +typedef struct CellInfo CellInfo;
 +struct CellInfo {
-+  u8 *pCell;     /* Pointer to the start of cell content */
 +  i64 nKey;      /* The key for INTKEY tables, or number of bytes in key */
++  u8 *pCell;     /* Pointer to the start of cell content */
 +  u32 nData;     /* Number of bytes of data */
 +  u32 nPayload;  /* Total amount of payload */
 +  u16 nHeader;   /* Size of the cell content header in bytes */
@@ -534,20 +535,20 @@
 +  Pgno pgnoRoot;            /* The root page of this tree */
 +  sqlite3_int64 cachedRowid; /* Next rowid cache.  0 means not valid */
 +  CellInfo info;            /* A parse of the cell we are pointing at */
++  i64 nKey;        /* Size of pKey, or last integer key */
++  void *pKey;      /* Saved key that was cursor's last known position */
++  int skipNext;    /* Prev() is noop if negative. Next() is noop if positive */
 +  u8 wrFlag;                /* True if writable */
 +  u8 atLast;                /* Cursor pointing to the last entry */
 +  u8 validNKey;             /* True if info.nKey is valid */
 +  u8 eState;                /* One of the CURSOR_XXX constants (see below) */
-+  void *pKey;      /* Saved key that was cursor's last known position */
-+  i64 nKey;        /* Size of pKey, or last integer key */
-+  int skipNext;    /* Prev() is noop if negative. Next() is noop if positive */
 +#ifndef SQLITE_OMIT_INCRBLOB
-+  u8 isIncrblobHandle;      /* True if this cursor is an incr. io handle */
 +  Pgno *aOverflow;          /* Cache of overflow page locations */
++  u8 isIncrblobHandle;      /* True if this cursor is an incr. io handle */
 +#endif
 +  i16 iPage;                            /* Index of current page in apPage */
-+  MemPage *apPage[BTCURSOR_MAX_DEPTH];  /* Pages from root to current page */
 +  u16 aiIdx[BTCURSOR_MAX_DEPTH];        /* Current index in apPage[i] */
++  MemPage *apPage[BTCURSOR_MAX_DEPTH];  /* Pages from root to current page */
 +};
 +
 +/*
@@ -741,6 +742,10 @@
 +#define PBKDF2_ITER 4000
 +#endif
 +
++#ifndef DEFAULT_USE_HMAC
++#define DEFAULT_USE_HMAC 1
++#endif
++
 +SQLITE_PRIVATE void sqlite3pager_get_codec(Pager *pPager, void **ctx);
 +SQLITE_PRIVATE int sqlite3pager_is_mj_pgno(Pager *pPager, Pgno pgno);
 +SQLITE_PRIVATE sqlite3_file *sqlite3Pager_get_fd(Pager *pPager);
@@ -773,14 +778,20 @@
 +  int kdf_iter;
 +  int key_sz;
 +  int iv_sz;
++  int block_sz;
 +  int pass_sz;
++  int reserve_sz;
++  int hmac_sz;
++  int use_hmac;
 +  unsigned char *key;
++  unsigned char *hmac_key;
 +  char *pass;
 +} cipher_ctx;
 +
 +typedef struct {
 +  int kdf_salt_sz;
 +  int mode_rekey;
++  int page_sz;
 +  unsigned char *kdf_salt;
 +  unsigned char *buffer;
 +  Btree *pBt;
@@ -812,6 +823,15 @@
 +  }
 +}
 +
++static int fixed_time_memcmp(const unsigned char *a0, const unsigned char *a1, int len) {
++  int i = 0, noMatch = 0;
++
++  for(i = 0; i < len; i++) {
++    noMatch = (noMatch || (a0[i] != a1[i]));
++  }
++  
++  return noMatch;
++}
 +
 +/**
 +  * Free and wipe memory
@@ -858,7 +878,9 @@
 +  if(ctx == NULL) return SQLITE_NOMEM;
 +  memset(ctx, 0, sizeof(cipher_ctx)); 
 +  ctx->key = sqlite3Malloc(EVP_MAX_KEY_LENGTH);
++  ctx->hmac_key = sqlite3Malloc(EVP_MAX_KEY_LENGTH);
 +  if(ctx->key == NULL) return SQLITE_NOMEM;
++  if(ctx->hmac_key == NULL) return SQLITE_NOMEM;
 +  return SQLITE_OK;
 +}
 +
@@ -869,6 +891,7 @@
 +  cipher_ctx *ctx = *iCtx;
 +  CODEC_TRACE(("cipher_ctx_free: entered iCtx=%d\n", iCtx));
 +  codec_free(ctx->key, ctx->key_sz);
++  codec_free(ctx->hmac_key, ctx->key_sz);
 +  codec_free(ctx->pass, ctx->pass_sz);
 +  codec_free(ctx, sizeof(cipher_ctx)); 
 +}
@@ -883,15 +906,22 @@
 +  */
 +static int cipher_ctx_copy(cipher_ctx *target, cipher_ctx *source) {
 +  void *key = target->key; 
++  void *hmac_key = target->hmac_key; 
++
 +  CODEC_TRACE(("cipher_ctx_copy: entered target=%d, source=%d\n", target, source));
 +  codec_free(target->pass, target->pass_sz); 
 +  memcpy(target, source, sizeof(cipher_ctx));
 +  
 +  target->key = key; //restore pointer to previously allocated key data
 +  memcpy(target->key, source->key, EVP_MAX_KEY_LENGTH);
++
++  target->hmac_key = hmac_key; //restore pointer to previously allocated hmac key data
++  memcpy(target->hmac_key, source->hmac_key, EVP_MAX_KEY_LENGTH);
++
 +  target->pass = sqlite3Malloc(source->pass_sz);
 +  if(target->pass == NULL) return SQLITE_NOMEM;
 +  memcpy(target->pass, source->pass, source->pass_sz);
++
 +  return SQLITE_OK;
 +}
 +
@@ -912,7 +942,7 @@
 +    && c1->pass_sz == c2->pass_sz
 +    && (
 +      c1->pass == c2->pass
-+      || !memcmp(c1->pass, c2->pass, c1->pass_sz)
++      || !fixed_time_memcmp(c1->pass, c2->pass, c1->pass_sz)
 +    ) 
 +  ) return 0;
 +  return 1;
@@ -941,11 +971,13 @@
 +  * Otherwise, a key data will be derived using PBKDF2
 +  * 
 +  * returns SQLITE_OK if initialization was successful
-+  * returns SQLITE_NOMEM if the key could't be derived (for instance if pass is NULL or pass_sz is 0)
++  * returns SQLITE_ERROR if the key could't be derived (for instance if pass is NULL or pass_sz is 0)
 +  */
 +static int codec_key_derive(codec_ctx *ctx, cipher_ctx *c_ctx) { 
-+  CODEC_TRACE(("codec_key_derive: entered c_ctx->pass=%s, c_ctx->pass_sz=%d ctx->kdf_salt=%d ctx->kdf_salt_sz=%d c_ctx->kdf_iter=%d c_ctx->key_sz=%d\n", 
-+    c_ctx->pass, c_ctx->pass_sz, ctx->kdf_salt, ctx->kdf_salt_sz, c_ctx->kdf_iter, c_ctx->key_sz));
++  CODEC_TRACE(("codec_key_derive: entered c_ctx->pass=%s, c_ctx->pass_sz=%d \
++                ctx->kdf_salt=%d ctx->kdf_salt_sz=%d c_ctx->kdf_iter=%d c_ctx->key_sz=%d\n", 
++                c_ctx->pass, c_ctx->pass_sz, ctx->kdf_salt, ctx->kdf_salt_sz, 
++                c_ctx->kdf_iter, c_ctx->key_sz));
 +
 +  if(c_ctx->pass && c_ctx->pass_sz) { // if pass is not null
 +    if (c_ctx->pass_sz == ((c_ctx->key_sz*2)+3) && sqlite3StrNICmp(c_ctx->pass ,"x'", 2) == 0) { 
@@ -955,13 +987,42 @@
 +      cipher_hex2bin(z, n, c_ctx->key);
 +    } else { 
 +      CODEC_TRACE(("codec_key_derive: deriving key using PBKDF2\n")); 
-+      PKCS5_PBKDF2_HMAC_SHA1(c_ctx->pass, c_ctx->pass_sz, ctx->kdf_salt, ctx->kdf_salt_sz, c_ctx->kdf_iter, c_ctx->key_sz, c_ctx->key);
++      PKCS5_PBKDF2_HMAC_SHA1( c_ctx->pass, c_ctx->pass_sz, 
++                              ctx->kdf_salt, ctx->kdf_salt_sz, 
++                              c_ctx->kdf_iter, c_ctx->key_sz, c_ctx->key);
++                              
 +    }
++
++    /* if this context is setup to use hmac checks, generate a seperate and different 
++       key for HMAC. In this case, we use the output of the previous KDF as the input to 
++       this KDF run. This ensures a distinct but predictable HMAC key. */
++    if(c_ctx->use_hmac) {
++      CODEC_TRACE(("codec_key_derive: deriving hmac key using PBKDF2\n")); 
++      PKCS5_PBKDF2_HMAC_SHA1( c_ctx->key, c_ctx->key_sz, 
++                              ctx->kdf_salt, ctx->kdf_salt_sz, 
++                              c_ctx->kdf_iter, c_ctx->key_sz, c_ctx->hmac_key); 
++    }
++
 +    return SQLITE_OK;
 +  };
 +  return SQLITE_ERROR;
 +}
 +
++
++static int codec_hmac(cipher_ctx *ctx, Pgno pgno, unsigned char *in, int in_sz, unsigned char *out) {
++  HMAC_CTX hctx;
++  HMAC_CTX_init(&hctx);
++  HMAC_Init_ex(&hctx, ctx->hmac_key, ctx->key_sz, EVP_sha1(), NULL); 
++
++  /* include the encrypted page data,  initialization vector, and page number in HMAC. This will 
++     prevent both tampering with the ciphertext, manipulation of the IV, or resequencing otherwise
++     valid pages out of order in a database */ 
++  HMAC_Update(&hctx, in, in_sz); 
++  HMAC_Update(&hctx, (const unsigned char*) &pgno, sizeof(Pgno));
++  HMAC_Final(&hctx, out, NULL);
++  HMAC_CTX_cleanup(&hctx);
++}
++
 +/*
 + * ctx - codec context
 + * pgno - page number in database
@@ -970,10 +1031,21 @@
 + * in - pointer to input bytes
 + * out - pouter to output bytes
 + */
-+static int codec_cipher(cipher_ctx *ctx, Pgno pgno, int mode, int size, unsigned char *in, unsigned char *out) {
++static int codec_cipher(cipher_ctx *ctx, Pgno pgno, int mode, int page_sz, unsigned char *in, unsigned char *out) {
 +  EVP_CIPHER_CTX ectx;
-+  unsigned char *iv;
-+  int tmp_csz, csz;
++  unsigned char *iv_in, *iv_out, *hmac_in, *hmac_out, *out_start;
++  int tmp_csz, csz, size;
++
++  /* calculate some required positions into various buffers */
++  size = page_sz - ctx->reserve_sz; /* adjust size to useable size and memset reserve at end of page */
++  iv_out = out + size;
++  iv_in = in + size;
++
++  /* hmac will be written immediately after the initialization vector. the remainder of the page reserve will contain
++     random bytes. note, these pointers are only valid when use_hmac is true */
++  hmac_in = in + size + ctx->iv_sz; 
++  hmac_out = out + size + ctx->iv_sz;
++  out_start = out; /* note the original position of the output buffer pointer, as out will be rewritten during encryption */
 +
 +  CODEC_TRACE(("codec_cipher:entered pgno=%d, mode=%d, size=%d\n", pgno, mode, size));
 +
@@ -984,18 +1056,29 @@
 +    return SQLITE_OK;
 +  } 
 +
-+  // FIXME - only run if using an IV
-+  size = size - ctx->iv_sz; /* adjust size to useable size and memset reserve at end of page */
-+  iv = out + size;
 +  if(mode == CIPHER_ENCRYPT) {
-+    RAND_pseudo_bytes(iv, ctx->iv_sz);
-+  } else {
-+    memcpy(iv, in+size, ctx->iv_sz);
++    RAND_pseudo_bytes(iv_out, ctx->reserve_sz); /* start at front of the reserve block, write random data to the end */
++  } else { /* CIPHER_DECRYPT */
++    memcpy(iv_out, iv_in, ctx->iv_sz); /* copy the iv from the input to output buffer */
 +  } 
-+  
++
++  if(ctx->use_hmac && (mode == CIPHER_DECRYPT)) {
++    codec_hmac(ctx, pgno, in, size + ctx->iv_sz, hmac_out); 
++
++    CODEC_TRACE(("codec_cipher: comparing hmac on in=%d out=%d hmac_sz=%d\n", hmac_in, hmac_out, ctx->hmac_sz));
++    if(fixed_time_memcmp(hmac_in, hmac_out, ctx->hmac_sz) != 0) {
++      /* the hmac check failed, which means the data was tampered with or
++         corrupted in some way. we will return an error, and zero out the page data
++         to force an error */
++      memset(out, 0, page_sz); 
++      CODEC_TRACE(("codec_cipher: hmac check failed for pgno=%d\n", pgno));
++      return SQLITE_ERROR;
++    }
++  } 
++
 +  EVP_CipherInit(&ectx, ctx->evp_cipher, NULL, NULL, mode);
 +  EVP_CIPHER_CTX_set_padding(&ectx, 0);
-+  EVP_CipherInit(&ectx, NULL, ctx->key, iv, mode);
++  EVP_CipherInit(&ectx, NULL, ctx->key, iv_out, mode);
 +  EVP_CipherUpdate(&ectx, out, &tmp_csz, in, size);
 +  csz = tmp_csz;  
 +  out += tmp_csz;
@@ -1004,6 +1087,10 @@
 +  EVP_CIPHER_CTX_cleanup(&ectx);
 +  assert(size == csz);
 +
++  if(ctx->use_hmac && (mode == CIPHER_ENCRYPT)) {
++    codec_hmac(ctx, pgno, out_start, size + ctx->iv_sz, hmac_out); 
++  }
++
 +  return SQLITE_OK;
 +}
 +
@@ -1026,6 +1113,68 @@
 +  return SQLITE_ERROR;
 +}
 +
++int codec_set_use_hmac(sqlite3* db, int nDb, int use) {
++  int reserve;
++  struct Db *pDb = &db->aDb[nDb];
++
++  CODEC_TRACE(("codec_set_use_hmac: entered db=%d nDb=%d use=%d\n", db, nDb, use));
++
++  if(pDb->pBt) {
++    codec_ctx *ctx;
++    sqlite3pager_get_codec(pDb->pBt->pBt->pPager, (void **) &ctx);
++
++    reserve = EVP_MAX_IV_LENGTH; /* base reserve size will be IV only */
++    if(use) reserve += ctx->read_ctx->hmac_sz; /* if reserve will include hmac, update that size */
++
++    /* calculate the amount of reserve needed in even increments of the cipher block size */
++
++    reserve = ((reserve % ctx->read_ctx->block_sz) == 0) ? reserve :
++                 ((reserve / ctx->read_ctx->block_sz) + 1) * ctx->read_ctx->block_sz;  
++
++    CODEC_TRACE(("codec_set_use_hmac: use=%d block_sz=%d md_size=%d reserve=%d\n", 
++                  use, ctx->read_ctx->block_sz, ctx->read_ctx->hmac_sz, reserve)); 
++
++    ctx->write_ctx->use_hmac = ctx->read_ctx->use_hmac = use;
++    ctx->write_ctx->reserve_sz = ctx->read_ctx->reserve_sz = reserve;
++
++    /* since the use of hmac has changed, the page size has also changed */
++    return codec_set_page_size(db, nDb, ctx->page_sz);
++  }
++  return SQLITE_ERROR;
++}
++
++int codec_set_page_size(sqlite3* db, int nDb, int size) {
++  int rc;
++  struct Db *pDb = &db->aDb[nDb];
++  CODEC_TRACE(("codec_set_page_size: entered db=%d nDb=%d size=%d\n", db, nDb, size));
++
++  if(pDb->pBt) {
++    codec_ctx *ctx;
++    sqlite3pager_get_codec(pDb->pBt->pBt->pPager, (void **) &ctx);
++    
++    /* attempt to free the existing page bugger */
++    codec_free(ctx->buffer,ctx->page_sz);
++    ctx->page_sz = size;
++
++    /* pre-allocate a page buffer of PageSize bytes. This will
++       be used as a persistent buffer for encryption and decryption 
++       operations to avoid overhead of multiple memory allocations*/
++    ctx->buffer = sqlite3Malloc(size);
++    if(ctx->buffer == NULL) return SQLITE_NOMEM;
++
++    /* Note: before forcing the page size we need to force pageSizeFixed to 0, else  
++             sqliteBtreeSetPageSize will block the change  */
++    sqlite3_mutex_enter(db->mutex);
++    db->nextPagesize = size; 
++    pDb->pBt->pBt->pageSizeFixed = 0; 
++    CODEC_TRACE(("codec_set_page_size: sqlite3BtreeSetPageSize() size=%d reserve=%d\n", size, ctx->read_ctx->reserve_sz));
++    rc = sqlite3BtreeSetPageSize(pDb->pBt, size, ctx->read_ctx->reserve_sz, 0);
++    sqlite3_mutex_leave(db->mutex);
++    return rc;
++  }
++  return SQLITE_ERROR;
++}
++
 +/**
 +  * 
 +  * when for_ctx == 0 then it will change for read
@@ -1045,6 +1194,9 @@
 +    c_ctx->evp_cipher = (EVP_CIPHER *) EVP_get_cipherbyname(cipher_name);
 +    c_ctx->key_sz = EVP_CIPHER_key_length(c_ctx->evp_cipher);
 +    c_ctx->iv_sz = EVP_CIPHER_iv_length(c_ctx->evp_cipher);
++    c_ctx->block_sz = EVP_CIPHER_block_size(c_ctx->evp_cipher);
++    c_ctx->hmac_sz = EVP_MD_size(EVP_sha1());
++
 +    c_ctx->derive_key = 1;
 +
 +    if(for_ctx == 2) cipher_ctx_copy( for_ctx ? ctx->read_ctx : ctx->write_ctx, c_ctx); 
@@ -1080,11 +1232,10 @@
 + */
 +void* sqlite3Codec(void *iCtx, void *data, Pgno pgno, int mode) {
 +  codec_ctx *ctx = (codec_ctx *) iCtx;
-+  int pg_sz = SQLITE_DEFAULT_PAGE_SIZE;
-+  int offset = 0;
++  int offset = 0, rc = 0;
 +  unsigned char *pData = (unsigned char *) data;
 + 
-+  CODEC_TRACE(("sqlite3Codec: entered pgno=%d, mode=%d, ctx->mode_rekey=%d, pg_sz=%d\n", pgno, mode, ctx->mode_rekey, pg_sz));
++  CODEC_TRACE(("sqlite3Codec: entered pgno=%d, mode=%d, ctx->mode_rekey=%d, page_sz=%d\n", pgno, mode, ctx->mode_rekey, ctx->page_sz));
 +
 +  /* derive key on first use if necessary */
 +  if(ctx->read_ctx->derive_key) {
@@ -1110,18 +1261,21 @@
 +    case 2:
 +    case 3:
 +      if(pgno == 1) memcpy(ctx->buffer, SQLITE_FILE_HEADER, FILE_HEADER_SZ); /* copy file header to the first 16 bytes of the page */ 
-+      codec_cipher(ctx->read_ctx, pgno, CIPHER_DECRYPT, pg_sz - offset, pData + offset, ctx->buffer + offset);
-+      memcpy(pData, ctx->buffer, pg_sz); /* copy buffer data back to pData and return */
++      rc = codec_cipher(ctx->read_ctx, pgno, CIPHER_DECRYPT, ctx->page_sz - offset, pData + offset, ctx->buffer + offset);
++      if(rc != SQLITE_OK) ctx->pBt->db->errCode = rc;
++      memcpy(pData, ctx->buffer, ctx->page_sz); /* copy buffer data back to pData and return */
 +      return pData;
 +      break;
 +    case 6: /* encrypt */
 +      if(pgno == 1) memcpy(ctx->buffer, ctx->kdf_salt, FILE_HEADER_SZ); /* copy salt to output buffer */ 
-+      codec_cipher(ctx->write_ctx, pgno, CIPHER_ENCRYPT, pg_sz - offset, pData + offset, ctx->buffer + offset);
++      rc = codec_cipher(ctx->write_ctx, pgno, CIPHER_ENCRYPT, ctx->page_sz - offset, pData + offset, ctx->buffer + offset);
++      if(rc != SQLITE_OK) ctx->pBt->db->errCode = rc;
 +      return ctx->buffer; /* return persistent buffer data, pData remains intact */
 +      break;
 +    case 7:
 +      if(pgno == 1) memcpy(ctx->buffer, ctx->kdf_salt, FILE_HEADER_SZ); /* copy salt to output buffer */ 
-+      codec_cipher(ctx->read_ctx, pgno, CIPHER_ENCRYPT, pg_sz - offset, pData + offset, ctx->buffer + offset);
++      rc = codec_cipher(ctx->read_ctx, pgno, CIPHER_ENCRYPT, ctx->page_sz - offset, pData + offset, ctx->buffer + offset);
++      if(rc != SQLITE_OK) ctx->pBt->db->errCode = rc;
 +      return ctx->buffer; /* return persistent buffer data, pData remains intact */
 +      break;
 +    default:
@@ -1146,18 +1300,18 @@
 +    ctx = sqlite3Malloc(sizeof(codec_ctx));
 +    if(ctx == NULL) return SQLITE_NOMEM;
 +    memset(ctx, 0, sizeof(codec_ctx)); /* initialize all pointers and values to 0 */
-+
 +    ctx->pBt = pDb->pBt; /* assign pointer to database btree structure */
 +
++    /*
++       Always overwrite page size and set to the default because the first page of the database
++       in encrypted and thus sqlite can't effectively determine the pagesize. this causes an issue in 
++       cases where bytes 16 & 17 of the page header are a power of 2 as reported by John Lehman
++    */
++    ctx->page_sz = SQLITE_DEFAULT_PAGE_SIZE;
++
 +    if((rc = cipher_ctx_init(&ctx->read_ctx)) != SQLITE_OK) return rc; 
 +    if((rc = cipher_ctx_init(&ctx->write_ctx)) != SQLITE_OK) return rc; 
 +    
-+    /* pre-allocate a page buffer of PageSize bytes. This will
-+       be used as a persistent buffer for encryption and decryption 
-+       operations to avoid overhead of multiple memory allocations*/
-+    ctx->buffer = sqlite3Malloc(SQLITE_DEFAULT_PAGE_SIZE);
-+    if(ctx->buffer == NULL) return SQLITE_NOMEM;
-+     
 +    /* allocate space for salt data. Then read the first 16 bytes 
 +       directly off the database file. This is the salt for the
 +       key derivation function. If we get a short read allocate
@@ -1178,19 +1332,15 @@
 +    codec_set_cipher_name(db, nDb, CIPHER, 0);
 +    codec_set_kdf_iter(db, nDb, PBKDF2_ITER, 0);
 +    codec_set_pass_key(db, nDb, zKey, nKey, 0);
++
++
++    /* Use HMAC signatures by default. Note that codec_set_use_hmac will implicity call
++       codec_set_page_size to set the default */
++    if((rc = codec_set_use_hmac(db, nDb, DEFAULT_USE_HMAC)) != SQLITE_OK) return rc;
++
 +    cipher_ctx_copy(ctx->write_ctx, ctx->read_ctx);
 +
 +    sqlite3_mutex_enter(db->mutex);
-+    
-+    /* Always overwrite page size and set to the default because the first page of the database
-+       in encrypted and thus sqlite can't effectively determine the pagesize. this causes an issue in 
-+       cases where bytes 16 & 17 of the page header are a power of 2 as reported by John Lehman
-+
-+       Note: before forcing the page size we need to force pageSizeFixed to 0, else  
-+             sqliteBtreeSetPageSize will block the change 
-+    */
-+    pDb->pBt->pBt->pageSizeFixed = 0; 
-+    sqlite3BtreeSetPageSize(ctx->pBt, SQLITE_DEFAULT_PAGE_SIZE, EVP_MAX_IV_LENGTH, 0);
 +
 +    /* if fd is null, then this is an in-memory database and
 +       we dont' want to overwrite the AutoVacuum settings
@@ -1266,15 +1416,6 @@
 +
 +      sqlite3_mutex_enter(db->mutex);
 +
-+      if(ctx->read_ctx->iv_sz != ctx->write_ctx->iv_sz) {
-+        char *error;
-+        CODEC_TRACE(("sqlite3_rekey: updating page size for iv_sz change from %d to %d\n", ctx->read_ctx->iv_sz, ctx->write_ctx->iv_sz));
-+        db->nextPagesize = SQLITE_DEFAULT_PAGE_SIZE;
-+        pDb->pBt->pBt->pageSizeFixed = 0; /* required for sqlite3BtreeSetPageSize to modify pagesize setting */
-+        sqlite3BtreeSetPageSize(pDb->pBt, db->nextPagesize, EVP_MAX_IV_LENGTH, 0);
-+        sqlite3RunVacuum(&error, db);
-+      }
-+
 +      codec_set_pass_key(db, 0, pKey, nKey, 1);
 +      ctx->mode_rekey = 1; 
 +    
@@ -1302,7 +1443,6 @@
 +      /* if commit was successful commit and copy the rekey data to current key, else rollback to release locks */
 +      if(rc == SQLITE_OK) { 
 +        CODEC_TRACE(("sqlite3_rekey: committing\n"));
-+        db->nextPagesize = SQLITE_DEFAULT_PAGE_SIZE;
 +        rc = sqlite3BtreeCommit(pDb->pBt); 
 +        cipher_ctx_copy(ctx->read_ctx, ctx->write_ctx);
 +      } else {
@@ -1344,7 +1484,7 @@
  /************** Begin file global.c ******************************************/
  /*
  ** 2008 June 13
-@@ -40807,11 +42144,40 @@
+@@ -41688,11 +43165,40 @@
    CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData);
    return aData;
  }
@@ -1388,20 +1528,10 @@
  
  /************** End of pager.c ***********************************************/
  /************** Begin file wal.c *********************************************/
-@@ -43340,854 +44706,208 @@
- #if defined(SQLITE_HAS_CODEC)
-       if( (pData = sqlite3PagerCodec(pLast))==0 ) return SQLITE_NOMEM;
- #else
--      pData = pLast->pData;
--#endif
--      walEncodeFrame(pWal, pLast->pgno, nTruncate, pData, aFrame);
--      /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
--      rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOffset);
--      if( rc!=SQLITE_OK ){
--        return rc;
--      }
--      iOffset += WAL_FRAME_HDRSIZE;
--      rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOffset); 
+@@ -44298,855 +45804,208 @@
+       }
+       iOffset += WAL_FRAME_HDRSIZE;
+       rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOffset); 
 -      if( rc!=SQLITE_OK ){
 -        return rc;
 -      }
@@ -1533,13 +1663,14 @@
 -** on the main database file before invoking this operation.
 -**
 -** If op is negative, then do a dry-run of the op==1 case but do
--** not actually change anything.  The pager uses this to see if it
+-** not actually change anything. The pager uses this to see if it
 -** should acquire the database exclusive lock prior to invoking
 -** the op==1 case.
 -*/
 -SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op){
 -  int rc;
 -  assert( pWal->writeLock==0 );
+-  assert( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE || op==-1 );
 -
 -  /* pWal->readLock is usually set, but might be -1 if there was a 
 -  ** prior error while attempting to acquire are read-lock. This cannot 
@@ -1573,6 +1704,15 @@
 -  return rc;
 -}
 -
+-/* 
+-** Return true if the argument is non-NULL and the WAL module is using
+-** heap-memory for the wal-index. Otherwise, if the argument is NULL or the
+-** WAL module is using shared-memory, return false. 
+-*/
+-SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal){
+-  return (pWal && pWal->exclusiveMode==WAL_HEAPMEMORY_MODE );
+-}
+-
 -#endif /* #ifndef SQLITE_OMIT_WAL */
 -
 -/************** End of wal.c *************************************************/
@@ -1889,16 +2029,6 @@
 -  DbPage *pDbPage;     /* Pager page handle */
 -  Pgno pgno;           /* Page number for this page */
 -};
-+      pData = pLast->pData;
-+#endif
-+      walEncodeFrame(pWal, pLast->pgno, nTruncate, pData, aFrame);
-+      /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
-+      rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOffset);
-+      if( rc!=SQLITE_OK ){
-+        return rc;
-+      }
-+      iOffset += WAL_FRAME_HDRSIZE;
-+      rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOffset); 
 +      if( rc!=SQLITE_OK ){
 +        return rc;
 +      }
@@ -2071,16 +2201,17 @@
 -  u8 pageSizeFixed;     /* True if the page size can no longer be changed */
 -  u8 secureDelete;      /* True if secure_delete is enabled */
 -  u8 initiallyEmpty;    /* Database is empty at start of transaction */
+-  u8 openFlags;         /* Flags to sqlite3BtreeOpen() */
 -#ifndef SQLITE_OMIT_AUTOVACUUM
 -  u8 autoVacuum;        /* True if auto-vacuum is enabled */
 -  u8 incrVacuum;        /* True if incr-vacuum is enabled */
 -#endif
+-  u8 inTransaction;     /* Transaction state */
+-  u8 doNotUseWAL;       /* If true, do not open write-ahead-log file */
 -  u16 maxLocal;         /* Maximum local payload in non-LEAFDATA tables */
 -  u16 minLocal;         /* Minimum local payload in non-LEAFDATA tables */
 -  u16 maxLeaf;          /* Maximum local payload in a LEAFDATA table */
 -  u16 minLeaf;          /* Minimum local payload in a LEAFDATA table */
--  u8 inTransaction;     /* Transaction state */
--  u8 doNotUseWAL;       /* If true, do not open write-ahead-log file */
 -  u32 pageSize;         /* Total number of bytes on a page */
 -  u32 usableSize;       /* Number of usable bytes on each page */
 -  int nTransaction;     /* Number of open transactions (read + write) */
@@ -2108,8 +2239,8 @@
 -*/
 -typedef struct CellInfo CellInfo;
 -struct CellInfo {
--  u8 *pCell;     /* Pointer to the start of cell content */
 -  i64 nKey;      /* The key for INTKEY tables, or number of bytes in key */
+-  u8 *pCell;     /* Pointer to the start of cell content */
 -  u32 nData;     /* Number of bytes of data */
 -  u32 nPayload;  /* Total amount of payload */
 -  u16 nHeader;   /* Size of the cell content header in bytes */
@@ -2185,20 +2316,20 @@
 -  Pgno pgnoRoot;            /* The root page of this tree */
 -  sqlite3_int64 cachedRowid; /* Next rowid cache.  0 means not valid */
 -  CellInfo info;            /* A parse of the cell we are pointing at */
+-  i64 nKey;        /* Size of pKey, or last integer key */
+-  void *pKey;      /* Saved key that was cursor's last known position */
+-  int skipNext;    /* Prev() is noop if negative. Next() is noop if positive */
 -  u8 wrFlag;                /* True if writable */
 -  u8 atLast;                /* Cursor pointing to the last entry */
 -  u8 validNKey;             /* True if info.nKey is valid */
 -  u8 eState;                /* One of the CURSOR_XXX constants (see below) */
--  void *pKey;      /* Saved key that was cursor's last known position */
--  i64 nKey;        /* Size of pKey, or last integer key */
--  int skipNext;    /* Prev() is noop if negative. Next() is noop if positive */
 -#ifndef SQLITE_OMIT_INCRBLOB
--  u8 isIncrblobHandle;      /* True if this cursor is an incr. io handle */
 -  Pgno *aOverflow;          /* Cache of overflow page locations */
+-  u8 isIncrblobHandle;      /* True if this cursor is an incr. io handle */
 -#endif
 -  i16 iPage;                            /* Index of current page in apPage */
--  MemPage *apPage[BTCURSOR_MAX_DEPTH];  /* Pages from root to current page */
 -  u16 aiIdx[BTCURSOR_MAX_DEPTH];        /* Current index in apPage[i] */
+-  MemPage *apPage[BTCURSOR_MAX_DEPTH];  /* Pages from root to current page */
 -};
 +SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal){
 +  u32 ret = 0;
@@ -2249,7 +2380,7 @@
 -**   Do nothing else with this cursor.  Any attempt to use the cursor
 -**   should return the error code stored in BtCursor.skip
 +** If op is negative, then do a dry-run of the op==1 case but do
-+** not actually change anything.  The pager uses this to see if it
++** not actually change anything. The pager uses this to see if it
 +** should acquire the database exclusive lock prior to invoking
 +** the op==1 case.
  */
@@ -2260,11 +2391,8 @@
 +SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op){
 +  int rc;
 +  assert( pWal->writeLock==0 );
- 
--/* 
--** The database page the PENDING_BYTE occupies. This page is never used.
--*/
--# define PENDING_BYTE_PAGE(pBt) PAGER_MJ_PGNO(pBt)
++  assert( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE || op==-1 );
++
 +  /* pWal->readLock is usually set, but might be -1 if there was a 
 +  ** prior error while attempting to acquire are read-lock. This cannot 
 +  ** happen if the connection is actually in exclusive mode (as no xShmLock
@@ -2273,25 +2401,7 @@
 +  */
 +  assert( pWal->readLock>=0 || pWal->lockError );
 +  assert( pWal->readLock>=0 || (op<=0 && pWal->exclusiveMode==0) );
- 
--/*
--** These macros define the location of the pointer-map entry for a 
--** database page. The first argument to each is the number of usable
--** bytes on each page of the database (often 1024). The second is the
--** page number to look up in the pointer map.
--**
--** PTRMAP_PAGENO returns the database page number of the pointer-map
--** page that stores the required pointer. PTRMAP_PTROFFSET returns
--** the offset of the requested map entry.
--**
--** If the pgno argument passed to PTRMAP_PAGENO is a pointer-map page,
--** then pgno is returned. So (pgno==PTRMAP_PAGENO(pgsz, pgno)) can be
--** used to test if pgno is a pointer-map page. PTRMAP_ISPAGE implements
--** this test.
--*/
--#define PTRMAP_PAGENO(pBt, pgno) ptrmapPageno(pBt, pgno)
--#define PTRMAP_PTROFFSET(pgptrmap, pgno) (5*(pgno-pgptrmap-1))
--#define PTRMAP_ISPAGE(pBt, pgno) (PTRMAP_PAGENO((pBt),(pgno))==(pgno))
++
 +  if( op==0 ){
 +    if( pWal->exclusiveMode ){
 +      pWal->exclusiveMode = 0;
@@ -2314,7 +2424,36 @@
 +  }
 +  return rc;
 +}
-+
+ 
+ /* 
+-** The database page the PENDING_BYTE occupies. This page is never used.
++** Return true if the argument is non-NULL and the WAL module is using
++** heap-memory for the wal-index. Otherwise, if the argument is NULL or the
++** WAL module is using shared-memory, return false. 
+ */
+-# define PENDING_BYTE_PAGE(pBt) PAGER_MJ_PGNO(pBt)
++SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal){
++  return (pWal && pWal->exclusiveMode==WAL_HEAPMEMORY_MODE );
++}
+ 
+-/*
+-** These macros define the location of the pointer-map entry for a 
+-** database page. The first argument to each is the number of usable
+-** bytes on each page of the database (often 1024). The second is the
+-** page number to look up in the pointer map.
+-**
+-** PTRMAP_PAGENO returns the database page number of the pointer-map
+-** page that stores the required pointer. PTRMAP_PTROFFSET returns
+-** the offset of the requested map entry.
+-**
+-** If the pgno argument passed to PTRMAP_PAGENO is a pointer-map page,
+-** then pgno is returned. So (pgno==PTRMAP_PAGENO(pgsz, pgno)) can be
+-** used to test if pgno is a pointer-map page. PTRMAP_ISPAGE implements
+-** this test.
+-*/
+-#define PTRMAP_PAGENO(pBt, pgno) ptrmapPageno(pBt, pgno)
+-#define PTRMAP_PTROFFSET(pgptrmap, pgno) (5*(pgno-pgptrmap-1))
+-#define PTRMAP_ISPAGE(pBt, pgno) (PTRMAP_PAGENO((pBt),(pgno))==(pgno))
 +#endif /* #ifndef SQLITE_OMIT_WAL */
  
 +/************** End of wal.c *************************************************/
@@ -2418,7 +2557,7 @@
  #ifndef SQLITE_OMIT_SHARED_CACHE
  #if SQLITE_THREADSAFE
  
-@@ -85120,60 +85840,6 @@
+@@ -86518,60 +87377,6 @@
  
  #ifndef SQLITE_OMIT_SCHEMA_PRAGMAS
    /*
@@ -2479,27 +2618,39 @@
    **   PRAGMA table_info(<table>)
    **
    ** Return a single row for each column of the named table. The columns of
-@@ -85795,6 +86461,24 @@
+@@ -87192,6 +87997,36 @@
        sqlite3_rekey(db, zKey, i/2);
      }
    }else
 +/** BEGIN CRYPTO **/
 +  if( sqlite3StrICmp(zLeft, "cipher")==0 && zRight ){
 +    extern int codec_set_cipher_name(sqlite3*, int, const char *, int);
-+    codec_set_cipher_name(db,0,zRight,2); // change cipher for both
++    codec_set_cipher_name(db, iDb, zRight, 2); // change cipher for both
 +  }else
 +  if( sqlite3StrICmp(zLeft, "rekey_cipher")==0 && zRight ){
 +    extern int codec_set_cipher_name(sqlite3*, int, const char *, int); 
-+    codec_set_cipher_name(db,0,zRight,1); // change write cipher only
++    codec_set_cipher_name(db, iDb, zRight, 1); // change write cipher only
 +  }else
 +  if( sqlite3StrICmp(zLeft, "kdf_iter")==0 && zRight ){
 +    extern int codec_set_kdf_iter(sqlite3*, int, int, int);
-+    codec_set_kdf_iter(db,0,atoi(zRight),2); // change cipher for both
++    codec_set_kdf_iter(db, iDb, atoi(zRight), 2); // change of RW PBKDF2 iteration
 +  }else
 +  if( sqlite3StrICmp(zLeft, "rekey_kdf_iter")==0 && zRight ){
 +    extern int codec_set_kdf_iter(sqlite3*, int, int, int); 
-+    codec_set_kdf_iter(db,0,atoi(zRight),1); // change write cipher only
++    codec_set_kdf_iter(db, iDb, atoi(zRight), 1); // change # if W iterations
 +  }else
++  if( sqlite3StrICmp(zLeft,"cipher_page_size")==0 ){
++    extern int codec_set_page_size(sqlite3*, int, int); 
++    codec_set_page_size(db, iDb, atoi(zRight)); // change page size
++  }
++  if( sqlite3StrICmp(zLeft,"cipher_use_hmac")==0 ){
++    extern int codec_set_use_hmac(sqlite3*, int, int);
++    if(getBoolean(zRight)) {
++      codec_set_use_hmac(db, iDb, 1);
++    } else {
++      codec_set_use_hmac(db, iDb, 0);
++    }
++  }
 +/** END CRYPTO **/
  #endif
  #if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
diff --git a/providers/sqlite/Makefile.am b/providers/sqlite/Makefile.am
index 83d56fe..3d8b153 100644
--- a/providers/sqlite/Makefile.am
+++ b/providers/sqlite/Makefile.am
@@ -17,10 +17,10 @@ libgda_sqlite_la_SOURCES = \
 
 libgda_sqlite_la_LDFLAGS = -export-dynamic -module -avoid-version $(NO_UNDEFINED) $(LIBTOOL_PROV_EXPORT_OPTIONS)
 libgda_sqlite_la_LIBADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS)
 
-xmldir   = $(datadir)/libgda-4.0
+xmldir   = $(datadir)/libgda-5.0
 xml_in_files = \
 	sqlite_specs_dsn.xml.in \
 	sqlite_specs_create_db.xml.in \
@@ -39,7 +39,7 @@ xml_in_files = \
 xml_DATA = $(xml_in_files:.xml.in=.xml)
 
 pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = libgda-sqlite-4.0.pc
+pkgconfig_DATA = libgda-sqlite-5.0.pc
 
-EXTRA_DIST = $(xml_in_files) libgda-sqlite-4.0.pc.in
+EXTRA_DIST = $(xml_in_files) libgda-sqlite-5.0.pc.in
 DISTCLEANFILES = $(xml_DATA)
diff --git a/providers/sqlite/libgda-sqlite-4.0.pc.in b/providers/sqlite/libgda-sqlite-5.0.pc.in
similarity index 100%
rename from providers/sqlite/libgda-sqlite-4.0.pc.in
rename to providers/sqlite/libgda-sqlite-5.0.pc.in
diff --git a/providers/web/Makefile.am b/providers/web/Makefile.am
index 8ff50b9..cd37d6f 100644
--- a/providers/web/Makefile.am
+++ b/providers/web/Makefile.am
@@ -34,10 +34,10 @@ libgda_web_la_SOURCES = \
 libgda_web_la_LDFLAGS = -export-dynamic -module -avoid-version $(NO_UNDEFINED) $(LIBTOOL_PROV_EXPORT_OPTIONS)
 libgda_web_la_LIBADD = \
 	$(top_builddir)/providers/reuseable/libreuseable.la \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS) $(LIBSOUP_LIBS)
 
-xmldir   = $(datadir)/libgda-4.0
+xmldir   = $(datadir)/libgda-5.0
 xml_in_files = \
 	web_specs_dsn.xml.in \
 	web_specs_auth.xml.in
@@ -47,9 +47,9 @@ xml_in_files = \
 xml_DATA = $(xml_in_files:.xml.in=.xml) 
 
 pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = libgda-web-4.0.pc
+pkgconfig_DATA = libgda-web-5.0.pc
 
-phpdir = $(datadir)/libgda-4.0/php
+phpdir = $(datadir)/libgda-5.0/php
 php_DATA = \
 	php/README \
 	php/gda-clean.php \
@@ -63,7 +63,7 @@ php_DATA = \
 	php/gda-worker.php
 
 
-EXTRA_DIST = $(xml_in_files) libgda-web-4.0.pc.in \
+EXTRA_DIST = $(xml_in_files) libgda-web-5.0.pc.in \
 	$(php_DATA)
 
 DISTCLEANFILES = $(xml_DATA)
diff --git a/providers/web/gda-web-provider.c b/providers/web/gda-web-provider.c
index 8ce394d..5313b01 100644
--- a/providers/web/gda-web-provider.c
+++ b/providers/web/gda-web-provider.c
@@ -1175,8 +1175,6 @@ gtype_to_webtype (GType type)
                 return "text";
         if (type == G_TYPE_INT)
                 return "integer";
-        if (type == GDA_TYPE_LIST)
-                return "text";
         if (type == GDA_TYPE_NUMERIC)
                 return "decimal";
         if (type == G_TYPE_FLOAT)
diff --git a/providers/web/libgda-web-4.0.pc.in b/providers/web/libgda-web-5.0.pc.in
similarity index 100%
rename from providers/web/libgda-web-4.0.pc.in
rename to providers/web/libgda-web-5.0.pc.in
diff --git a/providers/web/php/gda-config.php.HOME b/providers/web/php/gda-config.php.HOME
new file mode 100644
index 0000000..8cab5d3
--- /dev/null
+++ b/providers/web/php/gda-config.php.HOME
@@ -0,0 +1,32 @@
+<?php
+
+/*
+ * initial shared secret: will have to be passed as the SECRET argument when opening
+ * the connection from Libgda
+ */
+$init_shared = "MySecret";
+
+/*
+ * declared connections: for each connection which can be opened by Libgda, the
+ * the connection's password and the real connection's DSN need to be added respectively
+ * to the $cnc and $dsn arrays, using the connection name as a key. The connection name
+ * and password have no significance outside of the Libgda's context and be arbitrary.
+ * However the real connection's DSN need to be valid for the PEAR's MDB2 module, as
+ * per http://pear.php.net/manual/en/package.database.mdb2.intro-dsn.php
+ *
+ */
+
+/* sample connection cnc1 */
+$cnc["cnc1"] = "MyPass1";
+//$dsn["cnc1"] = "pgsql://vivien unix(/var/run/postgresql)/sales";
+$dsn["cnc1"] = "pgsql://unix(/tmp)/sales";
+
+/* sample connection cnc2 */
+$cnc["cnc2"] = "MyPass2";
+$dsn["cnc2"] = "pgsql://vivien:Escobar 127 0 0 1/sales";
+
+/* sample connection cnc3 */
+$cnc["cnc3"] = "MyPass3";
+$dsn["cnc3"] = "mysql://vmalerba:Escobar unix(/tmp/mysql.sock)/sales";
+
+?>
diff --git a/samples/SimpleExample/example.c b/samples/SimpleExample/example.c
index ded1406..f6bf6fa 100644
--- a/samples/SimpleExample/example.c
+++ b/samples/SimpleExample/example.c
@@ -117,7 +117,7 @@ insert_data (GdaConnection *cnc)
 			g_value_set_float (v3, data[i].price);
 		}
 		
-		res = gda_insert_row_into_table (cnc, "products", &error, "ref", v1, "name", v2, "price", v3, NULL);
+		res = gda_connection_insert_row_into_table (cnc, "products", &error, "ref", v1, "name", v2, "price", v3, NULL);
 
 		if (!res) {
 			g_error ("Could not INSERT data into the 'products' table: %s\n",
@@ -146,7 +146,7 @@ update_data (GdaConnection *cnc)
 	v3 = gda_value_new (G_TYPE_FLOAT);
 	g_value_set_float (v3, 1.99);
 		
-	res = gda_update_row_in_table (cnc, "products", "ref", v1, &error, "name", v2, "price", v3, NULL);
+	res = gda_connection_update_row_in_table (cnc, "products", "ref", v1, &error, "name", v2, "price", v3, NULL);
 
 	if (!res) {
 		g_error ("Could not UPDATE data in the 'products' table: %s\n",
@@ -169,7 +169,7 @@ delete_data (GdaConnection *cnc)
 
 	/* delete data where name is 'table' */
 	v = gda_value_new_from_string ("table", G_TYPE_STRING);
-	res = gda_delete_row_from_table (cnc, "products", "name", v, &error);
+	res = gda_connection_delete_row_from_table (cnc, "products", "name", v, &error);
 	if (!res) {
 		g_error ("Could not DELETE data from the 'products' table: %s\n",
 			 error && error->message ? error->message : "No detail");
@@ -177,7 +177,7 @@ delete_data (GdaConnection *cnc)
 	gda_value_free (v);
 
 	/* delete data where price is NULL */
-	res = gda_delete_row_from_table (cnc, "products", "price", NULL, &error);
+	res = gda_connection_delete_row_from_table (cnc, "products", "price", NULL, &error);
 	if (!res) {
 		g_error ("Could not DELETE data from the 'products' table: %s\n",
 			 error && error->message ? error->message : "No detail");
diff --git a/testing/.gitignore b/testing/.gitignore
index f2bb3ea..21f2418 100644
--- a/testing/.gitignore
+++ b/testing/.gitignore
@@ -1,4 +1,4 @@
-gda-test-connection-4.*
+gda-test-connection-5.*
 gda-test-blob
 gda-provider-status
 gdaui-test-data-entries
diff --git a/testing/Makefile.am b/testing/Makefile.am
index fe8de0f..ec11025 100644
--- a/testing/Makefile.am
+++ b/testing/Makefile.am
@@ -6,17 +6,17 @@ AM_CPPFLAGS = \
 	$(LIBGDA_CFLAGS) \
 	$(LIBGDA_WFLAGS)
 
-bin_PROGRAMS = gda-test-connection-4.0
+bin_PROGRAMS = gda-test-connection-5.0
 if HAVE_UI
 UI_PROGS=gdaui-test-data-entries gdaui-test-widget-entry gdaui-test-errors gdaui-test-rt-editor
 endif
 noinst_PROGRAMS = gda-test-blob gda-provider-status virtual-test virtual-test-2 $(UI_PROGS)
 
-gda_test_connection_4_0_SOURCES = \
+gda_test_connection_5_0_SOURCES = \
         gda-test-connection.c
 
-gda_test_connection_4_0_LDADD = \
-        $(top_builddir)/libgda/libgda-4.0.la \
+gda_test_connection_5_0_LDADD = \
+        $(top_builddir)/libgda/libgda-5.0.la \
         $(LIBGDA_LIBS)
 
 
@@ -24,7 +24,7 @@ gda_test_blob_SOURCES = \
         gda-test-blob.c
 
 gda_test_blob_LDADD = \
-        $(top_builddir)/libgda/libgda-4.0.la \
+        $(top_builddir)/libgda/libgda-5.0.la \
         $(LIBGDA_LIBS)
 
 
@@ -34,21 +34,21 @@ gda_provider_status_SOURCES = \
         gda-provider-status.c
 
 gda_provider_status_LDADD = \
-        $(top_builddir)/libgda/libgda-4.0.la \
+        $(top_builddir)/libgda/libgda-5.0.la \
         $(LIBGDA_LIBS)
 
 virtual_test_SOURCES = \
 	virtual-test.c
 
 virtual_test_LDADD = \
-        $(top_builddir)/libgda/libgda-4.0.la \
+        $(top_builddir)/libgda/libgda-5.0.la \
         $(LIBGDA_LIBS)
 
 virtual_test_2_SOURCES = \
 	virtual-test-2.c
 
 virtual_test_2_LDADD = \
-        $(top_builddir)/libgda/libgda-4.0.la \
+        $(top_builddir)/libgda/libgda-5.0.la \
         $(LIBGDA_LIBS)
 
 gdaui_test_data_entries_CFLAGS = $(GTK_CFLAGS)
@@ -56,8 +56,8 @@ gdaui_test_data_entries_SOURCES = \
         gdaui-test-data-entries.c
 
 gdaui_test_data_entries_LDADD = \
-        $(top_builddir)/libgda/libgda-4.0.la \
-        $(top_builddir)/libgda-ui/libgda-ui-4.0.la \
+        $(top_builddir)/libgda/libgda-5.0.la \
+        $(top_builddir)/libgda-ui/libgda-ui-5.0.la \
         $(LIBGDA_LIBS) \
 	$(GTK_LIBS)
 
@@ -66,8 +66,8 @@ gdaui_test_widget_entry_SOURCES = \
         gdaui-test-widget-entry.c
 
 gdaui_test_widget_entry_LDADD = \
-        $(top_builddir)/libgda/libgda-4.0.la \
-        $(top_builddir)/libgda-ui/libgda-ui-4.0.la \
+        $(top_builddir)/libgda/libgda-5.0.la \
+        $(top_builddir)/libgda-ui/libgda-ui-5.0.la \
         $(LIBGDA_LIBS) \
 	$(GTK_LIBS)
 
@@ -76,9 +76,9 @@ gdaui_test_errors_SOURCES = \
         gdaui-test-errors.c
 
 gdaui_test_errors_LDADD = \
-        $(top_builddir)/libgda/libgda-4.0.la \
-        $(top_builddir)/libgda-ui/libgda-ui-4.0.la \
-	$(top_builddir)/tests/libgda-test-4.0.la \
+        $(top_builddir)/libgda/libgda-5.0.la \
+        $(top_builddir)/libgda-ui/libgda-ui-5.0.la \
+	$(top_builddir)/tests/libgda-test-5.0.la \
         $(LIBGDA_LIBS) \
 	$(GTK_LIBS)
 
@@ -87,8 +87,8 @@ gdaui_test_rt_editor_SOURCES = \
         gdaui-test-rt-editor.c
 
 gdaui_test_rt_editor_LDADD = \
-        $(top_builddir)/libgda/libgda-4.0.la \
-        $(top_builddir)/libgda-ui/libgda-ui-4.0.la \
+        $(top_builddir)/libgda/libgda-5.0.la \
+        $(top_builddir)/libgda-ui/libgda-ui-5.0.la \
         $(LIBGDA_LIBS) \
 	$(GTK_LIBS)
 
diff --git a/testing/gdaui-test-data-entries.c b/testing/gdaui-test-data-entries.c
index a312a75..dc7ab0b 100644
--- a/testing/gdaui-test-data-entries.c
+++ b/testing/gdaui-test-data-entries.c
@@ -2,6 +2,9 @@
 #include <libgda-ui/libgda-ui.h>
 #include <libgda-ui/gdaui-plugin.h>
 #include <gtk/gtk.h>
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
 
 typedef enum {
 	TESTED_BASIC,
@@ -104,8 +107,10 @@ main (int argc, char **argv)
 	GOptionContext *context;
 	GError *error = NULL;
 
+#ifdef HAVE_LOCALE_H
 	/* Initialize i18n support */
-	gtk_set_locale ();
+	setlocale (LC_ALL,"");
+#endif
 
 	/* command line parsing */
         context = g_option_context_new ("Gdaui entry widgets and cell renderers testing");
@@ -123,7 +128,7 @@ main (int argc, char **argv)
 	/* init main conf */
 	GType tested_gtypes [] = {G_TYPE_INT64, G_TYPE_UINT64, GDA_TYPE_BINARY, G_TYPE_BOOLEAN, GDA_TYPE_BLOB,
 				  G_TYPE_DATE, G_TYPE_DOUBLE,
-				  GDA_TYPE_GEOMETRIC_POINT, G_TYPE_OBJECT, G_TYPE_INT, GDA_TYPE_LIST, 
+				  GDA_TYPE_GEOMETRIC_POINT, G_TYPE_OBJECT, G_TYPE_INT, 
 				  GDA_TYPE_NUMERIC, G_TYPE_FLOAT, GDA_TYPE_SHORT, GDA_TYPE_USHORT, G_TYPE_STRING, 
 				  GDA_TYPE_TIME, GDA_TYPE_TIMESTAMP, G_TYPE_CHAR, G_TYPE_UCHAR, G_TYPE_UINT};
 	mainconf.test_type = TESTED_BASIC;
@@ -543,7 +548,7 @@ static GtkWidget *build_form_test_for_gtype (GdaDataHandler *dh, GType type, con
 static GtkWidget *build_grid_test_for_gtype (GdaDataHandler *dh, GType type, const gchar *plugin_name);
 
 static void
-plugin_nb_page_changed_cb (GtkNotebook *nb, G_GNUC_UNUSED GtkWidget *page, gint pageno, 
+plugin_nb_page_changed_cb (GtkNotebook *nb, G_GNUC_UNUSED GtkWidget *page, gint pageno,
 			   G_GNUC_UNUSED GtkWidget *table)
 {
 	GtkWidget *vbox;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 8eb45b7..d68ca7c 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,5 +1,5 @@
-noinst_LTLIBRARIES = libgda-test-4.0.la
-TESTS = test-ddl-creator test-bin-converter test-sql-identifier test-identifiers-quotes test-sql-builder test-connection-string-split test-input-parsers
+noinst_LTLIBRARIES = libgda-test-5.0.la
+TESTS = test-ddl-creator test-bin-converter test-sql-identifier test-identifiers-quotes test-sql-builder test-connection-string-split
 check_PROGRAMS = test-ddl-creator test-bin-converter test-sql-identifier test-identifiers-quotes test-sql-builder test-connection-string-split test-input-parsers
 
 
@@ -17,7 +17,7 @@ AM_CPPFLAGS = \
 test_headers = \
         gda-ddl-creator.h
 
-libgda_test_4_0_la_SOURCES = \
+libgda_test_5_0_la_SOURCES = \
         $(test_headers) \
         gda-ddl-creator.c \
 	test-cnc-utils.h \
@@ -25,18 +25,18 @@ libgda_test_4_0_la_SOURCES = \
 	data-model-errors.h \
 	data-model-errors.c
 
-libgda_test_4_0_la_LDFLAGS = $(NO_UNDEFINED)
+libgda_test_5_0_la_LDFLAGS = $(NO_UNDEFINED)
 
-libgda_test_4_0_la_LIBADD = \
+libgda_test_5_0_la_LIBADD = \
 	$(LIBGDA_LIBS) \
-	$(top_builddir)/libgda/libgda-4.0.la 
+	$(top_builddir)/libgda/libgda-5.0.la 
 
 test_ddl_creator_SOURCES = \
         test-ddl-creator.c
 
 test_ddl_creator_LDADD = \
-        $(top_builddir)/libgda/libgda-4.0.la \
-	libgda-test-4.0.la \
+        $(top_builddir)/libgda/libgda-5.0.la \
+	libgda-test-5.0.la \
         $(LIBGDA_LIBS)
 
 
@@ -44,43 +44,43 @@ test_bin_converter_SOURCES = \
         test-bin-converter.c
 
 test_bin_converter_LDADD = \
-        $(top_builddir)/libgda/libgda-4.0.la \
-	libgda-test-4.0.la \
+        $(top_builddir)/libgda/libgda-5.0.la \
+	libgda-test-5.0.la \
         $(LIBGDA_LIBS)
 
 test_sql_identifier_SOURCES = \
         test-sql-identifier.c
 
 test_sql_identifier_LDADD = \
-        $(top_builddir)/libgda/libgda-4.0.la \
+        $(top_builddir)/libgda/libgda-5.0.la \
         $(LIBGDA_LIBS)
 
 test_identifiers_quotes_SOURCES = \
         test-identifiers-quotes.c
 
 test_identifiers_quotes_LDADD = \
-        $(top_builddir)/libgda/libgda-4.0.la \
+        $(top_builddir)/libgda/libgda-5.0.la \
         $(LIBGDA_LIBS)
 
 test_sql_builder_SOURCES = \
         test-sql-builder.c
 
 test_sql_builder_LDADD = \
-        $(top_builddir)/libgda/libgda-4.0.la \
+        $(top_builddir)/libgda/libgda-5.0.la \
         $(LIBGDA_LIBS)
 
 test_connection_string_split_SOURCES = \
         test-connection-string-split.c
 
 test_connection_string_split_LDADD = \
-        $(top_builddir)/libgda/libgda-4.0.la \
+        $(top_builddir)/libgda/libgda-5.0.la \
         $(LIBGDA_LIBS)
 
 test_input_parsers_SOURCES = \
         test-input-parsers.c
 
 test_input_parsers_LDADD = \
-        $(top_builddir)/libgda/libgda-4.0.la \
+        $(top_builddir)/libgda/libgda-5.0.la \
         $(LIBGDA_LIBS)
 
 EXTRA_DIST = dbstruct.xml
diff --git a/tests/data-models/Makefile.am b/tests/data-models/Makefile.am
index fec0bd6..a22993b 100644
--- a/tests/data-models/Makefile.am
+++ b/tests/data-models/Makefile.am
@@ -15,7 +15,7 @@ common_sources =
 
 check_model_import_SOURCES = $(common_sources) check_model_import.c
 check_model_import_LDADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS)
 
 check_virtual_SOURCES = $(common_sources) check_virtual.c
@@ -23,38 +23,38 @@ check_virtual_CFLAGS = \
 	-I$(top_srcdir)/libgda/sqlite \
 	-I$(top_srcdir)/libgda/sqlite/virtual
 check_virtual_LDADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS)
 
 check_data_proxy_SOURCES = $(common_sources) check_data_proxy.c
 check_data_proxy_LDADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS)
 
 check_model_copy_SOURCES = $(common_sources) check_model_copy.c
 check_model_copy_LDADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS)
 
 check_pmodel_SOURCES = $(common_sources) check_pmodel.c
 check_pmodel_CFLAGS = \
 	-I$(top_srcdir)/libgda/sqlite
 check_pmodel_LDADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
-	$(top_builddir)/tests/libgda-test-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
+	$(top_builddir)/tests/libgda-test-5.0.la \
 	$(LIBGDA_LIBS)
 
 check_empty_rs_SOURCES = $(common_sources) check_empty_rs.c
 check_empty_rs_LDADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS)
 
 check_model_errors_SOURCES = $(common_sources) check_model_errors.c
 check_model_errors_CFLAGS = \
 	-I$(top_srcdir)/libgda/sqlite
 check_model_errors_LDADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
-	$(top_builddir)/tests/libgda-test-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
+	$(top_builddir)/tests/libgda-test-5.0.la \
 	$(LIBGDA_LIBS)
 
 check_vcnc_SOURCES = $(common_sources) check_vcnc.c
@@ -62,7 +62,7 @@ check_vcnc_CFLAGS = \
 	-I$(top_srcdir)/libgda/sqlite \
 	-I$(top_srcdir)/libgda/sqlite/vcnc
 check_vcnc_LDADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS)
 
 
diff --git a/tests/meta-store/Makefile.am b/tests/meta-store/Makefile.am
index 4bf5da8..992d964 100644
--- a/tests/meta-store/Makefile.am
+++ b/tests/meta-store/Makefile.am
@@ -14,22 +14,22 @@ common_sources = common.c common.h
 
 check_meta_store_memory_SOURCES = check_meta_store_memory.c $(common_sources)
 check_meta_store_memory_LDADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS)
 
 check_meta_store_sqlite_SOURCES = check_meta_store_sqlite.c $(common_sources)
 check_meta_store_sqlite_LDADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS)
 
 check_meta_store_postgresql_SOURCES = check_meta_store_postgresql.c $(common_sources)
 check_meta_store_postgresql_LDADD = \
-        $(top_builddir)/libgda/libgda-4.0.la \
+        $(top_builddir)/libgda/libgda-5.0.la \
         $(LIBGDA_LIBS)
 
 check_meta_store_mysql_SOURCES = check_meta_store_mysql.c $(common_sources)
 check_meta_store_mysql_LDADD = \
-        $(top_builddir)/libgda/libgda-4.0.la \
+        $(top_builddir)/libgda/libgda-5.0.la \
         $(LIBGDA_LIBS)
 
 EXTRA_DIST = data_builtin_data_types.csv \
diff --git a/tests/multi-threading/Makefile.am b/tests/multi-threading/Makefile.am
index f595884..a65586d 100644
--- a/tests/multi-threading/Makefile.am
+++ b/tests/multi-threading/Makefile.am
@@ -12,27 +12,27 @@ check_PROGRAMS = check_mutex check_parser check_cnc_lock check_threaded_cnc chec
 
 check_mutex_SOURCES = check_mutex.c
 check_mutex_LDADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS)
 
 check_parser_SOURCES = check_parser.c
 check_parser_LDADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS)
 
 check_cnc_lock_SOURCES = check_cnc_lock.c common.c common.h
 check_cnc_lock_LDADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS)
 
 check_threaded_cnc_SOURCES = check_threaded_cnc.c common.c common.h
 check_threaded_cnc_LDADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS)
 
 check_wrapper_SOURCES = check_wrapper.c dummy-object.c dummy-object.h
 check_wrapper_LDADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS)
 
 EXTRA_DIST = testdb.sql
diff --git a/tests/parser/Makefile.am b/tests/parser/Makefile.am
index acc8e81..c774ce7 100644
--- a/tests/parser/Makefile.am
+++ b/tests/parser/Makefile.am
@@ -13,32 +13,32 @@ check_PROGRAMS = check_parser check_validation check_normalization check_dml_com
 
 check_parser_SOURCES = check_parser.c
 check_parser_LDADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS)
 
 check_validation_SOURCES = check_validation.c
 check_validation_LDADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS)
 
 check_normalization_SOURCES = check_normalization.c
 check_normalization_LDADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS)
 
 check_dml_comp_SOURCES = check_dml_comp.c
 check_dml_comp_LDADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS)
 
 check_script_SOURCES = check_script.c
 check_script_LDADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS)
 
 check_rewrite_for_default_SOURCES = check_rewrite_for_default.c
 check_rewrite_for_default_LDADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS)
 
 
diff --git a/tests/providers/Makefile.am b/tests/providers/Makefile.am
index 784b60e..f8e1961 100644
--- a/tests/providers/Makefile.am
+++ b/tests/providers/Makefile.am
@@ -49,50 +49,50 @@ common_sources = \
 check_sqlite_SOURCES = $(common_sources) check_sqlite.c
 check_sqlite_CFLAGS = 
 check_sqlite_LDADD =  \
-	$(top_builddir)/libgda/libgda-4.0.la \
-	$(top_builddir)/tests/libgda-test-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
+	$(top_builddir)/tests/libgda-test-5.0.la \
 	$(LIBGDA_LIBS)
 
 check_bdb_SOURCES = $(common_sources) check_bdb.c
 check_bdb_CFLAGS = 
 check_bdb_LDADD =  \
-	$(top_builddir)/libgda/libgda-4.0.la \
-	$(top_builddir)/tests/libgda-test-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
+	$(top_builddir)/tests/libgda-test-5.0.la \
 	$(LIBGDA_LIBS)
 
 check_firebird_SOURCES = $(common_sources) check_firebird.c
 check_firebird_CFLAGS = 
 check_firebird_LDADD =  \
-	$(top_builddir)/libgda/libgda-4.0.la \
-	$(top_builddir)/tests/libgda-test-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
+	$(top_builddir)/tests/libgda-test-5.0.la \
 	$(LIBGDA_LIBS)
 
 check_mdb_SOURCES = $(common_sources) check_mdb.c
 check_mdb_CFLAGS = 
 check_mdb_LDADD =  \
-	$(top_builddir)/libgda/libgda-4.0.la \
-	$(top_builddir)/tests/libgda-test-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
+	$(top_builddir)/tests/libgda-test-5.0.la \
 	$(LIBGDA_LIBS)
 
 check_mysql_SOURCES = $(common_sources) check_mysql.c
 check_mysql_CFLAGS = 
 check_mysql_LDADD =  \
-	$(top_builddir)/libgda/libgda-4.0.la \
-	$(top_builddir)/tests/libgda-test-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
+	$(top_builddir)/tests/libgda-test-5.0.la \
 	$(LIBGDA_LIBS)
 
 check_oracle_SOURCES = $(common_sources) check_oracle.c
 check_oracle_CFLAGS = 
 check_oracle_LDADD =  \
-	$(top_builddir)/libgda/libgda-4.0.la \
-	$(top_builddir)/tests/libgda-test-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
+	$(top_builddir)/tests/libgda-test-5.0.la \
 	$(LIBGDA_LIBS)
 
 check_postgres_SOURCES = $(common_sources) check_postgres.c
 check_postgres_CFLAGS = 
 check_postgres_LDADD =  \
-	$(top_builddir)/libgda/libgda-4.0.la \
-	$(top_builddir)/tests/libgda-test-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
+	$(top_builddir)/tests/libgda-test-5.0.la \
 	$(LIBGDA_LIBS)
 
 EXTRA_DIST = \
diff --git a/tests/test-cnc-utils.c b/tests/test-cnc-utils.c
index db5dd8e..f7579d6 100644
--- a/tests/test-cnc-utils.c
+++ b/tests/test-cnc-utils.c
@@ -114,14 +114,14 @@ test_cnc_setup_connection (const gchar *provider, const gchar *dbname, GError **
 		GdaServerOperation *op;
 
 		db_quark_list = gda_quark_list_new_from_string (db_params);
-		op = gda_server_operation_prepare_drop_database (prov_info->id, dbname, NULL);
+		op = gda_server_operation_prepare_create_database (prov_info->id, dbname, NULL);
 		gda_quark_list_foreach (db_quark_list, (GHFunc) db_create_quark_foreach_func, op);
 		gda_server_operation_perform_drop_database (op, NULL, NULL);
 		g_object_unref (op);
 
 		op = gda_server_operation_prepare_create_database (prov_info->id, dbname, NULL);
 		gda_quark_list_foreach (db_quark_list, (GHFunc) db_create_quark_foreach_func, op);
-		if (!gda_perform_create_database (NULL, op, error)) 
+		if (!gda_server_operation_perform_create_database (op, NULL, error)) 
 			goto out;
 		db_created = TRUE;
 	}
diff --git a/tests/test-sql-identifier.c b/tests/test-sql-identifier.c
index 8378986..e081f77 100644
--- a/tests/test-sql-identifier.c
+++ b/tests/test-sql-identifier.c
@@ -44,13 +44,47 @@ ATest tests[] = {
 	{"T8BLE_a", TRUE},
 };
 
+static gboolean
+identifier_needs_quotes (const gchar *str)
+{
+	const gchar *ptr;
+	gchar icase = 0;
+
+	g_return_val_if_fail (str, FALSE);
+	for (ptr = str; *ptr; ptr++) {
+		/* quote if 1st char is a number */
+		if ((*ptr <= '9') && (*ptr >= '0')) {
+			if (ptr == str)
+				return TRUE;
+			continue;
+		}
+		if ((*ptr >= 'A') && (*ptr <= 'Z')) {
+			if (icase == 0) /* first alpha char encountered */
+				icase = 'U';
+			else if (icase == 'L') /* @str has mixed case */
+				return TRUE;
+			continue;
+		}
+		if ((*ptr >= 'a') && (*ptr <= 'z')) {
+			if (icase == 0) /* first alpha char encountered */
+				icase = 'L';
+			else if (icase == 'U')
+				return TRUE; /* @str has mixed case */
+			continue;
+		}
+		if ((*ptr != '$') && (*ptr != '_') && (*ptr != '#'))
+			return TRUE;
+	}
+	return FALSE;
+}
+
 int
 main (int argc, char** argv)
 {
 	gint i, nfailed = 0;
 	for (i = 0; i < G_N_ELEMENTS (tests); i++) {
 		ATest *test = &(tests [i]);
-		if (gda_sql_identifier_needs_quotes (test->sql_identifier) != test->need_quotes) {
+		if (identifier_needs_quotes (test->sql_identifier) != test->need_quotes) {
 			g_print ("Failed for %s: reported %s\n", test->sql_identifier,
 				 test->need_quotes ? "no quotes needed" : "quotes needed");
 			nfailed++;
diff --git a/tests/value-holders/Makefile.am b/tests/value-holders/Makefile.am
index 21c357a..b04fa54 100644
--- a/tests/value-holders/Makefile.am
+++ b/tests/value-holders/Makefile.am
@@ -14,17 +14,17 @@ common_sources = common.c common.h
 
 check_holder_SOURCES = check_holder.c $(common_sources)
 check_holder_LDADD = $(JSON_GLIB_LIBS) \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS)
 
 check_set_SOURCES = check_set.c $(common_sources)
 check_set_LDADD = $(JSON_GLIB_LIBS) \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS)
 
 check_statement_SOURCES = check_statement.c $(common_sources)
 check_statement_LDADD = $(JSON_GLIB_LIBS) \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS)
 
 
diff --git a/tools/.gitignore b/tools/.gitignore
index d1e24a3..09a88dd 100644
--- a/tools/.gitignore
+++ b/tools/.gitignore
@@ -1,6 +1,6 @@
-gda-sql-4*
-gda-list-config-4*
-gda-list-server-op-4*
+gda-sql-5*
+gda-list-config-5*
+gda-list-server-op-5*
 information-schema-doc
 information-schema-types
-gda-sql-4.*.1
+gda-sql-5.*.1
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 652329b..56a7bc7 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -5,9 +5,9 @@ endif
 SUBDIRS = $(BROWSER_DIR)
 
 bin_PROGRAMS = \
-	gda-list-config-4.0 \
-	gda-sql-4.0 \
-	gda-list-server-op-4.0
+	gda-list-config-5.0 \
+	gda-sql-5.0 \
+	gda-list-server-op-5.0
 
 noinst_PROGRAMS = information-schema-doc information-schema-types
 
@@ -21,14 +21,14 @@ AM_CPPFLAGS = \
 	$(LIBGDA_CFLAGS) \
 	-DROOT_DIR=\""$(top_srcdir)"\"
 
-gda_list_config_4_0_SOURCES = \
+gda_list_config_5_0_SOURCES = \
         gda-list-config.c
 
-gda_list_config_4_0_LDADD = \
-        $(top_builddir)/libgda/libgda-4.0.la \
+gda_list_config_5_0_LDADD = \
+        $(top_builddir)/libgda/libgda-5.0.la \
         $(LIBGDA_LIBS)
 
-gda_sql_4_0_SOURCES = \
+gda_sql_5_0_SOURCES = \
 	config-info.h \
 	config-info.c \
 	tools-utils.h \
@@ -45,24 +45,24 @@ gda_sql_4_0_SOURCES = \
 	$(top_srcdir)/libgda/md5.h \
 	$(top_srcdir)/libgda/md5c.c
 
-gda_sql_4_0_LDADD = \
-        $(top_builddir)/libgda/libgda-4.0.la \
+gda_sql_5_0_LDADD = \
+        $(top_builddir)/libgda/libgda-5.0.la \
         $(LIBGDA_LIBS) \
 	$(READLINE_LIB) \
         $(HISTORY_LIB)
 
 if LIBSOUP
-gda_sql_4_0_SOURCES += web-server.h web-server.c html-doc.h html-doc.c
+gda_sql_5_0_SOURCES += web-server.h web-server.c html-doc.h html-doc.c
 AM_CPPFLAGS += $(LIBSOUP_CFLAGS)
-gda_sql_4_0_LDADD += $(LIBSOUP_LIBS)
+gda_sql_5_0_LDADD += $(LIBSOUP_LIBS)
 endif
 
 
 
 # setenv() is in libiberty in mingw
 if PLATFORM_WIN32
-gda_sql_4_0_LDADD += -liberty
-gda_sql_4_0_SOURCES += gda-sql-res.rc
+gda_sql_5_0_LDADD += -liberty
+gda_sql_5_0_SOURCES += gda-sql-res.rc
 endif
 
 .rc.o:
@@ -71,13 +71,13 @@ endif
 gda-sql-res.o: gda-sql-res.rc
 	$(WINDRES) $^ -o $@
 
-gda_list_server_op_4_0_SOURCES = \
+gda_list_server_op_5_0_SOURCES = \
         gda-list-server-op.c \
 	gda-tree-mgr-xml.c \
 	gda-tree-mgr-xml.h
 
-gda_list_server_op_4_0_LDADD = \
-        $(top_builddir)/libgda/libgda-4.0.la \
+gda_list_server_op_5_0_LDADD = \
+        $(top_builddir)/libgda/libgda-5.0.la \
         $(LIBGDA_LIBS)
 
 
@@ -85,17 +85,17 @@ information_schema_doc_SOURCES = \
         information-schema-doc.c
 
 information_schema_doc_LDADD = \
-        $(top_builddir)/libgda/libgda-4.0.la \
+        $(top_builddir)/libgda/libgda-5.0.la \
         $(LIBGDA_LIBS)
 
 information_schema_types_SOURCES = \
         information-schema-types.c
 
 information_schema_types_LDADD = \
-        $(top_builddir)/libgda/libgda-4.0.la \
+        $(top_builddir)/libgda/libgda-5.0.la \
         $(LIBGDA_LIBS)
 
-webdatadir = $(datadir)/libgda-4.0/web
+webdatadir = $(datadir)/libgda-5.0/web
 webdata_DATA = \
 	cnc.js \
 	md5.js \
@@ -113,7 +113,7 @@ EXTRA_DIST = \
 	$(webdata_DATA)
 
 mans = \
-	gda-sql-4.0.1
+	gda-sql-5.0.1
 
 man_MANS = \
 	$(mans)
@@ -150,9 +150,9 @@ install-exec-hook:
 if DEFAULT_BINARY
 	cd $(DESTDIR)$(bindir) \
 	&& rm -f gda-list-config$(EXEEXT) gda-sql$(EXEEXT) gda-list-server-op$(EXEEXT) \
-	&& $(LN_S) gda-list-config-4.0$(EXEEXT) gda-list-config$(EXEEXT) \
-	&& $(LN_S) gda-sql-4.0$(EXEEXT) gda-sql$(EXEEXT) \
-	&& $(LN_S) gda-list-server-op-4.0$(EXEEXT) gda-list-server-op$(EXEEXT)
+	&& $(LN_S) gda-list-config-5.0$(EXEEXT) gda-list-config$(EXEEXT) \
+	&& $(LN_S) gda-sql-5.0$(EXEEXT) gda-sql$(EXEEXT) \
+	&& $(LN_S) gda-list-server-op-5.0$(EXEEXT) gda-list-server-op$(EXEEXT)
 endif
 
 uninstall-local:
diff --git a/tools/browser/.gitignore b/tools/browser/.gitignore
index 51cb8a3..ce62655 100644
--- a/tools/browser/.gitignore
+++ b/tools/browser/.gitignore
@@ -1,5 +1,5 @@
-gda-browser-4.0
-gda-browser-4.*.desktop
+gda-browser-5.0
+gda-browser-5.*.desktop
 canvas-example
 marshal.c
 marshal.h
diff --git a/tools/browser/Makefile.am b/tools/browser/Makefile.am
index 4dc77dd..99a3a70 100644
--- a/tools/browser/Makefile.am
+++ b/tools/browser/Makefile.am
@@ -1,4 +1,4 @@
-bin_PROGRAMS=gda-browser-4.0
+bin_PROGRAMS=gda-browser-5.0
 noinst_LTLIBRARIES = libbrowser.la
 
 SUBDIRS = data common schema-browser query-exec data-manager dummy-perspective
@@ -77,14 +77,14 @@ libbrowser_la_SOURCES=\
 	browser-stock-icons.c \
 	browser-stock-icons.h
 
-gda_browser_4_0_SOURCES=\
+gda_browser_5_0_SOURCES=\
 	main.c
 
 $(OBJECTS): marshal.c marshal.h
 
 if PLATFORM_WIN32
 EXTRALDFLAGS=-mwindows
-gda_browser_4_0_SOURCES += browser-res.rc
+gda_browser_5_0_SOURCES += browser-res.rc
 else
 EXTRALDFLAGS=
 endif
@@ -99,8 +99,8 @@ endif
 browser-res.o: browser-res.rc
 	$(WINDRES) $^ -o $@
 
-gda_browser_4_0_LDFLAGS = $(EXTRALDFLAGS)
-gda_browser_4_0_LDADD=\
+gda_browser_5_0_LDFLAGS = $(EXTRALDFLAGS)
+gda_browser_5_0_LDADD=\
 	schema-browser/libperspective.la \
 	query-exec/libperspective.la \
 	data-manager/libperspective.la \
@@ -108,15 +108,15 @@ gda_browser_4_0_LDADD=\
 	$(top_builddir)/libgda-ui/internal/libgda-ui-internal.la \
 	$(CANVAS_LDADD) \
 	common/libcommon.la \
-	$(top_builddir)/libgda/libgda-4.0.la \
-	$(top_builddir)/libgda-ui/libgda-ui-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
+	$(top_builddir)/libgda-ui/libgda-ui-5.0.la \
 	$(LIBGDA_LIBS) $(GTK_LIBS) $(GTKSOURCEVIEW_LIBS) $(MAC_INTEGRATION_LIBS)
 
 
 @INTLTOOL_DESKTOP_RULE@
 
 desktopdir=$(datadir)/applications
-Desktop_in_files = gda-browser-4.0.desktop.in
+Desktop_in_files = gda-browser-5.0.desktop.in
 desktop_DATA = $(Desktop_in_files:.desktop.in=.desktop)
 
 # canvas example
@@ -139,12 +139,12 @@ canvas_example_LDADD=\
 	libbrowser.la \
 	$(top_builddir)/libgda-ui/internal/libgda-ui-internal.la \
 	common/libcommon.la \
-	$(top_builddir)/libgda/libgda-4.0.la \
-	$(top_builddir)/libgda-ui/libgda-ui-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
+	$(top_builddir)/libgda-ui/libgda-ui-5.0.la \
 	$(LIBGDA_LIBS) $(GTK_LIBS)
 
 # icons
-iconsdir=$(datadir)/libgda-4.0/pixmaps
+iconsdir=$(datadir)/libgda-5.0/pixmaps
 icons_DATA= \
 	gda-browser.png \
 	gda-browser-auth.png \
@@ -172,7 +172,7 @@ icons_DATA= \
 # app icon
 appiconsdir=$(datadir)/pixmaps
 appicons_DATA= \
-        gda-browser-4.0.png
+        gda-browser-5.0.png
 
 EXTRA_DIST = \
 	marshal.list \
diff --git a/tools/browser/auth-dialog.c b/tools/browser/auth-dialog.c
index 13ee9c7..823c8d2 100644
--- a/tools/browser/auth-dialog.c
+++ b/tools/browser/auth-dialog.c
@@ -1,8 +1,8 @@
 /* 
  * Copyright (C) 2009 - 2011 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -207,11 +207,7 @@ auth_dialog_init (AuthDialog *dialog)
 				GTK_STOCK_CANCEL,
 				GTK_RESPONSE_REJECT, NULL);
 
-#if GTK_CHECK_VERSION(2,18,0)
 	dcontents = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
-#else
-	dcontents = GTK_DIALOG (dialog)->vbox;
-#endif
 	gtk_box_set_spacing (GTK_BOX (dcontents), 5);
 	gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT, TRUE);
 
@@ -286,8 +282,7 @@ auth_dialog_new (GtkWindow *parent)
 	return (AuthDialog*) g_object_new (AUTH_TYPE_DIALOG, "title", _("Authentication"),
 					   "transient-for", parent,
 					   "resizable", FALSE,
-					   "border-width", 10, 
-					   "has-separator", FALSE, NULL);
+					   "border-width", 10, NULL);
 }
 
 /*
@@ -366,13 +361,11 @@ update_dialog_focus (AuthDialog *dialog)
 		}
 	}
 
-#if GTK_CHECK_VERSION(2,20,0)
 	if (allvalid) {
 		GtkWidget *wid;
 		wid = gtk_dialog_get_widget_for_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
 		gtk_widget_grab_focus (wid);
 	}
-#endif
 }
 
 /**
@@ -503,12 +496,7 @@ auth_dialog_add_cnc_string (AuthDialog *dialog, const gchar *cnc_string, GError
 		gchar *str, *tmp, *ptr;
 		GtkWidget *dcontents;
 
-#if GTK_CHECK_VERSION(2,18,0)
 		dcontents = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
-#else
-		dcontents = GTK_DIALOG (dialog)->vbox;
-#endif
-
 		label = gtk_label_new ("");
 		tmp = g_strdup (ad->ext.cnc_string);
 		for (ptr = tmp; *ptr; ptr++) {
diff --git a/tools/browser/auth-dialog.h b/tools/browser/auth-dialog.h
index 3894bef..fcb9e64 100644
--- a/tools/browser/auth-dialog.h
+++ b/tools/browser/auth-dialog.h
@@ -1,8 +1,8 @@
 /* 
  * Copyright (C) 2009 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/browser-connection-priv.h b/tools/browser/browser-connection-priv.h
index ce1e38f..6380f5b 100644
--- a/tools/browser/browser-connection-priv.h
+++ b/tools/browser/browser-connection-priv.h
@@ -1,8 +1,8 @@
 /*
  * Copyright (C) 2009 - 2010 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/browser-connection.c b/tools/browser/browser-connection.c
index ae1ccda..0c76447 100644
--- a/tools/browser/browser-connection.c
+++ b/tools/browser/browser-connection.c
@@ -1,8 +1,8 @@
 /*
  * Copyright (C) 2009 - 2011 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/browser-connection.h b/tools/browser/browser-connection.h
index ad0dfa0..9c0784e 100644
--- a/tools/browser/browser-connection.h
+++ b/tools/browser/browser-connection.h
@@ -1,8 +1,8 @@
 /* 
  * Copyright (C) 2009 - 2011 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -17,7 +17,6 @@
  * Boston, MA 02111-1307, USA.
  */
 
-
 #ifndef __BROWSER_CONNECTION_H_
 #define __BROWSER_CONNECTION_H_
 
@@ -57,6 +56,19 @@ struct _BrowserConnectionClass
 							      const gchar *attr_name, const gchar *value);
 };
 
+/**
+ * SECTION:browser-connection
+ * @short_description: An opened connection
+ * @title: BrowserConnection
+ * @stability: Stable
+ * @see_also:
+ *
+ * The #BrowserConnection object wraps a #GdaConnection with some
+ * additionnal features. The wrapped #GdaConnection is only accessible from within
+ * the #BrowserConnection object, so to use a connection, you have to use the
+ * #BrowserConnection's methods.
+ */
+
 GType               browser_connection_get_type               (void) G_GNUC_CONST;
 
 BrowserConnection  *browser_connection_new                    (GdaConnection *cnc);
diff --git a/tools/browser/browser-connections-list.c b/tools/browser/browser-connections-list.c
index 0162c98..b4649db 100644
--- a/tools/browser/browser-connections-list.c
+++ b/tools/browser/browser-connections-list.c
@@ -1,8 +1,8 @@
 /*
  * Copyright (C) 2009 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/browser-connections-list.h b/tools/browser/browser-connections-list.h
index 9ae8c06..cb8bbfc 100644
--- a/tools/browser/browser-connections-list.h
+++ b/tools/browser/browser-connections-list.h
@@ -1,8 +1,8 @@
 /* 
  * Copyright (C) 2009 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/browser-core.c b/tools/browser/browser-core.c
index 3f7aabe..8287f8f 100644
--- a/tools/browser/browser-core.c
+++ b/tools/browser/browser-core.c
@@ -1,8 +1,8 @@
 /*
  * Copyright (C) 2009 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/browser-core.h b/tools/browser/browser-core.h
index 3822ff1..2110686 100644
--- a/tools/browser/browser-core.h
+++ b/tools/browser/browser-core.h
@@ -1,8 +1,8 @@
 /* 
- * Copyright (C) 2009 Vivien Malerba
+ * Copyright (C) 2009 - 2011 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -52,6 +52,17 @@ struct _BrowserCoreClass
 	void    (*connection_removed) (BrowserCore *bcore, BrowserConnection *bcnc);
 };
 
+/**
+ * SECTION:browser-core
+ * @short_description: Singleton holding the global browser information
+ * @title: BrowserCore
+ * @stability: Stable
+ * @see_also:
+ *
+ * A single instance of a #BrowserCore is created when the browser is started,
+ * accessible using browser_core_get().
+ */
+
 GType           browser_core_get_type               (void) G_GNUC_CONST;
 gboolean        browser_core_exists                 (void);
 BrowserCore    *browser_core_get                    (void);
diff --git a/tools/browser/browser-favorites.c b/tools/browser/browser-favorites.c
index d90587f..2e7a0c7 100644
--- a/tools/browser/browser-favorites.c
+++ b/tools/browser/browser-favorites.c
@@ -1,8 +1,8 @@
 /*
  * Copyright (C) 2009 - 2011 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/browser-favorites.h b/tools/browser/browser-favorites.h
index 65e3756..9444bf4 100644
--- a/tools/browser/browser-favorites.h
+++ b/tools/browser/browser-favorites.h
@@ -1,8 +1,8 @@
 /* 
  * Copyright (C) 2009 - 2011 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -39,6 +39,9 @@ typedef struct _BrowserFavoritesPrivate BrowserFavoritesPrivate;
  * BrowserFavoritesType:
  * @BROWSER_FAVORITES_TABLES: a database's table favorite
  * @BROWSER_FAVORITES_DIAGRAMS: a diagram favorite
+ * @BROWSER_FAVORITES_QUERIES:
+ * @BROWSER_FAVORITES_DATA_MANAGERS:
+ * @BROWSER_FAVORITES_ACTIONS:
  *
  * Enum to identify favorite's types.
  */
@@ -82,6 +85,17 @@ struct _BrowserFavoritesClass
 	void                    (*favorites_changed) (BrowserFavorites *bfav);
 };
 
+/**
+ * SECTION:browser-favorites
+ * @short_description: Favorites management
+ * @title: BrowserFavorites
+ * @stability: Stable
+ * @see_also:
+ *
+ * Each connection uses a single #BrowserFavorites object to manage its favorites,
+ * see browser_connection_get_favorites().
+ */
+
 GType               browser_favorites_get_type               (void) G_GNUC_CONST;
 
 BrowserFavorites   *browser_favorites_new                    (GdaMetaStore *store);
diff --git a/tools/browser/browser-page.c b/tools/browser/browser-page.c
index fdcdc39..7733b1f 100644
--- a/tools/browser/browser-page.c
+++ b/tools/browser/browser-page.c
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/browser-page.h b/tools/browser/browser-page.h
index 937ea26..64a1df2 100644
--- a/tools/browser/browser-page.h
+++ b/tools/browser/browser-page.h
@@ -1,11 +1,11 @@
 /*
- * Copyright (C) 2009 The GNOME Foundation.
+ * Copyright (C) 2009 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -43,6 +43,19 @@ struct _BrowserPageIface {
 	GtkWidget           *(* i_get_tab_label) (BrowserPage *page, GtkWidget **out_close_button);
 };
 
+/**
+ * SECTION:browser-page
+ * @short_description: A "page" within a #BrowserPerspective widget
+ * @title: BrowserPage
+ * @stability: Stable
+ * @see_also:
+ *
+ * Some widgets packed within a #BrowserPerspective can implement
+ * the #BrowserPage interface to specify their specific actions and menu and
+ * toolbar customizations. When they are packed in a notebook, they can also
+ * request some specific tab labels.
+ */
+
 GType               browser_page_get_type          (void) G_GNUC_CONST;
 
 GtkActionGroup     *browser_page_get_actions_group (BrowserPage *page);
diff --git a/tools/browser/browser-perspective.c b/tools/browser/browser-perspective.c
index 97dd40b..8a1e012 100644
--- a/tools/browser/browser-perspective.c
+++ b/tools/browser/browser-perspective.c
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/browser-perspective.h b/tools/browser/browser-perspective.h
index e6e865b..ab7daf4 100644
--- a/tools/browser/browser-perspective.h
+++ b/tools/browser/browser-perspective.h
@@ -1,11 +1,11 @@
 /*
- * Copyright (C) 2009 - 2010 The GNOME Foundation.
+ * Copyright (C) 2009 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -46,6 +46,17 @@ struct _BrowserPerspectiveIface {
 	void                 (* i_page_tab_label_change) (BrowserPerspective *perspective, BrowserPage *page);
 };
 
+/**
+ * SECTION:browser-perspective
+ * @short_description: A "perspective" in a #BrowserWindow window
+ * @title: BrowserPerspective
+ * @stability: Stable
+ * @see_also:
+ *
+ * #BrowserPerspective is an interface used by the #BrowserWindow object to switch
+ * between the activities ("perspectives"); it requires the #GtkWidget.
+ */
+
 GType           browser_perspective_get_type          (void) G_GNUC_CONST;
 
 GtkActionGroup *browser_perspective_get_actions_group (BrowserPerspective *perspective);
diff --git a/tools/browser/browser-spinner.c b/tools/browser/browser-spinner.c
index 69aa6c0..868496c 100644
--- a/tools/browser/browser-spinner.c
+++ b/tools/browser/browser-spinner.c
@@ -33,7 +33,7 @@
   #define GSEAL_ENABLE
   #undef KEEP_GSEAL_ENABLE
 #endif
-#if GTK_CHECK_VERSION(2,20,0)
+
 #include "browser-spinner.h"
 /**
  * browser_spinner_start:
@@ -79,910 +79,3 @@ browser_spinner_set_size (BrowserSpinner *spinner,
 					   size, &width, &height);
 	gtk_widget_set_size_request (GTK_WIDGET (spinner), width, height);
 }
-#else
-
-#include <gdk-pixbuf/gdk-pixbuf.h>
-#include "browser-spinner.h"
-
-/* Spinner cache implementation */
-
-#define BROWSER_TYPE_SPINNER_CACHE			(browser_spinner_cache_get_type())
-#define BROWSER_SPINNER_CACHE(object)		(G_TYPE_CHECK_INSTANCE_CAST((object), BROWSER_TYPE_SPINNER_CACHE, BrowserSpinnerCache))
-#define BROWSER_SPINNER_CACHE_CLASS(klass) 	(G_TYPE_CHECK_CLASS_CAST((klass), BROWSER_TYPE_SPINNER_CACHE, BrowserSpinnerCacheClass))
-#define BROWSER_IS_SPINNER_CACHE(object)		(G_TYPE_CHECK_INSTANCE_TYPE((object), BROWSER_TYPE_SPINNER_CACHE))
-#define BROWSER_IS_SPINNER_CACHE_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE((klass), BROWSER_TYPE_SPINNER_CACHE))
-#define BROWSER_SPINNER_CACHE_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS((obj), BROWSER_TYPE_SPINNER_CACHE, BrowserSpinnerCacheClass))
-
-typedef struct _BrowserSpinnerCache	BrowserSpinnerCache;
-typedef struct _BrowserSpinnerCacheClass	BrowserSpinnerCacheClass;
-typedef struct _BrowserSpinnerCachePrivate	BrowserSpinnerCachePrivate;
-
-struct _BrowserSpinnerCacheClass
-{
-	GObjectClass parent_class;
-};
-
-struct _BrowserSpinnerCache
-{
-	GObject parent_object;
-
-	/*< private >*/
-	BrowserSpinnerCachePrivate *priv;
-};
-
-#define BROWSER_SPINNER_CACHE_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), BROWSER_TYPE_SPINNER_CACHE, BrowserSpinnerCachePrivate))
-
-struct _BrowserSpinnerCachePrivate
-{
-	/* Hash table of GdkScreen -> BrowserSpinnerCacheData */
-	GHashTable *hash;
-};
-
-typedef struct
-{
-	guint ref_count;
-	GtkIconSize size;
-	int width;
-	int height;
-	GdkPixbuf **animation_pixbufs;
-	guint n_animation_pixbufs;
-} BrowserSpinnerImages;
-
-#define LAST_ICON_SIZE			GTK_ICON_SIZE_DIALOG + 1
-#define SPINNER_ICON_NAME		"process-working"
-#define SPINNER_FALLBACK_ICON_NAME	"gnome-spinner"
-#define BROWSER_SPINNER_IMAGES_INVALID	((BrowserSpinnerImages *) 0x1)
-
-typedef struct
-{
-	GdkScreen *screen;
-	GtkIconTheme *icon_theme;
-	BrowserSpinnerImages *images[LAST_ICON_SIZE];
-} BrowserSpinnerCacheData;
-
-static void browser_spinner_cache_class_init (BrowserSpinnerCacheClass *klass);
-static void browser_spinner_cache_init	  (BrowserSpinnerCache *cache);
-
-static GObjectClass *browser_spinner_cache_parent_class;
-
-static GType
-browser_spinner_cache_get_type (void)
-{
-	static GType type = 0;
-
-	if (G_UNLIKELY (type == 0))
-	{
-		const GTypeInfo our_info =
-		{
-			sizeof (BrowserSpinnerCacheClass),
-			NULL,
-			NULL,
-			(GClassInitFunc) browser_spinner_cache_class_init,
-			NULL,
-			NULL,
-			sizeof (BrowserSpinnerCache),
-			0,
-			(GInstanceInitFunc) browser_spinner_cache_init
-		};
-
-		type = g_type_register_static (G_TYPE_OBJECT,
-					       "BrowserSpinnerCache",
-					       &our_info, 0);
-	}
-
-	return type;
-}
-
-static BrowserSpinnerImages *
-browser_spinner_images_ref (BrowserSpinnerImages *images)
-{
-	g_return_val_if_fail (images != NULL, NULL);
-
-	images->ref_count++;
-
-	return images;
-}
-
-static void
-browser_spinner_images_unref (BrowserSpinnerImages *images)
-{
-	g_return_if_fail (images != NULL);
-
-	images->ref_count--;
-	if (images->ref_count == 0)
-	{
-		guint i;
-
-		for (i = 0; i < images->n_animation_pixbufs; ++i)
-		{
-			g_object_unref (images->animation_pixbufs[i]);
-		}
-		g_free (images->animation_pixbufs);
-
-		g_free (images);
-	}
-}
-
-static void
-browser_spinner_cache_data_unload (BrowserSpinnerCacheData *data)
-{
-	GtkIconSize size;
-	BrowserSpinnerImages *images;
-
-	g_return_if_fail (data != NULL);
-
-	for (size = GTK_ICON_SIZE_INVALID; size < LAST_ICON_SIZE; ++size)
-	{
-		images = data->images[size];
-		data->images[size] = NULL;
-
-		if (images != NULL && images != BROWSER_SPINNER_IMAGES_INVALID)
-		{
-			browser_spinner_images_unref (images);
-		}
-	}
-}
-
-static GdkPixbuf *
-extract_frame (GdkPixbuf *grid_pixbuf,
-	       int x,
-	       int y,
-	       int size)
-{
-	GdkPixbuf *pixbuf;
-
-	if (x + size > gdk_pixbuf_get_width (grid_pixbuf) ||
-	    y + size > gdk_pixbuf_get_height (grid_pixbuf))
-	{
-		return NULL;
-	}
-
-	pixbuf = gdk_pixbuf_new_subpixbuf (grid_pixbuf,
-					   x, y,
-					   size, size);
-	g_return_val_if_fail (pixbuf != NULL, NULL);
-
-	return pixbuf;
-}
-
-static GdkPixbuf *
-scale_to_size (GdkPixbuf *pixbuf,
-	       int dw,
-	       int dh)
-{
-	GdkPixbuf *result;
-	int pw, ph;
-
-	g_return_val_if_fail (pixbuf != NULL, NULL);
-
-	pw = gdk_pixbuf_get_width (pixbuf);
-	ph = gdk_pixbuf_get_height (pixbuf);
-
-	if (pw != dw || ph != dh)
-	{
-		result = gdk_pixbuf_scale_simple (pixbuf, dw, dh,
-						  GDK_INTERP_BILINEAR);
-		g_object_unref (pixbuf);
-		return result;
-	}
-
-	return pixbuf;
-}
-
-static BrowserSpinnerImages *
-browser_spinner_images_load (GdkScreen *screen,
-			  GtkIconTheme *icon_theme,
-			  GtkIconSize icon_size)
-{
-	BrowserSpinnerImages *images;
-	GdkPixbuf *icon_pixbuf, *pixbuf;
-	GtkIconInfo *icon_info = NULL;
-	int grid_width, grid_height, x, y, requested_size, size, isw, ish, n;
-	const char *icon;
-	GSList *list = NULL, *l;
-
-	if (!gtk_icon_size_lookup_for_settings (gtk_settings_get_for_screen (screen),
-						icon_size, &isw, &ish)) goto loser;
-
-	requested_size = MAX (ish, isw);
-
-	/* Load the animation. The 'rest icon' is the 0th frame */
-	icon_info = gtk_icon_theme_lookup_icon (icon_theme,
-						SPINNER_ICON_NAME,
-					        requested_size, 0);
-	if (icon_info == NULL)
-	{
-		g_warning ("Throbber animation not found");
-	
-		/* If the icon naming spec compliant name wasn't found, try the old name */
-		icon_info = gtk_icon_theme_lookup_icon (icon_theme,
-							SPINNER_FALLBACK_ICON_NAME,
-							requested_size, 0);
-		if (icon_info == NULL)
-		{
-			g_warning ("Throbber fallback animation not found either");
-			goto loser;
-		}
-	}
-	g_assert (icon_info != NULL);
-
-	size = gtk_icon_info_get_base_size (icon_info);
-	icon = gtk_icon_info_get_filename (icon_info);
-	if (icon == NULL) goto loser;
-
-	icon_pixbuf = gdk_pixbuf_new_from_file (icon, NULL);
-	gtk_icon_info_free (icon_info);
-	icon_info = NULL;
-
-	if (icon_pixbuf == NULL)
-	{
-		g_warning ("Could not load the spinner file");
-		goto loser;
-	}
-
-	grid_width = gdk_pixbuf_get_width (icon_pixbuf);
-	grid_height = gdk_pixbuf_get_height (icon_pixbuf);
-
-	n = 0;
-	for (y = 0; y < grid_height; y += size)
-	{
-		for (x = 0; x < grid_width ; x += size)
-		{
-			pixbuf = extract_frame (icon_pixbuf, x, y, size);
-
-			if (pixbuf)
-			{
-				list = g_slist_prepend (list, pixbuf);
-				++n;
-			}
-			else
-			{
-				g_warning ("Cannot extract frame (%d, %d) from the grid\n", x, y);
-			}
-		}
-	}
-
-	g_object_unref (icon_pixbuf);
-
-	if (list == NULL) goto loser;
-	g_assert (n > 0);
-
-	if (size > requested_size)
-	{
-		for (l = list; l != NULL; l = l->next)
-		{
-			l->data = scale_to_size (l->data, isw, ish);
-		}
-	}
-
-	/* Now we've successfully got all the data */
-	images = g_new (BrowserSpinnerImages, 1);
-	images->ref_count = 1;
-
-	images->size = icon_size;
-	images->width = images->height = requested_size;
-
-	images->n_animation_pixbufs = n;
-	images->animation_pixbufs = g_new (GdkPixbuf *, n);
-
-	for (l = list; l != NULL; l = l->next)
-	{
-		g_assert (l->data != NULL);
-		images->animation_pixbufs[--n] = l->data;
-	}
-	g_assert (n == 0);
-
-	g_slist_free (list);
-
-	return images;
-
-loser:
-	if (icon_info)
-	{
-		gtk_icon_info_free (icon_info);
-	}
-	g_slist_foreach (list, (GFunc) g_object_unref, NULL);
-
-	return NULL;
-}
-
-static BrowserSpinnerCacheData *
-browser_spinner_cache_data_new (GdkScreen *screen)
-{
-	BrowserSpinnerCacheData *data;
-
-	data = g_new0 (BrowserSpinnerCacheData, 1);
-
-	data->screen = screen;
-	data->icon_theme = gtk_icon_theme_get_for_screen (screen);
-	g_signal_connect_swapped (data->icon_theme, "changed",
-				  G_CALLBACK (browser_spinner_cache_data_unload),
-				  data);
-
-	return data;
-}
-
-static void
-browser_spinner_cache_data_free (BrowserSpinnerCacheData *data)
-{
-	g_return_if_fail (data != NULL);
-	g_return_if_fail (data->icon_theme != NULL);
-
-	g_signal_handlers_disconnect_by_func
-		(data->icon_theme,
-		 G_CALLBACK (browser_spinner_cache_data_unload), data);
-
-	browser_spinner_cache_data_unload (data);
-
-	g_free (data);
-}
-
-static BrowserSpinnerImages *
-browser_spinner_cache_get_images (BrowserSpinnerCache *cache,
-			       GdkScreen *screen,
-			       GtkIconSize icon_size)
-{
-	BrowserSpinnerCachePrivate *priv = cache->priv;
-	BrowserSpinnerCacheData *data;
-	BrowserSpinnerImages *images;
-
-	g_return_val_if_fail (icon_size >= 0 && icon_size < LAST_ICON_SIZE, NULL);
-
-	/* Backward compat: "invalid" meant "native" size which doesn't exist anymore */
-	if (icon_size == GTK_ICON_SIZE_INVALID)
-	{
-		icon_size = GTK_ICON_SIZE_DIALOG;
-	}
-
-	data = g_hash_table_lookup (priv->hash, screen);
-	if (data == NULL)
-	{
-		data = browser_spinner_cache_data_new (screen);
-		/* FIXME: think about what happens when the screen's display is closed later on */
-		g_hash_table_insert (priv->hash, screen, data);
-	}
-
-	images = data->images[icon_size];
-	if (images == BROWSER_SPINNER_IMAGES_INVALID)
-	{
-		/* Load failed, but don't try endlessly again! */
-		return NULL;
-	}
-
-	if (images != NULL)
-	{
-		/* Return cached data */
-		return browser_spinner_images_ref (images);
-	}
-
-	images = browser_spinner_images_load (screen, data->icon_theme, icon_size);
-
-	if (images == NULL)
-	{
-		/* Mark as failed-to-load */
-		data->images[icon_size] = BROWSER_SPINNER_IMAGES_INVALID;
-
-		return NULL;
-	}
-
-	data->images[icon_size] = images;
-
-	return browser_spinner_images_ref (images);
-}
-
-static void
-browser_spinner_cache_init (BrowserSpinnerCache *cache)
-{
-	BrowserSpinnerCachePrivate *priv;
-
-	priv = cache->priv = BROWSER_SPINNER_CACHE_GET_PRIVATE (cache);
-
-	priv->hash = g_hash_table_new_full (g_direct_hash, g_direct_equal,
-					    NULL,
-					    (GDestroyNotify) browser_spinner_cache_data_free);
-}
-
-static void
-browser_spinner_cache_finalize (GObject *object)
-{
-	BrowserSpinnerCache *cache = BROWSER_SPINNER_CACHE (object); 
-	BrowserSpinnerCachePrivate *priv = cache->priv;
-
-	g_hash_table_destroy (priv->hash);
-
-	G_OBJECT_CLASS (browser_spinner_cache_parent_class)->finalize (object);
-}
-
-static void
-browser_spinner_cache_class_init (BrowserSpinnerCacheClass *klass)
-{
-	GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
-	browser_spinner_cache_parent_class = g_type_class_peek_parent (klass);
-
-	object_class->finalize = browser_spinner_cache_finalize;
-
-	g_type_class_add_private (object_class, sizeof (BrowserSpinnerCachePrivate));
-}
-
-static BrowserSpinnerCache *spinner_cache = NULL;
-
-static BrowserSpinnerCache *
-browser_spinner_cache_ref (void)
-{
-	if (spinner_cache == NULL)
-	{
-		BrowserSpinnerCache **cache_ptr;
-
-		spinner_cache = g_object_new (BROWSER_TYPE_SPINNER_CACHE, NULL);
-		cache_ptr = &spinner_cache;
-		g_object_add_weak_pointer (G_OBJECT (spinner_cache),
-					   (gpointer *) cache_ptr);
-
-		return spinner_cache;
-	}
-		
-	return g_object_ref (spinner_cache);
-}
-
-/* Spinner implementation */
-
-#define SPINNER_TIMEOUT 125 /* ms */
-
-#define BROWSER_SPINNER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), BROWSER_TYPE_SPINNER, BrowserSpinnerPriv))
-
-struct _BrowserSpinnerPriv
-{
-	GtkIconTheme *icon_theme;
-	BrowserSpinnerCache *cache;
-	GtkIconSize size;
-	BrowserSpinnerImages *images;
-	guint current_image;
-	guint timeout;
-	guint timer_task;
-	guint spinning : 1;
-	guint need_load : 1;
-};
-
-static void browser_spinner_class_init (BrowserSpinnerClass *class);
-static void browser_spinner_init	    (BrowserSpinner *spinner);
-
-static GObjectClass *parent_class;
-
-GType
-browser_spinner_get_type (void)
-{
-	static GType type = 0;
-
-	if (G_UNLIKELY (type == 0))
-	{
-		const GTypeInfo our_info =
-		{
-			sizeof (BrowserSpinnerClass),
-			NULL, /* base_init */
-			NULL, /* base_finalize */
-			(GClassInitFunc) browser_spinner_class_init,
-			NULL,
-			NULL, /* class_data */
-			sizeof (BrowserSpinner),
-			0, /* n_preallocs */
-			(GInstanceInitFunc) browser_spinner_init
-		};
-
-		type = g_type_register_static (GTK_TYPE_WIDGET,
-					       "BrowserSpinner",
-					       &our_info, 0);
-	}
-
-	return type;
-}
-
-static gboolean
-browser_spinner_load_images (BrowserSpinner *spinner)
-{
-	BrowserSpinnerPriv *priv = spinner->priv;
-
-	if (priv->need_load)
-	{
-		priv->images =
-			browser_spinner_cache_get_images
-				(priv->cache,
-				 gtk_widget_get_screen (GTK_WIDGET (spinner)),
-				 priv->size);
-
-		priv->current_image = 0; /* 'rest' icon */
-		priv->need_load = FALSE;
-	}
-
-	return priv->images != NULL;
-}
-
-static void
-browser_spinner_unload_images (BrowserSpinner *spinner)
-{
-	BrowserSpinnerPriv *priv = spinner->priv;
-
-	if (priv->images != NULL)
-	{
-		browser_spinner_images_unref (priv->images);
-		priv->images = NULL;
-	}
-
-	priv->current_image = 0;
-	priv->need_load = TRUE;
-}
-
-static void
-icon_theme_changed_cb (GtkIconTheme *icon_theme,
-		       BrowserSpinner *spinner)
-{
-	browser_spinner_unload_images (spinner);
-	gtk_widget_queue_resize (GTK_WIDGET (spinner));
-}
-
-static void
-browser_spinner_init (BrowserSpinner *spinner)
-{
-	BrowserSpinnerPriv *priv;
-
-	priv = spinner->priv = BROWSER_SPINNER_GET_PRIVATE (spinner);
-
-#if GTK_CHECK_VERSION(2,18,0)
-	gtk_widget_set_has_window (GTK_WIDGET (spinner), FALSE);
-#else
-	GTK_WIDGET_SET_FLAGS (GTK_WIDGET (spinner), GTK_NO_WINDOW);
-#endif
-
-	priv->cache = browser_spinner_cache_ref ();
-	priv->size = GTK_ICON_SIZE_DIALOG;
-	priv->spinning = FALSE;
-	priv->timeout = SPINNER_TIMEOUT;
-	priv->need_load = TRUE;
-}
-
-static int
-browser_spinner_expose (GtkWidget *widget, GdkEventExpose *event)
-{
-	BrowserSpinner *spinner = BROWSER_SPINNER (widget);
-	BrowserSpinnerPriv *priv = spinner->priv;
-	BrowserSpinnerImages *images;
-	GdkPixbuf *pixbuf;
-	GdkGC *gc;
-	int x_offset, y_offset, width, height;
-	GdkRectangle pix_area, dest;
-	gboolean drawable;
-
-#if GTK_CHECK_VERSION(2,18,0)
-	drawable = gtk_widget_is_drawable (widget);
-#else
-	drawable = GTK_WIDGET_DRAWABLE (widget);
-#endif
-	if (!drawable)
-		return FALSE;
-
-	if (priv->need_load && !browser_spinner_load_images (spinner))
-		return FALSE;
-
-	images = priv->images;
-	if (!images)
-		return FALSE;
-
-	/* Otherwise |images| will be NULL anyway */
-	g_assert (images->n_animation_pixbufs > 0);
-		
-	g_assert (priv->current_image >= 0 &&
-		  priv->current_image < images->n_animation_pixbufs);
-
-	pixbuf = images->animation_pixbufs[priv->current_image];
-
-	g_assert (pixbuf != NULL);
-
-	width = gdk_pixbuf_get_width (pixbuf);
-	height = gdk_pixbuf_get_height (pixbuf);
-
-	/* Compute the offsets for the image centered on our allocation */
-	GtkAllocation alloc;
-#if GTK_CHECK_VERSION(2,18,0)
-	gtk_widget_get_allocation (widget, &alloc);
-#else
-	alloc = widget->allocation;
-#endif
-	x_offset = (alloc.width - width) / 2;
-	y_offset = (alloc.height - height) / 2;
-	pix_area.x = x_offset + alloc.x;
-	pix_area.y = y_offset + alloc.y;
-
-	pix_area.width = width;
-	pix_area.height = height;
-
-	if (!gdk_rectangle_intersect (&event->area, &pix_area, &dest))
-		return FALSE;
-
-	GdkWindow *win;
-#if GTK_CHECK_VERSION(2,18,0)
-	win = gtk_widget_get_window (widget);
-#else
-	win = widget->window;
-#endif
-	gc = gdk_gc_new (win);
-	gdk_draw_pixbuf (win, gc, pixbuf,
-			 dest.x - x_offset - alloc.x,
-			 dest.y - y_offset - alloc.y,
-			 dest.x, dest.y,
-			 dest.width, dest.height,
-			 GDK_RGB_DITHER_MAX, 0, 0);
-	g_object_unref (gc);
-
-	return FALSE;
-}
-
-static gboolean
-bump_spinner_frame_cb (BrowserSpinner *spinner)
-{
-	BrowserSpinnerPriv *priv = spinner->priv;
-
-	/* This can happen when we've unloaded the images on a theme
-	 * change, but haven't been in the queued size request yet.
-	 * Just skip this update.
-	 */
-	if (priv->images == NULL) return TRUE;
-
-	priv->current_image++;
-	if (priv->current_image >= priv->images->n_animation_pixbufs)
-	{
-		/* the 0th frame is the 'rest' icon */
-		priv->current_image = MIN (1, priv->images->n_animation_pixbufs);
-	}
-
-	gtk_widget_queue_draw (GTK_WIDGET (spinner));
-
-	/* run again */
-	return TRUE;
-}
-
-/**
- * browser_spinner_start:
- * @spinner: a #BrowserSpinner
- *
- * Start the spinner animation.
- **/
-void
-browser_spinner_start (BrowserSpinner *spinner)
-{
-	BrowserSpinnerPriv *priv = spinner->priv;
-
-	priv->spinning = TRUE;
-
-#if GTK_CHECK_VERSION (2,19,5)
-	if (gtk_widget_get_mapped (GTK_WIDGET (spinner)) &&
-#else
-	if (GTK_WIDGET_MAPPED (GTK_WIDGET (spinner)) &&
-#endif
-	    priv->timer_task == 0 &&
-	    browser_spinner_load_images (spinner)) {
-		/* the 0th frame is the 'rest' icon */
-		priv->current_image = MIN (1, priv->images->n_animation_pixbufs);
-
-		priv->timer_task =
-			g_timeout_add_full (G_PRIORITY_LOW,
-			                    priv->timeout,
-				            (GSourceFunc) bump_spinner_frame_cb,
-				            spinner,
-				            NULL);
-	}
-}
-
-static void
-browser_spinner_remove_update_callback (BrowserSpinner *spinner)
-{
-	BrowserSpinnerPriv *priv = spinner->priv;
-
-	if (priv->timer_task != 0) {
-		g_source_remove (priv->timer_task);
-		priv->timer_task = 0;
-	}
-}
-
-/**
- * browser_spinner_stop:
- * @spinner: a #BrowserSpinner
- *
- * Stop the spinner animation.
- **/
-void
-browser_spinner_stop (BrowserSpinner *spinner)
-{
-	BrowserSpinnerPriv *priv = spinner->priv;
-
-	priv->spinning = FALSE;
-	priv->current_image = 0;
-
-	if (priv->timer_task != 0) {
-		browser_spinner_remove_update_callback (spinner);
-
-#if GTK_CHECK_VERSION (2,19,4)
-		if (gtk_widget_get_mapped (GTK_WIDGET (spinner)))
-#else
-		if (GTK_WIDGET_MAPPED (GTK_WIDGET (spinner)))
-#endif
-			gtk_widget_queue_draw (GTK_WIDGET (spinner));
-	}
-}
-
-/*
- * browser_spinner_set_size:
- * @spinner: a #BrowserSpinner
- * @size: the size of type %GtkIconSize
- *
- * Set the size of the spinner.
- **/
-void
-browser_spinner_set_size (BrowserSpinner *spinner,
-			  GtkIconSize size)
-{
-	if (size == GTK_ICON_SIZE_INVALID)
-	{
-		size = GTK_ICON_SIZE_DIALOG;
-	}
-
-	if (size != spinner->priv->size)
-	{
-		browser_spinner_unload_images (spinner);
-
-		spinner->priv->size = size;
-
-		gtk_widget_queue_resize (GTK_WIDGET (spinner));
-	}
-}
-
-static void
-browser_spinner_size_request (GtkWidget *widget,
-			   GtkRequisition *requisition)
-{
-	BrowserSpinner *spinner = BROWSER_SPINNER (widget);
-	BrowserSpinnerPriv *priv = spinner->priv;
-
-	if ((priv->need_load &&
-	     !browser_spinner_load_images (spinner)) ||
-            priv->images == NULL)
-	{
-		requisition->width = requisition->height = 0;
-		gtk_icon_size_lookup_for_settings (gtk_widget_get_settings (widget),
-						   priv->size,
-						   &requisition->width,
-					           &requisition->height);
-		return;
-	}
-
-	requisition->width = priv->images->width;
-	requisition->height = priv->images->height;
-
-	/* FIXME fix this hack */
-	/* allocate some extra margin so we don't butt up against toolbar edges */
-	if (priv->size != GTK_ICON_SIZE_MENU)
-	{
-		requisition->width += 2;
-		requisition->height += 2;
-	}
-}
-
-static void
-browser_spinner_map (GtkWidget *widget)
-{
-	BrowserSpinner *spinner = BROWSER_SPINNER (widget);
-	BrowserSpinnerPriv *priv = spinner->priv;
-
-	GTK_WIDGET_CLASS (parent_class)->map (widget);
-
-	if (priv->spinning)
-		browser_spinner_start (spinner);
-}
-
-static void
-browser_spinner_unmap (GtkWidget *widget)
-{
-	BrowserSpinner *spinner = BROWSER_SPINNER (widget);
-
-	browser_spinner_remove_update_callback (spinner);
-
-	GTK_WIDGET_CLASS (parent_class)->unmap (widget);
-}
-
-static void
-browser_spinner_dispose (GObject *object)
-{
-	BrowserSpinner *spinner = BROWSER_SPINNER (object);
-
-	g_signal_handlers_disconnect_by_func
-			(spinner->priv->icon_theme,
-		 G_CALLBACK (icon_theme_changed_cb), spinner);
-
-	G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
-static void
-browser_spinner_finalize (GObject *object)
-{
-	BrowserSpinner *spinner = BROWSER_SPINNER (object);
-
-	browser_spinner_remove_update_callback (spinner);
-	browser_spinner_unload_images (spinner);
-
-	g_object_unref (spinner->priv->cache);
-
-	G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static void
-browser_spinner_screen_changed (GtkWidget *widget,
-			     GdkScreen *old_screen)
-{
-	BrowserSpinner *spinner = BROWSER_SPINNER (widget);
-	BrowserSpinnerPriv *priv = spinner->priv;
-	GdkScreen *screen;
-
-	if (GTK_WIDGET_CLASS (parent_class)->screen_changed)
-	{
-		GTK_WIDGET_CLASS (parent_class)->screen_changed (widget, old_screen);
-	}
-
-	screen = gtk_widget_get_screen (widget);
-
-	/* FIXME: this seems to be happening when then spinner is destroyed!? */
-	if (old_screen == screen) return;
-
-	/* We'll get mapped again on the new screen, but not unmapped from
-	 * the old screen, so remove timeout here.
-	 */
-	browser_spinner_remove_update_callback (spinner);
-
-	browser_spinner_unload_images (spinner);
-
-	if (old_screen != NULL)
-	{
-		g_signal_handlers_disconnect_by_func
-			(gtk_icon_theme_get_for_screen (old_screen),
-			 G_CALLBACK (icon_theme_changed_cb), spinner);
-	}
-
-	priv->icon_theme = gtk_icon_theme_get_for_screen (screen);
-	g_signal_connect (priv->icon_theme, "changed",
-			  G_CALLBACK (icon_theme_changed_cb), spinner);
-}
-
-static void
-browser_spinner_class_init (BrowserSpinnerClass *class)
-{
-	GObjectClass *object_class =  G_OBJECT_CLASS (class);
-	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
-
-	parent_class = g_type_class_peek_parent (class);
-
-	object_class->dispose = browser_spinner_dispose;
-	object_class->finalize = browser_spinner_finalize;
-
-	widget_class->expose_event = browser_spinner_expose;
-	widget_class->size_request = browser_spinner_size_request;
-	widget_class->map = browser_spinner_map;
-	widget_class->unmap = browser_spinner_unmap;
-	widget_class->screen_changed = browser_spinner_screen_changed;
-
-	g_type_class_add_private (object_class, sizeof (BrowserSpinnerPriv));
-}
-
-/*
- * browser_spinner_new:
- *
- * Create a new #BrowserSpinner. The spinner is a widget
- * that gives the user feedback about network status with
- * an animated image.
- *
- * Return Value: the spinner #GtkWidget
- **/
-GtkWidget *
-browser_spinner_new (void)
-{
-	return GTK_WIDGET (g_object_new (BROWSER_TYPE_SPINNER, NULL));
-}
-
-#endif /* GTK_CHECK_VERSION */
diff --git a/tools/browser/browser-spinner.h b/tools/browser/browser-spinner.h
index 6019bac..f7ebfbd 100644
--- a/tools/browser/browser-spinner.h
+++ b/tools/browser/browser-spinner.h
@@ -1,74 +1,30 @@
-/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
 /*
- * Copyright © 2000 Eazel, Inc.
- * Copyright © 2004, 2006 Christian Persch
+ * Copyright (C) 2009 - 2010 Vivien Malerba
  *
- * Nautilus is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
  *
- * Nautilus is distributed in the hope that it will be useful,
+ * This Library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * Author: Andy Hertzfeld <andy eazel com>
- *
- * $Id$
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
  */
 
 #ifndef BROWSER_SPINNER_H
 #define BROWSER_SPINNER_H
 
-#if GTK_CHECK_VERSION(2,20,0)
 #define BROWSER_SPINNER(x) GTK_SPINNER(x)
 #define BrowserSpinner GtkSpinner
 #define browser_spinner_new() gtk_spinner_new()
-void		browser_spinner_start	 (BrowserSpinner *throbber);
-void		browser_spinner_stop	 (BrowserSpinner *throbber);
-void            browser_spinner_set_size (BrowserSpinner *spinner, GtkIconSize size);
-#else
-#include <gtk/gtk.h>
-
-G_BEGIN_DECLS
-
-#define BROWSER_TYPE_SPINNER		(browser_spinner_get_type ())
-#define BROWSER_SPINNER(o)			(G_TYPE_CHECK_INSTANCE_CAST ((o), BROWSER_TYPE_SPINNER, BrowserSpinner))
-#define BROWSER_SPINNER_CLASS(k)		(G_TYPE_CHECK_CLASS_CAST((k), BROWSER_TYPE_SPINNER, BrowserSpinnerClass))
-#define BROWSER_IS_SPINNER(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), BROWSER_TYPE_SPINNER))
-#define BROWSER_IS_SPINNER_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), BROWSER_TYPE_SPINNER))
-#define BROWSER_SPINNER_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), BROWSER_TYPE_SPINNER, BrowserSpinnerClass))
-
-typedef struct _BrowserSpinner		BrowserSpinner;
-typedef struct _BrowserSpinnerClass	BrowserSpinnerClass;
-typedef struct _BrowserSpinnerPriv	BrowserSpinnerPriv;
-
-struct _BrowserSpinner
-{
-	GtkWidget parent;
-
-	/*< private >*/
-	BrowserSpinnerPriv *priv;
-};
-
-struct _BrowserSpinnerClass
-{
-	GtkWidgetClass parent_class;
-};
-
-GType		browser_spinner_get_type (void);
-GtkWidget      *browser_spinner_new	 (void);
-void		browser_spinner_start	 (BrowserSpinner *throbber);
-void		browser_spinner_stop	 (BrowserSpinner *throbber);
-void		browser_spinner_set_size (BrowserSpinner *spinner,
-					  GtkIconSize size);
-
-G_END_DECLS
-#endif /* GTK_CHECK_VERSION */
+void	browser_spinner_start	 (BrowserSpinner *throbber);
+void	browser_spinner_stop	 (BrowserSpinner *throbber);
+void    browser_spinner_set_size (BrowserSpinner *spinner, GtkIconSize size);
 
 #endif /* BROWSER_SPINNER_H */
diff --git a/tools/browser/browser-variable.c b/tools/browser/browser-variable.c
index cbfff79..0bd79e4 100644
--- a/tools/browser/browser-variable.c
+++ b/tools/browser/browser-variable.c
@@ -1,8 +1,8 @@
 /*
  * Copyright (C) 2009 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/browser-variable.h b/tools/browser/browser-variable.h
index d01bb32..e295174 100644
--- a/tools/browser/browser-variable.h
+++ b/tools/browser/browser-variable.h
@@ -1,8 +1,8 @@
 /* 
  * Copyright (C) 2009 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/browser-virtual-connection.c b/tools/browser/browser-virtual-connection.c
index 23abf59..4530b40 100644
--- a/tools/browser/browser-virtual-connection.c
+++ b/tools/browser/browser-virtual-connection.c
@@ -1,8 +1,8 @@
 /*
  * Copyright (C) 2009 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/browser-virtual-connection.h b/tools/browser/browser-virtual-connection.h
index a58c37d..bcb47a8 100644
--- a/tools/browser/browser-virtual-connection.h
+++ b/tools/browser/browser-virtual-connection.h
@@ -1,8 +1,8 @@
 /* 
  * Copyright (C) 2009 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/browser-window.c b/tools/browser/browser-window.c
index 346e6a7..34ff165 100644
--- a/tools/browser/browser-window.c
+++ b/tools/browser/browser-window.c
@@ -1,8 +1,8 @@
 /*
  * Copyright (C) 2009 - 2011 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -102,10 +102,8 @@ struct _BrowserWindowPrivate {
 	gulong             cnc_added_sigid;
 	gulong             cnc_removed_sigid;
 
-#if GTK_CHECK_VERSION (2,18,0)
 	GtkWidget         *notif_box;
 	GSList            *notif_widgets;
-#endif
 
 	GtkWidget         *statusbar;
 	guint              cnc_statusbar_context;
@@ -227,10 +225,8 @@ browser_window_dispose (GObject *object)
 		if (bwin->priv->perspectives_nb)
 			g_object_unref (bwin->priv->perspectives_nb);
 
-#if GTK_CHECK_VERSION (2,18,0)
 		if (bwin->priv->notif_widgets)
 			g_slist_free (bwin->priv->notif_widgets);
-#endif
 		g_free (bwin->priv);
 		bwin->priv = NULL;
 	}
@@ -453,12 +449,10 @@ browser_window_new (BrowserConnection *bcnc, BrowserPerspectiveFactory *factory)
         gtk_widget_show (toolbar);
 	bwin->priv->toolbar_style = gtk_toolbar_get_style (GTK_TOOLBAR (toolbar));
 
-#if GTK_CHECK_VERSION (2,18,0)
 	bwin->priv->notif_box = gtk_vbox_new (FALSE, 0);
 	gtk_box_pack_start (GTK_BOX (vbox), bwin->priv->notif_box, FALSE, FALSE, 0);
         gtk_widget_show (bwin->priv->notif_box);
 	bwin->priv->notif_widgets = NULL;
-#endif
 
 	GtkToolItem *ti;
 	GtkWidget *spinner, *svbox, *align;
@@ -592,16 +586,7 @@ browser_window_new (BrowserConnection *bcnc, BrowserPerspectiveFactory *factory)
 
         gtk_widget_show (GTK_WIDGET (bwin));
 
-#if GTK_CHECK_VERSION(2,18,0)
 	gtk_widget_set_can_focus ((GtkWidget* )pers->perspective_widget, TRUE);
-#else
-	GtkWidget *fwid = (GtkWidget* )pers->perspective_widget;
-	if (! GTK_WIDGET_CAN_FOCUS (fwid)) {
-		GTK_WIDGET_SET_FLAGS (fwid, GTK_CAN_FOCUS);
-		gtk_widget_queue_resize (fwid);
-		g_object_notify (G_OBJECT (fwid), "can-focus");
-	}
-#endif
 	gtk_widget_grab_focus ((GtkWidget* )pers->perspective_widget);
 
 	return bwin;
@@ -958,13 +943,8 @@ static gboolean
 fullscreen_motion_notify_cb (GtkWidget *widget, GdkEventMotion *event, G_GNUC_UNUSED gpointer user_data)
 {
 	BrowserWindow *bwin = BROWSER_WINDOW (widget);
-#if GTK_CHECK_VERSION(2,14,0)
 	if (gtk_widget_get_window (widget) != event->window)
 		return FALSE;
-#else
-	if (widget->window != event->window)
-		return FALSE;
-#endif
 
 	if (event->y < BWIN_WINDOW_FULLSCREEN_POPUP_THRESHOLD) {
 		gtk_widget_show (bwin->priv->toolbar);
@@ -1048,7 +1028,7 @@ window_fullscreen_cb (GtkToggleAction *action, BrowserWindow *bwin)
 static gboolean
 key_press_event (GtkWidget *widget, GdkEventKey *event)
 {
-	if ((event->keyval == GDK_Escape) &&
+	if ((event->keyval == GDK_KEY_Escape) &&
 	    browser_window_is_fullscreen (BROWSER_WINDOW (widget))) {
 		browser_window_set_fullscreen (BROWSER_WINDOW (widget), FALSE);
 		return TRUE;
@@ -1094,7 +1074,6 @@ window_state_event (GtkWidget *widget, GdkEventWindowState *event)
 		else
 			gtk_widget_show (wid);
 		
-		gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (bwin->priv->statusbar), !fullscreen);
 		g_signal_emit (G_OBJECT (bwin), browser_window_signals[FULLSCREEN_CHANGED], 0, fullscreen);
         }
 	return FALSE;
@@ -1411,14 +1390,12 @@ browser_window_show_notice_printf (BrowserWindow *bwin, GtkMessageType type, con
 }
 
 
-#if GTK_CHECK_VERSION (2,18,0)
 static void
 info_bar_response_cb (GtkInfoBar *ibar, G_GNUC_UNUSED gint response, BrowserWindow *bwin)
 {
 	bwin->priv->notif_widgets = g_slist_remove (bwin->priv->notif_widgets, ibar);	
 	gtk_widget_destroy ((GtkWidget*) ibar);
 }
-#endif
 
 /* hash table to remain which context notices have to be hidden: key=context, value=GINT_TO_POINTER (1) */
 static GHashTable *hidden_contexts = NULL;
@@ -1556,7 +1533,6 @@ browser_window_show_notice (BrowserWindow *bwin, GtkMessageType type, const gcha
 					       (GClosureNotify) g_free, 0);
 		}
 
-#if GTK_CHECK_VERSION (2,18,0)
 		/* use a GtkInfoBar */
 		GtkWidget *ibar, *content_area, *label;
 		
@@ -1589,21 +1565,6 @@ browser_window_show_notice (BrowserWindow *bwin, GtkMessageType type, const gcha
 									 bwin->priv->notif_widgets);
 		}
 		gtk_widget_show (ibar);
-#else
-		/* create the error message dialog */
-		GtkWidget *dialog;
-		dialog = gtk_message_dialog_new_with_markup (GTK_WINDOW (bwin),
-							     GTK_DIALOG_DESTROY_WITH_PARENT |
-							     GTK_DIALOG_MODAL, GTK_MESSAGE_INFO,
-							     GTK_BUTTONS_CLOSE,
-							     "<span weight=\"bold\">%s</span>\n%s", _("Note:"), text);
-		if (cb)
-			gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), cb, FALSE, FALSE, 10);
-	
-		gtk_widget_show_all (dialog);
-		gtk_dialog_run (GTK_DIALOG (dialog));
-		gtk_widget_destroy (dialog);
-#endif
 	}
 }
 
diff --git a/tools/browser/browser-window.h b/tools/browser/browser-window.h
index 4797953..ff83f54 100644
--- a/tools/browser/browser-window.h
+++ b/tools/browser/browser-window.h
@@ -1,8 +1,8 @@
 /* 
- * Copyright (C) 2009 Vivien Malerba
+ * Copyright (C) 2009 - 2011 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -51,6 +51,17 @@ struct _BrowserWindowClass
 	void                (*fullscreen_changed) (BrowserWindow *bwin, gboolean fullscreen);
 };
 
+/**
+ * SECTION:browser-window
+ * @short_description: A top level browser window
+ * @title: BrowserWindow
+ * @stability: Stable
+ * @see_also:
+ *
+ * Each top level browser window is represented by a #BrowserWindow object, and uses
+ * a single #BrowserConnection connection object.
+ */
+
 GType               browser_window_get_type               (void) G_GNUC_CONST;
 BrowserWindow      *browser_window_new                    (BrowserConnection *bcnc, BrowserPerspectiveFactory *factory);
 BrowserConnection  *browser_window_get_connection         (BrowserWindow *bwin);
diff --git a/tools/browser/canvas-example.c b/tools/browser/canvas-example.c
index d60bdd0..5fc24bf 100644
--- a/tools/browser/canvas-example.c
+++ b/tools/browser/canvas-example.c
@@ -133,20 +133,12 @@ label_drag_data_received (G_GNUC_UNUSED GtkWidget *label, GdkDragContext *contex
 			  G_GNUC_UNUSED gint x, G_GNUC_UNUSED gint y, GtkSelectionData *data,
 			  G_GNUC_UNUSED guint info, guint time)
 {
-#if GTK_CHECK_VERSION(2,18,0)
 	if ((gtk_selection_data_get_length (data) >= 0) && (gtk_selection_data_get_format (data) == 8)) {
 		g_print ("Received \"%s\" in drop zone\n",
 			 (gchar *) gtk_selection_data_get_data (data));
 		gtk_drag_finish (context, TRUE, FALSE, time);
 		return;
 	}
-#else
-	if ((data->length >= 0) && (data->format == 8)) {
-		g_print ("Received \"%s\" in drop zone\n", (gchar *)data->data);
-		gtk_drag_finish (context, TRUE, FALSE, time);
-		return;
-	}
-#endif
 
 	gtk_drag_finish (context, FALSE, FALSE, time);
 }
diff --git a/tools/browser/canvas/Makefile.am b/tools/browser/canvas/Makefile.am
index 3eabadc..aab686c 100644
--- a/tools/browser/canvas/Makefile.am
+++ b/tools/browser/canvas/Makefile.am
@@ -35,7 +35,7 @@ libcanvas_la_SOURCES = \
 	browser-canvas-utility.h
 
 libcanvas_la_LIBADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS) \
 	$(GTK_LIBS) \
 	$(GOOCANVAS_LIBS) \
diff --git a/tools/browser/canvas/browser-canvas-column.c b/tools/browser/canvas/browser-canvas-column.c
index c2dd73b..b02f1f7 100644
--- a/tools/browser/canvas/browser-canvas-column.c
+++ b/tools/browser/canvas/browser-canvas-column.c
@@ -1,18 +1,18 @@
 /* browser-canvas-column.c
  *
- * Copyright (C) 2002 - 2008 Vivien Malerba
+ * Copyright (C) 2002 - 2010 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
+ * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public License
+ * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  * USA
@@ -328,10 +328,6 @@ browser_canvas_column_drag_data_get (BrowserCanvasItem *citem, G_GNUC_UNUSED Gdk
 	g_free (tmp2);
 	g_free (tmp3);
 	g_free (tmp4);
-#if GTK_CHECK_VERSION(2,18,0)
 	gtk_selection_data_set (data, gtk_selection_data_get_target (data), 8, (guchar*) str, strlen (str));
-#else
-	gtk_selection_data_set (data, data->target, 8, (guchar*) str, strlen (str));
-#endif
 	g_free (str);
 }
diff --git a/tools/browser/canvas/browser-canvas-column.h b/tools/browser/canvas/browser-canvas-column.h
index 0845924..39e4c45 100644
--- a/tools/browser/canvas/browser-canvas-column.h
+++ b/tools/browser/canvas/browser-canvas-column.h
@@ -2,17 +2,17 @@
  *
  * Copyright (C) 2004 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
+ * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public License
+ * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  * USA
diff --git a/tools/browser/canvas/browser-canvas-db-relations.c b/tools/browser/canvas/browser-canvas-db-relations.c
index f5d21a4..f02519d 100644
--- a/tools/browser/canvas/browser-canvas-db-relations.c
+++ b/tools/browser/canvas/browser-canvas-db-relations.c
@@ -4,16 +4,16 @@
  * Copyright (C) 2002 Fernando Martins
  *
  * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
+ * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public License
+ * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  * USA
@@ -829,7 +829,7 @@ popup_add_table_cb (G_GNUC_UNUSED GtkMenuItem *mitem, BrowserCanvasDbRelations *
 		GtkWidget *vbox, *cloud, *find, *dcontents;
 		dbrels->priv->add_dialog = gtk_dialog_new_with_buttons (_("Select tables to add to diagram"),
 									(GtkWindow*) gtk_widget_get_toplevel ((GtkWidget*) dbrels),
-									GTK_DIALOG_NO_SEPARATOR,
+									0,
 									NULL);
 		g_signal_connect (dbrels->priv->add_dialog, "close",
 				  G_CALLBACK (gtk_widget_hide), NULL);
@@ -840,11 +840,7 @@ popup_add_table_cb (G_GNUC_UNUSED GtkMenuItem *mitem, BrowserCanvasDbRelations *
 		g_object_set_data (G_OBJECT (dbrels->priv->add_dialog), "__canvas", dbrels);
 
 		vbox = gtk_vbox_new (FALSE, 0);
-#if GTK_CHECK_VERSION(2,18,0)
 		dcontents = gtk_dialog_get_content_area (GTK_DIALOG (dbrels->priv->add_dialog));
-#else
-		dcontents = GTK_DIALOG (dbrels->priv->add_dialog)->vbox;
-#endif
 		gtk_container_add (GTK_CONTAINER (dcontents), vbox);
 		
 		cloud = objects_cloud_new (dbrels->priv->mstruct, OBJECTS_CLOUD_TYPE_TABLE);
diff --git a/tools/browser/canvas/browser-canvas-db-relations.h b/tools/browser/canvas/browser-canvas-db-relations.h
index 0ade836..91ff081 100644
--- a/tools/browser/canvas/browser-canvas-db-relations.h
+++ b/tools/browser/canvas/browser-canvas-db-relations.h
@@ -2,17 +2,17 @@
  *
  * Copyright (C) 2004 - 2009 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
+ * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public License
+ * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  * USA
diff --git a/tools/browser/canvas/browser-canvas-decl.h b/tools/browser/canvas/browser-canvas-decl.h
index 9b506d8..ea1f9e1 100644
--- a/tools/browser/canvas/browser-canvas-decl.h
+++ b/tools/browser/canvas/browser-canvas-decl.h
@@ -2,17 +2,17 @@
  *
  * Copyright (C) 2009 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
+ * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public License
+ * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  * USA
diff --git a/tools/browser/canvas/browser-canvas-fkey.c b/tools/browser/canvas/browser-canvas-fkey.c
index 21c6688..a22c37b 100644
--- a/tools/browser/canvas/browser-canvas-fkey.c
+++ b/tools/browser/canvas/browser-canvas-fkey.c
@@ -2,17 +2,17 @@
  *
  * Copyright (C) 2004 - 2011 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
+ * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public License
+ * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  * USA
diff --git a/tools/browser/canvas/browser-canvas-fkey.h b/tools/browser/canvas/browser-canvas-fkey.h
index d0cc99a..bbab0ca 100644
--- a/tools/browser/canvas/browser-canvas-fkey.h
+++ b/tools/browser/canvas/browser-canvas-fkey.h
@@ -2,17 +2,17 @@
  *
  * Copyright (C) 2005 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
+ * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public License
+ * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  * USA
diff --git a/tools/browser/canvas/browser-canvas-item.c b/tools/browser/canvas/browser-canvas-item.c
index 04d0cb6..e3ca4f2 100644
--- a/tools/browser/canvas/browser-canvas-item.c
+++ b/tools/browser/canvas/browser-canvas-item.c
@@ -2,17 +2,17 @@
  *
  * Copyright (C) 2007 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
+ * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public License
+ * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  * USA
diff --git a/tools/browser/canvas/browser-canvas-item.h b/tools/browser/canvas/browser-canvas-item.h
index 58555e5..1d6871e 100644
--- a/tools/browser/canvas/browser-canvas-item.h
+++ b/tools/browser/canvas/browser-canvas-item.h
@@ -2,17 +2,17 @@
  *
  * Copyright (C) 2007 - 2008 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
+ * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public License
+ * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  * USA
diff --git a/tools/browser/canvas/browser-canvas-print.c b/tools/browser/canvas/browser-canvas-print.c
index 13e5ad7..78e04a6 100644
--- a/tools/browser/canvas/browser-canvas-print.c
+++ b/tools/browser/canvas/browser-canvas-print.c
@@ -2,17 +2,17 @@
  *
  * Copyright (C) 2007 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
+ * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public License
+ * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  * USA
diff --git a/tools/browser/canvas/browser-canvas-priv.h b/tools/browser/canvas/browser-canvas-priv.h
index ecaf2a3..93b1ff2 100644
--- a/tools/browser/canvas/browser-canvas-priv.h
+++ b/tools/browser/canvas/browser-canvas-priv.h
@@ -2,17 +2,17 @@
  *
  * Copyright (C) 2009 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
+ * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public License
+ * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  * USA
diff --git a/tools/browser/canvas/browser-canvas-table.c b/tools/browser/canvas/browser-canvas-table.c
index 529ad5d..fb05b30 100644
--- a/tools/browser/canvas/browser-canvas-table.c
+++ b/tools/browser/canvas/browser-canvas-table.c
@@ -1,18 +1,18 @@
 /* browser-canvas-table.c
  *
- * Copyright (C) 2002 - 2007 Vivien Malerba
+ * Copyright (C) 2002 - 2010 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
+ * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public License
+ * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  * USA
@@ -318,7 +318,7 @@ create_items (BrowserCanvasTable *ce)
 	y = RADIUS_Y;
         title = goo_canvas_text_new  (GOO_CANVAS_ITEM (ce), tmpstr,
 				      RADIUS_X + X_PAD, y, 
-				      -1, GTK_ANCHOR_NORTH_WEST,
+				      -1, GOO_CANVAS_ANCHOR_NORTH_WEST,
 				      "font", "Sans 11",
 				      "use-markup", TRUE, NULL);
 
@@ -544,11 +544,7 @@ browser_canvas_table_drag_data_get (BrowserCanvasItem *citem, G_GNUC_UNUSED GdkD
 	g_free (tmp1);
 	g_free (tmp2);
 	g_free (tmp3);
-#if GTK_CHECK_VERSION(2,18,0)
 	gtk_selection_data_set (data, gtk_selection_data_get_target (data), 8, (guchar*) str, strlen (str));
-#else
-	gtk_selection_data_set (data, data->target, 8, (guchar*) str, strlen (str));
-#endif
 	g_free (str);
 }
 
diff --git a/tools/browser/canvas/browser-canvas-table.h b/tools/browser/canvas/browser-canvas-table.h
index 67d663c..7264412 100644
--- a/tools/browser/canvas/browser-canvas-table.h
+++ b/tools/browser/canvas/browser-canvas-table.h
@@ -2,17 +2,17 @@
  *
  * Copyright (C) 2007 - 2008 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
+ * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public License
+ * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  * USA
diff --git a/tools/browser/canvas/browser-canvas-text.c b/tools/browser/canvas/browser-canvas-text.c
index 8bd35dc..a67c8f4 100644
--- a/tools/browser/canvas/browser-canvas-text.c
+++ b/tools/browser/canvas/browser-canvas-text.c
@@ -2,17 +2,17 @@
  *
  * Copyright (C) 2002 - 2007 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
+ * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public License
+ * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  * USA
@@ -346,7 +346,7 @@ create_items (BrowserCanvasText *ct)
 	/* text: text's name */
 	text = goo_canvas_text_new (GOO_CANVAS_ITEM (ct), ct->priv->text,
 				    0., 0.,
-				    -1, GTK_ANCHOR_NORTH_WEST, 
+				    -1, GOO_CANVAS_ANCHOR_NORTH_WEST, 
 				    "fill_color", "black",
 				    "font", BROWSER_CANVAS_FONT,
 				    "alignment", PANGO_ALIGN_RIGHT, 
diff --git a/tools/browser/canvas/browser-canvas-text.h b/tools/browser/canvas/browser-canvas-text.h
index 4beba91..efdbd12 100644
--- a/tools/browser/canvas/browser-canvas-text.h
+++ b/tools/browser/canvas/browser-canvas-text.h
@@ -2,17 +2,17 @@
  *
  * Copyright (C) 2007 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
+ * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public License
+ * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  * USA
diff --git a/tools/browser/canvas/browser-canvas-utility.c b/tools/browser/canvas/browser-canvas-utility.c
index bead0fa..7a5cf8b 100644
--- a/tools/browser/canvas/browser-canvas-utility.c
+++ b/tools/browser/canvas/browser-canvas-utility.c
@@ -26,7 +26,7 @@ static gboolean compute_intersect_rect_line (gdouble rectx1, gdouble recty1, gdo
 					     gdouble *R1x, gdouble *R1y, gdouble *R2x, gdouble *R2y);
 
 static void     compute_text_marks_offsets (gdouble x1, gdouble y1, gdouble x2, gdouble y2,
-					    gdouble *xoff, gdouble *yoff, GtkAnchorType *anchor_type);
+					    gdouble *xoff, gdouble *yoff, GooCanvasAnchorType *anchor_type);
 
 static GSList *browser_canvas_util_compute_handle_shapes  (GooCanvasItem *parent, GSList *shapes, gint index,
 							 gdouble x1, gdouble y1, gdouble x2, gdouble y2);
@@ -172,7 +172,7 @@ browser_canvas_util_compute_anchor_shapes (GooCanvasItem *parent, GSList *shapes
 					item = goo_canvas_text_new (parent, "*", 
 								    points->coords[2] + 5.,
 								    points->coords[3] - 5., -1,
-								    GTK_ANCHOR_SOUTH, NULL);
+								    GOO_CANVAS_ANCHOR_SOUTH, NULL);
 					retval = browser_canvas_canvas_shape_add_to_list (retval, id, item);
 				}
 			}
@@ -190,7 +190,7 @@ browser_canvas_util_compute_anchor_shapes (GooCanvasItem *parent, GSList *shapes
 					item = goo_canvas_text_new (parent, "*", 
 								    points->coords[4] + 5.,
 								    points->coords[5] + 5., -1,
-								    GTK_ANCHOR_NORTH, NULL);
+								    GOO_CANVAS_ANCHOR_NORTH, NULL);
 					retval = browser_canvas_canvas_shape_add_to_list (retval, id, item);
 				}
 			}
@@ -295,7 +295,7 @@ browser_canvas_util_compute_anchor_shapes (GooCanvasItem *parent, GSList *shapes
 			/* extension marks as text */
 			if (ext & CANVAS_SHAPE_EXT_JOIN_OUTER_1) {
 				gdouble mxoff = 0., myoff = 0.;
-				GtkAnchorType atype;
+				GooCanvasAnchorType atype;
 
 				compute_text_marks_offsets (points->coords[0], points->coords[1], 
 							    points->coords[2], points->coords[3],
@@ -321,7 +321,7 @@ browser_canvas_util_compute_anchor_shapes (GooCanvasItem *parent, GSList *shapes
 
 			if (ext & CANVAS_SHAPE_EXT_JOIN_OUTER_2) {
 				gdouble mxoff, myoff;
-				GtkAnchorType atype;
+				GooCanvasAnchorType atype;
 				
 				compute_text_marks_offsets (points->coords[2], points->coords[3], 
 							    points->coords[0], points->coords[1],
@@ -365,10 +365,10 @@ browser_canvas_util_compute_anchor_shapes (GooCanvasItem *parent, GSList *shapes
  */
 static void
 compute_text_marks_offsets (gdouble x1, gdouble y1, gdouble x2, gdouble y2,
-			    gdouble *xoff, gdouble *yoff, GtkAnchorType *anchor_type)
+			    gdouble *xoff, gdouble *yoff, GooCanvasAnchorType *anchor_type)
 {
 	gdouble mxoff, myoff;
-	GtkAnchorType atype = GTK_ANCHOR_CENTER; /* FIXME */
+	GooCanvasAnchorType atype = GOO_CANVAS_ANCHOR_CENTER; /* FIXME */
 	gdouble sint, cost;
 	gdouble sina = 0.5;
 	gdouble cosa = 0.866025; /* sqrt(3)/2 */
@@ -620,7 +620,7 @@ browser_canvas_util_compute_connect_shapes (GooCanvasItem *parent, GSList *shape
 	/* extension marks as text */
 	if (ext & CANVAS_SHAPE_EXT_JOIN_OUTER_1) {
 		gdouble mxoff = 0., myoff = 0.;
-		GtkAnchorType atype;
+		GooCanvasAnchorType atype;
 		
 		compute_text_marks_offsets (points->coords[4], points->coords[5], 
 					    points->coords[2], points->coords[3],
@@ -647,7 +647,7 @@ browser_canvas_util_compute_connect_shapes (GooCanvasItem *parent, GSList *shape
 	
 	if (ext & CANVAS_SHAPE_EXT_JOIN_OUTER_2) {
 		gdouble mxoff, myoff;
-		GtkAnchorType atype;
+		GooCanvasAnchorType atype;
 		
 		compute_text_marks_offsets (points->coords[2], points->coords[3], 
 					    points->coords[4], points->coords[5],
diff --git a/tools/browser/canvas/browser-canvas.c b/tools/browser/canvas/browser-canvas.c
index 5006407..ea92812 100644
--- a/tools/browser/canvas/browser-canvas.c
+++ b/tools/browser/canvas/browser-canvas.c
@@ -1,18 +1,18 @@
 /* browser-canvas.c
  *
- * Copyright (C) 2007 - 2009 Vivien Malerba
+ * Copyright (C) 2007 - 2010 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
+ * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public License
+ * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  * USA
@@ -170,7 +170,7 @@ browser_canvas_init (BrowserCanvas *canvas)
 		      "automatic-bounds", TRUE,
 		      "bounds-padding", 5., 
 		      "bounds-from-origin", FALSE, 
-		      "anchor", GTK_ANCHOR_CENTER, NULL);
+		      "anchor", GOO_CANVAS_ANCHOR_CENTER, NULL);
 
 	/* reseting the zoom */
 	goo_canvas_set_scale (canvas->priv->goocanvas, DEFAULT_SCALE);
@@ -275,29 +275,17 @@ motion_notify_event_cb (BrowserCanvas *canvas, GdkEvent *event, G_GNUC_UNUSED Go
 				ha = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (canvas));
 				va = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (canvas));
 
-#if GTK_CHECK_VERSION(2,18,0)
 				upper = gtk_adjustment_get_upper (ha);
 				lower = gtk_adjustment_get_lower (ha);
 				page_size = gtk_adjustment_get_page_size (ha);
-#else
-				upper = ha->upper;
-				lower = ha->lower;
-				page_size = ha->page_size;
-#endif
 				x = gtk_adjustment_get_value (ha);
 				x = CLAMP (x + canvas->xmouse - ((GdkEventMotion*) event)->x,
 					   lower, upper - page_size);
 				gtk_adjustment_set_value (ha, x);
 
-#if GTK_CHECK_VERSION(2,18,0)
 				upper = gtk_adjustment_get_upper (va);
 				lower = gtk_adjustment_get_lower (va);
 				page_size = gtk_adjustment_get_page_size (va);
-#else
-				upper = va->upper;
-				lower = va->lower;
-				page_size = va->page_size;
-#endif
 				y = gtk_adjustment_get_value (va);
 				y = CLAMP (y + canvas->ymouse - ((GdkEventMotion*) event)->y,
 					   lower, upper - page_size);
@@ -309,13 +297,8 @@ motion_notify_event_cb (BrowserCanvas *canvas, GdkEvent *event, G_GNUC_UNUSED Go
 				canvas->priv->canvas_moving = TRUE;
 				if (! hand_cursor)
 					hand_cursor = gdk_cursor_new (GDK_HAND2);
-#if GTK_CHECK_VERSION(2,18,0)
 				gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (canvas)),
 						       hand_cursor);
-#else
-				gdk_window_set_cursor (GTK_WIDGET (canvas)->window,
-						       hand_cursor);
-#endif
 			}
 		}
 		done = TRUE;
@@ -420,11 +403,7 @@ canvas_event_cb (BrowserCanvas *canvas, GdkEvent *event, GooCanvas *gcanvas)
 	case GDK_BUTTON_RELEASE:
 		if (canvas->priv->canvas_moving) {
 			canvas->priv->canvas_moving = FALSE;
-#if GTK_CHECK_VERSION(2,18,0)
 			gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (canvas)), NULL);
-#else
-			gdk_window_set_cursor (GTK_WIDGET (canvas)->window, NULL);
-#endif
 		}
 		break;
 	case GDK_2BUTTON_PRESS:
@@ -496,13 +475,8 @@ popup_export_cb (G_GNUC_UNUSED GtkMenuItem *mitem, BrowserCanvas *canvas)
 
 #define MARGIN 5.
 
-#if GTK_CHECK_VERSION(2,18,0)
 	if (!gtk_widget_is_toplevel (toplevel))
 		toplevel = NULL;
-#else
-	if (!GTK_WIDGET_TOPLEVEL (toplevel))
-		toplevel = NULL;
-#endif
 
 	dlg = gtk_file_chooser_dialog_new (_("Save diagram as"), (GtkWindow*) toplevel,
 					   GTK_FILE_CHOOSER_ACTION_SAVE, 
@@ -784,15 +758,10 @@ browser_canvas_fit_zoom_factor (BrowserCanvas *canvas)
 	g_return_val_if_fail (IS_BROWSER_CANVAS (canvas), 1.);
 	g_return_val_if_fail (canvas->priv, 1.);
 
-#if GTK_CHECK_VERSION(2,18,0)
 	GtkAllocation alloc;
 	gtk_widget_get_allocation (GTK_WIDGET (canvas), &alloc);
 	xall = alloc.width;
 	yall = alloc.height;
-#else
-	xall = GTK_WIDGET (canvas)->allocation.width;
-	yall = GTK_WIDGET (canvas)->allocation.height;
-#endif
 
 	goo_canvas_item_get_bounds (GOO_CANVAS_ITEM (goo_canvas_get_root_item (canvas->priv->goocanvas)),
 				    &bounds);
diff --git a/tools/browser/canvas/browser-canvas.h b/tools/browser/canvas/browser-canvas.h
index 16ac943..94d3d8f 100644
--- a/tools/browser/canvas/browser-canvas.h
+++ b/tools/browser/canvas/browser-canvas.h
@@ -2,17 +2,17 @@
  *
  * Copyright (C) 2007 - 2008 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
+ * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public License
+ * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  * USA
diff --git a/tools/browser/common/Makefile.am b/tools/browser/common/Makefile.am
index 147883e..641b3ec 100644
--- a/tools/browser/common/Makefile.am
+++ b/tools/browser/common/Makefile.am
@@ -31,11 +31,11 @@ libcommon_la_SOURCES = \
 $(OBJECTS): marshal.c marshal.h
 
 libcommon_la_LIBADD = \
-	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
 	$(LIBGDA_LIBS) \
 	$(GTK_LIBS)
 
-xmldir=$(datadir)/libgda-4.0
+xmldir=$(datadir)/libgda-5.0
 xml_DATA= \
 	import_encodings.xml
 
diff --git a/tools/browser/common/fk-declare.c b/tools/browser/common/fk-declare.c
index 0849efc..2aa79e3 100644
--- a/tools/browser/common/fk-declare.c
+++ b/tools/browser/common/fk-declare.c
@@ -1,8 +1,8 @@
 /* 
  * Copyright (C) 2011 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -177,11 +177,7 @@ create_internal_layout (FkDeclare *decl)
 	gint i, nrows;
 	GSList *list;
 
-#if GTK_CHECK_VERSION(2,18,0)
 	dcontents = gtk_dialog_get_content_area (GTK_DIALOG (decl));
-#else
-	dcontents = GTK_DIALOG (decl)->vbox;
-#endif
 	gtk_box_set_spacing (GTK_BOX (dcontents), 5);
 
 	/* label */
@@ -404,8 +400,7 @@ fk_declare_new (GtkWindow *parent, GdaMetaStruct *mstruct, GdaMetaTable *table)
 			       GDA_META_DB_OBJECT (table)->obj_short_name);
 	wid = (GtkWidget*) g_object_new (FK_DECLARE_TYPE, "title", str,
 					 "transient-for", parent,
-					 "border-width", 10, 
-					 "has-separator", FALSE, NULL);
+					 "border-width", 10, NULL);
 	g_free (str);
 
 	decl = FK_DECLARE (wid);
diff --git a/tools/browser/common/fk-declare.h b/tools/browser/common/fk-declare.h
index ff60eb4..78b5c93 100644
--- a/tools/browser/common/fk-declare.h
+++ b/tools/browser/common/fk-declare.h
@@ -1,8 +1,8 @@
 /* 
  * Copyright (C) 2011 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/common/gdaui-data-import.c b/tools/browser/common/gdaui-data-import.c
index 7d219d9..234dcb5 100644
--- a/tools/browser/common/gdaui-data-import.c
+++ b/tools/browser/common/gdaui-data-import.c
@@ -2,17 +2,17 @@
  *
  * Copyright (C) 2006 - 2008 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
+ * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public License
+ * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  * USA
diff --git a/tools/browser/common/gdaui-data-import.h b/tools/browser/common/gdaui-data-import.h
index ce5b80d..913439a 100644
--- a/tools/browser/common/gdaui-data-import.h
+++ b/tools/browser/common/gdaui-data-import.h
@@ -2,17 +2,17 @@
  *
  * Copyright (C) 2006 - 2009 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
+ * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public License
+ * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  * USA
diff --git a/tools/browser/common/gdaui-entry-import.c b/tools/browser/common/gdaui-entry-import.c
index a8cf6ae..027510d 100644
--- a/tools/browser/common/gdaui-entry-import.c
+++ b/tools/browser/common/gdaui-entry-import.c
@@ -2,17 +2,17 @@
  *
  * Copyright (C) 2009 - 2010 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
+ * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public License
+ * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  * USA
@@ -179,11 +179,7 @@ open_button_clicked_cb (GtkWidget *button, GdauiEntryImport *mgtxt)
 					      GTK_RESPONSE_REJECT,
 					      NULL);
 	wid = gdaui_data_import_new ();
-#if GTK_CHECK_VERSION(2,18,0)
 	gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), wid);
-#else
-	gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), wid);
-#endif
 	gtk_widget_show_all (dialog);
 	
 	res = gtk_dialog_run (GTK_DIALOG (dialog));
diff --git a/tools/browser/common/gdaui-entry-import.h b/tools/browser/common/gdaui-entry-import.h
index afb004e..a6281c2 100644
--- a/tools/browser/common/gdaui-entry-import.h
+++ b/tools/browser/common/gdaui-entry-import.h
@@ -2,17 +2,17 @@
  *
  * Copyright (C) 2003 - 2006 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
+ * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public License
+ * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  * USA
diff --git a/tools/browser/common/objects-cloud.c b/tools/browser/common/objects-cloud.c
index 503888d..b70ffa2 100644
--- a/tools/browser/common/objects-cloud.c
+++ b/tools/browser/common/objects-cloud.c
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -527,11 +527,7 @@ visibility_notify_event (GtkWidget *text_view, G_GNUC_UNUSED GdkEventVisibility
 {
 	gint wx, wy, bx, by;
 
-#if GTK_CHECK_VERSION(2,18,0)
 	gdk_window_get_pointer (gtk_widget_get_window (text_view), &wx, &wy, NULL);
-#else
-	gdk_window_get_pointer (text_view->window, &wx, &wy, NULL);
-#endif
 	
 	gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view), 
 					       GTK_TEXT_WINDOW_WIDGET,
@@ -555,11 +551,7 @@ motion_notify_event (GtkWidget *text_view, GdkEventMotion *event, ObjectsCloud *
 					       event->x, event->y, &x, &y);
 	
 	set_cursor_if_appropriate (GTK_TEXT_VIEW (text_view), x, y, cloud);
-#if GTK_CHECK_VERSION(2,18,0)
 	gdk_window_get_pointer (gtk_widget_get_window (text_view), NULL, NULL, NULL);
-#else
-	gdk_window_get_pointer (text_view->window, NULL, NULL, NULL);
-#endif
 	return FALSE;
 }
 
@@ -653,8 +645,8 @@ key_press_event (GtkWidget *text_view, GdkEventKey *event, ObjectsCloud *cloud)
 	GtkTextBuffer *buffer;
 	
 	switch (event->keyval) {
-	case GDK_Return: 
-	case GDK_KP_Enter:
+	case GDK_KEY_Return: 
+	case GDK_KEY_KP_Enter:
 		buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
 		gtk_text_buffer_get_iter_at_mark (buffer, &iter, 
 						  gtk_text_buffer_get_insert (buffer));
diff --git a/tools/browser/common/objects-cloud.h b/tools/browser/common/objects-cloud.h
index b9d7aaa..b059f3a 100644
--- a/tools/browser/common/objects-cloud.h
+++ b/tools/browser/common/objects-cloud.h
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/common/ui-formgrid.c b/tools/browser/common/ui-formgrid.c
index c2ac466..f38f204 100644
--- a/tools/browser/common/ui-formgrid.c
+++ b/tools/browser/common/ui-formgrid.c
@@ -463,13 +463,9 @@ statement_executed_cb (G_GNUC_UNUSED BrowserConnection *bcnc,
 		gchar *tmp;
 		dialog = gtk_dialog_new_with_buttons (aed->name,
 						      NULL,
-						      GTK_DIALOG_NO_SEPARATOR,
+						      0,
 						      GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
-#if GTK_CHECK_VERSION(2,18,0)
 		dcontents = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
-#else
-		dcontents = GTK_DIALOG (dialog)->vbox;
-#endif
 		gtk_box_set_spacing (GTK_BOX (dcontents), 5);
 		gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE, TRUE);
 		
diff --git a/tools/browser/common/ui-formgrid.h b/tools/browser/common/ui-formgrid.h
index 6216b45..20dafc7 100644
--- a/tools/browser/common/ui-formgrid.h
+++ b/tools/browser/common/ui-formgrid.h
@@ -53,9 +53,14 @@ struct _UiFormGridClass
 	GtkVBoxClass       parent_class;
 };
 
-/* 
- * Generic widget's methods 
+/**
+ * SECTION:ui-formgrid
+ * @short_description: Widget embedding both a form and a grid to display a #GdaDataModel's contents
+ * @title: UiFormgrid
+ * @stability: Stable
+ * @see_also:
  */
+
 GType             ui_formgrid_get_type            (void);
 
 GtkWidget        *ui_formgrid_new                 (GdaDataModel *model, GdauiDataProxyInfoFlag flags);
diff --git a/tools/browser/connection-binding-properties.c b/tools/browser/connection-binding-properties.c
index 49bf0bb..c0b6972 100644
--- a/tools/browser/connection-binding-properties.c
+++ b/tools/browser/connection-binding-properties.c
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 2009 Vivien Malerba
+ * Copyright (C) 2009 - 2010 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -186,12 +186,7 @@ create_layout (ConnectionBindingProperties *cprop)
 	gchar *str;
 	GtkWidget *dcontents;
 
-#if GTK_CHECK_VERSION(2,18,0)
 	dcontents = gtk_dialog_get_content_area (GTK_DIALOG (cprop));
-#else
-	dcontents = GTK_DIALOG (cprop)->vbox;
-#endif
-
 
 	str = g_strdup_printf ("<b>%s:</b>\n<small>%s</small>",
 			       _("Virtual connection's properties"),
diff --git a/tools/browser/connection-binding-properties.h b/tools/browser/connection-binding-properties.h
index 110d4db..299214f 100644
--- a/tools/browser/connection-binding-properties.h
+++ b/tools/browser/connection-binding-properties.h
@@ -1,8 +1,8 @@
 /* 
  * Copyright (C) 2009 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/data-manager/analyser.c b/tools/browser/data-manager/analyser.c
index 94158d9..2b9cf4f 100644
--- a/tools/browser/data-manager/analyser.c
+++ b/tools/browser/data-manager/analyser.c
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/data-manager/data-console.c b/tools/browser/data-manager/data-console.c
index 14cad94..f2302f8 100644
--- a/tools/browser/data-manager/data-console.c
+++ b/tools/browser/data-manager/data-console.c
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -148,7 +148,7 @@ key_press_event (GtkWidget *widget, GdkEventKey *event)
 {
 	DataConsole *dconsole;
 	dconsole = DATA_CONSOLE (widget);
-	if ((event->keyval == GDK_Escape) &&
+	if ((event->keyval == GDK_KEY_Escape) &&
 	    (gtk_notebook_get_current_page (GTK_NOTEBOOK (dconsole->priv->main_notebook)) == MAIN_PAGE_DATA)) {
 		if (dconsole->priv->agroup) {
 			GtkAction *action;
diff --git a/tools/browser/data-manager/data-console.h b/tools/browser/data-manager/data-console.h
index 086625a..8d48ff8 100644
--- a/tools/browser/data-manager/data-console.h
+++ b/tools/browser/data-manager/data-console.h
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/data-manager/data-favorite-selector.c b/tools/browser/data-manager/data-favorite-selector.c
index b1702a6..a7eb4a9 100644
--- a/tools/browser/data-manager/data-favorite-selector.c
+++ b/tools/browser/data-manager/data-favorite-selector.c
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -181,7 +181,7 @@ data_favorite_selector_get_type (void)
 static gboolean
 key_press_event_cb (GtkTreeView *treeview, GdkEventKey *event, DataFavoriteSelector *tsel)
 {
-	if (event->keyval == GDK_Delete) {
+	if (event->keyval == GDK_KEY_Delete) {
 		GtkTreeModel *model;
 		GtkTreeSelection *select;
 		GtkTreeIter iter;
@@ -600,23 +600,15 @@ tree_store_drag_drop_cb (G_GNUC_UNUSED GdauiTreeStore *store, const gchar *path,
 	gint id;
 	bfav = browser_connection_get_favorites (tsel->priv->bcnc);
 
-#if GTK_CHECK_VERSION(2,18,0)
 	id = browser_favorites_find (bfav, 0, (gchar*) gtk_selection_data_get_data (selection_data),
 				     &fav, NULL);
-#else
-	id = browser_favorites_find (bfav, 0, (gchar*) selection_data->data, &fav, NULL);
-#endif
 	if (id < 0) {
 		memset (&fav, 0, sizeof (BrowserFavoritesAttributes));
 		fav.id = -1;
 		fav.type = BROWSER_FAVORITES_DATA_MANAGERS;
 		fav.name = _("Unnamed data manager");
 		fav.descr = NULL;
-#if GTK_CHECK_VERSION(2,18,0)
 		fav.contents = (gchar*) gtk_selection_data_get_data (selection_data);
-#else
-		fav.contents = (gchar*) selection_data->data;
-#endif
 	}
 
 	pos = atoi (path);
@@ -664,13 +656,8 @@ tree_store_drag_get_cb (G_GNUC_UNUSED GdauiTreeStore *store, const gchar *path,
 		if (cvalue) {
 			const gchar *str;
 			str = g_value_get_string (cvalue);
-#if GTK_CHECK_VERSION(2,18,0)
 			gtk_selection_data_set (selection_data, gtk_selection_data_get_target (selection_data),
 						8, (guchar*) str, strlen (str));
-#else
-			gtk_selection_data_set (selection_data, selection_data->target,
-						8, (guchar*) str, strlen (str));
-#endif
 			return TRUE;
 		}
 	}
diff --git a/tools/browser/data-manager/data-favorite-selector.h b/tools/browser/data-manager/data-favorite-selector.h
index aa7a76d..a6c1584 100644
--- a/tools/browser/data-manager/data-favorite-selector.h
+++ b/tools/browser/data-manager/data-favorite-selector.h
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/data-manager/data-manager-perspective.c b/tools/browser/data-manager/data-manager-perspective.c
index 07649bd..27f4170 100644
--- a/tools/browser/data-manager/data-manager-perspective.c
+++ b/tools/browser/data-manager/data-manager-perspective.c
@@ -1,8 +1,8 @@
 /*
  * Copyright (C) 2009 - 2011 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -193,7 +193,7 @@ data_manager_perspective_new (BrowserWindow *bwin)
         gtk_notebook_append_page (GTK_NOTEBOOK (nb), page, tlabel);
 
         gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (nb), page, TRUE);
-        gtk_notebook_set_group (GTK_NOTEBOOK (nb), bcnc + 0x02); /* add 0x01 to differentiate it from SchemaBrowser */
+        gtk_notebook_set_group_name (GTK_NOTEBOOK (nb), "data-manager");
         gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (perspective->priv->notebook), page,
                                          TRUE);
 
diff --git a/tools/browser/data-manager/data-manager-perspective.h b/tools/browser/data-manager/data-manager-perspective.h
index 91cd8ab..efd7619 100644
--- a/tools/browser/data-manager/data-manager-perspective.h
+++ b/tools/browser/data-manager/data-manager-perspective.h
@@ -1,8 +1,8 @@
 /* 
- * Copyright (C) 2009 - 2010 Vivien Malerba
+ * Copyright (C) 2009 - 2011 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -48,6 +48,14 @@ struct _DataManagerPerspectiveClass
 	GtkVBoxClass                parent_class;
 };
 
+/**
+ * SECTION:data-manager-perspective
+ * @short_description: Perspective to manipulate data contained in the database
+ * @title: Data Manager perspective
+ * @stability: Stable
+ * @see_also:
+ */
+
 GType                data_manager_perspective_get_type (void) G_GNUC_CONST;
 BrowserPerspective  *data_manager_perspective_new      (BrowserWindow *bwin);
 void                 data_manager_perspective_new_tab  (DataManagerPerspective *dmp, const gchar *xml_spec);
diff --git a/tools/browser/data-manager/data-source-editor.c b/tools/browser/data-manager/data-source-editor.c
index fe5de5a..dd3fdbc 100644
--- a/tools/browser/data-manager/data-source-editor.c
+++ b/tools/browser/data-manager/data-source-editor.c
@@ -1,8 +1,8 @@
 /*
  * Copyright (C) 2010 - 2011 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/data-manager/data-source-editor.h b/tools/browser/data-manager/data-source-editor.h
index 4cbdf2e..2cb5fd2 100644
--- a/tools/browser/data-manager/data-source-editor.h
+++ b/tools/browser/data-manager/data-source-editor.h
@@ -1,8 +1,8 @@
 /* 
  * Copyright (C) 2010 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/data-manager/data-source-manager.c b/tools/browser/data-manager/data-source-manager.c
index ad15da4..e5cab8d 100644
--- a/tools/browser/data-manager/data-source-manager.c
+++ b/tools/browser/data-manager/data-source-manager.c
@@ -1,8 +1,8 @@
 /*
  * Copyright (C) 2010 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/data-manager/data-source-manager.h b/tools/browser/data-manager/data-source-manager.h
index 02bd50d..2b9286a 100644
--- a/tools/browser/data-manager/data-source-manager.h
+++ b/tools/browser/data-manager/data-source-manager.h
@@ -1,8 +1,8 @@
 /* 
  * Copyright (C) 2010 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/data-manager/data-source.c b/tools/browser/data-manager/data-source.c
index da35bb7..b8dee88 100644
--- a/tools/browser/data-manager/data-source.c
+++ b/tools/browser/data-manager/data-source.c
@@ -1,8 +1,8 @@
 /*
  * Copyright (C) 2009 - 2010 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/data-manager/data-source.h b/tools/browser/data-manager/data-source.h
index e596b99..05b3e91 100644
--- a/tools/browser/data-manager/data-source.h
+++ b/tools/browser/data-manager/data-source.h
@@ -1,8 +1,8 @@
 /* 
  * Copyright (C) 2009 - 2010 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/data-manager/data-widget.c b/tools/browser/data-manager/data-widget.c
index 40cebb8..dc26348 100644
--- a/tools/browser/data-manager/data-widget.c
+++ b/tools/browser/data-manager/data-widget.c
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -109,7 +109,6 @@ data_widget_init (DataWidget *dwid, G_GNUC_UNUSED DataWidgetClass *klass)
 	gtk_box_pack_start (GTK_BOX (dwid), dwid->priv->top_nb, TRUE, TRUE, 0);
 
 	/* error page */
-#if GTK_CHECK_VERSION (2,18,0)
 	GtkWidget *info;
 	info = gtk_info_bar_new ();
 	gtk_notebook_append_page (GTK_NOTEBOOK (dwid->priv->top_nb), info, NULL);
@@ -118,10 +117,6 @@ data_widget_init (DataWidget *dwid, G_GNUC_UNUSED DataWidgetClass *klass)
 	gtk_label_set_ellipsize (GTK_LABEL (dwid->priv->info_label), PANGO_ELLIPSIZE_END);
 	gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (GTK_INFO_BAR (info))),
 			   dwid->priv->info_label);
-#else
-	dwid->priv->info_label = gtk_label_new ("");
-	gtk_notebook_append_page (GTK_NOTEBOOK (dwid->priv->top_nb), dwid->priv->info_label, NULL);
-#endif
 
 	/* contents page */
 	GtkWidget *vbox;
@@ -262,12 +257,8 @@ create_or_reuse_part (DataWidget *dwid, DataSource *source, gboolean *out_reused
 
 	part->spinner = BROWSER_SPINNER (browser_spinner_new ());
 	browser_spinner_set_size ((BrowserSpinner*) part->spinner, GTK_ICON_SIZE_LARGE_TOOLBAR);
-#if GTK_CHECK_VERSION(2,20,0)
 	page = gtk_alignment_new (0.5, 0.5, 0., 0.);
 	gtk_container_add (GTK_CONTAINER (page), (GtkWidget*) part->spinner);
-#else
-	page = GTK_WIDGET (part->spinner);
-#endif
 	gtk_notebook_append_page (GTK_NOTEBOOK (nb), page, NULL);
 	part->data_widget = NULL;
 
diff --git a/tools/browser/data-manager/data-widget.h b/tools/browser/data-manager/data-widget.h
index 8756cd0..0f04d9a 100644
--- a/tools/browser/data-manager/data-widget.h
+++ b/tools/browser/data-manager/data-widget.h
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/data-manager/ui-spec-editor.c b/tools/browser/data-manager/ui-spec-editor.c
index 65c2cf7..f2cd133 100644
--- a/tools/browser/data-manager/ui-spec-editor.c
+++ b/tools/browser/data-manager/ui-spec-editor.c
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -206,7 +206,7 @@ button_press_event_cb (GtkTreeView *treeview, GdkEventButton *event, UiSpecEdito
 static gboolean
 key_press_event_cb (GtkTreeView *treeview, GdkEventKey *event, UiSpecEditor *sped)
 {
-        if (event->keyval == GDK_Delete) {
+        if (event->keyval == GDK_KEY_Delete) {
 		GtkTreeModel *model;
                 GtkTreeSelection *select;
                 GtkTreeIter iter;
diff --git a/tools/browser/data-manager/ui-spec-editor.h b/tools/browser/data-manager/ui-spec-editor.h
index cd3d837..843a7f9 100644
--- a/tools/browser/data-manager/ui-spec-editor.h
+++ b/tools/browser/data-manager/ui-spec-editor.h
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/data-manager/xml-spec-editor.c b/tools/browser/data-manager/xml-spec-editor.c
index 174c512..dc319df 100644
--- a/tools/browser/data-manager/xml-spec-editor.c
+++ b/tools/browser/data-manager/xml-spec-editor.c
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -218,7 +218,6 @@ signal_editor_changed (XmlSpecEditor *sped)
 
 	if (lerror) {
 		if (! sped->priv->info) {
-#if GTK_CHECK_VERSION (2,18,0)
 			sped->priv->info = gtk_info_bar_new ();
 			gtk_box_pack_start (GTK_BOX (sped), sped->priv->info, FALSE, FALSE, 0);
 			sped->priv->info_label = gtk_label_new ("");
@@ -226,10 +225,6 @@ signal_editor_changed (XmlSpecEditor *sped)
 			gtk_label_set_ellipsize (GTK_LABEL (sped->priv->info_label), PANGO_ELLIPSIZE_END);
 			gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (GTK_INFO_BAR (sped->priv->info))),
 					   sped->priv->info_label);
-#else
-			sped->priv->info = gtk_label_new ("");
-			sped->priv->info_label = sped->priv->info;
-#endif
 			gtk_widget_show (sped->priv->info_label);
 		}
 		gchar *str;
diff --git a/tools/browser/data-manager/xml-spec-editor.h b/tools/browser/data-manager/xml-spec-editor.h
index 0bf3726..b0a9b27 100644
--- a/tools/browser/data-manager/xml-spec-editor.h
+++ b/tools/browser/data-manager/xml-spec-editor.h
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/data/Makefile.am b/tools/browser/data/Makefile.am
index bea8cab..ae0df1f 100644
--- a/tools/browser/data/Makefile.am
+++ b/tools/browser/data/Makefile.am
@@ -45,12 +45,12 @@ update-icon-cache:
 	@-if test -z "$(DESTDIR)"; then \
 		echo "Updating Gtk icon cache."; \
 		for theme in $(public_icons_themes); do \
-			$(gtk_update_icon_cache) $(datadir)/libgda-4.0/icons/$$theme; \
+			$(gtk_update_icon_cache) $(datadir)/libgda-5.0/icons/$$theme; \
 		done; \
 	else \
 		echo "*** Icon cache not updated.  After (un)install, run this:"; \
 		for theme in $(public_icons_themes); do \
-			echo "***   $(gtk_update_icon_cache) $(datadir)/libgda-4.0/icons/$$theme"; \
+			echo "***   $(gtk_update_icon_cache) $(datadir)/libgda-5.0/icons/$$theme"; \
 		done; \
 	fi
 
@@ -68,8 +68,8 @@ install-icons:
 		CONTEXT=`echo $$icon | cut -d_ -f2`; \
 		SIZE=`echo $$icon | cut -d_ -f3`; \
 		ICONFILE=`echo $$icon | cut -d_ -f4`; \
-		mkdir -p $(DESTDIR)$(datadir)/libgda-4.0/icons/$$THEME/$$SIZE/$$CONTEXT; \
-		$(INSTALL_DATA) $(srcdir)/$$icon $(DESTDIR)$(datadir)/libgda-4.0/icons/$$THEME/$$SIZE/$$CONTEXT/$$ICONFILE; \
+		mkdir -p $(DESTDIR)$(datadir)/libgda-5.0/icons/$$THEME/$$SIZE/$$CONTEXT; \
+		$(INSTALL_DATA) $(srcdir)/$$icon $(DESTDIR)$(datadir)/libgda-5.0/icons/$$THEME/$$SIZE/$$CONTEXT/$$ICONFILE; \
 	done
 
 uninstall-icons:
@@ -85,7 +85,7 @@ uninstall-icons:
 		CONTEXT=`echo $$icon | cut -d_ -f2`; \
 		SIZE=`echo $$icon | cut -d_ -f3`; \
 		ICONFILE=`echo $$icon | cut -d_ -f4`; \
-		rm -f $(DESTDIR)$(datadir)/libgda-4.0/icons/$$THEME/$$SIZE/$$CONTEXT/$$ICONFILE; \
+		rm -f $(DESTDIR)$(datadir)/libgda-5.0/icons/$$THEME/$$SIZE/$$CONTEXT/$$ICONFILE; \
 	done
 
 install-data-local: install-icons update-icon-cache
diff --git a/tools/browser/dnd.c b/tools/browser/dnd.c
index 219489e..c969905 100644
--- a/tools/browser/dnd.c
+++ b/tools/browser/dnd.c
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/doc/Makefile.am b/tools/browser/doc/Makefile.am
index d4b470f..3970987 100644
--- a/tools/browser/doc/Makefile.am
+++ b/tools/browser/doc/Makefile.am
@@ -53,8 +53,8 @@ GTKDOC_LIBS = \
 	$(top_builddir)/tools/browser/libbrowser.la \
 	$(top_builddir)/libgda-ui/internal/libgda-ui-internal.la \
 	$(top_builddir)/tools/browser/common/libcommon.la \
-	$(top_builddir)/libgda/libgda-4.0.la \
-	$(top_builddir)/libgda-ui/libgda-ui-4.0.la \
+	$(top_builddir)/libgda/libgda-5.0.la \
+	$(top_builddir)/libgda-ui/libgda-ui-5.0.la \
 	$(LIBGDA_LIBS) \
 	$(GTK_LIBS) \
 	$(GTKSOURCEVIEW_LIBS)
diff --git a/tools/browser/doc/gda-browser-docs.sgml b/tools/browser/doc/gda-browser-docs.sgml
index d969a87..de7cb6d 100644
--- a/tools/browser/doc/gda-browser-docs.sgml
+++ b/tools/browser/doc/gda-browser-docs.sgml
@@ -1,27 +1,7 @@
 <?xml version="1.0"?>
 <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
-     "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd"; [
-<!ENTITY nbsp            " ">
-<!ENTITY LIBGDA          "<application>Libgda</application>">
-<!ENTITY GNOMEDB         "<application>GNOME-DB</application>">
-<!ENTITY fdl-appendix SYSTEM "fdl-appendix.sgml">
-<!ENTITY BrowserCore SYSTEM "xml/browser-core.xml">
-<!ENTITY BrowserWindow SYSTEM "xml/browser-window.xml">
-<!ENTITY BrowserConnection SYSTEM "xml/browser-connection.xml">
-<!ENTITY BrowserFavorites SYSTEM "xml/browser-favorites.xml">
-<!ENTITY BrowserPage SYSTEM "xml/browser-page.xml">
-<!ENTITY BrowserPerspective SYSTEM "xml/browser-perspective.xml">
-<!ENTITY DataManagerPerspective SYSTEM "xml/data-manager-perspective.xml">
-<!ENTITY SchemaBrowserPerspective SYSTEM "xml/schema-browser-perspective.xml">
-<!ENTITY QueryExecPerspective SYSTEM "xml/query-exec-perspective.xml">
-<!ENTITY CCGrayBar SYSTEM "xml/cc-gray-bar.xml">
-<!ENTITY PopupContainer SYSTEM "xml/popup-container.xml">
-<!ENTITY UIFomrGrid SYSTEM "xml/ui-formgrid.xml">
-<!ENTITY MgrFavorites SYSTEM "xml/mgr-favorites.xml">
-<!ENTITY Support SYSTEM "xml/support.xml">
-]>
-
-<book id="index">
+     "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd";>
+<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude";>
   <bookinfo>
     <title>GdaBrowser hacking manual</title>
     <authorgroup>
@@ -35,7 +15,7 @@
         </contrib>
       </author>
     </authorgroup>
-    <date>Jan. 2011</date>
+    <date>Feb. 2011</date>
     <copyright>
       <year>2009 - 2011</year>
       <holder>The GNOME Foundation</holder>
@@ -126,10 +106,10 @@
 	This section is a reference to all the core objects of the Gda browser,
 	which can be used in any extension.
       </para>
-      &BrowserCore;
-      &BrowserConnection;
-      &BrowserFavorites;
-      &Support;
+      <xi:include href="xml/browser-core.xml"/>
+      <xi:include href="xml/browser-connection.xml"/>
+      <xi:include href="xml/browser-favorites.xml"/>
+      <xi:include href="xml/support.xml"/>
     </chapter>
 
     <chapter id="windows">
@@ -150,9 +130,9 @@
         </textobject>
       </mediaobject>
       </para>
-      &BrowserWindow;
-      &BrowserPerspective;
-      &BrowserPage;
+      <xi:include href="xml/browser-window.xml"/>
+      <xi:include href="xml/browser-perspective.xml"/>
+      <xi:include href="xml/browser-page.xml"/>
     </chapter>
 
     <chapter id="extrawidgets">
@@ -161,9 +141,9 @@
 	This section is a reference to all the extra widgets used in the Gda browser,
 	which can be used in any extension.
       </para>
-      &UIFomrGrid;
-      &CCGrayBar;
-      &PopupContainer;
+      <xi:include href="xml/ui-formgrid.xml"/>
+      <xi:include href="xml/cc-gray-bar.xml"/>
+      <xi:include href="xml/popup-container.xml"/>
     </chapter>
 
     <chapter id="perspectives">
@@ -172,16 +152,16 @@
 	This section is a reference to some of the existing perspectives and the associated
 	widgets.
       </para>
-      &MgrFavorites;
-      &SchemaBrowserPerspective;
-      &DataManagerPerspective;
-      &QueryExecPerspective;
+      <xi:include href="xml/mgr-favorites.xml"/>
+      <xi:include href="xml/schema-browser-perspective.xml"/>
+      <xi:include href="xml/data-manager-perspective.xml"/>
+      <xi:include href="xml/query-exec-perspective.xml"/>
     </chapter>
   </part>
 
   <part id="part_index">
     <title>Appendix</title>
-    &fdl-appendix;
+      <xi:include href="fdl-appendix.xml"/>
   </part>
 </book>
 
diff --git a/tools/browser/dummy-perspective/dummy-perspective.c b/tools/browser/dummy-perspective/dummy-perspective.c
index fd6a0d8..cf8a247 100644
--- a/tools/browser/dummy-perspective/dummy-perspective.c
+++ b/tools/browser/dummy-perspective/dummy-perspective.c
@@ -1,8 +1,8 @@
 /*
  * Copyright (C) 2009 - 2011 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/dummy-perspective/dummy-perspective.h b/tools/browser/dummy-perspective/dummy-perspective.h
index c18e9b2..00d730c 100644
--- a/tools/browser/dummy-perspective/dummy-perspective.h
+++ b/tools/browser/dummy-perspective/dummy-perspective.h
@@ -1,8 +1,8 @@
 /* 
  * Copyright (C) 2009 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/favorites-test.c b/tools/browser/favorites-test.c
index b3fbcf2..84d6160 100644
--- a/tools/browser/favorites-test.c
+++ b/tools/browser/favorites-test.c
@@ -12,7 +12,7 @@
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
+ * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
diff --git a/tools/browser/gda-browser-4.0.desktop.in b/tools/browser/gda-browser-5.0.desktop.in
similarity index 80%
rename from tools/browser/gda-browser-4.0.desktop.in
rename to tools/browser/gda-browser-5.0.desktop.in
index 8cee47b..1d996f1 100644
--- a/tools/browser/gda-browser-4.0.desktop.in
+++ b/tools/browser/gda-browser-5.0.desktop.in
@@ -1,8 +1,8 @@
 [Desktop Entry]
 _Name=Database browser
 _Comment=Browse your database's contents
-Icon=gda-browser-4.0
-Exec=gda-browser-4.0
+Icon=gda-browser-5.0
+Exec=gda-browser-5.0
 Terminal=false
 Type=Application
 Categories=GTK;Development;Database;
diff --git a/tools/browser/gda-browser-4.0.png b/tools/browser/gda-browser-5.0.png
similarity index 100%
rename from tools/browser/gda-browser-4.0.png
rename to tools/browser/gda-browser-5.0.png
diff --git a/tools/browser/login-dialog.c b/tools/browser/login-dialog.c
index 740b5ca..c014bad 100644
--- a/tools/browser/login-dialog.c
+++ b/tools/browser/login-dialog.c
@@ -1,8 +1,8 @@
 /* 
- * Copyright (C) 2009 Vivien Malerba
+ * Copyright (C) 2009 - 2010 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -107,12 +107,7 @@ login_dialog_init (LoginDialog *dialog)
 	char *markup, *str;
 	GtkWidget *dcontents;
 
-#if GTK_CHECK_VERSION(2,18,0)
 	dcontents = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
-#else
-	dcontents = GTK_DIALOG (dialog)->vbox;
-#endif
-
 	dialog->priv = g_new0 (LoginDialogPrivate, 1);
 
 	gtk_dialog_add_buttons (GTK_DIALOG (dialog),
@@ -159,7 +154,8 @@ login_dialog_init (LoginDialog *dialog)
 	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
 	
 	dialog->priv->login = gdaui_login_new (NULL);
-	gdaui_login_set_mode (GDAUI_LOGIN (dialog->priv->login), GDA_UI_LOGIN_ENABLE_CONTROL_CENTRE_MODE);
+	gdaui_login_set_mode (GDAUI_LOGIN (dialog->priv->login),
+			      GDA_UI_LOGIN_ENABLE_CONTROL_CENTRE_MODE);
 	g_signal_connect (dialog->priv->login, "changed",
 			  G_CALLBACK (login_contents_changed_cb), dialog);
 	gtk_container_add (GTK_CONTAINER (hbox), dialog->priv->login);
@@ -192,8 +188,7 @@ login_dialog_new (GtkWindow *parent)
 {
 	return (LoginDialog*) g_object_new (LOGIN_TYPE_DIALOG, "title", _("Connection opening"),
 					    "transient-for", parent,
-					    "resizable", FALSE,
-					    "has-separator", FALSE, NULL);
+					    "resizable", FALSE, NULL);
 }
 
 /**
diff --git a/tools/browser/login-dialog.h b/tools/browser/login-dialog.h
index 6675ee5..3b7c051 100644
--- a/tools/browser/login-dialog.h
+++ b/tools/browser/login-dialog.h
@@ -1,8 +1,8 @@
 /* 
  * Copyright (C) 2009 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/main.c b/tools/browser/main.c
index 552137a..b10429d 100644
--- a/tools/browser/main.c
+++ b/tools/browser/main.c
@@ -12,7 +12,7 @@
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Library General Public License for more details.
+ * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
diff --git a/tools/browser/mgr-favorites.c b/tools/browser/mgr-favorites.c
index 52a796a..73da388 100644
--- a/tools/browser/mgr-favorites.c
+++ b/tools/browser/mgr-favorites.c
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/mgr-favorites.h b/tools/browser/mgr-favorites.h
index 46c4740..1e6794b 100644
--- a/tools/browser/mgr-favorites.h
+++ b/tools/browser/mgr-favorites.h
@@ -1,11 +1,11 @@
 /* 
- * Copyright (C) 2009 The GNOME Foundation.
+ * Copyright (C) 2009 - 2011 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -47,6 +47,14 @@ struct _MgrFavoritesClass {
 	GdaTreeManagerClass object_class;
 };
 
+/**
+ * SECTION:mgr-favorites
+ * @short_description: A #GdaTreeManager for the stored favorites
+ * @title: MgrFavorites
+ * @stability: Stable
+ * @see_also:
+ */
+
 GType           mgr_favorites_get_type                 (void) G_GNUC_CONST;
 GdaTreeManager* mgr_favorites_new                      (BrowserConnection *bcnc, BrowserFavoritesType type,
 							gint order_key);
diff --git a/tools/browser/query-exec/query-console.c b/tools/browser/query-exec/query-console.c
index 5b9dd79..0ca600e 100644
--- a/tools/browser/query-exec/query-console.c
+++ b/tools/browser/query-exec/query-console.c
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -843,18 +843,11 @@ popup_container_position_func (PopupContainer *cont, gint *out_x, gint *out_y)
 	console = g_object_get_data (G_OBJECT (cont), "console");
 	top = gtk_widget_get_toplevel (console);	
         gtk_widget_size_request ((GtkWidget*) cont, &req);
-#if GTK_CHECK_VERSION(2,18,0)
 	GtkAllocation alloc;
         gdk_window_get_origin (gtk_widget_get_window (top), &x, &y);
 	gtk_widget_get_allocation (top, &alloc);
 	x += (alloc.width - req.width) / 2;
 	y += (alloc.height - req.height) / 2;
-#else
-        gdk_window_get_origin (top->window, &x, &y);
-	
-	x += (top->allocation.width - req.width) / 2;
-	y += (top->allocation.height - req.height) / 2;
-#endif
 
         if (x < 0)
                 x = 0;
diff --git a/tools/browser/query-exec/query-console.h b/tools/browser/query-exec/query-console.h
index 491d44e..cf09777 100644
--- a/tools/browser/query-exec/query-console.h
+++ b/tools/browser/query-exec/query-console.h
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/query-exec/query-editor.c b/tools/browser/query-exec/query-editor.c
index f2d9ff1..0618a0c 100644
--- a/tools/browser/query-exec/query-editor.c
+++ b/tools/browser/query-exec/query-editor.c
@@ -5,8 +5,8 @@
  *      Rodrigo Moya <rodrigo gnome-db org>
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -490,10 +490,10 @@ event (GtkWidget *text_view, GdkEvent *ev, QueryEditor *editor)
 	else if (ev->type == GDK_KEY_PRESS) {
 		GdkEventKey *evkey = ((GdkEventKey*) ev);
 		if ((editor->priv->mode == QUERY_EDITOR_HISTORY) &&
-		    ((evkey->keyval == GDK_Up) || (evkey->keyval == GDK_Down))) {
+		    ((evkey->keyval == GDK_KEY_Up) || (evkey->keyval == GDK_KEY_Down))) {
 			HistItemData *nfocus = NULL;
 			if (editor->priv->hist_focus) {
-				if (((GdkEventKey*) ev)->keyval == GDK_Up)
+				if (((GdkEventKey*) ev)->keyval == GDK_KEY_Up)
 					nfocus = get_prev_hist_data (editor, editor->priv->hist_focus);
 				else
 					nfocus = get_next_hist_data (editor, editor->priv->hist_focus);
@@ -505,7 +505,7 @@ event (GtkWidget *text_view, GdkEvent *ev, QueryEditor *editor)
 			return TRUE;
 		}
 		else if ((editor->priv->mode == QUERY_EDITOR_HISTORY) &&
-			 ((evkey->keyval == GDK_Delete) && editor->priv->hist_focus)) {
+			 ((evkey->keyval == GDK_KEY_Delete) && editor->priv->hist_focus)) {
 			if (editor->priv->hist_focus->item)
 				query_editor_del_current_history_item (editor);
 			else if (editor->priv->hist_focus->batch)
@@ -514,7 +514,7 @@ event (GtkWidget *text_view, GdkEvent *ev, QueryEditor *editor)
 		}
 		else if ((editor->priv->mode == QUERY_EDITOR_READWRITE) && 
 			 (evkey->state & GDK_CONTROL_MASK) &&
-			 ((evkey->keyval == GDK_L) || (evkey->keyval == GDK_l))) {
+			 ((evkey->keyval == GDK_KEY_L) || (evkey->keyval == GDK_KEY_l))) {
 			GtkTextIter start, end;
 			gtk_text_buffer_get_start_iter (buffer, &start);
 			gtk_text_buffer_get_end_iter (buffer, &end);
@@ -523,13 +523,13 @@ event (GtkWidget *text_view, GdkEvent *ev, QueryEditor *editor)
 		}
 		else if ((editor->priv->mode == QUERY_EDITOR_READWRITE) && 
 			 (evkey->state & GDK_CONTROL_MASK) &&
-			 (evkey->keyval == GDK_Return)) {
+			 (evkey->keyval == GDK_KEY_Return)) {
 			g_signal_emit (editor, query_editor_signals[EXECUTE_REQUEST], 0);
 			return TRUE;
 		}
 		else if ((editor->priv->mode == QUERY_EDITOR_READWRITE) && 
 			 (evkey->state & GDK_CONTROL_MASK) &&
-			 (evkey->keyval == GDK_Up) &&
+			 (evkey->keyval == GDK_KEY_Up) &&
 			 editor->priv->states) {
 			if (editor->priv->states->len > 0) {
 				gint i = -1;
@@ -560,7 +560,7 @@ event (GtkWidget *text_view, GdkEvent *ev, QueryEditor *editor)
 		}
 		else if ((editor->priv->mode == QUERY_EDITOR_READWRITE) && 
 			 (evkey->state & GDK_CONTROL_MASK) &&
-			 (evkey->keyval == GDK_Down) &&
+			 (evkey->keyval == GDK_KEY_Down) &&
 			 editor->priv->states) {
 			if (editor->priv->states->len > 0) {
 				if (editor->priv->current_state < editor->priv->states->len - 1) {
@@ -580,7 +580,7 @@ event (GtkWidget *text_view, GdkEvent *ev, QueryEditor *editor)
 		}
 		else if ((editor->priv->mode == QUERY_EDITOR_READWRITE) && 
 			 (evkey->state & GDK_CONTROL_MASK) &&
-			 (evkey->keyval == GDK_space)) {
+			 (evkey->keyval == GDK_KEY_space)) {
 			display_completions (editor);
 			return TRUE;
 		}
@@ -592,13 +592,8 @@ event (GtkWidget *text_view, GdkEvent *ev, QueryEditor *editor)
 }
 
 static gboolean
-text_view_expose_event (GtkTextView *tv, GdkEventExpose *event, QueryEditor *editor)
+text_view_draw (GtkTextView *tv, cairo_t *cr, QueryEditor *editor)
 {
-	GdkWindow *win;
-
-	win = gtk_text_view_get_window (tv, GTK_TEXT_WINDOW_TEXT);
-	if (event->window != win)
-		return FALSE;
 	if (!editor->priv->hist_focus)
 		return FALSE;
 	
@@ -608,7 +603,6 @@ text_view_expose_event (GtkTextView *tv, GdkEventExpose *event, QueryEditor *edi
 	gint y, ye;
 	gint height, heighte;
 	gint win_y;
-	GdkGC *gc;
 	gint margin;
 	GtkTextBuffer *tbuffer;
 	
@@ -649,22 +643,15 @@ text_view_expose_event (GtkTextView *tv, GdkEventExpose *event, QueryEditor *edi
 	redraw_rect.width = visible_rect.width;
 	redraw_rect.height = visible_rect.height;
 	
-	GtkStateType state;
-#if GTK_CHECK_VERSION(2,18,0)
-	state = gtk_widget_get_state (GTK_WIDGET (tv));
-#else
-	state = GTK_WIDGET_STATE (GTK_WIDGET (tv));
-#endif
-	gc = gtk_widget_get_style (GTK_WIDGET (tv))->bg_gc[state];
+	GdkRectangle rect;
 	margin = gtk_text_view_get_left_margin (tv);
-	
-	gdk_draw_rectangle (event->window,
-			    gc,
-			    TRUE,
-			    redraw_rect.x + MAX (0, margin - 1),
-			    win_y,
-			    redraw_rect.width,
-			    height);
+	rect.x = redraw_rect.x + MAX (0, margin - 1);
+	rect.y = win_y;
+	rect.width = redraw_rect.width;
+	rect.height = height;
+	cairo_set_source_rgba (cr, .5, .5, .5, .3);
+	gdk_cairo_rectangle (cr, &rect);
+	cairo_fill (cr);
 
 	return FALSE;
 }
@@ -715,8 +702,8 @@ query_editor_init (QueryEditor *editor, G_GNUC_UNUSED QueryEditorClass *klass)
 			  G_CALLBACK (event), editor);
 	g_signal_connect (gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->priv->text)), "changed", 
 			  G_CALLBACK (text_buffer_changed_cb), editor);
-	g_signal_connect (editor->priv->text, "expose-event",
-			  G_CALLBACK (text_view_expose_event), editor);
+	g_signal_connect (editor->priv->text, "draw",
+			  G_CALLBACK (text_view_draw), editor);
 
 	/* create some tags */
 	GtkTextBuffer *buffer;
diff --git a/tools/browser/query-exec/query-editor.h b/tools/browser/query-exec/query-editor.h
index c2f262a..7868b2b 100644
--- a/tools/browser/query-exec/query-editor.h
+++ b/tools/browser/query-exec/query-editor.h
@@ -5,8 +5,8 @@
  *      Rodrigo Moya <rodrigo gnome-db org>
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/query-exec/query-exec-perspective.c b/tools/browser/query-exec/query-exec-perspective.c
index 68c2010..05cfa3b 100644
--- a/tools/browser/query-exec/query-exec-perspective.c
+++ b/tools/browser/query-exec/query-exec-perspective.c
@@ -1,8 +1,8 @@
 /*
  * Copyright (C) 2009 - 2011 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -195,7 +195,7 @@ query_exec_perspective_new (BrowserWindow *bwin)
 	gtk_notebook_append_page (GTK_NOTEBOOK (nb), page, tlabel);
 
 	gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (nb), page, TRUE);
-	gtk_notebook_set_group (GTK_NOTEBOOK (nb), bcnc + 0x01); /* add 0x01 to differentiate it from SchemaBrowser */
+	gtk_notebook_set_group_name (GTK_NOTEBOOK (nb), "query-exec");
 	gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (perspective->priv->notebook), page,
 					 TRUE);
 
diff --git a/tools/browser/query-exec/query-exec-perspective.h b/tools/browser/query-exec/query-exec-perspective.h
index 0e6edaa..81553db 100644
--- a/tools/browser/query-exec/query-exec-perspective.h
+++ b/tools/browser/query-exec/query-exec-perspective.h
@@ -1,8 +1,8 @@
 /* 
- * Copyright (C) 2009 Vivien Malerba
+ * Copyright (C) 2009 - 2011 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -48,6 +48,14 @@ struct _QueryExecPerspectiveClass
 	GtkVBoxClass         parent_class;
 };
 
+/**
+ * SECTION:query-exec-perspective
+ * @short_description: Perspective to execute SQL commands
+ * @title: Query Exec perspective
+ * @stability: Stable
+ * @see_also:
+ */
+
 GType                query_exec_perspective_get_type               (void) G_GNUC_CONST;
 BrowserPerspective  *query_exec_perspective_new                    (BrowserWindow *bwin);
 
diff --git a/tools/browser/query-exec/query-favorite-selector.c b/tools/browser/query-exec/query-favorite-selector.c
index 128cca4..c1b29dd 100644
--- a/tools/browser/query-exec/query-favorite-selector.c
+++ b/tools/browser/query-exec/query-favorite-selector.c
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -212,7 +212,7 @@ static gboolean
 key_press_event_cb (G_GNUC_UNUSED GtkTreeView *treeview, GdkEventKey *event,
 		    QueryFavoriteSelector *tsel)
 {
-	if (event->keyval == GDK_Delete) {
+	if (event->keyval == GDK_KEY_Delete) {
 		favorite_delete_selected (tsel);
 		return TRUE;
 	}
@@ -688,23 +688,15 @@ tree_store_drag_drop_cb (G_GNUC_UNUSED GdauiTreeStore *store, const gchar *path,
 	gint id;
 	bfav = browser_connection_get_favorites (tsel->priv->bcnc);
 
-#if GTK_CHECK_VERSION(2,18,0)
 	id = browser_favorites_find (bfav, 0, (gchar*) gtk_selection_data_get_data (selection_data),
 				     &fav, NULL);
-#else
-	id = browser_favorites_find (bfav, 0, (gchar*) selection_data->data, &fav, NULL);
-#endif
 	if (id < 0) {
 		memset (&fav, 0, sizeof (BrowserFavoritesAttributes));
 		fav.id = -1;
 		fav.type = BROWSER_FAVORITES_QUERIES;
 		fav.name = _("Unnamed query");
 		fav.descr = NULL;
-#if GTK_CHECK_VERSION(2,18,0)
 		fav.contents = (gchar*) gtk_selection_data_get_data (selection_data);
-#else
-		fav.contents = (gchar*) selection_data->data;
-#endif
 	}
 
 	pos = atoi (path);
@@ -753,13 +745,8 @@ tree_store_drag_get_cb (G_GNUC_UNUSED GdauiTreeStore *store, const gchar *path,
 		if (cvalue) {
 			const gchar *str;
 			str = g_value_get_string (cvalue);
-#if GTK_CHECK_VERSION(2,18,0)
 			gtk_selection_data_set (selection_data, gtk_selection_data_get_target (selection_data),
 						8, (guchar*) str, strlen (str));
-#else
-			gtk_selection_data_set (selection_data, selection_data->target,
-						8, (guchar*) str, strlen (str));
-#endif
 			return TRUE;
 		}
 	}
diff --git a/tools/browser/query-exec/query-favorite-selector.h b/tools/browser/query-exec/query-favorite-selector.h
index acf75d7..959cad0 100644
--- a/tools/browser/query-exec/query-favorite-selector.h
+++ b/tools/browser/query-exec/query-favorite-selector.h
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/query-exec/query-result.c b/tools/browser/query-exec/query-result.c
index ee19c68..75b00c9 100644
--- a/tools/browser/query-exec/query-result.c
+++ b/tools/browser/query-exec/query-result.c
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/query-exec/query-result.h b/tools/browser/query-exec/query-result.h
index ddef00c..5ab6d2b 100644
--- a/tools/browser/query-exec/query-result.h
+++ b/tools/browser/query-exec/query-result.h
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/schema-browser/favorite-selector.c b/tools/browser/schema-browser/favorite-selector.c
index 66d0c89..e4db63d 100644
--- a/tools/browser/schema-browser/favorite-selector.c
+++ b/tools/browser/schema-browser/favorite-selector.c
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -150,7 +150,7 @@ favorite_selector_get_type (void)
 static gboolean
 key_press_event_cb (GtkTreeView *treeview, GdkEventKey *event, FavoriteSelector *tsel)
 {
-	if (event->keyval == GDK_Delete) {
+	if (event->keyval == GDK_KEY_Delete) {
 		GtkTreeModel *model;
 		GtkTreeSelection *select;
 		GtkTreeIter iter;
@@ -342,11 +342,7 @@ tree_store_drag_drop_cb (G_GNUC_UNUSED GdauiTreeStore *store, const gchar *path,
 	fav.type = BROWSER_FAVORITES_TABLES;
 	fav.name = NULL;
 	fav.descr = NULL;
-#if GTK_CHECK_VERSION(2,18,0)
 	fav.contents = (gchar*) gtk_selection_data_get_data (selection_data);
-#else
-	fav.contents = (gchar*) selection_data->data;
-#endif
 
 	pos = atoi (path);
 	/*g_print ("%s() path => %s, pos: %d\n", __FUNCTION__, path, pos);*/
@@ -390,14 +386,9 @@ tree_store_drag_get_cb (G_GNUC_UNUSED GdauiTreeStore *store, const gchar *path,
 		if (cvalue) {
 			const gchar *str;
 			str = g_value_get_string (cvalue);
-#if GTK_CHECK_VERSION(2,18,0)
 			gtk_selection_data_set (selection_data,
 						gtk_selection_data_get_target (selection_data), 8,
 						(guchar*) str, strlen (str));
-#else
-			gtk_selection_data_set (selection_data, selection_data->target, 8,
-						(guchar*) str, strlen (str));
-#endif
 			return TRUE;
 		}
 	}
diff --git a/tools/browser/schema-browser/favorite-selector.h b/tools/browser/schema-browser/favorite-selector.h
index 1e50ac3..5b538fe 100644
--- a/tools/browser/schema-browser/favorite-selector.h
+++ b/tools/browser/schema-browser/favorite-selector.h
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/schema-browser/mgr-columns.c b/tools/browser/schema-browser/mgr-columns.c
index 81e185a..1f803b6 100644
--- a/tools/browser/schema-browser/mgr-columns.c
+++ b/tools/browser/schema-browser/mgr-columns.c
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/schema-browser/mgr-columns.h b/tools/browser/schema-browser/mgr-columns.h
index 951b36d..f6c8528 100644
--- a/tools/browser/schema-browser/mgr-columns.h
+++ b/tools/browser/schema-browser/mgr-columns.h
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/schema-browser/objects-index.c b/tools/browser/schema-browser/objects-index.c
index 6dfbf13..efbe41c 100644
--- a/tools/browser/schema-browser/objects-index.c
+++ b/tools/browser/schema-browser/objects-index.c
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/schema-browser/objects-index.h b/tools/browser/schema-browser/objects-index.h
index d2c48c1..c0d4f79 100644
--- a/tools/browser/schema-browser/objects-index.h
+++ b/tools/browser/schema-browser/objects-index.h
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/schema-browser/relations-diagram.c b/tools/browser/schema-browser/relations-diagram.c
index c767782..b948666 100644
--- a/tools/browser/schema-browser/relations-diagram.c
+++ b/tools/browser/schema-browser/relations-diagram.c
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/schema-browser/relations-diagram.h b/tools/browser/schema-browser/relations-diagram.h
index e0bb91a..fdbeae2 100644
--- a/tools/browser/schema-browser/relations-diagram.h
+++ b/tools/browser/schema-browser/relations-diagram.h
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/schema-browser/schema-browser-perspective.c b/tools/browser/schema-browser/schema-browser-perspective.c
index 61c630e..c020af8 100644
--- a/tools/browser/schema-browser/schema-browser-perspective.c
+++ b/tools/browser/schema-browser/schema-browser-perspective.c
@@ -1,8 +1,8 @@
 /*
  * Copyright (C) 2009 - 2010 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -167,7 +167,7 @@ schema_browser_perspective_new (BrowserWindow *bwin)
 				  browser_make_tab_label_with_stock (_("Index"), GTK_STOCK_ABOUT, FALSE,
 								     NULL));
 	gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (nb), wid, TRUE);
-	gtk_notebook_set_group (GTK_NOTEBOOK (nb), bcnc);
+	gtk_notebook_set_group_name (GTK_NOTEBOOK (nb), "schema-browser");
 
 	gtk_notebook_set_menu_label (GTK_NOTEBOOK (nb), wid,
 				     browser_make_tab_label_with_stock (_("Index"), GTK_STOCK_ABOUT, FALSE,
@@ -332,11 +332,13 @@ static const gchar *ui_actions_info =
 	"    <menu name='Display' action='Display'>"
 	"      <menuitem name='SchemaBrowserFavoritesShow' action='SchemaBrowserFavoritesShow'/>"
         "    </menu>"
+#ifdef HAVE_GOOCANVAS
         "    <placeholder name='MenuExtension'>"
         "      <menu name='Schema' action='Schema'>"
         "        <menuitem name='NewDiagram' action= 'NewDiagram'/>"
         "      </menu>"
         "    </placeholder>"
+#endif
         "  </menubar>"
         "</ui>";
 
diff --git a/tools/browser/schema-browser/schema-browser-perspective.h b/tools/browser/schema-browser/schema-browser-perspective.h
index 6e8d060..ec28e4b 100644
--- a/tools/browser/schema-browser/schema-browser-perspective.h
+++ b/tools/browser/schema-browser/schema-browser-perspective.h
@@ -1,8 +1,8 @@
 /* 
- * Copyright (C) 2009 Vivien Malerba
+ * Copyright (C) 2009 - 2011 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -48,6 +48,14 @@ struct _SchemaBrowserPerspectiveClass
 	GtkVBoxClass         parent_class;
 };
 
+/**
+ * SECTION:schema-browser-perspective
+ * @short_description: Perspective to analyse the database's schema
+ * @title: Schema Browser perspective
+ * @stability: Stable
+ * @see_also:
+ */
+
 GType                schema_browser_perspective_get_type               (void) G_GNUC_CONST;
 BrowserPerspective  *schema_browser_perspective_new                    (BrowserWindow *bwin);
 void                 schema_browser_perspective_display_table_info     (SchemaBrowserPerspective *bpers,
diff --git a/tools/browser/schema-browser/table-columns.c b/tools/browser/schema-browser/table-columns.c
index 60e98b5..a8cc96e 100644
--- a/tools/browser/schema-browser/table-columns.c
+++ b/tools/browser/schema-browser/table-columns.c
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -684,11 +684,7 @@ visibility_notify_event (GtkWidget *text_view, G_GNUC_UNUSED GdkEventVisibility
 {
 	gint wx, wy, bx, by;
 	
-#if GTK_CHECK_VERSION(2,18,0)
 	gdk_window_get_pointer (gtk_widget_get_window (text_view), &wx, &wy, NULL);
-#else
-	gdk_window_get_pointer (text_view->window, &wx, &wy, NULL);
-#endif
 	
 	gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view), 
 					       GTK_TEXT_WINDOW_WIDGET,
@@ -713,11 +709,7 @@ motion_notify_event (GtkWidget *text_view, GdkEventMotion *event, TableColumns *
 	
 	set_cursor_if_appropriate (GTK_TEXT_VIEW (text_view), x, y, tcolumns);
 
-#if GTK_CHECK_VERSION(2,18,0)
 	gdk_window_get_pointer (gtk_widget_get_window (text_view), NULL, NULL, NULL);
-#else
-	gdk_window_get_pointer (text_view->window, NULL, NULL, NULL);
-#endif
 
 	return FALSE;
 }
@@ -862,8 +854,8 @@ key_press_event (GtkWidget *text_view, GdkEventKey *event, TableColumns *tcolumn
 	GtkTextBuffer *buffer;
 	
 	switch (event->keyval) {
-	case GDK_Return: 
-	case GDK_KP_Enter:
+	case GDK_KEY_Return: 
+	case GDK_KEY_KP_Enter:
 		buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
 		gtk_text_buffer_get_iter_at_mark (buffer, &iter, 
 						  gtk_text_buffer_get_insert (buffer));
diff --git a/tools/browser/schema-browser/table-columns.h b/tools/browser/schema-browser/table-columns.h
index 7c6bce0..46285b1 100644
--- a/tools/browser/schema-browser/table-columns.h
+++ b/tools/browser/schema-browser/table-columns.h
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/schema-browser/table-info.c b/tools/browser/schema-browser/table-info.c
index d313708..c761040 100644
--- a/tools/browser/schema-browser/table-info.c
+++ b/tools/browser/schema-browser/table-info.c
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -242,14 +242,9 @@ source_drag_data_get_cb (G_GNUC_UNUSED GtkWidget *widget, G_GNUC_UNUSED GdkDragC
 	case TARGET_KEY_VALUE: {
 		gchar *str;
 		str = table_info_to_selection (tinfo);
-#if GTK_CHECK_VERSION(2,18,0)
 		gtk_selection_data_set (selection_data,
 					gtk_selection_data_get_target (selection_data), 8, (guchar*) str,
 					strlen (str));
-#else
-		gtk_selection_data_set (selection_data, selection_data->target, 8, (guchar*) str,
-					strlen (str));
-#endif
 		g_free (str);
 		break;
 	}
@@ -932,23 +927,15 @@ action_insert_cb (G_GNUC_UNUSED GtkAction *action, TableInfo *tinfo)
 			       _("assign values to the following variables"));
 	gtk_label_set_markup (GTK_LABEL (label), str);
 	g_free (str);
-#if GTK_CHECK_VERSION(2,18,0)
 	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (popup))),
 			    label, FALSE, FALSE, 0);
-#else
-	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (popup)->vbox), label, FALSE, FALSE, 0);
-#endif
 	
 	form = gdaui_basic_form_new (params);
 	g_object_set ((GObject*) form, "show-actions", TRUE, NULL);
 	g_signal_connect (form, "holder-changed",
 			  G_CALLBACK (insert_form_params_changed_cb), popup);
-#if GTK_CHECK_VERSION(2,18,0)
 	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (popup))),
 			    form, TRUE, TRUE, 5);
-#else
-	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (popup)->vbox), form, TRUE, TRUE, 5);
-#endif
 
 	gtk_dialog_set_response_sensitive (GTK_DIALOG (popup), GTK_RESPONSE_ACCEPT,
 					   gdaui_basic_form_is_valid (GDAUI_BASIC_FORM (form)));
diff --git a/tools/browser/schema-browser/table-info.h b/tools/browser/schema-browser/table-info.h
index 82a652e..04c1a72 100644
--- a/tools/browser/schema-browser/table-info.h
+++ b/tools/browser/schema-browser/table-info.h
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/schema-browser/table-preferences.c b/tools/browser/schema-browser/table-preferences.c
index f284b6a..92bd5e4 100644
--- a/tools/browser/schema-browser/table-preferences.c
+++ b/tools/browser/schema-browser/table-preferences.c
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/schema-browser/table-preferences.h b/tools/browser/schema-browser/table-preferences.h
index c52c560..58901e1 100644
--- a/tools/browser/schema-browser/table-preferences.h
+++ b/tools/browser/schema-browser/table-preferences.h
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/schema-browser/table-relations.c b/tools/browser/schema-browser/table-relations.c
index f135e80..fde7fd3 100644
--- a/tools/browser/schema-browser/table-relations.c
+++ b/tools/browser/schema-browser/table-relations.c
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/schema-browser/table-relations.h b/tools/browser/schema-browser/table-relations.h
index 7d66df4..839efcf 100644
--- a/tools/browser/schema-browser/table-relations.h
+++ b/tools/browser/schema-browser/table-relations.h
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/browser/support.c b/tools/browser/support.c
index b1b885f..e52a6bc 100644
--- a/tools/browser/support.c
+++ b/tools/browser/support.c
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -250,7 +250,6 @@ browser_show_help (GtkWindow *parent, const gchar *topic)
 		return;
 	}
 
-#if GTK_CHECK_VERSION(2,14,0)
 	gchar *ruri;
 
 	screen = gtk_widget_get_screen ((GtkWidget*) parent);
@@ -258,14 +257,6 @@ browser_show_help (GtkWindow *parent, const gchar *topic)
 	gtk_show_uri (screen, ruri,  gtk_get_current_event_time (), &error);
 	g_free (ruri);
 
-#else
-	gchar *command;
-	
-	command = g_strconcat ("gnome-help ghelp://", uri,  NULL);
-	screen = gtk_widget_get_screen (GTK_WIDGET (parent));
-	gdk_spawn_command_line_on_screen (screen, command, &error);
-	g_free (command);
-#endif
 	if (error) {
 		GtkWidget *d;
 		d = gtk_message_dialog_new (parent, 
diff --git a/tools/browser/support.h b/tools/browser/support.h
index eec7e75..d1af082 100644
--- a/tools/browser/support.h
+++ b/tools/browser/support.h
@@ -33,6 +33,14 @@ extern GtkOSXApplication *theApp;
 
 G_BEGIN_DECLS
 
+/**
+ * SECTION:support
+ * @short_description: Misc. functions for various situations
+ * @title: Support functions
+ * @stability: Stable
+ * @see_also:
+ */
+
 BrowserConnection *browser_connection_open (GError **error);
 gboolean           browser_connection_close (GtkWindow *parent, BrowserConnection *bcnc);
 void               browser_show_error (GtkWindow *parent, const gchar *format, ...);
diff --git a/tools/command-exec.c b/tools/command-exec.c
index ddcee88..89c465a 100644
--- a/tools/command-exec.c
+++ b/tools/command-exec.c
@@ -398,7 +398,7 @@ gda_internal_command_list_tables (G_GNUC_UNUSED SqlConsole *console, GdaConnecti
 			"table_type LIKE '%TABLE%' "
 			"ORDER BY table_schema, table_name";
 
-		gchar *tmp = gda_sql_identifier_remove_quotes (g_strdup (args[0]));
+		gchar *tmp = gda_sql_identifier_prepare_for_compare (g_strdup (args[0]));
 		g_value_take_string (v = gda_value_new (G_TYPE_STRING), tmp);
 		model = gda_meta_store_extract (gda_connection_get_meta_store (cnc), sql, error, "tname", v, NULL);
 		gda_value_free (v);
diff --git a/tools/config-info.c b/tools/config-info.c
index 0606870..156afc5 100644
--- a/tools/config-info.c
+++ b/tools/config-info.c
@@ -506,7 +506,6 @@ config_info_compute_dict_file_name (GdaDsnInfo *info, const gchar *cnc_string)
 					    info->name);
 	}
 	else {
-#if GLIB_CHECK_VERSION(2,16,0)
 		GdaQuarkList *ql;
 		GSList *list, *sorted_list = NULL;
 		GString *string = NULL;
@@ -538,7 +537,6 @@ config_info_compute_dict_file_name (GdaDsnInfo *info, const gchar *cnc_string)
 					    chname);
 			g_free (chname);
 		}
-#endif
 	}
 
 	g_free (confdir);
diff --git a/tools/gda-list-server-op.c b/tools/gda-list-server-op.c
index 6676684..24ffe68 100644
--- a/tools/gda-list-server-op.c
+++ b/tools/gda-list-server-op.c
@@ -38,7 +38,7 @@ main (int argc, char **argv) {
         g_option_context_free (context);
 
 	gda_init ();
-	xml_dir = gda_gbr_get_file_path (GDA_DATA_DIR, "libgda-4.0", NULL);
+	xml_dir = gda_gbr_get_file_path (GDA_DATA_DIR, "libgda-5.0", NULL);
 	g_print (_("Using XML descriptions in %s\n"), xml_dir);
 	if (prov)
 		g_print ("For provider %s\n", prov);
diff --git a/tools/gda-threader.c b/tools/gda-threader.c
index 4cf4632..082ff84 100644
--- a/tools/gda-threader.c
+++ b/tools/gda-threader.c
@@ -2,8 +2,8 @@
  *
  * Copyright (C) 2005 - 2007 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/gda-threader.h b/tools/gda-threader.h
index d8ecd04..0014aae 100644
--- a/tools/gda-threader.h
+++ b/tools/gda-threader.h
@@ -2,8 +2,8 @@
  *
  * Copyright (C) 2005 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/gda-tree-mgr-xml.c b/tools/gda-tree-mgr-xml.c
index 45ed02d..7865174 100644
--- a/tools/gda-tree-mgr-xml.c
+++ b/tools/gda-tree-mgr-xml.c
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/gda-tree-mgr-xml.h b/tools/gda-tree-mgr-xml.h
index b1c9c19..d37f9a5 100644
--- a/tools/gda-tree-mgr-xml.h
+++ b/tools/gda-tree-mgr-xml.h
@@ -4,8 +4,8 @@
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
diff --git a/tools/web-server.c b/tools/web-server.c
index 63aa35f..63f1aff 100644
--- a/tools/web-server.c
+++ b/tools/web-server.c
@@ -1,9 +1,9 @@
 /* web-server.c
  *
- * Copyright (C) 2008 - 2009 Vivien Malerba
+ * Copyright (C) 2008 - 2011 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
@@ -444,7 +444,7 @@ get_file (G_GNUC_UNUSED WebServer *server, SoupMessage *msg, const char *path, G
 	GMappedFile *mfile;
 	gchar *real_path;
 
-	real_path = gda_gbr_get_file_path (GDA_DATA_DIR, "libgda-4.0", "web", path, NULL);
+	real_path = gda_gbr_get_file_path (GDA_DATA_DIR, "libgda-5.0", "web", path, NULL);
 	if (!real_path)
 		return FALSE;
 
@@ -472,11 +472,7 @@ get_file (G_GNUC_UNUSED WebServer *server, SoupMessage *msg, const char *path, G
 	SoupBuffer *buffer;
 	buffer = soup_buffer_new_with_owner (g_mapped_file_get_contents (mfile),
 					     g_mapped_file_get_length (mfile),
-#if GLIB_CHECK_VERSION(2,22,0)
 					     mfile, (GDestroyNotify) g_mapped_file_unref);
-#else
-					     mfile, (GDestroyNotify) g_mapped_file_free);
-#endif
 	soup_message_body_append_buffer (msg->response_body, buffer);
 	soup_buffer_free (buffer);
 	soup_message_set_status (msg, SOUP_STATUS_OK);
diff --git a/tools/web-server.h b/tools/web-server.h
index d2c355f..5d8f8de 100644
--- a/tools/web-server.h
+++ b/tools/web-server.h
@@ -2,8 +2,8 @@
  *
  * Copyright (C) 2008 Vivien Malerba
  *
- * This Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]