Started implementing assets - docs needed.
jump to
@@ -0,0 +1,92 @@
+### assets (LiteStore Assets) + +> %note% +> API v8 Required +> +> This resource has been introduced in version 5 of the LiteStore API. + +Assets represents another way to query LiteStore Documents. All documents can also be retrieved via `/assets/` instead of docs, but when doing so: +* a non-row version of the document will always be returned +* when querying a folder without specifying a document ID, LiteStore will attempt to retrieve an `index.html` or `index.htm` file within that folder + +This is particularly useful when your documents have been imported from the filesystem and you need to effectively serve files. + +#### OPTIONS assets + +Returns the allowed HTTP verbs for this resource. + +##### Example + +``` +$ curl -i -X OPTIONS 'http://127.0.0.1:9500/assets' +HTTP/1.1 200 OK +Content-Length: 0 +Access-Control-Allow-Methods: GET,OPTIONS +Allow: GET,OPTIONS +Access-Control-Allow-Headers: Content-Type +Access-Control-Allow-Origin: * +Server: LiteStore/1.12.0 +``` + +#### OPTIONS assets/:id + +Returns the allowed HTTP verbs for this resource. + +##### Example + +``` +curl -i -X OPTIONS 'http://127.0.0.1:9500/assets/test.json' +HTTP/1.1 200 OK +Content-Length: 0 +Access-Control-Allow-Methods: GET,OPTIONS +Allow: GET,OPTIONS +Access-Control-Allow-Headers: Content-Type +Access-Control-Allow-Origin: * +Server: LiteStore/1.12.0 +``` + +#### OPTIONS docs/:folder/ + +Returns the allowed HTTP verbs for this resource. + +##### Example + +``` +$ curl -i -X OPTIONS 'http://127.0.0.1:9500/docs/test/' +HTTP/1.1 200 OK +Content-Length: 0 +Access-Control-Allow-Methods: GET,OPTIONS +Allow: GET,OPTIONS +Access-Control-Allow-Headers: Content-Type +Access-Control-Allow-Origin: * +Server: LiteStore/1.12.0 +``` + +#### GET assets + +Retrieves the file `assets/index.html` or `assets/index.htm` if not found. + + +#### GET assets/:folder/ + + +Retrieves a list of documents in JSON format starting with the specified folder path (it must end with '/'). + + +#### GET assets/:id + +Retrieves the specified document. By default the response is returned in the document's content type; however, it is possible to retrieve the raw document (including metadata) in JSON format by setting the **raw** query string option to true. + +##### Example: original content type + +``` +$ curl -i 'http://127.0.0.1:9500/docs/test' +HTTP/1.1 200 OK +Content-Length: 24 +Content-Type: text/plain +Access-Control-Allow-Headers: Content-Type +Access-Control-Allow-Origin: * +Server: LiteStore/1.0.3 + +This is a test document. +```
@@ -883,7 +883,7 @@ options.select = @["documents.id AS id", "created", "modified"]
try: parseQueryOptions(req.url.query, options); if id != "" and options.folder == "": - if req.url.query.contains("raw=true"): + if req.url.query.contains("raw=true") or req.headers.hasKey("Accept") and req.headers["Accept"] == "application/json": return LS.getRawDocument(id, options, req) else: return LS.getDocument(id, options, req)
@@ -0,0 +1,1295 @@
+import + asynchttpserver, + strutils, + sequtils, + cgi, + strtabs, + pegs, + json, + os, + uri, + tables, + times +import + types, + contenttypes, + core, + utils, + logger, + duktape + +# Helper procs + +proc sqlOp(op: string): string = + let table = newStringTable() + table["not eq"] = "<>" + table["eq"] = "==" + table["gt"] = ">" + table["gte"] = ">=" + table["lt"] = "<" + table["lte"] = "<=" + table["contains"] = "contains" + table["like"] = "like" + return table[op] + +proc orderByClauses*(str: string): string = + var clauses = newSeq[string]() + var fragments = str.split(",") + let clause = peg""" + clause <- {[-+]} {field} + field <- ('id' / 'created' / 'modified' / path) + path <- '$' (objField)+ + ident <- [a-zA-Z0-9_]+ + objField <- '.' ident + """ + for f in fragments: + var matches = @["", ""] + if f.find(clause, matches) != -1: + var field = matches[1] + if field[0] == '$': + field = "json_extract(documents.data, '$1')" % matches[1] + if matches[0] == "-": + clauses.add("$1 COLLATE NOCASE DESC" % field) + else: + clauses.add("$1 COLLATE NOCASE ASC" % field) + return clauses.join(", ") + +proc selectClause*(str: string, options: var QueryOptions) = + let tokens = """ + path <- '$' (objItem / objField)+ + ident <- [a-zA-Z0-9_]+ + objIndex <- '[' \d+ ']' + objField <- '.' ident + objItem <- objField objIndex + """ + let fields = peg(""" + fields <- ^{field} (\s* ',' \s* {field})*$ + field <- path \s+ ('as' / 'AS') \s+ ident + """ & tokens) + let field = peg(""" + field <- ^{path} \s+ ('as' / 'AS') \s+ {ident}$ + """ & tokens) + var fieldMatches = newSeq[string](10) + if str.strip.match(fields, fieldMatches): + for m in fieldMatches: + if m.len > 0: + var rawTuple = newSeq[string](2) + if m.match(field, rawTuple): + options.jsonSelect.add((path: rawTuple[0], alias: rawTuple[1])) + +proc filterClauses*(str: string, options: var QueryOptions) = + let tokens = """ + operator <- 'not eq' / 'eq' / 'gte' / 'gt' / 'lte' / 'lt' / 'contains' / 'like' + value <- string / number / 'null' / 'true' / 'false' + string <- '"' ('\\"' . / [^"])* '"' + number <- '-'? '0' / [1-9] [0-9]* ('.' [0-9]+)? (( 'e' / 'E' ) ( '+' / '-' )? [0-9]+)? + path <- '$' (objItem / objField)+ + ident <- [a-zA-Z0-9_]+ + objIndex <- '[' \d+ ']' + objField <- '.' ident + objItem <- objField objIndex + """ + let clause = peg(""" + clause <- {path} \s+ {operator} \s+ {value} + """ & tokens) + let andClauses = peg(""" + andClauses <- ^{clause} (\s+ 'and' \s+ {clause})*$ + clause <- path \s+ operator \s+ value + """ & tokens) + let orClauses = peg(""" + orClauses <- ^{andClauses} (\s+ 'or' \s+ {andClauses})*$ + andClauses <- clause (\s+ 'and' \s+ clause)* + clause <- path \s+ operator \s+ value + """ & tokens) + var orClausesMatches = newSeq[string](10) + discard str.strip.match(orClauses, orClausesMatches) + var parsedClauses = newSeq[seq[seq[string]]]() + for orClause in orClausesMatches: + if orClause.len > 0: + var andClausesMatches = newSeq[string](10) + discard orClause.strip.match(andClauses, andClausesMatches) + var parsedAndClauses = newSeq[seq[string]]() + for andClause in andClausesMatches: + if andClause.len > 0: + var clauses = newSeq[string](3) + discard andClause.strip.match(clause, clauses) + clauses[1] = sqlOp(clauses[1]) + if clauses[2] == "true": + clauses[2] = "1" + elif clauses[2] == "false": + clauses[2] = "0" + parsedAndClauses.add clauses + if parsedAndClauses.len > 0: + parsedClauses.add parsedAndClauses + if parsedClauses.len == 0: + return + var currentArr = 0 + var tables = newSeq[string]() + let resOrClauses = parsedClauses.map do (it: seq[seq[string]]) -> string: + let resAndClauses = it.map do (x: seq[string]) -> string: + if x[1] == "contains": + currentArr = currentArr + 1 + tables.add "json_each(documents.data, '$1') AS arr$2" % [x[0], $currentArr] + return "arr$1.value == $2" % [$currentArr, x[2]] + else: + var arr = @[x[0], x[1], x[2]] + if x[1] == "like": + arr[2] = x[2].replace('*', '%') + return "json_extract(documents.data, '$1') $2 $3 " % arr + return resAndClauses.join(" AND ") + options.tables = options.tables & tables + options.jsonFilter = resOrClauses.join(" OR ") + +proc parseQueryOption*(fragment: string, options: var QueryOptions) = + if fragment == "": + return + var pair = fragment.split('=') + if pair.len < 2 or pair[1] == "": + raise newException(EInvalidRequest, "Invalid query string fragment '$1'" % fragment) + try: + pair[1] = pair[1].replace("+", "%2B").decodeURL + except: + raise newException(EInvalidRequest, "Unable to decode query string fragment '$1'" % fragment) + case pair[0]: + of "filter": + filterClauses(pair[1], options) + if options.jsonFilter == "": + raise newException(EInvalidRequest, "Invalid filter clause: $1" % pair[1].replace("\"", "\\\"")) + of "select": + selectClause(pair[1], options) + if options.jsonSelect.len == 0: + raise newException(EInvalidRequest, "Invalid select clause: $1" % pair[1].replace("\"", "\\\"")) + of "like": + options.like = pair[1] + of "search": + options.search = pair[1] + of "tags": + options.tags = pair[1] + of "created-after": + try: + options.createdAfter = pair[1].parseInt.fromUnix.utc.format("yyyy-MM-dd'T'HH:mm:ss'Z'") + except: + raise newException(EInvalidRequest, "Invalid created-after value: $1" % getCurrentExceptionMsg()) + of "created-before": + try: + options.createdBefore = pair[1].parseInt.fromUnix.utc.format("yyyy-MM-dd'T'HH:mm:ss'Z'") + except: + raise newException(EInvalidRequest, "Invalid created-before value: $1" % getCurrentExceptionMsg()) + of "modified-after": + try: + options.modifiedAfter = pair[1].parseInt.fromUnix.utc.format("yyyy-MM-dd'T'HH:mm:ss'Z'") + except: + raise newException(EInvalidRequest, "Invalid modified.after value: $1" % getCurrentExceptionMsg()) + of "modified-before": + try: + options.modifiedBefore = pair[1].parseInt.fromUnix.utc.format("yyyy-MM-dd'T'HH:mm:ss'Z'") + except: + raise newException(EInvalidRequest, "Invalid modified-before value: $1" % getCurrentExceptionMsg()) + of "limit": + try: + options.limit = pair[1].parseInt + except: + raise newException(EInvalidRequest, "Invalid limit value: $1" % getCurrentExceptionMsg()) + of "offset": + try: + options.offset = pair[1].parseInt + except: + raise newException(EInvalidRequest, "Invalid offset value: $1" % getCurrentExceptionMsg()) + of "sort": + let orderby = pair[1].orderByClauses() + if orderby != "": + options.orderby = orderby + else: + raise newException(EInvalidRequest, "Invalid sort value: $1" % pair[1]) + of "contents", "raw": + discard + else: + discard + +proc parseQueryOptions*(querystring: string, options: var QueryOptions) = + var q = querystring + if q.startsWith("?"): + q = q[1 .. q.len - 1] + var fragments = q.split('&') + for f in fragments: + f.parseQueryOption(options) + +proc validate*(req: LSRequest, LS: LiteStore, resource: string, id: string, cb: proc(req: LSRequest, LS: LiteStore, resource: string, id: string):LSResponse): LSResponse = + if req.reqMethod == HttpPost or req.reqMethod == HttpPut or req.reqMethod == HttpPatch: + var ct = "" + let body = req.body.strip + if body == "": + return resError(Http400, "Bad request: No content specified for document.") + if req.headers.hasKey("Content-Type"): + ct = req.headers["Content-Type"] + case ct: + of "application/json": + try: + discard body.parseJson() + except: + return resError(Http400, "Invalid JSON content - $1" % getCurrentExceptionMsg()) + else: + discard + return cb(req, LS, resource, id) + +proc patchTag(tags: var seq[string], index: int, op, path, value: string): bool = + LOG.debug("- PATCH -> $1 tag['$2'] = \"$3\" - Total tags: $4." % [op, $index, $value, $tags.len]) + case op: + of "remove": + let tag = tags[index] + if not tag.startsWith("$"): + tags[index] = "" # Not removing element, otherwise subsequent indexes won't work! + else: + raise newException(EInvalidRequest, "cannot remove system tag: $1" % tag) + of "add": + if value.match(PEG_USER_TAG): + tags.insert(value, index) + else: + if value.strip == "": + raise newException(EInvalidRequest, "tag not specified." % value) + else: + raise newException(EInvalidRequest, "invalid tag: $1" % value) + of "replace": + if value.match(PEG_USER_TAG): + if tags[index].startsWith("$"): + raise newException(EInvalidRequest, "cannot replace system tag: $1" % tags[index]) + else: + tags[index] = value + else: + if value.strip == "": + raise newException(EInvalidRequest, "tag not specified." % value) + else: + raise newException(EInvalidRequest, "invalid tag: $1" % value) + of "test": + if tags[index] != value: + return false + else: + raise newException(EInvalidRequest, "invalid patch operation: $1" % op) + return true + +proc patchData*(data: var JsonNode, origData: JsonNode, op: string, path: string, value: JsonNode): bool = + LOG.debug("- PATCH -> $1 path $2 with $3" % [op, path, $value]) + var keys = path.replace(peg"^\/data\/", "").split("/") + if keys.len == 0: + raise newException(EInvalidRequest, "no valid path specified: $1" % path) + var d = data + var dorig = origData + var c = 1 + for key in keys: + if d.kind == JArray: + try: + var index = key.parseInt + if c >= keys.len: + d.elems[index] = value + case op: + of "remove": + d.elems.del(index) + of "add": + d.elems.insert(value, index) + of "replace": + d.elems[index] = value + of "test": + if d.elems[index] != value: + return false + else: + raise newException(EInvalidRequest, "invalid patch operation: $1" % op) + else: + d = d[index] + dorig = dorig[index] + except: + raise newException(EInvalidRequest, "invalid index key '$1' in path '$2'" % [key, path]) + else: + if c >= keys.len: + case op: + of "remove": + if d.hasKey(key): + d.delete(key) + else: + raise newException(EInvalidRequest, "key '$1' not found in path '$2'" % [key, path]) + of "add": + d[key] = value + of "replace": + if d.hasKey(key): + d[key] = value + else: + raise newException(EInvalidRequest, "key '$1' not found in path '$2'" % [key, path]) + of "test": + if dorig.hasKey(key): + if dorig[key] != value: + return false + else: + raise newException(EInvalidRequest, "key '$1' not found in path '$2'" % [key, path]) + else: + raise newException(EInvalidRequest, "invalid patch operation: $1" % op) + else: + d = d[key] + dorig = dorig[key] + c += 1 + return true + + +proc applyPatchOperation*(data: var JsonNode, origData: JsonNode, tags: var seq[string], op: string, path: string, value: JsonNode): bool = + var matches = @[""] + let p = peg""" + path <- ^tagPath / fieldPath$ + tagPath <- '\/tags\/' {\d+} + fieldPath <- '\/data\/' ident ('\/' ident)* + ident <- [a-zA-Z0-9_]+ / '-' + """ + if path.find(p, matches) == -1: + raise newException(EInvalidRequest, "cannot patch path '$1'" % path) + if path.match(peg"^\/tags\/"): + let index = matches[0].parseInt + if value.kind != JString: + raise newException(EInvalidRequest, "tag '$1' is not a string." % $value) + let tag = value.getStr + return patchTag(tags, index, op, path, tag) + elif tags.contains("$subtype:json"): + return patchData(data, origData, op, path, value) + else: + raise newException(EInvalidRequest, "cannot patch data of a non-JSON document.") + +# Low level procs + +proc getTag*(LS: LiteStore, id: string, options = newQueryOptions(), req: LSRequest): LSResponse = + let doc = LS.store.retrieveTag(id, options) + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + if doc == newJNull(): + result = resTagNotFound(id) + else: + result.content = $doc + result.code = Http200 + +proc getStore*(LS: LiteStore, id: string, options = newQueryOptions(), req: LSRequest): LSResponse = + if (not LSDICT.hasKey(id)): + return resStoreNotFound(id) + let store = LSDICT[id] + var doc = newJObject() + doc["id"] = %id + doc["file"] = %store.file + doc["config"] = store.config + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + result.content = $doc + result.code = Http200 + +proc getIndex*(LS: LiteStore, id: string, options = newQueryOptions(), req: LSRequest): LSResponse = + let doc = LS.store.retrieveIndex(id, options) + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + if doc == newJNull(): + result = resIndexNotFound(id) + else: + result.content = $doc + result.code = Http200 + +proc getRawDocument*(LS: LiteStore, id: string, options = newQueryOptions(), req: LSRequest): LSResponse = + let doc = LS.store.retrieveRawDocument(id, options) + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + if doc == "": + result = resDocumentNotFound(id) + else: + result.content = doc + result.code = Http200 + +proc getDocument*(LS: LiteStore, id: string, options = newQueryOptions(), req: LSRequest): LSResponse = + let doc = LS.store.retrieveDocument(id, options) + if doc.data == "": + result = resDocumentNotFound(id) + else: + result.headers = doc.contenttype.ctHeader + setOrigin(LS, req, result.headers) + result.content = doc.data + result.code = Http200 + +proc deleteDocument*(LS: LiteStore, id: string, req: LSRequest): LSResponse = + let doc = LS.store.retrieveDocument(id) + if doc.data == "": + result = resDocumentNotFound(id) + else: + try: + let res = LS.store.destroyDocument(id) + if res == 0: + result = resError(Http500, "Unable to delete document '$1'" % id) + else: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Content-Length"] = "0" + result.content = "" + result.code = Http204 + except: + result = resError(Http500, "Unable to delete document '$1'" % id) + +proc getTags*(LS: LiteStore, options: QueryOptions = newQueryOptions(), req: LSRequest): LSResponse = + var options = options + let t0 = cpuTime() + let docs = LS.store.retrieveTags(options) + let orig_limit = options.limit + let orig_offset = options.offset + options.limit = 0 + options.offset = 0 + options.select = @["COUNT(tag_id)"] + let total = LS.store.countTags(prepareSelectTagsQuery(options), options.like.replace("*", "%")) + var content = newJObject() + if options.like != "": + content["like"] = %(options.like.decodeURL) + if orig_limit > 0: + content["limit"] = %orig_limit + if orig_offset > 0: + content["offset"] = %orig_offset + content["total"] = %total + content["execution_time"] = %(cputime()-t0) + content["results"] = docs + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + result.content = content.pretty + result.code = Http200 + +proc getStores(LS: LiteStore, options: QueryOptions = newQueryOptions(), req: LSRequest): LSResponse = + let t0 = cpuTime() + var docs = newJArray() + for k, v in LSDICT.pairs: + var store = newJObject() + store["id"] = %k + store["file"] = %v.file + store["config"] = v.config + docs.add(store) + var content = newJObject() + content["total"] = %LSDICT.len + content["execution_time"] = %(cputime()-t0) + content["results"] = docs + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + result.content = content.pretty + result.code = Http200 + +proc getIndexes*(LS: LiteStore, options: QueryOptions = newQueryOptions(), req: LSRequest): LSResponse = + var options = options + let t0 = cpuTime() + let docs = LS.store.retrieveIndexes(options) + let orig_limit = options.limit + let orig_offset = options.offset + options.limit = 0 + options.offset = 0 + options.select = @["COUNT(name)"] + let total = LS.store.countIndexes(prepareSelectIndexesQuery(options), options.like.replace("*", "%")) + var content = newJObject() + if options.like != "": + content["like"] = %(options.like.decodeURL) + if orig_limit > 0: + content["limit"] = %orig_limit + if orig_offset > 0: + content["offset"] = %orig_offset + content["total"] = %total + content["execution_time"] = %(cputime()-t0) + content["results"] = docs + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + result.content = content.pretty + result.code = Http200 + +proc getRawDocuments*(LS: LiteStore, options: QueryOptions = newQueryOptions(), req: LSRequest): LSResponse = + var options = options + let t0 = cpuTime() + let docs = LS.store.retrieveRawDocuments(options) + let orig_limit = options.limit + let orig_offset = options.offset + options.limit = 0 + options.offset = 0 + options.select = @["COUNT(docid)"] + let total = LS.store.retrieveRawDocuments(options)[0].num + var content = newJObject() + if options.folder != "": + content["folder"] = %(options.folder) + if options.search != "": + content["search"] = %(options.search.decodeURL) + if options.tags != "": + content["tags"] = newJArray() + for tag in options.tags.replace("+", "%2B").decodeURL.split(","): + content["tags"].add(%tag) + if orig_limit > 0: + content["limit"] = %orig_limit + if orig_offset > 0: + content["offset"] = %orig_offset + if options.orderby != "": + content["sort"] = %options.orderby + content["total"] = %total + content["execution_time"] = %(cputime()-t0) + content["results"] = docs + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + result.content = content.pretty + result.code = Http200 + +proc getInfo*(LS: LiteStore, req: LSRequest): LSResponse = + let info = LS.store.retrieveInfo() + let version = info[0] + let total_documents = info[1] + let total_tags = LS.store.countTags() + let tags = LS.store.retrieveTagsWithTotals() + var content = newJObject() + content["version"] = %(LS.appname & " v" & LS.appversion) + content["datastore_version"] = %version + content["api_version"] = %7 + content["size"] = %($((LS.file.getFileSize().float/(1024*1024)).formatFloat(ffDecimal, 2)) & " MB") + content["read_only"] = %LS.readonly + content["log_level"] = %LS.loglevel + if LS.directory.len == 0: + content["directory"] = newJNull() + else: + content["directory"] = %LS.directory + content["mount"] = %LS.mount + if LS.config != newJNull() and LS.config.hasKey("stores") and LS.config["stores"].len > 0: + content["additional_stores"] = %toSeq(LS.config["stores"].keys) + else: + content["additional_stores"] = newJArray() + if LS.auth != newJNull(): + content["auth"] = %true + else: + content["auth"] = %false + content["total_documents"] = %total_documents + content["total_tags"] = %total_tags + content["tags"] = tags + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + result.content = content.pretty + result.code = Http200 + +proc putIndex*(LS: LiteStore, id, field: string, req: LSRequest): LSResponse = + try: + if (not id.match(PEG_INDEX)): + return resError(Http400, "invalid index ID: $1" % id) + if (not field.match(PEG_JSON_FIELD)): + return resError(Http400, "invalid field path: $1" % field) + if (LS.store.retrieveIndex(id) != newJNull()): + return resError(Http409, "Index already exists: $1" % id) + LS.store.createIndex(id, field) + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + result.content = "{\"id\": \"$1\", \"field\": \"$2\"}" % [id, field] + result.code = Http201 + except: + eWarn() + result = resError(Http500, "Unable to create index.") + +proc putStore*(LS: LiteStore, id: string, config: JsonNode, req: LSRequest): LSResponse = + try: + if (not id.match(PEG_STORE) or id == "master"): + return resError(Http400, "invalid store ID: $1" % id) + if (LSDICT.hasKey(id)): + return resError(Http409, "Store already exists: $1" % id) + let store = LS.addStore(id, id & ".db", config) + LS.updateConfig() + LSDICT[id] = store + result = getStore(LS, id, newQueryOptions(), req) + result.code = Http201 + except: + eWarn() + result = resError(Http500, "Unable to create store.") + +proc deleteIndex*(LS: LiteStore, id: string, req: LSRequest): LSResponse = + if (not id.match(PEG_INDEX)): + return resError(Http400, "invalid index ID: $1" % id) + if (LS.store.retrieveIndex(id) == newJNull()): + return resError(Http404, "Index not found: $1" % id) + try: + LS.store.dropIndex(id) + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Content-Length"] = "0" + result.content = "" + result.code = Http204 + except: + eWarn() + result = resError(Http500, "Unable to delete index.") + +proc deleteStore*(LS: LiteStore, id: string, req: LSRequest): LSResponse = + if (not id.match(PEG_STORE)): + return resError(Http400, "invalid store ID: $1" % id) + if (not LSDICT.hasKey(id)): + return resError(Http404, "Store not found: $1" % id) + try: + LSDICT.del(id) + if LS.config.hasKey("stores") and LS.config["stores"].hasKey(id): + LS.config["stores"].delete(id) + LS.updateConfig() + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Content-Length"] = "0" + result.content = "" + result.code = Http204 + except: + eWarn() + result = resError(Http500, "Unable to delete index.") + +proc postDocument*(LS: LiteStore, body: string, ct: string, folder="", req: LSRequest): LSResponse = + if not folder.isFolder: + return resError(Http400, "Invalid folder specified when creating document: $1" % folder) + try: + var doc = LS.store.createDocument(folder, body, ct) + if doc != "": + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + result.content = doc + result.code = Http201 + else: + result = resError(Http500, "Unable to create document.") + except: + eWarn() + result = resError(Http500, "Unable to create document.") + +proc putDocument*(LS: LiteStore, id: string, body: string, ct: string, req: LSRequest): LSResponse = + if id.isFolder: + return resError(Http400, "Invalid ID '$1' (Document IDs cannot end with '/')." % id) + let doc = LS.store.retrieveDocument(id) + if doc.data == "": + # Create a new document + var doc = LS.store.createDocument(id, body, ct) + if doc != "": + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + result.content = doc + result.code = Http201 + else: + result = resError(Http500, "Unable to create document.") + else: + # Update existing document + try: + var doc = LS.store.updateDocument(id, body, ct) + if doc != "": + result.headers = ctJsonHeader() + setOrigin(LS, req, result.headers) + result.content = doc + result.code = Http200 + else: + result = resError(Http500, "Unable to update document '$1'." % id) + except: + result = resError(Http500, "Unable to update document '$1'." % id) + +proc patchDocument*(LS: LiteStore, id: string, body: string, req: LSRequest): LSResponse = + var apply = true + let jbody = body.parseJson + if jbody.kind != JArray: + return resError(Http400, "Bad request: PATCH request body is not an array.") + var options = newQueryOptions() + options.select = @["documents.id AS id", "created", "modified", "data"] + let doc = LS.store.retrieveRawDocument(id, options) + if doc == "": + return resDocumentNotFound(id) + let jdoc = doc.parseJson + var tags = newSeq[string]() + var origTags = newSeq[string]() + for tag in jdoc["tags"].items: + tags.add(tag.str) + origTags.add(tag.str) + var data: JsonNode + var origData: JsonNode + if tags.contains("$subtype:json"): + try: + origData = jdoc["data"].getStr.parseJson + data = origData.copy + except: + discard + var c = 1 + for item in jbody.items: + if item.hasKey("op") and item.hasKey("path"): + if not item.hasKey("value"): + item["value"] = %"" + try: + apply = applyPatchOperation(data, origData, tags, item["op"].str, item["path"].str, item["value"]) + if not apply: + break + except: + return resError(Http400, "Bad request - $1" % getCurrentExceptionMsg()) + else: + return resError(Http400, "Bad request: patch operation #$1 is malformed." % $c) + c.inc + if apply: + # when document is not JSON the origData is not defined + # the extra check allows editing tags for non-JSON documents + if origData != nil and origData.len > 0 and origData != data: + try: + var doc = LS.store.updateDocument(id, data.pretty, "application/json") + if doc == "": + return resError(Http500, "Unable to patch document '$1'." % id) + except: + return resError(Http500, "Unable to patch document '$1' - $2" % id, getCurrentExceptionMsg()) + if origTags != tags: + try: + for t1 in jdoc["tags"].items: + discard LS.store.destroyTag(t1.str, id, true) + for t2 in tags: + if t2 != "": + LS.store.createTag(t2, id, true) + except: + return resError(Http500, "Unable to patch document '$1' - $2" % [id, getCurrentExceptionMsg()]) + return LS.getRawDocument(id, newQueryOptions(), req) + +# Main routing + +proc options*(req: LSRequest, LS: LiteStore, resource: string, id = ""): LSResponse = + case resource: + of "info": + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS" + if id != "": + return resError(Http404, "Info '$1' not found." % id) + else: + result.code = Http204 + result.content = "" + of "dir": + result.code = Http204 + result.content = "" + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS" + of "assets": + result.code = Http204 + result.content = "" + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS" + of "tags": + result.code = Http204 + result.content = "" + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS" + of "indexes": + result.code = Http204 + result.content = "" + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + if id != "": + result.code = Http204 + result.content = "" + if LS.readonly: + result.headers["Allow"] = "GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS" + else: + result.headers["Allow"] = "GET, OPTIONS, PUT, DELETE" + result.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS, PUT, DELETE" + else: + result.code = Http204 + result.content = "" + if LS.readonly: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS" + else: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS" + of "docs": + var folder: string + if id.isFolder: + folder = id + if folder.len > 0: + result.code = Http204 + result.content = "" + if LS.readonly: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "HEAD, GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "HEAD, GET, OPTIONS" + else: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "HEAD, GET, OPTIONS, POST, PUT" + result.headers["Access-Control-Allow-Methods"] = "HEAD, GET, OPTIONS, POST, PUT" + elif id != "": + result.code = Http204 + result.content = "" + if LS.readonly: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "HEAD, GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "HEAD, GET, OPTIONS" + else: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "HEAD, GET, OPTIONS, PUT, PATCH, DELETE" + result.headers["Allow-Patch"] = "application/json-patch+json" + result.headers["Access-Control-Allow-Methods"] = "HEAD, GET, OPTIONS, PUT, PATCH, DELETE" + else: + result.code = Http204 + result.content = "" + if LS.readonly: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "HEAD, GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "HEAD, GET, OPTIONS" + else: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "HEAD, GET, OPTIONS, POST" + result.headers["Access-Control-Allow-Methods"] = "HEAD, GET, OPTIONS, POST" + of "stores": + result.code = Http204 + result.content = "" + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + if id != "": + result.code = Http204 + result.content = "" + if LS.readonly: + result.headers["Allow"] = "GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS" + else: + result.headers["Allow"] = "GET, OPTIONS, PUT, DELETE" + result.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS, PUT, DELETE" + else: + result.code = Http204 + result.content = "" + if LS.readonly: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS" + else: + result.headers = newHttpHeaders(TAB_HEADERS) + setOrigin(LS, req, result.headers) + result.headers["Allow"] = "GET, OPTIONS" + result.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS" + else: + discard # never happens really. + +proc head*(req: LSRequest, LS: LiteStore, resource: string, id = ""): LSResponse = + var options = newQueryOptions() + options.select = @["documents.id AS id", "created", "modified"] + if id.isFolder: + options.folder = id + try: + parseQueryOptions(req.url.query, options); + if id != "" and options.folder == "": + result = LS.getRawDocument(id, options, req) + result.content = "" + else: + result = LS.getRawDocuments(options, req) + result.content = "" + except: + return resError(Http400, "Bad request - $1" % getCurrentExceptionMsg()) + +proc get*(req: LSRequest, LS: LiteStore, resource: string, id = ""): LSResponse = + case resource: + of "docs": + var options = newQueryOptions() + if id.isFolder: + options.folder = id + if req.url.query.contains("contents=false"): + options.select = @["documents.id AS id", "created", "modified"] + try: + parseQueryOptions(req.url.query, options); + if id != "" and options.folder == "": + if req.url.query.contains("raw=true") or req.headers.hasKey("Accept") and req.headers["Accept"] == "application/json": + return LS.getRawDocument(id, options, req) + else: + return LS.getDocument(id, options, req) + else: + return LS.getRawDocuments(options, req) + except: + let e = getCurrentException() + let trace = e.getStackTrace() + echo trace + return resError(Http400, "Bad Request - $1" % getCurrentExceptionMsg()) + of "assets": + var options = newQueryOptions() + if id.isFolder: + options.folder = id + try: + parseQueryOptions(req.url.query, options); + if id != "" and options.folder == "": + return LS.getDocument(id, options, req) + else: + options.folder = "" + result = LS.getDocument(id & "index.html", options, req) + if result.code == Http404: + result = LS.getDocument(id & "index.htm", options, req) + return result + except: + let e = getCurrentException() + let trace = e.getStackTrace() + echo trace + return resError(Http400, "Bad Request - $1" % getCurrentExceptionMsg()) + of "tags": + var options = newQueryOptions() + try: + parseQueryOptions(req.url.query, options); + if id != "": + return LS.getTag(id, options, req) + else: + return LS.getTags(options, req) + except: + return resError(Http400, "Bad Request - $1" % getCurrentExceptionMsg()) + of "indexes": + var options = newQueryOptions() + try: + parseQueryOptions(req.url.query, options); + if id != "": + return LS.getIndex(id, options, req) + else: + return LS.getIndexes(options, req) + except: + return resError(Http400, "Bad Request - $1" % getCurrentExceptionMsg()) + of "stores": + var options = newQueryOptions() + try: + parseQueryOptions(req.url.query, options); + if id != "": + return LS.getStore(id, options, req) + else: + return LS.getStores(options, req) + except: + return resError(Http400, "Bad Request - $1" % getCurrentExceptionMsg()) + of "info": + if id != "": + return resError(Http404, "Info '$1' not found." % id) + return LS.getInfo(req) + else: + discard # never happens really. + +proc post*(req: LSRequest, LS: LiteStore, resource: string, id = ""): LSResponse = + var ct = "text/plain" + if req.headers.hasKey("Content-Type"): + ct = req.headers["Content-Type"] + return LS.postDocument(req.body.strip, ct, id, req) + +proc put*(req: LSRequest, LS: LiteStore, resource: string, id = ""): LSResponse = + if id != "": + if resource == "indexes": + var field = "" + try: + field = parseJson(req.body.strip)["field"].getStr + except: + return resError(Http400, "Bad Request - Invalid JSON body - $1" % getCurrentExceptionMsg()) + return LS.putIndex(id, field, req) + elif resource == "stores": + var config = newJNull() + try: + config = parseJson(req.body) + except: + return resError(Http400, "Bad Request - Invalid JSON body - $1" % getCurrentExceptionMsg()) + return LS.putStore(id, config, req) + else: # Assume docs + var ct = "text/plain" + if req.headers.hasKey("Content-Type"): + ct = req.headers["Content-Type"] + return LS.putDocument(id, req.body.strip, ct, req) + else: + return resError(Http400, "Bad request: document ID must be specified in PUT requests.") + +proc delete*(req: LSRequest, LS: LiteStore, resource: string, id = ""): LSResponse = + if id != "": + if resource == "indexes": + return LS.deleteIndex(id, req) + elif resource == "stores": + return LS.deleteStore(id, req) + else: # Assume docs + return LS.deleteDocument(id, req) + else: + return resError(Http400, "Bad request: document ID must be specified in DELETE requests.") + +proc patch*(req: LSRequest, LS: LiteStore, resource: string, id = ""): LSResponse = + if id != "": + return LS.patchDocument(id, req.body, req) + else: + return resError(Http400, "Bad request: document ID must be specified in PATCH requests.") + +proc serveFile*(req: LSRequest, LS: LiteStore, id: string): LSResponse = + let path = LS.directory / id + var reqMethod = $req.reqMethod + if req.headers.hasKey("X-HTTP-Method-Override"): + reqMethod = req.headers["X-HTTP-Method-Override"] + case reqMethod.toUpperAscii: + of "OPTIONS": + return validate(req, LS, "dir", id, options) + of "GET": + if path.fileExists: + try: + let contents = path.readFile + let parts = path.splitFile + if CONTENT_TYPES.hasKey(parts.ext): + result.headers = CONTENT_TYPES[parts.ext].ctHeader + else: + result.headers = ctHeader("text/plain") + setOrigin(LS, req, result.headers) + result.content = contents + result.code = Http200 + except: + return resError(Http500, "Unable to read file '$1'." % path) + else: + return resError(Http404, "File '$1' not found." % path) + else: + return resError(Http405, "Method not allowed: $1" % $req.reqMethod) + +proc route*(req: LSRequest, LS: LiteStore, resource = "docs", id = ""): LSResponse = + var reqMethod = $req.reqMethod + if req.headers.hasKey("X-HTTP-Method-Override"): + reqMethod = req.headers["X-HTTP-Method-Override"] + LOG.debug("ROUTE - resource: " & resource & " id: " & id) + case reqMethod.toUpperAscii: + of "POST": + if LS.readonly: + return resError(Http405, "Method not allowed: $1" % $req.reqMethod) + return validate(req, LS, resource, id, post) + of "PUT": + if LS.readonly: + return resError(Http405, "Method not allowed: $1" % $req.reqMethod) + return validate(req, LS, resource, id, put) + of "DELETE": + if LS.readonly: + return resError(Http405, "Method not allowed: $1" % $req.reqMethod) + return validate(req, LS, resource, id, delete) + of "HEAD": + return validate(req, LS, resource, id, head) + of "OPTIONS": + return validate(req, LS, resource, id, options) + of "GET": + return validate(req, LS, resource, id, get) + of "PATCH": + if LS.readonly: + return resError(Http405, "Method not allowed: $1" % $req.reqMethod) + return validate(req, LS, resource, id, patch) + else: + return resError(Http405, "Method not allowed: $1" % $req.reqMethod) + +proc multiRoute(req: LSRequest, resource, id: string): LSResponse = + var matches = @["", "", ""] + if req.url.path.find(PEG_STORE_URL, matches) != -1: + let id = matches[0] + let path = "/v7/" & matches[1] + matches = @["", "", ""] + discard path.find(PEG_URL, matches) + return req.route(LSDICT[id], matches[1], matches[2]) + return req.route(LS, resource, id) + +proc newSimpleLSRequest(meth: HttpMethod, resource, id, body = "", params = "", headers = newHttpHeaders()): LSRequest = + result.reqMethod = meth + result.body = body + result.headers = headers + result.url = parseUri("$1://$2:$3/$4/$5?$6" % @["http", "localhost", "9500", resource, id, params]) + +proc get(resource, id: string, params = ""): LSResponse = + return newSimpleLSRequest(HttpGet, resource, id, "", params).multiRoute(resource, id) + +proc post(resource, folder, body: string, ct = ""): LSResponse = + var headers = newHttpHeaders() + if ct != "": + headers["Content-Type"] = ct + return newSimpleLSRequest(HttpPost, resource, folder, body, "", headers).multiRoute(resource, folder & "/") + +proc put(resource, id, body: string, ct = ""): LSResponse = + var headers = newHttpHeaders() + if ct != "": + headers["Content-Type"] = ct + return newSimpleLSRequest(HttpPut, resource, id, body, "", headers).multiRoute(resource, id) + +proc patch(resource, id, body: string): LSResponse = + var headers = newHttpHeaders() + headers["Content-Type"] = "application/json" + return newSimpleLSRequest(HttpPatch, resource, id, body, "", headers).multiRoute(resource, id) + +proc delete(resource, id: string): LSResponse = + return newSimpleLSRequest(HttpDelete, resource, id).multiRoute(resource, id) + +proc head(resource, id: string): LSResponse = + return newSimpleLSRequest(HttpHead, resource, id).multiRoute(resource, id) + +proc registerStoreApi(LS: LiteStore, ctx: DTContext, origResource, origId: string) = + var api_idx = ctx.duk_push_object() + # GET + var get: DTCFunction = (proc (ctx: DTContext): cint{.stdcall.} = + let resource = duk_get_string(ctx, 0) + let id = duk_get_string(ctx, 1) + let params = duk_get_string(ctx, 2) + let resp = get($resource, $id, $params) + var res_idx = ctx.duk_push_object() + ctx.duk_push_int(cast[cint](resp.code)) + discard ctx.duk_put_prop_string(res_idx, "code") + discard ctx.duk_push_string(resp.content.cstring) + discard ctx.duk_put_prop_string(res_idx, "content") + return 1 + ) + discard duk_push_c_function(ctx, get, 3) + discard ctx.duk_put_prop_string(api_idx, "get") + # POST + var post: DTCFunction = (proc (ctx: DTContext): cint{.stdcall.} = + let resource = duk_get_string(ctx, 0) + let folder = duk_get_string(ctx, 1) + let body = duk_get_string(ctx, 2) + let ct = duk_get_string(ctx, 3) + let resp = post($resource, $folder, $body, $ct) + var res_idx = ctx.duk_push_object() + ctx.duk_push_int(cast[cint](resp.code)) + discard ctx.duk_put_prop_string(res_idx, "code") + discard ctx.duk_push_string(resp.content.cstring) + discard ctx.duk_put_prop_string(res_idx, "content") + return 1 + ) + discard duk_push_c_function(ctx, post, 4) + discard ctx.duk_put_prop_string(api_idx, "post") + # PUT + var put: DTCFunction = (proc (ctx: DTContext): cint{.stdcall.} = + let resource = duk_get_string(ctx, 0) + let id = duk_get_string(ctx, 1) + let body = duk_get_string(ctx, 2) + let ct = duk_get_string(ctx, 3) + let resp = put($resource, $id, $body, $ct) + var res_idx = ctx.duk_push_object() + ctx.duk_push_int(cast[cint](resp.code)) + discard ctx.duk_put_prop_string(res_idx, "code") + discard ctx.duk_push_string(resp.content.cstring) + discard ctx.duk_put_prop_string(res_idx, "content") + return 1 + ) + discard duk_push_c_function(ctx, put, 4) + discard ctx.duk_put_prop_string(api_idx, "put") + # PATCH + var patch: DTCFunction = (proc (ctx: DTContext): cint{.stdcall.} = + let resource = duk_get_string(ctx, 0) + let id = duk_get_string(ctx, 1) + let body = duk_get_string(ctx, 2) + let resp = patch($resource, $id, $body) + var res_idx = ctx.duk_push_object() + ctx.duk_push_int(cast[cint](resp.code)) + discard ctx.duk_put_prop_string(res_idx, "code") + discard ctx.duk_push_string(resp.content.cstring) + discard ctx.duk_put_prop_string(res_idx, "content") + return 1 + ) + discard duk_push_c_function(ctx, patch, 3) + discard ctx.duk_put_prop_string(api_idx, "patch") + # DELETE + var delete: DTCFunction = (proc (ctx: DTContext): cint{.stdcall.} = + let resource = duk_get_string(ctx, 0) + let id = duk_get_string(ctx, 1) + let resp = delete($resource, $id) + var res_idx = ctx.duk_push_object() + ctx.duk_push_int(cast[cint](resp.code)) + discard ctx.duk_put_prop_string(res_idx, "code") + discard ctx.duk_push_string(resp.content.cstring) + discard ctx.duk_put_prop_string(res_idx, "content") + return 1 + ) + discard duk_push_c_function(ctx, delete, 2) + discard ctx.duk_put_prop_string(api_idx, "delete") + # HEAD + var head: DTCFunction = (proc (ctx: DTContext): cint{.stdcall.} = + let resource = duk_get_string(ctx, 0) + let id = duk_get_string(ctx, 1) + let resp = head($resource, $id) + var res_idx = ctx.duk_push_object() + ctx.duk_push_int(cast[cint](resp.code)) + discard ctx.duk_put_prop_string(res_idx, "code") + discard ctx.duk_push_string(resp.content.cstring) + discard ctx.duk_put_prop_string(res_idx, "content") + return 1 + ) + discard duk_push_c_function(ctx, head, 2) + discard ctx.duk_put_prop_string(api_idx, "head") + discard ctx.duk_put_global_string("$store") + +proc jError(ctx: DTContext): LSResponse = + return resError(Http500, "Middleware Error: " & $ctx.duk_safe_to_string(-1)) + +proc getMiddleware*(LS: LiteStore, id: string): string = + if not LS.middleware.hasKey(id): + # Attempt to retrieve resource from system documents + let options = newQueryOptions(true) + let doc = LS.store.retrieveDocument("middleware/" & id & ".js", options) + result = doc.data + if result == "": + LOG.warn("Middleware '$1' not found" % id) + else: + result = LS.middleware[id] + +proc getMiddlewareSeq(LS: LiteStore, resource, id, meth: string): seq[string] = + result = newSeq[string]() + if LS.config.kind != JObject or not LS.config.hasKey("resources"): + return + var reqUri = "/" & resource & "/" & id + if reqUri[^1] == '/': + reqUri.removeSuffix({'/'}) + let parts = reqUri.split("/") + let ancestors = parts[1..parts.len-2] + var currentPath = "" + var currentPaths = "" + for p in ancestors: + currentPath &= "/" & p + currentPaths = currentPath & "/*" + if LS.config["resources"].hasKey(currentPaths) and LS.config["resources"][currentPaths].hasKey(meth) and LS.config["resources"][currentPaths][meth].hasKey("middleware"): + let mw = LS.config["resources"][currentPaths][meth]["middleware"] + if (mw.kind == JArray): + for m in mw: + result.add m.getStr + if LS.config["resources"].hasKey(reqUri) and LS.config["resources"][reqUri].hasKey(meth) and LS.config["resources"][reqUri][meth].hasKey("middleware"): + let mw = LS.config["resources"][reqUri][meth]["middleware"] + if (mw.kind == JArray): + for m in mw: + result.add m.getStr + +proc execute*(req: var LSRequest, LS: LiteStore, resource, id: string): LSResponse = + let middleware = getMiddlewareSeq(LS, resource, id, $req.reqMethod) + if middleware.len > 0: + LOG.debug("Middleware: " & middleware.join(" -> ")); + if middleware.len == 0: + return route(req, LS, resource, id) + var jReq = $(%* req) + LOG.debug("Request: " & jReq) + var jRes = """{ + "code": 200, + "content": {}, + "final": false, + "headers": { + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Headers": "Authorization, Content-Type", + "Server": "$1", + "Content-Type": "application/json" + } + }""" % [LS.appname & "/" & LS.appversion] + var context = "{}" + # Create execution context + var ctx = duk_create_heap_default() + duk_console_init(ctx) + duk_print_alert_init(ctx) + LS.registerStoreApi(ctx, resource, id) + if ctx.duk_peval_string(cstring("($1)" % $jReq)) != 0: + return jError(ctx) + discard ctx.duk_put_global_string("$req") + if ctx.duk_peval_string(cstring("($1)" % $jRes)) != 0: + return jError(ctx) + discard ctx.duk_put_global_string("$res") + if ctx.duk_peval_string(cstring("($1)" % $context)) != 0: + return jError(ctx) + discard ctx.duk_put_global_string("$ctx") + # Middleware-specific functions + var i = 0 + var abort = 0 + while abort != 1 and i < middleware.len: + let code = LS.getMiddleware(middleware[i]) + LOG.debug("Evaluating middleware '$1'" % middleware[i]) + if ctx.duk_peval_string(code.cstring) != 0: + return jError(ctx) + abort = ctx.duk_get_boolean(-1) + i.inc + # Retrieve response, and request + if ctx.duk_peval_string("JSON.stringify($res);") != 0: + return jError(ctx) + let fRes = parseJson($(ctx.duk_get_string(-1))).newLSResponse + if ctx.duk_peval_string("JSON.stringify($req);") != 0: + return jError(ctx) + let fReq = parseJson($(ctx.duk_get_string(-1))).newLSRequest() + ctx.duk_destroy_heap(); + LOG.debug("abort: $1", [$abort]) + if abort == 1: + return fRes + return route(fReq, LS, resource, id)
@@ -1,6 +1,6 @@
const pkgName* = "litestore" - pkgVersion* = "1.11.0" + pkgVersion* = "1.12.0" pkgAuthor* = "Fabio Cevasco" pkgDescription* = "Self-contained, lightweight, RESTful document store." pkgLicense* = "MIT"
@@ -467,6 +467,7 @@ contenttype: string] =
var options = options options.single = true var select = prepareSelectDocumentsQuery(options) + echo "-------" var raw_document = store.db.getRow(select.sql, id) LOG.debug("Retrieving document '$1'" % id) if raw_document[0] == "":
@@ -23,7 +23,8 @@ api_v3,
api_v4, api_v5, api_v6, - api_v7 + api_v7, + api_v8 export api_v5@@ -144,6 +145,19 @@ uri = "/*"
if access.hasKey(uri): auth(uri, jwt, LS) break + if info.version == "v8": + if info.resource.match(peg"^assets / docs / info / tags / indexes / stores$"): + var nReq = req + if jwt.signature.len != 0: + nReq.jwt = jwt + return api_v8.execute(nReq, LS, info.resource, info.id) + elif info.resource.match(peg"^dir$"): + if LS.directory.len > 0: + return api_v8.serveFile(req, LS, info.id) + else: + return resError(Http400, "Bad Request - Not serving any directory." % info.version) + else: + return resError(Http404, "Resource Not Found: $1" % info.resource) if info.version == "v7": if info.resource.match(peg"^docs / info / tags / indexes / stores$"): var nReq = req@@ -237,7 +251,7 @@ op
try: var info: ResourceInfo req.route peg"^\/?$": - info.version = "v7" + info.version = "v8" info.resource = "info" return req.processApiUrl(LS, info) req.route peg"^\/favicon.ico$":@@ -246,7 +260,7 @@ result.content = LS.favicon
result.headers = ctHeader("image/x-icon") return result req.route PEG_DEFAULT_URL: - info.version = "v7" + info.version = "v8" info.resource = matches[0] info.id = matches[1].decodeUrl return req.processApiUrl(LS, info)
@@ -245,7 +245,7 @@ PEG_USER_TAG = peg"""^[a-zA-Z0-9_\-?~:.@#^!+]+$"""
PEG_INDEX = peg"""^[a-zA-Z0-9_]+$""" PEG_STORE = peg"""^[a-zA-Z0-9_]+$""" PEG_JSON_FIELD = peg"""'$' ('.' [a-z-A-Z0-9_]+)+""" -PEG_DEFAULT_URL = peg"""^\/{(docs / info / dir / tags / indexes / stores)} (\/ {(.+)} / \/?)$""" +PEG_DEFAULT_URL = peg"""^\/{(assets / docs / info / dir / tags / indexes / stores)} (\/ {(.+)} / \/?)$""" PEG_STORE_URL = peg"""^\/stores \/ {([a-z0-9_]+)} (\/ {(.+)} / \/?)$""" PEG_URL = peg"""^\/({(v\d+)} \/) {([^\/]+)} (\/ {(.+)} / \/?)$"""
@@ -1,6 +1,6 @@
/****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite -** version 3.36.0. By combining all the individual C code files into this +** version 3.39.2. 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@@ -22,793 +22,6 @@ #define SQLITE_AMALGAMATION 1
#ifndef SQLITE_PRIVATE # define SQLITE_PRIVATE static #endif -/************** Begin file ctime.c *******************************************/ -/* -** 2010 February 23 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** -** This file implements routines used to report what compile-time options -** SQLite was built with. -*/ - -#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS /* IMP: R-16824-07538 */ - -/* -** Include the configuration header output by 'configure' if we're using the -** autoconf-based build -*/ -#if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H) -#include "config.h" -#define SQLITECONFIG_H 1 -#endif - -/* These macros are provided to "stringify" the value of the define -** for those options in which the value is meaningful. */ -#define CTIMEOPT_VAL_(opt) #opt -#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt) - -/* Like CTIMEOPT_VAL, but especially for SQLITE_DEFAULT_LOOKASIDE. This -** option requires a separate macro because legal values contain a single -** comma. e.g. (-DSQLITE_DEFAULT_LOOKASIDE="100,100") */ -#define CTIMEOPT_VAL2_(opt1,opt2) #opt1 "," #opt2 -#define CTIMEOPT_VAL2(opt) CTIMEOPT_VAL2_(opt) - -/* -** An array of names of all compile-time options. This array should -** be sorted A-Z. -** -** This array looks large, but in a typical installation actually uses -** only a handful of compile-time options, so most times this array is usually -** rather short and uses little memory space. -*/ -static const char * const sqlite3azCompileOpt[] = { - -/* -** BEGIN CODE GENERATED BY tool/mkctime.tcl -*/ -#if SQLITE_32BIT_ROWID - "32BIT_ROWID", -#endif -#if SQLITE_4_BYTE_ALIGNED_MALLOC - "4_BYTE_ALIGNED_MALLOC", -#endif -#if SQLITE_64BIT_STATS - "64BIT_STATS", -#endif -#ifdef SQLITE_ALLOW_COVERING_INDEX_SCAN -# if SQLITE_ALLOW_COVERING_INDEX_SCAN != 1 - "ALLOW_COVERING_INDEX_SCAN=" CTIMEOPT_VAL(SQLITE_ALLOW_COVERING_INDEX_SCAN), -# endif -#endif -#if SQLITE_ALLOW_URI_AUTHORITY - "ALLOW_URI_AUTHORITY", -#endif -#ifdef SQLITE_BITMASK_TYPE - "BITMASK_TYPE=" CTIMEOPT_VAL(SQLITE_BITMASK_TYPE), -#endif -#if SQLITE_BUG_COMPATIBLE_20160819 - "BUG_COMPATIBLE_20160819", -#endif -#if SQLITE_CASE_SENSITIVE_LIKE - "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", -#endif -#if SQLITE_DEFAULT_AUTOMATIC_INDEX - "DEFAULT_AUTOMATIC_INDEX", -#endif -#if SQLITE_DEFAULT_AUTOVACUUM - "DEFAULT_AUTOVACUUM", -#endif -#ifdef SQLITE_DEFAULT_CACHE_SIZE - "DEFAULT_CACHE_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_CACHE_SIZE), -#endif -#if SQLITE_DEFAULT_CKPTFULLFSYNC - "DEFAULT_CKPTFULLFSYNC", -#endif -#ifdef SQLITE_DEFAULT_FILE_FORMAT - "DEFAULT_FILE_FORMAT=" CTIMEOPT_VAL(SQLITE_DEFAULT_FILE_FORMAT), -#endif -#ifdef SQLITE_DEFAULT_FILE_PERMISSIONS - "DEFAULT_FILE_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_FILE_PERMISSIONS), -#endif -#if SQLITE_DEFAULT_FOREIGN_KEYS - "DEFAULT_FOREIGN_KEYS", -#endif -#ifdef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT - "DEFAULT_JOURNAL_SIZE_LIMIT=" CTIMEOPT_VAL(SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT), -#endif -#ifdef SQLITE_DEFAULT_LOCKING_MODE - "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE), -#endif -#ifdef SQLITE_DEFAULT_LOOKASIDE - "DEFAULT_LOOKASIDE=" CTIMEOPT_VAL2(SQLITE_DEFAULT_LOOKASIDE), -#endif -#ifdef SQLITE_DEFAULT_MEMSTATUS -# if SQLITE_DEFAULT_MEMSTATUS != 1 - "DEFAULT_MEMSTATUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_MEMSTATUS), -# endif -#endif -#ifdef SQLITE_DEFAULT_MMAP_SIZE - "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE), -#endif -#ifdef SQLITE_DEFAULT_PAGE_SIZE - "DEFAULT_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_PAGE_SIZE), -#endif -#ifdef SQLITE_DEFAULT_PCACHE_INITSZ - "DEFAULT_PCACHE_INITSZ=" CTIMEOPT_VAL(SQLITE_DEFAULT_PCACHE_INITSZ), -#endif -#ifdef SQLITE_DEFAULT_PROXYDIR_PERMISSIONS - "DEFAULT_PROXYDIR_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_PROXYDIR_PERMISSIONS), -#endif -#if SQLITE_DEFAULT_RECURSIVE_TRIGGERS - "DEFAULT_RECURSIVE_TRIGGERS", -#endif -#ifdef SQLITE_DEFAULT_ROWEST - "DEFAULT_ROWEST=" CTIMEOPT_VAL(SQLITE_DEFAULT_ROWEST), -#endif -#ifdef SQLITE_DEFAULT_SECTOR_SIZE - "DEFAULT_SECTOR_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_SECTOR_SIZE), -#endif -#ifdef SQLITE_DEFAULT_SYNCHRONOUS - "DEFAULT_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_SYNCHRONOUS), -#endif -#ifdef SQLITE_DEFAULT_WAL_AUTOCHECKPOINT - "DEFAULT_WAL_AUTOCHECKPOINT=" CTIMEOPT_VAL(SQLITE_DEFAULT_WAL_AUTOCHECKPOINT), -#endif -#ifdef SQLITE_DEFAULT_WAL_SYNCHRONOUS - "DEFAULT_WAL_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WAL_SYNCHRONOUS), -#endif -#ifdef SQLITE_DEFAULT_WORKER_THREADS - "DEFAULT_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WORKER_THREADS), -#endif -#if SQLITE_DIRECT_OVERFLOW_READ - "DIRECT_OVERFLOW_READ", -#endif -#if SQLITE_DISABLE_DIRSYNC - "DISABLE_DIRSYNC", -#endif -#if SQLITE_DISABLE_FTS3_UNICODE - "DISABLE_FTS3_UNICODE", -#endif -#if SQLITE_DISABLE_FTS4_DEFERRED - "DISABLE_FTS4_DEFERRED", -#endif -#if SQLITE_DISABLE_INTRINSIC - "DISABLE_INTRINSIC", -#endif -#if SQLITE_DISABLE_LFS - "DISABLE_LFS", -#endif -#if SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS - "DISABLE_PAGECACHE_OVERFLOW_STATS", -#endif -#if SQLITE_DISABLE_SKIPAHEAD_DISTINCT - "DISABLE_SKIPAHEAD_DISTINCT", -#endif -#ifdef SQLITE_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 - "ENABLE_ATOMIC_WRITE", -#endif -#if SQLITE_ENABLE_BATCH_ATOMIC_WRITE - "ENABLE_BATCH_ATOMIC_WRITE", -#endif -#if SQLITE_ENABLE_BYTECODE_VTAB - "ENABLE_BYTECODE_VTAB", -#endif -#ifdef SQLITE_ENABLE_CEROD - "ENABLE_CEROD=" CTIMEOPT_VAL(SQLITE_ENABLE_CEROD), -#endif -#if SQLITE_ENABLE_COLUMN_METADATA - "ENABLE_COLUMN_METADATA", -#endif -#if SQLITE_ENABLE_COLUMN_USED_MASK - "ENABLE_COLUMN_USED_MASK", -#endif -#if SQLITE_ENABLE_COSTMULT - "ENABLE_COSTMULT", -#endif -#if SQLITE_ENABLE_CURSOR_HINTS - "ENABLE_CURSOR_HINTS", -#endif -#if SQLITE_ENABLE_DBPAGE_VTAB - "ENABLE_DBPAGE_VTAB", -#endif -#if SQLITE_ENABLE_DBSTAT_VTAB - "ENABLE_DBSTAT_VTAB", -#endif -#if SQLITE_ENABLE_EXPENSIVE_ASSERT - "ENABLE_EXPENSIVE_ASSERT", -#endif -#if SQLITE_ENABLE_EXPLAIN_COMMENTS - "ENABLE_EXPLAIN_COMMENTS", -#endif -#if SQLITE_ENABLE_FTS3 - "ENABLE_FTS3", -#endif -#if SQLITE_ENABLE_FTS3_PARENTHESIS - "ENABLE_FTS3_PARENTHESIS", -#endif -#if SQLITE_ENABLE_FTS3_TOKENIZER - "ENABLE_FTS3_TOKENIZER", -#endif -#if SQLITE_ENABLE_FTS4 - "ENABLE_FTS4", -#endif -#if SQLITE_ENABLE_FTS5 - "ENABLE_FTS5", -#endif -#if SQLITE_ENABLE_GEOPOLY - "ENABLE_GEOPOLY", -#endif -#if SQLITE_ENABLE_HIDDEN_COLUMNS - "ENABLE_HIDDEN_COLUMNS", -#endif -#if SQLITE_ENABLE_ICU - "ENABLE_ICU", -#endif -#if SQLITE_ENABLE_IOTRACE - "ENABLE_IOTRACE", -#endif -#if SQLITE_ENABLE_JSON1 - "ENABLE_JSON1", -#endif -#if SQLITE_ENABLE_LOAD_EXTENSION - "ENABLE_LOAD_EXTENSION", -#endif -#ifdef SQLITE_ENABLE_LOCKING_STYLE - "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE), -#endif -#if SQLITE_ENABLE_MATH_FUNCTIONS - "ENABLE_MATH_FUNCTIONS", -#endif -#if SQLITE_ENABLE_MEMORY_MANAGEMENT - "ENABLE_MEMORY_MANAGEMENT", -#endif -#if SQLITE_ENABLE_MEMSYS3 - "ENABLE_MEMSYS3", -#endif -#if SQLITE_ENABLE_MEMSYS5 - "ENABLE_MEMSYS5", -#endif -#if SQLITE_ENABLE_MULTIPLEX - "ENABLE_MULTIPLEX", -#endif -#if SQLITE_ENABLE_NORMALIZE - "ENABLE_NORMALIZE", -#endif -#if SQLITE_ENABLE_NULL_TRIM - "ENABLE_NULL_TRIM", -#endif -#if SQLITE_ENABLE_OFFSET_SQL_FUNC - "ENABLE_OFFSET_SQL_FUNC", -#endif -#if SQLITE_ENABLE_OVERSIZE_CELL_CHECK - "ENABLE_OVERSIZE_CELL_CHECK", -#endif -#if SQLITE_ENABLE_PREUPDATE_HOOK - "ENABLE_PREUPDATE_HOOK", -#endif -#if SQLITE_ENABLE_QPSG - "ENABLE_QPSG", -#endif -#if SQLITE_ENABLE_RBU - "ENABLE_RBU", -#endif -#if SQLITE_ENABLE_RTREE - "ENABLE_RTREE", -#endif -#if SQLITE_ENABLE_SELECTTRACE - "ENABLE_SELECTTRACE", -#endif -#if SQLITE_ENABLE_SESSION - "ENABLE_SESSION", -#endif -#if SQLITE_ENABLE_SNAPSHOT - "ENABLE_SNAPSHOT", -#endif -#if SQLITE_ENABLE_SORTER_REFERENCES - "ENABLE_SORTER_REFERENCES", -#endif -#if SQLITE_ENABLE_SQLLOG - "ENABLE_SQLLOG", -#endif -#if SQLITE_ENABLE_STAT4 - "ENABLE_STAT4", -#endif -#if SQLITE_ENABLE_STMTVTAB - "ENABLE_STMTVTAB", -#endif -#if SQLITE_ENABLE_STMT_SCANSTATUS - "ENABLE_STMT_SCANSTATUS", -#endif -#if SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION - "ENABLE_UNKNOWN_SQL_FUNCTION", -#endif -#if SQLITE_ENABLE_UNLOCK_NOTIFY - "ENABLE_UNLOCK_NOTIFY", -#endif -#if SQLITE_ENABLE_UPDATE_DELETE_LIMIT - "ENABLE_UPDATE_DELETE_LIMIT", -#endif -#if SQLITE_ENABLE_URI_00_ERROR - "ENABLE_URI_00_ERROR", -#endif -#if SQLITE_ENABLE_VFSTRACE - "ENABLE_VFSTRACE", -#endif -#if SQLITE_ENABLE_WHERETRACE - "ENABLE_WHERETRACE", -#endif -#if SQLITE_ENABLE_ZIPVFS - "ENABLE_ZIPVFS", -#endif -#if SQLITE_EXPLAIN_ESTIMATED_ROWS - "EXPLAIN_ESTIMATED_ROWS", -#endif -#if SQLITE_EXTRA_IFNULLROW - "EXTRA_IFNULLROW", -#endif -#ifdef SQLITE_EXTRA_INIT - "EXTRA_INIT=" CTIMEOPT_VAL(SQLITE_EXTRA_INIT), -#endif -#ifdef SQLITE_EXTRA_SHUTDOWN - "EXTRA_SHUTDOWN=" CTIMEOPT_VAL(SQLITE_EXTRA_SHUTDOWN), -#endif -#ifdef SQLITE_FTS3_MAX_EXPR_DEPTH - "FTS3_MAX_EXPR_DEPTH=" CTIMEOPT_VAL(SQLITE_FTS3_MAX_EXPR_DEPTH), -#endif -#if SQLITE_FTS5_ENABLE_TEST_MI - "FTS5_ENABLE_TEST_MI", -#endif -#if SQLITE_FTS5_NO_WITHOUT_ROWID - "FTS5_NO_WITHOUT_ROWID", -#endif -#if HAVE_ISNAN || SQLITE_HAVE_ISNAN - "HAVE_ISNAN", -#endif -#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX -# if SQLITE_HOMEGROWN_RECURSIVE_MUTEX != 1 - "HOMEGROWN_RECURSIVE_MUTEX=" CTIMEOPT_VAL(SQLITE_HOMEGROWN_RECURSIVE_MUTEX), -# endif -#endif -#if SQLITE_IGNORE_AFP_LOCK_ERRORS - "IGNORE_AFP_LOCK_ERRORS", -#endif -#if SQLITE_IGNORE_FLOCK_LOCK_ERRORS - "IGNORE_FLOCK_LOCK_ERRORS", -#endif -#if SQLITE_INLINE_MEMCPY - "INLINE_MEMCPY", -#endif -#if SQLITE_INT64_TYPE - "INT64_TYPE", -#endif -#ifdef SQLITE_INTEGRITY_CHECK_ERROR_MAX - "INTEGRITY_CHECK_ERROR_MAX=" CTIMEOPT_VAL(SQLITE_INTEGRITY_CHECK_ERROR_MAX), -#endif -#if SQLITE_LIKE_DOESNT_MATCH_BLOBS - "LIKE_DOESNT_MATCH_BLOBS", -#endif -#if SQLITE_LOCK_TRACE - "LOCK_TRACE", -#endif -#if SQLITE_LOG_CACHE_SPILL - "LOG_CACHE_SPILL", -#endif -#ifdef SQLITE_MALLOC_SOFT_LIMIT - "MALLOC_SOFT_LIMIT=" CTIMEOPT_VAL(SQLITE_MALLOC_SOFT_LIMIT), -#endif -#ifdef SQLITE_MAX_ATTACHED - "MAX_ATTACHED=" CTIMEOPT_VAL(SQLITE_MAX_ATTACHED), -#endif -#ifdef SQLITE_MAX_COLUMN - "MAX_COLUMN=" CTIMEOPT_VAL(SQLITE_MAX_COLUMN), -#endif -#ifdef SQLITE_MAX_COMPOUND_SELECT - "MAX_COMPOUND_SELECT=" CTIMEOPT_VAL(SQLITE_MAX_COMPOUND_SELECT), -#endif -#ifdef SQLITE_MAX_DEFAULT_PAGE_SIZE - "MAX_DEFAULT_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_DEFAULT_PAGE_SIZE), -#endif -#ifdef SQLITE_MAX_EXPR_DEPTH - "MAX_EXPR_DEPTH=" CTIMEOPT_VAL(SQLITE_MAX_EXPR_DEPTH), -#endif -#ifdef SQLITE_MAX_FUNCTION_ARG - "MAX_FUNCTION_ARG=" CTIMEOPT_VAL(SQLITE_MAX_FUNCTION_ARG), -#endif -#ifdef SQLITE_MAX_LENGTH - "MAX_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_LENGTH), -#endif -#ifdef SQLITE_MAX_LIKE_PATTERN_LENGTH - "MAX_LIKE_PATTERN_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_LIKE_PATTERN_LENGTH), -#endif -#ifdef SQLITE_MAX_MEMORY - "MAX_MEMORY=" CTIMEOPT_VAL(SQLITE_MAX_MEMORY), -#endif -#ifdef SQLITE_MAX_MMAP_SIZE - "MAX_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE), -#endif -#ifdef SQLITE_MAX_MMAP_SIZE_ - "MAX_MMAP_SIZE_=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE_), -#endif -#ifdef SQLITE_MAX_PAGE_COUNT - "MAX_PAGE_COUNT=" CTIMEOPT_VAL(SQLITE_MAX_PAGE_COUNT), -#endif -#ifdef SQLITE_MAX_PAGE_SIZE - "MAX_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_PAGE_SIZE), -#endif -#ifdef SQLITE_MAX_SCHEMA_RETRY - "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY), -#endif -#ifdef SQLITE_MAX_SQL_LENGTH - "MAX_SQL_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_SQL_LENGTH), -#endif -#ifdef SQLITE_MAX_TRIGGER_DEPTH - "MAX_TRIGGER_DEPTH=" CTIMEOPT_VAL(SQLITE_MAX_TRIGGER_DEPTH), -#endif -#ifdef SQLITE_MAX_VARIABLE_NUMBER - "MAX_VARIABLE_NUMBER=" CTIMEOPT_VAL(SQLITE_MAX_VARIABLE_NUMBER), -#endif -#ifdef SQLITE_MAX_VDBE_OP - "MAX_VDBE_OP=" CTIMEOPT_VAL(SQLITE_MAX_VDBE_OP), -#endif -#ifdef SQLITE_MAX_WORKER_THREADS - "MAX_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_MAX_WORKER_THREADS), -#endif -#if SQLITE_MEMDEBUG - "MEMDEBUG", -#endif -#if SQLITE_MIXED_ENDIAN_64BIT_FLOAT - "MIXED_ENDIAN_64BIT_FLOAT", -#endif -#if SQLITE_MMAP_READWRITE - "MMAP_READWRITE", -#endif -#if SQLITE_MUTEX_NOOP - "MUTEX_NOOP", -#endif -#if SQLITE_MUTEX_OMIT - "MUTEX_OMIT", -#endif -#if SQLITE_MUTEX_PTHREADS - "MUTEX_PTHREADS", -#endif -#if SQLITE_MUTEX_W32 - "MUTEX_W32", -#endif -#if SQLITE_NEED_ERR_NAME - "NEED_ERR_NAME", -#endif -#if SQLITE_NOINLINE - "NOINLINE", -#endif -#if SQLITE_NO_SYNC - "NO_SYNC", -#endif -#if SQLITE_OMIT_ALTERTABLE - "OMIT_ALTERTABLE", -#endif -#if SQLITE_OMIT_ANALYZE - "OMIT_ANALYZE", -#endif -#if SQLITE_OMIT_ATTACH - "OMIT_ATTACH", -#endif -#if SQLITE_OMIT_AUTHORIZATION - "OMIT_AUTHORIZATION", -#endif -#if SQLITE_OMIT_AUTOINCREMENT - "OMIT_AUTOINCREMENT", -#endif -#if SQLITE_OMIT_AUTOINIT - "OMIT_AUTOINIT", -#endif -#if SQLITE_OMIT_AUTOMATIC_INDEX - "OMIT_AUTOMATIC_INDEX", -#endif -#if SQLITE_OMIT_AUTORESET - "OMIT_AUTORESET", -#endif -#if SQLITE_OMIT_AUTOVACUUM - "OMIT_AUTOVACUUM", -#endif -#if SQLITE_OMIT_BETWEEN_OPTIMIZATION - "OMIT_BETWEEN_OPTIMIZATION", -#endif -#if SQLITE_OMIT_BLOB_LITERAL - "OMIT_BLOB_LITERAL", -#endif -#if SQLITE_OMIT_CAST - "OMIT_CAST", -#endif -#if SQLITE_OMIT_CHECK - "OMIT_CHECK", -#endif -#if SQLITE_OMIT_COMPLETE - "OMIT_COMPLETE", -#endif -#if SQLITE_OMIT_COMPOUND_SELECT - "OMIT_COMPOUND_SELECT", -#endif -#if SQLITE_OMIT_CONFLICT_CLAUSE - "OMIT_CONFLICT_CLAUSE", -#endif -#if SQLITE_OMIT_CTE - "OMIT_CTE", -#endif -#if defined(SQLITE_OMIT_DATETIME_FUNCS) || defined(SQLITE_OMIT_FLOATING_POINT) - "OMIT_DATETIME_FUNCS", -#endif -#if SQLITE_OMIT_DECLTYPE - "OMIT_DECLTYPE", -#endif -#if SQLITE_OMIT_DEPRECATED - "OMIT_DEPRECATED", -#endif -#if SQLITE_OMIT_DESERIALIZE - "OMIT_DESERIALIZE", -#endif -#if SQLITE_OMIT_DISKIO - "OMIT_DISKIO", -#endif -#if SQLITE_OMIT_EXPLAIN - "OMIT_EXPLAIN", -#endif -#if SQLITE_OMIT_FLAG_PRAGMAS - "OMIT_FLAG_PRAGMAS", -#endif -#if SQLITE_OMIT_FLOATING_POINT - "OMIT_FLOATING_POINT", -#endif -#if SQLITE_OMIT_FOREIGN_KEY - "OMIT_FOREIGN_KEY", -#endif -#if SQLITE_OMIT_GET_TABLE - "OMIT_GET_TABLE", -#endif -#if SQLITE_OMIT_HEX_INTEGER - "OMIT_HEX_INTEGER", -#endif -#if SQLITE_OMIT_INCRBLOB - "OMIT_INCRBLOB", -#endif -#if SQLITE_OMIT_INTEGRITY_CHECK - "OMIT_INTEGRITY_CHECK", -#endif -#if SQLITE_OMIT_INTROSPECTION_PRAGMAS - "OMIT_INTROSPECTION_PRAGMAS", -#endif -#if SQLITE_OMIT_LIKE_OPTIMIZATION - "OMIT_LIKE_OPTIMIZATION", -#endif -#if SQLITE_OMIT_LOAD_EXTENSION - "OMIT_LOAD_EXTENSION", -#endif -#if SQLITE_OMIT_LOCALTIME - "OMIT_LOCALTIME", -#endif -#if SQLITE_OMIT_LOOKASIDE - "OMIT_LOOKASIDE", -#endif -#if SQLITE_OMIT_MEMORYDB - "OMIT_MEMORYDB", -#endif -#if SQLITE_OMIT_OR_OPTIMIZATION - "OMIT_OR_OPTIMIZATION", -#endif -#if SQLITE_OMIT_PAGER_PRAGMAS - "OMIT_PAGER_PRAGMAS", -#endif -#if SQLITE_OMIT_PARSER_TRACE - "OMIT_PARSER_TRACE", -#endif -#if SQLITE_OMIT_POPEN - "OMIT_POPEN", -#endif -#if SQLITE_OMIT_PRAGMA - "OMIT_PRAGMA", -#endif -#if SQLITE_OMIT_PROGRESS_CALLBACK - "OMIT_PROGRESS_CALLBACK", -#endif -#if SQLITE_OMIT_QUICKBALANCE - "OMIT_QUICKBALANCE", -#endif -#if SQLITE_OMIT_REINDEX - "OMIT_REINDEX", -#endif -#if SQLITE_OMIT_SCHEMA_PRAGMAS - "OMIT_SCHEMA_PRAGMAS", -#endif -#if SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS - "OMIT_SCHEMA_VERSION_PRAGMAS", -#endif -#if SQLITE_OMIT_SHARED_CACHE - "OMIT_SHARED_CACHE", -#endif -#if SQLITE_OMIT_SHUTDOWN_DIRECTORIES - "OMIT_SHUTDOWN_DIRECTORIES", -#endif -#if SQLITE_OMIT_SUBQUERY - "OMIT_SUBQUERY", -#endif -#if SQLITE_OMIT_TCL_VARIABLE - "OMIT_TCL_VARIABLE", -#endif -#if SQLITE_OMIT_TEMPDB - "OMIT_TEMPDB", -#endif -#if SQLITE_OMIT_TEST_CONTROL - "OMIT_TEST_CONTROL", -#endif -#ifdef SQLITE_OMIT_TRACE -# if SQLITE_OMIT_TRACE != 1 - "OMIT_TRACE=" CTIMEOPT_VAL(SQLITE_OMIT_TRACE), -# endif -#endif -#if SQLITE_OMIT_TRIGGER - "OMIT_TRIGGER", -#endif -#if SQLITE_OMIT_TRUNCATE_OPTIMIZATION - "OMIT_TRUNCATE_OPTIMIZATION", -#endif -#if SQLITE_OMIT_UTF16 - "OMIT_UTF16", -#endif -#if SQLITE_OMIT_VACUUM - "OMIT_VACUUM", -#endif -#if SQLITE_OMIT_VIEW - "OMIT_VIEW", -#endif -#if SQLITE_OMIT_VIRTUALTABLE - "OMIT_VIRTUALTABLE", -#endif -#if SQLITE_OMIT_WAL - "OMIT_WAL", -#endif -#if SQLITE_OMIT_WSD - "OMIT_WSD", -#endif -#if SQLITE_OMIT_XFER_OPT - "OMIT_XFER_OPT", -#endif -#if SQLITE_PCACHE_SEPARATE_HEADER - "PCACHE_SEPARATE_HEADER", -#endif -#if SQLITE_PERFORMANCE_TRACE - "PERFORMANCE_TRACE", -#endif -#ifdef SQLITE_POWERSAFE_OVERWRITE -# if SQLITE_POWERSAFE_OVERWRITE != 1 - "POWERSAFE_OVERWRITE=" CTIMEOPT_VAL(SQLITE_POWERSAFE_OVERWRITE), -# endif -#endif -#if SQLITE_PREFER_PROXY_LOCKING - "PREFER_PROXY_LOCKING", -#endif -#if SQLITE_PROXY_DEBUG - "PROXY_DEBUG", -#endif -#if SQLITE_REVERSE_UNORDERED_SELECTS - "REVERSE_UNORDERED_SELECTS", -#endif -#if SQLITE_RTREE_INT_ONLY - "RTREE_INT_ONLY", -#endif -#if SQLITE_SECURE_DELETE - "SECURE_DELETE", -#endif -#if SQLITE_SMALL_STACK - "SMALL_STACK", -#endif -#ifdef SQLITE_SORTER_PMASZ - "SORTER_PMASZ=" CTIMEOPT_VAL(SQLITE_SORTER_PMASZ), -#endif -#if SQLITE_SOUNDEX - "SOUNDEX", -#endif -#ifdef SQLITE_STAT4_SAMPLES - "STAT4_SAMPLES=" CTIMEOPT_VAL(SQLITE_STAT4_SAMPLES), -#endif -#ifdef SQLITE_STMTJRNL_SPILL - "STMTJRNL_SPILL=" CTIMEOPT_VAL(SQLITE_STMTJRNL_SPILL), -#endif -#if SQLITE_SUBSTR_COMPATIBILITY - "SUBSTR_COMPATIBILITY", -#endif -#if (!defined(SQLITE_WIN32_MALLOC) \ - && !defined(SQLITE_ZERO_MALLOC) \ - && !defined(SQLITE_MEMDEBUG) \ - ) || defined(SQLITE_SYSTEM_MALLOC) - "SYSTEM_MALLOC", -#endif -#if SQLITE_TCL - "TCL", -#endif -#ifdef SQLITE_TEMP_STORE - "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE), -#endif -#if SQLITE_TEST - "TEST", -#endif -#if defined(SQLITE_THREADSAFE) - "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE), -#elif defined(THREADSAFE) - "THREADSAFE=" CTIMEOPT_VAL(THREADSAFE), -#else - "THREADSAFE=1", -#endif -#if SQLITE_UNLINK_AFTER_CLOSE - "UNLINK_AFTER_CLOSE", -#endif -#if SQLITE_UNTESTABLE - "UNTESTABLE", -#endif -#if SQLITE_USER_AUTHENTICATION - "USER_AUTHENTICATION", -#endif -#if SQLITE_USE_ALLOCA - "USE_ALLOCA", -#endif -#if SQLITE_USE_FCNTL_TRACE - "USE_FCNTL_TRACE", -#endif -#if SQLITE_USE_URI - "USE_URI", -#endif -#if SQLITE_VDBE_COVERAGE - "VDBE_COVERAGE", -#endif -#if SQLITE_WIN32_MALLOC - "WIN32_MALLOC", -#endif -#if SQLITE_ZERO_MALLOC - "ZERO_MALLOC", -#endif -/* -** END CODE GENERATED BY tool/mkctime.tcl -*/ -}; - -SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt){ - *pnOpt = sizeof(sqlite3azCompileOpt) / sizeof(sqlite3azCompileOpt[0]); - return (const char**)sqlite3azCompileOpt; -} - -#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ - -/************** End of ctime.c ***********************************************/ /************** Begin file sqliteInt.h ***************************************/ /* ** 2001 September 15@@ -1074,6 +287,17 @@ defined(__MSVCRT__)
# define _USE_32BIT_TIME_T #endif +/* Optionally #include a user-defined header, whereby compilation options +** may be set prior to where they take effect, but after platform setup. +** If SQLITE_CUSTOM_INCLUDE=? is defined, its value names the #include +** file. +*/ +#ifdef SQLITE_CUSTOM_INCLUDE +# define INC_STRINGIFY_(f) #f +# define INC_STRINGIFY(f) INC_STRINGIFY_(f) +# include INC_STRINGIFY(SQLITE_CUSTOM_INCLUDE) +#endif + /* The public SQLite interface. The _FILE_OFFSET_BITS macro must appear ** first in QNX. Also, the _USE_32BIT_TIME_T macro must appear first for ** MinGW.@@ -1125,7 +349,30 @@ #endif
/* -** Provide the ability to override linkage features of the interface. +** Facilitate override of interface linkage and calling conventions. +** Be aware that these macros may not be used within this particular +** translation of the amalgamation and its associated header file. +** +** The SQLITE_EXTERN and SQLITE_API macros are used to instruct the +** compiler that the target identifier should have external linkage. +** +** The SQLITE_CDECL macro is used to set the calling convention for +** public functions that accept a variable number of arguments. +** +** The SQLITE_APICALL macro is used to set the calling convention for +** public functions that accept a fixed number of arguments. +** +** The SQLITE_STDCALL macro is no longer used and is now deprecated. +** +** The SQLITE_CALLBACK macro is used to set the calling convention for +** function pointers. +** +** The SQLITE_SYSAPI macro is used to set the calling convention for +** functions provided by the operating system. +** +** Currently, the SQLITE_CDECL, SQLITE_APICALL, SQLITE_CALLBACK, and +** SQLITE_SYSAPI macros are used only when building for environments +** that require non-default calling conventions. */ #ifndef SQLITE_EXTERN # define SQLITE_EXTERN extern@@ -1205,9 +452,9 @@ ** See also: [sqlite3_libversion()],
** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.36.0" -#define SQLITE_VERSION_NUMBER 3036000 -#define SQLITE_SOURCE_ID "2021-06-18 18:36:39 5c9a6c06871cb9fe42814af9c039eb6da5427a6ec28f187af7ebfb62eafa66e5" +#define SQLITE_VERSION "3.39.2" +#define SQLITE_VERSION_NUMBER 3039002 +#define SQLITE_SOURCE_ID "2022-07-21 15:24:47 698edb77537b67c41adc68f9b892db56bcf9a55e00371a61420f3ddd668e6603" /* ** CAPI3REF: Run-Time Library Version Numbers@@ -1619,12 +866,13 @@ #define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8))
#define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8)) #define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT |(10<<8)) #define SQLITE_CONSTRAINT_PINNED (SQLITE_CONSTRAINT |(11<<8)) +#define SQLITE_CONSTRAINT_DATATYPE (SQLITE_CONSTRAINT |(12<<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)) -#define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) +#define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) /* internal use only */ /* ** CAPI3REF: Flags For File Open Operations@@ -1632,6 +880,19 @@ **
** These bit values are intended for use in the ** 3rd parameter to the [sqlite3_open_v2()] interface and ** in the 4th parameter to the [sqlite3_vfs.xOpen] method. +** +** Only those flags marked as "Ok for sqlite3_open_v2()" may be +** used as the third argument to the [sqlite3_open_v2()] interface. +** The other flags have historically been ignored by sqlite3_open_v2(), +** though future versions of SQLite might change so that an error is +** raised if any of the disallowed bits are passed into sqlite3_open_v2(). +** Applications should not depend on the historical behavior. +** +** Note in particular that passing the SQLITE_OPEN_EXCLUSIVE flag into +** [sqlite3_open_v2()] does *not* cause the underlying database file +** to be opened using O_EXCL. Passing SQLITE_OPEN_EXCLUSIVE into +** [sqlite3_open_v2()] has historically be a no-op and might become an +** error in future versions of SQLite. */ #define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */@@ -1654,6 +915,7 @@ #define SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_PRIVATECACHE 0x00040000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_WAL 0x00080000 /* VFS only */ #define SQLITE_OPEN_NOFOLLOW 0x01000000 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_EXRESCODE 0x02000000 /* Extended result codes */ /* Reserved: 0x00F00000 */ /* Legacy compatibility: */@@ -3546,11 +2808,14 @@ /*
** CAPI3REF: Count The Number Of Rows Modified ** METHOD: sqlite3 ** -** ^This function returns the number of rows modified, inserted or +** ^These functions return the number of rows modified, inserted or ** deleted by the most recently completed INSERT, UPDATE or DELETE ** statement on the database connection specified by the only parameter. -** ^Executing any other type of SQL statement does not modify the value -** returned by this function. +** The two functions are identical except for the type of the return value +** and that if the number of rows modified by the most recent INSERT, UPDATE +** or DELETE is greater than the maximum value supported by type "int", then +** the return value of sqlite3_changes() is undefined. ^Executing any other +** type of SQL statement does not modify the value returned by these functions. ** ** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are ** considered - auxiliary changes caused by [CREATE TRIGGER | triggers],@@ -3599,16 +2864,21 @@ ** <li> the [data_version pragma]
** </ul> */ SQLITE_API int sqlite3_changes(sqlite3*); +SQLITE_API sqlite3_int64 sqlite3_changes64(sqlite3*); /* ** CAPI3REF: Total Number Of Rows Modified ** METHOD: sqlite3 ** -** ^This function returns the total number of rows inserted, modified or +** ^These functions return the total number of rows inserted, modified or ** deleted by all [INSERT], [UPDATE] or [DELETE] statements completed ** since the database connection was opened, including those executed as -** part of trigger programs. ^Executing any other type of SQL statement -** does not affect the value returned by sqlite3_total_changes(). +** part of trigger programs. The two functions are identical except for the +** type of the return value and that if the number of rows modified by the +** connection exceeds the maximum value supported by type "int", then +** the return value of sqlite3_total_changes() is undefined. ^Executing +** any other type of SQL statement does not affect the value returned by +** sqlite3_total_changes(). ** ** ^Changes made as part of [foreign key actions] are included in the ** count, but those made as part of REPLACE constraint resolution are@@ -3636,6 +2906,7 @@ ** <li> the [SQLITE_FCNTL_DATA_VERSION] [file control]
** </ul> */ SQLITE_API int sqlite3_total_changes(sqlite3*); +SQLITE_API sqlite3_int64 sqlite3_total_changes64(sqlite3*); /* ** CAPI3REF: Interrupt A Long-Running Query@@ -4465,6 +3736,14 @@ ** <dd>The database is opened [shared cache] disabled, overriding
** the default shared cache setting provided by ** [sqlite3_enable_shared_cache()].)^ ** +** [[OPEN_EXRESCODE]] ^(<dt>[SQLITE_OPEN_EXRESCODE]</dt> +** <dd>The database connection comes up in "extended result code mode". +** In other words, the database behaves has if +** [sqlite3_extended_result_codes(db,1)] where called on the database +** connection as soon as the connection is created. In addition to setting +** the extended result code mode, this flag also causes [sqlite3_open_v2()] +** to return an extended result code.</dd> +** ** [[OPEN_NOFOLLOW]] ^(<dt>[SQLITE_OPEN_NOFOLLOW]</dt> ** <dd>The database filename is not allowed to be a symbolic link</dd> ** </dl>)^@@ -4472,7 +3751,15 @@ **
** If the 3rd parameter to sqlite3_open_v2() is not one of the ** required combinations shown above optionally combined with other ** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits] -** then the behavior is undefined. +** then the behavior is undefined. Historic versions of SQLite +** have silently ignored surplus bits in the flags parameter to +** sqlite3_open_v2(), however that behavior might not be carried through +** into future versions of SQLite and so applications should not rely +** upon it. Note in particular that the SQLITE_OPEN_EXCLUSIVE flag is a no-op +** for sqlite3_open_v2(). The SQLITE_OPEN_EXCLUSIVE does *not* cause +** the open to fail if the database already exists. The SQLITE_OPEN_EXCLUSIVE +** flag is intended for use by the [sqlite3_vfs|VFS interface] only, and not +** by sqlite3_open_v2(). ** ** ^The fourth parameter to sqlite3_open_v2() is the name of the ** [sqlite3_vfs] object that defines the operating system interface that@@ -4843,13 +4130,14 @@ ** The values returned by sqlite3_errcode() and/or
** sqlite3_extended_errcode() might change with each API call. ** Except, there are some interfaces that are guaranteed to never ** change the value of the error code. The error-code preserving -** interfaces are: +** interfaces include the following: ** ** <ul> ** <li> sqlite3_errcode() ** <li> sqlite3_extended_errcode() ** <li> sqlite3_errmsg() ** <li> sqlite3_errmsg16() +** <li> sqlite3_error_offset() ** </ul> ** ** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language@@ -4864,6 +4152,13 @@ ** that describes the [result code], as UTF-8.
** ^(Memory to hold the error message string is managed internally ** and must not be freed by the application)^. ** +** ^If the most recent error references a specific token in the input +** SQL, the sqlite3_error_offset() interface returns the byte offset +** of the start of that token. ^The byte offset returned by +** sqlite3_error_offset() assumes that the input SQL is UTF8. +** ^If the most recent error does not reference a specific token in the input +** SQL, then the sqlite3_error_offset() function returns -1. +** ** When the serialized [threading mode] is in use, it might be the ** case that a second error occurs on a separate thread in between ** the time of the first error and the call to these interfaces.@@ -4883,6 +4178,7 @@ SQLITE_API int sqlite3_extended_errcode(sqlite3 *db);
SQLITE_API const char *sqlite3_errmsg(sqlite3*); SQLITE_API const void *sqlite3_errmsg16(sqlite3*); SQLITE_API const char *sqlite3_errstr(int); +SQLITE_API int sqlite3_error_offset(sqlite3 *db); /* ** CAPI3REF: Prepared Statement Object@@ -5240,12 +4536,17 @@ ** ^The strings returned by sqlite3_sql(P) and sqlite3_normalized_sql(P)
** are managed by SQLite and are 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 +** is obtained from [sqlite3_malloc()] and must be freed by the application ** by passing it to [sqlite3_free()]. +** +** ^The sqlite3_normalized_sql() interface is only available if +** the [SQLITE_ENABLE_NORMALIZE] compile-time option is defined. */ SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt); SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt); +#ifdef SQLITE_ENABLE_NORMALIZE SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt); +#endif /* ** CAPI3REF: Determine If An SQL Statement Writes The Database@@ -5289,6 +4590,10 @@ ** makes it a no-op, but the sqlite3_stmt_readonly() result would still
** be false. ^Similarly, a CREATE TABLE IF NOT EXISTS statement is a ** read-only no-op if the table already exists, but ** sqlite3_stmt_readonly() still returns false for such a statement. +** +** ^If prepared statement X is an [EXPLAIN] or [EXPLAIN QUERY PLAN] +** statement, then sqlite3_stmt_readonly(X) returns the same value as +** if the EXPLAIN or EXPLAIN QUERY PLAN prefix were omitted. */ SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);@@ -5357,6 +4662,8 @@ ** sqlite3_value objects even when not strictly required.
** ** ^The sqlite3_value objects that are passed as parameters into the ** implementation of [application-defined SQL functions] are protected. +** ^The sqlite3_value objects returned by [sqlite3_vtab_rhs_value()] +** are protected. ** ^The sqlite3_value object returned by ** [sqlite3_column_value()] is unprotected. ** Unprotected sqlite3_value objects may only be used as arguments@@ -5977,6 +5284,10 @@ **
** ^Strings returned by sqlite3_column_text() and sqlite3_column_text16(), ** even empty strings, are always zero-terminated. ^The return ** value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer. +** +** ^Strings returned by sqlite3_column_text16() always have the endianness +** which is native to the platform, regardless of the text encoding set +** for the database. ** ** <b>Warning:</b> ^The object returned by [sqlite3_column_value()] is an ** [unprotected sqlite3_value] object. In a multithreaded environment,@@ -5991,7 +5302,7 @@ ** is normally only useful within the implementation of
** [application-defined SQL functions] or [virtual tables], not within ** top-level application code. ** -** The these routines may attempt to convert the datatype of the result. +** These routines may attempt to convert the datatype of the result. ** ^For example, if the internal representation is FLOAT and a text result ** is requested, [sqlite3_snprintf()] is used internally to perform the ** conversion automatically. ^(The following table details the conversions@@ -6016,7 +5327,7 @@ ** <tr><td> TEXT <td> FLOAT <td> [CAST] to REAL
** <tr><td> TEXT <td> BLOB <td> No change ** <tr><td> BLOB <td> INTEGER <td> [CAST] to INTEGER ** <tr><td> BLOB <td> FLOAT <td> [CAST] to REAL -** <tr><td> BLOB <td> TEXT <td> Add a zero terminator if needed +** <tr><td> BLOB <td> TEXT <td> [CAST] to TEXT, ensure zero terminator ** </table> ** </blockquote>)^ **@@ -6588,7 +5899,8 @@ ** ^The sqlite3_value_dup(V) interface makes a copy of the [sqlite3_value]
** object D and returns a pointer to that copy. ^The [sqlite3_value] returned ** is a [protected sqlite3_value] object even if the input is not. ** ^The sqlite3_value_dup(V) interface returns NULL if V is NULL or if a -** memory allocation fails. +** memory allocation fails. ^If V is a [pointer value], then the result +** of sqlite3_value_dup(V) is a NULL value. ** ** ^The sqlite3_value_free(V) interface frees an [sqlite3_value] object ** previously obtained from [sqlite3_value_dup()]. ^If V is a NULL pointer@@ -7271,6 +6583,28 @@ */
SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*); /* +** CAPI3REF: Return The Schema Name For A Database Connection +** METHOD: sqlite3 +** +** ^The sqlite3_db_name(D,N) interface returns a pointer to the schema name +** for the N-th database on database connection D, or a NULL pointer of N is +** out of range. An N value of 0 means the main database file. An N of 1 is +** the "temp" schema. Larger values of N correspond to various ATTACH-ed +** databases. +** +** Space to hold the string that is returned by sqlite3_db_name() is managed +** by SQLite itself. The string might be deallocated by any operation that +** changes the schema, including [ATTACH] or [DETACH] or calls to +** [sqlite3_serialize()] or [sqlite3_deserialize()], even operations that +** occur on a different thread. Applications that need to +** remember the string long-term should make their own copy. Applications that +** are accessing the same database connection simultaneously on multiple +** threads should mutex-protect calls to this API and should make their own +** private copy of the result prior to releasing the mutex. +*/ +SQLITE_API const char *sqlite3_db_name(sqlite3 *db, int N); + +/* ** CAPI3REF: Return The Filename For A Database Connection ** METHOD: sqlite3 **@@ -7430,6 +6764,72 @@ SQLITE_API void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); /* +** CAPI3REF: Autovacuum Compaction Amount Callback +** METHOD: sqlite3 +** +** ^The sqlite3_autovacuum_pages(D,C,P,X) interface registers a callback +** function C that is invoked prior to each autovacuum of the database +** file. ^The callback is passed a copy of the generic data pointer (P), +** the schema-name of the attached database that is being autovacuumed, +** the the size of the database file in pages, the number of free pages, +** and the number of bytes per page, respectively. The callback should +** return the number of free pages that should be removed by the +** autovacuum. ^If the callback returns zero, then no autovacuum happens. +** ^If the value returned is greater than or equal to the number of +** free pages, then a complete autovacuum happens. +** +** <p>^If there are multiple ATTACH-ed database files that are being +** modified as part of a transaction commit, then the autovacuum pages +** callback is invoked separately for each file. +** +** <p><b>The callback is not reentrant.</b> The callback function should +** not attempt to invoke any other SQLite interface. If it does, bad +** things may happen, including segmentation faults and corrupt database +** files. The callback function should be a simple function that +** does some arithmetic on its input parameters and returns a result. +** +** ^The X parameter to sqlite3_autovacuum_pages(D,C,P,X) is an optional +** destructor for the P parameter. ^If X is not NULL, then X(P) is +** invoked whenever the database connection closes or when the callback +** is overwritten by another invocation of sqlite3_autovacuum_pages(). +** +** <p>^There is only one autovacuum pages callback per database connection. +** ^Each call to the sqlite3_autovacuum_pages() interface overrides all +** previous invocations for that database connection. ^If the callback +** argument (C) to sqlite3_autovacuum_pages(D,C,P,X) is a NULL pointer, +** then the autovacuum steps callback is cancelled. The return value +** from sqlite3_autovacuum_pages() is normally SQLITE_OK, but might +** be some other error code if something goes wrong. The current +** implementation will only return SQLITE_OK or SQLITE_MISUSE, but other +** return codes might be added in future releases. +** +** <p>If no autovacuum pages callback is specified (the usual case) or +** a NULL pointer is provided for the callback, +** then the default behavior is to vacuum all free pages. So, in other +** words, the default behavior is the same as if the callback function +** were something like this: +** +** <blockquote><pre> +** unsigned int demonstration_autovac_pages_callback( +** void *pClientData, +** const char *zSchema, +** unsigned int nDbPage, +** unsigned int nFreePage, +** unsigned int nBytePerPage +** ){ +** return nFreePage; +** } +** </pre></blockquote> +*/ +SQLITE_API int sqlite3_autovacuum_pages( + sqlite3 *db, + unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int), + void*, + void(*)(void*) +); + + +/* ** CAPI3REF: Data Change Notification Callbacks ** METHOD: sqlite3 **@@ -8070,24 +7470,56 @@ ** CAPI3REF: Virtual Table Constraint Operator Codes
** ** These macros define the allowed values for the ** [sqlite3_index_info].aConstraint[].op field. Each value represents -** an operator that is part of a constraint term in the wHERE clause of +** an operator that is part of a constraint term in the WHERE clause of ** a query that uses a [virtual table]. +** +** ^The left-hand operand of the operator is given by the corresponding +** aConstraint[].iColumn field. ^An iColumn of -1 indicates the left-hand +** operand is the rowid. +** The SQLITE_INDEX_CONSTRAINT_LIMIT and SQLITE_INDEX_CONSTRAINT_OFFSET +** operators have no left-hand operand, and so for those operators the +** corresponding aConstraint[].iColumn is meaningless and should not be +** used. +** +** All operator values from SQLITE_INDEX_CONSTRAINT_FUNCTION through +** value 255 are reserved to represent functions that are overloaded +** by the [xFindFunction|xFindFunction method] of the virtual table +** implementation. +** +** The right-hand operands for each constraint might be accessible using +** the [sqlite3_vtab_rhs_value()] interface. Usually the right-hand +** operand is only available if it appears as a single constant literal +** in the input SQL. If the right-hand operand is another column or an +** expression (even a constant expression) or a parameter, then the +** sqlite3_vtab_rhs_value() probably will not be able to extract it. +** ^The SQLITE_INDEX_CONSTRAINT_ISNULL and +** SQLITE_INDEX_CONSTRAINT_ISNOTNULL operators have no right-hand operand +** and hence calls to sqlite3_vtab_rhs_value() for those operators will +** always return SQLITE_NOTFOUND. +** +** The collating sequence to be used for comparison can be found using +** the [sqlite3_vtab_collation()] interface. For most real-world virtual +** tables, the collating sequence of constraints does not matter (for example +** because the constraints are numeric) and so the sqlite3_vtab_collation() +** interface is no commonly needed. */ -#define SQLITE_INDEX_CONSTRAINT_EQ 2 -#define SQLITE_INDEX_CONSTRAINT_GT 4 -#define SQLITE_INDEX_CONSTRAINT_LE 8 -#define SQLITE_INDEX_CONSTRAINT_LT 16 -#define SQLITE_INDEX_CONSTRAINT_GE 32 -#define SQLITE_INDEX_CONSTRAINT_MATCH 64 -#define SQLITE_INDEX_CONSTRAINT_LIKE 65 -#define SQLITE_INDEX_CONSTRAINT_GLOB 66 -#define SQLITE_INDEX_CONSTRAINT_REGEXP 67 -#define SQLITE_INDEX_CONSTRAINT_NE 68 -#define SQLITE_INDEX_CONSTRAINT_ISNOT 69 -#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70 -#define SQLITE_INDEX_CONSTRAINT_ISNULL 71 -#define SQLITE_INDEX_CONSTRAINT_IS 72 -#define SQLITE_INDEX_CONSTRAINT_FUNCTION 150 +#define SQLITE_INDEX_CONSTRAINT_EQ 2 +#define SQLITE_INDEX_CONSTRAINT_GT 4 +#define SQLITE_INDEX_CONSTRAINT_LE 8 +#define SQLITE_INDEX_CONSTRAINT_LT 16 +#define SQLITE_INDEX_CONSTRAINT_GE 32 +#define SQLITE_INDEX_CONSTRAINT_MATCH 64 +#define SQLITE_INDEX_CONSTRAINT_LIKE 65 +#define SQLITE_INDEX_CONSTRAINT_GLOB 66 +#define SQLITE_INDEX_CONSTRAINT_REGEXP 67 +#define SQLITE_INDEX_CONSTRAINT_NE 68 +#define SQLITE_INDEX_CONSTRAINT_ISNOT 69 +#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70 +#define SQLITE_INDEX_CONSTRAINT_ISNULL 71 +#define SQLITE_INDEX_CONSTRAINT_IS 72 +#define SQLITE_INDEX_CONSTRAINT_LIMIT 73 +#define SQLITE_INDEX_CONSTRAINT_OFFSET 74 +#define SQLITE_INDEX_CONSTRAINT_FUNCTION 150 /* ** CAPI3REF: Register A Virtual Table Implementation@@ -8116,7 +7548,7 @@ ** interface is equivalent to sqlite3_create_module_v2() with a NULL
** destructor. ** ** ^If the third parameter (the pointer to the sqlite3_module object) is -** NULL then no new module is create and any existing modules with the +** NULL then no new module is created and any existing modules with the ** same name are dropped. ** ** See also: [sqlite3_drop_modules()]@@ -8892,7 +8324,8 @@ #define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29
#define SQLITE_TESTCTRL_SEEK_COUNT 30 #define SQLITE_TESTCTRL_TRACEFLAGS 31 #define SQLITE_TESTCTRL_TUNE 32 -#define SQLITE_TESTCTRL_LAST 32 /* Largest TESTCTRL */ +#define SQLITE_TESTCTRL_LOGEST 33 +#define SQLITE_TESTCTRL_LAST 33 /* Largest TESTCTRL */ /* ** CAPI3REF: SQL Keyword Checking@@ -9415,6 +8848,16 @@ ** or more calls to [sqlite3_step()] followed by a call to [sqlite3_reset()].
** The counter is incremented on the first [sqlite3_step()] call of each ** cycle. ** +** [[SQLITE_STMTSTATUS_FILTER_MISS]] +** [[SQLITE_STMTSTATUS_FILTER HIT]] +** <dt>SQLITE_STMTSTATUS_FILTER_HIT<br> +** SQLITE_STMTSTATUS_FILTER_MISS</dt> +** <dd>^SQLITE_STMTSTATUS_FILTER_HIT is the number of times that a join +** step was bypassed because a Bloom filter returned not-found. The +** corresponding SQLITE_STMTSTATUS_FILTER_MISS value is the number of +** times that the Bloom filter returned a find, and thus the join step +** had to be processed as normal. +** ** [[SQLITE_STMTSTATUS_MEMUSED]] <dt>SQLITE_STMTSTATUS_MEMUSED</dt> ** <dd>^This is the approximate number of bytes of heap memory ** used to store the prepared statement. ^This value is not actually@@ -9429,6 +8872,8 @@ #define SQLITE_STMTSTATUS_AUTOINDEX 3
#define SQLITE_STMTSTATUS_VM_STEP 4 #define SQLITE_STMTSTATUS_REPREPARE 5 #define SQLITE_STMTSTATUS_RUN 6 +#define SQLITE_STMTSTATUS_FILTER_MISS 7 +#define SQLITE_STMTSTATUS_FILTER_HIT 8 #define SQLITE_STMTSTATUS_MEMUSED 99 /*@@ -10092,8 +9537,9 @@ ** are undefined.
** ** A single database handle may have at most a single write-ahead log callback ** registered at one time. ^Calling [sqlite3_wal_hook()] replaces any -** previously registered write-ahead log callback. ^Note that the -** [sqlite3_wal_autocheckpoint()] interface and the +** previously registered write-ahead log callback. ^The return value is +** a copy of the third parameter from the previous call, if any, or 0. +** ^Note that the [sqlite3_wal_autocheckpoint()] interface and the ** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will ** overwrite any prior [sqlite3_wal_hook()] settings. */@@ -10396,20 +9842,277 @@ SQLITE_API int sqlite3_vtab_nochange(sqlite3_context*);
/* ** CAPI3REF: Determine The Collation For a Virtual Table Constraint +** METHOD: sqlite3_index_info ** ** This function may only be called from within a call to the [xBestIndex] -** method of a [virtual table]. +** method of a [virtual table]. This function returns a pointer to a string +** that is the name of the appropriate collation sequence to use for text +** comparisons on the constraint identified by its arguments. +** +** The first argument must be the pointer to the [sqlite3_index_info] object +** that is the first parameter to the xBestIndex() method. The second argument +** must be an index into the aConstraint[] array belonging to the +** sqlite3_index_info structure passed to xBestIndex. +** +** Important: +** The first parameter must be the same pointer that is passed into the +** xBestMethod() method. The first parameter may not be a pointer to a +** different [sqlite3_index_info] object, even an exact copy. ** -** The first argument must be the sqlite3_index_info object that is the -** first parameter to the xBestIndex() method. The second argument must be -** an index into the aConstraint[] array belonging to the sqlite3_index_info -** structure passed to xBestIndex. This function returns a pointer to a buffer -** containing the name of the collation sequence for the corresponding -** constraint. +** The return value is computed as follows: +** +** <ol> +** <li><p> If the constraint comes from a WHERE clause expression that contains +** a [COLLATE operator], then the name of the collation specified by +** that COLLATE operator is returned. +** <li><p> If there is no COLLATE operator, but the column that is the subject +** of the constraint specifies an alternative collating sequence via +** a [COLLATE clause] on the column definition within the CREATE TABLE +** statement that was passed into [sqlite3_declare_vtab()], then the +** name of that alternative collating sequence is returned. +** <li><p> Otherwise, "BINARY" is returned. +** </ol> */ SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int); /* +** CAPI3REF: Determine if a virtual table query is DISTINCT +** METHOD: sqlite3_index_info +** +** This API may only be used from within an [xBestIndex|xBestIndex method] +** of a [virtual table] implementation. The result of calling this +** interface from outside of xBestIndex() is undefined and probably harmful. +** +** ^The sqlite3_vtab_distinct() interface returns an integer between 0 and +** 3. The integer returned by sqlite3_vtab_distinct() +** gives the virtual table additional information about how the query +** planner wants the output to be ordered. As long as the virtual table +** can meet the ordering requirements of the query planner, it may set +** the "orderByConsumed" flag. +** +** <ol><li value="0"><p> +** ^If the sqlite3_vtab_distinct() interface returns 0, that means +** that the query planner needs the virtual table to return all rows in the +** sort order defined by the "nOrderBy" and "aOrderBy" fields of the +** [sqlite3_index_info] object. This is the default expectation. If the +** virtual table outputs all rows in sorted order, then it is always safe for +** the xBestIndex method to set the "orderByConsumed" flag, regardless of +** the return value from sqlite3_vtab_distinct(). +** <li value="1"><p> +** ^(If the sqlite3_vtab_distinct() interface returns 1, that means +** that the query planner does not need the rows to be returned in sorted order +** as long as all rows with the same values in all columns identified by the +** "aOrderBy" field are adjacent.)^ This mode is used when the query planner +** is doing a GROUP BY. +** <li value="2"><p> +** ^(If the sqlite3_vtab_distinct() interface returns 2, that means +** that the query planner does not need the rows returned in any particular +** order, as long as rows with the same values in all "aOrderBy" columns +** are adjacent.)^ ^(Furthermore, only a single row for each particular +** combination of values in the columns identified by the "aOrderBy" field +** needs to be returned.)^ ^It is always ok for two or more rows with the same +** values in all "aOrderBy" columns to be returned, as long as all such rows +** are adjacent. ^The virtual table may, if it chooses, omit extra rows +** that have the same value for all columns identified by "aOrderBy". +** ^However omitting the extra rows is optional. +** This mode is used for a DISTINCT query. +** <li value="3"><p> +** ^(If the sqlite3_vtab_distinct() interface returns 3, that means +** that the query planner needs only distinct rows but it does need the +** rows to be sorted.)^ ^The virtual table implementation is free to omit +** rows that are identical in all aOrderBy columns, if it wants to, but +** it is not required to omit any rows. This mode is used for queries +** that have both DISTINCT and ORDER BY clauses. +** </ol> +** +** ^For the purposes of comparing virtual table output values to see if the +** values are same value for sorting purposes, two NULL values are considered +** to be the same. In other words, the comparison operator is "IS" +** (or "IS NOT DISTINCT FROM") and not "==". +** +** If a virtual table implementation is unable to meet the requirements +** specified above, then it must not set the "orderByConsumed" flag in the +** [sqlite3_index_info] object or an incorrect answer may result. +** +** ^A virtual table implementation is always free to return rows in any order +** it wants, as long as the "orderByConsumed" flag is not set. ^When the +** the "orderByConsumed" flag is unset, the query planner will add extra +** [bytecode] to ensure that the final results returned by the SQL query are +** ordered correctly. The use of the "orderByConsumed" flag and the +** sqlite3_vtab_distinct() interface is merely an optimization. ^Careful +** use of the sqlite3_vtab_distinct() interface and the "orderByConsumed" +** flag might help queries against a virtual table to run faster. Being +** overly aggressive and setting the "orderByConsumed" flag when it is not +** valid to do so, on the other hand, might cause SQLite to return incorrect +** results. +*/ +SQLITE_API int sqlite3_vtab_distinct(sqlite3_index_info*); + +/* +** CAPI3REF: Identify and handle IN constraints in xBestIndex +** +** This interface may only be used from within an +** [xBestIndex|xBestIndex() method] of a [virtual table] implementation. +** The result of invoking this interface from any other context is +** undefined and probably harmful. +** +** ^(A constraint on a virtual table of the form +** "[IN operator|column IN (...)]" is +** communicated to the xBestIndex method as a +** [SQLITE_INDEX_CONSTRAINT_EQ] constraint.)^ If xBestIndex wants to use +** this constraint, it must set the corresponding +** aConstraintUsage[].argvIndex to a postive integer. ^(Then, under +** the usual mode of handling IN operators, SQLite generates [bytecode] +** that invokes the [xFilter|xFilter() method] once for each value +** on the right-hand side of the IN operator.)^ Thus the virtual table +** only sees a single value from the right-hand side of the IN operator +** at a time. +** +** In some cases, however, it would be advantageous for the virtual +** table to see all values on the right-hand of the IN operator all at +** once. The sqlite3_vtab_in() interfaces facilitates this in two ways: +** +** <ol> +** <li><p> +** ^A call to sqlite3_vtab_in(P,N,-1) will return true (non-zero) +** if and only if the [sqlite3_index_info|P->aConstraint][N] constraint +** is an [IN operator] that can be processed all at once. ^In other words, +** sqlite3_vtab_in() with -1 in the third argument is a mechanism +** by which the virtual table can ask SQLite if all-at-once processing +** of the IN operator is even possible. +** +** <li><p> +** ^A call to sqlite3_vtab_in(P,N,F) with F==1 or F==0 indicates +** to SQLite that the virtual table does or does not want to process +** the IN operator all-at-once, respectively. ^Thus when the third +** parameter (F) is non-negative, this interface is the mechanism by +** which the virtual table tells SQLite how it wants to process the +** IN operator. +** </ol> +** +** ^The sqlite3_vtab_in(P,N,F) interface can be invoked multiple times +** within the same xBestIndex method call. ^For any given P,N pair, +** the return value from sqlite3_vtab_in(P,N,F) will always be the same +** within the same xBestIndex call. ^If the interface returns true +** (non-zero), that means that the constraint is an IN operator +** that can be processed all-at-once. ^If the constraint is not an IN +** operator or cannot be processed all-at-once, then the interface returns +** false. +** +** ^(All-at-once processing of the IN operator is selected if both of the +** following conditions are met: +** +** <ol> +** <li><p> The P->aConstraintUsage[N].argvIndex value is set to a positive +** integer. This is how the virtual table tells SQLite that it wants to +** use the N-th constraint. +** +** <li><p> The last call to sqlite3_vtab_in(P,N,F) for which F was +** non-negative had F>=1. +** </ol>)^ +** +** ^If either or both of the conditions above are false, then SQLite uses +** the traditional one-at-a-time processing strategy for the IN constraint. +** ^If both conditions are true, then the argvIndex-th parameter to the +** xFilter method will be an [sqlite3_value] that appears to be NULL, +** but which can be passed to [sqlite3_vtab_in_first()] and +** [sqlite3_vtab_in_next()] to find all values on the right-hand side +** of the IN constraint. +*/ +SQLITE_API int sqlite3_vtab_in(sqlite3_index_info*, int iCons, int bHandle); + +/* +** CAPI3REF: Find all elements on the right-hand side of an IN constraint. +** +** These interfaces are only useful from within the +** [xFilter|xFilter() method] of a [virtual table] implementation. +** The result of invoking these interfaces from any other context +** is undefined and probably harmful. +** +** The X parameter in a call to sqlite3_vtab_in_first(X,P) or +** sqlite3_vtab_in_next(X,P) must be one of the parameters to the +** xFilter method which invokes these routines, and specifically +** a parameter that was previously selected for all-at-once IN constraint +** processing use the [sqlite3_vtab_in()] interface in the +** [xBestIndex|xBestIndex method]. ^(If the X parameter is not +** an xFilter argument that was selected for all-at-once IN constraint +** processing, then these routines return [SQLITE_MISUSE])^ or perhaps +** exhibit some other undefined or harmful behavior. +** +** ^(Use these routines to access all values on the right-hand side +** of the IN constraint using code like the following: +** +** <blockquote><pre> +** for(rc=sqlite3_vtab_in_first(pList, &pVal); +** rc==SQLITE_OK && pVal +** rc=sqlite3_vtab_in_next(pList, &pVal) +** ){ +** // do something with pVal +** } +** if( rc!=SQLITE_OK ){ +** // an error has occurred +** } +** </pre></blockquote>)^ +** +** ^On success, the sqlite3_vtab_in_first(X,P) and sqlite3_vtab_in_next(X,P) +** routines return SQLITE_OK and set *P to point to the first or next value +** on the RHS of the IN constraint. ^If there are no more values on the +** right hand side of the IN constraint, then *P is set to NULL and these +** routines return [SQLITE_DONE]. ^The return value might be +** some other value, such as SQLITE_NOMEM, in the event of a malfunction. +** +** The *ppOut values returned by these routines are only valid until the +** next call to either of these routines or until the end of the xFilter +** method from which these routines were called. If the virtual table +** implementation needs to retain the *ppOut values for longer, it must make +** copies. The *ppOut values are [protected sqlite3_value|protected]. +*/ +SQLITE_API int sqlite3_vtab_in_first(sqlite3_value *pVal, sqlite3_value **ppOut); +SQLITE_API int sqlite3_vtab_in_next(sqlite3_value *pVal, sqlite3_value **ppOut); + +/* +** CAPI3REF: Constraint values in xBestIndex() +** METHOD: sqlite3_index_info +** +** This API may only be used from within the [xBestIndex|xBestIndex method] +** of a [virtual table] implementation. The result of calling this interface +** from outside of an xBestIndex method are undefined and probably harmful. +** +** ^When the sqlite3_vtab_rhs_value(P,J,V) interface is invoked from within +** the [xBestIndex] method of a [virtual table] implementation, with P being +** a copy of the [sqlite3_index_info] object pointer passed into xBestIndex and +** J being a 0-based index into P->aConstraint[], then this routine +** attempts to set *V to the value of the right-hand operand of +** that constraint if the right-hand operand is known. ^If the +** right-hand operand is not known, then *V is set to a NULL pointer. +** ^The sqlite3_vtab_rhs_value(P,J,V) interface returns SQLITE_OK if +** and only if *V is set to a value. ^The sqlite3_vtab_rhs_value(P,J,V) +** inteface returns SQLITE_NOTFOUND if the right-hand side of the J-th +** constraint is not available. ^The sqlite3_vtab_rhs_value() interface +** can return an result code other than SQLITE_OK or SQLITE_NOTFOUND if +** something goes wrong. +** +** The sqlite3_vtab_rhs_value() interface is usually only successful if +** the right-hand operand of a constraint is a literal value in the original +** SQL statement. If the right-hand operand is an expression or a reference +** to some other column or a [host parameter], then sqlite3_vtab_rhs_value() +** will probably return [SQLITE_NOTFOUND]. +** +** ^(Some constraints, such as [SQLITE_INDEX_CONSTRAINT_ISNULL] and +** [SQLITE_INDEX_CONSTRAINT_ISNOTNULL], have no right-hand operand. For such +** constraints, sqlite3_vtab_rhs_value() always returns SQLITE_NOTFOUND.)^ +** +** ^The [sqlite3_value] object returned in *V is a protected sqlite3_value +** and remains valid for the duration of the xBestIndex method call. +** ^When xBestIndex returns, the sqlite3_value object returned by +** sqlite3_vtab_rhs_value() is automatically deallocated. +** +** The "_rhs_" in the name of this routine is an abbreviation for +** "Right-Hand Side". +*/ +SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **ppVal); + +/* ** CAPI3REF: Conflict resolution modes ** KEYWORDS: {conflict resolution mode} **@@ -10959,6 +10662,10 @@ **
** The sqlite3_deserialize() interface will fail with SQLITE_BUSY if the ** database is currently in a read transaction or is involved in a backup ** operation. +** +** It is not possible to deserialized into the TEMP database. If the +** S argument to sqlite3_deserialize(D,S,P,N,M,F) is "temp" then the +** function returns SQLITE_ERROR. ** ** If sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the ** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then@@ -13442,7 +13149,7 @@ ** Include the configuration header output by 'configure' if we're using the
** autoconf-based build */ #if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H) -/* #include "config.h" */ +#include "config.h" #define SQLITECONFIG_H 1 #endif@@ -13678,11 +13385,12 @@ */
#ifndef __has_extension # define __has_extension(x) 0 /* compatibility with non-clang compilers */ #endif -#if GCC_VERSION>=4007000 || \ - (__has_extension(c_atomic) && __has_extension(c_atomic_store_n)) +#if GCC_VERSION>=4007000 || __has_extension(c_atomic) +# define SQLITE_ATOMIC_INTRINSICS 1 # define AtomicLoad(PTR) __atomic_load_n((PTR),__ATOMIC_RELAXED) # define AtomicStore(PTR,VAL) __atomic_store_n((PTR),(VAL),__ATOMIC_RELAXED) #else +# define SQLITE_ATOMIC_INTRINSICS 0 # define AtomicLoad(PTR) (*(PTR)) # define AtomicStore(PTR,VAL) (*(PTR) = (VAL)) #endif@@ -13887,11 +13595,12 @@ ** bitmask tests, testcase() can be used to make sure each bit
** is significant and used at least once. On switch statements ** where multiple cases go to the same block of code, testcase() ** can insure that all cases are evaluated. -** */ -#ifdef SQLITE_COVERAGE_TEST -SQLITE_PRIVATE void sqlite3Coverage(int); -# define testcase(X) if( X ){ sqlite3Coverage(__LINE__); } +#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG) +# ifndef SQLITE_AMALGAMATION + extern unsigned int sqlite3CoverageCounter; +# endif +# define testcase(X) if( X ){ sqlite3CoverageCounter += (unsigned)__LINE__; } #else # define testcase(X) #endif@@ -13922,6 +13631,14 @@ # define VVA_ONLY(X)
#endif /* +** Disable ALWAYS() and NEVER() (make them pass-throughs) for coverage +** and mutation testing +*/ +#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) +# define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1 +#endif + +/* ** The ALWAYS and NEVER macros surround boolean expressions which ** are intended to always be true or false, respectively. Such ** expressions could be omitted from the code completely. But they@@ -13936,7 +13653,7 @@ ** When doing coverage testing ALWAYS and NEVER are hard-coded to
** be true and false so that the unreachable code they specify will ** not be counted as untested code. */ -#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) +#if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS) # define ALWAYS(X) (1) # define NEVER(X) (0) #elif !defined(NDEBUG)@@ -13948,26 +13665,6 @@ # define NEVER(X) (X)
#endif /* -** The harmless(X) macro indicates that expression X is usually false -** but can be true without causing any problems, but we don't know of -** any way to cause X to be true. -** -** In debugging and testing builds, this macro will abort if X is ever -** true. In this way, developers are alerted to a possible test case -** that causes X to be true. If a harmless macro ever fails, that is -** an opportunity to change the macro into a testcase() and add a new -** test case to the test suite. -** -** For normal production builds, harmless(X) is a no-op, since it does -** not matter whether expression X is true or false. -*/ -#ifdef SQLITE_DEBUG -# define harmless(X) assert(!(X)); -#else -# define harmless(X) -#endif - -/* ** Some conditionals are optimizations only. In other words, if the ** conditionals are replaced with a constant 1 (true) or 0 (false) then ** the correct answer is still obtained, though perhaps not as quickly.@@ -14028,6 +13725,13 @@ ** SQLITE_ENABLE_EXPLAIN_COMMENTS is incompatible with SQLITE_OMIT_EXPLAIN
*/ #ifdef SQLITE_OMIT_EXPLAIN # undef SQLITE_ENABLE_EXPLAIN_COMMENTS +#endif + +/* +** SQLITE_OMIT_VIRTUALTABLE implies SQLITE_OMIT_ALTERTABLE +*/ +#if defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_ALTERTABLE) +# define SQLITE_OMIT_ALTERTABLE #endif /*@@ -14142,7 +13846,7 @@
/* ** Number of entries in a hash table */ -/* #define sqliteHashCount(H) ((H)->count) // NOT USED */ +#define sqliteHashCount(H) ((H)->count) #endif /* SQLITE_HASH_H */@@ -14174,8 +13878,8 @@ #define TK_TEMP 21
#define TK_LP 22 #define TK_RP 23 #define TK_AS 24 -#define TK_WITHOUT 25 -#define TK_COMMA 26 +#define TK_COMMA 25 +#define TK_WITHOUT 26 #define TK_ABORT 27 #define TK_ACTION 28 #define TK_AFTER 29@@ -14261,78 +13965,79 @@ #define TK_STAR 108
#define TK_SLASH 109 #define TK_REM 110 #define TK_CONCAT 111 -#define TK_COLLATE 112 -#define TK_BITNOT 113 -#define TK_ON 114 -#define TK_INDEXED 115 -#define TK_STRING 116 -#define TK_JOIN_KW 117 -#define TK_CONSTRAINT 118 -#define TK_DEFAULT 119 -#define TK_NULL 120 -#define TK_PRIMARY 121 -#define TK_UNIQUE 122 -#define TK_CHECK 123 -#define TK_REFERENCES 124 -#define TK_AUTOINCR 125 -#define TK_INSERT 126 -#define TK_DELETE 127 -#define TK_UPDATE 128 -#define TK_SET 129 -#define TK_DEFERRABLE 130 -#define TK_FOREIGN 131 -#define TK_DROP 132 -#define TK_UNION 133 -#define TK_ALL 134 -#define TK_EXCEPT 135 -#define TK_INTERSECT 136 -#define TK_SELECT 137 -#define TK_VALUES 138 -#define TK_DISTINCT 139 -#define TK_DOT 140 -#define TK_FROM 141 -#define TK_JOIN 142 -#define TK_USING 143 -#define TK_ORDER 144 -#define TK_GROUP 145 -#define TK_HAVING 146 -#define TK_LIMIT 147 -#define TK_WHERE 148 -#define TK_RETURNING 149 -#define TK_INTO 150 -#define TK_NOTHING 151 -#define TK_FLOAT 152 -#define TK_BLOB 153 -#define TK_INTEGER 154 -#define TK_VARIABLE 155 -#define TK_CASE 156 -#define TK_WHEN 157 -#define TK_THEN 158 -#define TK_ELSE 159 -#define TK_INDEX 160 -#define TK_ALTER 161 -#define TK_ADD 162 -#define TK_WINDOW 163 -#define TK_OVER 164 -#define TK_FILTER 165 -#define TK_COLUMN 166 -#define TK_AGG_FUNCTION 167 -#define TK_AGG_COLUMN 168 -#define TK_TRUEFALSE 169 -#define TK_ISNOT 170 -#define TK_FUNCTION 171 -#define TK_UMINUS 172 -#define TK_UPLUS 173 -#define TK_TRUTH 174 -#define TK_REGISTER 175 -#define TK_VECTOR 176 -#define TK_SELECT_COLUMN 177 -#define TK_IF_NULL_ROW 178 -#define TK_ASTERISK 179 -#define TK_SPAN 180 -#define TK_ERROR 181 -#define TK_SPACE 182 -#define TK_ILLEGAL 183 +#define TK_PTR 112 +#define TK_COLLATE 113 +#define TK_BITNOT 114 +#define TK_ON 115 +#define TK_INDEXED 116 +#define TK_STRING 117 +#define TK_JOIN_KW 118 +#define TK_CONSTRAINT 119 +#define TK_DEFAULT 120 +#define TK_NULL 121 +#define TK_PRIMARY 122 +#define TK_UNIQUE 123 +#define TK_CHECK 124 +#define TK_REFERENCES 125 +#define TK_AUTOINCR 126 +#define TK_INSERT 127 +#define TK_DELETE 128 +#define TK_UPDATE 129 +#define TK_SET 130 +#define TK_DEFERRABLE 131 +#define TK_FOREIGN 132 +#define TK_DROP 133 +#define TK_UNION 134 +#define TK_ALL 135 +#define TK_EXCEPT 136 +#define TK_INTERSECT 137 +#define TK_SELECT 138 +#define TK_VALUES 139 +#define TK_DISTINCT 140 +#define TK_DOT 141 +#define TK_FROM 142 +#define TK_JOIN 143 +#define TK_USING 144 +#define TK_ORDER 145 +#define TK_GROUP 146 +#define TK_HAVING 147 +#define TK_LIMIT 148 +#define TK_WHERE 149 +#define TK_RETURNING 150 +#define TK_INTO 151 +#define TK_NOTHING 152 +#define TK_FLOAT 153 +#define TK_BLOB 154 +#define TK_INTEGER 155 +#define TK_VARIABLE 156 +#define TK_CASE 157 +#define TK_WHEN 158 +#define TK_THEN 159 +#define TK_ELSE 160 +#define TK_INDEX 161 +#define TK_ALTER 162 +#define TK_ADD 163 +#define TK_WINDOW 164 +#define TK_OVER 165 +#define TK_FILTER 166 +#define TK_COLUMN 167 +#define TK_AGG_FUNCTION 168 +#define TK_AGG_COLUMN 169 +#define TK_TRUEFALSE 170 +#define TK_ISNOT 171 +#define TK_FUNCTION 172 +#define TK_UMINUS 173 +#define TK_UPLUS 174 +#define TK_TRUTH 175 +#define TK_REGISTER 176 +#define TK_VECTOR 177 +#define TK_SELECT_COLUMN 178 +#define TK_IF_NULL_ROW 179 +#define TK_ASTERISK 180 +#define TK_SPAN 181 +#define TK_ERROR 182 +#define TK_SPACE 183 +#define TK_ILLEGAL 184 /************** End of parse.h ***********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/@@ -14438,7 +14143,7 @@ ** pagecaches for each database connection. A positive number is the
** number of pages. A negative number N translations means that a buffer ** of -1024*N bytes is allocated and used for as many pages as it will hold. ** -** The default value of "20" was choosen to minimize the run-time of the +** The default value of "20" was chosen to minimize the run-time of the ** speedtest1 test program with options: --shrink-memory --reprepare */ #ifndef SQLITE_DEFAULT_PCACHE_INITSZ@@ -14600,6 +14305,7 @@ # if defined(__SIZEOF_POINTER__)
# define SQLITE_PTRSIZE __SIZEOF_POINTER__ # elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \ defined(_M_ARM) || defined(__arm__) || defined(__x86) || \ + (defined(__APPLE__) && defined(__POWERPC__)) || \ (defined(__TOS_AIX__) && !defined(__64BIT__)) # define SQLITE_PTRSIZE 4 # else@@ -14681,8 +14387,19 @@
/* ** Round up a number to the next larger multiple of 8. This is used ** to force 8-byte alignment on 64-bit architectures. +** +** ROUND8() always does the rounding, for any argument. +** +** ROUND8P() assumes that the argument is already an integer number of +** pointers in size, and so it is a no-op on systems where the pointer +** size is 8. */ #define ROUND8(x) (((x)+7)&~7) +#if SQLITE_PTRSIZE==8 +# define ROUND8P(x) (x) +#else +# define ROUND8P(x) (((x)+7)&~7) +#endif /* ** Round down to the nearest multiple of 8@@ -14745,22 +14462,23 @@ # define SQLITE_DEFAULT_MMAP_SIZE SQLITE_MAX_MMAP_SIZE
#endif /* -** SELECTTRACE_ENABLED will be either 1 or 0 depending on whether or not -** the Select query generator tracing logic is turned on. +** TREETRACE_ENABLED will be either 1 or 0 depending on whether or not +** the Abstract Syntax Tree tracing logic is turned on. */ #if !defined(SQLITE_AMALGAMATION) -SQLITE_PRIVATE u32 sqlite3SelectTrace; +SQLITE_PRIVATE u32 sqlite3TreeTrace; #endif #if defined(SQLITE_DEBUG) \ - && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_SELECTTRACE)) -# define SELECTTRACE_ENABLED 1 + && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_SELECTTRACE) \ + || defined(SQLITE_ENABLE_TREETRACE)) +# define TREETRACE_ENABLED 1 # define SELECTTRACE(K,P,S,X) \ - if(sqlite3SelectTrace&(K)) \ + if(sqlite3TreeTrace&(K)) \ sqlite3DebugPrintf("%u/%d/%p: ",(S)->selId,(P)->addrExplain,(S)),\ sqlite3DebugPrintf X #else # define SELECTTRACE(K,P,S,X) -# define SELECTTRACE_ENABLED 0 +# define TREETRACE_ENABLED 0 #endif /*@@ -14794,11 +14512,25 @@ };
/* ** Name of table that holds the database schema. +** +** The PREFERRED names are used whereever possible. But LEGACY is also +** used for backwards compatibility. +** +** 1. Queries can use either the PREFERRED or the LEGACY names +** 2. The sqlite3_set_authorizer() callback uses the LEGACY name +** 3. The PRAGMA table_list statement uses the PREFERRED name +** +** The LEGACY names are stored in the internal symbol hash table +** in support of (2). Names are translated using sqlite3PreferredTableName() +** for (3). The sqlite3FindTable() function takes care of translating +** names for (1). +** +** Note that "sqlite_temp_schema" can also be called "temp.sqlite_schema". */ -#define DFLT_SCHEMA_TABLE "sqlite_master" -#define DFLT_TEMP_SCHEMA_TABLE "sqlite_temp_master" -#define ALT_SCHEMA_TABLE "sqlite_schema" -#define ALT_TEMP_SCHEMA_TABLE "sqlite_temp_schema" +#define LEGACY_SCHEMA_TABLE "sqlite_master" +#define LEGACY_TEMP_SCHEMA_TABLE "sqlite_temp_master" +#define PREFERRED_SCHEMA_TABLE "sqlite_schema" +#define PREFERRED_TEMP_SCHEMA_TABLE "sqlite_temp_schema" /*@@ -14810,7 +14542,7 @@ /*
** The name of the schema table. The name is different for TEMP. */ #define SCHEMA_TABLE(x) \ - ((!OMIT_TEMPDB)&&(x==1)?DFLT_TEMP_SCHEMA_TABLE:DFLT_SCHEMA_TABLE) + ((!OMIT_TEMPDB)&&(x==1)?LEGACY_TEMP_SCHEMA_TABLE:LEGACY_SCHEMA_TABLE) /* ** A convenience macro that returns the number of elements in@@ -14831,7 +14563,7 @@ ** this magic value that the code knows to handle differently. Any
** pointer will work here as long as it is distinct from SQLITE_STATIC ** and SQLITE_TRANSIENT. */ -#define SQLITE_DYNAMIC ((sqlite3_destructor_type)sqlite3OomFault) +#define SQLITE_DYNAMIC ((sqlite3_destructor_type)sqlite3OomClear) /* ** When SQLITE_OMIT_WSD is defined, it means that the target platform does@@ -14907,6 +14639,7 @@ typedef struct Lookaside Lookaside;
typedef struct LookasideSlot LookasideSlot; typedef struct Module Module; typedef struct NameContext NameContext; +typedef struct OnOrUsing OnOrUsing; typedef struct Parse Parse; typedef struct ParseCleanup ParseCleanup; typedef struct PreUpdate PreUpdate;@@ -14959,10 +14692,11 @@
/* ** A bit in a Bitmask */ -#define MASKBIT(n) (((Bitmask)1)<<(n)) -#define MASKBIT64(n) (((u64)1)<<(n)) -#define MASKBIT32(n) (((unsigned int)1)<<(n)) -#define ALLBITS ((Bitmask)-1) +#define MASKBIT(n) (((Bitmask)1)<<(n)) +#define MASKBIT64(n) (((u64)1)<<(n)) +#define MASKBIT32(n) (((unsigned int)1)<<(n)) +#define SMASKBIT32(n) ((n)<=31?((unsigned int)1)<<(n):0) +#define ALLBITS ((Bitmask)-1) /* A VList object records a mapping between parameters/variables/wildcards ** in the SQL statement (such as $abc, @pqr, or :xyz) and the integer@@ -15024,14 +14758,15 @@ */
typedef struct PgHdr DbPage; /* -** Page number PAGER_MJ_PGNO is never used in an SQLite database (it is +** Page number PAGER_SJ_PGNO is never used in an SQLite database (it is ** reserved for working around a windows/posix incompatibility). It is ** used in the journal to signify that the remainder of the journal file ** is devoted to storing a super-journal name - there are no more pages to ** roll back. See comments for function writeSuperJournal() in pager.c ** for details. */ -#define PAGER_MJ_PGNO(x) ((Pgno)((PENDING_BYTE/((x)->pageSize))+1)) +#define PAGER_SJ_PGNO_COMPUTED(x) ((Pgno)((PENDING_BYTE/((x)->pageSize))+1)) +#define PAGER_SJ_PGNO(x) ((x)->lckPgno) /* ** Allowed values for the flags parameter to sqlite3PagerOpen().@@ -15351,7 +15086,7 @@ #define BTREE_INTKEY 1 /* Table has only 64-bit signed integer keys */
#define BTREE_BLOBKEY 2 /* Table has keys only - no data */ SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree*, int, int*); -SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree*, int, int*); +SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree*, int, i64*); SQLITE_PRIVATE int sqlite3BtreeClearTableOfCursor(BtCursor*); SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree*, int, int);@@ -15475,11 +15210,15 @@ SQLITE_PRIVATE void sqlite3BtreeCursorHint(BtCursor*, int, ...);
#endif SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor*); -SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( +SQLITE_PRIVATE int sqlite3BtreeTableMoveto( BtCursor*, - UnpackedRecord *pUnKey, i64 intKey, int bias, + int *pRes +); +SQLITE_PRIVATE int sqlite3BtreeIndexMoveto( + BtCursor*, + UnpackedRecord *pUnKey, int *pRes ); SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor*);@@ -15704,7 +15443,6 @@ Table *pTab; /* Used when p4type is P4_TABLE */
#ifdef SQLITE_ENABLE_CURSOR_HINTS Expr *pExpr; /* Used when p4type is P4_EXPR */ #endif - int (*xAdvance)(BtCursor *, int); } p4; #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS char *zComment; /* Comment to improve readability */@@ -15755,21 +15493,19 @@ #define P4_STATIC (-1) /* Pointer to a static string */
#define P4_COLLSEQ (-2) /* P4 is a pointer to a CollSeq structure */ #define P4_INT32 (-3) /* P4 is a 32-bit signed integer */ #define P4_SUBPROGRAM (-4) /* P4 is a pointer to a SubProgram structure */ -#define P4_ADVANCE (-5) /* P4 is a pointer to BtreeNext() or BtreePrev() */ -#define P4_TABLE (-6) /* P4 is a pointer to a Table structure */ +#define P4_TABLE (-5) /* P4 is a pointer to a Table structure */ /* Above do not own any resources. Must free those below */ -#define P4_FREE_IF_LE (-7) -#define P4_DYNAMIC (-7) /* Pointer to memory from sqliteMalloc() */ -#define P4_FUNCDEF (-8) /* P4 is a pointer to a FuncDef structure */ -#define P4_KEYINFO (-9) /* P4 is a pointer to a KeyInfo structure */ -#define P4_EXPR (-10) /* P4 is a pointer to an Expr tree */ -#define P4_MEM (-11) /* P4 is a pointer to a Mem* structure */ -#define P4_VTAB (-12) /* P4 is a pointer to an sqlite3_vtab structure */ -#define P4_REAL (-13) /* P4 is a 64-bit floating point value */ -#define P4_INT64 (-14) /* P4 is a 64-bit signed integer */ -#define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */ -#define P4_FUNCCTX (-16) /* P4 is a pointer to an sqlite3_context object */ -#define P4_DYNBLOB (-17) /* Pointer to memory from sqliteMalloc() */ +#define P4_FREE_IF_LE (-6) +#define P4_DYNAMIC (-6) /* Pointer to memory from sqliteMalloc() */ +#define P4_FUNCDEF (-7) /* P4 is a pointer to a FuncDef structure */ +#define P4_KEYINFO (-8) /* P4 is a pointer to a KeyInfo structure */ +#define P4_EXPR (-9) /* P4 is a pointer to an Expr tree */ +#define P4_MEM (-10) /* P4 is a pointer to a Mem* structure */ +#define P4_VTAB (-11) /* P4 is a pointer to an sqlite3_vtab structure */ +#define P4_REAL (-12) /* P4 is a 64-bit floating point value */ +#define P4_INT64 (-13) /* P4 is a 64-bit signed integer */ +#define P4_INTARRAY (-14) /* P4 is a vector of 32-bit integers */ +#define P4_FUNCCTX (-15) /* P4 is a pointer to an sqlite3_context object */ /* Error message codes for OP_Halt */ #define P5_ConstraintNotNull 1@@ -15814,53 +15550,53 @@ /* See the tool/mkopcodeh.tcl script for details */
#define OP_Savepoint 0 #define OP_AutoCommit 1 #define OP_Transaction 2 -#define OP_SorterNext 3 /* jump */ -#define OP_Prev 4 /* jump */ -#define OP_Next 5 /* jump */ -#define OP_Checkpoint 6 -#define OP_JournalMode 7 -#define OP_Vacuum 8 -#define OP_VFilter 9 /* jump, synopsis: iplan=r[P3] zplan='P4' */ -#define OP_VUpdate 10 /* synopsis: data=r[P3@P2] */ -#define OP_Goto 11 /* jump */ -#define OP_Gosub 12 /* jump */ -#define OP_InitCoroutine 13 /* jump */ -#define OP_Yield 14 /* jump */ -#define OP_MustBeInt 15 /* jump */ -#define OP_Jump 16 /* jump */ -#define OP_Once 17 /* jump */ -#define OP_If 18 /* jump */ +#define OP_Checkpoint 3 +#define OP_JournalMode 4 +#define OP_Vacuum 5 +#define OP_VFilter 6 /* jump, synopsis: iplan=r[P3] zplan='P4' */ +#define OP_VUpdate 7 /* synopsis: data=r[P3@P2] */ +#define OP_Goto 8 /* jump */ +#define OP_Gosub 9 /* jump */ +#define OP_InitCoroutine 10 /* jump */ +#define OP_Yield 11 /* jump */ +#define OP_MustBeInt 12 /* jump */ +#define OP_Jump 13 /* jump */ +#define OP_Once 14 /* jump */ +#define OP_If 15 /* jump */ +#define OP_IfNot 16 /* jump */ +#define OP_IsNullOrType 17 /* jump, synopsis: if typeof(r[P1]) IN (P3,5) goto P2 */ +#define OP_IfNullRow 18 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */ #define OP_Not 19 /* same as TK_NOT, synopsis: r[P2]= !r[P1] */ -#define OP_IfNot 20 /* jump */ -#define OP_IfNullRow 21 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */ -#define OP_SeekLT 22 /* jump, synopsis: key=r[P3@P4] */ -#define OP_SeekLE 23 /* jump, synopsis: key=r[P3@P4] */ -#define OP_SeekGE 24 /* jump, synopsis: key=r[P3@P4] */ -#define OP_SeekGT 25 /* jump, synopsis: key=r[P3@P4] */ -#define OP_IfNotOpen 26 /* jump, synopsis: if( !csr[P1] ) goto P2 */ -#define OP_IfNoHope 27 /* jump, synopsis: key=r[P3@P4] */ -#define OP_NoConflict 28 /* jump, synopsis: key=r[P3@P4] */ -#define OP_NotFound 29 /* jump, synopsis: key=r[P3@P4] */ -#define OP_Found 30 /* jump, synopsis: key=r[P3@P4] */ -#define OP_SeekRowid 31 /* jump, synopsis: intkey=r[P3] */ -#define OP_NotExists 32 /* jump, synopsis: intkey=r[P3] */ -#define OP_Last 33 /* jump */ -#define OP_IfSmaller 34 /* jump */ -#define OP_SorterSort 35 /* jump */ -#define OP_Sort 36 /* jump */ -#define OP_Rewind 37 /* jump */ -#define OP_IdxLE 38 /* jump, synopsis: key=r[P3@P4] */ -#define OP_IdxGT 39 /* jump, synopsis: key=r[P3@P4] */ -#define OP_IdxLT 40 /* jump, synopsis: key=r[P3@P4] */ -#define OP_IdxGE 41 /* jump, synopsis: key=r[P3@P4] */ -#define OP_RowSetRead 42 /* jump, synopsis: r[P3]=rowset(P1) */ +#define OP_SeekLT 20 /* jump, synopsis: key=r[P3@P4] */ +#define OP_SeekLE 21 /* jump, synopsis: key=r[P3@P4] */ +#define OP_SeekGE 22 /* jump, synopsis: key=r[P3@P4] */ +#define OP_SeekGT 23 /* jump, synopsis: key=r[P3@P4] */ +#define OP_IfNotOpen 24 /* jump, synopsis: if( !csr[P1] ) goto P2 */ +#define OP_IfNoHope 25 /* jump, synopsis: key=r[P3@P4] */ +#define OP_NoConflict 26 /* jump, synopsis: key=r[P3@P4] */ +#define OP_NotFound 27 /* jump, synopsis: key=r[P3@P4] */ +#define OP_Found 28 /* jump, synopsis: key=r[P3@P4] */ +#define OP_SeekRowid 29 /* jump, synopsis: intkey=r[P3] */ +#define OP_NotExists 30 /* jump, synopsis: intkey=r[P3] */ +#define OP_Last 31 /* jump */ +#define OP_IfSmaller 32 /* jump */ +#define OP_SorterSort 33 /* jump */ +#define OP_Sort 34 /* jump */ +#define OP_Rewind 35 /* jump */ +#define OP_SorterNext 36 /* jump */ +#define OP_Prev 37 /* jump */ +#define OP_Next 38 /* jump */ +#define OP_IdxLE 39 /* jump, synopsis: key=r[P3@P4] */ +#define OP_IdxGT 40 /* jump, synopsis: key=r[P3@P4] */ +#define OP_IdxLT 41 /* jump, synopsis: key=r[P3@P4] */ +#define OP_IdxGE 42 /* jump, synopsis: key=r[P3@P4] */ #define OP_Or 43 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */ #define OP_And 44 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */ -#define OP_RowSetTest 45 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */ -#define OP_Program 46 /* jump */ -#define OP_FkIfZero 47 /* jump, synopsis: if fkctr[P1]==0 goto P2 */ -#define OP_IfPos 48 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */ -#define OP_IfNotZero 49 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */ +#define OP_RowSetRead 45 /* jump, synopsis: r[P3]=rowset(P1) */ +#define OP_RowSetTest 46 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */ +#define OP_Program 47 /* jump */ +#define OP_FkIfZero 48 /* jump, synopsis: if fkctr[P1]==0 goto P2 */ +#define OP_IfPos 49 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */ #define OP_IsNull 50 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */ #define OP_NotNull 51 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */ #define OP_Ne 52 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */@@ -15870,49 +15606,49 @@ #define OP_Le 55 /* jump, same as TK_LE, synopsis: IF r[P3]<=r[P1] */
#define OP_Lt 56 /* jump, same as TK_LT, synopsis: IF r[P3]<r[P1] */ #define OP_Ge 57 /* jump, same as TK_GE, synopsis: IF r[P3]>=r[P1] */ #define OP_ElseEq 58 /* jump, same as TK_ESCAPE */ -#define OP_DecrJumpZero 59 /* jump, synopsis: if (--r[P1])==0 goto P2 */ -#define OP_IncrVacuum 60 /* jump */ -#define OP_VNext 61 /* jump */ -#define OP_Init 62 /* jump, synopsis: Start at P2 */ -#define OP_PureFunc 63 /* synopsis: r[P3]=func(r[P2@NP]) */ -#define OP_Function 64 /* synopsis: r[P3]=func(r[P2@NP]) */ -#define OP_Return 65 -#define OP_EndCoroutine 66 -#define OP_HaltIfNull 67 /* synopsis: if r[P3]=null halt */ -#define OP_Halt 68 -#define OP_Integer 69 /* synopsis: r[P2]=P1 */ -#define OP_Int64 70 /* synopsis: r[P2]=P4 */ -#define OP_String 71 /* synopsis: r[P2]='P4' (len=P1) */ -#define OP_Null 72 /* synopsis: r[P2..P3]=NULL */ -#define OP_SoftNull 73 /* synopsis: r[P1]=NULL */ -#define OP_Blob 74 /* synopsis: r[P2]=P4 (len=P1) */ -#define OP_Variable 75 /* synopsis: r[P2]=parameter(P1,P4) */ -#define OP_Move 76 /* synopsis: r[P2@P3]=r[P1@P3] */ -#define OP_Copy 77 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */ -#define OP_SCopy 78 /* synopsis: r[P2]=r[P1] */ -#define OP_IntCopy 79 /* synopsis: r[P2]=r[P1] */ -#define OP_ChngCntRow 80 /* synopsis: output=r[P1] */ -#define OP_ResultRow 81 /* synopsis: output=r[P1@P2] */ -#define OP_CollSeq 82 -#define OP_AddImm 83 /* synopsis: r[P1]=r[P1]+P2 */ -#define OP_RealAffinity 84 -#define OP_Cast 85 /* synopsis: affinity(r[P1]) */ -#define OP_Permutation 86 -#define OP_Compare 87 /* synopsis: r[P1@P3] <-> r[P2@P3] */ -#define OP_IsTrue 88 /* synopsis: r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4 */ -#define OP_ZeroOrNull 89 /* synopsis: r[P2] = 0 OR NULL */ -#define OP_Offset 90 /* synopsis: r[P3] = sqlite_offset(P1) */ -#define OP_Column 91 /* synopsis: r[P3]=PX */ -#define OP_Affinity 92 /* synopsis: affinity(r[P1@P2]) */ -#define OP_MakeRecord 93 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ -#define OP_Count 94 /* synopsis: r[P2]=count() */ -#define OP_ReadCookie 95 -#define OP_SetCookie 96 -#define OP_ReopenIdx 97 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenRead 98 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenWrite 99 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenDup 100 -#define OP_OpenAutoindex 101 /* synopsis: nColumn=P2 */ +#define OP_IfNotZero 59 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */ +#define OP_DecrJumpZero 60 /* jump, synopsis: if (--r[P1])==0 goto P2 */ +#define OP_IncrVacuum 61 /* jump */ +#define OP_VNext 62 /* jump */ +#define OP_Filter 63 /* jump, synopsis: if key(P3@P4) not in filter(P1) goto P2 */ +#define OP_Init 64 /* jump, synopsis: Start at P2 */ +#define OP_PureFunc 65 /* synopsis: r[P3]=func(r[P2@NP]) */ +#define OP_Function 66 /* synopsis: r[P3]=func(r[P2@NP]) */ +#define OP_Return 67 +#define OP_EndCoroutine 68 +#define OP_HaltIfNull 69 /* synopsis: if r[P3]=null halt */ +#define OP_Halt 70 +#define OP_Integer 71 /* synopsis: r[P2]=P1 */ +#define OP_Int64 72 /* synopsis: r[P2]=P4 */ +#define OP_String 73 /* synopsis: r[P2]='P4' (len=P1) */ +#define OP_BeginSubrtn 74 /* synopsis: r[P2]=NULL */ +#define OP_Null 75 /* synopsis: r[P2..P3]=NULL */ +#define OP_SoftNull 76 /* synopsis: r[P1]=NULL */ +#define OP_Blob 77 /* synopsis: r[P2]=P4 (len=P1) */ +#define OP_Variable 78 /* synopsis: r[P2]=parameter(P1,P4) */ +#define OP_Move 79 /* synopsis: r[P2@P3]=r[P1@P3] */ +#define OP_Copy 80 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */ +#define OP_SCopy 81 /* synopsis: r[P2]=r[P1] */ +#define OP_IntCopy 82 /* synopsis: r[P2]=r[P1] */ +#define OP_FkCheck 83 +#define OP_ResultRow 84 /* synopsis: output=r[P1@P2] */ +#define OP_CollSeq 85 +#define OP_AddImm 86 /* synopsis: r[P1]=r[P1]+P2 */ +#define OP_RealAffinity 87 +#define OP_Cast 88 /* synopsis: affinity(r[P1]) */ +#define OP_Permutation 89 +#define OP_Compare 90 /* synopsis: r[P1@P3] <-> r[P2@P3] */ +#define OP_IsTrue 91 /* synopsis: r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4 */ +#define OP_ZeroOrNull 92 /* synopsis: r[P2] = 0 OR NULL */ +#define OP_Offset 93 /* synopsis: r[P3] = sqlite_offset(P1) */ +#define OP_Column 94 /* synopsis: r[P3]=PX cursor P1 column P2 */ +#define OP_TypeCheck 95 /* synopsis: typecheck(r[P1@P2]) */ +#define OP_Affinity 96 /* synopsis: affinity(r[P1@P2]) */ +#define OP_MakeRecord 97 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ +#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_BitAnd 102 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */ #define OP_BitOr 103 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */ #define OP_ShiftLeft 104 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<<r[P1] */@@ -15923,74 +15659,81 @@ #define OP_Multiply 108 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */
#define OP_Divide 109 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */ #define OP_Remainder 110 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */ #define OP_Concat 111 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */ -#define OP_OpenEphemeral 112 /* synopsis: nColumn=P2 */ -#define OP_BitNot 113 /* same as TK_BITNOT, synopsis: r[P2]= ~r[P1] */ -#define OP_SorterOpen 114 -#define OP_SequenceTest 115 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */ -#define OP_String8 116 /* same as TK_STRING, synopsis: r[P2]='P4' */ -#define OP_OpenPseudo 117 /* synopsis: P3 columns in r[P2] */ -#define OP_Close 118 -#define OP_ColumnsUsed 119 -#define OP_SeekScan 120 /* synopsis: Scan-ahead up to P1 rows */ -#define OP_SeekHit 121 /* synopsis: set P2<=seekHit<=P3 */ -#define OP_Sequence 122 /* synopsis: r[P2]=cursor[P1].ctr++ */ -#define OP_NewRowid 123 /* synopsis: r[P2]=rowid */ -#define OP_Insert 124 /* synopsis: intkey=r[P3] data=r[P2] */ -#define OP_RowCell 125 -#define OP_Delete 126 -#define OP_ResetCount 127 -#define OP_SorterCompare 128 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */ -#define OP_SorterData 129 /* synopsis: r[P2]=data */ -#define OP_RowData 130 /* synopsis: r[P2]=data */ -#define OP_Rowid 131 /* synopsis: r[P2]=rowid */ -#define OP_NullRow 132 -#define OP_SeekEnd 133 -#define OP_IdxInsert 134 /* synopsis: key=r[P2] */ -#define OP_SorterInsert 135 /* synopsis: key=r[P2] */ -#define OP_IdxDelete 136 /* synopsis: key=r[P2@P3] */ -#define OP_DeferredSeek 137 /* synopsis: Move P3 to P1.rowid if needed */ -#define OP_IdxRowid 138 /* synopsis: r[P2]=rowid */ -#define OP_FinishSeek 139 -#define OP_Destroy 140 -#define OP_Clear 141 -#define OP_ResetSorter 142 -#define OP_CreateBtree 143 /* synopsis: r[P2]=root iDb=P1 flags=P3 */ -#define OP_SqlExec 144 -#define OP_ParseSchema 145 -#define OP_LoadAnalysis 146 -#define OP_DropTable 147 -#define OP_DropIndex 148 -#define OP_DropTrigger 149 -#define OP_IntegrityCk 150 -#define OP_RowSetAdd 151 /* synopsis: rowset(P1)=r[P2] */ -#define OP_Real 152 /* same as TK_FLOAT, synopsis: r[P2]=P4 */ -#define OP_Param 153 -#define OP_FkCounter 154 /* synopsis: fkctr[P1]+=P2 */ -#define OP_MemMax 155 /* synopsis: r[P1]=max(r[P1],r[P2]) */ -#define OP_OffsetLimit 156 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */ -#define OP_AggInverse 157 /* synopsis: accum=r[P3] inverse(r[P2@P5]) */ -#define OP_AggStep 158 /* synopsis: accum=r[P3] step(r[P2@P5]) */ -#define OP_AggStep1 159 /* synopsis: accum=r[P3] step(r[P2@P5]) */ -#define OP_AggValue 160 /* synopsis: r[P3]=value N=P2 */ -#define OP_AggFinal 161 /* synopsis: accum=r[P1] N=P2 */ -#define OP_Expire 162 -#define OP_CursorLock 163 -#define OP_CursorUnlock 164 -#define OP_TableLock 165 /* synopsis: iDb=P1 root=P2 write=P3 */ -#define OP_VBegin 166 -#define OP_VCreate 167 -#define OP_VDestroy 168 -#define OP_VOpen 169 -#define OP_VColumn 170 /* synopsis: r[P3]=vcolumn(P2) */ -#define OP_VRename 171 -#define OP_Pagecount 172 -#define OP_MaxPgcnt 173 -#define OP_Trace 174 -#define OP_CursorHint 175 -#define OP_ReleaseReg 176 /* synopsis: release r[P1@P2] mask P3 */ -#define OP_Noop 177 -#define OP_Explain 178 -#define OP_Abortable 179 +#define OP_OpenRead 112 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenWrite 113 /* synopsis: root=P2 iDb=P3 */ +#define OP_BitNot 114 /* same as TK_BITNOT, synopsis: r[P2]= ~r[P1] */ +#define OP_OpenDup 115 +#define OP_OpenAutoindex 116 /* synopsis: nColumn=P2 */ +#define OP_String8 117 /* same as TK_STRING, synopsis: r[P2]='P4' */ +#define OP_OpenEphemeral 118 /* synopsis: nColumn=P2 */ +#define OP_SorterOpen 119 +#define OP_SequenceTest 120 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */ +#define OP_OpenPseudo 121 /* synopsis: P3 columns in r[P2] */ +#define OP_Close 122 +#define OP_ColumnsUsed 123 +#define OP_SeekScan 124 /* synopsis: Scan-ahead up to P1 rows */ +#define OP_SeekHit 125 /* synopsis: set P2<=seekHit<=P3 */ +#define OP_Sequence 126 /* synopsis: r[P2]=cursor[P1].ctr++ */ +#define OP_NewRowid 127 /* synopsis: r[P2]=rowid */ +#define OP_Insert 128 /* synopsis: intkey=r[P3] data=r[P2] */ +#define OP_RowCell 129 +#define OP_Delete 130 +#define OP_ResetCount 131 +#define OP_SorterCompare 132 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */ +#define OP_SorterData 133 /* synopsis: r[P2]=data */ +#define OP_RowData 134 /* synopsis: r[P2]=data */ +#define OP_Rowid 135 /* synopsis: r[P2]=PX rowid of P1 */ +#define OP_NullRow 136 +#define OP_SeekEnd 137 +#define OP_IdxInsert 138 /* synopsis: key=r[P2] */ +#define OP_SorterInsert 139 /* synopsis: key=r[P2] */ +#define OP_IdxDelete 140 /* synopsis: key=r[P2@P3] */ +#define OP_DeferredSeek 141 /* synopsis: Move P3 to P1.rowid if needed */ +#define OP_IdxRowid 142 /* synopsis: r[P2]=rowid */ +#define OP_FinishSeek 143 +#define OP_Destroy 144 +#define OP_Clear 145 +#define OP_ResetSorter 146 +#define OP_CreateBtree 147 /* synopsis: r[P2]=root iDb=P1 flags=P3 */ +#define OP_SqlExec 148 +#define OP_ParseSchema 149 +#define OP_LoadAnalysis 150 +#define OP_DropTable 151 +#define OP_DropIndex 152 +#define OP_Real 153 /* same as TK_FLOAT, synopsis: r[P2]=P4 */ +#define OP_DropTrigger 154 +#define OP_IntegrityCk 155 +#define OP_RowSetAdd 156 /* synopsis: rowset(P1)=r[P2] */ +#define OP_Param 157 +#define OP_FkCounter 158 /* synopsis: fkctr[P1]+=P2 */ +#define OP_MemMax 159 /* synopsis: r[P1]=max(r[P1],r[P2]) */ +#define OP_OffsetLimit 160 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */ +#define OP_AggInverse 161 /* synopsis: accum=r[P3] inverse(r[P2@P5]) */ +#define OP_AggStep 162 /* synopsis: accum=r[P3] step(r[P2@P5]) */ +#define OP_AggStep1 163 /* synopsis: accum=r[P3] step(r[P2@P5]) */ +#define OP_AggValue 164 /* synopsis: r[P3]=value N=P2 */ +#define OP_AggFinal 165 /* synopsis: accum=r[P1] N=P2 */ +#define OP_Expire 166 +#define OP_CursorLock 167 +#define OP_CursorUnlock 168 +#define OP_TableLock 169 /* synopsis: iDb=P1 root=P2 write=P3 */ +#define OP_VBegin 170 +#define OP_VCreate 171 +#define OP_VDestroy 172 +#define OP_VOpen 173 +#define OP_VInitIn 174 /* synopsis: r[P2]=ValueList(P1,P3) */ +#define OP_VColumn 175 /* synopsis: r[P3]=vcolumn(P2) */ +#define OP_VRename 176 +#define OP_Pagecount 177 +#define OP_MaxPgcnt 178 +#define OP_ClrSubtype 179 /* synopsis: r[P1].subtype = 0 */ +#define OP_FilterAdd 180 /* synopsis: filter(P1) += key(P3@P4) */ +#define OP_Trace 181 +#define OP_CursorHint 182 +#define OP_ReleaseReg 183 /* synopsis: release r[P1@P2] mask P3 */ +#define OP_Noop 184 +#define OP_Explain 185 +#define OP_Abortable 186 /* Properties such as "out2" or "jump" that are specified in ** comments following the "case" for each opcode in the vdbe.c@@ -16003,29 +15746,30 @@ #define OPFLG_IN3 0x08 /* in3: P3 is an input */
#define OPFLG_OUT2 0x10 /* out2: P2 is an output */ #define OPFLG_OUT3 0x20 /* out3: P3 is an output */ #define OPFLG_INITIALIZER {\ -/* 0 */ 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x10,\ -/* 8 */ 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x03, 0x03,\ -/* 16 */ 0x01, 0x01, 0x03, 0x12, 0x03, 0x01, 0x09, 0x09,\ -/* 24 */ 0x09, 0x09, 0x01, 0x09, 0x09, 0x09, 0x09, 0x09,\ -/* 32 */ 0x09, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\ -/* 40 */ 0x01, 0x01, 0x23, 0x26, 0x26, 0x0b, 0x01, 0x01,\ -/* 48 */ 0x03, 0x03, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\ -/* 56 */ 0x0b, 0x0b, 0x01, 0x03, 0x01, 0x01, 0x01, 0x00,\ -/* 64 */ 0x00, 0x02, 0x02, 0x08, 0x00, 0x10, 0x10, 0x10,\ -/* 72 */ 0x10, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10,\ -/* 80 */ 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00,\ -/* 88 */ 0x12, 0x1e, 0x20, 0x00, 0x00, 0x00, 0x10, 0x10,\ -/* 96 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x26,\ +/* 0 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,\ +/* 8 */ 0x01, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01, 0x03,\ +/* 16 */ 0x03, 0x03, 0x01, 0x12, 0x09, 0x09, 0x09, 0x09,\ +/* 24 */ 0x01, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x01,\ +/* 32 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\ +/* 40 */ 0x01, 0x01, 0x01, 0x26, 0x26, 0x23, 0x0b, 0x01,\ +/* 48 */ 0x01, 0x03, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\ +/* 56 */ 0x0b, 0x0b, 0x01, 0x03, 0x03, 0x01, 0x01, 0x01,\ +/* 64 */ 0x01, 0x00, 0x00, 0x02, 0x02, 0x08, 0x00, 0x10,\ +/* 72 */ 0x10, 0x10, 0x00, 0x10, 0x00, 0x10, 0x10, 0x00,\ +/* 80 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x02, 0x02,\ +/* 88 */ 0x02, 0x00, 0x00, 0x12, 0x1e, 0x20, 0x00, 0x00,\ +/* 96 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x26, 0x26,\ /* 104 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,\ -/* 112 */ 0x00, 0x12, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\ -/* 120 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,\ -/* 128 */ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x04, 0x04,\ -/* 136 */ 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x10,\ -/* 144 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,\ -/* 152 */ 0x10, 0x10, 0x00, 0x04, 0x1a, 0x00, 0x00, 0x00,\ -/* 160 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ -/* 168 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\ -/* 176 */ 0x00, 0x00, 0x00, 0x00,} +/* 112 */ 0x00, 0x00, 0x12, 0x00, 0x00, 0x10, 0x00, 0x00,\ +/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10,\ +/* 128 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\ +/* 136 */ 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x10, 0x00,\ +/* 144 */ 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,\ +/* 152 */ 0x00, 0x10, 0x00, 0x00, 0x06, 0x10, 0x00, 0x04,\ +/* 160 */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,\ +/* 176 */ 0x00, 0x10, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00,\ +/* 184 */ 0x00, 0x00, 0x00,} /* The resolve3P2Values() routine is able to run faster if it knows ** the value of the largest JUMP opcode. The smaller the maximum@@ -16033,7 +15777,7 @@ ** 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 62 /* Maximum JUMP opcode */ +#define SQLITE_MX_JUMP_OPCODE 64 /* Maximum JUMP opcode */ /************** End of opcodes.h *********************************************/ /************** Continuing where we left off in vdbe.h ***********************/@@ -16071,8 +15815,10 @@ # define sqlite3VdbeVerifyNoResultRow(A)
#endif #if defined(SQLITE_DEBUG) SQLITE_PRIVATE void sqlite3VdbeVerifyAbortable(Vdbe *p, int); +SQLITE_PRIVATE void sqlite3VdbeNoJumpsOutsideSubrtn(Vdbe*,int,int,int); #else # define sqlite3VdbeVerifyAbortable(A,B) +# define sqlite3VdbeNoJumpsOutsideSubrtn(A,B,C,D) #endif SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp,int iLineno); #ifndef SQLITE_OMIT_EXPLAIN@@ -16117,7 +15863,6 @@ SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Parse*);
SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeReusable(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe*); -SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3*,Vdbe*); SQLITE_PRIVATE void sqlite3VdbeMakeReady(Vdbe*,Parse*); SQLITE_PRIVATE int sqlite3VdbeFinalize(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe*, int);@@ -16566,6 +16311,13 @@ #ifndef SQLITE_MAX_PATHLEN
# define SQLITE_MAX_PATHLEN FILENAME_MAX #endif +/* Maximum number of symlinks that will be resolved while trying to +** expand a filename in xFullPathname() in the VFS. +*/ +#ifndef SQLITE_MAX_SYMLINK +# define SQLITE_MAX_SYMLINK 200 +#endif + /* ** The default size of a disk sector */@@ -17094,6 +16846,7 @@ i64 szMmap; /* Default mmap_size setting */
u32 nSchemaLock; /* Do not reset the schema when non-zero */ unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */ int errCode; /* Most recent error code (SQLITE_*) */ + int errByteOffset; /* Byte offset of error in SQL statement */ int errMask; /* & result codes with this before returning */ int iSysErrno; /* Errno value from last system error */ u32 dbOptFlags; /* Flags to enable/disable optimizations */@@ -17110,10 +16863,10 @@ u8 isTransactionSavepoint; /* True if the outermost savepoint is a TS */
u8 mTrace; /* zero or more SQLITE_TRACE flags */ u8 noSharedCache; /* True if no shared-cache backends */ u8 nSqlExec; /* Number of pending OP_SqlExec opcodes */ + u8 eOpenState; /* Current condition of the connection */ 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() */ + i64 nChange; /* Value returned by sqlite3_changes() */ + i64 nTotalChange; /* Value returned by sqlite3_total_changes() */ int aLimit[SQLITE_N_LIMIT]; /* Limits */ int nMaxSorterMmap; /* Maximum size of regions mapped by sorter */ struct sqlite3InitInfo { /* Information used during initialization */@@ -17123,7 +16876,7 @@ u8 busy; /* TRUE if currently initializing */
unsigned orphanTrigger : 1; /* Last statement is orphaned TEMP trigger */ unsigned imposterTable : 1; /* Building an imposter table */ unsigned reopenMemdb : 1; /* ATTACH is really a reopen using MemDB */ - char **azInit; /* "type", "name", and "tbl_name" columns */ + const char **azInit; /* "type", "name", and "tbl_name" columns */ } init; int nVdbeActive; /* Number of VDBEs currently running */ int nVdbeRead; /* Number of active VDBEs that read or write */@@ -17133,10 +16886,10 @@ int nVDestroy; /* Number of active OP_VDestroy operations */
int nExtension; /* Number of loaded extensions */ void **aExtension; /* Array of shared library handles */ union { - void (*xLegacy)(void*,const char*); /* Legacy trace function */ - int (*xV2)(u32,void*,void*,void*); /* V2 Trace function */ + void (*xLegacy)(void*,const char*); /* mTrace==SQLITE_TRACE_LEGACY */ + int (*xV2)(u32,void*,void*,void*); /* All other mTrace values */ } trace; - void *pTraceArg; /* Argument to the trace function */ + void *pTraceArg; /* Argument to the trace function */ #ifndef SQLITE_OMIT_DEPRECATED void (*xProfile)(void*,const char*,u64); /* Profiling function */ void *pProfileArg; /* Argument to profile function */@@ -17147,6 +16900,9 @@ void *pRollbackArg; /* Argument to xRollbackCallback() */
void (*xRollbackCallback)(void*); /* Invoked at every commit. */ void *pUpdateArg; void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64); + void *pAutovacPagesArg; /* Client argument to autovac_pages */ + void (*xAutovacDestr)(void*); /* Destructor for pAutovacPAgesArg */ + unsigned int (*xAutovacPages)(void*,const char*,u32,u32,u32); Parse *pParse; /* Current parse */ #ifdef SQLITE_ENABLE_PREUPDATE_HOOK void *pPreUpdateArg; /* First argument to xPreUpdateCallback */@@ -17276,6 +17032,7 @@ #define SQLITE_EnableView 0x80000000 /* Enable the use of views */
#define SQLITE_CountRows HI(0x00001) /* Count rows changed by INSERT, */ /* DELETE, or UPDATE and return */ /* the count using a callback. */ +#define SQLITE_CorruptRdOnly HI(0x00002) /* Prohibit writes due to error */ /* Flags used only if debugging */ #ifdef SQLITE_DEBUG@@ -17322,6 +17079,14 @@ #define SQLITE_SkipScan 0x00004000 /* Skip-scans */
#define SQLITE_PropagateConst 0x00008000 /* The constant propagation opt */ #define SQLITE_MinMaxOpt 0x00010000 /* The min/max optimization */ #define SQLITE_SeekScan 0x00020000 /* The OP_SeekScan optimization */ +#define SQLITE_OmitOrderBy 0x00040000 /* Omit pointless ORDER BY */ + /* TH3 expects this value ^^^^^^^^^^ to be 0x40000. Coordinate any change */ +#define SQLITE_BloomFilter 0x00080000 /* Use a Bloom filter on searches */ +#define SQLITE_BloomPulldown 0x00100000 /* Run Bloom filters early */ +#define SQLITE_BalancedMerge 0x00200000 /* Balance multi-way merges */ +#define SQLITE_ReleaseReg 0x00400000 /* Use OP_ReleaseReg for testing */ +#define SQLITE_FlttnUnionAll 0x00800000 /* Disable the UNION ALL flattener */ + /* TH3 expects this value ^^^^^^^^^^ See flatten04.test */ #define SQLITE_AllOpts 0xffffffff /* All optimizations */ /*@@ -17336,17 +17101,16 @@ ** code. The argument is a Parse object for the code generator.
*/ #define ConstFactorOk(P) ((P)->okConstFactor) -/* -** Possible values for the sqlite.magic field. -** The numbers are obtained at random and have no special meaning, other -** than being distinct from one another. +/* Possible values for the sqlite3.eOpenState field. +** The numbers are randomly selected such that a minimum of three bits must +** change to convert any number to another or to zero */ -#define SQLITE_MAGIC_OPEN 0xa029a697 /* Database is open */ -#define SQLITE_MAGIC_CLOSED 0x9f3c2d33 /* Database is closed */ -#define SQLITE_MAGIC_SICK 0x4b771290 /* Error and awaiting close */ -#define SQLITE_MAGIC_BUSY 0xf03b7906 /* Database currently in use */ -#define SQLITE_MAGIC_ERROR 0xb5357930 /* An SQLITE_MISUSE error occurred */ -#define SQLITE_MAGIC_ZOMBIE 0x64cffc7f /* Close with last statement close */ +#define SQLITE_STATE_OPEN 0x76 /* Database is open */ +#define SQLITE_STATE_CLOSED 0xce /* Database is closed */ +#define SQLITE_STATE_SICK 0xba /* Error and awaiting close */ +#define SQLITE_STATE_BUSY 0x6d /* Database currently in use */ +#define SQLITE_STATE_ERROR 0xd5 /* An SQLITE_MISUSE error occurred */ +#define SQLITE_STATE_ZOMBIE 0xa7 /* Close with last statement close */ /* ** Each SQL function is defined by an instance of the following@@ -17371,7 +17135,7 @@ const char *zName; /* SQL name of the function. */
union { FuncDef *pHash; /* Next with a different name but the same hash */ FuncDestructor *pDestructor; /* Reference counted destructor function */ - } u; + } u; /* pHash if SQLITE_FUNC_BUILTIN, pDestructor otherwise */ }; /*@@ -17401,12 +17165,13 @@ ** SQLITE_FUNC_CONSTANT must be the same as SQLITE_DETERMINISTIC. There
** are assert() statements in the code to verify this. ** ** Value constraints (enforced via assert()): -** SQLITE_FUNC_MINMAX == NC_MinMaxAgg == SF_MinMaxAgg -** SQLITE_FUNC_LENGTH == OPFLAG_LENGTHARG -** SQLITE_FUNC_TYPEOF == OPFLAG_TYPEOFARG -** SQLITE_FUNC_CONSTANT == SQLITE_DETERMINISTIC from the API -** SQLITE_FUNC_DIRECT == SQLITE_DIRECTONLY from the API -** SQLITE_FUNC_UNSAFE == SQLITE_INNOCUOUS +** SQLITE_FUNC_MINMAX == NC_MinMaxAgg == SF_MinMaxAgg +** SQLITE_FUNC_ANYORDER == NC_OrderAgg == SF_OrderByReqd +** SQLITE_FUNC_LENGTH == OPFLAG_LENGTHARG +** SQLITE_FUNC_TYPEOF == OPFLAG_TYPEOFARG +** SQLITE_FUNC_CONSTANT == SQLITE_DETERMINISTIC from the API +** SQLITE_FUNC_DIRECT == SQLITE_DIRECTONLY from the API +** SQLITE_FUNC_UNSAFE == SQLITE_INNOCUOUS ** SQLITE_FUNC_ENCMASK depends on SQLITE_UTF* macros in the API */ #define SQLITE_FUNC_ENCMASK 0x0003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */@@ -17424,13 +17189,15 @@ #define SQLITE_FUNC_MINMAX 0x1000 /* True for min() and max() aggregates */
#define SQLITE_FUNC_SLOCHNG 0x2000 /* "Slow Change". Value constant during a ** single query - might change over time */ #define SQLITE_FUNC_TEST 0x4000 /* Built-in testing functions */ -#define SQLITE_FUNC_OFFSET 0x8000 /* Built-in sqlite_offset() function */ +/* 0x8000 -- available for reuse */ #define SQLITE_FUNC_WINDOW 0x00010000 /* Built-in window-only function */ #define SQLITE_FUNC_INTERNAL 0x00040000 /* For use by NestedParse() only */ #define SQLITE_FUNC_DIRECT 0x00080000 /* Not for use in TRIGGERs or VIEWs */ #define SQLITE_FUNC_SUBTYPE 0x00100000 /* Result likely to have sub-type */ #define SQLITE_FUNC_UNSAFE 0x00200000 /* Function has side effects */ #define SQLITE_FUNC_INLINE 0x00400000 /* Functions implemented in-line */ +#define SQLITE_FUNC_BUILTIN 0x00800000 /* This is a built-in function */ +#define SQLITE_FUNC_ANYORDER 0x08000000 /* count/min/max aggregate */ /* Identifier numbers for each in-line function */ #define INLINEFUNC_coalesce 0@@ -17439,6 +17206,7 @@ #define INLINEFUNC_expr_implies_expr 2
#define INLINEFUNC_expr_compare 3 #define INLINEFUNC_affinity 4 #define INLINEFUNC_iif 5 +#define INLINEFUNC_sqlite_offset 6 #define INLINEFUNC_unlikely 99 /* Default case */ /*@@ -17493,7 +17261,7 @@ ** the C functions xStep and xFinal. The first four parameters
** are interpreted in the same way as the first 4 parameters to ** FUNCTION(). ** -** WFUNCTION(zName, nArg, iArg, xStep, xFinal, xValue, xInverse) +** WAGGREGATE(zName, nArg, iArg, xStep, xFinal, xValue, xInverse) ** Used to create an aggregate function definition implemented by ** the C functions xStep and xFinal. The first four parameters ** are interpreted in the same way as the first 4 parameters to@@ -17508,44 +17276,55 @@ ** FuncDef.flags variable is set to the value passed as the flags
** parameter. */ #define FUNCTION(zName, nArg, iArg, bNC, xFunc) \ - {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ + {nArg, SQLITE_FUNC_BUILTIN|\ + SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } #define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \ - {nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ + {nArg, SQLITE_FUNC_BUILTIN|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } #define SFUNCTION(zName, nArg, iArg, bNC, xFunc) \ - {nArg, SQLITE_UTF8|SQLITE_DIRECTONLY|SQLITE_FUNC_UNSAFE, \ + {nArg, SQLITE_FUNC_BUILTIN|SQLITE_UTF8|SQLITE_DIRECTONLY|SQLITE_FUNC_UNSAFE, \ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } #define MFUNCTION(zName, nArg, xPtr, xFunc) \ - {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \ + {nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \ xPtr, 0, xFunc, 0, 0, 0, #zName, {0} } +#define JFUNCTION(zName, nArg, iArg, xFunc) \ + {nArg, SQLITE_FUNC_BUILTIN|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS|\ + SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \ + SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } #define INLINE_FUNC(zName, nArg, iArg, mFlags) \ - {nArg, SQLITE_UTF8|SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \ + {nArg, SQLITE_FUNC_BUILTIN|\ + SQLITE_UTF8|SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \ SQLITE_INT_TO_PTR(iArg), 0, noopFunc, 0, 0, 0, #zName, {0} } #define TEST_FUNC(zName, nArg, iArg, mFlags) \ - {nArg, SQLITE_UTF8|SQLITE_FUNC_INTERNAL|SQLITE_FUNC_TEST| \ + {nArg, SQLITE_FUNC_BUILTIN|\ + SQLITE_UTF8|SQLITE_FUNC_INTERNAL|SQLITE_FUNC_TEST| \ SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \ SQLITE_INT_TO_PTR(iArg), 0, noopFunc, 0, 0, 0, #zName, {0} } #define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \ - {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8, \ + {nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_SLOCHNG|SQLITE_UTF8, \ 0, 0, xFunc, 0, 0, 0, #zName, {0} } #define PURE_DATE(zName, nArg, iArg, bNC, xFunc) \ - {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \ + {nArg, SQLITE_FUNC_BUILTIN|\ + SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \ (void*)&sqlite3Config, 0, xFunc, 0, 0, 0, #zName, {0} } #define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \ - {nArg,SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\ + {nArg, SQLITE_FUNC_BUILTIN|\ + SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } #define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \ - {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ + {nArg, SQLITE_FUNC_BUILTIN|\ + SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ pArg, 0, xFunc, 0, 0, 0, #zName, } #define LIKEFUNC(zName, nArg, arg, flags) \ - {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \ + {nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \ (void *)arg, 0, likeFunc, 0, 0, 0, #zName, {0} } #define WAGGREGATE(zName, nArg, arg, nc, xStep, xFinal, xValue, xInverse, f) \ - {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|f, \ + {nArg, SQLITE_FUNC_BUILTIN|SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|f, \ SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xValue,xInverse,#zName, {0}} #define INTERNAL_FUNCTION(zName, nArg, xFunc) \ - {nArg, SQLITE_FUNC_INTERNAL|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \ + {nArg, SQLITE_FUNC_BUILTIN|\ + SQLITE_FUNC_INTERNAL|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \ 0, 0, xFunc, 0, 0, 0, #zName, {0} }@@ -17601,18 +17380,42 @@ ** opcode. The storage column index is less than
** or equal to the table column index. It is ** equal if and only if there are no VIRTUAL ** columns to the left. +** +** Notes on zCnName: +** The zCnName field stores the name of the column, the datatype of the +** column, and the collating sequence for the column, in that order, all in +** a single allocation. Each string is 0x00 terminated. The datatype +** is only included if the COLFLAG_HASTYPE bit of colFlags is set and the +** collating sequence name is only included if the COLFLAG_HASCOLL bit is +** set. */ struct Column { - char *zName; /* Name of this column, \000, then the type */ - Expr *pDflt; /* Default value or GENERATED ALWAYS AS value */ - char *zColl; /* Collating sequence. If NULL, use the default */ - u8 notNull; /* An OE_ code for handling a NOT NULL constraint */ - char affinity; /* One of the SQLITE_AFF_... values */ - u8 szEst; /* Estimated size of value in this column. sizeof(INT)==1 */ - u8 hName; /* Column name hash for faster lookup */ - u16 colFlags; /* Boolean properties. See COLFLAG_ defines below */ + char *zCnName; /* Name of this column */ + unsigned notNull :4; /* An OE_ code for handling a NOT NULL constraint */ + unsigned eCType :4; /* One of the standard types */ + char affinity; /* One of the SQLITE_AFF_... values */ + u8 szEst; /* Est size of value in this column. sizeof(INT)==1 */ + u8 hName; /* Column name hash for faster lookup */ + u16 iDflt; /* 1-based index of DEFAULT. 0 means "none" */ + u16 colFlags; /* Boolean properties. See COLFLAG_ defines below */ }; +/* Allowed values for Column.eCType. +** +** Values must match entries in the global constant arrays +** sqlite3StdTypeLen[] and sqlite3StdType[]. Each value is one more +** than the offset into these arrays for the corresponding name. +** Adjust the SQLITE_N_STDTYPE value if adding or removing entries. +*/ +#define COLTYPE_CUSTOM 0 /* Type appended to zName */ +#define COLTYPE_ANY 1 +#define COLTYPE_BLOB 2 +#define COLTYPE_INT 3 +#define COLTYPE_INTEGER 4 +#define COLTYPE_REAL 5 +#define COLTYPE_TEXT 6 +#define SQLITE_N_STDTYPE 6 /* Number of standard types */ + /* Allowed values for Column.colFlags. ** ** Constraints:@@ -17629,6 +17432,8 @@ #define COLFLAG_VIRTUAL 0x0020 /* GENERATED ALWAYS AS ... VIRTUAL */
#define COLFLAG_STORED 0x0040 /* GENERATED ALWAYS AS ... STORED */ #define COLFLAG_NOTAVAIL 0x0080 /* STORED column not yet calculated */ #define COLFLAG_BUSY 0x0100 /* Blocks recursion on GENERATED columns */ +#define COLFLAG_HASCOLL 0x0200 /* Has collating sequence name in zCnName */ +#define COLFLAG_NOEXPAND 0x0400 /* Omit this column when expanding "*" */ #define COLFLAG_GENERATED 0x0060 /* Combo: _STORED, _VIRTUAL */ #define COLFLAG_NOINSERT 0x0062 /* Combo: _HIDDEN, _STORED, _VIRTUAL */@@ -17758,15 +17563,13 @@ #define SQLITE_VTABRISK_Normal 1
#define SQLITE_VTABRISK_High 2 /* -** The schema for each SQL table and view is represented in memory -** by an instance of the following structure. +** The schema for each SQL table, virtual table, and view is represented +** in memory by an instance of the following structure. */ struct Table { char *zName; /* Name of the table or view */ Column *aCol; /* Information about each column */ Index *pIndex; /* List of SQL indexes on this table. */ - Select *pSelect; /* NULL for tables. Points to definition if a view. */ - FKey *pFKey; /* Linked list of all foreign keys in this table */ char *zColAff; /* String defining the affinity of each column */ ExprList *pCheck; /* All CHECK constraints */ /* ... also used as column name list in a VIEW */@@ -17782,15 +17585,24 @@ #ifdef SQLITE_ENABLE_COSTMULT
LogEst costMult; /* Cost multiplier for using this table */ #endif u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */ -#ifndef SQLITE_OMIT_ALTERTABLE - int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */ -#endif -#ifndef SQLITE_OMIT_VIRTUALTABLE - int nModuleArg; /* Number of arguments to the module */ - char **azModuleArg; /* 0: module 1: schema 2: vtab name 3...: args */ - VTable *pVTable; /* List of VTable objects. */ -#endif - Trigger *pTrigger; /* List of triggers stored in pSchema */ + u8 eTabType; /* 0: normal, 1: virtual, 2: view */ + union { + struct { /* Used by ordinary tables: */ + int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */ + FKey *pFKey; /* Linked list of all foreign keys in this table */ + ExprList *pDfltList; /* DEFAULT clauses on various columns. + ** Or the AS clause for generated columns. */ + } tab; + struct { /* Used by views: */ + Select *pSelect; /* View definition */ + } view; + struct { /* Used by virtual tables only: */ + int nArg; /* Number of arguments to the module */ + char **azArg; /* 0: module 1: schema 2: vtab name 3...: args */ + VTable *p; /* List of VTable objects. */ + } vtab; + } u; + Trigger *pTrigger; /* List of triggers on this object */ Schema *pSchema; /* Schema that contains this table */ };@@ -17809,24 +17621,35 @@ ** TF_HasVirtual == COLFLAG_VIRTUAL
** TF_HasStored == COLFLAG_STORED ** TF_HasHidden == COLFLAG_HIDDEN */ -#define TF_Readonly 0x0001 /* Read-only system table */ -#define TF_HasHidden 0x0002 /* Has one or more hidden columns */ -#define TF_HasPrimaryKey 0x0004 /* Table has a primary key */ -#define TF_Autoincrement 0x0008 /* Integer primary key is autoincrement */ -#define TF_HasStat1 0x0010 /* nRowLogEst set from sqlite_stat1 */ -#define TF_HasVirtual 0x0020 /* Has one or more VIRTUAL columns */ -#define TF_HasStored 0x0040 /* Has one or more STORED columns */ -#define TF_HasGenerated 0x0060 /* Combo: HasVirtual + HasStored */ -#define TF_WithoutRowid 0x0080 /* No rowid. PRIMARY KEY is the key */ -#define TF_StatsUsed 0x0100 /* Query planner decisions affected by +#define TF_Readonly 0x00000001 /* Read-only system table */ +#define TF_HasHidden 0x00000002 /* Has one or more hidden columns */ +#define TF_HasPrimaryKey 0x00000004 /* Table has a primary key */ +#define TF_Autoincrement 0x00000008 /* Integer primary key is autoincrement */ +#define TF_HasStat1 0x00000010 /* nRowLogEst set from sqlite_stat1 */ +#define TF_HasVirtual 0x00000020 /* Has one or more VIRTUAL columns */ +#define TF_HasStored 0x00000040 /* Has one or more STORED columns */ +#define TF_HasGenerated 0x00000060 /* Combo: HasVirtual + HasStored */ +#define TF_WithoutRowid 0x00000080 /* No rowid. PRIMARY KEY is the key */ +#define TF_StatsUsed 0x00000100 /* Query planner decisions affected by ** Index.aiRowLogEst[] values */ -#define TF_NoVisibleRowid 0x0200 /* No user-visible "rowid" column */ -#define TF_OOOHidden 0x0400 /* Out-of-Order hidden columns */ -#define TF_HasNotNull 0x0800 /* Contains NOT NULL constraints */ -#define TF_Shadow 0x1000 /* True for a shadow table */ -#define TF_HasStat4 0x2000 /* STAT4 info available for this table */ -#define TF_Ephemeral 0x4000 /* An ephemeral table */ -#define TF_Eponymous 0x8000 /* An eponymous virtual table */ +#define TF_NoVisibleRowid 0x00000200 /* No user-visible "rowid" column */ +#define TF_OOOHidden 0x00000400 /* Out-of-Order hidden columns */ +#define TF_HasNotNull 0x00000800 /* Contains NOT NULL constraints */ +#define TF_Shadow 0x00001000 /* True for a shadow table */ +#define TF_HasStat4 0x00002000 /* STAT4 info available for this table */ +#define TF_Ephemeral 0x00004000 /* An ephemeral table */ +#define TF_Eponymous 0x00008000 /* An eponymous virtual table */ +#define TF_Strict 0x00010000 /* STRICT mode */ + +/* +** Allowed values for Table.eTabType +*/ +#define TABTYP_NORM 0 /* Ordinary table */ +#define TABTYP_VTAB 1 /* Virtual table */ +#define TABTYP_VIEW 2 /* A view */ + +#define IsView(X) ((X)->eTabType==TABTYP_VIEW) +#define IsOrdinaryTable(X) ((X)->eTabType==TABTYP_NORM) /* ** Test to see whether or not a table is a virtual table. This is@@ -17834,9 +17657,9 @@ ** done as a macro so that it will be optimized out when virtual
** table support is omitted from the build. */ #ifndef SQLITE_OMIT_VIRTUALTABLE -# define IsVirtual(X) ((X)->nModuleArg) +# define IsVirtual(X) ((X)->eTabType==TABTYP_VTAB) # define ExprIsVtab(X) \ - ((X)->op==TK_COLUMN && (X)->y.pTab!=0 && (X)->y.pTab->nModuleArg) + ((X)->op==TK_COLUMN && (X)->y.pTab!=0 && (X)->y.pTab->eTabType==TABTYP_VTAB) #else # define IsVirtual(X) 0 # define ExprIsVtab(X) 0@@ -18017,6 +17840,11 @@ */
struct UnpackedRecord { KeyInfo *pKeyInfo; /* Collation and sort-order information */ Mem *aMem; /* Values */ + union { + char *z; /* Cache of aMem[0].z for vdbeRecordCompareString() */ + i64 i; /* Cache of aMem[0].u.i for vdbeRecordCompareInt() */ + } u; + int n; /* Cache of aMem[0].n used by vdbeRecordCompareString() */ u16 nField; /* Number of entries in apMem[] */ i8 default_rc; /* Comparison result if keys are equal */ u8 errCode; /* Error detected by xRecordCompare (CORRUPT or NOMEM) */@@ -18225,10 +18053,10 @@ ** to represent the greater-than-or-equal-to operator in the expression
** tree. ** ** If the expression is an SQL literal (TK_INTEGER, TK_FLOAT, TK_BLOB, -** or TK_STRING), then Expr.token contains the text of the SQL literal. If -** the expression is a variable (TK_VARIABLE), then Expr.token contains the +** or TK_STRING), then Expr.u.zToken contains the text of the SQL literal. If +** the expression is a variable (TK_VARIABLE), then Expr.u.zToken contains the ** variable name. Finally, if the expression is an SQL function (TK_FUNCTION), -** then Expr.token contains the name of the function. +** then Expr.u.zToken contains the name of the function. ** ** Expr.pRight and Expr.pLeft are the left and right subexpressions of a ** binary operator. Either or both may be NULL.@@ -18268,7 +18096,7 @@ ** Expr objects can use a lot of memory space in database schema. To
** help reduce memory requirements, sometimes an Expr object will be ** truncated. And to reduce the number of memory allocations, sometimes ** two or more Expr objects will be stored in a single memory allocation, -** together with Expr.zToken strings. +** together with Expr.u.zToken strings. ** ** If the EP_Reduced and EP_TokenOnly flags are set when ** an Expr object is truncated. When EP_Reduced is set, then all@@ -18324,7 +18152,10 @@ ynVar iColumn; /* TK_COLUMN: column index. -1 for rowid.
** TK_VARIABLE: variable number (always >= 1). ** TK_SELECT_COLUMN: column of the result vector */ i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */ - int iRightJoinTable; /* If EP_FromJoin, the right table of the join */ + union { + int iJoin; /* If EP_OuterON or EP_InnerON, the right table */ + int iOfst; /* else: start of token from start of statement */ + } w; AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */ union { Table *pTab; /* TK_COLUMN: Table containing column. Can be NULL@@ -18337,36 +18168,35 @@ } sub;
} y; }; -/* -** The following are the meanings of bits in the Expr.flags field. +/* The following are the meanings of bits in the Expr.flags field. ** Value restrictions: ** ** EP_Agg == NC_HasAgg == SF_HasAgg ** EP_Win == NC_HasWin */ -#define EP_FromJoin 0x000001 /* Originates in ON/USING clause of outer join */ -#define EP_Distinct 0x000002 /* Aggregate function with DISTINCT keyword */ -#define EP_HasFunc 0x000004 /* Contains one or more functions of any kind */ -#define EP_FixedCol 0x000008 /* TK_Column with a known fixed value */ +#define EP_OuterON 0x000001 /* Originates in ON/USING clause of outer join */ +#define EP_InnerON 0x000002 /* Originates in ON/USING of an inner join */ +#define EP_Distinct 0x000004 /* Aggregate function with DISTINCT keyword */ +#define EP_HasFunc 0x000008 /* Contains one or more functions of any kind */ #define EP_Agg 0x000010 /* Contains one or more aggregate functions */ -#define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */ -#define EP_DblQuoted 0x000040 /* token.z was originally in "..." */ -#define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */ -#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE operator */ -#define EP_Commuted 0x000200 /* Comparison operator has been commuted */ -#define EP_IntValue 0x000400 /* Integer value contained in u.iValue */ -#define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */ -#define EP_Skip 0x001000 /* Operator does not contribute to affinity */ -#define EP_Reduced 0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */ -#define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */ +#define EP_FixedCol 0x000020 /* TK_Column with a known fixed value */ +#define EP_VarSelect 0x000040 /* pSelect is correlated, not constant */ +#define EP_DblQuoted 0x000080 /* token.z was originally in "..." */ +#define EP_InfixFunc 0x000100 /* True for an infix function: LIKE, GLOB, etc */ +#define EP_Collate 0x000200 /* Tree contains a TK_COLLATE operator */ +#define EP_Commuted 0x000400 /* Comparison operator has been commuted */ +#define EP_IntValue 0x000800 /* Integer value contained in u.iValue */ +#define EP_xIsSelect 0x001000 /* x.pSelect is valid (otherwise x.pList is) */ +#define EP_Skip 0x002000 /* Operator does not contribute to affinity */ +#define EP_Reduced 0x004000 /* Expr struct EXPR_REDUCEDSIZE bytes only */ #define EP_Win 0x008000 /* Contains window functions */ -#define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */ -#define EP_IfNullRow 0x020000 /* The TK_IF_NULL_ROW opcode */ -#define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */ -#define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */ -#define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */ -#define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */ - /* 0x400000 // Available */ +#define EP_TokenOnly 0x010000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */ +#define EP_MemToken 0x020000 /* Need to sqlite3DbFree() Expr.zToken */ +#define EP_IfNullRow 0x040000 /* The TK_IF_NULL_ROW opcode */ +#define EP_Unlikely 0x080000 /* unlikely() or likelihood() function */ +#define EP_ConstFunc 0x100000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */ +#define EP_CanBeNull 0x200000 /* Can be null despite NOT NULL constraint */ +#define EP_Subquery 0x400000 /* Tree contains a TK_SELECT operator */ #define EP_Leaf 0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */ #define EP_WinFunc 0x1000000 /* TK_FUNCTION with Expr.y.pWin set */ #define EP_Subrtn 0x2000000 /* Uses Expr.y.sub. TK_IN, _SELECT, or _EXISTS */@@ -18377,23 +18207,31 @@ #define EP_IsFalse 0x20000000 /* Always has boolean value of FALSE */
#define EP_FromDDL 0x40000000 /* Originates from sqlite_schema */ /* 0x80000000 // Available */ -/* -** The EP_Propagate mask is a set of properties that automatically propagate +/* The EP_Propagate mask is a set of properties that automatically propagate ** upwards into parent nodes. */ #define EP_Propagate (EP_Collate|EP_Subquery|EP_HasFunc) -/* -** These macros can be used to test, set, or clear bits in the +/* Macros can be used to test, set, or clear bits in the ** Expr.flags field. */ #define ExprHasProperty(E,P) (((E)->flags&(P))!=0) #define ExprHasAllProperty(E,P) (((E)->flags&(P))==(P)) #define ExprSetProperty(E,P) (E)->flags|=(P) #define ExprClearProperty(E,P) (E)->flags&=~(P) -#define ExprAlwaysTrue(E) (((E)->flags&(EP_FromJoin|EP_IsTrue))==EP_IsTrue) -#define ExprAlwaysFalse(E) (((E)->flags&(EP_FromJoin|EP_IsFalse))==EP_IsFalse) +#define ExprAlwaysTrue(E) (((E)->flags&(EP_OuterON|EP_IsTrue))==EP_IsTrue) +#define ExprAlwaysFalse(E) (((E)->flags&(EP_OuterON|EP_IsFalse))==EP_IsFalse) +/* Macros used to ensure that the correct members of unions are accessed +** in Expr. +*/ +#define ExprUseUToken(E) (((E)->flags&EP_IntValue)==0) +#define ExprUseUValue(E) (((E)->flags&EP_IntValue)!=0) +#define ExprUseXList(E) (((E)->flags&EP_xIsSelect)==0) +#define ExprUseXSelect(E) (((E)->flags&EP_xIsSelect)!=0) +#define ExprUseYTab(E) (((E)->flags&(EP_WinFunc|EP_Subrtn))==0) +#define ExprUseYWin(E) (((E)->flags&EP_WinFunc)!=0) +#define ExprUseYSub(E) (((E)->flags&EP_Subrtn)!=0) /* Flags for use with Expr.vvaFlags */@@ -18469,18 +18307,25 @@ int nAlloc; /* Number of a[] slots allocated */
struct ExprList_item { /* For each expression in the list */ Expr *pExpr; /* The parse tree for this expression */ char *zEName; /* Token associated with this expression */ - u8 sortFlags; /* Mask of KEYINFO_ORDER_* flags */ - unsigned eEName :2; /* Meaning of zEName */ - unsigned done :1; /* A flag to indicate when processing is finished */ - unsigned reusable :1; /* Constant expression is reusable */ - unsigned bSorterRef :1; /* Defer evaluation until after sorting */ - unsigned bNulls: 1; /* True if explicit "NULLS FIRST/LAST" */ + struct { + u8 sortFlags; /* Mask of KEYINFO_ORDER_* flags */ + unsigned eEName :2; /* Meaning of zEName */ + unsigned done :1; /* Indicates when processing is finished */ + unsigned reusable :1; /* Constant expression is reusable */ + unsigned bSorterRef :1; /* Defer evaluation until after sorting */ + unsigned bNulls :1; /* True if explicit "NULLS FIRST/LAST" */ + unsigned bUsed :1; /* This column used in a SF_NestedFrom subquery */ + unsigned bUsingTerm:1; /* Term from the USING clause of a NestedFrom */ + unsigned bNoExpand: 1; /* Term is an auxiliary in NestedFrom and should + ** not be expanded by "*" in parent queries */ + } fg; union { - struct { + struct { /* Used by any ExprList other than Parse.pConsExpr */ u16 iOrderByCol; /* For ORDER BY, column number in result set */ u16 iAlias; /* Index into Parse.aAlias[] for zName */ } x; - int iConstExprReg; /* Register in which Expr value is cached */ + int iConstExprReg; /* Register in which Expr value is cached. Used only + ** by Parse.pConstExpr */ } u; } a[1]; /* One slot for each expression in the list */ };@@ -18508,16 +18353,35 @@ **
** If "a" is the k-th column of table "t", then IdList.a[0].idx==k. */ struct IdList { + int nId; /* Number of identifiers on the list */ + u8 eU4; /* Which element of a.u4 is valid */ struct IdList_item { char *zName; /* Name of the identifier */ - int idx; /* Index in some Table.aCol[] of a column named zName */ - } *a; - int nId; /* Number of identifiers on the list */ + union { + int idx; /* Index in some Table.aCol[] of a column named zName */ + Expr *pExpr; /* Expr to implement a USING variable -- NOT USED */ + } u4; + } a[1]; }; /* +** Allowed values for IdList.eType, which determines which value of the a.u4 +** is valid. +*/ +#define EU4_NONE 0 /* Does not use IdList.a.u4 */ +#define EU4_IDX 1 /* Uses IdList.a.u4.idx */ +#define EU4_EXPR 2 /* Uses IdList.a.u4.pExpr -- NOT CURRENTLY USED */ + +/* ** The SrcItem object represents a single term in the FROM clause of a query. ** The SrcList object is mostly an array of SrcItems. +** +** Union member validity: +** +** u1.zIndexedBy fg.isIndexedBy && !fg.isTabFunc +** u1.pFuncArg fg.isTabFunc && !fg.isIndexedBy +** u2.pIBIndex fg.isIndexedBy && !fg.isCte +** u2.pCteUse fg.isCte && !fg.isIndexedBy */ struct SrcItem { Schema *pSchema; /* Schema to which this item is fixed */@@ -18535,15 +18399,22 @@ 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 isMaterialized:1; /* This is a materialized view */ unsigned viaCoroutine :1; /* Implemented as a co-routine */ unsigned isRecursive :1; /* True for recursive reference in WITH */ unsigned fromDDL :1; /* Comes from sqlite_schema */ unsigned isCte :1; /* This is a CTE */ unsigned notCte :1; /* This item may not match a CTE */ + unsigned isUsing :1; /* u3.pUsing is valid */ + unsigned isOn :1; /* u3.pOn was once valid and non-NULL */ + unsigned isSynthUsing :1; /* u3.pUsing is synthensized from NATURAL */ + unsigned isNestedFrom :1; /* pSelect is a SF_NestedFrom subquery */ } fg; int iCursor; /* The VDBE cursor number used to access this table */ - Expr *pOn; /* The ON clause of a join */ - IdList *pUsing; /* The USING clause of a join */ + union { + Expr *pOn; /* fg.isUsing==0 => The ON clause of a join */ + IdList *pUsing; /* fg.isUsing==1 => The USING clause of a join */ + } u3; Bitmask colUsed; /* Bit N (1<<N) set if column N of pTab is used */ union { char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */@@ -18553,6 +18424,15 @@ union {
Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */ CteUse *pCteUse; /* CTE Usage info info fg.isCte is true */ } u2; +}; + +/* +** The OnOrUsing object represents either an ON clause or a USING clause. +** It can never be both at the same time, but it can be neither. +*/ +struct OnOrUsing { + Expr *pOn; /* The ON clause of a join */ + IdList *pUsing; /* The USING clause of a join */ }; /*@@ -18583,14 +18463,15 @@
/* ** Permitted values of the SrcList.a.jointype field */ -#define JT_INNER 0x0001 /* Any kind of inner or cross join */ -#define JT_CROSS 0x0002 /* Explicit use of the CROSS keyword */ -#define JT_NATURAL 0x0004 /* True for a "natural" join */ -#define JT_LEFT 0x0008 /* Left outer join */ -#define JT_RIGHT 0x0010 /* Right outer join */ -#define JT_OUTER 0x0020 /* The "OUTER" keyword is present */ -#define JT_ERROR 0x0040 /* unknown or unsupported join type */ - +#define JT_INNER 0x01 /* Any kind of inner or cross join */ +#define JT_CROSS 0x02 /* Explicit use of the CROSS keyword */ +#define JT_NATURAL 0x04 /* True for a "natural" join */ +#define JT_LEFT 0x08 /* Left outer join */ +#define JT_RIGHT 0x10 /* Right outer join */ +#define JT_OUTER 0x20 /* The "OUTER" keyword is present */ +#define JT_LTORJ 0x40 /* One of the LEFT operands of a RIGHT JOIN + ** Mnemonic: Left Table Of Right Join */ +#define JT_ERROR 0x80 /* unknown or unsupported join type */ /* ** Flags appropriate for the wctrlFlags parameter of sqlite3WhereBegin()@@ -18613,7 +18494,7 @@ #define WHERE_WANT_DISTINCT 0x0100 /* All output needs to be distinct */
#define WHERE_SORTBYGROUP 0x0200 /* Support sqlite3WhereIsSorted() */ #define WHERE_AGG_DISTINCT 0x0400 /* Query is "SELECT agg(DISTINCT ...)" */ #define WHERE_ORDERBY_LIMIT 0x0800 /* ORDERBY+LIMIT on the inner loop */ - /* 0x1000 not currently used */ +#define WHERE_RIGHT_JOIN 0x1000 /* Processing a RIGHT JOIN */ /* 0x2000 not currently used */ #define WHERE_USE_LIMIT 0x4000 /* Use the LIMIT in cost estimates */ /* 0x8000 not currently used */@@ -18666,31 +18547,33 @@ /*
** Allowed values for the NameContext, ncFlags field. ** ** Value constraints (all checked via assert()): -** NC_HasAgg == SF_HasAgg == EP_Agg -** NC_MinMaxAgg == SF_MinMaxAgg == SQLITE_FUNC_MINMAX +** NC_HasAgg == SF_HasAgg == EP_Agg +** NC_MinMaxAgg == SF_MinMaxAgg == SQLITE_FUNC_MINMAX +** NC_OrderAgg == SF_OrderByReqd == SQLITE_FUNC_ANYORDER ** NC_HasWin == EP_Win ** */ -#define NC_AllowAgg 0x00001 /* Aggregate functions are allowed here */ -#define NC_PartIdx 0x00002 /* True if resolving a partial index WHERE */ -#define NC_IsCheck 0x00004 /* True if resolving a CHECK constraint */ -#define NC_GenCol 0x00008 /* True for a GENERATED ALWAYS AS clause */ -#define NC_HasAgg 0x00010 /* One or more aggregate functions seen */ -#define NC_IdxExpr 0x00020 /* True if resolving columns of CREATE INDEX */ -#define NC_SelfRef 0x0002e /* Combo: PartIdx, isCheck, GenCol, and IdxExpr */ -#define NC_VarSelect 0x00040 /* A correlated subquery has been seen */ -#define NC_UEList 0x00080 /* True if uNC.pEList is used */ -#define NC_UAggInfo 0x00100 /* True if uNC.pAggInfo is used */ -#define NC_UUpsert 0x00200 /* True if uNC.pUpsert is used */ -#define NC_UBaseReg 0x00400 /* True if uNC.iBaseReg is used */ -#define NC_MinMaxAgg 0x01000 /* min/max aggregates seen. See note above */ -#define NC_Complex 0x02000 /* True if a function or subquery seen */ -#define NC_AllowWin 0x04000 /* Window functions are allowed here */ -#define NC_HasWin 0x08000 /* One or more window functions seen */ -#define NC_IsDDL 0x10000 /* Resolving names in a CREATE statement */ -#define NC_InAggFunc 0x20000 /* True if analyzing arguments to an agg func */ -#define NC_FromDDL 0x40000 /* SQL text comes from sqlite_schema */ -#define NC_NoSelect 0x80000 /* Do not descend into sub-selects */ +#define NC_AllowAgg 0x000001 /* Aggregate functions are allowed here */ +#define NC_PartIdx 0x000002 /* True if resolving a partial index WHERE */ +#define NC_IsCheck 0x000004 /* True if resolving a CHECK constraint */ +#define NC_GenCol 0x000008 /* True for a GENERATED ALWAYS AS clause */ +#define NC_HasAgg 0x000010 /* One or more aggregate functions seen */ +#define NC_IdxExpr 0x000020 /* True if resolving columns of CREATE INDEX */ +#define NC_SelfRef 0x00002e /* Combo: PartIdx, isCheck, GenCol, and IdxExpr */ +#define NC_VarSelect 0x000040 /* A correlated subquery has been seen */ +#define NC_UEList 0x000080 /* True if uNC.pEList is used */ +#define NC_UAggInfo 0x000100 /* True if uNC.pAggInfo is used */ +#define NC_UUpsert 0x000200 /* True if uNC.pUpsert is used */ +#define NC_UBaseReg 0x000400 /* True if uNC.iBaseReg is used */ +#define NC_MinMaxAgg 0x001000 /* min/max aggregates seen. See note above */ +#define NC_Complex 0x002000 /* True if a function or subquery seen */ +#define NC_AllowWin 0x004000 /* Window functions are allowed here */ +#define NC_HasWin 0x008000 /* One or more window functions seen */ +#define NC_IsDDL 0x010000 /* Resolving names in a CREATE statement */ +#define NC_InAggFunc 0x020000 /* True if analyzing arguments to an agg func */ +#define NC_FromDDL 0x040000 /* SQL text comes from sqlite_schema */ +#define NC_NoSelect 0x080000 /* Do not descend into sub-selects */ +#define NC_OrderAgg 0x8000000 /* Has an aggregate other than count/min/max */ /* ** An instance of the following object describes a single ON CONFLICT@@ -18773,9 +18656,10 @@ ** Allowed values for Select.selFlags. The "SF" prefix stands for
** "Select Flag". ** ** Value constraints (all checked via assert()) -** SF_HasAgg == NC_HasAgg -** SF_MinMaxAgg == NC_MinMaxAgg == SQLITE_FUNC_MINMAX -** SF_FixedLimit == WHERE_USE_LIMIT +** SF_HasAgg == NC_HasAgg +** SF_MinMaxAgg == NC_MinMaxAgg == SQLITE_FUNC_MINMAX +** SF_OrderByReqd == NC_OrderAgg == SQLITE_FUNC_ANYORDER +** SF_FixedLimit == WHERE_USE_LIMIT */ #define SF_Distinct 0x0000001 /* Output should be DISTINCT */ #define SF_All 0x0000002 /* Includes the ALL keyword */@@ -18800,10 +18684,14 @@ #define SF_WhereBegin 0x0080000 /* Really a WhereBegin() call. Debug Only */
#define SF_WinRewrite 0x0100000 /* Window function rewrite accomplished */ #define SF_View 0x0200000 /* SELECT statement is a view */ #define SF_NoopOrderBy 0x0400000 /* ORDER BY is ignored for this query */ -#define SF_UpdateFrom 0x0800000 /* Statement is an UPDATE...FROM */ +#define SF_UFSrcCheck 0x0800000 /* Check pSrc as required by UPDATE...FROM */ #define SF_PushDown 0x1000000 /* SELECT has be modified by push-down opt */ #define SF_MultiPart 0x2000000 /* Has multiple incompatible PARTITIONs */ #define SF_CopyCte 0x4000000 /* SELECT statement is a copy of a CTE */ +#define SF_OrderByReqd 0x8000000 /* The ORDER BY clause may not be omitted */ + +/* True if S exists and has SF_NestedFrom */ +#define IsNestedFrom(S) ((S)!=0 && ((S)->selFlags&SF_NestedFrom)!=0) /* ** The results of a SELECT can be distributed in several ways, as defined@@ -19016,6 +18904,7 @@ u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */
u8 okConstFactor; /* OK to factor out constants */ u8 disableLookaside; /* Number of times lookaside has been disabled */ u8 disableVtab; /* Disable all virtual tables for this parse */ + u8 withinRJSubrtn; /* Nesting level for RIGHT JOIN body subroutines */ #if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) u8 earlyCleanup; /* OOM inside sqlite3ParserAddCleanup() */ #endif@@ -19045,7 +18934,8 @@ #endif
AutoincInfo *pAinc; /* Information about AUTOINCREMENT counters */ Parse *pToplevel; /* Parse structure for main program (or NULL) */ Table *pTriggerTab; /* Table triggers are being coded for */ - Parse *pParentParse; /* Parent parser if this parser is nested */ + TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */ + ParseCleanup *pCleanup; /* List of cleanup operations to run after parse */ union { int addrCrTab; /* Address of OP_CreateBtree on CREATE TABLE */ Returning *pReturning; /* The RETURNING clause */@@ -19066,6 +18956,7 @@ ** determined by offsetof(Parse,aTempReg).
**************************************************************************/ int aTempReg[8]; /* Holding area for temporary registers */ + Parse *pOuterParse; /* Outer Parse object when nested */ Token sNameToken; /* Token with unqualified schema object name */ /************************************************************************@@ -19100,14 +18991,14 @@ #ifndef SQLITE_OMIT_VIRTUALTABLE
Token sArg; /* Complete text of a module argument */ Table **apVtabLock; /* Pointer to virtual tables needing locking */ #endif - TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */ With *pWith; /* Current WITH clause, or NULL */ - ParseCleanup *pCleanup; /* List of cleanup operations to run after parse */ #ifndef SQLITE_OMIT_ALTERTABLE RenameToken *pRename; /* Tokens subject to renaming by ALTER TABLE */ #endif }; +/* Allowed values for Parse.eParseMode +*/ #define PARSE_MODE_NORMAL 0 #define PARSE_MODE_DECLARE_VTAB 1 #define PARSE_MODE_RENAME 2@@ -19116,7 +19007,8 @@
/* ** Sizes and pointers of various parts of the Parse object. */ -#define PARSE_HDR_SZ offsetof(Parse,aTempReg) /* Recursive part w/o aColCache*/ +#define PARSE_HDR(X) (((char*)(X))+offsetof(Parse,zErrMsg)) +#define PARSE_HDR_SZ (offsetof(Parse,aTempReg)-offsetof(Parse,zErrMsg)) /* Recursive part w/o aColCache*/ #define PARSE_RECURSE_SZ offsetof(Parse,sLastToken) /* Recursive part */ #define PARSE_TAIL_SZ (sizeof(Parse)-PARSE_RECURSE_SZ) /* Non-recursive part */ #define PARSE_TAIL(X) (((char*)(X))+PARSE_RECURSE_SZ) /* Pointer to tail */@@ -19185,20 +19077,20 @@ #define OPFLAG_NOCHNG_MAGIC 0x6d /* OP_MakeRecord: serialtype 10 is ok */
#define OPFLAG_PREFORMAT 0x80 /* OP_Insert uses preformatted cell */ /* - * Each trigger present in the database schema is stored as an instance of - * struct Trigger. - * - * Pointers to instances of struct Trigger are stored in two ways. - * 1. In the "trigHash" hash table (part of the sqlite3* that represents the - * database). This allows Trigger structures to be retrieved by name. - * 2. All triggers associated with a single table form a linked list, using the - * pNext member of struct Trigger. A pointer to the first element of the - * linked list is stored as the "pTrigger" member of the associated - * struct Table. - * - * The "step_list" member points to the first element of a linked list - * containing the SQL statements specified as the trigger program. - */ +** Each trigger present in the database schema is stored as an instance of +** struct Trigger. +** +** Pointers to instances of struct Trigger are stored in two ways. +** 1. In the "trigHash" hash table (part of the sqlite3* that represents the +** database). This allows Trigger structures to be retrieved by name. +** 2. All triggers associated with a single table form a linked list, using the +** pNext member of struct Trigger. A pointer to the first element of the +** linked list is stored as the "pTrigger" member of the associated +** struct Table. +** +** The "step_list" member points to the first element of a linked list +** containing the SQL statements specified as the trigger program. +*/ struct Trigger { char *zName; /* The name of the trigger */ char *table; /* The table or view to which the trigger applies */@@ -19225,43 +19117,48 @@ #define TRIGGER_BEFORE 1
#define TRIGGER_AFTER 2 /* - * An instance of struct TriggerStep is used to store a single SQL statement - * that is a part of a trigger-program. - * - * Instances of struct TriggerStep are stored in a singly linked list (linked - * using the "pNext" member) referenced by the "step_list" member of the - * associated struct Trigger instance. The first element of the linked list is - * the first step of the trigger-program. - * - * The "op" member indicates whether this is a "DELETE", "INSERT", "UPDATE" or - * "SELECT" statement. The meanings of the other members is determined by the - * value of "op" as follows: - * - * (op == TK_INSERT) - * orconf -> stores the ON CONFLICT algorithm - * pSelect -> If this is an INSERT INTO ... SELECT ... statement, then - * this stores a pointer to the SELECT statement. Otherwise NULL. - * zTarget -> Dequoted name of the table to insert into. - * pExprList -> If this is an INSERT INTO ... VALUES ... statement, then - * this stores values to be inserted. Otherwise NULL. - * pIdList -> If this is an INSERT INTO ... (<column-names>) VALUES ... - * statement, then this stores the column-names to be - * inserted into. - * - * (op == TK_DELETE) - * zTarget -> Dequoted name of the table to delete from. - * pWhere -> The WHERE clause of the DELETE statement if one is specified. - * Otherwise NULL. - * - * (op == TK_UPDATE) - * zTarget -> Dequoted name of the table to update. - * pWhere -> The WHERE clause of the UPDATE statement if one is specified. - * Otherwise NULL. - * pExprList -> A list of the columns to update and the expressions to update - * them to. See sqlite3Update() documentation of "pChanges" - * argument. - * - */ +** An instance of struct TriggerStep is used to store a single SQL statement +** that is a part of a trigger-program. +** +** Instances of struct TriggerStep are stored in a singly linked list (linked +** using the "pNext" member) referenced by the "step_list" member of the +** associated struct Trigger instance. The first element of the linked list is +** the first step of the trigger-program. +** +** The "op" member indicates whether this is a "DELETE", "INSERT", "UPDATE" or +** "SELECT" statement. The meanings of the other members is determined by the +** value of "op" as follows: +** +** (op == TK_INSERT) +** orconf -> stores the ON CONFLICT algorithm +** pSelect -> The content to be inserted - either a SELECT statement or +** a VALUES clause. +** zTarget -> Dequoted name of the table to insert into. +** pIdList -> If this is an INSERT INTO ... (<column-names>) VALUES ... +** statement, then this stores the column-names to be +** inserted into. +** pUpsert -> The ON CONFLICT clauses for an Upsert +** +** (op == TK_DELETE) +** zTarget -> Dequoted name of the table to delete from. +** pWhere -> The WHERE clause of the DELETE statement if one is specified. +** Otherwise NULL. +** +** (op == TK_UPDATE) +** zTarget -> Dequoted name of the table to update. +** pWhere -> The WHERE clause of the UPDATE statement if one is specified. +** Otherwise NULL. +** pExprList -> A list of the columns to update and the expressions to update +** them to. See sqlite3Update() documentation of "pChanges" +** argument. +** +** (op == TK_SELECT) +** pSelect -> The SELECT statement +** +** (op == TK_RETURNING) +** pExprList -> The list of expressions that follow the RETURNING keyword. +** +*/ struct TriggerStep { u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT, ** or TK_RETURNING */@@ -19329,8 +19226,10 @@
/* ** Allowed values for mInitFlags */ +#define INITFLAG_AlterMask 0x0003 /* Types of ALTER */ #define INITFLAG_AlterRename 0x0001 /* Reparse after a RENAME */ #define INITFLAG_AlterDrop 0x0002 /* Reparse after a DROP COLUMN */ +#define INITFLAG_AlterAdd 0x0003 /* Reparse after an ADD COLUMN */ /* Tuning parameters are set using SQLITE_TESTCTRL_TUNE and are controlled ** on debug-builds of the CLI using ".testctrl tune ID VALUE". Tuning@@ -19409,6 +19308,7 @@ #ifndef SQLITE_UNTESTABLE
int (*xTestCallback)(int); /* Invoked by sqlite3FaultSim() */ #endif int bLocaltimeFault; /* True to fail localtime() calls */ + int (*xAltLocaltime)(const void*,void*); /* Alternative localtime() routine */ int iOnceResetThreshold; /* When to reset OP_Once counters */ u32 szSorterRef; /* Min size in bytes to use sorter-refs */ unsigned int iPrngSeed; /* Alternative fixed seed for the PRNG */@@ -19451,8 +19351,8 @@ NameContext *pNC; /* Naming context */
int n; /* A counter */ int iCur; /* A cursor number */ SrcList *pSrcList; /* FROM clause */ - struct SrcCount *pSrcCount; /* Counting column references */ struct CCurHint *pCCurHint; /* Used by codeCursorHint() */ + struct RefSrcList *pRefSrcList; /* sqlite3ReferencesSrcList() */ int *aiCol; /* array of column indexes */ struct IdxCover *pIdxCover; /* Check for index coverage */ struct IdxExprTrans *pIdxTrans; /* Convert idxed expr to column */@@ -19613,7 +19513,7 @@ Expr *pEnd; /* Expression for "<expr> FOLLOWING" */
Window **ppThis; /* Pointer to this object in Select.pWin list */ Window *pNextWin; /* Next window function belonging to this SELECT */ Expr *pFilter; /* The FILTER expression */ - FuncDef *pFunc; /* The function */ + FuncDef *pWFunc; /* The function */ int iEphCsr; /* Partition buffer or Peer buffer */ int regAccum; /* Accumulator */ int regResult; /* Interim result */@@ -19637,7 +19537,7 @@ SQLITE_PRIVATE void sqlite3WindowListDelete(sqlite3 *db, Window *p);
SQLITE_PRIVATE Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*, u8); SQLITE_PRIVATE void sqlite3WindowAttach(Parse*, Expr*, Window*); SQLITE_PRIVATE void sqlite3WindowLink(Select *pSel, Window *pWin); -SQLITE_PRIVATE int sqlite3WindowCompare(Parse*, Window*, Window*, int); +SQLITE_PRIVATE int sqlite3WindowCompare(const Parse*, const Window*, const Window*, int); SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse*, Select*); SQLITE_PRIVATE void sqlite3WindowCodeStep(Parse*, Select*, WhereInfo*, int, int); SQLITE_PRIVATE int sqlite3WindowRewrite(Parse*, Select*);@@ -19769,8 +19669,8 @@ SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *, void *, u64);
SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *, void *, u64); SQLITE_PRIVATE void sqlite3DbFree(sqlite3*, void*); SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3*, void*); -SQLITE_PRIVATE int sqlite3MallocSize(void*); -SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3*, void*); +SQLITE_PRIVATE int sqlite3MallocSize(const void*); +SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3*, const void*); SQLITE_PRIVATE void *sqlite3PageMalloc(int); SQLITE_PRIVATE void sqlite3PageFree(void*); SQLITE_PRIVATE void sqlite3MemSetDefault(void);@@ -19868,27 +19768,63 @@ SQLITE_PRIVATE void *sqlite3TestTextToPtr(const char*);
#endif #if defined(SQLITE_DEBUG) +SQLITE_PRIVATE void sqlite3TreeViewLine(TreeView*, const char *zFormat, ...); SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView*, const Expr*, u8); SQLITE_PRIVATE void sqlite3TreeViewBareExprList(TreeView*, const ExprList*, const char*); SQLITE_PRIVATE void sqlite3TreeViewExprList(TreeView*, const ExprList*, u8, const char*); +SQLITE_PRIVATE void sqlite3TreeViewBareIdList(TreeView*, const IdList*, const char*); +SQLITE_PRIVATE void sqlite3TreeViewIdList(TreeView*, const IdList*, u8, const char*); +SQLITE_PRIVATE void sqlite3TreeViewColumnList(TreeView*, const Column*, int, u8); SQLITE_PRIVATE void sqlite3TreeViewSrcList(TreeView*, const SrcList*); SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView*, const Select*, u8); SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView*, const With*, u8); +SQLITE_PRIVATE void sqlite3TreeViewUpsert(TreeView*, const Upsert*, u8); +#if TREETRACE_ENABLED +SQLITE_PRIVATE void sqlite3TreeViewDelete(const With*, const SrcList*, const Expr*, + const ExprList*,const Expr*, const Trigger*); +SQLITE_PRIVATE void sqlite3TreeViewInsert(const With*, const SrcList*, + const IdList*, const Select*, const ExprList*, + int, const Upsert*, const Trigger*); +SQLITE_PRIVATE void sqlite3TreeViewUpdate(const With*, const SrcList*, const ExprList*, + const Expr*, int, const ExprList*, const Expr*, + const Upsert*, const Trigger*); +#endif +#ifndef SQLITE_OMIT_TRIGGER +SQLITE_PRIVATE void sqlite3TreeViewTriggerStep(TreeView*, const TriggerStep*, u8, u8); +SQLITE_PRIVATE void sqlite3TreeViewTrigger(TreeView*, const Trigger*, u8, u8); +#endif #ifndef SQLITE_OMIT_WINDOWFUNC SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView*, const Window*, u8); SQLITE_PRIVATE void sqlite3TreeViewWinFunc(TreeView*, const Window*, u8); #endif +SQLITE_PRIVATE void sqlite3ShowExpr(const Expr*); +SQLITE_PRIVATE void sqlite3ShowExprList(const ExprList*); +SQLITE_PRIVATE void sqlite3ShowIdList(const IdList*); +SQLITE_PRIVATE void sqlite3ShowSrcList(const SrcList*); +SQLITE_PRIVATE void sqlite3ShowSelect(const Select*); +SQLITE_PRIVATE void sqlite3ShowWith(const With*); +SQLITE_PRIVATE void sqlite3ShowUpsert(const Upsert*); +#ifndef SQLITE_OMIT_TRIGGER +SQLITE_PRIVATE void sqlite3ShowTriggerStep(const TriggerStep*); +SQLITE_PRIVATE void sqlite3ShowTriggerStepList(const TriggerStep*); +SQLITE_PRIVATE void sqlite3ShowTrigger(const Trigger*); +SQLITE_PRIVATE void sqlite3ShowTriggerList(const Trigger*); #endif - +#ifndef SQLITE_OMIT_WINDOWFUNC +SQLITE_PRIVATE void sqlite3ShowWindow(const Window*); +SQLITE_PRIVATE void sqlite3ShowWinFunc(const Window*); +#endif +#endif SQLITE_PRIVATE void sqlite3SetString(char **, sqlite3*, const char*); SQLITE_PRIVATE void sqlite3ErrorMsg(Parse*, const char*, ...); SQLITE_PRIVATE int sqlite3ErrorToParser(sqlite3*,int); SQLITE_PRIVATE void sqlite3Dequote(char*); SQLITE_PRIVATE void sqlite3DequoteExpr(Expr*); +SQLITE_PRIVATE void sqlite3DequoteToken(Token*); SQLITE_PRIVATE void sqlite3TokenInit(Token*,char*); SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char*, int); -SQLITE_PRIVATE int sqlite3RunParser(Parse*, const char*, char **); +SQLITE_PRIVATE int sqlite3RunParser(Parse*, const char*); SQLITE_PRIVATE void sqlite3FinishCoding(Parse*); SQLITE_PRIVATE int sqlite3GetTempReg(Parse*); SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse*,int);@@ -19905,16 +19841,17 @@ SQLITE_PRIVATE Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*);
SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse*, Expr*, Select*); SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse*,Expr*, Expr*); SQLITE_PRIVATE Expr *sqlite3ExprSimplifiedAndOr(Expr*); -SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*, int); -SQLITE_PRIVATE void sqlite3ExprFunctionUsable(Parse*,Expr*,FuncDef*); +SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse*,ExprList*, const Token*, int); +SQLITE_PRIVATE void sqlite3ExprFunctionUsable(Parse*,const Expr*,const FuncDef*); SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32); SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3*, Expr*); SQLITE_PRIVATE void sqlite3ExprDeferredDelete(Parse*, Expr*); SQLITE_PRIVATE void sqlite3ExprUnmapAndDelete(Parse*, Expr*); SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*); SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*); +SQLITE_PRIVATE Select *sqlite3ExprListToValues(Parse*, int, ExprList*); SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList*,int,int); -SQLITE_PRIVATE void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int); +SQLITE_PRIVATE void sqlite3ExprListSetName(Parse*,ExprList*,const Token*,int); SQLITE_PRIVATE void sqlite3ExprListSetSpan(Parse*,ExprList*,const char*,const char*); SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3*, ExprList*); SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList*);@@ -19930,6 +19867,10 @@ SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3*);
SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3*,int); SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3*); SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3*); +SQLITE_PRIVATE void sqlite3ColumnSetExpr(Parse*,Table*,Column*,Expr*); +SQLITE_PRIVATE Expr *sqlite3ColumnExpr(Table*,Column*); +SQLITE_PRIVATE void sqlite3ColumnSetColl(sqlite3*,Column*,const char*zColl); +SQLITE_PRIVATE const char *sqlite3ColumnColl(Column*); SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3*,Table*); SQLITE_PRIVATE void sqlite3GenerateColumnNames(Parse *pParse, Select *pSelect); SQLITE_PRIVATE int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**);@@ -19951,14 +19892,14 @@ SQLITE_PRIVATE void sqlite3ColumnPropertiesFromName(Table*, Column*);
#else # define sqlite3ColumnPropertiesFromName(T,C) /* no-op */ #endif -SQLITE_PRIVATE void sqlite3AddColumn(Parse*,Token*,Token*); +SQLITE_PRIVATE void sqlite3AddColumn(Parse*,Token,Token); SQLITE_PRIVATE void sqlite3AddNotNull(Parse*, int); SQLITE_PRIVATE void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int); SQLITE_PRIVATE void sqlite3AddCheckConstraint(Parse*, Expr*, const char*, const char*); SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse*,Expr*,const char*,const char*); SQLITE_PRIVATE void sqlite3AddCollateType(Parse*, Token*); SQLITE_PRIVATE void sqlite3AddGenerated(Parse*,Expr*,Token*); -SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,u8,Select*); +SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,u32,Select*); SQLITE_PRIVATE void sqlite3AddReturning(Parse*,ExprList*); SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*, sqlite3_vfs**,char**,char **);@@ -20022,13 +19963,14 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(Parse*, SrcList*, int, int);
SQLITE_PRIVATE SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2); SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(Parse*, SrcList*, Token*, Token*); SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*, - Token*, Select*, Expr*, IdList*); + Token*, Select*, OnOrUsing*); SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *); SQLITE_PRIVATE void sqlite3SrcListFuncArgs(Parse*, SrcList*, ExprList*); SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *, SrcItem *); -SQLITE_PRIVATE void sqlite3SrcListShiftJoinType(SrcList*); +SQLITE_PRIVATE void sqlite3SrcListShiftJoinType(Parse*,SrcList*); SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse*, SrcList*); SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3*, IdList*); +SQLITE_PRIVATE void sqlite3ClearOnOrUsing(sqlite3*, OnOrUsing*); SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3*, SrcList*); SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(sqlite3*,i16,int,char**); SQLITE_PRIVATE void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,@@ -20044,10 +19986,12 @@ SQLITE_PRIVATE void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,char*); #endif +SQLITE_PRIVATE void sqlite3CodeChangeCount(Vdbe*,int,const char*); SQLITE_PRIVATE void sqlite3DeleteFrom(Parse*, SrcList*, Expr*, ExprList*, Expr*); SQLITE_PRIVATE void sqlite3Update(Parse*, SrcList*, ExprList*,Expr*,int,ExprList*,Expr*, Upsert*); -SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int); +SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*, + ExprList*,Select*,u16,int); SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo*); SQLITE_PRIVATE LogEst sqlite3WhereOutputRowCount(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereIsDistinct(WhereInfo*);@@ -20068,7 +20012,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);
SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse*, int, int, int); SQLITE_PRIVATE void sqlite3ExprCode(Parse*, Expr*, int); #ifndef SQLITE_OMIT_GENERATED_COLUMNS -SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn(Parse*, Column*, int); +SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn(Parse*, Table*, Column*, int); #endif SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse*, Expr*, int); SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse*, Expr*, int);@@ -20087,23 +20031,24 @@ SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3*,const char*, const char*);
#define LOCATE_VIEW 0x01 #define LOCATE_NOERR 0x02 SQLITE_PRIVATE Table *sqlite3LocateTable(Parse*,u32 flags,const char*, const char*); +SQLITE_PRIVATE const char *sqlite3PreferredTableName(const char*); SQLITE_PRIVATE Table *sqlite3LocateTableItem(Parse*,u32 flags,SrcItem *); 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*,Token*,Expr*); SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*, int, sqlite3_value*); -SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3*, Token*); -SQLITE_PRIVATE int sqlite3ExprCompare(Parse*,Expr*, Expr*, int); -SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr*, Expr*, int); -SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList*, ExprList*, int); -SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Parse*,Expr*, Expr*, int); +SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3*, const Token*); +SQLITE_PRIVATE int sqlite3ExprCompare(const Parse*,const Expr*,const Expr*, int); +SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr*,Expr*,int); +SQLITE_PRIVATE int sqlite3ExprListCompare(const ExprList*,const ExprList*, int); +SQLITE_PRIVATE int sqlite3ExprImpliesExpr(const Parse*,const Expr*,const Expr*, int); SQLITE_PRIVATE int sqlite3ExprImpliesNonNullRow(Expr*,int); SQLITE_PRIVATE void sqlite3AggInfoPersistWalkerInit(Walker*,Parse*); 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 int sqlite3ReferencesSrcList(Parse*, Expr*, SrcList*); SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse*); #ifndef SQLITE_UNTESTABLE SQLITE_PRIVATE void sqlite3PrngSaveState(void);@@ -20125,10 +20070,11 @@ SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr*);
SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr*, u8); SQLITE_PRIVATE int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*); SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr*,int); +SQLITE_PRIVATE int sqlite3ExprIsTableConstraint(Expr*,const SrcItem*); #ifdef SQLITE_ENABLE_CURSOR_HINTS SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr*); #endif -SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr*, int*); +SQLITE_PRIVATE int sqlite3ExprIsInteger(const Expr*, int*); SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr*); SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr*, char); SQLITE_PRIVATE int sqlite3IsRowid(const char*);@@ -20153,17 +20099,22 @@ SQLITE_PRIVATE void sqlite3MayAbort(Parse*);
SQLITE_PRIVATE void sqlite3HaltConstraint(Parse*, int, int, char*, i8, u8); SQLITE_PRIVATE void sqlite3UniqueConstraint(Parse*, int, Index*); SQLITE_PRIVATE void sqlite3RowidConstraint(Parse*, int, Table*); -SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3*,Expr*,int); -SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int); -SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int); -SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3*,IdList*); -SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3*,Select*,int); +SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3*,const Expr*,int); +SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3*,const ExprList*,int); +SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3*,const SrcList*,int); +SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3*,const IdList*); +SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3*,const Select*,int); SQLITE_PRIVATE FuncDef *sqlite3FunctionSearch(int,const char*); SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(FuncDef*,int); SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8); +SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum*,sqlite3_value*); SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void); SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void); +SQLITE_PRIVATE void sqlite3RegisterJsonFunctions(void); SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3*); +#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON) +SQLITE_PRIVATE int sqlite3JsonTableFunctions(sqlite3*); +#endif SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3*); SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3*); SQLITE_PRIVATE void sqlite3ChangeCookie(Parse*, int);@@ -20217,7 +20168,8 @@ #endif
SQLITE_PRIVATE int sqlite3JoinType(Parse*, Token*, Token*, Token*); SQLITE_PRIVATE int sqlite3ColumnIndex(Table *pTab, const char *zCol); -SQLITE_PRIVATE void sqlite3SetJoinExpr(Expr*,int); +SQLITE_PRIVATE void sqlite3SrcItemColumnUsed(SrcItem*,int); +SQLITE_PRIVATE void sqlite3SetJoinExpr(Expr*,int,u32); SQLITE_PRIVATE void sqlite3CreateForeignKey(Parse*, ExprList*, Token*, ExprList*, int); SQLITE_PRIVATE void sqlite3DeferForeignKey(Parse*, int); #ifndef SQLITE_OMIT_AUTHORIZATION@@ -20253,14 +20205,8 @@ SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte);
SQLITE_PRIVATE u32 sqlite3Utf8Read(const u8**); SQLITE_PRIVATE LogEst sqlite3LogEst(u64); SQLITE_PRIVATE LogEst sqlite3LogEstAdd(LogEst,LogEst); -#ifndef SQLITE_OMIT_VIRTUALTABLE SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double); -#endif -#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \ - defined(SQLITE_ENABLE_STAT4) || \ - defined(SQLITE_EXPLAIN_ESTIMATED_ROWS) SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst); -#endif SQLITE_PRIVATE VList *sqlite3VListAdd(sqlite3*,VList*,const char*,int,int); SQLITE_PRIVATE const char *sqlite3VListNumToName(VList*,int); SQLITE_PRIVATE int sqlite3VListNameToNum(VList*,const char*,int);@@ -20295,7 +20241,7 @@ SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3*, Index*);
SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe*, Table*, int); SQLITE_PRIVATE char sqlite3CompareAffinity(const Expr *pExpr, char aff2); SQLITE_PRIVATE int sqlite3IndexAffinityOk(const Expr *pExpr, char idx_affinity); -SQLITE_PRIVATE char sqlite3TableColumnAffinity(Table*,int); +SQLITE_PRIVATE char sqlite3TableColumnAffinity(const Table*,int); SQLITE_PRIVATE char sqlite3ExprAffinity(const Expr *pExpr); SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8); SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char*, i64*);@@ -20324,14 +20270,14 @@ SQLITE_PRIVATE void sqlite3SetTextEncoding(sqlite3 *db, u8);
SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr); SQLITE_PRIVATE CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, const Expr *pExpr); SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse*,const Expr*,const Expr*); -SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*, int); -SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*); +SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(const Parse *pParse, Expr*, const Token*, int); +SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(const Parse*,Expr*,const char*); SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr*); SQLITE_PRIVATE Expr *sqlite3ExprSkipCollateAndLikely(Expr*); SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *, CollSeq *); SQLITE_PRIVATE int sqlite3WritableSchema(sqlite3*); SQLITE_PRIVATE int sqlite3CheckObjectName(Parse*, const char*,const char*,const char*); -SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *, int); +SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *, i64); SQLITE_PRIVATE int sqlite3AddInt64(i64*,i64); SQLITE_PRIVATE int sqlite3SubInt64(i64*,i64); SQLITE_PRIVATE int sqlite3MulInt64(i64*,i64);@@ -20356,11 +20302,15 @@ SQLITE_PRIVATE sqlite3_value *sqlite3ValueNew(sqlite3 *);
#ifndef SQLITE_OMIT_UTF16 SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *, const void*, int, u8); #endif -SQLITE_PRIVATE int sqlite3ValueFromExpr(sqlite3 *, Expr *, u8, u8, sqlite3_value **); +SQLITE_PRIVATE int sqlite3ValueFromExpr(sqlite3 *, const Expr *, u8, u8, sqlite3_value **); SQLITE_PRIVATE void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8); #ifndef SQLITE_AMALGAMATION SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[]; SQLITE_PRIVATE const char sqlite3StrBINARY[]; +SQLITE_PRIVATE const unsigned char sqlite3StdTypeLen[]; +SQLITE_PRIVATE const char sqlite3StdTypeAffinity[]; +SQLITE_PRIVATE const char sqlite3StdTypeMap[]; +SQLITE_PRIVATE const char *sqlite3StdType[]; SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[]; SQLITE_PRIVATE const unsigned char *sqlite3aLTb; SQLITE_PRIVATE const unsigned char *sqlite3aEQb;@@ -20404,9 +20354,9 @@ SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);
SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *, Table *, int, int); SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *); SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *, SrcList *); -SQLITE_PRIVATE void sqlite3AlterDropColumn(Parse*, SrcList*, Token*); -SQLITE_PRIVATE void *sqlite3RenameTokenMap(Parse*, void*, Token*); -SQLITE_PRIVATE void sqlite3RenameTokenRemap(Parse*, void *pTo, void *pFrom); +SQLITE_PRIVATE void sqlite3AlterDropColumn(Parse*, SrcList*, const Token*); +SQLITE_PRIVATE const void *sqlite3RenameTokenMap(Parse*, const void*, const Token*); +SQLITE_PRIVATE void sqlite3RenameTokenRemap(Parse*, const void *pTo, const void *pFrom); SQLITE_PRIVATE void sqlite3RenameExprUnmap(Parse*, Expr*); SQLITE_PRIVATE void sqlite3RenameExprlistUnmap(Parse*, ExprList*); SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*);@@ -20443,15 +20393,20 @@ void (*)(sqlite3_context*,int,sqlite3_value **),
FuncDestructor *pDestructor ); SQLITE_PRIVATE void sqlite3NoopDestructor(void*); -SQLITE_PRIVATE void sqlite3OomFault(sqlite3*); +SQLITE_PRIVATE void *sqlite3OomFault(sqlite3*); SQLITE_PRIVATE void sqlite3OomClear(sqlite3*); SQLITE_PRIVATE int sqlite3ApiExit(sqlite3 *db, int); SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *); SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int); +SQLITE_PRIVATE int sqlite3StrAccumEnlarge(StrAccum*, int); SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum*); +SQLITE_PRIVATE void sqlite3StrAccumSetError(StrAccum*, u8); +SQLITE_PRIVATE void sqlite3ResultStrAccum(sqlite3_context*,StrAccum*); SQLITE_PRIVATE void sqlite3SelectDestInit(SelectDest*,int,int); SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *, SrcList *, int, int); +SQLITE_PRIVATE void sqlite3RecordErrorByteOffset(sqlite3*,const char*); +SQLITE_PRIVATE void sqlite3RecordErrorOffsetOfExpr(sqlite3*,const Expr*); SQLITE_PRIVATE void sqlite3BackupRestart(sqlite3_backup *); SQLITE_PRIVATE void sqlite3BackupUpdate(sqlite3_backup *, Pgno, const u8 *);@@ -20502,7 +20457,7 @@ SQLITE_PRIVATE int sqlite3Utf8To8(unsigned char*);
#endif #ifdef SQLITE_OMIT_VIRTUALTABLE -# define sqlite3VtabClear(Y) +# define sqlite3VtabClear(D,T) # define sqlite3VtabSync(X,Y) SQLITE_OK # define sqlite3VtabRollback(X) # define sqlite3VtabCommit(X)@@ -20539,9 +20494,11 @@ SQLITE_PRIVATE int sqlite3ReadOnlyShadowTables(sqlite3 *db);
#ifndef SQLITE_OMIT_VIRTUALTABLE SQLITE_PRIVATE int sqlite3ShadowTableName(sqlite3 *db, const char *zName); SQLITE_PRIVATE int sqlite3IsShadowTableOf(sqlite3*,Table*,const char*); +SQLITE_PRIVATE void sqlite3MarkAllShadowTablesOf(sqlite3*, Table*); #else # define sqlite3ShadowTableName(A,B) 0 # define sqlite3IsShadowTableOf(A,B,C) 0 +# define sqlite3MarkAllShadowTablesOf(A,B) #endif SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse*,Module*); SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3*,Module*);@@ -20554,11 +20511,17 @@ SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **);
SQLITE_PRIVATE int sqlite3VtabCallConnect(Parse*, Table*); SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3*, int, const char *); SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *, VTable *); + SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*); +#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \ + && !defined(SQLITE_OMIT_VIRTUALTABLE) +SQLITE_PRIVATE void sqlite3VtabUsesAllSchemas(sqlite3_index_info*); +#endif SQLITE_PRIVATE sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*); SQLITE_PRIVATE int sqlite3VdbeParameterIndex(Vdbe*, const char*, int); SQLITE_PRIVATE int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *); -SQLITE_PRIVATE void sqlite3ParserReset(Parse*); +SQLITE_PRIVATE void sqlite3ParseObjectInit(Parse*,sqlite3*); +SQLITE_PRIVATE void sqlite3ParseObjectReset(Parse*); SQLITE_PRIVATE void *sqlite3ParserAddCleanup(Parse*,void(*)(sqlite3*,void*),void*); #ifdef SQLITE_ENABLE_NORMALIZE SQLITE_PRIVATE char *sqlite3Normalize(Vdbe*, const char*);@@ -20584,7 +20547,7 @@ # define sqlite3CteNew(P,T,E,S) ((void*)0)
# define sqlite3CteDelete(D,C) # define sqlite3CteWithAdd(P,W,C) ((void*)0) # define sqlite3WithDelete(x,y) -# define sqlite3WithPush(x,y,z) +# define sqlite3WithPush(x,y,z) ((void*)0) #endif #ifndef SQLITE_OMIT_UPSERT SQLITE_PRIVATE Upsert *sqlite3UpsertNew(sqlite3*,ExprList*,Expr*,ExprList*,Expr*,Upsert*);@@ -20617,6 +20580,7 @@ SQLITE_PRIVATE void sqlite3FkActions(Parse*, Table*, ExprList*, int, int*, int);
SQLITE_PRIVATE int sqlite3FkRequired(Parse*, Table*, int*, int); SQLITE_PRIVATE u32 sqlite3FkOldmask(Parse*, Table*); SQLITE_PRIVATE FKey *sqlite3FkReferences(Table *); +SQLITE_PRIVATE void sqlite3FkClearTriggerCache(sqlite3*,int); #else #define sqlite3FkActions(a,b,c,d,e,f) #define sqlite3FkCheck(a,b,c,d,e,f)@@ -20624,6 +20588,7 @@ #define sqlite3FkDropTable(a,b,c)
#define sqlite3FkOldmask(a,b) 0 #define sqlite3FkRequired(a,b,c,d) 0 #define sqlite3FkReferences(a) 0 + #define sqlite3FkClearTriggerCache(a,b) #endif #ifndef SQLITE_OMIT_FOREIGN_KEY SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *, Table*);@@ -20681,7 +20646,7 @@ SQLITE_PRIVATE void sqlite3MemJournalOpen(sqlite3_file *);
SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p); #if SQLITE_MAX_EXPR_DEPTH>0 -SQLITE_PRIVATE int sqlite3SelectExprHeight(Select *); +SQLITE_PRIVATE int sqlite3SelectExprHeight(const Select *); SQLITE_PRIVATE int sqlite3ExprCheckHeight(Parse*, int); #else #define sqlite3SelectExprHeight(x) 0@@ -20752,8 +20717,8 @@ ** play when the SQLITE_MEMDEBUG compile-time option is used.
*/ #ifdef SQLITE_MEMDEBUG SQLITE_PRIVATE void sqlite3MemdebugSetType(void*,u8); -SQLITE_PRIVATE int sqlite3MemdebugHasType(void*,u8); -SQLITE_PRIVATE int sqlite3MemdebugNoType(void*,u8); +SQLITE_PRIVATE int sqlite3MemdebugHasType(const void*,u8); +SQLITE_PRIVATE int sqlite3MemdebugNoType(const void*,u8); #else # define sqlite3MemdebugSetType(X,Y) /* no-op */ # define sqlite3MemdebugHasType(X,Y) 1@@ -20778,10 +20743,10 @@ #if defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST)
SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3*); #endif -SQLITE_PRIVATE int sqlite3ExprVectorSize(Expr *pExpr); -SQLITE_PRIVATE int sqlite3ExprIsVector(Expr *pExpr); +SQLITE_PRIVATE int sqlite3ExprVectorSize(const Expr *pExpr); +SQLITE_PRIVATE int sqlite3ExprIsVector(const Expr *pExpr); SQLITE_PRIVATE Expr *sqlite3VectorFieldSubexpr(Expr*, int); -SQLITE_PRIVATE Expr *sqlite3ExprForVectorField(Parse*,Expr*,int); +SQLITE_PRIVATE Expr *sqlite3ExprForVectorField(Parse*,Expr*,int,int); SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse*, Expr*); #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS@@ -20791,6 +20756,993 @@
#endif /* SQLITEINT_H */ /************** End of sqliteInt.h *******************************************/ +/************** Begin file os_common.h ***************************************/ +/* +** 2004 May 22 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file contains macros and a little bit of code that is common to +** all of the platform-specific files (os_*.c) and is #included into those +** files. +** +** This file should be #included by the os_*.c files only. It is not a +** general purpose header file. +*/ +#ifndef _OS_COMMON_H_ +#define _OS_COMMON_H_ + +/* +** At least two bugs have slipped in because we changed the MEMORY_DEBUG +** macro to SQLITE_DEBUG and some older makefiles have not yet made the +** switch. The following code should catch this problem at compile-time. +*/ +#ifdef MEMORY_DEBUG +# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead." +#endif + +/* +** Macros for performance tracing. Normally turned off. Only works +** on i486 hardware. +*/ +#ifdef SQLITE_PERFORMANCE_TRACE + +/* +** hwtime.h contains inline assembler code for implementing +** high-performance timing routines. +*/ +/************** Include hwtime.h in the middle of os_common.h ****************/ +/************** Begin file hwtime.h ******************************************/ +/* +** 2008 May 27 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file contains inline asm code for retrieving "high-performance" +** counters for x86 and x86_64 class CPUs. +*/ +#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 +** profiling. +*/ +#if !defined(__STRICT_ANSI__) && \ + (defined(__GNUC__) || defined(_MSC_VER)) && \ + (defined(i386) || defined(__i386__) || defined(_M_IX86)) + + #if defined(__GNUC__) + + __inline__ sqlite_uint64 sqlite3Hwtime(void){ + unsigned int lo, hi; + __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); + return (sqlite_uint64)hi << 32 | lo; + } + + #elif defined(_MSC_VER) + + __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){ + __asm { + rdtsc + ret ; return value at EDX:EAX + } + } + + #endif + +#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__)) + + __inline__ sqlite_uint64 sqlite3Hwtime(void){ + unsigned long val; + __asm__ __volatile__ ("rdtsc" : "=A" (val)); + return val; + } + +#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__)) + + __inline__ sqlite_uint64 sqlite3Hwtime(void){ + unsigned long long retval; + unsigned long junk; + __asm__ __volatile__ ("\n\ + 1: mftbu %1\n\ + mftb %L0\n\ + mftbu %0\n\ + cmpw %0,%1\n\ + bne 1b" + : "=r" (retval), "=r" (junk)); + return retval; + } + +#else + + /* + ** asm() is needed for hardware timing support. Without asm(), + ** disable the sqlite3Hwtime() routine. + ** + ** sqlite3Hwtime() is only used for some obscure debugging + ** and analysis configurations, not in any deliverable, so this + ** should not be a great loss. + */ +SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } + +#endif + +#endif /* !defined(SQLITE_HWTIME_H) */ + +/************** End of hwtime.h **********************************************/ +/************** Continuing where we left off in os_common.h ******************/ + +static sqlite_uint64 g_start; +static sqlite_uint64 g_elapsed; +#define TIMER_START g_start=sqlite3Hwtime() +#define TIMER_END g_elapsed=sqlite3Hwtime()-g_start +#define TIMER_ELAPSED g_elapsed +#else +#define TIMER_START +#define TIMER_END +#define TIMER_ELAPSED ((sqlite_uint64)0) +#endif + +/* +** If we compile with the SQLITE_TEST macro set, then the following block +** of code will give us the ability to simulate a disk I/O error. This +** is used for testing the I/O recovery logic. +*/ +#if defined(SQLITE_TEST) +SQLITE_API extern int sqlite3_io_error_hit; +SQLITE_API extern int sqlite3_io_error_hardhit; +SQLITE_API extern int sqlite3_io_error_pending; +SQLITE_API extern int sqlite3_io_error_persist; +SQLITE_API extern int sqlite3_io_error_benign; +SQLITE_API extern int sqlite3_diskfull_pending; +SQLITE_API extern int sqlite3_diskfull; +#define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X) +#define SimulateIOError(CODE) \ + if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \ + || sqlite3_io_error_pending-- == 1 ) \ + { local_ioerr(); CODE; } +static void local_ioerr(){ + IOTRACE(("IOERR\n")); + sqlite3_io_error_hit++; + if( !sqlite3_io_error_benign ) sqlite3_io_error_hardhit++; +} +#define SimulateDiskfullError(CODE) \ + if( sqlite3_diskfull_pending ){ \ + if( sqlite3_diskfull_pending == 1 ){ \ + local_ioerr(); \ + sqlite3_diskfull = 1; \ + sqlite3_io_error_hit = 1; \ + CODE; \ + }else{ \ + sqlite3_diskfull_pending--; \ + } \ + } +#else +#define SimulateIOErrorBenign(X) +#define SimulateIOError(A) +#define SimulateDiskfullError(A) +#endif /* defined(SQLITE_TEST) */ + +/* +** When testing, keep a count of the number of open files. +*/ +#if defined(SQLITE_TEST) +SQLITE_API extern int sqlite3_open_file_count; +#define OpenCounter(X) sqlite3_open_file_count+=(X) +#else +#define OpenCounter(X) +#endif /* defined(SQLITE_TEST) */ + +#endif /* !defined(_OS_COMMON_H_) */ + +/************** End of os_common.h *******************************************/ +/************** Begin file ctime.c *******************************************/ +/* DO NOT EDIT! +** This file is automatically generated by the script in the canonical +** SQLite source tree at tool/mkctimec.tcl. +** +** To modify this header, edit any of the various lists in that script +** which specify categories of generated conditionals in this file. +*/ + +/* +** 2010 February 23 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** +** This file implements routines used to report what compile-time options +** SQLite was built with. +*/ +#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS /* IMP: R-16824-07538 */ + +/* +** Include the configuration header output by 'configure' if we're using the +** autoconf-based build +*/ +#if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H) +/* #include "config.h" */ +#define SQLITECONFIG_H 1 +#endif + +/* These macros are provided to "stringify" the value of the define +** for those options in which the value is meaningful. */ +#define CTIMEOPT_VAL_(opt) #opt +#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt) + +/* Like CTIMEOPT_VAL, but especially for SQLITE_DEFAULT_LOOKASIDE. This +** option requires a separate macro because legal values contain a single +** comma. e.g. (-DSQLITE_DEFAULT_LOOKASIDE="100,100") */ +#define CTIMEOPT_VAL2_(opt1,opt2) #opt1 "," #opt2 +#define CTIMEOPT_VAL2(opt) CTIMEOPT_VAL2_(opt) +/* #include "sqliteInt.h" */ + +/* +** An array of names of all compile-time options. This array should +** be sorted A-Z. +** +** This array looks large, but in a typical installation actually uses +** only a handful of compile-time options, so most times this array is usually +** rather short and uses little memory space. +*/ +static const char * const sqlite3azCompileOpt[] = { + +** sqlite3ExprIfTrue: Jump to dest if true + "32BIT_ROWID", +#endif +#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC + "4_BYTE_ALIGNED_MALLOC", +#endif +#ifdef SQLITE_64BIT_STATS + "64BIT_STATS", +#endif +#ifdef SQLITE_ALLOW_COVERING_INDEX_SCAN +# if SQLITE_ALLOW_COVERING_INDEX_SCAN != 1 + "ALLOW_COVERING_INDEX_SCAN=" CTIMEOPT_VAL(SQLITE_ALLOW_COVERING_INDEX_SCAN), +# endif +#endif +#ifdef SQLITE_ALLOW_URI_AUTHORITY + "ALLOW_URI_AUTHORITY", +#endif +#ifdef SQLITE_ATOMIC_INTRINSICS + "ATOMIC_INTRINSICS=" CTIMEOPT_VAL(SQLITE_ATOMIC_INTRINSICS), +#endif +#ifdef SQLITE_BITMASK_TYPE + "BITMASK_TYPE=" CTIMEOPT_VAL(SQLITE_BITMASK_TYPE), +#endif +#ifdef SQLITE_BUG_COMPATIBLE_20160819 + "BUG_COMPATIBLE_20160819", +#endif +#ifdef SQLITE_CASE_SENSITIVE_LIKE + "CASE_SENSITIVE_LIKE", +#endif +#ifdef 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 +#ifdef SQLITE_COVERAGE_TEST + "COVERAGE_TEST", +#endif +#ifdef SQLITE_DEBUG + "DEBUG", +#endif +#ifdef SQLITE_DEFAULT_AUTOMATIC_INDEX + "DEFAULT_AUTOMATIC_INDEX", +#endif +#ifdef SQLITE_DEFAULT_AUTOVACUUM + "DEFAULT_AUTOVACUUM", +#endif +#ifdef SQLITE_DEFAULT_CACHE_SIZE + "DEFAULT_CACHE_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_CACHE_SIZE), +#endif +#ifdef SQLITE_DEFAULT_CKPTFULLFSYNC + "DEFAULT_CKPTFULLFSYNC", +#endif +#ifdef SQLITE_DEFAULT_FILE_FORMAT + "DEFAULT_FILE_FORMAT=" CTIMEOPT_VAL(SQLITE_DEFAULT_FILE_FORMAT), +#endif +#ifdef SQLITE_DEFAULT_FILE_PERMISSIONS + "DEFAULT_FILE_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_FILE_PERMISSIONS), +#endif +#ifdef SQLITE_DEFAULT_FOREIGN_KEYS + "DEFAULT_FOREIGN_KEYS", +#endif +#ifdef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT + "DEFAULT_JOURNAL_SIZE_LIMIT=" CTIMEOPT_VAL(SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT), +#endif +#ifdef SQLITE_DEFAULT_LOCKING_MODE + "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE), +#endif +#ifdef SQLITE_DEFAULT_LOOKASIDE + "DEFAULT_LOOKASIDE=" CTIMEOPT_VAL2(SQLITE_DEFAULT_LOOKASIDE), +#endif +#ifdef SQLITE_DEFAULT_MEMSTATUS +# if SQLITE_DEFAULT_MEMSTATUS != 1 + "DEFAULT_MEMSTATUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_MEMSTATUS), +# endif +#endif +#ifdef SQLITE_DEFAULT_MMAP_SIZE + "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE), +#endif +#ifdef SQLITE_DEFAULT_PAGE_SIZE + "DEFAULT_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_PAGE_SIZE), +#endif +#ifdef SQLITE_DEFAULT_PCACHE_INITSZ + "DEFAULT_PCACHE_INITSZ=" CTIMEOPT_VAL(SQLITE_DEFAULT_PCACHE_INITSZ), +#endif +#ifdef SQLITE_DEFAULT_PROXYDIR_PERMISSIONS + "DEFAULT_PROXYDIR_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_PROXYDIR_PERMISSIONS), +#endif +#ifdef SQLITE_DEFAULT_RECURSIVE_TRIGGERS + "DEFAULT_RECURSIVE_TRIGGERS", +#endif +#ifdef SQLITE_DEFAULT_ROWEST + "DEFAULT_ROWEST=" CTIMEOPT_VAL(SQLITE_DEFAULT_ROWEST), +#endif +#ifdef SQLITE_DEFAULT_SECTOR_SIZE + "DEFAULT_SECTOR_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_SECTOR_SIZE), +#endif +#ifdef SQLITE_DEFAULT_SYNCHRONOUS + "DEFAULT_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_SYNCHRONOUS), +#endif +#ifdef SQLITE_DEFAULT_WAL_AUTOCHECKPOINT + "DEFAULT_WAL_AUTOCHECKPOINT=" CTIMEOPT_VAL(SQLITE_DEFAULT_WAL_AUTOCHECKPOINT), +#endif +#ifdef SQLITE_DEFAULT_WAL_SYNCHRONOUS + "DEFAULT_WAL_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WAL_SYNCHRONOUS), +#endif +#ifdef SQLITE_DEFAULT_WORKER_THREADS + "DEFAULT_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WORKER_THREADS), +#endif +#ifdef SQLITE_DIRECT_OVERFLOW_READ + "DIRECT_OVERFLOW_READ", +#endif +#ifdef SQLITE_DISABLE_DIRSYNC + "DISABLE_DIRSYNC", +#endif +#ifdef SQLITE_DISABLE_FTS3_UNICODE + "DISABLE_FTS3_UNICODE", +#endif +#ifdef SQLITE_DISABLE_FTS4_DEFERRED + "DISABLE_FTS4_DEFERRED", +#endif +#ifdef SQLITE_DISABLE_INTRINSIC + "DISABLE_INTRINSIC", +#endif +#ifdef SQLITE_DISABLE_LFS + "DISABLE_LFS", +#endif +#ifdef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS + "DISABLE_PAGECACHE_OVERFLOW_STATS", +#endif +#ifdef SQLITE_DISABLE_SKIPAHEAD_DISTINCT + "DISABLE_SKIPAHEAD_DISTINCT", +#endif +#ifdef SQLITE_ENABLE_8_3_NAMES + "ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES), +#endif +#ifdef SQLITE_ENABLE_API_ARMOR + "ENABLE_API_ARMOR", +#endif +#ifdef SQLITE_ENABLE_ATOMIC_WRITE + "ENABLE_ATOMIC_WRITE", +#endif +#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE + "ENABLE_BATCH_ATOMIC_WRITE", +#endif +#ifdef SQLITE_ENABLE_BYTECODE_VTAB + "ENABLE_BYTECODE_VTAB", +#endif +#ifdef SQLITE_ENABLE_CEROD + "ENABLE_CEROD=" CTIMEOPT_VAL(SQLITE_ENABLE_CEROD), +#endif +#ifdef SQLITE_ENABLE_COLUMN_METADATA + "ENABLE_COLUMN_METADATA", +#endif +#ifdef SQLITE_ENABLE_COLUMN_USED_MASK + "ENABLE_COLUMN_USED_MASK", +#endif +#ifdef SQLITE_ENABLE_COSTMULT + "ENABLE_COSTMULT", +#endif +#ifdef SQLITE_ENABLE_CURSOR_HINTS + "ENABLE_CURSOR_HINTS", +#endif +#ifdef SQLITE_ENABLE_DBPAGE_VTAB + "ENABLE_DBPAGE_VTAB", +#endif +#ifdef SQLITE_ENABLE_DBSTAT_VTAB + "ENABLE_DBSTAT_VTAB", +#endif +#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT + "ENABLE_EXPENSIVE_ASSERT", +#endif +#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS + "ENABLE_EXPLAIN_COMMENTS", +#endif +#ifdef SQLITE_ENABLE_FTS3 + "ENABLE_FTS3", +#endif +#ifdef SQLITE_ENABLE_FTS3_PARENTHESIS + "ENABLE_FTS3_PARENTHESIS", +#endif +#ifdef SQLITE_ENABLE_FTS3_TOKENIZER + "ENABLE_FTS3_TOKENIZER", +#endif +#ifdef SQLITE_ENABLE_FTS4 + "ENABLE_FTS4", +#endif +#ifdef SQLITE_ENABLE_FTS5 + "ENABLE_FTS5", +#endif +#ifdef SQLITE_ENABLE_GEOPOLY + "ENABLE_GEOPOLY", +#endif +#ifdef SQLITE_ENABLE_HIDDEN_COLUMNS + "ENABLE_HIDDEN_COLUMNS", +#endif +#ifdef SQLITE_ENABLE_ICU + "ENABLE_ICU", +#endif +#ifdef SQLITE_ENABLE_IOTRACE + "ENABLE_IOTRACE", +#endif +#ifdef SQLITE_ENABLE_LOAD_EXTENSION + "ENABLE_LOAD_EXTENSION", +#endif +#ifdef SQLITE_ENABLE_LOCKING_STYLE + "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE), +#endif +#ifdef SQLITE_ENABLE_MATH_FUNCTIONS + "ENABLE_MATH_FUNCTIONS", +#endif +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT + "ENABLE_MEMORY_MANAGEMENT", +#endif +#ifdef SQLITE_ENABLE_MEMSYS3 + "ENABLE_MEMSYS3", +#endif +#ifdef SQLITE_ENABLE_MEMSYS5 + "ENABLE_MEMSYS5", +#endif +#ifdef SQLITE_ENABLE_MULTIPLEX + "ENABLE_MULTIPLEX", +#endif +#ifdef SQLITE_ENABLE_NORMALIZE + "ENABLE_NORMALIZE", +#endif +#ifdef SQLITE_ENABLE_NULL_TRIM + "ENABLE_NULL_TRIM", +#endif +#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC + "ENABLE_OFFSET_SQL_FUNC", +#endif +#ifdef SQLITE_ENABLE_OVERSIZE_CELL_CHECK + "ENABLE_OVERSIZE_CELL_CHECK", +#endif +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK + "ENABLE_PREUPDATE_HOOK", +#endif +#ifdef SQLITE_ENABLE_QPSG + "ENABLE_QPSG", +#endif +#ifdef SQLITE_ENABLE_RBU + "ENABLE_RBU", +#endif +#ifdef SQLITE_ENABLE_RTREE + "ENABLE_RTREE", +#endif +#ifdef SQLITE_ENABLE_SESSION + "ENABLE_SESSION", +#endif +#ifdef SQLITE_ENABLE_SNAPSHOT + "ENABLE_SNAPSHOT", +#endif +#ifdef SQLITE_ENABLE_SORTER_REFERENCES + "ENABLE_SORTER_REFERENCES", +#endif +#ifdef SQLITE_ENABLE_SQLLOG + "ENABLE_SQLLOG", +#endif +#ifdef SQLITE_ENABLE_STAT4 + "ENABLE_STAT4", +#endif +#ifdef SQLITE_ENABLE_STMTVTAB + "ENABLE_STMTVTAB", +#endif +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + "ENABLE_STMT_SCANSTATUS", +#endif +#ifdef SQLITE_ENABLE_TREETRACE + "ENABLE_TREETRACE", +#endif +#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION + "ENABLE_UNKNOWN_SQL_FUNCTION", +#endif +#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY + "ENABLE_UNLOCK_NOTIFY", +#endif +#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT + "ENABLE_UPDATE_DELETE_LIMIT", +#endif +#ifdef SQLITE_ENABLE_URI_00_ERROR + "ENABLE_URI_00_ERROR", +#endif +#ifdef SQLITE_ENABLE_VFSTRACE + "ENABLE_VFSTRACE", +#endif +#ifdef SQLITE_ENABLE_WHERETRACE + "ENABLE_WHERETRACE", +#endif +#ifdef SQLITE_ENABLE_ZIPVFS + "ENABLE_ZIPVFS", +#endif +#ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS + "EXPLAIN_ESTIMATED_ROWS", +#endif +#ifdef SQLITE_EXTRA_IFNULLROW + "EXTRA_IFNULLROW", +#endif +#ifdef SQLITE_EXTRA_INIT + "EXTRA_INIT=" CTIMEOPT_VAL(SQLITE_EXTRA_INIT), +#endif +#ifdef SQLITE_EXTRA_SHUTDOWN + "EXTRA_SHUTDOWN=" CTIMEOPT_VAL(SQLITE_EXTRA_SHUTDOWN), +#endif +#ifdef SQLITE_FTS3_MAX_EXPR_DEPTH + "FTS3_MAX_EXPR_DEPTH=" CTIMEOPT_VAL(SQLITE_FTS3_MAX_EXPR_DEPTH), +#endif +#ifdef SQLITE_FTS5_ENABLE_TEST_MI + "FTS5_ENABLE_TEST_MI", +#endif +#ifdef SQLITE_FTS5_NO_WITHOUT_ROWID + "FTS5_NO_WITHOUT_ROWID", +#endif +#if HAVE_ISNAN || SQLITE_HAVE_ISNAN + "HAVE_ISNAN", +#endif +#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX +# if SQLITE_HOMEGROWN_RECURSIVE_MUTEX != 1 + "HOMEGROWN_RECURSIVE_MUTEX=" CTIMEOPT_VAL(SQLITE_HOMEGROWN_RECURSIVE_MUTEX), +# endif +#endif +#ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS + "IGNORE_AFP_LOCK_ERRORS", +#endif +#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS + "IGNORE_FLOCK_LOCK_ERRORS", +#endif +#ifdef SQLITE_INLINE_MEMCPY + "INLINE_MEMCPY", +#endif +#ifdef SQLITE_INT64_TYPE + "INT64_TYPE", +#endif +#ifdef SQLITE_INTEGRITY_CHECK_ERROR_MAX + "INTEGRITY_CHECK_ERROR_MAX=" CTIMEOPT_VAL(SQLITE_INTEGRITY_CHECK_ERROR_MAX), +#endif +#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS + "LIKE_DOESNT_MATCH_BLOBS", +#endif +#ifdef SQLITE_LOCK_TRACE + "LOCK_TRACE", +#endif +#ifdef SQLITE_LOG_CACHE_SPILL + "LOG_CACHE_SPILL", +#endif +#ifdef SQLITE_MALLOC_SOFT_LIMIT + "MALLOC_SOFT_LIMIT=" CTIMEOPT_VAL(SQLITE_MALLOC_SOFT_LIMIT), +#endif +#ifdef SQLITE_MAX_ATTACHED + "MAX_ATTACHED=" CTIMEOPT_VAL(SQLITE_MAX_ATTACHED), +#endif +#ifdef SQLITE_MAX_COLUMN + "MAX_COLUMN=" CTIMEOPT_VAL(SQLITE_MAX_COLUMN), +#endif +#ifdef SQLITE_MAX_COMPOUND_SELECT + "MAX_COMPOUND_SELECT=" CTIMEOPT_VAL(SQLITE_MAX_COMPOUND_SELECT), +#endif +#ifdef SQLITE_MAX_DEFAULT_PAGE_SIZE + "MAX_DEFAULT_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_DEFAULT_PAGE_SIZE), +#endif +#ifdef SQLITE_MAX_EXPR_DEPTH + "MAX_EXPR_DEPTH=" CTIMEOPT_VAL(SQLITE_MAX_EXPR_DEPTH), +#endif +#ifdef SQLITE_MAX_FUNCTION_ARG + "MAX_FUNCTION_ARG=" CTIMEOPT_VAL(SQLITE_MAX_FUNCTION_ARG), +#endif +#ifdef SQLITE_MAX_LENGTH + "MAX_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_LENGTH), +#endif +#ifdef SQLITE_MAX_LIKE_PATTERN_LENGTH + "MAX_LIKE_PATTERN_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_LIKE_PATTERN_LENGTH), +#endif +#ifdef SQLITE_MAX_MEMORY + "MAX_MEMORY=" CTIMEOPT_VAL(SQLITE_MAX_MEMORY), +#endif +#ifdef SQLITE_MAX_MMAP_SIZE + "MAX_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE), +#endif +#ifdef SQLITE_MAX_MMAP_SIZE_ + "MAX_MMAP_SIZE_=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE_), +#endif +#ifdef SQLITE_MAX_PAGE_COUNT + "MAX_PAGE_COUNT=" CTIMEOPT_VAL(SQLITE_MAX_PAGE_COUNT), +#endif +#ifdef SQLITE_MAX_PAGE_SIZE + "MAX_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_PAGE_SIZE), +#endif +#ifdef SQLITE_MAX_SCHEMA_RETRY + "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY), +#endif +#ifdef SQLITE_MAX_SQL_LENGTH + "MAX_SQL_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_SQL_LENGTH), +#endif +#ifdef SQLITE_MAX_TRIGGER_DEPTH + "MAX_TRIGGER_DEPTH=" CTIMEOPT_VAL(SQLITE_MAX_TRIGGER_DEPTH), +#endif +#ifdef SQLITE_MAX_VARIABLE_NUMBER + "MAX_VARIABLE_NUMBER=" CTIMEOPT_VAL(SQLITE_MAX_VARIABLE_NUMBER), +#endif +#ifdef SQLITE_MAX_VDBE_OP + "MAX_VDBE_OP=" CTIMEOPT_VAL(SQLITE_MAX_VDBE_OP), +#endif +#ifdef SQLITE_MAX_WORKER_THREADS + "MAX_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_MAX_WORKER_THREADS), +#endif +#ifdef SQLITE_MEMDEBUG + "MEMDEBUG", +#endif +#ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT + "MIXED_ENDIAN_64BIT_FLOAT", +#endif +#ifdef SQLITE_MMAP_READWRITE + "MMAP_READWRITE", +#endif +#ifdef SQLITE_MUTEX_NOOP + "MUTEX_NOOP", +#endif +#ifdef SQLITE_MUTEX_OMIT + "MUTEX_OMIT", +#endif +#ifdef SQLITE_MUTEX_PTHREADS + "MUTEX_PTHREADS", +#endif +#ifdef SQLITE_MUTEX_W32 + "MUTEX_W32", +#endif +#ifdef SQLITE_NEED_ERR_NAME + "NEED_ERR_NAME", +#endif +#ifdef SQLITE_NO_SYNC + "NO_SYNC", +#endif +#ifdef SQLITE_OMIT_ALTERTABLE + "OMIT_ALTERTABLE", +#endif +#ifdef SQLITE_OMIT_ANALYZE + "OMIT_ANALYZE", +#endif +#ifdef SQLITE_OMIT_ATTACH + "OMIT_ATTACH", +#endif +#ifdef SQLITE_OMIT_AUTHORIZATION + "OMIT_AUTHORIZATION", +#endif +#ifdef SQLITE_OMIT_AUTOINCREMENT + "OMIT_AUTOINCREMENT", +#endif +#ifdef SQLITE_OMIT_AUTOINIT + "OMIT_AUTOINIT", +#endif +#ifdef SQLITE_OMIT_AUTOMATIC_INDEX + "OMIT_AUTOMATIC_INDEX", +#endif +#ifdef SQLITE_OMIT_AUTORESET + "OMIT_AUTORESET", +#endif +#ifdef SQLITE_OMIT_AUTOVACUUM + "OMIT_AUTOVACUUM", +#endif +#ifdef SQLITE_OMIT_BETWEEN_OPTIMIZATION + "OMIT_BETWEEN_OPTIMIZATION", +#endif +#ifdef SQLITE_OMIT_BLOB_LITERAL + "OMIT_BLOB_LITERAL", +#endif +#ifdef SQLITE_OMIT_CAST + "OMIT_CAST", +#endif +#ifdef SQLITE_OMIT_CHECK + "OMIT_CHECK", +#endif +#ifdef SQLITE_OMIT_COMPLETE + "OMIT_COMPLETE", +#endif +#ifdef SQLITE_OMIT_COMPOUND_SELECT + "OMIT_COMPOUND_SELECT", +#endif +#ifdef SQLITE_OMIT_CONFLICT_CLAUSE + "OMIT_CONFLICT_CLAUSE", +#endif +#ifdef SQLITE_OMIT_CTE + "OMIT_CTE", +#endif +#if defined(SQLITE_OMIT_DATETIME_FUNCS) || defined(SQLITE_OMIT_FLOATING_POINT) + "OMIT_DATETIME_FUNCS", +#endif +#ifdef SQLITE_OMIT_DECLTYPE + "OMIT_DECLTYPE", +#endif +#ifdef SQLITE_OMIT_DEPRECATED + "OMIT_DEPRECATED", +#endif +#ifdef SQLITE_OMIT_DESERIALIZE + "OMIT_DESERIALIZE", +#endif +#ifdef SQLITE_OMIT_DISKIO + "OMIT_DISKIO", +#endif +#ifdef SQLITE_OMIT_EXPLAIN + "OMIT_EXPLAIN", +#endif +#ifdef SQLITE_OMIT_FLAG_PRAGMAS + "OMIT_FLAG_PRAGMAS", +#endif +#ifdef SQLITE_OMIT_FLOATING_POINT + "OMIT_FLOATING_POINT", +#endif +#ifdef SQLITE_OMIT_FOREIGN_KEY + "OMIT_FOREIGN_KEY", +#endif +#ifdef SQLITE_OMIT_GET_TABLE + "OMIT_GET_TABLE", +#endif +#ifdef SQLITE_OMIT_HEX_INTEGER + "OMIT_HEX_INTEGER", +#endif +#ifdef SQLITE_OMIT_INCRBLOB + "OMIT_INCRBLOB", +#endif +#ifdef SQLITE_OMIT_INTEGRITY_CHECK + "OMIT_INTEGRITY_CHECK", +#endif +#ifdef SQLITE_OMIT_INTROSPECTION_PRAGMAS + "OMIT_INTROSPECTION_PRAGMAS", +#endif +#ifdef SQLITE_OMIT_JSON + "OMIT_JSON", +#endif +#ifdef SQLITE_OMIT_LIKE_OPTIMIZATION + "OMIT_LIKE_OPTIMIZATION", +#endif +#ifdef SQLITE_OMIT_LOAD_EXTENSION + "OMIT_LOAD_EXTENSION", +#endif +#ifdef SQLITE_OMIT_LOCALTIME + "OMIT_LOCALTIME", +#endif +#ifdef SQLITE_OMIT_LOOKASIDE + "OMIT_LOOKASIDE", +#endif +#ifdef SQLITE_OMIT_MEMORYDB + "OMIT_MEMORYDB", +#endif +#ifdef SQLITE_OMIT_OR_OPTIMIZATION + "OMIT_OR_OPTIMIZATION", +#endif +#ifdef SQLITE_OMIT_PAGER_PRAGMAS + "OMIT_PAGER_PRAGMAS", +#endif +#ifdef SQLITE_OMIT_PARSER_TRACE + "OMIT_PARSER_TRACE", +#endif +#ifdef SQLITE_OMIT_POPEN + "OMIT_POPEN", +#endif +#ifdef SQLITE_OMIT_PRAGMA + "OMIT_PRAGMA", +#endif +#ifdef SQLITE_OMIT_PROGRESS_CALLBACK + "OMIT_PROGRESS_CALLBACK", +#endif +#ifdef SQLITE_OMIT_QUICKBALANCE + "OMIT_QUICKBALANCE", +#endif +#ifdef SQLITE_OMIT_REINDEX + "OMIT_REINDEX", +#endif +#ifdef SQLITE_OMIT_SCHEMA_PRAGMAS + "OMIT_SCHEMA_PRAGMAS", +#endif +#ifdef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS + "OMIT_SCHEMA_VERSION_PRAGMAS", +#endif +#ifdef SQLITE_OMIT_SHARED_CACHE + "OMIT_SHARED_CACHE", +#endif +#ifdef SQLITE_OMIT_SHUTDOWN_DIRECTORIES + "OMIT_SHUTDOWN_DIRECTORIES", +#endif +#ifdef SQLITE_OMIT_SUBQUERY + "OMIT_SUBQUERY", +#endif +#ifdef SQLITE_OMIT_TCL_VARIABLE + "OMIT_TCL_VARIABLE", +#endif +#ifdef SQLITE_OMIT_TEMPDB + "OMIT_TEMPDB", +#endif +#ifdef SQLITE_OMIT_TEST_CONTROL + "OMIT_TEST_CONTROL", +#endif +#ifdef SQLITE_OMIT_TRACE +# if SQLITE_OMIT_TRACE != 1 + "OMIT_TRACE=" CTIMEOPT_VAL(SQLITE_OMIT_TRACE), +# endif +#endif +#ifdef SQLITE_OMIT_TRIGGER + "OMIT_TRIGGER", +#endif +#ifdef SQLITE_OMIT_TRUNCATE_OPTIMIZATION + "OMIT_TRUNCATE_OPTIMIZATION", +#endif +#ifdef SQLITE_OMIT_UTF16 + "OMIT_UTF16", +#endif +#ifdef SQLITE_OMIT_VACUUM + "OMIT_VACUUM", +#endif +#ifdef SQLITE_OMIT_VIEW + "OMIT_VIEW", +#endif +#ifdef SQLITE_OMIT_VIRTUALTABLE + "OMIT_VIRTUALTABLE", +#endif +#ifdef SQLITE_OMIT_WAL + "OMIT_WAL", +#endif +#ifdef SQLITE_OMIT_WSD + "OMIT_WSD", +#endif +#ifdef SQLITE_OMIT_XFER_OPT + "OMIT_XFER_OPT", +#endif +#ifdef SQLITE_PCACHE_SEPARATE_HEADER + "PCACHE_SEPARATE_HEADER", +#endif +#ifdef SQLITE_PERFORMANCE_TRACE + "PERFORMANCE_TRACE", +#endif +#ifdef SQLITE_POWERSAFE_OVERWRITE +# if SQLITE_POWERSAFE_OVERWRITE != 1 + "POWERSAFE_OVERWRITE=" CTIMEOPT_VAL(SQLITE_POWERSAFE_OVERWRITE), +# endif +#endif +#ifdef SQLITE_PREFER_PROXY_LOCKING + "PREFER_PROXY_LOCKING", +#endif +#ifdef SQLITE_PROXY_DEBUG + "PROXY_DEBUG", +#endif +#ifdef SQLITE_REVERSE_UNORDERED_SELECTS + "REVERSE_UNORDERED_SELECTS", +#endif +#ifdef SQLITE_RTREE_INT_ONLY + "RTREE_INT_ONLY", +#endif +#ifdef SQLITE_SECURE_DELETE + "SECURE_DELETE", +#endif +#ifdef SQLITE_SMALL_STACK + "SMALL_STACK", +#endif +#ifdef SQLITE_SORTER_PMASZ + "SORTER_PMASZ=" CTIMEOPT_VAL(SQLITE_SORTER_PMASZ), +#endif +#ifdef SQLITE_SOUNDEX + "SOUNDEX", +#endif +#ifdef SQLITE_STAT4_SAMPLES + "STAT4_SAMPLES=" CTIMEOPT_VAL(SQLITE_STAT4_SAMPLES), +#endif +#ifdef SQLITE_STMTJRNL_SPILL + "STMTJRNL_SPILL=" CTIMEOPT_VAL(SQLITE_STMTJRNL_SPILL), +#endif +#ifdef SQLITE_SUBSTR_COMPATIBILITY + "SUBSTR_COMPATIBILITY", +#endif +#if (!defined(SQLITE_WIN32_MALLOC) \ + && !defined(SQLITE_ZERO_MALLOC) \ + && !defined(SQLITE_MEMDEBUG) \ + ) || defined(SQLITE_SYSTEM_MALLOC) + "SYSTEM_MALLOC", +#endif +#ifdef SQLITE_TCL + "TCL", +#endif +#ifdef SQLITE_TEMP_STORE + "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE), +#endif +#ifdef SQLITE_TEST + "TEST", +#endif +#if defined(SQLITE_THREADSAFE) + "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE), +#elif defined(THREADSAFE) + "THREADSAFE=" CTIMEOPT_VAL(THREADSAFE), +#else + "THREADSAFE=1", +#endif +#ifdef SQLITE_UNLINK_AFTER_CLOSE + "UNLINK_AFTER_CLOSE", +#endif +#ifdef SQLITE_UNTESTABLE + "UNTESTABLE", +#endif +#ifdef SQLITE_USER_AUTHENTICATION + "USER_AUTHENTICATION", +#endif +#ifdef SQLITE_USE_ALLOCA + "USE_ALLOCA", +#endif +#ifdef SQLITE_USE_FCNTL_TRACE + "USE_FCNTL_TRACE", +#endif +#ifdef SQLITE_USE_URI + "USE_URI", +#endif +#ifdef SQLITE_VDBE_COVERAGE + "VDBE_COVERAGE", +#endif +#ifdef SQLITE_WIN32_MALLOC + "WIN32_MALLOC", +#endif +#ifdef SQLITE_ZERO_MALLOC + "ZERO_MALLOC", +#endif + +} ; + +SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt){ + *pnOpt = sizeof(sqlite3azCompileOpt) / sizeof(sqlite3azCompileOpt[0]); + return (const char**)sqlite3azCompileOpt; +} + +#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ + +/************** End of ctime.c ***********************************************/ /************** Begin file global.c ******************************************/ /* ** 2008 June 13@@ -21080,9 +22032,13 @@ #ifndef SQLITE_UNTESTABLE
0, /* xTestCallback */ #endif 0, /* bLocaltimeFault */ + 0, /* xAltLocaltime */ 0x7ffffffe, /* iOnceResetThreshold */ SQLITE_DEFAULT_SORTERREF_SIZE, /* szSorterRef */ 0, /* iPrngSeed */ +#ifdef SQLITE_DEBUG + {0,0,0,0,0,0} /* aTune */ +#endif }; /*@@ -21091,6 +22047,18 @@ ** database connections. After initialization, this table is
** read-only. */ SQLITE_PRIVATE FuncDefHash sqlite3BuiltinFunctions; + +#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG) +/* +** Counter used for coverage testing. Does not come into play for +** release builds. +** +** Access to this global variable is not mutex protected. This might +** result in TSAN warnings. But as the variable does not exist in +** release builds, that should not be a concern. +*/ +SQLITE_PRIVATE unsigned int sqlite3CoverageCounter; +#endif /* SQLITE_COVERAGE_TEST || SQLITE_DEBUG */ #ifdef VDBE_PROFILE /*@@ -21125,7 +22093,7 @@
/* ** Tracing flags set by SQLITE_TESTCTRL_TRACEFLAGS. */ -SQLITE_PRIVATE u32 sqlite3SelectTrace = 0; +SQLITE_PRIVATE u32 sqlite3TreeTrace = 0; SQLITE_PRIVATE u32 sqlite3WhereTrace = 0; /* #include "opcodes.h" */@@ -21142,6 +22110,48 @@ ** Name of the default collating sequence
*/ SQLITE_PRIVATE const char sqlite3StrBINARY[] = "BINARY"; +/* +** Standard typenames. These names must match the COLTYPE_* definitions. +** Adjust the SQLITE_N_STDTYPE value if adding or removing entries. +** +** sqlite3StdType[] The actual names of the datatypes. +** +** sqlite3StdTypeLen[] The length (in bytes) of each entry +** in sqlite3StdType[]. +** +** sqlite3StdTypeAffinity[] The affinity associated with each entry +** in sqlite3StdType[]. +** +** sqlite3StdTypeMap[] The type value (as returned from +** sqlite3_column_type() or sqlite3_value_type()) +** for each entry in sqlite3StdType[]. +*/ +SQLITE_PRIVATE const unsigned char sqlite3StdTypeLen[] = { 3, 4, 3, 7, 4, 4 }; +SQLITE_PRIVATE const char sqlite3StdTypeAffinity[] = { + SQLITE_AFF_NUMERIC, + SQLITE_AFF_BLOB, + SQLITE_AFF_INTEGER, + SQLITE_AFF_INTEGER, + SQLITE_AFF_REAL, + SQLITE_AFF_TEXT +}; +SQLITE_PRIVATE const char sqlite3StdTypeMap[] = { + 0, + SQLITE_BLOB, + SQLITE_INTEGER, + SQLITE_INTEGER, + SQLITE_FLOAT, + SQLITE_TEXT +}; +SQLITE_PRIVATE const char *sqlite3StdType[] = { + "ANY", + "BLOB", + "INT", + "INTEGER", + "REAL", + "TEXT" +}; + /************** End of global.c **********************************************/ /************** Begin file status.c ******************************************/ /*@@ -21239,7 +22249,7 @@ */
typedef struct VdbeCursor VdbeCursor; struct VdbeCursor { u8 eCurType; /* One of the CURTYPE_* values above */ - i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */ + i8 iDb; /* Index of cursor database in db->aDb[] */ u8 nullRow; /* True if pointing to a row with no data */ u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */ u8 isTable; /* True for rowid tables. False for indexes */@@ -21250,11 +22260,13 @@ #endif
Bool isEphemeral:1; /* True for an ephemeral table */ Bool useRandomRowid:1; /* Generate new record numbers semi-randomly */ Bool isOrdered:1; /* True if the table is not BTREE_UNORDERED */ - Bool hasBeenDuped:1; /* This cursor was source or target of OP_OpenDup */ + Bool noReuse:1; /* OpenEphemeral may not reuse this cursor */ u16 seekHit; /* See the OP_SeekHit and OP_IfNoHope opcodes */ - Btree *pBtx; /* Separate file holding temporary table */ + union { /* pBtx for isEphermeral. pAltMap otherwise */ + Btree *pBtx; /* Separate file holding temporary table */ + u32 *aAltMap; /* Mapping from table to index column numbers */ + } ub; i64 seqCount; /* Sequence counter */ - u32 *aAltMap; /* Mapping from table to index column numbers */ /* Cached OP_Column parse information is only valid if cacheStatus matches ** Vdbe.cacheCtr. Vdbe.cacheCtr will never take on the value of@@ -21295,6 +22307,11 @@ ** static element declared in the structure. nField total array slots for
** aType[] and nField+1 array slots for aOffset[] */ u32 aType[1]; /* Type values record decode. MUST BE LAST */ }; + +/* Return true if P is a null-only cursor +*/ +#define IsNullCursor(P) \ + ((P)->eCurType==CURTYPE_PSEUDO && (P)->nullRow && (P)->seekResult==0) /*@@ -21344,8 +22361,8 @@ int nOp; /* Size of aOp array */
int nMem; /* Number of entries in aMem */ int nChildMem; /* Number of memory cells for child frame */ int nChildCsr; /* Number of cursors for child frame */ - int nChange; /* Statement changes (Vdbe.nChange) */ - int nDbChange; /* Value of db->nChange */ + i64 nChange; /* Statement changes (Vdbe.nChange) */ + i64 nDbChange; /* Value of db->nChange */ }; /* Magic number for sanity checking on VdbeFrame objects */@@ -21370,16 +22387,16 @@ int nZero; /* Extra zero bytes when MEM_Zero and MEM_Blob set */
const char *zPType; /* Pointer type when MEM_Term|MEM_Subtype|MEM_Null */ FuncDef *pDef; /* Used only when flags==MEM_Agg */ } u; + char *z; /* String or BLOB value */ + int n; /* Number of characters in string value, excluding '\0' */ u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */ u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */ u8 eSubtype; /* Subtype for this value */ - int n; /* Number of characters in string value, excluding '\0' */ - char *z; /* String or BLOB value */ /* ShallowCopy only needs to copy the information above */ - char *zMalloc; /* Space to hold MEM_Str or MEM_Blob if szMalloc>0 */ + sqlite3 *db; /* The associated database connection */ int szMalloc; /* Size of the zMalloc allocation */ u32 uTemp; /* Transient storage for serial_type in OP_MakeRecord */ - sqlite3 *db; /* The associated database connection */ + char *zMalloc; /* Space to hold MEM_Str or MEM_Blob if szMalloc>0 */ void (*xDel)(void*);/* Destructor for Mem.z - only valid if MEM_Dyn */ #ifdef SQLITE_DEBUG Mem *pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */@@ -21391,11 +22408,43 @@ /*
** Size of struct Mem not including the Mem.zMalloc member or anything that ** follows. */ -#define MEMCELLSIZE offsetof(Mem,zMalloc) +#define MEMCELLSIZE offsetof(Mem,db) -/* One or more of the following flags are set to indicate the validOK +/* One or more of the following flags are set to indicate the ** representations of the value stored in the Mem struct. ** +** * MEM_Null An SQL NULL value +** +** * MEM_Null|MEM_Zero An SQL NULL with the virtual table +** UPDATE no-change flag set +** +** * MEM_Null|MEM_Term| An SQL NULL, but also contains a +** MEM_Subtype pointer accessible using +** sqlite3_value_pointer(). +** +** * MEM_Null|MEM_Cleared Special SQL NULL that compares non-equal +** to other NULLs even using the IS operator. +** +** * MEM_Str A string, stored in Mem.z with +** length Mem.n. Zero-terminated if +** MEM_Term is set. This flag is +** incompatible with MEM_Blob and +** MEM_Null, but can appear with MEM_Int, +** MEM_Real, and MEM_IntReal. +** +** * MEM_Blob A blob, stored in Mem.z length Mem.n. +** Incompatible with MEM_Str, MEM_Null, +** MEM_Int, MEM_Real, and MEM_IntReal. +** +** * MEM_Blob|MEM_Zero A blob in Mem.z of length Mem.n plus +** MEM.u.i extra 0x00 bytes at the end. +** +** * MEM_Int Integer stored in Mem.u.i. +** +** * MEM_Real Real stored in Mem.u.r. +** +** * MEM_IntReal Real stored as an integer in Mem.u.i. +** ** If the MEM_Null flag is set, then the value is an SQL NULL value. ** For a pointer type created using sqlite3_bind_pointer() or ** sqlite3_result_pointer() the MEM_Term and MEM_Subtype flags are also set.@@ -21406,6 +22455,7 @@ ** database (see below for exceptions). If the MEM_Term flag is also
** set, then the string is nul terminated. The MEM_Int and MEM_Real ** flags may coexist with the MEM_Str flag. */ +#define MEM_Undefined 0x0000 /* Value is undefined */ #define MEM_Null 0x0001 /* Value is NULL (or a pointer) */ #define MEM_Str 0x0002 /* Value is a string */ #define MEM_Int 0x0004 /* Value is an integer */@@ -21413,28 +22463,24 @@ #define MEM_Real 0x0008 /* Value is a real number */
#define MEM_Blob 0x0010 /* Value is a BLOB */ #define MEM_IntReal 0x0020 /* MEM_Int that stringifies like MEM_Real */ #define MEM_AffMask 0x003f /* Mask of affinity bits */ + +/* Extra bits that modify the meanings of the core datatypes above +*/ #define MEM_FromBind 0x0040 /* Value originates from sqlite3_bind() */ -#define MEM_Undefined 0x0080 /* Value is undefined */ + /* 0x0080 // Available */ #define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */ -#define MEM_TypeMask 0xc1bf /* Mask of type bits */ +#define MEM_Term 0x0200 /* String in Mem.z is zero terminated */ +#define MEM_Zero 0x0400 /* Mem.i contains count of 0s appended to blob */ +#define MEM_Subtype 0x0800 /* Mem.eSubtype is valid */ +#define MEM_TypeMask 0x0dbf /* Mask of type bits */ - -/* Whenever Mem contains a valid string or blob representation, one of -** the following flags must be set to determine the memory management -** policy for Mem.z. The MEM_Term flag tells us whether or not the -** string is \000 or \u0000 terminated +/* Bits that determine the storage for Mem.z for a string or blob or +** aggregate accumulator. */ -#define MEM_Term 0x0200 /* String in Mem.z is zero terminated */ -#define MEM_Dyn 0x0400 /* Need to call Mem.xDel() on Mem.z */ -#define MEM_Static 0x0800 /* Mem.z points to a static string */ -#define MEM_Ephem 0x1000 /* Mem.z points to an ephemeral string */ -#define MEM_Agg 0x2000 /* Mem.z points to an agg function context */ -#define MEM_Zero 0x4000 /* Mem.i contains count of 0s appended to blob */ -#define MEM_Subtype 0x8000 /* Mem.eSubtype is valid */ -#ifdef SQLITE_OMIT_INCRBLOB - #undef MEM_Zero - #define MEM_Zero 0x0000 -#endif +#define MEM_Dyn 0x1000 /* Need to call Mem.xDel() on Mem.z */ +#define MEM_Static 0x2000 /* Mem.z points to a static string */ +#define MEM_Ephem 0x4000 /* Mem.z points to an ephemeral string */ +#define MEM_Agg 0x8000 /* Mem.z points to an agg function context */ /* Return TRUE if Mem X contains dynamically allocated content - anything ** that needs to be deallocated to avoid a leak.@@ -21456,11 +22502,15 @@ (((X)->flags&MEM_TypeMask)==(MEM_Null|MEM_Zero) \
&& (X)->n==0 && (X)->u.nZero==0) /* -** Return true if a memory cell is not marked as invalid. This macro +** Return true if a memory cell has been initialized and is valid. ** is for use inside assert() statements only. +** +** A Memory cell is initialized if at least one of the +** MEM_Null, MEM_Str, MEM_Int, MEM_Real, MEM_Blob, or MEM_IntReal bits +** is set. It is "undefined" if all those bits are zero. */ #ifdef SQLITE_DEBUG -#define memIsValid(M) ((M)->flags & MEM_Undefined)==0 +#define memIsValid(M) ((M)->flags & MEM_AffMask)!=0 #endif /*@@ -21498,6 +22548,7 @@ Mem *pMem; /* Memory cell used to store aggregate context */
Vdbe *pVdbe; /* The VM that owns this context */ int iOp; /* Instruction number of OP_Function */ int isError; /* Error code returned by the function. */ + u8 enc; /* Encoding to use for results */ u8 skipFlag; /* Skip accumulator loading if true */ u8 argc; /* Number of arguments */ sqlite3_value *argv[1]; /* Argument set */@@ -21546,13 +22597,12 @@ sqlite3 *db; /* The database connection that owns this statement */
Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */ Parse *pParse; /* Parsing context used to create this Vdbe */ ynVar nVar; /* Number of entries in aVar[] */ - u32 iVdbeMagic; /* Magic number defining state of the SQL statement */ int nMem; /* Number of memory locations currently allocated */ int nCursor; /* Number of slots in apCsr[] */ u32 cacheCtr; /* VdbeCursor row cache generation counter */ int pc; /* The program counter */ int rc; /* Value to return */ - int nChange; /* Number of db changes made since last reset */ + i64 nChange; /* Number of db changes made since last reset */ int iStatement; /* Statement number (or 0 if has no opened stmt) */ i64 iCurrentTime; /* Value of julianday('now') for this statement */ i64 nFkConstraint; /* Number of imm. FK constraints this VM */@@ -21584,17 +22634,16 @@ u16 nResColumn; /* Number of columns in one row of the result set */
u8 errorAction; /* Recovery action to do in case of an error */ u8 minWriteFileFormat; /* Minimum file format for writable database files */ u8 prepFlags; /* SQLITE_PREPARE_* flags */ - u8 doingRerun; /* True if rerunning after an auto-reprepare */ + u8 eVdbeState; /* On of the VDBE_*_STATE values */ bft expired:2; /* 1: recompile VM immediately 2: when convenient */ bft explain:2; /* True if EXPLAIN present on SQL command */ bft changeCntOn:1; /* True to update the change-counter */ - bft runOnlyOnce:1; /* Automatically expire on reset */ bft usesStmtJournal:1; /* True if uses a statement journal */ bft readOnly:1; /* True for statements that do not write */ bft bIsReader:1; /* True for statements that read */ yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */ yDbMask lockMask; /* Subset of btreeMask that requires a lock */ - u32 aCounter[7]; /* Counters used by sqlite3_stmt_status() */ + u32 aCounter[9]; /* Counters used by sqlite3_stmt_status() */ char *zSql; /* Text of the SQL statement that generated this */ #ifdef SQLITE_ENABLE_NORMALIZE char *zNormSql; /* Normalization of the associated SQL statement */@@ -21615,13 +22664,12 @@ #endif
}; /* -** The following are allowed values for Vdbe.magic +** The following are allowed values for Vdbe.eVdbeState */ -#define VDBE_MAGIC_INIT 0x16bceaa5 /* Building a VDBE program */ -#define VDBE_MAGIC_RUN 0x2df20da3 /* VDBE is ready to execute */ -#define VDBE_MAGIC_HALT 0x319c2973 /* VDBE has completed execution */ -#define VDBE_MAGIC_RESET 0x48fa9f76 /* Reset and ready to run again */ -#define VDBE_MAGIC_DEAD 0x5606c3c8 /* The VDBE has been deallocated */ +#define VDBE_INIT_STATE 0 /* Prepared statement under construction */ +#define VDBE_READY_STATE 1 /* Ready to run but not yet started */ +#define VDBE_RUN_STATE 2 /* Run in progress */ +#define VDBE_HALT_STATE 3 /* Finished. Need reset() or finalize() */ /* ** Structure used to store the context required by the@@ -21645,18 +22693,49 @@ Index *pPk; /* PK index if pTab is WITHOUT ROWID */
}; /* +** An instance of this object is used to pass an vector of values into +** OP_VFilter, the xFilter method of a virtual table. The vector is the +** set of values on the right-hand side of an IN constraint. +** +** The value as passed into xFilter is an sqlite3_value with a "pointer" +** type, such as is generated by sqlite3_result_pointer() and read by +** sqlite3_value_pointer. Such values have MEM_Term|MEM_Subtype|MEM_Null +** and a subtype of 'p'. The sqlite3_vtab_in_first() and _next() interfaces +** know how to use this object to step through all the values in the +** right operand of the IN constraint. +*/ +typedef struct ValueList ValueList; +struct ValueList { + BtCursor *pCsr; /* An ephemeral table holding all values */ + sqlite3_value *pOut; /* Register to hold each decoded output value */ +}; + +/* Size of content associated with serial types that fit into a +** single-byte varint. +*/ +#ifndef SQLITE_AMALGAMATION +SQLITE_PRIVATE const u8 sqlite3SmallTypeSizes[]; +#endif + +/* ** Function prototypes */ SQLITE_PRIVATE void sqlite3VdbeError(Vdbe*, const char *, ...); SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*); +SQLITE_PRIVATE void sqlite3VdbeFreeCursorNN(Vdbe*,VdbeCursor*); void sqliteVdbePopStack(Vdbe*,int); +SQLITE_PRIVATE int SQLITE_NOINLINE sqlite3VdbeHandleMovedCursor(VdbeCursor *p); SQLITE_PRIVATE int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor*); -SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor**, u32*); SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor*); SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32); SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8); -SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32); -SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*); +#ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT +SQLITE_PRIVATE u64 sqlite3FloatSwap(u64 in); +# define swapMixedEndianFloat(X) X = sqlite3FloatSwap(X) +#else +# define swapMixedEndianFloat(X) +#endif +SQLITE_PRIVATE void sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*); SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(sqlite3*, AuxData**, int, int); int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);@@ -21690,14 +22769,19 @@ #endif
SQLITE_PRIVATE void sqlite3VdbeMemSetPointer(Mem*, void*, const char*, void(*)(void*)); SQLITE_PRIVATE void sqlite3VdbeMemInit(Mem*,sqlite3*,u16); SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem*); +#ifndef SQLITE_OMIT_INCRBLOB SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem*,int); +#else +SQLITE_PRIVATE int sqlite3VdbeMemSetZeroBlob(Mem*,int); +#endif #ifdef SQLITE_DEBUG SQLITE_PRIVATE int sqlite3VdbeMemIsRowSet(const Mem*); #endif SQLITE_PRIVATE int sqlite3VdbeMemSetRowSet(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem*, u8, u8); -SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem*); +SQLITE_PRIVATE int sqlite3IntFloatCompare(i64,double); +SQLITE_PRIVATE i64 sqlite3VdbeIntValue(const Mem*); SQLITE_PRIVATE int sqlite3VdbeMemIntegerify(Mem*); SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem*); SQLITE_PRIVATE int sqlite3VdbeBooleanValue(Mem*, int ifNull);@@ -21708,6 +22792,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemCast(Mem*,u8,u8);
SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,Mem*); SQLITE_PRIVATE int sqlite3VdbeMemFromBtreeZeroOffset(BtCursor*,u32,Mem*); SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p); +SQLITE_PRIVATE void sqlite3VdbeMemReleaseMalloc(Mem*p); SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem*, FuncDef*); #ifndef SQLITE_OMIT_WINDOWFUNC SQLITE_PRIVATE int sqlite3VdbeMemAggValue(Mem*, Mem*, FuncDef*);@@ -22110,8 +23195,7 @@ int nByte = 0; /* Used to accumulate return value */
db->pnBytesFreed = &nByte; for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){ - sqlite3VdbeClearObject(db, pVdbe); - sqlite3DbFree(db, pVdbe); + sqlite3VdbeDelete(pVdbe); } db->pnBytesFreed = 0;@@ -22675,8 +23759,10 @@ ** using whatever operating-system specific localtime facility that
** is available. This routine returns 0 on success and ** non-zero on any kind of error. ** -** If the sqlite3GlobalConfig.bLocaltimeFault variable is true then this -** routine will always fail. +** If the sqlite3GlobalConfig.bLocaltimeFault variable is non-zero then this +** routine will always fail. If bLocaltimeFault is nonzero and +** sqlite3GlobalConfig.xAltLocaltime is not NULL, then xAltLocaltime() is +** invoked in place of the OS-defined localtime() function. ** ** EVIDENCE-OF: R-62172-00036 In this implementation, the standard C ** library function localtime_r() is used to assist in the calculation of@@ -22692,14 +23778,30 @@ #endif
sqlite3_mutex_enter(mutex); pX = localtime(t); #ifndef SQLITE_UNTESTABLE - if( sqlite3GlobalConfig.bLocaltimeFault ) pX = 0; + if( sqlite3GlobalConfig.bLocaltimeFault ){ + if( sqlite3GlobalConfig.xAltLocaltime!=0 + && 0==sqlite3GlobalConfig.xAltLocaltime((const void*)t,(void*)pTm) + ){ + pX = pTm; + }else{ + pX = 0; + } + } #endif if( pX ) *pTm = *pX; +#if SQLITE_THREADSAFE>0 sqlite3_mutex_leave(mutex); +#endif rc = pX==0; #else #ifndef SQLITE_UNTESTABLE - if( sqlite3GlobalConfig.bLocaltimeFault ) return 1; + if( sqlite3GlobalConfig.bLocaltimeFault ){ + if( sqlite3GlobalConfig.xAltLocaltime!=0 ){ + return sqlite3GlobalConfig.xAltLocaltime((const void*)t,(void*)pTm); + }else{ + return 1; + } + } #endif #if HAVE_LOCALTIME_R rc = localtime_r(t, pTm)==0;@@ -22714,67 +23816,56 @@
#ifndef SQLITE_OMIT_LOCALTIME /* -** Compute the difference (in milliseconds) between localtime and UTC -** (a.k.a. GMT) for the time value p where p is in UTC. If no error occurs, -** return this value and set *pRc to SQLITE_OK. -** -** Or, if an error does occur, set *pRc to SQLITE_ERROR. The returned value -** is undefined in this case. +** Assuming the input DateTime is UTC, move it to its localtime equivalent. */ -static sqlite3_int64 localtimeOffset( - DateTime *p, /* Date at which to calculate offset */ - sqlite3_context *pCtx, /* Write error here if one occurs */ - int *pRc /* OUT: Error code. SQLITE_OK or ERROR */ +static int toLocaltime( + DateTime *p, /* Date at which to calculate offset */ + sqlite3_context *pCtx /* Write error here if one occurs */ ){ - DateTime x, y; time_t t; struct tm sLocal; + int iYearDiff; /* Initialize the contents of sLocal to avoid a compiler warning. */ memset(&sLocal, 0, sizeof(sLocal)); - x = *p; - computeYMD_HMS(&x); - if( x.Y<1971 || x.Y>=2038 ){ + computeJD(p); + if( p->iJD<2108667600*(i64)100000 /* 1970-01-01 */ + || p->iJD>2130141456*(i64)100000 /* 2038-01-18 */ + ){ /* EVIDENCE-OF: R-55269-29598 The localtime_r() C function normally only ** works for years between 1970 and 2037. For dates outside this range, ** SQLite attempts to map the year into an equivalent year within this ** range, do the calculation, then map the year back. */ - x.Y = 2000; - x.M = 1; - x.D = 1; - x.h = 0; - x.m = 0; - x.s = 0.0; - } else { - int s = (int)(x.s + 0.5); - x.s = s; + DateTime x = *p; + computeYMD_HMS(&x); + iYearDiff = (2000 + x.Y%4) - x.Y; + x.Y += iYearDiff; + x.validJD = 0; + computeJD(&x); + t = (time_t)(x.iJD/1000 - 21086676*(i64)10000); + }else{ + iYearDiff = 0; + t = (time_t)(p->iJD/1000 - 21086676*(i64)10000); } - x.tz = 0; - x.validJD = 0; - computeJD(&x); - t = (time_t)(x.iJD/1000 - 21086676*(i64)10000); if( osLocaltime(&t, &sLocal) ){ sqlite3_result_error(pCtx, "local time unavailable", -1); - *pRc = SQLITE_ERROR; - return 0; + return SQLITE_ERROR; } - y.Y = sLocal.tm_year + 1900; - y.M = sLocal.tm_mon + 1; - y.D = sLocal.tm_mday; - y.h = sLocal.tm_hour; - y.m = sLocal.tm_min; - y.s = sLocal.tm_sec; - y.validYMD = 1; - y.validHMS = 1; - y.validJD = 0; - y.rawS = 0; - y.validTZ = 0; - y.isError = 0; - computeJD(&y); - *pRc = SQLITE_OK; - return y.iJD - x.iJD; + p->Y = sLocal.tm_year + 1900 - iYearDiff; + p->M = sLocal.tm_mon + 1; + p->D = sLocal.tm_mday; + p->h = sLocal.tm_hour; + p->m = sLocal.tm_min; + p->s = sLocal.tm_sec + (p->iJD%1000)*0.001; + p->validYMD = 1; + p->validHMS = 1; + p->validJD = 0; + p->rawS = 0; + p->validTZ = 0; + p->isError = 0; + return SQLITE_OK; } #endif /* SQLITE_OMIT_LOCALTIME */@@ -22787,18 +23878,17 @@ ** Where NNN is an arbitrary floating-point number and "days" can be one
** of several units of time. */ static const struct { - u8 eType; /* Transformation type code */ - u8 nName; /* Length of th name */ - char *zName; /* Name of the transformation */ - double rLimit; /* Maximum NNN value for this transform */ - double rXform; /* Constant used for this transform */ + u8 nName; /* Length of the name */ + char zName[7]; /* Name of the transformation */ + float rLimit; /* Maximum NNN value for this transform */ + float rXform; /* Constant used for this transform */ } aXformType[] = { - { 0, 6, "second", 464269060800.0, 1000.0 }, - { 0, 6, "minute", 7737817680.0, 60000.0 }, - { 0, 4, "hour", 128963628.0, 3600000.0 }, - { 0, 3, "day", 5373485.0, 86400000.0 }, - { 1, 5, "month", 176546.0, 2592000000.0 }, - { 2, 4, "year", 14713.0, 31536000000.0 }, + { 6, "second", 4.6427e+14, 1.0 }, + { 6, "minute", 7.7379e+12, 60.0 }, + { 4, "hour", 1.2897e+11, 3600.0 }, + { 3, "day", 5373485.0, 86400.0 }, + { 5, "month", 176546.0, 2592000.0 }, + { 4, "year", 14713.0, 31536000.0 }, }; /*@@ -22829,11 +23919,55 @@ static int parseModifier(
sqlite3_context *pCtx, /* Function context */ const char *z, /* The text of the modifier */ int n, /* Length of zMod in bytes */ - DateTime *p /* The date/time value to be modified */ + DateTime *p, /* The date/time value to be modified */ + int idx /* Parameter index of the modifier */ ){ int rc = 1; double r; switch(sqlite3UpperToLower[(u8)z[0]] ){ + case 'a': { + /* + ** auto + ** + ** If rawS is available, then interpret as a julian day number, or + ** a unix timestamp, depending on its magnitude. + */ + if( sqlite3_stricmp(z, "auto")==0 ){ + if( idx>1 ) return 1; /* IMP: R-33611-57934 */ + if( !p->rawS || p->validJD ){ + rc = 0; + p->rawS = 0; + }else if( p->s>=-21086676*(i64)10000 /* -4713-11-24 12:00:00 */ + && p->s<=(25340230*(i64)10000)+799 /* 9999-12-31 23:59:59 */ + ){ + r = p->s*1000.0 + 210866760000000.0; + clearYMD_HMS_TZ(p); + p->iJD = (sqlite3_int64)(r + 0.5); + p->validJD = 1; + p->rawS = 0; + rc = 0; + } + } + break; + } + case 'j': { + /* + ** julianday + ** + ** Always interpret the prior number as a julian-day value. If this + ** is not the first modifier, or if the prior argument is not a numeric + ** value in the allowed range of julian day numbers understood by + ** SQLite (0..5373484.5) then the result will be NULL. + */ + if( sqlite3_stricmp(z, "julianday")==0 ){ + if( idx>1 ) return 1; /* IMP: R-31176-64601 */ + if( p->validJD && p->rawS ){ + rc = 0; + p->rawS = 0; + } + } + break; + } #ifndef SQLITE_OMIT_LOCALTIME case 'l': { /* localtime@@ -22842,9 +23976,7 @@ ** Assuming the current time value is UTC (a.k.a. GMT), shift it to
** show local time. */ if( sqlite3_stricmp(z, "localtime")==0 && sqlite3NotPureFunc(pCtx) ){ - computeJD(p); - p->iJD += localtimeOffset(p, pCtx, &rc); - clearYMD_HMS_TZ(p); + rc = toLocaltime(p, pCtx); } break; }@@ -22857,6 +23989,7 @@ ** Treat the current value of p->s as the number of
** seconds since 1970. Convert to a real julian day number. */ if( sqlite3_stricmp(z, "unixepoch")==0 && p->rawS ){ + if( idx>1 ) return 1; /* IMP: R-49255-55373 */ r = p->s*1000.0 + 210866760000000.0; if( r>=0.0 && r<464269060800000.0 ){ clearYMD_HMS_TZ(p);@@ -22869,18 +24002,31 @@ }
#ifndef SQLITE_OMIT_LOCALTIME else if( sqlite3_stricmp(z, "utc")==0 && sqlite3NotPureFunc(pCtx) ){ if( p->tzSet==0 ){ - sqlite3_int64 c1; + i64 iOrigJD; /* Original localtime */ + i64 iGuess; /* Guess at the corresponding utc time */ + int cnt = 0; /* Safety to prevent infinite loop */ + int iErr; /* Guess is off by this much */ + computeJD(p); - c1 = localtimeOffset(p, pCtx, &rc); - if( rc==SQLITE_OK ){ - p->iJD -= c1; - clearYMD_HMS_TZ(p); - p->iJD += c1 - localtimeOffset(p, pCtx, &rc); - } + iGuess = iOrigJD = p->iJD; + iErr = 0; + do{ + DateTime new; + memset(&new, 0, sizeof(new)); + iGuess -= iErr; + new.iJD = iGuess; + new.validJD = 1; + rc = toLocaltime(&new, pCtx); + if( rc ) return rc; + computeJD(&new); + iErr = new.iJD - iOrigJD; + }while( iErr && cnt++<3 ); + memset(p, 0, sizeof(*p)); + p->iJD = iGuess; + p->validJD = 1; p->tzSet = 1; - }else{ - rc = SQLITE_OK; } + rc = SQLITE_OK; } #endif break;@@ -22996,9 +24142,10 @@ if( aXformType[i].nName==n
&& sqlite3_strnicmp(aXformType[i].zName, z, n)==0 && r>-aXformType[i].rLimit && r<aXformType[i].rLimit ){ - switch( aXformType[i].eType ){ - case 1: { /* Special processing to add months */ + switch( i ){ + case 4: { /* Special processing to add months */ int x; + assert( strcmp(aXformType[i].zName,"month")==0 ); computeYMD_HMS(p); p->M += (int)r; x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;@@ -23008,8 +24155,9 @@ p->validJD = 0;
r -= (int)r; break; } - case 2: { /* Special processing to add years */ + case 5: { /* Special processing to add years */ int y = (int)r; + assert( strcmp(aXformType[i].zName,"year")==0 ); computeYMD_HMS(p); p->Y += y; p->validJD = 0;@@ -23018,7 +24166,7 @@ break;
} } computeJD(p); - p->iJD += (sqlite3_int64)(r*aXformType[i].rXform + rRounder); + p->iJD += (sqlite3_int64)(r*1000.0*aXformType[i].rXform + rRounder); rc = 0; break; }@@ -23068,7 +24216,7 @@ }
for(i=1; i<argc; i++){ z = sqlite3_value_text(argv[i]); n = sqlite3_value_bytes(argv[i]); - if( z==0 || parseModifier(context, (char*)z, n, p) ) return 1; + if( z==0 || parseModifier(context, (char*)z, n, p, i) ) return 1; } computeJD(p); if( p->isError || !validJulianDay(p->iJD) ) return 1;@@ -23099,6 +24247,24 @@ }
} /* +** unixepoch( TIMESTRING, MOD, MOD, ...) +** +** Return the number of seconds (including fractional seconds) since +** the unix epoch of 1970-01-01 00:00:00 GMT. +*/ +static void unixepochFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + DateTime x; + if( isDate(context, argc, argv, &x)==0 ){ + computeJD(&x); + sqlite3_result_int64(context, x.iJD/1000 - 21086676*(i64)10000); + } +} + +/* ** datetime( TIMESTRING, MOD, MOD, ...) ** ** Return YYYY-MM-DD HH:MM:SS@@ -23110,11 +24276,38 @@ sqlite3_value **argv
){ DateTime x; if( isDate(context, argc, argv, &x)==0 ){ - char zBuf[100]; + int Y, s; + char zBuf[24]; computeYMD_HMS(&x); - sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d %02d:%02d:%02d", - x.Y, x.M, x.D, x.h, x.m, (int)(x.s)); - sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); + Y = x.Y; + if( Y<0 ) Y = -Y; + zBuf[1] = '0' + (Y/1000)%10; + zBuf[2] = '0' + (Y/100)%10; + zBuf[3] = '0' + (Y/10)%10; + zBuf[4] = '0' + (Y)%10; + zBuf[5] = '-'; + zBuf[6] = '0' + (x.M/10)%10; + zBuf[7] = '0' + (x.M)%10; + zBuf[8] = '-'; + zBuf[9] = '0' + (x.D/10)%10; + zBuf[10] = '0' + (x.D)%10; + zBuf[11] = ' '; + zBuf[12] = '0' + (x.h/10)%10; + zBuf[13] = '0' + (x.h)%10; + zBuf[14] = ':'; + zBuf[15] = '0' + (x.m/10)%10; + zBuf[16] = '0' + (x.m)%10; + zBuf[17] = ':'; + s = (int)x.s; + zBuf[18] = '0' + (s/10)%10; + zBuf[19] = '0' + (s)%10; + zBuf[20] = 0; + if( x.Y<0 ){ + zBuf[0] = '-'; + sqlite3_result_text(context, zBuf, 20, SQLITE_TRANSIENT); + }else{ + sqlite3_result_text(context, &zBuf[1], 19, SQLITE_TRANSIENT); + } } }@@ -23130,10 +24323,20 @@ sqlite3_value **argv
){ DateTime x; if( isDate(context, argc, argv, &x)==0 ){ - char zBuf[100]; + int s; + char zBuf[16]; computeHMS(&x); - sqlite3_snprintf(sizeof(zBuf), zBuf, "%02d:%02d:%02d", x.h, x.m, (int)x.s); - sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); + zBuf[0] = '0' + (x.h/10)%10; + zBuf[1] = '0' + (x.h)%10; + zBuf[2] = ':'; + zBuf[3] = '0' + (x.m/10)%10; + zBuf[4] = '0' + (x.m)%10; + zBuf[5] = ':'; + s = (int)x.s; + zBuf[6] = '0' + (s/10)%10; + zBuf[7] = '0' + (s)%10; + zBuf[8] = 0; + sqlite3_result_text(context, zBuf, 8, SQLITE_TRANSIENT); } }@@ -23149,10 +24352,28 @@ sqlite3_value **argv
){ DateTime x; if( isDate(context, argc, argv, &x)==0 ){ - char zBuf[100]; + int Y; + char zBuf[16]; computeYMD(&x); - sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d", x.Y, x.M, x.D); - sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); + Y = x.Y; + if( Y<0 ) Y = -Y; + zBuf[1] = '0' + (Y/1000)%10; + zBuf[2] = '0' + (Y/100)%10; + zBuf[3] = '0' + (Y/10)%10; + zBuf[4] = '0' + (Y)%10; + zBuf[5] = '-'; + zBuf[6] = '0' + (x.M/10)%10; + zBuf[7] = '0' + (x.M)%10; + zBuf[8] = '-'; + zBuf[9] = '0' + (x.D/10)%10; + zBuf[10] = '0' + (x.D)%10; + zBuf[11] = 0; + if( x.Y<0 ){ + zBuf[0] = '-'; + sqlite3_result_text(context, zBuf, 11, SQLITE_TRANSIENT); + }else{ + sqlite3_result_text(context, &zBuf[1], 10, SQLITE_TRANSIENT); + } } }@@ -23181,131 +24402,100 @@ int argc,
sqlite3_value **argv ){ DateTime x; - u64 n; size_t i,j; - char *z; sqlite3 *db; const char *zFmt; - char zBuf[100]; + sqlite3_str sRes; + + if( argc==0 ) return; zFmt = (const char*)sqlite3_value_text(argv[0]); if( zFmt==0 || isDate(context, argc-1, argv+1, &x) ) return; db = sqlite3_context_db_handle(context); - for(i=0, n=1; zFmt[i]; i++, n++){ - if( zFmt[i]=='%' ){ - switch( zFmt[i+1] ){ - case 'd': - case 'H': - case 'm': - case 'M': - case 'S': - case 'W': - n++; - /* fall thru */ - case 'w': - case '%': - break; - case 'f': - n += 8; - break; - case 'j': - n += 3; - break; - case 'Y': - n += 8; - break; - case 's': - case 'J': - n += 50; - break; - default: - return; /* ERROR. return a NULL */ - } - i++; - } - } - testcase( n==sizeof(zBuf)-1 ); - testcase( n==sizeof(zBuf) ); - testcase( n==(u64)db->aLimit[SQLITE_LIMIT_LENGTH]+1 ); - testcase( n==(u64)db->aLimit[SQLITE_LIMIT_LENGTH] ); - if( n<sizeof(zBuf) ){ - z = zBuf; - }else if( n>(u64)db->aLimit[SQLITE_LIMIT_LENGTH] ){ - sqlite3_result_error_toobig(context); - return; - }else{ - z = sqlite3DbMallocRawNN(db, (int)n); - if( z==0 ){ - sqlite3_result_error_nomem(context); - return; - } - } + sqlite3StrAccumInit(&sRes, 0, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]); + computeJD(&x); computeYMD_HMS(&x); for(i=j=0; zFmt[i]; i++){ - if( zFmt[i]!='%' ){ - z[j++] = zFmt[i]; - }else{ - i++; - switch( zFmt[i] ){ - case 'd': sqlite3_snprintf(3, &z[j],"%02d",x.D); j+=2; break; - case 'f': { - double s = x.s; - if( s>59.999 ) s = 59.999; - sqlite3_snprintf(7, &z[j],"%06.3f", s); - j += sqlite3Strlen30(&z[j]); - break; - } - case 'H': sqlite3_snprintf(3, &z[j],"%02d",x.h); j+=2; break; - case 'W': /* Fall thru */ - case 'j': { - int nDay; /* Number of days since 1st day of year */ - DateTime y = x; - y.validJD = 0; - y.M = 1; - y.D = 1; - computeJD(&y); - nDay = (int)((x.iJD-y.iJD+43200000)/86400000); - if( zFmt[i]=='W' ){ - int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */ - wd = (int)(((x.iJD+43200000)/86400000)%7); - sqlite3_snprintf(3, &z[j],"%02d",(nDay+7-wd)/7); - j += 2; - }else{ - sqlite3_snprintf(4, &z[j],"%03d",nDay+1); - j += 3; - } - break; - } - case 'J': { - sqlite3_snprintf(20, &z[j],"%.16g",x.iJD/86400000.0); - j+=sqlite3Strlen30(&z[j]); - break; - } - case 'm': sqlite3_snprintf(3, &z[j],"%02d",x.M); j+=2; break; - case 'M': sqlite3_snprintf(3, &z[j],"%02d",x.m); j+=2; break; - case 's': { - i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000); - sqlite3Int64ToText(iS, &z[j]); - j += sqlite3Strlen30(&z[j]); - break; - } - case 'S': sqlite3_snprintf(3,&z[j],"%02d",(int)x.s); j+=2; break; - case 'w': { - z[j++] = (char)(((x.iJD+129600000)/86400000) % 7) + '0'; - break; - } - case 'Y': { - sqlite3_snprintf(5,&z[j],"%04d",x.Y); j+=sqlite3Strlen30(&z[j]); - break; + if( zFmt[i]!='%' ) continue; + if( j<i ) sqlite3_str_append(&sRes, zFmt+j, (int)(i-j)); + i++; + j = i + 1; + switch( zFmt[i] ){ + case 'd': { + sqlite3_str_appendf(&sRes, "%02d", x.D); + break; + } + case 'f': { + double s = x.s; + if( s>59.999 ) s = 59.999; + sqlite3_str_appendf(&sRes, "%06.3f", s); + break; + } + case 'H': { + sqlite3_str_appendf(&sRes, "%02d", x.h); + break; + } + case 'W': /* Fall thru */ + case 'j': { + int nDay; /* Number of days since 1st day of year */ + DateTime y = x; + y.validJD = 0; + y.M = 1; + y.D = 1; + computeJD(&y); + nDay = (int)((x.iJD-y.iJD+43200000)/86400000); + if( zFmt[i]=='W' ){ + int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */ + wd = (int)(((x.iJD+43200000)/86400000)%7); + sqlite3_str_appendf(&sRes,"%02d",(nDay+7-wd)/7); + }else{ + sqlite3_str_appendf(&sRes,"%03d",nDay+1); } - default: z[j++] = '%'; break; + break; + } + case 'J': { + sqlite3_str_appendf(&sRes,"%.16g",x.iJD/86400000.0); + break; + } + case 'm': { + sqlite3_str_appendf(&sRes,"%02d",x.M); + break; + } + case 'M': { + sqlite3_str_appendf(&sRes,"%02d",x.m); + break; + } + case 's': { + i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000); + sqlite3_str_appendf(&sRes,"%lld",iS); + break; + } + case 'S': { + sqlite3_str_appendf(&sRes,"%02d",(int)x.s); + break; + } + case 'w': { + sqlite3_str_appendchar(&sRes, 1, + (char)(((x.iJD+129600000)/86400000) % 7) + '0'); + break; + } + case 'Y': { + sqlite3_str_appendf(&sRes,"%04d",x.Y); + break; + } + case '%': { + sqlite3_str_appendchar(&sRes, 1, '%'); + break; + } + default: { + sqlite3_str_reset(&sRes); + return; } } } - z[j] = 0; - sqlite3_result_text(context, z, -1, - z==zBuf ? SQLITE_TRANSIENT : SQLITE_DYNAMIC); + if( j<i ) sqlite3_str_append(&sRes, zFmt+j, (int)(i-j)); + sqlite3ResultStrAccum(context, &sRes); } /*@@ -23405,6 +24595,7 @@ SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){
static FuncDef aDateTimeFuncs[] = { #ifndef SQLITE_OMIT_DATETIME_FUNCS PURE_DATE(julianday, -1, 0, 0, juliandayFunc ), + PURE_DATE(unixepoch, -1, 0, 0, unixepochFunc ), PURE_DATE(date, -1, 0, 0, dateFunc ), PURE_DATE(time, -1, 0, 0, timeFunc ), PURE_DATE(datetime, -1, 0, 0, datetimeFunc ),@@ -23586,6 +24777,7 @@ int (*xSectorSize)(sqlite3_file*) = id->pMethods->xSectorSize;
return (xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE); } SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id){ + if( NEVER(id->pMethods==0) ) return 0; return id->pMethods->xDeviceCharacteristics(id); } #ifndef SQLITE_OMIT_WAL@@ -23740,12 +24932,15 @@ if( pFile ){
rc = sqlite3OsOpen(pVfs, zFile, pFile, flags, pOutFlags); if( rc!=SQLITE_OK ){ sqlite3_free(pFile); + *ppFile = 0; }else{ *ppFile = pFile; } }else{ + *ppFile = 0; rc = SQLITE_NOMEM_BKPT; } + assert( *ppFile!=0 || rc!=SQLITE_OK ); return rc; } SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *pFile){@@ -24463,7 +25658,7 @@ **
** This routine checks the guards at either end of the allocation and ** if they are incorrect it asserts. */ -static struct MemBlockHdr *sqlite3MemsysGetHeader(void *pAllocation){ +static struct MemBlockHdr *sqlite3MemsysGetHeader(const void *pAllocation){ struct MemBlockHdr *p; int *pInt; u8 *pU8;@@ -24710,7 +25905,7 @@ ** verify the type of an allocation. For example:
** ** assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); */ -SQLITE_PRIVATE int sqlite3MemdebugHasType(void *p, u8 eType){ +SQLITE_PRIVATE int sqlite3MemdebugHasType(const void *p, u8 eType){ int rc = 1; if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){ struct MemBlockHdr *pHdr;@@ -24732,7 +25927,7 @@ ** verify the type of an allocation. For example:
** ** assert( sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) ); */ -SQLITE_PRIVATE int sqlite3MemdebugNoType(void *p, u8 eType){ +SQLITE_PRIVATE int sqlite3MemdebugNoType(const void *p, u8 eType){ int rc = 1; if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){ struct MemBlockHdr *pHdr;@@ -25955,8 +27150,13 @@ ** or 1073741824 bytes.
*/ static int memsys5Roundup(int n){ int iFullSz; - if( n > 0x40000000 ) return 0; - for(iFullSz=mem5.szAtom; iFullSz<n; iFullSz *= 2); + if( n<=mem5.szAtom*2 ){ + if( n<=mem5.szAtom ) return mem5.szAtom; + return mem5.szAtom*2; + } + if( n>0x40000000 ) return 0; + for(iFullSz=mem5.szAtom*8; iFullSz<n; iFullSz *= 4); + if( (iFullSz/2)>=n ) return iFullSz/2; return iFullSz; }@@ -27110,205 +28310,7 @@ #if SQLITE_OS_WIN
/* ** Include code that is common to all os_*.c files */ -/************** Include os_common.h in the middle of mutex_w32.c *************/ -/************** Begin file os_common.h ***************************************/ -/* -** 2004 May 22 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This file contains macros and a little bit of code that is common to -** all of the platform-specific files (os_*.c) and is #included into those -** files. -** -** This file should be #included by the os_*.c files only. It is not a -** general purpose header file. -*/ -#ifndef _OS_COMMON_H_ -#define _OS_COMMON_H_ - -/* -** At least two bugs have slipped in because we changed the MEMORY_DEBUG -** macro to SQLITE_DEBUG and some older makefiles have not yet made the -** switch. The following code should catch this problem at compile-time. -*/ -#ifdef MEMORY_DEBUG -# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead." -#endif - -/* -** Macros for performance tracing. Normally turned off. Only works -** on i486 hardware. -*/ -#ifdef SQLITE_PERFORMANCE_TRACE - -/* -** hwtime.h contains inline assembler code for implementing -** high-performance timing routines. -*/ -/************** Include hwtime.h in the middle of os_common.h ****************/ -/************** Begin file hwtime.h ******************************************/ -/* -** 2008 May 27 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This file contains inline asm code for retrieving "high-performance" -** counters for x86 and x86_64 class CPUs. -*/ -#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 -** profiling. -*/ -#if !defined(__STRICT_ANSI__) && \ - (defined(__GNUC__) || defined(_MSC_VER)) && \ - (defined(i386) || defined(__i386__) || defined(_M_IX86)) - - #if defined(__GNUC__) - - __inline__ sqlite_uint64 sqlite3Hwtime(void){ - unsigned int lo, hi; - __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); - return (sqlite_uint64)hi << 32 | lo; - } - - #elif defined(_MSC_VER) - - __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){ - __asm { - rdtsc - ret ; return value at EDX:EAX - } - } - - #endif - -#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__)) - - __inline__ sqlite_uint64 sqlite3Hwtime(void){ - unsigned long val; - __asm__ __volatile__ ("rdtsc" : "=A" (val)); - return val; - } - -#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__)) - - __inline__ sqlite_uint64 sqlite3Hwtime(void){ - unsigned long long retval; - unsigned long junk; - __asm__ __volatile__ ("\n\ - 1: mftbu %1\n\ - mftb %L0\n\ - mftbu %0\n\ - cmpw %0,%1\n\ - bne 1b" - : "=r" (retval), "=r" (junk)); - return retval; - } - -#else - - /* - ** asm() is needed for hardware timing support. Without asm(), - ** disable the sqlite3Hwtime() routine. - ** - ** sqlite3Hwtime() is only used for some obscure debugging - ** and analysis configurations, not in any deliverable, so this - ** should not be a great loss. - */ -SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } - -#endif - -#endif /* !defined(SQLITE_HWTIME_H) */ - -/************** End of hwtime.h **********************************************/ -/************** Continuing where we left off in os_common.h ******************/ - -static sqlite_uint64 g_start; -static sqlite_uint64 g_elapsed; -#define TIMER_START g_start=sqlite3Hwtime() -#define TIMER_END g_elapsed=sqlite3Hwtime()-g_start -#define TIMER_ELAPSED g_elapsed -#else -#define TIMER_START -#define TIMER_END -#define TIMER_ELAPSED ((sqlite_uint64)0) -#endif - -/* -** If we compile with the SQLITE_TEST macro set, then the following block -** of code will give us the ability to simulate a disk I/O error. This -** is used for testing the I/O recovery logic. -*/ -#if defined(SQLITE_TEST) -SQLITE_API extern int sqlite3_io_error_hit; -SQLITE_API extern int sqlite3_io_error_hardhit; -SQLITE_API extern int sqlite3_io_error_pending; -SQLITE_API extern int sqlite3_io_error_persist; -SQLITE_API extern int sqlite3_io_error_benign; -SQLITE_API extern int sqlite3_diskfull_pending; -SQLITE_API extern int sqlite3_diskfull; -#define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X) -#define SimulateIOError(CODE) \ - if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \ - || sqlite3_io_error_pending-- == 1 ) \ - { local_ioerr(); CODE; } -static void local_ioerr(){ - IOTRACE(("IOERR\n")); - sqlite3_io_error_hit++; - if( !sqlite3_io_error_benign ) sqlite3_io_error_hardhit++; -} -#define SimulateDiskfullError(CODE) \ - if( sqlite3_diskfull_pending ){ \ - if( sqlite3_diskfull_pending == 1 ){ \ - local_ioerr(); \ - sqlite3_diskfull = 1; \ - sqlite3_io_error_hit = 1; \ - CODE; \ - }else{ \ - sqlite3_diskfull_pending--; \ - } \ - } -#else -#define SimulateIOErrorBenign(X) -#define SimulateIOError(A) -#define SimulateDiskfullError(A) -#endif /* defined(SQLITE_TEST) */ - -/* -** When testing, keep a count of the number of open files. -*/ -#if defined(SQLITE_TEST) -SQLITE_API extern int sqlite3_open_file_count; -#define OpenCounter(X) sqlite3_open_file_count+=(X) -#else -#define OpenCounter(X) -#endif /* defined(SQLITE_TEST) */ - -#endif /* !defined(_OS_COMMON_H_) */ - -/************** End of os_common.h *******************************************/ -/************** Continuing where we left off in mutex_w32.c ******************/ +/* #include "os_common.h" */ /* ** Include the header file for the Windows VFS.@@ -28101,7 +29103,7 @@ /*
** TRUE if p is a lookaside memory allocation from db */ #ifndef SQLITE_OMIT_LOOKASIDE -static int isLookaside(sqlite3 *db, void *p){ +static int isLookaside(sqlite3 *db, const void *p){ return SQLITE_WITHIN(p, db->lookaside.pStart, db->lookaside.pEnd); } #else@@ -28112,18 +29114,18 @@ /*
** Return the size of a memory allocation previously obtained from ** sqlite3Malloc() or sqlite3_malloc(). */ -SQLITE_PRIVATE int sqlite3MallocSize(void *p){ +SQLITE_PRIVATE int sqlite3MallocSize(const void *p){ assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); - return sqlite3GlobalConfig.m.xSize(p); + return sqlite3GlobalConfig.m.xSize((void*)p); } -static int lookasideMallocSize(sqlite3 *db, void *p){ +static int lookasideMallocSize(sqlite3 *db, const void *p){ #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE return p<db->lookaside.pMiddle ? db->lookaside.szTrue : LOOKASIDE_SMALL; #else return db->lookaside.szTrue; #endif } -SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){ +SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, const void *p){ assert( p!=0 ); #ifdef SQLITE_DEBUG if( db==0 || !isLookaside(db,p) ){@@ -28150,7 +29152,7 @@ return db->lookaside.szTrue;
} } } - return sqlite3GlobalConfig.m.xSize(p); + return sqlite3GlobalConfig.m.xSize((void*)p); } SQLITE_API sqlite3_uint64 sqlite3_msize(void *p){ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );@@ -28535,8 +29537,9 @@ /*
** Free any prior content in *pz and replace it with a copy of zNew. */ SQLITE_PRIVATE void sqlite3SetString(char **pz, sqlite3 *db, const char *zNew){ + char *z = sqlite3DbStrDup(db, zNew); sqlite3DbFree(db, *pz); - *pz = sqlite3DbStrDup(db, zNew); + *pz = z; } /*@@ -28544,8 +29547,15 @@ ** Call this routine to record the fact that an OOM (out-of-memory) error
** has happened. This routine will set db->mallocFailed, and also ** temporarily disable the lookaside memory allocator and interrupt ** any running VDBEs. +** +** Always return a NULL pointer so that this routine can be invoked using +** +** return sqlite3OomFault(db); +** +** and thereby avoid unnecessary stack frame allocations for the overwhelmingly +** common case where no OOM occurs. */ -SQLITE_PRIVATE void sqlite3OomFault(sqlite3 *db){ +SQLITE_PRIVATE void *sqlite3OomFault(sqlite3 *db){ if( db->mallocFailed==0 && db->bBenignMalloc==0 ){ db->mallocFailed = 1; if( db->nVdbeExec>0 ){@@ -28553,9 +29563,11 @@ AtomicStore(&db->u1.isInterrupted, 1);
} DisableLookaside; if( db->pParse ){ + sqlite3ErrorMsg(db->pParse, "out of memory"); db->pParse->rc = SQLITE_NOMEM_BKPT; } } + return 0; } /*@@ -28760,7 +29772,7 @@
/* ** Set the StrAccum object to an error mode. */ -static void setStrAccumError(StrAccum *p, u8 eError){ +SQLITE_PRIVATE void sqlite3StrAccumSetError(StrAccum *p, u8 eError){ assert( eError==SQLITE_NOMEM || eError==SQLITE_TOOBIG ); p->accError = eError; if( p->mxAlloc ) sqlite3_str_reset(p);@@ -28796,12 +29808,12 @@ static char *printfTempBuf(sqlite3_str *pAccum, sqlite3_int64 n){
char *z; if( pAccum->accError ) return 0; if( n>pAccum->nAlloc && n>pAccum->mxAlloc ){ - setStrAccumError(pAccum, SQLITE_TOOBIG); + sqlite3StrAccumSetError(pAccum, SQLITE_TOOBIG); return 0; } z = sqlite3DbMallocRaw(pAccum->db, n); if( z==0 ){ - setStrAccumError(pAccum, SQLITE_NOMEM); + sqlite3StrAccumSetError(pAccum, SQLITE_NOMEM); } return z; }@@ -29418,8 +30430,8 @@ break;
case etSQLESCAPE: /* %q: Escape ' characters */ case etSQLESCAPE2: /* %Q: Escape ' and enclose in '...' */ case etSQLESCAPE3: { /* %w: Escape " characters */ - int i, j, k, n, isnull; - int needQuote; + i64 i, j, k, n; + int needQuote, isnull; char ch; char q = ((xtype==etSQLESCAPE3)?'"':'\''); /* Quote character */ char *escarg;@@ -29464,12 +30476,22 @@ length = j;
goto adjust_width_for_utf8; } case etTOKEN: { - Token *pToken; if( (pAccum->printfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return; - pToken = va_arg(ap, Token*); - assert( bArgList==0 ); - if( pToken && pToken->n ){ - sqlite3_str_append(pAccum, (const char*)pToken->z, pToken->n); + if( flag_alternateform ){ + /* %#T means an Expr pointer that uses Expr.u.zToken */ + Expr *pExpr = va_arg(ap,Expr*); + if( ALWAYS(pExpr) && ALWAYS(!ExprHasProperty(pExpr,EP_IntValue)) ){ + sqlite3_str_appendall(pAccum, (const char*)pExpr->u.zToken); + sqlite3RecordErrorOffsetOfExpr(pAccum->db, pExpr); + } + }else{ + /* %T means a Token pointer */ + Token *pToken = va_arg(ap, Token*); + assert( bArgList==0 ); + if( pToken && pToken->n ){ + sqlite3_str_append(pAccum, (const char*)pToken->z, pToken->n); + sqlite3RecordErrorByteOffset(pAccum->db, pToken->z); + } } length = width = 0; break;@@ -29489,8 +30511,14 @@ }
sqlite3_str_appendall(pAccum, pItem->zName); }else if( pItem->zAlias ){ sqlite3_str_appendall(pAccum, pItem->zAlias); - }else if( ALWAYS(pItem->pSelect) ){ - sqlite3_str_appendf(pAccum, "SUBQUERY %u", pItem->pSelect->selId); + }else{ + Select *pSel = pItem->pSelect; + assert( pSel!=0 ); + if( pSel->selFlags & SF_NestedFrom ){ + sqlite3_str_appendf(pAccum, "(join-%u)", pSel->selId); + }else{ + sqlite3_str_appendf(pAccum, "(subquery-%u)", pSel->selId); + } } length = width = 0; break;@@ -29524,6 +30552,44 @@ }
}/* End for loop over the format string */ } /* End of function */ + +/* +** The z string points to the first character of a token that is +** associated with an error. If db does not already have an error +** byte offset recorded, try to compute the error byte offset for +** z and set the error byte offset in db. +*/ +SQLITE_PRIVATE void sqlite3RecordErrorByteOffset(sqlite3 *db, const char *z){ + const Parse *pParse; + const char *zText; + const char *zEnd; + assert( z!=0 ); + if( NEVER(db==0) ) return; + if( db->errByteOffset!=(-2) ) return; + pParse = db->pParse; + if( NEVER(pParse==0) ) return; + zText =pParse->zTail; + if( NEVER(zText==0) ) return; + zEnd = &zText[strlen(zText)]; + if( SQLITE_WITHIN(z,zText,zEnd) ){ + db->errByteOffset = (int)(z-zText); + } +} + +/* +** If pExpr has a byte offset for the start of a token, record that as +** as the error offset. +*/ +SQLITE_PRIVATE void sqlite3RecordErrorOffsetOfExpr(sqlite3 *db, const Expr *pExpr){ + while( pExpr + && (ExprHasProperty(pExpr,EP_OuterON|EP_InnerON) || pExpr->w.iOfst<=0) + ){ + pExpr = pExpr->pLeft; + } + if( pExpr==0 ) return; + db->errByteOffset = pExpr->w.iOfst; +} + /* ** Enlarge the memory allocation on a StrAccum object so that it is ** able to accept at least N more bytes of text.@@ -29531,7 +30597,7 @@ **
** Return the number of bytes of text that StrAccum is able to accept ** after the attempted enlargement. The value returned might be zero. */ -static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ +SQLITE_PRIVATE int sqlite3StrAccumEnlarge(StrAccum *p, int N){ char *zNew; assert( p->nChar+(i64)N >= p->nAlloc ); /* Only called if really needed */ if( p->accError ){@@ -29540,7 +30606,7 @@ testcase(p->accError==SQLITE_NOMEM);
return 0; } if( p->mxAlloc==0 ){ - setStrAccumError(p, SQLITE_TOOBIG); + sqlite3StrAccumSetError(p, SQLITE_TOOBIG); return p->nAlloc - p->nChar - 1; }else{ char *zOld = isMalloced(p) ? p->zText : 0;@@ -29553,7 +30619,7 @@ szNew += p->nChar;
} if( szNew > p->mxAlloc ){ sqlite3_str_reset(p); - setStrAccumError(p, SQLITE_TOOBIG); + sqlite3StrAccumSetError(p, SQLITE_TOOBIG); return 0; }else{ p->nAlloc = (int)szNew;@@ -29571,7 +30637,7 @@ p->nAlloc = sqlite3DbMallocSize(p->db, zNew);
p->printfFlags |= SQLITE_PRINTF_MALLOCED; }else{ sqlite3_str_reset(p); - setStrAccumError(p, SQLITE_NOMEM); + sqlite3StrAccumSetError(p, SQLITE_NOMEM); return 0; } }@@ -29644,7 +30710,7 @@ if( zText ){
memcpy(zText, p->zText, p->nChar+1); p->printfFlags |= SQLITE_PRINTF_MALLOCED; }else{ - setStrAccumError(p, SQLITE_NOMEM); + sqlite3StrAccumSetError(p, SQLITE_NOMEM); } p->zText = zText; return zText;@@ -29657,6 +30723,22 @@ return strAccumFinishRealloc(p);
} } return p->zText; +} + +/* +** Use the content of the StrAccum passed as the second argument +** as the result of an SQL function. +*/ +SQLITE_PRIVATE void sqlite3ResultStrAccum(sqlite3_context *pCtx, StrAccum *p){ + if( p->accError ){ + sqlite3_result_error_code(pCtx, p->accError); + sqlite3_str_reset(p); + }else if( isMalloced(p) ){ + sqlite3_result_text(pCtx, p->zText, p->nChar, SQLITE_DYNAMIC); + }else{ + sqlite3_result_text(pCtx, "", 0, SQLITE_STATIC); + sqlite3_str_reset(p); + } } /*@@ -29961,40 +31043,44 @@ /*
** Add a new subitem to the tree. The moreToFollow flag indicates that this ** is not the last item in the tree. */ -static TreeView *sqlite3TreeViewPush(TreeView *p, u8 moreToFollow){ +static void sqlite3TreeViewPush(TreeView **pp, u8 moreToFollow){ + TreeView *p = *pp; if( p==0 ){ - p = sqlite3_malloc64( sizeof(*p) ); - if( p==0 ) return 0; + *pp = p = sqlite3_malloc64( sizeof(*p) ); + if( p==0 ) return; memset(p, 0, sizeof(*p)); }else{ p->iLevel++; } assert( moreToFollow==0 || moreToFollow==1 ); - if( p->iLevel<sizeof(p->bLine) ) p->bLine[p->iLevel] = moreToFollow; - return p; + if( p->iLevel<(int)sizeof(p->bLine) ) p->bLine[p->iLevel] = moreToFollow; } /* ** Finished with one layer of the tree */ -static void sqlite3TreeViewPop(TreeView *p){ +static void sqlite3TreeViewPop(TreeView **pp){ + TreeView *p = *pp; if( p==0 ) return; p->iLevel--; - if( p->iLevel<0 ) sqlite3_free(p); + if( p->iLevel<0 ){ + sqlite3_free(p); + *pp = 0; + } } /* ** Generate a single line of output for the tree, with a prefix that contains ** all the appropriate tree lines */ -static void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){ +SQLITE_PRIVATE void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){ va_list ap; int i; StrAccum acc; - char zBuf[500]; + char zBuf[1000]; sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); if( p ){ - for(i=0; i<p->iLevel && i<sizeof(p->bLine)-1; i++){ + for(i=0; i<p->iLevel && i<(int)sizeof(p->bLine)-1; i++){ sqlite3_str_append(&acc, p->bLine[i] ? "| " : " ", 4); } sqlite3_str_append(&acc, p->bLine[i] ? "|-- " : "'-- ", 4);@@ -30015,11 +31101,58 @@ /*
** Shorthand for starting a new tree item that consists of a single label */ static void sqlite3TreeViewItem(TreeView *p, const char *zLabel,u8 moreFollows){ - p = sqlite3TreeViewPush(p, moreFollows); + sqlite3TreeViewPush(&p, moreFollows); sqlite3TreeViewLine(p, "%s", zLabel); } /* +** Show a list of Column objects in tree format. +*/ +SQLITE_PRIVATE void sqlite3TreeViewColumnList( + TreeView *pView, + const Column *aCol, + int nCol, + u8 moreToFollow +){ + int i; + sqlite3TreeViewPush(&pView, moreToFollow); + sqlite3TreeViewLine(pView, "COLUMNS"); + for(i=0; i<nCol; i++){ + u16 flg = aCol[i].colFlags; + int colMoreToFollow = i<(nCol - 1); + sqlite3TreeViewPush(&pView, colMoreToFollow); + sqlite3TreeViewLine(pView, 0); + printf(" %s", aCol[i].zCnName); + switch( aCol[i].eCType ){ + case COLTYPE_ANY: printf(" ANY"); break; + case COLTYPE_BLOB: printf(" BLOB"); break; + case COLTYPE_INT: printf(" INT"); break; + case COLTYPE_INTEGER: printf(" INTEGER"); break; + case COLTYPE_REAL: printf(" REAL"); break; + case COLTYPE_TEXT: printf(" TEXT"); break; + case COLTYPE_CUSTOM: { + if( flg & COLFLAG_HASTYPE ){ + const char *z = aCol[i].zCnName; + z += strlen(z)+1; + printf(" X-%s", z); + break; + } + } + } + if( flg & COLFLAG_PRIMKEY ) printf(" PRIMARY KEY"); + if( flg & COLFLAG_HIDDEN ) printf(" HIDDEN"); +#ifdef COLFLAG_NOEXPAND + if( flg & COLFLAG_NOEXPAND ) printf(" NO-EXPAND"); +#endif + if( flg ) printf(" flags=%04x", flg); + printf("\n"); + fflush(stdout); + sqlite3TreeViewPop(&pView); + } + sqlite3TreeViewPop(&pView); +} + +/* ** Generate a human-readable description of a WITH clause. */ SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 moreToFollow){@@ -30032,7 +31165,7 @@ }else{
sqlite3TreeViewLine(pView, "WITH (0x%p)", pWith); } if( pWith->nCte>0 ){ - pView = sqlite3TreeViewPush(pView, 1); + sqlite3TreeViewPush(&pView, moreToFollow); for(i=0; i<pWith->nCte; i++){ StrAccum x; char zLine[1000];@@ -30048,6 +31181,10 @@ cSep = ',';
} sqlite3_str_appendf(&x, ")"); } + if( pCte->eM10d!=M10d_Any ){ + sqlite3_str_appendf(&x, " %sMATERIALIZED", + pCte->eM10d==M10d_No ? "NOT " : ""); + } if( pCte->pUse ){ sqlite3_str_appendf(&x, " (pUse=0x%p, nUse=%d)", pCte->pUse, pCte->pUse->nUse);@@ -30055,9 +31192,9 @@ }
sqlite3StrAccumFinish(&x); sqlite3TreeViewItem(pView, zLine, i<pWith->nCte-1); sqlite3TreeViewSelect(pView, pCte->pSelect, 0); - sqlite3TreeViewPop(pView); + sqlite3TreeViewPop(&pView); } - sqlite3TreeViewPop(pView); + sqlite3TreeViewPop(&pView); } }@@ -30066,10 +31203,12 @@ ** Generate a human-readable description of a SrcList object.
*/ SQLITE_PRIVATE void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){ int i; + if( pSrc==0 ) return; for(i=0; i<pSrc->nSrc; i++){ const SrcItem *pItem = &pSrc->a[i]; StrAccum x; - char zLine[100]; + int n = 0; + char zLine[1000]; sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); x.printfFlags |= SQLITE_PRINTF_INTERNAL; sqlite3_str_appendf(&x, "{%d:*} %!S", pItem->iCursor, pItem);@@ -30077,8 +31216,17 @@ if( pItem->pTab ){
sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p used=%llx", pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab, pItem->colUsed); } - if( pItem->fg.jointype & JT_LEFT ){ + if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))==(JT_LEFT|JT_RIGHT) ){ + sqlite3_str_appendf(&x, " FULL-OUTER-JOIN"); + }else if( pItem->fg.jointype & JT_LEFT ){ sqlite3_str_appendf(&x, " LEFT-JOIN"); + }else if( pItem->fg.jointype & JT_RIGHT ){ + sqlite3_str_appendf(&x, " RIGHT-JOIN"); + }else if( pItem->fg.jointype & JT_CROSS ){ + sqlite3_str_appendf(&x, " CROSS-JOIN"); + } + if( pItem->fg.jointype & JT_LTORJ ){ + sqlite3_str_appendf(&x, " LTORJ"); } if( pItem->fg.fromDDL ){ sqlite3_str_appendf(&x, " DDL");@@ -30086,15 +31234,30 @@ }
if( pItem->fg.isCte ){ sqlite3_str_appendf(&x, " CteUse=0x%p", pItem->u2.pCteUse); } + if( pItem->fg.isOn || (pItem->fg.isUsing==0 && pItem->u3.pOn!=0) ){ + sqlite3_str_appendf(&x, " ON"); + } sqlite3StrAccumFinish(&x); sqlite3TreeViewItem(pView, zLine, i<pSrc->nSrc-1); + n = 0; + if( pItem->pSelect ) n++; + if( pItem->fg.isTabFunc ) n++; + if( pItem->fg.isUsing ) n++; + if( pItem->fg.isUsing ){ + sqlite3TreeViewIdList(pView, pItem->u3.pUsing, (--n)>0, "USING"); + } if( pItem->pSelect ){ - sqlite3TreeViewSelect(pView, pItem->pSelect, 0); + if( pItem->pTab ){ + Table *pTab = pItem->pTab; + sqlite3TreeViewColumnList(pView, pTab->aCol, pTab->nCol, 1); + } + assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) ); + sqlite3TreeViewSelect(pView, pItem->pSelect, (--n)>0); } if( pItem->fg.isTabFunc ){ sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:"); } - sqlite3TreeViewPop(pView); + sqlite3TreeViewPop(&pView); } }@@ -30108,11 +31271,11 @@ if( p==0 ){
sqlite3TreeViewLine(pView, "nil-SELECT"); return; } - pView = sqlite3TreeViewPush(pView, moreToFollow); + sqlite3TreeViewPush(&pView, moreToFollow); if( p->pWith ){ sqlite3TreeViewWith(pView, p->pWith, 1); cnt = 1; - sqlite3TreeViewPush(pView, 1); + sqlite3TreeViewPush(&pView, 1); } do{ if( p->selFlags & SF_WhereBegin ){@@ -30126,7 +31289,7 @@ p->selId, p, p->selFlags,
(int)p->nSelectRow ); } - if( cnt++ ) sqlite3TreeViewPop(pView); + if( cnt++ ) sqlite3TreeViewPop(&pView); if( p->pPrior ){ n = 1000; }else{@@ -30149,24 +31312,24 @@ n--;
#ifndef SQLITE_OMIT_WINDOWFUNC if( p->pWin ){ Window *pX; - pView = sqlite3TreeViewPush(pView, (n--)>0); + sqlite3TreeViewPush(&pView, (n--)>0); sqlite3TreeViewLine(pView, "window-functions"); for(pX=p->pWin; pX; pX=pX->pNextWin){ sqlite3TreeViewWinFunc(pView, pX, pX->pNextWin!=0); } - sqlite3TreeViewPop(pView); + sqlite3TreeViewPop(&pView); } #endif if( p->pSrc && p->pSrc->nSrc ){ - pView = sqlite3TreeViewPush(pView, (n--)>0); + sqlite3TreeViewPush(&pView, (n--)>0); sqlite3TreeViewLine(pView, "FROM"); sqlite3TreeViewSrcList(pView, p->pSrc); - sqlite3TreeViewPop(pView); + sqlite3TreeViewPop(&pView); } if( p->pWhere ){ sqlite3TreeViewItem(pView, "WHERE", (n--)>0); sqlite3TreeViewExpr(pView, p->pWhere, 0); - sqlite3TreeViewPop(pView); + sqlite3TreeViewPop(&pView); } if( p->pGroupBy ){ sqlite3TreeViewExprList(pView, p->pGroupBy, (n--)>0, "GROUPBY");@@ -30174,7 +31337,7 @@ }
if( p->pHaving ){ sqlite3TreeViewItem(pView, "HAVING", (n--)>0); sqlite3TreeViewExpr(pView, p->pHaving, 0); - sqlite3TreeViewPop(pView); + sqlite3TreeViewPop(&pView); } #ifndef SQLITE_OMIT_WINDOWFUNC if( p->pWinDefn ){@@ -30183,7 +31346,7 @@ sqlite3TreeViewItem(pView, "WINDOW", (n--)>0);
for(pX=p->pWinDefn; pX; pX=pX->pNextWin){ sqlite3TreeViewWindow(pView, pX, pX->pNextWin!=0); } - sqlite3TreeViewPop(pView); + sqlite3TreeViewPop(&pView); } #endif if( p->pOrderBy ){@@ -30195,9 +31358,9 @@ sqlite3TreeViewExpr(pView, p->pLimit->pLeft, p->pLimit->pRight!=0);
if( p->pLimit->pRight ){ sqlite3TreeViewItem(pView, "OFFSET", (n--)>0); sqlite3TreeViewExpr(pView, p->pLimit->pRight, 0); - sqlite3TreeViewPop(pView); + sqlite3TreeViewPop(&pView); } - sqlite3TreeViewPop(pView); + sqlite3TreeViewPop(&pView); } if( p->pPrior ){ const char *zOp = "UNION";@@ -30210,7 +31373,7 @@ sqlite3TreeViewItem(pView, zOp, 1);
} p = p->pPrior; }while( p!=0 ); - sqlite3TreeViewPop(pView); + sqlite3TreeViewPop(&pView); } #ifndef SQLITE_OMIT_WINDOWFUNC@@ -30226,24 +31389,24 @@ ){
switch( eBound ){ case TK_UNBOUNDED: { sqlite3TreeViewItem(pView, "UNBOUNDED", moreToFollow); - sqlite3TreeViewPop(pView); + sqlite3TreeViewPop(&pView); break; } case TK_CURRENT: { sqlite3TreeViewItem(pView, "CURRENT", moreToFollow); - sqlite3TreeViewPop(pView); + sqlite3TreeViewPop(&pView); break; } case TK_PRECEDING: { sqlite3TreeViewItem(pView, "PRECEDING", moreToFollow); sqlite3TreeViewExpr(pView, pExpr, 0); - sqlite3TreeViewPop(pView); + sqlite3TreeViewPop(&pView); break; } case TK_FOLLOWING: { sqlite3TreeViewItem(pView, "FOLLOWING", moreToFollow); sqlite3TreeViewExpr(pView, pExpr, 0); - sqlite3TreeViewPop(pView); + sqlite3TreeViewPop(&pView); break; } }@@ -30256,12 +31419,13 @@ ** Generate a human-readable explanation for a Window object
*/ SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u8 more){ int nElement = 0; + if( pWin==0 ) return; if( pWin->pFilter ){ sqlite3TreeViewItem(pView, "FILTER", 1); sqlite3TreeViewExpr(pView, pWin->pFilter, 0); - sqlite3TreeViewPop(pView); + sqlite3TreeViewPop(&pView); } - pView = sqlite3TreeViewPush(pView, more); + sqlite3TreeViewPush(&pView, more); if( pWin->zName ){ sqlite3TreeViewLine(pView, "OVER %s (%p)", pWin->zName, pWin); }else{@@ -30272,9 +31436,9 @@ if( pWin->pOrderBy ) nElement++;
if( pWin->eFrmType ) nElement++; if( pWin->eExclude ) nElement++; if( pWin->zBase ){ - sqlite3TreeViewPush(pView, (--nElement)>0); + sqlite3TreeViewPush(&pView, (--nElement)>0); sqlite3TreeViewLine(pView, "window: %s", pWin->zBase); - sqlite3TreeViewPop(pView); + sqlite3TreeViewPop(&pView); } if( pWin->pPartition ){ sqlite3TreeViewExprList(pView, pWin->pPartition, nElement>0,"PARTITION-BY");@@ -30292,7 +31456,7 @@ pWin->bImplicitFrame ? " (implied)" : "");
sqlite3TreeViewItem(pView, zBuf, (--nElement)>0); sqlite3TreeViewBound(pView, pWin->eStart, pWin->pStart, 1); sqlite3TreeViewBound(pView, pWin->eEnd, pWin->pEnd, 0); - sqlite3TreeViewPop(pView); + sqlite3TreeViewPop(&pView); } if( pWin->eExclude ){ char zBuf[30];@@ -30307,11 +31471,11 @@ sqlite3_snprintf(sizeof(zBuf),zBuf,"invalid(%d)", pWin->eExclude);
zExclude = zBuf; break; } - sqlite3TreeViewPush(pView, 0); + sqlite3TreeViewPush(&pView, 0); sqlite3TreeViewLine(pView, "EXCLUDE %s", zExclude); - sqlite3TreeViewPop(pView); + sqlite3TreeViewPop(&pView); } - sqlite3TreeViewPop(pView); + sqlite3TreeViewPop(&pView); } #endif /* SQLITE_OMIT_WINDOWFUNC */@@ -30320,11 +31484,12 @@ /*
** Generate a human-readable explanation for a Window Function object */ SQLITE_PRIVATE void sqlite3TreeViewWinFunc(TreeView *pView, const Window *pWin, u8 more){ - pView = sqlite3TreeViewPush(pView, more); + if( pWin==0 ) return; + sqlite3TreeViewPush(&pView, more); sqlite3TreeViewLine(pView, "WINFUNC %s(%d)", - pWin->pFunc->zName, pWin->pFunc->nArg); + pWin->pWFunc->zName, pWin->pWFunc->nArg); sqlite3TreeViewWindow(pView, pWin, 0); - sqlite3TreeViewPop(pView); + sqlite3TreeViewPop(&pView); } #endif /* SQLITE_OMIT_WINDOWFUNC */@@ -30335,10 +31500,10 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
const char *zBinOp = 0; /* Binary operator */ const char *zUniOp = 0; /* Unary operator */ char zFlgs[200]; - pView = sqlite3TreeViewPush(pView, moreToFollow); + sqlite3TreeViewPush(&pView, moreToFollow); if( pExpr==0 ){ sqlite3TreeViewLine(pView, "nil"); - sqlite3TreeViewPop(pView); + sqlite3TreeViewPop(&pView); return; } if( pExpr->flags || pExpr->affExpr || pExpr->vvaFlags ){@@ -30346,8 +31511,11 @@ StrAccum x;
sqlite3StrAccumInit(&x, 0, zFlgs, sizeof(zFlgs), 0); sqlite3_str_appendf(&x, " fg.af=%x.%c", pExpr->flags, pExpr->affExpr ? pExpr->affExpr : 'n'); - if( ExprHasProperty(pExpr, EP_FromJoin) ){ - sqlite3_str_appendf(&x, " iRJT=%d", pExpr->iRightJoinTable); + if( ExprHasProperty(pExpr, EP_OuterON) ){ + sqlite3_str_appendf(&x, " outer.iJoin=%d", pExpr->w.iJoin); + } + if( ExprHasProperty(pExpr, EP_InnerON) ){ + sqlite3_str_appendf(&x, " inner.iJoin=%d", pExpr->w.iJoin); } if( ExprHasProperty(pExpr, EP_FromDDL) ){ sqlite3_str_appendf(&x, " DDL");@@ -30377,6 +31545,7 @@ }
sqlite3TreeViewLine(pView, "COLUMN(%d)%s%s", pExpr->iColumn, zFlgs, zOp2); }else{ + assert( ExprUseYTab(pExpr) ); sqlite3TreeViewLine(pView, "{%d:%d} pTab=%p%s", pExpr->iTable, pExpr->iColumn, pExpr->y.pTab, zFlgs);@@ -30396,11 +31565,13 @@ break;
} #ifndef SQLITE_OMIT_FLOATING_POINT case TK_FLOAT: { + assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken); break; } #endif case TK_STRING: { + assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView,"%Q", pExpr->u.zToken); break; }@@ -30409,17 +31580,19 @@ sqlite3TreeViewLine(pView,"NULL");
break; } case TK_TRUEFALSE: { - sqlite3TreeViewLine(pView, - sqlite3ExprTruthValue(pExpr) ? "TRUE" : "FALSE"); + sqlite3TreeViewLine(pView,"%s%s", + sqlite3ExprTruthValue(pExpr) ? "TRUE" : "FALSE", zFlgs); break; } #ifndef SQLITE_OMIT_BLOB_LITERAL case TK_BLOB: { + assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken); break; } #endif case TK_VARIABLE: { + assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView,"VARIABLE(%s,%d)", pExpr->u.zToken, pExpr->iColumn); break;@@ -30429,12 +31602,14 @@ sqlite3TreeViewLine(pView,"REGISTER(%d)", pExpr->iTable);
break; } case TK_ID: { + assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView,"ID \"%w\"", pExpr->u.zToken); break; } #ifndef SQLITE_OMIT_CAST case TK_CAST: { /* Expressions of the form: CAST(pLeft AS token) */ + assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView,"CAST %Q", pExpr->u.zToken); sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); break;@@ -30484,6 +31659,7 @@ break;
} case TK_SPAN: { + assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView, "SPAN %Q", pExpr->u.zToken); sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); break;@@ -30495,6 +31671,7 @@ ** emulate collation associated with a table column. These show
** up in the treeview output as "SOFT-COLLATE". Explicit COLLATE ** operators that appear in the original SQL always have the ** EP_Collate bit set and appear in treeview output as just "COLLATE" */ + assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView, "%sCOLLATE %Q%s", !ExprHasProperty(pExpr, EP_Collate) ? "SOFT-" : "", pExpr->u.zToken, zFlgs);@@ -30510,6 +31687,7 @@ if( ExprHasProperty(pExpr, EP_TokenOnly) ){
pFarg = 0; pWin = 0; }else{ + assert( ExprUseXList(pExpr) ); pFarg = pExpr->x.pList; #ifndef SQLITE_OMIT_WINDOWFUNC pWin = ExprHasProperty(pExpr, EP_WinFunc) ? pExpr->y.pWin : 0;@@ -30517,6 +31695,7 @@ #else
pWin = 0; #endif } + assert( !ExprHasProperty(pExpr, EP_IntValue) ); if( pExpr->op==TK_AGG_FUNCTION ){ sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q%s agg=%d[%d]/%p", pExpr->op2, pExpr->u.zToken, zFlgs,@@ -30548,19 +31727,31 @@ break;
} #ifndef SQLITE_OMIT_SUBQUERY case TK_EXISTS: { + assert( ExprUseXSelect(pExpr) ); sqlite3TreeViewLine(pView, "EXISTS-expr flags=0x%x", pExpr->flags); sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); break; } case TK_SELECT: { + assert( ExprUseXSelect(pExpr) ); sqlite3TreeViewLine(pView, "subquery-expr flags=0x%x", pExpr->flags); sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); break; } case TK_IN: { - sqlite3TreeViewLine(pView, "IN flags=0x%x", pExpr->flags); + sqlite3_str *pStr = sqlite3_str_new(0); + char *z; + sqlite3_str_appendf(pStr, "IN flags=0x%x", pExpr->flags); + if( pExpr->iTable ) sqlite3_str_appendf(pStr, " iTable=%d",pExpr->iTable); + if( ExprHasProperty(pExpr, EP_Subrtn) ){ + sqlite3_str_appendf(pStr, " subrtn(%d,%d)", + pExpr->y.sub.regReturn, pExpr->y.sub.iAddr); + } + z = sqlite3_str_finish(pStr); + sqlite3TreeViewLine(pView, z); + sqlite3_free(z); sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + if( ExprUseXSelect(pExpr) ){ sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); }else{ sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0);@@ -30581,9 +31772,12 @@ ** Y is stored in pExpr->pList->a[0].pExpr.
** Z is stored in pExpr->pList->a[1].pExpr. */ case TK_BETWEEN: { - Expr *pX = pExpr->pLeft; - Expr *pY = pExpr->x.pList->a[0].pExpr; - Expr *pZ = pExpr->x.pList->a[1].pExpr; + const Expr *pX, *pY, *pZ; + pX = pExpr->pLeft; + assert( ExprUseXList(pExpr) ); + assert( pExpr->x.pList->nExpr==2 ); + pY = pExpr->x.pList->a[0].pExpr; + pZ = pExpr->x.pList->a[1].pExpr; sqlite3TreeViewLine(pView, "BETWEEN"); sqlite3TreeViewExpr(pView, pX, 1); sqlite3TreeViewExpr(pView, pY, 1);@@ -30605,6 +31799,7 @@ }
case TK_CASE: { sqlite3TreeViewLine(pView, "CASE"); sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); + assert( ExprUseXList(pExpr) ); sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0); break; }@@ -30617,6 +31812,7 @@ case OE_Abort: zType = "abort"; break;
case OE_Fail: zType = "fail"; break; case OE_Ignore: zType = "ignore"; break; } + assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView, "RAISE %s(%Q)", zType, pExpr->u.zToken); break; }@@ -30629,12 +31825,16 @@ break;
} case TK_VECTOR: { char *z = sqlite3_mprintf("VECTOR%s",zFlgs); + assert( ExprUseXList(pExpr) ); sqlite3TreeViewBareExprList(pView, pExpr->x.pList, z); sqlite3_free(z); break; } case TK_SELECT_COLUMN: { - sqlite3TreeViewLine(pView, "SELECT-COLUMN %d", pExpr->iColumn); + sqlite3TreeViewLine(pView, "SELECT-COLUMN %d of [0..%d]%s", + pExpr->iColumn, pExpr->iTable-1, + pExpr->pRight==pExpr->pLeft ? " (SELECT-owner)" : ""); + assert( ExprUseXSelect(pExpr->pLeft) ); sqlite3TreeViewSelect(pView, pExpr->pLeft->x.pSelect, 0); break; }@@ -30651,6 +31851,15 @@ tmp.op = pExpr->op2;
sqlite3TreeViewExpr(pView, &tmp, 0); break; } + case TK_ROW: { + if( pExpr->iColumn<=0 ){ + sqlite3TreeViewLine(pView, "First FROM table rowid"); + }else{ + sqlite3TreeViewLine(pView, "First FROM table column %d", + pExpr->iColumn-1); + } + break; + } default: { sqlite3TreeViewLine(pView, "op=%d", pExpr->op); break;@@ -30664,7 +31873,7 @@ }else if( zUniOp ){
sqlite3TreeViewLine(pView, "%s%s", zUniOp, zFlgs); sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); } - sqlite3TreeViewPop(pView); + sqlite3TreeViewPop(&pView); }@@ -30686,13 +31895,25 @@ for(i=0; i<pList->nExpr; i++){
int j = pList->a[i].u.x.iOrderByCol; char *zName = pList->a[i].zEName; int moreToFollow = i<pList->nExpr - 1; - if( pList->a[i].eEName!=ENAME_NAME ) zName = 0; if( j || zName ){ - sqlite3TreeViewPush(pView, moreToFollow); + sqlite3TreeViewPush(&pView, moreToFollow); moreToFollow = 0; sqlite3TreeViewLine(pView, 0); if( zName ){ - fprintf(stdout, "AS %s ", zName); + switch( pList->a[i].fg.eEName ){ + default: + fprintf(stdout, "AS %s ", zName); + break; + case ENAME_TAB: + fprintf(stdout, "TABLE-ALIAS-NAME(\"%s\") ", zName); + if( pList->a[i].fg.bUsed ) fprintf(stdout, "(used) "); + if( pList->a[i].fg.bUsingTerm ) fprintf(stdout, "(USING-term) "); + if( pList->a[i].fg.bNoExpand ) fprintf(stdout, "(NoExpand) "); + break; + case ENAME_SPAN: + fprintf(stdout, "SPAN(\"%s\") ", zName); + break; + } } if( j ){ fprintf(stdout, "iOrderByCol=%d", j);@@ -30702,7 +31923,7 @@ fflush(stdout);
} sqlite3TreeViewExpr(pView, pList->a[i].pExpr, moreToFollow); if( j || zName ){ - sqlite3TreeViewPop(pView); + sqlite3TreeViewPop(&pView); } } }@@ -30713,10 +31934,377 @@ const ExprList *pList,
u8 moreToFollow, const char *zLabel ){ - pView = sqlite3TreeViewPush(pView, moreToFollow); + sqlite3TreeViewPush(&pView, moreToFollow); sqlite3TreeViewBareExprList(pView, pList, zLabel); - sqlite3TreeViewPop(pView); + sqlite3TreeViewPop(&pView); +} + +/* +** Generate a human-readable explanation of an id-list. +*/ +SQLITE_PRIVATE void sqlite3TreeViewBareIdList( + TreeView *pView, + const IdList *pList, + const char *zLabel +){ + if( zLabel==0 || zLabel[0]==0 ) zLabel = "LIST"; + if( pList==0 ){ + sqlite3TreeViewLine(pView, "%s (empty)", zLabel); + }else{ + int i; + sqlite3TreeViewLine(pView, "%s", zLabel); + for(i=0; i<pList->nId; i++){ + char *zName = pList->a[i].zName; + int moreToFollow = i<pList->nId - 1; + if( zName==0 ) zName = "(null)"; + sqlite3TreeViewPush(&pView, moreToFollow); + sqlite3TreeViewLine(pView, 0); + if( pList->eU4==EU4_NONE ){ + fprintf(stdout, "%s\n", zName); + }else if( pList->eU4==EU4_IDX ){ + fprintf(stdout, "%s (%d)\n", zName, pList->a[i].u4.idx); + }else{ + assert( pList->eU4==EU4_EXPR ); + if( pList->a[i].u4.pExpr==0 ){ + fprintf(stdout, "%s (pExpr=NULL)\n", zName); + }else{ + fprintf(stdout, "%s\n", zName); + sqlite3TreeViewPush(&pView, i<pList->nId-1); + sqlite3TreeViewExpr(pView, pList->a[i].u4.pExpr, 0); + sqlite3TreeViewPop(&pView); + } + } + sqlite3TreeViewPop(&pView); + } + } +} +SQLITE_PRIVATE void sqlite3TreeViewIdList( + TreeView *pView, + const IdList *pList, + u8 moreToFollow, + const char *zLabel +){ + sqlite3TreeViewPush(&pView, moreToFollow); + sqlite3TreeViewBareIdList(pView, pList, zLabel); + sqlite3TreeViewPop(&pView); +} + +/* +** Generate a human-readable explanation of a list of Upsert objects +*/ +SQLITE_PRIVATE void sqlite3TreeViewUpsert( + TreeView *pView, + const Upsert *pUpsert, + u8 moreToFollow +){ + if( pUpsert==0 ) return; + sqlite3TreeViewPush(&pView, moreToFollow); + while( pUpsert ){ + int n; + sqlite3TreeViewPush(&pView, pUpsert->pNextUpsert!=0 || moreToFollow); + sqlite3TreeViewLine(pView, "ON CONFLICT DO %s", + pUpsert->isDoUpdate ? "UPDATE" : "NOTHING"); + n = (pUpsert->pUpsertSet!=0) + (pUpsert->pUpsertWhere!=0); + sqlite3TreeViewExprList(pView, pUpsert->pUpsertTarget, (n--)>0, "TARGET"); + sqlite3TreeViewExprList(pView, pUpsert->pUpsertSet, (n--)>0, "SET"); + if( pUpsert->pUpsertWhere ){ + sqlite3TreeViewItem(pView, "WHERE", (n--)>0); + sqlite3TreeViewExpr(pView, pUpsert->pUpsertWhere, 0); + sqlite3TreeViewPop(&pView); + } + sqlite3TreeViewPop(&pView); + pUpsert = pUpsert->pNextUpsert; + } + sqlite3TreeViewPop(&pView); +} + +#if TREETRACE_ENABLED +/* +** Generate a human-readable diagram of the data structure that go +** into generating an DELETE statement. +*/ +SQLITE_PRIVATE void sqlite3TreeViewDelete( + const With *pWith, + const SrcList *pTabList, + const Expr *pWhere, + const ExprList *pOrderBy, + const Expr *pLimit, + const Trigger *pTrigger +){ + int n = 0; + TreeView *pView = 0; + sqlite3TreeViewPush(&pView, 0); + sqlite3TreeViewLine(pView, "DELETE"); + if( pWith ) n++; + if( pTabList ) n++; + if( pWhere ) n++; + if( pOrderBy ) n++; + if( pLimit ) n++; + if( pTrigger ) n++; + if( pWith ){ + sqlite3TreeViewPush(&pView, (--n)>0); + sqlite3TreeViewWith(pView, pWith, 0); + sqlite3TreeViewPop(&pView); + } + if( pTabList ){ + sqlite3TreeViewPush(&pView, (--n)>0); + sqlite3TreeViewLine(pView, "FROM"); + sqlite3TreeViewSrcList(pView, pTabList); + sqlite3TreeViewPop(&pView); + } + if( pWhere ){ + sqlite3TreeViewPush(&pView, (--n)>0); + sqlite3TreeViewLine(pView, "WHERE"); + sqlite3TreeViewExpr(pView, pWhere, 0); + sqlite3TreeViewPop(&pView); + } + if( pOrderBy ){ + sqlite3TreeViewExprList(pView, pOrderBy, (--n)>0, "ORDER-BY"); + } + if( pLimit ){ + sqlite3TreeViewPush(&pView, (--n)>0); + sqlite3TreeViewLine(pView, "LIMIT"); + sqlite3TreeViewExpr(pView, pLimit, 0); + sqlite3TreeViewPop(&pView); + } + if( pTrigger ){ + sqlite3TreeViewTrigger(pView, pTrigger, (--n)>0, 1); + } + sqlite3TreeViewPop(&pView); } +#endif /* TREETRACE_ENABLED */ + +#if TREETRACE_ENABLED +/* +** Generate a human-readable diagram of the data structure that go +** into generating an INSERT statement. +*/ +SQLITE_PRIVATE void sqlite3TreeViewInsert( + const With *pWith, + const SrcList *pTabList, + const IdList *pColumnList, + const Select *pSelect, + const ExprList *pExprList, + int onError, + const Upsert *pUpsert, + const Trigger *pTrigger +){ + TreeView *pView = 0; + int n = 0; + const char *zLabel = "INSERT"; + switch( onError ){ + case OE_Replace: zLabel = "REPLACE"; break; + case OE_Ignore: zLabel = "INSERT OR IGNORE"; break; + case OE_Rollback: zLabel = "INSERT OR ROLLBACK"; break; + case OE_Abort: zLabel = "INSERT OR ABORT"; break; + case OE_Fail: zLabel = "INSERT OR FAIL"; break; + } + sqlite3TreeViewPush(&pView, 0); + sqlite3TreeViewLine(pView, zLabel); + if( pWith ) n++; + if( pTabList ) n++; + if( pColumnList ) n++; + if( pSelect ) n++; + if( pExprList ) n++; + if( pUpsert ) n++; + if( pTrigger ) n++; + if( pWith ){ + sqlite3TreeViewPush(&pView, (--n)>0); + sqlite3TreeViewWith(pView, pWith, 0); + sqlite3TreeViewPop(&pView); + } + if( pTabList ){ + sqlite3TreeViewPush(&pView, (--n)>0); + sqlite3TreeViewLine(pView, "INTO"); + sqlite3TreeViewSrcList(pView, pTabList); + sqlite3TreeViewPop(&pView); + } + if( pColumnList ){ + sqlite3TreeViewIdList(pView, pColumnList, (--n)>0, "COLUMNS"); + } + if( pSelect ){ + sqlite3TreeViewPush(&pView, (--n)>0); + sqlite3TreeViewLine(pView, "DATA-SOURCE"); + sqlite3TreeViewSelect(pView, pSelect, 0); + sqlite3TreeViewPop(&pView); + } + if( pExprList ){ + sqlite3TreeViewExprList(pView, pExprList, (--n)>0, "VALUES"); + } + if( pUpsert ){ + sqlite3TreeViewPush(&pView, (--n)>0); + sqlite3TreeViewLine(pView, "UPSERT"); + sqlite3TreeViewUpsert(pView, pUpsert, 0); + sqlite3TreeViewPop(&pView); + } + if( pTrigger ){ + sqlite3TreeViewTrigger(pView, pTrigger, (--n)>0, 1); + } + sqlite3TreeViewPop(&pView); +} +#endif /* TREETRACE_ENABLED */ + +#if TREETRACE_ENABLED +/* +** Generate a human-readable diagram of the data structure that go +** into generating an UPDATE statement. +*/ +SQLITE_PRIVATE void sqlite3TreeViewUpdate( + const With *pWith, + const SrcList *pTabList, + const ExprList *pChanges, + const Expr *pWhere, + int onError, + const ExprList *pOrderBy, + const Expr *pLimit, + const Upsert *pUpsert, + const Trigger *pTrigger +){ + int n = 0; + TreeView *pView = 0; + const char *zLabel = "UPDATE"; + switch( onError ){ + case OE_Replace: zLabel = "UPDATE OR REPLACE"; break; + case OE_Ignore: zLabel = "UPDATE OR IGNORE"; break; + case OE_Rollback: zLabel = "UPDATE OR ROLLBACK"; break; + case OE_Abort: zLabel = "UPDATE OR ABORT"; break; + case OE_Fail: zLabel = "UPDATE OR FAIL"; break; + } + sqlite3TreeViewPush(&pView, 0); + sqlite3TreeViewLine(pView, zLabel); + if( pWith ) n++; + if( pTabList ) n++; + if( pChanges ) n++; + if( pWhere ) n++; + if( pOrderBy ) n++; + if( pLimit ) n++; + if( pUpsert ) n++; + if( pTrigger ) n++; + if( pWith ){ + sqlite3TreeViewPush(&pView, (--n)>0); + sqlite3TreeViewWith(pView, pWith, 0); + sqlite3TreeViewPop(&pView); + } + if( pTabList ){ + sqlite3TreeViewPush(&pView, (--n)>0); + sqlite3TreeViewLine(pView, "FROM"); + sqlite3TreeViewSrcList(pView, pTabList); + sqlite3TreeViewPop(&pView); + } + if( pChanges ){ + sqlite3TreeViewExprList(pView, pChanges, (--n)>0, "SET"); + } + if( pWhere ){ + sqlite3TreeViewPush(&pView, (--n)>0); + sqlite3TreeViewLine(pView, "WHERE"); + sqlite3TreeViewExpr(pView, pWhere, 0); + sqlite3TreeViewPop(&pView); + } + if( pOrderBy ){ + sqlite3TreeViewExprList(pView, pOrderBy, (--n)>0, "ORDER-BY"); + } + if( pLimit ){ + sqlite3TreeViewPush(&pView, (--n)>0); + sqlite3TreeViewLine(pView, "LIMIT"); + sqlite3TreeViewExpr(pView, pLimit, 0); + sqlite3TreeViewPop(&pView); + } + if( pUpsert ){ + sqlite3TreeViewPush(&pView, (--n)>0); + sqlite3TreeViewLine(pView, "UPSERT"); + sqlite3TreeViewUpsert(pView, pUpsert, 0); + sqlite3TreeViewPop(&pView); + } + if( pTrigger ){ + sqlite3TreeViewTrigger(pView, pTrigger, (--n)>0, 1); + } + sqlite3TreeViewPop(&pView); +} +#endif /* TREETRACE_ENABLED */ + +#ifndef SQLITE_OMIT_TRIGGER +/* +** Show a human-readable graph of a TriggerStep +*/ +SQLITE_PRIVATE void sqlite3TreeViewTriggerStep( + TreeView *pView, + const TriggerStep *pStep, + u8 moreToFollow, + u8 showFullList +){ + int cnt = 0; + if( pStep==0 ) return; + sqlite3TreeViewPush(&pView, + moreToFollow || (showFullList && pStep->pNext!=0)); + do{ + if( cnt++ && pStep->pNext==0 ){ + sqlite3TreeViewPop(&pView); + sqlite3TreeViewPush(&pView, 0); + } + sqlite3TreeViewLine(pView, "%s", pStep->zSpan ? pStep->zSpan : "RETURNING"); + }while( showFullList && (pStep = pStep->pNext)!=0 ); + sqlite3TreeViewPop(&pView); +} + +/* +** Show a human-readable graph of a Trigger +*/ +SQLITE_PRIVATE void sqlite3TreeViewTrigger( + TreeView *pView, + const Trigger *pTrigger, + u8 moreToFollow, + u8 showFullList +){ + int cnt = 0; + if( pTrigger==0 ) return; + sqlite3TreeViewPush(&pView, + moreToFollow || (showFullList && pTrigger->pNext!=0)); + do{ + if( cnt++ && pTrigger->pNext==0 ){ + sqlite3TreeViewPop(&pView); + sqlite3TreeViewPush(&pView, 0); + } + sqlite3TreeViewLine(pView, "TRIGGER %s", pTrigger->zName); + sqlite3TreeViewPush(&pView, 0); + sqlite3TreeViewTriggerStep(pView, pTrigger->step_list, 0, 1); + sqlite3TreeViewPop(&pView); + }while( showFullList && (pTrigger = pTrigger->pNext)!=0 ); + sqlite3TreeViewPop(&pView); +} +#endif /* SQLITE_OMIT_TRIGGER */ + + +/* +** These simplified versions of the tree-view routines omit unnecessary +** parameters. These variants are intended to be used from a symbolic +** debugger, such as "gdb", during interactive debugging sessions. +** +** This routines are given external linkage so that they will always be +** accessible to the debugging, and to avoid warnings about unused +** functions. But these routines only exist in debugging builds, so they +** do not contaminate the interface. +*/ +SQLITE_PRIVATE void sqlite3ShowExpr(const Expr *p){ sqlite3TreeViewExpr(0,p,0); } +SQLITE_PRIVATE void sqlite3ShowExprList(const ExprList *p){ sqlite3TreeViewExprList(0,p,0,0);} +SQLITE_PRIVATE void sqlite3ShowIdList(const IdList *p){ sqlite3TreeViewIdList(0,p,0,0); } +SQLITE_PRIVATE void sqlite3ShowSrcList(const SrcList *p){ sqlite3TreeViewSrcList(0,p); } +SQLITE_PRIVATE void sqlite3ShowSelect(const Select *p){ sqlite3TreeViewSelect(0,p,0); } +SQLITE_PRIVATE void sqlite3ShowWith(const With *p){ sqlite3TreeViewWith(0,p,0); } +SQLITE_PRIVATE void sqlite3ShowUpsert(const Upsert *p){ sqlite3TreeViewUpsert(0,p,0); } +#ifndef SQLITE_OMIT_TRIGGER +SQLITE_PRIVATE void sqlite3ShowTriggerStep(const TriggerStep *p){ + sqlite3TreeViewTriggerStep(0,p,0,0); +} +SQLITE_PRIVATE void sqlite3ShowTriggerStepList(const TriggerStep *p){ + sqlite3TreeViewTriggerStep(0,p,0,1); +} +SQLITE_PRIVATE void sqlite3ShowTrigger(const Trigger *p){ sqlite3TreeViewTrigger(0,p,0,0); } +SQLITE_PRIVATE void sqlite3ShowTriggerList(const Trigger *p){ sqlite3TreeViewTrigger(0,p,0,1);} +#endif +#ifndef SQLITE_OMIT_WINDOWFUNC +SQLITE_PRIVATE void sqlite3ShowWindow(const Window *p){ sqlite3TreeViewWindow(0,p,0); } +SQLITE_PRIVATE void sqlite3ShowWinFunc(const Window *p){ sqlite3TreeViewWinFunc(0,p,0); } +#endif #endif /* SQLITE_DEBUG */@@ -31703,16 +33291,6 @@ #include <math.h>
#endif /* -** Routine needed to support the testcase() macro. -*/ -#ifdef SQLITE_COVERAGE_TEST -SQLITE_PRIVATE void sqlite3Coverage(int x){ - static unsigned dummy = 0; - dummy += (unsigned)x; -} -#endif - -/* ** Calls to sqlite3FaultSim() are used to simulate a failure during testing, ** or to bypass normal error detection during testing in order to let ** execute proceed futher downstream.@@ -31741,11 +33319,21 @@
#ifndef SQLITE_OMIT_FLOATING_POINT /* ** Return true if the floating point value is Not a Number (NaN). +** +** Use the math library isnan() function if compiled with SQLITE_HAVE_ISNAN. +** Otherwise, we have our own implementation that works on most systems. */ SQLITE_PRIVATE int sqlite3IsNaN(double x){ + int rc; /* The value return */ +#if !SQLITE_HAVE_ISNAN && !HAVE_ISNAN u64 y; memcpy(&y,&x,sizeof(y)); - return IsNaN(y); + rc = IsNaN(y); +#else + rc = isnan(x); +#endif /* HAVE_ISNAN */ + testcase( rc ); + return rc; } #endif /* SQLITE_OMIT_FLOATING_POINT */@@ -31770,8 +33358,14 @@ ** The column type is an extra string stored after the zero-terminator on
** the column name if and only if the COLFLAG_HASTYPE flag is set. */ SQLITE_PRIVATE char *sqlite3ColumnType(Column *pCol, char *zDflt){ - if( (pCol->colFlags & COLFLAG_HASTYPE)==0 ) return zDflt; - return pCol->zName + strlen(pCol->zName) + 1; + if( pCol->colFlags & COLFLAG_HASTYPE ){ + return pCol->zCnName + strlen(pCol->zCnName) + 1; + }else if( pCol->eCType ){ + assert( pCol->eCType<=SQLITE_N_STDTYPE ); + return (char*)sqlite3StdType[pCol->eCType-1]; + }else{ + return zDflt; + } } /*@@ -31792,7 +33386,11 @@ */
SQLITE_PRIVATE void sqlite3Error(sqlite3 *db, int err_code){ assert( db!=0 ); db->errCode = err_code; - if( err_code || db->pErr ) sqlite3ErrorFinish(db, err_code); + if( err_code || db->pErr ){ + sqlite3ErrorFinish(db, err_code); + }else{ + db->errByteOffset = -1; + } } /*@@ -31802,6 +33400,7 @@ */
SQLITE_PRIVATE void sqlite3ErrorClear(sqlite3 *db){ assert( db!=0 ); db->errCode = SQLITE_OK; + db->errByteOffset = -1; if( db->pErr ) sqlite3ValueSetNull(db->pErr); }@@ -31822,17 +33421,8 @@ ** Set the most recent error code and error string for the sqlite
** handle "db". The error code is set to "err_code". ** ** If it is not NULL, string zFormat specifies the format of the -** error string in the style of the printf functions: The following -** format characters are allowed: -** -** %s Insert a string -** %z A string that should be freed after use -** %d Insert an integer -** %T Insert a token -** %S Insert the first element of a SrcList -** -** zFormat and any string tokens that follow it are assumed to be -** encoded in UTF-8. +** error string. zFormat and any string tokens that follow it are +** assumed to be encoded in UTF-8. ** ** To clear the most recent error for sqlite handle "db", sqlite3Error ** should be called with err_code set to SQLITE_OK and zFormat set@@ -31856,13 +33446,6 @@ }
/* ** Add an error message to pParse->zErrMsg and increment pParse->nErr. -** The following formatting characters are allowed: -** -** %s Insert a string -** %z A string that should be freed after use -** %d Insert an integer -** %T Insert a token -** %S Insert the first element of a SrcList ** ** This function should be used to report any error that occurs while ** compiling an SQL statement (i.e. within sqlite3_prepare()). The@@ -31875,11 +33458,19 @@ SQLITE_PRIVATE void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
char *zMsg; va_list ap; sqlite3 *db = pParse->db; + assert( db!=0 ); + assert( db->pParse==pParse ); + db->errByteOffset = -2; va_start(ap, zFormat); zMsg = sqlite3VMPrintf(db, zFormat, ap); va_end(ap); + if( db->errByteOffset<-1 ) db->errByteOffset = -1; if( db->suppressErr ){ sqlite3DbFree(db, zMsg); + if( db->mallocFailed ){ + pParse->nErr++; + pParse->rc = SQLITE_NOMEM; + } }else{ pParse->nErr++; sqlite3DbFree(db, pParse->zErrMsg);@@ -31942,9 +33533,32 @@ }
z[j] = 0; } SQLITE_PRIVATE void sqlite3DequoteExpr(Expr *p){ + assert( !ExprHasProperty(p, EP_IntValue) ); assert( sqlite3Isquote(p->u.zToken[0]) ); p->flags |= p->u.zToken[0]=='"' ? EP_Quoted|EP_DblQuoted : EP_Quoted; sqlite3Dequote(p->u.zToken); +} + +/* +** If the input token p is quoted, try to adjust the token to remove +** the quotes. This is not always possible: +** +** "abc" -> abc +** "ab""cd" -> (not possible because of the interior "") +** +** Remove the quotes if possible. This is a optimization. The overall +** system should still return the correct answer even if this routine +** is always a no-op. +*/ +SQLITE_PRIVATE void sqlite3DequoteToken(Token *p){ + unsigned int i; + if( p->n<2 ) return; + if( !sqlite3Isquote(p->z[0]) ) return; + for(i=1; i<p->n-1; i++){ + if( sqlite3Isquote(p->z[i]) ) return; + } + p->n -= 2; + p->z++; } /*@@ -33052,13 +34666,13 @@ ** open properly and is not fit for general use but which can be
** used as an argument to sqlite3_errmsg() or sqlite3_close(). */ SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3 *db){ - u32 magic; + u8 eOpenState; if( db==0 ){ logBadConnection("NULL"); return 0; } - magic = db->magic; - if( magic!=SQLITE_MAGIC_OPEN ){ + eOpenState = db->eOpenState; + if( eOpenState!=SQLITE_STATE_OPEN ){ if( sqlite3SafetyCheckSickOrOk(db) ){ testcase( sqlite3GlobalConfig.xLog!=0 ); logBadConnection("unopened");@@ -33069,11 +34683,11 @@ return 1;
} } SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3 *db){ - u32 magic; - magic = db->magic; - if( magic!=SQLITE_MAGIC_SICK && - magic!=SQLITE_MAGIC_OPEN && - magic!=SQLITE_MAGIC_BUSY ){ + u8 eOpenState; + eOpenState = db->eOpenState; + if( eOpenState!=SQLITE_STATE_SICK && + eOpenState!=SQLITE_STATE_OPEN && + eOpenState!=SQLITE_STATE_BUSY ){ testcase( sqlite3GlobalConfig.xLog!=0 ); logBadConnection("invalid"); return 0;@@ -33238,7 +34852,6 @@ }
return a[x&7] + y - 10; } -#ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Convert a double into a LogEst ** In other words, compute an approximation for 10*log2(x).@@ -33253,16 +34866,9 @@ memcpy(&a, &x, 8);
e = (a>>52) - 1022; return e*10; } -#endif /* SQLITE_OMIT_VIRTUALTABLE */ -#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \ - defined(SQLITE_ENABLE_STAT4) || \ - defined(SQLITE_EXPLAIN_ESTIMATED_ROWS) /* ** Convert a LogEst into an integer. -** -** Note that this routine is only used when one or more of various -** non-standard compile-time options is enabled. */ SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst x){ u64 n;@@ -33270,17 +34876,9 @@ n = x%10;
x /= 10; if( n>=5 ) n -= 2; else if( n>=1 ) n -= 1; -#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \ - defined(SQLITE_EXPLAIN_ESTIMATED_ROWS) if( x>60 ) return (u64)LARGEST_INT64; -#else - /* If only SQLITE_ENABLE_STAT4 is on, then the largest input - ** possible to this routine is 310, resulting in a maximum x of 31 */ - assert( x<=60 ); -#endif return x>=3 ? (n+8)<<(x-3) : (n+8)>>(3-x); } -#endif /* defined SCANSTAT or STAT4 or ESTIMATED_ROWS */ /* ** Add a new name/number pair to a VList. This might require that the@@ -33674,53 +35272,53 @@ static const char *const azName[] = {
/* 0 */ "Savepoint" OpHelp(""), /* 1 */ "AutoCommit" OpHelp(""), /* 2 */ "Transaction" OpHelp(""), - /* 3 */ "SorterNext" OpHelp(""), - /* 4 */ "Prev" OpHelp(""), - /* 5 */ "Next" OpHelp(""), - /* 6 */ "Checkpoint" OpHelp(""), - /* 7 */ "JournalMode" OpHelp(""), - /* 8 */ "Vacuum" OpHelp(""), - /* 9 */ "VFilter" OpHelp("iplan=r[P3] zplan='P4'"), - /* 10 */ "VUpdate" OpHelp("data=r[P3@P2]"), - /* 11 */ "Goto" OpHelp(""), - /* 12 */ "Gosub" OpHelp(""), - /* 13 */ "InitCoroutine" OpHelp(""), - /* 14 */ "Yield" OpHelp(""), - /* 15 */ "MustBeInt" OpHelp(""), - /* 16 */ "Jump" OpHelp(""), - /* 17 */ "Once" OpHelp(""), - /* 18 */ "If" OpHelp(""), + /* 3 */ "Checkpoint" OpHelp(""), + /* 4 */ "JournalMode" OpHelp(""), + /* 5 */ "Vacuum" OpHelp(""), + /* 6 */ "VFilter" OpHelp("iplan=r[P3] zplan='P4'"), + /* 7 */ "VUpdate" OpHelp("data=r[P3@P2]"), + /* 8 */ "Goto" OpHelp(""), + /* 9 */ "Gosub" OpHelp(""), + /* 10 */ "InitCoroutine" OpHelp(""), + /* 11 */ "Yield" OpHelp(""), + /* 12 */ "MustBeInt" OpHelp(""), + /* 13 */ "Jump" OpHelp(""), + /* 14 */ "Once" OpHelp(""), + /* 15 */ "If" OpHelp(""), + /* 16 */ "IfNot" OpHelp(""), + /* 17 */ "IsNullOrType" OpHelp("if typeof(r[P1]) IN (P3,5) goto P2"), + /* 18 */ "IfNullRow" OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"), /* 19 */ "Not" OpHelp("r[P2]= !r[P1]"), - /* 20 */ "IfNot" OpHelp(""), - /* 21 */ "IfNullRow" OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"), - /* 22 */ "SeekLT" OpHelp("key=r[P3@P4]"), - /* 23 */ "SeekLE" OpHelp("key=r[P3@P4]"), - /* 24 */ "SeekGE" OpHelp("key=r[P3@P4]"), - /* 25 */ "SeekGT" OpHelp("key=r[P3@P4]"), - /* 26 */ "IfNotOpen" OpHelp("if( !csr[P1] ) goto P2"), - /* 27 */ "IfNoHope" OpHelp("key=r[P3@P4]"), - /* 28 */ "NoConflict" OpHelp("key=r[P3@P4]"), - /* 29 */ "NotFound" OpHelp("key=r[P3@P4]"), - /* 30 */ "Found" OpHelp("key=r[P3@P4]"), - /* 31 */ "SeekRowid" OpHelp("intkey=r[P3]"), - /* 32 */ "NotExists" OpHelp("intkey=r[P3]"), - /* 33 */ "Last" OpHelp(""), - /* 34 */ "IfSmaller" OpHelp(""), - /* 35 */ "SorterSort" OpHelp(""), - /* 36 */ "Sort" OpHelp(""), - /* 37 */ "Rewind" OpHelp(""), - /* 38 */ "IdxLE" OpHelp("key=r[P3@P4]"), - /* 39 */ "IdxGT" OpHelp("key=r[P3@P4]"), - /* 40 */ "IdxLT" OpHelp("key=r[P3@P4]"), - /* 41 */ "IdxGE" OpHelp("key=r[P3@P4]"), - /* 42 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"), + /* 20 */ "SeekLT" OpHelp("key=r[P3@P4]"), + /* 21 */ "SeekLE" OpHelp("key=r[P3@P4]"), + /* 22 */ "SeekGE" OpHelp("key=r[P3@P4]"), + /* 23 */ "SeekGT" OpHelp("key=r[P3@P4]"), + /* 24 */ "IfNotOpen" OpHelp("if( !csr[P1] ) goto P2"), + /* 25 */ "IfNoHope" OpHelp("key=r[P3@P4]"), + /* 26 */ "NoConflict" OpHelp("key=r[P3@P4]"), + /* 27 */ "NotFound" OpHelp("key=r[P3@P4]"), + /* 28 */ "Found" OpHelp("key=r[P3@P4]"), + /* 29 */ "SeekRowid" OpHelp("intkey=r[P3]"), + /* 30 */ "NotExists" OpHelp("intkey=r[P3]"), + /* 31 */ "Last" OpHelp(""), + /* 32 */ "IfSmaller" OpHelp(""), + /* 33 */ "SorterSort" OpHelp(""), + /* 34 */ "Sort" OpHelp(""), + /* 35 */ "Rewind" OpHelp(""), + /* 36 */ "SorterNext" OpHelp(""), + /* 37 */ "Prev" OpHelp(""), + /* 38 */ "Next" OpHelp(""), + /* 39 */ "IdxLE" OpHelp("key=r[P3@P4]"), + /* 40 */ "IdxGT" OpHelp("key=r[P3@P4]"), + /* 41 */ "IdxLT" OpHelp("key=r[P3@P4]"), + /* 42 */ "IdxGE" OpHelp("key=r[P3@P4]"), /* 43 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"), /* 44 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"), - /* 45 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"), - /* 46 */ "Program" OpHelp(""), - /* 47 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), - /* 48 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"), - /* 49 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"), + /* 45 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"), + /* 46 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"), + /* 47 */ "Program" OpHelp(""), + /* 48 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), + /* 49 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"), /* 50 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"), /* 51 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"), /* 52 */ "Ne" OpHelp("IF r[P3]!=r[P1]"),@@ -33730,49 +35328,49 @@ /* 55 */ "Le" OpHelp("IF r[P3]<=r[P1]"),
/* 56 */ "Lt" OpHelp("IF r[P3]<r[P1]"), /* 57 */ "Ge" OpHelp("IF r[P3]>=r[P1]"), /* 58 */ "ElseEq" OpHelp(""), - /* 59 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"), - /* 60 */ "IncrVacuum" OpHelp(""), - /* 61 */ "VNext" OpHelp(""), - /* 62 */ "Init" OpHelp("Start at P2"), - /* 63 */ "PureFunc" OpHelp("r[P3]=func(r[P2@NP])"), - /* 64 */ "Function" OpHelp("r[P3]=func(r[P2@NP])"), - /* 65 */ "Return" OpHelp(""), - /* 66 */ "EndCoroutine" OpHelp(""), - /* 67 */ "HaltIfNull" OpHelp("if r[P3]=null halt"), - /* 68 */ "Halt" OpHelp(""), - /* 69 */ "Integer" OpHelp("r[P2]=P1"), - /* 70 */ "Int64" OpHelp("r[P2]=P4"), - /* 71 */ "String" OpHelp("r[P2]='P4' (len=P1)"), - /* 72 */ "Null" OpHelp("r[P2..P3]=NULL"), - /* 73 */ "SoftNull" OpHelp("r[P1]=NULL"), - /* 74 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"), - /* 75 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"), - /* 76 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"), - /* 77 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"), - /* 78 */ "SCopy" OpHelp("r[P2]=r[P1]"), - /* 79 */ "IntCopy" OpHelp("r[P2]=r[P1]"), - /* 80 */ "ChngCntRow" OpHelp("output=r[P1]"), - /* 81 */ "ResultRow" OpHelp("output=r[P1@P2]"), - /* 82 */ "CollSeq" OpHelp(""), - /* 83 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"), - /* 84 */ "RealAffinity" OpHelp(""), - /* 85 */ "Cast" OpHelp("affinity(r[P1])"), - /* 86 */ "Permutation" OpHelp(""), - /* 87 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), - /* 88 */ "IsTrue" OpHelp("r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4"), - /* 89 */ "ZeroOrNull" OpHelp("r[P2] = 0 OR NULL"), - /* 90 */ "Offset" OpHelp("r[P3] = sqlite_offset(P1)"), - /* 91 */ "Column" OpHelp("r[P3]=PX"), - /* 92 */ "Affinity" OpHelp("affinity(r[P1@P2])"), - /* 93 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), - /* 94 */ "Count" OpHelp("r[P2]=count()"), - /* 95 */ "ReadCookie" OpHelp(""), - /* 96 */ "SetCookie" OpHelp(""), - /* 97 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), - /* 98 */ "OpenRead" OpHelp("root=P2 iDb=P3"), - /* 99 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), - /* 100 */ "OpenDup" OpHelp(""), - /* 101 */ "OpenAutoindex" OpHelp("nColumn=P2"), + /* 59 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"), + /* 60 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"), + /* 61 */ "IncrVacuum" OpHelp(""), + /* 62 */ "VNext" OpHelp(""), + /* 63 */ "Filter" OpHelp("if key(P3@P4) not in filter(P1) goto P2"), + /* 64 */ "Init" OpHelp("Start at P2"), + /* 65 */ "PureFunc" OpHelp("r[P3]=func(r[P2@NP])"), + /* 66 */ "Function" OpHelp("r[P3]=func(r[P2@NP])"), + /* 67 */ "Return" OpHelp(""), + /* 68 */ "EndCoroutine" OpHelp(""), + /* 69 */ "HaltIfNull" OpHelp("if r[P3]=null halt"), + /* 70 */ "Halt" OpHelp(""), + /* 71 */ "Integer" OpHelp("r[P2]=P1"), + /* 72 */ "Int64" OpHelp("r[P2]=P4"), + /* 73 */ "String" OpHelp("r[P2]='P4' (len=P1)"), + /* 74 */ "BeginSubrtn" OpHelp("r[P2]=NULL"), + /* 75 */ "Null" OpHelp("r[P2..P3]=NULL"), + /* 76 */ "SoftNull" OpHelp("r[P1]=NULL"), + /* 77 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"), + /* 78 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"), + /* 79 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"), + /* 80 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"), + /* 81 */ "SCopy" OpHelp("r[P2]=r[P1]"), + /* 82 */ "IntCopy" OpHelp("r[P2]=r[P1]"), + /* 83 */ "FkCheck" OpHelp(""), + /* 84 */ "ResultRow" OpHelp("output=r[P1@P2]"), + /* 85 */ "CollSeq" OpHelp(""), + /* 86 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"), + /* 87 */ "RealAffinity" OpHelp(""), + /* 88 */ "Cast" OpHelp("affinity(r[P1])"), + /* 89 */ "Permutation" OpHelp(""), + /* 90 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), + /* 91 */ "IsTrue" OpHelp("r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4"), + /* 92 */ "ZeroOrNull" OpHelp("r[P2] = 0 OR NULL"), + /* 93 */ "Offset" OpHelp("r[P3] = sqlite_offset(P1)"), + /* 94 */ "Column" OpHelp("r[P3]=PX cursor P1 column P2"), + /* 95 */ "TypeCheck" OpHelp("typecheck(r[P1@P2])"), + /* 96 */ "Affinity" OpHelp("affinity(r[P1@P2])"), + /* 97 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), + /* 98 */ "Count" OpHelp("r[P2]=count()"), + /* 99 */ "ReadCookie" OpHelp(""), + /* 100 */ "SetCookie" OpHelp(""), + /* 101 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), /* 102 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"), /* 103 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"), /* 104 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<<r[P1]"),@@ -33783,74 +35381,81 @@ /* 108 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"),
/* 109 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"), /* 110 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"), /* 111 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"), - /* 112 */ "OpenEphemeral" OpHelp("nColumn=P2"), - /* 113 */ "BitNot" OpHelp("r[P2]= ~r[P1]"), - /* 114 */ "SorterOpen" OpHelp(""), - /* 115 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"), - /* 116 */ "String8" OpHelp("r[P2]='P4'"), - /* 117 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), - /* 118 */ "Close" OpHelp(""), - /* 119 */ "ColumnsUsed" OpHelp(""), - /* 120 */ "SeekScan" OpHelp("Scan-ahead up to P1 rows"), - /* 121 */ "SeekHit" OpHelp("set P2<=seekHit<=P3"), - /* 122 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"), - /* 123 */ "NewRowid" OpHelp("r[P2]=rowid"), - /* 124 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"), - /* 125 */ "RowCell" OpHelp(""), - /* 126 */ "Delete" OpHelp(""), - /* 127 */ "ResetCount" OpHelp(""), - /* 128 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"), - /* 129 */ "SorterData" OpHelp("r[P2]=data"), - /* 130 */ "RowData" OpHelp("r[P2]=data"), - /* 131 */ "Rowid" OpHelp("r[P2]=rowid"), - /* 132 */ "NullRow" OpHelp(""), - /* 133 */ "SeekEnd" OpHelp(""), - /* 134 */ "IdxInsert" OpHelp("key=r[P2]"), - /* 135 */ "SorterInsert" OpHelp("key=r[P2]"), - /* 136 */ "IdxDelete" OpHelp("key=r[P2@P3]"), - /* 137 */ "DeferredSeek" OpHelp("Move P3 to P1.rowid if needed"), - /* 138 */ "IdxRowid" OpHelp("r[P2]=rowid"), - /* 139 */ "FinishSeek" OpHelp(""), - /* 140 */ "Destroy" OpHelp(""), - /* 141 */ "Clear" OpHelp(""), - /* 142 */ "ResetSorter" OpHelp(""), - /* 143 */ "CreateBtree" OpHelp("r[P2]=root iDb=P1 flags=P3"), - /* 144 */ "SqlExec" OpHelp(""), - /* 145 */ "ParseSchema" OpHelp(""), - /* 146 */ "LoadAnalysis" OpHelp(""), - /* 147 */ "DropTable" OpHelp(""), - /* 148 */ "DropIndex" OpHelp(""), - /* 149 */ "DropTrigger" OpHelp(""), - /* 150 */ "IntegrityCk" OpHelp(""), - /* 151 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"), - /* 152 */ "Real" OpHelp("r[P2]=P4"), - /* 153 */ "Param" OpHelp(""), - /* 154 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), - /* 155 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), - /* 156 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"), - /* 157 */ "AggInverse" OpHelp("accum=r[P3] inverse(r[P2@P5])"), - /* 158 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), - /* 159 */ "AggStep1" OpHelp("accum=r[P3] step(r[P2@P5])"), - /* 160 */ "AggValue" OpHelp("r[P3]=value N=P2"), - /* 161 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), - /* 162 */ "Expire" OpHelp(""), - /* 163 */ "CursorLock" OpHelp(""), - /* 164 */ "CursorUnlock" OpHelp(""), - /* 165 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), - /* 166 */ "VBegin" OpHelp(""), - /* 167 */ "VCreate" OpHelp(""), - /* 168 */ "VDestroy" OpHelp(""), - /* 169 */ "VOpen" OpHelp(""), - /* 170 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), - /* 171 */ "VRename" OpHelp(""), - /* 172 */ "Pagecount" OpHelp(""), - /* 173 */ "MaxPgcnt" OpHelp(""), - /* 174 */ "Trace" OpHelp(""), - /* 175 */ "CursorHint" OpHelp(""), - /* 176 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"), - /* 177 */ "Noop" OpHelp(""), - /* 178 */ "Explain" OpHelp(""), - /* 179 */ "Abortable" OpHelp(""), + /* 112 */ "OpenRead" OpHelp("root=P2 iDb=P3"), + /* 113 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), + /* 114 */ "BitNot" OpHelp("r[P2]= ~r[P1]"), + /* 115 */ "OpenDup" OpHelp(""), + /* 116 */ "OpenAutoindex" OpHelp("nColumn=P2"), + /* 117 */ "String8" OpHelp("r[P2]='P4'"), + /* 118 */ "OpenEphemeral" OpHelp("nColumn=P2"), + /* 119 */ "SorterOpen" OpHelp(""), + /* 120 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"), + /* 121 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), + /* 122 */ "Close" OpHelp(""), + /* 123 */ "ColumnsUsed" OpHelp(""), + /* 124 */ "SeekScan" OpHelp("Scan-ahead up to P1 rows"), + /* 125 */ "SeekHit" OpHelp("set P2<=seekHit<=P3"), + /* 126 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"), + /* 127 */ "NewRowid" OpHelp("r[P2]=rowid"), + /* 128 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"), + /* 129 */ "RowCell" OpHelp(""), + /* 130 */ "Delete" OpHelp(""), + /* 131 */ "ResetCount" OpHelp(""), + /* 132 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"), + /* 133 */ "SorterData" OpHelp("r[P2]=data"), + /* 134 */ "RowData" OpHelp("r[P2]=data"), + /* 135 */ "Rowid" OpHelp("r[P2]=PX rowid of P1"), + /* 136 */ "NullRow" OpHelp(""), + /* 137 */ "SeekEnd" OpHelp(""), + /* 138 */ "IdxInsert" OpHelp("key=r[P2]"), + /* 139 */ "SorterInsert" OpHelp("key=r[P2]"), + /* 140 */ "IdxDelete" OpHelp("key=r[P2@P3]"), + /* 141 */ "DeferredSeek" OpHelp("Move P3 to P1.rowid if needed"), + /* 142 */ "IdxRowid" OpHelp("r[P2]=rowid"), + /* 143 */ "FinishSeek" OpHelp(""), + /* 144 */ "Destroy" OpHelp(""), + /* 145 */ "Clear" OpHelp(""), + /* 146 */ "ResetSorter" OpHelp(""), + /* 147 */ "CreateBtree" OpHelp("r[P2]=root iDb=P1 flags=P3"), + /* 148 */ "SqlExec" OpHelp(""), + /* 149 */ "ParseSchema" OpHelp(""), + /* 150 */ "LoadAnalysis" OpHelp(""), + /* 151 */ "DropTable" OpHelp(""), + /* 152 */ "DropIndex" OpHelp(""), + /* 153 */ "Real" OpHelp("r[P2]=P4"), + /* 154 */ "DropTrigger" OpHelp(""), + /* 155 */ "IntegrityCk" OpHelp(""), + /* 156 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"), + /* 157 */ "Param" OpHelp(""), + /* 158 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), + /* 159 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), + /* 160 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"), + /* 161 */ "AggInverse" OpHelp("accum=r[P3] inverse(r[P2@P5])"), + /* 162 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), + /* 163 */ "AggStep1" OpHelp("accum=r[P3] step(r[P2@P5])"), + /* 164 */ "AggValue" OpHelp("r[P3]=value N=P2"), + /* 165 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), + /* 166 */ "Expire" OpHelp(""), + /* 167 */ "CursorLock" OpHelp(""), + /* 168 */ "CursorUnlock" OpHelp(""), + /* 169 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), + /* 170 */ "VBegin" OpHelp(""), + /* 171 */ "VCreate" OpHelp(""), + /* 172 */ "VDestroy" OpHelp(""), + /* 173 */ "VOpen" OpHelp(""), + /* 174 */ "VInitIn" OpHelp("r[P2]=ValueList(P1,P3)"), + /* 175 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), + /* 176 */ "VRename" OpHelp(""), + /* 177 */ "Pagecount" OpHelp(""), + /* 178 */ "MaxPgcnt" OpHelp(""), + /* 179 */ "ClrSubtype" OpHelp("r[P1].subtype = 0"), + /* 180 */ "FilterAdd" OpHelp("filter(P1) += key(P3@P4)"), + /* 181 */ "Trace" OpHelp(""), + /* 182 */ "CursorHint" OpHelp(""), + /* 183 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"), + /* 184 */ "Noop" OpHelp(""), + /* 185 */ "Explain" OpHelp(""), + /* 186 */ "Abortable" OpHelp(""), }; return azName[i]; }@@ -34157,205 +35762,7 @@
/* ** Include code that is common to all os_*.c files */ -/************** Include os_common.h in the middle of os_unix.c ***************/ -/************** Begin file os_common.h ***************************************/ -/* -** 2004 May 22 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This file contains macros and a little bit of code that is common to -** all of the platform-specific files (os_*.c) and is #included into those -** files. -** -** This file should be #included by the os_*.c files only. It is not a -** general purpose header file. -*/ -#ifndef _OS_COMMON_H_ -#define _OS_COMMON_H_ - -/* -** At least two bugs have slipped in because we changed the MEMORY_DEBUG -** macro to SQLITE_DEBUG and some older makefiles have not yet made the -** switch. The following code should catch this problem at compile-time. -*/ -#ifdef MEMORY_DEBUG -# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead." -#endif - -/* -** Macros for performance tracing. Normally turned off. Only works -** on i486 hardware. -*/ -#ifdef SQLITE_PERFORMANCE_TRACE - -/* -** hwtime.h contains inline assembler code for implementing -** high-performance timing routines. -*/ -/************** Include hwtime.h in the middle of os_common.h ****************/ -/************** Begin file hwtime.h ******************************************/ -/* -** 2008 May 27 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This file contains inline asm code for retrieving "high-performance" -** counters for x86 and x86_64 class CPUs. -*/ -#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 -** profiling. -*/ -#if !defined(__STRICT_ANSI__) && \ - (defined(__GNUC__) || defined(_MSC_VER)) && \ - (defined(i386) || defined(__i386__) || defined(_M_IX86)) - - #if defined(__GNUC__) - - __inline__ sqlite_uint64 sqlite3Hwtime(void){ - unsigned int lo, hi; - __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); - return (sqlite_uint64)hi << 32 | lo; - } - - #elif defined(_MSC_VER) - - __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){ - __asm { - rdtsc - ret ; return value at EDX:EAX - } - } - - #endif - -#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__)) - - __inline__ sqlite_uint64 sqlite3Hwtime(void){ - unsigned long val; - __asm__ __volatile__ ("rdtsc" : "=A" (val)); - return val; - } - -#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__)) - - __inline__ sqlite_uint64 sqlite3Hwtime(void){ - unsigned long long retval; - unsigned long junk; - __asm__ __volatile__ ("\n\ - 1: mftbu %1\n\ - mftb %L0\n\ - mftbu %0\n\ - cmpw %0,%1\n\ - bne 1b" - : "=r" (retval), "=r" (junk)); - return retval; - } - -#else - - /* - ** asm() is needed for hardware timing support. Without asm(), - ** disable the sqlite3Hwtime() routine. - ** - ** sqlite3Hwtime() is only used for some obscure debugging - ** and analysis configurations, not in any deliverable, so this - ** should not be a great loss. - */ -SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } - -#endif - -#endif /* !defined(SQLITE_HWTIME_H) */ - -/************** End of hwtime.h **********************************************/ -/************** Continuing where we left off in os_common.h ******************/ - -static sqlite_uint64 g_start; -static sqlite_uint64 g_elapsed; -#define TIMER_START g_start=sqlite3Hwtime() -#define TIMER_END g_elapsed=sqlite3Hwtime()-g_start -#define TIMER_ELAPSED g_elapsed -#else -#define TIMER_START -#define TIMER_END -#define TIMER_ELAPSED ((sqlite_uint64)0) -#endif - -/* -** If we compile with the SQLITE_TEST macro set, then the following block -** of code will give us the ability to simulate a disk I/O error. This -** is used for testing the I/O recovery logic. -*/ -#if defined(SQLITE_TEST) -SQLITE_API extern int sqlite3_io_error_hit; -SQLITE_API extern int sqlite3_io_error_hardhit; -SQLITE_API extern int sqlite3_io_error_pending; -SQLITE_API extern int sqlite3_io_error_persist; -SQLITE_API extern int sqlite3_io_error_benign; -SQLITE_API extern int sqlite3_diskfull_pending; -SQLITE_API extern int sqlite3_diskfull; -#define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X) -#define SimulateIOError(CODE) \ - if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \ - || sqlite3_io_error_pending-- == 1 ) \ - { local_ioerr(); CODE; } -static void local_ioerr(){ - IOTRACE(("IOERR\n")); - sqlite3_io_error_hit++; - if( !sqlite3_io_error_benign ) sqlite3_io_error_hardhit++; -} -#define SimulateDiskfullError(CODE) \ - if( sqlite3_diskfull_pending ){ \ - if( sqlite3_diskfull_pending == 1 ){ \ - local_ioerr(); \ - sqlite3_diskfull = 1; \ - sqlite3_io_error_hit = 1; \ - CODE; \ - }else{ \ - sqlite3_diskfull_pending--; \ - } \ - } -#else -#define SimulateIOErrorBenign(X) -#define SimulateIOError(A) -#define SimulateDiskfullError(A) -#endif /* defined(SQLITE_TEST) */ - -/* -** When testing, keep a count of the number of open files. -*/ -#if defined(SQLITE_TEST) -SQLITE_API extern int sqlite3_open_file_count; -#define OpenCounter(X) sqlite3_open_file_count+=(X) -#else -#define OpenCounter(X) -#endif /* defined(SQLITE_TEST) */ - -#endif /* !defined(_OS_COMMON_H_) */ - -/************** End of os_common.h *******************************************/ -/************** Continuing where we left off in os_unix.c ********************/ +/* #include "os_common.h" */ /* ** Define various macros that are missing from some systems.@@ -38009,7 +39416,9 @@ }
/* Forward declaration */ static int unixGetTempname(int nBuf, char *zBuf); -static int unixFcntlExternalReader(unixFile*, int*); +#ifndef SQLITE_OMIT_WAL + static int unixFcntlExternalReader(unixFile*, int*); +#endif /* ** Information and control of an open file handle.@@ -38128,7 +39537,12 @@ }
#endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */ case SQLITE_FCNTL_EXTERNAL_READER: { +#ifndef SQLITE_OMIT_WAL return unixFcntlExternalReader((unixFile*)id, (int*)pArg); +#else + *(int*)pArg = 0; + return SQLITE_OK; +#endif } } return SQLITE_NOTFOUND;@@ -38961,11 +40375,17 @@ int n, /* Number of locks to acquire or release */
int flags /* What to do with the lock */ ){ unixFile *pDbFd = (unixFile*)fd; /* Connection holding shared memory */ - unixShm *p = pDbFd->pShm; /* The shared memory being locked */ - unixShmNode *pShmNode = p->pShmNode; /* The underlying file iNode */ + unixShm *p; /* The shared memory being locked */ + unixShmNode *pShmNode; /* The underlying file iNode */ int rc = SQLITE_OK; /* Result code */ u16 mask; /* Mask of locks to take or release */ - int *aLock = pShmNode->aLock; + int *aLock; + + p = pDbFd->pShm; + if( p==0 ) return SQLITE_IOERR_SHMLOCK; + pShmNode = p->pShmNode; + if( NEVER(pShmNode==0) ) return SQLITE_IOERR_SHMLOCK; + aLock = pShmNode->aLock; assert( pShmNode==pDbFd->pInode->pShmNode ); assert( pShmNode->pInode==pDbFd->pInode );@@ -39850,24 +41270,34 @@ return rc;
} /* +** Directories to consider for temp files. +*/ +static const char *azTempDirs[] = { + 0, + 0, + "/var/tmp", + "/usr/tmp", + "/tmp", + "." +}; + +/* +** Initialize first two members of azTempDirs[] array. +*/ +static void unixTempFileInit(void){ + azTempDirs[0] = getenv("SQLITE_TMPDIR"); + azTempDirs[1] = getenv("TMPDIR"); +} + +/* ** Return the name of a directory in which to put temporary files. ** If no suitable temporary file directory can be found, return NULL. */ static const char *unixTempFileDir(void){ - static const char *azDirs[] = { - 0, - 0, - "/var/tmp", - "/usr/tmp", - "/tmp", - "." - }; unsigned int i = 0; struct stat buf; const char *zDir = sqlite3_temp_directory; - if( !azDirs[0] ) azDirs[0] = getenv("SQLITE_TMPDIR"); - if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR"); while(1){ if( zDir!=0 && osStat(zDir, &buf)==0@@ -39876,8 +41306,8 @@ && osAccess(zDir, 03)==0
){ return zDir; } - if( i>=sizeof(azDirs)/sizeof(azDirs[0]) ) break; - zDir = azDirs[i++]; + if( i>=sizeof(azTempDirs)/sizeof(azTempDirs[0]) ) break; + zDir = azTempDirs[i++]; } return 0; }@@ -40052,20 +41482,23 @@ ** "<path to db>-walNN"
** ** where NN is a decimal number. The NN naming schemes are ** used by the test_multiplex.c module. + ** + ** In normal operation, the journal file name will always contain + ** a '-' character. However in 8+3 filename mode, or if a corrupt + ** rollback journal specifies a super-journal with a goofy name, then + ** the '-' might be missing or the '-' might be the first character in + ** the filename. In that case, just return SQLITE_OK with *pMode==0. */ nDb = sqlite3Strlen30(zPath) - 1; - while( zPath[nDb]!='-' ){ - /* In normal operation, the journal file name will always contain - ** a '-' character. However in 8+3 filename mode, or if a corrupt - ** rollback journal specifies a super-journal with a goofy name, then - ** the '-' might be missing. */ - if( nDb==0 || zPath[nDb]=='.' ) return SQLITE_OK; + while( nDb>0 && zPath[nDb]!='.' ){ + if( zPath[nDb]=='-' ){ + memcpy(zDb, zPath, nDb); + zDb[nDb] = '\0'; + rc = getFileMode(zDb, pMode, pUid, pGid); + break; + } nDb--; } - memcpy(zDb, zPath, nDb); - zDb[nDb] = '\0'; - - rc = getFileMode(zDb, pMode, pUid, pGid); }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){ *pMode = 0600; }else if( flags & SQLITE_OPEN_URI ){@@ -40182,6 +41615,11 @@ randomnessPid = osGetpid(0);
sqlite3_randomness(0,0); } memset(p, 0, sizeof(unixFile)); + +#ifdef SQLITE_ASSERT_NO_FILES + /* Applications that never read or write a persistent disk files */ + assert( zName==0 ); +#endif if( eType==SQLITE_OPEN_MAIN_DB ){ UnixUnusedFd *pUnused;@@ -40450,86 +41888,99 @@ return SQLITE_OK;
} /* -** If the last component of the pathname in z[0]..z[j-1] is something -** other than ".." then back it out and return true. If the last -** component is empty or if it is ".." then return false. +** A pathname under construction */ -static int unixBackupDir(const char *z, int *pJ){ - int j = *pJ; - int i; - if( j<=0 ) return 0; - for(i=j-1; i>0 && z[i-1]!='/'; i--){} - if( i==0 ) return 0; - if( z[i]=='.' && i==j-2 && z[i+1]=='.' ) return 0; - *pJ = i-1; - return 1; -} +typedef struct DbPath DbPath; +struct DbPath { + int rc; /* Non-zero following any error */ + int nSymlink; /* Number of symlinks resolved */ + char *zOut; /* Write the pathname here */ + int nOut; /* Bytes of space available to zOut[] */ + int nUsed; /* Bytes of zOut[] currently being used */ +}; + +/* Forward reference */ +static void appendAllPathElements(DbPath*,const char*); /* -** Convert a relative pathname into a full pathname. Also -** simplify the pathname as follows: -** -** Remove all instances of /./ -** Remove all isntances of /X/../ for any X +** Append a single path element to the DbPath under construction */ -static int mkFullPathname( - const char *zPath, /* Input path */ - char *zOut, /* Output buffer */ - int nOut /* Allocated size of buffer zOut */ +static void appendOnePathElement( + DbPath *pPath, /* Path under construction, to which to append zName */ + const char *zName, /* Name to append to pPath. Not zero-terminated */ + int nName /* Number of significant bytes in zName */ ){ - int nPath = sqlite3Strlen30(zPath); - int iOff = 0; - int i, j; - if( zPath[0]!='/' ){ - if( osGetcwd(zOut, nOut-2)==0 ){ - return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath); + assert( nName>0 ); + assert( zName!=0 ); + if( zName[0]=='.' ){ + if( nName==1 ) return; + if( zName[1]=='.' && nName==2 ){ + if( pPath->nUsed<=1 ){ + pPath->rc = SQLITE_ERROR; + return; + } + assert( pPath->zOut[0]=='/' ); + while( pPath->zOut[--pPath->nUsed]!='/' ){} + return; } - iOff = sqlite3Strlen30(zOut); - zOut[iOff++] = '/'; } - if( (iOff+nPath+1)>nOut ){ - /* SQLite assumes that xFullPathname() nul-terminates the output buffer - ** even if it returns an error. */ - zOut[iOff] = '\0'; - return SQLITE_CANTOPEN_BKPT; + if( pPath->nUsed + nName + 2 >= pPath->nOut ){ + pPath->rc = SQLITE_ERROR; + return; } - sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath); - - /* Remove duplicate '/' characters. Except, two // at the beginning - ** of a pathname is allowed since this is important on windows. */ - for(i=j=1; zOut[i]; i++){ - zOut[j++] = zOut[i]; - while( zOut[i]=='/' && zOut[i+1]=='/' ) i++; - } - zOut[j] = 0; - - assert( zOut[0]=='/' ); - for(i=j=0; zOut[i]; i++){ - if( zOut[i]=='/' ){ - /* Skip over internal "/." directory components */ - if( zOut[i+1]=='.' && zOut[i+2]=='/' ){ - i += 1; - continue; + pPath->zOut[pPath->nUsed++] = '/'; + memcpy(&pPath->zOut[pPath->nUsed], zName, nName); + pPath->nUsed += nName; +#if defined(HAVE_READLINK) && defined(HAVE_LSTAT) + if( pPath->rc==SQLITE_OK ){ + const char *zIn; + struct stat buf; + pPath->zOut[pPath->nUsed] = 0; + zIn = pPath->zOut; + if( osLstat(zIn, &buf)!=0 ){ + if( errno!=ENOENT ){ + pPath->rc = unixLogError(SQLITE_CANTOPEN_BKPT, "lstat", zIn); } - - /* If this is a "/.." directory component then back out the - ** previous term of the directory if it is something other than "..". - */ - if( zOut[i+1]=='.' - && zOut[i+2]=='.' - && zOut[i+3]=='/' - && unixBackupDir(zOut, &j) - ){ - i += 2; - continue; + }else if( S_ISLNK(buf.st_mode) ){ + ssize_t got; + char zLnk[SQLITE_MAX_PATHLEN+2]; + if( pPath->nSymlink++ > SQLITE_MAX_SYMLINK ){ + pPath->rc = SQLITE_CANTOPEN_BKPT; + return; + } + got = osReadlink(zIn, zLnk, sizeof(zLnk)-2); + if( got<=0 || got>=(ssize_t)sizeof(zLnk)-2 ){ + pPath->rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zIn); + return; + } + zLnk[got] = 0; + if( zLnk[0]=='/' ){ + pPath->nUsed = 0; + }else{ + pPath->nUsed -= nName + 1; } + appendAllPathElements(pPath, zLnk); } - if( ALWAYS(j>=0) ) zOut[j] = zOut[i]; - j++; } - if( NEVER(j==0) ) zOut[j++] = '/'; - zOut[j] = 0; - return SQLITE_OK; +#endif +} + +/* +** Append all path elements in zPath to the DbPath under construction. +*/ +static void appendAllPathElements( + DbPath *pPath, /* Path under construction, to which to append zName */ + const char *zPath /* Path to append to pPath. Is zero-terminated */ +){ + int i = 0; + int j = 0; + do{ + while( zPath[i] && zPath[i]!='/' ){ i++; } + if( i>j ){ + appendOnePathElement(pPath, &zPath[j], i-j); + } + j = i+1; + }while( zPath[i++] ); } /*@@ -40547,85 +41998,26 @@ const char *zPath, /* Possibly relative input path */
int nOut, /* Size of output buffer in bytes */ char *zOut /* Output buffer */ ){ -#if !defined(HAVE_READLINK) || !defined(HAVE_LSTAT) - return mkFullPathname(zPath, zOut, nOut); -#else - int rc = SQLITE_OK; - int nByte; - int nLink = 0; /* Number of symbolic links followed so far */ - const char *zIn = zPath; /* Input path for each iteration of loop */ - char *zDel = 0; - - assert( pVfs->mxPathname==MAX_PATHNAME ); + DbPath path; UNUSED_PARAMETER(pVfs); - - /* 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. - */ - SimulateIOError( return SQLITE_ERROR ); - - do { - - /* Call stat() on path zIn. Set bLink to true if the path is a symbolic - ** link, or false otherwise. */ - int bLink = 0; - struct stat buf; - if( osLstat(zIn, &buf)!=0 ){ - if( errno!=ENOENT ){ - rc = unixLogError(SQLITE_CANTOPEN_BKPT, "lstat", zIn); - } - }else{ - bLink = S_ISLNK(buf.st_mode); - } - - if( bLink ){ - nLink++; - if( zDel==0 ){ - zDel = sqlite3_malloc(nOut); - if( zDel==0 ) rc = SQLITE_NOMEM_BKPT; - }else if( nLink>=SQLITE_MAX_SYMLINKS ){ - rc = SQLITE_CANTOPEN_BKPT; - } - - if( rc==SQLITE_OK ){ - nByte = osReadlink(zIn, zDel, nOut-1); - if( nByte<0 ){ - rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zIn); - }else{ - if( zDel[0]!='/' ){ - int n; - for(n = sqlite3Strlen30(zIn); n>0 && zIn[n-1]!='/'; n--); - if( nByte+n+1>nOut ){ - rc = SQLITE_CANTOPEN_BKPT; - }else{ - memmove(&zDel[n], zDel, nByte+1); - memcpy(zDel, zIn, n); - nByte += n; - } - } - zDel[nByte] = '\0'; - } - } - - zIn = zDel; - } - - assert( rc!=SQLITE_OK || zIn!=zOut || zIn[0]=='/' ); - if( rc==SQLITE_OK && zIn!=zOut ){ - rc = mkFullPathname(zIn, zOut, nOut); + path.rc = 0; + path.nUsed = 0; + path.nSymlink = 0; + path.nOut = nOut; + path.zOut = zOut; + if( zPath[0]!='/' ){ + char zPwd[SQLITE_MAX_PATHLEN+2]; + if( osGetcwd(zPwd, sizeof(zPwd)-2)==0 ){ + return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath); } - if( bLink==0 ) break; - zIn = zOut; - }while( rc==SQLITE_OK ); - - sqlite3_free(zDel); - if( rc==SQLITE_OK && nLink ) rc = SQLITE_OK_SYMLINK; - return rc; -#endif /* HAVE_READLINK && HAVE_LSTAT */ + appendAllPathElements(&path, zPwd); + } + appendAllPathElements(&path, zPath); + zOut[path.nUsed] = 0; + if( path.rc || path.nUsed<2 ) return SQLITE_CANTOPEN_BKPT; + if( path.nSymlink ) return SQLITE_OK_SYMLINK; + return SQLITE_OK; } - #ifndef SQLITE_OMIT_LOAD_EXTENSION /*@@ -42144,6 +43536,9 @@ */
assert( UNIX_SHM_DMS==128 ); /* Byte offset of the deadman-switch */ #endif + /* Initialize temp file dir array. */ + unixTempFileInit(); + return SQLITE_OK; }@@ -42183,205 +43578,7 @@
/* ** Include code that is common to all os_*.c files */ -/************** Include os_common.h in the middle of os_win.c ****************/ -/************** Begin file os_common.h ***************************************/ -/* -** 2004 May 22 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This file contains macros and a little bit of code that is common to -** all of the platform-specific files (os_*.c) and is #included into those -** files. -** -** This file should be #included by the os_*.c files only. It is not a -** general purpose header file. -*/ -#ifndef _OS_COMMON_H_ -#define _OS_COMMON_H_ - -/* -** At least two bugs have slipped in because we changed the MEMORY_DEBUG -** macro to SQLITE_DEBUG and some older makefiles have not yet made the -** switch. The following code should catch this problem at compile-time. -*/ -#ifdef MEMORY_DEBUG -# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead." -#endif - -/* -** Macros for performance tracing. Normally turned off. Only works -** on i486 hardware. -*/ -#ifdef SQLITE_PERFORMANCE_TRACE - -/* -** hwtime.h contains inline assembler code for implementing -** high-performance timing routines. -*/ -/************** Include hwtime.h in the middle of os_common.h ****************/ -/************** Begin file hwtime.h ******************************************/ -/* -** 2008 May 27 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This file contains inline asm code for retrieving "high-performance" -** counters for x86 and x86_64 class CPUs. -*/ -#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 -** profiling. -*/ -#if !defined(__STRICT_ANSI__) && \ - (defined(__GNUC__) || defined(_MSC_VER)) && \ - (defined(i386) || defined(__i386__) || defined(_M_IX86)) - - #if defined(__GNUC__) - - __inline__ sqlite_uint64 sqlite3Hwtime(void){ - unsigned int lo, hi; - __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); - return (sqlite_uint64)hi << 32 | lo; - } - - #elif defined(_MSC_VER) - - __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){ - __asm { - rdtsc - ret ; return value at EDX:EAX - } - } - - #endif - -#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__)) - - __inline__ sqlite_uint64 sqlite3Hwtime(void){ - unsigned long val; - __asm__ __volatile__ ("rdtsc" : "=A" (val)); - return val; - } - -#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__)) - - __inline__ sqlite_uint64 sqlite3Hwtime(void){ - unsigned long long retval; - unsigned long junk; - __asm__ __volatile__ ("\n\ - 1: mftbu %1\n\ - mftb %L0\n\ - mftbu %0\n\ - cmpw %0,%1\n\ - bne 1b" - : "=r" (retval), "=r" (junk)); - return retval; - } - -#else - - /* - ** asm() is needed for hardware timing support. Without asm(), - ** disable the sqlite3Hwtime() routine. - ** - ** sqlite3Hwtime() is only used for some obscure debugging - ** and analysis configurations, not in any deliverable, so this - ** should not be a great loss. - */ -SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } - -#endif - -#endif /* !defined(SQLITE_HWTIME_H) */ - -/************** End of hwtime.h **********************************************/ -/************** Continuing where we left off in os_common.h ******************/ - -static sqlite_uint64 g_start; -static sqlite_uint64 g_elapsed; -#define TIMER_START g_start=sqlite3Hwtime() -#define TIMER_END g_elapsed=sqlite3Hwtime()-g_start -#define TIMER_ELAPSED g_elapsed -#else -#define TIMER_START -#define TIMER_END -#define TIMER_ELAPSED ((sqlite_uint64)0) -#endif - -/* -** If we compile with the SQLITE_TEST macro set, then the following block -** of code will give us the ability to simulate a disk I/O error. This -** is used for testing the I/O recovery logic. -*/ -#if defined(SQLITE_TEST) -SQLITE_API extern int sqlite3_io_error_hit; -SQLITE_API extern int sqlite3_io_error_hardhit; -SQLITE_API extern int sqlite3_io_error_pending; -SQLITE_API extern int sqlite3_io_error_persist; -SQLITE_API extern int sqlite3_io_error_benign; -SQLITE_API extern int sqlite3_diskfull_pending; -SQLITE_API extern int sqlite3_diskfull; -#define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X) -#define SimulateIOError(CODE) \ - if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \ - || sqlite3_io_error_pending-- == 1 ) \ - { local_ioerr(); CODE; } -static void local_ioerr(){ - IOTRACE(("IOERR\n")); - sqlite3_io_error_hit++; - if( !sqlite3_io_error_benign ) sqlite3_io_error_hardhit++; -} -#define SimulateDiskfullError(CODE) \ - if( sqlite3_diskfull_pending ){ \ - if( sqlite3_diskfull_pending == 1 ){ \ - local_ioerr(); \ - sqlite3_diskfull = 1; \ - sqlite3_io_error_hit = 1; \ - CODE; \ - }else{ \ - sqlite3_diskfull_pending--; \ - } \ - } -#else -#define SimulateIOErrorBenign(X) -#define SimulateIOError(A) -#define SimulateDiskfullError(A) -#endif /* defined(SQLITE_TEST) */ - -/* -** When testing, keep a count of the number of open files. -*/ -#if defined(SQLITE_TEST) -SQLITE_API extern int sqlite3_open_file_count; -#define OpenCounter(X) sqlite3_open_file_count+=(X) -#else -#define OpenCounter(X) -#endif /* defined(SQLITE_TEST) */ - -#endif /* !defined(_OS_COMMON_H_) */ - -/************** End of os_common.h *******************************************/ -/************** Continuing where we left off in os_win.c *********************/ +/* #include "os_common.h" */ /* ** Include the header file for the Windows VFS.@@ -46433,9 +47630,13 @@ ){
winFile *pDbFd = (winFile*)fd; /* Connection holding shared memory */ winShm *p = pDbFd->pShm; /* The shared memory being locked */ winShm *pX; /* For looping over all siblings */ - winShmNode *pShmNode = p->pShmNode; + winShmNode *pShmNode; int rc = SQLITE_OK; /* Result code */ u16 mask; /* Mask of locks to take or release */ + + if( p==0 ) return SQLITE_IOERR_SHMLOCK; + pShmNode = p->pShmNode; + if( NEVER(pShmNode==0) ) return SQLITE_IOERR_SHMLOCK; assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK ); assert( n>=1 );@@ -48792,7 +49993,7 @@ ** Try to enlarge the memory allocation to hold at least sz bytes
*/ static int memdbEnlarge(MemStore *p, sqlite3_int64 newSz){ unsigned char *pNew; - if( (p->mFlags & SQLITE_DESERIALIZE_RESIZEABLE)==0 || p->nMmap>0 ){ + if( (p->mFlags & SQLITE_DESERIALIZE_RESIZEABLE)==0 || NEVER(p->nMmap>0) ){ return SQLITE_FULL; } if( newSz>p->szMax ){@@ -48851,8 +50052,9 @@ static int memdbTruncate(sqlite3_file *pFile, sqlite_int64 size){
MemStore *p = ((MemFile*)pFile)->pStore; int rc = SQLITE_OK; memdbEnter(p); - if( NEVER(size>p->sz) ){ - rc = SQLITE_FULL; + if( size>p->sz ){ + /* This can only happen with a corrupt wal mode db */ + rc = SQLITE_CORRUPT; }else{ p->sz = size; }@@ -48991,7 +50193,7 @@ void **pp
){ MemStore *p = ((MemFile*)pFile)->pStore; memdbEnter(p); - if( iOfst+iAmt>p->sz ){ + if( iOfst+iAmt>p->sz || (p->mFlags & SQLITE_DESERIALIZE_RESIZEABLE)!=0 ){ *pp = 0; }else{ p->nMmap++;@@ -49025,10 +50227,9 @@ ){
MemFile *pFile = (MemFile*)pFd; MemStore *p = 0; int szName; - if( (flags & SQLITE_OPEN_MAIN_DB)==0 ){ - return ORIGVFS(pVfs)->xOpen(ORIGVFS(pVfs), zName, pFd, flags, pOutFlags); - } - memset(pFile, 0, sizeof(*p)); + UNUSED_PARAMETER(pVfs); + + memset(pFile, 0, sizeof(*pFile)); szName = sqlite3Strlen30(zName); if( szName>1 && zName[0]=='/' ){ int i;@@ -49087,8 +50288,9 @@ p->mFlags = SQLITE_DESERIALIZE_RESIZEABLE | SQLITE_DESERIALIZE_FREEONCLOSE;
p->szMax = sqlite3GlobalConfig.mxMemdbSize; } pFile->pStore = p; - assert( pOutFlags!=0 ); /* True because flags==SQLITE_OPEN_MAIN_DB */ - *pOutFlags = flags | SQLITE_OPEN_MEMORY; + if( pOutFlags!=0 ){ + *pOutFlags = flags | SQLITE_OPEN_MEMORY; + } pFd->pMethods = &memdb_io_methods; memdbLeave(p); return SQLITE_OK;@@ -49329,7 +50531,8 @@
sqlite3_mutex_enter(db->mutex); if( zSchema==0 ) zSchema = db->aDb[0].zDbSName; iDb = sqlite3FindDbName(db, zSchema); - if( iDb<0 ){ + testcase( iDb==1 ); + if( iDb<2 && iDb!=0 ){ rc = SQLITE_ERROR; goto end_deserialize; }@@ -49752,7 +50955,7 @@ sqlite3BitvecSet(0, 1);
sqlite3BitvecClear(0, 1, pTmpSpace); /* Run the program */ - pc = 0; + pc = i = 0; while( (op = aOp[pc])!=0 ){ switch( op ){ case 1:@@ -50056,11 +51259,14 @@ /* IMPLEMENTATION-OF: R-42059-47211 If the argument N is positive then the
** suggested cache size is set to N. */ return p->szCache; }else{ + i64 n; /* IMPLEMANTATION-OF: R-59858-46238 If the argument N is negative, then the ** number of cache pages is adjusted to be a number of pages that would ** use approximately abs(N*1024) bytes of memory based on the current ** page size. */ - return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra)); + n = ((-1024*(i64)p->szCache)/(p->szPage+p->szExtra)); + if( n>1000000000 ) n = 1000000000; + return (int)n; } }@@ -51515,12 +52721,18 @@ ** Configure the cache_size limit for a cache.
*/ static void pcache1Cachesize(sqlite3_pcache *p, int nMax){ PCache1 *pCache = (PCache1 *)p; + u32 n; + assert( nMax>=0 ); if( pCache->bPurgeable ){ PGroup *pGroup = pCache->pGroup; pcache1EnterMutex(pGroup); - pGroup->nMaxPage += (nMax - pCache->nMax); + n = (u32)nMax; + if( n > 0x7fff0000 - pGroup->nMaxPage + pCache->nMax ){ + n = 0x7fff0000 - pGroup->nMaxPage + pCache->nMax; + } + pGroup->nMaxPage += (n - pCache->nMax); pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage; - pCache->nMax = nMax; + pCache->nMax = n; pCache->n90pct = pCache->nMax*9/10; pcache1EnforceMaxPage(pCache); pcache1LeaveMutex(pGroup);@@ -51536,7 +52748,7 @@ static void pcache1Shrink(sqlite3_pcache *p){
PCache1 *pCache = (PCache1*)p; if( pCache->bPurgeable ){ PGroup *pGroup = pCache->pGroup; - int savedMaxPage; + unsigned int savedMaxPage; pcache1EnterMutex(pGroup); savedMaxPage = pGroup->nMaxPage; pGroup->nMaxPage = 0;@@ -53273,6 +54485,7 @@ u8 tempFile; /* zFilename is a temporary or immutable file */
u8 noLock; /* Do not lock (except in WAL mode) */ u8 readOnly; /* True for a read-only database */ u8 memDb; /* True to inhibit all file I/O */ + u8 memVfs; /* VFS-implemented memory database */ /************************************************************************** ** The following block contains those class members that change during@@ -53322,8 +54535,9 @@ u16 nExtra; /* Add this many bytes to each in-memory page */
i16 nReserve; /* Number of unused bytes at end of each page */ u32 vfsFlags; /* Flags for sqlite3_vfs.xOpen() */ u32 sectorSize; /* Assumed sector size during rollback */ - int pageSize; /* Number of bytes in a page */ Pgno mxPgno; /* Maximum allowed size of the database */ + Pgno lckPgno; /* Page number for the locking page */ + i64 pageSize; /* Number of bytes in a page */ i64 journalSizeLimit; /* Size limit for persistent journal files */ char *zFilename; /* Name of the database file */ char *zJournal; /* Name of the journal file */@@ -54309,7 +55523,7 @@ ** thing written to a journal file. If the pager is in full-sync mode, the
** journal file descriptor is advanced to the next sector boundary before ** anything is written. The format is: ** -** + 4 bytes: PAGER_MJ_PGNO. +** + 4 bytes: PAGER_SJ_PGNO. ** + N bytes: super-journal filename in utf-8. ** + 4 bytes: N (length of super-journal name in bytes, no nul-terminator). ** + 4 bytes: super-journal name checksum.@@ -54357,7 +55571,7 @@
/* Write the super-journal data to the end of the journal file. If ** an error occurs, return the error code to the caller. */ - if( (0 != (rc = write32bits(pPager->jfd, iHdrOff, PAGER_MJ_PGNO(pPager)))) + if( (0 != (rc = write32bits(pPager->jfd, iHdrOff, PAGER_SJ_PGNO(pPager)))) || (0 != (rc = sqlite3OsWrite(pPager->jfd, zSuper, nSuper, iHdrOff+4))) || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nSuper, nSuper))) || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nSuper+4, cksum)))@@ -54867,7 +56081,7 @@ ** is successfully read from the (sub-)journal file but appears to be
** corrupted, SQLITE_DONE is returned. Data is considered corrupted in ** two circumstances: ** -** * If the record page-number is illegal (0 or PAGER_MJ_PGNO), or +** * If the record page-number is illegal (0 or PAGER_SJ_PGNO), or ** * If the record is being rolled back from the main journal file ** and the checksum field does not match the record content. **@@ -54927,7 +56141,7 @@ ** thought. If a power failure occurs while the journal is being written,
** it could cause invalid data to be written into the journal. We need to ** detect this invalid data (with high probability) and ignore it. */ - if( pgno==0 || pgno==PAGER_MJ_PGNO(pPager) ){ + if( pgno==0 || pgno==PAGER_SJ_PGNO(pPager) ){ assert( !isSavepnt ); return SQLITE_DONE; }@@ -55264,6 +56478,7 @@ char *pTmp = pPager->pTmpSpace;
memset(pTmp, 0, szPage); testcase( (newSize-szPage) == currentSize ); testcase( (newSize-szPage) > currentSize ); + sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &newSize); rc = sqlite3OsWrite(pPager->fd, pTmp, szPage, newSize-szPage); } if( rc==SQLITE_OK ){@@ -55486,6 +56701,9 @@ if( rc!=SQLITE_OK ){
goto end_playback; } pPager->dbSize = mxPg; + if( pPager->mxPgno<mxPg ){ + pPager->mxPgno = mxPg; + } } /* Copy original pages out of the journal and back into the@@ -55667,6 +56885,7 @@ ** needed, as determined by the pPager->changeCountDone state variable.
*/ static void pager_write_changecounter(PgHdr *pPg){ u32 change_counter; + if( NEVER(pPg==0) ) return; /* Increment the value just read and write it back to byte 24. */ change_counter = sqlite3Get4byte((u8*)pPg->pPager->dbFileVers)+1;@@ -56381,6 +57600,7 @@ sqlite3PageFree(pPager->pTmpSpace);
pPager->pTmpSpace = pNew; pPager->dbSize = (Pgno)((nByte+pageSize-1)/pageSize); pPager->pageSize = pageSize; + pPager->lckPgno = (Pgno)(PENDING_BYTE/pageSize) + 1; }else{ sqlite3PageFree(pNew); }@@ -56541,8 +57761,7 @@ ** a) The page number is less than or equal to the size of the
** current database image, in pages, OR ** ** b) if the page content were written at this time, it would not -** be necessary to write the current content out to the sub-journal -** (as determined by function subjRequiresPage()). +** be necessary to write the current content out to the sub-journal. ** ** If the condition asserted by this function were not true, and the ** dirty page were to be discarded from the cache via the pagerStress()@@ -56557,8 +57776,16 @@ ** this circumstance cannot arise.
*/ #if defined(SQLITE_DEBUG) static void assertTruncateConstraintCb(PgHdr *pPg){ + Pager *pPager = pPg->pPager; assert( pPg->flags&PGHDR_DIRTY ); - assert( !subjRequiresPage(pPg) || pPg->pgno<=pPg->pPager->dbSize ); + if( pPg->pgno>pPager->dbSize ){ /* if (a) is false */ + Pgno pgno = pPg->pgno; + int i; + for(i=0; i<pPg->pPager->nSavepoint; i++){ + PagerSavepoint *p = &pPager->aSavepoint[i]; + assert( p->nOrig<pgno || sqlite3BitvecTestNotNull(p->pInSavepoint,pgno) ); + } + } } static void assertTruncateConstraint(Pager *pPager){ sqlite3PcacheIterateDirty(pPager->pPCache, assertTruncateConstraintCb);@@ -56580,7 +57807,6 @@ ** then continue writing to the database.
*/ SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){ assert( pPager->dbSize>=nPage || CORRUPT_DB ); - testcase( pPager->dbSize<nPage ); assert( pPager->eState>=PAGER_WRITER_CACHEMOD ); pPager->dbSize = nPage;@@ -57501,6 +58727,7 @@ }else{
pPager->zWal = 0; } #endif + (void)pPtr; /* Suppress warning about unused pPtr value */ if( nPathname ) sqlite3DbFree(0, zPathname); pPager->pVfs = pVfs;@@ -57513,7 +58740,7 @@ int fout = 0; /* VFS flags returned by xOpen() */
rc = sqlite3OsOpen(pVfs, pPager->zFilename, pPager->fd, vfsFlags, &fout); assert( !memDb ); #ifndef SQLITE_OMIT_DESERIALIZE - memJM = (fout&SQLITE_OPEN_MEMORY)!=0; + pPager->memVfs = memJM = (fout&SQLITE_OPEN_MEMORY)!=0; #endif readOnly = (fout&SQLITE_OPEN_READONLY)!=0;@@ -57898,7 +59125,7 @@ ** this connection obtained the exclusive lock above. Or, it
** may mean that the pager was in the error-state when this ** function was called and the journal file does not exist. */ - if( !isOpen(pPager->jfd) ){ + if( !isOpen(pPager->jfd) && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){ sqlite3_vfs * const pVfs = pPager->pVfs; int bExists; /* True if journal file exists */ rc = sqlite3OsAccess(@@ -58143,7 +59370,7 @@ noContent = (flags & PAGER_GET_NOCONTENT)!=0;
if( pPg->pPager && !noContent ){ /* In this case the pcache already contains an initialized copy of ** the page. Return without further ado. */ - assert( pgno!=PAGER_MJ_PGNO(pPager) ); + assert( pgno!=PAGER_SJ_PGNO(pPager) ); pPager->aStat[PAGER_STAT_HIT]++; return SQLITE_OK;@@ -58154,7 +59381,7 @@ **
** (*) obsolete. Was: maximum page number is 2^31 ** (2) Never try to fetch the locking page */ - if( pgno==PAGER_MJ_PGNO(pPager) ){ + if( pgno==PAGER_SJ_PGNO(pPager) ){ rc = SQLITE_CORRUPT_BKPT; goto pager_acquire_err; }@@ -58300,6 +59527,7 @@ Pgno pgno, /* Page number to fetch */
DbPage **ppPage, /* Write a pointer to the page here */ int flags /* PAGER_GET_XXX flags */ ){ + /* printf("PAGE %u\n", pgno); fflush(stdout); */ return pPager->xGet(pPager, pgno, ppPage, flags); }@@ -58552,7 +59780,7 @@
/* We should never write to the journal file the page that ** contains the database locks. The following assert verifies ** that we do not. */ - assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) ); + assert( pPg->pgno!=PAGER_SJ_PGNO(pPager) ); assert( pPager->journalHdr<=pPager->journalOff ); pData2 = pPg->pData;@@ -58731,7 +59959,7 @@ for(ii=0; ii<nPage && rc==SQLITE_OK; ii++){
Pgno pg = pg1+ii; PgHdr *pPage; if( pg==pPg->pgno || !sqlite3BitvecTest(pPager->pInJournal, pg) ){ - if( pg!=PAGER_MJ_PGNO(pPager) ){ + if( pg!=PAGER_SJ_PGNO(pPager) ){ rc = sqlite3PagerGet(pPager, pg, &pPage, 0); if( rc==SQLITE_OK ){ rc = pager_write(pPage);@@ -59209,7 +60437,7 @@ ** last page in the db image moved to the free-list. In this case the
** last page is never written out to disk, leaving the database file ** undersized. Fix this now if it is the case. */ if( pPager->dbSize>pPager->dbFileSize ){ - Pgno nNew = pPager->dbSize - (pPager->dbSize==PAGER_MJ_PGNO(pPager)); + Pgno nNew = pPager->dbSize - (pPager->dbSize==PAGER_SJ_PGNO(pPager)); assert( pPager->eState==PAGER_WRITER_DBMOD ); rc = pager_truncate(pPager, nNew); if( rc!=SQLITE_OK ) goto commit_phase_one_exit;@@ -59380,8 +60608,8 @@ ** Return the approximate number of bytes of memory currently
** used by the pager and its associated cache. */ SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager *pPager){ - int perPageSize = pPager->pageSize + pPager->nExtra + sizeof(PgHdr) - + 5*sizeof(void*); + int perPageSize = pPager->pageSize + pPager->nExtra + + (int)(sizeof(PgHdr) + 5*sizeof(void*)); return perPageSize*sqlite3PcachePagecount(pPager->pPCache) + sqlite3MallocSize(pPager) + pPager->pageSize;@@ -59450,7 +60678,7 @@ /*
** Return true if this is an in-memory or temp-file backed pager. */ SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager *pPager){ - return pPager->tempFile; + return pPager->tempFile || pPager->memVfs; } /*@@ -59575,14 +60803,14 @@ sqlite3BitvecDestroy(pPager->aSavepoint[ii].pInSavepoint);
} pPager->nSavepoint = nNew; - /* If this is a release of the outermost savepoint, truncate - ** the sub-journal to zero bytes in size. */ + /* Truncate the sub-journal so that it only includes the parts + ** that are still in use. */ if( op==SAVEPOINT_RELEASE ){ PagerSavepoint *pRel = &pPager->aSavepoint[nNew]; if( pRel->bTruncateOnRelease && isOpen(pPager->sjfd) ){ /* Only truncate if it is an in-memory sub-journal. */ if( sqlite3JournalIsInMemory(pPager->sjfd) ){ - i64 sz = (pPager->pageSize+4)*pRel->iSubRec; + i64 sz = (pPager->pageSize+4)*(i64)pRel->iSubRec; rc = sqlite3OsTruncate(pPager->sjfd, sz); assert( rc==SQLITE_OK ); }@@ -59770,7 +60998,7 @@ pPg->flags &= ~PGHDR_NEED_SYNC;
pPgOld = sqlite3PagerLookup(pPager, pgno); assert( !pPgOld || pPgOld->nRef==1 || CORRUPT_DB ); if( pPgOld ){ - if( pPgOld->nRef>1 ){ + if( NEVER(pPgOld->nRef>1) ){ sqlite3PagerUnrefNotNull(pPgOld); return SQLITE_CORRUPT_BKPT; }@@ -59905,12 +61133,12 @@ SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){
u8 eOld = pPager->journalMode; /* Prior journalmode */ /* The eMode parameter is always valid */ - assert( eMode==PAGER_JOURNALMODE_DELETE - || eMode==PAGER_JOURNALMODE_TRUNCATE - || eMode==PAGER_JOURNALMODE_PERSIST - || eMode==PAGER_JOURNALMODE_OFF - || eMode==PAGER_JOURNALMODE_WAL - || eMode==PAGER_JOURNALMODE_MEMORY ); + assert( eMode==PAGER_JOURNALMODE_DELETE /* 0 */ + || eMode==PAGER_JOURNALMODE_PERSIST /* 1 */ + || eMode==PAGER_JOURNALMODE_OFF /* 2 */ + || eMode==PAGER_JOURNALMODE_TRUNCATE /* 3 */ + || eMode==PAGER_JOURNALMODE_MEMORY /* 4 */ + || eMode==PAGER_JOURNALMODE_WAL /* 5 */ ); /* This routine is only called from the OP_JournalMode opcode, and ** the logic there will never allow a temporary file to be changed@@ -59947,7 +61175,6 @@ assert( (PAGER_JOURNALMODE_WAL & 5)==5 );
assert( isOpen(pPager->fd) || pPager->exclusiveMode ); if( !pPager->exclusiveMode && (eOld & 5)==1 && (eMode & 1)==0 ){ - /* In this case we would like to delete the journal file. If it is ** not possible, then that is not a problem. Deleting the journal file ** here is an optimization only.@@ -60059,6 +61286,18 @@ int *pnLog, /* OUT: Final number of frames in log */
int *pnCkpt /* OUT: Final number of checkpointed frames */ ){ int rc = SQLITE_OK; + if( pPager->pWal==0 && pPager->journalMode==PAGER_JOURNALMODE_WAL ){ + /* This only happens when a database file is zero bytes in size opened and + ** then "PRAGMA journal_mode=WAL" is run and then sqlite3_wal_checkpoint() + ** is invoked without any intervening transactions. We need to start + ** a transaction to initialize pWal. The PRAGMA table_list statement is + ** used for this since it starts transactions on every database file, + ** including all ATTACHed databases. This seems expensive for a single + ** sqlite3_wal_checkpoint() call, but it happens very rarely. + ** https://sqlite.org/forum/forumpost/fd0f19d229156939 + */ + sqlite3_exec(db, "PRAGMA table_list",0,0,0); + } if( pPager->pWal ){ rc = sqlite3WalCheckpoint(pPager->pWal, db, eMode, (eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler),@@ -60516,7 +61755,10 @@ ** HASHTABLE_NPAGE frames. The first index block contains information on
** HASHTABLE_NPAGE_ONE frames. The values of HASHTABLE_NPAGE_ONE and ** HASHTABLE_NPAGE are selected so that together the wal-index header and ** first index block are the same size as all other index blocks in the -** wal-index. +** wal-index. The values are: +** +** HASHTABLE_NPAGE 4096 +** HASHTABLE_NPAGE_ONE 4062 ** ** Each index block contains two sections, a page-mapping that contains the ** database page number associated with each wal frame, and a hash-table@@ -60752,6 +61994,70 @@ u32 notUsed0; /* Available for future enhancements */
}; #define READMARK_NOT_USED 0xffffffff +/* +** This is a schematic view of the complete 136-byte header of the +** wal-index file (also known as the -shm file): +** +** +-----------------------------+ +** 0: | iVersion | \ +** +-----------------------------+ | +** 4: | (unused padding) | | +** +-----------------------------+ | +** 8: | iChange | | +** +-------+-------+-------------+ | +** 12: | bInit | bBig | szPage | | +** +-------+-------+-------------+ | +** 16: | mxFrame | | First copy of the +** +-----------------------------+ | WalIndexHdr object +** 20: | nPage | | +** +-----------------------------+ | +** 24: | aFrameCksum | | +** | | | +** +-----------------------------+ | +** 32: | aSalt | | +** | | | +** +-----------------------------+ | +** 40: | aCksum | | +** | | / +** +-----------------------------+ +** 48: | iVersion | \ +** +-----------------------------+ | +** 52: | (unused padding) | | +** +-----------------------------+ | +** 56: | iChange | | +** +-------+-------+-------------+ | +** 60: | bInit | bBig | szPage | | +** +-------+-------+-------------+ | Second copy of the +** 64: | mxFrame | | WalIndexHdr +** +-----------------------------+ | +** 68: | nPage | | +** +-----------------------------+ | +** 72: | aFrameCksum | | +** | | | +** +-----------------------------+ | +** 80: | aSalt | | +** | | | +** +-----------------------------+ | +** 88: | aCksum | | +** | | / +** +-----------------------------+ +** 96: | nBackfill | +** +-----------------------------+ +** 100: | 5 read marks | +** | | +** | | +** | | +** | | +** +-------+-------+------+------+ +** 120: | Write | Ckpt | Rcvr | Rd0 | \ +** +-------+-------+------+------+ ) 8 lock bytes +** | Read1 | Read2 | Rd3 | Rd4 | / +** +-------+-------+------+------+ +** 128: | nBackfillAttempted | +** +-----------------------------+ +** 132: | (unused padding) | +** +-----------------------------+ +*/ /* A block of WALINDEX_LOCK_RESERVED bytes beginning at ** WALINDEX_LOCK_OFFSET is reserved for locks. Since some systems@@ -60908,9 +62214,13 @@ ** of the wal-index might be increased, but only if it is safe to do
** so. It is safe to enlarge the wal-index if pWal->writeLock is true ** or pWal->exclusiveMode==WAL_HEAPMEMORY_MODE. ** -** If this call is successful, *ppPage is set to point to the wal-index -** page and SQLITE_OK is returned. If an error (an OOM or VFS error) occurs, -** then an SQLite error code is returned and *ppPage is set to 0. +** Three possible result scenarios: +** +** (1) rc==SQLITE_OK and *ppPage==Requested-Wal-Index-Page +** (2) rc>=SQLITE_ERROR and *ppPage==NULL +** (3) rc==SQLITE_OK and *ppPage==NULL // only if iPage==0 +** +** Scenario (3) can only occur when pWal->writeLock is false and iPage==0 */ static SQLITE_NOINLINE int walIndexPageRealloc( Wal *pWal, /* The WAL context */@@ -60943,7 +62253,9 @@ }else{
rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ, pWal->writeLock, (void volatile **)&pWal->apWiData[iPage] ); - assert( pWal->apWiData[iPage]!=0 || rc!=SQLITE_OK || pWal->writeLock==0 ); + assert( pWal->apWiData[iPage]!=0 + || rc!=SQLITE_OK + || (pWal->writeLock==0 && iPage==0) ); testcase( pWal->apWiData[iPage]==0 && rc==SQLITE_OK ); if( rc==SQLITE_OK ){ if( iPage>0 && sqlite3FaultSim(600) ) rc = SQLITE_NOMEM;@@ -61282,8 +62594,8 @@ ** number of the first frame indexed by this hash table. If a
** slot in the hash table is set to N, it refers to frame number ** (pLoc->iZero+N) in the log. ** -** Finally, set pLoc->aPgno so that pLoc->aPgno[1] is the page number of the -** first frame indexed by the hash table, frame (pLoc->iZero+1). +** Finally, set pLoc->aPgno so that pLoc->aPgno[0] is the page number of the +** first frame indexed by the hash table, frame (pLoc->iZero). */ static int walHashGet( Wal *pWal, /* WAL handle */@@ -61295,7 +62607,7 @@
rc = walIndexPage(pWal, iHash, &pLoc->aPgno); assert( rc==SQLITE_OK || iHash>0 ); - if( rc==SQLITE_OK ){ + if( pLoc->aPgno ){ pLoc->aHash = (volatile ht_slot *)&pLoc->aPgno[HASHTABLE_NPAGE]; if( iHash==0 ){ pLoc->aPgno = &pLoc->aPgno[WALINDEX_HDR_SIZE/sizeof(u32)];@@ -61303,7 +62615,8 @@ pLoc->iZero = 0;
}else{ pLoc->iZero = HASHTABLE_NPAGE_ONE + (iHash-1)*HASHTABLE_NPAGE; } - pLoc->aPgno = &pLoc->aPgno[-1]; + }else if( NEVER(rc==SQLITE_OK) ){ + rc = SQLITE_ERROR; } return rc; }@@ -61385,8 +62698,9 @@
/* Zero the entries in the aPgno array that correspond to frames with ** frame numbers greater than pWal->hdr.mxFrame. */ - nByte = (int)((char *)sLoc.aHash - (char *)&sLoc.aPgno[iLimit+1]); - memset((void *)&sLoc.aPgno[iLimit+1], 0, nByte); + nByte = (int)((char *)sLoc.aHash - (char *)&sLoc.aPgno[iLimit]); + assert( nByte>=0 ); + memset((void *)&sLoc.aPgno[iLimit], 0, nByte); #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT /* Verify that the every entry in the mapping region is still reachable@@ -61395,11 +62709,11 @@ */
if( iLimit ){ int j; /* Loop counter */ int iKey; /* Hash key */ - for(j=1; j<=iLimit; j++){ + for(j=0; j<iLimit; j++){ for(iKey=walHash(sLoc.aPgno[j]);sLoc.aHash[iKey];iKey=walNextHash(iKey)){ - if( sLoc.aHash[iKey]==j ) break; + if( sLoc.aHash[iKey]==j+1 ) break; } - assert( sLoc.aHash[iKey]==j ); + assert( sLoc.aHash[iKey]==j+1 ); } } #endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */@@ -61431,9 +62745,9 @@ /* If this is the first entry to be added to this hash-table, zero the
** entire hash table and aPgno[] array before proceeding. */ if( idx==1 ){ - int nByte = (int)((u8 *)&sLoc.aHash[HASHTABLE_NSLOT] - - (u8 *)&sLoc.aPgno[1]); - memset((void*)&sLoc.aPgno[1], 0, nByte); + int nByte = (int)((u8*)&sLoc.aHash[HASHTABLE_NSLOT] - (u8*)sLoc.aPgno); + assert( nByte>=0 ); + memset((void*)sLoc.aPgno, 0, nByte); } /* If the entry in aPgno[] is already set, then the previous writer@@ -61442,9 +62756,9 @@ ** writing one or more dirty pages to the WAL to free up memory).
** Remove the remnants of that writers uncommitted transaction from ** the hash-table before writing any new entries. */ - if( sLoc.aPgno[idx] ){ + if( sLoc.aPgno[idx-1] ){ walCleanupHash(pWal); - assert( !sLoc.aPgno[idx] ); + assert( !sLoc.aPgno[idx-1] ); } /* Write the aPgno[] array entry and the hash-table slot. */@@ -61452,7 +62766,7 @@ nCollide = idx;
for(iKey=walHash(iPage); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){ if( (nCollide--)==0 ) return SQLITE_CORRUPT_BKPT; } - sLoc.aPgno[idx] = iPage; + sLoc.aPgno[idx-1] = iPage; AtomicStore(&sLoc.aHash[iKey], (ht_slot)idx); #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT@@ -61473,18 +62787,17 @@ ** iteration.
*/ if( (idx&0x3ff)==0 ){ int i; /* Loop counter */ - for(i=1; i<=idx; i++){ + for(i=0; i<idx; i++){ for(iKey=walHash(sLoc.aPgno[i]); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){ - if( sLoc.aHash[iKey]==i ) break; + if( sLoc.aHash[iKey]==i+1 ) break; } - assert( sLoc.aHash[iKey]==i ); + assert( sLoc.aHash[iKey]==i+1 ); } } #endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */ } - return rc; }@@ -61606,7 +62919,8 @@ u32 iLast = MIN(iLastFrame, HASHTABLE_NPAGE_ONE+iPg*HASHTABLE_NPAGE);
u32 iFirst = 1 + (iPg==0?0:HASHTABLE_NPAGE_ONE+(iPg-1)*HASHTABLE_NPAGE); u32 nHdr, nHdr32; rc = walIndexPage(pWal, iPg, (volatile u32**)&aShare); - if( rc ) break; + assert( aShare!=0 || rc!=SQLITE_OK ); + if( aShare==0 ) break; pWal->apWiData[iPg] = aPrivate; for(iFrame=iFirst; iFrame<=iLast; iFrame++){@@ -61765,14 +63079,43 @@
assert( zWalName && zWalName[0] ); assert( pDbFd ); + /* Verify the values of various constants. Any changes to the values + ** of these constants would result in an incompatible on-disk format + ** for the -shm file. Any change that causes one of these asserts to + ** fail is a backward compatibility problem, even if the change otherwise + ** works. + ** + ** This table also serves as a helpful cross-reference when trying to + ** interpret hex dumps of the -shm file. + */ + assert( 48 == sizeof(WalIndexHdr) ); + assert( 40 == sizeof(WalCkptInfo) ); + assert( 120 == WALINDEX_LOCK_OFFSET ); + assert( 136 == WALINDEX_HDR_SIZE ); + assert( 4096 == HASHTABLE_NPAGE ); + assert( 4062 == HASHTABLE_NPAGE_ONE ); + assert( 8192 == HASHTABLE_NSLOT ); + assert( 383 == HASHTABLE_HASH_1 ); + assert( 32768 == WALINDEX_PGSZ ); + assert( 8 == SQLITE_SHM_NLOCK ); + assert( 5 == WAL_NREADER ); + assert( 24 == WAL_FRAME_HDRSIZE ); + assert( 32 == WAL_HDRSIZE ); + assert( 120 == WALINDEX_LOCK_OFFSET + WAL_WRITE_LOCK ); + assert( 121 == WALINDEX_LOCK_OFFSET + WAL_CKPT_LOCK ); + assert( 122 == WALINDEX_LOCK_OFFSET + WAL_RECOVER_LOCK ); + assert( 123 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(0) ); + assert( 124 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(1) ); + assert( 125 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(2) ); + assert( 126 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(3) ); + assert( 127 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(4) ); + /* In the amalgamation, the os_unix.c and os_win.c source files come before ** this source file. Verify that the #defines of the locking byte offsets ** in os_unix.c and os_win.c agree with the WALINDEX_LOCK_OFFSET value. ** For that matter, if the lock offset ever changes from its initial design ** value of 120, we need to know that so there is an assert() to check it. */ - assert( 120==WALINDEX_LOCK_OFFSET ); - assert( 136==WALINDEX_HDR_SIZE ); #ifdef WIN_SHM_BASE assert( WIN_SHM_BASE==WALINDEX_LOCK_OFFSET ); #endif@@ -62074,7 +63417,6 @@ int j; /* Counter variable */
int nEntry; /* Number of entries in this segment */ ht_slot *aIndex; /* Sorted index for this segment */ - sLoc.aPgno++; if( (i+1)==nSegment ){ nEntry = (int)(iLast - sLoc.iZero); }else{@@ -62855,7 +64197,9 @@ goto begin_unreliable_shm_out;
} /* Allocate a buffer to read frames into */ - szFrame = pWal->hdr.szPage + WAL_FRAME_HDRSIZE; + assert( (pWal->szPage & (pWal->szPage-1))==0 ); + assert( pWal->szPage>=512 && pWal->szPage<=65536 ); + szFrame = pWal->szPage + WAL_FRAME_HDRSIZE; aFrame = (u8 *)sqlite3_malloc64(szFrame); if( aFrame==0 ){ rc = SQLITE_NOMEM_BKPT;@@ -62869,7 +64213,7 @@ ** heap-memory wal-index is discarded and WAL_RETRY returned to
** the caller. */ aSaveCksum[0] = pWal->hdr.aFrameCksum[0]; aSaveCksum[1] = pWal->hdr.aFrameCksum[1]; - for(iOffset=walFrameOffset(pWal->hdr.mxFrame+1, pWal->hdr.szPage); + for(iOffset=walFrameOffset(pWal->hdr.mxFrame+1, pWal->szPage); iOffset+szFrame<=szWal; iOffset+=szFrame ){@@ -63213,7 +64557,8 @@ i64 iWalOff; /* Offset of wal file entry */
rc = walHashGet(pWal, walFramePage(i), &sLoc); if( rc!=SQLITE_OK ) break; - pgno = sLoc.aPgno[i-sLoc.iZero]; + assert( i - sLoc.iZero - 1 >=0 ); + pgno = sLoc.aPgno[i-sLoc.iZero-1]; iDbOff = (i64)(pgno-1) * szPage; if( iDbOff+szPage<=szDb ){@@ -63446,7 +64791,7 @@ nCollide = HASHTABLE_NSLOT;
iKey = walHash(pgno); while( (iH = AtomicLoad(&sLoc.aHash[iKey]))!=0 ){ u32 iFrame = iH + sLoc.iZero; - if( iFrame<=iLast && iFrame>=pWal->minFrame && sLoc.aPgno[iH]==pgno ){ + if( iFrame<=iLast && iFrame>=pWal->minFrame && sLoc.aPgno[iH-1]==pgno ){ assert( iFrame>iRead || CORRUPT_DB ); iRead = iFrame; }@@ -64698,7 +66043,6 @@ ** stored in MemPage.pBt->mutex.
*/ struct MemPage { u8 isInit; /* True if previously initialized. MUST BE FIRST! */ - u8 bBusy; /* Prevent endless loops on corrupt database files */ u8 intKey; /* True if table b-trees. False for index b-trees */ u8 intKeyLeaf; /* True if the leaf of an intKey table */ Pgno pgno; /* Page number for this page */@@ -64720,7 +66064,9 @@ ** non-overflow cell */
u8 *apOvfl[4]; /* Pointers to the body of overflow cells */ BtShared *pBt; /* Pointer to BtShared that this page is part of */ u8 *aData; /* Pointer to disk image of the page data */ - u8 *aDataEnd; /* One byte past the end of usable data */ + u8 *aDataEnd; /* One byte past the end of the entire page - not just + ** the usable space, the entire page. Used to prevent + ** corruption-induced buffer overflow. */ u8 *aCellIdx; /* The cell index area */ u8 *aDataOfst; /* Same as aData for leaves. aData+4 for interior */ DbPage *pDbPage; /* Pager page handle */@@ -65025,7 +66371,7 @@
/* ** The database page the PENDING_BYTE occupies. This page is never used. */ -# define PENDING_BYTE_PAGE(pBt) PAGER_MJ_PGNO(pBt) +#define PENDING_BYTE_PAGE(pBt) ((Pgno)((PENDING_BYTE/((pBt)->pageSize))+1)) /* ** These macros define the location of the pointer-map entry for a@@ -65666,7 +67012,7 @@ HashElem *p;
int bSeen = 0; for(p=sqliteHashFirst(&pSchema->idxHash); p; p=sqliteHashNext(p)){ Index *pIdx = (Index *)sqliteHashData(p); - if( pIdx->tnum==(int)iRoot ){ + if( pIdx->tnum==iRoot ){ if( bSeen ){ /* Two or more indexes share the same root page. There must ** be imposter tables. So just return true. The assert is not@@ -66259,7 +67605,7 @@
/* ** In this version of BtreeMoveto, pKey is a packed index record ** such as is generated by the OP_MakeRecord opcode. Unpack the -** record and then call BtreeMovetoUnpacked() to do the work. +** record and then call sqlite3BtreeIndexMoveto() to do the work. */ static int btreeMoveto( BtCursor *pCur, /* Cursor open on the btree to be searched */@@ -66279,15 +67625,13 @@ if( pIdxKey==0 ) return SQLITE_NOMEM_BKPT;
sqlite3VdbeRecordUnpack(pKeyInfo, (int)nKey, pKey, pIdxKey); if( pIdxKey->nField==0 || pIdxKey->nField>pKeyInfo->nAllField ){ rc = SQLITE_CORRUPT_BKPT; - goto moveto_done; + }else{ + rc = sqlite3BtreeIndexMoveto(pCur, pIdxKey, pRes); } + sqlite3DbFree(pCur->pKeyInfo->db, pIdxKey); }else{ pIdxKey = 0; - } - rc = sqlite3BtreeMovetoUnpacked(pCur, pIdxKey, nKey, bias, pRes); -moveto_done: - if( pIdxKey ){ - sqlite3DbFree(pCur->pKeyInfo->db, pIdxKey); + rc = sqlite3BtreeTableMoveto(pCur, nKey, bias, pRes); } return rc; }@@ -66679,18 +68023,32 @@ /* The next block of code is equivalent to:
** ** pIter += getVarint(pIter, (u64*)&pInfo->nKey); ** - ** The code is inlined to avoid a function call. + ** The code is inlined and the loop is unrolled for performance. + ** This routine is a high-runner. */ iKey = *pIter; if( iKey>=0x80 ){ - u8 *pEnd = &pIter[7]; - iKey &= 0x7f; - while(1){ - iKey = (iKey<<7) | (*++pIter & 0x7f); - if( (*pIter)<0x80 ) break; - if( pIter>=pEnd ){ - iKey = (iKey<<8) | *++pIter; - break; + u8 x; + iKey = ((iKey&0x7f)<<7) | ((x = *++pIter) & 0x7f); + if( x>=0x80 ){ + iKey = (iKey<<7) | ((x =*++pIter) & 0x7f); + if( x>=0x80 ){ + iKey = (iKey<<7) | ((x = *++pIter) & 0x7f); + if( x>=0x80 ){ + iKey = (iKey<<7) | ((x = *++pIter) & 0x7f); + if( x>=0x80 ){ + iKey = (iKey<<7) | ((x = *++pIter) & 0x7f); + if( x>=0x80 ){ + iKey = (iKey<<7) | ((x = *++pIter) & 0x7f); + if( x>=0x80 ){ + iKey = (iKey<<7) | ((x = *++pIter) & 0x7f); + if( x>=0x80 ){ + iKey = (iKey<<8) | (*++pIter); + } + } + } + } + } } } }@@ -66700,7 +68058,7 @@ pInfo->nKey = *(i64*)&iKey;
pInfo->nPayload = nPayload; pInfo->pPayload = pIter; testcase( nPayload==pPage->maxLocal ); - testcase( nPayload==pPage->maxLocal+1 ); + testcase( nPayload==(u32)pPage->maxLocal+1 ); if( nPayload<=pPage->maxLocal ){ /* This is the (easy) common case where the entire payload fits ** on the local page. No overflow is required.@@ -66737,7 +68095,7 @@ pInfo->nKey = nPayload;
pInfo->nPayload = nPayload; pInfo->pPayload = pIter; testcase( nPayload==pPage->maxLocal ); - testcase( nPayload==pPage->maxLocal+1 ); + testcase( nPayload==(u32)pPage->maxLocal+1 ); if( nPayload<=pPage->maxLocal ){ /* This is the (easy) common case where the entire payload fits ** on the local page. No overflow is required.@@ -66767,6 +68125,7 @@ ** data header and the local payload, but not any overflow page or
** the space used by the cell pointer. ** ** cellSizePtrNoPayload() => table internal nodes +** cellSizePtrTableLeaf() => table leaf nodes ** cellSizePtr() => all index nodes & table leaf nodes */ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){@@ -66792,15 +68151,8 @@ nSize = (nSize<<7) | (*++pIter & 0x7f);
}while( *(pIter)>=0x80 && pIter<pEnd ); } pIter++; - if( pPage->intKey ){ - /* pIter now points at the 64-bit integer key value, a variable length - ** integer. The following block moves pIter to point at the first byte - ** past the end of the key value. */ - pEnd = &pIter[9]; - while( (*pIter++)&0x80 && pIter<pEnd ); - } testcase( nSize==pPage->maxLocal ); - testcase( nSize==pPage->maxLocal+1 ); + testcase( nSize==(u32)pPage->maxLocal+1 ); if( nSize<=pPage->maxLocal ){ nSize += (u32)(pIter - pCell); if( nSize<4 ) nSize = 4;@@ -66808,7 +68160,7 @@ }else{
int minLocal = pPage->minLocal; nSize = minLocal + (nSize - minLocal) % (pPage->pBt->usableSize - 4); testcase( nSize==pPage->maxLocal ); - testcase( nSize==pPage->maxLocal+1 ); + testcase( nSize==(u32)pPage->maxLocal+1 ); if( nSize>pPage->maxLocal ){ nSize = minLocal; }@@ -66838,6 +68190,58 @@ while( (*pIter++)&0x80 && pIter<pEnd );
assert( debuginfo.nSize==(u16)(pIter - pCell) || CORRUPT_DB ); return (u16)(pIter - pCell); } +static u16 cellSizePtrTableLeaf(MemPage *pPage, u8 *pCell){ + u8 *pIter = pCell; /* For looping over bytes of pCell */ + u8 *pEnd; /* End mark for a varint */ + u32 nSize; /* Size value to return */ + +#ifdef SQLITE_DEBUG + /* The value returned by this function should always be the same as + ** the (CellInfo.nSize) value found by doing a full parse of the + ** cell. If SQLITE_DEBUG is defined, an assert() at the bottom of + ** this function verifies that this invariant is not violated. */ + CellInfo debuginfo; + pPage->xParseCell(pPage, pCell, &debuginfo); +#endif + + nSize = *pIter; + if( nSize>=0x80 ){ + pEnd = &pIter[8]; + nSize &= 0x7f; + do{ + nSize = (nSize<<7) | (*++pIter & 0x7f); + }while( *(pIter)>=0x80 && pIter<pEnd ); + } + pIter++; + /* pIter now points at the 64-bit integer key value, a variable length + ** integer. The following block moves pIter to point at the first byte + ** past the end of the key value. */ + if( (*pIter++)&0x80 + && (*pIter++)&0x80 + && (*pIter++)&0x80 + && (*pIter++)&0x80 + && (*pIter++)&0x80 + && (*pIter++)&0x80 + && (*pIter++)&0x80 + && (*pIter++)&0x80 ){ pIter++; } + testcase( nSize==pPage->maxLocal ); + testcase( nSize==(u32)pPage->maxLocal+1 ); + if( nSize<=pPage->maxLocal ){ + nSize += (u32)(pIter - pCell); + if( nSize<4 ) nSize = 4; + }else{ + int minLocal = pPage->minLocal; + nSize = minLocal + (nSize - minLocal) % (pPage->pBt->usableSize - 4); + testcase( nSize==pPage->maxLocal ); + testcase( nSize==(u32)pPage->maxLocal+1 ); + if( nSize>pPage->maxLocal ){ + nSize = minLocal; + } + nSize += 4 + (u16)(pIter - pCell); + } + assert( nSize==debuginfo.nSize || CORRUPT_DB ); + return (u16)nSize; +} #ifdef SQLITE_DEBUG@@ -66851,7 +68255,7 @@
#ifndef SQLITE_OMIT_AUTOVACUUM /* ** The cell pCell is currently part of page pSrc but will ultimately be part -** of pPage. (pSrc and pPager are often the same.) If pCell contains a +** of pPage. (pSrc and pPage are often the same.) If pCell contains a ** pointer to an overflow page, insert an entry into the pointer-map for ** the overflow page that will be valid after pCell has been moved to pPage. */@@ -66942,7 +68346,7 @@ sz2 = get2byte(&data[iFree2+2]);
if( iFree2+sz2 > usableSize ) return SQLITE_CORRUPT_PAGE(pPage); memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz)); sz += sz2; - }else if( iFree+sz>usableSize ){ + }else if( NEVER(iFree+sz>usableSize) ){ return SQLITE_CORRUPT_PAGE(pPage); }@@ -67026,7 +68430,8 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
const int hdr = pPg->hdrOffset; /* Offset to page header */ u8 * const aData = pPg->aData; /* Page data */ int iAddr = hdr + 1; /* Address of ptr to pc */ - int pc = get2byte(&aData[iAddr]); /* Address of a free slot */ + u8 *pTmp = &aData[iAddr]; /* Temporary ptr into aData[] */ + int pc = get2byte(pTmp); /* Address of a free slot */ int x; /* Excess size of the slot */ int maxPC = pPg->pBt->usableSize - nByte; /* Max address for a usable slot */ int size; /* Size of the free slot */@@ -67036,7 +68441,8 @@ while( pc<=maxPC ){
/* EVIDENCE-OF: R-22710-53328 The third and fourth bytes of each ** freeblock form a big-endian integer which is the size of the freeblock ** in bytes, including the 4-byte header. */ - size = get2byte(&aData[pc+2]); + pTmp = &aData[pc+2]; + size = get2byte(pTmp); if( (x = size - nByte)>=0 ){ testcase( x==4 ); testcase( x==3 );@@ -67049,6 +68455,8 @@ /* Remove the slot from the free-list. Update the number of
** fragmented bytes within the page. */ memcpy(&aData[iAddr], &aData[pc], 2); aData[hdr+7] += (u8)x; + testcase( pc+x>maxPC ); + return &aData[pc]; }else if( x+pc > maxPC ){ /* This slot extends off the end of the usable part of the page */ *pRc = SQLITE_CORRUPT_PAGE(pPg);@@ -67061,7 +68469,8 @@ }
return &aData[pc + x]; } iAddr = pc; - pc = get2byte(&aData[pc]); + pTmp = &aData[pc]; + pc = get2byte(pTmp); if( pc<=iAddr+size ){ if( pc ){ /* The next slot in the chain is not past the end of the current slot */@@ -67095,6 +68504,7 @@ const int hdr = pPage->hdrOffset; /* Local cache of pPage->hdrOffset */
u8 * const data = pPage->aData; /* Local cache of pPage->aData */ int top; /* First byte of cell content area */ int rc = SQLITE_OK; /* Integer return code */ + u8 *pTmp; /* Temp ptr into data[] */ int gap; /* First byte of gap between cell pointers and cell content */ assert( sqlite3PagerIswriteable(pPage->pDbPage) );@@ -67113,7 +68523,8 @@ ** and the reserved space is zero (the usual value for reserved space)
** then the cell content offset of an empty page wants to be 65536. ** However, that integer is too large to be stored in a 2-byte unsigned ** integer, so a value of 0 is used in its place. */ - top = get2byte(&data[hdr+5]); + pTmp = &data[hdr+5]; + top = get2byte(pTmp); assert( top<=(int)pPage->pBt->usableSize ); /* by btreeComputeFreeSpace() */ if( gap>top ){ if( top==0 && pPage->pBt->usableSize==65536 ){@@ -67136,7 +68547,7 @@ if( pSpace ){
int g2; assert( pSpace+nByte<=data+pPage->pBt->usableSize ); *pIdx = g2 = (int)(pSpace-data); - if( NEVER(g2<=gap) ){ + if( g2<=gap ){ return SQLITE_CORRUPT_PAGE(pPage); }else{ return SQLITE_OK;@@ -67195,6 +68606,7 @@ u16 iOrigSize = iSize; /* Original value of iSize */
u16 x; /* Offset to cell content area */ u32 iEnd = iStart + iSize; /* First byte past the iStart buffer */ unsigned char *data = pPage->aData; /* Page content */ + u8 *pTmp; /* Temporary ptr into data[] */ assert( pPage->pBt!=0 ); assert( sqlite3PagerIswriteable(pPage->pDbPage) );@@ -67222,7 +68634,7 @@ }
if( iFreeBlk>pPage->pBt->usableSize-4 ){ /* TH3: corrupt081.100 */ return SQLITE_CORRUPT_PAGE(pPage); } - assert( iFreeBlk>iPtr || iFreeBlk==0 ); + assert( iFreeBlk>iPtr || iFreeBlk==0 || CORRUPT_DB ); /* At this point: ** iFreeBlk: First freeblock after iStart, or zero if none@@ -67257,7 +68669,8 @@ }
if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PAGE(pPage); data[hdr+7] -= nFrag; } - x = get2byte(&data[hdr+5]); + pTmp = &data[hdr+5]; + x = get2byte(pTmp); if( iStart<=x ){ /* The new freeblock is at the beginning of the cell content area, ** so just extend the cell content area rather than create another@@ -67301,7 +68714,6 @@ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
pPage->leaf = (u8)(flagByte>>3); assert( PTF_LEAF == 1<<3 ); flagByte &= ~PTF_LEAF; pPage->childPtrSize = 4-4*pPage->leaf; - pPage->xCellSize = cellSizePtr; pBt = pPage->pBt; if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){ /* EVIDENCE-OF: R-07291-35328 A value of 5 (0x05) means the page is an@@ -67313,6 +68725,7 @@ assert( (PTF_LEAFDATA|PTF_INTKEY|PTF_LEAF)==13 );
pPage->intKey = 1; if( pPage->leaf ){ pPage->intKeyLeaf = 1; + pPage->xCellSize = cellSizePtrTableLeaf; pPage->xParseCell = btreeParseCellPtr; }else{ pPage->intKeyLeaf = 0;@@ -67330,12 +68743,17 @@ ** leaf index b-tree page. */
assert( (PTF_ZERODATA|PTF_LEAF)==10 ); pPage->intKey = 0; pPage->intKeyLeaf = 0; + pPage->xCellSize = cellSizePtr; pPage->xParseCell = btreeParseCellPtrIndex; pPage->maxLocal = pBt->maxLocal; pPage->minLocal = pBt->minLocal; }else{ /* EVIDENCE-OF: R-47608-56469 Any other value for the b-tree page type is ** an error. */ + pPage->intKey = 0; + pPage->intKeyLeaf = 0; + pPage->xCellSize = cellSizePtr; + pPage->xParseCell = btreeParseCellPtrIndex; return SQLITE_CORRUPT_PAGE(pPage); } pPage->max1bytePayload = pBt->max1bytePayload;@@ -67493,7 +68911,7 @@ pPage->maskPage = (u16)(pBt->pageSize - 1);
pPage->nOverflow = 0; pPage->cellOffset = pPage->hdrOffset + 8 + pPage->childPtrSize; pPage->aCellIdx = data + pPage->childPtrSize + 8; - pPage->aDataEnd = pPage->aData + pBt->usableSize; + pPage->aDataEnd = pPage->aData + pBt->pageSize; pPage->aDataOfst = pPage->aData + pPage->childPtrSize; /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the ** number of cells on the page. */@@ -67528,7 +68946,7 @@ BtShared *pBt = pPage->pBt;
u8 hdr = pPage->hdrOffset; u16 first; - assert( sqlite3PagerPagenumber(pPage->pDbPage)==pPage->pgno ); + assert( sqlite3PagerPagenumber(pPage->pDbPage)==pPage->pgno || CORRUPT_DB ); assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage ); assert( sqlite3PagerGetData(pPage->pDbPage) == data ); assert( sqlite3PagerIswriteable(pPage->pDbPage) );@@ -67544,7 +68962,7 @@ put2byte(&data[hdr+5], pBt->usableSize);
pPage->nFree = (u16)(pBt->usableSize - first); decodeFlags(pPage, flags); pPage->cellOffset = first; - pPage->aDataEnd = &data[pBt->usableSize]; + pPage->aDataEnd = &data[pBt->pageSize]; pPage->aCellIdx = &data[first]; pPage->aDataOfst = &data[pPage->childPtrSize]; pPage->nOverflow = 0;@@ -67670,7 +69088,7 @@ if( rc!=SQLITE_OK ){
goto getAndInitPage_error2; } } - assert( (*ppPage)->pgno==pgno ); + assert( (*ppPage)->pgno==pgno || CORRUPT_DB ); assert( (*ppPage)->aData==sqlite3PagerGetData(pDbPage) ); /* If obtaining a child page for a cursor, we must verify that the page is@@ -67689,7 +69107,9 @@ pCur->iPage--;
pCur->pPage = pCur->apPage[pCur->iPage]; } testcase( pgno==0 ); - assert( pgno!=0 || rc==SQLITE_CORRUPT ); + assert( pgno!=0 || rc==SQLITE_CORRUPT + || rc==SQLITE_IOERR_NOMEM + || rc==SQLITE_NOMEM ); return rc; }@@ -68147,30 +69567,38 @@ ** Make sure pBt->pTmpSpace points to an allocation of
** MX_CELL_SIZE(pBt) bytes with a 4-byte prefix for a left-child ** pointer. */ -static void allocateTempSpace(BtShared *pBt){ - if( !pBt->pTmpSpace ){ - pBt->pTmpSpace = sqlite3PageMalloc( pBt->pageSize ); - - /* One of the uses of pBt->pTmpSpace is to format cells before - ** inserting them into a leaf page (function fillInCell()). If - ** a cell is less than 4 bytes in size, it is rounded up to 4 bytes - ** by the various routines that manipulate binary cells. Which - ** can mean that fillInCell() only initializes the first 2 or 3 - ** bytes of pTmpSpace, but that the first 4 bytes are copied from - ** it into a database page. This is not actually a problem, but it - ** does cause a valgrind error when the 1 or 2 bytes of unitialized - ** data is passed to system call write(). So to avoid this error, - ** zero the first 4 bytes of temp space here. - ** - ** Also: Provide four bytes of initialized space before the - ** beginning of pTmpSpace as an area available to prepend the - ** left-child pointer to the beginning of a cell. - */ - if( pBt->pTmpSpace ){ - memset(pBt->pTmpSpace, 0, 8); - pBt->pTmpSpace += 4; - } +static SQLITE_NOINLINE int allocateTempSpace(BtShared *pBt){ + assert( pBt!=0 ); + assert( pBt->pTmpSpace==0 ); + /* This routine is called only by btreeCursor() when allocating the + ** first write cursor for the BtShared object */ + assert( pBt->pCursor!=0 && (pBt->pCursor->curFlags & BTCF_WriteFlag)!=0 ); + pBt->pTmpSpace = sqlite3PageMalloc( pBt->pageSize ); + if( pBt->pTmpSpace==0 ){ + BtCursor *pCur = pBt->pCursor; + pBt->pCursor = pCur->pNext; /* Unlink the cursor */ + memset(pCur, 0, sizeof(*pCur)); + return SQLITE_NOMEM_BKPT; } + + /* One of the uses of pBt->pTmpSpace is to format cells before + ** inserting them into a leaf page (function fillInCell()). If + ** a cell is less than 4 bytes in size, it is rounded up to 4 bytes + ** by the various routines that manipulate binary cells. Which + ** can mean that fillInCell() only initializes the first 2 or 3 + ** bytes of pTmpSpace, but that the first 4 bytes are copied from + ** it into a database page. This is not actually a problem, but it + ** does cause a valgrind error when the 1 or 2 bytes of unitialized + ** data is passed to system call write(). So to avoid this error, + ** zero the first 4 bytes of temp space here. + ** + ** Also: Provide four bytes of initialized space before the + ** beginning of pTmpSpace as an area available to prepend the + ** left-child pointer to the beginning of a cell. + */ + memset(pBt->pTmpSpace, 0, 8); + pBt->pTmpSpace += 4; + return SQLITE_OK; } /*@@ -68549,7 +69977,6 @@ int rc; /* Result code from subfunctions */
MemPage *pPage1; /* Page 1 of the database file */ u32 nPage; /* Number of pages in the database */ u32 nPageFile = 0; /* Number of pages in the database file */ - u32 nPageHeader; /* Number of pages in the database according to hdr */ assert( sqlite3_mutex_held(pBt->mutex) ); assert( pBt->pPage1==0 );@@ -68561,7 +69988,7 @@
/* Do some checking to help insure the file we opened really is ** a valid database file. */ - nPage = nPageHeader = get4byte(28+(u8*)pPage1->aData); + nPage = get4byte(28+(u8*)pPage1->aData); sqlite3PagerPagecount(pBt->pPager, (int*)&nPageFile); if( nPage==0 || memcmp(24+(u8*)pPage1->aData, 92+(u8*)pPage1->aData,4)!=0 ){ nPage = nPageFile;@@ -68596,7 +70023,7 @@ if( page1[19]>2 ){
goto page1_init_failed; } - /* If the write version is set to 2, this database should be accessed + /* If the read version is set to 2, this database should be accessed ** in WAL mode. If the log is not already open, open it now. Then ** return SQLITE_OK and return without populating BtShared.pPage1. ** The caller detects this and calls this function again. This is@@ -68668,9 +70095,13 @@ rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize,
pageSize-usableSize); return rc; } - if( sqlite3WritableSchema(pBt->db)==0 && nPage>nPageFile ){ - rc = SQLITE_CORRUPT_BKPT; - goto page1_init_failed; + if( nPage>nPageFile ){ + if( sqlite3WritableSchema(pBt->db)==0 ){ + rc = SQLITE_CORRUPT_BKPT; + goto page1_init_failed; + }else{ + nPage = nPageFile; + } } /* EVIDENCE-OF: R-28312-64704 However, the usable size is not allowed to ** be less than 480. In other words, if the page size is 512, then the@@ -69300,12 +70731,17 @@ iNear = nFin;
} do { MemPage *pFreePg; + Pgno dbSize = btreePagecount(pBt); rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iNear, eMode); if( rc!=SQLITE_OK ){ releasePage(pLastPg); return rc; } releasePage(pFreePg); + if( iFreePg>dbSize ){ + releasePage(pLastPg); + return SQLITE_CORRUPT_BKPT; + } }while( bCommit && iFreePg>nFin ); assert( iFreePg<iLastPg );@@ -69394,16 +70830,18 @@
/* ** This routine is called prior to sqlite3PagerCommit when a transaction ** is committed for an auto-vacuum database. -** -** If SQLITE_OK is returned, then *pnTrunc is set to the number of pages -** the database file should be truncated to during the commit process. -** i.e. the database has been reorganized so that only the first *pnTrunc -** pages are in use. */ -static int autoVacuumCommit(BtShared *pBt){ +static int autoVacuumCommit(Btree *p){ int rc = SQLITE_OK; - Pager *pPager = pBt->pPager; - VVA_ONLY( int nRef = sqlite3PagerRefcount(pPager); ) + Pager *pPager; + BtShared *pBt; + sqlite3 *db; + VVA_ONLY( int nRef ); + + assert( p!=0 ); + pBt = p->pBt; + pPager = pBt->pPager; + VVA_ONLY( nRef = sqlite3PagerRefcount(pPager); ) assert( sqlite3_mutex_held(pBt->mutex) ); invalidateAllOverflowCache(pBt);@@ -69411,6 +70849,7 @@ assert(pBt->autoVacuum);
if( !pBt->incrVacuum ){ Pgno nFin; /* Number of pages in database after autovacuuming */ Pgno nFree; /* Number of pages on the freelist initially */ + Pgno nVac; /* Number of pages to vacuum */ Pgno iFree; /* The next page to be freed */ Pgno nOrig; /* Database size before freeing */@@ -69424,18 +70863,42 @@ return SQLITE_CORRUPT_BKPT;
} nFree = get4byte(&pBt->pPage1->aData[36]); - nFin = finalDbSize(pBt, nOrig, nFree); + db = p->db; + if( db->xAutovacPages ){ + int iDb; + for(iDb=0; ALWAYS(iDb<db->nDb); iDb++){ + if( db->aDb[iDb].pBt==p ) break; + } + nVac = db->xAutovacPages( + db->pAutovacPagesArg, + db->aDb[iDb].zDbSName, + nOrig, + nFree, + pBt->pageSize + ); + if( nVac>nFree ){ + nVac = nFree; + } + if( nVac==0 ){ + return SQLITE_OK; + } + }else{ + nVac = nFree; + } + nFin = finalDbSize(pBt, nOrig, nVac); if( nFin>nOrig ) return SQLITE_CORRUPT_BKPT; if( nFin<nOrig ){ rc = saveAllCursors(pBt, 0, 0); } for(iFree=nOrig; iFree>nFin && rc==SQLITE_OK; iFree--){ - rc = incrVacuumStep(pBt, nFin, iFree, 1); + rc = incrVacuumStep(pBt, nFin, iFree, nVac==nFree); } if( (rc==SQLITE_DONE || rc==SQLITE_OK) && nFree>0 ){ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); - put4byte(&pBt->pPage1->aData[32], 0); - put4byte(&pBt->pPage1->aData[36], 0); + if( nVac==nFree ){ + put4byte(&pBt->pPage1->aData[32], 0); + put4byte(&pBt->pPage1->aData[36], 0); + } put4byte(&pBt->pPage1->aData[28], nFin); pBt->bDoTruncate = 1; pBt->nPage = nFin;@@ -69486,7 +70949,7 @@ BtShared *pBt = p->pBt;
sqlite3BtreeEnter(p); #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum ){ - rc = autoVacuumCommit(pBt); + rc = autoVacuumCommit(p); if( rc!=SQLITE_OK ){ sqlite3BtreeLeave(p); return rc;@@ -69673,7 +71136,7 @@ static void btreeSetNPage(BtShared *pBt, MemPage *pPage1){
int nPage = get4byte(&pPage1->aData[28]); testcase( nPage==0 ); if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage); - testcase( pBt->nPage!=nPage ); + testcase( pBt->nPage!=(u32)nPage ); pBt->nPage = nPage; }@@ -69885,10 +71348,6 @@ assert( wrFlag==0 || p->inTrans==TRANS_WRITE );
assert( pBt->pPage1 && pBt->pPage1->aData ); assert( wrFlag==0 || (pBt->btsFlags & BTS_READ_ONLY)==0 ); - if( wrFlag ){ - allocateTempSpace(pBt); - if( pBt->pTmpSpace==0 ) return SQLITE_NOMEM_BKPT; - } if( iTable<=1 ){ if( iTable<1 ){ return SQLITE_CORRUPT_BKPT;@@ -69905,19 +71364,25 @@ pCur->iPage = -1;
pCur->pKeyInfo = pKeyInfo; pCur->pBtree = p; pCur->pBt = pBt; - pCur->curFlags = wrFlag ? BTCF_WriteFlag : 0; - pCur->curPagerFlags = wrFlag ? 0 : PAGER_GET_READONLY; + pCur->curFlags = 0; /* If there are two or more cursors on the same btree, then all such ** cursors *must* have the BTCF_Multiple flag set. */ for(pX=pBt->pCursor; pX; pX=pX->pNext){ if( pX->pgnoRoot==iTable ){ pX->curFlags |= BTCF_Multiple; - pCur->curFlags |= BTCF_Multiple; + pCur->curFlags = BTCF_Multiple; } } + pCur->eState = CURSOR_INVALID; pCur->pNext = pBt->pCursor; pBt->pCursor = pCur; - pCur->eState = CURSOR_INVALID; + if( wrFlag ){ + pCur->curFlags |= BTCF_WriteFlag; + pCur->curPagerFlags = 0; + if( pBt->pTmpSpace==0 ) return allocateTempSpace(pBt); + }else{ + pCur->curPagerFlags = PAGER_GET_READONLY; + } return SQLITE_OK; } static int btreeCursorWithLock(@@ -70291,7 +71756,9 @@
assert( pPage ); assert( eOp==0 || eOp==1 ); assert( pCur->eState==CURSOR_VALID ); - assert( pCur->ix<pPage->nCell ); + if( pCur->ix>=pPage->nCell ){ + return SQLITE_CORRUPT_PAGE(pPage); + } assert( cursorHoldsMutex(pCur) ); getCellInfo(pCur);@@ -70478,7 +71945,6 @@ SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->iPage>=0 && pCur->pPage ); - assert( pCur->ix<pCur->pPage->nCell ); return accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0); }@@ -70540,7 +72006,7 @@ assert( pCur!=0 && pCur->iPage>=0 && pCur->pPage);
assert( pCur->eState==CURSOR_VALID ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( cursorOwnsBtShared(pCur) ); - assert( pCur->ix<pCur->pPage->nCell ); + assert( pCur->ix<pCur->pPage->nCell || CORRUPT_DB ); assert( pCur->info.nSize>0 ); assert( pCur->info.pPayload>pCur->pPage->aData || CORRUPT_DB ); assert( pCur->info.pPayload<pCur->pPage->aDataEnd ||CORRUPT_DB);@@ -70691,7 +72157,7 @@ releasePageNotNull(pCur->pPage);
while( --pCur->iPage ){ releasePageNotNull(pCur->apPage[pCur->iPage]); } - pCur->pPage = pCur->apPage[0]; + pRoot = pCur->pPage = pCur->apPage[0]; goto skip_init; } }else if( pCur->pgnoRoot==0 ){@@ -70716,7 +72182,7 @@ pCur->iPage = 0;
pCur->curIntKey = pCur->pPage->intKey; } pRoot = pCur->pPage; - assert( pRoot->pgno==pCur->pgnoRoot ); + assert( pRoot->pgno==pCur->pgnoRoot || CORRUPT_DB ); /* If pCur->pKeyInfo is not NULL, then the caller that opened this cursor ** expected to open it on an index b-tree. Otherwise, if pKeyInfo is@@ -70738,7 +72204,6 @@ pCur->ix = 0;
pCur->info.nSize = 0; pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl); - pRoot = pCur->pPage; if( pRoot->nCell>0 ){ pCur->eState = CURSOR_VALID; }else if( !pRoot->leaf ){@@ -70873,12 +72338,8 @@ }
return rc; } -/* Move the cursor so that it points to an entry near the key -** specified by pIdxKey or intKey. Return a success code. -** -** For INTKEY tables, the intKey parameter is used. pIdxKey -** must be NULL. For index tables, pIdxKey is used and intKey -** is ignored. +/* Move the cursor so that it points to an entry in a table (a.k.a INTKEY) +** table near the key intKey. Return a success code. ** ** If an exact match is not found, then the cursor is always ** left pointing at a leaf page which would hold the entry if it@@ -70891,39 +72352,32 @@ ** pointing. The meaning of the integer written into
** *pRes is as follows: ** ** *pRes<0 The cursor is left pointing at an entry that -** is smaller than intKey/pIdxKey or if the table is empty +** is smaller than intKey or if the table is empty ** and the cursor is therefore left point to nothing. ** ** *pRes==0 The cursor is left pointing at an entry that -** exactly matches intKey/pIdxKey. +** exactly matches intKey. ** ** *pRes>0 The cursor is left pointing at an entry that -** is larger than intKey/pIdxKey. -** -** For index tables, the pIdxKey->eqSeen field is set to 1 if there -** exists an entry in the table that exactly matches pIdxKey. +** is larger than intKey. */ -SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( +SQLITE_PRIVATE int sqlite3BtreeTableMoveto( BtCursor *pCur, /* The cursor to be moved */ - UnpackedRecord *pIdxKey, /* Unpacked index key */ i64 intKey, /* The table key */ int biasRight, /* If true, bias the search to the high end */ int *pRes /* Write search results here */ ){ int rc; - RecordCompare xRecordCompare; 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) ); + assert( pCur->pKeyInfo==0 ); + assert( pCur->eState!=CURSOR_VALID || 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( pIdxKey==0 - && pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0 - ){ + if( pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0 ){ if( pCur->info.nKey==intKey ){ *pRes = 0; return SQLITE_OK;@@ -70945,9 +72399,7 @@ getCellInfo(pCur);
if( pCur->info.nKey==intKey ){ return SQLITE_OK; } - }else if( rc==SQLITE_DONE ){ - rc = SQLITE_OK; - }else{ + }else if( rc!=SQLITE_DONE ){ return rc; } }@@ -70958,17 +72410,6 @@ #ifdef SQLITE_DEBUG
pCur->pBtree->nSeek++; /* Performance measurement during testing */ #endif - if( pIdxKey ){ - xRecordCompare = sqlite3VdbeFindCompare(pIdxKey); - pIdxKey->errCode = 0; - assert( pIdxKey->default_rc==1 - || pIdxKey->default_rc==0 - || pIdxKey->default_rc==-1 - ); - }else{ - xRecordCompare = 0; /* All keys are integers */ - } - rc = moveToRoot(pCur); if( rc ){ if( rc==SQLITE_EMPTY ){@@ -70983,7 +72424,8 @@ assert( pCur->pPage->isInit );
assert( pCur->eState==CURSOR_VALID ); assert( pCur->pPage->nCell > 0 ); assert( pCur->iPage==0 || pCur->apPage[0]->intKey==pCur->curIntKey ); - assert( pCur->curIntKey || pIdxKey ); + assert( pCur->curIntKey ); + for(;;){ int lwr, upr, idx, c; Pgno chldPg;@@ -70997,144 +72439,348 @@ ** would have already detected db corruption. Similarly, pPage must
** be the right kind (index or table) of b-tree page. Otherwise ** a moveToChild() or moveToRoot() call would have detected corruption. */ assert( pPage->nCell>0 ); - assert( pPage->intKey==(pIdxKey==0) ); + assert( pPage->intKey ); lwr = 0; upr = pPage->nCell-1; assert( biasRight==0 || biasRight==1 ); idx = upr>>(1-biasRight); /* idx = biasRight ? upr : (lwr+upr)/2; */ - pCur->ix = (u16)idx; - if( xRecordCompare==0 ){ - for(;;){ - i64 nCellKey; - pCell = findCellPastPtr(pPage, idx); - if( pPage->intKeyLeaf ){ - while( 0x80 <= *(pCell++) ){ - if( pCell>=pPage->aDataEnd ){ - return SQLITE_CORRUPT_PAGE(pPage); - } + for(;;){ + i64 nCellKey; + pCell = findCellPastPtr(pPage, idx); + if( pPage->intKeyLeaf ){ + while( 0x80 <= *(pCell++) ){ + if( pCell>=pPage->aDataEnd ){ + return SQLITE_CORRUPT_PAGE(pPage); } } - getVarint(pCell, (u64*)&nCellKey); - if( nCellKey<intKey ){ - lwr = idx+1; - if( lwr>upr ){ c = -1; break; } - }else if( nCellKey>intKey ){ - upr = idx-1; - if( lwr>upr ){ c = +1; break; } + } + getVarint(pCell, (u64*)&nCellKey); + if( nCellKey<intKey ){ + lwr = idx+1; + if( lwr>upr ){ c = -1; break; } + }else if( nCellKey>intKey ){ + upr = idx-1; + if( lwr>upr ){ c = +1; break; } + }else{ + assert( nCellKey==intKey ); + pCur->ix = (u16)idx; + if( !pPage->leaf ){ + lwr = idx; + goto moveto_table_next_layer; }else{ - assert( nCellKey==intKey ); - pCur->ix = (u16)idx; - if( !pPage->leaf ){ - lwr = idx; - goto moveto_next_layer; - }else{ - pCur->curFlags |= BTCF_ValidNKey; - pCur->info.nKey = nCellKey; - pCur->info.nSize = 0; - *pRes = 0; - return SQLITE_OK; - } + pCur->curFlags |= BTCF_ValidNKey; + pCur->info.nKey = nCellKey; + pCur->info.nSize = 0; + *pRes = 0; + return SQLITE_OK; } - assert( lwr+upr>=0 ); - idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2; */ } + assert( lwr+upr>=0 ); + idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2; */ + } + assert( lwr==upr+1 || !pPage->leaf ); + assert( pPage->isInit ); + if( pPage->leaf ){ + assert( pCur->ix<pCur->pPage->nCell ); + pCur->ix = (u16)idx; + *pRes = c; + rc = SQLITE_OK; + goto moveto_table_finish; + } +moveto_table_next_layer: + if( lwr>=pPage->nCell ){ + chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]); }else{ - for(;;){ - int nCell; /* Size of the pCell cell in bytes */ - pCell = findCellPastPtr(pPage, idx); + chldPg = get4byte(findCell(pPage, lwr)); + } + pCur->ix = (u16)lwr; + rc = moveToChild(pCur, chldPg); + if( rc ) break; + } +moveto_table_finish: + pCur->info.nSize = 0; + assert( (pCur->curFlags & BTCF_ValidOvfl)==0 ); + return rc; +} + +/* +** Compare the "idx"-th cell on the page the cursor pCur is currently +** pointing to to pIdxKey using xRecordCompare. Return negative or +** zero if the cell is less than or equal pIdxKey. Return positive +** if unknown. +** +** Return value negative: Cell at pCur[idx] less than pIdxKey +** +** Return value is zero: Cell at pCur[idx] equals pIdxKey +** +** Return value positive: Nothing is known about the relationship +** of the cell at pCur[idx] and pIdxKey. +** +** This routine is part of an optimization. It is always safe to return +** a positive value as that will cause the optimization to be skipped. +*/ +static int indexCellCompare( + BtCursor *pCur, + int idx, + UnpackedRecord *pIdxKey, + RecordCompare xRecordCompare +){ + MemPage *pPage = pCur->pPage; + int c; + int nCell; /* Size of the pCell cell in bytes */ + u8 *pCell = findCellPastPtr(pPage, idx); + + nCell = pCell[0]; + if( nCell<=pPage->max1bytePayload ){ + /* This branch runs if the record-size field of the cell is a + ** single byte varint and the record fits entirely on the main + ** b-tree page. */ + testcase( pCell+nCell+1==pPage->aDataEnd ); + c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey); + }else if( !(pCell[1] & 0x80) + && (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal + ){ + /* The record-size field is a 2 byte varint and the record + ** fits entirely on the main b-tree page. */ + testcase( pCell+nCell+2==pPage->aDataEnd ); + c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey); + }else{ + /* If the record extends into overflow pages, do not attempt + ** the optimization. */ + c = 99; + } + return c; +} + +/* +** Return true (non-zero) if pCur is current pointing to the last +** page of a table. +*/ +static int cursorOnLastPage(BtCursor *pCur){ + int i; + assert( pCur->eState==CURSOR_VALID ); + for(i=0; i<pCur->iPage; i++){ + MemPage *pPage = pCur->apPage[i]; + if( pCur->aiIdx[i]<pPage->nCell ) return 0; + } + return 1; +} + +/* Move the cursor so that it points to an entry in an index table +** near the key pIdxKey. Return a success code. +** +** If an exact match is not found, then the cursor is always +** left pointing at a leaf page which would hold the entry if it +** were present. The cursor might point to an entry that comes +** before or after the key. +** +** An integer is written into *pRes which is the result of +** comparing the key with the entry to which the cursor is +** pointing. The meaning of the integer written into +** *pRes is as follows: +** +** *pRes<0 The cursor is left pointing at an entry that +** is smaller than pIdxKey or if the table is empty +** and the cursor is therefore left point to nothing. +** +** *pRes==0 The cursor is left pointing at an entry that +** exactly matches pIdxKey. +** +** *pRes>0 The cursor is left pointing at an entry that +** is larger than pIdxKey. +** +** The pIdxKey->eqSeen field is set to 1 if there +** exists an entry in the table that exactly matches pIdxKey. +*/ +SQLITE_PRIVATE int sqlite3BtreeIndexMoveto( + BtCursor *pCur, /* The cursor to be moved */ + UnpackedRecord *pIdxKey, /* Unpacked index key */ + int *pRes /* Write search results here */ +){ + int rc; + RecordCompare xRecordCompare; + + assert( cursorOwnsBtShared(pCur) ); + assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); + assert( pRes ); + assert( pCur->pKeyInfo!=0 ); + +#ifdef SQLITE_DEBUG + pCur->pBtree->nSeek++; /* Performance measurement during testing */ +#endif + + xRecordCompare = sqlite3VdbeFindCompare(pIdxKey); + pIdxKey->errCode = 0; + assert( pIdxKey->default_rc==1 + || pIdxKey->default_rc==0 + || pIdxKey->default_rc==-1 + ); + - /* The maximum supported page-size is 65536 bytes. This means that - ** the maximum number of record bytes stored on an index B-Tree - ** page is less than 16384 bytes and may be stored as a 2-byte - ** varint. This information is used to attempt to avoid parsing - ** the entire cell by checking for the cases where the record is - ** stored entirely within the b-tree page by inspecting the first - ** 2 bytes of the cell. - */ - nCell = pCell[0]; - if( nCell<=pPage->max1bytePayload ){ - /* This branch runs if the record-size field of the cell is a - ** single byte varint and the record fits entirely on the main - ** b-tree page. */ - testcase( pCell+nCell+1==pPage->aDataEnd ); - c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey); - }else if( !(pCell[1] & 0x80) - && (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal - ){ - /* The record-size field is a 2 byte varint and the record - ** fits entirely on the main b-tree page. */ - testcase( pCell+nCell+2==pPage->aDataEnd ); - c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey); - }else{ - /* The record flows over onto one or more overflow pages. In - ** this case the whole cell needs to be parsed, a buffer allocated - ** and accessPayload() used to retrieve the record into the - ** buffer before VdbeRecordCompare() can be called. - ** - ** If the record is corrupt, the xRecordCompare routine may read - ** up to two varints past the end of the buffer. An extra 18 - ** bytes of padding is allocated at the end of the buffer in - ** case this happens. */ - void *pCellKey; - u8 * const pCellBody = pCell - pPage->childPtrSize; - const int nOverrun = 18; /* Size of the overrun padding */ - pPage->xParseCell(pPage, pCellBody, &pCur->info); - nCell = (int)pCur->info.nKey; - testcase( nCell<0 ); /* True if key size is 2^32 or more */ - testcase( nCell==0 ); /* Invalid key size: 0x80 0x80 0x00 */ - testcase( nCell==1 ); /* Invalid key size: 0x80 0x80 0x01 */ - testcase( nCell==2 ); /* Minimum legal index key size */ - if( nCell<2 || nCell/pCur->pBt->usableSize>pCur->pBt->nPage ){ - rc = SQLITE_CORRUPT_PAGE(pPage); - goto moveto_finish; - } - pCellKey = sqlite3Malloc( nCell+nOverrun ); - if( pCellKey==0 ){ - rc = SQLITE_NOMEM_BKPT; - goto moveto_finish; - } - pCur->ix = (u16)idx; - rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0); - memset(((u8*)pCellKey)+nCell,0,nOverrun); /* Fix uninit warnings */ - pCur->curFlags &= ~BTCF_ValidOvfl; - if( rc ){ - sqlite3_free(pCellKey); - goto moveto_finish; - } - c = sqlite3VdbeRecordCompare(nCell, pCellKey, pIdxKey); + /* Check to see if we can skip a lot of work. Two cases: + ** + ** (1) If the cursor is already pointing to the very last cell + ** in the table and the pIdxKey search key is greater than or + ** equal to that last cell, then no movement is required. + ** + ** (2) If the cursor is on the last page of the table and the first + ** cell on that last page is less than or equal to the pIdxKey + ** search key, then we can start the search on the current page + ** without needing to go back to root. + */ + if( pCur->eState==CURSOR_VALID + && pCur->pPage->leaf + && cursorOnLastPage(pCur) + ){ + int c; + if( pCur->ix==pCur->pPage->nCell-1 + && (c = indexCellCompare(pCur, pCur->ix, pIdxKey, xRecordCompare))<=0 + && pIdxKey->errCode==SQLITE_OK + ){ + *pRes = c; + return SQLITE_OK; /* Cursor already pointing at the correct spot */ + } + if( pCur->iPage>0 + && indexCellCompare(pCur, 0, pIdxKey, xRecordCompare)<=0 + && pIdxKey->errCode==SQLITE_OK + ){ + pCur->curFlags &= ~BTCF_ValidOvfl; + if( !pCur->pPage->isInit ){ + return SQLITE_CORRUPT_BKPT; + } + goto bypass_moveto_root; /* Start search on the current page */ + } + pIdxKey->errCode = SQLITE_OK; + } + + rc = moveToRoot(pCur); + if( rc ){ + if( rc==SQLITE_EMPTY ){ + assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 ); + *pRes = -1; + return SQLITE_OK; + } + return rc; + } + +bypass_moveto_root: + assert( pCur->pPage ); + assert( pCur->pPage->isInit ); + assert( pCur->eState==CURSOR_VALID ); + assert( pCur->pPage->nCell > 0 ); + assert( pCur->curIntKey==0 ); + assert( pIdxKey!=0 ); + for(;;){ + int lwr, upr, idx, c; + Pgno chldPg; + MemPage *pPage = pCur->pPage; + u8 *pCell; /* Pointer to current cell in pPage */ + + /* pPage->nCell must be greater than zero. If this is the root-page + ** the cursor would have been INVALID above and this for(;;) loop + ** not run. If this is not the root-page, then the moveToChild() routine + ** would have already detected db corruption. Similarly, pPage must + ** be the right kind (index or table) of b-tree page. Otherwise + ** a moveToChild() or moveToRoot() call would have detected corruption. */ + assert( pPage->nCell>0 ); + assert( pPage->intKey==0 ); + lwr = 0; + upr = pPage->nCell-1; + idx = upr>>1; /* idx = (lwr+upr)/2; */ + for(;;){ + int nCell; /* Size of the pCell cell in bytes */ + pCell = findCellPastPtr(pPage, idx); + + /* The maximum supported page-size is 65536 bytes. This means that + ** the maximum number of record bytes stored on an index B-Tree + ** page is less than 16384 bytes and may be stored as a 2-byte + ** varint. This information is used to attempt to avoid parsing + ** the entire cell by checking for the cases where the record is + ** stored entirely within the b-tree page by inspecting the first + ** 2 bytes of the cell. + */ + nCell = pCell[0]; + if( nCell<=pPage->max1bytePayload ){ + /* This branch runs if the record-size field of the cell is a + ** single byte varint and the record fits entirely on the main + ** b-tree page. */ + testcase( pCell+nCell+1==pPage->aDataEnd ); + c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey); + }else if( !(pCell[1] & 0x80) + && (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal + ){ + /* The record-size field is a 2 byte varint and the record + ** fits entirely on the main b-tree page. */ + testcase( pCell+nCell+2==pPage->aDataEnd ); + c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey); + }else{ + /* The record flows over onto one or more overflow pages. In + ** this case the whole cell needs to be parsed, a buffer allocated + ** and accessPayload() used to retrieve the record into the + ** buffer before VdbeRecordCompare() can be called. + ** + ** If the record is corrupt, the xRecordCompare routine may read + ** up to two varints past the end of the buffer. An extra 18 + ** bytes of padding is allocated at the end of the buffer in + ** case this happens. */ + void *pCellKey; + u8 * const pCellBody = pCell - pPage->childPtrSize; + const int nOverrun = 18; /* Size of the overrun padding */ + pPage->xParseCell(pPage, pCellBody, &pCur->info); + nCell = (int)pCur->info.nKey; + testcase( nCell<0 ); /* True if key size is 2^32 or more */ + testcase( nCell==0 ); /* Invalid key size: 0x80 0x80 0x00 */ + testcase( nCell==1 ); /* Invalid key size: 0x80 0x80 0x01 */ + testcase( nCell==2 ); /* Minimum legal index key size */ + if( nCell<2 || nCell/pCur->pBt->usableSize>pCur->pBt->nPage ){ + rc = SQLITE_CORRUPT_PAGE(pPage); + goto moveto_index_finish; + } + pCellKey = sqlite3Malloc( nCell+nOverrun ); + if( pCellKey==0 ){ + rc = SQLITE_NOMEM_BKPT; + goto moveto_index_finish; + } + pCur->ix = (u16)idx; + rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0); + memset(((u8*)pCellKey)+nCell,0,nOverrun); /* Fix uninit warnings */ + pCur->curFlags &= ~BTCF_ValidOvfl; + if( rc ){ sqlite3_free(pCellKey); - } - assert( - (pIdxKey->errCode!=SQLITE_CORRUPT || c==0) - && (pIdxKey->errCode!=SQLITE_NOMEM || pCur->pBtree->db->mallocFailed) - ); - if( c<0 ){ - lwr = idx+1; - }else if( c>0 ){ - upr = idx-1; - }else{ - assert( c==0 ); - *pRes = 0; - rc = SQLITE_OK; - pCur->ix = (u16)idx; - if( pIdxKey->errCode ) rc = SQLITE_CORRUPT_BKPT; - goto moveto_finish; + goto moveto_index_finish; } - if( lwr>upr ) break; - assert( lwr+upr>=0 ); - idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2 */ + c = sqlite3VdbeRecordCompare(nCell, pCellKey, pIdxKey); + sqlite3_free(pCellKey); } + assert( + (pIdxKey->errCode!=SQLITE_CORRUPT || c==0) + && (pIdxKey->errCode!=SQLITE_NOMEM || pCur->pBtree->db->mallocFailed) + ); + if( c<0 ){ + lwr = idx+1; + }else if( c>0 ){ + upr = idx-1; + }else{ + assert( c==0 ); + *pRes = 0; + rc = SQLITE_OK; + pCur->ix = (u16)idx; + if( pIdxKey->errCode ) rc = SQLITE_CORRUPT_BKPT; + goto moveto_index_finish; + } + if( lwr>upr ) break; + assert( lwr+upr>=0 ); + idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2 */ } assert( lwr==upr+1 || (pPage->intKey && !pPage->leaf) ); assert( pPage->isInit ); if( pPage->leaf ){ - assert( pCur->ix<pCur->pPage->nCell ); + assert( pCur->ix<pCur->pPage->nCell || CORRUPT_DB ); pCur->ix = (u16)idx; *pRes = c; rc = SQLITE_OK; - goto moveto_finish; + goto moveto_index_finish; } -moveto_next_layer: if( lwr>=pPage->nCell ){ chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]); }else{@@ -71144,7 +72790,7 @@ pCur->ix = (u16)lwr;
rc = moveToChild(pCur, chldPg); if( rc ) break; } -moveto_finish: +moveto_index_finish: pCur->info.nSize = 0; assert( (pCur->curFlags & BTCF_ValidOvfl)==0 ); return rc;@@ -71244,16 +72890,6 @@ ** module cov1/btree78.test testcase 220 (2018-06-08) for an
** example. */ return SQLITE_CORRUPT_BKPT; } - - /* If the database file is corrupt, it is possible for the value of idx - ** to be invalid here. This can only occur if a second cursor modifies - ** the page while cursor pCur is holding a reference to it. Which can - ** only happen if the database is corrupt in such a way as to link the - ** page into more than one b-tree structure. - ** - ** Update 2019-12-23: appears to long longer be possible after the - ** addition of anotherValidCursor() condition on balance_deeper(). */ - harmless( idx>pPage->nCell ); if( idx>=pPage->nCell ){ if( !pPage->leaf ){@@ -72166,16 +73802,24 @@ int rc; /* The return code */
int hdr; /* Beginning of the header. 0 most pages. 100 page 1 */ if( *pRC ) return; - assert( idx>=0 && idx<pPage->nCell ); + assert( idx>=0 ); + assert( idx<pPage->nCell ); assert( CORRUPT_DB || sz==cellSize(pPage, idx) ); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( pPage->nFree>=0 ); data = pPage->aData; ptr = &pPage->aCellIdx[2*idx]; + assert( pPage->pBt->usableSize > (u32)(ptr-data) ); pc = get2byte(ptr); hdr = pPage->hdrOffset; - testcase( pc==get2byte(&data[hdr+5]) ); +#if 0 /* Not required. Omit for efficiency */ + if( pc<hdr+pPage->nCell*2 ){ + *pRC = SQLITE_CORRUPT_BKPT; + return; + } +#endif + testcase( pc==(u32)get2byte(&data[hdr+5]) ); testcase( pc+sz==pPage->pBt->usableSize ); if( pc+sz > pPage->pBt->usableSize ){ *pRC = SQLITE_CORRUPT_BKPT;@@ -72467,7 +74111,7 @@ u8 *pSrcEnd; /* Current pCArray->apEnd[k] value */
assert( i<iEnd ); j = get2byte(&aData[hdr+5]); - if( NEVER(j>(u32)usableSize) ){ j = 0; } + if( j>(u32)usableSize ){ j = 0; } memcpy(&pTmp[j], &aData[j], usableSize - j); for(k=0; pCArray->ixNx[k]<=i && ALWAYS(k<NB*2); k++){}@@ -72698,6 +74342,7 @@ }
pData = &aData[get2byteNotZero(&aData[hdr+5])]; if( pData<pBegin ) goto editpage_fail; + if( pData>pPg->aDataEnd ) goto editpage_fail; /* Add cells to the start of the page */ if( iNew<iOld ){@@ -73059,11 +74704,10 @@ u8 abDone[NB+2]; /* True after i'th new page is populated */
Pgno aPgno[NB+2]; /* Page numbers of new pages before shuffling */ Pgno aPgOrder[NB+2]; /* Copy of aPgno[] used for sorting pages */ u16 aPgFlags[NB+2]; /* flags field of new pages before shuffling */ - CellArray b; /* Parsed information on cells being balanced */ + CellArray b; /* Parsed information on cells being balanced */ memset(abDone, 0, sizeof(abDone)); - b.nCell = 0; - b.apCell = 0; + memset(&b, 0, sizeof(b)); pBt = pParent->pBt; assert( sqlite3_mutex_held(pBt->mutex) ); assert( sqlite3PagerIswriteable(pParent->pDbPage) );@@ -73128,6 +74772,7 @@ memset(apOld, 0, (i)*sizeof(MemPage*));
goto balance_cleanup; } } + nMaxCells += apOld[i]->nCell + ArraySize(pParent->apOvfl); if( (i--)==0 ) break; if( pParent->nOverflow && i+nxDiv==pParent->aiOvfl[0] ){@@ -73169,7 +74814,6 @@ }
/* Make nMaxCells a multiple of 4 in order to preserve 8-byte ** alignment */ - nMaxCells = nOld*(MX_CELL(pBt) + ArraySize(pParent->apOvfl)); nMaxCells = (nMaxCells + 3)&~3; /*@@ -73452,7 +75096,9 @@ pNew = apNew[i] = apOld[i];
apOld[i] = 0; rc = sqlite3PagerWrite(pNew->pDbPage); nNew++; - if( sqlite3PagerPageRefcount(pNew->pDbPage)!=1+(i==(iParentIdx-nxDiv)) ){ + if( sqlite3PagerPageRefcount(pNew->pDbPage)!=1+(i==(iParentIdx-nxDiv)) + && rc==SQLITE_OK + ){ rc = SQLITE_CORRUPT_BKPT; } if( rc ) goto balance_cleanup;@@ -73653,7 +75299,7 @@ }
iOvflSpace += sz; assert( sz<=pBt->maxLocal+23 ); assert( iOvflSpace <= (int)pBt->pageSize ); - for(k=0; b.ixNx[k]<=i && ALWAYS(k<NB*2); k++){} + for(k=0; b.ixNx[k]<=j && ALWAYS(k<NB*2); k++){} pSrcEnd = b.apEnd[k]; if( SQLITE_WITHIN(pSrcEnd, pCell, pCell+sz) ){ rc = SQLITE_CORRUPT_BKPT;@@ -73872,7 +75518,7 @@ /*
** Return SQLITE_CORRUPT if any cursor other than pCur is currently valid ** on the same B-tree as pCur. ** -** This can if a database is corrupt with two or more SQL tables +** This can occur if a database is corrupt with two or more SQL tables ** pointing to the same b-tree. If an insert occurs on one SQL table ** and causes a BEFORE TRIGGER to do a secondary insert on the other SQL ** table linked to the same b-tree. If the secondary insert causes a@@ -73904,7 +75550,6 @@ ** balance_nonroot()
*/ static int balance(BtCursor *pCur){ int rc = SQLITE_OK; - const int nMin = pCur->pBt->usableSize * 2 / 3; u8 aBalanceQuickSpace[13]; u8 *pFree = 0;@@ -73916,7 +75561,11 @@ int iPage;
MemPage *pPage = pCur->pPage; if( NEVER(pPage->nFree<0) && btreeComputeFreeSpace(pPage) ) break; - if( pPage->nOverflow==0 && pPage->nFree<=nMin ){ + if( pPage->nOverflow==0 && pPage->nFree*3<=(int)pCur->pBt->usableSize*2 ){ + /* No rebalance required as long as: + ** (1) There are no overflow cells + ** (2) The amount of free space on the page is less than 2/3rds of + ** the total usable space on the page. */ break; }else if( (iPage = pCur->iPage)==0 ){ if( pPage->nOverflow && (rc = anotherValidCursor(pCur))==SQLITE_OK ){@@ -74101,7 +75750,7 @@ ovflPageSize = pBt->usableSize - 4;
do{ rc = btreeGetPage(pBt, ovflPgno, &pPage, 0); if( rc ) return rc; - if( sqlite3PagerPageRefcount(pPage->pDbPage)!=1 ){ + if( sqlite3PagerPageRefcount(pPage->pDbPage)!=1 || pPage->isInit ){ rc = SQLITE_CORRUPT_BKPT; }else{ if( iOffset+ovflPageSize<(u32)nTotal ){@@ -74136,7 +75785,7 @@ ** 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 +** sqlite3BtreeIndexMoveto() to seek cursor pCur to (pKey,nKey) has already ** been performed. In other words, if seekResult!=0 then the cursor ** is currently pointing to a cell that will be adjacent to the cell ** to be inserted. If seekResult<0 then pCur points to a cell that is@@ -74154,7 +75803,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
BtCursor *pCur, /* Insert data into the table of this cursor */ const BtreePayload *pX, /* Content of the row to be inserted */ int flags, /* True if this is likely an append */ - int seekResult /* Result of prior MovetoUnpacked() call */ + int seekResult /* Result of prior IndexMoveto() call */ ){ int rc; int loc = seekResult; /* -1: before desired location +1: after */@@ -74169,24 +75818,6 @@
assert( (flags & (BTREE_SAVEPOSITION|BTREE_APPEND|BTREE_PREFORMAT))==flags ); assert( (flags & BTREE_PREFORMAT)==0 || seekResult || pCur->pKeyInfo==0 ); - if( pCur->eState==CURSOR_FAULT ){ - assert( pCur->skipNext!=SQLITE_OK ); - return pCur->skipNext; - } - - assert( cursorOwnsBtShared(pCur) ); - assert( (pCur->curFlags & BTCF_WriteFlag)!=0 - && pBt->inTransaction==TRANS_WRITE - && (pBt->btsFlags & BTS_READ_ONLY)==0 ); - assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); - - /* 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( (flags & BTREE_PREFORMAT) || (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@@ -74211,6 +75842,29 @@ return SQLITE_CORRUPT_BKPT;
} } + /* Ensure that the cursor is not in the CURSOR_FAULT state and that it + ** points to a valid cell. + */ + if( pCur->eState>=CURSOR_REQUIRESEEK ){ + testcase( pCur->eState==CURSOR_REQUIRESEEK ); + testcase( pCur->eState==CURSOR_FAULT ); + rc = moveToRoot(pCur); + if( rc && rc!=SQLITE_EMPTY ) return rc; + } + + assert( cursorOwnsBtShared(pCur) ); + assert( (pCur->curFlags & BTCF_WriteFlag)!=0 + && pBt->inTransaction==TRANS_WRITE + && (pBt->btsFlags & BTS_READ_ONLY)==0 ); + assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); + + /* 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( (flags & BTREE_PREFORMAT) || (pX->pKey==0)==(pCur->pKeyInfo==0) ); + if( pCur->pKeyInfo==0 ){ assert( pX->pKey==0 ); /* If this is an insert into a table b-tree, invalidate any incrblob@@ -74250,7 +75904,8 @@ /* The cursor is *not* pointing to the cell to be overwritten, nor
** to an adjacent cell. Move the cursor so that it is pointing either ** to the cell to be overwritten or an adjacent cell. */ - rc = sqlite3BtreeMovetoUnpacked(pCur, 0, pX->nKey, flags!=0, &loc); + rc = sqlite3BtreeTableMoveto(pCur, pX->nKey, + (flags & BTREE_APPEND)!=0, &loc); if( rc ) return rc; } }else{@@ -74273,13 +75928,11 @@ r.pKeyInfo = pCur->pKeyInfo;
r.aMem = pX->aMem; r.nField = pX->nMem; r.default_rc = 0; - r.errCode = 0; - r.r1 = 0; - r.r2 = 0; r.eqSeen = 0; - rc = sqlite3BtreeMovetoUnpacked(pCur, &r, 0, flags!=0, &loc); + rc = sqlite3BtreeIndexMoveto(pCur, &r, &loc); }else{ - rc = btreeMoveto(pCur, pX->pKey, pX->nKey, flags!=0, &loc); + rc = btreeMoveto(pCur, pX->pKey, pX->nKey, + (flags & BTREE_APPEND)!=0, &loc); } if( rc ) return rc; }@@ -74300,14 +75953,14 @@ }
} } assert( pCur->eState==CURSOR_VALID - || (pCur->eState==CURSOR_INVALID && loc) - || CORRUPT_DB ); + || (pCur->eState==CURSOR_INVALID && loc) ); pPage = pCur->pPage; assert( pPage->intKey || pX->nKey>=0 || (flags & BTREE_PREFORMAT) ); assert( pPage->leaf || !pPage->intKey ); if( pPage->nFree<0 ){ if( NEVER(pCur->eState>CURSOR_INVALID) ){ + /* ^^^^^--- due to the moveToRoot() call above */ rc = SQLITE_CORRUPT_BKPT; }else{ rc = btreeComputeFreeSpace(pPage);@@ -74318,7 +75971,7 @@
TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n", pCur->pgnoRoot, pX->nKey, pX->nData, pPage->pgno, loc==0 ? "overwrite" : "new entry")); - assert( pPage->isInit ); + assert( pPage->isInit || CORRUPT_DB ); newCell = pBt->pTmpSpace; assert( newCell!=0 ); if( flags & BTREE_PREFORMAT ){@@ -74342,7 +75995,10 @@ assert( szNew <= MX_CELL_SIZE(pBt) );
idx = pCur->ix; if( loc==0 ){ CellInfo info; - assert( idx<pPage->nCell ); + assert( idx>=0 ); + if( idx>=pPage->nCell ){ + return SQLITE_CORRUPT_BKPT; + } rc = sqlite3PagerWrite(pPage->pDbPage); if( rc ){ goto end_insert;@@ -74466,7 +76122,11 @@ u32 nIn; /* Size of input buffer aIn[] */
u32 nRem; /* Bytes of data still to copy */ getCellInfo(pSrc); - aOut += putVarint32(aOut, pSrc->info.nPayload); + if( pSrc->info.nPayload<0x80 ){ + *(aOut++) = pSrc->info.nPayload; + }else{ + aOut += sqlite3PutVarint(aOut, pSrc->info.nPayload); + } if( pDest->pKeyInfo==0 ) aOut += putVarint(aOut, iKey); nIn = pSrc->info.nLocal; aIn = pSrc->info.pPayload;@@ -74524,7 +76184,7 @@ }
} }while( rc==SQLITE_OK && nOut>0 ); - if( rc==SQLITE_OK && nRem>0 ){ + if( rc==SQLITE_OK && nRem>0 && ALWAYS(pPgnoOut) ){ Pgno pgnoNew; MemPage *pNew = 0; rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0);@@ -74570,14 +76230,13 @@ */
SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ Btree *p = pCur->pBtree; BtShared *pBt = p->pBt; - int rc; /* Return code */ - MemPage *pPage; /* Page to delete cell from */ - unsigned char *pCell; /* Pointer to cell to delete */ - int iCellIdx; /* Index of cell to delete */ - int iCellDepth; /* Depth of node containing pCell */ - CellInfo info; /* Size of the cell being deleted */ - int bSkipnext = 0; /* Leaf cursor in SKIPNEXT state */ - u8 bPreserve = flags & BTREE_SAVEPOSITION; /* Keep cursor valid */ + int rc; /* Return code */ + MemPage *pPage; /* Page to delete cell from */ + unsigned char *pCell; /* Pointer to cell to delete */ + int iCellIdx; /* Index of cell to delete */ + int iCellDepth; /* Depth of node containing pCell */ + CellInfo info; /* Size of the cell being deleted */ + u8 bPreserve; /* Keep cursor valid. 2 for CURSOR_SKIPNEXT */ assert( cursorOwnsBtShared(pCur) ); assert( pBt->inTransaction==TRANS_WRITE );@@ -74586,31 +76245,49 @@ assert( pCur->curFlags & BTCF_WriteFlag );
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); assert( !hasReadConflicts(p, pCur->pgnoRoot) ); assert( (flags & ~(BTREE_SAVEPOSITION | BTREE_AUXDELETE))==0 ); - if( pCur->eState==CURSOR_REQUIRESEEK ){ - rc = btreeRestoreCursorPosition(pCur); - assert( rc!=SQLITE_OK || CORRUPT_DB || pCur->eState==CURSOR_VALID ); - if( rc || pCur->eState!=CURSOR_VALID ) return rc; + if( pCur->eState!=CURSOR_VALID ){ + if( pCur->eState>=CURSOR_REQUIRESEEK ){ + rc = btreeRestoreCursorPosition(pCur); + assert( rc!=SQLITE_OK || CORRUPT_DB || pCur->eState==CURSOR_VALID ); + if( rc || pCur->eState!=CURSOR_VALID ) return rc; + }else{ + return SQLITE_CORRUPT_BKPT; + } } - assert( CORRUPT_DB || pCur->eState==CURSOR_VALID ); + assert( pCur->eState==CURSOR_VALID ); iCellDepth = pCur->iPage; iCellIdx = pCur->ix; pPage = pCur->pPage; + if( pPage->nCell<=iCellIdx ){ + return SQLITE_CORRUPT_BKPT; + } pCell = findCell(pPage, iCellIdx); - if( pPage->nFree<0 && btreeComputeFreeSpace(pPage) ) return SQLITE_CORRUPT; + if( pPage->nFree<0 && btreeComputeFreeSpace(pPage) ){ + return SQLITE_CORRUPT_BKPT; + } - /* If the bPreserve flag is set to true, then the cursor position must + /* If the BTREE_SAVEPOSITION bit is on, then the cursor position must ** be preserved following this delete operation. If the current delete ** will cause a b-tree rebalance, then this is done by saving the cursor ** key and leaving the cursor in CURSOR_REQUIRESEEK state before ** returning. ** - ** Or, if the current delete will not cause a rebalance, then the cursor + ** If the current delete will not cause a rebalance, then the cursor ** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately - ** before or after the deleted entry. In this case set bSkipnext to true. */ + ** before or after the deleted entry. + ** + ** The bPreserve value records which path is required: + ** + ** bPreserve==0 Not necessary to save the cursor position + ** bPreserve==1 Use CURSOR_REQUIRESEEK to save the cursor position + ** bPreserve==2 Cursor won't move. Set CURSOR_SKIPNEXT. + */ + bPreserve = (flags & BTREE_SAVEPOSITION)!=0; if( bPreserve ){ if( !pPage->leaf - || (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3) + || (pPage->nFree+pPage->xCellSize(pPage,pCell)+2) > + (int)(pBt->usableSize*2/3) || pPage->nCell==1 /* See dbfuzz001.test for a test case */ ){ /* A b-tree rebalance will be required after deleting this entry.@@ -74618,7 +76295,7 @@ ** Save the cursor key. */
rc = saveCursorKey(pCur); if( rc ) return rc; }else{ - bSkipnext = 1; + bPreserve = 2; } }@@ -74706,7 +76383,15 @@ ** tree that we can be sure that any problem in the internal node has
** been corrected, so be it. Otherwise, after balancing the leaf node, ** walk the cursor up the tree to the internal node and balance it as ** well. */ - rc = balance(pCur); + assert( pCur->pPage->nOverflow==0 ); + assert( pCur->pPage->nFree>=0 ); + if( pCur->pPage->nFree*3<=(int)pCur->pBt->usableSize*2 ){ + /* Optimization: If the free space is less than 2/3rds of the page, + ** then balance() will always be a no-op. No need to invoke it. */ + rc = SQLITE_OK; + }else{ + rc = balance(pCur); + } if( rc==SQLITE_OK && pCur->iPage>iCellDepth ){ releasePageNotNull(pCur->pPage); pCur->iPage--;@@ -74718,8 +76403,8 @@ rc = balance(pCur);
} if( rc==SQLITE_OK ){ - if( bSkipnext ){ - assert( bPreserve && (pCur->iPage==iCellDepth || CORRUPT_DB) ); + if( bPreserve>1 ){ + assert( (pCur->iPage==iCellDepth || CORRUPT_DB) ); assert( pPage==pCur->pPage || CORRUPT_DB ); assert( (pPage->nCell>0 || CORRUPT_DB) && iCellIdx<=pPage->nCell ); pCur->eState = CURSOR_SKIPNEXT;@@ -74913,7 +76598,7 @@ static int clearDatabasePage(
BtShared *pBt, /* The BTree that contains the table */ Pgno pgno, /* Page number to clear */ int freePageFlag, /* Deallocate page if true */ - int *pnChange /* Add number of Cells freed to this counter */ + i64 *pnChange /* Add number of Cells freed to this counter */ ){ MemPage *pPage; int rc;@@ -74928,11 +76613,12 @@ return SQLITE_CORRUPT_BKPT;
} rc = getAndInitPage(pBt, pgno, &pPage, 0, 0); if( rc ) return rc; - if( pPage->bBusy ){ + if( (pBt->openFlags & BTREE_SINGLE)==0 + && sqlite3PagerPageRefcount(pPage->pDbPage) != (1 + (pgno==1)) + ){ rc = SQLITE_CORRUPT_BKPT; goto cleardatabasepage_out; } - pPage->bBusy = 1; hdr = pPage->hdrOffset; for(i=0; i<pPage->nCell; i++){ pCell = findCell(pPage, i);@@ -74946,6 +76632,7 @@ }
if( !pPage->leaf ){ rc = clearDatabasePage(pBt, get4byte(&pPage->aData[hdr+8]), 1, pnChange); if( rc ) goto cleardatabasepage_out; + if( pPage->intKey ) pnChange = 0; } if( pnChange ){ testcase( !pPage->intKey );@@ -74958,7 +76645,6 @@ zeroPage(pPage, pPage->aData[hdr] | PTF_LEAF);
} cleardatabasepage_out: - pPage->bBusy = 0; releasePage(pPage); return rc; }@@ -74975,7 +76661,7 @@ **
** If pnChange is not NULL, then the integer value pointed to by pnChange ** is incremented by the number of entries in the table. */ -SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){ +SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree *p, int iTable, i64 *pnChange){ int rc; BtShared *pBt = p->pBt; sqlite3BtreeEnter(p);@@ -75037,10 +76723,10 @@ if( iTable>btreePagecount(pBt) ){
return SQLITE_CORRUPT_BKPT; } - rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0); - if( rc ) return rc; rc = sqlite3BtreeClearTable(p, iTable, 0); - if( rc ){ + if( rc ) return rc; + rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0); + if( NEVER(rc) ){ releasePage(pPage); return rc; }@@ -76308,14 +77994,13 @@
if( i==1 ){ Parse sParse; int rc = 0; - memset(&sParse, 0, sizeof(sParse)); - sParse.db = pDb; + sqlite3ParseObjectInit(&sParse,pDb); if( sqlite3OpenTempDatabase(&sParse) ){ sqlite3ErrorWithMsg(pErrorDb, sParse.rc, "%s", sParse.zErrMsg); rc = SQLITE_ERROR; } sqlite3DbFree(pErrorDb, sParse.zErrMsg); - sqlite3ParserReset(&sParse); + sqlite3ParseObjectReset(&sParse); if( rc ){ return 0; }@@ -77197,10 +78882,15 @@ SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
#ifndef SQLITE_OMIT_UTF16 int rc; #endif + assert( pMem!=0 ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( desiredEnc==SQLITE_UTF8 || desiredEnc==SQLITE_UTF16LE || desiredEnc==SQLITE_UTF16BE ); - if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){ + if( !(pMem->flags&MEM_Str) ){ + pMem->enc = desiredEnc; + return SQLITE_OK; + } + if( pMem->enc==desiredEnc ){ return SQLITE_OK; } assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );@@ -77329,6 +79019,7 @@ **
** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails. */ SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){ + assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); if( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ){@@ -77353,6 +79044,7 @@ */
#ifndef SQLITE_OMIT_INCRBLOB SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *pMem){ int nByte; + assert( pMem!=0 ); assert( pMem->flags & MEM_Zero ); assert( (pMem->flags&MEM_Blob)!=0 || MemNullNochng(pMem) ); testcase( sqlite3_value_nochange(pMem) );@@ -77368,6 +79060,8 @@ }
if( sqlite3VdbeMemGrow(pMem, nByte, 1) ){ return SQLITE_NOMEM_BKPT; } + assert( pMem->z!=0 ); + assert( sqlite3DbMallocSize(pMem->db,pMem->z) >= nByte ); memset(&pMem->z[pMem->n], 0, pMem->u.nZero); pMem->n += pMem->u.nZero;@@ -77380,6 +79074,7 @@ /*
** Make sure the given Mem is \u0000 terminated. */ SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem *pMem){ + assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); testcase( (pMem->flags & (MEM_Term|MEM_Str))==(MEM_Term|MEM_Str) ); testcase( (pMem->flags & (MEM_Term|MEM_Str))==0 );@@ -77407,6 +79102,7 @@ */
SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){ const int nByte = 32; + assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( !(pMem->flags&MEM_Zero) ); assert( !(pMem->flags&(MEM_Str|MEM_Blob)) );@@ -77442,9 +79138,11 @@ SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
sqlite3_context ctx; Mem t; assert( pFunc!=0 ); + assert( pMem!=0 ); + assert( pMem->db!=0 ); assert( pFunc->xFinalize!=0 ); assert( (pMem->flags & MEM_Null)!=0 || pFunc==pMem->u.pDef ); - assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); + assert( sqlite3_mutex_held(pMem->db->mutex) ); memset(&ctx, 0, sizeof(ctx)); memset(&t, 0, sizeof(t)); t.flags = MEM_Null;@@ -77452,6 +79150,7 @@ t.db = pMem->db;
ctx.pOut = &t; ctx.pMem = pMem; ctx.pFunc = pFunc; + ctx.enc = ENC(t.db); pFunc->xFinalize(&ctx); /* IMP: R-24505-23230 */ assert( (pMem->flags & MEM_Dyn)==0 ); if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc);@@ -77473,12 +79172,14 @@ sqlite3_context ctx;
assert( pFunc!=0 ); assert( pFunc->xValue!=0 ); assert( (pAccum->flags & MEM_Null)!=0 || pFunc==pAccum->u.pDef ); - assert( pAccum->db==0 || sqlite3_mutex_held(pAccum->db->mutex) ); + assert( pAccum->db!=0 ); + assert( sqlite3_mutex_held(pAccum->db->mutex) ); memset(&ctx, 0, sizeof(ctx)); sqlite3VdbeMemSetNull(pOut); ctx.pOut = pOut; ctx.pMem = pAccum; ctx.pFunc = pFunc; + ctx.enc = ENC(pAccum->db); pFunc->xValue(&ctx); return ctx.isError; }@@ -77544,6 +79245,14 @@ vdbeMemClear(p);
} } +/* Like sqlite3VdbeMemRelease() but faster for cases where we +** know in advance that the Mem is not MEM_Dyn or MEM_Agg. +*/ +SQLITE_PRIVATE void sqlite3VdbeMemReleaseMalloc(Mem *p){ + assert( !VdbeMemDynamic(p) ); + if( p->szMalloc ) vdbeMemClear(p); +} + /* ** Convert a 64-bit IEEE double into a 64-bit signed integer. ** If the double is out of range of a 64-bit signed integer then@@ -77585,13 +79294,14 @@ ** an SQL-NULL value, return 0.
** ** If pMem represents a string value, its encoding might be changed. */ -static SQLITE_NOINLINE i64 memIntValue(Mem *pMem){ +static SQLITE_NOINLINE i64 memIntValue(const Mem *pMem){ i64 value = 0; sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc); return value; } -SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem *pMem){ +SQLITE_PRIVATE i64 sqlite3VdbeIntValue(const Mem *pMem){ int flags; + assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); flags = pMem->flags;@@ -77620,6 +79330,7 @@ sqlite3AtoF(pMem->z, &val, pMem->n, pMem->enc);
return val; } SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){ + assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); if( pMem->flags & MEM_Real ){@@ -77652,6 +79363,7 @@ ** MEM_Int if we can.
*/ SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem *pMem){ i64 ix; + assert( pMem!=0 ); assert( pMem->flags & MEM_Real ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );@@ -77679,6 +79391,7 @@ /*
** Convert pMem to type integer. Invalidate any prior representations. */ SQLITE_PRIVATE int sqlite3VdbeMemIntegerify(Mem *pMem){ + assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) );@@ -77693,6 +79406,7 @@ ** Convert pMem so that it is of type MEM_Real.
** Invalidate any prior representations. */ SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem *pMem){ + assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) );@@ -77726,6 +79440,7 @@ ** is a string that does not look completely like a number. Convert
** as much of the string as we can and ignore the rest. */ SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){ + assert( pMem!=0 ); testcase( pMem->flags & MEM_Int ); testcase( pMem->flags & MEM_Real ); testcase( pMem->flags & MEM_IntReal );@@ -77835,6 +79550,7 @@ /*
** Delete any previous value and set the value to be a BLOB of length ** n containing all zeros. */ +#ifndef SQLITE_OMIT_INCRBLOB SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){ sqlite3VdbeMemRelease(pMem); pMem->flags = MEM_Blob|MEM_Zero;@@ -77844,6 +79560,21 @@ pMem->u.nZero = n;
pMem->enc = SQLITE_UTF8; pMem->z = 0; } +#else +SQLITE_PRIVATE int sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){ + int nByte = n>0?n:1; + if( sqlite3VdbeMemGrow(pMem, nByte, 0) ){ + return SQLITE_NOMEM_BKPT; + } + assert( pMem->z!=0 ); + assert( sqlite3DbMallocSize(pMem->db, pMem->z)>=nByte ); + memset(pMem->z, 0, nByte); + pMem->n = n>0?n:0; + pMem->flags = MEM_Blob; + pMem->enc = SQLITE_UTF8; + return SQLITE_OK; +} +#endif /* ** The pMem is known to contain content that needs to be destroyed prior@@ -77883,6 +79614,7 @@ const char *zPType,
void (*xDestructor)(void*) ){ assert( pMem->flags==MEM_Null ); + vdbeMemClear(pMem); pMem->u.zPType = zPType ? zPType : ""; pMem->z = pPtr; pMem->flags = MEM_Null|MEM_Dyn|MEM_Subtype|MEM_Term;@@ -78065,6 +79797,13 @@ ** size limit) then no memory allocation occurs. If the string can be
** stored without allocating memory, then it is. If a memory allocation ** is required to store the string, then value of pMem is unchanged. In ** either case, SQLITE_TOOBIG is returned. +** +** The "enc" parameter is the text encoding for the string, or zero +** to store a blob. +** +** If n is negative, then the string consists of all bytes up to but +** excluding the first zero character. The n parameter must be +** non-negative for blobs. */ SQLITE_PRIVATE int sqlite3VdbeMemSetStr( Mem *pMem, /* Memory cell to set to string value */@@ -78075,10 +79814,12 @@ void (*xDel)(void*) /* Destructor function */
){ i64 nByte = n; /* New value for pMem->n */ int iLimit; /* Maximum allowed string or blob size */ - u16 flags = 0; /* New value for pMem->flags */ + u16 flags; /* New value for pMem->flags */ + assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); + assert( enc!=0 || n>=0 ); /* If z is a NULL pointer, set pMem to contain an SQL NULL. */ if( !z ){@@ -78091,7 +79832,6 @@ iLimit = pMem->db->aLimit[SQLITE_LIMIT_LENGTH];
}else{ iLimit = SQLITE_MAX_LENGTH; } - flags = (enc==0?MEM_Blob:MEM_Str); if( nByte<0 ){ assert( enc!=0 ); if( enc==SQLITE_UTF8 ){@@ -78099,7 +79839,23 @@ nByte = strlen(z);
}else{ for(nByte=0; nByte<=iLimit && (z[nByte] | z[nByte+1]); nByte+=2){} } - flags |= MEM_Term; + flags= MEM_Str|MEM_Term; + }else if( enc==0 ){ + flags = MEM_Blob; + enc = SQLITE_UTF8; + }else{ + flags = MEM_Str; + } + if( nByte>iLimit ){ + if( xDel && xDel!=SQLITE_TRANSIENT ){ + if( xDel==SQLITE_DYNAMIC ){ + sqlite3DbFree(pMem->db, (void*)z); + }else{ + xDel((void*)z); + } + } + sqlite3VdbeMemSetNull(pMem); + return sqlite3ErrorToParser(pMem->db, SQLITE_TOOBIG); } /* The following block sets the new values of Mem.z and Mem.xDel. It@@ -78110,9 +79866,6 @@ if( xDel==SQLITE_TRANSIENT ){
i64 nAlloc = nByte; if( flags&MEM_Term ){ nAlloc += (enc==SQLITE_UTF8?1:2); - } - if( nByte>iLimit ){ - return sqlite3ErrorToParser(pMem->db, SQLITE_TOOBIG); } testcase( nAlloc==0 ); testcase( nAlloc==31 );@@ -78135,16 +79888,7 @@ }
pMem->n = (int)(nByte & 0x7fffffff); pMem->flags = flags; - if( enc ){ - pMem->enc = enc; -#ifdef SQLITE_ENABLE_SESSION - }else if( pMem->db==0 ){ - pMem->enc = SQLITE_UTF8; -#endif - }else{ - assert( pMem->db!=0 ); - pMem->enc = ENC(pMem->db); - } + pMem->enc = enc; #ifndef SQLITE_OMIT_UTF16 if( enc>SQLITE_UTF8 && sqlite3VdbeMemHandleBom(pMem) ){@@ -78152,9 +79896,6 @@ return SQLITE_NOMEM_BKPT;
} #endif - if( nByte>iLimit ){ - return sqlite3ErrorToParser(pMem->db, SQLITE_TOOBIG); - } return SQLITE_OK; }@@ -78385,7 +80126,7 @@ */
#ifdef SQLITE_ENABLE_STAT4 static int valueFromFunction( sqlite3 *db, /* The database connection */ - Expr *p, /* The expression to evaluate */ + const Expr *p, /* The expression to evaluate */ u8 enc, /* Encoding to use */ u8 aff, /* Affinity to use */ sqlite3_value **ppVal, /* Write the new value here */@@ -78402,8 +80143,10 @@ int i; /* Iterator variable */
assert( pCtx!=0 ); assert( (p->flags & EP_TokenOnly)==0 ); + assert( ExprUseXList(p) ); pList = p->x.pList; if( pList ) nVal = pList->nExpr; + assert( !ExprHasProperty(p, EP_IntValue) ); pFunc = sqlite3FindFunction(db, p->u.zToken, nVal, enc, 0); assert( pFunc ); if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0@@ -78430,10 +80173,12 @@ rc = SQLITE_NOMEM_BKPT;
goto value_from_function_out; } - assert( pCtx->pParse->rc==SQLITE_OK ); + testcase( pCtx->pParse->rc==SQLITE_ERROR ); + testcase( pCtx->pParse->rc==SQLITE_OK ); memset(&ctx, 0, sizeof(ctx)); ctx.pOut = pVal; ctx.pFunc = pFunc; + ctx.enc = ENC(db); pFunc->xSFunc(&ctx, nVal, apVal); if( ctx.isError ){ rc = ctx.isError;@@ -78479,7 +80224,7 @@ ** in all cases.
*/ static int valueFromExpr( sqlite3 *db, /* The database connection */ - Expr *pExpr, /* The expression to evaluate */ + const Expr *pExpr, /* The expression to evaluate */ u8 enc, /* Encoding to use */ u8 affinity, /* Affinity to use */ sqlite3_value **ppVal, /* Write the new value here */@@ -78494,11 +80239,7 @@ int rc = SQLITE_OK;
assert( pExpr!=0 ); while( (op = pExpr->op)==TK_UPLUS || op==TK_SPAN ) pExpr = pExpr->pLeft; -#if defined(SQLITE_ENABLE_STAT4) if( op==TK_REGISTER ) op = pExpr->op2; -#else - if( NEVER(op==TK_REGISTER) ) op = pExpr->op2; -#endif /* Compressed expressions only appear when parsing the DEFAULT clause ** on a table column definition, and hence only when pCtx==0. This@@ -78507,12 +80248,14 @@ ** into valueFromFunction(). */
assert( (pExpr->flags & EP_TokenOnly)==0 || pCtx==0 ); if( op==TK_CAST ){ - u8 aff = sqlite3AffinityType(pExpr->u.zToken,0); + u8 aff; + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + aff = sqlite3AffinityType(pExpr->u.zToken,0); rc = valueFromExpr(db, pExpr->pLeft, enc, aff, ppVal, pCtx); testcase( rc!=SQLITE_OK ); if( *ppVal ){ - sqlite3VdbeMemCast(*ppVal, aff, SQLITE_UTF8); - sqlite3ValueApplyAffinity(*ppVal, affinity, SQLITE_UTF8); + sqlite3VdbeMemCast(*ppVal, aff, enc); + sqlite3ValueApplyAffinity(*ppVal, affinity, enc); } return rc; }@@ -78580,6 +80323,7 @@ }
#ifndef SQLITE_OMIT_BLOB_LITERAL else if( op==TK_BLOB ){ int nVal; + assert( !ExprHasProperty(pExpr, EP_IntValue) ); assert( pExpr->u.zToken[0]=='x' || pExpr->u.zToken[0]=='X' ); assert( pExpr->u.zToken[1]=='\'' ); pVal = valueNew(db, pCtx);@@ -78597,6 +80341,7 @@ rc = valueFromFunction(db, pExpr, enc, affinity, &pVal, pCtx);
} #endif else if( op==TK_TRUEFALSE ){ + assert( !ExprHasProperty(pExpr, EP_IntValue) ); pVal = valueNew(db, pCtx); if( pVal ){ pVal->flags = MEM_Int;@@ -78609,7 +80354,7 @@ return rc;
no_mem: #ifdef SQLITE_ENABLE_STAT4 - if( pCtx==0 || pCtx->pParse->nErr==0 ) + if( pCtx==0 || NEVER(pCtx->pParse->nErr==0) ) #endif sqlite3OomFault(db); sqlite3DbFree(db, zVal);@@ -78634,7 +80379,7 @@ ** cannot be converted to a value, then *ppVal is set to NULL.
*/ SQLITE_PRIVATE int sqlite3ValueFromExpr( sqlite3 *db, /* The database connection */ - Expr *pExpr, /* The expression to evaluate */ + const Expr *pExpr, /* The expression to evaluate */ u8 enc, /* Encoding to use */ u8 affinity, /* Affinity to use */ sqlite3_value **ppVal /* Write the new value here */@@ -78944,7 +80689,7 @@ }
p->pNext = db->pVdbe; p->pPrev = 0; db->pVdbe = p; - p->iVdbeMagic = VDBE_MAGIC_INIT; + assert( p->eVdbeState==VDBE_INIT_STATE ); p->pParse = pParse; pParse->pVdbe = p; assert( pParse->aLabel==0 );@@ -79089,7 +80834,7 @@ sqlite3OomFault(p->db);
return SQLITE_NOMEM; } - assert( nOp<=(1024/sizeof(Op)) ); + assert( nOp<=(int)(1024/sizeof(Op)) ); assert( nNew>=(v->nOpAlloc+nOp) ); pNew = sqlite3DbRealloc(p->db, v->aOp, nNew*sizeof(Op)); if( pNew ){@@ -79145,13 +80890,15 @@ int i;
VdbeOp *pOp; i = p->nOp; - assert( p->iVdbeMagic==VDBE_MAGIC_INIT ); + assert( p->eVdbeState==VDBE_INIT_STATE ); assert( op>=0 && op<0xff ); if( p->nOpAlloc<=i ){ return growOp3(p, op, p1, p2, p3); } + assert( p->aOp!=0 ); p->nOp++; pOp = &p->aOp[i]; + assert( pOp!=0 ); pOp->opcode = (u8)op; pOp->p5 = 0; pOp->p1 = p1;@@ -79475,7 +81222,7 @@ }
SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe *v, int x){ Parse *p = v->pParse; int j = ADDR(x); - assert( v->iVdbeMagic==VDBE_MAGIC_INIT ); + assert( v->eVdbeState==VDBE_INIT_STATE ); assert( j<-p->nLabel ); assert( j>=0 ); #ifdef SQLITE_DEBUG@@ -79495,14 +81242,20 @@ /*
** Mark the VDBE as one that can only be run one time. */ SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe *p){ - p->runOnlyOnce = 1; + sqlite3VdbeAddOp2(p, OP_Expire, 1, 1); } /* -** Mark the VDBE as one that can only be run multiple times. +** Mark the VDBE as one that can be run multiple times. */ SQLITE_PRIVATE void sqlite3VdbeReusable(Vdbe *p){ - p->runOnlyOnce = 0; + int i; + for(i=1; ALWAYS(i<p->nOp); i++){ + if( ALWAYS(p->aOp[i].opcode==OP_Expire) ){ + p->aOp[1].opcode = OP_Noop; + break; + } + } } #ifdef SQLITE_DEBUG /* sqlite3AssertMayAbort() logic */@@ -79606,6 +81359,8 @@ int hasCreateIndex = 0;
int hasInitCoroutine = 0; Op *pOp; VdbeOpIter sIter; + + if( v==0 ) return 0; memset(&sIter, 0, sizeof(sIter)); sIter.v = v;@@ -79689,7 +81444,7 @@ **
** (3) Update the Vdbe.readOnly and Vdbe.bIsReader flags to accurately ** indicate what the prepared statement actually does. ** -** (4) Initialize the p4.xAdvance pointer on opcodes that use it. +** (4) (discontinued) ** ** (5) Reclaim the memory allocated for storing labels. **@@ -79735,25 +81490,6 @@ p->readOnly = 0;
p->bIsReader = 1; break; } - case OP_Next: - case OP_SorterNext: { - pOp->p4.xAdvance = sqlite3BtreeNext; - pOp->p4type = P4_ADVANCE; - /* The code generator never codes any of these opcodes as a jump - ** to a label. They are always coded as a jump backwards to a - ** known address */ - assert( pOp->p2>=0 ); - break; - } - case OP_Prev: { - pOp->p4.xAdvance = sqlite3BtreePrevious; - pOp->p4type = P4_ADVANCE; - /* The code generator never codes any of these opcodes as a jump - ** to a label. They are always coded as a jump backwards to a - ** known address */ - assert( pOp->p2>=0 ); - break; - } #ifndef SQLITE_OMIT_VIRTUALTABLE case OP_VUpdate: { if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;@@ -79789,18 +81525,104 @@ }
if( pOp==p->aOp ) break; pOp--; } - sqlite3DbFree(p->db, pParse->aLabel); - pParse->aLabel = 0; + if( aLabel ){ + sqlite3DbFreeNN(p->db, pParse->aLabel); + pParse->aLabel = 0; + } pParse->nLabel = 0; *pMaxFuncArgs = nMaxArgs; assert( p->bIsReader!=0 || DbMaskAllZero(p->btreeMask) ); } +#ifdef SQLITE_DEBUG +/* +** Check to see if a subroutine contains a jump to a location outside of +** the subroutine. If a jump outside the subroutine is detected, add code +** that will cause the program to halt with an error message. +** +** The subroutine consists of opcodes between iFirst and iLast. Jumps to +** locations within the subroutine are acceptable. iRetReg is a register +** that contains the return address. Jumps to outside the range of iFirst +** through iLast are also acceptable as long as the jump destination is +** an OP_Return to iReturnAddr. +** +** A jump to an unresolved label means that the jump destination will be +** beyond the current address. That is normally a jump to an early +** termination and is consider acceptable. +** +** This routine only runs during debug builds. The purpose is (of course) +** to detect invalid escapes out of a subroutine. The OP_Halt opcode +** is generated rather than an assert() or other error, so that ".eqp full" +** will still work to show the original bytecode, to aid in debugging. +*/ +SQLITE_PRIVATE void sqlite3VdbeNoJumpsOutsideSubrtn( + Vdbe *v, /* The byte-code program under construction */ + int iFirst, /* First opcode of the subroutine */ + int iLast, /* Last opcode of the subroutine */ + int iRetReg /* Subroutine return address register */ +){ + VdbeOp *pOp; + Parse *pParse; + int i; + sqlite3_str *pErr = 0; + assert( v!=0 ); + pParse = v->pParse; + assert( pParse!=0 ); + if( pParse->nErr ) return; + assert( iLast>=iFirst ); + assert( iLast<v->nOp ); + pOp = &v->aOp[iFirst]; + for(i=iFirst; i<=iLast; i++, pOp++){ + if( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 ){ + int iDest = pOp->p2; /* Jump destination */ + if( iDest==0 ) continue; + if( pOp->opcode==OP_Gosub ) continue; + if( iDest<0 ){ + int j = ADDR(iDest); + assert( j>=0 ); + if( j>=-pParse->nLabel || pParse->aLabel[j]<0 ){ + continue; + } + iDest = pParse->aLabel[j]; + } + if( iDest<iFirst || iDest>iLast ){ + int j = iDest; + for(; j<v->nOp; j++){ + VdbeOp *pX = &v->aOp[j]; + if( pX->opcode==OP_Return ){ + if( pX->p1==iRetReg ) break; + continue; + } + if( pX->opcode==OP_Noop ) continue; + if( pX->opcode==OP_Explain ) continue; + if( pErr==0 ){ + pErr = sqlite3_str_new(0); + }else{ + sqlite3_str_appendchar(pErr, 1, '\n'); + } + sqlite3_str_appendf(pErr, + "Opcode at %d jumps to %d which is outside the " + "subroutine at %d..%d", + i, iDest, iFirst, iLast); + break; + } + } + } + } + if( pErr ){ + char *zErr = sqlite3_str_finish(pErr); + sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_INTERNAL, OE_Abort, 0, zErr, 0); + sqlite3_free(zErr); + sqlite3MayAbort(pParse); + } +} +#endif /* SQLITE_DEBUG */ + /* ** Return the address of the next instruction to be inserted. */ SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe *p){ - assert( p->iVdbeMagic==VDBE_MAGIC_INIT ); + assert( p->eVdbeState==VDBE_INIT_STATE ); return p->nOp; }@@ -79885,7 +81707,7 @@ ){
int i; VdbeOp *pOut, *pFirst; assert( nOp>0 ); - assert( p->iVdbeMagic==VDBE_MAGIC_INIT ); + assert( p->eVdbeState==VDBE_INIT_STATE ); if( p->nOp + nOp > p->nOpAlloc && growOpArray(p, nOp) ){ return 0; }@@ -80037,7 +81859,6 @@ }
case P4_REAL: case P4_INT64: case P4_DYNAMIC: - case P4_DYNBLOB: case P4_INTARRAY: { sqlite3DbFree(db, p4); break;@@ -80077,13 +81898,16 @@ ** opcodes contained within. If aOp is not NULL it is assumed to contain
** nOp entries. */ static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){ + assert( nOp>=0 ); if( aOp ){ - Op *pOp; - for(pOp=&aOp[nOp-1]; pOp>=aOp; pOp--){ + Op *pOp = &aOp[nOp-1]; + while(1){ /* Exit via break */ if( pOp->p4type <= P4_FREE_IF_LE ) freeP4(db, pOp->p4type, pOp->p4.p); #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS sqlite3DbFree(db, pOp->zComment); #endif + if( pOp==aOp ) break; + pOp--; } sqlite3DbFreeNN(db, aOp); }@@ -80145,7 +81969,7 @@ int N, /* Number of registers to release */
u32 mask, /* Mask of registers to NOT release */ int bUndefine /* If true, mark registers as undefined */ ){ - if( N==0 ) return; + if( N==0 || OptimizationDisabled(pParse->db, SQLITE_ReleaseReg) ) return; assert( pParse->pVdbe ); assert( iFirst>=1 ); assert( iFirst+N-1<=pParse->nMem );@@ -80209,7 +82033,7 @@ Op *pOp;
sqlite3 *db; assert( p!=0 ); db = p->db; - assert( p->iVdbeMagic==VDBE_MAGIC_INIT ); + assert( p->eVdbeState==VDBE_INIT_STATE ); assert( p->aOp!=0 || db->mallocFailed ); if( db->mallocFailed ){ if( n!=P4_VTAB ) freeP4(db, n, (void*)*(char**)&zP4);@@ -80285,8 +82109,7 @@ ** in a production build.
*/ static void vdbeVComment(Vdbe *p, const char *zFormat, va_list ap){ assert( p->nOp>0 || p->aOp==0 ); - assert( p->aOp==0 || p->aOp[p->nOp-1].zComment==0 || p->db->mallocFailed - || p->pParse->nErr>0 ); + assert( p->aOp==0 || p->aOp[p->nOp-1].zComment==0 || p->pParse->nErr>0 ); if( p->nOp ){ assert( p->aOp ); sqlite3DbFree(p->db, p->aOp[p->nOp-1].zComment);@@ -80338,7 +82161,7 @@ SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
/* C89 specifies that the constant "dummy" will be initialized to all ** zeros, which is correct. MSVC generates a warning, nevertheless. */ static VdbeOp dummy; /* Ignore the MSVC warning about no initializer */ - assert( p->iVdbeMagic==VDBE_MAGIC_INIT ); + assert( p->eVdbeState==VDBE_INIT_STATE ); if( addr<0 ){ addr = p->nOp - 1; }@@ -80394,7 +82217,7 @@ nOpName = sqlite3Strlen30(zOpName);
if( zOpName[nOpName+1] ){ int seenCom = 0; char c; - zSynopsis = zOpName += nOpName + 1; + zSynopsis = zOpName + nOpName + 1; if( strncmp(zSynopsis,"IF ",3)==0 ){ sqlite3_snprintf(sizeof(zAlt), zAlt, "if %s goto P2", zSynopsis+3); zSynopsis = zAlt;@@ -80405,8 +82228,11 @@ c = zSynopsis[++ii];
if( c=='4' ){ sqlite3_str_appendall(&x, zP4); }else if( c=='X' ){ - sqlite3_str_appendall(&x, pOp->zComment); - seenCom = 1; + if( pOp->zComment && pOp->zComment[0] ){ + sqlite3_str_appendall(&x, pOp->zComment); + seenCom = 1; + break; + } }else{ int v1 = translateP(c, pOp); int v2;@@ -80467,6 +82293,7 @@ static void displayP4Expr(StrAccum *p, Expr *pExpr){
const char *zOp = 0; switch( pExpr->op ){ case TK_STRING: + assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3_str_appendf(p, "%Q", pExpr->u.zToken); break; case TK_INTEGER:@@ -80569,7 +82396,7 @@ #endif
case P4_COLLSEQ: { static const char *const encnames[] = {"?", "8", "16LE", "16BE"}; CollSeq *pColl = pOp->p4.pColl; - assert( pColl->enc>=0 && pColl->enc<4 ); + assert( pColl->enc<4 ); sqlite3_str_appendf(&x, "%.18s-%s", pColl->zName, encnames[pColl->enc]); break;@@ -80634,10 +82461,6 @@ case P4_SUBPROGRAM: {
zP4 = "program"; break; } - case P4_DYNBLOB: - case P4_ADVANCE: { - break; - } case P4_TABLE: { zP4 = pOp->p4.pTab->zName; break;@@ -80769,21 +82592,40 @@ #endif
/* ** Initialize an array of N Mem element. +** +** This is a high-runner, so only those fields that really do need to +** be initialized are set. The Mem structure is organized so that +** the fields that get initialized are nearby and hopefully on the same +** cache line. +** +** Mem.flags = flags +** Mem.db = db +** Mem.szMalloc = 0 +** +** All other fields of Mem can safely remain uninitialized for now. They +** will be initialized before use. */ static void initMemArray(Mem *p, int N, sqlite3 *db, u16 flags){ - while( (N--)>0 ){ - p->db = db; - p->flags = flags; - p->szMalloc = 0; + if( N>0 ){ + do{ + p->flags = flags; + p->db = db; + p->szMalloc = 0; #ifdef SQLITE_DEBUG - p->pScopyFrom = 0; + p->pScopyFrom = 0; #endif - p++; + p++; + }while( (--N)>0 ); } } /* -** Release an array of N Mem elements +** Release auxiliary memory held in an array of N Mem elements. +** +** After this routine returns, all Mem elements in the array will still +** be valid. Those Mem elements that were not holding auxiliary resources +** will be unchanged. Mem elements which had something freed will be +** set to MEM_Undefined. */ static void releaseMemArray(Mem *p, int N){ if( p && N ){@@ -80813,15 +82655,20 @@ ** and reset(). Inserts are grouped into a transaction.
*/ testcase( p->flags & MEM_Agg ); testcase( p->flags & MEM_Dyn ); - testcase( p->xDel==sqlite3VdbeFrameMemDel ); if( p->flags&(MEM_Agg|MEM_Dyn) ){ + testcase( (p->flags & MEM_Dyn)!=0 && p->xDel==sqlite3VdbeFrameMemDel ); sqlite3VdbeMemRelease(p); + p->flags = MEM_Undefined; }else if( p->szMalloc ){ sqlite3DbFreeNN(db, p->zMalloc); p->szMalloc = 0; + p->flags = MEM_Undefined; } - - p->flags = MEM_Undefined; +#ifdef SQLITE_DEBUG + else{ + p->flags = MEM_Undefined; + } +#endif }while( (++p)<pEnd ); } }@@ -80980,7 +82827,7 @@ Mem *aMem = VdbeFrameMem(p);
VdbeCursor **apCsr = (VdbeCursor **)&aMem[p->nChildMem]; assert( sqlite3VdbeFrameIsValid(p) ); for(i=0; i<p->nChildCsr; i++){ - sqlite3VdbeFreeCursor(p->v, apCsr[i]); + if( apCsr[i] ) sqlite3VdbeFreeCursorNN(p->v, apCsr[i]); } releaseMemArray(aMem, p->nChildMem); sqlite3VdbeDeleteAuxData(p->v->db, &p->pAuxData, -1, 0);@@ -81019,7 +82866,7 @@ Op *aOp; /* Array of opcodes */
Op *pOp; /* Current opcode */ assert( p->explain ); - assert( p->iVdbeMagic==VDBE_MAGIC_RUN ); + assert( p->eVdbeState==VDBE_RUN_STATE ); assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY || p->rc==SQLITE_NOMEM ); /* Even though this opcode does not use dynamic strings for@@ -81174,11 +83021,11 @@ */
static void *allocSpace( struct ReusableSpace *p, /* Bulk memory available for allocation */ void *pBuf, /* Pointer to a prior allocation */ - sqlite3_int64 nByte /* Bytes of memory needed */ + sqlite3_int64 nByte /* Bytes of memory needed. */ ){ assert( EIGHT_BYTE_ALIGNMENT(p->pSpace) ); if( pBuf==0 ){ - nByte = ROUND8(nByte); + nByte = ROUND8P(nByte); if( nByte <= p->nFree ){ p->nFree -= nByte; pBuf = &p->pSpace[p->nFree];@@ -81199,14 +83046,15 @@ #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
int i; #endif assert( p!=0 ); - assert( p->iVdbeMagic==VDBE_MAGIC_INIT || p->iVdbeMagic==VDBE_MAGIC_RESET ); + assert( p->eVdbeState==VDBE_INIT_STATE + || p->eVdbeState==VDBE_READY_STATE + || p->eVdbeState==VDBE_HALT_STATE ); /* There should be at least one opcode. */ assert( p->nOp>0 ); - /* Set the magic to VDBE_MAGIC_RUN sooner rather than later. */ - p->iVdbeMagic = VDBE_MAGIC_RUN; + p->eVdbeState = VDBE_READY_STATE; #ifdef SQLITE_DEBUG for(i=0; i<p->nMem; i++){@@ -81262,7 +83110,7 @@
assert( p!=0 ); assert( p->nOp>0 ); assert( pParse!=0 ); - assert( p->iVdbeMagic==VDBE_MAGIC_INIT ); + assert( p->eVdbeState==VDBE_INIT_STATE ); assert( pParse==p->pParse ); p->pVList = pParse->pVList; pParse->pVList = 0;@@ -81285,7 +83133,7 @@ /* Figure out how much reusable memory is available at the end of the
** opcode array. This extra memory will be reallocated for other elements ** of the prepared statement. */ - n = ROUND8(sizeof(Op)*p->nOp); /* Bytes of opcode memory used */ + n = ROUND8P(sizeof(Op)*p->nOp); /* Bytes of opcode memory used */ x.pSpace = &((u8*)p->aOp)[n]; /* Unused opcode memory */ assert( EIGHT_BYTE_ALIGNMENT(x.pSpace) ); x.nFree = ROUNDDOWN8(pParse->szOpAlloc - n); /* Bytes of unused memory */@@ -81373,11 +83221,9 @@ ** Close a VDBE cursor and release all the resources that cursor
** happens to hold. */ SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){ - if( pCx==0 ){ - return; - } - assert( pCx->pBtx==0 || pCx->eCurType==CURTYPE_BTREE ); - assert( pCx->pBtx==0 || pCx->isEphemeral ); + if( pCx ) sqlite3VdbeFreeCursorNN(p,pCx); +} +SQLITE_PRIVATE void sqlite3VdbeFreeCursorNN(Vdbe *p, VdbeCursor *pCx){ switch( pCx->eCurType ){ case CURTYPE_SORTER: { sqlite3VdbeSorterClose(p->db, pCx);@@ -81405,14 +83251,12 @@ /*
** Close all cursors in the current frame. */ static void closeCursorsInFrame(Vdbe *p){ - if( p->apCsr ){ - int i; - for(i=0; i<p->nCursor; i++){ - VdbeCursor *pC = p->apCsr[i]; - if( pC ){ - sqlite3VdbeFreeCursor(p, pC); - p->apCsr[i] = 0; - } + int i; + for(i=0; i<p->nCursor; i++){ + VdbeCursor *pC = p->apCsr[i]; + if( pC ){ + sqlite3VdbeFreeCursorNN(p, pC); + p->apCsr[i] = 0; } } }@@ -81461,9 +83305,7 @@ p->nFrame = 0;
} assert( p->nFrame==0 ); closeCursorsInFrame(p); - if( p->aMem ){ - releaseMemArray(p->aMem, p->nMem); - } + releaseMemArray(p->aMem, p->nMem); while( p->pDelFrame ){ VdbeFrame *pDel = p->pDelFrame; p->pDelFrame = pDel->pParent;@@ -81903,7 +83745,8 @@ ){
p->rc = SQLITE_CONSTRAINT_FOREIGNKEY; p->errorAction = OE_Abort; sqlite3VdbeError(p, "FOREIGN KEY constraint failed"); - return SQLITE_ERROR; + if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)==0 ) return SQLITE_ERROR; + return SQLITE_CONSTRAINT_FOREIGNKEY; } return SQLITE_OK; }@@ -81914,9 +83757,9 @@ ** This routine is called the when a VDBE tries to halt. If the VDBE
** has made changes and is in autocommit mode, then commit those ** changes. If a rollback is needed, then do the rollback. ** -** This routine is the only way to move the state of a VM from -** SQLITE_MAGIC_RUN to SQLITE_MAGIC_HALT. It is harmless to -** call this on a VM that is in the SQLITE_MAGIC_HALT state. +** This routine is the only way to move the sqlite3eOpenState of a VM from +** SQLITE_STATE_RUN to SQLITE_STATE_HALT. It is harmless to +** call this on a VM that is in the SQLITE_STATE_HALT state. ** ** Return an error code. If the commit could not complete because of ** lock contention, return SQLITE_BUSY. If SQLITE_BUSY is returned, it@@ -81942,9 +83785,7 @@ ** state. We need to rollback the statement transaction, if there is
** one, or the complete transaction if there is no statement transaction. */ - if( p->iVdbeMagic!=VDBE_MAGIC_RUN ){ - return SQLITE_OK; - } + assert( p->eVdbeState==VDBE_RUN_STATE ); if( db->mallocFailed ){ p->rc = SQLITE_NOMEM_BKPT; }@@ -81953,7 +83794,7 @@ checkActiveVdbeCnt(db);
/* No commit or rollback needed if the program never started or if the ** SQL statement does not read or write a database file. */ - if( p->pc>=0 && p->bIsReader ){ + if( p->bIsReader ){ int mrc; /* Primary error code from p->rc */ int eStatementOp = 0; int isSpecialError; /* Set to true if a 'special' error */@@ -81962,9 +83803,15 @@ /* Lock all btrees used by the statement */
sqlite3VdbeEnter(p); /* Check for one of the special errors */ - mrc = p->rc & 0xff; - isSpecialError = mrc==SQLITE_NOMEM || mrc==SQLITE_IOERR - || mrc==SQLITE_INTERRUPT || mrc==SQLITE_FULL; + if( p->rc ){ + mrc = p->rc & 0xff; + isSpecialError = mrc==SQLITE_NOMEM + || mrc==SQLITE_IOERR + || mrc==SQLITE_INTERRUPT + || mrc==SQLITE_FULL; + }else{ + mrc = isSpecialError = 0; + } if( isSpecialError ){ /* If the query was read-only and the error code is SQLITE_INTERRUPT, ** no rollback is necessary. Otherwise, at least a savepoint@@ -82016,6 +83863,9 @@ sqlite3VdbeLeave(p);
return SQLITE_ERROR; } rc = SQLITE_CONSTRAINT_FOREIGNKEY; + }else if( db->flags & SQLITE_CorruptRdOnly ){ + rc = SQLITE_CORRUPT; + db->flags &= ~SQLITE_CorruptRdOnly; }else{ /* The auto-commit flag is true, the vdbe program was successful ** or hit an 'OR FAIL' constraint and there are no deferred foreign@@ -82092,15 +83942,13 @@ sqlite3VdbeLeave(p);
} /* We have successfully halted and closed the VM. Record this fact. */ - if(