Compare commits

..
Author SHA1 Message Date
SVN Migration 62e263f01e This commit was manufactured by cvs2svn to create tag
'php_4_3_0_dev_ZendEngine2'.
2002-05-19 13:54:38 +00:00
127 changed files with 2006 additions and 105265 deletions

No files matched your search

+2
View File
@@ -0,0 +1,2 @@
dbplus
Hartmut Holzgraefe
+5
View File
@@ -0,0 +1,5 @@
this extension is experimental,
its functions may change their names
or move to extension all together
so do not rely to much on them
you have been warned!
+3
View File
@@ -0,0 +1,3 @@
experimental db++ extension
for more information on db++ see
http://www.concept-asa.de
+47
View File
@@ -0,0 +1,47 @@
dnl
dnl $Id$
dnl
PHP_ARG_WITH(dbplus, for dbplus support,
[ --with-dbplus Include dbplus support])
if test "$PHP_DBPLUS" != "no"; then
# --with-dbplus -> check with-path
SEARCH_PATH="/usr/dbplus /usr/local/dbplus /opt/dbplus"
SEARCH_FOR="/include/dbconfig.h"
if test -r $PHP_DBPLUS/; then # path given as parameter
DBPLUS_DIR=$PHP_DBPLUS
else # search default path list
AC_MSG_CHECKING(for dbplus files in default path)
for i in $SEARCH_PATH ; do
if test -r $i/$SEARCH_FOR; then
DBPLUS_DIR=$i
AC_MSG_RESULT(found in $i)
fi
done
fi
if test -z "$DBPLUS_DIR"; then
AC_MSG_RESULT(not found)
AC_MSG_ERROR(Please reinstall the dbplus distribution)
fi
# --with-dbplus -> add include path
PHP_ADD_INCLUDE($DBPLUS_DIR/include)
# --with-dbplus -> chech for lib and symbol presence
LIBNAME=Ddb
LIBSYMBOL=Db_Init
old_LIBS=$LIBS
LIBS="-L$DBPLUS_DIR/lib -lm -ldl -lDmacc -lDracc"
AC_CHECK_LIB($LIBNAME, $LIBSYMBOL, [AC_DEFINE(HAVE_DBPLUSLIB,1,[ ])],
[AC_MSG_ERROR(wrong dbplus lib version or lib not found)])
LIBS=$old_LIBS
PHP_SUBST(DBPLUS_SHARED_LIBADD)
PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $DBPLUS_DIR/lib, DBPLUS_SHARED_LIBADD)
PHP_ADD_LIBRARY_WITH_PATH(Dmacc, $DBPLUS_DIR/lib, DBPLUS_SHARED_LIBADD)
PHP_ADD_LIBRARY_WITH_PATH(Dracc, $DBPLUS_DIR/lib, DBPLUS_SHARED_LIBADD)
PHP_NEW_EXTENSION(dbplus, dbplus.c php_dbplus.c , $ext_shared)
fi
+247
View File
@@ -0,0 +1,247 @@
/*
+----------------------------------------------------------------------+
| PHP Version 4 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2002 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 2.02 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available at through the world-wide-web at |
| http://www.php.net/license/2_02.txt. |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Hartmut Holzgraefe <hartmut@six.de> |
+----------------------------------------------------------------------+
*/
#include "php.h"
#include "ext/standard/info.h"
#include "php_ini.h"
#include "php_dbplus.h"
#include <saccess.h>
#include <relation.h>
#include <dblight.h>
/* If you declare any globals in php_dbplus.h uncomment this:
ZEND_DECLARE_MODULE_GLOBALS(dbplus)
*/
#ifdef COMPILE_DL_DBPLUS
ZEND_GET_MODULE(dbplus)
#endif
/* {{{ Resource handling */
/* True global resources - no need for thread safety here */
int le_dbplus_relation;
int le_dbplus_tupel;
void dbplus_destruct_relation(zend_rsrc_list_entry *rsrc TSRMLS_DC)
{
relf *conn = (relf *)(rsrc->ptr);
cdb_close(conn);
}
void dbplus_destruct_tupel(zend_rsrc_list_entry *rsrc TSRMLS_DC)
{
tuple *t = (tuple *)(rsrc->ptr);
efree(t);
}
/* }}} */
/* {{{ function table */
/* Every user visible function must have an entry in dbplus_functions[].
*/
function_entry dbplus_functions[] = {
PHP_FE(dbplus_add, NULL)
PHP_FE(dbplus_aql, NULL)
PHP_FE(dbplus_chdir, NULL)
PHP_FE(dbplus_close, NULL)
PHP_FE(dbplus_curr, NULL)
PHP_FE(dbplus_errno, NULL)
PHP_FE(dbplus_errcode, NULL)
PHP_FE(dbplus_find, NULL)
PHP_FE(dbplus_first, NULL)
PHP_FE(dbplus_flush, NULL)
PHP_FE(dbplus_freealllocks, NULL)
PHP_FE(dbplus_freelock, NULL)
PHP_FE(dbplus_freerlocks, NULL)
PHP_FE(dbplus_getlock, NULL)
PHP_FE(dbplus_getunique, NULL)
PHP_FE(dbplus_info, NULL)
PHP_FE(dbplus_last, NULL)
PHP_FE(dbplus_next, NULL)
PHP_FE(dbplus_open, NULL)
PHP_FE(dbplus_prev, NULL)
PHP_FE(dbplus_rchperm, NULL)
PHP_FE(dbplus_rcreate, NULL)
PHP_FE(dbplus_rcrtexact, NULL)
PHP_FE(dbplus_rcrtlike, NULL)
PHP_FE(dbplus_resolve, NULL)
PHP_FE(dbplus_restorepos, NULL)
PHP_FE(dbplus_rkeys, NULL)
PHP_FE(dbplus_ropen, NULL)
PHP_FE(dbplus_rquery, NULL)
PHP_FE(dbplus_rrename, NULL)
PHP_FE(dbplus_rsecindex, NULL)
PHP_FE(dbplus_runlink, NULL)
PHP_FE(dbplus_rzap, NULL)
PHP_FE(dbplus_savepos, NULL)
PHP_FE(dbplus_setindex, NULL)
PHP_FE(dbplus_setindexbynumber, NULL)
PHP_FE(dbplus_sql, NULL)
PHP_FE(dbplus_tcl, NULL)
PHP_FE(dbplus_tremove, NULL)
PHP_FE(dbplus_undo, NULL)
PHP_FE(dbplus_undoprepare, NULL)
PHP_FE(dbplus_unlockrel, NULL)
PHP_FE(dbplus_unselect, NULL)
PHP_FE(dbplus_update, NULL)
PHP_FE(dbplus_xlockrel, NULL)
PHP_FE(dbplus_xunlockrel, NULL)
{NULL, NULL, NULL} /* Must be the last line in dbplus_functions[] */
};
/* }}} */
/* {{{ module entry */
zend_module_entry dbplus_module_entry = {
STANDARD_MODULE_HEADER,
"dbplus",
dbplus_functions,
PHP_MINIT(dbplus),
PHP_MSHUTDOWN(dbplus),
PHP_RINIT(dbplus), /* Replace with NULL if there's nothing to do at request start */
PHP_RSHUTDOWN(dbplus), /* Replace with NULL if there's nothing to do at request end */
PHP_MINFO(dbplus),
NO_VERSION_YET,
STANDARD_MODULE_PROPERTIES
};
/* }}} */
/* {{{ ini parameters */
/* Remove comments and fill if you need to have entries in php.ini
PHP_INI_BEGIN()
PHP_INI_END()
*/
/* }}} */
/* {{{ module init */
PHP_MINIT_FUNCTION(dbplus)
{
/* resource id for cdb connections */
le_dbplus_relation = zend_register_list_destructors_ex(dbplus_destruct_relation, NULL, "dbplus_relation", module_number);
le_dbplus_tupel = zend_register_list_destructors_ex(dbplus_destruct_tupel , NULL, "dbplus_tuple" , module_number);
/* constants for DBPLUS error codes */
REGISTER_LONG_CONSTANT("DBPLUS_ERR_NOERR", ERR_NOERR, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_DUPLICATE", ERR_DUPLICATE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_EOSCAN", ERR_EOSCAN, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_EMPTY", ERR_EMPTY, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_CLOSE", ERR_CLOSE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_WLOCKED", ERR_WLOCKED, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_LOCKED", ERR_LOCKED, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_NOLOCK", ERR_NOLOCK, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_READ", ERR_READ, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_WRITE", ERR_WRITE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_CREATE", ERR_CREATE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_LSEEK", ERR_LSEEK, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_LENGTH", ERR_LENGTH, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_OPEN", ERR_OPEN, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_WOPEN", ERR_WOPEN, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_MAGIC", ERR_MAGIC, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_VERSION", ERR_VERSION, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_PGSIZE", ERR_PGSIZE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_CRC", ERR_CRC, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_PIPE", ERR_PIPE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_NIDX", ERR_NIDX, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_MALLOC", ERR_MALLOC, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_NUSERS", ERR_NUSERS, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_PREEXIT", ERR_PREEXIT, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_ONTRAP", ERR_ONTRAP, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_PREPROC", ERR_PREPROC, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_DBPARSE", ERR_DBPARSE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_DBRUNERR", ERR_DBRUNERR, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_DBPREEXIT", ERR_DBPREEXIT, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_WAIT", ERR_WAIT, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_CORRUPT_TUPLE", ERR_CORRUPT_TUPLE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_WARNING0", ERR_WARNING0, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_PANIC", ERR_PANIC, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_FIFO", ERR_FIFO, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_PERM", ERR_PERM, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_TCL", ERR_TCL, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_RESTRICTED", ERR_RESTRICTED, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_USER", ERR_USER, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("DBPLUS_ERR_UNKNOWN", ERR_UNKNOWN, CONST_CS | CONST_PERSISTENT);
return SUCCESS;
}
/* }}} */
/* {{{ module shutdown */
PHP_MSHUTDOWN_FUNCTION(dbplus)
{
return SUCCESS;
}
/* }}} */
/* {{{ request init */
/* Remove if there's nothing to do at request start */
PHP_RINIT_FUNCTION(dbplus)
{
return SUCCESS;
}
/* }}} */
/* {{{ request shutdown */
/* Remove if there's nothing to do at request end */
PHP_RSHUTDOWN_FUNCTION(dbplus)
{
return SUCCESS;
}
/* }}} */
/* {{{ module information */
PHP_MINFO_FUNCTION(dbplus)
{
php_info_print_table_start();
php_info_print_table_header(2, "dbplus support", "enabled");
php_info_print_table_end();
/* Remove comments if you have entries in php.ini
DISPLAY_INI_ENTRIES();
*/
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
*/
File diff suppressed because it is too large. Load diff
+122
View File
@@ -0,0 +1,122 @@
/*
+----------------------------------------------------------------------+
| PHP Version 4 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2002 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 2.02 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available at through the world-wide-web at |
| http://www.php.net/license/2_02.txt. |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#ifndef PHP_DBPLUS_H
#define PHP_DBPLUS_H
extern zend_module_entry dbplus_module_entry;
#define phpext_dbplus_ptr &dbplus_module_entry
#ifdef PHP_WIN32
#define PHP_DBPLUS_API __declspec(dllexport)
#else
#define PHP_DBPLUS_API
#endif
PHP_MINIT_FUNCTION(dbplus);
PHP_MSHUTDOWN_FUNCTION(dbplus);
PHP_RINIT_FUNCTION(dbplus);
PHP_RSHUTDOWN_FUNCTION(dbplus);
PHP_MINFO_FUNCTION(dbplus);
PHP_FUNCTION(dbplus_add);
PHP_FUNCTION(dbplus_aql);
PHP_FUNCTION(dbplus_chdir);
PHP_FUNCTION(dbplus_close);
PHP_FUNCTION(dbplus_curr);
PHP_FUNCTION(dbplus_errno);
PHP_FUNCTION(dbplus_errcode);
PHP_FUNCTION(dbplus_find);
PHP_FUNCTION(dbplus_first);
PHP_FUNCTION(dbplus_flush);
PHP_FUNCTION(dbplus_freealllocks);
PHP_FUNCTION(dbplus_freelock);
PHP_FUNCTION(dbplus_freerlocks);
PHP_FUNCTION(dbplus_getlock);
PHP_FUNCTION(dbplus_getunique);
PHP_FUNCTION(dbplus_info);
PHP_FUNCTION(dbplus_last);
PHP_FUNCTION(dbplus_next);
PHP_FUNCTION(dbplus_open);
PHP_FUNCTION(dbplus_prev);
PHP_FUNCTION(dbplus_rchperm);
PHP_FUNCTION(dbplus_rcreate);
PHP_FUNCTION(dbplus_rcrtexact);
PHP_FUNCTION(dbplus_rcrtlike);
PHP_FUNCTION(dbplus_resolve);
PHP_FUNCTION(dbplus_restorepos);
PHP_FUNCTION(dbplus_rkeys);
PHP_FUNCTION(dbplus_ropen);
PHP_FUNCTION(dbplus_rquery);
PHP_FUNCTION(dbplus_rrename);
PHP_FUNCTION(dbplus_rsecindex);
PHP_FUNCTION(dbplus_runlink);
PHP_FUNCTION(dbplus_rzap);
PHP_FUNCTION(dbplus_savepos);
PHP_FUNCTION(dbplus_setindex);
PHP_FUNCTION(dbplus_setindexbynumber);
PHP_FUNCTION(dbplus_sql);
PHP_FUNCTION(dbplus_tcl);
PHP_FUNCTION(dbplus_tremove);
PHP_FUNCTION(dbplus_undo);
PHP_FUNCTION(dbplus_undoprepare);
PHP_FUNCTION(dbplus_unlockrel);
PHP_FUNCTION(dbplus_unselect);
PHP_FUNCTION(dbplus_update);
PHP_FUNCTION(dbplus_xlockrel);
PHP_FUNCTION(dbplus_xunlockrel);
/*
Declare any global variables you may need between the BEGIN
and END macros here:
ZEND_BEGIN_MODULE_GLOBALS(dbplus)
int global_variable;
ZEND_END_MODULE_GLOBALS(dbplus)
*/
/* In every function that needs to use variables in php_dbplus_globals,
do call DBPLUSLS_FETCH(); after declaring other variables used by
that function, and always refer to them as DBPLUSG(variable).
You are encouraged to rename these macros something shorter, see
examples in any other php module directory.
*/
#ifdef ZTS
#define AG(v) TSRMG(dbplus_globals_id, php_dbplus_globals *, v)
#else
#define DBPLUSG(v) (dbplus_globals.v)
#endif
int le_dbplus_relation;
int le_dbplus_tuple;
void dbplus_destruct_relation(zend_rsrc_list_entry *rsrc TSRMLS_DC);
void dbplus_destruct_tupel(zend_rsrc_list_entry *rsrc TSRMLS_DC);
#endif /* PHP_DBPLUS_H */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
*/
+23
View File
@@ -0,0 +1,23 @@
--TEST--
Check for dbplus presence
--SKIPIF--
<?php if (!extension_loaded("dbplus")) print "skip"; ?>
--POST--
--GET--
--FILE--
<?php
echo "dbplus extension is available";
/*
you can add regression tests for your extension here
the output of your test code has to be equal to the
text in the --EXPECT-- section below for the tests
to pass, differences between the output and the
expected text are interpreted as failure
see php4/tests/README for further information on
writing regression tests
*/
?>
--EXPECT--
dbplus extension is available
-2
View File
@@ -1,2 +0,0 @@
PHP Data Objects
Wez Furlong, Marcus Boerger, Sterling Hughes, George Schlossnagle
-39
View File
@@ -1,39 +0,0 @@
phpincludedir=$(prefix)/include/php
PDO_HEADER_FILES= \
php_pdo.h \
php_pdo_driver.h
install-pdo-headers:
echo "Installing PDO headers: $(INSTALL_ROOT)$(phpincludedir)/ext/pdo/"
$(mkinstalldirs) $(INSTALL_ROOT)$(phpincludedir)/ext/pdo
for f in $(PDO_HEADER_FILES); do \
if test -f "$(top_srcdir)/$$f"; then \
$(INSTALL_DATA) $(top_srcdir)/$$f $(INSTALL_ROOT)$(phpincludedir)/ext/pdo; \
elif test -f "$(top_builddir)/$$f"; then \
$(INSTALL_DATA) $(top_builddir)/$$f $(INSTALL_ROOT)$(phpincludedir)/ext/pdo; \
elif test -f "$(top_srcdir)/ext/pdo/$$f"; then \
$(INSTALL_DATA) $(top_srcdir)/ext/pdo/$$f $(INSTALL_ROOT)$(phpincludedir)/ext/pdo; \
elif test -f "$(top_builddir)/ext/pdo/$$f"; then \
$(INSTALL_DATA) $(top_builddir)/ext/pdo/$$f $(INSTALL_ROOT)$(phpincludedir)/ext/pdo; \
else \
echo "hmmm"; \
fi \
done;
@echo ""
@echo ""
@echo "You're now ready to install PDO drivers for your database"
@echo "If you'd like to have PDO show up in the list of installed"
@echo "packages when you run \"pear list\", you may now run"
@echo "\"sudo pear install package.xml\""
@echo "this time, when prompted to press enter, you should type"
@echo "\"no\" and press enter instead."
# mini hack
install: $(all_targets) $(install_targets) install-pdo-headers
$(top_srcdir)/ext/pdo/pdo_sql_parser.c: $(top_srcdir)/ext/pdo/pdo_sql_parser.re
exit 0; re2c -b $(top_srcdir)/ext/pdo/pdo_sql_parser.re > $@
$(srcdir)/pdo_sql_parser.c: $(srcdir)/pdo_sql_parser.re
exit 0; re2c -b $(srcdir)/pdo_sql_parser.re > $@
-56
View File
@@ -1,56 +0,0 @@
$Id$
PHP Data Objects
================
Concept: Data Access Abstraction
Goals:
1/ Be light-weight
2/ Provide common API for common database operations
3/ Be performant
4/ Keep majority of PHP specific stuff in the PDO core (such as persistent
resource management); drivers should only have to worry about getting the
data and not about PHP internals.
Transactions and autocommit
===========================
When you create a database handle, you *should* specify the autocommit
behaviour that you require. PDO will default to autocommit on.
$dbh = new PDO("...", $user, $pass, array(PDO_ATTR_AUTOCOMMIT => true));
When auto-commit is on, the driver will implicitly commit each query as it is
executed. This works fine for most simple tasks but can be significantly
slower when you are making a large number of udpates.
$dbh = new PDO("...", $user, $pass, array(PDO_ATTR_AUTOCOMMIT => false));
When auto-commit is off, you must then use $dbh->beginTransaction() to
initiate a transaction. When your work is done, you then call $dbh->commit()
or $dbh->rollBack() to persist or abort your changes respectively. Not all
databases support transactions.
You can change the auto-commit mode at run-time:
$dbh->setAttribute(PDO_ATTR_AUTOCOMMIT, false);
Regardless of the error handling mode set on the database handle, if the
autocommit mode cannot be changed, an exception will be thrown.
Some drivers will allow you to temporarily disable autocommit if you call
$dbh->beginTransaction(). When you commit() or rollBack() such a transaction,
the handle will switch back to autocommit mode again. If the mode could not
be changed, an exception will be raised, as noted above.
When the database handle is closed or destroyed (or at request end for
persistent handles), the driver will implicitly rollBack(). It is your
responsibility to call commit() when you are done making changes and
autocommit is turned off.
vim:tw=78:et
-21
View File
@@ -1,21 +0,0 @@
$Id$
In no particular order:
Probable Bugs:
- persistent connections with bound parameters might segv on subsequent
requests
Low-level:
- $dbh->quote()
- LOB support via Streams API
- make errors generated at the pdo level (as opposed to driver level) use the
selected error mode.
Not-so-low-level:
- fetchAll(), single row, single column fetches etc.
Could be more...
vim:tw=78:et
-46
View File
@@ -1,46 +0,0 @@
dnl $Id$
dnl config.m4 for extension pdo
AC_ARG_WITH(broken-pear-install,
[],[
if test "x$withval" = "xyes"; then
AC_MSG_ERROR([
Due to a bug in the pear installer you should install the PDO package manually
using the following steps:
1. Download the PDO package to your local machine:
% wget http://pecl.php.net/get/PDO
2. Determine your PHP bin dir.
If your php5 cli binary lives at /usr/local/php5/bin/php
the bin dir is /usr/local/php5/bin
3. Set your path so that your PHP bin dir is at the front:
export PATH="/usr/local/php5/bin:\$PATH"
4. Manually build:
% tar xzf PDO-0.2.tgz
% cd PDO-0.2
% phpize
% ./configure
% make
% sudo -s
# make install
# echo extension=pdo.so >> /usr/local/php5/lib/php.ini
We apologize for the inconvenience, and hope to resolve this problem
in a future PHP/PEAR release.
])
fi
])
PHP_ARG_ENABLE(pdo, whether to disable PDO support,
[ --disable-pdo Disable PHP Data Objects support], yes)
if test "$PHP_PDO" != "no"; then
PHP_NEW_EXTENSION(pdo, pdo.c pdo_dbh.c pdo_stmt.c pdo_sql_parser.c pdo_sqlstate.c, $ext_shared)
PHP_ADD_MAKEFILE_FRAGMENT
fi
-9
View File
@@ -1,9 +0,0 @@
// $Id$
// vim:ft=javascript
ARG_ENABLE("pdo", "Enable PHP Data Objects support", "no");
if (PHP_PDO != "no") {
EXTENSION('pdo', 'pdo.c pdo_dbh.c pdo_stmt.c pdo_sql_parser.c pdo_sqlstate.c');
}
-97
View File
@@ -1,97 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE package SYSTEM "../pear/package.dtd">
<package version="1.0">
<name>PDO</name>
<summary>PHP Data Objects Interface</summary>
<maintainers>
<maintainer>
<user>wez</user>
<name>Wez Furlong</name>
<email>wez@php.net</email>
<role>lead</role>
</maintainer>
<maintainer>
<user>helly</user>
<name>Marcus Boerger</name>
<email>helly@php.net</email>
<role>lead</role>
</maintainer>
<maintainer>
<user>iliaa</user>
<name>Ilia Alshanetsky</name>
<email>iliaa@php.net</email>
<role>lead</role>
</maintainer>
<maintainer>
<user>gschlossnagle</user>
<name>George Schlossnagle</name>
<email>george@omniti.com</email>
<role>lead</role>
</maintainer>
</maintainers>
<!-- pear is still broken -->
<configureoptions>
<configureoption name="with-broken-pear-install" default="yes" prompt="the pear installer has a bug; press enter to find out more"/>
</configureoptions>
<description>
PDO provides a uniform data access interface, sporting advanced features such
as prepared statements and bound parameters. PDO drivers are dynamically
loadable and may be developed independently from the core, but still accessed
using the same API.
Read the documentation at http://www.php.net/pdo for more information.
</description>
<license>PHP</license>
<release>
<state>beta</state>
<version>0.2.2</version>
<date>2005-02-11</date>
<notes>
Note that PDO on its own is useless.
You need to install a PDO database driver to make use of it,
check http://pecl.php.net for a list of available PDO drivers.
It is highly recommended that you update to the latest stable PHP 5 snapshot
before using PDO.
You can obtain it from http://snaps.php.net.
If you are running on Windows, you should download:
http://snaps.php.net/win32/php5.0-win32-latest.zip
http://snaps.php.net/win32/PECL_5_0/php_pdo.dll
You can find additional PDO drivers at:
http://snaps.php.net/win32/PECL_5_0/
- Added PDO::quote($string). Closes PECL Bug #3393
- Fixed PDO::query() for drivers using bound parameter emulation.
</notes>
<filelist>
<file role="src" name="config.m4"/>
<file role="src" name="config.w32"/>
<file role="src" name="pdo.c"/>
<file role="src" name="pdo_dbh.c"/>
<file role="src" name="pdo_stmt.c"/>
<file role="src" name="php_pdo.h"/>
<file role="src" name="php_pdo_driver.h"/>
<file role="src" name="php_pdo_int.h"/>
<file role="src" name="pdo_sql_parser.re"/>
<file role="src" name="pdo_sql_parser.c"/>
<file role="src" name="pdo_sqlstate.c"/>
<file role="src" name="Makefile.frag"/>
<file role="doc" name="README"/>
<file role="doc" name="TODO"/>
<file role="doc" name="pdo.php"/>
<file role="doc" name="CREDITS"/>
</filelist>
<deps>
<dep type="php" rel="ge" version="5.0.3"/>
</deps>
</release>
</package>
-351
View File
@@ -1,351 +0,0 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2005 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.0 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_0.txt. |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Wez Furlong <wez@php.net> |
| Marcus Boerger <helly@php.net> |
| Sterling Hughes <sterling@php.net> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <ctype.h>
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_pdo.h"
#include "php_pdo_driver.h"
#include "php_pdo_int.h"
#include "zend_exceptions.h"
ZEND_DECLARE_MODULE_GLOBALS(pdo)
/* True global resources - no need for thread safety here */
/* the registry of PDO drivers */
static HashTable pdo_driver_hash;
/* we use persistent resources for the driver connection stuff */
static int le_ppdo;
int php_pdo_list_entry(void)
{
return le_ppdo;
}
/* for exceptional circumstances */
zend_class_entry *pdo_exception_ce;
PDO_API zend_class_entry *php_pdo_get_exception(void)
{
return pdo_exception_ce;
}
zend_class_entry *pdo_dbh_ce, *pdo_dbstmt_ce, *pdo_row_ce;
/* {{{ pdo_functions[] */
function_entry pdo_functions[] = {
{NULL, NULL, NULL}
};
/* }}} */
/* {{{ pdo_module_entry */
zend_module_entry pdo_module_entry = {
STANDARD_MODULE_HEADER,
"PDO",
pdo_functions,
PHP_MINIT(pdo),
PHP_MSHUTDOWN(pdo),
PHP_RINIT(pdo),
PHP_RSHUTDOWN(pdo),
PHP_MINFO(pdo),
"0.2.2",
STANDARD_MODULE_PROPERTIES
};
/* }}} */
#ifdef COMPILE_DL_PDO
ZEND_GET_MODULE(pdo)
#endif
/* {{{ PHP_INI */
PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("pdo.global_value", "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_pdo_globals, pdo_globals)
PHP_INI_END()
/* }}} */
/* {{{ php_pdo_init_globals */
static void php_pdo_init_globals(zend_pdo_globals *pdo_globals)
{
pdo_globals->global_value = 0;
}
/* }}} */
PDO_API int php_pdo_register_driver(pdo_driver_t *driver)
{
if (driver->api_version != PDO_DRIVER_API) {
zend_error(E_ERROR, "PDO: driver %s requires PDO API version %ld; this is PDO version %d",
driver->driver_name, driver->api_version, PDO_DRIVER_API);
return FAILURE;
}
if (!zend_hash_exists(&module_registry, "pdo", sizeof("pdo"))) {
zend_error(E_ERROR, "You MUST load PDO before loading any PDO drivers");
return FAILURE; /* NOTREACHED */
}
return zend_hash_add(&pdo_driver_hash, (char*)driver->driver_name, driver->driver_name_len,
(void**)&driver, sizeof(driver), NULL);
}
PDO_API void php_pdo_unregister_driver(pdo_driver_t *driver)
{
if (!zend_hash_exists(&module_registry, "pdo", sizeof("pdo"))) {
return;
}
zend_hash_del(&pdo_driver_hash, (char*)driver->driver_name, driver->driver_name_len);
}
pdo_driver_t *pdo_find_driver(const char *name, int namelen)
{
pdo_driver_t **driver = NULL;
zend_hash_find(&pdo_driver_hash, (char*)name, namelen, (void**)&driver);
return driver ? *driver : NULL;
}
PDO_API int php_pdo_parse_data_source(const char *data_source,
unsigned long data_source_len, struct pdo_data_src_parser *parsed,
int nparams)
{
int i, j;
int valstart = -1;
int semi = -1;
int optstart = 0;
int nlen;
int n_matches = 0;
i = 0;
while (i < data_source_len) {
/* looking for NAME= */
if (data_source[i] == '\0') {
break;
}
if (data_source[i] != '=') {
++i;
continue;
}
valstart = ++i;
/* now we're looking for VALUE; or just VALUE<NUL> */
semi = -1;
while (i < data_source_len) {
if (data_source[i] == '\0') {
semi = i++;
break;
}
if (data_source[i] == ';') {
semi = i++;
break;
}
++i;
}
if (semi == -1) {
semi = i;
}
/* find the entry in the array */
nlen = valstart - optstart - 1;
for (j = 0; j < nparams; j++) {
if (0 == strncmp(data_source + optstart, parsed[j].optname, nlen) && parsed[j].optname[nlen] == '\0') {
/* got a match */
if (parsed[j].freeme) {
efree(parsed[j].optval);
}
parsed[j].optval = estrndup(data_source + valstart, semi - valstart);
parsed[j].freeme = 1;
++n_matches;
break;
}
}
while (i < data_source_len && isspace(data_source[i])) {
i++;
}
optstart = i;
}
return n_matches;
}
/* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(pdo)
{
zend_class_entry ce;
ZEND_INIT_MODULE_GLOBALS(pdo, php_pdo_init_globals, NULL);
REGISTER_INI_ENTRIES();
if (FAILURE == pdo_sqlstate_init_error_table()) {
return FAILURE;
}
zend_hash_init(&pdo_driver_hash, 0, NULL, NULL, 1);
le_ppdo = zend_register_list_destructors_ex(NULL, php_pdo_pdbh_dtor,
"PDO persistent database", module_number);
REGISTER_LONG_CONSTANT("PDO_PARAM_NULL", (long)PDO_PARAM_NULL, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_PARAM_INT", (long)PDO_PARAM_INT, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_PARAM_STR", (long)PDO_PARAM_STR, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_PARAM_LOB", (long)PDO_PARAM_LOB, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_PARAM_STMT", (long)PDO_PARAM_STMT, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_PARAM_INPUT_OUTPUT", (long)PDO_PARAM_INPUT_OUTPUT, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_FETCH_LAZY", (long)PDO_FETCH_LAZY, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_FETCH_ASSOC",(long)PDO_FETCH_ASSOC, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_FETCH_NUM", (long)PDO_FETCH_NUM, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_FETCH_BOTH", (long)PDO_FETCH_BOTH, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_FETCH_OBJ", (long)PDO_FETCH_OBJ, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_FETCH_BOUND",(long)PDO_FETCH_BOUND, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_FETCH_COLUMN",(long)PDO_FETCH_COLUMN, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_FETCH_CLASS",(long)PDO_FETCH_CLASS, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_FETCH_INTO", (long)PDO_FETCH_INTO, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ATTR_AUTOCOMMIT", (long)PDO_ATTR_AUTOCOMMIT, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ATTR_PREFETCH", (long)PDO_ATTR_PREFETCH, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ATTR_TIMEOUT", (long)PDO_ATTR_TIMEOUT, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ATTR_ERRMODE", (long)PDO_ATTR_ERRMODE, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ATTR_SERVER_VERSION", (long)PDO_ATTR_SERVER_VERSION, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ATTR_CLIENT_VERSION", (long)PDO_ATTR_CLIENT_VERSION, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ATTR_SERVER_INFO", (long)PDO_ATTR_SERVER_INFO, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ATTR_CONNECTION_STATUS", (long)PDO_ATTR_CONNECTION_STATUS, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ATTR_CASE", (long)PDO_ATTR_CASE, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ATTR_CURSOR_NAME", (long)PDO_ATTR_CURSOR_NAME, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ATTR_CURSOR", (long)PDO_ATTR_CURSOR, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ATTR_ORACLE_NULLS", (long)PDO_ATTR_ORACLE_NULLS, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ATTR_PERSISTENT", (long)PDO_ATTR_PERSISTENT, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ERRMODE_SILENT", (long)PDO_ERRMODE_SILENT, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ERRMODE_WARNING", (long)PDO_ERRMODE_WARNING, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ERRMODE_EXCEPTION", (long)PDO_ERRMODE_EXCEPTION, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_CASE_NATURAL", (long)PDO_CASE_NATURAL, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_CASE_LOWER", (long)PDO_CASE_LOWER, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_CASE_UPPER", (long)PDO_CASE_UPPER, CONST_CS|CONST_PERSISTENT);
REGISTER_STRING_CONSTANT("PDO_ERR_NONE", PDO_ERR_NONE, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_FETCH_ORI_NEXT", (long)PDO_FETCH_ORI_NEXT, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_FETCH_ORI_PRIOR", (long)PDO_FETCH_ORI_PRIOR, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_FETCH_ORI_FIRST", (long)PDO_FETCH_ORI_FIRST, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_FETCH_ORI_LAST", (long)PDO_FETCH_ORI_LAST, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_FETCH_ORI_ABS", (long)PDO_FETCH_ORI_ABS, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_FETCH_ORI_REL", (long)PDO_FETCH_ORI_REL, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_CURSOR_FWDONLY", (long)PDO_CURSOR_FWDONLY,CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_CURSOR_SCROLL", (long)PDO_CURSOR_SCROLL,CONST_CS|CONST_PERSISTENT);
#if 0
REGISTER_LONG_CONSTANT("PDO_ERR_CANT_MAP", (long)PDO_ERR_CANT_MAP, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ERR_SYNTAX", (long)PDO_ERR_SYNTAX, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ERR_CONSTRAINT", (long)PDO_ERR_CONSTRAINT, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ERR_NOT_FOUND", (long)PDO_ERR_NOT_FOUND, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ERR_ALREADY_EXISTS", (long)PDO_ERR_ALREADY_EXISTS, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ERR_NOT_IMPLEMENTED", (long)PDO_ERR_NOT_IMPLEMENTED, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ERR_MISMATCH", (long)PDO_ERR_MISMATCH, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ERR_TRUNCATED", (long)PDO_ERR_TRUNCATED, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ERR_DISCONNECTED", (long)PDO_ERR_DISCONNECTED, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PDO_ERR_NO_PERM", (long)PDO_ERR_NO_PERM, CONST_CS|CONST_PERSISTENT);
#endif
INIT_CLASS_ENTRY(ce, "PDOException", NULL);
pdo_exception_ce = zend_register_internal_class_ex(&ce, zend_exception_get_default(), NULL TSRMLS_CC);
zend_declare_property_null(pdo_exception_ce, "errorInfo", sizeof("errorInfo")-1, ZEND_ACC_PUBLIC TSRMLS_CC);
INIT_CLASS_ENTRY(ce, "PDO", pdo_dbh_functions);
ce.create_object = pdo_dbh_new;
pdo_dbh_ce = zend_register_internal_class(&ce TSRMLS_CC);
INIT_CLASS_ENTRY(ce, "PDOStatement", pdo_dbstmt_functions);
ce.create_object = pdo_dbstmt_new;
pdo_dbstmt_ce = zend_register_internal_class(&ce TSRMLS_CC);
pdo_dbstmt_ce->get_iterator = pdo_stmt_iter_get;
INIT_CLASS_ENTRY(ce, "PDORow", pdo_row_functions);
ce.create_object = pdo_row_new;
pdo_row_ce = zend_register_internal_class(&ce TSRMLS_CC);
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MSHUTDOWN_FUNCTION */
PHP_MSHUTDOWN_FUNCTION(pdo)
{
UNREGISTER_INI_ENTRIES();
zend_hash_destroy(&pdo_driver_hash);
pdo_sqlstate_fini_error_table();
return SUCCESS;
}
/* }}} */
/* {{{ PHP_RINIT_FUNCTION */
PHP_RINIT_FUNCTION(pdo)
{
return SUCCESS;
}
/* }}} */
/* {{{ PHP_RSHUTDOWN_FUNCTION */
PHP_RSHUTDOWN_FUNCTION(pdo)
{
/* TODO: visit persistent handles: for each persistent statement handle,
* remove bound parameter associations */
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MINFO_FUNCTION */
PHP_MINFO_FUNCTION(pdo)
{
php_info_print_table_start();
php_info_print_table_header(2, "pdo support", "enabled");
php_info_print_table_end();
#if 0
DISPLAY_INI_ENTRIES();
#endif
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
-62
View File
@@ -1,62 +0,0 @@
<?php
dl('pdo.so');
dl('pdo_sqlite.so');
//$x = new PDO("oci:dbname=hostname", 'php', 'php');
$x = new PDO("sqlite::memory:");
$x->query("create table test(name string, value string)");
debug_zval_dump($x);
$stmt = $x->prepare("INSERT INTO test (NAME, VALUE) VALUES (:name, :value)");
$stmt->bindParam(":name", $the_name, PDO_PARAM_STR, 32);
$stmt->bindParam(":value", $the_value, PDO_PARAM_STR, 32);
for ($i = 0; $i < 4; $i++) {
$the_name = "foo" . rand();
$the_value = "bar" . rand();
if (!$stmt->execute()) {
break;
}
}
$stmt = null;
echo "DEFAULT:\n";
foreach ($x->query("select NAME, VALUE from test") as $row) {
print_r($row);
}
echo "OBJ:\n";
class Foo {
public $NAME = "Don't change me";
}
$foo = new foo;
foreach ($x->query("select NAME, VALUE from test", PDO_FETCH_COLUMN, 1) as $row) {
debug_zval_dump($row);
}
echo "Done\n";
exit;
$stmt = $x->prepare("select NAME, VALUE from test where value like ?");
$the_name = 'bar%';
$stmt->execute(array($the_name)) or die("failed to execute!");
$stmt->bindColumn('VALUE', $value);
while ($row = $stmt->fetch()) {
echo "name=$row[NAME] value=$row[VALUE]\n";
echo "value is $value\n";
echo "\n";
}
echo "Let's try an update\n";
echo "All done\n";
?>
-1119
View File
File diff suppressed because it is too large. Load diff
-558
View File
@@ -1,558 +0,0 @@
/* Generated by re2c 0.9.3 on Tue Feb 8 19:46:35 2005 */
#line 1 "/data/wez/pecl/pdo/pdo_sql_parser.re"
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2004 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.0 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_0.txt. |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: George Schlossnagle <george@omniti.com> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#include "php.h"
#include "php_pdo_driver.h"
#define PDO_PARSER_TEXT 1
#define PDO_PARSER_BIND 2
#define PDO_PARSER_BIND_POS 3
#define PDO_PARSER_EOI 4
#define RET(i) {s->cur = cursor; return i; }
#define YYCTYPE char
#define YYCURSOR cursor
#define YYLIMIT s->lim
#define YYMARKER s->ptr
#define YYFILL(n)
typedef struct Scanner {
char *lim, *ptr, *cur, *tok;
} Scanner;
static int scan(Scanner *s)
{
char *cursor = s->cur;
std:
s->tok = cursor;
#line 54 "/data/wez/pecl/pdo/pdo_sql_parser.re"
#line 7 "<stdout>"
{
YYCTYPE yych;
unsigned int yyaccept;
static unsigned char yybm[] = {
0, 168, 168, 168, 168, 168, 168, 168,
168, 168, 168, 168, 168, 168, 168, 168,
168, 168, 168, 168, 168, 168, 168, 168,
168, 168, 168, 168, 168, 168, 168, 168,
168, 168, 0, 168, 168, 168, 168, 192,
168, 168, 168, 168, 168, 168, 168, 168,
184, 184, 184, 184, 184, 184, 184, 184,
184, 184, 160, 168, 168, 168, 168, 160,
168, 184, 184, 184, 184, 184, 184, 184,
184, 184, 184, 184, 184, 184, 184, 184,
184, 184, 184, 184, 184, 184, 184, 184,
184, 184, 184, 168, 8, 168, 168, 184,
168, 184, 184, 184, 184, 184, 184, 184,
184, 184, 184, 184, 184, 184, 184, 184,
184, 184, 184, 184, 184, 184, 184, 184,
184, 184, 184, 168, 168, 168, 168, 168,
168, 168, 168, 168, 168, 168, 168, 168,
168, 168, 168, 168, 168, 168, 168, 168,
168, 168, 168, 168, 168, 168, 168, 168,
168, 168, 168, 168, 168, 168, 168, 168,
168, 168, 168, 168, 168, 168, 168, 168,
168, 168, 168, 168, 168, 168, 168, 168,
168, 168, 168, 168, 168, 168, 168, 168,
168, 168, 168, 168, 168, 168, 168, 168,
168, 168, 168, 168, 168, 168, 168, 168,
168, 168, 168, 168, 168, 168, 168, 168,
168, 168, 168, 168, 168, 168, 168, 168,
168, 168, 168, 168, 168, 168, 168, 168,
168, 168, 168, 168, 168, 168, 168, 168,
168, 168, 168, 168, 168, 168, 168, 168,
168, 168, 168, 168, 168, 168, 168, 168,
168, 168, 168, 168, 168, 168, 168, 168,
};
goto yy0;
yy1: ++YYCURSOR;
yy0:
if((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
yych = *YYCURSOR;
if(yybm[0+yych] & 8) goto yy8;
if(yych <= '\000') goto yy11;
if(yych <= '&') goto yy2;
if(yych <= '\'') goto yy4;
if(yych <= '>') goto yy5;
goto yy6;
yy2: yyaccept = 0;
yych = *(YYMARKER = ++YYCURSOR);
if(yych >= '\001') goto yy24;
goto yy3;
yy3:
#line 61 "/data/wez/pecl/pdo/pdo_sql_parser.re"
{ RET(PDO_PARSER_TEXT); }
#line 63 "<stdout>"
yy4: yyaccept = 0;
yych = *(YYMARKER = ++YYCURSOR);
if(yych <= '\000') goto yy3;
if(yych == '"') goto yy3;
goto yy17;
yy5: yych = *++YYCURSOR;
if(yybm[0+yych] & 16) goto yy13;
goto yy3;
yy6: ++YYCURSOR;
goto yy7;
yy7:
#line 60 "/data/wez/pecl/pdo/pdo_sql_parser.re"
{ RET(PDO_PARSER_BIND_POS); }
#line 77 "<stdout>"
yy8: ++YYCURSOR;
if(YYLIMIT == YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
goto yy9;
yy9: if(yybm[0+yych] & 8) goto yy8;
goto yy10;
yy10:
#line 62 "/data/wez/pecl/pdo/pdo_sql_parser.re"
{ RET(PDO_PARSER_TEXT); }
#line 88 "<stdout>"
yy11: ++YYCURSOR;
goto yy12;
yy12:
#line 63 "/data/wez/pecl/pdo/pdo_sql_parser.re"
{ RET(PDO_PARSER_EOI); }
#line 94 "<stdout>"
yy13: ++YYCURSOR;
if(YYLIMIT == YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
goto yy14;
yy14: if(yybm[0+yych] & 16) goto yy13;
goto yy15;
yy15:
#line 59 "/data/wez/pecl/pdo/pdo_sql_parser.re"
{ RET(PDO_PARSER_BIND); }
#line 105 "<stdout>"
yy16: ++YYCURSOR;
if(YYLIMIT == YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
goto yy17;
yy17: if(yybm[0+yych] & 32) goto yy16;
if(yych <= '&') goto yy18;
if(yych <= '\'') goto yy19;
goto yy22;
yy18: YYCURSOR = YYMARKER;
switch(yyaccept){
case 1: goto yy21;
case 0: goto yy3;
}
yy19: yyaccept = 1;
YYMARKER = ++YYCURSOR;
if(YYLIMIT == YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
goto yy20;
yy20: if(yybm[0+yych] & 32) goto yy16;
if(yych <= '&') goto yy21;
if(yych <= '\'') goto yy19;
goto yy22;
yy21:
#line 58 "/data/wez/pecl/pdo/pdo_sql_parser.re"
{ RET(PDO_PARSER_TEXT); }
#line 132 "<stdout>"
yy22: ++YYCURSOR;
if(YYLIMIT == YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
if(yych == '\'') goto yy16;
goto yy18;
yy23: ++YYCURSOR;
if(YYLIMIT == YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
goto yy24;
yy24: if(yybm[0+yych] & 128) goto yy23;
if(yych <= '\000') goto yy18;
if(yych <= '[') goto yy26;
goto yy25;
yy25: ++YYCURSOR;
if(YYLIMIT == YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
if(yych == '"') goto yy23;
goto yy18;
yy26: ++YYCURSOR;
goto yy27;
yy27:
#line 57 "/data/wez/pecl/pdo/pdo_sql_parser.re"
{ RET(PDO_PARSER_TEXT); }
#line 159 "<stdout>"
}
#line 64 "/data/wez/pecl/pdo/pdo_sql_parser.re"
}
struct placeholder {
char *pos;
int len;
int bindno;
int qlen; /* quoted length of value */
char *quoted; /* quoted value */
int freeq;
struct placeholder *next;
};
PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, int inquery_len,
char **outquery, int *outquery_len TSRMLS_DC)
{
Scanner s;
char *ptr, *newbuffer;
int t;
int bindno = 0;
int ret = 0;
int newbuffer_len;
int padding;
HashTable *params;
struct pdo_bound_param_data *param;
int query_type = PDO_PLACEHOLDER_NONE;
struct placeholder *placeholders = NULL, *placetail = NULL, *plc = NULL;
ptr = *outquery;
s.cur = inquery;
s.lim = inquery + inquery_len;
/* phase 1: look for args */
while((t = scan(&s)) != PDO_PARSER_EOI) {
if (t == PDO_PARSER_BIND || t == PDO_PARSER_BIND_POS) {
if (t == PDO_PARSER_BIND) {
query_type |= PDO_PLACEHOLDER_NAMED;
} else {
query_type |= PDO_PLACEHOLDER_POSITIONAL;
}
plc = emalloc(sizeof(*plc));
memset(plc, 0, sizeof(*plc));
plc->next = NULL;
plc->pos = s.tok;
plc->len = s.cur - s.tok;
plc->bindno = bindno++;
if (placetail) {
placetail->next = plc;
} else {
placeholders = plc;
}
placetail = plc;
}
}
if (bindno == 0) {
/* nothing to do; good! */
return 0;
}
/* did the query make sense to me? */
if (query_type == (PDO_PLACEHOLDER_NAMED|PDO_PLACEHOLDER_POSITIONAL)) {
/* they mixed both types; punt */
pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "mixed named and positional parameters" TSRMLS_CC);
return -1;
}
if (stmt->supports_placeholders == query_type) {
/* query matches native syntax */
ret = 0;
goto clean_up;
}
params = stmt->bound_params;
/* Do we have placeholders but no bound params */
if (bindno && !params) {
pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "no parameters were bound" TSRMLS_CC);
ret = -1;
goto clean_up;
}
/* what are we going to do ? */
if (stmt->supports_placeholders == PDO_PLACEHOLDER_NONE) {
/* query generation */
newbuffer_len = inquery_len;
/* let's quote all the values */
for (plc = placeholders; plc; plc = plc->next) {
if (query_type == PDO_PLACEHOLDER_POSITIONAL) {
ret = zend_hash_index_find(params, plc->bindno, (void**) &param);
} else {
ret = zend_hash_find(params, plc->pos, plc->len, (void**) &param);
}
if (ret == FAILURE) {
/* parameter was not defined */
ret = -1;
pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined" TSRMLS_CC);
goto clean_up;
}
if (stmt->dbh->methods->quoter) {
if (param->param_type == PDO_PARAM_LOB && Z_TYPE_P(param->parameter) == IS_RESOURCE) {
php_stream *stm;
php_stream_from_zval_no_verify(stm, &param->parameter);
if (stm) {
size_t len;
char *buf = NULL;
len = php_stream_copy_to_mem(stm, &buf, PHP_STREAM_COPY_ALL, 0);
if (!stmt->dbh->methods->quoter(stmt->dbh, buf, len, &plc->quoted, &plc->qlen,
param->param_type TSRMLS_CC)) {
/* bork */
ret = -1;
strcpy(stmt->error_code, stmt->dbh->error_code);
efree(buf);
goto clean_up;
}
efree(buf);
} else {
pdo_raise_impl_error(stmt->dbh, stmt, "HY105", "Expected a stream resource" TSRMLS_CC);
ret = -1;
goto clean_up;
}
} else {
convert_to_string(param->parameter);
if (!stmt->dbh->methods->quoter(stmt->dbh, Z_STRVAL_P(param->parameter),
Z_STRLEN_P(param->parameter), &plc->quoted, &plc->qlen,
param->param_type TSRMLS_CC)) {
/* bork */
ret = -1;
strcpy(stmt->error_code, stmt->dbh->error_code);
goto clean_up;
}
}
plc->freeq = 1;
} else {
plc->quoted = Z_STRVAL_P(param->parameter);
plc->qlen = Z_STRLEN_P(param->parameter);
}
newbuffer_len += plc->qlen;
}
rewrite:
/* allocate output buffer */
newbuffer = emalloc(newbuffer_len + 1);
*outquery = newbuffer;
/* and build the query */
plc = placeholders;
ptr = inquery;
do {
t = plc->pos - ptr;
if (t) {
memcpy(newbuffer, ptr, t);
newbuffer += t;
}
memcpy(newbuffer, plc->quoted, plc->qlen);
newbuffer += plc->qlen;
ptr = plc->pos + plc->len;
plc = plc->next;
} while (plc);
t = (inquery + inquery_len) - ptr;
if (t) {
memcpy(newbuffer, ptr, t);
newbuffer += t;
}
*newbuffer = '\0';
*outquery_len = newbuffer - *outquery;
ret = 1;
goto clean_up;
} else if (query_type == PDO_PLACEHOLDER_POSITIONAL) {
/* rewrite ? to :pdoX */
char idxbuf[32];
newbuffer_len = inquery_len;
for (plc = placeholders; plc; plc = plc->next) {
snprintf(idxbuf, sizeof(idxbuf), ":pdo%d", plc->bindno);
plc->quoted = estrdup(idxbuf);
plc->qlen = strlen(plc->quoted);
plc->freeq = 1;
newbuffer_len += plc->qlen;
}
goto rewrite;
} else {
/* rewrite :name to ? */
/* HARD!. We need to remember the mapping and bind those positions. */
pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "cannot map :name to ? in this version" TSRMLS_CC);
ret = -1;
}
clean_up:
while (placeholders) {
plc = placeholders;
placeholders = plc->next;
if (plc->freeq) {
efree(plc->quoted);
}
efree(plc);
}
return ret;
}
#if 0
int old_pdo_parse_params(pdo_stmt_t *stmt, char *inquery, int inquery_len, char **outquery,
int *outquery_len TSRMLS_DC)
{
Scanner s;
char *ptr;
int t;
int bindno = 0;
int newbuffer_len;
int padding;
HashTable *params = stmt->bound_params;
struct pdo_bound_param_data *param;
/* allocate buffer for query with expanded binds, ptr is our writing pointer */
newbuffer_len = inquery_len;
/* calculate the possible padding factor due to quoting */
if(stmt->dbh->max_escaped_char_length) {
padding = stmt->dbh->max_escaped_char_length;
} else {
padding = 3;
}
if(params) {
zend_hash_internal_pointer_reset(params);
while (SUCCESS == zend_hash_get_current_data(params, (void**)&param)) {
if(param->parameter) {
convert_to_string(param->parameter);
/* accomodate a string that needs to be fully quoted
bind placeholders are at least 2 characters, so
the accomodate their own "'s
*/
newbuffer_len += padding * Z_STRLEN_P(param->parameter);
}
zend_hash_move_forward(params);
}
}
*outquery = (char *) emalloc(newbuffer_len + 1);
*outquery_len = 0;
ptr = *outquery;
s.cur = inquery;
s.lim = inquery + inquery_len;
while((t = scan(&s)) != PDO_PARSER_EOI) {
if(t == PDO_PARSER_TEXT) {
memcpy(ptr, s.tok, s.cur - s.tok);
ptr += (s.cur - s.tok);
*outquery_len += (s.cur - s.tok);
}
else if(t == PDO_PARSER_BIND) {
if(!params) {
/* error */
efree(*outquery);
*outquery = NULL;
return (int) (s.cur - inquery);
}
/* lookup bind first via hash and then index */
/* stupid keys need to be null-terminated, even though we know their length */
if((SUCCESS == zend_hash_find(params, s.tok, s.cur-s.tok,(void **)&param))
||
(SUCCESS == zend_hash_index_find(params, bindno, (void **)&param)))
{
char *quotedstr;
int quotedstrlen;
/* restore the in-string key, doesn't need null-termination here */
/* currently everything is a string here */
/* quote the bind value if necessary */
if(stmt->dbh->methods->quoter(stmt->dbh, Z_STRVAL_P(param->parameter),
Z_STRLEN_P(param->parameter), &quotedstr, &quotedstrlen TSRMLS_CC))
{
memcpy(ptr, quotedstr, quotedstrlen);
ptr += quotedstrlen;
*outquery_len += quotedstrlen;
efree(quotedstr);
} else {
memcpy(ptr, Z_STRVAL_P(param->parameter), Z_STRLEN_P(param->parameter));
ptr += Z_STRLEN_P(param->parameter);
*outquery_len += (Z_STRLEN_P(param->parameter));
}
}
else {
/* error and cleanup */
efree(*outquery);
*outquery = NULL;
return (int) (s.cur - inquery);
}
bindno++;
}
else if(t == PDO_PARSER_BIND_POS) {
if(!params) {
/* error */
efree(*outquery);
*outquery = NULL;
return (int) (s.cur - inquery);
}
/* lookup bind by index */
if(SUCCESS == zend_hash_index_find(params, bindno, (void **)&param))
{
char *quotedstr;
int quotedstrlen;
/* currently everything is a string here */
/* quote the bind value if necessary */
if(stmt->dbh->methods->quoter(stmt->dbh, Z_STRVAL_P(param->parameter),
Z_STRLEN_P(param->parameter), &quotedstr, &quotedstrlen TSRMLS_CC))
{
memcpy(ptr, quotedstr, quotedstrlen);
ptr += quotedstrlen;
*outquery_len += quotedstrlen;
efree(quotedstr);
} else {
memcpy(ptr, Z_STRVAL_P(param->parameter), Z_STRLEN_P(param->parameter));
ptr += Z_STRLEN_P(param->parameter);
*outquery_len += (Z_STRLEN_P(param->parameter));
}
}
else {
/* error and cleanup */
efree(*outquery);
*outquery = NULL;
return (int) (s.cur - inquery);
}
bindno++;
}
}
*ptr = '\0';
return 0;
}
#endif
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker ft=c
* vim<600: noet sw=4 ts=4
*/
-420
View File
@@ -1,420 +0,0 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2004 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.0 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_0.txt. |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: George Schlossnagle <george@omniti.com> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#include "php.h"
#include "php_pdo_driver.h"
#define PDO_PARSER_TEXT 1
#define PDO_PARSER_BIND 2
#define PDO_PARSER_BIND_POS 3
#define PDO_PARSER_EOI 4
#define RET(i) {s->cur = cursor; return i; }
#define YYCTYPE char
#define YYCURSOR cursor
#define YYLIMIT s->lim
#define YYMARKER s->ptr
#define YYFILL(n)
typedef struct Scanner {
char *lim, *ptr, *cur, *tok;
} Scanner;
static int scan(Scanner *s)
{
char *cursor = s->cur;
std:
s->tok = cursor;
/*!re2c
BINDCHR = [:][a-zA-Z0-9_]+;
QUESTION = [?];
SPECIALS = [:?"'];
ESCQQ = [\\]["];
ESCQ = [\\]['];
EOF = [\000];
ANYNOEOF = [\001-\377];
*/
/*!re2c
(["] (ESCQQ|ANYNOEOF\[\\"])* ["]) { RET(PDO_PARSER_TEXT); }
(['] (ESCQ|ANYNOEOF\[\\"])* [']) { RET(PDO_PARSER_TEXT); }
BINDCHR { RET(PDO_PARSER_BIND); }
QUESTION { RET(PDO_PARSER_BIND_POS); }
SPECIALS { RET(PDO_PARSER_TEXT); }
(ANYNOEOF\SPECIALS)+ { RET(PDO_PARSER_TEXT); }
EOF { RET(PDO_PARSER_EOI); }
*/
}
struct placeholder {
char *pos;
int len;
int bindno;
int qlen; /* quoted length of value */
char *quoted; /* quoted value */
int freeq;
struct placeholder *next;
};
PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, int inquery_len,
char **outquery, int *outquery_len TSRMLS_DC)
{
Scanner s;
char *ptr, *newbuffer;
int t;
int bindno = 0;
int ret = 0;
int newbuffer_len;
HashTable *params;
struct pdo_bound_param_data *param;
int query_type = PDO_PLACEHOLDER_NONE;
struct placeholder *placeholders = NULL, *placetail = NULL, *plc = NULL;
ptr = *outquery;
s.cur = inquery;
s.lim = inquery + inquery_len;
/* phase 1: look for args */
while((t = scan(&s)) != PDO_PARSER_EOI) {
if (t == PDO_PARSER_BIND || t == PDO_PARSER_BIND_POS) {
if (t == PDO_PARSER_BIND) {
query_type |= PDO_PLACEHOLDER_NAMED;
} else {
query_type |= PDO_PLACEHOLDER_POSITIONAL;
}
plc = emalloc(sizeof(*plc));
memset(plc, 0, sizeof(*plc));
plc->next = NULL;
plc->pos = s.tok;
plc->len = s.cur - s.tok;
plc->bindno = bindno++;
if (placetail) {
placetail->next = plc;
} else {
placeholders = plc;
}
placetail = plc;
}
}
if (bindno == 0) {
/* nothing to do; good! */
return 0;
}
/* did the query make sense to me? */
if (query_type == (PDO_PLACEHOLDER_NAMED|PDO_PLACEHOLDER_POSITIONAL)) {
/* they mixed both types; punt */
pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "mixed named and positional parameters" TSRMLS_CC);
return -1;
}
if (stmt->supports_placeholders == query_type) {
/* query matches native syntax */
ret = 0;
goto clean_up;
}
params = stmt->bound_params;
/* Do we have placeholders but no bound params */
if (bindno && !params) {
pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "no parameters were bound" TSRMLS_CC);
ret = -1;
goto clean_up;
}
/* what are we going to do ? */
if (stmt->supports_placeholders == PDO_PLACEHOLDER_NONE) {
/* query generation */
newbuffer_len = inquery_len;
/* let's quote all the values */
for (plc = placeholders; plc; plc = plc->next) {
if (query_type == PDO_PLACEHOLDER_POSITIONAL) {
ret = zend_hash_index_find(params, plc->bindno, (void**) &param);
} else {
ret = zend_hash_find(params, plc->pos, plc->len, (void**) &param);
}
if (ret == FAILURE) {
/* parameter was not defined */
ret = -1;
pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined" TSRMLS_CC);
goto clean_up;
}
if (stmt->dbh->methods->quoter) {
if (param->param_type == PDO_PARAM_LOB && Z_TYPE_P(param->parameter) == IS_RESOURCE) {
php_stream *stm;
php_stream_from_zval_no_verify(stm, &param->parameter);
if (stm) {
size_t len;
char *buf = NULL;
len = php_stream_copy_to_mem(stm, &buf, PHP_STREAM_COPY_ALL, 0);
if (!stmt->dbh->methods->quoter(stmt->dbh, buf, len, &plc->quoted, &plc->qlen,
param->param_type TSRMLS_CC)) {
/* bork */
ret = -1;
strcpy(stmt->error_code, stmt->dbh->error_code);
efree(buf);
goto clean_up;
}
efree(buf);
} else {
pdo_raise_impl_error(stmt->dbh, stmt, "HY105", "Expected a stream resource" TSRMLS_CC);
ret = -1;
goto clean_up;
}
} else {
convert_to_string(param->parameter);
if (!stmt->dbh->methods->quoter(stmt->dbh, Z_STRVAL_P(param->parameter),
Z_STRLEN_P(param->parameter), &plc->quoted, &plc->qlen,
param->param_type TSRMLS_CC)) {
/* bork */
ret = -1;
strcpy(stmt->error_code, stmt->dbh->error_code);
goto clean_up;
}
}
plc->freeq = 1;
} else {
plc->quoted = Z_STRVAL_P(param->parameter);
plc->qlen = Z_STRLEN_P(param->parameter);
}
newbuffer_len += plc->qlen;
}
rewrite:
/* allocate output buffer */
newbuffer = emalloc(newbuffer_len + 1);
*outquery = newbuffer;
/* and build the query */
plc = placeholders;
ptr = inquery;
do {
t = plc->pos - ptr;
if (t) {
memcpy(newbuffer, ptr, t);
newbuffer += t;
}
memcpy(newbuffer, plc->quoted, plc->qlen);
newbuffer += plc->qlen;
ptr = plc->pos + plc->len;
plc = plc->next;
} while (plc);
t = (inquery + inquery_len) - ptr;
if (t) {
memcpy(newbuffer, ptr, t);
newbuffer += t;
}
*newbuffer = '\0';
*outquery_len = newbuffer - *outquery;
ret = 1;
goto clean_up;
} else if (query_type == PDO_PLACEHOLDER_POSITIONAL) {
/* rewrite ? to :pdoX */
char idxbuf[32];
newbuffer_len = inquery_len;
for (plc = placeholders; plc; plc = plc->next) {
snprintf(idxbuf, sizeof(idxbuf), ":pdo%d", plc->bindno);
plc->quoted = estrdup(idxbuf);
plc->qlen = strlen(plc->quoted);
plc->freeq = 1;
newbuffer_len += plc->qlen;
}
goto rewrite;
} else {
/* rewrite :name to ? */
/* HARD!. We need to remember the mapping and bind those positions. */
pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "cannot map :name to ? in this version" TSRMLS_CC);
ret = -1;
}
clean_up:
while (placeholders) {
plc = placeholders;
placeholders = plc->next;
if (plc->freeq) {
efree(plc->quoted);
}
efree(plc);
}
return ret;
}
#if 0
int old_pdo_parse_params(pdo_stmt_t *stmt, char *inquery, int inquery_len, char **outquery,
int *outquery_len TSRMLS_DC)
{
Scanner s;
char *ptr;
int t;
int bindno = 0;
int newbuffer_len;
int padding;
HashTable *params = stmt->bound_params;
struct pdo_bound_param_data *param;
/* allocate buffer for query with expanded binds, ptr is our writing pointer */
newbuffer_len = inquery_len;
/* calculate the possible padding factor due to quoting */
if(stmt->dbh->max_escaped_char_length) {
padding = stmt->dbh->max_escaped_char_length;
} else {
padding = 3;
}
if(params) {
zend_hash_internal_pointer_reset(params);
while (SUCCESS == zend_hash_get_current_data(params, (void**)&param)) {
if(param->parameter) {
convert_to_string(param->parameter);
/* accomodate a string that needs to be fully quoted
bind placeholders are at least 2 characters, so
the accomodate their own "'s
*/
newbuffer_len += padding * Z_STRLEN_P(param->parameter);
}
zend_hash_move_forward(params);
}
}
*outquery = (char *) emalloc(newbuffer_len + 1);
*outquery_len = 0;
ptr = *outquery;
s.cur = inquery;
s.lim = inquery + inquery_len;
while((t = scan(&s)) != PDO_PARSER_EOI) {
if(t == PDO_PARSER_TEXT) {
memcpy(ptr, s.tok, s.cur - s.tok);
ptr += (s.cur - s.tok);
*outquery_len += (s.cur - s.tok);
}
else if(t == PDO_PARSER_BIND) {
if(!params) {
/* error */
efree(*outquery);
*outquery = NULL;
return (int) (s.cur - inquery);
}
/* lookup bind first via hash and then index */
/* stupid keys need to be null-terminated, even though we know their length */
if((SUCCESS == zend_hash_find(params, s.tok, s.cur-s.tok,(void **)&param))
||
(SUCCESS == zend_hash_index_find(params, bindno, (void **)&param)))
{
char *quotedstr;
int quotedstrlen;
/* restore the in-string key, doesn't need null-termination here */
/* currently everything is a string here */
/* quote the bind value if necessary */
if(stmt->dbh->methods->quoter(stmt->dbh, Z_STRVAL_P(param->parameter),
Z_STRLEN_P(param->parameter), &quotedstr, &quotedstrlen TSRMLS_CC))
{
memcpy(ptr, quotedstr, quotedstrlen);
ptr += quotedstrlen;
*outquery_len += quotedstrlen;
efree(quotedstr);
} else {
memcpy(ptr, Z_STRVAL_P(param->parameter), Z_STRLEN_P(param->parameter));
ptr += Z_STRLEN_P(param->parameter);
*outquery_len += (Z_STRLEN_P(param->parameter));
}
}
else {
/* error and cleanup */
efree(*outquery);
*outquery = NULL;
return (int) (s.cur - inquery);
}
bindno++;
}
else if(t == PDO_PARSER_BIND_POS) {
if(!params) {
/* error */
efree(*outquery);
*outquery = NULL;
return (int) (s.cur - inquery);
}
/* lookup bind by index */
if(SUCCESS == zend_hash_index_find(params, bindno, (void **)&param))
{
char *quotedstr;
int quotedstrlen;
/* currently everything is a string here */
/* quote the bind value if necessary */
if(stmt->dbh->methods->quoter(stmt->dbh, Z_STRVAL_P(param->parameter),
Z_STRLEN_P(param->parameter), &quotedstr, &quotedstrlen TSRMLS_CC))
{
memcpy(ptr, quotedstr, quotedstrlen);
ptr += quotedstrlen;
*outquery_len += quotedstrlen;
efree(quotedstr);
} else {
memcpy(ptr, Z_STRVAL_P(param->parameter), Z_STRLEN_P(param->parameter));
ptr += Z_STRLEN_P(param->parameter);
*outquery_len += (Z_STRLEN_P(param->parameter));
}
}
else {
/* error and cleanup */
efree(*outquery);
*outquery = NULL;
return (int) (s.cur - inquery);
}
bindno++;
}
}
*ptr = '\0';
return 0;
}
#endif
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker ft=c
* vim<600: noet sw=4 ts=4
*/
-190
View File
@@ -1,190 +0,0 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2005 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.0 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_0.txt. |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Wez Furlong <wez@php.net> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_pdo.h"
#include "php_pdo_driver.h"
struct pdo_sqlstate_info {
char state[6];
const char *desc;
};
static HashTable err_hash;
static struct pdo_sqlstate_info err_initializer[] = {
{ "00000", "No error" },
{ "01001", "Cursor operation conflict" },
{ "01002", "Disconnect error" },
{ "01003", "NULL value eliminated in set function" },
{ "01004", "String data, right truncated" },
{ "01006", "Privilege not revoked" },
{ "01007", "Privilege not granted" },
{ "01S00", "Invalid connection string attribute" },
{ "01S01", "Error in row" },
{ "01S02", "Option value changed" },
{ "01S06", "Attempt to fetch before the result set returned the first rowset" },
{ "01S07", "Fractional truncation" },
{ "01S08", "Error saving File DSN" },
{ "01S09", "Invalid keyword" },
{ "07002", "COUNT field incorrect" },
{ "07005", "Prepared statement not a cursor-specification" },
{ "07006", "Restricted data type attribute violation" },
{ "07009", "Invalid descriptor index" },
{ "07S01", "Invalid use of default parameter" },
{ "08001", "Client unable to establish connection" },
{ "08002", "Connection name in use" },
{ "08003", "Connection does not exist" },
{ "08004", "Server rejected the connection" },
{ "08007", "Connection failure during transaction" },
{ "08S01", "Communication link failure" },
{ "21S01", "Insert value list does not match column list" },
{ "21S02", "Degree of derived table does not match column list" },
{ "22001", "String data, right truncated" },
{ "22002", "Indicator variable required but not supplied" },
{ "22003", "Numeric value out of range" },
{ "22007", "Invalid datetime format" },
{ "22008", "Datetime field overflow" },
{ "22012", "Division by zero" },
{ "22015", "Interval field overflow" },
{ "22018", "Invalid character value for cast specification" },
{ "22019", "Invalid escape character" },
{ "22025", "Invalid escape sequence" },
{ "22026", "String data, length mismatch" },
{ "23000", "Integrity constraint violation" },
{ "24000", "Invalid cursor state" },
{ "25000", "Invalid transaction state" },
{ "25S01", "Transaction state" },
{ "25S02", "Transaction is still active" },
{ "25S03", "Transaction is rolled back" },
{ "28000", "Invalid authorization specification" },
{ "34000", "Invalid cursor name" },
{ "3C000", "Duplicate cursor name" },
{ "3D000", "Invalid catalog name" },
{ "3F000", "Invalid schema name" },
{ "40001", "Serialization failure" },
{ "40003", "Statement completion unknown" },
{ "42000", "Syntax error or access violation" },
{ "42S01", "Base table or view already exists" },
{ "42S02", "Base table or view not found" },
{ "42S11", "Index already exists" },
{ "42S12", "Index not found" },
{ "42S21", "Column already exists" },
{ "42S22", "Column not found" },
{ "44000", "WITH CHECK OPTION violation" },
{ "HY000", "General error" },
{ "HY001", "Memory allocation error" },
{ "HY003", "Invalid application buffer type" },
{ "HY004", "Invalid SQL data type" },
{ "HY007", "Associated statement is not prepared" },
{ "HY008", "Operation canceled" },
{ "HY009", "Invalid use of null pointer" },
{ "HY010", "Function sequence error" },
{ "HY011", "Attribute cannot be set now" },
{ "HY012", "Invalid transaction operation code" },
{ "HY013", "Memory management error" },
{ "HY014", "Limit on the number of handles exceeded" },
{ "HY015", "No cursor name available" },
{ "HY016", "Cannot modify an implementation row descriptor" },
{ "HY017", "Invalid use of an automatically allocated descriptor handle" },
{ "HY018", "Server declined cancel request" },
{ "HY019", "Non-character and non-binary data sent in pieces" },
{ "HY020", "Attempt to concatenate a null value" },
{ "HY021", "Inconsistent descriptor information" },
{ "HY024", "Invalid attribute value" },
{ "HY090", "Invalid string or buffer length" },
{ "HY091", "Invalid descriptor field identifier" },
{ "HY092", "Invalid attribute/option identifier" },
{ "HY093", "Invalid parameter number" },
{ "HY095", "Function type out of range" },
{ "HY096", "Invalid information type" },
{ "HY097", "Column type out of range" },
{ "HY098", "Scope type out of range" },
{ "HY099", "Nullable type out of range" },
{ "HY100", "Uniqueness option type out of range" },
{ "HY101", "Accuracy option type out of range" },
{ "HY103", "Invalid retrieval code" },
{ "HY104", "Invalid precision or scale value" },
{ "HY105", "Invalid parameter type" },
{ "HY106", "Fetch type out of range" },
{ "HY107", "Row value out of range" },
{ "HY109", "Invalid cursor position" },
{ "HY110", "Invalid driver completion" },
{ "HY111", "Invalid bookmark value" },
{ "HYC00", "Optional feature not implemented" },
{ "HYT00", "Timeout expired" },
{ "HYT01", "Connection timeout expired" },
{ "IM001", "Driver does not support this function" },
{ "IM002", "Data source name not found and no default driver specified" },
{ "IM003", "Specified driver could not be loaded" },
{ "IM004", "Driver's SQLAllocHandle on SQL_HANDLE_ENV failed" },
{ "IM005", "Driver's SQLAllocHandle on SQL_HANDLE_DBC failed" },
{ "IM006", "Driver's SQLSetConnectAttr failed" },
{ "IM007", "No data source or driver specified; dialog prohibited" },
{ "IM008", "Dialog failed" },
{ "IM009", "Unable to load translation DLL" },
{ "IM010", "Data source name too long" },
{ "IM011", "Driver name too long" },
{ "IM012", "DRIVER keyword syntax error" },
{ "IM013", "Trace file error" },
{ "IM014", "Invalid name of File DSN" },
{ "IM015", "Corrupt file data source" }
};
void pdo_sqlstate_fini_error_table(void)
{
zend_hash_destroy(&err_hash);
}
int pdo_sqlstate_init_error_table(void)
{
int i;
struct pdo_sqlstate_info *info;
if (FAILURE == zend_hash_init(&err_hash,
sizeof(err_initializer)/sizeof(err_initializer[0]), NULL, NULL, 1)) {
return FAILURE;
}
for (i = 0; i < sizeof(err_initializer)/sizeof(err_initializer[0]); i++) {
info = &err_initializer[i];
zend_hash_add(&err_hash, info->state, sizeof(info->state), &info, sizeof(info), NULL);
}
return SUCCESS;
}
const char *pdo_sqlstate_state_to_description(char *state)
{
struct pdo_sqlstate_info **info;
if (SUCCESS == zend_hash_find(&err_hash, state, sizeof(err_initializer[0].state),
(void**)&info)) {
return (*info)->desc;
}
return NULL;
}
-1586
View File
File diff suppressed because it is too large. Load diff
-71
View File
@@ -1,71 +0,0 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2005 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.0 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_0.txt. |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Wez Furlong <wez@php.net> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifndef PHP_PDO_H
#define PHP_PDO_H
#include "zend.h"
extern zend_module_entry pdo_module_entry;
#define phpext_pdo_ptr &pdo_module_entry
#ifdef PHP_WIN32
# ifdef PDO_EXPORTS
# define PDO_API __declspec(dllexport)
# elif defined(COMPILE_DL_PDO)
# define PDO_API __declspec(dllimport)
# else
# define PDO_API /* nothing special */
# endif
#else
# define PDO_API /* nothing special */
#endif
#ifdef ZTS
# include "TSRM.h"
#endif
PHP_MINIT_FUNCTION(pdo);
PHP_MSHUTDOWN_FUNCTION(pdo);
PHP_RINIT_FUNCTION(pdo);
PHP_RSHUTDOWN_FUNCTION(pdo);
PHP_MINFO_FUNCTION(pdo);
ZEND_BEGIN_MODULE_GLOBALS(pdo)
long global_value;
ZEND_END_MODULE_GLOBALS(pdo)
#ifdef ZTS
# define PDOG(v) TSRMG(pdo_globals_id, zend_pdo_globals *, v)
#else
# define PDOG(v) (pdo_globals.v)
#endif
#endif /* PHP_PDO_H */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
-571
View File
@@ -1,571 +0,0 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2005 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.0 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_0.txt. |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Wez Furlong <wez@php.net> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifndef PHP_PDO_DRIVER_H
#define PHP_PDO_DRIVER_H
#include "php_pdo.h"
/* forward declarations */
typedef struct _pdo_dbh_t pdo_dbh_t;
typedef struct _pdo_stmt_t pdo_stmt_t;
struct pdo_bound_param_data;
#ifndef TRUE
# define TRUE 1
#endif
#ifndef FALSE
# define FALSE 0
#endif
#define PDO_DRIVER_API 20050206
enum pdo_param_type {
PDO_PARAM_NULL,
/* int as in long (the php native int type).
* If you mark a column as an int, PDO expects get_col to return
* a pointer to a long */
PDO_PARAM_INT,
/* get_col ptr should point to start of the string buffer */
PDO_PARAM_STR,
/* get_col: when len is 0 ptr should point to a php_stream *,
* otherwise it should behave like a string. Indicate a NULL field
* value by setting the ptr to NULL */
PDO_PARAM_LOB,
/* get_col: will expect the ptr to point to a new PDOStatement object handle,
* but this isn't wired up yet */
PDO_PARAM_STMT, /* hierarchical result set */
/* get_col ptr should point to a zend_bool */
PDO_PARAM_BOOL,
/* magic flag to denote a parameter as being input/output */
PDO_PARAM_INPUT_OUTPUT = 0x80000000
};
#define PDO_PARAM_TYPE(x) ((x) & ~PDO_PARAM_INPUT_OUTPUT)
enum pdo_fetch_type {
PDO_FETCH_USE_DEFAULT,
PDO_FETCH_LAZY,
PDO_FETCH_ASSOC,
PDO_FETCH_NUM,
PDO_FETCH_BOTH,
PDO_FETCH_OBJ,
PDO_FETCH_BOUND, /* return true/false only; rely on bound columns */
PDO_FETCH_COLUMN, /* fetch a numbered column only */
PDO_FETCH_CLASS, /* create an instance of named class, call ctor and set properties */
PDO_FETCH_INTO, /* fetch row into an existing object */
PDO_FETCH__MAX /* must be last */
};
/* fetch orientation for scrollable cursors */
enum pdo_fetch_orientation {
PDO_FETCH_ORI_NEXT, /* default: fetch the next available row */
PDO_FETCH_ORI_PRIOR, /* scroll back to prior row and fetch that */
PDO_FETCH_ORI_FIRST, /* scroll to the first row and fetch that */
PDO_FETCH_ORI_LAST, /* scroll to the last row and fetch that */
PDO_FETCH_ORI_ABS, /* scroll to an absolute numbered row and fetch that */
PDO_FETCH_ORI_REL, /* scroll relative to the current row, and fetch that */
};
enum pdo_attribute_type {
PDO_ATTR_AUTOCOMMIT, /* use to turn on or off auto-commit mode */
PDO_ATTR_PREFETCH, /* configure the prefetch size for drivers that support it. Size is in KB */
PDO_ATTR_TIMEOUT, /* connection timeout in seconds */
PDO_ATTR_ERRMODE, /* control how errors are handled */
PDO_ATTR_SERVER_VERSION, /* database server version */
PDO_ATTR_CLIENT_VERSION, /* client library version */
PDO_ATTR_SERVER_INFO, /* server information */
PDO_ATTR_CONNECTION_STATUS, /* connection status */
PDO_ATTR_CASE, /* control case folding for portability */
PDO_ATTR_CURSOR_NAME, /* name a cursor for use in "WHERE CURRENT OF <name>" */
PDO_ATTR_CURSOR, /* cursor type */
PDO_ATTR_ORACLE_NULLS, /* convert empty strings to NULL */
PDO_ATTR_PERSISTENT, /* pconnect style connection */
/* this defines the start of the range for driver specific options.
* Drivers should define their own attribute constants beginning with this
* value. */
PDO_ATTR_DRIVER_SPECIFIC = 1000
};
enum pdo_cursor_type {
PDO_CURSOR_FWDONLY, /* forward only cursor (default) */
PDO_CURSOR_SCROLL, /* scrollable cursor */
};
/* SQL-92 SQLSTATE error codes.
The character string value returned for an SQLSTATE consists of a two-character
class value followed by a three-character subclass value. A class value of 01
indicates a warning and is accompanied by a return code of
SQL_SUCCESS_WITH_INFO.
Class values other than '01', except for the class 'IM',
indicate an error and are accompanied by a return code of SQL_ERROR. The class
'IM' is specific to warnings and errors that derive from the implementation of
ODBC itself.
The subclass value '000' in any class indicates that there is no
subclass for that SQLSTATE. The assignment of class and subclass values is
defined by SQL-92.
*/
typedef char pdo_error_type[6]; /* SQLSTATE */
#define PDO_ERR_NONE "00000"
#if 0
/* generic error code values.
* Don't want to go overboard with these.
* */
#define PDO_ERR_SYNTAX "42000"
#define PDO_ERR_CONSTRAINT "23000"
#define PDO_ERR_NOT_FOUND ""
#define PDO_ERR_ALREADY_EXISTS,
#define PDO_ERR_NOT_IMPLEMENTED,
#define PDO_ERR_MISMATCH,
#define PDO_ERR_TRUNCATED,
#define PDO_ERR_DISCONNECTED,
#define PDO_ERR_NO_PERM,
PDO_ERR_CANT_MAP, /* no way to map native error to the generic
* codes; consult the native error for more info */
};
#endif
enum pdo_error_mode {
PDO_ERRMODE_SILENT, /* just set error codes */
PDO_ERRMODE_WARNING, /* raise E_WARNING */
PDO_ERRMODE_EXCEPTION, /* throw exceptions */
};
enum pdo_case_conversion {
PDO_CASE_NATURAL,
PDO_CASE_UPPER,
PDO_CASE_LOWER
};
/* {{{ utils for reading attributes set as driver_options */
static inline long pdo_attr_lval(zval *options, enum pdo_fetch_type option_name, long defval TSRMLS_DC)
{
zval **v;
if (options && SUCCESS == zend_hash_index_find(Z_ARRVAL_P(options), option_name, (void**)&v)) {
convert_to_long_ex(v);
return Z_LVAL_PP(v);
}
return defval;
}
/* }}} */
/* This structure is registered with PDO when a PDO driver extension is
* initialized */
typedef struct {
const char *driver_name;
unsigned long driver_name_len;
unsigned long api_version; /* needs to be compatible with PDO */
#define PDO_DRIVER_HEADER(name) \
#name, sizeof(#name)-1, \
PDO_DRIVER_API
/* create driver specific portion of the database handle and stash it into
* the dbh. dbh contains the data source string and flags for this
* instance. You MUST respect dbh->is_persistent and pass that flag to
* pemalloc() for all allocations that are stored in the dbh or your instance
* data in the db, otherwise you will crash PHP when persistent connections
* are used.
*/
int (*db_handle_factory)(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC);
} pdo_driver_t;
/* {{{ methods for a database handle */
/* close or otherwise disconnect the database */
typedef int (*pdo_dbh_close_func)(pdo_dbh_t *dbh TSRMLS_DC);
/* prepare a statement and stash driver specific portion into stmt */
typedef int (*pdo_dbh_prepare_func)(pdo_dbh_t *dbh, const char *sql, long sql_len, pdo_stmt_t *stmt, zval *driver_options TSRMLS_DC);
/* execute a statement (that does not return a result set) */
typedef long (*pdo_dbh_do_func)(pdo_dbh_t *dbh, const char *sql, long sql_len TSRMLS_DC);
/* quote a string */
typedef int (*pdo_dbh_quote_func)(pdo_dbh_t *dbh, const char *unquoted, int unquotedlen, char **quoted, int *quotedlen, enum pdo_param_type paramtype TSRMLS_DC);
/* transaction related */
typedef int (*pdo_dbh_txn_func)(pdo_dbh_t *dbh TSRMLS_DC);
/* setting of attributes */
typedef int (*pdo_dbh_set_attr_func)(pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC);
/* return last insert id */
typedef long (*pdo_dbh_last_id_func)(pdo_dbh_t *dbh TSRMLS_DC);
/* fetch error information. if stmt is not null, fetch information pertaining
* to the statement, otherwise fetch global error information. The driver
* should add the following information to the array "info" in this order:
* - native error code
* - string representation of the error code ... any other optional driver
* specific data ... */
typedef int (*pdo_dbh_fetch_error_func)(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info TSRMLS_DC);
/* fetching of attributes */
typedef int (*pdo_dbh_get_attr_func)(pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC);
/* checking/pinging persistent connections; return SUCCESS if the connection
* is still alive and ready to be used, FAILURE otherwise.
* You may set this handler to NULL, which is equivalent to returning SUCCESS. */
typedef int (*pdo_dbh_check_liveness_func)(pdo_dbh_t *dbh TSRMLS_DC);
/* for adding methods to the dbh or stmt objects
pointer to a list of driver specific functions. The convention is
to prefix the function names using the PDO driver name; this will
reduce the chance of collisions with future functionality in the
PDO class or in user code (they can extend the PDO object).
*/
enum {
PDO_DBH_DRIVER_METHOD_KIND_DBH = 0,
PDO_DBH_DRIVER_METHOD_KIND_STMT,
PDO_DBH_DRIVER_METHOD_KIND__MAX
};
typedef function_entry *(*pdo_dbh_get_driver_methods_func)(pdo_dbh_t *dbh, int kind TSRMLS_DC);
struct pdo_dbh_methods {
pdo_dbh_close_func closer;
pdo_dbh_prepare_func preparer;
pdo_dbh_do_func doer;
pdo_dbh_quote_func quoter;
pdo_dbh_txn_func begin;
pdo_dbh_txn_func commit;
pdo_dbh_txn_func rollback;
pdo_dbh_set_attr_func set_attribute;
pdo_dbh_last_id_func last_id;
pdo_dbh_fetch_error_func fetch_err;
pdo_dbh_get_attr_func get_attribute;
pdo_dbh_check_liveness_func check_liveness;
pdo_dbh_get_driver_methods_func get_driver_methods;
};
/* }}} */
/* {{{ methods for a statement handle */
/* free the statement handle */
typedef int (*pdo_stmt_dtor_func)(pdo_stmt_t *stmt TSRMLS_DC);
/* start the query */
typedef int (*pdo_stmt_execute_func)(pdo_stmt_t *stmt TSRMLS_DC);
/* causes the next row in the set to be fetched; indicates if there are no
* more rows. The ori and offset params modify which row should be returned,
* if the stmt represents a scrollable cursor */
typedef int (*pdo_stmt_fetch_func)(pdo_stmt_t *stmt,
enum pdo_fetch_orientation ori, long offset TSRMLS_DC);
/* queries information about the type of a column, by index (0 based).
* Driver should populate stmt->columns[colno] with appropriate info */
typedef int (*pdo_stmt_describe_col_func)(pdo_stmt_t *stmt, int colno TSRMLS_DC);
/* retrieves pointer and size of the value for a column.
* Note that PDO expects the driver to manage the lifetime of this data;
* it will copy the value into a zval on behalf of the script.
* If the driver sets caller_frees, ptr should point to emalloc'd memory
* and PDO will free it as soon as it is done using it.
*/
typedef int (*pdo_stmt_get_col_data_func)(pdo_stmt_t *stmt, int colno, char **ptr, unsigned long *len, int *caller_frees TSRMLS_DC);
/* hook for bound params */
enum pdo_param_event {
PDO_PARAM_EVT_ALLOC,
PDO_PARAM_EVT_FREE,
PDO_PARAM_EVT_EXEC_PRE,
PDO_PARAM_EVT_EXEC_POST,
PDO_PARAM_EVT_FETCH_PRE,
PDO_PARAM_EVT_FETCH_POST,
};
typedef int (*pdo_stmt_param_hook_func)(pdo_stmt_t *stmt, struct pdo_bound_param_data *param, enum pdo_param_event event_type TSRMLS_DC);
/* setting of attributes */
typedef int (*pdo_stmt_set_attr_func)(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC);
/* fetching of attributes */
typedef int (*pdo_stmt_get_attr_func)(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC);
/* retrieves meta data for a numbered column.
* Returns SUCCESS/FAILURE.
* On SUCCESS, fill in return_value with an array with the following fields.
* If a particular field is not supported, then the driver simply does not add it to
* the array, so that scripts can use isset() to check for it.
*
* ### this is just a rough first cut, and subject to change ###
*
* these are added by PDO itself, based on data from the describe handler:
* name => the column name
* len => the length/size of the column
* precision => precision of the column
* pdo_type => an integer, one of the PDO_PARAM_XXX values
*
* scale => the floating point scale
* table => the table for that column
* type => a string representation of the type, mapped to the PHP equivalent type name
* native_type => a string representation of the type, native style, if different from
* the mapped name.
* flags => an array of flags including zero or more of the following:
* primary_key, not_null, unique_key, multiple_key, unsigned, auto_increment, blob
*
* Any driver specific data should be returned using a prefixed key or value.
* Eg: custom data for the mysql driver would use either
* 'mysql:foobar' => 'some data' // to add a new key to the array
* or
* 'flags' => array('not_null', 'mysql:some_flag'); // to add data to an existing key
*/
typedef int (*pdo_stmt_get_column_meta_func)(pdo_stmt_t *stmt, long colno, zval *return_value TSRMLS_DC);
/* advances the statement to the next rowset of the batch.
* If it returns 1, PDO will tear down its idea of columns
* and meta data. If it returns 0, PDO will indicate an error
* to the caller. */
typedef int (*pdo_stmt_next_rowset_func)(pdo_stmt_t *stmt TSRMLS_DC);
struct pdo_stmt_methods {
pdo_stmt_dtor_func dtor;
pdo_stmt_execute_func executer;
pdo_stmt_fetch_func fetcher;
pdo_stmt_describe_col_func describer;
pdo_stmt_get_col_data_func get_col;
pdo_stmt_param_hook_func param_hook;
pdo_stmt_set_attr_func set_attribute;
pdo_stmt_get_attr_func get_attribute;
pdo_stmt_get_column_meta_func get_column_meta;
pdo_stmt_next_rowset_func next_rowset;
};
/* }}} */
enum pdo_placeholder_support {
PDO_PLACEHOLDER_NONE=0,
PDO_PLACEHOLDER_NAMED=1,
PDO_PLACEHOLDER_POSITIONAL=2
};
/* represents a connection to a database */
struct _pdo_dbh_t {
/* these items must appear in this order at the beginning of the
struct so that this can be cast as a zend_object. we need this
to allow the extending class to escape all the custom handlers
that PDO declares.
*/
zend_class_entry *ce;
HashTable *properties;
unsigned int in_get:1;
unsigned int in_set:1;
/* driver specific methods */
struct pdo_dbh_methods *methods;
/* driver specific data */
void *driver_data;
/* credentials */
char *username, *password;
/* if true, then data stored and pointed at by this handle must all be
* persistently allocated */
unsigned is_persistent:1;
/* if true, driver should act as though a COMMIT were executed between
* each executed statement; otherwise, COMMIT must be carried out manually
* */
unsigned auto_commit:1;
/* if true, the handle has been closed and will not function anymore */
unsigned is_closed:1;
/* if true, the driver requires that memory be allocated explicitly for
* the columns that are returned */
unsigned alloc_own_columns:1;
/* if true, commit or rollBack is allowed to be called */
unsigned in_txn:1;
/* max length a single character can become after correct quoting */
unsigned max_escaped_char_length:3;
/* when set, convert empty strings to NULL */
unsigned oracle_nulls:1;
/* the sum of the number of bits here and the bit fields preceeding should
* equal 32 */
unsigned _reserved_flags:23;
/* data source string used to open this handle */
const char *data_source;
unsigned long data_source_len;
/* the global error code. */
pdo_error_type error_code;
enum pdo_error_mode error_mode;
enum pdo_case_conversion native_case, desired_case;
/* persistent hash key associated with this handle */
const char *persistent_id;
int persistent_id_len;
unsigned int refcount;
/* driver specific "class" methods for the dbh and stmt */
HashTable *cls_methods[PDO_DBH_DRIVER_METHOD_KIND__MAX];
};
/* describes a column */
struct pdo_column_data {
char *name;
long namelen;
unsigned long maxlen;
enum pdo_param_type param_type;
unsigned long precision;
};
/* describes a bound parameter */
struct pdo_bound_param_data {
long paramno; /* if -1, then it has a name, and we don't know the index *yet* */
char *name;
long namelen;
long max_value_len; /* as a hint for pre-allocation */
zval *parameter; /* the variable itself */
enum pdo_param_type param_type; /* desired or suggested type */
zval *driver_params; /* optional parameter(s) for the driver */
void *driver_data;
pdo_stmt_t *stmt; /* for convenience in dtor */
int is_param; /* parameter or column ? */
};
/* represents a prepared statement */
struct _pdo_stmt_t {
/* driver specifics */
struct pdo_stmt_methods *methods;
void *driver_data;
/* if true, we've already successfully executed this statement at least
* once */
unsigned executed:1;
/* if true, the statement supports placeholders and can implement
* bindParam() for its prepared statements, if false, PDO should
* emulate prepare and bind on its behalf */
unsigned supports_placeholders:2;
unsigned _reserved:29;
/* the number of columns in the result set; not valid until after
* the statement has been executed at least once. In some cases, might
* not be valid until fetch (at the driver level) has been called at least once.
* */
int column_count;
struct pdo_column_data *columns;
/* we want to keep the dbh alive while we live, so we own a reference */
zval database_object_handle;
pdo_dbh_t *dbh;
/* keep track of bound input parameters. Some drivers support
* input/output parameters, but you can't rely on that working */
HashTable *bound_params;
/* keep track of PHP variables bound to named (or positional) columns
* in the result set */
HashTable *bound_columns;
/* not always meaningful */
long row_count;
/* used to hold the statement's current query */
char *query_string;
int query_stringlen;
/* the copy of the query with expanded binds ONLY for emulated-prepare drivers */
char *active_query_string;
int active_query_stringlen;
/* the cursor specific error code. */
pdo_error_type error_code;
/* for lazy fetches, we always return the same lazy object handle.
* Let's keep it here. */
zval lazy_object_ref;
unsigned long refcount;
/* defaults for fetches */
enum pdo_fetch_type default_fetch_type;
union {
int column;
struct {
zend_class_entry *ce;
zval *ctor_args;
} cls;
zval *into;
} fetch;
};
/* call this in MINIT to register your PDO driver */
PDO_API int php_pdo_register_driver(pdo_driver_t *driver);
/* call this in MSHUTDOWN to unregister your PDO driver */
PDO_API void php_pdo_unregister_driver(pdo_driver_t *driver);
/* For the convenience of drivers, this function will parse a data source
* string, of the form "name=value; name2=value2" and populate variables
* according to the data you pass in and array of pdo_data_src_parser structures */
struct pdo_data_src_parser {
const char *optname;
char *optval;
int freeme;
};
PDO_API int php_pdo_parse_data_source(const char *data_source,
unsigned long data_source_len, struct pdo_data_src_parser *parsed,
int nparams);
PDO_API zend_class_entry *php_pdo_get_exception(void);
PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, int inquery_len,
char **outquery, int *outquery_len TSRMLS_DC);
#endif /* PHP_PDO_DRIVER_H */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
-73
View File
@@ -1,73 +0,0 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2005 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.0 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_0.txt. |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Wez Furlong <wez@php.net> |
| Marcus Boerger <helly@php.net> |
| Sterling Hughes <sterling@php.net> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
/* Stuff private to the PDO extension and not for consumption by PDO drivers
* */
extern zend_class_entry *pdo_exception_ce;
int php_pdo_list_entry(void);
extern zend_object_value pdo_dbh_new(zend_class_entry *ce TSRMLS_DC);
extern function_entry pdo_dbh_functions[];
extern zend_class_entry *pdo_dbh_ce;
extern ZEND_RSRC_DTOR_FUNC(php_pdo_pdbh_dtor);
extern zend_object_value pdo_dbstmt_new(zend_class_entry *ce TSRMLS_DC);
extern function_entry pdo_dbstmt_functions[];
extern zend_class_entry *pdo_dbstmt_ce;
void pdo_dbstmt_free_storage(zend_object *object TSRMLS_DC);
zend_object_iterator *pdo_stmt_iter_get(zend_class_entry *ce, zval *object TSRMLS_DC);
extern zend_object_handlers pdo_dbstmt_object_handlers;
int pdo_stmt_describe_columns(pdo_stmt_t *stmt TSRMLS_DC);
int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int skip_first_arg);
extern zend_object_value pdo_row_new(zend_class_entry *ce TSRMLS_DC);
extern function_entry pdo_row_functions[];
extern zend_class_entry *pdo_row_ce;
void pdo_row_free_storage(zend_object *object TSRMLS_DC);
extern zend_object_handlers pdo_row_object_handlers;
zend_object_iterator *php_pdo_dbstmt_iter_get(zend_class_entry *ce, zval *object TSRMLS_DC);
extern pdo_driver_t *pdo_find_driver(const char *name, int namelen);
extern void pdo_handle_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt TSRMLS_DC);
extern void pdo_raise_impl_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *sqlstate, const char *supp TSRMLS_DC);
#define PDO_DBH_CLEAR_ERR() strcpy(dbh->error_code, PDO_ERR_NONE)
#define PDO_STMT_CLEAR_ERR() strcpy(stmt->error_code, PDO_ERR_NONE)
#define PDO_HANDLE_DBH_ERR() if (strcmp(dbh->error_code, PDO_ERR_NONE)) { pdo_handle_error(dbh, NULL TSRMLS_CC); }
#define PDO_HANDLE_STMT_ERR() if (strcmp(stmt->error_code, PDO_ERR_NONE)) { pdo_handle_error(stmt->dbh, stmt TSRMLS_CC); }
int pdo_sqlstate_init_error_table(void);
void pdo_sqlstate_fini_error_table(void);
const char *pdo_sqlstate_state_to_description(char *state);
int pdo_hash_methods(pdo_dbh_t *dbh, int kind TSRMLS_DC);
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
-2
View File
@@ -1,2 +0,0 @@
SQLite 3.x driver for PDO
Wez Furlong
-115
View File
@@ -1,115 +0,0 @@
dnl $Id$
dnl config.m4 for extension pdo_sqlite
dnl vim:et:sw=2:ts=2:
PHP_ARG_WITH(pdo-sqlite, for sqlite 3 driver for PDO,
[ --with-pdo-sqlite Include PDO sqlite 3 support])
if test "$PHP_PDO_SQLITE" != "no"; then
AC_MSG_CHECKING([for PDO includes])
if test -f $prefix/include/php/ext/pdo/php_pdo_driver.h; then
pdo_inc_path=$prefix/include/php/ext
elif test -f $abs_srcdir/include/php/ext/pdo/php_pdo_driver.h; then
pdo_inc_path=$abs_srcdir/ext
elif test -f ext/pdo/php_pdo_driver.h; then
pdo_inc_path=ext
else
AC_MSG_ERROR([Cannot find php_pdo_driver.h.])
fi
AC_MSG_RESULT($pdo_inc_path)
php_pdo_sqlite_sources_core="pdo_sqlite.c sqlite_driver.c sqlite_statement.c"
if test "$PHP_PDO_SQLITE" != "yes"; then
SEARCH_PATH="$PHP_PDO_SQLITE /usr/local /usr" # you might want to change this
SEARCH_FOR="/include/sqlite3.h" # you most likely want to change this
if test -r $PHP_PDO_SQLITE/$SEARCH_FOR; then # path given as parameter
PDO_SQLITE_DIR=$PHP_PDO_SQLITE
else # search default path list
AC_MSG_CHECKING([for sqlite3 files in default path])
for i in $SEARCH_PATH ; do
if test -r $i/$SEARCH_FOR; then
PDO_SQLITE_DIR=$i
AC_MSG_RESULT(found in $i)
fi
done
fi
if test -z "$PDO_SQLITE_DIR"; then
AC_MSG_RESULT([not found])
AC_MSG_ERROR([Please reinstall the sqlite3 distribution])
fi
PHP_ADD_INCLUDE($PDO_SQLITE_DIR/include)
LIBNAME=sqlite3
LIBSYMBOL=sqlite3_open
PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL,
[
PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $PDO_SQLITE_DIR/lib, PDO_SQLITE_SHARED_LIBADD)
AC_DEFINE(HAVE_PDO_SQLITELIB,1,[ ])
],[
AC_MSG_ERROR([wrong sqlite lib version or lib not found])
],[
-L$PDO_SQLITE_DIR/lib -lm
])
PHP_CHECK_LIBRARY(sqlite3,sqlite3_key,[
AC_DEFINE(HAVE_SQLITE3_KEY,1, [have commercial sqlite3 with crypto support])
])
PHP_SUBST(PDO_SQLITE_SHARED_LIBADD)
PHP_NEW_EXTENSION(pdo_sqlite, $php_pdo_sqlite_sources_core, $ext_shared,,-I$pdo_inc_path)
else
# use bundled libs
PHP_PDO_SQLITE_CFLAGS="-I@ext_srcdir@/sqlite/src"
pdo_sqlite_sources="sqlite/src/attach.c sqlite/src/auth.c sqlite/src/btree.c \
sqlite/src/build.c sqlite/src/date.c sqlite/src/delete.c sqlite/src/expr.c \
sqlite/src/func.c sqlite/src/hash.c sqlite/src/insert.c sqlite/src/legacy.c \
sqlite/src/main.c sqlite/src/os_mac.c sqlite/src/os_unix.c sqlite/src/os_win.c \
sqlite/src/pager.c sqlite/src/pragma.c \
sqlite/src/printf.c sqlite/src/random.c sqlite/src/select.c \
sqlite/src/table.c sqlite/src/tokenize.c \
sqlite/src/trigger.c sqlite/src/update.c sqlite/src/utf.c sqlite/src/util.c \
sqlite/src/vacuum.c sqlite/src/vdbeapi.c sqlite/src/vdbeaux.c sqlite/src/vdbe.c \
sqlite/src/vdbemem.c sqlite/src/where.c sqlite/src/parse.c sqlite/src/opcodes.c"
PHP_NEW_EXTENSION(pdo_sqlite,
$php_pdo_sqlite_sources_core $pdo_sqlite_sources,
$ext_shared,,-I@ext_srcdir@/sqlite/src -DPDO_SQLITE_BUNDLED=1 -I$pdo_inc_path)
PHP_ADD_BUILD_DIR($ext_builddir/sqlite)
PHP_ADD_BUILD_DIR($ext_builddir/sqlite/src)
AC_CHECK_SIZEOF(char *,4)
AC_DEFINE(SQLITE_PTR_SZ, SIZEOF_CHAR_P, [Size of a pointer])
PDO_SQLITE_VERSION=`cat $ext_srcdir/sqlite/VERSION`
sed -e s/--VERS--/$PDO_SQLITE_VERSION/ $ext_srcdir/sqlite/src/sqlite.h.in > $ext_srcdir/sqlite3.h
if ! test -f $ext_srcdir/sqlite/src/parse.h ; then
$CC -o $ext_srcdir/sqlite/tool/lemon $ext_srcdir/sqlite/tool/lemon.c
$ext_srcdir/sqlite/tool/lemon $ext_srcdir/sqlite/src/parse.y
cat $ext_srcdir/sqlite/src/parse.h $ext_srcdir/sqlite/src/vdbe.c | awk -f $ext_srcdir/sqlite/mkopcodeh.awk > $ext_srcdir/sqlite/src/opcodes.h
sort -n +2 $ext_srcdir/sqlite/src/opcodes.h | awk -f $ext_srcdir/sqlite/mkopcodec.awk > $ext_srcdir/sqlite/src/opcodes.c
fi
if test "$ext_shared" = "no"; then
echo '#include "php_config.h"' > $ext_srcdir/sqlite/src/config.h
else
echo "#include \"$abs_builddir/config.h\"" > $ext_srcdir/sqlite/src/config.h
fi
cat >> $ext_srcdir/sqlite/src/config.h <<EOF
#if ZTS
# define THREADSAFE 1
#endif
#if !ZEND_DEBUG
# define NDEBUG
#endif
/* discourage foolishness */
#define sqlite3_temp_directory sqlite3_temp_directory_unsafe_except_in_minit
EOF
AC_CHECK_FUNCS(usleep nanosleep)
AC_CHECK_HEADERS(time.h)
fi
dnl PHP_ADD_EXTENSION_DEP(pdo_sqlite, pdo)
fi
-16
View File
@@ -1,16 +0,0 @@
// $Id$
// vim:ft=javascript
ARG_WITH("pdo-sqlite", "for pdo_sqlite support", "no");
if (PHP_PDO_SQLITE != "no") {
if (CHECK_LIB("sqlite3.lib", "pdo_sqlite", PHP_PDO_SQLITE) &&
CHECK_HEADER_ADD_INCLUDE("sqlite3.h", "CFLAGS_PDO_SQLITE", PHP_PDO_SQLITE + ";" + PHP_PHP_BUILD + "\\include\\sqlite3")) {
EXTENSION("pdo_sqlite", "pdo_sqlite.c sqlite_driver.c sqlite_statement.c");
ADD_FLAG('CFLAGS_PDO_SQLITE', "/I ..\\pecl");
} else {
WARNING("pdo_sqlite not enabled; libraries and headers not found");
}
ADD_EXTENSION_DEP('pdo_sqlite', 'pdo');
}
-161
View File
@@ -1,161 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE package SYSTEM "../pear/package.dtd">
<package version="1.0">
<name>PDO_SQLITE</name>
<summary>SQLite v3 Interface driver for PDO</summary>
<maintainers>
<maintainer>
<user>wez</user>
<name>Wez Furlong</name>
<email>wez@php.net</email>
<role>lead</role>
</maintainer>
</maintainers>
<!-- configureoptions>
<configureoption name="with-pdo-sqlite" prompt="Path to your sqlite3 install"/>
</configureoptions -->
<description>
This extension provides an SQLite v3 driver for PDO.
SQLite V3 is NOT compatible with the bundled SQLite 2 in PHP 5, but is a significant
step forwards, featuring complete utf-8 support, native support for blobs,
native support for prepared statements with bound parameters and improved
concurrency.
</description>
<license>PHP</license>
<release>
<state>beta</state>
<version>0.2.2</version>
<date>2005-02-12</date>
<notes>
You need to install the PDO core module before you can make use of this one.
This package includes a bundled SQLite 3 library.
Windows binary: http://snaps.php.net/win32/PECL_5_0/php_pdo_sqlite.dll
- setting PDO_ATTR_TIMEOUT controls the busy timeout
- Fixed PECL Bug #3391; cannot bind NULL parameters
- Fixed build problem when building the bundled sqlite library
</notes>
<filelist>
<file role="src" name="config.m4"/>
<file role="src" name="config.w32"/>
<file role="src" name="pdo_sqlite.c"/>
<file role="src" name="sqlite_driver.c"/>
<file role="src" name="sqlite_statement.c"/>
<file role="src" name="php_pdo_sqlite.h"/>
<file role="src" name="php_pdo_sqlite_int.h"/>
<file role="doc" name="CREDITS"/>
<dir name="sqlite">
<file role="src" name="aclocal.m4"/>
<file role="src" name="config.guess"/>
<file role="src" name="config.sub"/>
<file role="src" name="configure"/>
<file role="src" name="configure.ac"/>
<file role="src" name="install-sh"/>
<file role="src" name="ltmain.sh"/>
<file role="src" name="main.mk"/>
<file role="src" name="Makefile.in"/>
<file role="src" name="Makefile.linux-gcc"/>
<file role="src" name="mkdll.sh"/>
<file role="src" name="mkopcodec.awk"/>
<file role="src" name="mkopcodeh.awk"/>
<file role="src" name="mkso.sh"/>
<file role="src" name="publish.sh"/>
<file role="src" name="README"/>
<file role="src" name="spec.template"/>
<file role="src" name="sqlite.1"/>
<file role="src" name="sqlite3.def"/>
<file role="src" name="sqlite3.pc.in"/>
<file role="src" name="sqlite.pc.in"/>
<file role="src" name="VERSION"/>
<dir name="src">
<file role="src" name="attach.c"/>
<file role="src" name="auth.c"/>
<file role="src" name="btree.c"/>
<file role="src" name="btree.h"/>
<file role="src" name="build.c"/>
<file role="src" name="date.c"/>
<file role="src" name="delete.c"/>
<file role="src" name="expr.c"/>
<file role="src" name="func.c"/>
<file role="src" name="hash.c"/>
<file role="src" name="hash.h"/>
<file role="src" name="insert.c"/>
<file role="src" name="legacy.c"/>
<file role="src" name="main.c"/>
<file role="src" name="md5.c"/>
<file role="src" name="os_common.h"/>
<file role="src" name="os.h"/>
<file role="src" name="os_mac.c"/>
<file role="src" name="os_mac.h"/>
<file role="src" name="os_test.c"/>
<file role="src" name="os_test.h"/>
<file role="src" name="os_unix.c"/>
<file role="src" name="os_unix.h"/>
<file role="src" name="os_win.c"/>
<file role="src" name="os_win.h"/>
<file role="src" name="pager.c"/>
<file role="src" name="pager.h"/>
<file role="src" name="parse.y"/>
<file role="src" name="pragma.c"/>
<file role="src" name="printf.c"/>
<file role="src" name="random.c"/>
<file role="src" name="select.c"/>
<file role="src" name="shell.c"/>
<file role="src" name="sqlite.h.in"/>
<file role="src" name="sqliteInt.h"/>
<file role="src" name="table.c"/>
<file role="src" name="tclsqlite.c"/>
<file role="src" name="test1.c"/>
<file role="src" name="test2.c"/>
<file role="src" name="test3.c"/>
<file role="src" name="test4.c"/>
<file role="src" name="test5.c"/>
<file role="src" name="tokenize.c"/>
<file role="src" name="trigger.c"/>
<file role="src" name="update.c"/>
<file role="src" name="utf.c"/>
<file role="src" name="util.c"/>
<file role="src" name="vacuum.c"/>
<file role="src" name="vdbeapi.c"/>
<file role="src" name="vdbeaux.c"/>
<file role="src" name="vdbe.c"/>
<file role="src" name="vdbe.h"/>
<file role="src" name="vdbeInt.h"/>
<file role="src" name="vdbemem.c"/>
<file role="src" name="where.c"/>
</dir>
<dir name="tool">
<file role="src" name="diffdb.c"/>
<file role="src" name="lemon.c"/>
<file role="src" name="lempar.c"/>
<file role="src" name="memleak2.awk"/>
<file role="src" name="memleak3.tcl"/>
<file role="src" name="memleak.awk"/>
<file role="src" name="mkkeywordhash.c"/>
<file role="src" name="mkopts.tcl"/>
<file role="src" name="opcodeDoc.awk"/>
<file role="src" name="report1.txt"/>
<file role="src" name="showdb.c"/>
<file role="src" name="showjournal.c"/>
<file role="src" name="spaceanal.tcl"/>
<file role="src" name="space_used.tcl"/>
<file role="src" name="speedtest2.tcl"/>
<file role="src" name="speedtest.tcl"/>
</dir>
</dir>
</filelist>
<deps>
<dep type="php" rel="ge" version="5.0.3"/>
<dep type="ext" rel="ge" name="pdo" version="0.2"/>
</deps>
</release>
</package>
<!-- vim: se ts=2 sw=2 et: -->
-101
View File
@@ -1,101 +0,0 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2005 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.0 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_0.txt. |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Wez Furlong <wez@php.net> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "pdo/php_pdo.h"
#include "pdo/php_pdo_driver.h"
#include "php_pdo_sqlite.h"
#include "php_pdo_sqlite_int.h"
#include "zend_exceptions.h"
#define PHP_PDO_SQLITE_MODULE_VERSION "0.2.2"
/* {{{ pdo_sqlite_functions[] */
function_entry pdo_sqlite_functions[] = {
{NULL, NULL, NULL}
};
/* }}} */
/* {{{ pdo_sqlite_module_entry
*/
zend_module_entry pdo_sqlite_module_entry = {
STANDARD_MODULE_HEADER,
"pdo_sqlite",
pdo_sqlite_functions,
PHP_MINIT(pdo_sqlite),
PHP_MSHUTDOWN(pdo_sqlite),
NULL,
NULL,
PHP_MINFO(pdo_sqlite),
PHP_PDO_SQLITE_MODULE_VERSION,
STANDARD_MODULE_PROPERTIES
};
/* }}} */
#ifdef COMPILE_DL_PDO_SQLITE
ZEND_GET_MODULE(pdo_sqlite)
#endif
/* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(pdo_sqlite)
{
return php_pdo_register_driver(&pdo_sqlite_driver);
}
/* }}} */
/* {{{ PHP_MSHUTDOWN_FUNCTION */
PHP_MSHUTDOWN_FUNCTION(pdo_sqlite)
{
php_pdo_unregister_driver(&pdo_sqlite_driver);
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MINFO_FUNCTION
*/
PHP_MINFO_FUNCTION(pdo_sqlite)
{
php_info_print_table_start();
php_info_print_table_header(2, "PDO Driver for SQLite 3.x", "enabled");
php_info_print_table_row(2, "PECL Module version",
#if PDO_SQLITE_BUNDLED
"(bundled) "
#endif
PHP_PDO_SQLITE_MODULE_VERSION
" $Id$");
php_info_print_table_row(2, "SQLite Library", sqlite3_libversion());
php_info_print_table_end();
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
-71
View File
@@ -1,71 +0,0 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2004 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.0 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_0.txt. |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Wez Furlong <wez@php.net> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifndef PHP_PDO_SQLITE_H
#define PHP_PDO_SQLITE_H
extern zend_module_entry pdo_sqlite_module_entry;
#define phpext_pdo_sqlite_ptr &pdo_sqlite_module_entry
#ifdef PHP_WIN32
#define PHP_PDO_SQLITE_API __declspec(dllexport)
#else
#define PHP_PDO_SQLITE_API
#endif
#ifdef ZTS
#include "TSRM.h"
#endif
PHP_MINIT_FUNCTION(pdo_sqlite);
PHP_MSHUTDOWN_FUNCTION(pdo_sqlite);
PHP_RINIT_FUNCTION(pdo_sqlite);
PHP_RSHUTDOWN_FUNCTION(pdo_sqlite);
PHP_MINFO_FUNCTION(pdo_sqlite);
/*
Declare any global variables you may need between the BEGIN
and END macros here:
ZEND_BEGIN_MODULE_GLOBALS(pdo_sqlite)
long global_value;
char *global_string;
ZEND_END_MODULE_GLOBALS(pdo_sqlite)
*/
/* In every utility function you add that needs to use variables
in php_pdo_sqlite_globals, call TSRMLS_FETCH(); after declaring other
variables used by that function, or better yet, pass in TSRMLS_CC
after the last function argument and declare your utility function
with TSRMLS_DC after the last declared argument. Always refer to
the globals in your function as PDO_SQLITE_G(variable). You are
encouraged to rename these macros something shorter, see
examples in any other php module directory.
*/
#ifdef ZTS
#define PDO_SQLITE_G(v) TSRMG(pdo_sqlite_globals_id, zend_pdo_sqlite_globals *, v)
#else
#define PDO_SQLITE_G(v) (pdo_sqlite_globals.v)
#endif
#endif /* PHP_PDO_SQLITE_H */
-52
View File
@@ -1,52 +0,0 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2004 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.0 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_0.txt. |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Wez Furlong <wez@php.net> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifndef PHP_PDO_SQLITE_INT_H
#define PHP_PDO_SQLITE_INT_H
#include <sqlite3.h>
typedef struct {
const char *file;
int line;
unsigned int errcode;
char *errmsg;
} pdo_sqlite_error_info;
typedef struct {
sqlite3 *db;
pdo_sqlite_error_info einfo;
} pdo_sqlite_db_handle;
typedef struct {
pdo_sqlite_db_handle *H;
sqlite3_stmt *stmt;
unsigned pre_fetched:1;
unsigned done:1;
} pdo_sqlite_stmt;
extern pdo_driver_t pdo_sqlite_driver;
extern int _pdo_sqlite_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *file, int line TSRMLS_DC);
#define pdo_sqlite_error(s) _pdo_sqlite_error(s, NULL, __FILE__, __LINE__ TSRMLS_CC)
#define pdo_sqlite_error_stmt(s) _pdo_sqlite_error(stmt->dbh, stmt, __FILE__, __LINE__ TSRMLS_CC)
extern struct pdo_stmt_methods sqlite_stmt_methods;
#endif
-586
View File
@@ -1,586 +0,0 @@
#!/usr/make
#
# Makefile for SQLITE
#
# This makefile is suppose to be configured automatically using the
# autoconf. But if that does not work for you, you can configure
# the makefile manually. Just set the parameters below to values that
# work well for your system.
#
# If the configure script does not work out-of-the-box, you might
# be able to get it to work by giving it some hints. See the comment
# at the beginning of configure.in for additional information.
#
# The toplevel directory of the source tree. This is the directory
# that contains this "Makefile.in" and the "configure.in" script.
#
TOP = @srcdir@
# C Compiler and options for use in building executables that
# will run on the platform that is doing the build.
#
BCC = @BUILD_CC@ @BUILD_CFLAGS@
# C Compile and options for use in building executables that
# will run on the target platform. (BCC and TCC are usually the
# same unless your are cross-compiling.)
#
TCC = @TARGET_CC@ @TARGET_CFLAGS@ -I. -I${TOP}/src -DNDEBUG
# Some standard variables and programs
#
prefix = @prefix@
exec_prefix = @exec_prefix@
libdir = @libdir@
INSTALL = @INSTALL@
LIBTOOL = ./libtool
RELEASE = @ALLOWRELEASE@
# libtool compile/link/install
LTCOMPILE = $(LIBTOOL) --mode=compile $(TCC)
LTLINK = $(LIBTOOL) --mode=link $(TCC)
LTINSTALL = $(LIBTOOL) --mode=install $(INSTALL)
# Compiler options needed for programs that use the TCL library.
#
TCL_FLAGS = @TARGET_TCL_INC@
# The library that programs using TCL must link against.
#
LIBTCL = @TARGET_TCL_LIBS@
# Compiler options needed for programs that use the readline() library.
#
READLINE_FLAGS = -DHAVE_READLINE=@TARGET_HAVE_READLINE@ @TARGET_READLINE_INC@
# The library that programs using readline() must link against.
#
LIBREADLINE = @TARGET_READLINE_LIBS@
# Should the database engine be compiled threadsafe
#
THREADSAFE = -DTHREADSAFE=@THREADSAFE@
# The pthreads library if needed
#
LIBPTHREAD=@TARGET_THREAD_LIB@
# Flags controlling use of the in memory btree implementation
#
# TEMP_STORE is 0 to force temporary tables to be in a file, 1 to
# default to file, 2 to default to memory, and 3 to force temporary
# tables to always be in memory.
#
TEMP_STORE = -DTEMP_STORE=@TEMP_STORE@
# You should not have to change anything below this line
###############################################################################
# Object files for the SQLite library.
#
LIBOBJ = attach.lo auth.lo btree.lo build.lo date.lo delete.lo \
expr.lo func.lo hash.lo insert.lo \
main.lo opcodes.lo os_mac.lo os_unix.lo os_win.lo \
pager.lo parse.lo pragma.lo printf.lo random.lo \
select.lo table.lo tokenize.lo trigger.lo update.lo util.lo vacuum.lo \
vdbe.lo vdbeapi.lo vdbeaux.lo vdbemem.lo \
where.lo utf.lo legacy.lo
# All of the source code files.
#
SRC = \
$(TOP)/src/attach.c \
$(TOP)/src/auth.c \
$(TOP)/src/btree.c \
$(TOP)/src/btree.h \
$(TOP)/src/build.c \
$(TOP)/src/date.c \
$(TOP)/src/delete.c \
$(TOP)/src/expr.c \
$(TOP)/src/func.c \
$(TOP)/src/hash.c \
$(TOP)/src/hash.h \
$(TOP)/src/insert.c \
$(TOP)/src/legacy.c \
$(TOP)/src/main.c \
$(TOP)/src/os_mac.c \
$(TOP)/src/os_unix.c \
$(TOP)/src/os_win.c \
$(TOP)/src/pager.c \
$(TOP)/src/pager.h \
$(TOP)/src/parse.y \
$(TOP)/src/pragma.c \
$(TOP)/src/printf.c \
$(TOP)/src/random.c \
$(TOP)/src/select.c \
$(TOP)/src/shell.c \
$(TOP)/src/sqlite.h.in \
$(TOP)/src/sqliteInt.h \
$(TOP)/src/table.c \
$(TOP)/src/tclsqlite.c \
$(TOP)/src/tokenize.c \
$(TOP)/src/trigger.c \
$(TOP)/src/utf.c \
$(TOP)/src/update.c \
$(TOP)/src/util.c \
$(TOP)/src/vacuum.c \
$(TOP)/src/vdbe.c \
$(TOP)/src/vdbe.h \
$(TOP)/src/vdbeapi.c \
$(TOP)/src/vdbeaux.c \
$(TOP)/src/vdbemem.c \
$(TOP)/src/vdbeInt.h \
$(TOP)/src/where.c
# Source code to the test files.
#
TESTSRC = \
$(TOP)/src/btree.c \
$(TOP)/src/func.c \
$(TOP)/src/os_mac.c \
$(TOP)/src/os_unix.c \
$(TOP)/src/os_win.c \
$(TOP)/src/pager.c \
$(TOP)/src/pragma.c \
$(TOP)/src/printf.c \
$(TOP)/src/test1.c \
$(TOP)/src/test2.c \
$(TOP)/src/test3.c \
$(TOP)/src/test4.c \
$(TOP)/src/test5.c \
$(TOP)/src/utf.c \
$(TOP)/src/util.c \
$(TOP)/src/vdbe.c \
$(TOP)/src/md5.c
# Header files used by all library source files.
#
HDR = \
sqlite3.h \
$(TOP)/src/btree.h \
config.h \
$(TOP)/src/hash.h \
opcodes.h \
$(TOP)/src/os.h \
$(TOP)/src/os_common.h \
$(TOP)/src/os_mac.h \
$(TOP)/src/os_unix.h \
$(TOP)/src/os_win.h \
$(TOP)/src/sqliteInt.h \
$(TOP)/src/vdbe.h \
parse.h
# Header files used by the VDBE submodule
#
VDBEHDR = \
$(HDR) \
$(TOP)/src/vdbeInt.h
# This is the default Makefile target. The objects listed here
# are what get build when you type just "make" with no arguments.
#
all: sqlite3.h libsqlite3.la sqlite3@TARGET_EXEEXT@
Makefile: $(TOP)/Makefile.in
./config.status
# Generate the file "last_change" which contains the date of change
# of the most recently modified source code file
#
last_change: $(SRC)
cat $(SRC) | grep '$$Id: ' | sort +4 | tail -1 \
| awk '{print $$5,$$6}' >last_change
libsqlite3.la: $(LIBOBJ)
$(LTLINK) -o libsqlite3.la $(LIBOBJ) $(LIBPTHREAD) \
${RELEASE} -rpath $(libdir) -version-info "8:6:8"
libtclsqlite3.la: tclsqlite.lo libsqlite3.la
$(LTLINK) -o libtclsqlite3.la tclsqlite.lo \
libsqlite3.la $(LIBTCL) $(LIBPTHREAD) -rpath $(libdir)/sqlite \
-version-info "8:6:8"
sqlite3@TARGET_EXEEXT@: $(TOP)/src/shell.c libsqlite3.la sqlite3.h
$(LTLINK) $(READLINE_FLAGS) $(LIBPTHREAD) \
-o sqlite3 $(TOP)/src/shell.c libsqlite3.la $(LIBREADLINE)
# This target creates a directory named "tsrc" and fills it with
# copies of all of the C source code and header files needed to
# build on the target system. Some of the C source code and header
# files are automatically generated. This target takes care of
# all that automatic generation.
#
target_source: $(SRC) $(VDBEHDR)
rm -rf tsrc
mkdir -p tsrc
cp $(SRC) $(VDBEHDR) tsrc
rm tsrc/sqlite.h.in tsrc/parse.y
cp parse.c opcodes.c tsrc
cp $(TOP)/sqlite3.def tsrc
# Rules to build the LEMON compiler generator
#
lemon@BUILD_EXEEXT@: $(TOP)/tool/lemon.c $(TOP)/tool/lempar.c
$(BCC) -o lemon $(TOP)/tool/lemon.c
cp $(TOP)/tool/lempar.c .
# Rules to build individual files
#
attach.lo: $(TOP)/src/attach.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/attach.c
auth.lo: $(TOP)/src/auth.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/auth.c
btree.lo: $(TOP)/src/btree.c $(HDR) $(TOP)/src/pager.h
$(LTCOMPILE) -c $(TOP)/src/btree.c
build.lo: $(TOP)/src/build.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/build.c
# The config.h file will contain a single #define that tells us how
# many bytes are in a pointer. This only works if a pointer is the
# same size on the host as it is on the target. If you are cross-compiling
# to a target with a different pointer size, you'll need to manually
# configure the config.h file.
#
config.h:
echo '#include <stdio.h>' >temp.c
echo 'int main(){printf(' >>temp.c
echo '"#define SQLITE_PTR_SZ %d",sizeof(char*));' >>temp.c
echo 'exit(0);}' >>temp.c
$(BCC) -o temp temp.c
./temp >config.h
echo >>config.h
rm -f temp.c temp
date.lo: $(TOP)/src/date.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/date.c
delete.lo: $(TOP)/src/delete.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/delete.c
expr.lo: $(TOP)/src/expr.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/expr.c
func.lo: $(TOP)/src/func.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/func.c
hash.lo: $(TOP)/src/hash.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/hash.c
insert.lo: $(TOP)/src/insert.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/insert.c
legacy.lo: $(TOP)/src/legacy.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/legacy.c
main.lo: $(TOP)/src/main.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/main.c
pager.lo: $(TOP)/src/pager.c $(HDR) $(TOP)/src/pager.h
$(LTCOMPILE) -c $(TOP)/src/pager.c
opcodes.lo: opcodes.c
$(LTCOMPILE) -c opcodes.c
opcodes.c: opcodes.h $(TOP)/mkopcodec.awk
sort -n +2 opcodes.h | awk -f $(TOP)/mkopcodec.awk >opcodes.c
opcodes.h: parse.h $(TOP)/src/vdbe.c $(TOP)/mkopcodeh.awk
cat parse.h $(TOP)/src/vdbe.c | awk -f $(TOP)/mkopcodeh.awk >opcodes.h
os_mac.lo: $(TOP)/src/os_mac.c $(HDR)
$(LTCOMPILE) $(THREADSAFE) -c $(TOP)/src/os_mac.c
os_unix.lo: $(TOP)/src/os_unix.c $(HDR)
$(LTCOMPILE) $(THREADSAFE) -c $(TOP)/src/os_unix.c
os_win.lo: $(TOP)/src/os_win.c $(HDR)
$(LTCOMPILE) $(THREADSAFE) -c $(TOP)/src/os_win.c
parse.lo: parse.c $(HDR)
$(LTCOMPILE) -c parse.c
parse.h: parse.c
parse.c: $(TOP)/src/parse.y lemon@BUILD_EXEEXT@
cp $(TOP)/src/parse.y .
./lemon parse.y
pragma.lo: $(TOP)/src/pragma.c $(HDR)
$(LTCOMPILE) $(TCL_FLAGS) -c $(TOP)/src/pragma.c
printf.lo: $(TOP)/src/printf.c $(HDR)
$(LTCOMPILE) $(TCL_FLAGS) -c $(TOP)/src/printf.c
random.lo: $(TOP)/src/random.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/random.c
select.lo: $(TOP)/src/select.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/select.c
sqlite3.h: $(TOP)/src/sqlite.h.in
sed -e s/--VERS--/`cat ${TOP}/VERSION`/ \
$(TOP)/src/sqlite.h.in >sqlite3.h
table.lo: $(TOP)/src/table.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/table.c
tclsqlite.lo: $(TOP)/src/tclsqlite.c $(HDR)
$(LTCOMPILE) $(TCL_FLAGS) -c $(TOP)/src/tclsqlite.c
tokenize.lo: $(TOP)/src/tokenize.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/tokenize.c
trigger.lo: $(TOP)/src/trigger.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/trigger.c
update.lo: $(TOP)/src/update.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/update.c
utf.lo: $(TOP)/src/utf.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/utf.c
util.lo: $(TOP)/src/util.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/util.c
vacuum.lo: $(TOP)/src/vacuum.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/vacuum.c
vdbe.lo: $(TOP)/src/vdbe.c $(VDBEHDR)
$(LTCOMPILE) -c $(TOP)/src/vdbe.c
vdbeapi.lo: $(TOP)/src/vdbeapi.c $(VDBEHDR)
$(LTCOMPILE) -c $(TOP)/src/vdbeapi.c
vdbeaux.lo: $(TOP)/src/vdbeaux.c $(VDBEHDR)
$(LTCOMPILE) -c $(TOP)/src/vdbeaux.c
vdbemem.lo: $(TOP)/src/vdbemem.c $(VDBEHDR)
$(LTCOMPILE) -c $(TOP)/src/vdbemem.c
where.lo: $(TOP)/src/where.c $(HDR)
$(LTCOMPILE) -c $(TOP)/src/where.c
tclsqlite-sh.lo: $(TOP)/src/tclsqlite.c $(HDR)
$(LTCOMPILE) $(TCL_FLAGS) -DTCLSH=1 -o $@ -c $(TOP)/src/tclsqlite.c
tclsqlite3: tclsqlite-sh.lo libsqlite3.la
$(LTLINK) $(TCL_FLAGS) -o tclsqlite3 tclsqlite-sh.lo \
libsqlite3.la $(LIBTCL)
testfixture@TARGET_EXEEXT@: $(TOP)/src/tclsqlite.c libtclsqlite3.la libsqlite3.la $(TESTSRC)
$(LTLINK) $(TCL_FLAGS) -DTCLSH=1 -DSQLITE_TEST=1\
$(THREADSAFE) $(TEMP_STORE)\
-o testfixture $(TESTSRC) $(TOP)/src/tclsqlite.c \
libtclsqlite3.la libsqlite3.la $(LIBTCL)
crashtest@TARGET_EXEEXT@: $(TOP)/src/tclsqlite.c libsqlite3.la $(TESTSRC) $(TOP)/src/os_test.c
$(LTLINK) $(TCL_FLAGS) -DOS_TEST=1 -DTCLSH=1 -DSQLITE_TEST=1 \
-o crashtest \
$(TESTSRC) $(TOP)/src/os_test.c $(TOP)/src/tclsqlite.c \
libsqlite3.la $(LIBTCL) $(THREADLIB)
fulltest: testfixture@TARGET_EXEEXT@ sqlite3@TARGET_EXEEXT@ crashtest@TARGET_EXEEXT@
./testfixture $(TOP)/test/all.test
test: testfixture@TARGET_EXEEXT@ sqlite3@TARGET_EXEEXT@
./testfixture $(TOP)/test/quick.test
# Rules used to build documentation
#
arch.html: $(TOP)/www/arch.tcl
tclsh $(TOP)/www/arch.tcl >arch.html
arch2.gif: $(TOP)/www/arch2.gif
cp $(TOP)/www/arch2.gif .
c_interface.html: $(TOP)/www/c_interface.tcl
tclsh $(TOP)/www/c_interface.tcl >c_interface.html
capi3.html: $(TOP)/www/capi3.tcl
tclsh $(TOP)/www/capi3.tcl >capi3.html
capi3ref.html: $(TOP)/www/capi3ref.tcl
tclsh $(TOP)/www/capi3ref.tcl >capi3ref.html
changes.html: $(TOP)/www/changes.tcl
tclsh $(TOP)/www/changes.tcl >changes.html
copyright.html: $(TOP)/www/copyright.tcl
tclsh $(TOP)/www/copyright.tcl >copyright.html
copyright-release.html: $(TOP)/www/copyright-release.html
cp $(TOP)/www/copyright-release.html .
copyright-release.pdf: $(TOP)/www/copyright-release.pdf
cp $(TOP)/www/copyright-release.pdf .
common.tcl: $(TOP)/www/common.tcl
cp $(TOP)/www/common.tcl .
conflict.html: $(TOP)/www/conflict.tcl
tclsh $(TOP)/www/conflict.tcl >conflict.html
datatypes.html: $(TOP)/www/datatypes.tcl
tclsh $(TOP)/www/datatypes.tcl >datatypes.html
datatype3.html: $(TOP)/www/datatype3.tcl
tclsh $(TOP)/www/datatype3.tcl >datatype3.html
docs.html: $(TOP)/www/docs.tcl
tclsh $(TOP)/www/docs.tcl >docs.html
download.html: $(TOP)/www/download.tcl
mkdir -p doc
tclsh $(TOP)/www/download.tcl >download.html
faq.html: $(TOP)/www/faq.tcl
tclsh $(TOP)/www/faq.tcl >faq.html
fileformat.html: $(TOP)/www/fileformat.tcl
tclsh $(TOP)/www/fileformat.tcl >fileformat.html
formatchng.html: $(TOP)/www/formatchng.tcl
tclsh $(TOP)/www/formatchng.tcl >formatchng.html
index.html: $(TOP)/www/index.tcl last_change
tclsh $(TOP)/www/index.tcl >index.html
lang.html: $(TOP)/www/lang.tcl
tclsh $(TOP)/www/lang.tcl >lang.html
lockingv3.html: $(TOP)/www/lockingv3.tcl
tclsh $(TOP)/www/lockingv3.tcl >lockingv3.html
oldnews.html: $(TOP)/www/oldnews.tcl
tclsh $(TOP)/www/oldnews.tcl >oldnews.html
omitted.html: $(TOP)/www/omitted.tcl
tclsh $(TOP)/www/omitted.tcl >omitted.html
opcode.html: $(TOP)/www/opcode.tcl $(TOP)/src/vdbe.c
tclsh $(TOP)/www/opcode.tcl $(TOP)/src/vdbe.c >opcode.html
mingw.html: $(TOP)/www/mingw.tcl
tclsh $(TOP)/www/mingw.tcl >mingw.html
nulls.html: $(TOP)/www/nulls.tcl
tclsh $(TOP)/www/nulls.tcl >nulls.html
quickstart.html: $(TOP)/www/quickstart.tcl
tclsh $(TOP)/www/quickstart.tcl >quickstart.html
speed.html: $(TOP)/www/speed.tcl
tclsh $(TOP)/www/speed.tcl >speed.html
sqlite.gif: $(TOP)/art/SQLite.gif
cp $(TOP)/art/SQLite.gif sqlite.gif
sqlite.html: $(TOP)/www/sqlite.tcl
tclsh $(TOP)/www/sqlite.tcl >sqlite.html
support.html: $(TOP)/www/support.tcl
tclsh $(TOP)/www/support.tcl >support.html
tclsqlite.html: $(TOP)/www/tclsqlite.tcl
tclsh $(TOP)/www/tclsqlite.tcl >tclsqlite.html
vdbe.html: $(TOP)/www/vdbe.tcl
tclsh $(TOP)/www/vdbe.tcl >vdbe.html
version3.html: $(TOP)/www/version3.tcl
tclsh $(TOP)/www/version3.tcl >version3.html
# Files to be published on the website.
#
DOC = \
arch.html \
arch2.gif \
c_interface.html \
capi3.html \
capi3ref.html \
changes.html \
copyright.html \
copyright-release.html \
copyright-release.pdf \
conflict.html \
datatypes.html \
datatype3.html \
docs.html \
download.html \
faq.html \
fileformat.html \
formatchng.html \
index.html \
lang.html \
lockingv3.html \
mingw.html \
nulls.html \
oldnews.html \
omitted.html \
opcode.html \
quickstart.html \
speed.html \
sqlite.gif \
sqlite.html \
support.html \
tclsqlite.html \
vdbe.html \
version3.html
doc: common.tcl $(DOC)
mkdir -p doc
mv $(DOC) doc
install: sqlite3 libsqlite3.la sqlite3.h
$(INSTALL) -d $(DESTDIR)$(libdir)
$(LTINSTALL) libsqlite3.la $(DESTDIR)$(libdir)
$(INSTALL) -d $(DESTDIR)$(exec_prefix)/bin
$(LTINSTALL) sqlite3 $(DESTDIR)$(exec_prefix)/bin
$(INSTALL) -d $(DESTDIR)$(prefix)/include
$(INSTALL) -m 0644 sqlite3.h $(DESTDIR)$(prefix)/include
$(INSTALL) -d $(DESTDIR)$(libdir)/pkgconfig;
$(INSTALL) -m 0644 sqlite3.pc $(DESTDIR)$(libdir)/pkgconfig;
clean:
rm -f *.lo *.la *.o sqlite3@TARGET_EXEEXT@ libsqlite3.la
rm -f sqlite3.h opcodes.*
rm -rf .libs .deps
rm -f lemon@BUILD_EXEEXT@ lempar.c parse.* sqlite*.tar.gz
rm -f $(PUBLISH)
rm -f *.da *.bb *.bbg gmon.out
rm -f testfixture@TARGET_EXEEXT@ test.db
rm -rf doc
rm -f common.tcl
rm -f sqlite3.dll sqlite3.lib
#
# Windows section; all this funky .dll stuff ;-)
#
dll: sqlite3.dll
REAL_LIBOBJ = $(LIBOBJ:%.lo=.libs/%.o)
sqlite3.dll: $(LIBOBJ) $(TOP)/sqlite3.def
dllwrap --dllname sqlite3.dll --def $(TOP)/sqlite3.def $(REAL_LIBOBJ)
strip sqlite3.dll
#target for dll import libraries
implib: sqlite3.lib
#make Borland C++ and/or Microsoft VC import library for the dll
# ignore any errors (usually due to missing programs)
sqlite3.lib: sqlite3.dll
-implib -a sqlite3.lib sqlite3.dll
-lib /machine:i386 /def:$(TOP)/sqlite3.def
distclean: clean
rm -f config.log config.status libtool Makefile config.h
-112
View File
@@ -1,112 +0,0 @@
#!/usr/make
#
# Makefile for SQLITE
#
# This is a template makefile for SQLite. Most people prefer to
# use the autoconf generated "configure" script to generate the
# makefile automatically. But that does not work for everybody
# and in every situation. If you are having problems with the
# "configure" script, you might want to try this makefile as an
# alternative. Create a copy of this file, edit the parameters
# below and type "make".
#
#### The toplevel directory of the source tree. This is the directory
# that contains this "Makefile.in" and the "configure.in" script.
#
TOP = ../sqlite
#### C Compiler and options for use in building executables that
# will run on the platform that is doing the build.
#
BCC = gcc -g -O2
#BCC = /opt/ancic/bin/c89 -0
#### If the target operating system supports the "usleep()" system
# call, then define the HAVE_USLEEP macro for all C modules.
#
#USLEEP =
USLEEP = -DHAVE_USLEEP=1
#### If you want the SQLite library to be safe for use within a
# multi-threaded program, then define the following macro
# appropriately:
#
#THREADSAFE = -DTHREADSAFE=1
THREADSAFE = -DTHREADSAFE=0
#### Specify any extra linker options needed to make the library
# thread safe
#
#THREADLIB = -lpthread
THREADLIB =
#### Leave SQLITE_DEBUG undefined for maximum speed. Use SQLITE_DEBUG=1
# to check for memory leaks. Use SQLITE_DEBUG=2 to print a log of all
# malloc()s and free()s in order to track down memory leaks.
#
# SQLite uses some expensive assert() statements in the inner loop.
# You can make the library go almost twice as fast if you compile
# with -DNDEBUG=1
#
#OPTS = -DSQLITE_DEBUG=2
#OPTS = -DSQLITE_DEBUG=1
#OPTS =
OPTS = -DNDEBUG=1
#### The suffix to add to executable files. ".exe" for windows.
# Nothing for unix.
#
#EXE = .exe
EXE =
#### C Compile and options for use in building executables that
# will run on the target platform. This is usually the same
# as BCC, unless you are cross-compiling.
#
TCC = gcc -O6
#TCC = gcc -g -O0 -Wall
#TCC = gcc -g -O0 -Wall -fprofile-arcs -ftest-coverage
#TCC = /opt/mingw/bin/i386-mingw32-gcc -O6
#TCC = /opt/ansic/bin/c89 -O +z -Wl,-a,archive
#### Tools used to build a static library.
#
AR = ar cr
#AR = /opt/mingw/bin/i386-mingw32-ar cr
RANLIB = ranlib
#RANLIB = /opt/mingw/bin/i386-mingw32-ranlib
#### Extra compiler options needed for programs that use the TCL library.
#
#TCL_FLAGS =
#TCL_FLAGS = -DSTATIC_BUILD=1
TCL_FLAGS = -I/home/drh/tcltk/8.4linux
#TCL_FLAGS = -I/home/drh/tcltk/8.4win -DSTATIC_BUILD=1
#TCL_FLAGS = -I/home/drh/tcltk/8.3hpux
#### Linker options needed to link against the TCL library.
#
#LIBTCL = -ltcl -lm -ldl
LIBTCL = /home/drh/tcltk/8.4linux/libtcl8.4g.a -lm -ldl
#LIBTCL = /home/drh/tcltk/8.4win/libtcl84s.a -lmsvcrt
#LIBTCL = /home/drh/tcltk/8.3hpux/libtcl8.3.a -ldld -lm -lc
#### Compiler options needed for programs that use the readline() library.
#
#READLINE_FLAGS =
READLINE_FLAGS = -DHAVE_READLINE=1 -I/usr/include/readline
#### Linker options needed by programs using readline() must link against.
#
#LIBREADLINE =
LIBREADLINE = -static -lreadline -ltermcap
#### Should the database engine assume text is coded as UTF-8 or iso8859?
#
# ENCODING = UTF8
ENCODING = ISO8859
# You should not have to change anything below this line
###############################################################################
include $(TOP)/main.mk
-34
View File
@@ -1,34 +0,0 @@
This directory contains source code to
SQLite: An Embeddable SQL Database Engine
To compile the project, first create a directory in which to place
the build products. It is recommended, but not required, that the
build directory be separate from the source directory. Cd into the
build directory and then from the build directory run the configure
script found at the root of the source tree. Then run "make".
For example:
tar xzf sqlite.tar.gz ;# Unpack the source tree into "sqlite"
mkdir bld ;# Build will occur in a sibling directory
cd bld ;# Change to the build directory
../sqlite/configure ;# Run the configure script
make ;# Run the makefile.
The configure script uses autoconf 2.50 and libtool. If the configure
script does not work out for you, there is a generic makefile named
"Makefile.linux-gcc" in the top directory of the source tree that you
can copy and edit to suite your needs. Comments on the generic makefile
show what changes are needed.
The linux binaries on the website are created using the generic makefile,
not the configure script. The configure script is unmaintained. (You
can volunteer to take over maintenance of the configure script, if you want!)
The windows binaries on the website are created using MinGW32 configured
as a cross-compiler running under Linux. For details, see the ./publish.sh
script at the top-level of the source tree.
Contacts:
http://www.sqlite.org/
-1
View File
@@ -1 +0,0 @@
3.0.8
-5913
View File
File diff suppressed because it is too large. Load diff
-1432
View File
File diff suppressed because it is too large. Load diff
-1537
View File
File diff suppressed because it is too large. Load diff
-21639
View File
File diff suppressed because it is too large. Load diff
-540
View File
@@ -1,540 +0,0 @@
#
# This file describes a "configure" script that is used to build
# makefiles for a particular platform. Process this file using
# Autoconf version 1.13 in order to generate that script. All
# lines of this file up to the AC_INIT macro are ignored.
#
# The build process allows for using a cross-compiler. But the default
# action is to target the same platform that we are running on. The
# configure script needs to discover the following properties of the
# build and target systems:
#
# srcdir
#
# The is the name of the directory that contains the
# "configure" shell script. All source files are
# located relative to this directory.
#
# bindir
#
# The name of the directory where executables should be
# written by the "install" target of the makefile.
#
# program_prefix
#
# Add this prefix to the names of all executables that run
# on the target machine. Default: ""
#
# ENABLE_SHARED
#
# True if shared libraries should be generated.
#
# BUILD_CC
#
# The name of a command that is used to convert C
# source files into executables that run on the build
# platform.
#
# BUILD_CFLAGS
#
# Switches that the build compiler needs in order to construct
# command-line programs.
#
# BUILD_LIBS
#
# Libraries that the build compiler needs in order to construct
# command-line programs.
#
# BUILD_EXEEXT
#
# The filename extension for executables on the build
# platform. "" for Unix and ".exe" for Windows.
#
# TARGET_CC
#
# The name of a command that runs on the build platform
# and converts C source files into *.o files for the
# target platform. In other words, the cross-compiler.
#
# TARGET_CFLAGS
#
# Switches that the target compiler needs to turn C source files
# into *.o files. Do not include TARGET_TCL_INC in this list.
# Makefiles might add additional switches such as "-I.".
#
# TARGET_TCL_LIBS
#
# This is the library directives passed to the target linker
# that cause the executable to link against Tcl. This might
# be a switch like "-ltcl8.0" or pathnames of library file
# like "../../src/libtcl8.0.a".
#
# TARGET_TCL_INC
#
# This variables define the directory that contain header
# files for Tcl. If the compiler is able to find <tcl.h>
# on its own, then this can be blank.
#
# TARGET_READLINE_LIBS
#
# This is the library directives passed to the target linker
# that cause the executable to link against the readline library.
# This might be a switch like "-lreadline" or pathnames of library
# file like "../../src/libreadline.a".
#
# TARGET_READLINE_INC
#
# This variables define the directory that contain header
# files for the readline library. If the compiler is able
# to find <readline.h> on its own, then this can be blank.
#
# TARGET_LINK
#
# The name of the linker that combines *.o files generated
# by TARGET_CC into executables for the target platform.
#
# TARGET_LIBS
#
# Additional libraries or other switch that the target linker needs
# to build an executable on the target. Do not include
# on this list any libraries in TARGET_TCL_LIBS and
# TARGET_READLINE_LIBS, etc.
#
# TARGET_EXEEXT
#
# The filename extension for executables on the
# target platform. "" for Unix and ".exe" for windows.
#
# The generated configure script will make an attempt to guess
# at all of the above parameters. You can override any of
# the guesses by setting the environment variable named
# "config_AAAA" where "AAAA" is the name of the parameter
# described above. (Exception: srcdir cannot be set this way.)
# If you have a file that sets one or more of these environment
# variables, you can invoke configure as follows:
#
# configure --with-hints=FILE
#
# where FILE is the name of the file that sets the environment
# variables. FILE should be an absolute pathname.
#
# If you have a Tcl/Tk/BLT source distribution available, then the
# files in that distribution will be used instead of any other
# Tcl/Tk/BLT files the script might discover if you tell the configure
# script about the source tree. Use commandline options:
#
# --with-tcl=PATH --with-tk=PATH --with-blt=PATH
#
# Or set environment variables config_WITH_TCL, config_WITH_TK, or
# config_WITH_BLT.
#
# This configure.in file is easy to reuse on other projects. Just
# change the argument to AC_INIT(). And disable any features that
# you don't need (for example BLT) by erasing or commenting out
# the corresponding code.
#
AC_INIT(src/sqlite.h.in)
dnl Put the RCS revision string after AC_INIT so that it will also
dnl show in in configure.
# The following RCS revision string applies to configure.in
# $Revision$
#########
# Programs needed
#
AC_PROG_LIBTOOL
AC_PROG_INSTALL
#########
# Set up an appropriate program prefix
#
if test "$program_prefix" = "NONE"; then
program_prefix=""
fi
AC_SUBST(program_prefix)
if test -f VERSION; then
VERSION=`cat VERSION`
echo "Version set to $VERSION"
fi
AC_SUBST(VERSION)
#########
# Check to see if the --with-hints=FILE option is used. If there is none,
# then check for a files named "$host.hints" and ../$hosts.hints where
# $host is the hostname of the build system. If still no hints are
# found, try looking in $system.hints and ../$system.hints where
# $system is the result of uname -s.
#
AC_ARG_WITH(hints,
[ --with-hints=FILE Read configuration options from FILE],
hints=$withval)
if test "$hints" = ""; then
host=`hostname | sed 's/\..*//'`
if test -r $host.hints; then
hints=$host.hints
else
if test -r ../$host.hints; then
hints=../$host.hints
fi
fi
fi
if test "$hints" = ""; then
sys=`uname -s`
if test -r $sys.hints; then
hints=$sys.hints
else
if test -r ../$sys.hints; then
hints=../$sys.hints
fi
fi
fi
if test "$hints" != ""; then
AC_MSG_RESULT(reading hints from $hints)
. $hints
fi
#########
# Locate a compiler for the build machine. This compiler should
# generate command-line programs that run on the build machine.
#
default_build_cflags="-g"
if test "$config_BUILD_CC" = ""; then
AC_PROG_CC
if test "$cross_compiling" = "yes"; then
AC_MSG_ERROR([unable to find a compiler for building build tools])
fi
BUILD_CC=$CC
default_build_cflags=$CFLAGS
else
BUILD_CC=$config_BUILD_CC
AC_MSG_CHECKING([host compiler])
CC=$BUILD_CC
AC_MSG_RESULT($BUILD_CC)
fi
AC_MSG_CHECKING([switches for the host compiler])
if test "$config_BUILD_CFLAGS" != ""; then
CFLAGS=$config_BUILD_CFLAGS
BUILD_CFLAGS=$config_BUILD_CFLAGS
else
BUILD_CFLAGS=$default_build_cflags
fi
AC_MSG_RESULT($BUILD_CFLAGS)
if test "$config_BUILD_LIBS" != ""; then
BUILD_LIBS=$config_BUILD_LIBS
fi
AC_SUBST(BUILD_CC)
AC_SUBST(BUILD_CFLAGS)
AC_SUBST(BUILD_LIBS)
##########
# Locate a compiler that converts C code into *.o files that run on
# the target machine.
#
AC_MSG_CHECKING([target compiler])
if test "$config_TARGET_CC" != ""; then
TARGET_CC=$config_TARGET_CC
else
TARGET_CC=$BUILD_CC
fi
AC_MSG_RESULT($TARGET_CC)
AC_MSG_CHECKING([switches on the target compiler])
if test "$config_TARGET_CFLAGS" != ""; then
TARGET_CFLAGS=$config_TARGET_CFLAGS
else
TARGET_CFLAGS=$BUILD_CFLAGS
fi
AC_MSG_RESULT($TARGET_CFLAGS)
AC_MSG_CHECKING([target linker])
if test "$config_TARGET_LINK" = ""; then
TARGET_LINK=$TARGET_CC
else
TARGET_LINK=$config_TARGET_LINK
fi
AC_MSG_RESULT($TARGET_LINK)
AC_MSG_CHECKING([switches on the target compiler])
if test "$config_TARGET_TFLAGS" != ""; then
TARGET_TFLAGS=$config_TARGET_TFLAGS
else
TARGET_TFLAGS=$BUILD_CFLAGS
fi
if test "$config_TARGET_RANLIB" != ""; then
TARGET_RANLIB=$config_TARGET_RANLIB
else
AC_PROG_RANLIB
TARGET_RANLIB=$RANLIB
fi
if test "$config_TARGET_AR" != ""; then
TARGET_AR=$config_TARGET_AR
else
TARGET_AR='ar cr'
fi
AC_MSG_RESULT($TARGET_TFLAGS)
AC_SUBST(TARGET_CC)
AC_SUBST(TARGET_CFLAGS)
AC_SUBST(TARGET_LINK)
AC_SUBST(TARGET_LFLAGS)
AC_SUBST(TARGET_RANLIB)
AC_SUBST(TARGET_AR)
# Set the $cross variable if we are cross-compiling. Make
# it 0 if we are not.
#
AC_MSG_CHECKING([if host and target compilers are the same])
if test "$BUILD_CC" = "$TARGET_CC"; then
cross=0
AC_MSG_RESULT(yes)
else
cross=1
AC_MSG_RESULT(no)
fi
##########
# Do we want to support multithreaded use of sqlite
#
AC_ARG_ENABLE(threadsafe,
[ --enable-threadsafe Support threadsafe operation],,enable_threadsafe=no)
AC_MSG_CHECKING([whether to support threadsafe operation])
if test "$enable_threadsafe" = "no"; then
THREADSAFE=0
AC_MSG_RESULT([no])
else
THREADSAFE=1
AC_MSG_RESULT([yes])
fi
AC_SUBST(THREADSAFE)
if test "$THREADSAFE" = "1"; then
LIBS=""
AC_CHECK_LIB(pthread, pthread_create)
TARGET_THREAD_LIB="$LIBS"
LIBS=""
else
TARGET_THREAD_LIB=""
fi
AC_SUBST(TARGET_THREAD_LIB)
##########
# Do we want to support release
#
AC_ARG_ENABLE(releasemode,
[ --enable-releasemode Support libtool link to release mode],,enable_releasemode=no)
AC_MSG_CHECKING([whether to support shared library linked as release mode or not])
if test "$enable_releasemode" = "no"; then
ALLOWRELEASE=""
AC_MSG_RESULT([no])
else
ALLOWRELEASE="-release `cat VERSION`"
AC_MSG_RESULT([yes])
fi
AC_SUBST(ALLOWRELEASE)
##########
# Do we want temporary databases in memory
#
AC_ARG_ENABLE(tempstore,
[ --enable-tempstore Use an in-ram database for temporary tables (never,no,yes,always)],,enable_tempstore=yes)
AC_MSG_CHECKING([whether to use an in-ram database for temporary tables])
case "$enable_tempstore" in
never )
TEMP_STORE=0
AC_MSG_RESULT([never])
;;
no )
TEMP_STORE=1
AC_MSG_RESULT([no])
;;
always )
TEMP_STORE=3
AC_MSG_RESULT([always])
;;
* )
TEMP_STORE=2
AC_MSG_RESULT([yes])
;;
esac
AC_SUBST(TEMP_STORE)
###########
# Lots of things are different if we are compiling for Windows using
# the CYGWIN environment. So check for that special case and handle
# things accordingly.
#
AC_MSG_CHECKING([if executables have the .exe suffix])
if test "$config_BUILD_EXEEXT" = ".exe"; then
CYGWIN=yes
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(unknown)
fi
if test "$CYGWIN" != "yes"; then
AC_CYGWIN
fi
if test "$CYGWIN" = "yes"; then
BUILD_EXEEXT=.exe
else
BUILD_EXEEXT=$EXEEXT
fi
if test "$cross" = "0"; then
TARGET_EXEEXT=$BUILD_EXEEXT
else
TARGET_EXEEXT=$config_TARGET_EXEEXT
fi
if test "$TARGET_EXEEXT" = ".exe"; then
OS_UNIX=0
OS_WIN=1
tclsubdir=win
TARGET_CFLAGS="$TARGET_CFLAGS -DOS_WIN=1"
else
OS_UNIX=1
OS_WIN=0
tclsubdir=unix
TARGET_CFLAGS="$TARGET_CFLAGS -DOS_UNIX=1"
fi
AC_SUBST(BUILD_EXEEXT)
AC_SUBST(OS_UNIX)
AC_SUBST(OS_WIN)
AC_SUBST(TARGET_EXEEXT)
##########
# Extract generic linker options from the environment.
#
if test "$config_TARGET_LIBS" != ""; then
TARGET_LIBS=$config_TARGET_LIBS
else
TARGET_LIBS=""
fi
AC_SUBST(TARGET_LIBS)
##########
# Figure out what C libraries are required to compile Tcl programs.
#
if test "$config_TARGET_TCL_LIBS" != ""; then
TARGET_TCL_LIBS="$config_TARGET_TCL_LIBS"
else
if test "$with_tcl" != ""; then
extra=`echo $with_tcl/$tclsubdir/libtcl8*.a`
fi
CC=$TARGET_CC
AC_CHECK_FUNC(sin, LIBS="", LIBS="-lm")
AC_CHECK_LIB(dl, dlopen)
otherlibs=$LIBS
if test "$extra" != ""; then
LIBS=$extra
else
LIBS=""
AC_SEARCH_LIBS(Tcl_Init, dnl
tcl8.4 tcl8.3 tcl84 tcl83 tcl,,,$otherlibs)
fi
TARGET_TCL_LIBS="$LIBS $otherlibs"
fi
AC_SUBST(TARGET_TCL_LIBS)
##########
# Figure out where to get the TCL header files.
#
AC_MSG_CHECKING([TCL header files])
found=no
if test "$config_TARGET_TCL_INC" != ""; then
TARGET_TCL_INC=$config_TARGET_TCL_INC
found=yes
else
if test "$with_tcl" != ""; then
TARGET_TCL_INC="-I$with_tcl/generic -I$with_tcl/$tclsubdir"
found=yes
else
TARGET_TCL_INC=""
found=no
fi
fi
if test "$found" = "yes"; then
AC_MSG_RESULT($TARGET_TCL_INC)
else
AC_MSG_RESULT(not specified: still searching...)
AC_CHECK_HEADER(tcl.h, [found=yes])
fi
if test "$found" = "no"; then
for dir in /usr/local /usr/X11 /usr/X11R6 /usr/pkg /usr/contrib /usr; do
AC_CHECK_FILE($dir/include/tcl.h, found=yes)
if test "$found" = "yes"; then
TARGET_TCL_INC="-I$dir/include"
break
fi
done
fi
if test "$found" = "no"; then
TARGET_TCL_INC="-DNO_TCL=1"
fi
AC_SUBST(TARGET_TCL_INC)
##########
# Figure out what C libraries are required to compile programs
# that use "readline()" library.
#
if test "$config_TARGET_READLINE_LIBS" != ""; then
TARGET_READLINE_LIBS="$config_TARGET_READLINE_LIBS"
else
CC=$TARGET_CC
LIBS=""
AC_SEARCH_LIBS(tgetent, [readline ncurses curses termcap])
AC_CHECK_LIB([readline], [readline])
TARGET_READLINE_LIBS="$LIBS"
fi
AC_SUBST(TARGET_READLINE_LIBS)
##########
# Figure out where to get the READLINE header files.
#
AC_MSG_CHECKING([readline header files])
found=no
if test "$config_TARGET_READLINE_INC" != ""; then
TARGET_READLINE_INC=$config_TARGET_READLINE_INC
found=yes
fi
if test "$found" = "yes"; then
AC_MSG_RESULT($TARGET_READLINE_INC)
else
AC_MSG_RESULT(not specified: still searching...)
AC_CHECK_HEADER(readline.h, [found=yes])
fi
if test "$found" = "no"; then
for dir in /usr /usr/local /usr/local/readline /usr/contrib /mingw; do
AC_CHECK_FILE($dir/include/readline.h, found=yes)
if test "$found" = "yes"; then
TARGET_READLINE_INC="-I$dir/include"
break
fi
AC_CHECK_FILE($dir/include/readline/readline.h, found=yes)
if test "$found" = "yes"; then
TARGET_READLINE_INC="-I$dir/include/readline"
break
fi
done
fi
if test "$found" = "yes"; then
if test "$TARGET_READLINE_LIBS" = ""; then
TARGET_HAVE_READLINE=0
else
TARGET_HAVE_READLINE=1
fi
else
TARGET_HAVE_READLINE=0
fi
AC_SUBST(TARGET_READLINE_INC)
AC_SUBST(TARGET_HAVE_READLINE)
#########
# Figure out whether or not we have a "usleep()" function.
#
AC_CHECK_FUNC(usleep, [TARGET_CFLAGS="$TARGET_CFLAGS -DHAVE_USLEEP=1"])
#########
# Generate the output files.
#
AC_OUTPUT([
Makefile
sqlite3.pc
])
-251
View File
@@ -1,251 +0,0 @@
#!/bin/sh
#
# install - install a program, script, or datafile
# This comes from X11R5 (mit/util/scripts/install.sh).
#
# Copyright 1991 by the Massachusetts Institute of Technology
#
# Permission to use, copy, modify, distribute, and sell this software and its
# documentation for any purpose is hereby granted without fee, provided that
# the above copyright notice appear in all copies and that both that
# copyright notice and this permission notice appear in supporting
# documentation, and that the name of M.I.T. not be used in advertising or
# publicity pertaining to distribution of the software without specific,
# written prior permission. M.I.T. makes no representations about the
# suitability of this software for any purpose. It is provided "as is"
# without express or implied warranty.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch. It can only install one file at a time, a restriction
# shared with many OS's install programs.
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
# put in absolute paths if you don't have them in your path; or use env. vars.
mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
transformbasename=""
transform_arg=""
instcmd="$mvprog"
chmodcmd="$chmodprog 0755"
chowncmd=""
chgrpcmd=""
stripcmd=""
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=""
dst=""
dir_arg=""
while [ x"$1" != x ]; do
case $1 in
-c) instcmd="$cpprog"
shift
continue;;
-d) dir_arg=true
shift
continue;;
-m) chmodcmd="$chmodprog $2"
shift
shift
continue;;
-o) chowncmd="$chownprog $2"
shift
shift
continue;;
-g) chgrpcmd="$chgrpprog $2"
shift
shift
continue;;
-s) stripcmd="$stripprog"
shift
continue;;
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
shift
continue;;
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
shift
continue;;
*) if [ x"$src" = x ]
then
src=$1
else
# this colon is to work around a 386BSD /bin/sh bug
:
dst=$1
fi
shift
continue;;
esac
done
if [ x"$src" = x ]
then
echo "install: no input file specified"
exit 1
else
true
fi
if [ x"$dir_arg" != x ]; then
dst=$src
src=""
if [ -d $dst ]; then
instcmd=:
chmodcmd=""
else
instcmd=mkdir
fi
else
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if [ -f $src -o -d $src ]
then
true
else
echo "install: $src does not exist"
exit 1
fi
if [ x"$dst" = x ]
then
echo "install: no destination specified"
exit 1
else
true
fi
# If destination is a directory, append the input filename; if your system
# does not like double slashes in filenames, you may need to add some logic
if [ -d $dst ]
then
dst="$dst"/`basename $src`
else
true
fi
fi
## this sed command emulates the dirname command
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
# Make sure that the destination directory exists.
# this part is taken from Noah Friedman's mkinstalldirs script
# Skip lots of stat calls in the usual case.
if [ ! -d "$dstdir" ]; then
defaultIFS='
'
IFS="${IFS-${defaultIFS}}"
oIFS="${IFS}"
# Some sh's can't handle IFS=/ for some reason.
IFS='%'
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
IFS="${oIFS}"
pathcomp=''
while [ $# -ne 0 ] ; do
pathcomp="${pathcomp}${1}"
shift
if [ ! -d "${pathcomp}" ] ;
then
$mkdirprog "${pathcomp}"
else
true
fi
pathcomp="${pathcomp}/"
done
fi
if [ x"$dir_arg" != x ]
then
$doit $instcmd $dst &&
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
else
# If we're going to rename the final executable, determine the name now.
if [ x"$transformarg" = x ]
then
dstfile=`basename $dst`
else
dstfile=`basename $dst $transformbasename |
sed $transformarg`$transformbasename
fi
# don't allow the sed command to completely eliminate the filename
if [ x"$dstfile" = x ]
then
dstfile=`basename $dst`
else
true
fi
# Make a temp file name in the proper directory.
dsttmp=$dstdir/#inst.$$#
# Move or copy the file name to the temp name
$doit $instcmd $src $dsttmp &&
trap "rm -f ${dsttmp}" 0 &&
# and set any options; do chmod last to preserve setuid bits
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $instcmd $src $dsttmp" command.
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
# Now rename the file to the real destination.
$doit $rmcmd -f $dstdir/$dstfile &&
$doit $mvcmd $dsttmp $dstdir/$dstfile
fi &&
exit 0
File diff suppressed because it is too large. Load diff
-533
View File
@@ -1,533 +0,0 @@
###############################################################################
# The following macros should be defined before this script is
# invoked:
#
# TOP The toplevel directory of the source tree. This is the
# directory that contains this "Makefile.in" and the
# "configure.in" script.
#
# BCC C Compiler and options for use in building executables that
# will run on the platform that is doing the build.
#
# USLEEP If the target operating system supports the "usleep()" system
# call, then define the HAVE_USLEEP macro for all C modules.
#
# THREADSAFE If you want the SQLite library to be safe for use within a
# multi-threaded program, then define the following macro
# appropriately:
#
# THREADLIB Specify any extra linker options needed to make the library
# thread safe
#
# OPTS Extra compiler command-line options.
#
# EXE The suffix to add to executable files. ".exe" for windows
# and "" for Unix.
#
# TCC C Compiler and options for use in building executables that
# will run on the target platform. This is usually the same
# as BCC, unless you are cross-compiling.
#
# AR Tools used to build a static library.
# RANLIB
#
# TCL_FLAGS Extra compiler options needed for programs that use the
# TCL library.
#
# LIBTCL Linker options needed to link against the TCL library.
#
# READLINE_FLAGS Compiler options needed for programs that use the
# readline() library.
#
# LIBREADLINE Linker options needed by programs using readline() must
# link against.
#
# ENCODING "UTF8" or "ISO8859"
#
# Once the macros above are defined, the rest of this make script will
# build the SQLite library and testing tools.
################################################################################
# This is how we compile
#
TCCX = $(TCC) $(OPTS) $(THREADSAFE) $(USLEEP) -I. -I$(TOP)/src
# Object files for the SQLite library.
#
LIBOBJ+= attach.o auth.o btree.o build.o date.o delete.o \
expr.o func.o hash.o insert.o \
main.o opcodes.o os_mac.o os_unix.o os_win.o \
pager.o parse.o pragma.o printf.o random.o \
select.o table.o tclsqlite.o tokenize.o trigger.o \
update.o util.o vacuum.o \
vdbe.o vdbeapi.o vdbeaux.o vdbemem.o \
where.o utf.o legacy.o
# All of the source code files.
#
SRC = \
$(TOP)/src/attach.c \
$(TOP)/src/auth.c \
$(TOP)/src/btree.c \
$(TOP)/src/btree.h \
$(TOP)/src/build.c \
$(TOP)/src/date.c \
$(TOP)/src/delete.c \
$(TOP)/src/expr.c \
$(TOP)/src/func.c \
$(TOP)/src/hash.c \
$(TOP)/src/hash.h \
$(TOP)/src/insert.c \
$(TOP)/src/legacy.c \
$(TOP)/src/main.c \
$(TOP)/src/os_mac.c \
$(TOP)/src/os_unix.c \
$(TOP)/src/os_win.c \
$(TOP)/src/pager.c \
$(TOP)/src/pager.h \
$(TOP)/src/parse.y \
$(TOP)/src/pragma.c \
$(TOP)/src/printf.c \
$(TOP)/src/random.c \
$(TOP)/src/select.c \
$(TOP)/src/shell.c \
$(TOP)/src/sqlite.h.in \
$(TOP)/src/sqliteInt.h \
$(TOP)/src/table.c \
$(TOP)/src/tclsqlite.c \
$(TOP)/src/tokenize.c \
$(TOP)/src/trigger.c \
$(TOP)/src/utf.c \
$(TOP)/src/update.c \
$(TOP)/src/util.c \
$(TOP)/src/vacuum.c \
$(TOP)/src/vdbe.c \
$(TOP)/src/vdbe.h \
$(TOP)/src/vdbeapi.c \
$(TOP)/src/vdbeaux.c \
$(TOP)/src/vdbemem.c \
$(TOP)/src/vdbeInt.h \
$(TOP)/src/where.c
# Source code to the test files.
#
TESTSRC = \
$(TOP)/src/btree.c \
$(TOP)/src/func.c \
$(TOP)/src/os_mac.c \
$(TOP)/src/os_unix.c \
$(TOP)/src/os_win.c \
$(TOP)/src/pager.c \
$(TOP)/src/pragma.c \
$(TOP)/src/printf.c \
$(TOP)/src/test1.c \
$(TOP)/src/test2.c \
$(TOP)/src/test3.c \
$(TOP)/src/test4.c \
$(TOP)/src/test5.c \
$(TOP)/src/utf.c \
$(TOP)/src/util.c \
$(TOP)/src/vdbe.c \
$(TOP)/src/md5.c
# Header files used by all library source files.
#
HDR = \
sqlite3.h \
$(TOP)/src/btree.h \
config.h \
$(TOP)/src/hash.h \
opcodes.h \
$(TOP)/src/os.h \
$(TOP)/src/os_common.h \
$(TOP)/src/os_mac.h \
$(TOP)/src/os_unix.h \
$(TOP)/src/os_win.h \
$(TOP)/src/sqliteInt.h \
$(TOP)/src/vdbe.h \
parse.h
# Header files used by the VDBE submodule
#
VDBEHDR = \
$(HDR) \
$(TOP)/src/vdbeInt.h
# This is the default Makefile target. The objects listed here
# are what get build when you type just "make" with no arguments.
#
all: sqlite3.h config.h libsqlite3.a sqlite3$(EXE)
# Generate the file "last_change" which contains the date of change
# of the most recently modified source code file
#
last_change: $(SRC)
cat $(SRC) | grep '$$Id: ' | sort +4 | tail -1 \
| awk '{print $$5,$$6}' >last_change
libsqlite3.a: $(LIBOBJ)
$(AR) libsqlite3.a $(LIBOBJ)
$(RANLIB) libsqlite3.a
sqlite3$(EXE): $(TOP)/src/shell.c libsqlite3.a sqlite3.h
$(TCCX) $(READLINE_FLAGS) -o sqlite3$(EXE) $(TOP)/src/shell.c \
libsqlite3.a $(LIBREADLINE) $(THREADLIB)
objects: $(LIBOBJ_ORIG)
# This target creates a directory named "tsrc" and fills it with
# copies of all of the C source code and header files needed to
# build on the target system. Some of the C source code and header
# files are automatically generated. This target takes care of
# all that automatic generation.
#
target_source: $(SRC) $(VDBEHDR) opcodes.c
rm -rf tsrc
mkdir tsrc
cp $(SRC) $(VDBEHDR) tsrc
rm tsrc/sqlite.h.in tsrc/parse.y
cp parse.c opcodes.c tsrc
cp $(TOP)/sqlite3.def tsrc
# Rules to build the LEMON compiler generator
#
lemon: $(TOP)/tool/lemon.c $(TOP)/tool/lempar.c
$(BCC) -o lemon $(TOP)/tool/lemon.c
cp $(TOP)/tool/lempar.c .
# Rules to build individual files
#
attach.o: $(TOP)/src/attach.c $(HDR)
$(TCCX) -c $(TOP)/src/attach.c
auth.o: $(TOP)/src/auth.c $(HDR)
$(TCCX) -c $(TOP)/src/auth.c
btree.o: $(TOP)/src/btree.c $(HDR) $(TOP)/src/pager.h
$(TCCX) -c $(TOP)/src/btree.c
build.o: $(TOP)/src/build.c $(HDR)
$(TCCX) -c $(TOP)/src/build.c
# The config.h file will contain a single #define that tells us how
# many bytes are in a pointer. This only works if a pointer is the
# same size on the host as it is on the target. If you are cross-compiling
# to a target with a different pointer size, you'll need to manually
# configure the config.h file.
#
config.h:
echo '#include <stdio.h>' >temp.c
echo 'int main(){printf(' >>temp.c
echo '"#define SQLITE_PTR_SZ %d",sizeof(char*));' >>temp.c
echo 'exit(0);}' >>temp.c
$(BCC) -o temp temp.c
./temp >config.h
echo >>config.h
rm -f temp.c temp
date.o: $(TOP)/src/date.c $(HDR)
$(TCCX) -c $(TOP)/src/date.c
delete.o: $(TOP)/src/delete.c $(HDR)
$(TCCX) -c $(TOP)/src/delete.c
expr.o: $(TOP)/src/expr.c $(HDR)
$(TCCX) -c $(TOP)/src/expr.c
func.o: $(TOP)/src/func.c $(HDR)
$(TCCX) -c $(TOP)/src/func.c
hash.o: $(TOP)/src/hash.c $(HDR)
$(TCCX) -c $(TOP)/src/hash.c
insert.o: $(TOP)/src/insert.c $(HDR)
$(TCCX) -c $(TOP)/src/insert.c
legacy.o: $(TOP)/src/legacy.c $(HDR)
$(TCCX) -c $(TOP)/src/legacy.c
main.o: $(TOP)/src/main.c $(HDR)
$(TCCX) -c $(TOP)/src/main.c
pager.o: $(TOP)/src/pager.c $(HDR) $(TOP)/src/pager.h
$(TCCX) -c $(TOP)/src/pager.c
opcodes.o: opcodes.c
$(TCCX) -c opcodes.c
opcodes.c: opcodes.h $(TOP)/mkopcodec.awk
sort -n +2 opcodes.h | awk -f $(TOP)/mkopcodec.awk >opcodes.c
opcodes.h: parse.h $(TOP)/src/vdbe.c $(TOP)/mkopcodeh.awk
cat parse.h $(TOP)/src/vdbe.c | awk -f $(TOP)/mkopcodeh.awk >opcodes.h
os_mac.o: $(TOP)/src/os_mac.c $(HDR)
$(TCCX) -c $(TOP)/src/os_mac.c
os_unix.o: $(TOP)/src/os_unix.c $(HDR)
$(TCCX) -c $(TOP)/src/os_unix.c
os_win.o: $(TOP)/src/os_win.c $(HDR)
$(TCCX) -c $(TOP)/src/os_win.c
parse.o: parse.c $(HDR)
$(TCCX) -c parse.c
parse.h: parse.c
parse.c: $(TOP)/src/parse.y lemon
cp $(TOP)/src/parse.y .
./lemon parse.y
pragma.o: $(TOP)/src/pragma.c $(HDR)
$(TCCX) $(TCL_FLAGS) -c $(TOP)/src/pragma.c
printf.o: $(TOP)/src/printf.c $(HDR)
$(TCCX) $(TCL_FLAGS) -c $(TOP)/src/printf.c
random.o: $(TOP)/src/random.c $(HDR)
$(TCCX) -c $(TOP)/src/random.c
select.o: $(TOP)/src/select.c $(HDR)
$(TCCX) -c $(TOP)/src/select.c
sqlite3.h: $(TOP)/src/sqlite.h.in
sed -e s/--VERS--/`cat ${TOP}/VERSION`/ \
-e s/--ENCODING--/$(ENCODING)/ \
$(TOP)/src/sqlite.h.in >sqlite3.h
table.o: $(TOP)/src/table.c $(HDR)
$(TCCX) -c $(TOP)/src/table.c
tclsqlite.o: $(TOP)/src/tclsqlite.c $(HDR)
$(TCCX) $(TCL_FLAGS) -c $(TOP)/src/tclsqlite.c
tokenize.o: $(TOP)/src/tokenize.c $(HDR)
$(TCCX) -c $(TOP)/src/tokenize.c
trigger.o: $(TOP)/src/trigger.c $(HDR)
$(TCCX) -c $(TOP)/src/trigger.c
update.o: $(TOP)/src/update.c $(HDR)
$(TCCX) -c $(TOP)/src/update.c
utf.o: $(TOP)/src/utf.c $(HDR)
$(TCCX) -c $(TOP)/src/utf.c
util.o: $(TOP)/src/util.c $(HDR)
$(TCCX) -c $(TOP)/src/util.c
vacuum.o: $(TOP)/src/vacuum.c $(HDR)
$(TCCX) -c $(TOP)/src/vacuum.c
vdbe.o: $(TOP)/src/vdbe.c $(VDBEHDR)
$(TCCX) -c $(TOP)/src/vdbe.c
vdbeapi.o: $(TOP)/src/vdbeapi.c $(VDBEHDR)
$(TCCX) -c $(TOP)/src/vdbeapi.c
vdbeaux.o: $(TOP)/src/vdbeaux.c $(VDBEHDR)
$(TCCX) -c $(TOP)/src/vdbeaux.c
vdbemem.o: $(TOP)/src/vdbemem.c $(VDBEHDR)
$(TCCX) -c $(TOP)/src/vdbemem.c
where.o: $(TOP)/src/where.c $(HDR)
$(TCCX) -c $(TOP)/src/where.c
# Rules for building test programs and for running tests
#
tclsqlite3: $(TOP)/src/tclsqlite.c libsqlite3.a
$(TCCX) $(TCL_FLAGS) -DTCLSH=1 -o tclsqlite3 \
$(TOP)/src/tclsqlite.c libsqlite3.a $(LIBTCL) $(THREADLIB)
testfixture$(EXE): $(TOP)/src/tclsqlite.c libsqlite3.a $(TESTSRC)
$(TCCX) $(TCL_FLAGS) -DTCLSH=1 -DSQLITE_TEST=1 -o testfixture$(EXE) \
$(TESTSRC) $(TOP)/src/tclsqlite.c \
libsqlite3.a $(LIBTCL) $(THREADLIB)
crashtest: $(TOP)/src/tclsqlite.c libsqlite3.a $(TESTSRC) $(TOP)/src/os_test.c
$(TCCX) $(TCL_FLAGS) -DOS_TEST=1 -DTCLSH=1 -DSQLITE_TEST=1 \
-o crashtest \
$(TESTSRC) $(TOP)/src/os_test.c $(TOP)/src/tclsqlite.c \
libsqlite3.a $(LIBTCL) $(THREADLIB)
fulltest: testfixture$(EXE) sqlite3$(EXE) crashtest
./testfixture$(EXE) $(TOP)/test/all.test
test: testfixture$(EXE) sqlite3$(EXE)
./testfixture$(EXE) $(TOP)/test/quick.test
sqlite3_analyzer$(EXE): $(TOP)/src/tclsqlite.c libsqlite3.a $(TESTSRC) \
$(TOP)/tool/spaceanal.tcl
sed \
-e '/^#/d' \
-e 's,\\,\\\\,g' \
-e 's,",\\",g' \
-e 's,^,",' \
-e 's,$$,\\n",' \
$(TOP)/tool/spaceanal.tcl >spaceanal_tcl.h
$(TCCX) $(TCL_FLAGS) -DTCLSH=2 -DSQLITE_TEST=1 -static -o \
sqlite3_analyzer$(EXE) $(TESTSRC) $(TOP)/src/tclsqlite.c \
libsqlite3.a $(LIBTCL) $(THREADLIB)
# Rules used to build documentation
#
arch.html: $(TOP)/www/arch.tcl
tclsh $(TOP)/www/arch.tcl >arch.html
arch.png: $(TOP)/www/arch.png
cp $(TOP)/www/arch.png .
c_interface.html: $(TOP)/www/c_interface.tcl
tclsh $(TOP)/www/c_interface.tcl >c_interface.html
capi3.html: $(TOP)/www/capi3.tcl
tclsh $(TOP)/www/capi3.tcl >capi3.html
capi3ref.html: $(TOP)/www/capi3ref.tcl
tclsh $(TOP)/www/capi3ref.tcl >capi3ref.html
changes.html: $(TOP)/www/changes.tcl
tclsh $(TOP)/www/changes.tcl >changes.html
copyright.html: $(TOP)/www/copyright.tcl
tclsh $(TOP)/www/copyright.tcl >copyright.html
copyright-release.html: $(TOP)/www/copyright-release.html
cp $(TOP)/www/copyright-release.html .
copyright-release.pdf: $(TOP)/www/copyright-release.pdf
cp $(TOP)/www/copyright-release.pdf .
common.tcl: $(TOP)/www/common.tcl
cp $(TOP)/www/common.tcl .
conflict.html: $(TOP)/www/conflict.tcl
tclsh $(TOP)/www/conflict.tcl >conflict.html
datatypes.html: $(TOP)/www/datatypes.tcl
tclsh $(TOP)/www/datatypes.tcl >datatypes.html
datatype3.html: $(TOP)/www/datatype3.tcl
tclsh $(TOP)/www/datatype3.tcl >datatype3.html
docs.html: $(TOP)/www/docs.tcl
tclsh $(TOP)/www/docs.tcl >docs.html
download.html: $(TOP)/www/download.tcl
mkdir -p doc
tclsh $(TOP)/www/download.tcl >download.html
faq.html: $(TOP)/www/faq.tcl
tclsh $(TOP)/www/faq.tcl >faq.html
fileformat.html: $(TOP)/www/fileformat.tcl
tclsh $(TOP)/www/fileformat.tcl >fileformat.html
formatchng.html: $(TOP)/www/formatchng.tcl
tclsh $(TOP)/www/formatchng.tcl >formatchng.html
index.html: $(TOP)/www/index.tcl last_change
tclsh $(TOP)/www/index.tcl >index.html
lang.html: $(TOP)/www/lang.tcl
tclsh $(TOP)/www/lang.tcl >lang.html
lockingv3.html: $(TOP)/www/lockingv3.tcl
tclsh $(TOP)/www/lockingv3.tcl >lockingv3.html
oldnews.html: $(TOP)/www/oldnews.tcl
tclsh $(TOP)/www/oldnews.tcl >oldnews.html
omitted.html: $(TOP)/www/omitted.tcl
tclsh $(TOP)/www/omitted.tcl >omitted.html
opcode.html: $(TOP)/www/opcode.tcl $(TOP)/src/vdbe.c
tclsh $(TOP)/www/opcode.tcl $(TOP)/src/vdbe.c >opcode.html
mingw.html: $(TOP)/www/mingw.tcl
tclsh $(TOP)/www/mingw.tcl >mingw.html
nulls.html: $(TOP)/www/nulls.tcl
tclsh $(TOP)/www/nulls.tcl >nulls.html
quickstart.html: $(TOP)/www/quickstart.tcl
tclsh $(TOP)/www/quickstart.tcl >quickstart.html
speed.html: $(TOP)/www/speed.tcl
tclsh $(TOP)/www/speed.tcl >speed.html
sqlite.gif: $(TOP)/art/SQLite.gif
cp $(TOP)/art/SQLite.gif sqlite.gif
sqlite.html: $(TOP)/www/sqlite.tcl
tclsh $(TOP)/www/sqlite.tcl >sqlite.html
support.html: $(TOP)/www/support.tcl
tclsh $(TOP)/www/support.tcl >support.html
tclsqlite.html: $(TOP)/www/tclsqlite.tcl
tclsh $(TOP)/www/tclsqlite.tcl >tclsqlite.html
vdbe.html: $(TOP)/www/vdbe.tcl
tclsh $(TOP)/www/vdbe.tcl >vdbe.html
version3.html: $(TOP)/www/version3.tcl
tclsh $(TOP)/www/version3.tcl >version3.html
# Files to be published on the website.
#
DOC = \
arch.html \
arch.png \
c_interface.html \
capi3.html \
capi3ref.html \
changes.html \
copyright.html \
copyright-release.html \
copyright-release.pdf \
conflict.html \
datatypes.html \
datatype3.html \
docs.html \
download.html \
faq.html \
fileformat.html \
formatchng.html \
index.html \
lang.html \
lockingv3.html \
mingw.html \
nulls.html \
oldnews.html \
omitted.html \
opcode.html \
quickstart.html \
speed.html \
sqlite.gif \
sqlite.html \
support.html \
tclsqlite.html \
vdbe.html \
version3.html
doc: common.tcl $(DOC)
mkdir -p doc
mv $(DOC) doc
# Standard install and cleanup targets
#
install: sqlite3 libsqlite3.a sqlite3.h
mv sqlite3 /usr/bin
mv libsqlite3.a /usr/lib
mv sqlite3.h /usr/include
clean:
rm -f *.o sqlite3 libsqlite3.a sqlite3.h opcodes.*
rm -f lemon lempar.c parse.* sqlite*.tar.gz
rm -f $(PUBLISH)
rm -f *.da *.bb *.bbg gmon.out
rm -rf tsrc
-42
View File
@@ -1,42 +0,0 @@
#!/bin/sh
#
# This script is used to compile SQLite into a DLL.
#
# Two separate DLLs are generated. "sqlite3.dll" is the core
# library. "tclsqlite3.dll" contains the TCL bindings and is the
# library that is loaded into TCL in order to run SQLite.
#
make target_source
cd tsrc
PATH=$PATH:/opt/mingw/bin
TCLDIR=/home/drh/tcltk/846/win/846win
TCLSTUBLIB=$TCLDIR/libtcl84stub.a
OPTS='-DUSE_TCL_STUBS=1 -DNDEBUG=1 -DTHREADSAFE=1'
CC="i386-mingw32msvc-gcc -O2 $OPTS -I. -I$TCLDIR"
rm shell.c
for i in *.c; do
CMD="$CC -c $i"
echo $CMD
$CMD
done
echo 'EXPORTS' >tclsqlite3.def
echo 'Tclsqlite3_Init' >>tclsqlite3.def
echo 'Sqlite3_Init' >>tclsqlite3.def
i386-mingw32msvc-dllwrap \
--def tclsqlite3.def -v --export-all \
--driver-name i386-mingw32msvc-gcc \
--dlltool-name i386-mingw32msvc-dlltool \
--as i386-mingw32msvc-as \
--target i386-mingw32 \
-dllname tclsqlite3.dll -lmsvcrt *.o $TCLSTUBLIB
i386-mingw32msvc-strip tclsqlite3.dll
rm tclsqlite.o
i386-mingw32msvc-dllwrap \
--def sqlite3.def -v --export-all \
--driver-name i386-mingw32msvc-gcc \
--dlltool-name i386-mingw32msvc-dlltool \
--as i386-mingw32msvc-as \
--target i386-mingw32 \
-dllname sqlite3.dll -lmsvcrt *.o
i386-mingw32msvc-strip sqlite3.dll
cd ..
-22
View File
@@ -1,22 +0,0 @@
#!/usr/bin/awk -f
#
# This AWK script scans the opcodes.h file (which is itself generated by
# another awk script) and uses the information gleaned to create the
# opcodes.c source file.
#
# Opcodes.c contains strings which are the symbolic names for the various
# opcodes used by the VDBE. These strings are used when disassembling a
# VDBE program during tracing or as a result of the EXPLAIN keyword.
#
BEGIN {
print "/* Automatically generated. Do not edit */"
print "/* See the mkopcodec.h script for details. */"
print "const char *const sqlite3OpcodeNames[] = { \"?\","
}
/^#define OP_/ {
sub("OP_","",$2)
print " \"" $2 "\","
}
END {
print "};"
}
-48
View File
@@ -1,48 +0,0 @@
#!/usr/bin/awk -f
#
# This AWK script scans a concatenation of the parse.h output file from the
# parser and the vdbe.c source file in order to generate the opcodes numbers
# for all opcodes.
#
# The lines of the vdbe.c that we are interested in are of the form:
#
# case OP_aaaa: /* same as TK_bbbbb */
#
# The TK_ comment is optional. If it is present, then the value assigned to
# the OP_ is the same as the TK_ value. If missing, the OP_ value is assigned
# a small integer that is different from every other OP_ value.
#
# Remember the TK_ values from the parse.h file
/^#define TK_/ {
tk[$2] = $3
}
# Scan for "case OP_aaaa:" lines in the vdbe.c file
/^case OP_/ {
name = $2
gsub(/:/,"",name)
gsub("\r","",name)
op[name] = -1
for(i=3; i<NF-2; i++){
if($i=="same" && $(i+1)=="as"){
op[name] = tk[$(i+2)]
used[op[name]] = 1
}
}
}
# Assign numbers to all opcodes and output the result.
END {
cnt = 0
print "/* Automatically generated. Do not edit */"
print "/* See the mkopcodeh.awk script for details */"
for(name in op){
if( op[name]<0 ){
cnt++
while( used[cnt] ) cnt++
op[name] = cnt
}
printf "#define %-30s %d\n", name, op[name]
}
}
-27
View File
@@ -1,27 +0,0 @@
#!/bin/sh
#
# This script is used to compile SQLite into a shared library on Linux.
#
# Two separate shared libraries are generated. "sqlite3.so" is the core
# library. "tclsqlite3.so" contains the TCL bindings and is the
# library that is loaded into TCL in order to run SQLite.
#
make target_source
cd tsrc
rm shell.c
TCLDIR=/home/drh/tcltk/846/linux/846linux
TCLSTUBLIB=$TCLDIR/libtclstub8.4g.a
OPTS='-DUSE_TCL_STUBS=1 -DNDEBUG=1'
for i in *.c; do
CMD="cc -fPIC $OPTS -O2 -I. -I$TCLDIR -c $i"
echo $CMD
$CMD
done
echo gcc -shared *.o $TCLSTUBLIB -o tclsqlite3.so
gcc -shared *.o $TCLSTUBLIB -o tclsqlite3.so
strip tclsqlite3.so
rm tclsqlite.c tclsqlite.o
echo gcc -shared *.o -o sqlite3.so
gcc -shared *.o -o sqlite3.so
strip sqlite3.so
cd ..
-113
View File
@@ -1,113 +0,0 @@
#!/bin/sh
#
# This script is used to compile SQLite and all its documentation and
# ship everything up to the SQLite website. This script will only work
# on the system "zadok" at the Hwaci offices. But others might find
# the script useful as an example.
#
# Set srcdir to the name of the directory that contains the publish.sh
# script.
#
srcdir=`echo "$0" | sed 's%\(^.*\)/[^/][^/]*$%\1%'`
# Get the makefile.
#
cp $srcdir/Makefile.linux-gcc ./Makefile
chmod +x $srcdir/install-sh
# Get the current version number - needed to help build filenames
#
VERS=`cat $srcdir/VERSION`
VERSW=`sed 's/\./_/g' $srcdir/VERSION`
# Start by building an sqlite shell for linux.
#
make clean
make sqlite3
strip sqlite3
mv sqlite3 sqlite3-$VERS.bin
gzip sqlite3-$VERS.bin
mv sqlite3-$VERS.bin.gz doc
# Build a source archive useful for windows.
#
make target_source
cd tsrc
zip ../doc/sqlite-source-$VERSW.zip *
cd ..
# Build the sqlite.so and tclsqlite.so shared libraries
# under Linux
#
. $srcdir/mkso.sh
cd tsrc
mv tclsqlite3.so tclsqlite-$VERS.so
gzip tclsqlite-$VERS.so
mv tclsqlite-$VERS.so.gz ../doc
mv sqlite3.so sqlite-$VERS.so
gzip sqlite-$VERS.so
mv sqlite-$VERS.so.gz ../doc
cd ..
# Build the tclsqlite3.dll and sqlite3.dll shared libraries.
#
. $srcdir/mkdll.sh
cd tsrc
echo zip ../doc/tclsqlite-$VERSW.zip tclsqlite3.dll
zip ../doc/tclsqlite-$VERSW.zip tclsqlite3.dll
echo zip ../doc/sqlitedll-$VERSW.zip sqlite3.dll sqlite3.def
zip ../doc/sqlitedll-$VERSW.zip sqlite3.dll sqlite3.def
cd ..
# Build the sqlite.exe executable for windows.
#
make target_source
cd tsrc
rm tclsqlite.c
OPTS='-DSTATIC_BUILD=1 -DNDEBUG=1'
i386-mingw32msvc-gcc -O2 $OPTS -I. -I$TCLDIR *.c -o sqlite3.exe
zip ../doc/sqlite-$VERSW.zip sqlite3.exe
cd ..
# Construct a tarball of the source tree
#
ORIGIN=`pwd`
cd $srcdir
cd ..
EXCLUDE=`find sqlite -print | grep CVS | sed 's,^, --exclude ,'`
tar czf $ORIGIN/doc/sqlite-$VERS.tar.gz $EXCLUDE sqlite
cd $ORIGIN
#
# Build RPMS (binary) and Source RPM
#
# Make sure we are properly setup to build RPMs
#
echo "%HOME %{expand:%%(cd; pwd)}" > $HOME/.rpmmacros
echo "%_topdir %{HOME}/rpm" >> $HOME/.rpmmacros
mkdir $HOME/rpm
mkdir $HOME/rpm/BUILD
mkdir $HOME/rpm/SOURCES
mkdir $HOME/rpm/RPMS
mkdir $HOME/rpm/SRPMS
mkdir $HOME/rpm/SPECS
# create the spec file from the template
sed s/SQLITE_VERSION/$VERS/g $srcdir/spec.template > $HOME/rpm/SPECS/sqlite.spec
# copy the source tarball to the rpm directory
cp doc/sqlite-$VERS.tar.gz $HOME/rpm/SOURCES/.
# build all the rpms
rpm -ba $HOME/rpm/SPECS/sqlite.spec >& rpm-$vers.log
# copy the RPMs into the build directory.
mv $HOME/rpm/RPMS/i386/sqlite*-$vers*.rpm doc
mv $HOME/rpm/SRPMS/sqlite-$vers*.rpm doc
# Build the website
#
#cp $srcdir/../historical/* doc
make doc
-62
View File
@@ -1,62 +0,0 @@
%define name sqlite
%define version SQLITE_VERSION
%define release 1
Name: %{name}
Summary: SQLite is a C library that implements an embeddable SQL database engine
Version: %{version}
Release: %{release}
Source: %{name}-%{version}.tar.gz
Group: System/Libraries
URL: http://www.hwaci.com/sw/sqlite/
License: Public Domain
BuildRoot: %{_tmppath}/%{name}-%{version}-root
%description
SQLite is a C library that implements an embeddable SQL database engine.
Programs that link with the SQLite library can have SQL database access
without running a separate RDBMS process. The distribution comes with a
standalone command-line access program (sqlite) that can be used to
administer an SQLite database and which serves as an example of how to
use the SQLite library.
%package -n %{name}-devel
Summary: Header files and libraries for developing apps which will use sqlite
Group: Development/C
Requires: %{name} = %{version}-%{release}
%description -n %{name}-devel
The sqlite-devel package contains the header files and libraries needed
to develop programs that use the sqlite database library.
%prep
%setup -q -n %{name}
%build
CFLAGS="%optflags -DNDEBUG=1" CXXFLAGS="%optflags -DNDEBUG=1" ./configure --prefix=%{_prefix}
make
make doc
%install
install -d $RPM_BUILD_ROOT/%{_prefix}
install -d $RPM_BUILD_ROOT/%{_prefix}/bin
install -d $RPM_BUILD_ROOT/%{_prefix}/include
install -d $RPM_BUILD_ROOT/%{_prefix}/lib
make install prefix=$RPM_BUILD_ROOT/%{_prefix}
%clean
rm -fr $RPM_BUILD_ROOT
%files
%defattr(-, root, root)
%{_libdir}/*.so*
%{_bindir}/*
%files -n %{name}-devel
%defattr(-, root, root)
%{_libdir}/pkgconfig/sqlite3.pc
%{_libdir}/*.a
%{_libdir}/*.la
%{_includedir}/*
%doc doc/*
-203
View File
@@ -1,203 +0,0 @@
.\" Hey, EMACS: -*- nroff -*-
.\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1)
.TH SQLITE 1 "Mon Apr 15 23:49:17 2002"
.\" Please adjust this date whenever revising the manpage.
.\"
.\" Some roff macros, for reference:
.\" .nh disable hyphenation
.\" .hy enable hyphenation
.\" .ad l left justify
.\" .ad b justify to both left and right margins
.\" .nf disable filling
.\" .fi enable filling
.\" .br insert line break
.\" .sp <n> insert n+1 empty lines
.\" for manpage-specific macros, see man(7)
.SH NAME
sqlite \- A command line interface for SQLite
.SH SYNOPSIS
.B sqlite
.RI [ options ] " filename " [ SQL ]
.SS SUMMARY
.PP
sqlite is a terminal-based front-end to the SQLite library. It enables
you to type in queries interactively, issue them to SQLite and see the
results. Alternatively, you can specify SQL code on the command-line. In
addition it provides a number of meta-commands.
.SH DESCRIPTION
This manual page documents briefly the
.B sqlite
command.
This manual page was written for the Debian GNU/Linux distribution
because the original program does not have a manual page.
.SS GETTING STARTED
.PP
To start the sqlite program, just type "sqlite" followed by the name
the file that holds the SQLite database. If the file does not exist, a
new one is created automatically. The sqlite program will then prompt
you to enter SQL. Type in SQL statements (terminated by a semicolon),
press "Enter" and the SQL will be executed.
For example, to create a new SQLite database named "ex1" with a single
table named "tbl1", you might do this:
.sp
.nf
$ sqlite ex1
SQLite version 2.0.0
Enter ".help" for instructions
sqlite> create table tbl1(one varchar(10), two smallint);
sqlite> insert into tbl1 values('hello!',10);
sqlite> insert into tbl1 values('goodbye', 20);
sqlite> select * from tbl1;
hello!|10
goodbye|20
sqlite>
.sp
.fi
.SS SQLITE META-COMMANDS
.PP
Most of the time, sqlite just reads lines of input and passes them on
to the SQLite library for execution. But if an input line begins with
a dot ("."), then that line is intercepted and interpreted by the
sqlite program itself. These "dot commands" are typically used to
change the output format of queries, or to execute certain prepackaged
query statements.
For a listing of the available dot commands, you can enter ".help" at
any time. For example:
.sp
.nf
.cc |
sqlite> .help
.dump ?TABLE? ... Dump the database in an text format
.echo ON|OFF Turn command echo on or off
.exit Exit this program
.explain ON|OFF Turn output mode suitable for EXPLAIN on or off.
"off" will revert to the output mode that was
previously in effect
.header(s) ON|OFF Turn display of headers on or off
.help Show this message
.indices TABLE Show names of all indices on TABLE
.mode MODE Set mode to one of "line(s)", "column(s)",
"insert", "list", or "html"
.mode insert TABLE Generate SQL insert statements for TABLE
.nullvalue STRING Print STRING instead of nothing for NULL data
.output FILENAME Send output to FILENAME
.output stdout Send output to the screen
.prompt MAIN CONTINUE Replace the standard prompts
"sqlite > " and " ...> "
with the strings MAIN and CONTINUE
CONTINUE is optional.
.quit Exit this program
.read FILENAME Execute SQL in FILENAME
.reindex ?TABLE? Rebuild indices
.schema ?TABLE? Show the CREATE statements
.separator STRING Change separator string for "list" mode
.show Show the current values for the following:
.echo
.explain
.mode
.nullvalue
.output
.separator
.width
.tables ?PATTERN? List names of tables matching a pattern
.timeout MS Try opening locked tables for MS milliseconds
.width NUM NUM ... Set column widths for "column" mode
sqlite>
|cc .
.sp
.fi
.SH OPTIONS
The program has the following options:
.TP
.BI \-init\ file
Read in and process 'file', which contains "dot commands".
You can use this file to initialize display settings.
.TP
.B \-html
Set output mode to HTML.
.TP
.B \-list
Set output mode to 'list'.
.TP
.B \-line
Set output mode to 'line'.
.TP
.B \-column
Set output mode to 'column'.
.TP
.BI \-separator\ separator
Specify which output field separator for 'list' mode to use.
Default is '|'.
.TP
.BI \-nullvalue\ string
When a null is encountered, print 'string'. Default is no string.
.TP
.B \-[no]header
Turn headers on or off. Default is off.
.TP
.B \-echo
Print commands before execution.
.SH OUTPUT MODE
The SQLite program has different output modes, which define the way
the output (from queries) is formatted.
In 'list' mode, which is the default, one record per line is output,
each field separated by the separator specified with the
\fB-separator\fP option or \fB.separator\fP command.
In 'line' mode, each column is output on its own line, records are
separated by blank lines.
In HTML mode, an XHTML table is generated.
In 'column' mode, one record per line is output, aligned neatly in colums.
.SH INIT FILE
sqlite can be initialized using resource files. These can be combined with
command line arguments to set up sqlite exactly the way you want it.
Initialization proceeds as follows:
o The defaults of
.sp
.nf
.cc |
mode = LIST
separator = "|"
main prompt = "sqlite> "
continue prompt = " ...> "
|cc .
.sp
.fi
are established.
o If a file .sqliterc can be found in the user's home directory, it is
read and processed. It should only contain "dot commands". If the
file is not found or cannot be read, processing continues without
notification.
o If a file is specified on the command line with the -init option, it
is processed in the same manner as .sqliterc
o All other command line options are processed
o The database is opened and you are now ready to begin.
.SH SEE ALSO
http://www.hwaci.com/sw/sqlite/
.br
The sqlite-doc package
.SH AUTHOR
This manual page was originally written by Andreas Rottmann
<rotty@debian.org>, for the Debian GNU/Linux system (but may be used
by others).
-12
View File
@@ -1,12 +0,0 @@
# Package Information for pkg-config
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: SQLite
Description: SQL database engine
Version: @VERSION@
Libs: -L${libdir} -lsqlite
Cflags: -I${includedir}
-91
View File
@@ -1,91 +0,0 @@
EXPORTS
sqlite3_aggregate_context
sqlite3_aggregate_count
sqlite3_bind_blob
sqlite3_bind_double
sqlite3_bind_int
sqlite3_bind_int64
sqlite3_bind_null
sqlite3_bind_parameter_count
sqlite3_bind_parameter_index
sqlite3_bind_parameter_name
sqlite3_bind_text
sqlite3_bind_text16
sqlite3_busy_handler
sqlite3_busy_timeout
sqlite3_changes
sqlite3_close
sqlite3_collation_needed
sqlite3_collation_needed16
sqlite3_column_blob
sqlite3_column_bytes
sqlite3_column_bytes16
sqlite3_column_count
sqlite3_column_decltype
sqlite3_column_decltype16
sqlite3_column_double
sqlite3_column_int
sqlite3_column_int64
sqlite3_column_name
sqlite3_column_name16
sqlite3_column_text
sqlite3_column_text16
sqlite3_column_type
sqlite3_commit_hook
sqlite3_complete
sqlite3_complete16
sqlite3_create_collation
sqlite3_create_collation16
sqlite3_create_function
sqlite3_create_function16
sqlite3_data_count
sqlite3_errcode
sqlite3_errmsg
sqlite3_errmsg16
sqlite3_exec
sqlite3_finalize
sqlite3_free
sqlite3_free_table
sqlite3_get_auxdata
sqlite3_get_table
sqlite3_interrupt
sqlite3_last_insert_rowid
sqlite3_libversion
sqlite3_mprintf
sqlite3_open
sqlite3_open16
sqlite3_prepare
sqlite3_prepare16
sqlite3_progress_handler
sqlite3_reset
sqlite3_result_blob
sqlite3_result_double
sqlite3_result_error
sqlite3_result_error16
sqlite3_result_int
sqlite3_result_int64
sqlite3_result_null
sqlite3_result_text
sqlite3_result_text16
sqlite3_result_text16be
sqlite3_result_text16le
sqlite3_result_value
sqlite3_set_authorizer
sqlite3_set_auxdata
sqlite3_snprintf
sqlite3_step
sqlite3_total_changes
sqlite3_trace
sqlite3_user_data
sqlite3_value_blob
sqlite3_value_bytes
sqlite3_value_bytes16
sqlite3_value_double
sqlite3_value_int
sqlite3_value_int64
sqlite3_value_text
sqlite3_value_text16
sqlite3_value_text16be
sqlite3_value_text16le
sqlite3_value_type
sqlite3_vmprintf
-12
View File
@@ -1,12 +0,0 @@
# Package Information for pkg-config
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: SQLite
Description: SQL database engine
Version: @VERSION@
Libs: -L${libdir} -lsqlite3
Cflags: -I${includedir}
-329
View File
@@ -1,329 +0,0 @@
/*
** 2003 April 6
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains code used to implement the ATTACH and DETACH commands.
**
** $Id$
*/
#include "sqliteInt.h"
/*
** This routine is called by the parser to process an ATTACH statement:
**
** ATTACH DATABASE filename AS dbname
**
** The pFilename and pDbname arguments are the tokens that define the
** filename and dbname in the ATTACH statement.
*/
void sqlite3Attach(
Parse *pParse, /* The parser context */
Token *pFilename, /* Name of database file */
Token *pDbname, /* Name of the database to use internally */
int keyType, /* 0: no key. 1: TEXT, 2: BLOB */
Token *pKey /* Text of the key for keytype 1 and 2 */
){
Db *aNew;
int rc, i;
char *zFile, *zName;
sqlite3 *db;
Vdbe *v;
v = sqlite3GetVdbe(pParse);
if( !v ) return;
sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
if( pParse->explain ) return;
db = pParse->db;
if( db->nDb>=MAX_ATTACHED+2 ){
sqlite3ErrorMsg(pParse, "too many attached databases - max %d",
MAX_ATTACHED);
pParse->rc = SQLITE_ERROR;
return;
}
if( !db->autoCommit ){
sqlite3ErrorMsg(pParse, "cannot ATTACH database within transaction");
pParse->rc = SQLITE_ERROR;
return;
}
zFile = sqlite3NameFromToken(pFilename);;
if( zFile==0 ) return;
#ifndef SQLITE_OMIT_AUTHORIZATION
if( sqlite3AuthCheck(pParse, SQLITE_ATTACH, zFile, 0, 0)!=SQLITE_OK ){
sqliteFree(zFile);
return;
}
#endif /* SQLITE_OMIT_AUTHORIZATION */
zName = sqlite3NameFromToken(pDbname);
if( zName==0 ) return;
for(i=0; i<db->nDb; i++){
char *z = db->aDb[i].zName;
if( z && sqlite3StrICmp(z, zName)==0 ){
sqlite3ErrorMsg(pParse, "database %z is already in use", zName);
pParse->rc = SQLITE_ERROR;
sqliteFree(zFile);
return;
}
}
if( db->aDb==db->aDbStatic ){
aNew = sqliteMalloc( sizeof(db->aDb[0])*3 );
if( aNew==0 ) return;
memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2);
}else{
aNew = sqliteRealloc(db->aDb, sizeof(db->aDb[0])*(db->nDb+1) );
if( aNew==0 ) return;
}
db->aDb = aNew;
aNew = &db->aDb[db->nDb++];
memset(aNew, 0, sizeof(*aNew));
sqlite3HashInit(&aNew->tblHash, SQLITE_HASH_STRING, 0);
sqlite3HashInit(&aNew->idxHash, SQLITE_HASH_STRING, 0);
sqlite3HashInit(&aNew->trigHash, SQLITE_HASH_STRING, 0);
sqlite3HashInit(&aNew->aFKey, SQLITE_HASH_STRING, 1);
aNew->zName = zName;
aNew->safety_level = 3;
rc = sqlite3BtreeFactory(db, zFile, 0, MAX_PAGES, &aNew->pBt);
if( rc ){
sqlite3ErrorMsg(pParse, "unable to open database: %s", zFile);
}
#if SQLITE_HAS_CODEC
{
extern int sqlite3CodecAttach(sqlite3*, int, void*, int);
char *zKey;
int nKey;
if( keyType==0 ){
/* No key specified. Use the key from the main database */
extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
}else if( keyType==1 ){
/* Key specified as text */
zKey = sqlite3NameFromToken(pKey);
nKey = strlen(zKey);
}else{
/* Key specified as a BLOB */
char *zTemp;
assert( keyType==2 );
pKey->z++;
pKey->n--;
zTemp = sqlite3NameFromToken(pKey);
zKey = sqlite3HexToBlob(zTemp);
sqliteFree(zTemp);
}
sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
if( keyType ){
sqliteFree(zKey);
}
}
#endif
sqliteFree(zFile);
db->flags &= ~SQLITE_Initialized;
if( pParse->nErr==0 && rc==SQLITE_OK ){
rc = sqlite3ReadSchema(pParse);
}
if( rc ){
int i = db->nDb - 1;
assert( i>=2 );
if( db->aDb[i].pBt ){
sqlite3BtreeClose(db->aDb[i].pBt);
db->aDb[i].pBt = 0;
}
sqlite3ResetInternalSchema(db, 0);
if( 0==pParse->nErr ){
pParse->nErr++;
pParse->rc = SQLITE_ERROR;
}
}
}
/*
** This routine is called by the parser to process a DETACH statement:
**
** DETACH DATABASE dbname
**
** The pDbname argument is the name of the database in the DETACH statement.
*/
void sqlite3Detach(Parse *pParse, Token *pDbname){
int i;
sqlite3 *db;
Vdbe *v;
Db *pDb = 0;
v = sqlite3GetVdbe(pParse);
if( !v ) return;
sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
if( pParse->explain ) return;
db = pParse->db;
for(i=0; i<db->nDb; i++){
pDb = &db->aDb[i];
if( pDb->pBt==0 || pDb->zName==0 ) continue;
if( strlen(pDb->zName)!=pDbname->n ) continue;
if( sqlite3StrNICmp(pDb->zName, pDbname->z, pDbname->n)==0 ) break;
}
if( i>=db->nDb ){
sqlite3ErrorMsg(pParse, "no such database: %T", pDbname);
return;
}
if( i<2 ){
sqlite3ErrorMsg(pParse, "cannot detach database %T", pDbname);
return;
}
if( !db->autoCommit ){
sqlite3ErrorMsg(pParse, "cannot DETACH database within transaction");
pParse->rc = SQLITE_ERROR;
return;
}
#ifndef SQLITE_OMIT_AUTHORIZATION
if( sqlite3AuthCheck(pParse,SQLITE_DETACH,db->aDb[i].zName,0,0)!=SQLITE_OK ){
return;
}
#endif /* SQLITE_OMIT_AUTHORIZATION */
sqlite3BtreeClose(pDb->pBt);
pDb->pBt = 0;
sqlite3ResetInternalSchema(db, 0);
}
/*
** Initialize a DbFixer structure. This routine must be called prior
** to passing the structure to one of the sqliteFixAAAA() routines below.
**
** The return value indicates whether or not fixation is required. TRUE
** means we do need to fix the database references, FALSE means we do not.
*/
int sqlite3FixInit(
DbFixer *pFix, /* The fixer to be initialized */
Parse *pParse, /* Error messages will be written here */
int iDb, /* This is the database that must be used */
const char *zType, /* "view", "trigger", or "index" */
const Token *pName /* Name of the view, trigger, or index */
){
sqlite3 *db;
if( iDb<0 || iDb==1 ) return 0;
db = pParse->db;
assert( db->nDb>iDb );
pFix->pParse = pParse;
pFix->zDb = db->aDb[iDb].zName;
pFix->zType = zType;
pFix->pName = pName;
return 1;
}
/*
** The following set of routines walk through the parse tree and assign
** a specific database to all table references where the database name
** was left unspecified in the original SQL statement. The pFix structure
** must have been initialized by a prior call to sqlite3FixInit().
**
** These routines are used to make sure that an index, trigger, or
** view in one database does not refer to objects in a different database.
** (Exception: indices, triggers, and views in the TEMP database are
** allowed to refer to anything.) If a reference is explicitly made
** to an object in a different database, an error message is added to
** pParse->zErrMsg and these routines return non-zero. If everything
** checks out, these routines return 0.
*/
int sqlite3FixSrcList(
DbFixer *pFix, /* Context of the fixation */
SrcList *pList /* The Source list to check and modify */
){
int i;
const char *zDb;
struct SrcList_item *pItem;
if( pList==0 ) return 0;
zDb = pFix->zDb;
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
if( pItem->zDatabase==0 ){
pItem->zDatabase = sqliteStrDup(zDb);
}else if( sqlite3StrICmp(pItem->zDatabase,zDb)!=0 ){
sqlite3ErrorMsg(pFix->pParse,
"%s %T cannot reference objects in database %s",
pFix->zType, pFix->pName, pItem->zDatabase);
return 1;
}
if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1;
if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1;
}
return 0;
}
int sqlite3FixSelect(
DbFixer *pFix, /* Context of the fixation */
Select *pSelect /* The SELECT statement to be fixed to one database */
){
while( pSelect ){
if( sqlite3FixExprList(pFix, pSelect->pEList) ){
return 1;
}
if( sqlite3FixSrcList(pFix, pSelect->pSrc) ){
return 1;
}
if( sqlite3FixExpr(pFix, pSelect->pWhere) ){
return 1;
}
if( sqlite3FixExpr(pFix, pSelect->pHaving) ){
return 1;
}
pSelect = pSelect->pPrior;
}
return 0;
}
int sqlite3FixExpr(
DbFixer *pFix, /* Context of the fixation */
Expr *pExpr /* The expression to be fixed to one database */
){
while( pExpr ){
if( sqlite3FixSelect(pFix, pExpr->pSelect) ){
return 1;
}
if( sqlite3FixExprList(pFix, pExpr->pList) ){
return 1;
}
if( sqlite3FixExpr(pFix, pExpr->pRight) ){
return 1;
}
pExpr = pExpr->pLeft;
}
return 0;
}
int sqlite3FixExprList(
DbFixer *pFix, /* Context of the fixation */
ExprList *pList /* The expression to be fixed to one database */
){
int i;
struct ExprList_item *pItem;
if( pList==0 ) return 0;
for(i=0, pItem=pList->a; i<pList->nExpr; i++, pItem++){
if( sqlite3FixExpr(pFix, pItem->pExpr) ){
return 1;
}
}
return 0;
}
int sqlite3FixTriggerStep(
DbFixer *pFix, /* Context of the fixation */
TriggerStep *pStep /* The trigger step be fixed to one database */
){
while( pStep ){
if( sqlite3FixSelect(pFix, pStep->pSelect) ){
return 1;
}
if( sqlite3FixExpr(pFix, pStep->pWhere) ){
return 1;
}
if( sqlite3FixExprList(pFix, pStep->pExprList) ){
return 1;
}
pStep = pStep->pNext;
}
return 0;
}
-223
View File
@@ -1,223 +0,0 @@
/*
** 2003 January 11
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains code used to implement the sqlite3_set_authorizer()
** API. This facility is an optional feature of the library. Embedded
** systems that do not need this facility may omit it by recompiling
** the library with -DSQLITE_OMIT_AUTHORIZATION=1
**
** $Id$
*/
#include "sqliteInt.h"
/*
** All of the code in this file may be omitted by defining a single
** macro.
*/
#ifndef SQLITE_OMIT_AUTHORIZATION
/*
** Set or clear the access authorization function.
**
** The access authorization function is be called during the compilation
** phase to verify that the user has read and/or write access permission on
** various fields of the database. The first argument to the auth function
** is a copy of the 3rd argument to this routine. The second argument
** to the auth function is one of these constants:
**
** SQLITE_CREATE_INDEX
** SQLITE_CREATE_TABLE
** SQLITE_CREATE_TEMP_INDEX
** SQLITE_CREATE_TEMP_TABLE
** SQLITE_CREATE_TEMP_TRIGGER
** SQLITE_CREATE_TEMP_VIEW
** SQLITE_CREATE_TRIGGER
** SQLITE_CREATE_VIEW
** SQLITE_DELETE
** SQLITE_DROP_INDEX
** SQLITE_DROP_TABLE
** SQLITE_DROP_TEMP_INDEX
** SQLITE_DROP_TEMP_TABLE
** SQLITE_DROP_TEMP_TRIGGER
** SQLITE_DROP_TEMP_VIEW
** SQLITE_DROP_TRIGGER
** SQLITE_DROP_VIEW
** SQLITE_INSERT
** SQLITE_PRAGMA
** SQLITE_READ
** SQLITE_SELECT
** SQLITE_TRANSACTION
** SQLITE_UPDATE
**
** The third and fourth arguments to the auth function are the name of
** the table and the column that are being accessed. The auth function
** should return either SQLITE_OK, SQLITE_DENY, or SQLITE_IGNORE. If
** SQLITE_OK is returned, it means that access is allowed. SQLITE_DENY
** means that the SQL statement will never-run - the sqlite3_exec() call
** will return with an error. SQLITE_IGNORE means that the SQL statement
** should run but attempts to read the specified column will return NULL
** and attempts to write the column will be ignored.
**
** Setting the auth function to NULL disables this hook. The default
** setting of the auth function is NULL.
*/
int sqlite3_set_authorizer(
sqlite3 *db,
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
void *pArg
){
db->xAuth = xAuth;
db->pAuthArg = pArg;
return SQLITE_OK;
}
/*
** Write an error message into pParse->zErrMsg that explains that the
** user-supplied authorization function returned an illegal value.
*/
static void sqliteAuthBadReturnCode(Parse *pParse, int rc){
sqlite3ErrorMsg(pParse, "illegal return value (%d) from the "
"authorization function - should be SQLITE_OK, SQLITE_IGNORE, "
"or SQLITE_DENY", rc);
pParse->rc = SQLITE_ERROR;
}
/*
** The pExpr should be a TK_COLUMN expression. The table referred to
** is in pTabList or else it is the NEW or OLD table of a trigger.
** Check to see if it is OK to read this particular column.
**
** If the auth function returns SQLITE_IGNORE, change the TK_COLUMN
** instruction into a TK_NULL. If the auth function returns SQLITE_DENY,
** then generate an error.
*/
void sqlite3AuthRead(
Parse *pParse, /* The parser context */
Expr *pExpr, /* The expression to check authorization on */
SrcList *pTabList /* All table that pExpr might refer to */
){
sqlite3 *db = pParse->db;
int rc;
Table *pTab; /* The table being read */
const char *zCol; /* Name of the column of the table */
int iSrc; /* Index in pTabList->a[] of table being read */
const char *zDBase; /* Name of database being accessed */
TriggerStack *pStack; /* The stack of current triggers */
if( db->xAuth==0 ) return;
assert( pExpr->op==TK_COLUMN );
for(iSrc=0; iSrc<pTabList->nSrc; iSrc++){
if( pExpr->iTable==pTabList->a[iSrc].iCursor ) break;
}
if( iSrc>=0 && iSrc<pTabList->nSrc ){
pTab = pTabList->a[iSrc].pTab;
}else if( (pStack = pParse->trigStack)!=0 ){
/* This must be an attempt to read the NEW or OLD pseudo-tables
** of a trigger.
*/
assert( pExpr->iTable==pStack->newIdx || pExpr->iTable==pStack->oldIdx );
pTab = pStack->pTab;
}else{
return;
}
if( pTab==0 ) return;
if( pExpr->iColumn>=0 ){
assert( pExpr->iColumn<pTab->nCol );
zCol = pTab->aCol[pExpr->iColumn].zName;
}else if( pTab->iPKey>=0 ){
assert( pTab->iPKey<pTab->nCol );
zCol = pTab->aCol[pTab->iPKey].zName;
}else{
zCol = "ROWID";
}
assert( pExpr->iDb<db->nDb );
zDBase = db->aDb[pExpr->iDb].zName;
rc = db->xAuth(db->pAuthArg, SQLITE_READ, pTab->zName, zCol, zDBase,
pParse->zAuthContext);
if( rc==SQLITE_IGNORE ){
pExpr->op = TK_NULL;
}else if( rc==SQLITE_DENY ){
if( db->nDb>2 || pExpr->iDb!=0 ){
sqlite3ErrorMsg(pParse, "access to %s.%s.%s is prohibited",
zDBase, pTab->zName, zCol);
}else{
sqlite3ErrorMsg(pParse, "access to %s.%s is prohibited",pTab->zName,zCol);
}
pParse->rc = SQLITE_AUTH;
}else if( rc!=SQLITE_OK ){
sqliteAuthBadReturnCode(pParse, rc);
}
}
/*
** Do an authorization check using the code and arguments given. Return
** either SQLITE_OK (zero) or SQLITE_IGNORE or SQLITE_DENY. If SQLITE_DENY
** is returned, then the error count and error message in pParse are
** modified appropriately.
*/
int sqlite3AuthCheck(
Parse *pParse,
int code,
const char *zArg1,
const char *zArg2,
const char *zArg3
){
sqlite3 *db = pParse->db;
int rc;
/* Don't do any authorization checks if the database is initialising. */
if( db->init.busy ){
return SQLITE_OK;
}
if( db->xAuth==0 ){
return SQLITE_OK;
}
rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext);
if( rc==SQLITE_DENY ){
sqlite3ErrorMsg(pParse, "not authorized");
pParse->rc = SQLITE_AUTH;
}else if( rc!=SQLITE_OK && rc!=SQLITE_IGNORE ){
rc = SQLITE_DENY;
sqliteAuthBadReturnCode(pParse, rc);
}
return rc;
}
/*
** Push an authorization context. After this routine is called, the
** zArg3 argument to authorization callbacks will be zContext until
** popped. Or if pParse==0, this routine is a no-op.
*/
void sqlite3AuthContextPush(
Parse *pParse,
AuthContext *pContext,
const char *zContext
){
pContext->pParse = pParse;
if( pParse ){
pContext->zAuthContext = pParse->zAuthContext;
pParse->zAuthContext = zContext;
}
}
/*
** Pop an authorization context that was previously pushed
** by sqlite3AuthContextPush
*/
void sqlite3AuthContextPop(AuthContext *pContext){
if( pContext->pParse ){
pContext->pParse->zAuthContext = pContext->zAuthContext;
pContext->pParse = 0;
}
}
#endif /* SQLITE_OMIT_AUTHORIZATION */
File diff suppressed because it is too large. Load diff
-124
View File
@@ -1,124 +0,0 @@
/*
** 2001 September 15
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This header file defines the interface that the sqlite B-Tree file
** subsystem. See comments in the source code for a detailed description
** of what each interface routine does.
**
** @(#) $Id$
*/
#ifndef _BTREE_H_
#define _BTREE_H_
/* TODO: This definition is just included so other modules compile. It
** needs to be revisited.
*/
#define SQLITE_N_BTREE_META 10
/*
** Forward declarations of structure
*/
typedef struct Btree Btree;
typedef struct BtCursor BtCursor;
int sqlite3BtreeOpen(
const char *zFilename, /* Name of database file to open */
Btree **, /* Return open Btree* here */
int flags /* Flags */
);
/* The flags parameter to sqlite3BtreeOpen can be the bitwise or of the
** following values.
*/
#define BTREE_OMIT_JOURNAL 1 /* Do not use journal. No argument */
#define BTREE_MEMORY 2 /* In-memory DB. No argument */
int sqlite3BtreeClose(Btree*);
int sqlite3BtreeSetBusyHandler(Btree*,BusyHandler*);
int sqlite3BtreeSetCacheSize(Btree*,int);
int sqlite3BtreeSetSafetyLevel(Btree*,int);
int sqlite3BtreeSetPageSize(Btree*,int,int);
int sqlite3BtreeGetPageSize(Btree*);
int sqlite3BtreeGetReserve(Btree*);
int sqlite3BtreeBeginTrans(Btree*,int);
int sqlite3BtreeCommit(Btree*);
int sqlite3BtreeRollback(Btree*);
int sqlite3BtreeBeginStmt(Btree*);
int sqlite3BtreeCommitStmt(Btree*);
int sqlite3BtreeRollbackStmt(Btree*);
int sqlite3BtreeCreateTable(Btree*, int*, int flags);
int sqlite3BtreeIsInTrans(Btree*);
int sqlite3BtreeIsInStmt(Btree*);
int sqlite3BtreeSync(Btree*, const char *zMaster);
const char *sqlite3BtreeGetFilename(Btree *);
const char *sqlite3BtreeGetDirname(Btree *);
const char *sqlite3BtreeGetJournalname(Btree *);
int sqlite3BtreeCopyFile(Btree *, Btree *);
/* The flags parameter to sqlite3BtreeCreateTable can be the bitwise OR
** of the following flags:
*/
#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 */
int sqlite3BtreeDropTable(Btree*, int);
int sqlite3BtreeClearTable(Btree*, int);
int sqlite3BtreeGetMeta(Btree*, int idx, u32 *pValue);
int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
int sqlite3BtreeCursor(
Btree*, /* BTree containing table to open */
int iTable, /* Index of root page */
int wrFlag, /* 1 for writing. 0 for read-only */
int(*)(void*,int,const void*,int,const void*), /* Key comparison function */
void*, /* First argument to compare function */
BtCursor **ppCursor /* Returned cursor */
);
void sqlite3BtreeSetCompare(
BtCursor *,
int(*)(void*,int,const void*,int,const void*),
void*
);
int sqlite3BtreeCloseCursor(BtCursor*);
int sqlite3BtreeMoveto(BtCursor*, const void *pKey, i64 nKey, int *pRes);
int sqlite3BtreeDelete(BtCursor*);
int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey,
const void *pData, int nData);
int sqlite3BtreeFirst(BtCursor*, int *pRes);
int sqlite3BtreeLast(BtCursor*, int *pRes);
int sqlite3BtreeNext(BtCursor*, int *pRes);
int sqlite3BtreeEof(BtCursor*);
int sqlite3BtreeFlags(BtCursor*);
int sqlite3BtreePrevious(BtCursor*, int *pRes);
int sqlite3BtreeKeySize(BtCursor*, i64 *pSize);
int sqlite3BtreeKey(BtCursor*, u32 offset, u32 amt, void*);
const void *sqlite3BtreeKeyFetch(BtCursor*, int *pAmt);
const void *sqlite3BtreeDataFetch(BtCursor*, int *pAmt);
int sqlite3BtreeDataSize(BtCursor*, u32 *pSize);
int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*);
char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot);
struct Pager *sqlite3BtreePager(Btree*);
#ifdef SQLITE_TEST
int sqlite3BtreeCursorInfo(BtCursor*, int*, int);
void sqlite3BtreeCursorList(Btree*);
int sqlite3BtreePageDump(Btree*, int, int recursive);
#endif
#endif /* _BTREE_H_ */
File diff suppressed because it is too large. Load diff
-893
View File
@@ -1,893 +0,0 @@
/*
** 2003 October 31
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains the C functions that implement date and time
** functions for SQLite.
**
** There is only one exported symbol in this file - the function
** sqlite3RegisterDateTimeFunctions() found at the bottom of the file.
** All other code has file scope.
**
** $Id$
**
** NOTES:
**
** SQLite processes all times and dates as Julian Day numbers. The
** dates and times are stored as the number of days since noon
** in Greenwich on November 24, 4714 B.C. according to the Gregorian
** calendar system.
**
** 1970-01-01 00:00:00 is JD 2440587.5
** 2000-01-01 00:00:00 is JD 2451544.5
**
** This implemention requires years to be expressed as a 4-digit number
** which means that only dates between 0000-01-01 and 9999-12-31 can
** be represented, even though julian day numbers allow a much wider
** range of dates.
**
** The Gregorian calendar system is used for all dates and times,
** even those that predate the Gregorian calendar. Historians usually
** use the Julian calendar for dates prior to 1582-10-15 and for some
** dates afterwards, depending on locale. Beware of this difference.
**
** The conversion algorithms are implemented based on descriptions
** in the following text:
**
** Jean Meeus
** Astronomical Algorithms, 2nd Edition, 1998
** ISBM 0-943396-61-1
** Willmann-Bell, Inc
** Richmond, Virginia (USA)
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include <stdlib.h>
#include <assert.h>
#include <time.h>
#ifndef SQLITE_OMIT_DATETIME_FUNCS
/*
** A structure for holding a single date and time.
*/
typedef struct DateTime DateTime;
struct DateTime {
double rJD; /* The julian day number */
int Y, M, D; /* Year, month, and day */
int h, m; /* Hour and minutes */
int tz; /* Timezone offset in minutes */
double s; /* Seconds */
char validYMD; /* True if Y,M,D are valid */
char validHMS; /* True if h,m,s are valid */
char validJD; /* True if rJD is valid */
char validTZ; /* True if tz is valid */
};
/*
** Convert zDate into one or more integers. Additional arguments
** come in groups of 5 as follows:
**
** N number of digits in the integer
** min minimum allowed value of the integer
** max maximum allowed value of the integer
** nextC first character after the integer
** pVal where to write the integers value.
**
** Conversions continue until one with nextC==0 is encountered.
** The function returns the number of successful conversions.
*/
static int getDigits(const char *zDate, ...){
va_list ap;
int val;
int N;
int min;
int max;
int nextC;
int *pVal;
int cnt = 0;
va_start(ap, zDate);
do{
N = va_arg(ap, int);
min = va_arg(ap, int);
max = va_arg(ap, int);
nextC = va_arg(ap, int);
pVal = va_arg(ap, int*);
val = 0;
while( N-- ){
if( !isdigit(*(u8*)zDate) ){
return cnt;
}
val = val*10 + *zDate - '0';
zDate++;
}
if( val<min || val>max || (nextC!=0 && nextC!=*zDate) ){
return cnt;
}
*pVal = val;
zDate++;
cnt++;
}while( nextC );
return cnt;
}
/*
** Read text from z[] and convert into a floating point number. Return
** the number of digits converted.
*/
static int getValue(const char *z, double *pR){
const char *zEnd;
*pR = sqlite3AtoF(z, &zEnd);
return zEnd - z;
}
/*
** Parse a timezone extension on the end of a date-time.
** The extension is of the form:
**
** (+/-)HH:MM
**
** If the parse is successful, write the number of minutes
** of change in *pnMin and return 0. If a parser error occurs,
** return 0.
**
** A missing specifier is not considered an error.
*/
static int parseTimezone(const char *zDate, DateTime *p){
int sgn = 0;
int nHr, nMn;
while( isspace(*(u8*)zDate) ){ zDate++; }
p->tz = 0;
if( *zDate=='-' ){
sgn = -1;
}else if( *zDate=='+' ){
sgn = +1;
}else{
return *zDate!=0;
}
zDate++;
if( getDigits(zDate, 2, 0, 14, ':', &nHr, 2, 0, 59, 0, &nMn)!=2 ){
return 1;
}
zDate += 5;
p->tz = sgn*(nMn + nHr*60);
while( isspace(*(u8*)zDate) ){ zDate++; }
return *zDate!=0;
}
/*
** Parse times of the form HH:MM or HH:MM:SS or HH:MM:SS.FFFF.
** The HH, MM, and SS must each be exactly 2 digits. The
** fractional seconds FFFF can be one or more digits.
**
** Return 1 if there is a parsing error and 0 on success.
*/
static int parseHhMmSs(const char *zDate, DateTime *p){
int h, m, s;
double ms = 0.0;
if( getDigits(zDate, 2, 0, 24, ':', &h, 2, 0, 59, 0, &m)!=2 ){
return 1;
}
zDate += 5;
if( *zDate==':' ){
zDate++;
if( getDigits(zDate, 2, 0, 59, 0, &s)!=1 ){
return 1;
}
zDate += 2;
if( *zDate=='.' && isdigit((u8)zDate[1]) ){
double rScale = 1.0;
zDate++;
while( isdigit(*(u8*)zDate) ){
ms = ms*10.0 + *zDate - '0';
rScale *= 10.0;
zDate++;
}
ms /= rScale;
}
}else{
s = 0;
}
p->validJD = 0;
p->validHMS = 1;
p->h = h;
p->m = m;
p->s = s + ms;
if( parseTimezone(zDate, p) ) return 1;
p->validTZ = p->tz!=0;
return 0;
}
/*
** Convert from YYYY-MM-DD HH:MM:SS to julian day. We always assume
** that the YYYY-MM-DD is according to the Gregorian calendar.
**
** Reference: Meeus page 61
*/
static void computeJD(DateTime *p){
int Y, M, D, A, B, X1, X2;
if( p->validJD ) return;
if( p->validYMD ){
Y = p->Y;
M = p->M;
D = p->D;
}else{
Y = 2000; /* If no YMD specified, assume 2000-Jan-01 */
M = 1;
D = 1;
}
if( M<=2 ){
Y--;
M += 12;
}
A = Y/100;
B = 2 - A + (A/4);
X1 = 365.25*(Y+4716);
X2 = 30.6001*(M+1);
p->rJD = X1 + X2 + D + B - 1524.5;
p->validJD = 1;
p->validYMD = 0;
if( p->validHMS ){
p->rJD += (p->h*3600.0 + p->m*60.0 + p->s)/86400.0;
if( p->validTZ ){
p->rJD += p->tz*60/86400.0;
p->validHMS = 0;
p->validTZ = 0;
}
}
}
/*
** Parse dates of the form
**
** YYYY-MM-DD HH:MM:SS.FFF
** YYYY-MM-DD HH:MM:SS
** YYYY-MM-DD HH:MM
** YYYY-MM-DD
**
** Write the result into the DateTime structure and return 0
** on success and 1 if the input string is not a well-formed
** date.
*/
static int parseYyyyMmDd(const char *zDate, DateTime *p){
int Y, M, D, neg;
if( zDate[0]=='-' ){
zDate++;
neg = 1;
}else{
neg = 0;
}
if( getDigits(zDate,4,0,9999,'-',&Y,2,1,12,'-',&M,2,1,31,0,&D)!=3 ){
return 1;
}
zDate += 10;
while( isspace(*(u8*)zDate) ){ zDate++; }
if( parseHhMmSs(zDate, p)==0 ){
/* We got the time */
}else if( *zDate==0 ){
p->validHMS = 0;
}else{
return 1;
}
p->validJD = 0;
p->validYMD = 1;
p->Y = neg ? -Y : Y;
p->M = M;
p->D = D;
if( p->validTZ ){
computeJD(p);
}
return 0;
}
/*
** Attempt to parse the given string into a Julian Day Number. Return
** the number of errors.
**
** The following are acceptable forms for the input string:
**
** YYYY-MM-DD HH:MM:SS.FFF +/-HH:MM
** DDDD.DD
** now
**
** In the first form, the +/-HH:MM is always optional. The fractional
** seconds extension (the ".FFF") is optional. The seconds portion
** (":SS.FFF") is option. The year and date can be omitted as long
** as there is a time string. The time string can be omitted as long
** as there is a year and date.
*/
static int parseDateOrTime(const char *zDate, DateTime *p){
memset(p, 0, sizeof(*p));
if( parseYyyyMmDd(zDate,p)==0 ){
return 0;
}else if( parseHhMmSs(zDate, p)==0 ){
return 0;
}else if( sqlite3StrICmp(zDate,"now")==0){
double r;
if( sqlite3OsCurrentTime(&r)==0 ){
p->rJD = r;
p->validJD = 1;
return 0;
}
return 1;
}else if( sqlite3IsNumber(zDate, 0, SQLITE_UTF8) ){
p->rJD = sqlite3AtoF(zDate, 0);
p->validJD = 1;
return 0;
}
return 1;
}
/*
** Compute the Year, Month, and Day from the julian day number.
*/
static void computeYMD(DateTime *p){
int Z, A, B, C, D, E, X1;
if( p->validYMD ) return;
if( !p->validJD ){
p->Y = 2000;
p->M = 1;
p->D = 1;
}else{
Z = p->rJD + 0.5;
A = (Z - 1867216.25)/36524.25;
A = Z + 1 + A - (A/4);
B = A + 1524;
C = (B - 122.1)/365.25;
D = 365.25*C;
E = (B-D)/30.6001;
X1 = 30.6001*E;
p->D = B - D - X1;
p->M = E<14 ? E-1 : E-13;
p->Y = p->M>2 ? C - 4716 : C - 4715;
}
p->validYMD = 1;
}
/*
** Compute the Hour, Minute, and Seconds from the julian day number.
*/
static void computeHMS(DateTime *p){
int Z, s;
if( p->validHMS ) return;
Z = p->rJD + 0.5;
s = (p->rJD + 0.5 - Z)*86400000.0 + 0.5;
p->s = 0.001*s;
s = p->s;
p->s -= s;
p->h = s/3600;
s -= p->h*3600;
p->m = s/60;
p->s += s - p->m*60;
p->validHMS = 1;
}
/*
** Compute both YMD and HMS
*/
static void computeYMD_HMS(DateTime *p){
computeYMD(p);
computeHMS(p);
}
/*
** Clear the YMD and HMS and the TZ
*/
static void clearYMD_HMS_TZ(DateTime *p){
p->validYMD = 0;
p->validHMS = 0;
p->validTZ = 0;
}
/*
** Compute the difference (in days) between localtime and UTC (a.k.a. GMT)
** for the time value p where p is in UTC.
*/
static double localtimeOffset(DateTime *p){
DateTime x, y;
time_t t;
struct tm *pTm;
x = *p;
computeYMD_HMS(&x);
if( x.Y<1971 || x.Y>=2038 ){
x.Y = 2000;
x.M = 1;
x.D = 1;
x.h = 0;
x.m = 0;
x.s = 0.0;
} else {
int s = x.s + 0.5;
x.s = s;
}
x.tz = 0;
x.validJD = 0;
computeJD(&x);
t = (x.rJD-2440587.5)*86400.0 + 0.5;
sqlite3OsEnterMutex();
pTm = localtime(&t);
y.Y = pTm->tm_year + 1900;
y.M = pTm->tm_mon + 1;
y.D = pTm->tm_mday;
y.h = pTm->tm_hour;
y.m = pTm->tm_min;
y.s = pTm->tm_sec;
sqlite3OsLeaveMutex();
y.validYMD = 1;
y.validHMS = 1;
y.validJD = 0;
y.validTZ = 0;
computeJD(&y);
return y.rJD - x.rJD;
}
/*
** Process a modifier to a date-time stamp. The modifiers are
** as follows:
**
** NNN days
** NNN hours
** NNN minutes
** NNN.NNNN seconds
** NNN months
** NNN years
** start of month
** start of year
** start of week
** start of day
** weekday N
** unixepoch
** localtime
** utc
**
** Return 0 on success and 1 if there is any kind of error.
*/
static int parseModifier(const char *zMod, DateTime *p){
int rc = 1;
int n;
double r;
char *z, zBuf[30];
z = zBuf;
for(n=0; n<sizeof(zBuf)-1 && zMod[n]; n++){
z[n] = tolower(zMod[n]);
}
z[n] = 0;
switch( z[0] ){
case 'l': {
/* localtime
**
** Assuming the current time value is UTC (a.k.a. GMT), shift it to
** show local time.
*/
if( strcmp(z, "localtime")==0 ){
computeJD(p);
p->rJD += localtimeOffset(p);
clearYMD_HMS_TZ(p);
rc = 0;
}
break;
}
case 'u': {
/*
** unixepoch
**
** Treat the current value of p->rJD as the number of
** seconds since 1970. Convert to a real julian day number.
*/
if( strcmp(z, "unixepoch")==0 && p->validJD ){
p->rJD = p->rJD/86400.0 + 2440587.5;
clearYMD_HMS_TZ(p);
rc = 0;
}else if( strcmp(z, "utc")==0 ){
double c1;
computeJD(p);
c1 = localtimeOffset(p);
p->rJD -= c1;
clearYMD_HMS_TZ(p);
p->rJD += c1 - localtimeOffset(p);
rc = 0;
}
break;
}
case 'w': {
/*
** weekday N
**
** Move the date to the same time on the next occurrence of
** 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=r)==r && n>=0 && r<7 ){
int Z;
computeYMD_HMS(p);
p->validTZ = 0;
p->validJD = 0;
computeJD(p);
Z = p->rJD + 1.5;
Z %= 7;
if( Z>n ) Z -= 7;
p->rJD += n - Z;
clearYMD_HMS_TZ(p);
rc = 0;
}
break;
}
case 's': {
/*
** start of TTTTT
**
** Move the date backwards to the beginning of the current day,
** or month or year.
*/
if( strncmp(z, "start of ", 9)!=0 ) break;
z += 9;
computeYMD(p);
p->validHMS = 1;
p->h = p->m = 0;
p->s = 0.0;
p->validTZ = 0;
p->validJD = 0;
if( strcmp(z,"month")==0 ){
p->D = 1;
rc = 0;
}else if( strcmp(z,"year")==0 ){
computeYMD(p);
p->M = 1;
p->D = 1;
rc = 0;
}else if( strcmp(z,"day")==0 ){
rc = 0;
}
break;
}
case '+':
case '-':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9': {
n = getValue(z, &r);
if( n<=0 ) 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
** to the time. The ".FFF" may be omitted. The ":SS.FFF" may be
** omitted.
*/
const char *z2 = z;
DateTime tx;
int day;
if( !isdigit(*(u8*)z2) ) z2++;
memset(&tx, 0, sizeof(tx));
if( parseHhMmSs(z2, &tx) ) break;
computeJD(&tx);
tx.rJD -= 0.5;
day = (int)tx.rJD;
tx.rJD -= day;
if( z[0]=='-' ) tx.rJD = -tx.rJD;
computeJD(p);
clearYMD_HMS_TZ(p);
p->rJD += tx.rJD;
rc = 0;
break;
}
z += n;
while( isspace(*(u8*)z) ) z++;
n = strlen(z);
if( n>10 || n<3 ) break;
if( z[n-1]=='s' ){ z[n-1] = 0; n--; }
computeJD(p);
rc = 0;
if( n==3 && strcmp(z,"day")==0 ){
p->rJD += r;
}else if( n==4 && strcmp(z,"hour")==0 ){
p->rJD += r/24.0;
}else if( n==6 && strcmp(z,"minute")==0 ){
p->rJD += r/(24.0*60.0);
}else if( n==6 && strcmp(z,"second")==0 ){
p->rJD += r/(24.0*60.0*60.0);
}else if( n==5 && strcmp(z,"month")==0 ){
int x, y;
computeYMD_HMS(p);
p->M += r;
x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
p->Y += x;
p->M -= x*12;
p->validJD = 0;
computeJD(p);
y = r;
if( y!=r ){
p->rJD += (r - y)*30.0;
}
}else if( n==4 && strcmp(z,"year")==0 ){
computeYMD_HMS(p);
p->Y += r;
p->validJD = 0;
computeJD(p);
}else{
rc = 1;
}
clearYMD_HMS_TZ(p);
break;
}
default: {
break;
}
}
return rc;
}
/*
** Process time function arguments. argv[0] is a date-time stamp.
** argv[1] and following are modifiers. Parse them all and write
** the resulting time into the DateTime structure p. Return 0
** on success and 1 if there are any errors.
*/
static int isDate(int argc, sqlite3_value **argv, DateTime *p){
int i;
if( argc==0 ) return 1;
if( SQLITE_NULL==sqlite3_value_type(argv[0]) ||
parseDateOrTime(sqlite3_value_text(argv[0]), p) ) return 1;
for(i=1; i<argc; i++){
if( SQLITE_NULL==sqlite3_value_type(argv[i]) ||
parseModifier(sqlite3_value_text(argv[i]), p) ) return 1;
}
return 0;
}
/*
** The following routines implement the various date and time functions
** of SQLite.
*/
/*
** julianday( TIMESTRING, MOD, MOD, ...)
**
** Return the julian day number of the date specified in the arguments
*/
static void juliandayFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
DateTime x;
if( isDate(argc, argv, &x)==0 ){
computeJD(&x);
sqlite3_result_double(context, x.rJD);
}
}
/*
** datetime( TIMESTRING, MOD, MOD, ...)
**
** Return YYYY-MM-DD HH:MM:SS
*/
static void datetimeFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
DateTime x;
if( isDate(argc, argv, &x)==0 ){
char zBuf[100];
computeYMD_HMS(&x);
sprintf(zBuf, "%04d-%02d-%02d %02d:%02d:%02d",x.Y, x.M, x.D, x.h, x.m,
(int)(x.s));
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
}
}
/*
** time( TIMESTRING, MOD, MOD, ...)
**
** Return HH:MM:SS
*/
static void timeFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
DateTime x;
if( isDate(argc, argv, &x)==0 ){
char zBuf[100];
computeHMS(&x);
sprintf(zBuf, "%02d:%02d:%02d", x.h, x.m, (int)x.s);
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
}
}
/*
** date( TIMESTRING, MOD, MOD, ...)
**
** Return YYYY-MM-DD
*/
static void dateFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
DateTime x;
if( isDate(argc, argv, &x)==0 ){
char zBuf[100];
computeYMD(&x);
sprintf(zBuf, "%04d-%02d-%02d", x.Y, x.M, x.D);
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
}
}
/*
** strftime( FORMAT, TIMESTRING, MOD, MOD, ...)
**
** Return a string described by FORMAT. Conversions as follows:
**
** %d day of month
** %f ** fractional seconds SS.SSS
** %H hour 00-24
** %j day of year 000-366
** %J ** Julian day number
** %m month 01-12
** %M minute 00-59
** %s seconds since 1970-01-01
** %S seconds 00-59
** %w day of week 0-6 sunday==0
** %W week of year 00-53
** %Y year 0000-9999
** %% %
*/
static void strftimeFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
DateTime x;
int n, i, j;
char *z;
const char *zFmt = sqlite3_value_text(argv[0]);
char zBuf[100];
if( zFmt==0 || isDate(argc-1, argv+1, &x) ) return;
for(i=0, n=1; zFmt[i]; i++, n++){
if( zFmt[i]=='%' ){
switch( zFmt[i+1] ){
case 'd':
case 'H':
case 'm':
case 'M':
case 'S':
case 'W':
n++;
/* fall thru */
case 'w':
case '%':
break;
case 'f':
n += 8;
break;
case 'j':
n += 3;
break;
case 'Y':
n += 8;
break;
case 's':
case 'J':
n += 50;
break;
default:
return; /* ERROR. return a NULL */
}
i++;
}
}
if( n<sizeof(zBuf) ){
z = zBuf;
}else{
z = sqliteMalloc( n );
if( z==0 ) return;
}
computeJD(&x);
computeYMD_HMS(&x);
for(i=j=0; zFmt[i]; i++){
if( zFmt[i]!='%' ){
z[j++] = zFmt[i];
}else{
i++;
switch( zFmt[i] ){
case 'd': sprintf(&z[j],"%02d",x.D); j+=2; break;
case 'f': {
int s = x.s;
int ms = (x.s - s)*1000.0;
sprintf(&z[j],"%02d.%03d",s,ms);
j += strlen(&z[j]);
break;
}
case 'H': sprintf(&z[j],"%02d",x.h); j+=2; break;
case 'W': /* Fall thru */
case 'j': {
int n; /* Number of days since 1st day of year */
DateTime y = x;
y.validJD = 0;
y.M = 1;
y.D = 1;
computeJD(&y);
n = x.rJD - y.rJD;
if( zFmt[i]=='W' ){
int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */
wd = ((int)(x.rJD+0.5)) % 7;
sprintf(&z[j],"%02d",(n+7-wd)/7);
j += 2;
}else{
sprintf(&z[j],"%03d",n+1);
j += 3;
}
break;
}
case 'J': sprintf(&z[j],"%.16g",x.rJD); j+=strlen(&z[j]); break;
case 'm': sprintf(&z[j],"%02d",x.M); j+=2; break;
case 'M': sprintf(&z[j],"%02d",x.m); j+=2; break;
case 's': {
sprintf(&z[j],"%d",(int)((x.rJD-2440587.5)*86400.0 + 0.5));
j += strlen(&z[j]);
break;
}
case 'S': sprintf(&z[j],"%02d",(int)(x.s+0.5)); j+=2; break;
case 'w': z[j++] = (((int)(x.rJD+1.5)) % 7) + '0'; break;
case 'Y': sprintf(&z[j],"%04d",x.Y); j+=strlen(&z[j]); break;
case '%': z[j++] = '%'; break;
}
}
}
z[j] = 0;
sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT);
if( z!=zBuf ){
sqliteFree(z);
}
}
#endif /* !defined(SQLITE_OMIT_DATETIME_FUNCS) */
/*
** This function registered all of the above C functions as SQL
** functions. This should be the only routine in this file with
** external linkage.
*/
void sqlite3RegisterDateTimeFunctions(sqlite3 *db){
#ifndef SQLITE_OMIT_DATETIME_FUNCS
static const struct {
char *zName;
int nArg;
void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
} aFuncs[] = {
{ "julianday", -1, juliandayFunc },
{ "date", -1, dateFunc },
{ "time", -1, timeFunc },
{ "datetime", -1, datetimeFunc },
{ "strftime", -1, strftimeFunc },
};
int i;
for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg,
SQLITE_UTF8, 0, aFuncs[i].xFunc, 0, 0);
}
#endif
}
-419
View File
@@ -1,419 +0,0 @@
/*
** 2001 September 15
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle DELETE FROM statements.
**
** $Id$
*/
#include "sqliteInt.h"
/*
** Look up every table that is named in pSrc. If any table is not found,
** add an error message to pParse->zErrMsg and return NULL. If all tables
** are found, return a pointer to the last table.
*/
Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
Table *pTab = 0;
int i;
struct SrcList_item *pItem;
for(i=0, pItem=pSrc->a; i<pSrc->nSrc; i++, pItem++){
pTab = sqlite3LocateTable(pParse, pItem->zName, pItem->zDatabase);
pItem->pTab = pTab;
}
return pTab;
}
/*
** Check to make sure the given table is writable. If it is not
** writable, generate an error message and return 1. If it is
** writable return 0;
*/
int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
if( pTab->readOnly ){
sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName);
return 1;
}
if( !viewOk && pTab->pSelect ){
sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName);
return 1;
}
return 0;
}
/*
** Generate code that will open a table for reading.
*/
void sqlite3OpenTableForReading(
Vdbe *v, /* Generate code into this VDBE */
int iCur, /* The cursor number of the table */
Table *pTab /* The table to be opened */
){
sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum);
VdbeComment((v, "# %s", pTab->zName));
sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol);
}
/*
** Process a DELETE FROM statement.
*/
void sqlite3DeleteFrom(
Parse *pParse, /* The parser context */
SrcList *pTabList, /* The table from which we should delete things */
Expr *pWhere /* The WHERE clause. May be null */
){
Vdbe *v; /* The virtual database engine */
Table *pTab; /* The table from which records will be deleted */
const char *zDb; /* Name of database holding pTab */
int end, addr = 0; /* A couple addresses of generated code */
int i; /* Loop counter */
WhereInfo *pWInfo; /* Information about the WHERE clause */
Index *pIdx; /* For looping over indices of the table */
int iCur; /* VDBE Cursor number for pTab */
sqlite3 *db; /* Main database structure */
int isView; /* True if attempting to delete from a view */
AuthContext sContext; /* Authorization context */
int row_triggers_exist = 0; /* True if any triggers exist */
int before_triggers; /* True if there are BEFORE triggers */
int after_triggers; /* True if there are AFTER triggers */
int oldIdx = -1; /* Cursor for the OLD table of AFTER triggers */
sContext.pParse = 0;
if( pParse->nErr || sqlite3_malloc_failed ){
pTabList = 0;
goto delete_from_cleanup;
}
db = pParse->db;
assert( pTabList->nSrc==1 );
/* Locate the table which we want to delete. This table has to be
** put in an SrcList structure because some of the subroutines we
** will be calling are designed to work with multiple tables and expect
** an SrcList* parameter instead of just a Table* parameter.
*/
pTab = sqlite3SrcListLookup(pParse, pTabList);
if( pTab==0 ) goto delete_from_cleanup;
before_triggers = sqlite3TriggersExist(pParse, pTab->pTrigger,
TK_DELETE, TK_BEFORE, TK_ROW, 0);
after_triggers = sqlite3TriggersExist(pParse, pTab->pTrigger,
TK_DELETE, TK_AFTER, TK_ROW, 0);
row_triggers_exist = before_triggers || after_triggers;
isView = pTab->pSelect!=0;
if( sqlite3IsReadOnly(pParse, pTab, before_triggers) ){
goto delete_from_cleanup;
}
assert( pTab->iDb<db->nDb );
zDb = db->aDb[pTab->iDb].zName;
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){
goto delete_from_cleanup;
}
/* If pTab is really a view, make sure it has been initialized.
*/
if( isView && sqlite3ViewGetColumnNames(pParse, pTab) ){
goto delete_from_cleanup;
}
/* Allocate a cursor used to store the old.* data for a trigger.
*/
if( row_triggers_exist ){
oldIdx = pParse->nTab++;
}
/* Resolve the column names in all the expressions.
*/
assert( pTabList->nSrc==1 );
iCur = pTabList->a[0].iCursor = pParse->nTab++;
if( sqlite3ExprResolveAndCheck(pParse, pTabList, 0, pWhere, 0, 0) ){
goto delete_from_cleanup;
}
/* Start the view context
*/
if( isView ){
sqlite3AuthContextPush(pParse, &sContext, pTab->zName);
}
/* Begin generating code.
*/
v = sqlite3GetVdbe(pParse);
if( v==0 ){
goto delete_from_cleanup;
}
sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, row_triggers_exist, pTab->iDb);
/* If we are trying to delete from a view, construct that view into
** a temporary table.
*/
if( isView ){
Select *pView = sqlite3SelectDup(pTab->pSelect);
sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0);
sqlite3SelectDelete(pView);
}
/* Initialize the counter of the number of rows deleted, if
** we are counting rows.
*/
if( db->flags & SQLITE_CountRows ){
sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
}
/* Special case: A DELETE without a WHERE clause deletes everything.
** It is easier just to erase the whole table. Note, however, that
** this means that the row change count will be incorrect.
*/
if( pWhere==0 && !row_triggers_exist ){
if( db->flags & SQLITE_CountRows ){
/* If counting rows deleted, just count the total number of
** entries in the table. */
int endOfLoop = sqlite3VdbeMakeLabel(v);
int addr;
if( !isView ){
sqlite3OpenTableForReading(v, iCur, pTab);
}
sqlite3VdbeAddOp(v, OP_Rewind, iCur, sqlite3VdbeCurrentAddr(v)+2);
addr = sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
sqlite3VdbeAddOp(v, OP_Next, iCur, addr);
sqlite3VdbeResolveLabel(v, endOfLoop);
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
}
if( !isView ){
sqlite3VdbeAddOp(v, OP_Clear, pTab->tnum, pTab->iDb);
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
sqlite3VdbeAddOp(v, OP_Clear, pIdx->tnum, pIdx->iDb);
}
}
}
/* The usual case: There is a WHERE clause so we have to scan through
** the table and pick which records to delete.
*/
else{
/* Ensure all required collation sequences are available. */
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
if( sqlite3CheckIndexCollSeq(pParse, pIdx) ){
goto delete_from_cleanup;
}
}
/* Begin the database scan
*/
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0);
if( pWInfo==0 ) goto delete_from_cleanup;
/* Remember the key of every item to be deleted.
*/
sqlite3VdbeAddOp(v, OP_ListWrite, 0, 0);
if( db->flags & SQLITE_CountRows ){
sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
}
/* End the database scan loop.
*/
sqlite3WhereEnd(pWInfo);
/* Open the pseudo-table used to store OLD if there are triggers.
*/
if( row_triggers_exist ){
sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol);
}
/* Delete every item whose key was written to the list during the
** database scan. We have to delete items after the scan is complete
** because deleting an item can change the scan order.
*/
sqlite3VdbeAddOp(v, OP_ListRewind, 0, 0);
end = sqlite3VdbeMakeLabel(v);
/* This is the beginning of the delete loop when there are
** row triggers.
*/
if( row_triggers_exist ){
addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, end);
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
if( !isView ){
sqlite3OpenTableForReading(v, iCur, pTab);
}
sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
sqlite3VdbeAddOp(v, OP_Recno, iCur, 0);
sqlite3VdbeAddOp(v, OP_RowData, iCur, 0);
sqlite3VdbeAddOp(v, OP_PutIntKey, oldIdx, 0);
if( !isView ){
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
}
sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1,
oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
addr);
}
if( !isView ){
/* Open cursors for the table we are deleting from and all its
** indices. If there are row triggers, this happens inside the
** OP_ListRead loop because the cursor have to all be closed
** before the trigger fires. If there are no row triggers, the
** cursors are opened only once on the outside the loop.
*/
sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite);
/* This is the beginning of the delete loop when there are no
** row triggers */
if( !row_triggers_exist ){
addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, end);
}
/* Delete the row */
sqlite3GenerateRowDelete(db, v, pTab, iCur, 1);
}
/* If there are row triggers, close all cursors then invoke
** the AFTER triggers
*/
if( row_triggers_exist ){
if( !isView ){
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
}
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
}
sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1,
oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
addr);
}
/* End of the delete loop */
sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
sqlite3VdbeResolveLabel(v, end);
sqlite3VdbeAddOp(v, OP_ListReset, 0, 0);
/* Close the cursors after the loop if there are no row triggers */
if( !row_triggers_exist ){
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
}
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
}
}
/*
** Return the number of rows that were deleted.
*/
if( db->flags & SQLITE_CountRows ){
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, "rows deleted", P3_STATIC);
}
delete_from_cleanup:
sqlite3AuthContextPop(&sContext);
sqlite3SrcListDelete(pTabList);
sqlite3ExprDelete(pWhere);
return;
}
/*
** This routine generates VDBE code that causes a single row of a
** single table to be deleted.
**
** The VDBE must be in a particular state when this routine is called.
** These are the requirements:
**
** 1. A read/write cursor pointing to pTab, the table containing the row
** to be deleted, must be opened as cursor number "base".
**
** 2. Read/write cursors for all indices of pTab must be open as
** cursor number base+i for the i-th index.
**
** 3. The record number of the row to be deleted must be on the top
** of the stack.
**
** This routine pops the top of the stack to remove the record number
** and then generates code to remove both the table record and all index
** entries that point to that record.
*/
void sqlite3GenerateRowDelete(
sqlite3 *db, /* The database containing the index */
Vdbe *v, /* Generate code into this VDBE */
Table *pTab, /* Table containing the row to be deleted */
int iCur, /* Cursor number for the table */
int count /* Increment the row change counter */
){
int addr;
addr = sqlite3VdbeAddOp(v, OP_NotExists, iCur, 0);
sqlite3GenerateRowIndexDelete(db, v, pTab, iCur, 0);
sqlite3VdbeAddOp(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0));
sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
}
/*
** This routine generates VDBE code that causes the deletion of all
** index entries associated with a single row of a single table.
**
** The VDBE must be in a particular state when this routine is called.
** These are the requirements:
**
** 1. A read/write cursor pointing to pTab, the table containing the row
** to be deleted, must be opened as cursor number "iCur".
**
** 2. Read/write cursors for all indices of pTab must be open as
** cursor number iCur+i for the i-th index.
**
** 3. The "iCur" cursor must be pointing to the row that is to be
** deleted.
*/
void sqlite3GenerateRowIndexDelete(
sqlite3 *db, /* The database containing the index */
Vdbe *v, /* Generate code into this VDBE */
Table *pTab, /* Table containing the row to be deleted */
int iCur, /* Cursor number for the table */
char *aIdxUsed /* Only delete if aIdxUsed!=0 && aIdxUsed[i]!=0 */
){
int i;
Index *pIdx;
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
if( aIdxUsed!=0 && aIdxUsed[i-1]==0 ) continue;
sqlite3GenerateIndexKey(v, pIdx, iCur);
sqlite3VdbeAddOp(v, OP_IdxDelete, iCur+i, 0);
}
}
/*
** Generate code that will assemble an index key and put it on the top
** of the tack. The key with be for index pIdx which is an index on pTab.
** iCur is the index of a cursor open on the pTab table and pointing to
** the entry that needs indexing.
*/
void sqlite3GenerateIndexKey(
Vdbe *v, /* Generate code into this VDBE */
Index *pIdx, /* The index for which to generate a key */
int iCur /* Cursor number for the pIdx->pTable table */
){
int j;
Table *pTab = pIdx->pTable;
sqlite3VdbeAddOp(v, OP_Recno, iCur, 0);
for(j=0; j<pIdx->nColumn; j++){
int idx = pIdx->aiColumn[j];
if( idx==pTab->iPKey ){
sqlite3VdbeAddOp(v, OP_Dup, j, 0);
}else{
sqlite3VdbeAddOp(v, OP_Column, iCur, idx);
}
}
sqlite3VdbeAddOp(v, OP_MakeRecord, pIdx->nColumn, (1<<24));
sqlite3IndexAffinityStr(v, pIdx);
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
-380
View File
@@ -1,380 +0,0 @@
/*
** 2001 September 22
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This is the implementation of generic hash-tables
** used in SQLite.
**
** $Id$
*/
#include "sqliteInt.h"
#include <assert.h>
/* Turn bulk memory into a hash table object by initializing the
** fields of the Hash structure.
**
** "pNew" is a pointer to the hash table that is to be initialized.
** keyClass is one of the constants SQLITE_HASH_INT, SQLITE_HASH_POINTER,
** SQLITE_HASH_BINARY, or SQLITE_HASH_STRING. The value of keyClass
** determines what kind of key the hash table will use. "copyKey" is
** true if the hash table should make its own private copy of keys and
** false if it should just use the supplied pointer. CopyKey only makes
** sense for SQLITE_HASH_STRING and SQLITE_HASH_BINARY and is ignored
** for other key classes.
*/
void sqlite3HashInit(Hash *pNew, int keyClass, int copyKey){
assert( pNew!=0 );
assert( keyClass>=SQLITE_HASH_STRING && keyClass<=SQLITE_HASH_BINARY );
pNew->keyClass = keyClass;
#if 0
if( keyClass==SQLITE_HASH_POINTER || keyClass==SQLITE_HASH_INT ) copyKey = 0;
#endif
pNew->copyKey = copyKey;
pNew->first = 0;
pNew->count = 0;
pNew->htsize = 0;
pNew->ht = 0;
}
/* Remove all entries from a hash table. Reclaim all memory.
** Call this routine to delete a hash table or to reset a hash table
** to the empty state.
*/
void sqlite3HashClear(Hash *pH){
HashElem *elem; /* For looping over all elements of the table */
assert( pH!=0 );
elem = pH->first;
pH->first = 0;
if( pH->ht ) sqliteFree(pH->ht);
pH->ht = 0;
pH->htsize = 0;
while( elem ){
HashElem *next_elem = elem->next;
if( pH->copyKey && elem->pKey ){
sqliteFree(elem->pKey);
}
sqliteFree(elem);
elem = next_elem;
}
pH->count = 0;
}
#if 0 /* NOT USED */
/*
** Hash and comparison functions when the mode is SQLITE_HASH_INT
*/
static int intHash(const void *pKey, int nKey){
return nKey ^ (nKey<<8) ^ (nKey>>8);
}
static int intCompare(const void *pKey1, int n1, const void *pKey2, int n2){
return n2 - n1;
}
#endif
#if 0 /* NOT USED */
/*
** Hash and comparison functions when the mode is SQLITE_HASH_POINTER
*/
static int ptrHash(const void *pKey, int nKey){
uptr x = Addr(pKey);
return x ^ (x<<8) ^ (x>>8);
}
static int ptrCompare(const void *pKey1, int n1, const void *pKey2, int n2){
if( pKey1==pKey2 ) return 0;
if( pKey1<pKey2 ) return -1;
return 1;
}
#endif
/*
** Hash and comparison functions when the mode is SQLITE_HASH_STRING
*/
static int strHash(const void *pKey, int nKey){
return sqlite3HashNoCase((const char*)pKey, nKey);
}
static int strCompare(const void *pKey1, int n1, const void *pKey2, int n2){
if( n1!=n2 ) return 1;
return sqlite3StrNICmp((const char*)pKey1,(const char*)pKey2,n1);
}
/*
** Hash and comparison functions when the mode is SQLITE_HASH_BINARY
*/
static int binHash(const void *pKey, int nKey){
int h = 0;
const char *z = (const char *)pKey;
while( nKey-- > 0 ){
h = (h<<3) ^ h ^ *(z++);
}
return h & 0x7fffffff;
}
static int binCompare(const void *pKey1, int n1, const void *pKey2, int n2){
if( n1!=n2 ) return 1;
return memcmp(pKey1,pKey2,n1);
}
/*
** Return a pointer to the appropriate hash function given the key class.
**
** The C syntax in this function definition may be unfamilar to some
** programmers, so we provide the following additional explanation:
**
** The name of the function is "hashFunction". The function takes a
** single parameter "keyClass". The return value of hashFunction()
** is a pointer to another function. Specifically, the return value
** of hashFunction() is a pointer to a function that takes two parameters
** with types "const void*" and "int" and returns an "int".
*/
static int (*hashFunction(int keyClass))(const void*,int){
#if 0 /* HASH_INT and HASH_POINTER are never used */
switch( keyClass ){
case SQLITE_HASH_INT: return &intHash;
case SQLITE_HASH_POINTER: return &ptrHash;
case SQLITE_HASH_STRING: return &strHash;
case SQLITE_HASH_BINARY: return &binHash;;
default: break;
}
return 0;
#else
if( keyClass==SQLITE_HASH_STRING ){
return &strHash;
}else{
assert( keyClass==SQLITE_HASH_BINARY );
return &binHash;
}
#endif
}
/*
** Return a pointer to the appropriate hash function given the key class.
**
** For help in interpreted the obscure C code in the function definition,
** see the header comment on the previous function.
*/
static int (*compareFunction(int keyClass))(const void*,int,const void*,int){
#if 0 /* HASH_INT and HASH_POINTER are never used */
switch( keyClass ){
case SQLITE_HASH_INT: return &intCompare;
case SQLITE_HASH_POINTER: return &ptrCompare;
case SQLITE_HASH_STRING: return &strCompare;
case SQLITE_HASH_BINARY: return &binCompare;
default: break;
}
return 0;
#else
if( keyClass==SQLITE_HASH_STRING ){
return &strCompare;
}else{
assert( keyClass==SQLITE_HASH_BINARY );
return &binCompare;
}
#endif
}
/* Link an element into the hash table
*/
static void insertElement(
Hash *pH, /* The complete hash table */
struct _ht *pEntry, /* The entry into which pNew is inserted */
HashElem *pNew /* The element to be inserted */
){
HashElem *pHead; /* First element already in pEntry */
pHead = pEntry->chain;
if( pHead ){
pNew->next = pHead;
pNew->prev = pHead->prev;
if( pHead->prev ){ pHead->prev->next = pNew; }
else { pH->first = pNew; }
pHead->prev = pNew;
}else{
pNew->next = pH->first;
if( pH->first ){ pH->first->prev = pNew; }
pNew->prev = 0;
pH->first = pNew;
}
pEntry->count++;
pEntry->chain = pNew;
}
/* Resize the hash table so that it cantains "new_size" buckets.
** "new_size" must be a power of 2. The hash table might fail
** to resize if sqliteMalloc() fails.
*/
static void rehash(Hash *pH, int new_size){
struct _ht *new_ht; /* The new hash table */
HashElem *elem, *next_elem; /* For looping over existing elements */
int (*xHash)(const void*,int); /* The hash function */
assert( (new_size & (new_size-1))==0 );
new_ht = (struct _ht *)sqliteMalloc( new_size*sizeof(struct _ht) );
if( new_ht==0 ) return;
if( pH->ht ) sqliteFree(pH->ht);
pH->ht = new_ht;
pH->htsize = new_size;
xHash = hashFunction(pH->keyClass);
for(elem=pH->first, pH->first=0; elem; elem = next_elem){
int h = (*xHash)(elem->pKey, elem->nKey) & (new_size-1);
next_elem = elem->next;
insertElement(pH, &new_ht[h], elem);
}
}
/* This function (for internal use only) locates an element in an
** hash table that matches the given key. The hash for this key has
** already been computed and is passed as the 4th parameter.
*/
static HashElem *findElementGivenHash(
const Hash *pH, /* The pH to be searched */
const void *pKey, /* The key we are searching for */
int nKey,
int h /* The hash for this key. */
){
HashElem *elem; /* Used to loop thru the element list */
int count; /* Number of elements left to test */
int (*xCompare)(const void*,int,const void*,int); /* comparison function */
if( pH->ht ){
struct _ht *pEntry = &pH->ht[h];
elem = pEntry->chain;
count = pEntry->count;
xCompare = compareFunction(pH->keyClass);
while( count-- && elem ){
if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){
return elem;
}
elem = elem->next;
}
}
return 0;
}
/* Remove a single entry from the hash table given a pointer to that
** element and a hash on the element's key.
*/
static void removeElementGivenHash(
Hash *pH, /* The pH containing "elem" */
HashElem* elem, /* The element to be removed from the pH */
int h /* Hash value for the element */
){
struct _ht *pEntry;
if( elem->prev ){
elem->prev->next = elem->next;
}else{
pH->first = elem->next;
}
if( elem->next ){
elem->next->prev = elem->prev;
}
pEntry = &pH->ht[h];
if( pEntry->chain==elem ){
pEntry->chain = elem->next;
}
pEntry->count--;
if( pEntry->count<=0 ){
pEntry->chain = 0;
}
if( pH->copyKey && elem->pKey ){
sqliteFree(elem->pKey);
}
sqliteFree( elem );
pH->count--;
}
/* Attempt to locate an element of the hash table pH with a key
** that matches pKey,nKey. Return the data for this element if it is
** found, or NULL if there is no match.
*/
void *sqlite3HashFind(const Hash *pH, const void *pKey, int nKey){
int h; /* A hash on key */
HashElem *elem; /* The element that matches key */
int (*xHash)(const void*,int); /* The hash function */
if( pH==0 || pH->ht==0 ) return 0;
xHash = hashFunction(pH->keyClass);
assert( xHash!=0 );
h = (*xHash)(pKey,nKey);
assert( (pH->htsize & (pH->htsize-1))==0 );
elem = findElementGivenHash(pH,pKey,nKey, h & (pH->htsize-1));
return elem ? elem->data : 0;
}
/* Insert an element into the hash table pH. The key is pKey,nKey
** and the data is "data".
**
** If no element exists with a matching key, then a new
** element is created. A copy of the key is made if the copyKey
** flag is set. NULL is returned.
**
** If another element already exists with the same key, then the
** new data replaces the old data and the old data is returned.
** The key is not copied in this instance. If a malloc fails, then
** the new data is returned and the hash table is unchanged.
**
** If the "data" parameter to this function is NULL, then the
** element corresponding to "key" is removed from the hash table.
*/
void *sqlite3HashInsert(Hash *pH, const void *pKey, int nKey, void *data){
int hraw; /* Raw hash value of the key */
int h; /* the hash of the key modulo hash table size */
HashElem *elem; /* Used to loop thru the element list */
HashElem *new_elem; /* New element added to the pH */
int (*xHash)(const void*,int); /* The hash function */
assert( pH!=0 );
xHash = hashFunction(pH->keyClass);
assert( xHash!=0 );
hraw = (*xHash)(pKey, nKey);
assert( (pH->htsize & (pH->htsize-1))==0 );
h = hraw & (pH->htsize-1);
elem = findElementGivenHash(pH,pKey,nKey,h);
if( elem ){
void *old_data = elem->data;
if( data==0 ){
removeElementGivenHash(pH,elem,h);
}else{
elem->data = data;
}
return old_data;
}
if( data==0 ) return 0;
new_elem = (HashElem*)sqliteMalloc( sizeof(HashElem) );
if( new_elem==0 ) return data;
if( pH->copyKey && pKey!=0 ){
new_elem->pKey = sqliteMallocRaw( nKey );
if( new_elem->pKey==0 ){
sqliteFree(new_elem);
return data;
}
memcpy((void*)new_elem->pKey, pKey, nKey);
}else{
new_elem->pKey = (void*)pKey;
}
new_elem->nKey = nKey;
pH->count++;
if( pH->htsize==0 ){
rehash(pH,8);
if( pH->htsize==0 ){
pH->count = 0;
sqliteFree(new_elem);
return data;
}
}
if( pH->count > pH->htsize ){
rehash(pH,pH->htsize*2);
}
assert( pH->htsize>0 );
assert( (pH->htsize & (pH->htsize-1))==0 );
h = hraw & (pH->htsize-1);
insertElement(pH, &pH->ht[h], new_elem);
new_elem->data = data;
return 0;
}
-109
View File
@@ -1,109 +0,0 @@
/*
** 2001 September 22
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This is the header file for the generic hash-table implemenation
** used in SQLite.
**
** $Id$
*/
#ifndef _SQLITE_HASH_H_
#define _SQLITE_HASH_H_
/* Forward declarations of structures. */
typedef struct Hash Hash;
typedef struct HashElem HashElem;
/* A complete hash table is an instance of the following structure.
** The internals of this structure are intended to be opaque -- client
** code should not attempt to access or modify the fields of this structure
** directly. Change this structure only by using the routines below.
** However, many of the "procedures" and "functions" for modifying and
** accessing this structure are really macros, so we can't really make
** this structure opaque.
*/
struct Hash {
char keyClass; /* SQLITE_HASH_INT, _POINTER, _STRING, _BINARY */
char copyKey; /* True if copy of key made on insert */
int count; /* Number of entries in this table */
HashElem *first; /* The first element of the array */
int htsize; /* Number of buckets in the hash table */
struct _ht { /* the hash table */
int count; /* Number of entries with this hash */
HashElem *chain; /* Pointer to first entry with this hash */
} *ht;
};
/* Each element in the hash table is an instance of the following
** structure. All elements are stored on a single doubly-linked list.
**
** Again, this structure is intended to be opaque, but it can't really
** be opaque because it is used by macros.
*/
struct HashElem {
HashElem *next, *prev; /* Next and previous elements in the table */
void *data; /* Data associated with this element */
void *pKey; int nKey; /* Key associated with this element */
};
/*
** There are 4 different modes of operation for a hash table:
**
** SQLITE_HASH_INT nKey is used as the key and pKey is ignored.
**
** SQLITE_HASH_POINTER pKey is used as the key and nKey is ignored.
**
** SQLITE_HASH_STRING pKey points to a string that is nKey bytes long
** (including the null-terminator, if any). Case
** is ignored in comparisons.
**
** SQLITE_HASH_BINARY pKey points to binary data nKey bytes long.
** memcmp() is used to compare keys.
**
** A copy of the key is made for SQLITE_HASH_STRING and SQLITE_HASH_BINARY
** if the copyKey parameter to HashInit is 1.
*/
/* #define SQLITE_HASH_INT 1 // NOT USED */
/* #define SQLITE_HASH_POINTER 2 // NOT USED */
#define SQLITE_HASH_STRING 3
#define SQLITE_HASH_BINARY 4
/*
** Access routines. To delete, insert a NULL pointer.
*/
void sqlite3HashInit(Hash*, int keytype, int copyKey);
void *sqlite3HashInsert(Hash*, const void *pKey, int nKey, void *pData);
void *sqlite3HashFind(const Hash*, const void *pKey, int nKey);
void sqlite3HashClear(Hash*);
/*
** Macros for looping over all elements of a hash table. The idiom is
** like this:
**
** Hash h;
** HashElem *p;
** ...
** for(p=sqliteHashFirst(&h); p; p=sqliteHashNext(p)){
** SomeStructure *pData = sqliteHashData(p);
** // do something with pData
** }
*/
#define sqliteHashFirst(H) ((H)->first)
#define sqliteHashNext(E) ((E)->next)
#define sqliteHashData(E) ((E)->data)
#define sqliteHashKey(E) ((E)->pKey)
#define sqliteHashKeysize(E) ((E)->nKey)
/*
** Number of entries in a hash table
*/
#define sqliteHashCount(H) ((H)->count)
#endif /* _SQLITE_HASH_H_ */
File diff suppressed because it is too large. Load diff
-138
View File
@@ -1,138 +0,0 @@
/*
** 2001 September 15
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** Main file for the SQLite library. The routines in this file
** implement the programmer interface to the library. Routines in
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id$
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
/*
** Execute SQL code. Return one of the SQLITE_ success/failure
** codes. Also write an error message into memory obtained from
** malloc() and make *pzErrMsg point to that message.
**
** If the SQL is a query, then for each row in the query result
** the xCallback() function is called. pArg becomes the first
** argument to xCallback(). If xCallback=NULL then no callback
** is invoked, even for queries.
*/
int sqlite3_exec(
sqlite3 *db, /* The database on which the SQL executes */
const char *zSql, /* The SQL to be executed */
sqlite3_callback xCallback, /* Invoke this callback routine */
void *pArg, /* First argument to xCallback() */
char **pzErrMsg /* Write error messages here */
){
int rc = SQLITE_OK;
const char *zLeftover;
sqlite3_stmt *pStmt = 0;
char **azCols = 0;
int nRetry = 0;
int nChange = 0;
int nCallback;
if( zSql==0 ) return SQLITE_OK;
while( (rc==SQLITE_OK || (rc==SQLITE_SCHEMA && (++nRetry)<2)) && zSql[0] ){
int nCol;
char **azVals = 0;
pStmt = 0;
rc = sqlite3_prepare(db, zSql, -1, &pStmt, &zLeftover);
if( rc!=SQLITE_OK ){
if( pStmt ) sqlite3_finalize(pStmt);
continue;
}
if( !pStmt ){
/* this happens for a comment or white-space */
zSql = zLeftover;
continue;
}
db->nChange += nChange;
nCallback = 0;
nCol = sqlite3_column_count(pStmt);
azCols = sqliteMalloc(2*nCol*sizeof(const char *));
if( nCol && !azCols ){
rc = SQLITE_NOMEM;
goto exec_out;
}
while( 1 ){
int i;
rc = sqlite3_step(pStmt);
/* Invoke the callback function if required */
if( xCallback && (SQLITE_ROW==rc ||
(SQLITE_DONE==rc && !nCallback && db->flags&SQLITE_NullCallback)) ){
if( 0==nCallback ){
for(i=0; i<nCol; i++){
azCols[i] = (char *)sqlite3_column_name(pStmt, i);
}
nCallback++;
}
if( rc==SQLITE_ROW ){
azVals = &azCols[nCol];
for(i=0; i<nCol; i++){
azVals[i] = (char *)sqlite3_column_text(pStmt, i);
}
}
if( xCallback(pArg, nCol, azVals, azCols) ){
rc = SQLITE_ABORT;
goto exec_out;
}
}
if( rc!=SQLITE_ROW ){
rc = sqlite3_finalize(pStmt);
pStmt = 0;
if( db->pVdbe==0 ){
nChange = db->nChange;
}
if( rc!=SQLITE_SCHEMA ){
nRetry = 0;
zSql = zLeftover;
while( isspace((unsigned char)zSql[0]) ) zSql++;
}
break;
}
}
sqliteFree(azCols);
azCols = 0;
}
exec_out:
if( pStmt ) sqlite3_finalize(pStmt);
if( azCols ) sqliteFree(azCols);
if( sqlite3_malloc_failed ){
rc = SQLITE_NOMEM;
}
if( rc!=SQLITE_OK && rc==sqlite3_errcode(db) && pzErrMsg ){
*pzErrMsg = malloc(1+strlen(sqlite3_errmsg(db)));
if( *pzErrMsg ){
strcpy(*pzErrMsg, sqlite3_errmsg(db));
}
}else if( pzErrMsg ){
*pzErrMsg = 0;
}
return rc;
}
File diff suppressed because it is too large. Load diff
-387
View File
@@ -1,387 +0,0 @@
/*
** SQLite uses this code for testing only. It is not a part of
** the SQLite library. This file implements two new TCL commands
** "md5" and "md5file" that compute md5 checksums on arbitrary text
** and on complete files. These commands are used by the "testfixture"
** program to help verify the correct operation of the SQLite library.
**
** The original use of these TCL commands was to test the ROLLBACK
** feature of SQLite. First compute the MD5-checksum of the database.
** Then make some changes but rollback the changes rather than commit
** them. Compute a second MD5-checksum of the file and verify that the
** two checksums are the same. Such is the original use of this code.
** New uses may have been added since this comment was written.
*/
/*
* This code implements the MD5 message-digest algorithm.
* The algorithm is due to Ron Rivest. This code was
* written by Colin Plumb in 1993, no copyright is claimed.
* This code is in the public domain; do with it what you wish.
*
* Equivalent code is available from RSA Data Security, Inc.
* This code has been tested against that, and is equivalent,
* except that you don't need to include two pages of legalese
* with every copy.
*
* To compute the message digest of a chunk of bytes, declare an
* MD5Context structure, pass it to MD5Init, call MD5Update as
* needed on buffers full of bytes, and then call MD5Final, which
* will fill a supplied 16-byte array with the digest.
*/
#include <tcl.h>
#include <string.h>
#include "sqlite3.h"
/*
* If compiled on a machine that doesn't have a 32-bit integer,
* you just set "uint32" to the appropriate datatype for an
* unsigned 32-bit integer. For example:
*
* cc -Duint32='unsigned long' md5.c
*
*/
#ifndef uint32
# define uint32 unsigned int
#endif
struct Context {
uint32 buf[4];
uint32 bits[2];
unsigned char in[64];
};
typedef char MD5Context[88];
/*
* Note: this code is harmless on little-endian machines.
*/
static void byteReverse (unsigned char *buf, unsigned longs){
uint32 t;
do {
t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 |
((unsigned)buf[1]<<8 | buf[0]);
*(uint32 *)buf = t;
buf += 4;
} while (--longs);
}
/* The four core functions - F1 is optimized somewhat */
/* #define F1(x, y, z) (x & y | ~x & z) */
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
/* This is the central step in the MD5 algorithm. */
#define MD5STEP(f, w, x, y, z, data, s) \
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
/*
* The core of the MD5 algorithm, this alters an existing MD5 hash to
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine.
*/
static void MD5Transform(uint32 buf[4], const uint32 in[16]){
register uint32 a, b, c, d;
a = buf[0];
b = buf[1];
c = buf[2];
d = buf[3];
MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7);
MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7);
MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7);
MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7);
MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5);
MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9);
MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5);
MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9);
MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5);
MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9);
MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5);
MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9);
MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4);
MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4);
MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4);
MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4);
MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6);
MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6);
MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6);
MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6);
MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}
/*
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
* initialization constants.
*/
static void MD5Init(MD5Context *pCtx){
struct Context *ctx = (struct Context *)pCtx;
ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89;
ctx->buf[2] = 0x98badcfe;
ctx->buf[3] = 0x10325476;
ctx->bits[0] = 0;
ctx->bits[1] = 0;
}
/*
* Update context to reflect the concatenation of another buffer full
* of bytes.
*/
static
void MD5Update(MD5Context *pCtx, const unsigned char *buf, unsigned int len){
struct Context *ctx = (struct Context *)pCtx;
uint32 t;
/* Update bitcount */
t = ctx->bits[0];
if ((ctx->bits[0] = t + ((uint32)len << 3)) < t)
ctx->bits[1]++; /* Carry from low to high */
ctx->bits[1] += len >> 29;
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
/* Handle any leading odd-sized chunks */
if ( t ) {
unsigned char *p = (unsigned char *)ctx->in + t;
t = 64-t;
if (len < t) {
memcpy(p, buf, len);
return;
}
memcpy(p, buf, t);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32 *)ctx->in);
buf += t;
len -= t;
}
/* Process data in 64-byte chunks */
while (len >= 64) {
memcpy(ctx->in, buf, 64);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32 *)ctx->in);
buf += 64;
len -= 64;
}
/* Handle any remaining bytes of data. */
memcpy(ctx->in, buf, len);
}
/*
* Final wrapup - pad to 64-byte boundary with the bit pattern
* 1 0* (64-bit count of bits processed, MSB-first)
*/
static void MD5Final(unsigned char digest[16], MD5Context *pCtx){
struct Context *ctx = (struct Context *)pCtx;
unsigned count;
unsigned char *p;
/* Compute number of bytes mod 64 */
count = (ctx->bits[0] >> 3) & 0x3F;
/* Set the first char of padding to 0x80. This is safe since there is
always at least one byte free */
p = ctx->in + count;
*p++ = 0x80;
/* Bytes of padding needed to make 64 bytes */
count = 64 - 1 - count;
/* Pad out to 56 mod 64 */
if (count < 8) {
/* Two lots of padding: Pad the first block to 64 bytes */
memset(p, 0, count);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32 *)ctx->in);
/* Now fill the next block with 56 bytes */
memset(ctx->in, 0, 56);
} else {
/* Pad block to 56 bytes */
memset(p, 0, count-8);
}
byteReverse(ctx->in, 14);
/* Append length in bits and transform */
((uint32 *)ctx->in)[ 14 ] = ctx->bits[0];
((uint32 *)ctx->in)[ 15 ] = ctx->bits[1];
MD5Transform(ctx->buf, (uint32 *)ctx->in);
byteReverse((unsigned char *)ctx->buf, 4);
memcpy(digest, ctx->buf, 16);
memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
}
/*
** Convert a digest into base-16. digest should be declared as
** "unsigned char digest[16]" in the calling function. The MD5
** digest is stored in the first 16 bytes. zBuf should
** be "char zBuf[33]".
*/
static void DigestToBase16(unsigned char *digest, char *zBuf){
static char const zEncode[] = "0123456789abcdef";
int i, j;
for(j=i=0; i<16; i++){
int a = digest[i];
zBuf[j++] = zEncode[(a>>4)&0xf];
zBuf[j++] = zEncode[a & 0xf];
}
zBuf[j] = 0;
}
/*
** A TCL command for md5. The argument is the text to be hashed. The
** Result is the hash in base64.
*/
static int md5_cmd(void*cd, Tcl_Interp *interp, int argc, const char **argv){
MD5Context ctx;
unsigned char digest[16];
if( argc!=2 ){
Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
" TEXT\"", 0);
return TCL_ERROR;
}
MD5Init(&ctx);
MD5Update(&ctx, (unsigned char*)argv[1], (unsigned)strlen(argv[1]));
MD5Final(digest, &ctx);
DigestToBase16(digest, interp->result);
return TCL_OK;
}
/*
** A TCL command to take the md5 hash of a file. The argument is the
** name of the file.
*/
static int md5file_cmd(void*cd, Tcl_Interp*interp, int argc, const char **argv){
FILE *in;
MD5Context ctx;
unsigned char digest[16];
char zBuf[10240];
if( argc!=2 ){
Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
" FILENAME\"", 0);
return TCL_ERROR;
}
in = fopen(argv[1],"rb");
if( in==0 ){
Tcl_AppendResult(interp,"unable to open file \"", argv[1],
"\" for reading", 0);
return TCL_ERROR;
}
MD5Init(&ctx);
for(;;){
int n;
n = fread(zBuf, 1, sizeof(zBuf), in);
if( n<=0 ) break;
MD5Update(&ctx, (unsigned char*)zBuf, (unsigned)n);
}
fclose(in);
MD5Final(digest, &ctx);
DigestToBase16(digest, interp->result);
return TCL_OK;
}
/*
** Register the two TCL commands above with the TCL interpreter.
*/
int Md5_Init(Tcl_Interp *interp){
Tcl_CreateCommand(interp, "md5", (Tcl_CmdProc*)md5_cmd, 0, 0);
Tcl_CreateCommand(interp, "md5file", (Tcl_CmdProc*)md5file_cmd, 0, 0);
return TCL_OK;
}
/*
** During testing, the special md5sum() aggregate function is available.
** inside SQLite. The following routines implement that function.
*/
static void md5step(sqlite3_context *context, int argc, sqlite3_value **argv){
MD5Context *p;
int i;
if( argc<1 ) return;
p = sqlite3_aggregate_context(context, sizeof(*p));
if( p==0 ) return;
if( sqlite3_aggregate_count(context)==1 ){
MD5Init(p);
}
for(i=0; i<argc; i++){
const char *zData = sqlite3_value_text(argv[i]);
if( zData ){
MD5Update(p, zData, strlen(zData));
}
}
}
static void md5finalize(sqlite3_context *context){
MD5Context *p;
unsigned char digest[16];
char zBuf[33];
p = sqlite3_aggregate_context(context, sizeof(*p));
MD5Final(digest,p);
DigestToBase16(digest, zBuf);
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
}
void Md5_Register(sqlite3 *db){
sqlite3_create_function(db, "md5sum", -1, SQLITE_UTF8, 0, 0,
md5step, md5finalize);
}
-197
View File
@@ -1,197 +0,0 @@
/*
** 2001 September 16
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
******************************************************************************
**
** This header file (together with is companion C source-code file
** "os.c") attempt to abstract the underlying operating system so that
** the SQLite library will work on both POSIX and windows systems.
*/
#ifndef _SQLITE_OS_H_
#define _SQLITE_OS_H_
/*
** Figure out if we are dealing with Unix, Windows or MacOS.
**
** N.B. MacOS means Mac Classic (or Carbon). Treat Darwin (OS X) as Unix.
** The MacOS build is designed to use CodeWarrior (tested with v8)
*/
#if !defined(OS_UNIX) && !defined(OS_TEST)
# ifndef OS_WIN
# ifndef OS_MAC
# if defined(__MACOS__)
# define OS_MAC 1
# define OS_WIN 0
# define OS_UNIX 0
# elif defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__)
# define OS_MAC 0
# define OS_WIN 1
# define OS_UNIX 0
# else
# define OS_MAC 0
# define OS_WIN 0
# define OS_UNIX 1
# endif
# else
# define OS_WIN 0
# define OS_UNIX 0
# endif
# else
# define OS_MAC 0
# define OS_UNIX 0
# endif
#else
# define OS_MAC 0
# ifndef OS_WIN
# define OS_WIN 0
# endif
#endif
/*
** Invoke the appropriate operating-system specific header file.
*/
#if OS_TEST
# include "os_test.h"
#endif
#if OS_UNIX
# include "os_unix.h"
#endif
#if OS_WIN
# include "os_win.h"
#endif
#if OS_MAC
# include "os_mac.h"
#endif
/*
** Temporary files are named starting with this prefix followed by 16 random
** alphanumeric characters, and no file extension. They are stored in the
** OS's standard temporary file directory, and are deleted prior to exit.
** If sqlite is being embedded in another program, you may wish to change the
** prefix to reflect your program's name, so that if your program exits
** prematurely, old temporary files can be easily identified. This can be done
** using -DTEMP_FILE_PREFIX=myprefix_ on the compiler command line.
*/
#ifndef TEMP_FILE_PREFIX
# define TEMP_FILE_PREFIX "sqlite_"
#endif
/*
** The following values may be passed as the second argument to
** sqlite3OsLock(). The various locks exhibit the following semantics:
**
** SHARED: Any number of processes may hold a SHARED lock simultaneously.
** RESERVED: A single process may hold a RESERVED lock on a file at
** any time. Other processes may hold and obtain new SHARED locks.
** PENDING: A single process may hold a PENDING lock on a file at
** any one time. Existing SHARED locks may persist, but no new
** SHARED locks may be obtained by other processes.
** EXCLUSIVE: An EXCLUSIVE lock precludes all other locks.
**
** PENDING_LOCK may not be passed directly to sqlite3OsLock(). Instead, a
** process that requests an EXCLUSIVE lock may actually obtain a PENDING
** lock. This can be upgraded to an EXCLUSIVE lock by a subsequent call to
** sqlite3OsLock().
*/
#define NO_LOCK 0
#define SHARED_LOCK 1
#define RESERVED_LOCK 2
#define PENDING_LOCK 3
#define EXCLUSIVE_LOCK 4
/*
** File Locking Notes: (Mostly about windows but also some info for Unix)
**
** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because
** those functions are not available. So we use only LockFile() and
** UnlockFile().
**
** LockFile() prevents not just writing but also reading by other processes.
** A SHARED_LOCK is obtained by locking a single randomly-chosen
** byte out of a specific range of bytes. The lock byte is obtained at
** random so two separate readers can probably access the file at the
** same time, unless they are unlucky and choose the same lock byte.
** An EXCLUSIVE_LOCK is obtained by locking all bytes in the range.
** There can only be one writer. A RESERVED_LOCK is obtained by locking
** a single byte of the file that is designated as the reserved lock byte.
** A PENDING_LOCK is obtained by locking a designated byte different from
** the RESERVED_LOCK byte.
**
** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available,
** which means we can use reader/writer locks. When reader/writer locks
** are used, the lock is placed on the same range of bytes that is used
** for probabilistic locking in Win95/98/ME. Hence, the locking scheme
** will support two or more Win95 readers or two or more WinNT readers.
** But a single Win95 reader will lock out all WinNT readers and a single
** WinNT reader will lock out all other Win95 readers.
**
** The following #defines specify the range of bytes used for locking.
** SHARED_SIZE is the number of bytes available in the pool from which
** a random byte is selected for a shared lock. The pool of bytes for
** shared locks begins at SHARED_FIRST.
**
** These #defines are available in os.h so that Unix can use the same
** byte ranges for locking. This leaves open the possiblity of having
** clients on win95, winNT, and unix all talking to the same shared file
** and all locking correctly. To do so would require that samba (or whatever
** tool is being used for file sharing) implements locks correctly between
** windows and unix. I'm guessing that isn't likely to happen, but by
** using the same locking range we are at least open to the possibility.
**
** Locking in windows is manditory. For this reason, we cannot store
** actual data in the bytes used for locking. The pager never allocates
** the pages involved in locking therefore. SHARED_SIZE is selected so
** that all locks will fit on a single page even at the minimum page size.
** PENDING_BYTE defines the beginning of the locks. By default PENDING_BYTE
** is set high so that we don't have to allocate an unused page except
** for very large databases. But one should test the page skipping logic
** by setting PENDING_BYTE low and running the entire regression suite.
**
** Changing the value of PENDING_BYTE results in a subtly incompatible
** file format. Depending on how it is changed, you might not notice
** the incompatibility right away, even running a full regression test.
** The default location of PENDING_BYTE is the first byte past the
** 1GB boundary.
**
*/
#define PENDING_BYTE 0x40000000 /* First byte past the 1GB boundary */
/* #define PENDING_BYTE 0x5400 // Page 20 - for testing */
#define RESERVED_BYTE (PENDING_BYTE+1)
#define SHARED_FIRST (PENDING_BYTE+2)
#define SHARED_SIZE 510
int sqlite3OsDelete(const char*);
int sqlite3OsFileExists(const char*);
int sqlite3OsOpenReadWrite(const char*, OsFile*, int*);
int sqlite3OsOpenExclusive(const char*, OsFile*, int);
int sqlite3OsOpenReadOnly(const char*, OsFile*);
int sqlite3OsOpenDirectory(const char*, OsFile*);
int sqlite3OsSyncDirectory(const char*);
int sqlite3OsTempFileName(char*);
int sqlite3OsClose(OsFile*);
int sqlite3OsRead(OsFile*, void*, int amt);
int sqlite3OsWrite(OsFile*, const void*, int amt);
int sqlite3OsSeek(OsFile*, i64 offset);
int sqlite3OsSync(OsFile*);
int sqlite3OsTruncate(OsFile*, i64 size);
int sqlite3OsFileSize(OsFile*, i64 *pSize);
int sqlite3OsRandomSeed(char*);
int sqlite3OsSleep(int ms);
int sqlite3OsCurrentTime(double*);
int sqlite3OsFileModTime(OsFile*, double*);
void sqlite3OsEnterMutex(void);
void sqlite3OsLeaveMutex(void);
char *sqlite3OsFullPathname(const char*);
int sqlite3OsLock(OsFile*, int);
int sqlite3OsUnlock(OsFile*, int);
int sqlite3OsCheckReservedLock(OsFile *id);
#endif /* _SQLITE_OS_H_ */
-107
View File
@@ -1,107 +0,0 @@
/*
** 2004 May 22
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
******************************************************************************
**
** This file contains macros and a little bit of code that is common to
** all of the platform-specific files (os_*.c) and is #included into those
** files.
**
** This file should be #included by the os_*.c files only. It is not a
** general purpose header file.
*/
/*
** At least two bugs have slipped in because we changed the MEMORY_DEBUG
** macro to SQLITE_DEBUG and some older makefiles have not yet made the
** switch. The following code should catch this problem at compile-time.
*/
#ifdef MEMORY_DEBUG
# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead."
#endif
int sqlite3_os_trace = 0;
#ifdef SQLITE_DEBUG
static int last_page = 0;
#define SEEK(X) last_page=(X)
#define TRACE1(X) if( sqlite3_os_trace ) sqlite3DebugPrintf(X)
#define TRACE2(X,Y) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y)
#define TRACE3(X,Y,Z) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z)
#define TRACE4(X,Y,Z,A) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z,A)
#define TRACE5(X,Y,Z,A,B) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z,A,B)
#define TRACE6(X,Y,Z,A,B,C) if(sqlite3_os_trace) sqlite3DebugPrintf(X,Y,Z,A,B,C)
#define TRACE7(X,Y,Z,A,B,C,D) \
if(sqlite3_os_trace) sqlite3DebugPrintf(X,Y,Z,A,B,C,D)
#else
#define SEEK(X)
#define TRACE1(X)
#define TRACE2(X,Y)
#define TRACE3(X,Y,Z)
#define TRACE4(X,Y,Z,A)
#define TRACE5(X,Y,Z,A,B)
#define TRACE6(X,Y,Z,A,B,C)
#define TRACE7(X,Y,Z,A,B,C,D)
#endif
/*
** Macros for performance tracing. Normally turned off. Only works
** on i486 hardware.
*/
#ifdef SQLITE_PERFORMANCE_TRACE
__inline__ unsigned long long int hwtime(void){
unsigned long long int x;
__asm__("rdtsc\n\t"
"mov %%edx, %%ecx\n\t"
:"=A" (x));
return x;
}
static unsigned long long int g_start;
static unsigned int elapse;
#define TIMER_START g_start=hwtime()
#define TIMER_END elapse=hwtime()-g_start
#define TIMER_ELAPSED elapse
#else
#define TIMER_START
#define TIMER_END
#define TIMER_ELAPSED 0
#endif
/*
** If we compile with the SQLITE_TEST macro set, then the following block
** of code will give us the ability to simulate a disk I/O error. This
** is used for testing the I/O recovery logic.
*/
#ifdef SQLITE_TEST
int sqlite3_io_error_pending = 0;
int sqlite3_diskfull_pending = 0;
#define SimulateIOError(A) \
if( sqlite3_io_error_pending ) \
if( sqlite3_io_error_pending-- == 1 ){ local_ioerr(); return A; }
static void local_ioerr(){
sqlite3_io_error_pending = 0; /* Really just a place to set a breakpoint */
}
#define SimulateDiskfullError \
if( sqlite3_diskfull_pending ) \
if( sqlite3_diskfull_pending-- == 1 ){ local_ioerr(); return SQLITE_FULL; }
#else
#define SimulateIOError(A)
#define SimulateDiskfullError
#endif
/*
** When testing, keep a count of the number of open files.
*/
#ifdef SQLITE_TEST
int sqlite3_open_file_count = 0;
#define OpenCounter(X) sqlite3_open_file_count+=(X)
#else
#define OpenCounter(X)
#endif
-738
View File
@@ -1,738 +0,0 @@
/*
** 2004 May 22
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
******************************************************************************
**
** This file contains code that is specific classic mac. Mac OS X
** uses the os_unix.c file, not this one.
*/
#include "sqliteInt.h"
#include "os.h"
#if OS_MAC /* This file used on classic mac only */
#include <extras.h>
#include <path2fss.h>
#include <TextUtils.h>
#include <FinderRegistry.h>
#include <Folders.h>
#include <Timer.h>
#include <OSUtils.h>
/*
** Macros used to determine whether or not to use threads.
*/
#if defined(THREADSAFE) && THREADSAFE
# include <Multiprocessing.h>
# define SQLITE_MACOS_MULTITASKING 1
#endif
/*
** Include code that is common to all os_*.c files
*/
#include "os_common.h"
/*
** Delete the named file
*/
int sqlite3OsDelete(const char *zFilename){
unlink(zFilename);
return SQLITE_OK;
}
/*
** Return TRUE if the named file exists.
*/
int sqlite3OsFileExists(const char *zFilename){
return access(zFilename, 0)==0;
}
/*
** Attempt to open a file for both reading and writing. If that
** fails, try opening it read-only. If the file does not exist,
** try to create it.
**
** On success, a handle for the open file is written to *id
** and *pReadonly is set to 0 if the file was opened for reading and
** writing or 1 if the file was opened read-only. The function returns
** SQLITE_OK.
**
** On failure, the function returns SQLITE_CANTOPEN and leaves
** *id and *pReadonly unchanged.
*/
int sqlite3OsOpenReadWrite(
const char *zFilename,
OsFile *id,
int *pReadonly
){
FSSpec fsSpec;
# ifdef _LARGE_FILE
HFSUniStr255 dfName;
FSRef fsRef;
if( __path2fss(zFilename, &fsSpec) != noErr ){
if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )
return SQLITE_CANTOPEN;
}
if( FSpMakeFSRef(&fsSpec, &fsRef) != noErr )
return SQLITE_CANTOPEN;
FSGetDataForkName(&dfName);
if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,
fsRdWrShPerm, &(id->refNum)) != noErr ){
if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,
fsRdWrPerm, &(id->refNum)) != noErr ){
if (FSOpenFork(&fsRef, dfName.length, dfName.unicode,
fsRdPerm, &(id->refNum)) != noErr )
return SQLITE_CANTOPEN;
else
*pReadonly = 1;
} else
*pReadonly = 0;
} else
*pReadonly = 0;
# else
__path2fss(zFilename, &fsSpec);
if( !sqlite3OsFileExists(zFilename) ){
if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )
return SQLITE_CANTOPEN;
}
if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrShPerm, &(id->refNum)) != noErr ){
if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrPerm, &(id->refNum)) != noErr ){
if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdPerm, &(id->refNum)) != noErr )
return SQLITE_CANTOPEN;
else
*pReadonly = 1;
} else
*pReadonly = 0;
} else
*pReadonly = 0;
# endif
if( HOpenRF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrShPerm, &(id->refNumRF)) != noErr){
id->refNumRF = -1;
}
id->locked = 0;
id->delOnClose = 0;
OpenCounter(+1);
return SQLITE_OK;
}
/*
** Attempt to open a new file for exclusive access by this process.
** The file will be opened for both reading and writing. To avoid
** a potential security problem, we do not allow the file to have
** previously existed. Nor do we allow the file to be a symbolic
** link.
**
** If delFlag is true, then make arrangements to automatically delete
** the file when it is closed.
**
** On success, write the file handle into *id and return SQLITE_OK.
**
** On failure, return SQLITE_CANTOPEN.
*/
int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
FSSpec fsSpec;
# ifdef _LARGE_FILE
HFSUniStr255 dfName;
FSRef fsRef;
__path2fss(zFilename, &fsSpec);
if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )
return SQLITE_CANTOPEN;
if( FSpMakeFSRef(&fsSpec, &fsRef) != noErr )
return SQLITE_CANTOPEN;
FSGetDataForkName(&dfName);
if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,
fsRdWrPerm, &(id->refNum)) != noErr )
return SQLITE_CANTOPEN;
# else
__path2fss(zFilename, &fsSpec);
if( HCreate(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, 'SQLI', cDocumentFile) != noErr )
return SQLITE_CANTOPEN;
if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrPerm, &(id->refNum)) != noErr )
return SQLITE_CANTOPEN;
# endif
id->refNumRF = -1;
id->locked = 0;
id->delOnClose = delFlag;
if (delFlag)
id->pathToDel = sqlite3OsFullPathname(zFilename);
OpenCounter(+1);
return SQLITE_OK;
}
/*
** Attempt to open a new file for read-only access.
**
** On success, write the file handle into *id and return SQLITE_OK.
**
** On failure, return SQLITE_CANTOPEN.
*/
int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
FSSpec fsSpec;
# ifdef _LARGE_FILE
HFSUniStr255 dfName;
FSRef fsRef;
if( __path2fss(zFilename, &fsSpec) != noErr )
return SQLITE_CANTOPEN;
if( FSpMakeFSRef(&fsSpec, &fsRef) != noErr )
return SQLITE_CANTOPEN;
FSGetDataForkName(&dfName);
if( FSOpenFork(&fsRef, dfName.length, dfName.unicode,
fsRdPerm, &(id->refNum)) != noErr )
return SQLITE_CANTOPEN;
# else
__path2fss(zFilename, &fsSpec);
if( HOpenDF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdPerm, &(id->refNum)) != noErr )
return SQLITE_CANTOPEN;
# endif
if( HOpenRF(fsSpec.vRefNum, fsSpec.parID, fsSpec.name, fsRdWrShPerm, &(id->refNumRF)) != noErr){
id->refNumRF = -1;
}
id->locked = 0;
id->delOnClose = 0;
OpenCounter(+1);
return SQLITE_OK;
}
/*
** Attempt to open a file descriptor for the directory that contains a
** file. This file descriptor can be used to fsync() the directory
** in order to make sure the creation of a new file is actually written
** to disk.
**
** This routine is only meaningful for Unix. It is a no-op under
** windows since windows does not support hard links.
**
** On success, a handle for a previously open file is at *id is
** updated with the new directory file descriptor and SQLITE_OK is
** returned.
**
** On failure, the function returns SQLITE_CANTOPEN and leaves
** *id unchanged.
*/
int sqlite3OsOpenDirectory(
const char *zDirname,
OsFile *id
){
return SQLITE_OK;
}
/*
** Create a temporary file name in zBuf. zBuf must be big enough to
** hold at least SQLITE_TEMPNAME_SIZE characters.
*/
int sqlite3OsTempFileName(char *zBuf){
static char zChars[] =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
int i, j;
char zTempPath[SQLITE_TEMPNAME_SIZE];
char zdirName[32];
CInfoPBRec infoRec;
Str31 dirName;
memset(&infoRec, 0, sizeof(infoRec));
memset(zTempPath, 0, SQLITE_TEMPNAME_SIZE);
if( FindFolder(kOnSystemDisk, kTemporaryFolderType, kCreateFolder,
&(infoRec.dirInfo.ioVRefNum), &(infoRec.dirInfo.ioDrParID)) == noErr ){
infoRec.dirInfo.ioNamePtr = dirName;
do{
infoRec.dirInfo.ioFDirIndex = -1;
infoRec.dirInfo.ioDrDirID = infoRec.dirInfo.ioDrParID;
if( PBGetCatInfoSync(&infoRec) == noErr ){
CopyPascalStringToC(dirName, zdirName);
i = strlen(zdirName);
memmove(&(zTempPath[i+1]), zTempPath, strlen(zTempPath));
strcpy(zTempPath, zdirName);
zTempPath[i] = ':';
}else{
*zTempPath = 0;
break;
}
} while( infoRec.dirInfo.ioDrDirID != fsRtDirID );
}
if( *zTempPath == 0 )
getcwd(zTempPath, SQLITE_TEMPNAME_SIZE-24);
for(;;){
sprintf(zBuf, "%s"TEMP_FILE_PREFIX, zTempPath);
j = strlen(zBuf);
sqlite3Randomness(15, &zBuf[j]);
for(i=0; i<15; i++, j++){
zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
}
zBuf[j] = 0;
if( !sqlite3OsFileExists(zBuf) ) break;
}
return SQLITE_OK;
}
/*
** Close a file.
*/
int sqlite3OsClose(OsFile *id){
if( id->refNumRF!=-1 )
FSClose(id->refNumRF);
# ifdef _LARGE_FILE
FSCloseFork(id->refNum);
# else
FSClose(id->refNum);
# endif
if( id->delOnClose ){
unlink(id->pathToDel);
sqliteFree(id->pathToDel);
}
OpenCounter(-1);
return SQLITE_OK;
}
/*
** Read data from a file into a buffer. Return SQLITE_OK if all
** bytes were read successfully and SQLITE_IOERR if anything goes
** wrong.
*/
int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
int got;
SimulateIOError(SQLITE_IOERR);
TRACE2("READ %d\n", last_page);
# ifdef _LARGE_FILE
FSReadFork(id->refNum, fsAtMark, 0, (ByteCount)amt, pBuf, (ByteCount*)&got);
# else
got = amt;
FSRead(id->refNum, &got, pBuf);
# endif
if( got==amt ){
return SQLITE_OK;
}else{
return SQLITE_IOERR;
}
}
/*
** Write data from a buffer into a file. Return SQLITE_OK on success
** or some other error code on failure.
*/
int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
OSErr oserr;
int wrote = 0;
SimulateIOError(SQLITE_IOERR);
TRACE2("WRITE %d\n", last_page);
while( amt>0 ){
# ifdef _LARGE_FILE
oserr = FSWriteFork(id->refNum, fsAtMark, 0,
(ByteCount)amt, pBuf, (ByteCount*)&wrote);
# else
wrote = amt;
oserr = FSWrite(id->refNum, &wrote, pBuf);
# endif
if( wrote == 0 || oserr != noErr)
break;
amt -= wrote;
pBuf = &((char*)pBuf)[wrote];
}
if( oserr != noErr || amt>wrote ){
return SQLITE_FULL;
}
return SQLITE_OK;
}
/*
** Move the read/write pointer in a file.
*/
int sqlite3OsSeek(OsFile *id, off_t offset){
off_t curSize;
SEEK(offset/1024 + 1);
if( sqlite3OsFileSize(id, &curSize) != SQLITE_OK ){
return SQLITE_IOERR;
}
if( offset >= curSize ){
if( sqlite3OsTruncate(id, offset+1) != SQLITE_OK ){
return SQLITE_IOERR;
}
}
# ifdef _LARGE_FILE
if( FSSetForkPosition(id->refNum, fsFromStart, offset) != noErr ){
# else
if( SetFPos(id->refNum, fsFromStart, offset) != noErr ){
# endif
return SQLITE_IOERR;
}else{
return SQLITE_OK;
}
}
/*
** Make sure all writes to a particular file are committed to disk.
**
** Under Unix, also make sure that the directory entry for the file
** has been created by fsync-ing the directory that contains the file.
** If we do not do this and we encounter a power failure, the directory
** entry for the journal might not exist after we reboot. The next
** SQLite to access the file will not know that the journal exists (because
** the directory entry for the journal was never created) and the transaction
** will not roll back - possibly leading to database corruption.
*/
int sqlite3OsSync(OsFile *id){
# ifdef _LARGE_FILE
if( FSFlushFork(id->refNum) != noErr ){
# else
ParamBlockRec params;
memset(&params, 0, sizeof(ParamBlockRec));
params.ioParam.ioRefNum = id->refNum;
if( PBFlushFileSync(&params) != noErr ){
# endif
return SQLITE_IOERR;
}else{
return SQLITE_OK;
}
}
/*
** Sync the directory zDirname. This is a no-op on operating systems other
** than UNIX.
*/
int sqlite3OsSyncDirectory(const char *zDirname){
SimulateIOError(SQLITE_IOERR);
return SQLITE_OK;
}
/*
** Truncate an open file to a specified size
*/
int sqlite3OsTruncate(OsFile *id, off_t nByte){
SimulateIOError(SQLITE_IOERR);
# ifdef _LARGE_FILE
if( FSSetForkSize(id->refNum, fsFromStart, nByte) != noErr){
# else
if( SetEOF(id->refNum, nByte) != noErr ){
# endif
return SQLITE_IOERR;
}else{
return SQLITE_OK;
}
}
/*
** Determine the current size of a file in bytes
*/
int sqlite3OsFileSize(OsFile *id, off_t *pSize){
# ifdef _LARGE_FILE
if( FSGetForkSize(id->refNum, pSize) != noErr){
# else
if( GetEOF(id->refNum, pSize) != noErr ){
# endif
return SQLITE_IOERR;
}else{
return SQLITE_OK;
}
}
/*
** Windows file locking notes: [similar issues apply to MacOS]
**
** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because
** those functions are not available. So we use only LockFile() and
** UnlockFile().
**
** LockFile() prevents not just writing but also reading by other processes.
** (This is a design error on the part of Windows, but there is nothing
** we can do about that.) So the region used for locking is at the
** end of the file where it is unlikely to ever interfere with an
** actual read attempt.
**
** A database read lock is obtained by locking a single randomly-chosen
** byte out of a specific range of bytes. The lock byte is obtained at
** random so two separate readers can probably access the file at the
** same time, unless they are unlucky and choose the same lock byte.
** A database write lock is obtained by locking all bytes in the range.
** There can only be one writer.
**
** A lock is obtained on the first byte of the lock range before acquiring
** either a read lock or a write lock. This prevents two processes from
** attempting to get a lock at a same time. The semantics of
** sqlite3OsReadLock() require that if there is already a write lock, that
** lock is converted into a read lock atomically. The lock on the first
** byte allows us to drop the old write lock and get the read lock without
** another process jumping into the middle and messing us up. The same
** argument applies to sqlite3OsWriteLock().
**
** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available,
** which means we can use reader/writer locks. When reader writer locks
** are used, the lock is placed on the same range of bytes that is used
** for probabilistic locking in Win95/98/ME. Hence, the locking scheme
** will support two or more Win95 readers or two or more WinNT readers.
** But a single Win95 reader will lock out all WinNT readers and a single
** WinNT reader will lock out all other Win95 readers.
**
** Note: On MacOS we use the resource fork for locking.
**
** The following #defines specify the range of bytes used for locking.
** N_LOCKBYTE is the number of bytes available for doing the locking.
** The first byte used to hold the lock while the lock is changing does
** not count toward this number. FIRST_LOCKBYTE is the address of
** the first byte in the range of bytes used for locking.
*/
#define N_LOCKBYTE 10239
#define FIRST_LOCKBYTE (0x000fffff - N_LOCKBYTE)
/*
** Change the status of the lock on the file "id" to be a readlock.
** If the file was write locked, then this reduces the lock to a read.
** If the file was read locked, then this acquires a new read lock.
**
** Return SQLITE_OK on success and SQLITE_BUSY on failure. If this
** library was compiled with large file support (LFS) but LFS is not
** available on the host, then an SQLITE_NOLFS is returned.
*/
int sqlite3OsReadLock(OsFile *id){
int rc;
if( id->locked>0 || id->refNumRF == -1 ){
rc = SQLITE_OK;
}else{
int lk;
OSErr res;
int cnt = 5;
ParamBlockRec params;
sqlite3Randomness(sizeof(lk), &lk);
lk = (lk & 0x7fffffff)%N_LOCKBYTE + 1;
memset(&params, 0, sizeof(params));
params.ioParam.ioRefNum = id->refNumRF;
params.ioParam.ioPosMode = fsFromStart;
params.ioParam.ioPosOffset = FIRST_LOCKBYTE;
params.ioParam.ioReqCount = 1;
while( cnt-->0 && (res = PBLockRangeSync(&params))!=noErr ){
UInt32 finalTicks;
Delay(1, &finalTicks); /* 1/60 sec */
}
if( res == noErr ){
params.ioParam.ioPosOffset = FIRST_LOCKBYTE+1;
params.ioParam.ioReqCount = N_LOCKBYTE;
PBUnlockRangeSync(&params);
params.ioParam.ioPosOffset = FIRST_LOCKBYTE+lk;
params.ioParam.ioReqCount = 1;
res = PBLockRangeSync(&params);
params.ioParam.ioPosOffset = FIRST_LOCKBYTE;
params.ioParam.ioReqCount = 1;
PBUnlockRangeSync(&params);
}
if( res == noErr ){
id->locked = lk;
rc = SQLITE_OK;
}else{
rc = SQLITE_BUSY;
}
}
return rc;
}
/*
** Change the lock status to be an exclusive or write lock. Return
** SQLITE_OK on success and SQLITE_BUSY on a failure. If this
** library was compiled with large file support (LFS) but LFS is not
** available on the host, then an SQLITE_NOLFS is returned.
*/
int sqlite3OsWriteLock(OsFile *id){
int rc;
if( id->locked<0 || id->refNumRF == -1 ){
rc = SQLITE_OK;
}else{
OSErr res;
int cnt = 5;
ParamBlockRec params;
memset(&params, 0, sizeof(params));
params.ioParam.ioRefNum = id->refNumRF;
params.ioParam.ioPosMode = fsFromStart;
params.ioParam.ioPosOffset = FIRST_LOCKBYTE;
params.ioParam.ioReqCount = 1;
while( cnt-->0 && (res = PBLockRangeSync(&params))!=noErr ){
UInt32 finalTicks;
Delay(1, &finalTicks); /* 1/60 sec */
}
if( res == noErr ){
params.ioParam.ioPosOffset = FIRST_LOCKBYTE + id->locked;
params.ioParam.ioReqCount = 1;
if( id->locked==0
|| PBUnlockRangeSync(&params)==noErr ){
params.ioParam.ioPosOffset = FIRST_LOCKBYTE+1;
params.ioParam.ioReqCount = N_LOCKBYTE;
res = PBLockRangeSync(&params);
}else{
res = afpRangeNotLocked;
}
params.ioParam.ioPosOffset = FIRST_LOCKBYTE;
params.ioParam.ioReqCount = 1;
PBUnlockRangeSync(&params);
}
if( res == noErr ){
id->locked = -1;
rc = SQLITE_OK;
}else{
rc = SQLITE_BUSY;
}
}
return rc;
}
/*
** Unlock the given file descriptor. If the file descriptor was
** not previously locked, then this routine is a no-op. If this
** library was compiled with large file support (LFS) but LFS is not
** available on the host, then an SQLITE_NOLFS is returned.
*/
int sqlite3OsUnlock(OsFile *id){
int rc;
ParamBlockRec params;
memset(&params, 0, sizeof(params));
params.ioParam.ioRefNum = id->refNumRF;
params.ioParam.ioPosMode = fsFromStart;
if( id->locked==0 || id->refNumRF == -1 ){
rc = SQLITE_OK;
}else if( id->locked<0 ){
params.ioParam.ioPosOffset = FIRST_LOCKBYTE+1;
params.ioParam.ioReqCount = N_LOCKBYTE;
PBUnlockRangeSync(&params);
rc = SQLITE_OK;
id->locked = 0;
}else{
params.ioParam.ioPosOffset = FIRST_LOCKBYTE+id->locked;
params.ioParam.ioReqCount = 1;
PBUnlockRangeSync(&params);
rc = SQLITE_OK;
id->locked = 0;
}
return rc;
}
/*
** Get information to seed the random number generator. The seed
** is written into the buffer zBuf[256]. The calling function must
** supply a sufficiently large buffer.
*/
int sqlite3OsRandomSeed(char *zBuf){
/* We have to initialize zBuf to prevent valgrind from reporting
** errors. The reports issued by valgrind are incorrect - we would
** prefer that the randomness be increased by making use of the
** uninitialized space in zBuf - but valgrind errors tend to worry
** some users. Rather than argue, it seems easier just to initialize
** the whole array and silence valgrind, even if that means less randomness
** in the random seed.
**
** When testing, initializing zBuf[] to zero is all we do. That means
** that we always use the same random number sequence.* This makes the
** tests repeatable.
*/
memset(zBuf, 0, 256);
#if !defined(SQLITE_TEST)
{
int pid;
Microseconds((UnsignedWide*)zBuf);
pid = getpid();
memcpy(&zBuf[sizeof(UnsignedWide)], &pid, sizeof(pid));
}
#endif
return SQLITE_OK;
}
/*
** Sleep for a little while. Return the amount of time slept.
*/
int sqlite3OsSleep(int ms){
UInt32 finalTicks;
UInt32 ticks = (((UInt32)ms+16)*3)/50; /* 1/60 sec per tick */
Delay(ticks, &finalTicks);
return (int)((ticks*50)/3);
}
/*
** Static variables used for thread synchronization
*/
static int inMutex = 0;
#ifdef SQLITE_MACOS_MULTITASKING
static MPCriticalRegionID criticalRegion;
#endif
/*
** The following pair of routine implement mutual exclusion for
** multi-threaded processes. Only a single thread is allowed to
** executed code that is surrounded by EnterMutex() and LeaveMutex().
**
** SQLite uses only a single Mutex. There is not much critical
** code and what little there is executes quickly and without blocking.
*/
void sqlite3OsEnterMutex(){
#ifdef SQLITE_MACOS_MULTITASKING
static volatile int notInit = 1;
if( notInit ){
if( notInit == 2 ) /* as close as you can get to thread safe init */
MPYield();
else{
notInit = 2;
MPCreateCriticalRegion(&criticalRegion);
notInit = 0;
}
}
MPEnterCriticalRegion(criticalRegion, kDurationForever);
#endif
assert( !inMutex );
inMutex = 1;
}
void sqlite3OsLeaveMutex(){
assert( inMutex );
inMutex = 0;
#ifdef SQLITE_MACOS_MULTITASKING
MPExitCriticalRegion(criticalRegion);
#endif
}
/*
** Turn a relative pathname into a full pathname. Return a pointer
** to the full pathname stored in space obtained from sqliteMalloc().
** The calling function is responsible for freeing this space once it
** is no longer needed.
*/
char *sqlite3OsFullPathname(const char *zRelative){
char *zFull = 0;
if( zRelative[0]==':' ){
char zBuf[_MAX_PATH+1];
sqlite3SetString(&zFull, getcwd(zBuf, sizeof(zBuf)), &(zRelative[1]),
(char*)0);
}else{
if( strchr(zRelative, ':') ){
sqlite3SetString(&zFull, zRelative, (char*)0);
}else{
char zBuf[_MAX_PATH+1];
sqlite3SetString(&zFull, getcwd(zBuf, sizeof(zBuf)), zRelative, (char*)0);
}
}
return zFull;
}
/*
** The following variable, if set to a non-zero value, becomes the result
** returned from sqlite3OsCurrentTime(). This is used for testing.
*/
#ifdef SQLITE_TEST
int sqlite3_current_time = 0;
#endif
/*
** Find the current time (in Universal Coordinated Time). Write the
** current time and date as a Julian Day number into *prNow and
** return 0. Return 1 if the time and date cannot be found.
*/
int sqlite3OsCurrentTime(double *prNow){
*prNow = 0.0; /**** FIX ME *****/
#ifdef SQLITE_TEST
if( sqlite3_current_time ){
*prNow = sqlite3_current_time/86400.0 + 2440587.5;
}
#endif
return 0;
}
#endif /* OS_MAC */
-41
View File
@@ -1,41 +0,0 @@
/*
** 2004 May 22
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
******************************************************************************
**
** This header file defines OS-specific features of classic Mac.
** OS X uses the os_unix.h file, not this one.
*/
#ifndef _SQLITE_OS_MAC_H_
#define _SQLITE_OS_MAC_H_
#include <unistd.h>
#include <Files.h>
#define SQLITE_TEMPNAME_SIZE _MAX_PATH
#define SQLITE_MIN_SLEEP_MS 17
/*
** The OsFile structure is a operating-system independing representation
** of an open file handle. It is defined differently for each architecture.
**
** This is the definition for class Mac.
*/
typedef struct OsFile OsFile;
struct OsFile {
SInt16 refNum; /* Data fork/file reference number */
SInt16 refNumRF; /* Resource fork reference number (for locking) */
int locked; /* 0: unlocked, <0: write lock, >0: read lock */
int delOnClose; /* True if file is to be deleted on close */
char *pathToDel; /* Name of file to delete on close */
};
#endif /* _SQLITE_OS_MAC_H_ */
-461
View File
@@ -1,461 +0,0 @@
/*
** 2004 May 22
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
******************************************************************************
**
** This file contains code that is specific to Unix systems. It is used
** for testing SQLite only.
*/
#if OS_TEST /* This file is used for the test backend only */
#include "sqliteInt.h"
#include "os.h" /* Must be first to enable large file support */
#define sqlite3OsOpenReadWrite sqlite3RealOpenReadWrite
#define sqlite3OsOpenExclusive sqlite3RealOpenExclusive
#define sqlite3OsOpenReadOnly sqlite3RealOpenReadOnly
#define sqlite3OsOpenDirectory sqlite3RealOpenDirectory
#define sqlite3OsClose sqlite3RealClose
#define sqlite3OsRead sqlite3RealRead
#define sqlite3OsWrite sqlite3RealWrite
#define sqlite3OsSeek sqlite3RealSeek
#define sqlite3OsSync sqlite3RealSync
#define sqlite3OsTruncate sqlite3RealTruncate
#define sqlite3OsFileSize sqlite3RealFileSize
#define sqlite3OsLock sqlite3RealLock
#define sqlite3OsUnlock sqlite3RealUnlock
#define sqlite3OsCheckReservedLock sqlite3RealCheckReservedLock
#define OsFile OsRealFile
#define OS_UNIX 1
#include "os_unix.c"
#undef OS_UNIX
#undef OsFile
#undef sqlite3OsOpenReadWrite
#undef sqlite3OsOpenExclusive
#undef sqlite3OsOpenReadOnly
#undef sqlite3OsOpenDirectory
#undef sqlite3OsClose
#undef sqlite3OsRead
#undef sqlite3OsWrite
#undef sqlite3OsSeek
#undef sqlite3OsSync
#undef sqlite3OsTruncate
#undef sqlite3OsFileSize
#undef sqlite3OsLock
#undef sqlite3OsUnlock
#undef sqlite3OsCheckReservedLock
#define BLOCKSIZE 512
#define BLOCK_OFFSET(x) ((x) * BLOCKSIZE)
/*
** The following variables control when a simulated crash occurs.
**
** If iCrashDelay is non-zero, then zCrashFile contains (full path) name of
** a file that SQLite will call sqlite3OsSync() on. Each time this happens
** iCrashDelay is decremented. If iCrashDelay is zero after being
** decremented, a "crash" occurs during the sync() operation.
**
** In other words, a crash occurs the iCrashDelay'th time zCrashFile is
** synced.
*/
static int iCrashDelay = 0;
char zCrashFile[256];
/*
** Set the value of the two crash parameters.
*/
void sqlite3SetCrashParams(int iDelay, char const *zFile){
sqlite3OsEnterMutex();
assert( strlen(zFile)<256 );
strcpy(zCrashFile, zFile);
iCrashDelay = iDelay;
sqlite3OsLeaveMutex();
}
/*
** File zPath is being sync()ed. Return non-zero if this should
** cause a crash.
*/
static int crashRequired(char const *zPath){
int r;
int n;
sqlite3OsEnterMutex();
n = strlen(zCrashFile);
if( zCrashFile[n-1]=='*' ){
n--;
}else if( strlen(zPath)>n ){
n = strlen(zPath);
}
r = 0;
if( iCrashDelay>0 && strncmp(zPath, zCrashFile, n)==0 ){
iCrashDelay--;
if( iCrashDelay<=0 ){
r = 1;
}
}
sqlite3OsLeaveMutex();
return r;
}
static OsTestFile *pAllFiles = 0;
/*
** Initialise the os_test.c specific fields of pFile.
*/
static void initFile(OsFile *id, char const *zName){
OsTestFile *pFile = (OsTestFile *)
sqliteMalloc(sizeof(OsTestFile) + strlen(zName)+1);
pFile->nMaxWrite = 0;
pFile->nBlk = 0;
pFile->apBlk = 0;
pFile->zName = (char *)(&pFile[1]);
strcpy(pFile->zName, zName);
*id = pFile;
pFile->pNext = pAllFiles;
pAllFiles = pFile;
}
/*
** Undo the work done by initFile. Delete the OsTestFile structure
** and unlink the structure from the pAllFiles list.
*/
static void closeFile(OsFile *id){
OsTestFile *pFile = *id;
if( pFile==pAllFiles ){
pAllFiles = pFile->pNext;
}else{
OsTestFile *p;
for(p=pAllFiles; p->pNext!=pFile; p=p->pNext ){
assert( p );
}
p->pNext = pFile->pNext;
}
sqliteFree(pFile);
*id = 0;
}
/*
** Return the current seek offset from the start of the file. This
** is unix-only code.
*/
static i64 osTell(OsTestFile *pFile){
return lseek(pFile->fd.h, 0, SEEK_CUR);
}
/*
** Load block 'blk' into the cache of pFile.
*/
static int cacheBlock(OsTestFile *pFile, int blk){
if( blk>=pFile->nBlk ){
int n = ((pFile->nBlk * 2) + 100 + blk);
/* if( pFile->nBlk==0 ){ printf("DIRTY %s\n", pFile->zName); } */
pFile->apBlk = (u8 **)sqliteRealloc(pFile->apBlk, n * sizeof(u8*));
if( !pFile->apBlk ) return SQLITE_NOMEM;
memset(&pFile->apBlk[pFile->nBlk], 0, (n - pFile->nBlk)*sizeof(u8*));
pFile->nBlk = n;
}
if( !pFile->apBlk[blk] ){
i64 filesize;
int rc;
u8 *p = sqliteMalloc(BLOCKSIZE);
if( !p ) return SQLITE_NOMEM;
pFile->apBlk[blk] = p;
rc = sqlite3RealFileSize(&pFile->fd, &filesize);
if( rc!=SQLITE_OK ) return rc;
if( BLOCK_OFFSET(blk)<filesize ){
int len = BLOCKSIZE;
rc = sqlite3RealSeek(&pFile->fd, blk*BLOCKSIZE);
if( BLOCK_OFFSET(blk+1)>filesize ){
len = filesize - BLOCK_OFFSET(blk);
}
if( rc!=SQLITE_OK ) return rc;
rc = sqlite3RealRead(&pFile->fd, p, len);
if( rc!=SQLITE_OK ) return rc;
}
}
return SQLITE_OK;
}
/* #define TRACE_WRITECACHE */
/*
** Write the cache of pFile to disk. If crash is non-zero, randomly
** skip blocks when writing. The cache is deleted before returning.
*/
static int writeCache2(OsTestFile *pFile, int crash){
int i;
int nMax = pFile->nMaxWrite;
i64 offset;
int rc = SQLITE_OK;
offset = osTell(pFile);
for(i=0; i<pFile->nBlk; i++){
u8 *p = pFile->apBlk[i];
if( p ){
int skip = 0;
int trash = 0;
if( crash ){
char random;
sqlite3Randomness(1, &random);
if( random & 0x01 ){
if( random & 0x02 ){
trash = 1;
#ifdef TRACE_WRITECACHE
printf("Trashing block %d of %s\n", i, pFile->zName);
#endif
}else{
skip = 1;
#ifdef TRACE_WRITECACHE
printf("Skiping block %d of %s\n", i, pFile->zName);
#endif
}
}else{
#ifdef TRACE_WRITECACHE
printf("Writing block %d of %s\n", i, pFile->zName);
#endif
}
}
if( rc==SQLITE_OK ){
rc = sqlite3RealSeek(&pFile->fd, BLOCK_OFFSET(i));
}
if( rc==SQLITE_OK && !skip ){
int len = BLOCKSIZE;
if( BLOCK_OFFSET(i+1)>nMax ){
len = nMax-BLOCK_OFFSET(i);
}
if( trash ){
sqlite3Randomness(len, p);
}
rc = sqlite3RealWrite(&pFile->fd, p, len);
}
sqliteFree(p);
}
}
sqliteFree(pFile->apBlk);
pFile->nBlk = 0;
pFile->apBlk = 0;
pFile->nMaxWrite = 0;
if( rc==SQLITE_OK ){
rc = sqlite3RealSeek(&pFile->fd, offset);
}
return rc;
}
/*
** Write the cache to disk.
*/
static int writeCache(OsTestFile *pFile){
if( pFile->apBlk ){
int c = crashRequired(pFile->zName);
if( c ){
OsTestFile *p;
#ifdef TRACE_WRITECACHE
printf("\nCrash during sync of %s\n", pFile->zName);
#endif
for(p=pAllFiles; p; p=p->pNext){
writeCache2(p, 1);
}
exit(-1);
}else{
return writeCache2(pFile, 0);
}
}
return SQLITE_OK;
}
/*
** Close the file.
*/
int sqlite3OsClose(OsFile *id){
if( !(*id) ) return SQLITE_OK;
if( (*id)->fd.isOpen ){
/* printf("CLOSE %s (%d blocks)\n", (*id)->zName, (*id)->nBlk); */
writeCache(*id);
sqlite3RealClose(&(*id)->fd);
}
closeFile(id);
return SQLITE_OK;
}
int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
i64 offset; /* The current offset from the start of the file */
i64 end; /* The byte just past the last byte read */
int blk; /* Block number the read starts on */
int i;
u8 *zCsr;
int rc = SQLITE_OK;
OsTestFile *pFile = *id;
offset = osTell(pFile);
end = offset+amt;
blk = (offset/BLOCKSIZE);
zCsr = (u8 *)pBuf;
for(i=blk; i*BLOCKSIZE<end; i++){
int off = 0;
int len = 0;
if( BLOCK_OFFSET(i) < offset ){
off = offset-BLOCK_OFFSET(i);
}
len = BLOCKSIZE - off;
if( BLOCK_OFFSET(i+1) > end ){
len = len - (BLOCK_OFFSET(i+1)-end);
}
if( i<pFile->nBlk && pFile->apBlk[i]){
u8 *pBlk = pFile->apBlk[i];
memcpy(zCsr, &pBlk[off], len);
}else{
rc = sqlite3RealSeek(&pFile->fd, BLOCK_OFFSET(i) + off);
if( rc!=SQLITE_OK ) return rc;
rc = sqlite3RealRead(&pFile->fd, zCsr, len);
if( rc!=SQLITE_OK ) return rc;
}
zCsr += len;
}
assert( zCsr==&((u8 *)pBuf)[amt] );
rc = sqlite3RealSeek(&pFile->fd, end);
return rc;
}
int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
i64 offset; /* The current offset from the start of the file */
i64 end; /* The byte just past the last byte written */
int blk; /* Block number the write starts on */
int i;
const u8 *zCsr;
int rc = SQLITE_OK;
OsTestFile *pFile = *id;
offset = osTell(pFile);
end = offset+amt;
blk = (offset/BLOCKSIZE);
zCsr = (u8 *)pBuf;
for(i=blk; i*BLOCKSIZE<end; i++){
u8 *pBlk;
int off = 0;
int len = 0;
/* Make sure the block is in the cache */
rc = cacheBlock(pFile, i);
if( rc!=SQLITE_OK ) return rc;
/* Write into the cache */
pBlk = pFile->apBlk[i];
assert( pBlk );
if( BLOCK_OFFSET(i) < offset ){
off = offset-BLOCK_OFFSET(i);
}
len = BLOCKSIZE - off;
if( BLOCK_OFFSET(i+1) > end ){
len = len - (BLOCK_OFFSET(i+1)-end);
}
memcpy(&pBlk[off], zCsr, len);
zCsr += len;
}
if( pFile->nMaxWrite<end ){
pFile->nMaxWrite = end;
}
assert( zCsr==&((u8 *)pBuf)[amt] );
rc = sqlite3RealSeek(&pFile->fd, end);
return rc;
}
/*
** Sync the file. First flush the write-cache to disk, then call the
** real sync() function.
*/
int sqlite3OsSync(OsFile *id){
int rc;
/* printf("SYNC %s (%d blocks)\n", (*id)->zName, (*id)->nBlk); */
rc = writeCache(*id);
if( rc!=SQLITE_OK ) return rc;
rc = sqlite3RealSync(&(*id)->fd);
return rc;
}
/*
** Truncate the file. Set the internal OsFile.nMaxWrite variable to the new
** file size to ensure that nothing in the write-cache past this point
** is written to disk.
*/
int sqlite3OsTruncate(OsFile *id, i64 nByte){
(*id)->nMaxWrite = nByte;
return sqlite3RealTruncate(&(*id)->fd, nByte);
}
/*
** Return the size of the file. If the cache contains a write that extended
** the file, then return this size instead of the on-disk size.
*/
int sqlite3OsFileSize(OsFile *id, i64 *pSize){
int rc = sqlite3RealFileSize(&(*id)->fd, pSize);
if( rc==SQLITE_OK && pSize && *pSize<(*id)->nMaxWrite ){
*pSize = (*id)->nMaxWrite;
}
return rc;
}
/*
** The three functions used to open files. All that is required is to
** initialise the os_test.c specific fields and then call the corresponding
** os_unix.c function to really open the file.
*/
int sqlite3OsOpenReadWrite(const char *zFilename, OsFile *id, int *pReadonly){
initFile(id, zFilename);
return sqlite3RealOpenReadWrite(zFilename, &(*id)->fd, pReadonly);
}
int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
initFile(id, zFilename);
return sqlite3RealOpenExclusive(zFilename, &(*id)->fd, delFlag);
}
int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
initFile(id, zFilename);
return sqlite3RealOpenReadOnly(zFilename, &(*id)->fd);
}
/*
** These six function calls are passed straight through to the os_unix.c
** backend.
*/
int sqlite3OsSeek(OsFile *id, i64 offset){
return sqlite3RealSeek(&(*id)->fd, offset);
}
int sqlite3OsCheckReservedLock(OsFile *id){
return sqlite3RealCheckReservedLock(&(*id)->fd);
}
int sqlite3OsLock(OsFile *id, int locktype){
return sqlite3RealLock(&(*id)->fd, locktype);
}
int sqlite3OsUnlock(OsFile *id, int locktype){
return sqlite3RealUnlock(&(*id)->fd, locktype);
}
int sqlite3OsOpenDirectory(const char *zDirname, OsFile *id){
return sqlite3RealOpenDirectory(zDirname, &(*id)->fd);
}
#endif /* OS_TEST */
-39
View File
@@ -1,39 +0,0 @@
/*
** 2004 May 22
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
******************************************************************************
**
*/
#ifndef _SQLITE_OS_TEST_H_
#define _SQLITE_OS_TEST_H_
#define OsFile OsRealFile
#define OS_UNIX 1
#include "os_unix.h"
#undef OS_UNIX
#undef OsFile
/* Include sqliteInt.h now to get the type u8. */
#include "sqliteInt.h"
typedef struct OsTestFile* OsFile;
typedef struct OsTestFile OsTestFile;
struct OsTestFile {
u8 **apBlk; /* Array of blocks that have been written to. */
int nBlk; /* Size of apBlock. */
int nMaxWrite; /* Largest offset written to. */
char *zName; /* File name */
OsRealFile fd;
OsTestFile *pNext;
};
void sqlite3SetCrashParams(int iDelay, char const *zFile);
#endif /* _SQLITE_OS_UNIX_H_ */
File diff suppressed because it is too large. Load diff
-89
View File
@@ -1,89 +0,0 @@
/*
** 2004 May 22
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
******************************************************************************
**
** This header file defined OS-specific features for Unix.
*/
#ifndef _SQLITE_OS_UNIX_H_
#define _SQLITE_OS_UNIX_H_
/*
** Helpful hint: To get this to compile on HP/UX, add -D_INCLUDE_POSIX_SOURCE
** to the compiler command line.
*/
/*
** These #defines should enable >2GB file support on Posix if the
** underlying operating system supports it. If the OS lacks
** large file support, or if the OS is windows, these should be no-ops.
**
** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch
** on the compiler command line. This is necessary if you are compiling
** on a recent machine (ex: RedHat 7.2) but you want your code to work
** on an older machine (ex: RedHat 6.0). If you compile on RedHat 7.2
** without this option, LFS is enable. But LFS does not exist in the kernel
** in RedHat 6.0, so the code won't work. Hence, for maximum binary
** portability you should omit LFS.
**
** Similar is true for MacOS. LFS is only supported on MacOS 9 and later.
*/
#ifndef SQLITE_DISABLE_LFS
# define _LARGE_FILE 1
# ifndef _FILE_OFFSET_BITS
# define _FILE_OFFSET_BITS 64
# endif
# define _LARGEFILE_SOURCE 1
#endif
/*
** standard include files.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
/*
** The OsFile structure is a operating-system independing representation
** of an open file handle. It is defined differently for each architecture.
**
** This is the definition for Unix.
**
** OsFile.locktype takes one of the values SHARED_LOCK, RESERVED_LOCK,
** PENDING_LOCK or EXCLUSIVE_LOCK.
*/
typedef struct OsFile OsFile;
struct OsFile {
struct Pager *pPager; /* The pager that owns this OsFile. Might be 0 */
struct openCnt *pOpen; /* Info about all open fd's on this inode */
struct lockInfo *pLock; /* Info about locks on this inode */
int h; /* The file descriptor */
unsigned char locktype; /* The type of lock held on this fd */
unsigned char isOpen; /* True if needs to be closed */
int dirfd; /* File descriptor for the directory */
};
/*
** Maximum number of characters in a temporary file name
*/
#define SQLITE_TEMPNAME_SIZE 200
/*
** Minimum interval supported by sqlite3OsSleep().
*/
#if defined(HAVE_USLEEP) && HAVE_USLEEP
# define SQLITE_MIN_SLEEP_MS 1
#else
# define SQLITE_MIN_SLEEP_MS 1000
#endif
#endif /* _SQLITE_OS_UNIX_H_ */
-747
View File
@@ -1,747 +0,0 @@
/*
** 2004 May 22
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
******************************************************************************
**
** This file contains code that is specific to windows.
*/
#include "sqliteInt.h"
#include "os.h"
#if OS_WIN /* This file is used for windows only */
#include <winbase.h>
/*
** Macros used to determine whether or not to use threads.
*/
#if defined(THREADSAFE) && THREADSAFE
# define SQLITE_W32_THREADS 1
#endif
/*
** Include code that is common to all os_*.c files
*/
#include "os_common.h"
/*
** Delete the named file
*/
int sqlite3OsDelete(const char *zFilename){
DeleteFileA(zFilename);
TRACE2("DELETE \"%s\"\n", zFilename);
return SQLITE_OK;
}
/*
** Return TRUE if the named file exists.
*/
int sqlite3OsFileExists(const char *zFilename){
return GetFileAttributesA(zFilename) != 0xffffffff;
}
/*
** Attempt to open a file for both reading and writing. If that
** fails, try opening it read-only. If the file does not exist,
** try to create it.
**
** On success, a handle for the open file is written to *id
** and *pReadonly is set to 0 if the file was opened for reading and
** writing or 1 if the file was opened read-only. The function returns
** SQLITE_OK.
**
** On failure, the function returns SQLITE_CANTOPEN and leaves
** *id and *pReadonly unchanged.
*/
int sqlite3OsOpenReadWrite(
const char *zFilename,
OsFile *id,
int *pReadonly
){
HANDLE h;
assert( !id->isOpen );
h = CreateFileA(zFilename,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
NULL
);
if( h==INVALID_HANDLE_VALUE ){
h = CreateFileA(zFilename,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
NULL
);
if( h==INVALID_HANDLE_VALUE ){
return SQLITE_CANTOPEN;
}
*pReadonly = 1;
}else{
*pReadonly = 0;
}
id->h = h;
id->locktype = NO_LOCK;
id->sharedLockByte = 0;
id->isOpen = 1;
OpenCounter(+1);
TRACE3("OPEN R/W %d \"%s\"\n", h, zFilename);
return SQLITE_OK;
}
/*
** Attempt to open a new file for exclusive access by this process.
** The file will be opened for both reading and writing. To avoid
** a potential security problem, we do not allow the file to have
** previously existed. Nor do we allow the file to be a symbolic
** link.
**
** If delFlag is true, then make arrangements to automatically delete
** the file when it is closed.
**
** On success, write the file handle into *id and return SQLITE_OK.
**
** On failure, return SQLITE_CANTOPEN.
*/
int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
HANDLE h;
int fileflags;
assert( !id->isOpen );
if( delFlag ){
fileflags = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_RANDOM_ACCESS
| FILE_FLAG_DELETE_ON_CLOSE;
}else{
fileflags = FILE_FLAG_RANDOM_ACCESS;
}
h = CreateFileA(zFilename,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
fileflags,
NULL
);
if( h==INVALID_HANDLE_VALUE ){
return SQLITE_CANTOPEN;
}
id->h = h;
id->locktype = NO_LOCK;
id->sharedLockByte = 0;
id->isOpen = 1;
OpenCounter(+1);
TRACE3("OPEN EX %d \"%s\"\n", h, zFilename);
return SQLITE_OK;
}
/*
** Attempt to open a new file for read-only access.
**
** On success, write the file handle into *id and return SQLITE_OK.
**
** On failure, return SQLITE_CANTOPEN.
*/
int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
HANDLE h;
assert( !id->isOpen );
h = CreateFileA(zFilename,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
NULL
);
if( h==INVALID_HANDLE_VALUE ){
return SQLITE_CANTOPEN;
}
id->h = h;
id->locktype = NO_LOCK;
id->sharedLockByte = 0;
id->isOpen = 1;
OpenCounter(+1);
TRACE3("OPEN RO %d \"%s\"\n", h, zFilename);
return SQLITE_OK;
}
/*
** Attempt to open a file descriptor for the directory that contains a
** file. This file descriptor can be used to fsync() the directory
** in order to make sure the creation of a new file is actually written
** to disk.
**
** This routine is only meaningful for Unix. It is a no-op under
** windows since windows does not support hard links.
**
** On success, a handle for a previously open file is at *id is
** updated with the new directory file descriptor and SQLITE_OK is
** returned.
**
** On failure, the function returns SQLITE_CANTOPEN and leaves
** *id unchanged.
*/
int sqlite3OsOpenDirectory(
const char *zDirname,
OsFile *id
){
return SQLITE_OK;
}
/*
** If the following global variable points to a string which is the
** name of a directory, then that directory will be used to store
** temporary files.
*/
const char *sqlite3_temp_directory = 0;
/*
** Create a temporary file name in zBuf. zBuf must be big enough to
** hold at least SQLITE_TEMPNAME_SIZE characters.
*/
int sqlite3OsTempFileName(char *zBuf){
static char zChars[] =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
int i, j;
char zTempPath[SQLITE_TEMPNAME_SIZE];
if( sqlite3_temp_directory ){
strncpy(zTempPath, sqlite3_temp_directory, SQLITE_TEMPNAME_SIZE-30);
zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0;
}else{
GetTempPathA(SQLITE_TEMPNAME_SIZE-30, zTempPath);
}
for(i=strlen(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){}
zTempPath[i] = 0;
for(;;){
sprintf(zBuf, "%s\\"TEMP_FILE_PREFIX, zTempPath);
j = strlen(zBuf);
sqlite3Randomness(15, &zBuf[j]);
for(i=0; i<15; i++, j++){
zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
}
zBuf[j] = 0;
if( !sqlite3OsFileExists(zBuf) ) break;
}
TRACE2("TEMP FILENAME: %s\n", zBuf);
return SQLITE_OK;
}
/*
** Close a file.
*/
int sqlite3OsClose(OsFile *id){
if( id->isOpen ){
TRACE2("CLOSE %d\n", id->h);
CloseHandle(id->h);
OpenCounter(-1);
id->isOpen = 0;
}
return SQLITE_OK;
}
/*
** Read data from a file into a buffer. Return SQLITE_OK if all
** bytes were read successfully and SQLITE_IOERR if anything goes
** wrong.
*/
int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
DWORD got;
assert( id->isOpen );
SimulateIOError(SQLITE_IOERR);
TRACE3("READ %d lock=%d\n", id->h, id->locktype);
if( !ReadFile(id->h, pBuf, amt, &got, 0) ){
got = 0;
}
if( got==(DWORD)amt ){
return SQLITE_OK;
}else{
return SQLITE_IOERR;
}
}
/*
** Write data from a buffer into a file. Return SQLITE_OK on success
** or some other error code on failure.
*/
int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
int rc;
DWORD wrote;
assert( id->isOpen );
SimulateIOError(SQLITE_IOERR);
SimulateDiskfullError;
TRACE3("WRITE %d lock=%d\n", id->h, id->locktype);
while( amt>0 && (rc = WriteFile(id->h, pBuf, amt, &wrote, 0))!=0 && wrote>0 ){
amt -= wrote;
pBuf = &((char*)pBuf)[wrote];
}
if( !rc || amt>(int)wrote ){
return SQLITE_FULL;
}
return SQLITE_OK;
}
/*
** Move the read/write pointer in a file.
*/
int sqlite3OsSeek(OsFile *id, i64 offset){
LONG upperBits = offset>>32;
LONG lowerBits = offset & 0xffffffff;
DWORD rc;
assert( id->isOpen );
SEEK(offset/1024 + 1);
rc = SetFilePointer(id->h, lowerBits, &upperBits, FILE_BEGIN);
TRACE3("SEEK %d %lld\n", id->h, offset);
return SQLITE_OK;
}
/*
** Make sure all writes to a particular file are committed to disk.
*/
int sqlite3OsSync(OsFile *id){
assert( id->isOpen );
TRACE3("SYNC %d lock=%d\n", id->h, id->locktype);
if( FlushFileBuffers(id->h) ){
return SQLITE_OK;
}else{
return SQLITE_IOERR;
}
}
/*
** Sync the directory zDirname. This is a no-op on operating systems other
** than UNIX.
*/
int sqlite3OsSyncDirectory(const char *zDirname){
SimulateIOError(SQLITE_IOERR);
return SQLITE_OK;
}
/*
** Truncate an open file to a specified size
*/
int sqlite3OsTruncate(OsFile *id, i64 nByte){
LONG upperBits = nByte>>32;
assert( id->isOpen );
TRACE3("TRUNCATE %d %lld\n", id->h, nByte);
SimulateIOError(SQLITE_IOERR);
SetFilePointer(id->h, nByte, &upperBits, FILE_BEGIN);
SetEndOfFile(id->h);
return SQLITE_OK;
}
/*
** Determine the current size of a file in bytes
*/
int sqlite3OsFileSize(OsFile *id, i64 *pSize){
DWORD upperBits, lowerBits;
assert( id->isOpen );
SimulateIOError(SQLITE_IOERR);
lowerBits = GetFileSize(id->h, &upperBits);
*pSize = (((i64)upperBits)<<32) + lowerBits;
return SQLITE_OK;
}
/*
** Return true (non-zero) if we are running under WinNT, Win2K or WinXP.
** Return false (zero) for Win95, Win98, or WinME.
**
** Here is an interesting observation: Win95, Win98, and WinME lack
** the LockFileEx() API. But we can still statically link against that
** API as long as we don't call it win running Win95/98/ME. A call to
** this routine is used to determine if the host is Win95/98/ME or
** WinNT/2K/XP so that we will know whether or not we can safely call
** the LockFileEx() API.
*/
static int isNT(void){
static int osType = 0; /* 0=unknown 1=win95 2=winNT */
if( osType==0 ){
OSVERSIONINFO sInfo;
sInfo.dwOSVersionInfoSize = sizeof(sInfo);
GetVersionEx(&sInfo);
osType = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
}
return osType==2;
}
/*
** Acquire a reader lock.
** Different API routines are called depending on whether or not this
** is Win95 or WinNT.
*/
static int getReadLock(OsFile *id){
int res;
if( isNT() ){
OVERLAPPED ovlp;
ovlp.Offset = SHARED_FIRST;
ovlp.OffsetHigh = 0;
ovlp.hEvent = 0;
res = LockFileEx(id->h, LOCKFILE_FAIL_IMMEDIATELY, 0, SHARED_SIZE,0,&ovlp);
}else{
int lk;
sqlite3Randomness(sizeof(lk), &lk);
id->sharedLockByte = (lk & 0x7fffffff)%(SHARED_SIZE - 1);
res = LockFile(id->h, SHARED_FIRST+id->sharedLockByte, 0, 1, 0);
}
return res;
}
/*
** Undo a readlock
*/
static int unlockReadLock(OsFile *id){
int res;
if( isNT() ){
res = UnlockFile(id->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
}else{
res = UnlockFile(id->h, SHARED_FIRST + id->sharedLockByte, 0, 1, 0);
}
return res;
}
/*
** Lock the file with the lock specified by parameter locktype - one
** of the following:
**
** (1) SHARED_LOCK
** (2) RESERVED_LOCK
** (3) PENDING_LOCK
** (4) EXCLUSIVE_LOCK
**
** Sometimes when requesting one lock state, additional lock states
** are inserted in between. The locking might fail on one of the later
** transitions leaving the lock state different from what it started but
** still short of its goal. The following chart shows the allowed
** transitions and the inserted intermediate states:
**
** UNLOCKED -> SHARED
** SHARED -> RESERVED
** SHARED -> (PENDING) -> EXCLUSIVE
** RESERVED -> (PENDING) -> EXCLUSIVE
** PENDING -> EXCLUSIVE
**
** This routine will only increase a lock. The sqlite3OsUnlock() routine
** erases all locks at once and returns us immediately to locking level 0.
** It is not possible to lower the locking level one step at a time. You
** must go straight to locking level 0.
*/
int sqlite3OsLock(OsFile *id, int locktype){
int rc = SQLITE_OK; /* Return code from subroutines */
int res = 1; /* Result of a windows lock call */
int newLocktype; /* Set id->locktype to this value before exiting */
int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */
assert( id->isOpen );
TRACE5("LOCK %d %d was %d(%d)\n",
id->h, locktype, id->locktype, id->sharedLockByte);
/* If there is already a lock of this type or more restrictive on the
** OsFile, do nothing. Don't use the end_lock: exit path, as
** sqlite3OsEnterMutex() hasn't been called yet.
*/
if( id->locktype>=locktype ){
return SQLITE_OK;
}
/* Make sure the locking sequence is correct
*/
assert( id->locktype!=NO_LOCK || locktype==SHARED_LOCK );
assert( locktype!=PENDING_LOCK );
assert( locktype!=RESERVED_LOCK || id->locktype==SHARED_LOCK );
/* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or
** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of
** the PENDING_LOCK byte is temporary.
*/
newLocktype = id->locktype;
if( id->locktype==NO_LOCK
|| (locktype==EXCLUSIVE_LOCK && id->locktype==RESERVED_LOCK)
){
int cnt = 3;
while( cnt-->0 && (res = LockFile(id->h, PENDING_BYTE, 0, 1, 0))==0 ){
/* Try 3 times to get the pending lock. The pending lock might be
** held by another reader process who will release it momentarily.
*/
TRACE2("could not get a PENDING lock. cnt=%d\n", cnt);
Sleep(1);
}
gotPendingLock = res;
}
/* Acquire a shared lock
*/
if( locktype==SHARED_LOCK && res ){
assert( id->locktype==NO_LOCK );
res = getReadLock(id);
if( res ){
newLocktype = SHARED_LOCK;
}
}
/* Acquire a RESERVED lock
*/
if( locktype==RESERVED_LOCK && res ){
assert( id->locktype==SHARED_LOCK );
res = LockFile(id->h, RESERVED_BYTE, 0, 1, 0);
if( res ){
newLocktype = RESERVED_LOCK;
}
}
/* Acquire a PENDING lock
*/
if( locktype==EXCLUSIVE_LOCK && res ){
newLocktype = PENDING_LOCK;
gotPendingLock = 0;
}
/* Acquire an EXCLUSIVE lock
*/
if( locktype==EXCLUSIVE_LOCK && res ){
assert( id->locktype>=SHARED_LOCK );
res = unlockReadLock(id);
TRACE2("unreadlock = %d\n", res);
res = LockFile(id->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
if( res ){
newLocktype = EXCLUSIVE_LOCK;
}else{
TRACE2("error-code = %d\n", GetLastError());
}
}
/* If we are holding a PENDING lock that ought to be released, then
** release it now.
*/
if( gotPendingLock && locktype==SHARED_LOCK ){
UnlockFile(id->h, PENDING_BYTE, 0, 1, 0);
}
/* Update the state of the lock has held in the file descriptor then
** return the appropriate result code.
*/
if( res ){
rc = SQLITE_OK;
}else{
TRACE4("LOCK FAILED %d trying for %d but got %d\n", id->h,
locktype, newLocktype);
rc = SQLITE_BUSY;
}
id->locktype = newLocktype;
return rc;
}
/*
** This routine checks if there is a RESERVED lock held on the specified
** file by this or any other process. If such a lock is held, return
** non-zero, otherwise zero.
*/
int sqlite3OsCheckReservedLock(OsFile *id){
int rc;
assert( id->isOpen );
if( id->locktype>=RESERVED_LOCK ){
rc = 1;
TRACE3("TEST WR-LOCK %d %d (local)\n", id->h, rc);
}else{
rc = LockFile(id->h, RESERVED_BYTE, 0, 1, 0);
if( rc ){
UnlockFile(id->h, RESERVED_BYTE, 0, 1, 0);
}
rc = !rc;
TRACE3("TEST WR-LOCK %d %d (remote)\n", id->h, rc);
}
return rc;
}
/*
** Lower the locking level on file descriptor id to locktype. locktype
** must be either NO_LOCK or SHARED_LOCK.
**
** If the locking level of the file descriptor is already at or below
** the requested locking level, this routine is a no-op.
**
** It is not possible for this routine to fail if the second argument
** is NO_LOCK. If the second argument is SHARED_LOCK then this routine
** might return SQLITE_IOERR;
*/
int sqlite3OsUnlock(OsFile *id, int locktype){
int type;
int rc = SQLITE_OK;
assert( id->isOpen );
assert( locktype<=SHARED_LOCK );
TRACE5("UNLOCK %d to %d was %d(%d)\n", id->h, locktype,
id->locktype, id->sharedLockByte);
type = id->locktype;
if( type>=EXCLUSIVE_LOCK ){
UnlockFile(id->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
if( locktype==SHARED_LOCK && !getReadLock(id) ){
/* This should never happen. We should always be able to
** reacquire the read lock */
rc = SQLITE_IOERR;
}
}
if( type>=RESERVED_LOCK ){
UnlockFile(id->h, RESERVED_BYTE, 0, 1, 0);
}
if( locktype==NO_LOCK && type>=SHARED_LOCK ){
unlockReadLock(id);
}
if( type>=PENDING_LOCK ){
UnlockFile(id->h, PENDING_BYTE, 0, 1, 0);
}
id->locktype = locktype;
return rc;
}
/*
** Get information to seed the random number generator. The seed
** is written into the buffer zBuf[256]. The calling function must
** supply a sufficiently large buffer.
*/
int sqlite3OsRandomSeed(char *zBuf){
/* We have to initialize zBuf to prevent valgrind from reporting
** errors. The reports issued by valgrind are incorrect - we would
** prefer that the randomness be increased by making use of the
** uninitialized space in zBuf - but valgrind errors tend to worry
** some users. Rather than argue, it seems easier just to initialize
** the whole array and silence valgrind, even if that means less randomness
** in the random seed.
**
** When testing, initializing zBuf[] to zero is all we do. That means
** that we always use the same random number sequence.* This makes the
** tests repeatable.
*/
memset(zBuf, 0, 256);
GetSystemTime((LPSYSTEMTIME)zBuf);
return SQLITE_OK;
}
/*
** Sleep for a little while. Return the amount of time slept.
*/
int sqlite3OsSleep(int ms){
Sleep(ms);
return ms;
}
/*
** Static variables used for thread synchronization
*/
static int inMutex = 0;
#ifdef SQLITE_W32_THREADS
static CRITICAL_SECTION cs;
#endif
/*
** The following pair of routine implement mutual exclusion for
** multi-threaded processes. Only a single thread is allowed to
** executed code that is surrounded by EnterMutex() and LeaveMutex().
**
** SQLite uses only a single Mutex. There is not much critical
** code and what little there is executes quickly and without blocking.
*/
void sqlite3OsEnterMutex(){
#ifdef SQLITE_W32_THREADS
static int isInit = 0;
while( !isInit ){
static long lock = 0;
if( InterlockedIncrement(&lock)==1 ){
InitializeCriticalSection(&cs);
isInit = 1;
}else{
Sleep(1);
}
}
EnterCriticalSection(&cs);
#endif
assert( !inMutex );
inMutex = 1;
}
void sqlite3OsLeaveMutex(){
assert( inMutex );
inMutex = 0;
#ifdef SQLITE_W32_THREADS
LeaveCriticalSection(&cs);
#endif
}
/*
** Turn a relative pathname into a full pathname. Return a pointer
** to the full pathname stored in space obtained from sqliteMalloc().
** The calling function is responsible for freeing this space once it
** is no longer needed.
*/
char *sqlite3OsFullPathname(const char *zRelative){
char *zNotUsed;
char *zFull;
int nByte;
nByte = GetFullPathNameA(zRelative, 0, 0, &zNotUsed) + 1;
zFull = sqliteMalloc( nByte );
if( zFull==0 ) return 0;
GetFullPathNameA(zRelative, nByte, zFull, &zNotUsed);
return zFull;
}
/*
** The following variable, if set to a non-zero value, becomes the result
** returned from sqlite3OsCurrentTime(). This is used for testing.
*/
#ifdef SQLITE_TEST
int sqlite3_current_time = 0;
#endif
/*
** Find the current time (in Universal Coordinated Time). Write the
** current time and date as a Julian Day number into *prNow and
** return 0. Return 1 if the time and date cannot be found.
*/
int sqlite3OsCurrentTime(double *prNow){
FILETIME ft;
/* FILETIME structure is a 64-bit value representing the number of
100-nanosecond intervals since January 1, 1601 (= JD 2305813.5).
*/
double now;
GetSystemTimeAsFileTime( &ft );
now = ((double)ft.dwHighDateTime) * 4294967296.0;
*prNow = (now + ft.dwLowDateTime)/864000000000.0 + 2305813.5;
#ifdef SQLITE_TEST
if( sqlite3_current_time ){
*prNow = sqlite3_current_time/86400.0 + 2440587.5;
}
#endif
return 0;
}
/*
** Find the time that the file was last modified. Write the
** modification time and date as a Julian Day number into *prNow and
** return SQLITE_OK. Return SQLITE_ERROR if the modification
** time cannot be found.
*/
int sqlite3OsFileModTime(OsFile *id, double *prMTime){
int rc;
FILETIME ft;
/* FILETIME structure is a 64-bit value representing the number of
** 100-nanosecond intervals since January 1, 1601 (= JD 2305813.5).
*/
if( GetFileTime(id->h, 0, 0, &ft) ){
double t;
t = ((double)ft.dwHighDateTime) * 4294967296.0;
*prMTime = (t + ft.dwLowDateTime)/864000000000.0 + 2305813.5;
rc = SQLITE_OK;
}else{
rc = SQLITE_ERROR;
}
return rc;
}
#endif /* OS_WIN */
-40
View File
@@ -1,40 +0,0 @@
/*
** 2004 May 22
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
******************************************************************************
**
** This header file defines OS-specific features for Win32
*/
#ifndef _SQLITE_OS_WIN_H_
#define _SQLITE_OS_WIN_H_
#include <windows.h>
#include <winbase.h>
/*
** The OsFile structure is a operating-system independing representation
** of an open file handle. It is defined differently for each architecture.
**
** This is the definition for Win32.
*/
typedef struct OsFile OsFile;
struct OsFile {
HANDLE h; /* Handle for accessing the file */
unsigned char locktype; /* Type of lock currently held on this file */
unsigned char isOpen; /* True if needs to be closed */
short sharedLockByte; /* Randomly chosen byte used as a shared lock */
};
#define SQLITE_TEMPNAME_SIZE (MAX_PATH+50)
#define SQLITE_MIN_SLEEP_MS 1
#endif /* _SQLITE_OS_WIN_H_ */
File diff suppressed because it is too large. Load diff
-102
View File
@@ -1,102 +0,0 @@
/*
** 2001 September 15
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This header file defines the interface that the sqlite page cache
** subsystem. The page cache subsystem reads and writes a file a page
** at a time and provides a journal for rollback.
**
** @(#) $Id$
*/
/*
** The default size of a database page.
*/
#ifndef SQLITE_DEFAULT_PAGE_SIZE
# define SQLITE_DEFAULT_PAGE_SIZE 1024
#endif
/* Maximum page size. The upper bound on this value is 65536 (a limit
** imposed by the 2-byte size of cell array pointers.) The
** maximum page size determines the amount of stack space allocated
** by many of the routines in pager.c and btree.c On embedded architectures
** or any machine where memory and especially stack memory is limited,
** one may wish to chose a smaller value for the maximum page size.
*/
#ifndef SQLITE_MAX_PAGE_SIZE
# define SQLITE_MAX_PAGE_SIZE 8192
#endif
/*
** Maximum number of pages in one database.
*/
#define SQLITE_MAX_PAGE 1073741823
/*
** The type used to represent a page number. The first page in a file
** is called page 1. 0 is used to represent "not a page".
*/
typedef unsigned int Pgno;
/*
** Each open file is managed by a separate instance of the "Pager" structure.
*/
typedef struct Pager Pager;
/*
** See source code comments for a detailed description of the following
** routines:
*/
int sqlite3pager_open(Pager **ppPager, const char *zFilename,
int nExtra, int useJournal);
void sqlite3pager_set_busyhandler(Pager*, BusyHandler *pBusyHandler);
void sqlite3pager_set_destructor(Pager*, void(*)(void*,int));
void sqlite3pager_set_reiniter(Pager*, void(*)(void*,int));
void sqlite3pager_set_pagesize(Pager*, int);
void sqlite3pager_read_fileheader(Pager*, int, unsigned char*);
void sqlite3pager_set_cachesize(Pager*, int);
int sqlite3pager_close(Pager *pPager);
int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage);
void *sqlite3pager_lookup(Pager *pPager, Pgno pgno);
int sqlite3pager_ref(void*);
int sqlite3pager_unref(void*);
Pgno sqlite3pager_pagenumber(void*);
int sqlite3pager_write(void*);
int sqlite3pager_iswriteable(void*);
int sqlite3pager_overwrite(Pager *pPager, Pgno pgno, void*);
int sqlite3pager_pagecount(Pager*);
int sqlite3pager_truncate(Pager*,Pgno);
int sqlite3pager_begin(void*, int exFlag);
int sqlite3pager_commit(Pager*);
int sqlite3pager_sync(Pager*,const char *zMaster);
int sqlite3pager_rollback(Pager*);
int sqlite3pager_isreadonly(Pager*);
int sqlite3pager_stmt_begin(Pager*);
int sqlite3pager_stmt_commit(Pager*);
int sqlite3pager_stmt_rollback(Pager*);
void sqlite3pager_dont_rollback(void*);
void sqlite3pager_dont_write(Pager*, Pgno);
int *sqlite3pager_stats(Pager*);
void sqlite3pager_set_safety_level(Pager*,int);
const char *sqlite3pager_filename(Pager*);
const char *sqlite3pager_dirname(Pager*);
const char *sqlite3pager_journalname(Pager*);
int sqlite3pager_rename(Pager*, const char *zNewName);
void sqlite3pager_set_codec(Pager*,void(*)(void*,void*,Pgno,int),void*);
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
int sqlite3pager_lockstate(Pager*);
#endif
#ifdef SQLITE_TEST
void sqlite3pager_refdump(Pager*);
int pager3_refinfo_enable;
#endif
-898
View File
@@ -1,898 +0,0 @@
/*
** 2001 September 15
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains SQLite's grammar for SQL. Process this file
** using the lemon parser generator to generate C code that runs
** the parser. Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
** @(#) $Id$
*/
%token_prefix TK_
%token_type {Token}
%default_type {Token}
%extra_argument {Parse *pParse}
%syntax_error {
if( pParse->zErrMsg==0 ){
if( TOKEN.z[0] ){
sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
}else{
sqlite3ErrorMsg(pParse, "incomplete SQL statement");
}
}
}
%name sqlite3Parser
%include {
#include "sqliteInt.h"
#include "parse.h"
/*
** An instance of this structure holds information about the
** LIMIT clause of a SELECT statement.
*/
struct LimitVal {
int limit; /* The LIMIT value. -1 if there is no limit */
int offset; /* The OFFSET. 0 if there is none */
};
/*
** An instance of this structure is used to store the LIKE,
** GLOB, NOT LIKE, and NOT GLOB operators.
*/
struct LikeOp {
int opcode; /* Either TK_GLOB or TK_LIKE */
int not; /* True if the NOT keyword is present */
};
/*
** An instance of the following structure describes the event of a
** TRIGGER. "a" is the event type, one of TK_UPDATE, TK_INSERT,
** TK_DELETE, or TK_INSTEAD. If the event is of the form
**
** UPDATE ON (a,b,c)
**
** Then the "b" IdList records the list "a,b,c".
*/
struct TrigEvent { int a; IdList * b; };
/*
** An instance of this structure holds the ATTACH key and the key type.
*/
struct AttachKey { int type; Token key; };
} // end %include
// These are extra tokens used by the lexer but never seen by the
// parser. We put them in a rule so that the parser generator will
// add them to the parse.h output file.
//
%nonassoc END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION
COLUMN AGG_FUNCTION.
// Input is a single SQL command
input ::= cmdlist.
cmdlist ::= cmdlist ecmd.
cmdlist ::= ecmd.
ecmd ::= explain cmdx SEMI.
ecmd ::= SEMI.
cmdx ::= cmd. { sqlite3FinishCoding(pParse); }
explain ::= EXPLAIN. { sqlite3BeginParse(pParse, 1); }
explain ::= . { sqlite3BeginParse(pParse, 0); }
///////////////////// Begin and end transactions. ////////////////////////////
//
cmd ::= BEGIN transtype(Y) trans_opt. {sqlite3BeginTransaction(pParse, Y);}
trans_opt ::= .
trans_opt ::= TRANSACTION.
trans_opt ::= TRANSACTION nm.
%type transtype {int}
transtype(A) ::= . {A = TK_DEFERRED;}
transtype(A) ::= DEFERRED(X). {A = @X;}
transtype(A) ::= IMMEDIATE(X). {A = @X;}
transtype(A) ::= EXCLUSIVE(X). {A = @X;}
cmd ::= COMMIT trans_opt. {sqlite3CommitTransaction(pParse);}
cmd ::= END trans_opt. {sqlite3CommitTransaction(pParse);}
cmd ::= ROLLBACK trans_opt. {sqlite3RollbackTransaction(pParse);}
///////////////////// The CREATE TABLE statement ////////////////////////////
//
cmd ::= create_table create_table_args.
create_table ::= CREATE(X) temp(T) TABLE nm(Y) dbnm(Z). {
sqlite3StartTable(pParse,&X,&Y,&Z,T,0);
}
%type temp {int}
temp(A) ::= TEMP. {A = 1;}
temp(A) ::= . {A = 0;}
create_table_args ::= LP columnlist conslist_opt RP(X). {
sqlite3EndTable(pParse,&X,0);
}
create_table_args ::= AS select(S). {
sqlite3EndTable(pParse,0,S);
sqlite3SelectDelete(S);
}
columnlist ::= columnlist COMMA column.
columnlist ::= column.
// About the only information used for a column is the name of the
// column. The type is always just "text". But the code will accept
// an elaborate typename. Perhaps someday we'll do something with it.
//
column ::= columnid type carglist.
columnid ::= nm(X). {sqlite3AddColumn(pParse,&X);}
// An IDENTIFIER can be a generic identifier, or one of several
// keywords. Any non-standard keyword can also be an identifier.
//
%type id {Token}
id(A) ::= ID(X). {A = X;}
// The following directive causes tokens ABORT, AFTER, ASC, etc. to
// fallback to ID if they will not parse as their original value.
// This obviates the need for the "id" nonterminal.
//
%fallback ID
ABORT AFTER ASC ATTACH BEFORE BEGIN CASCADE CONFLICT
DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR
GLOB IGNORE IMMEDIATE INITIALLY INSTEAD LIKE MATCH KEY
OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW STATEMENT
TEMP TRIGGER VACUUM VIEW.
// Define operator precedence early so that this is the first occurance
// of the operator tokens in the grammer. Keeping the operators together
// causes them to be assigned integer values that are close together,
// which keeps parser tables smaller.
//
// The token values assigned to these symbols is determined by the order
// in which lemon first sees them. It must be the case that ISNULL/NOTNULL,
// NE/EQ, GT/LE, and GE/LT are separated by only a single value. See
// the sqlite3ExprIfFalse() routine for additional information on this
// constraint.
//
%left OR.
%left AND.
%right NOT.
%left IS LIKE GLOB BETWEEN IN ISNULL NOTNULL NE EQ.
%left GT LE LT GE.
%left BITAND BITOR LSHIFT RSHIFT.
%left PLUS MINUS.
%left STAR SLASH REM.
%left CONCAT.
%right UMINUS UPLUS BITNOT.
// And "ids" is an identifer-or-string.
//
%type ids {Token}
ids(A) ::= ID(X). {A = X;}
ids(A) ::= STRING(X). {A = X;}
// The name of a column or table can be any of the following:
//
%type nm {Token}
nm(A) ::= ID(X). {A = X;}
nm(A) ::= STRING(X). {A = X;}
nm(A) ::= JOIN_KW(X). {A = X;}
type ::= .
type ::= typename(X). {sqlite3AddColumnType(pParse,&X,&X);}
type ::= typename(X) LP signed RP(Y). {sqlite3AddColumnType(pParse,&X,&Y);}
type ::= typename(X) LP signed COMMA signed RP(Y).
{sqlite3AddColumnType(pParse,&X,&Y);}
%type typename {Token}
typename(A) ::= ids(X). {A = X;}
typename(A) ::= typename(X) ids(Y). {A.z=X.z; A.n=Y.n+(Y.z-X.z);}
%type signed {int}
signed(A) ::= plus_num(X). { A = atoi(X.z); }
signed(A) ::= minus_num(X). { A = -atoi(X.z); }
carglist ::= carglist carg.
carglist ::= .
carg ::= CONSTRAINT nm ccons.
carg ::= ccons.
carg ::= DEFAULT ids(X). {sqlite3AddDefaultValue(pParse,&X,0);}
carg ::= DEFAULT plus_num(X). {sqlite3AddDefaultValue(pParse,&X,0);}
carg ::= DEFAULT minus_num(X). {sqlite3AddDefaultValue(pParse,&X,1);}
carg ::= DEFAULT NULL.
// In addition to the type name, we also care about the primary key and
// UNIQUE constraints.
//
ccons ::= NULL onconf.
ccons ::= NOT NULL onconf(R). {sqlite3AddNotNull(pParse, R);}
ccons ::= PRIMARY KEY sortorder onconf(R). {sqlite3AddPrimaryKey(pParse,0,R);}
ccons ::= UNIQUE onconf(R). {sqlite3CreateIndex(pParse,0,0,0,0,R,0,0);}
ccons ::= CHECK LP expr RP onconf.
ccons ::= REFERENCES nm(T) idxlist_opt(TA) refargs(R).
{sqlite3CreateForeignKey(pParse,0,&T,TA,R);}
ccons ::= defer_subclause(D). {sqlite3DeferForeignKey(pParse,D);}
ccons ::= COLLATE id(C). {sqlite3AddCollateType(pParse, C.z, C.n);}
// The next group of rules parses the arguments to a REFERENCES clause
// that determine if the referential integrity checking is deferred or
// or immediate and which determine what action to take if a ref-integ
// check fails.
//
%type refargs {int}
refargs(A) ::= . { A = OE_Restrict * 0x010101; }
refargs(A) ::= refargs(X) refarg(Y). { A = (X & Y.mask) | Y.value; }
%type refarg {struct {int value; int mask;}}
refarg(A) ::= MATCH nm. { A.value = 0; A.mask = 0x000000; }
refarg(A) ::= ON DELETE refact(X). { A.value = X; A.mask = 0x0000ff; }
refarg(A) ::= ON UPDATE refact(X). { A.value = X<<8; A.mask = 0x00ff00; }
refarg(A) ::= ON INSERT refact(X). { A.value = X<<16; A.mask = 0xff0000; }
%type refact {int}
refact(A) ::= SET NULL. { A = OE_SetNull; }
refact(A) ::= SET DEFAULT. { A = OE_SetDflt; }
refact(A) ::= CASCADE. { A = OE_Cascade; }
refact(A) ::= RESTRICT. { A = OE_Restrict; }
%type defer_subclause {int}
defer_subclause(A) ::= NOT DEFERRABLE init_deferred_pred_opt(X). {A = X;}
defer_subclause(A) ::= DEFERRABLE init_deferred_pred_opt(X). {A = X;}
%type init_deferred_pred_opt {int}
init_deferred_pred_opt(A) ::= . {A = 0;}
init_deferred_pred_opt(A) ::= INITIALLY DEFERRED. {A = 1;}
init_deferred_pred_opt(A) ::= INITIALLY IMMEDIATE. {A = 0;}
// For the time being, the only constraint we care about is the primary
// key and UNIQUE. Both create indices.
//
conslist_opt ::= .
conslist_opt ::= COMMA conslist.
conslist ::= conslist COMMA tcons.
conslist ::= conslist tcons.
conslist ::= tcons.
tcons ::= CONSTRAINT nm.
tcons ::= PRIMARY KEY LP idxlist(X) RP onconf(R).
{sqlite3AddPrimaryKey(pParse,X,R);}
tcons ::= UNIQUE LP idxlist(X) RP onconf(R).
{sqlite3CreateIndex(pParse,0,0,0,X,R,0,0);}
tcons ::= CHECK expr onconf.
tcons ::= FOREIGN KEY LP idxlist(FA) RP
REFERENCES nm(T) idxlist_opt(TA) refargs(R) defer_subclause_opt(D). {
sqlite3CreateForeignKey(pParse, FA, &T, TA, R);
sqlite3DeferForeignKey(pParse, D);
}
%type defer_subclause_opt {int}
defer_subclause_opt(A) ::= . {A = 0;}
defer_subclause_opt(A) ::= defer_subclause(X). {A = X;}
// The following is a non-standard extension that allows us to declare the
// default behavior when there is a constraint conflict.
//
%type onconf {int}
%type orconf {int}
%type resolvetype {int}
onconf(A) ::= . {A = OE_Default;}
onconf(A) ::= ON CONFLICT resolvetype(X). {A = X;}
orconf(A) ::= . {A = OE_Default;}
orconf(A) ::= OR resolvetype(X). {A = X;}
resolvetype(A) ::= raisetype(X). {A = X;}
resolvetype(A) ::= IGNORE. {A = OE_Ignore;}
resolvetype(A) ::= REPLACE. {A = OE_Replace;}
////////////////////////// The DROP TABLE /////////////////////////////////////
//
cmd ::= DROP TABLE fullname(X). {
sqlite3DropTable(pParse, X, 0);
}
///////////////////// The CREATE VIEW statement /////////////////////////////
//
cmd ::= CREATE(X) temp(T) VIEW nm(Y) dbnm(Z) AS select(S). {
sqlite3CreateView(pParse, &X, &Y, &Z, S, T);
}
cmd ::= DROP VIEW fullname(X). {
sqlite3DropTable(pParse, X, 1);
}
//////////////////////// The SELECT statement /////////////////////////////////
//
cmd ::= select(X). {
sqlite3Select(pParse, X, SRT_Callback, 0, 0, 0, 0, 0);
sqlite3SelectDelete(X);
}
%type select {Select*}
%destructor select {sqlite3SelectDelete($$);}
%type oneselect {Select*}
%destructor oneselect {sqlite3SelectDelete($$);}
select(A) ::= oneselect(X). {A = X;}
select(A) ::= select(X) multiselect_op(Y) oneselect(Z). {
if( Z ){
Z->op = Y;
Z->pPrior = X;
}
A = Z;
}
%type multiselect_op {int}
multiselect_op(A) ::= UNION(OP). {A = @OP;}
multiselect_op(A) ::= UNION ALL. {A = TK_ALL;}
multiselect_op(A) ::= INTERSECT(OP). {A = @OP;}
multiselect_op(A) ::= EXCEPT(OP). {A = @OP;}
oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y)
groupby_opt(P) having_opt(Q) orderby_opt(Z) limit_opt(L). {
A = sqlite3SelectNew(W,X,Y,P,Q,Z,D,L.limit,L.offset);
}
// The "distinct" nonterminal is true (1) if the DISTINCT keyword is
// present and false (0) if it is not.
//
%type distinct {int}
distinct(A) ::= DISTINCT. {A = 1;}
distinct(A) ::= ALL. {A = 0;}
distinct(A) ::= . {A = 0;}
// selcollist is a list of expressions that are to become the return
// values of the SELECT statement. The "*" in statements like
// "SELECT * FROM ..." is encoded as a special expression with an
// opcode of TK_ALL.
//
%type selcollist {ExprList*}
%destructor selcollist {sqlite3ExprListDelete($$);}
%type sclp {ExprList*}
%destructor sclp {sqlite3ExprListDelete($$);}
sclp(A) ::= selcollist(X) COMMA. {A = X;}
sclp(A) ::= . {A = 0;}
selcollist(A) ::= sclp(P) expr(X) as(Y). {
A = sqlite3ExprListAppend(P,X,Y.n?&Y:0);
}
selcollist(A) ::= sclp(P) STAR. {
A = sqlite3ExprListAppend(P, sqlite3Expr(TK_ALL, 0, 0, 0), 0);
}
selcollist(A) ::= sclp(P) nm(X) DOT STAR. {
Expr *pRight = sqlite3Expr(TK_ALL, 0, 0, 0);
Expr *pLeft = sqlite3Expr(TK_ID, 0, 0, &X);
A = sqlite3ExprListAppend(P, sqlite3Expr(TK_DOT, pLeft, pRight, 0), 0);
}
// An option "AS <id>" phrase that can follow one of the expressions that
// define the result set, or one of the tables in the FROM clause.
//
%type as {Token}
as(X) ::= AS nm(Y). {X = Y;}
as(X) ::= ids(Y). {X = Y;}
as(X) ::= . {X.n = 0;}
%type seltablist {SrcList*}
%destructor seltablist {sqlite3SrcListDelete($$);}
%type stl_prefix {SrcList*}
%destructor stl_prefix {sqlite3SrcListDelete($$);}
%type from {SrcList*}
%destructor from {sqlite3SrcListDelete($$);}
// A complete FROM clause.
//
from(A) ::= . {A = sqliteMalloc(sizeof(*A));}
from(A) ::= FROM seltablist(X). {A = X;}
// "seltablist" is a "Select Table List" - the content of the FROM clause
// in a SELECT statement. "stl_prefix" is a prefix of this list.
//
stl_prefix(A) ::= seltablist(X) joinop(Y). {
A = X;
if( A && A->nSrc>0 ) A->a[A->nSrc-1].jointype = Y;
}
stl_prefix(A) ::= . {A = 0;}
seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) on_opt(N) using_opt(U). {
A = sqlite3SrcListAppend(X,&Y,&D);
if( Z.n ) sqlite3SrcListAddAlias(A,&Z);
if( N ){
if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pOn = N; }
else { sqlite3ExprDelete(N); }
}
if( U ){
if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pUsing = U; }
else { sqlite3IdListDelete(U); }
}
}
seltablist(A) ::= stl_prefix(X) LP seltablist_paren(S) RP
as(Z) on_opt(N) using_opt(U). {
A = sqlite3SrcListAppend(X,0,0);
A->a[A->nSrc-1].pSelect = S;
if( Z.n ) sqlite3SrcListAddAlias(A,&Z);
if( N ){
if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pOn = N; }
else { sqlite3ExprDelete(N); }
}
if( U ){
if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pUsing = U; }
else { sqlite3IdListDelete(U); }
}
}
// A seltablist_paren nonterminal represents anything in a FROM that
// is contained inside parentheses. This can be either a subquery or
// a grouping of table and subqueries.
//
%type seltablist_paren {Select*}
%destructor seltablist_paren {sqlite3SelectDelete($$);}
seltablist_paren(A) ::= select(S). {A = S;}
seltablist_paren(A) ::= seltablist(F). {
A = sqlite3SelectNew(0,F,0,0,0,0,0,-1,0);
}
%type dbnm {Token}
dbnm(A) ::= . {A.z=0; A.n=0;}
dbnm(A) ::= DOT nm(X). {A = X;}
%type fullname {SrcList*}
%destructor fullname {sqlite3SrcListDelete($$);}
fullname(A) ::= nm(X) dbnm(Y). {A = sqlite3SrcListAppend(0,&X,&Y);}
%type joinop {int}
%type joinop2 {int}
joinop(X) ::= COMMA. { X = JT_INNER; }
joinop(X) ::= JOIN. { X = JT_INNER; }
joinop(X) ::= JOIN_KW(A) JOIN. { X = sqlite3JoinType(pParse,&A,0,0); }
joinop(X) ::= JOIN_KW(A) nm(B) JOIN. { X = sqlite3JoinType(pParse,&A,&B,0); }
joinop(X) ::= JOIN_KW(A) nm(B) nm(C) JOIN.
{ X = sqlite3JoinType(pParse,&A,&B,&C); }
%type on_opt {Expr*}
%destructor on_opt {sqlite3ExprDelete($$);}
on_opt(N) ::= ON expr(E). {N = E;}
on_opt(N) ::= . {N = 0;}
%type using_opt {IdList*}
%destructor using_opt {sqlite3IdListDelete($$);}
using_opt(U) ::= USING LP inscollist(L) RP. {U = L;}
using_opt(U) ::= . {U = 0;}
%type orderby_opt {ExprList*}
%destructor orderby_opt {sqlite3ExprListDelete($$);}
%type sortlist {ExprList*}
%destructor sortlist {sqlite3ExprListDelete($$);}
%type sortitem {Expr*}
%destructor sortitem {sqlite3ExprDelete($$);}
orderby_opt(A) ::= . {A = 0;}
orderby_opt(A) ::= ORDER BY sortlist(X). {A = X;}
sortlist(A) ::= sortlist(X) COMMA sortitem(Y) collate(C) sortorder(Z). {
A = sqlite3ExprListAppend(X,Y,C.n>0?&C:0);
if( A ) A->a[A->nExpr-1].sortOrder = Z;
}
sortlist(A) ::= sortitem(Y) collate(C) sortorder(Z). {
A = sqlite3ExprListAppend(0,Y,C.n>0?&C:0);
if( A && A->a ) A->a[0].sortOrder = Z;
}
sortitem(A) ::= expr(X). {A = X;}
%type sortorder {int}
%type collate {Token}
sortorder(A) ::= ASC. {A = SQLITE_SO_ASC;}
sortorder(A) ::= DESC. {A = SQLITE_SO_DESC;}
sortorder(A) ::= . {A = SQLITE_SO_ASC;}
collate(C) ::= . {C.z = 0; C.n = 0;}
collate(C) ::= COLLATE id(X). {C = X;}
%type groupby_opt {ExprList*}
%destructor groupby_opt {sqlite3ExprListDelete($$);}
groupby_opt(A) ::= . {A = 0;}
groupby_opt(A) ::= GROUP BY exprlist(X). {A = X;}
%type having_opt {Expr*}
%destructor having_opt {sqlite3ExprDelete($$);}
having_opt(A) ::= . {A = 0;}
having_opt(A) ::= HAVING expr(X). {A = X;}
%type limit_opt {struct LimitVal}
limit_opt(A) ::= . {A.limit = -1; A.offset = 0;}
limit_opt(A) ::= LIMIT signed(X). {A.limit = X; A.offset = 0;}
limit_opt(A) ::= LIMIT signed(X) OFFSET signed(Y).
{A.limit = X; A.offset = Y;}
limit_opt(A) ::= LIMIT signed(X) COMMA signed(Y).
{A.limit = Y; A.offset = X;}
/////////////////////////// The DELETE statement /////////////////////////////
//
cmd ::= DELETE FROM fullname(X) where_opt(Y). {sqlite3DeleteFrom(pParse,X,Y);}
%type where_opt {Expr*}
%destructor where_opt {sqlite3ExprDelete($$);}
where_opt(A) ::= . {A = 0;}
where_opt(A) ::= WHERE expr(X). {A = X;}
%type setlist {ExprList*}
%destructor setlist {sqlite3ExprListDelete($$);}
////////////////////////// The UPDATE command ////////////////////////////////
//
cmd ::= UPDATE orconf(R) fullname(X) SET setlist(Y) where_opt(Z).
{sqlite3Update(pParse,X,Y,Z,R);}
setlist(A) ::= setlist(Z) COMMA nm(X) EQ expr(Y).
{A = sqlite3ExprListAppend(Z,Y,&X);}
setlist(A) ::= nm(X) EQ expr(Y). {A = sqlite3ExprListAppend(0,Y,&X);}
////////////////////////// The INSERT command /////////////////////////////////
//
cmd ::= insert_cmd(R) INTO fullname(X) inscollist_opt(F)
VALUES LP itemlist(Y) RP.
{sqlite3Insert(pParse, X, Y, 0, F, R);}
cmd ::= insert_cmd(R) INTO fullname(X) inscollist_opt(F) select(S).
{sqlite3Insert(pParse, X, 0, S, F, R);}
%type insert_cmd {int}
insert_cmd(A) ::= INSERT orconf(R). {A = R;}
insert_cmd(A) ::= REPLACE. {A = OE_Replace;}
%type itemlist {ExprList*}
%destructor itemlist {sqlite3ExprListDelete($$);}
itemlist(A) ::= itemlist(X) COMMA expr(Y). {A = sqlite3ExprListAppend(X,Y,0);}
itemlist(A) ::= expr(X). {A = sqlite3ExprListAppend(0,X,0);}
%type inscollist_opt {IdList*}
%destructor inscollist_opt {sqlite3IdListDelete($$);}
%type inscollist {IdList*}
%destructor inscollist {sqlite3IdListDelete($$);}
inscollist_opt(A) ::= . {A = 0;}
inscollist_opt(A) ::= LP inscollist(X) RP. {A = X;}
inscollist(A) ::= inscollist(X) COMMA nm(Y). {A = sqlite3IdListAppend(X,&Y);}
inscollist(A) ::= nm(Y). {A = sqlite3IdListAppend(0,&Y);}
/////////////////////////// Expression Processing /////////////////////////////
//
%type expr {Expr*}
%destructor expr {sqlite3ExprDelete($$);}
expr(A) ::= LP(B) expr(X) RP(E). {A = X; sqlite3ExprSpan(A,&B,&E); }
expr(A) ::= NULL(X). {A = sqlite3Expr(@X, 0, 0, &X);}
expr(A) ::= ID(X). {A = sqlite3Expr(TK_ID, 0, 0, &X);}
expr(A) ::= JOIN_KW(X). {A = sqlite3Expr(TK_ID, 0, 0, &X);}
expr(A) ::= nm(X) DOT nm(Y). {
Expr *temp1 = sqlite3Expr(TK_ID, 0, 0, &X);
Expr *temp2 = sqlite3Expr(TK_ID, 0, 0, &Y);
A = sqlite3Expr(TK_DOT, temp1, temp2, 0);
}
expr(A) ::= nm(X) DOT nm(Y) DOT nm(Z). {
Expr *temp1 = sqlite3Expr(TK_ID, 0, 0, &X);
Expr *temp2 = sqlite3Expr(TK_ID, 0, 0, &Y);
Expr *temp3 = sqlite3Expr(TK_ID, 0, 0, &Z);
Expr *temp4 = sqlite3Expr(TK_DOT, temp2, temp3, 0);
A = sqlite3Expr(TK_DOT, temp1, temp4, 0);
}
expr(A) ::= INTEGER(X). {A = sqlite3Expr(@X, 0, 0, &X);}
expr(A) ::= FLOAT(X). {A = sqlite3Expr(@X, 0, 0, &X);}
expr(A) ::= STRING(X). {A = sqlite3Expr(@X, 0, 0, &X);}
expr(A) ::= BLOB(X). {A = sqlite3Expr(@X, 0, 0, &X);}
expr(A) ::= VARIABLE(X). {
Token *pToken = &X;
Expr *pExpr = A = sqlite3Expr(TK_VARIABLE, 0, 0, pToken);
sqlite3ExprAssignVarNumber(pParse, pExpr);
}
expr(A) ::= ID(X) LP exprlist(Y) RP(E). {
A = sqlite3ExprFunction(Y, &X);
sqlite3ExprSpan(A,&X,&E);
}
expr(A) ::= ID(X) LP STAR RP(E). {
A = sqlite3ExprFunction(0, &X);
sqlite3ExprSpan(A,&X,&E);
}
expr(A) ::= expr(X) AND(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
expr(A) ::= expr(X) OR(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
expr(A) ::= expr(X) LT(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
expr(A) ::= expr(X) GT(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
expr(A) ::= expr(X) LE(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
expr(A) ::= expr(X) GE(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
expr(A) ::= expr(X) NE(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
expr(A) ::= expr(X) EQ(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
expr(A) ::= expr(X) BITAND(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
expr(A) ::= expr(X) BITOR(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
expr(A) ::= expr(X) LSHIFT(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
expr(A) ::= expr(X) RSHIFT(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
expr(A) ::= expr(X) PLUS(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
expr(A) ::= expr(X) MINUS(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
expr(A) ::= expr(X) STAR(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
expr(A) ::= expr(X) SLASH(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
expr(A) ::= expr(X) REM(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
expr(A) ::= expr(X) CONCAT(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
%type likeop {struct LikeOp}
likeop(A) ::= LIKE. {A.opcode = TK_LIKE; A.not = 0;}
likeop(A) ::= GLOB. {A.opcode = TK_GLOB; A.not = 0;}
likeop(A) ::= NOT LIKE. {A.opcode = TK_LIKE; A.not = 1;}
likeop(A) ::= NOT GLOB. {A.opcode = TK_GLOB; A.not = 1;}
expr(A) ::= expr(X) likeop(OP) expr(Y). [LIKE] {
ExprList *pList = sqlite3ExprListAppend(0, Y, 0);
pList = sqlite3ExprListAppend(pList, X, 0);
A = sqlite3ExprFunction(pList, 0);
if( A ) A->op = OP.opcode;
if( OP.not ) A = sqlite3Expr(TK_NOT, A, 0, 0);
sqlite3ExprSpan(A, &X->span, &Y->span);
}
expr(A) ::= expr(X) ISNULL(E). {
A = sqlite3Expr(TK_ISNULL, X, 0, 0);
sqlite3ExprSpan(A,&X->span,&E);
}
expr(A) ::= expr(X) IS NULL(E). {
A = sqlite3Expr(TK_ISNULL, X, 0, 0);
sqlite3ExprSpan(A,&X->span,&E);
}
expr(A) ::= expr(X) NOTNULL(E). {
A = sqlite3Expr(TK_NOTNULL, X, 0, 0);
sqlite3ExprSpan(A,&X->span,&E);
}
expr(A) ::= expr(X) NOT NULL(E). {
A = sqlite3Expr(TK_NOTNULL, X, 0, 0);
sqlite3ExprSpan(A,&X->span,&E);
}
expr(A) ::= expr(X) IS NOT NULL(E). {
A = sqlite3Expr(TK_NOTNULL, X, 0, 0);
sqlite3ExprSpan(A,&X->span,&E);
}
expr(A) ::= NOT(B) expr(X). {
A = sqlite3Expr(@B, X, 0, 0);
sqlite3ExprSpan(A,&B,&X->span);
}
expr(A) ::= BITNOT(B) expr(X). {
A = sqlite3Expr(@B, X, 0, 0);
sqlite3ExprSpan(A,&B,&X->span);
}
expr(A) ::= MINUS(B) expr(X). [UMINUS] {
A = sqlite3Expr(TK_UMINUS, X, 0, 0);
sqlite3ExprSpan(A,&B,&X->span);
}
expr(A) ::= PLUS(B) expr(X). [UPLUS] {
A = sqlite3Expr(TK_UPLUS, X, 0, 0);
sqlite3ExprSpan(A,&B,&X->span);
}
expr(A) ::= LP(B) select(X) RP(E). {
A = sqlite3Expr(TK_SELECT, 0, 0, 0);
if( A ) A->pSelect = X;
sqlite3ExprSpan(A,&B,&E);
}
%type between_op {int}
between_op(A) ::= BETWEEN. {A = 0;}
between_op(A) ::= NOT BETWEEN. {A = 1;}
expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
ExprList *pList = sqlite3ExprListAppend(0, X, 0);
pList = sqlite3ExprListAppend(pList, Y, 0);
A = sqlite3Expr(TK_BETWEEN, W, 0, 0);
if( A ) A->pList = pList;
if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0);
sqlite3ExprSpan(A,&W->span,&Y->span);
}
%type in_op {int}
in_op(A) ::= IN. {A = 0;}
in_op(A) ::= NOT IN. {A = 1;}
expr(A) ::= expr(X) in_op(N) LP exprlist(Y) RP(E). [IN] {
A = sqlite3Expr(TK_IN, X, 0, 0);
if( A ) A->pList = Y;
if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0);
sqlite3ExprSpan(A,&X->span,&E);
}
expr(A) ::= expr(X) in_op(N) LP select(Y) RP(E). [IN] {
A = sqlite3Expr(TK_IN, X, 0, 0);
if( A ) A->pSelect = Y;
if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0);
sqlite3ExprSpan(A,&X->span,&E);
}
expr(A) ::= expr(X) in_op(N) nm(Y) dbnm(Z). [IN] {
SrcList *pSrc = sqlite3SrcListAppend(0,&Y,&Z);
A = sqlite3Expr(TK_IN, X, 0, 0);
if( A ) A->pSelect = sqlite3SelectNew(0,pSrc,0,0,0,0,0,-1,0);
if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0);
sqlite3ExprSpan(A,&X->span,Z.z?&Z:&Y);
}
/* CASE expressions */
expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
A = sqlite3Expr(TK_CASE, X, Z, 0);
if( A ) A->pList = Y;
sqlite3ExprSpan(A, &C, &E);
}
%type case_exprlist {ExprList*}
%destructor case_exprlist {sqlite3ExprListDelete($$);}
case_exprlist(A) ::= case_exprlist(X) WHEN expr(Y) THEN expr(Z). {
A = sqlite3ExprListAppend(X, Y, 0);
A = sqlite3ExprListAppend(A, Z, 0);
}
case_exprlist(A) ::= WHEN expr(Y) THEN expr(Z). {
A = sqlite3ExprListAppend(0, Y, 0);
A = sqlite3ExprListAppend(A, Z, 0);
}
%type case_else {Expr*}
case_else(A) ::= ELSE expr(X). {A = X;}
case_else(A) ::= . {A = 0;}
%type case_operand {Expr*}
case_operand(A) ::= expr(X). {A = X;}
case_operand(A) ::= . {A = 0;}
%type exprlist {ExprList*}
%destructor exprlist {sqlite3ExprListDelete($$);}
%type expritem {Expr*}
%destructor expritem {sqlite3ExprDelete($$);}
exprlist(A) ::= exprlist(X) COMMA expritem(Y).
{A = sqlite3ExprListAppend(X,Y,0);}
exprlist(A) ::= expritem(X). {A = sqlite3ExprListAppend(0,X,0);}
expritem(A) ::= expr(X). {A = X;}
expritem(A) ::= . {A = 0;}
///////////////////////////// The CREATE INDEX command ///////////////////////
//
cmd ::= CREATE(S) uniqueflag(U) INDEX nm(X) dbnm(D)
ON fullname(Y) LP idxlist(Z) RP(E) onconf(R). {
if( U!=OE_None ) U = R;
if( U==OE_Default) U = OE_Abort;
sqlite3CreateIndex(pParse, &X, &D, Y, Z, U, &S, &E);
}
%type uniqueflag {int}
uniqueflag(A) ::= UNIQUE. {A = OE_Abort;}
uniqueflag(A) ::= . {A = OE_None;}
%type idxlist {ExprList*}
%destructor idxlist {sqlite3ExprListDelete($$);}
%type idxlist_opt {ExprList*}
%destructor idxlist_opt {sqlite3ExprListDelete($$);}
%type idxitem {Token}
idxlist_opt(A) ::= . {A = 0;}
idxlist_opt(A) ::= LP idxlist(X) RP. {A = X;}
idxlist(A) ::= idxlist(X) COMMA idxitem(Y) collate(C) sortorder. {
Expr *p = 0;
if( C.n>0 ){
p = sqlite3Expr(TK_COLUMN, 0, 0, 0);
if( p ) p->pColl = sqlite3LocateCollSeq(pParse, C.z, C.n);
}
A = sqlite3ExprListAppend(X, p, &Y);
}
idxlist(A) ::= idxitem(Y) collate(C) sortorder. {
Expr *p = 0;
if( C.n>0 ){
p = sqlite3Expr(TK_COLUMN, 0, 0, 0);
if( p ) p->pColl = sqlite3LocateCollSeq(pParse, C.z, C.n);
}
A = sqlite3ExprListAppend(0, p, &Y);
}
idxitem(A) ::= nm(X). {A = X;}
///////////////////////////// The DROP INDEX command /////////////////////////
//
cmd ::= DROP INDEX fullname(X). {sqlite3DropIndex(pParse, X);}
///////////////////////////// The VACUUM command /////////////////////////////
//
cmd ::= VACUUM. {sqlite3Vacuum(pParse,0);}
cmd ::= VACUUM nm. {sqlite3Vacuum(pParse,0);}
///////////////////////////// The PRAGMA command /////////////////////////////
//
cmd ::= PRAGMA nm(X) dbnm(Z) EQ nm(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
cmd ::= PRAGMA nm(X) dbnm(Z) EQ ON(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
cmd ::= PRAGMA nm(X) dbnm(Z) EQ plus_num(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
cmd ::= PRAGMA nm(X) dbnm(Z) EQ minus_num(Y). {
sqlite3Pragma(pParse,&X,&Z,&Y,1);
}
cmd ::= PRAGMA nm(X) dbnm(Z) LP nm(Y) RP. {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
cmd ::= PRAGMA nm(X) dbnm(Z). {sqlite3Pragma(pParse,&X,&Z,0,0);}
plus_num(A) ::= plus_opt number(X). {A = X;}
minus_num(A) ::= MINUS number(X). {A = X;}
number(A) ::= INTEGER(X). {A = X;}
number(A) ::= FLOAT(X). {A = X;}
plus_opt ::= PLUS.
plus_opt ::= .
//////////////////////////// The CREATE TRIGGER command /////////////////////
cmd ::= CREATE trigger_decl(A) BEGIN trigger_cmd_list(S) END(Z). {
Token all;
all.z = A.z;
all.n = (Z.z - A.z) + Z.n;
sqlite3FinishTrigger(pParse, S, &all);
}
trigger_decl(A) ::= temp(T) TRIGGER nm(B) dbnm(Z) trigger_time(C)
trigger_event(D)
ON fullname(E) foreach_clause(F) when_clause(G). {
sqlite3BeginTrigger(pParse, &B, &Z, C, D.a, D.b, E, F, G, T);
A = (Z.n==0?B:Z);
}
%type trigger_time {int}
trigger_time(A) ::= BEFORE. { A = TK_BEFORE; }
trigger_time(A) ::= AFTER. { A = TK_AFTER; }
trigger_time(A) ::= INSTEAD OF. { A = TK_INSTEAD;}
trigger_time(A) ::= . { A = TK_BEFORE; }
%type trigger_event {struct TrigEvent}
%destructor trigger_event {sqlite3IdListDelete($$.b);}
trigger_event(A) ::= DELETE(OP). {A.a = @OP; A.b = 0;}
trigger_event(A) ::= INSERT(OP). {A.a = @OP; A.b = 0;}
trigger_event(A) ::= UPDATE(OP). {A.a = @OP; A.b = 0;}
trigger_event(A) ::= UPDATE OF inscollist(X). {A.a = TK_UPDATE; A.b = X;}
%type foreach_clause {int}
foreach_clause(A) ::= . { A = TK_ROW; }
foreach_clause(A) ::= FOR EACH ROW. { A = TK_ROW; }
foreach_clause(A) ::= FOR EACH STATEMENT. { A = TK_STATEMENT; }
%type when_clause {Expr*}
when_clause(A) ::= . { A = 0; }
when_clause(A) ::= WHEN expr(X). { A = X; }
%type trigger_cmd_list {TriggerStep*}
%destructor trigger_cmd_list {sqlite3DeleteTriggerStep($$);}
trigger_cmd_list(A) ::= trigger_cmd(X) SEMI trigger_cmd_list(Y). {
X->pNext = Y;
A = X;
}
trigger_cmd_list(A) ::= . { A = 0; }
%type trigger_cmd {TriggerStep*}
%destructor trigger_cmd {sqlite3DeleteTriggerStep($$);}
// UPDATE
trigger_cmd(A) ::= UPDATE orconf(R) nm(X) SET setlist(Y) where_opt(Z).
{ A = sqlite3TriggerUpdateStep(&X, Y, Z, R); }
// INSERT
trigger_cmd(A) ::= insert_cmd(R) INTO nm(X) inscollist_opt(F)
VALUES LP itemlist(Y) RP.
{A = sqlite3TriggerInsertStep(&X, F, Y, 0, R);}
trigger_cmd(A) ::= insert_cmd(R) INTO nm(X) inscollist_opt(F) select(S).
{A = sqlite3TriggerInsertStep(&X, F, 0, S, R);}
// DELETE
trigger_cmd(A) ::= DELETE FROM nm(X) where_opt(Y).
{A = sqlite3TriggerDeleteStep(&X, Y);}
// SELECT
trigger_cmd(A) ::= select(X). {A = sqlite3TriggerSelectStep(X); }
// The special RAISE expression that may occur in trigger programs
expr(A) ::= RAISE(X) LP IGNORE RP(Y). {
A = sqlite3Expr(TK_RAISE, 0, 0, 0);
A->iColumn = OE_Ignore;
sqlite3ExprSpan(A, &X, &Y);
}
expr(A) ::= RAISE(X) LP raisetype(T) COMMA nm(Z) RP(Y). {
A = sqlite3Expr(TK_RAISE, 0, 0, &Z);
A->iColumn = T;
sqlite3ExprSpan(A, &X, &Y);
}
%type raisetype {int}
raisetype(A) ::= ROLLBACK. {A = OE_Rollback;}
raisetype(A) ::= ABORT. {A = OE_Abort;}
raisetype(A) ::= FAIL. {A = OE_Fail;}
//////////////////////// DROP TRIGGER statement //////////////////////////////
cmd ::= DROP TRIGGER fullname(X). {
sqlite3DropTrigger(pParse,X);
}
//////////////////////// ATTACH DATABASE file AS name /////////////////////////
cmd ::= ATTACH database_kw_opt ids(F) AS nm(D) key_opt(K). {
sqlite3Attach(pParse, &F, &D, K.type, &K.key);
}
%type key_opt {struct AttachKey}
key_opt(A) ::= . { A.type = 0; }
key_opt(A) ::= KEY ids(X). { A.type=1; A.key = X; }
key_opt(A) ::= KEY BLOB(X). { A.type=2; A.key = X; }
database_kw_opt ::= DATABASE.
database_kw_opt ::= .
//////////////////////// DETACH DATABASE name /////////////////////////////////
cmd ::= DETACH database_kw_opt nm(D). {
sqlite3Detach(pParse, &D);
}
-754
View File
@@ -1,754 +0,0 @@
/*
** 2003 April 6
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains code used to implement the PRAGMA command.
**
** $Id$
*/
#include "sqliteInt.h"
#include <ctype.h>
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
# include "pager.h"
# include "btree.h"
#endif
/*
** Interpret the given string as a boolean value.
*/
static int getBoolean(const u8 *z){
static const u8 *azTrue[] = { "yes", "on", "true" };
int i;
if( z[0]==0 ) return 0;
if( sqlite3IsNumber(z, 0, SQLITE_UTF8) ){
return atoi(z);
}
for(i=0; i<sizeof(azTrue)/sizeof(azTrue[0]); i++){
if( sqlite3StrICmp(z,azTrue[i])==0 ) return 1;
}
return 0;
}
/*
** Interpret the given string as a safety level. Return 0 for OFF,
** 1 for ON or NORMAL and 2 for FULL. Return 1 for an empty or
** unrecognized string argument.
**
** Note that the values returned are one less that the values that
** should be passed into sqlite3BtreeSetSafetyLevel(). The is done
** to support legacy SQL code. The safety level used to be boolean
** and older scripts may have used numbers 0 for OFF and 1 for ON.
*/
static int getSafetyLevel(u8 *z){
static const struct {
const u8 *zWord;
int val;
} aKey[] = {
{ "no", 0 },
{ "off", 0 },
{ "false", 0 },
{ "yes", 1 },
{ "on", 1 },
{ "true", 1 },
{ "full", 2 },
};
int i;
if( z[0]==0 ) return 1;
if( sqlite3IsNumber(z, 0, SQLITE_UTF8) ){
return atoi(z);
}
for(i=0; i<sizeof(aKey)/sizeof(aKey[0]); i++){
if( sqlite3StrICmp(z,aKey[i].zWord)==0 ) return aKey[i].val;
}
return 1;
}
/*
** Interpret the given string as a temp db location. Return 1 for file
** backed temporary databases, 2 for the Red-Black tree in memory database
** and 0 to use the compile-time default.
*/
static int getTempStore(const char *z){
if( z[0]>='0' && z[0]<='2' ){
return z[0] - '0';
}else if( sqlite3StrICmp(z, "file")==0 ){
return 1;
}else if( sqlite3StrICmp(z, "memory")==0 ){
return 2;
}else{
return 0;
}
}
/*
** If the TEMP database is open, close it and mark the database schema
** as needing reloading. This must be done when using the TEMP_STORE
** or DEFAULT_TEMP_STORE pragmas.
*/
static int changeTempStorage(Parse *pParse, const char *zStorageType){
int ts = getTempStore(zStorageType);
sqlite3 *db = pParse->db;
if( db->temp_store==ts ) return SQLITE_OK;
if( db->aDb[1].pBt!=0 ){
if( db->flags & SQLITE_InTrans ){
sqlite3ErrorMsg(pParse, "temporary storage cannot be changed "
"from within a transaction");
return SQLITE_ERROR;
}
sqlite3BtreeClose(db->aDb[1].pBt);
db->aDb[1].pBt = 0;
sqlite3ResetInternalSchema(db, 0);
}
db->temp_store = ts;
return SQLITE_OK;
}
/*
** Generate code to return a single integer value.
*/
static void returnSingleInt(Parse *pParse, const char *zLabel, int value){
Vdbe *v = sqlite3GetVdbe(pParse);
sqlite3VdbeAddOp(v, OP_Integer, value, 0);
if( pParse->explain==0 ){
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, zLabel, P3_STATIC);
}
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
}
/*
** Check to see if zRight and zLeft refer to a pragma that queries
** or changes one of the flags in db->flags. Return 1 if so and 0 if not.
** Also, implement the pragma.
*/
static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
static const struct {
const char *zName; /* Name of the pragma */
int mask; /* Mask for the db->flags value */
} aPragma[] = {
{ "vdbe_trace", SQLITE_VdbeTrace },
{ "sql_trace", SQLITE_SqlTrace },
{ "vdbe_listing", SQLITE_VdbeListing },
#if 1 /* FIX ME: Remove the following pragmas */
{ "full_column_names", SQLITE_FullColNames },
{ "short_column_names", SQLITE_ShortColNames },
{ "count_changes", SQLITE_CountRows },
{ "empty_result_callbacks", SQLITE_NullCallback },
#endif
};
int i;
for(i=0; i<sizeof(aPragma)/sizeof(aPragma[0]); i++){
if( sqlite3StrICmp(zLeft, aPragma[i].zName)==0 ){
sqlite3 *db = pParse->db;
Vdbe *v;
if( zRight==0 ){
v = sqlite3GetVdbe(pParse);
if( v ){
returnSingleInt(pParse,
aPragma[i].zName, (db->flags&aPragma[i].mask)!=0);
}
}else if( getBoolean(zRight) ){
db->flags |= aPragma[i].mask;
}else{
db->flags &= ~aPragma[i].mask;
}
return 1;
}
}
return 0;
}
/*
** Process a pragma statement.
**
** Pragmas are of this form:
**
** PRAGMA [database.]id [= value]
**
** The identifier might also be a string. The value is a string, and
** identifier, or a number. If minusFlag is true, then the value is
** a number that was preceded by a minus sign.
**
** If the left side is "database.id" then pId1 is the database name
** and pId2 is the id. If the left side is just "id" then pId1 is the
** id and pId2 is any empty string.
*/
void sqlite3Pragma(
Parse *pParse,
Token *pId1, /* First part of [database.]id field */
Token *pId2, /* Second part of [database.]id field, or NULL */
Token *pValue, /* Token for <value>, or NULL */
int minusFlag /* True if a '-' sign preceded <value> */
){
char *zLeft = 0; /* Nul-terminated UTF-8 string <id> */
char *zRight = 0; /* Nul-terminated UTF-8 string <value>, or NULL */
const char *zDb = 0; /* The database name */
Token *pId; /* Pointer to <id> token */
int iDb; /* Database index for <database> */
sqlite3 *db = pParse->db;
Db *pDb;
Vdbe *v = sqlite3GetVdbe(pParse);
if( v==0 ) return;
/* Interpret the [database.] part of the pragma statement. iDb is the
** index of the database this pragma is being applied to in db.aDb[]. */
iDb = sqlite3TwoPartName(pParse, pId1, pId2, &pId);
if( iDb<0 ) return;
pDb = &db->aDb[iDb];
zLeft = sqlite3NameFromToken(pId);
if( !zLeft ) return;
if( minusFlag ){
zRight = sqlite3MPrintf("-%T", pValue);
}else{
zRight = sqlite3NameFromToken(pValue);
}
zDb = ((iDb>0)?pDb->zName:0);
if( sqlite3AuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight, zDb) ){
goto pragma_out;
}
/*
** PRAGMA [database.]default_cache_size
** PRAGMA [database.]default_cache_size=N
**
** The first form reports the current persistent setting for the
** page cache size. The value returned is the maximum number of
** pages in the page cache. The second form sets both the current
** page cache size value and the persistent page cache size value
** stored in the database file.
**
** The default cache size is stored in meta-value 2 of page 1 of the
** database file. The cache size is actually the absolute value of
** this memory location. The sign of meta-value 2 determines the
** synchronous setting. A negative value means synchronous is off
** and a positive value means synchronous is on.
*/
if( sqlite3StrICmp(zLeft,"default_cache_size")==0 ){
static const VdbeOpList getCacheSize[] = {
{ OP_ReadCookie, 0, 2, 0}, /* 0 */
{ OP_AbsValue, 0, 0, 0},
{ OP_Dup, 0, 0, 0},
{ OP_Integer, 0, 0, 0},
{ OP_Ne, 0, 6, 0},
{ OP_Integer, 0, 0, 0}, /* 5 */
{ OP_Callback, 1, 0, 0},
};
int addr;
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
if( !zRight ){
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, "cache_size", P3_STATIC);
addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
sqlite3VdbeChangeP1(v, addr, iDb);
sqlite3VdbeChangeP1(v, addr+5, MAX_PAGES);
}else{
int size = atoi(zRight);
if( size<0 ) size = -size;
sqlite3BeginWriteOperation(pParse, 0, iDb);
sqlite3VdbeAddOp(v, OP_Integer, size, 0);
sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 2);
addr = sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
sqlite3VdbeAddOp(v, OP_Ge, 0, addr+3);
sqlite3VdbeAddOp(v, OP_Negative, 0, 0);
sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 2);
pDb->cache_size = size;
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->cache_size);
}
}else
/*
** PRAGMA [database.]page_size
** PRAGMA [database.]page_size=N
**
** The first form reports the current setting for the
** database page size in bytes. The second form sets the
** database page size value. The value can only be set if
** the database has not yet been created.
*/
if( sqlite3StrICmp(zLeft,"page_size")==0 ){
Btree *pBt = pDb->pBt;
if( !zRight ){
int size = pBt ? sqlite3BtreeGetPageSize(pBt) : 0;
returnSingleInt(pParse, "page_size", size);
}else{
sqlite3BtreeSetPageSize(pBt, atoi(zRight), sqlite3BtreeGetReserve(pBt));
}
}else
/*
** PRAGMA [database.]cache_size
** PRAGMA [database.]cache_size=N
**
** The first form reports the current local setting for the
** page cache size. The local setting can be different from
** the persistent cache size value that is stored in the database
** file itself. The value returned is the maximum number of
** pages in the page cache. The second form sets the local
** page cache size value. It does not change the persistent
** cache size stored on the disk so the cache size will revert
** to its default value when the database is closed and reopened.
** N should be a positive integer.
*/
if( sqlite3StrICmp(zLeft,"cache_size")==0 ){
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
if( !zRight ){
returnSingleInt(pParse, "cache_size", pDb->cache_size);
}else{
int size = atoi(zRight);
if( size<0 ) size = -size;
pDb->cache_size = size;
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->cache_size);
}
}else
/*
** PRAGMA temp_store
** PRAGMA temp_store = "default"|"memory"|"file"
**
** Return or set the local value of the temp_store flag. Changing
** the local value does not make changes to the disk file and the default
** value will be restored the next time the database is opened.
**
** Note that it is possible for the library compile-time options to
** override this setting
*/
if( sqlite3StrICmp(zLeft, "temp_store")==0 ){
if( !zRight ){
returnSingleInt(pParse, "temp_store", db->temp_store);
}else{
changeTempStorage(pParse, zRight);
}
}else
/*
** PRAGMA [database.]synchronous
** PRAGMA [database.]synchronous=OFF|ON|NORMAL|FULL
**
** Return or set the local value of the synchronous flag. Changing
** the local value does not make changes to the disk file and the
** default value will be restored the next time the database is
** opened.
*/
if( sqlite3StrICmp(zLeft,"synchronous")==0 ){
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
if( !zRight ){
returnSingleInt(pParse, "synchronous", pDb->safety_level-1);
}else{
if( !db->autoCommit ){
sqlite3ErrorMsg(pParse,
"Safety level may not be changed inside a transaction");
}else{
pDb->safety_level = getSafetyLevel(zRight)+1;
sqlite3BtreeSetSafetyLevel(pDb->pBt, pDb->safety_level);
}
}
}else
#if 0 /* Used once during development. No longer needed */
if( sqlite3StrICmp(zLeft, "trigger_overhead_test")==0 ){
if( getBoolean(zRight) ){
sqlite3_always_code_trigger_setup = 1;
}else{
sqlite3_always_code_trigger_setup = 0;
}
}else
#endif
if( flagPragma(pParse, zLeft, zRight) ){
/* The flagPragma() subroutine also generates any necessary code
** there is nothing more to do here */
}else
/*
** PRAGMA table_info(<table>)
**
** Return a single row for each column of the named table. The columns of
** the returned data set are:
**
** cid: Column id (numbered from left to right, starting at 0)
** name: Column name
** type: Column declaration type.
** notnull: True if 'NOT NULL' is part of column declaration
** dflt_value: The default value for the column, if any.
*/
if( sqlite3StrICmp(zLeft, "table_info")==0 && zRight ){
Table *pTab;
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
pTab = sqlite3FindTable(db, zRight, zDb);
if( pTab ){
int i;
sqlite3VdbeSetNumCols(v, 6);
sqlite3VdbeSetColName(v, 0, "cid", P3_STATIC);
sqlite3VdbeSetColName(v, 1, "name", P3_STATIC);
sqlite3VdbeSetColName(v, 2, "type", P3_STATIC);
sqlite3VdbeSetColName(v, 3, "notnull", P3_STATIC);
sqlite3VdbeSetColName(v, 4, "dflt_value", P3_STATIC);
sqlite3VdbeSetColName(v, 5, "pk", P3_STATIC);
sqlite3ViewGetColumnNames(pParse, pTab);
for(i=0; i<pTab->nCol; i++){
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->aCol[i].zName, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0,
pTab->aCol[i].zType ? pTab->aCol[i].zType : "numeric", 0);
sqlite3VdbeAddOp(v, OP_Integer, pTab->aCol[i].notNull, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0,
pTab->aCol[i].zDflt, P3_STATIC);
sqlite3VdbeAddOp(v, OP_Integer, pTab->aCol[i].isPrimKey, 0);
sqlite3VdbeAddOp(v, OP_Callback, 6, 0);
}
}
}else
if( sqlite3StrICmp(zLeft, "index_info")==0 && zRight ){
Index *pIdx;
Table *pTab;
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
pIdx = sqlite3FindIndex(db, zRight, zDb);
if( pIdx ){
int i;
pTab = pIdx->pTable;
sqlite3VdbeSetNumCols(v, 3);
sqlite3VdbeSetColName(v, 0, "seqno", P3_STATIC);
sqlite3VdbeSetColName(v, 1, "cid", P3_STATIC);
sqlite3VdbeSetColName(v, 2, "name", P3_STATIC);
for(i=0; i<pIdx->nColumn; i++){
int cnum = pIdx->aiColumn[i];
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
sqlite3VdbeAddOp(v, OP_Integer, cnum, 0);
assert( pTab->nCol>cnum );
sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->aCol[cnum].zName, 0);
sqlite3VdbeAddOp(v, OP_Callback, 3, 0);
}
}
}else
if( sqlite3StrICmp(zLeft, "index_list")==0 && zRight ){
Index *pIdx;
Table *pTab;
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
pTab = sqlite3FindTable(db, zRight, zDb);
if( pTab ){
v = sqlite3GetVdbe(pParse);
pIdx = pTab->pIndex;
if( pIdx ){
int i = 0;
sqlite3VdbeSetNumCols(v, 3);
sqlite3VdbeSetColName(v, 0, "seq", P3_STATIC);
sqlite3VdbeSetColName(v, 1, "name", P3_STATIC);
sqlite3VdbeSetColName(v, 2, "unique", P3_STATIC);
while(pIdx){
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, pIdx->zName, 0);
sqlite3VdbeAddOp(v, OP_Integer, pIdx->onError!=OE_None, 0);
sqlite3VdbeAddOp(v, OP_Callback, 3, 0);
++i;
pIdx = pIdx->pNext;
}
}
}
}else
if( sqlite3StrICmp(zLeft, "foreign_key_list")==0 && zRight ){
FKey *pFK;
Table *pTab;
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
pTab = sqlite3FindTable(db, zRight, zDb);
if( pTab ){
v = sqlite3GetVdbe(pParse);
pFK = pTab->pFKey;
if( pFK ){
int i = 0;
sqlite3VdbeSetNumCols(v, 5);
sqlite3VdbeSetColName(v, 0, "id", P3_STATIC);
sqlite3VdbeSetColName(v, 1, "seq", P3_STATIC);
sqlite3VdbeSetColName(v, 2, "table", P3_STATIC);
sqlite3VdbeSetColName(v, 3, "from", P3_STATIC);
sqlite3VdbeSetColName(v, 4, "to", P3_STATIC);
while(pFK){
int j;
for(j=0; j<pFK->nCol; j++){
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
sqlite3VdbeAddOp(v, OP_Integer, j, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, pFK->zTo, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0,
pTab->aCol[pFK->aCol[j].iFrom].zName, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, pFK->aCol[j].zCol, 0);
sqlite3VdbeAddOp(v, OP_Callback, 5, 0);
}
++i;
pFK = pFK->pNextFrom;
}
}
}
}else
if( sqlite3StrICmp(zLeft, "database_list")==0 ){
int i;
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
sqlite3VdbeSetNumCols(v, 3);
sqlite3VdbeSetColName(v, 0, "seq", P3_STATIC);
sqlite3VdbeSetColName(v, 1, "name", P3_STATIC);
sqlite3VdbeSetColName(v, 2, "file", P3_STATIC);
for(i=0; i<db->nDb; i++){
if( db->aDb[i].pBt==0 ) continue;
assert( db->aDb[i].zName!=0 );
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, db->aDb[i].zName, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0,
sqlite3BtreeGetFilename(db->aDb[i].pBt), 0);
sqlite3VdbeAddOp(v, OP_Callback, 3, 0);
}
}else
#ifndef NDEBUG
if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){
extern void sqlite3ParserTrace(FILE*, char *);
if( getBoolean(zRight) ){
sqlite3ParserTrace(stdout, "parser: ");
}else{
sqlite3ParserTrace(0, 0);
}
}else
#endif
if( sqlite3StrICmp(zLeft, "integrity_check")==0 ){
int i, j, addr;
/* Code that initializes the integrity check program. Set the
** error count 0
*/
static const VdbeOpList initCode[] = {
{ OP_Integer, 0, 0, 0},
{ OP_MemStore, 0, 1, 0},
};
/* Code that appears at the end of the integrity check. If no error
** messages have been generated, output OK. Otherwise output the
** error message
*/
static const VdbeOpList endCode[] = {
{ OP_MemLoad, 0, 0, 0},
{ OP_Integer, 0, 0, 0},
{ OP_Ne, 0, 0, 0}, /* 2 */
{ OP_String8, 0, 0, "ok"},
{ OP_Callback, 1, 0, 0},
};
/* Initialize the VDBE program */
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, "integrity_check", P3_STATIC);
sqlite3VdbeAddOpList(v, ArraySize(initCode), initCode);
/* Do an integrity check on each database file */
for(i=0; i<db->nDb; i++){
HashElem *x;
int cnt = 0;
sqlite3CodeVerifySchema(pParse, i);
/* Do an integrity check of the B-Tree
*/
for(x=sqliteHashFirst(&db->aDb[i].tblHash); x; x=sqliteHashNext(x)){
Table *pTab = sqliteHashData(x);
Index *pIdx;
sqlite3VdbeAddOp(v, OP_Integer, pTab->tnum, 0);
cnt++;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
if( sqlite3CheckIndexCollSeq(pParse, pIdx) ) goto pragma_out;
sqlite3VdbeAddOp(v, OP_Integer, pIdx->tnum, 0);
cnt++;
}
}
assert( cnt>0 );
sqlite3VdbeAddOp(v, OP_IntegrityCk, cnt, i);
sqlite3VdbeAddOp(v, OP_Dup, 0, 1);
addr = sqlite3VdbeOp3(v, OP_String8, 0, 0, "ok", P3_STATIC);
sqlite3VdbeAddOp(v, OP_Eq, 0, addr+6);
sqlite3VdbeOp3(v, OP_String8, 0, 0,
sqlite3MPrintf("*** in database %s ***\n", db->aDb[i].zName),
P3_DYNAMIC);
sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
sqlite3VdbeAddOp(v, OP_Concat, 0, 1);
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
/* Make sure all the indices are constructed correctly.
*/
sqlite3CodeVerifySchema(pParse, i);
for(x=sqliteHashFirst(&db->aDb[i].tblHash); x; x=sqliteHashNext(x)){
Table *pTab = sqliteHashData(x);
Index *pIdx;
int loopTop;
if( pTab->pIndex==0 ) continue;
sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead);
sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
sqlite3VdbeAddOp(v, OP_MemStore, 1, 1);
loopTop = sqlite3VdbeAddOp(v, OP_Rewind, 1, 0);
sqlite3VdbeAddOp(v, OP_MemIncr, 1, 0);
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
int jmp2;
static const VdbeOpList idxErr[] = {
{ OP_MemIncr, 0, 0, 0},
{ OP_String8, 0, 0, "rowid "},
{ OP_Recno, 1, 0, 0},
{ OP_String8, 0, 0, " missing from index "},
{ OP_String8, 0, 0, 0}, /* 4 */
{ OP_Concat, 2, 0, 0},
{ OP_Callback, 1, 0, 0},
};
sqlite3GenerateIndexKey(v, pIdx, 1);
jmp2 = sqlite3VdbeAddOp(v, OP_Found, j+2, 0);
addr = sqlite3VdbeAddOpList(v, ArraySize(idxErr), idxErr);
sqlite3VdbeChangeP3(v, addr+4, pIdx->zName, P3_STATIC);
sqlite3VdbeChangeP2(v, jmp2, sqlite3VdbeCurrentAddr(v));
}
sqlite3VdbeAddOp(v, OP_Next, 1, loopTop+1);
sqlite3VdbeChangeP2(v, loopTop, sqlite3VdbeCurrentAddr(v));
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
static const VdbeOpList cntIdx[] = {
{ OP_Integer, 0, 0, 0},
{ OP_MemStore, 2, 1, 0},
{ OP_Rewind, 0, 0, 0}, /* 2 */
{ OP_MemIncr, 2, 0, 0},
{ OP_Next, 0, 0, 0}, /* 4 */
{ OP_MemLoad, 1, 0, 0},
{ OP_MemLoad, 2, 0, 0},
{ OP_Eq, 0, 0, 0}, /* 7 */
{ OP_MemIncr, 0, 0, 0},
{ OP_String8, 0, 0, "wrong # of entries in index "},
{ OP_String8, 0, 0, 0}, /* 10 */
{ OP_Concat, 0, 0, 0},
{ OP_Callback, 1, 0, 0},
};
if( pIdx->tnum==0 ) continue;
addr = sqlite3VdbeAddOpList(v, ArraySize(cntIdx), cntIdx);
sqlite3VdbeChangeP1(v, addr+2, j+2);
sqlite3VdbeChangeP2(v, addr+2, addr+5);
sqlite3VdbeChangeP1(v, addr+4, j+2);
sqlite3VdbeChangeP2(v, addr+4, addr+3);
sqlite3VdbeChangeP2(v, addr+7, addr+ArraySize(cntIdx));
sqlite3VdbeChangeP3(v, addr+10, pIdx->zName, P3_STATIC);
}
}
}
addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode);
sqlite3VdbeChangeP2(v, addr+2, addr+ArraySize(endCode));
}else
/*
** PRAGMA encoding
** PRAGMA encoding = "utf-8"|"utf-16"|"utf-16le"|"utf-16be"
**
** In it's first form, this pragma returns the encoding of the main
** database. If the database is not initialized, it is initialized now.
**
** The second form of this pragma is a no-op if the main database file
** has not already been initialized. In this case it sets the default
** encoding that will be used for the main database file if a new file
** is created. If an existing main database file is opened, then the
** default text encoding for the existing database is used.
**
** In all cases new databases created using the ATTACH command are
** created to use the same default text encoding as the main database. If
** the main database has not been initialized and/or created when ATTACH
** is executed, this is done before the ATTACH operation.
**
** In the second form this pragma sets the text encoding to be used in
** new database files created using this database handle. It is only
** useful if invoked immediately after the main database i
*/
if( sqlite3StrICmp(zLeft, "encoding")==0 ){
static struct EncName {
char *zName;
u8 enc;
} encnames[] = {
{ "UTF-8", SQLITE_UTF8 },
{ "UTF8", SQLITE_UTF8 },
{ "UTF-16le", SQLITE_UTF16LE },
{ "UTF16le", SQLITE_UTF16LE },
{ "UTF-16be", SQLITE_UTF16BE },
{ "UTF16be", SQLITE_UTF16BE },
{ "UTF-16", 0 /* Filled in at run-time */ },
{ "UTF16", 0 /* Filled in at run-time */ },
{ 0, 0 }
};
struct EncName *pEnc;
encnames[6].enc = encnames[7].enc = SQLITE_UTF16NATIVE;
if( !zRight ){ /* "PRAGMA encoding" */
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, "encoding", P3_STATIC);
sqlite3VdbeAddOp(v, OP_String8, 0, 0);
for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
if( pEnc->enc==pParse->db->enc ){
sqlite3VdbeChangeP3(v, -1, pEnc->zName, P3_STATIC);
break;
}
}
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
}else{ /* "PRAGMA encoding = XXX" */
/* Only change the value of sqlite.enc if the database handle is not
** initialized. If the main database exists, the new sqlite.enc value
** will be overwritten when the schema is next loaded. If it does not
** already exists, it will be created to use the new encoding value.
*/
if( !(pParse->db->flags&SQLITE_Initialized) ){
for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){
pParse->db->enc = pEnc->enc;
break;
}
}
if( !pEnc->zName ){
sqlite3ErrorMsg(pParse, "unsupported encoding: %s", zRight);
}
}
}
}else
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
/*
** Report the current state of file logs for all databases
*/
if( sqlite3StrICmp(zLeft, "lock_status")==0 ){
static const char *const azLockName[] = {
"unlocked", "shared", "reserved", "pending", "exclusive"
};
int i;
Vdbe *v = sqlite3GetVdbe(pParse);
sqlite3VdbeSetNumCols(v, 2);
sqlite3VdbeSetColName(v, 0, "database", P3_STATIC);
sqlite3VdbeSetColName(v, 1, "status", P3_STATIC);
for(i=0; i<db->nDb; i++){
Btree *pBt;
Pager *pPager;
if( db->aDb[i].zName==0 ) continue;
sqlite3VdbeOp3(v, OP_String, 0, 0, db->aDb[i].zName, P3_STATIC);
pBt = db->aDb[i].pBt;
if( pBt==0 || (pPager = sqlite3BtreePager(pBt))==0 ){
sqlite3VdbeOp3(v, OP_String, 0, 0, "closed", P3_STATIC);
}else{
int j = sqlite3pager_lockstate(pPager);
sqlite3VdbeOp3(v, OP_String, 0, 0,
(j>=0 && j<=4) ? azLockName[j] : "unknown", P3_STATIC);
}
sqlite3VdbeAddOp(v, OP_Callback, 2, 0);
}
}else
#endif
{}
pragma_out:
sqliteFree(zLeft);
sqliteFree(zRight);
}
-825
View File
@@ -1,825 +0,0 @@
/*
** The "printf" code that follows dates from the 1980's. It is in
** the public domain. The original comments are included here for
** completeness. They are very out-of-date but might be useful as
** an historical reference. Most of the "enhancements" have been backed
** out so that the functionality is now the same as standard printf().
**
**************************************************************************
**
** The following modules is an enhanced replacement for the "printf" subroutines
** found in the standard C library. The following enhancements are
** supported:
**
** + Additional functions. The standard set of "printf" functions
** includes printf, fprintf, sprintf, vprintf, vfprintf, and
** vsprintf. This module adds the following:
**
** * snprintf -- Works like sprintf, but has an extra argument
** which is the size of the buffer written to.
**
** * mprintf -- Similar to sprintf. Writes output to memory
** obtained from malloc.
**
** * xprintf -- Calls a function to dispose of output.
**
** * nprintf -- No output, but returns the number of characters
** that would have been output by printf.
**
** * A v- version (ex: vsnprintf) of every function is also
** supplied.
**
** + A few extensions to the formatting notation are supported:
**
** * The "=" flag (similar to "-") causes the output to be
** be centered in the appropriately sized field.
**
** * The %b field outputs an integer in binary notation.
**
** * The %c field now accepts a precision. The character output
** is repeated by the number of times the precision specifies.
**
** * The %' field works like %c, but takes as its character the
** next character of the format string, instead of the next
** argument. For example, printf("%.78'-") prints 78 minus
** signs, the same as printf("%.78c",'-').
**
** + When compiled using GCC on a SPARC, this version of printf is
** faster than the library printf for SUN OS 4.1.
**
** + All functions are fully reentrant.
**
*/
#include "sqliteInt.h"
/*
** Conversion types fall into various categories as defined by the
** following enumeration.
*/
#define etRADIX 1 /* Integer types. %d, %x, %o, and so forth */
#define etFLOAT 2 /* Floating point. %f */
#define etEXP 3 /* Exponentional notation. %e and %E */
#define etGENERIC 4 /* Floating or exponential, depending on exponent. %g */
#define etSIZE 5 /* Return number of characters processed so far. %n */
#define etSTRING 6 /* Strings. %s */
#define etDYNSTRING 7 /* Dynamically allocated strings. %z */
#define etPERCENT 8 /* Percent symbol. %% */
#define etCHARX 9 /* Characters. %c */
#define etERROR 10 /* Used to indicate no such conversion type */
/* The rest are extensions, not normally found in printf() */
#define etCHARLIT 11 /* Literal characters. %' */
#define etSQLESCAPE 12 /* Strings with '\'' doubled. %q */
#define etSQLESCAPE2 13 /* Strings with '\'' doubled and enclosed in '',
NULL pointers replaced by SQL NULL. %Q */
#define etTOKEN 14 /* a pointer to a Token structure */
#define etSRCLIST 15 /* a pointer to a SrcList */
#define etPOINTER 16 /* The %p conversion */
/*
** An "etByte" is an 8-bit unsigned value.
*/
typedef unsigned char etByte;
/*
** Each builtin conversion character (ex: the 'd' in "%d") is described
** by an instance of the following structure
*/
typedef struct et_info { /* Information about each format field */
char fmttype; /* The format field code letter */
etByte base; /* The base for radix conversion */
etByte flags; /* One or more of FLAG_ constants below */
etByte type; /* Conversion paradigm */
etByte charset; /* Offset into aDigits[] of the digits string */
etByte prefix; /* Offset into aPrefix[] of the prefix string */
} et_info;
/*
** Allowed values for et_info.flags
*/
#define FLAG_SIGNED 1 /* True if the value to convert is signed */
#define FLAG_INTERN 2 /* True if for internal use only */
/*
** The following table is searched linearly, so it is good to put the
** most frequently used conversion types first.
*/
static const char aDigits[] = "0123456789ABCDEF0123456789abcdef";
static const char aPrefix[] = "-x0\000X0";
static const et_info fmtinfo[] = {
{ 'd', 10, 1, etRADIX, 0, 0 },
{ 's', 0, 0, etSTRING, 0, 0 },
{ 'z', 0, 2, etDYNSTRING, 0, 0 },
{ 'q', 0, 0, etSQLESCAPE, 0, 0 },
{ 'Q', 0, 0, etSQLESCAPE2, 0, 0 },
{ 'c', 0, 0, etCHARX, 0, 0 },
{ 'o', 8, 0, etRADIX, 0, 2 },
{ 'u', 10, 0, etRADIX, 0, 0 },
{ 'x', 16, 0, etRADIX, 16, 1 },
{ 'X', 16, 0, etRADIX, 0, 4 },
{ 'f', 0, 1, etFLOAT, 0, 0 },
{ 'e', 0, 1, etEXP, 30, 0 },
{ 'E', 0, 1, etEXP, 14, 0 },
{ 'g', 0, 1, etGENERIC, 30, 0 },
{ 'G', 0, 1, etGENERIC, 14, 0 },
{ 'i', 10, 1, etRADIX, 0, 0 },
{ 'n', 0, 0, etSIZE, 0, 0 },
{ '%', 0, 0, etPERCENT, 0, 0 },
{ 'p', 16, 0, etPOINTER, 0, 1 },
{ 'T', 0, 2, etTOKEN, 0, 0 },
{ 'S', 0, 2, etSRCLIST, 0, 0 },
};
#define etNINFO (sizeof(fmtinfo)/sizeof(fmtinfo[0]))
/*
** If NOFLOATINGPOINT is defined, then none of the floating point
** conversions will work.
*/
#ifndef etNOFLOATINGPOINT
/*
** "*val" is a double such that 0.1 <= *val < 10.0
** Return the ascii code for the leading digit of *val, then
** multiply "*val" by 10.0 to renormalize.
**
** Example:
** input: *val = 3.14159
** output: *val = 1.4159 function return = '3'
**
** The counter *cnt is incremented each time. After counter exceeds
** 16 (the number of significant digits in a 64-bit float) '0' is
** always returned.
*/
static int et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
int digit;
LONGDOUBLE_TYPE d;
if( (*cnt)++ >= 16 ) return '0';
digit = (int)*val;
d = digit;
digit += '0';
*val = (*val - d)*10.0;
return digit;
}
#endif
#define etBUFSIZE 1000 /* Size of the output buffer */
/*
** The root program. All variations call this core.
**
** INPUTS:
** func This is a pointer to a function taking three arguments
** 1. A pointer to anything. Same as the "arg" parameter.
** 2. A pointer to the list of characters to be output
** (Note, this list is NOT null terminated.)
** 3. An integer number of characters to be output.
** (Note: This number might be zero.)
**
** arg This is the pointer to anything which will be passed as the
** first argument to "func". Use it for whatever you like.
**
** fmt This is the format string, as in the usual print.
**
** ap This is a pointer to a list of arguments. Same as in
** vfprint.
**
** OUTPUTS:
** The return value is the total number of characters sent to
** the function "func". Returns -1 on a error.
**
** Note that the order in which automatic variables are declared below
** seems to make a big difference in determining how fast this beast
** will run.
*/
static int vxprintf(
void (*func)(void*,const char*,int), /* Consumer of text */
void *arg, /* First argument to the consumer */
int useExtended, /* Allow extended %-conversions */
const char *fmt, /* Format string */
va_list ap /* arguments */
){
int c; /* Next character in the format string */
char *bufpt; /* Pointer to the conversion buffer */
int precision; /* Precision of the current field */
int length; /* Length of the field */
int idx; /* A general purpose loop counter */
int count; /* Total number of characters output */
int width; /* Width of the current field */
etByte flag_leftjustify; /* True if "-" flag is present */
etByte flag_plussign; /* True if "+" flag is present */
etByte flag_blanksign; /* True if " " flag is present */
etByte flag_alternateform; /* True if "#" flag is present */
etByte flag_zeropad; /* True if field width constant starts with zero */
etByte flag_long; /* True if "l" flag is present */
etByte flag_longlong; /* True if the "ll" flag is present */
UINT64_TYPE longvalue; /* Value for integer types */
LONGDOUBLE_TYPE realvalue; /* Value for real types */
const et_info *infop; /* Pointer to the appropriate info structure */
char buf[etBUFSIZE]; /* Conversion buffer */
char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */
etByte errorflag = 0; /* True if an error is encountered */
etByte xtype; /* Conversion paradigm */
char *zExtra; /* Extra memory used for etTCLESCAPE conversions */
static const char spaces[] =
" ";
#define etSPACESIZE (sizeof(spaces)-1)
#ifndef etNOFLOATINGPOINT
int exp; /* exponent of real numbers */
double rounder; /* Used for rounding floating point values */
etByte flag_dp; /* True if decimal point should be shown */
etByte flag_rtz; /* True if trailing zeros should be removed */
etByte flag_exp; /* True to force display of the exponent */
int nsd; /* Number of significant digits returned */
#endif
func(arg,"",0);
count = length = 0;
bufpt = 0;
for(; (c=(*fmt))!=0; ++fmt){
if( c!='%' ){
int amt;
bufpt = (char *)fmt;
amt = 1;
while( (c=(*++fmt))!='%' && c!=0 ) amt++;
(*func)(arg,bufpt,amt);
count += amt;
if( c==0 ) break;
}
if( (c=(*++fmt))==0 ){
errorflag = 1;
(*func)(arg,"%",1);
count++;
break;
}
/* Find out what flags are present */
flag_leftjustify = flag_plussign = flag_blanksign =
flag_alternateform = flag_zeropad = 0;
do{
switch( c ){
case '-': flag_leftjustify = 1; c = 0; break;
case '+': flag_plussign = 1; c = 0; break;
case ' ': flag_blanksign = 1; c = 0; break;
case '#': flag_alternateform = 1; c = 0; break;
case '0': flag_zeropad = 1; c = 0; break;
default: break;
}
}while( c==0 && (c=(*++fmt))!=0 );
/* Get the field width */
width = 0;
if( c=='*' ){
width = va_arg(ap,int);
if( width<0 ){
flag_leftjustify = 1;
width = -width;
}
c = *++fmt;
}else{
while( c>='0' && c<='9' ){
width = width*10 + c - '0';
c = *++fmt;
}
}
if( width > etBUFSIZE-10 ){
width = etBUFSIZE-10;
}
/* Get the precision */
if( c=='.' ){
precision = 0;
c = *++fmt;
if( c=='*' ){
precision = va_arg(ap,int);
if( precision<0 ) precision = -precision;
c = *++fmt;
}else{
while( c>='0' && c<='9' ){
precision = precision*10 + c - '0';
c = *++fmt;
}
}
/* Limit the precision to prevent overflowing buf[] during conversion */
if( precision>etBUFSIZE-40 ) precision = etBUFSIZE-40;
}else{
precision = -1;
}
/* Get the conversion type modifier */
if( c=='l' ){
flag_long = 1;
c = *++fmt;
if( c=='l' ){
flag_longlong = 1;
c = *++fmt;
}else{
flag_longlong = 0;
}
}else{
flag_long = flag_longlong = 0;
}
/* Fetch the info entry for the field */
infop = 0;
xtype = etERROR;
for(idx=0; idx<etNINFO; idx++){
if( c==fmtinfo[idx].fmttype ){
infop = &fmtinfo[idx];
if( useExtended || (infop->flags & FLAG_INTERN)==0 ){
xtype = infop->type;
}
break;
}
}
zExtra = 0;
/*
** At this point, variables are initialized as follows:
**
** flag_alternateform TRUE if a '#' is present.
** flag_plussign TRUE if a '+' is present.
** flag_leftjustify TRUE if a '-' is present or if the
** field width was negative.
** flag_zeropad TRUE if the width began with 0.
** flag_long TRUE if the letter 'l' (ell) prefixed
** the conversion character.
** flag_longlong TRUE if the letter 'll' (ell ell) prefixed
** the conversion character.
** flag_blanksign TRUE if a ' ' is present.
** width The specified field width. This is
** always non-negative. Zero is the default.
** precision The specified precision. The default
** is -1.
** xtype The class of the conversion.
** infop Pointer to the appropriate info struct.
*/
switch( xtype ){
case etPOINTER:
flag_longlong = sizeof(char*)==sizeof(i64);
flag_long = sizeof(char*)==sizeof(long int);
/* Fall through into the next case */
case etRADIX:
if( infop->flags & FLAG_SIGNED ){
i64 v;
if( flag_longlong ) v = va_arg(ap,i64);
else if( flag_long ) v = va_arg(ap,long int);
else v = va_arg(ap,int);
if( v<0 ){
longvalue = -v;
prefix = '-';
}else{
longvalue = v;
if( flag_plussign ) prefix = '+';
else if( flag_blanksign ) prefix = ' ';
else prefix = 0;
}
}else{
if( flag_longlong ) longvalue = va_arg(ap,u64);
else if( flag_long ) longvalue = va_arg(ap,unsigned long int);
else longvalue = va_arg(ap,unsigned int);
prefix = 0;
}
if( longvalue==0 ) flag_alternateform = 0;
if( flag_zeropad && precision<width-(prefix!=0) ){
precision = width-(prefix!=0);
}
bufpt = &buf[etBUFSIZE-1];
{
register const char *cset; /* Use registers for speed */
register int base;
cset = &aDigits[infop->charset];
base = infop->base;
do{ /* Convert to ascii */
*(--bufpt) = cset[longvalue%base];
longvalue = longvalue/base;
}while( longvalue>0 );
}
length = &buf[etBUFSIZE-1]-bufpt;
for(idx=precision-length; idx>0; idx--){
*(--bufpt) = '0'; /* Zero pad */
}
if( prefix ) *(--bufpt) = prefix; /* Add sign */
if( flag_alternateform && infop->prefix ){ /* Add "0" or "0x" */
const char *pre;
char x;
pre = &aPrefix[infop->prefix];
if( *bufpt!=pre[0] ){
for(; (x=(*pre))!=0; pre++) *(--bufpt) = x;
}
}
length = &buf[etBUFSIZE-1]-bufpt;
break;
case etFLOAT:
case etEXP:
case etGENERIC:
realvalue = va_arg(ap,double);
#ifndef etNOFLOATINGPOINT
if( precision<0 ) precision = 6; /* Set default precision */
if( precision>etBUFSIZE-10 ) precision = etBUFSIZE-10;
if( realvalue<0.0 ){
realvalue = -realvalue;
prefix = '-';
}else{
if( flag_plussign ) prefix = '+';
else if( flag_blanksign ) prefix = ' ';
else prefix = 0;
}
if( infop->type==etGENERIC && precision>0 ) precision--;
rounder = 0.0;
#if 0
/* Rounding works like BSD when the constant 0.4999 is used. Wierd! */
for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1);
#else
/* It makes more sense to use 0.5 */
for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1);
#endif
if( infop->type==etFLOAT ) realvalue += rounder;
/* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
exp = 0;
if( realvalue>0.0 ){
while( realvalue>=1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; }
while( realvalue>=10.0 && exp<=350 ){ realvalue *= 0.1; exp++; }
while( realvalue<1e-8 && exp>=-350 ){ realvalue *= 1e8; exp-=8; }
while( realvalue<1.0 && exp>=-350 ){ realvalue *= 10.0; exp--; }
if( exp>350 || exp<-350 ){
bufpt = "NaN";
length = 3;
break;
}
}
bufpt = buf;
/*
** If the field type is etGENERIC, then convert to either etEXP
** or etFLOAT, as appropriate.
*/
flag_exp = xtype==etEXP;
if( xtype!=etFLOAT ){
realvalue += rounder;
if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; }
}
if( xtype==etGENERIC ){
flag_rtz = !flag_alternateform;
if( exp<-4 || exp>precision ){
xtype = etEXP;
}else{
precision = precision - exp;
xtype = etFLOAT;
}
}else{
flag_rtz = 0;
}
/*
** The "exp+precision" test causes output to be of type etEXP if
** the precision is too large to fit in buf[].
*/
nsd = 0;
if( xtype==etFLOAT && exp+precision<etBUFSIZE-30 ){
flag_dp = (precision>0 || flag_alternateform);
if( prefix ) *(bufpt++) = prefix; /* Sign */
if( exp<0 ) *(bufpt++) = '0'; /* Digits before "." */
else for(; exp>=0; exp--) *(bufpt++) = et_getdigit(&realvalue,&nsd);
if( flag_dp ) *(bufpt++) = '.'; /* The decimal point */
for(exp++; exp<0 && precision>0; precision--, exp++){
*(bufpt++) = '0';
}
while( (precision--)>0 ) *(bufpt++) = et_getdigit(&realvalue,&nsd);
*(bufpt--) = 0; /* Null terminate */
if( flag_rtz && flag_dp ){ /* Remove trailing zeros and "." */
while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0;
if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0;
}
bufpt++; /* point to next free slot */
}else{ /* etEXP or etGENERIC */
flag_dp = (precision>0 || flag_alternateform);
if( prefix ) *(bufpt++) = prefix; /* Sign */
*(bufpt++) = et_getdigit(&realvalue,&nsd); /* First digit */
if( flag_dp ) *(bufpt++) = '.'; /* Decimal point */
while( (precision--)>0 ) *(bufpt++) = et_getdigit(&realvalue,&nsd);
bufpt--; /* point to last digit */
if( flag_rtz && flag_dp ){ /* Remove tail zeros */
while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0;
if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0;
}
bufpt++; /* point to next free slot */
if( exp || flag_exp ){
*(bufpt++) = aDigits[infop->charset];
if( exp<0 ){ *(bufpt++) = '-'; exp = -exp; } /* sign of exp */
else { *(bufpt++) = '+'; }
if( exp>=100 ){
*(bufpt++) = (exp/100)+'0'; /* 100's digit */
exp %= 100;
}
*(bufpt++) = exp/10+'0'; /* 10's digit */
*(bufpt++) = exp%10+'0'; /* 1's digit */
}
}
/* The converted number is in buf[] and zero terminated. Output it.
** Note that the number is in the usual order, not reversed as with
** integer conversions. */
length = bufpt-buf;
bufpt = buf;
/* Special case: Add leading zeros if the flag_zeropad flag is
** set and we are not left justified */
if( flag_zeropad && !flag_leftjustify && length < width){
int i;
int nPad = width - length;
for(i=width; i>=nPad; i--){
bufpt[i] = bufpt[i-nPad];
}
i = prefix!=0;
while( nPad-- ) bufpt[i++] = '0';
length = width;
}
#endif
break;
case etSIZE:
*(va_arg(ap,int*)) = count;
length = width = 0;
break;
case etPERCENT:
buf[0] = '%';
bufpt = buf;
length = 1;
break;
case etCHARLIT:
case etCHARX:
c = buf[0] = (xtype==etCHARX ? va_arg(ap,int) : *++fmt);
if( precision>=0 ){
for(idx=1; idx<precision; idx++) buf[idx] = c;
length = precision;
}else{
length =1;
}
bufpt = buf;
break;
case etSTRING:
case etDYNSTRING:
bufpt = va_arg(ap,char*);
if( bufpt==0 ){
bufpt = "";
}else if( xtype==etDYNSTRING ){
zExtra = bufpt;
}
length = strlen(bufpt);
if( precision>=0 && precision<length ) length = precision;
break;
case etSQLESCAPE:
case etSQLESCAPE2:
{
int i, j, n, c, isnull;
char *arg = va_arg(ap,char*);
isnull = arg==0;
if( isnull ) arg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
for(i=n=0; (c=arg[i])!=0; i++){
if( c=='\'' ) n++;
}
n += i + 1 + ((!isnull && xtype==etSQLESCAPE2) ? 2 : 0);
if( n>etBUFSIZE ){
bufpt = zExtra = sqliteMalloc( n );
if( bufpt==0 ) return -1;
}else{
bufpt = buf;
}
j = 0;
if( !isnull && xtype==etSQLESCAPE2 ) bufpt[j++] = '\'';
for(i=0; (c=arg[i])!=0; i++){
bufpt[j++] = c;
if( c=='\'' ) bufpt[j++] = c;
}
if( !isnull && xtype==etSQLESCAPE2 ) bufpt[j++] = '\'';
bufpt[j] = 0;
length = j;
if( precision>=0 && precision<length ) length = precision;
}
break;
case etTOKEN: {
Token *pToken = va_arg(ap, Token*);
if( pToken && pToken->z ){
(*func)(arg, pToken->z, pToken->n);
}
length = width = 0;
break;
}
case etSRCLIST: {
SrcList *pSrc = va_arg(ap, SrcList*);
int k = va_arg(ap, int);
struct SrcList_item *pItem = &pSrc->a[k];
assert( k>=0 && k<pSrc->nSrc );
if( pItem->zDatabase && pItem->zDatabase[0] ){
(*func)(arg, pItem->zDatabase, strlen(pItem->zDatabase));
(*func)(arg, ".", 1);
}
(*func)(arg, pItem->zName, strlen(pItem->zName));
length = width = 0;
break;
}
case etERROR:
buf[0] = '%';
buf[1] = c;
errorflag = 0;
idx = 1+(c!=0);
(*func)(arg,"%",idx);
count += idx;
if( c==0 ) fmt--;
break;
}/* End switch over the format type */
/*
** The text of the conversion is pointed to by "bufpt" and is
** "length" characters long. The field width is "width". Do
** the output.
*/
if( !flag_leftjustify ){
register int nspace;
nspace = width-length;
if( nspace>0 ){
count += nspace;
while( nspace>=etSPACESIZE ){
(*func)(arg,spaces,etSPACESIZE);
nspace -= etSPACESIZE;
}
if( nspace>0 ) (*func)(arg,spaces,nspace);
}
}
if( length>0 ){
(*func)(arg,bufpt,length);
count += length;
}
if( flag_leftjustify ){
register int nspace;
nspace = width-length;
if( nspace>0 ){
count += nspace;
while( nspace>=etSPACESIZE ){
(*func)(arg,spaces,etSPACESIZE);
nspace -= etSPACESIZE;
}
if( nspace>0 ) (*func)(arg,spaces,nspace);
}
}
if( zExtra ){
sqliteFree(zExtra);
}
}/* End for loop over the format string */
return errorflag ? -1 : count;
} /* End of function */
/* This structure is used to store state information about the
** write to memory that is currently in progress.
*/
struct sgMprintf {
char *zBase; /* A base allocation */
char *zText; /* The string collected so far */
int nChar; /* Length of the string so far */
int nTotal; /* Output size if unconstrained */
int nAlloc; /* Amount of space allocated in zText */
void *(*xRealloc)(void*,int); /* Function used to realloc memory */
};
/*
** This function implements the callback from vxprintf.
**
** This routine add nNewChar characters of text in zNewText to
** the sgMprintf structure pointed to by "arg".
*/
static void mout(void *arg, const char *zNewText, int nNewChar){
struct sgMprintf *pM = (struct sgMprintf*)arg;
pM->nTotal += nNewChar;
if( pM->nChar + nNewChar + 1 > pM->nAlloc ){
if( pM->xRealloc==0 ){
nNewChar = pM->nAlloc - pM->nChar - 1;
}else{
pM->nAlloc = pM->nChar + nNewChar*2 + 1;
if( pM->zText==pM->zBase ){
pM->zText = pM->xRealloc(0, pM->nAlloc);
if( pM->zText && pM->nChar ){
memcpy(pM->zText, pM->zBase, pM->nChar);
}
}else{
pM->zText = pM->xRealloc(pM->zText, pM->nAlloc);
}
}
}
if( pM->zText ){
if( nNewChar>0 ){
memcpy(&pM->zText[pM->nChar], zNewText, nNewChar);
pM->nChar += nNewChar;
}
pM->zText[pM->nChar] = 0;
}
}
/*
** This routine is a wrapper around xprintf() that invokes mout() as
** the consumer.
*/
static char *base_vprintf(
void *(*xRealloc)(void*,int), /* Routine to realloc memory. May be NULL */
int useInternal, /* Use internal %-conversions if true */
char *zInitBuf, /* Initially write here, before mallocing */
int nInitBuf, /* Size of zInitBuf[] */
const char *zFormat, /* format string */
va_list ap /* arguments */
){
struct sgMprintf sM;
sM.zBase = sM.zText = zInitBuf;
sM.nChar = sM.nTotal = 0;
sM.nAlloc = nInitBuf;
sM.xRealloc = xRealloc;
vxprintf(mout, &sM, useInternal, zFormat, ap);
if( xRealloc ){
if( sM.zText==sM.zBase ){
sM.zText = xRealloc(0, sM.nChar+1);
if( sM.zText ){
memcpy(sM.zText, sM.zBase, sM.nChar+1);
}
}else if( sM.nAlloc>sM.nChar+10 ){
sM.zText = xRealloc(sM.zText, sM.nChar+1);
}
}
return sM.zText;
}
/*
** Realloc that is a real function, not a macro.
*/
static void *printf_realloc(void *old, int size){
return sqliteRealloc(old,size);
}
/*
** Print into memory obtained from sqliteMalloc(). Use the internal
** %-conversion extensions.
*/
char *sqlite3VMPrintf(const char *zFormat, va_list ap){
char zBase[1000];
return base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap);
}
/*
** Print into memory obtained from sqliteMalloc(). Use the internal
** %-conversion extensions.
*/
char *sqlite3MPrintf(const char *zFormat, ...){
va_list ap;
char *z;
char zBase[1000];
va_start(ap, zFormat);
z = base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap);
va_end(ap);
return z;
}
/*
** Print into memory obtained from malloc(). Do not use the internal
** %-conversion extensions. This routine is for use by external users.
*/
char *sqlite3_mprintf(const char *zFormat, ...){
va_list ap;
char *z;
char zBuf[200];
va_start(ap,zFormat);
z = base_vprintf((void*(*)(void*,int))realloc, 0,
zBuf, sizeof(zBuf), zFormat, ap);
va_end(ap);
return z;
}
/* This is the varargs version of sqlite3_mprintf.
*/
char *sqlite3_vmprintf(const char *zFormat, va_list ap){
char zBuf[200];
return base_vprintf((void*(*)(void*,int))realloc, 0,
zBuf, sizeof(zBuf), zFormat, ap);
}
/*
** sqlite3_snprintf() works like snprintf() except that it ignores the
** 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.
*/
char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
char *z;
va_list ap;
va_start(ap,zFormat);
z = base_vprintf(0, 0, zBuf, n, zFormat, ap);
va_end(ap);
return z;
}
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
/*
** A version of printf() that understands %lld. Used for debugging.
** The printf() built into some versions of windows does not understand %lld
** and segfaults if you give it a long long int.
*/
void sqlite3DebugPrintf(const char *zFormat, ...){
extern int getpid(void);
va_list ap;
char zBuf[500];
va_start(ap, zFormat);
base_vprintf(0, 0, zBuf, sizeof(zBuf), zFormat, ap);
va_end(ap);
fprintf(stdout,"%d: %s", getpid(), zBuf);
fflush(stdout);
}
#endif
-100
View File
@@ -1,100 +0,0 @@
/*
** 2001 September 15
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains code to implement a pseudo-random number
** generator (PRNG) for SQLite.
**
** Random numbers are used by some of the database backends in order
** to generate random integer keys for tables or random filenames.
**
** $Id$
*/
#include "sqliteInt.h"
#include "os.h"
/*
** Get a single 8-bit random value from the RC4 PRNG. The Mutex
** must be held while executing this routine.
**
** Why not just use a library random generator like lrand48() for this?
** Because the OP_NewRecno opcode in the VDBE depends on having a very
** good source of random numbers. The lrand48() library function may
** well be good enough. But maybe not. Or maybe lrand48() has some
** subtle problems on some systems that could cause problems. It is hard
** to know. To minimize the risk of problems due to bad lrand48()
** implementations, SQLite uses this random number generator based
** on RC4, which we know works very well.
*/
static int randomByte(){
unsigned char t;
/* All threads share a single random number generator.
** This structure is the current state of the generator.
*/
static struct {
unsigned char isInit; /* True if initialized */
unsigned char i, j; /* State variables */
unsigned char s[256]; /* State variables */
} prng;
/* Initialize the state of the random number generator once,
** the first time this routine is called. The seed value does
** not need to contain a lot of randomness since we are not
** trying to do secure encryption or anything like that...
**
** Nothing in this file or anywhere else in SQLite does any kind of
** encryption. The RC4 algorithm is being used as a PRNG (pseudo-random
** number generator) not as an encryption device.
*/
if( !prng.isInit ){
int i;
char k[256];
prng.j = 0;
prng.i = 0;
sqlite3OsRandomSeed(k);
for(i=0; i<256; i++){
prng.s[i] = i;
}
for(i=0; i<256; i++){
prng.j += prng.s[i] + k[i];
t = prng.s[prng.j];
prng.s[prng.j] = prng.s[i];
prng.s[i] = t;
}
prng.isInit = 1;
}
/* Generate and return single random byte
*/
prng.i++;
t = prng.s[prng.i];
prng.j += t;
prng.s[prng.i] = prng.s[prng.j];
prng.s[prng.j] = t;
t += prng.s[prng.i];
return prng.s[t];
}
/*
** Return N random bytes.
*/
void sqlite3Randomness(int N, void *pBuf){
unsigned char *zBuf = pBuf;
sqlite3OsEnterMutex();
while( N-- ){
*(zBuf++) = randomByte();
}
sqlite3OsLeaveMutex();
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
-195
View File
@@ -1,195 +0,0 @@
/*
** 2001 September 15
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains the sqlite3_get_table() and sqlite3_free_table()
** interface routines. These are just wrappers around the main
** interface routine of sqlite3_exec().
**
** These routines are in a separate files so that they will not be linked
** if they are not used.
*/
#include <stdlib.h>
#include <string.h>
#include "sqliteInt.h"
/*
** This structure is used to pass data from sqlite3_get_table() through
** to the callback function is uses to build the result.
*/
typedef struct TabResult {
char **azResult;
char *zErrMsg;
int nResult;
int nAlloc;
int nRow;
int nColumn;
int nData;
int rc;
} TabResult;
/*
** This routine is called once for each row in the result table. Its job
** is to fill in the TabResult structure appropriately, allocating new
** memory as necessary.
*/
static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
TabResult *p = (TabResult*)pArg;
int need;
int i;
char *z;
/* Make sure there is enough space in p->azResult to hold everything
** we need to remember from this invocation of the callback.
*/
if( p->nRow==0 && argv!=0 ){
need = nCol*2;
}else{
need = nCol;
}
if( p->nData + need >= p->nAlloc ){
char **azNew;
p->nAlloc = p->nAlloc*2 + need + 1;
azNew = realloc( p->azResult, sizeof(char*)*p->nAlloc );
if( azNew==0 ) goto malloc_failed;
p->azResult = azNew;
}
/* If this is the first row, then generate an extra row containing
** the names of all columns.
*/
if( p->nRow==0 ){
p->nColumn = nCol;
for(i=0; i<nCol; i++){
if( colv[i]==0 ){
z = 0;
}else{
z = malloc( strlen(colv[i])+1 );
if( z==0 ) goto malloc_failed;
strcpy(z, colv[i]);
}
p->azResult[p->nData++] = z;
}
}else if( p->nColumn!=nCol ){
sqlite3SetString(&p->zErrMsg,
"sqlite3_get_table() called with two or more incompatible queries",
(char*)0);
p->rc = SQLITE_ERROR;
return 1;
}
/* Copy over the row data
*/
if( argv!=0 ){
for(i=0; i<nCol; i++){
if( argv[i]==0 ){
z = 0;
}else{
z = malloc( strlen(argv[i])+1 );
if( z==0 ) goto malloc_failed;
strcpy(z, argv[i]);
}
p->azResult[p->nData++] = z;
}
p->nRow++;
}
return 0;
malloc_failed:
p->rc = SQLITE_NOMEM;
return 1;
}
/*
** Query the database. But instead of invoking a callback for each row,
** malloc() for space to hold the result and return the entire results
** at the conclusion of the call.
**
** The result that is written to ***pazResult is held in memory obtained
** from malloc(). But the caller cannot free this memory directly.
** Instead, the entire table should be passed to sqlite3_free_table() when
** the calling procedure is finished using it.
*/
int sqlite3_get_table(
sqlite3 *db, /* The database on which the SQL executes */
const char *zSql, /* The SQL to be executed */
char ***pazResult, /* Write the result table here */
int *pnRow, /* Write the number of rows in the result here */
int *pnColumn, /* Write the number of columns of result here */
char **pzErrMsg /* Write error messages here */
){
int rc;
TabResult res;
if( pazResult==0 ){ return SQLITE_ERROR; }
*pazResult = 0;
if( pnColumn ) *pnColumn = 0;
if( pnRow ) *pnRow = 0;
res.zErrMsg = 0;
res.nResult = 0;
res.nRow = 0;
res.nColumn = 0;
res.nData = 1;
res.nAlloc = 20;
res.rc = SQLITE_OK;
res.azResult = malloc( sizeof(char*)*res.nAlloc );
if( res.azResult==0 ) return SQLITE_NOMEM;
res.azResult[0] = 0;
rc = sqlite3_exec(db, zSql, sqlite3_get_table_cb, &res, pzErrMsg);
if( res.azResult ){
res.azResult[0] = (char*)res.nData;
}
if( rc==SQLITE_ABORT ){
sqlite3_free_table(&res.azResult[1]);
if( res.zErrMsg ){
if( pzErrMsg ){
free(*pzErrMsg);
*pzErrMsg = sqlite3_mprintf("%s",res.zErrMsg);
}
sqliteFree(res.zErrMsg);
}
db->errCode = res.rc;
return res.rc;
}
sqliteFree(res.zErrMsg);
if( rc!=SQLITE_OK ){
sqlite3_free_table(&res.azResult[1]);
return rc;
}
if( res.nAlloc>res.nData ){
char **azNew;
azNew = realloc( res.azResult, sizeof(char*)*(res.nData+1) );
if( azNew==0 ){
sqlite3_free_table(&res.azResult[1]);
return SQLITE_NOMEM;
}
res.nAlloc = res.nData+1;
res.azResult = azNew;
}
*pazResult = &res.azResult[1];
if( pnColumn ) *pnColumn = res.nColumn;
if( pnRow ) *pnRow = res.nRow;
return rc;
}
/*
** This routine frees the space the sqlite3_get_table() malloced.
*/
void sqlite3_free_table(
char **azResult /* Result returned from from sqlite3_get_table() */
){
if( azResult ){
int i, n;
azResult--;
if( azResult==0 ) return;
n = (int)azResult[0];
for(i=1; i<n; i++){ if( azResult[i] ) free(azResult[i]); }
free(azResult);
}
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
-569
View File
@@ -1,569 +0,0 @@
/*
** 2001 September 15
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing the pager.c module in SQLite. This code
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
** $Id$
*/
#include "sqliteInt.h"
#include "os.h"
#include "pager.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>
/*
** Interpret an SQLite error number
*/
static char *errorName(int rc){
char *zName;
switch( rc ){
case SQLITE_OK: zName = "SQLITE_OK"; break;
case SQLITE_ERROR: zName = "SQLITE_ERROR"; break;
case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; break;
case SQLITE_PERM: zName = "SQLITE_PERM"; break;
case SQLITE_ABORT: zName = "SQLITE_ABORT"; break;
case SQLITE_BUSY: zName = "SQLITE_BUSY"; break;
case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break;
case SQLITE_READONLY: zName = "SQLITE_READONLY"; break;
case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break;
case SQLITE_IOERR: zName = "SQLITE_IOERR"; break;
case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break;
case SQLITE_NOTFOUND: zName = "SQLITE_NOTFOUND"; break;
case SQLITE_FULL: zName = "SQLITE_FULL"; break;
case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break;
case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break;
case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break;
case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break;
case SQLITE_TOOBIG: zName = "SQLITE_TOOBIG"; break;
case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT"; break;
case SQLITE_MISMATCH: zName = "SQLITE_MISMATCH"; break;
case SQLITE_MISUSE: zName = "SQLITE_MISUSE"; break;
case SQLITE_NOLFS: zName = "SQLITE_NOLFS"; break;
default: zName = "SQLITE_Unknown"; break;
}
return zName;
}
/*
** Page size and reserved size used for testing.
*/
static int test_pagesize = 1024;
/*
** Usage: pager_open FILENAME N-PAGE
**
** Open a new pager
*/
static int pager_open(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
Pager *pPager;
int nPage;
int rc;
char zBuf[100];
if( argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" FILENAME N-PAGE\"", 0);
return TCL_ERROR;
}
if( Tcl_GetInt(interp, argv[2], &nPage) ) return TCL_ERROR;
rc = sqlite3pager_open(&pPager, argv[1], 0, 1);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
}
sqlite3pager_set_cachesize(pPager, nPage);
sqlite3pager_set_pagesize(pPager, test_pagesize);
sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPager);
Tcl_AppendResult(interp, zBuf, 0);
return TCL_OK;
}
/*
** Usage: pager_close ID
**
** Close the given pager.
*/
static int pager_close(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
Pager *pPager;
int rc;
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ID\"", 0);
return TCL_ERROR;
}
pPager = sqlite3TextToPtr(argv[1]);
rc = sqlite3pager_close(pPager);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
}
return TCL_OK;
}
/*
** Usage: pager_rollback ID
**
** Rollback changes
*/
static int pager_rollback(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
Pager *pPager;
int rc;
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ID\"", 0);
return TCL_ERROR;
}
pPager = sqlite3TextToPtr(argv[1]);
rc = sqlite3pager_rollback(pPager);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
}
return TCL_OK;
}
/*
** Usage: pager_commit ID
**
** Commit all changes
*/
static int pager_commit(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
Pager *pPager;
int rc;
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ID\"", 0);
return TCL_ERROR;
}
pPager = sqlite3TextToPtr(argv[1]);
rc = sqlite3pager_commit(pPager);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
}
return TCL_OK;
}
/*
** Usage: pager_stmt_begin ID
**
** Start a new checkpoint.
*/
static int pager_stmt_begin(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
Pager *pPager;
int rc;
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ID\"", 0);
return TCL_ERROR;
}
pPager = sqlite3TextToPtr(argv[1]);
rc = sqlite3pager_stmt_begin(pPager);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
}
return TCL_OK;
}
/*
** Usage: pager_stmt_rollback ID
**
** Rollback changes to a checkpoint
*/
static int pager_stmt_rollback(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
Pager *pPager;
int rc;
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ID\"", 0);
return TCL_ERROR;
}
pPager = sqlite3TextToPtr(argv[1]);
rc = sqlite3pager_stmt_rollback(pPager);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
}
return TCL_OK;
}
/*
** Usage: pager_stmt_commit ID
**
** Commit changes to a checkpoint
*/
static int pager_stmt_commit(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
Pager *pPager;
int rc;
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ID\"", 0);
return TCL_ERROR;
}
pPager = sqlite3TextToPtr(argv[1]);
rc = sqlite3pager_stmt_commit(pPager);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
}
return TCL_OK;
}
/*
** Usage: pager_stats ID
**
** Return pager statistics.
*/
static int pager_stats(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
Pager *pPager;
int i, *a;
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ID\"", 0);
return TCL_ERROR;
}
pPager = sqlite3TextToPtr(argv[1]);
a = sqlite3pager_stats(pPager);
for(i=0; i<9; i++){
static char *zName[] = {
"ref", "page", "max", "size", "state", "err",
"hit", "miss", "ovfl",
};
char zBuf[100];
Tcl_AppendElement(interp, zName[i]);
sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",a[i]);
Tcl_AppendElement(interp, zBuf);
}
return TCL_OK;
}
/*
** Usage: pager_pagecount ID
**
** Return the size of the database file.
*/
static int pager_pagecount(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
Pager *pPager;
char zBuf[100];
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ID\"", 0);
return TCL_ERROR;
}
pPager = sqlite3TextToPtr(argv[1]);
sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",sqlite3pager_pagecount(pPager));
Tcl_AppendResult(interp, zBuf, 0);
return TCL_OK;
}
/*
** Usage: page_get ID PGNO
**
** Return a pointer to a page from the database.
*/
static int page_get(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
Pager *pPager;
char zBuf[100];
void *pPage;
int pgno;
int rc;
if( argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ID PGNO\"", 0);
return TCL_ERROR;
}
pPager = sqlite3TextToPtr(argv[1]);
if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR;
rc = sqlite3pager_get(pPager, pgno, &pPage);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
}
sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPage);
Tcl_AppendResult(interp, zBuf, 0);
return TCL_OK;
}
/*
** Usage: page_lookup ID PGNO
**
** Return a pointer to a page if the page is already in cache.
** If not in cache, return an empty string.
*/
static int page_lookup(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
Pager *pPager;
char zBuf[100];
void *pPage;
int pgno;
if( argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ID PGNO\"", 0);
return TCL_ERROR;
}
pPager = sqlite3TextToPtr(argv[1]);
if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR;
pPage = sqlite3pager_lookup(pPager, pgno);
if( pPage ){
sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPage);
Tcl_AppendResult(interp, zBuf, 0);
}
return TCL_OK;
}
/*
** Usage: page_unref PAGE
**
** Drop a pointer to a page.
*/
static int page_unref(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
void *pPage;
int rc;
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" PAGE\"", 0);
return TCL_ERROR;
}
pPage = sqlite3TextToPtr(argv[1]);
rc = sqlite3pager_unref(pPage);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
}
return TCL_OK;
}
/*
** Usage: page_read PAGE
**
** Return the content of a page
*/
static int page_read(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
char zBuf[100];
void *pPage;
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" PAGE\"", 0);
return TCL_ERROR;
}
pPage = sqlite3TextToPtr(argv[1]);
memcpy(zBuf, pPage, sizeof(zBuf));
Tcl_AppendResult(interp, zBuf, 0);
return TCL_OK;
}
/*
** Usage: page_number PAGE
**
** Return the page number for a page.
*/
static int page_number(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
char zBuf[100];
void *pPage;
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" PAGE\"", 0);
return TCL_ERROR;
}
pPage = sqlite3TextToPtr(argv[1]);
sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", sqlite3pager_pagenumber(pPage));
Tcl_AppendResult(interp, zBuf, 0);
return TCL_OK;
}
/*
** Usage: page_write PAGE DATA
**
** Write something into a page.
*/
static int page_write(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
void *pPage;
int rc;
if( argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" PAGE DATA\"", 0);
return TCL_ERROR;
}
pPage = sqlite3TextToPtr(argv[1]);
rc = sqlite3pager_write(pPage);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
}
strncpy((char*)pPage, argv[2], test_pagesize-1);
((char*)pPage)[test_pagesize-1] = 0;
return TCL_OK;
}
/*
** Usage: fake_big_file N FILENAME
**
** Write a few bytes at the N megabyte point of FILENAME. This will
** create a large file. If the file was a valid SQLite database, then
** the next time the database is opened, SQLite will begin allocating
** new pages after N. If N is 2096 or bigger, this will test the
** ability of SQLite to write to large files.
*/
static int fake_big_file(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
int rc;
int n;
i64 offset;
OsFile fd;
int readOnly = 0;
if( argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" N-MEGABYTES FILE\"", 0);
return TCL_ERROR;
}
if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
memset(&fd, 0, sizeof(fd));
rc = sqlite3OsOpenReadWrite(argv[2], &fd, &readOnly);
if( rc ){
Tcl_AppendResult(interp, "open failed: ", errorName(rc), 0);
return TCL_ERROR;
}
offset = n;
offset *= 1024*1024;
rc = sqlite3OsSeek(&fd, offset);
if( rc ){
Tcl_AppendResult(interp, "seek failed: ", errorName(rc), 0);
return TCL_ERROR;
}
rc = sqlite3OsWrite(&fd, "Hello, World!", 14);
sqlite3OsClose(&fd);
if( rc ){
Tcl_AppendResult(interp, "write failed: ", errorName(rc), 0);
return TCL_ERROR;
}
return TCL_OK;
}
/*
** Register commands with the TCL interpreter.
*/
int Sqlitetest2_Init(Tcl_Interp *interp){
extern int sqlite3_io_error_pending;
extern int sqlite3_diskfull_pending;
static struct {
char *zName;
Tcl_CmdProc *xProc;
} aCmd[] = {
{ "pager_open", (Tcl_CmdProc*)pager_open },
{ "pager_close", (Tcl_CmdProc*)pager_close },
{ "pager_commit", (Tcl_CmdProc*)pager_commit },
{ "pager_rollback", (Tcl_CmdProc*)pager_rollback },
{ "pager_stmt_begin", (Tcl_CmdProc*)pager_stmt_begin },
{ "pager_stmt_commit", (Tcl_CmdProc*)pager_stmt_commit },
{ "pager_stmt_rollback", (Tcl_CmdProc*)pager_stmt_rollback },
{ "pager_stats", (Tcl_CmdProc*)pager_stats },
{ "pager_pagecount", (Tcl_CmdProc*)pager_pagecount },
{ "page_get", (Tcl_CmdProc*)page_get },
{ "page_lookup", (Tcl_CmdProc*)page_lookup },
{ "page_unref", (Tcl_CmdProc*)page_unref },
{ "page_read", (Tcl_CmdProc*)page_read },
{ "page_write", (Tcl_CmdProc*)page_write },
{ "page_number", (Tcl_CmdProc*)page_number },
{ "fake_big_file", (Tcl_CmdProc*)fake_big_file },
};
int i;
for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
}
Tcl_LinkVar(interp, "sqlite_io_error_pending",
(char*)&sqlite3_io_error_pending, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_diskfull_pending",
(char*)&sqlite3_diskfull_pending, TCL_LINK_INT);
Tcl_LinkVar(interp, "pager_pagesize",
(char*)&test_pagesize, TCL_LINK_INT);
return TCL_OK;
}
File diff suppressed because it is too large. Load diff
-650
View File
@@ -1,650 +0,0 @@
/*
** 2003 December 18
**
** 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.
**
*************************************************************************
** Code for testing the the SQLite library in a multithreaded environment.
**
** $Id$
*/
#include "sqliteInt.h"
#include "tcl.h"
#include "os.h"
#if defined(OS_UNIX) && OS_UNIX==1 && defined(THREADSAFE) && THREADSAFE==1
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sched.h>
#include <ctype.h>
/*
** Each thread is controlled by an instance of the following
** structure.
*/
typedef struct Thread Thread;
struct Thread {
/* The first group of fields are writable by the master and read-only
** to the thread. */
char *zFilename; /* Name of database file */
void (*xOp)(Thread*); /* next operation to do */
char *zArg; /* argument usable by xOp */
int opnum; /* Operation number */
int busy; /* True if this thread is in use */
/* The next group of fields are writable by the thread but read-only to the
** master. */
int completed; /* Number of operations completed */
sqlite3 *db; /* Open database */
sqlite3_stmt *pStmt; /* Pending operation */
char *zErr; /* operation error */
char *zStaticErr; /* Static error message */
int rc; /* operation return code */
int argc; /* number of columns in result */
const char *argv[100]; /* result columns */
const char *colv[100]; /* result column names */
};
/*
** There can be as many as 26 threads running at once. Each is named
** by a capital letter: A, B, C, ..., Y, Z.
*/
#define N_THREAD 26
static Thread threadset[N_THREAD];
/*
** The main loop for a thread. Threads use busy waiting.
*/
static void *thread_main(void *pArg){
Thread *p = (Thread*)pArg;
if( p->db ){
sqlite3_close(p->db);
}
sqlite3_open(p->zFilename, &p->db);
if( SQLITE_OK!=sqlite3_errcode(p->db) ){
p->zErr = strdup(sqlite3_errmsg(p->db));
sqlite3_close(p->db);
p->db = 0;
}
p->pStmt = 0;
p->completed = 1;
while( p->opnum<=p->completed ) sched_yield();
while( p->xOp ){
if( p->zErr && p->zErr!=p->zStaticErr ){
sqlite3_free(p->zErr);
p->zErr = 0;
}
(*p->xOp)(p);
p->completed++;
while( p->opnum<=p->completed ) sched_yield();
}
if( p->pStmt ){
sqlite3_finalize(p->pStmt);
p->pStmt = 0;
}
if( p->db ){
sqlite3_close(p->db);
p->db = 0;
}
if( p->zErr && p->zErr!=p->zStaticErr ){
sqlite3_free(p->zErr);
p->zErr = 0;
}
p->completed++;
return 0;
}
/*
** Get a thread ID which is an upper case letter. Return the index.
** If the argument is not a valid thread ID put an error message in
** the interpreter and return -1.
*/
static int parse_thread_id(Tcl_Interp *interp, const char *zArg){
if( zArg==0 || zArg[0]==0 || zArg[1]!=0 || !isupper((unsigned char)zArg[0]) ){
Tcl_AppendResult(interp, "thread ID must be an upper case letter", 0);
return -1;
}
return zArg[0] - 'A';
}
/*
** Usage: thread_create NAME FILENAME
**
** NAME should be an upper case letter. Start the thread running with
** an open connection to the given database.
*/
static int tcl_thread_create(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
int i;
pthread_t x;
int rc;
if( argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ID FILENAME", 0);
return TCL_ERROR;
}
i = parse_thread_id(interp, argv[1]);
if( i<0 ) return TCL_ERROR;
if( threadset[i].busy ){
Tcl_AppendResult(interp, "thread ", argv[1], " is already running", 0);
return TCL_ERROR;
}
threadset[i].busy = 1;
sqliteFree(threadset[i].zFilename);
threadset[i].zFilename = sqliteStrDup(argv[2]);
threadset[i].opnum = 1;
threadset[i].completed = 0;
rc = pthread_create(&x, 0, thread_main, &threadset[i]);
if( rc ){
Tcl_AppendResult(interp, "failed to create the thread", 0);
sqliteFree(threadset[i].zFilename);
threadset[i].busy = 0;
return TCL_ERROR;
}
pthread_detach(x);
return TCL_OK;
}
/*
** Wait for a thread to reach its idle state.
*/
static void thread_wait(Thread *p){
while( p->opnum>p->completed ) sched_yield();
}
/*
** Usage: thread_wait ID
**
** Wait on thread ID to reach its idle state.
*/
static int tcl_thread_wait(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
int i;
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ID", 0);
return TCL_ERROR;
}
i = parse_thread_id(interp, argv[1]);
if( i<0 ) return TCL_ERROR;
if( !threadset[i].busy ){
Tcl_AppendResult(interp, "no such thread", 0);
return TCL_ERROR;
}
thread_wait(&threadset[i]);
return TCL_OK;
}
/*
** Stop a thread.
*/
static void stop_thread(Thread *p){
thread_wait(p);
p->xOp = 0;
p->opnum++;
thread_wait(p);
sqliteFree(p->zArg);
p->zArg = 0;
sqliteFree(p->zFilename);
p->zFilename = 0;
p->busy = 0;
}
/*
** Usage: thread_halt ID
**
** Cause a thread to shut itself down. Wait for the shutdown to be
** completed. If ID is "*" then stop all threads.
*/
static int tcl_thread_halt(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
int i;
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ID", 0);
return TCL_ERROR;
}
if( argv[1][0]=='*' && argv[1][1]==0 ){
for(i=0; i<N_THREAD; i++){
if( threadset[i].busy ) stop_thread(&threadset[i]);
}
}else{
i = parse_thread_id(interp, argv[1]);
if( i<0 ) return TCL_ERROR;
if( !threadset[i].busy ){
Tcl_AppendResult(interp, "no such thread", 0);
return TCL_ERROR;
}
stop_thread(&threadset[i]);
}
return TCL_OK;
}
/*
** Usage: thread_argc ID
**
** Wait on the most recent thread_step to complete, then return the
** number of columns in the result set.
*/
static int tcl_thread_argc(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
int i;
char zBuf[100];
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ID", 0);
return TCL_ERROR;
}
i = parse_thread_id(interp, argv[1]);
if( i<0 ) return TCL_ERROR;
if( !threadset[i].busy ){
Tcl_AppendResult(interp, "no such thread", 0);
return TCL_ERROR;
}
thread_wait(&threadset[i]);
sprintf(zBuf, "%d", threadset[i].argc);
Tcl_AppendResult(interp, zBuf, 0);
return TCL_OK;
}
/*
** Usage: thread_argv ID N
**
** Wait on the most recent thread_step to complete, then return the
** value of the N-th columns in the result set.
*/
static int tcl_thread_argv(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
int i;
int n;
if( argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ID N", 0);
return TCL_ERROR;
}
i = parse_thread_id(interp, argv[1]);
if( i<0 ) return TCL_ERROR;
if( !threadset[i].busy ){
Tcl_AppendResult(interp, "no such thread", 0);
return TCL_ERROR;
}
if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR;
thread_wait(&threadset[i]);
if( n<0 || n>=threadset[i].argc ){
Tcl_AppendResult(interp, "column number out of range", 0);
return TCL_ERROR;
}
Tcl_AppendResult(interp, threadset[i].argv[n], 0);
return TCL_OK;
}
/*
** Usage: thread_colname ID N
**
** Wait on the most recent thread_step to complete, then return the
** name of the N-th columns in the result set.
*/
static int tcl_thread_colname(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
int i;
int n;
if( argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ID N", 0);
return TCL_ERROR;
}
i = parse_thread_id(interp, argv[1]);
if( i<0 ) return TCL_ERROR;
if( !threadset[i].busy ){
Tcl_AppendResult(interp, "no such thread", 0);
return TCL_ERROR;
}
if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR;
thread_wait(&threadset[i]);
if( n<0 || n>=threadset[i].argc ){
Tcl_AppendResult(interp, "column number out of range", 0);
return TCL_ERROR;
}
Tcl_AppendResult(interp, threadset[i].colv[n], 0);
return TCL_OK;
}
/*
** Usage: thread_result ID
**
** Wait on the most recent operation to complete, then return the
** result code from that operation.
*/
static int tcl_thread_result(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
int i;
const char *zName;
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ID", 0);
return TCL_ERROR;
}
i = parse_thread_id(interp, argv[1]);
if( i<0 ) return TCL_ERROR;
if( !threadset[i].busy ){
Tcl_AppendResult(interp, "no such thread", 0);
return TCL_ERROR;
}
thread_wait(&threadset[i]);
switch( threadset[i].rc ){
case SQLITE_OK: zName = "SQLITE_OK"; break;
case SQLITE_ERROR: zName = "SQLITE_ERROR"; break;
case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; break;
case SQLITE_PERM: zName = "SQLITE_PERM"; break;
case SQLITE_ABORT: zName = "SQLITE_ABORT"; break;
case SQLITE_BUSY: zName = "SQLITE_BUSY"; break;
case SQLITE_LOCKED: zName = "SQLITE_LOCKED"; break;
case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break;
case SQLITE_READONLY: zName = "SQLITE_READONLY"; break;
case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break;
case SQLITE_IOERR: zName = "SQLITE_IOERR"; break;
case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break;
case SQLITE_NOTFOUND: zName = "SQLITE_NOTFOUND"; break;
case SQLITE_FULL: zName = "SQLITE_FULL"; break;
case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break;
case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break;
case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break;
case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break;
case SQLITE_TOOBIG: zName = "SQLITE_TOOBIG"; break;
case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT"; break;
case SQLITE_MISMATCH: zName = "SQLITE_MISMATCH"; break;
case SQLITE_MISUSE: zName = "SQLITE_MISUSE"; break;
case SQLITE_NOLFS: zName = "SQLITE_NOLFS"; break;
case SQLITE_AUTH: zName = "SQLITE_AUTH"; break;
case SQLITE_FORMAT: zName = "SQLITE_FORMAT"; break;
case SQLITE_RANGE: zName = "SQLITE_RANGE"; break;
case SQLITE_ROW: zName = "SQLITE_ROW"; break;
case SQLITE_DONE: zName = "SQLITE_DONE"; break;
default: zName = "SQLITE_Unknown"; break;
}
Tcl_AppendResult(interp, zName, 0);
return TCL_OK;
}
/*
** Usage: thread_error ID
**
** Wait on the most recent operation to complete, then return the
** error string.
*/
static int tcl_thread_error(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
int i;
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ID", 0);
return TCL_ERROR;
}
i = parse_thread_id(interp, argv[1]);
if( i<0 ) return TCL_ERROR;
if( !threadset[i].busy ){
Tcl_AppendResult(interp, "no such thread", 0);
return TCL_ERROR;
}
thread_wait(&threadset[i]);
Tcl_AppendResult(interp, threadset[i].zErr, 0);
return TCL_OK;
}
/*
** This procedure runs in the thread to compile an SQL statement.
*/
static void do_compile(Thread *p){
if( p->db==0 ){
p->zErr = p->zStaticErr = "no database is open";
p->rc = SQLITE_ERROR;
return;
}
if( p->pStmt ){
sqlite3_finalize(p->pStmt);
p->pStmt = 0;
}
p->rc = sqlite3_prepare(p->db, p->zArg, -1, &p->pStmt, 0);
}
/*
** Usage: thread_compile ID SQL
**
** Compile a new virtual machine.
*/
static int tcl_thread_compile(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
int i;
if( argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ID SQL", 0);
return TCL_ERROR;
}
i = parse_thread_id(interp, argv[1]);
if( i<0 ) return TCL_ERROR;
if( !threadset[i].busy ){
Tcl_AppendResult(interp, "no such thread", 0);
return TCL_ERROR;
}
thread_wait(&threadset[i]);
threadset[i].xOp = do_compile;
sqliteFree(threadset[i].zArg);
threadset[i].zArg = sqliteStrDup(argv[2]);
threadset[i].opnum++;
return TCL_OK;
}
/*
** This procedure runs in the thread to step the virtual machine.
*/
static void do_step(Thread *p){
int i;
if( p->pStmt==0 ){
p->zErr = p->zStaticErr = "no virtual machine available";
p->rc = SQLITE_ERROR;
return;
}
p->rc = sqlite3_step(p->pStmt);
if( p->rc==SQLITE_ROW ){
p->argc = sqlite3_column_count(p->pStmt);
for(i=0; i<sqlite3_data_count(p->pStmt); i++){
p->argv[i] = sqlite3_column_text(p->pStmt, i);
}
for(i=0; i<p->argc; i++){
p->colv[i] = sqlite3_column_name(p->pStmt, i);
}
}
}
/*
** Usage: thread_step ID
**
** Advance the virtual machine by one step
*/
static int tcl_thread_step(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
int i;
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" IDL", 0);
return TCL_ERROR;
}
i = parse_thread_id(interp, argv[1]);
if( i<0 ) return TCL_ERROR;
if( !threadset[i].busy ){
Tcl_AppendResult(interp, "no such thread", 0);
return TCL_ERROR;
}
thread_wait(&threadset[i]);
threadset[i].xOp = do_step;
threadset[i].opnum++;
return TCL_OK;
}
/*
** This procedure runs in the thread to finalize a virtual machine.
*/
static void do_finalize(Thread *p){
if( p->pStmt==0 ){
p->zErr = p->zStaticErr = "no virtual machine available";
p->rc = SQLITE_ERROR;
return;
}
p->rc = sqlite3_finalize(p->pStmt);
p->pStmt = 0;
}
/*
** Usage: thread_finalize ID
**
** Finalize the virtual machine.
*/
static int tcl_thread_finalize(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
int i;
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" IDL", 0);
return TCL_ERROR;
}
i = parse_thread_id(interp, argv[1]);
if( i<0 ) return TCL_ERROR;
if( !threadset[i].busy ){
Tcl_AppendResult(interp, "no such thread", 0);
return TCL_ERROR;
}
thread_wait(&threadset[i]);
threadset[i].xOp = do_finalize;
sqliteFree(threadset[i].zArg);
threadset[i].zArg = 0;
threadset[i].opnum++;
return TCL_OK;
}
/*
** Usage: thread_swap ID ID
**
** Interchange the sqlite* pointer between two threads.
*/
static int tcl_thread_swap(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
int i, j;
sqlite3 *temp;
if( argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ID1 ID2", 0);
return TCL_ERROR;
}
i = parse_thread_id(interp, argv[1]);
if( i<0 ) return TCL_ERROR;
if( !threadset[i].busy ){
Tcl_AppendResult(interp, "no such thread", 0);
return TCL_ERROR;
}
thread_wait(&threadset[i]);
j = parse_thread_id(interp, argv[2]);
if( j<0 ) return TCL_ERROR;
if( !threadset[j].busy ){
Tcl_AppendResult(interp, "no such thread", 0);
return TCL_ERROR;
}
thread_wait(&threadset[j]);
temp = threadset[i].db;
threadset[i].db = threadset[j].db;
threadset[j].db = temp;
return TCL_OK;
}
/*
** Register commands with the TCL interpreter.
*/
int Sqlitetest4_Init(Tcl_Interp *interp){
static struct {
char *zName;
Tcl_CmdProc *xProc;
} aCmd[] = {
{ "thread_create", (Tcl_CmdProc*)tcl_thread_create },
{ "thread_wait", (Tcl_CmdProc*)tcl_thread_wait },
{ "thread_halt", (Tcl_CmdProc*)tcl_thread_halt },
{ "thread_argc", (Tcl_CmdProc*)tcl_thread_argc },
{ "thread_argv", (Tcl_CmdProc*)tcl_thread_argv },
{ "thread_colname", (Tcl_CmdProc*)tcl_thread_colname },
{ "thread_result", (Tcl_CmdProc*)tcl_thread_result },
{ "thread_error", (Tcl_CmdProc*)tcl_thread_error },
{ "thread_compile", (Tcl_CmdProc*)tcl_thread_compile },
{ "thread_step", (Tcl_CmdProc*)tcl_thread_step },
{ "thread_finalize", (Tcl_CmdProc*)tcl_thread_finalize },
{ "thread_swap", (Tcl_CmdProc*)tcl_thread_swap },
};
int i;
for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
}
return TCL_OK;
}
#else
int Sqlitetest4_Init(Tcl_Interp *interp){ return TCL_OK; }
#endif /* OS_UNIX */
-217
View File
@@ -1,217 +0,0 @@
/*
** 2001 September 15
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing the utf.c module in SQLite. This code
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library. Specifically, the code in this file
** is used for testing the SQLite routines for converting between
** the various supported unicode encodings.
**
** $Id$
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
#include "os.h" /* to get SQLITE_BIGENDIAN */
#include "tcl.h"
#include <stdlib.h>
#include <string.h>
/*
** The first argument is a TCL UTF-8 string. Return the byte array
** object with the encoded representation of the string, including
** the NULL terminator.
*/
static int binarize(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
int len;
char *bytes;
Tcl_Obj *pRet;
assert(objc==2);
bytes = Tcl_GetStringFromObj(objv[1], &len);
pRet = Tcl_NewByteArrayObj(bytes, len+1);
Tcl_SetObjResult(interp, pRet);
return TCL_OK;
}
/*
** Usage: test_value_overhead <repeat-count> <do-calls>.
**
** This routine is used to test the overhead of calls to
** sqlite3_value_text(), on a value that contains a UTF-8 string. The idea
** is to figure out whether or not it is a problem to use sqlite3_value
** structures with collation sequence functions.
**
** If <do-calls> is 0, then the calls to sqlite3_value_text() are not
** actually made.
*/
static int test_value_overhead(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
int do_calls;
int repeat_count;
int i;
Mem val;
const char *zVal;
if( objc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"",
Tcl_GetStringFromObj(objv[0], 0), " <repeat-count> <do-calls>", 0);
return TCL_ERROR;
}
if( Tcl_GetIntFromObj(interp, objv[1], &repeat_count) ) return TCL_ERROR;
if( Tcl_GetIntFromObj(interp, objv[2], &do_calls) ) return TCL_ERROR;
val.flags = MEM_Str|MEM_Term|MEM_Static;
val.z = "hello world";
val.type = SQLITE_TEXT;
val.enc = SQLITE_UTF8;
for(i=0; i<repeat_count; i++){
if( do_calls ){
zVal = sqlite3_value_text(&val);
}
}
return TCL_OK;
}
static u8 name_to_enc(Tcl_Interp *interp, Tcl_Obj *pObj){
struct EncName {
char *zName;
u8 enc;
} encnames[] = {
{ "UTF8", SQLITE_UTF8 },
{ "UTF16LE", SQLITE_UTF16LE },
{ "UTF16BE", SQLITE_UTF16BE },
{ "UTF16", SQLITE_UTF16NATIVE },
{ 0, 0 }
};
struct EncName *pEnc;
char *z = Tcl_GetString(pObj);
for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
if( 0==sqlite3StrICmp(z, pEnc->zName) ){
break;
}
}
if( !pEnc->enc ){
Tcl_AppendResult(interp, "No such encoding: ", z, 0);
}
return pEnc->enc;
}
/*
** Usage: test_translate <string/blob> <from enc> <to enc> ?<transient>?
**
*/
static int test_translate(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
u8 enc_from;
u8 enc_to;
sqlite3_value *pVal;
char *z;
int len;
void (*xDel)(void *p) = SQLITE_STATIC;
if( objc!=4 && objc!=5 ){
Tcl_AppendResult(interp, "wrong # args: should be \"",
Tcl_GetStringFromObj(objv[0], 0),
" <string/blob> <from enc> <to enc>", 0
);
return TCL_ERROR;
}
if( objc==5 ){
xDel = sqlite3FreeX;
}
enc_from = name_to_enc(interp, objv[2]);
if( !enc_from ) return TCL_ERROR;
enc_to = name_to_enc(interp, objv[3]);
if( !enc_to ) return TCL_ERROR;
pVal = sqlite3ValueNew();
if( enc_from==SQLITE_UTF8 ){
z = Tcl_GetString(objv[1]);
if( objc==5 ){
z = sqliteStrDup(z);
}
sqlite3ValueSetStr(pVal, -1, z, enc_from, xDel);
}else{
z = Tcl_GetByteArrayFromObj(objv[1], &len);
if( objc==5 ){
char *zTmp = z;
z = sqliteMalloc(len);
memcpy(z, zTmp, len);
}
sqlite3ValueSetStr(pVal, -1, z, enc_from, xDel);
}
z = (char *)sqlite3ValueText(pVal, enc_to);
len = sqlite3ValueBytes(pVal, enc_to) + (enc_to==SQLITE_UTF8?1:2);
Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(z, len));
sqlite3ValueFree(pVal);
return TCL_OK;
}
/*
** Usage: translate_selftest
**
** Call sqlite3utfSelfTest() to run the internal tests for unicode
** translation. If there is a problem an assert() will fail.
**/
void sqlite3utfSelfTest();
static int test_translate_selftest(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
sqlite3utfSelfTest();
return SQLITE_OK;
}
/*
** Register commands with the TCL interpreter.
*/
int Sqlitetest5_Init(Tcl_Interp *interp){
static struct {
char *zName;
Tcl_ObjCmdProc *xProc;
} aCmd[] = {
{ "binarize", (Tcl_ObjCmdProc*)binarize },
{ "test_value_overhead", (Tcl_ObjCmdProc*)test_value_overhead },
{ "test_translate", (Tcl_ObjCmdProc*)test_translate },
{ "translate_selftest", (Tcl_ObjCmdProc*)test_translate_selftest},
};
int i;
for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
}
return SQLITE_OK;
}
-707
View File
@@ -1,707 +0,0 @@
/*
** 2001 September 15
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** An tokenizer for SQL
**
** This file contains C code that splits an SQL input string up into
** individual tokens and sends those tokens one-by-one over to the
** parser for analysis.
**
** $Id$
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include <stdlib.h>
/*
** This function looks up an identifier to determine if it is a
** keyword. If it is a keyword, the token code of that keyword is
** returned. If the input is not a keyword, TK_ID is returned.
**
** The implementation of this routine was generated by a program,
** mkkeywordhash.c, located in the tool subdirectory of the distribution.
** The output of the mkkeywordhash.c program was manually cut and pasted
** into this file. When the set of keywords for SQLite changes, you
** must modify the mkkeywordhash.c program (to add or remove keywords from
** the data tables) then rerun that program to regenerate this function.
*/
int sqlite3KeywordCode(const char *z, int n){
static const char zText[519] =
"ABORTAFTERALLANDASCATTACHBEFOREBEGINBETWEENBYCASCADECASECHECK"
"COLLATECOMMITCONFLICTCONSTRAINTCREATECROSSDATABASEDEFAULTDEFERRABLE"
"DEFERREDDELETEDESCDETACHDISTINCTDROPEACHELSEENDEXCEPTEXCLUSIVE"
"EXPLAINFAILFOREIGNFROMFULLGLOBGROUPHAVINGIGNOREIMMEDIATEINDEX"
"INITIALLYINNERINSERTINSTEADINTERSECTINTOISNULLJOINKEYLEFTLIKE"
"LIMITMATCHNATURALNOTNULLNULLOFFSETONORDEROUTERPRAGMAPRIMARYRAISE"
"REFERENCESREPLACERESTRICTRIGHTROLLBACKROWSELECTSETSTATEMENTTABLE"
"TEMPORARYTHENTRANSACTIONTRIGGERUNIONUNIQUEUPDATEUSINGVACUUMVALUES"
"VIEWWHENWHERE";
static const unsigned char aHash[154] = {
0, 75, 82, 0, 0, 97, 80, 0, 83, 0, 0, 0, 0,
0, 0, 6, 0, 95, 4, 0, 0, 0, 0, 0, 0, 0,
0, 96, 86, 8, 0, 26, 13, 7, 19, 15, 0, 0, 32,
25, 0, 21, 31, 41, 0, 0, 0, 34, 27, 0, 0, 30,
0, 0, 0, 9, 0, 10, 0, 0, 0, 0, 51, 0, 44,
43, 0, 45, 40, 0, 29, 39, 35, 0, 0, 20, 0, 59,
0, 16, 0, 17, 0, 18, 0, 55, 42, 72, 0, 33, 0,
0, 61, 66, 56, 0, 0, 0, 0, 0, 0, 0, 54, 0,
0, 0, 0, 0, 74, 50, 76, 64, 52, 0, 0, 0, 0,
68, 84, 0, 47, 0, 58, 60, 92, 0, 0, 48, 0, 93,
0, 63, 71, 98, 0, 0, 0, 0, 0, 67, 0, 0, 0,
0, 87, 0, 0, 0, 0, 0, 90, 88, 0, 94,
};
static const unsigned char aNext[98] = {
0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0,
0, 12, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0,
0, 0, 0, 14, 3, 24, 0, 0, 0, 1, 22, 0, 0,
36, 23, 28, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0,
0, 49, 37, 0, 0, 0, 38, 0, 53, 0, 57, 62, 0,
0, 0, 0, 0, 0, 70, 46, 0, 65, 0, 0, 0, 0,
69, 73, 0, 77, 0, 0, 0, 0, 0, 0, 81, 85, 0,
91, 79, 78, 0, 0, 89, 0,
};
static const unsigned char aLen[98] = {
5, 5, 3, 3, 2, 3, 6, 6, 5, 7, 2, 7, 4,
5, 7, 6, 8, 10, 6, 5, 8, 7, 10, 8, 6, 4,
6, 8, 4, 4, 4, 3, 6, 9, 7, 4, 3, 7, 4,
4, 4, 5, 6, 6, 9, 2, 5, 9, 5, 6, 7, 9,
4, 2, 6, 4, 3, 4, 4, 5, 5, 7, 3, 7, 4,
2, 6, 2, 2, 5, 5, 6, 7, 5, 10, 7, 8, 5,
8, 3, 6, 3, 9, 5, 4, 9, 4, 11, 7, 5, 6,
6, 5, 6, 6, 4, 4, 5,
};
static const unsigned short int aOffset[98] = {
0, 5, 10, 13, 16, 16, 19, 25, 31, 36, 43, 45, 52,
56, 61, 68, 74, 82, 92, 98, 103, 111, 118, 128, 136, 142,
146, 152, 160, 164, 168, 172, 175, 181, 190, 197, 201, 201, 208,
212, 216, 220, 225, 231, 237, 246, 246, 251, 260, 265, 271, 278,
287, 291, 291, 297, 301, 304, 308, 312, 317, 322, 329, 329, 336,
340, 340, 346, 348, 348, 353, 358, 364, 371, 376, 386, 393, 401,
406, 414, 417, 423, 426, 435, 440, 440, 449, 453, 464, 471, 476,
482, 488, 493, 499, 505, 509, 513,
};
static const unsigned char aCode[98] = {
TK_ABORT, TK_AFTER, TK_ALL, TK_AND, TK_AS,
TK_ASC, TK_ATTACH, TK_BEFORE, TK_BEGIN, TK_BETWEEN,
TK_BY, TK_CASCADE, TK_CASE, TK_CHECK, TK_COLLATE,
TK_COMMIT, TK_CONFLICT, TK_CONSTRAINT, TK_CREATE, TK_JOIN_KW,
TK_DATABASE, TK_DEFAULT, TK_DEFERRABLE, TK_DEFERRED, TK_DELETE,
TK_DESC, TK_DETACH, TK_DISTINCT, TK_DROP, TK_EACH,
TK_ELSE, TK_END, TK_EXCEPT, TK_EXCLUSIVE, TK_EXPLAIN,
TK_FAIL, TK_FOR, TK_FOREIGN, TK_FROM, TK_JOIN_KW,
TK_GLOB, TK_GROUP, TK_HAVING, TK_IGNORE, TK_IMMEDIATE,
TK_IN, TK_INDEX, TK_INITIALLY, TK_JOIN_KW, TK_INSERT,
TK_INSTEAD, TK_INTERSECT, TK_INTO, TK_IS, TK_ISNULL,
TK_JOIN, TK_KEY, TK_JOIN_KW, TK_LIKE, TK_LIMIT,
TK_MATCH, TK_JOIN_KW, TK_NOT, TK_NOTNULL, TK_NULL,
TK_OF, TK_OFFSET, TK_ON, TK_OR, TK_ORDER,
TK_JOIN_KW, TK_PRAGMA, TK_PRIMARY, TK_RAISE, TK_REFERENCES,
TK_REPLACE, TK_RESTRICT, TK_JOIN_KW, TK_ROLLBACK, TK_ROW,
TK_SELECT, TK_SET, TK_STATEMENT, TK_TABLE, TK_TEMP,
TK_TEMP, TK_THEN, TK_TRANSACTION,TK_TRIGGER, TK_UNION,
TK_UNIQUE, TK_UPDATE, TK_USING, TK_VACUUM, TK_VALUES,
TK_VIEW, TK_WHEN, TK_WHERE,
};
int h, i;
if( n<2 ) return TK_ID;
h = (sqlite3UpperToLower[((unsigned char*)z)[0]]*5 +
sqlite3UpperToLower[((unsigned char*)z)[n-1]]*3 +
n) % 154;
for(i=((int)aHash[h])-1; i>=0; i=((int)aNext[i])-1){
if( aLen[i]==n && sqlite3StrNICmp(&zText[aOffset[i]],z,n)==0 ){
return aCode[i];
}
}
return TK_ID;
}
/*
** If X is a character that can be used in an identifier and
** X&0x80==0 then isIdChar[X] will be 1. If X&0x80==0x80 then
** X is always an identifier character. (Hence all UTF-8
** characters can be part of an identifier). isIdChar[X] will
** be 0 for every character in the lower 128 ASCII characters
** that cannot be used as part of an identifier.
**
** In this implementation, an identifier can be a string of
** alphabetic characters, digits, and "_" plus any character
** with the high-order bit set. The latter rule means that
** any sequence of UTF-8 characters or characters taken from
** an extended ISO8859 character set can form an identifier.
*/
static const char isIdChar[] = {
/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */
};
#define IdChar(C) (((c=C)&0x80)!=0 || (c>0x2f && isIdChar[c-0x30]))
/*
** Return the length of the token that begins at z[0].
** Store the token type in *tokenType before returning.
*/
static int sqliteGetToken(const unsigned char *z, int *tokenType){
int i, c;
switch( *z ){
case ' ': case '\t': case '\n': case '\f': case '\r': {
for(i=1; isspace(z[i]); i++){}
*tokenType = TK_SPACE;
return i;
}
case '-': {
if( z[1]=='-' ){
for(i=2; (c=z[i])!=0 && c!='\n'; i++){}
*tokenType = TK_COMMENT;
return i;
}
*tokenType = TK_MINUS;
return 1;
}
case '(': {
*tokenType = TK_LP;
return 1;
}
case ')': {
*tokenType = TK_RP;
return 1;
}
case ';': {
*tokenType = TK_SEMI;
return 1;
}
case '+': {
*tokenType = TK_PLUS;
return 1;
}
case '*': {
*tokenType = TK_STAR;
return 1;
}
case '/': {
if( z[1]!='*' || z[2]==0 ){
*tokenType = TK_SLASH;
return 1;
}
for(i=3, c=z[2]; (c!='*' || z[i]!='/') && (c=z[i])!=0; i++){}
if( c ) i++;
*tokenType = TK_COMMENT;
return i;
}
case '%': {
*tokenType = TK_REM;
return 1;
}
case '=': {
*tokenType = TK_EQ;
return 1 + (z[1]=='=');
}
case '<': {
if( (c=z[1])=='=' ){
*tokenType = TK_LE;
return 2;
}else if( c=='>' ){
*tokenType = TK_NE;
return 2;
}else if( c=='<' ){
*tokenType = TK_LSHIFT;
return 2;
}else{
*tokenType = TK_LT;
return 1;
}
}
case '>': {
if( (c=z[1])=='=' ){
*tokenType = TK_GE;
return 2;
}else if( c=='>' ){
*tokenType = TK_RSHIFT;
return 2;
}else{
*tokenType = TK_GT;
return 1;
}
}
case '!': {
if( z[1]!='=' ){
*tokenType = TK_ILLEGAL;
return 2;
}else{
*tokenType = TK_NE;
return 2;
}
}
case '|': {
if( z[1]!='|' ){
*tokenType = TK_BITOR;
return 1;
}else{
*tokenType = TK_CONCAT;
return 2;
}
}
case ',': {
*tokenType = TK_COMMA;
return 1;
}
case '&': {
*tokenType = TK_BITAND;
return 1;
}
case '~': {
*tokenType = TK_BITNOT;
return 1;
}
case '\'': case '"': {
int delim = z[0];
for(i=1; (c=z[i])!=0; i++){
if( c==delim ){
if( z[i+1]==delim ){
i++;
}else{
break;
}
}
}
if( c ) i++;
*tokenType = TK_STRING;
return i;
}
case '.': {
*tokenType = TK_DOT;
return 1;
}
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': {
*tokenType = TK_INTEGER;
for(i=1; isdigit(z[i]); i++){}
if( z[i]=='.' && isdigit(z[i+1]) ){
i += 2;
while( isdigit(z[i]) ){ i++; }
*tokenType = TK_FLOAT;
}
if( (z[i]=='e' || z[i]=='E') &&
( isdigit(z[i+1])
|| ((z[i+1]=='+' || z[i+1]=='-') && isdigit(z[i+2]))
)
){
i += 2;
while( isdigit(z[i]) ){ i++; }
*tokenType = TK_FLOAT;
}
return i;
}
case '[': {
for(i=1, c=z[0]; c!=']' && (c=z[i])!=0; i++){}
*tokenType = TK_ID;
return i;
}
case '?': {
*tokenType = TK_VARIABLE;
for(i=1; isdigit(z[i]); i++){}
return i;
}
case ':': {
for(i=1; IdChar(z[i]); i++){}
*tokenType = i>1 ? TK_VARIABLE : TK_ILLEGAL;
return i;
}
case '$': {
*tokenType = TK_VARIABLE;
if( z[1]=='{' ){
int nBrace = 1;
for(i=2; (c=z[i])!=0 && nBrace; i++){
if( c=='{' ){
nBrace++;
}else if( c=='}' ){
nBrace--;
}
}
if( c==0 ) *tokenType = TK_ILLEGAL;
}else{
int n = 0;
for(i=1; (c=z[i])!=0; i++){
if( isalnum(c) || c=='_' ){
n++;
}else if( c=='(' && n>0 ){
do{
i++;
}while( (c=z[i])!=0 && !isspace(c) && c!=')' );
if( c==')' ){
i++;
}else{
*tokenType = TK_ILLEGAL;
}
break;
}else if( c==':' && z[i+1]==':' ){
i++;
}else{
break;
}
}
if( n==0 ) *tokenType = TK_ILLEGAL;
}
return i;
}
case 'x': case 'X': {
if( (c=z[1])=='\'' || c=='"' ){
int delim = c;
*tokenType = TK_BLOB;
for(i=2; (c=z[i])!=0; i++){
if( c==delim ){
if( i%2 ) *tokenType = TK_ILLEGAL;
break;
}
if( !isxdigit(c) ){
*tokenType = TK_ILLEGAL;
return i;
}
}
if( c ) i++;
return i;
}
/* Otherwise fall through to the next case */
}
default: {
if( !IdChar(*z) ){
break;
}
for(i=1; IdChar(z[i]); i++){}
*tokenType = sqlite3KeywordCode((char*)z, i);
return i;
}
}
*tokenType = TK_ILLEGAL;
return 1;
}
/*
** Run the parser on the given SQL string. The parser structure is
** passed in. An SQLITE_ status code is returned. If an error occurs
** and pzErrMsg!=NULL then an error message might be written into
** memory obtained from malloc() and *pzErrMsg made to point to that
** error message. Or maybe not.
*/
int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
int nErr = 0;
int i;
void *pEngine;
int tokenType;
int lastTokenParsed = -1;
sqlite3 *db = pParse->db;
extern void *sqlite3ParserAlloc(void*(*)(int));
extern void sqlite3ParserFree(void*, void(*)(void*));
extern int sqlite3Parser(void*, int, Token, Parse*);
db->flags &= ~SQLITE_Interrupt;
pParse->rc = SQLITE_OK;
i = 0;
pEngine = sqlite3ParserAlloc((void*(*)(int))malloc);
if( pEngine==0 ){
sqlite3SetString(pzErrMsg, "out of memory", (char*)0);
return 1;
}
assert( pParse->sLastToken.dyn==0 );
assert( pParse->pNewTable==0 );
assert( pParse->pNewTrigger==0 );
assert( pParse->nVar==0 );
assert( pParse->nVarExpr==0 );
assert( pParse->nVarExprAlloc==0 );
assert( pParse->apVarExpr==0 );
pParse->zTail = pParse->zSql = zSql;
while( sqlite3_malloc_failed==0 && zSql[i]!=0 ){
assert( i>=0 );
pParse->sLastToken.z = &zSql[i];
assert( pParse->sLastToken.dyn==0 );
pParse->sLastToken.n = sqliteGetToken((unsigned char*)&zSql[i], &tokenType);
i += pParse->sLastToken.n;
switch( tokenType ){
case TK_SPACE:
case TK_COMMENT: {
if( (db->flags & SQLITE_Interrupt)!=0 ){
pParse->rc = SQLITE_INTERRUPT;
sqlite3SetString(pzErrMsg, "interrupt", (char*)0);
goto abort_parse;
}
break;
}
case TK_ILLEGAL: {
if( pzErrMsg ){
sqliteFree(*pzErrMsg);
*pzErrMsg = sqlite3MPrintf("unrecognized token: \"%T\"",
&pParse->sLastToken);
}
nErr++;
goto abort_parse;
}
case TK_SEMI: {
pParse->zTail = &zSql[i];
/* Fall thru into the default case */
}
default: {
sqlite3Parser(pEngine, tokenType, pParse->sLastToken, pParse);
lastTokenParsed = tokenType;
if( pParse->rc!=SQLITE_OK ){
goto abort_parse;
}
break;
}
}
}
abort_parse:
if( zSql[i]==0 && nErr==0 && pParse->rc==SQLITE_OK ){
if( lastTokenParsed!=TK_SEMI ){
sqlite3Parser(pEngine, TK_SEMI, pParse->sLastToken, pParse);
pParse->zTail = &zSql[i];
}
sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse);
}
sqlite3ParserFree(pEngine, free);
if( sqlite3_malloc_failed ){
pParse->rc = SQLITE_NOMEM;
}
if( pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE && pParse->zErrMsg==0 ){
sqlite3SetString(&pParse->zErrMsg, sqlite3ErrStr(pParse->rc),
(char*)0);
}
if( pParse->zErrMsg ){
if( pzErrMsg && *pzErrMsg==0 ){
*pzErrMsg = pParse->zErrMsg;
}else{
sqliteFree(pParse->zErrMsg);
}
pParse->zErrMsg = 0;
if( !nErr ) nErr++;
}
if( pParse->pVdbe && pParse->nErr>0 ){
sqlite3VdbeDelete(pParse->pVdbe);
pParse->pVdbe = 0;
}
sqlite3DeleteTable(pParse->db, pParse->pNewTable);
sqlite3DeleteTrigger(pParse->pNewTrigger);
sqliteFree(pParse->apVarExpr);
if( nErr>0 && (pParse->rc==SQLITE_OK || pParse->rc==SQLITE_DONE) ){
pParse->rc = SQLITE_ERROR;
}
return nErr;
}
/*
** Token types used by the sqlite3_complete() routine. See the header
** comments on that procedure for additional information.
*/
#define tkEXPLAIN 0
#define tkCREATE 1
#define tkTEMP 2
#define tkTRIGGER 3
#define tkEND 4
#define tkSEMI 5
#define tkWS 6
#define tkOTHER 7
/*
** Return TRUE if the given SQL string ends in a semicolon.
**
** Special handling is require for CREATE TRIGGER statements.
** Whenever the CREATE TRIGGER keywords are seen, the statement
** must end with ";END;".
**
** This implementation uses a state machine with 7 states:
**
** (0) START At the beginning or end of an SQL statement. This routine
** returns 1 if it ends in the START state and 0 if it ends
** in any other state.
**
** (1) EXPLAIN The keyword EXPLAIN has been seen at the beginning of
** a statement.
**
** (2) CREATE The keyword CREATE has been seen at the beginning of a
** statement, possibly preceeded by EXPLAIN and/or followed by
** TEMP or TEMPORARY
**
** (3) NORMAL We are in the middle of statement which ends with a single
** semicolon.
**
** (4) TRIGGER We are in the middle of a trigger definition that must be
** ended by a semicolon, the keyword END, and another semicolon.
**
** (5) SEMI We've seen the first semicolon in the ";END;" that occurs at
** the end of a trigger definition.
**
** (6) END We've seen the ";END" of the ";END;" that occurs at the end
** of a trigger difinition.
**
** Transitions between states above are determined by tokens extracted
** from the input. The following tokens are significant:
**
** (0) tkEXPLAIN The "explain" keyword.
** (1) tkCREATE The "create" keyword.
** (2) tkTEMP The "temp" or "temporary" keyword.
** (3) tkTRIGGER The "trigger" keyword.
** (4) tkEND The "end" keyword.
** (5) tkSEMI A semicolon.
** (6) tkWS Whitespace
** (7) tkOTHER Any other SQL token.
**
** Whitespace never causes a state transition and is always ignored.
*/
int sqlite3_complete(const char *zSql){
u8 state = 0; /* Current state, using numbers defined in header comment */
u8 token; /* Value of the next token */
/* The following matrix defines the transition from one state to another
** according to what token is seen. trans[state][token] returns the
** next state.
*/
static const u8 trans[7][8] = {
/* Token: */
/* State: ** EXPLAIN CREATE TEMP TRIGGER END SEMI WS OTHER */
/* 0 START: */ { 1, 2, 3, 3, 3, 0, 0, 3, },
/* 1 EXPLAIN: */ { 3, 2, 3, 3, 3, 0, 1, 3, },
/* 2 CREATE: */ { 3, 3, 2, 4, 3, 0, 2, 3, },
/* 3 NORMAL: */ { 3, 3, 3, 3, 3, 0, 3, 3, },
/* 4 TRIGGER: */ { 4, 4, 4, 4, 4, 5, 4, 4, },
/* 5 SEMI: */ { 4, 4, 4, 4, 6, 5, 5, 4, },
/* 6 END: */ { 4, 4, 4, 4, 4, 0, 6, 4, },
};
while( *zSql ){
switch( *zSql ){
case ';': { /* A semicolon */
token = tkSEMI;
break;
}
case ' ':
case '\r':
case '\t':
case '\n':
case '\f': { /* White space is ignored */
token = tkWS;
break;
}
case '/': { /* C-style comments */
if( zSql[1]!='*' ){
token = tkOTHER;
break;
}
zSql += 2;
while( zSql[0] && (zSql[0]!='*' || zSql[1]!='/') ){ zSql++; }
if( zSql[0]==0 ) return 0;
zSql++;
token = tkWS;
break;
}
case '-': { /* SQL-style comments from "--" to end of line */
if( zSql[1]!='-' ){
token = tkOTHER;
break;
}
while( *zSql && *zSql!='\n' ){ zSql++; }
if( *zSql==0 ) return state==0;
token = tkWS;
break;
}
case '[': { /* Microsoft-style identifiers in [...] */
zSql++;
while( *zSql && *zSql!=']' ){ zSql++; }
if( *zSql==0 ) return 0;
token = tkOTHER;
break;
}
case '"': /* single- and double-quoted strings */
case '\'': {
int c = *zSql;
zSql++;
while( *zSql && *zSql!=c ){ zSql++; }
if( *zSql==0 ) return 0;
token = tkOTHER;
break;
}
default: {
int c;
if( IdChar((u8)*zSql) ){
/* Keywords and unquoted identifiers */
int nId;
for(nId=1; IdChar(zSql[nId]); nId++){}
switch( *zSql ){
case 'c': case 'C': {
if( nId==6 && sqlite3StrNICmp(zSql, "create", 6)==0 ){
token = tkCREATE;
}else{
token = tkOTHER;
}
break;
}
case 't': case 'T': {
if( nId==7 && sqlite3StrNICmp(zSql, "trigger", 7)==0 ){
token = tkTRIGGER;
}else if( nId==4 && sqlite3StrNICmp(zSql, "temp", 4)==0 ){
token = tkTEMP;
}else if( nId==9 && sqlite3StrNICmp(zSql, "temporary", 9)==0 ){
token = tkTEMP;
}else{
token = tkOTHER;
}
break;
}
case 'e': case 'E': {
if( nId==3 && sqlite3StrNICmp(zSql, "end", 3)==0 ){
token = tkEND;
}else if( nId==7 && sqlite3StrNICmp(zSql, "explain", 7)==0 ){
token = tkEXPLAIN;
}else{
token = tkOTHER;
}
break;
}
default: {
token = tkOTHER;
break;
}
}
zSql += nId-1;
}else{
/* Operators and special symbols */
token = tkOTHER;
}
break;
}
}
state = trans[state][token];
zSql++;
}
return state==0;
}
/*
** This routine is the same as the sqlite3_complete() routine described
** above, except that the parameter is required to be UTF-16 encoded, not
** UTF-8.
*/
int sqlite3_complete16(const void *zSql){
sqlite3_value *pVal;
char const *zSql8;
int rc = 0;
pVal = sqlite3ValueNew();
sqlite3ValueSetStr(pVal, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC);
zSql8 = sqlite3ValueText(pVal, SQLITE_UTF8);
if( zSql8 ){
rc = sqlite3_complete(zSql8);
}
sqlite3ValueFree(pVal);
return rc;
}
-804
View File
@@ -1,804 +0,0 @@
/*
**
** 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.
**
*************************************************************************
*
*/
#include "sqliteInt.h"
/*
** Delete a linked list of TriggerStep structures.
*/
void sqlite3DeleteTriggerStep(TriggerStep *pTriggerStep){
while( pTriggerStep ){
TriggerStep * pTmp = pTriggerStep;
pTriggerStep = pTriggerStep->pNext;
if( pTmp->target.dyn ) sqliteFree((char*)pTmp->target.z);
sqlite3ExprDelete(pTmp->pWhere);
sqlite3ExprListDelete(pTmp->pExprList);
sqlite3SelectDelete(pTmp->pSelect);
sqlite3IdListDelete(pTmp->pIdList);
sqliteFree(pTmp);
}
}
/*
** This is called by the parser when it sees a CREATE TRIGGER statement
** up to the point of the BEGIN before the trigger actions. A Trigger
** structure is generated based on the information available and stored
** in pParse->pNewTrigger. After the trigger actions have been parsed, the
** sqlite3FinishTrigger() function is called to complete the trigger
** construction process.
*/
void sqlite3BeginTrigger(
Parse *pParse, /* The parse context of the CREATE TRIGGER statement */
Token *pName1, /* The name of the trigger */
Token *pName2, /* The name of the trigger */
int tr_tm, /* One of TK_BEFORE, TK_AFTER, TK_INSTEAD */
int op, /* One of TK_INSERT, TK_UPDATE, TK_DELETE */
IdList *pColumns, /* column list if this is an UPDATE OF trigger */
SrcList *pTableName,/* The name of the table/view the trigger applies to */
int foreach, /* One of TK_ROW or TK_STATEMENT */
Expr *pWhen, /* WHEN clause */
int isTemp /* True if the TEMPORARY keyword is present */
){
Trigger *pTrigger;
Table *pTab;
char *zName = 0; /* Name of the trigger */
sqlite3 *db = pParse->db;
int iDb; /* The database to store the trigger in */
Token *pName; /* The unqualified db name */
DbFixer sFix;
if( isTemp ){
/* If TEMP was specified, then the trigger name may not be qualified. */
if( pName2 && pName2->n>0 ){
sqlite3ErrorMsg(pParse, "temporary trigger may not have qualified name");
goto trigger_cleanup;
}
iDb = 1;
pName = pName1;
}else{
/* Figure out the db that the the trigger will be created in */
iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName);
if( iDb<0 ){
goto trigger_cleanup;
}
}
/* If the trigger name was unqualified, and the table is a temp table,
** then set iDb to 1 to create the trigger in the temporary database.
** If sqlite3SrcListLookup() returns 0, indicating the table does not
** exist, the error is caught by the block below.
*/
if( !pTableName || sqlite3_malloc_failed ) goto trigger_cleanup;
pTab = sqlite3SrcListLookup(pParse, pTableName);
if( pName2->n==0 && pTab && pTab->iDb==1 ){
iDb = 1;
}
/* Ensure the table name matches database name and that the table exists */
if( sqlite3_malloc_failed ) goto trigger_cleanup;
assert( pTableName->nSrc==1 );
if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName) &&
sqlite3FixSrcList(&sFix, pTableName) ){
goto trigger_cleanup;
}
pTab = sqlite3SrcListLookup(pParse, pTableName);
if( !pTab ){
/* The table does not exist. */
goto trigger_cleanup;
}
/* Check that the trigger name is not reserved and that no trigger of the
** specified name exists */
zName = sqlite3NameFromToken(pName);
if( !zName || SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
goto trigger_cleanup;
}
if( sqlite3HashFind(&(db->aDb[iDb].trigHash), zName,pName->n+1) ){
sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
goto trigger_cleanup;
}
/* Do not create a trigger on a system table */
if( (iDb!=1 && sqlite3StrICmp(pTab->zName, MASTER_NAME)==0) ||
(iDb==1 && sqlite3StrICmp(pTab->zName, TEMP_MASTER_NAME)==0)
){
sqlite3ErrorMsg(pParse, "cannot create trigger on system table");
pParse->nErr++;
goto trigger_cleanup;
}
/* INSTEAD of triggers are only for views and views only support INSTEAD
** of triggers.
*/
if( pTab->pSelect && tr_tm!=TK_INSTEAD ){
sqlite3ErrorMsg(pParse, "cannot create %s trigger on view: %S",
(tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName, 0);
goto trigger_cleanup;
}
if( !pTab->pSelect && tr_tm==TK_INSTEAD ){
sqlite3ErrorMsg(pParse, "cannot create INSTEAD OF"
" trigger on table: %S", pTableName, 0);
goto trigger_cleanup;
}
#ifndef SQLITE_OMIT_AUTHORIZATION
{
int code = SQLITE_CREATE_TRIGGER;
const char *zDb = db->aDb[pTab->iDb].zName;
const char *zDbTrig = isTemp ? db->aDb[1].zName : zDb;
if( pTab->iDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER;
if( sqlite3AuthCheck(pParse, code, zName, pTab->zName, zDbTrig) ){
goto trigger_cleanup;
}
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(pTab->iDb),0,zDb)){
goto trigger_cleanup;
}
}
#endif
/* INSTEAD OF triggers can only appear on views and BEFORE triggers
** cannot appear on views. So we might as well translate every
** INSTEAD OF trigger into a BEFORE trigger. It simplifies code
** elsewhere.
*/
if (tr_tm == TK_INSTEAD){
tr_tm = TK_BEFORE;
}
/* Build the Trigger object */
pTrigger = (Trigger*)sqliteMalloc(sizeof(Trigger));
if( pTrigger==0 ) goto trigger_cleanup;
pTrigger->name = zName;
zName = 0;
pTrigger->table = sqliteStrDup(pTableName->a[0].zName);
if( sqlite3_malloc_failed ) goto trigger_cleanup;
pTrigger->iDb = iDb;
pTrigger->iTabDb = pTab->iDb;
pTrigger->op = op;
pTrigger->tr_tm = tr_tm;
pTrigger->pWhen = sqlite3ExprDup(pWhen);
pTrigger->pColumns = sqlite3IdListDup(pColumns);
pTrigger->foreach = foreach;
sqlite3TokenCopy(&pTrigger->nameToken,pName);
assert( pParse->pNewTrigger==0 );
pParse->pNewTrigger = pTrigger;
trigger_cleanup:
sqliteFree(zName);
sqlite3SrcListDelete(pTableName);
sqlite3IdListDelete(pColumns);
sqlite3ExprDelete(pWhen);
}
/*
** This routine is called after all of the trigger actions have been parsed
** in order to complete the process of building the trigger.
*/
void sqlite3FinishTrigger(
Parse *pParse, /* Parser context */
TriggerStep *pStepList, /* The triggered program */
Token *pAll /* Token that describes the complete CREATE TRIGGER */
){
Trigger *nt = 0; /* The trigger whose construction is finishing up */
sqlite3 *db = pParse->db; /* The database */
DbFixer sFix;
if( pParse->nErr || pParse->pNewTrigger==0 ) goto triggerfinish_cleanup;
nt = pParse->pNewTrigger;
pParse->pNewTrigger = 0;
nt->step_list = pStepList;
while( pStepList ){
pStepList->pTrig = nt;
pStepList = pStepList->pNext;
}
if( sqlite3FixInit(&sFix, pParse, nt->iDb, "trigger", &nt->nameToken)
&& sqlite3FixTriggerStep(&sFix, nt->step_list) ){
goto triggerfinish_cleanup;
}
/* if we are not initializing, and this trigger is not on a TEMP table,
** build the sqlite_master entry
*/
if( !db->init.busy ){
static const VdbeOpList insertTrig[] = {
{ OP_NewRecno, 0, 0, 0 },
{ OP_String8, 0, 0, "trigger" },
{ OP_String8, 0, 0, 0 }, /* 2: trigger name */
{ OP_String8, 0, 0, 0 }, /* 3: table name */
{ OP_Integer, 0, 0, 0 },
{ OP_String8, 0, 0, "CREATE TRIGGER "},
{ OP_String8, 0, 0, 0 }, /* 6: SQL */
{ OP_Concat, 0, 0, 0 },
{ OP_MakeRecord, 5, 0, "tttit" },
{ OP_PutIntKey, 0, 0, 0 },
};
int addr;
Vdbe *v;
/* Make an entry in the sqlite_master table */
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto triggerfinish_cleanup;
sqlite3BeginWriteOperation(pParse, 0, nt->iDb);
sqlite3OpenMasterTable(v, nt->iDb);
addr = sqlite3VdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
sqlite3VdbeChangeP3(v, addr+2, nt->name, 0);
sqlite3VdbeChangeP3(v, addr+3, nt->table, 0);
sqlite3VdbeChangeP3(v, addr+6, pAll->z, pAll->n);
if( nt->iDb!=0 ){
sqlite3ChangeCookie(db, v, nt->iDb);
}
sqlite3VdbeAddOp(v, OP_Close, 0, 0);
sqlite3VdbeOp3(v, OP_ParseSchema, nt->iDb, 0,
sqlite3MPrintf("type='trigger' AND name='%q'", nt->name), P3_DYNAMIC);
}
if( db->init.busy ){
Table *pTab;
sqlite3HashInsert(&db->aDb[nt->iDb].trigHash,
nt->name, strlen(nt->name)+1, nt);
pTab = sqlite3LocateTable(pParse, nt->table, db->aDb[nt->iTabDb].zName);
assert( pTab!=0 );
nt->pNext = pTab->pTrigger;
pTab->pTrigger = nt;
nt = 0;
}
triggerfinish_cleanup:
sqlite3DeleteTrigger(nt);
sqlite3DeleteTrigger(pParse->pNewTrigger);
pParse->pNewTrigger = 0;
sqlite3DeleteTriggerStep(pStepList);
}
/*
** Make a copy of all components of the given trigger step. This has
** the effect of copying all Expr.token.z values into memory obtained
** from sqliteMalloc(). As initially created, the Expr.token.z values
** all point to the input string that was fed to the parser. But that
** string is ephemeral - it will go away as soon as the sqlite3_exec()
** call that started the parser exits. This routine makes a persistent
** copy of all the Expr.token.z strings so that the TriggerStep structure
** will be valid even after the sqlite3_exec() call returns.
*/
static void sqlitePersistTriggerStep(TriggerStep *p){
if( p->target.z ){
p->target.z = sqliteStrNDup(p->target.z, p->target.n);
p->target.dyn = 1;
}
if( p->pSelect ){
Select *pNew = sqlite3SelectDup(p->pSelect);
sqlite3SelectDelete(p->pSelect);
p->pSelect = pNew;
}
if( p->pWhere ){
Expr *pNew = sqlite3ExprDup(p->pWhere);
sqlite3ExprDelete(p->pWhere);
p->pWhere = pNew;
}
if( p->pExprList ){
ExprList *pNew = sqlite3ExprListDup(p->pExprList);
sqlite3ExprListDelete(p->pExprList);
p->pExprList = pNew;
}
if( p->pIdList ){
IdList *pNew = sqlite3IdListDup(p->pIdList);
sqlite3IdListDelete(p->pIdList);
p->pIdList = pNew;
}
}
/*
** Turn a SELECT statement (that the pSelect parameter points to) into
** a trigger step. Return a pointer to a TriggerStep structure.
**
** The parser calls this routine when it finds a SELECT statement in
** body of a TRIGGER.
*/
TriggerStep *sqlite3TriggerSelectStep(Select *pSelect){
TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
if( pTriggerStep==0 ) return 0;
pTriggerStep->op = TK_SELECT;
pTriggerStep->pSelect = pSelect;
pTriggerStep->orconf = OE_Default;
sqlitePersistTriggerStep(pTriggerStep);
return pTriggerStep;
}
/*
** Build a trigger step out of an INSERT statement. Return a pointer
** to the new trigger step.
**
** The parser calls this routine when it sees an INSERT inside the
** body of a trigger.
*/
TriggerStep *sqlite3TriggerInsertStep(
Token *pTableName, /* Name of the table into which we insert */
IdList *pColumn, /* List of columns in pTableName to insert into */
ExprList *pEList, /* The VALUE clause: a list of values to be inserted */
Select *pSelect, /* A SELECT statement that supplies values */
int orconf /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
){
TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
if( pTriggerStep==0 ) return 0;
assert(pEList == 0 || pSelect == 0);
assert(pEList != 0 || pSelect != 0);
pTriggerStep->op = TK_INSERT;
pTriggerStep->pSelect = pSelect;
pTriggerStep->target = *pTableName;
pTriggerStep->pIdList = pColumn;
pTriggerStep->pExprList = pEList;
pTriggerStep->orconf = orconf;
sqlitePersistTriggerStep(pTriggerStep);
return pTriggerStep;
}
/*
** Construct a trigger step that implements an UPDATE statement and return
** a pointer to that trigger step. The parser calls this routine when it
** sees an UPDATE statement inside the body of a CREATE TRIGGER.
*/
TriggerStep *sqlite3TriggerUpdateStep(
Token *pTableName, /* Name of the table to be updated */
ExprList *pEList, /* The SET clause: list of column and new values */
Expr *pWhere, /* The WHERE clause */
int orconf /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
){
TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
if( pTriggerStep==0 ) return 0;
pTriggerStep->op = TK_UPDATE;
pTriggerStep->target = *pTableName;
pTriggerStep->pExprList = pEList;
pTriggerStep->pWhere = pWhere;
pTriggerStep->orconf = orconf;
sqlitePersistTriggerStep(pTriggerStep);
return pTriggerStep;
}
/*
** Construct a trigger step that implements a DELETE statement and return
** a pointer to that trigger step. The parser calls this routine when it
** sees a DELETE statement inside the body of a CREATE TRIGGER.
*/
TriggerStep *sqlite3TriggerDeleteStep(Token *pTableName, Expr *pWhere){
TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
if( pTriggerStep==0 ) return 0;
pTriggerStep->op = TK_DELETE;
pTriggerStep->target = *pTableName;
pTriggerStep->pWhere = pWhere;
pTriggerStep->orconf = OE_Default;
sqlitePersistTriggerStep(pTriggerStep);
return pTriggerStep;
}
/*
** Recursively delete a Trigger structure
*/
void sqlite3DeleteTrigger(Trigger *pTrigger){
if( pTrigger==0 ) return;
sqlite3DeleteTriggerStep(pTrigger->step_list);
sqliteFree(pTrigger->name);
sqliteFree(pTrigger->table);
sqlite3ExprDelete(pTrigger->pWhen);
sqlite3IdListDelete(pTrigger->pColumns);
if( pTrigger->nameToken.dyn ) sqliteFree((char*)pTrigger->nameToken.z);
sqliteFree(pTrigger);
}
/*
** This function is called to drop a trigger from the database schema.
**
** This may be called directly from the parser and therefore identifies
** the trigger by name. The sqlite3DropTriggerPtr() routine does the
** same job as this routine except it takes a pointer to the trigger
** instead of the trigger name.
**/
void sqlite3DropTrigger(Parse *pParse, SrcList *pName){
Trigger *pTrigger = 0;
int i;
const char *zDb;
const char *zName;
int nName;
sqlite3 *db = pParse->db;
if( sqlite3_malloc_failed ) goto drop_trigger_cleanup;
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
goto drop_trigger_cleanup;
}
assert( pName->nSrc==1 );
zDb = pName->a[0].zDatabase;
zName = pName->a[0].zName;
nName = strlen(zName);
for(i=0; i<db->nDb; i++){
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
if( zDb && sqlite3StrICmp(db->aDb[j].zName, zDb) ) continue;
pTrigger = sqlite3HashFind(&(db->aDb[j].trigHash), zName, nName+1);
if( pTrigger ) break;
}
if( !pTrigger ){
sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0);
goto drop_trigger_cleanup;
}
sqlite3DropTriggerPtr(pParse, pTrigger, 0);
drop_trigger_cleanup:
sqlite3SrcListDelete(pName);
}
/*
** Return a pointer to the Table structure for the table that a trigger
** is set on.
*/
static Table *tableOfTrigger(sqlite3 *db, Trigger *pTrigger){
return sqlite3FindTable(db,pTrigger->table,db->aDb[pTrigger->iTabDb].zName);
}
/*
** Drop a trigger given a pointer to that trigger. If nested is false,
** then also generate code to remove the trigger from the SQLITE_MASTER
** table.
*/
void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){
Table *pTable;
Vdbe *v;
sqlite3 *db = pParse->db;
int iDb;
iDb = pTrigger->iDb;
assert( iDb>=0 && iDb<db->nDb );
pTable = tableOfTrigger(db, pTrigger);
assert(pTable);
assert( pTable->iDb==iDb || iDb==1 );
#ifndef SQLITE_OMIT_AUTHORIZATION
{
int code = SQLITE_DROP_TRIGGER;
const char *zDb = db->aDb[iDb].zName;
const char *zTab = SCHEMA_TABLE(iDb);
if( iDb==1 ) code = SQLITE_DROP_TEMP_TRIGGER;
if( sqlite3AuthCheck(pParse, code, pTrigger->name, pTable->zName, zDb) ||
sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
return;
}
}
#endif
/* Generate code to destroy the database record of the trigger.
*/
if( pTable!=0 && (v = sqlite3GetVdbe(pParse))!=0 ){
int base;
static const VdbeOpList dropTrigger[] = {
{ OP_Rewind, 0, ADDR(9), 0},
{ OP_String8, 0, 0, 0}, /* 1 */
{ OP_Column, 0, 1, 0},
{ OP_Ne, 0, ADDR(8), 0},
{ OP_String8, 0, 0, "trigger"},
{ OP_Column, 0, 0, 0},
{ OP_Ne, 0, ADDR(8), 0},
{ OP_Delete, 0, 0, 0},
{ OP_Next, 0, ADDR(1), 0}, /* 8 */
};
sqlite3BeginWriteOperation(pParse, 0, iDb);
sqlite3OpenMasterTable(v, iDb);
base = sqlite3VdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger);
sqlite3VdbeChangeP3(v, base+1, pTrigger->name, 0);
sqlite3ChangeCookie(db, v, iDb);
sqlite3VdbeAddOp(v, OP_Close, 0, 0);
sqlite3VdbeOp3(v, OP_DropTrigger, iDb, 0, pTrigger->name, 0);
}
}
/*
** Remove a trigger from the hash tables of the sqlite* pointer.
*/
void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){
Trigger *pTrigger;
int nName = strlen(zName);
pTrigger = sqlite3HashInsert(&(db->aDb[iDb].trigHash), zName, nName+1, 0);
if( pTrigger ){
Table *pTable = tableOfTrigger(db, pTrigger);
assert( pTable!=0 );
if( pTable->pTrigger == pTrigger ){
pTable->pTrigger = pTrigger->pNext;
}else{
Trigger *cc = pTable->pTrigger;
while( cc ){
if( cc->pNext == pTrigger ){
cc->pNext = cc->pNext->pNext;
break;
}
cc = cc->pNext;
}
assert(cc);
}
sqlite3DeleteTrigger(pTrigger);
db->flags |= SQLITE_InternChanges;
}
}
/*
** pEList is the SET clause of an UPDATE statement. Each entry
** in pEList is of the format <id>=<expr>. If any of the entries
** in pEList have an <id> which matches an identifier in pIdList,
** then return TRUE. If pIdList==NULL, then it is considered a
** wildcard that matches anything. Likewise if pEList==NULL then
** it matches anything so always return true. Return false only
** if there is no match.
*/
static int checkColumnOverLap(IdList *pIdList, ExprList *pEList){
int e;
if( !pIdList || !pEList ) return 1;
for(e=0; e<pEList->nExpr; e++){
if( sqlite3IdListIndex(pIdList, pEList->a[e].zName)>=0 ) return 1;
}
return 0;
}
/* A global variable that is TRUE if we should always set up temp tables for
* for triggers, even if there are no triggers to code. This is used to test
* how much overhead the triggers algorithm is causing.
*
* This flag can be set or cleared using the "trigger_overhead_test" pragma.
* The pragma is not documented since it is not really part of the interface
* to SQLite, just the test procedure.
*/
int sqlite3_always_code_trigger_setup = 0;
/*
* Returns true if a trigger matching op, tr_tm and foreach that is NOT already
* on the Parse objects trigger-stack (to prevent recursive trigger firing) is
* found in the list specified as pTrigger.
*/
int sqlite3TriggersExist(
Parse *pParse, /* Used to check for recursive triggers */
Trigger *pTrigger, /* A list of triggers associated with a table */
int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
int tr_tm, /* one of TK_BEFORE, TK_AFTER */
int foreach, /* one of TK_ROW or TK_STATEMENT */
ExprList *pChanges /* Columns that change in an UPDATE statement */
){
Trigger * pTriggerCursor;
if( sqlite3_always_code_trigger_setup ){
return 1;
}
pTriggerCursor = pTrigger;
while( pTriggerCursor ){
if( pTriggerCursor->op == op &&
pTriggerCursor->tr_tm == tr_tm &&
pTriggerCursor->foreach == foreach &&
checkColumnOverLap(pTriggerCursor->pColumns, pChanges) ){
TriggerStack * ss;
ss = pParse->trigStack;
while( ss && ss->pTrigger != pTrigger ){
ss = ss->pNext;
}
if( !ss )return 1;
}
pTriggerCursor = pTriggerCursor->pNext;
}
return 0;
}
/*
** Convert the pStep->target token into a SrcList and return a pointer
** to that SrcList.
**
** This routine adds a specific database name, if needed, to the target when
** forming the SrcList. This prevents a trigger in one database from
** referring to a target in another database. An exception is when the
** trigger is in TEMP in which case it can refer to any other database it
** wants.
*/
static SrcList *targetSrcList(
Parse *pParse, /* The parsing context */
TriggerStep *pStep /* The trigger containing the target token */
){
Token sDb; /* Dummy database name token */
int iDb; /* Index of the database to use */
SrcList *pSrc; /* SrcList to be returned */
iDb = pStep->pTrig->iDb;
if( iDb==0 || iDb>=2 ){
assert( iDb<pParse->db->nDb );
sDb.z = pParse->db->aDb[iDb].zName;
sDb.n = strlen(sDb.z);
pSrc = sqlite3SrcListAppend(0, &sDb, &pStep->target);
} else {
pSrc = sqlite3SrcListAppend(0, &pStep->target, 0);
}
return pSrc;
}
/*
** Generate VDBE code for zero or more statements inside the body of a
** trigger.
*/
static int codeTriggerProgram(
Parse *pParse, /* The parser context */
TriggerStep *pStepList, /* List of statements inside the trigger body */
int orconfin /* Conflict algorithm. (OE_Abort, etc) */
){
TriggerStep * pTriggerStep = pStepList;
int orconf;
Vdbe *v = pParse->pVdbe;
assert( pTriggerStep!=0 );
assert( v!=0 );
sqlite3VdbeAddOp(v, OP_ContextPush, 0, 0);
VdbeComment((v, "# begin trigger %s", pStepList->pTrig->name));
while( pTriggerStep ){
orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin;
pParse->trigStack->orconf = orconf;
switch( pTriggerStep->op ){
case TK_SELECT: {
Select * ss = sqlite3SelectDup(pTriggerStep->pSelect);
assert(ss);
assert(ss->pSrc);
sqlite3Select(pParse, ss, SRT_Discard, 0, 0, 0, 0, 0);
sqlite3SelectDelete(ss);
break;
}
case TK_UPDATE: {
SrcList *pSrc;
pSrc = targetSrcList(pParse, pTriggerStep);
sqlite3VdbeAddOp(v, OP_ResetCount, 0, 0);
sqlite3Update(pParse, pSrc,
sqlite3ExprListDup(pTriggerStep->pExprList),
sqlite3ExprDup(pTriggerStep->pWhere), orconf);
sqlite3VdbeAddOp(v, OP_ResetCount, 1, 0);
break;
}
case TK_INSERT: {
SrcList *pSrc;
pSrc = targetSrcList(pParse, pTriggerStep);
sqlite3VdbeAddOp(v, OP_ResetCount, 0, 0);
sqlite3Insert(pParse, pSrc,
sqlite3ExprListDup(pTriggerStep->pExprList),
sqlite3SelectDup(pTriggerStep->pSelect),
sqlite3IdListDup(pTriggerStep->pIdList), orconf);
sqlite3VdbeAddOp(v, OP_ResetCount, 1, 0);
break;
}
case TK_DELETE: {
SrcList *pSrc;
sqlite3VdbeAddOp(v, OP_ResetCount, 0, 0);
pSrc = targetSrcList(pParse, pTriggerStep);
sqlite3DeleteFrom(pParse, pSrc, sqlite3ExprDup(pTriggerStep->pWhere));
sqlite3VdbeAddOp(v, OP_ResetCount, 1, 0);
break;
}
default:
assert(0);
}
pTriggerStep = pTriggerStep->pNext;
}
sqlite3VdbeAddOp(v, OP_ContextPop, 0, 0);
VdbeComment((v, "# end trigger %s", pStepList->pTrig->name));
return 0;
}
/*
** This is called to code FOR EACH ROW triggers.
**
** When the code that this function generates is executed, the following
** must be true:
**
** 1. No cursors may be open in the main database. (But newIdx and oldIdx
** can be indices of cursors in temporary tables. See below.)
**
** 2. If the triggers being coded are ON INSERT or ON UPDATE triggers, then
** a temporary vdbe cursor (index newIdx) must be open and pointing at
** a row containing values to be substituted for new.* expressions in the
** trigger program(s).
**
** 3. If the triggers being coded are ON DELETE or ON UPDATE triggers, then
** a temporary vdbe cursor (index oldIdx) must be open and pointing at
** a row containing values to be substituted for old.* expressions in the
** trigger program(s).
**
*/
int sqlite3CodeRowTrigger(
Parse *pParse, /* Parse context */
int op, /* One of TK_UPDATE, TK_INSERT, TK_DELETE */
ExprList *pChanges, /* Changes list for any UPDATE OF triggers */
int tr_tm, /* One of TK_BEFORE, TK_AFTER */
Table *pTab, /* The table to code triggers from */
int newIdx, /* The indice of the "new" row to access */
int oldIdx, /* The indice of the "old" row to access */
int orconf, /* ON CONFLICT policy */
int ignoreJump /* Instruction to jump to for RAISE(IGNORE) */
){
Trigger *pTrigger;
TriggerStack *pStack;
TriggerStack trigStackEntry;
assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);
assert(tr_tm == TK_BEFORE || tr_tm == TK_AFTER );
assert(newIdx != -1 || oldIdx != -1);
pTrigger = pTab->pTrigger;
while( pTrigger ){
int fire_this = 0;
/* determine whether we should code this trigger */
if( pTrigger->op == op && pTrigger->tr_tm == tr_tm &&
pTrigger->foreach == TK_ROW ){
fire_this = 1;
for(pStack=pParse->trigStack; pStack; pStack=pStack->pNext){
if( pStack->pTrigger==pTrigger ){
fire_this = 0;
}
}
if( op == TK_UPDATE && pTrigger->pColumns &&
!checkColumnOverLap(pTrigger->pColumns, pChanges) ){
fire_this = 0;
}
}
if( fire_this ){
int endTrigger;
SrcList dummyTablist;
Expr * whenExpr;
AuthContext sContext;
dummyTablist.nSrc = 0;
/* Push an entry on to the trigger stack */
trigStackEntry.pTrigger = pTrigger;
trigStackEntry.newIdx = newIdx;
trigStackEntry.oldIdx = oldIdx;
trigStackEntry.pTab = pTab;
trigStackEntry.pNext = pParse->trigStack;
trigStackEntry.ignoreJump = ignoreJump;
pParse->trigStack = &trigStackEntry;
sqlite3AuthContextPush(pParse, &sContext, pTrigger->name);
/* code the WHEN clause */
endTrigger = sqlite3VdbeMakeLabel(pParse->pVdbe);
whenExpr = sqlite3ExprDup(pTrigger->pWhen);
if( sqlite3ExprResolveIds(pParse, &dummyTablist, 0, whenExpr) ){
pParse->trigStack = trigStackEntry.pNext;
sqlite3ExprDelete(whenExpr);
return 1;
}
sqlite3ExprIfFalse(pParse, whenExpr, endTrigger, 1);
sqlite3ExprDelete(whenExpr);
codeTriggerProgram(pParse, pTrigger->step_list, orconf);
/* Pop the entry off the trigger stack */
pParse->trigStack = trigStackEntry.pNext;
sqlite3AuthContextPop(&sContext);
sqlite3VdbeResolveLabel(pParse->pVdbe, endTrigger);
}
pTrigger = pTrigger->pNext;
}
return 0;
}
-450
View File
@@ -1,450 +0,0 @@
/*
** 2001 September 15
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
** $Id$
*/
#include "sqliteInt.h"
/*
** Process an UPDATE statement.
**
** UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL;
** \_______/ \________/ \______/ \________________/
* onError pTabList pChanges pWhere
*/
void sqlite3Update(
Parse *pParse, /* The parser context */
SrcList *pTabList, /* The table in which we should change things */
ExprList *pChanges, /* Things to be changed */
Expr *pWhere, /* The WHERE clause. May be null */
int onError /* How to handle constraint errors */
){
int i, j; /* Loop counters */
Table *pTab; /* The table to be updated */
int addr = 0; /* VDBE instruction address of the start of the loop */
WhereInfo *pWInfo; /* Information about the WHERE clause */
Vdbe *v; /* The virtual database engine */
Index *pIdx; /* For looping over indices */
int nIdx; /* Number of indices that need updating */
int nIdxTotal; /* Total number of indices */
int iCur; /* VDBE Cursor number of pTab */
sqlite3 *db; /* The database structure */
Index **apIdx = 0; /* An array of indices that need updating too */
char *aIdxUsed = 0; /* aIdxUsed[i]==1 if the i-th index is used */
int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the
** an expression for the i-th column of the table.
** aXRef[i]==-1 if the i-th column is not changed. */
int chngRecno; /* True if the record number is being changed */
Expr *pRecnoExpr = 0; /* Expression defining the new record number */
int openAll = 0; /* True if all indices need to be opened */
int isView; /* Trying to update a view */
AuthContext sContext; /* The authorization context */
int before_triggers; /* True if there are any BEFORE triggers */
int after_triggers; /* True if there are any AFTER triggers */
int row_triggers_exist = 0; /* True if any row triggers exist */
int newIdx = -1; /* index of trigger "new" temp table */
int oldIdx = -1; /* index of trigger "old" temp table */
sContext.pParse = 0;
if( pParse->nErr || sqlite3_malloc_failed ) goto update_cleanup;
db = pParse->db;
assert( pTabList->nSrc==1 );
/* Locate the table which we want to update.
*/
pTab = sqlite3SrcListLookup(pParse, pTabList);
if( pTab==0 ) goto update_cleanup;
before_triggers = sqlite3TriggersExist(pParse, pTab->pTrigger,
TK_UPDATE, TK_BEFORE, TK_ROW, pChanges);
after_triggers = sqlite3TriggersExist(pParse, pTab->pTrigger,
TK_UPDATE, TK_AFTER, TK_ROW, pChanges);
row_triggers_exist = before_triggers || after_triggers;
isView = pTab->pSelect!=0;
if( sqlite3IsReadOnly(pParse, pTab, before_triggers) ){
goto update_cleanup;
}
if( isView ){
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
goto update_cleanup;
}
}
aXRef = sqliteMallocRaw( sizeof(int) * pTab->nCol );
if( aXRef==0 ) goto update_cleanup;
for(i=0; i<pTab->nCol; i++) aXRef[i] = -1;
/* If there are FOR EACH ROW triggers, allocate cursors for the
** special OLD and NEW tables
*/
if( row_triggers_exist ){
newIdx = pParse->nTab++;
oldIdx = pParse->nTab++;
}
/* Allocate a cursors for the main database table and for all indices.
** The index cursors might not be used, but if they are used they
** need to occur right after the database cursor. So go ahead and
** allocate enough space, just in case.
*/
pTabList->a[0].iCursor = iCur = pParse->nTab++;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
pParse->nTab++;
}
/* Resolve the column names in all the expressions of the
** of the UPDATE statement. Also find the column index
** for each column to be updated in the pChanges array. For each
** column to be updated, make sure we have authorization to change
** that column.
*/
chngRecno = 0;
for(i=0; i<pChanges->nExpr; i++){
if( sqlite3ExprResolveAndCheck(pParse, pTabList, 0,
pChanges->a[i].pExpr, 0, 0) ){
goto update_cleanup;
}
for(j=0; j<pTab->nCol; j++){
if( sqlite3StrICmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){
if( j==pTab->iPKey ){
chngRecno = 1;
pRecnoExpr = pChanges->a[i].pExpr;
}
aXRef[j] = i;
break;
}
}
if( j>=pTab->nCol ){
if( sqlite3IsRowid(pChanges->a[i].zName) ){
chngRecno = 1;
pRecnoExpr = pChanges->a[i].pExpr;
}else{
sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zName);
goto update_cleanup;
}
}
#ifndef SQLITE_OMIT_AUTHORIZATION
{
int rc;
rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab->zName,
pTab->aCol[j].zName, db->aDb[pTab->iDb].zName);
if( rc==SQLITE_DENY ){
goto update_cleanup;
}else if( rc==SQLITE_IGNORE ){
aXRef[j] = -1;
}
}
#endif
}
/* Allocate memory for the array apIdx[] and fill it with pointers to every
** index that needs to be updated. Indices only need updating if their
** key includes one of the columns named in pChanges or if the record
** number of the original table entry is changing.
*/
for(nIdx=nIdxTotal=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdxTotal++){
if( chngRecno ){
i = 0;
}else {
for(i=0; i<pIdx->nColumn; i++){
if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
}
}
if( i<pIdx->nColumn ) nIdx++;
}
if( nIdxTotal>0 ){
apIdx = sqliteMallocRaw( sizeof(Index*) * nIdx + nIdxTotal );
if( apIdx==0 ) goto update_cleanup;
aIdxUsed = (char*)&apIdx[nIdx];
}
for(nIdx=j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
if( chngRecno ){
i = 0;
}else{
for(i=0; i<pIdx->nColumn; i++){
if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
}
}
if( i<pIdx->nColumn ){
if( sqlite3CheckIndexCollSeq(pParse, pIdx) ) goto update_cleanup;
apIdx[nIdx++] = pIdx;
aIdxUsed[j] = 1;
}else{
aIdxUsed[j] = 0;
}
}
/* Resolve the column names in all the expressions in the
** WHERE clause.
*/
if( sqlite3ExprResolveAndCheck(pParse, pTabList, 0, pWhere, 0, 0) ){
goto update_cleanup;
}
/* Start the view context
*/
if( isView ){
sqlite3AuthContextPush(pParse, &sContext, pTab->zName);
}
/* Begin generating code.
*/
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto update_cleanup;
sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, 1, pTab->iDb);
/* If we are trying to update a view, construct that view into
** a temporary table.
*/
if( isView ){
Select *pView;
pView = sqlite3SelectDup(pTab->pSelect);
sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0);
sqlite3SelectDelete(pView);
}
/* Begin the database scan
*/
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0);
if( pWInfo==0 ) goto update_cleanup;
/* Remember the index of every item to be updated.
*/
sqlite3VdbeAddOp(v, OP_ListWrite, 0, 0);
/* End the database scan loop.
*/
sqlite3WhereEnd(pWInfo);
/* Initialize the count of updated rows
*/
if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
}
if( row_triggers_exist ){
/* Create pseudo-tables for NEW and OLD
*/
sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol);
sqlite3VdbeAddOp(v, OP_OpenPseudo, newIdx, 0);
sqlite3VdbeAddOp(v, OP_SetNumColumns, newIdx, pTab->nCol);
/* The top of the update loop for when there are triggers.
*/
sqlite3VdbeAddOp(v, OP_ListRewind, 0, 0);
addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, 0);
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
/* Open a cursor and make it point to the record that is
** being updated.
*/
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
if( !isView ){
sqlite3OpenTableForReading(v, iCur, pTab);
}
sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
/* Generate the OLD table
*/
sqlite3VdbeAddOp(v, OP_Recno, iCur, 0);
sqlite3VdbeAddOp(v, OP_RowData, iCur, 0);
sqlite3VdbeAddOp(v, OP_PutIntKey, oldIdx, 0);
/* Generate the NEW table
*/
if( chngRecno ){
sqlite3ExprCode(pParse, pRecnoExpr);
}else{
sqlite3VdbeAddOp(v, OP_Recno, iCur, 0);
}
for(i=0; i<pTab->nCol; i++){ /* TODO: Factor out this loop as common code */
if( i==pTab->iPKey ){
sqlite3VdbeAddOp(v, OP_String8, 0, 0);
continue;
}
j = aXRef[i];
if( j<0 ){
sqlite3VdbeAddOp(v, OP_Column, iCur, i);
}else{
sqlite3ExprCode(pParse, pChanges->a[j].pExpr);
}
}
sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
if( !isView ){
sqlite3TableAffinityStr(v, pTab);
}
if( pParse->nErr ) goto update_cleanup;
sqlite3VdbeAddOp(v, OP_PutIntKey, newIdx, 0);
if( !isView ){
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
}
/* Fire the BEFORE and INSTEAD OF triggers
*/
if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_BEFORE, pTab,
newIdx, oldIdx, onError, addr) ){
goto update_cleanup;
}
}
if( !isView ){
/*
** Open every index that needs updating. Note that if any
** index could potentially invoke a REPLACE conflict resolution
** action, then we need to open all indices because we might need
** to be deleting some records.
*/
sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqlite3VdbeAddOp(v, OP_OpenWrite, iCur, pTab->tnum);
sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol);
if( onError==OE_Replace ){
openAll = 1;
}else{
openAll = 0;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
if( pIdx->onError==OE_Replace ){
openAll = 1;
break;
}
}
}
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
if( openAll || aIdxUsed[i] ){
sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
sqlite3VdbeOp3(v, OP_OpenWrite, iCur+i+1, pIdx->tnum,
(char*)&pIdx->keyInfo, P3_KEYINFO);
assert( pParse->nTab>iCur+i+1 );
}
}
/* Loop over every record that needs updating. We have to load
** the old data for each record to be updated because some columns
** might not change and we will need to copy the old value.
** Also, the old data is needed to delete the old index entires.
** So make the cursor point at the old record.
*/
if( !row_triggers_exist ){
sqlite3VdbeAddOp(v, OP_ListRewind, 0, 0);
addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, 0);
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
}
sqlite3VdbeAddOp(v, OP_NotExists, iCur, addr);
/* If the record number will change, push the record number as it
** will be after the update. (The old record number is currently
** on top of the stack.)
*/
if( chngRecno ){
sqlite3ExprCode(pParse, pRecnoExpr);
sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0);
}
/* Compute new data for this record.
*/
for(i=0; i<pTab->nCol; i++){
if( i==pTab->iPKey ){
sqlite3VdbeAddOp(v, OP_String8, 0, 0);
continue;
}
j = aXRef[i];
if( j<0 ){
sqlite3VdbeAddOp(v, OP_Column, iCur, i);
}else{
sqlite3ExprCode(pParse, pChanges->a[j].pExpr);
}
}
/* Do constraint checks
*/
sqlite3GenerateConstraintChecks(pParse, pTab, iCur, aIdxUsed, chngRecno, 1,
onError, addr);
/* Delete the old indices for the current record.
*/
sqlite3GenerateRowIndexDelete(db, v, pTab, iCur, aIdxUsed);
/* If changing the record number, delete the old record.
*/
if( chngRecno ){
sqlite3VdbeAddOp(v, OP_Delete, iCur, 0);
}
/* Create the new index entries and the new record.
*/
sqlite3CompleteInsertion(pParse, pTab, iCur, aIdxUsed, chngRecno, 1, -1);
}
/* Increment the row counter
*/
if( db->flags & SQLITE_CountRows && !pParse->trigStack){
sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
}
/* If there are triggers, close all the cursors after each iteration
** through the loop. The fire the after triggers.
*/
if( row_triggers_exist ){
if( !isView ){
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
if( openAll || aIdxUsed[i] )
sqlite3VdbeAddOp(v, OP_Close, iCur+i+1, 0);
}
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
}
if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_AFTER, pTab,
newIdx, oldIdx, onError, addr) ){
goto update_cleanup;
}
}
/* Repeat the above with the next record to be updated, until
** all record selected by the WHERE clause have been updated.
*/
sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
sqlite3VdbeAddOp(v, OP_ListReset, 0, 0);
/* Close all tables if there were no FOR EACH ROW triggers */
if( !row_triggers_exist ){
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
if( openAll || aIdxUsed[i] ){
sqlite3VdbeAddOp(v, OP_Close, iCur+i+1, 0);
}
}
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
}else{
sqlite3VdbeAddOp(v, OP_Close, newIdx, 0);
sqlite3VdbeAddOp(v, OP_Close, oldIdx, 0);
}
/*
** Return the number of rows that were changed.
*/
if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, "rows updated", P3_STATIC);
}
update_cleanup:
sqlite3AuthContextPop(&sContext);
sqliteFree(apIdx);
sqliteFree(aXRef);
sqlite3SrcListDelete(pTabList);
sqlite3ExprListDelete(pChanges);
sqlite3ExprDelete(pWhere);
return;
}
-566
View File
@@ -1,566 +0,0 @@
/*
** 2004 April 13
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains routines used to translate between UTF-8,
** UTF-16, UTF-16BE, and UTF-16LE.
**
** $Id$
**
** Notes on UTF-8:
**
** Byte-0 Byte-1 Byte-2 Byte-3 Value
** 0xxxxxxx 00000000 00000000 0xxxxxxx
** 110yyyyy 10xxxxxx 00000000 00000yyy yyxxxxxx
** 1110zzzz 10yyyyyy 10xxxxxx 00000000 zzzzyyyy yyxxxxxx
** 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx 000uuuuu zzzzyyyy yyxxxxxx
**
**
** Notes on UTF-16: (with wwww+1==uuuuu)
**
** Word-0 Word-1 Value
** 110110ww wwzzzzyy 110111yy yyxxxxxx 000uuuuu zzzzyyyy yyxxxxxx
** zzzzyyyy yyxxxxxx 00000000 zzzzyyyy yyxxxxxx
**
**
** BOM or Byte Order Mark:
** 0xff 0xfe little-endian utf-16 follows
** 0xfe 0xff big-endian utf-16 follows
**
**
** Handling of malformed strings:
**
** SQLite accepts and processes malformed strings without an error wherever
** possible. However this is not possible when converting between UTF-8 and
** UTF-16.
**
** When converting malformed UTF-8 strings to UTF-16, one instance of the
** replacement character U+FFFD for each byte that cannot be interpeted as
** part of a valid unicode character.
**
** When converting malformed UTF-16 strings to UTF-8, one instance of the
** replacement character U+FFFD for each pair of bytes that cannot be
** interpeted as part of a valid unicode character.
**
** This file contains the following public routines:
**
** sqlite3VdbeMemTranslate() - Translate the encoding used by a Mem* string.
** sqlite3VdbeMemHandleBom() - Handle byte-order-marks in UTF16 Mem* strings.
** sqlite3utf16ByteLen() - Calculate byte-length of a void* UTF16 string.
** sqlite3utf8CharLen() - Calculate char-length of a char* UTF8 string.
** sqlite3utf8LikeCompare() - Do a LIKE match given two UTF8 char* strings.
**
*/
#include <assert.h>
#include "sqliteInt.h"
#include "vdbeInt.h"
/*
** This table maps from the first byte of a UTF-8 character to the number
** of trailing bytes expected. A value '255' indicates that the table key
** is not a legal first byte for a UTF-8 character.
*/
static const u8 xtra_utf8_bytes[256] = {
/* 0xxxxxxx */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 10wwwwww */
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
/* 110yyyyy */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 1110zzzz */
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* 11110yyy */
3, 3, 3, 3, 3, 3, 3, 3, 255, 255, 255, 255, 255, 255, 255, 255,
};
/*
** This table maps from the number of trailing bytes in a UTF-8 character
** to an integer constant that is effectively calculated for each character
** read by a naive implementation of a UTF-8 character reader. The code
** in the READ_UTF8 macro explains things best.
*/
static const int xtra_utf8_bits[4] = {
0,
12416, /* (0xC0 << 6) + (0x80) */
925824, /* (0xE0 << 12) + (0x80 << 6) + (0x80) */
63447168 /* (0xF0 << 18) + (0x80 << 12) + (0x80 << 6) + 0x80 */
};
#define READ_UTF8(zIn, c) { \
int xtra; \
c = *(zIn)++; \
xtra = xtra_utf8_bytes[c]; \
switch( xtra ){ \
case 255: c = (int)0xFFFD; break; \
case 3: c = (c<<6) + *(zIn)++; \
case 2: c = (c<<6) + *(zIn)++; \
case 1: c = (c<<6) + *(zIn)++; \
c -= xtra_utf8_bits[xtra]; \
} \
}
int sqlite3ReadUtf8(const unsigned char *z){
int c;
READ_UTF8(z, c);
return c;
}
#define SKIP_UTF8(zIn) { \
zIn += (xtra_utf8_bytes[*(u8 *)zIn] + 1); \
}
#define WRITE_UTF8(zOut, c) { \
if( c<0x00080 ){ \
*zOut++ = (c&0xFF); \
} \
else if( c<0x00800 ){ \
*zOut++ = 0xC0 + ((c>>6)&0x1F); \
*zOut++ = 0x80 + (c & 0x3F); \
} \
else if( c<0x10000 ){ \
*zOut++ = 0xE0 + ((c>>12)&0x0F); \
*zOut++ = 0x80 + ((c>>6) & 0x3F); \
*zOut++ = 0x80 + (c & 0x3F); \
}else{ \
*zOut++ = 0xF0 + ((c>>18) & 0x07); \
*zOut++ = 0x80 + ((c>>12) & 0x3F); \
*zOut++ = 0x80 + ((c>>6) & 0x3F); \
*zOut++ = 0x80 + (c & 0x3F); \
} \
}
#define WRITE_UTF16LE(zOut, c) { \
if( c<=0xFFFF ){ \
*zOut++ = (c&0x00FF); \
*zOut++ = ((c>>8)&0x00FF); \
}else{ \
*zOut++ = (((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \
*zOut++ = (0x00D8 + (((c-0x10000)>>18)&0x03)); \
*zOut++ = (c&0x00FF); \
*zOut++ = (0x00DC + ((c>>8)&0x03)); \
} \
}
#define WRITE_UTF16BE(zOut, c) { \
if( c<=0xFFFF ){ \
*zOut++ = ((c>>8)&0x00FF); \
*zOut++ = (c&0x00FF); \
}else{ \
*zOut++ = (0x00D8 + (((c-0x10000)>>18)&0x03)); \
*zOut++ = (((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \
*zOut++ = (0x00DC + ((c>>8)&0x03)); \
*zOut++ = (c&0x00FF); \
} \
}
#define READ_UTF16LE(zIn, c){ \
c = (*zIn++); \
c += ((*zIn++)<<8); \
if( c>=0xD800 && c<=0xE000 ){ \
int c2 = (*zIn++); \
c2 += ((*zIn++)<<8); \
c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \
} \
}
#define READ_UTF16BE(zIn, c){ \
c = ((*zIn++)<<8); \
c += (*zIn++); \
if( c>=0xD800 && c<=0xE000 ){ \
int c2 = ((*zIn++)<<8); \
c2 += (*zIn++); \
c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \
} \
}
#define SKIP_UTF16BE(zIn){ \
if( *zIn>=0xD8 && (*zIn<0xE0 || (*zIn==0xE0 && *(zIn+1)==0x00)) ){ \
zIn += 4; \
}else{ \
zIn += 2; \
} \
}
#define SKIP_UTF16LE(zIn){ \
zIn++; \
if( *zIn>=0xD8 && (*zIn<0xE0 || (*zIn==0xE0 && *(zIn-1)==0x00)) ){ \
zIn += 3; \
}else{ \
zIn += 1; \
} \
}
#define RSKIP_UTF16LE(zIn){ \
if( *zIn>=0xD8 && (*zIn<0xE0 || (*zIn==0xE0 && *(zIn-1)==0x00)) ){ \
zIn -= 4; \
}else{ \
zIn -= 2; \
} \
}
#define RSKIP_UTF16BE(zIn){ \
zIn--; \
if( *zIn>=0xD8 && (*zIn<0xE0 || (*zIn==0xE0 && *(zIn+1)==0x00)) ){ \
zIn -= 3; \
}else{ \
zIn -= 1; \
} \
}
/*
** If the TRANSLATE_TRACE macro is defined, the value of each Mem is
** printed on stderr on the way into and out of sqlite3VdbeMemTranslate().
*/
/* #define TRANSLATE_TRACE 1 */
/*
** This routine transforms the internal text encoding used by pMem to
** desiredEnc. It is an error if the string is already of the desired
** encoding, or if *pMem does not contain a string value.
*/
int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
unsigned char zShort[NBFS]; /* Temporary short output buffer */
int len; /* Maximum length of output string in bytes */
unsigned char *zOut; /* Output buffer */
unsigned char *zIn; /* Input iterator */
unsigned char *zTerm; /* End of input */
unsigned char *z; /* Output iterator */
int c;
assert( pMem->flags&MEM_Str );
assert( pMem->enc!=desiredEnc );
assert( pMem->enc!=0 );
assert( pMem->n>=0 );
#ifdef TRANSLATE_TRACE
{
char zBuf[100];
sqlite3VdbeMemPrettyPrint(pMem, zBuf, 100);
fprintf(stderr, "INPUT: %s\n", zBuf);
}
#endif
/* If the translation is between UTF-16 little and big endian, then
** all that is required is to swap the byte order. This case is handled
** differently from the others.
*/
if( pMem->enc!=SQLITE_UTF8 && desiredEnc!=SQLITE_UTF8 ){
u8 temp;
int rc;
rc = sqlite3VdbeMemMakeWriteable(pMem);
if( rc!=SQLITE_OK ){
assert( rc==SQLITE_NOMEM );
return SQLITE_NOMEM;
}
zIn = pMem->z;
zTerm = &zIn[pMem->n];
while( zIn<zTerm ){
temp = *zIn;
*zIn = *(zIn+1);
zIn++;
*zIn++ = temp;
}
pMem->enc = desiredEnc;
goto translate_out;
}
/* Set len to the maximum number of bytes required in the output buffer. */
if( desiredEnc==SQLITE_UTF8 ){
/* When converting from UTF-16, the maximum growth results from
** translating a 2-byte character to a 3-byte UTF-8 character (i.e.
** code-point 0xFFFC). A single byte is required for the output string
** nul-terminator.
*/
len = (pMem->n/2) * 3 + 1;
}else{
/* When converting from UTF-8 to UTF-16 the maximum growth is caused
** when a 1-byte UTF-8 character is translated into a 2-byte UTF-16
** character. Two bytes are required in the output buffer for the
** nul-terminator.
*/
len = pMem->n * 2 + 2;
}
/* Set zIn to point at the start of the input buffer and zTerm to point 1
** byte past the end.
**
** Variable zOut is set to point at the output buffer. This may be space
** obtained from malloc(), or Mem.zShort, if it large enough and not in
** use, or the zShort array on the stack (see above).
*/
zIn = pMem->z;
zTerm = &zIn[pMem->n];
if( len>NBFS ){
zOut = sqliteMallocRaw(len);
if( !zOut ) return SQLITE_NOMEM;
}else{
zOut = zShort;
}
z = zOut;
if( pMem->enc==SQLITE_UTF8 ){
if( desiredEnc==SQLITE_UTF16LE ){
/* UTF-8 -> UTF-16 Little-endian */
while( zIn<zTerm ){
READ_UTF8(zIn, c);
WRITE_UTF16LE(z, c);
}
}else{
assert( desiredEnc==SQLITE_UTF16BE );
/* UTF-8 -> UTF-16 Big-endian */
while( zIn<zTerm ){
READ_UTF8(zIn, c);
WRITE_UTF16BE(z, c);
}
}
pMem->n = z - zOut;
*z++ = 0;
}else{
assert( desiredEnc==SQLITE_UTF8 );
if( pMem->enc==SQLITE_UTF16LE ){
/* UTF-16 Little-endian -> UTF-8 */
while( zIn<zTerm ){
READ_UTF16LE(zIn, c);
WRITE_UTF8(z, c);
}
}else{
/* UTF-16 Little-endian -> UTF-8 */
while( zIn<zTerm ){
READ_UTF16BE(zIn, c);
WRITE_UTF8(z, c);
}
}
pMem->n = z - zOut;
}
*z = 0;
assert( (pMem->n+(desiredEnc==SQLITE_UTF8?1:2))<=len );
sqlite3VdbeMemRelease(pMem);
pMem->flags &= ~(MEM_Static|MEM_Dyn|MEM_Ephem|MEM_Short);
pMem->enc = desiredEnc;
if( zOut==zShort ){
memcpy(pMem->zShort, zOut, len);
zOut = pMem->zShort;
pMem->flags |= (MEM_Term|MEM_Short);
}else{
pMem->flags |= (MEM_Term|MEM_Dyn);
}
pMem->z = zOut;
translate_out:
#ifdef TRANSLATE_TRACE
{
char zBuf[100];
sqlite3VdbeMemPrettyPrint(pMem, zBuf, 100);
fprintf(stderr, "OUTPUT: %s\n", zBuf);
}
#endif
return SQLITE_OK;
}
/*
** This routine checks for a byte-order mark at the beginning of the
** UTF-16 string stored in *pMem. If one is present, it is removed and
** the encoding of the Mem adjusted. This routine does not do any
** byte-swapping, it just sets Mem.enc appropriately.
**
** The allocation (static, dynamic etc.) and encoding of the Mem may be
** changed by this function.
*/
int sqlite3VdbeMemHandleBom(Mem *pMem){
int rc = SQLITE_OK;
u8 bom = 0;
if( pMem->n<0 || pMem->n>1 ){
u8 b1 = *(u8 *)pMem->z;
u8 b2 = *(((u8 *)pMem->z) + 1);
if( b1==0xFE && b2==0xFF ){
bom = SQLITE_UTF16BE;
}
if( b1==0xFF && b2==0xFE ){
bom = SQLITE_UTF16LE;
}
}
if( bom ){
/* This function is called as soon as a string is stored in a Mem*,
** from within sqlite3VdbeMemSetStr(). At that point it is not possible
** for the string to be stored in Mem.zShort, or for it to be stored
** in dynamic memory with no destructor.
*/
assert( !(pMem->flags&MEM_Short) );
assert( !(pMem->flags&MEM_Dyn) || pMem->xDel );
if( pMem->flags & MEM_Dyn ){
void (*xDel)(void*) = pMem->xDel;
char *z = pMem->z;
pMem->z = 0;
pMem->xDel = 0;
rc = sqlite3VdbeMemSetStr(pMem, &z[2], pMem->n-2, bom, SQLITE_TRANSIENT);
xDel(z);
}else{
rc = sqlite3VdbeMemSetStr(pMem, &pMem->z[2], pMem->n-2, bom,
SQLITE_TRANSIENT);
}
}
return rc;
}
/*
** pZ is a UTF-8 encoded unicode string. If nByte is less than zero,
** return the number of unicode characters in pZ up to (but not including)
** the first 0x00 byte. If nByte is not less than zero, return the
** number of unicode characters in the first nByte of pZ (or up to
** the first 0x00, whichever comes first).
*/
int sqlite3utf8CharLen(const char *z, int nByte){
int r = 0;
const char *zTerm;
if( nByte>=0 ){
zTerm = &z[nByte];
}else{
zTerm = (const char *)(-1);
}
assert( z<=zTerm );
while( *z!=0 && z<zTerm ){
SKIP_UTF8(z);
r++;
}
return r;
}
/*
** pZ is a UTF-16 encoded unicode string. If nChar is less than zero,
** return the number of bytes up to (but not including), the first pair
** of consecutive 0x00 bytes in pZ. If nChar is not less than zero,
** then return the number of bytes in the first nChar unicode characters
** in pZ (or up until the first pair of 0x00 bytes, whichever comes first).
*/
int sqlite3utf16ByteLen(const void *zIn, int nChar){
int c = 1;
char const *z = zIn;
int n = 0;
if( SQLITE_UTF16NATIVE==SQLITE_UTF16BE ){
while( c && ((nChar<0) || n<nChar) ){
READ_UTF16BE(z, c);
n++;
}
}else{
while( c && ((nChar<0) || n<nChar) ){
READ_UTF16LE(z, c);
n++;
}
}
return (z-(char const *)zIn)-((c==0)?2:0);
}
/*
** UTF-16 implementation of the substr()
*/
void sqlite3utf16Substr(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
int y, z;
unsigned char const *zStr;
unsigned char const *zStrEnd;
unsigned char const *zStart;
unsigned char const *zEnd;
int i;
zStr = (unsigned char const *)sqlite3_value_text16(argv[0]);
zStrEnd = &zStr[sqlite3_value_bytes16(argv[0])];
y = sqlite3_value_int(argv[1]);
z = sqlite3_value_int(argv[2]);
if( y>0 ){
y = y-1;
zStart = zStr;
if( SQLITE_UTF16BE==SQLITE_UTF16NATIVE ){
for(i=0; i<y && zStart<zStrEnd; i++) SKIP_UTF16BE(zStart);
}else{
for(i=0; i<y && zStart<zStrEnd; i++) SKIP_UTF16LE(zStart);
}
}else{
zStart = zStrEnd;
if( SQLITE_UTF16BE==SQLITE_UTF16NATIVE ){
for(i=y; i<0 && zStart>zStr; i++) RSKIP_UTF16BE(zStart);
}else{
for(i=y; i<0 && zStart>zStr; i++) RSKIP_UTF16LE(zStart);
}
for(; i<0; i++) z -= 1;
}
zEnd = zStart;
if( SQLITE_UTF16BE==SQLITE_UTF16NATIVE ){
for(i=0; i<z && zEnd<zStrEnd; i++) SKIP_UTF16BE(zEnd);
}else{
for(i=0; i<z && zEnd<zStrEnd; i++) SKIP_UTF16LE(zEnd);
}
sqlite3_result_text16(context, zStart, zEnd-zStart, SQLITE_TRANSIENT);
}
#if defined(SQLITE_TEST)
/*
** This routine is called from the TCL test function "translate_selftest".
** It checks that the primitives for serializing and deserializing
** characters in each encoding are inverses of each other.
*/
void sqlite3utfSelfTest(){
int i;
unsigned char zBuf[20];
unsigned char *z;
int n;
int c;
for(i=0; i<0x00110000; i++){
z = zBuf;
WRITE_UTF8(z, i);
n = z-zBuf;
z = zBuf;
READ_UTF8(z, c);
assert( c==i );
assert( (z-zBuf)==n );
}
for(i=0; i<0x00110000; i++){
if( i>=0xD800 && i<=0xE000 ) continue;
z = zBuf;
WRITE_UTF16LE(z, i);
n = z-zBuf;
z = zBuf;
READ_UTF16LE(z, c);
assert( c==i );
assert( (z-zBuf)==n );
}
for(i=0; i<0x00110000; i++){
if( i>=0xD800 && i<=0xE000 ) continue;
z = zBuf;
WRITE_UTF16BE(z, i);
n = z-zBuf;
z = zBuf;
READ_UTF16BE(z, c);
assert( c==i );
assert( (z-zBuf)==n );
}
}
#endif
Loaded 100 of 127 files, more files were not shown because too many files have changed in this diff. Show more