Index: ajax/js/fossil-ajaj.js ================================================================== --- ajax/js/fossil-ajaj.js +++ ajax/js/fossil-ajaj.js @@ -7,16 +7,16 @@ */ /** Constructor for a new Fossil AJAJ client. ajajOpt may be an optional object suitable for passing to the WhAjaj.Connector() constructor. - - On returning, this.ajaj is-a WhAjaj.Connector instance which can - be used to send requests to the back-end (though the convenience - functions of this class are the preferred way to do it). Clients - are encouraged to use FossilAjaj.sendCommand() (and friends) instead - of the underlying WhAjaj.Connector API, since this class' API + + On returning, this.ajaj is-a WhAjaj.Connector instance which can + be used to send requests to the back-end (though the convenience + functions of this class are the preferred way to do it). Clients + are encouraged to use FossilAjaj.sendCommand() (and friends) instead + of the underlying WhAjaj.Connector API, since this class' API contains Fossil-specific request-calling handling (e.g. of authentication info) whereas WhAjaj is more generic. */ function FossilAjaj(ajajOpt) { @@ -38,11 +38,11 @@ /** Sends a command to the fossil back-end. Command should be the path part of the URL, e.g. /json/stat, payload is a request-specific value type (may often be null/undefined). ajajOpt is an optional object holding WhAjaj.sendRequest()-compatible options. - + This function constructs a Fossil/JSON request envelope based on the given arguments and adds this.auth.authToken and a requestId to it. */ FossilAjaj.prototype.sendCommand = function(command, payload, ajajOpt) { @@ -63,24 +63,24 @@ }; /** Sends a login request to the back-end. - ajajOpt is an optional configuration object suitable for passing + ajajOpt is an optional configuration object suitable for passing to sendCommand(). After the response returns, this.auth will be set to the response payload. - + If name === 'anonymous' (the default if none is passed in) then this function ignores the pw argument and must make two requests - the first one gets the captcha code and the second one submits it. ajajOpt.onResponse() (if set) is only called for the actual login response (the 2nd one), as opposed to being called for both requests. However, this.ajaj.callbacks.onResponse() _is_ called for both (because it happens at a lower level). - + If this object has an onLogin() function it is called (with no arguments) before the onResponse() handler of the login is called (that is the 2nd request for anonymous logins) and any exceptions it throws are ignored. @@ -135,13 +135,13 @@ }; /** Logs out of fossil, invaliding this login token. - ajajOpt is an optional configuration object suitable for passing + ajajOpt is an optional configuration object suitable for passing to sendCommand(). - + If this object has an onLogout() function it is called (with no arguments) before the onResponse() handler is called. IFF the response succeeds then this.auth is unset. */ FossilAjaj.prototype.logout = function(ajajOpt) { @@ -163,11 +163,11 @@ }; /** Sends a HAI request to the server. /json/HAI is an alias /json/version. - ajajOpt is an optional configuration object suitable for passing + ajajOpt is an optional configuration object suitable for passing to sendCommand(). */ FossilAjaj.prototype.HAI = function(ajajOpt) { this.sendCommand('/json/HAI', undefined, ajajOpt); }; @@ -226,11 +226,11 @@ The interface is otherwise compatible with the "normal" FossilAjaj.sendCommand() front-end (it is, however, fossil-specific, and not back-end agnostic like the WhAjaj.sendImpl() interface intends). - + */ FossilAjaj.rhinoLocalBinarySendImpl = function(request,args){ var self = this; request = request || {}; if(!args.fossilBinary){ @@ -240,19 +240,19 @@ if(url.length>1){ // 3x shift(): protocol, host, 'json' part of path request.command = (url.shift(),url.shift(),url.shift(), url.join('/')); } delete args.url; - //print("rhinoLocalBinarySendImpl SENDING: "+WhAjaj.stringify(request)); + //print("rhinoLocalBinarySendImpl SENDING: "+WhAjaj.stringify(request)); var json; try{ var pargs = [args.fossilBinary, 'json', '--json-input', '-']; var p = java.lang.Runtime.getRuntime().exec(pargs); var outs = p.getOutputStream(); var osr = new java.io.OutputStreamWriter(outs); var osb = new java.io.BufferedWriter(osr); - + json = JSON.stringify(request); osb.write(json,0, json.length); osb.close(); var ins = p.getInputStream(); var isr = new java.io.InputStreamReader(ins); Index: ajax/js/whajaj.js ================================================================== --- ajax/js/whajaj.js +++ ajax/js/whajaj.js @@ -10,22 +10,22 @@ acts as namespace for this framework. Author: Stephan Beal (http://wanderinghorse.net/home/stephan/) License: Public Domain - - This framework is directly derived from code originally found in - http://code.google.com/p/jsonmessage, and later in - http://whiki.wanderinghorse.net, where it contained quite a bit - of application-specific logic. It was eventually (the 3rd time i - needed it) split off into its own library to simplify inclusion + + This framework is directly derived from code originally found in + http://code.google.com/p/jsonmessage, and later in + http://whiki.wanderinghorse.net, where it contained quite a bit + of application-specific logic. It was eventually (the 3rd time i + needed it) split off into its own library to simplify inclusion into my many mini-projects. */ /** - The WhAjaj function is primarily a namespace, and not intended + The WhAjaj function is primarily a namespace, and not intended to called or instantiated via the 'new' operator. */ function WhAjaj() { } @@ -36,11 +36,11 @@ return (new Date()).getTime(); }; /** Returns a Unix Epoch timestamp (in seconds) in integer format. - Reminder to self: (1.1 %1.2) evaluates to a floating-point value + Reminder to self: (1.1 %1.2) evaluates to a floating-point value in JS, and thus this implementation is less than optimal. */ WhAjaj.unixTimestamp = function() { var ts = (new Date()).getTime(); @@ -88,22 +88,22 @@ }; /** Parses window.location.search-style string into an object containing key/value pairs of URL arguments (already urldecoded). - - If the str argument is not passed (arguments.length==0) then - window.location.search.substring(1) is used by default. If + + If the str argument is not passed (arguments.length==0) then + window.location.search.substring(1) is used by default. If neither str is passed in nor window exists then false is returned. On success it returns an Object containing the key/value pairs parsed from the string. Keys which have no value are treated has having the boolean true value. - + FIXME: for keys in the form "name[]", build an array of results, like PHP does. - + */ WhAjaj.processUrlArgs = function(str) { if( 0 === arguments.length ) { if( ('undefined' === typeof window) || !window.location || @@ -127,11 +127,11 @@ /** A simple wrapper around JSON.stringify(), using my own personal preferred values for the 2nd and 3rd parameters. To globally set its indentation level, assign WhAjaj.stringify.indent to an integer value (0 for no intendation). - + This function is intended only for human-readable output, not generic over-the-wire JSON output (where JSON.stringify(val) will produce smaller results). */ WhAjaj.stringify = function(val) { @@ -138,34 +138,34 @@ if( ! arguments.callee.indent ) arguments.callee.indent = 4; return JSON.stringify(val,0,arguments.callee.indent); }; /** - Each instance of this class holds state information for making - AJAJ requests to a back-end system. While clients may use one + Each instance of this class holds state information for making + AJAJ requests to a back-end system. While clients may use one "requester" object per connection attempt, for connections to the - same back-end, using an instance configured for that back-end - can simplify usage. This class is designed so that the actual - connection-related details (i.e. _how_ it connects to the - back-end) may be re-implemented to use a client's preferred + same back-end, using an instance configured for that back-end + can simplify usage. This class is designed so that the actual + connection-related details (i.e. _how_ it connects to the + back-end) may be re-implemented to use a client's preferred connection mechanism (e.g. jQuery). - - The optional opt paramater may be an object with any (or all) of - the properties documented for WhAjaj.Connector.options.ajax. - Properties set here (or later via modification of the "options" - property of this object) will be used in calls to + + The optional opt paramater may be an object with any (or all) of + the properties documented for WhAjaj.Connector.options.ajax. + Properties set here (or later via modification of the "options" + property of this object) will be used in calls to WhAjaj.Connector.sendRequest(), and these override (normally) any - options set in WhAjaj.Connector.options.ajax. Note that - WhAjaj.Connector.sendRequest() _also_ takes an options object, - and ones passed there will override, for purposes of that one - request, any options passed in here or defined in + options set in WhAjaj.Connector.options.ajax. Note that + WhAjaj.Connector.sendRequest() _also_ takes an options object, + and ones passed there will override, for purposes of that one + request, any options passed in here or defined in WhAjaj.Connector.options.ajax. See WhAjaj.Connector.options.ajax and WhAjaj.Connector.prototype.sendRequest() for more details about the precedence of options. - + Sample usage: - + @code // Set up common connection-level options: var cgi = new WhAjaj.Connector({ url: '/cgi-bin/my.cgi', timeout:10000, @@ -185,25 +185,25 @@ @endcode For common request types, clients can add functions to this object which act as wrappers for backend-specific functionality. As a simple example: - + @code cgi.login = function(name,pw,ajajOpt) { this.sendRequest( {command:"json/login", name:name, password:pw }, ajajOpt ); }; @endcode - + TODOs: - + - Caching of page-load requests, with a configurable lifetime. - + - Use-cases like the above login() function are a tiny bit problematic to implement when each request has a different URL path (i know this from the whiki and fossil implementations). This is partly a side-effect of design descisions made back in the very first days of this code's life. i need to go through @@ -230,42 +230,42 @@ A (meaningless) prefix to apply to WhAjaj.Connector-generated request IDs. */ requestIdPrefix:'WhAjaj.Connector-', /** - Default options for WhAjaj.Connector.sendRequest() connection - parameters. This object holds only connection-related - options and callbacks (all optional), and not options - related to the required JSON structure of any given request. - i.e. the page name used in a get-page request are not set + Default options for WhAjaj.Connector.sendRequest() connection + parameters. This object holds only connection-related + options and callbacks (all optional), and not options + related to the required JSON structure of any given request. + i.e. the page name used in a get-page request are not set here but are specified as part of the request object. - These connection options are a "normalized form" of options - often found in various AJAX libraries like jQuery, - Prototype, dojo, etc. This approach allows us to swap out - the real connection-related parts by writing a simple proxy - which transforms our "normalized" form to the - backend-specific form. For examples, see the various + These connection options are a "normalized form" of options + often found in various AJAX libraries like jQuery, + Prototype, dojo, etc. This approach allows us to swap out + the real connection-related parts by writing a simple proxy + which transforms our "normalized" form to the + backend-specific form. For examples, see the various implementations stored in WhAjaj.Connector.sendImpls. - The following callback options are, in practice, almost + The following callback options are, in practice, almost always set globally to some app-wide defaults: - onError() to report errors using a common mechanism. - beforeSend() to start a visual activity notification - afterSend() to disable the visual activity notification - However, be aware that if any given WhAjaj.Connector instance is - given its own before/afterSend callback then those will + However, be aware that if any given WhAjaj.Connector instance is + given its own before/afterSend callback then those will override these. Mixing shared/global and per-instance callbacks can potentially lead to confusing results if, e.g., the beforeSend() and afterSend() functions have side-effects but are not used with their proper before/after partner. - - TODO: rename this to 'ajaj' (the name is historical). The - problem with renaming it is is that the word 'ajax' is - pretty prevelant in the source tree, so i can't globally + + TODO: rename this to 'ajaj' (the name is historical). The + problem with renaming it is is that the word 'ajax' is + pretty prevelant in the source tree, so i can't globally swap it out. */ ajax: { /** URL of the back-end server/CGI. @@ -273,48 +273,48 @@ url: '/some/path', /** Connection method. Some connection-related functions might override any client-defined setting. - - Must be one of 'GET' or 'POST'. For custom connection - implementation, it may optionally be some + + Must be one of 'GET' or 'POST'. For custom connection + implementation, it may optionally be some implementation-specified value. Normally the API can derive this value automatically - if the request uses JSON data it is POSTed, else it is GETted. */ method:'GET', /** - A hint whether to run the operation asynchronously or - not. Not all concrete WhAjaj.Connector.sendImpl() - implementations can support this. Interestingly, at - least one popular AJAX toolkit does not document - supporting _synchronous_ AJAX operations. All common - browser-side implementations support async operation, but + A hint whether to run the operation asynchronously or + not. Not all concrete WhAjaj.Connector.sendImpl() + implementations can support this. Interestingly, at + least one popular AJAX toolkit does not document + supporting _synchronous_ AJAX operations. All common + browser-side implementations support async operation, but non-browser implementations might not. */ asynchronous:true, /** - A HTTP authentication login name for the AJAX - connection. Not all concrete WhAjaj.Connector.sendImpl() + A HTTP authentication login name for the AJAX + connection. Not all concrete WhAjaj.Connector.sendImpl() implementations can support this. */ loginName:undefined, /** - An HTTP authentication login password for the AJAJ - connection. Not all concrete WhAjaj.Connector.sendImpl() + An HTTP authentication login password for the AJAJ + connection. Not all concrete WhAjaj.Connector.sendImpl() implementations can support this. */ loginPassword:undefined, /** - A connection timeout, in milliseconds, for establishing - an AJAJ connection. Not all concrete + A connection timeout, in milliseconds, for establishing + an AJAJ connection. Not all concrete WhAjaj.Connector.sendImpl() implementations can support this. */ timeout:10000, /** @@ -328,11 +328,11 @@ is the same as the 'this' object for the context of the callback, but is provided because the instance-level callbacks (set in (WhAjaj.Connector instance).callbacks, require it in some cases (because their 'this' is different!). - + Note that the response might contain error information which comes from the back-end. The difference between this error info and the info passed to the onError() callback is that this data indicates an application-level error, whereas onError() is used to @@ -342,21 +342,21 @@ connection error). */ onResponse: function(response, request, opt){}, /** - If an AJAX request fails to establish a connection or it - receives non-JSON data from the back-end, this function - is called (e.g. timeout error or host name not + If an AJAX request fails to establish a connection or it + receives non-JSON data from the back-end, this function + is called (e.g. timeout error or host name not resolvable). It is passed the originating request and the - "normalized" connection parameters used for that - request. The connectOpt object "should" (or "might") - have an "errorMessage" property which describes the + "normalized" connection parameters used for that + request. The connectOpt object "should" (or "might") + have an "errorMessage" property which describes the nature of the problem. - - Clients will almost always want to replace the default - implementation with something which integrates into + + Clients will almost always want to replace the default + implementation with something which integrates into their application. */ onError: function(request, connectOpt) { alert('AJAJ request failed:\n' @@ -364,60 +364,60 @@ +JSON.stringify(connectOpt,0,4) ); }, /** - Called before each connection attempt is made. Clients + Called before each connection attempt is made. Clients can use this to, e.g., enable a visual "network activity - notification" for the user. It is passed the original - request object and the normalized connection parameters - for the request. If this function changes opt, those - changes _are_ applied to the subsequent request. If this - function throws, neither the onError() nor afterSend() - callbacks are triggered and WhAjaj.Connector.sendImpl() + notification" for the user. It is passed the original + request object and the normalized connection parameters + for the request. If this function changes opt, those + changes _are_ applied to the subsequent request. If this + function throws, neither the onError() nor afterSend() + callbacks are triggered and WhAjaj.Connector.sendImpl() propagates the exception back to the caller. */ beforeSend: function(request,opt){}, /** - Called after an AJAJ connection attempt completes, - regardless of success or failure. Passed the same - parameters as beforeSend() (see that function for + Called after an AJAJ connection attempt completes, + regardless of success or failure. Passed the same + parameters as beforeSend() (see that function for details). - - Here's an example of setting up a visual notification on - ajax operations using jQuery (but it's also easy to do + + Here's an example of setting up a visual notification on + ajax operations using jQuery (but it's also easy to do without jQuery as well): - + @code function startAjaxNotif(req,opt) { var me = arguments.callee; var c = ++me.ajaxCount; me.element.text( c + " pending AJAX operation(s)..." ); if( 1 == c ) me.element.stop().fadeIn(); } startAjaxNotif.ajaxCount = 0. startAjaxNotif.element = jQuery('#whikiAjaxNotification'); - + function endAjaxNotif() { var c = --startAjaxNotif.ajaxCount; startAjaxNotif.element.text( c+" pending AJAX operation(s)..." ); if( 0 == c ) startAjaxNotif.element.stop().fadeOut(); } @endcode - Set the beforeSend/afterSend properties to those - functions to enable the notifications by default. + Set the beforeSend/afterSend properties to those + functions to enable the notifications by default. */ afterSend: function(request,opt){}, /** If jsonp is a string then the WhAjaj-internal response handling code ASSUMES that the response contains a JSONP-style construct and eval()s it after afterSend() but before onResponse(). In this case, onResponse() will get a string value for the response - instead of a response object parsed from JSON. + instead of a response object parsed from JSON. */ jsonp:undefined, /** Don't use yet. Planned future option. */ @@ -468,25 +468,25 @@ else v = WhAjaj.Connector.options.ajax[key]; return v; }; /** - Returns a unique string on each call containing a generic - reandom request identifier string. This is not used by the core - API but can be used by client code to generate unique IDs for + Returns a unique string on each call containing a generic + reandom request identifier string. This is not used by the core + API but can be used by client code to generate unique IDs for each request (if needed). The exact format is unspecified and may change in the future. - Request IDs can be used by clients to "match up" responses to - specific requests if needed. In practice, however, they are - seldom, if ever, needed. When passing several concurrent - requests through the same response callback, it might be useful - for some clients to be able to distinguish, possibly re-routing + Request IDs can be used by clients to "match up" responses to + specific requests if needed. In practice, however, they are + seldom, if ever, needed. When passing several concurrent + requests through the same response callback, it might be useful + for some clients to be able to distinguish, possibly re-routing them through other handlers based on the originating request type. - - If this.options.requestIdPrefix or + + If this.options.requestIdPrefix or WhAjaj.Connector.options.requestIdPrefix is set then that text is prefixed to the returned string. */ WhAjaj.Connector.prototype.generateRequestId = function() { @@ -512,39 +512,39 @@ } return this.options; }; /** - An internal helper object which holds several functions intended - to simplify the creation of concrete communication channel + An internal helper object which holds several functions intended + to simplify the creation of concrete communication channel implementations for WhAjaj.Connector.sendImpl(). These operations take care of some of the more error-prone parts of ensuring that - onResponse(), onError(), etc. callbacks are called consistently + onResponse(), onError(), etc. callbacks are called consistently using the same rules. */ WhAjaj.Connector.sendHelper = { /** - opt is assumed to be a normalized set of - WhAjaj.Connector.sendRequest() options. This function - creates a url by concatenating opt.url and some form of + opt is assumed to be a normalized set of + WhAjaj.Connector.sendRequest() options. This function + creates a url by concatenating opt.url and some form of opt.urlParam. - - If opt.urlParam is an object or string then it is appended - to the url. An object is assumed to be a one-dimensional set - of simple (urlencodable) key/value pairs, and not larger - data structures. A string value is assumed to be a - well-formed, urlencoded set of key/value pairs separated by + + If opt.urlParam is an object or string then it is appended + to the url. An object is assumed to be a one-dimensional set + of simple (urlencodable) key/value pairs, and not larger + data structures. A string value is assumed to be a + well-formed, urlencoded set of key/value pairs separated by '&' characters. - - The new/normalized URL is returned (opt is not modified). If - opt.urlParam is not set then opt.url is returned (or an + + The new/normalized URL is returned (opt is not modified). If + opt.urlParam is not set then opt.url is returned (or an empty string if opt.url is itself a false value). - - TODO: if opt is-a Object and any key points to an array, - build up a list of keys in the form "keyname[]". We could - arguably encode sub-objects like "keyname[subkey]=...", but - i don't know if that's conventions-compatible with other + + TODO: if opt is-a Object and any key points to an array, + build up a list of keys in the form "keyname[]". We could + arguably encode sub-objects like "keyname[subkey]=...", but + i don't know if that's conventions-compatible with other frameworks. */ normalizeURL: function(opt) { var u = opt.url || ''; if( opt.urlParam ) { @@ -564,50 +564,50 @@ u = u + (addQ ? '?' : '') + (addA ? '&' : '') + tail; } return u; }, /** - Should be called by WhAjaj.Connector.sendImpl() - implementations after a response has come back. This - function takes care of most of ensuring that framework-level - conventions involving WhAjaj.Connector.options.ajax + Should be called by WhAjaj.Connector.sendImpl() + implementations after a response has come back. This + function takes care of most of ensuring that framework-level + conventions involving WhAjaj.Connector.options.ajax properties are followed. - - The request argument must be the original request passed to + + The request argument must be the original request passed to the sendImpl() function. It may legally be null for GET requests. - - The opt object should be the normalized AJAX options used + + The opt object should be the normalized AJAX options used for the connection. - - The resp argument may be either a plain Object or a string + + The resp argument may be either a plain Object or a string (in which case it is assumed to be JSON). The 'this' object for this call MUST be a WhAjaj.Connector instance in order for callback processing to work properly. - + This function takes care of the following: - + - Calling opt.afterSend() - + - If resp is a string, de-JSON-izing it to an object. - + - Calling opt.onResponse() - - - Calling opt.onError() in several common (potential) error + + - Calling opt.onError() in several common (potential) error cases. - If resp is-a String and opt.jsonp then resp is assumed to be a JSONP-form construct and is eval()d BEFORE opt.onResponse() is called. It is arguable to eval() it first, but the logic integrates better with the non-jsonp handler. The sendImpl() should return immediately after calling this. - - The sendImpl() must call only one of onSendSuccess() or - onSendError(). It must call one of them or it must implement - its own response/error handling, which is not recommended - because getting the documented semantics of the + + The sendImpl() must call only one of onSendSuccess() or + onSendError(). It must call one of them or it must implement + its own response/error handling, which is not recommended + because getting the documented semantics of the onError/onResponse/afterSend handling correct can be tedious. */ onSendSuccess:function(request,resp,opt) { var cb = this.callbacks || {}; if( WhAjaj.isFunction(cb.afterSend) ) { @@ -666,23 +666,23 @@ Should be called by sendImpl() implementations after a response has failed to connect (e.g. could not resolve host or timeout reached). This function takes care of most of ensuring that framework-level conventions involving WhAjaj.Connector.options.ajax properties are followed. - - The request argument must be the original request passed to - the sendImpl() function. It may legally be null for GET + + The request argument must be the original request passed to + the sendImpl() function. It may legally be null for GET requests. The 'this' object for this call MUST be a WhAjaj.Connector instance in order for callback processing to work properly. - - The opt object should be the normalized AJAX options used - for the connection. By convention, the caller of this - function "should" set opt.errorMessage to contain a + + The opt object should be the normalized AJAX options used + for the connection. By convention, the caller of this + function "should" set opt.errorMessage to contain a human-readable description of the error. - + The sendImpl() should return immediately after calling this. The return value from this function is unspecified. */ onSendError: function(request,opt) { var cb = this.callbacks || {}; @@ -704,64 +704,64 @@ } } }; /** - WhAjaj.Connector.sendImpls holds several concrete - implementations of WhAjaj.Connector.prototype.sendImpl(). To use - a specific implementation by default assign + WhAjaj.Connector.sendImpls holds several concrete + implementations of WhAjaj.Connector.prototype.sendImpl(). To use + a specific implementation by default assign WhAjaj.Connector.prototype.sendImpl to one of these functions. - + The functions defined here require that the 'this' object be-a WhAjaj.Connector instance. - + Historical notes: - a) We once had an implementation based on Prototype, but that - library just pisses me off (they change base-most types' - prototypes, introducing side-effects in client code which - doesn't even use Prototype). The Prototype version at the time - had a serious toJSON() bug which caused empty arrays to - serialize as the string "[]", which broke a bunch of my code. - (That has been fixed in the mean time, but i don't use + a) We once had an implementation based on Prototype, but that + library just pisses me off (they change base-most types' + prototypes, introducing side-effects in client code which + doesn't even use Prototype). The Prototype version at the time + had a serious toJSON() bug which caused empty arrays to + serialize as the string "[]", which broke a bunch of my code. + (That has been fixed in the mean time, but i don't use Prototype.) - - b) We once had an implementation for the dojo library, - + + b) We once had an implementation for the dojo library, + If/when the time comes to add Prototype/dojo support, we simply need to port: - + http://code.google.com/p/jsonmessage/source/browse/trunk/lib/JSONMessage/JSONMessage.inc.js - - (search that file for "dojo" and "Prototype") to this tree. That - code is this code's generic grandfather and they are still very - similar, so a port is trivial. - + + (search that file for "dojo" and "Prototype") to this tree. That + code is this code's generic grandfather and they are still very + similar, so a port is trivial. + */ WhAjaj.Connector.sendImpls = { /** - This is a concrete implementation of - WhAjaj.Connector.prototype.sendImpl() which uses the - environment's native XMLHttpRequest class to send whiki + This is a concrete implementation of + WhAjaj.Connector.prototype.sendImpl() which uses the + environment's native XMLHttpRequest class to send whiki requests and fetch the responses. - The only argument must be a connection properties object, as + The only argument must be a connection properties object, as constructed by WhAjaj.Connector.normalizeAjaxParameters(). - If window.firebug is set then window.firebug.watchXHR() is + If window.firebug is set then window.firebug.watchXHR() is called to enable monitoring of the XMLHttpRequest object. - This implementation honors the loginName and loginPassword + This implementation honors the loginName and loginPassword connection parameters. Returns the XMLHttpRequest object. - This implementation requires that the 'this' object be-a + This implementation requires that the 'this' object be-a WhAjaj.Connector. - - This implementation uses setTimeout() to implement the - timeout support, and thus the JS engine must provide that + + This implementation uses setTimeout() to implement the + timeout support, and thus the JS engine must provide that functionality. */ XMLHttpRequest: function(request, args) { var json = WhAjaj.isObject(request) ? JSON.stringify(request) : request; @@ -864,30 +864,30 @@ WhAjaj.Connector.sendHelper.onSendError.apply( whself, [request, args] ); return undefined; } }/*XMLHttpRequest()*/, /** - This is a concrete implementation of - WhAjaj.Connector.prototype.sendImpl() which uses the jQuery + This is a concrete implementation of + WhAjaj.Connector.prototype.sendImpl() which uses the jQuery AJAX API to send requests and fetch the responses. - The first argument may be either null/false, an Object + The first argument may be either null/false, an Object containing toJSON-able data to post to the back-end, or such an object in JSON string form. - The second argument must be a connection properties object, as + The second argument must be a connection properties object, as constructed by WhAjaj.Connector.normalizeAjaxParameters(). - If window.firebug is set then window.firebug.watchXHR() is + If window.firebug is set then window.firebug.watchXHR() is called to enable monitoring of the XMLHttpRequest object. - This implementation honors the loginName and loginPassword + This implementation honors the loginName and loginPassword connection parameters. Returns the XMLHttpRequest object. - This implementation requires that the 'this' object be-a + This implementation requires that the 'this' object be-a WhAjaj.Connector. */ jQuery:function(request,args) { var data = request || undefined; @@ -943,12 +943,12 @@ WhAjaj.Connector.sendHelper.onSendError.apply( whself, [request, args] ); return undefined; } }/*jQuery()*/, /** - This is a concrete implementation of - WhAjaj.Connector.prototype.sendImpl() which uses the rhino + This is a concrete implementation of + WhAjaj.Connector.prototype.sendImpl() which uses the rhino Java API to send requests and fetch the responses. Limitations vis-a-vis the interface: - timeouts are not supported. @@ -1051,28 +1051,28 @@ WhAjaj.Connector.sendHelper.onSendSuccess.apply( self, [request, json, args] ); }/*rhino*/ }; /** - An internal function which takes an object containing properties - for a WhAjaj.Connector network request. This function creates a new + An internal function which takes an object containing properties + for a WhAjaj.Connector network request. This function creates a new object containing a superset of the properties from: a) opt b) this.options c) WhAjaj.Connector.options.ajax in that order, using the first one it finds. - All non-function properties are _deeply_ copied via JSON cloning - in order to prevent accidental "cross-request pollenation" (been - there, done that). Functions cannot be cloned and are simply + All non-function properties are _deeply_ copied via JSON cloning + in order to prevent accidental "cross-request pollenation" (been + there, done that). Functions cannot be cloned and are simply copied by reference. - + This function throws if JSON-copying one of the options fails (e.g. due to cyclic data structures). - + Reminder to self: this function does not "normalize" opt.urlParam by encoding it into opt.url, mainly for historical reasons, but also because that behaviour was specifically undesirable in this code's genetic father. */ @@ -1100,68 +1100,68 @@ // no, not here: rc.url = WhAjaj.Connector.sendHelper.normalizeURL(rc); return rc; }; /** - This is the generic interface for making calls to a back-end - JSON-producing request handler. It is a simple wrapper around - WhAjaj.Connector.prototype.sendImpl(), which just normalizes the - connection options for sendImpl() and makes sure that + This is the generic interface for making calls to a back-end + JSON-producing request handler. It is a simple wrapper around + WhAjaj.Connector.prototype.sendImpl(), which just normalizes the + connection options for sendImpl() and makes sure that opt.beforeSend() is (possibly) called. - - The request parameter must either be false/null/empty or a - fully-populated JSON-able request object (which will be sent as - unencoded application/json text), depending on the type of - request being made. It is never semantically legal (in this API) - for request to be a string/number/true/array value. As a rule, - only POST requests use the request data. GET requests should + + The request parameter must either be false/null/empty or a + fully-populated JSON-able request object (which will be sent as + unencoded application/json text), depending on the type of + request being made. It is never semantically legal (in this API) + for request to be a string/number/true/array value. As a rule, + only POST requests use the request data. GET requests should encode their data in opt.url or opt.urlParam (see below). - - opt must contain the network-related parameters for the request. - Paramters _not_ set in opt are pulled from this.options or - WhAjaj.Connector.options.ajax (in that order, using the first - value it finds). Thus the set of connection-level options used + + opt must contain the network-related parameters for the request. + Paramters _not_ set in opt are pulled from this.options or + WhAjaj.Connector.options.ajax (in that order, using the first + value it finds). Thus the set of connection-level options used for the request are a superset of those various sources. - - The "normalized" (or "superimposed") opt object's URL may be + + The "normalized" (or "superimposed") opt object's URL may be modified before the request is sent, as follows: - if opt.urlParam is a string then it is assumed to be properly - URL-encoded parameters and is appended to the opt.url. If it is - an Object then it is assumed to be a one-dimensional set of - key/value pairs with simple values (numbers, strings, booleans, - null, and NOT objects/arrays). The keys/values are URL-encoded + if opt.urlParam is a string then it is assumed to be properly + URL-encoded parameters and is appended to the opt.url. If it is + an Object then it is assumed to be a one-dimensional set of + key/value pairs with simple values (numbers, strings, booleans, + null, and NOT objects/arrays). The keys/values are URL-encoded and appended to the URL. The beforeSend() callback (see below) can modify the options object before the request attempt is made. - + The callbacks in the normalized opt object will be triggered as follows (if they are set to Function values): - - - beforeSend(request,opt) will be called before any network - processing starts. If beforeSend() throws then no other - callbacks are triggered and this function propagates the + + - beforeSend(request,opt) will be called before any network + processing starts. If beforeSend() throws then no other + callbacks are triggered and this function propagates the exception. This function is passed normalized connection options as its second parameter, and changes this function makes to that object _will_ be used for the pending connection attempt. - - - onError(request,opt) will be called if a connection to the - back-end cannot be established. It will be passed the original - request object (which might be null, depending on the request - type) and the normalized options object. In the error case, the - opt object passed to onError() "should" have a property called + + - onError(request,opt) will be called if a connection to the + back-end cannot be established. It will be passed the original + request object (which might be null, depending on the request + type) and the normalized options object. In the error case, the + opt object passed to onError() "should" have a property called "errorMessage" which contains a description of the problem. - - - onError(request,opt) will also be called if connection + + - onError(request,opt) will also be called if connection succeeds but the response is not JSON data. - - - onResponse(response,request) will be called if the response - returns JSON data. That data might hold an error response code - - clients need to check for that. It is passed the response object + + - onResponse(response,request) will be called if the response + returns JSON data. That data might hold an error response code - + clients need to check for that. It is passed the response object (a plain object) and the original request object. - + - afterSend(request,opt) will be called directly after the AJAX request is finished, before onError() or onResonse() are called. Possible TODO: we explicitly do NOT pass the response to this function in order to keep the line between the responsibilities of the various callback clear (otherwise this could be used the same @@ -1179,14 +1179,14 @@ { throw new Error("This object has no sendImpl() member function! I don't know how to send the request!"); } var ex = false; var av = Array.prototype.slice.apply( arguments, [0] ); - + /** - FIXME: how to handle the error, vis-a-vis- the callbacks, if - normalizeAjaxParameters() throws? It can throw if + FIXME: how to handle the error, vis-a-vis- the callbacks, if + normalizeAjaxParameters() throws? It can throw if (de)JSON-izing fails. */ var norm = this.normalizeAjaxParameters( WhAjaj.isObject(opt) ? opt : {} ); norm.url = WhAjaj.Connector.sendHelper.normalizeURL(norm); if( ! request ) norm.method = 'GET'; Index: ajax/wiki-editor.html ================================================================== --- ajax/wiki-editor.html +++ ajax/wiki-editor.html @@ -277,11 +277,11 @@ if(resp.resultCode) return; delete p.isNew; p.timestamp = resp.payload.timestamp; } }); - + }; TheApp.createNewPage = function(){ var name = prompt("New page name?"); if(!name) return; Index: auto.def ================================================================== --- auto.def +++ auto.def @@ -88,17 +88,17 @@ # the code below will append -ldl to LIBS. # foreach extralibs {{} {-ldl}} { # Locate the system SQLite by searching for sqlite3_open(). Then check - # if sqlite3_strlike() can be found as well. If we can find open() but - # not strlike(), then the system SQLite is too old to link against + # if sqlite3_trace_v2() can be found as well. If we can find open() but + # not trace_v2(), then the system SQLite is too old to link against # fossil. # if {[check-function-in-lib sqlite3_open sqlite3 $extralibs]} { - if {![check-function-in-lib sqlite3_strlike sqlite3 $extralibs]} { - user-error "system sqlite3 too old (require >= 3.10.0)" + if {![check-function-in-lib sqlite3_trace_v2 sqlite3 $extralibs]} { + user-error "system sqlite3 too old (require >= 3.14.0)" } # Success. Update symbols and return. # define USE_SYSTEM_SQLITE 1 @@ -194,11 +194,11 @@ # Helper for OpenSSL checking proc check-for-openssl {msg {cflags {}} {libs {-lssl -lcrypto}}} { msg-checking "Checking for $msg..." set rc 0 if {[is_mingw]} { - lappend libs -lgdi32 -lwsock32 + lappend libs -lgdi32 -lwsock32 -lcrypt32 } if {[info exists ::zlib_lib]} { lappend libs $::zlib_lib } msg-quiet cc-with [list -cflags $cflags -libs $libs] { @@ -313,11 +313,11 @@ } if {[info exists ::zlib_lib]} { define-append LIBS $::zlib_lib } if {[is_mingw]} { - define-append LIBS -lgdi32 -lwsock32 + define-append LIBS -lgdi32 -lwsock32 -lcrypt32 } msg-result "HTTPS support enabled" # Silence OpenSSL deprecation warnings on Mac OS X 10.7. if {[string match *-darwin* [get-define host]]} { Index: src/add.c ================================================================== --- src/add.c +++ src/add.c @@ -385,11 +385,11 @@ */ static void process_files_to_remove( int dryRunFlag /* Zero to actually operate on the file-system. */ ){ Stmt remove; - if( db_table_exists(db_name("temp"), "fremove") ){ + if( db_table_exists("temp", "fremove") ){ db_prepare(&remove, "SELECT x FROM fremove ORDER BY x;"); while( db_step(&remove)==SQLITE_ROW ){ const char *zOldName = db_column_text(&remove, 0); if( !dryRunFlag ){ file_delete(zOldName); @@ -550,13 +550,12 @@ #endif caseSensitive = db_get_boolean("case-sensitive",caseSensitive); } if( !caseSensitive && g.localOpen ){ db_multi_exec( - "CREATE INDEX IF NOT EXISTS %s.vfile_nocase" - " ON vfile(pathname COLLATE nocase)", - db_name("localdb") + "CREATE INDEX IF NOT EXISTS localdb.vfile_nocase" + " ON vfile(pathname COLLATE nocase)" ); } } return caseSensitive; } @@ -779,11 +778,11 @@ */ static void process_files_to_move( int dryRunFlag /* Zero to actually operate on the file-system. */ ){ Stmt move; - if( db_table_exists(db_name("temp"), "fmove") ){ + if( db_table_exists("temp", "fmove") ){ db_prepare(&move, "SELECT x, y FROM fmove ORDER BY x;"); while( db_step(&move)==SQLITE_ROW ){ const char *zOldName = db_column_text(&move, 0); const char *zNewName = db_column_text(&move, 1); if( !dryRunFlag ){ Index: src/allrepo.c ================================================================== --- src/allrepo.c +++ src/allrepo.c @@ -51,12 +51,13 @@ ** Build a string that contains all of the command-line options ** specified as arguments. If the option name begins with "+" then ** it takes an argument. Without the "+" it does not. */ static void collect_argument(Blob *pExtra, const char *zArg, const char *zShort){ - if( find_option(zArg, zShort, 0)!=0 ){ - blob_appendf(pExtra, " --%s", zArg); + const char *z = find_option(zArg, zShort, 0); + if( z!=0 ){ + blob_appendf(pExtra, " %s", z); } } static void collect_argument_value(Blob *pExtra, const char *zArg){ const char *zValue = find_option(zArg, 0, 1); if( zValue ){ @@ -271,10 +272,11 @@ zCmd = "fts-config -R"; collect_argv(&extra, 3); }else if( strncmp(zCmd, "sync", n)==0 ){ zCmd = "sync -autourl -R"; collect_argument(&extra, "verbose","v"); + collect_argument(&extra, "unversioned","u"); }else if( strncmp(zCmd, "test-integrity", n)==0 ){ collect_argument(&extra, "parse", 0); zCmd = "test-integrity"; }else if( strncmp(zCmd, "test-orphans", n)==0 ){ zCmd = "test-orphans -R"; Index: src/attach.c ================================================================== --- src/attach.c +++ src/attach.c @@ -86,11 +86,11 @@ const char *zFilename = db_column_text(&q, 3); const char *zComment = db_column_text(&q, 4); const char *zUser = db_column_text(&q, 5); const char *zUuid = db_column_text(&q, 6); int attachid = db_column_int(&q, 7); - // type 0 is a wiki page, 1 is a ticket, 2 is a tech note + /* type 0 is a wiki page, 1 is a ticket, 2 is a tech note */ int type = db_column_int(&q, 8); const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous"; int i; char *zUrlTail; for(i=0; zFilename[i]; i++){ @@ -699,10 +699,16 @@ ** with the specified timestamp. ** -t|--technote TECHNOTE-ID Specifies the technote to be ** updated by its technote id. ** ** One of PAGENAME, DATETIME or TECHNOTE-ID must be specified. +** +** DATETIME may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in +** year-month-day form, it may be truncated, the "T" may be replaced by +** a space, and it may also name a timezone offset from UTC as "-HH:MM" +** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z" +** means UTC. */ void attachment_cmd(void){ int n; db_find_and_open_repository(0, 0); if( g.argc<3 ){ Index: src/blob.c ================================================================== --- src/blob.c +++ src/blob.c @@ -653,19 +653,47 @@ */ int blob_is_uuid(Blob *pBlob){ return blob_size(pBlob)==UUID_SIZE && validate16(blob_buffer(pBlob), UUID_SIZE); } + +/* +** Return true if the blob contains a valid filename +*/ +int blob_is_filename(Blob *pBlob){ + return file_is_simple_pathname(blob_str(pBlob), 1); +} /* ** Return true if the blob contains a valid 32-bit integer. Store ** the integer value in *pValue. */ int blob_is_int(Blob *pBlob, int *pValue){ const char *z = blob_buffer(pBlob); int i, n, c, v; n = blob_size(pBlob); + v = 0; + for(i=0; i='0' && c<='9'; i++){ + v = v*10 + c - '0'; + } + if( i==n ){ + *pValue = v; + return 1; + }else{ + return 0; + } +} + +/* +** Return true if the blob contains a valid 64-bit integer. Store +** the integer value in *pValue. +*/ +int blob_is_int64(Blob *pBlob, sqlite3_int64 *pValue){ + const char *z = blob_buffer(pBlob); + int i, n, c; + sqlite3_int64 v; + n = blob_size(pBlob); v = 0; for(i=0; i='0' && c<='9'; i++){ v = v*10 + c - '0'; } if( i==n ){ @@ -1000,11 +1028,11 @@ ** COMMAND: test-uncompress ** ** Usage: %fossil test-uncompress IN OUT ** ** Read the content of file IN, uncompress that content, and write the -** result into OUT. This command is intended for testing of the the +** result into OUT. This command is intended for testing of the ** blob_compress() function. */ void uncompress_cmd(void){ Blob f; if( g.argc!=4 ) usage("INPUTFILE OUTPUTFILE"); Index: src/branch.c ================================================================== --- src/branch.c +++ src/branch.c @@ -188,11 +188,11 @@ #define BRL_CLOSED_ONLY 0x001 /* Show only closed branches */ #define BRL_OPEN_ONLY 0x002 /* Show only open branches */ #define BRL_BOTH 0x003 /* Show both open and closed branches */ #define BRL_OPEN_CLOSED_MASK 0x003 #define BRL_MTIME 0x004 /* Include lastest check-in time */ -#dfeine BRL_ORDERBY_MTIME 0x008 /* Sort by MTIME. (otherwise sort by name)*/ +#define BRL_ORDERBY_MTIME 0x008 /* Sort by MTIME. (otherwise sort by name)*/ #endif /* INTERFACE */ /* ** Prepare a query that will list branches. @@ -257,10 +257,16 @@ ** --private branch is private (i.e., remains local) ** --bgcolor COLOR use COLOR instead of automatic background ** --nosign do not sign contents on this branch ** --date-override DATE DATE to use instead of 'now' ** --user-override USER USER to use instead of the current default +** +** DATE may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in +** year-month-day form, it may be truncated, the "T" may be +** replaced by a space, and it may also name a timezone offset +** from UTC as "-HH:MM" (westward) or "+HH:MM" (eastward). +** Either no timezone suffix or "Z" means UTC. ** ** %fossil branch list ?-a|--all|-c|--closed? ** %fossil branch ls ?-a|--all|-c|--closed? ** ** List all branches. Use -a or --all to list all branches and Index: src/bundle.c ================================================================== --- src/bundle.c +++ src/bundle.c @@ -313,11 +313,11 @@ " VALUES('mtime',datetime('now'));" ); db_multi_exec( "INSERT INTO bconfig(bcname,bcvalue)" " SELECT name, value FROM config" - " WHERE name IN ('project-code');" + " WHERE name IN ('project-code','parent-project-code');" ); /* Directly copy content from the repository into the bundle as long ** as the repository content is a delta from some other artifact that ** is also in the bundle. Index: src/checkin.c ================================================================== --- src/checkin.c +++ src/checkin.c @@ -546,11 +546,11 @@ } } /* ** COMMAND: extras -** +** ** Usage: %fossil extras ?OPTIONS? ?PATH1 ...? ** ** Print a list of all files in the source tree that are not part of the ** current checkout. See also the "clean" command. If paths are specified, ** only files in the given directories will be listed. @@ -632,11 +632,11 @@ db_finalize(&q); } /* ** COMMAND: clean -** +** ** Usage: %fossil clean ?OPTIONS? ?PATH ...? ** ** Delete all "extra" files in the source tree. "Extra" files are files ** that are not officially part of the checkout. If one or more PATH ** arguments appear, then only the files named, or files contained with @@ -645,21 +645,21 @@ ** If the --prompt option is used, prompts are issued to confirm the ** permanent removal of each file. Otherwise, files are backed up to the ** undo buffer prior to removal, and prompts are issued only for files ** whose removal cannot be undone due to their large size or due to ** --disable-undo being used. -** +** ** The --force option treats all prompts as having been answered yes, ** whereas --no-prompt treats them as having been answered no. -** +** ** Files matching any glob pattern specified by the --clean option are ** deleted without prompting, and the removal cannot be undone. ** ** No file that matches glob patterns specified by --ignore or --keep will ** ever be deleted. Files and subdirectories whose names begin with "." ** are automatically ignored unless the --dotfiles option is used. -** +** ** The default values for --clean, --ignore, and --keep are determined by ** the (versionable) clean-glob, ignore-glob, and keep-glob settings. ** ** The --verily option ignores the keep-glob and ignore-glob settings and ** turns on --force, --emptydirs, --dotfiles, and --disable-undo. Use the @@ -1689,12 +1689,18 @@ ** --nosign do not attempt to sign this commit with gpg ** --private do not sync changes and their descendants ** --sha1sum verify file status using SHA1 hashing rather ** than relying on file mtimes ** --tag TAG-NAME assign given tag TAG-NAME to the check-in -** --date-override DATE DATE to use instead of 'now' +** --date-override DATETIME DATE to use instead of 'now' ** --user-override USER USER to use instead of the current default +** +** DATETIME may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in +** year-month-day form, it may be truncated, the "T" may be replaced by +** a space, and it may also name a timezone offset from UTC as "-HH:MM" +** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z" +** means UTC. ** ** See also: branch, changes, checkout, extras, sync */ void commit_cmd(void){ int hasChanges; /* True if unsaved changes exist */ @@ -2223,12 +2229,12 @@ /* Clear the undo/redo stack */ undo_reset(); /* Commit */ db_multi_exec("DELETE FROM vvar WHERE name='ci-comment'"); - db_multi_exec("PRAGMA %s.application_id=252006673;", db_name("repository")); - db_multi_exec("PRAGMA %s.application_id=252006674;", db_name("localdb")); + db_multi_exec("PRAGMA repository.application_id=252006673;"); + db_multi_exec("PRAGMA localdb.application_id=252006674;"); if( dryRunFlag ){ db_end_transaction(1); exit(1); } db_end_transaction(0); Index: src/checkout.c ================================================================== --- src/checkout.c +++ src/checkout.c @@ -306,11 +306,11 @@ if( !forceFlag && unsaved_changes(0) ){ fossil_fatal("there are unsaved changes in the current checkout"); } if( !forceFlag && db_table_exists("localdb","stash") - && db_exists("SELECT 1 FROM %s.stash", db_name("localdb")) + && db_exists("SELECT 1 FROM localdb.stash") ){ fossil_fatal("closing the checkout will delete your stash"); } if( db_is_writeable("repository") ){ char *zUnset = mprintf("ckout:%q", g.zLocalRoot); Index: src/clone.c ================================================================== --- src/clone.c +++ src/clone.c @@ -99,11 +99,11 @@ ** [file://]path/to/repo.fossil ** ** Note 1: For ssh and filesystem, path must have an extra leading ** '/' to use an absolute path. ** -** Note 2: Use %HH escapes for special characters in the userid and +** Note 2: Use %HH escapes for special characters in the userid and ** password. For example "%40" in place of "@", "%2f" in place ** of "/", and "%3a" in place of ":". ** ** By default, your current login name is used to create the default ** admin user. This can be overridden using the -A|--admin-user @@ -114,11 +114,12 @@ ** --once Don't remember the URI. ** --private Also clone private branches ** --ssl-identity FILENAME Use the SSL identity if requested by the server ** --ssh-command|-c SSH Use SSH as the "ssh" command ** --httpauth|-B USER:PASS Add HTTP Basic Authorization to requests -** --verbose Show more statistics in output +** -u|--unversioned Also sync unversioned content +** -v|--verbose Show more statistics in output ** ** See also: init */ void clone_cmd(void){ char *zPassword; @@ -129,11 +130,12 @@ int syncFlags = SYNC_CLONE; /* Also clone private branches */ if( find_option("private",0,0)!=0 ) syncFlags |= SYNC_PRIVATE; if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER; - if( find_option("verbose",0,0)!=0) syncFlags |= SYNC_VERBOSE; + if( find_option("verbose","v",0)!=0) syncFlags |= SYNC_VERBOSE; + if( find_option("unversioned","u",0)!=0 ) syncFlags |= SYNC_UNVERSIONED; zHttpAuth = find_option("httpauth","B",1); zDefaultUser = find_option("admin-user","A",1); clone_ssh_find_options(); url_proxy_options(); Index: src/codecheck1.c ================================================================== --- src/codecheck1.c +++ src/codecheck1.c @@ -249,11 +249,10 @@ ** A list of functions that return strings that are safe to insert into ** SQL using %s. */ static const char *azSafeFunc[] = { "filename_collation", - "db_name", "leaf_is_closed_sql", "timeline_query_for_www", "timeline_query_for_tty", "blob_sql_text", "glob_expr", Index: src/configure.c ================================================================== --- src/configure.c +++ src/configure.c @@ -126,10 +126,12 @@ { "crnl-glob", CONFIGSET_PROJ }, { "encoding-glob", CONFIGSET_PROJ }, { "empty-dirs", CONFIGSET_PROJ }, { "allow-symlinks", CONFIGSET_PROJ }, { "dotfiles", CONFIGSET_PROJ }, + { "parent-project-code", CONFIGSET_PROJ }, + { "parent-project-name", CONFIGSET_PROJ }, #ifdef FOSSIL_ENABLE_LEGACY_MV_RM { "mv-rm-files", CONFIGSET_PROJ }, #endif Index: src/content.c ================================================================== --- src/content.c +++ src/content.c @@ -452,10 +452,30 @@ ** Turn dephantomization processing on or off. */ void content_enable_dephantomize(int onoff){ ignoreDephantomizations = !onoff; } + +/* +** Make sure the g.rcvid global variable has been initialized. +** +** If the g.zIpAddr variable has not been set when this routine is +** called, use zSrc as the source of content for the rcvfrom +** table entry. +*/ +void content_rcvid_init(const char *zSrc){ + if( g.rcvid==0 ){ + user_select(); + if( g.zIpAddr ) zSrc = g.zIpAddr; + db_multi_exec( + "INSERT INTO rcvfrom(uid, mtime, nonce, ipaddr)" + "VALUES(%d, julianday('now'), %Q, %Q)", + g.userUid, g.zNonce, zSrc + ); + g.rcvid = db_last_insert_rowid(); + } +} /* ** Write content into the database. Return the record ID. If the ** content is already in the database, just return the record ID. ** @@ -530,18 +550,11 @@ markAsUnclustered = 1; } db_finalize(&s1); /* Construct a received-from ID if we do not already have one */ - if( g.rcvid==0 ){ - db_multi_exec( - "INSERT INTO rcvfrom(uid, mtime, nonce, ipaddr)" - "VALUES(%d, julianday('now'), %Q, %Q)", - g.userUid, g.zNonce, g.zIpAddr - ); - g.rcvid = db_last_insert_rowid(); - } + content_rcvid_init(0); if( nBlob ){ cmpr = pBlob[0]; }else{ blob_compress(pBlob, &cmpr); @@ -1163,11 +1176,11 @@ db_find_and_open_repository(OPEN_ANY_SCHEMA, 0); db_begin_transaction(); db_prepare(&q, "SELECT rid FROM delta WHERE srcid=:rid"); for(i=2; ivalue)) /** Assumes V is a pointer to memory which is allocated as part of a cson_value instance (the bytes immediately after that part). - Returns a pointer a a cson_value by subtracting sizeof(cson_value) + Returns a pointer a cson_value by subtracting sizeof(cson_value) from that address and casting it to a (cson_value*) */ #define CSON_VCAST(V) ((cson_value *)(((unsigned char *)(V))-sizeof(cson_value))) /** Index: src/db.c ================================================================== --- src/db.c +++ src/db.c @@ -934,11 +934,11 @@ db, "is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0 ); sqlite3_create_function( db, "if_selected", 3, SQLITE_UTF8, 0, file_is_selected,0,0 ); - if( g.fSqlTrace ) sqlite3_trace(db, db_sql_trace, 0); + if( g.fSqlTrace ) sqlite3_trace_v2(db, SQLITE_TRACE_STMT, db_sql_trace, 0); db_add_aux_functions(db); re_add_sql_func(db); /* The REGEXP operator */ foci_register(db); /* The "files_of_checkin" virtual table */ sqlite3_exec(db, "PRAGMA foreign_keys=OFF;", 0, 0, 0); return db; @@ -961,52 +961,79 @@ db_encryption_key(zDbName, &key); db_multi_exec("ATTACH DATABASE %Q AS %Q KEY %Q", zDbName, zLabel, blob_str(&key)); blob_reset(&key); } + +/* +** Change the schema name of the "main" database to zLabel. +** zLabel must be a static string that is unchanged for the life of +** the database connection. +** +** After calling this routine, db_database_slot(zLabel) should +** return 0. +*/ +void db_set_main_schemaname(sqlite3 *db, const char *zLabel){ + if( sqlite3_db_config(db, SQLITE_DBCONFIG_MAINDBNAME, zLabel) ){ + fossil_fatal("Fossil requires a version of SQLite that supports the " + "SQLITE_DBCONFIG_MAINDBNAME interface."); + } +} + +/* +** Return the slot number for database zLabel. The first database +** opened is slot 0. The "temp" database is slot 1. Attached databases +** are slots 2 and higher. +** +** Return -1 if zLabel does not match any open database. +*/ +int db_database_slot(const char *zLabel){ + int iSlot = -1; + Stmt q; + if( g.db==0 ) return iSlot; + db_prepare(&q, "PRAGMA database_list"); + while( db_step(&q)==SQLITE_ROW ){ + if( fossil_strcmp(db_column_text(&q,1),zLabel)==0 ){ + iSlot = db_column_int(&q, 0); + break; + } + } + db_finalize(&q); + return iSlot; +} /* ** zDbName is the name of a database file. If no other database ** file is open, then open this one. If another database file is ** already open, then attach zDbName using the name zLabel. */ -void db_open_or_attach( - const char *zDbName, - const char *zLabel, - int *pWasAttached -){ +void db_open_or_attach(const char *zDbName, const char *zLabel){ if( !g.db ){ - assert( g.zMainDbType==0 ); g.db = db_open(zDbName); - g.zMainDbType = zLabel; - if( pWasAttached ) *pWasAttached = 0; + db_set_main_schemaname(g.db, zLabel); }else{ - assert( g.zMainDbType!=0 ); db_attach(zDbName, zLabel); - if( pWasAttached ) *pWasAttached = 1; } } /* -** Close the user database. +** Close the per-user database file in ~/.fossil */ void db_close_config(){ - if( g.useAttach ){ + int iSlot = db_database_slot("configdb"); + if( iSlot>0 ){ db_detach("configdb"); - g.useAttach = 0; g.zConfigDbName = 0; }else if( g.dbConfig ){ sqlite3_wal_checkpoint(g.dbConfig, 0); sqlite3_close(g.dbConfig); g.dbConfig = 0; - g.zConfigDbType = 0; g.zConfigDbName = 0; - }else if( g.db && fossil_strcmp(g.zMainDbType, "configdb")==0 ){ + }else if( g.db && 0==iSlot ){ sqlite3_wal_checkpoint(g.db, 0); sqlite3_close(g.db); g.db = 0; - g.zMainDbType = 0; g.zConfigDbName = 0; } } /* @@ -1023,11 +1050,12 @@ */ int db_open_config(int useAttach, int isOptional){ char *zDbName; char *zHome; if( g.zConfigDbName ){ - if( useAttach==g.useAttach ) return 1; /* Already open. */ + int alreadyAttached = db_database_slot("configdb")>0; + if( useAttach==alreadyAttached ) return 1; /* Already open. */ db_close_config(); } zHome = fossil_getenv("FOSSIL_HOME"); #if defined(_WIN32) || defined(__CYGWIN__) if( zHome==0 ){ @@ -1077,17 +1105,15 @@ if( file_access(zDbName, W_OK) ){ if( isOptional ) return 0; fossil_fatal("configuration file %s must be writeable", zDbName); } if( useAttach ){ - db_open_or_attach(zDbName, "configdb", &g.useAttach); + db_open_or_attach(zDbName, "configdb"); g.dbConfig = 0; - g.zConfigDbType = 0; }else{ - g.useAttach = 0; g.dbConfig = db_open(zDbName); - g.zConfigDbType = "configdb"; + db_set_main_schemaname(g.dbConfig, "configdb"); } g.zConfigDbName = zDbName; return 1; } @@ -1096,13 +1122,12 @@ */ int db_table_exists( const char *zDb, /* One of: NULL, "configdb", "localdb", "repository" */ const char *zTable /* Name of table */ ){ - return sqlite3_table_column_metadata(g.db, - zDb ? db_name(zDb) : 0, zTable, 0, - 0, 0, 0, 0, 0)==SQLITE_OK; + return sqlite3_table_column_metadata(g.db, zDb, zTable, 0, + 0, 0, 0, 0, 0)==SQLITE_OK; } /* ** Return TRUE if zTable exists and contains column zColumn. ** Return FALSE if zTable does not exist or if zTable exists @@ -1111,13 +1136,12 @@ int db_table_has_column( const char *zDb, /* One of: NULL, "config", "localdb", "repository" */ const char *zTable, /* Name of table */ const char *zColumn /* Name of column in table */ ){ - return sqlite3_table_column_metadata(g.db, - zDb ? db_name(zDb) : 0, zTable, zColumn, - 0, 0, 0, 0, 0)==SQLITE_OK; + return sqlite3_table_column_metadata(g.db, zDb, zTable, zColumn, + 0, 0, 0, 0, 0)==SQLITE_OK; } /* ** Returns TRUE if zTable exists in the local database but lacks column ** zColumn @@ -1124,12 +1148,12 @@ */ static int db_local_table_exists_but_lacks_column( const char *zTable, const char *zColumn ){ - return db_table_exists(db_name("localdb"), zTable) - && !db_table_has_column(db_name("localdb"), zTable, zColumn); + return db_table_exists("localdb", zTable) + && !db_table_has_column("localdb", zTable, zColumn); } /* ** If zDbName is a valid local database file, open it and return ** true. If it is not a valid local database file, return 0. @@ -1139,13 +1163,13 @@ char *zVFileDef; if( file_access(zDbName, F_OK) ) return 0; lsize = file_size(zDbName); if( lsize%1024!=0 || lsize<4096 ) return 0; - db_open_or_attach(zDbName, "localdb", 0); - zVFileDef = db_text(0, "SELECT sql FROM %s.sqlite_master" - " WHERE name=='vfile'", db_name("localdb")); + db_open_or_attach(zDbName, "localdb"); + zVFileDef = db_text(0, "SELECT sql FROM localdb.sqlite_master" + " WHERE name=='vfile'"); if( zVFileDef==0 ) return 0; /* If the "isexe" column is missing from the vfile table, then ** add it now. This code added on 2010-03-06. After all users have ** upgraded, this code can be safely deleted. @@ -1290,11 +1314,11 @@ #endif fossil_panic("not a valid repository: %s", zDbName); } } g.zRepositoryName = mprintf("%s", zDbName); - db_open_or_attach(g.zRepositoryName, "repository", 0); + db_open_or_attach(g.zRepositoryName, "repository"); g.repositoryOpen = 1; /* Cache "allow-symlinks" option, because we'll need it on every stat call */ g.allowSymlinks = db_get_boolean("allow-symlinks", db_allow_symlinks_by_default()); g.zAuxSchema = db_get("aux-schema",""); @@ -1304,11 +1328,11 @@ ** can be removed in the future, once all users have upgraded to the ** 2014-11-28 or later schema. */ if( !db_table_has_column("repository","plink","baseid") ){ db_multi_exec( - "ALTER TABLE %s.plink ADD COLUMN baseid;", db_name("repository") + "ALTER TABLE repository.plink ADD COLUMN baseid;" ); } /* Verify that the MLINK table has the newer columns added by the ** 2015-01-24 schema change. Create them if necessary. This code @@ -1316,13 +1340,12 @@ ** 2015-01-24 or later schema. */ if( !db_table_has_column("repository","mlink","isaux") ){ db_begin_transaction(); db_multi_exec( - "ALTER TABLE %s.mlink ADD COLUMN pmid INTEGER DEFAULT 0;" - "ALTER TABLE %s.mlink ADD COLUMN isaux BOOLEAN DEFAULT 0;", - db_name("repository"), db_name("repository") + "ALTER TABLE repository.mlink ADD COLUMN pmid INTEGER DEFAULT 0;" + "ALTER TABLE repository.mlink ADD COLUMN isaux BOOLEAN DEFAULT 0;" ); db_end_transaction(0); } } @@ -1374,22 +1397,10 @@ fossil_fatal("specify the repository name as a command-line argument"); } } } -/* -** Return the name of the database "localdb", "configdb", or "repository". -*/ -const char *db_name(const char *zDb){ - assert( fossil_strcmp(zDb,"localdb")==0 - || fossil_strcmp(zDb,"configdb")==0 - || fossil_strcmp(zDb,"repository")==0 - || fossil_strcmp(zDb,"temp")==0 ); - if( fossil_strcmp(zDb, g.zMainDbType)==0 ) zDb = "main"; - return zDb; -} - /* ** Return TRUE if the schema is out-of-date */ int db_schema_is_outofdate(void){ return strcmp(g.zAuxSchema,AUX_SCHEMA_MIN)<0 @@ -1398,11 +1409,11 @@ /* ** Return true if the database is writeable */ int db_is_writeable(const char *zName){ - return g.db!=0 && !sqlite3_db_readonly(g.db, db_name(zName)); + return g.db!=0 && !sqlite3_db_readonly(g.db, zName); } /* ** Verify that the repository schema is correct. If it is not correct, ** issue a fatal error and die. @@ -1443,11 +1454,11 @@ } if( db_open_local(zRepo)==0 ){ fossil_fatal("not in a local checkout"); return; } - db_open_or_attach(zRepo, "test_repo", 0); + db_open_or_attach(zRepo, "test_repo"); db_lset("repository", blob_str(&repo)); db_record_repository_filename(blob_str(&repo)); db_close(1); } @@ -1503,18 +1514,18 @@ } db_end_transaction(1); pStmt = 0; db_close_config(); - /* If the localdb (the check-out database) is open and if it has - ** a lot of unused free space, then VACUUM it as we shut down. + /* If the localdb has a lot of unused free space, + ** then VACUUM it as we shut down. */ - if( g.localOpen && strcmp(db_name("localdb"),"main")==0 ){ - int nFree = db_int(0, "PRAGMA main.freelist_count"); - int nTotal = db_int(0, "PRAGMA main.page_count"); + if( db_database_slot("localdb")>=0 ){ + int nFree = db_int(0, "PRAGMA localdb.freelist_count"); + int nTotal = db_int(0, "PRAGMA localdb.page_count"); if( nFree>nTotal/4 ){ - db_multi_exec("VACUUM;"); + db_multi_exec("VACUUM localdb;"); } } if( g.db ){ int rc; @@ -1524,18 +1535,15 @@ while( (pStmt = sqlite3_next_stmt(g.db, pStmt))!=0 ){ fossil_warning("unfinalized SQL statement: [%s]", sqlite3_sql(pStmt)); } } g.db = 0; - g.zMainDbType = 0; } g.repositoryOpen = 0; g.localOpen = 0; assert( g.dbConfig==0 ); - assert( g.useAttach==0 ); assert( g.zConfigDbName==0 ); - assert( g.zConfigDbType==0 ); } /* ** Create a new empty repository database with the given name. @@ -1750,10 +1758,16 @@ ** ** Options: ** --template FILE copy settings from repository file ** --admin-user|-A USERNAME select given USERNAME as admin user ** --date-override DATETIME use DATETIME as time of the initial check-in +** +** DATETIME may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in +** year-month-day form, it may be truncated, the "T" may be replaced by +** a space, and it may also name a timezone offset from UTC as "-HH:MM" +** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z" +** means UTC. ** ** See also: clone */ void create_repository_cmd(void){ char *zPassword; @@ -1808,13 +1822,21 @@ char c = i==argc-1 ? '\n' : ' '; fossil_print("%s%c", sqlite3_value_text(argv[i]), c); } } } -LOCAL void db_sql_trace(void *notUsed, const char *zSql){ - int n = strlen(zSql); +LOCAL int db_sql_trace(unsigned m, void *notUsed, void *pP, void *pX){ + sqlite3_stmt *pStmt = (sqlite3_stmt*)pP; + char *zSql; + int n; + const char *zArg = (const char*)pX; + if( zArg[0]=='-' ) return 0; + zSql = sqlite3_expanded_sql(pStmt); + n = (int)strlen(zSql); fossil_trace("%s%s\n", zSql, (n>0 && zSql[n-1]==';') ? "" : ";"); + sqlite3_free(zSql); + return 0; } /* ** Implement the user() SQL function. user() takes no arguments and ** returns the user ID of the current user. @@ -1994,15 +2016,12 @@ ** because the main database connection was already pointing to the config ** database. */ if( g.dbConfig ){ sqlite3 *dbTemp = g.db; - const char *zTempDbType = g.zMainDbType; g.db = g.dbConfig; - g.zMainDbType = g.zConfigDbType; g.dbConfig = dbTemp; - g.zConfigDbType = zTempDbType; } } /* ** Try to read a versioned setting string from .fossil-settings/. @@ -2862,16 +2881,20 @@ ** ** Options: ** --global set or unset the given property globally instead of ** setting or unsetting it for the open repository only. ** +** --exact only consider exact name matches. +** ** See also: configuration */ void setting_cmd(void){ int i; int globalFlag = find_option("global","g",0)!=0; + int exactFlag = find_option("exact",0,0)!=0; int unsetFlag = g.argv[1][0]=='u'; + verify_all_options(); db_open_config(1, 0); if( !globalFlag ){ db_find_and_open_repository(OPEN_ANY_SCHEMA | OPEN_OK_NOT_FOUND, 0); } if( !g.repositoryOpen ){ @@ -2897,11 +2920,11 @@ print_setting(&aSetting[i]); } }else if( g.argc==3 || g.argc==4 ){ const char *zName = g.argv[2]; int n = (int)strlen(zName); - const Setting *pSetting = db_find_setting(zName, 1); + const Setting *pSetting = db_find_setting(zName, !exactFlag); if( pSetting==0 ){ fossil_fatal("no such setting: %s", zName); } if( globalFlag && fossil_strcmp(pSetting->name, "manifest")==0 ){ fossil_fatal("cannot set 'manifest' globally"); @@ -2930,11 +2953,16 @@ } if( isManifest && g.localOpen ){ manifest_to_disk(db_lget_int("checkout", 0)); } }else{ - while( pSetting->name && fossil_strncmp(pSetting->name,zName,n)==0 ){ + while( pSetting->name ){ + if( exactFlag ){ + if( fossil_strcmp(pSetting->name,zName)!=0 ) break; + }else{ + if( fossil_strncmp(pSetting->name,zName,n)!=0 ) break; + } print_setting(pSetting); pSetting++; } } }else{ @@ -2969,11 +2997,11 @@ return sqlite3_mprintf("%.1f years", rSpan); } /* ** COMMAND: test-timespan -** +** ** Usage: %fossil test-timespan TIMESTAMP ** ** Print the approximate span of time from now to TIMESTAMP. */ void test_timespan_cmd(void){ @@ -2986,11 +3014,11 @@ g.db = 0; } /* ** COMMAND: test-without-rowid -** +** ** Usage: %fossil test-without-rowid FILENAME... ** ** Change the Fossil repository FILENAME to make use of the WITHOUT ROWID ** optimization. FILENAME can also be the ~/.fossil file or a local ** .fslckout or _FOSSIL_ file. @@ -3005,11 +3033,11 @@ int i, j; Stmt q; Blob allSql; int dryRun = find_option("dry-run", "n", 0)!=0; for(i=2; i=1300 while( z= 16){ sum0 += ((unsigned)z[0] + z[4] + z[8] + z[12]); Index: src/descendants.c ================================================================== --- src/descendants.c +++ src/descendants.c @@ -196,11 +196,11 @@ "WITH RECURSIVE g(x,i) AS (" " VALUES(%d,1)" " UNION ALL" " SELECT plink.pid, g.i+1 FROM plink, g" " WHERE plink.cid=g.x AND plink.isprim)" - "INSERT INTO ancestor(rid,generation) SELECT x,i FROM g;", + "INSERT INTO ancestor(rid,generation) SELECT x,i FROM g;", rid ); } /* Index: src/diff.c ================================================================== --- src/diff.c +++ src/diff.c @@ -113,11 +113,11 @@ int nEditAlloc; /* Space allocated for aEdit[] */ DLine *aFrom; /* File on left side of the diff */ int nFrom; /* Number of lines in aFrom[] */ DLine *aTo; /* File on right side of the diff */ int nTo; /* Number of lines in aTo[] */ - int (*same_fn)(const DLine *, const DLine *); /* Function to be used for comparing */ + int (*same_fn)(const DLine*,const DLine*); /* comparison function */ }; /* ** Return an array of DLine objects containing a pointer to the ** start of each line and a hash of that line. The lower @@ -131,11 +131,16 @@ ** too long. ** ** Profiling show that in most cases this routine consumes the bulk of ** the CPU time on a diff. */ -static DLine *break_into_lines(const char *z, int n, int *pnLine, u64 diffFlags){ +static DLine *break_into_lines( + const char *z, + int n, + int *pnLine, + u64 diffFlags +){ int nLine, i, j, k, s, x; unsigned int h, h2; DLine *a; /* Count the number of lines. Allocate space to hold @@ -2090,11 +2095,16 @@ /* ** The input pParent is the next most recent ancestor of the file ** being annotated. Do another step of the annotation. Return true ** if additional annotation is required. */ -static int annotation_step(Annotator *p, Blob *pParent, int iVers, u64 diffFlags){ +static int annotation_step( + Annotator *p, + Blob *pParent, + int iVers, + u64 diffFlags +){ int i, j; int lnTo; /* Prepare the parent file to be diffed */ p->c.aFrom = break_into_lines(blob_str(pParent), blob_size(pParent), @@ -2134,12 +2144,12 @@ return 0; } /* Annotation flags (any DIFF flag can be used as Annotation flag as well) */ -#define ANN_FILE_VERS (((u64)0x20)<<32) /* Show file vers rather than commit vers */ -#define ANN_FILE_ANCEST (((u64)0x40)<<32) /* Prefer check-ins in the ANCESTOR table */ +#define ANN_FILE_VERS (((u64)0x20)<<32) /* File vers not commit vers */ +#define ANN_FILE_ANCEST (((u64)0x40)<<32) /* Prefer checkins in the ANCESTOR */ /* ** Compute a complete annotation on a file. The file is identified ** by its filename number (filename.fnid) and check-in (mlink.mid). */ @@ -2443,15 +2453,16 @@ ** the file was last modified. The "annotate" command shows line numbers ** and omits the username. The "blame" and "praise" commands show the user ** who made each check-in and omits the line number. ** ** Options: -** --filevers Show file version numbers rather than check-in versions -** -l|--log List all versions analyzed -** -n|--limit N Only look backwards in time by N versions -** -w|--ignore-all-space Ignore white space when comparing lines -** -Z|--ignore-trailing-space Ignore whitespace at line end +** --filevers Show file version numbers rather than +** check-in versions +** -l|--log List all versions analyzed +** -n|--limit N Only look backwards in time by N versions +** -w|--ignore-all-space Ignore white space when comparing lines +** -Z|--ignore-trailing-space Ignore whitespace at line end ** ** See also: info, finfo, timeline */ void annotate_cmd(void){ int fnid; /* Filename ID */ Index: src/diff.tcl ================================================================== --- src/diff.tcl +++ src/diff.tcl @@ -227,16 +227,26 @@ } wm withdraw . wm title . $CFG(TITLE) wm iconname . $CFG(TITLE) -bind . exit +# Keystroke bindings for on the top-level window for navigation and +# control also fire when those same keystrokes are pressed in the +# Search entry box. Disable them, to prevent the diff screen from +# disappearing abruptly and unexpectedly when searching for "q". +# +# bind . exit +# bind .

{catch searchPrev; break} +# bind . {catch searchNext; break} +# bind . exit bind . {after 0 exit} bind . {cycleDiffs; break} bind . <> {cycleDiffs 1; break} +bind . {searchOnOff; break} +bind . {catch searchNext; break} bind . { - event generate .bb.files <1> + event generate bb.files <1> event generate .bb.files break } foreach {key axis args} { Up y {scroll -5 units} @@ -259,10 +269,14 @@ bind . continue } frame .bb ::ttk::menubutton .bb.files -text "Files" +if {[tk windowingsystem] eq "win32"} { + ::ttk::style theme use winnative + .bb.files configure -padding {20 1 10 2} +} toplevel .wfiles wm withdraw .wfiles update idletasks wm transient .wfiles . wm overrideredirect .wfiles 1 @@ -358,31 +372,100 @@ grid config .txtB -column 1 .txtB tag config add -background $CFG(RM_BG) grid config .lnA -column 3 grid config .txtA -column 4 .txtA tag config rm -background $CFG(ADD_BG) + .bb.invert config -text Uninvert } else { grid config .lnA -column 0 grid config .txtA -column 1 .txtA tag config rm -background $CFG(RM_BG) grid config .lnB -column 3 grid config .txtB -column 4 .txtB tag config add -background $CFG(ADD_BG) + .bb.invert config -text Invert } .mkr config -state normal set clt [.mkr search -all < 1.0 end] set cgt [.mkr search -all > 1.0 end] foreach c $clt {.mkr replace $c "$c +1 chars" >} foreach c $cgt {.mkr replace $c "$c +1 chars" <} .mkr config -state disabled +} +proc searchOnOff {} { + if {[info exists ::search]} { + unset ::search + .txtA tag remove search 1.0 end + .txtB tag remove search 1.0 end + pack forget .bb.sframe + } else { + set ::search .txtA + if {![winfo exists .bb.sframe]} { + frame .bb.sframe + ::ttk::entry .bb.sframe.e -width 10 + pack .bb.sframe.e -side left -fill y -expand 1 + bind .bb.sframe.e {searchNext; break} + ::ttk::button .bb.sframe.nx -text \u2193 -width 1 -command searchNext + ::ttk::button .bb.sframe.pv -text \u2191 -width 1 -command searchPrev + tk_optionMenu .bb.sframe.typ ::search_type \ + Exact {No Case} {RegExp} {Whole Word} + .bb.sframe.typ config -width 10 + set ::search_type Exact + pack .bb.sframe.nx .bb.sframe.pv .bb.sframe.typ -side left + } + pack .bb.sframe -side left + after idle {focus .bb.sframe.e} + } +} +proc searchNext {} {searchStep -forwards +1 1.0 end} +proc searchPrev {} {searchStep -backwards -1 end 1.0} +proc searchStep {direction incr start stop} { + set pattern [.bb.sframe.e get] + if {$pattern==""} return + set count 0 + set w $::search + if {"$w"==".txtA"} {set other .txtB} {set other .txtA} + if {[lsearch [$w mark names] search]<0} { + $w mark set search $start + } + switch $::search_type { + Exact {set st -exact} + {No Case} {set st -nocase} + {RegExp} {set st -regexp} + {Whole Word} {set st -regexp; set pattern \\y$pattern\\y} + } + set idx [$w search -count count $direction $st -- \ + $pattern "search $incr chars" $stop] + if {"$idx"==""} { + set idx [$other search -count count $direction $st -- $pattern $start $stop] + if {"$idx"!=""} { + set this $w + set w $other + set other $this + } else { + set idx [$w search -count count $direction $st -- $pattern $start $stop] + } + } + $w tag remove search 1.0 end + $w mark unset search + $other tag remove search 1.0 end + $other mark unset search + if {"$idx"!=""} { + $w mark set search $idx + $w yview -pickplace $idx + $w tag add search search "$idx +$count chars" + $w tag config search -background {#fcc000} + } + set ::search $w } ::ttk::button .bb.quit -text {Quit} -command exit ::ttk::button .bb.invert -text {Invert} -command invertDiff ::ttk::button .bb.save -text {Save As...} -command saveDiff +::ttk::button .bb.search -text {Search} -command searchOnOff pack .bb.quit .bb.invert -side left if {$fossilcmd!=""} {pack .bb.save -side left} -pack .bb.files -side left +pack .bb.files .bb.search -side left grid rowconfigure . 1 -weight 1 grid columnconfigure . 1 -weight 1 grid columnconfigure . 4 -weight 1 grid .bb -row 0 -columnspan 6 eval grid [cols] -row 1 -sticky nsew Index: src/doc.c ================================================================== --- src/doc.c +++ src/doc.c @@ -506,11 +506,11 @@ static void convert_href_and_output(Blob *pIn){ int i, base; int n = blob_size(pIn); char *z = blob_buffer(pIn); for(base=0, i=7; i=9 && (fossil_strnicmp(&z[i-7]," href=", 6)==0 || fossil_strnicmp(&z[i-9]," action=", 8)==0) @@ -522,12 +522,13 @@ } blob_append(cgi_output_blob(), &z[base], i-base); } /* +** WEBPAGE: uv ** WEBPAGE: doc -** URL: /doc?name=CHECKIN/FILE +** URL: /uv/FILE ** URL: /doc/CHECKIN/FILE ** ** CHECKIN can be either tag or SHA1 hash or timestamp identifying a ** particular check, or the name of a branch (meaning the most recent ** check-in on that branch) or one of various magic words: @@ -578,10 +579,12 @@ int rid = 0; /* Artifact of file */ int i; /* Loop counter */ Blob filebody; /* Content of the documentation file */ Blob title; /* Document title */ int nMiss = (-1); /* Failed attempts to find the document */ + int isUV = g.zPath[0]=='u'; /* True for /uv. False for /doc */ + const char *zDfltTitle; static const char *const azSuffix[] = { "index.html", "index.wiki", "index.md" #ifdef FOSSIL_ENABLE_TH1_DOCS , "index.th1" #endif @@ -588,29 +591,39 @@ }; login_check_credentials(); if( !g.perm.Read ){ login_needed(g.anon.Read); return; } blob_init(&title, 0, 0); + zDfltTitle = isUV ? "" : "Documentation"; db_begin_transaction(); while( rid==0 && (++nMiss)<=ArraySize(azSuffix) ){ zName = P("name"); - if( zName==0 || zName[0]==0 ) zName = "tip/index.wiki"; - for(i=0; zName[i] && zName[i]!='/'; i++){} - zCheckin = mprintf("%.*s", i, zName); - if( fossil_strcmp(zCheckin,"ckout")==0 && g.localOpen==0 ){ - zCheckin = "tip"; + if( isUV ){ + if( zName==0 ) zName = "index.wiki"; + i = 0; + }else{ + if( zName==0 || zName[0]==0 ) zName = "tip/index.wiki"; + for(i=0; zName[i] && zName[i]!='/'; i++){} + zCheckin = mprintf("%.*s", i, zName); + if( fossil_strcmp(zCheckin,"ckout")==0 && g.localOpen==0 ){ + zCheckin = "tip"; + } } if( nMiss==ArraySize(azSuffix) ){ zName = "404.md"; }else if( zName[i]==0 ){ assert( nMiss>=0 && nMiss=0 && nMiss0 ){ style_header("%s", blob_str(&title)); }else{ style_header("%s", nMiss>=ArraySize(azSuffix)? - "Not Found" : "Documentation"); + "Not Found" : zDfltTitle); } convert_href_and_output(&tail); style_footer(); }else if( fossil_strcmp(zMime, "text/plain")==0 ){ - style_header("Documentation"); + style_header("%s", zDfltTitle); @

     @ %h(blob_str(&filebody))
     @ 
style_footer(); }else if( fossil_strcmp(zMime, "text/html")==0 @@ -686,13 +706,18 @@ convert_href_and_output(&filebody); style_footer(); #ifdef FOSSIL_ENABLE_TH1_DOCS }else if( Th_AreDocsEnabled() && fossil_strcmp(zMime, "application/x-th1")==0 ){ - style_header("%h", zName); + int raw = P("raw")!=0; + if( !raw ){ + style_header("%h", zName); + } Th_Render(blob_str(&filebody)); - style_footer(); + if( !raw ){ + style_footer(); + } #endif }else{ cgi_set_content_type(zMime); cgi_set_content(&filebody); } @@ -701,10 +726,14 @@ return; /* Jump here when unable to locate the document */ doc_not_found: db_end_transaction(0); + if( isUV && P("name")==0 ){ + uvstat_page(); + return; + } cgi_set_status(404, "Not Found"); style_header("Not Found"); @

Document %h(zOrigName) not found if( fossil_strcmp(zCheckin,"ckout")!=0 ){ @ in %z(href("%R/tree?ci=%T",zCheckin))%h(zCheckin) Index: src/encode.c ================================================================== --- src/encode.c +++ src/encode.c @@ -367,11 +367,11 @@ return z64; } /* ** COMMAND: test-encode64 -** +** ** Usage: %fossil test-encode64 STRING */ void test_encode64_cmd(void){ char *z; int i; @@ -433,11 +433,11 @@ return zData; } /* ** COMMAND: test-decode64 -** +** ** Usage: %fossil test-decode64 STRING */ void test_decode64_cmd(void){ char *z; int i, n; Index: src/event.c ================================================================== --- src/event.c +++ src/event.c @@ -59,11 +59,11 @@ ** complete. ** aid=ARTIFACTID Which specific version of the tech-note. Optional. ** v=BOOLEAN Show details if TRUE. Default is FALSE. Optional. ** ** Display an existing tech-note identified by its ID, optionally at a -** specific version, and optionally with additional details. +** specific version, and optionally with additional details. */ void event_page(void){ int rid = 0; /* rid of the event artifact */ char *zUuid; /* UUID corresponding to rid */ const char *zId; /* Event identifier */ @@ -155,11 +155,11 @@ style_header("%s", blob_str(&title)); if( g.perm.WrWiki && g.perm.Write && nextRid==0 ){ style_submenu_element("Edit", 0, "%R/technoteedit?name=%!S", zId); if( g.perm.Attach ){ style_submenu_element("Attach", "Add an attachment", - "%R/attachadd?technote=%!S&from=%R/technote/%!S", + "%R/attachadd?technote=%!S&from=%R/technote/%!S", zId, zId); } } zETime = db_text(0, "SELECT datetime(%.17g)", pTNote->rEventDate); style_submenu_element("Context", 0, "%R/timeline?c=%.20s", zId); @@ -235,11 +235,11 @@ manifest_destroy(pTNote); } /* ** Add or update a new tech note to the repository. rid is id of -** the prior version of this technote, if any. +** the prior version of this technote, if any. ** ** returns 1 if the tech note was added or updated, 0 if the ** update failed making an invalid artifact */ int event_commit_common( @@ -266,11 +266,11 @@ blob_appendf(&event, "C %#F\n", n, zComment); } zDate = date_in_standard_format("now"); blob_appendf(&event, "D %s\n", zDate); free(zDate); - + zETime[10] = 'T'; blob_appendf(&event, "E %s %s\n", zETime, zId); zETime[10] = ' '; if( rid ){ char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); Index: src/file.c ================================================================== --- src/file.c +++ src/file.c @@ -521,11 +521,11 @@ char *zDate; i64 iMTime; if( g.argc!=4 ){ usage("FILENAME DATE/TIME"); } - db_open_or_attach(":memory:", "mem", 0); + db_open_or_attach(":memory:", "mem"); iMTime = db_int64(0, "SELECT strftime('%%s',%Q)", g.argv[3]); zFile = g.argv[2]; file_set_mtime(zFile, iMTime); iMTime = file_wd_mtime(zFile); zDate = db_text(0, "SELECT datetime(%lld, 'unixepoch')", iMTime); @@ -923,11 +923,11 @@ blob_size(pOut), slash)); } /* ** COMMAND: test-canonical-name -** +** ** Usage: %fossil test-canonical-name FILENAME... ** ** Test the operation of the canonical name generator. ** Also test Fossil's ability to measure attributes of a file. */ Index: src/finfo.c ================================================================== --- src/finfo.c +++ src/finfo.c @@ -282,17 +282,22 @@ ** ** Show the change history for a single file. ** ** Additional query parameters: ** -** a=DATE Only show changes after DATE -** b=DATE Only show changes before DATE +** a=DATETIME Only show changes after DATETIME +** b=DATETIME Only show changes before DATETIME ** n=NUM Show the first NUM changes only ** brbg Background color by branch name ** ubg Background color by user name ** ci=UUID Ancestors of a particular check-in ** showid Show RID values for debugging +** +** DATETIME may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in +** year-month-day form, it may be truncated, and it may also name a +** timezone offset from UTC as "-HH:MM" (westward) or "+HH:MM" +** (eastward). Either no timezone suffix or "Z" means UTC. */ void finfo_page(void){ Stmt q; const char *zFilename; char zPrevDate[20]; @@ -406,11 +411,11 @@ if( fShowId ) blob_appendf(&title, " (%d)", fnid); blob_appendf(&title, " from check-in %z%S", zLink, zUuid); if( fShowId ) blob_appendf(&title, " (%d)", baseCheckin); fossil_free(zUuid); }else{ - blob_appendf(&title, "History of files named "); + blob_appendf(&title, "History of "); hyperlinked_path(zFilename, &title, 0, "tree", ""); if( fShowId ) blob_appendf(&title, " (%d)", fnid); } @

%b(&title)

blob_reset(&title); Index: src/foci.c ================================================================== --- src/foci.c +++ src/foci.c @@ -34,11 +34,11 @@ ** previousName TEXT, -- Name of the file in previous check-in ** perm TEXT, -- Permissions on the file ** symname TEXT HIDDEN -- Symbolic name of the check-in. ** ); ** -** The hidden symname column is (optionally) used as a query parameter to +** The hidden symname column is (optionally) used as a query parameter to ** identify the particular check-in to parse. The checkinID parameter ** (such is a unique numeric RID rather than symbolic name) can also be used ** to identify the check-in. Example: ** ** SELECT * FROM files_of_checkin ADDED src/fshell.c Index: src/fshell.c ================================================================== --- /dev/null +++ src/fshell.c @@ -0,0 +1,118 @@ +/* +** Copyright (c) 2016 D. Richard Hipp +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the Simplified BSD License (also +** known as the "2-Clause License" or "FreeBSD License".) + +** This program is distributed in the hope that it will be useful, +** but without any warranty; without even the implied warranty of +** merchantability or fitness for a particular purpose. +** +** Author contact information: +** drh@hwaci.com +** http://www.hwaci.com/drh/ +** +******************************************************************************* +** +** This module contains the code that implements the "fossil shell" command. +** +** The fossil shell prompts for lines of user input, then parses each line +** after the fashion of a standard Bourne shell and forks a child process +** to run the corresponding Fossil command. This only works on Unix. +** +** The "fossil shell" command is intended for use with SEE-enabled fossil. +** It allows multiple commands to be issued without having to reenter the +** crypto phasephrase for each command. +*/ +#include "config.h" +#include "fshell.h" +#include + +#ifndef _WIN32 +#include +#include +#endif + + +/* +** COMMAND: shell* +** +** Usage: %fossil shell +** +** Prompt for lines of input from stdin. Parse each line and evaluate +** it as a separate fossil command, in a child process. The initial +** "fossil" is omitted from each line. +** +** This command only works on unix-like platforms that support fork(). +** It is non-functional on Windows. +*/ +void shell_cmd(void){ +#ifdef _WIN32 + fossil_fatal("the 'shell' command is not supported on windows"); +#else + int nArg; + int mxArg = 0; + int n, i; + char **azArg = 0; + int fDebug; + pid_t childPid; + char zLine[10000]; + fDebug = find_option("debug", 0, 0)!=0; + db_find_and_open_repository(OPEN_ANY_SCHEMA|OPEN_OK_NOT_FOUND, 0); + db_close(0); + sqlite3_shutdown(); + while( printf("fossil> "),fflush(stdout),fgets(zLine, sizeof(zLine), stdin) ){ + /* Parse the line of input */ + n = (int)strlen(zLine); + for(i=0, nArg=1; i=n ) break; + if( nArg>=mxArg ){ + mxArg = nArg+10; + azArg = fossil_realloc(azArg, sizeof(char*)*mxArg); + if( nArg==1 ) azArg[0] = g.argv[0]; + } + if( zLine[i]=='"' || zLine[i]=='\'' ){ + char cQuote = zLine[i]; + i++; + azArg[nArg++] = &zLine[i]; + for(i++; ipLast; pRow; pRow=pRow->pPrev){ int parentRid; if( pRow->iRail>=0 ){ if( pRow->pChild==0 && !pRow->timeWarp ){ - if( omitDescenders || pRow->isLeaf ){ - /* no-op */ - }else{ + if( !omitDescenders && count_nonbranch_children(pRow->rid)!=0 ){ riser_to_top(pRow); } } continue; } @@ -519,11 +517,11 @@ } mask = BIT(pRow->iRail); pRow->railInUse |= mask; if( pRow->pChild ){ assignChildrenToRail(pRow); - }else if( !pRow->isLeaf && !omitDescenders ){ + }else if( !omitDescenders && count_nonbranch_children(pRow->rid)!=0 ){ riser_to_top(pRow); } if( pParent ){ for(pLoop=pParent->pPrev; pLoop && pLoop!=pRow; pLoop=pLoop->pPrev){ pLoop->railInUse |= mask; Index: src/http_ssl.c ================================================================== --- src/http_ssl.c +++ src/http_ssl.c @@ -294,11 +294,11 @@ SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); if( !pUrlData->useProxy ){ BIO_set_conn_hostname(iBio, pUrlData->name); - BIO_set_conn_int_port(iBio, &pUrlData->port); + BIO_ctrl(iBio,BIO_C_SET_CONNECT,3,(char *)&pUrlData->port); if( BIO_do_connect(iBio)<=0 ){ ssl_set_errmsg("SSL: cannot connect to host %s:%d (%s)", pUrlData->name, pUrlData->port, ERR_reason_error_string(ERR_get_error())); ssl_close(); return 1; @@ -389,11 +389,11 @@ ** This is used to populate the ipaddr column of the rcvfrom table, ** if any files are received from the server. */ { /* IPv4 only code */ - const unsigned char *ip = (const unsigned char *) BIO_get_conn_ip(iBio); + const unsigned char *ip = (const unsigned char *) BIO_ptr_ctrl(iBio,BIO_C_GET_CONNECT,2); g.zIpAddr = mprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); } X509_free(cert); return 0; Index: src/info.c ================================================================== --- src/info.c +++ src/info.c @@ -154,10 +154,21 @@ db_column_text(&s, 1)); } db_finalize(&s); } +/* +** Show the parent project, if any +*/ +static void showParentProject(void){ + const char *zParentCode; + zParentCode = db_get("parent-project-code",0); + if( zParentCode ){ + fossil_print("derived-from: %s %s\n", zParentCode, db_get("parent-project-name","")); + } +} + /* ** COMMAND: info ** ** Usage: %fossil info ?VERSION | REPOSITORY_FILENAME? ?OPTIONS? @@ -189,10 +200,11 @@ db_open_config(0, 0); db_open_repository(g.argv[2]); db_record_repository_filename(g.argv[2]); fossil_print("project-name: %s\n", db_get("project-name", "")); fossil_print("project-code: %s\n", db_get("project-code", "")); + showParentProject(); extraRepoInfo(); return; } db_find_and_open_repository(0,0); verify_all_options(); @@ -208,10 +220,11 @@ if( verboseFlag ) extraRepoInfo(); if( g.zConfigDbName ){ fossil_print("config-db: %s\n", g.zConfigDbName); } fossil_print("project-code: %s\n", db_get("project-code", "")); + showParentProject(); vid = g.localOpen ? db_lget_int("checkout", 0) : 0; if( vid ){ show_common_info(vid, "checkout:", 1, 1); } fossil_print("check-ins: %d\n", @@ -2825,18 +2838,24 @@ ** ** --author USER Make USER the author for check-in ** -m|--comment COMMENT Make COMMENT the check-in comment ** -M|--message-file FILE Read the amended comment from FILE ** -e|--edit-comment Launch editor to revise comment -** --date DATE Make DATE the check-in time +** --date DATETIME Make DATETIME the check-in time ** --bgcolor COLOR Apply COLOR to this check-in ** --branchcolor COLOR Apply and propagate COLOR to the branch ** --tag TAG Add new TAG to this check-in ** --cancel TAG Cancel TAG from this check-in ** --branch NAME Make this check-in the start of branch NAME ** --hide Hide branch starting from this check-in ** --close Mark this "leaf" as closed +** +** DATETIME may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in +** year-month-day form, it may be truncated, the "T" may be replaced by +** a space, and it may also name a timezone offset from UTC as "-HH:MM" +** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z" +** means UTC. */ void ci_amend_cmd(void){ int rid; const char *zComment; /* Current comment on the check-in */ const char *zNewComment; /* Revised check-in comment */ Index: src/json.c ================================================================== --- src/json.c +++ src/json.c @@ -1259,11 +1259,10 @@ #define CSTR(OBJ,K) cson_object_set(o, #K, OBJ.K ? json_new_string(OBJ.K) : cson_value_null()) #define VAL(K,V) cson_object_set(o, #K, (V) ? (V) : cson_value_null()) VAL(capabilities, json_cap_value()); INT(g, argc); INT(g, isConst); - INT(g, useAttach); CSTR(g, zConfigDbName); INT(g, repositoryOpen); INT(g, localOpen); INT(g, minPrefix); INT(g, fSqlTrace); @@ -1296,12 +1295,10 @@ INT(g, thTrace); INT(g, isHome); INT(g, nAux); INT(g, allowSymlinks); - CSTR(g, zMainDbType); - CSTR(g, zConfigDbType); CSTR(g, zOpenRevision); CSTR(g, zLocalRoot); CSTR(g, zPath); CSTR(g, zExtra); CSTR(g, zBaseURL); @@ -1905,11 +1902,10 @@ */ cson_value * json_page_stat(){ i64 t, fsize; int n, m; int full; - const char *zDb; enum { BufLen = 1000 }; char zBuf[BufLen]; cson_value * jv = NULL; cson_object * jo = NULL; cson_value * jv2 = NULL; @@ -1989,17 +1985,16 @@ jo2 = cson_value_get_object(jv2); cson_object_set(jo, "sqlite", jv2); sqlite3_snprintf(BufLen, zBuf, "%.19s [%.10s] (%s)", sqlite3_sourceid(), &sqlite3_sourceid()[20], sqlite3_libversion()); SETBUF(jo2, "version"); - zDb = db_name("repository"); - cson_object_set(jo2, "pageCount", cson_value_new_integer((cson_int_t)db_int(0, "PRAGMA \"%w\".page_count", zDb))); - cson_object_set(jo2, "pageSize", cson_value_new_integer((cson_int_t)db_int(0, "PRAGMA \"%w\".page_size", zDb))); - cson_object_set(jo2, "freeList", cson_value_new_integer((cson_int_t)db_int(0, "PRAGMA \"%w\".freelist_count", zDb))); - sqlite3_snprintf(BufLen, zBuf, "%s", db_text(0, "PRAGMA \"%w\".encoding", zDb)); + cson_object_set(jo2, "pageCount", cson_value_new_integer((cson_int_t)db_int(0, "PRAGMA repository.page_count"))); + cson_object_set(jo2, "pageSize", cson_value_new_integer((cson_int_t)db_int(0, "PRAGMA repository.page_size"))); + cson_object_set(jo2, "freeList", cson_value_new_integer((cson_int_t)db_int(0, "PRAGMA repository.freelist_count"))); + sqlite3_snprintf(BufLen, zBuf, "%s", db_text(0, "PRAGMA repository.encoding")); SETBUF(jo2, "encoding"); - sqlite3_snprintf(BufLen, zBuf, "%s", db_text(0, "PRAGMA \"%w\".journal_mode", zDb)); + sqlite3_snprintf(BufLen, zBuf, "%s", db_text(0, "PRAGMA repository.journal_mode")); cson_object_set(jo2, "journalMode", *zBuf ? cson_value_new_string(zBuf, strlen(zBuf)) : cson_value_null()); return jv; #undef SETBUF } Index: src/loadctrl.c ================================================================== --- src/loadctrl.c +++ src/loadctrl.c @@ -35,11 +35,11 @@ return 0.0; } /* ** COMMAND: test-loadavg -** +** ** %fossil test-loadavg ** ** Print the load average on the host machine. */ void loadavg_test_cmd(void){ Index: src/login.c ================================================================== --- src/login.c +++ src/login.c @@ -174,16 +174,16 @@ /* ** Make sure the accesslog table exists. Create it if it does not */ void create_accesslog_table(void){ db_multi_exec( - "CREATE TABLE IF NOT EXISTS %s.accesslog(" + "CREATE TABLE IF NOT EXISTS repository.accesslog(" " uname TEXT," " ipaddr TEXT," " success BOOLEAN," " mtime TIMESTAMP" - ");", db_name("repository") + ");" ); } /* ** Make a record of a login attempt, if login record keeping is enabled. @@ -1005,17 +1005,18 @@ g.isHuman = 1; } /* Set the capabilities */ login_replace_capabilities(zCap, 0); - login_set_anon_nobody_capabilities(); /* The auto-hyperlink setting allows hyperlinks to be displayed for users ** who do not have the "h" permission as long as their UserAgent string ** makes it appear that they are human. Check to see if auto-hyperlink is ** enabled for this repository and make appropriate adjustments to the - ** permission flags if it is. + ** permission flags if it is. This should be done before the permissions + ** are (potentially) copied to the anonymous permission set; otherwise, + ** those will be out-of-sync. */ if( zCap[0] && !g.perm.Hyperlink && g.isHuman && db_get_boolean("auto-hyperlink",1) @@ -1022,10 +1023,20 @@ ){ g.perm.Hyperlink = 1; g.javascriptHyperlink = 1; } + /* + ** At this point, the capabilities for the logged in user are not going + ** to be modified anymore; therefore, we can copy them over to the ones + ** for the anonymous user. + ** + ** WARNING: In the future, please do not add code after this point that + ** modifies the capabilities for the logged in user. + */ + login_set_anon_nobody_capabilities(); + /* If the public-pages glob pattern is defined and REQUEST_URI matches ** one of the globs in public-pages, then also add in all default-perms ** permissions. */ zPublicPages = db_get("public-pages",0); @@ -1095,11 +1106,11 @@ p->RdWiki = p->WrWiki = p->NewWiki = p->ApndWiki = p->Hyperlink = p->Clone = p->NewTkt = p->Password = p->RdAddr = p->TktFmt = p->Attach = p->ApndTkt = p->ModWiki = p->ModTkt = p->Delete = - p->Private = 1; + p->WrUnver = p->Private = 1; /* Fall thru into Read/Write */ case 'i': p->Read = p->Write = 1; break; case 'o': p->Read = 1; break; case 'z': p->Zip = 1; break; @@ -1122,10 +1133,11 @@ case 'c': p->ApndTkt = 1; break; case 'q': p->ModTkt = 1; break; case 't': p->TktFmt = 1; break; case 'b': p->Attach = 1; break; case 'x': p->Private = 1; break; + case 'y': p->WrUnver = 1; break; /* The "u" privileges is a little different. It recursively ** inherits all privileges of the user named "reader" */ case 'u': { if( (flags & LOGIN_IGNORE_UV)==0 ){ @@ -1193,11 +1205,11 @@ case 't': rc = p->TktFmt; break; /* case 'u': READER */ /* case 'v': DEVELOPER */ case 'w': rc = p->WrTkt; break; case 'x': rc = p->Private; break; - /* case 'y': */ + case 'y': rc = p->WrUnver; break; case 'z': rc = p->Zip; break; default: rc = 0; break; } } return rc; @@ -1554,11 +1566,11 @@ char *zSelfProjCode; /* Our project-code */ char *zSql; /* SQL to run on all peers */ const char *zSelf; /* The ATTACH name of our repository */ *pzErrMsg = 0; /* Default to no errors */ - zSelf = db_name("repository"); + zSelf = "repository"; /* Get the full pathname of the other repository */ file_canonical_name(zRepo, &fullName, 0); zRepo = fossil_strdup(blob_str(&fullName)); blob_reset(&fullName); Index: src/main.c ================================================================== --- src/main.c +++ src/main.c @@ -91,10 +91,11 @@ char Attach; /* b: add attachments */ char TktFmt; /* t: create new ticket report formats */ char RdAddr; /* e: read email addresses or other private data */ char Zip; /* z: download zipped artifact via /zip URL */ char Private; /* x: can send and receive private content */ + char WrUnver; /* y: can push unversioned content */ }; #ifdef FOSSIL_ENABLE_TCL /* ** All Tcl related context information is in this structure. This structure @@ -127,19 +128,17 @@ int isConst; /* True if the output is unchanging & cacheable */ const char *zVfsName; /* The VFS to use for database connections */ sqlite3 *db; /* The connection to the databases */ sqlite3 *dbConfig; /* Separate connection for global_config table */ char *zAuxSchema; /* Main repository aux-schema */ - int useAttach; /* True if global_config is attached to repository */ + int dbIgnoreErrors; /* Ignore database errors if true */ const char *zConfigDbName;/* Path of the config database. NULL if not open */ sqlite3_int64 now; /* Seconds since 1970 */ int repositoryOpen; /* True if the main repository database is open */ char *zRepositoryOption; /* Most recent cached repository option value */ - char *zRepositoryName; /* Name of the repository database */ - char *zLocalDbName; /* Name of the local database */ - const char *zMainDbType;/* "configdb", "localdb", or "repository" */ - const char *zConfigDbType; /* "configdb", "localdb", or "repository" */ + char *zRepositoryName; /* Name of the repository database file */ + char *zLocalDbName; /* Name of the local database file */ char *zOpenRevision; /* Check-in version to use during database open */ int localOpen; /* True if the local database is open */ char *zLocalRoot; /* The directory holding the local database */ int minPrefix; /* Number of digits needed for a distinct UUID */ int fSqlTrace; /* True if --sqltrace flag is present */ @@ -558,10 +557,11 @@ /* Disable the file alias warning on apple products because Time Machine ** creates lots of aliases and the warning alarms people. */ if( iCode==SQLITE_WARNING ) return; #endif if( iCode==SQLITE_SCHEMA ) return; + if( g.dbIgnoreErrors ) return; fossil_warning("%s: %s", fossil_sqlite_return_code_name(iCode), zErrmsg); } /* ** This function attempts to find command line options known to contain @@ -592,12 +592,12 @@ #endif { const char *zCmdName = "unknown"; int idx; int rc; - if( sqlite3_libversion_number()<3010000 ){ - fossil_fatal("Unsuitable SQLite version %s, must be at least 3.10.0", + if( sqlite3_libversion_number()<3014000 ){ + fossil_fatal("Unsuitable SQLite version %s, must be at least 3.14.0", sqlite3_libversion()); } sqlite3_config(SQLITE_CONFIG_MULTITHREAD); sqlite3_config(SQLITE_CONFIG_LOG, fossil_sqlite_log, 0); memset(&g, 0, sizeof(g)); @@ -1228,11 +1228,11 @@ putchar('\n'); } /* ** COMMAND: test-all-help -** +** ** Usage: %fossil test-all-help ?OPTIONS? ** ** Show help text for commands and pages. Useful for proof-reading. ** Defaults to just the CLI commands. Specify --www to see only the ** web pages, or --everything to see both commands and pages. @@ -2023,24 +2023,75 @@ } /* ** COMMAND: cgi* ** -** Usage: %fossil ?cgi? SCRIPT +** Usage: %fossil ?cgi? FILE +** +** This command causes Fossil to generate reply to a CGI request. ** -** The SCRIPT argument is the name of a file that is the CGI script -** that is being run. The command name, "cgi", may be omitted if -** the GATEWAY_INTERFACE environment variable is set to "CGI" (which -** should always be the case for CGI scripts run by a webserver.) The -** SCRIPT file should look something like this: +** The FILE argument is the name of a control file that provides Fossil +** with important information such as where to find its repository. In +** a typical CGI deployment, FILE is the name of the CGI script and will +** typically look something like this: ** ** #!/usr/bin/fossil ** repository: /home/somebody/project.db ** -** The second line defines the name of the repository. After locating -** the repository, fossil will generate a webpage on stdout based on -** the values of standard CGI environment variables. +** The command name, "cgi", may be omitted if the GATEWAY_INTERFACE +** environment variable is set to "CGI", which should always be the +** case for CGI scripts run by a webserver. Fossil ignores any lines +** that begin with "#". +** +** The following control lines are recognized: +** +** repository: PATH Name of the Fossil repository +** +** directory: PATH Name of a directory containing many Fossil +** repositories whose names all end with ".fossil". +** There should only be one of "repository:" +** or "directory:" +** +** notfound: URL When in "directory:" mode, redirect to +** URL if no suitable repository is found. +** +** repolist When in "directory:" mode, display a page +** showing a list of available repositories if +** the URL is "/". +** +** localauth Grant administrator privileges to connections +** from 127.0.0.1 or ::1. +** +** skin: LABEL Use the built-in skin called LABEL rather than +** the default. If there are no skins called LABEL +** then this line is a no-op. +** +** files: GLOBLIST GLOBLIST is a comma-separated list of GLOB +** patterns that specify files that can be +** returned verbatim. This feature allows Fossil +** to act as a web server returning static +** content. +** +** setenv: NAME VALUE Set environment variable NAME to VALUE. Or +** if VALUE is omitted, unset NAME. +** +** HOME: PATH Shorthand for "setenv: HOME PATH" +** +** debug: FILE Causing debugging information to be written +** into FILE. +** +** errorlog: FILE Warnings, errors, and panics written to FILE. +** +** redirect: REPO URL Extract the "name" query parameter and search +** REPO for a check-in or ticket that matches the +** value of "name", then redirect to URL. There +** can be multiple "redirect:" lines that are +** processed in order. If the REPO is "*", then +** an unconditional redirect to URL is taken. +** +** Most CGI files contain only a "repository:" line. It is uncommon to +** use any other option. ** ** See also: http, server, winsrv */ void cmd_cgi(void){ const char *zFile; @@ -2309,10 +2360,11 @@ ** --nossl signal that no SSL connections are available ** --notfound URL use URL as "HTTP 404, object not found" page. ** --repolist If REPOSITORY is directory, URL "/" lists all repos ** --scgi Interpret input as SCGI rather than HTTP ** --skin LABEL Use override skin LABEL +** --th-trace trace TH1 execution (for debugging purposes) ** ** See also: cgi, server, winsrv */ void cmd_http(void){ const char *zIpAddr = 0; @@ -2321,10 +2373,12 @@ const char *zAltBase; const char *zFileGlob; int useSCGI; int noJail; int allowRepoList; + + Th_InitTraceLog(); /* The winhttp module passes the --files option as --files-urlenc with ** the argument being URL encoded, to avoid wildcard expansion in the ** shell. This option is for internal use and is undocumented. */ Index: src/main.mk ================================================================== --- src/main.mk +++ src/main.mk @@ -45,10 +45,11 @@ $(SRCDIR)/event.c \ $(SRCDIR)/export.c \ $(SRCDIR)/file.c \ $(SRCDIR)/finfo.c \ $(SRCDIR)/foci.c \ + $(SRCDIR)/fshell.c \ $(SRCDIR)/fusefs.c \ $(SRCDIR)/glob.c \ $(SRCDIR)/graph.c \ $(SRCDIR)/gzip.c \ $(SRCDIR)/http.c \ @@ -116,10 +117,11 @@ $(SRCDIR)/timeline.c \ $(SRCDIR)/tkt.c \ $(SRCDIR)/tktsetup.c \ $(SRCDIR)/undo.c \ $(SRCDIR)/unicode.c \ + $(SRCDIR)/unversioned.c \ $(SRCDIR)/update.c \ $(SRCDIR)/url.c \ $(SRCDIR)/user.c \ $(SRCDIR)/utf8.c \ $(SRCDIR)/util.c \ @@ -217,10 +219,11 @@ $(OBJDIR)/event_.c \ $(OBJDIR)/export_.c \ $(OBJDIR)/file_.c \ $(OBJDIR)/finfo_.c \ $(OBJDIR)/foci_.c \ + $(OBJDIR)/fshell_.c \ $(OBJDIR)/fusefs_.c \ $(OBJDIR)/glob_.c \ $(OBJDIR)/graph_.c \ $(OBJDIR)/gzip_.c \ $(OBJDIR)/http_.c \ @@ -288,10 +291,11 @@ $(OBJDIR)/timeline_.c \ $(OBJDIR)/tkt_.c \ $(OBJDIR)/tktsetup_.c \ $(OBJDIR)/undo_.c \ $(OBJDIR)/unicode_.c \ + $(OBJDIR)/unversioned_.c \ $(OBJDIR)/update_.c \ $(OBJDIR)/url_.c \ $(OBJDIR)/user_.c \ $(OBJDIR)/utf8_.c \ $(OBJDIR)/util_.c \ @@ -338,10 +342,11 @@ $(OBJDIR)/event.o \ $(OBJDIR)/export.o \ $(OBJDIR)/file.o \ $(OBJDIR)/finfo.o \ $(OBJDIR)/foci.o \ + $(OBJDIR)/fshell.o \ $(OBJDIR)/fusefs.o \ $(OBJDIR)/glob.o \ $(OBJDIR)/graph.o \ $(OBJDIR)/gzip.o \ $(OBJDIR)/http.o \ @@ -409,10 +414,11 @@ $(OBJDIR)/timeline.o \ $(OBJDIR)/tkt.o \ $(OBJDIR)/tktsetup.o \ $(OBJDIR)/undo.o \ $(OBJDIR)/unicode.o \ + $(OBJDIR)/unversioned.o \ $(OBJDIR)/update.o \ $(OBJDIR)/url.o \ $(OBJDIR)/user.o \ $(OBJDIR)/utf8.o \ $(OBJDIR)/util.o \ @@ -613,10 +619,11 @@ $(OBJDIR)/event_.c:$(OBJDIR)/event.h \ $(OBJDIR)/export_.c:$(OBJDIR)/export.h \ $(OBJDIR)/file_.c:$(OBJDIR)/file.h \ $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h \ $(OBJDIR)/foci_.c:$(OBJDIR)/foci.h \ + $(OBJDIR)/fshell_.c:$(OBJDIR)/fshell.h \ $(OBJDIR)/fusefs_.c:$(OBJDIR)/fusefs.h \ $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h \ $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h \ $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h \ $(OBJDIR)/http_.c:$(OBJDIR)/http.h \ @@ -684,10 +691,11 @@ $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h \ $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h \ $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h \ $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h \ $(OBJDIR)/unicode_.c:$(OBJDIR)/unicode.h \ + $(OBJDIR)/unversioned_.c:$(OBJDIR)/unversioned.h \ $(OBJDIR)/update_.c:$(OBJDIR)/update.h \ $(OBJDIR)/url_.c:$(OBJDIR)/url.h \ $(OBJDIR)/user_.c:$(OBJDIR)/user.h \ $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h \ $(OBJDIR)/util_.c:$(OBJDIR)/util.h \ @@ -969,10 +977,18 @@ $(OBJDIR)/foci.o: $(OBJDIR)/foci_.c $(OBJDIR)/foci.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/foci.o -c $(OBJDIR)/foci_.c $(OBJDIR)/foci.h: $(OBJDIR)/headers + +$(OBJDIR)/fshell_.c: $(SRCDIR)/fshell.c $(OBJDIR)/translate + $(OBJDIR)/translate $(SRCDIR)/fshell.c >$@ + +$(OBJDIR)/fshell.o: $(OBJDIR)/fshell_.c $(OBJDIR)/fshell.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/fshell.o -c $(OBJDIR)/fshell_.c + +$(OBJDIR)/fshell.h: $(OBJDIR)/headers $(OBJDIR)/fusefs_.c: $(SRCDIR)/fusefs.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/fusefs.c >$@ $(OBJDIR)/fusefs.o: $(OBJDIR)/fusefs_.c $(OBJDIR)/fusefs.h $(SRCDIR)/config.h @@ -1537,10 +1553,18 @@ $(OBJDIR)/unicode.o: $(OBJDIR)/unicode_.c $(OBJDIR)/unicode.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/unicode.o -c $(OBJDIR)/unicode_.c $(OBJDIR)/unicode.h: $(OBJDIR)/headers + +$(OBJDIR)/unversioned_.c: $(SRCDIR)/unversioned.c $(OBJDIR)/translate + $(OBJDIR)/translate $(SRCDIR)/unversioned.c >$@ + +$(OBJDIR)/unversioned.o: $(OBJDIR)/unversioned_.c $(OBJDIR)/unversioned.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/unversioned.o -c $(OBJDIR)/unversioned_.c + +$(OBJDIR)/unversioned.h: $(OBJDIR)/headers $(OBJDIR)/update_.c: $(SRCDIR)/update.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/update.c >$@ $(OBJDIR)/update.o: $(OBJDIR)/update_.c $(OBJDIR)/update.h $(SRCDIR)/config.h Index: src/makeheaders.c ================================================================== --- src/makeheaders.c +++ src/makeheaders.c @@ -1106,11 +1106,11 @@ ** ** The number of errors encountered is returned. An error is an ** unterminated token. */ static int GetBigToken(InStream *pIn, Token *pToken, IdentTable *pTable){ - const char *z, *zStart; + const char *zStart; int iStart; int nBrace; int c; int nLine; int nErr; @@ -1135,11 +1135,10 @@ default: return nErr; } - z = pIn->z; iStart = pIn->i; zStart = pToken->zText; nLine = pToken->nLine; nBrace = 1; while( nBrace ){ @@ -1681,18 +1680,16 @@ ** This routine is called when we see a method for a class that begins ** with the PUBLIC, PRIVATE, or PROTECTED keywords. Such methods are ** added to their class definitions. */ static int ProcessMethodDef(Token *pFirst, Token *pLast, int flags){ - Token *pCode; Token *pClass; char *zDecl; Decl *pDecl; String str; int type; - pCode = pLast; pLast = pLast->pPrev; while( pFirst->zText[0]=='P' ){ int rc = 1; switch( pFirst->nText ){ case 6: rc = strncmp(pFirst->zText,"PUBLIC",6); break; Index: src/makemake.tcl ================================================================== --- src/makemake.tcl +++ src/makemake.tcl @@ -52,10 +52,11 @@ event export file finfo foci + fshell fusefs glob graph gzip http @@ -122,10 +123,11 @@ timeline tkt tktsetup undo unicode + unversioned update url user utf8 util @@ -643,13 +645,13 @@ ZLIBCONFIG = ZLIBTARGETS = endif #### Disable creation of the OpenSSL shared libraries. Also, disable support -# for both SSLv2 and SSLv3 (i.e. thereby forcing the use of TLS). +# for SSLv3 (i.e. thereby forcing the use of TLS). # -SSLCONFIG += no-ssl2 no-ssl3 no-shared +SSLCONFIG += no-ssl3 no-shared #### When using zlib, make sure that OpenSSL is configured to use the zlib # that Fossil knows about (i.e. the one within the source tree). # ifndef FOSSIL_ENABLE_MINIZ @@ -659,11 +661,11 @@ #### The directories where the OpenSSL include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "openssl-1.x" sub-directory of the # Fossil source code directory and the target OpenSSL source directory. # -OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2h +OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.1.0 OPENSSLINCDIR = $(OPENSSLDIR)/include OPENSSLLIBDIR = $(OPENSSLDIR) #### Either the directory where the Tcl library is installed or the Tcl # source code directory resides (depending on the value of the macro @@ -853,11 +855,11 @@ endif #### OpenSSL: Add the necessary libraries required, if enabled. # ifdef FOSSIL_ENABLE_SSL -LIB += -lssl -lcrypto -lgdi32 +LIB += -lssl -lcrypto -lgdi32 -lcrypt32 endif #### Tcl: Add the necessary libraries required, if enabled. # ifdef FOSSIL_ENABLE_TCL @@ -1094,21 +1096,21 @@ BLDTARGETS = zlib endif openssl: $(BLDTARGETS) cd $(OPENSSLLIBDIR);./Configure --cross-compile-prefix=$(PREFIX) $(SSLCONFIG) - $(MAKE) -C $(OPENSSLLIBDIR) CC=$(TCCEXE) build_libs + $(MAKE) -C $(OPENSSLLIBDIR) PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) build_libs clean-openssl: - $(MAKE) -C $(OPENSSLLIBDIR) CC=$(TCCEXE) clean + $(MAKE) -C $(OPENSSLLIBDIR) PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) clean tcl: cd $(TCLSRCDIR)/win;./configure - $(MAKE) -C $(TCLSRCDIR)/win CC=$(TCCEXE) $(TCLTARGET) + $(MAKE) -C $(TCLSRCDIR)/win PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) $(TCLTARGET) clean-tcl: - $(MAKE) -C $(TCLSRCDIR)/win CC=$(TCCEXE) distclean + $(MAKE) -C $(TCLSRCDIR)/win PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) distclean APPTARGETS += $(BLDTARGETS) ifdef FOSSIL_BUILD_SSL APPTARGETS += openssl @@ -1489,23 +1491,23 @@ !ifndef USE_SEE USE_SEE = 0 !endif !if $(FOSSIL_ENABLE_SSL)!=0 -SSLDIR = $(B)\compat\openssl-1.0.2h +SSLDIR = $(B)\compat\openssl-1.1.0 SSLINCDIR = $(SSLDIR)\inc32 !if $(FOSSIL_DYNAMIC_BUILD)!=0 SSLLIBDIR = $(SSLDIR)\out32dll !else SSLLIBDIR = $(SSLDIR)\out32 !endif SSLLFLAGS = /nologo /opt:ref /debug -SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib +SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib crypt32.lib !if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64" !message Using 'x64' platform for OpenSSL... # BUGBUG (OpenSSL): Using "no-ssl*" here breaks the build. -# SSLCONFIG = VC-WIN64A no-asm no-ssl2 no-ssl3 +# SSLCONFIG = VC-WIN64A no-asm no-ssl3 SSLCONFIG = VC-WIN64A no-asm !if $(FOSSIL_DYNAMIC_BUILD)!=0 SSLCONFIG = $(SSLCONFIG) shared !else SSLCONFIG = $(SSLCONFIG) no-shared @@ -1516,16 +1518,16 @@ !else SSLNMAKE = ms\nt.mak all !endif # BUGBUG (OpenSSL): Using "OPENSSL_NO_SSL*" here breaks dynamic builds. !if $(FOSSIL_DYNAMIC_BUILD)==0 -SSLCFLAGS = -DOPENSSL_NO_SSL2 -DOPENSSL_NO_SSL3 +SSLCFLAGS = -DOPENSSL_NO_SSL3 !endif !elseif "$(PLATFORM)"=="ia64" !message Using 'ia64' platform for OpenSSL... # BUGBUG (OpenSSL): Using "no-ssl*" here breaks the build. -# SSLCONFIG = VC-WIN64I no-asm no-ssl2 no-ssl3 +# SSLCONFIG = VC-WIN64I no-asm no-ssl3 SSLCONFIG = VC-WIN64I no-asm !if $(FOSSIL_DYNAMIC_BUILD)!=0 SSLCONFIG = $(SSLCONFIG) shared !else SSLCONFIG = $(SSLCONFIG) no-shared @@ -1536,16 +1538,16 @@ !else SSLNMAKE = ms\nt.mak all !endif # BUGBUG (OpenSSL): Using "OPENSSL_NO_SSL*" here breaks dynamic builds. !if $(FOSSIL_DYNAMIC_BUILD)==0 -SSLCFLAGS = -DOPENSSL_NO_SSL2 -DOPENSSL_NO_SSL3 +SSLCFLAGS = -DOPENSSL_NO_SSL3 !endif !else !message Assuming 'x86' platform for OpenSSL... # BUGBUG (OpenSSL): Using "no-ssl*" here breaks the build. -# SSLCONFIG = VC-WIN32 no-asm no-ssl2 no-ssl3 +# SSLCONFIG = VC-WIN32 no-asm no-ssl3 SSLCONFIG = VC-WIN32 no-asm !if $(FOSSIL_DYNAMIC_BUILD)!=0 SSLCONFIG = $(SSLCONFIG) shared !else SSLCONFIG = $(SSLCONFIG) no-shared @@ -1556,11 +1558,11 @@ !else SSLNMAKE = ms\nt.mak all !endif # BUGBUG (OpenSSL): Using "OPENSSL_NO_SSL*" here breaks dynamic builds. !if $(FOSSIL_DYNAMIC_BUILD)==0 -SSLCFLAGS = -DOPENSSL_NO_SSL2 -DOPENSSL_NO_SSL3 +SSLCFLAGS = -DOPENSSL_NO_SSL3 !endif !endif !endif !if $(FOSSIL_ENABLE_TCL)!=0 Index: src/md5.c ================================================================== --- src/md5.c +++ src/md5.c @@ -422,11 +422,11 @@ } /* ** COMMAND: md5sum* -** +** ** Usage: %fossil md5sum FILES.... ** ** Compute an MD5 checksum of all files named on the command-line. ** If a file is named "-" then content is read from standard input. */ Index: src/merge.c ================================================================== --- src/merge.c +++ src/merge.c @@ -395,11 +395,11 @@ } if( zPivot ){ vAncestor = db_exists( "WITH RECURSIVE ancestor(id) AS (" " VALUES(%d)" - " UNION ALL" + " UNION" " SELECT pid FROM plink, ancestor" " WHERE cid=ancestor.id AND pid!=%d AND cid!=%d)" "SELECT 1 FROM ancestor WHERE id=%d LIMIT 1", vid, nid, pid, pid ) ? 'p' : 'n'; Index: src/mkindex.c ================================================================== --- src/mkindex.c +++ src/mkindex.c @@ -70,16 +70,16 @@ } Entry; /* ** Maximum number of entries */ -#define N_ENTRY 500 +#define N_ENTRY 5000 /* ** Maximum size of a help message */ -#define MX_HELP 25000 +#define MX_HELP 250000 /* ** Table of entries */ Entry aEntry[N_ENTRY]; @@ -91,11 +91,11 @@ int nHelp; /* ** Most recently encountered #if */ -char zIf[200]; +char zIf[2000]; /* ** How many entries are used */ int nUsed; @@ -154,11 +154,11 @@ int len; if( zLine[0]!='#' ) return; for(i=1; isspace(zLine[i]); i++){} if( zLine[i]==0 ) return; len = strlen(&zLine[i]); - if( memcmp(&zLine[i],"if",2)==0 ){ + if( strncmp(&zLine[i],"if",2)==0 ){ zIf[0] = '#'; memcpy(&zIf[1], &zLine[i], len+1); }else if( zLine[i]=='e' ){ zIf[0] = 0; } @@ -173,12 +173,12 @@ if( nUsed<=nFixed ) return; if( strncmp(zLine, "**", 2)==0 && isspace(zLine[2]) && strlen(zLine)nFixed - && memcmp(zLine,"** COMMAND:",11)!=0 - && memcmp(zLine,"** WEBPAGE:",11)!=0 + && strncmp(zLine,"** COMMAND:",11)!=0 + && strncmp(zLine,"** WEBPAGE:",11)!=0 ){ if( zLine[2]=='\n' ){ zHelp[nHelp++] = '\n'; }else{ if( strncmp(&zLine[3], "Usage: ", 6)==0 ) nHelp = 0; @@ -287,11 +287,11 @@ int cmdFlags = (1==aEntry[i].eType) ? 0x01 : 0x08; if( 0x01==cmdFlags ){ if( z[n-1]=='*' ){ n--; cmdFlags = 0x02; - }else if( memcmp(z, "test-", 5)==0 ){ + }else if( strncmp(z, "test-", 5)==0 ){ cmdFlags = 0x04; } } if( aEntry[i].zIf ) printf("%s", aEntry[i].zIf); printf(" { \"%s%.*s\",%*s %s,%*s %d },\n", Index: src/moderate.c ================================================================== --- src/moderate.c +++ src/moderate.c @@ -26,15 +26,15 @@ ** Create a table to represent pending moderation requests, if the ** table does not already exist. */ void moderation_table_create(void){ db_multi_exec( - "CREATE TABLE IF NOT EXISTS %s.modreq(\n" + "CREATE TABLE IF NOT EXISTS repository.modreq(\n" " objid INTEGER PRIMARY KEY,\n" /* Record pending approval */ " attachRid INT,\n" /* Object attached */ " tktid TEXT\n" /* Associated ticket id */ - ");\n", db_name("repository") + ");\n" ); } /* ** Return TRUE if the modreq table exists Index: src/name.c ================================================================== --- src/name.c +++ src/name.c @@ -333,11 +333,11 @@ ** takes its parameters and returns its value, and in that it does not ** treat errors as fatal. zName must be a UUID, as described for ** name_to_uuid(). zType is also as described for that function. If ** zName does not resolve, 0 is returned. If it is ambiguous, a ** negative value is returned. On success the rid is returned and -** pUuid (if it is not NULL) is set to the a newly-allocated string, +** pUuid (if it is not NULL) is set to a newly-allocated string, ** the full UUID, which must eventually be free()d by the caller. */ int name_to_uuid2(const char *zName, const char *zType, char **pUuid){ int rid = symbolic_name_to_rid(zName, zType); if((rid>0) && pUuid){ @@ -665,11 +665,11 @@ db_finalize(&q); } /* ** COMMAND: whatis* -** +** ** Usage: %fossil whatis NAME ** ** Resolve the symbol NAME into its canonical 40-character SHA1-hash ** artifact name and provide a description of what role that artifact ** plays. @@ -721,11 +721,11 @@ } } /* ** COMMAND: test-whatis-all -** +** ** Usage: %fossil test-whatis-all ** ** Show "whatis" information about every artifact in the repository */ void test_whatis_all_cmd(void){ @@ -741,11 +741,11 @@ } /* ** COMMAND: test-ambiguous -** +** ** Usage: %fossil test-ambiguous [--minsize N] ** ** Show a list of ambiguous SHA1-hash abbreviations of N characters or ** more where N defaults to 4. Change N to a different value using ** the "--minsize N" command-line option. @@ -934,16 +934,21 @@ "UPDATE description SET isPrivate=1 WHERE rid IN private" ); } /* -** Print the content of the description table on stdout +** Print the content of the description table on stdout. +** +** The description table is computed using the WHERE clause zWhere if +** the zWhere parameter is not NULL. If zWhere is NULL, then this +** routine assumes that the description table already exists and is +** populated and merely prints the contents. */ int describe_artifacts_to_stdout(const char *zWhere, const char *zLabel){ Stmt q; int cnt = 0; - describe_artifacts(zWhere); + if( zWhere!=0 ) describe_artifacts(zWhere); db_prepare(&q, "SELECT uuid, summary, isPrivate\n" " FROM description\n" " ORDER BY ctime, type;" ); @@ -956,11 +961,11 @@ if( db_column_int(&q,2) ) fossil_print(" (unpublished)"); fossil_print("\n"); cnt++; } db_finalize(&q); - db_multi_exec("DELETE FROM description;"); + if( zWhere!=0 ) db_multi_exec("DELETE FROM description;"); return cnt; } /* ** COMMAND: test-describe-artifacts Index: src/piechart.c ================================================================== --- src/piechart.c +++ src/piechart.c @@ -242,20 +242,20 @@ y4 = rLwrLeft; } rLwrLeft = y4 + TEXT_HEIGHT; } } - if( x4<=cx ){ + if( x4rCos); @ + @ x1='%g(x3)' y1='%g(y3)' x2='%g(x4)' y2='%g(y4)'/> @ %h(p->z) fossil_free(p->z); } db_finalize(&q); @@ -267,60 +267,65 @@ ** ** Generate a pie-chart based on data input from a form. */ void piechart_test_page(void){ const char *zData; - Stmt ins, q; - Blob all, line, token1, token2; + Stmt ins; int n = 0; int width; int height; + int i, j; login_check_credentials(); style_header("Pie Chart Test"); db_multi_exec("CREATE TEMP TABLE piechart(amt REAL, label TEXT);"); db_prepare(&ins, "INSERT INTO piechart(amt,label) VALUES(:amt,:label)"); zData = PD("data",""); width = atoi(PD("width","800")); height = atoi(PD("height","400")); - blob_init(&all, zData, -1); - while( blob_line(&all, &line) ){ + i = 0; + while( zData[i] ){ double rAmt; - if( blob_token(&line, &token1)==0 ) continue; - rAmt = atof(blob_str(&token1)); - if( rAmt<=0.0 ) continue; - blob_tail(&line, &token2); + char *zLabel; + while( fossil_isspace(zData[i]) ){ i++; } + j = i; + while( fossil_isdigit(zData[j]) ){ j++; } + if( zData[j]=='.' ){ + j++; + while( fossil_isdigit(zData[j]) ){ j++; } + } + if( i==j ) break; + rAmt = atof(&zData[i]); + i = j; + while( zData[i]==',' || fossil_isspace(zData[i]) ){ i++; } + n++; + zLabel = mprintf("label%02d-%g", n, rAmt); db_bind_double(&ins, ":amt", rAmt); - db_bind_text(&ins, ":label", blob_str(&token2)); + db_bind_text(&ins, ":label", zLabel); db_step(&ins); db_reset(&ins); - n++; + fossil_free(zLabel); } db_finalize(&ins); - blob_reset(&all); - if( n>0 ){ + if( n>1 ){ @ - piechart_render(width,height, PIE_OTHER); + piechart_render(width,height, PIE_OTHER|PIE_PERCENT); @ @
} - @
- @

One slice per line. Value and then Label.

- @
+ @ + @

Comma-separated list of slice widths:
+ @
@ Width: @ Height:
- @ - @ @ @

- @

Previous Data:

- @ - db_prepare(&q, "SELECT rowid, amt, label FROM piechart"); - while( db_step(&q)==SQLITE_ROW ){ - @ - @ - @ - } - db_finalize(&q); - @
%d(db_column_int(&q,0))%g(db_column_double(&q,1))%h(db_column_text(&q,2))
+ @

Interesting test cases: + @

style_footer(); } Index: src/purge.c ================================================================== --- src/purge.c +++ src/purge.c @@ -22,11 +22,11 @@ #include "config.h" #include "purge.h" #include /* -** SQL code used to initialize the schema of a bundle. +** SQL code used to initialize the schema of the graveyard. ** ** The purgeevent table contains one entry for each purge event. For each ** purge event, multiple artifacts might have been removed. Each removed ** artifact is stored as an entry in the purgeitem table. ** @@ -52,10 +52,19 @@ @ desc TEXT, -- Brief description of this artifact @ data BLOB -- Compressed artifact content @ ); ; +/* +** Flags for the purge_artifact_list() function. +*/ +#if INTERFACE +#define PURGE_MOVETO_GRAVEYARD 0x0001 /* Move artifacts in graveyard */ +#define PURGE_EXPLAIN_ONLY 0x0002 /* Show what would have happened */ +#define PURGE_PRINT_SUMMARY 0x0004 /* Print a summary report at end */ +#endif + /* ** This routine purges multiple artifacts from the repository, transfering ** those artifacts into the PURGEITEM table. ** ** Prior to invoking this routine, the caller must create a (TEMP) table @@ -81,17 +90,17 @@ ** (j) TICKETCHNG ** (7) If any ticket artifacts were removed (6j) then rebuild the ** corresponding ticket entries. Possibly remove entries from ** the ticket table. ** -** Stops 1-4 (saving the purged artifacts into the graveyard) are only +** Steps 1-4 (saving the purged artifacts into the graveyard) are only ** undertaken if the moveToGraveyard flag is true. */ int purge_artifact_list( const char *zTab, /* TEMP table containing list of RIDS to be purged */ const char *zNote, /* Text of the purgeevent.pnotes field */ - int moveToGraveyard /* Move purged artifacts into the graveyard */ + unsigned purgeFlags /* zero or more PURGE_* flags */ ){ int peid = 0; /* New purgeevent ID */ Stmt q; /* General-use prepared statement */ char *z; @@ -98,10 +107,20 @@ assert( g.repositoryOpen ); /* Main database must already be open */ db_begin_transaction(); z = sqlite3_mprintf("IN \"%w\"", zTab); describe_artifacts(z); sqlite3_free(z); + describe_artifacts_to_stdout(0, 0); + + /* The explain-only flags causes this routine to list the artifacts + ** that would have been purged but to not actually make any changes + ** to the repository. + */ + if( purgeFlags & PURGE_EXPLAIN_ONLY ){ + db_end_transaction(0); + return 0; + } /* Make sure we are not removing a manifest that is the baseline of some ** manifest that is being left behind. This step is not strictly necessary. ** is is just a safety check. */ if( purge_baseline_out_from_under_delta(zTab) ){ @@ -121,13 +140,13 @@ } db_finalize(&q); /* Construct the graveyard and copy the artifacts to be purged into the ** graveyard */ - if( moveToGraveyard ){ + if( purgeFlags & PURGE_MOVETO_GRAVEYARD ){ db_multi_exec(zPurgeInit /*works-like:"%w%w"*/, - db_name("repository"), db_name("repository")); + "repository", "repository"); db_multi_exec( "INSERT INTO purgeevent(ctime,pnotes) VALUES(now(),%Q)", zNote ); peid = db_last_insert_rowid(); db_prepare(&q, "SELECT rid FROM delta WHERE rid IN \"%w\"" @@ -189,10 +208,17 @@ db_finalize(&q); /* db_multi_exec("DROP TABLE \"%w_tickets\"", zTab); */ /* Mission accomplished */ db_end_transaction(0); + + if( purgeFlags & PURGE_PRINT_SUMMARY ){ + fossil_print("%d artifacts purged\n", + db_int(0, "SELECT count(*) FROM \"%w\";", zTab)); + fossil_print("undoable using \"%s purge undo %d\".\n", + g.nameOfExe, peid); + } return peid; } /* ** The TEMP table named zTab contains RIDs for a set of check-ins. @@ -220,11 +246,11 @@ /* ** The TEMP table named zTab contains the RIDs for a set of check-in ** artifacts. Expand this set (by adding new entries to zTab) to include -** all other artifacts that are used the set of check-ins in +** all other artifacts that are used by the check-ins in ** the original list. ** ** If the bExclusive flag is true, then the set is only expanded by ** artifacts that are used exclusively by the check-ins in the set. ** When bExclusive is false, then all artifacts used by the check-ins @@ -422,64 +448,113 @@ db_finalize(&q); if( iSrc>0 ) bag_remove(&busy, iSrc); } /* -** COMMAND: purge +** COMMAND: purge* ** ** The purge command removes content from a repository and stores that content ** in a "graveyard". The graveyard exists so that content can be recovered -** using the "fossil purge undo" command. +** using the "fossil purge undo" command. The "fossil purge obliterate" +** command empties the graveyard, making the content unrecoverable. +** +** ==== WARNING: This command can potentially destroy historical data and ==== +** ==== leave your repository in a goofy state. Know what you are doing! ==== +** ==== Make a backup of your repository before using this command! ==== +** +** ==== FURTHER WARNING: This command is a work-in-progress and may yet ==== +** ==== contain bugs. ==== +** +** fossil purge artifacts UUID... ?OPTIONS? +** +** Move arbitrary artifacts identified by the UUID list into the +** graveyard. ** ** fossil purge cat UUID... ** ** Write the content of one or more artifacts in the graveyard onto ** standard output. ** -** fossil purge ?checkins? TAGS... ?OPTIONS? +** fossil purge checkins TAGS... ?OPTIONS? ** -** Move the check-ins identified by TAGS and all of their descendants -** out of the repository and into the graveyard. The "checkins" -** subcommand keyword is optional and can be omitted as long as TAGS -** does not conflict with any other subcommand. -** +** Move the check-ins or branches identified by TAGS and all of +** their descendants out of the repository and into the graveyard. ** If TAGS includes a branch name then it means all the check-ins -** on the most recent occurrance of that branch. +** on the most recent occurrence of that branch. +** +** fossil purge files NAME ... ?OPTIONS? ** -** --explain Make no changes, but show what would happen. -** --dry-run Make no changes. +** Move all instances of files called NAME into the graveyard. +** NAME should be the name of the file relative to the root of the +** repository. If NAME is a directory, then all files within that +** directory are moved. ** ** fossil purge list|ls ?-l? ** ** Show the graveyard of prior purges. The -l option gives more ** detail in the output. ** -** fossil purge obliterate ID... +** fossil purge obliterate ID... ?--force? ** ** Remove one or more purge events from the graveyard. Once a purge -** event is obliterated, it can no longer be undone. +** event is obliterated, it can no longer be undone. The --force +** option suppresses the confirmation prompt. +** +** fossil purge tickets NAME ... ?OPTIONS? +** +** TBD... ** ** fossil purge undo ID ** ** Restore the content previously removed by purge ID. ** +** fossil purge wiki NAME ... ?OPTIONS? +** +** TBD... +** +** COMMON OPTIONS: +** +** --explain Make no changes, but show what would happen. +** --dry-run An alias for --explain +** ** SUMMARY: +** fossil purge artifacts UUID.. [OPTIONS] ** fossil purge cat UUID... -** fossil purge [checkins] TAGS... [--explain] +** fossil purge checkins TAGS... [OPTIONS] +** fossil purge files FILENAME... [OPTIONS] ** fossil purge list ** fossil purge obliterate ID... +** fossil purge tickets NAME... [OPTIONS] ** fossil purge undo ID +** fossil purge wiki NAME... [OPTIONS] */ void purge_cmd(void){ + int purgeFlags = PURGE_MOVETO_GRAVEYARD | PURGE_PRINT_SUMMARY; const char *zSubcmd; int n; + int i; Stmt q; + if( g.argc<3 ) usage("SUBCOMMAND ?ARGS?"); zSubcmd = g.argv[2]; db_find_and_open_repository(0,0); n = (int)strlen(zSubcmd); - if( strncmp(zSubcmd, "cat", n)==0 ){ + if( find_option("explain",0,0)!=0 || find_option("dry-run",0,0)!=0 ){ + purgeFlags |= PURGE_EXPLAIN_ONLY; + } + if( strncmp(zSubcmd, "artifacts", n)==0 ){ + verify_all_options(); + db_begin_transaction(); + db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)"); + for(i=3; i=g.argc ) usage("[checkin] TAGS... [--explain]"); - db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)"); - for(; i #if INTERFACE -/* Maximum number of search terms */ +/* Maximum number of search terms for full-scan search */ #define SEARCH_MAX_TERM 8 /* -** A compiled search pattern +** A compiled search pattern used for full-scan search. */ struct Search { int nTerm; /* Number of search terms */ struct srchTerm { /* For each search term */ char *z; /* Text */ @@ -85,11 +94,11 @@ }; #define ISALNUM(x) (!isBoundary[(x)&0xff]) /* -** Destroy a search context. +** Destroy a full-scan search context. */ void search_end(Search *p){ if( p ){ fossil_free(p->zPattern); fossil_free(p->zMarkBegin); @@ -100,11 +109,11 @@ if( p!=&gSearch ) fossil_free(p); } } /* -** Compile a search pattern +** Compile a full-scan search pattern */ static Search *search_init( const char *zPattern, /* The search pattern */ const char *zMarkBegin, /* Start of a match */ const char *zMarkEnd, /* End of a match */ @@ -157,11 +166,12 @@ blob_append(pSnip, zTxt, n); } } } -/* +/* This the core search engine for full-scan search. +** ** Compare a search pattern against one or more input strings which ** collectively comprise a document. Return a match score. Any ** postive value means there was a match. Zero means that one or ** more terms are missing. ** @@ -318,10 +328,13 @@ /* ** COMMAND: test-match ** ** Usage: %fossil test-match SEARCHSTRING FILE1 FILE2 ... +** +** Run the full-scan search algorithm using SEARCHSTRING against +** the text of the files listed. Output matches and snippets. */ void test_match_cmd(void){ Search *p; int i; Blob x; @@ -351,15 +364,19 @@ } search_end(p); } /* -** An SQL function to initialize the global search pattern: +** An SQL function to initialize the full-scan search pattern: ** ** search_init(PATTERN,BEGIN,END,GAP,FLAGS) ** -** All arguments are optional. +** All arguments are optional. PATTERN is the search pattern. If it +** is omitted, then the global search pattern is reset. BEGIN and END +** and GAP are the strings used to construct snippets. FLAGS is an +** integer bit pattern containing the various SRCH_CKIN, SRCH_DOC, +** SRCH_TKT, or SRCH_ALL bits to determine what is to be searched. */ static void search_init_sqlfunc( sqlite3_context *context, int argc, sqlite3_value **argv @@ -386,13 +403,15 @@ }else{ search_end(&gSearch); } } -/* -** Try to match the input text against the search parameters set up -** by the previous search_init() call. Remember the results globally. +/* search_match(TEXT, TEXT, ....) +** +** Using the full-scan search engine created by the most recent call +** to search_init(), match the input the TEXT arguments. +** Remember the results global full-scan search object. ** Return non-zero on a match and zero on a miss. */ static void search_match_sqlfunc( sqlite3_context *context, int argc, @@ -407,21 +426,27 @@ } rc = search_match(&gSearch, nDoc, azDoc); sqlite3_result_int(context, rc); } -/* -** These SQL functions return the results of the last -** call to the search_match() SQL function. + +/* search_score() +** +** Return the match score for the last successful search_match call. */ static void search_score_sqlfunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ sqlite3_result_int(context, gSearch.iScore); } + +/* search_snippet() +** +** Return a snippet for the last successful search_match() call. +*/ static void search_snippet_sqlfunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ @@ -429,11 +454,12 @@ sqlite3_result_text(context, blob_str(&gSearch.snip), -1, fossil_free); blob_init(&gSearch.snip, 0, 0); } } -/* +/* stext(TYPE, RID, ARG) +** ** This is an SQLite function that computes the searchable text. ** It is a wrapper around the search_stext() routine. See the ** search_stext() routine for further detail. */ static void search_stext_sqlfunc( @@ -445,10 +471,15 @@ int rid = sqlite3_value_int(argv[1]); const char *zName = (const char*)sqlite3_value_text(argv[2]); sqlite3_result_text(context, search_stext_cached(zType[0],rid,zName,0), -1, SQLITE_TRANSIENT); } + +/* title(TYPE, RID, ARG) +** +** Return the title of the document to be search. +*/ static void search_title_sqlfunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ @@ -461,10 +492,15 @@ sqlite3_result_text(context, z, nHdr, SQLITE_TRANSIENT); }else{ sqlite3_result_value(context, argv[2]); } } + +/* body(TYPE, RID, ARG) +** +** Return the body of the document to be search. +*/ static void search_body_sqlfunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ @@ -474,12 +510,14 @@ int nHdr = 0; char *z = search_stext_cached(zType[0], rid, zName, &nHdr); sqlite3_result_text(context, z+nHdr+1, -1, SQLITE_TRANSIENT); } -/* -** Encode a string for use as a query parameter in a URL +/* urlencode(X) +** +** Encode a string for use as a query parameter in a URL. This is +** the equivalent of printf("%T",X). */ static void search_urlencode_sqlfunc( sqlite3_context *context, int argc, sqlite3_value **argv @@ -487,13 +525,12 @@ char *z = mprintf("%T",sqlite3_value_text(argv[0])); sqlite3_result_text(context, z, -1, fossil_free); } /* -** Register the "score()" SQL function to score its input text -** using the given Search object. Once this function is registered, -** do not delete the Search object. +** Register the various SQL functions (defined above) needed to implement +** full-scan search. */ void search_sql_setup(sqlite3 *db){ static int once = 0; if( once++ ) return; sqlite3_create_function(db, "search_match", -1, SQLITE_UTF8, 0, @@ -636,16 +673,22 @@ } /* ** When this routine is called, there already exists a table ** -** x(label,url,score,date,snip). +** x(label,url,score,id,snip). +** +** label: The "name" of the document containing the match +** url: A URL for the document +** score: How well the document matched +** id: The document id. Format: xNNNNN, x: type, N: number +** snip: A snippet for the match ** ** And the srchFlags parameter has been validated. This routine -** fills the X table with search results using a full-text scan. +** fills the X table with search results using a full-scan search. ** -** The companion indexed scan routine is search_indexed(). +** The companion indexed search routine is search_indexed(). */ static void search_fullscan( const char *zPattern, /* The query pattern */ unsigned int srchFlags /* What to search over */ ){ @@ -805,16 +848,22 @@ } /* ** When this routine is called, there already exists a table ** -** x(label,url,score,date,snip). +** x(label,url,score,id,snip). +** +** label: The "name" of the document containing the match +** url: A URL for the document +** score: How well the document matched +** id: The document id. Format: xNNNNN, x: type, N: number +** snip: A snippet for the match ** ** And the srchFlags parameter has been validated. This routine -** fills the X table with search results using a index scan. +** fills the X table with search results using FTS indexed search. ** -** The companion full-text scan routine is search_fullscan(). +** The companion full-scan search routine is search_fullscan(). */ static void search_indexed( const char *zPattern, /* The query pattern */ unsigned int srchFlags /* What to search over */ ){ @@ -910,10 +959,14 @@ /* ** This routine generates web-page output for a search operation. ** Other web-pages can invoke this routine to add search results ** in the middle of the page. +** +** This routine works for both full-scan and indexed search. The +** appropriate low-level search routine is called according to the +** current configuration. ** ** Return the number of rows. */ int search_run_and_output( const char *zPattern, /* The query pattern */ @@ -929,14 +982,14 @@ add_content_sql_commands(g.db); db_multi_exec( "CREATE TEMP TABLE x(label,url,score,id,date,snip);" ); if( !search_index_exists() ){ - search_fullscan(zPattern, srchFlags); + search_fullscan(zPattern, srchFlags); /* Full-scan search */ }else{ - search_update_index(srchFlags); - search_indexed(zPattern, srchFlags); + search_update_index(srchFlags); /* Update the index, if necessary */ + search_indexed(zPattern, srchFlags); /* Indexed search */ } db_prepare(&q, "SELECT url, snip, label, score, id" " FROM x" " ORDER BY score DESC, date DESC;"); while( db_step(&q)==SQLITE_ROW ){ @@ -947,11 +1000,11 @@ @
    } nRow++; @
  1. %h(zLabel) if( fDebug ){ - @ (%e(db_column_double(&q,3)), %s(db_column_text(&q,4))) + @ (%e(db_column_double(&q,3)), %s(db_column_text(&q,4)) } @
    %z(cleanSnippet(zSnippet))

  2. } db_finalize(&q); if( nRow ){ @@ -998,11 +1051,11 @@ }else{ zDisable1 = " autofocus"; zDisable2 = ""; zPattern = PD("s",""); } - @
    + @ if( zClass ){ @
    }else{ @
    } @@ -1173,11 +1226,14 @@ ** t Ticket text ** ** rid The RID of an artifact that defines the object ** being searched. ** -** zName Name of the object being searched. +** zName Name of the object being searched. This is used +** only to help figure out the mimetype (text/plain, +** test/html, test/x-fossil-wiki, or text/x-markdown) +** so that the code can know how to simplify the text. */ void search_stext( char cType, /* Type of document */ int rid, /* BLOB.RID or TAG.TAGID value for document */ const char *zName, /* Auxiliary information */ @@ -1276,11 +1332,11 @@ ** with an eType of 0 to clear the cache. */ char *search_stext_cached( char cType, /* Type of document */ int rid, /* BLOB.RID or TAG.TAGID value for document */ - const char *zName, /* Auxiliary information */ + const char *zName, /* Auxiliary information, for mimetype */ int *pnTitle /* OUT: length of title in bytes excluding \n */ ){ static struct { Blob stext; /* Cached search text */ char cType; /* The type */ @@ -1308,11 +1364,16 @@ } /* ** COMMAND: test-search-stext ** -** Usage: fossil test-search-stext TYPE ARG1 ARG2 +** Usage: fossil test-search-stext TYPE RID NAME +** +** Compute the search text for document TYPE-RID whose name is NAME. +** The TYPE is one of "c", "d", "t", or "w". The RID is the document +** ID. The NAME is used to figure out a mimetype to use for formatting +** the raw document text. */ void test_search_stext(void){ Blob out; db_find_and_open_repository(0,0); if( g.argc!=5 ) usage("TYPE RID NAME"); @@ -1343,11 +1404,11 @@ /* The schema for the full-text index */ static const char zFtsSchema[] = @ -- One entry for each possible search result -@ CREATE TABLE IF NOT EXISTS "%w".ftsdocs( +@ CREATE TABLE IF NOT EXISTS repository.ftsdocs( @ rowid INTEGER PRIMARY KEY, -- Maps to the ftsidx.docid @ type CHAR(1), -- Type of document @ rid INTEGER, -- BLOB.RID or TAG.TAGID for the document @ name TEXT, -- Additional document description @ idxed BOOLEAN, -- True if currently in the index @@ -1355,41 +1416,38 @@ @ url TEXT, -- URL to access this document @ mtime DATE, -- Date when document created @ bx TEXT, -- Temporary "body" content cache @ UNIQUE(type,rid) @ ); -@ CREATE INDEX "%w".ftsdocIdxed ON ftsdocs(type,rid,name) WHERE idxed==0; -@ CREATE INDEX "%w".ftsdocName ON ftsdocs(name) WHERE type='w'; -@ CREATE VIEW IF NOT EXISTS "%w".ftscontent AS +@ CREATE INDEX repository.ftsdocIdxed ON ftsdocs(type,rid,name) WHERE idxed==0; +@ CREATE INDEX repository.ftsdocName ON ftsdocs(name) WHERE type='w'; +@ CREATE VIEW IF NOT EXISTS repository.ftscontent AS @ SELECT rowid, type, rid, name, idxed, label, url, mtime, @ title(type,rid,name) AS 'title', body(type,rid,name) AS 'body' @ FROM ftsdocs; -@ CREATE VIRTUAL TABLE IF NOT EXISTS "%w".ftsidx +@ CREATE VIRTUAL TABLE IF NOT EXISTS repository.ftsidx @ USING fts4(content="ftscontent", title, body%s); ; static const char zFtsDrop[] = -@ DROP TABLE IF EXISTS "%w".ftsidx; -@ DROP VIEW IF EXISTS "%w".ftscontent; -@ DROP TABLE IF EXISTS "%w".ftsdocs; +@ DROP TABLE IF EXISTS repository.ftsidx; +@ DROP VIEW IF EXISTS repository.ftscontent; +@ DROP TABLE IF EXISTS repository.ftsdocs; ; /* ** Create or drop the tables associated with a full-text index. */ static int searchIdxExists = -1; void search_create_index(void){ - const char *zDb = db_name("repository"); int useStemmer = db_get_boolean("search-stemmer",0); const char *zExtra = useStemmer ? ",tokenize=porter" : ""; search_sql_setup(g.db); - db_multi_exec(zFtsSchema/*works-like:"%w%w%w%w%w%s"*/, - zDb, zDb, zDb, zDb, zDb, zExtra/*safe-for-%s*/); + db_multi_exec(zFtsSchema/*works-like:"%s"*/, zExtra/*safe-for-%s*/); searchIdxExists = 1; } void search_drop_index(void){ - const char *zDb = db_name("repository"); - db_multi_exec(zFtsDrop/*works-like:"%w%w%w"*/, zDb, zDb, zDb); + db_multi_exec(zFtsDrop/*works-like:""*/); searchIdxExists = 0; } /* ** Return true if the full-text search index exists @@ -1474,19 +1532,17 @@ */ static void search_update_doc_index(void){ const char *zDocBr = db_get("doc-branch","trunk"); int ckid = zDocBr ? symbolic_name_to_rid(zDocBr,"ci") : 0; double rTime; - char *zBrUuid; if( ckid==0 ) return; if( !db_exists("SELECT 1 FROM ftsdocs WHERE type='c' AND rid=%d" " AND NOT idxed", ckid) ) return; /* If we get this far, it means that changes to 'd' entries are ** required. */ rTime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", ckid); - zBrUuid = db_text("","SELECT substr(uuid,1,20) FROM blob WHERE rid=%d",ckid); db_multi_exec( "CREATE TEMP TABLE current_docs(rid INTEGER PRIMARY KEY, name);" "CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;" "INSERT OR IGNORE INTO current_docs(rid, name)" " SELECT blob.rid, foci.filename FROM foci, blob" @@ -1506,14 +1562,14 @@ db_multi_exec( "INSERT OR IGNORE INTO ftsdocs(type,rid,name,idxed,label,bx,url,mtime)" " SELECT 'd', rid, name, 0," " title('d',rid,name)," " body('d',rid,name)," - " printf('/doc/%q/%%s',urlencode(name))," + " printf('/doc/%T/%%s',urlencode(name))," " %.17g" " FROM current_docs", - zBrUuid, rTime + zDocBr, rTime ); db_multi_exec( "INSERT INTO ftsidx(docid,title,body)" " SELECT rowid, label, bx FROM ftsdocs WHERE type='d' AND NOT idxed" ); @@ -1733,5 +1789,96 @@ }else{ fossil_print("%-16s disabled\n", "full-text index:"); } db_end_transaction(0); } + +/* +** WEBPAGE: test-ftsdocs +** +** Show a table of all documents currently in the search index. +*/ +void search_data_page(void){ + Stmt q; + const char *zId = P("id"); + const char *zType = P("y"); + const char *zIdxed = P("ixed"); + int id; + int cnt = 0; + login_check_credentials(); + if( !g.perm.Admin ){ login_needed(0); return; } + if( !search_index_exists() ){ + @

    Indexed search is disabled + style_footer(); + return; + } + if( zId!=0 && (id = atoi(zId))>0 ){ + /* Show information about a single ftsdocs entry */ + style_header("Information about ftsdoc entry %d", id); + db_prepare(&q, + "SELECT type||rid, name, idxed, label, url, datetime(mtime)" + " FROM ftsdocs WHERE rowid=%d", id + ); + if( db_step(&q)==SQLITE_ROW ){ + const char *zUrl = db_column_text(&q,4); + @ + @
    rowid:  %d(id) + @
    id:%s(db_column_text(&q,0)) + @
    name:%h(db_column_text(&q,1)) + @
    idxed:%d(db_column_int(&q,2)) + @
    label:%h(db_column_text(&q,3)) + @
    url: + @ %h(zUrl) + @
    mtime:%s(db_column_text(&q,5)) + @
    + } + db_finalize(&q); + style_footer(); + return; + } + if( zType!=0 && zType[0]!=0 && zType[1]==0 && + zIdxed!=0 && (zIdxed[0]=='1' || zIdxed[0]=='0') && zIdxed[1]==0 + ){ + int ixed = zIdxed[0]=='1'; + style_header("List of '%c' documents that are%s indexed", + zType[0], ixed ? "" : " not"); + db_prepare(&q, + "SELECT rowid, type||rid ||' '|| coalesce(label,'')" + " FROM ftsdocs WHERE type='%c' AND %s idxed", + zType[0], ixed ? "" : "NOT" + ); + @

    + db_finalize(&q); + style_footer(); + return; + } + style_header("Summary of ftsdocs"); + db_prepare(&q, + "SELECT type, idxed, count(*) FROM ftsdocs" + " GROUP BY 1, 2 ORDER BY 3 DESC" + ); + @ + @ + @ + @ + while( db_step(&q)==SQLITE_ROW ){ + const char *zType = db_column_text(&q,0); + int idxed = db_column_int(&q,1); + int n = db_column_int(&q,2); + @ + cnt += n; + } + @ + @
    TypeIndexed?CountLink + @
    %h(zType)%d(idxed) + @ %d(n) + @ listing + @
    Total%d(cnt) + @ + @
    + style_footer(); +} Index: src/setup.c ================================================================== --- src/setup.c +++ src/setup.c @@ -115,10 +115,12 @@ setup_menu_entry("Moderation", "setup_modreq", "Enable/Disable requiring moderator approval of Wiki and/or Ticket" " changes and attachments."); setup_menu_entry("Ad-Unit", "setup_adunit", "Edit HTML text for an ad unit inserted after the menu bar"); + setup_menu_entry("Web-Cache", "cachestat", + "View the status of the expensive-page cache"); setup_menu_entry("Logo", "setup_logo", "Change the logo and background images for the server"); setup_menu_entry("Shunned", "shun", "Show artifacts that are shunned by this repository"); setup_menu_entry("Artifact Receipts Log", "rcvfromlist", @@ -125,10 +127,12 @@ "A record of received artifacts and their sources"); setup_menu_entry("User Log", "access_log", "A record of login attempts"); setup_menu_entry("Administrative Log", "admin_log", "View the admin_log entries"); + setup_menu_entry("Unversioned Files", "uvlist?byage=1", + "Show all unversioned files held"); setup_menu_entry("Stats", "stat", "Repository Status Reports"); setup_menu_entry("Sitemap", "sitemap", "Links to miscellaneous pages"); setup_menu_entry("SQL", "admin_sql", @@ -158,11 +162,14 @@ style_submenu_element("Add", "Add User", "setup_uedit"); style_submenu_element("Log", "Access Log", "access_log"); style_submenu_element("Help", "Help", "setup_ulist_notes"); style_header("User List"); @ - @ + @ + @ @ db_prepare(&s, "SELECT uid, login, cap, date(mtime,'unixepoch')" " FROM user" " WHERE login IN ('anonymous','nobody','developer','reader')" @@ -234,21 +241,13 @@ output_table_sorting_javascript("userlist","nktxTT",2); style_footer(); } /* -** WEBPAGE: setup_ulist_notes -** -** A documentation page showing notes about user configuration. This information -** used to be a side-bar on the user list page, but has been factored out for -** improved presentation. +** Render the user-capability table */ -void setup_ulist_notes(void){ - style_header("User Configuration Notes"); - @

    User Configuration Notes:

    - @
      - @
    1. The permission flags are as follows:

      +static void setup_usercap_table(void){ @
    UID Category Capabilities Info Last Change
    UID Category + @ Capabilities (key) + @ Info Last Change
    @ @ @ @ @@ -297,15 +296,28 @@ @ user developer @ @ @ @ + @ + @ @ @ @
    aAdmin: Create and delete users
    bAttach: Add attachments to wiki or tickets
    wWrite-Tkt: Edit tickets
    xPrivate: Push and/or pull private branches
    yWrite-Unver: Push unversioned files
    zZip download: Download a ZIP archive or tarball
    - @ - @ +} + +/* +** WEBPAGE: setup_ulist_notes +** +** A documentation page showing notes about user configuration. This information +** used to be a side-bar on the user list page, but has been factored out for +** improved presentation. +*/ +void setup_ulist_notes(void){ + style_header("User Configuration Notes"); + @

    User Configuration Notes:

    + @
      @
    1. @ Every user, logged in or not, inherits the privileges of @ nobody. @

    2. @ @@ -316,21 +328,42 @@ @ Every logged-in user inherits the combined privileges of @ anonymous and @ nobody. @

      @ + @
    3. + @ Users with privilege u inherit the combined + @ privileges of reader, + @ anonymous, and + @ nobody. + @

    4. + @ @
    5. @ Users with privilege v inherit the combined @ privileges of developer, @ anonymous, and @ nobody. @

    6. @ + @
    7. The permission flags are as follows:

      + setup_usercap_table(); + @
    8. @
    style_footer(); } +/* +** WEBPAGE: setup_ucap_list +** +** A documentation page showing the meaning of the various user capabilities +** code letters. +*/ +void setup_ucap_list(void){ + style_header("User Capability Codes"); + setup_usercap_table(); + style_footer(); +} /* ** Return true if zPw is a valid password string. A valid ** password string is: ** @@ -685,10 +718,13 @@ @ onchange="updateCapabilityString()" /> @ Ticket Report%s(B('t'))
    @
    + @
    @ @ @ @@ -1136,11 +1172,11 @@ "Enable hyperlinks for \"nobody\" based on User-Agent and Javascript", "auto-hyperlink", "autohyperlink", 1, 0); @

    Enable hyperlinks (the equivalent of the "h" permission) for all users @ including user "nobody", as long as (1) the User-Agent string in the @ HTTP header indicates that the request is coming from an actual human - @ being and not a a robot or spider and (2) the user agent is able to + @ being and not a robot or spider and (2) the user agent is able to @ run Javascript in order to set the href= attribute of hyperlinks. Bots @ and spiders can forge a User-Agent string that makes them seem to be a @ normal browser and they can run javascript just like browsers. But most @ bots do not go to that much trouble so this is normally an effective @ defense.

    @@ -1892,16 +1928,16 @@ @ repository. Proceed with extreme caution.

    @ @

    Only the first statement in the entry box will be run. @ Any subsequent statements will be silently ignored.

    @ - @

    Database names:

    • repository → %s(db_name("repository")) + @

      Database names:

      • repository if( g.zConfigDbName ){ - @
      • config → %s(db_name("configdb")) + @
      • configdb } if( g.localOpen ){ - @
      • local-checkout → %s(db_name("localdb")) + @
      • localdb } @

      @ @ login_insert_csrf_secret(); @@ -1911,18 +1947,16 @@ @ @ @
    • if( P("schema") ){ zQ = sqlite3_mprintf( - "SELECT sql FROM %s.sqlite_master WHERE sql IS NOT NULL", - db_name("repository")); + "SELECT sql FROM repository.sqlite_master WHERE sql IS NOT NULL"); go = 1; }else if( P("tablelist") ){ zQ = sqlite3_mprintf( - "SELECT name FROM %s.sqlite_master WHERE type='table'" - " ORDER BY name", - db_name("repository")); + "SELECT name FROM repository.sqlite_master WHERE type='table'" + " ORDER BY name"); go = 1; } if( go ){ sqlite3_stmt *pStmt; int rc; Index: src/shell.c ================================================================== --- src/shell.c +++ src/shell.c @@ -2541,17 +2541,26 @@ } /* ** A routine for handling output from sqlite3_trace(). */ -static void sql_trace_callback(void *pArg, const char *z){ +static int sql_trace_callback( + unsigned mType, + void *pArg, + void *pP, + void *pX +){ FILE *f = (FILE*)pArg; + UNUSED_PARAMETER(mType); + UNUSED_PARAMETER(pP); if( f ){ + const char *z = (const char*)pX; int i = (int)strlen(z); while( i>0 && z[i-1]==';' ){ i--; } utf8_printf(f, "%.*s;\n", i, z); } + return 0; } /* ** A no-op routine that runs with the ".breakpoint" doc-command. This is ** a useful spot to set a debugger breakpoint. @@ -2944,14 +2953,14 @@ } /* ** Convert a 2-byte or 4-byte big-endian integer into a native integer */ -unsigned int get2byteInt(unsigned char *a){ +static unsigned int get2byteInt(unsigned char *a){ return (a[0]<<8) + a[1]; } -unsigned int get4byteInt(unsigned char *a){ +static unsigned int get4byteInt(unsigned char *a){ return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3]; } /* ** Implementation of the ".info" command. @@ -4653,13 +4662,13 @@ } output_file_close(p->traceOut); p->traceOut = output_file_open(azArg[1]); #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) if( p->traceOut==0 ){ - sqlite3_trace(p->db, 0, 0); + sqlite3_trace_v2(p->db, 0, 0, 0); }else{ - sqlite3_trace(p->db, sql_trace_callback, p->traceOut); + sqlite3_trace_v2(p->db, SQLITE_TRACE_STMT, sql_trace_callback,p->traceOut); } #endif }else #if SQLITE_USER_AUTHENTICATION @@ -5315,10 +5324,12 @@ zSize = cmdline_option_value(argc, argv, ++i); szHeap = integerValue(zSize); if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000; sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64); +#else + (void)cmdline_option_value(argc, argv, ++i); #endif }else if( strcmp(z,"-scratch")==0 ){ int n, sz; sz = (int)integerValue(cmdline_option_value(argc,argv,++i)); if( sz>400000 ) sz = 400000; Index: src/shun.c ================================================================== --- src/shun.c +++ src/shun.c @@ -327,10 +327,15 @@ } db_multi_exec( "CREATE TEMP TABLE rcvidUsed(x INTEGER PRIMARY KEY);" "INSERT OR IGNORE INTO rcvidUsed(x) SELECT rcvid FROM blob;" ); + if( db_table_exists("repository","unversioned") ){ + db_multi_exec( + "INSERT OR IGNORE INTO rcvidUsed(x) SELECT rcvid FROM unversioned;" + ); + } db_prepare(&q, "SELECT rcvid, login, datetime(rcvfrom.mtime), rcvfrom.ipaddr," " EXISTS(SELECT 1 FROM rcvidUsed WHERE x=rcvfrom.rcvid)" " FROM rcvfrom LEFT JOIN user USING(uid)" " ORDER BY rcvid DESC LIMIT %d OFFSET %d", @@ -389,10 +394,11 @@ ** parameters. Requires Admin privilege. */ void rcvfrom_page(void){ int rcvid = atoi(PD("rcvid","0")); Stmt q; + int cnt; login_check_credentials(); if( !g.perm.Admin ){ login_needed(0); return; @@ -441,20 +447,90 @@ db_prepare(&q, "SELECT blob.rid, blob.uuid, blob.size, description.summary\n" " FROM blob LEFT JOIN description ON (blob.rid=description.rid)" " WHERE blob.rcvid=%d", rcvid ); - @ Artifacts: - @ + cnt = 0; while( db_step(&q)==SQLITE_ROW ){ const char *zUuid = db_column_text(&q, 1); int size = db_column_int(&q, 2); const char *zDesc = db_column_text(&q, 3); if( zDesc==0 ) zDesc = ""; + if( cnt==0 ){ + @ Artifacts: + @ + } + cnt++; @ %s(zUuid) @ %h(zDesc) (size: %d(size))
      } - @ + if( cnt>0 ){ + @

      + if( db_exists( + "SELECT 1 FROM blob WHERE rcvid=%d AND" + " NOT EXISTS (SELECT 1 FROM shun WHERE shun.uuid=blob.uuid)", rcvid) + ){ + @

      + @ + @ + @ + @
      + } + if( db_exists( + "SELECT 1 FROM blob WHERE rcvid=%d AND" + " EXISTS (SELECT 1 FROM shun WHERE shun.uuid=blob.uuid)", rcvid) + ){ + @
      + @ + @ + @ + @
      + } + @ + } + if( db_table_exists("repository","unversioned") ){ + cnt = 0; + if( PB("uvdelete") && PB("confirmdelete") ){ + db_multi_exec( + "DELETE FROM unversioned WHERE rcvid=%d", rcvid + ); + } + db_finalize(&q); + db_prepare(&q, + "SELECT name, hash, sz\n" + " FROM unversioned " + " WHERE rcvid=%d", rcvid + ); + while( db_step(&q)==SQLITE_ROW ){ + const char *zName = db_column_text(&q,0); + const char *zHash = db_column_text(&q,1); + int size = db_column_int(&q,2); + int isDeleted = zHash==0; + if( cnt==0 ){ + @ Unversioned Files: + @ + } + cnt++; + if( isDeleted ){ + @ %h(zName) (deleted)
      + }else{ + @ %h(zName) (size: %d(size))
      + } + } + if( cnt>0 ){ + @

      + @ + @ + if( PB("uvdelete") ){ + @ + @ + }else{ + @ + } + @
      + @ + } + } @ db_finalize(&q); style_footer(); } Index: src/sitemap.c ================================================================== --- src/sitemap.c +++ src/sitemap.c @@ -101,10 +101,13 @@ @
    • %z(href("%R/timeline?y=t"))Recent activity
    • @
    • %z(href("%R/attachlist"))List of Attachments
    • @
    @ } + if( g.perm.Read ){ + @
  3. %z(href("%R/uvlist"))Unversioned Files + } if( srchFlags ){ @
  4. %z(href("%R/search"))Full-Text Search
  5. } @
  6. %z(href("%R/login"))Login/Logout/Change Password
  7. if( g.perm.Read ){ Index: src/sqlcmd.c ================================================================== --- src/sqlcmd.c +++ src/sqlcmd.c @@ -142,11 +142,10 @@ ){ add_content_sql_commands(db); db_add_aux_functions(db); re_add_sql_func(db); search_sql_setup(db); - g.zMainDbType = "repository"; foci_register(db); g.repositoryOpen = 1; g.db = db; return SQLITE_OK; } @@ -223,9 +222,8 @@ */ void fossil_close(int bDb, int noRepository){ if( bDb ) db_close(1); if( noRepository ) g.zRepositoryName = 0; g.db = 0; - g.zMainDbType = 0; g.repositoryOpen = 0; g.localOpen = 0; } Index: src/sqlite3.c ================================================================== --- src/sqlite3.c +++ src/sqlite3.c @@ -1,8 +1,8 @@ /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite -** version 3.13.0. By combining all the individual C code files into this +** version 3.15.0. By combining all the individual C code files into this ** single large file, the entire code can be compiled as a single translation ** unit. This allows many compilers to do optimizations that would not be ** possible if the files were compiled separately. Performance improvements ** of 5% or more are commonly seen when SQLite is compiled as a single ** translation unit. @@ -35,12 +35,12 @@ ** ************************************************************************* ** Internal interface definitions for SQLite. ** */ -#ifndef _SQLITEINT_H_ -#define _SQLITEINT_H_ +#ifndef SQLITEINT_H +#define SQLITEINT_H /* Special Comments: ** ** Some comments have special meaning to the tools that measure test ** coverage: @@ -65,10 +65,18 @@ ** In all cases, the special comment must be enclosed in the usual ** slash-asterisk...asterisk-slash comment marks, with no spaces between the ** asterisks and the comment text. */ +/* +** Make sure the Tcl calling convention macro is defined. This macro is +** only used by test code and Tcl integration code. +*/ +#ifndef SQLITE_TCLAPI +# define SQLITE_TCLAPI +#endif + /* ** Make sure that rand_s() is available on Windows systems with MSVC 2005 ** or higher. */ #if defined(_MSC_VER) && _MSC_VER>=1400 @@ -95,12 +103,12 @@ ** ****************************************************************************** ** ** This file contains code that is specific to MSVC. */ -#ifndef _MSVC_H_ -#define _MSVC_H_ +#ifndef SQLITE_MSVC_H +#define SQLITE_MSVC_H #if defined(_MSC_VER) #pragma warning(disable : 4054) #pragma warning(disable : 4055) #pragma warning(disable : 4100) @@ -116,11 +124,11 @@ #pragma warning(disable : 4306) #pragma warning(disable : 4702) #pragma warning(disable : 4706) #endif /* defined(_MSC_VER) */ -#endif /* _MSVC_H_ */ +#endif /* SQLITE_MSVC_H */ /************** End of msvc.h ************************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /* @@ -280,12 +288,12 @@ ** The name of this file under configuration management is "sqlite.h.in". ** The makefile makes some minor changes to this file (such as inserting ** the version number) and changes its name to "sqlite3.h" as ** part of the build process. */ -#ifndef _SQLITE3_H_ -#define _SQLITE3_H_ +#ifndef SQLITE3_H +#define SQLITE3_H #include /* Needed for the definition of va_list */ /* ** Make sure we can call this stuff from C++. */ @@ -304,12 +312,21 @@ # define SQLITE_API #endif #ifndef SQLITE_CDECL # define SQLITE_CDECL #endif +#ifndef SQLITE_APICALL +# define SQLITE_APICALL +#endif #ifndef SQLITE_STDCALL -# define SQLITE_STDCALL +# define SQLITE_STDCALL SQLITE_APICALL +#endif +#ifndef SQLITE_CALLBACK +# define SQLITE_CALLBACK +#endif +#ifndef SQLITE_SYSAPI +# define SQLITE_SYSAPI #endif /* ** These no-op macros are used in front of interfaces to mark those ** interfaces as either deprecated or experimental. New applications @@ -361,13 +378,13 @@ ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.13.0" -#define SQLITE_VERSION_NUMBER 3013000 -#define SQLITE_SOURCE_ID "2016-05-18 10:57:30 fc49f556e48970561d7ab6a2f24fdd7d9eb81ff2" +#define SQLITE_VERSION "3.15.0" +#define SQLITE_VERSION_NUMBER 3015000 +#define SQLITE_SOURCE_ID "2016-08-22 20:10:01 7839519349c7371cdb4e16a215eacd27004cbc62" /* ** CAPI3REF: Run-Time Library Version Numbers ** KEYWORDS: sqlite3_version, sqlite3_sourceid ** @@ -756,10 +773,11 @@ #define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT |(10<<8)) #define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) #define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) +#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8)) /* ** CAPI3REF: Flags For File Open Operations ** ** These bit values are intended for use in the @@ -1285,10 +1303,20 @@ ** ** Mutexes are created using [sqlite3_mutex_alloc()]. */ typedef struct sqlite3_mutex sqlite3_mutex; +/* +** CAPI3REF: Loadable Extension Thunk +** +** A pointer to the opaque sqlite3_api_routines structure is passed as +** the third parameter to entry points of [loadable extensions]. This +** structure must be typedefed in order to work around compiler warnings +** on some platforms. +*/ +typedef struct sqlite3_api_routines sqlite3_api_routines; + /* ** CAPI3REF: OS Interface Object ** ** An instance of the sqlite3_vfs object defines the interface between ** the SQLite core and the underlying operating system. The "vfs" @@ -2189,22 +2217,32 @@ ** interface independently of the [load_extension()] SQL function. ** The [sqlite3_enable_load_extension()] API enables or disables both the ** C-API [sqlite3_load_extension()] and the SQL function [load_extension()]. ** There should be two additional arguments. ** When the first argument to this interface is 1, then only the C-API is -** enabled and the SQL function remains disabled. If the first argment to +** enabled and the SQL function remains disabled. If the first argument to ** this interface is 0, then both the C-API and the SQL function are disabled. ** If the first argument is -1, then no changes are made to state of either the ** C-API or the SQL function. ** The second parameter is a pointer to an integer into which ** is written 0 or 1 to indicate whether [sqlite3_load_extension()] interface ** is disabled or enabled following this call. The second parameter may ** be a NULL pointer, in which case the new setting is not reported back. ** ** +**
    SQLITE_DBCONFIG_MAINDBNAME
    +**
    ^This option is used to change the name of the "main" database +** schema. ^The sole argument is a pointer to a constant UTF8 string +** which will become the new schema name in place of "main". ^SQLite +** does not make a copy of the new main schema name string, so the application +** must ensure that the argument passed into this DBCONFIG option is unchanged +** until after the database connection closes. +**
    +** ** */ +#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ #define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */ #define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */ @@ -2482,11 +2520,11 @@ ** result in undefined behavior. ** ** A busy handler must not close the database connection ** or [prepared statement] that invoked the busy handler. */ -SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*); +SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*); /* ** CAPI3REF: Set A Busy Timeout ** METHOD: sqlite3 ** @@ -3003,10 +3041,13 @@ #define SQLITE_RECURSIVE 33 /* NULL NULL */ /* ** CAPI3REF: Tracing And Profiling Functions ** METHOD: sqlite3 +** +** These routines are deprecated. Use the [sqlite3_trace_v2()] interface +** instead of the routines described here. ** ** These routines register callback functions that can be used for ** tracing and profiling the execution of SQL statements. ** ** ^The callback function registered by sqlite3_trace() is invoked at @@ -3029,13 +3070,107 @@ ** digits in the time are meaningless. Future versions of SQLite ** might provide greater resolution on the profiler callback. The ** sqlite3_profile() function is considered experimental and is ** subject to change in future versions of SQLite. */ -SQLITE_API void *SQLITE_STDCALL sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*); -SQLITE_API SQLITE_EXPERIMENTAL void *SQLITE_STDCALL sqlite3_profile(sqlite3*, +SQLITE_API SQLITE_DEPRECATED void *SQLITE_STDCALL sqlite3_trace(sqlite3*, + void(*xTrace)(void*,const char*), void*); +SQLITE_API SQLITE_DEPRECATED void *SQLITE_STDCALL sqlite3_profile(sqlite3*, void(*xProfile)(void*,const char*,sqlite3_uint64), void*); + +/* +** CAPI3REF: SQL Trace Event Codes +** KEYWORDS: SQLITE_TRACE +** +** These constants identify classes of events that can be monitored +** using the [sqlite3_trace_v2()] tracing logic. The third argument +** to [sqlite3_trace_v2()] is an OR-ed combination of one or more of +** the following constants. ^The first argument to the trace callback +** is one of the following constants. +** +** New tracing constants may be added in future releases. +** +** ^A trace callback has four arguments: xCallback(T,C,P,X). +** ^The T argument is one of the integer type codes above. +** ^The C argument is a copy of the context pointer passed in as the +** fourth argument to [sqlite3_trace_v2()]. +** The P and X arguments are pointers whose meanings depend on T. +** +**
    +** [[SQLITE_TRACE_STMT]]
    SQLITE_TRACE_STMT
    +**
    ^An SQLITE_TRACE_STMT callback is invoked when a prepared statement +** first begins running and possibly at other times during the +** execution of the prepared statement, such as at the start of each +** trigger subprogram. ^The P argument is a pointer to the +** [prepared statement]. ^The X argument is a pointer to a string which +** is the unexpanded SQL text of the prepared statement or an SQL comment +** that indicates the invocation of a trigger. ^The callback can compute +** the same text that would have been returned by the legacy [sqlite3_trace()] +** interface by using the X argument when X begins with "--" and invoking +** [sqlite3_expanded_sql(P)] otherwise. +** +** [[SQLITE_TRACE_PROFILE]]
    SQLITE_TRACE_PROFILE
    +**
    ^An SQLITE_TRACE_PROFILE callback provides approximately the same +** information as is provided by the [sqlite3_profile()] callback. +** ^The P argument is a pointer to the [prepared statement] and the +** X argument points to a 64-bit integer which is the estimated of +** the number of nanosecond that the prepared statement took to run. +** ^The SQLITE_TRACE_PROFILE callback is invoked when the statement finishes. +** +** [[SQLITE_TRACE_ROW]]
    SQLITE_TRACE_ROW
    +**
    ^An SQLITE_TRACE_ROW callback is invoked whenever a prepared +** statement generates a single row of result. +** ^The P argument is a pointer to the [prepared statement] and the +** X argument is unused. +** +** [[SQLITE_TRACE_CLOSE]]
    SQLITE_TRACE_CLOSE
    +**
    ^An SQLITE_TRACE_CLOSE callback is invoked when a database +** connection closes. +** ^The P argument is a pointer to the [database connection] object +** and the X argument is unused. +**
    +*/ +#define SQLITE_TRACE_STMT 0x01 +#define SQLITE_TRACE_PROFILE 0x02 +#define SQLITE_TRACE_ROW 0x04 +#define SQLITE_TRACE_CLOSE 0x08 + +/* +** CAPI3REF: SQL Trace Hook +** METHOD: sqlite3 +** +** ^The sqlite3_trace_v2(D,M,X,P) interface registers a trace callback +** function X against [database connection] D, using property mask M +** and context pointer P. ^If the X callback is +** NULL or if the M mask is zero, then tracing is disabled. The +** M argument should be the bitwise OR-ed combination of +** zero or more [SQLITE_TRACE] constants. +** +** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides +** (cancels) any prior calls to sqlite3_trace() or sqlite3_trace_v2(). +** +** ^The X callback is invoked whenever any of the events identified by +** mask M occur. ^The integer return value from the callback is currently +** ignored, though this may change in future releases. Callback +** implementations should return zero to ensure future compatibility. +** +** ^A trace callback is invoked with four arguments: callback(T,C,P,X). +** ^The T argument is one of the [SQLITE_TRACE] +** constants to indicate why the callback was invoked. +** ^The C argument is a copy of the context pointer. +** The P and X arguments are pointers whose meanings depend on T. +** +** The sqlite3_trace_v2() interface is intended to replace the legacy +** interfaces [sqlite3_trace()] and [sqlite3_profile()], both of which +** are deprecated. +*/ +SQLITE_API int SQLITE_STDCALL sqlite3_trace_v2( + sqlite3*, + unsigned uMask, + int(*xCallback)(unsigned,void*,void*,void*), + void *pCtx +); /* ** CAPI3REF: Query Progress Callbacks ** METHOD: sqlite3 ** @@ -3651,15 +3786,39 @@ /* ** CAPI3REF: Retrieving Statement SQL ** METHOD: sqlite3_stmt ** -** ^This interface can be used to retrieve a saved copy of the original -** SQL text used to create a [prepared statement] if that statement was -** compiled using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()]. +** ^The sqlite3_sql(P) interface returns a pointer to a copy of the UTF-8 +** SQL text used to create [prepared statement] P if P was +** created by either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()]. +** ^The sqlite3_expanded_sql(P) interface returns a pointer to a UTF-8 +** string containing the SQL text of prepared statement P with +** [bound parameters] expanded. +** +** ^(For example, if a prepared statement is created using the SQL +** text "SELECT $abc,:xyz" and if parameter $abc is bound to integer 2345 +** and parameter :xyz is unbound, then sqlite3_sql() will return +** the original string, "SELECT $abc,:xyz" but sqlite3_expanded_sql() +** will return "SELECT 2345,NULL".)^ +** +** ^The sqlite3_expanded_sql() interface returns NULL if insufficient memory +** is available to hold the result, or if the result would exceed the +** the maximum string length determined by the [SQLITE_LIMIT_LENGTH]. +** +** ^The [SQLITE_TRACE_SIZE_LIMIT] compile-time option limits the size of +** bound parameter expansions. ^The [SQLITE_OMIT_TRACE] compile-time +** option causes sqlite3_expanded_sql() to always return NULL. +** +** ^The string returned by sqlite3_sql(P) is managed by SQLite and is +** automatically freed when the prepared statement is finalized. +** ^The string returned by sqlite3_expanded_sql(P), on the other hand, +** is obtained from [sqlite3_malloc()] and must be free by the application +** by passing it to [sqlite3_free()]. */ SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt); +SQLITE_API char *SQLITE_STDCALL sqlite3_expanded_sql(sqlite3_stmt *pStmt); /* ** CAPI3REF: Determine If An SQL Statement Writes The Database ** METHOD: sqlite3_stmt ** @@ -4813,16 +4972,17 @@ ** NULL if the metadata has been discarded. ** ^After each call to sqlite3_set_auxdata(C,N,P,X) where X is not NULL, ** SQLite will invoke the destructor function X with parameter P exactly ** once, when the metadata is discarded. ** SQLite is free to discard the metadata at any time, including:
      -**
    • when the corresponding function parameter changes, or -**
    • when [sqlite3_reset()] or [sqlite3_finalize()] is called for the -** SQL statement, or -**
    • when sqlite3_set_auxdata() is invoked again on the same parameter, or -**
    • during the original sqlite3_set_auxdata() call when a memory -** allocation error occurs.
    )^ +**
  8. ^(when the corresponding function parameter changes)^, or +**
  9. ^(when [sqlite3_reset()] or [sqlite3_finalize()] is called for the +** SQL statement)^, or +**
  10. ^(when sqlite3_set_auxdata() is invoked again on the same +** parameter)^, or +**
  11. ^(during the original sqlite3_set_auxdata() call when a memory +** allocation error occurs.)^ ** ** Note the last bullet in particular. The destructor X in ** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the ** sqlite3_set_auxdata() interface even returns. Hence sqlite3_set_auxdata() ** should be called near the end of the function implementation and the @@ -5645,11 +5805,11 @@ ** interface returns SQLITE_OK and fills in the non-NULL pointers in ** the final five arguments with appropriate values if the specified ** column exists. ^The sqlite3_table_column_metadata() interface returns ** SQLITE_ERROR and if the specified column does not exist. ** ^If the column-name parameter to sqlite3_table_column_metadata() is a -** NULL pointer, then this routine simply checks for the existance of the +** NULL pointer, then this routine simply checks for the existence of the ** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it ** does not. ** ** ^The column is identified by the second, third and fourth parameters to ** this function. ^(The second parameter is either the name of the database @@ -5779,12 +5939,12 @@ ** to turn extension loading on and call it with onoff==0 to turn ** it back off again. ** ** ^This interface enables or disables both the C-API ** [sqlite3_load_extension()] and the SQL function [load_extension()]. -** Use [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],..) -** to enable or disable only the C-API. +** ^(Use [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],..) +** to enable or disable only the C-API.)^ ** ** Security warning: It is recommended that extension loading ** be disabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method ** rather than this interface, so the [load_extension()] SQL function ** remains disabled. This will prevent SQL injections from giving attackers @@ -5800,11 +5960,11 @@ ** xEntryPoint() is the entry point for a statically linked [SQLite extension] ** that is to be automatically loaded into all new database connections. ** ** ^(Even though the function prototype shows that xEntryPoint() takes ** no arguments and returns void, SQLite invokes xEntryPoint() with three -** arguments and expects and integer result as if the signature of the +** arguments and expects an integer result as if the signature of the ** entry point where as follows: ** **
     **    int xEntryPoint(
     **      sqlite3 *db,
    @@ -5826,11 +5986,11 @@
     ** will be called more than once for each database connection that is opened.
     **
     ** See also: [sqlite3_reset_auto_extension()]
     ** and [sqlite3_cancel_auto_extension()]
     */
    -SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xEntryPoint)(void));
    +SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void(*xEntryPoint)(void));
     
     /*
     ** CAPI3REF: Cancel Automatic Extension Loading
     **
     ** ^The [sqlite3_cancel_auto_extension(X)] interface unregisters the
    @@ -5838,11 +5998,11 @@
     ** [sqlite3_auto_extension(X)].  ^The [sqlite3_cancel_auto_extension(X)]
     ** routine returns 1 if initialization routine X was successfully 
     ** unregistered and it returns 0 if X was not on the list of initialization
     ** routines.
     */
    -SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xEntryPoint)(void));
    +SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void(*xEntryPoint)(void));
     
     /*
     ** CAPI3REF: Reset Automatic Extension Loading
     **
     ** ^This interface disables all automatic extensions previously
    @@ -7014,10 +7174,22 @@
     ** [[SQLITE_DBSTATUS_CACHE_USED]] ^(
    SQLITE_DBSTATUS_CACHE_USED
    **
    This parameter returns the approximate number of bytes of heap ** memory used by all pager caches associated with the database connection.)^ ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0. ** +** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]] +** ^(
    SQLITE_DBSTATUS_CACHE_USED_SHARED
    +**
    This parameter is similar to DBSTATUS_CACHE_USED, except that if a +** pager cache is shared between two or more connections the bytes of heap +** memory used by that pager cache is divided evenly between the attached +** connections.)^ In other words, if none of the pager caches associated +** with the database connection are shared, this request returns the same +** value as DBSTATUS_CACHE_USED. Or, if one or more or the pager caches are +** shared, the value returned by this call will be smaller than that returned +** by DBSTATUS_CACHE_USED. ^The highwater mark associated with +** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0. +** ** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(
    SQLITE_DBSTATUS_SCHEMA_USED
    **
    This parameter returns the approximate number of bytes of heap ** memory used to store the schema for all databases associated ** with the connection - main, temp, and any [ATTACH]-ed databases.)^ ** ^The full amount of memory used by the schemas is reported, even if the @@ -7071,11 +7243,12 @@ #define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL 6 #define SQLITE_DBSTATUS_CACHE_HIT 7 #define SQLITE_DBSTATUS_CACHE_MISS 8 #define SQLITE_DBSTATUS_CACHE_WRITE 9 #define SQLITE_DBSTATUS_DEFERRED_FKS 10 -#define SQLITE_DBSTATUS_MAX 10 /* Largest defined DBSTATUS */ +#define SQLITE_DBSTATUS_CACHE_USED_SHARED 11 +#define SQLITE_DBSTATUS_MAX 11 /* Largest defined DBSTATUS */ /* ** CAPI3REF: Prepared Statement Status ** METHOD: sqlite3_stmt @@ -8227,11 +8400,11 @@ ** tables. ** ** ^The second parameter to the preupdate callback is a pointer to ** the [database connection] that registered the preupdate hook. ** ^The third parameter to the preupdate callback is one of the constants -** [SQLITE_INSERT], [SQLITE_DELETE], or [SQLITE_UPDATE] to indentify the +** [SQLITE_INSERT], [SQLITE_DELETE], or [SQLITE_UPDATE] to identify the ** kind of update operation that is about to occur. ** ^(The fourth parameter to the preupdate callback is the name of the ** database within the database connection that is being modified. This ** will be "main" for the main database or "temp" for TEMP tables or ** the name given after the AS keyword in the [ATTACH] statement for attached @@ -8454,11 +8627,11 @@ #endif #if 0 } /* End of the 'extern "C"' block */ #endif -#endif /* _SQLITE3_H_ */ +#endif /* SQLITE3_H */ /******** Begin file sqlite3rtree.h *********/ /* ** 2010 August 30 ** @@ -10174,11 +10347,11 @@ ** following structure. All structure methods must be defined, setting ** any member of the fts5_tokenizer struct to NULL leads to undefined ** behaviour. The structure methods are expected to function as follows: ** ** xCreate: -** This function is used to allocate and inititalize a tokenizer instance. +** This function is used to allocate and initialize a tokenizer instance. ** A tokenizer instance is required to actually tokenize text. ** ** The first argument passed to this function is a copy of the (void*) ** pointer provided by the application when the fts5_tokenizer object ** was registered with FTS5 (the third argument to xCreateTokenizer()). @@ -10433,11 +10606,10 @@ #if 0 } /* end of the 'extern "C"' block */ #endif #endif /* _FTS5_H */ - /******** End of fts5.h *********/ /************** End of sqlite3.h *********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ @@ -10732,11 +10904,11 @@ ** Make sure that the compiler intrinsics we desire are enabled when ** compiling with an appropriate version of MSVC unless prevented by ** the SQLITE_DISABLE_INTRINSIC define. */ #if !defined(SQLITE_DISABLE_INTRINSIC) -# if defined(_MSC_VER) && _MSC_VER>=1300 +# if defined(_MSC_VER) && _MSC_VER>=1400 # if !defined(_WIN32_WCE) # include # pragma intrinsic(_byteswap_ushort) # pragma intrinsic(_byteswap_ulong) # pragma intrinsic(_ReadWriteBarrier) @@ -11009,12 +11181,12 @@ ** ************************************************************************* ** This is the header file for the generic hash-table implementation ** used in SQLite. */ -#ifndef _SQLITE_HASH_H_ -#define _SQLITE_HASH_H_ +#ifndef SQLITE_HASH_H +#define SQLITE_HASH_H /* Forward declarations of structures. */ typedef struct Hash Hash; typedef struct HashElem HashElem; @@ -11090,11 +11262,11 @@ /* ** Number of entries in a hash table */ /* #define sqliteHashCount(H) ((H)->count) // NOT USED */ -#endif /* _SQLITE_HASH_H_ */ +#endif /* SQLITE_HASH_H */ /************** End of hash.h ************************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /************** Include parse.h in the middle of sqliteInt.h *****************/ /************** Begin file parse.h *******************************************/ @@ -11838,12 +12010,12 @@ ************************************************************************* ** 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. */ -#ifndef _BTREE_H_ -#define _BTREE_H_ +#ifndef SQLITE_BTREE_H +#define SQLITE_BTREE_H /* TODO: This definition is just included so other modules compile. It ** needs to be revisited. */ #define SQLITE_N_BTREE_META 16 @@ -11864,10 +12036,11 @@ ** Forward declarations of structure */ typedef struct Btree Btree; typedef struct BtCursor BtCursor; typedef struct BtShared BtShared; +typedef struct BtreePayload BtreePayload; SQLITE_PRIVATE int sqlite3BtreeOpen( sqlite3_vfs *pVfs, /* VFS to use with this b-tree */ const char *zFilename, /* Name of database file to open */ @@ -12075,23 +12248,47 @@ /* Allowed flags for the 2nd argument to sqlite3BtreeDelete() */ #define BTREE_SAVEPOSITION 0x02 /* Leave cursor pointing at NEXT or PREV */ #define BTREE_AUXDELETE 0x04 /* not the primary delete operation */ -SQLITE_PRIVATE int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey, - const void *pData, int nData, - int nZero, int bias, int seekResult); +/* An instance of the BtreePayload object describes the content of a single +** entry in either an index or table btree. +** +** Index btrees (used for indexes and also WITHOUT ROWID tables) contain +** an arbitrary key and no data. These btrees have pKey,nKey set to their +** key and pData,nData,nZero set to zero. +** +** Table btrees (used for rowid tables) contain an integer rowid used as +** the key and passed in the nKey field. The pKey field is zero. +** pData,nData hold the content of the new entry. nZero extra zero bytes +** are appended to the end of the content when constructing the entry. +** +** This object is used to pass information into sqlite3BtreeInsert(). The +** same information used to be passed as five separate parameters. But placing +** the information into this object helps to keep the interface more +** organized and understandable, and it also helps the resulting code to +** run a little faster by using fewer registers for parameter passing. +*/ +struct BtreePayload { + const void *pKey; /* Key content for indexes. NULL for tables */ + sqlite3_int64 nKey; /* Size of pKey for indexes. PRIMARY KEY for tabs */ + const void *pData; /* Data for tables. NULL for indexes */ + int nData; /* Size of pData. 0 if none. */ + int nZero; /* Extra zero data appended after pData,nData */ +}; + +SQLITE_PRIVATE int sqlite3BtreeInsert(BtCursor*, const BtreePayload *pPayload, + int bias, int seekResult); SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor*, int *pRes); SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor*, int *pRes); SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor*, int *pRes); SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor*); SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor*, int *pRes); -SQLITE_PRIVATE int sqlite3BtreeKeySize(BtCursor*, i64 *pSize); +SQLITE_PRIVATE i64 sqlite3BtreeIntegerKey(BtCursor*); SQLITE_PRIVATE int sqlite3BtreeKey(BtCursor*, u32 offset, u32 amt, void*); -SQLITE_PRIVATE const void *sqlite3BtreeKeyFetch(BtCursor*, u32 *pAmt); -SQLITE_PRIVATE const void *sqlite3BtreeDataFetch(BtCursor*, u32 *pAmt); -SQLITE_PRIVATE int sqlite3BtreeDataSize(BtCursor*, u32 *pSize); +SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt); +SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor*); SQLITE_PRIVATE int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*); SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*); SQLITE_PRIVATE struct Pager *sqlite3BtreePager(Btree*); @@ -12128,15 +12325,17 @@ #ifndef SQLITE_OMIT_SHARED_CACHE SQLITE_PRIVATE void sqlite3BtreeEnter(Btree*); SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3*); SQLITE_PRIVATE int sqlite3BtreeSharable(Btree*); SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor*); +SQLITE_PRIVATE int sqlite3BtreeConnectionCount(Btree*); #else # define sqlite3BtreeEnter(X) # define sqlite3BtreeEnterAll(X) # define sqlite3BtreeSharable(X) 0 # define sqlite3BtreeEnterCursor(X) +# define sqlite3BtreeConnectionCount(X) 1 #endif #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE SQLITE_PRIVATE void sqlite3BtreeLeave(Btree*); SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor*); @@ -12157,11 +12356,11 @@ # define sqlite3BtreeHoldsAllMutexes(X) 1 # define sqlite3SchemaMutexHeld(X,Y,Z) 1 #endif -#endif /* _BTREE_H_ */ +#endif /* SQLITE_BTREE_H */ /************** End of btree.h ***********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /************** Include vdbe.h in the middle of sqliteInt.h ******************/ /************** Begin file vdbe.h ********************************************/ @@ -12180,12 +12379,12 @@ ** ** This header defines the interface to the virtual database engine ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. */ -#ifndef _SQLITE_VDBE_H_ -#define _SQLITE_VDBE_H_ +#ifndef SQLITE_VDBE_H +#define SQLITE_VDBE_H /* #include */ /* ** A single VDBE is an opaque structure named "Vdbe". Only routines ** in the source file sqliteVdbe.c are allowed to see the insides @@ -12366,21 +12565,21 @@ #define OP_Or 27 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */ #define OP_And 28 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */ #define OP_NoConflict 29 /* synopsis: key=r[P3@P4] */ #define OP_NotFound 30 /* synopsis: key=r[P3@P4] */ #define OP_Found 31 /* synopsis: key=r[P3@P4] */ -#define OP_NotExists 32 /* synopsis: intkey=r[P3] */ -#define OP_Last 33 +#define OP_SeekRowid 32 /* synopsis: intkey=r[P3] */ +#define OP_NotExists 33 /* synopsis: intkey=r[P3] */ #define OP_IsNull 34 /* same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */ #define OP_NotNull 35 /* same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */ #define OP_Ne 36 /* same as TK_NE, synopsis: if r[P1]!=r[P3] goto P2 */ #define OP_Eq 37 /* same as TK_EQ, synopsis: if r[P1]==r[P3] goto P2 */ #define OP_Gt 38 /* same as TK_GT, synopsis: if r[P1]>r[P3] goto P2 */ #define OP_Le 39 /* same as TK_LE, synopsis: if r[P1]<=r[P3] goto P2 */ #define OP_Lt 40 /* same as TK_LT, synopsis: if r[P1]=r[P3] goto P2 */ -#define OP_SorterSort 42 +#define OP_Last 42 #define OP_BitAnd 43 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */ #define OP_BitOr 44 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */ #define OP_ShiftLeft 45 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<>r[P1] */ #define OP_Add 47 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */ @@ -12387,118 +12586,119 @@ #define OP_Subtract 48 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */ #define OP_Multiply 49 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */ #define OP_Divide 50 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */ #define OP_Remainder 51 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */ #define OP_Concat 52 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */ -#define OP_Sort 53 +#define OP_SorterSort 53 #define OP_BitNot 54 /* same as TK_BITNOT, synopsis: r[P1]= ~r[P1] */ -#define OP_Rewind 55 -#define OP_IdxLE 56 /* synopsis: key=r[P3@P4] */ -#define OP_IdxGT 57 /* synopsis: key=r[P3@P4] */ -#define OP_IdxLT 58 /* synopsis: key=r[P3@P4] */ -#define OP_IdxGE 59 /* synopsis: key=r[P3@P4] */ -#define OP_RowSetRead 60 /* synopsis: r[P3]=rowset(P1) */ -#define OP_RowSetTest 61 /* synopsis: if r[P3] in rowset(P1) goto P2 */ -#define OP_Program 62 -#define OP_FkIfZero 63 /* synopsis: if fkctr[P1]==0 goto P2 */ -#define OP_IfPos 64 /* synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */ -#define OP_IfNotZero 65 /* synopsis: if r[P1]!=0 then r[P1]-=P3, goto P2 */ -#define OP_DecrJumpZero 66 /* synopsis: if (--r[P1])==0 goto P2 */ -#define OP_IncrVacuum 67 -#define OP_VNext 68 -#define OP_Init 69 /* synopsis: Start at P2 */ -#define OP_Return 70 -#define OP_EndCoroutine 71 -#define OP_HaltIfNull 72 /* synopsis: if r[P3]=null halt */ -#define OP_Halt 73 -#define OP_Integer 74 /* synopsis: r[P2]=P1 */ -#define OP_Int64 75 /* synopsis: r[P2]=P4 */ -#define OP_String 76 /* synopsis: r[P2]='P4' (len=P1) */ -#define OP_Null 77 /* synopsis: r[P2..P3]=NULL */ -#define OP_SoftNull 78 /* synopsis: r[P1]=NULL */ -#define OP_Blob 79 /* synopsis: r[P2]=P4 (len=P1) */ -#define OP_Variable 80 /* synopsis: r[P2]=parameter(P1,P4) */ -#define OP_Move 81 /* synopsis: r[P2@P3]=r[P1@P3] */ -#define OP_Copy 82 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */ -#define OP_SCopy 83 /* synopsis: r[P2]=r[P1] */ -#define OP_IntCopy 84 /* synopsis: r[P2]=r[P1] */ -#define OP_ResultRow 85 /* synopsis: output=r[P1@P2] */ -#define OP_CollSeq 86 -#define OP_Function0 87 /* synopsis: r[P3]=func(r[P2@P5]) */ -#define OP_Function 88 /* synopsis: r[P3]=func(r[P2@P5]) */ -#define OP_AddImm 89 /* synopsis: r[P1]=r[P1]+P2 */ -#define OP_RealAffinity 90 -#define OP_Cast 91 /* synopsis: affinity(r[P1]) */ -#define OP_Permutation 92 -#define OP_Compare 93 /* synopsis: r[P1@P3] <-> r[P2@P3] */ -#define OP_Column 94 /* synopsis: r[P3]=PX */ -#define OP_Affinity 95 /* synopsis: affinity(r[P1@P2]) */ -#define OP_MakeRecord 96 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ +#define OP_Sort 55 +#define OP_Rewind 56 +#define OP_IdxLE 57 /* synopsis: key=r[P3@P4] */ +#define OP_IdxGT 58 /* synopsis: key=r[P3@P4] */ +#define OP_IdxLT 59 /* synopsis: key=r[P3@P4] */ +#define OP_IdxGE 60 /* synopsis: key=r[P3@P4] */ +#define OP_RowSetRead 61 /* synopsis: r[P3]=rowset(P1) */ +#define OP_RowSetTest 62 /* synopsis: if r[P3] in rowset(P1) goto P2 */ +#define OP_Program 63 +#define OP_FkIfZero 64 /* synopsis: if fkctr[P1]==0 goto P2 */ +#define OP_IfPos 65 /* synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */ +#define OP_IfNotZero 66 /* synopsis: if r[P1]!=0 then r[P1]-=P3, goto P2 */ +#define OP_DecrJumpZero 67 /* synopsis: if (--r[P1])==0 goto P2 */ +#define OP_IncrVacuum 68 +#define OP_VNext 69 +#define OP_Init 70 /* synopsis: Start at P2 */ +#define OP_Return 71 +#define OP_EndCoroutine 72 +#define OP_HaltIfNull 73 /* synopsis: if r[P3]=null halt */ +#define OP_Halt 74 +#define OP_Integer 75 /* synopsis: r[P2]=P1 */ +#define OP_Int64 76 /* synopsis: r[P2]=P4 */ +#define OP_String 77 /* synopsis: r[P2]='P4' (len=P1) */ +#define OP_Null 78 /* synopsis: r[P2..P3]=NULL */ +#define OP_SoftNull 79 /* synopsis: r[P1]=NULL */ +#define OP_Blob 80 /* synopsis: r[P2]=P4 (len=P1) */ +#define OP_Variable 81 /* synopsis: r[P2]=parameter(P1,P4) */ +#define OP_Move 82 /* synopsis: r[P2@P3]=r[P1@P3] */ +#define OP_Copy 83 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */ +#define OP_SCopy 84 /* synopsis: r[P2]=r[P1] */ +#define OP_IntCopy 85 /* synopsis: r[P2]=r[P1] */ +#define OP_ResultRow 86 /* synopsis: output=r[P1@P2] */ +#define OP_CollSeq 87 +#define OP_Function0 88 /* synopsis: r[P3]=func(r[P2@P5]) */ +#define OP_Function 89 /* synopsis: r[P3]=func(r[P2@P5]) */ +#define OP_AddImm 90 /* synopsis: r[P1]=r[P1]+P2 */ +#define OP_RealAffinity 91 +#define OP_Cast 92 /* synopsis: affinity(r[P1]) */ +#define OP_Permutation 93 +#define OP_Compare 94 /* synopsis: r[P1@P3] <-> r[P2@P3] */ +#define OP_Column 95 /* synopsis: r[P3]=PX */ +#define OP_Affinity 96 /* synopsis: affinity(r[P1@P2]) */ #define OP_String8 97 /* same as TK_STRING, synopsis: r[P2]='P4' */ -#define OP_Count 98 /* synopsis: r[P2]=count() */ -#define OP_ReadCookie 99 -#define OP_SetCookie 100 -#define OP_ReopenIdx 101 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenRead 102 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenWrite 103 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenAutoindex 104 /* synopsis: nColumn=P2 */ -#define OP_OpenEphemeral 105 /* synopsis: nColumn=P2 */ -#define OP_SorterOpen 106 -#define OP_SequenceTest 107 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */ -#define OP_OpenPseudo 108 /* synopsis: P3 columns in r[P2] */ -#define OP_Close 109 -#define OP_ColumnsUsed 110 -#define OP_Sequence 111 /* synopsis: r[P2]=cursor[P1].ctr++ */ -#define OP_NewRowid 112 /* synopsis: r[P2]=rowid */ -#define OP_Insert 113 /* synopsis: intkey=r[P3] data=r[P2] */ -#define OP_InsertInt 114 /* synopsis: intkey=P3 data=r[P2] */ -#define OP_Delete 115 -#define OP_ResetCount 116 -#define OP_SorterCompare 117 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */ -#define OP_SorterData 118 /* synopsis: r[P2]=data */ -#define OP_RowKey 119 /* synopsis: r[P2]=key */ -#define OP_RowData 120 /* synopsis: r[P2]=data */ -#define OP_Rowid 121 /* synopsis: r[P2]=rowid */ -#define OP_NullRow 122 -#define OP_SorterInsert 123 -#define OP_IdxInsert 124 /* synopsis: key=r[P2] */ -#define OP_IdxDelete 125 /* synopsis: key=r[P2@P3] */ -#define OP_Seek 126 /* synopsis: Move P3 to P1.rowid */ -#define OP_IdxRowid 127 /* synopsis: r[P2]=rowid */ -#define OP_Destroy 128 -#define OP_Clear 129 -#define OP_ResetSorter 130 -#define OP_CreateIndex 131 /* synopsis: r[P2]=root iDb=P1 */ -#define OP_CreateTable 132 /* synopsis: r[P2]=root iDb=P1 */ +#define OP_MakeRecord 98 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ +#define OP_Count 99 /* synopsis: r[P2]=count() */ +#define OP_ReadCookie 100 +#define OP_SetCookie 101 +#define OP_ReopenIdx 102 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenRead 103 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenWrite 104 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenAutoindex 105 /* synopsis: nColumn=P2 */ +#define OP_OpenEphemeral 106 /* synopsis: nColumn=P2 */ +#define OP_SorterOpen 107 +#define OP_SequenceTest 108 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */ +#define OP_OpenPseudo 109 /* synopsis: P3 columns in r[P2] */ +#define OP_Close 110 +#define OP_ColumnsUsed 111 +#define OP_Sequence 112 /* synopsis: r[P2]=cursor[P1].ctr++ */ +#define OP_NewRowid 113 /* synopsis: r[P2]=rowid */ +#define OP_Insert 114 /* synopsis: intkey=r[P3] data=r[P2] */ +#define OP_InsertInt 115 /* synopsis: intkey=P3 data=r[P2] */ +#define OP_Delete 116 +#define OP_ResetCount 117 +#define OP_SorterCompare 118 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */ +#define OP_SorterData 119 /* synopsis: r[P2]=data */ +#define OP_RowKey 120 /* synopsis: r[P2]=key */ +#define OP_RowData 121 /* synopsis: r[P2]=data */ +#define OP_Rowid 122 /* synopsis: r[P2]=rowid */ +#define OP_NullRow 123 +#define OP_SorterInsert 124 +#define OP_IdxInsert 125 /* synopsis: key=r[P2] */ +#define OP_IdxDelete 126 /* synopsis: key=r[P2@P3] */ +#define OP_Seek 127 /* synopsis: Move P3 to P1.rowid */ +#define OP_IdxRowid 128 /* synopsis: r[P2]=rowid */ +#define OP_Destroy 129 +#define OP_Clear 130 +#define OP_ResetSorter 131 +#define OP_CreateIndex 132 /* synopsis: r[P2]=root iDb=P1 */ #define OP_Real 133 /* same as TK_FLOAT, synopsis: r[P2]=P4 */ -#define OP_ParseSchema 134 -#define OP_LoadAnalysis 135 -#define OP_DropTable 136 -#define OP_DropIndex 137 -#define OP_DropTrigger 138 -#define OP_IntegrityCk 139 -#define OP_RowSetAdd 140 /* synopsis: rowset(P1)=r[P2] */ -#define OP_Param 141 -#define OP_FkCounter 142 /* synopsis: fkctr[P1]+=P2 */ -#define OP_MemMax 143 /* synopsis: r[P1]=max(r[P1],r[P2]) */ -#define OP_OffsetLimit 144 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */ -#define OP_AggStep0 145 /* synopsis: accum=r[P3] step(r[P2@P5]) */ -#define OP_AggStep 146 /* synopsis: accum=r[P3] step(r[P2@P5]) */ -#define OP_AggFinal 147 /* synopsis: accum=r[P1] N=P2 */ -#define OP_Expire 148 -#define OP_TableLock 149 /* synopsis: iDb=P1 root=P2 write=P3 */ -#define OP_VBegin 150 -#define OP_VCreate 151 -#define OP_VDestroy 152 -#define OP_VOpen 153 -#define OP_VColumn 154 /* synopsis: r[P3]=vcolumn(P2) */ -#define OP_VRename 155 -#define OP_Pagecount 156 -#define OP_MaxPgcnt 157 -#define OP_CursorHint 158 -#define OP_Noop 159 -#define OP_Explain 160 +#define OP_CreateTable 134 /* synopsis: r[P2]=root iDb=P1 */ +#define OP_ParseSchema 135 +#define OP_LoadAnalysis 136 +#define OP_DropTable 137 +#define OP_DropIndex 138 +#define OP_DropTrigger 139 +#define OP_IntegrityCk 140 +#define OP_RowSetAdd 141 /* synopsis: rowset(P1)=r[P2] */ +#define OP_Param 142 +#define OP_FkCounter 143 /* synopsis: fkctr[P1]+=P2 */ +#define OP_MemMax 144 /* synopsis: r[P1]=max(r[P1],r[P2]) */ +#define OP_OffsetLimit 145 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */ +#define OP_AggStep0 146 /* synopsis: accum=r[P3] step(r[P2@P5]) */ +#define OP_AggStep 147 /* synopsis: accum=r[P3] step(r[P2@P5]) */ +#define OP_AggFinal 148 /* synopsis: accum=r[P1] N=P2 */ +#define OP_Expire 149 +#define OP_TableLock 150 /* synopsis: iDb=P1 root=P2 write=P3 */ +#define OP_VBegin 151 +#define OP_VCreate 152 +#define OP_VDestroy 153 +#define OP_VOpen 154 +#define OP_VColumn 155 /* synopsis: r[P3]=vcolumn(P2) */ +#define OP_VRename 156 +#define OP_Pagecount 157 +#define OP_MaxPgcnt 158 +#define OP_CursorHint 159 +#define OP_Noop 160 +#define OP_Explain 161 /* Properties such as "out2" or "jump" that are specified in ** comments following the "case" for each opcode in the vdbe.c ** are encoded into bitvectors as follows: */ @@ -12511,35 +12711,35 @@ #define OPFLG_INITIALIZER {\ /* 0 */ 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01,\ /* 8 */ 0x00, 0x10, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01,\ /* 16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0x03, 0x03, 0x09,\ /* 24 */ 0x09, 0x09, 0x09, 0x26, 0x26, 0x09, 0x09, 0x09,\ -/* 32 */ 0x09, 0x01, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\ +/* 32 */ 0x09, 0x09, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\ /* 40 */ 0x0b, 0x0b, 0x01, 0x26, 0x26, 0x26, 0x26, 0x26,\ /* 48 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x01, 0x12, 0x01,\ -/* 56 */ 0x01, 0x01, 0x01, 0x01, 0x23, 0x0b, 0x01, 0x01,\ -/* 64 */ 0x03, 0x03, 0x03, 0x01, 0x01, 0x01, 0x02, 0x02,\ -/* 72 */ 0x08, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10,\ -/* 80 */ 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00,\ -/* 88 */ 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,\ -/* 96 */ 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,\ -/* 104 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\ -/* 112 */ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ -/* 120 */ 0x00, 0x10, 0x00, 0x04, 0x04, 0x00, 0x00, 0x10,\ -/* 128 */ 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00,\ -/* 136 */ 0x00, 0x00, 0x00, 0x00, 0x06, 0x10, 0x00, 0x04,\ -/* 144 */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ -/* 152 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\ -/* 160 */ 0x00,} +/* 56 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x23, 0x0b, 0x01,\ +/* 64 */ 0x01, 0x03, 0x03, 0x03, 0x01, 0x01, 0x01, 0x02,\ +/* 72 */ 0x02, 0x08, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00,\ +/* 80 */ 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\ +/* 88 */ 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00,\ +/* 96 */ 0x00, 0x10, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00,\ +/* 104 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 112 */ 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 120 */ 0x00, 0x00, 0x10, 0x00, 0x04, 0x04, 0x00, 0x00,\ +/* 128 */ 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x00,\ +/* 136 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x10, 0x00,\ +/* 144 */ 0x04, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 152 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00,\ +/* 160 */ 0x00, 0x00,} /* The sqlite3P2Values() routine is able to run faster if it knows ** the value of the largest JUMP opcode. The smaller the maximum ** JUMP opcode the better, so the mkopcodeh.tcl script that ** generated this include file strives to group all JUMP opcodes ** together near the beginning of the list. */ -#define SQLITE_MX_JUMP_OPCODE 69 /* Maximum JUMP opcode */ +#define SQLITE_MX_JUMP_OPCODE 70 /* Maximum JUMP opcode */ /************** End of opcodes.h *********************************************/ /************** Continuing where we left off in vdbe.h ***********************/ /* @@ -12682,11 +12882,11 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const char*); #else # define sqlite3VdbeScanStatus(a,b,c,d,e) #endif -#endif +#endif /* SQLITE_VDBE_H */ /************** End of vdbe.h ************************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /************** Include pager.h in the middle of sqliteInt.h *****************/ /************** Begin file pager.h *******************************************/ @@ -12704,12 +12904,12 @@ ** 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. */ -#ifndef _PAGER_H_ -#define _PAGER_H_ +#ifndef SQLITE_PAGER_H +#define SQLITE_PAGER_H /* ** Default maximum size for persistent journal files. A negative ** value means no limit. This value may be overridden using the ** sqlite3PagerJournalSizeLimit() API. See also "PRAGMA journal_size_limit". @@ -12893,11 +13093,11 @@ SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager*); SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*); SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*); SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*); SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *); -SQLITE_PRIVATE void sqlite3PagerClearCache(Pager *); +SQLITE_PRIVATE void sqlite3PagerClearCache(Pager*); SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *); /* Functions used to truncate the database file. */ SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno); @@ -12920,11 +13120,11 @@ #else # define disable_simulated_io_errors() # define enable_simulated_io_errors() #endif -#endif /* _PAGER_H_ */ +#endif /* SQLITE_PAGER_H */ /************** End of pager.h ***********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /************** Include pcache.h in the middle of sqliteInt.h ****************/ /************** Begin file pcache.h ******************************************/ @@ -13158,12 +13358,12 @@ ****************************************************************************** ** ** This file contains pre-processor directives related to operating system ** detection and/or setup. */ -#ifndef _OS_SETUP_H_ -#define _OS_SETUP_H_ +#ifndef SQLITE_OS_SETUP_H +#define SQLITE_OS_SETUP_H /* ** Figure out if we are dealing with Unix, Windows, or some other operating ** system. ** @@ -13199,11 +13399,11 @@ # ifndef SQLITE_OS_WIN # define SQLITE_OS_WIN 0 # endif #endif -#endif /* _OS_SETUP_H_ */ +#endif /* SQLITE_OS_SETUP_H */ /************** End of os_setup.h ********************************************/ /************** Continuing where we left off in os.h *************************/ /* If the SET_FULLSYNC macro is not defined above, then make it @@ -13504,11 +13704,11 @@ ** in the sqlite.aDb[] array. aDb[0] is the main database file and ** aDb[1] is the database file used to hold temporary tables. Additional ** databases may be attached. */ struct Db { - char *zName; /* Name of this database */ + char *zDbSName; /* Name of this database. (schema name, not filename) */ Btree *pBt; /* The B*Tree structure for this database file */ u8 safety_level; /* How aggressive at syncing data to disk */ u8 bSyncSet; /* True if "PRAGMA synchronous=N" has been run */ Schema *pSchema; /* Pointer to database schema (possibly shared) */ }; @@ -13656,10 +13856,19 @@ #else typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*, const char*); #endif +#ifndef SQLITE_OMIT_DEPRECATED +/* This is an extra SQLITE_TRACE macro that indicates "legacy" tracing +** in the style of sqlite3_trace() +*/ +#define SQLITE_TRACE_LEGACY 0x80 +#else +#define SQLITE_TRACE_LEGACY 0 +#endif /* SQLITE_OMIT_DEPRECATED */ + /* ** Each database connection is an instance of the following structure. */ struct sqlite3 { @@ -13685,10 +13894,11 @@ u8 dfltLockMode; /* Default locking-mode for attached dbs */ signed char nextAutovac; /* Autovac setting after VACUUM if >=0 */ u8 suppressErr; /* Do not issue error messages if true */ u8 vtabOnConflict; /* Value to return for s3_vtab_on_conflict() */ u8 isTransactionSavepoint; /* True if the outermost savepoint is a TS */ + u8 mTrace; /* zero or more SQLITE_TRACE flags */ int nextPagesize; /* Pagesize after VACUUM if >0 */ u32 magic; /* Magic number for detect library misuse */ int nChange; /* Value returned by sqlite3_changes() */ int nTotalChange; /* Value returned by sqlite3_total_changes() */ int aLimit[SQLITE_N_LIMIT]; /* Limits */ @@ -13705,11 +13915,11 @@ int nVdbeWrite; /* Number of active VDBEs that read and write */ int nVdbeExec; /* Number of nested calls to VdbeExec() */ int nVDestroy; /* Number of active OP_VDestroy operations */ int nExtension; /* Number of loaded extensions */ void **aExtension; /* Array of shared library handles */ - void (*xTrace)(void*,const char*); /* Trace function */ + int (*xTrace)(u32,void*,void*,void*); /* Trace function */ void *pTraceArg; /* Argument to the trace function */ void (*xProfile)(void*,const char*,u64); /* Profiling function */ void *pProfileArg; /* Argument to profile function */ void *pCommitArg; /* Argument to xCommitCallback() */ int (*xCommitCallback)(void*); /* Invoked at every commit. */ @@ -14900,11 +15110,11 @@ Select *pSelect; /* A SELECT statement used in place of a table name */ int addrFillSub; /* Address of subroutine to manifest a subquery */ int regReturn; /* Register holding return address of addrFillSub */ int regResult; /* Registers holding results of a co-routine */ struct { - u8 jointype; /* Type of join between this able and the previous */ + u8 jointype; /* Type of join between this table and the previous */ unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */ unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */ unsigned isTabFunc :1; /* True if table-valued-function syntax */ unsigned isCorrelated :1; /* True if sub-query is correlated */ unsigned viaCoroutine :1; /* Implemented as a co-routine */ @@ -14946,23 +15156,24 @@ */ #define WHERE_ORDERBY_NORMAL 0x0000 /* No-op */ #define WHERE_ORDERBY_MIN 0x0001 /* ORDER BY processing for min() func */ #define WHERE_ORDERBY_MAX 0x0002 /* ORDER BY processing for max() func */ #define WHERE_ONEPASS_DESIRED 0x0004 /* Want to do one-pass UPDATE/DELETE */ -#define WHERE_DUPLICATES_OK 0x0008 /* Ok to return a row more than once */ -#define WHERE_OMIT_OPEN_CLOSE 0x0010 /* Table cursors are already open */ -#define WHERE_FORCE_TABLE 0x0020 /* Do not use an index-only search */ -#define WHERE_ONETABLE_ONLY 0x0040 /* Only code the 1st table in pTabList */ -#define WHERE_NO_AUTOINDEX 0x0080 /* Disallow automatic indexes */ -#define WHERE_GROUPBY 0x0100 /* pOrderBy is really a GROUP BY */ -#define WHERE_DISTINCTBY 0x0200 /* pOrderby is really a DISTINCT clause */ -#define WHERE_WANT_DISTINCT 0x0400 /* All output needs to be distinct */ -#define WHERE_SORTBYGROUP 0x0800 /* Support sqlite3WhereIsSorted() */ -#define WHERE_REOPEN_IDX 0x1000 /* Try to use OP_ReopenIdx */ -#define WHERE_ONEPASS_MULTIROW 0x2000 /* ONEPASS is ok with multiple rows */ -#define WHERE_USE_LIMIT 0x4000 /* There is a constant LIMIT clause */ -#define WHERE_SEEK_TABLE 0x8000 /* Do not defer seeks on main table */ +#define WHERE_ONEPASS_MULTIROW 0x0008 /* ONEPASS is ok with multiple rows */ +#define WHERE_DUPLICATES_OK 0x0010 /* Ok to return a row more than once */ +#define WHERE_OR_SUBCLAUSE 0x0020 /* Processing a sub-WHERE as part of + ** the OR optimization */ +#define WHERE_GROUPBY 0x0040 /* pOrderBy is really a GROUP BY */ +#define WHERE_DISTINCTBY 0x0080 /* pOrderby is really a DISTINCT clause */ +#define WHERE_WANT_DISTINCT 0x0100 /* All output needs to be distinct */ +#define WHERE_SORTBYGROUP 0x0200 /* Support sqlite3WhereIsSorted() */ +#define WHERE_SEEK_TABLE 0x0400 /* Do not defer seeks on main table */ +#define WHERE_ORDERBY_LIMIT 0x0800 /* ORDERBY+LIMIT on the inner loop */ + /* 0x1000 not currently used */ + /* 0x2000 not currently used */ +#define WHERE_USE_LIMIT 0x4000 /* Use the LIMIT in cost estimates */ + /* 0x8000 not currently used */ /* Allowed return values from sqlite3WhereIsDistinct() */ #define WHERE_DISTINCT_NOOP 0 /* DISTINCT keyword not used */ #define WHERE_DISTINCT_UNIQUE 1 /* No duplicates */ @@ -15661,10 +15872,11 @@ int iCur; /* A cursor number */ SrcList *pSrcList; /* FROM clause */ struct SrcCount *pSrcCount; /* Counting column references */ struct CCurHint *pCCurHint; /* Used by codeCursorHint() */ int *aiCol; /* array of column indexes */ + struct IdxCover *pIdxCover; /* Check for index coverage */ } u; }; /* Forward declarations */ SQLITE_PRIVATE int sqlite3WalkExpr(Walker*, Expr*); @@ -15844,15 +16056,19 @@ # define sqlite3StackAllocRaw(D,N) sqlite3DbMallocRaw(D,N) # define sqlite3StackAllocZero(D,N) sqlite3DbMallocZero(D,N) # define sqlite3StackFree(D,P) sqlite3DbFree(D,P) #endif -#ifdef SQLITE_ENABLE_MEMSYS3 -SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void); -#endif +/* Do not allow both MEMSYS5 and MEMSYS3 to be defined together. If they +** are, disable MEMSYS3 +*/ #ifdef SQLITE_ENABLE_MEMSYS5 SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys5(void); +#undef SQLITE_ENABLE_MEMSYS3 +#endif +#ifdef SQLITE_ENABLE_MEMSYS3 +SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void); #endif #ifndef SQLITE_MUTEX_OMIT SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void); @@ -16031,12 +16247,12 @@ SQLITE_PRIVATE void sqlite3SrcListShiftJoinType(SrcList*); SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse*, SrcList*); SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3*, IdList*); SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3*, SrcList*); SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(sqlite3*,i16,int,char**); -SQLITE_PRIVATE Index *sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*, - Expr*, int, int); +SQLITE_PRIVATE void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*, + Expr*, int, int, u8); SQLITE_PRIVATE void sqlite3DropIndex(Parse*, SrcList*, int); SQLITE_PRIVATE int sqlite3Select(Parse*, Select*, SelectDest*); SQLITE_PRIVATE Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*, Expr*,ExprList*,u32,Expr*,Expr*); SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3*, Select*); @@ -16051,10 +16267,11 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int); SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo*); SQLITE_PRIVATE LogEst sqlite3WhereOutputRowCount(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereIsDistinct(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo*); +SQLITE_PRIVATE int sqlite3WhereOrderedInnerLoop(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereIsSorted(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereContinueLabel(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereOkOnePass(WhereInfo*, int*); #define ONEPASS_OFF 0 /* Use of ONEPASS not allowed */ @@ -16084,23 +16301,26 @@ #define SQLITE_ECEL_REF 0x04 /* Use ExprList.u.x.iOrderByCol */ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse*, Expr*, int, int); SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse*, Expr*, int, int); SQLITE_PRIVATE void sqlite3ExprIfFalseDup(Parse*, Expr*, int, int); SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3*,const char*, const char*); -SQLITE_PRIVATE Table *sqlite3LocateTable(Parse*,int isView,const char*, const char*); -SQLITE_PRIVATE Table *sqlite3LocateTableItem(Parse*,int isView,struct SrcList_item *); +#define LOCATE_VIEW 0x01 +#define LOCATE_NOERR 0x02 +SQLITE_PRIVATE Table *sqlite3LocateTable(Parse*,u32 flags,const char*, const char*); +SQLITE_PRIVATE Table *sqlite3LocateTableItem(Parse*,u32 flags,struct SrcList_item *); SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3*,const char*, const char*); SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*); SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*); -SQLITE_PRIVATE void sqlite3Vacuum(Parse*); -SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*); +SQLITE_PRIVATE void sqlite3Vacuum(Parse*,Token*); +SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*, int); SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3*, Token*); SQLITE_PRIVATE int sqlite3ExprCompare(Expr*, Expr*, int); SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList*, ExprList*, int); SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Expr*, Expr*, int); SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*); SQLITE_PRIVATE void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); +SQLITE_PRIVATE int sqlite3ExprCoveredByIndex(Expr*, int iCur, Index *pIdx); SQLITE_PRIVATE int sqlite3FunctionUsesThisSrc(Expr*, SrcList*); SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse*); #ifndef SQLITE_OMIT_BUILTIN_TEST SQLITE_PRIVATE void sqlite3PrngSaveState(void); SQLITE_PRIVATE void sqlite3PrngRestoreState(void); @@ -16648,11 +16868,11 @@ #if defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST) SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3*); #endif -#endif /* _SQLITEINT_H_ */ +#endif /* SQLITEINT_H */ /************** End of sqliteInt.h *******************************************/ /************** Begin file global.c ******************************************/ /* ** 2008 June 13 @@ -16983,10 +17203,19 @@ "CASE_SENSITIVE_LIKE", #endif #if SQLITE_CHECK_PAGES "CHECK_PAGES", #endif +#if defined(__clang__) && defined(__clang_major__) + "COMPILER=clang-" CTIMEOPT_VAL(__clang_major__) "." + CTIMEOPT_VAL(__clang_minor__) "." + CTIMEOPT_VAL(__clang_patchlevel__), +#elif defined(_MSC_VER) + "COMPILER=msvc-" CTIMEOPT_VAL(_MSC_VER), +#elif defined(__GNUC__) && defined(__VERSION__) + "COMPILER=gcc-" __VERSION__, +#endif #if SQLITE_COVERAGE_TEST "COVERAGE_TEST", #endif #if SQLITE_DEBUG "DEBUG", @@ -17002,11 +17231,11 @@ #endif #if SQLITE_DISABLE_LFS "DISABLE_LFS", #endif #if SQLITE_ENABLE_8_3_NAMES - "ENABLE_8_3_NAMES", + "ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES), #endif #if SQLITE_ENABLE_API_ARMOR "ENABLE_API_ARMOR", #endif #if SQLITE_ENABLE_ATOMIC_WRITE @@ -17416,12 +17645,12 @@ ** VDBE. This information used to all be at the top of the single ** source code file "vdbe.c". When that file became too big (over ** 6000 lines long) it was split up into several smaller files and ** this header information was factored out. */ -#ifndef _VDBEINT_H_ -#define _VDBEINT_H_ +#ifndef SQLITE_VDBEINT_H +#define SQLITE_VDBEINT_H /* ** The maximum number of times that a statement will try to reparse ** itself before giving up and returning SQLITE_SCHEMA. */ @@ -17959,11 +18188,11 @@ #else #define sqlite3VdbeMemExpandBlob(x) SQLITE_OK #define ExpandBlob(P) SQLITE_OK #endif -#endif /* !defined(_VDBEINT_H_) */ +#endif /* !defined(SQLITE_VDBEINT_H) */ /************** End of vdbeInt.h *********************************************/ /************** Continuing where we left off in status.c *********************/ /* @@ -18106,11 +18335,11 @@ sqlite3_mutex_leave(pMutex); (void)pMutex; /* Prevent warning when SQLITE_THREADSAFE=0 */ return SQLITE_OK; } SQLITE_API int SQLITE_STDCALL sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){ - sqlite3_int64 iCur, iHwtr; + sqlite3_int64 iCur = 0, iHwtr = 0; int rc; #ifdef SQLITE_ENABLE_API_ARMOR if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT; #endif rc = sqlite3_status64(op, &iCur, &iHwtr, resetFlag); @@ -18167,19 +18396,24 @@ /* ** Return an approximation for the amount of memory currently used ** by all pagers associated with the given database connection. The ** highwater mark is meaningless and is returned as zero. */ + case SQLITE_DBSTATUS_CACHE_USED_SHARED: case SQLITE_DBSTATUS_CACHE_USED: { int totalUsed = 0; int i; sqlite3BtreeEnterAll(db); for(i=0; inDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ Pager *pPager = sqlite3BtreePager(pBt); - totalUsed += sqlite3PagerMemUsed(pPager); + int nByte = sqlite3PagerMemUsed(pPager); + if( op==SQLITE_DBSTATUS_CACHE_USED_SHARED ){ + nByte = nByte / sqlite3BtreeConnectionCount(pBt); + } + totalUsed += nByte; } } sqlite3BtreeLeaveAll(db); *pCurrent = totalUsed; *pHighwater = 0; @@ -19409,11 +19643,10 @@ int argc, sqlite3_value **argv ){ time_t t; char *zFormat = (char *)sqlite3_user_data(context); - sqlite3 *db; sqlite3_int64 iT; struct tm *pTm; struct tm sNow; char zBuf[20]; @@ -19478,13 +19711,11 @@ ****************************************************************************** ** ** This file contains OS interface code that is common to all ** architectures. */ -#define _SQLITE_OS_C_ 1 /* #include "sqliteInt.h" */ -#undef _SQLITE_OS_C_ /* ** 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. @@ -22993,12 +23224,12 @@ ****************************************************************************** ** ** This file contains inline asm code for retrieving "high-performance" ** counters for x86 class CPUs. */ -#ifndef _HWTIME_H_ -#define _HWTIME_H_ +#ifndef SQLITE_HWTIME_H +#define SQLITE_HWTIME_H /* ** The following routine only works on pentium-class (or newer) processors. ** It uses the RDTSC opcode to read the cycle count value out of the ** processor and returns that value. This can be used for high-res @@ -23062,11 +23293,11 @@ */ SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } #endif -#endif /* !defined(_HWTIME_H_) */ +#endif /* !defined(SQLITE_HWTIME_H) */ /************** End of hwtime.h **********************************************/ /************** Continuing where we left off in os_common.h ******************/ static sqlite_uint64 g_start; @@ -23152,12 +23383,12 @@ ** ****************************************************************************** ** ** This file contains code that is specific to Windows. */ -#ifndef _OS_WIN_H_ -#define _OS_WIN_H_ +#ifndef SQLITE_OS_WIN_H +#define SQLITE_OS_WIN_H /* ** Include the primary Windows SDK header file. */ #include "windows.h" @@ -23225,11 +23456,11 @@ # define SQLITE_OS_WIN_THREADS 1 #else # define SQLITE_OS_WIN_THREADS 0 #endif -#endif /* _OS_WIN_H_ */ +#endif /* SQLITE_OS_WIN_H */ /************** End of os_win.h **********************************************/ /************** Continuing where we left off in mutex_w32.c ******************/ #endif @@ -25976,10 +26207,16 @@ } sqlite3TreeViewLine(pView, "RAISE %s(%Q)", zType, pExpr->u.zToken); break; } #endif + case TK_MATCH: { + sqlite3TreeViewLine(pView, "MATCH {%d:%d}%s", + pExpr->iTable, pExpr->iColumn, zFlgs); + sqlite3TreeViewExpr(pView, pExpr->pRight, 0); + break; + } default: { sqlite3TreeViewLine(pView, "op=%d", pExpr->op); break; } } @@ -28759,21 +28996,21 @@ /* 27 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"), /* 28 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"), /* 29 */ "NoConflict" OpHelp("key=r[P3@P4]"), /* 30 */ "NotFound" OpHelp("key=r[P3@P4]"), /* 31 */ "Found" OpHelp("key=r[P3@P4]"), - /* 32 */ "NotExists" OpHelp("intkey=r[P3]"), - /* 33 */ "Last" OpHelp(""), + /* 32 */ "SeekRowid" OpHelp("intkey=r[P3]"), + /* 33 */ "NotExists" OpHelp("intkey=r[P3]"), /* 34 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"), /* 35 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"), /* 36 */ "Ne" OpHelp("if r[P1]!=r[P3] goto P2"), /* 37 */ "Eq" OpHelp("if r[P1]==r[P3] goto P2"), /* 38 */ "Gt" OpHelp("if r[P1]>r[P3] goto P2"), /* 39 */ "Le" OpHelp("if r[P1]<=r[P3] goto P2"), /* 40 */ "Lt" OpHelp("if r[P1]=r[P3] goto P2"), - /* 42 */ "SorterSort" OpHelp(""), + /* 42 */ "Last" OpHelp(""), /* 43 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"), /* 44 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"), /* 45 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<>r[P1]"), /* 47 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"), @@ -28780,118 +29017,119 @@ /* 48 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"), /* 49 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"), /* 50 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"), /* 51 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"), /* 52 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"), - /* 53 */ "Sort" OpHelp(""), + /* 53 */ "SorterSort" OpHelp(""), /* 54 */ "BitNot" OpHelp("r[P1]= ~r[P1]"), - /* 55 */ "Rewind" OpHelp(""), - /* 56 */ "IdxLE" OpHelp("key=r[P3@P4]"), - /* 57 */ "IdxGT" OpHelp("key=r[P3@P4]"), - /* 58 */ "IdxLT" OpHelp("key=r[P3@P4]"), - /* 59 */ "IdxGE" OpHelp("key=r[P3@P4]"), - /* 60 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"), - /* 61 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"), - /* 62 */ "Program" OpHelp(""), - /* 63 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), - /* 64 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"), - /* 65 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]-=P3, goto P2"), - /* 66 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"), - /* 67 */ "IncrVacuum" OpHelp(""), - /* 68 */ "VNext" OpHelp(""), - /* 69 */ "Init" OpHelp("Start at P2"), - /* 70 */ "Return" OpHelp(""), - /* 71 */ "EndCoroutine" OpHelp(""), - /* 72 */ "HaltIfNull" OpHelp("if r[P3]=null halt"), - /* 73 */ "Halt" OpHelp(""), - /* 74 */ "Integer" OpHelp("r[P2]=P1"), - /* 75 */ "Int64" OpHelp("r[P2]=P4"), - /* 76 */ "String" OpHelp("r[P2]='P4' (len=P1)"), - /* 77 */ "Null" OpHelp("r[P2..P3]=NULL"), - /* 78 */ "SoftNull" OpHelp("r[P1]=NULL"), - /* 79 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"), - /* 80 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"), - /* 81 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"), - /* 82 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"), - /* 83 */ "SCopy" OpHelp("r[P2]=r[P1]"), - /* 84 */ "IntCopy" OpHelp("r[P2]=r[P1]"), - /* 85 */ "ResultRow" OpHelp("output=r[P1@P2]"), - /* 86 */ "CollSeq" OpHelp(""), - /* 87 */ "Function0" OpHelp("r[P3]=func(r[P2@P5])"), - /* 88 */ "Function" OpHelp("r[P3]=func(r[P2@P5])"), - /* 89 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"), - /* 90 */ "RealAffinity" OpHelp(""), - /* 91 */ "Cast" OpHelp("affinity(r[P1])"), - /* 92 */ "Permutation" OpHelp(""), - /* 93 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), - /* 94 */ "Column" OpHelp("r[P3]=PX"), - /* 95 */ "Affinity" OpHelp("affinity(r[P1@P2])"), - /* 96 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), + /* 55 */ "Sort" OpHelp(""), + /* 56 */ "Rewind" OpHelp(""), + /* 57 */ "IdxLE" OpHelp("key=r[P3@P4]"), + /* 58 */ "IdxGT" OpHelp("key=r[P3@P4]"), + /* 59 */ "IdxLT" OpHelp("key=r[P3@P4]"), + /* 60 */ "IdxGE" OpHelp("key=r[P3@P4]"), + /* 61 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"), + /* 62 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"), + /* 63 */ "Program" OpHelp(""), + /* 64 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), + /* 65 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"), + /* 66 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]-=P3, goto P2"), + /* 67 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"), + /* 68 */ "IncrVacuum" OpHelp(""), + /* 69 */ "VNext" OpHelp(""), + /* 70 */ "Init" OpHelp("Start at P2"), + /* 71 */ "Return" OpHelp(""), + /* 72 */ "EndCoroutine" OpHelp(""), + /* 73 */ "HaltIfNull" OpHelp("if r[P3]=null halt"), + /* 74 */ "Halt" OpHelp(""), + /* 75 */ "Integer" OpHelp("r[P2]=P1"), + /* 76 */ "Int64" OpHelp("r[P2]=P4"), + /* 77 */ "String" OpHelp("r[P2]='P4' (len=P1)"), + /* 78 */ "Null" OpHelp("r[P2..P3]=NULL"), + /* 79 */ "SoftNull" OpHelp("r[P1]=NULL"), + /* 80 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"), + /* 81 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"), + /* 82 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"), + /* 83 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"), + /* 84 */ "SCopy" OpHelp("r[P2]=r[P1]"), + /* 85 */ "IntCopy" OpHelp("r[P2]=r[P1]"), + /* 86 */ "ResultRow" OpHelp("output=r[P1@P2]"), + /* 87 */ "CollSeq" OpHelp(""), + /* 88 */ "Function0" OpHelp("r[P3]=func(r[P2@P5])"), + /* 89 */ "Function" OpHelp("r[P3]=func(r[P2@P5])"), + /* 90 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"), + /* 91 */ "RealAffinity" OpHelp(""), + /* 92 */ "Cast" OpHelp("affinity(r[P1])"), + /* 93 */ "Permutation" OpHelp(""), + /* 94 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), + /* 95 */ "Column" OpHelp("r[P3]=PX"), + /* 96 */ "Affinity" OpHelp("affinity(r[P1@P2])"), /* 97 */ "String8" OpHelp("r[P2]='P4'"), - /* 98 */ "Count" OpHelp("r[P2]=count()"), - /* 99 */ "ReadCookie" OpHelp(""), - /* 100 */ "SetCookie" OpHelp(""), - /* 101 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), - /* 102 */ "OpenRead" OpHelp("root=P2 iDb=P3"), - /* 103 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), - /* 104 */ "OpenAutoindex" OpHelp("nColumn=P2"), - /* 105 */ "OpenEphemeral" OpHelp("nColumn=P2"), - /* 106 */ "SorterOpen" OpHelp(""), - /* 107 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"), - /* 108 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), - /* 109 */ "Close" OpHelp(""), - /* 110 */ "ColumnsUsed" OpHelp(""), - /* 111 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"), - /* 112 */ "NewRowid" OpHelp("r[P2]=rowid"), - /* 113 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"), - /* 114 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"), - /* 115 */ "Delete" OpHelp(""), - /* 116 */ "ResetCount" OpHelp(""), - /* 117 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"), - /* 118 */ "SorterData" OpHelp("r[P2]=data"), - /* 119 */ "RowKey" OpHelp("r[P2]=key"), - /* 120 */ "RowData" OpHelp("r[P2]=data"), - /* 121 */ "Rowid" OpHelp("r[P2]=rowid"), - /* 122 */ "NullRow" OpHelp(""), - /* 123 */ "SorterInsert" OpHelp(""), - /* 124 */ "IdxInsert" OpHelp("key=r[P2]"), - /* 125 */ "IdxDelete" OpHelp("key=r[P2@P3]"), - /* 126 */ "Seek" OpHelp("Move P3 to P1.rowid"), - /* 127 */ "IdxRowid" OpHelp("r[P2]=rowid"), - /* 128 */ "Destroy" OpHelp(""), - /* 129 */ "Clear" OpHelp(""), - /* 130 */ "ResetSorter" OpHelp(""), - /* 131 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"), - /* 132 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"), + /* 98 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), + /* 99 */ "Count" OpHelp("r[P2]=count()"), + /* 100 */ "ReadCookie" OpHelp(""), + /* 101 */ "SetCookie" OpHelp(""), + /* 102 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), + /* 103 */ "OpenRead" OpHelp("root=P2 iDb=P3"), + /* 104 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), + /* 105 */ "OpenAutoindex" OpHelp("nColumn=P2"), + /* 106 */ "OpenEphemeral" OpHelp("nColumn=P2"), + /* 107 */ "SorterOpen" OpHelp(""), + /* 108 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"), + /* 109 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), + /* 110 */ "Close" OpHelp(""), + /* 111 */ "ColumnsUsed" OpHelp(""), + /* 112 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"), + /* 113 */ "NewRowid" OpHelp("r[P2]=rowid"), + /* 114 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"), + /* 115 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"), + /* 116 */ "Delete" OpHelp(""), + /* 117 */ "ResetCount" OpHelp(""), + /* 118 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"), + /* 119 */ "SorterData" OpHelp("r[P2]=data"), + /* 120 */ "RowKey" OpHelp("r[P2]=key"), + /* 121 */ "RowData" OpHelp("r[P2]=data"), + /* 122 */ "Rowid" OpHelp("r[P2]=rowid"), + /* 123 */ "NullRow" OpHelp(""), + /* 124 */ "SorterInsert" OpHelp(""), + /* 125 */ "IdxInsert" OpHelp("key=r[P2]"), + /* 126 */ "IdxDelete" OpHelp("key=r[P2@P3]"), + /* 127 */ "Seek" OpHelp("Move P3 to P1.rowid"), + /* 128 */ "IdxRowid" OpHelp("r[P2]=rowid"), + /* 129 */ "Destroy" OpHelp(""), + /* 130 */ "Clear" OpHelp(""), + /* 131 */ "ResetSorter" OpHelp(""), + /* 132 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"), /* 133 */ "Real" OpHelp("r[P2]=P4"), - /* 134 */ "ParseSchema" OpHelp(""), - /* 135 */ "LoadAnalysis" OpHelp(""), - /* 136 */ "DropTable" OpHelp(""), - /* 137 */ "DropIndex" OpHelp(""), - /* 138 */ "DropTrigger" OpHelp(""), - /* 139 */ "IntegrityCk" OpHelp(""), - /* 140 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"), - /* 141 */ "Param" OpHelp(""), - /* 142 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), - /* 143 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), - /* 144 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"), - /* 145 */ "AggStep0" OpHelp("accum=r[P3] step(r[P2@P5])"), - /* 146 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), - /* 147 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), - /* 148 */ "Expire" OpHelp(""), - /* 149 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), - /* 150 */ "VBegin" OpHelp(""), - /* 151 */ "VCreate" OpHelp(""), - /* 152 */ "VDestroy" OpHelp(""), - /* 153 */ "VOpen" OpHelp(""), - /* 154 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), - /* 155 */ "VRename" OpHelp(""), - /* 156 */ "Pagecount" OpHelp(""), - /* 157 */ "MaxPgcnt" OpHelp(""), - /* 158 */ "CursorHint" OpHelp(""), - /* 159 */ "Noop" OpHelp(""), - /* 160 */ "Explain" OpHelp(""), + /* 134 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"), + /* 135 */ "ParseSchema" OpHelp(""), + /* 136 */ "LoadAnalysis" OpHelp(""), + /* 137 */ "DropTable" OpHelp(""), + /* 138 */ "DropIndex" OpHelp(""), + /* 139 */ "DropTrigger" OpHelp(""), + /* 140 */ "IntegrityCk" OpHelp(""), + /* 141 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"), + /* 142 */ "Param" OpHelp(""), + /* 143 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), + /* 144 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), + /* 145 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"), + /* 146 */ "AggStep0" OpHelp("accum=r[P3] step(r[P2@P5])"), + /* 147 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), + /* 148 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), + /* 149 */ "Expire" OpHelp(""), + /* 150 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), + /* 151 */ "VBegin" OpHelp(""), + /* 152 */ "VCreate" OpHelp(""), + /* 153 */ "VDestroy" OpHelp(""), + /* 154 */ "VOpen" OpHelp(""), + /* 155 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), + /* 156 */ "VRename" OpHelp(""), + /* 157 */ "Pagecount" OpHelp(""), + /* 158 */ "MaxPgcnt" OpHelp(""), + /* 159 */ "CursorHint" OpHelp(""), + /* 160 */ "Noop" OpHelp(""), + /* 161 */ "Explain" OpHelp(""), }; return azName[i]; } #endif @@ -29237,12 +29475,12 @@ ****************************************************************************** ** ** This file contains inline asm code for retrieving "high-performance" ** counters for x86 class CPUs. */ -#ifndef _HWTIME_H_ -#define _HWTIME_H_ +#ifndef SQLITE_HWTIME_H +#define SQLITE_HWTIME_H /* ** The following routine only works on pentium-class (or newer) processors. ** It uses the RDTSC opcode to read the cycle count value out of the ** processor and returns that value. This can be used for high-res @@ -29306,11 +29544,11 @@ */ SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } #endif -#endif /* !defined(_HWTIME_H_) */ +#endif /* !defined(SQLITE_HWTIME_H) */ /************** End of hwtime.h **********************************************/ /************** Continuing where we left off in os_common.h ******************/ static sqlite_uint64 g_start; @@ -34623,10 +34861,31 @@ unixLeaveMutex(); } #endif /* if !OS_VXWORKS */ return pUnused; } + +/* +** Find the mode, uid and gid of file zFile. +*/ +static int getFileMode( + const char *zFile, /* File name */ + mode_t *pMode, /* OUT: Permissions of zFile */ + uid_t *pUid, /* OUT: uid of zFile. */ + gid_t *pGid /* OUT: gid of zFile. */ +){ + struct stat sStat; /* Output of stat() on database file */ + int rc = SQLITE_OK; + if( 0==osStat(zFile, &sStat) ){ + *pMode = sStat.st_mode & 0777; + *pUid = sStat.st_uid; + *pGid = sStat.st_gid; + }else{ + rc = SQLITE_IOERR_FSTAT; + } + return rc; +} /* ** This function is called by unixOpen() to determine the unix permissions ** to create new files with. If no error occurs, then SQLITE_OK is returned ** and a value suitable for passing as the third argument to open(2) is @@ -34659,11 +34918,10 @@ *pUid = 0; *pGid = 0; if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){ char zDb[MAX_PATHNAME+1]; /* Database file path */ int nDb; /* Number of valid bytes in zDb */ - struct stat sStat; /* Output of stat() on database file */ /* zPath is a path to a WAL or journal file. The following block derives ** the path to the associated database file from zPath. This block handles ** the following naming conventions: ** @@ -34690,19 +34948,22 @@ nDb--; } memcpy(zDb, zPath, nDb); zDb[nDb] = '\0'; - if( 0==osStat(zDb, &sStat) ){ - *pMode = sStat.st_mode & 0777; - *pUid = sStat.st_uid; - *pGid = sStat.st_gid; - }else{ - rc = SQLITE_IOERR_FSTAT; - } + rc = getFileMode(zDb, pMode, pUid, pGid); }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){ *pMode = 0600; + }else if( flags & SQLITE_OPEN_URI ){ + /* If this is a main database file and the file was opened using a URI + ** filename, check for the "modeof" parameter. If present, interpret + ** its value as a filename and try to copy the mode, uid and gid from + ** that file. */ + const char *z = sqlite3_uri_parameter(zPath, "modeof"); + if( z ){ + rc = getFileMode(z, pMode, pUid, pGid); + } } return rc; } /* @@ -36766,12 +37027,12 @@ ****************************************************************************** ** ** This file contains inline asm code for retrieving "high-performance" ** counters for x86 class CPUs. */ -#ifndef _HWTIME_H_ -#define _HWTIME_H_ +#ifndef SQLITE_HWTIME_H +#define SQLITE_HWTIME_H /* ** The following routine only works on pentium-class (or newer) processors. ** It uses the RDTSC opcode to read the cycle count value out of the ** processor and returns that value. This can be used for high-res @@ -36835,11 +37096,11 @@ */ SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } #endif -#endif /* !defined(_HWTIME_H_) */ +#endif /* !defined(SQLITE_HWTIME_H) */ /************** End of hwtime.h **********************************************/ /************** Continuing where we left off in os_common.h ******************/ static sqlite_uint64 g_start; @@ -37175,10 +37436,21 @@ sqlite3_int64 mmapSize; /* Usable size of mapped region */ sqlite3_int64 mmapSizeActual; /* Actual size of mapped region */ sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */ #endif }; + +/* +** The winVfsAppData structure is used for the pAppData member for all of the +** Win32 VFS variants. +*/ +typedef struct winVfsAppData winVfsAppData; +struct winVfsAppData { + const sqlite3_io_methods *pMethod; /* The file I/O methods to use. */ + void *pAppData; /* The extra pAppData, if any. */ + BOOL bNoLock; /* Non-zero if locking is disabled. */ +}; /* ** Allowed values for winFile.ctrlFlags */ #define WINFILE_RDONLY 0x02 /* Connection is read only */ @@ -39497,11 +39769,16 @@ rc = osCloseHandle(pFile->h); /* SimulateIOError( rc=0; cnt=MX_CLOSE_ATTEMPT; ); */ }while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (sqlite3_win32_sleep(100), 1) ); #if SQLITE_OS_WINCE #define WINCE_DELETION_ATTEMPTS 3 - winceDestroyLock(pFile); + { + winVfsAppData *pAppData = (winVfsAppData*)pFile->pVfs->pAppData; + if( pAppData==NULL || !pAppData->bNoLock ){ + winceDestroyLock(pFile); + } + } if( pFile->zDeleteOnClose ){ int cnt = 0; while( osDeleteFileW(pFile->zDeleteOnClose)==0 && osGetFileAttributesW(pFile->zDeleteOnClose)!=0xffffffff @@ -40229,10 +40506,48 @@ OSTRACE(("UNLOCK file=%p, lock=%d, rc=%s\n", pFile->h, pFile->locktype, sqlite3ErrName(rc))); return rc; } +/****************************************************************************** +****************************** No-op Locking ********************************** +** +** Of the various locking implementations available, this is by far the +** simplest: locking is ignored. No attempt is made to lock the database +** file for reading or writing. +** +** This locking mode is appropriate for use on read-only databases +** (ex: databases that are burned into CD-ROM, for example.) It can +** also be used if the application employs some external mechanism to +** prevent simultaneous access of the same database by two or more +** database connections. But there is a serious risk of database +** corruption if this locking mode is used in situations where multiple +** database connections are accessing the same database file at the same +** time and one or more of those connections are writing. +*/ + +static int winNolockLock(sqlite3_file *id, int locktype){ + UNUSED_PARAMETER(id); + UNUSED_PARAMETER(locktype); + return SQLITE_OK; +} + +static int winNolockCheckReservedLock(sqlite3_file *id, int *pResOut){ + UNUSED_PARAMETER(id); + UNUSED_PARAMETER(pResOut); + return SQLITE_OK; +} + +static int winNolockUnlock(sqlite3_file *id, int locktype){ + UNUSED_PARAMETER(id); + UNUSED_PARAMETER(locktype); + return SQLITE_OK; +} + +/******************* End of the no-op lock implementation ********************* +******************************************************************************/ + /* ** If *pArg is initially negative then this is a query. Set *pArg to ** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set. ** ** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags. @@ -40507,16 +40822,16 @@ #define WIN_SHM_DMS (WIN_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */ /* ** Apply advisory locks for all n bytes beginning at ofst. */ -#define _SHM_UNLCK 1 -#define _SHM_RDLCK 2 -#define _SHM_WRLCK 3 +#define WINSHM_UNLCK 1 +#define WINSHM_RDLCK 2 +#define WINSHM_WRLCK 3 static int winShmSystemLock( winShmNode *pFile, /* Apply locks to this open shared-memory segment */ - int lockType, /* _SHM_UNLCK, _SHM_RDLCK, or _SHM_WRLCK */ + int lockType, /* WINSHM_UNLCK, WINSHM_RDLCK, or WINSHM_WRLCK */ int ofst, /* Offset to first byte to be locked/unlocked */ int nByte /* Number of bytes to lock or unlock */ ){ int rc = 0; /* Result code form Lock/UnlockFileEx() */ @@ -40525,16 +40840,16 @@ OSTRACE(("SHM-LOCK file=%p, lock=%d, offset=%d, size=%d\n", pFile->hFile.h, lockType, ofst, nByte)); /* Release/Acquire the system-level lock */ - if( lockType==_SHM_UNLCK ){ + if( lockType==WINSHM_UNLCK ){ rc = winUnlockFile(&pFile->hFile.h, ofst, 0, nByte, 0); }else{ /* Initialize the locking parameters */ DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY; - if( lockType == _SHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; + if( lockType == WINSHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; rc = winLockFile(&pFile->hFile.h, dwFlags, ofst, 0, nByte, 0); } if( rc!= 0 ){ rc = SQLITE_OK; @@ -40542,11 +40857,11 @@ pFile->lastErrno = osGetLastError(); rc = SQLITE_BUSY; } OSTRACE(("SHM-LOCK file=%p, func=%s, errno=%lu, rc=%s\n", - pFile->hFile.h, (lockType == _SHM_UNLCK) ? "winUnlockFile" : + pFile->hFile.h, (lockType == WINSHM_UNLCK) ? "winUnlockFile" : "winLockFile", pFile->lastErrno, sqlite3ErrName(rc))); return rc; } @@ -40670,20 +40985,20 @@ } /* Check to see if another process is holding the dead-man switch. ** If not, truncate the file to zero length. */ - if( winShmSystemLock(pShmNode, _SHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){ + if( winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){ rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0); if( rc!=SQLITE_OK ){ rc = winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(), "winOpenShm", pDbFd->zPath); } } if( rc==SQLITE_OK ){ - winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1); - rc = winShmSystemLock(pShmNode, _SHM_RDLCK, WIN_SHM_DMS, 1); + winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1); + rc = winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1); } if( rc ) goto shm_open_err; } /* Make the new connection a child of the winShmNode */ @@ -40708,11 +41023,11 @@ sqlite3_mutex_leave(pShmNode->mutex); return SQLITE_OK; /* Jump here on any error */ shm_open_err: - winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1); + winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1); winShmPurge(pDbFd->pVfs, 0); /* This call frees pShmNode if required */ sqlite3_free(p); sqlite3_free(pNew); winShmLeaveMutex(); return rc; @@ -40797,11 +41112,11 @@ allMask |= pX->sharedMask; } /* Unlock the system-level locks */ if( (mask & allMask)==0 ){ - rc = winShmSystemLock(pShmNode, _SHM_UNLCK, ofst+WIN_SHM_BASE, n); + rc = winShmSystemLock(pShmNode, WINSHM_UNLCK, ofst+WIN_SHM_BASE, n); }else{ rc = SQLITE_OK; } /* Undo the local locks */ @@ -40825,11 +41140,11 @@ } /* Get shared locks at the system level, if necessary */ if( rc==SQLITE_OK ){ if( (allShared & mask)==0 ){ - rc = winShmSystemLock(pShmNode, _SHM_RDLCK, ofst+WIN_SHM_BASE, n); + rc = winShmSystemLock(pShmNode, WINSHM_RDLCK, ofst+WIN_SHM_BASE, n); }else{ rc = SQLITE_OK; } } @@ -40850,11 +41165,11 @@ /* Get the exclusive locks at the system level. Then if successful ** also mark the local connection as being locked. */ if( rc==SQLITE_OK ){ - rc = winShmSystemLock(pShmNode, _SHM_WRLCK, ofst+WIN_SHM_BASE, n); + rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, ofst+WIN_SHM_BASE, n); if( rc==SQLITE_OK ){ assert( (p->sharedMask & mask)==0 ); p->exclMask |= mask; } } @@ -41292,10 +41607,48 @@ winShmBarrier, /* xShmBarrier */ winShmUnmap, /* xShmUnmap */ winFetch, /* xFetch */ winUnfetch /* xUnfetch */ }; + +/* +** This vector defines all the methods that can operate on an +** sqlite3_file for win32 without performing any locking. +*/ +static const sqlite3_io_methods winIoNolockMethod = { + 3, /* iVersion */ + winClose, /* xClose */ + winRead, /* xRead */ + winWrite, /* xWrite */ + winTruncate, /* xTruncate */ + winSync, /* xSync */ + winFileSize, /* xFileSize */ + winNolockLock, /* xLock */ + winNolockUnlock, /* xUnlock */ + winNolockCheckReservedLock, /* xCheckReservedLock */ + winFileControl, /* xFileControl */ + winSectorSize, /* xSectorSize */ + winDeviceCharacteristics, /* xDeviceCharacteristics */ + winShmMap, /* xShmMap */ + winShmLock, /* xShmLock */ + winShmBarrier, /* xShmBarrier */ + winShmUnmap, /* xShmUnmap */ + winFetch, /* xFetch */ + winUnfetch /* xUnfetch */ +}; + +static winVfsAppData winAppData = { + &winIoMethod, /* pMethod */ + 0, /* pAppData */ + 0 /* bNoLock */ +}; + +static winVfsAppData winNolockAppData = { + &winIoNolockMethod, /* pMethod */ + 0, /* pAppData */ + 1 /* bNoLock */ +}; /**************************************************************************** **************************** sqlite3_vfs methods **************************** ** ** This division contains the implementation of methods on the @@ -41625,11 +41978,11 @@ /* ** Open a file. */ static int winOpen( - sqlite3_vfs *pVfs, /* Used to get maximum path name length */ + sqlite3_vfs *pVfs, /* Used to get maximum path length and AppData */ const char *zName, /* Name of the file (UTF-8) */ sqlite3_file *id, /* Write the SQLite file handle here */ int flags, /* Open mode flags */ int *pOutFlags /* Status return flags */ ){ @@ -41640,10 +41993,11 @@ DWORD dwCreationDisposition; DWORD dwFlagsAndAttributes = 0; #if SQLITE_OS_WINCE int isTemp = 0; #endif + winVfsAppData *pAppData; winFile *pFile = (winFile*)id; void *zConverted; /* Filename in OS encoding */ const char *zUtf8Name = zName; /* Filename in UTF-8 encoding */ int cnt = 0; @@ -41861,19 +42215,24 @@ OSTRACE(("OPEN file=%p, name=%s, access=%lx, pOutFlags=%p, *pOutFlags=%d, " "rc=%s\n", h, zUtf8Name, dwDesiredAccess, pOutFlags, pOutFlags ? *pOutFlags : 0, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok")); + pAppData = (winVfsAppData*)pVfs->pAppData; + #if SQLITE_OS_WINCE - if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB - && (rc = winceCreateLock(zName, pFile))!=SQLITE_OK - ){ - osCloseHandle(h); - sqlite3_free(zConverted); - sqlite3_free(zTmpname); - OSTRACE(("OPEN-CE-LOCK name=%s, rc=%s\n", zName, sqlite3ErrName(rc))); - return rc; + { + if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB + && ((pAppData==NULL) || !pAppData->bNoLock) + && (rc = winceCreateLock(zName, pFile))!=SQLITE_OK + ){ + osCloseHandle(h); + sqlite3_free(zConverted); + sqlite3_free(zTmpname); + OSTRACE(("OPEN-CE-LOCK name=%s, rc=%s\n", zName, sqlite3ErrName(rc))); + return rc; + } } if( isTemp ){ pFile->zDeleteOnClose = zConverted; }else #endif @@ -41880,11 +42239,11 @@ { sqlite3_free(zConverted); } sqlite3_free(zTmpname); - pFile->pMethod = &winIoMethod; + pFile->pMethod = pAppData ? pAppData->pMethod : &winIoMethod; pFile->pVfs = pVfs; pFile->h = h; if( isReadonly ){ pFile->ctrlFlags |= WINFILE_RDONLY; } @@ -42155,10 +42514,22 @@ sqlite3_vfs *pVfs, /* Pointer to vfs object */ const char *zRelative, /* Possibly relative input path */ int nFull, /* Size of output buffer in bytes */ char *zFull /* Output buffer */ ){ +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__) + DWORD nByte; + void *zConverted; + char *zOut; +#endif + + /* If this path name begins with "/X:", where "X" is any alphabetic + ** character, discard the initial "/" from the pathname. + */ + if( zRelative[0]=='/' && winIsDriveLetterAndColon(zRelative+1) ){ + zRelative++; + } #if defined(__CYGWIN__) SimulateIOError( return SQLITE_ERROR ); UNUSED_PARAMETER(nFull); assert( nFull>=pVfs->mxPathname ); @@ -42233,21 +42604,10 @@ } return SQLITE_OK; #endif #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__) - DWORD nByte; - void *zConverted; - char *zOut; - - /* If this path name begins with "/X:", where "X" is any alphabetic - ** character, discard the initial "/" from the pathname. - */ - if( zRelative[0]=='/' && winIsDriveLetterAndColon(zRelative+1) ){ - zRelative++; - } - /* It's odd to simulate an io-error here, but really this is just ** using the io-error infrastructure to test that SQLite handles this ** function failing. This function could fail if, for example, the ** current working directory has been unlinked. */ @@ -42602,57 +42962,107 @@ /* ** Initialize and deinitialize the operating system interface. */ SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void){ static sqlite3_vfs winVfs = { - 3, /* iVersion */ - sizeof(winFile), /* szOsFile */ + 3, /* iVersion */ + sizeof(winFile), /* szOsFile */ SQLITE_WIN32_MAX_PATH_BYTES, /* mxPathname */ - 0, /* pNext */ - "win32", /* zName */ - 0, /* pAppData */ - winOpen, /* xOpen */ - winDelete, /* xDelete */ - winAccess, /* xAccess */ - winFullPathname, /* xFullPathname */ - winDlOpen, /* xDlOpen */ - winDlError, /* xDlError */ - winDlSym, /* xDlSym */ - winDlClose, /* xDlClose */ - winRandomness, /* xRandomness */ - winSleep, /* xSleep */ - winCurrentTime, /* xCurrentTime */ - winGetLastError, /* xGetLastError */ - winCurrentTimeInt64, /* xCurrentTimeInt64 */ - winSetSystemCall, /* xSetSystemCall */ - winGetSystemCall, /* xGetSystemCall */ - winNextSystemCall, /* xNextSystemCall */ + 0, /* pNext */ + "win32", /* zName */ + &winAppData, /* pAppData */ + winOpen, /* xOpen */ + winDelete, /* xDelete */ + winAccess, /* xAccess */ + winFullPathname, /* xFullPathname */ + winDlOpen, /* xDlOpen */ + winDlError, /* xDlError */ + winDlSym, /* xDlSym */ + winDlClose, /* xDlClose */ + winRandomness, /* xRandomness */ + winSleep, /* xSleep */ + winCurrentTime, /* xCurrentTime */ + winGetLastError, /* xGetLastError */ + winCurrentTimeInt64, /* xCurrentTimeInt64 */ + winSetSystemCall, /* xSetSystemCall */ + winGetSystemCall, /* xGetSystemCall */ + winNextSystemCall, /* xNextSystemCall */ }; #if defined(SQLITE_WIN32_HAS_WIDE) static sqlite3_vfs winLongPathVfs = { - 3, /* iVersion */ - sizeof(winFile), /* szOsFile */ + 3, /* iVersion */ + sizeof(winFile), /* szOsFile */ + SQLITE_WINNT_MAX_PATH_BYTES, /* mxPathname */ + 0, /* pNext */ + "win32-longpath", /* zName */ + &winAppData, /* pAppData */ + winOpen, /* xOpen */ + winDelete, /* xDelete */ + winAccess, /* xAccess */ + winFullPathname, /* xFullPathname */ + winDlOpen, /* xDlOpen */ + winDlError, /* xDlError */ + winDlSym, /* xDlSym */ + winDlClose, /* xDlClose */ + winRandomness, /* xRandomness */ + winSleep, /* xSleep */ + winCurrentTime, /* xCurrentTime */ + winGetLastError, /* xGetLastError */ + winCurrentTimeInt64, /* xCurrentTimeInt64 */ + winSetSystemCall, /* xSetSystemCall */ + winGetSystemCall, /* xGetSystemCall */ + winNextSystemCall, /* xNextSystemCall */ + }; +#endif + static sqlite3_vfs winNolockVfs = { + 3, /* iVersion */ + sizeof(winFile), /* szOsFile */ + SQLITE_WIN32_MAX_PATH_BYTES, /* mxPathname */ + 0, /* pNext */ + "win32-none", /* zName */ + &winNolockAppData, /* pAppData */ + winOpen, /* xOpen */ + winDelete, /* xDelete */ + winAccess, /* xAccess */ + winFullPathname, /* xFullPathname */ + winDlOpen, /* xDlOpen */ + winDlError, /* xDlError */ + winDlSym, /* xDlSym */ + winDlClose, /* xDlClose */ + winRandomness, /* xRandomness */ + winSleep, /* xSleep */ + winCurrentTime, /* xCurrentTime */ + winGetLastError, /* xGetLastError */ + winCurrentTimeInt64, /* xCurrentTimeInt64 */ + winSetSystemCall, /* xSetSystemCall */ + winGetSystemCall, /* xGetSystemCall */ + winNextSystemCall, /* xNextSystemCall */ + }; +#if defined(SQLITE_WIN32_HAS_WIDE) + static sqlite3_vfs winLongPathNolockVfs = { + 3, /* iVersion */ + sizeof(winFile), /* szOsFile */ SQLITE_WINNT_MAX_PATH_BYTES, /* mxPathname */ - 0, /* pNext */ - "win32-longpath", /* zName */ - 0, /* pAppData */ - winOpen, /* xOpen */ - winDelete, /* xDelete */ - winAccess, /* xAccess */ - winFullPathname, /* xFullPathname */ - winDlOpen, /* xDlOpen */ - winDlError, /* xDlError */ - winDlSym, /* xDlSym */ - winDlClose, /* xDlClose */ - winRandomness, /* xRandomness */ - winSleep, /* xSleep */ - winCurrentTime, /* xCurrentTime */ - winGetLastError, /* xGetLastError */ - winCurrentTimeInt64, /* xCurrentTimeInt64 */ - winSetSystemCall, /* xSetSystemCall */ - winGetSystemCall, /* xGetSystemCall */ - winNextSystemCall, /* xNextSystemCall */ + 0, /* pNext */ + "win32-longpath-none", /* zName */ + &winNolockAppData, /* pAppData */ + winOpen, /* xOpen */ + winDelete, /* xDelete */ + winAccess, /* xAccess */ + winFullPathname, /* xFullPathname */ + winDlOpen, /* xDlOpen */ + winDlError, /* xDlError */ + winDlSym, /* xDlSym */ + winDlClose, /* xDlClose */ + winRandomness, /* xRandomness */ + winSleep, /* xSleep */ + winCurrentTime, /* xCurrentTime */ + winGetLastError, /* xGetLastError */ + winCurrentTimeInt64, /* xCurrentTimeInt64 */ + winSetSystemCall, /* xSetSystemCall */ + winGetSystemCall, /* xGetSystemCall */ + winNextSystemCall, /* xNextSystemCall */ }; #endif /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ @@ -42671,10 +43081,16 @@ sqlite3_vfs_register(&winVfs, 1); #if defined(SQLITE_WIN32_HAS_WIDE) sqlite3_vfs_register(&winLongPathVfs, 0); #endif + + sqlite3_vfs_register(&winNolockVfs, 0); + +#if defined(SQLITE_WIN32_HAS_WIDE) + sqlite3_vfs_register(&winLongPathNolockVfs, 0); +#endif return SQLITE_OK; } SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void){ @@ -43792,32 +44208,34 @@ sqlite3PcacheTruncate(pCache, 0); } /* ** Merge two lists of pages connected by pDirty and in pgno order. -** Do not both fixing the pDirtyPrev pointers. +** Do not bother fixing the pDirtyPrev pointers. */ static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){ PgHdr result, *pTail; pTail = &result; - while( pA && pB ){ + assert( pA!=0 && pB!=0 ); + for(;;){ if( pA->pgnopgno ){ pTail->pDirty = pA; pTail = pA; pA = pA->pDirty; + if( pA==0 ){ + pTail->pDirty = pB; + break; + } }else{ pTail->pDirty = pB; pTail = pB; pB = pB->pDirty; - } - } - if( pA ){ - pTail->pDirty = pA; - }else if( pB ){ - pTail->pDirty = pB; - }else{ - pTail->pDirty = 0; + if( pB==0 ){ + pTail->pDirty = pA; + break; + } + } } return result.pDirty; } /* @@ -43855,11 +44273,12 @@ a[i] = pcacheMergeDirtyList(a[i], p); } } p = a[0]; for(i=1; inPage is correct */ - unsigned int h; + TESTONLY( int nPage = 0; ) /* To assert pCache->nPage is correct */ + unsigned int h, iStop; assert( sqlite3_mutex_held(pCache->pGroup->mutex) ); - for(h=0; hnHash; h++){ - PgHdr1 **pp = &pCache->apHash[h]; + assert( pCache->iMaxKey >= iLimit ); + assert( pCache->nHash > 0 ); + if( pCache->iMaxKey - iLimit < pCache->nHash ){ + /* If we are just shaving the last few pages off the end of the + ** cache, then there is no point in scanning the entire hash table. + ** Only scan those hash slots that might contain pages that need to + ** be removed. */ + h = iLimit % pCache->nHash; + iStop = pCache->iMaxKey % pCache->nHash; + TESTONLY( nPage = -10; ) /* Disable the pCache->nPage validity check */ + }else{ + /* This is the general case where many pages are being removed. + ** It is necessary to scan the entire hash table */ + h = pCache->nHash/2; + iStop = h - 1; + } + for(;;){ + PgHdr1 **pp; PgHdr1 *pPage; + assert( hnHash ); + pp = &pCache->apHash[h]; while( (pPage = *pp)!=0 ){ if( pPage->iKey>=iLimit ){ pCache->nPage--; *pp = pPage->pNext; if( !pPage->isPinned ) pcache1PinPage(pPage); pcache1FreePage(pPage); }else{ pp = &pPage->pNext; - TESTONLY( nPage++; ) + TESTONLY( if( nPage>=0 ) nPage++; ) } } + if( h==iStop ) break; + h = (h+1) % pCache->nHash; } - assert( pCache->nPage==nPage ); + assert( nPage<0 || pCache->nPage==(unsigned)nPage ); } /******************************************************************************/ /******** sqlite3_pcache Methods **********************************************/ @@ -45105,11 +45544,11 @@ static void pcache1Destroy(sqlite3_pcache *p){ PCache1 *pCache = (PCache1 *)p; PGroup *pGroup = pCache->pGroup; assert( pCache->bPurgeable || (pCache->nMax==0 && pCache->nMin==0) ); pcache1EnterMutex(pGroup); - pcache1TruncateUnsafe(pCache, 0); + if( pCache->nPage ) pcache1TruncateUnsafe(pCache, 0); assert( pGroup->nMaxPage >= pCache->nMax ); pGroup->nMaxPage -= pCache->nMax; assert( pGroup->nMinPage >= pCache->nMin ); pGroup->nMinPage -= pCache->nMin; pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage; @@ -45460,31 +45899,29 @@ ){ struct RowSetEntry head; struct RowSetEntry *pTail; pTail = &head; - while( pA && pB ){ + assert( pA!=0 && pB!=0 ); + for(;;){ assert( pA->pRight==0 || pA->v<=pA->pRight->v ); assert( pB->pRight==0 || pB->v<=pB->pRight->v ); - if( pA->vv ){ - pTail->pRight = pA; + if( pA->v<=pB->v ){ + if( pA->vv ) pTail = pTail->pRight = pA; pA = pA->pRight; - pTail = pTail->pRight; - }else if( pB->vv ){ - pTail->pRight = pB; + if( pA==0 ){ + pTail->pRight = pB; + break; + } + }else{ + pTail = pTail->pRight = pB; pB = pB->pRight; - pTail = pTail->pRight; - }else{ - pA = pA->pRight; - } - } - if( pA ){ - assert( pA->pRight==0 || pA->v<=pA->pRight->v ); - pTail->pRight = pA; - }else{ - assert( pB==0 || pB->pRight==0 || pB->v<=pB->pRight->v ); - pTail->pRight = pB; + if( pB==0 ){ + pTail->pRight = pA; + break; + } + } } return head.pRight; } /* @@ -45504,13 +45941,14 @@ aBucket[i] = 0; } aBucket[i] = pIn; pIn = pNext; } - pIn = 0; - for(i=0; itempFile ); if( pPager->tempFile==0 ) pager_reset(pPager); } #endif + #ifndef SQLITE_OMIT_WAL /* ** This function is called when the user invokes "PRAGMA wal_checkpoint", ** "PRAGMA wal_blocking_checkpoint" or calls the sqlite3_wal_checkpoint() @@ -53261,11 +53700,10 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){ assert( pPager->eState>=PAGER_READER ); return sqlite3WalFramesize(pPager->pWal); } #endif - #endif /* SQLITE_OMIT_DISKIO */ /************** End of pager.c ***********************************************/ /************** Begin file wal.c *********************************************/ @@ -56378,20 +56816,25 @@ ** boundary is crossed. Only the part of the WAL prior to the last ** sector boundary is synced; the part of the last frame that extends ** past the sector boundary is written after the sync. */ if( isCommit && (sync_flags & WAL_SYNC_TRANSACTIONS)!=0 ){ + int bSync = 1; if( pWal->padToSectorBoundary ){ int sectorSize = sqlite3SectorSize(pWal->pWalFd); w.iSyncPoint = ((iOffset+sectorSize-1)/sectorSize)*sectorSize; + bSync = (w.iSyncPoint==iOffset); + testcase( bSync ); while( iOffsetpBt->mutex); } + +/* Verify that the cursor and the BtShared agree about what is the current +** database connetion. This is important in shared-cache mode. If the database +** connection pointers get out-of-sync, it is possible for routines like +** btreeInitPage() to reference an stale connection pointer that references a +** a connection that has already closed. This routine is used inside assert() +** statements only and for the purpose of double-checking that the btree code +** does keep the database connection pointers up-to-date. +*/ static int cursorOwnsBtShared(BtCursor *p){ assert( cursorHoldsMutex(p) ); return (p->pBtree->db==p->pBt->db); } #endif @@ -58333,25 +58785,23 @@ ** NULL. If the cursor is open on a non-intkey table, then pCur->pKey is ** set to point to a malloced buffer pCur->nKey bytes in size containing ** the key. */ static int saveCursorKey(BtCursor *pCur){ - int rc; + int rc = SQLITE_OK; assert( CURSOR_VALID==pCur->eState ); assert( 0==pCur->pKey ); assert( cursorHoldsMutex(pCur) ); - rc = sqlite3BtreeKeySize(pCur, &pCur->nKey); - assert( rc==SQLITE_OK ); /* KeySize() cannot fail */ - - /* If this is an intKey table, then the above call to BtreeKeySize() - ** stores the integer key in pCur->nKey. In this case this value is - ** all that is required. Otherwise, if pCur is not open on an intKey - ** table, then malloc space for and store the pCur->nKey bytes of key - ** data. */ - if( 0==pCur->curIntKey ){ - void *pKey = sqlite3Malloc( pCur->nKey ); + if( pCur->curIntKey ){ + /* Only the rowid is required for a table btree */ + pCur->nKey = sqlite3BtreeIntegerKey(pCur); + }else{ + /* For an index btree, save the complete key content */ + void *pKey; + pCur->nKey = sqlite3BtreePayloadSize(pCur); + pKey = sqlite3Malloc( pCur->nKey ); if( pKey ){ rc = sqlite3BtreeKey(pCur, 0, (int)pCur->nKey, pKey); if( rc==SQLITE_OK ){ pCur->pKey = pKey; }else{ @@ -60054,13 +60504,13 @@ assert( (pBt->pageSize & 7)==0 ); /* 8-byte alignment of pageSize */ #if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) /* Add the new BtShared object to the linked list sharable BtShareds. */ + pBt->nRef = 1; if( p->sharable ){ MUTEX_LOGIC( sqlite3_mutex *mutexShared; ) - pBt->nRef = 1; MUTEX_LOGIC( mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);) if( SQLITE_THREADSAFE && sqlite3GlobalConfig.bCoreMutex ){ pBt->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_FAST); if( pBt->mutex==0 ){ rc = SQLITE_NOMEM_BKPT; @@ -60127,10 +60577,11 @@ } if( mutexOpen ){ assert( sqlite3_mutex_held(mutexOpen) ); sqlite3_mutex_leave(mutexOpen); } + assert( rc!=SQLITE_OK || sqlite3BtreeConnectionCount(*ppBtree)>0 ); return rc; } /* ** Decrement the BtShared.nRef counter. When it reaches zero, @@ -61986,50 +62437,37 @@ return pCur && pCur->eState==CURSOR_VALID; } #endif /* NDEBUG */ /* -** Set *pSize to the size of the buffer needed to hold the value of -** the key for the current entry. If the cursor is not pointing -** to a valid entry, *pSize is set to 0. -** -** For a table with the INTKEY flag set, this routine returns the key -** itself, not the number of bytes in the key. -** -** The caller must position the cursor prior to invoking this routine. -** -** This routine cannot fail. It always returns SQLITE_OK. +** Return the value of the integer key or "rowid" for a table btree. +** This routine is only valid for a cursor that is pointing into a +** ordinary table btree. If the cursor points to an index btree or +** is invalid, the result of this routine is undefined. */ -SQLITE_PRIVATE int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){ +SQLITE_PRIVATE i64 sqlite3BtreeIntegerKey(BtCursor *pCur){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); + assert( pCur->curIntKey ); getCellInfo(pCur); - *pSize = pCur->info.nKey; - return SQLITE_OK; + return pCur->info.nKey; } /* -** Set *pSize to the number of bytes of data in the entry the -** cursor currently points to. +** Return the number of bytes of payload for the entry that pCur is +** currently pointing to. For table btrees, this will be the amount +** of data. For index btrees, this will be the size of the key. ** ** The caller must guarantee that the cursor is pointing to a non-NULL ** valid entry. In other words, the calling procedure must guarantee ** that the cursor has Cursor.eState==CURSOR_VALID. -** -** Failure is not possible. This function always returns SQLITE_OK. -** It might just as well be a procedure (returning void) but we continue -** to return an integer result code for historical reasons. */ -SQLITE_PRIVATE int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){ - assert( cursorOwnsBtShared(pCur) ); +SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor *pCur){ + assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); - assert( pCur->iPage>=0 ); - assert( pCur->iPageapPage[pCur->iPage]->intKeyLeaf==1 ); getCellInfo(pCur); - *pSize = pCur->info.nPayload; - return SQLITE_OK; + return pCur->info.nPayload; } /* ** Given the page number of an overflow page in the database (parameter ** ovfl), this function finds the page number of the next page in the @@ -62467,14 +62905,11 @@ ** this routine. ** ** These routines is used to get quick access to key and data ** in the common case where no overflow pages are used. */ -SQLITE_PRIVATE const void *sqlite3BtreeKeyFetch(BtCursor *pCur, u32 *pAmt){ - return fetchPayload(pCur, pAmt); -} -SQLITE_PRIVATE const void *sqlite3BtreeDataFetch(BtCursor *pCur, u32 *pAmt){ +SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor *pCur, u32 *pAmt){ return fetchPayload(pCur, pAmt); } /* @@ -62803,15 +63238,16 @@ assert( cursorOwnsBtShared(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( pRes ); assert( (pIdxKey==0)==(pCur->pKeyInfo==0) ); + assert( pCur->eState!=CURSOR_VALID || (pIdxKey==0)==(pCur->curIntKey!=0) ); /* If the cursor is already positioned at the point we are trying ** to move to, then just return without doing any work */ - if( pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0 - && pCur->curIntKey + if( pIdxKey==0 + && pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0 ){ if( pCur->info.nKey==intKey ){ *pRes = 0; return SQLITE_OK; } @@ -63796,13 +64232,11 @@ ** later. */ static int fillInCell( MemPage *pPage, /* The page that contains the cell */ unsigned char *pCell, /* Complete text of the cell */ - const void *pKey, i64 nKey, /* The key */ - const void *pData,int nData, /* The data */ - int nZero, /* Extra zero bytes to append to pData */ + const BtreePayload *pX, /* Payload with which to construct the cell */ int *pnSize /* Write cell size here */ ){ int nPayload; const u8 *pSrc; int nSrc, n, rc; @@ -63822,30 +64256,27 @@ assert( pCellaData || pCell>=&pPage->aData[pBt->pageSize] || sqlite3PagerIswriteable(pPage->pDbPage) ); /* Fill in the header. */ nHeader = pPage->childPtrSize; - nPayload = nData + nZero; - if( pPage->intKeyLeaf ){ - nHeader += putVarint32(&pCell[nHeader], nPayload); - }else{ - assert( nData==0 ); - assert( nZero==0 ); - } - nHeader += putVarint(&pCell[nHeader], *(u64*)&nKey); - - /* Fill in the payload size */ if( pPage->intKey ){ - pSrc = pData; - nSrc = nData; - nData = 0; - }else{ - assert( nKey<=0x7fffffff && pKey!=0 ); - nPayload = (int)nKey; - pSrc = pKey; - nSrc = (int)nKey; - } + nPayload = pX->nData + pX->nZero; + pSrc = pX->pData; + nSrc = pX->nData; + assert( pPage->intKeyLeaf ); /* fillInCell() only called for leaves */ + nHeader += putVarint32(&pCell[nHeader], nPayload); + nHeader += putVarint(&pCell[nHeader], *(u64*)&pX->nKey); + }else{ + assert( pX->nData==0 ); + assert( pX->nZero==0 ); + assert( pX->nKey<=0x7fffffff && pX->pKey!=0 ); + nSrc = nPayload = (int)pX->nKey; + pSrc = pX->pKey; + nHeader += putVarint32(&pCell[nHeader], nPayload); + } + + /* Fill in the payload */ if( nPayload<=pPage->maxLocal ){ n = nHeader + nPayload; testcase( n==3 ); testcase( n==4 ); if( n<4 ) n = 4; @@ -63879,11 +64310,11 @@ #if SQLITE_DEBUG { CellInfo info; pPage->xParseCell(pPage, pCell, &info); assert( nHeader==(int)(info.pPayload - pCell) ); - assert( info.nKey==nKey ); + assert( info.nKey==pX->nKey ); assert( *pnSize == info.nSize ); assert( spaceLeft == info.nLocal ); } #endif @@ -63964,14 +64395,10 @@ nPayload -= n; pPayload += n; pSrc += n; nSrc -= n; spaceLeft -= n; - if( nSrc==0 ){ - nSrc = nData; - pSrc = pData; - } } releasePage(pToRelease); return SQLITE_OK; } @@ -64034,10 +64461,12 @@ ** pTemp is not null. Regardless of pTemp, allocate a new entry ** in pPage->apOvfl[] and make it point to the cell content (either ** in pTemp or the original pCell) and also record its index. ** Allocating a new entry in pPage->aCell[] implies that ** pPage->nOverflow is incremented. +** +** *pRC must be SQLITE_OK when this routine is called. */ static void insertCell( MemPage *pPage, /* Page into which we are copying */ int i, /* New cell becomes the i-th cell of the page */ u8 *pCell, /* Content of the new cell */ @@ -64049,12 +64478,11 @@ int idx = 0; /* Where to write new cell content in data[] */ int j; /* Loop counter */ u8 *data; /* The content of the whole page */ u8 *pIns; /* The point in pPage->aCellIdx[] where no cell inserted */ - if( *pRC ) return; - + assert( *pRC==SQLITE_OK ); assert( i>=0 && i<=pPage->nCell+pPage->nOverflow ); assert( MX_CELL(pPage->pBt)<=10921 ); assert( pPage->nCell<=MX_CELL(pPage->pBt) || CORRUPT_DB ); assert( pPage->nOverflow<=ArraySize(pPage->apOvfl) ); assert( ArraySize(pPage->apOvfl)==ArraySize(pPage->aiOvfl) ); @@ -64124,11 +64552,11 @@ } } /* ** A CellArray object contains a cache of pointers and sizes for a -** consecutive sequence of cells that might be held multiple pages. +** consecutive sequence of cells that might be held on multiple pages. */ typedef struct CellArray CellArray; struct CellArray { int nCell; /* Number of cells in apCell[] */ MemPage *pRef; /* Reference page */ @@ -64556,12 +64984,14 @@ while( (*(pCell++)&0x80) && pCellnCell, pSpace, (int)(pOut-pSpace), - 0, pPage->pgno, &rc); + if( rc==SQLITE_OK ){ + insertCell(pParent, pParent->nCell, pSpace, (int)(pOut-pSpace), + 0, pPage->pgno, &rc); + } /* Set the right-child pointer of pParent to point to the new page. */ put4byte(&pParent->aData[pParent->hdrOffset+8], pgnoNew); /* Release the reference to the new page. */ @@ -65077,11 +65507,11 @@ do{ assert( d szLeft-(b.szCell[r]+2)) ){ + && (bBulk || szRight+b.szCell[d]+2 > szLeft-(b.szCell[r]+(i==k-1?0:2)))){ break; } szRight += b.szCell[d] + 2; szLeft -= b.szCell[r] + 2; cntNew[i-1] = r; @@ -65649,17 +66079,23 @@ return rc; } /* -** Insert a new record into the BTree. The key is given by (pKey,nKey) -** and the data is given by (pData,nData). The cursor is used only to -** define what table the record should be inserted into. The cursor -** is left pointing at a random location. +** Insert a new record into the BTree. The content of the new record +** is described by the pX object. The pCur cursor is used only to +** define what table the record should be inserted into, and is left +** pointing at a random location. ** -** For an INTKEY table, only the nKey value of the key is used. pKey is -** ignored. For a ZERODATA table, the pData and nData are both ignored. +** For a table btree (used for rowid tables), only the pX.nKey value of +** the key is used. The pX.pKey value must be NULL. The pX.nKey is the +** rowid or INTEGER PRIMARY KEY of the row. The pX.nData,pData,nZero fields +** hold the content of the row. +** +** For an index btree (used for indexes and WITHOUT ROWID tables), the +** key is an arbitrary byte sequence stored in pX.pKey,nKey. The +** pX.pData,nData,nZero fields must be zero. ** ** If the seekResult parameter is non-zero, then a successful call to ** MovetoUnpacked() to seek cursor pCur to (pKey, nKey) has already ** been performed. seekResult is the search result returned (a negative ** number if pCur points at an entry that is smaller than (pKey, nKey), or @@ -65672,13 +66108,11 @@ ** point to any entry or to no entry at all and so this function has to seek ** the cursor before the new key can be inserted. */ SQLITE_PRIVATE int sqlite3BtreeInsert( BtCursor *pCur, /* Insert data into the table of this cursor */ - const void *pKey, i64 nKey, /* The key of the new record */ - const void *pData, int nData, /* The data of the new record */ - int nZero, /* Number of extra 0 bytes to append to data */ + const BtreePayload *pX, /* Content of the row to be inserted */ int appendBias, /* True if this is likely an append */ int seekResult /* Result of prior MovetoUnpacked() call */ ){ int rc; int loc = seekResult; /* -1: before desired location +1: after */ @@ -65704,11 +66138,11 @@ /* Assert that the caller has been consistent. If this cursor was opened ** expecting an index b-tree, then the caller should be inserting blob ** keys with no associated data. If the cursor was opened expecting an ** intkey table, the caller should be inserting integer keys with a ** blob of associated data. */ - assert( (pKey==0)==(pCur->pKeyInfo==0) ); + assert( (pX->pKey==0)==(pCur->pKeyInfo==0) ); /* Save the positions of any other cursors open on this table. ** ** In some cases, the call to btreeMoveto() below is a no-op. For ** example, when inserting data into a table with auto-generated integer @@ -65723,42 +66157,42 @@ rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur); if( rc ) return rc; } if( pCur->pKeyInfo==0 ){ - assert( pKey==0 ); + assert( pX->pKey==0 ); /* If this is an insert into a table b-tree, invalidate any incrblob ** cursors open on the row being replaced */ - invalidateIncrblobCursors(p, nKey, 0); + invalidateIncrblobCursors(p, pX->nKey, 0); /* If the cursor is currently on the last row and we are appending a ** new row onto the end, set the "loc" to avoid an unnecessary ** btreeMoveto() call */ - if( (pCur->curFlags&BTCF_ValidNKey)!=0 && nKey>0 - && pCur->info.nKey==nKey-1 ){ + if( (pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey>0 + && pCur->info.nKey==pX->nKey-1 ){ loc = -1; }else if( loc==0 ){ - rc = sqlite3BtreeMovetoUnpacked(pCur, 0, nKey, appendBias, &loc); + rc = sqlite3BtreeMovetoUnpacked(pCur, 0, pX->nKey, appendBias, &loc); if( rc ) return rc; } }else if( loc==0 ){ - rc = btreeMoveto(pCur, pKey, nKey, appendBias, &loc); + rc = btreeMoveto(pCur, pX->pKey, pX->nKey, appendBias, &loc); if( rc ) return rc; } assert( pCur->eState==CURSOR_VALID || (pCur->eState==CURSOR_INVALID && loc) ); pPage = pCur->apPage[pCur->iPage]; - assert( pPage->intKey || nKey>=0 ); + assert( pPage->intKey || pX->nKey>=0 ); assert( pPage->leaf || !pPage->intKey ); TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n", - pCur->pgnoRoot, nKey, nData, pPage->pgno, + pCur->pgnoRoot, pX->nKey, pX->nData, pPage->pgno, loc==0 ? "overwrite" : "new entry")); assert( pPage->isInit ); newCell = pBt->pTmpSpace; assert( newCell!=0 ); - rc = fillInCell(pPage, newCell, pKey, nKey, pData, nData, nZero, &szNew); + rc = fillInCell(pPage, newCell, pX, &szNew); if( rc ) goto end_insert; assert( szNew==pPage->xCellSize(pPage, newCell) ); assert( szNew <= MX_CELL_SIZE(pBt) ); idx = pCur->aiIdx[pCur->iPage]; if( loc==0 ){ @@ -65780,10 +66214,11 @@ idx = ++pCur->aiIdx[pCur->iPage]; }else{ assert( pPage->leaf ); } insertCell(pPage, idx, newCell, szNew, 0, 0, &rc); + assert( pPage->nOverflow==0 || rc==SQLITE_OK ); assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 ); /* If no error has occurred and pPage has an overflow cell, call balance() ** to redistribute the cells within the tree. Since balance() may move ** the cursor, zero the BtCursor.info.nSize and BTCF_ValidNKey @@ -65803,11 +66238,12 @@ ** entry in the table, and the next row inserted has an integer key ** larger than the largest existing key, it is possible to insert the ** row without seeking the cursor. This can be a big performance boost. */ pCur->info.nSize = 0; - if( rc==SQLITE_OK && pPage->nOverflow ){ + if( pPage->nOverflow ){ + assert( rc==SQLITE_OK ); pCur->curFlags &= ~(BTCF_ValidNKey); rc = balance(pCur); /* Must make sure nOverflow is reset to zero even if the balance() ** fails. Internal data structure corruption will result otherwise. @@ -65939,11 +66375,13 @@ nCell = pLeaf->xCellSize(pLeaf, pCell); assert( MX_CELL_SIZE(pBt) >= nCell ); pTmp = pBt->pTmpSpace; assert( pTmp!=0 ); rc = sqlite3PagerWrite(pLeaf->pDbPage); - insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n, &rc); + if( rc==SQLITE_OK ){ + insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n, &rc); + } dropCell(pLeaf, pLeaf->nCell-1, nCell, &rc); if( rc ) return rc; } /* Balance the tree. If the entry deleted was located on a leaf page, @@ -67428,10 +67866,20 @@ ** Return true if the Btree passed as the only argument is sharable. */ SQLITE_PRIVATE int sqlite3BtreeSharable(Btree *p){ return p->sharable; } + +/* +** Return the number of connections to the BtShared object accessed by +** the Btree handle passed as the only argument. For private caches +** this is always 1. For shared caches it may be 1 or greater. +*/ +SQLITE_PRIVATE int sqlite3BtreeConnectionCount(Btree *p){ + testcase( p->sharable ); + return p->pBt->nRef; +} #endif /************** End of btree.c ***********************************************/ /************** Begin file backup.c ******************************************/ /* @@ -68211,14 +68659,14 @@ /* 0x7FFFFFFF is the hard limit for the number of pages in a database ** file. By passing this as the number of pages to copy to ** sqlite3_backup_step(), we can guarantee that the copy finishes ** within a single call (unless an error occurs). The assert() statement ** checks this assumption - (p->rc) should be set to either SQLITE_DONE - ** or an error code. - */ + ** or an error code. */ sqlite3_backup_step(&b, 0x7FFFFFFF); assert( b.rc!=SQLITE_OK ); + rc = sqlite3_backup_finish(&b); if( rc==SQLITE_OK ){ pTo->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED; }else{ sqlite3PagerClearCache(sqlite3BtreePager(b.pDest)); @@ -69225,15 +69673,11 @@ assert( !VdbeMemDynamic(pMem) ); /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert() ** that both the BtShared and database handle mutexes are held. */ assert( (pMem->flags & MEM_RowSet)==0 ); - if( key ){ - zData = (char *)sqlite3BtreeKeyFetch(pCur, &available); - }else{ - zData = (char *)sqlite3BtreeDataFetch(pCur, &available); - } + zData = (char *)sqlite3BtreePayloadFetch(pCur, &available); assert( zData!=0 ); if( offset+amt<=available ){ pMem->z = &zData[offset]; pMem->flags = MEM_Blob|MEM_Ephem; @@ -70009,18 +70453,10 @@ assert( p->zSql==0 ); p->zSql = sqlite3DbStrNDup(p->db, z, n); p->isPrepareV2 = (u8)isPrepareV2; } -/* -** Return the SQL associated with a prepared statement -*/ -SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt){ - Vdbe *p = (Vdbe *)pStmt; - return p ? p->zSql : 0; -} - /* ** Swap all content between two VDBE structures. */ SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){ Vdbe tmp, *pTmp; @@ -70736,26 +71172,34 @@ /* ** If the input FuncDef structure is ephemeral, then free it. If ** the FuncDef is not ephermal, then do nothing. */ static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){ - if( ALWAYS(pDef) && (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){ + if( (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){ sqlite3DbFree(db, pDef); } } static void vdbeFreeOpArray(sqlite3 *, Op *, int); /* ** Delete a P4 value if necessary. */ +static SQLITE_NOINLINE void freeP4Mem(sqlite3 *db, Mem *p){ + if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc); + sqlite3DbFree(db, p); +} +static SQLITE_NOINLINE void freeP4FuncCtx(sqlite3 *db, sqlite3_context *p){ + freeEphemeralFunction(db, p->pFunc); + sqlite3DbFree(db, p); +} static void freeP4(sqlite3 *db, int p4type, void *p4){ assert( db ); switch( p4type ){ case P4_FUNCCTX: { - freeEphemeralFunction(db, ((sqlite3_context*)p4)->pFunc); - /* Fall through into the next case */ + freeP4FuncCtx(db, (sqlite3_context*)p4); + break; } case P4_REAL: case P4_INT64: case P4_DYNAMIC: case P4_INTARRAY: { @@ -70782,13 +71226,11 @@ } case P4_MEM: { if( db->pnBytesFreed==0 ){ sqlite3ValueFree((sqlite3_value*)p4); }else{ - Mem *p = (Mem*)p4; - if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc); - sqlite3DbFree(db, p); + freeP4Mem(db, (Mem*)p4); } break; } case P4_VTAB : { if( db->pnBytesFreed==0 ) sqlite3VtabUnlock((VTable *)p4); @@ -74254,12 +74696,11 @@ ** than 2GiB are support - anything large must be database corruption. ** Any corruption is detected in sqlite3BtreeParseCellPtr(), though, so ** this code can safely assume that nCellKey is 32-bits */ assert( sqlite3BtreeCursorIsValid(pCur) ); - VVA_ONLY(rc =) sqlite3BtreeKeySize(pCur, &nCellKey); - assert( rc==SQLITE_OK ); /* pCur is always valid so KeySize cannot fail */ + nCellKey = sqlite3BtreePayloadSize(pCur); assert( (nCellKey & SQLITE_MAX_U32)==(u64)nCellKey ); /* Read in the complete content of the index entry */ sqlite3VdbeMemInit(&m, db, 0); rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, 1, &m); @@ -74332,12 +74773,11 @@ Mem m; assert( pC->eCurType==CURTYPE_BTREE ); pCur = pC->uc.pCursor; assert( sqlite3BtreeCursorIsValid(pCur) ); - VVA_ONLY(rc =) sqlite3BtreeKeySize(pCur, &nCellKey); - assert( rc==SQLITE_OK ); /* pCur is always valid so KeySize cannot fail */ + nCellKey = sqlite3BtreePayloadSize(pCur); /* nCellKey will always be between 0 and 0xffffffff because of the way ** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */ if( nCellKey<=0 || nCellKey>0x7fffffff ){ *res = 0; return SQLITE_CORRUPT_BKPT; @@ -74595,16 +75035,23 @@ ** Invoke the profile callback. This routine is only called if we already ** know that the profile callback is defined and needs to be invoked. */ static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){ sqlite3_int64 iNow; + sqlite3_int64 iElapse; assert( p->startTime>0 ); - assert( db->xProfile!=0 ); + assert( db->xProfile!=0 || (db->mTrace & SQLITE_TRACE_PROFILE)!=0 ); assert( db->init.busy==0 ); assert( p->zSql!=0 ); sqlite3OsCurrentTimeInt64(db->pVfs, &iNow); - db->xProfile(db->pProfileArg, p->zSql, (iNow - p->startTime)*1000000); + iElapse = (iNow - p->startTime)*1000000; + if( db->xProfile ){ + db->xProfile(db->pProfileArg, p->zSql, iElapse); + } + if( db->mTrace & SQLITE_TRACE_PROFILE ){ + db->xTrace(SQLITE_TRACE_PROFILE, db->pTraceArg, p, (void*)&iElapse); + } p->startTime = 0; } /* ** The checkProfileCallback(DB,P) macro checks to see if a profile callback ** is needed, and it invokes the callback if it is needed. @@ -75027,11 +75474,11 @@ int nEntry; sqlite3BtreeEnter(pBt); nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt)); sqlite3BtreeLeave(pBt); if( db->xWalCallback && nEntry>0 && rc==SQLITE_OK ){ - rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zName, nEntry); + rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zDbSName, nEntry); } } } #endif return rc; @@ -75104,11 +75551,12 @@ assert( db->nVdbeWrite>0 || db->autoCommit==0 || (db->nDeferredCons==0 && db->nDeferredImmCons==0) ); #ifndef SQLITE_OMIT_TRACE - if( db->xProfile && !db->init.busy && p->zSql ){ + if( (db->xProfile || (db->mTrace & SQLITE_TRACE_PROFILE)!=0) + && !db->init.busy && p->zSql ){ sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime); }else{ assert( p->startTime==0 ); } #endif @@ -76138,10 +76586,43 @@ #endif v = pVdbe->aCounter[op]; if( resetFlag ) pVdbe->aCounter[op] = 0; return (int)v; } + +/* +** Return the SQL associated with a prepared statement +*/ +SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt){ + Vdbe *p = (Vdbe *)pStmt; + return p ? p->zSql : 0; +} + +/* +** Return the SQL associated with a prepared statement with +** bound parameters expanded. Space to hold the returned string is +** obtained from sqlite3_malloc(). The caller is responsible for +** freeing the returned string by passing it to sqlite3_free(). +** +** The SQLITE_TRACE_SIZE_LIMIT puts an upper bound on the size of +** expanded bound parameters. +*/ +SQLITE_API char *SQLITE_STDCALL sqlite3_expanded_sql(sqlite3_stmt *pStmt){ +#ifdef SQLITE_OMIT_TRACE + return 0; +#else + char *z = 0; + const char *zSql = sqlite3_sql(pStmt); + if( zSql ){ + Vdbe *p = (Vdbe *)pStmt; + sqlite3_mutex_enter(p->db->mutex); + z = sqlite3VdbeExpandSql(p, zSql); + sqlite3_mutex_leave(p->db->mutex); + } + return z; +#endif +} #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* ** Allocate and populate an UnpackedRecord structure based on the serialized ** record in nKey/pKey. Return a pointer to the new UnpackedRecord structure @@ -76185,12 +76666,11 @@ /* If the old.* record has not yet been loaded into memory, do so now. */ if( p->pUnpacked==0 ){ u32 nRec; u8 *aRec; - rc = sqlite3BtreeDataSize(p->pCsr->uc.pCursor, &nRec); - if( rc!=SQLITE_OK ) goto preupdate_old_out; + nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor); aRec = sqlite3DbMallocRaw(db, nRec); if( !aRec ) goto preupdate_old_out; rc = sqlite3BtreeData(p->pCsr->uc.pCursor, 0, nRec, aRec); if( rc==SQLITE_OK ){ p->pUnpacked = vdbeUnpackRecord(&p->keyinfo, nRec, aRec); @@ -76474,14 +76954,17 @@ int n; /* Length of a token prefix */ int nToken; /* Length of the parameter token */ int i; /* Loop counter */ Mem *pVar; /* Value of a host parameter */ StrAccum out; /* Accumulate the output here */ +#ifndef SQLITE_OMIT_UTF16 + Mem utf8; /* Used to convert UTF16 parameters into UTF8 for display */ +#endif char zBase[100]; /* Initial working space */ db = p->db; - sqlite3StrAccumInit(&out, db, zBase, sizeof(zBase), + sqlite3StrAccumInit(&out, 0, zBase, sizeof(zBase), db->aLimit[SQLITE_LIMIT_LENGTH]); if( db->nVdbeExec>1 ){ while( *zRawSql ){ const char *zStart = zRawSql; while( *(zRawSql++)!='\n' && *zRawSql ); @@ -76528,16 +77011,18 @@ sqlite3XPrintf(&out, "%!.15g", pVar->u.r); }else if( pVar->flags & MEM_Str ){ int nOut; /* Number of bytes of the string text to include in output */ #ifndef SQLITE_OMIT_UTF16 u8 enc = ENC(db); - Mem utf8; if( enc!=SQLITE_UTF8 ){ memset(&utf8, 0, sizeof(utf8)); utf8.db = db; sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, enc, SQLITE_STATIC); - sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8); + if( SQLITE_NOMEM==sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8) ){ + out.accError = STRACCUM_NOMEM; + out.nAlloc = 0; + } pVar = &utf8; } #endif nOut = pVar->n; #ifdef SQLITE_TRACE_SIZE_LIMIT @@ -76575,10 +77060,11 @@ } #endif } } } + if( out.accError ) sqlite3StrAccumReset(&out); return sqlite3StrAccumFinish(&out); } #endif /* #ifndef SQLITE_OMIT_TRACE */ @@ -77107,12 +77593,12 @@ ****************************************************************************** ** ** This file contains inline asm code for retrieving "high-performance" ** counters for x86 class CPUs. */ -#ifndef _HWTIME_H_ -#define _HWTIME_H_ +#ifndef SQLITE_HWTIME_H +#define SQLITE_HWTIME_H /* ** The following routine only works on pentium-class (or newer) processors. ** It uses the RDTSC opcode to read the cycle count value out of the ** processor and returns that value. This can be used for high-res @@ -77176,11 +77662,11 @@ */ SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } #endif -#endif /* !defined(_HWTIME_H_) */ +#endif /* !defined(SQLITE_HWTIME_H) */ /************** End of hwtime.h **********************************************/ /************** Continuing where we left off in vdbe.c ***********************/ #endif @@ -78055,10 +78541,14 @@ || (pMem[i].flags & (MEM_Str|MEM_Blob))==0 ); sqlite3VdbeMemNulTerminate(&pMem[i]); REGISTER_TRACE(pOp->p1+i, &pMem[i]); } if( db->mallocFailed ) goto no_mem; + + if( db->mTrace & SQLITE_TRACE_ROW ){ + db->xTrace(SQLITE_TRACE_ROW, db->pTraceArg, p, 0); + } /* Return SQLITE_ROW */ p->pc = (int)(pOp - aOp) + 1; rc = SQLITE_ROW; @@ -78689,10 +79179,11 @@ affinity = pOp->p5 & SQLITE_AFF_MASK; if( affinity>=SQLITE_AFF_NUMERIC ){ if( (flags1 | flags3)&MEM_Str ){ if( (flags1 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn1,0); + flags3 = pIn3->flags; } if( (flags3 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn3,0); } } @@ -78701,10 +79192,11 @@ testcase( pIn1->flags & MEM_Int ); testcase( pIn1->flags & MEM_Real ); sqlite3VdbeMemStringify(pIn1, encoding, 1); testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) ); flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask); + flags3 = pIn3->flags; } if( (flags3 & MEM_Str)==0 && (flags3 & (MEM_Int|MEM_Real))!=0 ){ testcase( pIn3->flags & MEM_Int ); testcase( pIn3->flags & MEM_Real ); sqlite3VdbeMemStringify(pIn3, encoding, 1); @@ -79053,11 +79545,10 @@ ** the result is guaranteed to only be used as the argument of a length() ** or typeof() function, respectively. The loading of large blobs can be ** skipped for length() and all content loading can be skipped for typeof(). */ case OP_Column: { - i64 payloadSize64; /* Number of bytes in the record */ int p2; /* column number to retrieve */ VdbeCursor *pC; /* The VDBE cursor */ BtCursor *pCrsr; /* The BTree cursor */ u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */ int len; /* The length of the serialized data for the column */ @@ -79076,10 +79567,11 @@ pC = p->apCsr[pOp->p1]; p2 = pOp->p2; /* If the cursor cache is stale, bring it up-to-date */ rc = sqlite3VdbeCursorMoveto(&pC, &p2); + if( rc ) goto abort_due_to_error; assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); pDest = &aMem[pOp->p3]; memAboutToChange(p, pDest); assert( pOp->p1>=0 && pOp->p1nCursor ); @@ -79089,12 +79581,11 @@ assert( pC->eCurType!=CURTYPE_VTAB ); assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow ); assert( pC->eCurType!=CURTYPE_SORTER ); pCrsr = pC->uc.pCursor; - if( rc ) goto abort_due_to_error; - if( pC->cacheStatus!=p->cacheCtr ){ + if( pC->cacheStatus!=p->cacheCtr ){ /*OPTIMIZATION-IF-FALSE*/ if( pC->nullRow ){ if( pC->eCurType==CURTYPE_PSEUDO ){ assert( pC->uc.pseudoTableReg>0 ); pReg = &aMem[pC->uc.pseudoTableReg]; assert( pReg->flags & MEM_Blob ); @@ -79106,26 +79597,13 @@ goto op_column_out; } }else{ assert( pC->eCurType==CURTYPE_BTREE ); assert( pCrsr ); - if( pC->isTable==0 ){ - assert( sqlite3BtreeCursorIsValid(pCrsr) ); - VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &payloadSize64); - assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */ - /* sqlite3BtreeParseCellPtr() uses getVarint32() to extract the - ** payload size, so it is impossible for payloadSize64 to be - ** larger than 32 bits. */ - assert( (payloadSize64 & SQLITE_MAX_U32)==(u64)payloadSize64 ); - pC->aRow = sqlite3BtreeKeyFetch(pCrsr, &avail); - pC->payloadSize = (u32)payloadSize64; - }else{ - assert( sqlite3BtreeCursorIsValid(pCrsr) ); - VVA_ONLY(rc =) sqlite3BtreeDataSize(pCrsr, &pC->payloadSize); - assert( rc==SQLITE_OK ); /* DataSize() cannot fail */ - pC->aRow = sqlite3BtreeDataFetch(pCrsr, &avail); - } + assert( sqlite3BtreeCursorIsValid(pCrsr) ); + pC->payloadSize = sqlite3BtreePayloadSize(pCrsr); + pC->aRow = sqlite3BtreePayloadFetch(pCrsr, &avail); assert( avail<=65536 ); /* Maximum page size is 64KiB */ if( pC->payloadSize <= (u32)avail ){ pC->szRow = pC->payloadSize; }else if( pC->payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; @@ -79137,11 +79615,11 @@ pC->iHdrOffset = getVarint32(pC->aRow, offset); pC->nHdrParsed = 0; aOffset[0] = offset; - if( availaRow does not have to hold the entire row, but it does at least ** need to cover the header of the record. If pC->aRow does not contain ** the complete header, then set it to zero, forcing the header to be ** dynamically allocated. */ pC->aRow = 0; @@ -79158,28 +79636,28 @@ */ if( offset > 98307 || offset > pC->payloadSize ){ rc = SQLITE_CORRUPT_BKPT; goto abort_due_to_error; } - } - - /* The following goto is an optimization. It can be omitted and - ** everything will still work. But OP_Column is measurably faster - ** by skipping the subsequent conditional, which is always true. - */ - assert( pC->nHdrParsed<=p2 ); /* Conditional skipped */ - goto op_column_read_header; + }else if( offset>0 ){ /*OPTIMIZATION-IF-TRUE*/ + /* The following goto is an optimization. It can be omitted and + ** everything will still work. But OP_Column is measurably faster + ** by skipping the subsequent conditional, which is always true. + */ + zData = pC->aRow; + assert( pC->nHdrParsed<=p2 ); /* Conditional skipped */ + goto op_column_read_header; + } } /* Make sure at least the first p2+1 entries of the header have been ** parsed and valid information is in aOffset[] and pC->aType[]. */ if( pC->nHdrParsed<=p2 ){ /* If there is more header available for parsing in the record, try ** to extract additional fields up through the p2+1-th field */ - op_column_read_header: if( pC->iHdrOffsetaRow==0 ){ memset(&sMem, 0, sizeof(sMem)); rc = sqlite3VdbeMemFromBtree(pCrsr, 0, aOffset[0], !pC->isTable, &sMem); @@ -79188,15 +79666,15 @@ }else{ zData = pC->aRow; } /* Fill in pC->aType[i] and aOffset[i] values through the p2-th field. */ + op_column_read_header: i = pC->nHdrParsed; offset64 = aOffset[i]; zHdr = zData + pC->iHdrOffset; zEndHdr = zData + aOffset[0]; - assert( i<=p2 && zHdraType[i++] = t; aOffset[i] = (u32)(offset64 & 0xffffffff); }while( i<=p2 && zHdrnHdrParsed = i; - pC->iHdrOffset = (u32)(zHdr - zData); - + /* The record is corrupt if any of the following are true: ** (1) the bytes of the header extend past the declared header size ** (2) the entire header was used but not all data was used ** (3) the end of the data extends beyond the end of the record. */ @@ -79219,12 +79695,14 @@ ){ if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem); rc = SQLITE_CORRUPT_BKPT; goto abort_due_to_error; } + + pC->nHdrParsed = i; + pC->iHdrOffset = (u32)(zHdr - zData); if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem); - }else{ t = 0; } /* If after trying to extract new entries from the header, nHdrParsed is @@ -79248,13 +79726,14 @@ ** all valid. */ assert( p2nHdrParsed ); assert( rc==SQLITE_OK ); assert( sqlite3VdbeCheckMemInvariants(pDest) ); - if( VdbeMemDynamic(pDest) ) sqlite3VdbeMemSetNull(pDest); + if( VdbeMemDynamic(pDest) ){ + sqlite3VdbeMemSetNull(pDest); + } assert( t==pC->aType[p2] ); - pDest->enc = encoding; if( pC->szRow>=aOffset[p2+1] ){ /* This is the common case where the desired content fits on the original ** page - where the content is not on an overflow page */ zData = pC->aRow + aOffset[p2]; if( t<12 ){ @@ -79264,10 +79743,11 @@ ** a MEM_Ephem value. This branch is a fast short-cut that is equivalent ** to calling sqlite3VdbeSerialGet() and sqlite3VdbeDeephemeralize(). */ static const u16 aFlag[] = { MEM_Blob, MEM_Str|MEM_Term }; pDest->n = len = (t-12)/2; + pDest->enc = encoding; if( pDest->szMalloc < len+2 ){ pDest->flags = MEM_Null; if( sqlite3VdbeMemGrow(pDest, len+2, 0) ) goto no_mem; }else{ pDest->z = pDest->zMalloc; @@ -79276,10 +79756,11 @@ pDest->z[len] = 0; pDest->z[len+1] = 0; pDest->flags = aFlag[t&1]; } }else{ + pDest->enc = encoding; /* This branch happens only when content is on overflow pages */ if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0 && ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0)) || (len = sqlite3VdbeSerialTypeLen(t))==0 ){ @@ -80693,10 +81174,34 @@ if( takeJump || !alreadyExists ) goto jump_to_p2; } break; } +/* Opcode: SeekRowid P1 P2 P3 * * +** Synopsis: intkey=r[P3] +** +** P1 is the index of a cursor open on an SQL table btree (with integer +** keys). If register P3 does not contain an integer or if P1 does not +** contain a record with rowid P3 then jump immediately to P2. +** Or, if P2 is 0, raise an SQLITE_CORRUPT error. If P1 does contain +** a record with rowid P3 then +** leave the cursor pointing at that record and fall through to the next +** instruction. +** +** The OP_NotExists opcode performs the same operation, but with OP_NotExists +** the P3 register must be guaranteed to contain an integer value. With this +** opcode, register P3 might not contain an integer. +** +** The OP_NotFound opcode performs the same operation on index btrees +** (with arbitrary multi-value keys). +** +** This opcode leaves the cursor in a state where it cannot be advanced +** in either direction. In other words, the Next and Prev opcodes will +** not work following this opcode. +** +** See also: Found, NotFound, NoConflict, SeekRowid +*/ /* Opcode: NotExists P1 P2 P3 * * ** Synopsis: intkey=r[P3] ** ** P1 is the index of a cursor open on an SQL table btree (with integer ** keys). P3 is an integer rowid. If P1 does not contain a record with @@ -80703,26 +81208,37 @@ ** rowid P3 then jump immediately to P2. Or, if P2 is 0, raise an ** SQLITE_CORRUPT error. If P1 does contain a record with rowid P3 then ** leave the cursor pointing at that record and fall through to the next ** instruction. ** +** The OP_SeekRowid opcode performs the same operation but also allows the +** P3 register to contain a non-integer value, in which case the jump is +** always taken. This opcode requires that P3 always contain an integer. +** ** The OP_NotFound opcode performs the same operation on index btrees ** (with arbitrary multi-value keys). ** ** This opcode leaves the cursor in a state where it cannot be advanced ** in either direction. In other words, the Next and Prev opcodes will ** not work following this opcode. ** -** See also: Found, NotFound, NoConflict +** See also: Found, NotFound, NoConflict, SeekRowid */ -case OP_NotExists: { /* jump, in3 */ +case OP_SeekRowid: { /* jump, in3 */ VdbeCursor *pC; BtCursor *pCrsr; int res; u64 iKey; pIn3 = &aMem[pOp->p3]; + if( (pIn3->flags & MEM_Int)==0 ){ + applyAffinity(pIn3, SQLITE_AFF_NUMERIC, encoding); + if( (pIn3->flags & MEM_Int)==0 ) goto jump_to_p2; + } + /* Fall through into OP_NotExists */ +case OP_NotExists: /* jump, in3 */ + pIn3 = &aMem[pOp->p3]; assert( pIn3->flags & MEM_Int ); assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); #ifdef SQLITE_DEBUG @@ -80836,12 +81352,11 @@ } if( res ){ v = 1; /* IMP: R-61914-48074 */ }else{ assert( sqlite3BtreeCursorIsValid(pC->uc.pCursor) ); - rc = sqlite3BtreeKeySize(pC->uc.pCursor, &v); - assert( rc==SQLITE_OK ); /* Cannot fail following BtreeLast() */ + v = sqlite3BtreeIntegerKey(pC->uc.pCursor); if( v>=MAX_ROWID ){ pC->useRandomRowid = 1; }else{ v++; /* IMP: R-29538-34987 */ } @@ -80920,14 +81435,16 @@ ** incremented (otherwise not). If the OPFLAG_LASTROWID flag of P5 is set, ** then rowid is stored for subsequent return by the ** sqlite3_last_insert_rowid() function (otherwise it is unmodified). ** ** If the OPFLAG_USESEEKRESULT flag of P5 is set and if the result of -** the last seek operation (OP_NotExists) was a success, then this +** the last seek operation (OP_NotExists or OP_SeekRowid) was a success, +** then this ** operation will not attempt to find the appropriate row before doing ** the insert but will instead overwrite the row that the cursor is -** currently pointing to. Presumably, the prior OP_NotExists opcode +** currently pointing to. Presumably, the prior OP_NotExists or +** OP_SeekRowid opcode ** has already positioned the cursor correctly. This is an optimization ** that boosts performance by avoiding redundant seeks. ** ** If the OPFLAG_ISUPDATE flag is set, then this opcode is part of an ** UPDATE operation. Otherwise (if the flag is clear) then this opcode @@ -80955,17 +81472,16 @@ */ case OP_Insert: case OP_InsertInt: { Mem *pData; /* MEM cell holding data for the record to be inserted */ Mem *pKey; /* MEM cell holding key for the record */ - i64 iKey; /* The integer ROWID or key for the record to be inserted */ VdbeCursor *pC; /* Cursor to table into which insert is written */ - int nZero; /* Number of zero-bytes to append */ int seekResult; /* Result of prior seek or 0 if no USESEEKRESULT flag */ const char *zDb; /* database name - used by the update hook */ Table *pTab; /* Table structure - used by update and pre-update hooks */ int op; /* Opcode for update hook: SQLITE_UPDATE or SQLITE_INSERT */ + BtreePayload x; /* Payload to be inserted */ op = 0; pData = &aMem[pOp->p2]; assert( pOp->p1>=0 && pOp->p1nCursor ); assert( memIsValid(pData) ); @@ -80980,20 +81496,20 @@ if( pOp->opcode==OP_Insert ){ pKey = &aMem[pOp->p3]; assert( pKey->flags & MEM_Int ); assert( memIsValid(pKey) ); REGISTER_TRACE(pOp->p3, pKey); - iKey = pKey->u.i; + x.nKey = pKey->u.i; }else{ assert( pOp->opcode==OP_InsertInt ); - iKey = pOp->p3; + x.nKey = pOp->p3; } if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){ assert( pC->isTable ); assert( pC->iDb>=0 ); - zDb = db->aDb[pC->iDb].zName; + zDb = db->aDb[pC->iDb].zDbSName; pTab = pOp->p4.pTab; assert( HasRowid(pTab) ); op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT); }else{ pTab = 0; /* Not needed. Silence a comiler warning. */ @@ -81004,39 +81520,41 @@ /* Invoke the pre-update hook, if any */ if( db->xPreUpdateCallback && pOp->p4type==P4_TABLE && !(pOp->p5 & OPFLAG_ISUPDATE) ){ - sqlite3VdbePreUpdateHook(p, pC, SQLITE_INSERT, zDb, pTab, iKey, pOp->p2); + sqlite3VdbePreUpdateHook(p, pC, SQLITE_INSERT, zDb, pTab, x.nKey, pOp->p2); } #endif if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++; - if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = lastRowid = iKey; + if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = lastRowid = x.nKey; if( pData->flags & MEM_Null ){ - pData->z = 0; - pData->n = 0; + x.pData = 0; + x.nData = 0; }else{ assert( pData->flags & (MEM_Blob|MEM_Str) ); + x.pData = pData->z; + x.nData = pData->n; } seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0); if( pData->flags & MEM_Zero ){ - nZero = pData->u.nZero; + x.nZero = pData->u.nZero; }else{ - nZero = 0; + x.nZero = 0; } - rc = sqlite3BtreeInsert(pC->uc.pCursor, 0, iKey, - pData->z, pData->n, nZero, + x.pKey = 0; + rc = sqlite3BtreeInsert(pC->uc.pCursor, &x, (pOp->p5 & OPFLAG_APPEND)!=0, seekResult ); pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; /* Invoke the update-hook if required. */ if( rc ) goto abort_due_to_error; if( db->xUpdateCallback && op ){ - db->xUpdateCallback(db->pUpdateArg, op, zDb, pTab->zName, iKey); + db->xUpdateCallback(db->pUpdateArg, op, zDb, pTab->zName, x.nKey); } break; } /* Opcode: Delete P1 P2 P3 P4 P5 @@ -81091,12 +81609,11 @@ #ifdef SQLITE_DEBUG if( pOp->p4type==P4_TABLE && HasRowid(pOp->p4.pTab) && pOp->p5==0 ){ /* If p5 is zero, the seek operation that positioned the cursor prior to ** OP_Delete will have also set the pC->movetoTarget field to the rowid of ** the row that is being deleted */ - i64 iKey = 0; - sqlite3BtreeKeySize(pC->uc.pCursor, &iKey); + i64 iKey = sqlite3BtreeIntegerKey(pC->uc.pCursor); assert( pC->movetoTarget==iKey ); } #endif /* If the update-hook or pre-update-hook will be invoked, set zDb to @@ -81105,14 +81622,14 @@ ** last moved with OP_Next or OP_Prev, not Seek or NotFound, set ** VdbeCursor.movetoTarget to the current rowid. */ if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){ assert( pC->iDb>=0 ); assert( pOp->p4.pTab!=0 ); - zDb = db->aDb[pC->iDb].zName; + zDb = db->aDb[pC->iDb].zDbSName; pTab = pOp->p4.pTab; if( (pOp->p5 & OPFLAG_SAVEPOSITION)!=0 && pC->isTable ){ - sqlite3BtreeKeySize(pC->uc.pCursor, &pC->movetoTarget); + pC->movetoTarget = sqlite3BtreeIntegerKey(pC->uc.pCursor); } }else{ zDb = 0; /* Not needed. Silence a compiler warning. */ pTab = 0; /* Not needed. Silence a compiler warning. */ } @@ -81262,11 +81779,10 @@ case OP_RowKey: case OP_RowData: { VdbeCursor *pC; BtCursor *pCrsr; u32 n; - i64 n64; pOut = &aMem[pOp->p2]; memAboutToChange(p, pOut); /* Note that RowKey and RowData are really exactly the same instruction */ @@ -81280,12 +81796,13 @@ assert( pC->nullRow==0 ); assert( pC->uc.pCursor!=0 ); pCrsr = pC->uc.pCursor; /* The OP_RowKey and OP_RowData opcodes always follow OP_NotExists or - ** OP_Rewind/Op_Next with no intervening instructions that might invalidate - ** the cursor. If this where not the case, on of the following assert()s + ** OP_SeekRowid or OP_Rewind/Op_Next with no intervening instructions + ** that might invalidate the cursor. + ** If this where not the case, on of the following assert()s ** would fail. Should this ever change (because of changes in the code ** generator) then the fix would be to insert a call to ** sqlite3VdbeCursorMoveto(). */ assert( pC->deferredMoveto==0 ); @@ -81293,24 +81810,13 @@ #if 0 /* Not required due to the previous to assert() statements */ rc = sqlite3VdbeCursorMoveto(pC); if( rc!=SQLITE_OK ) goto abort_due_to_error; #endif - if( pC->isTable==0 ){ - assert( !pC->isTable ); - VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &n64); - assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */ - if( n64>db->aLimit[SQLITE_LIMIT_LENGTH] ){ - goto too_big; - } - n = (u32)n64; - }else{ - VVA_ONLY(rc =) sqlite3BtreeDataSize(pCrsr, &n); - assert( rc==SQLITE_OK ); /* DataSize() cannot fail */ - if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ - goto too_big; - } + n = sqlite3BtreePayloadSize(pCrsr); + if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ + goto too_big; } testcase( n==0 ); if( sqlite3VdbeMemClearAndResize(pOut, MAX(n,32)) ){ goto no_mem; } @@ -81371,12 +81877,11 @@ if( rc ) goto abort_due_to_error; if( pC->nullRow ){ pOut->flags = MEM_Null; break; } - rc = sqlite3BtreeKeySize(pC->uc.pCursor, &v); - assert( rc==SQLITE_OK ); /* Always so because of CursorRestore() above */ + v = sqlite3BtreeIntegerKey(pC->uc.pCursor); } pOut->u.i = v; break; } @@ -81647,12 +82152,11 @@ ** for tables is OP_Insert. */ case OP_SorterInsert: /* in2 */ case OP_IdxInsert: { /* in2 */ VdbeCursor *pC; - int nKey; - const char *zKey; + BtreePayload x; assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( isSorter(pC)==(pOp->opcode==OP_SorterInsert) ); @@ -81664,13 +82168,16 @@ rc = ExpandBlob(pIn2); if( rc ) goto abort_due_to_error; if( pOp->opcode==OP_SorterInsert ){ rc = sqlite3VdbeSorterWrite(pC, pIn2); }else{ - nKey = pIn2->n; - zKey = pIn2->z; - rc = sqlite3BtreeInsert(pC->uc.pCursor, zKey, nKey, "", 0, 0, pOp->p3, + x.nKey = pIn2->n; + x.pKey = pIn2->z; + x.nData = 0; + x.nZero = 0; + x.pData = 0; + rc = sqlite3BtreeInsert(pC->uc.pCursor, &x, pOp->p3, ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0) ); assert( pC->deferredMoveto==0 ); pC->cacheStatus = CACHE_STALE; } @@ -82085,11 +82592,11 @@ initData.db = db; initData.iDb = pOp->p1; initData.pzErrMsg = &p->zErrMsg; zSql = sqlite3MPrintf(db, "SELECT name, rootpage, sql FROM '%q'.%s WHERE %s ORDER BY rowid", - db->aDb[iDb].zName, zMaster, pOp->p4.z); + db->aDb[iDb].zDbSName, zMaster, pOp->p4.z); if( zSql==0 ){ rc = SQLITE_NOMEM_BKPT; }else{ assert( db->init.busy==0 ); db->init.busy = 1; @@ -82914,19 +83421,18 @@ break; }; #endif /* SQLITE_OMIT_PRAGMA */ #if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH) -/* Opcode: Vacuum * * * * * +/* Opcode: Vacuum P1 * * * * ** -** Vacuum the entire database. This opcode will cause other virtual -** machines to be created and run. It may not be called from within -** a transaction. +** Vacuum the entire database P1. P1 is 0 for "main", and 2 or more +** for an attached database. The "temp" database may not be vacuumed. */ case OP_Vacuum: { assert( p->readOnly==0 ); - rc = sqlite3RunVacuum(&p->zErrMsg, db); + rc = sqlite3RunVacuum(&p->zErrMsg, db, pOp->p1); if( rc ) goto abort_due_to_error; break; } #endif @@ -83434,28 +83940,46 @@ ** ** If P2 is not zero, jump to instruction P2. */ case OP_Init: { /* jump */ char *zTrace; - char *z; + + /* If the P4 argument is not NULL, then it must be an SQL comment string. + ** The "--" string is broken up to prevent false-positives with srcck1.c. + ** + ** This assert() provides evidence for: + ** EVIDENCE-OF: R-50676-09860 The callback can compute the same text that + ** would have been returned by the legacy sqlite3_trace() interface by + ** using the X argument when X begins with "--" and invoking + ** sqlite3_expanded_sql(P) otherwise. + */ + assert( pOp->p4.z==0 || strncmp(pOp->p4.z, "-" "- ", 3)==0 ); #ifndef SQLITE_OMIT_TRACE - if( db->xTrace + if( (db->mTrace & (SQLITE_TRACE_STMT|SQLITE_TRACE_LEGACY))!=0 && !p->doingRerun && (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0 ){ - z = sqlite3VdbeExpandSql(p, zTrace); - db->xTrace(db->pTraceArg, z); - sqlite3DbFree(db, z); +#ifndef SQLITE_OMIT_DEPRECATED + if( db->mTrace & SQLITE_TRACE_LEGACY ){ + void (*x)(void*,const char*) = (void(*)(void*,const char*))db->xTrace; + char *z = sqlite3VdbeExpandSql(p, zTrace); + x(db->pTraceArg, z); + sqlite3_free(z); + }else +#endif + { + (void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, zTrace); + } } #ifdef SQLITE_USE_FCNTL_TRACE zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql); if( zTrace ){ int i; for(i=0; inDb; i++){ if( DbMaskTest(p->btreeMask, i)==0 ) continue; - sqlite3_file_control(db, db->aDb[i].zName, SQLITE_FCNTL_TRACE, zTrace); + sqlite3_file_control(db, db->aDb[i].zDbSName, SQLITE_FCNTL_TRACE, zTrace); } } #endif /* SQLITE_USE_FCNTL_TRACE */ #ifdef SQLITE_DEBUG if( (db->flags & SQLITE_SqlTrace)!=0 @@ -83787,11 +84311,11 @@ rc = SQLITE_ERROR; sqlite3BtreeLeaveAll(db); goto blob_open_out; } pBlob->pTab = pTab; - pBlob->zDb = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zName; + pBlob->zDb = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zDbSName; /* Now search pTab for the exact column. */ for(iCol=0; iColnCol; iCol++) { if( sqlite3StrICmp(pTab->aCol[iCol].zName, zColumn)==0 ){ break; @@ -84026,11 +84550,11 @@ ** slightly more efficient). Since you cannot write to a PK column ** using the incremental-blob API, this works. For the sessions module ** anyhow. */ sqlite3_int64 iKey; - sqlite3BtreeKeySize(p->pCsr, &iKey); + iKey = sqlite3BtreeIntegerKey(p->pCsr); sqlite3VdbePreUpdateHook( v, v->apCsr[0], SQLITE_DELETE, p->zDb, p->pTab, iKey, -1 ); } #endif @@ -85461,41 +85985,47 @@ } /* ** Merge the two sorted lists p1 and p2 into a single list. -** Set *ppOut to the head of the new list. */ -static void vdbeSorterMerge( +static SorterRecord *vdbeSorterMerge( SortSubtask *pTask, /* Calling thread context */ SorterRecord *p1, /* First list to merge */ - SorterRecord *p2, /* Second list to merge */ - SorterRecord **ppOut /* OUT: Head of merged list */ + SorterRecord *p2 /* Second list to merge */ ){ SorterRecord *pFinal = 0; SorterRecord **pp = &pFinal; int bCached = 0; - while( p1 && p2 ){ + assert( p1!=0 && p2!=0 ); + for(;;){ int res; res = pTask->xCompare( pTask, &bCached, SRVAL(p1), p1->nVal, SRVAL(p2), p2->nVal ); if( res<=0 ){ *pp = p1; pp = &p1->u.pNext; p1 = p1->u.pNext; + if( p1==0 ){ + *pp = p2; + break; + } }else{ *pp = p2; pp = &p2->u.pNext; p2 = p2->u.pNext; bCached = 0; + if( p2==0 ){ + *pp = p1; + break; + } } } - *pp = p1 ? p1 : p2; - *ppOut = pFinal; + return pFinal; } /* ** Return the SorterCompare function to compare values collected by the ** sorter object passed as the only argument. @@ -85544,20 +86074,21 @@ pNext = p->u.pNext; } p->u.pNext = 0; for(i=0; aSlot[i]; i++){ - vdbeSorterMerge(pTask, p, aSlot[i], &p); + p = vdbeSorterMerge(pTask, p, aSlot[i]); aSlot[i] = 0; } aSlot[i] = p; p = pNext; } p = 0; for(i=0; i<64; i++){ - vdbeSorterMerge(pTask, p, aSlot[i], &p); + if( aSlot[i]==0 ) continue; + p = p ? vdbeSorterMerge(pTask, p, aSlot[i]) : aSlot[i]; } pList->pList = p; sqlite3_free(aSlot); assert( pTask->pUnpacked->errCode==SQLITE_OK @@ -87332,21 +87863,19 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){ int rc; testcase( ExprHasProperty(pExpr, EP_TokenOnly) ); testcase( ExprHasProperty(pExpr, EP_Reduced) ); rc = pWalker->xExprCallback(pWalker, pExpr); - if( rc==WRC_Continue - && !ExprHasProperty(pExpr,EP_TokenOnly) ){ - if( sqlite3WalkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort; - if( sqlite3WalkExpr(pWalker, pExpr->pRight) ) return WRC_Abort; - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ - if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort; - }else{ - if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort; - } - } - return rc & WRC_Abort; + if( rc || ExprHasProperty(pExpr,EP_TokenOnly) ) return rc & WRC_Abort; + if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort; + if( pExpr->pRight && walkExpr(pWalker, pExpr->pRight) ) return WRC_Abort; + if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort; + }else{ + if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort; + } + return WRC_Continue; } SQLITE_PRIVATE int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){ return pExpr ? walkExpr(pWalker,pExpr) : WRC_Continue; } @@ -87676,12 +88205,12 @@ ** legacy and because it does not hurt anything to just ignore the ** database name. */ zDb = 0; }else{ for(i=0; inDb; i++){ - assert( db->aDb[i].zName ); - if( sqlite3StrICmp(db->aDb[i].zName,zDb)==0 ){ + assert( db->aDb[i].zDbSName ); + if( sqlite3StrICmp(db->aDb[i].zDbSName,zDb)==0 ){ pSchema = db->aDb[i].pSchema; break; } } } @@ -88173,11 +88702,15 @@ } if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){ sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId); pNC->nErr++; is_agg = 0; - }else if( no_such_func && pParse->db->init.busy==0 ){ + }else if( no_such_func && pParse->db->init.busy==0 +#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION + && pParse->explain==0 +#endif + ){ sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId); pNC->nErr++; }else if( wrong_num_args ){ sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()", nId, zId); @@ -90773,10 +91306,15 @@ VdbeComment((v, "%s", pIdx->zName)); assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 ); eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0]; if( prRhsHasNull && !pTab->aCol[iCol].notNull ){ +#ifdef SQLITE_ENABLE_COLUMN_USED_MASK + const i64 sOne = 1; + sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed, + iTab, 0, 0, (u8*)&sOne, P4_INT64); +#endif *prRhsHasNull = ++pParse->nMem; sqlite3SetHasNullFlag(v, iTab, *prRhsHasNull); } sqlite3VdbeJumpHere(v, iAddr); } @@ -90785,11 +91323,11 @@ } /* If no preexisting index is available for the IN clause ** and IN_INDEX_NOOP is an allowed reply ** and the RHS of the IN operator is a list, not a subquery - ** and the RHS is not contant or has two or fewer terms, + ** and the RHS is not constant or has two or fewer terms, ** then it is not worth creating an ephemeral table to evaluate ** the IN operator so return IN_INDEX_NOOP. */ if( eType==0 && (inFlags & IN_INDEX_NOOP_OK) @@ -91177,12 +91715,11 @@ } if( eType==IN_INDEX_ROWID ){ /* In this case, the RHS is the ROWID of table b-tree */ - sqlite3VdbeAddOp2(v, OP_MustBeInt, r1, destIfFalse); VdbeCoverage(v); - sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, destIfFalse, r1); + sqlite3VdbeAddOp3(v, OP_SeekRowid, pExpr->iTable, destIfFalse, r1); VdbeCoverage(v); }else{ /* In this case, the RHS is an index b-tree. */ sqlite3VdbeAddOp4(v, OP_Affinity, r1, 1, 0, &affinity, 1); @@ -91491,11 +92028,11 @@ if( iCol<0 || iCol==pTab->iPKey ){ sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut); }else{ int op = IsVirtual(pTab) ? OP_VColumn : OP_Column; int x = iCol; - if( !HasRowid(pTab) ){ + if( !HasRowid(pTab) && !IsVirtual(pTab) ){ x = sqlite3ColumnOfIndex(sqlite3PrimaryKeyIndex(pTab), iCol); } sqlite3VdbeAddOp3(v, op, iTabCur, x, regOut); } if( iCol>=0 ){ @@ -91894,10 +92431,15 @@ } nFarg = pFarg ? pFarg->nExpr : 0; assert( !ExprHasProperty(pExpr, EP_IntValue) ); zId = pExpr->u.zToken; pDef = sqlite3FindFunction(db, zId, nFarg, enc, 0); +#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION + if( pDef==0 && pParse->explain ){ + pDef = sqlite3FindFunction(db, "unknown", nFarg, enc, 0); + } +#endif if( pDef==0 || pDef->xFinalize!=0 ){ sqlite3ErrorMsg(pParse, "unknown function: %s()", zId); break; } @@ -92915,10 +93457,65 @@ ){ return 1; } return 0; } + +/* +** An instance of the following structure is used by the tree walker +** to determine if an expression can be evaluated by reference to the +** index only, without having to do a search for the corresponding +** table entry. The IdxCover.pIdx field is the index. IdxCover.iCur +** is the cursor for the table. +*/ +struct IdxCover { + Index *pIdx; /* The index to be tested for coverage */ + int iCur; /* Cursor number for the table corresponding to the index */ +}; + +/* +** Check to see if there are references to columns in table +** pWalker->u.pIdxCover->iCur can be satisfied using the index +** pWalker->u.pIdxCover->pIdx. +*/ +static int exprIdxCover(Walker *pWalker, Expr *pExpr){ + if( pExpr->op==TK_COLUMN + && pExpr->iTable==pWalker->u.pIdxCover->iCur + && sqlite3ColumnOfIndex(pWalker->u.pIdxCover->pIdx, pExpr->iColumn)<0 + ){ + pWalker->eCode = 1; + return WRC_Abort; + } + return WRC_Continue; +} + +/* +** Determine if an index pIdx on table with cursor iCur contains will +** the expression pExpr. Return true if the index does cover the +** expression and false if the pExpr expression references table columns +** that are not found in the index pIdx. +** +** An index covering an expression means that the expression can be +** evaluated using only the index and without having to lookup the +** corresponding table entry. +*/ +SQLITE_PRIVATE int sqlite3ExprCoveredByIndex( + Expr *pExpr, /* The index to be tested */ + int iCur, /* The cursor number for the corresponding table */ + Index *pIdx /* The index that might be used for coverage */ +){ + Walker w; + struct IdxCover xcov; + memset(&w, 0, sizeof(w)); + xcov.iCur = iCur; + xcov.pIdx = pIdx; + w.xExprCallback = exprIdxCover; + w.u.pIdxCover = &xcov; + sqlite3WalkExpr(&w, pExpr); + return !w.eCode; +} + /* ** An instance of the following structure is used by the tree walker ** to count references to table columns in the arguments of an ** aggregate function, in order to implement the @@ -93682,11 +94279,11 @@ assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]); if( !pTab ) goto exit_rename_table; iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); - zDb = db->aDb[iDb].zName; + zDb = db->aDb[iDb].zDbSName; db->flags |= SQLITE_PreferBuiltin; /* Get a NULL terminated version of the new table name. */ zName = sqlite3NameFromToken(db, pName); if( !zName ) goto exit_rename_table; @@ -93870,20 +94467,21 @@ char *zCol; /* Null-terminated column definition */ Column *pCol; /* The new column */ Expr *pDflt; /* Default value for the new column */ sqlite3 *db; /* The database connection; */ Vdbe *v = pParse->pVdbe; /* The prepared statement under construction */ + int r1; /* Temporary registers */ db = pParse->db; if( pParse->nErr || db->mallocFailed ) return; assert( v!=0 ); pNew = pParse->pNewTable; assert( pNew ); assert( sqlite3BtreeHoldsAllMutexes(db) ); iDb = sqlite3SchemaToIndex(db, pNew->pSchema); - zDb = db->aDb[iDb].zName; + zDb = db->aDb[iDb].zDbSName; zTab = &pNew->zName[16]; /* Skip the "sqlite_altertab_" prefix on the name */ pCol = &pNew->aCol[pNew->nCol-1]; pDflt = pCol->pDflt; pTab = sqlite3FindTable(db, zTab, zDb); assert( pTab ); @@ -93964,20 +94562,22 @@ ); sqlite3DbFree(db, zCol); db->flags = savedDbFlags; } - /* If the default value of the new column is NULL, then the file - ** format to 2. If the default value of the new column is not NULL, - ** the file format be 3. Back when this feature was first added - ** in 2006, we went to the trouble to upgrade the file format to the - ** minimum support values. But 10-years on, we can assume that all - ** extent versions of SQLite support file-format 4, so we always and - ** unconditionally upgrade to 4. + /* Make sure the schema version is at least 3. But do not upgrade + ** from less than 3 to 4, as that will corrupt any preexisting DESC + ** index. */ - sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, - SQLITE_MAX_FILE_FORMAT); + r1 = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, BTREE_FILE_FORMAT); + sqlite3VdbeUsesBtree(v, iDb); + sqlite3VdbeAddOp2(v, OP_AddImm, r1, -2); + sqlite3VdbeAddOp2(v, OP_IfPos, r1, sqlite3VdbeCurrentAddr(v)+2); + VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, 3); + sqlite3ReleaseTempReg(pParse, r1); /* Reload the schema of the modified table. */ reloadTableSchema(pParse, pTab, pTab->zName); } @@ -94287,18 +94887,18 @@ ** if they do already exist. */ for(i=0; izName))==0 ){ + if( (pStat = sqlite3FindTable(db, zTab, pDb->zDbSName))==0 ){ if( aTable[i].zCols ){ /* The sqlite_statN table does not exist. Create it. Note that a ** side-effect of the CREATE TABLE statement is to leave the rootpage ** of the new table in register pParse->regRoot. This is important ** because the OpenWrite opcode below will be needing it. */ sqlite3NestedParse(pParse, - "CREATE TABLE %Q.%s(%s)", pDb->zName, zTab, aTable[i].zCols + "CREATE TABLE %Q.%s(%s)", pDb->zDbSName, zTab, aTable[i].zCols ); aRoot[i] = pParse->regRoot; aCreateTbl[i] = OPFLAG_P2ISREG; } }else{ @@ -94309,11 +94909,11 @@ aCreateTbl[i] = 0; sqlite3TableLock(pParse, iDb, aRoot[i], 1, zTab); if( zWhere ){ sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE %s=%Q", - pDb->zName, zTab, zWhereType, zWhere + pDb->zDbSName, zTab, zWhereType, zWhere ); }else{ /* The sqlite_stat[134] table already exists. Delete all rows. */ sqlite3VdbeAddOp2(v, OP_Clear, aRoot[i], iDb); } @@ -95071,11 +95671,11 @@ iDb = sqlite3SchemaToIndex(db, pTab->pSchema); assert( iDb>=0 ); assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); #ifndef SQLITE_OMIT_AUTHORIZATION if( sqlite3AuthCheck(pParse, SQLITE_ANALYZE, pTab->zName, 0, - db->aDb[iDb].zName ) ){ + db->aDb[iDb].zDbSName ) ){ return; } #endif /* Establish a read-lock on the table at the shared-cache level. @@ -95461,11 +96061,11 @@ } }else{ /* Form 3: Analyze the fully qualified table name */ iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pTableName); if( iDb>=0 ){ - zDb = db->aDb[iDb].zName; + zDb = db->aDb[iDb].zDbSName; z = sqlite3NameFromToken(db, pTableName); if( z ){ if( (pIdx = sqlite3FindIndex(db, z, zDb))!=0 ){ analyzeTable(pParse, pIdx->pTable, pIdx); }else if( (pTab = sqlite3LocateTable(pParse, 0, z, zDb))!=0 ){ @@ -95921,11 +96521,11 @@ #endif } /* Load new statistics out of the sqlite_stat1 table */ sInfo.db = db; - sInfo.zDatabase = db->aDb[iDb].zName; + sInfo.zDatabase = db->aDb[iDb].zDbSName; if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)!=0 ){ zSql = sqlite3MPrintf(db, "SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase); if( zSql==0 ){ rc = SQLITE_NOMEM_BKPT; @@ -96064,11 +96664,11 @@ if( !db->autoCommit ){ zErrDyn = sqlite3MPrintf(db, "cannot ATTACH database within transaction"); goto attach_error; } for(i=0; inDb; i++){ - char *z = db->aDb[i].zName; + char *z = db->aDb[i].zDbSName; assert( z && zName ); if( sqlite3StrICmp(z, zName)==0 ){ zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName); goto attach_error; } @@ -96129,12 +96729,12 @@ PAGER_SYNCHRONOUS_FULL | (db->flags & PAGER_FLAGS_MASK)); #endif sqlite3BtreeLeave(aNew->pBt); } aNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1; - aNew->zName = sqlite3DbStrDup(db, zName); - if( rc==SQLITE_OK && aNew->zName==0 ){ + aNew->zDbSName = sqlite3DbStrDup(db, zName); + if( rc==SQLITE_OK && aNew->zDbSName==0 ){ rc = SQLITE_NOMEM_BKPT; } #ifdef SQLITE_HAS_CODEC @@ -96242,11 +96842,11 @@ if( zName==0 ) zName = ""; for(i=0; inDb; i++){ pDb = &db->aDb[i]; if( pDb->pBt==0 ) continue; - if( sqlite3StrICmp(pDb->zName, zName)==0 ) break; + if( sqlite3StrICmp(pDb->zDbSName, zName)==0 ) break; } if( i>=db->nDb ){ sqlite3_snprintf(sizeof(zErr),zErr, "no such database: %s", zName); goto detach_error; @@ -96400,11 +97000,11 @@ sqlite3 *db; db = pParse->db; assert( db->nDb>iDb ); pFix->pParse = pParse; - pFix->zDb = db->aDb[iDb].zName; + pFix->zDb = db->aDb[iDb].zDbSName; pFix->pSchema = db->aDb[iDb].pSchema; pFix->zType = zType; pFix->pName = pName; pFix->bVarOnly = (iDb==1); } @@ -96658,14 +97258,15 @@ Parse *pParse, /* The parser context */ const char *zTab, /* Table name */ const char *zCol, /* Column name */ int iDb /* Index of containing database. */ ){ - sqlite3 *db = pParse->db; /* Database handle */ - char *zDb = db->aDb[iDb].zName; /* Name of attached database */ - int rc; /* Auth callback return code */ + sqlite3 *db = pParse->db; /* Database handle */ + char *zDb = db->aDb[iDb].zDbSName; /* Schema name of attached database */ + int rc; /* Auth callback return code */ + if( db->init.busy ) return SQLITE_OK; rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext #ifdef SQLITE_USER_AUTHENTICATION ,db->auth.zAuthUser #endif ); @@ -97132,14 +97733,15 @@ return 0; } #endif for(i=OMIT_TEMPDB; inDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ - if( zDatabase!=0 && sqlite3StrICmp(zDatabase, db->aDb[j].zName) ) continue; - assert( sqlite3SchemaMutexHeld(db, j, 0) ); - p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName); - if( p ) break; + if( zDatabase==0 || sqlite3StrICmp(zDatabase, db->aDb[j].zDbSName)==0 ){ + assert( sqlite3SchemaMutexHeld(db, j, 0) ); + p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName); + if( p ) break; + } } return p; } /* @@ -97152,11 +97754,11 @@ ** routine leaves an error message in pParse->zErrMsg where ** sqlite3FindTable() does not. */ SQLITE_PRIVATE Table *sqlite3LocateTable( Parse *pParse, /* context in which to report errors */ - int isView, /* True if looking for a VIEW rather than a TABLE */ + u32 flags, /* LOCATE_VIEW or LOCATE_NOERR */ const char *zName, /* Name of the table we are looking for */ const char *zDbase /* Name of the database. Might be NULL */ ){ Table *p; @@ -97166,11 +97768,11 @@ return 0; } p = sqlite3FindTable(pParse->db, zName, zDbase); if( p==0 ){ - const char *zMsg = isView ? "no such view" : "no such table"; + const char *zMsg = flags & LOCATE_VIEW ? "no such view" : "no such table"; #ifndef SQLITE_OMIT_VIRTUALTABLE if( sqlite3FindDbName(pParse->db, zDbase)<1 ){ /* If zName is the not the name of a table in the schema created using ** CREATE, then check to see if it is the name of an virtual table that ** can be an eponymous virtual table. */ @@ -97178,16 +97780,18 @@ if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){ return pMod->pEpoTab; } } #endif - if( zDbase ){ - sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName); - }else{ - sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName); + if( (flags & LOCATE_NOERR)==0 ){ + if( zDbase ){ + sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName); + }else{ + sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName); + } + pParse->checkSchema = 1; } - pParse->checkSchema = 1; } return p; } @@ -97200,22 +97804,22 @@ ** non-NULL if it is part of a view or trigger program definition. See ** sqlite3FixSrcList() for details. */ SQLITE_PRIVATE Table *sqlite3LocateTableItem( Parse *pParse, - int isView, + u32 flags, struct SrcList_item *p ){ const char *zDb; assert( p->pSchema==0 || p->zDatabase==0 ); if( p->pSchema ){ int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema); - zDb = pParse->db->aDb[iDb].zName; + zDb = pParse->db->aDb[iDb].zDbSName; }else{ zDb = p->zDatabase; } - return sqlite3LocateTable(pParse, isView, p->zName, zDb); + return sqlite3LocateTable(pParse, flags, p->zName, zDb); } /* ** Locate the in-memory structure that describes ** a particular index given the name of that index @@ -97235,11 +97839,11 @@ assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) ); for(i=OMIT_TEMPDB; inDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ Schema *pSchema = db->aDb[j].pSchema; assert( pSchema ); - if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zName) ) continue; + if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zDbSName) ) continue; assert( sqlite3SchemaMutexHeld(db, j, 0) ); p = sqlite3HashFind(&pSchema->idxHash, zName); if( p ) break; } return p; @@ -97304,12 +97908,12 @@ SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3 *db){ int i, j; for(i=j=2; inDb; i++){ struct Db *pDb = &db->aDb[i]; if( pDb->pBt==0 ){ - sqlite3DbFree(db, pDb->zName); - pDb->zName = 0; + sqlite3DbFree(db, pDb->zDbSName); + pDb->zDbSName = 0; continue; } if( jaDb[j] = db->aDb[i]; } @@ -97419,12 +98023,13 @@ db->lookaside.nOut : 0 ); /* Delete all indices associated with this table. */ for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){ pNext = pIndex->pNext; - assert( pIndex->pSchema==pTable->pSchema ); - if( !db || db->pnBytesFreed==0 ){ + assert( pIndex->pSchema==pTable->pSchema + || (IsVirtual(pTable) && pIndex->idxType!=SQLITE_IDXTYPE_APPDEF) ); + if( (db==0 || db->pnBytesFreed==0) && !IsVirtual(pTable) ){ char *zName = pIndex->zName; TESTONLY ( Index *pOld = ) sqlite3HashInsert( &pIndex->pSchema->idxHash, zName, 0 ); assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); @@ -97524,11 +98129,11 @@ SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *db, const char *zName){ int i = -1; /* Database number */ if( zName ){ Db *pDb; for(i=(db->nDb-1), pDb=&db->aDb[i]; i>=0; i--, pDb--){ - if( 0==sqlite3StrICmp(pDb->zName, zName) ) break; + if( 0==sqlite3StrICmp(pDb->zDbSName, zName) ) break; } } return i; } @@ -97583,11 +98188,11 @@ if( iDb<0 ){ sqlite3ErrorMsg(pParse, "unknown database %T", pName1); return -1; } }else{ - assert( db->init.iDb==0 || db->init.busy ); + assert( db->init.iDb==0 || db->init.busy || (db->flags & SQLITE_Vacuum)!=0); iDb = db->init.iDb; *pUnqual = pName1; } return iDb; } @@ -97694,11 +98299,11 @@ SQLITE_CREATE_TABLE, SQLITE_CREATE_TEMP_TABLE, SQLITE_CREATE_VIEW, SQLITE_CREATE_TEMP_VIEW }; - char *zDb = db->aDb[iDb].zName; + char *zDb = db->aDb[iDb].zDbSName; if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){ goto begin_table_error; } if( !isVirtual && sqlite3AuthCheck(pParse, (int)aCode[isTemp+2*isView], zName, 0, zDb) ){ @@ -97713,11 +98318,11 @@ ** to an sqlite3_declare_vtab() call. In that case only the column names ** and types will be used, so there is no need to test for namespace ** collisions. */ if( !IN_DECLARE_VTAB ){ - char *zDb = db->aDb[iDb].zName; + char *zDb = db->aDb[iDb].zDbSName; if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto begin_table_error; } pTable = sqlite3FindTable(db, zName, zDb); if( pTable ){ @@ -98102,11 +98707,11 @@ ){ Table *pTab = pParse->pNewTable; Column *pCol = 0; int iCol = -1, i; int nTerm; - if( pTab==0 || IN_DECLARE_VTAB ) goto primary_key_exit; + if( pTab==0 ) goto primary_key_exit; if( pTab->tabFlags & TF_HasPrimaryKey ){ sqlite3ErrorMsg(pParse, "table \"%s\" has more than one primary key", pTab->zName); goto primary_key_exit; } @@ -98148,16 +98753,12 @@ #ifndef SQLITE_OMIT_AUTOINCREMENT sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an " "INTEGER PRIMARY KEY"); #endif }else{ - Index *p; - p = sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, - 0, sortOrder, 0); - if( p ){ - p->idxType = SQLITE_IDXTYPE_PRIMARYKEY; - } + sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, + 0, sortOrder, 0, SQLITE_IDXTYPE_PRIMARYKEY); pList = 0; } primary_key_exit: sqlite3ExprListDelete(pParse->db, pList); @@ -98470,33 +99071,49 @@ ** has a WITHOUT ROWID clause. The job of this routine is to convert both ** internal schema data structures and the generated VDBE code so that they ** are appropriate for a WITHOUT ROWID table instead of a rowid table. ** Changes include: ** -** (1) Convert the OP_CreateTable into an OP_CreateIndex. There is +** (1) Set all columns of the PRIMARY KEY schema object to be NOT NULL. +** (2) Convert the OP_CreateTable into an OP_CreateIndex. There is ** no rowid btree for a WITHOUT ROWID. Instead, the canonical ** data storage is a covering index btree. -** (2) Bypass the creation of the sqlite_master table entry +** (3) Bypass the creation of the sqlite_master table entry ** for the PRIMARY KEY as the primary key index is now ** identified by the sqlite_master table entry of the table itself. -** (3) Set the Index.tnum of the PRIMARY KEY Index object in the +** (4) Set the Index.tnum of the PRIMARY KEY Index object in the ** schema to the rootpage from the main table. -** (4) Set all columns of the PRIMARY KEY schema object to be NOT NULL. ** (5) Add all table columns to the PRIMARY KEY Index object ** so that the PRIMARY KEY is a covering index. The surplus ** columns are part of KeyInfo.nXField and are not used for ** sorting or lookup or uniqueness checks. ** (6) Replace the rowid tail on all automatically generated UNIQUE ** indices with the PRIMARY KEY columns. +** +** For virtual tables, only (1) is performed. */ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ Index *pIdx; Index *pPk; int nPk; int i, j; sqlite3 *db = pParse->db; Vdbe *v = pParse->pVdbe; + + /* Mark every PRIMARY KEY column as NOT NULL (except for imposter tables) + */ + if( !db->init.imposterTable ){ + for(i=0; inCol; i++){ + if( (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0 ){ + pTab->aCol[i].notNull = OE_Abort; + } + } + } + + /* The remaining transformations only apply to b-tree tables, not to + ** virtual tables */ + if( IN_DECLARE_VTAB ) return; /* Convert the OP_CreateTable opcode that would normally create the ** root-page for the table into an OP_CreateIndex opcode. The index ** created will become the PRIMARY KEY index. */ @@ -98515,13 +99132,14 @@ pList = sqlite3ExprListAppend(pParse, 0, sqlite3ExprAlloc(db, TK_ID, &ipkToken, 0)); if( pList==0 ) return; pList->a[0].sortOrder = pParse->iPkSortOrder; assert( pParse->pNewTable==pTab ); - pPk = sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0); - if( pPk==0 ) return; - pPk->idxType = SQLITE_IDXTYPE_PRIMARYKEY; + sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0, + SQLITE_IDXTYPE_PRIMARYKEY); + if( db->mallocFailed ) return; + pPk = sqlite3PrimaryKeyIndex(pTab); pTab->iPKey = -1; }else{ pPk = sqlite3PrimaryKeyIndex(pTab); /* Bypass the creation of the PRIMARY KEY btree and the sqlite_master @@ -98545,23 +99163,15 @@ pPk->aiColumn[j++] = pPk->aiColumn[i]; } } pPk->nKeyCol = j; } - pPk->isCovering = 1; assert( pPk!=0 ); + pPk->isCovering = 1; + if( !db->init.imposterTable ) pPk->uniqNotNull = 1; nPk = pPk->nKeyCol; - /* Make sure every column of the PRIMARY KEY is NOT NULL. (Except, - ** do not enforce this for imposter tables.) */ - if( !db->init.imposterTable ){ - for(i=0; iaCol[pPk->aiColumn[i]].notNull = OE_Abort; - } - pPk->uniqNotNull = 1; - } - /* The root page of the PRIMARY KEY is the table root page */ pPk->tnum = pTab->tnum; /* Update the in-memory representation of all UNIQUE indices by converting ** the final rowid column into one or more columns of the PRIMARY KEY. @@ -98801,11 +99411,11 @@ */ sqlite3NestedParse(pParse, "UPDATE %Q.%s " "SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q " "WHERE rowid=#%d", - db->aDb[iDb].zName, SCHEMA_TABLE(iDb), + db->aDb[iDb].zDbSName, SCHEMA_TABLE(iDb), zType, p->zName, p->zName, pParse->regRoot, zStmt, @@ -98816,17 +99426,17 @@ #ifndef SQLITE_OMIT_AUTOINCREMENT /* Check to see if we need to create an sqlite_sequence table for ** keeping track of autoincrement keys. */ - if( p->tabFlags & TF_Autoincrement ){ + if( (p->tabFlags & TF_Autoincrement)!=0 ){ Db *pDb = &db->aDb[iDb]; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); if( pDb->pSchema->pSeqTab==0 ){ sqlite3NestedParse(pParse, "CREATE TABLE %Q.sqlite_sequence(name,seq)", - pDb->zName + pDb->zDbSName ); } } #endif @@ -99136,11 +99746,11 @@ ** is in register NNN. See grammar rules associated with the TK_REGISTER ** token for additional information. */ sqlite3NestedParse(pParse, "UPDATE %Q.%s SET rootpage=%d WHERE #%d AND rootpage=#%d", - pParse->db->aDb[iDb].zName, SCHEMA_TABLE(iDb), iTable, r1, r1); + pParse->db->aDb[iDb].zDbSName, SCHEMA_TABLE(iDb), iTable, r1, r1); #endif sqlite3ReleaseTempReg(pParse, r1); } /* @@ -99212,11 +99822,11 @@ int iDb, /* The database number */ const char *zType, /* "idx" or "tbl" */ const char *zName /* Name of index or table */ ){ int i; - const char *zDbName = pParse->db->aDb[iDb].zName; + const char *zDbName = pParse->db->aDb[iDb].zDbSName; for(i=1; i<=4; i++){ char zTab[24]; sqlite3_snprintf(sizeof(zTab),zTab,"sqlite_stat%d",i); if( sqlite3FindTable(pParse->db, zTab, zDbName) ){ sqlite3NestedParse(pParse, @@ -99265,11 +99875,11 @@ ** move as a result of the drop (can happen in auto-vacuum mode). */ if( pTab->tabFlags & TF_Autoincrement ){ sqlite3NestedParse(pParse, "DELETE FROM %Q.sqlite_sequence WHERE name=%Q", - pDb->zName, pTab->zName + pDb->zDbSName, pTab->zName ); } #endif /* Drop all SQLITE_MASTER table and index entries that refer to the @@ -99279,11 +99889,11 @@ ** created in the temp database that refers to a table in another ** database. */ sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'", - pDb->zName, SCHEMA_TABLE(iDb), pTab->zName); + pDb->zDbSName, SCHEMA_TABLE(iDb), pTab->zName); if( !isView && !IsVirtual(pTab) ){ destroyTable(pParse, pTab); } /* Remove the table entry from SQLite's internal schema and modify @@ -99312,10 +99922,11 @@ } assert( pParse->nErr==0 ); assert( pName->nSrc==1 ); if( sqlite3ReadSchema(pParse) ) goto exit_drop_table; if( noErr ) db->suppressErr++; + assert( isView==0 || isView==LOCATE_VIEW ); pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]); if( noErr ) db->suppressErr--; if( pTab==0 ){ if( noErr ) sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); @@ -99332,11 +99943,11 @@ } #ifndef SQLITE_OMIT_AUTHORIZATION { int code; const char *zTab = SCHEMA_TABLE(iDb); - const char *zDb = db->aDb[iDb].zName; + const char *zDb = db->aDb[iDb].zDbSName; const char *zArg2 = 0; if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){ goto exit_drop_table; } if( isView ){ @@ -99573,11 +100184,11 @@ sqlite3 *db = pParse->db; /* The database connection */ int iDb = sqlite3SchemaToIndex(db, pIndex->pSchema); #ifndef SQLITE_OMIT_AUTHORIZATION if( sqlite3AuthCheck(pParse, SQLITE_REINDEX, pIndex->zName, 0, - db->aDb[iDb].zName ) ){ + db->aDb[iDb].zDbSName ) ){ return; } #endif /* Require a write-lock on the table to perform this operation */ @@ -99682,28 +100293,24 @@ ** currently being constructed by a CREATE TABLE statement. ** ** pList is a list of columns to be indexed. pList will be NULL if this ** is a primary key or unique-constraint on the most recent column added ** to the table currently under construction. -** -** If the index is created successfully, return a pointer to the new Index -** structure. This is used by sqlite3AddPrimaryKey() to mark the index -** as the tables primary key (Index.idxType==SQLITE_IDXTYPE_PRIMARYKEY) */ -SQLITE_PRIVATE Index *sqlite3CreateIndex( +SQLITE_PRIVATE void sqlite3CreateIndex( Parse *pParse, /* All information about this parse */ Token *pName1, /* First part of index name. May be NULL */ Token *pName2, /* Second part of index name. May be NULL */ SrcList *pTblName, /* Table to index. Use pParse->pNewTable if 0 */ ExprList *pList, /* A list of columns to be indexed */ int onError, /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ Token *pStart, /* The CREATE token that begins this statement */ Expr *pPIWhere, /* WHERE clause for partial indices */ int sortOrder, /* Sort order of primary key when pList==NULL */ - int ifNotExist /* Omit error if index already exists */ + int ifNotExist, /* Omit error if index already exists */ + u8 idxType /* The index type */ ){ - Index *pRet = 0; /* Pointer to return */ Table *pTab = 0; /* Table to be indexed */ Index *pIndex = 0; /* The index to be created */ char *zName = 0; /* Name of the index */ int nName; /* Number of characters in zName */ int i, j; @@ -99717,11 +100324,14 @@ int nExtra = 0; /* Space allocated for zExtra[] */ int nExtraCol; /* Number of extra columns needed */ char *zExtra = 0; /* Extra space after the Index object */ Index *pPk = 0; /* PRIMARY KEY index for WITHOUT ROWID tables */ - if( db->mallocFailed || IN_DECLARE_VTAB || pParse->nErr>0 ){ + if( db->mallocFailed || pParse->nErr>0 ){ + goto exit_create_index; + } + if( IN_DECLARE_VTAB && idxType!=SQLITE_IDXTYPE_PRIMARYKEY ){ goto exit_create_index; } if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto exit_create_index; } @@ -99826,11 +100436,11 @@ if( sqlite3FindTable(db, zName, 0)!=0 ){ sqlite3ErrorMsg(pParse, "there is already a table named %s", zName); goto exit_create_index; } } - if( sqlite3FindIndex(db, zName, pDb->zName)!=0 ){ + if( sqlite3FindIndex(db, zName, pDb->zDbSName)!=0 ){ if( !ifNotExist ){ sqlite3ErrorMsg(pParse, "index %s already exists", zName); }else{ assert( !db->init.busy ); sqlite3CodeVerifySchema(pParse, iDb); @@ -99843,17 +100453,24 @@ for(pLoop=pTab->pIndex, n=1; pLoop; pLoop=pLoop->pNext, n++){} zName = sqlite3MPrintf(db, "sqlite_autoindex_%s_%d", pTab->zName, n); if( zName==0 ){ goto exit_create_index; } + + /* Automatic index names generated from within sqlite3_declare_vtab() + ** must have names that are distinct from normal automatic index names. + ** The following statement converts "sqlite3_autoindex..." into + ** "sqlite3_butoindex..." in order to make the names distinct. + ** The "vtab_err.test" test demonstrates the need of this statement. */ + if( IN_DECLARE_VTAB ) zName[7]++; } /* Check for authorization to create an index. */ #ifndef SQLITE_OMIT_AUTHORIZATION { - const char *zDb = pDb->zName; + const char *zDb = pDb->zDbSName; if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iDb), 0, zDb) ){ goto exit_create_index; } i = SQLITE_CREATE_INDEX; if( !OMIT_TEMPDB && iDb==1 ) i = SQLITE_CREATE_TEMP_INDEX; @@ -99906,11 +100523,11 @@ zExtra += nName + 1; memcpy(pIndex->zName, zName, nName+1); pIndex->pTable = pTab; pIndex->onError = (u8)onError; pIndex->uniqNotNull = onError!=OE_None; - pIndex->idxType = pName ? SQLITE_IDXTYPE_APPDEF : SQLITE_IDXTYPE_UNIQUE; + pIndex->idxType = idxType; pIndex->pSchema = db->aDb[iDb].pSchema; pIndex->nKeyCol = pList->nExpr; if( pPIWhere ){ sqlite3ResolveSelfReference(pParse, pTab, NC_PartIdx, pPIWhere, 0); pIndex->pPartIdxWhere = pPIWhere; @@ -100086,11 +100703,11 @@ } if( pIdx->onError==OE_Default ){ pIdx->onError = pIndex->onError; } } - pRet = pIdx; + if( idxType==SQLITE_IDXTYPE_PRIMARYKEY ) pIdx->idxType = idxType; goto exit_create_index; } } } @@ -100098,10 +100715,11 @@ ** in-memory database structures. */ assert( pParse->nErr==0 ); if( db->init.busy ){ Index *p; + assert( !IN_DECLARE_VTAB ); assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); p = sqlite3HashInsert(&pIndex->pSchema->idxHash, pIndex->zName, pIndex); if( p ){ assert( p==pIndex ); /* Malloc must have failed */ @@ -100163,11 +100781,11 @@ /* Add an entry in sqlite_master for this index */ sqlite3NestedParse(pParse, "INSERT INTO %Q.%s VALUES('index',%Q,%Q,#%d,%Q);", - db->aDb[iDb].zName, SCHEMA_TABLE(iDb), + db->aDb[iDb].zDbSName, SCHEMA_TABLE(iDb), pIndex->zName, pTab->zName, iMem, zStmt ); @@ -100179,11 +100797,11 @@ if( pTblName ){ sqlite3RefillIndex(pParse, pIndex, iMem); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddParseSchemaOp(v, iDb, sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName)); - sqlite3VdbeAddOp1(v, OP_Expire, 0); + sqlite3VdbeAddOp0(v, OP_Expire); } sqlite3VdbeJumpHere(v, pIndex->tnum); } @@ -100204,11 +100822,10 @@ pOther = pOther->pNext; } pIndex->pNext = pOther->pNext; pOther->pNext = pIndex; } - pRet = pIndex; pIndex = 0; } /* Clean up before exiting */ exit_create_index: @@ -100215,11 +100832,10 @@ if( pIndex ) freeIndex(db, pIndex); sqlite3ExprDelete(db, pPIWhere); sqlite3ExprListDelete(db, pList); sqlite3SrcListDelete(db, pTblName); sqlite3DbFree(db, zName); - return pRet; } /* ** Fill the Index.aiRowEst[] array with default information - information ** to be used when we have not run the ANALYZE command. @@ -100244,14 +100860,15 @@ LogEst *a = pIdx->aiRowLogEst; int nCopy = MIN(ArraySize(aVal), pIdx->nKeyCol); int i; /* Set the first entry (number of rows in the index) to the estimated - ** number of rows in the table. Or 10, if the estimated number of rows - ** in the table is less than that. */ + ** number of rows in the table, or half the number of rows in the table + ** for a partial index. But do not let the estimate drop below 10. */ a[0] = pIdx->pTable->nRowLogEst; - if( a[0]<33 ) a[0] = 33; assert( 33==sqlite3LogEst(10) ); + if( pIdx->pPartIdxWhere!=0 ) a[0] -= 10; assert( 10==sqlite3LogEst(2) ); + if( a[0]<33 ) a[0] = 33; assert( 33==sqlite3LogEst(10) ); /* Estimate that a[1] is 10, a[2] is 9, a[3] is 8, a[4] is 7, a[5] is ** 6 and each subsequent value (if any) is 5. */ memcpy(&a[1], aVal, nCopy*sizeof(LogEst)); for(i=nCopy+1; i<=pIdx->nKeyCol; i++){ @@ -100298,11 +100915,11 @@ iDb = sqlite3SchemaToIndex(db, pIndex->pSchema); #ifndef SQLITE_OMIT_AUTHORIZATION { int code = SQLITE_DROP_INDEX; Table *pTab = pIndex->pTable; - const char *zDb = db->aDb[iDb].zName; + const char *zDb = db->aDb[iDb].zDbSName; const char *zTab = SCHEMA_TABLE(iDb); if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){ goto exit_drop_index; } if( !OMIT_TEMPDB && iDb ) code = SQLITE_DROP_TEMP_INDEX; @@ -100316,11 +100933,11 @@ v = sqlite3GetVdbe(pParse); if( v ){ sqlite3BeginWriteOperation(pParse, 1, iDb); sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE name=%Q AND type='index'", - db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pIndex->zName + db->aDb[iDb].zDbSName, SCHEMA_TABLE(iDb), pIndex->zName ); sqlite3ClearStatTables(pParse, iDb, "idx", pIndex->zName); sqlite3ChangeCookie(pParse, iDb); destroyRootPage(pParse, pIndex->tnum, iDb); sqlite3VdbeAddOp4(v, OP_DropIndex, iDb, 0, 0, pIndex->zName, 0); @@ -100861,11 +101478,11 @@ SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse *pParse, const char *zDb){ sqlite3 *db = pParse->db; int i; for(i=0; inDb; i++){ Db *pDb = &db->aDb[i]; - if( pDb->pBt && (!zDb || 0==sqlite3StrICmp(zDb, pDb->zName)) ){ + if( pDb->pBt && (!zDb || 0==sqlite3StrICmp(zDb, pDb->zDbSName)) ){ sqlite3CodeVerifySchema(pParse, i); } } } @@ -101108,11 +101725,11 @@ } iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pObjName); if( iDb<0 ) return; z = sqlite3NameFromToken(db, pObjName); if( z==0 ) return; - zDb = db->aDb[iDb].zName; + zDb = db->aDb[iDb].zDbSName; pTab = sqlite3FindTable(db, z, zDb); if( pTab ){ reindexTable(pParse, pTab, 0); sqlite3DbFree(db, z); return; @@ -101129,14 +101746,10 @@ #endif /* ** Return a KeyInfo structure that is appropriate for the given Index. ** -** The KeyInfo structure for an index is cached in the Index object. -** So there might be multiple references to the returned pointer. The -** caller should not try to modify the KeyInfo object. -** ** The caller should invoke sqlite3KeyInfoUnref() on the returned object ** when it has finished using it. */ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){ int i; @@ -101826,11 +102439,11 @@ pWhere = sqlite3ExprDup(db, pWhere, 0); pFrom = sqlite3SrcListAppend(db, 0, 0, 0); if( pFrom ){ assert( pFrom->nSrc==1 ); pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName); - pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zName); + pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName); assert( pFrom->a[0].pOn==0 ); assert( pFrom->a[0].pUsing==0 ); } pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0, SF_IncludeHidden, 0, 0); @@ -102013,11 +102626,11 @@ if( sqlite3IsReadOnly(pParse, pTab, (pTrigger?1:0)) ){ goto delete_from_cleanup; } iDb = sqlite3SchemaToIndex(db, pTab->pSchema); assert( iDbnDb ); - zDb = db->aDb[iDb].zName; + zDb = db->aDb[iDb].zDbSName; rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb); assert( rcauth==SQLITE_OK || rcauth==SQLITE_DENY || rcauth==SQLITE_IGNORE ); if( rcauth==SQLITE_DENY ){ goto delete_from_cleanup; } @@ -103364,11 +103977,11 @@ continue; } } c2 = Utf8Read(zString); if( c==c2 ) continue; - if( noCase && c<0x80 && c2<0x80 && sqlite3Tolower(c)==sqlite3Tolower(c2) ){ + if( noCase && sqlite3Tolower(c)==sqlite3Tolower(c2) && c<0x80 && c2<0x80 ){ continue; } if( c==matchOne && zPattern!=zEscaped && c2!=0 ) continue; return 0; } @@ -103939,10 +104552,30 @@ } } sqlite3_result_text(context, (char*)zIn, nIn, SQLITE_TRANSIENT); } + +#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION +/* +** The "unknown" function is automatically substituted in place of +** any unrecognized function name when doing an EXPLAIN or EXPLAIN QUERY PLAN +** when the SQLITE_ENABLE_UNKNOWN_FUNCTION compile-time option is used. +** When the "sqlite3" command-line shell is built using this functionality, +** that allows an EXPLAIN or EXPLAIN QUERY PLAN for complex queries +** involving application-defined functions to be examined in a generic +** sqlite3 shell. +*/ +static void unknownFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + /* no-op */ +} +#endif /*SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION*/ + /* IMP: R-25361-16150 This function is omitted from SQLite by default. It ** is only available if the SQLITE_SOUNDEX compile-time option is used ** when SQLite is built. */ @@ -104410,17 +105043,20 @@ AGGREGATE(count, 1, 0, 0, countStep, countFinalize ), AGGREGATE(group_concat, 1, 0, 0, groupConcatStep, groupConcatFinalize), AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize), LIKEFUNC(glob, 2, &globInfo, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), - #ifdef SQLITE_CASE_SENSITIVE_LIKE +#ifdef SQLITE_CASE_SENSITIVE_LIKE LIKEFUNC(like, 2, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), LIKEFUNC(like, 3, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), - #else +#else LIKEFUNC(like, 2, &likeInfoNorm, SQLITE_FUNC_LIKE), LIKEFUNC(like, 3, &likeInfoNorm, SQLITE_FUNC_LIKE), - #endif +#endif +#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION + FUNCTION(unknown, -1, 0, 0, unknownFunc ), +#endif FUNCTION(coalesce, 1, 0, 0, 0 ), FUNCTION(coalesce, 0, 0, 0, 0 ), FUNCTION2(coalesce, -1, 0, 0, noopFunc, SQLITE_FUNC_COALESCE), }; #ifndef SQLITE_OMIT_ALTERTABLE @@ -105322,11 +105958,11 @@ /* If foreign-keys are disabled, this function is a no-op. */ if( (db->flags&SQLITE_ForeignKeys)==0 ) return; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); - zDb = db->aDb[iDb].zName; + zDb = db->aDb[iDb].zDbSName; /* Loop through all the foreign key constraints for which pTab is the ** child table (the table that the foreign key definition is part of). */ for(pFKey=pTab->pFKey; pFKey; pFKey=pFKey->pNextFrom){ Table *pTo; /* Parent table of foreign key pFKey */ @@ -105823,11 +106459,12 @@ */ SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *db, Table *pTab){ FKey *pFKey; /* Iterator variable */ FKey *pNext; /* Copy of pFKey->pNextFrom */ - assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) ); + assert( db==0 || IsVirtual(pTab) + || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) ); for(pFKey=pTab->pFKey; pFKey; pFKey=pNext){ /* Remove the FK from the fkeyHash hash table. */ if( !db || db->pnBytesFreed==0 ){ if( pFKey->pPrevTo ){ @@ -106061,11 +106698,13 @@ #ifndef SQLITE_OMIT_AUTOINCREMENT /* ** Locate or create an AutoincInfo structure associated with table pTab ** which is in database iDb. Return the register number for the register -** that holds the maximum rowid. +** that holds the maximum rowid. Return zero if pTab is not an AUTOINCREMENT +** table. (Also return zero when doing a VACUUM since we do not want to +** update the AUTOINCREMENT counters during a VACUUM.) ** ** There is at most one AutoincInfo structure per table even if the ** same table is autoincremented multiple times due to inserts within ** triggers. A new AutoincInfo structure is created if this is the ** first use of table pTab. On 2nd and subsequent uses, the original @@ -106084,11 +106723,13 @@ Parse *pParse, /* Parsing context */ int iDb, /* Index of the database holding pTab */ Table *pTab /* The table we are writing to */ ){ int memId = 0; /* Register holding maximum rowid */ - if( pTab->tabFlags & TF_Autoincrement ){ + if( (pTab->tabFlags & TF_Autoincrement)!=0 + && (pParse->db->flags & SQLITE_Vacuum)==0 + ){ Parse *pToplevel = sqlite3ParseToplevel(pParse); AutoincInfo *pInfo; pInfo = pToplevel->pAinc; while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; } @@ -106408,11 +107049,11 @@ goto insert_cleanup; } iDb = sqlite3SchemaToIndex(db, pTab->pSchema); assert( iDbnDb ); pDb = &db->aDb[iDb]; - zDb = pDb->zName; + zDb = pDb->zDbSName; if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb) ){ goto insert_cleanup; } withoutRowid = !HasRowid(pTab); @@ -108233,16 +108874,14 @@ ** shared libraries that want to be imported as extensions into ** an SQLite instance. Shared libraries that intend to be loaded ** as extensions by SQLite should #include this file instead of ** sqlite3.h. */ -#ifndef _SQLITE3EXT_H_ -#define _SQLITE3EXT_H_ +#ifndef SQLITE3EXT_H +#define SQLITE3EXT_H /* #include "sqlite3.h" */ -typedef struct sqlite3_api_routines sqlite3_api_routines; - /* ** The following structure holds pointers to all of the SQLite API ** routines. ** ** WARNING: In order to maintain backwards compatibility, add new @@ -108499,11 +109138,24 @@ int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int); int (*strlike)(const char*,const char*,unsigned int); int (*db_cacheflush)(sqlite3*); /* Version 3.12.0 and later */ int (*system_errno)(sqlite3*); + /* Version 3.14.0 and later */ + int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*); + char *(*expanded_sql)(sqlite3_stmt*); }; + +/* +** This is the function signature used for all extension entry points. It +** is also defined in the file "loadext.c". +*/ +typedef int (*sqlite3_loadext_entry)( + sqlite3 *db, /* Handle to the database. */ + char **pzErrMsg, /* Used to set error string on failure. */ + const sqlite3_api_routines *pThunk /* Extension API function pointers. */ +); /* ** The following macros redefine the API routines so that they are ** redirected through the global sqlite3_api structure. ** @@ -108744,10 +109396,13 @@ #define sqlite3_status64 sqlite3_api->status64 #define sqlite3_strlike sqlite3_api->strlike #define sqlite3_db_cacheflush sqlite3_api->db_cacheflush /* Version 3.12.0 and later */ #define sqlite3_system_errno sqlite3_api->system_errno +/* Version 3.14.0 and later */ +#define sqlite3_trace_v2 sqlite3_api->trace_v2 +#define sqlite3_expanded_sql sqlite3_api->expanded_sql #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) /* This case when the file really is being compiled as a loadable ** extension */ @@ -108761,19 +109416,18 @@ # define SQLITE_EXTENSION_INIT1 /*no-op*/ # define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */ # define SQLITE_EXTENSION_INIT3 /*no-op*/ #endif -#endif /* _SQLITE3EXT_H_ */ +#endif /* SQLITE3EXT_H */ /************** End of sqlite3ext.h ******************************************/ /************** Continuing where we left off in loadext.c ********************/ /* #include "sqliteInt.h" */ /* #include */ #ifndef SQLITE_OMIT_LOAD_EXTENSION - /* ** Some API routines are omitted when various features are ** excluded from a build of SQLite. Substitute a NULL pointer ** for any missing APIs. */ @@ -108839,11 +109493,11 @@ #ifdef SQLITE_OMIT_SHARED_CACHE # define sqlite3_enable_shared_cache 0 #endif -#ifdef SQLITE_OMIT_TRACE +#if defined(SQLITE_OMIT_TRACE) || defined(SQLITE_OMIT_DEPRECATED) # define sqlite3_profile 0 # define sqlite3_trace 0 #endif #ifdef SQLITE_OMIT_GET_TABLE @@ -108858,10 +109512,14 @@ #define sqlite3_blob_open 0 #define sqlite3_blob_read 0 #define sqlite3_blob_write 0 #define sqlite3_blob_reopen 0 #endif + +#if defined(SQLITE_OMIT_TRACE) +# define sqlite3_trace_v2 0 +#endif /* ** The following structure contains pointers to all SQLite API routines. ** A pointer to this structure is passed into extensions when they are ** loaded so that the extension can make calls back into the SQLite @@ -109164,11 +109822,14 @@ /* Version 3.10.0 and later */ sqlite3_status64, sqlite3_strlike, sqlite3_db_cacheflush, /* Version 3.12.0 and later */ - sqlite3_system_errno + sqlite3_system_errno, + /* Version 3.14.0 and later */ + sqlite3_trace_v2, + sqlite3_expanded_sql }; /* ** Attempt to load an SQLite extension library contained in the file ** zFile. The entry point is zProc. zProc may be 0 in which case a @@ -109187,17 +109848,18 @@ const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */ char **pzErrMsg /* Put error message here if not 0 */ ){ sqlite3_vfs *pVfs = db->pVfs; void *handle; - int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*); + sqlite3_loadext_entry xInit; char *zErrmsg = 0; const char *zEntry; char *zAltEntry = 0; void **aHandle; u64 nMsg = 300 + sqlite3Strlen30(zFile); int ii; + int rc; /* Shared library endings to try if zFile cannot be loaded as written */ static const char *azEndings[] = { #if SQLITE_OS_WIN "dll" @@ -109245,12 +109907,11 @@ sqlite3OsDlError(pVfs, nMsg-1, zErrmsg); } } return SQLITE_ERROR; } - xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*)) - sqlite3OsDlSym(pVfs, handle, zEntry); + xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry); /* If no entry point was specified and the default legacy ** entry point name "sqlite3_extension_init" was not found, then ** construct an entry point name "sqlite3_X_init" where the X is ** replaced by the lowercase value of every ASCII alphabetic @@ -109278,12 +109939,11 @@ zAltEntry[iEntry++] = (char)sqlite3UpperToLower[(unsigned)c]; } } memcpy(zAltEntry+iEntry, "_init", 6); zEntry = zAltEntry; - xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*)) - sqlite3OsDlSym(pVfs, handle, zEntry); + xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry); } if( xInit==0 ){ if( pzErrMsg ){ nMsg += sqlite3Strlen30(zEntry); *pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg); @@ -109296,11 +109956,13 @@ sqlite3OsDlClose(pVfs, handle); sqlite3_free(zAltEntry); return SQLITE_ERROR; } sqlite3_free(zAltEntry); - if( xInit(db, &zErrmsg, &sqlite3Apis) ){ + rc = xInit(db, &zErrmsg, &sqlite3Apis); + if( rc ){ + if( rc==SQLITE_OK_LOAD_PERMANENTLY ) return SQLITE_OK; if( pzErrMsg ){ *pzErrMsg = sqlite3_mprintf("error during initialization: %s", zErrmsg); } sqlite3_free(zErrmsg); sqlite3OsDlClose(pVfs, handle); @@ -109407,11 +110069,13 @@ /* ** Register a statically linked extension that is automatically ** loaded by every new database connection. */ -SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xInit)(void)){ +SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension( + void (*xInit)(void) +){ int rc = SQLITE_OK; #ifndef SQLITE_OMIT_AUTOINIT rc = sqlite3_initialize(); if( rc ){ return rc; @@ -109452,11 +110116,13 @@ ** routine is a no-op. ** ** Return 1 if xInit was found on the list and removed. Return 0 if xInit ** was not on the list. */ -SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xInit)(void)){ +SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension( + void (*xInit)(void) +){ #if SQLITE_THREADSAFE sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); #endif int i; int n = 0; @@ -109501,11 +110167,11 @@ */ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){ u32 i; int go = 1; int rc; - int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*); + sqlite3_loadext_entry xInit; wsdAutoextInit; if( wsdAutoext.nExt==0 ){ /* Common case: early out without every having to acquire a mutex */ return; @@ -109518,12 +110184,11 @@ sqlite3_mutex_enter(mutex); if( i>=wsdAutoext.nExt ){ xInit = 0; go = 0; }else{ - xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*)) - wsdAutoext.aExt[i]; + xInit = (sqlite3_loadext_entry)wsdAutoext.aExt[i]; } sqlite3_mutex_leave(mutex); zErrmsg = 0; if( xInit && (rc = xInit(db, &zErrmsg, &sqlite3Apis))!=0 ){ sqlite3ErrorWithMsg(db, rc, @@ -110342,11 +111007,11 @@ }else{ zRight = sqlite3NameFromToken(db, pValue); } assert( pId2 ); - zDb = pId2->n>0 ? pDb->zName : 0; + zDb = pId2->n>0 ? pDb->zDbSName : 0; if( sqlite3AuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight, zDb) ){ goto pragma_out; } /* Send an SQLITE_FCNTL_PRAGMA file-control to the underlying VFS @@ -111034,11 +111699,11 @@ /* Many of the flag-pragmas modify the code generated by the SQL ** compiler (eg. count_changes). So add an opcode to expire all ** compiled SQL statements after modifying a pragma value. */ - sqlite3VdbeAddOp2(v, OP_Expire, 0, 0); + sqlite3VdbeAddOp0(v, OP_Expire); setAllPagerFlags(db); } break; } #endif /* SQLITE_OMIT_FLAG_PRAGMAS */ @@ -111056,11 +111721,11 @@ ** notnull: True if 'NOT NULL' is part of column declaration ** dflt_value: The default value for the column, if any. */ case PragTyp_TABLE_INFO: if( zRight ){ Table *pTab; - pTab = sqlite3FindTable(db, zRight, zDb); + pTab = sqlite3LocateTable(pParse, LOCATE_NOERR, zRight, zDb); if( pTab ){ static const char *azCol[] = { "cid", "name", "type", "notnull", "dflt_value", "pk" }; int i, k; @@ -111195,14 +111860,14 @@ int i; pParse->nMem = 3; setAllColumnNames(v, 3, azCol); assert( 3==ArraySize(azCol) ); for(i=0; inDb; i++){ if( db->aDb[i].pBt==0 ) continue; - assert( db->aDb[i].zName!=0 ); + assert( db->aDb[i].zDbSName!=0 ); sqlite3VdbeMultiLoad(v, 1, "iss", i, - db->aDb[i].zName, + db->aDb[i].zDbSName, sqlite3BtreeGetFilename(db->aDb[i].pBt)); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3); } } break; @@ -111338,16 +112003,14 @@ assert( iKey>=0 && iKeynCol ); if( iKey!=pTab->iPKey ){ sqlite3VdbeAddOp3(v, OP_Column, 0, iKey, regRow); sqlite3ColumnDefault(v, pTab, iKey, regRow); sqlite3VdbeAddOp2(v, OP_IsNull, regRow, addrOk); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_MustBeInt, regRow, - sqlite3VdbeCurrentAddr(v)+3); VdbeCoverage(v); }else{ sqlite3VdbeAddOp2(v, OP_Rowid, 0, regRow); } - sqlite3VdbeAddOp3(v, OP_NotExists, i, 0, regRow); VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_SeekRowid, i, 0, regRow); VdbeCoverage(v); sqlite3VdbeGoto(v, addrOk); sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2); }else{ for(j=0; jnCol; j++){ sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, @@ -111489,11 +112152,11 @@ /* Do the b-tree integrity checks */ sqlite3VdbeAddOp4(v, OP_IntegrityCk, 2, cnt, 1, (char*)aRoot,P4_INTARRAY); sqlite3VdbeChangeP5(v, (u8)i); addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); VdbeCoverage(v); sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, - sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName), + sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zDbSName), P4_DYNAMIC); sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1); sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2); sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1); sqlite3VdbeJumpHere(v, addr); @@ -111928,19 +112591,19 @@ pParse->nMem = 2; for(i=0; inDb; i++){ Btree *pBt; const char *zState = "unknown"; int j; - if( db->aDb[i].zName==0 ) continue; + if( db->aDb[i].zDbSName==0 ) continue; pBt = db->aDb[i].pBt; if( pBt==0 || sqlite3BtreePager(pBt)==0 ){ zState = "closed"; - }else if( sqlite3_file_control(db, i ? db->aDb[i].zName : 0, + }else if( sqlite3_file_control(db, i ? db->aDb[i].zDbSName : 0, SQLITE_FCNTL_LOCKSTATE, &j)==SQLITE_OK ){ zState = azLockName[j]; } - sqlite3VdbeMultiLoad(v, 1, "ss", db->aDb[i].zName, zState); + sqlite3VdbeMultiLoad(v, 1, "ss", db->aDb[i].zDbSName, zState); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2); } break; } #endif @@ -112072,10 +112735,11 @@ ** But because db->init.busy is set to 1, no VDBE code is generated ** or executed. All the parser does is build the internal data ** structures that describe the table, index, or view. */ int rc; + u8 saved_iDb = db->init.iDb; sqlite3_stmt *pStmt; TESTONLY(int rcp); /* Return code from sqlite3_prepare() */ assert( db->init.busy ); db->init.iDb = iDb; @@ -112082,11 +112746,12 @@ db->init.newTnum = sqlite3Atoi(argv[1]); db->init.orphanTrigger = 0; TESTONLY(rcp = ) sqlite3_prepare(db, argv[2], -1, &pStmt, 0); rc = db->errCode; assert( (rc&0xFF)==(rcp&0xFF) ); - db->init.iDb = 0; + db->init.iDb = saved_iDb; + assert( saved_iDb==0 || (db->flags & SQLITE_Vacuum)!=0 ); if( SQLITE_OK!=rc ){ if( db->init.orphanTrigger ){ assert( iDb==1 ); }else{ pData->rc = rc; @@ -112106,11 +112771,11 @@ ** constraint for a CREATE TABLE. The index should have already ** been created when we processed the CREATE TABLE. All we have ** to do here is record the root page number for that index. */ Index *pIndex; - pIndex = sqlite3FindIndex(db, argv[0], db->aDb[iDb].zName); + pIndex = sqlite3FindIndex(db, argv[0], db->aDb[iDb].zDbSName); if( pIndex==0 ){ /* This can occur if there exists an index on a TEMP table which ** has the same name as another index on a permanent index. Since ** the permanent table is hidden by the TEMP table, we can also ** safely ignore the index on the permanent table. @@ -112285,11 +112950,11 @@ assert( db->init.busy ); { char *zSql; zSql = sqlite3MPrintf(db, "SELECT name, rootpage, sql FROM \"%w\".%s ORDER BY rowid", - db->aDb[iDb].zName, zMasterName); + db->aDb[iDb].zDbSName, zMasterName); #ifndef SQLITE_OMIT_AUTHORIZATION { sqlite3_xauth xAuth; xAuth = db->xAuth; db->xAuth = 0; @@ -112560,11 +113225,11 @@ Btree *pBt = db->aDb[i].pBt; if( pBt ){ assert( sqlite3BtreeHoldsMutex(pBt) ); rc = sqlite3BtreeSchemaLocked(pBt); if( rc ){ - const char *zDb = db->aDb[i].zName; + const char *zDb = db->aDb[i].zDbSName; sqlite3ErrorWithMsg(db, rc, "database schema is locked: %s", zDb); testcase( db->flags & SQLITE_ReadUncommitted ); goto end_prepare; } } @@ -112914,10 +113579,11 @@ int regReturn; /* Register holding block-output return address */ int labelBkOut; /* Start label for the block-output subroutine */ int addrSortIndex; /* Address of the OP_SorterOpen or OP_OpenEphemeral */ int labelDone; /* Jump here when done, ex: LIMIT reached */ u8 sortFlags; /* Zero or more SORTFLAG_* bits */ + u8 bOrderedInnerLoop; /* ORDER BY correctly sorts the inner loop */ }; #define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */ /* ** Delete all the content of a Select structure. Deallocate the structure @@ -113447,13 +114113,34 @@ op = OP_IdxInsert; } sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord); if( iLimit ){ int addr; + int r1 = 0; + /* Fill the sorter until it contains LIMIT+OFFSET entries. (The iLimit + ** register is initialized with value of LIMIT+OFFSET.) After the sorter + ** fills up, delete the least entry in the sorter after each insert. + ** Thus we never hold more than the LIMIT+OFFSET rows in memory at once */ addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, 1); VdbeCoverage(v); sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor); + if( pSort->bOrderedInnerLoop ){ + r1 = ++pParse->nMem; + sqlite3VdbeAddOp3(v, OP_Column, pSort->iECursor, nExpr, r1); + VdbeComment((v, "seq")); + } sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor); + if( pSort->bOrderedInnerLoop ){ + /* If the inner loop is driven by an index such that values from + ** the same iteration of the inner loop are in sorted order, then + ** immediately jump to the next iteration of an inner loop if the + ** entry from the current iteration does not fit into the top + ** LIMIT+OFFSET entries of the sorter. */ + int iBrk = sqlite3VdbeCurrentAddr(v) + 2; + sqlite3VdbeAddOp3(v, OP_Eq, regBase+nExpr, iBrk, r1); + sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); + VdbeCoverage(v); + } sqlite3VdbeJumpHere(v, addr); } } /* @@ -113864,11 +114551,11 @@ ** Allocate a KeyInfo object sufficient for an index of N key columns and ** X extra columns. */ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){ int nExtra = (N+X)*(sizeof(CollSeq*)+1); - KeyInfo *p = sqlite3Malloc(sizeof(KeyInfo) + nExtra); + KeyInfo *p = sqlite3DbMallocRaw(db, sizeof(KeyInfo) + nExtra); if( p ){ p->aSortOrder = (u8*)&p->aColl[N+X]; p->nField = (u16)N; p->nXField = (u16)X; p->enc = ENC(db); @@ -113886,11 +114573,11 @@ */ SQLITE_PRIVATE void sqlite3KeyInfoUnref(KeyInfo *p){ if( p ){ assert( p->nRef>0 ); p->nRef--; - if( p->nRef==0 ) sqlite3DbFree(0, p); + if( p->nRef==0 ) sqlite3DbFree(p->db, p); } } /* ** Make a new pointer to a KeyInfo object @@ -114294,11 +114981,11 @@ estWidth = pTab->aCol[iCol].szEst; } zOrigTab = pTab->zName; if( pNC->pParse ){ int iDb = sqlite3SchemaToIndex(pNC->pParse->db, pTab->pSchema); - zOrigDb = pNC->pParse->db->aDb[iDb].zName; + zOrigDb = pNC->pParse->db->aDb[iDb].zDbSName; } #else if( iCol<0 ){ zType = "INTEGER"; }else{ @@ -117250,11 +117937,11 @@ pSub = 0; if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){ continue; } iDb = sqlite3SchemaToIndex(db, pTab->pSchema); - zSchemaName = iDb>=0 ? db->aDb[iDb].zName : "*"; + zSchemaName = iDb>=0 ? db->aDb[iDb].zDbSName : "*"; } for(j=0; jnCol; j++){ char *zName = pTab->aCol[j].zName; char *zColname; /* The computed column name */ char *zToFree; /* Malloced string that needs to be freed */ @@ -118034,10 +118721,11 @@ if( sDistinct.isTnct && sqlite3WhereIsDistinct(pWInfo) ){ sDistinct.eTnctType = sqlite3WhereIsDistinct(pWInfo); } if( sSort.pOrderBy ){ sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo); + sSort.bOrderedInnerLoop = sqlite3WhereOrderedInnerLoop(pWInfo); if( sSort.nOBSat==sSort.pOrderBy->nExpr ){ sSort.pOrderBy = 0; } } @@ -118961,12 +119649,12 @@ iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); #ifndef SQLITE_OMIT_AUTHORIZATION { int code = SQLITE_CREATE_TRIGGER; - const char *zDb = db->aDb[iTabDb].zName; - const char *zDbTrig = isTemp ? db->aDb[1].zName : zDb; + const char *zDb = db->aDb[iTabDb].zDbSName; + const char *zDbTrig = isTemp ? db->aDb[1].zDbSName : zDb; if( iTabDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER; if( sqlite3AuthCheck(pParse, code, zName, pTab->zName, zDbTrig) ){ goto trigger_cleanup; } if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iTabDb),0,zDb)){ @@ -119056,11 +119744,11 @@ if( v==0 ) goto triggerfinish_cleanup; sqlite3BeginWriteOperation(pParse, 0, iDb); z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n); sqlite3NestedParse(pParse, "INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')", - db->aDb[iDb].zName, SCHEMA_TABLE(iDb), zName, + db->aDb[iDb].zDbSName, SCHEMA_TABLE(iDb), zName, pTrig->table, z); sqlite3DbFree(db, z); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddParseSchemaOp(v, iDb, sqlite3MPrintf(db, "type='trigger' AND name='%q'", zName)); @@ -119245,11 +119933,11 @@ zDb = pName->a[0].zDatabase; zName = pName->a[0].zName; assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) ); for(i=OMIT_TEMPDB; inDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ - if( zDb && sqlite3StrICmp(db->aDb[j].zName, zDb) ) continue; + if( zDb && sqlite3StrICmp(db->aDb[j].zDbSName, zDb) ) continue; assert( sqlite3SchemaMutexHeld(db, j, 0) ); pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName); if( pTrigger ) break; } if( !pTrigger ){ @@ -119291,11 +119979,11 @@ assert( pTable ); assert( pTable->pSchema==pTrigger->pSchema || iDb==1 ); #ifndef SQLITE_OMIT_AUTHORIZATION { int code = SQLITE_DROP_TRIGGER; - const char *zDb = db->aDb[iDb].zName; + const char *zDb = db->aDb[iDb].zDbSName; const char *zTab = SCHEMA_TABLE(iDb); if( iDb==1 ) code = SQLITE_DROP_TEMP_TRIGGER; if( sqlite3AuthCheck(pParse, code, pTrigger->zName, pTable->zName, zDb) || sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){ return; @@ -119307,11 +119995,11 @@ */ assert( pTable!=0 ); if( (v = sqlite3GetVdbe(pParse))!=0 ){ sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE name=%Q AND type='trigger'", - db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pTrigger->zName + db->aDb[iDb].zDbSName, SCHEMA_TABLE(iDb), pTrigger->zName ); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddOp4(v, OP_DropTrigger, iDb, 0, 0, pTrigger->zName, 0); } } @@ -119410,12 +120098,14 @@ if( pSrc ){ assert( pSrc->nSrc>0 ); pSrc->a[pSrc->nSrc-1].zName = sqlite3DbStrDup(db, pStep->zTarget); iDb = sqlite3SchemaToIndex(db, pStep->pTrig->pSchema); if( iDb==0 || iDb>=2 ){ + const char *zDb; assert( iDbnDb ); - pSrc->a[pSrc->nSrc-1].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zName); + zDb = db->aDb[iDb].zDbSName; + pSrc->a[pSrc->nSrc-1].zDatabase = sqlite3DbStrDup(db, zDb); } } return pSrc; } @@ -120098,11 +120788,11 @@ #ifndef SQLITE_OMIT_AUTHORIZATION { int rc; rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab->zName, j<0 ? "ROWID" : pTab->aCol[j].zName, - db->aDb[iDb].zName); + db->aDb[iDb].zDbSName); if( rc==SQLITE_DENY ){ goto update_cleanup; }else if( rc==SQLITE_IGNORE ){ aXRef[j] = -1; } @@ -120700,61 +121390,56 @@ */ /* #include "sqliteInt.h" */ /* #include "vdbeInt.h" */ #if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH) -/* -** Finalize a prepared statement. If there was an error, store the -** text of the error message in *pzErrMsg. Return the result code. -*/ -static int vacuumFinalize(sqlite3 *db, sqlite3_stmt *pStmt, char **pzErrMsg){ - int rc; - rc = sqlite3VdbeFinalize((Vdbe*)pStmt); - if( rc ){ - sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db)); - } - return rc; -} - -/* -** Execute zSql on database db. Return an error code. + +/* +** Execute zSql on database db. +** +** If zSql returns rows, then each row will have exactly one +** column. (This will only happen if zSql begins with "SELECT".) +** Take each row of result and call execSql() again recursively. +** +** The execSqlF() routine does the same thing, except it accepts +** a format string as its third argument */ static int execSql(sqlite3 *db, char **pzErrMsg, const char *zSql){ sqlite3_stmt *pStmt; - VVA_ONLY( int rc; ) - if( !zSql ){ - return SQLITE_NOMEM_BKPT; + int rc; + + /* printf("SQL: [%s]\n", zSql); fflush(stdout); */ + rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); + if( rc!=SQLITE_OK ) return rc; + while( SQLITE_ROW==(rc = sqlite3_step(pStmt)) ){ + const char *zSubSql = (const char*)sqlite3_column_text(pStmt,0); + assert( sqlite3_strnicmp(zSql,"SELECT",6)==0 ); + if( zSubSql ){ + assert( zSubSql[0]!='S' ); + rc = execSql(db, pzErrMsg, zSubSql); + if( rc!=SQLITE_OK ) break; + } } - if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){ + assert( rc!=SQLITE_ROW ); + if( rc==SQLITE_DONE ) rc = SQLITE_OK; + if( rc ){ sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db)); - return sqlite3_errcode(db); - } - VVA_ONLY( rc = ) sqlite3_step(pStmt); - assert( rc!=SQLITE_ROW || (db->flags&SQLITE_CountRows) ); - return vacuumFinalize(db, pStmt, pzErrMsg); -} - -/* -** Execute zSql on database db. The statement returns exactly -** one column. Execute this as SQL on the same database. -*/ -static int execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql){ - sqlite3_stmt *pStmt; - int rc; - - rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0); - if( rc!=SQLITE_OK ) return rc; - - while( SQLITE_ROW==sqlite3_step(pStmt) ){ - rc = execSql(db, pzErrMsg, (char*)sqlite3_column_text(pStmt, 0)); - if( rc!=SQLITE_OK ){ - vacuumFinalize(db, pStmt, pzErrMsg); - return rc; - } - } - - return vacuumFinalize(db, pStmt, pzErrMsg); + } + (void)sqlite3_finalize(pStmt); + return rc; +} +static int execSqlF(sqlite3 *db, char **pzErrMsg, const char *zSql, ...){ + char *z; + va_list ap; + int rc; + va_start(ap, zSql); + z = sqlite3VMPrintf(db, zSql, ap); + va_end(ap); + if( z==0 ) return SQLITE_NOMEM; + rc = execSql(db, pzErrMsg, z); + sqlite3DbFree(db, z); + return rc; } /* ** The VACUUM command is used to clean up the database, ** collapse free space, etc. It is modelled after the VACUUM command @@ -120783,35 +121468,36 @@ ** not work if other processes are attached to the original database. ** And a power loss in between deleting the original and renaming the ** transient would cause the database file to appear to be deleted ** following reboot. */ -SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse){ +SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse, Token *pNm){ Vdbe *v = sqlite3GetVdbe(pParse); - if( v ){ - sqlite3VdbeAddOp2(v, OP_Vacuum, 0, 0); - sqlite3VdbeUsesBtree(v, 0); + int iDb = pNm ? sqlite3TwoPartName(pParse, pNm, pNm, &pNm) : 0; + if( v && (iDb>=2 || iDb==0) ){ + sqlite3VdbeAddOp1(v, OP_Vacuum, iDb); + sqlite3VdbeUsesBtree(v, iDb); } return; } /* ** This routine implements the OP_Vacuum opcode of the VDBE. */ -SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){ +SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){ int rc = SQLITE_OK; /* Return code from service routines */ Btree *pMain; /* The database being vacuumed */ Btree *pTemp; /* The temporary database we vacuum into */ - char *zSql = 0; /* SQL statements */ int saved_flags; /* Saved value of the db->flags */ int saved_nChange; /* Saved value of db->nChange */ int saved_nTotalChange; /* Saved value of db->nTotalChange */ - void (*saved_xTrace)(void*,const char*); /* Saved db->xTrace */ + u8 saved_mTrace; /* Saved trace settings */ Db *pDb = 0; /* Database to detach at end of vacuum */ int isMemDb; /* True if vacuuming a :memory: database */ int nRes; /* Bytes of reserved space at the end of each page */ int nDb; /* Number of attached databases */ + const char *zDbMain; /* Schema name of database to vacuum */ if( !db->autoCommit ){ sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction"); return SQLITE_ERROR; } @@ -120824,16 +121510,18 @@ ** restored before returning. Then set the writable-schema flag, and ** disable CHECK and foreign key constraints. */ saved_flags = db->flags; saved_nChange = db->nChange; saved_nTotalChange = db->nTotalChange; - saved_xTrace = db->xTrace; - db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks | SQLITE_PreferBuiltin; - db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder); - db->xTrace = 0; + saved_mTrace = db->mTrace; + db->flags |= (SQLITE_WriteSchema | SQLITE_IgnoreChecks + | SQLITE_PreferBuiltin | SQLITE_Vacuum); + db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder | SQLITE_CountRows); + db->mTrace = 0; - pMain = db->aDb[0].pBt; + zDbMain = db->aDb[iDb].zDbSName; + pMain = db->aDb[iDb].pBt; isMemDb = sqlite3PagerIsMemdb(sqlite3BtreePager(pMain)); /* Attach the temporary database as 'vacuum_db'. The synchronous pragma ** can be set to 'off' for this file, as it is not recovered if a crash ** occurs anyway. The integrity of the database is maintained by a @@ -120847,22 +121535,16 @@ ** empty. Only the journal header is written. Apparently it takes more ** time to parse and run the PRAGMA to turn journalling off than it does ** to write the journal header file. */ nDb = db->nDb; - if( sqlite3TempInMemory(db) ){ - zSql = "ATTACH ':memory:' AS vacuum_db;"; - }else{ - zSql = "ATTACH '' AS vacuum_db;"; - } - rc = execSql(db, pzErrMsg, zSql); - if( db->nDb>nDb ){ - pDb = &db->aDb[db->nDb-1]; - assert( strcmp(pDb->zName,"vacuum_db")==0 ); - } + rc = execSql(db, pzErrMsg, "ATTACH''AS vacuum_db"); if( rc!=SQLITE_OK ) goto end_of_vacuum; - pTemp = db->aDb[db->nDb-1].pBt; + assert( (db->nDb-1)==nDb ); + pDb = &db->aDb[nDb]; + assert( strcmp(pDb->zDbSName,"vacuum_db")==0 ); + pTemp = pDb->pBt; /* The call to execSql() to attach the temp database has left the file ** locked (as there was more than one active statement when the transaction ** to read the schema was concluded. Unlock it here so that this doesn't ** cause problems for the call to BtreeSetPageSize() below. */ @@ -120879,18 +121561,19 @@ sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); if( nKey ) db->nextPagesize = 0; } #endif - rc = execSql(db, pzErrMsg, "PRAGMA vacuum_db.synchronous=OFF"); - if( rc!=SQLITE_OK ) goto end_of_vacuum; + sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size); + sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0)); + sqlite3BtreeSetPagerFlags(pTemp, PAGER_SYNCHRONOUS_OFF); /* Begin a transaction and take an exclusive lock on the main database ** file. This is done before the sqlite3BtreeGetPageSize(pMain) call below, ** to ensure that we do not try to change the page-size on a WAL database. */ - rc = execSql(db, pzErrMsg, "BEGIN;"); + rc = execSql(db, pzErrMsg, "BEGIN"); if( rc!=SQLITE_OK ) goto end_of_vacuum; rc = sqlite3BtreeBeginTrans(pMain, 2); if( rc!=SQLITE_OK ) goto end_of_vacuum; /* Do not attempt to change the page size for a WAL database */ @@ -120913,68 +121596,52 @@ #endif /* Query the schema of the main database. Create a mirror schema ** in the temporary database. */ - rc = execExecSql(db, pzErrMsg, - "SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14) " - " FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'" - " AND coalesce(rootpage,1)>0" + db->init.iDb = nDb; /* force new CREATE statements into vacuum_db */ + rc = execSqlF(db, pzErrMsg, + "SELECT sql FROM \"%w\".sqlite_master" + " WHERE type='table'AND name<>'sqlite_sequence'" + " AND coalesce(rootpage,1)>0", + zDbMain + ); + if( rc!=SQLITE_OK ) goto end_of_vacuum; + rc = execSqlF(db, pzErrMsg, + "SELECT sql FROM \"%w\".sqlite_master" + " WHERE type='index' AND length(sql)>10", + zDbMain ); if( rc!=SQLITE_OK ) goto end_of_vacuum; - rc = execExecSql(db, pzErrMsg, - "SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14)" - " FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %' "); - if( rc!=SQLITE_OK ) goto end_of_vacuum; - rc = execExecSql(db, pzErrMsg, - "SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21) " - " FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'"); - if( rc!=SQLITE_OK ) goto end_of_vacuum; + db->init.iDb = 0; /* Loop through the tables in the main database. For each, do ** an "INSERT INTO vacuum_db.xxx SELECT * FROM main.xxx;" to copy ** the contents to the temporary database. */ - assert( (db->flags & SQLITE_Vacuum)==0 ); - db->flags |= SQLITE_Vacuum; - rc = execExecSql(db, pzErrMsg, - "SELECT 'INSERT INTO vacuum_db.' || quote(name) " - "|| ' SELECT * FROM main.' || quote(name) || ';'" - "FROM main.sqlite_master " - "WHERE type = 'table' AND name!='sqlite_sequence' " - " AND coalesce(rootpage,1)>0" + rc = execSqlF(db, pzErrMsg, + "SELECT'INSERT INTO vacuum_db.'||quote(name)" + "||' SELECT*FROM\"%w\".'||quote(name)" + "FROM vacuum_db.sqlite_master " + "WHERE type='table'AND coalesce(rootpage,1)>0", + zDbMain ); assert( (db->flags & SQLITE_Vacuum)!=0 ); db->flags &= ~SQLITE_Vacuum; if( rc!=SQLITE_OK ) goto end_of_vacuum; - - /* Copy over the sequence table - */ - rc = execExecSql(db, pzErrMsg, - "SELECT 'DELETE FROM vacuum_db.' || quote(name) || ';' " - "FROM vacuum_db.sqlite_master WHERE name='sqlite_sequence' " - ); - if( rc!=SQLITE_OK ) goto end_of_vacuum; - rc = execExecSql(db, pzErrMsg, - "SELECT 'INSERT INTO vacuum_db.' || quote(name) " - "|| ' SELECT * FROM main.' || quote(name) || ';' " - "FROM vacuum_db.sqlite_master WHERE name=='sqlite_sequence';" - ); - if( rc!=SQLITE_OK ) goto end_of_vacuum; - /* Copy the triggers, views, and virtual tables from the main database ** over to the temporary database. None of these objects has any ** associated storage, so all we have to do is copy their entries ** from the SQLITE_MASTER table. */ - rc = execSql(db, pzErrMsg, - "INSERT INTO vacuum_db.sqlite_master " - " SELECT type, name, tbl_name, rootpage, sql" - " FROM main.sqlite_master" - " WHERE type='view' OR type='trigger'" - " OR (type='table' AND rootpage=0)" + rc = execSqlF(db, pzErrMsg, + "INSERT INTO vacuum_db.sqlite_master" + " SELECT*FROM \"%w\".sqlite_master" + " WHERE type IN('view','trigger')" + " OR(type='table'AND rootpage=0)", + zDbMain ); if( rc ) goto end_of_vacuum; /* At this point, there is a write transaction open on both the ** vacuum database and the main database. Assuming no error occurs, @@ -121024,14 +121691,15 @@ assert( rc==SQLITE_OK ); rc = sqlite3BtreeSetPageSize(pMain, sqlite3BtreeGetPageSize(pTemp), nRes,1); end_of_vacuum: /* Restore the original value of db->flags */ + db->init.iDb = 0; db->flags = saved_flags; db->nChange = saved_nChange; db->nTotalChange = saved_nTotalChange; - db->xTrace = saved_xTrace; + db->mTrace = saved_mTrace; sqlite3BtreeSetPageSize(pMain, -1, -1, 1); /* Currently there is an SQL level transaction open on the vacuum ** database. No locks are held on any other files (since the main file ** was committed at the btree level). So it safe to end the transaction @@ -121402,11 +122070,11 @@ ** sqlite_master table, has already been made by sqlite3StartTable(). ** The second call, to obtain permission to create the table, is made now. */ if( pTable->azModuleArg ){ sqlite3AuthCheck(pParse, SQLITE_CREATE_VTABLE, pTable->zName, - pTable->azModuleArg[0], pParse->db->aDb[iDb].zName); + pTable->azModuleArg[0], pParse->db->aDb[iDb].zDbSName); } #endif } /* @@ -121466,21 +122134,21 @@ iDb = sqlite3SchemaToIndex(db, pTab->pSchema); sqlite3NestedParse(pParse, "UPDATE %Q.%s " "SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q " "WHERE rowid=#%d", - db->aDb[iDb].zName, SCHEMA_TABLE(iDb), + db->aDb[iDb].zDbSName, SCHEMA_TABLE(iDb), pTab->zName, pTab->zName, zStmt, pParse->regRowid ); sqlite3DbFree(db, zStmt); v = sqlite3GetVdbe(pParse); sqlite3ChangeCookie(pParse, iDb); - sqlite3VdbeAddOp2(v, OP_Expire, 0, 0); + sqlite3VdbeAddOp0(v, OP_Expire); zWhere = sqlite3MPrintf(db, "name='%q' AND type='table'", pTab->zName); sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere); iReg = ++pParse->nMem; sqlite3VdbeLoadString(v, iReg, pTab->zName); @@ -121576,11 +122244,11 @@ } pVTable->db = db; pVTable->pMod = pMod; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); - pTab->azModuleArg[1] = db->aDb[iDb].zName; + pTab->azModuleArg[1] = db->aDb[iDb].zDbSName; /* Invoke the virtual table constructor */ assert( &db->pVtabCtx ); assert( xConstruct ); sCtx.pTab = pTab; @@ -121740,11 +122408,11 @@ int rc = SQLITE_OK; Table *pTab; Module *pMod; const char *zMod; - pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName); + pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zDbSName); assert( pTab && (pTab->tabFlags & TF_Virtual)!=0 && !pTab->pVTable ); /* Locate the required virtual table module */ zMod = pTab->azModuleArg[0]; pMod = (Module*)sqlite3HashFind(&db->aModule, zMod); @@ -121812,14 +122480,28 @@ && !db->mallocFailed && !pParse->pNewTable->pSelect && (pParse->pNewTable->tabFlags & TF_Virtual)==0 ){ if( !pTab->aCol ){ - pTab->aCol = pParse->pNewTable->aCol; - pTab->nCol = pParse->pNewTable->nCol; - pParse->pNewTable->nCol = 0; - pParse->pNewTable->aCol = 0; + Table *pNew = pParse->pNewTable; + Index *pIdx; + pTab->aCol = pNew->aCol; + pTab->nCol = pNew->nCol; + pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid); + pNew->nCol = 0; + pNew->aCol = 0; + assert( pTab->pIndex==0 ); + if( !HasRowid(pNew) && pCtx->pVTable->pMod->pModule->xUpdate!=0 ){ + rc = SQLITE_ERROR; + } + pIdx = pNew->pIndex; + if( pIdx ){ + assert( pIdx->pNext==0 ); + pTab->pIndex = pIdx; + pNew->pIndex = 0; + pIdx->pTable = pTab; + } } pCtx->bDeclared = 1; }else{ sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr); sqlite3DbFree(db, zErr); @@ -121850,12 +122532,12 @@ */ SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){ int rc = SQLITE_OK; Table *pTab; - pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName); - if( ALWAYS(pTab!=0 && pTab->pVTable!=0) ){ + pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zDbSName); + if( pTab!=0 && ALWAYS(pTab->pVTable!=0) ){ VTable *p; int (*xDestroy)(sqlite3_vtab *); for(p=pTab->pVTable; p; p=p->pNext){ assert( p->pVtab ); if( p->pVtab->nRef>0 ){ @@ -121991,11 +122673,14 @@ if( rc==SQLITE_OK ){ rc = pModule->xBegin(pVTab->pVtab); if( rc==SQLITE_OK ){ int iSvpt = db->nStatement + db->nSavepoint; addToVTrans(db, pVTab); - if( iSvpt ) rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, iSvpt-1); + if( iSvpt && pModule->xSavepoint ){ + pVTab->iSavepoint = iSvpt; + rc = pModule->xSavepoint(pVTab->pVtab, iSvpt-1); + } } } } return rc; } @@ -122145,11 +122830,11 @@ sqlite3OomFault(pToplevel->db); } } /* -** Check to see if virtual tale module pMod can be have an eponymous +** Check to see if virtual table module pMod can be have an eponymous ** virtual table instance. If it can, create one if one does not already ** exist. Return non-zero if the eponymous virtual table instance exists ** when this routine returns, and return zero if it does not exist. ** ** An eponymous virtual table instance is one that is named after its @@ -122162,21 +122847,22 @@ */ SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){ const sqlite3_module *pModule = pMod->pModule; Table *pTab; char *zErr = 0; - int nName; int rc; sqlite3 *db = pParse->db; if( pMod->pEpoTab ) return 1; if( pModule->xCreate!=0 && pModule->xCreate!=pModule->xConnect ) return 0; - nName = sqlite3Strlen30(pMod->zName) + 1; - pTab = sqlite3DbMallocZero(db, sizeof(Table) + nName); + pTab = sqlite3DbMallocZero(db, sizeof(Table)); if( pTab==0 ) return 0; + pTab->zName = sqlite3DbStrDup(db, pMod->zName); + if( pTab->zName==0 ){ + sqlite3DbFree(db, pTab); + return 0; + } pMod->pEpoTab = pTab; - pTab->zName = (char*)&pTab[1]; - memcpy(pTab->zName, pMod->zName, nName); pTab->nRef = 1; pTab->pSchema = db->aDb[0].pSchema; pTab->tabFlags |= TF_Virtual; pTab->nModuleArg = 0; pTab->iPKey = -1; @@ -122198,13 +122884,15 @@ ** virtual table module pMod, if it exists. */ SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){ Table *pTab = pMod->pEpoTab; if( pTab!=0 ){ - sqlite3DeleteColumnNames(db, pTab); - sqlite3VtabClear(db, pTab); - sqlite3DbFree(db, pTab); + /* Mark the table as Ephemeral prior to deleting it, so that the + ** sqlite3DeleteTable() routine will know that it is not stored in + ** the schema. */ + pTab->tabFlags |= TF_Ephemeral; + sqlite3DeleteTable(db, pTab); pMod->pEpoTab = 0; } } /* @@ -122707,12 +123395,13 @@ u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */ i8 nOBSat; /* Number of ORDER BY terms satisfied by indices */ u8 sorted; /* True if really sorted (not just grouped) */ u8 eOnePass; /* ONEPASS_OFF, or _SINGLE, or _MULTI */ u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */ - u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */ + u8 eDistinct; /* One of the WHERE_DISTINCT_* values */ u8 nLevel; /* Number of nested loop */ + u8 bOrderedInnerLoop; /* True if only the inner-most loop is ordered */ int iTop; /* The very beginning of the WHERE loop */ int iContinue; /* Jump here to continue with next record */ int iBreak; /* Jump here to break out of the loop */ int savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */ int aiCurOnePass[2]; /* OP_OpenWrite cursors for the ONEPASS opt */ @@ -122725,10 +123414,13 @@ ** Private interfaces - callable only by other where.c routines. ** ** where.c: */ SQLITE_PRIVATE Bitmask sqlite3WhereGetMask(WhereMaskSet*,int); +#ifdef WHERETRACE_ENABLED +SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC); +#endif SQLITE_PRIVATE WhereTerm *sqlite3WhereFindTerm( WhereClause *pWC, /* The WHERE clause to be searched */ int iCur, /* Cursor number of LHS */ int iColumn, /* Column number of LHS */ Bitmask notReady, /* RHS must not overlap with this mask */ @@ -122941,11 +123633,11 @@ StrAccum str; /* EQP output string */ char zBuf[100]; /* Initial space for EQP output string */ pLoop = pLevel->pWLoop; flags = pLoop->wsFlags; - if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return 0; + if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_OR_SUBCLAUSE) ) return 0; isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0 || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0)) || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX)); @@ -123384,11 +124076,11 @@ ** ** The LIKE optimization trys to evaluate "x LIKE 'abc%'" as a range ** expression: "x>='ABC' AND x<'abd'". But this requires that the range ** scan loop run twice, once for strings and a second time for BLOBs. ** The OP_String opcodes on the second pass convert the upper and lower -** bound string contants to blobs. This routine makes the necessary changes +** bound string constants to blobs. This routine makes the necessary changes ** to the OP_String opcodes for that to happen. ** ** Except, of course, if SQLITE_LIKE_DOESNT_MATCH_BLOBS is defined, then ** only the one pass through the string space is required, so this routine ** becomes a no-op. @@ -123441,10 +124133,42 @@ pWalker->eCode = 1; } return WRC_Continue; } +/* +** Test whether or not expression pExpr, which was part of a WHERE clause, +** should be included in the cursor-hint for a table that is on the rhs +** of a LEFT JOIN. Set Walker.eCode to non-zero before returning if the +** expression is not suitable. +** +** An expression is unsuitable if it might evaluate to non NULL even if +** a TK_COLUMN node that does affect the value of the expression is set +** to NULL. For example: +** +** col IS NULL +** col IS NOT NULL +** coalesce(col, 1) +** CASE WHEN col THEN 0 ELSE 1 END +*/ +static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){ + if( pExpr->op==TK_IS + || pExpr->op==TK_ISNULL || pExpr->op==TK_ISNOT + || pExpr->op==TK_NOTNULL || pExpr->op==TK_CASE + ){ + pWalker->eCode = 1; + }else if( pExpr->op==TK_FUNCTION ){ + int d1; + char d2[3]; + if( 0==sqlite3IsLikeFunction(pWalker->pParse->db, pExpr, &d1, d2) ){ + pWalker->eCode = 1; + } + } + + return WRC_Continue; +} + /* ** This function is called on every node of an expression tree used as an ** argument to the OP_CursorHint instruction. If the node is a TK_COLUMN ** that accesses any table other than the one identified by @@ -123493,10 +124217,11 @@ /* ** Insert an OP_CursorHint instruction if it is appropriate to do so. */ static void codeCursorHint( + struct SrcList_item *pTabItem, /* FROM clause item */ WhereInfo *pWInfo, /* The where clause */ WhereLevel *pLevel, /* Which loop to provide hints for */ WhereTerm *pEndRange /* Hint this end-of-scan boundary term if not NULL */ ){ Parse *pParse = pWInfo->pParse; @@ -123523,11 +124248,46 @@ pWC = &pWInfo->sWC; for(i=0; inTerm; i++){ pTerm = &pWC->a[i]; if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( pTerm->prereqAll & pLevel->notReady ) continue; - if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue; + + /* Any terms specified as part of the ON(...) clause for any LEFT + ** JOIN for which the current table is not the rhs are omitted + ** from the cursor-hint. + ** + ** If this table is the rhs of a LEFT JOIN, "IS" or "IS NULL" terms + ** that were specified as part of the WHERE clause must be excluded. + ** This is to address the following: + ** + ** SELECT ... t1 LEFT JOIN t2 ON (t1.a=t2.b) WHERE t2.c IS NULL; + ** + ** Say there is a single row in t2 that matches (t1.a=t2.b), but its + ** t2.c values is not NULL. If the (t2.c IS NULL) constraint is + ** pushed down to the cursor, this row is filtered out, causing + ** SQLite to synthesize a row of NULL values. Which does match the + ** WHERE clause, and so the query returns a row. Which is incorrect. + ** + ** For the same reason, WHERE terms such as: + ** + ** WHERE 1 = (t2.c IS NULL) + ** + ** are also excluded. See codeCursorHintIsOrFunction() for details. + */ + if( pTabItem->fg.jointype & JT_LEFT ){ + Expr *pExpr = pTerm->pExpr; + if( !ExprHasProperty(pExpr, EP_FromJoin) + || pExpr->iRightJoinTable!=pTabItem->iCursor + ){ + sWalker.eCode = 0; + sWalker.xExprCallback = codeCursorHintIsOrFunction; + sqlite3WalkExpr(&sWalker, pTerm->pExpr); + if( sWalker.eCode ) continue; + } + }else{ + if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue; + } /* All terms in pWLoop->aLTerm[] except pEndRange are used to initialize ** the cursor. These terms are not needed as hints for a pure range ** scan (that has no == terms) so omit them. */ if( pLoop->u.btree.nEq==0 && pTerm!=pEndRange ){ @@ -123557,11 +124317,11 @@ (sHint.pIdx ? sHint.iIdxCur : sHint.iTabCur), 0, 0, (const char*)pExpr, P4_EXPR); } } #else -# define codeCursorHint(A,B,C) /* No-op */ +# define codeCursorHint(A,B,C,D) /* No-op */ #endif /* SQLITE_ENABLE_CURSOR_HINTS */ /* ** Cursor iCur is open on an intkey b-tree (a table). Register iRowid contains ** a rowid value just read from cursor iIdxCur, open on index pIdx. This @@ -123591,11 +124351,11 @@ assert( iIdxCur>0 ); assert( pIdx->aiColumn[pIdx->nColumn-1]==-1 ); sqlite3VdbeAddOp3(v, OP_Seek, iIdxCur, 0, iCur); - if( (pWInfo->wctrlFlags & WHERE_FORCE_TABLE) + if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE) && DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask) ){ int i; Table *pTab = pIdx->pTable; int *ai = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*(pTab->nCol+1)); @@ -123646,11 +124406,11 @@ pTabItem = &pWInfo->pTabList->a[pLevel->iFrom]; iCur = pTabItem->iCursor; pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); bRev = (pWInfo->revMask>>iLevel)&1; omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0 - && (pWInfo->wctrlFlags & WHERE_FORCE_TABLE)==0; + && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0; VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName)); /* Create labels for the "break" and "continue" instructions ** for the current loop. Jump to addrBrk to break out of a loop. ** Jump to cont to go immediately to the next iteration of the @@ -123786,12 +124546,11 @@ testcase( pTerm->wtFlags & TERM_VIRTUAL ); iReleaseReg = ++pParse->nMem; iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg); if( iRowidReg!=iReleaseReg ) sqlite3ReleaseTempReg(pParse, iReleaseReg); addrNxt = pLevel->addrNxt; - sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt); VdbeCoverage(v); - sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, iRowidReg); + sqlite3VdbeAddOp3(v, OP_SeekRowid, iCur, addrNxt, iRowidReg); VdbeCoverage(v); sqlite3ExprCacheAffinityChange(pParse, iRowidReg, 1); sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); VdbeComment((v, "pk")); pLevel->op = OP_Noop; @@ -123814,11 +124573,11 @@ if( bRev ){ pTerm = pStart; pStart = pEnd; pEnd = pTerm; } - codeCursorHint(pWInfo, pLevel, pEnd); + codeCursorHint(pTabItem, pWInfo, pLevel, pEnd); if( pStart ){ Expr *pX; /* The expression that defines the start bound */ int r1, rTemp; /* Registers for holding the start boundary */ /* The following constant maps TK_xx codes into corresponding @@ -124028,11 +124787,11 @@ /* Generate code to evaluate all constraint terms using == or IN ** and store the values of those terms in an array of registers ** starting at regBase. */ - codeCursorHint(pWInfo, pLevel, pRangeEnd); + codeCursorHint(pTabItem, pWInfo, pLevel, pRangeEnd); regBase = codeAllEqualityTerms(pParse,pLevel,bRev,nExtraReg,&zStartAff); assert( zStartAff==0 || sqlite3Strlen30(zStartAff)>=nEq ); if( zStartAff ) cEndAff = zStartAff[nEq]; addrNxt = pLevel->addrNxt; @@ -124067,10 +124826,11 @@ zStartAff[nEq] = SQLITE_AFF_BLOB; } } nConstraint++; testcase( pRangeStart->wtFlags & TERM_VIRTUAL ); + bSeekPastNull = 0; }else if( bSeekPastNull ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); nConstraint++; startEq = 0; start_constraints = 1; @@ -124332,15 +125092,11 @@ /* Run a separate WHERE clause for each term of the OR clause. After ** eliminating duplicates from other WHERE clauses, the action for each ** sub-WHERE clause is to to invoke the main loop body as a subroutine. */ - wctrlFlags = WHERE_OMIT_OPEN_CLOSE - | WHERE_FORCE_TABLE - | WHERE_ONETABLE_ONLY - | WHERE_NO_AUTOINDEX - | (pWInfo->wctrlFlags & WHERE_SEEK_TABLE); + wctrlFlags = WHERE_OR_SUBCLAUSE | (pWInfo->wctrlFlags & WHERE_SEEK_TABLE); for(ii=0; iinTerm; ii++){ WhereTerm *pOrTerm = &pOrWc->a[ii]; if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){ WhereInfo *pSubWInfo; /* Info for single OR-term scan */ Expr *pOrExpr = pOrTerm->pExpr; /* Current OR clause term */ @@ -124444,11 +125200,10 @@ && (ii==0 || pSubLoop->u.btree.pIndex==pCov) && (HasRowid(pTab) || !IsPrimaryKeyIndex(pSubLoop->u.btree.pIndex)) ){ assert( pSubWInfo->a[0].iIdxCur==iCovCur ); pCov = pSubLoop->u.btree.pIndex; - wctrlFlags |= WHERE_REOPEN_IDX; }else{ pCov = 0; } /* Finish the loop through table entries that match term pOrTerm. */ @@ -124481,11 +125236,11 @@ if( pTabItem->fg.isRecursive ){ /* Tables marked isRecursive have only a single row that is stored in ** a pseudo-cursor. No need to Rewind or Next such cursors. */ pLevel->op = OP_Noop; }else{ - codeCursorHint(pWInfo, pLevel, 0); + codeCursorHint(pTabItem, pWInfo, pLevel, 0); pLevel->op = aStep[bRev]; pLevel->p1 = iCur; pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk); VdbeCoverageIf(v, bRev==0); VdbeCoverageIf(v, bRev!=0); @@ -124506,11 +125261,11 @@ testcase( pTerm->wtFlags & TERM_VIRTUAL ); testcase( pTerm->wtFlags & TERM_CODED ); if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( (pTerm->prereqAll & pLevel->notReady)!=0 ){ testcase( pWInfo->untestedTerms==0 - && (pWInfo->wctrlFlags & WHERE_ONETABLE_ONLY)!=0 ); + && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 ); pWInfo->untestedTerms = 1; continue; } pE = pTerm->pExpr; assert( pE!=0 ); @@ -124890,11 +125645,11 @@ */ static int isMatchOfColumn( Expr *pExpr, /* Test this expression */ unsigned char *peOp2 /* OUT: 0 for MATCH, or else an op2 value */ ){ - struct Op2 { + static const struct Op2 { const char *zOp; unsigned char eOp2; } aOp[] = { { "match", SQLITE_INDEX_CONSTRAINT_MATCH }, { "glob", SQLITE_INDEX_CONSTRAINT_GLOB }, @@ -125168,11 +125923,13 @@ sqlite3WhereExprAnalyze(pSrc, pAndWC); pAndWC->pOuter = pWC; if( !db->mallocFailed ){ for(j=0, pAndTerm=pAndWC->a; jnTerm; j++, pAndTerm++){ assert( pAndTerm->pExpr ); - if( allowedOp(pAndTerm->pExpr->op) ){ + if( allowedOp(pAndTerm->pExpr->op) + || pAndTerm->eOperator==WO_MATCH + ){ b |= sqlite3WhereGetMask(&pWInfo->sMaskSet, pAndTerm->leftCursor); } } } indexable &= b; @@ -125383,16 +126140,14 @@ return 0; } pColl = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight); if( pColl==0 || sqlite3StrICmp(pColl->zName, "BINARY")==0 ) return 1; pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft); - /* Since pLeft and pRight are both a column references, their collating - ** sequence should always be defined. */ - zColl1 = ALWAYS(pColl) ? pColl->zName : 0; + zColl1 = pColl ? pColl->zName : 0; pColl = sqlite3ExprCollSeq(pParse, pExpr->pRight); - zColl2 = ALWAYS(pColl) ? pColl->zName : 0; - return sqlite3StrICmp(zColl1, zColl2)==0; + zColl2 = pColl ? pColl->zName : 0; + return sqlite3_stricmp(zColl1, zColl2)==0; } /* ** Recursively walk the expressions of a SELECT statement and generate ** a bitmask indicating which tables are used in that expression @@ -125722,11 +126477,11 @@ ** current expression is of the form: column MATCH expr. ** This information is used by the xBestIndex methods of ** virtual tables. The native query optimizer does not attempt ** to do anything with MATCH functions. */ - if( isMatchOfColumn(pExpr, &eOp2) ){ + if( pWC->op==TK_AND && isMatchOfColumn(pExpr, &eOp2) ){ int idxNew; Expr *pRight, *pLeft; WhereTerm *pNewTerm; Bitmask prereqColumn, prereqExpr; @@ -125875,17 +126630,18 @@ ** These routines walk (recursively) an expression tree and generate ** a bitmask indicating which tables are used in that expression ** tree. */ SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){ - Bitmask mask = 0; + Bitmask mask; if( p==0 ) return 0; if( p->op==TK_COLUMN ){ mask = sqlite3WhereGetMask(pMaskSet, p->iTable); return mask; } - mask = sqlite3WhereExprUsage(pMaskSet, p->pRight); + assert( !ExprHasProperty(p, EP_TokenOnly) ); + mask = p->pRight ? sqlite3WhereExprUsage(pMaskSet, p->pRight) : 0; if( p->pLeft ) mask |= sqlite3WhereExprUsage(pMaskSet, p->pLeft); if( ExprHasProperty(p, EP_xIsSelect) ){ mask |= exprSelectUsage(pMaskSet, p->x.pSelect); }else if( p->x.pList ){ mask |= sqlite3WhereExprListUsage(pMaskSet, p->x.pList); @@ -126014,10 +126770,22 @@ ** Return FALSE if the output needs to be sorted. */ SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo *pWInfo){ return pWInfo->nOBSat; } + +/* +** Return TRUE if the innermost loop of the WHERE clause implementation +** returns rows in ORDER BY order for complete run of the inner loop. +** +** Across multiple iterations of outer loops, the output rows need not be +** sorted. As long as rows are sorted for just the innermost loop, this +** routine can return TRUE. +*/ +SQLITE_PRIVATE int sqlite3WhereOrderedInnerLoop(WhereInfo *pWInfo){ + return pWInfo->bOrderedInnerLoop; +} /* ** Return the VDBE address or label to jump to in order to continue ** immediately with the next row of a WHERE clause. */ @@ -127600,20 +128368,42 @@ static void whereTermPrint(WhereTerm *pTerm, int iTerm){ if( pTerm==0 ){ sqlite3DebugPrintf("TERM-%-3d NULL\n", iTerm); }else{ char zType[4]; + char zLeft[50]; memcpy(zType, "...", 4); if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V'; if( pTerm->eOperator & WO_EQUIV ) zType[1] = 'E'; if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L'; + if( pTerm->eOperator & WO_SINGLE ){ + sqlite3_snprintf(sizeof(zLeft),zLeft,"left={%d:%d}", + pTerm->leftCursor, pTerm->u.leftColumn); + }else if( (pTerm->eOperator & WO_OR)!=0 && pTerm->u.pOrInfo!=0 ){ + sqlite3_snprintf(sizeof(zLeft),zLeft,"indexable=0x%lld", + pTerm->u.pOrInfo->indexable); + }else{ + sqlite3_snprintf(sizeof(zLeft),zLeft,"left=%d", pTerm->leftCursor); + } sqlite3DebugPrintf( - "TERM-%-3d %p %s cursor=%-3d prob=%-3d op=0x%03x wtFlags=0x%04x\n", - iTerm, pTerm, zType, pTerm->leftCursor, pTerm->truthProb, + "TERM-%-3d %p %s %-12s prob=%-3d op=0x%03x wtFlags=0x%04x\n", + iTerm, pTerm, zType, zLeft, pTerm->truthProb, pTerm->eOperator, pTerm->wtFlags); sqlite3TreeViewExpr(0, pTerm->pExpr, 0); } +} +#endif + +#ifdef WHERETRACE_ENABLED +/* +** Show the complete content of a WhereClause +*/ +SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC){ + int i; + for(i=0; inTerm; i++){ + whereTermPrint(&pWC->a[i], i); + } } #endif #ifdef WHERETRACE_ENABLED /* @@ -128599,11 +129389,11 @@ rLogSize = estLog(rSize); #ifndef SQLITE_OMIT_AUTOMATIC_INDEX /* Automatic indexes */ if( !pBuilder->pOrSet /* Not part of an OR optimization */ - && (pWInfo->wctrlFlags & WHERE_NO_AUTOINDEX)==0 + && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 && (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0 && pSrc->pIBIndex==0 /* Has no INDEXED BY clause */ && !pSrc->fg.notIndexed /* Has no NOT INDEXED clause */ && HasRowid(pTab) /* Not WITHOUT ROWID table. (FIXME: Why not?) */ && !pSrc->fg.isCorrelated /* Not a correlated subquery */ @@ -128631,10 +129421,11 @@ pNew->rSetup = rLogSize + rSize + 4; if( pTab->pSelect==0 && (pTab->tabFlags & TF_Ephemeral)==0 ){ pNew->rSetup += 24; } ApplyCostMultiplier(pNew->rSetup, pTab->costMult); + if( pNew->rSetup<0 ) pNew->rSetup = 0; /* TUNING: Each index lookup yields 20 rows in the table. This ** is more than the usual guess of 10 rows, since we have no way ** of knowing how selective the index will ultimately be. It would ** not be unreasonable to make this value much larger. */ pNew->nOut = 43; assert( 43==sqlite3LogEst(20) ); @@ -128691,10 +129482,11 @@ } /* Full scan via index */ if( b || !HasRowid(pTab) + || pProbe->pPartIdxWhere!=0 || ( m==0 && pProbe->bUnordered==0 && (pProbe->szIdxRowszTabRow) && (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 && sqlite3GlobalConfig.bUseCis @@ -128703,15 +129495,38 @@ ){ pNew->iSortIdx = b ? iSortIdx : 0; /* The cost of visiting the index rows is N*K, where K is ** between 1.1 and 3.0, depending on the relative sizes of the - ** index and table rows. If this is a non-covering index scan, - ** also add the cost of visiting table rows (N*3.0). */ + ** index and table rows. */ pNew->rRun = rSize + 1 + (15*pProbe->szIdxRow)/pTab->szTabRow; if( m!=0 ){ - pNew->rRun = sqlite3LogEstAdd(pNew->rRun, rSize+16); + /* If this is a non-covering index scan, add in the cost of + ** doing table lookups. The cost will be 3x the number of + ** lookups. Take into account WHERE clause terms that can be + ** satisfied using just the index, and that do not require a + ** table lookup. */ + LogEst nLookup = rSize + 16; /* Base cost: N*3 */ + int ii; + int iCur = pSrc->iCursor; + WhereClause *pWC2 = &pWInfo->sWC; + for(ii=0; iinTerm; ii++){ + WhereTerm *pTerm = &pWC2->a[ii]; + if( !sqlite3ExprCoveredByIndex(pTerm->pExpr, iCur, pProbe) ){ + break; + } + /* pTerm can be evaluated using just the index. So reduce + ** the expected number of table lookups accordingly */ + if( pTerm->truthProb<=0 ){ + nLookup += pTerm->truthProb; + }else{ + nLookup--; + if( pTerm->eOperator & (WO_EQ|WO_IS) ) nLookup -= 19; + } + } + + pNew->rRun = sqlite3LogEstAdd(pNew->rRun, nLookup); } ApplyCostMultiplier(pNew->rRun, pTab->costMult); whereLoopOutputAdjust(pWC, pNew, rSize); rc = whereLoopInsert(pBuilder, pNew); pNew->nOut = rSize; @@ -129076,13 +129891,11 @@ sCur.n = 0; #ifdef WHERETRACE_ENABLED WHERETRACE(0x200, ("OR-term %d of %p has %d subterms:\n", (int)(pOrTerm-pOrWC->a), pTerm, sSubBuild.pWC->nTerm)); if( sqlite3WhereTrace & 0x400 ){ - for(i=0; inTerm; i++){ - whereTermPrint(&sSubBuild.pWC->a[i], i); - } + sqlite3WhereClausePrint(sSubBuild.pWC); } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pItem->pTab) ){ rc = whereLoopAddVirtual(&sSubBuild, mPrereq, mUnusable); @@ -129171,19 +129984,22 @@ /* This condition is true when pItem is the FROM clause term on the ** right-hand-side of a LEFT or CROSS JOIN. */ mPrereq = mPrior; } priorJointype = pItem->fg.jointype; +#ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pItem->pTab) ){ struct SrcList_item *p; for(p=&pItem[1]; pfg.jointype & (JT_LEFT|JT_CROSS)) ){ mUnusable |= sqlite3WhereGetMask(&pWInfo->sMaskSet, p->iCursor); } } rc = whereLoopAddVirtual(pBuilder, mPrereq, mUnusable); - }else{ + }else +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + { rc = whereLoopAddBtree(pBuilder, mPrereq); } if( rc==SQLITE_OK ){ rc = whereLoopAddOr(pBuilder, mPrereq, mUnusable); } @@ -129214,11 +130030,11 @@ */ static i8 wherePathSatisfiesOrderBy( WhereInfo *pWInfo, /* The WHERE clause */ ExprList *pOrderBy, /* ORDER BY or GROUP BY or DISTINCT clause to check */ WherePath *pPath, /* The WherePath to check */ - u16 wctrlFlags, /* Might contain WHERE_GROUPBY or WHERE_DISTINCTBY */ + u16 wctrlFlags, /* WHERE_GROUPBY or _DISTINCTBY or _ORDERBY_LIMIT */ u16 nLoop, /* Number of entries in pPath->aLoop[] */ WhereLoop *pLast, /* Add this WhereLoop to the end of pPath->aLoop[] */ Bitmask *pRevMask /* OUT: Mask of WhereLoops to run in reverse order */ ){ u8 revSet; /* True if rev is known */ @@ -129225,10 +130041,11 @@ u8 rev; /* Composite sort order */ u8 revIdx; /* Index sort order */ u8 isOrderDistinct; /* All prior WhereLoops are order-distinct */ u8 distinctColumns; /* True if the loop has UNIQUE NOT NULL columns */ u8 isMatch; /* iColumn matches a term of the ORDER BY clause */ + u16 eqOpMask; /* Allowed equality operators */ u16 nKeyCol; /* Number of key columns in pIndex */ u16 nColumn; /* Total number of ordered columns in the index */ u16 nOrderBy; /* Number terms in the ORDER BY clause */ int iLoop; /* Index of WhereLoop in pPath being processed */ int i, j; /* Loop counters */ @@ -129275,13 +130092,20 @@ if( nOrderBy>BMS-1 ) return 0; /* Cannot optimize overly large ORDER BYs */ isOrderDistinct = 1; obDone = MASKBIT(nOrderBy)-1; orderDistinctMask = 0; ready = 0; + eqOpMask = WO_EQ | WO_IS | WO_ISNULL; + if( wctrlFlags & WHERE_ORDERBY_LIMIT ) eqOpMask |= WO_IN; for(iLoop=0; isOrderDistinct && obSat0 ) ready |= pLoop->maskSelf; - pLoop = iLoopaLoop[iLoop] : pLast; + if( iLoopaLoop[iLoop]; + if( wctrlFlags & WHERE_ORDERBY_LIMIT ) continue; + }else{ + pLoop = pLast; + } if( pLoop->wsFlags & WHERE_VIRTUALTABLE ){ if( pLoop->u.vtab.isOrdered ) obSat = obDone; break; } iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor; @@ -129295,11 +130119,11 @@ if( MASKBIT(i) & obSat ) continue; pOBExpr = sqlite3ExprSkipCollate(pOrderBy->a[i].pExpr); if( pOBExpr->op!=TK_COLUMN ) continue; if( pOBExpr->iTable!=iCur ) continue; pTerm = sqlite3WhereFindTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn, - ~ready, WO_EQ|WO_ISNULL|WO_IS, 0); + ~ready, eqOpMask, 0); if( pTerm==0 ) continue; if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0 && pOBExpr->iColumn>=0 ){ const char *z1, *z2; pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr); if( !pColl ) pColl = db->pDfltColl; @@ -129335,14 +130159,16 @@ rev = revSet = 0; distinctColumns = 0; for(j=0; ju.btree.nEq && pLoop->nSkip==0 - && ((i = pLoop->aLTerm[j]->eOperator) & (WO_EQ|WO_ISNULL|WO_IS))!=0 + && ((i = pLoop->aLTerm[j]->eOperator) & eqOpMask)!=0 ){ if( i & WO_ISNULL ){ testcase( isOrderDistinct ); isOrderDistinct = 0; } @@ -129862,12 +130688,23 @@ if( pFrom->isOrdered==pWInfo->pOrderBy->nExpr ){ pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; } }else{ pWInfo->nOBSat = pFrom->isOrdered; - if( pWInfo->nOBSat<0 ) pWInfo->nOBSat = 0; pWInfo->revMask = pFrom->revLoop; + if( pWInfo->nOBSat<=0 ){ + pWInfo->nOBSat = 0; + if( nLoop>0 && (pFrom->aLoop[nLoop-1]->wsFlags & WHERE_ONEROW)==0 ){ + Bitmask m = 0; + int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, pFrom, + WHERE_ORDERBY_LIMIT, nLoop-1, pFrom->aLoop[nLoop-1], &m); + if( rc==pWInfo->pOrderBy->nExpr ){ + pWInfo->bOrderedInnerLoop = 1; + pWInfo->revMask = m; + } + } + } } if( (pWInfo->wctrlFlags & WHERE_SORTBYGROUP) && pWInfo->nOBSat==pWInfo->pOrderBy->nExpr && nLoop>0 ){ Bitmask revMask = 0; @@ -129911,11 +130748,11 @@ int j; Table *pTab; Index *pIdx; pWInfo = pBuilder->pWInfo; - if( pWInfo->wctrlFlags & WHERE_FORCE_TABLE ) return 0; + if( pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE ) return 0; assert( pWInfo->pTabList->nSrc>=1 ); pItem = pWInfo->pTabList->a; pTab = pItem->pTab; if( IsVirtual(pTab) ) return 0; if( pItem->fg.isIndexedBy ) return 0; @@ -130058,11 +130895,11 @@ ** if the WHERE_GROUPBY flag is set in wctrlFlags) of a SELECT statement ** if there is one. If there is no ORDER BY clause or if this routine ** is called from an UPDATE or DELETE statement, then pOrderBy is NULL. ** ** The iIdxCur parameter is the cursor number of an index. If -** WHERE_ONETABLE_ONLY is set, iIdxCur is the cursor number of an index +** WHERE_OR_SUBCLAUSE is set, iIdxCur is the cursor number of an index ** to use for OR clause processing. The WHERE clause should use this ** specific cursor. If WHERE_ONEPASS_DESIRED is set, then iIdxCur is ** the first cursor in an array of cursors for all indices. iIdxCur should ** be used to compute the appropriate cursor depending on which index is ** used. @@ -130072,11 +130909,11 @@ SrcList *pTabList, /* FROM clause: A list of all tables to be scanned */ Expr *pWhere, /* The WHERE clause */ ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */ ExprList *pDistinctSet, /* Try not to output two rows that duplicate these */ u16 wctrlFlags, /* The WHERE_* flags defined in sqliteInt.h */ - int iAuxArg /* If WHERE_ONETABLE_ONLY is set, index cursor number + int iAuxArg /* If WHERE_OR_SUBCLAUSE is set, index cursor number ** If WHERE_USE_LIMIT, then the limit amount */ ){ int nByteWInfo; /* Num. bytes allocated for WhereInfo struct */ int nTabList; /* Number of elements in pTabList */ WhereInfo *pWInfo; /* Will become the return value of this function */ @@ -130091,15 +130928,15 @@ int rc; /* Return code */ u8 bFordelete = 0; /* OPFLAG_FORDELETE or zero, as appropriate */ assert( (wctrlFlags & WHERE_ONEPASS_MULTIROW)==0 || ( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 - && (wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0 + && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0 )); - /* Only one of WHERE_ONETABLE_ONLY or WHERE_USE_LIMIT */ - assert( (wctrlFlags & WHERE_ONETABLE_ONLY)==0 + /* Only one of WHERE_OR_SUBCLAUSE or WHERE_USE_LIMIT */ + assert( (wctrlFlags & WHERE_OR_SUBCLAUSE)==0 || (wctrlFlags & WHERE_USE_LIMIT)==0 ); /* Variable initialization */ db = pParse->db; memset(&sWLB, 0, sizeof(sWLB)); @@ -130123,15 +130960,15 @@ sqlite3ErrorMsg(pParse, "at most %d tables in a join", BMS); return 0; } /* This function normally generates a nested loop for all tables in - ** pTabList. But if the WHERE_ONETABLE_ONLY flag is set, then we should + ** pTabList. But if the WHERE_OR_SUBCLAUSE flag is set, then we should ** only generate code for the first table in pTabList and assume that ** any cursors associated with subsequent tables are uninitialized. */ - nTabList = (wctrlFlags & WHERE_ONETABLE_ONLY) ? 1 : pTabList->nSrc; + nTabList = (wctrlFlags & WHERE_OR_SUBCLAUSE) ? 1 : pTabList->nSrc; /* Allocate and initialize the WhereInfo structure that will become the ** return value. A single allocation is used to store the WhereInfo ** struct, the contents of WhereInfo.a[], the WhereClause structure ** and the WhereMaskSet structure. Since WhereClause contains an 8-byte @@ -130203,11 +131040,11 @@ ** important. Ticket #3015. ** ** Note that bitmasks are created for all pTabList->nSrc tables in ** pTabList, not just the first nTabList tables. nTabList is normally ** equal to pTabList->nSrc but might be shortened to 1 if the - ** WHERE_ONETABLE_ONLY flag is set. + ** WHERE_OR_SUBCLAUSE flag is set. */ for(ii=0; iinSrc; ii++){ createMask(pMaskSet, pTabList->a[ii].iCursor); sqlite3WhereTabFuncArgs(pParse, &pTabList->a[ii], &pWInfo->sWC); } @@ -130241,14 +131078,11 @@ sqlite3DebugPrintf(", limit: %d", iAuxArg); } sqlite3DebugPrintf(")\n"); } if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */ - int i; - for(i=0; inTerm; i++){ - whereTermPrint(&sWLB.pWC->a[i], i); - } + sqlite3WhereClausePrint(sWLB.pWC); } #endif if( nTabList!=1 || whereShortCut(&sWLB)==0 ){ rc = whereLoopAddAll(&sWLB); @@ -130386,11 +131220,11 @@ }else if( IsVirtual(pTab) ){ /* noop */ }else #endif if( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 - && (wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0 ){ + && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0 ){ int op = OP_OpenRead; if( pWInfo->eOnePass!=ONEPASS_OFF ){ op = OP_OpenWrite; pWInfo->aiCurOnePass[0] = pTabItem->iCursor; }; @@ -130425,11 +131259,11 @@ int iIndexCur; int op = OP_OpenRead; /* iAuxArg is always set if to a positive value if ONEPASS is possible */ assert( iAuxArg!=0 || (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 ); if( !HasRowid(pTab) && IsPrimaryKeyIndex(pIx) - && (wctrlFlags & WHERE_ONETABLE_ONLY)!=0 + && (wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 ){ /* This is one term of an OR-optimization using the PRIMARY KEY of a ** WITHOUT ROWID table. No need for a separate index */ iIndexCur = pLevel->iTabCur; op = 0; @@ -130441,13 +131275,13 @@ iIndexCur++; pJ = pJ->pNext; } op = OP_OpenWrite; pWInfo->aiCurOnePass[1] = iIndexCur; - }else if( iAuxArg && (wctrlFlags & WHERE_ONETABLE_ONLY)!=0 ){ + }else if( iAuxArg && (wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 ){ iIndexCur = iAuxArg; - if( wctrlFlags & WHERE_REOPEN_IDX ) op = OP_ReopenIdx; + op = OP_ReopenIdx; }else{ iIndexCur = pParse->nTab++; } pLevel->iIdxCur = iIndexCur; assert( pIx->pSchema==pTab->pSchema ); @@ -130505,11 +131339,11 @@ pParse, pTabList, pLevel, ii, pLevel->iFrom, wctrlFlags ); pLevel->addrBody = sqlite3VdbeCurrentAddr(v); notReady = sqlite3WhereCodeOneLoopStart(pWInfo, ii, notReady); pWInfo->iContinue = pLevel->addrCont; - if( (wsFlags&WHERE_MULTI_OR)==0 && (wctrlFlags&WHERE_ONETABLE_ONLY)==0 ){ + if( (wsFlags&WHERE_MULTI_OR)==0 && (wctrlFlags&WHERE_OR_SUBCLAUSE)==0 ){ sqlite3WhereAddScanStatus(v, pTabList, pLevel, addrExplain); } } /* Done. */ @@ -130628,16 +131462,16 @@ continue; } /* Close all of the cursors that were opened by sqlite3WhereBegin. ** Except, do not close cursors that will be reused by the OR optimization - ** (WHERE_OMIT_OPEN_CLOSE). And do not close the OP_OpenWrite cursors + ** (WHERE_OR_SUBCLAUSE). And do not close the OP_OpenWrite cursors ** created for the ONEPASS optimization. */ if( (pTab->tabFlags & TF_Ephemeral)==0 && pTab->pSelect==0 - && (pWInfo->wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0 + && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 ){ int ws = pLoop->wsFlags; if( pWInfo->eOnePass==ONEPASS_OFF && (ws & WHERE_IDX_ONLY)==0 ){ sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor); } @@ -130980,49 +131814,49 @@ #ifndef INTERFACE # define INTERFACE 1 #endif /************* Begin control #defines *****************************************/ #define YYCODETYPE unsigned char -#define YYNOCODE 251 +#define YYNOCODE 252 #define YYACTIONTYPE unsigned short int #define YYWILDCARD 96 #define sqlite3ParserTOKENTYPE Token typedef union { int yyinit; sqlite3ParserTOKENTYPE yy0; - struct LimitVal yy64; - Expr* yy122; - Select* yy159; - IdList* yy180; - struct {int value; int mask;} yy207; - struct LikeOp yy318; - TriggerStep* yy327; - With* yy331; - ExprSpan yy342; - SrcList* yy347; - int yy392; - struct TrigEvent yy410; - ExprList* yy442; + Expr* yy72; + TriggerStep* yy145; + ExprList* yy148; + SrcList* yy185; + ExprSpan yy190; + int yy194; + Select* yy243; + IdList* yy254; + With* yy285; + struct TrigEvent yy332; + struct LimitVal yy354; + struct LikeOp yy392; + struct {int value; int mask;} yy497; } YYMINORTYPE; #ifndef YYSTACKDEPTH #define YYSTACKDEPTH 100 #endif #define sqlite3ParserARG_SDECL Parse *pParse; #define sqlite3ParserARG_PDECL ,Parse *pParse #define sqlite3ParserARG_FETCH Parse *pParse = yypParser->pParse #define sqlite3ParserARG_STORE yypParser->pParse = pParse #define YYFALLBACK 1 -#define YYNSTATE 440 -#define YYNRULE 326 -#define YY_MAX_SHIFT 439 -#define YY_MIN_SHIFTREDUCE 649 -#define YY_MAX_SHIFTREDUCE 974 -#define YY_MIN_REDUCE 975 -#define YY_MAX_REDUCE 1300 -#define YY_ERROR_ACTION 1301 -#define YY_ACCEPT_ACTION 1302 -#define YY_NO_ACTION 1303 +#define YYNSTATE 443 +#define YYNRULE 328 +#define YY_MAX_SHIFT 442 +#define YY_MIN_SHIFTREDUCE 653 +#define YY_MAX_SHIFTREDUCE 980 +#define YY_MIN_REDUCE 981 +#define YY_MAX_REDUCE 1308 +#define YY_ERROR_ACTION 1309 +#define YY_ACCEPT_ACTION 1310 +#define YY_NO_ACTION 1311 /************* End control #defines *******************************************/ /* Define the yytestcase() macro to be a no-op if is not already defined ** otherwise. ** @@ -131050,29 +131884,33 @@ ** N between YY_MIN_SHIFTREDUCE Shift to an arbitrary state then ** and YY_MAX_SHIFTREDUCE reduce by rule N-YY_MIN_SHIFTREDUCE. ** ** N between YY_MIN_REDUCE Reduce by rule N-YY_MIN_REDUCE ** and YY_MAX_REDUCE - +** ** N == YY_ERROR_ACTION A syntax error has occurred. ** ** N == YY_ACCEPT_ACTION The parser accepts its input. ** ** N == YY_NO_ACTION No such action. Denotes unused ** slots in the yy_action[] table. ** ** The action table is constructed as a single large table named yy_action[]. -** Given state S and lookahead X, the action is computed as -** -** yy_action[ yy_shift_ofst[S] + X ] -** -** If the index value yy_shift_ofst[S]+X is out of range or if the value -** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S] -** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table -** and that yy_default[S] should be used instead. -** -** The formula above is for computing the action when the lookahead is +** Given state S and lookahead X, the action is computed as either: +** +** (A) N = yy_action[ yy_shift_ofst[S] + X ] +** (B) N = yy_default[S] +** +** The (A) formula is preferred. The B formula is used instead if: +** (1) The yy_shift_ofst[S]+X value is out of range, or +** (2) yy_lookahead[yy_shift_ofst[S]+X] is not equal to X, or +** (3) yy_shift_ofst[S] equal YY_SHIFT_USE_DFLT. +** (Implementation note: YY_SHIFT_USE_DFLT is chosen so that +** YY_SHIFT_USE_DFLT+X will be out of range for all possible lookaheads X. +** Hence only tests (1) and (2) need to be evaluated.) +** +** The formulas above are for computing the action when the lookahead is ** a terminal symbol. If the lookahead is a non-terminal (as occurs after ** a reduce action) then the yy_reduce_ofst[] array is used in place of ** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of ** YY_SHIFT_USE_DFLT. ** @@ -131086,450 +131924,452 @@ ** yy_reduce_ofst[] For each state, the offset into yy_action for ** shifting non-terminals after a reduce. ** yy_default[] Default action for each state. ** *********** Begin parsing tables **********************************************/ -#define YY_ACTTAB_COUNT (1501) +#define YY_ACTTAB_COUNT (1507) static const YYACTIONTYPE yy_action[] = { - /* 0 */ 315, 810, 339, 804, 5, 194, 194, 798, 92, 93, - /* 10 */ 83, 819, 819, 831, 834, 823, 823, 90, 90, 91, - /* 20 */ 91, 91, 91, 290, 89, 89, 89, 89, 88, 88, - /* 30 */ 87, 87, 87, 86, 339, 315, 952, 952, 803, 803, - /* 40 */ 803, 922, 342, 92, 93, 83, 819, 819, 831, 834, - /* 50 */ 823, 823, 90, 90, 91, 91, 91, 91, 123, 89, - /* 60 */ 89, 89, 89, 88, 88, 87, 87, 87, 86, 339, - /* 70 */ 88, 88, 87, 87, 87, 86, 339, 772, 952, 952, - /* 80 */ 315, 87, 87, 87, 86, 339, 773, 68, 92, 93, - /* 90 */ 83, 819, 819, 831, 834, 823, 823, 90, 90, 91, - /* 100 */ 91, 91, 91, 434, 89, 89, 89, 89, 88, 88, - /* 110 */ 87, 87, 87, 86, 339, 1302, 146, 921, 2, 315, - /* 120 */ 427, 24, 679, 953, 48, 86, 339, 92, 93, 83, - /* 130 */ 819, 819, 831, 834, 823, 823, 90, 90, 91, 91, - /* 140 */ 91, 91, 94, 89, 89, 89, 89, 88, 88, 87, - /* 150 */ 87, 87, 86, 339, 933, 933, 315, 259, 412, 398, - /* 160 */ 396, 57, 733, 733, 92, 93, 83, 819, 819, 831, - /* 170 */ 834, 823, 823, 90, 90, 91, 91, 91, 91, 56, - /* 180 */ 89, 89, 89, 89, 88, 88, 87, 87, 87, 86, - /* 190 */ 339, 315, 1245, 922, 342, 268, 934, 935, 241, 92, - /* 200 */ 93, 83, 819, 819, 831, 834, 823, 823, 90, 90, - /* 210 */ 91, 91, 91, 91, 291, 89, 89, 89, 89, 88, - /* 220 */ 88, 87, 87, 87, 86, 339, 315, 913, 1295, 682, - /* 230 */ 687, 1295, 233, 397, 92, 93, 83, 819, 819, 831, - /* 240 */ 834, 823, 823, 90, 90, 91, 91, 91, 91, 326, - /* 250 */ 89, 89, 89, 89, 88, 88, 87, 87, 87, 86, - /* 260 */ 339, 315, 85, 82, 168, 680, 431, 938, 939, 92, - /* 270 */ 93, 83, 819, 819, 831, 834, 823, 823, 90, 90, - /* 280 */ 91, 91, 91, 91, 291, 89, 89, 89, 89, 88, - /* 290 */ 88, 87, 87, 87, 86, 339, 315, 319, 913, 1296, - /* 300 */ 797, 911, 1296, 681, 92, 93, 83, 819, 819, 831, - /* 310 */ 834, 823, 823, 90, 90, 91, 91, 91, 91, 335, - /* 320 */ 89, 89, 89, 89, 88, 88, 87, 87, 87, 86, - /* 330 */ 339, 315, 876, 876, 373, 85, 82, 168, 944, 92, - /* 340 */ 93, 83, 819, 819, 831, 834, 823, 823, 90, 90, - /* 350 */ 91, 91, 91, 91, 896, 89, 89, 89, 89, 88, - /* 360 */ 88, 87, 87, 87, 86, 339, 315, 370, 307, 973, - /* 370 */ 367, 1, 911, 433, 92, 93, 83, 819, 819, 831, - /* 380 */ 834, 823, 823, 90, 90, 91, 91, 91, 91, 189, - /* 390 */ 89, 89, 89, 89, 88, 88, 87, 87, 87, 86, - /* 400 */ 339, 315, 720, 948, 933, 933, 149, 718, 948, 92, - /* 410 */ 93, 83, 819, 819, 831, 834, 823, 823, 90, 90, - /* 420 */ 91, 91, 91, 91, 434, 89, 89, 89, 89, 88, - /* 430 */ 88, 87, 87, 87, 86, 339, 338, 938, 939, 947, - /* 440 */ 694, 940, 974, 315, 953, 48, 934, 935, 715, 689, - /* 450 */ 71, 92, 93, 83, 819, 819, 831, 834, 823, 823, - /* 460 */ 90, 90, 91, 91, 91, 91, 320, 89, 89, 89, - /* 470 */ 89, 88, 88, 87, 87, 87, 86, 339, 315, 412, - /* 480 */ 403, 820, 820, 832, 835, 74, 92, 81, 83, 819, - /* 490 */ 819, 831, 834, 823, 823, 90, 90, 91, 91, 91, - /* 500 */ 91, 698, 89, 89, 89, 89, 88, 88, 87, 87, - /* 510 */ 87, 86, 339, 315, 259, 654, 655, 656, 393, 111, - /* 520 */ 331, 153, 93, 83, 819, 819, 831, 834, 823, 823, - /* 530 */ 90, 90, 91, 91, 91, 91, 434, 89, 89, 89, - /* 540 */ 89, 88, 88, 87, 87, 87, 86, 339, 315, 188, - /* 550 */ 187, 186, 824, 937, 328, 219, 953, 48, 83, 819, - /* 560 */ 819, 831, 834, 823, 823, 90, 90, 91, 91, 91, - /* 570 */ 91, 956, 89, 89, 89, 89, 88, 88, 87, 87, - /* 580 */ 87, 86, 339, 79, 429, 738, 3, 1174, 955, 348, - /* 590 */ 737, 332, 792, 933, 933, 937, 79, 429, 730, 3, - /* 600 */ 203, 160, 278, 391, 273, 390, 190, 892, 434, 400, - /* 610 */ 741, 76, 77, 271, 287, 253, 353, 242, 78, 340, - /* 620 */ 340, 85, 82, 168, 76, 77, 233, 397, 953, 48, - /* 630 */ 432, 78, 340, 340, 277, 934, 935, 185, 439, 651, - /* 640 */ 388, 385, 384, 432, 234, 276, 107, 418, 349, 337, - /* 650 */ 336, 383, 893, 728, 215, 949, 123, 971, 308, 810, - /* 660 */ 418, 436, 435, 412, 394, 798, 400, 873, 894, 123, - /* 670 */ 721, 872, 810, 889, 436, 435, 215, 949, 798, 351, - /* 680 */ 722, 697, 380, 434, 771, 371, 22, 434, 400, 79, - /* 690 */ 429, 232, 3, 189, 413, 870, 803, 803, 803, 805, - /* 700 */ 18, 54, 148, 953, 48, 956, 113, 953, 9, 803, - /* 710 */ 803, 803, 805, 18, 310, 123, 748, 76, 77, 742, - /* 720 */ 123, 325, 955, 866, 78, 340, 340, 113, 350, 359, - /* 730 */ 85, 82, 168, 343, 960, 960, 432, 770, 412, 414, - /* 740 */ 407, 23, 1240, 1240, 79, 429, 357, 3, 166, 91, - /* 750 */ 91, 91, 91, 418, 89, 89, 89, 89, 88, 88, - /* 760 */ 87, 87, 87, 86, 339, 810, 434, 436, 435, 792, - /* 770 */ 320, 798, 76, 77, 789, 271, 123, 434, 360, 78, - /* 780 */ 340, 340, 864, 85, 82, 168, 953, 9, 395, 743, - /* 790 */ 360, 432, 253, 358, 252, 933, 933, 953, 30, 889, - /* 800 */ 327, 216, 803, 803, 803, 805, 18, 113, 418, 89, - /* 810 */ 89, 89, 89, 88, 88, 87, 87, 87, 86, 339, - /* 820 */ 810, 113, 436, 435, 792, 185, 798, 288, 388, 385, - /* 830 */ 384, 123, 113, 920, 2, 796, 696, 934, 935, 383, - /* 840 */ 69, 429, 434, 3, 218, 110, 738, 253, 358, 252, - /* 850 */ 434, 737, 933, 933, 892, 359, 222, 803, 803, 803, - /* 860 */ 805, 18, 953, 47, 933, 933, 933, 933, 76, 77, - /* 870 */ 953, 9, 366, 904, 217, 78, 340, 340, 677, 305, - /* 880 */ 304, 303, 206, 301, 224, 259, 664, 432, 337, 336, - /* 890 */ 434, 228, 247, 144, 934, 935, 933, 933, 667, 893, - /* 900 */ 324, 1259, 96, 434, 418, 796, 934, 935, 934, 935, - /* 910 */ 953, 48, 401, 148, 289, 894, 810, 417, 436, 435, - /* 920 */ 677, 759, 798, 953, 9, 314, 220, 162, 161, 170, - /* 930 */ 402, 239, 953, 8, 194, 683, 683, 410, 934, 935, - /* 940 */ 238, 959, 933, 933, 225, 408, 945, 365, 957, 212, - /* 950 */ 958, 172, 757, 803, 803, 803, 805, 18, 173, 365, - /* 960 */ 176, 123, 171, 113, 244, 952, 246, 434, 356, 796, - /* 970 */ 372, 365, 236, 960, 960, 810, 290, 804, 191, 165, - /* 980 */ 852, 798, 259, 316, 934, 935, 237, 953, 34, 404, - /* 990 */ 91, 91, 91, 91, 84, 89, 89, 89, 89, 88, - /* 1000 */ 88, 87, 87, 87, 86, 339, 701, 952, 434, 240, - /* 1010 */ 347, 758, 803, 803, 803, 434, 245, 1179, 434, 389, - /* 1020 */ 434, 376, 434, 895, 167, 434, 405, 702, 953, 35, - /* 1030 */ 673, 321, 221, 434, 333, 953, 11, 434, 953, 26, - /* 1040 */ 953, 36, 953, 37, 251, 953, 38, 434, 259, 434, - /* 1050 */ 757, 434, 329, 953, 27, 434, 223, 953, 28, 434, - /* 1060 */ 690, 434, 67, 434, 65, 434, 862, 953, 39, 953, - /* 1070 */ 40, 953, 41, 423, 434, 953, 10, 434, 772, 953, - /* 1080 */ 42, 953, 98, 953, 43, 953, 44, 773, 434, 346, - /* 1090 */ 434, 75, 434, 73, 953, 31, 434, 953, 45, 434, - /* 1100 */ 259, 434, 690, 434, 757, 434, 887, 434, 953, 46, - /* 1110 */ 953, 32, 953, 115, 434, 266, 953, 116, 951, 953, - /* 1120 */ 117, 953, 52, 953, 33, 953, 99, 953, 49, 726, - /* 1130 */ 434, 909, 434, 19, 953, 100, 434, 344, 434, 113, - /* 1140 */ 434, 258, 692, 434, 259, 434, 670, 434, 20, 434, - /* 1150 */ 953, 101, 953, 97, 434, 259, 953, 114, 953, 112, - /* 1160 */ 953, 105, 113, 953, 104, 953, 102, 953, 103, 953, - /* 1170 */ 51, 434, 148, 434, 953, 53, 167, 434, 259, 113, - /* 1180 */ 300, 307, 912, 363, 311, 860, 248, 261, 209, 264, - /* 1190 */ 416, 953, 50, 953, 25, 420, 727, 953, 29, 430, - /* 1200 */ 321, 424, 757, 428, 322, 124, 1269, 214, 165, 710, - /* 1210 */ 859, 908, 806, 794, 309, 158, 193, 361, 254, 723, - /* 1220 */ 364, 67, 381, 269, 735, 199, 67, 70, 113, 700, - /* 1230 */ 699, 707, 708, 884, 113, 766, 113, 855, 193, 883, - /* 1240 */ 199, 869, 869, 675, 868, 868, 109, 368, 255, 260, - /* 1250 */ 263, 280, 859, 265, 806, 974, 267, 711, 695, 272, - /* 1260 */ 764, 282, 795, 284, 150, 744, 755, 415, 292, 293, - /* 1270 */ 802, 678, 672, 661, 660, 662, 927, 6, 306, 386, - /* 1280 */ 352, 786, 243, 250, 886, 362, 163, 286, 419, 298, - /* 1290 */ 930, 159, 968, 196, 126, 903, 901, 965, 55, 58, - /* 1300 */ 323, 275, 857, 136, 147, 694, 856, 121, 65, 354, - /* 1310 */ 355, 379, 175, 61, 151, 369, 180, 871, 375, 129, - /* 1320 */ 257, 756, 210, 181, 145, 131, 132, 377, 262, 663, - /* 1330 */ 133, 134, 139, 783, 791, 182, 392, 183, 312, 330, - /* 1340 */ 714, 888, 713, 851, 692, 195, 712, 406, 686, 705, - /* 1350 */ 313, 685, 64, 839, 274, 72, 684, 334, 942, 95, - /* 1360 */ 752, 279, 281, 704, 753, 751, 422, 283, 411, 750, - /* 1370 */ 426, 66, 204, 409, 21, 285, 928, 669, 437, 205, - /* 1380 */ 207, 208, 438, 658, 657, 652, 118, 108, 119, 226, - /* 1390 */ 650, 341, 157, 235, 169, 345, 106, 734, 790, 296, - /* 1400 */ 294, 295, 120, 297, 867, 865, 127, 128, 130, 724, - /* 1410 */ 229, 174, 249, 882, 137, 230, 138, 135, 885, 231, - /* 1420 */ 59, 60, 177, 881, 7, 178, 12, 179, 256, 874, - /* 1430 */ 140, 193, 962, 374, 141, 152, 666, 378, 276, 184, - /* 1440 */ 270, 122, 142, 382, 387, 62, 13, 14, 703, 63, - /* 1450 */ 125, 317, 318, 227, 809, 808, 837, 732, 15, 164, - /* 1460 */ 736, 4, 765, 211, 399, 213, 192, 143, 760, 70, - /* 1470 */ 67, 16, 17, 838, 836, 891, 841, 890, 198, 197, - /* 1480 */ 917, 154, 421, 923, 918, 155, 200, 977, 425, 840, - /* 1490 */ 156, 201, 807, 676, 80, 302, 299, 977, 202, 1261, - /* 1500 */ 1260, + /* 0 */ 317, 814, 341, 808, 5, 195, 195, 802, 93, 94, + /* 10 */ 84, 823, 823, 835, 838, 827, 827, 91, 91, 92, + /* 20 */ 92, 92, 92, 293, 90, 90, 90, 90, 89, 89, + /* 30 */ 88, 88, 88, 87, 341, 317, 958, 958, 807, 807, + /* 40 */ 807, 928, 344, 93, 94, 84, 823, 823, 835, 838, + /* 50 */ 827, 827, 91, 91, 92, 92, 92, 92, 328, 90, + /* 60 */ 90, 90, 90, 89, 89, 88, 88, 88, 87, 341, + /* 70 */ 89, 89, 88, 88, 88, 87, 341, 776, 958, 958, + /* 80 */ 317, 88, 88, 88, 87, 341, 777, 69, 93, 94, + /* 90 */ 84, 823, 823, 835, 838, 827, 827, 91, 91, 92, + /* 100 */ 92, 92, 92, 437, 90, 90, 90, 90, 89, 89, + /* 110 */ 88, 88, 88, 87, 341, 1310, 147, 147, 2, 317, + /* 120 */ 76, 25, 74, 49, 49, 87, 341, 93, 94, 84, + /* 130 */ 823, 823, 835, 838, 827, 827, 91, 91, 92, 92, + /* 140 */ 92, 92, 95, 90, 90, 90, 90, 89, 89, 88, + /* 150 */ 88, 88, 87, 341, 939, 939, 317, 260, 415, 400, + /* 160 */ 398, 58, 737, 737, 93, 94, 84, 823, 823, 835, + /* 170 */ 838, 827, 827, 91, 91, 92, 92, 92, 92, 57, + /* 180 */ 90, 90, 90, 90, 89, 89, 88, 88, 88, 87, + /* 190 */ 341, 317, 1253, 928, 344, 269, 940, 941, 242, 93, + /* 200 */ 94, 84, 823, 823, 835, 838, 827, 827, 91, 91, + /* 210 */ 92, 92, 92, 92, 293, 90, 90, 90, 90, 89, + /* 220 */ 89, 88, 88, 88, 87, 341, 317, 919, 1303, 793, + /* 230 */ 691, 1303, 724, 724, 93, 94, 84, 823, 823, 835, + /* 240 */ 838, 827, 827, 91, 91, 92, 92, 92, 92, 337, + /* 250 */ 90, 90, 90, 90, 89, 89, 88, 88, 88, 87, + /* 260 */ 341, 317, 114, 919, 1304, 684, 395, 1304, 124, 93, + /* 270 */ 94, 84, 823, 823, 835, 838, 827, 827, 91, 91, + /* 280 */ 92, 92, 92, 92, 683, 90, 90, 90, 90, 89, + /* 290 */ 89, 88, 88, 88, 87, 341, 317, 86, 83, 169, + /* 300 */ 801, 917, 234, 399, 93, 94, 84, 823, 823, 835, + /* 310 */ 838, 827, 827, 91, 91, 92, 92, 92, 92, 686, + /* 320 */ 90, 90, 90, 90, 89, 89, 88, 88, 88, 87, + /* 330 */ 341, 317, 436, 742, 86, 83, 169, 917, 741, 93, + /* 340 */ 94, 84, 823, 823, 835, 838, 827, 827, 91, 91, + /* 350 */ 92, 92, 92, 92, 902, 90, 90, 90, 90, 89, + /* 360 */ 89, 88, 88, 88, 87, 341, 317, 321, 434, 434, + /* 370 */ 434, 1, 722, 722, 93, 94, 84, 823, 823, 835, + /* 380 */ 838, 827, 827, 91, 91, 92, 92, 92, 92, 190, + /* 390 */ 90, 90, 90, 90, 89, 89, 88, 88, 88, 87, + /* 400 */ 341, 317, 685, 292, 939, 939, 150, 977, 310, 93, + /* 410 */ 94, 84, 823, 823, 835, 838, 827, 827, 91, 91, + /* 420 */ 92, 92, 92, 92, 437, 90, 90, 90, 90, 89, + /* 430 */ 89, 88, 88, 88, 87, 341, 926, 2, 372, 719, + /* 440 */ 698, 369, 950, 317, 49, 49, 940, 941, 719, 177, + /* 450 */ 72, 93, 94, 84, 823, 823, 835, 838, 827, 827, + /* 460 */ 91, 91, 92, 92, 92, 92, 322, 90, 90, 90, + /* 470 */ 90, 89, 89, 88, 88, 88, 87, 341, 317, 415, + /* 480 */ 405, 824, 824, 836, 839, 75, 93, 82, 84, 823, + /* 490 */ 823, 835, 838, 827, 827, 91, 91, 92, 92, 92, + /* 500 */ 92, 430, 90, 90, 90, 90, 89, 89, 88, 88, + /* 510 */ 88, 87, 341, 317, 340, 340, 340, 658, 659, 660, + /* 520 */ 333, 288, 94, 84, 823, 823, 835, 838, 827, 827, + /* 530 */ 91, 91, 92, 92, 92, 92, 437, 90, 90, 90, + /* 540 */ 90, 89, 89, 88, 88, 88, 87, 341, 317, 882, + /* 550 */ 882, 375, 828, 66, 330, 409, 49, 49, 84, 823, + /* 560 */ 823, 835, 838, 827, 827, 91, 91, 92, 92, 92, + /* 570 */ 92, 351, 90, 90, 90, 90, 89, 89, 88, 88, + /* 580 */ 88, 87, 341, 80, 432, 742, 3, 1180, 351, 350, + /* 590 */ 741, 334, 796, 939, 939, 761, 80, 432, 278, 3, + /* 600 */ 204, 161, 279, 393, 274, 392, 191, 362, 437, 277, + /* 610 */ 745, 77, 78, 272, 800, 254, 355, 243, 79, 342, + /* 620 */ 342, 86, 83, 169, 77, 78, 234, 399, 49, 49, + /* 630 */ 435, 79, 342, 342, 437, 940, 941, 186, 442, 655, + /* 640 */ 390, 387, 386, 435, 235, 213, 108, 421, 761, 351, + /* 650 */ 437, 385, 167, 732, 10, 10, 124, 124, 671, 814, + /* 660 */ 421, 439, 438, 415, 414, 802, 362, 168, 327, 124, + /* 670 */ 49, 49, 814, 219, 439, 438, 800, 186, 802, 326, + /* 680 */ 390, 387, 386, 437, 1248, 1248, 23, 939, 939, 80, + /* 690 */ 432, 385, 3, 761, 416, 876, 807, 807, 807, 809, + /* 700 */ 19, 290, 149, 49, 49, 415, 396, 260, 910, 807, + /* 710 */ 807, 807, 809, 19, 312, 237, 145, 77, 78, 746, + /* 720 */ 168, 702, 437, 149, 79, 342, 342, 114, 358, 940, + /* 730 */ 941, 302, 223, 397, 345, 313, 435, 260, 415, 417, + /* 740 */ 858, 374, 31, 31, 80, 432, 761, 3, 348, 92, + /* 750 */ 92, 92, 92, 421, 90, 90, 90, 90, 89, 89, + /* 760 */ 88, 88, 88, 87, 341, 814, 114, 439, 438, 796, + /* 770 */ 367, 802, 77, 78, 701, 796, 124, 1187, 220, 79, + /* 780 */ 342, 342, 124, 747, 734, 939, 939, 775, 404, 939, + /* 790 */ 939, 435, 254, 360, 253, 402, 895, 346, 254, 360, + /* 800 */ 253, 774, 807, 807, 807, 809, 19, 800, 421, 90, + /* 810 */ 90, 90, 90, 89, 89, 88, 88, 88, 87, 341, + /* 820 */ 814, 114, 439, 438, 939, 939, 802, 940, 941, 114, + /* 830 */ 437, 940, 941, 86, 83, 169, 192, 166, 309, 979, + /* 840 */ 70, 432, 700, 3, 382, 870, 238, 86, 83, 169, + /* 850 */ 10, 10, 361, 406, 763, 190, 222, 807, 807, 807, + /* 860 */ 809, 19, 870, 872, 329, 24, 940, 941, 77, 78, + /* 870 */ 359, 437, 335, 260, 218, 79, 342, 342, 437, 307, + /* 880 */ 306, 305, 207, 303, 339, 338, 668, 435, 339, 338, + /* 890 */ 407, 10, 10, 762, 216, 216, 939, 939, 49, 49, + /* 900 */ 437, 260, 97, 241, 421, 225, 402, 189, 188, 187, + /* 910 */ 309, 918, 980, 149, 221, 898, 814, 868, 439, 438, + /* 920 */ 10, 10, 802, 870, 915, 316, 898, 163, 162, 171, + /* 930 */ 249, 240, 322, 410, 412, 687, 687, 272, 940, 941, + /* 940 */ 239, 965, 901, 437, 226, 403, 226, 437, 963, 367, + /* 950 */ 964, 173, 248, 807, 807, 807, 809, 19, 174, 367, + /* 960 */ 899, 124, 172, 48, 48, 9, 9, 35, 35, 966, + /* 970 */ 966, 899, 363, 966, 966, 814, 900, 808, 725, 939, + /* 980 */ 939, 802, 895, 318, 980, 324, 125, 900, 726, 420, + /* 990 */ 92, 92, 92, 92, 85, 90, 90, 90, 90, 89, + /* 1000 */ 89, 88, 88, 88, 87, 341, 216, 216, 437, 946, + /* 1010 */ 349, 292, 807, 807, 807, 114, 291, 693, 402, 705, + /* 1020 */ 890, 940, 941, 437, 245, 889, 247, 437, 36, 36, + /* 1030 */ 437, 353, 391, 437, 260, 252, 260, 437, 361, 437, + /* 1040 */ 706, 437, 370, 12, 12, 224, 437, 27, 27, 437, + /* 1050 */ 37, 37, 437, 38, 38, 752, 368, 39, 39, 28, + /* 1060 */ 28, 29, 29, 215, 166, 331, 40, 40, 437, 41, + /* 1070 */ 41, 437, 42, 42, 437, 866, 246, 731, 437, 879, + /* 1080 */ 437, 256, 437, 878, 437, 267, 437, 261, 11, 11, + /* 1090 */ 437, 43, 43, 437, 99, 99, 437, 373, 44, 44, + /* 1100 */ 45, 45, 32, 32, 46, 46, 47, 47, 437, 426, + /* 1110 */ 33, 33, 776, 116, 116, 437, 117, 117, 437, 124, + /* 1120 */ 437, 777, 437, 260, 437, 957, 437, 352, 118, 118, + /* 1130 */ 437, 195, 437, 111, 437, 53, 53, 264, 34, 34, + /* 1140 */ 100, 100, 50, 50, 101, 101, 102, 102, 437, 260, + /* 1150 */ 98, 98, 115, 115, 113, 113, 437, 262, 437, 265, + /* 1160 */ 437, 943, 958, 437, 727, 437, 681, 437, 106, 106, + /* 1170 */ 68, 437, 893, 730, 437, 365, 105, 105, 103, 103, + /* 1180 */ 104, 104, 217, 52, 52, 54, 54, 51, 51, 694, + /* 1190 */ 259, 26, 26, 266, 30, 30, 677, 323, 433, 323, + /* 1200 */ 674, 423, 427, 943, 958, 114, 114, 431, 681, 865, + /* 1210 */ 1277, 233, 366, 714, 112, 20, 154, 704, 703, 810, + /* 1220 */ 914, 55, 159, 311, 798, 255, 383, 194, 68, 200, + /* 1230 */ 21, 694, 268, 114, 114, 114, 270, 711, 712, 68, + /* 1240 */ 114, 739, 770, 715, 71, 194, 861, 875, 875, 200, + /* 1250 */ 696, 865, 874, 874, 679, 699, 273, 110, 229, 419, + /* 1260 */ 768, 810, 799, 378, 748, 759, 418, 210, 294, 281, + /* 1270 */ 295, 806, 283, 682, 676, 665, 664, 666, 933, 151, + /* 1280 */ 285, 7, 1267, 308, 251, 790, 354, 244, 892, 364, + /* 1290 */ 287, 422, 300, 164, 160, 936, 974, 127, 197, 137, + /* 1300 */ 909, 907, 971, 388, 276, 863, 862, 56, 698, 325, + /* 1310 */ 148, 59, 122, 66, 356, 381, 357, 176, 152, 62, + /* 1320 */ 371, 130, 877, 181, 377, 760, 211, 182, 132, 133, + /* 1330 */ 134, 135, 258, 146, 140, 795, 787, 263, 183, 379, + /* 1340 */ 667, 394, 184, 332, 894, 314, 718, 717, 857, 716, + /* 1350 */ 696, 315, 709, 690, 65, 196, 6, 408, 289, 708, + /* 1360 */ 275, 689, 688, 948, 756, 757, 280, 282, 425, 755, + /* 1370 */ 284, 336, 73, 67, 754, 429, 411, 96, 286, 413, + /* 1380 */ 205, 934, 673, 22, 209, 440, 119, 120, 109, 206, + /* 1390 */ 208, 441, 662, 661, 656, 843, 654, 343, 158, 236, + /* 1400 */ 170, 347, 107, 227, 121, 738, 873, 298, 296, 297, + /* 1410 */ 299, 871, 794, 128, 129, 728, 230, 131, 175, 250, + /* 1420 */ 888, 136, 138, 231, 232, 139, 60, 61, 891, 178, + /* 1430 */ 179, 887, 8, 13, 180, 257, 880, 968, 194, 141, + /* 1440 */ 142, 376, 153, 670, 380, 185, 143, 277, 63, 384, + /* 1450 */ 14, 707, 271, 15, 389, 64, 319, 320, 126, 228, + /* 1460 */ 813, 812, 841, 736, 123, 16, 401, 740, 4, 769, + /* 1470 */ 165, 212, 214, 193, 144, 764, 71, 68, 17, 18, + /* 1480 */ 856, 842, 840, 897, 845, 896, 199, 198, 923, 155, + /* 1490 */ 424, 929, 924, 156, 201, 202, 428, 844, 157, 203, + /* 1500 */ 811, 680, 81, 1269, 1268, 301, 304, }; static const YYCODETYPE yy_lookahead[] = { /* 0 */ 19, 95, 53, 97, 22, 24, 24, 101, 27, 28, /* 10 */ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, /* 20 */ 39, 40, 41, 152, 43, 44, 45, 46, 47, 48, /* 30 */ 49, 50, 51, 52, 53, 19, 55, 55, 132, 133, /* 40 */ 134, 1, 2, 27, 28, 29, 30, 31, 32, 33, - /* 50 */ 34, 35, 36, 37, 38, 39, 40, 41, 92, 43, + /* 50 */ 34, 35, 36, 37, 38, 39, 40, 41, 187, 43, /* 60 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, /* 70 */ 47, 48, 49, 50, 51, 52, 53, 61, 97, 97, /* 80 */ 19, 49, 50, 51, 52, 53, 70, 26, 27, 28, /* 90 */ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, /* 100 */ 39, 40, 41, 152, 43, 44, 45, 46, 47, 48, /* 110 */ 49, 50, 51, 52, 53, 144, 145, 146, 147, 19, - /* 120 */ 249, 22, 172, 172, 173, 52, 53, 27, 28, 29, + /* 120 */ 137, 22, 139, 172, 173, 52, 53, 27, 28, 29, /* 130 */ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, /* 140 */ 40, 41, 81, 43, 44, 45, 46, 47, 48, 49, /* 150 */ 50, 51, 52, 53, 55, 56, 19, 152, 207, 208, /* 160 */ 115, 24, 117, 118, 27, 28, 29, 30, 31, 32, /* 170 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 79, /* 180 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, /* 190 */ 53, 19, 0, 1, 2, 23, 97, 98, 193, 27, /* 200 */ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, /* 210 */ 38, 39, 40, 41, 152, 43, 44, 45, 46, 47, - /* 220 */ 48, 49, 50, 51, 52, 53, 19, 22, 23, 172, - /* 230 */ 23, 26, 119, 120, 27, 28, 29, 30, 31, 32, + /* 220 */ 48, 49, 50, 51, 52, 53, 19, 22, 23, 163, + /* 230 */ 23, 26, 190, 191, 27, 28, 29, 30, 31, 32, /* 240 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 187, /* 250 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, - /* 260 */ 53, 19, 221, 222, 223, 23, 168, 169, 170, 27, + /* 260 */ 53, 19, 196, 22, 23, 23, 49, 26, 92, 27, /* 270 */ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, - /* 280 */ 38, 39, 40, 41, 152, 43, 44, 45, 46, 47, - /* 290 */ 48, 49, 50, 51, 52, 53, 19, 157, 22, 23, - /* 300 */ 23, 96, 26, 172, 27, 28, 29, 30, 31, 32, - /* 310 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 187, + /* 280 */ 38, 39, 40, 41, 172, 43, 44, 45, 46, 47, + /* 290 */ 48, 49, 50, 51, 52, 53, 19, 221, 222, 223, + /* 300 */ 23, 96, 119, 120, 27, 28, 29, 30, 31, 32, + /* 310 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 172, /* 320 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, - /* 330 */ 53, 19, 108, 109, 110, 221, 222, 223, 185, 27, + /* 330 */ 53, 19, 152, 116, 221, 222, 223, 96, 121, 27, /* 340 */ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, - /* 350 */ 38, 39, 40, 41, 240, 43, 44, 45, 46, 47, - /* 360 */ 48, 49, 50, 51, 52, 53, 19, 227, 22, 23, - /* 370 */ 230, 22, 96, 152, 27, 28, 29, 30, 31, 32, + /* 350 */ 38, 39, 40, 41, 241, 43, 44, 45, 46, 47, + /* 360 */ 48, 49, 50, 51, 52, 53, 19, 157, 168, 169, + /* 370 */ 170, 22, 190, 191, 27, 28, 29, 30, 31, 32, /* 380 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 30, /* 390 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, - /* 400 */ 53, 19, 190, 191, 55, 56, 24, 190, 191, 27, + /* 400 */ 53, 19, 172, 152, 55, 56, 24, 247, 248, 27, /* 410 */ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, /* 420 */ 38, 39, 40, 41, 152, 43, 44, 45, 46, 47, - /* 430 */ 48, 49, 50, 51, 52, 53, 168, 169, 170, 179, - /* 440 */ 180, 171, 96, 19, 172, 173, 97, 98, 188, 179, + /* 430 */ 48, 49, 50, 51, 52, 53, 146, 147, 228, 179, + /* 440 */ 180, 231, 185, 19, 172, 173, 97, 98, 188, 26, /* 450 */ 138, 27, 28, 29, 30, 31, 32, 33, 34, 35, /* 460 */ 36, 37, 38, 39, 40, 41, 107, 43, 44, 45, /* 470 */ 46, 47, 48, 49, 50, 51, 52, 53, 19, 207, /* 480 */ 208, 30, 31, 32, 33, 138, 27, 28, 29, 30, /* 490 */ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - /* 500 */ 41, 181, 43, 44, 45, 46, 47, 48, 49, 50, - /* 510 */ 51, 52, 53, 19, 152, 7, 8, 9, 49, 22, - /* 520 */ 19, 24, 28, 29, 30, 31, 32, 33, 34, 35, + /* 500 */ 41, 250, 43, 44, 45, 46, 47, 48, 49, 50, + /* 510 */ 51, 52, 53, 19, 168, 169, 170, 7, 8, 9, + /* 520 */ 19, 152, 28, 29, 30, 31, 32, 33, 34, 35, /* 530 */ 36, 37, 38, 39, 40, 41, 152, 43, 44, 45, /* 540 */ 46, 47, 48, 49, 50, 51, 52, 53, 19, 108, - /* 550 */ 109, 110, 101, 55, 53, 193, 172, 173, 29, 30, + /* 550 */ 109, 110, 101, 130, 53, 152, 172, 173, 29, 30, /* 560 */ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 570 */ 41, 152, 43, 44, 45, 46, 47, 48, 49, 50, /* 580 */ 51, 52, 53, 19, 20, 116, 22, 23, 169, 170, - /* 590 */ 121, 207, 85, 55, 56, 97, 19, 20, 195, 22, - /* 600 */ 99, 100, 101, 102, 103, 104, 105, 12, 152, 206, + /* 590 */ 121, 207, 85, 55, 56, 26, 19, 20, 101, 22, + /* 600 */ 99, 100, 101, 102, 103, 104, 105, 152, 152, 112, /* 610 */ 210, 47, 48, 112, 152, 108, 109, 110, 54, 55, /* 620 */ 56, 221, 222, 223, 47, 48, 119, 120, 172, 173, - /* 630 */ 66, 54, 55, 56, 101, 97, 98, 99, 148, 149, - /* 640 */ 102, 103, 104, 66, 154, 112, 156, 83, 229, 47, - /* 650 */ 48, 113, 57, 163, 194, 195, 92, 246, 247, 95, - /* 660 */ 83, 97, 98, 207, 208, 101, 206, 59, 73, 92, - /* 670 */ 75, 63, 95, 163, 97, 98, 194, 195, 101, 219, - /* 680 */ 85, 181, 19, 152, 175, 77, 196, 152, 206, 19, - /* 690 */ 20, 199, 22, 30, 163, 11, 132, 133, 134, 135, - /* 700 */ 136, 209, 152, 172, 173, 152, 196, 172, 173, 132, - /* 710 */ 133, 134, 135, 136, 164, 92, 213, 47, 48, 49, - /* 720 */ 92, 186, 169, 170, 54, 55, 56, 196, 100, 219, - /* 730 */ 221, 222, 223, 243, 132, 133, 66, 175, 207, 208, - /* 740 */ 152, 231, 119, 120, 19, 20, 236, 22, 152, 38, + /* 630 */ 66, 54, 55, 56, 152, 97, 98, 99, 148, 149, + /* 640 */ 102, 103, 104, 66, 154, 23, 156, 83, 26, 230, + /* 650 */ 152, 113, 152, 163, 172, 173, 92, 92, 21, 95, + /* 660 */ 83, 97, 98, 207, 208, 101, 152, 98, 186, 92, + /* 670 */ 172, 173, 95, 218, 97, 98, 152, 99, 101, 217, + /* 680 */ 102, 103, 104, 152, 119, 120, 196, 55, 56, 19, + /* 690 */ 20, 113, 22, 124, 163, 11, 132, 133, 134, 135, + /* 700 */ 136, 152, 152, 172, 173, 207, 208, 152, 152, 132, + /* 710 */ 133, 134, 135, 136, 164, 152, 84, 47, 48, 49, + /* 720 */ 98, 181, 152, 152, 54, 55, 56, 196, 91, 97, + /* 730 */ 98, 160, 218, 163, 244, 164, 66, 152, 207, 208, + /* 740 */ 103, 217, 172, 173, 19, 20, 124, 22, 193, 38, /* 750 */ 39, 40, 41, 83, 43, 44, 45, 46, 47, 48, - /* 760 */ 49, 50, 51, 52, 53, 95, 152, 97, 98, 85, - /* 770 */ 107, 101, 47, 48, 163, 112, 92, 152, 152, 54, - /* 780 */ 55, 56, 229, 221, 222, 223, 172, 173, 163, 49, - /* 790 */ 152, 66, 108, 109, 110, 55, 56, 172, 173, 163, - /* 800 */ 186, 22, 132, 133, 134, 135, 136, 196, 83, 43, + /* 760 */ 49, 50, 51, 52, 53, 95, 196, 97, 98, 85, + /* 770 */ 152, 101, 47, 48, 181, 85, 92, 140, 193, 54, + /* 780 */ 55, 56, 92, 49, 195, 55, 56, 175, 163, 55, + /* 790 */ 56, 66, 108, 109, 110, 206, 163, 242, 108, 109, + /* 800 */ 110, 175, 132, 133, 134, 135, 136, 152, 83, 43, /* 810 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - /* 820 */ 95, 196, 97, 98, 85, 99, 101, 152, 102, 103, - /* 830 */ 104, 92, 196, 146, 147, 152, 181, 97, 98, 113, - /* 840 */ 19, 20, 152, 22, 218, 22, 116, 108, 109, 110, - /* 850 */ 152, 121, 55, 56, 12, 219, 218, 132, 133, 134, - /* 860 */ 135, 136, 172, 173, 55, 56, 55, 56, 47, 48, - /* 870 */ 172, 173, 236, 152, 5, 54, 55, 56, 55, 10, - /* 880 */ 11, 12, 13, 14, 186, 152, 17, 66, 47, 48, - /* 890 */ 152, 210, 16, 84, 97, 98, 55, 56, 21, 57, - /* 900 */ 217, 122, 22, 152, 83, 152, 97, 98, 97, 98, - /* 910 */ 172, 173, 152, 152, 224, 73, 95, 75, 97, 98, - /* 920 */ 97, 124, 101, 172, 173, 164, 193, 47, 48, 60, - /* 930 */ 163, 62, 172, 173, 24, 55, 56, 186, 97, 98, - /* 940 */ 71, 100, 55, 56, 183, 207, 185, 152, 107, 23, - /* 950 */ 109, 82, 26, 132, 133, 134, 135, 136, 89, 152, - /* 960 */ 26, 92, 93, 196, 88, 55, 90, 152, 91, 152, - /* 970 */ 217, 152, 152, 132, 133, 95, 152, 97, 211, 212, - /* 980 */ 103, 101, 152, 114, 97, 98, 152, 172, 173, 19, + /* 820 */ 95, 196, 97, 98, 55, 56, 101, 97, 98, 196, + /* 830 */ 152, 97, 98, 221, 222, 223, 211, 212, 22, 23, + /* 840 */ 19, 20, 181, 22, 19, 152, 152, 221, 222, 223, + /* 850 */ 172, 173, 219, 19, 124, 30, 238, 132, 133, 134, + /* 860 */ 135, 136, 169, 170, 186, 232, 97, 98, 47, 48, + /* 870 */ 237, 152, 217, 152, 5, 54, 55, 56, 152, 10, + /* 880 */ 11, 12, 13, 14, 47, 48, 17, 66, 47, 48, + /* 890 */ 56, 172, 173, 124, 194, 195, 55, 56, 172, 173, + /* 900 */ 152, 152, 22, 152, 83, 186, 206, 108, 109, 110, + /* 910 */ 22, 23, 96, 152, 193, 12, 95, 152, 97, 98, + /* 920 */ 172, 173, 101, 230, 152, 164, 12, 47, 48, 60, + /* 930 */ 152, 62, 107, 207, 186, 55, 56, 112, 97, 98, + /* 940 */ 71, 100, 193, 152, 183, 152, 185, 152, 107, 152, + /* 950 */ 109, 82, 16, 132, 133, 134, 135, 136, 89, 152, + /* 960 */ 57, 92, 93, 172, 173, 172, 173, 172, 173, 132, + /* 970 */ 133, 57, 152, 132, 133, 95, 73, 97, 75, 55, + /* 980 */ 56, 101, 163, 114, 96, 245, 246, 73, 85, 75, /* 990 */ 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - /* 1000 */ 48, 49, 50, 51, 52, 53, 65, 97, 152, 152, - /* 1010 */ 141, 124, 132, 133, 134, 152, 140, 140, 152, 78, - /* 1020 */ 152, 233, 152, 193, 98, 152, 56, 86, 172, 173, - /* 1030 */ 166, 167, 237, 152, 217, 172, 173, 152, 172, 173, - /* 1040 */ 172, 173, 172, 173, 237, 172, 173, 152, 152, 152, - /* 1050 */ 124, 152, 111, 172, 173, 152, 237, 172, 173, 152, - /* 1060 */ 55, 152, 26, 152, 130, 152, 152, 172, 173, 172, - /* 1070 */ 173, 172, 173, 249, 152, 172, 173, 152, 61, 172, - /* 1080 */ 173, 172, 173, 172, 173, 172, 173, 70, 152, 193, - /* 1090 */ 152, 137, 152, 139, 172, 173, 152, 172, 173, 152, - /* 1100 */ 152, 152, 97, 152, 26, 152, 163, 152, 172, 173, - /* 1110 */ 172, 173, 172, 173, 152, 16, 172, 173, 26, 172, - /* 1120 */ 173, 172, 173, 172, 173, 172, 173, 172, 173, 163, - /* 1130 */ 152, 152, 152, 22, 172, 173, 152, 241, 152, 196, - /* 1140 */ 152, 193, 106, 152, 152, 152, 163, 152, 37, 152, - /* 1150 */ 172, 173, 172, 173, 152, 152, 172, 173, 172, 173, - /* 1160 */ 172, 173, 196, 172, 173, 172, 173, 172, 173, 172, - /* 1170 */ 173, 152, 152, 152, 172, 173, 98, 152, 152, 196, - /* 1180 */ 160, 22, 23, 19, 164, 193, 152, 88, 232, 90, - /* 1190 */ 191, 172, 173, 172, 173, 163, 193, 172, 173, 166, - /* 1200 */ 167, 163, 124, 163, 244, 245, 23, 211, 212, 26, - /* 1210 */ 55, 23, 55, 23, 26, 123, 26, 152, 23, 193, - /* 1220 */ 56, 26, 23, 23, 23, 26, 26, 26, 196, 100, - /* 1230 */ 101, 7, 8, 152, 196, 23, 196, 23, 26, 152, - /* 1240 */ 26, 132, 133, 23, 132, 133, 26, 152, 152, 152, - /* 1250 */ 152, 210, 97, 152, 97, 96, 152, 152, 152, 152, - /* 1260 */ 152, 210, 152, 210, 197, 152, 152, 152, 152, 152, - /* 1270 */ 152, 152, 152, 152, 152, 152, 152, 198, 150, 176, - /* 1280 */ 214, 201, 214, 238, 201, 238, 184, 214, 226, 200, - /* 1290 */ 155, 198, 67, 122, 242, 159, 159, 69, 239, 239, - /* 1300 */ 159, 175, 175, 22, 220, 180, 175, 27, 130, 18, - /* 1310 */ 159, 18, 158, 137, 220, 159, 158, 235, 74, 189, - /* 1320 */ 234, 159, 159, 158, 22, 192, 192, 177, 159, 159, - /* 1330 */ 192, 192, 189, 201, 189, 158, 107, 158, 177, 76, - /* 1340 */ 174, 201, 174, 201, 106, 159, 174, 125, 174, 182, - /* 1350 */ 177, 176, 107, 159, 174, 137, 174, 53, 174, 129, - /* 1360 */ 216, 215, 215, 182, 216, 216, 177, 215, 126, 216, - /* 1370 */ 177, 128, 25, 127, 26, 215, 13, 162, 161, 153, - /* 1380 */ 153, 6, 151, 151, 151, 151, 165, 178, 165, 178, - /* 1390 */ 4, 3, 22, 142, 15, 94, 16, 205, 120, 202, - /* 1400 */ 204, 203, 165, 201, 23, 23, 131, 111, 123, 20, - /* 1410 */ 225, 125, 16, 1, 131, 228, 111, 123, 56, 228, - /* 1420 */ 37, 37, 64, 1, 5, 122, 22, 107, 140, 80, - /* 1430 */ 80, 26, 87, 72, 107, 24, 20, 19, 112, 105, - /* 1440 */ 23, 68, 22, 79, 79, 22, 22, 22, 58, 22, - /* 1450 */ 245, 248, 248, 79, 23, 23, 23, 116, 22, 122, - /* 1460 */ 23, 22, 56, 23, 26, 23, 64, 22, 124, 26, - /* 1470 */ 26, 64, 64, 23, 23, 23, 11, 23, 22, 26, - /* 1480 */ 23, 22, 24, 1, 23, 22, 26, 250, 24, 23, - /* 1490 */ 22, 122, 23, 23, 22, 15, 23, 250, 122, 122, - /* 1500 */ 122, -}; -#define YY_SHIFT_USE_DFLT (-95) -#define YY_SHIFT_COUNT (439) -#define YY_SHIFT_MIN (-94) -#define YY_SHIFT_MAX (1482) + /* 1000 */ 48, 49, 50, 51, 52, 53, 194, 195, 152, 171, + /* 1010 */ 141, 152, 132, 133, 134, 196, 225, 179, 206, 65, + /* 1020 */ 152, 97, 98, 152, 88, 152, 90, 152, 172, 173, + /* 1030 */ 152, 219, 78, 152, 152, 238, 152, 152, 219, 152, + /* 1040 */ 86, 152, 152, 172, 173, 238, 152, 172, 173, 152, + /* 1050 */ 172, 173, 152, 172, 173, 213, 237, 172, 173, 172, + /* 1060 */ 173, 172, 173, 211, 212, 111, 172, 173, 152, 172, + /* 1070 */ 173, 152, 172, 173, 152, 193, 140, 193, 152, 59, + /* 1080 */ 152, 152, 152, 63, 152, 16, 152, 152, 172, 173, + /* 1090 */ 152, 172, 173, 152, 172, 173, 152, 77, 172, 173, + /* 1100 */ 172, 173, 172, 173, 172, 173, 172, 173, 152, 250, + /* 1110 */ 172, 173, 61, 172, 173, 152, 172, 173, 152, 92, + /* 1120 */ 152, 70, 152, 152, 152, 26, 152, 100, 172, 173, + /* 1130 */ 152, 24, 152, 22, 152, 172, 173, 152, 172, 173, + /* 1140 */ 172, 173, 172, 173, 172, 173, 172, 173, 152, 152, + /* 1150 */ 172, 173, 172, 173, 172, 173, 152, 88, 152, 90, + /* 1160 */ 152, 55, 55, 152, 193, 152, 55, 152, 172, 173, + /* 1170 */ 26, 152, 163, 163, 152, 19, 172, 173, 172, 173, + /* 1180 */ 172, 173, 22, 172, 173, 172, 173, 172, 173, 55, + /* 1190 */ 193, 172, 173, 152, 172, 173, 166, 167, 166, 167, + /* 1200 */ 163, 163, 163, 97, 97, 196, 196, 163, 97, 55, + /* 1210 */ 23, 199, 56, 26, 22, 22, 24, 100, 101, 55, + /* 1220 */ 23, 209, 123, 26, 23, 23, 23, 26, 26, 26, + /* 1230 */ 37, 97, 152, 196, 196, 196, 23, 7, 8, 26, + /* 1240 */ 196, 23, 23, 152, 26, 26, 23, 132, 133, 26, + /* 1250 */ 106, 97, 132, 133, 23, 152, 152, 26, 210, 191, + /* 1260 */ 152, 97, 152, 234, 152, 152, 152, 233, 152, 210, + /* 1270 */ 152, 152, 210, 152, 152, 152, 152, 152, 152, 197, + /* 1280 */ 210, 198, 122, 150, 239, 201, 214, 214, 201, 239, + /* 1290 */ 214, 227, 200, 184, 198, 155, 67, 243, 122, 22, + /* 1300 */ 159, 159, 69, 176, 175, 175, 175, 240, 180, 159, + /* 1310 */ 220, 240, 27, 130, 18, 18, 159, 158, 220, 137, + /* 1320 */ 159, 189, 236, 158, 74, 159, 159, 158, 192, 192, + /* 1330 */ 192, 192, 235, 22, 189, 189, 201, 159, 158, 177, + /* 1340 */ 159, 107, 158, 76, 201, 177, 174, 174, 201, 174, + /* 1350 */ 106, 177, 182, 174, 107, 159, 22, 125, 159, 182, + /* 1360 */ 174, 176, 174, 174, 216, 216, 215, 215, 177, 216, + /* 1370 */ 215, 53, 137, 128, 216, 177, 127, 129, 215, 126, + /* 1380 */ 25, 13, 162, 26, 6, 161, 165, 165, 178, 153, + /* 1390 */ 153, 151, 151, 151, 151, 224, 4, 3, 22, 142, + /* 1400 */ 15, 94, 16, 178, 165, 205, 23, 202, 204, 203, + /* 1410 */ 201, 23, 120, 131, 111, 20, 226, 123, 125, 16, + /* 1420 */ 1, 123, 131, 229, 229, 111, 37, 37, 56, 64, + /* 1430 */ 122, 1, 5, 22, 107, 140, 80, 87, 26, 80, + /* 1440 */ 107, 72, 24, 20, 19, 105, 22, 112, 22, 79, + /* 1450 */ 22, 58, 23, 22, 79, 22, 249, 249, 246, 79, + /* 1460 */ 23, 23, 23, 116, 68, 22, 26, 23, 22, 56, + /* 1470 */ 122, 23, 23, 64, 22, 124, 26, 26, 64, 64, + /* 1480 */ 23, 23, 23, 23, 11, 23, 22, 26, 23, 22, + /* 1490 */ 24, 1, 23, 22, 26, 122, 24, 23, 22, 122, + /* 1500 */ 23, 23, 22, 122, 122, 23, 15, +}; +#define YY_SHIFT_USE_DFLT (1507) +#define YY_SHIFT_COUNT (442) +#define YY_SHIFT_MIN (-94) +#define YY_SHIFT_MAX (1491) static const short yy_shift_ofst[] = { - /* 0 */ 40, 564, 869, 577, 725, 725, 725, 739, -19, 16, - /* 10 */ 16, 100, 725, 725, 725, 725, 725, 725, 725, 841, - /* 20 */ 841, 538, 507, 684, 623, 61, 137, 172, 207, 242, - /* 30 */ 277, 312, 347, 382, 424, 424, 424, 424, 424, 424, - /* 40 */ 424, 424, 424, 424, 424, 424, 424, 424, 424, 459, - /* 50 */ 424, 494, 529, 529, 670, 725, 725, 725, 725, 725, + /* 0 */ 40, 564, 869, 577, 725, 725, 725, 725, 690, -19, + /* 10 */ 16, 16, 100, 725, 725, 725, 725, 725, 725, 725, + /* 20 */ 841, 841, 538, 507, 684, 565, 61, 137, 172, 207, + /* 30 */ 242, 277, 312, 347, 382, 424, 424, 424, 424, 424, + /* 40 */ 424, 424, 424, 424, 424, 424, 424, 424, 424, 424, + /* 50 */ 459, 424, 494, 529, 529, 670, 725, 725, 725, 725, /* 60 */ 725, 725, 725, 725, 725, 725, 725, 725, 725, 725, /* 70 */ 725, 725, 725, 725, 725, 725, 725, 725, 725, 725, - /* 80 */ 725, 725, 725, 821, 725, 725, 725, 725, 725, 725, - /* 90 */ 725, 725, 725, 725, 725, 725, 725, 952, 711, 711, - /* 100 */ 711, 711, 711, 766, 23, 32, 811, 877, 663, 602, - /* 110 */ 602, 811, 73, 113, -51, -95, -95, -95, 501, 501, - /* 120 */ 501, 595, 595, 809, 205, 276, 811, 811, 811, 811, - /* 130 */ 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, - /* 140 */ 811, 811, 811, 811, 811, 811, 192, 628, 498, 498, - /* 150 */ 113, -34, -34, -34, -34, -34, -34, -95, -95, -95, - /* 160 */ 880, -94, -94, 726, 740, 99, 797, 887, 349, 811, - /* 170 */ 811, 811, 811, 811, 811, 811, 811, 811, 811, 811, - /* 180 */ 811, 811, 811, 811, 811, 811, 941, 941, 941, 811, - /* 190 */ 811, 926, 811, 811, 811, -18, 811, 811, 842, 811, - /* 200 */ 811, 811, 811, 811, 811, 811, 811, 811, 811, 224, - /* 210 */ 608, 910, 910, 910, 1078, 45, 469, 508, 934, 970, - /* 220 */ 970, 1164, 934, 1164, 1036, 1183, 359, 1017, 970, 954, - /* 230 */ 1017, 1017, 1092, 730, 497, 1225, 1171, 1171, 1228, 1228, - /* 240 */ 1171, 1281, 1280, 1178, 1291, 1291, 1291, 1291, 1171, 1293, - /* 250 */ 1178, 1281, 1280, 1280, 1178, 1171, 1293, 1176, 1244, 1171, - /* 260 */ 1171, 1293, 1302, 1171, 1293, 1171, 1293, 1302, 1229, 1229, - /* 270 */ 1229, 1263, 1302, 1229, 1238, 1229, 1263, 1229, 1229, 1222, - /* 280 */ 1245, 1222, 1245, 1222, 1245, 1222, 1245, 1171, 1171, 1218, - /* 290 */ 1302, 1304, 1304, 1302, 1230, 1242, 1243, 1246, 1178, 1347, - /* 300 */ 1348, 1363, 1363, 1375, 1375, 1375, 1375, -95, -95, -95, - /* 310 */ -95, -95, -95, -95, -95, 451, 876, 346, 1159, 1099, - /* 320 */ 441, 823, 1188, 1111, 1190, 1195, 1199, 1200, 1005, 1129, - /* 330 */ 1224, 533, 1201, 1212, 1155, 1214, 1109, 1112, 1220, 1157, - /* 340 */ 779, 1386, 1388, 1370, 1251, 1379, 1301, 1380, 1381, 1382, - /* 350 */ 1278, 1275, 1296, 1285, 1389, 1286, 1396, 1412, 1294, 1283, - /* 360 */ 1383, 1384, 1305, 1362, 1358, 1303, 1422, 1419, 1404, 1320, - /* 370 */ 1288, 1349, 1405, 1350, 1345, 1361, 1327, 1411, 1416, 1418, - /* 380 */ 1326, 1334, 1420, 1364, 1423, 1424, 1417, 1425, 1365, 1390, - /* 390 */ 1427, 1374, 1373, 1431, 1432, 1433, 1341, 1436, 1437, 1439, - /* 400 */ 1438, 1337, 1440, 1442, 1406, 1402, 1445, 1344, 1443, 1407, - /* 410 */ 1444, 1408, 1443, 1450, 1451, 1452, 1453, 1454, 1456, 1465, - /* 420 */ 1457, 1459, 1458, 1460, 1461, 1463, 1464, 1460, 1466, 1468, - /* 430 */ 1469, 1470, 1472, 1369, 1376, 1377, 1378, 1473, 1480, 1482, + /* 80 */ 725, 725, 725, 725, 821, 725, 725, 725, 725, 725, + /* 90 */ 725, 725, 725, 725, 725, 725, 725, 725, 952, 711, + /* 100 */ 711, 711, 711, 711, 766, 23, 32, 924, 637, 825, + /* 110 */ 837, 837, 924, 73, 183, -51, 1507, 1507, 1507, 501, + /* 120 */ 501, 501, 903, 903, 632, 205, 241, 924, 924, 924, + /* 130 */ 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, + /* 140 */ 924, 924, 924, 924, 924, 924, 924, 192, 1027, 1106, + /* 150 */ 1106, 183, 176, 176, 176, 176, 176, 176, 1507, 1507, + /* 160 */ 1507, 880, -94, -94, 578, 734, 99, 730, 769, 349, + /* 170 */ 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, + /* 180 */ 924, 924, 924, 924, 924, 924, 924, 954, 954, 954, + /* 190 */ 924, 924, 622, 924, 924, 924, -18, 924, 924, 914, + /* 200 */ 924, 924, 924, 924, 924, 924, 924, 924, 924, 924, + /* 210 */ 441, 1020, 1107, 1107, 1107, 569, 45, 217, 510, 423, + /* 220 */ 834, 834, 1156, 423, 1156, 1144, 1187, 359, 1051, 834, + /* 230 */ -17, 1051, 1051, 1099, 469, 1192, 1229, 1176, 1176, 1233, + /* 240 */ 1233, 1176, 1277, 1285, 1183, 1296, 1296, 1296, 1296, 1176, + /* 250 */ 1297, 1183, 1277, 1285, 1285, 1183, 1176, 1297, 1182, 1250, + /* 260 */ 1176, 1176, 1297, 1311, 1176, 1297, 1176, 1297, 1311, 1234, + /* 270 */ 1234, 1234, 1267, 1311, 1234, 1244, 1234, 1267, 1234, 1234, + /* 280 */ 1232, 1247, 1232, 1247, 1232, 1247, 1232, 1247, 1176, 1334, + /* 290 */ 1176, 1235, 1311, 1318, 1318, 1311, 1248, 1253, 1245, 1249, + /* 300 */ 1183, 1355, 1357, 1368, 1368, 1378, 1378, 1378, 1378, 1507, + /* 310 */ 1507, 1507, 1507, 1507, 1507, 1507, 1507, 451, 936, 816, + /* 320 */ 888, 1069, 799, 1111, 1197, 1193, 1201, 1202, 1203, 1213, + /* 330 */ 1134, 1117, 1230, 497, 1218, 1219, 1154, 1223, 1115, 1120, + /* 340 */ 1231, 1164, 1160, 1392, 1394, 1376, 1257, 1385, 1307, 1386, + /* 350 */ 1383, 1388, 1292, 1282, 1303, 1294, 1395, 1293, 1403, 1419, + /* 360 */ 1298, 1291, 1389, 1390, 1314, 1372, 1365, 1308, 1430, 1427, + /* 370 */ 1411, 1327, 1295, 1356, 1412, 1359, 1350, 1369, 1333, 1418, + /* 380 */ 1423, 1425, 1335, 1340, 1424, 1370, 1426, 1428, 1429, 1431, + /* 390 */ 1375, 1393, 1433, 1380, 1396, 1437, 1438, 1439, 1347, 1443, + /* 400 */ 1444, 1446, 1440, 1348, 1448, 1449, 1413, 1409, 1452, 1351, + /* 410 */ 1450, 1414, 1451, 1415, 1457, 1450, 1458, 1459, 1460, 1461, + /* 420 */ 1462, 1464, 1473, 1465, 1467, 1466, 1468, 1469, 1471, 1472, + /* 430 */ 1468, 1474, 1476, 1477, 1478, 1480, 1373, 1377, 1381, 1382, + /* 440 */ 1482, 1491, 1490, }; #define YY_REDUCE_USE_DFLT (-130) -#define YY_REDUCE_COUNT (314) +#define YY_REDUCE_COUNT (316) #define YY_REDUCE_MIN (-129) -#define YY_REDUCE_MAX (1237) +#define YY_REDUCE_MAX (1243) static const short yy_reduce_ofst[] = { - /* 0 */ -29, 531, 490, 625, -49, 272, 456, 510, 400, 509, - /* 10 */ 562, 114, 535, 614, 698, 384, 738, 751, 690, 419, - /* 20 */ 553, 761, 460, 636, 767, 41, 41, 41, 41, 41, - /* 30 */ 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, - /* 40 */ 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, - /* 50 */ 41, 41, 41, 41, 760, 815, 856, 863, 866, 868, - /* 60 */ 870, 873, 881, 885, 895, 897, 899, 903, 907, 909, - /* 70 */ 911, 913, 922, 925, 936, 938, 940, 944, 947, 949, - /* 80 */ 951, 953, 955, 962, 978, 980, 984, 986, 988, 991, - /* 90 */ 993, 995, 997, 1002, 1019, 1021, 1025, 41, 41, 41, - /* 100 */ 41, 41, 41, 41, 41, 41, 896, 140, 260, 98, - /* 110 */ 268, 1020, 41, 482, 41, 41, 41, 41, 270, 270, - /* 120 */ 270, 212, 217, -129, 411, 411, 550, 5, 626, 362, - /* 130 */ 733, 830, 992, 1003, 1026, 795, 683, 807, 638, 819, - /* 140 */ 753, 948, 62, 817, 824, 132, 687, 611, 864, 1033, - /* 150 */ 403, 943, 966, 983, 1032, 1038, 1040, 960, 996, 492, - /* 160 */ -50, 57, 131, 153, 221, 462, 588, 596, 675, 721, - /* 170 */ 820, 834, 857, 914, 979, 1034, 1065, 1081, 1087, 1095, - /* 180 */ 1096, 1097, 1098, 1101, 1104, 1105, 320, 500, 655, 1106, - /* 190 */ 1107, 503, 1108, 1110, 1113, 681, 1114, 1115, 999, 1116, - /* 200 */ 1117, 1118, 221, 1119, 1120, 1121, 1122, 1123, 1124, 788, - /* 210 */ 956, 1041, 1051, 1053, 503, 1067, 1079, 1128, 1080, 1066, - /* 220 */ 1068, 1045, 1083, 1047, 1103, 1102, 1125, 1126, 1073, 1062, - /* 230 */ 1127, 1131, 1089, 1093, 1135, 1052, 1136, 1137, 1059, 1060, - /* 240 */ 1141, 1084, 1130, 1132, 1133, 1134, 1138, 1139, 1151, 1154, - /* 250 */ 1140, 1094, 1143, 1145, 1142, 1156, 1158, 1082, 1086, 1162, - /* 260 */ 1163, 1165, 1150, 1169, 1177, 1170, 1179, 1161, 1166, 1168, - /* 270 */ 1172, 1167, 1173, 1174, 1175, 1180, 1181, 1182, 1184, 1144, - /* 280 */ 1146, 1148, 1147, 1149, 1152, 1153, 1160, 1186, 1194, 1185, - /* 290 */ 1189, 1187, 1191, 1193, 1192, 1196, 1198, 1197, 1202, 1215, - /* 300 */ 1217, 1226, 1227, 1231, 1232, 1233, 1234, 1203, 1204, 1205, - /* 310 */ 1221, 1223, 1209, 1211, 1237, + /* 0 */ -29, 531, 490, 570, -49, 272, 456, 498, 633, 400, + /* 10 */ 612, 626, 113, 482, 678, 719, 384, 726, 748, 791, + /* 20 */ 419, 693, 761, 812, 819, 625, 76, 76, 76, 76, + /* 30 */ 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + /* 40 */ 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + /* 50 */ 76, 76, 76, 76, 76, 793, 795, 856, 871, 875, + /* 60 */ 878, 881, 885, 887, 889, 894, 897, 900, 916, 919, + /* 70 */ 922, 926, 928, 930, 932, 934, 938, 941, 944, 956, + /* 80 */ 963, 966, 968, 970, 972, 974, 978, 980, 982, 996, + /* 90 */ 1004, 1006, 1008, 1011, 1013, 1015, 1019, 1022, 76, 76, + /* 100 */ 76, 76, 76, 76, 76, 76, 76, 555, 210, 260, + /* 110 */ 200, 346, 571, 76, 700, 76, 76, 76, 76, 838, + /* 120 */ 838, 838, 42, 182, 251, 160, 160, 550, 5, 455, + /* 130 */ 585, 721, 749, 882, 884, 971, 618, 462, 797, 514, + /* 140 */ 807, 524, 997, -129, 655, 859, 62, 290, 66, 1030, + /* 150 */ 1032, 589, 1009, 1010, 1037, 1038, 1039, 1044, 740, 852, + /* 160 */ 1012, 112, 147, 230, 257, 180, 369, 403, 500, 549, + /* 170 */ 556, 563, 694, 751, 765, 772, 778, 820, 868, 873, + /* 180 */ 890, 929, 935, 985, 1041, 1080, 1091, 540, 593, 661, + /* 190 */ 1103, 1104, 842, 1108, 1110, 1112, 1048, 1113, 1114, 1068, + /* 200 */ 1116, 1118, 1119, 180, 1121, 1122, 1123, 1124, 1125, 1126, + /* 210 */ 1029, 1034, 1059, 1062, 1070, 842, 1082, 1083, 1133, 1084, + /* 220 */ 1072, 1073, 1045, 1087, 1050, 1127, 1109, 1128, 1129, 1076, + /* 230 */ 1064, 1130, 1131, 1092, 1096, 1140, 1054, 1141, 1142, 1067, + /* 240 */ 1071, 1150, 1090, 1132, 1135, 1136, 1137, 1138, 1139, 1157, + /* 250 */ 1159, 1143, 1098, 1145, 1146, 1147, 1161, 1165, 1086, 1097, + /* 260 */ 1166, 1167, 1169, 1162, 1178, 1180, 1181, 1184, 1168, 1172, + /* 270 */ 1173, 1175, 1170, 1174, 1179, 1185, 1186, 1177, 1188, 1189, + /* 280 */ 1148, 1151, 1149, 1152, 1153, 1155, 1158, 1163, 1196, 1171, + /* 290 */ 1199, 1190, 1191, 1194, 1195, 1198, 1200, 1204, 1206, 1205, + /* 300 */ 1209, 1220, 1224, 1236, 1237, 1240, 1241, 1242, 1243, 1207, + /* 310 */ 1208, 1212, 1221, 1222, 1210, 1225, 1239, }; static const YYACTIONTYPE yy_default[] = { - /* 0 */ 1250, 1240, 1240, 1240, 1174, 1174, 1174, 1240, 1071, 1100, - /* 10 */ 1100, 1224, 1301, 1301, 1301, 1301, 1301, 1301, 1173, 1301, - /* 20 */ 1301, 1301, 1301, 1240, 1075, 1106, 1301, 1301, 1301, 1301, - /* 30 */ 1301, 1301, 1301, 1301, 1223, 1225, 1114, 1113, 1206, 1087, - /* 40 */ 1111, 1104, 1108, 1175, 1169, 1170, 1168, 1172, 1176, 1301, - /* 50 */ 1107, 1138, 1153, 1137, 1301, 1301, 1301, 1301, 1301, 1301, - /* 60 */ 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, - /* 70 */ 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, - /* 80 */ 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, - /* 90 */ 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1147, 1152, 1159, - /* 100 */ 1151, 1148, 1140, 1139, 1141, 1142, 1301, 994, 1042, 1301, - /* 110 */ 1301, 1301, 1143, 1301, 1144, 1156, 1155, 1154, 1231, 1258, - /* 120 */ 1257, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, - /* 130 */ 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, - /* 140 */ 1301, 1301, 1301, 1301, 1301, 1301, 1250, 1240, 1000, 1000, - /* 150 */ 1301, 1240, 1240, 1240, 1240, 1240, 1240, 1236, 1075, 1066, - /* 160 */ 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, - /* 170 */ 1228, 1226, 1301, 1187, 1301, 1301, 1301, 1301, 1301, 1301, - /* 180 */ 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, - /* 190 */ 1301, 1301, 1301, 1301, 1301, 1071, 1301, 1301, 1301, 1301, - /* 200 */ 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1252, 1301, - /* 210 */ 1201, 1071, 1071, 1071, 1073, 1055, 1065, 979, 1110, 1089, - /* 220 */ 1089, 1290, 1110, 1290, 1017, 1272, 1014, 1100, 1089, 1171, - /* 230 */ 1100, 1100, 1072, 1065, 1301, 1293, 1080, 1080, 1292, 1292, - /* 240 */ 1080, 1119, 1045, 1110, 1051, 1051, 1051, 1051, 1080, 991, - /* 250 */ 1110, 1119, 1045, 1045, 1110, 1080, 991, 1205, 1287, 1080, - /* 260 */ 1080, 991, 1180, 1080, 991, 1080, 991, 1180, 1043, 1043, - /* 270 */ 1043, 1032, 1180, 1043, 1017, 1043, 1032, 1043, 1043, 1093, - /* 280 */ 1088, 1093, 1088, 1093, 1088, 1093, 1088, 1080, 1080, 1301, - /* 290 */ 1180, 1184, 1184, 1180, 1105, 1094, 1103, 1101, 1110, 997, - /* 300 */ 1035, 1255, 1255, 1251, 1251, 1251, 1251, 1298, 1298, 1236, - /* 310 */ 1267, 1267, 1019, 1019, 1267, 1301, 1301, 1301, 1301, 1301, - /* 320 */ 1301, 1262, 1301, 1189, 1301, 1301, 1301, 1301, 1301, 1301, - /* 330 */ 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, - /* 340 */ 1125, 1301, 975, 1233, 1301, 1301, 1232, 1301, 1301, 1301, - /* 350 */ 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, - /* 360 */ 1301, 1301, 1301, 1301, 1301, 1289, 1301, 1301, 1301, 1301, - /* 370 */ 1301, 1301, 1204, 1203, 1301, 1301, 1301, 1301, 1301, 1301, - /* 380 */ 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, - /* 390 */ 1301, 1301, 1301, 1301, 1301, 1301, 1057, 1301, 1301, 1301, - /* 400 */ 1276, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1102, 1301, - /* 410 */ 1095, 1301, 1280, 1301, 1301, 1301, 1301, 1301, 1301, 1301, - /* 420 */ 1301, 1301, 1301, 1242, 1301, 1301, 1301, 1241, 1301, 1301, - /* 430 */ 1301, 1301, 1301, 1127, 1301, 1126, 1130, 1301, 985, 1301, + /* 0 */ 1258, 1248, 1248, 1248, 1180, 1180, 1180, 1180, 1248, 1077, + /* 10 */ 1106, 1106, 1232, 1309, 1309, 1309, 1309, 1309, 1309, 1179, + /* 20 */ 1309, 1309, 1309, 1309, 1248, 1081, 1112, 1309, 1309, 1309, + /* 30 */ 1309, 1309, 1309, 1309, 1309, 1231, 1233, 1120, 1119, 1214, + /* 40 */ 1093, 1117, 1110, 1114, 1181, 1175, 1176, 1174, 1178, 1182, + /* 50 */ 1309, 1113, 1144, 1159, 1143, 1309, 1309, 1309, 1309, 1309, + /* 60 */ 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, + /* 70 */ 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, + /* 80 */ 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, + /* 90 */ 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1153, 1158, + /* 100 */ 1165, 1157, 1154, 1146, 1145, 1147, 1148, 1309, 1000, 1048, + /* 110 */ 1309, 1309, 1309, 1149, 1309, 1150, 1162, 1161, 1160, 1239, + /* 120 */ 1266, 1265, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, + /* 130 */ 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, + /* 140 */ 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1258, 1248, 1006, + /* 150 */ 1006, 1309, 1248, 1248, 1248, 1248, 1248, 1248, 1244, 1081, + /* 160 */ 1072, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, + /* 170 */ 1309, 1236, 1234, 1309, 1195, 1309, 1309, 1309, 1309, 1309, + /* 180 */ 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, + /* 190 */ 1309, 1309, 1309, 1309, 1309, 1309, 1077, 1309, 1309, 1309, + /* 200 */ 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1260, + /* 210 */ 1309, 1209, 1077, 1077, 1077, 1079, 1061, 1071, 985, 1116, + /* 220 */ 1095, 1095, 1298, 1116, 1298, 1023, 1280, 1020, 1106, 1095, + /* 230 */ 1177, 1106, 1106, 1078, 1071, 1309, 1301, 1086, 1086, 1300, + /* 240 */ 1300, 1086, 1125, 1051, 1116, 1057, 1057, 1057, 1057, 1086, + /* 250 */ 997, 1116, 1125, 1051, 1051, 1116, 1086, 997, 1213, 1295, + /* 260 */ 1086, 1086, 997, 1188, 1086, 997, 1086, 997, 1188, 1049, + /* 270 */ 1049, 1049, 1038, 1188, 1049, 1023, 1049, 1038, 1049, 1049, + /* 280 */ 1099, 1094, 1099, 1094, 1099, 1094, 1099, 1094, 1086, 1183, + /* 290 */ 1086, 1309, 1188, 1192, 1192, 1188, 1111, 1100, 1109, 1107, + /* 300 */ 1116, 1003, 1041, 1263, 1263, 1259, 1259, 1259, 1259, 1306, + /* 310 */ 1306, 1244, 1275, 1275, 1025, 1025, 1275, 1309, 1309, 1309, + /* 320 */ 1309, 1309, 1309, 1270, 1309, 1197, 1309, 1309, 1309, 1309, + /* 330 */ 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, + /* 340 */ 1309, 1309, 1131, 1309, 981, 1241, 1309, 1309, 1240, 1309, + /* 350 */ 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, + /* 360 */ 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1297, 1309, 1309, + /* 370 */ 1309, 1309, 1309, 1309, 1212, 1211, 1309, 1309, 1309, 1309, + /* 380 */ 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, + /* 390 */ 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1309, 1063, 1309, + /* 400 */ 1309, 1309, 1284, 1309, 1309, 1309, 1309, 1309, 1309, 1309, + /* 410 */ 1108, 1309, 1101, 1309, 1309, 1288, 1309, 1309, 1309, 1309, + /* 420 */ 1309, 1309, 1309, 1309, 1309, 1309, 1250, 1309, 1309, 1309, + /* 430 */ 1249, 1309, 1309, 1309, 1309, 1309, 1133, 1309, 1132, 1136, + /* 440 */ 1309, 991, 1309, }; /********** End of lemon-generated parsing tables *****************************/ /* The next table maps tokens (terminal symbols) into fallback tokens. ** If a construct like the following: @@ -131672,21 +132512,22 @@ typedef struct yyStackEntry yyStackEntry; /* The state of the parser is completely contained in an instance of ** the following structure */ struct yyParser { - int yyidx; /* Index of top element in stack */ + yyStackEntry *yytos; /* Pointer to top element of the stack */ #ifdef YYTRACKMAXSTACKDEPTH - int yyidxMax; /* Maximum value of yyidx */ + int yyhwm; /* High-water mark of the stack */ #endif #ifndef YYNOERRORRECOVERY int yyerrcnt; /* Shifts left before out of the error */ #endif sqlite3ParserARG_SDECL /* A place to hold %extra_argument */ #if YYSTACKDEPTH<=0 int yystksz; /* Current side of the stack */ yyStackEntry *yystack; /* The parser's stack */ + yyStackEntry yystk0; /* First stack entry */ #else yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ #endif }; typedef struct yyParser yyParser; @@ -131781,17 +132622,17 @@ "orderby_opt", "limit_opt", "values", "nexprlist", "exprlist", "sclp", "as", "seltablist", "stl_prefix", "joinop", "indexed_opt", "on_opt", "using_opt", "idlist", "setlist", "insert_cmd", "idlist_opt", "likeop", "between_op", "in_op", - "case_operand", "case_exprlist", "case_else", "uniqueflag", - "collate", "nmnum", "trigger_decl", "trigger_cmd_list", - "trigger_time", "trigger_event", "foreach_clause", "when_clause", - "trigger_cmd", "trnm", "tridxby", "database_kw_opt", - "key_opt", "add_column_fullname", "kwcolumn_opt", "create_vtab", - "vtabarglist", "vtabarg", "vtabargtoken", "lp", - "anylist", "wqlist", + "paren_exprlist", "case_operand", "case_exprlist", "case_else", + "uniqueflag", "collate", "nmnum", "trigger_decl", + "trigger_cmd_list", "trigger_time", "trigger_event", "foreach_clause", + "when_clause", "trigger_cmd", "trnm", "tridxby", + "database_kw_opt", "key_opt", "add_column_fullname", "kwcolumn_opt", + "create_vtab", "vtabarglist", "vtabarg", "vtabargtoken", + "lp", "anylist", "wqlist", }; #endif /* NDEBUG */ #ifndef NDEBUG /* For tracing reduce actions, the names of all rules are required. @@ -131985,11 +132826,11 @@ /* 185 */ "in_op ::= IN", /* 186 */ "in_op ::= NOT IN", /* 187 */ "expr ::= expr in_op LP exprlist RP", /* 188 */ "expr ::= LP select RP", /* 189 */ "expr ::= expr in_op LP select RP", - /* 190 */ "expr ::= expr in_op nm dbnm", + /* 190 */ "expr ::= expr in_op nm dbnm paren_exprlist", /* 191 */ "expr ::= EXISTS LP select RP", /* 192 */ "expr ::= CASE case_operand case_exprlist case_else END", /* 193 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", /* 194 */ "case_exprlist ::= WHEN expr THEN expr", /* 195 */ "case_else ::= ELSE expr", @@ -131997,158 +132838,170 @@ /* 197 */ "case_operand ::= expr", /* 198 */ "case_operand ::=", /* 199 */ "exprlist ::=", /* 200 */ "nexprlist ::= nexprlist COMMA expr", /* 201 */ "nexprlist ::= expr", - /* 202 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt", - /* 203 */ "uniqueflag ::= UNIQUE", - /* 204 */ "uniqueflag ::=", - /* 205 */ "eidlist_opt ::=", - /* 206 */ "eidlist_opt ::= LP eidlist RP", - /* 207 */ "eidlist ::= eidlist COMMA nm collate sortorder", - /* 208 */ "eidlist ::= nm collate sortorder", - /* 209 */ "collate ::=", - /* 210 */ "collate ::= COLLATE ID|STRING", - /* 211 */ "cmd ::= DROP INDEX ifexists fullname", - /* 212 */ "cmd ::= VACUUM", - /* 213 */ "cmd ::= VACUUM nm", - /* 214 */ "cmd ::= PRAGMA nm dbnm", - /* 215 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", - /* 216 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", - /* 217 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", - /* 218 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", - /* 219 */ "plus_num ::= PLUS INTEGER|FLOAT", - /* 220 */ "minus_num ::= MINUS INTEGER|FLOAT", - /* 221 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END", - /* 222 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", - /* 223 */ "trigger_time ::= BEFORE", - /* 224 */ "trigger_time ::= AFTER", - /* 225 */ "trigger_time ::= INSTEAD OF", - /* 226 */ "trigger_time ::=", - /* 227 */ "trigger_event ::= DELETE|INSERT", - /* 228 */ "trigger_event ::= UPDATE", - /* 229 */ "trigger_event ::= UPDATE OF idlist", - /* 230 */ "when_clause ::=", - /* 231 */ "when_clause ::= WHEN expr", - /* 232 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", - /* 233 */ "trigger_cmd_list ::= trigger_cmd SEMI", - /* 234 */ "trnm ::= nm DOT nm", - /* 235 */ "tridxby ::= INDEXED BY nm", - /* 236 */ "tridxby ::= NOT INDEXED", - /* 237 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt", - /* 238 */ "trigger_cmd ::= insert_cmd INTO trnm idlist_opt select", - /* 239 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt", - /* 240 */ "trigger_cmd ::= select", - /* 241 */ "expr ::= RAISE LP IGNORE RP", - /* 242 */ "expr ::= RAISE LP raisetype COMMA nm RP", - /* 243 */ "raisetype ::= ROLLBACK", - /* 244 */ "raisetype ::= ABORT", - /* 245 */ "raisetype ::= FAIL", - /* 246 */ "cmd ::= DROP TRIGGER ifexists fullname", - /* 247 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", - /* 248 */ "cmd ::= DETACH database_kw_opt expr", - /* 249 */ "key_opt ::=", - /* 250 */ "key_opt ::= KEY expr", - /* 251 */ "cmd ::= REINDEX", - /* 252 */ "cmd ::= REINDEX nm dbnm", - /* 253 */ "cmd ::= ANALYZE", - /* 254 */ "cmd ::= ANALYZE nm dbnm", - /* 255 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", - /* 256 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist", - /* 257 */ "add_column_fullname ::= fullname", - /* 258 */ "cmd ::= create_vtab", - /* 259 */ "cmd ::= create_vtab LP vtabarglist RP", - /* 260 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", - /* 261 */ "vtabarg ::=", - /* 262 */ "vtabargtoken ::= ANY", - /* 263 */ "vtabargtoken ::= lp anylist RP", - /* 264 */ "lp ::= LP", - /* 265 */ "with ::=", - /* 266 */ "with ::= WITH wqlist", - /* 267 */ "with ::= WITH RECURSIVE wqlist", - /* 268 */ "wqlist ::= nm eidlist_opt AS LP select RP", - /* 269 */ "wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP", - /* 270 */ "input ::= cmdlist", - /* 271 */ "cmdlist ::= cmdlist ecmd", - /* 272 */ "cmdlist ::= ecmd", - /* 273 */ "ecmd ::= SEMI", - /* 274 */ "ecmd ::= explain cmdx SEMI", - /* 275 */ "explain ::=", - /* 276 */ "trans_opt ::=", - /* 277 */ "trans_opt ::= TRANSACTION", - /* 278 */ "trans_opt ::= TRANSACTION nm", - /* 279 */ "savepoint_opt ::= SAVEPOINT", - /* 280 */ "savepoint_opt ::=", - /* 281 */ "cmd ::= create_table create_table_args", - /* 282 */ "columnlist ::= columnlist COMMA columnname carglist", - /* 283 */ "columnlist ::= columnname carglist", - /* 284 */ "nm ::= ID|INDEXED", - /* 285 */ "nm ::= STRING", - /* 286 */ "nm ::= JOIN_KW", - /* 287 */ "typetoken ::= typename", - /* 288 */ "typename ::= ID|STRING", - /* 289 */ "signed ::= plus_num", - /* 290 */ "signed ::= minus_num", - /* 291 */ "carglist ::= carglist ccons", - /* 292 */ "carglist ::=", - /* 293 */ "ccons ::= NULL onconf", - /* 294 */ "conslist_opt ::= COMMA conslist", - /* 295 */ "conslist ::= conslist tconscomma tcons", - /* 296 */ "conslist ::= tcons", - /* 297 */ "tconscomma ::=", - /* 298 */ "defer_subclause_opt ::= defer_subclause", - /* 299 */ "resolvetype ::= raisetype", - /* 300 */ "selectnowith ::= oneselect", - /* 301 */ "oneselect ::= values", - /* 302 */ "sclp ::= selcollist COMMA", - /* 303 */ "as ::= ID|STRING", - /* 304 */ "expr ::= term", - /* 305 */ "exprlist ::= nexprlist", - /* 306 */ "nmnum ::= plus_num", - /* 307 */ "nmnum ::= nm", - /* 308 */ "nmnum ::= ON", - /* 309 */ "nmnum ::= DELETE", - /* 310 */ "nmnum ::= DEFAULT", - /* 311 */ "plus_num ::= INTEGER|FLOAT", - /* 312 */ "foreach_clause ::=", - /* 313 */ "foreach_clause ::= FOR EACH ROW", - /* 314 */ "trnm ::= nm", - /* 315 */ "tridxby ::=", - /* 316 */ "database_kw_opt ::= DATABASE", - /* 317 */ "database_kw_opt ::=", - /* 318 */ "kwcolumn_opt ::=", - /* 319 */ "kwcolumn_opt ::= COLUMNKW", - /* 320 */ "vtabarglist ::= vtabarg", - /* 321 */ "vtabarglist ::= vtabarglist COMMA vtabarg", - /* 322 */ "vtabarg ::= vtabarg vtabargtoken", - /* 323 */ "anylist ::=", - /* 324 */ "anylist ::= anylist LP anylist RP", - /* 325 */ "anylist ::= anylist ANY", + /* 202 */ "paren_exprlist ::=", + /* 203 */ "paren_exprlist ::= LP exprlist RP", + /* 204 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt", + /* 205 */ "uniqueflag ::= UNIQUE", + /* 206 */ "uniqueflag ::=", + /* 207 */ "eidlist_opt ::=", + /* 208 */ "eidlist_opt ::= LP eidlist RP", + /* 209 */ "eidlist ::= eidlist COMMA nm collate sortorder", + /* 210 */ "eidlist ::= nm collate sortorder", + /* 211 */ "collate ::=", + /* 212 */ "collate ::= COLLATE ID|STRING", + /* 213 */ "cmd ::= DROP INDEX ifexists fullname", + /* 214 */ "cmd ::= VACUUM", + /* 215 */ "cmd ::= VACUUM nm", + /* 216 */ "cmd ::= PRAGMA nm dbnm", + /* 217 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", + /* 218 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", + /* 219 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", + /* 220 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", + /* 221 */ "plus_num ::= PLUS INTEGER|FLOAT", + /* 222 */ "minus_num ::= MINUS INTEGER|FLOAT", + /* 223 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END", + /* 224 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", + /* 225 */ "trigger_time ::= BEFORE", + /* 226 */ "trigger_time ::= AFTER", + /* 227 */ "trigger_time ::= INSTEAD OF", + /* 228 */ "trigger_time ::=", + /* 229 */ "trigger_event ::= DELETE|INSERT", + /* 230 */ "trigger_event ::= UPDATE", + /* 231 */ "trigger_event ::= UPDATE OF idlist", + /* 232 */ "when_clause ::=", + /* 233 */ "when_clause ::= WHEN expr", + /* 234 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", + /* 235 */ "trigger_cmd_list ::= trigger_cmd SEMI", + /* 236 */ "trnm ::= nm DOT nm", + /* 237 */ "tridxby ::= INDEXED BY nm", + /* 238 */ "tridxby ::= NOT INDEXED", + /* 239 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt", + /* 240 */ "trigger_cmd ::= insert_cmd INTO trnm idlist_opt select", + /* 241 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt", + /* 242 */ "trigger_cmd ::= select", + /* 243 */ "expr ::= RAISE LP IGNORE RP", + /* 244 */ "expr ::= RAISE LP raisetype COMMA nm RP", + /* 245 */ "raisetype ::= ROLLBACK", + /* 246 */ "raisetype ::= ABORT", + /* 247 */ "raisetype ::= FAIL", + /* 248 */ "cmd ::= DROP TRIGGER ifexists fullname", + /* 249 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", + /* 250 */ "cmd ::= DETACH database_kw_opt expr", + /* 251 */ "key_opt ::=", + /* 252 */ "key_opt ::= KEY expr", + /* 253 */ "cmd ::= REINDEX", + /* 254 */ "cmd ::= REINDEX nm dbnm", + /* 255 */ "cmd ::= ANALYZE", + /* 256 */ "cmd ::= ANALYZE nm dbnm", + /* 257 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", + /* 258 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist", + /* 259 */ "add_column_fullname ::= fullname", + /* 260 */ "cmd ::= create_vtab", + /* 261 */ "cmd ::= create_vtab LP vtabarglist RP", + /* 262 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", + /* 263 */ "vtabarg ::=", + /* 264 */ "vtabargtoken ::= ANY", + /* 265 */ "vtabargtoken ::= lp anylist RP", + /* 266 */ "lp ::= LP", + /* 267 */ "with ::=", + /* 268 */ "with ::= WITH wqlist", + /* 269 */ "with ::= WITH RECURSIVE wqlist", + /* 270 */ "wqlist ::= nm eidlist_opt AS LP select RP", + /* 271 */ "wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP", + /* 272 */ "input ::= cmdlist", + /* 273 */ "cmdlist ::= cmdlist ecmd", + /* 274 */ "cmdlist ::= ecmd", + /* 275 */ "ecmd ::= SEMI", + /* 276 */ "ecmd ::= explain cmdx SEMI", + /* 277 */ "explain ::=", + /* 278 */ "trans_opt ::=", + /* 279 */ "trans_opt ::= TRANSACTION", + /* 280 */ "trans_opt ::= TRANSACTION nm", + /* 281 */ "savepoint_opt ::= SAVEPOINT", + /* 282 */ "savepoint_opt ::=", + /* 283 */ "cmd ::= create_table create_table_args", + /* 284 */ "columnlist ::= columnlist COMMA columnname carglist", + /* 285 */ "columnlist ::= columnname carglist", + /* 286 */ "nm ::= ID|INDEXED", + /* 287 */ "nm ::= STRING", + /* 288 */ "nm ::= JOIN_KW", + /* 289 */ "typetoken ::= typename", + /* 290 */ "typename ::= ID|STRING", + /* 291 */ "signed ::= plus_num", + /* 292 */ "signed ::= minus_num", + /* 293 */ "carglist ::= carglist ccons", + /* 294 */ "carglist ::=", + /* 295 */ "ccons ::= NULL onconf", + /* 296 */ "conslist_opt ::= COMMA conslist", + /* 297 */ "conslist ::= conslist tconscomma tcons", + /* 298 */ "conslist ::= tcons", + /* 299 */ "tconscomma ::=", + /* 300 */ "defer_subclause_opt ::= defer_subclause", + /* 301 */ "resolvetype ::= raisetype", + /* 302 */ "selectnowith ::= oneselect", + /* 303 */ "oneselect ::= values", + /* 304 */ "sclp ::= selcollist COMMA", + /* 305 */ "as ::= ID|STRING", + /* 306 */ "expr ::= term", + /* 307 */ "exprlist ::= nexprlist", + /* 308 */ "nmnum ::= plus_num", + /* 309 */ "nmnum ::= nm", + /* 310 */ "nmnum ::= ON", + /* 311 */ "nmnum ::= DELETE", + /* 312 */ "nmnum ::= DEFAULT", + /* 313 */ "plus_num ::= INTEGER|FLOAT", + /* 314 */ "foreach_clause ::=", + /* 315 */ "foreach_clause ::= FOR EACH ROW", + /* 316 */ "trnm ::= nm", + /* 317 */ "tridxby ::=", + /* 318 */ "database_kw_opt ::= DATABASE", + /* 319 */ "database_kw_opt ::=", + /* 320 */ "kwcolumn_opt ::=", + /* 321 */ "kwcolumn_opt ::= COLUMNKW", + /* 322 */ "vtabarglist ::= vtabarg", + /* 323 */ "vtabarglist ::= vtabarglist COMMA vtabarg", + /* 324 */ "vtabarg ::= vtabarg vtabargtoken", + /* 325 */ "anylist ::=", + /* 326 */ "anylist ::= anylist LP anylist RP", + /* 327 */ "anylist ::= anylist ANY", }; #endif /* NDEBUG */ #if YYSTACKDEPTH<=0 /* -** Try to increase the size of the parser stack. +** Try to increase the size of the parser stack. Return the number +** of errors. Return 0 on success. */ -static void yyGrowStack(yyParser *p){ +static int yyGrowStack(yyParser *p){ int newSize; + int idx; yyStackEntry *pNew; newSize = p->yystksz*2 + 100; - pNew = realloc(p->yystack, newSize*sizeof(pNew[0])); + idx = p->yytos ? (int)(p->yytos - p->yystack) : 0; + if( p->yystack==&p->yystk0 ){ + pNew = malloc(newSize*sizeof(pNew[0])); + if( pNew ) pNew[0] = p->yystk0; + }else{ + pNew = realloc(p->yystack, newSize*sizeof(pNew[0])); + } if( pNew ){ p->yystack = pNew; - p->yystksz = newSize; + p->yytos = &p->yystack[idx]; #ifndef NDEBUG if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sStack grows to %d entries!\n", - yyTracePrompt, p->yystksz); + fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n", + yyTracePrompt, p->yystksz, newSize); } #endif + p->yystksz = newSize; } + return pNew==0; } #endif /* Datatype of the argument to the memory allocated passed as the ** second argument to sqlite3ParserAlloc() below. This can be changed by @@ -132173,19 +133026,28 @@ */ SQLITE_PRIVATE void *sqlite3ParserAlloc(void *(*mallocProc)(YYMALLOCARGTYPE)){ yyParser *pParser; pParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) ); if( pParser ){ - pParser->yyidx = -1; #ifdef YYTRACKMAXSTACKDEPTH - pParser->yyidxMax = 0; + pParser->yyhwm = 0; #endif #if YYSTACKDEPTH<=0 + pParser->yytos = NULL; pParser->yystack = NULL; pParser->yystksz = 0; - yyGrowStack(pParser); + if( yyGrowStack(pParser) ){ + pParser->yystack = &pParser->yystk0; + pParser->yystksz = 1; + } #endif +#ifndef YYNOERRORRECOVERY + pParser->yyerrcnt = -1; +#endif + pParser->yytos = pParser->yystack; + pParser->yystack[0].stateno = 0; + pParser->yystack[0].major = 0; } return pParser; } /* The following function deletes the "minor type" or semantic value @@ -132216,17 +133078,17 @@ case 163: /* select */ case 194: /* selectnowith */ case 195: /* oneselect */ case 206: /* values */ { -sqlite3SelectDelete(pParse->db, (yypminor->yy159)); +sqlite3SelectDelete(pParse->db, (yypminor->yy243)); } break; case 172: /* term */ case 173: /* expr */ { -sqlite3ExprDelete(pParse->db, (yypminor->yy342).pExpr); +sqlite3ExprDelete(pParse->db, (yypminor->yy190).pExpr); } break; case 177: /* eidlist_opt */ case 186: /* sortlist */ case 187: /* eidlist */ @@ -132235,56 +133097,57 @@ case 204: /* orderby_opt */ case 207: /* nexprlist */ case 208: /* exprlist */ case 209: /* sclp */ case 218: /* setlist */ - case 225: /* case_exprlist */ + case 224: /* paren_exprlist */ + case 226: /* case_exprlist */ { -sqlite3ExprListDelete(pParse->db, (yypminor->yy442)); +sqlite3ExprListDelete(pParse->db, (yypminor->yy148)); } break; case 193: /* fullname */ case 200: /* from */ case 211: /* seltablist */ case 212: /* stl_prefix */ { -sqlite3SrcListDelete(pParse->db, (yypminor->yy347)); +sqlite3SrcListDelete(pParse->db, (yypminor->yy185)); } break; case 196: /* with */ - case 249: /* wqlist */ + case 250: /* wqlist */ { -sqlite3WithDelete(pParse->db, (yypminor->yy331)); +sqlite3WithDelete(pParse->db, (yypminor->yy285)); } break; case 201: /* where_opt */ case 203: /* having_opt */ case 215: /* on_opt */ - case 224: /* case_operand */ - case 226: /* case_else */ - case 235: /* when_clause */ - case 240: /* key_opt */ + case 225: /* case_operand */ + case 227: /* case_else */ + case 236: /* when_clause */ + case 241: /* key_opt */ { -sqlite3ExprDelete(pParse->db, (yypminor->yy122)); +sqlite3ExprDelete(pParse->db, (yypminor->yy72)); } break; case 216: /* using_opt */ case 217: /* idlist */ case 220: /* idlist_opt */ { -sqlite3IdListDelete(pParse->db, (yypminor->yy180)); +sqlite3IdListDelete(pParse->db, (yypminor->yy254)); } break; - case 231: /* trigger_cmd_list */ - case 236: /* trigger_cmd */ + case 232: /* trigger_cmd_list */ + case 237: /* trigger_cmd */ { -sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy327)); +sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy145)); } break; - case 233: /* trigger_event */ + case 234: /* trigger_event */ { -sqlite3IdListDelete(pParse->db, (yypminor->yy410).b); +sqlite3IdListDelete(pParse->db, (yypminor->yy332).b); } break; /********* End destructor definitions *****************************************/ default: break; /* If no destructor action specified: do nothing */ } @@ -132296,12 +133159,13 @@ ** If there is a destructor routine associated with the token which ** is popped from the stack, then call it. */ static void yy_pop_parser_stack(yyParser *pParser){ yyStackEntry *yytos; - assert( pParser->yyidx>=0 ); - yytos = &pParser->yystack[pParser->yyidx--]; + assert( pParser->yytos!=0 ); + assert( pParser->yytos > pParser->yystack ); + yytos = pParser->yytos--; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sPopping %s\n", yyTracePrompt, yyTokenName[yytos->major]); @@ -132324,13 +133188,13 @@ ){ yyParser *pParser = (yyParser*)p; #ifndef YYPARSEFREENEVERNULL if( pParser==0 ) return; #endif - while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser); + while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser); #if YYSTACKDEPTH<=0 - free(pParser->yystack); + if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack); #endif (*freeProc)((void*)pParser); } /* @@ -132337,11 +133201,11 @@ ** Return the peak depth of the stack for a parser. */ #ifdef YYTRACKMAXSTACKDEPTH SQLITE_PRIVATE int sqlite3ParserStackPeak(void *p){ yyParser *pParser = (yyParser*)p; - return pParser->yyidxMax; + return pParser->yyhwm; } #endif /* ** Find the appropriate action for a parser given the terminal @@ -132350,60 +133214,57 @@ static unsigned int yy_find_shift_action( yyParser *pParser, /* The parser */ YYCODETYPE iLookAhead /* The look-ahead token */ ){ int i; - int stateno = pParser->yystack[pParser->yyidx].stateno; + int stateno = pParser->yytos->stateno; if( stateno>=YY_MIN_REDUCE ) return stateno; assert( stateno <= YY_SHIFT_COUNT ); do{ i = yy_shift_ofst[stateno]; - if( i==YY_SHIFT_USE_DFLT ) return yy_default[stateno]; assert( iLookAhead!=YYNOCODE ); i += iLookAhead; if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ - if( iLookAhead>0 ){ #ifdef YYFALLBACK - YYCODETYPE iFallback; /* Fallback token */ - if( iLookAhead %s\n", - yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); - } + if( yyTraceFILE ){ + fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n", + yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); + } #endif - assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */ - iLookAhead = iFallback; - continue; - } + assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */ + iLookAhead = iFallback; + continue; + } #endif #ifdef YYWILDCARD - { - int j = i - iLookAhead + YYWILDCARD; - if( + { + int j = i - iLookAhead + YYWILDCARD; + if( #if YY_SHIFT_MIN+YYWILDCARD<0 - j>=0 && + j>=0 && #endif #if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT - j0 + ){ #ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n", - yyTracePrompt, yyTokenName[iLookAhead], - yyTokenName[YYWILDCARD]); - } + if( yyTraceFILE ){ + fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n", + yyTracePrompt, yyTokenName[iLookAhead], + yyTokenName[YYWILDCARD]); + } #endif /* NDEBUG */ - return yy_action[j]; - } + return yy_action[j]; } + } #endif /* YYWILDCARD */ - } return yy_default[stateno]; }else{ return yy_action[i]; } }while(1); @@ -132443,17 +133304,17 @@ /* ** The following routine is called if the stack overflows. */ static void yyStackOverflow(yyParser *yypParser){ sqlite3ParserARG_FETCH; - yypParser->yyidx--; + yypParser->yytos--; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt); } #endif - while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); + while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser); /* Here code is inserted which will execute if the parser ** stack every overflows */ /******** Begin %stack_overflow code ******************************************/ sqlite3ErrorMsg(pParse, "parser stack overflow"); @@ -132467,15 +133328,15 @@ #ifndef NDEBUG static void yyTraceShift(yyParser *yypParser, int yyNewState){ if( yyTraceFILE ){ if( yyNewStateyystack[yypParser->yyidx].major], + yyTracePrompt,yyTokenName[yypParser->yytos->major], yyNewState); }else{ fprintf(yyTraceFILE,"%sShift '%s'\n", - yyTracePrompt,yyTokenName[yypParser->yystack[yypParser->yyidx].major]); + yyTracePrompt,yyTokenName[yypParser->yytos->major]); } } } #else # define yyTraceShift(X,Y) @@ -132489,31 +133350,34 @@ int yyNewState, /* The new state to shift in */ int yyMajor, /* The major token to shift in */ sqlite3ParserTOKENTYPE yyMinor /* The minor token to shift in */ ){ yyStackEntry *yytos; - yypParser->yyidx++; + yypParser->yytos++; #ifdef YYTRACKMAXSTACKDEPTH - if( yypParser->yyidx>yypParser->yyidxMax ){ - yypParser->yyidxMax = yypParser->yyidx; + if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){ + yypParser->yyhwm++; + assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) ); } #endif #if YYSTACKDEPTH>0 - if( yypParser->yyidx>=YYSTACKDEPTH ){ + if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH] ){ yyStackOverflow(yypParser); return; } #else - if( yypParser->yyidx>=yypParser->yystksz ){ - yyGrowStack(yypParser); - if( yypParser->yyidx>=yypParser->yystksz ){ + if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz] ){ + if( yyGrowStack(yypParser) ){ yyStackOverflow(yypParser); return; } } #endif - yytos = &yypParser->yystack[yypParser->yyidx]; + if( yyNewState > YY_MAX_SHIFT ){ + yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; + } + yytos = yypParser->yytos; yytos->stateno = (YYACTIONTYPE)yyNewState; yytos->major = (YYCODETYPE)yyMajor; yytos->minor.yy0 = yyMinor; yyTraceShift(yypParser, yyNewState); } @@ -132713,31 +133577,33 @@ { 223, 1 }, { 223, 2 }, { 173, 5 }, { 173, 3 }, { 173, 5 }, - { 173, 4 }, + { 173, 5 }, { 173, 4 }, { 173, 5 }, - { 225, 5 }, - { 225, 4 }, - { 226, 2 }, - { 226, 0 }, - { 224, 1 }, - { 224, 0 }, + { 226, 5 }, + { 226, 4 }, + { 227, 2 }, + { 227, 0 }, + { 225, 1 }, + { 225, 0 }, { 208, 0 }, { 207, 3 }, { 207, 1 }, + { 224, 0 }, + { 224, 3 }, { 149, 12 }, - { 227, 1 }, - { 227, 0 }, + { 228, 1 }, + { 228, 0 }, { 177, 0 }, { 177, 3 }, { 187, 5 }, { 187, 3 }, - { 228, 0 }, - { 228, 2 }, + { 229, 0 }, + { 229, 2 }, { 149, 4 }, { 149, 1 }, { 149, 2 }, { 149, 3 }, { 149, 5 }, @@ -132745,58 +133611,58 @@ { 149, 5 }, { 149, 6 }, { 169, 2 }, { 170, 2 }, { 149, 5 }, - { 230, 11 }, - { 232, 1 }, - { 232, 1 }, - { 232, 2 }, - { 232, 0 }, + { 231, 11 }, { 233, 1 }, { 233, 1 }, - { 233, 3 }, - { 235, 0 }, - { 235, 2 }, - { 231, 3 }, - { 231, 2 }, - { 237, 3 }, + { 233, 2 }, + { 233, 0 }, + { 234, 1 }, + { 234, 1 }, + { 234, 3 }, + { 236, 0 }, + { 236, 2 }, + { 232, 3 }, + { 232, 2 }, { 238, 3 }, - { 238, 2 }, - { 236, 7 }, - { 236, 5 }, - { 236, 5 }, - { 236, 1 }, + { 239, 3 }, + { 239, 2 }, + { 237, 7 }, + { 237, 5 }, + { 237, 5 }, + { 237, 1 }, { 173, 4 }, { 173, 6 }, { 191, 1 }, { 191, 1 }, { 191, 1 }, { 149, 4 }, { 149, 6 }, { 149, 3 }, - { 240, 0 }, - { 240, 2 }, + { 241, 0 }, + { 241, 2 }, { 149, 1 }, { 149, 3 }, { 149, 1 }, { 149, 3 }, { 149, 6 }, { 149, 7 }, - { 241, 1 }, + { 242, 1 }, { 149, 1 }, { 149, 4 }, - { 243, 8 }, - { 245, 0 }, - { 246, 1 }, - { 246, 3 }, + { 244, 8 }, + { 246, 0 }, { 247, 1 }, + { 247, 3 }, + { 248, 1 }, { 196, 0 }, { 196, 2 }, { 196, 3 }, - { 249, 6 }, - { 249, 8 }, + { 250, 6 }, + { 250, 8 }, { 144, 1 }, { 145, 2 }, { 145, 1 }, { 146, 1 }, { 146, 3 }, @@ -132829,30 +133695,30 @@ { 195, 1 }, { 209, 2 }, { 210, 1 }, { 173, 1 }, { 208, 1 }, - { 229, 1 }, - { 229, 1 }, - { 229, 1 }, - { 229, 1 }, - { 229, 1 }, + { 230, 1 }, + { 230, 1 }, + { 230, 1 }, + { 230, 1 }, + { 230, 1 }, { 169, 1 }, - { 234, 0 }, - { 234, 3 }, - { 237, 1 }, - { 238, 0 }, - { 239, 1 }, + { 235, 0 }, + { 235, 3 }, + { 238, 1 }, { 239, 0 }, - { 242, 0 }, - { 242, 1 }, - { 244, 1 }, - { 244, 3 }, - { 245, 2 }, - { 248, 0 }, - { 248, 4 }, - { 248, 2 }, + { 240, 1 }, + { 240, 0 }, + { 243, 0 }, + { 243, 1 }, + { 245, 1 }, + { 245, 3 }, + { 246, 2 }, + { 249, 0 }, + { 249, 4 }, + { 249, 2 }, }; static void yy_accept(yyParser*); /* Forward Declaration */ /* @@ -132866,11 +133732,11 @@ int yygoto; /* The next state */ int yyact; /* The next action */ yyStackEntry *yymsp; /* The top of the parser's stack */ int yysize; /* Amount to pop the stack */ sqlite3ParserARG_FETCH; - yymsp = &yypParser->yystack[yypParser->yyidx]; + yymsp = yypParser->yytos; #ifndef NDEBUG if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ yysize = yyRuleInfo[yyruleno].nrhs; fprintf(yyTraceFILE, "%sReduce [%s], go to state %d.\n", yyTracePrompt, yyRuleName[yyruleno], yymsp[-yysize].stateno); @@ -132880,26 +133746,27 @@ /* Check that the stack is large enough to grow by a single entry ** if the RHS of the rule is empty. This ensures that there is room ** enough on the stack to push the LHS value */ if( yyRuleInfo[yyruleno].nrhs==0 ){ #ifdef YYTRACKMAXSTACKDEPTH - if( yypParser->yyidx>yypParser->yyidxMax ){ - yypParser->yyidxMax = yypParser->yyidx; + if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){ + yypParser->yyhwm++; + assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack)); } #endif #if YYSTACKDEPTH>0 - if( yypParser->yyidx>=YYSTACKDEPTH-1 ){ + if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH-1] ){ yyStackOverflow(yypParser); return; } #else - if( yypParser->yyidx>=yypParser->yystksz-1 ){ - yyGrowStack(yypParser); - if( yypParser->yyidx>=yypParser->yystksz-1 ){ + if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){ + if( yyGrowStack(yypParser) ){ yyStackOverflow(yypParser); return; } + yymsp = yypParser->yytos; } #endif } switch( yyruleno ){ @@ -132921,19 +133788,19 @@ break; case 2: /* cmdx ::= cmd */ { sqlite3FinishCoding(pParse); } break; case 3: /* cmd ::= BEGIN transtype trans_opt */ -{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy392);} +{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy194);} break; case 4: /* transtype ::= */ -{yymsp[1].minor.yy392 = TK_DEFERRED;} +{yymsp[1].minor.yy194 = TK_DEFERRED;} break; case 5: /* transtype ::= DEFERRED */ case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6); case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7); -{yymsp[0].minor.yy392 = yymsp[0].major; /*A-overwrites-X*/} +{yymsp[0].minor.yy194 = yymsp[0].major; /*A-overwrites-X*/} break; case 8: /* cmd ::= COMMIT trans_opt */ case 9: /* cmd ::= END trans_opt */ yytestcase(yyruleno==9); {sqlite3CommitTransaction(pParse);} break; @@ -132955,11 +133822,11 @@ sqlite3Savepoint(pParse, SAVEPOINT_ROLLBACK, &yymsp[0].minor.yy0); } break; case 14: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */ { - sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy392,0,0,yymsp[-2].minor.yy392); + sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy194,0,0,yymsp[-2].minor.yy194); } break; case 15: /* createkw ::= CREATE */ {disableLookaside(pParse);} break; @@ -132969,37 +133836,37 @@ case 42: /* autoinc ::= */ yytestcase(yyruleno==42); case 57: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==57); case 67: /* defer_subclause_opt ::= */ yytestcase(yyruleno==67); case 76: /* ifexists ::= */ yytestcase(yyruleno==76); case 90: /* distinct ::= */ yytestcase(yyruleno==90); - case 209: /* collate ::= */ yytestcase(yyruleno==209); -{yymsp[1].minor.yy392 = 0;} + case 211: /* collate ::= */ yytestcase(yyruleno==211); +{yymsp[1].minor.yy194 = 0;} break; case 17: /* ifnotexists ::= IF NOT EXISTS */ -{yymsp[-2].minor.yy392 = 1;} +{yymsp[-2].minor.yy194 = 1;} break; case 18: /* temp ::= TEMP */ case 43: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==43); -{yymsp[0].minor.yy392 = 1;} +{yymsp[0].minor.yy194 = 1;} break; case 20: /* create_table_args ::= LP columnlist conslist_opt RP table_options */ { - sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy392,0); + sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy194,0); } break; case 21: /* create_table_args ::= AS select */ { - sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy159); - sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy159); + sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy243); + sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy243); } break; case 23: /* table_options ::= WITHOUT nm */ { if( yymsp[0].minor.yy0.n==5 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"rowid",5)==0 ){ - yymsp[-1].minor.yy392 = TF_WithoutRowid | TF_NoVisibleRowid; + yymsp[-1].minor.yy194 = TF_WithoutRowid | TF_NoVisibleRowid; }else{ - yymsp[-1].minor.yy392 = 0; + yymsp[-1].minor.yy194 = 0; sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z); } } break; case 24: /* columnname ::= nm typetoken */ @@ -133027,21 +133894,21 @@ case 62: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==62); {pParse->constraintName = yymsp[0].minor.yy0;} break; case 30: /* ccons ::= DEFAULT term */ case 32: /* ccons ::= DEFAULT PLUS term */ yytestcase(yyruleno==32); -{sqlite3AddDefaultValue(pParse,&yymsp[0].minor.yy342);} +{sqlite3AddDefaultValue(pParse,&yymsp[0].minor.yy190);} break; case 31: /* ccons ::= DEFAULT LP expr RP */ -{sqlite3AddDefaultValue(pParse,&yymsp[-1].minor.yy342);} +{sqlite3AddDefaultValue(pParse,&yymsp[-1].minor.yy190);} break; case 33: /* ccons ::= DEFAULT MINUS term */ { ExprSpan v; - v.pExpr = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy342.pExpr, 0, 0); + v.pExpr = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy190.pExpr, 0, 0); v.zStart = yymsp[-1].minor.yy0.z; - v.zEnd = yymsp[0].minor.yy342.zEnd; + v.zEnd = yymsp[0].minor.yy190.zEnd; sqlite3AddDefaultValue(pParse,&v); } break; case 34: /* ccons ::= DEFAULT ID|INDEXED */ { @@ -133049,184 +133916,186 @@ spanExpr(&v, pParse, TK_STRING, yymsp[0].minor.yy0); sqlite3AddDefaultValue(pParse,&v); } break; case 35: /* ccons ::= NOT NULL onconf */ -{sqlite3AddNotNull(pParse, yymsp[0].minor.yy392);} +{sqlite3AddNotNull(pParse, yymsp[0].minor.yy194);} break; case 36: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */ -{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy392,yymsp[0].minor.yy392,yymsp[-2].minor.yy392);} +{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy194,yymsp[0].minor.yy194,yymsp[-2].minor.yy194);} break; case 37: /* ccons ::= UNIQUE onconf */ -{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy392,0,0,0,0);} +{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy194,0,0,0,0, + SQLITE_IDXTYPE_UNIQUE);} break; case 38: /* ccons ::= CHECK LP expr RP */ -{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy342.pExpr);} +{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy190.pExpr);} break; case 39: /* ccons ::= REFERENCES nm eidlist_opt refargs */ -{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy442,yymsp[0].minor.yy392);} +{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy148,yymsp[0].minor.yy194);} break; case 40: /* ccons ::= defer_subclause */ -{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy392);} +{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy194);} break; case 41: /* ccons ::= COLLATE ID|STRING */ {sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);} break; case 44: /* refargs ::= */ -{ yymsp[1].minor.yy392 = OE_None*0x0101; /* EV: R-19803-45884 */} +{ yymsp[1].minor.yy194 = OE_None*0x0101; /* EV: R-19803-45884 */} break; case 45: /* refargs ::= refargs refarg */ -{ yymsp[-1].minor.yy392 = (yymsp[-1].minor.yy392 & ~yymsp[0].minor.yy207.mask) | yymsp[0].minor.yy207.value; } +{ yymsp[-1].minor.yy194 = (yymsp[-1].minor.yy194 & ~yymsp[0].minor.yy497.mask) | yymsp[0].minor.yy497.value; } break; case 46: /* refarg ::= MATCH nm */ -{ yymsp[-1].minor.yy207.value = 0; yymsp[-1].minor.yy207.mask = 0x000000; } +{ yymsp[-1].minor.yy497.value = 0; yymsp[-1].minor.yy497.mask = 0x000000; } break; case 47: /* refarg ::= ON INSERT refact */ -{ yymsp[-2].minor.yy207.value = 0; yymsp[-2].minor.yy207.mask = 0x000000; } +{ yymsp[-2].minor.yy497.value = 0; yymsp[-2].minor.yy497.mask = 0x000000; } break; case 48: /* refarg ::= ON DELETE refact */ -{ yymsp[-2].minor.yy207.value = yymsp[0].minor.yy392; yymsp[-2].minor.yy207.mask = 0x0000ff; } +{ yymsp[-2].minor.yy497.value = yymsp[0].minor.yy194; yymsp[-2].minor.yy497.mask = 0x0000ff; } break; case 49: /* refarg ::= ON UPDATE refact */ -{ yymsp[-2].minor.yy207.value = yymsp[0].minor.yy392<<8; yymsp[-2].minor.yy207.mask = 0x00ff00; } +{ yymsp[-2].minor.yy497.value = yymsp[0].minor.yy194<<8; yymsp[-2].minor.yy497.mask = 0x00ff00; } break; case 50: /* refact ::= SET NULL */ -{ yymsp[-1].minor.yy392 = OE_SetNull; /* EV: R-33326-45252 */} +{ yymsp[-1].minor.yy194 = OE_SetNull; /* EV: R-33326-45252 */} break; case 51: /* refact ::= SET DEFAULT */ -{ yymsp[-1].minor.yy392 = OE_SetDflt; /* EV: R-33326-45252 */} +{ yymsp[-1].minor.yy194 = OE_SetDflt; /* EV: R-33326-45252 */} break; case 52: /* refact ::= CASCADE */ -{ yymsp[0].minor.yy392 = OE_Cascade; /* EV: R-33326-45252 */} +{ yymsp[0].minor.yy194 = OE_Cascade; /* EV: R-33326-45252 */} break; case 53: /* refact ::= RESTRICT */ -{ yymsp[0].minor.yy392 = OE_Restrict; /* EV: R-33326-45252 */} +{ yymsp[0].minor.yy194 = OE_Restrict; /* EV: R-33326-45252 */} break; case 54: /* refact ::= NO ACTION */ -{ yymsp[-1].minor.yy392 = OE_None; /* EV: R-33326-45252 */} +{ yymsp[-1].minor.yy194 = OE_None; /* EV: R-33326-45252 */} break; case 55: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ -{yymsp[-2].minor.yy392 = 0;} +{yymsp[-2].minor.yy194 = 0;} break; case 56: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ case 71: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==71); case 142: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==142); -{yymsp[-1].minor.yy392 = yymsp[0].minor.yy392;} +{yymsp[-1].minor.yy194 = yymsp[0].minor.yy194;} break; case 58: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ case 75: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==75); case 183: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==183); case 186: /* in_op ::= NOT IN */ yytestcase(yyruleno==186); - case 210: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==210); -{yymsp[-1].minor.yy392 = 1;} + case 212: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==212); +{yymsp[-1].minor.yy194 = 1;} break; case 59: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ -{yymsp[-1].minor.yy392 = 0;} +{yymsp[-1].minor.yy194 = 0;} break; case 61: /* tconscomma ::= COMMA */ {pParse->constraintName.n = 0;} break; case 63: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ -{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy442,yymsp[0].minor.yy392,yymsp[-2].minor.yy392,0);} +{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy148,yymsp[0].minor.yy194,yymsp[-2].minor.yy194,0);} break; case 64: /* tcons ::= UNIQUE LP sortlist RP onconf */ -{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy442,yymsp[0].minor.yy392,0,0,0,0);} +{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy148,yymsp[0].minor.yy194,0,0,0,0, + SQLITE_IDXTYPE_UNIQUE);} break; case 65: /* tcons ::= CHECK LP expr RP onconf */ -{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy342.pExpr);} +{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy190.pExpr);} break; case 66: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ { - sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy442, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy442, yymsp[-1].minor.yy392); - sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy392); + sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy148, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy148, yymsp[-1].minor.yy194); + sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy194); } break; case 68: /* onconf ::= */ case 70: /* orconf ::= */ yytestcase(yyruleno==70); -{yymsp[1].minor.yy392 = OE_Default;} +{yymsp[1].minor.yy194 = OE_Default;} break; case 69: /* onconf ::= ON CONFLICT resolvetype */ -{yymsp[-2].minor.yy392 = yymsp[0].minor.yy392;} +{yymsp[-2].minor.yy194 = yymsp[0].minor.yy194;} break; case 72: /* resolvetype ::= IGNORE */ -{yymsp[0].minor.yy392 = OE_Ignore;} +{yymsp[0].minor.yy194 = OE_Ignore;} break; case 73: /* resolvetype ::= REPLACE */ case 143: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==143); -{yymsp[0].minor.yy392 = OE_Replace;} +{yymsp[0].minor.yy194 = OE_Replace;} break; case 74: /* cmd ::= DROP TABLE ifexists fullname */ { - sqlite3DropTable(pParse, yymsp[0].minor.yy347, 0, yymsp[-1].minor.yy392); + sqlite3DropTable(pParse, yymsp[0].minor.yy185, 0, yymsp[-1].minor.yy194); } break; case 77: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ { - sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy442, yymsp[0].minor.yy159, yymsp[-7].minor.yy392, yymsp[-5].minor.yy392); + sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy148, yymsp[0].minor.yy243, yymsp[-7].minor.yy194, yymsp[-5].minor.yy194); } break; case 78: /* cmd ::= DROP VIEW ifexists fullname */ { - sqlite3DropTable(pParse, yymsp[0].minor.yy347, 1, yymsp[-1].minor.yy392); + sqlite3DropTable(pParse, yymsp[0].minor.yy185, 1, yymsp[-1].minor.yy194); } break; case 79: /* cmd ::= select */ { SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0}; - sqlite3Select(pParse, yymsp[0].minor.yy159, &dest); - sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy159); + sqlite3Select(pParse, yymsp[0].minor.yy243, &dest); + sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy243); } break; case 80: /* select ::= with selectnowith */ { - Select *p = yymsp[0].minor.yy159; + Select *p = yymsp[0].minor.yy243; if( p ){ - p->pWith = yymsp[-1].minor.yy331; + p->pWith = yymsp[-1].minor.yy285; parserDoubleLinkSelect(pParse, p); }else{ - sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy331); + sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy285); } - yymsp[-1].minor.yy159 = p; /*A-overwrites-W*/ + yymsp[-1].minor.yy243 = p; /*A-overwrites-W*/ } break; case 81: /* selectnowith ::= selectnowith multiselect_op oneselect */ { - Select *pRhs = yymsp[0].minor.yy159; - Select *pLhs = yymsp[-2].minor.yy159; + Select *pRhs = yymsp[0].minor.yy243; + Select *pLhs = yymsp[-2].minor.yy243; if( pRhs && pRhs->pPrior ){ SrcList *pFrom; Token x; x.n = 0; parserDoubleLinkSelect(pParse, pRhs); pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0,0); pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0,0); } if( pRhs ){ - pRhs->op = (u8)yymsp[-1].minor.yy392; + pRhs->op = (u8)yymsp[-1].minor.yy194; pRhs->pPrior = pLhs; if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue; pRhs->selFlags &= ~SF_MultiValue; - if( yymsp[-1].minor.yy392!=TK_ALL ) pParse->hasCompound = 1; + if( yymsp[-1].minor.yy194!=TK_ALL ) pParse->hasCompound = 1; }else{ sqlite3SelectDelete(pParse->db, pLhs); } - yymsp[-2].minor.yy159 = pRhs; + yymsp[-2].minor.yy243 = pRhs; } break; case 82: /* multiselect_op ::= UNION */ case 84: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==84); -{yymsp[0].minor.yy392 = yymsp[0].major; /*A-overwrites-OP*/} +{yymsp[0].minor.yy194 = yymsp[0].major; /*A-overwrites-OP*/} break; case 83: /* multiselect_op ::= UNION ALL */ -{yymsp[-1].minor.yy392 = TK_ALL;} +{yymsp[-1].minor.yy194 = TK_ALL;} break; case 85: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ { #if SELECTTRACE_ENABLED Token s = yymsp[-8].minor.yy0; /*A-overwrites-S*/ #endif - yymsp[-8].minor.yy159 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy442,yymsp[-5].minor.yy347,yymsp[-4].minor.yy122,yymsp[-3].minor.yy442,yymsp[-2].minor.yy122,yymsp[-1].minor.yy442,yymsp[-7].minor.yy392,yymsp[0].minor.yy64.pLimit,yymsp[0].minor.yy64.pOffset); + yymsp[-8].minor.yy243 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy148,yymsp[-5].minor.yy185,yymsp[-4].minor.yy72,yymsp[-3].minor.yy148,yymsp[-2].minor.yy72,yymsp[-1].minor.yy148,yymsp[-7].minor.yy194,yymsp[0].minor.yy354.pLimit,yymsp[0].minor.yy354.pOffset); #if SELECTTRACE_ENABLED /* Populate the Select.zSelName[] string that is used to help with ** query planner debugging, to differentiate between multiple Select ** objects in a complex query. ** @@ -133233,464 +134102,465 @@ ** If the SELECT keyword is immediately followed by a C-style comment ** then extract the first few alphanumeric characters from within that ** comment to be the zSelName value. Otherwise, the label is #N where ** is an integer that is incremented with each SELECT statement seen. */ - if( yymsp[-8].minor.yy159!=0 ){ + if( yymsp[-8].minor.yy243!=0 ){ const char *z = s.z+6; int i; - sqlite3_snprintf(sizeof(yymsp[-8].minor.yy159->zSelName), yymsp[-8].minor.yy159->zSelName, "#%d", + sqlite3_snprintf(sizeof(yymsp[-8].minor.yy243->zSelName), yymsp[-8].minor.yy243->zSelName, "#%d", ++pParse->nSelect); while( z[0]==' ' ) z++; if( z[0]=='/' && z[1]=='*' ){ z += 2; while( z[0]==' ' ) z++; for(i=0; sqlite3Isalnum(z[i]); i++){} - sqlite3_snprintf(sizeof(yymsp[-8].minor.yy159->zSelName), yymsp[-8].minor.yy159->zSelName, "%.*s", i, z); + sqlite3_snprintf(sizeof(yymsp[-8].minor.yy243->zSelName), yymsp[-8].minor.yy243->zSelName, "%.*s", i, z); } } #endif /* SELECTRACE_ENABLED */ } break; case 86: /* values ::= VALUES LP nexprlist RP */ { - yymsp[-3].minor.yy159 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy442,0,0,0,0,0,SF_Values,0,0); + yymsp[-3].minor.yy243 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy148,0,0,0,0,0,SF_Values,0,0); } break; case 87: /* values ::= values COMMA LP exprlist RP */ { - Select *pRight, *pLeft = yymsp[-4].minor.yy159; - pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy442,0,0,0,0,0,SF_Values|SF_MultiValue,0,0); + Select *pRight, *pLeft = yymsp[-4].minor.yy243; + pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy148,0,0,0,0,0,SF_Values|SF_MultiValue,0,0); if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue; if( pRight ){ pRight->op = TK_ALL; pRight->pPrior = pLeft; - yymsp[-4].minor.yy159 = pRight; + yymsp[-4].minor.yy243 = pRight; }else{ - yymsp[-4].minor.yy159 = pLeft; + yymsp[-4].minor.yy243 = pLeft; } } break; case 88: /* distinct ::= DISTINCT */ -{yymsp[0].minor.yy392 = SF_Distinct;} +{yymsp[0].minor.yy194 = SF_Distinct;} break; case 89: /* distinct ::= ALL */ -{yymsp[0].minor.yy392 = SF_All;} +{yymsp[0].minor.yy194 = SF_All;} break; case 91: /* sclp ::= */ case 119: /* orderby_opt ::= */ yytestcase(yyruleno==119); case 126: /* groupby_opt ::= */ yytestcase(yyruleno==126); case 199: /* exprlist ::= */ yytestcase(yyruleno==199); - case 205: /* eidlist_opt ::= */ yytestcase(yyruleno==205); -{yymsp[1].minor.yy442 = 0;} + case 202: /* paren_exprlist ::= */ yytestcase(yyruleno==202); + case 207: /* eidlist_opt ::= */ yytestcase(yyruleno==207); +{yymsp[1].minor.yy148 = 0;} break; case 92: /* selcollist ::= sclp expr as */ { - yymsp[-2].minor.yy442 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy442, yymsp[-1].minor.yy342.pExpr); - if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-2].minor.yy442, &yymsp[0].minor.yy0, 1); - sqlite3ExprListSetSpan(pParse,yymsp[-2].minor.yy442,&yymsp[-1].minor.yy342); + yymsp[-2].minor.yy148 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy148, yymsp[-1].minor.yy190.pExpr); + if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-2].minor.yy148, &yymsp[0].minor.yy0, 1); + sqlite3ExprListSetSpan(pParse,yymsp[-2].minor.yy148,&yymsp[-1].minor.yy190); } break; case 93: /* selcollist ::= sclp STAR */ { Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0); - yymsp[-1].minor.yy442 = sqlite3ExprListAppend(pParse, yymsp[-1].minor.yy442, p); + yymsp[-1].minor.yy148 = sqlite3ExprListAppend(pParse, yymsp[-1].minor.yy148, p); } break; case 94: /* selcollist ::= sclp nm DOT STAR */ { Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0, &yymsp[0].minor.yy0); Expr *pLeft = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy0); Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0); - yymsp[-3].minor.yy442 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy442, pDot); + yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy148, pDot); } break; case 95: /* as ::= AS nm */ case 106: /* dbnm ::= DOT nm */ yytestcase(yyruleno==106); - case 219: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==219); - case 220: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==220); + case 221: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==221); + case 222: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==222); {yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;} break; case 97: /* from ::= */ -{yymsp[1].minor.yy347 = sqlite3DbMallocZero(pParse->db, sizeof(*yymsp[1].minor.yy347));} +{yymsp[1].minor.yy185 = sqlite3DbMallocZero(pParse->db, sizeof(*yymsp[1].minor.yy185));} break; case 98: /* from ::= FROM seltablist */ { - yymsp[-1].minor.yy347 = yymsp[0].minor.yy347; - sqlite3SrcListShiftJoinType(yymsp[-1].minor.yy347); + yymsp[-1].minor.yy185 = yymsp[0].minor.yy185; + sqlite3SrcListShiftJoinType(yymsp[-1].minor.yy185); } break; case 99: /* stl_prefix ::= seltablist joinop */ { - if( ALWAYS(yymsp[-1].minor.yy347 && yymsp[-1].minor.yy347->nSrc>0) ) yymsp[-1].minor.yy347->a[yymsp[-1].minor.yy347->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy392; + if( ALWAYS(yymsp[-1].minor.yy185 && yymsp[-1].minor.yy185->nSrc>0) ) yymsp[-1].minor.yy185->a[yymsp[-1].minor.yy185->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy194; } break; case 100: /* stl_prefix ::= */ -{yymsp[1].minor.yy347 = 0;} +{yymsp[1].minor.yy185 = 0;} break; case 101: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */ { - yymsp[-6].minor.yy347 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy347,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy122,yymsp[0].minor.yy180); - sqlite3SrcListIndexedBy(pParse, yymsp[-6].minor.yy347, &yymsp[-2].minor.yy0); + yymsp[-6].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy185,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy72,yymsp[0].minor.yy254); + sqlite3SrcListIndexedBy(pParse, yymsp[-6].minor.yy185, &yymsp[-2].minor.yy0); } break; case 102: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */ { - yymsp[-8].minor.yy347 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-8].minor.yy347,&yymsp[-7].minor.yy0,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy122,yymsp[0].minor.yy180); - sqlite3SrcListFuncArgs(pParse, yymsp[-8].minor.yy347, yymsp[-4].minor.yy442); + yymsp[-8].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-8].minor.yy185,&yymsp[-7].minor.yy0,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy72,yymsp[0].minor.yy254); + sqlite3SrcListFuncArgs(pParse, yymsp[-8].minor.yy185, yymsp[-4].minor.yy148); } break; case 103: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */ { - yymsp[-6].minor.yy347 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy347,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy159,yymsp[-1].minor.yy122,yymsp[0].minor.yy180); + yymsp[-6].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy185,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy243,yymsp[-1].minor.yy72,yymsp[0].minor.yy254); } break; case 104: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */ { - if( yymsp[-6].minor.yy347==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy122==0 && yymsp[0].minor.yy180==0 ){ - yymsp[-6].minor.yy347 = yymsp[-4].minor.yy347; - }else if( yymsp[-4].minor.yy347->nSrc==1 ){ - yymsp[-6].minor.yy347 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy347,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy122,yymsp[0].minor.yy180); - if( yymsp[-6].minor.yy347 ){ - struct SrcList_item *pNew = &yymsp[-6].minor.yy347->a[yymsp[-6].minor.yy347->nSrc-1]; - struct SrcList_item *pOld = yymsp[-4].minor.yy347->a; + if( yymsp[-6].minor.yy185==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy72==0 && yymsp[0].minor.yy254==0 ){ + yymsp[-6].minor.yy185 = yymsp[-4].minor.yy185; + }else if( yymsp[-4].minor.yy185->nSrc==1 ){ + yymsp[-6].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy185,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy72,yymsp[0].minor.yy254); + if( yymsp[-6].minor.yy185 ){ + struct SrcList_item *pNew = &yymsp[-6].minor.yy185->a[yymsp[-6].minor.yy185->nSrc-1]; + struct SrcList_item *pOld = yymsp[-4].minor.yy185->a; pNew->zName = pOld->zName; pNew->zDatabase = pOld->zDatabase; pNew->pSelect = pOld->pSelect; pOld->zName = pOld->zDatabase = 0; pOld->pSelect = 0; } - sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy347); + sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy185); }else{ Select *pSubquery; - sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy347); - pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy347,0,0,0,0,SF_NestedFrom,0,0); - yymsp[-6].minor.yy347 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy347,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy122,yymsp[0].minor.yy180); + sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy185); + pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy185,0,0,0,0,SF_NestedFrom,0,0); + yymsp[-6].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy185,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy72,yymsp[0].minor.yy254); } } break; case 105: /* dbnm ::= */ case 114: /* indexed_opt ::= */ yytestcase(yyruleno==114); {yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;} break; case 107: /* fullname ::= nm dbnm */ -{yymsp[-1].minor.yy347 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/} +{yymsp[-1].minor.yy185 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/} break; case 108: /* joinop ::= COMMA|JOIN */ -{ yymsp[0].minor.yy392 = JT_INNER; } +{ yymsp[0].minor.yy194 = JT_INNER; } break; case 109: /* joinop ::= JOIN_KW JOIN */ -{yymsp[-1].minor.yy392 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/} +{yymsp[-1].minor.yy194 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/} break; case 110: /* joinop ::= JOIN_KW nm JOIN */ -{yymsp[-2].minor.yy392 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/} +{yymsp[-2].minor.yy194 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/} break; case 111: /* joinop ::= JOIN_KW nm nm JOIN */ -{yymsp[-3].minor.yy392 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/} +{yymsp[-3].minor.yy194 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/} break; case 112: /* on_opt ::= ON expr */ case 129: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==129); case 136: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==136); case 195: /* case_else ::= ELSE expr */ yytestcase(yyruleno==195); -{yymsp[-1].minor.yy122 = yymsp[0].minor.yy342.pExpr;} +{yymsp[-1].minor.yy72 = yymsp[0].minor.yy190.pExpr;} break; case 113: /* on_opt ::= */ case 128: /* having_opt ::= */ yytestcase(yyruleno==128); case 135: /* where_opt ::= */ yytestcase(yyruleno==135); case 196: /* case_else ::= */ yytestcase(yyruleno==196); case 198: /* case_operand ::= */ yytestcase(yyruleno==198); -{yymsp[1].minor.yy122 = 0;} +{yymsp[1].minor.yy72 = 0;} break; case 115: /* indexed_opt ::= INDEXED BY nm */ {yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;} break; case 116: /* indexed_opt ::= NOT INDEXED */ {yymsp[-1].minor.yy0.z=0; yymsp[-1].minor.yy0.n=1;} break; case 117: /* using_opt ::= USING LP idlist RP */ -{yymsp[-3].minor.yy180 = yymsp[-1].minor.yy180;} +{yymsp[-3].minor.yy254 = yymsp[-1].minor.yy254;} break; case 118: /* using_opt ::= */ case 144: /* idlist_opt ::= */ yytestcase(yyruleno==144); -{yymsp[1].minor.yy180 = 0;} +{yymsp[1].minor.yy254 = 0;} break; case 120: /* orderby_opt ::= ORDER BY sortlist */ case 127: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==127); -{yymsp[-2].minor.yy442 = yymsp[0].minor.yy442;} +{yymsp[-2].minor.yy148 = yymsp[0].minor.yy148;} break; case 121: /* sortlist ::= sortlist COMMA expr sortorder */ { - yymsp[-3].minor.yy442 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy442,yymsp[-1].minor.yy342.pExpr); - sqlite3ExprListSetSortOrder(yymsp[-3].minor.yy442,yymsp[0].minor.yy392); + yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy148,yymsp[-1].minor.yy190.pExpr); + sqlite3ExprListSetSortOrder(yymsp[-3].minor.yy148,yymsp[0].minor.yy194); } break; case 122: /* sortlist ::= expr sortorder */ { - yymsp[-1].minor.yy442 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy342.pExpr); /*A-overwrites-Y*/ - sqlite3ExprListSetSortOrder(yymsp[-1].minor.yy442,yymsp[0].minor.yy392); + yymsp[-1].minor.yy148 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy190.pExpr); /*A-overwrites-Y*/ + sqlite3ExprListSetSortOrder(yymsp[-1].minor.yy148,yymsp[0].minor.yy194); } break; case 123: /* sortorder ::= ASC */ -{yymsp[0].minor.yy392 = SQLITE_SO_ASC;} +{yymsp[0].minor.yy194 = SQLITE_SO_ASC;} break; case 124: /* sortorder ::= DESC */ -{yymsp[0].minor.yy392 = SQLITE_SO_DESC;} +{yymsp[0].minor.yy194 = SQLITE_SO_DESC;} break; case 125: /* sortorder ::= */ -{yymsp[1].minor.yy392 = SQLITE_SO_UNDEFINED;} +{yymsp[1].minor.yy194 = SQLITE_SO_UNDEFINED;} break; case 130: /* limit_opt ::= */ -{yymsp[1].minor.yy64.pLimit = 0; yymsp[1].minor.yy64.pOffset = 0;} +{yymsp[1].minor.yy354.pLimit = 0; yymsp[1].minor.yy354.pOffset = 0;} break; case 131: /* limit_opt ::= LIMIT expr */ -{yymsp[-1].minor.yy64.pLimit = yymsp[0].minor.yy342.pExpr; yymsp[-1].minor.yy64.pOffset = 0;} +{yymsp[-1].minor.yy354.pLimit = yymsp[0].minor.yy190.pExpr; yymsp[-1].minor.yy354.pOffset = 0;} break; case 132: /* limit_opt ::= LIMIT expr OFFSET expr */ -{yymsp[-3].minor.yy64.pLimit = yymsp[-2].minor.yy342.pExpr; yymsp[-3].minor.yy64.pOffset = yymsp[0].minor.yy342.pExpr;} +{yymsp[-3].minor.yy354.pLimit = yymsp[-2].minor.yy190.pExpr; yymsp[-3].minor.yy354.pOffset = yymsp[0].minor.yy190.pExpr;} break; case 133: /* limit_opt ::= LIMIT expr COMMA expr */ -{yymsp[-3].minor.yy64.pOffset = yymsp[-2].minor.yy342.pExpr; yymsp[-3].minor.yy64.pLimit = yymsp[0].minor.yy342.pExpr;} +{yymsp[-3].minor.yy354.pOffset = yymsp[-2].minor.yy190.pExpr; yymsp[-3].minor.yy354.pLimit = yymsp[0].minor.yy190.pExpr;} break; case 134: /* cmd ::= with DELETE FROM fullname indexed_opt where_opt */ { - sqlite3WithPush(pParse, yymsp[-5].minor.yy331, 1); - sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy347, &yymsp[-1].minor.yy0); - sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy347,yymsp[0].minor.yy122); + sqlite3WithPush(pParse, yymsp[-5].minor.yy285, 1); + sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy185, &yymsp[-1].minor.yy0); + sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy185,yymsp[0].minor.yy72); } break; case 137: /* cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt */ { - sqlite3WithPush(pParse, yymsp[-7].minor.yy331, 1); - sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy347, &yymsp[-3].minor.yy0); - sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy442,"set list"); - sqlite3Update(pParse,yymsp[-4].minor.yy347,yymsp[-1].minor.yy442,yymsp[0].minor.yy122,yymsp[-5].minor.yy392); + sqlite3WithPush(pParse, yymsp[-7].minor.yy285, 1); + sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy185, &yymsp[-3].minor.yy0); + sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy148,"set list"); + sqlite3Update(pParse,yymsp[-4].minor.yy185,yymsp[-1].minor.yy148,yymsp[0].minor.yy72,yymsp[-5].minor.yy194); } break; case 138: /* setlist ::= setlist COMMA nm EQ expr */ { - yymsp[-4].minor.yy442 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy442, yymsp[0].minor.yy342.pExpr); - sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy442, &yymsp[-2].minor.yy0, 1); + yymsp[-4].minor.yy148 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy148, yymsp[0].minor.yy190.pExpr); + sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy148, &yymsp[-2].minor.yy0, 1); } break; case 139: /* setlist ::= nm EQ expr */ { - yylhsminor.yy442 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy342.pExpr); - sqlite3ExprListSetName(pParse, yylhsminor.yy442, &yymsp[-2].minor.yy0, 1); + yylhsminor.yy148 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy190.pExpr); + sqlite3ExprListSetName(pParse, yylhsminor.yy148, &yymsp[-2].minor.yy0, 1); } - yymsp[-2].minor.yy442 = yylhsminor.yy442; + yymsp[-2].minor.yy148 = yylhsminor.yy148; break; case 140: /* cmd ::= with insert_cmd INTO fullname idlist_opt select */ { - sqlite3WithPush(pParse, yymsp[-5].minor.yy331, 1); - sqlite3Insert(pParse, yymsp[-2].minor.yy347, yymsp[0].minor.yy159, yymsp[-1].minor.yy180, yymsp[-4].minor.yy392); + sqlite3WithPush(pParse, yymsp[-5].minor.yy285, 1); + sqlite3Insert(pParse, yymsp[-2].minor.yy185, yymsp[0].minor.yy243, yymsp[-1].minor.yy254, yymsp[-4].minor.yy194); } break; case 141: /* cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES */ { - sqlite3WithPush(pParse, yymsp[-6].minor.yy331, 1); - sqlite3Insert(pParse, yymsp[-3].minor.yy347, 0, yymsp[-2].minor.yy180, yymsp[-5].minor.yy392); + sqlite3WithPush(pParse, yymsp[-6].minor.yy285, 1); + sqlite3Insert(pParse, yymsp[-3].minor.yy185, 0, yymsp[-2].minor.yy254, yymsp[-5].minor.yy194); } break; case 145: /* idlist_opt ::= LP idlist RP */ -{yymsp[-2].minor.yy180 = yymsp[-1].minor.yy180;} +{yymsp[-2].minor.yy254 = yymsp[-1].minor.yy254;} break; case 146: /* idlist ::= idlist COMMA nm */ -{yymsp[-2].minor.yy180 = sqlite3IdListAppend(pParse->db,yymsp[-2].minor.yy180,&yymsp[0].minor.yy0);} +{yymsp[-2].minor.yy254 = sqlite3IdListAppend(pParse->db,yymsp[-2].minor.yy254,&yymsp[0].minor.yy0);} break; case 147: /* idlist ::= nm */ -{yymsp[0].minor.yy180 = sqlite3IdListAppend(pParse->db,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/} +{yymsp[0].minor.yy254 = sqlite3IdListAppend(pParse->db,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/} break; case 148: /* expr ::= LP expr RP */ -{spanSet(&yymsp[-2].minor.yy342,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/ yymsp[-2].minor.yy342.pExpr = yymsp[-1].minor.yy342.pExpr;} +{spanSet(&yymsp[-2].minor.yy190,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/ yymsp[-2].minor.yy190.pExpr = yymsp[-1].minor.yy190.pExpr;} break; case 149: /* term ::= NULL */ case 154: /* term ::= INTEGER|FLOAT|BLOB */ yytestcase(yyruleno==154); case 155: /* term ::= STRING */ yytestcase(yyruleno==155); -{spanExpr(&yymsp[0].minor.yy342,pParse,yymsp[0].major,yymsp[0].minor.yy0);/*A-overwrites-X*/} +{spanExpr(&yymsp[0].minor.yy190,pParse,yymsp[0].major,yymsp[0].minor.yy0);/*A-overwrites-X*/} break; case 150: /* expr ::= ID|INDEXED */ case 151: /* expr ::= JOIN_KW */ yytestcase(yyruleno==151); -{spanExpr(&yymsp[0].minor.yy342,pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/} +{spanExpr(&yymsp[0].minor.yy190,pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/} break; case 152: /* expr ::= nm DOT nm */ { Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy0); Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[0].minor.yy0); - spanSet(&yymsp[-2].minor.yy342,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ - yymsp[-2].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp2, 0); + spanSet(&yymsp[-2].minor.yy190,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ + yymsp[-2].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp2, 0); } break; case 153: /* expr ::= nm DOT nm DOT nm */ { Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-4].minor.yy0); Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy0); Expr *temp3 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[0].minor.yy0); Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3, 0); - spanSet(&yymsp[-4].minor.yy342,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ - yymsp[-4].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp4, 0); + spanSet(&yymsp[-4].minor.yy190,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ + yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp4, 0); } break; case 156: /* expr ::= VARIABLE */ { if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){ - spanExpr(&yymsp[0].minor.yy342, pParse, TK_VARIABLE, yymsp[0].minor.yy0); - sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy342.pExpr); + spanExpr(&yymsp[0].minor.yy190, pParse, TK_VARIABLE, yymsp[0].minor.yy0); + sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy190.pExpr); }else{ /* When doing a nested parse, one can include terms in an expression ** that look like this: #1 #2 ... These terms refer to registers ** in the virtual machine. #N is the N-th register. */ Token t = yymsp[0].minor.yy0; /*A-overwrites-X*/ assert( t.n>=2 ); - spanSet(&yymsp[0].minor.yy342, &t, &t); + spanSet(&yymsp[0].minor.yy190, &t, &t); if( pParse->nested==0 ){ sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t); - yymsp[0].minor.yy342.pExpr = 0; + yymsp[0].minor.yy190.pExpr = 0; }else{ - yymsp[0].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_REGISTER, 0, 0, &t); - if( yymsp[0].minor.yy342.pExpr ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy342.pExpr->iTable); + yymsp[0].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_REGISTER, 0, 0, &t); + if( yymsp[0].minor.yy190.pExpr ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy190.pExpr->iTable); } } } break; case 157: /* expr ::= expr COLLATE ID|STRING */ { - yymsp[-2].minor.yy342.pExpr = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy342.pExpr, &yymsp[0].minor.yy0, 1); - yymsp[-2].minor.yy342.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; + yymsp[-2].minor.yy190.pExpr = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy190.pExpr, &yymsp[0].minor.yy0, 1); + yymsp[-2].minor.yy190.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; } break; case 158: /* expr ::= CAST LP expr AS typetoken RP */ { - spanSet(&yymsp[-5].minor.yy342,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ - yymsp[-5].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_CAST, yymsp[-3].minor.yy342.pExpr, 0, &yymsp[-1].minor.yy0); + spanSet(&yymsp[-5].minor.yy190,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ + yymsp[-5].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_CAST, yymsp[-3].minor.yy190.pExpr, 0, &yymsp[-1].minor.yy0); } break; case 159: /* expr ::= ID|INDEXED LP distinct exprlist RP */ { - if( yymsp[-1].minor.yy442 && yymsp[-1].minor.yy442->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){ + if( yymsp[-1].minor.yy148 && yymsp[-1].minor.yy148->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){ sqlite3ErrorMsg(pParse, "too many arguments on function %T", &yymsp[-4].minor.yy0); } - yylhsminor.yy342.pExpr = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy442, &yymsp[-4].minor.yy0); - spanSet(&yylhsminor.yy342,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); - if( yymsp[-2].minor.yy392==SF_Distinct && yylhsminor.yy342.pExpr ){ - yylhsminor.yy342.pExpr->flags |= EP_Distinct; + yylhsminor.yy190.pExpr = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy148, &yymsp[-4].minor.yy0); + spanSet(&yylhsminor.yy190,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); + if( yymsp[-2].minor.yy194==SF_Distinct && yylhsminor.yy190.pExpr ){ + yylhsminor.yy190.pExpr->flags |= EP_Distinct; } } - yymsp[-4].minor.yy342 = yylhsminor.yy342; + yymsp[-4].minor.yy190 = yylhsminor.yy190; break; case 160: /* expr ::= ID|INDEXED LP STAR RP */ { - yylhsminor.yy342.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0); - spanSet(&yylhsminor.yy342,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); + yylhsminor.yy190.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0); + spanSet(&yylhsminor.yy190,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); } - yymsp[-3].minor.yy342 = yylhsminor.yy342; + yymsp[-3].minor.yy190 = yylhsminor.yy190; break; case 161: /* term ::= CTIME_KW */ { - yylhsminor.yy342.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0); - spanSet(&yylhsminor.yy342, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0); + yylhsminor.yy190.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0); + spanSet(&yylhsminor.yy190, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0); } - yymsp[0].minor.yy342 = yylhsminor.yy342; + yymsp[0].minor.yy190 = yylhsminor.yy190; break; case 162: /* expr ::= expr AND expr */ case 163: /* expr ::= expr OR expr */ yytestcase(yyruleno==163); case 164: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==164); case 165: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==165); case 166: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==166); case 167: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==167); case 168: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==168); case 169: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==169); -{spanBinaryExpr(pParse,yymsp[-1].major,&yymsp[-2].minor.yy342,&yymsp[0].minor.yy342);} +{spanBinaryExpr(pParse,yymsp[-1].major,&yymsp[-2].minor.yy190,&yymsp[0].minor.yy190);} break; case 170: /* likeop ::= LIKE_KW|MATCH */ -{yymsp[0].minor.yy318.eOperator = yymsp[0].minor.yy0; yymsp[0].minor.yy318.bNot = 0;/*A-overwrites-X*/} +{yymsp[0].minor.yy392.eOperator = yymsp[0].minor.yy0; yymsp[0].minor.yy392.bNot = 0;/*A-overwrites-X*/} break; case 171: /* likeop ::= NOT LIKE_KW|MATCH */ -{yymsp[-1].minor.yy318.eOperator = yymsp[0].minor.yy0; yymsp[-1].minor.yy318.bNot = 1;} +{yymsp[-1].minor.yy392.eOperator = yymsp[0].minor.yy0; yymsp[-1].minor.yy392.bNot = 1;} break; case 172: /* expr ::= expr likeop expr */ { ExprList *pList; - pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy342.pExpr); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy342.pExpr); - yymsp[-2].minor.yy342.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy318.eOperator); - exprNot(pParse, yymsp[-1].minor.yy318.bNot, &yymsp[-2].minor.yy342); - yymsp[-2].minor.yy342.zEnd = yymsp[0].minor.yy342.zEnd; - if( yymsp[-2].minor.yy342.pExpr ) yymsp[-2].minor.yy342.pExpr->flags |= EP_InfixFunc; + pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy190.pExpr); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy190.pExpr); + yymsp[-2].minor.yy190.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy392.eOperator); + exprNot(pParse, yymsp[-1].minor.yy392.bNot, &yymsp[-2].minor.yy190); + yymsp[-2].minor.yy190.zEnd = yymsp[0].minor.yy190.zEnd; + if( yymsp[-2].minor.yy190.pExpr ) yymsp[-2].minor.yy190.pExpr->flags |= EP_InfixFunc; } break; case 173: /* expr ::= expr likeop expr ESCAPE expr */ { ExprList *pList; - pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy342.pExpr); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy342.pExpr); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy342.pExpr); - yymsp[-4].minor.yy342.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy318.eOperator); - exprNot(pParse, yymsp[-3].minor.yy318.bNot, &yymsp[-4].minor.yy342); - yymsp[-4].minor.yy342.zEnd = yymsp[0].minor.yy342.zEnd; - if( yymsp[-4].minor.yy342.pExpr ) yymsp[-4].minor.yy342.pExpr->flags |= EP_InfixFunc; + pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy190.pExpr); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy190.pExpr); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy190.pExpr); + yymsp[-4].minor.yy190.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy392.eOperator); + exprNot(pParse, yymsp[-3].minor.yy392.bNot, &yymsp[-4].minor.yy190); + yymsp[-4].minor.yy190.zEnd = yymsp[0].minor.yy190.zEnd; + if( yymsp[-4].minor.yy190.pExpr ) yymsp[-4].minor.yy190.pExpr->flags |= EP_InfixFunc; } break; case 174: /* expr ::= expr ISNULL|NOTNULL */ -{spanUnaryPostfix(pParse,yymsp[0].major,&yymsp[-1].minor.yy342,&yymsp[0].minor.yy0);} +{spanUnaryPostfix(pParse,yymsp[0].major,&yymsp[-1].minor.yy190,&yymsp[0].minor.yy0);} break; case 175: /* expr ::= expr NOT NULL */ -{spanUnaryPostfix(pParse,TK_NOTNULL,&yymsp[-2].minor.yy342,&yymsp[0].minor.yy0);} +{spanUnaryPostfix(pParse,TK_NOTNULL,&yymsp[-2].minor.yy190,&yymsp[0].minor.yy0);} break; case 176: /* expr ::= expr IS expr */ { - spanBinaryExpr(pParse,TK_IS,&yymsp[-2].minor.yy342,&yymsp[0].minor.yy342); - binaryToUnaryIfNull(pParse, yymsp[0].minor.yy342.pExpr, yymsp[-2].minor.yy342.pExpr, TK_ISNULL); + spanBinaryExpr(pParse,TK_IS,&yymsp[-2].minor.yy190,&yymsp[0].minor.yy190); + binaryToUnaryIfNull(pParse, yymsp[0].minor.yy190.pExpr, yymsp[-2].minor.yy190.pExpr, TK_ISNULL); } break; case 177: /* expr ::= expr IS NOT expr */ { - spanBinaryExpr(pParse,TK_ISNOT,&yymsp[-3].minor.yy342,&yymsp[0].minor.yy342); - binaryToUnaryIfNull(pParse, yymsp[0].minor.yy342.pExpr, yymsp[-3].minor.yy342.pExpr, TK_NOTNULL); + spanBinaryExpr(pParse,TK_ISNOT,&yymsp[-3].minor.yy190,&yymsp[0].minor.yy190); + binaryToUnaryIfNull(pParse, yymsp[0].minor.yy190.pExpr, yymsp[-3].minor.yy190.pExpr, TK_NOTNULL); } break; case 178: /* expr ::= NOT expr */ case 179: /* expr ::= BITNOT expr */ yytestcase(yyruleno==179); -{spanUnaryPrefix(&yymsp[-1].minor.yy342,pParse,yymsp[-1].major,&yymsp[0].minor.yy342,&yymsp[-1].minor.yy0);/*A-overwrites-B*/} +{spanUnaryPrefix(&yymsp[-1].minor.yy190,pParse,yymsp[-1].major,&yymsp[0].minor.yy190,&yymsp[-1].minor.yy0);/*A-overwrites-B*/} break; case 180: /* expr ::= MINUS expr */ -{spanUnaryPrefix(&yymsp[-1].minor.yy342,pParse,TK_UMINUS,&yymsp[0].minor.yy342,&yymsp[-1].minor.yy0);/*A-overwrites-B*/} +{spanUnaryPrefix(&yymsp[-1].minor.yy190,pParse,TK_UMINUS,&yymsp[0].minor.yy190,&yymsp[-1].minor.yy0);/*A-overwrites-B*/} break; case 181: /* expr ::= PLUS expr */ -{spanUnaryPrefix(&yymsp[-1].minor.yy342,pParse,TK_UPLUS,&yymsp[0].minor.yy342,&yymsp[-1].minor.yy0);/*A-overwrites-B*/} +{spanUnaryPrefix(&yymsp[-1].minor.yy190,pParse,TK_UPLUS,&yymsp[0].minor.yy190,&yymsp[-1].minor.yy0);/*A-overwrites-B*/} break; case 182: /* between_op ::= BETWEEN */ case 185: /* in_op ::= IN */ yytestcase(yyruleno==185); -{yymsp[0].minor.yy392 = 0;} +{yymsp[0].minor.yy194 = 0;} break; case 184: /* expr ::= expr between_op expr AND expr */ { - ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy342.pExpr); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy342.pExpr); - yymsp[-4].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy342.pExpr, 0, 0); - if( yymsp[-4].minor.yy342.pExpr ){ - yymsp[-4].minor.yy342.pExpr->x.pList = pList; + ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy190.pExpr); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy190.pExpr); + yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy190.pExpr, 0, 0); + if( yymsp[-4].minor.yy190.pExpr ){ + yymsp[-4].minor.yy190.pExpr->x.pList = pList; }else{ sqlite3ExprListDelete(pParse->db, pList); } - exprNot(pParse, yymsp[-3].minor.yy392, &yymsp[-4].minor.yy342); - yymsp[-4].minor.yy342.zEnd = yymsp[0].minor.yy342.zEnd; + exprNot(pParse, yymsp[-3].minor.yy194, &yymsp[-4].minor.yy190); + yymsp[-4].minor.yy190.zEnd = yymsp[0].minor.yy190.zEnd; } break; case 187: /* expr ::= expr in_op LP exprlist RP */ { - if( yymsp[-1].minor.yy442==0 ){ + if( yymsp[-1].minor.yy148==0 ){ /* Expressions of the form ** ** expr1 IN () ** expr1 NOT IN () ** ** simplify to constants 0 (false) and 1 (true), respectively, ** regardless of the value of expr1. */ - sqlite3ExprDelete(pParse->db, yymsp[-4].minor.yy342.pExpr); - yymsp[-4].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[yymsp[-3].minor.yy392]); - }else if( yymsp[-1].minor.yy442->nExpr==1 ){ + sqlite3ExprDelete(pParse->db, yymsp[-4].minor.yy190.pExpr); + yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[yymsp[-3].minor.yy194]); + }else if( yymsp[-1].minor.yy148->nExpr==1 ){ /* Expressions of the form: ** ** expr1 IN (?1) ** expr1 NOT IN (?2) ** @@ -133703,417 +134573,423 @@ ** But, the RHS of the == or <> is marked with the EP_Generic flag ** so that it may not contribute to the computation of comparison ** affinity or the collating sequence to use for comparison. Otherwise, ** the semantics would be subtly different from IN or NOT IN. */ - Expr *pRHS = yymsp[-1].minor.yy442->a[0].pExpr; - yymsp[-1].minor.yy442->a[0].pExpr = 0; - sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy442); + Expr *pRHS = yymsp[-1].minor.yy148->a[0].pExpr; + yymsp[-1].minor.yy148->a[0].pExpr = 0; + sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy148); /* pRHS cannot be NULL because a malloc error would have been detected ** before now and control would have never reached this point */ if( ALWAYS(pRHS) ){ pRHS->flags &= ~EP_Collate; pRHS->flags |= EP_Generic; } - yymsp[-4].minor.yy342.pExpr = sqlite3PExpr(pParse, yymsp[-3].minor.yy392 ? TK_NE : TK_EQ, yymsp[-4].minor.yy342.pExpr, pRHS, 0); - }else{ - yymsp[-4].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy342.pExpr, 0, 0); - if( yymsp[-4].minor.yy342.pExpr ){ - yymsp[-4].minor.yy342.pExpr->x.pList = yymsp[-1].minor.yy442; - sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy342.pExpr); - }else{ - sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy442); - } - exprNot(pParse, yymsp[-3].minor.yy392, &yymsp[-4].minor.yy342); - } - yymsp[-4].minor.yy342.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; + yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, yymsp[-3].minor.yy194 ? TK_NE : TK_EQ, yymsp[-4].minor.yy190.pExpr, pRHS, 0); + }else{ + yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy190.pExpr, 0, 0); + if( yymsp[-4].minor.yy190.pExpr ){ + yymsp[-4].minor.yy190.pExpr->x.pList = yymsp[-1].minor.yy148; + sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy190.pExpr); + }else{ + sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy148); + } + exprNot(pParse, yymsp[-3].minor.yy194, &yymsp[-4].minor.yy190); + } + yymsp[-4].minor.yy190.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; } break; case 188: /* expr ::= LP select RP */ { - spanSet(&yymsp[-2].minor.yy342,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/ - yymsp[-2].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0); - sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy342.pExpr, yymsp[-1].minor.yy159); + spanSet(&yymsp[-2].minor.yy190,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/ + yymsp[-2].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0); + sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy190.pExpr, yymsp[-1].minor.yy243); } break; case 189: /* expr ::= expr in_op LP select RP */ { - yymsp[-4].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy342.pExpr, 0, 0); - sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy342.pExpr, yymsp[-1].minor.yy159); - exprNot(pParse, yymsp[-3].minor.yy392, &yymsp[-4].minor.yy342); - yymsp[-4].minor.yy342.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; - } - break; - case 190: /* expr ::= expr in_op nm dbnm */ -{ - SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0); + yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy190.pExpr, 0, 0); + sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy190.pExpr, yymsp[-1].minor.yy243); + exprNot(pParse, yymsp[-3].minor.yy194, &yymsp[-4].minor.yy190); + yymsp[-4].minor.yy190.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; + } + break; + case 190: /* expr ::= expr in_op nm dbnm paren_exprlist */ +{ + SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0); - yymsp[-3].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-3].minor.yy342.pExpr, 0, 0); - sqlite3PExprAddSelect(pParse, yymsp[-3].minor.yy342.pExpr, pSelect); - exprNot(pParse, yymsp[-2].minor.yy392, &yymsp[-3].minor.yy342); - yymsp[-3].minor.yy342.zEnd = yymsp[0].minor.yy0.z ? &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] : &yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]; + if( yymsp[0].minor.yy148 ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy148); + yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy190.pExpr, 0, 0); + sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy190.pExpr, pSelect); + exprNot(pParse, yymsp[-3].minor.yy194, &yymsp[-4].minor.yy190); + yymsp[-4].minor.yy190.zEnd = yymsp[-1].minor.yy0.z ? &yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n] : &yymsp[-2].minor.yy0.z[yymsp[-2].minor.yy0.n]; } break; case 191: /* expr ::= EXISTS LP select RP */ { Expr *p; - spanSet(&yymsp[-3].minor.yy342,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/ - p = yymsp[-3].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0); - sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy159); + spanSet(&yymsp[-3].minor.yy190,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/ + p = yymsp[-3].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0); + sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy243); } break; case 192: /* expr ::= CASE case_operand case_exprlist case_else END */ { - spanSet(&yymsp[-4].minor.yy342,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-C*/ - yymsp[-4].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy122, 0, 0); - if( yymsp[-4].minor.yy342.pExpr ){ - yymsp[-4].minor.yy342.pExpr->x.pList = yymsp[-1].minor.yy122 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy442,yymsp[-1].minor.yy122) : yymsp[-2].minor.yy442; - sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy342.pExpr); + spanSet(&yymsp[-4].minor.yy190,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-C*/ + yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy72, 0, 0); + if( yymsp[-4].minor.yy190.pExpr ){ + yymsp[-4].minor.yy190.pExpr->x.pList = yymsp[-1].minor.yy72 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy148,yymsp[-1].minor.yy72) : yymsp[-2].minor.yy148; + sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy190.pExpr); }else{ - sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy442); - sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy122); + sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy148); + sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy72); } } break; case 193: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ { - yymsp[-4].minor.yy442 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy442, yymsp[-2].minor.yy342.pExpr); - yymsp[-4].minor.yy442 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy442, yymsp[0].minor.yy342.pExpr); + yymsp[-4].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy148, yymsp[-2].minor.yy190.pExpr); + yymsp[-4].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy148, yymsp[0].minor.yy190.pExpr); } break; case 194: /* case_exprlist ::= WHEN expr THEN expr */ { - yymsp[-3].minor.yy442 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy342.pExpr); - yymsp[-3].minor.yy442 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy442, yymsp[0].minor.yy342.pExpr); + yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy190.pExpr); + yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy148, yymsp[0].minor.yy190.pExpr); } break; case 197: /* case_operand ::= expr */ -{yymsp[0].minor.yy122 = yymsp[0].minor.yy342.pExpr; /*A-overwrites-X*/} +{yymsp[0].minor.yy72 = yymsp[0].minor.yy190.pExpr; /*A-overwrites-X*/} break; case 200: /* nexprlist ::= nexprlist COMMA expr */ -{yymsp[-2].minor.yy442 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy442,yymsp[0].minor.yy342.pExpr);} +{yymsp[-2].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy148,yymsp[0].minor.yy190.pExpr);} break; case 201: /* nexprlist ::= expr */ -{yymsp[0].minor.yy442 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy342.pExpr); /*A-overwrites-Y*/} +{yymsp[0].minor.yy148 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy190.pExpr); /*A-overwrites-Y*/} break; - case 202: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ + case 203: /* paren_exprlist ::= LP exprlist RP */ + case 208: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==208); +{yymsp[-2].minor.yy148 = yymsp[-1].minor.yy148;} + break; + case 204: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ { sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, - sqlite3SrcListAppend(pParse->db,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy442, yymsp[-10].minor.yy392, - &yymsp[-11].minor.yy0, yymsp[0].minor.yy122, SQLITE_SO_ASC, yymsp[-8].minor.yy392); -} - break; - case 203: /* uniqueflag ::= UNIQUE */ - case 244: /* raisetype ::= ABORT */ yytestcase(yyruleno==244); -{yymsp[0].minor.yy392 = OE_Abort;} - break; - case 204: /* uniqueflag ::= */ -{yymsp[1].minor.yy392 = OE_None;} - break; - case 206: /* eidlist_opt ::= LP eidlist RP */ -{yymsp[-2].minor.yy442 = yymsp[-1].minor.yy442;} - break; - case 207: /* eidlist ::= eidlist COMMA nm collate sortorder */ -{ - yymsp[-4].minor.yy442 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy442, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy392, yymsp[0].minor.yy392); -} - break; - case 208: /* eidlist ::= nm collate sortorder */ -{ - yymsp[-2].minor.yy442 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy392, yymsp[0].minor.yy392); /*A-overwrites-Y*/ -} - break; - case 211: /* cmd ::= DROP INDEX ifexists fullname */ -{sqlite3DropIndex(pParse, yymsp[0].minor.yy347, yymsp[-1].minor.yy392);} - break; - case 212: /* cmd ::= VACUUM */ - case 213: /* cmd ::= VACUUM nm */ yytestcase(yyruleno==213); -{sqlite3Vacuum(pParse);} - break; - case 214: /* cmd ::= PRAGMA nm dbnm */ + sqlite3SrcListAppend(pParse->db,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy148, yymsp[-10].minor.yy194, + &yymsp[-11].minor.yy0, yymsp[0].minor.yy72, SQLITE_SO_ASC, yymsp[-8].minor.yy194, SQLITE_IDXTYPE_APPDEF); +} + break; + case 205: /* uniqueflag ::= UNIQUE */ + case 246: /* raisetype ::= ABORT */ yytestcase(yyruleno==246); +{yymsp[0].minor.yy194 = OE_Abort;} + break; + case 206: /* uniqueflag ::= */ +{yymsp[1].minor.yy194 = OE_None;} + break; + case 209: /* eidlist ::= eidlist COMMA nm collate sortorder */ +{ + yymsp[-4].minor.yy148 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy148, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy194, yymsp[0].minor.yy194); +} + break; + case 210: /* eidlist ::= nm collate sortorder */ +{ + yymsp[-2].minor.yy148 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy194, yymsp[0].minor.yy194); /*A-overwrites-Y*/ +} + break; + case 213: /* cmd ::= DROP INDEX ifexists fullname */ +{sqlite3DropIndex(pParse, yymsp[0].minor.yy185, yymsp[-1].minor.yy194);} + break; + case 214: /* cmd ::= VACUUM */ +{sqlite3Vacuum(pParse,0);} + break; + case 215: /* cmd ::= VACUUM nm */ +{sqlite3Vacuum(pParse,&yymsp[0].minor.yy0);} + break; + case 216: /* cmd ::= PRAGMA nm dbnm */ {sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);} break; - case 215: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ + case 217: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);} break; - case 216: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ + case 218: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);} break; - case 217: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ + case 219: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);} break; - case 218: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ + case 220: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,1);} break; - case 221: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ + case 223: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ { Token all; all.z = yymsp[-3].minor.yy0.z; all.n = (int)(yymsp[0].minor.yy0.z - yymsp[-3].minor.yy0.z) + yymsp[0].minor.yy0.n; - sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy327, &all); + sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy145, &all); } break; - case 222: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ + case 224: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ { - sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy392, yymsp[-4].minor.yy410.a, yymsp[-4].minor.yy410.b, yymsp[-2].minor.yy347, yymsp[0].minor.yy122, yymsp[-10].minor.yy392, yymsp[-8].minor.yy392); + sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy194, yymsp[-4].minor.yy332.a, yymsp[-4].minor.yy332.b, yymsp[-2].minor.yy185, yymsp[0].minor.yy72, yymsp[-10].minor.yy194, yymsp[-8].minor.yy194); yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/ } break; - case 223: /* trigger_time ::= BEFORE */ -{ yymsp[0].minor.yy392 = TK_BEFORE; } - break; - case 224: /* trigger_time ::= AFTER */ -{ yymsp[0].minor.yy392 = TK_AFTER; } - break; - case 225: /* trigger_time ::= INSTEAD OF */ -{ yymsp[-1].minor.yy392 = TK_INSTEAD;} - break; - case 226: /* trigger_time ::= */ -{ yymsp[1].minor.yy392 = TK_BEFORE; } - break; - case 227: /* trigger_event ::= DELETE|INSERT */ - case 228: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==228); -{yymsp[0].minor.yy410.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy410.b = 0;} - break; - case 229: /* trigger_event ::= UPDATE OF idlist */ -{yymsp[-2].minor.yy410.a = TK_UPDATE; yymsp[-2].minor.yy410.b = yymsp[0].minor.yy180;} - break; - case 230: /* when_clause ::= */ - case 249: /* key_opt ::= */ yytestcase(yyruleno==249); -{ yymsp[1].minor.yy122 = 0; } - break; - case 231: /* when_clause ::= WHEN expr */ - case 250: /* key_opt ::= KEY expr */ yytestcase(yyruleno==250); -{ yymsp[-1].minor.yy122 = yymsp[0].minor.yy342.pExpr; } - break; - case 232: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ -{ - assert( yymsp[-2].minor.yy327!=0 ); - yymsp[-2].minor.yy327->pLast->pNext = yymsp[-1].minor.yy327; - yymsp[-2].minor.yy327->pLast = yymsp[-1].minor.yy327; -} - break; - case 233: /* trigger_cmd_list ::= trigger_cmd SEMI */ -{ - assert( yymsp[-1].minor.yy327!=0 ); - yymsp[-1].minor.yy327->pLast = yymsp[-1].minor.yy327; -} - break; - case 234: /* trnm ::= nm DOT nm */ + case 225: /* trigger_time ::= BEFORE */ +{ yymsp[0].minor.yy194 = TK_BEFORE; } + break; + case 226: /* trigger_time ::= AFTER */ +{ yymsp[0].minor.yy194 = TK_AFTER; } + break; + case 227: /* trigger_time ::= INSTEAD OF */ +{ yymsp[-1].minor.yy194 = TK_INSTEAD;} + break; + case 228: /* trigger_time ::= */ +{ yymsp[1].minor.yy194 = TK_BEFORE; } + break; + case 229: /* trigger_event ::= DELETE|INSERT */ + case 230: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==230); +{yymsp[0].minor.yy332.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy332.b = 0;} + break; + case 231: /* trigger_event ::= UPDATE OF idlist */ +{yymsp[-2].minor.yy332.a = TK_UPDATE; yymsp[-2].minor.yy332.b = yymsp[0].minor.yy254;} + break; + case 232: /* when_clause ::= */ + case 251: /* key_opt ::= */ yytestcase(yyruleno==251); +{ yymsp[1].minor.yy72 = 0; } + break; + case 233: /* when_clause ::= WHEN expr */ + case 252: /* key_opt ::= KEY expr */ yytestcase(yyruleno==252); +{ yymsp[-1].minor.yy72 = yymsp[0].minor.yy190.pExpr; } + break; + case 234: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ +{ + assert( yymsp[-2].minor.yy145!=0 ); + yymsp[-2].minor.yy145->pLast->pNext = yymsp[-1].minor.yy145; + yymsp[-2].minor.yy145->pLast = yymsp[-1].minor.yy145; +} + break; + case 235: /* trigger_cmd_list ::= trigger_cmd SEMI */ +{ + assert( yymsp[-1].minor.yy145!=0 ); + yymsp[-1].minor.yy145->pLast = yymsp[-1].minor.yy145; +} + break; + case 236: /* trnm ::= nm DOT nm */ { yymsp[-2].minor.yy0 = yymsp[0].minor.yy0; sqlite3ErrorMsg(pParse, "qualified table names are not allowed on INSERT, UPDATE, and DELETE " "statements within triggers"); } break; - case 235: /* tridxby ::= INDEXED BY nm */ + case 237: /* tridxby ::= INDEXED BY nm */ { sqlite3ErrorMsg(pParse, "the INDEXED BY clause is not allowed on UPDATE or DELETE statements " "within triggers"); } break; - case 236: /* tridxby ::= NOT INDEXED */ + case 238: /* tridxby ::= NOT INDEXED */ { sqlite3ErrorMsg(pParse, "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements " "within triggers"); } break; - case 237: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt */ -{yymsp[-6].minor.yy327 = sqlite3TriggerUpdateStep(pParse->db, &yymsp[-4].minor.yy0, yymsp[-1].minor.yy442, yymsp[0].minor.yy122, yymsp[-5].minor.yy392);} - break; - case 238: /* trigger_cmd ::= insert_cmd INTO trnm idlist_opt select */ -{yymsp[-4].minor.yy327 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy180, yymsp[0].minor.yy159, yymsp[-4].minor.yy392);/*A-overwrites-R*/} - break; - case 239: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt */ -{yymsp[-4].minor.yy327 = sqlite3TriggerDeleteStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[0].minor.yy122);} - break; - case 240: /* trigger_cmd ::= select */ -{yymsp[0].minor.yy327 = sqlite3TriggerSelectStep(pParse->db, yymsp[0].minor.yy159); /*A-overwrites-X*/} - break; - case 241: /* expr ::= RAISE LP IGNORE RP */ -{ - spanSet(&yymsp[-3].minor.yy342,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ - yymsp[-3].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, 0); - if( yymsp[-3].minor.yy342.pExpr ){ - yymsp[-3].minor.yy342.pExpr->affinity = OE_Ignore; - } -} - break; - case 242: /* expr ::= RAISE LP raisetype COMMA nm RP */ -{ - spanSet(&yymsp[-5].minor.yy342,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ - yymsp[-5].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, &yymsp[-1].minor.yy0); - if( yymsp[-5].minor.yy342.pExpr ) { - yymsp[-5].minor.yy342.pExpr->affinity = (char)yymsp[-3].minor.yy392; - } -} - break; - case 243: /* raisetype ::= ROLLBACK */ -{yymsp[0].minor.yy392 = OE_Rollback;} - break; - case 245: /* raisetype ::= FAIL */ -{yymsp[0].minor.yy392 = OE_Fail;} - break; - case 246: /* cmd ::= DROP TRIGGER ifexists fullname */ -{ - sqlite3DropTrigger(pParse,yymsp[0].minor.yy347,yymsp[-1].minor.yy392); -} - break; - case 247: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ -{ - sqlite3Attach(pParse, yymsp[-3].minor.yy342.pExpr, yymsp[-1].minor.yy342.pExpr, yymsp[0].minor.yy122); -} - break; - case 248: /* cmd ::= DETACH database_kw_opt expr */ -{ - sqlite3Detach(pParse, yymsp[0].minor.yy342.pExpr); -} - break; - case 251: /* cmd ::= REINDEX */ + case 239: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt */ +{yymsp[-6].minor.yy145 = sqlite3TriggerUpdateStep(pParse->db, &yymsp[-4].minor.yy0, yymsp[-1].minor.yy148, yymsp[0].minor.yy72, yymsp[-5].minor.yy194);} + break; + case 240: /* trigger_cmd ::= insert_cmd INTO trnm idlist_opt select */ +{yymsp[-4].minor.yy145 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy254, yymsp[0].minor.yy243, yymsp[-4].minor.yy194);/*A-overwrites-R*/} + break; + case 241: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt */ +{yymsp[-4].minor.yy145 = sqlite3TriggerDeleteStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[0].minor.yy72);} + break; + case 242: /* trigger_cmd ::= select */ +{yymsp[0].minor.yy145 = sqlite3TriggerSelectStep(pParse->db, yymsp[0].minor.yy243); /*A-overwrites-X*/} + break; + case 243: /* expr ::= RAISE LP IGNORE RP */ +{ + spanSet(&yymsp[-3].minor.yy190,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ + yymsp[-3].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, 0); + if( yymsp[-3].minor.yy190.pExpr ){ + yymsp[-3].minor.yy190.pExpr->affinity = OE_Ignore; + } +} + break; + case 244: /* expr ::= RAISE LP raisetype COMMA nm RP */ +{ + spanSet(&yymsp[-5].minor.yy190,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ + yymsp[-5].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, &yymsp[-1].minor.yy0); + if( yymsp[-5].minor.yy190.pExpr ) { + yymsp[-5].minor.yy190.pExpr->affinity = (char)yymsp[-3].minor.yy194; + } +} + break; + case 245: /* raisetype ::= ROLLBACK */ +{yymsp[0].minor.yy194 = OE_Rollback;} + break; + case 247: /* raisetype ::= FAIL */ +{yymsp[0].minor.yy194 = OE_Fail;} + break; + case 248: /* cmd ::= DROP TRIGGER ifexists fullname */ +{ + sqlite3DropTrigger(pParse,yymsp[0].minor.yy185,yymsp[-1].minor.yy194); +} + break; + case 249: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ +{ + sqlite3Attach(pParse, yymsp[-3].minor.yy190.pExpr, yymsp[-1].minor.yy190.pExpr, yymsp[0].minor.yy72); +} + break; + case 250: /* cmd ::= DETACH database_kw_opt expr */ +{ + sqlite3Detach(pParse, yymsp[0].minor.yy190.pExpr); +} + break; + case 253: /* cmd ::= REINDEX */ {sqlite3Reindex(pParse, 0, 0);} break; - case 252: /* cmd ::= REINDEX nm dbnm */ + case 254: /* cmd ::= REINDEX nm dbnm */ {sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} break; - case 253: /* cmd ::= ANALYZE */ + case 255: /* cmd ::= ANALYZE */ {sqlite3Analyze(pParse, 0, 0);} break; - case 254: /* cmd ::= ANALYZE nm dbnm */ + case 256: /* cmd ::= ANALYZE nm dbnm */ {sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} break; - case 255: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ + case 257: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ { - sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy347,&yymsp[0].minor.yy0); + sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy185,&yymsp[0].minor.yy0); } break; - case 256: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ + case 258: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ { yymsp[-1].minor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-1].minor.yy0.z) + pParse->sLastToken.n; sqlite3AlterFinishAddColumn(pParse, &yymsp[-1].minor.yy0); } break; - case 257: /* add_column_fullname ::= fullname */ + case 259: /* add_column_fullname ::= fullname */ { disableLookaside(pParse); - sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy347); + sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy185); } break; - case 258: /* cmd ::= create_vtab */ + case 260: /* cmd ::= create_vtab */ {sqlite3VtabFinishParse(pParse,0);} break; - case 259: /* cmd ::= create_vtab LP vtabarglist RP */ + case 261: /* cmd ::= create_vtab LP vtabarglist RP */ {sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);} break; - case 260: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + case 262: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ { - sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy392); + sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy194); } break; - case 261: /* vtabarg ::= */ + case 263: /* vtabarg ::= */ {sqlite3VtabArgInit(pParse);} break; - case 262: /* vtabargtoken ::= ANY */ - case 263: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==263); - case 264: /* lp ::= LP */ yytestcase(yyruleno==264); + case 264: /* vtabargtoken ::= ANY */ + case 265: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==265); + case 266: /* lp ::= LP */ yytestcase(yyruleno==266); {sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);} break; - case 265: /* with ::= */ -{yymsp[1].minor.yy331 = 0;} - break; - case 266: /* with ::= WITH wqlist */ -{ yymsp[-1].minor.yy331 = yymsp[0].minor.yy331; } - break; - case 267: /* with ::= WITH RECURSIVE wqlist */ -{ yymsp[-2].minor.yy331 = yymsp[0].minor.yy331; } - break; - case 268: /* wqlist ::= nm eidlist_opt AS LP select RP */ -{ - yymsp[-5].minor.yy331 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy442, yymsp[-1].minor.yy159); /*A-overwrites-X*/ -} - break; - case 269: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */ -{ - yymsp[-7].minor.yy331 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy331, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy442, yymsp[-1].minor.yy159); + case 267: /* with ::= */ +{yymsp[1].minor.yy285 = 0;} + break; + case 268: /* with ::= WITH wqlist */ +{ yymsp[-1].minor.yy285 = yymsp[0].minor.yy285; } + break; + case 269: /* with ::= WITH RECURSIVE wqlist */ +{ yymsp[-2].minor.yy285 = yymsp[0].minor.yy285; } + break; + case 270: /* wqlist ::= nm eidlist_opt AS LP select RP */ +{ + yymsp[-5].minor.yy285 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy148, yymsp[-1].minor.yy243); /*A-overwrites-X*/ +} + break; + case 271: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */ +{ + yymsp[-7].minor.yy285 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy285, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy148, yymsp[-1].minor.yy243); } break; default: - /* (270) input ::= cmdlist */ yytestcase(yyruleno==270); - /* (271) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==271); - /* (272) cmdlist ::= ecmd */ yytestcase(yyruleno==272); - /* (273) ecmd ::= SEMI */ yytestcase(yyruleno==273); - /* (274) ecmd ::= explain cmdx SEMI */ yytestcase(yyruleno==274); - /* (275) explain ::= */ yytestcase(yyruleno==275); - /* (276) trans_opt ::= */ yytestcase(yyruleno==276); - /* (277) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==277); - /* (278) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==278); - /* (279) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==279); - /* (280) savepoint_opt ::= */ yytestcase(yyruleno==280); - /* (281) cmd ::= create_table create_table_args */ yytestcase(yyruleno==281); - /* (282) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==282); - /* (283) columnlist ::= columnname carglist */ yytestcase(yyruleno==283); - /* (284) nm ::= ID|INDEXED */ yytestcase(yyruleno==284); - /* (285) nm ::= STRING */ yytestcase(yyruleno==285); - /* (286) nm ::= JOIN_KW */ yytestcase(yyruleno==286); - /* (287) typetoken ::= typename */ yytestcase(yyruleno==287); - /* (288) typename ::= ID|STRING */ yytestcase(yyruleno==288); - /* (289) signed ::= plus_num */ yytestcase(yyruleno==289); - /* (290) signed ::= minus_num */ yytestcase(yyruleno==290); - /* (291) carglist ::= carglist ccons */ yytestcase(yyruleno==291); - /* (292) carglist ::= */ yytestcase(yyruleno==292); - /* (293) ccons ::= NULL onconf */ yytestcase(yyruleno==293); - /* (294) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==294); - /* (295) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==295); - /* (296) conslist ::= tcons */ yytestcase(yyruleno==296); - /* (297) tconscomma ::= */ yytestcase(yyruleno==297); - /* (298) defer_subclause_opt ::= defer_subclause */ yytestcase(yyruleno==298); - /* (299) resolvetype ::= raisetype */ yytestcase(yyruleno==299); - /* (300) selectnowith ::= oneselect */ yytestcase(yyruleno==300); - /* (301) oneselect ::= values */ yytestcase(yyruleno==301); - /* (302) sclp ::= selcollist COMMA */ yytestcase(yyruleno==302); - /* (303) as ::= ID|STRING */ yytestcase(yyruleno==303); - /* (304) expr ::= term */ yytestcase(yyruleno==304); - /* (305) exprlist ::= nexprlist */ yytestcase(yyruleno==305); - /* (306) nmnum ::= plus_num */ yytestcase(yyruleno==306); - /* (307) nmnum ::= nm */ yytestcase(yyruleno==307); - /* (308) nmnum ::= ON */ yytestcase(yyruleno==308); - /* (309) nmnum ::= DELETE */ yytestcase(yyruleno==309); - /* (310) nmnum ::= DEFAULT */ yytestcase(yyruleno==310); - /* (311) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==311); - /* (312) foreach_clause ::= */ yytestcase(yyruleno==312); - /* (313) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==313); - /* (314) trnm ::= nm */ yytestcase(yyruleno==314); - /* (315) tridxby ::= */ yytestcase(yyruleno==315); - /* (316) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==316); - /* (317) database_kw_opt ::= */ yytestcase(yyruleno==317); - /* (318) kwcolumn_opt ::= */ yytestcase(yyruleno==318); - /* (319) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==319); - /* (320) vtabarglist ::= vtabarg */ yytestcase(yyruleno==320); - /* (321) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==321); - /* (322) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==322); - /* (323) anylist ::= */ yytestcase(yyruleno==323); - /* (324) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==324); - /* (325) anylist ::= anylist ANY */ yytestcase(yyruleno==325); + /* (272) input ::= cmdlist */ yytestcase(yyruleno==272); + /* (273) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==273); + /* (274) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=274); + /* (275) ecmd ::= SEMI */ yytestcase(yyruleno==275); + /* (276) ecmd ::= explain cmdx SEMI */ yytestcase(yyruleno==276); + /* (277) explain ::= */ yytestcase(yyruleno==277); + /* (278) trans_opt ::= */ yytestcase(yyruleno==278); + /* (279) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==279); + /* (280) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==280); + /* (281) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==281); + /* (282) savepoint_opt ::= */ yytestcase(yyruleno==282); + /* (283) cmd ::= create_table create_table_args */ yytestcase(yyruleno==283); + /* (284) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==284); + /* (285) columnlist ::= columnname carglist */ yytestcase(yyruleno==285); + /* (286) nm ::= ID|INDEXED */ yytestcase(yyruleno==286); + /* (287) nm ::= STRING */ yytestcase(yyruleno==287); + /* (288) nm ::= JOIN_KW */ yytestcase(yyruleno==288); + /* (289) typetoken ::= typename */ yytestcase(yyruleno==289); + /* (290) typename ::= ID|STRING */ yytestcase(yyruleno==290); + /* (291) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=291); + /* (292) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=292); + /* (293) carglist ::= carglist ccons */ yytestcase(yyruleno==293); + /* (294) carglist ::= */ yytestcase(yyruleno==294); + /* (295) ccons ::= NULL onconf */ yytestcase(yyruleno==295); + /* (296) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==296); + /* (297) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==297); + /* (298) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=298); + /* (299) tconscomma ::= */ yytestcase(yyruleno==299); + /* (300) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=300); + /* (301) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=301); + /* (302) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=302); + /* (303) oneselect ::= values */ yytestcase(yyruleno==303); + /* (304) sclp ::= selcollist COMMA */ yytestcase(yyruleno==304); + /* (305) as ::= ID|STRING */ yytestcase(yyruleno==305); + /* (306) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=306); + /* (307) exprlist ::= nexprlist */ yytestcase(yyruleno==307); + /* (308) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=308); + /* (309) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=309); + /* (310) nmnum ::= ON */ yytestcase(yyruleno==310); + /* (311) nmnum ::= DELETE */ yytestcase(yyruleno==311); + /* (312) nmnum ::= DEFAULT */ yytestcase(yyruleno==312); + /* (313) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==313); + /* (314) foreach_clause ::= */ yytestcase(yyruleno==314); + /* (315) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==315); + /* (316) trnm ::= nm */ yytestcase(yyruleno==316); + /* (317) tridxby ::= */ yytestcase(yyruleno==317); + /* (318) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==318); + /* (319) database_kw_opt ::= */ yytestcase(yyruleno==319); + /* (320) kwcolumn_opt ::= */ yytestcase(yyruleno==320); + /* (321) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==321); + /* (322) vtabarglist ::= vtabarg */ yytestcase(yyruleno==322); + /* (323) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==323); + /* (324) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==324); + /* (325) anylist ::= */ yytestcase(yyruleno==325); + /* (326) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==326); + /* (327) anylist ::= anylist ANY */ yytestcase(yyruleno==327); break; /********** End reduce actions ************************************************/ }; assert( yyrulenoYY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; - yypParser->yyidx -= yysize - 1; + if( yyact>YY_MAX_SHIFT ){ + yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; + } yymsp -= yysize-1; + yypParser->yytos = yymsp; yymsp->stateno = (YYACTIONTYPE)yyact; yymsp->major = (YYCODETYPE)yygoto; yyTraceShift(yypParser, yyact); }else{ assert( yyact == YY_ACCEPT_ACTION ); - yypParser->yyidx -= yysize; + yypParser->yytos -= yysize; yy_accept(yypParser); } } /* @@ -134127,11 +135003,11 @@ #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt); } #endif - while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); + while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser); /* Here code is inserted which will be executed whenever the ** parser fails */ /************ Begin %parse_failure code ***************************************/ /************ End %parse_failure code *****************************************/ sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ @@ -134167,11 +135043,14 @@ #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt); } #endif - while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); +#ifndef YYNOERRORRECOVERY + yypParser->yyerrcnt = -1; +#endif + assert( yypParser->yytos==yypParser->yystack ); /* Here code is inserted which will be executed whenever the ** parser accepts */ /*********** Begin %parse_accept code *****************************************/ /*********** End %parse_accept code *******************************************/ sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ @@ -134210,32 +135089,12 @@ #ifdef YYERRORSYMBOL int yyerrorhit = 0; /* True if yymajor has invoked an error */ #endif yyParser *yypParser; /* The parser */ - /* (re)initialize the parser, if necessary */ yypParser = (yyParser*)yyp; - if( yypParser->yyidx<0 ){ -#if YYSTACKDEPTH<=0 - if( yypParser->yystksz <=0 ){ - yyStackOverflow(yypParser); - return; - } -#endif - yypParser->yyidx = 0; -#ifndef YYNOERRORRECOVERY - yypParser->yyerrcnt = -1; -#endif - yypParser->yystack[0].stateno = 0; - yypParser->yystack[0].major = 0; -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sInitialize. Empty stack. State 0\n", - yyTracePrompt); - } -#endif - } + assert( yypParser->yytos!=0 ); #if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) yyendofinput = (yymajor==0); #endif sqlite3ParserARG_STORE; @@ -134246,11 +135105,10 @@ #endif do{ yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor); if( yyact <= YY_MAX_SHIFTREDUCE ){ - if( yyact > YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; yy_shift(yypParser,yyact,yymajor,yyminor); #ifndef YYNOERRORRECOVERY yypParser->yyerrcnt--; #endif yymajor = YYNOCODE; @@ -134288,11 +135146,11 @@ ** */ if( yypParser->yyerrcnt<0 ){ yy_syntax_error(yypParser,yymajor,yyminor); } - yymx = yypParser->yystack[yypParser->yyidx].major; + yymx = yypParser->yytos->major; if( yymx==YYERRORSYMBOL || yyerrorhit ){ #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sDiscard input token %s\n", yyTracePrompt,yyTokenName[yymajor]); @@ -134299,22 +135157,24 @@ } #endif yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion); yymajor = YYNOCODE; }else{ - while( - yypParser->yyidx >= 0 && - yymx != YYERRORSYMBOL && - (yyact = yy_find_reduce_action( - yypParser->yystack[yypParser->yyidx].stateno, + while( yypParser->yytos >= &yypParser->yystack + && yymx != YYERRORSYMBOL + && (yyact = yy_find_reduce_action( + yypParser->yytos->stateno, YYERRORSYMBOL)) >= YY_MIN_REDUCE ){ yy_pop_parser_stack(yypParser); } - if( yypParser->yyidx < 0 || yymajor==0 ){ + if( yypParser->yytos < yypParser->yystack || yymajor==0 ){ yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); yy_parse_failed(yypParser); +#ifndef YYNOERRORRECOVERY + yypParser->yyerrcnt = -1; +#endif yymajor = YYNOCODE; }else if( yymx!=YYERRORSYMBOL ){ yy_shift(yypParser,yyact,YYERRORSYMBOL,yyminor); } } @@ -134347,22 +135207,27 @@ } yypParser->yyerrcnt = 3; yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); if( yyendofinput ){ yy_parse_failed(yypParser); +#ifndef YYNOERRORRECOVERY + yypParser->yyerrcnt = -1; +#endif } yymajor = YYNOCODE; #endif } - }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 ); + }while( yymajor!=YYNOCODE && yypParser->yytos>yypParser->yystack ); #ifndef NDEBUG if( yyTraceFILE ){ - int i; + yyStackEntry *i; + char cDiv = '['; fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt); - for(i=1; i<=yypParser->yyidx; i++) - fprintf(yyTraceFILE,"%c%s", i==1 ? '[' : ' ', - yyTokenName[yypParser->yystack[i].major]); + for(i=&yypParser->yystack[1]; i<=yypParser->yytos; i++){ + fprintf(yyTraceFILE,"%c%s", cDiv, yyTokenName[i->major]); + cDiv = ' '; + } fprintf(yyTraceFILE,"]\n"); } #endif return; } @@ -135160,18 +136025,30 @@ assert( pParse->pNewTable==0 ); assert( pParse->pNewTrigger==0 ); assert( pParse->nVar==0 ); assert( pParse->nzVar==0 ); assert( pParse->azVar==0 ); - while( zSql[i]!=0 ){ + while( 1 ){ assert( i>=0 ); - pParse->sLastToken.z = &zSql[i]; - pParse->sLastToken.n = sqlite3GetToken((unsigned char*)&zSql[i],&tokenType); - i += pParse->sLastToken.n; - if( i>mxSqlLen ){ - pParse->rc = SQLITE_TOOBIG; - break; + if( zSql[i]!=0 ){ + pParse->sLastToken.z = &zSql[i]; + pParse->sLastToken.n = sqlite3GetToken((u8*)&zSql[i],&tokenType); + i += pParse->sLastToken.n; + if( i>mxSqlLen ){ + pParse->rc = SQLITE_TOOBIG; + break; + } + }else{ + /* Upon reaching the end of input, call the parser two more times + ** with tokens TK_SEMI and 0, in that order. */ + if( lastTokenParsed==TK_SEMI ){ + tokenType = 0; + }else if( lastTokenParsed==0 ){ + break; + }else{ + tokenType = TK_SEMI; + } } if( tokenType>=TK_SPACE ){ assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL ); if( db->u1.isInterrupted ){ pParse->rc = SQLITE_INTERRUPT; @@ -135188,19 +136065,10 @@ if( pParse->rc!=SQLITE_OK || db->mallocFailed ) break; } } assert( nErr==0 ); pParse->zTail = &zSql[i]; - if( pParse->rc==SQLITE_OK && db->mallocFailed==0 ){ - assert( zSql[i]==0 ); - if( lastTokenParsed!=TK_SEMI ){ - sqlite3Parser(pEngine, TK_SEMI, pParse->sLastToken, pParse); - } - if( pParse->rc==SQLITE_OK && db->mallocFailed==0 ){ - sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse); - } - } #ifdef YYTRACKMAXSTACKDEPTH sqlite3_mutex_enter(sqlite3MallocMutex()); sqlite3StatusHighwater(SQLITE_STATUS_PARSER_STACK, sqlite3ParserStackPeak(pEngine) ); @@ -136436,10 +137304,15 @@ SQLITE_API int SQLITE_CDECL sqlite3_db_config(sqlite3 *db, int op, ...){ va_list ap; int rc; va_start(ap, op); switch( op ){ + case SQLITE_DBCONFIG_MAINDBNAME: { + db->aDb[0].zDbSName = va_arg(ap,char*); + rc = SQLITE_OK; + break; + } case SQLITE_DBCONFIG_LOOKASIDE: { void *pBuf = va_arg(ap, void*); /* IMP: R-26835-10964 */ int sz = va_arg(ap, int); /* IMP: R-47871-25994 */ int cnt = va_arg(ap, int); /* IMP: R-04460-53386 */ rc = setupLookaside(db, pBuf, sz, cnt); @@ -136680,10 +137553,13 @@ } if( !sqlite3SafetyCheckSickOrOk(db) ){ return SQLITE_MISUSE_BKPT; } sqlite3_mutex_enter(db->mutex); + if( db->mTrace & SQLITE_TRACE_CLOSE ){ + db->xTrace(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0); + } /* Force xDisconnect calls on all virtual tables */ disconnectAllVtab(db); /* If a transaction is open, the disconnectAllVtab() call above @@ -137448,11 +138324,12 @@ ** ** A NULL trace function means that no tracing is executes. A non-NULL ** trace is a pointer to a function that is invoked at the start of each ** SQL statement. */ -SQLITE_API void *SQLITE_STDCALL sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){ +#ifndef SQLITE_OMIT_DEPRECATED +SQLITE_API void *SQLITE_STDCALL sqlite3_trace(sqlite3 *db, void(*xTrace)(void*,const char*), void *pArg){ void *pOld; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; @@ -137459,15 +138336,40 @@ return 0; } #endif sqlite3_mutex_enter(db->mutex); pOld = db->pTraceArg; - db->xTrace = xTrace; + db->mTrace = xTrace ? SQLITE_TRACE_LEGACY : 0; + db->xTrace = (int(*)(u32,void*,void*,void*))xTrace; db->pTraceArg = pArg; sqlite3_mutex_leave(db->mutex); return pOld; } +#endif /* SQLITE_OMIT_DEPRECATED */ + +/* Register a trace callback using the version-2 interface. +*/ +SQLITE_API int SQLITE_STDCALL sqlite3_trace_v2( + sqlite3 *db, /* Trace this connection */ + unsigned mTrace, /* Mask of events to be traced */ + int(*xTrace)(unsigned,void*,void*,void*), /* Callback to invoke */ + void *pArg /* Context */ +){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + return SQLITE_MISUSE_BKPT; + } +#endif + sqlite3_mutex_enter(db->mutex); + db->mTrace = mTrace; + db->xTrace = xTrace; + db->pTraceArg = pArg; + sqlite3_mutex_leave(db->mutex); + return SQLITE_OK; +} + +#ifndef SQLITE_OMIT_DEPRECATED /* ** Register a profile function. The pArg from the previously registered ** profile function is returned. ** ** A NULL profile function means that no profiling is executes. A non-NULL @@ -137492,10 +138394,11 @@ db->xProfile = xProfile; db->pProfileArg = pArg; sqlite3_mutex_leave(db->mutex); return pOld; } +#endif /* SQLITE_OMIT_DEPRECATED */ #endif /* SQLITE_OMIT_TRACE */ /* ** Register a function to be invoked when a transaction commits. ** If the invoked function returns non-zero, then the commit becomes a @@ -138549,13 +139452,13 @@ db->aDb[1].pSchema = sqlite3SchemaGet(db, 0); /* The default safety_level for the main database is FULL; for the temp ** database it is OFF. This matches the pager layer defaults. */ - db->aDb[0].zName = "main"; + db->aDb[0].zDbSName = "main"; db->aDb[0].safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1; - db->aDb[1].zName = "temp"; + db->aDb[1].zDbSName = "temp"; db->aDb[1].safety_level = PAGER_SYNCHRONOUS_OFF; db->magic = SQLITE_MAGIC_OPEN; if( db->mallocFailed ){ goto opendb_out; @@ -139512,11 +140415,11 @@ */ SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){ int i; for(i=0; inDb; i++){ if( db->aDb[i].pBt - && (zDbName==0 || sqlite3StrICmp(zDbName, db->aDb[i].zName)==0) + && (zDbName==0 || sqlite3StrICmp(zDbName, db->aDb[i].zDbSName)==0) ){ return db->aDb[i].pBt; } } return 0; @@ -149942,11 +150845,15 @@ } #ifdef SQLITE_TEST -#include +#if defined(INCLUDE_SQLITE_TCL_H) +# include "sqlite_tcl.h" +#else +# include "tcl.h" +#endif /* #include */ /* ** Implementation of a special SQL scalar function for testing tokenizers ** designed to be used in concert with the Tcl testing framework. This @@ -161881,10 +162788,57 @@ } return f; } #endif /* !defined(SQLITE_RTREE_INT_ONLY) */ +/* +** A constraint has failed while inserting a row into an rtree table. +** Assuming no OOM error occurs, this function sets the error message +** (at pRtree->base.zErrMsg) to an appropriate value and returns +** SQLITE_CONSTRAINT. +** +** Parameter iCol is the index of the leftmost column involved in the +** constraint failure. If it is 0, then the constraint that failed is +** the unique constraint on the id column. Otherwise, it is the rtree +** (c1<=c2) constraint on columns iCol and iCol+1 that has failed. +** +** If an OOM occurs, SQLITE_NOMEM is returned instead of SQLITE_CONSTRAINT. +*/ +static int rtreeConstraintError(Rtree *pRtree, int iCol){ + sqlite3_stmt *pStmt = 0; + char *zSql; + int rc; + + assert( iCol==0 || iCol%2 ); + zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", pRtree->zDb, pRtree->zName); + if( zSql ){ + rc = sqlite3_prepare_v2(pRtree->db, zSql, -1, &pStmt, 0); + }else{ + rc = SQLITE_NOMEM; + } + sqlite3_free(zSql); + + if( rc==SQLITE_OK ){ + if( iCol==0 ){ + const char *zCol = sqlite3_column_name(pStmt, 0); + pRtree->base.zErrMsg = sqlite3_mprintf( + "UNIQUE constraint failed: %s.%s", pRtree->zName, zCol + ); + }else{ + const char *zCol1 = sqlite3_column_name(pStmt, iCol); + const char *zCol2 = sqlite3_column_name(pStmt, iCol+1); + pRtree->base.zErrMsg = sqlite3_mprintf( + "rtree constraint failed: %s.(%s<=%s)", pRtree->zName, zCol1, zCol2 + ); + } + } + + sqlite3_finalize(pStmt); + return (rc==SQLITE_OK ? SQLITE_CONSTRAINT : rc); +} + + /* ** The xUpdate method for rtree module virtual tables. */ static int rtreeUpdate( @@ -161931,11 +162885,11 @@ if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ for(ii=0; iicell.aCoord[ii+1].f ){ - rc = SQLITE_CONSTRAINT; + rc = rtreeConstraintError(pRtree, ii+1); goto constraint; } } }else #endif @@ -161942,11 +162896,11 @@ { for(ii=0; iicell.aCoord[ii+1].i ){ - rc = SQLITE_CONSTRAINT; + rc = rtreeConstraintError(pRtree, ii+1); goto constraint; } } } @@ -161963,11 +162917,11 @@ rc = sqlite3_reset(pRtree->pReadRowid); if( SQLITE_ROW==steprc ){ if( sqlite3_vtab_on_conflict(pRtree->db)==SQLITE_REPLACE ){ rc = rtreeDeleteRowid(pRtree, cell.iRowid); }else{ - rc = SQLITE_CONSTRAINT; + rc = rtreeConstraintError(pRtree, 0); goto constraint; } } } bHaveRowid = 1; @@ -162046,10 +163000,15 @@ char *zSql; sqlite3_stmt *p; int rc; i64 nRow = 0; + if( sqlite3_table_column_metadata(db,pRtree->zDb,"sqlite_stat1", + 0,0,0,0,0,0)==SQLITE_ERROR ){ + pRtree->nRowEst = RTREE_DEFAULT_ROWEST; + return SQLITE_OK; + } zSql = sqlite3_mprintf(zFmt, pRtree->zDb, pRtree->zName); if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_prepare_v2(db, zSql, -1, &p, 0); @@ -163822,19 +164781,25 @@ /* ** Open an RBU handle to perform an RBU vacuum on database file zTarget. ** An RBU vacuum is similar to SQLite's built-in VACUUM command, except ** that it can be suspended and resumed like an RBU update. ** -** The second argument to this function, which may not be NULL, identifies -** a database in which to store the state of the RBU vacuum operation if -** it is suspended. The first time sqlite3rbu_vacuum() is called, to start -** an RBU vacuum operation, the state database should either not exist or -** be empty (contain no tables). If an RBU vacuum is suspended by calling +** The second argument to this function identifies a database in which +** to store the state of the RBU vacuum operation if it is suspended. The +** first time sqlite3rbu_vacuum() is called, to start an RBU vacuum +** operation, the state database should either not exist or be empty +** (contain no tables). If an RBU vacuum is suspended by calling ** sqlite3rbu_close() on the RBU handle before sqlite3rbu_step() has ** returned SQLITE_DONE, the vacuum state is stored in the state database. ** The vacuum can be resumed by calling this function to open a new RBU ** handle specifying the same target and state databases. +** +** If the second argument passed to this function is NULL, then the +** name of the state database is "-vacuum", where +** is the name of the target database file. In this case, on UNIX, if the +** state database is not already present in the file-system, it is created +** with the same permissions as the target db is made. ** ** This function does not delete the state database after an RBU vacuum ** is completed, even if it created it. However, if the call to ** sqlite3rbu_close() returns any value other than SQLITE_OK, the contents ** of the state tables within the state database are zeroed. This way, @@ -163977,10 +164942,48 @@ ** table exists but is not correctly populated, the value of the *pnOne ** output variable during stage 1 is undefined. */ SQLITE_API void SQLITE_STDCALL sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int *pnTwo); +/* +** Obtain an indication as to the current stage of an RBU update or vacuum. +** This function always returns one of the SQLITE_RBU_STATE_XXX constants +** defined in this file. Return values should be interpreted as follows: +** +** SQLITE_RBU_STATE_OAL: +** RBU is currently building a *-oal file. The next call to sqlite3rbu_step() +** may either add further data to the *-oal file, or compute data that will +** be added by a subsequent call. +** +** SQLITE_RBU_STATE_MOVE: +** RBU has finished building the *-oal file. The next call to sqlite3rbu_step() +** will move the *-oal file to the equivalent *-wal path. If the current +** operation is an RBU update, then the updated version of the database +** file will become visible to ordinary SQLite clients following the next +** call to sqlite3rbu_step(). +** +** SQLITE_RBU_STATE_CHECKPOINT: +** RBU is currently performing an incremental checkpoint. The next call to +** sqlite3rbu_step() will copy a page of data from the *-wal file into +** the target database file. +** +** SQLITE_RBU_STATE_DONE: +** The RBU operation has finished. Any subsequent calls to sqlite3rbu_step() +** will immediately return SQLITE_DONE. +** +** SQLITE_RBU_STATE_ERROR: +** An error has occurred. Any subsequent calls to sqlite3rbu_step() will +** immediately return the SQLite error code associated with the error. +*/ +#define SQLITE_RBU_STATE_OAL 1 +#define SQLITE_RBU_STATE_MOVE 2 +#define SQLITE_RBU_STATE_CHECKPOINT 3 +#define SQLITE_RBU_STATE_DONE 4 +#define SQLITE_RBU_STATE_ERROR 5 + +SQLITE_API int SQLITE_STDCALL sqlite3rbu_state(sqlite3rbu *pRbu); + /* ** Create an RBU VFS named zName that accesses the underlying file-system ** via existing VFS zParent. Or, if the zParent parameter is passed NULL, ** then the new RBU VFS uses the default system VFS to access the file-system. ** The new object is registered as a non-default VFS with SQLite before @@ -164872,16 +165875,18 @@ */ static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){ int rc; memset(pIter, 0, sizeof(RbuObjIter)); - rc = prepareAndCollectError(p->dbRbu, &pIter->pTblIter, &p->zErrmsg, + rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pTblIter, &p->zErrmsg, + sqlite3_mprintf( "SELECT rbu_target_name(name, type='view') AS target, name " "FROM sqlite_master " "WHERE type IN ('table', 'view') AND target IS NOT NULL " + " %s " "ORDER BY name" - ); + , rbuIsVacuum(p) ? "AND rootpage!=0 AND rootpage IS NOT NULL" : "")); if( rc==SQLITE_OK ){ rc = prepareAndCollectError(p->dbMain, &pIter->pIdxIter, &p->zErrmsg, "SELECT name, rootpage, sql IS NULL OR substr(8, 6)=='UNIQUE' " " FROM main.sqlite_master " @@ -166283,19 +167288,22 @@ /* ** Open the database handle and attach the RBU database as "rbu". If an ** error occurs, leave an error code and message in the RBU handle. */ static void rbuOpenDatabase(sqlite3rbu *p){ - assert( p->rc==SQLITE_OK ); - assert( p->dbMain==0 && p->dbRbu==0 ); - assert( rbuIsVacuum(p) || p->zTarget!=0 ); + assert( p->rc || (p->dbMain==0 && p->dbRbu==0) ); + assert( p->rc || rbuIsVacuum(p) || p->zTarget!=0 ); /* Open the RBU database */ p->dbRbu = rbuOpenDbhandle(p, p->zRbu, 1); if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){ sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, (void*)p); + if( p->zState==0 ){ + const char *zFile = sqlite3_db_filename(p->dbRbu, "main"); + p->zState = rbuMPrintf(p, "file://%s-vacuum?modeof=%s", zFile, zFile); + } } /* If using separate RBU and state databases, attach the state database to ** the RBU db handle now. */ if( p->zState ){ @@ -166456,13 +167464,13 @@ #if SQLITE_ENABLE_8_3_NAMES<2 if( sqlite3_uri_boolean(zBase, "8_3_names", 0) ) #endif { int i, sz; - sz = sqlite3Strlen30(z); + sz = (int)strlen(z)&0xffffff; for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){} - if( z[i]=='.' && ALWAYS(sz>i+4) ) memmove(&z[i+1], &z[sz-3], 4); + if( z[i]=='.' && sz>i+4 ) memmove(&z[i+1], &z[sz-3], 4); } #endif } /* @@ -167426,12 +168434,11 @@ const char *zState ){ sqlite3rbu *p; size_t nTarget = zTarget ? strlen(zTarget) : 0; size_t nRbu = strlen(zRbu); - size_t nState = zState ? strlen(zState) : 0; - size_t nByte = sizeof(sqlite3rbu) + nTarget+1 + nRbu+1+ nState+1; + size_t nByte = sizeof(sqlite3rbu) + nTarget+1 + nRbu+1; p = (sqlite3rbu*)sqlite3_malloc64(nByte); if( p ){ RbuState *pState = 0; @@ -167449,12 +168456,11 @@ } p->zRbu = pCsr; memcpy(p->zRbu, zRbu, nRbu+1); pCsr += nRbu+1; if( zState ){ - p->zState = pCsr; - memcpy(p->zState, zState, nState+1); + p->zState = rbuMPrintf(p, "%s", zState); } rbuOpenDatabase(p); } if( p->rc==SQLITE_OK ){ @@ -167504,34 +168510,11 @@ } if( p->rc==SQLITE_OK ){ if( p->eStage==RBU_STAGE_OAL ){ sqlite3 *db = p->dbMain; - - if( pState->eStage==0 && rbuIsVacuum(p) ){ - rbuCopyPragma(p, "page_size"); - rbuCopyPragma(p, "auto_vacuum"); - } - - /* Open transactions both databases. The *-oal file is opened or - ** created at this point. */ - if( p->rc==SQLITE_OK ){ - p->rc = sqlite3_exec(db, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg); - } - if( p->rc==SQLITE_OK ){ - p->rc = sqlite3_exec(p->dbRbu, "BEGIN", 0, 0, &p->zErrmsg); - } - - /* Check if the main database is a zipvfs db. If it is, set the upper - ** level pager to use "journal_mode=off". This prevents it from - ** generating a large journal using a temp file. */ - if( p->rc==SQLITE_OK ){ - int frc = sqlite3_file_control(db, "main", SQLITE_FCNTL_ZIPVFS, 0); - if( frc==SQLITE_OK ){ - p->rc = sqlite3_exec(db, "PRAGMA journal_mode=off",0,0,&p->zErrmsg); - } - } + p->rc = sqlite3_exec(p->dbRbu, "BEGIN", 0, 0, &p->zErrmsg); /* Point the object iterator at the first object */ if( p->rc==SQLITE_OK ){ p->rc = rbuObjIterFirst(p, &p->objiter); } @@ -167538,16 +168521,38 @@ /* If the RBU database contains no data_xxx tables, declare the RBU ** update finished. */ if( p->rc==SQLITE_OK && p->objiter.zTbl==0 ){ p->rc = SQLITE_DONE; + p->eStage = RBU_STAGE_DONE; + }else{ + if( p->rc==SQLITE_OK && pState->eStage==0 && rbuIsVacuum(p) ){ + rbuCopyPragma(p, "page_size"); + rbuCopyPragma(p, "auto_vacuum"); + } + + /* Open transactions both databases. The *-oal file is opened or + ** created at this point. */ + if( p->rc==SQLITE_OK ){ + p->rc = sqlite3_exec(db, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg); + } + + /* Check if the main database is a zipvfs db. If it is, set the upper + ** level pager to use "journal_mode=off". This prevents it from + ** generating a large journal using a temp file. */ + if( p->rc==SQLITE_OK ){ + int frc = sqlite3_file_control(db, "main", SQLITE_FCNTL_ZIPVFS, 0); + if( frc==SQLITE_OK ){ + p->rc = sqlite3_exec( + db, "PRAGMA journal_mode=off",0,0,&p->zErrmsg); + } + } + + if( p->rc==SQLITE_OK ){ + rbuSetupOal(p, pState); + } } - - if( p->rc==SQLITE_OK ){ - rbuSetupOal(p, pState); - } - }else if( p->eStage==RBU_STAGE_MOVE ){ /* no-op */ }else if( p->eStage==RBU_STAGE_CKPT ){ rbuSetupCheckpoint(p, pState); }else if( p->eStage==RBU_STAGE_DONE ){ @@ -167560,19 +168565,34 @@ rbuFreeState(pState); } return p; } + +/* +** Allocate and return an RBU handle with all fields zeroed except for the +** error code, which is set to SQLITE_MISUSE. +*/ +static sqlite3rbu *rbuMisuseError(void){ + sqlite3rbu *pRet; + pRet = sqlite3_malloc64(sizeof(sqlite3rbu)); + if( pRet ){ + memset(pRet, 0, sizeof(sqlite3rbu)); + pRet->rc = SQLITE_MISUSE; + } + return pRet; +} /* ** Open and return a new RBU handle. */ SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open( const char *zTarget, const char *zRbu, const char *zState ){ + if( zTarget==0 || zRbu==0 ){ return rbuMisuseError(); } /* TODO: Check that zTarget and zRbu are non-NULL */ return openRbuHandle(zTarget, zRbu, zState); } /* @@ -167580,10 +168600,11 @@ */ SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_vacuum( const char *zTarget, const char *zState ){ + if( zTarget==0 ){ return rbuMisuseError(); } /* TODO: Check that both arguments are non-NULL */ return openRbuHandle(0, zTarget, zState); } /* @@ -167657,10 +168678,11 @@ sqlite3_free(p->aFrame); rbuEditErrmsg(p); rc = p->rc; *pzErrmsg = p->zErrmsg; + sqlite3_free(p->zState); sqlite3_free(p); }else{ rc = SQLITE_NOMEM; *pzErrmsg = 0; } @@ -167709,14 +168731,44 @@ default: assert( 0 ); } } + +/* +** Return the current state of the RBU vacuum or update operation. +*/ +SQLITE_API int SQLITE_STDCALL sqlite3rbu_state(sqlite3rbu *p){ + int aRes[] = { + 0, SQLITE_RBU_STATE_OAL, SQLITE_RBU_STATE_MOVE, + 0, SQLITE_RBU_STATE_CHECKPOINT, SQLITE_RBU_STATE_DONE + }; + + assert( RBU_STAGE_OAL==1 ); + assert( RBU_STAGE_MOVE==2 ); + assert( RBU_STAGE_CKPT==4 ); + assert( RBU_STAGE_DONE==5 ); + assert( aRes[RBU_STAGE_OAL]==SQLITE_RBU_STATE_OAL ); + assert( aRes[RBU_STAGE_MOVE]==SQLITE_RBU_STATE_MOVE ); + assert( aRes[RBU_STAGE_CKPT]==SQLITE_RBU_STATE_CHECKPOINT ); + assert( aRes[RBU_STAGE_DONE]==SQLITE_RBU_STATE_DONE ); + + if( p->rc!=SQLITE_OK && p->rc!=SQLITE_DONE ){ + return SQLITE_RBU_STATE_ERROR; + }else{ + assert( p->rc!=SQLITE_DONE || p->eStage==RBU_STAGE_DONE ); + assert( p->eStage==RBU_STAGE_OAL + || p->eStage==RBU_STAGE_MOVE + || p->eStage==RBU_STAGE_CKPT + || p->eStage==RBU_STAGE_DONE + ); + return aRes[p->eStage]; + } +} SQLITE_API int SQLITE_STDCALL sqlite3rbu_savestate(sqlite3rbu *p){ int rc = p->rc; - if( rc==SQLITE_DONE ) return SQLITE_OK; assert( p->eStage>=RBU_STAGE_OAL && p->eStage<=RBU_STAGE_DONE ); if( p->eStage==RBU_STAGE_OAL ){ assert( rc!=SQLITE_DONE ); @@ -168694,14 +169746,14 @@ ** ** '/1c2/000/' // Left-most child of 451st child of root */ #define VTAB_SCHEMA \ "CREATE TABLE xx( " \ - " name STRING, /* Name of table or index */" \ - " path INTEGER, /* Path to page from root */" \ + " name TEXT, /* Name of table or index */" \ + " path TEXT, /* Path to page from root */" \ " pageno INTEGER, /* Page number */" \ - " pagetype STRING, /* 'internal', 'leaf' or 'overflow' */" \ + " pagetype TEXT, /* 'internal', 'leaf' or 'overflow' */" \ " ncell INTEGER, /* Cells on page (0 for overflow) */" \ " payload INTEGER, /* Bytes of payload on this page */" \ " unused INTEGER, /* Bytes of unused space on this page */" \ " mx_payload INTEGER, /* Largest payload size of all cells */" \ " pgoffset INTEGER, /* Offset of page in file */" \ @@ -169238,11 +170290,11 @@ zSql = sqlite3_mprintf( "SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type" " UNION ALL " "SELECT name, rootpage, type" " FROM \"%w\".%s WHERE rootpage!=0" - " ORDER BY name", pTab->db->aDb[pCsr->iDb].zName, zMaster); + " ORDER BY name", pTab->db->aDb[pCsr->iDb].zDbSName, zMaster); if( zSql==0 ){ return SQLITE_NOMEM_BKPT; }else{ rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0); sqlite3_free(zSql); @@ -169292,11 +170344,11 @@ sqlite3_result_int(ctx, pCsr->szPage); break; default: { /* schema */ sqlite3 *db = sqlite3_context_db_handle(ctx); int iDb = pCsr->iDb; - sqlite3_result_text(ctx, db->aDb[iDb].zName, -1, SQLITE_STATIC); + sqlite3_result_text(ctx, db->aDb[iDb].zDbSName, -1, SQLITE_STATIC); break; } } return SQLITE_OK; } @@ -175195,10 +176247,30 @@ #endif /* SQLITE_DEBUG */ /**************************************************************************** ** Scalar SQL function implementations ****************************************************************************/ + +/* +** Implementation of the json_QUOTE(VALUE) function. Return a JSON value +** corresponding to the SQL value input. Mostly this means putting +** double-quotes around strings and returning the unquoted string "null" +** when given a NULL input. +*/ +static void jsonQuoteFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + JsonString jx; + UNUSED_PARAM(argc); + + jsonInit(&jx, ctx); + jsonAppendValue(&jx, argv[0]); + jsonResult(&jx); + sqlite3_result_subtype(ctx, JSON_SUBTYPE); +} /* ** Implementation of the json_array(VALUE,...) function. Return a JSON ** array that contains all values given in arguments. Or if any argument ** is a BLOB, throw an error. @@ -176109,10 +177181,11 @@ { "json_array_length", 1, 0, jsonArrayLengthFunc }, { "json_array_length", 2, 0, jsonArrayLengthFunc }, { "json_extract", -1, 0, jsonExtractFunc }, { "json_insert", -1, 0, jsonSetFunc }, { "json_object", -1, 0, jsonObjectFunc }, + { "json_quote", 1, 0, jsonQuoteFunc }, { "json_remove", -1, 0, jsonRemoveFunc }, { "json_replace", -1, 0, jsonReplaceFunc }, { "json_set", -1, 1, jsonSetFunc }, { "json_type", 1, 0, jsonTypeFunc }, { "json_type", 2, 0, jsonTypeFunc }, @@ -176509,11 +177582,11 @@ ** following structure. All structure methods must be defined, setting ** any member of the fts5_tokenizer struct to NULL leads to undefined ** behaviour. The structure methods are expected to function as follows: ** ** xCreate: -** This function is used to allocate and inititalize a tokenizer instance. +** This function is used to allocate and initialize a tokenizer instance. ** A tokenizer instance is required to actually tokenize text. ** ** The first argument passed to this function is a copy of the (void*) ** pointer provided by the application when the fts5_tokenizer object ** was registered with FTS5 (the third argument to xCreateTokenizer()). @@ -176768,11 +177841,10 @@ #if 0 } /* end of the 'extern "C"' block */ #endif #endif /* _FTS5_H */ - /* ** 2014 May 31 ** ** The author disclaims copyright to this source code. In place of @@ -177458,11 +178530,10 @@ static Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr*, int); static int sqlite3Fts5ExprPopulatePoslists( Fts5Config*, Fts5Expr*, Fts5PoslistPopulator*, int, const char*, int ); static void sqlite3Fts5ExprCheckPoslists(Fts5Expr*, i64); -static void sqlite3Fts5ExprClearEof(Fts5Expr*); static int sqlite3Fts5ExprClonePhrase(Fts5Expr*, int, Fts5Expr**); static int sqlite3Fts5ExprPhraseCollist(Fts5Expr *, int, const u8 **, int *); @@ -177510,10 +178581,11 @@ static void sqlite3Fts5ParseNearsetFree(Fts5ExprNearset*); static void sqlite3Fts5ParseNodeFree(Fts5ExprNode*); static void sqlite3Fts5ParseSetDistance(Fts5Parse*, Fts5ExprNearset*, Fts5Token*); static void sqlite3Fts5ParseSetColset(Fts5Parse*, Fts5ExprNearset*, Fts5Colset*); +static Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse*, Fts5Colset*); static void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p); static void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token*); /* ** End of interface to code in fts5_expr.c. @@ -177567,16 +178639,17 @@ #define FTS5_NOT 3 #define FTS5_TERM 4 #define FTS5_COLON 5 #define FTS5_LP 6 #define FTS5_RP 7 -#define FTS5_LCP 8 -#define FTS5_RCP 9 -#define FTS5_STRING 10 -#define FTS5_COMMA 11 -#define FTS5_PLUS 12 -#define FTS5_STAR 13 +#define FTS5_MINUS 8 +#define FTS5_LCP 9 +#define FTS5_RCP 10 +#define FTS5_STRING 11 +#define FTS5_COMMA 12 +#define FTS5_PLUS 13 +#define FTS5_STAR 14 /* ** 2000-05-29 ** ** The author disclaims copyright to this source code. In place of @@ -177686,39 +178759,39 @@ #ifndef INTERFACE # define INTERFACE 1 #endif /************* Begin control #defines *****************************************/ #define fts5YYCODETYPE unsigned char -#define fts5YYNOCODE 27 +#define fts5YYNOCODE 28 #define fts5YYACTIONTYPE unsigned char #define sqlite3Fts5ParserFTS5TOKENTYPE Fts5Token typedef union { int fts5yyinit; sqlite3Fts5ParserFTS5TOKENTYPE fts5yy0; - Fts5Colset* fts5yy3; - Fts5ExprPhrase* fts5yy11; - Fts5ExprNode* fts5yy18; - int fts5yy20; - Fts5ExprNearset* fts5yy26; + int fts5yy4; + Fts5Colset* fts5yy11; + Fts5ExprNode* fts5yy24; + Fts5ExprNearset* fts5yy46; + Fts5ExprPhrase* fts5yy53; } fts5YYMINORTYPE; #ifndef fts5YYSTACKDEPTH #define fts5YYSTACKDEPTH 100 #endif #define sqlite3Fts5ParserARG_SDECL Fts5Parse *pParse; #define sqlite3Fts5ParserARG_PDECL ,Fts5Parse *pParse #define sqlite3Fts5ParserARG_FETCH Fts5Parse *pParse = fts5yypParser->pParse #define sqlite3Fts5ParserARG_STORE fts5yypParser->pParse = pParse -#define fts5YYNSTATE 26 -#define fts5YYNRULE 24 -#define fts5YY_MAX_SHIFT 25 -#define fts5YY_MIN_SHIFTREDUCE 40 -#define fts5YY_MAX_SHIFTREDUCE 63 -#define fts5YY_MIN_REDUCE 64 -#define fts5YY_MAX_REDUCE 87 -#define fts5YY_ERROR_ACTION 88 -#define fts5YY_ACCEPT_ACTION 89 -#define fts5YY_NO_ACTION 90 +#define fts5YYNSTATE 29 +#define fts5YYNRULE 26 +#define fts5YY_MAX_SHIFT 28 +#define fts5YY_MIN_SHIFTREDUCE 45 +#define fts5YY_MAX_SHIFTREDUCE 70 +#define fts5YY_MIN_REDUCE 71 +#define fts5YY_MAX_REDUCE 96 +#define fts5YY_ERROR_ACTION 97 +#define fts5YY_ACCEPT_ACTION 98 +#define fts5YY_NO_ACTION 99 /************* End control #defines *******************************************/ /* Define the fts5yytestcase() macro to be a no-op if is not already defined ** otherwise. ** @@ -177746,29 +178819,33 @@ ** N between fts5YY_MIN_SHIFTREDUCE Shift to an arbitrary state then ** and fts5YY_MAX_SHIFTREDUCE reduce by rule N-fts5YY_MIN_SHIFTREDUCE. ** ** N between fts5YY_MIN_REDUCE Reduce by rule N-fts5YY_MIN_REDUCE ** and fts5YY_MAX_REDUCE - +** ** N == fts5YY_ERROR_ACTION A syntax error has occurred. ** ** N == fts5YY_ACCEPT_ACTION The parser accepts its input. ** ** N == fts5YY_NO_ACTION No such action. Denotes unused ** slots in the fts5yy_action[] table. ** ** The action table is constructed as a single large table named fts5yy_action[]. -** Given state S and lookahead X, the action is computed as -** -** fts5yy_action[ fts5yy_shift_ofst[S] + X ] -** -** If the index value fts5yy_shift_ofst[S]+X is out of range or if the value -** fts5yy_lookahead[fts5yy_shift_ofst[S]+X] is not equal to X or if fts5yy_shift_ofst[S] -** is equal to fts5YY_SHIFT_USE_DFLT, it means that the action is not in the table -** and that fts5yy_default[S] should be used instead. -** -** The formula above is for computing the action when the lookahead is +** Given state S and lookahead X, the action is computed as either: +** +** (A) N = fts5yy_action[ fts5yy_shift_ofst[S] + X ] +** (B) N = fts5yy_default[S] +** +** The (A) formula is preferred. The B formula is used instead if: +** (1) The fts5yy_shift_ofst[S]+X value is out of range, or +** (2) fts5yy_lookahead[fts5yy_shift_ofst[S]+X] is not equal to X, or +** (3) fts5yy_shift_ofst[S] equal fts5YY_SHIFT_USE_DFLT. +** (Implementation note: fts5YY_SHIFT_USE_DFLT is chosen so that +** fts5YY_SHIFT_USE_DFLT+X will be out of range for all possible lookaheads X. +** Hence only tests (1) and (2) need to be evaluated.) +** +** The formulas above are for computing the action when the lookahead is ** a terminal symbol. If the lookahead is a non-terminal (as occurs after ** a reduce action) then the fts5yy_reduce_ofst[] array is used in place of ** the fts5yy_shift_ofst[] array and fts5YY_REDUCE_USE_DFLT is used in place of ** fts5YY_SHIFT_USE_DFLT. ** @@ -177782,52 +178859,54 @@ ** fts5yy_reduce_ofst[] For each state, the offset into fts5yy_action for ** shifting non-terminals after a reduce. ** fts5yy_default[] Default action for each state. ** *********** Begin parsing tables **********************************************/ -#define fts5YY_ACTTAB_COUNT (78) +#define fts5YY_ACTTAB_COUNT (85) static const fts5YYACTIONTYPE fts5yy_action[] = { - /* 0 */ 89, 15, 46, 5, 48, 24, 12, 19, 23, 14, - /* 10 */ 46, 5, 48, 24, 20, 21, 23, 43, 46, 5, - /* 20 */ 48, 24, 6, 18, 23, 17, 46, 5, 48, 24, - /* 30 */ 75, 7, 23, 25, 46, 5, 48, 24, 62, 47, - /* 40 */ 23, 48, 24, 7, 11, 23, 9, 3, 4, 2, - /* 50 */ 62, 50, 52, 44, 64, 3, 4, 2, 49, 4, - /* 60 */ 2, 1, 23, 11, 16, 9, 12, 2, 10, 61, - /* 70 */ 53, 59, 62, 60, 22, 13, 55, 8, + /* 0 */ 98, 16, 51, 5, 53, 27, 83, 7, 26, 15, + /* 10 */ 51, 5, 53, 27, 13, 69, 26, 48, 51, 5, + /* 20 */ 53, 27, 19, 11, 26, 9, 20, 51, 5, 53, + /* 30 */ 27, 13, 22, 26, 28, 51, 5, 53, 27, 68, + /* 40 */ 1, 26, 19, 11, 17, 9, 52, 10, 53, 27, + /* 50 */ 23, 24, 26, 54, 3, 4, 2, 26, 6, 21, + /* 60 */ 49, 71, 3, 4, 2, 7, 56, 59, 55, 59, + /* 70 */ 4, 2, 12, 69, 58, 60, 18, 67, 62, 69, + /* 80 */ 25, 66, 8, 14, 2, }; static const fts5YYCODETYPE fts5yy_lookahead[] = { - /* 0 */ 15, 16, 17, 18, 19, 20, 10, 11, 23, 16, - /* 10 */ 17, 18, 19, 20, 23, 24, 23, 16, 17, 18, - /* 20 */ 19, 20, 22, 23, 23, 16, 17, 18, 19, 20, - /* 30 */ 5, 6, 23, 16, 17, 18, 19, 20, 13, 17, - /* 40 */ 23, 19, 20, 6, 8, 23, 10, 1, 2, 3, - /* 50 */ 13, 9, 10, 7, 0, 1, 2, 3, 19, 2, - /* 60 */ 3, 6, 23, 8, 21, 10, 10, 3, 10, 25, - /* 70 */ 10, 10, 13, 25, 12, 10, 7, 5, -}; -#define fts5YY_SHIFT_USE_DFLT (-5) -#define fts5YY_SHIFT_COUNT (25) -#define fts5YY_SHIFT_MIN (-4) -#define fts5YY_SHIFT_MAX (72) -static const signed char fts5yy_shift_ofst[] = { - /* 0 */ 55, 55, 55, 55, 55, 36, -4, 56, 58, 25, - /* 10 */ 37, 60, 59, 59, 46, 54, 42, 57, 62, 61, - /* 20 */ 62, 69, 65, 62, 72, 64, -}; -#define fts5YY_REDUCE_USE_DFLT (-16) -#define fts5YY_REDUCE_COUNT (13) -#define fts5YY_REDUCE_MIN (-15) -#define fts5YY_REDUCE_MAX (48) + /* 0 */ 16, 17, 18, 19, 20, 21, 5, 6, 24, 17, + /* 10 */ 18, 19, 20, 21, 11, 14, 24, 17, 18, 19, + /* 20 */ 20, 21, 8, 9, 24, 11, 17, 18, 19, 20, + /* 30 */ 21, 11, 12, 24, 17, 18, 19, 20, 21, 26, + /* 40 */ 6, 24, 8, 9, 22, 11, 18, 11, 20, 21, + /* 50 */ 24, 25, 24, 20, 1, 2, 3, 24, 23, 24, + /* 60 */ 7, 0, 1, 2, 3, 6, 10, 11, 10, 11, + /* 70 */ 2, 3, 9, 14, 11, 11, 22, 26, 7, 14, + /* 80 */ 13, 11, 5, 11, 3, +}; +#define fts5YY_SHIFT_USE_DFLT (85) +#define fts5YY_SHIFT_COUNT (28) +#define fts5YY_SHIFT_MIN (0) +#define fts5YY_SHIFT_MAX (81) +static const unsigned char fts5yy_shift_ofst[] = { + /* 0 */ 34, 34, 34, 34, 34, 14, 20, 3, 36, 1, + /* 10 */ 59, 64, 64, 65, 65, 53, 61, 56, 58, 63, + /* 20 */ 68, 67, 70, 67, 71, 72, 67, 77, 81, +}; +#define fts5YY_REDUCE_USE_DFLT (-17) +#define fts5YY_REDUCE_COUNT (14) +#define fts5YY_REDUCE_MIN (-16) +#define fts5YY_REDUCE_MAX (54) static const signed char fts5yy_reduce_ofst[] = { - /* 0 */ -15, -7, 1, 9, 17, 22, -9, 0, 39, 44, - /* 10 */ 44, 43, 44, 48, + /* 0 */ -16, -8, 0, 9, 17, 28, 26, 35, 33, 13, + /* 10 */ 13, 22, 54, 13, 51, }; static const fts5YYACTIONTYPE fts5yy_default[] = { - /* 0 */ 88, 88, 88, 88, 88, 69, 82, 88, 88, 87, - /* 10 */ 87, 88, 87, 87, 88, 88, 88, 66, 80, 88, - /* 20 */ 81, 88, 88, 78, 88, 65, + /* 0 */ 97, 97, 97, 97, 97, 76, 91, 97, 97, 96, + /* 10 */ 96, 97, 97, 96, 96, 97, 97, 97, 97, 97, + /* 20 */ 73, 89, 97, 90, 97, 97, 87, 97, 72, }; /********** End of lemon-generated parsing tables *****************************/ /* The next table maps tokens (terminal symbols) into fallback tokens. ** If a construct like the following: @@ -177874,21 +178953,22 @@ typedef struct fts5yyStackEntry fts5yyStackEntry; /* The state of the parser is completely contained in an instance of ** the following structure */ struct fts5yyParser { - int fts5yyidx; /* Index of top element in stack */ + fts5yyStackEntry *fts5yytos; /* Pointer to top element of the stack */ #ifdef fts5YYTRACKMAXSTACKDEPTH - int fts5yyidxMax; /* Maximum value of fts5yyidx */ + int fts5yyhwm; /* High-water mark of the stack */ #endif #ifndef fts5YYNOERRORRECOVERY int fts5yyerrcnt; /* Shifts left before out of the error */ #endif sqlite3Fts5ParserARG_SDECL /* A place to hold %extra_argument */ #if fts5YYSTACKDEPTH<=0 int fts5yystksz; /* Current side of the stack */ fts5yyStackEntry *fts5yystack; /* The parser's stack */ + fts5yyStackEntry fts5yystk0; /* First stack entry */ #else fts5yyStackEntry fts5yystack[fts5YYSTACKDEPTH]; /* The parser's stack */ #endif }; typedef struct fts5yyParser fts5yyParser; @@ -177929,15 +179009,15 @@ /* For tracing shifts, the names of all terminals and nonterminals ** are required. The following table supplies these names */ static const char *const fts5yyTokenName[] = { "$", "OR", "AND", "NOT", "TERM", "COLON", "LP", "RP", - "LCP", "RCP", "STRING", "COMMA", - "PLUS", "STAR", "error", "input", - "expr", "cnearset", "exprlist", "nearset", - "colset", "colsetlist", "nearphrases", "phrase", - "neardist_opt", "star_opt", + "MINUS", "LCP", "RCP", "STRING", + "COMMA", "PLUS", "STAR", "error", + "input", "expr", "cnearset", "exprlist", + "nearset", "colset", "colsetlist", "nearphrases", + "phrase", "neardist_opt", "star_opt", }; #endif /* NDEBUG */ #ifndef NDEBUG /* For tracing reduce actions, the names of all rules are required. @@ -177951,48 +179031,60 @@ /* 5 */ "expr ::= exprlist", /* 6 */ "exprlist ::= cnearset", /* 7 */ "exprlist ::= exprlist cnearset", /* 8 */ "cnearset ::= nearset", /* 9 */ "cnearset ::= colset COLON nearset", - /* 10 */ "colset ::= LCP colsetlist RCP", - /* 11 */ "colset ::= STRING", - /* 12 */ "colsetlist ::= colsetlist STRING", - /* 13 */ "colsetlist ::= STRING", - /* 14 */ "nearset ::= phrase", - /* 15 */ "nearset ::= STRING LP nearphrases neardist_opt RP", - /* 16 */ "nearphrases ::= phrase", - /* 17 */ "nearphrases ::= nearphrases phrase", - /* 18 */ "neardist_opt ::=", - /* 19 */ "neardist_opt ::= COMMA STRING", - /* 20 */ "phrase ::= phrase PLUS STRING star_opt", - /* 21 */ "phrase ::= STRING star_opt", - /* 22 */ "star_opt ::= STAR", - /* 23 */ "star_opt ::=", + /* 10 */ "colset ::= MINUS LCP colsetlist RCP", + /* 11 */ "colset ::= LCP colsetlist RCP", + /* 12 */ "colset ::= STRING", + /* 13 */ "colset ::= MINUS STRING", + /* 14 */ "colsetlist ::= colsetlist STRING", + /* 15 */ "colsetlist ::= STRING", + /* 16 */ "nearset ::= phrase", + /* 17 */ "nearset ::= STRING LP nearphrases neardist_opt RP", + /* 18 */ "nearphrases ::= phrase", + /* 19 */ "nearphrases ::= nearphrases phrase", + /* 20 */ "neardist_opt ::=", + /* 21 */ "neardist_opt ::= COMMA STRING", + /* 22 */ "phrase ::= phrase PLUS STRING star_opt", + /* 23 */ "phrase ::= STRING star_opt", + /* 24 */ "star_opt ::= STAR", + /* 25 */ "star_opt ::=", }; #endif /* NDEBUG */ #if fts5YYSTACKDEPTH<=0 /* -** Try to increase the size of the parser stack. +** Try to increase the size of the parser stack. Return the number +** of errors. Return 0 on success. */ -static void fts5yyGrowStack(fts5yyParser *p){ +static int fts5yyGrowStack(fts5yyParser *p){ int newSize; + int idx; fts5yyStackEntry *pNew; newSize = p->fts5yystksz*2 + 100; - pNew = realloc(p->fts5yystack, newSize*sizeof(pNew[0])); + idx = p->fts5yytos ? (int)(p->fts5yytos - p->fts5yystack) : 0; + if( p->fts5yystack==&p->fts5yystk0 ){ + pNew = malloc(newSize*sizeof(pNew[0])); + if( pNew ) pNew[0] = p->fts5yystk0; + }else{ + pNew = realloc(p->fts5yystack, newSize*sizeof(pNew[0])); + } if( pNew ){ p->fts5yystack = pNew; - p->fts5yystksz = newSize; + p->fts5yytos = &p->fts5yystack[idx]; #ifndef NDEBUG if( fts5yyTraceFILE ){ - fprintf(fts5yyTraceFILE,"%sStack grows to %d entries!\n", - fts5yyTracePrompt, p->fts5yystksz); + fprintf(fts5yyTraceFILE,"%sStack grows from %d to %d entries.\n", + fts5yyTracePrompt, p->fts5yystksz, newSize); } #endif + p->fts5yystksz = newSize; } + return pNew==0; } #endif /* Datatype of the argument to the memory allocated passed as the ** second argument to sqlite3Fts5ParserAlloc() below. This can be changed by @@ -178017,19 +179109,28 @@ */ static void *sqlite3Fts5ParserAlloc(void *(*mallocProc)(fts5YYMALLOCARGTYPE)){ fts5yyParser *pParser; pParser = (fts5yyParser*)(*mallocProc)( (fts5YYMALLOCARGTYPE)sizeof(fts5yyParser) ); if( pParser ){ - pParser->fts5yyidx = -1; #ifdef fts5YYTRACKMAXSTACKDEPTH - pParser->fts5yyidxMax = 0; + pParser->fts5yyhwm = 0; #endif #if fts5YYSTACKDEPTH<=0 + pParser->fts5yytos = NULL; pParser->fts5yystack = NULL; pParser->fts5yystksz = 0; - fts5yyGrowStack(pParser); + if( fts5yyGrowStack(pParser) ){ + pParser->fts5yystack = &pParser->fts5yystk0; + pParser->fts5yystksz = 1; + } #endif +#ifndef fts5YYNOERRORRECOVERY + pParser->fts5yyerrcnt = -1; +#endif + pParser->fts5yytos = pParser->fts5yystack; + pParser->fts5yystack[0].stateno = 0; + pParser->fts5yystack[0].major = 0; } return pParser; } /* The following function deletes the "minor type" or semantic value @@ -178055,37 +179156,37 @@ ** Note: during a reduce, the only symbols destroyed are those ** which appear on the RHS of the rule, but which are *not* used ** inside the C code. */ /********* Begin destructor definitions ***************************************/ - case 15: /* input */ + case 16: /* input */ { (void)pParse; } break; - case 16: /* expr */ - case 17: /* cnearset */ - case 18: /* exprlist */ -{ - sqlite3Fts5ParseNodeFree((fts5yypminor->fts5yy18)); -} - break; - case 19: /* nearset */ - case 22: /* nearphrases */ -{ - sqlite3Fts5ParseNearsetFree((fts5yypminor->fts5yy26)); -} - break; - case 20: /* colset */ - case 21: /* colsetlist */ -{ - sqlite3_free((fts5yypminor->fts5yy3)); -} - break; - case 23: /* phrase */ -{ - sqlite3Fts5ParsePhraseFree((fts5yypminor->fts5yy11)); + case 17: /* expr */ + case 18: /* cnearset */ + case 19: /* exprlist */ +{ + sqlite3Fts5ParseNodeFree((fts5yypminor->fts5yy24)); +} + break; + case 20: /* nearset */ + case 23: /* nearphrases */ +{ + sqlite3Fts5ParseNearsetFree((fts5yypminor->fts5yy46)); +} + break; + case 21: /* colset */ + case 22: /* colsetlist */ +{ + sqlite3_free((fts5yypminor->fts5yy11)); +} + break; + case 24: /* phrase */ +{ + sqlite3Fts5ParsePhraseFree((fts5yypminor->fts5yy53)); } break; /********* End destructor definitions *****************************************/ default: break; /* If no destructor action specified: do nothing */ } @@ -178097,12 +179198,13 @@ ** If there is a destructor routine associated with the token which ** is popped from the stack, then call it. */ static void fts5yy_pop_parser_stack(fts5yyParser *pParser){ fts5yyStackEntry *fts5yytos; - assert( pParser->fts5yyidx>=0 ); - fts5yytos = &pParser->fts5yystack[pParser->fts5yyidx--]; + assert( pParser->fts5yytos!=0 ); + assert( pParser->fts5yytos > pParser->fts5yystack ); + fts5yytos = pParser->fts5yytos--; #ifndef NDEBUG if( fts5yyTraceFILE ){ fprintf(fts5yyTraceFILE,"%sPopping %s\n", fts5yyTracePrompt, fts5yyTokenName[fts5yytos->major]); @@ -178125,13 +179227,13 @@ ){ fts5yyParser *pParser = (fts5yyParser*)p; #ifndef fts5YYPARSEFREENEVERNULL if( pParser==0 ) return; #endif - while( pParser->fts5yyidx>=0 ) fts5yy_pop_parser_stack(pParser); + while( pParser->fts5yytos>pParser->fts5yystack ) fts5yy_pop_parser_stack(pParser); #if fts5YYSTACKDEPTH<=0 - free(pParser->fts5yystack); + if( pParser->fts5yystack!=&pParser->fts5yystk0 ) free(pParser->fts5yystack); #endif (*freeProc)((void*)pParser); } /* @@ -178138,11 +179240,11 @@ ** Return the peak depth of the stack for a parser. */ #ifdef fts5YYTRACKMAXSTACKDEPTH static int sqlite3Fts5ParserStackPeak(void *p){ fts5yyParser *pParser = (fts5yyParser*)p; - return pParser->fts5yyidxMax; + return pParser->fts5yyhwm; } #endif /* ** Find the appropriate action for a parser given the terminal @@ -178151,60 +179253,57 @@ static unsigned int fts5yy_find_shift_action( fts5yyParser *pParser, /* The parser */ fts5YYCODETYPE iLookAhead /* The look-ahead token */ ){ int i; - int stateno = pParser->fts5yystack[pParser->fts5yyidx].stateno; + int stateno = pParser->fts5yytos->stateno; if( stateno>=fts5YY_MIN_REDUCE ) return stateno; assert( stateno <= fts5YY_SHIFT_COUNT ); do{ i = fts5yy_shift_ofst[stateno]; - if( i==fts5YY_SHIFT_USE_DFLT ) return fts5yy_default[stateno]; assert( iLookAhead!=fts5YYNOCODE ); i += iLookAhead; if( i<0 || i>=fts5YY_ACTTAB_COUNT || fts5yy_lookahead[i]!=iLookAhead ){ - if( iLookAhead>0 ){ #ifdef fts5YYFALLBACK - fts5YYCODETYPE iFallback; /* Fallback token */ - if( iLookAhead %s\n", - fts5yyTracePrompt, fts5yyTokenName[iLookAhead], fts5yyTokenName[iFallback]); - } + if( fts5yyTraceFILE ){ + fprintf(fts5yyTraceFILE, "%sFALLBACK %s => %s\n", + fts5yyTracePrompt, fts5yyTokenName[iLookAhead], fts5yyTokenName[iFallback]); + } #endif - assert( fts5yyFallback[iFallback]==0 ); /* Fallback loop must terminate */ - iLookAhead = iFallback; - continue; - } + assert( fts5yyFallback[iFallback]==0 ); /* Fallback loop must terminate */ + iLookAhead = iFallback; + continue; + } #endif #ifdef fts5YYWILDCARD - { - int j = i - iLookAhead + fts5YYWILDCARD; - if( + { + int j = i - iLookAhead + fts5YYWILDCARD; + if( #if fts5YY_SHIFT_MIN+fts5YYWILDCARD<0 - j>=0 && + j>=0 && #endif #if fts5YY_SHIFT_MAX+fts5YYWILDCARD>=fts5YY_ACTTAB_COUNT - j0 + ){ #ifndef NDEBUG - if( fts5yyTraceFILE ){ - fprintf(fts5yyTraceFILE, "%sWILDCARD %s => %s\n", - fts5yyTracePrompt, fts5yyTokenName[iLookAhead], - fts5yyTokenName[fts5YYWILDCARD]); - } + if( fts5yyTraceFILE ){ + fprintf(fts5yyTraceFILE, "%sWILDCARD %s => %s\n", + fts5yyTracePrompt, fts5yyTokenName[iLookAhead], + fts5yyTokenName[fts5YYWILDCARD]); + } #endif /* NDEBUG */ - return fts5yy_action[j]; - } + return fts5yy_action[j]; } + } #endif /* fts5YYWILDCARD */ - } return fts5yy_default[stateno]; }else{ return fts5yy_action[i]; } }while(1); @@ -178244,17 +179343,17 @@ /* ** The following routine is called if the stack overflows. */ static void fts5yyStackOverflow(fts5yyParser *fts5yypParser){ sqlite3Fts5ParserARG_FETCH; - fts5yypParser->fts5yyidx--; + fts5yypParser->fts5yytos--; #ifndef NDEBUG if( fts5yyTraceFILE ){ fprintf(fts5yyTraceFILE,"%sStack Overflow!\n",fts5yyTracePrompt); } #endif - while( fts5yypParser->fts5yyidx>=0 ) fts5yy_pop_parser_stack(fts5yypParser); + while( fts5yypParser->fts5yytos>fts5yypParser->fts5yystack ) fts5yy_pop_parser_stack(fts5yypParser); /* Here code is inserted which will execute if the parser ** stack every overflows */ /******** Begin %stack_overflow code ******************************************/ sqlite3Fts5ParseError(pParse, "fts5: parser stack overflow"); @@ -178268,15 +179367,15 @@ #ifndef NDEBUG static void fts5yyTraceShift(fts5yyParser *fts5yypParser, int fts5yyNewState){ if( fts5yyTraceFILE ){ if( fts5yyNewStatefts5yystack[fts5yypParser->fts5yyidx].major], + fts5yyTracePrompt,fts5yyTokenName[fts5yypParser->fts5yytos->major], fts5yyNewState); }else{ fprintf(fts5yyTraceFILE,"%sShift '%s'\n", - fts5yyTracePrompt,fts5yyTokenName[fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx].major]); + fts5yyTracePrompt,fts5yyTokenName[fts5yypParser->fts5yytos->major]); } } } #else # define fts5yyTraceShift(X,Y) @@ -178290,31 +179389,34 @@ int fts5yyNewState, /* The new state to shift in */ int fts5yyMajor, /* The major token to shift in */ sqlite3Fts5ParserFTS5TOKENTYPE fts5yyMinor /* The minor token to shift in */ ){ fts5yyStackEntry *fts5yytos; - fts5yypParser->fts5yyidx++; + fts5yypParser->fts5yytos++; #ifdef fts5YYTRACKMAXSTACKDEPTH - if( fts5yypParser->fts5yyidx>fts5yypParser->fts5yyidxMax ){ - fts5yypParser->fts5yyidxMax = fts5yypParser->fts5yyidx; + if( (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack)>fts5yypParser->fts5yyhwm ){ + fts5yypParser->fts5yyhwm++; + assert( fts5yypParser->fts5yyhwm == (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack) ); } #endif #if fts5YYSTACKDEPTH>0 - if( fts5yypParser->fts5yyidx>=fts5YYSTACKDEPTH ){ + if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5YYSTACKDEPTH] ){ fts5yyStackOverflow(fts5yypParser); return; } #else - if( fts5yypParser->fts5yyidx>=fts5yypParser->fts5yystksz ){ - fts5yyGrowStack(fts5yypParser); - if( fts5yypParser->fts5yyidx>=fts5yypParser->fts5yystksz ){ + if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5yypParser->fts5yystksz] ){ + if( fts5yyGrowStack(fts5yypParser) ){ fts5yyStackOverflow(fts5yypParser); return; } } #endif - fts5yytos = &fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx]; + if( fts5yyNewState > fts5YY_MAX_SHIFT ){ + fts5yyNewState += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE; + } + fts5yytos = fts5yypParser->fts5yytos; fts5yytos->stateno = (fts5YYACTIONTYPE)fts5yyNewState; fts5yytos->major = (fts5YYCODETYPE)fts5yyMajor; fts5yytos->minor.fts5yy0 = fts5yyMinor; fts5yyTraceShift(fts5yypParser, fts5yyNewState); } @@ -178324,34 +179426,36 @@ */ static const struct { fts5YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ unsigned char nrhs; /* Number of right-hand side symbols in the rule */ } fts5yyRuleInfo[] = { - { 15, 1 }, - { 16, 3 }, - { 16, 3 }, - { 16, 3 }, - { 16, 3 }, { 16, 1 }, + { 17, 3 }, + { 17, 3 }, + { 17, 3 }, + { 17, 3 }, + { 17, 1 }, + { 19, 1 }, + { 19, 2 }, { 18, 1 }, - { 18, 2 }, - { 17, 1 }, - { 17, 3 }, - { 20, 3 }, - { 20, 1 }, + { 18, 3 }, + { 21, 4 }, + { 21, 3 }, + { 21, 1 }, { 21, 2 }, - { 21, 1 }, - { 19, 1 }, - { 19, 5 }, + { 22, 2 }, { 22, 1 }, - { 22, 2 }, - { 24, 0 }, - { 24, 2 }, - { 23, 4 }, + { 20, 1 }, + { 20, 5 }, + { 23, 1 }, { 23, 2 }, - { 25, 1 }, { 25, 0 }, + { 25, 2 }, + { 24, 4 }, + { 24, 2 }, + { 26, 1 }, + { 26, 0 }, }; static void fts5yy_accept(fts5yyParser*); /* Forward Declaration */ /* @@ -178365,11 +179469,11 @@ int fts5yygoto; /* The next state */ int fts5yyact; /* The next action */ fts5yyStackEntry *fts5yymsp; /* The top of the parser's stack */ int fts5yysize; /* Amount to pop the stack */ sqlite3Fts5ParserARG_FETCH; - fts5yymsp = &fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx]; + fts5yymsp = fts5yypParser->fts5yytos; #ifndef NDEBUG if( fts5yyTraceFILE && fts5yyruleno<(int)(sizeof(fts5yyRuleName)/sizeof(fts5yyRuleName[0])) ){ fts5yysize = fts5yyRuleInfo[fts5yyruleno].nrhs; fprintf(fts5yyTraceFILE, "%sReduce [%s], go to state %d.\n", fts5yyTracePrompt, fts5yyRuleName[fts5yyruleno], fts5yymsp[-fts5yysize].stateno); @@ -178379,26 +179483,27 @@ /* Check that the stack is large enough to grow by a single entry ** if the RHS of the rule is empty. This ensures that there is room ** enough on the stack to push the LHS value */ if( fts5yyRuleInfo[fts5yyruleno].nrhs==0 ){ #ifdef fts5YYTRACKMAXSTACKDEPTH - if( fts5yypParser->fts5yyidx>fts5yypParser->fts5yyidxMax ){ - fts5yypParser->fts5yyidxMax = fts5yypParser->fts5yyidx; + if( (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack)>fts5yypParser->fts5yyhwm ){ + fts5yypParser->fts5yyhwm++; + assert( fts5yypParser->fts5yyhwm == (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack)); } #endif #if fts5YYSTACKDEPTH>0 - if( fts5yypParser->fts5yyidx>=fts5YYSTACKDEPTH-1 ){ + if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5YYSTACKDEPTH-1] ){ fts5yyStackOverflow(fts5yypParser); return; } #else - if( fts5yypParser->fts5yyidx>=fts5yypParser->fts5yystksz-1 ){ - fts5yyGrowStack(fts5yypParser); - if( fts5yypParser->fts5yyidx>=fts5yypParser->fts5yystksz-1 ){ + if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5yypParser->fts5yystksz-1] ){ + if( fts5yyGrowStack(fts5yypParser) ){ fts5yyStackOverflow(fts5yypParser); return; } + fts5yymsp = fts5yypParser->fts5yytos; } #endif } switch( fts5yyruleno ){ @@ -178411,124 +179516,135 @@ ** break; */ /********** Begin reduce actions **********************************************/ fts5YYMINORTYPE fts5yylhsminor; case 0: /* input ::= expr */ -{ sqlite3Fts5ParseFinished(pParse, fts5yymsp[0].minor.fts5yy18); } +{ sqlite3Fts5ParseFinished(pParse, fts5yymsp[0].minor.fts5yy24); } break; case 1: /* expr ::= expr AND expr */ { - fts5yylhsminor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_AND, fts5yymsp[-2].minor.fts5yy18, fts5yymsp[0].minor.fts5yy18, 0); + fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_AND, fts5yymsp[-2].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24, 0); } - fts5yymsp[-2].minor.fts5yy18 = fts5yylhsminor.fts5yy18; + fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24; break; case 2: /* expr ::= expr OR expr */ { - fts5yylhsminor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_OR, fts5yymsp[-2].minor.fts5yy18, fts5yymsp[0].minor.fts5yy18, 0); + fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_OR, fts5yymsp[-2].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24, 0); } - fts5yymsp[-2].minor.fts5yy18 = fts5yylhsminor.fts5yy18; + fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24; break; case 3: /* expr ::= expr NOT expr */ { - fts5yylhsminor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_NOT, fts5yymsp[-2].minor.fts5yy18, fts5yymsp[0].minor.fts5yy18, 0); + fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_NOT, fts5yymsp[-2].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24, 0); } - fts5yymsp[-2].minor.fts5yy18 = fts5yylhsminor.fts5yy18; + fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24; break; case 4: /* expr ::= LP expr RP */ -{fts5yymsp[-2].minor.fts5yy18 = fts5yymsp[-1].minor.fts5yy18;} +{fts5yymsp[-2].minor.fts5yy24 = fts5yymsp[-1].minor.fts5yy24;} break; case 5: /* expr ::= exprlist */ case 6: /* exprlist ::= cnearset */ fts5yytestcase(fts5yyruleno==6); -{fts5yylhsminor.fts5yy18 = fts5yymsp[0].minor.fts5yy18;} - fts5yymsp[0].minor.fts5yy18 = fts5yylhsminor.fts5yy18; +{fts5yylhsminor.fts5yy24 = fts5yymsp[0].minor.fts5yy24;} + fts5yymsp[0].minor.fts5yy24 = fts5yylhsminor.fts5yy24; break; case 7: /* exprlist ::= exprlist cnearset */ { - fts5yylhsminor.fts5yy18 = sqlite3Fts5ParseImplicitAnd(pParse, fts5yymsp[-1].minor.fts5yy18, fts5yymsp[0].minor.fts5yy18); + fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseImplicitAnd(pParse, fts5yymsp[-1].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24); } - fts5yymsp[-1].minor.fts5yy18 = fts5yylhsminor.fts5yy18; + fts5yymsp[-1].minor.fts5yy24 = fts5yylhsminor.fts5yy24; break; case 8: /* cnearset ::= nearset */ { - fts5yylhsminor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy26); + fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy46); } - fts5yymsp[0].minor.fts5yy18 = fts5yylhsminor.fts5yy18; + fts5yymsp[0].minor.fts5yy24 = fts5yylhsminor.fts5yy24; break; case 9: /* cnearset ::= colset COLON nearset */ { - sqlite3Fts5ParseSetColset(pParse, fts5yymsp[0].minor.fts5yy26, fts5yymsp[-2].minor.fts5yy3); - fts5yylhsminor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy26); -} - fts5yymsp[-2].minor.fts5yy18 = fts5yylhsminor.fts5yy18; - break; - case 10: /* colset ::= LCP colsetlist RCP */ -{ fts5yymsp[-2].minor.fts5yy3 = fts5yymsp[-1].minor.fts5yy3; } - break; - case 11: /* colset ::= STRING */ -{ - fts5yylhsminor.fts5yy3 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0); -} - fts5yymsp[0].minor.fts5yy3 = fts5yylhsminor.fts5yy3; - break; - case 12: /* colsetlist ::= colsetlist STRING */ -{ - fts5yylhsminor.fts5yy3 = sqlite3Fts5ParseColset(pParse, fts5yymsp[-1].minor.fts5yy3, &fts5yymsp[0].minor.fts5yy0); } - fts5yymsp[-1].minor.fts5yy3 = fts5yylhsminor.fts5yy3; - break; - case 13: /* colsetlist ::= STRING */ -{ - fts5yylhsminor.fts5yy3 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0); -} - fts5yymsp[0].minor.fts5yy3 = fts5yylhsminor.fts5yy3; - break; - case 14: /* nearset ::= phrase */ -{ fts5yylhsminor.fts5yy26 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy11); } - fts5yymsp[0].minor.fts5yy26 = fts5yylhsminor.fts5yy26; - break; - case 15: /* nearset ::= STRING LP nearphrases neardist_opt RP */ + sqlite3Fts5ParseSetColset(pParse, fts5yymsp[0].minor.fts5yy46, fts5yymsp[-2].minor.fts5yy11); + fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy46); +} + fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24; + break; + case 10: /* colset ::= MINUS LCP colsetlist RCP */ +{ + fts5yymsp[-3].minor.fts5yy11 = sqlite3Fts5ParseColsetInvert(pParse, fts5yymsp[-1].minor.fts5yy11); +} + break; + case 11: /* colset ::= LCP colsetlist RCP */ +{ fts5yymsp[-2].minor.fts5yy11 = fts5yymsp[-1].minor.fts5yy11; } + break; + case 12: /* colset ::= STRING */ +{ + fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0); +} + fts5yymsp[0].minor.fts5yy11 = fts5yylhsminor.fts5yy11; + break; + case 13: /* colset ::= MINUS STRING */ +{ + fts5yymsp[-1].minor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0); + fts5yymsp[-1].minor.fts5yy11 = sqlite3Fts5ParseColsetInvert(pParse, fts5yymsp[-1].minor.fts5yy11); +} + break; + case 14: /* colsetlist ::= colsetlist STRING */ +{ + fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, fts5yymsp[-1].minor.fts5yy11, &fts5yymsp[0].minor.fts5yy0); } + fts5yymsp[-1].minor.fts5yy11 = fts5yylhsminor.fts5yy11; + break; + case 15: /* colsetlist ::= STRING */ +{ + fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0); +} + fts5yymsp[0].minor.fts5yy11 = fts5yylhsminor.fts5yy11; + break; + case 16: /* nearset ::= phrase */ +{ fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy53); } + fts5yymsp[0].minor.fts5yy46 = fts5yylhsminor.fts5yy46; + break; + case 17: /* nearset ::= STRING LP nearphrases neardist_opt RP */ { sqlite3Fts5ParseNear(pParse, &fts5yymsp[-4].minor.fts5yy0); - sqlite3Fts5ParseSetDistance(pParse, fts5yymsp[-2].minor.fts5yy26, &fts5yymsp[-1].minor.fts5yy0); - fts5yylhsminor.fts5yy26 = fts5yymsp[-2].minor.fts5yy26; -} - fts5yymsp[-4].minor.fts5yy26 = fts5yylhsminor.fts5yy26; - break; - case 16: /* nearphrases ::= phrase */ -{ - fts5yylhsminor.fts5yy26 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy11); -} - fts5yymsp[0].minor.fts5yy26 = fts5yylhsminor.fts5yy26; - break; - case 17: /* nearphrases ::= nearphrases phrase */ -{ - fts5yylhsminor.fts5yy26 = sqlite3Fts5ParseNearset(pParse, fts5yymsp[-1].minor.fts5yy26, fts5yymsp[0].minor.fts5yy11); -} - fts5yymsp[-1].minor.fts5yy26 = fts5yylhsminor.fts5yy26; - break; - case 18: /* neardist_opt ::= */ + sqlite3Fts5ParseSetDistance(pParse, fts5yymsp[-2].minor.fts5yy46, &fts5yymsp[-1].minor.fts5yy0); + fts5yylhsminor.fts5yy46 = fts5yymsp[-2].minor.fts5yy46; +} + fts5yymsp[-4].minor.fts5yy46 = fts5yylhsminor.fts5yy46; + break; + case 18: /* nearphrases ::= phrase */ +{ + fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy53); +} + fts5yymsp[0].minor.fts5yy46 = fts5yylhsminor.fts5yy46; + break; + case 19: /* nearphrases ::= nearphrases phrase */ +{ + fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, fts5yymsp[-1].minor.fts5yy46, fts5yymsp[0].minor.fts5yy53); +} + fts5yymsp[-1].minor.fts5yy46 = fts5yylhsminor.fts5yy46; + break; + case 20: /* neardist_opt ::= */ { fts5yymsp[1].minor.fts5yy0.p = 0; fts5yymsp[1].minor.fts5yy0.n = 0; } break; - case 19: /* neardist_opt ::= COMMA STRING */ + case 21: /* neardist_opt ::= COMMA STRING */ { fts5yymsp[-1].minor.fts5yy0 = fts5yymsp[0].minor.fts5yy0; } break; - case 20: /* phrase ::= phrase PLUS STRING star_opt */ -{ - fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseTerm(pParse, fts5yymsp[-3].minor.fts5yy11, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy20); -} - fts5yymsp[-3].minor.fts5yy11 = fts5yylhsminor.fts5yy11; - break; - case 21: /* phrase ::= STRING star_opt */ -{ - fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseTerm(pParse, 0, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy20); -} - fts5yymsp[-1].minor.fts5yy11 = fts5yylhsminor.fts5yy11; - break; - case 22: /* star_opt ::= STAR */ -{ fts5yymsp[0].minor.fts5yy20 = 1; } - break; - case 23: /* star_opt ::= */ -{ fts5yymsp[1].minor.fts5yy20 = 0; } + case 22: /* phrase ::= phrase PLUS STRING star_opt */ +{ + fts5yylhsminor.fts5yy53 = sqlite3Fts5ParseTerm(pParse, fts5yymsp[-3].minor.fts5yy53, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy4); +} + fts5yymsp[-3].minor.fts5yy53 = fts5yylhsminor.fts5yy53; + break; + case 23: /* phrase ::= STRING star_opt */ +{ + fts5yylhsminor.fts5yy53 = sqlite3Fts5ParseTerm(pParse, 0, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy4); +} + fts5yymsp[-1].minor.fts5yy53 = fts5yylhsminor.fts5yy53; + break; + case 24: /* star_opt ::= STAR */ +{ fts5yymsp[0].minor.fts5yy4 = 1; } + break; + case 25: /* star_opt ::= */ +{ fts5yymsp[1].minor.fts5yy4 = 0; } break; default: break; /********** End reduce actions ************************************************/ }; @@ -178535,19 +179651,21 @@ assert( fts5yyrulenofts5YY_MAX_SHIFT ) fts5yyact += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE; - fts5yypParser->fts5yyidx -= fts5yysize - 1; + if( fts5yyact>fts5YY_MAX_SHIFT ){ + fts5yyact += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE; + } fts5yymsp -= fts5yysize-1; + fts5yypParser->fts5yytos = fts5yymsp; fts5yymsp->stateno = (fts5YYACTIONTYPE)fts5yyact; fts5yymsp->major = (fts5YYCODETYPE)fts5yygoto; fts5yyTraceShift(fts5yypParser, fts5yyact); }else{ assert( fts5yyact == fts5YY_ACCEPT_ACTION ); - fts5yypParser->fts5yyidx -= fts5yysize; + fts5yypParser->fts5yytos -= fts5yysize; fts5yy_accept(fts5yypParser); } } /* @@ -178561,11 +179679,11 @@ #ifndef NDEBUG if( fts5yyTraceFILE ){ fprintf(fts5yyTraceFILE,"%sFail!\n",fts5yyTracePrompt); } #endif - while( fts5yypParser->fts5yyidx>=0 ) fts5yy_pop_parser_stack(fts5yypParser); + while( fts5yypParser->fts5yytos>fts5yypParser->fts5yystack ) fts5yy_pop_parser_stack(fts5yypParser); /* Here code is inserted which will be executed whenever the ** parser fails */ /************ Begin %parse_failure code ***************************************/ /************ End %parse_failure code *****************************************/ sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ @@ -178602,11 +179720,14 @@ #ifndef NDEBUG if( fts5yyTraceFILE ){ fprintf(fts5yyTraceFILE,"%sAccept!\n",fts5yyTracePrompt); } #endif - while( fts5yypParser->fts5yyidx>=0 ) fts5yy_pop_parser_stack(fts5yypParser); +#ifndef fts5YYNOERRORRECOVERY + fts5yypParser->fts5yyerrcnt = -1; +#endif + assert( fts5yypParser->fts5yytos==fts5yypParser->fts5yystack ); /* Here code is inserted which will be executed whenever the ** parser accepts */ /*********** Begin %parse_accept code *****************************************/ /*********** End %parse_accept code *******************************************/ sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ @@ -178645,32 +179766,12 @@ #ifdef fts5YYERRORSYMBOL int fts5yyerrorhit = 0; /* True if fts5yymajor has invoked an error */ #endif fts5yyParser *fts5yypParser; /* The parser */ - /* (re)initialize the parser, if necessary */ fts5yypParser = (fts5yyParser*)fts5yyp; - if( fts5yypParser->fts5yyidx<0 ){ -#if fts5YYSTACKDEPTH<=0 - if( fts5yypParser->fts5yystksz <=0 ){ - fts5yyStackOverflow(fts5yypParser); - return; - } -#endif - fts5yypParser->fts5yyidx = 0; -#ifndef fts5YYNOERRORRECOVERY - fts5yypParser->fts5yyerrcnt = -1; -#endif - fts5yypParser->fts5yystack[0].stateno = 0; - fts5yypParser->fts5yystack[0].major = 0; -#ifndef NDEBUG - if( fts5yyTraceFILE ){ - fprintf(fts5yyTraceFILE,"%sInitialize. Empty stack. State 0\n", - fts5yyTracePrompt); - } -#endif - } + assert( fts5yypParser->fts5yytos!=0 ); #if !defined(fts5YYERRORSYMBOL) && !defined(fts5YYNOERRORRECOVERY) fts5yyendofinput = (fts5yymajor==0); #endif sqlite3Fts5ParserARG_STORE; @@ -178681,11 +179782,10 @@ #endif do{ fts5yyact = fts5yy_find_shift_action(fts5yypParser,(fts5YYCODETYPE)fts5yymajor); if( fts5yyact <= fts5YY_MAX_SHIFTREDUCE ){ - if( fts5yyact > fts5YY_MAX_SHIFT ) fts5yyact += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE; fts5yy_shift(fts5yypParser,fts5yyact,fts5yymajor,fts5yyminor); #ifndef fts5YYNOERRORRECOVERY fts5yypParser->fts5yyerrcnt--; #endif fts5yymajor = fts5YYNOCODE; @@ -178723,11 +179823,11 @@ ** */ if( fts5yypParser->fts5yyerrcnt<0 ){ fts5yy_syntax_error(fts5yypParser,fts5yymajor,fts5yyminor); } - fts5yymx = fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx].major; + fts5yymx = fts5yypParser->fts5yytos->major; if( fts5yymx==fts5YYERRORSYMBOL || fts5yyerrorhit ){ #ifndef NDEBUG if( fts5yyTraceFILE ){ fprintf(fts5yyTraceFILE,"%sDiscard input token %s\n", fts5yyTracePrompt,fts5yyTokenName[fts5yymajor]); @@ -178734,22 +179834,24 @@ } #endif fts5yy_destructor(fts5yypParser, (fts5YYCODETYPE)fts5yymajor, &fts5yyminorunion); fts5yymajor = fts5YYNOCODE; }else{ - while( - fts5yypParser->fts5yyidx >= 0 && - fts5yymx != fts5YYERRORSYMBOL && - (fts5yyact = fts5yy_find_reduce_action( - fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx].stateno, + while( fts5yypParser->fts5yytos >= &fts5yypParser->fts5yystack + && fts5yymx != fts5YYERRORSYMBOL + && (fts5yyact = fts5yy_find_reduce_action( + fts5yypParser->fts5yytos->stateno, fts5YYERRORSYMBOL)) >= fts5YY_MIN_REDUCE ){ fts5yy_pop_parser_stack(fts5yypParser); } - if( fts5yypParser->fts5yyidx < 0 || fts5yymajor==0 ){ + if( fts5yypParser->fts5yytos < fts5yypParser->fts5yystack || fts5yymajor==0 ){ fts5yy_destructor(fts5yypParser,(fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion); fts5yy_parse_failed(fts5yypParser); +#ifndef fts5YYNOERRORRECOVERY + fts5yypParser->fts5yyerrcnt = -1; +#endif fts5yymajor = fts5YYNOCODE; }else if( fts5yymx!=fts5YYERRORSYMBOL ){ fts5yy_shift(fts5yypParser,fts5yyact,fts5YYERRORSYMBOL,fts5yyminor); } } @@ -178782,22 +179884,27 @@ } fts5yypParser->fts5yyerrcnt = 3; fts5yy_destructor(fts5yypParser,(fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion); if( fts5yyendofinput ){ fts5yy_parse_failed(fts5yypParser); +#ifndef fts5YYNOERRORRECOVERY + fts5yypParser->fts5yyerrcnt = -1; +#endif } fts5yymajor = fts5YYNOCODE; #endif } - }while( fts5yymajor!=fts5YYNOCODE && fts5yypParser->fts5yyidx>=0 ); + }while( fts5yymajor!=fts5YYNOCODE && fts5yypParser->fts5yytos>fts5yypParser->fts5yystack ); #ifndef NDEBUG if( fts5yyTraceFILE ){ - int i; + fts5yyStackEntry *i; + char cDiv = '['; fprintf(fts5yyTraceFILE,"%sReturn. Stack=",fts5yyTracePrompt); - for(i=1; i<=fts5yypParser->fts5yyidx; i++) - fprintf(fts5yyTraceFILE,"%c%s", i==1 ? '[' : ' ', - fts5yyTokenName[fts5yypParser->fts5yystack[i].major]); + for(i=&fts5yypParser->fts5yystack[1]; i<=fts5yypParser->fts5yytos; i++){ + fprintf(fts5yyTraceFILE,"%c%s", cDiv, fts5yyTokenName[i->major]); + cDiv = ' '; + } fprintf(fts5yyTraceFILE,"]\n"); } #endif return; } @@ -178991,11 +180098,11 @@ } if( p->iRangeEnd>0 && iPos==p->iRangeEnd ){ fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff); p->iOff = iEndOff; - if( iPositer.iEnd ){ + if( iPos>=p->iter.iStart && iPositer.iEnd ){ fts5HighlightAppend(&rc, p, p->zClose, -1); } } return rc; @@ -179152,10 +180259,17 @@ ctx.iRangeEnd = iBestStart + nToken - 1; if( iBestStart>0 ){ fts5HighlightAppend(&rc, &ctx, zEllips, -1); } + + /* Advance iterator ctx.iter so that it points to the first coalesced + ** phrase instance at or following position iBestStart. */ + while( ctx.iter.iStart>=0 && ctx.iter.iStartxTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb); } if( ctx.iRangeEnd>=(nColSize-1) ){ fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff); @@ -180887,10 +182001,11 @@ case '}': tok = FTS5_RCP; break; case ':': tok = FTS5_COLON; break; case ',': tok = FTS5_COMMA; break; case '+': tok = FTS5_PLUS; break; case '*': tok = FTS5_STAR; break; + case '-': tok = FTS5_MINUS; break; case '\0': tok = FTS5_EOF; break; case '"': { const char *z2; tok = FTS5_STRING; @@ -182378,11 +183493,11 @@ sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*)); } if( rc==SQLITE_OK ){ Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset; if( pColsetOrig ){ - int nByte = sizeof(Fts5Colset) + pColsetOrig->nCol * sizeof(int); + int nByte = sizeof(Fts5Colset) + (pColsetOrig->nCol-1) * sizeof(int); Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte); if( pColset ){ memcpy(pColset, pColsetOrig, nByte); } pNew->pRoot->pNear->pColset = pColset; @@ -182512,10 +183627,38 @@ #endif } return pNew; } + +/* +** Allocate and return an Fts5Colset object specifying the inverse of +** the colset passed as the second argument. Free the colset passed +** as the second argument before returning. +*/ +static Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse *pParse, Fts5Colset *p){ + Fts5Colset *pRet; + int nCol = pParse->pConfig->nCol; + + pRet = (Fts5Colset*)sqlite3Fts5MallocZero(&pParse->rc, + sizeof(Fts5Colset) + sizeof(int)*nCol + ); + if( pRet ){ + int i; + int iOld = 0; + for(i=0; i=p->nCol || p->aiCol[iOld]!=i ){ + pRet->aiCol[pRet->nCol++] = i; + }else{ + iOld++; + } + } + } + + sqlite3_free(p); + return pRet; +} static Fts5Colset *sqlite3Fts5ParseColset( Fts5Parse *pParse, /* Store SQLITE_NOMEM here if required */ Fts5Colset *pColset, /* Existing colset object */ Fts5Token *p @@ -183337,21 +184480,10 @@ static void sqlite3Fts5ExprCheckPoslists(Fts5Expr *pExpr, i64 iRowid){ fts5ExprCheckPoslists(pExpr->pRoot, iRowid); } -static void fts5ExprClearEof(Fts5ExprNode *pNode){ - int i; - for(i=0; inChild; i++){ - fts5ExprClearEof(pNode->apChild[i]); - } - pNode->bEof = 0; -} -static void sqlite3Fts5ExprClearEof(Fts5Expr *pExpr){ - fts5ExprClearEof(pExpr->pRoot); -} - /* ** This function is only called for detail=columns tables. */ static int sqlite3Fts5ExprPhraseCollist( Fts5Expr *pExpr, @@ -184619,18 +185751,29 @@ assert( (pRet==0)==(p->rc!=SQLITE_OK) ); return pRet; } - /* ** Release a reference to data record returned by an earlier call to ** fts5DataRead(). */ static void fts5DataRelease(Fts5Data *pData){ sqlite3_free(pData); } + +static Fts5Data *fts5LeafRead(Fts5Index *p, i64 iRowid){ + Fts5Data *pRet = fts5DataRead(p, iRowid); + if( pRet ){ + if( pRet->szLeaf>pRet->nn ){ + p->rc = FTS5_CORRUPT; + fts5DataRelease(pRet); + pRet = 0; + } + } + return pRet; +} static int fts5IndexPrepareStmt( Fts5Index *p, sqlite3_stmt **ppStmt, char *zSql @@ -185436,11 +186579,11 @@ pIter->iLeafPgno++; if( pIter->pNextLeaf ){ pIter->pLeaf = pIter->pNextLeaf; pIter->pNextLeaf = 0; }else if( pIter->iLeafPgno<=pSeg->pgnoLast ){ - pIter->pLeaf = fts5DataRead(p, + pIter->pLeaf = fts5LeafRead(p, FTS5_SEGMENT_ROWID(pSeg->iSegid, pIter->iLeafPgno) ); }else{ pIter->pLeaf = 0; } @@ -185939,13 +187082,12 @@ pIter->iLeafOffset = iOff; if( pLeaf->nn>pLeaf->szLeaf ){ pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32( &pLeaf->p[pLeaf->szLeaf], pIter->iEndofDoclist - ); + ); } - } else if( pLeaf->nn>pLeaf->szLeaf ){ pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32( &pLeaf->p[pLeaf->szLeaf], iOff ); @@ -186185,10 +187327,15 @@ } iPgidx += fts5GetVarint32(&a[iPgidx], nKeep); iTermOff += nKeep; iOff = iTermOff; + + if( iOff>=n ){ + p->rc = FTS5_CORRUPT; + return; + } /* Read the nKeep field of the next term. */ fts5FastGetVarint32(a, iOff, nKeep); } @@ -187111,10 +188258,19 @@ fts5BufferZero(&pIter->poslist); fts5SegiterPoslist(pIter->pIndex, pSeg, 0, &pIter->poslist); pIter->base.pData = pIter->poslist.p; } } + +/* +** xSetOutputs callback used when the Fts5Colset object has nCol==0 (match +** against no columns at all). +*/ +static void fts5IterSetOutputs_ZeroColset(Fts5Iter *pIter, Fts5SegIter *pSeg){ + UNUSED_PARAM(pSeg); + pIter->base.nData = 0; +} /* ** xSetOutputs callback used by detail=col when there is a column filter ** and there are 100 or more columns. Also called as a fallback from ** fts5IterSetOutputs_Col100 if the column-list spans more than one page. @@ -187216,10 +188372,14 @@ } else if( pIter->pColset==0 ){ pIter->xSetOutputs = fts5IterSetOutputs_Nocolset; } + + else if( pIter->pColset->nCol==0 ){ + pIter->xSetOutputs = fts5IterSetOutputs_ZeroColset; + } else if( pConfig->eDetail==FTS5_DETAIL_FULL ){ pIter->xSetOutputs = fts5IterSetOutputs_Full; } @@ -191565,11 +192725,10 @@ assert( pCsr->iLastRowid==LARGEST_INT64 ); assert( pCsr->iFirstRowid==SMALLEST_INT64 ); pCsr->ePlan = FTS5_PLAN_SOURCE; pCsr->pExpr = pTab->pSortCsr->pExpr; rc = fts5CursorFirst(pTab, pCsr, bDesc); - sqlite3Fts5ExprClearEof(pCsr->pExpr); }else if( pMatch ){ const char *zExpr = (const char*)sqlite3_value_text(apVal[0]); if( zExpr==0 ) zExpr = ""; rc = fts5CursorParseRank(pConfig, pCsr, pRank); @@ -192994,11 +194153,11 @@ int nArg, /* Number of args */ sqlite3_value **apUnused /* Function arguments */ ){ assert( nArg==0 ); UNUSED_PARAM2(nArg, apUnused); - sqlite3_result_text(pCtx, "fts5: 2016-05-18 10:57:30 fc49f556e48970561d7ab6a2f24fdd7d9eb81ff2", -1, SQLITE_TRANSIENT); + sqlite3_result_text(pCtx, "fts5: 2016-08-20 18:06:14 9041ee4a6f0e8389297f887f1431ab5cfe783390", -1, SQLITE_TRANSIENT); } static int fts5Init(sqlite3 *db){ static const sqlite3_module fts5Mod = { /* iVersion */ 2, @@ -193359,11 +194518,15 @@ ){ int rc; char *zErr = 0; rc = fts5ExecPrintf(pConfig->db, &zErr, "CREATE TABLE %Q.'%q_%q'(%s)%s", - pConfig->zDb, pConfig->zName, zPost, zDefn, bWithout?" WITHOUT ROWID":"" + pConfig->zDb, pConfig->zName, zPost, zDefn, +#ifndef SQLITE_FTS5_NO_WITHOUT_ROWID + bWithout?" WITHOUT ROWID": +#endif + "" ); if( zErr ){ *pzErr = sqlite3_mprintf( "fts5: error creating shadow table %q_%s: %s", pConfig->zName, zPost, zErr Index: src/sqlite3.h ================================================================== --- src/sqlite3.h +++ src/sqlite3.h @@ -28,12 +28,12 @@ ** The name of this file under configuration management is "sqlite.h.in". ** The makefile makes some minor changes to this file (such as inserting ** the version number) and changes its name to "sqlite3.h" as ** part of the build process. */ -#ifndef _SQLITE3_H_ -#define _SQLITE3_H_ +#ifndef SQLITE3_H +#define SQLITE3_H #include /* Needed for the definition of va_list */ /* ** Make sure we can call this stuff from C++. */ @@ -52,12 +52,21 @@ # define SQLITE_API #endif #ifndef SQLITE_CDECL # define SQLITE_CDECL #endif +#ifndef SQLITE_APICALL +# define SQLITE_APICALL +#endif #ifndef SQLITE_STDCALL -# define SQLITE_STDCALL +# define SQLITE_STDCALL SQLITE_APICALL +#endif +#ifndef SQLITE_CALLBACK +# define SQLITE_CALLBACK +#endif +#ifndef SQLITE_SYSAPI +# define SQLITE_SYSAPI #endif /* ** These no-op macros are used in front of interfaces to mark those ** interfaces as either deprecated or experimental. New applications @@ -109,13 +118,13 @@ ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.13.0" -#define SQLITE_VERSION_NUMBER 3013000 -#define SQLITE_SOURCE_ID "2016-05-18 10:57:30 fc49f556e48970561d7ab6a2f24fdd7d9eb81ff2" +#define SQLITE_VERSION "3.15.0" +#define SQLITE_VERSION_NUMBER 3015000 +#define SQLITE_SOURCE_ID "2016-08-22 20:10:01 7839519349c7371cdb4e16a215eacd27004cbc62" /* ** CAPI3REF: Run-Time Library Version Numbers ** KEYWORDS: sqlite3_version, sqlite3_sourceid ** @@ -504,10 +513,11 @@ #define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT |(10<<8)) #define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) #define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) +#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8)) /* ** CAPI3REF: Flags For File Open Operations ** ** These bit values are intended for use in the @@ -1033,10 +1043,20 @@ ** ** Mutexes are created using [sqlite3_mutex_alloc()]. */ typedef struct sqlite3_mutex sqlite3_mutex; +/* +** CAPI3REF: Loadable Extension Thunk +** +** A pointer to the opaque sqlite3_api_routines structure is passed as +** the third parameter to entry points of [loadable extensions]. This +** structure must be typedefed in order to work around compiler warnings +** on some platforms. +*/ +typedef struct sqlite3_api_routines sqlite3_api_routines; + /* ** CAPI3REF: OS Interface Object ** ** An instance of the sqlite3_vfs object defines the interface between ** the SQLite core and the underlying operating system. The "vfs" @@ -1937,22 +1957,32 @@ ** interface independently of the [load_extension()] SQL function. ** The [sqlite3_enable_load_extension()] API enables or disables both the ** C-API [sqlite3_load_extension()] and the SQL function [load_extension()]. ** There should be two additional arguments. ** When the first argument to this interface is 1, then only the C-API is -** enabled and the SQL function remains disabled. If the first argment to +** enabled and the SQL function remains disabled. If the first argument to ** this interface is 0, then both the C-API and the SQL function are disabled. ** If the first argument is -1, then no changes are made to state of either the ** C-API or the SQL function. ** The second parameter is a pointer to an integer into which ** is written 0 or 1 to indicate whether [sqlite3_load_extension()] interface ** is disabled or enabled following this call. The second parameter may ** be a NULL pointer, in which case the new setting is not reported back. **
    ** +**
    SQLITE_DBCONFIG_MAINDBNAME
    +**
    ^This option is used to change the name of the "main" database +** schema. ^The sole argument is a pointer to a constant UTF8 string +** which will become the new schema name in place of "main". ^SQLite +** does not make a copy of the new main schema name string, so the application +** must ensure that the argument passed into this DBCONFIG option is unchanged +** until after the database connection closes. +**
    +** ** */ +#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ #define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */ #define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */ @@ -2230,11 +2260,11 @@ ** result in undefined behavior. ** ** A busy handler must not close the database connection ** or [prepared statement] that invoked the busy handler. */ -SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*); +SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*); /* ** CAPI3REF: Set A Busy Timeout ** METHOD: sqlite3 ** @@ -2751,10 +2781,13 @@ #define SQLITE_RECURSIVE 33 /* NULL NULL */ /* ** CAPI3REF: Tracing And Profiling Functions ** METHOD: sqlite3 +** +** These routines are deprecated. Use the [sqlite3_trace_v2()] interface +** instead of the routines described here. ** ** These routines register callback functions that can be used for ** tracing and profiling the execution of SQL statements. ** ** ^The callback function registered by sqlite3_trace() is invoked at @@ -2777,13 +2810,107 @@ ** digits in the time are meaningless. Future versions of SQLite ** might provide greater resolution on the profiler callback. The ** sqlite3_profile() function is considered experimental and is ** subject to change in future versions of SQLite. */ -SQLITE_API void *SQLITE_STDCALL sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*); -SQLITE_API SQLITE_EXPERIMENTAL void *SQLITE_STDCALL sqlite3_profile(sqlite3*, +SQLITE_API SQLITE_DEPRECATED void *SQLITE_STDCALL sqlite3_trace(sqlite3*, + void(*xTrace)(void*,const char*), void*); +SQLITE_API SQLITE_DEPRECATED void *SQLITE_STDCALL sqlite3_profile(sqlite3*, void(*xProfile)(void*,const char*,sqlite3_uint64), void*); + +/* +** CAPI3REF: SQL Trace Event Codes +** KEYWORDS: SQLITE_TRACE +** +** These constants identify classes of events that can be monitored +** using the [sqlite3_trace_v2()] tracing logic. The third argument +** to [sqlite3_trace_v2()] is an OR-ed combination of one or more of +** the following constants. ^The first argument to the trace callback +** is one of the following constants. +** +** New tracing constants may be added in future releases. +** +** ^A trace callback has four arguments: xCallback(T,C,P,X). +** ^The T argument is one of the integer type codes above. +** ^The C argument is a copy of the context pointer passed in as the +** fourth argument to [sqlite3_trace_v2()]. +** The P and X arguments are pointers whose meanings depend on T. +** +**
    +** [[SQLITE_TRACE_STMT]]
    SQLITE_TRACE_STMT
    +**
    ^An SQLITE_TRACE_STMT callback is invoked when a prepared statement +** first begins running and possibly at other times during the +** execution of the prepared statement, such as at the start of each +** trigger subprogram. ^The P argument is a pointer to the +** [prepared statement]. ^The X argument is a pointer to a string which +** is the unexpanded SQL text of the prepared statement or an SQL comment +** that indicates the invocation of a trigger. ^The callback can compute +** the same text that would have been returned by the legacy [sqlite3_trace()] +** interface by using the X argument when X begins with "--" and invoking +** [sqlite3_expanded_sql(P)] otherwise. +** +** [[SQLITE_TRACE_PROFILE]]
    SQLITE_TRACE_PROFILE
    +**
    ^An SQLITE_TRACE_PROFILE callback provides approximately the same +** information as is provided by the [sqlite3_profile()] callback. +** ^The P argument is a pointer to the [prepared statement] and the +** X argument points to a 64-bit integer which is the estimated of +** the number of nanosecond that the prepared statement took to run. +** ^The SQLITE_TRACE_PROFILE callback is invoked when the statement finishes. +** +** [[SQLITE_TRACE_ROW]]
    SQLITE_TRACE_ROW
    +**
    ^An SQLITE_TRACE_ROW callback is invoked whenever a prepared +** statement generates a single row of result. +** ^The P argument is a pointer to the [prepared statement] and the +** X argument is unused. +** +** [[SQLITE_TRACE_CLOSE]]
    SQLITE_TRACE_CLOSE
    +**
    ^An SQLITE_TRACE_CLOSE callback is invoked when a database +** connection closes. +** ^The P argument is a pointer to the [database connection] object +** and the X argument is unused. +**
    +*/ +#define SQLITE_TRACE_STMT 0x01 +#define SQLITE_TRACE_PROFILE 0x02 +#define SQLITE_TRACE_ROW 0x04 +#define SQLITE_TRACE_CLOSE 0x08 + +/* +** CAPI3REF: SQL Trace Hook +** METHOD: sqlite3 +** +** ^The sqlite3_trace_v2(D,M,X,P) interface registers a trace callback +** function X against [database connection] D, using property mask M +** and context pointer P. ^If the X callback is +** NULL or if the M mask is zero, then tracing is disabled. The +** M argument should be the bitwise OR-ed combination of +** zero or more [SQLITE_TRACE] constants. +** +** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides +** (cancels) any prior calls to sqlite3_trace() or sqlite3_trace_v2(). +** +** ^The X callback is invoked whenever any of the events identified by +** mask M occur. ^The integer return value from the callback is currently +** ignored, though this may change in future releases. Callback +** implementations should return zero to ensure future compatibility. +** +** ^A trace callback is invoked with four arguments: callback(T,C,P,X). +** ^The T argument is one of the [SQLITE_TRACE] +** constants to indicate why the callback was invoked. +** ^The C argument is a copy of the context pointer. +** The P and X arguments are pointers whose meanings depend on T. +** +** The sqlite3_trace_v2() interface is intended to replace the legacy +** interfaces [sqlite3_trace()] and [sqlite3_profile()], both of which +** are deprecated. +*/ +SQLITE_API int SQLITE_STDCALL sqlite3_trace_v2( + sqlite3*, + unsigned uMask, + int(*xCallback)(unsigned,void*,void*,void*), + void *pCtx +); /* ** CAPI3REF: Query Progress Callbacks ** METHOD: sqlite3 ** @@ -3399,15 +3526,39 @@ /* ** CAPI3REF: Retrieving Statement SQL ** METHOD: sqlite3_stmt ** -** ^This interface can be used to retrieve a saved copy of the original -** SQL text used to create a [prepared statement] if that statement was -** compiled using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()]. +** ^The sqlite3_sql(P) interface returns a pointer to a copy of the UTF-8 +** SQL text used to create [prepared statement] P if P was +** created by either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()]. +** ^The sqlite3_expanded_sql(P) interface returns a pointer to a UTF-8 +** string containing the SQL text of prepared statement P with +** [bound parameters] expanded. +** +** ^(For example, if a prepared statement is created using the SQL +** text "SELECT $abc,:xyz" and if parameter $abc is bound to integer 2345 +** and parameter :xyz is unbound, then sqlite3_sql() will return +** the original string, "SELECT $abc,:xyz" but sqlite3_expanded_sql() +** will return "SELECT 2345,NULL".)^ +** +** ^The sqlite3_expanded_sql() interface returns NULL if insufficient memory +** is available to hold the result, or if the result would exceed the +** the maximum string length determined by the [SQLITE_LIMIT_LENGTH]. +** +** ^The [SQLITE_TRACE_SIZE_LIMIT] compile-time option limits the size of +** bound parameter expansions. ^The [SQLITE_OMIT_TRACE] compile-time +** option causes sqlite3_expanded_sql() to always return NULL. +** +** ^The string returned by sqlite3_sql(P) is managed by SQLite and is +** automatically freed when the prepared statement is finalized. +** ^The string returned by sqlite3_expanded_sql(P), on the other hand, +** is obtained from [sqlite3_malloc()] and must be free by the application +** by passing it to [sqlite3_free()]. */ SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt); +SQLITE_API char *SQLITE_STDCALL sqlite3_expanded_sql(sqlite3_stmt *pStmt); /* ** CAPI3REF: Determine If An SQL Statement Writes The Database ** METHOD: sqlite3_stmt ** @@ -4561,16 +4712,17 @@ ** NULL if the metadata has been discarded. ** ^After each call to sqlite3_set_auxdata(C,N,P,X) where X is not NULL, ** SQLite will invoke the destructor function X with parameter P exactly ** once, when the metadata is discarded. ** SQLite is free to discard the metadata at any time, including:
      -**
    • when the corresponding function parameter changes, or -**
    • when [sqlite3_reset()] or [sqlite3_finalize()] is called for the -** SQL statement, or -**
    • when sqlite3_set_auxdata() is invoked again on the same parameter, or -**
    • during the original sqlite3_set_auxdata() call when a memory -** allocation error occurs.
    )^ +**
  12. ^(when the corresponding function parameter changes)^, or +**
  13. ^(when [sqlite3_reset()] or [sqlite3_finalize()] is called for the +** SQL statement)^, or +**
  14. ^(when sqlite3_set_auxdata() is invoked again on the same +** parameter)^, or +**
  15. ^(during the original sqlite3_set_auxdata() call when a memory +** allocation error occurs.)^ ** ** Note the last bullet in particular. The destructor X in ** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the ** sqlite3_set_auxdata() interface even returns. Hence sqlite3_set_auxdata() ** should be called near the end of the function implementation and the @@ -5393,11 +5545,11 @@ ** interface returns SQLITE_OK and fills in the non-NULL pointers in ** the final five arguments with appropriate values if the specified ** column exists. ^The sqlite3_table_column_metadata() interface returns ** SQLITE_ERROR and if the specified column does not exist. ** ^If the column-name parameter to sqlite3_table_column_metadata() is a -** NULL pointer, then this routine simply checks for the existance of the +** NULL pointer, then this routine simply checks for the existence of the ** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it ** does not. ** ** ^The column is identified by the second, third and fourth parameters to ** this function. ^(The second parameter is either the name of the database @@ -5527,12 +5679,12 @@ ** to turn extension loading on and call it with onoff==0 to turn ** it back off again. ** ** ^This interface enables or disables both the C-API ** [sqlite3_load_extension()] and the SQL function [load_extension()]. -** Use [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],..) -** to enable or disable only the C-API. +** ^(Use [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],..) +** to enable or disable only the C-API.)^ ** ** Security warning: It is recommended that extension loading ** be disabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method ** rather than this interface, so the [load_extension()] SQL function ** remains disabled. This will prevent SQL injections from giving attackers @@ -5548,11 +5700,11 @@ ** xEntryPoint() is the entry point for a statically linked [SQLite extension] ** that is to be automatically loaded into all new database connections. ** ** ^(Even though the function prototype shows that xEntryPoint() takes ** no arguments and returns void, SQLite invokes xEntryPoint() with three -** arguments and expects and integer result as if the signature of the +** arguments and expects an integer result as if the signature of the ** entry point where as follows: ** **
     **    int xEntryPoint(
     **      sqlite3 *db,
    @@ -5574,11 +5726,11 @@
     ** will be called more than once for each database connection that is opened.
     **
     ** See also: [sqlite3_reset_auto_extension()]
     ** and [sqlite3_cancel_auto_extension()]
     */
    -SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xEntryPoint)(void));
    +SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void(*xEntryPoint)(void));
     
     /*
     ** CAPI3REF: Cancel Automatic Extension Loading
     **
     ** ^The [sqlite3_cancel_auto_extension(X)] interface unregisters the
    @@ -5586,11 +5738,11 @@
     ** [sqlite3_auto_extension(X)].  ^The [sqlite3_cancel_auto_extension(X)]
     ** routine returns 1 if initialization routine X was successfully 
     ** unregistered and it returns 0 if X was not on the list of initialization
     ** routines.
     */
    -SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xEntryPoint)(void));
    +SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void(*xEntryPoint)(void));
     
     /*
     ** CAPI3REF: Reset Automatic Extension Loading
     **
     ** ^This interface disables all automatic extensions previously
    @@ -6762,10 +6914,22 @@
     ** [[SQLITE_DBSTATUS_CACHE_USED]] ^(
    SQLITE_DBSTATUS_CACHE_USED
    **
    This parameter returns the approximate number of bytes of heap ** memory used by all pager caches associated with the database connection.)^ ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0. ** +** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]] +** ^(
    SQLITE_DBSTATUS_CACHE_USED_SHARED
    +**
    This parameter is similar to DBSTATUS_CACHE_USED, except that if a +** pager cache is shared between two or more connections the bytes of heap +** memory used by that pager cache is divided evenly between the attached +** connections.)^ In other words, if none of the pager caches associated +** with the database connection are shared, this request returns the same +** value as DBSTATUS_CACHE_USED. Or, if one or more or the pager caches are +** shared, the value returned by this call will be smaller than that returned +** by DBSTATUS_CACHE_USED. ^The highwater mark associated with +** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0. +** ** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(
    SQLITE_DBSTATUS_SCHEMA_USED
    **
    This parameter returns the approximate number of bytes of heap ** memory used to store the schema for all databases associated ** with the connection - main, temp, and any [ATTACH]-ed databases.)^ ** ^The full amount of memory used by the schemas is reported, even if the @@ -6819,11 +6983,12 @@ #define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL 6 #define SQLITE_DBSTATUS_CACHE_HIT 7 #define SQLITE_DBSTATUS_CACHE_MISS 8 #define SQLITE_DBSTATUS_CACHE_WRITE 9 #define SQLITE_DBSTATUS_DEFERRED_FKS 10 -#define SQLITE_DBSTATUS_MAX 10 /* Largest defined DBSTATUS */ +#define SQLITE_DBSTATUS_CACHE_USED_SHARED 11 +#define SQLITE_DBSTATUS_MAX 11 /* Largest defined DBSTATUS */ /* ** CAPI3REF: Prepared Statement Status ** METHOD: sqlite3_stmt @@ -7975,11 +8140,11 @@ ** tables. ** ** ^The second parameter to the preupdate callback is a pointer to ** the [database connection] that registered the preupdate hook. ** ^The third parameter to the preupdate callback is one of the constants -** [SQLITE_INSERT], [SQLITE_DELETE], or [SQLITE_UPDATE] to indentify the +** [SQLITE_INSERT], [SQLITE_DELETE], or [SQLITE_UPDATE] to identify the ** kind of update operation that is about to occur. ** ^(The fourth parameter to the preupdate callback is the name of the ** database within the database connection that is being modified. This ** will be "main" for the main database or "temp" for TEMP tables or ** the name given after the AS keyword in the [ATTACH] statement for attached @@ -8202,11 +8367,11 @@ #endif #ifdef __cplusplus } /* End of the 'extern "C"' block */ #endif -#endif /* _SQLITE3_H_ */ +#endif /* SQLITE3_H */ /******** Begin file sqlite3rtree.h *********/ /* ** 2010 August 30 ** @@ -9922,11 +10087,11 @@ ** following structure. All structure methods must be defined, setting ** any member of the fts5_tokenizer struct to NULL leads to undefined ** behaviour. The structure methods are expected to function as follows: ** ** xCreate: -** This function is used to allocate and inititalize a tokenizer instance. +** This function is used to allocate and initialize a tokenizer instance. ** A tokenizer instance is required to actually tokenize text. ** ** The first argument passed to this function is a copy of the (void*) ** pointer provided by the application when the fts5_tokenizer object ** was registered with FTS5 (the third argument to xCreateTokenizer()). @@ -10181,8 +10346,7 @@ #ifdef __cplusplus } /* end of the 'extern "C"' block */ #endif #endif /* _FTS5_H */ - /******** End of fts5.h *********/ Index: src/stash.c ================================================================== --- src/stash.c +++ src/stash.c @@ -23,17 +23,17 @@ /* ** SQL code to implement the tables needed by the stash. */ static const char zStashInit[] = -@ CREATE TABLE IF NOT EXISTS "%w".stash( +@ CREATE TABLE IF NOT EXISTS localdb.stash( @ stashid INTEGER PRIMARY KEY, -- Unique stash identifier @ vid INTEGER, -- The baseline check-out for this stash @ comment TEXT, -- Comment for this stash. Or NULL @ ctime TIMESTAMP -- When the stash was created @ ); -@ CREATE TABLE IF NOT EXISTS "%w".stashfile( +@ CREATE TABLE IF NOT EXISTS localdb.stashfile( @ stashid INTEGER REFERENCES stash, -- Stash that contains this file @ rid INTEGER, -- Baseline content in BLOB table or 0. @ isAdded BOOLEAN, -- True if this is an added file @ isRemoved BOOLEAN, -- True if this file is deleted @ isExec BOOLEAN, -- True if file is executable @@ -477,21 +477,19 @@ ** fossil stash goto ?STASHID? ** fossil stash rm|drop ?STASHID? ?-a|--all? ** fossil stash [g]diff ?STASHID? ?DIFF-OPTIONS? */ void stash_cmd(void){ - const char *zDb; const char *zCmd; int nCmd; int stashid = 0; int rc; undo_capture_command_line(); db_must_be_within_tree(); db_open_config(0, 0); db_begin_transaction(); - zDb = db_name("localdb"); - db_multi_exec(zStashInit /*works-like:"%w,%w"*/, zDb, zDb); + db_multi_exec(zStashInit /*works-like:""*/); rc = db_exists("SELECT 1 FROM sqlite_master" " WHERE name='stashfile'" " AND sql GLOB '* PRIMARY KEY(origname, stashid)*'"); if( rc!=0 ){ db_multi_exec( Index: src/stat.c ================================================================== --- src/stat.c +++ src/stat.c @@ -61,11 +61,10 @@ */ void stat_page(void){ i64 t, fsize; int n, m; int szMax, szAvg; - const char *zDb; int brief; char zBuf[100]; const char *p; login_check_credentials(); @@ -120,10 +119,31 @@ b = 1; } a = t/fsize; @ %d(a):%d(b) @ + } + if( db_table_exists("repository","unversioned") ){ + Stmt q; + char zStored[100]; + db_prepare(&q, + "SELECT count(*), sum(sz), sum(length(content))" + " FROM unversioned" + " WHERE length(hash)>1" + ); + if( db_step(&q)==SQLITE_ROW && (n = db_column_int(&q,0))>0 ){ + sqlite3_int64 iSz, iStored; + iSz = db_column_int64(&q,1); + iStored = db_column_int64(&q,2); + approxSizeName(sizeof(zBuf), zBuf, iSz); + approxSizeName(sizeof(zStored), zStored, iStored); + @ Unversioned Files: + @ %z(href("%R/uvlist"))%d(n) files, + @ total size %s(zBuf) uncompressed, %s(zStored) compressed + @ + } + db_finalize(&q); } @ Number Of Check-ins: n = db_int(0, "SELECT count(*) FROM event WHERE type='ci' /*scan*/"); @ %d(n) @ @@ -147,13 +167,19 @@ " + 0.99"); @ %d(n) days or approximately %.2f(n/365.2425) years. @ p = db_get("project-code", 0); if( p ){ - @ Project ID:%h(p) + @ Project ID: + @ %h(p) %h(db_get("project-name","")) + } + p = db_get("parent-project-code", 0); + if( p ){ + @ Parent Project ID: + @ %h(p) %h(db_get("parent-project-name","")) } - @ Server ID:%h(db_get("server-code","")) + /* @ Server ID:%h(db_get("server-code","")) */ @ Fossil Version: @ %h(MANIFEST_DATE) %h(MANIFEST_VERSION) @ (%h(RELEASE_VERSION)) [compiled using %h(COMPILER_NAME)] @ @ SQLite Version:%.19s(sqlite3_sourceid()) @@ -161,16 +187,15 @@ @ Schema Version:%h(g.zAuxSchema) @ Repository Rebuilt: @ %h(db_get_mtime("rebuilt","%Y-%m-%d %H:%M:%S","Never")) @ By Fossil %h(db_get("rebuilt","Unknown")) @ Database Stats: - zDb = db_name("repository"); - @ %d(db_int(0, "PRAGMA \"%w\".page_count", zDb)) pages, - @ %d(db_int(0, "PRAGMA \"%w\".page_size", zDb)) bytes/page, - @ %d(db_int(0, "PRAGMA \"%w\".freelist_count", zDb)) free pages, - @ %s(db_text(0, "PRAGMA \"%w\".encoding", zDb)), - @ %s(db_text(0, "PRAGMA \"%w\".journal_mode", zDb)) mode + @ %d(db_int(0, "PRAGMA repository.page_count")) pages, + @ %d(db_int(0, "PRAGMA repository.page_size")) bytes/page, + @ %d(db_int(0, "PRAGMA repository.freelist_count")) free pages, + @ %s(db_text(0, "PRAGMA repository.encoding")), + @ %s(db_text(0, "PRAGMA repository.journal_mode")) mode @ @ style_footer(); } @@ -190,11 +215,10 @@ */ void dbstat_cmd(void){ i64 t, fsize; int n, m; int szMax, szAvg; - const char *zDb; int brief; int omitVers; /* Omit Fossil and SQLite version information */ int dbCheck; /* True for the --db-check option */ char zBuf[100]; const int colWidth = -19 /* printf alignment/width for left column */; @@ -289,19 +313,18 @@ fossil_print("%*s%.19s [%.10s] (%s)\n", colWidth, "sqlite-version:", sqlite3_sourceid(), &sqlite3_sourceid()[20], sqlite3_libversion()); } - zDb = db_name("repository"); fossil_print("%*s%d pages, %d bytes/pg, %d free pages, " "%s, %s mode\n", colWidth, "database-stats:", - db_int(0, "PRAGMA \"%w\".page_count", zDb), - db_int(0, "PRAGMA \"%w\".page_size", zDb), - db_int(0, "PRAGMA \"%w\".freelist_count", zDb), - db_text(0, "PRAGMA \"%w\".encoding", zDb), - db_text(0, "PRAGMA \"%w\".journal_mode", zDb)); + db_int(0, "PRAGMA repository.page_count"), + db_int(0, "PRAGMA repository.page_size"), + db_int(0, "PRAGMA repository.freelist_count"), + db_text(0, "PRAGMA repository.encoding"), + db_text(0, "PRAGMA repository.journal_mode")); if( dbCheck ){ fossil_print("%*s%s\n", colWidth, "database-check:", db_text(0, "PRAGMA quick_check(1)")); } } @@ -369,12 +392,12 @@ style_submenu_element("Stat", "Repository Stats", "stat"); style_submenu_element("URLs", "URLs and Checkouts", "urllist"); if( sqlite3_compileoption_used("ENABLE_DBSTAT_VTAB") ){ style_submenu_element("Table Sizes", 0, "repo-tabsize"); } - db_prepare(&q, "SELECT sql FROM %s.sqlite_master WHERE sql IS NOT NULL", - db_name("repository")); + db_prepare(&q, + "SELECT sql FROM repository.sqlite_master WHERE sql IS NOT NULL"); @
       while( db_step(&q)==SQLITE_ROW ){
         @ %h(db_column_text(&q, 0));
       }
       @ 
    @@ -399,23 +422,22 @@ style_submenu_element("Stat", "Repository Stats", "stat"); if( g.perm.Admin ){ style_submenu_element("Schema", "Repository Schema", "repo_schema"); } db_multi_exec( - "CREATE VIRTUAL TABLE temp.dbx USING dbstat(%s);" + "CREATE VIRTUAL TABLE temp.dbx USING dbstat(repository);" "CREATE TEMP TABLE trans(name TEXT PRIMARY KEY,tabname TEXT)WITHOUT ROWID;" "INSERT INTO trans(name,tabname)" - " SELECT name, tbl_name FROM %s.sqlite_master;" + " SELECT name, tbl_name FROM repository.sqlite_master;" "CREATE TEMP TABLE piechart(amt REAL, label TEXT);" "INSERT INTO piechart(amt,label)" " SELECT count(*), " " coalesce((SELECT tabname FROM trans WHERE trans.name=dbx.name),name)" " FROM dbx" - " GROUP BY 2 ORDER BY 2;", - db_name("repository"), db_name("repository") + " GROUP BY 2 ORDER BY 2;" ); - nPageFree = db_int(0, "PRAGMA \"%w\".freelist_count", db_name("repository")); + nPageFree = db_int(0, "PRAGMA repository.freelist_count"); if( nPageFree>0 ){ db_multi_exec( "INSERT INTO piechart(amt,label) VALUES(%d,'freelist')", nPageFree ); @@ -428,23 +450,22 @@ @ if( g.localOpen ){ db_multi_exec( "DROP TABLE temp.dbx;" - "CREATE VIRTUAL TABLE temp.dbx USING dbstat(%s);" + "CREATE VIRTUAL TABLE temp.dbx USING dbstat(localdb);" "DELETE FROM trans;" "INSERT INTO trans(name,tabname)" - " SELECT name, tbl_name FROM %s.sqlite_master;" + " SELECT name, tbl_name FROM localdb.sqlite_master;" "DELETE FROM piechart;" "INSERT INTO piechart(amt,label)" " SELECT count(*), " " coalesce((SELECT tabname FROM trans WHERE trans.name=dbx.name),name)" " FROM dbx" - " GROUP BY 2 ORDER BY 2;", - db_name("localdb"), db_name("localdb") + " GROUP BY 2 ORDER BY 2;" ); - nPageFree = db_int(0, "PRAGMA \"%s\".freelist_count", db_name("localdb")); + nPageFree = db_int(0, "PRAGMA localdb.freelist_count"); if( nPageFree>0 ){ db_multi_exec( "INSERT INTO piechart(amt,label) VALUES(%d,'freelist')", nPageFree ); Index: src/style.c ================================================================== --- src/style.c +++ src/style.c @@ -1561,11 +1561,14 @@ "HTTP_USER_AGENT", "HTTP_REFERER", "PATH_INFO", "PATH_TRANSLATED", "QUERY_STRING", "REMOTE_ADDR", "REMOTE_PORT", "REQUEST_METHOD", "REQUEST_URI", "SCRIPT_FILENAME", "SCRIPT_NAME", "SERVER_PROTOCOL", "HOME", "FOSSIL_HOME", "USERNAME", "USER", "FOSSIL_USER", "SQLITE_TMPDIR", "TMPDIR", - "TEMP", "TMP", "FOSSIL_VFS" + "TEMP", "TMP", "FOSSIL_VFS", + "FOSSIL_FORCE_TICKET_MODERATION", "FOSSIL_FORCE_WIKI_MODERATION", + "FOSSIL_TCL_PATH", "TH1_DELETE_INTERP", "TH1_ENABLE_DOCS", + "TH1_ENABLE_HOOKS", "TH1_ENABLE_TCL", "REMOTE_HOST" }; login_check_credentials(); if( !g.perm.Admin && !g.perm.Setup && !db_get_boolean("test_env_enable",0) ){ login_needed(0); Index: src/sync.c ================================================================== --- src/sync.c +++ src/sync.c @@ -113,11 +113,15 @@ ** This routine processes the command-line argument for push, pull, ** and sync. If a command-line argument is given, that is the URL ** of a server to sync against. If no argument is given, use the ** most recently synced URL. Remember the current URL for next time. */ -static void process_sync_args(unsigned *pConfigFlags, unsigned *pSyncFlags){ +static void process_sync_args( + unsigned *pConfigFlags, /* Write configuration flags here */ + unsigned *pSyncFlags, /* Write sync flags here */ + int uvOnly /* Special handling flags for UV sync */ +){ const char *zUrl = 0; const char *zHttpAuth = 0; unsigned configSync = 0; unsigned urlFlags = URL_REMEMBER | URL_PROMPT_PW; int urlOptional = 0; @@ -125,25 +129,31 @@ urlOptional = 1; urlFlags = 0; } zHttpAuth = find_option("httpauth","B",1); if( find_option("once",0,0)!=0 ) urlFlags &= ~URL_REMEMBER; + if( (*pSyncFlags) & SYNC_FROMPARENT ) urlFlags &= ~URL_REMEMBER; + if( !uvOnly ){ + if( find_option("private",0,0)!=0 ){ + *pSyncFlags |= SYNC_PRIVATE; + } + /* The --verily option to sync, push, and pull forces extra igot cards + ** to be exchanged. This can overcome malfunctions in the sync protocol. + */ + if( find_option("verily",0,0)!=0 ){ + *pSyncFlags |= SYNC_RESYNC; + } + } if( find_option("private",0,0)!=0 ){ *pSyncFlags |= SYNC_PRIVATE; } if( find_option("verbose","v",0)!=0 ){ *pSyncFlags |= SYNC_VERBOSE; } - /* The --verily option to sync, push, and pull forces extra igot cards - ** to be exchanged. This can overcome malfunctions in the sync protocol. - */ - if( find_option("verily",0,0)!=0 ){ - *pSyncFlags |= SYNC_RESYNC; - } url_proxy_options(); clone_ssh_find_options(); - db_find_and_open_repository(0, 0); + if( !uvOnly ) db_find_and_open_repository(0, 0); db_open_config(0, 0); if( g.argc==2 ){ if( db_get_boolean("auto-shun",1) ) configSync = CONFIGSET_SHUN; }else if( g.argc==3 ){ zUrl = g.argv[2]; @@ -177,11 +187,11 @@ ** ** Usage: %fossil pull ?URL? ?options? ** ** Pull all sharable changes from a remote repository into the local repository. ** Sharable changes include public check-ins, and wiki, ticket, and tech-note -** edits. Add the --private option to pull private branches. Use the +** edits. Add the --private option to pull private branches. Use the ** "configuration pull" command to pull website configuration details. ** ** If URL is not specified, then the URL from the most recent clone, push, ** pull, remote-url, or sync command is used. See "fossil help clone" for ** details on the URL formats. @@ -188,10 +198,11 @@ ** ** Options: ** ** -B|--httpauth USER:PASS Credentials for the simple HTTP auth protocol, ** if required by the remote website +** --from-parent-project Pull content from the parent project ** --ipv4 Use only IPv4, not IPv6 ** --once Do not remember URL for subsequent syncs ** --proxy PROXY Use the specified HTTP proxy ** --private Pull private branches too ** -R|--repository REPO Repository to pull into @@ -204,11 +215,14 @@ ** See also: clone, config pull, push, remote-url, sync */ void pull_cmd(void){ unsigned configFlags = 0; unsigned syncFlags = SYNC_PULL; - process_sync_args(&configFlags, &syncFlags); + if( find_option("from-parent-project",0,0)!=0 ){ + syncFlags |= SYNC_FROMPARENT; + } + process_sync_args(&configFlags, &syncFlags, 0); /* We should be done with options.. */ verify_all_options(); client_sync(syncFlags, configFlags, 0); @@ -219,12 +233,12 @@ ** ** Usage: %fossil push ?URL? ?options? ** ** Push all sharable changes from the local repository to a remote repository. ** Sharable changes include public check-ins, and wiki, ticket, and tech-note -** edits. Use --private to also push private branches. Use the -** "configuration pull" command to push website configuration details. +** edits. Use --private to also push private branches. Use the +** "configuration push" command to push website configuration details. ** ** If URL is not specified, then the URL from the most recent clone, push, ** pull, remote-url, or sync command is used. See "fossil help clone" for ** details on the URL formats. ** @@ -233,11 +247,11 @@ ** -B|--httpauth USER:PASS Credentials for the simple HTTP auth protocol, ** if required by the remote website ** --ipv4 Use only IPv4, not IPv6 ** --once Do not remember URL for subsequent syncs ** --proxy PROXY Use the specified HTTP proxy -** --private Pull private branches too +** --private Push private branches too ** -R|--repository REPO Repository to pull into ** --ssl-identity FILE Local SSL credentials, if requested by remote ** --ssh-command SSH Use SSH as the "ssh" command ** -v|--verbose Additional (debugging) output ** --verily Exchange extra information with the remote @@ -246,11 +260,11 @@ ** See also: clone, config push, pull, remote-url, sync */ void push_cmd(void){ unsigned configFlags = 0; unsigned syncFlags = SYNC_PUSH; - process_sync_args(&configFlags, &syncFlags); + process_sync_args(&configFlags, &syncFlags, 0); /* We should be done with options.. */ verify_all_options(); if( db_get_boolean("dont-push",0) ){ @@ -263,11 +277,11 @@ /* ** COMMAND: sync ** ** Usage: %fossil sync ?URL? ?options? ** -** Synchronize all sharable changes between the local repository and a a +** Synchronize all sharable changes between the local repository and a ** remote repository. Sharable changes include public check-ins and ** edits to wiki pages, tickets, and technical notes. ** ** If URL is not specified, then the URL from the most recent clone, push, ** pull, remote-url, or sync command is used. See "fossil help clone" for @@ -278,24 +292,28 @@ ** -B|--httpauth USER:PASS Credentials for the simple HTTP auth protocol, ** if required by the remote website ** --ipv4 Use only IPv4, not IPv6 ** --once Do not remember URL for subsequent syncs ** --proxy PROXY Use the specified HTTP proxy -** --private Pull private branches too +** --private Sync private branches too ** -R|--repository REPO Repository to pull into ** --ssl-identity FILE Local SSL credentials, if requested by remote ** --ssh-command SSH Use SSH as the "ssh" command +** -u|--unversioned Also sync unversioned content ** -v|--verbose Additional (debugging) output ** --verily Exchange extra information with the remote ** to ensure no content is overlooked ** ** See also: clone, pull, push, remote-url */ void sync_cmd(void){ unsigned configFlags = 0; unsigned syncFlags = SYNC_PUSH|SYNC_PULL; - process_sync_args(&configFlags, &syncFlags); + if( find_option("unversioned","u",0)!=0 ){ + syncFlags |= SYNC_UNVERSIONED; + } + process_sync_args(&configFlags, &syncFlags, 0); /* We should be done with options.. */ verify_all_options(); if( db_get_boolean("dont-push",0) ) syncFlags &= ~SYNC_PUSH; @@ -302,10 +320,22 @@ client_sync(syncFlags, configFlags, 0); if( (syncFlags & SYNC_PUSH)==0 ){ fossil_warning("pull only: the 'dont-push' option is set"); } } + +/* +** Handle the "fossil unversioned sync" and "fossil unversioned revert" +** commands. +*/ +void sync_unversioned(unsigned syncFlags){ + unsigned configFlags = 0; + (void)find_option("uv-noop",0,0); + process_sync_args(&configFlags, &syncFlags, 1); + verify_all_options(); + client_sync(syncFlags, 0, 0); +} /* ** COMMAND: remote-url ** ** Usage: %fossil remote-url ?URL|off? Index: src/tag.c ================================================================== --- src/tag.c +++ src/tag.c @@ -382,11 +382,11 @@ ** --propagate Propagating tag. ** --date-override DATETIME Set date and time added. ** --user-override USER Name USER when adding the tag. ** --dryrun|-n Display the tag text, but to not ** actually insert it into the database. -** +** ** The --date-override and --user-override options support ** importing history from other SCM systems. DATETIME has ** the form 'YYYY-MMM-DD HH:MM:SS'. ** ** %fossil tag cancel ?--raw? TAGNAME CHECK-IN @@ -398,11 +398,11 @@ ** %fossil tag find ?OPTIONS? TAGNAME ** ** List all objects that use TAGNAME. TYPE can be "ci" for ** check-ins or "e" for events. The limit option limits the number ** of results to the given value. -** +** ** Options: ** --raw Raw tag name. ** -t|--type TYPE One of "ci", or "e". ** -n|--limit N Limit to N results. ** Index: src/th_main.c ================================================================== --- src/th_main.c +++ src/th_main.c @@ -636,19 +636,25 @@ void *p, int argc, const char **argv, int *argl ){ - int rc = 0, i; + int rc = 1, i; + char *zCapList = 0; + int nCapList = 0; if( argc<2 ){ return Th_WrongNumArgs(interp, "hascap STRING ..."); } - for(i=1; i %d
    \n", argl[1], argv[1], rc); + Th_Trace("[%s %#h] => %d
    \n", argv[0], nCapList, zCapList, rc); + Th_Free(interp, zCapList); } Th_SetResultInt(interp, rc); return TH_OK; } @@ -878,11 +884,11 @@ } for(i=0; rc==0 && i %d
    \n", argl[1], argv[1], rc); + Th_Trace("[anycap %#h] => %d
    \n", argl[1], argv[1], rc); } Th_SetResultInt(interp, rc); return TH_OK; } @@ -1428,11 +1434,23 @@ Th_SetResult(interp, (const char *)zOut, -1); return TH_OK; } /* -** TH1 command: query SQL CODE +** Run sqlite3_step() while suppressing error messages sent to the +** rendered webpage or to the console. +*/ +static int ignore_errors_step(sqlite3_stmt *pStmt){ + int rc; + g.dbIgnoreErrors++; + rc = sqlite3_step(pStmt); + g.dbIgnoreErrors--; + return rc; +} + +/* +** TH1 command: query [-nocomplain] SQL CODE ** ** Run the SQL query given by the SQL argument. For each row in the result ** set, run CODE. ** ** In SQL, parameters such as $var are filled in using the value of variable @@ -1453,26 +1471,37 @@ const char *zTail; int n, i; int res = TH_OK; int nVar; char *zErr = 0; + int noComplain = 0; + if( argc>3 && argl[1]==11 && strncmp(argv[1], "-nocomplain", 11)==0 ){ + argc--; + argv++; + argl++; + noComplain = 1; + } if( argc!=3 ){ return Th_WrongNumArgs(interp, "query SQL CODE"); } if( g.db==0 ){ + if( noComplain ) return TH_OK; Th_ErrorMessage(interp, "database is not open", 0, 0); return TH_ERROR; } zSql = argv[1]; nSql = argl[1]; while( res==TH_OK && nSql>0 ){ zErr = 0; sqlite3_set_authorizer(g.db, report_query_authorizer, (void*)&zErr); + g.dbIgnoreErrors++; rc = sqlite3_prepare_v2(g.db, argv[1], argl[1], &pStmt, &zTail); + g.dbIgnoreErrors--; sqlite3_set_authorizer(g.db, 0, 0); if( rc!=0 || zErr!=0 ){ + if( noComplain ) return TH_OK; Th_ErrorMessage(interp, "SQL error: ", zErr ? zErr : sqlite3_errmsg(g.db), -1); return TH_ERROR; } n = (int)(zTail - zSql); @@ -1488,11 +1517,11 @@ int nVal; const char *zVal = Th_GetResult(interp, &nVal); sqlite3_bind_text(pStmt, i, zVal, nVal, SQLITE_TRANSIENT); } } - while( res==TH_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ + while( res==TH_OK && ignore_errors_step(pStmt)==SQLITE_ROW ){ int nCol = sqlite3_column_count(pStmt); for(i=0; i +#if defined(FOSSIL_ENABLE_MINIZ) +# define MINIZ_HEADER_FILE_ONLY +# include "miniz.c" +#else +# include +#endif +#include "unversioned.h" +#include + +/* +** SQL code to implement the tables needed by the unversioned. +*/ +static const char zUnversionedInit[] = +@ CREATE TABLE IF NOT EXISTS repository.unversioned( +@ uvid INTEGER PRIMARY KEY AUTOINCREMENT, -- unique ID for this file +@ name TEXT UNIQUE, -- Name of the uv file +@ rcvid INTEGER, -- Where received from +@ mtime DATETIME, -- timestamp. Seconds since 1970. +@ hash TEXT, -- Content hash. NULL if a delete marker +@ sz INTEGER, -- size of content after decompression +@ encoding INT, -- 0: plaintext. 1: zlib compressed +@ content BLOB -- content of the file. NULL if oversized +@ ); +; + +/* +** Make sure the unversioned table exists in the repository. +*/ +void unversioned_schema(void){ + if( !db_table_exists("repository", "unversioned") ){ + db_multi_exec(zUnversionedInit/*works-like:""*/); + } +} + +/* +** Return a string which is the hash of the unversioned content. +** This is the hash used by repositories to compare content before +** exchanging a catalog. So all repositories must compute this hash +** in exactly the same way. +** +** If debugFlag is set, force the value to be recomputed and write +** the text of the hashed string to stdout. +*/ +const char *unversioned_content_hash(int debugFlag){ + const char *zHash = debugFlag ? 0 : db_get("uv-hash", 0); + if( zHash==0 ){ + Stmt q; + db_prepare(&q, + "SELECT printf('%%s %%s %%s\n',name,datetime(mtime,'unixepoch'),hash)" + " FROM unversioned" + " WHERE hash IS NOT NULL" + " ORDER BY name" + ); + while( db_step(&q)==SQLITE_ROW ){ + const char *z = db_column_text(&q, 0); + if( debugFlag ) fossil_print("%s", z); + sha1sum_step_text(z,-1); + } + db_finalize(&q); + db_set("uv-hash", sha1sum_finish(0), 0); + zHash = db_get("uv-hash",0); + } + return zHash; +} + +/* +** Initialize pContent to be the content of an unversioned file zName. +** +** Return 0 on success. Return 1 if zName is not found. +*/ +int unversioned_content(const char *zName, Blob *pContent){ + Stmt q; + int rc = 1; + blob_init(pContent, 0, 0); + db_prepare(&q, "SELECT encoding, content FROM unversioned WHERE name=%Q", zName); + if( db_step(&q)==SQLITE_ROW ){ + db_column_blob(&q, 1, pContent); + if( db_column_int(&q, 0)==1 ){ + blob_uncompress(pContent, pContent); + } + rc = 0; + } + db_finalize(&q); + return rc; +} + +/* +** Write unversioned content into the database. +*/ +static void unversioned_write( + const char *zUVFile, /* Name of the unversioned file */ + Blob *pContent, /* File content */ + sqlite3_int64 mtime /* Modification time */ +){ + Stmt ins; + Blob compressed; + Blob hash; + + db_prepare(&ins, + "REPLACE INTO unversioned(name,rcvid,mtime,hash,sz,encoding,content)" + " VALUES(:name,:rcvid,:mtime,:hash,:sz,:encoding,:content)" + ); + sha1sum_blob(pContent, &hash); + blob_compress(pContent, &compressed); + db_bind_text(&ins, ":name", zUVFile); + db_bind_int(&ins, ":rcvid", g.rcvid); + db_bind_int64(&ins, ":mtime", mtime); + db_bind_text(&ins, ":hash", blob_str(&hash)); + db_bind_int(&ins, ":sz", blob_size(pContent)); + if( blob_size(&compressed) <= 0.8*blob_size(pContent) ){ + db_bind_int(&ins, ":encoding", 1); + db_bind_blob(&ins, ":content", &compressed); + }else{ + db_bind_int(&ins, ":encoding", 0); + db_bind_blob(&ins, ":content", pContent); + } + db_step(&ins); + blob_reset(&compressed); + blob_reset(&hash); + db_finalize(&ins); + db_unset("uv-hash", 0); +} + + +/* +** Check the status of unversioned file zName. Return an integer status +** code as follows: +** +** 0: zName does not exist in the unversioned table. +** 1: zName exists and should be replaced by mtime/zHash. +** 2: zName exists and is the same as zHash but has a older mtime +** 3: zName exists and is identical to mtime/zHash in all respects. +** 4: zName exists and is the same as zHash but has a newer mtime. +** 5: zName exists and should override mtime/zHash. +*/ +int unversioned_status(const char *zName, sqlite3_int64 mtime, const char *zHash){ + int iStatus = 0; + Stmt q; + db_prepare(&q, "SELECT mtime, hash FROM unversioned WHERE name=%Q", zName); + if( db_step(&q)==SQLITE_ROW ){ + const char *zLocalHash = db_column_text(&q, 1); + int hashCmp; + sqlite3_int64 iLocalMtime = db_column_int64(&q, 0); + int mtimeCmp = iLocalMtime=3 ? g.argv[2] : "x"; + nCmd = (int)strlen(zCmd); + if( zMtime==0 ){ + mtime = time(0); + }else{ + mtime = db_int(0, "SELECT strftime('%%s',%Q)", zMtime); + if( mtime<=0 ) fossil_fatal("bad timestamp: %Q", zMtime); + } + if( memcmp(zCmd, "add", nCmd)==0 ){ + const char *zIn; + const char *zAs; + Blob file; + int i; + + zAs = find_option("as",0,1); + if( zAs && g.argc!=4 ) usage("add DISKFILE --as UVFILE"); + verify_all_options(); + db_begin_transaction(); + content_rcvid_init("#!fossil unversioned add"); + for(i=3; i1 && zCmd[1]=='i'); + verify_all_options(); + if( !longFlag ){ + if( allFlag ){ + db_prepare(&q, "SELECT name FROM unversioned ORDER BY name"); + }else{ + db_prepare(&q, "SELECT name FROM unversioned WHERE hash IS NOT NULL" + " ORDER BY name"); + } + while( db_step(&q)==SQLITE_ROW ){ + fossil_print("%s\n", db_column_text(&q,0)); + } + }else{ + db_prepare(&q, + "SELECT hash, datetime(mtime,'unixepoch'), sz, length(content), name" + " FROM unversioned" + " ORDER BY name;" + ); + while( db_step(&q)==SQLITE_ROW ){ + const char *zHash = db_column_text(&q, 0); + const char *zNoContent = ""; + if( zHash==0 ){ + if( !allFlag ) continue; + zHash = "(deleted)"; + }else if( db_column_type(&q,3)==SQLITE_NULL ){ + zNoContent = " (no content)"; + } + fossil_print("%12.12s %s %8d %8d %s%s\n", + zHash, + db_column_text(&q,1), + db_column_int(&q,2), + db_column_int(&q,3), + db_column_text(&q,4), + zNoContent + ); + } + } + db_finalize(&q); + }else if( memcmp(zCmd, "revert", nCmd)==0 ){ + g.argv[1] = "sync"; + g.argv[2] = "--uv-noop"; + sync_unversioned(SYNC_UNVERSIONED|SYNC_UV_REVERT); + }else if( memcmp(zCmd, "rm", nCmd)==0 ){ + int i; + verify_all_options(); + db_begin_transaction(); + for(i=3; i + @ + @ + @ + @ + } + @ + if( isDeleted ){ + sqlite3_snprintf(sizeof(zSzName), zSzName, "Deleted"); + zHash = ""; + fullSize = 0; + @ + }else{ + approxSizeName(sizeof(zSzName), zSzName, fullSize); + iTotalSz += fullSize; + cnt++; + @ + } + @ + @ + @ + @ + if( g.perm.Admin ){ + if( rcvid ){ + @ + fossil_free(zAge); + } + db_finalize(&q); + if( n ){ + approxSizeName(sizeof(zSzName), zSzName, iTotalSz); + @ + @ + @
    Name + @ Age + @ Size + @ User + @ SHA1 + if( g.perm.Admin ){ + @ rcvid + } + @
    %h(zName) %h(zName) %s(zAge) %s(zSzName) %h(zLogin) %h(zHash) %d(rcvid) + }else{ + @ + } + } + @
    Total over %d(cnt) files%s(zSzName) + @
  16. + output_table_sorting_javascript("uvtab","tkKttN",1); + }else{ + @ No unversioned files on this server. + } + style_footer(); +} Index: src/user.c ================================================================== --- src/user.c +++ src/user.c @@ -170,27 +170,29 @@ /* ** Do a single prompt for a passphrase. Store the results in the blob. ** -** If the FOSSIL_PWREADER environment variable is set, then it will -** be the name of a program that prompts the user for their password/ -** passphrase in a secure manner. The program should take one or more -** arguments which are the prompts and should output the acquired -** passphrase as a single line on stdout. This function will read the -** output using popen(). -** -** If FOSSIL_PWREADER is not set, or if it is not the name of an -** executable, then use the C-library getpass() routine. ** ** The return value is a pointer to a static buffer that is overwritten ** on subsequent calls to this same routine. */ static void prompt_for_passphrase(const char *zPrompt, Blob *pPassphrase){ char *z; +#if 0 + */ + ** If the FOSSIL_PWREADER environment variable is set, then it will + ** be the name of a program that prompts the user for their password/ + ** passphrase in a secure manner. The program should take one or more + ** arguments which are the prompts and should output the acquired + ** passphrase as a single line on stdout. This function will read the + ** output using popen(). + ** + ** If FOSSIL_PWREADER is not set, or if it is not the name of an + ** executable, then use the C-library getpass() routine. + */ const char *zProg = fossil_getenv("FOSSIL_PWREADER"); - const char *zSecure; if( zProg && zProg[0] ){ static char zPass[100]; Blob cmd; FILE *in; blob_zero(&cmd); @@ -199,11 +201,13 @@ in = popen(blob_str(&cmd), "r"); fgets(zPass, sizeof(zPass), in); pclose(in); blob_reset(&cmd); z = zPass; - }else if( fossil_security_level()>=2 ){ + }else +#endif + if( fossil_security_level()>=2 ){ userGenerateScrambleCode(); z = getpass(zPrompt); if( z ) userDescramble(z); printf("\033[3A\033[J"); /* Erase previous three lines */ fflush(stdout); Index: src/util.c ================================================================== --- src/util.c +++ src/util.c @@ -341,5 +341,54 @@ int fossil_all_whitespace(const char *z){ if( z==0 ) return 1; while( fossil_isspace(z[0]) ){ z++; } return z[0]==0; } + +/* +** Return the name of the users preferred text editor. Return NULL if +** not found. +** +** Search algorithm: +** (1) The local "editor" setting +** (2) The global "editor" setting +** (3) The VISUAL environment variable +** (4) The EDITOR environment variable +** (5) (Windows only:) "notepad.exe" +*/ +const char *fossil_text_editor(void){ + const char *zEditor = db_get("editor", 0); + if( zEditor==0 ){ + zEditor = fossil_getenv("VISUAL"); + } + if( zEditor==0 ){ + zEditor = fossil_getenv("EDITOR"); + } +#if defined(_WIN32) || defined(__CYGWIN__) + if( zEditor==0 ){ + zEditor = mprintf("%s\\notepad.exe", fossil_getenv("SYSTEMROOT")); +#if defined(__CYGWIN__) + zEditor = fossil_utf8_to_path(zEditor, 0); +#endif + } +#endif + return zEditor; +} + +/* +** Construct a temporary filename. +** +** The returned string is obtained from sqlite3_malloc() and must be +** freed by the caller. +*/ +char *fossil_temp_filename(void){ + char *zTFile = 0; + sqlite3 *db; + if( g.db ){ + db = g.db; + }else{ + sqlite3_open("",&db); + } + sqlite3_file_control(db, 0, SQLITE_FCNTL_TEMPFILENAME, (void*)&zTFile); + if( g.db==0 ) sqlite3_close(db); + return zTFile; +} Index: src/wiki.c ================================================================== --- src/wiki.c +++ src/wiki.c @@ -1220,10 +1220,16 @@ ** -s|--show-technote-ids The id of the tech note will be listed ** along side the timestamp. The tech note ** id will be the first word on each line. ** This option only applies if the ** --technote option is also specified. +** +** DATETIME may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in +** year-month-day form, it may be truncated, the "T" may be replaced by +** a space, and it may also name a timezone offset from UTC as "-HH:MM" +** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z" +** means UTC. ** */ void wiki_cmd(void){ int n; db_find_and_open_repository(0, 0); Index: src/winhttp.c ================================================================== --- src/winhttp.c +++ src/winhttp.c @@ -34,11 +34,11 @@ struct HttpRequest { int id; /* ID counter */ SOCKET s; /* Socket on which to receive data */ SOCKADDR_IN addr; /* Address from which data is coming */ int flags; /* Flags passed to win32_http_server() */ - const char *zOptions; /* --baseurl, --notfound and/or --localauth options */ + const char *zOptions; /* --baseurl, --notfound, --localauth, --th-trace */ }; /* ** Prefix for a temporary file. */ @@ -265,10 +265,13 @@ blob_appendf(&options, " --files-urlenc %T", zFileGlob); } if( g.useLocalauth ){ blob_appendf(&options, " --localauth"); } + if( g.thTrace ){ + blob_appendf(&options, " --th-trace"); + } if( flags & HTTP_SERVER_REPOLIST ){ blob_appendf(&options, " --repolist"); } if( WSAStartup(MAKEWORD(1,1), &wd) ){ fossil_fatal("unable to initialize winsock"); Index: src/xfer.c ================================================================== --- src/xfer.c +++ src/xfer.c @@ -2,11 +2,11 @@ ** Copyright (c) 2007 D. Richard Hipp ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the Simplified BSD License (also ** known as the "2-Clause License" or "FreeBSD License".) - +** ** This program is distributed in the hope that it will be useful, ** but without any warranty; without even the implied warranty of ** merchantability or fitness for a particular purpose. ** ** Author contact information: @@ -282,10 +282,129 @@ Th_AppendToList(pzUuidList, pnUuidList, blob_str(&pXfer->aToken[1]), blob_size(&pXfer->aToken[1])); remote_has(rid); blob_reset(&content); } + +/* +** The aToken[0..nToken-1] blob array is a parse of a "uvfile" line +** message. This routine finishes parsing that message and adds the +** unversioned file to the "unversioned" table. +** +** The file line is in one of the following two forms: +** +** uvfile NAME MTIME HASH SIZE FLAGS +** uvfile NAME MTIME HASH SIZE FLAGS \n CONTENT +** +** If the 0x0001 bit of FLAGS is set, that means the file has been +** deleted, SIZE is zero, the HASH is "-", and the "\n CONTENT" is omitted. +** +** SIZE is the number of bytes of CONTENT. The CONTENT is uncompressed. +** HASH is the SHA1 hash of CONTENT. +** +** If the 0x0004 bit of FLAGS is set, that means the CONTENT is omitted. +** The sender might have omitted the content because it is too big to +** transmit, or because it is unchanged and this record exists purely +** to update the MTIME. +*/ +static void xfer_accept_unversioned_file(Xfer *pXfer, int isWriter){ + sqlite3_int64 mtime; /* The MTIME */ + Blob *pHash; /* The HASH value */ + int sz; /* The SIZE */ + int flags; /* The FLAGS */ + Blob content; /* The CONTENT */ + Blob hash; /* Hash computed from CONTENT to compare with HASH */ + Blob x; /* Compressed content */ + Stmt q; /* SQL statements for comparison and insert */ + int isDelete; /* HASH is "-" indicating this is a delete */ + int nullContent; /* True of CONTENT is NULL */ + int iStatus; /* Result from unversioned_status() */ + + pHash = &pXfer->aToken[3]; + if( pXfer->nToken==5 + || !blob_is_filename(&pXfer->aToken[1]) + || !blob_is_int64(&pXfer->aToken[2], &mtime) + || (!blob_eq(pHash,"-") && !blob_is_uuid(pHash)) + || !blob_is_int(&pXfer->aToken[4], &sz) + || !blob_is_int(&pXfer->aToken[5], &flags) + ){ + blob_appendf(&pXfer->err, "malformed uvfile line"); + return; + } + blob_init(&content, 0, 0); + blob_init(&hash, 0, 0); + blob_init(&x, 0, 0); + if( sz>0 && (flags & 0x0005)==0 ){ + blob_extract(pXfer->pIn, sz, &content); + nullContent = 0; + sha1sum_blob(&content, &hash); + if( blob_compare(&hash, pHash)!=0 ){ + blob_appendf(&pXfer->err, "in uvfile line, HASH does not match CONTENT"); + goto end_accept_unversioned_file; + } + }else{ + nullContent = 1; + } + + /* The isWriter flag must be true in order to land the new file */ + if( !isWriter ) goto end_accept_unversioned_file; + + /* Make sure we have a valid g.rcvid marker */ + content_rcvid_init(0); + + /* Check to see if current content really should be overwritten. Ideally, + ** a uvfile card should never have been sent unless the overwrite should + ** occur. But do not trust the sender. Double-check. + */ + iStatus = unversioned_status(blob_str(&pXfer->aToken[1]), mtime, + blob_str(pHash)); + if( iStatus>=3 ) goto end_accept_unversioned_file; + + /* Store the content */ + isDelete = blob_eq(pHash, "-"); + if( isDelete ){ + db_prepare(&q, + "UPDATE unversioned" + " SET rcvid=:rcvid, mtime=:mtime, hash=NULL," + " sz=0, encoding=0, content=NULL" + " WHERE name=:name" + ); + db_bind_int(&q, ":rcvid", g.rcvid); + }else if( iStatus==4 ){ + db_prepare(&q, "UPDATE unversioned SET mtime=:mtime WHERE name=:name"); + }else{ + db_prepare(&q, + "REPLACE INTO unversioned(name,rcvid,mtime,hash,sz,encoding,content)" + " VALUES(:name,:rcvid,:mtime,:hash,:sz,:encoding,:content)" + ); + db_bind_int(&q, ":rcvid", g.rcvid); + db_bind_text(&q, ":hash", blob_str(pHash)); + db_bind_int(&q, ":sz", blob_size(&content)); + if( !nullContent ){ + blob_compress(&content, &x); + if( blob_size(&x) < 0.8*blob_size(&content) ){ + db_bind_blob(&q, ":content", &x); + db_bind_int(&q, ":encoding", 1); + }else{ + db_bind_blob(&q, ":content", &content); + db_bind_int(&q, ":encoding", 0); + } + }else{ + db_bind_int(&q, ":encoding", 0); + } + } + db_bind_text(&q, ":name", blob_str(&pXfer->aToken[1])); + db_bind_int64(&q, ":mtime", mtime); + db_step(&q); + db_finalize(&q); + db_unset("uv-hash", 0); + +end_accept_unversioned_file: + blob_reset(&x); + blob_reset(&content); + blob_reset(&hash); +} /* ** Try to send a file as a delta against its parent. ** If successful, return the number of bytes in the delta. ** If we cannot generate an appropriate delta, then send @@ -524,10 +643,71 @@ blob_reset(&fullContent); } } db_reset(&q1); } + +/* +** Send the unversioned file identified by zName by generating the +** appropriate "uvfile" card. +** +** uvfile NAME MTIME HASH SIZE FLAGS \n CONTENT +** +** If the noContent flag is set, omit the CONTENT and set the 0x0004 +** flag in FLAGS. +*/ +static void send_unversioned_file( + Xfer *pXfer, /* Transfer context */ + const char *zName, /* Name of unversioned file to be sent */ + int noContent /* True to omit the content */ +){ + Stmt q1; + + if( blob_size(pXfer->pOut)>=pXfer->mxSend ) noContent = 1; + if( noContent ){ + db_prepare(&q1, + "SELECT mtime, hash, encoding, sz FROM unversioned WHERE name=%Q", + zName + ); + }else{ + db_prepare(&q1, + "SELECT mtime, hash, encoding, sz, content FROM unversioned" + " WHERE name=%Q", + zName + ); + } + if( db_step(&q1)==SQLITE_ROW ){ + sqlite3_int64 mtime = db_column_int64(&q1, 0); + const char *zHash = db_column_text(&q1, 1); + if( blob_size(pXfer->pOut)>=pXfer->mxSend ){ + /* If we have already reached the send size limit, send a (short) + ** uvigot card rather than a uvfile card. This only happens on the + ** server side. The uvigot card will provoke the client to resend + ** another uvgimme on the next cycle. */ + blob_appendf(pXfer->pOut, "uvigot %s %lld %s %d\n", + zName, mtime, zHash, db_column_int(&q1,3)); + }else{ + blob_appendf(pXfer->pOut, "uvfile %s %lld", zName, mtime); + if( zHash==0 ){ + blob_append(pXfer->pOut, " - 0 1\n", -1); + }else if( noContent ){ + blob_appendf(pXfer->pOut, " %s %d 4\n", zHash, db_column_int(&q1,3)); + }else{ + Blob content; + blob_init(&content, 0, 0); + db_column_blob(&q1, 4, &content); + if( db_column_int(&q1, 2) ){ + blob_uncompress(&content, &content); + } + blob_appendf(pXfer->pOut, " %s %d 0\n", zHash, blob_size(&content)); + blob_append(pXfer->pOut, blob_buffer(&content), blob_size(&content)); + blob_reset(&content); + } + } + } + db_finalize(&q1); +} /* ** Send a gimme message for every phantom. ** ** Except: do not request shunned artifacts. And do not request @@ -593,11 +773,13 @@ Stmt q; int rc = -1; char *zLogin = blob_terminate(pLogin); defossilize(zLogin); - if( fossil_strcmp(zLogin, "nobody")==0 || fossil_strcmp(zLogin,"anonymous")==0 ){ + if( fossil_strcmp(zLogin, "nobody")==0 + || fossil_strcmp(zLogin,"anonymous")==0 + ){ return 0; /* Anybody is allowed to sync as "nobody" or "anonymous" */ } if( fossil_strcmp(P("REMOTE_USER"), zLogin)==0 && db_get_boolean("remote_user_ok",0) ){ return 0; /* Accept Basic Authorization */ @@ -833,10 +1015,40 @@ blob_size(&content), blob_str(&content)); blob_reset(&content); } } + +/* +** pXfer is a "pragma uv-hash HASH" card. +** +** If HASH is different from the unversioned content hash on this server, +** then send a bunch of uvigot cards, one for each entry unversioned file +** on this server. +*/ +static void send_unversioned_catalog(Xfer *pXfer){ + unversioned_schema(); + if( !blob_eq(&pXfer->aToken[2], unversioned_content_hash(0)) ){ + int nUvIgot = 0; + Stmt uvq; + db_prepare(&uvq, + "SELECT name, mtime, hash, sz FROM unversioned" + ); + while( db_step(&uvq)==SQLITE_ROW ){ + const char *zName = db_column_text(&uvq,0); + sqlite3_int64 mtime = db_column_int64(&uvq,1); + const char *zHash = db_column_text(&uvq,2); + int sz = db_column_int(&uvq,3); + nUvIgot++; + if( zHash==0 ){ sz = 0; zHash = "-"; } + blob_appendf(pXfer->pOut, "uvigot %s %lld %s %d\n", + zName, mtime, zHash, sz); + } + db_finalize(&uvq); + } +} + /* ** Called when there is an attempt to transfer private content to and ** from a server without authorization. */ static void server_private_xfer_not_authorized(void){ @@ -1026,10 +1238,24 @@ @ error %T(blob_str(&xfer.err)) nErr++; break; } }else + + /* uvfile NAME MTIME HASH SIZE FLAGS \n CONTENT + ** + ** Accept an unversioned file from the client. + */ + if( blob_eq(&xfer.aToken[0], "uvfile") ){ + xfer_accept_unversioned_file(&xfer, g.perm.WrUnver); + if( blob_size(&xfer.err) ){ + cgi_reset_content(); + @ error %T(blob_str(&xfer.err)) + nErr++; + break; + } + }else /* gimme UUID ** ** Client is requesting a file. Send it. */ @@ -1043,10 +1269,21 @@ if( rid ){ send_file(&xfer, rid, &xfer.aToken[1], deltaFlag); } } }else + + /* uvgimme NAME + ** + ** Client is requesting an unversioned file. Send it. + */ + if( blob_eq(&xfer.aToken[0], "uvgimme") + && xfer.nToken==2 + && blob_is_filename(&xfer.aToken[1]) + ){ + send_unversioned_file(&xfer, blob_str(&xfer.aToken[1]), 0); + }else /* igot UUID ?ISPRIVATE? ** ** Client announces that it has a particular file. If the ISPRIVATE ** argument exists and is non-zero, then the file is a private file. @@ -1225,11 +1462,10 @@ blob_reset(&content); blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR); }else - /* cookie TEXT ** ** A cookie contains a arbitrary-length argument that is server-defined. ** The argument must be encoded so as not to contain any whitespace. ** The server can optionally send a cookie to the client. The client @@ -1269,10 +1505,11 @@ ** The client issue pragmas to try to influence the behavior of the ** server. These are requests only. Unknown pragmas are silently ** ignored. */ if( blob_eq(&xfer.aToken[0], "pragma") && xfer.nToken>=2 ){ + /* pragma send-private ** ** If the user has the "x" privilege (which must be set explicitly - ** it is not automatic with "a" or "s") then this pragma causes ** private information to be pulled in addition to public records. @@ -1283,17 +1520,36 @@ server_private_xfer_not_authorized(); }else{ xfer.syncPrivate = 1; } } + /* pragma send-catalog ** ** Send igot cards for all known artifacts. */ if( blob_eq(&xfer.aToken[1], "send-catalog") ){ xfer.resync = 0x7fffffff; } + + /* pragma uv-hash HASH + ** + ** The client wants to make sure that unversioned files are all synced. + ** If the HASH does not match, send a complete catalog of + ** "uvigot" cards. + */ + if( blob_eq(&xfer.aToken[1], "uv-hash") + && blob_is_uuid(&xfer.aToken[2]) + ){ + if( g.perm.Read && g.perm.WrUnver ){ + @ pragma uv-push-ok + send_unversioned_catalog(&xfer); + }else if( g.perm.Read ){ + @ pragma uv-pull-only + send_unversioned_catalog(&xfer); + } + } }else /* Unknown message */ { @@ -1391,16 +1647,19 @@ #if INTERFACE /* ** Flag options for controlling client_sync() */ -#define SYNC_PUSH 0x0001 -#define SYNC_PULL 0x0002 -#define SYNC_CLONE 0x0004 -#define SYNC_PRIVATE 0x0008 -#define SYNC_VERBOSE 0x0010 -#define SYNC_RESYNC 0x0020 +#define SYNC_PUSH 0x0001 /* push content client to server */ +#define SYNC_PULL 0x0002 /* pull content server to client */ +#define SYNC_CLONE 0x0004 /* clone the repository */ +#define SYNC_PRIVATE 0x0008 /* Also transfer private content */ +#define SYNC_VERBOSE 0x0010 /* Extra diagnostics */ +#define SYNC_RESYNC 0x0020 /* --verily */ +#define SYNC_UNVERSIONED 0x0040 /* Sync unversioned content */ +#define SYNC_UV_REVERT 0x0080 /* Copy server unversioned to client */ +#define SYNC_FROMPARENT 0x0100 /* Pull from the parent project */ #endif /* ** Floating-point absolute value */ @@ -1423,11 +1682,11 @@ ){ int go = 1; /* Loop until zero */ int nCardSent = 0; /* Number of cards sent */ int nCardRcvd = 0; /* Number of cards received */ int nCycle = 0; /* Number of round trips to the server */ - int size; /* Size of a config value */ + int size; /* Size of a config value or uvfile */ int origConfigRcvMask; /* Original value of configRcvMask */ int nFileRecv; /* Number of files received */ int mxPhantomReq = 200; /* Max number of phantoms to request per comm */ const char *zCookie; /* Server cookie */ i64 nSent, nRcvd; /* Bytes sent and received (after compression) */ @@ -1444,14 +1703,31 @@ int nRoundtrip= 0; /* Number of HTTP requests */ int nArtifactSent = 0; /* Total artifacts sent */ int nArtifactRcvd = 0; /* Total artifacts received */ const char *zOpType = 0;/* Push, Pull, Sync, Clone */ double rSkew = 0.0; /* Maximum time skew */ + int uvHashSent = 0; /* The "pragma uv-hash" message has been sent */ + int uvStatus = 0; /* 0: no I/O. 1: pull-only 2: push-and-pull */ + int uvDoPush = 0; /* Generate uvfile messages to send to server */ + int nUvGimmeSent = 0; /* Number of uvgimme cards sent on this cycle */ + int nUvFileRcvd = 0; /* Number of uvfile cards received on this cycle */ + sqlite3_int64 mtime; /* Modification time on a UV file */ if( db_get_boolean("dont-push", 0) ) syncFlags &= ~SYNC_PUSH; - if( (syncFlags & (SYNC_PUSH|SYNC_PULL|SYNC_CLONE))==0 + if( (syncFlags & (SYNC_PUSH|SYNC_PULL|SYNC_CLONE|SYNC_UNVERSIONED))==0 && configRcvMask==0 && configSendMask==0 ) return 0; + if( syncFlags & SYNC_FROMPARENT ){ + configRcvMask = 0; + configSendMask = 0; + syncFlags &= ~(SYNC_PUSH); + zPCode = db_get("parent-project-code", 0); + if( zPCode==0 || db_get("parent-project-name",0)==0 ){ + fossil_fatal("there is no parent project: set the 'parent-project-code'" + " and 'parent-project-name' config parameters set in order" + " to pull from a parent project"); + } + } transport_stats(0, 0, 1); socket_global_init(); memset(&xfer, 0, sizeof(xfer)); xfer.pIn = &recv; @@ -1473,10 +1749,25 @@ /* Send the send-private pragma if we are trying to sync private data */ if( syncFlags & SYNC_PRIVATE ){ blob_append(&send, "pragma send-private\n", -1); } + + /* When syncing unversioned files, create a TEMP table in which to store + ** the names of files that do not need to be sent from client to server. + */ + if( (syncFlags & SYNC_UNVERSIONED)!=0 ){ + unversioned_schema(); + db_multi_exec( + "CREATE TEMP TABLE uv_tosend(" + " name TEXT PRIMARY KEY," + " mtimeOnly BOOLEAN" + ") WITHOUT ROWID;" + "INSERT INTO uv_toSend(name,mtimeOnly)" + " SELECT name, 0 FROM unversioned WHERE hash IS NOT NULL;" + ); + } /* ** Always begin with a clone, pull, or push message */ if( syncFlags & SYNC_CLONE ){ @@ -1514,11 +1805,11 @@ db_multi_exec( "CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);" ); manifest_crosslink_begin(); - /* Send make the most recently received cookie. Let the server + /* Send back the most recently received cookie. Let the server ** figure out if this is a cookie that it cares about. */ zCookie = db_get("cookie", 0); if( zCookie ){ blob_appendf(&send, "cookie %s\n", zCookie); @@ -1558,10 +1849,23 @@ configure_prepare_to_receive(overwrite); } origConfigRcvMask = configRcvMask; configRcvMask = 0; } + + /* Send a request to sync unversioned files. On a clone, delay sending + ** this until the second cycle since the login card might fail on + ** the first cycle. + */ + if( (syncFlags & SYNC_UNVERSIONED)!=0 + && ((syncFlags & SYNC_CLONE)==0 || nCycle>0) + && !uvHashSent + ){ + blob_appendf(&send, "pragma uv-hash %s\n", unversioned_content_hash(0)); + nCardSent++; + uvHashSent = 1; + } /* Send configuration parameters being pushed */ if( configSendMask ){ if( zOpType==0 ) zOpType = "Push"; if( configSendMask & CONFIGSET_OLDFORMAT ){ @@ -1575,10 +1879,46 @@ }else{ nCardSent += configure_send_group(xfer.pOut, configSendMask, 0); } configSendMask = 0; } + + /* Send unversioned files present here on the client but missing or + ** obsolete on the server. + ** + ** Or, if the SYNC_UV_REVERT flag is set, delete the local unversioned + ** files that do not exist on the server. + */ + if( uvDoPush ){ + assert( (syncFlags & SYNC_UNVERSIONED)!=0 ); + assert( uvStatus==2 ); + if( syncFlags & SYNC_UV_REVERT ){ + db_multi_exec( + "DELETE FROM unversioned" + " WHERE name IN (SELECT name FROM uv_tosend);" + "DELETE FROM uv_tosend;" + ); + uvDoPush = 0; + }else{ + Stmt uvq; + int rc = SQLITE_OK; + db_prepare(&uvq, "SELECT name, mtimeOnly FROM uv_tosend"); + while( (rc = db_step(&uvq))==SQLITE_ROW ){ + const char *zName = db_column_text(&uvq, 0); + send_unversioned_file(&xfer, zName, db_column_int(&uvq,1)); + nCardSent++; + nArtifactSent++; + db_multi_exec("DELETE FROM uv_tosend WHERE name=%Q", zName); + if( syncFlags & SYNC_VERBOSE ){ + fossil_print("\rUnversioned-file sent: %s\n", zName); + } + if( blob_size(xfer.pOut)>xfer.mxSend ) break; + } + db_finalize(&uvq); + if( rc==SQLITE_DONE ) uvDoPush = 0; + } + } /* Append randomness to the end of the message. This makes all ** messages unique so that that the login-card nonce will always ** be unique. */ @@ -1635,10 +1975,12 @@ if( syncFlags & SYNC_PUSH ){ blob_appendf(&send, "push %s %s\n", zSCode, zPCode); nCardSent++; } go = 0; + nUvGimmeSent = 0; + nUvFileRcvd = 0; /* Process the reply that came back from the server */ while( blob_line(&recv, &xfer.line) ){ if( blob_buffer(&xfer.line)[0]=='#' ){ const char *zLine = blob_buffer(&xfer.line); @@ -1647,11 +1989,13 @@ double rDiff; sqlite3_snprintf(sizeof(zTime), zTime, "%.19s", &zLine[12]); rDiff = db_double(9e99, "SELECT julianday('%q') - %.17g", zTime, rArrivalTime); if( rDiff>9e98 || rDiff<-9e98 ) rDiff = 0.0; - if( rDiff*24.0*3600.0 >= -(blob_size(&recv)/5000.0 + 20) ) rDiff = 0.0; + if( rDiff*24.0*3600.0 >= -(blob_size(&recv)/5000.0 + 20) ){ + rDiff = 0.0; + } if( fossil_fabs(rDiff)>fossil_fabs(rSkew) ) rSkew = rDiff; } nCardRcvd++; continue; } @@ -1683,10 +2027,24 @@ */ if( blob_eq(&xfer.aToken[0],"cfile") ){ xfer_accept_compressed_file(&xfer, 0, 0); nArtifactRcvd++; }else + + /* uvfile NAME MTIME HASH SIZE FLAGS \n CONTENT + ** + ** Accept an unversioned file from the client. + */ + if( blob_eq(&xfer.aToken[0], "uvfile") ){ + xfer_accept_unversioned_file(&xfer, 1); + nArtifactRcvd++; + nUvFileRcvd++; + if( syncFlags & SYNC_VERBOSE ){ + fossil_print("\rUnversioned-file received: %s\n", + blob_str(&xfer.aToken[1])); + } + }else /* gimme UUID ** ** Server is requesting a file. If the file is a manifest, assume ** that the server will also want to know all of the content files @@ -1730,10 +2088,64 @@ if( rid ) newPhantom = 1; } remote_has(rid); }else + /* uvigot NAME MTIME HASH SIZE + ** + ** Server announces that it has a particular unversioned file. The + ** server will only send this card if the client had previously sent + ** a "pragma uv-hash" card with a hash that does not match. + ** + ** If the identified file needs to be transferred, then setup for the + ** transfer. Generate a "uvgimme" card in the reply if the server + ** version is newer than the client. Generate a "uvfile" card if + ** the client version is newer than the server. If HASH is "-" + ** (indicating that the file has been deleted) and MTIME is newer, + ** then do the deletion. + */ + if( xfer.nToken==5 + && blob_eq(&xfer.aToken[0], "uvigot") + && blob_is_filename(&xfer.aToken[1]) + && blob_is_int64(&xfer.aToken[2], &mtime) + && blob_is_int(&xfer.aToken[4], &size) + && (blob_eq(&xfer.aToken[3],"-") || blob_is_uuid(&xfer.aToken[3])) + ){ + const char *zName = blob_str(&xfer.aToken[1]); + const char *zHash = blob_str(&xfer.aToken[3]); + int iStatus; + if( uvStatus==0 ) uvStatus = 2; + iStatus = unversioned_status(zName, mtime, zHash); + if( (syncFlags & SYNC_UV_REVERT)!=0 && iStatus==4 ) iStatus = 2; + if( iStatus<=1 ){ + if( zHash[0]!='-' ){ + blob_appendf(xfer.pOut, "uvgimme %s\n", zName); + nCardSent++; + nUvGimmeSent++; + }else if( iStatus==1 ){ + db_multi_exec( + "UPDATE unversioned" + " SET mtime=%lld, hash=NULL, sz=0, encoding=0, content=NULL" + " WHERE name=%Q", mtime, zName + ); + db_unset("uv-hash", 0); + } + }else if( iStatus==2 ){ + db_multi_exec( + "UPDATE unversioned SET mtime=%lld WHERE name=%Q", mtime, zName + ); + db_unset("uv-hash", 0); + } + if( iStatus<=3 ){ + db_multi_exec("DELETE FROM uv_tosend WHERE name=%Q", zName); + }else if( iStatus==4 ){ + db_multi_exec("UPDATE uv_tosend SET mtimeOnly=1 WHERE name=%Q",zName); + }else if( iStatus==5 ){ + db_multi_exec("REPLACE INTO uv_tosend(name,mtimeOnly) VALUES(%Q,0)", + zName); + } + }else /* push SERVERCODE PRODUCTCODE ** ** Should only happen in response to a clone. This message tells ** the client what product to use for the new database. @@ -1816,11 +2228,12 @@ ** to the next cycle. */ if( blob_eq(&xfer.aToken[0],"message") && xfer.nToken==2 ){ char *zMsg = blob_terminate(&xfer.aToken[1]); defossilize(zMsg); - if( (syncFlags & SYNC_PUSH) && zMsg && sqlite3_strglob("pull only *", zMsg)==0 ){ + if( (syncFlags & SYNC_PUSH) && zMsg + && sqlite3_strglob("pull only *", zMsg)==0 ){ syncFlags &= ~SYNC_PUSH; zMsg = 0; } if( zMsg && zMsg[0] ){ fossil_force_newline(); @@ -1833,10 +2246,23 @@ ** The server can send pragmas to try to convey meta-information to ** the client. These are informational only. Unknown pragmas are ** silently ignored. */ if( blob_eq(&xfer.aToken[0], "pragma") && xfer.nToken>=2 ){ + /* If the server is unwill to accept new unversioned content (because + ** this client lacks the necessary permissions) then it sends a + ** "uv-pull-only" pragma so that the client will know not to waste + ** bandwidth trying to upload unversioned content. If the server + ** does accept new unversioned content, it sends "uv-push-ok". + */ + if( blob_eq(&xfer.aToken[1], "uv-pull-only") ){ + uvStatus = 1; + if( syncFlags & SYNC_UV_REVERT ) uvDoPush = 1; + }else if( blob_eq(&xfer.aToken[1], "uv-push-ok") ){ + uvStatus = 2; + uvDoPush = 1; + } }else /* error MESSAGE ** ** Report an error and abandon the sync session. @@ -1931,11 +2357,11 @@ xfer.nDanglingFile = 0; /* If we have one or more files queued to send, then go ** another round */ - if( xfer.nFileSent+xfer.nDeltaSent>0 ){ + if( xfer.nFileSent+xfer.nDeltaSent>0 || uvDoPush ){ go = 1; } /* If this is a clone, the go at least two rounds */ if( (syncFlags & SYNC_CLONE)!=0 && nCycle==1 ) go = 1; @@ -1944,10 +2370,15 @@ ** we have gone at least two rounds. Always go at least two rounds ** on a clone in order to be sure to retrieve the configuration ** information which is only sent on the second round. */ if( cloneSeqno<=0 && nCycle>1 ) go = 0; + + /* Continue looping as long as new uvfile cards are being received + ** and uvgimme cards are being sent. */ + if( nUvGimmeSent>0 && nUvFileRcvd>0 ) go = 1; + db_multi_exec("DROP TABLE onremote"); if( go ){ manifest_crosslink_end(MC_PERMIT_HOOKS); }else{ manifest_crosslink_end(MC_PERMIT_HOOKS); Index: src/zip.c ================================================================== --- src/zip.c +++ src/zip.c @@ -326,11 +326,11 @@ void zip_of_checkin( int rid, /* The RID of the checkin to construct the ZIP archive from */ Blob *pZip, /* Write the ZIP archive content into this blob */ const char *zDir, /* Top-level directory of the ZIP archive */ Glob *pInclude, /* Only include files that match this pattern */ - Glob *pExclude /* Exclude files that match this pattern */ + Glob *pExclude /* Exclude files that match this pattern */ ){ Blob mfile, hash, file; Manifest *pManifest; ManifestFile *pFile; Blob filename; Index: test/amend.test ================================================================== --- test/amend.test +++ test/amend.test @@ -304,11 +304,11 @@ set cancels {} set t1exp "" set t2exp "*" set t3exp "*" set t5exp "*" - foreach tag $tagt { + foreach tag $tagt { lappend tags -tag $tag lappend cancels -cancel $tag } foreach res $result { append t1exp ", $res" Index: test/revert.test ================================================================== --- test/revert.test +++ test/revert.test @@ -25,25 +25,25 @@ # on the file system. 'fossil undo' is called after each test # proc revert-test {testid revertArgs expectedRevertOutput args} { global RESULT set passed 1 - + set args [dict merge { -changes {} -addremove {} -exists {} -notexists {} } $args] - + set result [fossil revert {*}$revertArgs] test_status_list revert-$testid $result $expectedRevertOutput - + set statusListTests [list -changes changes -addremove {addremove -n}] foreach {key fossilArgs} $statusListTests { set expected [dict get $args $key] - set result [fossil {*}$fossilArgs] + set result [fossil {*}$fossilArgs] test_status_list revert-$testid$key $result $expected } - + set fileExistsTests [list -exists 1 does -notexists 0 should] foreach {key expected verb} $fileExistsTests { foreach path [dict get $args $key] { if {[file exists $path] != $expected} { set passed 0 @@ -50,11 +50,11 @@ protOut " Failure: File $verb not exist: $path" } } test revert-$testid$key $passed } - + fossil undo } require_no_open_checkout test_setup ADDED test/settings-repo.test Index: test/settings-repo.test ================================================================== --- /dev/null +++ test/settings-repo.test @@ -0,0 +1,259 @@ +# +# Copyright (c) 2016 D. Richard Hipp +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the Simplified BSD License (also +# known as the "2-Clause License" or "FreeBSD License".) +# +# This program is distributed in the hope that it will be useful, +# but without any warranty; without even the implied warranty of +# merchantability or fitness for a particular purpose. +# +# Author contact information: +# drh@hwaci.com +# http://www.hwaci.com/drh/ +# +############################################################################ +# +# The "settings" and "unset" commands that may modify the repository. +# + +require_no_open_checkout +set dir [file dirname [info script]]; test_setup + +############################################################################### +# +# Complete syntax as tested: +# +# fossil settings ?PROPERTY? ?VALUE? ?OPTIONS? +# fossil unset PROPERTY ?OPTIONS? +# +# Where the only supported options are "--global" and "--exact". +# +############################################################################### + +set all_settings [get_all_settings] + +foreach name $all_settings { + # + # HACK: Make 100% sure that there are no non-default setting values + # present anywhere. + # + fossil unset $name --exact --global + fossil unset $name --exact + + # + # NOTE: Query for the hard-coded default value of this setting and + # save it. + # + fossil test-th-eval "setting $name" + set defaults($name) [normalize_result] +} + +############################################################################### + +fossil settings bad-setting some_value + +test settings-set-bad-local { + [normalize_result] eq "no such setting: bad-setting" +} + +fossil settings bad-setting some_value --global + +test settings-set-bad-global { + [normalize_result] eq "no such setting: bad-setting" +} + +############################################################################### + +fossil unset bad-setting + +test settings-unset-bad-local { + [normalize_result] eq "no such setting: bad-setting" +} + +fossil unset bad-setting --global + +test settings-unset-bad-global { + [normalize_result] eq "no such setting: bad-setting" +} + +############################################################################### + +fossil settings ssl some_value + +test settings-set-ambiguous-local { + [normalize_result] eq + "ambiguous setting \"ssl\" - might be: ssl-ca-location ssl-identity" +} + +fossil settings ssl some_value --global + +test settings-set-ambiguous-global { + [normalize_result] eq + "ambiguous setting \"ssl\" - might be: ssl-ca-location ssl-identity" +} + +############################################################################### + +fossil unset ssl + +test settings-unset-ambiguous-local { + [normalize_result] eq + "ambiguous setting \"ssl\" - might be: ssl-ca-location ssl-identity" +} + +fossil unset ssl --global + +test settings-unset-ambiguous-global { + [normalize_result] eq + "ambiguous setting \"ssl\" - might be: ssl-ca-location ssl-identity" +} + +############################################################################### + +set pattern(1) {^%name%$} +set pattern(3) {^%name%[ ]+\(global\)[ ]+%value%+$} +set pattern(4) {^%name%[ ]+\(local\)[ ]+%value%+$} + +foreach name $all_settings { + if {$name ne "manifest"} { + set value #global_for_$name + fossil settings $name $value --exact --global + set data [normalize_result] + + test settings-set-$name-global { + $data eq "" + } + + fossil settings $name --exact --global + set data [normalize_result] + + test settings-set-check1-$name-global { + [regexp -- [string map \ + [list %name% $name %value% $value] $pattern(3)] $data] + } + + fossil test-th-eval --open-config "setting $name" + set data [normalize_result] + + test settings-set-check2-$name-global { + $data eq $value + } + + fossil unset $name --exact --global + set data [normalize_result] + + test settings-unset-$name-global { + $data eq "" + } + + fossil settings $name --exact --global + set data [normalize_result] + + test settings-unset-check1-$name-global { + [regexp -- [string map \ + [list %name% $name %value% $value] $pattern(1)] $data] + } + + fossil test-th-eval --open-config "setting $name" + set data [normalize_result] + + test settings-unset-check2-$name-global { + $data eq $defaults($name) + } + } + + set value #local_for_$name + fossil settings $name $value --exact + set data [normalize_result] + + test settings-set-$name-local { + $data eq "" + } + + fossil settings $name --exact + set data [normalize_result] + + test settings-set-check1-$name-local { + [regexp -- [string map \ + [list %name% $name %value% $value] $pattern(4)] $data] + } + + fossil test-th-eval --open-config "setting $name" + set data [normalize_result] + + test settings-set-check2-$name-local { + $data eq $value + } + + fossil unset $name --exact + set data [normalize_result] + + test settings-unset-$name-local { + $data eq "" + } + + fossil settings $name --exact + set data [normalize_result] + + test settings-unset-check1-$name-local { + [regexp -- [string map \ + [list %name% $name %value% $value] $pattern(1)] $data] + } + + fossil test-th-eval --open-config "setting $name" + set data [normalize_result] + + test settings-unset-check2-$name-local { + $data eq $defaults($name) + } +} + +############################################################################### + +set pattern(5) \ + {^%name%[ ]+\n \(overridden by contents of file \.fossil-settings/%name%\)$} + +set versionable_settings [get_versionable_settings] +file mkdir .fossil-settings + +foreach name $versionable_settings { + fossil settings $name --exact + set data [normalize_result] + + test settings-before-versionable-$name { + [regexp -- [string map [list %name% $name] $pattern(1)] $data] + } + + set value #versionable_for_$name + set fileName [file join .fossil-settings $name] + write_file $fileName $value + + fossil settings $name --exact + set data [normalize_result] + + test settings-set-check1-versionable-$name { + [regexp -- [string map [list %name% $name] $pattern(5)] $data] + } + + fossil test-th-eval --open-config "setting $name" + set data [normalize_result] + + test settings-set-check2-versionable-$name { + $data eq $value + } + + file delete $fileName + + fossil settings $name --exact + set data [normalize_result] + + test settings-after-versionable-$name { + [regexp -- [string map [list %name% $name] $pattern(1)] $data] + } +} + +############################################################################### + +test_cleanup ADDED test/settings.test Index: test/settings.test ================================================================== --- /dev/null +++ test/settings.test @@ -0,0 +1,128 @@ +# +# Copyright (c) 2016 D. Richard Hipp +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the Simplified BSD License (also +# known as the "2-Clause License" or "FreeBSD License".) +# +# This program is distributed in the hope that it will be useful, +# but without any warranty; without even the implied warranty of +# merchantability or fitness for a particular purpose. +# +# Author contact information: +# drh@hwaci.com +# http://www.hwaci.com/drh/ +# +############################################################################ +# +# The "settings" and "unset" commands. +# + +set dir [file dirname [info script]]; test_setup + +############################################################################### +# +# Complete syntax as tested: +# +# fossil settings ?PROPERTY? ?VALUE? ?OPTIONS? +# fossil unset PROPERTY ?OPTIONS? +# +# Where the only supported options are "--global" and "--exact". +# +############################################################################### +# +# NOTE: The [extract_setting_names] procedure extracts the list of setting +# names from the line-ending normalized output of the "fossil settings" +# command. It assumes that a setting name must begin with a lowercase +# letter. It also assumes that any output lines that start with a +# lowercase letter contain a setting name starting at that same point. +# +proc extract_setting_names { data } { + set names [list] + + foreach {dummy name} [regexp \ + -all -line -inline -- {^([a-z][a-z0-9\-]*) } $data] { + lappend names $name + } + + return $names +} + +############################################################################### + +set all_settings [get_all_settings] + +fossil settings +set local_settings [extract_setting_names [normalize_result_no_trim]] + +fossil settings --global +set global_settings [extract_setting_names [normalize_result_no_trim]] + +foreach name $all_settings { + test settings-have-local-$name { + [lsearch -exact $local_settings $name] != -1 + } + + test settings-have-global-$name { + [lsearch -exact $global_settings $name] != -1 + } +} + +foreach name $local_settings { + test settings-valid-local-$name { + [lsearch -exact $all_settings $name] != -1 + } +} + +foreach name $global_settings { + test settings-valid-global-$name { + [lsearch -exact $all_settings $name] != -1 + } +} + +############################################################################### + +set pattern(1) {^%name%$} +set pattern(2) {^%name%[ ]+\((?:local|global)\)[ ]+[^ ]+$} + +foreach name $all_settings { + fossil settings $name --exact + set data [normalize_result] + + test settings-query-local-$name { + [regexp -- [string map [list %name% $name] $pattern(1)] $data] || + [regexp -- [string map [list %name% $name] $pattern(2)] $data] + } + + fossil settings $name --exact --global + set data [normalize_result] + + if {$name eq "manifest"} { + test settings-query-global-$name { + $data eq "cannot set 'manifest' globally" + } + } else { + test settings-query-global-$name { + [regexp -- [string map [list %name% $name] $pattern(1)] $data] || + [regexp -- [string map [list %name% $name] $pattern(2)] $data] + } + } +} + +############################################################################### + +fossil settings bad-setting + +test settings-query-bad-local { + [normalize_result] eq "no such setting: bad-setting" +} + +fossil settings bad-setting --global + +test settings-query-bad-global { + [normalize_result] eq "no such setting: bad-setting" +} + +############################################################################### + +test_cleanup Index: test/stash.test ================================================================== --- test/stash.test +++ test/stash.test @@ -15,11 +15,11 @@ # ############################################################################ # # # Tests for 'fossil stash' -# +# # proc knownBug {t tests} { return [expr {$t in $tests ? "knownBug" : ""}] } @@ -43,11 +43,11 @@ # Also, if the exit status of fossil stash does not match # expectations, the rest of the areas are not tested. proc test_result_state {testid cmdArgs expectedOutput args} { global RESULT set passed 1 - + set args [dict merge { -changes {} -addremove {} -exists {} -notexists {} -knownbugs {} } $args] set knownbugs [dict get $args "-knownbugs"] @@ -63,18 +63,18 @@ if {$code} { return } } test_status_list $testid $result $expectedOutput [knownBug "-result" $knownbugs] - + set statusListTests [list -changes changes -addremove {addremove -n}] foreach {key fossilArgs} $statusListTests { set expected [dict get $args $key] - set result [fossil {*}$fossilArgs] + set result [fossil {*}$fossilArgs] test_status_list $testid$key $result $expected [knownBug $key $knownbugs] } - + set fileExistsTests [list -exists 1 does -notexists 0 should] foreach {key expected verb} $fileExistsTests { foreach path [dict get $args $key] { if {[file exists $path] != $expected} { set passed 0 @@ -81,17 +81,17 @@ protOut " Failure: File $verb not exist: $path" } } test $testid$key $passed [knownBug $key $knownbugs] } - + #fossil undo } proc stash-test {testid stashArgs expectedStashOutput args} { fossil stash {*}$stashArgs - return [test_result_state stash-$testid "stash $stashArgs" $expectedStashOutput {*}$args] + return [test_result_state stash-$testid "stash $stashArgs" $expectedStashOutput {*}$args] } require_no_open_checkout test_setup @@ -241,15 +241,15 @@ DELETE f1n } -exists {f1} -notexists {f1n} -knownbugs {-code -result} # TODO: add tests that verify the saved stash is sensible. Possibly # by applying it and checking results. But until the MISSING file # error is fixed, there is nothing stashed to test. - + # Test stashing a newly added (but never committed) file. As with -# fossil revert, fossil stash save unmanages the new file, but -# leaves the copy present on disk. This is undocumented, but +# fossil revert, fossil stash save unmanages the new file, but +# leaves the copy present on disk. This is undocumented, but # probably sensible. test_setup write_file f1 "f1" write_file f2 "f2" fossil add f1 f2 @@ -280,11 +280,11 @@ fossil status # Test stashing a rename of one file with at least one file # unchanged. This should stash (and revert) just the rename -# operation. Instead it also stores and touches the unchanged file. +# operation. Instead it also stores and touches the unchanged file. test_setup write_file f1 "f1" write_file f2 "f2" fossil add f1 f2 fossil commit -m "baseline" Index: test/tester.tcl ================================================================== --- test/tester.tcl +++ test/tester.tcl @@ -186,10 +186,122 @@ close $out } proc write_file_indented {filename txt} { write_file $filename [string trim [string map [list "\n " \n] $txt]]\n } + +# Returns the list of all supported versionable settings. +# +proc get_versionable_settings {} { + # + # TODO: If the list of supported versionable settings in "db.c" is modified, + # this list (and procedure) most likely needs to be modified as well. + # + set result [list \ + allow-symlinks \ + binary-glob \ + clean-glob \ + crnl-glob \ + dotfiles \ + empty-dirs \ + encoding-glob \ + ignore-glob \ + keep-glob \ + manifest \ + th1-setup \ + th1-uri-regexp] + + fossil test-th-eval "hasfeature tcl" + + if {$::RESULT eq "1"} { + lappend result tcl-setup + } + + return [lsort -dictionary $result] +} + +# Returns the list of all supported settings. +# +proc get_all_settings {} { + # + # TODO: If the list of supported settings in "db.c" is modified, this list + # (and procedure) most likely needs to be modified as well. + # + set result [list \ + access-log \ + admin-log \ + allow-symlinks \ + auto-captcha \ + auto-hyperlink \ + auto-shun \ + autosync \ + autosync-tries \ + binary-glob \ + case-sensitive \ + clean-glob \ + clearsign \ + crnl-glob \ + default-perms \ + diff-binary \ + diff-command \ + dont-push \ + dotfiles \ + editor \ + empty-dirs \ + encoding-glob \ + exec-rel-paths \ + gdiff-command \ + gmerge-command \ + hash-digits \ + http-port \ + https-login \ + ignore-glob \ + keep-glob \ + localauth \ + main-branch \ + manifest \ + max-loadavg \ + max-upload \ + mtime-changes \ + pgp-command \ + proxy \ + relative-paths \ + repo-cksum \ + self-register \ + ssh-command \ + ssl-ca-location \ + ssl-identity \ + th1-setup \ + th1-uri-regexp \ + web-browser] + + fossil test-th-eval "hasfeature legacyMvRm" + + if {$::RESULT eq "1"} { + lappend result mv-rm-files + } + + fossil test-th-eval "hasfeature tcl" + + if {$::RESULT eq "1"} { + lappend result tcl tcl-setup + } + + fossil test-th-eval "hasfeature th1Docs" + + if {$::RESULT eq "1"} { + lappend result th1-docs + } + + fossil test-th-eval "hasfeature th1Hooks" + + if {$::RESULT eq "1"} { + lappend result th1-hooks + } + + return [lsort -dictionary $result] +} # Return true if two files are the same # proc same_file {a b} { set x [read_file $a] @@ -655,10 +767,15 @@ # fixup the whitespace in the result to make it easier to compare. proc normalize_result {} { return [string map [list \r\n \n] [string trim $::RESULT]] } + +# fixup the line-endings in the result to make it easier to compare. +proc normalize_result_no_trim {} { + return [string map [list \r\n \n] $::RESULT] +} # returns the first line of the normalized result. proc first_data_line {} { return [lindex [split [normalize_result] \n] 0] } Index: test/th1-tcl.test ================================================================== --- test/th1-tcl.test +++ test/th1-tcl.test @@ -77,55 +77,55 @@ ############################################################################### fossil test-th-render --open-config \ [file nativename [file join $dir th1-tcl3.txt]] -test th1-tcl-3 {$RESULT eq {

    ERROR:\ +test th1-tcl-3 {$RESULT eq {


    ERROR:\ invalid command name "bad_command"

    }} ############################################################################### fossil test-th-render --open-config \ [file nativename [file join $dir th1-tcl4.txt]] -test th1-tcl-4 {$RESULT eq {

    ERROR:\ +test th1-tcl-4 {$RESULT eq {


    ERROR:\ divide by zero

    }} ############################################################################### fossil test-th-render --open-config \ [file nativename [file join $dir th1-tcl5.txt]] -test th1-tcl-5 {$RESULT eq {

    ERROR:\ -Tcl command not found: bad_command

    } || $RESULT eq {

    ERROR:\ +Tcl command not found: bad_command

    } || $RESULT eq {
    ERROR: invalid command name "bad_command"

    }} ############################################################################### fossil test-th-render --open-config \ [file nativename [file join $dir th1-tcl6.txt]] -test th1-tcl-6 {$RESULT eq {

    ERROR:\ +test th1-tcl-6 {$RESULT eq {


    ERROR:\ no such command: bad_command

    }} ############################################################################### fossil test-th-render --open-config \ [file nativename [file join $dir th1-tcl7.txt]] -test th1-tcl-7 {$RESULT eq {

    ERROR:\ +test th1-tcl-7 {$RESULT eq {


    ERROR:\ syntax error in expression: "2**0"

    }} ############################################################################### fossil test-th-render --open-config \ [file nativename [file join $dir th1-tcl8.txt]] -test th1-tcl-8 {$RESULT eq {

    ERROR:\ -cannot invoke Tcl command: tailcall

    } || $RESULT eq {

    ERROR:\ +cannot invoke Tcl command: tailcall

    } || $RESULT eq {
    ERROR: tailcall can only be called from a proc or\ -lambda

    } || $RESULT eq {

    ERROR: This test\ +lambda

    } || $RESULT eq {

    ERROR: This test\ requires Tcl 8.6 or higher.

    }} ############################################################################### fossil test-th-render --open-config \ Index: test/th1.test ================================================================== --- test/th1.test +++ test/th1.test @@ -554,10 +554,121 @@ fossil test-th-eval "lindex list -0x" test th1-expr-49 {$RESULT eq {TH_ERROR: expected integer, got: "-0x"}} ############################################################################### +foreach perm [list a b c d e f g h i j k l m n o p q r s t u v w x y z] { + if {$perm eq "u"} continue; # NOTE: Skip "reader" meta-permission. + if {$perm eq "v"} continue; # NOTE: Skip "developer" meta-permission. + + fossil test-th-eval "anycap $perm" + test th1-anycap-no-$perm-1 {$RESULT eq {0}} + + fossil test-th-eval "hascap $perm" + test th1-hascap-no-$perm-1 {$RESULT eq {0}} + + fossil test-th-eval "anoncap $perm" + test th1-anoncap-no-$perm-1 {$RESULT eq {0}} + + run_in_checkout { + fossil test-th-eval --set-user-caps "anycap $perm" + test th1-anycap-yes-$perm-1 {$RESULT eq {1}} + + set ::env(TH1_TEST_USER_CAPS) 1; # NOTE: Bad permission. + fossil test-th-eval --set-user-caps "anycap $perm" + test th1-anycap-no-$perm-1 {$RESULT eq {0}} + unset ::env(TH1_TEST_USER_CAPS) + + fossil test-th-eval --set-user-caps "hascap $perm" + test th1-hascap-yes-$perm-1 {$RESULT eq {1}} + + set ::env(TH1_TEST_USER_CAPS) 1; # NOTE: Bad permission. + fossil test-th-eval --set-user-caps "hascap $perm" + test th1-hascap-no-$perm-1 {$RESULT eq {0}} + unset ::env(TH1_TEST_USER_CAPS) + + fossil test-th-eval --set-anon-caps "anoncap $perm" + test th1-anoncap-yes-$perm-1 {$RESULT eq {1}} + + set ::env(TH1_TEST_ANON_CAPS) 1; # NOTE: Bad permission. + fossil test-th-eval --set-anon-caps "anoncap $perm" + test th1-anoncap-no-$perm-1 {$RESULT eq {0}} + unset ::env(TH1_TEST_ANON_CAPS) + } +} + +############################################################################### + +fossil test-th-eval "anycap oh" +test th1-anycap-no-multiple-1 {$RESULT eq {0}} + +############################################################################### + +fossil test-th-eval "hascap oh" +test th1-hascap-no-multiple-1 {$RESULT eq {0}} + +############################################################################### + +fossil test-th-eval "hascap o h" +test th1-hascap-no-multiple-2 {$RESULT eq {0}} + +############################################################################### + +fossil test-th-eval "anoncap oh" +test th1-anoncap-no-multiple-1 {$RESULT eq {0}} + +############################################################################### + +fossil test-th-eval "anoncap o h" +test th1-anoncap-no-multiple-2 {$RESULT eq {0}} + +############################################################################### + +run_in_checkout { + fossil test-th-eval --set-user-caps "anycap oh" + test th1-anycap-yes-multiple-1 {$RESULT eq {1}} + + set ::env(TH1_TEST_USER_CAPS) o + fossil test-th-eval --set-user-caps "anycap oh" + test th1-anycap-yes-multiple-2 {$RESULT eq {1}} + unset ::env(TH1_TEST_USER_CAPS) + + fossil test-th-eval --set-user-caps "hascap oh" + test th1-hascap-yes-multiple-1 {$RESULT eq {1}} + + set ::env(TH1_TEST_USER_CAPS) o + fossil test-th-eval --set-user-caps "hascap oh" + test th1-hascap-no-multiple-3 {$RESULT eq {0}} + unset ::env(TH1_TEST_USER_CAPS) + + fossil test-th-eval --set-user-caps "hascap o h" + test th1-hascap-yes-multiple-2 {$RESULT eq {1}} + + set ::env(TH1_TEST_USER_CAPS) o + fossil test-th-eval --set-user-caps "hascap o h" + test th1-hascap-no-multiple-4 {$RESULT eq {0}} + unset ::env(TH1_TEST_USER_CAPS) + + fossil test-th-eval --set-anon-caps "anoncap oh" + test th1-anoncap-yes-multiple-1 {$RESULT eq {1}} + + set ::env(TH1_TEST_ANON_CAPS) o + fossil test-th-eval --set-anon-caps "anoncap oh" + test th1-anoncap-no-multiple-3 {$RESULT eq {0}} + unset ::env(TH1_TEST_ANON_CAPS) + + fossil test-th-eval --set-anon-caps "anoncap o h" + test th1-anoncap-yes-multiple-2 {$RESULT eq {1}} + + set ::env(TH1_TEST_ANON_CAPS) o + fossil test-th-eval --set-anon-caps "anoncap o h" + test th1-anoncap-no-multiple-4 {$RESULT eq {0}} + unset ::env(TH1_TEST_ANON_CAPS) +} + +############################################################################### + run_in_checkout { # NOTE: The "1" here forces the checkout to be opened. fossil test-th-eval "checkout 1" } @@ -914,11 +1025,11 @@ ############################################################################### # # NOTE: This test will fail if the command names are added to TH1, or -# moved from Tcl builds to plain or the reverse. Sorting the +# moved from Tcl builds to plain or the reverse. Sorting the # command lists eliminates a dependence on order. # fossil test-th-eval "info commands" set sorted_result [lsort $RESULT] protOut "Sorted: $sorted_result" Index: test/wiki.test ================================================================== --- test/wiki.test +++ test/wiki.test @@ -124,11 +124,11 @@ # Trying to add a technote with the same timestamp should succeed and create a # second tech note fossil wiki create 2ndnote f3 -technote {2016-01-01 12:34} test wiki-13 {$CODE == 0} fossil wiki list --technote -set technotelist [split $RESULT "\n"] +set technotelist [split $RESULT "\n"] test wiki-13.1 {[llength $technotelist] == 2} ############################################################################### # commiting a change to an existing technote should replace the page on export # (this should update the tech note from wiki-13 as that the most recently @@ -147,11 +147,11 @@ # But we shouldn't be able to update non-existant pages fossil wiki commit doesntexist f1 -expectError test wiki-16 {$CODE != 0} ############################################################################### -# Check specifying tags for a technote is OK +# Check specifying tags for a technote is OK write_file f5 "technote with tags" fossil wiki create {tagged technote} f5 --technote {2016-01-02 12:34} --technote-tags {A B} test wiki-17 {$CODE == 0} write_file f5.1 "editted and tagged technote" fossil wiki commit {tagged technote} f5 --technote {2016-01-02 12:34} --technote-tags {C D} @@ -208,16 +208,16 @@ fossil timeline test wiki-30 {[string match *Unique*technote* $RESULT]} ############################################################################### # Check for a collision between an attachment and a note, this was a -# bug that resulted from some code treating the attachment entry as if it -# were a technote when it isn't really. +# bug that resulted from some code treating the attachment entry as if it +# were a technote when it isn't really. # # First, wait for the top of the next second so the attachment # happens at a known time, then add an attachment to an existing note -# and a new note immediately after. +# and a new note immediately after. set t0 [clock seconds] while {$t0 == [clock seconds]} { after 100 } @@ -242,29 +242,29 @@ write_file f10 "Even unstampted notes are delivered.\nStamped $t2" fossil wiki create "Unstamped Note" f10 --technote -expectError test wiki-33 {$CODE != 0} fossil wiki create "Unstamped Note" f10 --technote now test wiki-34 {$CODE == 0} -fossil wiki list -t +fossil wiki list -t test wiki-35 {[string match "*$t2*" $RESULT]} ############################################################################### -# Check an attachment to it in the same second works. +# Check an attachment to it in the same second works. write_file f11 "Time Stamp was $t2" fossil attachment add f11 --technote $t2 test wiki-36 {$CODE == 0} fossil timeline test wiki-36-1 {$CODE == 0} fossil wiki list -t test wiki-36-2 {$CODE == 0} ############################################################################### -# Check that we have the expected number of tech notes on the list (and not -# extra ones from other events (such as the attachments) - 8 tech notes -# expected created by tests 9, 13, 17, 19, 29, 31, 32 and 34 +# Check that we have the expected number of tech notes on the list (and not +# extra ones from other events (such as the attachments) - 8 tech notes +# expected created by tests 9, 13, 17, 19, 29, 31, 32 and 34 fossil wiki list --technote -set technotelist [split $RESULT "\n"] +set technotelist [split $RESULT "\n"] test wiki-37 {[llength $technotelist] == 8} ############################################################################### # Check that using the show-technote-ids shows the same tech notes in the same # order (with the technote id as the first word of the line) @@ -289,11 +289,11 @@ test wiki-40 {[similar_file f12 a12]} ############################################################################### # Also check that we can specify a prefix of the tech note id (note: with # 9 items in the tech note at this point there is a chance of a collision. -# However with a 20 character prefix the chance of the collision is +# However with a 20 character prefix the chance of the collision is # approximately 1 in 10^22 so this test ignores that possibility.) fossil wiki export a12.1 --technote [string range $anoldtechnoteid 0 20] test wiki-41 {[similar_file f12 a12.1]} ############################################################################### @@ -308,11 +308,11 @@ set fullid [lindex $technotelist $i] set id [string range $fullid 0 3] dict incr idcounts $id if {[dict get $idcounts $id] > $maxcount} { set maxid $id - incr maxcount + incr maxcount } } # get i so that, as a julian date, it is in the 1800s, i.e., older than # any other tech note, but after 1 AD set i 2400000 @@ -326,11 +326,11 @@ set oldesttechnoteid [lindex [split [lindex $technotelist [llength $technotelist]-1]] 0] set id [string range $oldesttechnoteid 0 3] dict incr idcounts $id if {[dict get $idcounts $id] > $maxcount} { set maxid $id - incr maxcount + incr maxcount } } # Save the duplicate id for this and later tests set duplicateid $maxid fossil wiki export a13 --technote $duplicateid -expectError Index: win/Makefile.dmc ================================================================== --- win/Makefile.dmc +++ win/Makefile.dmc @@ -28,13 +28,13 @@ SQLITE_OPTIONS = -DNDEBUG=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_OMIT_DEPRECATED -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 SHELL_OPTIONS = -Dmain=sqlite3_shell -DSQLITE_SHELL_IS_UTF8=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=fossil_open -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen -SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c foci_.c fusefs_.c glob_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c loadctrl_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c piechart_.c pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c sitemap_.c skins_.c sqlcmd_.c stash_.c stat_.c statrep_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c +SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c foci_.c fshell_.c fusefs_.c glob_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c loadctrl_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c piechart_.c pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c sitemap_.c skins_.c sqlcmd_.c stash_.c stat_.c statrep_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c unversioned_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c -OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\builtin$O $(OBJDIR)\bundle$O $(OBJDIR)\cache$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\fusefs$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\loadctrl$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\piechart$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\statrep$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\wysiwyg$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O +OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\builtin$O $(OBJDIR)\bundle$O $(OBJDIR)\cache$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\fshell$O $(OBJDIR)\fusefs$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\loadctrl$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\piechart$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\statrep$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\unversioned$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\wysiwyg$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O RC=$(DMDIR)\bin\rcc RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__ @@ -49,11 +49,11 @@ $(OBJDIR)\fossil.res: $B\win\fossil.rc $(RC) $(RCFLAGS) -o$@ $** $(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res - +echo add allrepo attach bag bisect blob branch browse builtin bundle cache captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo foci fusefs glob graph gzip http http_socket http_ssl http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf loadctrl login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path piechart pivot popen pqueue printf publish purge rebuild regexp report rss schema search setup sha1 shun sitemap skins sqlcmd stash stat statrep style sync tag tar th_main timeline tkt tktsetup undo unicode update url user utf8 util verify vfile wiki wikiformat winfile winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@ + +echo add allrepo attach bag bisect blob branch browse builtin bundle cache captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo foci fshell fusefs glob graph gzip http http_socket http_ssl http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf loadctrl login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path piechart pivot popen pqueue printf publish purge rebuild regexp report rss schema search setup sha1 shun sitemap skins sqlcmd stash stat statrep style sync tag tar th_main timeline tkt tktsetup undo unicode unversioned update url user utf8 util verify vfile wiki wikiformat winfile winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@ +echo fossil >> $@ +echo fossil >> $@ +echo $(LIBS) >> $@ +echo. >> $@ +echo fossil >> $@ @@ -320,10 +320,16 @@ $(OBJDIR)\foci$O : foci_.c foci.h $(TCC) -o$@ -c foci_.c foci_.c : $(SRCDIR)\foci.c +translate$E $** > $@ + +$(OBJDIR)\fshell$O : fshell_.c fshell.h + $(TCC) -o$@ -c fshell_.c + +fshell_.c : $(SRCDIR)\fshell.c + +translate$E $** > $@ $(OBJDIR)\fusefs$O : fusefs_.c fusefs.h $(TCC) -o$@ -c fusefs_.c fusefs_.c : $(SRCDIR)\fusefs.c @@ -746,10 +752,16 @@ $(OBJDIR)\unicode$O : unicode_.c unicode.h $(TCC) -o$@ -c unicode_.c unicode_.c : $(SRCDIR)\unicode.c +translate$E $** > $@ + +$(OBJDIR)\unversioned$O : unversioned_.c unversioned.h + $(TCC) -o$@ -c unversioned_.c + +unversioned_.c : $(SRCDIR)\unversioned.c + +translate$E $** > $@ $(OBJDIR)\update$O : update_.c update.h $(TCC) -o$@ -c update_.c update_.c : $(SRCDIR)\update.c @@ -838,7 +850,7 @@ zip_.c : $(SRCDIR)\zip.c +translate$E $** > $@ headers: makeheaders$E page_index.h builtin_data.h VERSION.h - +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h builtin_.c:builtin.h bundle_.c:bundle.h cache_.c:cache.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h foci_.c:foci.h fusefs_.c:fusefs.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h loadctrl_.c:loadctrl.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h piechart_.c:piechart.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h publish_.c:publish.h purge_.c:purge.h rebuild_.c:rebuild.h regexp_.c:regexp.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h sitemap_.c:sitemap.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h statrep_.c:statrep.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winfile_.c:winfile.h winhttp_.c:winhttp.h wysiwyg_.c:wysiwyg.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h + +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h builtin_.c:builtin.h bundle_.c:bundle.h cache_.c:cache.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h foci_.c:foci.h fshell_.c:fshell.h fusefs_.c:fusefs.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h loadctrl_.c:loadctrl.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h piechart_.c:piechart.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h publish_.c:publish.h purge_.c:purge.h rebuild_.c:rebuild.h regexp_.c:regexp.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h sitemap_.c:sitemap.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h statrep_.c:statrep.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h unversioned_.c:unversioned.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winfile_.c:winfile.h winhttp_.c:winhttp.h wysiwyg_.c:wysiwyg.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h @copy /Y nul: headers Index: win/Makefile.mingw ================================================================== --- win/Makefile.mingw +++ win/Makefile.mingw @@ -154,13 +154,13 @@ ZLIBCONFIG = ZLIBTARGETS = endif #### Disable creation of the OpenSSL shared libraries. Also, disable support -# for both SSLv2 and SSLv3 (i.e. thereby forcing the use of TLS). +# for SSLv3 (i.e. thereby forcing the use of TLS). # -SSLCONFIG += no-ssl2 no-ssl3 no-shared +SSLCONFIG += no-ssl3 no-shared #### When using zlib, make sure that OpenSSL is configured to use the zlib # that Fossil knows about (i.e. the one within the source tree). # ifndef FOSSIL_ENABLE_MINIZ @@ -170,11 +170,11 @@ #### The directories where the OpenSSL include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "openssl-1.x" sub-directory of the # Fossil source code directory and the target OpenSSL source directory. # -OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2h +OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.1.0 OPENSSLINCDIR = $(OPENSSLDIR)/include OPENSSLLIBDIR = $(OPENSSLDIR) #### Either the directory where the Tcl library is installed or the Tcl # source code directory resides (depending on the value of the macro @@ -364,11 +364,11 @@ endif #### OpenSSL: Add the necessary libraries required, if enabled. # ifdef FOSSIL_ENABLE_SSL -LIB += -lssl -lcrypto -lgdi32 +LIB += -lssl -lcrypto -lgdi32 -lcrypt32 endif #### Tcl: Add the necessary libraries required, if enabled. # ifdef FOSSIL_ENABLE_TCL @@ -454,10 +454,11 @@ $(SRCDIR)/event.c \ $(SRCDIR)/export.c \ $(SRCDIR)/file.c \ $(SRCDIR)/finfo.c \ $(SRCDIR)/foci.c \ + $(SRCDIR)/fshell.c \ $(SRCDIR)/fusefs.c \ $(SRCDIR)/glob.c \ $(SRCDIR)/graph.c \ $(SRCDIR)/gzip.c \ $(SRCDIR)/http.c \ @@ -525,10 +526,11 @@ $(SRCDIR)/timeline.c \ $(SRCDIR)/tkt.c \ $(SRCDIR)/tktsetup.c \ $(SRCDIR)/undo.c \ $(SRCDIR)/unicode.c \ + $(SRCDIR)/unversioned.c \ $(SRCDIR)/update.c \ $(SRCDIR)/url.c \ $(SRCDIR)/user.c \ $(SRCDIR)/utf8.c \ $(SRCDIR)/util.c \ @@ -626,10 +628,11 @@ $(OBJDIR)/event_.c \ $(OBJDIR)/export_.c \ $(OBJDIR)/file_.c \ $(OBJDIR)/finfo_.c \ $(OBJDIR)/foci_.c \ + $(OBJDIR)/fshell_.c \ $(OBJDIR)/fusefs_.c \ $(OBJDIR)/glob_.c \ $(OBJDIR)/graph_.c \ $(OBJDIR)/gzip_.c \ $(OBJDIR)/http_.c \ @@ -697,10 +700,11 @@ $(OBJDIR)/timeline_.c \ $(OBJDIR)/tkt_.c \ $(OBJDIR)/tktsetup_.c \ $(OBJDIR)/undo_.c \ $(OBJDIR)/unicode_.c \ + $(OBJDIR)/unversioned_.c \ $(OBJDIR)/update_.c \ $(OBJDIR)/url_.c \ $(OBJDIR)/user_.c \ $(OBJDIR)/utf8_.c \ $(OBJDIR)/util_.c \ @@ -747,10 +751,11 @@ $(OBJDIR)/event.o \ $(OBJDIR)/export.o \ $(OBJDIR)/file.o \ $(OBJDIR)/finfo.o \ $(OBJDIR)/foci.o \ + $(OBJDIR)/fshell.o \ $(OBJDIR)/fusefs.o \ $(OBJDIR)/glob.o \ $(OBJDIR)/graph.o \ $(OBJDIR)/gzip.o \ $(OBJDIR)/http.o \ @@ -818,10 +823,11 @@ $(OBJDIR)/timeline.o \ $(OBJDIR)/tkt.o \ $(OBJDIR)/tktsetup.o \ $(OBJDIR)/undo.o \ $(OBJDIR)/unicode.o \ + $(OBJDIR)/unversioned.o \ $(OBJDIR)/update.o \ $(OBJDIR)/url.o \ $(OBJDIR)/user.o \ $(OBJDIR)/utf8.o \ $(OBJDIR)/util.o \ @@ -996,21 +1002,21 @@ BLDTARGETS = zlib endif openssl: $(BLDTARGETS) cd $(OPENSSLLIBDIR);./Configure --cross-compile-prefix=$(PREFIX) $(SSLCONFIG) - $(MAKE) -C $(OPENSSLLIBDIR) CC=$(TCCEXE) build_libs + $(MAKE) -C $(OPENSSLLIBDIR) PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) build_libs clean-openssl: - $(MAKE) -C $(OPENSSLLIBDIR) CC=$(TCCEXE) clean + $(MAKE) -C $(OPENSSLLIBDIR) PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) clean tcl: cd $(TCLSRCDIR)/win;./configure - $(MAKE) -C $(TCLSRCDIR)/win CC=$(TCCEXE) $(TCLTARGET) + $(MAKE) -C $(TCLSRCDIR)/win PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) $(TCLTARGET) clean-tcl: - $(MAKE) -C $(TCLSRCDIR)/win CC=$(TCCEXE) distclean + $(MAKE) -C $(TCLSRCDIR)/win PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) distclean APPTARGETS += $(BLDTARGETS) ifdef FOSSIL_BUILD_SSL APPTARGETS += openssl @@ -1079,10 +1085,11 @@ $(OBJDIR)/event_.c:$(OBJDIR)/event.h \ $(OBJDIR)/export_.c:$(OBJDIR)/export.h \ $(OBJDIR)/file_.c:$(OBJDIR)/file.h \ $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h \ $(OBJDIR)/foci_.c:$(OBJDIR)/foci.h \ + $(OBJDIR)/fshell_.c:$(OBJDIR)/fshell.h \ $(OBJDIR)/fusefs_.c:$(OBJDIR)/fusefs.h \ $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h \ $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h \ $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h \ $(OBJDIR)/http_.c:$(OBJDIR)/http.h \ @@ -1150,10 +1157,11 @@ $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h \ $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h \ $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h \ $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h \ $(OBJDIR)/unicode_.c:$(OBJDIR)/unicode.h \ + $(OBJDIR)/unversioned_.c:$(OBJDIR)/unversioned.h \ $(OBJDIR)/update_.c:$(OBJDIR)/update.h \ $(OBJDIR)/url_.c:$(OBJDIR)/url.h \ $(OBJDIR)/user_.c:$(OBJDIR)/user.h \ $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h \ $(OBJDIR)/util_.c:$(OBJDIR)/util.h \ @@ -1437,10 +1445,18 @@ $(OBJDIR)/foci.o: $(OBJDIR)/foci_.c $(OBJDIR)/foci.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/foci.o -c $(OBJDIR)/foci_.c $(OBJDIR)/foci.h: $(OBJDIR)/headers + +$(OBJDIR)/fshell_.c: $(SRCDIR)/fshell.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/fshell.c >$@ + +$(OBJDIR)/fshell.o: $(OBJDIR)/fshell_.c $(OBJDIR)/fshell.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/fshell.o -c $(OBJDIR)/fshell_.c + +$(OBJDIR)/fshell.h: $(OBJDIR)/headers $(OBJDIR)/fusefs_.c: $(SRCDIR)/fusefs.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/fusefs.c >$@ $(OBJDIR)/fusefs.o: $(OBJDIR)/fusefs_.c $(OBJDIR)/fusefs.h $(SRCDIR)/config.h @@ -2005,10 +2021,18 @@ $(OBJDIR)/unicode.o: $(OBJDIR)/unicode_.c $(OBJDIR)/unicode.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/unicode.o -c $(OBJDIR)/unicode_.c $(OBJDIR)/unicode.h: $(OBJDIR)/headers + +$(OBJDIR)/unversioned_.c: $(SRCDIR)/unversioned.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/unversioned.c >$@ + +$(OBJDIR)/unversioned.o: $(OBJDIR)/unversioned_.c $(OBJDIR)/unversioned.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/unversioned.o -c $(OBJDIR)/unversioned_.c + +$(OBJDIR)/unversioned.h: $(OBJDIR)/headers $(OBJDIR)/update_.c: $(SRCDIR)/update.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/update.c >$@ $(OBJDIR)/update.o: $(OBJDIR)/update_.c $(OBJDIR)/update.h $(SRCDIR)/config.h Index: win/Makefile.mingw.mistachkin ================================================================== --- win/Makefile.mingw.mistachkin +++ win/Makefile.mingw.mistachkin @@ -154,13 +154,13 @@ ZLIBCONFIG = ZLIBTARGETS = endif #### Disable creation of the OpenSSL shared libraries. Also, disable support -# for both SSLv2 and SSLv3 (i.e. thereby forcing the use of TLS). +# for SSLv3 (i.e. thereby forcing the use of TLS). # -SSLCONFIG += no-ssl2 no-ssl3 no-shared +SSLCONFIG += no-ssl3 no-shared #### When using zlib, make sure that OpenSSL is configured to use the zlib # that Fossil knows about (i.e. the one within the source tree). # ifndef FOSSIL_ENABLE_MINIZ @@ -170,11 +170,11 @@ #### The directories where the OpenSSL include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "openssl-1.x" sub-directory of the # Fossil source code directory and the target OpenSSL source directory. # -OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2h +OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.1.0 OPENSSLINCDIR = $(OPENSSLDIR)/include OPENSSLLIBDIR = $(OPENSSLDIR) #### Either the directory where the Tcl library is installed or the Tcl # source code directory resides (depending on the value of the macro @@ -364,11 +364,11 @@ endif #### OpenSSL: Add the necessary libraries required, if enabled. # ifdef FOSSIL_ENABLE_SSL -LIB += -lssl -lcrypto -lgdi32 +LIB += -lssl -lcrypto -lgdi32 -lcrypt32 endif #### Tcl: Add the necessary libraries required, if enabled. # ifdef FOSSIL_ENABLE_TCL @@ -454,10 +454,11 @@ $(SRCDIR)/event.c \ $(SRCDIR)/export.c \ $(SRCDIR)/file.c \ $(SRCDIR)/finfo.c \ $(SRCDIR)/foci.c \ + $(SRCDIR)/fshell.c \ $(SRCDIR)/fusefs.c \ $(SRCDIR)/glob.c \ $(SRCDIR)/graph.c \ $(SRCDIR)/gzip.c \ $(SRCDIR)/http.c \ @@ -525,10 +526,11 @@ $(SRCDIR)/timeline.c \ $(SRCDIR)/tkt.c \ $(SRCDIR)/tktsetup.c \ $(SRCDIR)/undo.c \ $(SRCDIR)/unicode.c \ + $(SRCDIR)/unversioned.c \ $(SRCDIR)/update.c \ $(SRCDIR)/url.c \ $(SRCDIR)/user.c \ $(SRCDIR)/utf8.c \ $(SRCDIR)/util.c \ @@ -626,10 +628,11 @@ $(OBJDIR)/event_.c \ $(OBJDIR)/export_.c \ $(OBJDIR)/file_.c \ $(OBJDIR)/finfo_.c \ $(OBJDIR)/foci_.c \ + $(OBJDIR)/fshell_.c \ $(OBJDIR)/fusefs_.c \ $(OBJDIR)/glob_.c \ $(OBJDIR)/graph_.c \ $(OBJDIR)/gzip_.c \ $(OBJDIR)/http_.c \ @@ -697,10 +700,11 @@ $(OBJDIR)/timeline_.c \ $(OBJDIR)/tkt_.c \ $(OBJDIR)/tktsetup_.c \ $(OBJDIR)/undo_.c \ $(OBJDIR)/unicode_.c \ + $(OBJDIR)/unversioned_.c \ $(OBJDIR)/update_.c \ $(OBJDIR)/url_.c \ $(OBJDIR)/user_.c \ $(OBJDIR)/utf8_.c \ $(OBJDIR)/util_.c \ @@ -747,10 +751,11 @@ $(OBJDIR)/event.o \ $(OBJDIR)/export.o \ $(OBJDIR)/file.o \ $(OBJDIR)/finfo.o \ $(OBJDIR)/foci.o \ + $(OBJDIR)/fshell.o \ $(OBJDIR)/fusefs.o \ $(OBJDIR)/glob.o \ $(OBJDIR)/graph.o \ $(OBJDIR)/gzip.o \ $(OBJDIR)/http.o \ @@ -818,10 +823,11 @@ $(OBJDIR)/timeline.o \ $(OBJDIR)/tkt.o \ $(OBJDIR)/tktsetup.o \ $(OBJDIR)/undo.o \ $(OBJDIR)/unicode.o \ + $(OBJDIR)/unversioned.o \ $(OBJDIR)/update.o \ $(OBJDIR)/url.o \ $(OBJDIR)/user.o \ $(OBJDIR)/utf8.o \ $(OBJDIR)/util.o \ @@ -996,21 +1002,21 @@ BLDTARGETS = zlib endif openssl: $(BLDTARGETS) cd $(OPENSSLLIBDIR);./Configure --cross-compile-prefix=$(PREFIX) $(SSLCONFIG) - $(MAKE) -C $(OPENSSLLIBDIR) CC=$(TCCEXE) build_libs + $(MAKE) -C $(OPENSSLLIBDIR) PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) build_libs clean-openssl: - $(MAKE) -C $(OPENSSLLIBDIR) CC=$(TCCEXE) clean + $(MAKE) -C $(OPENSSLLIBDIR) PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) clean tcl: cd $(TCLSRCDIR)/win;./configure - $(MAKE) -C $(TCLSRCDIR)/win CC=$(TCCEXE) $(TCLTARGET) + $(MAKE) -C $(TCLSRCDIR)/win PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) $(TCLTARGET) clean-tcl: - $(MAKE) -C $(TCLSRCDIR)/win CC=$(TCCEXE) distclean + $(MAKE) -C $(TCLSRCDIR)/win PREFIX=$(PREFIX) CC=$(PREFIX)$(TCCEXE) distclean APPTARGETS += $(BLDTARGETS) ifdef FOSSIL_BUILD_SSL APPTARGETS += openssl @@ -1079,10 +1085,11 @@ $(OBJDIR)/event_.c:$(OBJDIR)/event.h \ $(OBJDIR)/export_.c:$(OBJDIR)/export.h \ $(OBJDIR)/file_.c:$(OBJDIR)/file.h \ $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h \ $(OBJDIR)/foci_.c:$(OBJDIR)/foci.h \ + $(OBJDIR)/fshell_.c:$(OBJDIR)/fshell.h \ $(OBJDIR)/fusefs_.c:$(OBJDIR)/fusefs.h \ $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h \ $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h \ $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h \ $(OBJDIR)/http_.c:$(OBJDIR)/http.h \ @@ -1150,10 +1157,11 @@ $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h \ $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h \ $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h \ $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h \ $(OBJDIR)/unicode_.c:$(OBJDIR)/unicode.h \ + $(OBJDIR)/unversioned_.c:$(OBJDIR)/unversioned.h \ $(OBJDIR)/update_.c:$(OBJDIR)/update.h \ $(OBJDIR)/url_.c:$(OBJDIR)/url.h \ $(OBJDIR)/user_.c:$(OBJDIR)/user.h \ $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h \ $(OBJDIR)/util_.c:$(OBJDIR)/util.h \ @@ -1437,10 +1445,18 @@ $(OBJDIR)/foci.o: $(OBJDIR)/foci_.c $(OBJDIR)/foci.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/foci.o -c $(OBJDIR)/foci_.c $(OBJDIR)/foci.h: $(OBJDIR)/headers + +$(OBJDIR)/fshell_.c: $(SRCDIR)/fshell.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/fshell.c >$@ + +$(OBJDIR)/fshell.o: $(OBJDIR)/fshell_.c $(OBJDIR)/fshell.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/fshell.o -c $(OBJDIR)/fshell_.c + +$(OBJDIR)/fshell.h: $(OBJDIR)/headers $(OBJDIR)/fusefs_.c: $(SRCDIR)/fusefs.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/fusefs.c >$@ $(OBJDIR)/fusefs.o: $(OBJDIR)/fusefs_.c $(OBJDIR)/fusefs.h $(SRCDIR)/config.h @@ -2005,10 +2021,18 @@ $(OBJDIR)/unicode.o: $(OBJDIR)/unicode_.c $(OBJDIR)/unicode.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/unicode.o -c $(OBJDIR)/unicode_.c $(OBJDIR)/unicode.h: $(OBJDIR)/headers + +$(OBJDIR)/unversioned_.c: $(SRCDIR)/unversioned.c $(TRANSLATE) + $(TRANSLATE) $(SRCDIR)/unversioned.c >$@ + +$(OBJDIR)/unversioned.o: $(OBJDIR)/unversioned_.c $(OBJDIR)/unversioned.h $(SRCDIR)/config.h + $(XTCC) -o $(OBJDIR)/unversioned.o -c $(OBJDIR)/unversioned_.c + +$(OBJDIR)/unversioned.h: $(OBJDIR)/headers $(OBJDIR)/update_.c: $(SRCDIR)/update.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/update.c >$@ $(OBJDIR)/update.o: $(OBJDIR)/update_.c $(OBJDIR)/update.h $(SRCDIR)/config.h Index: win/Makefile.msc ================================================================== --- win/Makefile.msc +++ win/Makefile.msc @@ -98,23 +98,23 @@ !ifndef USE_SEE USE_SEE = 0 !endif !if $(FOSSIL_ENABLE_SSL)!=0 -SSLDIR = $(B)\compat\openssl-1.0.2h +SSLDIR = $(B)\compat\openssl-1.1.0 SSLINCDIR = $(SSLDIR)\inc32 !if $(FOSSIL_DYNAMIC_BUILD)!=0 SSLLIBDIR = $(SSLDIR)\out32dll !else SSLLIBDIR = $(SSLDIR)\out32 !endif SSLLFLAGS = /nologo /opt:ref /debug -SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib +SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib crypt32.lib !if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64" !message Using 'x64' platform for OpenSSL... # BUGBUG (OpenSSL): Using "no-ssl*" here breaks the build. -# SSLCONFIG = VC-WIN64A no-asm no-ssl2 no-ssl3 +# SSLCONFIG = VC-WIN64A no-asm no-ssl3 SSLCONFIG = VC-WIN64A no-asm !if $(FOSSIL_DYNAMIC_BUILD)!=0 SSLCONFIG = $(SSLCONFIG) shared !else SSLCONFIG = $(SSLCONFIG) no-shared @@ -125,16 +125,16 @@ !else SSLNMAKE = ms\nt.mak all !endif # BUGBUG (OpenSSL): Using "OPENSSL_NO_SSL*" here breaks dynamic builds. !if $(FOSSIL_DYNAMIC_BUILD)==0 -SSLCFLAGS = -DOPENSSL_NO_SSL2 -DOPENSSL_NO_SSL3 +SSLCFLAGS = -DOPENSSL_NO_SSL3 !endif !elseif "$(PLATFORM)"=="ia64" !message Using 'ia64' platform for OpenSSL... # BUGBUG (OpenSSL): Using "no-ssl*" here breaks the build. -# SSLCONFIG = VC-WIN64I no-asm no-ssl2 no-ssl3 +# SSLCONFIG = VC-WIN64I no-asm no-ssl3 SSLCONFIG = VC-WIN64I no-asm !if $(FOSSIL_DYNAMIC_BUILD)!=0 SSLCONFIG = $(SSLCONFIG) shared !else SSLCONFIG = $(SSLCONFIG) no-shared @@ -145,16 +145,16 @@ !else SSLNMAKE = ms\nt.mak all !endif # BUGBUG (OpenSSL): Using "OPENSSL_NO_SSL*" here breaks dynamic builds. !if $(FOSSIL_DYNAMIC_BUILD)==0 -SSLCFLAGS = -DOPENSSL_NO_SSL2 -DOPENSSL_NO_SSL3 +SSLCFLAGS = -DOPENSSL_NO_SSL3 !endif !else !message Assuming 'x86' platform for OpenSSL... # BUGBUG (OpenSSL): Using "no-ssl*" here breaks the build. -# SSLCONFIG = VC-WIN32 no-asm no-ssl2 no-ssl3 +# SSLCONFIG = VC-WIN32 no-asm no-ssl3 SSLCONFIG = VC-WIN32 no-asm !if $(FOSSIL_DYNAMIC_BUILD)!=0 SSLCONFIG = $(SSLCONFIG) shared !else SSLCONFIG = $(SSLCONFIG) no-shared @@ -165,11 +165,11 @@ !else SSLNMAKE = ms\nt.mak all !endif # BUGBUG (OpenSSL): Using "OPENSSL_NO_SSL*" here breaks dynamic builds. !if $(FOSSIL_DYNAMIC_BUILD)==0 -SSLCFLAGS = -DOPENSSL_NO_SSL2 -DOPENSSL_NO_SSL3 +SSLCFLAGS = -DOPENSSL_NO_SSL3 !endif !endif !endif !if $(FOSSIL_ENABLE_TCL)!=0 @@ -373,10 +373,11 @@ event_.c \ export_.c \ file_.c \ finfo_.c \ foci_.c \ + fshell_.c \ fusefs_.c \ glob_.c \ graph_.c \ gzip_.c \ http_.c \ @@ -444,10 +445,11 @@ timeline_.c \ tkt_.c \ tktsetup_.c \ undo_.c \ unicode_.c \ + unversioned_.c \ update_.c \ url_.c \ user_.c \ utf8_.c \ util_.c \ @@ -544,10 +546,11 @@ $(OX)\event$O \ $(OX)\export$O \ $(OX)\file$O \ $(OX)\finfo$O \ $(OX)\foci$O \ + $(OX)\fshell$O \ $(OX)\fusefs$O \ $(OX)\glob$O \ $(OX)\graph$O \ $(OX)\gzip$O \ $(OX)\http$O \ @@ -620,10 +623,11 @@ $(OX)\timeline$O \ $(OX)\tkt$O \ $(OX)\tktsetup$O \ $(OX)\undo$O \ $(OX)\unicode$O \ + $(OX)\unversioned$O \ $(OX)\update$O \ $(OX)\url$O \ $(OX)\user$O \ $(OX)\utf8$O \ $(OX)\util$O \ @@ -724,10 +728,11 @@ echo $(OX)\event.obj >> $@ echo $(OX)\export.obj >> $@ echo $(OX)\file.obj >> $@ echo $(OX)\finfo.obj >> $@ echo $(OX)\foci.obj >> $@ + echo $(OX)\fshell.obj >> $@ echo $(OX)\fusefs.obj >> $@ echo $(OX)\glob.obj >> $@ echo $(OX)\graph.obj >> $@ echo $(OX)\gzip.obj >> $@ echo $(OX)\http.obj >> $@ @@ -800,10 +805,11 @@ echo $(OX)\timeline.obj >> $@ echo $(OX)\tkt.obj >> $@ echo $(OX)\tktsetup.obj >> $@ echo $(OX)\undo.obj >> $@ echo $(OX)\unicode.obj >> $@ + echo $(OX)\unversioned.obj >> $@ echo $(OX)\update.obj >> $@ echo $(OX)\url.obj >> $@ echo $(OX)\user.obj >> $@ echo $(OX)\utf8.obj >> $@ echo $(OX)\util.obj >> $@ @@ -1123,10 +1129,16 @@ $(OX)\foci$O : foci_.c foci.h $(TCC) /Fo$@ -c foci_.c foci_.c : $(SRCDIR)\foci.c translate$E $** > $@ + +$(OX)\fshell$O : fshell_.c fshell.h + $(TCC) /Fo$@ -c fshell_.c + +fshell_.c : $(SRCDIR)\fshell.c + translate$E $** > $@ $(OX)\fusefs$O : fusefs_.c fusefs.h $(TCC) /Fo$@ -c fusefs_.c fusefs_.c : $(SRCDIR)\fusefs.c @@ -1549,10 +1561,16 @@ $(OX)\unicode$O : unicode_.c unicode.h $(TCC) /Fo$@ -c unicode_.c unicode_.c : $(SRCDIR)\unicode.c translate$E $** > $@ + +$(OX)\unversioned$O : unversioned_.c unversioned.h + $(TCC) /Fo$@ -c unversioned_.c + +unversioned_.c : $(SRCDIR)\unversioned.c + translate$E $** > $@ $(OX)\update$O : update_.c update.h $(TCC) /Fo$@ -c update_.c update_.c : $(SRCDIR)\update.c @@ -1677,10 +1695,11 @@ event_.c:event.h \ export_.c:export.h \ file_.c:file.h \ finfo_.c:finfo.h \ foci_.c:foci.h \ + fshell_.c:fshell.h \ fusefs_.c:fusefs.h \ glob_.c:glob.h \ graph_.c:graph.h \ gzip_.c:gzip.h \ http_.c:http.h \ @@ -1748,10 +1767,11 @@ timeline_.c:timeline.h \ tkt_.c:tkt.h \ tktsetup_.c:tktsetup.h \ undo_.c:undo.h \ unicode_.c:unicode.h \ + unversioned_.c:unversioned.h \ update_.c:update.h \ url_.c:url.h \ user_.c:user.h \ utf8_.c:utf8.h \ util_.c:util.h \ ADDED www/aboutcgi.wiki Index: www/aboutcgi.wiki ================================================================== --- /dev/null +++ www/aboutcgi.wiki @@ -0,0 +1,214 @@ +How CGI Works In Fossil +

    Introduction

    +

    CGI or "Common Gateway Interface" is a venerable yet reliable technique for +generating dynamic web content. This article gives a quick background on how +CGI works and describes how Fossil can act as a CGI service. +

    This is a "how it works" guide. If you just want to set up Fossil +as a CGI server, see the [./server.wiki | Fossil Server Setup] page. +

    +

    A Quick Review Of CGI

    +

    +An HTTP request is a block of text that is sent by a client application +(usually a web browser) and arrives at the web server over a network +connection. The HTTP request contains a URL that describes the information +being requested. The URL in the HTTP request is typically the same URL +that appears in the URL bar at the top of the web browser that is making +the request. The URL might contain a "?" character followed +query parameters. The HTTP will usually also contain other information +such as the name of the application that made the request, whether or +not the requesting application can except a compressed reply, POST +parameters from forms, and so forth. +

    +The job of the web server is to interpret the HTTP request and formulate +an appropriate reply. +The web server is free to interpret the HTTP request in any way it wants. +But most web servers follow a similar pattern, described below. +(Note: details may vary from one web server to another.) +

    +Suppose the URL in the HTTP request looks like this: +

    /one/two/timeline/four
    +Most web servers will search their content area for files that match +some prefix of the URL. The search starts with /one, then goes to +/one/two, then /one/two/timeline, and finally +/one/two/timeline/four is checked. The search stops at the first +match. +

    +Suppose the first match is /one/two. If /one/two is an +ordinary file in the content area, then that file is returned as static +content. The "/timeline/four" suffix is silently ignored. +

    +If /one/two is a CGI script (or program), then the web server +executes the /one/two script. The output generated by +the script is collected and repackaged as the HTTP reply. +

    +Before executing the CGI script, the web server will set up various +environment variables with information useful to the CGI script: + +
    Environment
    Variable
    Meaning +
    GATEWAY_INTERFACEAlways set to "CGI/1.0" +
    REQUEST_URI + The input URL from the HTTP request. +
    SCRIPT_NAME + The prefix of the input URL that matches the CGI script name. + In this example: "/one/two". +
    PATH_INFO + The suffix of the URL beyond the name of the CGI script. + In this example: "timeline/four". +
    QUERY_STRING + The query string that follows the "?" in the URL, if there is one. +
    +

    +There are other CGI environment variables beyond those listed above. +Many Fossil servers implement the +[https://www.fossil-scm.org/fossil/test_env/two/three?abc=xyz|test_env] +webpage that shows some of the CGI environment +variables that Fossil pays attention to. +

    +In addition to setting various CGI environment variables, if the HTTP +request contains POST content, then the web server relays the POST content +to standard input of the CGI script. +

    +In summary, the task of the +CGI script is to read the various CGI environment variables and +the POST content on standard input (if any), figure out an appropriate +reply, then write that reply on standard output. +The web server will read the output from the CGI script, reformat it +into an appropriate HTTP reply, and relay the result back to the +requesting application. +The CGI script exits as soon as it generates a single reply. +The web server will (usually) persist and handle multiple HTTP requests, +but a CGI script handles just one HTTP request and then exits. +

    +The above is a rough outline of how CGI works. +There are many details omitted from this brief discussion. +See other on-line CGI tutorials for further information. +

    +

    How Fossil Acts As A CGI Program

    +
    +An appropriate CGI script for running Fossil will look something +like the following: +
    +#!/usr/bin/fossil
    +repository: /home/www/repos/project.fossil
    +
    +The first line of the script is a +"[https://en.wikipedia.org/wiki/Shebang_%28Unix%29|shebang]" +that tells the operating system what program to use as the interpreter +for this script. On unix, when you execute a script that starts with +a shebang, the operating system runs the program identified by the +shebang with a single argument that is the full pathname of the script +itself. +In our example, the interpreter is Fossil, and the argument might +be something like "/var/www/cgi-bin/one/two" (depending on how your +particular web server is configured). +

    +The Fossil program that is run as the script interpreter +is the same Fossil that runs when +you type ordinary Fossil commands like "fossil sync" or "fossil commit". +But in this case, as soon as it launches, the Fossil program +recognizes that the GATEWAY_INTERFACE environment variable is +set to "CGI/1.0" and it therefore knows that it is being used as +CGI rather than as an ordinary command-line tool, and behaves accordingly. +

    +When Fossil recognizes that it is being run as CGI, it opens and reads +the file identified by its sole argument (the file named by +argv[1]). In our example, the second line of that file +tells Fossil the location of the repository it will be serving. +Fossil then starts looking at the CGI environment variables to figure +out what web page is being requested, generates that one web page, +then exits. +

    +Usually, the webpage being requested is the first term of the +PATH_INFO environment variable. (Exceptions to this rule are noted +in the sequel.) For our example, the first term of PATH_INFO +is "timeline", which means that Fossil will generate +the [/help?cmd=/timeline|/timeline] webpage. +

    +With Fossil, terms of PATH_INFO beyond the webpage name are converted into +the "name" query parameter. Hence, the following two URLs mean +exactly the same thing to Fossil: +

      +
    1. [https://www.fossil-scm.org/fossil/info/c14ecc43] +
    2. [https://www.fossil-scm.org/fossil/info?name=c14ecc43] +
    +In both cases, the CGI script is called "/fossil". For case (A), +the PATH_INFO variable will be "info/c14ecc43" and so the +"[/help?cmd=/info]" webpage will be generated and the suffix of +PATH_INFO will be converted into the "name" query parameter, which +identifies the artifact about which information is requested. +In case (B), the PATH_INFO is just "info", but the same "name" +query parameter is set explicitly by the URL itself. +
    +

    Serving Multiple Fossil Repositories From One CGI Script

    +
    +The previous example showed how to serve a single Fossil repository +using a single CGI script. +On a website that wants to server multiple repositories, one could +simply create multiple CGI scripts, one script for each repository. +But it is also possible to serve multiple Fossil repositories from +a single CGI script. +

    +If the CGI script for Fossil contains a "directory:" line instead of +a "repository:" line, then the argument to "directory:" is the name +of a directory that contains multiple repository files, each ending +with ".fossil". For example: +

    +#!/usr/bin/fossil
    +directory: /home/www/repos
    +
    +Suppose the /home/www/repos directory contains files named +one.fossil, two.fossil, and subdir/three.fossil. +Further suppose that the name of the CGI script (relative to the root +of the webserver document area) is "cgis/example2". Then to +see the timeline for the "three.fossil" repository, the URL would be: +
    +http://example.com/cgis/example2/subdir/three/timeline +
    +Here is what happens: +
      +
    1. The input URI on the HTTP request is + /cgis/example2/subdir/three/timeline +
    2. The web server searches prefixes of the input URI until it finds + the "cgis/example2" script. The web server then sets + PATH_INFO to the "subdir/three/timeline" suffix and invokes the + "cgis/example2" script. +
    3. Fossil runs and sees the "directory:" line pointing to + "/home/www/repos". Fossil then starts pulling terms off the + front of the PATH_INFO looking for a repository. It first looks + at "/home/www/resps/subdir.fossil" but there is no such repository. + So then it looks at "/home/www/repos/subdir/three.fossil" and finds + a repository. The PATH_INFO is shortened by removing + "subdir/three/" leaving it at just "timeline". +
    4. Fossil looks at the rest of PATH_INFO to see that the webpage + requested is "timeline". +
    +
    +

    Additional Observations

    +
      +
    1. +Fossil does not distinguish between the various HTTP methods (GET, PUT, +DELETE, etc). Fossil figures out what it needs to do purely from the +webpage term of the URI. +

    2. +Fossil does not distinguish between query parameters that are part of the +URI, application/x-www-form-urlencoded or multipart/form-data encoded +parameter that are part of the POST content, and cookies. Each information +source is seen as a space of key/value pairs which are loaded into an +internal property hash table. The code that runs to generate the reply +can then reference various properties values. +Fossil does not care where the value of each property comes from (POST +content, cookies, or query parameters) only that the property exists +and has a value. +

    3. +The "[/help?cmd=ui|fossil ui]" and "[/help?cmd=server|fossil server]" commands +are implemented using a simple built-in web server that accepts incoming HTTP +requests, translates each request into a CGI invocation, then creates a +separate child Fossil process to handle each request. In other words, CGI +is used internally to implement "fossil ui/server". +

      +SCGI is processed using the same built-in web server, just modified +to parse SCGI requests instead of HTTP requests. Each SCGI request is +converted into CGI, then Fossil creates a separate child Fossil +process to handle each CGI request. +

    +
    Index: www/bugtheory.wiki ================================================================== --- www/bugtheory.wiki +++ www/bugtheory.wiki @@ -112,11 +112,11 @@ and is not shared with other repositories during a sync, push, or pull. Each repository also defines scripts used to generate web pages for creating new tickets, viewing existing tickets, and modifying an existing ticket. These scripts consist of HTML with an embedded -scripts written an a Tcl-like language called "TH1". Every new fossil +scripts written a Tcl-like language called "TH1". Every new fossil repository is created with default scripts. Paul Ruizendaal has written documentation on the TH1 language that is available at [http://www.sqliteconcepts.org/THManual.pdf]. Administrators wishing to customize their ticket entry, viewing, and editing screens should modify the default scripts to suit their needs. These screen generator Index: www/build.wiki ================================================================== --- www/build.wiki +++ www/build.wiki @@ -141,11 +141,11 @@ the optional OpenSSL support, first download the official source code for OpenSSL and extract it to an appropriately named "openssl-X.Y.ZA" subdirectory within the local [/tree?ci=trunk&name=compat | compat] directory (e.g. -"compat/openssl-1.0.2h"), then make sure that some recent +"compat/openssl-1.1.0"), then make sure that some recent Perl binaries are installed locally, and finally run one of the following commands:
     nmake /f Makefile.msc FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin
     
    Index: www/changes.wiki ================================================================== --- www/changes.wiki +++ www/changes.wiki @@ -1,11 +1,33 @@ Change Log

    Changes for Version 1.36 (2016-00-00)

    + * Add support for [./unvers.wiki|unversioned content], + the [/help?cmd=unversioned|fossil unversioned] command and the + [/help?cmd=/uv|/uv] and [/uvlist] web pages. + * The [/uv/download.html|download page] is moved into + [./unvers.wiki|unversioned content] so that the self-hosting Fossil + websites no longer uses any external content. + * Added the "Search" button to the graphical diff generated by + the --tk option on the [/help?cmd=diff|diff] command. * Update internal Unicode character tables, used in regular expression handling, from version 8.0 to 9.0. + * Update the built-in SQLite to version 3.15 (beta). Fossil now requires + the SQLITE_DBCONFIG_MAINDBNAME interface of SQLite which is only available + in SQLite version 3.15 and later and so Fossil will not work with + earlier SQLite versions. + * Fix [https://www.mail-archive.com/fossil-users@lists.fossil-scm.org/msg23618.html|multi-line timeline bug] + * Enhance the [/help?cmd=purge|fossil purge] command. + * New command [/help?cmd=shell|fossil shell]. + * SQL parameters whose names are all lower-case in Ticket Report SQL + queries are filled in using HTTP query parameter values. + * Added support for [./childprojects.wiki|child projects] that are + able to pull from their parent but not push. + * Added the -nocomplain option to the TH1 "query" command. + * Added support for the chng=GLOBLIST query parameter on the + [/help?cmd=/timeline|/timeline] webpage.

    Changes for Version 1.35 (2016-06-14)

    * Enable symlinks by default on all non-Windows platforms. * Enhance the [/md_rules|Markdown formatting] so that hyperlinks that begin ADDED www/childprojects.wiki Index: www/childprojects.wiki ================================================================== --- /dev/null +++ www/childprojects.wiki @@ -0,0 +1,57 @@ +Child Projects + +

    Background

    + +The default behavior of Fossil is to share everything (all check-ins, +tickets, wiki, etc) between all clients and all servers. Such a policy +helps to promote a cohesive design for a cathedral-style project run +by a small cliche of developers - the sort of project for which Fossil +was designed. + +But sometimes it is desirable to branch off a side project that does not +sync back to the master but does continue to track changes in the master. +For example, the master project might be an open-source project like +[https://www.sqlite.org/|SQLite] and a team might want to do a proprietary +closed-source enhancement to that master project in a separate repository. +All changes in the master project should flow forward into the derived +project, but care must be taken to prevent proprietary content from the +derived project from leaking back into the master. + +

    Child Projects

    + +A scenario such as the above can be accomplished in Fossil by creating +a child project. The child project is able to freely pull from the parent, +but the parent cannot push or pull from the child nor is the child able to +push to the parent. Content flows from parent to child only, and then only +at the request of the child. + +

    Creating a Child Project

    + +To create a new child project, first clone the parent. Then make manual +SQL changes to the child repository as follows: + +
    +UPDATE config SET name='parent-project-code' WHERE name='project-code'; +UPDATE config SET name='parent-project-name' WHERE name='project-name'; +INSERT INTO config(name,value) + VALUES('project-code',lower(hex(randomblob(20)))); +INSERT INTO config(name,value) + VALUES('project-name','CHILD-PROJECT-NAME'); +
    + +Modify the CHILD-PROJECT-NAME in the last statement to be the name of +the child project, of course. + +The repository is now a separate project, independent from its parent. +Clone the new project to the developers as needed. + +The child project and the parent project will not normally be able to sync +with one another, since they are now separate projects with distinct +project codes. However, if the +"--from-parent-project" command-line option is provided to the +"[/help?cmd=pull|fossil pull]" command in the child, and the URL of +parent repository is also provided on the command-line, then updates to +the parent project that occurred after the child was created will be added +to the child repository. Thus, by periodically doing a +pull --from-parent-project, the child project is able to stay up to date +with all the latest changes in the parent. Index: www/encryptedrepos.wiki ================================================================== --- www/encryptedrepos.wiki +++ www/encryptedrepos.wiki @@ -10,11 +10,13 @@

    Assuming you have an SEE license, the first step of compiling Fossil to use SEE is to create an SEE-enabled version of the SQLite database source code. This alternative SQLite database source file should be called "sqlite3-see.c" and should be placed in the src/ subfolder of the Fossil sources, right beside -the public-domain "sqlite3.c" source file. +the public-domain "sqlite3.c" source file. Also make a copy of the SEE-enabled +"shell.c" file, renamed as "shell-see.c", and place it in the src/ subfolder +beside the original "shell.c".

    Add the --with-see command-line option to the configuration script to enable the use of SEE on unix-like systems.

     ./configure --with-see; make
    @@ -28,10 +30,40 @@
     

    Using Encrypted Repositories

    Any Fossil repositories whose filename ends with ".efossil" is taken to be an encrypted repository. Fossil will prompt for the encryption password and attempt to open the repository database using that password.

    -Every use of an encrypted repository requires retyping the encryption password. +Every invocation of fossil on an encrypted repository requires retyping the +encryption password. +To avoid excess password typing, consider using the "fossil shell" +command which prompts for the password just once, then reuses it for each +subsequent Fossil command entered at the prompt.

    -On Windows, the "fossil server" and "fossil ui" commands do not +On Windows, the "fossil server", "fossil ui", and "fossil shell" commands do not (currently) work on an encrypted repository. +

    +

    Additional Security

    +Use the FOSSIL_SECURITY_LEVEL environment for additional protection. +
    +export FOSSIL_SECURITY_LEVEL=1
    +
    +A setting of 1 or greater +prevents fossil from trying to remember the previous sync password. +
    +export FOSSIL_SECURITY_LEVEL=2
    +
    +A setting of 2 or greater +causes all password prompts to be preceeded by a random translation matrix similar +to the following: +
    +abcde fghij klmno pqrst uvwyz
    +qresw gjymu dpcoa fhkzv inlbt
    +
    +When entering the password, the user must substitute the letter on the second +line that corresponds to the letter on the first line. Uppercase substitutes +for uppercase inputs, and lowercase substitutes for lowercase inputs. Letters +that are not in the translation matrix (digits, punctuation, and "x") are not +modified. For example, given the +translation matrix above, if the password is "pilot-9crazy-xube", then the user +must type "fmpav-9ekqtb-xirw". This simple substitution cypher helps prevent +password capture by keyloggers.
    Index: www/env-opts.md ================================================================== --- www/env-opts.md +++ www/env-opts.md @@ -258,10 +258,18 @@ `TH1_ENABLE_HOOKS`: Override the local or global setting `tcl-hooks` to enable TH1 hooks in fossil. `TH1_ENABLE_TCL`: Override the local or global setting `tcl` to enable Tcl in fossil. + +`TH1_TEST_ANON_CAPS`: Override the default anonymous permissions used +when processing the `--set-anon-caps` option for the `test-th-eval`, +`test-th-render`, and `test-th-source` test commands. + +`TH1_TEST_USER_CAPS`: Override the default user permissions used when +processing the `--set-user-caps` option for the `test-th-eval`, +`test-th-render`, and `test-th-source` test commands. `TMP`: On Windows, the location of temporary files. The first environment variable found in the environment that names an existing directory from the list `TMP`, `TEMP`, `USERPROFILE`, the Windows directory (usually `C:\WINDOWS`), `TEMP`, `TMP`, and the current Index: www/index.wiki ================================================================== --- www/index.wiki +++ www/index.wiki @@ -35,19 +35,18 @@ 2. Built-in Web Interface - Fossil has a built-in and intuitive [./webui.wiki | web interface] with a rich assortment of information pages ([./webpage-ex.md|examples]) designed to promote situational awareness. - This entire website¹ - is just a running instance of Fossil. The pages you see here - are all [./wikitheory.wiki | wiki] or - [./embeddeddoc.wiki | embedded documentation]. + This entire website is just a running instance of Fossil. + The pages you see here are all [./wikitheory.wiki | wiki] or + [./embeddeddoc.wiki | embedded documentation] or (in the case of + the [/uv/download.html|download] page) + [./unvers.wiki | unversioned files]. When you clone Fossil from one of its [./selfhost.wiki | self-hosting repositories], you get more than just source code - you get this entire website. - (¹except the - [http://www.fossil-scm.org/download.html | download] page) 3. Self-Contained - Fossil is a single self-contained stand-alone executable. To install, simply download a precompiled binary Index: www/mkindex.tcl ================================================================== --- www/mkindex.tcl +++ www/mkindex.tcl @@ -1,33 +1,36 @@ #!/bin/sh # # Run this TCL script to generate a WIKI page that contains a # permuted index of the various documentation files. # -# tclsh mkindex.tcl +# tclsh mkindex.tcl # set doclist { + aboutcgi.wiki {How CGI Works In Fossil} adding_code.wiki {Adding New Features To Fossil} adding_code.wiki {Hacking Fossil} antibot.wiki {Defense against Spiders and Bots} blame.wiki {The Annotate/Blame Algorithm Of Fossil} branching.wiki {Branching, Forking, Merging, and Tagging} bugtheory.wiki {Bug Tracking In Fossil} build.wiki {Compiling and Installing Fossil} + changes.wiki {Fossil Changelog} checkin_names.wiki {Check-in And Version Names} checkin.wiki {Check-in Checklist} - changes.wiki {Fossil Changelog} + childprojects.wiki {Child Projects} copyright-release.html {Contributor License Agreement} concepts.wiki {Fossil Core Concepts} contribute.wiki {Contributing Code or Documentation To The Fossil Project} customgraph.md {Theming: Customizing the Timeline Graph} customskin.md {Theming: Customizing The Appearance of Web Pages} custom_ticket.wiki {Customizing The Ticket System} delta_encoder_algorithm.wiki {Fossil Delta Encoding Algorithm} delta_format.wiki {Fossil Delta Format} embeddeddoc.wiki {Embedded Project Documentation} + encryptedrepos.wiki {How To Use Encrypted Repositories} env-opts.md {Environment Variables and Global Options} event.wiki {Events} faq.wiki {Frequently Asked Questions} fileformat.wiki {Fossil File Format} fiveminutes.wiki {Update and Running in 5 Minutes as a Single User} @@ -62,10 +65,11 @@ Of Fossil} tech_overview.wiki {SQLite Databases Used By Fossil} th1.md {The TH1 Scripting Language} tickets.wiki {The Fossil Ticket System} theory1.wiki {Thoughts On The Design Of The Fossil DVCS} + unvers.wiki {Unversioned Files} webpage-ex.md {Webpage Examples} webui.wiki {The Fossil Web Interface} wikitheory.wiki {Wiki In Fossil} } Index: www/permutedindex.html ================================================================== --- www/permutedindex.html +++ www/permutedindex.html @@ -35,17 +35,19 @@
  17. Bots — Defense against Spiders and
  18. Branches — Creating, Syncing, and Deleting Private
  19. Branching, Forking, Merging, and Tagging
  20. Bug Tracking In Fossil
  21. Build Process — The Fossil
  22. +
  23. CGI Works In Fossil — How
  24. Changelog — Fossil
  25. Check-in And Version Names
  26. Check-in Checklist
  27. Checklist — Check-in
  28. Checklist — Pre-Release Testing
  29. Checklist For Successful Open-Source Projects
  30. Checks — Fossil Repository Integrity Self
  31. +
  32. Child Projects
  33. Code or Documentation To The Fossil Project — Contributing
  34. Code Style Guidelines — Source
  35. Compiling and Installing Fossil
  36. Concepts — Fossil Core
  37. Configure A Fossil Server — How To
  38. @@ -71,17 +73,19 @@
  39. Documentation To The Fossil Project — Contributing Code or
  40. DVCS — Thoughts On The Design Of The Fossil
  41. DVCSes in General — Quotes: What People Are Saying About Fossil, Git, and
  42. Embedded Project Documentation
  43. Encoding Algorithm — Fossil Delta
  44. +
  45. Encrypted Repositories — How To Use
  46. Environment Variables and Global Options
  47. Events
  48. Examples — Webpage
  49. Export To And From Git — Import And
  50. Express 2010 IDE — Integrating Fossil in the Microsoft
  51. Features To Fossil — Adding New
  52. File Format — Fossil
  53. +
  54. Files — Unversioned
  55. Forking, Merging, and Tagging — Branching,
  56. Format — Fossil Delta
  57. Format — Fossil File
  58. Fossil Changelog
  59. Fossil Core Concepts
  60. @@ -109,12 +113,14 @@
  61. Hacker How-To
  62. Hacking Fossil
  63. Hints — Fossil Tips And Usage
  64. Home Page
  65. Hosting Repositories — Fossil Self
  66. +
  67. How CGI Works In Fossil
  68. How To Configure A Fossil Server
  69. How To Create A New Fossil Repository
  70. +
  71. How To Use Encrypted Repositories
  72. How-To — Hacker
  73. IDE — Integrating Fossil in the Microsoft Express 2010
  74. Implementation Of Fossil — A Technical Overview Of The Design And
  75. Import And Export To And From Git
  76. Installing Fossil — Compiling and
  77. @@ -144,16 +150,18 @@
  78. Private Branches — Creating, Syncing, and Deleting
  79. Process — The Fossil Build
  80. Project — Contributing Code or Documentation To The Fossil
  81. Project Documentation — Embedded
  82. Projects — Checklist For Successful Open-Source
  83. +
  84. Projects — Child
  85. Protocol — The Fossil Sync
  86. Questions — Frequently Asked
  87. Questions And Criticisms
  88. Quick Start Guide — Fossil
  89. Quotes: What People Are Saying About Fossil, Git, and DVCSes in General
  90. Repositories — Fossil Self Hosting
  91. +
  92. Repositories — How To Use Encrypted
  93. Repository — How To Create A New Fossil
  94. Repository Integrity Self Checks — Fossil
  95. Reviews
  96. Running in 5 Minutes as a Single User — Update and
  97. Saying About Fossil, Git, and DVCSes in General — Quotes: What People Are
  98. @@ -192,12 +200,14 @@
  99. Ticket System — Customizing The
  100. Ticket System — The Fossil
  101. Timeline Graph — Theming: Customizing the
  102. Tips And Usage Hints — Fossil
  103. Tracking In Fossil — Bug
  104. +
  105. Unversioned Files
  106. Update and Running in 5 Minutes as a Single User
  107. Usage Hints — Fossil Tips And
  108. +
  109. Use Encrypted Repositories — How To
  110. User — Update and Running in 5 Minutes as a Single
  111. Using SSL with Fossil
  112. Variables and Global Options — Environment
  113. Version Names — Check-in And
  114. Versus Git — Fossil
  115. @@ -205,6 +215,7 @@
  116. Web Pages — Theming: Customizing The Appearance of
  117. Webpage Examples
  118. What People Are Saying About Fossil, Git, and DVCSes in General — Quotes:
  119. Wiki In Fossil
  120. with Fossil — Using SSL
  121. +
  122. Works In Fossil — How CGI
  123. Index: www/server.wiki ================================================================== --- www/server.wiki +++ www/server.wiki @@ -5,11 +5,16 @@ For example, the complete [https://www.fossil-scm.org/] website, including the page you are now reading (but excepting the [https://www.fossil-scm.org/download.html|download page]), is just a Fossil server displaying the content of the self-hosting repository for Fossil.

    -

    This article is a guide for setting up your own Fossil server.

    +

    This article is a guide for setting up your own Fossil server. +

    See "[./aboutcgi.wiki|How CGI Works In Fossil]" for background +information on the underlying CGI technology. +See "[./sync.wiki|The Fossil Sync Protocol]" for information on the +wire protocol used for client/server communication.

    +

    Overview

    There are basically four ways to set up a Fossil server:
    1. A stand-alone server
    2. Using inetd or xinetd or stunnel @@ -346,15 +351,16 @@ Note also that Linux implements "getloadavg()" by accessing the "/proc/loadavg" file in the "proc" virtual filesystem. If you are running a Fossil instance inside a chroot() jail on Linux, you will need to make the "/proc" file system available inside that jail in order for this feature to work. On the self-hosting Fossil repository, this was accomplished by adding a line -to the "/etc/mtab" or "/etc/fstab" file that looks like: +to the "/etc/fstab" file that looks like:
      -chroot_jail_proc /home/www/proc proc r 0 0
      +chroot_jail_proc /home/www/proc proc ro 0 0
       
      -Pathnames should be adjusted for individual systems, of course. +The /home/www/proc pathname should be adjusted so that the "/proc" component is +in the root of the chroot jail, of course.

      To see if the load-average limiter is functional, visit the [/test_env] page of the server to view the current load average. If the value for the load average is greater than zero, that means that it is possible to activate the load-average limiter on that repository. If the load average shows Index: www/sync.wiki ================================================================== --- www/sync.wiki +++ www/sync.wiki @@ -1,20 +1,16 @@ The Fossil Sync Protocol -

      Fossil supports commands push, pull, and sync -for transferring information from one repository to another. The -command is run on the client repository. A URL for the server repository -is specified as part of the command. This document describes what happens -behind the scenes in order to synchronize the information on the two -repositories.

      +

      This document describes the wire protocol used to synchronize +content between two Fossil repositories.

      1.0 Overview

      The global state of a fossil repository consists of an unordered collection of artifacts. Each artifact is identified by its SHA1 hash expressed as a 40-character lower-case hexadecimal string. -Synchronization is simply the process of sharing artifacts between +Synchronization is the process of sharing artifacts between servers so that all servers have copies of all artifacts. Because artifacts are unordered, the order in which artifacts are received at a server is inconsequential. It is assumed that the SHA1 hashes of artifacts are unique - that every artifact has a different SHA1 hash. To a first approximation, synchronization proceeds by sharing lists @@ -26,15 +22,16 @@ shared to a few hundred.

      Each repository also has local state. The local state determines the web-page formatting preferences, authorized users, ticket formats, and similar information that varies from one repository to another. -The local state is not transferred by the push, pull, -and sync command, though some local state is transferred during -a clone in order to initialize the local state of the new -repository. The configuration push and configuration pull -commands can be used to send or receive local state.

      +The local state is not using transferred during a sync. Except, +some local state is transferred during a [/help?cmd=clone|clone] +in order to initialize the local state of the new repository. And +the [/help?cmd=configuration|config push] and +[/help?cmd=configuration|config pull] +commands can be an administrator to sync local state.

      2.0 Transport

      All communication between client and server is via HTTP requests. @@ -43,20 +40,31 @@ request.

      The server might be running as an independent server using the server command, or it might be launched from inetd or xinetd using the http command. Or the server might -be launched from CGI. The details of how the server is configured -to "listen" for incoming HTTP requests is immaterial. The important -point is that the server is listening for requests and the client -is the issuer of the requests.

      +be launched from CGI. +(See "[./server.wiki|How To Configure A Fossil Server]" for details.) +The specifics of how the server listens +for incoming HTTP requests is immaterial to this protocol. +The important point is that the server is listening for requests and +the client is the issuer of the requests.

      A single push, pull, or sync might involve multiple HTTP requests. The client maintains state between all requests. But on the server side, each request is independent. The server does not preserve any information about the client from one request to the next.

      +

      2.0.1 Encrypted Transport

      + +

      In the current implementation of Fossil, the server only +understands HTTP requests. The client can send either +clear-text HTTP requests or encrypted HTTPS requests. But when +HTTPS requests are sent, they first must be decrypted by a webserver +or proxy before being passed to the Fossil server. This limitation +may be relaxed in a future release.

      +

      2.1 Server Identification

      The server is identified by a URL argument that accompanies the push, pull, or sync command on the client. (As a convenience to users, the URL can be omitted on the client command and the same URL @@ -159,18 +167,21 @@

      Privileges are cumulative. There can be multiple successful login cards. The session privileges are the bit-wise OR of the privileges of each individual login.

      -

      3.3 File and Compressed File Cards

      +

      3.3 File Cards

      -

      Artifacts are transferred using either "file" cards, or "cfile" cards. -(The name "file" card comes from the fact that most artifacts correspond to -files, and "cfile" is just a compressed file.) +

      Artifacts are transferred using either "file" cards, or "cfile" +or "uvfile" cards. +The name "file" card comes from the fact that most artifacts correspond to +files that are under version control. +The "cfile" name is an abbreviation for "compressed file". +The "uvfile" name is an abbreviation for "unversioned file".

      -

      3.3.1 File Cards

      +

      3.3.1 Ordinary File Cards

      For sync protocols, artifacts are transferred using "file" cards. File cards come in two different formats depending on whether the artifact is sent directly or as a delta from some other artifact.

      @@ -178,11 +189,11 @@
      file artifact-id size \n content
      file artifact-id delta-artifact-id size \n content
      -

      File cards are different from all other cards in that they +

      File cards are different from most other cards in that they are followed by in-line "payload" data. The content of the artifact or the artifact delta consists of the first size bytes of the x-fossil content that immediately follow the newline that terminates the file card. Only file and cfile cards have this characteristic.

      @@ -233,10 +244,60 @@ delta artifact.

      Unlike file cards, cfile cards are only sent in one direction during a clone from server to client for clone protocol version "3" or greater.

      +

      3.3.3 Private artifacts

      + +

      "Private" content consist of artifacts that are not normally synced. +However, private content will be synced when the +the [/help?cmd=sync|fossil sync] command includes the "--private" option. +

      + +

      Private content is marked by a "private" card: + +

      +private +
      + +

      The private card has no arguments and must directly precede a +file card that contains the private content.

      + +

      3.3.4 Unversioned File Cards

      + +

      Unversioned content is sent in both directions (client to server and +server to client) using "uvfile" cards in the following format: + +

      +uvfile name mtime hash size flags \n content +
      + +

      The name field is the name of the unversioned file. The +mtime is the last modification time of the file in seconds +since 1970. The hash field is the SHA1 hash of the content +for the unversioned file, or "-" for deleted content. +The size field is the (uncompressed) size of the content +in bytes. The flags field is an integer which is interpreted +as an array of bits. The 0x0004 bit of flags indicates that +the content is to be omitted. The content might be omitted if +it is too large to transmit, or if the send merely wants to update the +modification time of the file without changing the files content. +The content is the (uncompressed) content of the file. + +

      The receiver should only accept the uvfile card if the hash and +size match the content and if the mtime is newer than any existing +instance of the same file held by the receiver. The sender will not +normally transmit a uvfile card unless all these constraints are true, +but the receiver should double-check. + +

      A server should only accept uvfile cards if the login user has +the "y" write-unversioned permission. + +

      Servers send uvfile cards in response to uvgimme cards received from +the client. Clients send uvfile cards when they determine that the server +needs the content based on uvigot cards previously received from the server. +

      3.4 Push and Pull Cards

      Among the first cards in a client-to-server message are the push and pull cards. The push card tells the server that the client is pushing content. The pull card tells the server @@ -255,10 +316,12 @@ for the transaction to proceed.

      The server will also send a push card back to the client during a clone. This is how the client determines what project code to put in the new repository it is constructing.

      + +

      The servercode argument is currently unused.

      3.5 Clone Cards

      A clone card works like a pull card in that it is sent from client to server in order to tell the server that the client @@ -320,18 +383,54 @@

      An igot card can be sent from either client to server or from server to client in order to indicate that the sender holds a copy of a particular artifact. The format is:

      -igot artifact-id +igot artifact-id ?flag?
      -

      The argument of the igot card is the ID of the artifact that +

      The first argument of the igot card is the ID of the artifact that the sender possesses. The receiver of an igot card will typically check to see if it also holds the same artifact and if not it will request the artifact using a gimme card in either the reply or in the next message.

      + +

      If the second argument exists and is "1", then the artifact +identified by the first argument is private on the sender and should +be ignored unless a "--private" [/help?cmd=sync|sync] is occurring. + +

      3.6.1 Unversioned Igot Cards

      + +

      Zero or more "uvigot" cards are sent from client to server when +synchronizing unversioned content. The format of a uvigot card is +as follows: + +

      +uvigot name mtime hash size +
      + +

      The name argument is the name of an unversioned file. +The mtime is the last modification time of the unversioned file +in seconds since 1970. +The hash is the SHA1 hash of the unversioned file content, or +"-" if the file has been deleted. +The size is the uncompressed size of the file in bytes. + +

      When the server sees a "pragma uv-hash" card for which the hash +does not match, it sends uvigot cards for every unversioned file that it +holds. The client will use this information to figure out which +unversioned files need to be synchronized. +The server might also send a uvigot card when it receives a uvgimme card +but its reply message size is already oversized and hence unable to hold +the usual uvfile reply. + +

      When a client receives a "uvigot" card, it checks to see if the +file needs to be transfered from client to server or from server to client. +If a client-to-server transmission is needed, the client schedules that +transfer to occur on a subsequent HTTP request. If a server-to-client +transfer is needed, then the client sends a "uvgimme" card back to the +server to request the file content.

      3.7 Gimme Cards

      A gimme card is sent from either client to server or from server to client. The gimme card asks the receiver to send a particular @@ -344,10 +443,26 @@

      The argument to the gimme card is the ID of the artifact that the sender wants. The receiver will typically respond to a gimme card by sending a file card in its reply or in the next message.

      +

      3.7.1 Unversioned Gimme Cards

      + +

      Sync synchronizing unversioned content, the client may send "uvgimme" +cards to the server. A uvgimme card requests that the server send +unversioned content to the client. The format of a uvgimme card is +as follows: + +

      +uvgimme name +
      + +

      The name is the name of the unversioned file found on the +server that the client would like to have. When a server sees a +uvgimme card, it normally responses with a uvfile card, though it might +also send another uvigot card if the HTTP reply is already oversized. +

      3.8 Cookie Cards

      A cookie card can be used by a server to record a small amount of state information on a client. The server sends a cookie to the client. The client sends the same cookie back to the server on @@ -477,11 +592,89 @@ it had sent a corresponding reqconfig card in its request.

      The content of the configuration item is used to overwrite the corresponding configuration data in the receiver. -

      3.11 Error Cards

      +

      3.11 Pragma Cards

      + +

      The client may try to influence the behavior of the server by +issuing a pragma card: + +

      +pragma name value... +
      + +

      The "pragma" card has at least one argument which is the pragma name. +The pragma name defines what the pragma does. +A pragma might have zero or more "value" arguments +depending on the pragma name. + +

      New pragma names may be added to the protocol from time to time +in order to enhance the capabilities of Fossil. +Unknown pragmas are silently ignored, for backwards compatibility. + +

      The following are the known pragma names as of 2016-08-03: + +

        +
      1. send-private +

        The send-private pragma instructs the server to send all of its +private artifacts to the client. The server will only obey this +request if the user has the "x" or "Private" privilege. + +

      2. send-catalog +

        The send-catalog pragma instructs the server to transmit igot +cards for every known artifact. This can help the client and server +to get back in synchronization after a prior protocol error. The +"--verily" option to the [/help?cmd=sync|fossil sync] command causes +the send-catalog pragma to be transmitted.

        + +
      3. uv-hash HASH +

        The uv-hash pragma is sent from client to server to provoke a +synchronization of unversioned content. The HASH is a SHA1 +hash of the names, modification times, and individual hashes of all +unversioned files on the client. If the unversioned content hash +from the client does not match the unversioned content hash on the +server, then the server will reply with either a "pragma uv-push-ok" +or "pragma uv-pull-only" card followed by one "uvigot" card for +each unversioned file currently held on the server. The collection +of "uvigot" cards sent in response to a "uv-hash" pragma is called +the "unversioned catalog". The client will used the unversioned +catalog to figure out which files (if any) need to be synchronized +between client and server and send appropriate "uvfile" or "uvgimme" +cards on the next HTTP request.

        + +

        If a client sends a uv-hash pragma and does not receive back +either a uv-pull-only or uv-push-ok pragma, that means that the +content on the server exactly matches the content on the client and +no further synchronization is required. + +

      4. uv-pull-only +

        A server sends the uv-pull-only pragma to the client in response +to a uv-hash pragma with a mismatched content hash argument. This +pragma indicates that there are differences in unversioned content +between the client and server but that content can only be transfered +from server to client. The server is unwilling to accept content from +the client because the client login lacks the "write-unversioned" +permission.

        + +
      5. uv-push-ok +

        A server sends the uv-push-ok pragma to the client in response +to a uv-hash pragma with a mismatched content hash argument. This +pragma indicates that there are differences in unversioned content +between the client and server and that content can only be transfered +in either direction. The server is willing to accept content from +the client because the client login has the "write-unversioned" +permission.

        + +
      + +

      3.12 Comment Cards

      + +

      Any card that begins with "#" (ASCII 0x23) is a comment card and +is silently ignored.

      + +

      3.13 Error Cards

      If the server discovers anything wrong with a request, it generates an error card in its reply. When the client sees the error card, it displays an error message to the user and aborts the sync operation. An error card looks like this:

      @@ -497,16 +690,11 @@ (ASCII 0x5C) is represented as two backslashes "\\". Apart from space and newline, no other whitespace characters nor any unprintable characters are allowed in the error message.

      -

      3.12 Comment Cards

      - -

      Any card that begins with "#" (ASCII 0x23) is a comment card and -is silently ignored.

      - -

      3.13 Unknown Cards

      +

      3.14 Unknown Cards

      If either the client or the server sees a card that is not described above, then it generates an error and aborts.

      4.0 Phantoms And Clusters

      @@ -649,10 +837,52 @@ The first three steps of a pull are combined with the first five steps of a push. Steps (4) through (7) of a pull are combined with steps (5) through (8) of a push. And steps (8) through (10) of a pull are combined with step (9) of a push.

      +

      5.4 Unversioned File Sync

      + +

      "Unversioned files" are files held in the repository +where only the most recent version of the file is kept rather than +the entire change history. Unversioned files are intended to be +used to store ephemeral content, such as compiled binaries of the +most recent release. + +

      Unversioned files are identified by name and timestamp (mtime). +Only the most recent version of each file (the version with +the largest mtime value) is retained. + +

      Unversioned files are synchronized using the +[/help?cmd=unversioned|fossil unversioned sync] command. + +

      A schematic of an unversioned file synchronization is as follows: + +

        +
      1. The client sends a "pragma uv-hash" card to the server. The argument + to the uv-hash pragma is a hash of all filesnames, mtimes, and + content hashes for the unversioned files held by the client. +
        +
      2. If the unversioned content hash from the client matches the unversioned + content hash on the server, then nothing needs to be done and the + server no-ops. But if the hashes are different, then the server + replies with either a uv-pull-only or a uv-push-ok pragma followed by + uvigot cards for all unversioned files held on the server. +
        +
      3. The client examines the uvigot cards received from the server and + determines which unversioned files need to be exchanged in order + to bring the client and server into synchronization. The client + then sends appropriate "uvgimme" or "uvfile" cards back to the + server. +
        +
      4. The server updates its unversioned file store with received "uvfile" + cards and answers "uvgimme" cards with "uvfile" cards in its reply. +
      + +

      The last two steps might be repeated multiple +times if there is more unversioned content to be transferred than will +fit comfortably in a single HTTP request. +

      6.0 Summary

      Here are the key points of the synchronization protocol:

        @@ -665,23 +895,31 @@
        • login userid nonce signature
        • push servercode projectcode
        • pull servercode projectcode
        • clone +
        • clone_seqno sequence-number
        • file artifact-id size \n content
        • file artifact-id delta-artifact-id size \n content -
        • igot artifact-id +
        • cfile artifact-id size \n content +
        • cfile artifact-id delta-artifact-id size \n content +
        • uvfile name mtime hash size flags \n content +
        • private +
        • igot artifact-id ?flag? +
        • uvigot name mtime hash size
        • gimme artifact-id +
        • uvgimme name
        • cookie cookie-text
        • reqconfig parameter-name
        • config parameter-name size \n content -
        • # arbitrary-text... +
        • pragma name value...
        • error error-message +
        • # arbitrary-text...
      1. Phantoms are artifacts that a repository knows exist but does not possess.
      2. Clusters are artifacts that contain IDs of other artifacts.
      3. Clusters are created automatically on the server during a pull.
      4. Repositories keep track of all artifacts that are not named in any cluster and send igot messages for those artifacts.
      5. Repositories keep track of all the phantoms they hold and send gimme messages for those artifacts.
      Index: www/th1.md ================================================================== --- www/th1.md +++ www/th1.md @@ -418,11 +418,11 @@ Outputs the STRING unchanged. TH1 query Command ------------------------------------- - * query SQL CODE + * query ?-nocomplain? SQL CODE Runs the SQL query given by the SQL argument. For each row in the result set, run CODE. In SQL, parameters such as $var are filled in using the value of variable ADDED www/unvers.wiki Index: www/unvers.wiki ================================================================== --- /dev/null +++ www/unvers.wiki @@ -0,0 +1,99 @@ +Unversioned Content +

      Unversioned Content

      + +"Unversioned content" or "unversioned files" are +files stored in a Fossil repository without history. +Only the newest version of each unversioned file is retained. + +Though history is omitted, unversioned content is synced between +respositories. In the event of a conflict during a sync, the most recent +version of each unversioned file is retained and older versions are discarded. + +Unversioned files are useful for storing ephemeral content such as builds +or frequently changing web pages. +The [https://www.fossil-scm.org/fossil/uv/download.html|download] page of +the self-hosting Fossil repository is stored as unversioned +content, for example. + +

      Accessing Unversioned Files

      + +Unversioned files are not a part of a check-out. +Unversioned files are intended to be accessible as web pages using +URLs of the form: "http://domain/cgi-script/uv/FILENAME". +In other words, the URI method "uv" (short for "unversioned") +followed by the name of the unversioned file will retrieve the content +of the file. The mimetype is inferred from the filename suffix. + +The content of unversioned files can also be retrieved using the +[/help?cmd=unversioned|fossil unvers cat FILENAME] command. + +A list of all unversioned files on a server can be seen using +the [/help?cmd=/uvlist|/uvlist] URL. ([/uvlist|example]). + +

      Syncing Unversioned Files

      + +Unversioned content is synced between respositories, though not by default. +Special commands or command-line options are required. +Unversioned content can be synced using the following commands: + +
      +fossil sync -u
      +fossil clone -u URL local-repo-name
      +fossil unversioned sync
      +
      + +The [/help?cmd=sync|fossil sync] and [/help?cmd=clone|fossil clone] +commands will synchronize unversioned content if and only if the +"-u" (or "--unversioned") command-line option is supplied. The +[/help?cmd=unversioned|fossil unversioned sync] command will synchronize the +unversioned content without synchronizing anything else. + +Notice that the "-u" option does not work on +[/help?cmd=push|fossil push] or [/help?cmd=pull|fossil pull]. +The "-u" option is only available on "sync" and "clone". + +A rough equivalent of an unversioned pull would be the +[/help?cmd=unversioned|fossil unversioned revert] command. The +"unversioned revert" +command causes the unversioned content on the local repository to overwritten +by the unversioned content found on the remote repository. + +

      Implementation Details

      + +(This section outlines the current implementation of unversioned +files. This is not an interface spec and hence subject to change.) + +Unversioned content is stored in the repository in the +"unversioned" table: + +
      +CREATE TABLE unversioned(
      +  uvid INTEGER PRIMARY KEY AUTOINCREMENT,  -- unique ID for this file
      +  name TEXT UNIQUE,       -- Name of the file
      +  rcvid INTEGER,          -- From whence this file was received
      +  mtime DATETIME,         -- Last change (seconds since 1970)
      +  hash TEXT,              -- SHA1 hash of uncompressed content
      +  sz INTEGER,             -- Size of uncompressed content
      +  encoding INT,           -- 0: plaintext  1: zlib compressed
      +  content BLOB            -- File content
      +);
      +
      + +If there are no unversioned files in the repository, then the +"unversioned" table does not necessarily exist. +A simple way to purge all unversioned content from a repository +is to run: + +
      +fossil sql "DROP TABLE unversioned; VACUUM;"
      +
      + +No delta compression is performed on unversioned files, since there is no +history to delta against. + +Unversioned content is exchanged between servers as whole, uncompressed +files (though the content does get compressed when the overall HTTP message +payload is compressed). SHA1 hash exchanges are used to avoid sending +content over the wire unnecessarily. See the +[./sync.wiki|synchronization protocol documentation] for further +information. Index: www/webui.wiki ================================================================== --- www/webui.wiki +++ www/webui.wiki @@ -5,24 +5,25 @@ development project: * [./bugtheory.wiki | Ticketing and bug tracking] * [./wikitheory.wiki | Wiki] * [./embeddeddoc.wiki | On-line documentation] - * Status information + * [./event.wiki | Technical notes] * Timelines + * Full text search over all of the above + * Status information * Graphs of revision and branching history - * [./event.wiki | Technical notes] * File and version lists and differences * Download historical versions as ZIP archives * Historical change data * Add and remove tags on check-ins * Move check-ins between branches * Revise check-in comments * Manage user credentials and access permissions * And so forth... (some [./webpage-ex.md|examples]) -You get all of this, and more, for free when you use Fossil. +You get all of this, and more, for free when you use Fossil. There are no extra programs to install or setup. Everything you need is already pre-configured and built into the self-contained, stand-alone Fossil executable. As an example of how useful this web interface can be, @@ -52,11 +53,11 @@ fossil ui existing-repository.fossil Substitute the name of your repository, of course. The "ui" command will start a webserver running (it figures out an -available TCP port to use on its own) and then automatically launches +available TCP port to use on its own) and then automatically launches your web browser to point at that server. If you run the "ui" command from within an open check-out, you can omit the repository name: fossil ui @@ -150,11 +151,11 @@ Adjust the script above so that the paths are correct for your system, of course, and also make sure the Fossil binary is installed on the server. But that is all you have to do. You now have everything you need to host -a distributed software development project in less than five minutes using a +a distributed software development project in less than five minutes using a two-line CGI script. Instructions for setting up an SCGI server are [./scgi.wiki | available separately]. @@ -164,11 +165,11 @@ xinetd. An inetd configuration line sufficient to launch the Fossil web interface looks like this: 80 stream tcp nowait.1000 root /usr/local/bin/fossil \ - /usr/local/bin/fossil http /home/www/sample-project.fossil + /usr/local/bin/fossil http /home/www/sample-project.fossil As always, you'll want to adjust the pathnames to whatever is appropriate for your system. The xinetd setup uses a different syntax but follows the same idea.