Move MatterControl source code into a subdirectory
This commit is contained in:
parent
2c6e34243a
commit
70af2d9ae8
2007 changed files with 13 additions and 8 deletions
23
original/.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
23
original/.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Report a bug in MatterControl
|
||||
|
||||
---
|
||||
|
||||
Bug Report
|
||||
============
|
||||
**Steps to Reproduce**
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
**Expected Behavior**
|
||||
|
||||
**Actual Behavior**
|
||||
|
||||
**MatterControl Build Number**
|
||||
(To find this, go to the MatterControl menu in the top left and click "About MatterControl")
|
||||
|
||||
**Operating System Version**
|
||||
|
||||
**Printer Make/Model**
|
||||
14
original/.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
14
original/.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for MatterControl
|
||||
|
||||
---
|
||||
|
||||
Feature Request
|
||||
===============
|
||||
|
||||
**Problem**
|
||||
Describe the problem you feel needs to be solved.
|
||||
|
||||
**Solution**
|
||||
Explain how this feature will solve the problem.
|
||||
29
original/.github/ISSUE_TEMPLATE/submit_profile.md
vendored
Normal file
29
original/.github/ISSUE_TEMPLATE/submit_profile.md
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
---
|
||||
name: Submit Profile
|
||||
about: Send us a profile you have created to recieve $15 MatterHackers store credit. Profile must be a new, not currently part of MatterControl.
|
||||
|
||||
|
||||
---
|
||||
|
||||
Profile Information
|
||||
===============
|
||||
|
||||
**Printer**
|
||||
|
||||
Describe the printer you are uploading a profile for.
|
||||
- Make:
|
||||
- Model:
|
||||
|
||||
**Outstanding Issues**
|
||||
|
||||
Explain any issues that this profile still has that might impact a new user.
|
||||
|
||||
-
|
||||
-
|
||||
|
||||
|
||||
NEXT STEPS:
|
||||
|
||||
After you create this issue; send an email to support@matterhackers.com with its issue number. If your profile is accepted we will send you a $15 gift code for MatterHackers.com. Profiles must be complete, not currently part of MatterContol and have some market demand. Approval will be at the sole discretion of MatterHackers.
|
||||
|
||||
You can find more information at: https://forums.matterhackers.com/topic/7467/creating-new-profiles
|
||||
15
original/.github/ISSUE_TEMPLATE/support-question.md
vendored
Normal file
15
original/.github/ISSUE_TEMPLATE/support-question.md
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
name: Support Question
|
||||
about: Questions about using MatterControl
|
||||
|
||||
---
|
||||
|
||||
Question
|
||||
========
|
||||
|
||||
<!-- 🚨 STOP 🚨 𝗦𝗧𝗢𝗣 🚨 𝑺𝑻𝑶𝑷 🚨 -->
|
||||
|
||||
This issue tracker is for our MatterControl development team and they are not in a position to answer support questions.
|
||||
|
||||
If you have a question about using MatterControl, please ask it on the MatterControl forums.
|
||||
https://forums.matterhackers.com/category/20/mattercontrol
|
||||
6
original/.travis.yml
Normal file
6
original/.travis.yml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
language: csharp
|
||||
solution: MatterControl.sln
|
||||
mono: latest
|
||||
script:
|
||||
- nuget restore MatterControl.sln
|
||||
- msbuild MatterControl.sln
|
||||
33
original/CONTRIBUTING.md
Normal file
33
original/CONTRIBUTING.md
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
Contributing to MatterControl on Github
|
||||
=======================================
|
||||
|
||||
Github is a place for developer discussion. If you have a question or need help using MatterControl, please either post on the [MatterControl Forum](http://forums.matterhackers.com/category/20/mattercontrol) or send an email to support@matterhackers.com. If you are unsure if the problem you are having is really a bug, then send us an email. We will be happy to investigate and file a bug report if necessary.
|
||||
|
||||
This is not the place for rants or abusive posts. We welcome constructive criticism, but if you feel the need to vent, please do it elsewhere.
|
||||
|
||||
Bug Reports
|
||||
-----------
|
||||
|
||||
* If you have never filed a bug report for software before, [read this](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html).
|
||||
* Reports should only deal with a single bug at a time. Do not submit a laundry list of issues.
|
||||
* Search for existing bugs before posting. Be sure to search for closed issues as well. If your issue is already known to us, it will be marked as a duplicate and closed.
|
||||
* Use correct English and read your post aloud to yourself before submitting it. Avoid inflamatory language.
|
||||
* Please use a clear descriptive title.
|
||||
* Examples of good titles:
|
||||
* "Can't close MC without stopping print from SD Card"
|
||||
* "Add support for Monoprice Maker Select Mini firmware"
|
||||
* Examples of bad titles:
|
||||
* "This product is bad and you should feel bad"
|
||||
* Include clear step by step instructions to reproduce the issue. Remember, **the developers cannot fix the bug if we cannot get it to happen ourselves**.
|
||||
* Include a screenshot of the problem, if applicable.
|
||||
* Please attach a .zip to your issue with any applicable diagnostic files. See the wiki article on [gathering diagnostic information](http://wiki.mattercontrol.com/Send_Debugging_Information). These might include...
|
||||
* Crash Logs
|
||||
* .stl files
|
||||
* .gcode files
|
||||
* Exported slice settings (.printer file)
|
||||
* Print Logs
|
||||
|
||||
Feature Requests
|
||||
----------------
|
||||
|
||||
Feature requests are welcome. But take a moment to find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Please provide as much detail and context as possible.
|
||||
121
original/CSharpSerialPortWrapper.cs
Normal file
121
original/CSharpSerialPortWrapper.cs
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
Copyright (c) 2019, Kevin Pope, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO.Ports;
|
||||
|
||||
namespace MatterHackers.SerialPortCommunication.FrostedSerial
|
||||
{
|
||||
public class CSharpSerialPortWrapper : IFrostedSerialPort
|
||||
{
|
||||
private SerialPort port;
|
||||
|
||||
public CSharpSerialPortWrapper(string serialPortName)
|
||||
{
|
||||
if (FrostedSerialPortFactory.GetAppropriateFactory("RepRap").IsWindows)
|
||||
{
|
||||
try
|
||||
{
|
||||
SerialPortFixer.Execute(serialPortName);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
port = new SerialPort(serialPortName);
|
||||
}
|
||||
|
||||
public int ReadTimeout
|
||||
{
|
||||
get => port.ReadTimeout;
|
||||
set => port.ReadTimeout = value;
|
||||
}
|
||||
|
||||
public int WriteTimeout
|
||||
{
|
||||
get => port.WriteTimeout;
|
||||
set => port.WriteTimeout = value;
|
||||
}
|
||||
|
||||
public int BaudRate
|
||||
{
|
||||
get => port.BaudRate;
|
||||
set => port.BaudRate = value;
|
||||
}
|
||||
|
||||
public bool RtsEnable
|
||||
{
|
||||
get => port.RtsEnable;
|
||||
set => port.RtsEnable = value;
|
||||
}
|
||||
|
||||
public bool DtrEnable
|
||||
{
|
||||
get => port.DtrEnable;
|
||||
set => port.DtrEnable = value;
|
||||
}
|
||||
|
||||
public string ReadExisting() => port.ReadExisting();
|
||||
|
||||
public int BytesToRead => port.BytesToRead;
|
||||
|
||||
public void Dispose() => port.Dispose();
|
||||
|
||||
public bool IsOpen => port.IsOpen;
|
||||
|
||||
public void Open() => port.Open();
|
||||
|
||||
public void Close()
|
||||
{
|
||||
try
|
||||
{
|
||||
port.Close();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(string str)
|
||||
{
|
||||
port.Write(str);
|
||||
}
|
||||
|
||||
public void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
port.Write(buffer, offset, count);
|
||||
}
|
||||
|
||||
public int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return port.Read(buffer, offset, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<Company>MatterHackers Inc.</Company>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<ReleaseVersion>2.20.12</ReleaseVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DefineConstants>TRACE;DEBUG;SQLITE_DEBUG TRUE WIN32 _MSC_VER NO_TCL SQLITE_ASCII SQLITE_DISABLE_LFS SQLITE_HAS_CODEC SQLITE_MEM_POOL SQLITE_MUTEX_W32 SQLITE_THREADSAFE SQLITE_OMIT_AUTHORIZATION SQLITE_OMIT_DEPRECATED SQLITE_OMIT_GET_TABLE SQLITE_OMIT_INCRBLOB SQLITE_OMIT_LOOKASIDE SQLITE_OMIT_SHARED_CACHE SQLITE_OMIT_UTF16 SQLITE_OMIT_WAL SQLITE_OS_WIN SQLITE_SYSTEM_MALLOC VDBE_PROFILE_OFF</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<DefineConstants>TRACE;TRUE WIN32 _MSC_VER NDEBUG NO_TCL SQLITE_ASCII SQLITE_DISABLE_LFS SQLITE_ENABLE_OVERSIZE_CELL_CHECK SQLITE_MUTEX_OMIT SQLITE_OMIT_AUTHORIZATION SQLITE_OMIT_DEPRECATED SQLITE_OMIT_GET_TABLE SQLITE_OMIT_INCRBLOB SQLITE_OMIT_LOOKASIDE SQLITE_OMIT_SHARED_CACHE SQLITE_OMIT_UTF16 SQLITE_OMIT_WAL SQLITE_OS_WIN SQLITE_SYSTEM_MALLOC VDBE_PROFILE_OFF</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Management" Version="7.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
20
original/Community.CsharpSqlite/Community.CsharpSqlite.sln
Normal file
20
original/Community.CsharpSqlite/Community.CsharpSqlite.sln
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 10.00
|
||||
# Visual Studio 2008
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Community.CsharpSqlite", "Community.CsharpSqlite.csproj", "{F1653F20-D47D-4F29-8C55-3C835542AF5F}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{F1653F20-D47D-4F29-8C55-3C835542AF5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F1653F20-D47D-4F29-8C55-3C835542AF5F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F1653F20-D47D-4F29-8C55-3C835542AF5F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F1653F20-D47D-4F29-8C55-3C835542AF5F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
850
original/Community.CsharpSqlite/src/BtreeInt_h.cs
Normal file
850
original/Community.CsharpSqlite/src/BtreeInt_h.cs
Normal file
|
|
@ -0,0 +1,850 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using i16 = System.Int16;
|
||||
using i64 = System.Int64;
|
||||
using Pgno = System.UInt32;
|
||||
|
||||
using sqlite3_int64 = System.Int64;
|
||||
|
||||
using u16 = System.UInt16;
|
||||
|
||||
using u32 = System.UInt32;
|
||||
|
||||
using u8 = System.Byte;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
using DbPage = Sqlite3.PgHdr;
|
||||
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2004 April 6
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This file implements a external (disk-based) database using BTrees.
|
||||
** For a detailed discussion of BTrees, refer to
|
||||
**
|
||||
** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
|
||||
** "Sorting And Searching", pages 473-480. Addison-Wesley
|
||||
** Publishing Company, Reading, Massachusetts.
|
||||
**
|
||||
** The basic idea is that each page of the file contains N database
|
||||
** entries and N+1 pointers to subpages.
|
||||
**
|
||||
** ----------------------------------------------------------------
|
||||
** | Ptr(0) | Key(0) | Ptr(1) | Key(1) | ... | Key(N-1) | Ptr(N) |
|
||||
** ----------------------------------------------------------------
|
||||
**
|
||||
** All of the keys on the page that Ptr(0) points to have values less
|
||||
** than Key(0). All of the keys on page Ptr(1) and its subpages have
|
||||
** values greater than Key(0) and less than Key(1). All of the keys
|
||||
** on Ptr(N) and its subpages have values greater than Key(N-1). And
|
||||
** so forth.
|
||||
**
|
||||
** Finding a particular key requires reading O(log(M)) pages from the
|
||||
** disk where M is the number of entries in the tree.
|
||||
**
|
||||
** In this implementation, a single file can hold one or more separate
|
||||
** BTrees. Each BTree is identified by the index of its root page. The
|
||||
** key and data for any entry are combined to form the "payload". A
|
||||
** fixed amount of payload can be carried directly on the database
|
||||
** page. If the payload is larger than the preset amount then surplus
|
||||
** bytes are stored on overflow pages. The payload for an entry
|
||||
** and the preceding pointer are combined to form a "Cell". Each
|
||||
** page has a small header which contains the Ptr(N) pointer and other
|
||||
** information such as the size of key and data.
|
||||
**
|
||||
** FORMAT DETAILS
|
||||
**
|
||||
** The file is divided into pages. The first page is called page 1,
|
||||
** the second is page 2, and so forth. A page number of zero indicates
|
||||
** "no such page". The page size can be any power of 2 between 512 and 65536.
|
||||
** Each page can be either a btree page, a freelist page, an overflow
|
||||
** page, or a pointer-map page.
|
||||
**
|
||||
** The first page is always a btree page. The first 100 bytes of the first
|
||||
** page contain a special header (the "file header") that describes the file.
|
||||
** The format of the file header is as follows:
|
||||
**
|
||||
** OFFSET SIZE DESCRIPTION
|
||||
** 0 16 Header string: "SQLite format 3\000"
|
||||
** 16 2 Page size in bytes.
|
||||
** 18 1 File format write version
|
||||
** 19 1 File format read version
|
||||
** 20 1 Bytes of unused space at the end of each page
|
||||
** 21 1 Max embedded payload fraction
|
||||
** 22 1 Min embedded payload fraction
|
||||
** 23 1 Min leaf payload fraction
|
||||
** 24 4 File change counter
|
||||
** 28 4 Reserved for future use
|
||||
** 32 4 First freelist page
|
||||
** 36 4 Number of freelist pages in the file
|
||||
** 40 60 15 4-byte meta values passed to higher layers
|
||||
**
|
||||
** 40 4 Schema cookie
|
||||
** 44 4 File format of schema layer
|
||||
** 48 4 Size of page cache
|
||||
** 52 4 Largest root-page (auto/incr_vacuum)
|
||||
** 56 4 1=UTF-8 2=UTF16le 3=UTF16be
|
||||
** 60 4 User version
|
||||
** 64 4 Incremental vacuum mode
|
||||
** 68 4 unused
|
||||
** 72 4 unused
|
||||
** 76 4 unused
|
||||
**
|
||||
** All of the integer values are big-endian (most significant byte first).
|
||||
**
|
||||
** The file change counter is incremented when the database is changed
|
||||
** This counter allows other processes to know when the file has changed
|
||||
** and thus when they need to flush their cache.
|
||||
**
|
||||
** The max embedded payload fraction is the amount of the total usable
|
||||
** space in a page that can be consumed by a single cell for standard
|
||||
** B-tree (non-LEAFDATA) tables. A value of 255 means 100%. The default
|
||||
** is to limit the maximum cell size so that at least 4 cells will fit
|
||||
** on one page. Thus the default max embedded payload fraction is 64.
|
||||
**
|
||||
** If the payload for a cell is larger than the max payload, then extra
|
||||
** payload is spilled to overflow pages. Once an overflow page is allocated,
|
||||
** as many bytes as possible are moved into the overflow pages without letting
|
||||
** the cell size drop below the min embedded payload fraction.
|
||||
**
|
||||
** The min leaf payload fraction is like the min embedded payload fraction
|
||||
** except that it applies to leaf nodes in a LEAFDATA tree. The maximum
|
||||
** payload fraction for a LEAFDATA tree is always 100% (or 255) and it
|
||||
** not specified in the header.
|
||||
**
|
||||
** Each btree pages is divided into three sections: The header, the
|
||||
** cell pointer array, and the cell content area. Page 1 also has a 100-byte
|
||||
** file header that occurs before the page header.
|
||||
**
|
||||
** |----------------|
|
||||
** | file header | 100 bytes. Page 1 only.
|
||||
** |----------------|
|
||||
** | page header | 8 bytes for leaves. 12 bytes for interior nodes
|
||||
** |----------------|
|
||||
** | cell pointer | | 2 bytes per cell. Sorted order.
|
||||
** | array | | Grows downward
|
||||
** | | v
|
||||
** |----------------|
|
||||
** | unallocated |
|
||||
** | space |
|
||||
** |----------------| ^ Grows upwards
|
||||
** | cell content | | Arbitrary order interspersed with freeblocks.
|
||||
** | area | | and free space fragments.
|
||||
** |----------------|
|
||||
**
|
||||
** The page headers looks like this:
|
||||
**
|
||||
** OFFSET SIZE DESCRIPTION
|
||||
** 0 1 Flags. 1: intkey, 2: zerodata, 4: leafdata, 8: leaf
|
||||
** 1 2 byte offset to the first freeblock
|
||||
** 3 2 number of cells on this page
|
||||
** 5 2 first byte of the cell content area
|
||||
** 7 1 number of fragmented free bytes
|
||||
** 8 4 Right child (the Ptr(N) value). Omitted on leaves.
|
||||
**
|
||||
** The flags define the format of this btree page. The leaf flag means that
|
||||
** this page has no children. The zerodata flag means that this page carries
|
||||
** only keys and no data. The intkey flag means that the key is a integer
|
||||
** which is stored in the key size entry of the cell header rather than in
|
||||
** the payload area.
|
||||
**
|
||||
** The cell pointer array begins on the first byte after the page header.
|
||||
** The cell pointer array contains zero or more 2-byte numbers which are
|
||||
** offsets from the beginning of the page to the cell content in the cell
|
||||
** content area. The cell pointers occur in sorted order. The system strives
|
||||
** to keep free space after the last cell pointer so that new cells can
|
||||
** be easily added without having to defragment the page.
|
||||
**
|
||||
** Cell content is stored at the very end of the page and grows toward the
|
||||
** beginning of the page.
|
||||
**
|
||||
** Unused space within the cell content area is collected into a linked list of
|
||||
** freeblocks. Each freeblock is at least 4 bytes in size. The byte offset
|
||||
** to the first freeblock is given in the header. Freeblocks occur in
|
||||
** increasing order. Because a freeblock must be at least 4 bytes in size,
|
||||
** any group of 3 or fewer unused bytes in the cell content area cannot
|
||||
** exist on the freeblock chain. A group of 3 or fewer free bytes is called
|
||||
** a fragment. The total number of bytes in all fragments is recorded.
|
||||
** in the page header at offset 7.
|
||||
**
|
||||
** SIZE DESCRIPTION
|
||||
** 2 Byte offset of the next freeblock
|
||||
** 2 Bytes in this freeblock
|
||||
**
|
||||
** Cells are of variable length. Cells are stored in the cell content area at
|
||||
** the end of the page. Pointers to the cells are in the cell pointer array
|
||||
** that immediately follows the page header. Cells is not necessarily
|
||||
** contiguous or in order, but cell pointers are contiguous and in order.
|
||||
**
|
||||
** Cell content makes use of variable length integers. A variable
|
||||
** length integer is 1 to 9 bytes where the lower 7 bits of each
|
||||
** byte are used. The integer consists of all bytes that have bit 8 set and
|
||||
** the first byte with bit 8 clear. The most significant byte of the integer
|
||||
** appears first. A variable-length integer may not be more than 9 bytes long.
|
||||
** As a special case, all 8 bytes of the 9th byte are used as data. This
|
||||
** allows a 64-bit integer to be encoded in 9 bytes.
|
||||
**
|
||||
** 0x00 becomes 0x00000000
|
||||
** 0x7f becomes 0x0000007f
|
||||
** 0x81 0x00 becomes 0x00000080
|
||||
** 0x82 0x00 becomes 0x00000100
|
||||
** 0x80 0x7f becomes 0x0000007f
|
||||
** 0x8a 0x91 0xd1 0xac 0x78 becomes 0x12345678
|
||||
** 0x81 0x81 0x81 0x81 0x01 becomes 0x10204081
|
||||
**
|
||||
** Variable length integers are used for rowids and to hold the number of
|
||||
** bytes of key and data in a btree cell.
|
||||
**
|
||||
** The content of a cell looks like this:
|
||||
**
|
||||
** SIZE DESCRIPTION
|
||||
** 4 Page number of the left child. Omitted if leaf flag is set.
|
||||
** var Number of bytes of data. Omitted if the zerodata flag is set.
|
||||
** var Number of bytes of key. Or the key itself if intkey flag is set.
|
||||
** * Payload
|
||||
** 4 First page of the overflow chain. Omitted if no overflow
|
||||
**
|
||||
** Overflow pages form a linked list. Each page except the last is completely
|
||||
** filled with data (pagesize - 4 bytes). The last page can have as little
|
||||
** as 1 byte of data.
|
||||
**
|
||||
** SIZE DESCRIPTION
|
||||
** 4 Page number of next overflow page
|
||||
** * Data
|
||||
**
|
||||
** Freelist pages come in two subtypes: trunk pages and leaf pages. The
|
||||
** file header points to the first in a linked list of trunk page. Each trunk
|
||||
** page points to multiple leaf pages. The content of a leaf page is
|
||||
** unspecified. A trunk page looks like this:
|
||||
**
|
||||
** SIZE DESCRIPTION
|
||||
** 4 Page number of next trunk page
|
||||
** 4 Number of leaf pointers on this page
|
||||
** * zero or more pages numbers of leaves
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2011-05-19 13:26:54 ed1da510a239ea767a01dc332b667119fa3c908e
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#include "sqliteInt.h"
|
||||
|
||||
/* The following value is the maximum cell size assuming a maximum page
|
||||
** size give above.
|
||||
*/
|
||||
|
||||
//#define MX_CELL_SIZE(pBt) ((int)(pBt->pageSize-8))
|
||||
private static int MX_CELL_SIZE(BtShared pBt)
|
||||
{
|
||||
return (int)(pBt.pageSize - 8);
|
||||
}
|
||||
|
||||
/* The maximum number of cells on a single page of the database. This
|
||||
** assumes a minimum cell size of 6 bytes (4 bytes for the cell itself
|
||||
** plus 2 bytes for the index to the cell in the page header). Such
|
||||
** small cells will be rare, but they are possible.
|
||||
*/
|
||||
|
||||
//#define MX_CELL(pBt) ((pBt.pageSize-8)/6)
|
||||
private static int MX_CELL(BtShared pBt)
|
||||
{
|
||||
return ((int)(pBt.pageSize - 8) / 6);
|
||||
}
|
||||
|
||||
/* Forward declarations */
|
||||
//typedef struct MemPage MemPage;
|
||||
//typedef struct BtLock BtLock;
|
||||
|
||||
/*
|
||||
** This is a magic string that appears at the beginning of every
|
||||
** SQLite database in order to identify the file as a real database.
|
||||
**
|
||||
** You can change this value at compile-time by specifying a
|
||||
** -DSQLITE_FILE_HEADER="..." on the compiler command-line. The
|
||||
** header must be exactly 16 bytes including the zero-terminator so
|
||||
** the string itself should be 15 characters long. If you change
|
||||
** the header, then your custom library will not be able to read
|
||||
** databases generated by the standard tools and the standard tools
|
||||
** will not be able to read databases created by your custom library.
|
||||
*/
|
||||
#if !SQLITE_FILE_HEADER //* 123456789 123456 */
|
||||
private const string SQLITE_FILE_HEADER = "SQLite format 3\0";
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Page type flags. An ORed combination of these flags appear as the
|
||||
** first byte of on-disk image of every BTree page.
|
||||
*/
|
||||
private const byte PTF_INTKEY = 0x01;
|
||||
private const byte PTF_ZERODATA = 0x02;
|
||||
private const byte PTF_LEAFDATA = 0x04;
|
||||
private const byte PTF_LEAF = 0x08;
|
||||
|
||||
/*
|
||||
** As each page of the file is loaded into memory, an instance of the following
|
||||
** structure is appended and initialized to zero. This structure stores
|
||||
** information about the page that is decoded from the raw file page.
|
||||
**
|
||||
** The pParent field points back to the parent page. This allows us to
|
||||
** walk up the BTree from any leaf to the root. Care must be taken to
|
||||
** unref() the parent page pointer when this page is no longer referenced.
|
||||
** The pageDestructor() routine handles that chore.
|
||||
**
|
||||
** Access to all fields of this structure is controlled by the mutex
|
||||
** stored in MemPage.pBt.mutex.
|
||||
*/
|
||||
|
||||
public struct _OvflCell
|
||||
{ /* Cells that will not fit on aData[] */
|
||||
public u8[] pCell; /* Pointers to the body of the overflow cell */
|
||||
public u16 idx; /* Insert this cell before idx-th non-overflow cell */
|
||||
|
||||
public _OvflCell Copy()
|
||||
{
|
||||
_OvflCell cp = new _OvflCell();
|
||||
if (pCell != null)
|
||||
{
|
||||
cp.pCell = sqlite3Malloc(pCell.Length);
|
||||
Buffer.BlockCopy(pCell, 0, cp.pCell, 0, pCell.Length);
|
||||
}
|
||||
cp.idx = idx;
|
||||
return cp;
|
||||
}
|
||||
};
|
||||
|
||||
public class MemPage
|
||||
{
|
||||
public u8 isInit; /* True if previously initialized. MUST BE FIRST! */
|
||||
public u8 nOverflow; /* Number of overflow cell bodies in aCell[] */
|
||||
public u8 intKey; /* True if u8key flag is set */
|
||||
public u8 leaf; /* 1 if leaf flag is set */
|
||||
public u8 hasData; /* True if this page stores data */
|
||||
public u8 hdrOffset; /* 100 for page 1. 0 otherwise */
|
||||
public u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */
|
||||
public u16 maxLocal; /* Copy of BtShared.maxLocal or BtShared.maxLeaf */
|
||||
public u16 minLocal; /* Copy of BtShared.minLocal or BtShared.minLeaf */
|
||||
public u16 cellOffset; /* Index in aData of first cell pou16er */
|
||||
public u16 nFree; /* Number of free bytes on the page */
|
||||
public u16 nCell; /* Number of cells on this page, local and ovfl */
|
||||
public u16 maskPage; /* Mask for page offset */
|
||||
public _OvflCell[] aOvfl = new _OvflCell[5];
|
||||
public BtShared pBt; /* Pointer to BtShared that this page is part of */
|
||||
public byte[] aData; /* Pointer to disk image of the page data */
|
||||
public DbPage pDbPage; /* Pager page handle */
|
||||
public Pgno pgno; /* Page number for this page */
|
||||
|
||||
//public byte[] aData
|
||||
//{
|
||||
// get
|
||||
// {
|
||||
// Debug.Assert( pgno != 1 || pDbPage.pData == _aData );
|
||||
// return _aData;
|
||||
// }
|
||||
// set
|
||||
// {
|
||||
// _aData = value;
|
||||
// Debug.Assert( pgno != 1 || pDbPage.pData == _aData );
|
||||
// }
|
||||
//}
|
||||
|
||||
public MemPage Copy()
|
||||
{
|
||||
MemPage cp = (MemPage)MemberwiseClone();
|
||||
if (aOvfl != null)
|
||||
{
|
||||
cp.aOvfl = new _OvflCell[aOvfl.Length];
|
||||
for (int i = 0; i < aOvfl.Length; i++)
|
||||
cp.aOvfl[i] = aOvfl[i].Copy();
|
||||
}
|
||||
if (aData != null)
|
||||
{
|
||||
cp.aData = sqlite3Malloc(aData.Length);
|
||||
Buffer.BlockCopy(aData, 0, cp.aData, 0, aData.Length);
|
||||
}
|
||||
return cp;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
** The in-memory image of a disk page has the auxiliary information appended
|
||||
** to the end. EXTRA_SIZE is the number of bytes of space needed to hold
|
||||
** that extra information.
|
||||
*/
|
||||
private const int EXTRA_SIZE = 0;// No used in C#, since we use create a class; was MemPage.Length;
|
||||
|
||||
/*
|
||||
** A linked list of the following structures is stored at BtShared.pLock.
|
||||
** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor
|
||||
** is opened on the table with root page BtShared.iTable. Locks are removed
|
||||
** from this list when a transaction is committed or rolled back, or when
|
||||
** a btree handle is closed.
|
||||
*/
|
||||
|
||||
public class BtLock
|
||||
{
|
||||
private Btree pBtree; /* Btree handle holding this lock */
|
||||
private Pgno iTable; /* Root page of table */
|
||||
private u8 eLock; /* READ_LOCK or WRITE_LOCK */
|
||||
private BtLock pNext; /* Next in BtShared.pLock list */
|
||||
};
|
||||
|
||||
/* Candidate values for BtLock.eLock */
|
||||
|
||||
//#define READ_LOCK 1
|
||||
//#define WRITE_LOCK 2
|
||||
private const int READ_LOCK = 1;
|
||||
|
||||
private const int WRITE_LOCK = 2;
|
||||
|
||||
/* A Btree handle
|
||||
**
|
||||
** A database connection contains a pointer to an instance of
|
||||
** this object for every database file that it has open. This structure
|
||||
** is opaque to the database connection. The database connection cannot
|
||||
** see the internals of this structure and only deals with pointers to
|
||||
** this structure.
|
||||
**
|
||||
** For some database files, the same underlying database cache might be
|
||||
** shared between multiple connections. In that case, each connection
|
||||
** has it own instance of this object. But each instance of this object
|
||||
** points to the same BtShared object. The database cache and the
|
||||
** schema associated with the database file are all contained within
|
||||
** the BtShared object.
|
||||
**
|
||||
** All fields in this structure are accessed under sqlite3.mutex.
|
||||
** The pBt pointer itself may not be changed while there exists cursors
|
||||
** in the referenced BtShared that point back to this Btree since those
|
||||
** cursors have to go through this Btree to find their BtShared and
|
||||
** they often do so without holding sqlite3.mutex.
|
||||
*/
|
||||
|
||||
public class Btree
|
||||
{
|
||||
public sqlite3 db; /* The database connection holding this Btree */
|
||||
public BtShared pBt; /* Sharable content of this Btree */
|
||||
public u8 inTrans; /* TRANS_NONE, TRANS_READ or TRANS_WRITE */
|
||||
public bool sharable; /* True if we can share pBt with another db */
|
||||
public bool locked; /* True if db currently has pBt locked */
|
||||
public int wantToLock; /* Number of nested calls to sqlite3BtreeEnter() */
|
||||
public int nBackup; /* Number of backup operations reading this btree */
|
||||
public Btree pNext; /* List of other sharable Btrees from the same db */
|
||||
public Btree pPrev; /* Back pointer of the same list */
|
||||
#if !SQLITE_OMIT_SHARED_CACHE
|
||||
BtLock lock; /* Object used to lock page 1 */
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
** Btree.inTrans may take one of the following values.
|
||||
**
|
||||
** If the shared-data extension is enabled, there may be multiple users
|
||||
** of the Btree structure. At most one of these may open a write transaction,
|
||||
** but any number may have active read transactions.
|
||||
*/
|
||||
private const byte TRANS_NONE = 0;
|
||||
private const byte TRANS_READ = 1;
|
||||
private const byte TRANS_WRITE = 2;
|
||||
|
||||
/*
|
||||
** An instance of this object represents a single database file.
|
||||
**
|
||||
** A single database file can be in use as the same time by two
|
||||
** or more database connections. When two or more connections are
|
||||
** sharing the same database file, each connection has it own
|
||||
** private Btree object for the file and each of those Btrees points
|
||||
** to this one BtShared object. BtShared.nRef is the number of
|
||||
** connections currently sharing this database file.
|
||||
**
|
||||
** Fields in this structure are accessed under the BtShared.mutex
|
||||
** mutex, except for nRef and pNext which are accessed under the
|
||||
** global SQLITE_MUTEX_STATIC_MASTER mutex. The pPager field
|
||||
** may not be modified once it is initially set as long as nRef>0.
|
||||
** The pSchema field may be set once under BtShared.mutex and
|
||||
** thereafter is unchanged as long as nRef>0.
|
||||
**
|
||||
** isPending:
|
||||
**
|
||||
** If a BtShared client fails to obtain a write-lock on a database
|
||||
** table (because there exists one or more read-locks on the table),
|
||||
** the shared-cache enters 'pending-lock' state and isPending is
|
||||
** set to true.
|
||||
**
|
||||
** The shared-cache leaves the 'pending lock' state when either of
|
||||
** the following occur:
|
||||
**
|
||||
** 1) The current writer (BtShared.pWriter) concludes its transaction, OR
|
||||
** 2) The number of locks held by other connections drops to zero.
|
||||
**
|
||||
** while in the 'pending-lock' state, no connection may start a new
|
||||
** transaction.
|
||||
**
|
||||
** This feature is included to help prevent writer-starvation.
|
||||
*/
|
||||
|
||||
public class BtShared
|
||||
{
|
||||
public Pager pPager; /* The page cache */
|
||||
public sqlite3 db; /* Database connection currently using this Btree */
|
||||
public BtCursor pCursor; /* A list of all open cursors */
|
||||
public MemPage pPage1; /* First page of the database */
|
||||
public bool readOnly; /* True if the underlying file is readonly */
|
||||
public bool pageSizeFixed; /* True if the page size can no longer be changed */
|
||||
public bool secureDelete; /* True if secure_delete is enabled */
|
||||
public bool initiallyEmpty; /* Database is empty at start of transaction */
|
||||
public u8 openFlags; /* Flags to sqlite3BtreeOpen() */
|
||||
#if !SQLITE_OMIT_AUTOVACUUM
|
||||
public bool autoVacuum; /* True if auto-vacuum is enabled */
|
||||
public bool incrVacuum; /* True if incr-vacuum is enabled */
|
||||
#endif
|
||||
public u8 inTransaction; /* Transaction state */
|
||||
public bool doNotUseWAL; /* If true, do not open write-ahead-log file */
|
||||
public u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */
|
||||
public u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */
|
||||
public u16 maxLeaf; /* Maximum local payload in a LEAFDATA table */
|
||||
public u16 minLeaf; /* Minimum local payload in a LEAFDATA table */
|
||||
public u32 pageSize; /* Total number of bytes on a page */
|
||||
public u32 usableSize; /* Number of usable bytes on each page */
|
||||
public int nTransaction; /* Number of open transactions (read + write) */
|
||||
public Pgno nPage; /* Number of pages in the database */
|
||||
public Schema pSchema; /* Pointer to space allocated by sqlite3BtreeSchema() */
|
||||
public dxFreeSchema xFreeSchema;/* Destructor for BtShared.pSchema */
|
||||
public sqlite3_mutex mutex; /* Non-recursive mutex required to access this object */
|
||||
public Bitvec pHasContent; /* Set of pages moved to free-list this transaction */
|
||||
#if !SQLITE_OMIT_SHARED_CACHE
|
||||
public int nRef; /* Number of references to this structure */
|
||||
public BtShared pNext; /* Next on a list of sharable BtShared structs */
|
||||
public BtLock pLock; /* List of locks held on this shared-btree struct */
|
||||
public Btree pWriter; /* Btree with currently open write transaction */
|
||||
public u8 isExclusive; /* True if pWriter has an EXCLUSIVE lock on the db */
|
||||
public u8 isPending; /* If waiting for read-locks to clear */
|
||||
#endif
|
||||
public byte[] pTmpSpace; /* BtShared.pageSize bytes of space for tmp use */
|
||||
};
|
||||
|
||||
/*
|
||||
** An instance of the following structure is used to hold information
|
||||
** about a cell. The parseCellPtr() function fills in this structure
|
||||
** based on information extract from the raw disk page.
|
||||
*/
|
||||
|
||||
//typedef struct CellInfo CellInfo;
|
||||
public struct CellInfo
|
||||
{
|
||||
public int iCell; /* Offset to start of cell content -- Needed for C# */
|
||||
public byte[] pCell; /* Pointer to the start of cell content */
|
||||
public i64 nKey; /* The key for INTKEY tables, or number of bytes in key */
|
||||
public u32 nData; /* Number of bytes of data */
|
||||
public u32 nPayload; /* Total amount of payload */
|
||||
public u16 nHeader; /* Size of the cell content header in bytes */
|
||||
public u16 nLocal; /* Amount of payload held locally */
|
||||
public u16 iOverflow; /* Offset to overflow page number. Zero if no overflow */
|
||||
public u16 nSize; /* Size of the cell content on the main b-tree page */
|
||||
|
||||
public bool Equals(CellInfo ci)
|
||||
{
|
||||
if (ci.iCell >= ci.pCell.Length || iCell >= this.pCell.Length)
|
||||
return false;
|
||||
if (ci.pCell[ci.iCell] != this.pCell[iCell])
|
||||
return false;
|
||||
if (ci.nKey != this.nKey || ci.nData != this.nData || ci.nPayload != this.nPayload)
|
||||
return false;
|
||||
if (ci.nHeader != this.nHeader || ci.nLocal != this.nLocal)
|
||||
return false;
|
||||
if (ci.iOverflow != this.iOverflow || ci.nSize != this.nSize)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
** Maximum depth of an SQLite B-Tree structure. Any B-Tree deeper than
|
||||
** this will be declared corrupt. This value is calculated based on a
|
||||
** maximum database size of 2^31 pages a minimum fanout of 2 for a
|
||||
** root-node and 3 for all other internal nodes.
|
||||
**
|
||||
** If a tree that appears to be taller than this is encountered, it is
|
||||
** assumed that the database is corrupt.
|
||||
*/
|
||||
|
||||
//#define BTCURSOR_MAX_DEPTH 20
|
||||
private const int BTCURSOR_MAX_DEPTH = 20;
|
||||
|
||||
/*
|
||||
** A cursor is a pointer to a particular entry within a particular
|
||||
** b-tree within a database file.
|
||||
**
|
||||
** The entry is identified by its MemPage and the index in
|
||||
** MemPage.aCell[] of the entry.
|
||||
**
|
||||
** A single database file can shared by two more database connections,
|
||||
** but cursors cannot be shared. Each cursor is associated with a
|
||||
** particular database connection identified BtCursor.pBtree.db.
|
||||
**
|
||||
** Fields in this structure are accessed under the BtShared.mutex
|
||||
** found at self.pBt.mutex.
|
||||
*/
|
||||
|
||||
public class BtCursor
|
||||
{
|
||||
public Btree pBtree; /* The Btree to which this cursor belongs */
|
||||
public BtShared pBt; /* The BtShared this cursor points to */
|
||||
public BtCursor pNext;
|
||||
public BtCursor pPrev; /* Forms a linked list of all cursors */
|
||||
public KeyInfo pKeyInfo; /* Argument passed to comparison function */
|
||||
public Pgno pgnoRoot; /* The root page of this tree */
|
||||
public sqlite3_int64 cachedRowid; /* Next rowid cache. 0 means not valid */
|
||||
public CellInfo info = new CellInfo(); /* A parse of the cell we are pointing at */
|
||||
public byte[] pKey; /* Saved key that was cursor's last known position */
|
||||
public i64 nKey; /* Size of pKey, or last integer key */
|
||||
public int skipNext; /* Prev() is noop if negative. Next() is noop if positive */
|
||||
public u8 wrFlag; /* True if writable */
|
||||
public u8 atLast; /* VdbeCursor pointing to the last entry */
|
||||
public bool validNKey; /* True if info.nKey is valid */
|
||||
public int eState; /* One of the CURSOR_XXX constants (see below) */
|
||||
#if !SQLITE_OMIT_INCRBLOB
|
||||
public Pgno[] aOverflow; /* Cache of overflow page locations */
|
||||
public bool isIncrblobHandle; /* True if this cursor is an incr. io handle */
|
||||
#endif
|
||||
public i16 iPage; /* Index of current page in apPage */
|
||||
public u16[] aiIdx = new u16[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */
|
||||
public MemPage[] apPage = new MemPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
pNext = null;
|
||||
pPrev = null;
|
||||
pKeyInfo = null;
|
||||
pgnoRoot = 0;
|
||||
cachedRowid = 0;
|
||||
info = new CellInfo();
|
||||
wrFlag = 0;
|
||||
atLast = 0;
|
||||
validNKey = false;
|
||||
eState = 0;
|
||||
pKey = null;
|
||||
nKey = 0;
|
||||
skipNext = 0;
|
||||
#if !SQLITE_OMIT_INCRBLOB
|
||||
isIncrblobHandle=false;
|
||||
aOverflow= null;
|
||||
#endif
|
||||
iPage = 0;
|
||||
}
|
||||
|
||||
public BtCursor Copy()
|
||||
{
|
||||
BtCursor cp = (BtCursor)MemberwiseClone();
|
||||
return cp;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
** Potential values for BtCursor.eState.
|
||||
**
|
||||
** CURSOR_VALID:
|
||||
** VdbeCursor points to a valid entry. getPayload() etc. may be called.
|
||||
**
|
||||
** CURSOR_INVALID:
|
||||
** VdbeCursor does not point to a valid entry. This can happen (for example)
|
||||
** because the table is empty or because BtreeCursorFirst() has not been
|
||||
** called.
|
||||
**
|
||||
** CURSOR_REQUIRESEEK:
|
||||
** The table that this cursor was opened on still exists, but has been
|
||||
** modified since the cursor was last used. The cursor position is saved
|
||||
** in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in
|
||||
** this state, restoreCursorPosition() can be called to attempt to
|
||||
** seek the cursor to the saved position.
|
||||
**
|
||||
** CURSOR_FAULT:
|
||||
** A unrecoverable error (an I/O error or a malloc failure) has occurred
|
||||
** on a different connection that shares the BtShared cache with this
|
||||
** cursor. The error has left the cache in an inconsistent state.
|
||||
** Do nothing else with this cursor. Any attempt to use the cursor
|
||||
** should return the error code stored in BtCursor.skip
|
||||
*/
|
||||
private const int CURSOR_INVALID = 0;
|
||||
private const int CURSOR_VALID = 1;
|
||||
private const int CURSOR_REQUIRESEEK = 2;
|
||||
private const int CURSOR_FAULT = 3;
|
||||
|
||||
/*
|
||||
** The database page the PENDING_BYTE occupies. This page is never used.
|
||||
*/
|
||||
|
||||
//# define PENDING_BYTE_PAGE(pBt) PAGER_MJ_PGNO(pBt)
|
||||
// TODO -- Convert PENDING_BYTE_PAGE to inline
|
||||
private static u32 PENDING_BYTE_PAGE(BtShared pBt)
|
||||
{
|
||||
return (u32)PAGER_MJ_PGNO(pBt.pPager);
|
||||
}
|
||||
|
||||
/*
|
||||
** These macros define the location of the pointer-map entry for a
|
||||
** database page. The first argument to each is the number of usable
|
||||
** bytes on each page of the database (often 1024). The second is the
|
||||
** page number to look up in the pointer map.
|
||||
**
|
||||
** PTRMAP_PAGENO returns the database page number of the pointer-map
|
||||
** page that stores the required pointer. PTRMAP_PTROFFSET returns
|
||||
** the offset of the requested map entry.
|
||||
**
|
||||
** If the pgno argument passed to PTRMAP_PAGENO is a pointer-map page,
|
||||
** then pgno is returned. So (pgno==PTRMAP_PAGENO(pgsz, pgno)) can be
|
||||
** used to test if pgno is a pointer-map page. PTRMAP_ISPAGE implements
|
||||
** this test.
|
||||
*/
|
||||
|
||||
//#define PTRMAP_PAGENO(pBt, pgno) ptrmapPageno(pBt, pgno)
|
||||
private static Pgno PTRMAP_PAGENO(BtShared pBt, Pgno pgno)
|
||||
{
|
||||
return ptrmapPageno(pBt, pgno);
|
||||
}
|
||||
|
||||
//#define PTRMAP_PTROFFSET(pgptrmap, pgno) (5*(pgno-pgptrmap-1))
|
||||
private static u32 PTRMAP_PTROFFSET(u32 pgptrmap, u32 pgno)
|
||||
{
|
||||
return (5 * (pgno - pgptrmap - 1));
|
||||
}
|
||||
|
||||
//#define PTRMAP_ISPAGE(pBt, pgno) (PTRMAP_PAGENO((pBt),(pgno))==(pgno))
|
||||
private static bool PTRMAP_ISPAGE(BtShared pBt, u32 pgno)
|
||||
{
|
||||
return (PTRMAP_PAGENO((pBt), (pgno)) == (pgno));
|
||||
}
|
||||
|
||||
/*
|
||||
** The pointer map is a lookup table that identifies the parent page for
|
||||
** each child page in the database file. The parent page is the page that
|
||||
** contains a pointer to the child. Every page in the database contains
|
||||
** 0 or 1 parent pages. (In this context 'database page' refers
|
||||
** to any page that is not part of the pointer map itself.) Each pointer map
|
||||
** entry consists of a single byte 'type' and a 4 byte parent page number.
|
||||
** The PTRMAP_XXX identifiers below are the valid types.
|
||||
**
|
||||
** The purpose of the pointer map is to facility moving pages from one
|
||||
** position in the file to another as part of autovacuum. When a page
|
||||
** is moved, the pointer in its parent must be updated to point to the
|
||||
** new location. The pointer map is used to locate the parent page quickly.
|
||||
**
|
||||
** PTRMAP_ROOTPAGE: The database page is a root-page. The page-number is not
|
||||
** used in this case.
|
||||
**
|
||||
** PTRMAP_FREEPAGE: The database page is an unused (free) page. The page-number
|
||||
** is not used in this case.
|
||||
**
|
||||
** PTRMAP_OVERFLOW1: The database page is the first page in a list of
|
||||
** overflow pages. The page number identifies the page that
|
||||
** contains the cell with a pointer to this overflow page.
|
||||
**
|
||||
** PTRMAP_OVERFLOW2: The database page is the second or later page in a list of
|
||||
** overflow pages. The page-number identifies the previous
|
||||
** page in the overflow page list.
|
||||
**
|
||||
** PTRMAP_BTREE: The database page is a non-root btree page. The page number
|
||||
** identifies the parent page in the btree.
|
||||
*/
|
||||
|
||||
//#define PTRMAP_ROOTPAGE 1
|
||||
//#define PTRMAP_FREEPAGE 2
|
||||
//#define PTRMAP_OVERFLOW1 3
|
||||
//#define PTRMAP_OVERFLOW2 4
|
||||
//#define PTRMAP_BTREE 5
|
||||
private const int PTRMAP_ROOTPAGE = 1;
|
||||
|
||||
private const int PTRMAP_FREEPAGE = 2;
|
||||
private const int PTRMAP_OVERFLOW1 = 3;
|
||||
private const int PTRMAP_OVERFLOW2 = 4;
|
||||
private const int PTRMAP_BTREE = 5;
|
||||
|
||||
/* A bunch of Debug.Assert() statements to check the transaction state variables
|
||||
** of handle p (type Btree*) are internally consistent.
|
||||
*/
|
||||
#if DEBUG
|
||||
|
||||
//#define btreeIntegrity(p) \
|
||||
// Debug.Assert( p.pBt.inTransaction!=TRANS_NONE || p.pBt.nTransaction==0 ); \
|
||||
// Debug.Assert( p.pBt.inTransaction>=p.inTrans );
|
||||
private static void btreeIntegrity(Btree p)
|
||||
{
|
||||
Debug.Assert(p.pBt.inTransaction != TRANS_NONE || p.pBt.nTransaction == 0);
|
||||
Debug.Assert(p.pBt.inTransaction >= p.inTrans);
|
||||
}
|
||||
|
||||
#else
|
||||
static void btreeIntegrity(Btree p) { }
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The ISAUTOVACUUM macro is used within balance_nonroot() to determine
|
||||
** if the database supports auto-vacuum or not. Because it is used
|
||||
** within an expression that is an argument to another macro
|
||||
** (sqliteMallocRaw), it is not possible to use conditional compilation.
|
||||
** So, this macro is defined instead.
|
||||
*/
|
||||
#if !SQLITE_OMIT_AUTOVACUUM
|
||||
//#define ISAUTOVACUUM (pBt.autoVacuum)
|
||||
#else
|
||||
//#define ISAUTOVACUUM 0
|
||||
public static bool ISAUTOVACUUM =false;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This structure is passed around through all the sanity checking routines
|
||||
** in order to keep track of some global state information.
|
||||
*/
|
||||
|
||||
//typedef struct IntegrityCk IntegrityCk;
|
||||
public class IntegrityCk
|
||||
{
|
||||
public BtShared pBt; /* The tree being checked out */
|
||||
public Pager pPager; /* The associated pager. Also accessible by pBt.pPager */
|
||||
public Pgno nPage; /* Number of pages in the database */
|
||||
public int[] anRef; /* Number of times each page is referenced */
|
||||
public int mxErr; /* Stop accumulating errors when this reaches zero */
|
||||
public int nErr; /* Number of messages written to zErrMsg so far */
|
||||
|
||||
//public int mallocFailed; /* A memory allocation error has occurred */
|
||||
public StrAccum errMsg = new StrAccum(100); /* Accumulate the error message text here */
|
||||
};
|
||||
|
||||
/*
|
||||
** Read or write a two- and four-byte big-endian integer values.
|
||||
*/
|
||||
|
||||
//#define get2byte(x) ((x)[0]<<8 | (x)[1])
|
||||
private static int get2byte(byte[] p, int offset)
|
||||
{
|
||||
return p[offset + 0] << 8 | p[offset + 1];
|
||||
}
|
||||
|
||||
//#define put2byte(p,v) ((p)[0] = (u8)((v)>>8), (p)[1] = (u8)(v))
|
||||
private static void put2byte(byte[] pData, int Offset, u32 v)
|
||||
{
|
||||
pData[Offset + 0] = (byte)(v >> 8);
|
||||
pData[Offset + 1] = (byte)v;
|
||||
}
|
||||
|
||||
private static void put2byte(byte[] pData, int Offset, int v)
|
||||
{
|
||||
pData[Offset + 0] = (byte)(v >> 8);
|
||||
pData[Offset + 1] = (byte)v;
|
||||
}
|
||||
|
||||
//#define get4byte sqlite3Get4byte
|
||||
//#define put4byte sqlite3Put4byte
|
||||
}
|
||||
}
|
||||
317
original/Community.CsharpSqlite/src/Btree_h.cs
Normal file
317
original/Community.CsharpSqlite/src/Btree_h.cs
Normal file
|
|
@ -0,0 +1,317 @@
|
|||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This header file defines the interface that the sqlite B-Tree file
|
||||
** subsystem. See comments in the source code for a detailed description
|
||||
** of what each interface routine does.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#if !_BTREE_H_
|
||||
//#define _BTREE_H_
|
||||
|
||||
/* TODO: This definition is just included so other modules compile. It
|
||||
** needs to be revisited.
|
||||
*/
|
||||
private const int SQLITE_N_BTREE_META = 10;
|
||||
|
||||
/*
|
||||
** If defined as non-zero, auto-vacuum is enabled by default. Otherwise
|
||||
** it must be turned on for each database using "PRAGMA auto_vacuum = 1".
|
||||
*/
|
||||
#if !SQLITE_DEFAULT_AUTOVACUUM
|
||||
private const int SQLITE_DEFAULT_AUTOVACUUM = 0;
|
||||
#endif
|
||||
|
||||
private const int BTREE_AUTOVACUUM_NONE = 0; /* Do not do auto-vacuum */
|
||||
private const int BTREE_AUTOVACUUM_FULL = 1; /* Do full auto-vacuum */
|
||||
private const int BTREE_AUTOVACUUM_INCR = 2; /* Incremental vacuum */
|
||||
|
||||
/*
|
||||
** Forward declarations of structure
|
||||
*/
|
||||
//typedef struct Btree Btree;
|
||||
//typedef struct BtCursor BtCursor;
|
||||
//typedef struct BtShared BtShared;
|
||||
|
||||
//int sqlite3BtreeOpen(
|
||||
// sqlite3_vfs *pVfs, /* VFS to use with this b-tree */
|
||||
// string zFilename, /* Name of database file to open */
|
||||
// sqlite3 db, /* Associated database connection */
|
||||
// Btree **ppBtree, /* Return open Btree* here */
|
||||
// int flags, /* Flags */
|
||||
// int vfsFlags /* Flags passed through to VFS open */
|
||||
//);
|
||||
|
||||
/* The flags parameter to sqlite3BtreeOpen can be the bitwise or of the
|
||||
** following values.
|
||||
**
|
||||
** NOTE: These values must match the corresponding PAGER_ values in
|
||||
** pager.h.
|
||||
*/
|
||||
|
||||
//#define BTREE_OMIT_JOURNAL 1 /* Do not create or use a rollback journal */
|
||||
//#define BTREE_NO_READLOCK 2 /* Omit readlocks on readonly files */
|
||||
//#define BTREE_MEMORY 4 /* This is an in-memory DB */
|
||||
//#define BTREE_SINGLE 8 /* The file contains at most 1 b-tree */
|
||||
//#define BTREE_UNORDERED 16 /* Use of a hash implementation is OK */
|
||||
private const int BTREE_OMIT_JOURNAL = 1; /* Do not create or use a rollback journal */
|
||||
|
||||
private const int BTREE_NO_READLOCK = 2; /* Omit readlocks on readonly files */
|
||||
private const int BTREE_MEMORY = 4; /* This is an in-memory DB */
|
||||
private const int BTREE_SINGLE = 8; /* The file contains at most 1 b-tree */
|
||||
private const int BTREE_UNORDERED = 16; /* Use of a hash implementation is OK */
|
||||
|
||||
//int sqlite3BtreeClose(Btree);
|
||||
//int sqlite3BtreeSetCacheSize(Btree*,int);
|
||||
//int sqlite3BtreeSetSafetyLevel(Btree*,int,int,int);
|
||||
//int sqlite3BtreeSyncDisabled(Btree);
|
||||
//int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
|
||||
//int sqlite3BtreeGetPageSize(Btree);
|
||||
//int sqlite3BtreeMaxPageCount(Btree*,int);
|
||||
//u32 sqlite3BtreeLastPage(Btree);
|
||||
//int sqlite3BtreeSecureDelete(Btree*,int);
|
||||
//int sqlite3BtreeGetReserve(Btree);
|
||||
//int sqlite3BtreeSetAutoVacuum(Btree , int);
|
||||
//int sqlite3BtreeGetAutoVacuum(Btree );
|
||||
//int sqlite3BtreeBeginTrans(Btree*,int);
|
||||
//int sqlite3BtreeCommitPhaseOne(Btree*, string zMaster);
|
||||
//int sqlite3BtreeCommitPhaseTwo(Btree*, int);
|
||||
//int sqlite3BtreeCommit(Btree);
|
||||
//int sqlite3BtreeRollback(Btree);
|
||||
//int sqlite3BtreeBeginStmt(Btree);
|
||||
//int sqlite3BtreeCreateTable(Btree*, int*, int flags);
|
||||
//int sqlite3BtreeIsInTrans(Btree);
|
||||
//int sqlite3BtreeIsInReadTrans(Btree);
|
||||
//int sqlite3BtreeIsInBackup(Btree);
|
||||
//void *sqlite3BtreeSchema(Btree , int, void()(void ));
|
||||
//int sqlite3BtreeSchemaLocked( Btree* pBtree );
|
||||
//int sqlite3BtreeLockTable( Btree* pBtree, int iTab, u8 isWriteLock );
|
||||
//int sqlite3BtreeSavepoint(Btree *, int, int);
|
||||
|
||||
//string sqlite3BtreeGetFilename(Btree );
|
||||
//string sqlite3BtreeGetJournalname(Btree );
|
||||
//int sqlite3BtreeCopyFile(Btree *, Btree );
|
||||
|
||||
//int sqlite3BtreeIncrVacuum(Btree );
|
||||
|
||||
/* The flags parameter to sqlite3BtreeCreateTable can be the bitwise OR
|
||||
** of the flags shown below.
|
||||
**
|
||||
** Every SQLite table must have either BTREE_INTKEY or BTREE_BLOBKEY set.
|
||||
** With BTREE_INTKEY, the table key is a 64-bit integer and arbitrary data
|
||||
** is stored in the leaves. (BTREE_INTKEY is used for SQL tables.) With
|
||||
** BTREE_BLOBKEY, the key is an arbitrary BLOB and no content is stored
|
||||
** anywhere - the key is the content. (BTREE_BLOBKEY is used for SQL
|
||||
** indices.)
|
||||
*/
|
||||
|
||||
//#define BTREE_INTKEY 1 /* Table has only 64-bit signed integer keys */
|
||||
//#define BTREE_BLOBKEY 2 /* Table has keys only - no data */
|
||||
private const int BTREE_INTKEY = 1;
|
||||
|
||||
private const int BTREE_BLOBKEY = 2;
|
||||
|
||||
//int sqlite3BtreeDropTable(Btree*, int, int);
|
||||
//int sqlite3BtreeClearTable(Btree*, int, int);
|
||||
//void sqlite3BtreeTripAllCursors(Btree*, int);
|
||||
|
||||
//void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue);
|
||||
//int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
|
||||
|
||||
/*
|
||||
** The second parameter to sqlite3BtreeGetMeta or sqlite3BtreeUpdateMeta
|
||||
** should be one of the following values. The integer values are assigned
|
||||
** to constants so that the offset of the corresponding field in an
|
||||
** SQLite database header may be found using the following formula:
|
||||
**
|
||||
** offset = 36 + (idx * 4)
|
||||
**
|
||||
** For example, the free-page-count field is located at byte offset 36 of
|
||||
** the database file header. The incr-vacuum-flag field is located at
|
||||
** byte offset 64 (== 36+4*7).
|
||||
*/
|
||||
|
||||
//#define BTREE_FREE_PAGE_COUNT 0
|
||||
//#define BTREE_SCHEMA_VERSION 1
|
||||
//#define BTREE_FILE_FORMAT 2
|
||||
//#define BTREE_DEFAULT_CACHE_SIZE 3
|
||||
//#define BTREE_LARGEST_ROOT_PAGE 4
|
||||
//#define BTREE_TEXT_ENCODING 5
|
||||
//#define BTREE_USER_VERSION 6
|
||||
//#define BTREE_INCR_VACUUM 7
|
||||
private const int BTREE_FREE_PAGE_COUNT = 0;
|
||||
|
||||
private const int BTREE_SCHEMA_VERSION = 1;
|
||||
private const int BTREE_FILE_FORMAT = 2;
|
||||
private const int BTREE_DEFAULT_CACHE_SIZE = 3;
|
||||
private const int BTREE_LARGEST_ROOT_PAGE = 4;
|
||||
private const int BTREE_TEXT_ENCODING = 5;
|
||||
private const int BTREE_USER_VERSION = 6;
|
||||
private const int BTREE_INCR_VACUUM = 7;
|
||||
|
||||
//int sqlite3BtreeCursor(
|
||||
// Btree*, /* BTree containing table to open */
|
||||
// int iTable, /* Index of root page */
|
||||
// int wrFlag, /* 1 for writing. 0 for read-only */
|
||||
// struct KeyInfo*, /* First argument to compare function */
|
||||
// BtCursor pCursor /* Space to write cursor structure */
|
||||
//);
|
||||
//int sqlite3BtreeCursorSize(void);
|
||||
//void sqlite3BtreeCursorZero(BtCursor);
|
||||
|
||||
//int sqlite3BtreeCloseCursor(BtCursor);
|
||||
//int sqlite3BtreeMovetoUnpacked(
|
||||
// BtCursor*,
|
||||
// UnpackedRecord pUnKey,
|
||||
// i64 intKey,
|
||||
// int bias,
|
||||
// int pRes
|
||||
//);
|
||||
//int sqlite3BtreeCursorHasMoved(BtCursor*, int);
|
||||
//int sqlite3BtreeDelete(BtCursor);
|
||||
//int sqlite3BtreeInsert(BtCursor*, const void pKey, i64 nKey,
|
||||
// const void pData, int nData,
|
||||
// int nZero, int bias, int seekResult);
|
||||
//int sqlite3BtreeFirst(BtCursor*, int pRes);
|
||||
//int sqlite3BtreeLast(BtCursor*, int pRes);
|
||||
//int sqlite3BtreeNext(BtCursor*, int pRes);
|
||||
//int sqlite3BtreeEof(BtCursor);
|
||||
//int sqlite3BtreePrevious(BtCursor*, int pRes);
|
||||
//int sqlite3BtreeKeySize(BtCursor*, i64 pSize);
|
||||
//int sqlite3BtreeKey(BtCursor*, u32 offset, u32 amt, void);
|
||||
//const void *sqlite3BtreeKeyFetch(BtCursor*, int pAmt);
|
||||
//const void *sqlite3BtreeDataFetch(BtCursor*, int pAmt);
|
||||
//int sqlite3BtreeDataSize(BtCursor*, u32 pSize);
|
||||
//int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void);
|
||||
//void sqlite3BtreeSetCachedRowid(BtCursor*, sqlite3_int64);
|
||||
//sqlite3_int64 sqlite3BtreeGetCachedRowid(BtCursor);
|
||||
|
||||
//char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int);
|
||||
//struct Pager *sqlite3BtreePager(Btree);
|
||||
|
||||
//int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void);
|
||||
//void sqlite3BtreeCacheOverflow(BtCursor );
|
||||
//void sqlite3BtreeClearCursor(BtCursor );
|
||||
|
||||
//int sqlite3BtreeSetVersion(Btree *pBt, int iVersion);
|
||||
|
||||
//#if !NDEBUG
|
||||
//int sqlite3BtreeCursorIsValid(BtCursor);
|
||||
//#endif
|
||||
|
||||
//#if !SQLITE_OMIT_BTREECOUNT
|
||||
//int sqlite3BtreeCount(BtCursor *, i64 );
|
||||
//#endif
|
||||
|
||||
//#if SQLITE_TEST
|
||||
//int sqlite3BtreeCursorInfo(BtCursor*, int*, int);
|
||||
//void sqlite3BtreeCursorList(Btree);
|
||||
//#endif
|
||||
|
||||
#if !SQLITE_OMIT_WAL
|
||||
//int sqlite3BtreeCheckpoint(Btree*, int, int *, int );
|
||||
#endif
|
||||
|
||||
/*
|
||||
** If we are not using shared cache, then there is no need to
|
||||
** use mutexes to access the BtShared structures. So make the
|
||||
** Enter and Leave procedures no-ops.
|
||||
*/
|
||||
#if !SQLITE_OMIT_SHARED_CACHE
|
||||
//void sqlite3BtreeEnter(Btree);
|
||||
//void sqlite3BtreeEnterAll(sqlite3);
|
||||
#else
|
||||
|
||||
//# define sqlite3BtreeEnter(X)
|
||||
private static void sqlite3BtreeEnter(Btree bt)
|
||||
{
|
||||
}
|
||||
|
||||
//# define sqlite3BtreeEnterAll(X)
|
||||
private static void sqlite3BtreeEnterAll(sqlite3 p)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE
|
||||
//int sqlite3BtreeSharable(Btree);
|
||||
//void sqlite3BtreeLeave(Btree);
|
||||
//void sqlite3BtreeEnterCursor(BtCursor);
|
||||
//void sqlite3BtreeLeaveCursor(BtCursor);
|
||||
//void sqlite3BtreeLeaveAll(sqlite3);
|
||||
#if !NDEBUG
|
||||
/* These routines are used inside Debug.Assert() statements only. */
|
||||
int sqlite3BtreeHoldsMutex(Btree);
|
||||
int sqlite3BtreeHoldsAllMutexes(sqlite3);
|
||||
int sqlite3SchemaMutexHeld(sqlite3*,int,Schema);
|
||||
#endif
|
||||
#else
|
||||
|
||||
//# define sqlite3BtreeSharable(X) 0
|
||||
private static bool sqlite3BtreeSharable(Btree X)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//# define sqlite3BtreeLeave(X)
|
||||
private static void sqlite3BtreeLeave(Btree X)
|
||||
{
|
||||
}
|
||||
|
||||
//# define sqlite3BtreeEnterCursor(X)
|
||||
private static void sqlite3BtreeEnterCursor(BtCursor X)
|
||||
{
|
||||
}
|
||||
|
||||
//# define sqlite3BtreeLeaveCursor(X)
|
||||
private static void sqlite3BtreeLeaveCursor(BtCursor X)
|
||||
{
|
||||
}
|
||||
|
||||
//# define sqlite3BtreeLeaveAll(X)
|
||||
private static void sqlite3BtreeLeaveAll(sqlite3 X)
|
||||
{
|
||||
}
|
||||
|
||||
//# define sqlite3BtreeHoldsMutex(X) 1
|
||||
private static bool sqlite3BtreeHoldsMutex(Btree X)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//# define sqlite3BtreeHoldsAllMutexes(X) 1
|
||||
private static bool sqlite3BtreeHoldsAllMutexes(sqlite3 X)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//# define sqlite3SchemaMutexHeld(X,Y,Z) 1
|
||||
private static bool sqlite3SchemaMutexHeld(sqlite3 X, int y, Schema z)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//#endif // * _BTREE_H_ */
|
||||
}
|
||||
}
|
||||
504
original/Community.CsharpSqlite/src/Delegates.cs
Normal file
504
original/Community.CsharpSqlite/src/Delegates.cs
Normal file
|
|
@ -0,0 +1,504 @@
|
|||
/*
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
*************************************************************************
|
||||
*/
|
||||
|
||||
using System.Text;
|
||||
using HANDLE = System.IntPtr;
|
||||
using i16 = System.Int16;
|
||||
using sqlite3_int64 = System.Int64;
|
||||
using u32 = System.UInt32;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
using DbPage = Sqlite3.PgHdr;
|
||||
using sqlite3_pcache = Sqlite3.PCache1;
|
||||
using sqlite3_stmt = Sqlite3.Vdbe;
|
||||
using sqlite3_value = Sqlite3.Mem;
|
||||
|
||||
public partial class Sqlite3
|
||||
{
|
||||
public delegate void dxAuth(object pAuthArg, int b, string c, string d, string e, string f);
|
||||
|
||||
public delegate int dxBusy(object pBtShared, int iValue);
|
||||
|
||||
public delegate void dxFreeAux(object pAuxArg);
|
||||
|
||||
public delegate int dxCallback(object pCallbackArg, sqlite3_int64 argc, object p2, object p3);
|
||||
|
||||
public delegate void dxalarmCallback(object pNotUsed, sqlite3_int64 iNotUsed, int size);
|
||||
|
||||
public delegate void dxCollNeeded(object pCollNeededArg, sqlite3 db, int eTextRep, string collationName);
|
||||
|
||||
public delegate int dxCommitCallback(object pCommitArg);
|
||||
|
||||
public delegate int dxCompare(object pCompareArg, int size1, string Key1, int size2, string Key2);
|
||||
|
||||
public delegate bool dxCompare4(string Key1, int size1, string Key2, int size2);
|
||||
|
||||
public delegate void dxDel(ref string pDelArg); // needs ref
|
||||
|
||||
public delegate void dxDelCollSeq(ref object pDelArg); // needs ref
|
||||
|
||||
public delegate void dxLog(object pLogArg, int i, string msg);
|
||||
|
||||
public delegate void dxLogcallback(object pCallbackArg, int argc, string p2);
|
||||
|
||||
public delegate void dxProfile(object pProfileArg, string msg, sqlite3_int64 time);
|
||||
|
||||
public delegate int dxProgress(object pProgressArg);
|
||||
|
||||
public delegate void dxRollbackCallback(object pRollbackArg);
|
||||
|
||||
public delegate void dxTrace(object pTraceArg, string msg);
|
||||
|
||||
public delegate void dxUpdateCallback(object pUpdateArg, int b, string c, string d, sqlite3_int64 e);
|
||||
|
||||
public delegate int dxWalCallback(object pWalArg, sqlite3 db, string zDb, int nEntry);
|
||||
|
||||
/*
|
||||
* FUNCTIONS
|
||||
*
|
||||
*/
|
||||
|
||||
public delegate void dxFunc(sqlite3_context ctx, int intValue, sqlite3_value[] value);
|
||||
|
||||
public delegate void dxStep(sqlite3_context ctx, int intValue, sqlite3_value[] value);
|
||||
|
||||
public delegate void dxFinal(sqlite3_context ctx);
|
||||
|
||||
public delegate void dxFDestroy(object pArg);
|
||||
|
||||
//
|
||||
public delegate string dxColname(sqlite3_value pVal);
|
||||
|
||||
public delegate int dxFuncBtree(Btree p);
|
||||
|
||||
public delegate int dxExprTreeFunction(ref int pArg, Expr pExpr);
|
||||
|
||||
public delegate int dxExprTreeFunction_NC(NameContext pArg, ref Expr pExpr);
|
||||
|
||||
public delegate int dxExprTreeFunction_OBJ(object pArg, Expr pExpr);
|
||||
|
||||
/*
|
||||
VFS Delegates
|
||||
*/
|
||||
|
||||
public delegate int dxClose(sqlite3_file File_ID);
|
||||
|
||||
public delegate int dxCheckReservedLock(sqlite3_file File_ID, ref int pRes);
|
||||
|
||||
public delegate int dxDeviceCharacteristics(sqlite3_file File_ID);
|
||||
|
||||
public delegate int dxFileControl(sqlite3_file File_ID, int op, ref sqlite3_int64 pArgs);
|
||||
|
||||
public delegate int dxFileSize(sqlite3_file File_ID, ref long size);
|
||||
|
||||
public delegate int dxLock(sqlite3_file File_ID, int locktype);
|
||||
|
||||
public delegate int dxRead(sqlite3_file File_ID, byte[] buffer, int amount, sqlite3_int64 offset);
|
||||
|
||||
public delegate int dxSectorSize(sqlite3_file File_ID);
|
||||
|
||||
public delegate int dxSync(sqlite3_file File_ID, int flags);
|
||||
|
||||
public delegate int dxTruncate(sqlite3_file File_ID, sqlite3_int64 size);
|
||||
|
||||
public delegate int dxUnlock(sqlite3_file File_ID, int locktype);
|
||||
|
||||
public delegate int dxWrite(sqlite3_file File_ID, byte[] buffer, int amount, sqlite3_int64 offset);
|
||||
|
||||
public delegate int dxShmMap(sqlite3_file File_ID, int iPg, int pgsz, int pInt, out object pvolatile);
|
||||
|
||||
public delegate int dxShmLock(sqlite3_file File_ID, int offset, int n, int flags);
|
||||
|
||||
public delegate void dxShmBarrier(sqlite3_file File_ID);
|
||||
|
||||
public delegate int dxShmUnmap(sqlite3_file File_ID, int deleteFlag);
|
||||
|
||||
/*
|
||||
sqlite_vfs Delegates
|
||||
*/
|
||||
|
||||
public delegate int dxOpen(sqlite3_vfs vfs, string zName, sqlite3_file db, int flags, out int pOutFlags);
|
||||
|
||||
public delegate int dxDelete(sqlite3_vfs vfs, string zName, int syncDir);
|
||||
|
||||
public delegate int dxAccess(sqlite3_vfs vfs, string zName, int flags, out int pResOut);
|
||||
|
||||
public delegate int dxFullPathname(sqlite3_vfs vfs, string zName, int nOut, StringBuilder zOut);
|
||||
|
||||
public delegate HANDLE dxDlOpen(sqlite3_vfs vfs, string zFilename);
|
||||
|
||||
public delegate int dxDlError(sqlite3_vfs vfs, int nByte, string zErrMsg);
|
||||
|
||||
public delegate HANDLE dxDlSym(sqlite3_vfs vfs, HANDLE data, string zSymbol);
|
||||
|
||||
public delegate int dxDlClose(sqlite3_vfs vfs, HANDLE data);
|
||||
|
||||
public delegate int dxRandomness(sqlite3_vfs vfs, int nByte, byte[] buffer);
|
||||
|
||||
public delegate int dxSleep(sqlite3_vfs vfs, int microseconds);
|
||||
|
||||
public delegate int dxCurrentTime(sqlite3_vfs vfs, ref double currenttime);
|
||||
|
||||
public delegate int dxGetLastError(sqlite3_vfs pVfs, int nBuf, ref string zBuf);
|
||||
|
||||
public delegate int dxCurrentTimeInt64(sqlite3_vfs pVfs, ref sqlite3_int64 pTime);
|
||||
|
||||
public delegate int dxSetSystemCall(sqlite3_vfs pVfs, string zName, sqlite3_int64 sqlite3_syscall_ptr);
|
||||
|
||||
public delegate int dxGetSystemCall(sqlite3_vfs pVfs, string zName, sqlite3_int64 sqlite3_syscall_ptr);
|
||||
|
||||
public delegate int dxNextSystemCall(sqlite3_vfs pVfs, string zName, sqlite3_int64 sqlite3_syscall_ptr);
|
||||
|
||||
/*
|
||||
* Pager Delegates
|
||||
*/
|
||||
|
||||
public delegate void dxDestructor(DbPage dbPage); /* Call this routine when freeing pages */
|
||||
|
||||
public delegate int dxBusyHandler(object pBusyHandlerArg);
|
||||
|
||||
public delegate void dxReiniter(DbPage dbPage); /* Call this routine when reloading pages */
|
||||
|
||||
public delegate void dxFreeSchema(Schema schema);
|
||||
|
||||
#if SQLITE_HAS_CODEC
|
||||
|
||||
public delegate byte[] dxCodec(codec_ctx pCodec, byte[] D, uint pageNumber, int X); //void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
|
||||
|
||||
public delegate void dxCodecSizeChng(codec_ctx pCodec, int pageSize, i16 nReserve); //void (*xCodecSizeChng)(void*,int,int); /* Notify of page size changes */
|
||||
|
||||
public delegate void dxCodecFree(ref codec_ctx pCodec); //void (*xCodecFree)(void); /* Destructor for the codec */
|
||||
|
||||
#endif
|
||||
|
||||
//Module
|
||||
public delegate void dxDestroy(ref PgHdr pDestroyArg);
|
||||
|
||||
public delegate int dxStress(object obj, PgHdr pPhHdr);
|
||||
|
||||
//sqlite3_module
|
||||
public delegate int smdxCreateConnect(sqlite3 db, object pAux, int argc, string[] constargv, out sqlite3_vtab ppVTab, out string pError);
|
||||
|
||||
public delegate int smdxBestIndex(sqlite3_vtab pVTab, ref sqlite3_index_info pIndex);
|
||||
|
||||
public delegate int smdxDisconnect(ref object pVTab);
|
||||
|
||||
public delegate int smdxDestroy(ref object pVTab);
|
||||
|
||||
public delegate int smdxOpen(sqlite3_vtab pVTab, out sqlite3_vtab_cursor ppCursor);
|
||||
|
||||
public delegate int smdxClose(ref sqlite3_vtab_cursor pCursor);
|
||||
|
||||
public delegate int smdxFilter(sqlite3_vtab_cursor pCursor, int idxNum, string idxStr, int argc, sqlite3_value[] argv);
|
||||
|
||||
public delegate int smdxNext(sqlite3_vtab_cursor pCursor);
|
||||
|
||||
public delegate int smdxEof(sqlite3_vtab_cursor pCursor);
|
||||
|
||||
public delegate int smdxColumn(sqlite3_vtab_cursor pCursor, sqlite3_context p2, int p3);
|
||||
|
||||
public delegate int smdxRowid(sqlite3_vtab_cursor pCursor, out sqlite3_int64 pRowid);
|
||||
|
||||
public delegate int smdxUpdate(sqlite3_vtab pVTab, int p1, sqlite3_value[] p2, out sqlite3_int64 p3);
|
||||
|
||||
public delegate int smdxFunction(sqlite3_vtab pVTab);
|
||||
|
||||
public delegate int smdxFindFunction(sqlite3_vtab pVtab, int nArg, string zName, ref dxFunc pxFunc, ref object ppArg);
|
||||
|
||||
public delegate int smdxRename(sqlite3_vtab pVtab, string zNew);
|
||||
|
||||
public delegate int smdxFunctionArg(sqlite3_vtab pVTab, int nArg);
|
||||
|
||||
//AutoExtention
|
||||
public delegate int dxInit(sqlite3 db, ref string zMessage, sqlite3_api_routines sar);
|
||||
|
||||
#if !SQLITE_OMIT_VIRTUALTABLE
|
||||
|
||||
public delegate int dmxCreate(sqlite3 db, object pAux, int argc, string p4, object argv, sqlite3_vtab ppVTab, char p7);
|
||||
|
||||
public delegate int dmxConnect(sqlite3 db, object pAux, int argc, string p4, object argv, sqlite3_vtab ppVTab, char p7);
|
||||
|
||||
public delegate int dmxBestIndex(sqlite3_vtab pVTab, ref sqlite3_index_info pIndexInfo);
|
||||
|
||||
public delegate int dmxDisconnect(sqlite3_vtab pVTab);
|
||||
|
||||
public delegate int dmxDestroy(sqlite3_vtab pVTab);
|
||||
|
||||
public delegate int dmxOpen(sqlite3_vtab pVTab, sqlite3_vtab_cursor ppCursor);
|
||||
|
||||
public delegate int dmxClose(sqlite3_vtab_cursor pCursor);
|
||||
|
||||
public delegate int dmxFilter(sqlite3_vtab_cursor pCursor, int idmxNum, string idmxStr, int argc, sqlite3_value argv);
|
||||
|
||||
public delegate int dmxNext(sqlite3_vtab_cursor pCursor);
|
||||
|
||||
public delegate int dmxEof(sqlite3_vtab_cursor pCursor);
|
||||
|
||||
public delegate int dmxColumn(sqlite3_vtab_cursor pCursor, sqlite3_context ctx, int i3);
|
||||
|
||||
public delegate int dmxRowid(sqlite3_vtab_cursor pCursor, sqlite3_int64 pRowid);
|
||||
|
||||
public delegate int dmxUpdate(sqlite3_vtab pVTab, int i2, sqlite3_value sv3, sqlite3_int64 v4);
|
||||
|
||||
public delegate int dmxBegin(sqlite3_vtab pVTab);
|
||||
|
||||
public delegate int dmxSync(sqlite3_vtab pVTab);
|
||||
|
||||
public delegate int dmxCommit(sqlite3_vtab pVTab);
|
||||
|
||||
public delegate int dmxRollback(sqlite3_vtab pVTab);
|
||||
|
||||
public delegate int dmxFindFunction(sqlite3_vtab pVtab, int nArg, string zName);
|
||||
|
||||
public delegate int dmxRename(sqlite3_vtab pVtab, string zNew);
|
||||
|
||||
#endif
|
||||
|
||||
//Faults
|
||||
public delegate void void_function();
|
||||
|
||||
//Mem Methods
|
||||
public delegate int dxMemInit(object o);
|
||||
|
||||
public delegate void dxMemShutdown(object o);
|
||||
|
||||
public delegate byte[] dxMalloc(int nSize);
|
||||
|
||||
public delegate int[] dxMallocInt(int nSize);
|
||||
|
||||
public delegate Mem dxMallocMem(Mem pMem);
|
||||
|
||||
public delegate void dxFree(ref byte[] pOld);
|
||||
|
||||
public delegate void dxFreeInt(ref int[] pOld);
|
||||
|
||||
public delegate void dxFreeMem(ref Mem pOld);
|
||||
|
||||
public delegate byte[] dxRealloc(byte[] pOld, int nSize);
|
||||
|
||||
public delegate int dxSize(byte[] pArray);
|
||||
|
||||
public delegate int dxRoundup(int nSize);
|
||||
|
||||
//Mutex Methods
|
||||
public delegate int dxMutexInit();
|
||||
|
||||
public delegate int dxMutexEnd();
|
||||
|
||||
public delegate sqlite3_mutex dxMutexAlloc(int iNumber);
|
||||
|
||||
public delegate void dxMutexFree(sqlite3_mutex sm);
|
||||
|
||||
public delegate void dxMutexEnter(sqlite3_mutex sm);
|
||||
|
||||
public delegate int dxMutexTry(sqlite3_mutex sm);
|
||||
|
||||
public delegate void dxMutexLeave(sqlite3_mutex sm);
|
||||
|
||||
public delegate bool dxMutexHeld(sqlite3_mutex sm);
|
||||
|
||||
public delegate bool dxMutexNotheld(sqlite3_mutex sm);
|
||||
|
||||
public delegate object dxColumn(sqlite3_stmt pStmt, int i);
|
||||
|
||||
public delegate int dxColumn_I(sqlite3_stmt pStmt, int i);
|
||||
|
||||
// Walker Methods
|
||||
public delegate int dxExprCallback(Walker W, ref Expr E); /* Callback for expressions */
|
||||
|
||||
public delegate int dxSelectCallback(Walker W, Select S); /* Callback for SELECTs */
|
||||
|
||||
// pcache Methods
|
||||
public delegate int dxPC_Init(object NotUsed);
|
||||
|
||||
public delegate void dxPC_Shutdown(object NotUsed);
|
||||
|
||||
public delegate sqlite3_pcache dxPC_Create(int szPage, bool bPurgeable);
|
||||
|
||||
public delegate void dxPC_Cachesize(sqlite3_pcache pCache, int nCachesize);
|
||||
|
||||
public delegate int dxPC_Pagecount(sqlite3_pcache pCache);
|
||||
|
||||
public delegate PgHdr dxPC_Fetch(sqlite3_pcache pCache, u32 key, int createFlag);
|
||||
|
||||
public delegate void dxPC_Unpin(sqlite3_pcache pCache, PgHdr p2, bool discard);
|
||||
|
||||
public delegate void dxPC_Rekey(sqlite3_pcache pCache, PgHdr p2, u32 oldKey, u32 newKey);
|
||||
|
||||
public delegate void dxPC_Truncate(sqlite3_pcache pCache, u32 iLimit);
|
||||
|
||||
public delegate void dxPC_Destroy(ref sqlite3_pcache pCache);
|
||||
|
||||
public delegate void dxIter(PgHdr p);
|
||||
|
||||
#if NET_35 || NET_40
|
||||
//API Simplifications -- Actions
|
||||
public static Action<sqlite3_context, String, Int32, dxDel> ResultBlob = sqlite3_result_blob;
|
||||
public static Action<sqlite3_context, Double> ResultDouble = sqlite3_result_double;
|
||||
public static Action<sqlite3_context, String, Int32> ResultError = sqlite3_result_error;
|
||||
public static Action<sqlite3_context, Int32> ResultErrorCode = sqlite3_result_error_code;
|
||||
public static Action<sqlite3_context> ResultErrorNoMem = sqlite3_result_error_nomem;
|
||||
public static Action<sqlite3_context> ResultErrorTooBig = sqlite3_result_error_toobig;
|
||||
public static Action<sqlite3_context, Int32> ResultInt = sqlite3_result_int;
|
||||
public static Action<sqlite3_context, Int64> ResultInt64 = sqlite3_result_int64;
|
||||
public static Action<sqlite3_context> ResultNull = sqlite3_result_null;
|
||||
public static Action<sqlite3_context, String, Int32, dxDel> ResultText = sqlite3_result_text;
|
||||
public static Action<sqlite3_context, String, Int32, Int32, dxDel> ResultText_Offset = sqlite3_result_text;
|
||||
public static Action<sqlite3_context, sqlite3_value> ResultValue = sqlite3_result_value;
|
||||
public static Action<sqlite3_context, Int32> ResultZeroblob = sqlite3_result_zeroblob;
|
||||
public static Action<sqlite3_context, Int32, String> SetAuxdata = sqlite3_set_auxdata;
|
||||
|
||||
//API Simplifications -- Functions
|
||||
public delegate Int32 FinalizeDelegate( sqlite3_stmt pStmt );
|
||||
public static FinalizeDelegate Finalize = sqlite3_finalize;
|
||||
|
||||
public static Func<sqlite3_stmt, Int32> ClearBindings = sqlite3_clear_bindings;
|
||||
public static Func<sqlite3_stmt, Int32, Byte[]> ColumnBlob = sqlite3_column_blob;
|
||||
public static Func<sqlite3_stmt, Int32, Int32> ColumnBytes = sqlite3_column_bytes;
|
||||
public static Func<sqlite3_stmt, Int32, Int32> ColumnBytes16 = sqlite3_column_bytes16;
|
||||
public static Func<sqlite3_stmt, Int32> ColumnCount = sqlite3_column_count;
|
||||
public static Func<sqlite3_stmt, Int32, String> ColumnDecltype = sqlite3_column_decltype;
|
||||
public static Func<sqlite3_stmt, Int32, Double> ColumnDouble = sqlite3_column_double;
|
||||
public static Func<sqlite3_stmt, Int32, Int32> ColumnInt = sqlite3_column_int;
|
||||
public static Func<sqlite3_stmt, Int32, Int64> ColumnInt64 = sqlite3_column_int64;
|
||||
public static Func<sqlite3_stmt, Int32, String> ColumnName = sqlite3_column_name;
|
||||
public static Func<sqlite3_stmt, Int32, String> ColumnText = sqlite3_column_text;
|
||||
public static Func<sqlite3_stmt, Int32, Int32> ColumnType = sqlite3_column_type;
|
||||
public static Func<sqlite3_stmt, Int32, sqlite3_value> ColumnValue = sqlite3_column_value;
|
||||
public static Func<sqlite3_stmt, Int32> DataCount = sqlite3_data_count;
|
||||
public static Func<sqlite3_stmt, Int32> Reset = sqlite3_reset;
|
||||
public static Func<sqlite3_stmt, Int32> Step = sqlite3_step;
|
||||
|
||||
public static Func<sqlite3_stmt, Int32, Byte[], Int32, dxDel, Int32> BindBlob = sqlite3_bind_blob;
|
||||
public static Func<sqlite3_stmt, Int32, Double, Int32> BindDouble = sqlite3_bind_double;
|
||||
public static Func<sqlite3_stmt, Int32, Int32, Int32> BindInt = sqlite3_bind_int;
|
||||
public static Func<sqlite3_stmt, Int32, Int64, Int32> BindInt64 = sqlite3_bind_int64;
|
||||
public static Func<sqlite3_stmt, Int32, Int32> BindNull = sqlite3_bind_null;
|
||||
public static Func<sqlite3_stmt, Int32> BindParameterCount = sqlite3_bind_parameter_count;
|
||||
public static Func<sqlite3_stmt, String, Int32> BindParameterIndex = sqlite3_bind_parameter_index;
|
||||
public static Func<sqlite3_stmt, Int32, String> BindParameterName = sqlite3_bind_parameter_name;
|
||||
public static Func<sqlite3_stmt, Int32, String, Int32, dxDel, Int32> BindText = sqlite3_bind_text;
|
||||
public static Func<sqlite3_stmt, Int32, sqlite3_value, Int32> BindValue = sqlite3_bind_value;
|
||||
public static Func<sqlite3_stmt, Int32, Int32, Int32> BindZeroblob = sqlite3_bind_zeroblob;
|
||||
|
||||
public delegate Int32 OpenDelegate( string zFilename, out sqlite3 ppDb );
|
||||
public static Func<sqlite3, Int32> Close = sqlite3_close;
|
||||
public static Func<sqlite3_stmt, sqlite3> DbHandle = sqlite3_db_handle;
|
||||
public static Func<sqlite3, String> Errmsg = sqlite3_errmsg;
|
||||
public static OpenDelegate Open = sqlite3_open;
|
||||
public static Func<sqlite3, sqlite3_stmt, sqlite3_stmt> NextStmt = sqlite3_next_stmt;
|
||||
public static Func<Int32> Shutdown = sqlite3_shutdown;
|
||||
public static Func<sqlite3_stmt, Int32, Int32, Int32> StmtStatus = sqlite3_stmt_status;
|
||||
|
||||
public delegate Int32 PrepareDelegate( sqlite3 db, String zSql, Int32 nBytes, ref sqlite3_stmt ppStmt, ref string pzTail );
|
||||
public delegate Int32 PrepareDelegateNoTail( sqlite3 db, String zSql, Int32 nBytes, ref sqlite3_stmt ppStmt, Int32 iDummy );
|
||||
public static PrepareDelegate Prepare = sqlite3_prepare;
|
||||
public static PrepareDelegate PrepareV2 = sqlite3_prepare_v2;
|
||||
public static PrepareDelegateNoTail PrepareV2NoTail = sqlite3_prepare_v2;
|
||||
|
||||
public static Func<sqlite3_context, Int32, Mem> AggregateContext = sqlite3_aggregate_context;
|
||||
public static Func<sqlite3_context, Int32, Object> GetAuxdata = sqlite3_get_auxdata;
|
||||
public static Func<sqlite3_context, sqlite3> ContextDbHandle = sqlite3_context_db_handle;
|
||||
public static Func<sqlite3_context, Object> UserData = sqlite3_user_data;
|
||||
|
||||
public static Func<sqlite3_value, Byte[]> ValueBlob = sqlite3_value_blob;
|
||||
public static Func<sqlite3_value, Int32> ValueBytes = sqlite3_value_bytes;
|
||||
public static Func<sqlite3_value, Int32> ValueBytes16 = sqlite3_value_bytes16;
|
||||
public static Func<sqlite3_value, Double> ValueDouble = sqlite3_value_double;
|
||||
public static Func<sqlite3_value, Int32> ValueInt = sqlite3_value_int;
|
||||
public static Func<sqlite3_value, Int64> ValueInt64 = sqlite3_value_int64;
|
||||
public static Func<sqlite3_value, String> ValueText = sqlite3_value_text;
|
||||
public static Func<sqlite3_value, Int32> ValueType = sqlite3_value_type;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if( NET_35 && !NET_40) || WINDOWS_PHONE
|
||||
namespace System
|
||||
{
|
||||
// Summary:
|
||||
// Encapsulates a method that has four parameters and does not return a value.
|
||||
//
|
||||
// Parameters:
|
||||
// arg1:
|
||||
// The first parameter of the method that this delegate encapsulates.
|
||||
//
|
||||
// arg2:
|
||||
// The second parameter of the method that this delegate encapsulates.
|
||||
//
|
||||
// arg3:
|
||||
// The third parameter of the method that this delegate encapsulates.
|
||||
//
|
||||
// arg4:
|
||||
// The fourth parameter of the method that this delegate encapsulates.
|
||||
//
|
||||
// arg5:
|
||||
// The fifth parameter of the method that this delegate encapsulates.
|
||||
//
|
||||
// Type parameters:
|
||||
// T1:
|
||||
// The type of the first parameter of the method that this delegate encapsulates.
|
||||
//
|
||||
// T2:
|
||||
// The type of the second parameter of the method that this delegate encapsulates.
|
||||
//
|
||||
// T3:
|
||||
// The type of the third parameter of the method that this delegate encapsulates.
|
||||
//
|
||||
// T4:
|
||||
// The type of the fourth parameter of the method that this delegate encapsulates.
|
||||
//
|
||||
// T5:
|
||||
// The type of the fifth parameter of the method that this delegate encapsulates.
|
||||
public delegate void Action<T1, T2, T3, T4, T5>( T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5 );
|
||||
|
||||
// Summary:
|
||||
// Encapsulates a method that has three parameters and returns a value of the
|
||||
// type specified by the TResult parameter.
|
||||
//
|
||||
// Parameters:
|
||||
// arg1:
|
||||
// The first parameter of the method that this delegate encapsulates.
|
||||
//
|
||||
// arg2:
|
||||
// The second parameter of the method that this delegate encapsulates.
|
||||
//
|
||||
// arg3:
|
||||
// The third parameter of the method that this delegate encapsulates.
|
||||
//
|
||||
// arg4:
|
||||
// The fourth parameter of the method that this delegate encapsulates.
|
||||
//
|
||||
// arg5:
|
||||
// The fifth parameter of the method that this delegate encapsulates.
|
||||
//
|
||||
// Type parameters:
|
||||
// T1:
|
||||
// The type of the first parameter of the method that this delegate encapsulates.
|
||||
//
|
||||
// T2:
|
||||
// The type of the second parameter of the method that this delegate encapsulates.
|
||||
//
|
||||
// T3:
|
||||
// The type of the third parameter of the method that this delegate encapsulates.
|
||||
//
|
||||
// T4:
|
||||
// The type of the fourth parameter of the method that this delegate encapsulates.
|
||||
//
|
||||
// T5:
|
||||
// The type of the fifth parameter of the method that this delegate encapsulates.
|
||||
//
|
||||
// TResult:
|
||||
// The type of the return value of the method that this delegate encapsulates.
|
||||
//
|
||||
// Returns:
|
||||
// The return value of the method that this delegate encapsulates.
|
||||
public delegate TResult Func<T1, T2, T3, T4, TResult>( T1 arg1, T2 arg2, T3 arg3, T4 arg4 );
|
||||
public delegate TResult Func<T1, T2, T3, T4, T5, TResult>( T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5 );
|
||||
}
|
||||
#endif
|
||||
147
original/Community.CsharpSqlite/src/Hash_h.cs
Normal file
147
original/Community.CsharpSqlite/src/Hash_h.cs
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
using u32 = System.UInt32;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2001 September 22
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This is the header file for the generic hash-table implemenation
|
||||
** used in SQLite.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2010-08-23 18:52:01 42537b60566f288167f1b5864a5435986838e3a3
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#if !_SQLITE_HASH_H_
|
||||
//#define _SQLITE_HASH_H_
|
||||
|
||||
/* Forward declarations of structures. */
|
||||
//typedef struct Hash Hash;
|
||||
//typedef struct HashElem HashElem;
|
||||
|
||||
/* A complete hash table is an instance of the following structure.
|
||||
** The internals of this structure are intended to be opaque -- client
|
||||
** code should not attempt to access or modify the fields of this structure
|
||||
** directly. Change this structure only by using the routines below.
|
||||
** However, some of the "procedures" and "functions" for modifying and
|
||||
** accessing this structure are really macros, so we can't really make
|
||||
** this structure opaque.
|
||||
**
|
||||
** All elements of the hash table are on a single doubly-linked list.
|
||||
** Hash.first points to the head of this list.
|
||||
**
|
||||
** There are Hash.htsize buckets. Each bucket points to a spot in
|
||||
** the global doubly-linked list. The contents of the bucket are the
|
||||
** element pointed to plus the next _ht.count-1 elements in the list.
|
||||
**
|
||||
** Hash.htsize and Hash.ht may be zero. In that case lookup is done
|
||||
** by a linear search of the global list. For small tables, the
|
||||
** Hash.ht table is never allocated because if there are few elements
|
||||
** in the table, it is faster to do a linear search than to manage
|
||||
** the hash table.
|
||||
*/
|
||||
|
||||
public class _ht
|
||||
{ /* the hash table */
|
||||
public int count; /* Number of entries with this hash */
|
||||
public HashElem chain; /* Pointer to first entry with this hash */
|
||||
};
|
||||
|
||||
public class Hash
|
||||
{
|
||||
public u32 htsize = 31; /* Number of buckets in the hash table */
|
||||
public u32 count; /* Number of entries in this table */
|
||||
public HashElem first; /* The first element of the array */
|
||||
public _ht[] ht;
|
||||
|
||||
public Hash Copy()
|
||||
{
|
||||
if (this == null)
|
||||
return null;
|
||||
else
|
||||
{
|
||||
Hash cp = (Hash)MemberwiseClone();
|
||||
return cp;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* Each element in the hash table is an instance of the following
|
||||
** structure. All elements are stored on a single doubly-linked list.
|
||||
**
|
||||
** Again, this structure is intended to be opaque, but it can't really
|
||||
** be opaque because it is used by macros.
|
||||
*/
|
||||
|
||||
public class HashElem
|
||||
{
|
||||
public HashElem next;
|
||||
public HashElem prev; /* Next and previous elements in the table */
|
||||
public object data; /* Data associated with this element */
|
||||
public string pKey;
|
||||
public int nKey; /* Key associated with this element */
|
||||
};
|
||||
|
||||
/*
|
||||
** Access routines. To delete, insert a NULL pointer.
|
||||
*/
|
||||
//void sqlite3HashInit(Hash);
|
||||
//void *sqlite3HashInsert(Hash*, string pKey, int nKey, object *pData);
|
||||
//void *sqlite3HashFind(const Hash*, string pKey, int nKey);
|
||||
//void sqlite3HashClear(Hash);
|
||||
|
||||
/*
|
||||
** Macros for looping over all elements of a hash table. The idiom is
|
||||
** like this:
|
||||
**
|
||||
** Hash h;
|
||||
** HashElem p;
|
||||
** ...
|
||||
** for(p=sqliteHashFirst(&h); p; p=sqliteHashNext(p)){
|
||||
** SomeStructure pData = sqliteHashData(p);
|
||||
** // do something with pData
|
||||
** }
|
||||
*/
|
||||
|
||||
//#define sqliteHashFirst(H) ((H).first)
|
||||
private static HashElem sqliteHashFirst(Hash H)
|
||||
{
|
||||
return H.first;
|
||||
}
|
||||
|
||||
//#define sqliteHashNext(E) ((E).next)
|
||||
private static HashElem sqliteHashNext(HashElem E)
|
||||
{
|
||||
return E.next;
|
||||
}
|
||||
|
||||
//#define sqliteHashData(E) ((E).data)
|
||||
private static object sqliteHashData(HashElem E)
|
||||
{
|
||||
return E.data;
|
||||
}
|
||||
|
||||
/* #define sqliteHashKey(E) ((E)->pKey) // NOT USED */
|
||||
/* #define sqliteHashKeysize(E) ((E)->nKey) // NOT USED */
|
||||
|
||||
/*
|
||||
** Number of entries in a hash table
|
||||
*/
|
||||
/* #define sqliteHashCount(H) ((H)->count) // NOT USED */
|
||||
|
||||
//#endif // * _SQLITE_HASH_H_ */
|
||||
}
|
||||
}
|
||||
704
original/Community.CsharpSqlite/src/VdbeInt_h.cs
Normal file
704
original/Community.CsharpSqlite/src/VdbeInt_h.cs
Normal file
|
|
@ -0,0 +1,704 @@
|
|||
using System;
|
||||
|
||||
using FILE = System.IO.TextWriter;
|
||||
|
||||
using i64 = System.Int64;
|
||||
using u8 = System.Byte;
|
||||
using u16 = System.UInt16;
|
||||
using u32 = System.UInt32;
|
||||
|
||||
using Pgno = System.UInt32;
|
||||
|
||||
#if !SQLITE_MAX_VARIABLE_NUMBER
|
||||
|
||||
using ynVar = System.Int16;
|
||||
|
||||
#else
|
||||
using ynVar = System.Int32;
|
||||
#endif
|
||||
/*
|
||||
** The yDbMask datatype for the bitmask of all attached databases.
|
||||
*/
|
||||
#if SQLITE_MAX_ATTACHED//>30
|
||||
// typedef sqlite3_uint64 yDbMask;
|
||||
using yDbMask = System.Int64;
|
||||
#else
|
||||
|
||||
// typedef unsigned int yDbMask;
|
||||
using yDbMask = System.Int32;
|
||||
|
||||
#endif
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
using Op = Sqlite3.VdbeOp;
|
||||
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2003 September 6
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This is the header file for information that is private to the
|
||||
** VDBE. This information used to all be at the top of the single
|
||||
** source code file "vdbe.c". When that file became too big (over
|
||||
** 6000 lines long) it was split up into several smaller files and
|
||||
** this header information was factored out.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#if !_VDBEINT_H_
|
||||
//#define _VDBEINT_H_
|
||||
|
||||
/*
|
||||
** SQL is translated into a sequence of instructions to be
|
||||
** executed by a virtual machine. Each instruction is an instance
|
||||
** of the following structure.
|
||||
*/
|
||||
//typedef struct VdbeOp Op;
|
||||
|
||||
/*
|
||||
** Boolean values
|
||||
*/
|
||||
//typedef unsigned char Bool;
|
||||
|
||||
/*
|
||||
** A cursor is a pointer into a single BTree within a database file.
|
||||
** The cursor can seek to a BTree entry with a particular key, or
|
||||
** loop over all entries of the Btree. You can also insert new BTree
|
||||
** entries or retrieve the key or data from the entry that the cursor
|
||||
** is currently pointing to.
|
||||
**
|
||||
** Every cursor that the virtual machine has open is represented by an
|
||||
** instance of the following structure.
|
||||
*/
|
||||
|
||||
public class VdbeCursor
|
||||
{
|
||||
public BtCursor pCursor; /* The cursor structure of the backend */
|
||||
public Btree pBt; /* Separate file holding temporary table */
|
||||
public KeyInfo pKeyInfo; /* Info about index keys needed by index cursors */
|
||||
public int iDb; /* Index of cursor database in db->aDb[] (or -1) */
|
||||
public int pseudoTableReg; /* Register holding pseudotable content. */
|
||||
public int nField; /* Number of fields in the header */
|
||||
public bool zeroed; /* True if zeroed out and ready for reuse */
|
||||
public bool rowidIsValid; /* True if lastRowid is valid */
|
||||
public bool atFirst; /* True if pointing to first entry */
|
||||
public bool useRandomRowid; /* Generate new record numbers semi-randomly */
|
||||
public bool nullRow; /* True if pointing to a row with no data */
|
||||
public bool deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
|
||||
public bool isTable; /* True if a table requiring integer keys */
|
||||
public bool isIndex; /* True if an index containing keys only - no data */
|
||||
public bool isOrdered; /* True if the underlying table is BTREE_UNORDERED */
|
||||
#if !SQLITE_OMIT_VIRTUALTABLE
|
||||
public sqlite3_vtab_cursor pVtabCursor; /* The cursor for a virtual table */
|
||||
public sqlite3_module pModule; /* Module for cursor pVtabCursor */
|
||||
#endif
|
||||
public i64 seqCount; /* Sequence counter */
|
||||
public i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
|
||||
public i64 lastRowid; /* Last rowid from a Next or NextIdx operation */
|
||||
|
||||
/* Result of last sqlite3BtreeMoveto() done by an OP_NotExists or
|
||||
** OP_IsUnique opcode on this cursor. */
|
||||
public int seekResult;
|
||||
|
||||
/* Cached information about the header for the data record that the
|
||||
** cursor is currently pointing to. Only valid if cacheStatus matches
|
||||
** Vdbe.cacheCtr. Vdbe.cacheCtr will never take on the value of
|
||||
** CACHE_STALE and so setting cacheStatus=CACHE_STALE guarantees that
|
||||
** the cache is out of date.
|
||||
**
|
||||
** aRow might point to (ephemeral) data for the current row, or it might
|
||||
** be NULL.
|
||||
*/
|
||||
public u32 cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */
|
||||
public Pgno payloadSize; /* Total number of bytes in the record */
|
||||
public u32[] aType; /* Type values for all entries in the record */
|
||||
public u32[] aOffset; /* Cached offsets to the start of each columns data */
|
||||
public int aRow; /* Pointer to Data for the current row, if all on one page */
|
||||
|
||||
public VdbeCursor Copy()
|
||||
{
|
||||
return (VdbeCursor)MemberwiseClone();
|
||||
}
|
||||
};
|
||||
|
||||
//typedef struct VdbeCursor VdbeCursor;
|
||||
|
||||
/*
|
||||
** When a sub-program is executed (OP_Program), a structure of this type
|
||||
** is allocated to store the current value of the program counter, as
|
||||
** well as the current memory cell array and various other frame specific
|
||||
** values stored in the Vdbe struct. When the sub-program is finished,
|
||||
** these values are copied back to the Vdbe from the VdbeFrame structure,
|
||||
** restoring the state of the VM to as it was before the sub-program
|
||||
** began executing.
|
||||
**
|
||||
** The memory for a VdbeFrame object is allocated and managed by a memory
|
||||
** cell in the parent (calling) frame. When the memory cell is deleted or
|
||||
** overwritten, the VdbeFrame object is not freed immediately. Instead, it
|
||||
** is linked into the Vdbe.pDelFrame list. The contents of the Vdbe.pDelFrame
|
||||
** list is deleted when the VM is reset in VdbeHalt(). The reason for doing
|
||||
** this instead of deleting the VdbeFrame immediately is to avoid recursive
|
||||
** calls to sqlite3VdbeMemRelease() when the memory cells belonging to the
|
||||
** child frame are released.
|
||||
**
|
||||
** The currently executing frame is stored in Vdbe.pFrame. Vdbe.pFrame is
|
||||
** set to NULL if the currently executing frame is the main program.
|
||||
*/
|
||||
|
||||
//typedef struct VdbeFrame VdbeFrame;
|
||||
public class VdbeFrame
|
||||
{
|
||||
public Vdbe v; /* VM this frame belongs to */
|
||||
public int pc; /* Program Counter in parent (calling) frame */
|
||||
public Op[] aOp; /* Program instructions for parent frame */
|
||||
public int nOp; /* Size of aOp array */
|
||||
public Mem[] aMem; /* Array of memory cells for parent frame */
|
||||
public int nMem; /* Number of entries in aMem */
|
||||
public VdbeCursor[] apCsr; /* Array of Vdbe cursors for parent frame */
|
||||
public u16 nCursor; /* Number of entries in apCsr */
|
||||
public int token; /* Copy of SubProgram.token */
|
||||
public int nChildMem; /* Number of memory cells for child frame */
|
||||
public int nChildCsr; /* Number of cursors for child frame */
|
||||
public i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
|
||||
public int nChange; /* Statement changes (Vdbe.nChanges) */
|
||||
public VdbeFrame pParent; /* Parent of this frame, or NULL if parent is main */
|
||||
|
||||
//
|
||||
// Needed for C# Implementation
|
||||
//
|
||||
public Mem[] aChildMem; /* Array of memory cells for child frame */
|
||||
|
||||
public VdbeCursor[] aChildCsr; /* Array of cursors for child frame */
|
||||
};
|
||||
|
||||
//#define VdbeFrameMem(p) ((Mem )&((u8 )p)[ROUND8(sizeof(VdbeFrame))])
|
||||
/*
|
||||
** A value for VdbeCursor.cacheValid that means the cache is always invalid.
|
||||
*/
|
||||
private const int CACHE_STALE = 0;
|
||||
|
||||
/*
|
||||
** Internally, the vdbe manipulates nearly all SQL values as Mem
|
||||
** structures. Each Mem struct may cache multiple representations (string,
|
||||
** integer etc.) of the same value.
|
||||
*/
|
||||
|
||||
public class Mem
|
||||
{
|
||||
public sqlite3 db; /* The associated database connection */
|
||||
public string z; /* String value */
|
||||
public double r; /* Real value */
|
||||
|
||||
public struct union_ip
|
||||
{
|
||||
#if DEBUG_CLASS_MEM || DEBUG_CLASS_ALL
|
||||
public i64 _i; /* First operand */
|
||||
public i64 i
|
||||
{
|
||||
get { return _i; }
|
||||
set { _i = value; }
|
||||
}
|
||||
#else
|
||||
public i64 i; /* Integer value used when MEM_Int is set in flags */
|
||||
#endif
|
||||
public int nZero; /* Used when bit MEM_Zero is set in flags */
|
||||
public FuncDef pDef; /* Used only when flags==MEM_Agg */
|
||||
public RowSet pRowSet; /* Used only when flags==MEM_RowSet */
|
||||
public VdbeFrame pFrame; /* Used when flags==MEM_Frame */
|
||||
};
|
||||
|
||||
public union_ip u;
|
||||
public byte[] zBLOB; /* BLOB value */
|
||||
public int n; /* Number of characters in string value, excluding '\0' */
|
||||
#if DEBUG_CLASS_MEM || DEBUG_CLASS_ALL
|
||||
public u16 _flags; /* First operand */
|
||||
public u16 flags
|
||||
{
|
||||
get { return _flags; }
|
||||
set { _flags = value; }
|
||||
}
|
||||
#else
|
||||
public u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
|
||||
#endif
|
||||
public u8 type; /* One of SQLITE_NULL, SQLITE_TEXT, SQLITE_INTEGER, etc */
|
||||
public u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
|
||||
#if SQLITE_DEBUG
|
||||
public Mem pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */
|
||||
public object pFiller; /* So that sizeof(Mem) is a multiple of 8 */
|
||||
#endif
|
||||
public dxDel xDel; /* If not null, call this function to delete Mem.z */
|
||||
|
||||
// Not used under c#
|
||||
//public string zMalloc; /* Dynamic buffer allocated by sqlite3Malloc() */
|
||||
public Mem _Mem; /* Used when C# overload Z as MEM space */
|
||||
|
||||
public SumCtx _SumCtx; /* Used when C# overload Z as Sum context */
|
||||
public SubProgram[] _SubProgram;/* Used when C# overload Z as SubProgram*/
|
||||
public StrAccum _StrAccum; /* Used when C# overload Z as STR context */
|
||||
public object _MD5Context; /* Used when C# overload Z as MD5 context */
|
||||
|
||||
public Mem()
|
||||
{
|
||||
}
|
||||
|
||||
public Mem(sqlite3 db, string z, double r, int i, int n, u16 flags, u8 type, u8 enc
|
||||
#if SQLITE_DEBUG
|
||||
, Mem pScopyFrom, object pFiller /* pScopyFrom, pFiller */
|
||||
#endif
|
||||
)
|
||||
{
|
||||
this.db = db;
|
||||
this.z = z;
|
||||
this.r = r;
|
||||
this.u.i = i;
|
||||
this.n = n;
|
||||
this.flags = flags;
|
||||
#if SQLITE_DEBUG
|
||||
this.pScopyFrom = pScopyFrom;
|
||||
this.pFiller = pFiller;
|
||||
#endif
|
||||
this.type = type;
|
||||
this.enc = enc;
|
||||
}
|
||||
|
||||
public void CopyTo(ref Mem ct)
|
||||
{
|
||||
if (ct == null)
|
||||
ct = new Mem();
|
||||
ct.u = u;
|
||||
ct.r = r;
|
||||
ct.db = db;
|
||||
ct.z = z;
|
||||
if (zBLOB == null)
|
||||
ct.zBLOB = null;
|
||||
else
|
||||
{
|
||||
ct.zBLOB = sqlite3Malloc(zBLOB.Length);
|
||||
Buffer.BlockCopy(zBLOB, 0, ct.zBLOB, 0, zBLOB.Length);
|
||||
}
|
||||
ct.n = n;
|
||||
ct.flags = flags;
|
||||
ct.type = type;
|
||||
ct.enc = enc;
|
||||
ct.xDel = xDel;
|
||||
}
|
||||
};
|
||||
|
||||
/* One or more of the following flags are set to indicate the validOK
|
||||
** representations of the value stored in the Mem struct.
|
||||
**
|
||||
** If the MEM_Null flag is set, then the value is an SQL NULL value.
|
||||
** No other flags may be set in this case.
|
||||
**
|
||||
** If the MEM_Str flag is set then Mem.z points at a string representation.
|
||||
** Usually this is encoded in the same unicode encoding as the main
|
||||
** 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_Null 0x0001 /* Value is NULL */
|
||||
//#define MEM_Str 0x0002 /* Value is a string */
|
||||
//#define MEM_Int 0x0004 /* Value is an integer */
|
||||
//#define MEM_Real 0x0008 /* Value is a real number */
|
||||
//#define MEM_Blob 0x0010 /* Value is a BLOB */
|
||||
//#define MEM_RowSet 0x0020 /* Value is a RowSet object */
|
||||
//#define MEM_Frame 0x0040 /* Value is a VdbeFrame object */
|
||||
//#define MEM_Invalid 0x0080 /* Value is undefined */
|
||||
//#define MEM_TypeMask 0x00ff /* Mask of type bits */
|
||||
private const int MEM_Null = 0x0001;
|
||||
|
||||
private const int MEM_Str = 0x0002;
|
||||
private const int MEM_Int = 0x0004;
|
||||
private const int MEM_Real = 0x0008;
|
||||
private const int MEM_Blob = 0x0010;
|
||||
private const int MEM_RowSet = 0x0020;
|
||||
private const int MEM_Frame = 0x0040;
|
||||
private const int MEM_Invalid = 0x0080;
|
||||
private const int MEM_TypeMask = 0x00ff;
|
||||
|
||||
/* 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
|
||||
|
||||
// */
|
||||
//#define MEM_Term 0x0200 /* String rep is nul terminated */
|
||||
//#define MEM_Dyn 0x0400 /* Need to call sqliteFree() 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 */
|
||||
//#if SQLITE_OMIT_INCRBLOB
|
||||
// #undef MEM_Zero
|
||||
// #define MEM_Zero 0x0000
|
||||
//#endif
|
||||
private const int MEM_Term = 0x0200;
|
||||
|
||||
private const int MEM_Dyn = 0x0400;
|
||||
private const int MEM_Static = 0x0800;
|
||||
private const int MEM_Ephem = 0x1000;
|
||||
private const int MEM_Agg = 0x2000;
|
||||
#if !SQLITE_OMIT_INCRBLOB
|
||||
const int MEM_Zero = 0x4000;
|
||||
#else
|
||||
private const int MEM_Zero = 0x0000;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Clear any existing type flags from a Mem and replace them with f
|
||||
*/
|
||||
|
||||
//#define MemSetTypeFlag(p, f) \
|
||||
// ((p)->flags = ((p)->flags&~(MEM_TypeMask|MEM_Zero))|f)
|
||||
private static void MemSetTypeFlag(Mem p, int f)
|
||||
{
|
||||
p.flags = (u16)(p.flags & ~(MEM_TypeMask | MEM_Zero) | f);
|
||||
}// TODO -- Convert back to inline for speed
|
||||
|
||||
/*
|
||||
** Return true if a memory cell is not marked as invalid. This macro
|
||||
** is for use inside Debug.Assert() statements only.
|
||||
*/
|
||||
#if SQLITE_DEBUG
|
||||
|
||||
//#define memIsValid(M) ((M)->flags & MEM_Invalid)==0
|
||||
private static bool memIsValid(Mem M)
|
||||
{
|
||||
return ((M).flags & MEM_Invalid) == 0;
|
||||
}
|
||||
|
||||
#else
|
||||
static bool memIsValid( Mem M ) { return true; }
|
||||
#endif
|
||||
|
||||
/* A VdbeFunc is just a FuncDef (defined in sqliteInt.h) that contains
|
||||
** additional information about auxiliary information bound to arguments
|
||||
** of the function. This is used to implement the sqlite3_get_auxdata()
|
||||
** and sqlite3_set_auxdata() APIs. The "auxdata" is some auxiliary data
|
||||
** that can be associated with a constant argument to a function. This
|
||||
** allows functions such as "regexp" to compile their constant regular
|
||||
** expression argument once and reused the compiled code for multiple
|
||||
** invocations.
|
||||
*/
|
||||
|
||||
public class AuxData
|
||||
{
|
||||
public object pAux; /* Aux data for the i-th argument */
|
||||
//(void ); /* Destructor for the aux data */
|
||||
};
|
||||
|
||||
public class VdbeFunc : FuncDef
|
||||
{
|
||||
public FuncDef pFunc; /* The definition of the function */
|
||||
public int nAux; /* Number of entries allocated for apAux[] */
|
||||
public AuxData[] apAux = new AuxData[2]; /* One slot for each function argument */
|
||||
};
|
||||
|
||||
/*
|
||||
** The "context" argument for a installable function. A pointer to an
|
||||
** instance of this structure is the first argument to the routines used
|
||||
** implement the SQL functions.
|
||||
**
|
||||
** There is a typedef for this structure in sqlite.h. So all routines,
|
||||
** even the public interface to SQLite, can use a pointer to this structure.
|
||||
** But this file is the only place where the internal details of this
|
||||
** structure are known.
|
||||
**
|
||||
** This structure is defined inside of vdbeInt.h because it uses substructures
|
||||
** (Mem) which are only defined there.
|
||||
*/
|
||||
|
||||
public class sqlite3_context
|
||||
{
|
||||
public FuncDef pFunc; /* Pointer to function information. MUST BE FIRST */
|
||||
public VdbeFunc pVdbeFunc; /* Auxilary data, if created. */
|
||||
public Mem s = new Mem(); /* The return value is stored here */
|
||||
public Mem pMem; /* Memory cell used to store aggregate context */
|
||||
public int isError; /* Error code returned by the function. */
|
||||
public CollSeq pColl; /* Collating sequence */
|
||||
};
|
||||
|
||||
/*
|
||||
** An instance of the virtual machine. This structure contains the complete
|
||||
** state of the virtual machine.
|
||||
**
|
||||
** The "sqlite3_stmt" structure pointer that is returned by sqlite3_prepare()
|
||||
** is really a pointer to an instance of this structure.
|
||||
**
|
||||
** The Vdbe.inVtabMethod variable is set to non-zero for the duration of
|
||||
** any virtual table method invocations made by the vdbe program. It is
|
||||
** set to 2 for xDestroy method calls and 1 for all other methods. This
|
||||
** variable is used for two purposes: to allow xDestroy methods to execute
|
||||
** "DROP TABLE" statements and to prevent some nasty side effects of
|
||||
** malloc failure when SQLite is invoked recursively by a virtual table
|
||||
** method function.
|
||||
*/
|
||||
|
||||
public class Vdbe
|
||||
{
|
||||
public sqlite3 db; /* The database connection that owns this statement */
|
||||
public Op[] aOp; /* Space to hold the virtual machine's program */
|
||||
public Mem[] aMem; /* The memory locations */
|
||||
public Mem[] apArg; /* Arguments to currently executing user function */
|
||||
public Mem[] aColName; /* Column names to return */
|
||||
public Mem[] pResultSet; /* Pointer to an array of results */
|
||||
public int nMem; /* Number of memory locations currently allocated */
|
||||
public int nOp; /* Number of instructions in the program */
|
||||
public int nOpAlloc; /* Number of slots allocated for aOp[] */
|
||||
public int nLabel; /* Number of labels used */
|
||||
public int nLabelAlloc; /* Number of slots allocated in aLabel[] */
|
||||
public int[] aLabel; /* Space to hold the labels */
|
||||
public u16 nResColumn; /* Number of columns in one row of the result set */
|
||||
public u16 nCursor; /* Number of slots in apCsr[] */
|
||||
public u32 magic; /* Magic number for sanity checking */
|
||||
public string zErrMsg; /* Error message written here */
|
||||
public Vdbe pPrev; /* Linked list of VDBEs with the same Vdbe.db */
|
||||
public Vdbe pNext; /* Linked list of VDBEs with the same Vdbe.db */
|
||||
public VdbeCursor[] apCsr; /* One element of this array for each open cursor */
|
||||
public Mem[] aVar; /* Values for the OP_Variable opcode. */
|
||||
public string[] azVar; /* Name of variables */
|
||||
public ynVar nVar; /* Number of entries in aVar[] */
|
||||
public ynVar nzVar; /* Number of entries in azVar[] */
|
||||
public u32 cacheCtr; /* VdbeCursor row cache generation counter */
|
||||
public int pc; /* The program counter */
|
||||
public int rc; /* Value to return */
|
||||
public u8 errorAction; /* Recovery action to do in case of an error */
|
||||
public int explain; /* True if EXPLAIN present on SQL command */
|
||||
public bool changeCntOn; /* True to update the change-counter */
|
||||
public bool expired; /* True if the VM needs to be recompiled */
|
||||
public u8 runOnlyOnce; /* Automatically expire on reset */
|
||||
public int minWriteFileFormat; /* Minimum file format for writable database files */
|
||||
public int inVtabMethod; /* See comments above */
|
||||
public bool usesStmtJournal; /* True if uses a statement journal */
|
||||
public bool readOnly; /* True for read-only statements */
|
||||
public int nChange; /* Number of db changes made since last reset */
|
||||
public bool isPrepareV2; /* True if prepared with prepare_v2() */
|
||||
public yDbMask btreeMask; /* Bitmask of db.aDb[] entries referenced */
|
||||
public yDbMask lockMask; /* Subset of btreeMask that requires a lock */
|
||||
|
||||
public int iStatement; /* Statement number (or 0 if has not opened stmt) */
|
||||
public int[] aCounter = new int[3]; /* Counters used by sqlite3_stmt_status() */
|
||||
#if !SQLITE_OMIT_TRACE
|
||||
public i64 startTime; /* Time when query started - used for profiling */
|
||||
#endif
|
||||
public i64 nFkConstraint; /* Number of imm. FK constraints this VM */
|
||||
public i64 nStmtDefCons; /* Number of def. constraints when stmt started */
|
||||
public string zSql = ""; /* Text of the SQL statement that generated this */
|
||||
public object pFree; /* Free this when deleting the vdbe */
|
||||
#if SQLITE_DEBUG
|
||||
public FILE trace; /* Write an execution trace here, if not NULL */
|
||||
#endif
|
||||
public VdbeFrame pFrame; /* Parent frame */
|
||||
public VdbeFrame pDelFrame; /* List of frame objects to free on VM reset */
|
||||
public int nFrame; /* Number of frames in pFrame list */
|
||||
public u32 expmask; /* Binding to these vars invalidates VM */
|
||||
public SubProgram pProgram; /* Linked list of all sub-programs used by VM */
|
||||
|
||||
public Vdbe Copy()
|
||||
{
|
||||
Vdbe cp = (Vdbe)MemberwiseClone();
|
||||
return cp;
|
||||
}
|
||||
|
||||
public void CopyTo(Vdbe ct)
|
||||
{
|
||||
ct.db = db;
|
||||
ct.pPrev = pPrev;
|
||||
ct.pNext = pNext;
|
||||
ct.nOp = nOp;
|
||||
ct.nOpAlloc = nOpAlloc;
|
||||
ct.aOp = aOp;
|
||||
ct.nLabel = nLabel;
|
||||
ct.nLabelAlloc = nLabelAlloc;
|
||||
ct.aLabel = aLabel;
|
||||
ct.apArg = apArg;
|
||||
ct.aColName = aColName;
|
||||
ct.nCursor = nCursor;
|
||||
ct.apCsr = apCsr;
|
||||
ct.aVar = aVar;
|
||||
ct.azVar = azVar;
|
||||
ct.nVar = nVar;
|
||||
ct.nzVar = nzVar;
|
||||
ct.magic = magic;
|
||||
ct.nMem = nMem;
|
||||
ct.aMem = aMem;
|
||||
ct.cacheCtr = cacheCtr;
|
||||
ct.pc = pc;
|
||||
ct.rc = rc;
|
||||
ct.errorAction = errorAction;
|
||||
ct.nResColumn = nResColumn;
|
||||
ct.zErrMsg = zErrMsg;
|
||||
ct.pResultSet = pResultSet;
|
||||
ct.explain = explain;
|
||||
ct.changeCntOn = changeCntOn;
|
||||
ct.expired = expired;
|
||||
ct.minWriteFileFormat = minWriteFileFormat;
|
||||
ct.inVtabMethod = inVtabMethod;
|
||||
ct.usesStmtJournal = usesStmtJournal;
|
||||
ct.readOnly = readOnly;
|
||||
ct.nChange = nChange;
|
||||
ct.isPrepareV2 = isPrepareV2;
|
||||
#if !SQLITE_OMIT_TRACE
|
||||
ct.startTime = startTime;
|
||||
#endif
|
||||
ct.btreeMask = btreeMask;
|
||||
ct.lockMask = lockMask;
|
||||
aCounter.CopyTo(ct.aCounter, 0);
|
||||
ct.zSql = zSql;
|
||||
ct.pFree = pFree;
|
||||
#if SQLITE_DEBUG
|
||||
ct.trace = trace;
|
||||
#endif
|
||||
ct.nFkConstraint = nFkConstraint;
|
||||
ct.nStmtDefCons = nStmtDefCons;
|
||||
ct.iStatement = iStatement;
|
||||
ct.pFrame = pFrame;
|
||||
ct.nFrame = nFrame;
|
||||
ct.expmask = expmask;
|
||||
ct.pProgram = pProgram;
|
||||
#if SQLITE_SSE
|
||||
ct.fetchId=fetchId;
|
||||
ct.lru=lru;
|
||||
#endif
|
||||
#if SQLITE_ENABLE_MEMORY_MANAGEMENT
|
||||
ct.pLruPrev=pLruPrev;
|
||||
ct.pLruNext=pLruNext;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
** The following are allowed values for Vdbe.magic
|
||||
*/
|
||||
|
||||
//#define VDBE_MAGIC_INIT 0x26bceaa5 /* Building a VDBE program */
|
||||
//#define VDBE_MAGIC_RUN 0xbdf20da3 /* VDBE is ready to execute */
|
||||
//#define VDBE_MAGIC_HALT 0x519c2973 /* VDBE has completed execution */
|
||||
//#define VDBE_MAGIC_DEAD 0xb606c3c8 /* The VDBE has been deallocated */
|
||||
private const u32 VDBE_MAGIC_INIT = 0x26bceaa5; /* Building a VDBE program */
|
||||
|
||||
private const u32 VDBE_MAGIC_RUN = 0xbdf20da3; /* VDBE is ready to execute */
|
||||
private const u32 VDBE_MAGIC_HALT = 0x519c2973; /* VDBE has completed execution */
|
||||
private const u32 VDBE_MAGIC_DEAD = 0xb606c3c8; /* The VDBE has been deallocated */
|
||||
/*
|
||||
** Function prototypes
|
||||
*/
|
||||
//void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor);
|
||||
//void sqliteVdbePopStack(Vdbe*,int);
|
||||
//int sqlite3VdbeCursorMoveto(VdbeCursor);
|
||||
//#if (SQLITE_DEBUG) || defined(VDBE_PROFILE)
|
||||
//void sqlite3VdbePrintOp(FILE*, int, Op);
|
||||
//#endif
|
||||
//u32 sqlite3VdbeSerialTypeLen(u32);
|
||||
//u32 sqlite3VdbeSerialType(Mem*, int);
|
||||
//u32sqlite3VdbeSerialPut(unsigned char*, int, Mem*, int);
|
||||
//u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem);
|
||||
//void sqlite3VdbeDeleteAuxData(VdbeFunc*, int);
|
||||
|
||||
//int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int );
|
||||
//int sqlite3VdbeIdxKeyCompare(VdbeCursor*,UnpackedRecord*,int);
|
||||
//int sqlite3VdbeIdxRowid(sqlite3 *, i64 );
|
||||
//int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq);
|
||||
//int sqlite3VdbeExec(Vdbe);
|
||||
//int sqlite3VdbeList(Vdbe);
|
||||
//int sqlite3VdbeHalt(Vdbe);
|
||||
//int sqlite3VdbeChangeEncoding(Mem *, int);
|
||||
//int sqlite3VdbeMemTooBig(Mem);
|
||||
//int sqlite3VdbeMemCopy(Mem*, const Mem);
|
||||
//void sqlite3VdbeMemShallowCopy(Mem*, const Mem*, int);
|
||||
//void sqlite3VdbeMemMove(Mem*, Mem);
|
||||
//int sqlite3VdbeMemNulTerminate(Mem);
|
||||
//int sqlite3VdbeMemSetStr(Mem*, const char*, int, u8, void()(void));
|
||||
//void sqlite3VdbeMemSetInt64(Mem*, i64);
|
||||
#if SQLITE_OMIT_FLOATING_POINT
|
||||
//# define sqlite3VdbeMemSetDouble sqlite3VdbeMemSetInt64
|
||||
#else
|
||||
//void sqlite3VdbeMemSetDouble(Mem*, double);
|
||||
#endif
|
||||
//void sqlite3VdbeMemSetNull(Mem);
|
||||
//void sqlite3VdbeMemSetZeroBlob(Mem*,int);
|
||||
//void sqlite3VdbeMemSetRowSet(Mem);
|
||||
//int sqlite3VdbeMemMakeWriteable(Mem);
|
||||
//int sqlite3VdbeMemStringify(Mem*, int);
|
||||
//i64 sqlite3VdbeIntValue(Mem);
|
||||
//int sqlite3VdbeMemIntegerify(Mem);
|
||||
//double sqlite3VdbeRealValue(Mem);
|
||||
//void sqlite3VdbeIntegerAffinity(Mem);
|
||||
//int sqlite3VdbeMemRealify(Mem);
|
||||
//int sqlite3VdbeMemNumerify(Mem);
|
||||
//int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem);
|
||||
//void sqlite3VdbeMemRelease(Mem p);
|
||||
//void sqlite3VdbeMemReleaseExternal(Mem p);
|
||||
//int sqlite3VdbeMemFinalize(Mem*, FuncDef);
|
||||
//string sqlite3OpcodeName(int);
|
||||
//int sqlite3VdbeMemGrow(Mem pMem, int n, int preserve);
|
||||
//int sqlite3VdbeCloseStatement(Vdbe *, int);
|
||||
//void sqlite3VdbeFrameDelete(VdbeFrame);
|
||||
//int sqlite3VdbeFrameRestore(VdbeFrame );
|
||||
//void sqlite3VdbeMemStoreType(Mem *pMem);
|
||||
|
||||
#if !(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE//>0
|
||||
//void sqlite3VdbeEnter(Vdbe);
|
||||
//void sqlite3VdbeLeave(Vdbe);
|
||||
#else
|
||||
|
||||
//# define sqlite3VdbeEnter(X)
|
||||
private static void sqlite3VdbeEnter(Vdbe p)
|
||||
{
|
||||
}
|
||||
|
||||
//# define sqlite3VdbeLeave(X)
|
||||
private static void sqlite3VdbeLeave(Vdbe p)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if SQLITE_DEBUG
|
||||
//void sqlite3VdbeMemPrepareToChange(Vdbe*,Mem);
|
||||
#endif
|
||||
|
||||
#if !SQLITE_OMIT_FOREIGN_KEY
|
||||
//int sqlite3VdbeCheckFk(Vdbe *, int);
|
||||
#else
|
||||
//# define sqlite3VdbeCheckFk(p,i) 0
|
||||
static int sqlite3VdbeCheckFk( Vdbe p, int i ) { return 0; }
|
||||
#endif
|
||||
|
||||
//int sqlite3VdbeMemTranslate(Mem*, u8);
|
||||
//#if SQLITE_DEBUG
|
||||
// void sqlite3VdbePrintSql(Vdbe);
|
||||
// void sqlite3VdbeMemPrettyPrint(Mem pMem, string zBuf);
|
||||
//#endif
|
||||
//int sqlite3VdbeMemHandleBom(Mem pMem);
|
||||
|
||||
#if !SQLITE_OMIT_INCRBLOB
|
||||
// int sqlite3VdbeMemExpandBlob(Mem );
|
||||
#else
|
||||
|
||||
// #define sqlite3VdbeMemExpandBlob(x) SQLITE_OK
|
||||
private static int sqlite3VdbeMemExpandBlob(Mem x)
|
||||
{
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//#endif //* !_VDBEINT_H_) */
|
||||
}
|
||||
}
|
||||
325
original/Community.CsharpSqlite/src/Vdbe_h.cs
Normal file
325
original/Community.CsharpSqlite/src/Vdbe_h.cs
Normal file
|
|
@ -0,0 +1,325 @@
|
|||
using i64 = System.Int64;
|
||||
using u8 = System.Byte;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** Header file for the Virtual DataBase Engine (VDBE)
|
||||
**
|
||||
** This header defines the interface to the virtual database engine
|
||||
** or VDBE. The VDBE implements an abstract machine that runs a
|
||||
** simple program to access and modify the underlying database.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#if !_SQLITE_VDBE_H_
|
||||
//#define _SQLITE_VDBE_H_
|
||||
//#include <stdio.h>
|
||||
|
||||
/*
|
||||
** A single VDBE is an opaque structure named "Vdbe". Only routines
|
||||
** in the source file sqliteVdbe.c are allowed to see the insides
|
||||
** of this structure.
|
||||
*/
|
||||
//typedef struct Vdbe Vdbe;
|
||||
|
||||
/*
|
||||
** The names of the following types declared in vdbeInt.h are required
|
||||
** for the VdbeOp definition.
|
||||
*/
|
||||
//typedef struct VdbeFunc VdbeFunc;
|
||||
//typedef struct Mem Mem;
|
||||
//typedef struct SubProgram SubProgram;
|
||||
|
||||
/*
|
||||
** A single instruction of the virtual machine has an opcode
|
||||
** and as many as three operands. The instruction is recorded
|
||||
** as an instance of the following structure:
|
||||
*/
|
||||
|
||||
public class union_p4
|
||||
{ /* fourth parameter */
|
||||
public int i; /* Integer value if p4type==P4_INT32 */
|
||||
public object p; /* Generic pointer */
|
||||
|
||||
//public string z; /* Pointer to data for string (char array) types */
|
||||
public string z; // In C# string is unicode, so use byte[] instead
|
||||
|
||||
public i64 pI64; /* Used when p4type is P4_INT64 */
|
||||
public double pReal; /* Used when p4type is P4_REAL */
|
||||
public FuncDef pFunc; /* Used when p4type is P4_FUNCDEF */
|
||||
public VdbeFunc pVdbeFunc; /* Used when p4type is P4_VDBEFUNC */
|
||||
public CollSeq pColl; /* Used when p4type is P4_COLLSEQ */
|
||||
public Mem pMem; /* Used when p4type is P4_MEM */
|
||||
public VTable pVtab; /* Used when p4type is P4_VTAB */
|
||||
public KeyInfo pKeyInfo; /* Used when p4type is P4_KEYINFO */
|
||||
public int[] ai; /* Used when p4type is P4_INTARRAY */
|
||||
public SubProgram pProgram; /* Used when p4type is P4_SUBPROGRAM */
|
||||
public dxDel pFuncDel; /* Used when p4type is P4_FUNCDEL */
|
||||
} ;
|
||||
|
||||
public class VdbeOp
|
||||
{
|
||||
public u8 opcode; /* What operation to perform */
|
||||
public int p4type; /* One of the P4_xxx constants for p4 */
|
||||
public u8 opflags; /* Mask of the OPFLG_* flags in opcodes.h */
|
||||
public u8 p5; /* Fifth parameter is an unsigned character */
|
||||
#if DEBUG_CLASS_VDBEOP || DEBUG_CLASS_ALL
|
||||
public int _p1; /* First operand */
|
||||
public int p1
|
||||
{
|
||||
get { return _p1; }
|
||||
set { _p1 = value; }
|
||||
}
|
||||
|
||||
public int _p2; /* Second parameter (often the jump destination) */
|
||||
public int p2
|
||||
{
|
||||
get { return _p2; }
|
||||
set { _p2 = value; }
|
||||
}
|
||||
|
||||
public int _p3; /* The third parameter */
|
||||
public int p3
|
||||
{
|
||||
get { return _p3; }
|
||||
set { _p3 = value; }
|
||||
}
|
||||
#else
|
||||
public int p1; /* First operand */
|
||||
public int p2; /* Second parameter (often the jump destination) */
|
||||
public int p3; /* The third parameter */
|
||||
#endif
|
||||
public union_p4 p4 = new union_p4();
|
||||
#if SQLITE_DEBUG || DEBUG
|
||||
public string zComment; /* Comment to improve readability */
|
||||
#endif
|
||||
#if VDBE_PROFILE
|
||||
public int cnt; /* Number of times this instruction was executed */
|
||||
public u64 cycles; /* Total time spend executing this instruction */
|
||||
#endif
|
||||
};
|
||||
|
||||
//typedef struct VdbeOp VdbeOp;
|
||||
|
||||
/*
|
||||
** A sub-routine used to implement a trigger program.
|
||||
*/
|
||||
|
||||
public class SubProgram
|
||||
{
|
||||
public VdbeOp[] aOp; /* Array of opcodes for sub-program */
|
||||
public int nOp; /* Elements in aOp[] */
|
||||
public int nMem; /* Number of memory cells required */
|
||||
public int nCsr; /* Number of cursors required */
|
||||
public int token; /* id that may be used to recursive triggers */
|
||||
public SubProgram pNext; /* Next sub-program already visited */
|
||||
};
|
||||
|
||||
/*
|
||||
** A smaller version of VdbeOp used for the VdbeAddOpList() function because
|
||||
** it takes up less space.
|
||||
*/
|
||||
|
||||
public struct VdbeOpList
|
||||
{
|
||||
public u8 opcode; /* What operation to perform */
|
||||
public int p1; /* First operand */
|
||||
public int p2; /* Second parameter (often the jump destination) */
|
||||
public int p3; /* Third parameter */
|
||||
|
||||
public VdbeOpList(u8 opcode, int p1, int p2, int p3)
|
||||
{
|
||||
this.opcode = opcode;
|
||||
this.p1 = p1;
|
||||
this.p2 = p2;
|
||||
this.p3 = p3;
|
||||
}
|
||||
};
|
||||
|
||||
//typedef struct VdbeOpList VdbeOpList;
|
||||
|
||||
/*
|
||||
** Allowed values of VdbeOp.p4type
|
||||
*/
|
||||
private const int P4_NOTUSED = 0; /* The P4 parameter is not used */
|
||||
private const int P4_DYNAMIC = (-1); /* Pointer to a string obtained from sqliteMalloc=(); */
|
||||
private const int P4_STATIC = (-2); /* Pointer to a static string */
|
||||
private const int P4_COLLSEQ = (-4); /* P4 is a pointer to a CollSeq structure */
|
||||
private const int P4_FUNCDEF = (-5); /* P4 is a pointer to a FuncDef structure */
|
||||
private const int P4_KEYINFO = (-6); /* P4 is a pointer to a KeyInfo structure */
|
||||
private const int P4_VDBEFUNC = (-7); /* P4 is a pointer to a VdbeFunc structure */
|
||||
private const int P4_MEM = (-8); /* P4 is a pointer to a Mem* structure */
|
||||
private const int P4_TRANSIENT = 0; /* P4 is a pointer to a transient string */
|
||||
private const int P4_VTAB = (-10); /* P4 is a pointer to an sqlite3_vtab structure */
|
||||
private const int P4_MPRINTF = (-11); /* P4 is a string obtained from sqlite3_mprintf=(); */
|
||||
private const int P4_REAL = (-12); /* P4 is a 64-bit floating point value */
|
||||
private const int P4_INT64 = (-13); /* P4 is a 64-bit signed integer */
|
||||
private const int P4_INT32 = (-14); /* P4 is a 32-bit signed integer */
|
||||
private const int P4_INTARRAY = (-15); /* #define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */
|
||||
private const int P4_SUBPROGRAM = (-18);/* #define P4_SUBPROGRAM (-18) /* P4 is a pointer to a SubProgram structure */
|
||||
|
||||
/* When adding a P4 argument using P4_KEYINFO, a copy of the KeyInfo structure
|
||||
** is made. That copy is freed when the Vdbe is finalized. But if the
|
||||
** argument is P4_KEYINFO_HANDOFF, the passed in pointer is used. It still
|
||||
** gets freed when the Vdbe is finalized so it still should be obtained
|
||||
** from a single sqliteMalloc(). But no copy is made and the calling
|
||||
** function should *not* try to free the KeyInfo.
|
||||
*/
|
||||
private const int P4_KEYINFO_HANDOFF = (-16); // #define P4_KEYINFO_HANDOFF (-16)
|
||||
private const int P4_KEYINFO_STATIC = (-17); // #define P4_KEYINFO_STATIC (-17)
|
||||
|
||||
/*
|
||||
** The Vdbe.aColName array contains 5n Mem structures, where n is the
|
||||
** number of columns of data returned by the statement.
|
||||
*/
|
||||
|
||||
//#define COLNAME_NAME 0
|
||||
//#define COLNAME_DECLTYPE 1
|
||||
//#define COLNAME_DATABASE 2
|
||||
//#define COLNAME_TABLE 3
|
||||
//#define COLNAME_COLUMN 4
|
||||
//#if SQLITE_ENABLE_COLUMN_METADATA
|
||||
//# define COLNAME_N 5 /* Number of COLNAME_xxx symbols */
|
||||
//#else
|
||||
//# ifdef SQLITE_OMIT_DECLTYPE
|
||||
//# define COLNAME_N 1 /* Store only the name */
|
||||
//# else
|
||||
//# define COLNAME_N 2 /* Store the name and decltype */
|
||||
//# endif
|
||||
//#endif
|
||||
private const int COLNAME_NAME = 0;
|
||||
|
||||
private const int COLNAME_DECLTYPE = 1;
|
||||
private const int COLNAME_DATABASE = 2;
|
||||
private const int COLNAME_TABLE = 3;
|
||||
private const int COLNAME_COLUMN = 4;
|
||||
#if SQLITE_ENABLE_COLUMN_METADATA
|
||||
const int COLNAME_N = 5; /* Number of COLNAME_xxx symbols */
|
||||
#else
|
||||
# if SQLITE_OMIT_DECLTYPE
|
||||
const int COLNAME_N = 1; /* Number of COLNAME_xxx symbols */
|
||||
# else
|
||||
private const int COLNAME_N = 2;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The following macro converts a relative address in the p2 field
|
||||
** of a VdbeOp structure into a negative number so that
|
||||
** sqlite3VdbeAddOpList() knows that the address is relative. Calling
|
||||
** the macro again restores the address.
|
||||
*/
|
||||
|
||||
//#define ADDR(X) (-1-(X))
|
||||
private static int ADDR(int x)
|
||||
{
|
||||
return -1 - x;
|
||||
}
|
||||
|
||||
/*
|
||||
** The makefile scans the vdbe.c source file and creates the "opcodes.h"
|
||||
** header file that defines a number for each opcode used by the VDBE.
|
||||
*/
|
||||
//#include "opcodes.h"
|
||||
|
||||
/*
|
||||
** Prototypes for the VDBE interface. See comments on the implementation
|
||||
** for a description of what each of these routines does.
|
||||
*/
|
||||
/*
|
||||
** Prototypes for the VDBE interface. See comments on the implementation
|
||||
** for a description of what each of these routines does.
|
||||
*/
|
||||
//Vdbe *sqlite3VdbeCreate(sqlite3);
|
||||
//int sqlite3VdbeAddOp0(Vdbe*,int);
|
||||
//int sqlite3VdbeAddOp1(Vdbe*,int,int);
|
||||
//int sqlite3VdbeAddOp2(Vdbe*,int,int,int);
|
||||
//int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int);
|
||||
//int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,string zP4,int);
|
||||
//int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int);
|
||||
//int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp);
|
||||
//void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char);
|
||||
//void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
|
||||
//void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
|
||||
//void sqlite3VdbeChangeP3(Vdbe*, int addr, int P3);
|
||||
//void sqlite3VdbeChangeP5(Vdbe*, u8 P5);
|
||||
//void sqlite3VdbeJumpHere(Vdbe*, int addr);
|
||||
//void sqlite3VdbeChangeToNoop(Vdbe*, int addr, int N);
|
||||
//void sqlite3VdbeChangeP4(Vdbe*, int addr, string zP4, int N);
|
||||
//void sqlite3VdbeUsesBtree(Vdbe*, int);
|
||||
//VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
|
||||
//int sqlite3VdbeMakeLabel(Vdbe);
|
||||
//void sqlite3VdbeRunOnlyOnce(Vdbe);
|
||||
//void sqlite3VdbeDelete(Vdbe);
|
||||
//void sqlite3VdbeDeleteObject(sqlite3*,Vdbe);
|
||||
//void sqlite3VdbeMakeReady(Vdbe*,Parse);
|
||||
//int sqlite3VdbeFinalize(Vdbe);
|
||||
//void sqlite3VdbeResolveLabel(Vdbe*, int);
|
||||
//int sqlite3VdbeCurrentAddr(Vdbe);
|
||||
//#if SQLITE_DEBUG
|
||||
// int sqlite3VdbeAssertMayAbort(Vdbe *, int);
|
||||
// void sqlite3VdbeTrace(Vdbe*,FILE);
|
||||
//#endif
|
||||
//void sqlite3VdbeResetStepResult(Vdbe);
|
||||
//void sqlite3VdbeRewind(Vdbe);
|
||||
//int sqlite3VdbeReset(Vdbe);
|
||||
//void sqlite3VdbeSetNumCols(Vdbe*,int);
|
||||
//int sqlite3VdbeSetColName(Vdbe*, int, int, string , void()(void));
|
||||
//void sqlite3VdbeCountChanges(Vdbe);
|
||||
//sqlite3 *sqlite3VdbeDb(Vdbe);
|
||||
//void sqlite3VdbeSetSql(Vdbe*, string z, int n, int);
|
||||
//void sqlite3VdbeSwap(Vdbe*,Vdbe);
|
||||
//VdbeOp *sqlite3VdbeTakeOpArray(Vdbe*, int*, int);
|
||||
//sqlite3_value *sqlite3VdbeGetValue(Vdbe*, int, u8);
|
||||
//void sqlite3VdbeSetVarmask(Vdbe*, int);
|
||||
//#if !SQLITE_OMIT_TRACE
|
||||
// char *sqlite3VdbeExpandSql(Vdbe*, const char);
|
||||
//#endif
|
||||
|
||||
//UnpackedRecord *sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,char*,int);
|
||||
//void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord);
|
||||
//int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord);
|
||||
|
||||
//#if !SQLITE_OMIT_TRIGGER
|
||||
//void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram );
|
||||
//#endif
|
||||
#if !NDEBUG
|
||||
|
||||
//void sqlite3VdbeComment(Vdbe*, const char*, ...);
|
||||
private static void VdbeComment(Vdbe v, string zFormat, params object[] ap)
|
||||
{
|
||||
sqlite3VdbeComment(v, zFormat, ap);
|
||||
}//# define VdbeComment(X) sqlite3VdbeComment X
|
||||
|
||||
//void sqlite3VdbeNoopComment(Vdbe*, const char*, ...);
|
||||
private static void VdbeNoopComment(Vdbe v, string zFormat, params object[] ap)
|
||||
{
|
||||
sqlite3VdbeNoopComment(v, zFormat, ap);
|
||||
}//# define VdbeNoopComment(X) sqlite3VdbeNoopComment X
|
||||
|
||||
#else
|
||||
//# define VdbeComment(X)
|
||||
static void VdbeComment( Vdbe v, string zFormat, params object[] ap ) { }
|
||||
//# define VdbeNoopComment(X)
|
||||
static void VdbeNoopComment( Vdbe v, string zFormat, params object[] ap ) { }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
683
original/Community.CsharpSqlite/src/_Custom.cs
Normal file
683
original/Community.CsharpSqlite/src/_Custom.cs
Normal file
|
|
@ -0,0 +1,683 @@
|
|||
/*
|
||||
*************************************************************************
|
||||
** Custom classes used by C#
|
||||
*************************************************************************
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
#if !(SQLITE_SILVERLIGHT || WINDOWS_MOBILE || SQLITE_WINRT)
|
||||
|
||||
using System.Management;
|
||||
|
||||
#endif
|
||||
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
|
||||
#if SQLITE_WINRT
|
||||
using System.Reflection;
|
||||
#endif
|
||||
|
||||
using i64 = System.Int64;
|
||||
|
||||
using u32 = System.UInt32;
|
||||
|
||||
using time_t = System.Int64;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
using sqlite3_value = Sqlite3.Mem;
|
||||
|
||||
public partial class Sqlite3
|
||||
{
|
||||
private static int atoi(byte[] inStr)
|
||||
{
|
||||
return atoi(Encoding.UTF8.GetString(inStr, 0, inStr.Length));
|
||||
}
|
||||
|
||||
private static int atoi(string inStr)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < inStr.Length; i++)
|
||||
{
|
||||
if (!sqlite3Isdigit(inStr[i]) && inStr[i] != '-')
|
||||
break;
|
||||
}
|
||||
int result = 0;
|
||||
#if WINDOWS_MOBILE
|
||||
try { result = Int32.Parse(inStr.Substring(0, i)); }
|
||||
catch { }
|
||||
return result;
|
||||
#else
|
||||
return (Int32.TryParse(inStr.Substring(0, i), out result) ? result : 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
private static void fprintf(TextWriter tw, string zFormat, params object[] ap)
|
||||
{
|
||||
tw.Write(sqlite3_mprintf(zFormat, ap));
|
||||
}
|
||||
|
||||
private static void printf(string zFormat, params object[] ap)
|
||||
{
|
||||
#if !SQLITE_WINRT
|
||||
Console.Out.Write(sqlite3_mprintf(zFormat, ap));
|
||||
#endif
|
||||
}
|
||||
|
||||
//Byte Buffer Testing
|
||||
private static int memcmp(byte[] bA, byte[] bB, int Limit)
|
||||
{
|
||||
if (bA.Length < Limit)
|
||||
return (bA.Length < bB.Length) ? -1 : +1;
|
||||
if (bB.Length < Limit)
|
||||
return +1;
|
||||
for (int i = 0; i < Limit; i++)
|
||||
{
|
||||
if (bA[i] != bB[i])
|
||||
return (bA[i] < bB[i]) ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Byte Buffer & String Testing
|
||||
private static int memcmp(string A, byte[] bB, int Limit)
|
||||
{
|
||||
if (A.Length < Limit)
|
||||
return (A.Length < bB.Length) ? -1 : +1;
|
||||
if (bB.Length < Limit)
|
||||
return +1;
|
||||
char[] cA = A.ToCharArray();
|
||||
for (int i = 0; i < Limit; i++)
|
||||
{
|
||||
if (cA[i] != bB[i])
|
||||
return (cA[i] < bB[i]) ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//byte with Offset & String Testing
|
||||
private static int memcmp(byte[] a, int Offset, byte[] b, int Limit)
|
||||
{
|
||||
if (a.Length < Offset + Limit)
|
||||
return (a.Length - Offset < b.Length) ? -1 : +1;
|
||||
if (b.Length < Limit)
|
||||
return +1;
|
||||
for (int i = 0; i < Limit; i++)
|
||||
{
|
||||
if (a[i + Offset] != b[i])
|
||||
return (a[i + Offset] < b[i]) ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//byte with Offset & String Testing
|
||||
private static int memcmp(byte[] a, int Aoffset, byte[] b, int Boffset, int Limit)
|
||||
{
|
||||
if (a.Length < Aoffset + Limit)
|
||||
return (a.Length - Aoffset < b.Length - Boffset) ? -1 : +1;
|
||||
if (b.Length < Boffset + Limit)
|
||||
return +1;
|
||||
for (int i = 0; i < Limit; i++)
|
||||
{
|
||||
if (a[i + Aoffset] != b[i + Boffset])
|
||||
return (a[i + Aoffset] < b[i + Boffset]) ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int memcmp(byte[] a, int Offset, string b, int Limit)
|
||||
{
|
||||
if (a.Length < Offset + Limit)
|
||||
return (a.Length - Offset < b.Length) ? -1 : +1;
|
||||
if (b.Length < Limit)
|
||||
return +1;
|
||||
for (int i = 0; i < Limit; i++)
|
||||
{
|
||||
if (a[i + Offset] != b[i])
|
||||
return (a[i + Offset] < b[i]) ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//String Testing
|
||||
private static int memcmp(string A, string B, int Limit)
|
||||
{
|
||||
if (A.Length < Limit)
|
||||
return (A.Length < B.Length) ? -1 : +1;
|
||||
if (B.Length < Limit)
|
||||
return +1;
|
||||
int rc;
|
||||
if ((rc = String.Compare(A, 0, B, 0, Limit, StringComparison.Ordinal)) == 0)
|
||||
return 0;
|
||||
return rc < 0 ? -1 : +1;
|
||||
}
|
||||
|
||||
// ----------------------------
|
||||
// ** Builtin Functions
|
||||
// ----------------------------
|
||||
|
||||
private static Regex oRegex = null;
|
||||
/*
|
||||
** The regexp() function. two arguments are both strings
|
||||
** Collating sequences are not used.
|
||||
*/
|
||||
|
||||
private static void regexpFunc(
|
||||
sqlite3_context context,
|
||||
int argc,
|
||||
sqlite3_value[] argv
|
||||
)
|
||||
{
|
||||
string zTest; /* The input string A */
|
||||
string zRegex; /* The regex string B */
|
||||
|
||||
Debug.Assert(argc == 2);
|
||||
UNUSED_PARAMETER(argc);
|
||||
zRegex = sqlite3_value_text(argv[0]);
|
||||
zTest = sqlite3_value_text(argv[1]);
|
||||
|
||||
if (zTest == null || String.IsNullOrEmpty(zRegex))
|
||||
{
|
||||
sqlite3_result_int(context, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (oRegex == null || oRegex.ToString() == zRegex)
|
||||
{
|
||||
oRegex = new Regex(zRegex, RegexOptions.IgnoreCase);
|
||||
}
|
||||
sqlite3_result_int(context, oRegex.IsMatch(zTest) ? 1 : 0);
|
||||
}
|
||||
|
||||
// ----------------------------
|
||||
// ** Convertion routines
|
||||
// ----------------------------
|
||||
private static Object lock_va_list = new Object();
|
||||
|
||||
private static string vaFORMAT;
|
||||
private static int vaNEXT;
|
||||
|
||||
private static void va_start(object[] ap, string zFormat)
|
||||
{
|
||||
vaFORMAT = zFormat;
|
||||
vaNEXT = 0;
|
||||
}
|
||||
|
||||
private static Boolean va_arg(object[] ap, Boolean sysType)
|
||||
{
|
||||
return Convert.ToBoolean(ap[vaNEXT++]);
|
||||
}
|
||||
|
||||
private static Byte[] va_arg(object[] ap, Byte[] sysType)
|
||||
{
|
||||
return (Byte[])ap[vaNEXT++];
|
||||
}
|
||||
|
||||
private static Byte[][] va_arg(object[] ap, Byte[][] sysType)
|
||||
{
|
||||
if (ap[vaNEXT] == null)
|
||||
{
|
||||
{
|
||||
vaNEXT++;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return (Byte[][])ap[vaNEXT++];
|
||||
}
|
||||
}
|
||||
|
||||
private static Char va_arg(object[] ap, Char sysType)
|
||||
{
|
||||
if (ap[vaNEXT] is Int32 && (int)ap[vaNEXT] == 0)
|
||||
{
|
||||
vaNEXT++;
|
||||
return (char)'0';
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ap[vaNEXT] is Int64)
|
||||
if ((i64)ap[vaNEXT] == 0)
|
||||
{
|
||||
vaNEXT++;
|
||||
return (char)'0';
|
||||
}
|
||||
else
|
||||
return (char)((i64)ap[vaNEXT++]);
|
||||
else
|
||||
return (char)ap[vaNEXT++];
|
||||
}
|
||||
}
|
||||
|
||||
private static Double va_arg(object[] ap, Double sysType)
|
||||
{
|
||||
return Convert.ToDouble(ap[vaNEXT++]);
|
||||
}
|
||||
|
||||
private static dxLog va_arg(object[] ap, dxLog sysType)
|
||||
{
|
||||
return (dxLog)ap[vaNEXT++];
|
||||
}
|
||||
|
||||
private static Int64 va_arg(object[] ap, Int64 sysType)
|
||||
{
|
||||
if (ap[vaNEXT] is System.Int64)
|
||||
return Convert.ToInt64(ap[vaNEXT++]);
|
||||
else
|
||||
return (Int64)(ap[vaNEXT++].GetHashCode());
|
||||
}
|
||||
|
||||
private static Int32 va_arg(object[] ap, Int32 sysType)
|
||||
{
|
||||
if (Convert.ToInt64(ap[vaNEXT]) > 0 && (Convert.ToUInt32(ap[vaNEXT]) > Int32.MaxValue))
|
||||
return (Int32)(Convert.ToUInt32(ap[vaNEXT++]) - System.UInt32.MaxValue - 1);
|
||||
else
|
||||
return (Int32)Convert.ToInt32(ap[vaNEXT++]);
|
||||
}
|
||||
|
||||
private static Int32[] va_arg(object[] ap, Int32[] sysType)
|
||||
{
|
||||
if (ap[vaNEXT] == null)
|
||||
{
|
||||
{
|
||||
vaNEXT++;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return (Int32[])ap[vaNEXT++];
|
||||
}
|
||||
}
|
||||
|
||||
private static MemPage va_arg(object[] ap, MemPage sysType)
|
||||
{
|
||||
return (MemPage)ap[vaNEXT++];
|
||||
}
|
||||
|
||||
private static Object va_arg(object[] ap, Object sysType)
|
||||
{
|
||||
return (Object)ap[vaNEXT++];
|
||||
}
|
||||
|
||||
private static sqlite3 va_arg(object[] ap, sqlite3 sysType)
|
||||
{
|
||||
return (sqlite3)ap[vaNEXT++];
|
||||
}
|
||||
|
||||
private static sqlite3_mem_methods va_arg(object[] ap, sqlite3_mem_methods sysType)
|
||||
{
|
||||
return (sqlite3_mem_methods)ap[vaNEXT++];
|
||||
}
|
||||
|
||||
private static sqlite3_mutex_methods va_arg(object[] ap, sqlite3_mutex_methods sysType)
|
||||
{
|
||||
return (sqlite3_mutex_methods)ap[vaNEXT++];
|
||||
}
|
||||
|
||||
private static SrcList va_arg(object[] ap, SrcList sysType)
|
||||
{
|
||||
return (SrcList)ap[vaNEXT++];
|
||||
}
|
||||
|
||||
private static String va_arg(object[] ap, String sysType)
|
||||
{
|
||||
if (ap.Length < vaNEXT - 1 || ap[vaNEXT] == null)
|
||||
{
|
||||
vaNEXT++;
|
||||
return "NULL";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ap[vaNEXT] is Byte[])
|
||||
if (Encoding.UTF8.GetString((byte[])ap[vaNEXT], 0, ((byte[])ap[vaNEXT]).Length) == "\0")
|
||||
{
|
||||
vaNEXT++;
|
||||
return "";
|
||||
}
|
||||
else
|
||||
return Encoding.UTF8.GetString((byte[])ap[vaNEXT], 0, ((byte[])ap[vaNEXT++]).Length);
|
||||
else if (ap[vaNEXT] is Int32)
|
||||
{
|
||||
vaNEXT++;
|
||||
return null;
|
||||
}
|
||||
else if (ap[vaNEXT] is StringBuilder)
|
||||
return (String)ap[vaNEXT++].ToString();
|
||||
else if (ap[vaNEXT] is Char)
|
||||
return ((Char)ap[vaNEXT++]).ToString();
|
||||
else
|
||||
return (String)ap[vaNEXT++];
|
||||
}
|
||||
}
|
||||
|
||||
private static Token va_arg(object[] ap, Token sysType)
|
||||
{
|
||||
return (Token)ap[vaNEXT++];
|
||||
}
|
||||
|
||||
private static UInt32 va_arg(object[] ap, UInt32 sysType)
|
||||
{
|
||||
#if SQLITE_WINRT
|
||||
Type t = ap[vaNEXT].GetType();
|
||||
if ( t.GetTypeInfo().IsClass )
|
||||
#else
|
||||
if (ap[vaNEXT].GetType().IsClass)
|
||||
#endif
|
||||
{
|
||||
return (UInt32)ap[vaNEXT++].GetHashCode();
|
||||
}
|
||||
else
|
||||
{
|
||||
return (UInt32)Convert.ToUInt32(ap[vaNEXT++]);
|
||||
}
|
||||
}
|
||||
|
||||
private static UInt64 va_arg(object[] ap, UInt64 sysType)
|
||||
{
|
||||
#if SQLITE_WINRT
|
||||
Type t = ap[vaNEXT].GetType();
|
||||
if (t.GetTypeInfo().IsClass)
|
||||
#else
|
||||
if (ap[vaNEXT].GetType().IsClass)
|
||||
#endif
|
||||
{
|
||||
return (UInt64)ap[vaNEXT++].GetHashCode();
|
||||
}
|
||||
else
|
||||
{
|
||||
return (UInt64)Convert.ToUInt64(ap[vaNEXT++]);
|
||||
}
|
||||
}
|
||||
|
||||
private static void_function va_arg(object[] ap, void_function sysType)
|
||||
{
|
||||
return (void_function)ap[vaNEXT++];
|
||||
}
|
||||
|
||||
private static void va_end(ref string[] ap)
|
||||
{
|
||||
ap = null;
|
||||
vaNEXT = -1;
|
||||
vaFORMAT = "";
|
||||
}
|
||||
|
||||
private static void va_end(ref object[] ap)
|
||||
{
|
||||
ap = null;
|
||||
vaNEXT = -1;
|
||||
vaFORMAT = "";
|
||||
}
|
||||
|
||||
public static tm localtime(time_t baseTime)
|
||||
{
|
||||
System.DateTime RefTime = new System.DateTime(1970, 1, 1, 0, 0, 0, 0);
|
||||
RefTime = RefTime.AddSeconds(Convert.ToDouble(baseTime)).ToLocalTime();
|
||||
tm tm = new tm();
|
||||
tm.tm_sec = RefTime.Second;
|
||||
tm.tm_min = RefTime.Minute;
|
||||
tm.tm_hour = RefTime.Hour;
|
||||
tm.tm_mday = RefTime.Day;
|
||||
tm.tm_mon = RefTime.Month;
|
||||
tm.tm_year = RefTime.Year;
|
||||
tm.tm_wday = (int)RefTime.DayOfWeek;
|
||||
tm.tm_yday = RefTime.DayOfYear;
|
||||
tm.tm_isdst = RefTime.IsDaylightSavingTime() ? 1 : 0;
|
||||
return tm;
|
||||
}
|
||||
|
||||
public static long ToUnixtime(System.DateTime date)
|
||||
{
|
||||
System.DateTime unixStartTime = new System.DateTime(1970, 1, 1, 0, 0, 0, 0);
|
||||
System.TimeSpan timeSpan = date - unixStartTime;
|
||||
return Convert.ToInt64(timeSpan.TotalSeconds);
|
||||
}
|
||||
|
||||
public static System.DateTime ToCSharpTime(long unixTime)
|
||||
{
|
||||
System.DateTime unixStartTime = new System.DateTime(1970, 1, 1, 0, 0, 0, 0);
|
||||
return unixStartTime.AddSeconds(Convert.ToDouble(unixTime));
|
||||
}
|
||||
|
||||
public class tm
|
||||
{
|
||||
public int tm_sec; /* seconds after the minute - [0,59] */
|
||||
public int tm_min; /* minutes after the hour - [0,59] */
|
||||
public int tm_hour; /* hours since midnight - [0,23] */
|
||||
public int tm_mday; /* day of the month - [1,31] */
|
||||
public int tm_mon; /* months since January - [0,11] */
|
||||
public int tm_year; /* years since 1900 */
|
||||
public int tm_wday; /* days since Sunday - [0,6] */
|
||||
public int tm_yday; /* days since January 1 - [0,365] */
|
||||
public int tm_isdst; /* daylight savings time flag */
|
||||
};
|
||||
|
||||
public struct FILETIME
|
||||
{
|
||||
public u32 dwLowDateTime;
|
||||
public u32 dwHighDateTime;
|
||||
}
|
||||
|
||||
// Example (C#)
|
||||
public static int GetbytesPerSector(StringBuilder diskPath)
|
||||
{
|
||||
#if !(SQLITE_SILVERLIGHT || WINDOWS_MOBILE || SQLITE_WINRT)
|
||||
ManagementObjectSearcher mosLogicalDisks = new ManagementObjectSearcher("select * from Win32_LogicalDisk where DeviceID = '" + diskPath.ToString().Remove(diskPath.Length - 1, 1) + "'");
|
||||
try
|
||||
{
|
||||
foreach (ManagementObject moLogDisk in mosLogicalDisks.Get())
|
||||
{
|
||||
ManagementObjectSearcher mosDiskDrives = new ManagementObjectSearcher("select * from Win32_DiskDrive where SystemName = '" + moLogDisk["SystemName"] + "'");
|
||||
foreach (ManagementObject moPDisk in mosDiskDrives.Get())
|
||||
{
|
||||
return int.Parse(moPDisk["BytesPerSector"].ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
return 4096;
|
||||
#else
|
||||
return 4096;
|
||||
#endif
|
||||
}
|
||||
|
||||
private static void SWAP<T>(ref T A, ref T B)
|
||||
{
|
||||
T t = A;
|
||||
A = B;
|
||||
B = t;
|
||||
}
|
||||
|
||||
private static void x_CountStep(
|
||||
sqlite3_context context,
|
||||
int argc,
|
||||
sqlite3_value[] argv
|
||||
)
|
||||
{
|
||||
SumCtx p;
|
||||
|
||||
int type;
|
||||
Debug.Assert(argc <= 1);
|
||||
Mem pMem = sqlite3_aggregate_context(context, 1);//sizeof(*p));
|
||||
if (pMem._SumCtx == null)
|
||||
pMem._SumCtx = new SumCtx();
|
||||
p = pMem._SumCtx;
|
||||
if (p.Context == null)
|
||||
p.Context = pMem;
|
||||
if (argc == 0 || SQLITE_NULL == sqlite3_value_type(argv[0]))
|
||||
{
|
||||
p.cnt++;
|
||||
p.iSum += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
type = sqlite3_value_numeric_type(argv[0]);
|
||||
if (p != null && type != SQLITE_NULL)
|
||||
{
|
||||
p.cnt++;
|
||||
if (type == SQLITE_INTEGER)
|
||||
{
|
||||
i64 v = sqlite3_value_int64(argv[0]);
|
||||
if (v == 40 || v == 41)
|
||||
{
|
||||
sqlite3_result_error(context, "value of " + v + " handed to x_count", -1);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
p.iSum += v;
|
||||
if (!(p.approx | p.overflow != 0))
|
||||
{
|
||||
i64 iNewSum = p.iSum + v;
|
||||
int s1 = (int)(p.iSum >> (sizeof(i64) * 8 - 1));
|
||||
int s2 = (int)(v >> (sizeof(i64) * 8 - 1));
|
||||
int s3 = (int)(iNewSum >> (sizeof(i64) * 8 - 1));
|
||||
p.overflow = ((s1 & s2 & ~s3) | (~s1 & ~s2 & s3)) != 0 ? 1 : 0;
|
||||
p.iSum = iNewSum;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
p.rSum += sqlite3_value_double(argv[0]);
|
||||
p.approx = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void x_CountFinalize(sqlite3_context context)
|
||||
{
|
||||
SumCtx p;
|
||||
Mem pMem = sqlite3_aggregate_context(context, 0);
|
||||
p = pMem._SumCtx;
|
||||
if (p != null && p.cnt > 0)
|
||||
{
|
||||
if (p.overflow != 0)
|
||||
{
|
||||
sqlite3_result_error(context, "integer overflow", -1);
|
||||
}
|
||||
else if (p.approx)
|
||||
{
|
||||
sqlite3_result_double(context, p.rSum);
|
||||
}
|
||||
else if (p.iSum == 42)
|
||||
{
|
||||
sqlite3_result_error(context, "x_count totals to 42", -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
sqlite3_result_int64(context, p.iSum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if SQLITE_MUTEX_W32
|
||||
|
||||
//---------------------WIN32 Definitions
|
||||
private static int GetCurrentThreadId()
|
||||
{
|
||||
return Thread.CurrentThread.ManagedThreadId;
|
||||
}
|
||||
|
||||
private static long InterlockedIncrement(long location)
|
||||
{
|
||||
Interlocked.Increment(ref location);
|
||||
return location;
|
||||
}
|
||||
|
||||
private static void EnterCriticalSection(Object mtx)
|
||||
{
|
||||
//long mid = mtx.GetHashCode();
|
||||
//int tid = Thread.CurrentThread.ManagedThreadId;
|
||||
//long ticks = cnt++;
|
||||
//Debug.WriteLine(String.Format( "{2}: +EnterCriticalSection; Mutex {0} Thread {1}", mtx.GetHashCode(), Thread.CurrentThread.ManagedThreadId, ticks) );
|
||||
Monitor.Enter(mtx);
|
||||
}
|
||||
|
||||
private static void InitializeCriticalSection(Object mtx)
|
||||
{
|
||||
//Debug.WriteLine(String.Format( "{2}: +InitializeCriticalSection; Mutex {0} Thread {1}", mtx.GetHashCode(), Thread.CurrentThread.ManagedThreadId, System.DateTime.Now.Ticks ));
|
||||
}
|
||||
|
||||
private static void DeleteCriticalSection(Object mtx)
|
||||
{
|
||||
//Debug.WriteLine(String.Format( "{2}: +DeleteCriticalSection; Mutex {0} Thread {1}", mtx.GetHashCode(), Thread.CurrentThread.ManagedThreadId, System.DateTime.Now.Ticks) );
|
||||
}
|
||||
|
||||
private static void LeaveCriticalSection(Object mtx)
|
||||
{
|
||||
//Debug.WriteLine(String.Format("{2}: +LeaveCriticalSection; Mutex {0} Thread {1}", mtx.GetHashCode(), Thread.CurrentThread.ManagedThreadId, System.DateTime.Now.Ticks ));
|
||||
Monitor.Exit(mtx);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Miscellaneous Windows Constants
|
||||
//#define ERROR_FILE_NOT_FOUND 2L
|
||||
//#define ERROR_HANDLE_DISK_FULL 39L
|
||||
//#define ERROR_NOT_SUPPORTED 50L
|
||||
//#define ERROR_DISK_FULL 112L
|
||||
private const long ERROR_FILE_NOT_FOUND = 2L;
|
||||
|
||||
private const long ERROR_HANDLE_DISK_FULL = 39L;
|
||||
private const long ERROR_NOT_SUPPORTED = 50L;
|
||||
private const long ERROR_DISK_FULL = 112L;
|
||||
|
||||
private class SQLite3UpperToLower
|
||||
{
|
||||
private static int[] sqlite3UpperToLower = new int[] {
|
||||
#if SQLITE_ASCII
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
|
||||
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
|
||||
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
|
||||
54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103,
|
||||
104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,
|
||||
122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,
|
||||
108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,
|
||||
126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
|
||||
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,
|
||||
162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,
|
||||
180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,
|
||||
198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,
|
||||
216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,
|
||||
234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,
|
||||
252,253,254,255
|
||||
#endif
|
||||
};
|
||||
|
||||
public int this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (index < sqlite3UpperToLower.Length)
|
||||
return sqlite3UpperToLower[index];
|
||||
else
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
public int this[u32 index]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (index < sqlite3UpperToLower.Length)
|
||||
return sqlite3UpperToLower[index];
|
||||
else
|
||||
return (int)index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static SQLite3UpperToLower sqlite3UpperToLower = new SQLite3UpperToLower();
|
||||
private static SQLite3UpperToLower UpperToLower = sqlite3UpperToLower;
|
||||
}
|
||||
}
|
||||
949
original/Community.CsharpSqlite/src/alter_c.cs
Normal file
949
original/Community.CsharpSqlite/src/alter_c.cs
Normal file
|
|
@ -0,0 +1,949 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
using sqlite3_value = Sqlite3.Mem;
|
||||
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2005 February 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains C code routines that used to generate VDBE code
|
||||
** that implements the ALTER TABLE command.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** The code in this file only exists if we are not omitting the
|
||||
** ALTER TABLE logic from the build.
|
||||
*/
|
||||
#if !SQLITE_OMIT_ALTERTABLE
|
||||
|
||||
/*
|
||||
** This function is used by SQL generated to implement the
|
||||
** ALTER TABLE command. The first argument is the text of a CREATE TABLE or
|
||||
** CREATE INDEX command. The second is a table name. The table name in
|
||||
** the CREATE TABLE or CREATE INDEX statement is replaced with the third
|
||||
** argument and the result returned. Examples:
|
||||
**
|
||||
** sqlite_rename_table('CREATE TABLE abc(a, b, c)', 'def')
|
||||
** . 'CREATE TABLE def(a, b, c)'
|
||||
**
|
||||
** sqlite_rename_table('CREATE INDEX i ON abc(a)', 'def')
|
||||
** . 'CREATE INDEX i ON def(a, b, c)'
|
||||
*/
|
||||
|
||||
private static void renameTableFunc(
|
||||
sqlite3_context context,
|
||||
int NotUsed,
|
||||
sqlite3_value[] argv
|
||||
)
|
||||
{
|
||||
string bResult = sqlite3_value_text(argv[0]);
|
||||
string zSql = bResult == null ? "" : bResult;
|
||||
string zTableName = sqlite3_value_text(argv[1]);
|
||||
|
||||
int token = 0;
|
||||
Token tname = new Token();
|
||||
int zCsr = 0;
|
||||
int zLoc = 0;
|
||||
int len = 0;
|
||||
string zRet;
|
||||
|
||||
sqlite3 db = sqlite3_context_db_handle(context);
|
||||
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
|
||||
/* The principle used to locate the table name in the CREATE TABLE
|
||||
** statement is that the table name is the first non-space token that
|
||||
** is immediately followed by a TK_LP or TK_USING token.
|
||||
*/
|
||||
if (zSql != "")
|
||||
{
|
||||
do
|
||||
{
|
||||
if (zCsr == zSql.Length)
|
||||
{
|
||||
/* Ran out of input before finding an opening bracket. Return NULL. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Store the token that zCsr points to in tname. */
|
||||
zLoc = zCsr;
|
||||
tname.z = zSql.Substring(zCsr);//(char*)zCsr;
|
||||
tname.n = len;
|
||||
|
||||
/* Advance zCsr to the next token. Store that token type in 'token',
|
||||
** and its length in 'len' (to be used next iteration of this loop).
|
||||
*/
|
||||
do
|
||||
{
|
||||
zCsr += len;
|
||||
len = (zCsr == zSql.Length) ? 1 : sqlite3GetToken(zSql, zCsr, ref token);
|
||||
} while (token == TK_SPACE);
|
||||
Debug.Assert(len > 0);
|
||||
} while (token != TK_LP && token != TK_USING);
|
||||
|
||||
zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", zLoc, zSql.Substring(0, zLoc),
|
||||
zTableName, zSql.Substring(zLoc + tname.n));
|
||||
|
||||
sqlite3_result_text(context, zRet, -1, SQLITE_DYNAMIC);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This C function implements an SQL user function that is used by SQL code
|
||||
** generated by the ALTER TABLE ... RENAME command to modify the definition
|
||||
** of any foreign key constraints that use the table being renamed as the
|
||||
** parent table. It is passed three arguments:
|
||||
**
|
||||
** 1) The complete text of the CREATE TABLE statement being modified,
|
||||
** 2) The old name of the table being renamed, and
|
||||
** 3) The new name of the table being renamed.
|
||||
**
|
||||
** It returns the new CREATE TABLE statement. For example:
|
||||
**
|
||||
** sqlite_rename_parent('CREATE TABLE t1(a REFERENCES t2)', 't2', 't3')
|
||||
** -> 'CREATE TABLE t1(a REFERENCES t3)'
|
||||
*/
|
||||
#if !SQLITE_OMIT_FOREIGN_KEY
|
||||
|
||||
private static void renameParentFunc(
|
||||
sqlite3_context context,
|
||||
int NotUsed,
|
||||
sqlite3_value[] argv
|
||||
)
|
||||
{
|
||||
sqlite3 db = sqlite3_context_db_handle(context);
|
||||
string zOutput = "";
|
||||
string zResult;
|
||||
string zInput = sqlite3_value_text(argv[0]);
|
||||
string zOld = sqlite3_value_text(argv[1]);
|
||||
string zNew = sqlite3_value_text(argv[2]);
|
||||
|
||||
int zIdx; /* Pointer to token */
|
||||
int zLeft = 0; /* Pointer to remainder of String */
|
||||
int n = 0; /* Length of token z */
|
||||
int token = 0; /* Type of token */
|
||||
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
for (zIdx = 0; zIdx < zInput.Length; zIdx += n)//z=zInput; *z; z=z+n)
|
||||
{
|
||||
n = sqlite3GetToken(zInput, zIdx, ref token);
|
||||
if (token == TK_REFERENCES)
|
||||
{
|
||||
string zParent;
|
||||
do
|
||||
{
|
||||
zIdx += n;
|
||||
n = sqlite3GetToken(zInput, zIdx, ref token);
|
||||
} while (token == TK_SPACE);
|
||||
|
||||
zParent = zIdx + n < zInput.Length ? zInput.Substring(zIdx, n) : "";//sqlite3DbStrNDup(db, zIdx, n);
|
||||
if (String.IsNullOrEmpty(zParent))
|
||||
break;
|
||||
sqlite3Dequote(ref zParent);
|
||||
if (zOld.Equals(zParent, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
string zOut = sqlite3MPrintf(db, "%s%.*s\"%w\"",
|
||||
zOutput, zIdx - zLeft, zInput.Substring(zLeft), zNew
|
||||
);
|
||||
sqlite3DbFree(db, ref zOutput);
|
||||
zOutput = zOut;
|
||||
zIdx += n;// zInput = &z[n];
|
||||
zLeft = zIdx;
|
||||
}
|
||||
sqlite3DbFree(db, ref zParent);
|
||||
}
|
||||
}
|
||||
|
||||
zResult = sqlite3MPrintf(db, "%s%s", zOutput, zInput.Substring(zLeft));
|
||||
sqlite3_result_text(context, zResult, -1, SQLITE_DYNAMIC);
|
||||
sqlite3DbFree(db, ref zOutput);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !SQLITE_OMIT_TRIGGER
|
||||
/* This function is used by SQL generated to implement the
|
||||
** ALTER TABLE command. The first argument is the text of a CREATE TRIGGER
|
||||
** statement. The second is a table name. The table name in the CREATE
|
||||
** TRIGGER statement is replaced with the third argument and the result
|
||||
** returned. This is analagous to renameTableFunc() above, except for CREATE
|
||||
** TRIGGER, not CREATE INDEX and CREATE TABLE.
|
||||
*/
|
||||
|
||||
private static void renameTriggerFunc(
|
||||
sqlite3_context context,
|
||||
int NotUsed,
|
||||
sqlite3_value[] argv
|
||||
)
|
||||
{
|
||||
string zSql = sqlite3_value_text(argv[0]);
|
||||
string zTableName = sqlite3_value_text(argv[1]);
|
||||
|
||||
int token = 0;
|
||||
Token tname = new Token();
|
||||
int dist = 3;
|
||||
int zCsr = 0;
|
||||
int zLoc = 0;
|
||||
int len = 1;
|
||||
string zRet;
|
||||
|
||||
sqlite3 db = sqlite3_context_db_handle(context);
|
||||
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
|
||||
/* The principle used to locate the table name in the CREATE TRIGGER
|
||||
** statement is that the table name is the first token that is immediatedly
|
||||
** preceded by either TK_ON or TK_DOT and immediatedly followed by one
|
||||
** of TK_WHEN, TK_BEGIN or TK_FOR.
|
||||
*/
|
||||
if (zSql != null)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (zCsr == zSql.Length)
|
||||
{
|
||||
/* Ran out of input before finding the table name. Return NULL. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Store the token that zCsr points to in tname. */
|
||||
zLoc = zCsr;
|
||||
tname.z = zSql.Substring(zCsr, len);//(char*)zCsr;
|
||||
tname.n = len;
|
||||
|
||||
/* Advance zCsr to the next token. Store that token type in 'token',
|
||||
** and its length in 'len' (to be used next iteration of this loop).
|
||||
*/
|
||||
do
|
||||
{
|
||||
zCsr += len;
|
||||
len = (zCsr == zSql.Length) ? 1 : sqlite3GetToken(zSql, zCsr, ref token);
|
||||
} while (token == TK_SPACE);
|
||||
Debug.Assert(len > 0);
|
||||
|
||||
/* Variable 'dist' stores the number of tokens read since the most
|
||||
** recent TK_DOT or TK_ON. This means that when a WHEN, FOR or BEGIN
|
||||
** token is read and 'dist' equals 2, the condition stated above
|
||||
** to be met.
|
||||
**
|
||||
** Note that ON cannot be a database, table or column name, so
|
||||
** there is no need to worry about syntax like
|
||||
** "CREATE TRIGGER ... ON ON.ON BEGIN ..." etc.
|
||||
*/
|
||||
dist++;
|
||||
if (token == TK_DOT || token == TK_ON)
|
||||
{
|
||||
dist = 0;
|
||||
}
|
||||
} while (dist != 2 || (token != TK_WHEN && token != TK_FOR && token != TK_BEGIN));
|
||||
|
||||
/* Variable tname now contains the token that is the old table-name
|
||||
** in the CREATE TRIGGER statement.
|
||||
*/
|
||||
zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", zLoc, zSql.Substring(0, zLoc),
|
||||
zTableName, zSql.Substring(zLoc + tname.n));
|
||||
sqlite3_result_text(context, zRet, -1, SQLITE_DYNAMIC);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // * !SQLITE_OMIT_TRIGGER */
|
||||
|
||||
/*
|
||||
** Register built-in functions used to help implement ALTER TABLE
|
||||
*/
|
||||
private static FuncDef[] aAlterTableFuncs;
|
||||
|
||||
private static void sqlite3AlterFunctions()
|
||||
{
|
||||
aAlterTableFuncs = new FuncDef[] {
|
||||
FUNCTION("sqlite_rename_table", 2, 0, 0, renameTableFunc),
|
||||
#if !SQLITE_OMIT_TRIGGER
|
||||
FUNCTION("sqlite_rename_trigger", 2, 0, 0, renameTriggerFunc),
|
||||
#endif
|
||||
#if !SQLITE_OMIT_FOREIGN_KEY
|
||||
FUNCTION("sqlite_rename_parent", 3, 0, 0, renameParentFunc),
|
||||
#endif
|
||||
};
|
||||
int i;
|
||||
#if SQLITE_OMIT_WSD
|
||||
FuncDefHash pHash = GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
|
||||
FuncDef[] aFunc = GLOBAL(FuncDef, aAlterTableFuncs);
|
||||
#else
|
||||
FuncDefHash pHash = sqlite3GlobalFunctions;
|
||||
FuncDef[] aFunc = aAlterTableFuncs;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < ArraySize(aAlterTableFuncs); i++)
|
||||
{
|
||||
sqlite3FuncDefInsert(pHash, aFunc[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is used to create the text of expressions of the form:
|
||||
**
|
||||
** name=<constant1> OR name=<constant2> OR ...
|
||||
**
|
||||
** If argument zWhere is NULL, then a pointer string containing the text
|
||||
** "name=<constant>" is returned, where <constant> is the quoted version
|
||||
** of the string passed as argument zConstant. The returned buffer is
|
||||
** allocated using sqlite3DbMalloc(). It is the responsibility of the
|
||||
** caller to ensure that it is eventually freed.
|
||||
**
|
||||
** If argument zWhere is not NULL, then the string returned is
|
||||
** "<where> OR name=<constant>", where <where> is the contents of zWhere.
|
||||
** In this case zWhere is passed to sqlite3DbFree() before returning.
|
||||
**
|
||||
*/
|
||||
|
||||
private static string whereOrName(sqlite3 db, string zWhere, string zConstant)
|
||||
{
|
||||
string zNew;
|
||||
if (String.IsNullOrEmpty(zWhere))
|
||||
{
|
||||
zNew = sqlite3MPrintf(db, "name=%Q", zConstant);
|
||||
}
|
||||
else
|
||||
{
|
||||
zNew = sqlite3MPrintf(db, "%s OR name=%Q", zWhere, zConstant);
|
||||
sqlite3DbFree(db, ref zWhere);
|
||||
}
|
||||
return zNew;
|
||||
}
|
||||
|
||||
#if !(SQLITE_OMIT_FOREIGN_KEY) && !(SQLITE_OMIT_TRIGGER)
|
||||
/*
|
||||
** Generate the text of a WHERE expression which can be used to select all
|
||||
** tables that have foreign key constraints that refer to table pTab (i.e.
|
||||
** constraints for which pTab is the parent table) from the sqlite_master
|
||||
** table.
|
||||
*/
|
||||
|
||||
private static string whereForeignKeys(Parse pParse, Table pTab)
|
||||
{
|
||||
FKey p;
|
||||
string zWhere = "";
|
||||
for (p = sqlite3FkReferences(pTab); p != null; p = p.pNextTo)
|
||||
{
|
||||
zWhere = whereOrName(pParse.db, zWhere, p.pFrom.zName);
|
||||
}
|
||||
return zWhere;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Generate the text of a WHERE expression which can be used to select all
|
||||
** temporary triggers on table pTab from the sqlite_temp_master table. If
|
||||
** table pTab has no temporary triggers, or is itself stored in the
|
||||
** temporary database, NULL is returned.
|
||||
*/
|
||||
|
||||
private static string whereTempTriggers(Parse pParse, Table pTab)
|
||||
{
|
||||
Trigger pTrig;
|
||||
string zWhere = "";
|
||||
Schema pTempSchema = pParse.db.aDb[1].pSchema; /* Temp db schema */
|
||||
|
||||
/* If the table is not located in the temp.db (in which case NULL is
|
||||
** returned, loop through the tables list of triggers. For each trigger
|
||||
** that is not part of the temp.db schema, add a clause to the WHERE
|
||||
** expression being built up in zWhere.
|
||||
*/
|
||||
if (pTab.pSchema != pTempSchema)
|
||||
{
|
||||
sqlite3 db = pParse.db;
|
||||
for (pTrig = sqlite3TriggerList(pParse, pTab); pTrig != null; pTrig = pTrig.pNext)
|
||||
{
|
||||
if (pTrig.pSchema == pTempSchema)
|
||||
{
|
||||
zWhere = whereOrName(db, zWhere, pTrig.zName);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!String.IsNullOrEmpty(zWhere))
|
||||
{
|
||||
zWhere = sqlite3MPrintf(pParse.db, "type='trigger' AND (%s)", zWhere);
|
||||
//sqlite3DbFree( pParse.db, ref zWhere );
|
||||
//zWhere = zNew;
|
||||
}
|
||||
return zWhere;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code to drop and reload the internal representation of table
|
||||
** pTab from the database, including triggers and temporary triggers.
|
||||
** Argument zName is the name of the table in the database schema at
|
||||
** the time the generated code is executed. This can be different from
|
||||
** pTab.zName if this function is being called to code part of an
|
||||
** "ALTER TABLE RENAME TO" statement.
|
||||
*/
|
||||
|
||||
private static void reloadTableSchema(Parse pParse, Table pTab, string zName)
|
||||
{
|
||||
Vdbe v;
|
||||
string zWhere;
|
||||
int iDb; /* Index of database containing pTab */
|
||||
#if !SQLITE_OMIT_TRIGGER
|
||||
Trigger pTrig;
|
||||
#endif
|
||||
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if (NEVER(v == null))
|
||||
return;
|
||||
Debug.Assert(sqlite3BtreeHoldsAllMutexes(pParse.db));
|
||||
iDb = sqlite3SchemaToIndex(pParse.db, pTab.pSchema);
|
||||
Debug.Assert(iDb >= 0);
|
||||
|
||||
#if !SQLITE_OMIT_TRIGGER
|
||||
/* Drop any table triggers from the internal schema. */
|
||||
for (pTrig = sqlite3TriggerList(pParse, pTab); pTrig != null; pTrig = pTrig.pNext)
|
||||
{
|
||||
int iTrigDb = sqlite3SchemaToIndex(pParse.db, pTrig.pSchema);
|
||||
Debug.Assert(iTrigDb == iDb || iTrigDb == 1);
|
||||
sqlite3VdbeAddOp4(v, OP_DropTrigger, iTrigDb, 0, 0, pTrig.zName, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Drop the table and index from the internal schema. */
|
||||
sqlite3VdbeAddOp4(v, OP_DropTable, iDb, 0, 0, pTab.zName, 0);
|
||||
|
||||
/* Reload the table, index and permanent trigger schemas. */
|
||||
zWhere = sqlite3MPrintf(pParse.db, "tbl_name=%Q", zName);
|
||||
if (zWhere == null)
|
||||
return;
|
||||
sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere);
|
||||
|
||||
#if !SQLITE_OMIT_TRIGGER
|
||||
/* Now, if the table is not stored in the temp database, reload any temp
|
||||
** triggers. Don't use IN(...) in case SQLITE_OMIT_SUBQUERY is defined.
|
||||
*/
|
||||
if ((zWhere = whereTempTriggers(pParse, pTab)) != "")
|
||||
{
|
||||
sqlite3VdbeAddParseSchemaOp(v, 1, zWhere);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Parameter zName is the name of a table that is about to be altered
|
||||
** (either with ALTER TABLE ... RENAME TO or ALTER TABLE ... ADD COLUMN).
|
||||
** If the table is a system table, this function leaves an error message
|
||||
** in pParse->zErr (system tables may not be altered) and returns non-zero.
|
||||
**
|
||||
** Or, if zName is not a system table, zero is returned.
|
||||
*/
|
||||
|
||||
private static int isSystemTable(Parse pParse, string zName)
|
||||
{
|
||||
if (zName.StartsWith("sqlite_", System.StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
sqlite3ErrorMsg(pParse, "table %s may not be altered", zName);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code to implement the "ALTER TABLE xxx RENAME TO yyy"
|
||||
** command.
|
||||
*/
|
||||
|
||||
private static void sqlite3AlterRenameTable(
|
||||
Parse pParse, /* Parser context. */
|
||||
SrcList pSrc, /* The table to rename. */
|
||||
Token pName /* The new table name. */
|
||||
)
|
||||
{
|
||||
int iDb; /* Database that contains the table */
|
||||
string zDb; /* Name of database iDb */
|
||||
Table pTab; /* Table being renamed */
|
||||
string zName = null; /* NULL-terminated version of pName */
|
||||
sqlite3 db = pParse.db; /* Database connection */
|
||||
int nTabName; /* Number of UTF-8 characters in zTabName */
|
||||
string zTabName; /* Original name of the table */
|
||||
Vdbe v;
|
||||
#if !SQLITE_OMIT_TRIGGER
|
||||
string zWhere = ""; /* Where clause to locate temp triggers */
|
||||
#endif
|
||||
VTable pVTab = null; /* Non-zero if this is a v-tab with an xRename() */
|
||||
int savedDbFlags; /* Saved value of db->flags */
|
||||
|
||||
savedDbFlags = db.flags;
|
||||
|
||||
//if ( NEVER( db.mallocFailed != 0 ) ) goto exit_rename_table;
|
||||
Debug.Assert(pSrc.nSrc == 1);
|
||||
Debug.Assert(sqlite3BtreeHoldsAllMutexes(pParse.db));
|
||||
pTab = sqlite3LocateTable(pParse, 0, pSrc.a[0].zName, pSrc.a[0].zDatabase);
|
||||
if (pTab == null)
|
||||
goto exit_rename_table;
|
||||
iDb = sqlite3SchemaToIndex(pParse.db, pTab.pSchema);
|
||||
zDb = db.aDb[iDb].zName;
|
||||
db.flags |= SQLITE_PreferBuiltin;
|
||||
|
||||
/* Get a NULL terminated version of the new table name. */
|
||||
zName = sqlite3NameFromToken(db, pName);
|
||||
if (zName == null)
|
||||
goto exit_rename_table;
|
||||
|
||||
/* Check that a table or index named 'zName' does not already exist
|
||||
** in database iDb. If so, this is an error.
|
||||
*/
|
||||
if (sqlite3FindTable(db, zName, zDb) != null || sqlite3FindIndex(db, zName, zDb) != null)
|
||||
{
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"there is already another table or index with this name: %s", zName);
|
||||
goto exit_rename_table;
|
||||
}
|
||||
|
||||
/* Make sure it is not a system table being altered, or a reserved name
|
||||
** that the table is being renamed to.
|
||||
*/
|
||||
if (SQLITE_OK != isSystemTable(pParse, pTab.zName))
|
||||
{
|
||||
goto exit_rename_table;
|
||||
}
|
||||
if (SQLITE_OK != sqlite3CheckObjectName(pParse, zName))
|
||||
{
|
||||
goto exit_rename_table;
|
||||
}
|
||||
|
||||
#if !SQLITE_OMIT_VIEW
|
||||
if (pTab.pSelect != null)
|
||||
{
|
||||
sqlite3ErrorMsg(pParse, "view %s may not be altered", pTab.zName);
|
||||
goto exit_rename_table;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !SQLITE_OMIT_AUTHORIZATION
|
||||
/* Invoke the authorization callback. */
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab.zName, 0) ){
|
||||
goto exit_rename_table;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (sqlite3ViewGetColumnNames(pParse, pTab) != 0)
|
||||
{
|
||||
goto exit_rename_table;
|
||||
}
|
||||
#if !SQLITE_OMIT_VIRTUALTABLE
|
||||
if (IsVirtual(pTab))
|
||||
{
|
||||
pVTab = sqlite3GetVTable(db, pTab);
|
||||
if (pVTab.pVtab.pModule.xRename == null)
|
||||
{
|
||||
pVTab = null;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* Begin a transaction and code the VerifyCookie for database iDb.
|
||||
** Then modify the schema cookie (since the ALTER TABLE modifies the
|
||||
** schema). Open a statement transaction if the table is a virtual
|
||||
** table.
|
||||
*/
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if (v == null)
|
||||
{
|
||||
goto exit_rename_table;
|
||||
}
|
||||
sqlite3BeginWriteOperation(pParse, pVTab != null ? 1 : 0, iDb);
|
||||
sqlite3ChangeCookie(pParse, iDb);
|
||||
|
||||
/* If this is a virtual table, invoke the xRename() function if
|
||||
** one is defined. The xRename() callback will modify the names
|
||||
** of any resources used by the v-table implementation (including other
|
||||
** SQLite tables) that are identified by the name of the virtual table.
|
||||
*/
|
||||
#if !SQLITE_OMIT_VIRTUALTABLE
|
||||
if (pVTab != null)
|
||||
{
|
||||
int i = ++pParse.nMem;
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, i, 0, zName, 0);
|
||||
sqlite3VdbeAddOp4(v, OP_VRename, i, 0, 0, pVTab, P4_VTAB);
|
||||
sqlite3MayAbort(pParse);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* figure out how many UTF-8 characters are in zName */
|
||||
zTabName = pTab.zName;
|
||||
nTabName = sqlite3Utf8CharLen(zTabName, -1);
|
||||
|
||||
#if !(SQLITE_OMIT_FOREIGN_KEY) && !(SQLITE_OMIT_TRIGGER)
|
||||
if ((db.flags & SQLITE_ForeignKeys) != 0)
|
||||
{
|
||||
/* If foreign-key support is enabled, rewrite the CREATE TABLE
|
||||
** statements corresponding to all child tables of foreign key constraints
|
||||
** for which the renamed table is the parent table. */
|
||||
if ((zWhere = whereForeignKeys(pParse, pTab)) != null)
|
||||
{
|
||||
sqlite3NestedParse(pParse,
|
||||
"UPDATE \"%w\".%s SET " +
|
||||
"sql = sqlite_rename_parent(sql, %Q, %Q) " +
|
||||
"WHERE %s;", zDb, SCHEMA_TABLE(iDb), zTabName, zName, zWhere);
|
||||
sqlite3DbFree(db, ref zWhere);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Modify the sqlite_master table to use the new table name. */
|
||||
sqlite3NestedParse(pParse,
|
||||
"UPDATE %Q.%s SET " +
|
||||
#if SQLITE_OMIT_TRIGGER
|
||||
"sql = sqlite_rename_table(sql, %Q), " +
|
||||
#else
|
||||
"sql = CASE " +
|
||||
"WHEN type = 'trigger' THEN sqlite_rename_trigger(sql, %Q)" +
|
||||
"ELSE sqlite_rename_table(sql, %Q) END, " +
|
||||
#endif
|
||||
"tbl_name = %Q, " +
|
||||
"name = CASE " +
|
||||
"WHEN type='table' THEN %Q " +
|
||||
"WHEN name LIKE 'sqlite_autoindex%%' AND type='index' THEN " +
|
||||
"'sqlite_autoindex_' || %Q || substr(name,%d+18) " +
|
||||
"ELSE name END " +
|
||||
"WHERE tbl_name=%Q AND " +
|
||||
"(type='table' OR type='index' OR type='trigger');",
|
||||
zDb, SCHEMA_TABLE(iDb), zName, zName, zName,
|
||||
#if !SQLITE_OMIT_TRIGGER
|
||||
zName,
|
||||
#endif
|
||||
zName, nTabName, zTabName
|
||||
);
|
||||
|
||||
#if !SQLITE_OMIT_AUTOINCREMENT
|
||||
/* If the sqlite_sequence table exists in this database, then update
|
||||
** it with the new table name.
|
||||
*/
|
||||
if (sqlite3FindTable(db, "sqlite_sequence", zDb) != null)
|
||||
{
|
||||
sqlite3NestedParse(pParse,
|
||||
"UPDATE \"%w\".sqlite_sequence set name = %Q WHERE name = %Q",
|
||||
zDb, zName, pTab.zName
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !SQLITE_OMIT_TRIGGER
|
||||
/* If there are TEMP triggers on this table, modify the sqlite_temp_master
|
||||
** table. Don't do this if the table being ALTERed is itself located in
|
||||
** the temp database.
|
||||
*/
|
||||
if ((zWhere = whereTempTriggers(pParse, pTab)) != "")
|
||||
{
|
||||
sqlite3NestedParse(pParse,
|
||||
"UPDATE sqlite_temp_master SET " +
|
||||
"sql = sqlite_rename_trigger(sql, %Q), " +
|
||||
"tbl_name = %Q " +
|
||||
"WHERE %s;", zName, zName, zWhere);
|
||||
sqlite3DbFree(db, ref zWhere);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !(SQLITE_OMIT_FOREIGN_KEY) && !(SQLITE_OMIT_TRIGGER)
|
||||
if ((db.flags & SQLITE_ForeignKeys) != 0)
|
||||
{
|
||||
FKey p;
|
||||
for (p = sqlite3FkReferences(pTab); p != null; p = p.pNextTo)
|
||||
{
|
||||
Table pFrom = p.pFrom;
|
||||
if (pFrom != pTab)
|
||||
{
|
||||
reloadTableSchema(pParse, p.pFrom, pFrom.zName);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Drop and reload the internal table schema. */
|
||||
reloadTableSchema(pParse, pTab, zName);
|
||||
|
||||
exit_rename_table:
|
||||
sqlite3SrcListDelete(db, ref pSrc);
|
||||
sqlite3DbFree(db, ref zName);
|
||||
db.flags = savedDbFlags;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code to make sure the file format number is at least minFormat.
|
||||
** The generated code will increase the file format number if necessary.
|
||||
*/
|
||||
|
||||
private static void sqlite3MinimumFileFormat(Parse pParse, int iDb, int minFormat)
|
||||
{
|
||||
Vdbe v;
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
/* The VDBE should have been allocated before this routine is called.
|
||||
** If that allocation failed, we would have quit before reaching this
|
||||
** point */
|
||||
if (ALWAYS(v))
|
||||
{
|
||||
int r1 = sqlite3GetTempReg(pParse);
|
||||
int r2 = sqlite3GetTempReg(pParse);
|
||||
int j1;
|
||||
sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, BTREE_FILE_FORMAT);
|
||||
sqlite3VdbeUsesBtree(v, iDb);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, minFormat, r2);
|
||||
j1 = sqlite3VdbeAddOp3(v, OP_Ge, r2, 0, r1);
|
||||
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, r2);
|
||||
sqlite3VdbeJumpHere(v, j1);
|
||||
sqlite3ReleaseTempReg(pParse, r1);
|
||||
sqlite3ReleaseTempReg(pParse, r2);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is called after an "ALTER TABLE ... ADD" statement
|
||||
** has been parsed. Argument pColDef contains the text of the new
|
||||
** column definition.
|
||||
**
|
||||
** The Table structure pParse.pNewTable was extended to include
|
||||
** the new column during parsing.
|
||||
*/
|
||||
|
||||
private static void sqlite3AlterFinishAddColumn(Parse pParse, Token pColDef)
|
||||
{
|
||||
Table pNew; /* Copy of pParse.pNewTable */
|
||||
Table pTab; /* Table being altered */
|
||||
int iDb; /* Database number */
|
||||
string zDb; /* Database name */
|
||||
string zTab; /* Table name */
|
||||
string zCol; /* Null-terminated column definition */
|
||||
Column pCol; /* The new column */
|
||||
Expr pDflt; /* Default value for the new column */
|
||||
sqlite3 db; /* The database connection; */
|
||||
|
||||
db = pParse.db;
|
||||
if (pParse.nErr != 0 /*|| db.mallocFailed != 0 */ )
|
||||
return;
|
||||
pNew = pParse.pNewTable;
|
||||
Debug.Assert(pNew != null);
|
||||
Debug.Assert(sqlite3BtreeHoldsAllMutexes(db));
|
||||
iDb = sqlite3SchemaToIndex(db, pNew.pSchema);
|
||||
zDb = db.aDb[iDb].zName;
|
||||
zTab = pNew.zName.Substring(16);// zTab = &pNew->zName[16]; /* Skip the "sqlite_altertab_" prefix on the name */
|
||||
pCol = pNew.aCol[pNew.nCol - 1];
|
||||
pDflt = pCol.pDflt;
|
||||
pTab = sqlite3FindTable(db, zTab, zDb);
|
||||
Debug.Assert(pTab != null);
|
||||
|
||||
#if !SQLITE_OMIT_AUTHORIZATION
|
||||
/* Invoke the authorization callback. */
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab.zName, 0) ){
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If the default value for the new column was specified with a
|
||||
** literal NULL, then set pDflt to 0. This simplifies checking
|
||||
** for an SQL NULL default below.
|
||||
*/
|
||||
if (pDflt != null && pDflt.op == TK_NULL)
|
||||
{
|
||||
pDflt = null;
|
||||
}
|
||||
|
||||
/* Check that the new column is not specified as PRIMARY KEY or UNIQUE.
|
||||
** If there is a NOT NULL constraint, then the default value for the
|
||||
** column must not be NULL.
|
||||
*/
|
||||
if (pCol.isPrimKey != 0)
|
||||
{
|
||||
sqlite3ErrorMsg(pParse, "Cannot add a PRIMARY KEY column");
|
||||
return;
|
||||
}
|
||||
if (pNew.pIndex != null)
|
||||
{
|
||||
sqlite3ErrorMsg(pParse, "Cannot add a UNIQUE column");
|
||||
return;
|
||||
}
|
||||
if ((db.flags & SQLITE_ForeignKeys) != 0 && pNew.pFKey != null && pDflt != null)
|
||||
{
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"Cannot add a REFERENCES column with non-NULL default value");
|
||||
return;
|
||||
}
|
||||
if (pCol.notNull != 0 && pDflt == null)
|
||||
{
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"Cannot add a NOT NULL column with default value NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Ensure the default expression is something that sqlite3ValueFromExpr()
|
||||
** can handle (i.e. not CURRENT_TIME etc.)
|
||||
*/
|
||||
if (pDflt != null)
|
||||
{
|
||||
sqlite3_value pVal = null;
|
||||
if (sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, ref pVal) != 0)
|
||||
{
|
||||
// db.mallocFailed = 1;
|
||||
return;
|
||||
}
|
||||
if (pVal == null)
|
||||
{
|
||||
sqlite3ErrorMsg(pParse, "Cannot add a column with non-constant default");
|
||||
return;
|
||||
}
|
||||
sqlite3ValueFree(ref pVal);
|
||||
}
|
||||
|
||||
/* Modify the CREATE TABLE statement. */
|
||||
zCol = pColDef.z.Substring(0, pColDef.n).Replace(";", " ").Trim();//sqlite3DbStrNDup(db, (char*)pColDef.z, pColDef.n);
|
||||
if (zCol != null)
|
||||
{
|
||||
// char zEnd = zCol[pColDef.n-1];
|
||||
int savedDbFlags = db.flags;
|
||||
// while( zEnd>zCol && (*zEnd==';' || sqlite3Isspace(*zEnd)) ){
|
||||
// zEnd-- = '\0';
|
||||
// }
|
||||
db.flags |= SQLITE_PreferBuiltin;
|
||||
sqlite3NestedParse(pParse,
|
||||
"UPDATE \"%w\".%s SET " +
|
||||
"sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d) " +
|
||||
"WHERE type = 'table' AND name = %Q",
|
||||
zDb, SCHEMA_TABLE(iDb), pNew.addColOffset, zCol, pNew.addColOffset + 1,
|
||||
zTab
|
||||
);
|
||||
sqlite3DbFree(db, ref zCol);
|
||||
db.flags = savedDbFlags;
|
||||
}
|
||||
|
||||
/* If the default value of the new column is NULL, then set the file
|
||||
** format to 2. If the default value of the new column is not NULL,
|
||||
** the file format becomes 3.
|
||||
*/
|
||||
sqlite3MinimumFileFormat(pParse, iDb, pDflt != null ? 3 : 2);
|
||||
|
||||
/* Reload the schema of the modified table. */
|
||||
reloadTableSchema(pParse, pTab, pTab.zName);
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is called by the parser after the table-name in
|
||||
** an "ALTER TABLE <table-name> ADD" statement is parsed. Argument
|
||||
** pSrc is the full-name of the table being altered.
|
||||
**
|
||||
** This routine makes a (partial) copy of the Table structure
|
||||
** for the table being altered and sets Parse.pNewTable to point
|
||||
** to it. Routines called by the parser as the column definition
|
||||
** is parsed (i.e. sqlite3AddColumn()) add the new Column data to
|
||||
** the copy. The copy of the Table structure is deleted by tokenize.c
|
||||
** after parsing is finished.
|
||||
**
|
||||
** Routine sqlite3AlterFinishAddColumn() will be called to complete
|
||||
** coding the "ALTER TABLE ... ADD" statement.
|
||||
*/
|
||||
|
||||
private static void sqlite3AlterBeginAddColumn(Parse pParse, SrcList pSrc)
|
||||
{
|
||||
Table pNew;
|
||||
Table pTab;
|
||||
Vdbe v;
|
||||
int iDb;
|
||||
int i;
|
||||
int nAlloc;
|
||||
sqlite3 db = pParse.db;
|
||||
|
||||
/* Look up the table being altered. */
|
||||
Debug.Assert(pParse.pNewTable == null);
|
||||
Debug.Assert(sqlite3BtreeHoldsAllMutexes(db));
|
||||
// if ( db.mallocFailed != 0 ) goto exit_begin_add_column;
|
||||
pTab = sqlite3LocateTable(pParse, 0, pSrc.a[0].zName, pSrc.a[0].zDatabase);
|
||||
if (pTab == null)
|
||||
goto exit_begin_add_column;
|
||||
|
||||
if (IsVirtual(pTab))
|
||||
{
|
||||
sqlite3ErrorMsg(pParse, "virtual tables may not be altered");
|
||||
goto exit_begin_add_column;
|
||||
}
|
||||
|
||||
/* Make sure this is not an attempt to ALTER a view. */
|
||||
if (pTab.pSelect != null)
|
||||
{
|
||||
sqlite3ErrorMsg(pParse, "Cannot add a column to a view");
|
||||
goto exit_begin_add_column;
|
||||
}
|
||||
if (SQLITE_OK != isSystemTable(pParse, pTab.zName))
|
||||
{
|
||||
goto exit_begin_add_column;
|
||||
}
|
||||
|
||||
Debug.Assert(pTab.addColOffset > 0);
|
||||
iDb = sqlite3SchemaToIndex(db, pTab.pSchema);
|
||||
|
||||
/* Put a copy of the Table struct in Parse.pNewTable for the
|
||||
** sqlite3AddColumn() function and friends to modify. But modify
|
||||
** the name by adding an "sqlite_altertab_" prefix. By adding this
|
||||
** prefix, we insure that the name will not collide with an existing
|
||||
** table because user table are not allowed to have the "sqlite_"
|
||||
** prefix on their name.
|
||||
*/
|
||||
pNew = new Table();// (Table*)sqlite3DbMallocZero( db, sizeof(Table))
|
||||
if (pNew == null)
|
||||
goto exit_begin_add_column;
|
||||
pParse.pNewTable = pNew;
|
||||
pNew.nRef = 1;
|
||||
pNew.nCol = pTab.nCol;
|
||||
Debug.Assert(pNew.nCol > 0);
|
||||
nAlloc = (((pNew.nCol - 1) / 8) * 8) + 8;
|
||||
Debug.Assert(nAlloc >= pNew.nCol && nAlloc % 8 == 0 && nAlloc - pNew.nCol < 8);
|
||||
pNew.aCol = new Column[nAlloc];// (Column*)sqlite3DbMallocZero( db, sizeof(Column) * nAlloc );
|
||||
pNew.zName = sqlite3MPrintf(db, "sqlite_altertab_%s", pTab.zName);
|
||||
if (pNew.aCol == null || pNew.zName == null)
|
||||
{
|
||||
// db.mallocFailed = 1;
|
||||
goto exit_begin_add_column;
|
||||
}
|
||||
// memcpy( pNew.aCol, pTab.aCol, sizeof(Column) * pNew.nCol );
|
||||
for (i = 0; i < pNew.nCol; i++)
|
||||
{
|
||||
Column pCol = pTab.aCol[i].Copy();
|
||||
// sqlite3DbStrDup( db, pCol.zName );
|
||||
pCol.zColl = null;
|
||||
pCol.zType = null;
|
||||
pCol.pDflt = null;
|
||||
pCol.zDflt = null;
|
||||
pNew.aCol[i] = pCol;
|
||||
}
|
||||
pNew.pSchema = db.aDb[iDb].pSchema;
|
||||
pNew.addColOffset = pTab.addColOffset;
|
||||
pNew.nRef = 1;
|
||||
|
||||
/* Begin a transaction and increment the schema cookie. */
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if (v == null)
|
||||
goto exit_begin_add_column;
|
||||
sqlite3ChangeCookie(pParse, iDb);
|
||||
|
||||
exit_begin_add_column:
|
||||
sqlite3SrcListDelete(db, ref pSrc);
|
||||
return;
|
||||
}
|
||||
|
||||
#endif // * SQLITE_ALTER_TABLE */
|
||||
}
|
||||
}
|
||||
875
original/Community.CsharpSqlite/src/analyze_c.cs
Normal file
875
original/Community.CsharpSqlite/src/analyze_c.cs
Normal file
|
|
@ -0,0 +1,875 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
using u8 = System.Byte;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
using sqlite3_int64 = System.Int64;
|
||||
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2005 July 8
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains code associated with the ANALYZE command.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2011-05-19 13:26:54 ed1da510a239ea767a01dc332b667119fa3c908e
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
#if !SQLITE_OMIT_ANALYZE
|
||||
//#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** This routine generates code that opens the sqlite_stat1 table for
|
||||
** writing with cursor iStatCur. If the library was built with the
|
||||
** SQLITE_ENABLE_STAT2 macro defined, then the sqlite_stat2 table is
|
||||
** opened for writing using cursor (iStatCur+1)
|
||||
**
|
||||
** If the sqlite_stat1 tables does not previously exist, it is created.
|
||||
** Similarly, if the sqlite_stat2 table does not exist and the library
|
||||
** is compiled with SQLITE_ENABLE_STAT2 defined, it is created.
|
||||
**
|
||||
** Argument zWhere may be a pointer to a buffer containing a table name,
|
||||
** or it may be a NULL pointer. If it is not NULL, then all entries in
|
||||
** the sqlite_stat1 and (if applicable) sqlite_stat2 tables associated
|
||||
** with the named table are deleted. If zWhere==0, then code is generated
|
||||
** to delete all stat table entries.
|
||||
*/
|
||||
|
||||
public struct _aTable
|
||||
{
|
||||
public string zName;
|
||||
public string zCols;
|
||||
|
||||
public _aTable(string zName, string zCols)
|
||||
{
|
||||
this.zName = zName;
|
||||
this.zCols = zCols;
|
||||
}
|
||||
};
|
||||
|
||||
private static _aTable[] aTable = new _aTable[]{
|
||||
new _aTable( "sqlite_stat1", "tbl,idx,stat" ),
|
||||
#if SQLITE_ENABLE_STAT2
|
||||
new _aTable( "sqlite_stat2", "tbl,idx,sampleno,sample" ),
|
||||
#endif
|
||||
};
|
||||
|
||||
private static void openStatTable(
|
||||
Parse pParse, /* Parsing context */
|
||||
int iDb, /* The database we are looking in */
|
||||
int iStatCur, /* Open the sqlite_stat1 table on this cursor */
|
||||
string zWhere, /* Delete entries for this table or index */
|
||||
string zWhereType /* Either "tbl" or "idx" */
|
||||
)
|
||||
{
|
||||
int[] aRoot = new int[] { 0, 0 };
|
||||
u8[] aCreateTbl = new u8[] { 0, 0 };
|
||||
|
||||
int i;
|
||||
sqlite3 db = pParse.db;
|
||||
Db pDb;
|
||||
Vdbe v = sqlite3GetVdbe(pParse);
|
||||
|
||||
if (v == null)
|
||||
return;
|
||||
Debug.Assert(sqlite3BtreeHoldsAllMutexes(db));
|
||||
Debug.Assert(sqlite3VdbeDb(v) == db);
|
||||
pDb = db.aDb[iDb];
|
||||
|
||||
for (i = 0; i < ArraySize(aTable); i++)
|
||||
{
|
||||
string zTab = aTable[i].zName;
|
||||
Table pStat;
|
||||
if ((pStat = sqlite3FindTable(db, zTab, pDb.zName)) == null)
|
||||
{
|
||||
/* The sqlite_stat[12] table does not exist. Create it. Note that a
|
||||
** side-effect of the CREATE TABLE statement is to leave the rootpage
|
||||
** of the new table in register pParse.regRoot. This is important
|
||||
** because the OpenWrite opcode below will be needing it. */
|
||||
sqlite3NestedParse(pParse,
|
||||
"CREATE TABLE %Q.%s(%s)", pDb.zName, zTab, aTable[i].zCols
|
||||
);
|
||||
aRoot[i] = pParse.regRoot;
|
||||
aCreateTbl[i] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The table already exists. If zWhere is not NULL, delete all entries
|
||||
** associated with the table zWhere. If zWhere is NULL, delete the
|
||||
** entire contents of the table. */
|
||||
aRoot[i] = pStat.tnum;
|
||||
sqlite3TableLock(pParse, iDb, aRoot[i], 1, zTab);
|
||||
if (!String.IsNullOrEmpty(zWhere))
|
||||
{
|
||||
sqlite3NestedParse(pParse,
|
||||
"DELETE FROM %Q.%s WHERE %s=%Q", pDb.zName, zTab, zWhereType, zWhere
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The sqlite_stat[12] table already exists. Delete all rows. */
|
||||
sqlite3VdbeAddOp2(v, OP_Clear, aRoot[i], iDb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Open the sqlite_stat[12] tables for writing. */
|
||||
for (i = 0; i < ArraySize(aTable); i++)
|
||||
{
|
||||
sqlite3VdbeAddOp3(v, OP_OpenWrite, iStatCur + i, aRoot[i], iDb);
|
||||
sqlite3VdbeChangeP4(v, -1, 3, P4_INT32);
|
||||
sqlite3VdbeChangeP5(v, aCreateTbl[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code to do an analysis of all indices associated with
|
||||
** a single table.
|
||||
*/
|
||||
|
||||
private static void analyzeOneTable(
|
||||
Parse pParse, /* Parser context */
|
||||
Table pTab, /* Table whose indices are to be analyzed */
|
||||
Index pOnlyIdx, /* If not NULL, only analyze this one index */
|
||||
int iStatCur, /* Index of VdbeCursor that writes the sqlite_stat1 table */
|
||||
int iMem /* Available memory locations begin here */
|
||||
)
|
||||
{
|
||||
sqlite3 db = pParse.db; /* Database handle */
|
||||
Index pIdx; /* An index to being analyzed */
|
||||
int iIdxCur; /* Cursor open on index being analyzed */
|
||||
Vdbe v; /* The virtual machine being built up */
|
||||
int i; /* Loop counter */
|
||||
int topOfLoop; /* The top of the loop */
|
||||
int endOfLoop; /* The end of the loop */
|
||||
int jZeroRows = -1; /* Jump from here if number of rows is zero */
|
||||
int iDb; /* Index of database containing pTab */
|
||||
int regTabname = iMem++; /* Register containing table name */
|
||||
int regIdxname = iMem++; /* Register containing index name */
|
||||
int regSampleno = iMem++; /* Register containing next sample number */
|
||||
int regCol = iMem++; /* Content of a column analyzed table */
|
||||
int regRec = iMem++; /* Register holding completed record */
|
||||
int regTemp = iMem++; /* Temporary use register */
|
||||
int regRowid = iMem++; /* Rowid for the inserted record */
|
||||
|
||||
#if SQLITE_ENABLE_STAT2
|
||||
int addr = 0; /* Instruction address */
|
||||
int regTemp2 = iMem++; /* Temporary use register */
|
||||
int regSamplerecno = iMem++; /* Index of next sample to record */
|
||||
int regRecno = iMem++; /* Current sample index */
|
||||
int regLast = iMem++; /* Index of last sample to record */
|
||||
int regFirst = iMem++; /* Index of first sample to record */
|
||||
#endif
|
||||
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if (v == null || NEVER(pTab == null))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (pTab.tnum == 0)
|
||||
{
|
||||
/* Do not gather statistics on views or virtual tables */
|
||||
return;
|
||||
}
|
||||
if (pTab.zName.StartsWith("sqlite_", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
/* Do not gather statistics on system tables */
|
||||
return;
|
||||
}
|
||||
Debug.Assert(sqlite3BtreeHoldsAllMutexes(db));
|
||||
iDb = sqlite3SchemaToIndex(db, pTab.pSchema);
|
||||
Debug.Assert(iDb >= 0);
|
||||
Debug.Assert(sqlite3SchemaMutexHeld(db, iDb, null));
|
||||
#if !SQLITE_OMIT_AUTHORIZATION
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_ANALYZE, pTab.zName, 0,
|
||||
db.aDb[iDb].zName ) ){
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Establish a read-lock on the table at the shared-cache level. */
|
||||
sqlite3TableLock(pParse, iDb, pTab.tnum, 0, pTab.zName);
|
||||
|
||||
iIdxCur = pParse.nTab++;
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, regTabname, 0, pTab.zName, 0);
|
||||
for (pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext)
|
||||
{
|
||||
int nCol;
|
||||
KeyInfo pKey;
|
||||
if (pOnlyIdx != null && pOnlyIdx != pIdx)
|
||||
continue;
|
||||
nCol = pIdx.nColumn;
|
||||
pKey = sqlite3IndexKeyinfo(pParse, pIdx);
|
||||
|
||||
if (iMem + 1 + (nCol * 2) > pParse.nMem)
|
||||
{
|
||||
pParse.nMem = iMem + 1 + (nCol * 2);
|
||||
}
|
||||
|
||||
/* Open a cursor to the index to be analyzed. */
|
||||
Debug.Assert(iDb == sqlite3SchemaToIndex(db, pIdx.pSchema));
|
||||
sqlite3VdbeAddOp4(v, OP_OpenRead, iIdxCur, pIdx.tnum, iDb,
|
||||
pKey, P4_KEYINFO_HANDOFF);
|
||||
VdbeComment(v, "%s", pIdx.zName);
|
||||
|
||||
/* Populate the registers containing the index names. */
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, regIdxname, 0, pIdx.zName, 0);
|
||||
|
||||
#if SQLITE_ENABLE_STAT2
|
||||
|
||||
/* If this iteration of the loop is generating code to analyze the
|
||||
** first index in the pTab.pIndex list, then register regLast has
|
||||
** not been populated. In this case populate it now. */
|
||||
if ( pTab.pIndex == pIdx )
|
||||
{
|
||||
sqlite3VdbeAddOp2( v, OP_Integer, SQLITE_INDEX_SAMPLES, regSamplerecno );
|
||||
sqlite3VdbeAddOp2( v, OP_Integer, SQLITE_INDEX_SAMPLES * 2 - 1, regTemp );
|
||||
sqlite3VdbeAddOp2( v, OP_Integer, SQLITE_INDEX_SAMPLES * 2, regTemp2 );
|
||||
|
||||
sqlite3VdbeAddOp2( v, OP_Count, iIdxCur, regLast );
|
||||
sqlite3VdbeAddOp2( v, OP_Null, 0, regFirst );
|
||||
addr = sqlite3VdbeAddOp3( v, OP_Lt, regSamplerecno, 0, regLast );
|
||||
sqlite3VdbeAddOp3( v, OP_Divide, regTemp2, regLast, regFirst );
|
||||
sqlite3VdbeAddOp3( v, OP_Multiply, regLast, regTemp, regLast );
|
||||
sqlite3VdbeAddOp2( v, OP_AddImm, regLast, SQLITE_INDEX_SAMPLES * 2 - 2 );
|
||||
sqlite3VdbeAddOp3( v, OP_Divide, regTemp2, regLast, regLast );
|
||||
sqlite3VdbeJumpHere( v, addr );
|
||||
}
|
||||
|
||||
/* Zero the regSampleno and regRecno registers. */
|
||||
sqlite3VdbeAddOp2( v, OP_Integer, 0, regSampleno );
|
||||
sqlite3VdbeAddOp2( v, OP_Integer, 0, regRecno );
|
||||
sqlite3VdbeAddOp2( v, OP_Copy, regFirst, regSamplerecno );
|
||||
#endif
|
||||
|
||||
/* The block of memory cells initialized here is used as follows.
|
||||
**
|
||||
** iMem:
|
||||
** The total number of rows in the table.
|
||||
**
|
||||
** iMem+1 .. iMem+nCol:
|
||||
** Number of distinct entries in index considering the
|
||||
** left-most N columns only, where N is between 1 and nCol,
|
||||
** inclusive.
|
||||
**
|
||||
** iMem+nCol+1 .. Mem+2*nCol:
|
||||
** Previous value of indexed columns, from left to right.
|
||||
**
|
||||
** Cells iMem through iMem+nCol are initialized to 0. The others are
|
||||
** initialized to contain an SQL NULL.
|
||||
*/
|
||||
for (i = 0; i <= nCol; i++)
|
||||
{
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, iMem + i);
|
||||
}
|
||||
for (i = 0; i < nCol; i++)
|
||||
{
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, iMem + nCol + i + 1);
|
||||
}
|
||||
|
||||
/* Start the analysis loop. This loop runs through all the entries in
|
||||
** the index b-tree. */
|
||||
endOfLoop = sqlite3VdbeMakeLabel(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Rewind, iIdxCur, endOfLoop);
|
||||
topOfLoop = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, iMem, 1);
|
||||
|
||||
for (i = 0; i < nCol; i++)
|
||||
{
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regCol);
|
||||
CollSeq pColl;
|
||||
if (i == 0)
|
||||
{
|
||||
#if SQLITE_ENABLE_STAT2
|
||||
/* Check if the record that cursor iIdxCur points to contains a
|
||||
** value that should be stored in the sqlite_stat2 table. If so,
|
||||
** store it. */
|
||||
int ne = sqlite3VdbeAddOp3( v, OP_Ne, regRecno, 0, regSamplerecno );
|
||||
Debug.Assert( regTabname + 1 == regIdxname
|
||||
&& regTabname + 2 == regSampleno
|
||||
&& regTabname + 3 == regCol
|
||||
);
|
||||
sqlite3VdbeChangeP5( v, SQLITE_JUMPIFNULL );
|
||||
sqlite3VdbeAddOp4( v, OP_MakeRecord, regTabname, 4, regRec, "aaab", 0 );
|
||||
sqlite3VdbeAddOp2( v, OP_NewRowid, iStatCur + 1, regRowid );
|
||||
sqlite3VdbeAddOp3( v, OP_Insert, iStatCur + 1, regRec, regRowid );
|
||||
|
||||
/* Calculate new values for regSamplerecno and regSampleno.
|
||||
**
|
||||
** sampleno = sampleno + 1
|
||||
** samplerecno = samplerecno+(remaining records)/(remaining samples)
|
||||
*/
|
||||
sqlite3VdbeAddOp2( v, OP_AddImm, regSampleno, 1 );
|
||||
sqlite3VdbeAddOp3( v, OP_Subtract, regRecno, regLast, regTemp );
|
||||
sqlite3VdbeAddOp2( v, OP_AddImm, regTemp, -1 );
|
||||
sqlite3VdbeAddOp2( v, OP_Integer, SQLITE_INDEX_SAMPLES, regTemp2 );
|
||||
sqlite3VdbeAddOp3( v, OP_Subtract, regSampleno, regTemp2, regTemp2 );
|
||||
sqlite3VdbeAddOp3( v, OP_Divide, regTemp2, regTemp, regTemp );
|
||||
sqlite3VdbeAddOp3( v, OP_Add, regSamplerecno, regTemp, regSamplerecno );
|
||||
|
||||
sqlite3VdbeJumpHere( v, ne );
|
||||
sqlite3VdbeAddOp2( v, OP_AddImm, regRecno, 1 );
|
||||
#endif
|
||||
|
||||
/* Always record the very first row */
|
||||
sqlite3VdbeAddOp1(v, OP_IfNot, iMem + 1);
|
||||
}
|
||||
Debug.Assert(pIdx.azColl != null);
|
||||
Debug.Assert(pIdx.azColl[i] != null);
|
||||
pColl = sqlite3LocateCollSeq(pParse, pIdx.azColl[i]);
|
||||
sqlite3VdbeAddOp4(v, OP_Ne, regCol, 0, iMem + nCol + i + 1,
|
||||
pColl, P4_COLLSEQ);
|
||||
sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
|
||||
}
|
||||
//if( db.mallocFailed ){
|
||||
// /* If a malloc failure has occurred, then the result of the expression
|
||||
// ** passed as the second argument to the call to sqlite3VdbeJumpHere()
|
||||
// ** below may be negative. Which causes an Debug.Assert() to fail (or an
|
||||
// ** out-of-bounds write if SQLITE_DEBUG is not defined). */
|
||||
// return;
|
||||
//}
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, endOfLoop);
|
||||
for (i = 0; i < nCol; i++)
|
||||
{
|
||||
int addr2 = sqlite3VdbeCurrentAddr(v) - (nCol * 2);
|
||||
if (i == 0)
|
||||
{
|
||||
sqlite3VdbeJumpHere(v, addr2 - 1); /* Set jump dest for the OP_IfNot */
|
||||
}
|
||||
sqlite3VdbeJumpHere(v, addr2); /* Set jump dest for the OP_Ne */
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, iMem + i + 1, 1);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, iMem + nCol + i + 1);
|
||||
}
|
||||
|
||||
/* End of the analysis loop. */
|
||||
sqlite3VdbeResolveLabel(v, endOfLoop);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, topOfLoop);
|
||||
sqlite3VdbeAddOp1(v, OP_Close, iIdxCur);
|
||||
|
||||
/* Store the results in sqlite_stat1.
|
||||
**
|
||||
** The result is a single row of the sqlite_stat1 table. The first
|
||||
** two columns are the names of the table and index. The third column
|
||||
** is a string composed of a list of integer statistics about the
|
||||
** index. The first integer in the list is the total number of entries
|
||||
** in the index. There is one additional integer in the list for each
|
||||
** column of the table. This additional integer is a guess of how many
|
||||
** rows of the table the index will select. If D is the count of distinct
|
||||
** values and K is the total number of rows, then the integer is computed
|
||||
** as:
|
||||
**
|
||||
** I = (K+D-1)/D
|
||||
**
|
||||
** If K==0 then no entry is made into the sqlite_stat1 table.
|
||||
** If K>0 then it is always the case the D>0 so division by zero
|
||||
** is never possible.
|
||||
*/
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy, iMem, regSampleno);
|
||||
if (jZeroRows < 0)
|
||||
{
|
||||
jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, iMem);
|
||||
}
|
||||
for (i = 0; i < nCol; i++)
|
||||
{
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, regTemp, 0, " ", 0);
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regSampleno, regSampleno);
|
||||
sqlite3VdbeAddOp3(v, OP_Add, iMem, iMem + i + 1, regTemp);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, regTemp, -1);
|
||||
sqlite3VdbeAddOp3(v, OP_Divide, iMem + i + 1, regTemp, regTemp);
|
||||
sqlite3VdbeAddOp1(v, OP_ToInt, regTemp);
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regSampleno, regSampleno);
|
||||
}
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regRec, "aaa", 0);
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regRowid);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
|
||||
}
|
||||
|
||||
/* If the table has no indices, create a single sqlite_stat1 entry
|
||||
** containing NULL as the index name and the row count as the content.
|
||||
*/
|
||||
if (pTab.pIndex == null)
|
||||
{
|
||||
sqlite3VdbeAddOp3(v, OP_OpenRead, iIdxCur, pTab.tnum, iDb);
|
||||
VdbeComment(v, "%s", pTab.zName);
|
||||
sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regSampleno);
|
||||
sqlite3VdbeAddOp1(v, OP_Close, iIdxCur);
|
||||
jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, regSampleno);
|
||||
}
|
||||
else
|
||||
{
|
||||
sqlite3VdbeJumpHere(v, jZeroRows);
|
||||
jZeroRows = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regIdxname);
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regRec, "aaa", 0);
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regRowid);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
|
||||
if (pParse.nMem < regRec)
|
||||
pParse.nMem = regRec;
|
||||
sqlite3VdbeJumpHere(v, jZeroRows);
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code that will cause the most recent index analysis to
|
||||
** be loaded into internal hash tables where is can be used.
|
||||
*/
|
||||
|
||||
private static void loadAnalysis(Parse pParse, int iDb)
|
||||
{
|
||||
Vdbe v = sqlite3GetVdbe(pParse);
|
||||
if (v != null)
|
||||
{
|
||||
sqlite3VdbeAddOp1(v, OP_LoadAnalysis, iDb);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code that will do an analysis of an entire database
|
||||
*/
|
||||
|
||||
private static void analyzeDatabase(Parse pParse, int iDb)
|
||||
{
|
||||
sqlite3 db = pParse.db;
|
||||
Schema pSchema = db.aDb[iDb].pSchema; /* Schema of database iDb */
|
||||
HashElem k;
|
||||
int iStatCur;
|
||||
int iMem;
|
||||
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
iStatCur = pParse.nTab;
|
||||
pParse.nTab += 2;
|
||||
openStatTable(pParse, iDb, iStatCur, null, null);
|
||||
iMem = pParse.nMem + 1;
|
||||
Debug.Assert(sqlite3SchemaMutexHeld(db, iDb, null));
|
||||
//for(k=sqliteHashFirst(pSchema.tblHash); k; k=sqliteHashNext(k)){
|
||||
for (k = pSchema.tblHash.first; k != null; k = k.next)
|
||||
{
|
||||
Table pTab = (Table)k.data;// sqliteHashData( k );
|
||||
analyzeOneTable(pParse, pTab, null, iStatCur, iMem);
|
||||
}
|
||||
loadAnalysis(pParse, iDb);
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code that will do an analysis of a single table in
|
||||
** a database. If pOnlyIdx is not NULL then it is a single index
|
||||
** in pTab that should be analyzed.
|
||||
*/
|
||||
|
||||
private static void analyzeTable(Parse pParse, Table pTab, Index pOnlyIdx)
|
||||
{
|
||||
int iDb;
|
||||
int iStatCur;
|
||||
|
||||
Debug.Assert(pTab != null);
|
||||
Debug.Assert(sqlite3BtreeHoldsAllMutexes(pParse.db));
|
||||
iDb = sqlite3SchemaToIndex(pParse.db, pTab.pSchema);
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
iStatCur = pParse.nTab;
|
||||
pParse.nTab += 2;
|
||||
if (pOnlyIdx != null)
|
||||
{
|
||||
openStatTable(pParse, iDb, iStatCur, pOnlyIdx.zName, "idx");
|
||||
}
|
||||
else
|
||||
{
|
||||
openStatTable(pParse, iDb, iStatCur, pTab.zName, "tbl");
|
||||
}
|
||||
analyzeOneTable(pParse, pTab, pOnlyIdx, iStatCur, pParse.nMem + 1);
|
||||
loadAnalysis(pParse, iDb);
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code for the ANALYZE command. The parser calls this routine
|
||||
** when it recognizes an ANALYZE command.
|
||||
**
|
||||
** ANALYZE -- 1
|
||||
** ANALYZE <database> -- 2
|
||||
** ANALYZE ?<database>.?<tablename> -- 3
|
||||
**
|
||||
** Form 1 causes all indices in all attached databases to be analyzed.
|
||||
** Form 2 analyzes all indices the single database named.
|
||||
** Form 3 analyzes all indices associated with the named table.
|
||||
*/
|
||||
|
||||
// OVERLOADS, so I don't need to rewrite parse.c
|
||||
private static void sqlite3Analyze(Parse pParse, int null_2, int null_3)
|
||||
{
|
||||
sqlite3Analyze(pParse, null, null);
|
||||
}
|
||||
|
||||
private static void sqlite3Analyze(Parse pParse, Token pName1, Token pName2)
|
||||
{
|
||||
sqlite3 db = pParse.db;
|
||||
int iDb;
|
||||
int i;
|
||||
string z, zDb;
|
||||
Table pTab;
|
||||
Index pIdx;
|
||||
Token pTableName = null;
|
||||
|
||||
/* Read the database schema. If an error occurs, leave an error message
|
||||
** and code in pParse and return NULL. */
|
||||
Debug.Assert(sqlite3BtreeHoldsAllMutexes(pParse.db));
|
||||
if (SQLITE_OK != sqlite3ReadSchema(pParse))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Assert(pName2 != null || pName1 == null);
|
||||
if (pName1 == null)
|
||||
{
|
||||
/* Form 1: Analyze everything */
|
||||
for (i = 0; i < db.nDb; i++)
|
||||
{
|
||||
if (i == 1)
|
||||
continue; /* Do not analyze the TEMP database */
|
||||
analyzeDatabase(pParse, i);
|
||||
}
|
||||
}
|
||||
else if (pName2.n == 0)
|
||||
{
|
||||
/* Form 2: Analyze the database or table named */
|
||||
iDb = sqlite3FindDb(db, pName1);
|
||||
if (iDb >= 0)
|
||||
{
|
||||
analyzeDatabase(pParse, iDb);
|
||||
}
|
||||
else
|
||||
{
|
||||
z = sqlite3NameFromToken(db, pName1);
|
||||
if (z != null)
|
||||
{
|
||||
if ((pIdx = sqlite3FindIndex(db, z, null)) != null)
|
||||
{
|
||||
analyzeTable(pParse, pIdx.pTable, pIdx);
|
||||
}
|
||||
else if ((pTab = sqlite3LocateTable(pParse, 0, z, null)) != null)
|
||||
{
|
||||
analyzeTable(pParse, pTab, null);
|
||||
}
|
||||
z = null;//sqlite3DbFree( db, z );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Form 3: Analyze the fully qualified table name */
|
||||
iDb = sqlite3TwoPartName(pParse, pName1, pName2, ref pTableName);
|
||||
if (iDb >= 0)
|
||||
{
|
||||
zDb = db.aDb[iDb].zName;
|
||||
z = sqlite3NameFromToken(db, pTableName);
|
||||
if (z != null)
|
||||
{
|
||||
if ((pIdx = sqlite3FindIndex(db, z, zDb)) != null)
|
||||
{
|
||||
analyzeTable(pParse, pIdx.pTable, pIdx);
|
||||
}
|
||||
else if ((pTab = sqlite3LocateTable(pParse, 0, z, zDb)) != null)
|
||||
{
|
||||
analyzeTable(pParse, pTab, null);
|
||||
}
|
||||
z = null; //sqlite3DbFree( db, z );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Used to pass information from the analyzer reader through to the
|
||||
** callback routine.
|
||||
*/
|
||||
|
||||
//typedef struct analysisInfo analysisInfo;
|
||||
public struct analysisInfo
|
||||
{
|
||||
public sqlite3 db;
|
||||
public string zDatabase;
|
||||
};
|
||||
|
||||
/*
|
||||
** This callback is invoked once for each index when reading the
|
||||
** sqlite_stat1 table.
|
||||
**
|
||||
** argv[0] = name of the table
|
||||
** argv[1] = name of the index (might be NULL)
|
||||
** argv[2] = results of analysis - on integer for each column
|
||||
**
|
||||
** Entries for which argv[1]==NULL simply record the number of rows in
|
||||
** the table.
|
||||
*/
|
||||
|
||||
private static int analysisLoader(object pData, sqlite3_int64 argc, object Oargv, object NotUsed)
|
||||
{
|
||||
string[] argv = (string[])Oargv;
|
||||
analysisInfo pInfo = (analysisInfo)pData;
|
||||
Index pIndex;
|
||||
Table pTable;
|
||||
int i, c, n;
|
||||
int v;
|
||||
string z;
|
||||
|
||||
Debug.Assert(argc == 3);
|
||||
UNUSED_PARAMETER2(NotUsed, argc);
|
||||
if (argv == null || argv[0] == null || argv[2] == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
pTable = sqlite3FindTable(pInfo.db, argv[0], pInfo.zDatabase);
|
||||
if (pTable == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (!String.IsNullOrEmpty(argv[1]))
|
||||
{
|
||||
pIndex = sqlite3FindIndex(pInfo.db, argv[1], pInfo.zDatabase);
|
||||
}
|
||||
else
|
||||
{
|
||||
pIndex = null;
|
||||
}
|
||||
|
||||
n = pIndex != null ? pIndex.nColumn : 0;
|
||||
z = argv[2];
|
||||
int zIndex = 0;
|
||||
for (i = 0; z != null && i <= n; i++)
|
||||
{
|
||||
v = 0;
|
||||
while (zIndex < z.Length && (c = z[zIndex]) >= '0' && c <= '9')
|
||||
{
|
||||
v = v * 10 + c - '0';
|
||||
zIndex++;
|
||||
}
|
||||
if (i == 0)
|
||||
pTable.nRowEst = (uint)v;
|
||||
if (pIndex == null)
|
||||
break;
|
||||
pIndex.aiRowEst[i] = v;
|
||||
if (zIndex < z.Length && z[zIndex] == ' ')
|
||||
zIndex++;
|
||||
if (z.Substring(zIndex).CompareTo("unordered") == 0)//memcmp( z, "unordered", 10 ) == 0 )
|
||||
{
|
||||
pIndex.bUnordered = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** If the Index.aSample variable is not NULL, delete the aSample[] array
|
||||
** and its contents.
|
||||
*/
|
||||
|
||||
private static void sqlite3DeleteIndexSamples(sqlite3 db, Index pIdx)
|
||||
{
|
||||
#if SQLITE_ENABLE_STAT2
|
||||
if ( pIdx.aSample != null )
|
||||
{
|
||||
int j;
|
||||
for ( j = 0; j < SQLITE_INDEX_SAMPLES; j++ )
|
||||
{
|
||||
IndexSample p = pIdx.aSample[j];
|
||||
if ( p.eType == SQLITE_TEXT || p.eType == SQLITE_BLOB )
|
||||
{
|
||||
p.u.z = null;//sqlite3DbFree(db, p.u.z);
|
||||
p.u.zBLOB = null;
|
||||
}
|
||||
}
|
||||
sqlite3DbFree( db, ref pIdx.aSample );
|
||||
}
|
||||
#else
|
||||
UNUSED_PARAMETER(db);
|
||||
UNUSED_PARAMETER(pIdx);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Load the content of the sqlite_stat1 and sqlite_stat2 tables. The
|
||||
** contents of sqlite_stat1 are used to populate the Index.aiRowEst[]
|
||||
** arrays. The contents of sqlite_stat2 are used to populate the
|
||||
** Index.aSample[] arrays.
|
||||
**
|
||||
** If the sqlite_stat1 table is not present in the database, SQLITE_ERROR
|
||||
** is returned. In this case, even if SQLITE_ENABLE_STAT2 was defined
|
||||
** during compilation and the sqlite_stat2 table is present, no data is
|
||||
** read from it.
|
||||
**
|
||||
** If SQLITE_ENABLE_STAT2 was defined during compilation and the
|
||||
** sqlite_stat2 table is not present in the database, SQLITE_ERROR is
|
||||
** returned. However, in this case, data is read from the sqlite_stat1
|
||||
** table (if it is present) before returning.
|
||||
**
|
||||
** If an OOM error occurs, this function always sets db.mallocFailed.
|
||||
** This means if the caller does not care about other errors, the return
|
||||
** code may be ignored.
|
||||
*/
|
||||
|
||||
private static int sqlite3AnalysisLoad(sqlite3 db, int iDb)
|
||||
{
|
||||
analysisInfo sInfo;
|
||||
HashElem i;
|
||||
string zSql;
|
||||
int rc;
|
||||
|
||||
Debug.Assert(iDb >= 0 && iDb < db.nDb);
|
||||
Debug.Assert(db.aDb[iDb].pBt != null);
|
||||
/* Clear any prior statistics */
|
||||
Debug.Assert(sqlite3SchemaMutexHeld(db, iDb, null));
|
||||
//for(i=sqliteHashFirst(&db.aDb[iDb].pSchema.idxHash);i;i=sqliteHashNext(i)){
|
||||
for (i = db.aDb[iDb].pSchema.idxHash.first; i != null; i = i.next)
|
||||
{
|
||||
Index pIdx = (Index)i.data;// sqliteHashData( i );
|
||||
sqlite3DefaultRowEst(pIdx);
|
||||
sqlite3DeleteIndexSamples(db, pIdx);
|
||||
pIdx.aSample = null;
|
||||
}
|
||||
|
||||
/* Check to make sure the sqlite_stat1 table exists */
|
||||
sInfo.db = db;
|
||||
sInfo.zDatabase = db.aDb[iDb].zName;
|
||||
if (sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase) == null)
|
||||
{
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
/* Load new statistics out of the sqlite_stat1 table */
|
||||
zSql = sqlite3MPrintf(db,
|
||||
"SELECT tbl, idx, stat FROM %Q.sqlite_stat1", sInfo.zDatabase);
|
||||
//if ( zSql == null )
|
||||
//{
|
||||
// rc = SQLITE_NOMEM;
|
||||
//}
|
||||
//else
|
||||
{
|
||||
rc = sqlite3_exec(db, zSql, (dxCallback)analysisLoader, sInfo, 0);
|
||||
sqlite3DbFree(db, ref zSql);
|
||||
}
|
||||
|
||||
/* Load the statistics from the sqlite_stat2 table. */
|
||||
#if SQLITE_ENABLE_STAT2
|
||||
if ( rc == SQLITE_OK && null == sqlite3FindTable( db, "sqlite_stat2", sInfo.zDatabase ) )
|
||||
{
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
if ( rc == SQLITE_OK )
|
||||
{
|
||||
sqlite3_stmt pStmt = null;
|
||||
|
||||
zSql = sqlite3MPrintf( db,
|
||||
"SELECT idx,sampleno,sample FROM %Q.sqlite_stat2", sInfo.zDatabase );
|
||||
//if( null==zSql ){
|
||||
//rc = SQLITE_NOMEM;
|
||||
//}else{
|
||||
rc = sqlite3_prepare( db, zSql, -1, ref pStmt, 0 );
|
||||
sqlite3DbFree( db, ref zSql );
|
||||
//}
|
||||
|
||||
if ( rc == SQLITE_OK )
|
||||
{
|
||||
while ( sqlite3_step( pStmt ) == SQLITE_ROW )
|
||||
{
|
||||
string zIndex; /* Index name */
|
||||
Index pIdx; /* Pointer to the index object */
|
||||
zIndex = sqlite3_column_text( pStmt, 0 );
|
||||
pIdx = !String.IsNullOrEmpty( zIndex ) ? sqlite3FindIndex( db, zIndex, sInfo.zDatabase ) : null;
|
||||
if ( pIdx != null )
|
||||
{
|
||||
int iSample = sqlite3_column_int( pStmt, 1 );
|
||||
if ( iSample < SQLITE_INDEX_SAMPLES && iSample >= 0 )
|
||||
{
|
||||
int eType = sqlite3_column_type( pStmt, 2 );
|
||||
|
||||
if ( pIdx.aSample == null )
|
||||
{
|
||||
//static const int sz = sizeof(IndexSample)*SQLITE_INDEX_SAMPLES;
|
||||
//pIdx->aSample = (IndexSample )sqlite3DbMallocRaw(0, sz);
|
||||
//if( pIdx.aSample==0 ){
|
||||
//db.mallocFailed = 1;
|
||||
//break;
|
||||
//}
|
||||
pIdx.aSample = new IndexSample[SQLITE_INDEX_SAMPLES];//memset(pIdx->aSample, 0, sz);
|
||||
}
|
||||
|
||||
//Debug.Assert( pIdx.aSample != null );
|
||||
if ( pIdx.aSample[iSample] == null )
|
||||
pIdx.aSample[iSample] = new IndexSample();
|
||||
IndexSample pSample = pIdx.aSample[iSample];
|
||||
{
|
||||
pSample.eType = (u8)eType;
|
||||
if ( eType == SQLITE_INTEGER || eType == SQLITE_FLOAT )
|
||||
{
|
||||
pSample.u.r = sqlite3_column_double( pStmt, 2 );
|
||||
}
|
||||
else if ( eType == SQLITE_TEXT || eType == SQLITE_BLOB )
|
||||
{
|
||||
string z = null;
|
||||
byte[] zBLOB = null;
|
||||
//string z = (string )(
|
||||
//(eType==SQLITE_BLOB) ?
|
||||
//sqlite3_column_blob(pStmt, 2):
|
||||
//sqlite3_column_text(pStmt, 2)
|
||||
//);
|
||||
if ( eType == SQLITE_BLOB )
|
||||
zBLOB = sqlite3_column_blob( pStmt, 2 );
|
||||
else
|
||||
z = sqlite3_column_text( pStmt, 2 );
|
||||
int n = sqlite3_column_bytes( pStmt, 2 );
|
||||
if ( n > 24 )
|
||||
{
|
||||
n = 24;
|
||||
}
|
||||
pSample.nByte = (u8)n;
|
||||
if ( n < 1 )
|
||||
{
|
||||
pSample.u.z = null;
|
||||
pSample.u.zBLOB = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
pSample.u.z = z;
|
||||
pSample.u.zBLOB = zBLOB;
|
||||
//pSample->u.z = sqlite3DbMallocRaw(dbMem, n);
|
||||
//if( pSample->u.z ){
|
||||
// memcpy(pSample->u.z, z, n);
|
||||
//}else{
|
||||
// db->mallocFailed = 1;
|
||||
// break;
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
rc = sqlite3_finalize( pStmt );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//if( rc==SQLITE_NOMEM ){
|
||||
// db.mallocFailed = 1;
|
||||
//}
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif // * SQLITE_OMIT_ANALYZE */
|
||||
}
|
||||
}
|
||||
680
original/Community.CsharpSqlite/src/attach_c.cs
Normal file
680
original/Community.CsharpSqlite/src/attach_c.cs
Normal file
|
|
@ -0,0 +1,680 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
|
||||
using u8 = System.Byte;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
using sqlite3_value = Sqlite3.Mem;
|
||||
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2003 April 6
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains code used to implement the ATTACH and DETACH commands.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#include "sqliteInt.h"
|
||||
|
||||
#if !SQLITE_OMIT_ATTACH
|
||||
/*
|
||||
** Resolve an expression that was part of an ATTACH or DETACH statement. This
|
||||
** is slightly different from resolving a normal SQL expression, because simple
|
||||
** identifiers are treated as strings, not possible column names or aliases.
|
||||
**
|
||||
** i.e. if the parser sees:
|
||||
**
|
||||
** ATTACH DATABASE abc AS def
|
||||
**
|
||||
** it treats the two expressions as literal strings 'abc' and 'def' instead of
|
||||
** looking for columns of the same name.
|
||||
**
|
||||
** This only applies to the root node of pExpr, so the statement:
|
||||
**
|
||||
** ATTACH DATABASE abc||def AS 'db2'
|
||||
**
|
||||
** will fail because neither abc or def can be resolved.
|
||||
*/
|
||||
|
||||
private static int resolveAttachExpr(NameContext pName, Expr pExpr)
|
||||
{
|
||||
int rc = SQLITE_OK;
|
||||
if (pExpr != null)
|
||||
{
|
||||
if (pExpr.op != TK_ID)
|
||||
{
|
||||
rc = sqlite3ResolveExprNames(pName, ref pExpr);
|
||||
if (rc == SQLITE_OK && sqlite3ExprIsConstant(pExpr) == 0)
|
||||
{
|
||||
sqlite3ErrorMsg(pName.pParse, "invalid name: \"%s\"", pExpr.u.zToken);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pExpr.op = TK_STRING;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** An SQL user-function registered to do the work of an ATTACH statement. The
|
||||
** three arguments to the function come directly from an attach statement:
|
||||
**
|
||||
** ATTACH DATABASE x AS y KEY z
|
||||
**
|
||||
** SELECT sqlite_attach(x, y, z)
|
||||
**
|
||||
** If the optional "KEY z" syntax is omitted, an SQL NULL is passed as the
|
||||
** third argument.
|
||||
*/
|
||||
|
||||
private static void attachFunc(
|
||||
sqlite3_context context,
|
||||
int NotUsed,
|
||||
sqlite3_value[] argv
|
||||
)
|
||||
{
|
||||
int i;
|
||||
int rc = 0;
|
||||
sqlite3 db = sqlite3_context_db_handle(context);
|
||||
string zName;
|
||||
string zFile;
|
||||
string zPath = "";
|
||||
string zErr = "";
|
||||
int flags;
|
||||
|
||||
Db aNew = null;
|
||||
string zErrDyn = "";
|
||||
sqlite3_vfs pVfs = null;
|
||||
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
|
||||
zFile = argv[0].z != null && (argv[0].z.Length > 0) && argv[0].flags != MEM_Null ? sqlite3_value_text(argv[0]) : "";
|
||||
zName = argv[1].z != null && (argv[1].z.Length > 0) && argv[1].flags != MEM_Null ? sqlite3_value_text(argv[1]) : "";
|
||||
//if( zFile==null ) zFile = "";
|
||||
//if ( zName == null ) zName = "";
|
||||
|
||||
/* Check for the following errors:
|
||||
**
|
||||
** * Too many attached databases,
|
||||
** * Transaction currently open
|
||||
** * Specified database name already being used.
|
||||
*/
|
||||
if (db.nDb >= db.aLimit[SQLITE_LIMIT_ATTACHED] + 2)
|
||||
{
|
||||
zErrDyn = sqlite3MPrintf(db, "too many attached databases - max %d",
|
||||
db.aLimit[SQLITE_LIMIT_ATTACHED]
|
||||
);
|
||||
goto attach_error;
|
||||
}
|
||||
if (0 == db.autoCommit)
|
||||
{
|
||||
zErrDyn = sqlite3MPrintf(db, "cannot ATTACH database within transaction");
|
||||
goto attach_error;
|
||||
}
|
||||
for (i = 0; i < db.nDb; i++)
|
||||
{
|
||||
string z = db.aDb[i].zName;
|
||||
Debug.Assert(z != null && zName != null);
|
||||
if (z.Equals(zName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName);
|
||||
goto attach_error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate the new entry in the db.aDb[] array and initialise the schema
|
||||
** hash tables.
|
||||
*/
|
||||
/* Allocate the new entry in the db.aDb[] array and initialise the schema
|
||||
** hash tables.
|
||||
*/
|
||||
//if( db.aDb==db.aDbStatic ){
|
||||
// aNew = sqlite3DbMallocRaw(db, sizeof(db.aDb[0])*3 );
|
||||
// if( aNew==0 ) return;
|
||||
// memcpy(aNew, db.aDb, sizeof(db.aDb[0])*2);
|
||||
//}else {
|
||||
if (db.aDb.Length <= db.nDb)
|
||||
Array.Resize(ref db.aDb, db.nDb + 1);//aNew = sqlite3DbRealloc(db, db.aDb, sizeof(db.aDb[0])*(db.nDb+1) );
|
||||
if (db.aDb == null)
|
||||
return; // if( aNew==0 ) return;
|
||||
//}
|
||||
db.aDb[db.nDb] = new Db();//db.aDb = aNew;
|
||||
aNew = db.aDb[db.nDb];//memset(aNew, 0, sizeof(*aNew));
|
||||
// memset(aNew, 0, sizeof(*aNew));
|
||||
|
||||
/* Open the database file. If the btree is successfully opened, use
|
||||
** it to obtain the database schema. At this point the schema may
|
||||
** or may not be initialised.
|
||||
*/
|
||||
flags = (int)db.openFlags;
|
||||
rc = sqlite3ParseUri(vfsList.zName, zFile, ref flags, ref pVfs, ref zPath, ref zErr);
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
//if ( rc == SQLITE_NOMEM )
|
||||
//db.mallocFailed = 1;
|
||||
sqlite3_result_error(context, zErr, -1);
|
||||
//sqlite3_free( zErr );
|
||||
return;
|
||||
}
|
||||
Debug.Assert(pVfs != null);
|
||||
flags |= SQLITE_OPEN_MAIN_DB;
|
||||
rc = sqlite3BtreeOpen(pVfs, zPath, db, ref aNew.pBt, 0, (int)flags);
|
||||
//sqlite3_free( zPath );
|
||||
|
||||
db.nDb++;
|
||||
if (rc == SQLITE_CONSTRAINT)
|
||||
{
|
||||
rc = SQLITE_ERROR;
|
||||
zErrDyn = sqlite3MPrintf(db, "database is already attached");
|
||||
}
|
||||
else if (rc == SQLITE_OK)
|
||||
{
|
||||
Pager pPager;
|
||||
aNew.pSchema = sqlite3SchemaGet(db, aNew.pBt);
|
||||
//if ( aNew.pSchema == null )
|
||||
//{
|
||||
// rc = SQLITE_NOMEM;
|
||||
//}
|
||||
//else
|
||||
if (aNew.pSchema.file_format != 0 && aNew.pSchema.enc != ENC(db))
|
||||
{
|
||||
zErrDyn = sqlite3MPrintf(db,
|
||||
"attached databases must use the same text encoding as main database");
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
pPager = sqlite3BtreePager(aNew.pBt);
|
||||
sqlite3PagerLockingMode(pPager, db.dfltLockMode);
|
||||
sqlite3BtreeSecureDelete(aNew.pBt,
|
||||
sqlite3BtreeSecureDelete(db.aDb[0].pBt, -1));
|
||||
}
|
||||
aNew.safety_level = 3;
|
||||
aNew.zName = zName;//sqlite3DbStrDup(db, zName);
|
||||
//if( rc==SQLITE_OK && aNew.zName==0 ){
|
||||
// rc = SQLITE_NOMEM;
|
||||
//}
|
||||
|
||||
#if SQLITE_HAS_CODEC
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
//extern int sqlite3CodecAttach(sqlite3*, int, const void*, int);
|
||||
//extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
|
||||
int nKey;
|
||||
string zKey;
|
||||
int t = sqlite3_value_type(argv[2]);
|
||||
switch (t)
|
||||
{
|
||||
case SQLITE_INTEGER:
|
||||
case SQLITE_FLOAT:
|
||||
zErrDyn = "Invalid key value"; //sqlite3DbStrDup( db, "Invalid key value" );
|
||||
rc = SQLITE_ERROR;
|
||||
break;
|
||||
|
||||
case SQLITE_TEXT:
|
||||
case SQLITE_BLOB:
|
||||
nKey = sqlite3_value_bytes(argv[2]);
|
||||
zKey = sqlite3_value_blob(argv[2]).ToString(); // (char *)sqlite3_value_blob(argv[2]);
|
||||
rc = sqlite3CodecAttach(db, db.nDb - 1, zKey, nKey);
|
||||
break;
|
||||
|
||||
case SQLITE_NULL:
|
||||
/* No key specified. Use the key from the main database */
|
||||
sqlite3CodecGetKey(db, 0, out zKey, out nKey); //sqlite3CodecGetKey(db, 0, (void**)&zKey, nKey);
|
||||
if (nKey > 0 || sqlite3BtreeGetReserve(db.aDb[0].pBt) > 0)
|
||||
{
|
||||
rc = sqlite3CodecAttach(db, db.nDb - 1, zKey, nKey);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If the file was opened successfully, read the schema for the new database.
|
||||
** If this fails, or if opening the file failed, then close the file and
|
||||
** remove the entry from the db.aDb[] array. i.e. put everything back the way
|
||||
** we found it.
|
||||
*/
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
sqlite3BtreeEnterAll(db);
|
||||
rc = sqlite3Init(db, ref zErrDyn);
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
}
|
||||
if (rc != 0)
|
||||
{
|
||||
int iDb = db.nDb - 1;
|
||||
Debug.Assert(iDb >= 2);
|
||||
if (db.aDb[iDb].pBt != null)
|
||||
{
|
||||
sqlite3BtreeClose(ref db.aDb[iDb].pBt);
|
||||
db.aDb[iDb].pBt = null;
|
||||
db.aDb[iDb].pSchema = null;
|
||||
}
|
||||
sqlite3ResetInternalSchema(db, -1);
|
||||
db.nDb = iDb;
|
||||
if (rc == SQLITE_NOMEM || rc == SQLITE_IOERR_NOMEM)
|
||||
{
|
||||
//// db.mallocFailed = 1;
|
||||
sqlite3DbFree(db, ref zErrDyn);
|
||||
zErrDyn = sqlite3MPrintf(db, "out of memory");
|
||||
}
|
||||
else if (zErrDyn == "")
|
||||
{
|
||||
zErrDyn = sqlite3MPrintf(db, "unable to open database: %s", zFile);
|
||||
}
|
||||
goto attach_error;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
attach_error:
|
||||
/* Return an error if we get here */
|
||||
if (zErrDyn != "")
|
||||
{
|
||||
sqlite3_result_error(context, zErrDyn, -1);
|
||||
sqlite3DbFree(db, ref zErrDyn);
|
||||
}
|
||||
if (rc != 0)
|
||||
sqlite3_result_error_code(context, rc);
|
||||
}
|
||||
|
||||
/*
|
||||
** An SQL user-function registered to do the work of an DETACH statement. The
|
||||
** three arguments to the function come directly from a detach statement:
|
||||
**
|
||||
** DETACH DATABASE x
|
||||
**
|
||||
** SELECT sqlite_detach(x)
|
||||
*/
|
||||
|
||||
private static void detachFunc(
|
||||
sqlite3_context context,
|
||||
int NotUsed,
|
||||
sqlite3_value[] argv
|
||||
)
|
||||
{
|
||||
string zName = zName = argv[0].z != null && (argv[0].z.Length > 0) ? sqlite3_value_text(argv[0]) : "";//(sqlite3_value_text(argv[0]);
|
||||
sqlite3 db = sqlite3_context_db_handle(context);
|
||||
int i;
|
||||
Db pDb = null;
|
||||
StringBuilder zErr = new StringBuilder(200);
|
||||
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
|
||||
if (zName == null)
|
||||
zName = "";
|
||||
for (i = 0; i < db.nDb; i++)
|
||||
{
|
||||
pDb = db.aDb[i];
|
||||
if (pDb.pBt == null)
|
||||
continue;
|
||||
if (pDb.zName.Equals(zName, StringComparison.OrdinalIgnoreCase))
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= db.nDb)
|
||||
{
|
||||
sqlite3_snprintf(200, zErr, "no such database: %s", zName);
|
||||
goto detach_error;
|
||||
}
|
||||
if (i < 2)
|
||||
{
|
||||
sqlite3_snprintf(200, zErr, "cannot detach database %s", zName);
|
||||
goto detach_error;
|
||||
}
|
||||
if (0 == db.autoCommit)
|
||||
{
|
||||
sqlite3_snprintf(200, zErr,
|
||||
"cannot DETACH database within transaction");
|
||||
goto detach_error;
|
||||
}
|
||||
if (sqlite3BtreeIsInReadTrans(pDb.pBt) || sqlite3BtreeIsInBackup(pDb.pBt))
|
||||
{
|
||||
sqlite3_snprintf(200, zErr, "database %s is locked", zName);
|
||||
goto detach_error;
|
||||
}
|
||||
|
||||
sqlite3BtreeClose(ref pDb.pBt);
|
||||
pDb.pBt = null;
|
||||
pDb.pSchema = null;
|
||||
sqlite3ResetInternalSchema(db, -1);
|
||||
return;
|
||||
|
||||
detach_error:
|
||||
sqlite3_result_error(context, zErr.ToString(), -1);
|
||||
}
|
||||
|
||||
/*
|
||||
** This procedure generates VDBE code for a single invocation of either the
|
||||
** sqlite_detach() or sqlite_attach() SQL user functions.
|
||||
*/
|
||||
|
||||
private static void codeAttach(
|
||||
Parse pParse, /* The parser context */
|
||||
int type, /* Either SQLITE_ATTACH or SQLITE_DETACH */
|
||||
FuncDef pFunc, /* FuncDef wrapper for detachFunc() or attachFunc() */
|
||||
Expr pAuthArg, /* Expression to pass to authorization callback */
|
||||
Expr pFilename, /* Name of database file */
|
||||
Expr pDbname, /* Name of the database to use internally */
|
||||
Expr pKey /* Database key for encryption extension */
|
||||
)
|
||||
{
|
||||
NameContext sName;
|
||||
Vdbe v;
|
||||
sqlite3 db = pParse.db;
|
||||
int regArgs;
|
||||
|
||||
sName = new NameContext();// memset( &sName, 0, sizeof(NameContext));
|
||||
sName.pParse = pParse;
|
||||
|
||||
if (
|
||||
SQLITE_OK != resolveAttachExpr(sName, pFilename) ||
|
||||
SQLITE_OK != resolveAttachExpr(sName, pDbname) ||
|
||||
SQLITE_OK != resolveAttachExpr(sName, pKey)
|
||||
)
|
||||
{
|
||||
pParse.nErr++;
|
||||
goto attach_end;
|
||||
}
|
||||
|
||||
#if !SQLITE_OMIT_AUTHORIZATION
|
||||
if( pAuthArg ){
|
||||
char *zAuthArg;
|
||||
if( pAuthArg->op==TK_STRING ){
|
||||
zAuthArg = pAuthArg->u.zToken;
|
||||
}else{
|
||||
zAuthArg = 0;
|
||||
}
|
||||
int rc = sqlite3AuthCheck(pParse, type, zAuthArg, 0, 0);
|
||||
if(rc!=SQLITE_OK ){
|
||||
goto attach_end;
|
||||
}
|
||||
}
|
||||
#endif //* SQLITE_OMIT_AUTHORIZATION */
|
||||
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
regArgs = sqlite3GetTempRange(pParse, 4);
|
||||
sqlite3ExprCode(pParse, pFilename, regArgs);
|
||||
sqlite3ExprCode(pParse, pDbname, regArgs + 1);
|
||||
sqlite3ExprCode(pParse, pKey, regArgs + 2);
|
||||
|
||||
Debug.Assert(v != null /*|| db.mallocFailed != 0 */ );
|
||||
if (v != null)
|
||||
{
|
||||
sqlite3VdbeAddOp3(v, OP_Function, 0, regArgs + 3 - pFunc.nArg, regArgs + 3);
|
||||
Debug.Assert(pFunc.nArg == -1 || (pFunc.nArg & 0xff) == pFunc.nArg);
|
||||
sqlite3VdbeChangeP5(v, (u8)(pFunc.nArg));
|
||||
sqlite3VdbeChangeP4(v, -1, pFunc, P4_FUNCDEF);
|
||||
|
||||
/* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this
|
||||
** statement only). For DETACH, set it to false (expire all existing
|
||||
** statements).
|
||||
*/
|
||||
sqlite3VdbeAddOp1(v, OP_Expire, (type == SQLITE_ATTACH) ? 1 : 0);
|
||||
}
|
||||
|
||||
attach_end:
|
||||
sqlite3ExprDelete(db, ref pFilename);
|
||||
sqlite3ExprDelete(db, ref pDbname);
|
||||
sqlite3ExprDelete(db, ref pKey);
|
||||
}
|
||||
|
||||
/*
|
||||
** Called by the parser to compile a DETACH statement.
|
||||
**
|
||||
** DETACH pDbname
|
||||
*/
|
||||
|
||||
private static FuncDef detach_func = new FuncDef(
|
||||
1, /* nArg */
|
||||
SQLITE_UTF8, /* iPrefEnc */
|
||||
0, /* flags */
|
||||
null, /* pUserData */
|
||||
null, /* pNext */
|
||||
detachFunc, /* xFunc */
|
||||
null, /* xStep */
|
||||
null, /* xFinalize */
|
||||
"sqlite_detach", /* zName */
|
||||
null, /* pHash */
|
||||
null /* pDestructor */
|
||||
);
|
||||
|
||||
private static void sqlite3Detach(Parse pParse, Expr pDbname)
|
||||
{
|
||||
codeAttach(pParse, SQLITE_DETACH, detach_func, pDbname, null, null, pDbname);
|
||||
}
|
||||
|
||||
/*
|
||||
** Called by the parser to compile an ATTACH statement.
|
||||
**
|
||||
** ATTACH p AS pDbname KEY pKey
|
||||
*/
|
||||
|
||||
private static FuncDef attach_func = new FuncDef(
|
||||
3, /* nArg */
|
||||
SQLITE_UTF8, /* iPrefEnc */
|
||||
0, /* flags */
|
||||
null, /* pUserData */
|
||||
null, /* pNext */
|
||||
attachFunc, /* xFunc */
|
||||
null, /* xStep */
|
||||
null, /* xFinalize */
|
||||
"sqlite_attach", /* zName */
|
||||
null, /* pHash */
|
||||
null /* pDestructor */
|
||||
);
|
||||
|
||||
private static void sqlite3Attach(Parse pParse, Expr p, Expr pDbname, Expr pKey)
|
||||
{
|
||||
codeAttach(pParse, SQLITE_ATTACH, attach_func, p, p, pDbname, pKey);
|
||||
}
|
||||
|
||||
#endif // * SQLITE_OMIT_ATTACH */
|
||||
|
||||
/*
|
||||
** Initialize a DbFixer structure. This routine must be called prior
|
||||
** to passing the structure to one of the sqliteFixAAAA() routines below.
|
||||
**
|
||||
** The return value indicates whether or not fixation is required. TRUE
|
||||
** means we do need to fix the database references, FALSE means we do not.
|
||||
*/
|
||||
|
||||
private static int sqlite3FixInit(
|
||||
DbFixer pFix, /* The fixer to be initialized */
|
||||
Parse pParse, /* Error messages will be written here */
|
||||
int iDb, /* This is the database that must be used */
|
||||
string zType, /* "view", "trigger", or "index" */
|
||||
Token pName /* Name of the view, trigger, or index */
|
||||
)
|
||||
{
|
||||
sqlite3 db;
|
||||
|
||||
if (NEVER(iDb < 0) || iDb == 1)
|
||||
return 0;
|
||||
db = pParse.db;
|
||||
Debug.Assert(db.nDb > iDb);
|
||||
pFix.pParse = pParse;
|
||||
pFix.zDb = db.aDb[iDb].zName;
|
||||
pFix.zType = zType;
|
||||
pFix.pName = pName;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** The following set of routines walk through the parse tree and assign
|
||||
** a specific database to all table references where the database name
|
||||
** was left unspecified in the original SQL statement. The pFix structure
|
||||
** must have been initialized by a prior call to sqlite3FixInit().
|
||||
**
|
||||
** These routines are used to make sure that an index, trigger, or
|
||||
** view in one database does not refer to objects in a different database.
|
||||
** (Exception: indices, triggers, and views in the TEMP database are
|
||||
** allowed to refer to anything.) If a reference is explicitly made
|
||||
** to an object in a different database, an error message is added to
|
||||
** pParse.zErrMsg and these routines return non-zero. If everything
|
||||
** checks out, these routines return 0.
|
||||
*/
|
||||
|
||||
private static int sqlite3FixSrcList(
|
||||
DbFixer pFix, /* Context of the fixation */
|
||||
SrcList pList /* The Source list to check and modify */
|
||||
)
|
||||
{
|
||||
int i;
|
||||
string zDb;
|
||||
SrcList_item pItem;
|
||||
|
||||
if (NEVER(pList == null))
|
||||
return 0;
|
||||
zDb = pFix.zDb;
|
||||
for (i = 0; i < pList.nSrc; i++)
|
||||
{//, pItem++){
|
||||
pItem = pList.a[i];
|
||||
if (pItem.zDatabase == null)
|
||||
{
|
||||
pItem.zDatabase = zDb;// sqlite3DbStrDup( pFix.pParse.db, zDb );
|
||||
}
|
||||
else if (!pItem.zDatabase.Equals(zDb, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
sqlite3ErrorMsg(pFix.pParse,
|
||||
"%s %T cannot reference objects in database %s",
|
||||
pFix.zType, pFix.pName, pItem.zDatabase);
|
||||
return 1;
|
||||
}
|
||||
#if !SQLITE_OMIT_VIEW || !SQLITE_OMIT_TRIGGER
|
||||
if (sqlite3FixSelect(pFix, pItem.pSelect) != 0)
|
||||
return 1;
|
||||
if (sqlite3FixExpr(pFix, pItem.pOn) != 0)
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if !SQLITE_OMIT_VIEW || !SQLITE_OMIT_TRIGGER
|
||||
|
||||
private static int sqlite3FixSelect(
|
||||
DbFixer pFix, /* Context of the fixation */
|
||||
Select pSelect /* The SELECT statement to be fixed to one database */
|
||||
)
|
||||
{
|
||||
while (pSelect != null)
|
||||
{
|
||||
if (sqlite3FixExprList(pFix, pSelect.pEList) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (sqlite3FixSrcList(pFix, pSelect.pSrc) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (sqlite3FixExpr(pFix, pSelect.pWhere) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (sqlite3FixExpr(pFix, pSelect.pHaving) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
pSelect = pSelect.pPrior;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int sqlite3FixExpr(
|
||||
DbFixer pFix, /* Context of the fixation */
|
||||
Expr pExpr /* The expression to be fixed to one database */
|
||||
)
|
||||
{
|
||||
while (pExpr != null)
|
||||
{
|
||||
if (ExprHasAnyProperty(pExpr, EP_TokenOnly))
|
||||
break;
|
||||
if (ExprHasProperty(pExpr, EP_xIsSelect))
|
||||
{
|
||||
if (sqlite3FixSelect(pFix, pExpr.x.pSelect) != 0)
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sqlite3FixExprList(pFix, pExpr.x.pList) != 0)
|
||||
return 1;
|
||||
}
|
||||
if (sqlite3FixExpr(pFix, pExpr.pRight) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
pExpr = pExpr.pLeft;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int sqlite3FixExprList(
|
||||
DbFixer pFix, /* Context of the fixation */
|
||||
ExprList pList /* The expression to be fixed to one database */
|
||||
)
|
||||
{
|
||||
int i;
|
||||
ExprList_item pItem;
|
||||
if (pList == null)
|
||||
return 0;
|
||||
for (i = 0; i < pList.nExpr; i++)//, pItem++ )
|
||||
{
|
||||
pItem = pList.a[i];
|
||||
if (sqlite3FixExpr(pFix, pItem.pExpr) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !SQLITE_OMIT_TRIGGER
|
||||
|
||||
private static int sqlite3FixTriggerStep(
|
||||
DbFixer pFix, /* Context of the fixation */
|
||||
TriggerStep pStep /* The trigger step be fixed to one database */
|
||||
)
|
||||
{
|
||||
while (pStep != null)
|
||||
{
|
||||
if (sqlite3FixSelect(pFix, pStep.pSelect) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (sqlite3FixExpr(pFix, pStep.pWhere) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (sqlite3FixExprList(pFix, pStep.pExprList) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
pStep = pStep.pNext;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
261
original/Community.CsharpSqlite/src/auth_c.cs
Normal file
261
original/Community.CsharpSqlite/src/auth_c.cs
Normal file
|
|
@ -0,0 +1,261 @@
|
|||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2003 January 11
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains code used to implement the sqlite3_set_authorizer()
|
||||
** API. This facility is an optional feature of the library. Embedded
|
||||
** systems that do not need this facility may omit it by recompiling
|
||||
** the library with -DSQLITE_OMIT_AUTHORIZATION=1
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2010-08-23 18:52:01 42537b60566f288167f1b5864a5435986838e3a3
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** All of the code in this file may be omitted by defining a single
|
||||
** macro.
|
||||
*/
|
||||
#if !SQLITE_OMIT_AUTHORIZATION
|
||||
|
||||
/*
|
||||
** Set or clear the access authorization function.
|
||||
**
|
||||
** The access authorization function is be called during the compilation
|
||||
** phase to verify that the user has read and/or write access permission on
|
||||
** various fields of the database. The first argument to the auth function
|
||||
** is a copy of the 3rd argument to this routine. The second argument
|
||||
** to the auth function is one of these constants:
|
||||
**
|
||||
** SQLITE_CREATE_INDEX
|
||||
** SQLITE_CREATE_TABLE
|
||||
** SQLITE_CREATE_TEMP_INDEX
|
||||
** SQLITE_CREATE_TEMP_TABLE
|
||||
** SQLITE_CREATE_TEMP_TRIGGER
|
||||
** SQLITE_CREATE_TEMP_VIEW
|
||||
** SQLITE_CREATE_TRIGGER
|
||||
** SQLITE_CREATE_VIEW
|
||||
** SQLITE_DELETE
|
||||
** SQLITE_DROP_INDEX
|
||||
** SQLITE_DROP_TABLE
|
||||
** SQLITE_DROP_TEMP_INDEX
|
||||
** SQLITE_DROP_TEMP_TABLE
|
||||
** SQLITE_DROP_TEMP_TRIGGER
|
||||
** SQLITE_DROP_TEMP_VIEW
|
||||
** SQLITE_DROP_TRIGGER
|
||||
** SQLITE_DROP_VIEW
|
||||
** SQLITE_INSERT
|
||||
** SQLITE_PRAGMA
|
||||
** SQLITE_READ
|
||||
** SQLITE_SELECT
|
||||
** SQLITE_TRANSACTION
|
||||
** SQLITE_UPDATE
|
||||
**
|
||||
** The third and fourth arguments to the auth function are the name of
|
||||
** the table and the column that are being accessed. The auth function
|
||||
** should return either SQLITE_OK, SQLITE_DENY, or SQLITE_IGNORE. If
|
||||
** SQLITE_OK is returned, it means that access is allowed. SQLITE_DENY
|
||||
** means that the SQL statement will never-run - the sqlite3_exec() call
|
||||
** will return with an error. SQLITE_IGNORE means that the SQL statement
|
||||
** should run but attempts to read the specified column will return NULL
|
||||
** and attempts to write the column will be ignored.
|
||||
**
|
||||
** Setting the auth function to NULL disables this hook. The default
|
||||
** setting of the auth function is NULL.
|
||||
*/
|
||||
int sqlite3_set_authorizer(
|
||||
sqlite3 db,
|
||||
int (*xAuth)(void*,int,const char*,const char*,const char*,const char),
|
||||
void *pArg
|
||||
){
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
db->xAuth = xAuth;
|
||||
db->pAuthArg = pArg;
|
||||
sqlite3ExpirePreparedStatements(db);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Write an error message into pParse->zErrMsg that explains that the
|
||||
** user-supplied authorization function returned an illegal value.
|
||||
*/
|
||||
static void sqliteAuthBadReturnCode(Parse *pParse){
|
||||
sqlite3ErrorMsg(pParse, "authorizer malfunction");
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
** Invoke the authorization callback for permission to read column zCol from
|
||||
** table zTab in database zDb. This function assumes that an authorization
|
||||
** callback has been registered (i.e. that sqlite3.xAuth is not NULL).
|
||||
**
|
||||
** If SQLITE_IGNORE is returned and pExpr is not NULL, then pExpr is changed
|
||||
** to an SQL NULL expression. Otherwise, if pExpr is NULL, then SQLITE_IGNORE
|
||||
** is treated as SQLITE_DENY. In this case an error is left in pParse.
|
||||
*/
|
||||
int sqlite3AuthReadCol(
|
||||
Parse *pParse, /* The parser context */
|
||||
string zTab, /* Table name */
|
||||
string zCol, /* Column name */
|
||||
int iDb /* Index of containing database. */
|
||||
){
|
||||
sqlite3 db = pParse->db; /* Database handle */
|
||||
string zDb = db->aDb[iDb].zName; /* Name of attached database */
|
||||
int rc; /* Auth callback return code */
|
||||
|
||||
rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext);
|
||||
if( rc==SQLITE_DENY ){
|
||||
if( db->nDb>2 || iDb!=0 ){
|
||||
sqlite3ErrorMsg(pParse, "access to %s.%s.%s is prohibited",zDb,zTab,zCol);
|
||||
}else{
|
||||
sqlite3ErrorMsg(pParse, "access to %s.%s is prohibited", zTab, zCol);
|
||||
}
|
||||
pParse->rc = SQLITE_AUTH;
|
||||
}else if( rc!=SQLITE_IGNORE && rc!=SQLITE_OK ){
|
||||
sqliteAuthBadReturnCode(pParse);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** The pExpr should be a TK_COLUMN expression. The table referred to
|
||||
** is in pTabList or else it is the NEW or OLD table of a trigger.
|
||||
** Check to see if it is OK to read this particular column.
|
||||
**
|
||||
** If the auth function returns SQLITE_IGNORE, change the TK_COLUMN
|
||||
** instruction into a TK_NULL. If the auth function returns SQLITE_DENY,
|
||||
** then generate an error.
|
||||
*/
|
||||
void sqlite3AuthRead(
|
||||
Parse *pParse, /* The parser context */
|
||||
Expr *pExpr, /* The expression to check authorization on */
|
||||
Schema *pSchema, /* The schema of the expression */
|
||||
SrcList *pTabList /* All table that pExpr might refer to */
|
||||
){
|
||||
sqlite3 db = pParse->db;
|
||||
Table *pTab = 0; /* The table being read */
|
||||
string zCol; /* Name of the column of the table */
|
||||
int iSrc; /* Index in pTabList->a[] of table being read */
|
||||
int iDb; /* The index of the database the expression refers to */
|
||||
int iCol; /* Index of column in table */
|
||||
|
||||
if( db->xAuth==0 ) return;
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pSchema);
|
||||
if( iDb<0 ){
|
||||
/* An attempt to read a column out of a subquery or other
|
||||
** temporary table. */
|
||||
return;
|
||||
}
|
||||
Debug.Assert( pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER );
|
||||
if( pExpr->op==TK_TRIGGER ){
|
||||
pTab = pParse->pTriggerTab;
|
||||
}else{
|
||||
Debug.Assert( pTabList );
|
||||
for(iSrc=0; ALWAYS(iSrc<pTabList->nSrc); iSrc++){
|
||||
if( pExpr->iTable==pTabList->a[iSrc].iCursor ){
|
||||
pTab = pTabList->a[iSrc].pTab;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
iCol = pExpr->iColumn;
|
||||
if( NEVER(pTab==0) ) return;
|
||||
|
||||
if( iCol>=0 ){
|
||||
Debug.Assert( iCol<pTab->nCol );
|
||||
zCol = pTab->aCol[iCol].zName;
|
||||
}else if( pTab->iPKey>=0 ){
|
||||
Debug.Assert( pTab->iPKey<pTab->nCol );
|
||||
zCol = pTab->aCol[pTab->iPKey].zName;
|
||||
}else{
|
||||
zCol = "ROWID";
|
||||
}
|
||||
Debug.Assert( iDb>=0 && iDb<db->nDb );
|
||||
if( SQLITE_IGNORE==sqlite3AuthReadCol(pParse, pTab->zName, zCol, iDb) ){
|
||||
pExpr->op = TK_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Do an authorization check using the code and arguments given. Return
|
||||
** either SQLITE_OK (zero) or SQLITE_IGNORE or SQLITE_DENY. If SQLITE_DENY
|
||||
** is returned, then the error count and error message in pParse are
|
||||
** modified appropriately.
|
||||
*/
|
||||
int sqlite3AuthCheck(
|
||||
Parse *pParse,
|
||||
int code,
|
||||
string zArg1,
|
||||
string zArg2,
|
||||
string zArg3
|
||||
){
|
||||
sqlite3 db = pParse->db;
|
||||
int rc;
|
||||
|
||||
/* Don't do any authorization checks if the database is initialising
|
||||
** or if the parser is being invoked from within sqlite3_declare_vtab.
|
||||
*/
|
||||
if( db->init.busy || IN_DECLARE_VTAB ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
if( db->xAuth==0 ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext);
|
||||
if( rc==SQLITE_DENY ){
|
||||
sqlite3ErrorMsg(pParse, "not authorized");
|
||||
pParse->rc = SQLITE_AUTH;
|
||||
}else if( rc!=SQLITE_OK && rc!=SQLITE_IGNORE ){
|
||||
rc = SQLITE_DENY;
|
||||
sqliteAuthBadReturnCode(pParse);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Push an authorization context. After this routine is called, the
|
||||
** zArg3 argument to authorization callbacks will be zContext until
|
||||
** popped. Or if pParse==0, this routine is a no-op.
|
||||
*/
|
||||
void sqlite3AuthContextPush(
|
||||
Parse *pParse,
|
||||
AuthContext *pContext,
|
||||
string zContext
|
||||
){
|
||||
Debug.Assert( pParse );
|
||||
pContext->pParse = pParse;
|
||||
pContext->zAuthContext = pParse->zAuthContext;
|
||||
pParse->zAuthContext = zContext;
|
||||
}
|
||||
|
||||
/*
|
||||
** Pop an authorization context that was previously pushed
|
||||
** by sqlite3AuthContextPush
|
||||
*/
|
||||
void sqlite3AuthContextPop(AuthContext *pContext){
|
||||
if( pContext->pParse ){
|
||||
pContext->pParse->zAuthContext = pContext->zAuthContext;
|
||||
pContext->pParse = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif //* SQLITE_OMIT_AUTHORIZATION */
|
||||
}
|
||||
}
|
||||
829
original/Community.CsharpSqlite/src/backup_c.cs
Normal file
829
original/Community.CsharpSqlite/src/backup_c.cs
Normal file
|
|
@ -0,0 +1,829 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using i64 = System.Int64;
|
||||
using Pgno = System.UInt32;
|
||||
|
||||
using u32 = System.UInt32;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
using DbPage = Sqlite3.PgHdr;
|
||||
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2009 January 28
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains the implementation of the sqlite3_backup_XXX()
|
||||
** API functions and the related features.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2011-05-19 13:26:54 ed1da510a239ea767a01dc332b667119fa3c908e
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#include "sqliteInt.h"
|
||||
//#include "btreeInt.h"
|
||||
|
||||
/* Macro to find the minimum of two numeric values.
|
||||
*/
|
||||
#if !MIN
|
||||
//# define MIN(x,y) ((x)<(y)?(x):(y))
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Structure allocated for each backup operation.
|
||||
*/
|
||||
|
||||
public class sqlite3_backup
|
||||
{
|
||||
public sqlite3 pDestDb; /* Destination database handle */
|
||||
public Btree pDest; /* Destination b-tree file */
|
||||
public u32 iDestSchema; /* Original schema cookie in destination */
|
||||
public int bDestLocked; /* True once a write-transaction is open on pDest */
|
||||
|
||||
public Pgno iNext; /* Page number of the next source page to copy */
|
||||
public sqlite3 pSrcDb; /* Source database handle */
|
||||
public Btree pSrc; /* Source b-tree file */
|
||||
|
||||
public int rc; /* Backup process error code */
|
||||
|
||||
/* These two variables are set by every call to backup_step(). They are
|
||||
** read by calls to backup_remaining() and backup_pagecount().
|
||||
*/
|
||||
public Pgno nRemaining; /* Number of pages left to copy */
|
||||
public Pgno nPagecount; /* Total number of pages to copy */
|
||||
|
||||
public int isAttached; /* True once backup has been registered with pager */
|
||||
public sqlite3_backup pNext; /* Next backup associated with source pager */
|
||||
};
|
||||
|
||||
/*
|
||||
** THREAD SAFETY NOTES:
|
||||
**
|
||||
** Once it has been created using backup_init(), a single sqlite3_backup
|
||||
** structure may be accessed via two groups of thread-safe entry points:
|
||||
**
|
||||
** * Via the sqlite3_backup_XXX() API function backup_step() and
|
||||
** backup_finish(). Both these functions obtain the source database
|
||||
** handle mutex and the mutex associated with the source BtShared
|
||||
** structure, in that order.
|
||||
**
|
||||
** * Via the BackupUpdate() and BackupRestart() functions, which are
|
||||
** invoked by the pager layer to report various state changes in
|
||||
** the page cache associated with the source database. The mutex
|
||||
** associated with the source database BtShared structure will always
|
||||
** be held when either of these functions are invoked.
|
||||
**
|
||||
** The other sqlite3_backup_XXX() API functions, backup_remaining() and
|
||||
** backup_pagecount() are not thread-safe functions. If they are called
|
||||
** while some other thread is calling backup_step() or backup_finish(),
|
||||
** the values returned may be invalid. There is no way for a call to
|
||||
** BackupUpdate() or BackupRestart() to interfere with backup_remaining()
|
||||
** or backup_pagecount().
|
||||
**
|
||||
** Depending on the SQLite configuration, the database handles and/or
|
||||
** the Btree objects may have their own mutexes that require locking.
|
||||
** Non-sharable Btrees (in-memory databases for example), do not have
|
||||
** associated mutexes.
|
||||
*/
|
||||
|
||||
/*
|
||||
** Return a pointer corresponding to database zDb (i.e. "main", "temp")
|
||||
** in connection handle pDb. If such a database cannot be found, return
|
||||
** a NULL pointer and write an error message to pErrorDb.
|
||||
**
|
||||
** If the "temp" database is requested, it may need to be opened by this
|
||||
** function. If an error occurs while doing so, return 0 and write an
|
||||
** error message to pErrorDb.
|
||||
*/
|
||||
|
||||
private static Btree findBtree(sqlite3 pErrorDb, sqlite3 pDb, string zDb)
|
||||
{
|
||||
int i = sqlite3FindDbName(pDb, zDb);
|
||||
|
||||
if (i == 1)
|
||||
{
|
||||
Parse pParse;
|
||||
int rc = 0;
|
||||
pParse = new Parse();//sqlite3StackAllocZero(pErrorDb, sizeof(*pParse));
|
||||
if (pParse == null)
|
||||
{
|
||||
sqlite3Error(pErrorDb, SQLITE_NOMEM, "out of memory");
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
else
|
||||
{
|
||||
pParse.db = pDb;
|
||||
if (sqlite3OpenTempDatabase(pParse) != 0)
|
||||
{
|
||||
sqlite3Error(pErrorDb, pParse.rc, "%s", pParse.zErrMsg);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
sqlite3DbFree(pErrorDb, ref pParse.zErrMsg);
|
||||
//sqlite3StackFree( pErrorDb, pParse );
|
||||
}
|
||||
if (rc != 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (i < 0)
|
||||
{
|
||||
sqlite3Error(pErrorDb, SQLITE_ERROR, "unknown database %s", zDb);
|
||||
return null;
|
||||
}
|
||||
|
||||
return pDb.aDb[i].pBt;
|
||||
}
|
||||
|
||||
/*
|
||||
** Attempt to set the page size of the destination to match the page size
|
||||
** of the source.
|
||||
*/
|
||||
|
||||
private static int setDestPgsz(sqlite3_backup p)
|
||||
{
|
||||
int rc;
|
||||
rc = sqlite3BtreeSetPageSize(p.pDest, sqlite3BtreeGetPageSize(p.pSrc), -1, 0);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Create an sqlite3_backup process to copy the contents of zSrcDb from
|
||||
** connection handle pSrcDb to zDestDb in pDestDb. If successful, return
|
||||
** a pointer to the new sqlite3_backup object.
|
||||
**
|
||||
** If an error occurs, NULL is returned and an error code and error message
|
||||
** stored in database handle pDestDb.
|
||||
*/
|
||||
|
||||
static public sqlite3_backup sqlite3_backup_init(
|
||||
sqlite3 pDestDb, /* Database to write to */
|
||||
string zDestDb, /* Name of database within pDestDb */
|
||||
sqlite3 pSrcDb, /* Database connection to read from */
|
||||
string zSrcDb /* Name of database within pSrcDb */
|
||||
)
|
||||
{
|
||||
sqlite3_backup p; /* Value to return */
|
||||
|
||||
/* Lock the source database handle. The destination database
|
||||
** handle is not locked in this routine, but it is locked in
|
||||
** sqlite3_backup_step(). The user is required to ensure that no
|
||||
** other thread accesses the destination handle for the duration
|
||||
** of the backup operation. Any attempt to use the destination
|
||||
** database connection while a backup is in progress may cause
|
||||
** a malfunction or a deadlock.
|
||||
*/
|
||||
sqlite3_mutex_enter(pSrcDb.mutex);
|
||||
sqlite3_mutex_enter(pDestDb.mutex);
|
||||
|
||||
if (pSrcDb == pDestDb)
|
||||
{
|
||||
sqlite3Error(
|
||||
pDestDb, SQLITE_ERROR, "source and destination must be distinct"
|
||||
);
|
||||
p = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Allocate space for a new sqlite3_backup object...
|
||||
** EVIDENCE-OF: R-64852-21591 The sqlite3_backup object is created by a
|
||||
** call to sqlite3_backup_init() and is destroyed by a call to
|
||||
** sqlite3_backup_finish(). */
|
||||
p = new sqlite3_backup();// (sqlite3_backup)sqlite3_malloc( sizeof( sqlite3_backup ) );
|
||||
//if ( null == p )
|
||||
//{
|
||||
// sqlite3Error( pDestDb, SQLITE_NOMEM, 0 );
|
||||
//}
|
||||
}
|
||||
|
||||
/* If the allocation succeeded, populate the new object. */
|
||||
if (p != null)
|
||||
{
|
||||
// memset( p, 0, sizeof( sqlite3_backup ) );
|
||||
p.pSrc = findBtree(pDestDb, pSrcDb, zSrcDb);
|
||||
p.pDest = findBtree(pDestDb, pDestDb, zDestDb);
|
||||
p.pDestDb = pDestDb;
|
||||
p.pSrcDb = pSrcDb;
|
||||
p.iNext = 1;
|
||||
p.isAttached = 0;
|
||||
|
||||
if (null == p.pSrc || null == p.pDest || setDestPgsz(p) == SQLITE_NOMEM)
|
||||
{
|
||||
/* One (or both) of the named databases did not exist or an OOM
|
||||
** error was hit. The error has already been written into the
|
||||
** pDestDb handle. All that is left to do here is free the
|
||||
** sqlite3_backup structure.
|
||||
*/
|
||||
//sqlite3_free( ref p );
|
||||
p = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (p != null)
|
||||
{
|
||||
p.pSrc.nBackup++;
|
||||
}
|
||||
|
||||
sqlite3_mutex_leave(pDestDb.mutex);
|
||||
sqlite3_mutex_leave(pSrcDb.mutex);
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Argument rc is an SQLite error code. Return true if this error is
|
||||
** considered fatal if encountered during a backup operation. All errors
|
||||
** are considered fatal except for SQLITE_BUSY and SQLITE_LOCKED.
|
||||
*/
|
||||
|
||||
private static bool isFatalError(int rc)
|
||||
{
|
||||
return (rc != SQLITE_OK && rc != SQLITE_BUSY && ALWAYS(rc != SQLITE_LOCKED));
|
||||
}
|
||||
|
||||
/*
|
||||
** Parameter zSrcData points to a buffer containing the data for
|
||||
** page iSrcPg from the source database. Copy this data into the
|
||||
** destination database.
|
||||
*/
|
||||
|
||||
private static int backupOnePage(sqlite3_backup p, Pgno iSrcPg, byte[] zSrcData)
|
||||
{
|
||||
Pager pDestPager = sqlite3BtreePager(p.pDest);
|
||||
int nSrcPgsz = sqlite3BtreeGetPageSize(p.pSrc);
|
||||
int nDestPgsz = sqlite3BtreeGetPageSize(p.pDest);
|
||||
int nCopy = MIN(nSrcPgsz, nDestPgsz);
|
||||
i64 iEnd = (i64)iSrcPg * (i64)nSrcPgsz;
|
||||
#if SQLITE_HAS_CODEC
|
||||
int nSrcReserve = sqlite3BtreeGetReserve(p.pSrc);
|
||||
int nDestReserve = sqlite3BtreeGetReserve(p.pDest);
|
||||
#endif
|
||||
|
||||
int rc = SQLITE_OK;
|
||||
i64 iOff;
|
||||
|
||||
Debug.Assert(p.bDestLocked != 0);
|
||||
Debug.Assert(!isFatalError(p.rc));
|
||||
Debug.Assert(iSrcPg != PENDING_BYTE_PAGE(p.pSrc.pBt));
|
||||
Debug.Assert(zSrcData != null);
|
||||
|
||||
/* Catch the case where the destination is an in-memory database and the
|
||||
** page sizes of the source and destination differ.
|
||||
*/
|
||||
if (nSrcPgsz != nDestPgsz && sqlite3PagerIsMemdb(pDestPager))
|
||||
{
|
||||
rc = SQLITE_READONLY;
|
||||
}
|
||||
|
||||
#if SQLITE_HAS_CODEC
|
||||
/* Backup is not possible if the page size of the destination is changing
|
||||
** and a codec is in use.
|
||||
*/
|
||||
if (nSrcPgsz != nDestPgsz && sqlite3PagerGetCodec(pDestPager) != null)
|
||||
{
|
||||
rc = SQLITE_READONLY;
|
||||
}
|
||||
|
||||
/* Backup is not possible if the number of bytes of reserve space differ
|
||||
** between source and destination. If there is a difference, try to
|
||||
** fix the destination to agree with the source. If that is not possible,
|
||||
** then the backup cannot proceed.
|
||||
*/
|
||||
if (nSrcReserve != nDestReserve)
|
||||
{
|
||||
u32 newPgsz = (u32)nSrcPgsz;
|
||||
rc = sqlite3PagerSetPagesize(pDestPager, ref newPgsz, nSrcReserve);
|
||||
if (rc == SQLITE_OK && newPgsz != nSrcPgsz)
|
||||
rc = SQLITE_READONLY;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This loop runs once for each destination page spanned by the source
|
||||
** page. For each iteration, variable iOff is set to the byte offset
|
||||
** of the destination page.
|
||||
*/
|
||||
for (iOff = iEnd - (i64)nSrcPgsz; rc == SQLITE_OK && iOff < iEnd; iOff += nDestPgsz)
|
||||
{
|
||||
DbPage pDestPg = null;
|
||||
u32 iDest = (u32)(iOff / nDestPgsz) + 1;
|
||||
if (iDest == PENDING_BYTE_PAGE(p.pDest.pBt))
|
||||
continue;
|
||||
if (SQLITE_OK == (rc = sqlite3PagerGet(pDestPager, iDest, ref pDestPg))
|
||||
&& SQLITE_OK == (rc = sqlite3PagerWrite(pDestPg))
|
||||
)
|
||||
{
|
||||
//string zIn = &zSrcData[iOff%nSrcPgsz];
|
||||
byte[] zDestData = sqlite3PagerGetData(pDestPg);
|
||||
//string zOut = &zDestData[iOff % nDestPgsz];
|
||||
|
||||
/* Copy the data from the source page into the destination page.
|
||||
** Then clear the Btree layer MemPage.isInit flag. Both this module
|
||||
** and the pager code use this trick (clearing the first byte
|
||||
** of the page 'extra' space to invalidate the Btree layers
|
||||
** cached parse of the page). MemPage.isInit is marked
|
||||
** "MUST BE FIRST" for this purpose.
|
||||
*/
|
||||
Buffer.BlockCopy(zSrcData, (int)(iOff % nSrcPgsz), zDestData, (int)(iOff % nDestPgsz), nCopy);// memcpy( zOut, zIn, nCopy );
|
||||
sqlite3PagerGetExtra(pDestPg).isInit = 0;// ( sqlite3PagerGetExtra( pDestPg ) )[0] = 0;
|
||||
}
|
||||
sqlite3PagerUnref(pDestPg);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** If pFile is currently larger than iSize bytes, then truncate it to
|
||||
** exactly iSize bytes. If pFile is not larger than iSize bytes, then
|
||||
** this function is a no-op.
|
||||
**
|
||||
** Return SQLITE_OK if everything is successful, or an SQLite error
|
||||
** code if an error occurs.
|
||||
*/
|
||||
|
||||
private static int backupTruncateFile(sqlite3_file pFile, int iSize)
|
||||
{
|
||||
long iCurrent = 0;
|
||||
int rc = sqlite3OsFileSize(pFile, ref iCurrent);
|
||||
if (rc == SQLITE_OK && iCurrent > iSize)
|
||||
{
|
||||
rc = sqlite3OsTruncate(pFile, iSize);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Register this backup object with the associated source pager for
|
||||
** callbacks when pages are changed or the cache invalidated.
|
||||
*/
|
||||
|
||||
private static void attachBackupObject(sqlite3_backup p)
|
||||
{
|
||||
sqlite3_backup pp;
|
||||
Debug.Assert(sqlite3BtreeHoldsMutex(p.pSrc));
|
||||
pp = sqlite3PagerBackupPtr(sqlite3BtreePager(p.pSrc));
|
||||
p.pNext = pp;
|
||||
sqlite3BtreePager(p.pSrc).pBackup = p; //*pp = p;
|
||||
p.isAttached = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Copy nPage pages from the source b-tree to the destination.
|
||||
*/
|
||||
|
||||
static public int sqlite3_backup_step(sqlite3_backup p, int nPage)
|
||||
{
|
||||
int rc;
|
||||
int destMode; /* Destination journal mode */
|
||||
int pgszSrc = 0; /* Source page size */
|
||||
int pgszDest = 0; /* Destination page size */
|
||||
|
||||
sqlite3_mutex_enter(p.pSrcDb.mutex);
|
||||
sqlite3BtreeEnter(p.pSrc);
|
||||
if (p.pDestDb != null)
|
||||
{
|
||||
sqlite3_mutex_enter(p.pDestDb.mutex);
|
||||
}
|
||||
|
||||
rc = p.rc;
|
||||
if (!isFatalError(rc))
|
||||
{
|
||||
Pager pSrcPager = sqlite3BtreePager(p.pSrc); /* Source pager */
|
||||
Pager pDestPager = sqlite3BtreePager(p.pDest); /* Dest pager */
|
||||
int ii; /* Iterator variable */
|
||||
Pgno nSrcPage = 0; /* Size of source db in pages */
|
||||
int bCloseTrans = 0; /* True if src db requires unlocking */
|
||||
|
||||
/* If the source pager is currently in a write-transaction, return
|
||||
** SQLITE_BUSY immediately.
|
||||
*/
|
||||
if (p.pDestDb != null && p.pSrc.pBt.inTransaction == TRANS_WRITE)
|
||||
{
|
||||
rc = SQLITE_BUSY;
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Lock the destination database, if it is not locked already. */
|
||||
if (SQLITE_OK == rc && p.bDestLocked == 0
|
||||
&& SQLITE_OK == (rc = sqlite3BtreeBeginTrans(p.pDest, 2))
|
||||
)
|
||||
{
|
||||
p.bDestLocked = 1;
|
||||
sqlite3BtreeGetMeta(p.pDest, BTREE_SCHEMA_VERSION, ref p.iDestSchema);
|
||||
}
|
||||
|
||||
/* If there is no open read-transaction on the source database, open
|
||||
** one now. If a transaction is opened here, then it will be closed
|
||||
** before this function exits.
|
||||
*/
|
||||
if (rc == SQLITE_OK && !sqlite3BtreeIsInReadTrans(p.pSrc))
|
||||
{
|
||||
rc = sqlite3BtreeBeginTrans(p.pSrc, 0);
|
||||
bCloseTrans = 1;
|
||||
}
|
||||
|
||||
/* Do not allow backup if the destination database is in WAL mode
|
||||
** and the page sizes are different between source and destination */
|
||||
pgszSrc = sqlite3BtreeGetPageSize(p.pSrc);
|
||||
pgszDest = sqlite3BtreeGetPageSize(p.pDest);
|
||||
destMode = sqlite3PagerGetJournalMode(sqlite3BtreePager(p.pDest));
|
||||
if (SQLITE_OK == rc && destMode == PAGER_JOURNALMODE_WAL && pgszSrc != pgszDest)
|
||||
{
|
||||
rc = SQLITE_READONLY;
|
||||
}
|
||||
|
||||
/* Now that there is a read-lock on the source database, query the
|
||||
** source pager for the number of pages in the database.
|
||||
*/
|
||||
nSrcPage = sqlite3BtreeLastPage(p.pSrc);
|
||||
Debug.Assert(nSrcPage >= 0);
|
||||
|
||||
for (ii = 0; (nPage < 0 || ii < nPage) && p.iNext <= nSrcPage && 0 == rc; ii++)
|
||||
{
|
||||
Pgno iSrcPg = p.iNext; /* Source page number */
|
||||
if (iSrcPg != PENDING_BYTE_PAGE(p.pSrc.pBt))
|
||||
{
|
||||
DbPage pSrcPg = null; /* Source page object */
|
||||
rc = sqlite3PagerGet(pSrcPager, (u32)iSrcPg, ref pSrcPg);
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
rc = backupOnePage(p, iSrcPg, sqlite3PagerGetData(pSrcPg));
|
||||
sqlite3PagerUnref(pSrcPg);
|
||||
}
|
||||
}
|
||||
p.iNext++;
|
||||
}
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
p.nPagecount = nSrcPage;
|
||||
p.nRemaining = (nSrcPage + 1 - p.iNext);
|
||||
if (p.iNext > nSrcPage)
|
||||
{
|
||||
rc = SQLITE_DONE;
|
||||
}
|
||||
else if (0 == p.isAttached)
|
||||
{
|
||||
attachBackupObject(p);
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the schema version field in the destination database. This
|
||||
** is to make sure that the schema-version really does change in
|
||||
** the case where the source and destination databases have the
|
||||
** same schema version.
|
||||
*/
|
||||
if (rc == SQLITE_DONE
|
||||
&& (rc = sqlite3BtreeUpdateMeta(p.pDest, 1, p.iDestSchema + 1)) == SQLITE_OK
|
||||
)
|
||||
{
|
||||
Pgno nDestTruncate;
|
||||
if (p.pDestDb != null)
|
||||
{
|
||||
sqlite3ResetInternalSchema(p.pDestDb, -1);
|
||||
}
|
||||
|
||||
/* Set nDestTruncate to the final number of pages in the destination
|
||||
** database. The complication here is that the destination page
|
||||
** size may be different to the source page size.
|
||||
**
|
||||
** If the source page size is smaller than the destination page size,
|
||||
** round up. In this case the call to sqlite3OsTruncate() below will
|
||||
** fix the size of the file. However it is important to call
|
||||
** sqlite3PagerTruncateImage() here so that any pages in the
|
||||
** destination file that lie beyond the nDestTruncate page mark are
|
||||
** journalled by PagerCommitPhaseOne() before they are destroyed
|
||||
** by the file truncation.
|
||||
*/
|
||||
Debug.Assert(pgszSrc == sqlite3BtreeGetPageSize(p.pSrc));
|
||||
Debug.Assert(pgszDest == sqlite3BtreeGetPageSize(p.pDest));
|
||||
if (pgszSrc < pgszDest)
|
||||
{
|
||||
int ratio = pgszDest / pgszSrc;
|
||||
nDestTruncate = (Pgno)((nSrcPage + ratio - 1) / ratio);
|
||||
if (nDestTruncate == (int)PENDING_BYTE_PAGE(p.pDest.pBt))
|
||||
{
|
||||
nDestTruncate--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nDestTruncate = (Pgno)(nSrcPage * (pgszSrc / pgszDest));
|
||||
}
|
||||
sqlite3PagerTruncateImage(pDestPager, nDestTruncate);
|
||||
|
||||
if (pgszSrc < pgszDest)
|
||||
{
|
||||
/* If the source page-size is smaller than the destination page-size,
|
||||
** two extra things may need to happen:
|
||||
**
|
||||
** * The destination may need to be truncated, and
|
||||
**
|
||||
** * Data stored on the pages immediately following the
|
||||
** pending-byte page in the source database may need to be
|
||||
** copied into the destination database.
|
||||
*/
|
||||
int iSize = (int)(pgszSrc * nSrcPage);
|
||||
sqlite3_file pFile = sqlite3PagerFile(pDestPager);
|
||||
i64 iOff;
|
||||
i64 iEnd;
|
||||
|
||||
Debug.Assert(pFile != null);
|
||||
Debug.Assert((i64)nDestTruncate * (i64)pgszDest >= iSize || (
|
||||
nDestTruncate == (int)(PENDING_BYTE_PAGE(p.pDest.pBt) - 1)
|
||||
&& iSize >= PENDING_BYTE && iSize <= PENDING_BYTE + pgszDest
|
||||
));
|
||||
|
||||
/* This call ensures that all data required to recreate the original
|
||||
** database has been stored in the journal for pDestPager and the
|
||||
** journal synced to disk. So at this point we may safely modify
|
||||
** the database file in any way, knowing that if a power failure
|
||||
** occurs, the original database will be reconstructed from the
|
||||
** journal file. */
|
||||
rc = sqlite3PagerCommitPhaseOne(pDestPager, null, true);
|
||||
|
||||
/* Write the extra pages and truncate the database file as required. */
|
||||
iEnd = MIN(PENDING_BYTE + pgszDest, iSize);
|
||||
for (
|
||||
iOff = PENDING_BYTE + pgszSrc;
|
||||
rc == SQLITE_OK && iOff < iEnd;
|
||||
iOff += pgszSrc
|
||||
)
|
||||
{
|
||||
PgHdr pSrcPg = null;
|
||||
u32 iSrcPg = (u32)((iOff / pgszSrc) + 1);
|
||||
rc = sqlite3PagerGet(pSrcPager, iSrcPg, ref pSrcPg);
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
byte[] zData = sqlite3PagerGetData(pSrcPg);
|
||||
rc = sqlite3OsWrite(pFile, zData, pgszSrc, iOff);
|
||||
}
|
||||
sqlite3PagerUnref(pSrcPg);
|
||||
}
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
rc = backupTruncateFile(pFile, (int)iSize);
|
||||
}
|
||||
|
||||
/* Sync the database file to disk. */
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
rc = sqlite3PagerSync(pDestPager);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = sqlite3PagerCommitPhaseOne(pDestPager, null, false);
|
||||
}
|
||||
|
||||
/* Finish committing the transaction to the destination database. */
|
||||
if (SQLITE_OK == rc
|
||||
&& SQLITE_OK == (rc = sqlite3BtreeCommitPhaseTwo(p.pDest, 0))
|
||||
)
|
||||
{
|
||||
rc = SQLITE_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
/* If bCloseTrans is true, then this function opened a read transaction
|
||||
** on the source database. Close the read transaction here. There is
|
||||
** no need to check the return values of the btree methods here, as
|
||||
** "committing" a read-only transaction cannot fail.
|
||||
*/
|
||||
if (bCloseTrans != 0)
|
||||
{
|
||||
#if !NDEBUG || SQLITE_COVERAGE_TEST
|
||||
//TESTONLY( int rc2 );
|
||||
//TESTONLY( rc2 = ) sqlite3BtreeCommitPhaseOne(p.pSrc, 0);
|
||||
//TESTONLY( rc2 |= ) sqlite3BtreeCommitPhaseTwo(p.pSrc);
|
||||
int rc2;
|
||||
rc2 = sqlite3BtreeCommitPhaseOne(p.pSrc, "");
|
||||
rc2 |= sqlite3BtreeCommitPhaseTwo(p.pSrc, 0);
|
||||
Debug.Assert(rc2 == SQLITE_OK);
|
||||
#else
|
||||
sqlite3BtreeCommitPhaseOne(p.pSrc, null);
|
||||
sqlite3BtreeCommitPhaseTwo(p.pSrc, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (rc == SQLITE_IOERR_NOMEM)
|
||||
{
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
p.rc = rc;
|
||||
}
|
||||
if (p.pDestDb != null)
|
||||
{
|
||||
sqlite3_mutex_leave(p.pDestDb.mutex);
|
||||
}
|
||||
sqlite3BtreeLeave(p.pSrc);
|
||||
sqlite3_mutex_leave(p.pSrcDb.mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Release all resources associated with an sqlite3_backup* handle.
|
||||
*/
|
||||
|
||||
static public int sqlite3_backup_finish(sqlite3_backup p)
|
||||
{
|
||||
sqlite3_backup pp; /* Ptr to head of pagers backup list */
|
||||
sqlite3_mutex mutex; /* Mutex to protect source database */
|
||||
int rc; /* Value to return */
|
||||
|
||||
/* Enter the mutexes */
|
||||
if (p == null)
|
||||
return SQLITE_OK;
|
||||
sqlite3_mutex_enter(p.pSrcDb.mutex);
|
||||
sqlite3BtreeEnter(p.pSrc);
|
||||
mutex = p.pSrcDb.mutex;
|
||||
if (p.pDestDb != null)
|
||||
{
|
||||
sqlite3_mutex_enter(p.pDestDb.mutex);
|
||||
}
|
||||
|
||||
/* Detach this backup from the source pager. */
|
||||
if (p.pDestDb != null)
|
||||
{
|
||||
p.pSrc.nBackup--;
|
||||
}
|
||||
if (p.isAttached != 0)
|
||||
{
|
||||
pp = sqlite3PagerBackupPtr(sqlite3BtreePager(p.pSrc));
|
||||
while (pp != p)
|
||||
{
|
||||
pp = (pp).pNext;
|
||||
}
|
||||
sqlite3BtreePager(p.pSrc).pBackup = p.pNext;
|
||||
}
|
||||
|
||||
/* If a transaction is still open on the Btree, roll it back. */
|
||||
sqlite3BtreeRollback(p.pDest);
|
||||
|
||||
/* Set the error code of the destination database handle. */
|
||||
rc = (p.rc == SQLITE_DONE) ? SQLITE_OK : p.rc;
|
||||
sqlite3Error(p.pDestDb, rc, 0);
|
||||
|
||||
/* Exit the mutexes and free the backup context structure. */
|
||||
if (p.pDestDb != null)
|
||||
{
|
||||
sqlite3_mutex_leave(p.pDestDb.mutex);
|
||||
}
|
||||
sqlite3BtreeLeave(p.pSrc);
|
||||
if (p.pDestDb != null)
|
||||
{
|
||||
/* EVIDENCE-OF: R-64852-21591 The sqlite3_backup object is created by a
|
||||
** call to sqlite3_backup_init() and is destroyed by a call to
|
||||
** sqlite3_backup_finish(). */
|
||||
//sqlite3_free( ref p );
|
||||
}
|
||||
sqlite3_mutex_leave(mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of pages still to be backed up as of the most recent
|
||||
** call to sqlite3_backup_step().
|
||||
*/
|
||||
|
||||
private static int sqlite3_backup_remaining(sqlite3_backup p)
|
||||
{
|
||||
return (int)p.nRemaining;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the total number of pages in the source database as of the most
|
||||
** recent call to sqlite3_backup_step().
|
||||
*/
|
||||
|
||||
private static int sqlite3_backup_pagecount(sqlite3_backup p)
|
||||
{
|
||||
return (int)p.nPagecount;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is called after the contents of page iPage of the
|
||||
** source database have been modified. If page iPage has already been
|
||||
** copied into the destination database, then the data written to the
|
||||
** destination is now invalidated. The destination copy of iPage needs
|
||||
** to be updated with the new data before the backup operation is
|
||||
** complete.
|
||||
**
|
||||
** It is assumed that the mutex associated with the BtShared object
|
||||
** corresponding to the source database is held when this function is
|
||||
** called.
|
||||
*/
|
||||
|
||||
private static void sqlite3BackupUpdate(sqlite3_backup pBackup, Pgno iPage, byte[] aData)
|
||||
{
|
||||
sqlite3_backup p; /* Iterator variable */
|
||||
for (p = pBackup; p != null; p = p.pNext)
|
||||
{
|
||||
Debug.Assert(sqlite3_mutex_held(p.pSrc.pBt.mutex));
|
||||
if (!isFatalError(p.rc) && iPage < p.iNext)
|
||||
{
|
||||
/* The backup process p has already copied page iPage. But now it
|
||||
** has been modified by a transaction on the source pager. Copy
|
||||
** the new data into the backup.
|
||||
*/
|
||||
int rc;
|
||||
Debug.Assert(p.pDestDb != null);
|
||||
sqlite3_mutex_enter(p.pDestDb.mutex);
|
||||
rc = backupOnePage(p, iPage, aData);
|
||||
sqlite3_mutex_leave(p.pDestDb.mutex);
|
||||
Debug.Assert(rc != SQLITE_BUSY && rc != SQLITE_LOCKED);
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
p.rc = rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Restart the backup process. This is called when the pager layer
|
||||
** detects that the database has been modified by an external database
|
||||
** connection. In this case there is no way of knowing which of the
|
||||
** pages that have been copied into the destination database are still
|
||||
** valid and which are not, so the entire process needs to be restarted.
|
||||
**
|
||||
** It is assumed that the mutex associated with the BtShared object
|
||||
** corresponding to the source database is held when this function is
|
||||
** called.
|
||||
*/
|
||||
|
||||
private static void sqlite3BackupRestart(sqlite3_backup pBackup)
|
||||
{
|
||||
sqlite3_backup p; /* Iterator variable */
|
||||
for (p = pBackup; p != null; p = p.pNext)
|
||||
{
|
||||
Debug.Assert(sqlite3_mutex_held(p.pSrc.pBt.mutex));
|
||||
p.iNext = 1;
|
||||
}
|
||||
}
|
||||
|
||||
#if !SQLITE_OMIT_VACUUM
|
||||
/*
|
||||
** Copy the complete content of pBtFrom into pBtTo. A transaction
|
||||
** must be active for both files.
|
||||
**
|
||||
** The size of file pTo may be reduced by this operation. If anything
|
||||
** goes wrong, the transaction on pTo is rolled back. If successful, the
|
||||
** transaction is committed before returning.
|
||||
*/
|
||||
|
||||
private static int sqlite3BtreeCopyFile(Btree pTo, Btree pFrom)
|
||||
{
|
||||
int rc;
|
||||
sqlite3_backup b;
|
||||
sqlite3BtreeEnter(pTo);
|
||||
sqlite3BtreeEnter(pFrom);
|
||||
|
||||
/* Set up an sqlite3_backup object. sqlite3_backup.pDestDb must be set
|
||||
** to 0. This is used by the implementations of sqlite3_backup_step()
|
||||
** and sqlite3_backup_finish() to detect that they are being called
|
||||
** from this function, not directly by the user.
|
||||
*/
|
||||
b = new sqlite3_backup();// memset( &b, 0, sizeof( b ) );
|
||||
b.pSrcDb = pFrom.db;
|
||||
b.pSrc = pFrom;
|
||||
b.pDest = pTo;
|
||||
b.iNext = 1;
|
||||
|
||||
/* 0x7FFFFFFF is the hard limit for the number of pages in a database
|
||||
** file. By passing this as the number of pages to copy to
|
||||
** sqlite3_backup_step(), we can guarantee that the copy finishes
|
||||
** within a single call (unless an error occurs). The Debug.Assert() statement
|
||||
** checks this assumption - (p.rc) should be set to either SQLITE_DONE
|
||||
** or an error code.
|
||||
*/
|
||||
sqlite3_backup_step(b, 0x7FFFFFFF);
|
||||
Debug.Assert(b.rc != SQLITE_OK);
|
||||
rc = sqlite3_backup_finish(b);
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
pTo.pBt.pageSizeFixed = false;
|
||||
}
|
||||
|
||||
sqlite3BtreeLeave(pFrom);
|
||||
sqlite3BtreeLeave(pTo);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif //* SQLITE_OMIT_VACUUM */
|
||||
}
|
||||
}
|
||||
545
original/Community.CsharpSqlite/src/bitvec_c.cs
Normal file
545
original/Community.CsharpSqlite/src/bitvec_c.cs
Normal file
|
|
@ -0,0 +1,545 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using BITVEC_TELEM = System.Byte;
|
||||
using i64 = System.Int64;
|
||||
using u32 = System.UInt32;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2008 February 16
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file implements an object that represents a fixed-length
|
||||
** bitmap. Bits are numbered starting with 1.
|
||||
**
|
||||
** A bitmap is used to record which pages of a database file have been
|
||||
** journalled during a transaction, or which pages have the "dont-write"
|
||||
** property. Usually only a few pages are meet either condition.
|
||||
** So the bitmap is usually sparse and has low cardinality.
|
||||
** But sometimes (for example when during a DROP of a large table) most
|
||||
** or all of the pages in a database can get journalled. In those cases,
|
||||
** the bitmap becomes dense with high cardinality. The algorithm needs
|
||||
** to handle both cases well.
|
||||
**
|
||||
** The size of the bitmap is fixed when the object is created.
|
||||
**
|
||||
** All bits are clear when the bitmap is created. Individual bits
|
||||
** may be set or cleared one at a time.
|
||||
**
|
||||
** Test operations are about 100 times more common that set operations.
|
||||
** Clear operations are exceedingly rare. There are usually between
|
||||
** 5 and 500 set operations per Bitvec object, though the number of sets can
|
||||
** sometimes grow into tens of thousands or larger. The size of the
|
||||
** Bitvec object is the number of pages in the database file at the
|
||||
** start of a transaction, and is thus usually less than a few thousand,
|
||||
** but can be as large as 2 billion for a really big database.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2010-08-23 18:52:01 42537b60566f288167f1b5864a5435986838e3a3
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#include "sqliteInt.h"
|
||||
|
||||
/* Size of the Bitvec structure in bytes. */
|
||||
private static int BITVEC_SZ = 512;
|
||||
|
||||
/* Round the union size down to the nearest pointer boundary, since that's how
|
||||
** it will be aligned within the Bitvec struct. */
|
||||
|
||||
//#define BITVEC_USIZE (((BITVEC_SZ-(3*sizeof(u32)))/sizeof(Bitvec*))*sizeof(Bitvec*))
|
||||
private static int BITVEC_USIZE = (((BITVEC_SZ - (3 * sizeof(u32))) / 4) * 4);
|
||||
|
||||
/* Type of the array "element" for the bitmap representation.
|
||||
** Should be a power of 2, and ideally, evenly divide into BITVEC_USIZE.
|
||||
** Setting this to the "natural word" size of your CPU may improve
|
||||
** performance. */
|
||||
//#define BITVEC_TELEM u8
|
||||
//using BITVEC_TELEM = System.Byte;
|
||||
|
||||
/* Size, in bits, of the bitmap element. */
|
||||
|
||||
//#define BITVEC_SZELEM 8
|
||||
private const int BITVEC_SZELEM = 8;
|
||||
|
||||
/* Number of elements in a bitmap array. */
|
||||
|
||||
//#define BITVEC_NELEM (BITVEC_USIZE/sizeof(BITVEC_TELEM))
|
||||
private static int BITVEC_NELEM = (int)(BITVEC_USIZE / sizeof(BITVEC_TELEM));
|
||||
|
||||
/* Number of bits in the bitmap array. */
|
||||
|
||||
//#define BITVEC_NBIT (BITVEC_NELEM*BITVEC_SZELEM)
|
||||
private static int BITVEC_NBIT = (BITVEC_NELEM * BITVEC_SZELEM);
|
||||
|
||||
/* Number of u32 values in hash table. */
|
||||
|
||||
//#define BITVEC_NINT (BITVEC_USIZE/sizeof(u32))
|
||||
private static u32 BITVEC_NINT = (u32)(BITVEC_USIZE / sizeof(u32));
|
||||
|
||||
/* Maximum number of entries in hash table before
|
||||
** sub-dividing and re-hashing. */
|
||||
|
||||
//#define BITVEC_MXHASH (BITVEC_NINT/2)
|
||||
private static int BITVEC_MXHASH = (int)(BITVEC_NINT / 2);
|
||||
|
||||
/* Hashing function for the aHash representation.
|
||||
** Empirical testing showed that the *37 multiplier
|
||||
** (an arbitrary prime)in the hash function provided
|
||||
** no fewer collisions than the no-op *1. */
|
||||
|
||||
//#define BITVEC_HASH(X) (((X)*1)%BITVEC_NINT)
|
||||
private static u32 BITVEC_HASH(u32 X)
|
||||
{
|
||||
return (u32)(((X) * 1) % BITVEC_NINT);
|
||||
}
|
||||
|
||||
private static int BITVEC_NPTR = (int)(BITVEC_USIZE / 4);//sizeof(Bitvec *));
|
||||
|
||||
/*
|
||||
** A bitmap is an instance of the following structure.
|
||||
**
|
||||
** This bitmap records the existence of zero or more bits
|
||||
** with values between 1 and iSize, inclusive.
|
||||
**
|
||||
** There are three possible representations of the bitmap.
|
||||
** If iSize<=BITVEC_NBIT, then Bitvec.u.aBitmap[] is a straight
|
||||
** bitmap. The least significant bit is bit 1.
|
||||
**
|
||||
** If iSize>BITVEC_NBIT and iDivisor==0 then Bitvec.u.aHash[] is
|
||||
** a hash table that will hold up to BITVEC_MXHASH distinct values.
|
||||
**
|
||||
** Otherwise, the value i is redirected into one of BITVEC_NPTR
|
||||
** sub-bitmaps pointed to by Bitvec.u.apSub[]. Each subbitmap
|
||||
** handles up to iDivisor separate values of i. apSub[0] holds
|
||||
** values between 1 and iDivisor. apSub[1] holds values between
|
||||
** iDivisor+1 and 2*iDivisor. apSub[N] holds values between
|
||||
** N*iDivisor+1 and (N+1)*iDivisor. Each subbitmap is normalized
|
||||
** to hold deal with values between 1 and iDivisor.
|
||||
*/
|
||||
|
||||
public class _u
|
||||
{
|
||||
public BITVEC_TELEM[] aBitmap = new byte[BITVEC_NELEM]; /* Bitmap representation */
|
||||
public u32[] aHash = new u32[BITVEC_NINT]; /* Hash table representation */
|
||||
public Bitvec[] apSub = new Bitvec[BITVEC_NPTR]; /* Recursive representation */
|
||||
}
|
||||
|
||||
public class Bitvec
|
||||
{
|
||||
public u32 iSize; /* Maximum bit index. Max iSize is 4,294,967,296. */
|
||||
public u32 nSet; /* Number of bits that are set - only valid for aHash
|
||||
** element. Max is BITVEC_NINT. For BITVEC_SZ of 512,
|
||||
** this would be 125. */
|
||||
public u32 iDivisor; /* Number of bits handled by each apSub[] entry. */
|
||||
/* Should >=0 for apSub element. */
|
||||
/* Max iDivisor is max(u32) / BITVEC_NPTR + 1. */
|
||||
/* For a BITVEC_SZ of 512, this would be 34,359,739. */
|
||||
public _u u = new _u();
|
||||
|
||||
public static implicit operator bool(Bitvec b)
|
||||
{
|
||||
return (b != null);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
** Create a new bitmap object able to handle bits between 0 and iSize,
|
||||
** inclusive. Return a pointer to the new object. Return NULL if
|
||||
** malloc fails.
|
||||
*/
|
||||
|
||||
private static Bitvec sqlite3BitvecCreate(u32 iSize)
|
||||
{
|
||||
Bitvec p;
|
||||
//Debug.Assert( sizeof(p)==BITVEC_SZ );
|
||||
p = new Bitvec();//sqlite3MallocZero( sizeof(p) );
|
||||
if (p != null)
|
||||
{
|
||||
p.iSize = iSize;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Check to see if the i-th bit is set. Return true or false.
|
||||
** If p is NULL (if the bitmap has not been created) or if
|
||||
** i is out of range, then return false.
|
||||
*/
|
||||
|
||||
private static int sqlite3BitvecTest(Bitvec p, u32 i)
|
||||
{
|
||||
if (p == null || i == 0)
|
||||
return 0;
|
||||
if (i > p.iSize)
|
||||
return 0;
|
||||
i--;
|
||||
while (p.iDivisor != 0)
|
||||
{
|
||||
u32 bin = i / p.iDivisor;
|
||||
i = i % p.iDivisor;
|
||||
p = p.u.apSub[bin];
|
||||
if (null == p)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (p.iSize <= BITVEC_NBIT)
|
||||
{
|
||||
return ((p.u.aBitmap[i / BITVEC_SZELEM] & (1 << (int)(i & (BITVEC_SZELEM - 1)))) != 0) ? 1 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 h = BITVEC_HASH(i++);
|
||||
while (p.u.aHash[h] != 0)
|
||||
{
|
||||
if (p.u.aHash[h] == i)
|
||||
return 1;
|
||||
h = (h + 1) % BITVEC_NINT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the i-th bit. Return 0 on success and an error code if
|
||||
** anything goes wrong.
|
||||
**
|
||||
** This routine might cause sub-bitmaps to be allocated. Failing
|
||||
** to get the memory needed to hold the sub-bitmap is the only
|
||||
** that can go wrong with an insert, assuming p and i are valid.
|
||||
**
|
||||
** The calling function must ensure that p is a valid Bitvec object
|
||||
** and that the value for "i" is within range of the Bitvec object.
|
||||
** Otherwise the behavior is undefined.
|
||||
*/
|
||||
|
||||
private static int sqlite3BitvecSet(Bitvec p, u32 i)
|
||||
{
|
||||
u32 h;
|
||||
if (p == null)
|
||||
return SQLITE_OK;
|
||||
Debug.Assert(i > 0);
|
||||
Debug.Assert(i <= p.iSize);
|
||||
i--;
|
||||
while ((p.iSize > BITVEC_NBIT) && p.iDivisor != 0)
|
||||
{
|
||||
u32 bin = i / p.iDivisor;
|
||||
i = i % p.iDivisor;
|
||||
if (p.u.apSub[bin] == null)
|
||||
{
|
||||
p.u.apSub[bin] = sqlite3BitvecCreate(p.iDivisor);
|
||||
//if ( p.u.apSub[bin] == null )
|
||||
// return SQLITE_NOMEM;
|
||||
}
|
||||
p = p.u.apSub[bin];
|
||||
}
|
||||
if (p.iSize <= BITVEC_NBIT)
|
||||
{
|
||||
p.u.aBitmap[i / BITVEC_SZELEM] |= (byte)(1 << (int)(i & (BITVEC_SZELEM - 1)));
|
||||
return SQLITE_OK;
|
||||
}
|
||||
h = BITVEC_HASH(i++);
|
||||
/* if there wasn't a hash collision, and this doesn't */
|
||||
/* completely fill the hash, then just add it without */
|
||||
/* worring about sub-dividing and re-hashing. */
|
||||
if (0 == p.u.aHash[h])
|
||||
{
|
||||
if (p.nSet < (BITVEC_NINT - 1))
|
||||
{
|
||||
goto bitvec_set_end;
|
||||
}
|
||||
else
|
||||
{
|
||||
goto bitvec_set_rehash;
|
||||
}
|
||||
}
|
||||
/* there was a collision, check to see if it's already */
|
||||
/* in hash, if not, try to find a spot for it */
|
||||
do
|
||||
{
|
||||
if (p.u.aHash[h] == i)
|
||||
return SQLITE_OK;
|
||||
h++;
|
||||
if (h >= BITVEC_NINT)
|
||||
h = 0;
|
||||
} while (p.u.aHash[h] != 0);
|
||||
/* we didn't find it in the hash. h points to the first */
|
||||
/* available free spot. check to see if this is going to */
|
||||
/* make our hash too "full". */
|
||||
bitvec_set_rehash:
|
||||
if (p.nSet >= BITVEC_MXHASH)
|
||||
{
|
||||
u32 j;
|
||||
int rc;
|
||||
u32[] aiValues = new u32[BITVEC_NINT];// = sqlite3StackAllocRaw(0, sizeof(p->u.aHash));
|
||||
//if ( aiValues == null )
|
||||
//{
|
||||
// return SQLITE_NOMEM;
|
||||
//}
|
||||
//else
|
||||
{
|
||||
Buffer.BlockCopy(p.u.aHash, 0, aiValues, 0, aiValues.Length * (sizeof(u32)));// memcpy(aiValues, p->u.aHash, sizeof(p->u.aHash));
|
||||
p.u.apSub = new Bitvec[BITVEC_NPTR];//memset(p->u.apSub, 0, sizeof(p->u.apSub));
|
||||
p.iDivisor = (u32)((p.iSize + BITVEC_NPTR - 1) / BITVEC_NPTR);
|
||||
rc = sqlite3BitvecSet(p, i);
|
||||
for (j = 0; j < BITVEC_NINT; j++)
|
||||
{
|
||||
if (aiValues[j] != 0)
|
||||
rc |= sqlite3BitvecSet(p, aiValues[j]);
|
||||
}
|
||||
//sqlite3StackFree( null, aiValues );
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
bitvec_set_end:
|
||||
p.nSet++;
|
||||
p.u.aHash[h] = i;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Clear the i-th bit.
|
||||
**
|
||||
** pBuf must be a pointer to at least BITVEC_SZ bytes of temporary storage
|
||||
** that BitvecClear can use to rebuilt its hash table.
|
||||
*/
|
||||
|
||||
private static void sqlite3BitvecClear(Bitvec p, u32 i, u32[] pBuf)
|
||||
{
|
||||
if (p == null)
|
||||
return;
|
||||
Debug.Assert(i > 0);
|
||||
i--;
|
||||
while (p.iDivisor != 0)
|
||||
{
|
||||
u32 bin = i / p.iDivisor;
|
||||
i = i % p.iDivisor;
|
||||
p = p.u.apSub[bin];
|
||||
if (null == p)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (p.iSize <= BITVEC_NBIT)
|
||||
{
|
||||
p.u.aBitmap[i / BITVEC_SZELEM] &= (byte)~((1 << (int)(i & (BITVEC_SZELEM - 1))));
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 j;
|
||||
u32[] aiValues = pBuf;
|
||||
Array.Copy(p.u.aHash, aiValues, p.u.aHash.Length);//memcpy(aiValues, p->u.aHash, sizeof(p->u.aHash));
|
||||
p.u.aHash = new u32[aiValues.Length];// memset(p->u.aHash, 0, sizeof(p->u.aHash));
|
||||
p.nSet = 0;
|
||||
for (j = 0; j < BITVEC_NINT; j++)
|
||||
{
|
||||
if (aiValues[j] != 0 && aiValues[j] != (i + 1))
|
||||
{
|
||||
u32 h = BITVEC_HASH(aiValues[j] - 1);
|
||||
p.nSet++;
|
||||
while (p.u.aHash[h] != 0)
|
||||
{
|
||||
h++;
|
||||
if (h >= BITVEC_NINT)
|
||||
h = 0;
|
||||
}
|
||||
p.u.aHash[h] = aiValues[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Destroy a bitmap object. Reclaim all memory used.
|
||||
*/
|
||||
|
||||
private static void sqlite3BitvecDestroy(ref Bitvec p)
|
||||
{
|
||||
if (p == null)
|
||||
return;
|
||||
if (p.iDivisor != 0)
|
||||
{
|
||||
u32 i;
|
||||
for (i = 0; i < BITVEC_NPTR; i++)
|
||||
{
|
||||
sqlite3BitvecDestroy(ref p.u.apSub[i]);
|
||||
}
|
||||
}
|
||||
//sqlite3_free( ref p );
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the value of the iSize parameter specified when Bitvec *p
|
||||
** was created.
|
||||
*/
|
||||
|
||||
private static u32 sqlite3BitvecSize(Bitvec p)
|
||||
{
|
||||
return p.iSize;
|
||||
}
|
||||
|
||||
#if !SQLITE_OMIT_BUILTIN_TEST
|
||||
/*
|
||||
** Let V[] be an array of unsigned characters sufficient to hold
|
||||
** up to N bits. Let I be an integer between 0 and N. 0<=I<N.
|
||||
** Then the following macros can be used to set, clear, or test
|
||||
** individual bits within V.
|
||||
*/
|
||||
|
||||
//#define SETBIT(V,I) V[I>>3] |= (1<<(I&7))
|
||||
private static void SETBIT(byte[] V, int I)
|
||||
{
|
||||
V[I >> 3] |= (byte)(1 << (I & 7));
|
||||
}
|
||||
|
||||
//#define CLEARBIT(V,I) V[I>>3] &= ~(1<<(I&7))
|
||||
private static void CLEARBIT(byte[] V, int I)
|
||||
{
|
||||
V[I >> 3] &= (byte)~(1 << (I & 7));
|
||||
}
|
||||
|
||||
//#define TESTBIT(V,I) (V[I>>3]&(1<<(I&7)))!=0
|
||||
private static int TESTBIT(byte[] V, int I)
|
||||
{
|
||||
return (V[I >> 3] & (1 << (I & 7))) != 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine runs an extensive test of the Bitvec code.
|
||||
**
|
||||
** The input is an array of integers that acts as a program
|
||||
** to test the Bitvec. The integers are opcodes followed
|
||||
** by 0, 1, or 3 operands, depending on the opcode. Another
|
||||
** opcode follows immediately after the last operand.
|
||||
**
|
||||
** There are 6 opcodes numbered from 0 through 5. 0 is the
|
||||
** "halt" opcode and causes the test to end.
|
||||
**
|
||||
** 0 Halt and return the number of errors
|
||||
** 1 N S X Set N bits beginning with S and incrementing by X
|
||||
** 2 N S X Clear N bits beginning with S and incrementing by X
|
||||
** 3 N Set N randomly chosen bits
|
||||
** 4 N Clear N randomly chosen bits
|
||||
** 5 N S X Set N bits from S increment X in array only, not in bitvec
|
||||
**
|
||||
** The opcodes 1 through 4 perform set and clear operations are performed
|
||||
** on both a Bitvec object and on a linear array of bits obtained from malloc.
|
||||
** Opcode 5 works on the linear array only, not on the Bitvec.
|
||||
** Opcode 5 is used to deliberately induce a fault in order to
|
||||
** confirm that error detection works.
|
||||
**
|
||||
** At the conclusion of the test the linear array is compared
|
||||
** against the Bitvec object. If there are any differences,
|
||||
** an error is returned. If they are the same, zero is returned.
|
||||
**
|
||||
** If a memory allocation error occurs, return -1.
|
||||
*/
|
||||
|
||||
private static int sqlite3BitvecBuiltinTest(u32 sz, int[] aOp)
|
||||
{
|
||||
Bitvec pBitvec = null;
|
||||
byte[] pV = null;
|
||||
int rc = -1;
|
||||
int i, nx, pc, op;
|
||||
u32[] pTmpSpace;
|
||||
|
||||
/* Allocate the Bitvec to be tested and a linear array of
|
||||
** bits to act as the reference */
|
||||
pBitvec = sqlite3BitvecCreate(sz);
|
||||
pV = sqlite3_malloc((int)(sz + 7) / 8 + 1);
|
||||
pTmpSpace = new u32[BITVEC_SZ];// sqlite3_malloc( BITVEC_SZ );
|
||||
if (pBitvec == null || pV == null || pTmpSpace == null)
|
||||
goto bitvec_end;
|
||||
Array.Clear(pV, 0, (int)(sz + 7) / 8 + 1);// memset( pV, 0, ( sz + 7 ) / 8 + 1 );
|
||||
|
||||
/* NULL pBitvec tests */
|
||||
sqlite3BitvecSet(null, (u32)1);
|
||||
sqlite3BitvecClear(null, 1, pTmpSpace);
|
||||
|
||||
/* Run the program */
|
||||
pc = 0;
|
||||
while ((op = aOp[pc]) != 0)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
case 5:
|
||||
{
|
||||
nx = 4;
|
||||
i = aOp[pc + 2] - 1;
|
||||
aOp[pc + 2] += aOp[pc + 3];
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
case 4:
|
||||
default:
|
||||
{
|
||||
nx = 2;
|
||||
i64 i64Temp = 0;
|
||||
sqlite3_randomness(sizeof(i64), ref i64Temp);
|
||||
i = (int)i64Temp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((--aOp[pc + 1]) > 0)
|
||||
nx = 0;
|
||||
pc += nx;
|
||||
i = (int)((i & 0x7fffffff) % sz);
|
||||
if ((op & 1) != 0)
|
||||
{
|
||||
SETBIT(pV, (i + 1));
|
||||
if (op != 5)
|
||||
{
|
||||
if (sqlite3BitvecSet(pBitvec, (u32)i + 1) != 0)
|
||||
goto bitvec_end;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CLEARBIT(pV, (i + 1));
|
||||
sqlite3BitvecClear(pBitvec, (u32)i + 1, pTmpSpace);
|
||||
}
|
||||
}
|
||||
|
||||
/* Test to make sure the linear array exactly matches the
|
||||
** Bitvec object. Start with the assumption that they do
|
||||
** match (rc==0). Change rc to non-zero if a discrepancy
|
||||
** is found.
|
||||
*/
|
||||
rc = sqlite3BitvecTest(null, 0) + sqlite3BitvecTest(pBitvec, sz + 1)
|
||||
+ sqlite3BitvecTest(pBitvec, 0)
|
||||
+ (int)(sqlite3BitvecSize(pBitvec) - sz);
|
||||
for (i = 1; i <= sz; i++)
|
||||
{
|
||||
if ((TESTBIT(pV, i)) != sqlite3BitvecTest(pBitvec, (u32)i))
|
||||
{
|
||||
rc = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Free allocated structure */
|
||||
bitvec_end:
|
||||
//sqlite3_free( ref pTmpSpace );
|
||||
//sqlite3_free( ref pV );
|
||||
sqlite3BitvecDestroy(ref pBitvec);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif //* SQLITE_OMIT_BUILTIN_TEST */
|
||||
}
|
||||
}
|
||||
298
original/Community.CsharpSqlite/src/btmutex_c.cs
Normal file
298
original/Community.CsharpSqlite/src/btmutex_c.cs
Normal file
|
|
@ -0,0 +1,298 @@
|
|||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2007 August 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 code used to implement mutexes on Btree objects.
|
||||
** This code really belongs in btree.c. But btree.c is getting too
|
||||
** big and we want to break it down some. This packaged seemed like
|
||||
** a good breakout.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2011-05-19 13:26:54 ed1da510a239ea767a01dc332b667119fa3c908e
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#include "btreeInt.h"
|
||||
#if !SQLITE_OMIT_SHARED_CACHE
|
||||
#if SQLITE_THREADSAFE
|
||||
|
||||
/*
|
||||
** Obtain the BtShared mutex associated with B-Tree handle p. Also,
|
||||
** set BtShared.db to the database handle associated with p and the
|
||||
** p->locked boolean to true.
|
||||
*/
|
||||
static void lockBtreeMutex(Btree *p){
|
||||
assert( p->locked==0 );
|
||||
assert( sqlite3_mutex_notheld(p->pBt->mutex) );
|
||||
assert( sqlite3_mutex_held(p->db->mutex) );
|
||||
|
||||
sqlite3_mutex_enter(p->pBt->mutex);
|
||||
p->pBt->db = p->db;
|
||||
p->locked = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Release the BtShared mutex associated with B-Tree handle p and
|
||||
** clear the p->locked boolean.
|
||||
*/
|
||||
static void unlockBtreeMutex(Btree *p){
|
||||
BtShared *pBt = p->pBt;
|
||||
assert( p->locked==1 );
|
||||
assert( sqlite3_mutex_held(pBt->mutex) );
|
||||
assert( sqlite3_mutex_held(p->db->mutex) );
|
||||
assert( p->db==pBt->db );
|
||||
|
||||
sqlite3_mutex_leave(pBt->mutex);
|
||||
p->locked = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Enter a mutex on the given BTree object.
|
||||
**
|
||||
** If the object is not sharable, then no mutex is ever required
|
||||
** and this routine is a no-op. The underlying mutex is non-recursive.
|
||||
** But we keep a reference count in Btree.wantToLock so the behavior
|
||||
** of this interface is recursive.
|
||||
**
|
||||
** To avoid deadlocks, multiple Btrees are locked in the same order
|
||||
** by all database connections. The p->pNext is a list of other
|
||||
** Btrees belonging to the same database connection as the p Btree
|
||||
** which need to be locked after p. If we cannot get a lock on
|
||||
** p, then first unlock all of the others on p->pNext, then wait
|
||||
** for the lock to become available on p, then relock all of the
|
||||
** subsequent Btrees that desire a lock.
|
||||
*/
|
||||
void sqlite3BtreeEnter(Btree *p){
|
||||
Btree *pLater;
|
||||
|
||||
/* Some basic sanity checking on the Btree. The list of Btrees
|
||||
** connected by pNext and pPrev should be in sorted order by
|
||||
** Btree.pBt value. All elements of the list should belong to
|
||||
** the same connection. Only shared Btrees are on the list. */
|
||||
assert( p->pNext==0 || p->pNext->pBt>p->pBt );
|
||||
assert( p->pPrev==0 || p->pPrev->pBt<p->pBt );
|
||||
assert( p->pNext==0 || p->pNext->db==p->db );
|
||||
assert( p->pPrev==0 || p->pPrev->db==p->db );
|
||||
assert( p->sharable || (p->pNext==0 && p->pPrev==0) );
|
||||
|
||||
/* Check for locking consistency */
|
||||
assert( !p->locked || p->wantToLock>0 );
|
||||
assert( p->sharable || p->wantToLock==0 );
|
||||
|
||||
/* We should already hold a lock on the database connection */
|
||||
assert( sqlite3_mutex_held(p->db->mutex) );
|
||||
|
||||
/* Unless the database is sharable and unlocked, then BtShared.db
|
||||
** should already be set correctly. */
|
||||
assert( (p->locked==0 && p->sharable) || p->pBt->db==p->db );
|
||||
|
||||
if( !p->sharable ) return;
|
||||
p->wantToLock++;
|
||||
if( p->locked ) return;
|
||||
|
||||
/* In most cases, we should be able to acquire the lock we
|
||||
** want without having to go throught the ascending lock
|
||||
** procedure that follows. Just be sure not to block.
|
||||
*/
|
||||
if( sqlite3_mutex_try(p->pBt->mutex)==SQLITE_OK ){
|
||||
p->pBt->db = p->db;
|
||||
p->locked = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* To avoid deadlock, first release all locks with a larger
|
||||
** BtShared address. Then acquire our lock. Then reacquire
|
||||
** the other BtShared locks that we used to hold in ascending
|
||||
** order.
|
||||
*/
|
||||
for(pLater=p->pNext; pLater; pLater=pLater->pNext){
|
||||
assert( pLater->sharable );
|
||||
assert( pLater->pNext==0 || pLater->pNext->pBt>pLater->pBt );
|
||||
assert( !pLater->locked || pLater->wantToLock>0 );
|
||||
if( pLater->locked ){
|
||||
unlockBtreeMutex(pLater);
|
||||
}
|
||||
}
|
||||
lockBtreeMutex(p);
|
||||
for(pLater=p->pNext; pLater; pLater=pLater->pNext){
|
||||
if( pLater->wantToLock ){
|
||||
lockBtreeMutex(pLater);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Exit the recursive mutex on a Btree.
|
||||
*/
|
||||
void sqlite3BtreeLeave(Btree *p){
|
||||
if( p->sharable ){
|
||||
assert( p->wantToLock>0 );
|
||||
p->wantToLock--;
|
||||
if( p->wantToLock==0 ){
|
||||
unlockBtreeMutex(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if NDEBUG
|
||||
/*
|
||||
** Return true if the BtShared mutex is held on the btree, or if the
|
||||
** B-Tree is not marked as sharable.
|
||||
**
|
||||
** This routine is used only from within assert() statements.
|
||||
*/
|
||||
int sqlite3BtreeHoldsMutex(Btree *p){
|
||||
assert( p->sharable==0 || p->locked==0 || p->wantToLock>0 );
|
||||
assert( p->sharable==0 || p->locked==0 || p->db==p->pBt->db );
|
||||
assert( p->sharable==0 || p->locked==0 || sqlite3_mutex_held(p->pBt->mutex) );
|
||||
assert( p->sharable==0 || p->locked==0 || sqlite3_mutex_held(p->db->mutex) );
|
||||
|
||||
return (p->sharable==0 || p->locked);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SQLITE_OMIT_INCRBLOB
|
||||
/*
|
||||
** Enter and leave a mutex on a Btree given a cursor owned by that
|
||||
** Btree. These entry points are used by incremental I/O and can be
|
||||
** omitted if that module is not used.
|
||||
*/
|
||||
void sqlite3BtreeEnterCursor(BtCursor *pCur){
|
||||
sqlite3BtreeEnter(pCur->pBtree);
|
||||
}
|
||||
void sqlite3BtreeLeaveCursor(BtCursor *pCur){
|
||||
sqlite3BtreeLeave(pCur->pBtree);
|
||||
}
|
||||
#endif //* SQLITE_OMIT_INCRBLOB */
|
||||
|
||||
/*
|
||||
** Enter the mutex on every Btree associated with a database
|
||||
** connection. This is needed (for example) prior to parsing
|
||||
** a statement since we will be comparing table and column names
|
||||
** against all schemas and we do not want those schemas being
|
||||
** reset out from under us.
|
||||
**
|
||||
** There is a corresponding leave-all procedures.
|
||||
**
|
||||
** Enter the mutexes in accending order by BtShared pointer address
|
||||
** to avoid the possibility of deadlock when two threads with
|
||||
** two or more btrees in common both try to lock all their btrees
|
||||
** at the same instant.
|
||||
*/
|
||||
void sqlite3BtreeEnterAll(sqlite3 db){
|
||||
int i;
|
||||
Btree *p;
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
for(i=0; i<db->nDb; i++){
|
||||
p = db->aDb[i].pBt;
|
||||
if( p ) sqlite3BtreeEnter(p);
|
||||
}
|
||||
}
|
||||
void sqlite3BtreeLeaveAll(sqlite3 db){
|
||||
int i;
|
||||
Btree *p;
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
for(i=0; i<db->nDb; i++){
|
||||
p = db->aDb[i].pBt;
|
||||
if( p ) sqlite3BtreeLeave(p);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if a particular Btree requires a lock. Return FALSE if
|
||||
** no lock is ever required since it is not sharable.
|
||||
*/
|
||||
int sqlite3BtreeSharable(Btree *p){
|
||||
return p->sharable;
|
||||
}
|
||||
|
||||
#if NDEBUG
|
||||
/*
|
||||
** Return true if the current thread holds the database connection
|
||||
** mutex and all required BtShared mutexes.
|
||||
**
|
||||
** This routine is used inside assert() statements only.
|
||||
*/
|
||||
int sqlite3BtreeHoldsAllMutexes(sqlite3 db){
|
||||
int i;
|
||||
if( !sqlite3_mutex_held(db->mutex) ){
|
||||
return 0;
|
||||
}
|
||||
for(i=0; i<db->nDb; i++){
|
||||
Btree *p;
|
||||
p = db->aDb[i].pBt;
|
||||
if( p && p->sharable &&
|
||||
(p->wantToLock==0 || !sqlite3_mutex_held(p->pBt->mutex)) ){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif //* NDEBUG */
|
||||
|
||||
#if NDEBUG
|
||||
/*
|
||||
** Return true if the correct mutexes are held for accessing the
|
||||
** db->aDb[iDb].pSchema structure. The mutexes required for schema
|
||||
** access are:
|
||||
**
|
||||
** (1) The mutex on db
|
||||
** (2) if iDb!=1, then the mutex on db->aDb[iDb].pBt.
|
||||
**
|
||||
** If pSchema is not NULL, then iDb is computed from pSchema and
|
||||
** db using sqlite3SchemaToIndex().
|
||||
*/
|
||||
int sqlite3SchemaMutexHeld(sqlite3 db, int iDb, Schema *pSchema){
|
||||
Btree *p;
|
||||
assert( db!=0 );
|
||||
if( pSchema ) iDb = sqlite3SchemaToIndex(db, pSchema);
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
if( !sqlite3_mutex_held(db->mutex) ) return 0;
|
||||
if( iDb==1 ) return 1;
|
||||
p = db->aDb[iDb].pBt;
|
||||
assert( p!=0 );
|
||||
return p->sharable==0 || p->locked==1;
|
||||
}
|
||||
#endif //* NDEBUG */
|
||||
|
||||
#else //* SQLITE_THREADSAFE>0 above. SQLITE_THREADSAFE==0 below */
|
||||
/*
|
||||
** The following are special cases for mutex enter routines for use
|
||||
** in single threaded applications that use shared cache. Except for
|
||||
** these two routines, all mutex operations are no-ops in that case and
|
||||
** are null #defines in btree.h.
|
||||
**
|
||||
** If shared cache is disabled, then all btree mutex routines, including
|
||||
** the ones below, are no-ops and are null #defines in btree.h.
|
||||
*/
|
||||
|
||||
void sqlite3BtreeEnter(Btree *p){
|
||||
p->pBt->db = p->db;
|
||||
}
|
||||
void sqlite3BtreeEnterAll(sqlite3 db){
|
||||
int i;
|
||||
for(i=0; i<db->nDb; i++){
|
||||
Btree *p = db->aDb[i].pBt;
|
||||
if( p ){
|
||||
p->pBt->db = p->db;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif //* if SQLITE_THREADSAFE */
|
||||
#endif //* ifndef SQLITE_OMIT_SHARED_CACHE */
|
||||
}
|
||||
}
|
||||
9709
original/Community.CsharpSqlite/src/btree_c.cs
Normal file
9709
original/Community.CsharpSqlite/src/btree_c.cs
Normal file
File diff suppressed because it is too large
Load diff
4511
original/Community.CsharpSqlite/src/build_c.cs
Normal file
4511
original/Community.CsharpSqlite/src/build_c.cs
Normal file
File diff suppressed because it is too large
Load diff
560
original/Community.CsharpSqlite/src/callback_c.cs
Normal file
560
original/Community.CsharpSqlite/src/callback_c.cs
Normal file
|
|
@ -0,0 +1,560 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using i16 = System.Int16;
|
||||
using u16 = System.UInt16;
|
||||
using u8 = System.Byte;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2005 May 23
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This file contains functions used to access the internal hash tables
|
||||
** of user defined functions and collation sequences.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2011-05-19 13:26:54 ed1da510a239ea767a01dc332b667119fa3c908e
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
|
||||
//#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** Invoke the 'collation needed' callback to request a collation sequence
|
||||
** in the encoding enc of name zName, length nName.
|
||||
*/
|
||||
|
||||
private static void callCollNeeded(sqlite3 db, int enc, string zName)
|
||||
{
|
||||
Debug.Assert(db.xCollNeeded == null || db.xCollNeeded16 == null);
|
||||
if (db.xCollNeeded != null)
|
||||
{
|
||||
string zExternal = zName;// sqlite3DbStrDup(db, zName);
|
||||
if (zExternal == null)
|
||||
return;
|
||||
db.xCollNeeded(db.pCollNeededArg, db, enc, zExternal);
|
||||
sqlite3DbFree(db, ref zExternal);
|
||||
}
|
||||
#if !SQLITE_OMIT_UTF16
|
||||
if( db.xCollNeeded16!=null ){
|
||||
string zExternal;
|
||||
sqlite3_value pTmp = sqlite3ValueNew(db);
|
||||
sqlite3ValueSetStr(pTmp, -1, zName, SQLITE_UTF8, SQLITE_STATIC);
|
||||
zExternal = sqlite3ValueText(pTmp, SQLITE_UTF16NATIVE);
|
||||
if( zExternal!="" ){
|
||||
db.xCollNeeded16( db.pCollNeededArg, db, db.aDbStatic[0].pSchema.enc, zExternal );//(int)ENC(db), zExternal);
|
||||
}
|
||||
sqlite3ValueFree(ref pTmp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine is called if the collation factory fails to deliver a
|
||||
** collation function in the best encoding but there may be other versions
|
||||
** of this collation function (for other text encodings) available. Use one
|
||||
** of these instead if they exist. Avoid a UTF-8 <. UTF-16 conversion if
|
||||
** possible.
|
||||
*/
|
||||
|
||||
private static int synthCollSeq(sqlite3 db, CollSeq pColl)
|
||||
{
|
||||
CollSeq pColl2;
|
||||
string z = pColl.zName;
|
||||
int i;
|
||||
byte[] aEnc = { SQLITE_UTF16BE, SQLITE_UTF16LE, SQLITE_UTF8 };
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
pColl2 = sqlite3FindCollSeq(db, aEnc[i], z, 0);
|
||||
if (pColl2.xCmp != null)
|
||||
{
|
||||
pColl = pColl2.Copy(); //memcpy(pColl, pColl2, sizeof(CollSeq));
|
||||
pColl.xDel = null; /* Do not copy the destructor */
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is responsible for invoking the collation factory callback
|
||||
** or substituting a collation sequence of a different encoding when the
|
||||
** requested collation sequence is not available in the desired encoding.
|
||||
**
|
||||
** If it is not NULL, then pColl must point to the database native encoding
|
||||
** collation sequence with name zName, length nName.
|
||||
**
|
||||
** The return value is either the collation sequence to be used in database
|
||||
** db for collation type name zName, length nName, or NULL, if no collation
|
||||
** sequence can be found.
|
||||
**
|
||||
** See also: sqlite3LocateCollSeq(), sqlite3FindCollSeq()
|
||||
*/
|
||||
|
||||
private static CollSeq sqlite3GetCollSeq(
|
||||
sqlite3 db, /* The database connection */
|
||||
u8 enc, /* The desired encoding for the collating sequence */
|
||||
CollSeq pColl, /* Collating sequence with native encoding, or NULL */
|
||||
string zName /* Collating sequence name */
|
||||
)
|
||||
{
|
||||
CollSeq p;
|
||||
|
||||
p = pColl;
|
||||
if (p == null)
|
||||
{
|
||||
p = sqlite3FindCollSeq(db, enc, zName, 0);
|
||||
}
|
||||
if (p == null || p.xCmp == null)
|
||||
{
|
||||
/* No collation sequence of this type for this encoding is registered.
|
||||
** Call the collation factory to see if it can supply us with one.
|
||||
*/
|
||||
callCollNeeded(db, enc, zName);
|
||||
p = sqlite3FindCollSeq(db, enc, zName, 0);
|
||||
}
|
||||
if (p != null && p.xCmp == null && synthCollSeq(db, p) != 0)
|
||||
{
|
||||
p = null;
|
||||
}
|
||||
Debug.Assert(p == null || p.xCmp != null);
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine is called on a collation sequence before it is used to
|
||||
** check that it is defined. An undefined collation sequence exists when
|
||||
** a database is loaded that contains references to collation sequences
|
||||
** that have not been defined by sqlite3_create_collation() etc.
|
||||
**
|
||||
** If required, this routine calls the 'collation needed' callback to
|
||||
** request a definition of the collating sequence. If this doesn't work,
|
||||
** an equivalent collating sequence that uses a text encoding different
|
||||
** from the main database is substituted, if one is available.
|
||||
*/
|
||||
|
||||
private static int sqlite3CheckCollSeq(Parse pParse, CollSeq pColl)
|
||||
{
|
||||
if (pColl != null)
|
||||
{
|
||||
string zName = pColl.zName;
|
||||
sqlite3 db = pParse.db;
|
||||
CollSeq p = sqlite3GetCollSeq(db, ENC(db), pColl, zName);
|
||||
if (null == p)
|
||||
{
|
||||
sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName);
|
||||
pParse.nErr++;
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
//
|
||||
//Debug.Assert(p == pColl);
|
||||
if (p != pColl) // Had to lookup appropriate sequence
|
||||
{
|
||||
pColl.enc = p.enc;
|
||||
pColl.pUser = p.pUser;
|
||||
pColl.type = p.type;
|
||||
pColl.xCmp = p.xCmp;
|
||||
pColl.xDel = p.xDel;
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Locate and return an entry from the db.aCollSeq hash table. If the entry
|
||||
** specified by zName and nName is not found and parameter 'create' is
|
||||
** true, then create a new entry. Otherwise return NULL.
|
||||
**
|
||||
** Each pointer stored in the sqlite3.aCollSeq hash table contains an
|
||||
** array of three CollSeq structures. The first is the collation sequence
|
||||
** prefferred for UTF-8, the second UTF-16le, and the third UTF-16be.
|
||||
**
|
||||
** Stored immediately after the three collation sequences is a copy of
|
||||
** the collation sequence name. A pointer to this string is stored in
|
||||
** each collation sequence structure.
|
||||
*/
|
||||
|
||||
private static CollSeq[] findCollSeqEntry(
|
||||
sqlite3 db, /* Database connection */
|
||||
string zName, /* Name of the collating sequence */
|
||||
int create /* Create a new entry if true */
|
||||
)
|
||||
{
|
||||
CollSeq[] pColl;
|
||||
int nName = sqlite3Strlen30(zName);
|
||||
pColl = sqlite3HashFind(db.aCollSeq, zName, nName, (CollSeq[])null);
|
||||
|
||||
if ((null == pColl) && create != 0)
|
||||
{
|
||||
pColl = new CollSeq[3]; //sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName + 1 );
|
||||
if (pColl != null)
|
||||
{
|
||||
CollSeq pDel = null;
|
||||
pColl[0] = new CollSeq();
|
||||
pColl[0].zName = zName;
|
||||
pColl[0].enc = SQLITE_UTF8;
|
||||
pColl[1] = new CollSeq();
|
||||
pColl[1].zName = zName;
|
||||
pColl[1].enc = SQLITE_UTF16LE;
|
||||
pColl[2] = new CollSeq();
|
||||
pColl[2].zName = zName;
|
||||
pColl[2].enc = SQLITE_UTF16BE;
|
||||
//memcpy(pColl[0].zName, zName, nName);
|
||||
//pColl[0].zName[nName] = 0;
|
||||
CollSeq[] pDelArray = sqlite3HashInsert(ref db.aCollSeq, pColl[0].zName, nName, pColl);
|
||||
if (pDelArray != null)
|
||||
pDel = pDelArray[0];
|
||||
/* If a malloc() failure occurred in sqlite3HashInsert(), it will
|
||||
** return the pColl pointer to be deleted (because it wasn't added
|
||||
** to the hash table).
|
||||
*/
|
||||
Debug.Assert(pDel == null || pDel == pColl[0]);
|
||||
if (pDel != null)
|
||||
{
|
||||
//// db.mallocFailed = 1;
|
||||
pDel = null; //was sqlite3DbFree(db,ref pDel);
|
||||
pColl = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return pColl;
|
||||
}
|
||||
|
||||
/*
|
||||
** Parameter zName points to a UTF-8 encoded string nName bytes long.
|
||||
** Return the CollSeq* pointer for the collation sequence named zName
|
||||
** for the encoding 'enc' from the database 'db'.
|
||||
**
|
||||
** If the entry specified is not found and 'create' is true, then create a
|
||||
** new entry. Otherwise return NULL.
|
||||
**
|
||||
** A separate function sqlite3LocateCollSeq() is a wrapper around
|
||||
** this routine. sqlite3LocateCollSeq() invokes the collation factory
|
||||
** if necessary and generates an error message if the collating sequence
|
||||
** cannot be found.
|
||||
**
|
||||
** See also: sqlite3LocateCollSeq(), sqlite3GetCollSeq()
|
||||
*/
|
||||
|
||||
private static CollSeq sqlite3FindCollSeq(
|
||||
sqlite3 db,
|
||||
u8 enc,
|
||||
string zName,
|
||||
u8 create
|
||||
)
|
||||
{
|
||||
CollSeq[] pColl;
|
||||
if (zName != null)
|
||||
{
|
||||
pColl = findCollSeqEntry(db, zName, create);
|
||||
}
|
||||
else
|
||||
{
|
||||
pColl = new CollSeq[enc];
|
||||
pColl[enc - 1] = db.pDfltColl;
|
||||
}
|
||||
Debug.Assert(SQLITE_UTF8 == 1 && SQLITE_UTF16LE == 2 && SQLITE_UTF16BE == 3);
|
||||
Debug.Assert(enc >= SQLITE_UTF8 && enc <= SQLITE_UTF16BE);
|
||||
if (pColl != null)
|
||||
{
|
||||
enc -= 1; // if (pColl != null) pColl += enc - 1;
|
||||
return pColl[enc];
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
/* During the search for the best function definition, this procedure
|
||||
** is called to test how well the function passed as the first argument
|
||||
** matches the request for a function with nArg arguments in a system
|
||||
** that uses encoding enc. The value returned indicates how well the
|
||||
** request is matched. A higher value indicates a better match.
|
||||
**
|
||||
** The returned value is always between 0 and 6, as follows:
|
||||
**
|
||||
** 0: Not a match, or if nArg<0 and the function is has no implementation.
|
||||
** 1: A variable arguments function that prefers UTF-8 when a UTF-16
|
||||
** encoding is requested, or vice versa.
|
||||
** 2: A variable arguments function that uses UTF-16BE when UTF-16LE is
|
||||
** requested, or vice versa.
|
||||
** 3: A variable arguments function using the same text encoding.
|
||||
** 4: A function with the exact number of arguments requested that
|
||||
** prefers UTF-8 when a UTF-16 encoding is requested, or vice versa.
|
||||
** 5: A function with the exact number of arguments requested that
|
||||
** prefers UTF-16LE when UTF-16BE is requested, or vice versa.
|
||||
** 6: An exact match.
|
||||
**
|
||||
*/
|
||||
|
||||
private static int matchQuality(FuncDef p, int nArg, int enc)
|
||||
{
|
||||
int match = 0;
|
||||
if (p.nArg == -1 || p.nArg == nArg
|
||||
|| (nArg == -1 && (p.xFunc != null || p.xStep != null))
|
||||
)
|
||||
{
|
||||
match = 1;
|
||||
if (p.nArg == nArg || nArg == -1)
|
||||
{
|
||||
match = 4;
|
||||
}
|
||||
if (enc == p.iPrefEnc)
|
||||
{
|
||||
match += 2;
|
||||
}
|
||||
else if ((enc == SQLITE_UTF16LE && p.iPrefEnc == SQLITE_UTF16BE) ||
|
||||
(enc == SQLITE_UTF16BE && p.iPrefEnc == SQLITE_UTF16LE))
|
||||
{
|
||||
match += 1;
|
||||
}
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
/*
|
||||
** Search a FuncDefHash for a function with the given name. Return
|
||||
** a pointer to the matching FuncDef if found, or 0 if there is no match.
|
||||
*/
|
||||
|
||||
private static FuncDef functionSearch(
|
||||
FuncDefHash pHash, /* Hash table to search */
|
||||
int h, /* Hash of the name */
|
||||
string zFunc, /* Name of function */
|
||||
int nFunc /* Number of bytes in zFunc */
|
||||
)
|
||||
{
|
||||
FuncDef p;
|
||||
for (p = pHash.a[h]; p != null; p = p.pHash)
|
||||
{
|
||||
if (p.zName.Length == nFunc && p.zName.StartsWith(zFunc, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
** Insert a new FuncDef into a FuncDefHash hash table.
|
||||
*/
|
||||
|
||||
private static void sqlite3FuncDefInsert(
|
||||
FuncDefHash pHash, /* The hash table into which to insert */
|
||||
FuncDef pDef /* The function definition to insert */
|
||||
)
|
||||
{
|
||||
FuncDef pOther;
|
||||
int nName = sqlite3Strlen30(pDef.zName);
|
||||
u8 c1 = (u8)pDef.zName[0];
|
||||
int h = (sqlite3UpperToLower[c1] + nName) % ArraySize(pHash.a);
|
||||
pOther = functionSearch(pHash, h, pDef.zName, nName);
|
||||
if (pOther != null)
|
||||
{
|
||||
Debug.Assert(pOther != pDef && pOther.pNext != pDef);
|
||||
pDef.pNext = pOther.pNext;
|
||||
pOther.pNext = pDef;
|
||||
}
|
||||
else
|
||||
{
|
||||
pDef.pNext = null;
|
||||
pDef.pHash = pHash.a[h];
|
||||
pHash.a[h] = pDef;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Locate a user function given a name, a number of arguments and a flag
|
||||
** indicating whether the function prefers UTF-16 over UTF-8. Return a
|
||||
** pointer to the FuncDef structure that defines that function, or return
|
||||
** NULL if the function does not exist.
|
||||
**
|
||||
** If the createFlag argument is true, then a new (blank) FuncDef
|
||||
** structure is created and liked into the "db" structure if a
|
||||
** no matching function previously existed. When createFlag is true
|
||||
** and the nArg parameter is -1, then only a function that accepts
|
||||
** any number of arguments will be returned.
|
||||
**
|
||||
** If createFlag is false and nArg is -1, then the first valid
|
||||
** function found is returned. A function is valid if either xFunc
|
||||
** or xStep is non-zero.
|
||||
**
|
||||
** If createFlag is false, then a function with the required name and
|
||||
** number of arguments may be returned even if the eTextRep flag does not
|
||||
** match that requested.
|
||||
*/
|
||||
|
||||
private static FuncDef sqlite3FindFunction(
|
||||
sqlite3 db, /* An open database */
|
||||
string zName, /* Name of the function. Not null-terminated */
|
||||
int nName, /* Number of characters in the name */
|
||||
int nArg, /* Number of arguments. -1 means any number */
|
||||
u8 enc, /* Preferred text encoding */
|
||||
u8 createFlag /* Create new entry if true and does not otherwise exist */
|
||||
)
|
||||
{
|
||||
FuncDef p; /* Iterator variable */
|
||||
FuncDef pBest = null; /* Best match found so far */
|
||||
int bestScore = 0;
|
||||
int h; /* Hash value */
|
||||
|
||||
Debug.Assert(enc == SQLITE_UTF8 || enc == SQLITE_UTF16LE || enc == SQLITE_UTF16BE);
|
||||
h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % ArraySize(db.aFunc.a);
|
||||
|
||||
/* First search for a match amongst the application-defined functions.
|
||||
*/
|
||||
p = functionSearch(db.aFunc, h, zName, nName);
|
||||
while (p != null)
|
||||
{
|
||||
int score = matchQuality(p, nArg, enc);
|
||||
if (score > bestScore)
|
||||
{
|
||||
pBest = p;
|
||||
bestScore = score;
|
||||
}
|
||||
p = p.pNext;
|
||||
}
|
||||
|
||||
/* If no match is found, search the built-in functions.
|
||||
**
|
||||
** If the SQLITE_PreferBuiltin flag is set, then search the built-in
|
||||
** functions even if a prior app-defined function was found. And give
|
||||
** priority to built-in functions.
|
||||
**
|
||||
** Except, if createFlag is true, that means that we are trying to
|
||||
** install a new function. Whatever FuncDef structure is returned it will
|
||||
** have fields overwritten with new information appropriate for the
|
||||
** new function. But the FuncDefs for built-in functions are read-only.
|
||||
** So we must not search for built-ins when creating a new function.
|
||||
*/
|
||||
if (0 == createFlag && (pBest == null || (db.flags & SQLITE_PreferBuiltin) != 0))
|
||||
{
|
||||
#if SQLITE_OMIT_WSD
|
||||
FuncDefHash pHash = GLOBAL( FuncDefHash, sqlite3GlobalFunctions );
|
||||
#else
|
||||
FuncDefHash pHash = sqlite3GlobalFunctions;
|
||||
#endif
|
||||
bestScore = 0;
|
||||
p = functionSearch(pHash, h, zName, nName);
|
||||
while (p != null)
|
||||
{
|
||||
int score = matchQuality(p, nArg, enc);
|
||||
if (score > bestScore)
|
||||
{
|
||||
pBest = p;
|
||||
bestScore = score;
|
||||
}
|
||||
p = p.pNext;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the createFlag parameter is true and the search did not reveal an
|
||||
** exact match for the name, number of arguments and encoding, then add a
|
||||
** new entry to the hash table and return it.
|
||||
*/
|
||||
if (createFlag != 0 && (bestScore < 6 || pBest.nArg != nArg) &&
|
||||
(pBest = new FuncDef()) != null)
|
||||
{ //sqlite3DbMallocZero(db, sizeof(*pBest)+nName+1))!=0 ){
|
||||
//pBest.zName = (char *)&pBest[1];
|
||||
pBest.nArg = (i16)nArg;
|
||||
pBest.iPrefEnc = enc;
|
||||
pBest.zName = zName; //memcpy(pBest.zName, zName, nName);
|
||||
//pBest.zName[nName] = 0;
|
||||
sqlite3FuncDefInsert(db.aFunc, pBest);
|
||||
}
|
||||
|
||||
if (pBest != null && (pBest.xStep != null || pBest.xFunc != null || createFlag != 0))
|
||||
{
|
||||
return pBest;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
** Free all resources held by the schema structure. The void* argument points
|
||||
** at a Schema struct. This function does not call sqlite3DbFree(db, ) on the
|
||||
** pointer itself, it just cleans up subsidiary resources (i.e. the contents
|
||||
** of the schema hash tables).
|
||||
**
|
||||
** The Schema.cache_size variable is not cleared.
|
||||
*/
|
||||
|
||||
private static void sqlite3SchemaClear(Schema p)
|
||||
{
|
||||
Hash temp1;
|
||||
Hash temp2;
|
||||
HashElem pElem;
|
||||
Schema pSchema = p;
|
||||
|
||||
temp1 = pSchema.tblHash;
|
||||
temp2 = pSchema.trigHash;
|
||||
sqlite3HashInit(pSchema.trigHash);
|
||||
sqlite3HashClear(pSchema.idxHash);
|
||||
for (pElem = sqliteHashFirst(temp2); pElem != null; pElem = sqliteHashNext(pElem))
|
||||
{
|
||||
Trigger pTrigger = (Trigger)sqliteHashData(pElem);
|
||||
sqlite3DeleteTrigger(null, ref pTrigger);
|
||||
}
|
||||
sqlite3HashClear(temp2);
|
||||
sqlite3HashInit(pSchema.trigHash);
|
||||
for (pElem = temp1.first; pElem != null; pElem = pElem.next)//sqliteHashFirst(&temp1); pElem; pElem = sqliteHashNext(pElem))
|
||||
{
|
||||
Table pTab = (Table)pElem.data; //sqliteHashData(pElem);
|
||||
sqlite3DeleteTable(null, ref pTab);
|
||||
}
|
||||
sqlite3HashClear(temp1);
|
||||
sqlite3HashClear(pSchema.fkeyHash);
|
||||
pSchema.pSeqTab = null;
|
||||
if ((pSchema.flags & DB_SchemaLoaded) != 0)
|
||||
{
|
||||
pSchema.iGeneration++;
|
||||
pSchema.flags = (u16)(pSchema.flags & (~DB_SchemaLoaded));
|
||||
}
|
||||
p.Clear();
|
||||
}
|
||||
|
||||
/*
|
||||
** Find and return the schema associated with a BTree. Create
|
||||
** a new one if necessary.
|
||||
*/
|
||||
|
||||
private static Schema sqlite3SchemaGet(sqlite3 db, Btree pBt)
|
||||
{
|
||||
Schema p;
|
||||
if (pBt != null)
|
||||
{
|
||||
p = sqlite3BtreeSchema(pBt, -1, (dxFreeSchema)sqlite3SchemaClear);//Schema.Length, sqlite3SchemaFree);
|
||||
}
|
||||
else
|
||||
{
|
||||
p = new Schema(); // (Schema *)sqlite3DbMallocZero(0, sizeof(Schema));
|
||||
}
|
||||
if (p == null)
|
||||
{
|
||||
//// db.mallocFailed = 1;
|
||||
}
|
||||
else if (0 == p.file_format)
|
||||
{
|
||||
sqlite3HashInit(p.tblHash);
|
||||
sqlite3HashInit(p.idxHash);
|
||||
sqlite3HashInit(p.trigHash);
|
||||
sqlite3HashInit(p.fkeyHash);
|
||||
p.enc = SQLITE_UTF8;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
}
|
||||
}
|
||||
360
original/Community.CsharpSqlite/src/complete_c.cs
Normal file
360
original/Community.CsharpSqlite/src/complete_c.cs
Normal file
|
|
@ -0,0 +1,360 @@
|
|||
namespace Community.CsharpSqlite
|
||||
{
|
||||
using u8 = System.Byte;
|
||||
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** An tokenizer for SQL
|
||||
**
|
||||
** This file contains C code that implements the sqlite3_complete() API.
|
||||
** This code used to be part of the tokenizer.c source file. But by
|
||||
** separating it out, the code will be automatically omitted from
|
||||
** static links that do not use it.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2010-08-23 18:52:01 42537b60566f288167f1b5864a5435986838e3a3
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#include "sqliteInt.h"
|
||||
#if !SQLITE_OMIT_COMPLETE
|
||||
|
||||
/*
|
||||
** This is defined in tokenize.c. We just have to import the definition.
|
||||
*/
|
||||
#if !SQLITE_AMALGAMATION
|
||||
#if SQLITE_ASCII
|
||||
|
||||
//#define IdChar(C) ((sqlite3CtypeMap[(unsigned char)C]&0x46)!=0)
|
||||
private static bool IdChar(u8 C)
|
||||
{
|
||||
return (sqlite3CtypeMap[(char)C] & 0x46) != 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
//#if SQLITE_EBCDIC
|
||||
//extern const char sqlite3IsEbcdicIdChar[];
|
||||
//#define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40]))
|
||||
//#endif
|
||||
#endif // * SQLITE_AMALGAMATION */
|
||||
|
||||
/*
|
||||
** Token types used by the sqlite3_complete() routine. See the header
|
||||
** comments on that procedure for additional information.
|
||||
*/
|
||||
private const int tkSEMI = 0;
|
||||
private const int tkWS = 1;
|
||||
private const int tkOTHER = 2;
|
||||
#if !SQLITE_OMIT_TRIGGER
|
||||
private const int tkEXPLAIN = 3;
|
||||
private const int tkCREATE = 4;
|
||||
private const int tkTEMP = 5;
|
||||
private const int tkTRIGGER = 6;
|
||||
private const int tkEND = 7;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Return TRUE if the given SQL string ends in a semicolon.
|
||||
**
|
||||
** Special handling is require for CREATE TRIGGER statements.
|
||||
** Whenever the CREATE TRIGGER keywords are seen, the statement
|
||||
** must end with ";END;".
|
||||
**
|
||||
** This implementation uses a state machine with 8 states:
|
||||
**
|
||||
** (0) INVALID We have not yet seen a non-whitespace character.
|
||||
**
|
||||
** (1) START At the beginning or end of an SQL statement. This routine
|
||||
** returns 1 if it ends in the START state and 0 if it ends
|
||||
** in any other state.
|
||||
**
|
||||
** (2) NORMAL We are in the middle of statement which ends with a single
|
||||
** semicolon.
|
||||
**
|
||||
** (3) EXPLAIN The keyword EXPLAIN has been seen at the beginning of
|
||||
** a statement.
|
||||
**
|
||||
** (4) CREATE The keyword CREATE has been seen at the beginning of a
|
||||
** statement, possibly preceeded by EXPLAIN and/or followed by
|
||||
** TEMP or TEMPORARY
|
||||
**
|
||||
** (5) TRIGGER We are in the middle of a trigger definition that must be
|
||||
** ended by a semicolon, the keyword END, and another semicolon.
|
||||
**
|
||||
** (6) SEMI We've seen the first semicolon in the ";END;" that occurs at
|
||||
** the end of a trigger definition.
|
||||
**
|
||||
** (7) END We've seen the ";END" of the ";END;" that occurs at the end
|
||||
** of a trigger difinition.
|
||||
**
|
||||
** Transitions between states above are determined by tokens extracted
|
||||
** from the input. The following tokens are significant:
|
||||
**
|
||||
** (0) tkSEMI A semicolon.
|
||||
** (1) tkWS Whitespace.
|
||||
** (2) tkOTHER Any other SQL token.
|
||||
** (3) tkEXPLAIN The "explain" keyword.
|
||||
** (4) tkCREATE The "create" keyword.
|
||||
** (5) tkTEMP The "temp" or "temporary" keyword.
|
||||
** (6) tkTRIGGER The "trigger" keyword.
|
||||
** (7) tkEND The "end" keyword.
|
||||
**
|
||||
** Whitespace never causes a state transition and is always ignored.
|
||||
** This means that a SQL string of all whitespace is invalid.
|
||||
**
|
||||
** If we compile with SQLITE_OMIT_TRIGGER, all of the computation needed
|
||||
** to recognize the end of a trigger can be omitted. All we have to do
|
||||
** is look for a semicolon that is not part of an string or comment.
|
||||
*/
|
||||
|
||||
static public int sqlite3_complete(string zSql)
|
||||
{
|
||||
int state = 0; /* Current state, using numbers defined in header comment */
|
||||
int token; /* Value of the next token */
|
||||
|
||||
#if !SQLITE_OMIT_TRIGGER
|
||||
/* A complex statement machine used to detect the end of a CREATE TRIGGER
|
||||
** statement. This is the normal case.
|
||||
*/
|
||||
u8[][] trans = new u8[][] {
|
||||
/* Token: */
|
||||
/* State: ** SEMI WS OTHER EXPLAIN CREATE TEMP TRIGGER END */
|
||||
/* 0 INVALID: */ new u8[]{ 1, 0, 2, 3, 4, 2, 2, 2, },
|
||||
/* 1 START: */ new u8[]{ 1, 1, 2, 3, 4, 2, 2, 2, },
|
||||
/* 2 NORMAL: */ new u8[]{ 1, 2, 2, 2, 2, 2, 2, 2, },
|
||||
/* 3 EXPLAIN: */ new u8[]{ 1, 3, 3, 2, 4, 2, 2, 2, },
|
||||
/* 4 CREATE: */ new u8[]{ 1, 4, 2, 2, 2, 4, 5, 2, },
|
||||
/* 5 TRIGGER: */ new u8[]{ 6, 5, 5, 5, 5, 5, 5, 5, },
|
||||
/* 6 SEMI: */ new u8[]{ 6, 6, 5, 5, 5, 5, 5, 7, },
|
||||
/* 7 END: */ new u8[]{ 1, 7, 5, 5, 5, 5, 5, 5, },
|
||||
};
|
||||
#else
|
||||
/* If triggers are not supported by this compile then the statement machine
|
||||
** used to detect the end of a statement is much simplier
|
||||
*/
|
||||
u8[][] trans = new u8[][] {
|
||||
/* Token: */
|
||||
/* State: ** SEMI WS OTHER */
|
||||
/* 0 INVALID: */new u8[] { 1, 0, 2, },
|
||||
/* 1 START: */new u8[] { 1, 1, 2, },
|
||||
/* 2 NORMAL: */new u8[] { 1, 2, 2, },
|
||||
};
|
||||
#endif // * SQLITE_OMIT_TRIGGER */
|
||||
|
||||
int zIdx = 0;
|
||||
while (zIdx < zSql.Length)
|
||||
{
|
||||
switch (zSql[zIdx])
|
||||
{
|
||||
case ';':
|
||||
{ /* A semicolon */
|
||||
token = tkSEMI;
|
||||
break;
|
||||
}
|
||||
case ' ':
|
||||
case '\r':
|
||||
case '\t':
|
||||
case '\n':
|
||||
case '\f':
|
||||
{ /* White space is ignored */
|
||||
token = tkWS;
|
||||
break;
|
||||
}
|
||||
case '/':
|
||||
{ /* C-style comments */
|
||||
if (zSql[zIdx + 1] != '*')
|
||||
{
|
||||
token = tkOTHER;
|
||||
break;
|
||||
}
|
||||
zIdx += 2;
|
||||
while (zIdx < zSql.Length && zSql[zIdx] != '*' || zIdx < zSql.Length - 1 && zSql[zIdx + 1] != '/')
|
||||
{
|
||||
zIdx++;
|
||||
}
|
||||
if (zIdx == zSql.Length)
|
||||
return 0;
|
||||
zIdx++;
|
||||
token = tkWS;
|
||||
break;
|
||||
}
|
||||
case '-':
|
||||
{ /* SQL-style comments from "--" to end of line */
|
||||
if (zSql[zIdx + 1] != '-')
|
||||
{
|
||||
token = tkOTHER;
|
||||
break;
|
||||
}
|
||||
while (zIdx < zSql.Length && zSql[zIdx] != '\n')
|
||||
{
|
||||
zIdx++;
|
||||
}
|
||||
if (zIdx == zSql.Length)
|
||||
return state == 1 ? 1 : 0;//if( *zSql==0 ) return state==1;
|
||||
token = tkWS;
|
||||
break;
|
||||
}
|
||||
case '[':
|
||||
{ /* Microsoft-style identifiers in [...] */
|
||||
zIdx++;
|
||||
while (zIdx < zSql.Length && zSql[zIdx] != ']')
|
||||
{
|
||||
zIdx++;
|
||||
}
|
||||
if (zIdx == zSql.Length)
|
||||
return 0;
|
||||
token = tkOTHER;
|
||||
break;
|
||||
}
|
||||
case '`': /* Grave-accent quoted symbols used by MySQL */
|
||||
case '"': /* single- and double-quoted strings */
|
||||
case '\'':
|
||||
{
|
||||
int c = zSql[zIdx];
|
||||
zIdx++;
|
||||
while (zIdx < zSql.Length && zSql[zIdx] != c)
|
||||
{
|
||||
zIdx++;
|
||||
}
|
||||
if (zIdx == zSql.Length)
|
||||
return 0;
|
||||
token = tkOTHER;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
//#if SQLITE_EBCDIC
|
||||
// unsigned char c;
|
||||
//#endif
|
||||
if (IdChar((u8)zSql[zIdx]))
|
||||
{
|
||||
/* Keywords and unquoted identifiers */
|
||||
int nId;
|
||||
for (nId = 1; (zIdx + nId) < zSql.Length && IdChar((u8)zSql[zIdx + nId]); nId++)
|
||||
{
|
||||
}
|
||||
#if SQLITE_OMIT_TRIGGER
|
||||
token = tkOTHER;
|
||||
#else
|
||||
switch (zSql[zIdx])
|
||||
{
|
||||
case 'c':
|
||||
case 'C':
|
||||
{
|
||||
if (nId == 6 && sqlite3StrNICmp(zSql, zIdx, "create", 6) == 0)
|
||||
{
|
||||
token = tkCREATE;
|
||||
}
|
||||
else
|
||||
{
|
||||
token = tkOTHER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 't':
|
||||
case 'T':
|
||||
{
|
||||
if (nId == 7 && sqlite3StrNICmp(zSql, zIdx, "trigger", 7) == 0)
|
||||
{
|
||||
token = tkTRIGGER;
|
||||
}
|
||||
else if (nId == 4 && sqlite3StrNICmp(zSql, zIdx, "temp", 4) == 0)
|
||||
{
|
||||
token = tkTEMP;
|
||||
}
|
||||
else if (nId == 9 && sqlite3StrNICmp(zSql, zIdx, "temporary", 9) == 0)
|
||||
{
|
||||
token = tkTEMP;
|
||||
}
|
||||
else
|
||||
{
|
||||
token = tkOTHER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'e':
|
||||
case 'E':
|
||||
{
|
||||
if (nId == 3 && sqlite3StrNICmp(zSql, zIdx, "end", 3) == 0)
|
||||
{
|
||||
token = tkEND;
|
||||
}
|
||||
else
|
||||
#if !SQLITE_OMIT_EXPLAIN
|
||||
if (nId == 7 && sqlite3StrNICmp(zSql, zIdx, "explain", 7) == 0)
|
||||
{
|
||||
token = tkEXPLAIN;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
token = tkOTHER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
token = tkOTHER;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif // * SQLITE_OMIT_TRIGGER */
|
||||
zIdx += nId - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Operators and special symbols */
|
||||
token = tkOTHER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
state = trans[state][token];
|
||||
zIdx++;
|
||||
}
|
||||
return (state == 1) ? 1 : 0;//return state==1;
|
||||
}
|
||||
|
||||
#if !SQLITE_OMIT_UTF16
|
||||
/*
|
||||
** This routine is the same as the sqlite3_complete() routine described
|
||||
** above, except that the parameter is required to be UTF-16 encoded, not
|
||||
** UTF-8.
|
||||
*/
|
||||
int sqlite3_complete16(const void *zSql){
|
||||
sqlite3_value pVal;
|
||||
char const *zSql8;
|
||||
int rc = SQLITE_NOMEM;
|
||||
|
||||
#if !SQLITE_OMIT_AUTOINIT
|
||||
rc = sqlite3_initialize();
|
||||
if( rc !=0) return rc;
|
||||
#endif
|
||||
pVal = sqlite3ValueNew(0);
|
||||
sqlite3ValueSetStr(pVal, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC);
|
||||
zSql8 = sqlite3ValueText(pVal, SQLITE_UTF8);
|
||||
if( zSql8 ){
|
||||
rc = sqlite3_complete(zSql8);
|
||||
}else{
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
sqlite3ValueFree(pVal);
|
||||
return sqlite3ApiExit(0, rc);
|
||||
}
|
||||
#endif // * SQLITE_OMIT_UTF16 */
|
||||
#endif // * SQLITE_OMIT_COMPLETE */
|
||||
}
|
||||
}
|
||||
775
original/Community.CsharpSqlite/src/crypto.cs
Normal file
775
original/Community.CsharpSqlite/src/crypto.cs
Normal file
|
|
@ -0,0 +1,775 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using Pgno = System.UInt32;
|
||||
using u16 = System.UInt16;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
#if !SQLITE_WINRT
|
||||
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
#endif
|
||||
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2010 Noah B Hart, Diego Torres
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
** SQLCipher
|
||||
** crypto.c developed by Stephen Lombardo (Zetetic LLC)
|
||||
** sjlombardo at zetetic dot net
|
||||
** http://zetetic.net
|
||||
**
|
||||
** Copyright (c) 2009, ZETETIC LLC
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** * Neither the name of the ZETETIC LLC nor the
|
||||
** names of its contributors may be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY ZETETIC LLC ''AS IS'' AND ANY
|
||||
** EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
** DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY
|
||||
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**
|
||||
*/
|
||||
/* BEGIN CRYPTO */
|
||||
#if SQLITE_HAS_CODEC
|
||||
|
||||
//#include <assert.h>
|
||||
//#include <openssl/evp.h>
|
||||
//#include <openssl/rand.h>
|
||||
//#include <openssl/hmac.h>
|
||||
//#include "sqliteInt.h"
|
||||
//#include "btreeInt.h"
|
||||
//#include "crypto.h"
|
||||
|
||||
#if CODEC_DEBUG || TRACE
|
||||
//#define CODEC_TRACE(X) {printf X;fflush(stdout);}
|
||||
static void CODEC_TRACE( string T, params object[] ap ) { if ( sqlite3PagerTrace )sqlite3DebugPrintf( T, ap ); }
|
||||
#else
|
||||
|
||||
//#define CODEC_TRACE(X)
|
||||
private static void CODEC_TRACE(string T, params object[] ap)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//void sqlite3FreeCodecArg(void *pCodecArg);
|
||||
|
||||
public class cipher_ctx
|
||||
{//typedef struct {
|
||||
public string pass;
|
||||
public int pass_sz;
|
||||
public bool derive_key;
|
||||
public byte[] key;
|
||||
public int key_sz;
|
||||
public byte[] iv;
|
||||
public int iv_sz;
|
||||
public ICryptoTransform encryptor;
|
||||
public ICryptoTransform decryptor;
|
||||
|
||||
public cipher_ctx Copy()
|
||||
{
|
||||
cipher_ctx c = new cipher_ctx();
|
||||
c.derive_key = derive_key;
|
||||
c.pass = pass;
|
||||
c.pass_sz = pass_sz;
|
||||
if (key != null)
|
||||
{
|
||||
c.key = new byte[key.Length];
|
||||
key.CopyTo(c.key, 0);
|
||||
}
|
||||
c.key_sz = key_sz;
|
||||
if (iv != null)
|
||||
{
|
||||
c.iv = new byte[iv.Length];
|
||||
iv.CopyTo(c.iv, 0);
|
||||
}
|
||||
c.iv_sz = iv_sz;
|
||||
c.encryptor = encryptor;
|
||||
c.decryptor = decryptor;
|
||||
return c;
|
||||
}
|
||||
|
||||
public void CopyTo(cipher_ctx ct)
|
||||
{
|
||||
ct.derive_key = derive_key;
|
||||
ct.pass = pass;
|
||||
ct.pass_sz = pass_sz;
|
||||
if (key != null)
|
||||
{
|
||||
ct.key = new byte[key.Length];
|
||||
key.CopyTo(ct.key, 0);
|
||||
}
|
||||
ct.key_sz = key_sz;
|
||||
if (iv != null)
|
||||
{
|
||||
ct.iv = new byte[iv.Length];
|
||||
iv.CopyTo(ct.iv, 0);
|
||||
}
|
||||
ct.iv_sz = iv_sz;
|
||||
ct.encryptor = encryptor;
|
||||
ct.decryptor = decryptor;
|
||||
}
|
||||
}
|
||||
|
||||
public class codec_ctx
|
||||
{//typedef struct {
|
||||
public int mode_rekey;
|
||||
public byte[] buffer;
|
||||
public Btree pBt;
|
||||
public cipher_ctx read_ctx;
|
||||
public cipher_ctx write_ctx;
|
||||
|
||||
public codec_ctx Copy()
|
||||
{
|
||||
codec_ctx c = new codec_ctx();
|
||||
c.mode_rekey = mode_rekey;
|
||||
c.buffer = sqlite3MemMalloc(buffer.Length);
|
||||
c.pBt = pBt;
|
||||
if (read_ctx != null)
|
||||
c.read_ctx = read_ctx.Copy();
|
||||
if (write_ctx != null)
|
||||
c.write_ctx = write_ctx.Copy();
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
private const int FILE_HEADER_SZ = 16; //#define FILE_HEADER_SZ 16
|
||||
private const string CIPHER = "aes-256-cbc"; //#define CIPHER "aes-256-cbc"
|
||||
private const int CIPHER_DECRYPT = 0; //#define CIPHER_DECRYPT 0
|
||||
private const int CIPHER_ENCRYPT = 1; //#define CIPHER_ENCRYPT 1
|
||||
|
||||
#if NET_2_0
|
||||
static RijndaelManaged Aes = new RijndaelManaged();
|
||||
#else
|
||||
private static AesManaged Aes = new AesManaged();
|
||||
#endif
|
||||
|
||||
/* BEGIN CRYPTO */
|
||||
|
||||
private static void sqlite3pager_get_codec(Pager pPager, ref codec_ctx ctx)
|
||||
{
|
||||
ctx = pPager.pCodec;
|
||||
}
|
||||
|
||||
private static int sqlite3pager_is_mj_pgno(Pager pPager, Pgno pgno)
|
||||
{
|
||||
return (PAGER_MJ_PGNO(pPager) == pgno) ? 1 : 0;
|
||||
}
|
||||
|
||||
private static sqlite3_file sqlite3Pager_get_fd(Pager pPager)
|
||||
{
|
||||
return (isOpen(pPager.fd)) ? pPager.fd : null;
|
||||
}
|
||||
|
||||
private static void sqlite3pager_sqlite3PagerSetCodec(
|
||||
Pager pPager,
|
||||
dxCodec xCodec,
|
||||
dxCodecSizeChng xCodecSizeChng,
|
||||
dxCodecFree xCodecFree,
|
||||
codec_ctx pCodec
|
||||
)
|
||||
{
|
||||
sqlite3PagerSetCodec(pPager, xCodec, xCodecSizeChng, xCodecFree, pCodec);
|
||||
}
|
||||
|
||||
/* END CRYPTO */
|
||||
|
||||
//static void activate_openssl() {
|
||||
// if(EVP_get_cipherbyname(CIPHER) == null) {
|
||||
// OpenSSL_add_all_algorithms();
|
||||
// }
|
||||
//}
|
||||
|
||||
/**
|
||||
* Free and wipe memory
|
||||
* If ptr is not null memory will be freed.
|
||||
* If sz is greater than zero, the memory will be overwritten with zero before it is freed
|
||||
*/
|
||||
|
||||
private static void codec_free(ref byte[] ptr, int sz)
|
||||
{
|
||||
if (ptr != null)
|
||||
{
|
||||
if (sz > 0)
|
||||
Array.Clear(ptr, 0, sz);//memset( ptr, 0, sz );
|
||||
sqlite3_free(ref ptr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the raw password / key data for a cipher context
|
||||
*
|
||||
* returns SQLITE_OK if assignment was successfull
|
||||
* returns SQLITE_NOMEM if an error occured allocating memory
|
||||
* returns SQLITE_ERROR if the key couldn't be set because the pass was null or size was zero
|
||||
*/
|
||||
|
||||
private static int cipher_ctx_set_pass(cipher_ctx ctx, string zKey, int nKey)
|
||||
{
|
||||
ctx.pass = null; // codec_free( ctx.pass, ctx.pass_sz );
|
||||
ctx.pass_sz = nKey;
|
||||
if (!String.IsNullOrEmpty(zKey) && nKey > 0)
|
||||
{
|
||||
//ctx.pass = sqlite3Malloc(nKey);
|
||||
//if(ctx.pass == null) return SQLITE_NOMEM;
|
||||
ctx.pass = zKey;//memcpy(ctx.pass, zKey, nKey);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a new cipher_ctx struct. This function will allocate memory
|
||||
* for the cipher context and for the key
|
||||
*
|
||||
* returns SQLITE_OK if initialization was successful
|
||||
* returns SQLITE_NOMEM if an error occured allocating memory
|
||||
*/
|
||||
|
||||
private static int cipher_ctx_init(ref cipher_ctx iCtx)
|
||||
{
|
||||
iCtx = new cipher_ctx();
|
||||
//iCtx = sqlite3Malloc( sizeof( cipher_ctx ) );
|
||||
//ctx = *iCtx;
|
||||
//if ( ctx == null ) return SQLITE_NOMEM;
|
||||
//memset( ctx, 0, sizeof( cipher_ctx ) );
|
||||
//ctx.key = sqlite3Malloc( EVP_MAX_KEY_LENGTH );
|
||||
//if ( ctx.key == null ) return SQLITE_NOMEM;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* free and wipe memory associated with a cipher_ctx
|
||||
*/
|
||||
|
||||
private static void cipher_ctx_free(ref cipher_ctx ictx)
|
||||
{
|
||||
cipher_ctx ctx = ictx;
|
||||
CODEC_TRACE("cipher_ctx_free: entered ictx=%d\n", ictx);
|
||||
ctx.pass = null;//codec_free(ctx.pass, ctx.pass_sz);
|
||||
if (ctx.key != null)
|
||||
Array.Clear(ctx.key, 0, ctx.key.Length);//codec_free(ctx.key, ctx.key_sz);
|
||||
if (ctx.iv != null)
|
||||
Array.Clear(ctx.iv, 0, ctx.iv.Length);
|
||||
ictx = new cipher_ctx();// codec_free( ref ctx, sizeof( cipher_ctx ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy one cipher_ctx to another. For instance, assuming that read_ctx is a
|
||||
* fully initialized context, you could copy it to write_ctx and all yet data
|
||||
* and pass information across
|
||||
*
|
||||
* returns SQLITE_OK if initialization was successful
|
||||
* returns SQLITE_NOMEM if an error occured allocating memory
|
||||
*/
|
||||
|
||||
private static int cipher_ctx_copy(cipher_ctx target, cipher_ctx source)
|
||||
{
|
||||
//byte[] key = target.key;
|
||||
CODEC_TRACE("cipher_ctx_copy: entered target=%d, source=%d\n", target, source);
|
||||
//codec_free(target.pass, target.pass_sz);
|
||||
source.CopyTo(target);//memcpy(target, source, sizeof(cipher_ctx);
|
||||
|
||||
//target.key = key; //restore pointer to previously allocated key data
|
||||
//memcpy(target.key, source.key, EVP_MAX_KEY_LENGTH);
|
||||
//target.pass = sqlite3Malloc(source.pass_sz);
|
||||
//if(target.pass == null) return SQLITE_NOMEM;
|
||||
//memcpy(target.pass, source.pass, source.pass_sz);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare one cipher_ctx to another.
|
||||
*
|
||||
* returns 0 if all the parameters (except the derived key data) are the same
|
||||
* returns 1 otherwise
|
||||
*/
|
||||
|
||||
private static int cipher_ctx_cmp(cipher_ctx c1, cipher_ctx c2)
|
||||
{
|
||||
CODEC_TRACE("cipher_ctx_cmp: entered c1=%d c2=%d\n", c1, c2);
|
||||
|
||||
if (c1.key_sz == c2.key_sz
|
||||
&& c1.pass_sz == c2.pass_sz
|
||||
&& c1.pass == c2.pass
|
||||
)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free and wipe memory associated with a cipher_ctx, including the allocated
|
||||
* read_ctx and write_ctx.
|
||||
*/
|
||||
|
||||
private static void codec_ctx_free(ref codec_ctx iCtx)
|
||||
{
|
||||
codec_ctx ctx = iCtx;
|
||||
CODEC_TRACE("codec_ctx_free: entered iCtx=%d\n", iCtx);
|
||||
cipher_ctx_free(ref ctx.read_ctx);
|
||||
cipher_ctx_free(ref ctx.write_ctx);
|
||||
iCtx = new codec_ctx();//codec_free(ctx, sizeof(codec_ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive an encryption key for a cipher contex key based on the raw password.
|
||||
*
|
||||
* If the raw key data is formated as x'hex' and there are exactly enough hex chars to fill
|
||||
* the key space (i.e 64 hex chars for a 256 bit key) then the key data will be used directly.
|
||||
*
|
||||
* Otherwise, a key data will be derived using PBKDF2
|
||||
*
|
||||
* returns SQLITE_OK if initialization was successful
|
||||
* returns SQLITE_NOMEM if the key could't be derived (for instance if pass is null or pass_sz is 0)
|
||||
*/
|
||||
|
||||
private static int codec_key_derive(codec_ctx ctx, cipher_ctx c_ctx)
|
||||
{
|
||||
CODEC_TRACE("codec_key_derive: entered c_ctx.pass=%s, c_ctx.pass_sz=%d ctx.iv=%d ctx.iv_sz=%d c_ctx.kdf_iter=%d c_ctx.key_sz=%d\n",
|
||||
c_ctx.pass, c_ctx.pass_sz, c_ctx.iv, c_ctx.iv_sz, c_ctx.key_sz);
|
||||
|
||||
if (c_ctx.pass != null && c_ctx.pass_sz > 0)
|
||||
{ // if pass is not null
|
||||
if ((c_ctx.pass_sz == (c_ctx.key_sz * 2) + 3) && c_ctx.pass.StartsWith("x'", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
int n = c_ctx.pass_sz - 3; /* adjust for leading x' and tailing ' */
|
||||
string z = c_ctx.pass.Substring(2);// + 2; /* adjust lead offset of x' */
|
||||
CODEC_TRACE("codec_key_derive: deriving key from hex\n");
|
||||
c_ctx.key = sqlite3HexToBlob(null, z, n);
|
||||
}
|
||||
else
|
||||
{
|
||||
CODEC_TRACE("codec_key_derive: deriving key using AES256\n");
|
||||
|
||||
Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes(c_ctx.pass, c_ctx.iv, 2010);
|
||||
c_ctx.key_sz = 32;
|
||||
c_ctx.key = k1.GetBytes(c_ctx.key_sz);
|
||||
}
|
||||
#if NET_2_0
|
||||
Aes.BlockSize = 0x80;
|
||||
Aes.FeedbackSize = 8;
|
||||
Aes.KeySize = 0x100;
|
||||
Aes.Mode = CipherMode.CBC;
|
||||
#endif
|
||||
c_ctx.encryptor = Aes.CreateEncryptor(c_ctx.key, c_ctx.iv);
|
||||
c_ctx.decryptor = Aes.CreateDecryptor(c_ctx.key, c_ctx.iv);
|
||||
return SQLITE_OK;
|
||||
};
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* ctx - codec context
|
||||
* pgno - page number in database
|
||||
* size - size in bytes of input and output buffers
|
||||
* mode - 1 to encrypt, 0 to decrypt
|
||||
* in - pointer to input bytes
|
||||
* out - pouter to output bytes
|
||||
*/
|
||||
|
||||
private static int codec_cipher(cipher_ctx ctx, Pgno pgno, int mode, int size, byte[] bIn, byte[] bOut)
|
||||
{
|
||||
int iv;
|
||||
int tmp_csz, csz;
|
||||
|
||||
CODEC_TRACE("codec_cipher:entered pgno=%d, mode=%d, size=%d\n", pgno, mode, size);
|
||||
|
||||
/* just copy raw data from in to out when key size is 0
|
||||
* i.e. during a rekey of a plaintext database */
|
||||
if (ctx.key_sz == 0)
|
||||
{
|
||||
Array.Copy(bIn, bOut, bIn.Length);//memcpy(out, in, size);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
MemoryStream dataStream = new MemoryStream();
|
||||
CryptoStream encryptionStream;
|
||||
if (mode == CIPHER_ENCRYPT)
|
||||
{
|
||||
encryptionStream = new CryptoStream(dataStream, ctx.encryptor, CryptoStreamMode.Write);
|
||||
}
|
||||
else
|
||||
{
|
||||
encryptionStream = new CryptoStream(dataStream, ctx.decryptor, CryptoStreamMode.Write);
|
||||
}
|
||||
encryptionStream.Write(bIn, 0, size);
|
||||
encryptionStream.FlushFinalBlock();
|
||||
dataStream.Position = 0;
|
||||
|
||||
dataStream.Read(bOut, 0, (int)dataStream.Length);
|
||||
encryptionStream.Close();
|
||||
dataStream.Close();
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* when for_ctx == 0 then it will change for read
|
||||
* when for_ctx == 1 then it will change for write
|
||||
* when for_ctx == 2 then it will change for both
|
||||
*/
|
||||
|
||||
private static int codec_set_cipher_name(sqlite3 db, int nDb, string cipher_name, int for_ctx)
|
||||
{
|
||||
Db pDb = db.aDb[nDb];
|
||||
CODEC_TRACE("codec_set_cipher_name: entered db=%d nDb=%d cipher_name=%s for_ctx=%d\n", db, nDb, cipher_name, for_ctx);
|
||||
|
||||
if (pDb.pBt != null)
|
||||
{
|
||||
codec_ctx ctx = null;
|
||||
cipher_ctx c_ctx;
|
||||
sqlite3pager_get_codec(pDb.pBt.pBt.pPager, ref ctx);
|
||||
c_ctx = for_ctx != 0 ? ctx.write_ctx : ctx.read_ctx;
|
||||
|
||||
c_ctx.derive_key = true;
|
||||
|
||||
if (for_ctx == 2)
|
||||
cipher_ctx_copy(for_ctx != 0 ? ctx.read_ctx : ctx.write_ctx, c_ctx);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
private static int codec_set_pass_key(sqlite3 db, int nDb, string zKey, int nKey, int for_ctx)
|
||||
{
|
||||
Db pDb = db.aDb[nDb];
|
||||
CODEC_TRACE("codec_set_pass_key: entered db=%d nDb=%d cipher_name=%s nKey=%d for_ctx=%d\n", db, nDb, zKey, nKey, for_ctx);
|
||||
if (pDb.pBt != null)
|
||||
{
|
||||
codec_ctx ctx = null;
|
||||
cipher_ctx c_ctx;
|
||||
sqlite3pager_get_codec(pDb.pBt.pBt.pPager, ref ctx);
|
||||
c_ctx = for_ctx != 0 ? ctx.write_ctx : ctx.read_ctx;
|
||||
|
||||
cipher_ctx_set_pass(c_ctx, zKey, nKey);
|
||||
c_ctx.derive_key = true;
|
||||
|
||||
if (for_ctx == 2)
|
||||
cipher_ctx_copy(for_ctx != 0 ? ctx.read_ctx : ctx.write_ctx, c_ctx);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* sqlite3Codec can be called in multiple modes.
|
||||
* encrypt mode - expected to return a pointer to the
|
||||
* encrypted data without altering pData.
|
||||
* decrypt mode - expected to return a pointer to pData, with
|
||||
* the data decrypted in the input buffer
|
||||
*/
|
||||
|
||||
private static byte[] sqlite3Codec(codec_ctx iCtx, byte[] data, Pgno pgno, int mode)
|
||||
{
|
||||
codec_ctx ctx = (codec_ctx)iCtx;
|
||||
int pg_sz = sqlite3BtreeGetPageSize(ctx.pBt);
|
||||
int offset = 0;
|
||||
byte[] pData = data;
|
||||
|
||||
CODEC_TRACE("sqlite3Codec: entered pgno=%d, mode=%d, ctx.mode_rekey=%d, pg_sz=%d\n", pgno, mode, ctx.mode_rekey, pg_sz);
|
||||
|
||||
/* derive key on first use if necessary */
|
||||
if (ctx.read_ctx.derive_key)
|
||||
{
|
||||
codec_key_derive(ctx, ctx.read_ctx);
|
||||
ctx.read_ctx.derive_key = false;
|
||||
}
|
||||
|
||||
if (ctx.write_ctx.derive_key)
|
||||
{
|
||||
if (cipher_ctx_cmp(ctx.write_ctx, ctx.read_ctx) == 0)
|
||||
{
|
||||
cipher_ctx_copy(ctx.write_ctx, ctx.read_ctx); // the relevant parameters are the same, just copy read key
|
||||
}
|
||||
else
|
||||
{
|
||||
codec_key_derive(ctx, ctx.write_ctx);
|
||||
ctx.write_ctx.derive_key = false;
|
||||
}
|
||||
}
|
||||
|
||||
CODEC_TRACE("sqlite3Codec: switch mode=%d offset=%d\n", mode, offset);
|
||||
if (ctx.buffer.Length != pg_sz)
|
||||
ctx.buffer = sqlite3MemMalloc(pg_sz);
|
||||
switch (mode)
|
||||
{
|
||||
case SQLITE_DECRYPT:
|
||||
codec_cipher(ctx.read_ctx, pgno, CIPHER_DECRYPT, pg_sz, pData, ctx.buffer);
|
||||
if (pgno == 1)
|
||||
Buffer.BlockCopy(Encoding.UTF8.GetBytes(SQLITE_FILE_HEADER), 0, ctx.buffer, 0, FILE_HEADER_SZ);// memcpy( ctx.buffer, SQLITE_FILE_HEADER, FILE_HEADER_SZ ); /* copy file header to the first 16 bytes of the page */
|
||||
Buffer.BlockCopy(ctx.buffer, 0, pData, 0, pg_sz); //memcpy( pData, ctx.buffer, pg_sz ); /* copy buffer data back to pData and return */
|
||||
return pData;
|
||||
|
||||
case SQLITE_ENCRYPT_WRITE_CTX: /* encrypt */
|
||||
if (pgno == 1)
|
||||
Buffer.BlockCopy(ctx.write_ctx.iv, 0, ctx.buffer, 0, FILE_HEADER_SZ);//memcpy( ctx.buffer, ctx.iv, FILE_HEADER_SZ ); /* copy salt to output buffer */
|
||||
codec_cipher(ctx.write_ctx, pgno, CIPHER_ENCRYPT, pg_sz, pData, ctx.buffer);
|
||||
return ctx.buffer; /* return persistent buffer data, pData remains intact */
|
||||
case SQLITE_ENCRYPT_READ_CTX:
|
||||
if (pgno == 1)
|
||||
Buffer.BlockCopy(ctx.read_ctx.iv, 0, ctx.buffer, 0, FILE_HEADER_SZ);//memcpy( ctx.buffer, ctx.iv, FILE_HEADER_SZ ); /* copy salt to output buffer */
|
||||
codec_cipher(ctx.read_ctx, pgno, CIPHER_ENCRYPT, pg_sz, pData, ctx.buffer);
|
||||
return ctx.buffer; /* return persistent buffer data, pData remains intact */
|
||||
default:
|
||||
return pData;
|
||||
}
|
||||
}
|
||||
|
||||
private static int sqlite3CodecAttach(sqlite3 db, int nDb, string zKey, int nKey)
|
||||
{
|
||||
Db pDb = db.aDb[nDb];
|
||||
|
||||
CODEC_TRACE("sqlite3CodecAttach: entered nDb=%d zKey=%s, nKey=%d\n", nDb, zKey, nKey);
|
||||
//activate_openssl();
|
||||
|
||||
if (zKey != null && pDb.pBt != null)
|
||||
{
|
||||
Aes.KeySize = 256;
|
||||
#if !SQLITE_SILVERLIGHT
|
||||
Aes.Padding = PaddingMode.None;
|
||||
#endif
|
||||
codec_ctx ctx;
|
||||
int rc;
|
||||
////Pager pPager = pDb.pBt.pBt.pPager;
|
||||
sqlite3_file fd;
|
||||
|
||||
ctx = new codec_ctx();//sqlite3Malloc(sizeof(codec_ctx);
|
||||
//if(ctx == null) return SQLITE_NOMEM;
|
||||
//memset(ctx, 0, sizeof(codec_ctx); /* initialize all pointers and values to 0 */
|
||||
|
||||
ctx.pBt = pDb.pBt; /* assign pointer to database btree structure */
|
||||
|
||||
if ((rc = cipher_ctx_init(ref ctx.read_ctx)) != SQLITE_OK)
|
||||
return rc;
|
||||
if ((rc = cipher_ctx_init(ref ctx.write_ctx)) != SQLITE_OK)
|
||||
return rc;
|
||||
|
||||
/* pre-allocate a page buffer of PageSize bytes. This will
|
||||
be used as a persistent buffer for encryption and decryption
|
||||
operations to avoid overhead of multiple memory allocations*/
|
||||
ctx.buffer = sqlite3MemMalloc(sqlite3BtreeGetPageSize(ctx.pBt));//sqlite3Malloc(sqlite3BtreeGetPageSize(ctx.pBt);
|
||||
//if(ctx.buffer == null) return SQLITE_NOMEM;
|
||||
|
||||
/* allocate space for salt data. Then read the first 16 bytes header as the salt for the key derivation */
|
||||
ctx.read_ctx.iv_sz = FILE_HEADER_SZ;
|
||||
ctx.read_ctx.iv = new byte[ctx.read_ctx.iv_sz];//sqlite3Malloc( ctx.iv_sz );
|
||||
|
||||
Buffer.BlockCopy(Encoding.UTF8.GetBytes(SQLITE_FILE_HEADER), 0, ctx.read_ctx.iv, 0, FILE_HEADER_SZ);
|
||||
|
||||
sqlite3pager_sqlite3PagerSetCodec(sqlite3BtreePager(pDb.pBt), sqlite3Codec, null, sqlite3FreeCodecArg, ctx);
|
||||
|
||||
codec_set_cipher_name(db, nDb, CIPHER, 0);
|
||||
codec_set_pass_key(db, nDb, zKey, nKey, 0);
|
||||
cipher_ctx_copy(ctx.write_ctx, ctx.read_ctx);
|
||||
|
||||
//sqlite3BtreeSetPageSize( ctx.pBt, sqlite3BtreeGetPageSize( ctx.pBt ), MAX_IV_LENGTH, 0 );
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
private static void sqlite3FreeCodecArg(ref codec_ctx pCodecArg)
|
||||
{
|
||||
if (pCodecArg == null)
|
||||
return;
|
||||
codec_ctx_free(ref pCodecArg); // wipe and free allocated memory for the context
|
||||
}
|
||||
|
||||
private static void sqlite3_activate_see(string zPassword)
|
||||
{
|
||||
/* do nothing, security enhancements are always active */
|
||||
}
|
||||
|
||||
static public int sqlite3_key(sqlite3 db, string pKey, int nKey)
|
||||
{
|
||||
CODEC_TRACE("sqlite3_key: entered db=%d pKey=%s nKey=%d\n", db, pKey, nKey);
|
||||
/* attach key if db and pKey are not null and nKey is > 0 */
|
||||
if (db != null && pKey != null)
|
||||
{
|
||||
sqlite3CodecAttach(db, 0, pKey, nKey); // operate only on the main db
|
||||
//
|
||||
// If we are reopening an existing database, redo the header information setup
|
||||
//
|
||||
BtShared pBt = db.aDb[0].pBt.pBt;
|
||||
byte[] zDbHeader = sqlite3MemMalloc((int)pBt.pageSize);// pBt.pPager.pCodec.buffer;
|
||||
sqlite3PagerReadFileheader(pBt.pPager, zDbHeader.Length, zDbHeader);
|
||||
if (sqlite3Get4byte(zDbHeader) > 0) // Existing Database, need to reset some values
|
||||
{
|
||||
CODEC2(pBt.pPager, zDbHeader, 2, SQLITE_DECRYPT, ref zDbHeader);
|
||||
byte nReserve = zDbHeader[20];
|
||||
pBt.pageSize = (uint)((zDbHeader[16] << 8) | (zDbHeader[17] << 16));
|
||||
if (pBt.pageSize < 512 || pBt.pageSize > SQLITE_MAX_PAGE_SIZE
|
||||
|| ((pBt.pageSize - 1) & pBt.pageSize) != 0)
|
||||
pBt.pageSize = 0;
|
||||
pBt.pageSizeFixed = true;
|
||||
#if !SQLITE_OMIT_AUTOVACUUM
|
||||
pBt.autoVacuum = sqlite3Get4byte(zDbHeader, 36 + 4 * 4) != 0;
|
||||
pBt.incrVacuum = sqlite3Get4byte(zDbHeader, 36 + 7 * 4) != 0;
|
||||
#endif
|
||||
sqlite3PagerSetPagesize(pBt.pPager, ref pBt.pageSize, nReserve);
|
||||
pBt.usableSize = (u16)(pBt.pageSize - nReserve);
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
/* sqlite3_rekey
|
||||
** Given a database, this will reencrypt the database using a new key.
|
||||
** There are two possible modes of operation. The first is rekeying
|
||||
** an existing database that was not previously encrypted. The second
|
||||
** is to change the key on an existing database.
|
||||
**
|
||||
** The proposed logic for this function follows:
|
||||
** 1. Determine if there is already a key present
|
||||
** 2. If there is NOT already a key present, create one and attach a codec (key would be null)
|
||||
** 3. Initialize a ctx.rekey parameter of the codec
|
||||
**
|
||||
** Note: this will require modifications to the sqlite3Codec to support rekey
|
||||
**
|
||||
*/
|
||||
|
||||
public static int sqlite3_rekey(sqlite3 db, string pKey, int nKey)
|
||||
{
|
||||
CODEC_TRACE("sqlite3_rekey: entered db=%d pKey=%s, nKey=%d\n", db, pKey, nKey);
|
||||
//activate_openssl();
|
||||
if (db != null && pKey != null)
|
||||
{
|
||||
Db pDb = db.aDb[0];
|
||||
CODEC_TRACE("sqlite3_rekey: database pDb=%d\n", pDb);
|
||||
if (pDb.pBt != null)
|
||||
{
|
||||
codec_ctx ctx = null;
|
||||
int rc;
|
||||
Pgno page_count = 0;
|
||||
Pgno pgno;
|
||||
PgHdr page = null;
|
||||
Pager pPager = pDb.pBt.pBt.pPager;
|
||||
|
||||
sqlite3pager_get_codec(pDb.pBt.pBt.pPager, ref ctx);
|
||||
|
||||
if (ctx == null)
|
||||
{
|
||||
CODEC_TRACE("sqlite3_rekey: no codec attached to db, attaching now\n");
|
||||
/* there was no codec attached to this database,so attach one now with a null password */
|
||||
sqlite3CodecAttach(db, 0, pKey, nKey);
|
||||
sqlite3pager_get_codec(pDb.pBt.pBt.pPager, ref ctx);
|
||||
|
||||
/* prepare this setup as if it had already been initialized */
|
||||
Buffer.BlockCopy(Encoding.UTF8.GetBytes(SQLITE_FILE_HEADER), 0, ctx.read_ctx.iv, 0, FILE_HEADER_SZ);
|
||||
ctx.read_ctx.key_sz = ctx.read_ctx.iv_sz = ctx.read_ctx.pass_sz = 0;
|
||||
}
|
||||
|
||||
//if ( ctx.read_ctx.iv_sz != ctx.write_ctx.iv_sz )
|
||||
//{
|
||||
// string error = "";
|
||||
// CODEC_TRACE( "sqlite3_rekey: updating page size for iv_sz change from %d to %d\n", ctx.read_ctx.iv_sz, ctx.write_ctx.iv_sz );
|
||||
// db.nextPagesize = sqlite3BtreeGetPageSize( pDb.pBt );
|
||||
// pDb.pBt.pBt.pageSizeFixed = false; /* required for sqlite3BtreeSetPageSize to modify pagesize setting */
|
||||
// sqlite3BtreeSetPageSize( pDb.pBt, db.nextPagesize, MAX_IV_LENGTH, 0 );
|
||||
// sqlite3RunVacuum( ref error, db );
|
||||
//}
|
||||
|
||||
codec_set_pass_key(db, 0, pKey, nKey, 1);
|
||||
ctx.mode_rekey = 1;
|
||||
/* do stuff here to rewrite the database
|
||||
** 1. Create a transaction on the database
|
||||
** 2. Iterate through each page, reading it and then writing it.
|
||||
** 3. If that goes ok then commit and put ctx.rekey into ctx.key
|
||||
** note: don't deallocate rekey since it may be used in a subsequent iteration
|
||||
*/
|
||||
rc = sqlite3BtreeBeginTrans(pDb.pBt, 1); /* begin write transaction */
|
||||
sqlite3PagerPagecount(pPager, out page_count);
|
||||
for (pgno = 1; rc == SQLITE_OK && pgno <= page_count; pgno++)
|
||||
{ /* pgno's start at 1 see pager.c:pagerAcquire */
|
||||
if (0 == sqlite3pager_is_mj_pgno(pPager, pgno))
|
||||
{ /* skip this page (see pager.c:pagerAcquire for reasoning) */
|
||||
rc = sqlite3PagerGet(pPager, pgno, ref page);
|
||||
if (rc == SQLITE_OK)
|
||||
{ /* write page see pager_incr_changecounter for example */
|
||||
rc = sqlite3PagerWrite(page);
|
||||
//printf("sqlite3PagerWrite(%d)\n", pgno);
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
sqlite3PagerUnref(page);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if commit was successful commit and copy the rekey data to current key, else rollback to release locks */
|
||||
if (rc == SQLITE_OK)
|
||||
{
|
||||
CODEC_TRACE("sqlite3_rekey: committing\n");
|
||||
db.nextPagesize = sqlite3BtreeGetPageSize(pDb.pBt);
|
||||
rc = sqlite3BtreeCommit(pDb.pBt);
|
||||
if (ctx != null)
|
||||
cipher_ctx_copy(ctx.read_ctx, ctx.write_ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
CODEC_TRACE("sqlite3_rekey: rollback\n");
|
||||
sqlite3BtreeRollback(pDb.pBt);
|
||||
}
|
||||
|
||||
ctx.mode_rekey = 0;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
private static void sqlite3CodecGetKey(sqlite3 db, int nDb, out string zKey, out int nKey)
|
||||
{
|
||||
Db pDb = db.aDb[nDb];
|
||||
CODEC_TRACE("sqlite3CodecGetKey: entered db=%d, nDb=%d\n", db, nDb);
|
||||
|
||||
if (pDb.pBt != null)
|
||||
{
|
||||
codec_ctx ctx = null;
|
||||
sqlite3pager_get_codec(pDb.pBt.pBt.pPager, ref ctx);
|
||||
|
||||
if (ctx != null)
|
||||
{ /* if the codec has an attached codec_context user the raw key data */
|
||||
zKey = ctx.read_ctx.pass;
|
||||
nKey = ctx.read_ctx.pass_sz;
|
||||
return;
|
||||
}
|
||||
}
|
||||
zKey = null;
|
||||
nKey = 0;
|
||||
}
|
||||
|
||||
/* END CRYPTO */
|
||||
#endif
|
||||
private const int SQLITE_ENCRYPT_WRITE_CTX = 6; /* Encode page */
|
||||
private const int SQLITE_ENCRYPT_READ_CTX = 7; /* Encode page */
|
||||
private const int SQLITE_DECRYPT = 3; /* Decode page */
|
||||
}
|
||||
}
|
||||
421
original/Community.CsharpSqlite/src/ctime_c.cs
Normal file
421
original/Community.CsharpSqlite/src/ctime_c.cs
Normal file
|
|
@ -0,0 +1,421 @@
|
|||
namespace Community.CsharpSqlite
|
||||
{
|
||||
using System;
|
||||
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 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.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2011-01-28 17:03:50 ed759d5a9edb3bba5f48f243df47be29e3fe8cd7
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
|
||||
#if !SQLITE_OMIT_COMPILEOPTION_DIAGS
|
||||
|
||||
//#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.
|
||||
*/
|
||||
|
||||
private static string[] azCompileOpt = {
|
||||
/* 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)
|
||||
|
||||
#if SQLITE_32BIT_ROWID
|
||||
"32BIT_ROWID",
|
||||
#endif
|
||||
#if SQLITE_4_BYTE_ALIGNED_MALLOC
|
||||
"4_BYTE_ALIGNED_MALLOC",
|
||||
#endif
|
||||
#if SQLITE_CASE_SENSITIVE_LIKE
|
||||
"CASE_SENSITIVE_LIKE",
|
||||
#endif
|
||||
#if SQLITE_CHECK_PAGES
|
||||
"CHECK_PAGES",
|
||||
#endif
|
||||
#if SQLITE_COVERAGE_TEST
|
||||
"COVERAGE_TEST",
|
||||
#endif
|
||||
#if SQLITE_DEBUG
|
||||
"DEBUG",
|
||||
#endif
|
||||
#if SQLITE_DEFAULT_LOCKING_MODE
|
||||
"DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE),
|
||||
#endif
|
||||
#if SQLITE_DISABLE_DIRSYNC
|
||||
"DISABLE_DIRSYNC",
|
||||
#endif
|
||||
#if SQLITE_DISABLE_LFS
|
||||
"DISABLE_LFS",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_ATOMIC_WRITE
|
||||
"ENABLE_ATOMIC_WRITE",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_CEROD
|
||||
"ENABLE_CEROD",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_COLUMN_METADATA
|
||||
"ENABLE_COLUMN_METADATA",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_EXPENSIVE_ASSERT
|
||||
"ENABLE_EXPENSIVE_ASSERT",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_FTS1
|
||||
"ENABLE_FTS1",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_FTS2
|
||||
"ENABLE_FTS2",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_FTS3
|
||||
"ENABLE_FTS3",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_FTS3_PARENTHESIS
|
||||
"ENABLE_FTS3_PARENTHESIS",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_FTS4
|
||||
"ENABLE_FTS4",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_ICU
|
||||
"ENABLE_ICU",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_IOTRACE
|
||||
"ENABLE_IOTRACE",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_LOAD_EXTENSION
|
||||
"ENABLE_LOAD_EXTENSION",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_LOCKING_STYLE
|
||||
"ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE),
|
||||
#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_OVERSIZE_CELL_CHECK
|
||||
"ENABLE_OVERSIZE_CELL_CHECK",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_RTREE
|
||||
"ENABLE_RTREE",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_STAT2
|
||||
"ENABLE_STAT2",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_UNLOCK_NOTIFY
|
||||
"ENABLE_UNLOCK_NOTIFY",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
||||
"ENABLE_UPDATE_DELETE_LIMIT",
|
||||
#endif
|
||||
#if SQLITE_HAS_CODEC
|
||||
"HAS_CODEC",
|
||||
#endif
|
||||
#if SQLITE_HAVE_ISNAN
|
||||
"HAVE_ISNAN",
|
||||
#endif
|
||||
#if SQLITE_HOMEGROWN_RECURSIVE_MUTEX
|
||||
"HOMEGROWN_RECURSIVE_MUTEX",
|
||||
#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_INT64_TYPE
|
||||
"INT64_TYPE",
|
||||
#endif
|
||||
#if SQLITE_LOCK_TRACE
|
||||
"LOCK_TRACE",
|
||||
#endif
|
||||
#if SQLITE_MEMDEBUG
|
||||
"MEMDEBUG",
|
||||
#endif
|
||||
#if SQLITE_MIXED_ENDIAN_64BIT_FLOAT
|
||||
"MIXED_ENDIAN_64BIT_FLOAT",
|
||||
#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_BTREECOUNT
|
||||
"OMIT_BTREECOUNT",
|
||||
#endif
|
||||
#if SQLITE_OMIT_BUILTIN_TEST
|
||||
"OMIT_BUILTIN_TEST",
|
||||
#endif
|
||||
#if SQLITE_OMIT_CAST
|
||||
"OMIT_CAST",
|
||||
#endif
|
||||
#if SQLITE_OMIT_CHECK
|
||||
"OMIT_CHECK",
|
||||
#endif
|
||||
/* // redundant
|
||||
** #if SQLITE_OMIT_COMPILEOPTION_DIAGS
|
||||
** "OMIT_COMPILEOPTION_DIAGS",
|
||||
** #endif
|
||||
*/
|
||||
#if SQLITE_OMIT_COMPLETE
|
||||
"OMIT_COMPLETE",
|
||||
#endif
|
||||
#if SQLITE_OMIT_COMPOUND_SELECT
|
||||
"OMIT_COMPOUND_SELECT",
|
||||
#endif
|
||||
#if SQLITE_OMIT_DATETIME_FUNCS
|
||||
"OMIT_DATETIME_FUNCS",
|
||||
#endif
|
||||
#if SQLITE_OMIT_DECLTYPE
|
||||
"OMIT_DECLTYPE",
|
||||
#endif
|
||||
#if SQLITE_OMIT_DEPRECATED
|
||||
"OMIT_DEPRECATED",
|
||||
#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_INCRBLOB
|
||||
"OMIT_INCRBLOB",
|
||||
#endif
|
||||
#if SQLITE_OMIT_INTEGRITY_CHECK
|
||||
"OMIT_INTEGRITY_CHECK",
|
||||
#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_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_SUBQUERY
|
||||
"OMIT_SUBQUERY",
|
||||
#endif
|
||||
#if SQLITE_OMIT_TCL_VARIABLE
|
||||
"OMIT_TCL_VARIABLE",
|
||||
#endif
|
||||
#if SQLITE_OMIT_TEMPDB
|
||||
"OMIT_TEMPDB",
|
||||
#endif
|
||||
#if SQLITE_OMIT_TRACE
|
||||
"OMIT_TRACE",
|
||||
#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_PERFORMANCE_TRACE
|
||||
"PERFORMANCE_TRACE",
|
||||
#endif
|
||||
#if SQLITE_PROXY_DEBUG
|
||||
"PROXY_DEBUG",
|
||||
#endif
|
||||
#if SQLITE_SECURE_DELETE
|
||||
"SECURE_DELETE",
|
||||
#endif
|
||||
#if SQLITE_SMALL_STACK
|
||||
"SMALL_STACK",
|
||||
#endif
|
||||
#if SQLITE_SOUNDEX
|
||||
"SOUNDEX",
|
||||
#endif
|
||||
#if SQLITE_TCL
|
||||
"TCL",
|
||||
#endif
|
||||
//#if SQLITE_TEMP_STORE
|
||||
"TEMP_STORE=1",//CTIMEOPT_VAL(SQLITE_TEMP_STORE),
|
||||
//#endif
|
||||
#if SQLITE_TEST
|
||||
"TEST",
|
||||
#endif
|
||||
#if SQLITE_THREADSAFE
|
||||
"THREADSAFE=2", // For C#, hardcode to = 2 CTIMEOPT_VAL(SQLITE_THREADSAFE),
|
||||
#else
|
||||
"THREADSAFE=0", // For C#, hardcode to = 0
|
||||
#endif
|
||||
#if SQLITE_USE_ALLOCA
|
||||
"USE_ALLOCA",
|
||||
#endif
|
||||
#if SQLITE_ZERO_MALLOC
|
||||
"ZERO_MALLOC"
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
** Given the name of a compile-time option, return true if that option
|
||||
** was used and false if not.
|
||||
**
|
||||
** The name can optionally begin with "SQLITE_" but the "SQLITE_" prefix
|
||||
** is not required for a match.
|
||||
*/
|
||||
|
||||
private static int sqlite3_compileoption_used(string zOptName)
|
||||
{
|
||||
if (zOptName.EndsWith("="))
|
||||
return 0;
|
||||
int i, n = 0;
|
||||
if (zOptName.StartsWith("SQLITE_", System.StringComparison.OrdinalIgnoreCase))
|
||||
n = 7;
|
||||
//n = sqlite3Strlen30(zOptName);
|
||||
|
||||
/* Since ArraySize(azCompileOpt) is normally in single digits, a
|
||||
** linear search is adequate. No need for a binary search. */
|
||||
if (!String.IsNullOrEmpty(zOptName))
|
||||
for (i = 0; i < ArraySize(azCompileOpt); i++)
|
||||
{
|
||||
int n1 = (zOptName.Length - n < azCompileOpt[i].Length) ? zOptName.Length - n : azCompileOpt[i].Length;
|
||||
if (String.Compare(zOptName, n, azCompileOpt[i], 0, n1, StringComparison.OrdinalIgnoreCase) == 0)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the N-th compile-time option string. If N is out of range,
|
||||
** return a NULL pointer.
|
||||
*/
|
||||
|
||||
private static string sqlite3_compileoption_get(int N)
|
||||
{
|
||||
if (N >= 0 && N < ArraySize(azCompileOpt))
|
||||
{
|
||||
return azCompileOpt[N];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
#endif //* SQLITE_OMIT_COMPILEOPTION_DIAGS */
|
||||
}
|
||||
}
|
||||
1447
original/Community.CsharpSqlite/src/date_c.cs
Normal file
1447
original/Community.CsharpSqlite/src/date_c.cs
Normal file
File diff suppressed because it is too large
Load diff
750
original/Community.CsharpSqlite/src/delete_c.cs
Normal file
750
original/Community.CsharpSqlite/src/delete_c.cs
Normal file
|
|
@ -0,0 +1,750 @@
|
|||
using System.Diagnostics;
|
||||
|
||||
using u32 = System.UInt32;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains C code routines that are called by the parser
|
||||
** in order to generate code for DELETE FROM statements.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** While a SrcList can in general represent multiple tables and subqueries
|
||||
** (as in the FROM clause of a SELECT statement) in this case it contains
|
||||
** the name of a single table, as one might find in an INSERT, DELETE,
|
||||
** or UPDATE statement. Look up that table in the symbol table and
|
||||
** return a pointer. Set an error message and return NULL if the table
|
||||
** name is not found or if any other error occurs.
|
||||
**
|
||||
** The following fields are initialized appropriate in pSrc:
|
||||
**
|
||||
** pSrc->a[0].pTab Pointer to the Table object
|
||||
** pSrc->a[0].pIndex Pointer to the INDEXED BY index, if there is one
|
||||
**
|
||||
*/
|
||||
|
||||
private static Table sqlite3SrcListLookup(Parse pParse, SrcList pSrc)
|
||||
{
|
||||
SrcList_item pItem = pSrc.a[0];
|
||||
Table pTab;
|
||||
Debug.Assert(pItem != null && pSrc.nSrc == 1);
|
||||
pTab = sqlite3LocateTable(pParse, 0, pItem.zName, pItem.zDatabase);
|
||||
sqlite3DeleteTable(pParse.db, ref pItem.pTab);
|
||||
pItem.pTab = pTab;
|
||||
if (pTab != null)
|
||||
{
|
||||
pTab.nRef++;
|
||||
}
|
||||
if (sqlite3IndexedByLookup(pParse, pItem) != 0)
|
||||
{
|
||||
pTab = null;
|
||||
}
|
||||
return pTab;
|
||||
}
|
||||
|
||||
/*
|
||||
** Check to make sure the given table is writable. If it is not
|
||||
** writable, generate an error message and return 1. If it is
|
||||
** writable return 0;
|
||||
*/
|
||||
|
||||
private static bool sqlite3IsReadOnly(Parse pParse, Table pTab, int viewOk)
|
||||
{
|
||||
/* A table is not writable under the following circumstances:
|
||||
**
|
||||
** 1) It is a virtual table and no implementation of the xUpdate method
|
||||
** has been provided, or
|
||||
** 2) It is a system table (i.e. sqlite_master), this call is not
|
||||
** part of a nested parse and writable_schema pragma has not
|
||||
** been specified.
|
||||
**
|
||||
** In either case leave an error message in pParse and return non-zero.
|
||||
*/
|
||||
if (
|
||||
(IsVirtual(pTab)
|
||||
&& sqlite3GetVTable(pParse.db, pTab).pMod.pModule.xUpdate == null)
|
||||
|| ((pTab.tabFlags & TF_Readonly) != 0
|
||||
&& (pParse.db.flags & SQLITE_WriteSchema) == 0
|
||||
&& pParse.nested == 0)
|
||||
)
|
||||
{
|
||||
sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab.zName);
|
||||
return true;
|
||||
}
|
||||
|
||||
#if !SQLITE_OMIT_VIEW
|
||||
if (viewOk == 0 && pTab.pSelect != null)
|
||||
{
|
||||
sqlite3ErrorMsg(pParse, "cannot modify %s because it is a view", pTab.zName);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
#if !SQLITE_OMIT_VIEW && !SQLITE_OMIT_TRIGGER
|
||||
/*
|
||||
** Evaluate a view and store its result in an ephemeral table. The
|
||||
** pWhere argument is an optional WHERE clause that restricts the
|
||||
** set of rows in the view that are to be added to the ephemeral table.
|
||||
*/
|
||||
|
||||
private static void sqlite3MaterializeView(
|
||||
Parse pParse, /* Parsing context */
|
||||
Table pView, /* View definition */
|
||||
Expr pWhere, /* Optional WHERE clause to be added */
|
||||
int iCur /* VdbeCursor number for ephemerial table */
|
||||
)
|
||||
{
|
||||
SelectDest dest = new SelectDest();
|
||||
Select pDup;
|
||||
sqlite3 db = pParse.db;
|
||||
|
||||
pDup = sqlite3SelectDup(db, pView.pSelect, 0);
|
||||
if (pWhere != null)
|
||||
{
|
||||
SrcList pFrom;
|
||||
|
||||
pWhere = sqlite3ExprDup(db, pWhere, 0);
|
||||
pFrom = sqlite3SrcListAppend(db, null, null, null);
|
||||
//if ( pFrom != null )
|
||||
//{
|
||||
Debug.Assert(pFrom.nSrc == 1);
|
||||
pFrom.a[0].zAlias = pView.zName;// sqlite3DbStrDup( db, pView.zName );
|
||||
pFrom.a[0].pSelect = pDup;
|
||||
Debug.Assert(pFrom.a[0].pOn == null);
|
||||
Debug.Assert(pFrom.a[0].pUsing == null);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// sqlite3SelectDelete( db, ref pDup );
|
||||
//}
|
||||
pDup = sqlite3SelectNew(pParse, null, pFrom, pWhere, null, null, null, 0, null, null);
|
||||
}
|
||||
sqlite3SelectDestInit(dest, SRT_EphemTab, iCur);
|
||||
sqlite3Select(pParse, pDup, ref dest);
|
||||
sqlite3SelectDelete(db, ref pDup);
|
||||
}
|
||||
|
||||
#endif //* !SQLITE_OMIT_VIEW) && !SQLITE_OMIT_TRIGGER) */
|
||||
|
||||
#if (SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !(SQLITE_OMIT_SUBQUERY)
|
||||
/*
|
||||
** Generate an expression tree to implement the WHERE, ORDER BY,
|
||||
** and LIMIT/OFFSET portion of DELETE and UPDATE statements.
|
||||
**
|
||||
** DELETE FROM table_wxyz WHERE a<5 ORDER BY a LIMIT 1;
|
||||
** \__________________________/
|
||||
** pLimitWhere (pInClause)
|
||||
*/
|
||||
Expr sqlite3LimitWhere(
|
||||
Parse pParse, /* The parser context */
|
||||
SrcList pSrc, /* the FROM clause -- which tables to scan */
|
||||
Expr pWhere, /* The WHERE clause. May be null */
|
||||
ExprList pOrderBy, /* The ORDER BY clause. May be null */
|
||||
Expr pLimit, /* The LIMIT clause. May be null */
|
||||
Expr pOffset, /* The OFFSET clause. May be null */
|
||||
char zStmtType /* Either DELETE or UPDATE. For error messages. */
|
||||
){
|
||||
Expr pWhereRowid = null; /* WHERE rowid .. */
|
||||
Expr pInClause = null; /* WHERE rowid IN ( select ) */
|
||||
Expr pSelectRowid = null; /* SELECT rowid ... */
|
||||
ExprList pEList = null; /* Expression list contaning only pSelectRowid */
|
||||
SrcList pSelectSrc = null; /* SELECT rowid FROM x ... (dup of pSrc) */
|
||||
Select pSelect = null; /* Complete SELECT tree */
|
||||
|
||||
/* Check that there isn't an ORDER BY without a LIMIT clause.
|
||||
*/
|
||||
if( pOrderBy!=null && (pLimit == null) ) {
|
||||
sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on %s", zStmtType);
|
||||
pParse.parseError = 1;
|
||||
goto limit_where_cleanup_2;
|
||||
}
|
||||
|
||||
/* We only need to generate a select expression if there
|
||||
** is a limit/offset term to enforce.
|
||||
*/
|
||||
if ( pLimit == null )
|
||||
{
|
||||
/* if pLimit is null, pOffset will always be null as well. */
|
||||
Debug.Assert( pOffset == null );
|
||||
return pWhere;
|
||||
}
|
||||
|
||||
/* Generate a select expression tree to enforce the limit/offset
|
||||
** term for the DELETE or UPDATE statement. For example:
|
||||
** DELETE FROM table_a WHERE col1=1 ORDER BY col2 LIMIT 1 OFFSET 1
|
||||
** becomes:
|
||||
** DELETE FROM table_a WHERE rowid IN (
|
||||
** SELECT rowid FROM table_a WHERE col1=1 ORDER BY col2 LIMIT 1 OFFSET 1
|
||||
** );
|
||||
*/
|
||||
|
||||
pSelectRowid = sqlite3PExpr( pParse, TK_ROW, null, null, null );
|
||||
if( pSelectRowid == null ) goto limit_where_cleanup_2;
|
||||
pEList = sqlite3ExprListAppend( pParse, null, pSelectRowid);
|
||||
if( pEList == null ) goto limit_where_cleanup_2;
|
||||
|
||||
/* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
|
||||
** and the SELECT subtree. */
|
||||
pSelectSrc = sqlite3SrcListDup(pParse.db, pSrc,0);
|
||||
if( pSelectSrc == null ) {
|
||||
sqlite3ExprListDelete(pParse.db, pEList);
|
||||
goto limit_where_cleanup_2;
|
||||
}
|
||||
|
||||
/* generate the SELECT expression tree. */
|
||||
pSelect = sqlite3SelectNew( pParse, pEList, pSelectSrc, pWhere, null, null,
|
||||
pOrderBy, 0, pLimit, pOffset );
|
||||
if( pSelect == null ) return null;
|
||||
|
||||
/* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */
|
||||
pWhereRowid = sqlite3PExpr( pParse, TK_ROW, null, null, null );
|
||||
if( pWhereRowid == null ) goto limit_where_cleanup_1;
|
||||
pInClause = sqlite3PExpr( pParse, TK_IN, pWhereRowid, null, null );
|
||||
if( pInClause == null ) goto limit_where_cleanup_1;
|
||||
|
||||
pInClause->x.pSelect = pSelect;
|
||||
pInClause->flags |= EP_xIsSelect;
|
||||
sqlite3ExprSetHeight(pParse, pInClause);
|
||||
return pInClause;
|
||||
|
||||
/* something went wrong. clean up anything allocated. */
|
||||
limit_where_cleanup_1:
|
||||
sqlite3SelectDelete(pParse.db, pSelect);
|
||||
return null;
|
||||
|
||||
limit_where_cleanup_2:
|
||||
sqlite3ExprDelete(pParse.db, ref pWhere);
|
||||
sqlite3ExprListDelete(pParse.db, pOrderBy);
|
||||
sqlite3ExprDelete(pParse.db, ref pLimit);
|
||||
sqlite3ExprDelete(pParse.db, ref pOffset);
|
||||
return null;
|
||||
}
|
||||
#endif //* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) */
|
||||
|
||||
/*
|
||||
** Generate code for a DELETE FROM statement.
|
||||
**
|
||||
** DELETE FROM table_wxyz WHERE a<5 AND b NOT NULL;
|
||||
** \________/ \________________/
|
||||
** pTabList pWhere
|
||||
*/
|
||||
|
||||
private static void sqlite3DeleteFrom(
|
||||
Parse pParse, /* The parser context */
|
||||
SrcList pTabList, /* The table from which we should delete things */
|
||||
Expr pWhere /* The WHERE clause. May be null */
|
||||
)
|
||||
{
|
||||
Vdbe v; /* The virtual database engine */
|
||||
Table pTab; /* The table from which records will be deleted */
|
||||
int end, addr = 0; /* A couple addresses of generated code */
|
||||
int i; /* Loop counter */
|
||||
WhereInfo pWInfo; /* Information about the WHERE clause */
|
||||
Index pIdx; /* For looping over indices of the table */
|
||||
int iCur; /* VDBE VdbeCursor number for pTab */
|
||||
sqlite3 db; /* Main database structure */
|
||||
AuthContext sContext; /* Authorization context */
|
||||
NameContext sNC; /* Name context to resolve expressions in */
|
||||
int iDb; /* Database number */
|
||||
int memCnt = -1; /* Memory cell used for change counting */
|
||||
int rcauth; /* Value returned by authorization callback */
|
||||
|
||||
#if !SQLITE_OMIT_TRIGGER
|
||||
bool isView; /* True if attempting to delete from a view */
|
||||
Trigger pTrigger; /* List of table triggers, if required */
|
||||
#endif
|
||||
sContext = new AuthContext();//memset(&sContext, 0, sizeof(sContext));
|
||||
|
||||
db = pParse.db;
|
||||
if (pParse.nErr != 0 /*|| db.mallocFailed != 0 */ )
|
||||
{
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
Debug.Assert(pTabList.nSrc == 1);
|
||||
|
||||
/* Locate the table which we want to delete. This table has to be
|
||||
** put in an SrcList structure because some of the subroutines we
|
||||
** will be calling are designed to work with multiple tables and expect
|
||||
** an SrcList* parameter instead of just a Table* parameter.
|
||||
*/
|
||||
pTab = sqlite3SrcListLookup(pParse, pTabList);
|
||||
if (pTab == null)
|
||||
goto delete_from_cleanup;
|
||||
|
||||
/* Figure out if we have any triggers and if the table being
|
||||
** deleted from is a view
|
||||
*/
|
||||
#if !SQLITE_OMIT_TRIGGER
|
||||
int iDummy;
|
||||
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, null, out iDummy);
|
||||
isView = pTab.pSelect != null;
|
||||
#else
|
||||
const Trigger pTrigger = null;
|
||||
bool isView = false;
|
||||
#endif
|
||||
#if SQLITE_OMIT_VIEW
|
||||
//# undef isView
|
||||
isView = false;
|
||||
#endif
|
||||
|
||||
/* If pTab is really a view, make sure it has been initialized.
|
||||
*/
|
||||
if (sqlite3ViewGetColumnNames(pParse, pTab) != 0)
|
||||
{
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
|
||||
if (sqlite3IsReadOnly(pParse, pTab, (pTrigger != null ? 1 : 0)))
|
||||
{
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
iDb = sqlite3SchemaToIndex(db, pTab.pSchema);
|
||||
Debug.Assert(iDb < db.nDb);
|
||||
#if !SQLITE_OMIT_AUTHORIZATION
|
||||
string zDb = db.aDb[iDb].zName; /* Name of database holding pTab */
|
||||
rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb);
|
||||
#else
|
||||
rcauth = SQLITE_OK;
|
||||
#endif
|
||||
Debug.Assert(rcauth == SQLITE_OK || rcauth == SQLITE_DENY || rcauth == SQLITE_IGNORE);
|
||||
if (rcauth == SQLITE_DENY)
|
||||
{
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
Debug.Assert(!isView || pTrigger != null);
|
||||
|
||||
/* Assign cursor number to the table and all its indices.
|
||||
*/
|
||||
Debug.Assert(pTabList.nSrc == 1);
|
||||
iCur = pTabList.a[0].iCursor = pParse.nTab++;
|
||||
for (pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext)
|
||||
{
|
||||
pParse.nTab++;
|
||||
}
|
||||
|
||||
#if !SQLITE_OMIT_AUTHORIZATION
|
||||
/* Start the view context
|
||||
*/
|
||||
if( isView ){
|
||||
sqlite3AuthContextPush(pParse, sContext, pTab.zName);
|
||||
}
|
||||
#endif
|
||||
/* Begin generating code.
|
||||
*/
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if (v == null)
|
||||
{
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
if (pParse.nested == 0)
|
||||
sqlite3VdbeCountChanges(v);
|
||||
sqlite3BeginWriteOperation(pParse, 1, iDb);
|
||||
|
||||
/* If we are trying to delete from a view, realize that view into
|
||||
** a ephemeral table.
|
||||
*/
|
||||
#if !(SQLITE_OMIT_VIEW) && !(SQLITE_OMIT_TRIGGER)
|
||||
if (isView)
|
||||
{
|
||||
sqlite3MaterializeView(pParse, pTab, pWhere, iCur);
|
||||
}
|
||||
#endif
|
||||
/* Resolve the column names in the WHERE clause.
|
||||
*/
|
||||
sNC = new NameContext();// memset( &sNC, 0, sizeof( sNC ) );
|
||||
sNC.pParse = pParse;
|
||||
sNC.pSrcList = pTabList;
|
||||
if (sqlite3ResolveExprNames(sNC, ref pWhere) != 0)
|
||||
{
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
|
||||
/* Initialize the counter of the number of rows deleted, if
|
||||
** we are counting rows.
|
||||
*/
|
||||
if ((db.flags & SQLITE_CountRows) != 0)
|
||||
{
|
||||
memCnt = ++pParse.nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, memCnt);
|
||||
}
|
||||
|
||||
#if !SQLITE_OMIT_TRUNCATE_OPTIMIZATION
|
||||
/* Special case: A DELETE without a WHERE clause deletes everything.
|
||||
** It is easier just to erase the whole table. Prior to version 3.6.5,
|
||||
** this optimization caused the row change count (the value returned by
|
||||
** API function sqlite3_count_changes) to be set incorrectly. */
|
||||
if (rcauth == SQLITE_OK && pWhere == null && null == pTrigger && !IsVirtual(pTab)
|
||||
&& 0 == sqlite3FkRequired(pParse, pTab, null, 0)
|
||||
)
|
||||
{
|
||||
Debug.Assert(!isView);
|
||||
sqlite3VdbeAddOp4(v, OP_Clear, pTab.tnum, iDb, memCnt,
|
||||
pTab.zName, P4_STATIC);
|
||||
for (pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext)
|
||||
{
|
||||
Debug.Assert(pIdx.pSchema == pTab.pSchema);
|
||||
sqlite3VdbeAddOp2(v, OP_Clear, pIdx.tnum, iDb);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif //* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */
|
||||
/* The usual case: There is a WHERE clause so we have to scan through
|
||||
** the table and pick which records to delete.
|
||||
*/
|
||||
{
|
||||
int iRowSet = ++pParse.nMem; /* Register for rowset of rows to delete */
|
||||
int iRowid = ++pParse.nMem; /* Used for storing rowid values. */
|
||||
int regRowid; /* Actual register containing rowids */
|
||||
|
||||
/* Collect rowids of every row to be deleted.
|
||||
*/
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet);
|
||||
ExprList elDummy = null;
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, ref elDummy, WHERE_DUPLICATES_OK);
|
||||
if (pWInfo == null)
|
||||
goto delete_from_cleanup;
|
||||
regRowid = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, iRowid);
|
||||
sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, regRowid);
|
||||
if ((db.flags & SQLITE_CountRows) != 0)
|
||||
{
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1);
|
||||
}
|
||||
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
|
||||
/* Delete every item whose key was written to the list during the
|
||||
** database scan. We have to delete items after the scan is complete
|
||||
** because deleting an item can change the scan order. */
|
||||
end = sqlite3VdbeMakeLabel(v);
|
||||
|
||||
/* Unless this is a view, open cursors for the table we are
|
||||
** deleting from and all its indices. If this is a view, then the
|
||||
** only effect this statement has is to fire the INSTEAD OF
|
||||
** triggers. */
|
||||
if (!isView)
|
||||
{
|
||||
sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite);
|
||||
}
|
||||
|
||||
addr = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, end, iRowid);
|
||||
|
||||
/* Delete the row */
|
||||
#if !SQLITE_OMIT_VIRTUALTABLE
|
||||
if (IsVirtual(pTab))
|
||||
{
|
||||
VTable pVTab = sqlite3GetVTable(db, pTab);
|
||||
sqlite3VtabMakeWritable(pParse, pTab);
|
||||
sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iRowid, pVTab, P4_VTAB);
|
||||
sqlite3VdbeChangeP5(v, OE_Abort);
|
||||
sqlite3MayAbort(pParse);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
int count = (pParse.nested == 0) ? 1 : 0; /* True to count changes */
|
||||
sqlite3GenerateRowDelete(pParse, pTab, iCur, iRowid, count, pTrigger, OE_Default);
|
||||
}
|
||||
|
||||
/* End of the delete loop */
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addr);
|
||||
sqlite3VdbeResolveLabel(v, end);
|
||||
|
||||
/* Close the cursors open on the table and its indexes. */
|
||||
if (!isView && !IsVirtual(pTab))
|
||||
{
|
||||
for (i = 1, pIdx = pTab.pIndex; pIdx != null; i++, pIdx = pIdx.pNext)
|
||||
{
|
||||
sqlite3VdbeAddOp2(v, OP_Close, iCur + i, pIdx.tnum);
|
||||
}
|
||||
sqlite3VdbeAddOp1(v, OP_Close, iCur);
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the sqlite_sequence table by storing the content of the
|
||||
** maximum rowid counter values recorded while inserting into
|
||||
** autoincrement tables.
|
||||
*/
|
||||
if (pParse.nested == 0 && pParse.pTriggerTab == null)
|
||||
{
|
||||
sqlite3AutoincrementEnd(pParse);
|
||||
}
|
||||
|
||||
/* Return the number of rows that were deleted. If this routine is
|
||||
** generating code because of a call to sqlite3NestedParse(), do not
|
||||
** invoke the callback function.
|
||||
*/
|
||||
|
||||
if ((db.flags & SQLITE_CountRows) != 0 && 0 == pParse.nested && null == pParse.pTriggerTab)
|
||||
{
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, memCnt, 1);
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", SQLITE_STATIC);
|
||||
}
|
||||
|
||||
delete_from_cleanup:
|
||||
#if !SQLITE_OMIT_AUTHORIZATION
|
||||
sqlite3AuthContextPop(sContext);
|
||||
#endif
|
||||
sqlite3SrcListDelete(db, ref pTabList);
|
||||
sqlite3ExprDelete(db, ref pWhere);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Make sure "isView" and other macros defined above are undefined. Otherwise
|
||||
** thely may interfere with compilation of other functions in this file
|
||||
** (or in another file, if this file becomes part of the amalgamation). */
|
||||
//#if isView
|
||||
// #undef isView
|
||||
//#endif
|
||||
//#if pTrigger
|
||||
// #undef pTrigger
|
||||
//#endif
|
||||
|
||||
/*
|
||||
** This routine generates VDBE code that causes a single row of a
|
||||
** single table to be deleted.
|
||||
**
|
||||
** The VDBE must be in a particular state when this routine is called.
|
||||
** These are the requirements:
|
||||
**
|
||||
** 1. A read/write cursor pointing to pTab, the table containing the row
|
||||
** to be deleted, must be opened as cursor number $iCur.
|
||||
**
|
||||
** 2. Read/write cursors for all indices of pTab must be open as
|
||||
** cursor number base+i for the i-th index.
|
||||
**
|
||||
** 3. The record number of the row to be deleted must be stored in
|
||||
** memory cell iRowid.
|
||||
**
|
||||
** This routine generates code to remove both the table record and all
|
||||
** index entries that point to that record.
|
||||
*/
|
||||
|
||||
private static void sqlite3GenerateRowDelete(
|
||||
Parse pParse, /* Parsing context */
|
||||
Table pTab, /* Table containing the row to be deleted */
|
||||
int iCur, /* VdbeCursor number for the table */
|
||||
int iRowid, /* Memory cell that contains the rowid to delete */
|
||||
int count, /* If non-zero, increment the row change counter */
|
||||
Trigger pTrigger, /* List of triggers to (potentially) fire */
|
||||
int onconf /* Default ON CONFLICT policy for triggers */
|
||||
)
|
||||
{
|
||||
Vdbe v = pParse.pVdbe; /* Vdbe */
|
||||
int iOld = 0; /* First register in OLD.* array */
|
||||
int iLabel; /* Label resolved to end of generated code */
|
||||
|
||||
/* Vdbe is guaranteed to have been allocated by this stage. */
|
||||
Debug.Assert(v != null);
|
||||
|
||||
/* Seek cursor iCur to the row to delete. If this row no longer exists
|
||||
** (this can happen if a trigger program has already deleted it), do
|
||||
** not attempt to delete it or fire any DELETE triggers. */
|
||||
iLabel = sqlite3VdbeMakeLabel(v);
|
||||
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, iLabel, iRowid);
|
||||
|
||||
/* If there are any triggers to fire, allocate a range of registers to
|
||||
** use for the old.* references in the triggers. */
|
||||
if (sqlite3FkRequired(pParse, pTab, null, 0) != 0 || pTrigger != null)
|
||||
{
|
||||
u32 mask; /* Mask of OLD.* columns in use */
|
||||
int iCol; /* Iterator used while populating OLD.* */
|
||||
|
||||
/* TODO: Could use temporary registers here. Also could attempt to
|
||||
** avoid copying the contents of the rowid register. */
|
||||
mask = sqlite3TriggerColmask(
|
||||
pParse, pTrigger, null, 0, TRIGGER_BEFORE | TRIGGER_AFTER, pTab, onconf
|
||||
);
|
||||
mask |= sqlite3FkOldmask(pParse, pTab);
|
||||
iOld = pParse.nMem + 1;
|
||||
pParse.nMem += (1 + pTab.nCol);
|
||||
|
||||
/* Populate the OLD.* pseudo-table register array. These values will be
|
||||
** used by any BEFORE and AFTER triggers that exist. */
|
||||
sqlite3VdbeAddOp2(v, OP_Copy, iRowid, iOld);
|
||||
for (iCol = 0; iCol < pTab.nCol; iCol++)
|
||||
{
|
||||
if (mask == 0xffffffff || (mask & (1 << iCol)) != 0)
|
||||
{
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol, iOld + iCol + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Invoke BEFORE DELETE trigger programs. */
|
||||
sqlite3CodeRowTrigger(pParse, pTrigger,
|
||||
TK_DELETE, null, TRIGGER_BEFORE, pTab, iOld, onconf, iLabel
|
||||
);
|
||||
|
||||
/* Seek the cursor to the row to be deleted again. It may be that
|
||||
** the BEFORE triggers coded above have already removed the row
|
||||
** being deleted. Do not attempt to delete the row a second time, and
|
||||
** do not fire AFTER triggers. */
|
||||
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, iLabel, iRowid);
|
||||
|
||||
/* Do FK processing. This call checks that any FK constraints that
|
||||
** refer to this table (i.e. constraints attached to other tables)
|
||||
** are not violated by deleting this row. */
|
||||
sqlite3FkCheck(pParse, pTab, iOld, 0);
|
||||
}
|
||||
|
||||
/* Delete the index and table entries. Skip this step if pTab is really
|
||||
** a view (in which case the only effect of the DELETE statement is to
|
||||
** fire the INSTEAD OF triggers). */
|
||||
if (pTab.pSelect == null)
|
||||
{
|
||||
sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Delete, iCur, (count != 0 ? (int)OPFLAG_NCHANGE : 0));
|
||||
if (count != 0)
|
||||
{
|
||||
sqlite3VdbeChangeP4(v, -1, pTab.zName, P4_TRANSIENT);
|
||||
}
|
||||
}
|
||||
|
||||
/* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
|
||||
** handle rows (possibly in other tables) that refer via a foreign key
|
||||
** to the row just deleted. */
|
||||
sqlite3FkActions(pParse, pTab, null, iOld);
|
||||
|
||||
/* Invoke AFTER DELETE trigger programs. */
|
||||
sqlite3CodeRowTrigger(pParse, pTrigger,
|
||||
TK_DELETE, null, TRIGGER_AFTER, pTab, iOld, onconf, iLabel
|
||||
);
|
||||
|
||||
/* Jump here if the row had already been deleted before any BEFORE
|
||||
** trigger programs were invoked. Or if a trigger program throws a
|
||||
** RAISE(IGNORE) exception. */
|
||||
sqlite3VdbeResolveLabel(v, iLabel);
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine generates VDBE code that causes the deletion of all
|
||||
** index entries associated with a single row of a single table.
|
||||
**
|
||||
** The VDBE must be in a particular state when this routine is called.
|
||||
** These are the requirements:
|
||||
**
|
||||
** 1. A read/write cursor pointing to pTab, the table containing the row
|
||||
** to be deleted, must be opened as cursor number "iCur".
|
||||
**
|
||||
** 2. Read/write cursors for all indices of pTab must be open as
|
||||
** cursor number iCur+i for the i-th index.
|
||||
**
|
||||
** 3. The "iCur" cursor must be pointing to the row that is to be
|
||||
** deleted.
|
||||
*/
|
||||
|
||||
private static void sqlite3GenerateRowIndexDelete(
|
||||
Parse pParse, /* Parsing and code generating context */
|
||||
Table pTab, /* Table containing the row to be deleted */
|
||||
int iCur, /* VdbeCursor number for the table */
|
||||
int nothing /* Only delete if aRegIdx!=0 && aRegIdx[i]>0 */
|
||||
)
|
||||
{
|
||||
int[] aRegIdx = null;
|
||||
sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, aRegIdx);
|
||||
}
|
||||
|
||||
private static void sqlite3GenerateRowIndexDelete(
|
||||
Parse pParse, /* Parsing and code generating context */
|
||||
Table pTab, /* Table containing the row to be deleted */
|
||||
int iCur, /* VdbeCursor number for the table */
|
||||
int[] aRegIdx /* Only delete if aRegIdx!=0 && aRegIdx[i]>0 */
|
||||
)
|
||||
{
|
||||
int i;
|
||||
Index pIdx;
|
||||
int r1;
|
||||
|
||||
for (i = 1, pIdx = pTab.pIndex; pIdx != null; i++, pIdx = pIdx.pNext)
|
||||
{
|
||||
if (aRegIdx != null && aRegIdx[i - 1] == 0)
|
||||
continue;
|
||||
r1 = sqlite3GenerateIndexKey(pParse, pIdx, iCur, 0, false);
|
||||
sqlite3VdbeAddOp3(pParse.pVdbe, OP_IdxDelete, iCur + i, r1, pIdx.nColumn + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code that will assemble an index key and put it in register
|
||||
** regOut. The key with be for index pIdx which is an index on pTab.
|
||||
** iCur is the index of a cursor open on the pTab table and pointing to
|
||||
** the entry that needs indexing.
|
||||
**
|
||||
** Return a register number which is the first in a block of
|
||||
** registers that holds the elements of the index key. The
|
||||
** block of registers has already been deallocated by the time
|
||||
** this routine returns.
|
||||
*/
|
||||
|
||||
private static int sqlite3GenerateIndexKey(
|
||||
Parse pParse, /* Parsing context */
|
||||
Index pIdx, /* The index for which to generate a key */
|
||||
int iCur, /* VdbeCursor number for the pIdx.pTable table */
|
||||
int regOut, /* Write the new index key to this register */
|
||||
bool doMakeRec /* Run the OP_MakeRecord instruction if true */
|
||||
)
|
||||
{
|
||||
Vdbe v = pParse.pVdbe;
|
||||
int j;
|
||||
Table pTab = pIdx.pTable;
|
||||
int regBase;
|
||||
int nCol;
|
||||
|
||||
nCol = pIdx.nColumn;
|
||||
regBase = sqlite3GetTempRange(pParse, nCol + 1);
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regBase + nCol);
|
||||
for (j = 0; j < nCol; j++)
|
||||
{
|
||||
int idx = pIdx.aiColumn[j];
|
||||
if (idx == pTab.iPKey)
|
||||
{
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy, regBase + nCol, regBase + j);
|
||||
}
|
||||
else
|
||||
{
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iCur, idx, regBase + j);
|
||||
sqlite3ColumnDefault(v, pTab, idx, -1);
|
||||
}
|
||||
}
|
||||
if (doMakeRec)
|
||||
{
|
||||
string zAff;
|
||||
if (pTab.pSelect != null || (pParse.db.flags & SQLITE_IdxRealAsInt) != 0)
|
||||
{
|
||||
zAff = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
zAff = sqlite3IndexAffinityStr(v, pIdx);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol + 1, regOut);
|
||||
sqlite3VdbeChangeP4(v, -1, zAff, P4_TRANSIENT);
|
||||
}
|
||||
sqlite3ReleaseTempRange(pParse, regBase, nCol + 1);
|
||||
return regBase;
|
||||
}
|
||||
}
|
||||
}
|
||||
4547
original/Community.CsharpSqlite/src/expr_c.cs
Normal file
4547
original/Community.CsharpSqlite/src/expr_c.cs
Normal file
File diff suppressed because it is too large
Load diff
121
original/Community.CsharpSqlite/src/fault_c.cs
Normal file
121
original/Community.CsharpSqlite/src/fault_c.cs
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2008 Jan 22
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
*************************************************************************
|
||||
**
|
||||
** This file contains code to support the concept of "benign"
|
||||
** malloc failures (when the xMalloc() or xRealloc() method of the
|
||||
** sqlite3_mem_methods structure fails to allocate a block of memory
|
||||
** and returns 0).
|
||||
**
|
||||
** Most malloc failures are non-benign. After they occur, SQLite
|
||||
** abandons the current operation and returns an error code (usually
|
||||
** SQLITE_NOMEM) to the user. However, sometimes a fault is not necessarily
|
||||
** fatal. For example, if a malloc fails while resizing a hash table, this
|
||||
** is completely recoverable simply by not carrying out the resize. The
|
||||
** hash table will continue to function normally. So a malloc failure
|
||||
** during a hash table resize is a benign fault.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2010-08-23 18:52:01 42537b60566f288167f1b5864a5435986838e3a3
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#include "sqliteInt.h"
|
||||
|
||||
#if !SQLITE_OMIT_BUILTIN_TEST
|
||||
/*
|
||||
** Global variables.
|
||||
*/
|
||||
|
||||
//typedef struct BenignMallocHooks BenignMallocHooks;
|
||||
public struct BenignMallocHooks//
|
||||
{
|
||||
public void_function xBenignBegin;//void (*xBenignBegin)(void);
|
||||
public void_function xBenignEnd; //void (*xBenignEnd)(void);
|
||||
|
||||
public BenignMallocHooks(void_function xBenignBegin, void_function xBenignEnd)
|
||||
{
|
||||
this.xBenignBegin = xBenignBegin;
|
||||
this.xBenignEnd = xBenignEnd;
|
||||
}
|
||||
}
|
||||
|
||||
private static BenignMallocHooks sqlite3Hooks = new BenignMallocHooks(null, null);
|
||||
|
||||
/* The "wsdHooks" macro will resolve to the appropriate BenignMallocHooks
|
||||
** structure. If writable static data is unsupported on the target,
|
||||
** we have to locate the state vector at run-time. In the more common
|
||||
** case where writable static data is supported, wsdHooks can refer directly
|
||||
** to the "sqlite3Hooks" state vector declared above.
|
||||
*/
|
||||
#if SQLITE_OMIT_WSD
|
||||
//# define wsdHooksInit \
|
||||
BenignMallocHooks *x = &GLOBAL(BenignMallocHooks,sqlite3Hooks)
|
||||
//# define wsdHooks x[0]
|
||||
#else
|
||||
|
||||
//# define wsdHooksInit
|
||||
private static void wsdHooksInit()
|
||||
{
|
||||
}
|
||||
|
||||
//# define wsdHooks sqlite3Hooks
|
||||
private static BenignMallocHooks wsdHooks = sqlite3Hooks;
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Register hooks to call when sqlite3BeginBenignMalloc() and
|
||||
** sqlite3EndBenignMalloc() are called, respectively.
|
||||
*/
|
||||
|
||||
private static void sqlite3BenignMallocHooks(
|
||||
void_function xBenignBegin, //void (*xBenignBegin)(void),
|
||||
void_function xBenignEnd //void (*xBenignEnd)(void)
|
||||
)
|
||||
{
|
||||
wsdHooksInit();
|
||||
wsdHooks.xBenignBegin = xBenignBegin;
|
||||
wsdHooks.xBenignEnd = xBenignEnd;
|
||||
}
|
||||
|
||||
/*
|
||||
** This (sqlite3EndBenignMalloc()) is called by SQLite code to indicate that
|
||||
** subsequent malloc failures are benign. A call to sqlite3EndBenignMalloc()
|
||||
** indicates that subsequent malloc failures are non-benign.
|
||||
*/
|
||||
|
||||
private static void sqlite3BeginBenignMalloc()
|
||||
{
|
||||
wsdHooksInit();
|
||||
if (wsdHooks.xBenignBegin != null)
|
||||
{
|
||||
wsdHooks.xBenignBegin();
|
||||
}
|
||||
}
|
||||
|
||||
private static void sqlite3EndBenignMalloc()
|
||||
{
|
||||
wsdHooksInit();
|
||||
if (wsdHooks.xBenignEnd != null)
|
||||
{
|
||||
wsdHooks.xBenignEnd();
|
||||
}
|
||||
}
|
||||
|
||||
#endif //* SQLITE_OMIT_BUILTIN_TEST */
|
||||
}
|
||||
}
|
||||
1384
original/Community.CsharpSqlite/src/fkey_c.cs
Normal file
1384
original/Community.CsharpSqlite/src/fkey_c.cs
Normal file
File diff suppressed because it is too large
Load diff
2198
original/Community.CsharpSqlite/src/func_c.cs
Normal file
2198
original/Community.CsharpSqlite/src/func_c.cs
Normal file
File diff suppressed because it is too large
Load diff
245
original/Community.CsharpSqlite/src/global_c.cs
Normal file
245
original/Community.CsharpSqlite/src/global_c.cs
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2008 June 13
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This file contains definitions of global variables and contants.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#include "sqliteInt.h"
|
||||
|
||||
/* An array to map all upper-case characters into their corresponding
|
||||
** lower-case character.
|
||||
**
|
||||
** SQLite only considers US-ASCII (or EBCDIC) characters. We do not
|
||||
** handle case conversions for the UTF character set since the tables
|
||||
** involved are nearly as big or bigger than SQLite itself.
|
||||
*/
|
||||
/* An array to map all upper-case characters into their corresponding
|
||||
** lower-case character.
|
||||
*/
|
||||
//
|
||||
// Replaced in C# with sqlite3UpperToLower class
|
||||
// static int[] sqlite3UpperToLower = new int[] {
|
||||
//#if SQLITE_ASCII
|
||||
//0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
|
||||
//18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
|
||||
//36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
|
||||
//54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103,
|
||||
//104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,
|
||||
//122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,
|
||||
//108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,
|
||||
//126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
|
||||
//144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,
|
||||
//162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,
|
||||
//180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,
|
||||
//198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,
|
||||
//216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,
|
||||
//234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,
|
||||
//252,253,254,255
|
||||
//#endif
|
||||
//#if SQLITE_EBCDIC
|
||||
//0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 0x */
|
||||
//16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 1x */
|
||||
//32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 2x */
|
||||
//48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 3x */
|
||||
//64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 4x */
|
||||
//80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 5x */
|
||||
//96, 97, 66, 67, 68, 69, 70, 71, 72, 73,106,107,108,109,110,111, /* 6x */
|
||||
//112, 81, 82, 83, 84, 85, 86, 87, 88, 89,122,123,124,125,126,127, /* 7x */
|
||||
//128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, /* 8x */
|
||||
//144,145,146,147,148,149,150,151,152,153,154,155,156,157,156,159, /* 9x */
|
||||
//160,161,162,163,164,165,166,167,168,169,170,171,140,141,142,175, /* Ax */
|
||||
//176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, /* Bx */
|
||||
//192,129,130,131,132,133,134,135,136,137,202,203,204,205,206,207, /* Cx */
|
||||
//208,145,146,147,148,149,150,151,152,153,218,219,220,221,222,223, /* Dx */
|
||||
//224,225,162,163,164,165,166,167,168,169,232,203,204,205,206,207, /* Ex */
|
||||
//239,240,241,242,243,244,245,246,247,248,249,219,220,221,222,255, /* Fx */
|
||||
//#endif
|
||||
//};
|
||||
|
||||
/*
|
||||
** The following 256 byte lookup table is used to support SQLites built-in
|
||||
** equivalents to the following standard library functions:
|
||||
**
|
||||
** isspace() 0x01
|
||||
** isalpha() 0x02
|
||||
** isdigit() 0x04
|
||||
** isalnum() 0x06
|
||||
** isxdigit() 0x08
|
||||
** toupper() 0x20
|
||||
** SQLite identifier character 0x40
|
||||
**
|
||||
** Bit 0x20 is set if the mapped character requires translation to upper
|
||||
** case. i.e. if the character is a lower-case ASCII character.
|
||||
** If x is a lower-case ASCII character, then its upper-case equivalent
|
||||
** is (x - 0x20). Therefore toupper() can be implemented as:
|
||||
**
|
||||
** (x & ~(map[x]&0x20))
|
||||
**
|
||||
** Standard function tolower() is implemented using the sqlite3UpperToLower[]
|
||||
** array. tolower() is used more often than toupper() by SQLite.
|
||||
**
|
||||
** Bit 0x40 is set if the character non-alphanumeric and can be used in an
|
||||
** SQLite identifier. Identifiers are alphanumerics, "_", "$", and any
|
||||
** non-ASCII UTF character. Hence the test for whether or not a character is
|
||||
** part of an identifier is 0x46.
|
||||
**
|
||||
** SQLite's versions are identical to the standard versions assuming a
|
||||
** locale of "C". They are implemented as macros in sqliteInt.h.
|
||||
*/
|
||||
#if SQLITE_ASCII
|
||||
|
||||
private static byte[] sqlite3CtypeMap = new byte[] {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00..07 ........ */
|
||||
0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, /* 08..0f ........ */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10..17 ........ */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 18..1f ........ */
|
||||
0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, /* 20..27 !"#$%&' */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 28..2f ()*+,-./ */
|
||||
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, /* 30..37 01234567 */
|
||||
0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 38..3f 89:;<=>? */
|
||||
|
||||
0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x02, /* 40..47 @ABCDEFG */
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 48..4f HIJKLMNO */
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 50..57 PQRSTUVW */
|
||||
0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x40, /* 58..5f XYZ[\]^_ */
|
||||
0x00, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x22, /* 60..67 `abcdefg */
|
||||
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 68..6f hijklmno */
|
||||
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 70..77 pqrstuvw */
|
||||
0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, /* 78..7f xyz{|}~. */
|
||||
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 80..87 ........ */
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 88..8f ........ */
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 90..97 ........ */
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 98..9f ........ */
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* a0..a7 ........ */
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* a8..af ........ */
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* b0..b7 ........ */
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* b8..bf ........ */
|
||||
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* c0..c7 ........ */
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* c8..cf ........ */
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* d0..d7 ........ */
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* d8..df ........ */
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* e0..e7 ........ */
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* e8..ef ........ */
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* f0..f7 ........ */
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 /* f8..ff ........ */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#if SQLITE_USE_URI
|
||||
const bool SQLITE_USE_URI = true;
|
||||
#else
|
||||
|
||||
//# define SQLITE_USE_URI 0
|
||||
private const bool SQLITE_USE_URI = false;
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The following singleton contains the global configuration for
|
||||
** the SQLite library.
|
||||
*/
|
||||
|
||||
private static Sqlite3Config sqlite3Config = new Sqlite3Config(
|
||||
SQLITE_DEFAULT_MEMSTATUS, /* bMemstat */
|
||||
1, /* bCoreMutex */
|
||||
SQLITE_THREADSAFE != 0, /* bFullMutex */
|
||||
SQLITE_USE_URI, /* bOpenUri */
|
||||
0x7ffffffe, /* mxStrlen */
|
||||
100, /* szLookaside */
|
||||
500, /* nLookaside */
|
||||
new sqlite3_mem_methods(), /* m */
|
||||
new sqlite3_mutex_methods(null, null, null, null, null, null, null, null, null), /* mutex */
|
||||
new sqlite3_pcache_methods(),/* pcache */
|
||||
null, /* pHeap */
|
||||
0, /* nHeap */
|
||||
0, 0, /* mnHeap, mxHeap */
|
||||
null, /* pScratch */
|
||||
0, /* szScratch */
|
||||
0, /* nScratch */
|
||||
null, /* pPage */
|
||||
SQLITE_DEFAULT_PAGE_SIZE, /* szPage */
|
||||
0, /* nPage */
|
||||
0, /* mxParserStack */
|
||||
false, /* sharedCacheEnabled */
|
||||
/* All the rest should always be initialized to zero */
|
||||
0, /* isInit */
|
||||
0, /* inProgress */
|
||||
0, /* isMutexInit */
|
||||
0, /* isMallocInit */
|
||||
0, /* isPCacheInit */
|
||||
null, /* pInitMutex */
|
||||
0, /* nRefInitMutex */
|
||||
null, /* xLog */
|
||||
0, /* pLogArg */
|
||||
false /* bLocaltimeFault */
|
||||
);
|
||||
|
||||
/*
|
||||
** Hash table for global functions - functions common to all
|
||||
** database connections. After initialization, this table is
|
||||
** read-only.
|
||||
*/
|
||||
private static FuncDefHash sqlite3GlobalFunctions;
|
||||
/*
|
||||
** Constant tokens for values 0 and 1.
|
||||
*/
|
||||
|
||||
private static Token[] sqlite3IntTokens = {
|
||||
new Token( "0", 1 ),
|
||||
new Token( "1", 1 )
|
||||
};
|
||||
|
||||
/*
|
||||
** The value of the "pending" byte must be 0x40000000 (1 byte past the
|
||||
** 1-gibabyte boundary) in a compatible database. SQLite never uses
|
||||
** the database page that contains the pending byte. It never attempts
|
||||
** to read or write that page. The pending byte page is set assign
|
||||
** for use by the VFS layers as space for managing file locks.
|
||||
**
|
||||
** During testing, it is often desirable to move the pending byte to
|
||||
** a different position in the file. This allows code that has to
|
||||
** deal with the pending byte to run on files that are much smaller
|
||||
** than 1 GiB. The sqlite3_test_control() interface can be used to
|
||||
** move the pending byte.
|
||||
**
|
||||
** IMPORTANT: Changing the pending byte to any value other than
|
||||
** 0x40000000 results in an incompatible database file format!
|
||||
** Changing the pending byte during operating results in undefined
|
||||
** and dileterious behavior.
|
||||
*/
|
||||
#if !SQLITE_OMIT_WSD
|
||||
private static int sqlite3PendingByte = 0x40000000;
|
||||
#endif
|
||||
|
||||
//#include "opcodes.h"
|
||||
/*
|
||||
** Properties of opcodes. The OPFLG_INITIALIZER macro is
|
||||
** created by mkopcodeh.awk during compilation. Data is obtained
|
||||
** from the comments following the "case OP_xxxx:" statements in
|
||||
** the vdbe.c file.
|
||||
*/
|
||||
public static int[] sqlite3OpcodeProperty;
|
||||
}
|
||||
}
|
||||
368
original/Community.CsharpSqlite/src/hash_c.cs
Normal file
368
original/Community.CsharpSqlite/src/hash_c.cs
Normal file
|
|
@ -0,0 +1,368 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
using u32 = System.UInt32;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2001 September 22
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This is the implementation of generic hash-tables
|
||||
** used in SQLite.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2010-08-23 18:52:01 42537b60566f288167f1b5864a5435986838e3a3
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#include "sqliteInt.h"
|
||||
//#include <assert.h>
|
||||
|
||||
/* Turn bulk memory into a hash table object by initializing the
|
||||
** fields of the Hash structure.
|
||||
**
|
||||
** "pNew" is a pointer to the hash table that is to be initialized.
|
||||
*/
|
||||
|
||||
private static void sqlite3HashInit(Hash pNew)
|
||||
{
|
||||
Debug.Assert(pNew != null);
|
||||
pNew.first = null;
|
||||
pNew.count = 0;
|
||||
pNew.htsize = 0;
|
||||
pNew.ht = null;
|
||||
}
|
||||
|
||||
/* Remove all entries from a hash table. Reclaim all memory.
|
||||
** Call this routine to delete a hash table or to reset a hash table
|
||||
** to the empty state.
|
||||
*/
|
||||
|
||||
private static void sqlite3HashClear(Hash pH)
|
||||
{
|
||||
HashElem elem; /* For looping over all elements of the table */
|
||||
|
||||
Debug.Assert(pH != null);
|
||||
elem = pH.first;
|
||||
pH.first = null;
|
||||
//sqlite3_free( ref pH.ht );
|
||||
pH.ht = null;
|
||||
pH.htsize = 0;
|
||||
while (elem != null)
|
||||
{
|
||||
HashElem next_elem = elem.next;
|
||||
////sqlite3_free(ref elem );
|
||||
elem = next_elem;
|
||||
}
|
||||
pH.count = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** The hashing function.
|
||||
*/
|
||||
|
||||
private static u32 strHash(string z, int nKey)
|
||||
{
|
||||
int h = 0;
|
||||
Debug.Assert(nKey >= 0);
|
||||
int _z = 0;
|
||||
while (nKey > 0)
|
||||
{
|
||||
h = (h << 3) ^ h ^ ((_z < z.Length) ? (int)sqlite3UpperToLower[(byte)z[_z++]] : 0);
|
||||
nKey--;
|
||||
}
|
||||
return (u32)h;
|
||||
}
|
||||
|
||||
/* Link pNew element into the hash table pH. If pEntry!=0 then also
|
||||
** insert pNew into the pEntry hash bucket.
|
||||
*/
|
||||
|
||||
private static void insertElement(
|
||||
Hash pH, /* The complete hash table */
|
||||
_ht pEntry, /* The entry into which pNew is inserted */
|
||||
HashElem pNew /* The element to be inserted */
|
||||
)
|
||||
{
|
||||
HashElem pHead; /* First element already in pEntry */
|
||||
if (pEntry != null)
|
||||
{
|
||||
pHead = pEntry.count != 0 ? pEntry.chain : null;
|
||||
pEntry.count++;
|
||||
pEntry.chain = pNew;
|
||||
}
|
||||
else
|
||||
{
|
||||
pHead = null;
|
||||
}
|
||||
if (pHead != null)
|
||||
{
|
||||
pNew.next = pHead;
|
||||
pNew.prev = pHead.prev;
|
||||
if (pHead.prev != null)
|
||||
{
|
||||
pHead.prev.next = pNew;
|
||||
}
|
||||
else
|
||||
{
|
||||
pH.first = pNew;
|
||||
}
|
||||
pHead.prev = pNew;
|
||||
}
|
||||
else
|
||||
{
|
||||
pNew.next = pH.first;
|
||||
if (pH.first != null)
|
||||
{
|
||||
pH.first.prev = pNew;
|
||||
}
|
||||
pNew.prev = null;
|
||||
pH.first = pNew;
|
||||
}
|
||||
}
|
||||
|
||||
/* Resize the hash table so that it cantains "new_size" buckets.
|
||||
**
|
||||
** The hash table might fail to resize if sqlite3_malloc() fails or
|
||||
** if the new size is the same as the prior size.
|
||||
** Return TRUE if the resize occurs and false if not.
|
||||
*/
|
||||
|
||||
private static bool rehash(ref Hash pH, u32 new_size)
|
||||
{
|
||||
_ht[] new_ht; /* The new hash table */
|
||||
HashElem elem;
|
||||
HashElem next_elem; /* For looping over existing elements */
|
||||
|
||||
#if SQLITE_MALLOC_SOFT_LIMIT
|
||||
if( new_size*sizeof(struct _ht)>SQLITE_MALLOC_SOFT_LIMIT ){
|
||||
new_size = SQLITE_MALLOC_SOFT_LIMIT/sizeof(struct _ht);
|
||||
}
|
||||
if( new_size==pH->htsize ) return false;
|
||||
#endif
|
||||
|
||||
/* There is a call to sqlite3Malloc() inside rehash(). If there is
|
||||
** already an allocation at pH.ht, then if this malloc() fails it
|
||||
** is benign (since failing to resize a hash table is a performance
|
||||
** hit only, not a fatal error).
|
||||
*/
|
||||
sqlite3BeginBenignMalloc();
|
||||
new_ht = new _ht[new_size]; //(struct _ht )sqlite3Malloc( new_size*sizeof(struct _ht) );
|
||||
for (int i = 0; i < new_size; i++)
|
||||
new_ht[i] = new _ht();
|
||||
sqlite3EndBenignMalloc();
|
||||
|
||||
if (new_ht == null)
|
||||
return false;
|
||||
//sqlite3_free( ref pH.ht );
|
||||
pH.ht = new_ht;
|
||||
// pH.htsize = new_size = sqlite3MallocSize(new_ht)/sizeof(struct _ht);
|
||||
//memset(new_ht, 0, new_size*sizeof(struct _ht));
|
||||
pH.htsize = new_size;
|
||||
|
||||
for (elem = pH.first, pH.first = null; elem != null; elem = next_elem)
|
||||
{
|
||||
u32 h = strHash(elem.pKey, elem.nKey) % new_size;
|
||||
next_elem = elem.next;
|
||||
insertElement(pH, new_ht[h], elem);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* This function (for internal use only) locates an element in an
|
||||
** hash table that matches the given key. The hash for this key has
|
||||
** already been computed and is passed as the 4th parameter.
|
||||
*/
|
||||
|
||||
private static HashElem findElementGivenHash(
|
||||
Hash pH, /* The pH to be searched */
|
||||
string pKey, /* The key we are searching for */
|
||||
int nKey, /* Bytes in key (not counting zero terminator) */
|
||||
u32 h /* The hash for this key. */
|
||||
)
|
||||
{
|
||||
HashElem elem; /* Used to loop thru the element list */
|
||||
int count; /* Number of elements left to test */
|
||||
|
||||
if (pH.ht != null && pH.ht[h] != null)
|
||||
{
|
||||
_ht pEntry = pH.ht[h];
|
||||
elem = pEntry.chain;
|
||||
count = (int)pEntry.count;
|
||||
}
|
||||
else
|
||||
{
|
||||
elem = pH.first;
|
||||
count = (int)pH.count;
|
||||
}
|
||||
while (count-- > 0 && ALWAYS(elem))
|
||||
{
|
||||
if (elem.nKey == nKey && elem.pKey.Equals(pKey, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return elem;
|
||||
}
|
||||
elem = elem.next;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* Remove a single entry from the hash table given a pointer to that
|
||||
** element and a hash on the element's key.
|
||||
*/
|
||||
|
||||
private static void removeElementGivenHash(
|
||||
Hash pH, /* The pH containing "elem" */
|
||||
ref HashElem elem, /* The element to be removed from the pH */
|
||||
u32 h /* Hash value for the element */
|
||||
)
|
||||
{
|
||||
_ht pEntry;
|
||||
if (elem.prev != null)
|
||||
{
|
||||
elem.prev.next = elem.next;
|
||||
}
|
||||
else
|
||||
{
|
||||
pH.first = elem.next;
|
||||
}
|
||||
if (elem.next != null)
|
||||
{
|
||||
elem.next.prev = elem.prev;
|
||||
}
|
||||
if (pH.ht != null && pH.ht[h] != null)
|
||||
{
|
||||
pEntry = pH.ht[h];
|
||||
if (pEntry.chain == elem)
|
||||
{
|
||||
pEntry.chain = elem.next;
|
||||
}
|
||||
pEntry.count--;
|
||||
Debug.Assert(pEntry.count >= 0);
|
||||
}
|
||||
//sqlite3_free( ref elem );
|
||||
pH.count--;
|
||||
if (pH.count <= 0)
|
||||
{
|
||||
Debug.Assert(pH.first == null);
|
||||
Debug.Assert(pH.count == 0);
|
||||
sqlite3HashClear(pH);
|
||||
}
|
||||
}
|
||||
|
||||
/* Attempt to locate an element of the hash table pH with a key
|
||||
** that matches pKey,nKey. Return the data for this element if it is
|
||||
** found, or NULL if there is no match.
|
||||
*/
|
||||
|
||||
private static T sqlite3HashFind<T>(Hash pH, string pKey, int nKey, T nullType) where T : class
|
||||
{
|
||||
HashElem elem; /* The element that matches key */
|
||||
u32 h; /* A hash on key */
|
||||
|
||||
Debug.Assert(pH != null);
|
||||
Debug.Assert(pKey != null);
|
||||
Debug.Assert(nKey >= 0);
|
||||
if (pH.ht != null)
|
||||
{
|
||||
h = strHash(pKey, nKey) % pH.htsize;
|
||||
}
|
||||
else
|
||||
{
|
||||
h = 0;
|
||||
}
|
||||
elem = findElementGivenHash(pH, pKey, nKey, h);
|
||||
return elem != null ? (T)elem.data : nullType;
|
||||
}
|
||||
|
||||
/* Insert an element into the hash table pH. The key is pKey,nKey
|
||||
** and the data is "data".
|
||||
**
|
||||
** If no element exists with a matching key, then a new
|
||||
** element is created and NULL is returned.
|
||||
**
|
||||
** If another element already exists with the same key, then the
|
||||
** new data replaces the old data and the old data is returned.
|
||||
** The key is not copied in this instance. If a malloc fails, then
|
||||
** the new data is returned and the hash table is unchanged.
|
||||
**
|
||||
** If the "data" parameter to this function is NULL, then the
|
||||
** element corresponding to "key" is removed from the hash table.
|
||||
*/
|
||||
|
||||
private static T sqlite3HashInsert<T>(ref Hash pH, string pKey, int nKey, T data) where T : class
|
||||
{
|
||||
u32 h; /* the hash of the key modulo hash table size */
|
||||
|
||||
HashElem elem; /* Used to loop thru the element list */
|
||||
HashElem new_elem; /* New element added to the pH */
|
||||
|
||||
Debug.Assert(pH != null);
|
||||
Debug.Assert(pKey != null);
|
||||
Debug.Assert(nKey >= 0);
|
||||
|
||||
if (pH.htsize != 0)
|
||||
{
|
||||
h = strHash(pKey, nKey) % pH.htsize;
|
||||
}
|
||||
else
|
||||
{
|
||||
h = 0;
|
||||
}
|
||||
elem = findElementGivenHash(pH, pKey, nKey, h);
|
||||
if (elem != null)
|
||||
{
|
||||
T old_data = (T)elem.data;
|
||||
if (data == null)
|
||||
{
|
||||
removeElementGivenHash(pH, ref elem, h);
|
||||
}
|
||||
else
|
||||
{
|
||||
elem.data = data;
|
||||
elem.pKey = pKey;
|
||||
Debug.Assert(nKey == elem.nKey);
|
||||
}
|
||||
return old_data;
|
||||
}
|
||||
if (data == null)
|
||||
return data;
|
||||
new_elem = new HashElem();//(HashElem)sqlite3Malloc( sizeof(HashElem) );
|
||||
if (new_elem == null)
|
||||
return data;
|
||||
new_elem.pKey = pKey;
|
||||
new_elem.nKey = nKey;
|
||||
new_elem.data = data;
|
||||
pH.count++;
|
||||
if (pH.count >= 10 && pH.count > 2 * pH.htsize)
|
||||
{
|
||||
if (rehash(ref pH, pH.count * 2))
|
||||
{
|
||||
Debug.Assert(pH.htsize > 0);
|
||||
h = strHash(pKey, nKey) % pH.htsize;
|
||||
}
|
||||
}
|
||||
if (pH.ht != null)
|
||||
{
|
||||
insertElement(pH, pH.ht[h], new_elem);
|
||||
}
|
||||
else
|
||||
{
|
||||
insertElement(pH, null, new_elem);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
104
original/Community.CsharpSqlite/src/hwtime_c.cs
Normal file
104
original/Community.CsharpSqlite/src/hwtime_c.cs
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
namespace Community.CsharpSqlite
|
||||
{
|
||||
using sqlite_u3264 = System.UInt64;
|
||||
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 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 class CPUs.
|
||||
**
|
||||
** $Id: hwtime.h,v 1.3 2008/08/01 14:33:15 shane Exp $
|
||||
**
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#if !_HWTIME_H_
|
||||
//#define _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 ((__GNUC__) || (_MSC_VER)) && ((i386) || (__i386__) || (_M_IX86))
|
||||
|
||||
#if (__GNUC__)
|
||||
|
||||
__inline__ sqlite_u3264 sqlite3Hwtime(void){
|
||||
unsigned int lo, hi;
|
||||
__asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
|
||||
return (sqlite_u3264)hi << 32 | lo;
|
||||
}
|
||||
|
||||
#elif (_MSC_VER)
|
||||
|
||||
__declspec(naked) __inline sqlite_u3264 __cdecl sqlite3Hwtime(void){
|
||||
__asm {
|
||||
rdtsc
|
||||
ret ; return value at EDX:EAX
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#elif ((__GNUC__) && (__x86_64__))
|
||||
|
||||
__inline__ sqlite_u3264 sqlite3Hwtime(void){
|
||||
unsigned long val;
|
||||
__asm__ __volatile__ ("rdtsc" : "=A" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
#elif ( (__GNUC__) && (__ppc__))
|
||||
|
||||
__inline__ sqlite_u3264 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
|
||||
|
||||
//#error Need implementation of sqlite3Hwtime() for your platform.
|
||||
|
||||
/*
|
||||
** To compile without implementing sqlite3Hwtime() for your platform,
|
||||
** you can remove the above #error and use the following
|
||||
** stub function. You will lose timing support for many
|
||||
** of the debugging and testing utilities, but it should at
|
||||
** least compile and run.
|
||||
*/
|
||||
|
||||
private static sqlite_u3264 sqlite3Hwtime()
|
||||
{
|
||||
return (sqlite_u3264)System.DateTime.Now.Ticks;
|
||||
}// (sqlite_u3264)0 ); }
|
||||
|
||||
#endif
|
||||
|
||||
//#endif //* !_HWTIME_H_) */
|
||||
}
|
||||
}
|
||||
2183
original/Community.CsharpSqlite/src/insert_c.cs
Normal file
2183
original/Community.CsharpSqlite/src/insert_c.cs
Normal file
File diff suppressed because it is too large
Load diff
250
original/Community.CsharpSqlite/src/journal_c.cs
Normal file
250
original/Community.CsharpSqlite/src/journal_c.cs
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2007 August 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 implements a special kind of sqlite3_file object used
|
||||
** by SQLite to create journal files if the atomic-write optimization
|
||||
** is enabled.
|
||||
**
|
||||
** The distinctive characteristic of this sqlite3_file is that the
|
||||
** actual on disk file is created lazily. When the file is created,
|
||||
** the caller specifies a buffer size for an in-memory buffer to
|
||||
** be used to service read() and write() requests. The actual file
|
||||
** on disk is not created or populated until either:
|
||||
**
|
||||
** 1) The in-memory representation grows too large for the allocated
|
||||
** buffer, or
|
||||
** 2) The sqlite3JournalCreate() function is called.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2010-08-23 18:52:01 42537b60566f288167f1b5864a5435986838e3a3
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
#if SQLITE_ENABLE_ATOMIC_WRITE
|
||||
//#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** A JournalFile object is a subclass of sqlite3_file used by
|
||||
** as an open file handle for journal files.
|
||||
*/
|
||||
struct JournalFile {
|
||||
sqlite3_io_methods pMethod; /* I/O methods on journal files */
|
||||
int nBuf; /* Size of zBuf[] in bytes */
|
||||
string zBuf; /* Space to buffer journal writes */
|
||||
int iSize; /* Amount of zBuf[] currently used */
|
||||
int flags; /* xOpen flags */
|
||||
sqlite3_vfs pVfs; /* The "real" underlying VFS */
|
||||
sqlite3_file pReal; /* The "real" underlying file descriptor */
|
||||
string zJournal; /* Name of the journal file */
|
||||
};
|
||||
typedef struct JournalFile JournalFile;
|
||||
|
||||
/*
|
||||
** If it does not already exists, create and populate the on-disk file
|
||||
** for JournalFile p.
|
||||
*/
|
||||
static int createFile(JournalFile p){
|
||||
int rc = SQLITE_OK;
|
||||
if( null==p.pReal ){
|
||||
sqlite3_file pReal = (sqlite3_file )&p[1];
|
||||
rc = sqlite3OsOpen(p.pVfs, p.zJournal, pReal, p.flags, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
p.pReal = pReal;
|
||||
if( p.iSize>0 ){
|
||||
Debug.Assert(p.iSize<=p.nBuf);
|
||||
rc = sqlite3OsWrite(p.pReal, p.zBuf, p.iSize, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Close the file.
|
||||
*/
|
||||
static int jrnlClose(sqlite3_file pJfd){
|
||||
JournalFile p = (JournalFile )pJfd;
|
||||
if( p.pReal ){
|
||||
sqlite3OsClose(p.pReal);
|
||||
}
|
||||
sqlite3DbFree(db,p.zBuf);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Read data from the file.
|
||||
*/
|
||||
static int jrnlRead(
|
||||
sqlite3_file *pJfd, /* The journal file from which to read */
|
||||
void *zBuf, /* Put the results here */
|
||||
int iAmt, /* Number of bytes to read */
|
||||
sqlite_int64 iOfst /* Begin reading at this offset */
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
JournalFile *p = (JournalFile )pJfd;
|
||||
if( p->pReal ){
|
||||
rc = sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst);
|
||||
}else if( (iAmt+iOfst)>p->iSize ){
|
||||
rc = SQLITE_IOERR_SHORT_READ;
|
||||
}else{
|
||||
memcpy(zBuf, &p->zBuf[iOfst], iAmt);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Write data to the file.
|
||||
*/
|
||||
static int jrnlWrite(
|
||||
sqlite3_file pJfd, /* The journal file into which to write */
|
||||
string zBuf, /* Take data to be written from here */
|
||||
int iAmt, /* Number of bytes to write */
|
||||
sqlite_int64 iOfst /* Begin writing at this offset into the file */
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
JournalFile p = (JournalFile )pJfd;
|
||||
if( null==p.pReal && (iOfst+iAmt)>p.nBuf ){
|
||||
rc = createFile(p);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
if( p.pReal ){
|
||||
rc = sqlite3OsWrite(p.pReal, zBuf, iAmt, iOfst);
|
||||
}else{
|
||||
memcpy(p.zBuf[iOfst], zBuf, iAmt);
|
||||
if( p.iSize<(iOfst+iAmt) ){
|
||||
p.iSize = (iOfst+iAmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Truncate the file.
|
||||
*/
|
||||
static int jrnlTruncate(sqlite3_file pJfd, sqlite_int64 size){
|
||||
int rc = SQLITE_OK;
|
||||
JournalFile p = (JournalFile )pJfd;
|
||||
if( p.pReal ){
|
||||
rc = sqlite3OsTruncate(p.pReal, size);
|
||||
}else if( size<p.iSize ){
|
||||
p.iSize = size;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Sync the file.
|
||||
*/
|
||||
static int jrnlSync(sqlite3_file pJfd, int flags){
|
||||
int rc;
|
||||
JournalFile p = (JournalFile )pJfd;
|
||||
if( p.pReal ){
|
||||
rc = sqlite3OsSync(p.pReal, flags);
|
||||
}else{
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Query the size of the file in bytes.
|
||||
*/
|
||||
static int jrnlFileSize(sqlite3_file pJfd, sqlite_int64 pSize){
|
||||
int rc = SQLITE_OK;
|
||||
JournalFile p = (JournalFile )pJfd;
|
||||
if( p.pReal ){
|
||||
rc = sqlite3OsFileSize(p.pReal, pSize);
|
||||
}else{
|
||||
pSize = (sqlite_int64) p.iSize;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Table of methods for JournalFile sqlite3_file object.
|
||||
*/
|
||||
static struct sqlite3_io_methods JournalFileMethods = {
|
||||
1, /* iVersion */
|
||||
jrnlClose, /* xClose */
|
||||
jrnlRead, /* xRead */
|
||||
jrnlWrite, /* xWrite */
|
||||
jrnlTruncate, /* xTruncate */
|
||||
jrnlSync, /* xSync */
|
||||
jrnlFileSize, /* xFileSize */
|
||||
0, /* xLock */
|
||||
0, /* xUnlock */
|
||||
0, /* xCheckReservedLock */
|
||||
0, /* xFileControl */
|
||||
0, /* xSectorSize */
|
||||
0, /* xDeviceCharacteristics */
|
||||
0, /* xShmMap */
|
||||
0, /* xShmLock */
|
||||
0, /* xShmBarrier */
|
||||
0 /* xShmUnmap */
|
||||
};
|
||||
|
||||
/*
|
||||
** Open a journal file.
|
||||
*/
|
||||
int sqlite3JournalOpen(
|
||||
sqlite3_vfs pVfs, /* The VFS to use for actual file I/O */
|
||||
string zName, /* Name of the journal file */
|
||||
sqlite3_file pJfd, /* Preallocated, blank file handle */
|
||||
int flags, /* Opening flags */
|
||||
int nBuf /* Bytes buffered before opening the file */
|
||||
){
|
||||
JournalFile p = (JournalFile )pJfd;
|
||||
memset(p, 0, sqlite3JournalSize(pVfs));
|
||||
if( nBuf>0 ){
|
||||
p.zBuf = sqlite3MallocZero(nBuf);
|
||||
if( null==p.zBuf ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
}else{
|
||||
return sqlite3OsOpen(pVfs, zName, pJfd, flags, 0);
|
||||
}
|
||||
p.pMethod = JournalFileMethods;
|
||||
p.nBuf = nBuf;
|
||||
p.flags = flags;
|
||||
p.zJournal = zName;
|
||||
p.pVfs = pVfs;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** If the argument p points to a JournalFile structure, and the underlying
|
||||
** file has not yet been created, create it now.
|
||||
*/
|
||||
int sqlite3JournalCreate(sqlite3_file p){
|
||||
if( p.pMethods!=&JournalFileMethods ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
return createFile((JournalFile )p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of bytes required to store a JournalFile that uses vfs
|
||||
** pVfs to create the underlying on-disk files.
|
||||
*/
|
||||
int sqlite3JournalSize(sqlite3_vfs pVfs){
|
||||
return (pVfs->szOsFile+sizeof(JournalFile));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
310
original/Community.CsharpSqlite/src/keywordhash_h.cs
Normal file
310
original/Community.CsharpSqlite/src/keywordhash_h.cs
Normal file
|
|
@ -0,0 +1,310 @@
|
|||
using System;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/***** This file contains automatically generated code ******
|
||||
**
|
||||
** The code in this file has been automatically generated by
|
||||
**
|
||||
** sqlite/tool/mkkeywordhash.c
|
||||
**
|
||||
** The code in this file implements a function that determines whether
|
||||
** or not a given identifier is really an SQL keyword. The same thing
|
||||
** might be implemented more directly using a hand-written hash table.
|
||||
** But by using this automatically generated code, the size of the code
|
||||
** is substantially reduced. This is important for embedded applications
|
||||
** on platforms with limited memory.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2010-08-23 18:52:01 42537b60566f288167f1b5864a5435986838e3a3
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
/* Hash score: 175 */
|
||||
/* zText[] encodes 811 bytes of keywords in 541 bytes */
|
||||
/* REINDEXEDESCAPEACHECKEYBEFOREIGNOREGEXPLAINSTEADDATABASELECT */
|
||||
/* ABLEFTHENDEFERRABLELSEXCEPTRANSACTIONATURALTERAISEXCLUSIVE */
|
||||
/* XISTSAVEPOINTERSECTRIGGEREFERENCESCONSTRAINTOFFSETEMPORARY */
|
||||
/* UNIQUERYATTACHAVINGROUPDATEBEGINNERELEASEBETWEENOTNULLIKE */
|
||||
/* CASCADELETECASECOLLATECREATECURRENT_DATEDETACHIMMEDIATEJOIN */
|
||||
/* SERTMATCHPLANALYZEPRAGMABORTVALUESVIRTUALIMITWHENWHERENAME */
|
||||
/* AFTEREPLACEANDEFAULTAUTOINCREMENTCASTCOLUMNCOMMITCONFLICTCROSS */
|
||||
/* CURRENT_TIMESTAMPRIMARYDEFERREDISTINCTDROPFAILFROMFULLGLOBYIF */
|
||||
/* ISNULLORDERESTRICTOUTERIGHTROLLBACKROWUNIONUSINGVACUUMVIEW */
|
||||
/* INITIALLY */
|
||||
|
||||
private static string zText = new string(new char[540] {
|
||||
'R','E','I','N','D','E','X','E','D','E','S','C','A','P','E','A','C','H',
|
||||
'E','C','K','E','Y','B','E','F','O','R','E','I','G','N','O','R','E','G',
|
||||
'E','X','P','L','A','I','N','S','T','E','A','D','D','A','T','A','B','A',
|
||||
'S','E','L','E','C','T','A','B','L','E','F','T','H','E','N','D','E','F',
|
||||
'E','R','R','A','B','L','E','L','S','E','X','C','E','P','T','R','A','N',
|
||||
'S','A','C','T','I','O','N','A','T','U','R','A','L','T','E','R','A','I',
|
||||
'S','E','X','C','L','U','S','I','V','E','X','I','S','T','S','A','V','E',
|
||||
'P','O','I','N','T','E','R','S','E','C','T','R','I','G','G',
|
||||
#if !SQLITE_OMIT_TRIGGER
|
||||
'E',
|
||||
#else
|
||||
'\0',
|
||||
#endif
|
||||
'R',
|
||||
#if !SQLITE_OMIT_FOREIGN_KEY
|
||||
'E',
|
||||
#else
|
||||
'\0',
|
||||
#endif
|
||||
'F','E','R','E','N','C','E','S','C','O','N','S','T','R','A','I','N','T',
|
||||
'O','F','F','S','E','T','E','M','P','O','R','A','R','Y','U','N','I','Q',
|
||||
'U','E','R','Y','A','T','T','A','C','H','A','V','I','N','G','R','O','U',
|
||||
'P','D','A','T','E','B','E','G','I','N','N','E','R','E','L','E','A','S',
|
||||
'E','B','E','T','W','E','E','N','O','T','N','U','L','L','I','K','E','C',
|
||||
'A','S','C','A','D','E','L','E','T','E','C','A','S','E','C','O','L','L',
|
||||
'A','T','E','C','R','E','A','T','E','C','U','R','R','E','N','T','_','D',
|
||||
'A','T','E','D','E','T','A','C','H','I','M','M','E','D','I','A','T','E',
|
||||
'J','O','I','N','S','E','R','T','M','A','T','C','H','P','L','A','N','A',
|
||||
'L','Y','Z','E','P','R','A','G','M','A','B','O','R','T','V','A','L','U',
|
||||
'E','S','V','I','R','T','U','A','L','I','M','I','T','W','H','E','N','W',
|
||||
'H','E','R','E','N','A','M','E','A','F','T','E','R','E','P','L','A','C',
|
||||
'E','A','N','D','E','F','A','U','L','T','A','U','T','O','I','N','C','R',
|
||||
'E','M','E','N','T','C','A','S','T','C','O','L','U','M','N','C','O','M',
|
||||
'M','I','T','C','O','N','F','L','I','C','T','C','R','O','S','S','C','U',
|
||||
'R','R','E','N','T','_','T','I','M','E','S','T','A','M','P','R','I','M',
|
||||
'A','R','Y','D','E','F','E','R','R','E','D','I','S','T','I','N','C','T',
|
||||
'D','R','O','P','F','A','I','L','F','R','O','M','F','U','L','L','G','L',
|
||||
'O','B','Y','I','F','I','S','N','U','L','L','O','R','D','E','R','E','S',
|
||||
'T','R','I','C','T','O','U','T','E','R','I','G','H','T','R','O','L','L',
|
||||
'B','A','C','K','R','O','W','U','N','I','O','N','U','S','I','N','G','V',
|
||||
'A','C','U','U','M','V','I','E','W','I','N','I','T','I','A','L','L','Y',
|
||||
});
|
||||
|
||||
private static byte[] aHash = { //aHash[127]
|
||||
72, 101, 114, 70, 0, 45, 0, 0, 78, 0, 73, 0, 0,
|
||||
42, 12, 74, 15, 0, 113, 81, 50, 108, 0, 19, 0, 0,
|
||||
118, 0, 116, 111, 0, 22, 89, 0, 9, 0, 0, 66, 67,
|
||||
0, 65, 6, 0, 48, 86, 98, 0, 115, 97, 0, 0, 44,
|
||||
0, 99, 24, 0, 17, 0, 119, 49, 23, 0, 5, 106, 25,
|
||||
92, 0, 0, 121, 102, 56, 120, 53, 28, 51, 0, 87, 0,
|
||||
96, 26, 0, 95, 0, 0, 0, 91, 88, 93, 84, 105, 14,
|
||||
39, 104, 0, 77, 0, 18, 85, 107, 32, 0, 117, 76, 109,
|
||||
58, 46, 80, 0, 0, 90, 40, 0, 112, 0, 36, 0, 0,
|
||||
29, 0, 82, 59, 60, 0, 20, 57, 0, 52,
|
||||
};
|
||||
|
||||
private static byte[] aNext = { //aNext[121]
|
||||
0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 2, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0,
|
||||
0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 33, 0, 21, 0, 0, 0, 43, 3, 47,
|
||||
0, 0, 0, 0, 30, 0, 54, 0, 38, 0, 0, 0, 1,
|
||||
62, 0, 0, 63, 0, 41, 0, 0, 0, 0, 0, 0, 0,
|
||||
61, 0, 0, 0, 0, 31, 55, 16, 34, 10, 0, 0, 0,
|
||||
0, 0, 0, 0, 11, 68, 75, 0, 8, 0, 100, 94, 0,
|
||||
103, 0, 83, 0, 71, 0, 0, 110, 27, 37, 69, 79, 0,
|
||||
35, 64, 0, 0,
|
||||
};
|
||||
|
||||
private static byte[] aLen = { //aLen[121]
|
||||
7, 7, 5, 4, 6, 4, 5, 3, 6, 7, 3, 6, 6,
|
||||
7, 7, 3, 8, 2, 6, 5, 4, 4, 3, 10, 4, 6,
|
||||
11, 6, 2, 7, 5, 5, 9, 6, 9, 9, 7, 10, 10,
|
||||
4, 6, 2, 3, 9, 4, 2, 6, 5, 6, 6, 5, 6,
|
||||
5, 5, 7, 7, 7, 3, 2, 4, 4, 7, 3, 6, 4,
|
||||
7, 6, 12, 6, 9, 4, 6, 5, 4, 7, 6, 5, 6,
|
||||
7, 5, 4, 5, 6, 5, 7, 3, 7, 13, 2, 2, 4,
|
||||
6, 6, 8, 5, 17, 12, 7, 8, 8, 2, 4, 4, 4,
|
||||
4, 4, 2, 2, 6, 5, 8, 5, 5, 8, 3, 5, 5,
|
||||
6, 4, 9, 3,
|
||||
};
|
||||
|
||||
private static int[] aOffset = { //aOffset[121]
|
||||
0, 2, 2, 8, 9, 14, 16, 20, 23, 25, 25, 29, 33,
|
||||
36, 41, 46, 48, 53, 54, 59, 62, 65, 67, 69, 78, 81,
|
||||
86, 91, 95, 96, 101, 105, 109, 117, 122, 128, 136, 142, 152,
|
||||
159, 162, 162, 165, 167, 167, 171, 176, 179, 184, 189, 194, 197,
|
||||
203, 206, 210, 217, 223, 223, 223, 226, 229, 233, 234, 238, 244,
|
||||
248, 255, 261, 273, 279, 288, 290, 296, 301, 303, 310, 315, 320,
|
||||
326, 332, 337, 341, 344, 350, 354, 361, 363, 370, 372, 374, 383,
|
||||
387, 393, 399, 407, 412, 412, 428, 435, 442, 443, 450, 454, 458,
|
||||
462, 466, 469, 471, 473, 479, 483, 491, 495, 500, 508, 511, 516,
|
||||
521, 527, 531, 536,
|
||||
};
|
||||
|
||||
private static byte[] aCode = { //aCode[121
|
||||
TK_REINDEX, TK_INDEXED, TK_INDEX, TK_DESC, TK_ESCAPE,
|
||||
TK_EACH, TK_CHECK, TK_KEY, TK_BEFORE, TK_FOREIGN,
|
||||
TK_FOR, TK_IGNORE, TK_LIKE_KW, TK_EXPLAIN, TK_INSTEAD,
|
||||
TK_ADD, TK_DATABASE, TK_AS, TK_SELECT, TK_TABLE,
|
||||
TK_JOIN_KW, TK_THEN, TK_END, TK_DEFERRABLE, TK_ELSE,
|
||||
TK_EXCEPT, TK_TRANSACTION,TK_ACTION, TK_ON, TK_JOIN_KW,
|
||||
TK_ALTER, TK_RAISE, TK_EXCLUSIVE, TK_EXISTS, TK_SAVEPOINT,
|
||||
TK_INTERSECT, TK_TRIGGER, TK_REFERENCES, TK_CONSTRAINT, TK_INTO,
|
||||
TK_OFFSET, TK_OF, TK_SET, TK_TEMP, TK_TEMP,
|
||||
TK_OR, TK_UNIQUE, TK_QUERY, TK_ATTACH, TK_HAVING,
|
||||
TK_GROUP, TK_UPDATE, TK_BEGIN, TK_JOIN_KW, TK_RELEASE,
|
||||
TK_BETWEEN, TK_NOTNULL, TK_NOT, TK_NO, TK_NULL,
|
||||
TK_LIKE_KW, TK_CASCADE, TK_ASC, TK_DELETE, TK_CASE,
|
||||
TK_COLLATE, TK_CREATE, TK_CTIME_KW, TK_DETACH, TK_IMMEDIATE,
|
||||
TK_JOIN, TK_INSERT, TK_MATCH, TK_PLAN, TK_ANALYZE,
|
||||
TK_PRAGMA, TK_ABORT, TK_VALUES, TK_VIRTUAL, TK_LIMIT,
|
||||
TK_WHEN, TK_WHERE, TK_RENAME, TK_AFTER, TK_REPLACE,
|
||||
TK_AND, TK_DEFAULT, TK_AUTOINCR, TK_TO, TK_IN,
|
||||
TK_CAST, TK_COLUMNKW, TK_COMMIT, TK_CONFLICT, TK_JOIN_KW,
|
||||
TK_CTIME_KW, TK_CTIME_KW, TK_PRIMARY, TK_DEFERRED, TK_DISTINCT,
|
||||
TK_IS, TK_DROP, TK_FAIL, TK_FROM, TK_JOIN_KW,
|
||||
TK_LIKE_KW, TK_BY, TK_IF, TK_ISNULL, TK_ORDER,
|
||||
TK_RESTRICT, TK_JOIN_KW, TK_JOIN_KW, TK_ROLLBACK, TK_ROW,
|
||||
TK_UNION, TK_USING, TK_VACUUM, TK_VIEW, TK_INITIALLY,
|
||||
TK_ALL,
|
||||
};
|
||||
|
||||
private static int keywordCode(string z, int iOffset, int n)
|
||||
{
|
||||
int h, i;
|
||||
if (n < 2)
|
||||
return TK_ID;
|
||||
h = ((sqlite3UpperToLower[z[iOffset + 0]]) * 4 ^//(charMap(z[iOffset+0]) * 4) ^
|
||||
(sqlite3UpperToLower[z[iOffset + n - 1]] * 3) ^ //(charMap(z[iOffset+n - 1]) * 3) ^
|
||||
n) % 127;
|
||||
for (i = (aHash[h]) - 1; i >= 0; i = (aNext[i]) - 1)
|
||||
{
|
||||
if (aLen[i] == n && String.Compare(zText, aOffset[i], z, iOffset, n, StringComparison.OrdinalIgnoreCase) == 0)
|
||||
{
|
||||
testcase(i == 0); /* REINDEX */
|
||||
testcase(i == 1); /* INDEXED */
|
||||
testcase(i == 2); /* INDEX */
|
||||
testcase(i == 3); /* DESC */
|
||||
testcase(i == 4); /* ESCAPE */
|
||||
testcase(i == 5); /* EACH */
|
||||
testcase(i == 6); /* CHECK */
|
||||
testcase(i == 7); /* KEY */
|
||||
testcase(i == 8); /* BEFORE */
|
||||
testcase(i == 9); /* FOREIGN */
|
||||
testcase(i == 10); /* FOR */
|
||||
testcase(i == 11); /* IGNORE */
|
||||
testcase(i == 12); /* REGEXP */
|
||||
testcase(i == 13); /* EXPLAIN */
|
||||
testcase(i == 14); /* INSTEAD */
|
||||
testcase(i == 15); /* ADD */
|
||||
testcase(i == 16); /* DATABASE */
|
||||
testcase(i == 17); /* AS */
|
||||
testcase(i == 18); /* SELECT */
|
||||
testcase(i == 19); /* TABLE */
|
||||
testcase(i == 20); /* LEFT */
|
||||
testcase(i == 21); /* THEN */
|
||||
testcase(i == 22); /* END */
|
||||
testcase(i == 23); /* DEFERRABLE */
|
||||
testcase(i == 24); /* ELSE */
|
||||
testcase(i == 25); /* EXCEPT */
|
||||
testcase(i == 26); /* TRANSACTION */
|
||||
testcase(i == 27); /* ACTION */
|
||||
testcase(i == 28); /* ON */
|
||||
testcase(i == 29); /* NATURAL */
|
||||
testcase(i == 30); /* ALTER */
|
||||
testcase(i == 31); /* RAISE */
|
||||
testcase(i == 32); /* EXCLUSIVE */
|
||||
testcase(i == 33); /* EXISTS */
|
||||
testcase(i == 34); /* SAVEPOINT */
|
||||
testcase(i == 35); /* INTERSECT */
|
||||
testcase(i == 36); /* TRIGGER */
|
||||
testcase(i == 37); /* REFERENCES */
|
||||
testcase(i == 38); /* CONSTRAINT */
|
||||
testcase(i == 39); /* INTO */
|
||||
testcase(i == 40); /* OFFSET */
|
||||
testcase(i == 41); /* OF */
|
||||
testcase(i == 42); /* SET */
|
||||
testcase(i == 43); /* TEMPORARY */
|
||||
testcase(i == 44); /* TEMP */
|
||||
testcase(i == 45); /* OR */
|
||||
testcase(i == 46); /* UNIQUE */
|
||||
testcase(i == 47); /* QUERY */
|
||||
testcase(i == 48); /* ATTACH */
|
||||
testcase(i == 49); /* HAVING */
|
||||
testcase(i == 50); /* GROUP */
|
||||
testcase(i == 51); /* UPDATE */
|
||||
testcase(i == 52); /* BEGIN */
|
||||
testcase(i == 53); /* INNER */
|
||||
testcase(i == 54); /* RELEASE */
|
||||
testcase(i == 55); /* BETWEEN */
|
||||
testcase(i == 56); /* NOTNULL */
|
||||
testcase(i == 57); /* NOT */
|
||||
testcase(i == 58); /* NO */
|
||||
testcase(i == 59); /* NULL */
|
||||
testcase(i == 60); /* LIKE */
|
||||
testcase(i == 61); /* CASCADE */
|
||||
testcase(i == 62); /* ASC */
|
||||
testcase(i == 63); /* DELETE */
|
||||
testcase(i == 64); /* CASE */
|
||||
testcase(i == 65); /* COLLATE */
|
||||
testcase(i == 66); /* CREATE */
|
||||
testcase(i == 67); /* CURRENT_DATE */
|
||||
testcase(i == 68); /* DETACH */
|
||||
testcase(i == 69); /* IMMEDIATE */
|
||||
testcase(i == 70); /* JOIN */
|
||||
testcase(i == 71); /* INSERT */
|
||||
testcase(i == 72); /* MATCH */
|
||||
testcase(i == 73); /* PLAN */
|
||||
testcase(i == 74); /* ANALYZE */
|
||||
testcase(i == 75); /* PRAGMA */
|
||||
testcase(i == 76); /* ABORT */
|
||||
testcase(i == 77); /* VALUES */
|
||||
testcase(i == 78); /* VIRTUAL */
|
||||
testcase(i == 79); /* LIMIT */
|
||||
testcase(i == 80); /* WHEN */
|
||||
testcase(i == 81); /* WHERE */
|
||||
testcase(i == 82); /* RENAME */
|
||||
testcase(i == 83); /* AFTER */
|
||||
testcase(i == 84); /* REPLACE */
|
||||
testcase(i == 85); /* AND */
|
||||
testcase(i == 86); /* DEFAULT */
|
||||
testcase(i == 87); /* AUTOINCREMENT */
|
||||
testcase(i == 88); /* TO */
|
||||
testcase(i == 89); /* IN */
|
||||
testcase(i == 90); /* CAST */
|
||||
testcase(i == 91); /* COLUMN */
|
||||
testcase(i == 92); /* COMMIT */
|
||||
testcase(i == 93); /* CONFLICT */
|
||||
testcase(i == 94); /* CROSS */
|
||||
testcase(i == 95); /* CURRENT_TIMESTAMP */
|
||||
testcase(i == 96); /* CURRENT_TIME */
|
||||
testcase(i == 97); /* PRIMARY */
|
||||
testcase(i == 98); /* DEFERRED */
|
||||
testcase(i == 99); /* DISTINCT */
|
||||
testcase(i == 100); /* IS */
|
||||
testcase(i == 101); /* DROP */
|
||||
testcase(i == 102); /* FAIL */
|
||||
testcase(i == 103); /* FROM */
|
||||
testcase(i == 104); /* FULL */
|
||||
testcase(i == 105); /* GLOB */
|
||||
testcase(i == 106); /* BY */
|
||||
testcase(i == 107); /* IF */
|
||||
testcase(i == 108); /* ISNULL */
|
||||
testcase(i == 109); /* ORDER */
|
||||
testcase(i == 110); /* RESTRICT */
|
||||
testcase(i == 111); /* OUTER */
|
||||
testcase(i == 112); /* RIGHT */
|
||||
testcase(i == 113); /* ROLLBACK */
|
||||
testcase(i == 114); /* ROW */
|
||||
testcase(i == 115); /* UNION */
|
||||
testcase(i == 116); /* USING */
|
||||
testcase(i == 117); /* VACUUM */
|
||||
testcase(i == 118); /* VIEW */
|
||||
testcase(i == 119); /* INITIALLY */
|
||||
testcase(i == 120); /* ALL */
|
||||
return aCode[i];
|
||||
}
|
||||
}
|
||||
return TK_ID;
|
||||
}
|
||||
|
||||
private static int sqlite3KeywordCode(string z, int n)
|
||||
{
|
||||
return keywordCode(z, 0, n);
|
||||
}
|
||||
|
||||
public const int SQLITE_N_KEYWORD = 121;//#define SQLITE_N_KEYWORD 121
|
||||
}
|
||||
}
|
||||
235
original/Community.CsharpSqlite/src/legacy_c.cs
Normal file
235
original/Community.CsharpSqlite/src/legacy_c.cs
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
using System.Diagnostics;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
using sqlite3_callback = Sqlite3.dxCallback;
|
||||
using sqlite3_stmt = Sqlite3.Vdbe;
|
||||
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** Main file for the SQLite library. The routines in this file
|
||||
** implement the programmer interface to the library. Routines in
|
||||
** other files are for internal use by SQLite and should not be
|
||||
** accessed by users of the library.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2010-08-23 18:52:01 42537b60566f288167f1b5864a5435986838e3a3
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
|
||||
//#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** Execute SQL code. Return one of the SQLITE_ success/failure
|
||||
** codes. Also write an error message into memory obtained from
|
||||
** malloc() and make pzErrMsg point to that message.
|
||||
**
|
||||
** If the SQL is a query, then for each row in the query result
|
||||
** the xCallback() function is called. pArg becomes the first
|
||||
** argument to xCallback(). If xCallback=NULL then no callback
|
||||
** is invoked, even for queries.
|
||||
*/
|
||||
|
||||
//C# Alias
|
||||
static public int exec(sqlite3 db, /* The database on which the SQL executes */ string zSql, /* The SQL to be executed */ int NoCallback, int NoArgs, int NoErrors)
|
||||
{
|
||||
string Errors = "";
|
||||
return sqlite3_exec(db, zSql, null, null, ref Errors);
|
||||
}
|
||||
|
||||
static public int exec(sqlite3 db, /* The database on which the SQL executes */ string zSql, /* The SQL to be executed */ sqlite3_callback xCallback, /* Invoke this callback routine */ object pArg, /* First argument to xCallback() */ int NoErrors)
|
||||
{
|
||||
string Errors = "";
|
||||
return sqlite3_exec(db, zSql, xCallback, pArg, ref Errors);
|
||||
}
|
||||
|
||||
static public int exec(sqlite3 db, /* The database on which the SQL executes */ string zSql, /* The SQL to be executed */ sqlite3_callback xCallback, /* Invoke this callback routine */ object pArg, /* First argument to xCallback() */ ref string pzErrMsg /* Write error messages here */)
|
||||
{
|
||||
return sqlite3_exec(db, zSql, xCallback, pArg, ref pzErrMsg);
|
||||
}
|
||||
|
||||
//OVERLOADS
|
||||
static public int sqlite3_exec(
|
||||
sqlite3 db, /* The database on which the SQL executes */
|
||||
string zSql, /* The SQL to be executed */
|
||||
int NoCallback, int NoArgs, int NoErrors
|
||||
)
|
||||
{
|
||||
string Errors = "";
|
||||
return sqlite3_exec(db, zSql, null, null, ref Errors);
|
||||
}
|
||||
|
||||
static public int sqlite3_exec(
|
||||
sqlite3 db, /* The database on which the SQL executes */
|
||||
string zSql, /* The SQL to be executed */
|
||||
sqlite3_callback xCallback, /* Invoke this callback routine */
|
||||
object pArg, /* First argument to xCallback() */
|
||||
int NoErrors
|
||||
)
|
||||
{
|
||||
string Errors = "";
|
||||
return sqlite3_exec(db, zSql, xCallback, pArg, ref Errors);
|
||||
}
|
||||
|
||||
static public int sqlite3_exec(
|
||||
sqlite3 db, /* The database on which the SQL executes */
|
||||
string zSql, /* The SQL to be executed */
|
||||
sqlite3_callback xCallback, /* Invoke this callback routine */
|
||||
object pArg, /* First argument to xCallback() */
|
||||
ref string pzErrMsg /* Write error messages here */
|
||||
)
|
||||
{
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
string zLeftover = ""; /* Tail of unprocessed SQL */
|
||||
sqlite3_stmt pStmt = null; /* The current SQL statement */
|
||||
string[] azCols = null; /* Names of result columns */
|
||||
int nRetry = 0; /* Number of retry attempts */
|
||||
int callbackIsInit; /* True if callback data is initialized */
|
||||
|
||||
if (!sqlite3SafetyCheckOk(db))
|
||||
return SQLITE_MISUSE_BKPT();
|
||||
|
||||
if (zSql == null)
|
||||
zSql = "";
|
||||
|
||||
sqlite3_mutex_enter(db.mutex);
|
||||
sqlite3Error(db, SQLITE_OK, 0);
|
||||
while ((rc == SQLITE_OK || (rc == SQLITE_SCHEMA && (++nRetry) < 2)) && zSql != "")
|
||||
{
|
||||
int nCol;
|
||||
string[] azVals = null;
|
||||
|
||||
pStmt = null;
|
||||
rc = sqlite3_prepare(db, zSql, -1, ref pStmt, ref zLeftover);
|
||||
Debug.Assert(rc == SQLITE_OK || pStmt == null);
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (pStmt == null)
|
||||
{
|
||||
/* this happens for a comment or white-space */
|
||||
zSql = zLeftover;
|
||||
continue;
|
||||
}
|
||||
|
||||
callbackIsInit = 0;
|
||||
nCol = sqlite3_column_count(pStmt);
|
||||
|
||||
while (true)
|
||||
{
|
||||
int i;
|
||||
rc = sqlite3_step(pStmt);
|
||||
|
||||
/* Invoke the callback function if required */
|
||||
if (xCallback != null && (SQLITE_ROW == rc ||
|
||||
(SQLITE_DONE == rc && callbackIsInit == 0
|
||||
&& (db.flags & SQLITE_NullCallback) != 0)))
|
||||
{
|
||||
if (0 == callbackIsInit)
|
||||
{
|
||||
azCols = new string[nCol];//sqlite3DbMallocZero(db, 2*nCol*sizeof(const char*) + 1);
|
||||
//if ( azCols == null )
|
||||
//{
|
||||
// goto exec_out;
|
||||
//}
|
||||
for (i = 0; i < nCol; i++)
|
||||
{
|
||||
azCols[i] = sqlite3_column_name(pStmt, i);
|
||||
/* sqlite3VdbeSetColName() installs column names as UTF8
|
||||
** strings so there is no way for sqlite3_column_name() to fail. */
|
||||
Debug.Assert(azCols[i] != null);
|
||||
}
|
||||
callbackIsInit = 1;
|
||||
}
|
||||
if (rc == SQLITE_ROW)
|
||||
{
|
||||
azVals = new string[nCol];// azCols[nCol];
|
||||
for (i = 0; i < nCol; i++)
|
||||
{
|
||||
azVals[i] = sqlite3_column_text(pStmt, i);
|
||||
if (azVals[i] == null && sqlite3_column_type(pStmt, i) != SQLITE_NULL)
|
||||
{
|
||||
//db.mallocFailed = 1;
|
||||
//goto exec_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (xCallback(pArg, nCol, azVals, azCols) != 0)
|
||||
{
|
||||
rc = SQLITE_ABORT;
|
||||
sqlite3VdbeFinalize(ref pStmt);
|
||||
pStmt = null;
|
||||
sqlite3Error(db, SQLITE_ABORT, 0);
|
||||
goto exec_out;
|
||||
}
|
||||
}
|
||||
|
||||
if (rc != SQLITE_ROW)
|
||||
{
|
||||
rc = sqlite3VdbeFinalize(ref pStmt);
|
||||
pStmt = null;
|
||||
if (rc != SQLITE_SCHEMA)
|
||||
{
|
||||
nRetry = 0;
|
||||
if ((zSql = zLeftover) != "")
|
||||
{
|
||||
int zindex = 0;
|
||||
while (zindex < zSql.Length && sqlite3Isspace(zSql[zindex]))
|
||||
zindex++;
|
||||
if (zindex != 0)
|
||||
zSql = zindex < zSql.Length ? zSql.Substring(zindex) : "";
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3DbFree(db, ref azCols);
|
||||
azCols = null;
|
||||
}
|
||||
|
||||
exec_out:
|
||||
if (pStmt != null)
|
||||
sqlite3VdbeFinalize(ref pStmt);
|
||||
sqlite3DbFree(db, ref azCols);
|
||||
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
if (rc != SQLITE_OK && ALWAYS(rc == sqlite3_errcode(db)) && pzErrMsg != null)
|
||||
{
|
||||
//int nErrMsg = 1 + sqlite3Strlen30(sqlite3_errmsg(db));
|
||||
//pzErrMsg = sqlite3Malloc(nErrMsg);
|
||||
//if (pzErrMsg)
|
||||
//{
|
||||
// memcpy(pzErrMsg, sqlite3_errmsg(db), nErrMsg);
|
||||
//}else{
|
||||
//rc = SQLITE_NOMEM;
|
||||
//sqlite3Error(db, SQLITE_NOMEM, 0);
|
||||
//}
|
||||
pzErrMsg = sqlite3_errmsg(db);
|
||||
}
|
||||
else if (pzErrMsg != "")
|
||||
{
|
||||
pzErrMsg = "";
|
||||
}
|
||||
|
||||
Debug.Assert((rc & db.errMask) == rc);
|
||||
sqlite3_mutex_leave(db.mutex);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
779
original/Community.CsharpSqlite/src/loadext_c.cs
Normal file
779
original/Community.CsharpSqlite/src/loadext_c.cs
Normal file
|
|
@ -0,0 +1,779 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using HANDLE = System.IntPtr;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2006 June 7
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains code used to dynamically load extensions into
|
||||
** the SQLite library.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2011-05-19 13:26:54 ed1da510a239ea767a01dc332b667119fa3c908e
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
#if !SQLITE_CORE
|
||||
|
||||
//#define SQLITE_CORE 1 /* Disable the API redefinition in sqlite3ext.h */
|
||||
private const int SQLITE_CORE = 1;
|
||||
|
||||
#endif
|
||||
//#include "sqlite3ext.h"
|
||||
//#include "sqliteInt.h"
|
||||
//#include <string.h>
|
||||
|
||||
#if !SQLITE_OMIT_LOAD_EXTENSION
|
||||
|
||||
/*
|
||||
** Some API routines are omitted when various features are
|
||||
** excluded from a build of SQLite. Substitute a NULL pointer
|
||||
** for any missing APIs.
|
||||
*/
|
||||
#if !SQLITE_ENABLE_COLUMN_METADATA
|
||||
//# define sqlite3_column_database_name 0
|
||||
//# define sqlite3_column_database_name16 0
|
||||
//# define sqlite3_column_table_name 0
|
||||
//# define sqlite3_column_table_name16 0
|
||||
//# define sqlite3_column_origin_name 0
|
||||
//# define sqlite3_column_origin_name16 0
|
||||
//# define sqlite3_table_column_metadata 0
|
||||
#endif
|
||||
|
||||
#if SQLITE_OMIT_AUTHORIZATION
|
||||
//# define sqlite3_set_authorizer 0
|
||||
#endif
|
||||
|
||||
#if SQLITE_OMIT_UTF16
|
||||
|
||||
//# define sqlite3_bind_text16 0
|
||||
//# define sqlite3_collation_needed16 0
|
||||
//# define sqlite3_column_decltype16 0
|
||||
//# define sqlite3_column_name16 0
|
||||
//# define sqlite3_column_text16 0
|
||||
//# define sqlite3_complete16 0
|
||||
//# define sqlite3_create_collation16 0
|
||||
//# define sqlite3_create_function16 0
|
||||
//# define sqlite3_errmsg16 0
|
||||
private static string sqlite3_errmsg16(sqlite3 db)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
//# define sqlite3_open16 0
|
||||
//# define sqlite3_prepare16 0
|
||||
//# define sqlite3_prepare16_v2 0
|
||||
//# define sqlite3_result_error16 0
|
||||
//# define sqlite3_result_text16 0
|
||||
private static void sqlite3_result_text16(sqlite3_context pCtx, string z, int n, dxDel xDel)
|
||||
{
|
||||
}
|
||||
|
||||
//# define sqlite3_result_text16be 0
|
||||
//# define sqlite3_result_text16le 0
|
||||
//# define sqlite3_value_text16 0
|
||||
//# define sqlite3_value_text16be 0
|
||||
//# define sqlite3_value_text16le 0
|
||||
//# define sqlite3_column_database_name16 0
|
||||
//# define sqlite3_column_table_name16 0
|
||||
//# define sqlite3_column_origin_name16 0
|
||||
#endif
|
||||
|
||||
#if SQLITE_OMIT_COMPLETE
|
||||
//# define sqlite3_complete 0
|
||||
//# define sqlite3_complete16 0
|
||||
#endif
|
||||
|
||||
#if SQLITE_OMIT_DECLTYPE
|
||||
//# define sqlite3_column_decltype16 0
|
||||
//# define sqlite3_column_decltype 0
|
||||
#endif
|
||||
|
||||
#if SQLITE_OMIT_PROGRESS_CALLBACK
|
||||
//# define sqlite3_progress_handler 0
|
||||
static void sqlite3_progress_handler (sqlite3 db, int nOps, dxProgress xProgress, object pArg){}
|
||||
#endif
|
||||
|
||||
#if SQLITE_OMIT_VIRTUALTABLE
|
||||
//# define sqlite3_create_module 0
|
||||
//# define sqlite3_create_module_v2 0
|
||||
//# define sqlite3_declare_vtab 0
|
||||
#endif
|
||||
|
||||
#if SQLITE_OMIT_SHARED_CACHE
|
||||
//# define sqlite3_enable_shared_cache 0
|
||||
#endif
|
||||
|
||||
#if SQLITE_OMIT_TRACE
|
||||
//# define sqlite3_profile 0
|
||||
//# define sqlite3_trace 0
|
||||
#endif
|
||||
|
||||
#if SQLITE_OMIT_GET_TABLE
|
||||
|
||||
//# define //sqlite3_free_table 0
|
||||
static public int sqlite3_free_table(ref string[] pazResult)
|
||||
{
|
||||
pazResult = null; return 0;
|
||||
}
|
||||
|
||||
static public int sqlite3_get_table(
|
||||
sqlite3 db, /* An open database */
|
||||
string zSql, /* SQL to be evaluated */
|
||||
ref string[] pazResult, /* Results of the query */
|
||||
ref int pnRow, /* Number of result rows written here */
|
||||
object dummy,
|
||||
ref string pzErrmsg /* Error msg written here */
|
||||
)
|
||||
{
|
||||
int iDummy = 0;
|
||||
return sqlite3_get_table(db, zSql, ref pazResult, ref pnRow, ref iDummy, ref pzErrmsg);
|
||||
}
|
||||
|
||||
//# define sqlite3_get_table 0
|
||||
static public int sqlite3_get_table(
|
||||
sqlite3 db, /* An open database */
|
||||
string zSql, /* SQL to be evaluated */
|
||||
ref string[] pazResult, /* Results of the query */
|
||||
ref int pnRow, /* Number of result rows written here */
|
||||
ref int pnColumn, /* Number of result columns written here */
|
||||
ref string pzErrmsg /* Error msg written here */
|
||||
)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if SQLITE_OMIT_INCRBLOB
|
||||
//#define sqlite3_bind_zeroblob 0
|
||||
//#define sqlite3_blob_bytes 0
|
||||
//#define sqlite3_blob_close 0
|
||||
//#define sqlite3_blob_open 0
|
||||
//#define sqlite3_blob_read 0
|
||||
//#define sqlite3_blob_write 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The following structure contains pointers to all SQLite API routines.
|
||||
** A pointer to this structure is passed into extensions when they are
|
||||
** loaded so that the extension can make calls back into the SQLite
|
||||
** library.
|
||||
**
|
||||
** When adding new APIs, add them to the bottom of this structure
|
||||
** in order to preserve backwards compatibility.
|
||||
**
|
||||
** Extensions that use newer APIs should first call the
|
||||
** sqlite3_libversion_number() to make sure that the API they
|
||||
** intend to use is supported by the library. Extensions should
|
||||
** also check to make sure that the pointer to the function is
|
||||
** not NULL before calling it.
|
||||
*/
|
||||
|
||||
public class sqlite3_api_routines
|
||||
{
|
||||
public sqlite3 context_db_handle;
|
||||
};
|
||||
|
||||
private static sqlite3_api_routines sqlite3Apis = new sqlite3_api_routines();
|
||||
//{
|
||||
// sqlite3_aggregate_context,
|
||||
#if !SQLITE_OMIT_DEPRECATED
|
||||
/ sqlite3_aggregate_count,
|
||||
#else
|
||||
// 0,
|
||||
#endif
|
||||
// sqlite3_bind_blob,
|
||||
// sqlite3_bind_double,
|
||||
// sqlite3_bind_int,
|
||||
// sqlite3_bind_int64,
|
||||
// sqlite3_bind_null,
|
||||
// sqlite3_bind_parameter_count,
|
||||
// sqlite3_bind_parameter_index,
|
||||
// sqlite3_bind_parameter_name,
|
||||
// sqlite3_bind_text,
|
||||
// sqlite3_bind_text16,
|
||||
// sqlite3_bind_value,
|
||||
// sqlite3_busy_handler,
|
||||
// sqlite3_busy_timeout,
|
||||
// sqlite3_changes,
|
||||
// sqlite3_close,
|
||||
// sqlite3_collation_needed,
|
||||
// sqlite3_collation_needed16,
|
||||
// sqlite3_column_blob,
|
||||
// sqlite3_column_bytes,
|
||||
// sqlite3_column_bytes16,
|
||||
// sqlite3_column_count,
|
||||
// sqlite3_column_database_name,
|
||||
// sqlite3_column_database_name16,
|
||||
// sqlite3_column_decltype,
|
||||
// sqlite3_column_decltype16,
|
||||
// sqlite3_column_double,
|
||||
// sqlite3_column_int,
|
||||
// sqlite3_column_int64,
|
||||
// sqlite3_column_name,
|
||||
// sqlite3_column_name16,
|
||||
// sqlite3_column_origin_name,
|
||||
// sqlite3_column_origin_name16,
|
||||
// sqlite3_column_table_name,
|
||||
// sqlite3_column_table_name16,
|
||||
// sqlite3_column_text,
|
||||
// sqlite3_column_text16,
|
||||
// sqlite3_column_type,
|
||||
// sqlite3_column_value,
|
||||
// sqlite3_commit_hook,
|
||||
// sqlite3_complete,
|
||||
// sqlite3_complete16,
|
||||
// sqlite3_create_collation,
|
||||
// sqlite3_create_collation16,
|
||||
// sqlite3_create_function,
|
||||
// sqlite3_create_function16,
|
||||
// sqlite3_create_module,
|
||||
// sqlite3_data_count,
|
||||
// sqlite3_db_handle,
|
||||
// sqlite3_declare_vtab,
|
||||
// sqlite3_enable_shared_cache,
|
||||
// sqlite3_errcode,
|
||||
// sqlite3_errmsg,
|
||||
// sqlite3_errmsg16,
|
||||
// sqlite3_exec,
|
||||
#if !SQLITE_OMIT_DEPRECATED
|
||||
//sqlite3_expired,
|
||||
#else
|
||||
//0,
|
||||
#endif
|
||||
// sqlite3_finalize,
|
||||
// //sqlite3_free,
|
||||
// //sqlite3_free_table,
|
||||
// sqlite3_get_autocommit,
|
||||
// sqlite3_get_auxdata,
|
||||
// sqlite3_get_table,
|
||||
// 0, /* Was sqlite3_global_recover(), but that function is deprecated */
|
||||
// sqlite3_interrupt,
|
||||
// sqlite3_last_insert_rowid,
|
||||
// sqlite3_libversion,
|
||||
// sqlite3_libversion_number,
|
||||
// sqlite3_malloc,
|
||||
// sqlite3_mprintf,
|
||||
// sqlite3_open,
|
||||
// sqlite3_open16,
|
||||
// sqlite3_prepare,
|
||||
// sqlite3_prepare16,
|
||||
// sqlite3_profile,
|
||||
// sqlite3_progress_handler,
|
||||
// sqlite3_realloc,
|
||||
// sqlite3_reset,
|
||||
// sqlite3_result_blob,
|
||||
// sqlite3_result_double,
|
||||
// sqlite3_result_error,
|
||||
// sqlite3_result_error16,
|
||||
// sqlite3_result_int,
|
||||
// sqlite3_result_int64,
|
||||
// sqlite3_result_null,
|
||||
// sqlite3_result_text,
|
||||
// sqlite3_result_text16,
|
||||
// sqlite3_result_text16be,
|
||||
// sqlite3_result_text16le,
|
||||
// sqlite3_result_value,
|
||||
// sqlite3_rollback_hook,
|
||||
// sqlite3_set_authorizer,
|
||||
// sqlite3_set_auxdata,
|
||||
// sqlite3_snprintf,
|
||||
// sqlite3_step,
|
||||
// sqlite3_table_column_metadata,
|
||||
#if !SQLITE_OMIT_DEPRECATED
|
||||
//sqlite3_thread_cleanup,
|
||||
#else
|
||||
// 0,
|
||||
#endif
|
||||
// sqlite3_total_changes,
|
||||
// sqlite3_trace,
|
||||
#if !SQLITE_OMIT_DEPRECATED
|
||||
//sqlite3_transfer_bindings,
|
||||
#else
|
||||
// 0,
|
||||
#endif
|
||||
// sqlite3_update_hook,
|
||||
// sqlite3_user_data,
|
||||
// sqlite3_value_blob,
|
||||
// sqlite3_value_bytes,
|
||||
// sqlite3_value_bytes16,
|
||||
// sqlite3_value_double,
|
||||
// sqlite3_value_int,
|
||||
// sqlite3_value_int64,
|
||||
// sqlite3_value_numeric_type,
|
||||
// sqlite3_value_text,
|
||||
// sqlite3_value_text16,
|
||||
// sqlite3_value_text16be,
|
||||
// sqlite3_value_text16le,
|
||||
// sqlite3_value_type,
|
||||
// sqlite3_vmprintf,
|
||||
// /*
|
||||
// ** The original API set ends here. All extensions can call any
|
||||
// ** of the APIs above provided that the pointer is not NULL. But
|
||||
// ** before calling APIs that follow, extension should check the
|
||||
// ** sqlite3_libversion_number() to make sure they are dealing with
|
||||
// ** a library that is new enough to support that API.
|
||||
// *************************************************************************
|
||||
// */
|
||||
// sqlite3_overload_function,
|
||||
|
||||
// /*
|
||||
// ** Added after 3.3.13
|
||||
// */
|
||||
// sqlite3_prepare_v2,
|
||||
// sqlite3_prepare16_v2,
|
||||
// sqlite3_clear_bindings,
|
||||
|
||||
// /*
|
||||
// ** Added for 3.4.1
|
||||
// */
|
||||
// sqlite3_create_module_v2,
|
||||
|
||||
// /*
|
||||
// ** Added for 3.5.0
|
||||
// */
|
||||
// sqlite3_bind_zeroblob,
|
||||
// sqlite3_blob_bytes,
|
||||
// sqlite3_blob_close,
|
||||
// sqlite3_blob_open,
|
||||
// sqlite3_blob_read,
|
||||
// sqlite3_blob_write,
|
||||
// sqlite3_create_collation_v2,
|
||||
// sqlite3_file_control,
|
||||
// sqlite3_memory_highwater,
|
||||
// sqlite3_memory_used,
|
||||
#if SQLITE_MUTEX_OMIT
|
||||
// 0,
|
||||
// 0,
|
||||
// 0,
|
||||
// 0,
|
||||
// 0,
|
||||
#else
|
||||
// sqlite3MutexAlloc,
|
||||
// sqlite3_mutex_enter,
|
||||
// sqlite3_mutex_free,
|
||||
// sqlite3_mutex_leave,
|
||||
// sqlite3_mutex_try,
|
||||
#endif
|
||||
// sqlite3_open_v2,
|
||||
// sqlite3_release_memory,
|
||||
// sqlite3_result_error_nomem,
|
||||
// sqlite3_result_error_toobig,
|
||||
// sqlite3_sleep,
|
||||
// sqlite3_soft_heap_limit,
|
||||
// sqlite3_vfs_find,
|
||||
// sqlite3_vfs_register,
|
||||
// sqlite3_vfs_unregister,
|
||||
|
||||
// /*
|
||||
// ** Added for 3.5.8
|
||||
// */
|
||||
// sqlite3_threadsafe,
|
||||
// sqlite3_result_zeroblob,
|
||||
// sqlite3_result_error_code,
|
||||
// sqlite3_test_control,
|
||||
// sqlite3_randomness,
|
||||
// sqlite3_context_db_handle,
|
||||
|
||||
// /*
|
||||
// ** Added for 3.6.0
|
||||
// */
|
||||
// sqlite3_extended_result_codes,
|
||||
// sqlite3_limit,
|
||||
// sqlite3_next_stmt,
|
||||
// sqlite3_sql,
|
||||
// sqlite3_status,
|
||||
|
||||
// /*
|
||||
// ** Added for 3.7.4
|
||||
// */
|
||||
// sqlite3_backup_finish,
|
||||
// sqlite3_backup_init,
|
||||
// sqlite3_backup_pagecount,
|
||||
// sqlite3_backup_remaining,
|
||||
// sqlite3_backup_step,
|
||||
//#if !SQLITE_OMIT_COMPILEOPTION_DIAGS
|
||||
// sqlite3_compileoption_get,
|
||||
// sqlite3_compileoption_used,
|
||||
//#else
|
||||
// 0,
|
||||
// 0,
|
||||
//#endif
|
||||
// sqlite3_create_function_v2,
|
||||
// sqlite3_db_config,
|
||||
// sqlite3_db_mutex,
|
||||
// sqlite3_db_status,
|
||||
// sqlite3_extended_errcode,
|
||||
// sqlite3_log,
|
||||
// sqlite3_soft_heap_limit64,
|
||||
// sqlite3_sourceid,
|
||||
// sqlite3_stmt_status,
|
||||
// sqlite3_strnicmp,
|
||||
//#if SQLITE_ENABLE_UNLOCK_NOTIFY
|
||||
// sqlite3_unlock_notify,
|
||||
//#else
|
||||
// 0,
|
||||
//#endif
|
||||
//#if !SQLITE_OMIT_WAL
|
||||
// sqlite3_wal_autocheckpoint,
|
||||
// sqlite3_wal_checkpoint,
|
||||
// sqlite3_wal_hook,
|
||||
//#else
|
||||
// 0,
|
||||
// 0,
|
||||
// 0,
|
||||
//#endif
|
||||
//};
|
||||
|
||||
/*
|
||||
** Attempt to load an SQLite extension library contained in the file
|
||||
** zFile. The entry point is zProc. zProc may be 0 in which case a
|
||||
** default entry point name (sqlite3_extension_init) is used. Use
|
||||
** of the default name is recommended.
|
||||
**
|
||||
** Return SQLITE_OK on success and SQLITE_ERROR if something goes wrong.
|
||||
**
|
||||
** If an error occurs and pzErrMsg is not 0, then fill pzErrMsg with
|
||||
** error message text. The calling function should free this memory
|
||||
** by calling sqlite3DbFree(db, ).
|
||||
*/
|
||||
|
||||
private static int sqlite3LoadExtension(
|
||||
sqlite3 db, /* Load the extension into this database connection */
|
||||
string zFile, /* Name of the shared library containing extension */
|
||||
string zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */
|
||||
ref string pzErrMsg /* Put error message here if not 0 */
|
||||
)
|
||||
{
|
||||
sqlite3_vfs pVfs = db.pVfs;
|
||||
HANDLE handle;
|
||||
dxInit xInit; //int (*xInit)(sqlite3*,char**,const sqlite3_api_routines);
|
||||
StringBuilder zErrmsg = new StringBuilder(100);
|
||||
//object aHandle;
|
||||
const int nMsg = 300;
|
||||
if (pzErrMsg != null)
|
||||
pzErrMsg = null;
|
||||
|
||||
/* Ticket #1863. To avoid a creating security problems for older
|
||||
** applications that relink against newer versions of SQLite, the
|
||||
** ability to run load_extension is turned off by default. One
|
||||
** must call sqlite3_enable_load_extension() to turn on extension
|
||||
** loading. Otherwise you get the following error.
|
||||
*/
|
||||
if ((db.flags & SQLITE_LoadExtension) == 0)
|
||||
{
|
||||
//if( pzErrMsg != null){
|
||||
pzErrMsg = sqlite3_mprintf("not authorized");
|
||||
//}
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
if (zProc == null || zProc == "")
|
||||
{
|
||||
zProc = "sqlite3_extension_init";
|
||||
}
|
||||
|
||||
handle = sqlite3OsDlOpen(pVfs, zFile);
|
||||
if (handle == IntPtr.Zero)
|
||||
{
|
||||
// if( pzErrMsg ){
|
||||
pzErrMsg = "";//*pzErrMsg = zErrmsg = sqlite3_malloc(nMsg);
|
||||
//if( zErrmsg !=null){
|
||||
sqlite3_snprintf(nMsg, zErrmsg,
|
||||
"unable to open shared library [%s]", zFile);
|
||||
sqlite3OsDlError(pVfs, nMsg - 1, zErrmsg.ToString());
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
//xInit = (int()(sqlite3*,char**,const sqlite3_api_routines))
|
||||
// sqlite3OsDlSym(pVfs, handle, zProc);
|
||||
xInit = (dxInit)sqlite3OsDlSym(pVfs, handle, ref zProc);
|
||||
Debugger.Break(); // TODO --
|
||||
//if( xInit==0 ){
|
||||
// if( pzErrMsg ){
|
||||
// *pzErrMsg = zErrmsg = sqlite3_malloc(nMsg);
|
||||
// if( zErrmsg ){
|
||||
// sqlite3_snprintf(nMsg, zErrmsg,
|
||||
// "no entry point [%s] in shared library [%s]", zProc,zFile);
|
||||
// sqlite3OsDlError(pVfs, nMsg-1, zErrmsg);
|
||||
// }
|
||||
// sqlite3OsDlClose(pVfs, handle);
|
||||
// }
|
||||
// return SQLITE_ERROR;
|
||||
// }else if( xInit(db, ref zErrmsg, sqlite3Apis) ){
|
||||
//// if( pzErrMsg !=null){
|
||||
// pzErrMsg = sqlite3_mprintf("error during initialization: %s", zErrmsg);
|
||||
// //}
|
||||
// sqlite3DbFree(db,ref zErrmsg);
|
||||
// sqlite3OsDlClose(pVfs, ref handle);
|
||||
// return SQLITE_ERROR;
|
||||
// }
|
||||
|
||||
// /* Append the new shared library handle to the db.aExtension array. */
|
||||
// aHandle = sqlite3DbMallocZero(db, sizeof(handle)*db.nExtension+1);
|
||||
// if( aHandle==null ){
|
||||
// return SQLITE_NOMEM;
|
||||
// }
|
||||
// if( db.nExtension>0 ){
|
||||
// memcpy(aHandle, db.aExtension, sizeof(handle)*(db.nExtension));
|
||||
// }
|
||||
// sqlite3DbFree(db,ref db.aExtension);
|
||||
// db.aExtension = aHandle;
|
||||
|
||||
// db.aExtension[db.nExtension++] = handle;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static public int sqlite3_load_extension(
|
||||
sqlite3 db, /* Load the extension into this database connection */
|
||||
string zFile, /* Name of the shared library containing extension */
|
||||
string zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */
|
||||
ref string pzErrMsg /* Put error message here if not 0 */
|
||||
)
|
||||
{
|
||||
int rc;
|
||||
sqlite3_mutex_enter(db.mutex);
|
||||
rc = sqlite3LoadExtension(db, zFile, zProc, ref pzErrMsg);
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
sqlite3_mutex_leave(db.mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Call this routine when the database connection is closing in order
|
||||
** to clean up loaded extensions
|
||||
*/
|
||||
|
||||
private static void sqlite3CloseExtensions(sqlite3 db)
|
||||
{
|
||||
int i;
|
||||
Debug.Assert(sqlite3_mutex_held(db.mutex));
|
||||
for (i = 0; i < db.nExtension; i++)
|
||||
{
|
||||
sqlite3OsDlClose(db.pVfs, (HANDLE)db.aExtension[i]);
|
||||
}
|
||||
sqlite3DbFree(db, ref db.aExtension);
|
||||
}
|
||||
|
||||
/*
|
||||
** Enable or disable extension loading. Extension loading is disabled by
|
||||
** default so as not to open security holes in older applications.
|
||||
*/
|
||||
|
||||
static public int sqlite3_enable_load_extension(sqlite3 db, int onoff)
|
||||
{
|
||||
sqlite3_mutex_enter(db.mutex);
|
||||
if (onoff != 0)
|
||||
{
|
||||
db.flags |= SQLITE_LoadExtension;
|
||||
}
|
||||
else
|
||||
{
|
||||
db.flags &= ~SQLITE_LoadExtension;
|
||||
}
|
||||
sqlite3_mutex_leave(db.mutex);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
#endif //* SQLITE_OMIT_LOAD_EXTENSION */
|
||||
|
||||
/*
|
||||
** The auto-extension code added regardless of whether or not extension
|
||||
** loading is supported. We need a dummy sqlite3Apis pointer for that
|
||||
** code if regular extension loading is not available. This is that
|
||||
** dummy pointer.
|
||||
*/
|
||||
#if SQLITE_OMIT_LOAD_EXTENSION
|
||||
const sqlite3_api_routines sqlite3Apis = null;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The following object holds the list of automatically loaded
|
||||
** extensions.
|
||||
**
|
||||
** This list is shared across threads. The SQLITE_MUTEX_STATIC_MASTER
|
||||
** mutex must be held while accessing this list.
|
||||
*/
|
||||
|
||||
//typedef struct sqlite3AutoExtList sqlite3AutoExtList;
|
||||
public class sqlite3AutoExtList
|
||||
{
|
||||
public int nExt = 0; /* Number of entries in aExt[] */
|
||||
public dxInit[] aExt = null; /* Pointers to the extension init functions */
|
||||
|
||||
public sqlite3AutoExtList(int nExt, dxInit[] aExt)
|
||||
{
|
||||
this.nExt = nExt;
|
||||
this.aExt = aExt;
|
||||
}
|
||||
}
|
||||
|
||||
private static sqlite3AutoExtList sqlite3Autoext = new sqlite3AutoExtList(0, null);
|
||||
/* The "wsdAutoext" macro will resolve to the autoextension
|
||||
** state vector. If writable static data is unsupported on the target,
|
||||
** we have to locate the state vector at run-time. In the more common
|
||||
** case where writable static data is supported, wsdStat can refer directly
|
||||
** to the "sqlite3Autoext" state vector declared above.
|
||||
*/
|
||||
#if SQLITE_OMIT_WSD
|
||||
//# define wsdAutoextInit \
|
||||
sqlite3AutoExtList *x = &GLOBAL(sqlite3AutoExtList,sqlite3Autoext)
|
||||
//# define wsdAutoext x[0]
|
||||
#else
|
||||
|
||||
//# define wsdAutoextInit
|
||||
private static void wsdAutoextInit()
|
||||
{
|
||||
}
|
||||
|
||||
//# define wsdAutoext sqlite3Autoext
|
||||
private static sqlite3AutoExtList wsdAutoext = sqlite3Autoext;
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Register a statically linked extension that is automatically
|
||||
** loaded by every new database connection.
|
||||
*/
|
||||
|
||||
private static int sqlite3_auto_extension(dxInit xInit)
|
||||
{
|
||||
int rc = SQLITE_OK;
|
||||
#if !SQLITE_OMIT_AUTOINIT
|
||||
rc = sqlite3_initialize();
|
||||
if (rc != 0)
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
int i;
|
||||
#if SQLITE_THREADSAFE
|
||||
sqlite3_mutex mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
|
||||
#else
|
||||
sqlite3_mutex mutex = sqlite3MutexAlloc( SQLITE_MUTEX_STATIC_MASTER );
|
||||
#endif
|
||||
wsdAutoextInit();
|
||||
sqlite3_mutex_enter(mutex);
|
||||
for (i = 0; i < wsdAutoext.nExt; i++)
|
||||
{
|
||||
if (wsdAutoext.aExt[i] == xInit)
|
||||
break;
|
||||
}
|
||||
//if( i==wsdAutoext.nExt ){
|
||||
// int nByte = (wsdAutoext.nExt+1)*sizeof(wsdAutoext.aExt[0]);
|
||||
// void **aNew;
|
||||
// aNew = sqlite3_realloc(wsdAutoext.aExt, nByte);
|
||||
// if( aNew==0 ){
|
||||
// rc = SQLITE_NOMEM;
|
||||
// }else{
|
||||
Array.Resize(ref wsdAutoext.aExt, wsdAutoext.nExt + 1);// wsdAutoext.aExt = aNew;
|
||||
wsdAutoext.aExt[wsdAutoext.nExt] = xInit;
|
||||
wsdAutoext.nExt++;
|
||||
//}
|
||||
sqlite3_mutex_leave(mutex);
|
||||
Debug.Assert((rc & 0xff) == rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Reset the automatic extension loading mechanism.
|
||||
*/
|
||||
|
||||
private static void sqlite3_reset_auto_extension()
|
||||
{
|
||||
#if !SQLITE_OMIT_AUTOINIT
|
||||
if (sqlite3_initialize() == SQLITE_OK)
|
||||
#endif
|
||||
{
|
||||
#if SQLITE_THREADSAFE
|
||||
sqlite3_mutex mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
|
||||
#else
|
||||
sqlite3_mutex mutex = sqlite3MutexAlloc( SQLITE_MUTEX_STATIC_MASTER );
|
||||
#endif
|
||||
wsdAutoextInit();
|
||||
sqlite3_mutex_enter(mutex);
|
||||
#if SQLITE_OMIT_WSD
|
||||
//sqlite3_free( ref wsdAutoext.aExt );
|
||||
wsdAutoext.aExt = null;
|
||||
wsdAutoext.nExt = 0;
|
||||
#else
|
||||
//sqlite3_free( ref sqlite3Autoext.aExt );
|
||||
sqlite3Autoext.aExt = null;
|
||||
sqlite3Autoext.nExt = 0;
|
||||
#endif
|
||||
sqlite3_mutex_leave(mutex);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Load all automatic extensions.
|
||||
**
|
||||
** If anything goes wrong, set an error in the database connection.
|
||||
*/
|
||||
|
||||
private static void sqlite3AutoLoadExtensions(sqlite3 db)
|
||||
{
|
||||
int i;
|
||||
bool go = true;
|
||||
dxInit xInit;//)(sqlite3*,char**,const sqlite3_api_routines);
|
||||
|
||||
wsdAutoextInit();
|
||||
#if SQLITE_OMIT_WSD
|
||||
if ( wsdAutoext.nExt == 0 )
|
||||
#else
|
||||
if (sqlite3Autoext.nExt == 0)
|
||||
#endif
|
||||
{
|
||||
/* Common case: early out without every having to acquire a mutex */
|
||||
return;
|
||||
}
|
||||
for (i = 0; go; i++)
|
||||
{
|
||||
string zErrmsg = "";
|
||||
#if SQLITE_THREADSAFE
|
||||
sqlite3_mutex mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
|
||||
#else
|
||||
sqlite3_mutex mutex = sqlite3MutexAlloc( SQLITE_MUTEX_STATIC_MASTER );
|
||||
#endif
|
||||
sqlite3_mutex_enter(mutex);
|
||||
if (i >= wsdAutoext.nExt)
|
||||
{
|
||||
xInit = null;
|
||||
go = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
xInit = (dxInit)
|
||||
wsdAutoext.aExt[i];
|
||||
}
|
||||
sqlite3_mutex_leave(mutex);
|
||||
zErrmsg = "";
|
||||
if (xInit != null && xInit(db, ref zErrmsg, (sqlite3_api_routines)sqlite3Apis) != 0)
|
||||
{
|
||||
sqlite3Error(db, SQLITE_ERROR,
|
||||
"automatic extension loading failed: %s", zErrmsg);
|
||||
go = false;
|
||||
}
|
||||
sqlite3DbFree(db, ref zErrmsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3504
original/Community.CsharpSqlite/src/main_c.cs
Normal file
3504
original/Community.CsharpSqlite/src/main_c.cs
Normal file
File diff suppressed because it is too large
Load diff
1143
original/Community.CsharpSqlite/src/malloc_c.cs
Normal file
1143
original/Community.CsharpSqlite/src/malloc_c.cs
Normal file
File diff suppressed because it is too large
Load diff
484
original/Community.CsharpSqlite/src/mem_Pool.cs
Normal file
484
original/Community.CsharpSqlite/src/mem_Pool.cs
Normal file
|
|
@ -0,0 +1,484 @@
|
|||
using System;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
*************************************************************************
|
||||
**
|
||||
** This file contains low-level memory & pool allocation drivers
|
||||
**
|
||||
** This file contains implementations of the low-level memory allocation
|
||||
** routines specified in the sqlite3_mem_methods object.
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
** Like malloc(), but remember the size of the allocation
|
||||
** so that we can find it later using sqlite3MemSize().
|
||||
**
|
||||
** For this low-level routine, we are guaranteed that nByte>0 because
|
||||
** cases of nByte<=0 will be intercepted and dealt with by higher level
|
||||
** routines.
|
||||
*/
|
||||
#if SQLITE_POOL_MEM
|
||||
#if TRUE
|
||||
static byte[] sqlite3MemMalloc( u32 nByte )
|
||||
{
|
||||
return new byte[nByte];
|
||||
}
|
||||
static byte[] sqlite3MemMalloc( int nByte )
|
||||
{
|
||||
return new byte[nByte];
|
||||
}
|
||||
static int[] sqlite3MemMallocInt( int nInt )
|
||||
{
|
||||
return new int[nInt];
|
||||
}
|
||||
#else
|
||||
static byte[] sqlite3MemMalloc(int nByte)
|
||||
{
|
||||
byte[] pByte = null;
|
||||
int savej = -1;
|
||||
int BestSize = int.MaxValue;
|
||||
if (nByte > mem0.aByteSize[0])
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < mem0.aByteSize.Length - 1; i++) if (nByte <= mem0.aByteSize[i]) break;
|
||||
mem0.mr_Byte++;
|
||||
for (int j = 0; j <= mem0.aByte_used[i]; j++)
|
||||
if (mem0.aByte[i][j] != null)
|
||||
{
|
||||
if (mem0.aByte[i][j].Length == nByte)
|
||||
{
|
||||
pByte = mem0.aByte[i][j]; mem0.aByte[i][j] = null; mem0.cf_Byte++;
|
||||
if (j == mem0.aByte_used[i]) mem0.aByte_used[i]--;
|
||||
break;
|
||||
}
|
||||
if (mem0.aByte[i][j].Length > nByte)
|
||||
{
|
||||
if (mem0.aByte[i][j].Length < BestSize)
|
||||
{
|
||||
BestSize = mem0.aByte[i][j].Length;
|
||||
savej = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pByte == null && savej >= 0)
|
||||
{
|
||||
pByte = mem0.aByte[i][savej]; mem0.aByte[i][savej] = null; mem0.cf_Byte++;
|
||||
Array.Resize(ref pByte, nByte);
|
||||
}
|
||||
if (mem0.aByte_used[i] >=0 && mem0.aByte[i][mem0.aByte_used[i]] == null) mem0.aByte_used[i]--;
|
||||
}
|
||||
if (pByte == null) pByte = new byte[nByte];
|
||||
return pByte;
|
||||
}
|
||||
static int[] sqlite3MemMallocInt(int nInt)
|
||||
{
|
||||
int[] pInt = null;
|
||||
int savei = -1;
|
||||
int BestSize = int.MaxValue;
|
||||
if (nInt >=10)
|
||||
{
|
||||
mem0.mr_Int++;
|
||||
int i;
|
||||
for (i = 0; i < mem0.hw_Int; i++)
|
||||
if (mem0.aInt[i] != null)
|
||||
{
|
||||
if (mem0.aInt[i].Length == nInt)
|
||||
{
|
||||
pInt = mem0.aInt[i]; mem0.aInt[i] = null; mem0.cf_Int++; break;
|
||||
}
|
||||
if (mem0.aInt[i].Length > nInt)
|
||||
{
|
||||
if (mem0.aInt[i].Length < BestSize)
|
||||
{
|
||||
BestSize = mem0.aInt[i].Length;
|
||||
savei = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pInt == null && savei >= 0)
|
||||
{
|
||||
pInt = mem0.aInt[savei]; mem0.aInt[savei] = null; mem0.cf_Int++;
|
||||
}
|
||||
}
|
||||
if (pInt == null) pInt = new int[nInt];
|
||||
return pInt;
|
||||
}
|
||||
#endif
|
||||
|
||||
static Mem sqlite3MemMallocMem( Mem dummy )
|
||||
{
|
||||
Mem pMem;
|
||||
mem0.msMem.alloc++;
|
||||
if ( mem0.msMem.next > 0 && mem0.aMem[mem0.msMem.next] != null )
|
||||
{
|
||||
pMem = mem0.aMem[mem0.msMem.next];
|
||||
mem0.aMem[mem0.msMem.next] = null;
|
||||
mem0.msMem.cached++;
|
||||
mem0.msMem.next--;
|
||||
}
|
||||
else
|
||||
pMem = new Mem();
|
||||
return pMem;
|
||||
}
|
||||
static BtCursor sqlite3MemMallocBtCursor( BtCursor dummy )
|
||||
{
|
||||
BtCursor pBtCursor;
|
||||
mem0.msBtCursor.alloc++;
|
||||
if ( mem0.msBtCursor.next > 0 && mem0.aBtCursor[mem0.msBtCursor.next] != null )
|
||||
{
|
||||
pBtCursor = mem0.aBtCursor[mem0.msBtCursor.next];
|
||||
Debug.Assert( pBtCursor.pNext == null && pBtCursor.pPrev == null && pBtCursor.wrFlag == 0 );
|
||||
mem0.aBtCursor[mem0.msBtCursor.next] = null;
|
||||
mem0.msBtCursor.cached++;
|
||||
mem0.msBtCursor.next--;
|
||||
}
|
||||
else
|
||||
pBtCursor = new BtCursor();
|
||||
return pBtCursor;
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
** Free memory.
|
||||
*/
|
||||
|
||||
// -- overloads ---------------------------------------
|
||||
private static void sqlite3MemFree<T>(ref T x) where T : class
|
||||
{
|
||||
x = null;
|
||||
}
|
||||
|
||||
private static void sqlite3MemFree(ref string x)
|
||||
{
|
||||
x = null;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
/*
|
||||
** Like free() but works for allocations obtained from sqlite3MemMalloc()
|
||||
** or sqlite3MemRealloc().
|
||||
**
|
||||
** For this low-level routine, we already know that pPrior!=0 since
|
||||
** cases where pPrior==0 will have been intecepted and dealt with
|
||||
** by higher-level routines.
|
||||
*/
|
||||
#if SQLITE_POOL_MEM
|
||||
#if TRUE
|
||||
static void sqlite3MemFreeInt( ref int[] pPrior )
|
||||
{
|
||||
pPrior = null;
|
||||
}
|
||||
#else
|
||||
static void sqlite3MemFree(ref byte[] pPrior)
|
||||
{
|
||||
if (pPrior == null) return;
|
||||
if (pPrior.Length > mem0.aByteSize[0])
|
||||
{
|
||||
int savej = -1;
|
||||
int Smallest = int.MaxValue;
|
||||
int i;
|
||||
for (i = 0; i < mem0.aByteSize.Length - 1; i++) if (pPrior.Length <= mem0.aByteSize[i]) break;
|
||||
#if DEBUG
|
||||
for (int j = 0; j < mem0.aByte[i].Length; j++) if (mem0.aByte[i][j] != null && mem0.aByte[i][j] == pPrior) Debugger.Break();
|
||||
#endif
|
||||
mem0.mf_Byte++;
|
||||
for (int j = 0; j <= mem0.aByte_used[i]; j++)
|
||||
{
|
||||
if (mem0.aByte[i][j] == null)
|
||||
{
|
||||
mem0.aByte[i][j] = pPrior;
|
||||
pPrior = null;
|
||||
return;
|
||||
}
|
||||
if (mem0.aByte[i][j].Length < Smallest)
|
||||
{
|
||||
savej = j;
|
||||
Smallest = mem0.aByte[i][j].Length;
|
||||
}
|
||||
}
|
||||
|
||||
if (mem0.aByte_used[i] < mem0.aByte[i].Length - 1) mem0.aByte[i][++mem0.aByte_used[i]] = pPrior;
|
||||
else if (savej >= 0) mem0.aByte[i][savej] = pPrior;
|
||||
}
|
||||
pPrior = null;
|
||||
return;
|
||||
}
|
||||
static void sqlite3MemFreeInt(ref int[] pPrior)
|
||||
{
|
||||
if (pPrior == null) return;
|
||||
if (pPrior.Length >= 10)
|
||||
{
|
||||
int savei = -1;
|
||||
int Smallest = int.MaxValue;
|
||||
#if DEBUG
|
||||
for (int i = 0; i < mem0.aInt.Length; i++) if (mem0.aInt[i] != null && mem0.aInt[i] == pPrior) Debugger.Break();
|
||||
#endif
|
||||
mem0.mf_Int++;
|
||||
for (int i = 0; i < mem0.aInt.Length; i++)
|
||||
{
|
||||
if (mem0.aInt[i] == null)
|
||||
{
|
||||
mem0.aInt[i] = pPrior;
|
||||
pPrior = null;
|
||||
return;
|
||||
}
|
||||
if (mem0.aInt[i].Length < Smallest)
|
||||
{
|
||||
savei = i;
|
||||
Smallest = mem0.aInt[i].Length;
|
||||
}
|
||||
}
|
||||
if (savei >= 0) mem0.aInt[savei] = pPrior;
|
||||
}
|
||||
pPrior = null;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
static void sqlite3MemFreeMem( ref Mem pPrior )
|
||||
{
|
||||
if ( pPrior == null )
|
||||
return;
|
||||
#if FALSE && DEBUG
|
||||
for (int i = mem0.msMem.next - 1; i >= 0; i--) if (mem0.aMem[i] != null && mem0.aMem[i] == pPrior) Debugger.Break();
|
||||
#endif
|
||||
mem0.msMem.dealloc++;
|
||||
if ( mem0.msMem.next < mem0.aMem.Length - 1 )
|
||||
{
|
||||
pPrior.db = null;
|
||||
pPrior._SumCtx = null;
|
||||
pPrior._MD5Context = null;
|
||||
pPrior._SubProgram = null;
|
||||
pPrior.flags = MEM_Null;
|
||||
pPrior.r = 0;
|
||||
pPrior.u.i = 0;
|
||||
pPrior.n = 0;
|
||||
if ( pPrior.zBLOB != null )
|
||||
sqlite3MemFree( ref pPrior.zBLOB );
|
||||
mem0.aMem[++mem0.msMem.next] = pPrior;
|
||||
if ( mem0.msMem.next > mem0.msMem.max )
|
||||
mem0.msMem.max = mem0.msMem.next;
|
||||
}
|
||||
//Array.Resize( ref mem0.aMem, (int)(mem0.hw_Mem * 1.5 + 1 ));
|
||||
//mem0.aMem[mem0.hw_Mem] = pPrior;
|
||||
//mem0.hw_Mem = mem0.aMem.Length;
|
||||
pPrior = null;
|
||||
return;
|
||||
}
|
||||
static void sqlite3MemFreeBtCursor( ref BtCursor pPrior )
|
||||
{
|
||||
if ( pPrior == null )
|
||||
return;
|
||||
#if FALSE && DEBUG
|
||||
for ( int i = mem0.msBtCursor.next - 1; i >= 0; i-- ) if ( mem0.aBtCursor[i] != null && mem0.aBtCursor[i] == pPrior ) Debugger.Break();
|
||||
#endif
|
||||
mem0.msBtCursor.dealloc++;
|
||||
if ( mem0.msBtCursor.next < mem0.aBtCursor.Length - 1 )
|
||||
{
|
||||
mem0.aBtCursor[++mem0.msBtCursor.next] = pPrior;
|
||||
if ( mem0.msBtCursor.next > mem0.msBtCursor.max )
|
||||
mem0.msBtCursor.max = mem0.msBtCursor.next;
|
||||
}
|
||||
//Array.Resize( ref mem0.aBtCursor, (int)(mem0.hw_BtCursor * 1.5 + 1 ));
|
||||
//mem0.aBtCursor[mem0.hw_BtCursor] = pPrior;
|
||||
//mem0.hw_BtCursor = mem0.aBtCursor.Length;
|
||||
pPrior = null;
|
||||
return;
|
||||
}
|
||||
/*
|
||||
** Like realloc(). Resize an allocation previously obtained from
|
||||
** sqlite3MemMalloc().
|
||||
**
|
||||
** For this low-level interface, we know that pPrior!=0. Cases where
|
||||
** pPrior==0 while have been intercepted by higher-level routine and
|
||||
** redirected to xMalloc. Similarly, we know that nByte>0 becauses
|
||||
** cases where nByte<=0 will have been intercepted by higher-level
|
||||
** routines and redirected to xFree.
|
||||
*/
|
||||
static byte[] sqlite3MemRealloc( ref byte[] pPrior, int nByte )
|
||||
{
|
||||
// sqlite3_int64 p = (sqlite3_int64*)pPrior;
|
||||
// Debug.Assert(pPrior!=0 && nByte>0 );
|
||||
// nByte = ROUND8( nByte );
|
||||
// p = (sqlite3_int64*)pPrior;
|
||||
// p--;
|
||||
// p = realloc(p, nByte+8 );
|
||||
// if( p ){
|
||||
// p[0] = nByte;
|
||||
// p++;
|
||||
// }
|
||||
// return (void*)p;
|
||||
Array.Resize( ref pPrior, nByte );
|
||||
return pPrior;
|
||||
}
|
||||
#else
|
||||
/*
|
||||
** No-op versions of all memory allocation routines
|
||||
*/
|
||||
|
||||
private static byte[] sqlite3MemMalloc(int nByte)
|
||||
{
|
||||
return new byte[nByte];
|
||||
}
|
||||
|
||||
private static int[] sqlite3MemMallocInt(int nInt)
|
||||
{
|
||||
return new int[nInt];
|
||||
}
|
||||
|
||||
private static Mem sqlite3MemMallocMem(Mem pMem)
|
||||
{
|
||||
return new Mem();
|
||||
}
|
||||
|
||||
private static void sqlite3MemFree(ref byte[] pPrior)
|
||||
{
|
||||
pPrior = null;
|
||||
}
|
||||
|
||||
private static void sqlite3MemFreeInt(ref int[] pPrior)
|
||||
{
|
||||
pPrior = null;
|
||||
}
|
||||
|
||||
private static void sqlite3MemFreeMem(ref Mem pPrior)
|
||||
{
|
||||
pPrior = null;
|
||||
}
|
||||
|
||||
private static int sqlite3MemInit()
|
||||
{
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
private static void sqlite3MemShutdown()
|
||||
{
|
||||
}
|
||||
|
||||
private static BtCursor sqlite3MemMallocBtCursor(BtCursor dummy)
|
||||
{
|
||||
return new BtCursor();
|
||||
}
|
||||
|
||||
private static void sqlite3MemFreeBtCursor(ref BtCursor pPrior)
|
||||
{
|
||||
pPrior = null;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
private static byte[] sqlite3MemRealloc(byte[] pPrior, int nByte)
|
||||
{
|
||||
Array.Resize(ref pPrior, nByte);
|
||||
return pPrior;
|
||||
}
|
||||
|
||||
/*
|
||||
** Report the allocated size of a prior return from xMalloc()
|
||||
** or xRealloc().
|
||||
*/
|
||||
|
||||
private static int sqlite3MemSize(byte[] pPrior)
|
||||
{
|
||||
// sqlite3_int64 p;
|
||||
// if( pPrior==0 ) return 0;
|
||||
// p = (sqlite3_int64*)pPrior;
|
||||
// p--;
|
||||
// return p[0];
|
||||
return pPrior == null ? 0 : (int)pPrior.Length;
|
||||
}
|
||||
|
||||
/*
|
||||
** Round up a request size to the next valid allocation size.
|
||||
*/
|
||||
|
||||
private static int sqlite3MemRoundup(int n)
|
||||
{
|
||||
return n;// ROUND8( n );
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize this module.
|
||||
*/
|
||||
|
||||
private static int sqlite3MemInit(object NotUsed)
|
||||
{
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
if (!sqlite3GlobalConfig.bMemstat)
|
||||
{
|
||||
/* If memory status is enabled, then the malloc.c wrapper will already
|
||||
** hold the STATIC_MEM mutex when the routines here are invoked. */
|
||||
mem0.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Deinitialize this module.
|
||||
*/
|
||||
|
||||
private static void sqlite3MemShutdown(object NotUsed)
|
||||
{
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine is the only routine in this file with external linkage.
|
||||
**
|
||||
** Populate the low-level memory allocation function pointers in
|
||||
** sqlite3GlobalConfig.m with pointers to the routines in this file.
|
||||
*/
|
||||
|
||||
private static void sqlite3MemSetDefault()
|
||||
{
|
||||
sqlite3_mem_methods defaultMethods = new sqlite3_mem_methods(
|
||||
sqlite3MemMalloc,
|
||||
sqlite3MemMallocInt,
|
||||
sqlite3MemMallocMem,
|
||||
sqlite3MemFree,
|
||||
sqlite3MemFreeInt,
|
||||
sqlite3MemFreeMem,
|
||||
sqlite3MemRealloc,
|
||||
sqlite3MemSize,
|
||||
sqlite3MemRoundup,
|
||||
(dxMemInit)sqlite3MemInit,
|
||||
(dxMemShutdown)sqlite3MemShutdown,
|
||||
0
|
||||
);
|
||||
sqlite3_config(SQLITE_CONFIG_MALLOC, defaultMethods);
|
||||
}
|
||||
|
||||
private static void sqlite3DbFree(sqlite3 db, ref int[] pPrior)
|
||||
{
|
||||
if (pPrior != null)
|
||||
sqlite3MemFreeInt(ref pPrior);
|
||||
}
|
||||
|
||||
private static void sqlite3DbFree(sqlite3 db, ref Mem pPrior)
|
||||
{
|
||||
if (pPrior != null)
|
||||
sqlite3MemFreeMem(ref pPrior);
|
||||
}
|
||||
|
||||
private static void sqlite3DbFree(sqlite3 db, ref Mem[] pPrior)
|
||||
{
|
||||
if (pPrior != null)
|
||||
for (int i = 0; i < pPrior.Length; i++)
|
||||
sqlite3MemFreeMem(ref pPrior[i]);
|
||||
}
|
||||
|
||||
private static void sqlite3DbFree<T>(sqlite3 db, ref T pT) where T : class
|
||||
{
|
||||
}
|
||||
|
||||
private static void sqlite3DbFree(sqlite3 db, ref string pString)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
334
original/Community.CsharpSqlite/src/memjournal_c.cs
Normal file
334
original/Community.CsharpSqlite/src/memjournal_c.cs
Normal file
|
|
@ -0,0 +1,334 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
using u32 = System.UInt32;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
using MemJournal = Sqlite3.sqlite3_file;
|
||||
using sqlite3_int64 = System.Int64;
|
||||
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2007 August 22
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This file contains code use to implement an in-memory rollback journal.
|
||||
** The in-memory rollback journal is used to journal transactions for
|
||||
** ":memory:" databases and when the journal_mode=MEMORY pragma is used.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2010-12-07 20:14:09 a586a4deeb25330037a49df295b36aaf624d0f45
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
|
||||
//#include "sqliteInt.h"
|
||||
|
||||
/* Forward references to internal structures */
|
||||
//typedef struct MemJournal MemJournal;
|
||||
//typedef struct FilePoint FilePoint;
|
||||
//typedef struct FileChunk FileChunk;
|
||||
|
||||
/* Space to hold the rollback journal is allocated in increments of
|
||||
** this many bytes.
|
||||
**
|
||||
** The size chosen is a little less than a power of two. That way,
|
||||
** the FileChunk object will have a size that almost exactly fills
|
||||
** a power-of-two allocation. This mimimizes wasted space in power-of-two
|
||||
** memory allocators.
|
||||
*/
|
||||
|
||||
//#define JOURNAL_CHUNKSIZE ((int)(1024-sizeof(FileChunk*)))
|
||||
private const int JOURNAL_CHUNKSIZE = 4096;
|
||||
|
||||
/* Macro to find the minimum of two numeric values.
|
||||
*/
|
||||
|
||||
//#if !MIN
|
||||
//# define MIN(x,y) ((x)<(y)?(x):(y))
|
||||
//#endif
|
||||
private static int MIN(int x, int y)
|
||||
{
|
||||
return (x < y) ? x : y;
|
||||
}
|
||||
|
||||
private static int MIN(int x, u32 y)
|
||||
{
|
||||
return (x < y) ? x : (int)y;
|
||||
}
|
||||
|
||||
/*
|
||||
** The rollback journal is composed of a linked list of these structures.
|
||||
*/
|
||||
|
||||
public class FileChunk
|
||||
{
|
||||
public FileChunk pNext; /* Next chunk in the journal */
|
||||
public byte[] zChunk = new byte[JOURNAL_CHUNKSIZE]; /* Content of this chunk */
|
||||
};
|
||||
|
||||
/*
|
||||
** An instance of this object serves as a cursor into the rollback journal.
|
||||
** The cursor can be either for reading or writing.
|
||||
*/
|
||||
|
||||
public class FilePoint
|
||||
{
|
||||
public long iOffset; /* Offset from the beginning of the file */
|
||||
public FileChunk pChunk; /* Specific chunk into which cursor points */
|
||||
};
|
||||
|
||||
/*
|
||||
** This subclass is a subclass of sqlite3_file. Each open memory-journal
|
||||
** is an instance of this class.
|
||||
*/
|
||||
|
||||
public partial class sqlite3_file
|
||||
{
|
||||
//public sqlite3_io_methods pMethods; /* Parent class. MUST BE FIRST */
|
||||
public FileChunk pFirst; /* Head of in-memory chunk-list */
|
||||
|
||||
public FilePoint endpoint; /* Pointer to the end of the file */
|
||||
public FilePoint readpoint; /* Pointer to the end of the last xRead() */
|
||||
};
|
||||
|
||||
/*
|
||||
** Read data from the in-memory journal file. This is the implementation
|
||||
** of the sqlite3_vfs.xRead method.
|
||||
*/
|
||||
|
||||
private static int memjrnlRead(
|
||||
sqlite3_file pJfd, /* The journal file from which to read */
|
||||
byte[] zBuf, /* Put the results here */
|
||||
int iAmt, /* Number of bytes to read */
|
||||
sqlite3_int64 iOfst /* Begin reading at this offset */
|
||||
)
|
||||
{
|
||||
MemJournal p = (MemJournal)pJfd;
|
||||
byte[] zOut = zBuf;
|
||||
int nRead = iAmt;
|
||||
int iChunkOffset;
|
||||
FileChunk pChunk;
|
||||
|
||||
/* SQLite never tries to read past the end of a rollback journal file */
|
||||
Debug.Assert(iOfst + iAmt <= p.endpoint.iOffset);
|
||||
|
||||
if (p.readpoint.iOffset != iOfst || iOfst == 0)
|
||||
{
|
||||
int iOff = 0;
|
||||
for (pChunk = p.pFirst;
|
||||
ALWAYS(pChunk != null) && (iOff + JOURNAL_CHUNKSIZE) <= iOfst;
|
||||
pChunk = pChunk.pNext
|
||||
)
|
||||
{
|
||||
iOff += JOURNAL_CHUNKSIZE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pChunk = p.readpoint.pChunk;
|
||||
}
|
||||
|
||||
iChunkOffset = (int)(iOfst % JOURNAL_CHUNKSIZE);
|
||||
int izOut = 0;
|
||||
do
|
||||
{
|
||||
int iSpace = JOURNAL_CHUNKSIZE - iChunkOffset;
|
||||
int nCopy = MIN(nRead, (JOURNAL_CHUNKSIZE - iChunkOffset));
|
||||
Buffer.BlockCopy(pChunk.zChunk, iChunkOffset, zOut, izOut, nCopy); //memcpy( zOut, pChunk.zChunk[iChunkOffset], nCopy );
|
||||
izOut += nCopy;// zOut += nCopy;
|
||||
nRead -= iSpace;
|
||||
iChunkOffset = 0;
|
||||
} while (nRead >= 0 && (pChunk = pChunk.pNext) != null && nRead > 0);
|
||||
p.readpoint.iOffset = (int)(iOfst + iAmt);
|
||||
p.readpoint.pChunk = pChunk;
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Write data to the file.
|
||||
*/
|
||||
|
||||
private static int memjrnlWrite(
|
||||
sqlite3_file pJfd, /* The journal file into which to write */
|
||||
byte[] zBuf, /* Take data to be written from here */
|
||||
int iAmt, /* Number of bytes to write */
|
||||
sqlite3_int64 iOfst /* Begin writing at this offset into the file */
|
||||
)
|
||||
{
|
||||
MemJournal p = (MemJournal)pJfd;
|
||||
int nWrite = iAmt;
|
||||
byte[] zWrite = zBuf;
|
||||
int izWrite = 0;
|
||||
|
||||
/* An in-memory journal file should only ever be appended to. Random
|
||||
** access writes are not required by sqlite.
|
||||
*/
|
||||
Debug.Assert(iOfst == p.endpoint.iOffset);
|
||||
UNUSED_PARAMETER(iOfst);
|
||||
|
||||
while (nWrite > 0)
|
||||
{
|
||||
FileChunk pChunk = p.endpoint.pChunk;
|
||||
int iChunkOffset = (int)(p.endpoint.iOffset % JOURNAL_CHUNKSIZE);
|
||||
int iSpace = MIN(nWrite, JOURNAL_CHUNKSIZE - iChunkOffset);
|
||||
|
||||
if (iChunkOffset == 0)
|
||||
{
|
||||
/* New chunk is required to extend the file. */
|
||||
FileChunk pNew = new FileChunk();// sqlite3_malloc( sizeof( FileChunk ) );
|
||||
if (null == pNew)
|
||||
{
|
||||
return SQLITE_IOERR_NOMEM;
|
||||
}
|
||||
pNew.pNext = null;
|
||||
if (pChunk != null)
|
||||
{
|
||||
Debug.Assert(p.pFirst != null);
|
||||
pChunk.pNext = pNew;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Assert(null == p.pFirst);
|
||||
p.pFirst = pNew;
|
||||
}
|
||||
p.endpoint.pChunk = pNew;
|
||||
}
|
||||
|
||||
Buffer.BlockCopy(zWrite, izWrite, p.endpoint.pChunk.zChunk, iChunkOffset, iSpace); //memcpy( &p.endpoint.pChunk.zChunk[iChunkOffset], zWrite, iSpace );
|
||||
izWrite += iSpace;//zWrite += iSpace;
|
||||
nWrite -= iSpace;
|
||||
p.endpoint.iOffset += iSpace;
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Truncate the file.
|
||||
*/
|
||||
|
||||
private static int memjrnlTruncate(sqlite3_file pJfd, sqlite3_int64 size)
|
||||
{
|
||||
MemJournal p = (MemJournal)pJfd;
|
||||
////FileChunk pChunk;
|
||||
Debug.Assert(size == 0);
|
||||
UNUSED_PARAMETER(size);
|
||||
////pChunk = p.pFirst;
|
||||
////while ( pChunk != null )
|
||||
////{
|
||||
////FileChunk pTmp = pChunk;
|
||||
////pChunk = pChunk.pNext;
|
||||
////sqlite3_free( ref pTmp );
|
||||
////}
|
||||
sqlite3MemJournalOpen(pJfd);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Close the file.
|
||||
*/
|
||||
|
||||
private static int memjrnlClose(MemJournal pJfd)
|
||||
{
|
||||
memjrnlTruncate(pJfd, 0);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Sync the file.
|
||||
**
|
||||
** Syncing an in-memory journal is a no-op. And, in fact, this routine
|
||||
** is never called in a working implementation. This implementation
|
||||
** exists purely as a contingency, in case some malfunction in some other
|
||||
** part of SQLite causes Sync to be called by mistake.
|
||||
*/
|
||||
|
||||
private static int memjrnlSync(sqlite3_file NotUsed, int NotUsed2)
|
||||
{
|
||||
UNUSED_PARAMETER2(NotUsed, NotUsed2);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Query the size of the file in bytes.
|
||||
*/
|
||||
|
||||
private static int memjrnlFileSize(sqlite3_file pJfd, ref long pSize)
|
||||
{
|
||||
MemJournal p = (MemJournal)pJfd;
|
||||
pSize = p.endpoint.iOffset;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Table of methods for MemJournal sqlite3_file object.
|
||||
*/
|
||||
|
||||
private static sqlite3_io_methods MemJournalMethods = new sqlite3_io_methods(
|
||||
1, /* iVersion */
|
||||
(dxClose)memjrnlClose, /* xClose */
|
||||
(dxRead)memjrnlRead, /* xRead */
|
||||
(dxWrite)memjrnlWrite, /* xWrite */
|
||||
(dxTruncate)memjrnlTruncate, /* xTruncate */
|
||||
(dxSync)memjrnlSync, /* xSync */
|
||||
(dxFileSize)memjrnlFileSize, /* xFileSize */
|
||||
null, /* xLock */
|
||||
null, /* xUnlock */
|
||||
null, /* xCheckReservedLock */
|
||||
null, /* xFileControl */
|
||||
null, /* xSectorSize */
|
||||
null, /* xDeviceCharacteristics */
|
||||
null, /* xShmMap */
|
||||
null, /* xShmLock */
|
||||
null, /* xShmBarrier */
|
||||
null /* xShmUnlock */
|
||||
);
|
||||
|
||||
/*
|
||||
** Open a journal file.
|
||||
*/
|
||||
|
||||
private static void sqlite3MemJournalOpen(sqlite3_file pJfd)
|
||||
{
|
||||
MemJournal p = (MemJournal)pJfd;
|
||||
//memset( p, 0, sqlite3MemJournalSize() );
|
||||
p.pFirst = null;
|
||||
p.endpoint = new FilePoint();
|
||||
p.readpoint = new FilePoint();
|
||||
p.pMethods = MemJournalMethods;//(sqlite3_io_methods*)&MemJournalMethods;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if the file-handle passed as an argument is
|
||||
** an in-memory journal
|
||||
*/
|
||||
|
||||
private static bool sqlite3IsMemJournal(sqlite3_file pJfd)
|
||||
{
|
||||
return pJfd.pMethods == MemJournalMethods;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of bytes required to store a MemJournal file descriptor.
|
||||
*/
|
||||
|
||||
private static int sqlite3MemJournalSize()
|
||||
{
|
||||
return 3096; // sizeof( MemJournal );
|
||||
}
|
||||
}
|
||||
}
|
||||
197
original/Community.CsharpSqlite/src/mutex_c.cs
Normal file
197
original/Community.CsharpSqlite/src/mutex_c.cs
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
using System.Diagnostics;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2007 August 14
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains the C functions that implement mutexes.
|
||||
**
|
||||
** This file contains code that is common across all mutex implementations.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2011-05-19 13:26:54 ed1da510a239ea767a01dc332b667119fa3c908e
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#include "sqliteInt.h"
|
||||
|
||||
#if (SQLITE_DEBUG) && !(SQLITE_MUTEX_OMIT)
|
||||
/*
|
||||
** For debugging purposes, record when the mutex subsystem is initialized
|
||||
** and uninitialized so that we can assert() if there is an attempt to
|
||||
** allocate a mutex while the system is uninitialized.
|
||||
*/
|
||||
private static int mutexIsInit = 0;
|
||||
#endif //* SQLITE_DEBUG */
|
||||
|
||||
#if !SQLITE_MUTEX_OMIT
|
||||
/*
|
||||
** Initialize the mutex system.
|
||||
*/
|
||||
|
||||
private static int sqlite3MutexInit()
|
||||
{
|
||||
int rc = SQLITE_OK;
|
||||
if (null == sqlite3GlobalConfig.mutex.xMutexAlloc)
|
||||
{
|
||||
/* If the xMutexAlloc method has not been set, then the user did not
|
||||
** install a mutex implementation via sqlite3_config() prior to
|
||||
** sqlite3_initialize() being called. This block copies pointers to
|
||||
** the default implementation into the sqlite3GlobalConfig structure.
|
||||
*/
|
||||
sqlite3_mutex_methods pFrom;
|
||||
sqlite3_mutex_methods pTo = sqlite3GlobalConfig.mutex;
|
||||
|
||||
if (sqlite3GlobalConfig.bCoreMutex)
|
||||
{
|
||||
pFrom = sqlite3DefaultMutex();
|
||||
}
|
||||
else
|
||||
{
|
||||
pFrom = sqlite3NoopMutex();
|
||||
}
|
||||
//memcpy(pTo, pFrom, offsetof(sqlite3_mutex_methods, xMutexAlloc));
|
||||
//memcpy(pTo.xMutexFree, pFrom.xMutexFree,
|
||||
// sizeof(*pTo) - offsetof(sqlite3_mutex_methods, xMutexFree));
|
||||
pTo.Copy(pFrom);
|
||||
}
|
||||
rc = sqlite3GlobalConfig.mutex.xMutexInit();
|
||||
|
||||
#if SQLITE_DEBUG
|
||||
mutexIsInit = 1; //GLOBAL(int, mutexIsInit) = 1;
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Shutdown the mutex system. This call frees resources allocated by
|
||||
** sqlite3MutexInit().
|
||||
*/
|
||||
|
||||
private static int sqlite3MutexEnd()
|
||||
{
|
||||
int rc = SQLITE_OK;
|
||||
if (sqlite3GlobalConfig.mutex.xMutexEnd != null)
|
||||
{
|
||||
rc = sqlite3GlobalConfig.mutex.xMutexEnd();
|
||||
}
|
||||
|
||||
#if SQLITE_DEBUG
|
||||
mutexIsInit = 0;//GLOBAL(int, mutexIsInit) = 0;
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Retrieve a pointer to a static mutex or allocate a new dynamic one.
|
||||
*/
|
||||
|
||||
private static sqlite3_mutex sqlite3_mutex_alloc(int id)
|
||||
{
|
||||
#if !SQLITE_OMIT_AUTOINIT
|
||||
if (sqlite3_initialize() != 0) return null;
|
||||
#endif
|
||||
return sqlite3GlobalConfig.mutex.xMutexAlloc(id);
|
||||
}
|
||||
|
||||
private static sqlite3_mutex sqlite3MutexAlloc(int id)
|
||||
{
|
||||
if (!sqlite3GlobalConfig.bCoreMutex)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
Debug.Assert(mutexIsInit != 0);//assert( GLOBAL(int, mutexIsInit) );
|
||||
return sqlite3GlobalConfig.mutex.xMutexAlloc(id);
|
||||
}
|
||||
|
||||
/*
|
||||
** Free a dynamic mutex.
|
||||
*/
|
||||
|
||||
private static void sqlite3_mutex_free(sqlite3_mutex p)
|
||||
{
|
||||
if (p != null)
|
||||
{
|
||||
sqlite3GlobalConfig.mutex.xMutexFree(p);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Obtain the mutex p. If some other thread already has the mutex, block
|
||||
** until it can be obtained.
|
||||
*/
|
||||
|
||||
private static void sqlite3_mutex_enter(sqlite3_mutex p)
|
||||
{
|
||||
if (p != null)
|
||||
{
|
||||
sqlite3GlobalConfig.mutex.xMutexEnter(p);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Obtain the mutex p. If successful, return SQLITE_OK. Otherwise, if another
|
||||
** thread holds the mutex and it cannot be obtained, return SQLITE_BUSY.
|
||||
*/
|
||||
|
||||
private static int sqlite3_mutex_try(sqlite3_mutex p)
|
||||
{
|
||||
int rc = SQLITE_OK;
|
||||
if (p != null)
|
||||
{
|
||||
return sqlite3GlobalConfig.mutex.xMutexTry(p);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** The sqlite3_mutex_leave() routine exits a mutex that was previously
|
||||
** entered by the same thread. The behavior is undefined if the mutex
|
||||
** is not currently entered. If a NULL pointer is passed as an argument
|
||||
** this function is a no-op.
|
||||
*/
|
||||
|
||||
private static void sqlite3_mutex_leave(sqlite3_mutex p)
|
||||
{
|
||||
if (p != null)
|
||||
{
|
||||
sqlite3GlobalConfig.mutex.xMutexLeave(p);
|
||||
}
|
||||
}
|
||||
|
||||
#if !NDEBUG
|
||||
/*
|
||||
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
|
||||
** intended for use inside assert() statements.
|
||||
*/
|
||||
|
||||
private static bool sqlite3_mutex_held(sqlite3_mutex p)
|
||||
{
|
||||
return p == null || sqlite3GlobalConfig.mutex.xMutexHeld(p);
|
||||
}
|
||||
|
||||
private static bool sqlite3_mutex_notheld(sqlite3_mutex p)
|
||||
{
|
||||
return p == null || sqlite3GlobalConfig.mutex.xMutexNotheld(p);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif //* SQLITE_MUTEX_OMIT */
|
||||
}
|
||||
}
|
||||
148
original/Community.CsharpSqlite/src/mutex_h.cs
Normal file
148
original/Community.CsharpSqlite/src/mutex_h.cs
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
#define SQLITE_OS_WIN
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2007 August 28
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This file contains the common header for all mutex implementations.
|
||||
** The sqliteInt.h header #includes this file so that it is available
|
||||
** to all source files. We break it out in an effort to keep the code
|
||||
** better organized.
|
||||
**
|
||||
** NOTE: source files should *not* #include this header file directly.
|
||||
** Source files should #include the sqliteInt.h file and let that file
|
||||
** include this one indirectly.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2010-12-07 20:14:09 a586a4deeb25330037a49df295b36aaf624d0f45
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
** Figure out what version of the code to use. The choices are
|
||||
**
|
||||
** SQLITE_MUTEX_OMIT No mutex logic. Not even stubs. The
|
||||
** mutexes implemention cannot be overridden
|
||||
** at start-time.
|
||||
**
|
||||
** SQLITE_MUTEX_NOOP For single-threaded applications. No
|
||||
** mutual exclusion is provided. But this
|
||||
** implementation can be overridden at
|
||||
** start-time.
|
||||
**
|
||||
** SQLITE_MUTEX_PTHREADS For multi-threaded applications on Unix.
|
||||
**
|
||||
** SQLITE_MUTEX_W32 For multi-threaded applications on Win32.
|
||||
**
|
||||
** SQLITE_MUTEX_OS2 For multi-threaded applications on OS/2.
|
||||
*/
|
||||
|
||||
//#if !SQLITE_THREADSAFE
|
||||
//# define SQLITE_MUTEX_OMIT
|
||||
//#endif
|
||||
//#if SQLITE_THREADSAFE && !defined(SQLITE_MUTEX_NOOP)
|
||||
//# if SQLITE_OS_UNIX
|
||||
//# define SQLITE_MUTEX_PTHREADS
|
||||
//# elif SQLITE_OS_WIN
|
||||
//# define SQLITE_MUTEX_W32
|
||||
//# elif SQLITE_OS_OS2
|
||||
//# define SQLITE_MUTEX_OS2
|
||||
//# else
|
||||
//# define SQLITE_MUTEX_NOOP
|
||||
//# endif
|
||||
//#endif
|
||||
|
||||
#if WINDOWS_PHONE && SQLITE_THREADSAFE
|
||||
#error Cannot compile with both WINDOWS_PHONE and SQLITE_THREADSAFE
|
||||
#endif
|
||||
|
||||
#if SQLITE_SILVERLIGHT && SQLITE_THREADSAFE
|
||||
#error Cannot compile with both SQLITE_SILVERLIGHT and SQLITE_THREADSAFE
|
||||
#endif
|
||||
|
||||
#if SQLITE_WINRT && SQLITE_THREADSAFE
|
||||
#error Cannot compile with both SQLITE_WINRT and SQLITE_THREADSAFE
|
||||
#endif
|
||||
|
||||
#if SQLITE_THREADSAFE && SQLITE_MUTEX_NOOP
|
||||
#error Cannot compile with both SQLITE_THREADSAFE and SQLITE_MUTEX_NOOP
|
||||
#endif
|
||||
|
||||
#if SQLITE_THREADSAFE && SQLITE_MUTEX_OMIT
|
||||
#error Cannot compile with both SQLITE_THREADSAFE and SQLITE_MUTEX_OMIT
|
||||
#endif
|
||||
|
||||
#if SQLITE_MUTEX_OMIT && SQLITE_MUTEX_NOOP
|
||||
#error Cannot compile with both SQLITE_MUTEX_OMIT and SQLITE_MUTEX_NOOP
|
||||
#endif
|
||||
|
||||
#if SQLITE_MUTEX_OMIT && SQLITE_MUTEX_W32
|
||||
#error Cannot compile with both SQLITE_MUTEX_OMIT and SQLITE_MUTEX_W32
|
||||
#endif
|
||||
|
||||
#if SQLITE_MUTEX_NOOP && SQLITE_MUTEX_W32
|
||||
#error Cannot compile with both SQLITE_MUTEX_NOOP and SQLITE_MUTEX_W32
|
||||
#endif
|
||||
|
||||
#if SQLITE_MUTEX_OMIT
|
||||
/*
|
||||
** If this is a no-op implementation, implement everything as macros.
|
||||
*/
|
||||
public class sqlite3_mutex
|
||||
{
|
||||
}
|
||||
static sqlite3_mutex mutex = null; //sqlite3_mutex sqlite3_mutex;
|
||||
static sqlite3_mutex sqlite3MutexAlloc( int iType )
|
||||
{
|
||||
return new sqlite3_mutex();
|
||||
}//#define sqlite3MutexAlloc(X) ((sqlite3_mutex*)8)
|
||||
static sqlite3_mutex sqlite3_mutex_alloc( int iType )
|
||||
{
|
||||
return new sqlite3_mutex();
|
||||
}//#define sqlite3_mutex_alloc(X) ((sqlite3_mutex*)8)
|
||||
static void sqlite3_mutex_free( sqlite3_mutex m )
|
||||
{
|
||||
} //#define sqlite3_mutex_free(X)
|
||||
static void sqlite3_mutex_enter( sqlite3_mutex m )
|
||||
{
|
||||
} //#define sqlite3_mutex_enter(X)
|
||||
static int sqlite3_mutex_try( int iType )
|
||||
{
|
||||
return SQLITE_OK;
|
||||
} //#define sqlite3_mutex_try(X) SQLITE_OK
|
||||
static void sqlite3_mutex_leave( sqlite3_mutex m )
|
||||
{
|
||||
} //#define sqlite3_mutex_leave(X)
|
||||
static bool sqlite3_mutex_held( sqlite3_mutex m )
|
||||
{
|
||||
return true;
|
||||
}//#define sqlite3_mutex_held(X) ((void)(X),1)
|
||||
static bool sqlite3_mutex_notheld( sqlite3_mutex m )
|
||||
{
|
||||
return true;
|
||||
} //#define sqlite3_mutex_notheld(X) ((void)(X),1)
|
||||
static int sqlite3MutexInit()
|
||||
{
|
||||
return SQLITE_OK;
|
||||
} //#define sqlite3MutexInit() SQLITE_OK
|
||||
static void sqlite3MutexEnd()
|
||||
{
|
||||
} //#define sqlite3MutexEnd()
|
||||
#endif //* defined(SQLITE_MUTEX_OMIT) */
|
||||
}
|
||||
}
|
||||
248
original/Community.CsharpSqlite/src/mutex_noop_c.cs
Normal file
248
original/Community.CsharpSqlite/src/mutex_noop_c.cs
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
using System.Diagnostics;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2008 October 07
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains the C functions that implement mutexes.
|
||||
**
|
||||
** This implementation in this file does not provide any mutual
|
||||
** exclusion and is thus suitable for use only in applications
|
||||
** that use SQLite in a single thread. The routines defined
|
||||
** here are place-holders. Applications can substitute working
|
||||
** mutex routines at start-time using the
|
||||
**
|
||||
** sqlite3_config(SQLITE_CONFIG_MUTEX,...)
|
||||
**
|
||||
** interface.
|
||||
**
|
||||
** If compiled with SQLITE_DEBUG, then additional logic is inserted
|
||||
** that does error checking on mutexes to make sure they are being
|
||||
** called correctly.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2009-12-07 16:39:13 1ed88e9d01e9eda5cbc622e7614277f29bcc551c
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#include "sqliteInt.h"
|
||||
|
||||
#if !SQLITE_DEBUG
|
||||
/*
|
||||
** Stub routines for all mutex methods.
|
||||
**
|
||||
** This routines provide no mutual exclusion or error checking.
|
||||
*/
|
||||
static int noopMutexHeld(sqlite3_mutex p){ return 1; }
|
||||
static int noopMutexNotheld(sqlite3_mutex p){ return 1; }
|
||||
static int noopMutexInit(){ return SQLITE_OK; }
|
||||
static int noopMutexEnd(){ return SQLITE_OK; }
|
||||
static sqlite3_mutex noopMutexAlloc(int id){ return new sqlite3_mutex(); }
|
||||
static void noopMutexFree(sqlite3_mutex p){ }
|
||||
static void noopMutexEnter(sqlite3_mutex p){ }
|
||||
static int noopMutexTry(sqlite3_mutex p){ return SQLITE_OK; }
|
||||
static void noopMutexLeave(sqlite3_mutex p){ }
|
||||
|
||||
sqlite3_mutex_methods sqlite3NoopMutex(){
|
||||
sqlite3_mutex_methods sMutex = new sqlite3_mutex_methods(
|
||||
(dxMutexInit)noopMutexInit,
|
||||
(dxMutexEnd)noopMutexEnd,
|
||||
(dxMutexAlloc)noopMutexAlloc,
|
||||
(dxMutexFree)noopMutexFree,
|
||||
(dxMutexEnter)noopMutexEnter,
|
||||
(dxMutexTry)noopMutexTry,
|
||||
(dxMutexLeave)noopMutexLeave,
|
||||
#if SQLITE_DEBUG
|
||||
(dxMutexHeld)noopMutexHeld,
|
||||
(dxMutexNotheld)noopMutexNotheld
|
||||
#else
|
||||
null,
|
||||
null
|
||||
#endif
|
||||
);
|
||||
|
||||
return sMutex;
|
||||
}
|
||||
#endif //* !SQLITE_DEBUG */
|
||||
|
||||
#if SQLITE_DEBUG && !SQLITE_MUTEX_OMIT
|
||||
/*
|
||||
** In this implementation, error checking is provided for testing
|
||||
** and debugging purposes. The mutexes still do not provide any
|
||||
** mutual exclusion.
|
||||
*/
|
||||
|
||||
/*
|
||||
** The mutex object
|
||||
*/
|
||||
|
||||
public class sqlite3_debug_mutex : sqlite3_mutex
|
||||
{
|
||||
//public int id; /* The mutex type */
|
||||
public int cnt; /* Number of entries without a matching leave */
|
||||
};
|
||||
|
||||
/*
|
||||
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
|
||||
** intended for use inside Debug.Assert() statements.
|
||||
*/
|
||||
|
||||
private static bool debugMutexHeld(sqlite3_mutex pX)
|
||||
{
|
||||
sqlite3_debug_mutex p = (sqlite3_debug_mutex)pX;
|
||||
return p == null || p.cnt > 0;
|
||||
}
|
||||
|
||||
private static bool debugMutexNotheld(sqlite3_mutex pX)
|
||||
{
|
||||
sqlite3_debug_mutex p = (sqlite3_debug_mutex)pX;
|
||||
return p == null || p.cnt == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize and deinitialize the mutex subsystem.
|
||||
*/
|
||||
|
||||
private static int debugMutexInit()
|
||||
{
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
private static int debugMutexEnd()
|
||||
{
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** The sqlite3_mutex_alloc() routine allocates a new
|
||||
** mutex and returns a pointer to it. If it returns NULL
|
||||
** that means that a mutex could not be allocated.
|
||||
*/
|
||||
|
||||
private static sqlite3_mutex debugMutexAlloc(int id)
|
||||
{
|
||||
sqlite3_debug_mutex[] aStatic = new sqlite3_debug_mutex[6];
|
||||
sqlite3_debug_mutex pNew = null;
|
||||
switch (id)
|
||||
{
|
||||
case SQLITE_MUTEX_FAST:
|
||||
case SQLITE_MUTEX_RECURSIVE:
|
||||
{
|
||||
pNew = new sqlite3_debug_mutex();//sqlite3Malloc(sizeof(*pNew));
|
||||
if (pNew != null)
|
||||
{
|
||||
pNew.id = id;
|
||||
pNew.cnt = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
Debug.Assert(id - 2 >= 0);
|
||||
Debug.Assert(id - 2 < aStatic.Length);//(int)(sizeof(aStatic)/sizeof(aStatic[0])) );
|
||||
pNew = aStatic[id - 2];
|
||||
pNew.id = id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return pNew;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine deallocates a previously allocated mutex.
|
||||
*/
|
||||
|
||||
private static void debugMutexFree(sqlite3_mutex pX)
|
||||
{
|
||||
sqlite3_debug_mutex p = (sqlite3_debug_mutex)pX;
|
||||
Debug.Assert(p.cnt == 0);
|
||||
Debug.Assert(p.id == SQLITE_MUTEX_FAST || p.id == SQLITE_MUTEX_RECURSIVE);
|
||||
//sqlite3_free(ref p);
|
||||
}
|
||||
|
||||
/*
|
||||
** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
|
||||
** to enter a mutex. If another thread is already within the mutex,
|
||||
** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return
|
||||
** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK
|
||||
** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can
|
||||
** be entered multiple times by the same thread. In such cases the,
|
||||
** mutex must be exited an equal number of times before another thread
|
||||
** can enter. If the same thread tries to enter any other kind of mutex
|
||||
** more than once, the behavior is undefined.
|
||||
*/
|
||||
|
||||
private static void debugMutexEnter(sqlite3_mutex pX)
|
||||
{
|
||||
sqlite3_debug_mutex p = (sqlite3_debug_mutex)pX;
|
||||
Debug.Assert(p.id == SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(p));
|
||||
p.cnt++;
|
||||
}
|
||||
|
||||
private static int debugMutexTry(sqlite3_mutex pX)
|
||||
{
|
||||
sqlite3_debug_mutex p = (sqlite3_debug_mutex)pX;
|
||||
Debug.Assert(p.id == SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(p));
|
||||
p.cnt++;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** The sqlite3_mutex_leave() routine exits a mutex that was
|
||||
** previously entered by the same thread. The behavior
|
||||
** is undefined if the mutex is not currently entered or
|
||||
** is not currently allocated. SQLite will never do either.
|
||||
*/
|
||||
|
||||
private static void debugMutexLeave(sqlite3_mutex pX)
|
||||
{
|
||||
sqlite3_debug_mutex p = (sqlite3_debug_mutex)pX;
|
||||
Debug.Assert(debugMutexHeld(p));
|
||||
p.cnt--;
|
||||
Debug.Assert(p.id == SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(p));
|
||||
}
|
||||
|
||||
private static sqlite3_mutex_methods sqlite3NoopMutex()
|
||||
{
|
||||
sqlite3_mutex_methods sMutex = new sqlite3_mutex_methods(
|
||||
(dxMutexInit)debugMutexInit,
|
||||
(dxMutexEnd)debugMutexEnd,
|
||||
(dxMutexAlloc)debugMutexAlloc,
|
||||
(dxMutexFree)debugMutexFree,
|
||||
(dxMutexEnter)debugMutexEnter,
|
||||
(dxMutexTry)debugMutexTry,
|
||||
(dxMutexLeave)debugMutexLeave,
|
||||
|
||||
(dxMutexHeld)debugMutexHeld,
|
||||
(dxMutexNotheld)debugMutexNotheld
|
||||
);
|
||||
|
||||
return sMutex;
|
||||
}
|
||||
|
||||
#endif //* SQLITE_DEBUG */
|
||||
|
||||
/*
|
||||
** If compiled with SQLITE_MUTEX_NOOP, then the no-op mutex implementation
|
||||
** is used regardless of the run-time threadsafety setting.
|
||||
*/
|
||||
#if SQLITE_MUTEX_NOOP
|
||||
sqlite3_mutex_methods const sqlite3DefaultMutex(void){
|
||||
return sqlite3NoopMutex();
|
||||
}
|
||||
#endif //* SQLITE_MUTEX_NOOP */
|
||||
}
|
||||
}
|
||||
435
original/Community.CsharpSqlite/src/mutex_w32.cs
Normal file
435
original/Community.CsharpSqlite/src/mutex_w32.cs
Normal file
|
|
@ -0,0 +1,435 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using DWORD = System.Int32;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2007 August 14
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains the C functions that implement mutexes for win32
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2010-03-09 19:31:43 4ae453ea7be69018d8c16eb8dabe05617397dc4d
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** The code in this file is only used if we are compiling multithreaded
|
||||
** on a win32 system.
|
||||
*/
|
||||
#if SQLITE_MUTEX_W32
|
||||
|
||||
/*
|
||||
** Each recursive mutex is an instance of the following structure.
|
||||
*/
|
||||
|
||||
public partial class sqlite3_mutex
|
||||
{
|
||||
public Object mutex; /* Mutex controlling the lock */
|
||||
public int id; /* Mutex type */
|
||||
public int nRef; /* Number of enterances */
|
||||
public DWORD owner; /* Thread holding this mutex */
|
||||
#if SQLITE_DEBUG
|
||||
public int trace; /* True to trace changes */
|
||||
#endif
|
||||
|
||||
public sqlite3_mutex()
|
||||
{
|
||||
mutex = new Object();
|
||||
}
|
||||
|
||||
public sqlite3_mutex(Mutex mutex, int id, int nRef, DWORD owner
|
||||
#if SQLITE_DEBUG
|
||||
, int trace
|
||||
#endif
|
||||
)
|
||||
{
|
||||
this.mutex = mutex;
|
||||
this.id = id;
|
||||
this.nRef = nRef;
|
||||
this.owner = owner;
|
||||
#if SQLITE_DEBUG
|
||||
this.trace = 0;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
//#define SQLITE_W32_MUTEX_INITIALIZER { 0 }
|
||||
private static Mutex SQLITE_W32_MUTEX_INITIALIZER = null;
|
||||
|
||||
#if SQLITE_DEBUG
|
||||
//#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0, 0L, (DWORD)0, 0 }
|
||||
#else
|
||||
//#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0, 0L, (DWORD)0 }
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Return true (non-zero) if we are running under WinNT, Win2K, WinXP,
|
||||
** or WinCE. Return false (zero) for Win95, Win98, or WinME.
|
||||
**
|
||||
** Here is an interesting observation: Win95, Win98, and WinME lack
|
||||
** the LockFileEx() API. But we can still statically link against that
|
||||
** API as long as we don't call it win running Win95/98/ME. A call to
|
||||
** this routine is used to determine if the host is Win95/98/ME or
|
||||
** WinNT/2K/XP so that we will know whether or not we can safely call
|
||||
** the LockFileEx() API.
|
||||
**
|
||||
** mutexIsNT() is only used for the TryEnterCriticalSection() API call,
|
||||
** which is only available if your application was compiled with
|
||||
** _WIN32_WINNT defined to a value >= 0x0400. Currently, the only
|
||||
** call to TryEnterCriticalSection() is #ifdef'ed out, so #if
|
||||
** this out as well.
|
||||
*/
|
||||
#if FALSE
|
||||
#if SQLITE_OS_WINCE
|
||||
//# define mutexIsNT() (1)
|
||||
#else
|
||||
static int mutexIsNT(void){
|
||||
static int osType = 0;
|
||||
if( osType==0 ){
|
||||
OSVERSIONINFO sInfo;
|
||||
sInfo.dwOSVersionInfoSize = sizeof(sInfo);
|
||||
GetVersionEx(&sInfo);
|
||||
osType = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
|
||||
}
|
||||
return osType==2;
|
||||
}
|
||||
#endif //* SQLITE_OS_WINCE */
|
||||
#endif
|
||||
|
||||
#if SQLITE_DEBUG
|
||||
/*
|
||||
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
|
||||
** intended for use only inside Debug.Assert() statements.
|
||||
*/
|
||||
|
||||
private static bool winMutexHeld(sqlite3_mutex p)
|
||||
{
|
||||
return p.nRef != 0 && p.owner == GetCurrentThreadId();
|
||||
}
|
||||
|
||||
private static bool winMutexNotheld2(sqlite3_mutex p, DWORD tid)
|
||||
{
|
||||
return p.nRef == 0 || p.owner != tid;
|
||||
}
|
||||
|
||||
private static bool winMutexNotheld(sqlite3_mutex p)
|
||||
{
|
||||
DWORD tid = GetCurrentThreadId();
|
||||
return winMutexNotheld2(p, tid);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Initialize and deinitialize the mutex subsystem.
|
||||
*/
|
||||
|
||||
//No MACROS under C#; Cannot use SQLITE3_MUTEX_INITIALIZER,
|
||||
private static sqlite3_mutex[] winMutex_staticMutexes = new sqlite3_mutex[]{
|
||||
new sqlite3_mutex( SQLITE_W32_MUTEX_INITIALIZER, 0, 0, (DWORD)0
|
||||
#if SQLITE_DEBUG
|
||||
, 0
|
||||
#endif
|
||||
),// SQLITE3_MUTEX_INITIALIZER,
|
||||
new sqlite3_mutex( SQLITE_W32_MUTEX_INITIALIZER, 0, 0, (DWORD)0
|
||||
#if SQLITE_DEBUG
|
||||
, 0
|
||||
#endif
|
||||
),// SQLITE3_MUTEX_INITIALIZER,
|
||||
new sqlite3_mutex( SQLITE_W32_MUTEX_INITIALIZER, 0, 0, (DWORD)0
|
||||
#if SQLITE_DEBUG
|
||||
, 0
|
||||
#endif
|
||||
),// SQLITE3_MUTEX_INITIALIZER,
|
||||
new sqlite3_mutex( SQLITE_W32_MUTEX_INITIALIZER, 0, 0, (DWORD)0
|
||||
#if SQLITE_DEBUG
|
||||
, 0
|
||||
#endif
|
||||
),// SQLITE3_MUTEX_INITIALIZER,
|
||||
new sqlite3_mutex( SQLITE_W32_MUTEX_INITIALIZER, 0, 0, (DWORD)0
|
||||
#if SQLITE_DEBUG
|
||||
, 0
|
||||
#endif
|
||||
),// SQLITE3_MUTEX_INITIALIZER,
|
||||
new sqlite3_mutex( SQLITE_W32_MUTEX_INITIALIZER, 0, 0, (DWORD)0
|
||||
#if SQLITE_DEBUG
|
||||
, 0
|
||||
#endif
|
||||
),// SQLITE3_MUTEX_INITIALIZER,
|
||||
};
|
||||
|
||||
private static int winMutex_isInit = 0;
|
||||
/* As winMutexInit() and winMutexEnd() are called as part
|
||||
** of the sqlite3_initialize and sqlite3_shutdown()
|
||||
** processing, the "interlocked" magic is probably not
|
||||
** strictly necessary.
|
||||
*/
|
||||
private static long winMutex_lock = 0;
|
||||
|
||||
private static System.Object lockThis = new System.Object();
|
||||
|
||||
private static int winMutexInit()
|
||||
{
|
||||
/* The first to increment to 1 does actual initialization */
|
||||
|
||||
lock (lockThis)
|
||||
//if ( Interlocked.CompareExchange(ref winMutex_lock, 1, 0 ) == 0 )
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ArraySize(winMutex_staticMutexes); i++)
|
||||
{
|
||||
if (winMutex_staticMutexes[i].mutex == null) winMutex_staticMutexes[i].mutex = new Mutex();
|
||||
//InitializeCriticalSection( winMutex_staticMutexes[i].mutex );
|
||||
}
|
||||
winMutex_isInit = 1;
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// /* Someone else is in the process of initing the static mutexes */
|
||||
// while ( 0 == winMutex_isInit )
|
||||
// {
|
||||
// Thread.Sleep( 1 );
|
||||
// }
|
||||
//}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
private static int winMutexEnd()
|
||||
{
|
||||
/* The first to decrement to 0 does actual shutdown
|
||||
** (which should be the last to shutdown.) */
|
||||
if (Interlocked.CompareExchange(ref winMutex_lock, 0, 1) == 1)
|
||||
{
|
||||
if (winMutex_isInit == 1)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ArraySize(winMutex_staticMutexes); i++)
|
||||
{
|
||||
DeleteCriticalSection(winMutex_staticMutexes[i].mutex);
|
||||
}
|
||||
winMutex_isInit = 0;
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** The sqlite3_mutex_alloc() routine allocates a new
|
||||
** mutex and returns a pointer to it. If it returns NULL
|
||||
** that means that a mutex could not be allocated. SQLite
|
||||
** will unwind its stack and return an error. The argument
|
||||
** to sqlite3_mutex_alloc() is one of these integer constants:
|
||||
**
|
||||
** <ul>
|
||||
** <li> SQLITE_MUTEX_FAST
|
||||
** <li> SQLITE_MUTEX_RECURSIVE
|
||||
** <li> SQLITE_MUTEX_STATIC_MASTER
|
||||
** <li> SQLITE_MUTEX_STATIC_MEM
|
||||
** <li> SQLITE_MUTEX_STATIC_MEM2
|
||||
** <li> SQLITE_MUTEX_STATIC_PRNG
|
||||
** <li> SQLITE_MUTEX_STATIC_LRU
|
||||
** <li> SQLITE_MUTEX_STATIC_LRU2
|
||||
** </ul>
|
||||
**
|
||||
** The first two constants cause sqlite3_mutex_alloc() to create
|
||||
** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
|
||||
** is used but not necessarily so when SQLITE_MUTEX_FAST is used.
|
||||
** The mutex implementation does not need to make a distinction
|
||||
** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does
|
||||
** not want to. But SQLite will only request a recursive mutex in
|
||||
** cases where it really needs one. If a faster non-recursive mutex
|
||||
** implementation is available on the host platform, the mutex subsystem
|
||||
** might return such a mutex in response to SQLITE_MUTEX_FAST.
|
||||
**
|
||||
** The other allowed parameters to sqlite3_mutex_alloc() each return
|
||||
** a pointer to a static preexisting mutex. Six static mutexes are
|
||||
** used by the current version of SQLite. Future versions of SQLite
|
||||
** may add additional static mutexes. Static mutexes are for internal
|
||||
** use by SQLite only. Applications that use SQLite mutexes should
|
||||
** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or
|
||||
** SQLITE_MUTEX_RECURSIVE.
|
||||
**
|
||||
** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST
|
||||
** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc()
|
||||
** returns a different mutex on every call. But for the static
|
||||
** mutex types, the same mutex is returned on every call that has
|
||||
** the same type number.
|
||||
*/
|
||||
|
||||
private static sqlite3_mutex winMutexAlloc(int iType)
|
||||
{
|
||||
sqlite3_mutex p;
|
||||
|
||||
switch (iType)
|
||||
{
|
||||
case SQLITE_MUTEX_FAST:
|
||||
case SQLITE_MUTEX_RECURSIVE:
|
||||
{
|
||||
p = new sqlite3_mutex();//sqlite3MallocZero( sizeof(*p) );
|
||||
if (p != null)
|
||||
{
|
||||
p.id = iType;
|
||||
InitializeCriticalSection(p.mutex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
Debug.Assert(winMutex_isInit == 1);
|
||||
Debug.Assert(iType - 2 >= 0);
|
||||
Debug.Assert(iType - 2 < ArraySize(winMutex_staticMutexes));
|
||||
p = winMutex_staticMutexes[iType - 2];
|
||||
p.id = iType;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine deallocates a previously
|
||||
** allocated mutex. SQLite is careful to deallocate every
|
||||
** mutex that it allocates.
|
||||
*/
|
||||
|
||||
private static void winMutexFree(sqlite3_mutex p)
|
||||
{
|
||||
Debug.Assert(p != null);
|
||||
Debug.Assert(p.nRef == 0);
|
||||
Debug.Assert(p.id == SQLITE_MUTEX_FAST || p.id == SQLITE_MUTEX_RECURSIVE);
|
||||
DeleteCriticalSection(p.mutex);
|
||||
p.owner = 0;
|
||||
//sqlite3_free( p );
|
||||
}
|
||||
|
||||
/*
|
||||
** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
|
||||
** to enter a mutex. If another thread is already within the mutex,
|
||||
** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return
|
||||
** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK
|
||||
** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can
|
||||
** be entered multiple times by the same thread. In such cases the,
|
||||
** mutex must be exited an equal number of times before another thread
|
||||
** can enter. If the same thread tries to enter any other kind of mutex
|
||||
** more than once, the behavior is undefined.
|
||||
*/
|
||||
|
||||
private static void winMutexEnter(sqlite3_mutex p)
|
||||
{
|
||||
DWORD tid = GetCurrentThreadId();
|
||||
Debug.Assert(p.id == SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid));
|
||||
EnterCriticalSection(p.mutex);
|
||||
p.owner = tid;
|
||||
p.nRef++;
|
||||
#if SQLITE_DEBUG
|
||||
if (p.trace != 0)
|
||||
{
|
||||
printf("enter mutex {0} ({1}) with nRef={2}\n", p.GetHashCode(), p.owner, p.nRef);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private static int winMutexTry(sqlite3_mutex p)
|
||||
{
|
||||
#if !NDEBUG
|
||||
DWORD tid = GetCurrentThreadId();
|
||||
#endif
|
||||
int rc = SQLITE_BUSY;
|
||||
Debug.Assert(p.id == SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid));
|
||||
/*
|
||||
** The sqlite3_mutex_try() routine is very rarely used, and when it
|
||||
** is used it is merely an optimization. So it is OK for it to always
|
||||
** fail.
|
||||
**
|
||||
** The TryEnterCriticalSection() interface is only available on WinNT.
|
||||
** And some windows compilers complain if you try to use it without
|
||||
** first doing some #defines that prevent SQLite from building on Win98.
|
||||
** For that reason, we will omit this optimization for now. See
|
||||
** ticket #2685.
|
||||
*/
|
||||
#if FALSE
|
||||
if( mutexIsNT() && TryEnterCriticalSection(p.mutex) ){
|
||||
p.owner = tid;
|
||||
p.nRef++;
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
#else
|
||||
UNUSED_PARAMETER(p);
|
||||
#endif
|
||||
#if SQLITE_DEBUG
|
||||
if (rc == SQLITE_OK && p.trace != 0)
|
||||
{
|
||||
printf("try mutex {0} ({1}) with nRef={2}\n", p.GetHashCode(), p.owner, p.nRef);
|
||||
}
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** The sqlite3_mutex_leave() routine exits a mutex that was
|
||||
** previously entered by the same thread. The behavior
|
||||
** is undefined if the mutex is not currently entered or
|
||||
** is not currently allocated. SQLite will never do either.
|
||||
*/
|
||||
|
||||
private static void winMutexLeave(sqlite3_mutex p)
|
||||
{
|
||||
#if !NDEBUG
|
||||
DWORD tid = GetCurrentThreadId();
|
||||
#endif
|
||||
Debug.Assert(p.nRef > 0);
|
||||
Debug.Assert(p.owner == tid);
|
||||
p.nRef--;
|
||||
Debug.Assert(p.nRef == 0 || p.id == SQLITE_MUTEX_RECURSIVE);
|
||||
if (p.nRef == 0) p.owner = 0;
|
||||
LeaveCriticalSection(p.mutex);
|
||||
#if SQLITE_DEBUG
|
||||
if (p.trace != 0)
|
||||
{
|
||||
printf("leave mutex {0} ({1}) with nRef={2}\n", p.GetHashCode(), p.owner, p.nRef);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private static sqlite3_mutex_methods sqlite3DefaultMutex()
|
||||
{
|
||||
sqlite3_mutex_methods sMutex = new sqlite3_mutex_methods(
|
||||
(dxMutexInit)winMutexInit,
|
||||
(dxMutexEnd)winMutexEnd,
|
||||
(dxMutexAlloc)winMutexAlloc,
|
||||
(dxMutexFree)winMutexFree,
|
||||
(dxMutexEnter)winMutexEnter,
|
||||
(dxMutexTry)winMutexTry,
|
||||
(dxMutexLeave)winMutexLeave,
|
||||
#if SQLITE_DEBUG
|
||||
(dxMutexHeld)winMutexHeld,
|
||||
(dxMutexNotheld)winMutexNotheld
|
||||
#else
|
||||
null,
|
||||
null
|
||||
#endif
|
||||
);
|
||||
|
||||
return sMutex;
|
||||
}
|
||||
|
||||
#endif // * SQLITE_MUTEX_W32 */
|
||||
}
|
||||
}
|
||||
344
original/Community.CsharpSqlite/src/notify_c.cs
Normal file
344
original/Community.CsharpSqlite/src/notify_c.cs
Normal file
|
|
@ -0,0 +1,344 @@
|
|||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2009 March 3
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This file contains the implementation of the sqlite3_unlock_notify()
|
||||
** API method and its associated functionality.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2009-12-07 16:39:13 1ed88e9d01e9eda5cbc622e7614277f29bcc551c
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#include "sqliteInt.h"
|
||||
//#include "btreeInt.h"
|
||||
|
||||
/* Omit this entire file if SQLITE_ENABLE_UNLOCK_NOTIFY is not defined. */
|
||||
#if SQLITE_ENABLE_UNLOCK_NOTIFY
|
||||
|
||||
/*
|
||||
** Public interfaces:
|
||||
**
|
||||
** sqlite3ConnectionBlocked()
|
||||
** sqlite3ConnectionUnlocked()
|
||||
** sqlite3ConnectionClosed()
|
||||
** sqlite3_unlock_notify()
|
||||
*/
|
||||
|
||||
//#define assertMutexHeld() \
|
||||
assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)) )
|
||||
|
||||
/*
|
||||
** Head of a linked list of all sqlite3 objects created by this process
|
||||
** for which either sqlite3.pBlockingConnection or sqlite3.pUnlockConnection
|
||||
** is not NULL. This variable may only accessed while the STATIC_MASTER
|
||||
** mutex is held.
|
||||
*/
|
||||
static sqlite3 *SQLITE_WSD sqlite3BlockedList = 0;
|
||||
|
||||
#if !NDEBUG
|
||||
/*
|
||||
** This function is a complex assert() that verifies the following
|
||||
** properties of the blocked connections list:
|
||||
**
|
||||
** 1) Each entry in the list has a non-NULL value for either
|
||||
** pUnlockConnection or pBlockingConnection, or both.
|
||||
**
|
||||
** 2) All entries in the list that share a common value for
|
||||
** xUnlockNotify are grouped together.
|
||||
**
|
||||
** 3) If the argument db is not NULL, then none of the entries in the
|
||||
** blocked connections list have pUnlockConnection or pBlockingConnection
|
||||
** set to db. This is used when closing connection db.
|
||||
*/
|
||||
static void checkListProperties(sqlite3 *db){
|
||||
sqlite3 *p;
|
||||
for(p=sqlite3BlockedList; p; p=p->pNextBlocked){
|
||||
int seen = 0;
|
||||
sqlite3 *p2;
|
||||
|
||||
/* Verify property (1) */
|
||||
assert( p->pUnlockConnection || p->pBlockingConnection );
|
||||
|
||||
/* Verify property (2) */
|
||||
for(p2=sqlite3BlockedList; p2!=p; p2=p2->pNextBlocked){
|
||||
if( p2->xUnlockNotify==p->xUnlockNotify ) seen = 1;
|
||||
assert( p2->xUnlockNotify==p->xUnlockNotify || !seen );
|
||||
assert( db==0 || p->pUnlockConnection!=db );
|
||||
assert( db==0 || p->pBlockingConnection!=db );
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
//# define checkListProperties(x)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Remove connection db from the blocked connections list. If connection
|
||||
** db is not currently a part of the list, this function is a no-op.
|
||||
*/
|
||||
static void removeFromBlockedList(sqlite3 *db){
|
||||
sqlite3 **pp;
|
||||
assertMutexHeld();
|
||||
for(pp=&sqlite3BlockedList; *pp; pp = &(*pp)->pNextBlocked){
|
||||
if( *pp==db ){
|
||||
*pp = (*pp)->pNextBlocked;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Add connection db to the blocked connections list. It is assumed
|
||||
** that it is not already a part of the list.
|
||||
*/
|
||||
static void addToBlockedList(sqlite3 *db){
|
||||
sqlite3 **pp;
|
||||
assertMutexHeld();
|
||||
for(
|
||||
pp=&sqlite3BlockedList;
|
||||
*pp && (*pp)->xUnlockNotify!=db->xUnlockNotify;
|
||||
pp=&(*pp)->pNextBlocked
|
||||
);
|
||||
db->pNextBlocked = *pp;
|
||||
*pp = db;
|
||||
}
|
||||
|
||||
/*
|
||||
** Obtain the STATIC_MASTER mutex.
|
||||
*/
|
||||
static void enterMutex(){
|
||||
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
|
||||
checkListProperties(0);
|
||||
}
|
||||
|
||||
/*
|
||||
** Release the STATIC_MASTER mutex.
|
||||
*/
|
||||
static void leaveMutex(){
|
||||
assertMutexHeld();
|
||||
checkListProperties(0);
|
||||
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
|
||||
}
|
||||
|
||||
/*
|
||||
** Register an unlock-notify callback.
|
||||
**
|
||||
** This is called after connection "db" has attempted some operation
|
||||
** but has received an SQLITE_LOCKED error because another connection
|
||||
** (call it pOther) in the same process was busy using the same shared
|
||||
** cache. pOther is found by looking at db->pBlockingConnection.
|
||||
**
|
||||
** If there is no blocking connection, the callback is invoked immediately,
|
||||
** before this routine returns.
|
||||
**
|
||||
** If pOther is already blocked on db, then report SQLITE_LOCKED, to indicate
|
||||
** a deadlock.
|
||||
**
|
||||
** Otherwise, make arrangements to invoke xNotify when pOther drops
|
||||
** its locks.
|
||||
**
|
||||
** Each call to this routine overrides any prior callbacks registered
|
||||
** on the same "db". If xNotify==0 then any prior callbacks are immediately
|
||||
** cancelled.
|
||||
*/
|
||||
int sqlite3_unlock_notify(
|
||||
sqlite3 *db,
|
||||
void (*xNotify)(void **, int),
|
||||
void *pArg
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
enterMutex();
|
||||
|
||||
if( xNotify==0 ){
|
||||
removeFromBlockedList(db);
|
||||
db->pUnlockConnection = 0;
|
||||
db->xUnlockNotify = 0;
|
||||
db->pUnlockArg = 0;
|
||||
}else if( 0==db->pBlockingConnection ){
|
||||
/* The blocking transaction has been concluded. Or there never was a
|
||||
** blocking transaction. In either case, invoke the notify callback
|
||||
** immediately.
|
||||
*/
|
||||
xNotify(&pArg, 1);
|
||||
}else{
|
||||
sqlite3 *p;
|
||||
|
||||
for(p=db->pBlockingConnection; p && p!=db; p=p->pUnlockConnection){}
|
||||
if( p ){
|
||||
rc = SQLITE_LOCKED; /* Deadlock detected. */
|
||||
}else{
|
||||
db->pUnlockConnection = db->pBlockingConnection;
|
||||
db->xUnlockNotify = xNotify;
|
||||
db->pUnlockArg = pArg;
|
||||
removeFromBlockedList(db);
|
||||
addToBlockedList(db);
|
||||
}
|
||||
}
|
||||
|
||||
leaveMutex();
|
||||
assert( !db->mallocFailed );
|
||||
sqlite3Error(db, rc, (rc?"database is deadlocked":0));
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is called while stepping or preparing a statement
|
||||
** associated with connection db. The operation will return SQLITE_LOCKED
|
||||
** to the user because it requires a lock that will not be available
|
||||
** until connection pBlocker concludes its current transaction.
|
||||
*/
|
||||
void sqlite3ConnectionBlocked(sqlite3 *db, sqlite3 *pBlocker){
|
||||
enterMutex();
|
||||
if( db->pBlockingConnection==0 && db->pUnlockConnection==0 ){
|
||||
addToBlockedList(db);
|
||||
}
|
||||
db->pBlockingConnection = pBlocker;
|
||||
leaveMutex();
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is called when
|
||||
** the transaction opened by database db has just finished. Locks held
|
||||
** by database connection db have been released.
|
||||
**
|
||||
** This function loops through each entry in the blocked connections
|
||||
** list and does the following:
|
||||
**
|
||||
** 1) If the sqlite3.pBlockingConnection member of a list entry is
|
||||
** set to db, then set pBlockingConnection=0.
|
||||
**
|
||||
** 2) If the sqlite3.pUnlockConnection member of a list entry is
|
||||
** set to db, then invoke the configured unlock-notify callback and
|
||||
** set pUnlockConnection=0.
|
||||
**
|
||||
** 3) If the two steps above mean that pBlockingConnection==0 and
|
||||
** pUnlockConnection==0, remove the entry from the blocked connections
|
||||
** list.
|
||||
*/
|
||||
void sqlite3ConnectionUnlocked(sqlite3 *db){
|
||||
void (*xUnlockNotify)(void **, int) = 0; /* Unlock-notify cb to invoke */
|
||||
int nArg = 0; /* Number of entries in aArg[] */
|
||||
sqlite3 **pp; /* Iterator variable */
|
||||
void **aArg; /* Arguments to the unlock callback */
|
||||
void **aDyn = 0; /* Dynamically allocated space for aArg[] */
|
||||
void *aStatic[16]; /* Starter space for aArg[]. No malloc required */
|
||||
|
||||
aArg = aStatic;
|
||||
enterMutex(); /* Enter STATIC_MASTER mutex */
|
||||
|
||||
/* This loop runs once for each entry in the blocked-connections list. */
|
||||
for(pp=&sqlite3BlockedList; *pp; /* no-op */ ){
|
||||
sqlite3 *p = *pp;
|
||||
|
||||
/* Step 1. */
|
||||
if( p->pBlockingConnection==db ){
|
||||
p->pBlockingConnection = 0;
|
||||
}
|
||||
|
||||
/* Step 2. */
|
||||
if( p->pUnlockConnection==db ){
|
||||
assert( p->xUnlockNotify );
|
||||
if( p->xUnlockNotify!=xUnlockNotify && nArg!=0 ){
|
||||
xUnlockNotify(aArg, nArg);
|
||||
nArg = 0;
|
||||
}
|
||||
|
||||
sqlite3BeginBenignMalloc();
|
||||
assert( aArg==aDyn || (aDyn==0 && aArg==aStatic) );
|
||||
assert( nArg<=(int)ArraySize(aStatic) || aArg==aDyn );
|
||||
if( (!aDyn && nArg==(int)ArraySize(aStatic))
|
||||
|| (aDyn && nArg==(int)(sqlite3DbMallocSize(db, aDyn)/sizeof(void*)))
|
||||
){
|
||||
/* The aArg[] array needs to grow. */
|
||||
void **pNew = (void **)sqlite3Malloc(nArg*sizeof(void *)*2);
|
||||
if( pNew ){
|
||||
memcpy(pNew, aArg, nArg*sizeof(void *));
|
||||
//sqlite3_free(aDyn);
|
||||
aDyn = aArg = pNew;
|
||||
}else{
|
||||
/* This occurs when the array of context pointers that need to
|
||||
** be passed to the unlock-notify callback is larger than the
|
||||
** aStatic[] array allocated on the stack and the attempt to
|
||||
** allocate a larger array from the heap has failed.
|
||||
**
|
||||
** This is a difficult situation to handle. Returning an error
|
||||
** code to the caller is insufficient, as even if an error code
|
||||
** is returned the transaction on connection db will still be
|
||||
** closed and the unlock-notify callbacks on blocked connections
|
||||
** will go unissued. This might cause the application to wait
|
||||
** indefinitely for an unlock-notify callback that will never
|
||||
** arrive.
|
||||
**
|
||||
** Instead, invoke the unlock-notify callback with the context
|
||||
** array already accumulated. We can then clear the array and
|
||||
** begin accumulating any further context pointers without
|
||||
** requiring any dynamic allocation. This is sub-optimal because
|
||||
** it means that instead of one callback with a large array of
|
||||
** context pointers the application will receive two or more
|
||||
** callbacks with smaller arrays of context pointers, which will
|
||||
** reduce the applications ability to prioritize multiple
|
||||
** connections. But it is the best that can be done under the
|
||||
** circumstances.
|
||||
*/
|
||||
xUnlockNotify(aArg, nArg);
|
||||
nArg = 0;
|
||||
}
|
||||
}
|
||||
sqlite3EndBenignMalloc();
|
||||
|
||||
aArg[nArg++] = p->pUnlockArg;
|
||||
xUnlockNotify = p->xUnlockNotify;
|
||||
p->pUnlockConnection = 0;
|
||||
p->xUnlockNotify = 0;
|
||||
p->pUnlockArg = 0;
|
||||
}
|
||||
|
||||
/* Step 3. */
|
||||
if( p->pBlockingConnection==0 && p->pUnlockConnection==0 ){
|
||||
/* Remove connection p from the blocked connections list. */
|
||||
*pp = p->pNextBlocked;
|
||||
p->pNextBlocked = 0;
|
||||
}else{
|
||||
pp = &p->pNextBlocked;
|
||||
}
|
||||
}
|
||||
|
||||
if( nArg!=0 ){
|
||||
xUnlockNotify(aArg, nArg);
|
||||
}
|
||||
//sqlite3_free(aDyn);
|
||||
leaveMutex(); /* Leave STATIC_MASTER mutex */
|
||||
}
|
||||
|
||||
/*
|
||||
** This is called when the database connection passed as an argument is
|
||||
** being closed. The connection is removed from the blocked list.
|
||||
*/
|
||||
void sqlite3ConnectionClosed(sqlite3 *db){
|
||||
sqlite3ConnectionUnlocked(db);
|
||||
enterMutex();
|
||||
removeFromBlockedList(db);
|
||||
checkListProperties(db);
|
||||
leaveMutex();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
173
original/Community.CsharpSqlite/src/opcodes_c.cs
Normal file
173
original/Community.CsharpSqlite/src/opcodes_c.cs
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2010-08-23 18:52:01 42537b60566f288167f1b5864a5435986838e3a3
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/* Automatically generated. Do not edit */
|
||||
/* See the mkopcodec.awk script for details. */
|
||||
#if !SQLITE_OMIT_EXPLAIN || !NDEBUG || VDBE_PROFILE || SQLITE_DEBUG
|
||||
|
||||
private static string sqlite3OpcodeName(int i)
|
||||
{
|
||||
string[] azName = { "?",
|
||||
/* 1 */ "Goto",
|
||||
/* 2 */ "Gosub",
|
||||
/* 3 */ "Return",
|
||||
/* 4 */ "Yield",
|
||||
/* 5 */ "HaltIfNull",
|
||||
/* 6 */ "Halt",
|
||||
/* 7 */ "Integer",
|
||||
/* 8 */ "Int64",
|
||||
/* 9 */ "String",
|
||||
/* 10 */ "Null",
|
||||
/* 11 */ "Blob",
|
||||
/* 12 */ "Variable",
|
||||
/* 13 */ "Move",
|
||||
/* 14 */ "Copy",
|
||||
/* 15 */ "SCopy",
|
||||
/* 16 */ "ResultRow",
|
||||
/* 17 */ "CollSeq",
|
||||
/* 18 */ "Function",
|
||||
/* 19 */ "Not",
|
||||
/* 20 */ "AddImm",
|
||||
/* 21 */ "MustBeInt",
|
||||
/* 22 */ "RealAffinity",
|
||||
/* 23 */ "Permutation",
|
||||
/* 24 */ "Compare",
|
||||
/* 25 */ "Jump",
|
||||
/* 26 */ "If",
|
||||
/* 27 */ "IfNot",
|
||||
/* 28 */ "Column",
|
||||
/* 29 */ "Affinity",
|
||||
/* 30 */ "MakeRecord",
|
||||
/* 31 */ "Count",
|
||||
/* 32 */ "Savepoint",
|
||||
/* 33 */ "AutoCommit",
|
||||
/* 34 */ "Transaction",
|
||||
/* 35 */ "ReadCookie",
|
||||
/* 36 */ "SetCookie",
|
||||
/* 37 */ "VerifyCookie",
|
||||
/* 38 */ "OpenRead",
|
||||
/* 39 */ "OpenWrite",
|
||||
/* 40 */ "OpenAutoindex",
|
||||
/* 41 */ "OpenEphemeral",
|
||||
/* 42 */ "OpenPseudo",
|
||||
/* 43 */ "Close",
|
||||
/* 44 */ "SeekLt",
|
||||
/* 45 */ "SeekLe",
|
||||
/* 46 */ "SeekGe",
|
||||
/* 47 */ "SeekGt",
|
||||
/* 48 */ "Seek",
|
||||
/* 49 */ "NotFound",
|
||||
/* 50 */ "Found",
|
||||
/* 51 */ "IsUnique",
|
||||
/* 52 */ "NotExists",
|
||||
/* 53 */ "Sequence",
|
||||
/* 54 */ "NewRowid",
|
||||
/* 55 */ "Insert",
|
||||
/* 56 */ "InsertInt",
|
||||
/* 57 */ "Delete",
|
||||
/* 58 */ "ResetCount",
|
||||
/* 59 */ "RowKey",
|
||||
/* 60 */ "RowData",
|
||||
/* 61 */ "Rowid",
|
||||
/* 62 */ "NullRow",
|
||||
/* 63 */ "Last",
|
||||
/* 64 */ "Sort",
|
||||
/* 65 */ "Rewind",
|
||||
/* 66 */ "Prev",
|
||||
/* 67 */ "Next",
|
||||
/* 68 */ "Or",
|
||||
/* 69 */ "And",
|
||||
/* 70 */ "IdxInsert",
|
||||
/* 71 */ "IdxDelete",
|
||||
/* 72 */ "IdxRowid",
|
||||
/* 73 */ "IsNull",
|
||||
/* 74 */ "NotNull",
|
||||
/* 75 */ "Ne",
|
||||
/* 76 */ "Eq",
|
||||
/* 77 */ "Gt",
|
||||
/* 78 */ "Le",
|
||||
/* 79 */ "Lt",
|
||||
/* 80 */ "Ge",
|
||||
/* 81 */ "IdxLT",
|
||||
/* 82 */ "BitAnd",
|
||||
/* 83 */ "BitOr",
|
||||
/* 84 */ "ShiftLeft",
|
||||
/* 85 */ "ShiftRight",
|
||||
/* 86 */ "Add",
|
||||
/* 87 */ "Subtract",
|
||||
/* 88 */ "Multiply",
|
||||
/* 89 */ "Divide",
|
||||
/* 90 */ "Remainder",
|
||||
/* 91 */ "Concat",
|
||||
/* 92 */ "IdxGE",
|
||||
/* 93 */ "BitNot",
|
||||
/* 94 */ "String8",
|
||||
/* 95 */ "Destroy",
|
||||
/* 96 */ "Clear",
|
||||
/* 97 */ "CreateIndex",
|
||||
/* 98 */ "CreateTable",
|
||||
/* 99 */ "ParseSchema",
|
||||
/* 100 */ "LoadAnalysis",
|
||||
/* 101 */ "DropTable",
|
||||
/* 102 */ "DropIndex",
|
||||
/* 103 */ "DropTrigger",
|
||||
/* 104 */ "IntegrityCk",
|
||||
/* 105 */ "RowSetAdd",
|
||||
/* 106 */ "RowSetRead",
|
||||
/* 107 */ "RowSetTest",
|
||||
/* 108 */ "Program",
|
||||
/* 109 */ "Param",
|
||||
/* 110 */ "FkCounter",
|
||||
/* 111 */ "FkIfZero",
|
||||
/* 112 */ "MemMax",
|
||||
/* 113 */ "IfPos",
|
||||
/* 114 */ "IfNeg",
|
||||
/* 115 */ "IfZero",
|
||||
/* 116 */ "AggStep",
|
||||
/* 117 */ "AggFinal",
|
||||
/* 118 */ "Checkpoint",
|
||||
/* 119 */ "JournalMode",
|
||||
/* 120 */ "Vacuum",
|
||||
/* 121 */ "IncrVacuum",
|
||||
/* 122 */ "Expire",
|
||||
/* 123 */ "TableLock",
|
||||
/* 124 */ "VBegin",
|
||||
/* 125 */ "VCreate",
|
||||
/* 126 */ "VDestroy",
|
||||
/* 127 */ "VOpen",
|
||||
/* 128 */ "VFilter",
|
||||
/* 129 */ "VColumn",
|
||||
/* 130 */ "Real",
|
||||
/* 131 */ "VNext",
|
||||
/* 132 */ "VRename",
|
||||
/* 133 */ "VUpdate",
|
||||
/* 134 */ "Pagecount",
|
||||
/* 135 */ "MaxPgcnt",
|
||||
/* 136 */ "Trace",
|
||||
/* 137 */ "Noop",
|
||||
/* 138 */ "Explain",
|
||||
/* 139 */ "NotUsed_139",
|
||||
/* 140 */ "NotUsed_140",
|
||||
/* 141 */ "ToText",
|
||||
/* 142 */ "ToBlob",
|
||||
/* 143 */ "ToNumeric",
|
||||
/* 144 */ "ToInt",
|
||||
/* 145 */ "ToReal",
|
||||
};
|
||||
return azName[i];
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
348
original/Community.CsharpSqlite/src/opcodes_h.cs
Normal file
348
original/Community.CsharpSqlite/src/opcodes_h.cs
Normal file
|
|
@ -0,0 +1,348 @@
|
|||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/* Automatically generated. Do not edit */
|
||||
/* See the mkopcodeh.awk script for details */
|
||||
/* Automatically generated. Do not edit */
|
||||
/* See the mkopcodeh.awk script for details */
|
||||
//#define OP_Goto 1
|
||||
//#define OP_Gosub 2
|
||||
//#define OP_Return 3
|
||||
//#define OP_Yield 4
|
||||
//#define OP_HaltIfNull 5
|
||||
//#define OP_Halt 6
|
||||
//#define OP_Integer 7
|
||||
//#define OP_Int64 8
|
||||
//#define OP_Real 130 /* same as TK_FLOAT */
|
||||
//#define OP_String8 94 /* same as TK_STRING */
|
||||
//#define OP_String 9
|
||||
//#define OP_Null 10
|
||||
//#define OP_Blob 11
|
||||
//#define OP_Variable 12
|
||||
//#define OP_Move 13
|
||||
//#define OP_Copy 14
|
||||
//#define OP_SCopy 15
|
||||
//#define OP_ResultRow 16
|
||||
//#define OP_Concat 91 /* same as TK_CONCAT */
|
||||
//#define OP_Add 86 /* same as TK_PLUS */
|
||||
//#define OP_Subtract 87 /* same as TK_MINUS */
|
||||
//#define OP_Multiply 88 /* same as TK_STAR */
|
||||
//#define OP_Divide 89 /* same as TK_SLASH */
|
||||
//#define OP_Remainder 90 /* same as TK_REM */
|
||||
//#define OP_CollSeq 17
|
||||
//#define OP_Function 18
|
||||
//#define OP_BitAnd 82 /* same as TK_BITAND */
|
||||
//#define OP_BitOr 83 /* same as TK_BITOR */
|
||||
//#define OP_ShiftLeft 84 /* same as TK_LSHIFT */
|
||||
//#define OP_ShiftRight 85 /* same as TK_RSHIFT */
|
||||
//#define OP_AddImm 20
|
||||
//#define OP_MustBeInt 21
|
||||
//#define OP_RealAffinity 22
|
||||
//#define OP_ToText 141 /* same as TK_TO_TEXT */
|
||||
//#define OP_ToBlob 142 /* same as TK_TO_BLOB */
|
||||
//#define OP_ToNumeric 143 /* same as TK_TO_NUMERIC*/
|
||||
//#define OP_ToInt 144 /* same as TK_TO_INT */
|
||||
//#define OP_ToReal 145 /* same as TK_TO_REAL */
|
||||
//#define OP_Eq 76 /* same as TK_EQ */
|
||||
//#define OP_Ne 75 /* same as TK_NE */
|
||||
//#define OP_Lt 79 /* same as TK_LT */
|
||||
//#define OP_Le 78 /* same as TK_LE */
|
||||
//#define OP_Gt 77 /* same as TK_GT */
|
||||
//#define OP_Ge 80 /* same as TK_GE */
|
||||
//#define OP_Permutation 23
|
||||
//#define OP_Compare 24
|
||||
//#define OP_Jump 25
|
||||
//#define OP_And 69 /* same as TK_AND */
|
||||
//#define OP_Or 68 /* same as TK_OR */
|
||||
//#define OP_Not 19 /* same as TK_NOT */
|
||||
//#define OP_BitNot 93 /* same as TK_BITNOT */
|
||||
//#define OP_If 26
|
||||
//#define OP_IfNot 27
|
||||
//#define OP_IsNull 73 /* same as TK_ISNULL */
|
||||
//#define OP_NotNull 74 /* same as TK_NOTNULL */
|
||||
//#define OP_Column 28
|
||||
//#define OP_Affinity 29
|
||||
//#define OP_MakeRecord 30
|
||||
//#define OP_Count 31
|
||||
//#define OP_Savepoint 32
|
||||
//#define OP_AutoCommit 33
|
||||
//#define OP_Transaction 34
|
||||
//#define OP_ReadCookie 35
|
||||
//#define OP_SetCookie 36
|
||||
//#define OP_VerifyCookie 37
|
||||
//#define OP_OpenRead 38
|
||||
//#define OP_OpenWrite 39
|
||||
//#define OP_OpenAutoindex 40
|
||||
//#define OP_OpenEphemeral 41
|
||||
//#define OP_OpenPseudo 42
|
||||
//#define OP_Close 43
|
||||
//#define OP_SeekLt 44
|
||||
//#define OP_SeekLe 45
|
||||
//#define OP_SeekGe 46
|
||||
//#define OP_SeekGt 47
|
||||
//#define OP_Seek 48
|
||||
//#define OP_NotFound 49
|
||||
//#define OP_Found 50
|
||||
//#define OP_IsUnique 51
|
||||
//#define OP_NotExists 52
|
||||
//#define OP_Sequence 53
|
||||
//#define OP_NewRowid 54
|
||||
//#define OP_Insert 55
|
||||
//#define OP_InsertInt 56
|
||||
//#define OP_Delete 57
|
||||
//#define OP_ResetCount 58
|
||||
//#define OP_RowKey 59
|
||||
//#define OP_RowData 60
|
||||
//#define OP_Rowid 61
|
||||
//#define OP_NullRow 62
|
||||
//#define OP_Last 63
|
||||
//#define OP_Sort 64
|
||||
//#define OP_Rewind 65
|
||||
//#define OP_Prev 66
|
||||
//#define OP_Next 67
|
||||
//#define OP_IdxInsert 70
|
||||
//#define OP_IdxDelete 71
|
||||
//#define OP_IdxRowid 72
|
||||
//#define OP_IdxLT 81
|
||||
//#define OP_IdxGE 92
|
||||
//#define OP_Destroy 95
|
||||
//#define OP_Clear 96
|
||||
//#define OP_CreateIndex 97
|
||||
//#define OP_CreateTable 98
|
||||
//#define OP_ParseSchema 99
|
||||
//#define OP_LoadAnalysis 100
|
||||
//#define OP_DropTable 101
|
||||
//#define OP_DropIndex 102
|
||||
//#define OP_DropTrigger 103
|
||||
//#define OP_IntegrityCk 104
|
||||
//#define OP_RowSetAdd 105
|
||||
//#define OP_RowSetRead 106
|
||||
//#define OP_RowSetTest 107
|
||||
//#define OP_Program 108
|
||||
//#define OP_Param 109
|
||||
//#define OP_FkCounter 110
|
||||
//#define OP_FkIfZero 111
|
||||
//#define OP_MemMax 112
|
||||
//#define OP_IfPos 113
|
||||
//#define OP_IfNeg 114
|
||||
//#define OP_IfZero 115
|
||||
//#define OP_AggStep 116
|
||||
//#define OP_AggFinal 117
|
||||
//#define OP_Checkpoint 118
|
||||
//#define OP_JournalMode 119
|
||||
//#define OP_Vacuum 120
|
||||
//#define OP_IncrVacuum 121
|
||||
//#define OP_Expire 122
|
||||
//#define OP_TableLock 123
|
||||
//#define OP_VBegin 124
|
||||
//#define OP_VCreate 125
|
||||
//#define OP_VDestroy 126
|
||||
//#define OP_VOpen 127
|
||||
//#define OP_VFilter 128
|
||||
//#define OP_VColumn 129
|
||||
//#define OP_VNext 131
|
||||
//#define OP_VRename 132
|
||||
//#define OP_VUpdate 133
|
||||
//#define OP_Pagecount 134
|
||||
//#define OP_MaxPgcnt 135
|
||||
//#define OP_Trace 136
|
||||
//#define OP_Noop 137
|
||||
//#define OP_Explain 138
|
||||
|
||||
public const int OP_Goto = 1;
|
||||
public const int OP_Gosub = 2;
|
||||
public const int OP_Return = 3;
|
||||
public const int OP_Yield = 4;
|
||||
public const int OP_HaltIfNull = 5;
|
||||
public const int OP_Halt = 6;
|
||||
public const int OP_Integer = 7;
|
||||
public const int OP_Int64 = 8;
|
||||
public const int OP_Real = 130 /* same as TK_FLOAT */;
|
||||
public const int OP_String8 = 94 /* same as TK_STRING */;
|
||||
public const int OP_String = 9;
|
||||
public const int OP_Null = 10;
|
||||
public const int OP_Blob = 11;
|
||||
public const int OP_Variable = 12;
|
||||
public const int OP_Move = 13;
|
||||
public const int OP_Copy = 14;
|
||||
public const int OP_SCopy = 15;
|
||||
public const int OP_ResultRow = 16;
|
||||
public const int OP_Concat = 91 /* same as TK_CONCAT */;
|
||||
public const int OP_Add = 86 /* same as TK_PLUS */;
|
||||
public const int OP_Subtract = 87 /* same as TK_MINUS */;
|
||||
public const int OP_Multiply = 88 /* same as TK_STAR */;
|
||||
public const int OP_Divide = 89 /* same as TK_SLASH */;
|
||||
public const int OP_Remainder = 90 /* same as TK_REM */;
|
||||
public const int OP_CollSeq = 17;
|
||||
public const int OP_Function = 18;
|
||||
public const int OP_BitAnd = 82 /* same as TK_BITAND */;
|
||||
public const int OP_BitOr = 83 /* same as TK_BITOR */;
|
||||
public const int OP_ShiftLeft = 84 /* same as TK_LSHIFT */;
|
||||
public const int OP_ShiftRight = 85 /* same as TK_RSHIFT */;
|
||||
public const int OP_AddImm = 20;
|
||||
public const int OP_MustBeInt = 21;
|
||||
public const int OP_RealAffinity = 22;
|
||||
public const int OP_ToText = 141 /* same as TK_TO_TEXT */;
|
||||
public const int OP_ToBlob = 142 /* same as TK_TO_BLOB */;
|
||||
public const int OP_ToNumeric = 143 /* same as TK_TO_NUMERIC*/;
|
||||
public const int OP_ToInt = 144 /* same as TK_TO_INT */;
|
||||
public const int OP_ToReal = 145 /* same as TK_TO_REAL */;
|
||||
public const int OP_Eq = 76 /* same as TK_EQ */;
|
||||
public const int OP_Ne = 75 /* same as TK_NE */;
|
||||
public const int OP_Lt = 79 /* same as TK_LT */;
|
||||
public const int OP_Le = 78 /* same as TK_LE */;
|
||||
public const int OP_Gt = 77 /* same as TK_GT */;
|
||||
public const int OP_Ge = 80 /* same as TK_GE */;
|
||||
public const int OP_Permutation = 23;
|
||||
public const int OP_Compare = 24;
|
||||
public const int OP_Jump = 25;
|
||||
public const int OP_And = 69 /* same as TK_AND */;
|
||||
public const int OP_Or = 68 /* same as TK_OR */;
|
||||
public const int OP_Not = 19 /* same as TK_NOT */;
|
||||
public const int OP_BitNot = 93 /* same as TK_BITNOT */;
|
||||
public const int OP_If = 26;
|
||||
public const int OP_IfNot = 27;
|
||||
public const int OP_IsNull = 73 /* same as TK_ISNULL */;
|
||||
public const int OP_NotNull = 74 /* same as TK_NOTNULL */;
|
||||
public const int OP_Column = 28;
|
||||
public const int OP_Affinity = 29;
|
||||
public const int OP_MakeRecord = 30;
|
||||
public const int OP_Count = 31;
|
||||
public const int OP_Savepoint = 32;
|
||||
public const int OP_AutoCommit = 33;
|
||||
public const int OP_Transaction = 34;
|
||||
public const int OP_ReadCookie = 35;
|
||||
public const int OP_SetCookie = 36;
|
||||
public const int OP_VerifyCookie = 37;
|
||||
public const int OP_OpenRead = 38;
|
||||
public const int OP_OpenWrite = 39;
|
||||
public const int OP_OpenAutoindex = 40;
|
||||
public const int OP_OpenEphemeral = 41;
|
||||
public const int OP_OpenPseudo = 42;
|
||||
public const int OP_Close = 43;
|
||||
public const int OP_SeekLt = 44;
|
||||
public const int OP_SeekLe = 45;
|
||||
public const int OP_SeekGe = 46;
|
||||
public const int OP_SeekGt = 47;
|
||||
public const int OP_Seek = 48;
|
||||
public const int OP_NotFound = 49;
|
||||
public const int OP_Found = 50;
|
||||
public const int OP_IsUnique = 51;
|
||||
public const int OP_NotExists = 52;
|
||||
public const int OP_Sequence = 53;
|
||||
public const int OP_NewRowid = 54;
|
||||
public const int OP_Insert = 55;
|
||||
public const int OP_InsertInt = 56;
|
||||
public const int OP_Delete = 57;
|
||||
public const int OP_ResetCount = 58;
|
||||
public const int OP_RowKey = 59;
|
||||
public const int OP_RowData = 60;
|
||||
public const int OP_Rowid = 61;
|
||||
public const int OP_NullRow = 62;
|
||||
public const int OP_Last = 63;
|
||||
public const int OP_Sort = 64;
|
||||
public const int OP_Rewind = 65;
|
||||
public const int OP_Prev = 66;
|
||||
public const int OP_Next = 67;
|
||||
public const int OP_IdxInsert = 70;
|
||||
public const int OP_IdxDelete = 71;
|
||||
public const int OP_IdxRowid = 72;
|
||||
public const int OP_IdxLT = 81;
|
||||
public const int OP_IdxGE = 92;
|
||||
public const int OP_Destroy = 95;
|
||||
public const int OP_Clear = 96;
|
||||
public const int OP_CreateIndex = 97;
|
||||
public const int OP_CreateTable = 98;
|
||||
public const int OP_ParseSchema = 99;
|
||||
public const int OP_LoadAnalysis = 100;
|
||||
public const int OP_DropTable = 101;
|
||||
public const int OP_DropIndex = 102;
|
||||
public const int OP_DropTrigger = 103;
|
||||
public const int OP_IntegrityCk = 104;
|
||||
public const int OP_RowSetAdd = 105;
|
||||
public const int OP_RowSetRead = 106;
|
||||
public const int OP_RowSetTest = 107;
|
||||
public const int OP_Program = 108;
|
||||
public const int OP_Param = 109;
|
||||
public const int OP_FkCounter = 110;
|
||||
public const int OP_FkIfZero = 111;
|
||||
public const int OP_MemMax = 112;
|
||||
public const int OP_IfPos = 113;
|
||||
public const int OP_IfNeg = 114;
|
||||
public const int OP_IfZero = 115;
|
||||
public const int OP_AggStep = 116;
|
||||
public const int OP_AggFinal = 117;
|
||||
public const int OP_Checkpoint = 118;
|
||||
public const int OP_JournalMode = 119;
|
||||
public const int OP_Vacuum = 120;
|
||||
public const int OP_IncrVacuum = 121;
|
||||
public const int OP_Expire = 122;
|
||||
public const int OP_TableLock = 123;
|
||||
public const int OP_VBegin = 124;
|
||||
public const int OP_VCreate = 125;
|
||||
public const int OP_VDestroy = 126;
|
||||
public const int OP_VOpen = 127;
|
||||
public const int OP_VFilter = 128;
|
||||
public const int OP_VColumn = 129;
|
||||
public const int OP_VNext = 131;
|
||||
public const int OP_VRename = 132;
|
||||
public const int OP_VUpdate = 133;
|
||||
public const int OP_Pagecount = 134;
|
||||
public const int OP_MaxPgcnt = 135;
|
||||
public const int OP_Trace = 136;
|
||||
public const int OP_Noop = 137;
|
||||
public const int OP_Explain = 138;
|
||||
|
||||
/* The following opcode values are never used */
|
||||
//#define OP_NotUsed_139 139
|
||||
//#define OP_NotUsed_140 140
|
||||
|
||||
/* The following opcode values are never used */
|
||||
public const int OP_NotUsed_138 = 138;
|
||||
public const int OP_NotUsed_139 = 139;
|
||||
public const int OP_NotUsed_140 = 140;
|
||||
|
||||
/* Properties such as "out2" or "jump" that are specified in
|
||||
** comments following the "case" for each opcode in the vdbe.c
|
||||
** are encoded into bitvectors as follows:
|
||||
*/
|
||||
//#define OPFLG_JUMP 0x0001 /* jump: P2 holds jmp target */
|
||||
//#define OPFLG_OUT2_PRERELEASE 0x0002 /* out2-prerelease: */
|
||||
//#define OPFLG_IN1 0x0004 /* in1: P1 is an input */
|
||||
//#define OPFLG_IN2 0x0008 /* in2: P2 is an input */
|
||||
//#define OPFLG_IN3 0x0010 /* in3: P3 is an input */
|
||||
//#define OPFLG_OUT2 0x0020 /* out2: P2 is an output */
|
||||
//#define OPFLG_OUT3 0x0040 /* out3: P3 is an output */
|
||||
|
||||
public const int OPFLG_JUMP = 0x0001; /* jump: P2 holds jmp target */
|
||||
public const int OPFLG_OUT2_PRERELEASE = 0x0002; /* out2-prerelease: */
|
||||
public const int OPFLG_IN1 = 0x0004; /* in1: P1 is an input */
|
||||
public const int OPFLG_IN2 = 0x0008; /* in2: P2 is an input */
|
||||
public const int OPFLG_IN3 = 0x0010; /* in3: P3 is an input */
|
||||
public const int OPFLG_OUT2 = 0x0020; /* out2: P2 is an output */
|
||||
public const int OPFLG_OUT3 = 0x0040; /* out3: P3 is an output */
|
||||
|
||||
public static int[] OPFLG_INITIALIZER = new int[]{
|
||||
/* 0 */ 0x00, 0x01, 0x05, 0x04, 0x04, 0x10, 0x00, 0x02,
|
||||
/* 8 */ 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x24, 0x24,
|
||||
/* 16 */ 0x00, 0x00, 0x00, 0x24, 0x04, 0x05, 0x04, 0x00,
|
||||
/* 24 */ 0x00, 0x01, 0x05, 0x05, 0x00, 0x00, 0x00, 0x02,
|
||||
/* 32 */ 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00,
|
||||
/* 40 */ 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,
|
||||
/* 48 */ 0x08, 0x11, 0x11, 0x11, 0x11, 0x02, 0x02, 0x00,
|
||||
/* 56 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01,
|
||||
/* 64 */ 0x01, 0x01, 0x01, 0x01, 0x4c, 0x4c, 0x08, 0x00,
|
||||
/* 72 */ 0x02, 0x05, 0x05, 0x15, 0x15, 0x15, 0x15, 0x15,
|
||||
/* 80 */ 0x15, 0x01, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c,
|
||||
/* 88 */ 0x4c, 0x4c, 0x4c, 0x4c, 0x01, 0x24, 0x02, 0x02,
|
||||
/* 96 */ 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
/* 104 */ 0x00, 0x0c, 0x45, 0x15, 0x01, 0x02, 0x00, 0x01,
|
||||
/* 112 */ 0x08, 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x02,
|
||||
/* 120 */ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
/* 128 */ 0x01, 0x00, 0x02, 0x01, 0x00, 0x00, 0x02, 0x02,
|
||||
/* 136 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04,
|
||||
/* 144 */ 0x04, 0x04
|
||||
};
|
||||
}
|
||||
}
|
||||
451
original/Community.CsharpSqlite/src/os_c.cs
Normal file
451
original/Community.CsharpSqlite/src/os_c.cs
Normal file
|
|
@ -0,0 +1,451 @@
|
|||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using HANDLE = System.IntPtr;
|
||||
using i64 = System.Int64;
|
||||
|
||||
using sqlite3_int64 = System.Int64;
|
||||
|
||||
using u32 = System.UInt32;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2005 November 29
|
||||
**
|
||||
** 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 OS interface code that is common to all
|
||||
** architectures.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2010-12-07 20:14:09 a586a4deeb25330037a49df295b36aaf624d0f45
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#define _SQLITE_OS_C_ 1
|
||||
//#include "sqliteInt.h"
|
||||
//#undef _SQLITE_OS_C_
|
||||
|
||||
/*
|
||||
** The default SQLite sqlite3_vfs implementations do not allocate
|
||||
** memory (actually, os_unix.c allocates a small amount of memory
|
||||
** from within OsOpen()), but some third-party implementations may.
|
||||
** So we test the effects of a malloc() failing and the sqlite3OsXXX()
|
||||
** function returning SQLITE_IOERR_NOMEM using the DO_OS_MALLOC_TEST macro.
|
||||
**
|
||||
** The following functions are instrumented for malloc() failure
|
||||
** testing:
|
||||
**
|
||||
** sqlite3OsOpen()
|
||||
** sqlite3OsRead()
|
||||
** sqlite3OsWrite()
|
||||
** sqlite3OsSync()
|
||||
** sqlite3OsLock()
|
||||
**
|
||||
*/
|
||||
#if (SQLITE_TEST)
|
||||
static int sqlite3_memdebug_vfs_oom_test = 1;
|
||||
|
||||
//#define DO_OS_MALLOC_TEST(x) \
|
||||
//if (sqlite3_memdebug_vfs_oom_test && (!x || !sqlite3IsMemJournal(x))) { \
|
||||
// void *pTstAlloc = sqlite3Malloc(10); \
|
||||
// if (!pTstAlloc) return SQLITE_IOERR_NOMEM; \
|
||||
// sqlite3_free(pTstAlloc); \
|
||||
//}
|
||||
static void DO_OS_MALLOC_TEST( sqlite3_file x )
|
||||
{
|
||||
}
|
||||
#else
|
||||
|
||||
//#define DO_OS_MALLOC_TEST(x)
|
||||
private static void DO_OS_MALLOC_TEST(sqlite3_file x)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The following routines are convenience wrappers around methods
|
||||
** of the sqlite3_file object. This is mostly just syntactic sugar. All
|
||||
** of this would be completely automatic if SQLite were coded using
|
||||
** C++ instead of plain old C.
|
||||
*/
|
||||
|
||||
private static int sqlite3OsClose(sqlite3_file pId)
|
||||
{
|
||||
int rc = SQLITE_OK;
|
||||
if (pId.pMethods != null)
|
||||
{
|
||||
rc = pId.pMethods.xClose(pId);
|
||||
pId.pMethods = null;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
private static int sqlite3OsRead(sqlite3_file id, byte[] pBuf, int amt, i64 offset)
|
||||
{
|
||||
DO_OS_MALLOC_TEST(id);
|
||||
if (pBuf == null)
|
||||
pBuf = sqlite3Malloc(amt);
|
||||
return id.pMethods.xRead(id, pBuf, amt, offset);
|
||||
}
|
||||
|
||||
private static int sqlite3OsWrite(sqlite3_file id, byte[] pBuf, int amt, i64 offset)
|
||||
{
|
||||
DO_OS_MALLOC_TEST(id);
|
||||
return id.pMethods.xWrite(id, pBuf, amt, offset);
|
||||
}
|
||||
|
||||
private static int sqlite3OsTruncate(sqlite3_file id, i64 size)
|
||||
{
|
||||
return id.pMethods.xTruncate(id, size);
|
||||
}
|
||||
|
||||
private static int sqlite3OsSync(sqlite3_file id, int flags)
|
||||
{
|
||||
DO_OS_MALLOC_TEST(id);
|
||||
return id.pMethods.xSync(id, flags);
|
||||
}
|
||||
|
||||
private static int sqlite3OsFileSize(sqlite3_file id, ref long pSize)
|
||||
{
|
||||
return id.pMethods.xFileSize(id, ref pSize);
|
||||
}
|
||||
|
||||
private static int sqlite3OsLock(sqlite3_file id, int lockType)
|
||||
{
|
||||
DO_OS_MALLOC_TEST(id);
|
||||
return id.pMethods.xLock(id, lockType);
|
||||
}
|
||||
|
||||
private static int sqlite3OsUnlock(sqlite3_file id, int lockType)
|
||||
{
|
||||
return id.pMethods.xUnlock(id, lockType);
|
||||
}
|
||||
|
||||
private static int sqlite3OsCheckReservedLock(sqlite3_file id, ref int pResOut)
|
||||
{
|
||||
DO_OS_MALLOC_TEST(id);
|
||||
return id.pMethods.xCheckReservedLock(id, ref pResOut);
|
||||
}
|
||||
|
||||
private static int sqlite3OsFileControl(sqlite3_file id, u32 op, ref sqlite3_int64 pArg)
|
||||
{
|
||||
return id.pMethods.xFileControl(id, (int)op, ref pArg);
|
||||
}
|
||||
|
||||
private static int sqlite3OsSectorSize(sqlite3_file id)
|
||||
{
|
||||
dxSectorSize xSectorSize = id.pMethods.xSectorSize;
|
||||
return (xSectorSize != null ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE);
|
||||
}
|
||||
|
||||
private static int sqlite3OsDeviceCharacteristics(sqlite3_file id)
|
||||
{
|
||||
return id.pMethods.xDeviceCharacteristics(id);
|
||||
}
|
||||
|
||||
private static int sqlite3OsShmLock(sqlite3_file id, int offset, int n, int flags)
|
||||
{
|
||||
return id.pMethods.xShmLock(id, offset, n, flags);
|
||||
}
|
||||
|
||||
private static void sqlite3OsShmBarrier(sqlite3_file id)
|
||||
{
|
||||
id.pMethods.xShmBarrier(id);
|
||||
}
|
||||
|
||||
private static int sqlite3OsShmUnmap(sqlite3_file id, int deleteFlag)
|
||||
{
|
||||
return id.pMethods.xShmUnmap(id, deleteFlag);
|
||||
}
|
||||
|
||||
private static int sqlite3OsShmMap(
|
||||
sqlite3_file id, /* Database file handle */
|
||||
int iPage,
|
||||
int pgsz,
|
||||
int bExtend, /* True to extend file if necessary */
|
||||
out object pp /* OUT: Pointer to mapping */
|
||||
)
|
||||
{
|
||||
return id.pMethods.xShmMap(id, iPage, pgsz, bExtend, out pp);
|
||||
}
|
||||
|
||||
/*
|
||||
** The next group of routines are convenience wrappers around the
|
||||
** VFS methods.
|
||||
*/
|
||||
|
||||
private static int sqlite3OsOpen(
|
||||
sqlite3_vfs pVfs,
|
||||
string zPath,
|
||||
sqlite3_file pFile,
|
||||
int flags,
|
||||
ref int pFlagsOut
|
||||
)
|
||||
{
|
||||
int rc;
|
||||
DO_OS_MALLOC_TEST(null);
|
||||
/* 0x87f3f is a mask of SQLITE_OPEN_ flags that are valid to be passed
|
||||
** down into the VFS layer. Some SQLITE_OPEN_ flags (for example,
|
||||
** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before
|
||||
** reaching the VFS. */
|
||||
rc = pVfs.xOpen(pVfs, zPath, pFile, flags & 0x87f3f, out pFlagsOut);
|
||||
Debug.Assert(rc == SQLITE_OK || pFile.pMethods == null);
|
||||
return rc;
|
||||
}
|
||||
|
||||
private static int sqlite3OsDelete(sqlite3_vfs pVfs, string zPath, int dirSync)
|
||||
{
|
||||
return pVfs.xDelete(pVfs, zPath, dirSync);
|
||||
}
|
||||
|
||||
private static int sqlite3OsAccess(sqlite3_vfs pVfs, string zPath, int flags, ref int pResOut)
|
||||
{
|
||||
DO_OS_MALLOC_TEST(null);
|
||||
return pVfs.xAccess(pVfs, zPath, flags, out pResOut);
|
||||
}
|
||||
|
||||
private static int sqlite3OsFullPathname(
|
||||
sqlite3_vfs pVfs,
|
||||
string zPath,
|
||||
int nPathOut,
|
||||
StringBuilder zPathOut
|
||||
)
|
||||
{
|
||||
zPathOut.Length = 0;//zPathOut[0] = 0;
|
||||
return pVfs.xFullPathname(pVfs, zPath, nPathOut, zPathOut);
|
||||
}
|
||||
|
||||
#if !SQLITE_OMIT_LOAD_EXTENSION
|
||||
|
||||
private static HANDLE sqlite3OsDlOpen(sqlite3_vfs pVfs, string zPath)
|
||||
{
|
||||
return pVfs.xDlOpen(pVfs, zPath);
|
||||
}
|
||||
|
||||
private static void sqlite3OsDlError(sqlite3_vfs pVfs, int nByte, string zBufOut)
|
||||
{
|
||||
pVfs.xDlError(pVfs, nByte, zBufOut);
|
||||
}
|
||||
|
||||
private static object sqlite3OsDlSym(sqlite3_vfs pVfs, HANDLE pHdle, ref string zSym)
|
||||
{
|
||||
return pVfs.xDlSym(pVfs, pHdle, zSym);
|
||||
}
|
||||
|
||||
private static void sqlite3OsDlClose(sqlite3_vfs pVfs, HANDLE pHandle)
|
||||
{
|
||||
pVfs.xDlClose(pVfs, pHandle);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
private static int sqlite3OsRandomness(sqlite3_vfs pVfs, int nByte, byte[] zBufOut)
|
||||
{
|
||||
return pVfs.xRandomness(pVfs, nByte, zBufOut);
|
||||
}
|
||||
|
||||
private static int sqlite3OsSleep(sqlite3_vfs pVfs, int nMicro)
|
||||
{
|
||||
return pVfs.xSleep(pVfs, nMicro);
|
||||
}
|
||||
|
||||
private static int sqlite3OsCurrentTimeInt64(sqlite3_vfs pVfs, ref sqlite3_int64 pTimeOut)
|
||||
{
|
||||
int rc;
|
||||
/* IMPLEMENTATION-OF: R-49045-42493 SQLite will use the xCurrentTimeInt64()
|
||||
** method to get the current date and time if that method is available
|
||||
** (if iVersion is 2 or greater and the function pointer is not NULL) and
|
||||
** will fall back to xCurrentTime() if xCurrentTimeInt64() is
|
||||
** unavailable.
|
||||
*/
|
||||
if (pVfs.iVersion >= 2 && pVfs.xCurrentTimeInt64 != null)
|
||||
{
|
||||
rc = pVfs.xCurrentTimeInt64(pVfs, ref pTimeOut);
|
||||
}
|
||||
else
|
||||
{
|
||||
double r = 0;
|
||||
rc = pVfs.xCurrentTime(pVfs, ref r);
|
||||
pTimeOut = (sqlite3_int64)(r * 86400000.0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
private static int sqlite3OsOpenMalloc(
|
||||
ref sqlite3_vfs pVfs,
|
||||
string zFile,
|
||||
ref sqlite3_file ppFile,
|
||||
int flags,
|
||||
ref int pOutFlags
|
||||
)
|
||||
{
|
||||
int rc = SQLITE_NOMEM;
|
||||
sqlite3_file pFile;
|
||||
pFile = new sqlite3_file(); //sqlite3Malloc(ref pVfs.szOsFile);
|
||||
if (pFile != null)
|
||||
{
|
||||
rc = sqlite3OsOpen(pVfs, zFile, pFile, flags, ref pOutFlags);
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
pFile = null; // was sqlite3DbFree(db,ref pFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
ppFile = pFile;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
private static int sqlite3OsCloseFree(sqlite3_file pFile)
|
||||
{
|
||||
int rc = SQLITE_OK;
|
||||
Debug.Assert(pFile != null);
|
||||
rc = sqlite3OsClose(pFile);
|
||||
//sqlite3_free( ref pFile );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is a wrapper around the OS specific implementation of
|
||||
** sqlite3_os_init(). The purpose of the wrapper is to provide the
|
||||
** ability to simulate a malloc failure, so that the handling of an
|
||||
** error in sqlite3_os_init() by the upper layers can be tested.
|
||||
*/
|
||||
|
||||
private static int sqlite3OsInit()
|
||||
{
|
||||
//void *p = sqlite3_malloc(10);
|
||||
//if( p==null ) return SQLITE_NOMEM;
|
||||
//sqlite3_free(ref p);
|
||||
return sqlite3_os_init();
|
||||
}
|
||||
|
||||
/*
|
||||
** The list of all registered VFS implementations.
|
||||
*/
|
||||
private static sqlite3_vfs vfsList;
|
||||
//#define vfsList GLOBAL(sqlite3_vfs *, vfsList)
|
||||
|
||||
/*
|
||||
** Locate a VFS by name. If no name is given, simply return the
|
||||
** first VFS on the list.
|
||||
*/
|
||||
private static bool isInit = false;
|
||||
|
||||
static public sqlite3_vfs sqlite3_vfs_find(string zVfs)
|
||||
{
|
||||
sqlite3_vfs pVfs = null;
|
||||
#if SQLITE_THREADSAFE
|
||||
sqlite3_mutex mutex;
|
||||
#endif
|
||||
#if !SQLITE_OMIT_AUTOINIT
|
||||
int rc = sqlite3_initialize();
|
||||
if (rc != 0)
|
||||
return null;
|
||||
#endif
|
||||
#if SQLITE_THREADSAFE
|
||||
mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
|
||||
#endif
|
||||
sqlite3_mutex_enter(mutex);
|
||||
for (pVfs = vfsList; pVfs != null; pVfs = pVfs.pNext)
|
||||
{
|
||||
if (zVfs == null || zVfs == "")
|
||||
break;
|
||||
if (zVfs == pVfs.zName)
|
||||
break; //strcmp(zVfs, pVfs.zName) == null) break;
|
||||
}
|
||||
sqlite3_mutex_leave(mutex);
|
||||
return pVfs;
|
||||
}
|
||||
|
||||
/*
|
||||
** Unlink a VFS from the linked list
|
||||
*/
|
||||
|
||||
private static void vfsUnlink(sqlite3_vfs pVfs)
|
||||
{
|
||||
Debug.Assert(sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)));
|
||||
if (pVfs == null)
|
||||
{
|
||||
/* No-op */
|
||||
}
|
||||
else if (vfsList == pVfs)
|
||||
{
|
||||
vfsList = pVfs.pNext;
|
||||
}
|
||||
else if (vfsList != null)
|
||||
{
|
||||
sqlite3_vfs p = vfsList;
|
||||
while (p.pNext != null && p.pNext != pVfs)
|
||||
{
|
||||
p = p.pNext;
|
||||
}
|
||||
if (p.pNext == pVfs)
|
||||
{
|
||||
p.pNext = pVfs.pNext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Register a VFS with the system. It is harmless to register the same
|
||||
** VFS multiple times. The new VFS becomes the default if makeDflt is
|
||||
** true.
|
||||
*/
|
||||
|
||||
static public int sqlite3_vfs_register(sqlite3_vfs pVfs, int makeDflt)
|
||||
{
|
||||
sqlite3_mutex mutex;
|
||||
#if !SQLITE_OMIT_AUTOINIT
|
||||
int rc = sqlite3_initialize();
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
#endif
|
||||
mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
|
||||
sqlite3_mutex_enter(mutex);
|
||||
vfsUnlink(pVfs);
|
||||
if (makeDflt != 0 || vfsList == null)
|
||||
{
|
||||
pVfs.pNext = vfsList;
|
||||
vfsList = pVfs;
|
||||
}
|
||||
else
|
||||
{
|
||||
pVfs.pNext = vfsList.pNext;
|
||||
vfsList.pNext = pVfs;
|
||||
}
|
||||
Debug.Assert(vfsList != null);
|
||||
sqlite3_mutex_leave(mutex);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Unregister a VFS so that it is no longer accessible.
|
||||
*/
|
||||
|
||||
private static int sqlite3_vfs_unregister(sqlite3_vfs pVfs)
|
||||
{
|
||||
#if SQLITE_THREADSAFE
|
||||
sqlite3_mutex mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
|
||||
#endif
|
||||
sqlite3_mutex_enter(mutex);
|
||||
vfsUnlink(pVfs);
|
||||
sqlite3_mutex_leave(mutex);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
233
original/Community.CsharpSqlite/src/os_common_h.cs
Normal file
233
original/Community.CsharpSqlite/src/os_common_h.cs
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
using va_list = System.Object;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 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.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2010-08-23 18:52:01 42537b60566f288167f1b5864a5435986838e3a3
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#if !_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.
|
||||
*/
|
||||
#if MEMORY_DEBUG
|
||||
//# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead."
|
||||
#endif
|
||||
|
||||
#if SQLITE_DEBUG || TRACE
|
||||
private static bool sqlite3OsTrace = false;
|
||||
|
||||
//#define OSTRACE(X) if( sqlite3OSTrace ) sqlite3DebugPrintf X
|
||||
private static void OSTRACE(string X, params va_list[] ap)
|
||||
{
|
||||
if (sqlite3OsTrace)
|
||||
sqlite3DebugPrintf(X, ap);
|
||||
}
|
||||
|
||||
#else
|
||||
//#define OSTRACE(X)
|
||||
static void OSTRACE( string X, params object[] ap) { }
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Macros for performance tracing. Normally turned off. Only works
|
||||
** on i486 hardware.
|
||||
*/
|
||||
#if SQLITE_PERFORMANCE_TRACE
|
||||
|
||||
/*
|
||||
** hwtime.h contains inline assembler code for implementing
|
||||
** high-performance timing routines.
|
||||
*/
|
||||
//#include "hwtime.h"
|
||||
|
||||
static sqlite_u3264 g_start;
|
||||
static sqlite_u3264 g_elapsed;
|
||||
//#define TIMER_START g_start=sqlite3Hwtime()
|
||||
//#define TIMER_END g_elapsed=sqlite3Hwtime()-g_start
|
||||
//#define TIMER_ELAPSED g_elapsed
|
||||
#else
|
||||
private const int TIMER_START = 0; //#define TIMER_START
|
||||
private const int TIMER_END = 0; //#define TIMER_END
|
||||
private const int TIMER_ELAPSED = 0; //#define TIMER_ELAPSED ((sqlite_u3264)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 SQLITE_TEST
|
||||
|
||||
#if !TCLSH
|
||||
static int sqlite3_io_error_hit = 0; /* Total number of I/O Errors */
|
||||
static int sqlite3_io_error_hardhit = 0; /* Number of non-benign errors */
|
||||
static int sqlite3_io_error_pending = 0; /* Count down to first I/O error */
|
||||
static int sqlite3_io_error_persist = 0; /* True if I/O errors persist */
|
||||
static int sqlite3_io_error_benign = 0; /* True if errors are benign */
|
||||
static int sqlite3_diskfull_pending = 0;
|
||||
static int sqlite3_diskfull = 0;
|
||||
#else
|
||||
static tcl.lang.Var.SQLITE3_GETSET sqlite3_io_error_hit = new tcl.lang.Var.SQLITE3_GETSET( "sqlite_io_error_hit" );
|
||||
static tcl.lang.Var.SQLITE3_GETSET sqlite3_io_error_hardhit = new tcl.lang.Var.SQLITE3_GETSET( "sqlite_io_error_hardhit" );
|
||||
static tcl.lang.Var.SQLITE3_GETSET sqlite3_io_error_pending = new tcl.lang.Var.SQLITE3_GETSET( "sqlite_io_error_pending" );
|
||||
static tcl.lang.Var.SQLITE3_GETSET sqlite3_io_error_persist = new tcl.lang.Var.SQLITE3_GETSET( "sqlite_io_error_persist" );
|
||||
static tcl.lang.Var.SQLITE3_GETSET sqlite3_io_error_benign = new tcl.lang.Var.SQLITE3_GETSET( "sqlite_io_error_benign" );
|
||||
static tcl.lang.Var.SQLITE3_GETSET sqlite3_diskfull_pending = new tcl.lang.Var.SQLITE3_GETSET( "sqlite_diskfull_pending" );
|
||||
static tcl.lang.Var.SQLITE3_GETSET sqlite3_diskfull = new tcl.lang.Var.SQLITE3_GETSET( "sqlite_diskfull" );
|
||||
#endif
|
||||
static void SimulateIOErrorBenign( int X )
|
||||
{
|
||||
#if !TCLSH
|
||||
sqlite3_io_error_benign = ( X );
|
||||
#else
|
||||
sqlite3_io_error_benign.iValue = ( X );
|
||||
#endif
|
||||
}
|
||||
//#define SimulateIOError(CODE) \
|
||||
// if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \
|
||||
// || sqlite3_io_error_pending-- == 1 ) \
|
||||
// { local_ioerr(); CODE; }
|
||||
static bool SimulateIOError()
|
||||
{
|
||||
#if !TCLSH
|
||||
if ( ( sqlite3_io_error_persist != 0 && sqlite3_io_error_hit != 0 )
|
||||
|| sqlite3_io_error_pending-- == 1 )
|
||||
#else
|
||||
if ( ( sqlite3_io_error_persist.iValue != 0 && sqlite3_io_error_hit.iValue != 0 )
|
||||
|| sqlite3_io_error_pending.iValue-- == 1 )
|
||||
#endif
|
||||
{
|
||||
local_ioerr();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void local_ioerr()
|
||||
{
|
||||
#if TRACE
|
||||
IOTRACE( "IOERR\n" );
|
||||
#endif
|
||||
#if !TCLSH
|
||||
sqlite3_io_error_hit++;
|
||||
if ( sqlite3_io_error_benign == 0 )
|
||||
sqlite3_io_error_hardhit++;
|
||||
#else
|
||||
sqlite3_io_error_hit.iValue++;
|
||||
if ( sqlite3_io_error_benign.iValue == 0 )
|
||||
sqlite3_io_error_hardhit.iValue++;
|
||||
#endif
|
||||
}
|
||||
//#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--; \
|
||||
// } \
|
||||
// }
|
||||
static bool SimulateDiskfullError()
|
||||
{
|
||||
#if !TCLSH
|
||||
if ( sqlite3_diskfull_pending != 0 )
|
||||
{
|
||||
if ( sqlite3_diskfull_pending == 1 )
|
||||
{
|
||||
#else
|
||||
if ( sqlite3_diskfull_pending.iValue != 0 )
|
||||
{
|
||||
if ( sqlite3_diskfull_pending.iValue == 1 )
|
||||
{
|
||||
#endif
|
||||
local_ioerr();
|
||||
#if !TCLSH
|
||||
sqlite3_diskfull = 1;
|
||||
sqlite3_io_error_hit = 1;
|
||||
#else
|
||||
sqlite3_diskfull.iValue = 1;
|
||||
sqlite3_io_error_hit.iValue = 1;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if !TCLSH
|
||||
sqlite3_diskfull_pending--;
|
||||
#else
|
||||
sqlite3_diskfull_pending.iValue--;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
|
||||
private static bool SimulateIOError()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//#define SimulateIOErrorBenign(X)
|
||||
private static void SimulateIOErrorBenign(int x)
|
||||
{
|
||||
}
|
||||
|
||||
//#define SimulateIOError(A)
|
||||
//#define SimulateDiskfullError(A)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** When testing, keep a count of the number of open files.
|
||||
*/
|
||||
#if SQLITE_TEST
|
||||
#if !TCLSH
|
||||
static int sqlite3_open_file_count = 0;
|
||||
#else
|
||||
static tcl.lang.Var.SQLITE3_GETSET sqlite3_open_file_count = new tcl.lang.Var.SQLITE3_GETSET( "sqlite3_open_file_count" );
|
||||
#endif
|
||||
|
||||
static void OpenCounter( int X )
|
||||
{
|
||||
#if !TCLSH
|
||||
sqlite3_open_file_count += ( X );
|
||||
#else
|
||||
sqlite3_open_file_count.iValue += ( X );
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
//#define OpenCounter(X)
|
||||
#endif
|
||||
//#endif //* !_OS_COMMON_H_) */
|
||||
}
|
||||
}
|
||||
309
original/Community.CsharpSqlite/src/os_h.cs
Normal file
309
original/Community.CsharpSqlite/src/os_h.cs
Normal file
|
|
@ -0,0 +1,309 @@
|
|||
#define SQLITE_OS_WIN
|
||||
|
||||
using u32 = System.UInt32;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2001 September 16
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** This header file (together with is companion C source-code file
|
||||
** "os.c") attempt to abstract the underlying operating system so that
|
||||
** the SQLite library will work on both POSIX and windows systems.
|
||||
**
|
||||
** This header file is #include-ed by sqliteInt.h and thus ends up
|
||||
** being included by every source file.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2010-08-23 18:52:01 42537b60566f288167f1b5864a5435986838e3a3
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
#if !_SQLITE_OS_H_
|
||||
//#define _SQLITE_OS_H_
|
||||
|
||||
/*
|
||||
** Figure out if we are dealing with Unix, Windows, or some other
|
||||
** operating system. After the following block of preprocess macros,
|
||||
** all of SQLITE_OS_UNIX, SQLITE_OS_WIN, SQLITE_OS_OS2, and SQLITE_OS_OTHER
|
||||
** will defined to either 1 or 0. One of the four will be 1. The other
|
||||
** three will be 0.
|
||||
*/
|
||||
//#if (SQLITE_OS_OTHER)
|
||||
//# if SQLITE_OS_OTHER==1
|
||||
//# undef SQLITE_OS_UNIX
|
||||
//# define SQLITE_OS_UNIX 0
|
||||
//# undef SQLITE_OS_WIN
|
||||
//# define SQLITE_OS_WIN 0
|
||||
//# undef SQLITE_OS_OS2
|
||||
//# define SQLITE_OS_OS2 0
|
||||
//# else
|
||||
//# undef SQLITE_OS_OTHER
|
||||
//# endif
|
||||
//#endif
|
||||
//#if !(SQLITE_OS_UNIX) && !SQLITE_OS_OTHER)
|
||||
//# define SQLITE_OS_OTHER 0
|
||||
//# ifndef SQLITE_OS_WIN
|
||||
//# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__)
|
||||
//# define SQLITE_OS_WIN 1
|
||||
//# define SQLITE_OS_UNIX 0
|
||||
//# define SQLITE_OS_OS2 0
|
||||
//# elif defined(__EMX__) || defined(_OS2) || defined(OS2) || defined(_OS2_) || defined(__OS2__)
|
||||
//# define SQLITE_OS_WIN 0
|
||||
//# define SQLITE_OS_UNIX 0
|
||||
//# define SQLITE_OS_OS2 1
|
||||
//# else
|
||||
//# define SQLITE_OS_WIN 0
|
||||
//# define SQLITE_OS_UNIX 1
|
||||
//# define SQLITE_OS_OS2 0
|
||||
//# endif
|
||||
//# else
|
||||
//# define SQLITE_OS_UNIX 0
|
||||
//# define SQLITE_OS_OS2 0
|
||||
//# endif
|
||||
//#else
|
||||
//# ifndef SQLITE_OS_WIN
|
||||
//# define SQLITE_OS_WIN 0
|
||||
//# endif
|
||||
//#endif
|
||||
|
||||
private const bool SQLITE_OS_WIN = true;
|
||||
private const bool SQLITE_OS_UNIX = false;
|
||||
private const bool SQLITE_OS_OS2 = false;
|
||||
|
||||
/*
|
||||
** Determine if we are dealing with WindowsCE - which has a much
|
||||
** reduced API.
|
||||
*/
|
||||
//#if (_WIN32_WCE)
|
||||
//# define SQLITE_OS_WINCE 1
|
||||
//#else
|
||||
//# define SQLITE_OS_WINCE 0
|
||||
//#endif
|
||||
|
||||
/*
|
||||
** Define the maximum size of a temporary filename
|
||||
*/
|
||||
#if SQLITE_OS_WIN
|
||||
|
||||
//# include <windows.h>
|
||||
private const int MAX_PATH = 260;
|
||||
|
||||
private const int SQLITE_TEMPNAME_SIZE = (MAX_PATH + 50); //# define SQLITE_TEMPNAME_SIZE (MAX_PATH+50)
|
||||
#elif SQLITE_OS_OS2
|
||||
# if FALSE //(__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 3) && OS2_HIGH_MEMORY)
|
||||
//# include <os2safe.h> /* has to be included before os2.h for linking to work */
|
||||
# endif
|
||||
//# define INCL_DOSDATETIME
|
||||
//# define INCL_DOSFILEMGR
|
||||
//# define INCL_DOSERRORS
|
||||
//# define INCL_DOSMISC
|
||||
//# define INCL_DOSPROCESS
|
||||
//# define INCL_DOSMODULEMGR
|
||||
//# define INCL_DOSSEMAPHORES
|
||||
//# include <os2.h>
|
||||
//# include <uconv.h>
|
||||
//# define SQLITE_TEMPNAME_SIZE (CCHMAXPATHCOMP)
|
||||
//#else
|
||||
//# define SQLITE_TEMPNAME_SIZE 200
|
||||
#endif
|
||||
|
||||
/* If the SET_FULLSYNC macro is not defined above, then make it
|
||||
** a no-op
|
||||
*/
|
||||
//#if !SET_FULLSYNC
|
||||
//# define SET_FULLSYNC(x,y)
|
||||
//#endif
|
||||
|
||||
/*
|
||||
** The default size of a disk sector
|
||||
*/
|
||||
#if !SQLITE_DEFAULT_SECTOR_SIZE
|
||||
private const int SQLITE_DEFAULT_SECTOR_SIZE = 512;//# define SQLITE_DEFAULT_SECTOR_SIZE 512
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Temporary files are named starting with this prefix followed by 16 random
|
||||
** alphanumeric characters, and no file extension. They are stored in the
|
||||
** OS's standard temporary file directory, and are deleted prior to exit.
|
||||
** If sqlite is being embedded in another program, you may wish to change the
|
||||
** prefix to reflect your program's name, so that if your program exits
|
||||
** prematurely, old temporary files can be easily identified. This can be done
|
||||
** using -DSQLITE_TEMP_FILE_PREFIX=myprefix_ on the compiler command line.
|
||||
**
|
||||
** 2006-10-31: The default prefix used to be "sqlite_". But then
|
||||
** Mcafee started using SQLite in their anti-virus product and it
|
||||
** started putting files with the "sqlite" name in the c:/temp folder.
|
||||
** This annoyed many windows users. Those users would then do a
|
||||
** Google search for "sqlite", find the telephone numbers of the
|
||||
** developers and call to wake them up at night and complain.
|
||||
** For this reason, the default name prefix is changed to be "sqlite"
|
||||
** spelled backwards. So the temp files are still identified, but
|
||||
** anybody smart enough to figure out the code is also likely smart
|
||||
** enough to know that calling the developer will not help get rid
|
||||
** of the file.
|
||||
*/
|
||||
#if !SQLITE_TEMP_FILE_PREFIX
|
||||
private const string SQLITE_TEMP_FILE_PREFIX = "etilqs_"; //# define SQLITE_TEMP_FILE_PREFIX "etilqs_"
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The following values may be passed as the second argument to
|
||||
** sqlite3OsLock(). The various locks exhibit the following semantics:
|
||||
**
|
||||
** SHARED: Any number of processes may hold a SHARED lock simultaneously.
|
||||
** RESERVED: A single process may hold a RESERVED lock on a file at
|
||||
** any time. Other processes may hold and obtain new SHARED locks.
|
||||
** PENDING: A single process may hold a PENDING lock on a file at
|
||||
** any one time. Existing SHARED locks may persist, but no new
|
||||
** SHARED locks may be obtained by other processes.
|
||||
** EXCLUSIVE: An EXCLUSIVE lock precludes all other locks.
|
||||
**
|
||||
** PENDING_LOCK may not be passed directly to sqlite3OsLock(). Instead, a
|
||||
** process that requests an EXCLUSIVE lock may actually obtain a PENDING
|
||||
** lock. This can be upgraded to an EXCLUSIVE lock by a subsequent call to
|
||||
** sqlite3OsLock().
|
||||
*/
|
||||
private const int NO_LOCK = 0;
|
||||
private const int SHARED_LOCK = 1;
|
||||
private const int RESERVED_LOCK = 2;
|
||||
private const int PENDING_LOCK = 3;
|
||||
private const int EXCLUSIVE_LOCK = 4;
|
||||
|
||||
/*
|
||||
** File Locking Notes: (Mostly about windows but also some info for Unix)
|
||||
**
|
||||
** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because
|
||||
** those functions are not available. So we use only LockFile() and
|
||||
** UnlockFile().
|
||||
**
|
||||
** LockFile() prevents not just writing but also reading by other processes.
|
||||
** A SHARED_LOCK is obtained by locking a single randomly-chosen
|
||||
** byte out of a specific range of bytes. The lock byte is obtained at
|
||||
** random so two separate readers can probably access the file at the
|
||||
** same time, unless they are unlucky and choose the same lock byte.
|
||||
** An EXCLUSIVE_LOCK is obtained by locking all bytes in the range.
|
||||
** There can only be one writer. A RESERVED_LOCK is obtained by locking
|
||||
** a single byte of the file that is designated as the reserved lock byte.
|
||||
** A PENDING_LOCK is obtained by locking a designated byte different from
|
||||
** the RESERVED_LOCK byte.
|
||||
**
|
||||
** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available,
|
||||
** which means we can use reader/writer locks. When reader/writer locks
|
||||
** are used, the lock is placed on the same range of bytes that is used
|
||||
** for probabilistic locking in Win95/98/ME. Hence, the locking scheme
|
||||
** will support two or more Win95 readers or two or more WinNT readers.
|
||||
** But a single Win95 reader will lock out all WinNT readers and a single
|
||||
** WinNT reader will lock out all other Win95 readers.
|
||||
**
|
||||
** The following #defines specify the range of bytes used for locking.
|
||||
** SHARED_SIZE is the number of bytes available in the pool from which
|
||||
** a random byte is selected for a shared lock. The pool of bytes for
|
||||
** shared locks begins at SHARED_FIRST.
|
||||
**
|
||||
** The same locking strategy and
|
||||
** byte ranges are used for Unix. This leaves open the possiblity of having
|
||||
** clients on win95, winNT, and unix all talking to the same shared file
|
||||
** and all locking correctly. To do so would require that samba (or whatever
|
||||
** tool is being used for file sharing) implements locks correctly between
|
||||
** windows and unix. I'm guessing that isn't likely to happen, but by
|
||||
** using the same locking range we are at least open to the possibility.
|
||||
**
|
||||
** Locking in windows is manditory. For this reason, we cannot store
|
||||
** actual data in the bytes used for locking. The pager never allocates
|
||||
** the pages involved in locking therefore. SHARED_SIZE is selected so
|
||||
** that all locks will fit on a single page even at the minimum page size.
|
||||
** PENDING_BYTE defines the beginning of the locks. By default PENDING_BYTE
|
||||
** is set high so that we don't have to allocate an unused page except
|
||||
** for very large databases. But one should test the page skipping logic
|
||||
** by setting PENDING_BYTE low and running the entire regression suite.
|
||||
**
|
||||
** Changing the value of PENDING_BYTE results in a subtly incompatible
|
||||
** file format. Depending on how it is changed, you might not notice
|
||||
** the incompatibility right away, even running a full regression test.
|
||||
** The default location of PENDING_BYTE is the first byte past the
|
||||
** 1GB boundary.
|
||||
**
|
||||
*/
|
||||
#if SQLITE_OMIT_WSD
|
||||
//# define PENDING_BYTE (0x40000000)
|
||||
static int PENDING_BYTE = 0x40000000;
|
||||
#else
|
||||
|
||||
//# define PENDING_BYTE sqlite3PendingByte
|
||||
private static int PENDING_BYTE = 0x40000000;
|
||||
|
||||
#endif
|
||||
|
||||
private static int RESERVED_BYTE = (PENDING_BYTE + 1);
|
||||
private static int SHARED_FIRST = (PENDING_BYTE + 2);
|
||||
private static int SHARED_SIZE = 510;
|
||||
|
||||
/*
|
||||
** Wrapper around OS specific sqlite3_os_init() function.
|
||||
*/
|
||||
//int sqlite3OsInit(void);
|
||||
|
||||
/*
|
||||
** Functions for accessing sqlite3_file methods
|
||||
*/
|
||||
|
||||
//int sqlite3OsClose(sqlite3_file);
|
||||
//int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset);
|
||||
//int sqlite3OsWrite(sqlite3_file*, const void*, int amt, i64 offset);
|
||||
//int sqlite3OsTruncate(sqlite3_file*, i64 size);
|
||||
//int sqlite3OsSync(sqlite3_file*, int);
|
||||
//int sqlite3OsFileSize(sqlite3_file*, i64 pSize);
|
||||
//int sqlite3OsLock(sqlite3_file*, int);
|
||||
//int sqlite3OsUnlock(sqlite3_file*, int);
|
||||
//int sqlite3OsCheckReservedLock(sqlite3_file *id, int pResOut);
|
||||
//int sqlite3OsFileControl(sqlite3_file*,int,void);
|
||||
//#define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0
|
||||
private const u32 SQLITE_FCNTL_DB_UNCHANGED = 0xca093fa0;
|
||||
|
||||
//int sqlite3OsSectorSize(sqlite3_file *id);
|
||||
//int sqlite3OsDeviceCharacteristics(sqlite3_file *id);
|
||||
//int sqlite3OsShmMap(sqlite3_file *,int,int,int,object volatile *);
|
||||
//int sqlite3OsShmLock(sqlite3_file *id, int, int, int);
|
||||
//void sqlite3OsShmBarrier(sqlite3_file *id);
|
||||
//int sqlite3OsShmUnmap(sqlite3_file *id, int);
|
||||
|
||||
/*
|
||||
** Functions for accessing sqlite3_vfs methods
|
||||
*/
|
||||
//int sqlite3OsOpen(sqlite3_vfs *, string , sqlite3_file*, int, int );
|
||||
//int sqlite3OsDelete(sqlite3_vfs *, string , int);
|
||||
//int sqlite3OsAccess(sqlite3_vfs *, string , int, int pResOut);
|
||||
//int sqlite3OsFullPathname(sqlite3_vfs *, string , int, char );
|
||||
#if !SQLITE_OMIT_LOAD_EXTENSION
|
||||
//void *sqlite3OsDlOpen(sqlite3_vfs *, string );
|
||||
//void sqlite3OsDlError(sqlite3_vfs *, int, char );
|
||||
//void (*sqlite3OsDlSym(sqlite3_vfs *, object *, string ))(void);
|
||||
//void sqlite3OsDlClose(sqlite3_vfs *, object );
|
||||
#endif
|
||||
//int sqlite3OsRandomness(sqlite3_vfs *, int, char );
|
||||
//int sqlite3OsSleep(sqlite3_vfs *, int);
|
||||
//int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64);
|
||||
|
||||
/*
|
||||
** Convenience functions for opening and closing files using
|
||||
** sqlite3Malloc() to obtain space for the file-handle structure.
|
||||
*/
|
||||
//int sqlite3OsOpenMalloc(sqlite3_vfs *, string , sqlite3_file **, int,int);
|
||||
//int sqlite3OsCloseFree(sqlite3_file );
|
||||
#endif // * _SQLITE_OS_H_ */
|
||||
}
|
||||
}
|
||||
3845
original/Community.CsharpSqlite/src/os_win_c.cs
Normal file
3845
original/Community.CsharpSqlite/src/os_win_c.cs
Normal file
File diff suppressed because it is too large
Load diff
7936
original/Community.CsharpSqlite/src/pager_c.cs
Normal file
7936
original/Community.CsharpSqlite/src/pager_c.cs
Normal file
File diff suppressed because it is too large
Load diff
216
original/Community.CsharpSqlite/src/pager_h.cs
Normal file
216
original/Community.CsharpSqlite/src/pager_h.cs
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
using Pgno = System.UInt32;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This header file defines the interface that the sqlite page cache
|
||||
** subsystem. The page cache subsystem reads and writes a file a page
|
||||
** at a time and provides a journal for rollback.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2011-05-19 13:26:54 ed1da510a239ea767a01dc332b667119fa3c908e
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#if !_PAGER_H_
|
||||
//#define _PAGER_H_
|
||||
|
||||
/*
|
||||
** Default maximum size for persistent journal files. A negative
|
||||
** value means no limit. This value may be overridden using the
|
||||
** sqlite3PagerJournalSizeLimit() API. See also "PRAGMA journal_size_limit".
|
||||
*/
|
||||
#if !SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT
|
||||
private const int SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT = -1;//#define SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT -1
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The type used to represent a page number. The first page in a file
|
||||
** is called page 1. 0 is used to represent "not a page".
|
||||
*/
|
||||
//typedef u32 Pgno;
|
||||
|
||||
/*
|
||||
** Each open file is managed by a separate instance of the "Pager" structure.
|
||||
*/
|
||||
//typedef struct Pager Pager;
|
||||
|
||||
/*
|
||||
** Handle type for pages.
|
||||
*/
|
||||
//typedef struct PgHdr DbPage;
|
||||
|
||||
/*
|
||||
** Page number PAGER_MJ_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 master journal name - there are no more pages to
|
||||
** roll back. See comments for function writeMasterJournal() in pager.c
|
||||
** for details.
|
||||
*/
|
||||
|
||||
//#define PAGER_MJ_PGNO(x) ((Pgno)((PENDING_BYTE/((x)->pageSize))+1))
|
||||
private static Pgno PAGER_MJ_PGNO(Pager x)
|
||||
{
|
||||
return ((Pgno)((PENDING_BYTE / ((x).pageSize)) + 1));
|
||||
}
|
||||
|
||||
/*
|
||||
** Allowed values for the flags parameter to sqlite3PagerOpen().
|
||||
**
|
||||
** NOTE: These values must match the corresponding BTREE_ values in btree.h.
|
||||
*/
|
||||
|
||||
//#define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */
|
||||
//#define PAGER_NO_READLOCK 0x0002 /* Omit readlocks on readonly files */
|
||||
//#define PAGER_MEMORY 0x0004 /* In-memory database */
|
||||
private const int PAGER_OMIT_JOURNAL = 0x0001;
|
||||
|
||||
private const int PAGER_NO_READLOCK = 0x0002;
|
||||
private const int PAGER_MEMORY = 0x0004;
|
||||
|
||||
/*
|
||||
** Valid values for the second argument to sqlite3PagerLockingMode().
|
||||
*/
|
||||
|
||||
//#define PAGER_LOCKINGMODE_QUERY -1
|
||||
//#define PAGER_LOCKINGMODE_NORMAL 0
|
||||
//#define PAGER_LOCKINGMODE_EXCLUSIVE 1
|
||||
private static int PAGER_LOCKINGMODE_QUERY = -1;
|
||||
|
||||
private static int PAGER_LOCKINGMODE_NORMAL = 0;
|
||||
private static int PAGER_LOCKINGMODE_EXCLUSIVE = 1;
|
||||
|
||||
/*
|
||||
** Numeric constants that encode the journalmode.
|
||||
*/
|
||||
|
||||
//#define PAGER_JOURNALMODE_QUERY (-1) /* Query the value of journalmode */
|
||||
//#define PAGER_JOURNALMODE_DELETE 0 /* Commit by deleting journal file */
|
||||
//#define PAGER_JOURNALMODE_PERSIST 1 /* Commit by zeroing journal header */
|
||||
//#define PAGER_JOURNALMODE_OFF 2 /* Journal omitted. */
|
||||
//#define PAGER_JOURNALMODE_TRUNCATE 3 /* Commit by truncating journal */
|
||||
//#define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */
|
||||
//#define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */
|
||||
private const int PAGER_JOURNALMODE_QUERY = -1;
|
||||
|
||||
private const int PAGER_JOURNALMODE_DELETE = 0;
|
||||
private const int PAGER_JOURNALMODE_PERSIST = 1;
|
||||
private const int PAGER_JOURNALMODE_OFF = 2;
|
||||
private const int PAGER_JOURNALMODE_TRUNCATE = 3;
|
||||
private const int PAGER_JOURNALMODE_MEMORY = 4;
|
||||
private const int PAGER_JOURNALMODE_WAL = 5;
|
||||
|
||||
/*
|
||||
** The remainder of this file contains the declarations of the functions
|
||||
** that make up the Pager sub-system API. See source code comments for
|
||||
** a detailed description of each routine.
|
||||
*/
|
||||
/* Open and close a Pager connection. */
|
||||
//int sqlite3PagerOpen(
|
||||
// sqlite3_vfs*,
|
||||
// Pager **ppPager,
|
||||
// const char*,
|
||||
// int,
|
||||
// int,
|
||||
// int,
|
||||
//// void()(DbPage)
|
||||
//);
|
||||
//int sqlite3PagerClose(Pager *pPager);
|
||||
//int sqlite3PagerReadFileheader(Pager*, int, unsigned char);
|
||||
|
||||
/* Functions used to configure a Pager object. */
|
||||
//void sqlite3PagerSetBusyhandler(Pager*, int()(void ), object );
|
||||
//int sqlite3PagerSetPagesize(Pager*, u32*, int);
|
||||
//int sqlite3PagerMaxPageCount(Pager*, int);
|
||||
//void sqlite3PagerSetCachesize(Pager*, int);
|
||||
//void sqlite3PagerSetSafetyLevel(Pager*,int,int,int);
|
||||
//int sqlite3PagerLockingMode(Pager *, int);
|
||||
//int sqlite3PagerSetJournalMode(Pager *, int);
|
||||
//int sqlite3PagerGetJournalMode(Pager);
|
||||
//int sqlite3PagerOkToChangeJournalMode(Pager);
|
||||
//i64 sqlite3PagerJournalSizeLimit(Pager *, i64);
|
||||
//sqlite3_backup **sqlite3PagerBackupPtr(Pager);
|
||||
|
||||
/* Functions used to obtain and release page references. */
|
||||
//int sqlite3PagerAcquire(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag);
|
||||
//#define sqlite3PagerGet(A,B,C) sqlite3PagerAcquire(A,B,C,0)
|
||||
//DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno);
|
||||
//void sqlite3PagerRef(DbPage);
|
||||
//void sqlite3PagerUnref(DbPage);
|
||||
|
||||
/* Operations on page references. */
|
||||
//int sqlite3PagerWrite(DbPage);
|
||||
//void sqlite3PagerDontWrite(DbPage);
|
||||
//int sqlite3PagerMovepage(Pager*,DbPage*,Pgno,int);
|
||||
//int sqlite3PagerPageRefcount(DbPage);
|
||||
//void *sqlite3PagerGetData(DbPage );
|
||||
//void *sqlite3PagerGetExtra(DbPage );
|
||||
|
||||
/* Functions used to manage pager transactions and savepoints. */
|
||||
//void sqlite3PagerPagecount(Pager*, int);
|
||||
//int sqlite3PagerBegin(Pager*, int exFlag, int);
|
||||
//int sqlite3PagerCommitPhaseOne(Pager*,string zMaster, int);
|
||||
//int sqlite3PagerExclusiveLock(Pager);
|
||||
//int sqlite3PagerSync(Pager *pPager);
|
||||
//int sqlite3PagerCommitPhaseTwo(Pager);
|
||||
//int sqlite3PagerRollback(Pager);
|
||||
//int sqlite3PagerOpenSavepoint(Pager *pPager, int n);
|
||||
//int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint);
|
||||
//int sqlite3PagerSharedLock(Pager *pPager);
|
||||
|
||||
//int sqlite3PagerCheckpoint(Pager *pPager, int, int*, int);
|
||||
//int sqlite3PagerWalSupported(Pager* pPager);
|
||||
//int sqlite3PagerWalCallback(Pager* pPager);
|
||||
//int sqlite3PagerOpenWal(Pager* pPager, int* pisOpen);
|
||||
//int sqlite3PagerCloseWal(Pager* pPager);
|
||||
|
||||
/* Functions used to query pager state and configuration. */
|
||||
//u8 sqlite3PagerIsreadonly(Pager);
|
||||
//int sqlite3PagerRefcount(Pager);
|
||||
//int sqlite3PagerMemUsed(Pager);
|
||||
//string sqlite3PagerFilename(Pager);
|
||||
//const sqlite3_vfs *sqlite3PagerVfs(Pager);
|
||||
//sqlite3_file *sqlite3PagerFile(Pager);
|
||||
//string sqlite3PagerJournalname(Pager);
|
||||
//int sqlite3PagerNosync(Pager);
|
||||
//void *sqlite3PagerTempSpace(Pager);
|
||||
//int sqlite3PagerIsMemdb(Pager);
|
||||
|
||||
/* Functions used to truncate the database file. */
|
||||
//void sqlite3PagerTruncateImage(Pager*,Pgno);
|
||||
|
||||
//#if (SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL)
|
||||
//void *sqlite3PagerCodec(DbPage );
|
||||
//#endif
|
||||
|
||||
/* Functions to support testing and debugging. */
|
||||
//#if !NDEBUG || SQLITE_TEST
|
||||
// Pgno sqlite3PagerPagenumber(DbPage);
|
||||
// int sqlite3PagerIswriteable(DbPage);
|
||||
//#endif
|
||||
//#if SQLITE_TEST
|
||||
// int *sqlite3PagerStats(Pager);
|
||||
// void sqlite3PagerRefdump(Pager);
|
||||
// void disable_simulated_io_errors(void);
|
||||
// void enable_simulated_io_errors(void);
|
||||
//#else
|
||||
//# define disable_simulated_io_errors()
|
||||
//# define enable_simulated_io_errors()
|
||||
//#endif
|
||||
}
|
||||
}
|
||||
4625
original/Community.CsharpSqlite/src/parse_c.cs
Normal file
4625
original/Community.CsharpSqlite/src/parse_c.cs
Normal file
File diff suppressed because it is too large
Load diff
331
original/Community.CsharpSqlite/src/parse_h.cs
Normal file
331
original/Community.CsharpSqlite/src/parse_h.cs
Normal file
|
|
@ -0,0 +1,331 @@
|
|||
/*
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2010-08-23 18:52:01 42537b60566f288167f1b5864a5435986838e3a3
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
//#define TK_SEMI 1
|
||||
//#define TK_EXPLAIN 2
|
||||
//#define TK_QUERY 3
|
||||
//#define TK_PLAN 4
|
||||
//#define TK_BEGIN 5
|
||||
//#define TK_TRANSACTION 6
|
||||
//#define TK_DEFERRED 7
|
||||
//#define TK_IMMEDIATE 8
|
||||
//#define TK_EXCLUSIVE 9
|
||||
//#define TK_COMMIT 10
|
||||
//#define TK_END 11
|
||||
//#define TK_ROLLBACK 12
|
||||
//#define TK_SAVEPOINT 13
|
||||
//#define TK_RELEASE 14
|
||||
//#define TK_TO 15
|
||||
//#define TK_TABLE 16
|
||||
//#define TK_CREATE 17
|
||||
//#define TK_IF 18
|
||||
//#define TK_NOT 19
|
||||
//#define TK_EXISTS 20
|
||||
//#define TK_TEMP 21
|
||||
//#define TK_LP 22
|
||||
//#define TK_RP 23
|
||||
//#define TK_AS 24
|
||||
//#define TK_COMMA 25
|
||||
//#define TK_ID 26
|
||||
//#define TK_INDEXED 27
|
||||
//#define TK_ABORT 28
|
||||
//#define TK_ACTION 29
|
||||
//#define TK_AFTER 30
|
||||
//#define TK_ANALYZE 31
|
||||
//#define TK_ASC 32
|
||||
//#define TK_ATTACH 33
|
||||
//#define TK_BEFORE 34
|
||||
//#define TK_BY 35
|
||||
//#define TK_CASCADE 36
|
||||
//#define TK_CAST 37
|
||||
//#define TK_COLUMNKW 38
|
||||
//#define TK_CONFLICT 39
|
||||
//#define TK_DATABASE 40
|
||||
//#define TK_DESC 41
|
||||
//#define TK_DETACH 42
|
||||
//#define TK_EACH 43
|
||||
//#define TK_FAIL 44
|
||||
//#define TK_FOR 45
|
||||
//#define TK_IGNORE 46
|
||||
//#define TK_INITIALLY 47
|
||||
//#define TK_INSTEAD 48
|
||||
//#define TK_LIKE_KW 49
|
||||
//#define TK_MATCH 50
|
||||
//#define TK_NO 51
|
||||
//#define TK_KEY 52
|
||||
//#define TK_OF 53
|
||||
//#define TK_OFFSET 54
|
||||
//#define TK_PRAGMA 55
|
||||
//#define TK_RAISE 56
|
||||
//#define TK_REPLACE 57
|
||||
//#define TK_RESTRICT 58
|
||||
//#define TK_ROW 59
|
||||
//#define TK_TRIGGER 60
|
||||
//#define TK_VACUUM 61
|
||||
//#define TK_VIEW 62
|
||||
//#define TK_VIRTUAL 63
|
||||
//#define TK_REINDEX 64
|
||||
//#define TK_RENAME 65
|
||||
//#define TK_CTIME_KW 66
|
||||
//#define TK_ANY 67
|
||||
//#define TK_OR 68
|
||||
//#define TK_AND 69
|
||||
//#define TK_IS 70
|
||||
//#define TK_BETWEEN 71
|
||||
//#define TK_IN 72
|
||||
//#define TK_ISNULL 73
|
||||
//#define TK_NOTNULL 74
|
||||
//#define TK_NE 75
|
||||
//#define TK_EQ 76
|
||||
//#define TK_GT 77
|
||||
//#define TK_LE 78
|
||||
//#define TK_LT 79
|
||||
//#define TK_GE 80
|
||||
//#define TK_ESCAPE 81
|
||||
//#define TK_BITAND 82
|
||||
//#define TK_BITOR 83
|
||||
//#define TK_LSHIFT 84
|
||||
//#define TK_RSHIFT 85
|
||||
//#define TK_PLUS 86
|
||||
//#define TK_MINUS 87
|
||||
//#define TK_STAR 88
|
||||
//#define TK_SLASH 89
|
||||
//#define TK_REM 90
|
||||
//#define TK_CONCAT 91
|
||||
//#define TK_COLLATE 92
|
||||
//#define TK_BITNOT 93
|
||||
//#define TK_STRING 94
|
||||
//#define TK_JOIN_KW 95
|
||||
//#define TK_CONSTRAINT 96
|
||||
//#define TK_DEFAULT 97
|
||||
//#define TK_NULL 98
|
||||
//#define TK_PRIMARY 99
|
||||
//#define TK_UNIQUE 100
|
||||
//#define TK_CHECK 101
|
||||
//#define TK_REFERENCES 102
|
||||
//#define TK_AUTOINCR 103
|
||||
//#define TK_ON 104
|
||||
//#define TK_INSERT 105
|
||||
//#define TK_DELETE 106
|
||||
//#define TK_UPDATE 107
|
||||
//#define TK_SET 108
|
||||
//#define TK_DEFERRABLE 109
|
||||
//#define TK_FOREIGN 110
|
||||
//#define TK_DROP 111
|
||||
//#define TK_UNION 112
|
||||
//#define TK_ALL 113
|
||||
//#define TK_EXCEPT 114
|
||||
//#define TK_INTERSECT 115
|
||||
//#define TK_SELECT 116
|
||||
//#define TK_DISTINCT 117
|
||||
//#define TK_DOT 118
|
||||
//#define TK_FROM 119
|
||||
//#define TK_JOIN 120
|
||||
//#define TK_USING 121
|
||||
//#define TK_ORDER 122
|
||||
//#define TK_GROUP 123
|
||||
//#define TK_HAVING 124
|
||||
//#define TK_LIMIT 125
|
||||
//#define TK_WHERE 126
|
||||
//#define TK_INTO 127
|
||||
//#define TK_VALUES 128
|
||||
//#define TK_INTEGER 129
|
||||
//#define TK_FLOAT 130
|
||||
//#define TK_BLOB 131
|
||||
//#define TK_REGISTER 132
|
||||
//#define TK_VARIABLE 133
|
||||
//#define TK_CASE 134
|
||||
//#define TK_WHEN 135
|
||||
//#define TK_THEN 136
|
||||
//#define TK_ELSE 137
|
||||
//#define TK_INDEX 138
|
||||
//#define TK_ALTER 139
|
||||
//#define TK_ADD 140
|
||||
//#define TK_TO_TEXT 141
|
||||
//#define TK_TO_BLOB 142
|
||||
//#define TK_TO_NUMERIC 143
|
||||
//#define TK_TO_INT 144
|
||||
//#define TK_TO_REAL 145
|
||||
//#define TK_ISNOT 146
|
||||
//#define TK_END_OF_FILE 147
|
||||
//#define TK_ILLEGAL 148
|
||||
//#define TK_SPACE 149
|
||||
//#define TK_UNCLOSED_STRING 150
|
||||
//#define TK_FUNCTION 151
|
||||
//#define TK_COLUMN 152
|
||||
//#define TK_AGG_FUNCTION 153
|
||||
//#define TK_AGG_COLUMN 154
|
||||
//#define TK_CONST_FUNC 155
|
||||
//#define TK_UMINUS 156
|
||||
//#define TK_UPLUS 157
|
||||
public const int TK_SEMI = 1;
|
||||
|
||||
public const int TK_EXPLAIN = 2;
|
||||
public const int TK_QUERY = 3;
|
||||
public const int TK_PLAN = 4;
|
||||
public const int TK_BEGIN = 5;
|
||||
public const int TK_TRANSACTION = 6;
|
||||
public const int TK_DEFERRED = 7;
|
||||
public const int TK_IMMEDIATE = 8;
|
||||
public const int TK_EXCLUSIVE = 9;
|
||||
public const int TK_COMMIT = 10;
|
||||
public const int TK_END = 11;
|
||||
public const int TK_ROLLBACK = 12;
|
||||
public const int TK_SAVEPOINT = 13;
|
||||
public const int TK_RELEASE = 14;
|
||||
public const int TK_TO = 15;
|
||||
public const int TK_TABLE = 16;
|
||||
public const int TK_CREATE = 17;
|
||||
public const int TK_IF = 18;
|
||||
public const int TK_NOT = 19;
|
||||
public const int TK_EXISTS = 20;
|
||||
public const int TK_TEMP = 21;
|
||||
public const int TK_LP = 22;
|
||||
public const int TK_RP = 23;
|
||||
public const int TK_AS = 24;
|
||||
public const int TK_COMMA = 25;
|
||||
public const int TK_ID = 26;
|
||||
public const int TK_INDEXED = 27;
|
||||
public const int TK_ABORT = 28;
|
||||
public const int TK_ACTION = 29;
|
||||
public const int TK_AFTER = 30;
|
||||
public const int TK_ANALYZE = 31;
|
||||
public const int TK_ASC = 32;
|
||||
public const int TK_ATTACH = 33;
|
||||
public const int TK_BEFORE = 34;
|
||||
public const int TK_BY = 35;
|
||||
public const int TK_CASCADE = 36;
|
||||
public const int TK_CAST = 37;
|
||||
public const int TK_COLUMNKW = 38;
|
||||
public const int TK_CONFLICT = 39;
|
||||
public const int TK_DATABASE = 40;
|
||||
public const int TK_DESC = 41;
|
||||
public const int TK_DETACH = 42;
|
||||
public const int TK_EACH = 43;
|
||||
public const int TK_FAIL = 44;
|
||||
public const int TK_FOR = 45;
|
||||
public const int TK_IGNORE = 46;
|
||||
public const int TK_INITIALLY = 47;
|
||||
public const int TK_INSTEAD = 48;
|
||||
public const int TK_LIKE_KW = 49;
|
||||
public const int TK_MATCH = 50;
|
||||
public const int TK_NO = 51;
|
||||
public const int TK_KEY = 52;
|
||||
public const int TK_OF = 53;
|
||||
public const int TK_OFFSET = 54;
|
||||
public const int TK_PRAGMA = 55;
|
||||
public const int TK_RAISE = 56;
|
||||
public const int TK_REPLACE = 57;
|
||||
public const int TK_RESTRICT = 58;
|
||||
public const int TK_ROW = 59;
|
||||
public const int TK_TRIGGER = 60;
|
||||
public const int TK_VACUUM = 61;
|
||||
public const int TK_VIEW = 62;
|
||||
public const int TK_VIRTUAL = 63;
|
||||
public const int TK_REINDEX = 64;
|
||||
public const int TK_RENAME = 65;
|
||||
public const int TK_CTIME_KW = 66;
|
||||
public const int TK_ANY = 67;
|
||||
public const int TK_OR = 68;
|
||||
public const int TK_AND = 69;
|
||||
public const int TK_IS = 70;
|
||||
public const int TK_BETWEEN = 71;
|
||||
public const int TK_IN = 72;
|
||||
public const int TK_ISNULL = 73;
|
||||
public const int TK_NOTNULL = 74;
|
||||
public const int TK_NE = 75;
|
||||
public const int TK_EQ = 76;
|
||||
public const int TK_GT = 77;
|
||||
public const int TK_LE = 78;
|
||||
public const int TK_LT = 79;
|
||||
public const int TK_GE = 80;
|
||||
public const int TK_ESCAPE = 81;
|
||||
public const int TK_BITAND = 82;
|
||||
public const int TK_BITOR = 83;
|
||||
public const int TK_LSHIFT = 84;
|
||||
public const int TK_RSHIFT = 85;
|
||||
public const int TK_PLUS = 86;
|
||||
public const int TK_MINUS = 87;
|
||||
public const int TK_STAR = 88;
|
||||
public const int TK_SLASH = 89;
|
||||
public const int TK_REM = 90;
|
||||
public const int TK_CONCAT = 91;
|
||||
public const int TK_COLLATE = 92;
|
||||
public const int TK_BITNOT = 93;
|
||||
public const int TK_STRING = 94;
|
||||
public const int TK_JOIN_KW = 95;
|
||||
public const int TK_CONSTRAINT = 96;
|
||||
public const int TK_DEFAULT = 97;
|
||||
public const int TK_NULL = 98;
|
||||
public const int TK_PRIMARY = 99;
|
||||
public const int TK_UNIQUE = 100;
|
||||
public const int TK_CHECK = 101;
|
||||
public const int TK_REFERENCES = 102;
|
||||
public const int TK_AUTOINCR = 103;
|
||||
public const int TK_ON = 104;
|
||||
public const int TK_INSERT = 105;
|
||||
public const int TK_DELETE = 106;
|
||||
public const int TK_UPDATE = 107;
|
||||
public const int TK_SET = 108;
|
||||
public const int TK_DEFERRABLE = 109;
|
||||
public const int TK_FOREIGN = 110;
|
||||
public const int TK_DROP = 111;
|
||||
public const int TK_UNION = 112;
|
||||
public const int TK_ALL = 113;
|
||||
public const int TK_EXCEPT = 114;
|
||||
public const int TK_INTERSECT = 115;
|
||||
public const int TK_SELECT = 116;
|
||||
public const int TK_DISTINCT = 117;
|
||||
public const int TK_DOT = 118;
|
||||
public const int TK_FROM = 119;
|
||||
public const int TK_JOIN = 120;
|
||||
public const int TK_USING = 121;
|
||||
public const int TK_ORDER = 122;
|
||||
public const int TK_GROUP = 123;
|
||||
public const int TK_HAVING = 124;
|
||||
public const int TK_LIMIT = 125;
|
||||
public const int TK_WHERE = 126;
|
||||
public const int TK_INTO = 127;
|
||||
public const int TK_VALUES = 128;
|
||||
public const int TK_INTEGER = 129;
|
||||
public const int TK_FLOAT = 130;
|
||||
public const int TK_BLOB = 131;
|
||||
public const int TK_REGISTER = 132;
|
||||
public const int TK_VARIABLE = 133;
|
||||
public const int TK_CASE = 134;
|
||||
public const int TK_WHEN = 135;
|
||||
public const int TK_THEN = 136;
|
||||
public const int TK_ELSE = 137;
|
||||
public const int TK_INDEX = 138;
|
||||
public const int TK_ALTER = 139;
|
||||
public const int TK_ADD = 140;
|
||||
public const int TK_TO_TEXT = 141;
|
||||
public const int TK_TO_BLOB = 142;
|
||||
public const int TK_TO_NUMERIC = 143;
|
||||
public const int TK_TO_INT = 144;
|
||||
public const int TK_TO_REAL = 145;
|
||||
public const int TK_ISNOT = 146;
|
||||
public const int TK_END_OF_FILE = 147;
|
||||
public const int TK_ILLEGAL = 148;
|
||||
public const int TK_SPACE = 149;
|
||||
public const int TK_UNCLOSED_STRING = 150;
|
||||
public const int TK_FUNCTION = 151;
|
||||
public const int TK_COLUMN = 152;
|
||||
public const int TK_AGG_FUNCTION = 153;
|
||||
public const int TK_AGG_COLUMN = 154;
|
||||
public const int TK_CONST_FUNC = 155;
|
||||
public const int TK_UMINUS = 156;
|
||||
public const int TK_UPLUS = 157;
|
||||
}
|
||||
}
|
||||
1204
original/Community.CsharpSqlite/src/pcache1_c.cs
Normal file
1204
original/Community.CsharpSqlite/src/pcache1_c.cs
Normal file
File diff suppressed because it is too large
Load diff
772
original/Community.CsharpSqlite/src/pcache_c.cs
Normal file
772
original/Community.CsharpSqlite/src/pcache_c.cs
Normal file
|
|
@ -0,0 +1,772 @@
|
|||
using System.Diagnostics;
|
||||
using Pgno = System.UInt32;
|
||||
|
||||
using u32 = System.UInt32;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
using sqlite3_pcache = Sqlite3.PCache1;
|
||||
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2008 August 05
|
||||
**
|
||||
** 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 that page cache.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** A complete page cache is an instance of this structure.
|
||||
*/
|
||||
|
||||
public class PCache
|
||||
{
|
||||
public PgHdr pDirty, pDirtyTail; /* List of dirty pages in LRU order */
|
||||
public PgHdr pSynced; /* Last synced page in dirty page list */
|
||||
public int _nRef; /* Number of referenced pages */
|
||||
public int nMax; /* Configured cache size */
|
||||
public int szPage; /* Size of every page in this cache */
|
||||
public int szExtra; /* Size of extra space for each page */
|
||||
public bool bPurgeable; /* True if pages are on backing store */
|
||||
public dxStress xStress; //int (*xStress)(void*,PgHdr*); /* Call to try make a page clean */
|
||||
public object pStress; /* Argument to xStress */
|
||||
public sqlite3_pcache pCache; /* Pluggable cache module */
|
||||
public PgHdr pPage1; /* Reference to page 1 */
|
||||
|
||||
public int nRef /* Number of referenced pages */
|
||||
{
|
||||
get
|
||||
{
|
||||
return _nRef;
|
||||
}
|
||||
set
|
||||
{
|
||||
_nRef = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
pDirty = null;
|
||||
pDirtyTail = null;
|
||||
pSynced = null;
|
||||
nRef = 0;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
** Some of the Debug.Assert() macros in this code are too expensive to run
|
||||
** even during normal debugging. Use them only rarely on long-running
|
||||
** tests. Enable the expensive asserts using the
|
||||
** -DSQLITE_ENABLE_EXPENSIVE_ASSERT=1 compile-time option.
|
||||
*/
|
||||
#if SQLITE_ENABLE_EXPENSIVE_ASSERT
|
||||
//# define expensive_assert(X) Debug.Assert(X)
|
||||
static void expensive_assert( bool x ) { Debug.Assert( x ); }
|
||||
#else
|
||||
//# define expensive_assert(X)
|
||||
#endif
|
||||
|
||||
/********************************** Linked List Management ********************/
|
||||
|
||||
#if !NDEBUG && SQLITE_ENABLE_EXPENSIVE_ASSERT
|
||||
/*
|
||||
** Check that the pCache.pSynced variable is set correctly. If it
|
||||
** is not, either fail an Debug.Assert or return zero. Otherwise, return
|
||||
** non-zero. This is only used in debugging builds, as follows:
|
||||
**
|
||||
** expensive_assert( pcacheCheckSynced(pCache) );
|
||||
*/
|
||||
static int pcacheCheckSynced(PCache pCache){
|
||||
PgHdr p ;
|
||||
for(p=pCache.pDirtyTail; p!=pCache.pSynced; p=p.pDirtyPrev){
|
||||
Debug.Assert( p.nRef !=0|| (p.flags&PGHDR_NEED_SYNC) !=0);
|
||||
}
|
||||
return (p==null || p.nRef!=0 || (p.flags&PGHDR_NEED_SYNC)==0)?1:0;
|
||||
}
|
||||
#endif //* !NDEBUG && SQLITE_ENABLE_EXPENSIVE_ASSERT */
|
||||
|
||||
/*
|
||||
** Remove page pPage from the list of dirty pages.
|
||||
*/
|
||||
|
||||
private static void pcacheRemoveFromDirtyList(PgHdr pPage)
|
||||
{
|
||||
PCache p = pPage.pCache;
|
||||
|
||||
Debug.Assert(pPage.pDirtyNext != null || pPage == p.pDirtyTail);
|
||||
Debug.Assert(pPage.pDirtyPrev != null || pPage == p.pDirty);
|
||||
|
||||
/* Update the PCache1.pSynced variable if necessary. */
|
||||
if (p.pSynced == pPage)
|
||||
{
|
||||
PgHdr pSynced = pPage.pDirtyPrev;
|
||||
while (pSynced != null && (pSynced.flags & PGHDR_NEED_SYNC) != 0)
|
||||
{
|
||||
pSynced = pSynced.pDirtyPrev;
|
||||
}
|
||||
p.pSynced = pSynced;
|
||||
}
|
||||
|
||||
if (pPage.pDirtyNext != null)
|
||||
{
|
||||
pPage.pDirtyNext.pDirtyPrev = pPage.pDirtyPrev;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Assert(pPage == p.pDirtyTail);
|
||||
p.pDirtyTail = pPage.pDirtyPrev;
|
||||
}
|
||||
if (pPage.pDirtyPrev != null)
|
||||
{
|
||||
pPage.pDirtyPrev.pDirtyNext = pPage.pDirtyNext;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Assert(pPage == p.pDirty);
|
||||
p.pDirty = pPage.pDirtyNext;
|
||||
}
|
||||
pPage.pDirtyNext = null;
|
||||
pPage.pDirtyPrev = null;
|
||||
|
||||
#if SQLITE_ENABLE_EXPENSIVE_ASSERT
|
||||
expensive_assert( pcacheCheckSynced(p) );
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Add page pPage to the head of the dirty list (PCache1.pDirty is set to
|
||||
** pPage).
|
||||
*/
|
||||
|
||||
private static void pcacheAddToDirtyList(PgHdr pPage)
|
||||
{
|
||||
PCache p = pPage.pCache;
|
||||
|
||||
Debug.Assert(pPage.pDirtyNext == null && pPage.pDirtyPrev == null && p.pDirty != pPage);
|
||||
|
||||
pPage.pDirtyNext = p.pDirty;
|
||||
if (pPage.pDirtyNext != null)
|
||||
{
|
||||
Debug.Assert(pPage.pDirtyNext.pDirtyPrev == null);
|
||||
pPage.pDirtyNext.pDirtyPrev = pPage;
|
||||
}
|
||||
p.pDirty = pPage;
|
||||
if (null == p.pDirtyTail)
|
||||
{
|
||||
p.pDirtyTail = pPage;
|
||||
}
|
||||
if (null == p.pSynced && 0 == (pPage.flags & PGHDR_NEED_SYNC))
|
||||
{
|
||||
p.pSynced = pPage;
|
||||
}
|
||||
#if SQLITE_ENABLE_EXPENSIVE_ASSERT
|
||||
expensive_assert( pcacheCheckSynced(p) );
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Wrapper around the pluggable caches xUnpin method. If the cache is
|
||||
** being used for an in-memory database, this function is a no-op.
|
||||
*/
|
||||
|
||||
private static void pcacheUnpin(PgHdr p)
|
||||
{
|
||||
PCache pCache = p.pCache;
|
||||
if (pCache.bPurgeable)
|
||||
{
|
||||
if (p.pgno == 1)
|
||||
{
|
||||
pCache.pPage1 = null;
|
||||
}
|
||||
sqlite3GlobalConfig.pcache.xUnpin(pCache.pCache, p, false);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************** General Interfaces ******
|
||||
**
|
||||
** Initialize and shutdown the page cache subsystem. Neither of these
|
||||
** functions are threadsafe.
|
||||
*/
|
||||
|
||||
private static int sqlite3PcacheInitialize()
|
||||
{
|
||||
if (sqlite3GlobalConfig.pcache.xInit == null)
|
||||
{
|
||||
/* IMPLEMENTATION-OF: R-26801-64137 If the xInit() method is NULL, then the
|
||||
** built-in default page cache is used instead of the application defined
|
||||
** page cache. */
|
||||
sqlite3PCacheSetDefault();
|
||||
}
|
||||
return sqlite3GlobalConfig.pcache.xInit(sqlite3GlobalConfig.pcache.pArg);
|
||||
}
|
||||
|
||||
private static void sqlite3PcacheShutdown()
|
||||
{
|
||||
if (sqlite3GlobalConfig.pcache.xShutdown != null)
|
||||
{
|
||||
/* IMPLEMENTATION-OF: R-26000-56589 The xShutdown() method may be NULL. */
|
||||
sqlite3GlobalConfig.pcache.xShutdown(sqlite3GlobalConfig.pcache.pArg);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the size in bytes of a PCache object.
|
||||
*/
|
||||
|
||||
private static int sqlite3PcacheSize()
|
||||
{
|
||||
return 4;
|
||||
}// sizeof( PCache ); }
|
||||
|
||||
/*
|
||||
** Create a new PCache object. Storage space to hold the object
|
||||
** has already been allocated and is passed in as the p pointer.
|
||||
** The caller discovers how much space needs to be allocated by
|
||||
** calling sqlite3PcacheSize().
|
||||
*/
|
||||
|
||||
private static void sqlite3PcacheOpen(
|
||||
int szPage, /* Size of every page */
|
||||
int szExtra, /* Extra space associated with each page */
|
||||
bool bPurgeable, /* True if pages are on backing store */
|
||||
dxStress xStress,//int (*xStress)(void*,PgHdr*),/* Call to try to make pages clean */
|
||||
object pStress, /* Argument to xStress */
|
||||
PCache p /* Preallocated space for the PCache */
|
||||
)
|
||||
{
|
||||
p.Clear();//memset(p, 0, sizeof(PCache));
|
||||
p.szPage = szPage;
|
||||
p.szExtra = szExtra;
|
||||
p.bPurgeable = bPurgeable;
|
||||
p.xStress = xStress;
|
||||
p.pStress = pStress;
|
||||
p.nMax = 100;
|
||||
}
|
||||
|
||||
/*
|
||||
** Change the page size for PCache object. The caller must ensure that there
|
||||
** are no outstanding page references when this function is called.
|
||||
*/
|
||||
|
||||
private static void sqlite3PcacheSetPageSize(PCache pCache, int szPage)
|
||||
{
|
||||
Debug.Assert(pCache.nRef == 0 && pCache.pDirty == null);
|
||||
if (pCache.pCache != null)
|
||||
{
|
||||
sqlite3GlobalConfig.pcache.xDestroy(ref pCache.pCache);
|
||||
pCache.pCache = null;
|
||||
}
|
||||
pCache.szPage = szPage;
|
||||
}
|
||||
|
||||
/*
|
||||
** Try to obtain a page from the cache.
|
||||
*/
|
||||
|
||||
private static int sqlite3PcacheFetch(
|
||||
PCache pCache, /* Obtain the page from this cache */
|
||||
u32 pgno, /* Page number to obtain */
|
||||
int createFlag, /* If true, create page if it does not exist already */
|
||||
ref PgHdr ppPage /* Write the page here */
|
||||
)
|
||||
{
|
||||
PgHdr pPage = null;
|
||||
int eCreate;
|
||||
|
||||
Debug.Assert(pCache != null);
|
||||
Debug.Assert(createFlag == 1 || createFlag == 0);
|
||||
Debug.Assert(pgno > 0);
|
||||
|
||||
/* If the pluggable cache (sqlite3_pcache*) has not been allocated,
|
||||
** allocate it now.
|
||||
*/
|
||||
if (null == pCache.pCache && createFlag != 0)
|
||||
{
|
||||
sqlite3_pcache p;
|
||||
int nByte;
|
||||
nByte = pCache.szPage + pCache.szExtra + 0;// sizeof( PgHdr );
|
||||
p = sqlite3GlobalConfig.pcache.xCreate(nByte, pCache.bPurgeable);
|
||||
//if ( null == p )
|
||||
//{
|
||||
// return SQLITE_NOMEM;
|
||||
//}
|
||||
sqlite3GlobalConfig.pcache.xCachesize(p, pCache.nMax);
|
||||
pCache.pCache = p;
|
||||
}
|
||||
|
||||
eCreate = createFlag * (1 + ((!pCache.bPurgeable || null == pCache.pDirty) ? 1 : 0));
|
||||
|
||||
if (pCache.pCache != null)
|
||||
{
|
||||
pPage = sqlite3GlobalConfig.pcache.xFetch(pCache.pCache, pgno, eCreate);
|
||||
}
|
||||
|
||||
if (null == pPage && eCreate == 1)
|
||||
{
|
||||
PgHdr pPg;
|
||||
|
||||
/* Find a dirty page to write-out and recycle. First try to find a
|
||||
** page that does not require a journal-sync (one with PGHDR_NEED_SYNC
|
||||
** cleared), but if that is not possible settle for any other
|
||||
** unreferenced dirty page.
|
||||
*/
|
||||
#if SQLITE_ENABLE_EXPENSIVE_ASSERT
|
||||
expensive_assert( pcacheCheckSynced(pCache) );
|
||||
#endif
|
||||
for (pPg = pCache.pSynced;
|
||||
pPg != null && (pPg.nRef != 0 || (pPg.flags & PGHDR_NEED_SYNC) != 0);
|
||||
pPg = pPg.pDirtyPrev
|
||||
)
|
||||
;
|
||||
pCache.pSynced = pPg;
|
||||
if (null == pPg)
|
||||
{
|
||||
for (pPg = pCache.pDirtyTail; pPg != null && pPg.nRef != 0; pPg = pPg.pDirtyPrev)
|
||||
;
|
||||
}
|
||||
if (pPg != null)
|
||||
{
|
||||
int rc;
|
||||
#if SQLITE_LOG_CACHE_SPILL
|
||||
sqlite3_log(SQLITE_FULL,
|
||||
"spill page %d making room for %d - cache used: %d/%d",
|
||||
pPg->pgno, pgno,
|
||||
sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache),
|
||||
pCache->nMax);
|
||||
#endif
|
||||
rc = pCache.xStress(pCache.pStress, pPg);
|
||||
if (rc != SQLITE_OK && rc != SQLITE_BUSY)
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
pPage = sqlite3GlobalConfig.pcache.xFetch(pCache.pCache, pgno, 2);
|
||||
}
|
||||
|
||||
if (pPage != null)
|
||||
{
|
||||
if (null == pPage.pData)
|
||||
{
|
||||
// memset(pPage, 0, sizeof(PgHdr));
|
||||
pPage.pData = sqlite3Malloc(pCache.szPage);// pPage->pData = (void*)&pPage[1];
|
||||
//pPage->pExtra = (void*)&((char*)pPage->pData)[pCache->szPage];
|
||||
//memset(pPage->pExtra, 0, pCache->szExtra);
|
||||
pPage.pCache = pCache;
|
||||
pPage.pgno = pgno;
|
||||
}
|
||||
Debug.Assert(pPage.pCache == pCache);
|
||||
Debug.Assert(pPage.pgno == pgno);
|
||||
//assert(pPage->pData == (void*)&pPage[1]);
|
||||
//assert(pPage->pExtra == (void*)&((char*)&pPage[1])[pCache->szPage]);
|
||||
if (0 == pPage.nRef)
|
||||
{
|
||||
pCache.nRef++;
|
||||
}
|
||||
pPage.nRef++;
|
||||
if (pgno == 1)
|
||||
{
|
||||
pCache.pPage1 = pPage;
|
||||
}
|
||||
}
|
||||
ppPage = pPage;
|
||||
return (pPage == null && eCreate != 0) ? SQLITE_NOMEM : SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Decrement the reference count on a page. If the page is clean and the
|
||||
** reference count drops to 0, then it is made elible for recycling.
|
||||
*/
|
||||
|
||||
private static void sqlite3PcacheRelease(PgHdr p)
|
||||
{
|
||||
Debug.Assert(p.nRef > 0);
|
||||
p.nRef--;
|
||||
if (p.nRef == 0)
|
||||
{
|
||||
PCache pCache = p.pCache;
|
||||
pCache.nRef--;
|
||||
if ((p.flags & PGHDR_DIRTY) == 0)
|
||||
{
|
||||
pcacheUnpin(p);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Move the page to the head of the dirty list. */
|
||||
pcacheRemoveFromDirtyList(p);
|
||||
pcacheAddToDirtyList(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Increase the reference count of a supplied page by 1.
|
||||
*/
|
||||
|
||||
private static void sqlite3PcacheRef(PgHdr p)
|
||||
{
|
||||
Debug.Assert(p.nRef > 0);
|
||||
p.nRef++;
|
||||
}
|
||||
|
||||
/*
|
||||
** Drop a page from the cache. There must be exactly one reference to the
|
||||
** page. This function deletes that reference, so after it returns the
|
||||
** page pointed to by p is invalid.
|
||||
*/
|
||||
|
||||
private static void sqlite3PcacheDrop(PgHdr p)
|
||||
{
|
||||
PCache pCache;
|
||||
Debug.Assert(p.nRef == 1);
|
||||
if ((p.flags & PGHDR_DIRTY) != 0)
|
||||
{
|
||||
pcacheRemoveFromDirtyList(p);
|
||||
}
|
||||
pCache = p.pCache;
|
||||
pCache.nRef--;
|
||||
if (p.pgno == 1)
|
||||
{
|
||||
pCache.pPage1 = null;
|
||||
}
|
||||
sqlite3GlobalConfig.pcache.xUnpin(pCache.pCache, p, true);
|
||||
}
|
||||
|
||||
/*
|
||||
** Make sure the page is marked as dirty. If it isn't dirty already,
|
||||
** make it so.
|
||||
*/
|
||||
|
||||
private static void sqlite3PcacheMakeDirty(PgHdr p)
|
||||
{
|
||||
p.flags &= ~PGHDR_DONT_WRITE;
|
||||
Debug.Assert(p.nRef > 0);
|
||||
if (0 == (p.flags & PGHDR_DIRTY))
|
||||
{
|
||||
p.flags |= PGHDR_DIRTY;
|
||||
pcacheAddToDirtyList(p);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Make sure the page is marked as clean. If it isn't clean already,
|
||||
** make it so.
|
||||
*/
|
||||
|
||||
private static void sqlite3PcacheMakeClean(PgHdr p)
|
||||
{
|
||||
if ((p.flags & PGHDR_DIRTY) != 0)
|
||||
{
|
||||
pcacheRemoveFromDirtyList(p);
|
||||
p.flags &= ~(PGHDR_DIRTY | PGHDR_NEED_SYNC);
|
||||
if (p.nRef == 0)
|
||||
{
|
||||
pcacheUnpin(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Make every page in the cache clean.
|
||||
*/
|
||||
|
||||
private static void sqlite3PcacheCleanAll(PCache pCache)
|
||||
{
|
||||
PgHdr p;
|
||||
while ((p = pCache.pDirty) != null)
|
||||
{
|
||||
sqlite3PcacheMakeClean(p);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Clear the PGHDR_NEED_SYNC flag from all dirty pages.
|
||||
*/
|
||||
|
||||
private static void sqlite3PcacheClearSyncFlags(PCache pCache)
|
||||
{
|
||||
PgHdr p;
|
||||
for (p = pCache.pDirty; p != null; p = p.pDirtyNext)
|
||||
{
|
||||
p.flags &= ~PGHDR_NEED_SYNC;
|
||||
}
|
||||
pCache.pSynced = pCache.pDirtyTail;
|
||||
}
|
||||
|
||||
/*
|
||||
** Change the page number of page p to newPgno.
|
||||
*/
|
||||
|
||||
private static void sqlite3PcacheMove(PgHdr p, Pgno newPgno)
|
||||
{
|
||||
PCache pCache = p.pCache;
|
||||
Debug.Assert(p.nRef > 0);
|
||||
Debug.Assert(newPgno > 0);
|
||||
sqlite3GlobalConfig.pcache.xRekey(pCache.pCache, p, p.pgno, newPgno);
|
||||
p.pgno = newPgno;
|
||||
if ((p.flags & PGHDR_DIRTY) != 0 && (p.flags & PGHDR_NEED_SYNC) != 0)
|
||||
{
|
||||
pcacheRemoveFromDirtyList(p);
|
||||
pcacheAddToDirtyList(p);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Drop every cache entry whose page number is greater than "pgno". The
|
||||
** caller must ensure that there are no outstanding references to any pages
|
||||
** other than page 1 with a page number greater than pgno.
|
||||
**
|
||||
** If there is a reference to page 1 and the pgno parameter passed to this
|
||||
** function is 0, then the data area associated with page 1 is zeroed, but
|
||||
** the page object is not dropped.
|
||||
*/
|
||||
|
||||
private static void sqlite3PcacheTruncate(PCache pCache, u32 pgno)
|
||||
{
|
||||
if (pCache.pCache != null)
|
||||
{
|
||||
PgHdr p;
|
||||
PgHdr pNext;
|
||||
for (p = pCache.pDirty; p != null; p = pNext)
|
||||
{
|
||||
pNext = p.pDirtyNext;
|
||||
/* This routine never gets call with a positive pgno except right
|
||||
** after sqlite3PcacheCleanAll(). So if there are dirty pages,
|
||||
** it must be that pgno==0.
|
||||
*/
|
||||
Debug.Assert(p.pgno > 0);
|
||||
if (ALWAYS(p.pgno > pgno))
|
||||
{
|
||||
Debug.Assert((p.flags & PGHDR_DIRTY) != 0);
|
||||
sqlite3PcacheMakeClean(p);
|
||||
}
|
||||
}
|
||||
if (pgno == 0 && pCache.pPage1 != null)
|
||||
{
|
||||
// memset( pCache.pPage1.pData, 0, pCache.szPage );
|
||||
pCache.pPage1.pData = sqlite3Malloc(pCache.szPage);
|
||||
pgno = 1;
|
||||
}
|
||||
sqlite3GlobalConfig.pcache.xTruncate(pCache.pCache, pgno + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Close a cache.
|
||||
*/
|
||||
|
||||
private static void sqlite3PcacheClose(PCache pCache)
|
||||
{
|
||||
if (pCache.pCache != null)
|
||||
{
|
||||
sqlite3GlobalConfig.pcache.xDestroy(ref pCache.pCache);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Discard the contents of the cache.
|
||||
*/
|
||||
|
||||
private static void sqlite3PcacheClear(PCache pCache)
|
||||
{
|
||||
sqlite3PcacheTruncate(pCache, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
** Merge two lists of pages connected by pDirty and in pgno order.
|
||||
** Do not both fixing the pDirtyPrev pointers.
|
||||
*/
|
||||
|
||||
private static PgHdr pcacheMergeDirtyList(PgHdr pA, PgHdr pB)
|
||||
{
|
||||
PgHdr result = new PgHdr();
|
||||
PgHdr pTail = result;
|
||||
while (pA != null && pB != null)
|
||||
{
|
||||
if (pA.pgno < pB.pgno)
|
||||
{
|
||||
pTail.pDirty = pA;
|
||||
pTail = pA;
|
||||
pA = pA.pDirty;
|
||||
}
|
||||
else
|
||||
{
|
||||
pTail.pDirty = pB;
|
||||
pTail = pB;
|
||||
pB = pB.pDirty;
|
||||
}
|
||||
}
|
||||
if (pA != null)
|
||||
{
|
||||
pTail.pDirty = pA;
|
||||
}
|
||||
else if (pB != null)
|
||||
{
|
||||
pTail.pDirty = pB;
|
||||
}
|
||||
else
|
||||
{
|
||||
pTail.pDirty = null;
|
||||
}
|
||||
return result.pDirty;
|
||||
}
|
||||
|
||||
/*
|
||||
** Sort the list of pages in accending order by pgno. Pages are
|
||||
** connected by pDirty pointers. The pDirtyPrev pointers are
|
||||
** corrupted by this sort.
|
||||
**
|
||||
** Since there cannot be more than 2^31 distinct pages in a database,
|
||||
** there cannot be more than 31 buckets required by the merge sorter.
|
||||
** One extra bucket is added to catch overflow in case something
|
||||
** ever changes to make the previous sentence incorrect.
|
||||
*/
|
||||
|
||||
//#define N_SORT_BUCKET 32
|
||||
private const int N_SORT_BUCKET = 32;
|
||||
|
||||
private static PgHdr pcacheSortDirtyList(PgHdr pIn)
|
||||
{
|
||||
PgHdr[] a;
|
||||
PgHdr p;//a[N_SORT_BUCKET], p;
|
||||
int i;
|
||||
a = new PgHdr[N_SORT_BUCKET];//memset(a, 0, sizeof(a));
|
||||
while (pIn != null)
|
||||
{
|
||||
p = pIn;
|
||||
pIn = p.pDirty;
|
||||
p.pDirty = null;
|
||||
for (i = 0; ALWAYS(i < N_SORT_BUCKET - 1); i++)
|
||||
{
|
||||
if (a[i] == null)
|
||||
{
|
||||
a[i] = p;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = pcacheMergeDirtyList(a[i], p);
|
||||
a[i] = null;
|
||||
}
|
||||
}
|
||||
if (NEVER(i == N_SORT_BUCKET - 1))
|
||||
{
|
||||
/* To get here, there need to be 2^(N_SORT_BUCKET) elements in
|
||||
** the input list. But that is impossible.
|
||||
*/
|
||||
a[i] = pcacheMergeDirtyList(a[i], p);
|
||||
}
|
||||
}
|
||||
p = a[0];
|
||||
for (i = 1; i < N_SORT_BUCKET; i++)
|
||||
{
|
||||
p = pcacheMergeDirtyList(p, a[i]);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a list of all dirty pages in the cache, sorted by page number.
|
||||
*/
|
||||
|
||||
private static PgHdr sqlite3PcacheDirtyList(PCache pCache)
|
||||
{
|
||||
PgHdr p;
|
||||
for (p = pCache.pDirty; p != null; p = p.pDirtyNext)
|
||||
{
|
||||
p.pDirty = p.pDirtyNext;
|
||||
}
|
||||
return pcacheSortDirtyList(pCache.pDirty);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the total number of referenced pages held by the cache.
|
||||
*/
|
||||
|
||||
private static int sqlite3PcacheRefCount(PCache pCache)
|
||||
{
|
||||
return pCache.nRef;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of references to the page supplied as an argument.
|
||||
*/
|
||||
|
||||
private static int sqlite3PcachePageRefcount(PgHdr p)
|
||||
{
|
||||
return p.nRef;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the total number of pages in the cache.
|
||||
*/
|
||||
|
||||
private static int sqlite3PcachePagecount(PCache pCache)
|
||||
{
|
||||
int nPage = 0;
|
||||
if (pCache.pCache != null)
|
||||
{
|
||||
nPage = sqlite3GlobalConfig.pcache.xPagecount(pCache.pCache);
|
||||
}
|
||||
return nPage;
|
||||
}
|
||||
|
||||
#if SQLITE_TEST
|
||||
/*
|
||||
** Get the suggested cache-size value.
|
||||
*/
|
||||
static int sqlite3PcacheGetCachesize( PCache pCache )
|
||||
{
|
||||
return pCache.nMax;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Set the suggested cache-size value.
|
||||
*/
|
||||
|
||||
private static void sqlite3PcacheSetCachesize(PCache pCache, int mxPage)
|
||||
{
|
||||
pCache.nMax = mxPage;
|
||||
if (pCache.pCache != null)
|
||||
{
|
||||
sqlite3GlobalConfig.pcache.xCachesize(pCache.pCache, mxPage);
|
||||
}
|
||||
}
|
||||
|
||||
#if SQLITE_CHECK_PAGES || (SQLITE_DEBUG)
|
||||
/*
|
||||
** For all dirty pages currently in the cache, invoke the specified
|
||||
** callback. This is only used if the SQLITE_CHECK_PAGES macro is
|
||||
** defined.
|
||||
*/
|
||||
|
||||
private static void sqlite3PcacheIterateDirty(PCache pCache, dxIter xIter)
|
||||
{
|
||||
PgHdr pDirty;
|
||||
for (pDirty = pCache.pDirty; pDirty != null; pDirty = pDirty.pDirtyNext)
|
||||
{
|
||||
xIter(pDirty);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
206
original/Community.CsharpSqlite/src/pcache_h.cs
Normal file
206
original/Community.CsharpSqlite/src/pcache_h.cs
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
using Pgno = System.UInt32;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2008 August 05
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This header file defines the interface that the sqlite page cache
|
||||
** subsystem.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2010-08-23 18:52:01 42537b60566f288167f1b5864a5435986838e3a3
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
|
||||
#if !_PCACHE_H_
|
||||
|
||||
//typedef struct PgHdr PgHdr;
|
||||
//typedef struct PCache PCache;
|
||||
|
||||
/*
|
||||
** Every page in the cache is controlled by an instance of the following
|
||||
** structure.
|
||||
*/
|
||||
|
||||
public class PgHdr
|
||||
{
|
||||
public byte[] pData; /* Content of this page */
|
||||
public MemPage pExtra; /* Extra content */
|
||||
public PgHdr pDirty; /* Transient list of dirty pages */
|
||||
public Pgno pgno; /* The page number for this page */
|
||||
public Pager pPager; /* The pager to which this page belongs */
|
||||
#if SQLITE_CHECK_PAGES || (SQLITE_DEBUG)
|
||||
public int pageHash; /* Hash of page content */
|
||||
#endif
|
||||
public int flags; /* PGHDR flags defined below */
|
||||
/**********************************************************************
|
||||
** Elements above are public. All that follows is private to pcache.c
|
||||
** and should not be accessed by other modules.
|
||||
*/
|
||||
public int nRef; /* Number of users of this page */
|
||||
public PCache pCache; /* Cache that owns this page */
|
||||
public bool CacheAllocated; /* True, if allocated from cache */
|
||||
|
||||
public PgHdr pDirtyNext; /* Next element in list of dirty pages */
|
||||
public PgHdr pDirtyPrev; /* Previous element in list of dirty pages */
|
||||
public PgHdr1 pPgHdr1; /* Cache page header this this page */
|
||||
|
||||
public static implicit operator bool(PgHdr b)
|
||||
{
|
||||
return (b != null);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
sqlite3_free(ref this.pData);
|
||||
this.pData = null;
|
||||
this.pExtra = null;
|
||||
this.pDirty = null;
|
||||
this.pgno = 0;
|
||||
this.pPager = null;
|
||||
#if SQLITE_CHECK_PAGES
|
||||
this.pageHash=0;
|
||||
#endif
|
||||
this.flags = 0;
|
||||
this.nRef = 0;
|
||||
this.CacheAllocated = false;
|
||||
this.pCache = null;
|
||||
this.pDirtyNext = null;
|
||||
this.pDirtyPrev = null;
|
||||
this.pPgHdr1 = null;
|
||||
}
|
||||
};
|
||||
|
||||
/* Bit values for PgHdr.flags */
|
||||
//#define PGHDR_DIRTY 0x002 /* Page has changed */
|
||||
//#define PGHDR_NEED_SYNC 0x004 /* Fsync the rollback journal before
|
||||
// ** writing this page to the database */
|
||||
//#define PGHDR_NEED_READ 0x008 /* Content is unread */
|
||||
//#define PGHDR_REUSE_UNLIKELY 0x010 /* A hint that reuse is unlikely */
|
||||
//#define PGHDR_DONT_WRITE 0x020 /* Do not write content to disk */
|
||||
|
||||
private const int PGHDR_DIRTY = 0x002; /* Page has changed */
|
||||
private const int PGHDR_NEED_SYNC = 0x004;/* Fsync the rollback journal before
|
||||
** writing this page to the database */
|
||||
private const int PGHDR_NEED_READ = 0x008;/* Content is unread */
|
||||
private const int PGHDR_REUSE_UNLIKELY = 0x010;/* A hint that reuse is unlikely */
|
||||
private const int PGHDR_DONT_WRITE = 0x020;/* Do not write content to disk */
|
||||
|
||||
/* Initialize and shutdown the page cache subsystem */
|
||||
//int sqlite3PcacheInitialize(void);
|
||||
//void sqlite3PcacheShutdown(void);
|
||||
|
||||
/* Page cache buffer management:
|
||||
** These routines implement SQLITE_CONFIG_PAGECACHE.
|
||||
*/
|
||||
//void sqlite3PCacheBufferSetup(void *, int sz, int n);
|
||||
|
||||
/* Create a new pager cache.
|
||||
** Under memory stress, invoke xStress to try to make pages clean.
|
||||
** Only clean and unpinned pages can be reclaimed.
|
||||
*/
|
||||
//void sqlite3PcacheOpen(
|
||||
// int szPage, /* Size of every page */
|
||||
// int szExtra, /* Extra space associated with each page */
|
||||
// int bPurgeable, /* True if pages are on backing store */
|
||||
// int (*xStress)(void*, PgHdr*), /* Call to try to make pages clean */
|
||||
// void pStress, /* Argument to xStress */
|
||||
// PCache pToInit /* Preallocated space for the PCache */
|
||||
//);
|
||||
|
||||
/* Modify the page-size after the cache has been created. */
|
||||
//void sqlite3PcacheSetPageSize(PCache *, int);
|
||||
|
||||
/* Return the size in bytes of a PCache object. Used to preallocate
|
||||
** storage space.
|
||||
*/
|
||||
//int sqlite3PcacheSize(void);
|
||||
|
||||
/* One release per successful fetch. Page is pinned until released.
|
||||
** Reference counted.
|
||||
*/
|
||||
//int sqlite3PcacheFetch(PCache*, Pgno, int createFlag, PgHdr**);
|
||||
//void sqlite3PcacheRelease(PgHdr*);
|
||||
|
||||
//void sqlite3PcacheDrop(PgHdr*); /* Remove page from cache */
|
||||
//void sqlite3PcacheMakeDirty(PgHdr*); /* Make sure page is marked dirty */
|
||||
//void sqlite3PcacheMakeClean(PgHdr*); /* Mark a single page as clean */
|
||||
//void sqlite3PcacheCleanAll(PCache*); /* Mark all dirty list pages as clean */
|
||||
|
||||
/* Change a page number. Used by incr-vacuum. */
|
||||
//void sqlite3PcacheMove(PgHdr*, Pgno);
|
||||
|
||||
/* Remove all pages with pgno>x. Reset the cache if x==0 */
|
||||
//void sqlite3PcacheTruncate(PCache*, Pgno x);
|
||||
|
||||
/* Get a list of all dirty pages in the cache, sorted by page number */
|
||||
//PgHdr *sqlite3PcacheDirtyList(PCache*);
|
||||
|
||||
/* Reset and close the cache object */
|
||||
//void sqlite3PcacheClose(PCache*);
|
||||
|
||||
/* Clear flags from pages of the page cache */
|
||||
//void sqlite3PcacheClearSyncFlags(PCache *);
|
||||
|
||||
/* Discard the contents of the cache */
|
||||
//void sqlite3PcacheClear(PCache*);
|
||||
|
||||
/* Return the total number of outstanding page references */
|
||||
//int sqlite3PcacheRefCount(PCache*);
|
||||
|
||||
/* Increment the reference count of an existing page */
|
||||
//void sqlite3PcacheRef(PgHdr*);
|
||||
|
||||
//int sqlite3PcachePageRefcount(PgHdr*);
|
||||
|
||||
/* Return the total number of pages stored in the cache */
|
||||
//int sqlite3PcachePagecount(PCache*);
|
||||
|
||||
#if SQLITE_CHECK_PAGES
|
||||
/* Iterate through all dirty pages currently stored in the cache. This
|
||||
** interface is only available if SQLITE_CHECK_PAGES is defined when the
|
||||
** library is built.
|
||||
*/
|
||||
|
||||
//void sqlite3PcacheIterateDirty(PCache pCache, void (*xIter)(PgHdr *));
|
||||
#endif
|
||||
|
||||
/* Set and get the suggested cache-size for the specified pager-cache.
|
||||
**
|
||||
** If no global maximum is configured, then the system attempts to limit
|
||||
** the total number of pages cached by purgeable pager-caches to the sum
|
||||
** of the suggested cache-sizes.
|
||||
*/
|
||||
//void sqlite3PcacheSetCachesize(PCache *, int);
|
||||
#if SQLITE_TEST
|
||||
//int sqlite3PcacheGetCachesize(PCache *);
|
||||
#endif
|
||||
|
||||
#if SQLITE_ENABLE_MEMORY_MANAGEMENT
|
||||
/* Try to return memory used by the pcache module to the main memory heap */
|
||||
//int sqlite3PcacheReleaseMemory(int);
|
||||
#endif
|
||||
|
||||
#if SQLITE_TEST
|
||||
//void sqlite3PcacheStats(int*,int*,int*,int*);
|
||||
#endif
|
||||
|
||||
//void sqlite3PCacheSetDefault(void);
|
||||
|
||||
#endif //* _PCACHE_H_ */
|
||||
}
|
||||
}
|
||||
1913
original/Community.CsharpSqlite/src/pragma_c.cs
Normal file
1913
original/Community.CsharpSqlite/src/pragma_c.cs
Normal file
File diff suppressed because it is too large
Load diff
1098
original/Community.CsharpSqlite/src/prepare_c.cs
Normal file
1098
original/Community.CsharpSqlite/src/prepare_c.cs
Normal file
File diff suppressed because it is too large
Load diff
1479
original/Community.CsharpSqlite/src/printf_c.cs
Normal file
1479
original/Community.CsharpSqlite/src/printf_c.cs
Normal file
File diff suppressed because it is too large
Load diff
206
original/Community.CsharpSqlite/src/random_c.cs
Normal file
206
original/Community.CsharpSqlite/src/random_c.cs
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
using System;
|
||||
using i64 = System.Int64;
|
||||
using u32 = System.UInt32;
|
||||
using u8 = System.Byte;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains code to implement a pseudo-random number
|
||||
** generator (PRNG) for SQLite.
|
||||
**
|
||||
** Random numbers are used by some of the database backends in order
|
||||
** to generate random integer keys for tables or random filenames.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2010-08-23 18:52:01 42537b60566f288167f1b5864a5435986838e3a3
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#include "sqliteInt.h"
|
||||
|
||||
/* All threads share a single random number generator.
|
||||
** This structure is the current state of the generator.
|
||||
*/
|
||||
|
||||
public class sqlite3PrngType
|
||||
{
|
||||
public bool isInit; /* True if initialized */
|
||||
public int i;
|
||||
public int j; /* State variables */
|
||||
public u8[] s = new u8[256]; /* State variables */
|
||||
|
||||
public sqlite3PrngType Copy()
|
||||
{
|
||||
sqlite3PrngType cp = (sqlite3PrngType)MemberwiseClone();
|
||||
cp.s = new u8[s.Length];
|
||||
Array.Copy(s, cp.s, s.Length);
|
||||
return cp;
|
||||
}
|
||||
}
|
||||
|
||||
public static sqlite3PrngType sqlite3Prng = new sqlite3PrngType();
|
||||
/*
|
||||
** Get a single 8-bit random value from the RC4 PRNG. The Mutex
|
||||
** must be held while executing this routine.
|
||||
**
|
||||
** Why not just use a library random generator like lrand48() for this?
|
||||
** Because the OP_NewRowid opcode in the VDBE depends on having a very
|
||||
** good source of random numbers. The lrand48() library function may
|
||||
** well be good enough. But maybe not. Or maybe lrand48() has some
|
||||
** subtle problems on some systems that could cause problems. It is hard
|
||||
** to know. To minimize the risk of problems due to bad lrand48()
|
||||
** implementations, SQLite uses this random number generator based
|
||||
** on RC4, which we know works very well.
|
||||
**
|
||||
** (Later): Actually, OP_NewRowid does not depend on a good source of
|
||||
** randomness any more. But we will leave this code in all the same.
|
||||
*/
|
||||
|
||||
private static u8 randomu8()
|
||||
{
|
||||
u8 t;
|
||||
|
||||
/* The "wsdPrng" macro will resolve to the pseudo-random number generator
|
||||
** state vector. If writable static data is unsupported on the target,
|
||||
** we have to locate the state vector at run-time. In the more common
|
||||
** case where writable static data is supported, wsdPrng can refer directly
|
||||
** to the "sqlite3Prng" state vector declared above.
|
||||
*/
|
||||
#if SQLITE_OMIT_WSD
|
||||
struct sqlite3PrngType *p = &GLOBAL(struct sqlite3PrngType, sqlite3Prng);
|
||||
//# define wsdPrng p[0]
|
||||
#else
|
||||
//# define wsdPrng sqlite3Prng
|
||||
sqlite3PrngType wsdPrng = sqlite3Prng;
|
||||
#endif
|
||||
|
||||
/* Initialize the state of the random number generator once,
|
||||
** the first time this routine is called. The seed value does
|
||||
** not need to contain a lot of randomness since we are not
|
||||
** trying to do secure encryption or anything like that...
|
||||
**
|
||||
** Nothing in this file or anywhere else in SQLite does any kind of
|
||||
** encryption. The RC4 algorithm is being used as a PRNG (pseudo-random
|
||||
** number generator) not as an encryption device.
|
||||
*/
|
||||
if (!wsdPrng.isInit)
|
||||
{
|
||||
int i;
|
||||
u8[] k = new u8[256];
|
||||
wsdPrng.j = 0;
|
||||
wsdPrng.i = 0;
|
||||
sqlite3OsRandomness(sqlite3_vfs_find(""), 256, k);
|
||||
for (i = 0; i < 255; i++)
|
||||
{
|
||||
wsdPrng.s[i] = (u8)i;
|
||||
}
|
||||
for (i = 0; i < 255; i++)
|
||||
{
|
||||
wsdPrng.j = (u8)(wsdPrng.j + wsdPrng.s[i] + k[i]);
|
||||
t = wsdPrng.s[wsdPrng.j];
|
||||
wsdPrng.s[wsdPrng.j] = wsdPrng.s[i];
|
||||
wsdPrng.s[i] = t;
|
||||
}
|
||||
wsdPrng.isInit = true;
|
||||
}
|
||||
|
||||
/* Generate and return single random u8
|
||||
*/
|
||||
wsdPrng.i++;
|
||||
t = wsdPrng.s[(u8)wsdPrng.i];
|
||||
wsdPrng.j = (u8)(wsdPrng.j + t);
|
||||
wsdPrng.s[(u8)wsdPrng.i] = wsdPrng.s[wsdPrng.j];
|
||||
wsdPrng.s[wsdPrng.j] = t;
|
||||
t += wsdPrng.s[(u8)wsdPrng.i];
|
||||
return wsdPrng.s[t];
|
||||
}
|
||||
|
||||
/*
|
||||
** Return N random u8s.
|
||||
*/
|
||||
|
||||
private static void sqlite3_randomness(int N, ref i64 pBuf)
|
||||
{
|
||||
//u8[] zBuf = new u8[N];
|
||||
pBuf = 0;
|
||||
#if SQLITE_THREADSAFE
|
||||
sqlite3_mutex mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PRNG);
|
||||
#endif
|
||||
sqlite3_mutex_enter(mutex);
|
||||
while (N-- > 0)
|
||||
{
|
||||
pBuf = (u32)((pBuf << 8) + randomu8());// zBuf[N] = randomu8();
|
||||
}
|
||||
sqlite3_mutex_leave(mutex);
|
||||
}
|
||||
|
||||
private static void sqlite3_randomness(byte[] pBuf, int Offset, int N)
|
||||
{
|
||||
i64 iBuf = System.DateTime.Now.Ticks;
|
||||
#if SQLITE_THREADSAFE
|
||||
sqlite3_mutex mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PRNG);
|
||||
#endif
|
||||
sqlite3_mutex_enter(mutex);
|
||||
while (N-- > 0)
|
||||
{
|
||||
iBuf = (u32)((iBuf << 8) + randomu8());// zBuf[N] = randomu8();
|
||||
pBuf[Offset++] = (byte)iBuf;
|
||||
}
|
||||
sqlite3_mutex_leave(mutex);
|
||||
}
|
||||
|
||||
#if !SQLITE_OMIT_BUILTIN_TEST
|
||||
/*
|
||||
** For testing purposes, we sometimes want to preserve the state of
|
||||
** PRNG and restore the PRNG to its saved state at a later time, or
|
||||
** to reset the PRNG to its initial state. These routines accomplish
|
||||
** those tasks.
|
||||
**
|
||||
** The sqlite3_test_control() interface calls these routines to
|
||||
** control the PRNG.
|
||||
*/
|
||||
private static sqlite3PrngType sqlite3SavedPrng = null;
|
||||
|
||||
private static void sqlite3PrngSaveState()
|
||||
{
|
||||
sqlite3SavedPrng = sqlite3Prng.Copy();
|
||||
// memcpy(
|
||||
// &GLOBAL(struct sqlite3PrngType, sqlite3SavedPrng),
|
||||
// &GLOBAL(struct sqlite3PrngType, sqlite3Prng),
|
||||
// sizeof(sqlite3Prng)
|
||||
//);
|
||||
}
|
||||
|
||||
private static void sqlite3PrngRestoreState()
|
||||
{
|
||||
sqlite3Prng = sqlite3SavedPrng.Copy();
|
||||
//memcpy(
|
||||
// &GLOBAL(struct sqlite3PrngType, sqlite3Prng),
|
||||
// &GLOBAL(struct sqlite3PrngType, sqlite3SavedPrng),
|
||||
// sizeof(sqlite3Prng)
|
||||
//);
|
||||
}
|
||||
|
||||
private static void sqlite3PrngResetState()
|
||||
{
|
||||
sqlite3Prng.isInit = false;// GLOBAL(struct sqlite3PrngType, sqlite3Prng).isInit = 0;
|
||||
}
|
||||
|
||||
#endif //* SQLITE_OMIT_BUILTIN_TEST */
|
||||
}
|
||||
}
|
||||
1426
original/Community.CsharpSqlite/src/resolve_c.cs
Normal file
1426
original/Community.CsharpSqlite/src/resolve_c.cs
Normal file
File diff suppressed because it is too large
Load diff
529
original/Community.CsharpSqlite/src/rowset_c.cs
Normal file
529
original/Community.CsharpSqlite/src/rowset_c.cs
Normal file
|
|
@ -0,0 +1,529 @@
|
|||
using System.Diagnostics;
|
||||
using i64 = System.Int64;
|
||||
using u32 = System.UInt32;
|
||||
using u8 = System.Byte;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
using sqlite3_int64 = System.Int64;
|
||||
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2008 December 3
|
||||
**
|
||||
** 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 module implements an object we call a "RowSet".
|
||||
**
|
||||
** The RowSet object is a collection of rowids. Rowids
|
||||
** are inserted into the RowSet in an arbitrary order. Inserts
|
||||
** can be intermixed with tests to see if a given rowid has been
|
||||
** previously inserted into the RowSet.
|
||||
**
|
||||
** After all inserts are finished, it is possible to extract the
|
||||
** elements of the RowSet in sorted order. Once this extraction
|
||||
** process has started, no new elements may be inserted.
|
||||
**
|
||||
** Hence, the primitive operations for a RowSet are:
|
||||
**
|
||||
** CREATE
|
||||
** INSERT
|
||||
** TEST
|
||||
** SMALLEST
|
||||
** DESTROY
|
||||
**
|
||||
** The CREATE and DESTROY primitives are the constructor and destructor,
|
||||
** obviously. The INSERT primitive adds a new element to the RowSet.
|
||||
** TEST checks to see if an element is already in the RowSet. SMALLEST
|
||||
** extracts the least value from the RowSet.
|
||||
**
|
||||
** The INSERT primitive might allocate additional memory. Memory is
|
||||
** allocated in chunks so most INSERTs do no allocation. There is an
|
||||
** upper bound on the size of allocated memory. No memory is freed
|
||||
** until DESTROY.
|
||||
**
|
||||
** The TEST primitive includes a "batch" number. The TEST primitive
|
||||
** will only see elements that were inserted before the last change
|
||||
** in the batch number. In other words, if an INSERT occurs between
|
||||
** two TESTs where the TESTs have the same batch nubmer, then the
|
||||
** value added by the INSERT will not be visible to the second TEST.
|
||||
** The initial batch number is zero, so if the very first TEST contains
|
||||
** a non-zero batch number, it will see all prior INSERTs.
|
||||
**
|
||||
** No INSERTs may occurs after a SMALLEST. An assertion will fail if
|
||||
** that is attempted.
|
||||
**
|
||||
** The cost of an INSERT is roughly constant. (Sometime new memory
|
||||
** has to be allocated on an INSERT.) The cost of a TEST with a new
|
||||
** batch number is O(NlogN) where N is the number of elements in the RowSet.
|
||||
** The cost of a TEST using the same batch number is O(logN). The cost
|
||||
** of the first SMALLEST is O(NlogN). Second and subsequent SMALLEST
|
||||
** primitives are constant time. The cost of DESTROY is O(N).
|
||||
**
|
||||
** There is an added cost of O(N) when switching between TEST and
|
||||
** SMALLEST primitives.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2010-08-23 18:52:01 42537b60566f288167f1b5864a5435986838e3a3
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** Target size for allocation chunks.
|
||||
*/
|
||||
|
||||
//#define ROWSET_ALLOCATION_SIZE 1024
|
||||
private const int ROWSET_ALLOCATION_SIZE = 1024;
|
||||
|
||||
/*
|
||||
** The number of rowset entries per allocation chunk.
|
||||
*/
|
||||
|
||||
//#define ROWSET_ENTRY_PER_CHUNK \
|
||||
// ((ROWSET_ALLOCATION_SIZE-8)/sizeof(struct RowSetEntry))
|
||||
private const int ROWSET_ENTRY_PER_CHUNK = 63;
|
||||
|
||||
/*
|
||||
** Each entry in a RowSet is an instance of the following object.
|
||||
*/
|
||||
|
||||
public class RowSetEntry
|
||||
{
|
||||
public i64 v; /* ROWID value for this entry */
|
||||
public RowSetEntry pRight; /* Right subtree (larger entries) or list */
|
||||
public RowSetEntry pLeft; /* Left subtree (smaller entries) */
|
||||
};
|
||||
|
||||
/*
|
||||
** Index entries are allocated in large chunks (instances of the
|
||||
** following structure) to reduce memory allocation overhead. The
|
||||
** chunks are kept on a linked list so that they can be deallocated
|
||||
** when the RowSet is destroyed.
|
||||
*/
|
||||
|
||||
public class RowSetChunk
|
||||
{
|
||||
public RowSetChunk pNextChunk; /* Next chunk on list of them all */
|
||||
public RowSetEntry[] aEntry = new RowSetEntry[ROWSET_ENTRY_PER_CHUNK]; /* Allocated entries */
|
||||
};
|
||||
|
||||
/*
|
||||
** A RowSet in an instance of the following structure.
|
||||
**
|
||||
** A typedef of this structure if found in sqliteInt.h.
|
||||
*/
|
||||
|
||||
public class RowSet
|
||||
{
|
||||
public RowSetChunk pChunk; /* List of all chunk allocations */
|
||||
public sqlite3 db; /* The database connection */
|
||||
public RowSetEntry pEntry; /* /* List of entries using pRight */
|
||||
public RowSetEntry pLast; /* Last entry on the pEntry list */
|
||||
public RowSetEntry[] pFresh; /* Source of new entry objects */
|
||||
public RowSetEntry pTree; /* Binary tree of entries */
|
||||
public int nFresh; /* Number of objects on pFresh */
|
||||
public bool isSorted; /* True if pEntry is sorted */
|
||||
public u8 iBatch; /* Current insert batch */
|
||||
|
||||
public RowSet(sqlite3 db, int N)
|
||||
{
|
||||
this.pChunk = null;
|
||||
this.db = db;
|
||||
this.pEntry = null;
|
||||
this.pLast = null;
|
||||
this.pFresh = new RowSetEntry[N];
|
||||
this.pTree = null;
|
||||
this.nFresh = N;
|
||||
this.isSorted = true;
|
||||
this.iBatch = 0;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
** Turn bulk memory into a RowSet object. N bytes of memory
|
||||
** are available at pSpace. The db pointer is used as a memory context
|
||||
** for any subsequent allocations that need to occur.
|
||||
** Return a pointer to the new RowSet object.
|
||||
**
|
||||
** It must be the case that N is sufficient to make a Rowset. If not
|
||||
** an assertion fault occurs.
|
||||
**
|
||||
** If N is larger than the minimum, use the surplus as an initial
|
||||
** allocation of entries available to be filled.
|
||||
*/
|
||||
|
||||
private static RowSet sqlite3RowSetInit(sqlite3 db, object pSpace, u32 N)
|
||||
{
|
||||
RowSet p = new RowSet(db, (int)N);
|
||||
//Debug.Assert(N >= ROUND8(sizeof(*p)) );
|
||||
// p = pSpace;
|
||||
// p.pChunk = 0;
|
||||
// p.db = db;
|
||||
// p.pEntry = 0;
|
||||
// p.pLast = 0;
|
||||
// p.pTree = 0;
|
||||
// p.pFresh =(struct RowSetEntry*)(ROUND8(sizeof(*p)) + (char*)p);
|
||||
// p.nFresh = (u16)((N - ROUND8(sizeof(*p)))/sizeof(struct RowSetEntry));
|
||||
// p.isSorted = 1;
|
||||
// p.iBatch = 0;
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Deallocate all chunks from a RowSet. This frees all memory that
|
||||
** the RowSet has allocated over its lifetime. This routine is
|
||||
** the destructor for the RowSet.
|
||||
*/
|
||||
|
||||
private static void sqlite3RowSetClear(RowSet p)
|
||||
{
|
||||
RowSetChunk pChunk, pNextChunk;
|
||||
for (pChunk = p.pChunk; pChunk != null; pChunk = pNextChunk)
|
||||
{
|
||||
pNextChunk = pChunk.pNextChunk;
|
||||
sqlite3DbFree(p.db, ref pChunk);
|
||||
}
|
||||
p.pChunk = null;
|
||||
p.nFresh = 0;
|
||||
p.pEntry = null;
|
||||
p.pLast = null;
|
||||
p.pTree = null;
|
||||
p.isSorted = true;
|
||||
}
|
||||
|
||||
/*
|
||||
** Insert a new value into a RowSet.
|
||||
**
|
||||
** The mallocFailed flag of the database connection is set if a
|
||||
** memory allocation fails.
|
||||
*/
|
||||
|
||||
private static void sqlite3RowSetInsert(RowSet p, i64 rowid)
|
||||
{
|
||||
RowSetEntry pEntry; /* The new entry */
|
||||
RowSetEntry pLast; /* The last prior entry */
|
||||
Debug.Assert(p != null);
|
||||
if (p.nFresh == 0)
|
||||
{
|
||||
RowSetChunk pNew;
|
||||
pNew = new RowSetChunk();//sqlite3DbMallocRaw(p.db, sizeof(*pNew));
|
||||
if (pNew == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
pNew.pNextChunk = p.pChunk;
|
||||
p.pChunk = pNew;
|
||||
p.pFresh = pNew.aEntry;
|
||||
p.nFresh = ROWSET_ENTRY_PER_CHUNK;
|
||||
}
|
||||
p.pFresh[p.pFresh.Length - p.nFresh] = new RowSetEntry();
|
||||
pEntry = p.pFresh[p.pFresh.Length - p.nFresh];
|
||||
p.nFresh--;
|
||||
pEntry.v = rowid;
|
||||
pEntry.pRight = null;
|
||||
pLast = p.pLast;
|
||||
if (pLast != null)
|
||||
{
|
||||
if (p.isSorted && rowid <= pLast.v)
|
||||
{
|
||||
p.isSorted = false;
|
||||
}
|
||||
pLast.pRight = pEntry;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Assert(p.pEntry == null);/* Fires if INSERT after SMALLEST */
|
||||
p.pEntry = pEntry;
|
||||
}
|
||||
p.pLast = pEntry;
|
||||
}
|
||||
|
||||
/*
|
||||
** Merge two lists of RowSetEntry objects. Remove duplicates.
|
||||
**
|
||||
** The input lists are connected via pRight pointers and are
|
||||
** assumed to each already be in sorted order.
|
||||
*/
|
||||
|
||||
private static RowSetEntry rowSetMerge(
|
||||
RowSetEntry pA, /* First sorted list to be merged */
|
||||
RowSetEntry pB /* Second sorted list to be merged */
|
||||
)
|
||||
{
|
||||
RowSetEntry head = new RowSetEntry();
|
||||
RowSetEntry pTail;
|
||||
|
||||
pTail = head;
|
||||
while (pA != null && pB != null)
|
||||
{
|
||||
Debug.Assert(pA.pRight == null || pA.v <= pA.pRight.v);
|
||||
Debug.Assert(pB.pRight == null || pB.v <= pB.pRight.v);
|
||||
if (pA.v < pB.v)
|
||||
{
|
||||
pTail.pRight = pA;
|
||||
pA = pA.pRight;
|
||||
pTail = pTail.pRight;
|
||||
}
|
||||
else if (pB.v < pA.v)
|
||||
{
|
||||
pTail.pRight = pB;
|
||||
pB = pB.pRight;
|
||||
pTail = pTail.pRight;
|
||||
}
|
||||
else
|
||||
{
|
||||
pA = pA.pRight;
|
||||
}
|
||||
}
|
||||
if (pA != null)
|
||||
{
|
||||
Debug.Assert(pA.pRight == null || pA.v <= pA.pRight.v);
|
||||
pTail.pRight = pA;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Assert(pB == null || pB.pRight == null || pB.v <= pB.pRight.v);
|
||||
pTail.pRight = pB;
|
||||
}
|
||||
return head.pRight;
|
||||
}
|
||||
|
||||
/*
|
||||
** Sort all elements on the pEntry list of the RowSet into ascending order.
|
||||
*/
|
||||
|
||||
private static void rowSetSort(RowSet p)
|
||||
{
|
||||
u32 i;
|
||||
RowSetEntry pEntry;
|
||||
RowSetEntry[] aBucket = new RowSetEntry[40];
|
||||
|
||||
Debug.Assert(p.isSorted == false);
|
||||
//memset(aBucket, 0, sizeof(aBucket));
|
||||
while (p.pEntry != null)
|
||||
{
|
||||
pEntry = p.pEntry;
|
||||
p.pEntry = pEntry.pRight;
|
||||
pEntry.pRight = null;
|
||||
for (i = 0; aBucket[i] != null; i++)
|
||||
{
|
||||
pEntry = rowSetMerge(aBucket[i], pEntry);
|
||||
aBucket[i] = null;
|
||||
}
|
||||
aBucket[i] = pEntry;
|
||||
}
|
||||
pEntry = null;
|
||||
for (i = 0; i < aBucket.Length; i++)//sizeof(aBucket)/sizeof(aBucket[0])
|
||||
{
|
||||
pEntry = rowSetMerge(pEntry, aBucket[i]);
|
||||
}
|
||||
p.pEntry = pEntry;
|
||||
p.pLast = null;
|
||||
p.isSorted = true;
|
||||
}
|
||||
|
||||
/*
|
||||
** The input, pIn, is a binary tree (or subtree) of RowSetEntry objects.
|
||||
** Convert this tree into a linked list connected by the pRight pointers
|
||||
** and return pointers to the first and last elements of the new list.
|
||||
*/
|
||||
|
||||
private static void rowSetTreeToList(
|
||||
RowSetEntry pIn, /* Root of the input tree */
|
||||
ref RowSetEntry ppFirst, /* Write head of the output list here */
|
||||
ref RowSetEntry ppLast /* Write tail of the output list here */
|
||||
)
|
||||
{
|
||||
Debug.Assert(pIn != null);
|
||||
if (pIn.pLeft != null)
|
||||
{
|
||||
RowSetEntry p = new RowSetEntry();
|
||||
rowSetTreeToList(pIn.pLeft, ref ppFirst, ref p);
|
||||
p.pRight = pIn;
|
||||
}
|
||||
else
|
||||
{
|
||||
ppFirst = pIn;
|
||||
}
|
||||
if (pIn.pRight != null)
|
||||
{
|
||||
rowSetTreeToList(pIn.pRight, ref pIn.pRight, ref ppLast);
|
||||
}
|
||||
else
|
||||
{
|
||||
ppLast = pIn;
|
||||
}
|
||||
Debug.Assert((ppLast).pRight == null);
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert a sorted list of elements (connected by pRight) into a binary
|
||||
** tree with depth of iDepth. A depth of 1 means the tree contains a single
|
||||
** node taken from the head of *ppList. A depth of 2 means a tree with
|
||||
** three nodes. And so forth.
|
||||
**
|
||||
** Use as many entries from the input list as required and update the
|
||||
** *ppList to point to the unused elements of the list. If the input
|
||||
** list contains too few elements, then construct an incomplete tree
|
||||
** and leave *ppList set to NULL.
|
||||
**
|
||||
** Return a pointer to the root of the constructed binary tree.
|
||||
*/
|
||||
|
||||
private static RowSetEntry rowSetNDeepTree(
|
||||
ref RowSetEntry ppList,
|
||||
int iDepth
|
||||
)
|
||||
{
|
||||
RowSetEntry p; /* Root of the new tree */
|
||||
RowSetEntry pLeft; /* Left subtree */
|
||||
if (ppList == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (iDepth == 1)
|
||||
{
|
||||
p = ppList;
|
||||
ppList = p.pRight;
|
||||
p.pLeft = p.pRight = null;
|
||||
return p;
|
||||
}
|
||||
pLeft = rowSetNDeepTree(ref ppList, iDepth - 1);
|
||||
p = ppList;
|
||||
if (p == null)
|
||||
{
|
||||
return pLeft;
|
||||
}
|
||||
p.pLeft = pLeft;
|
||||
ppList = p.pRight;
|
||||
p.pRight = rowSetNDeepTree(ref ppList, iDepth - 1);
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert a sorted list of elements into a binary tree. Make the tree
|
||||
** as deep as it needs to be in order to contain the entire list.
|
||||
*/
|
||||
|
||||
private static RowSetEntry rowSetListToTree(RowSetEntry pList)
|
||||
{
|
||||
int iDepth; /* Depth of the tree so far */
|
||||
RowSetEntry p; /* Current tree root */
|
||||
RowSetEntry pLeft; /* Left subtree */
|
||||
|
||||
Debug.Assert(pList != null);
|
||||
p = pList;
|
||||
pList = p.pRight;
|
||||
p.pLeft = p.pRight = null;
|
||||
for (iDepth = 1; pList != null; iDepth++)
|
||||
{
|
||||
pLeft = p;
|
||||
p = pList;
|
||||
pList = p.pRight;
|
||||
p.pLeft = pLeft;
|
||||
p.pRight = rowSetNDeepTree(ref pList, iDepth);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert the list in p.pEntry into a sorted list if it is not
|
||||
** sorted already. If there is a binary tree on p.pTree, then
|
||||
** convert it into a list too and merge it into the p.pEntry list.
|
||||
*/
|
||||
|
||||
private static void rowSetToList(RowSet p)
|
||||
{
|
||||
if (!p.isSorted)
|
||||
{
|
||||
rowSetSort(p);
|
||||
}
|
||||
if (p.pTree != null)
|
||||
{
|
||||
RowSetEntry pHead = new RowSetEntry();
|
||||
RowSetEntry pTail = new RowSetEntry();
|
||||
rowSetTreeToList(p.pTree, ref pHead, ref pTail);
|
||||
p.pTree = null;
|
||||
p.pEntry = rowSetMerge(p.pEntry, pHead);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Extract the smallest element from the RowSet.
|
||||
** Write the element into *pRowid. Return 1 on success. Return
|
||||
** 0 if the RowSet is already empty.
|
||||
**
|
||||
** After this routine has been called, the sqlite3RowSetInsert()
|
||||
** routine may not be called again.
|
||||
*/
|
||||
|
||||
private static int sqlite3RowSetNext(RowSet p, ref i64 pRowid)
|
||||
{
|
||||
rowSetToList(p);
|
||||
if (p.pEntry != null)
|
||||
{
|
||||
pRowid = p.pEntry.v;
|
||||
p.pEntry = p.pEntry.pRight;
|
||||
if (p.pEntry == null)
|
||||
{
|
||||
sqlite3RowSetClear(p);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Check to see if element iRowid was inserted into the the rowset as
|
||||
** part of any insert batch prior to iBatch. Return 1 or 0.
|
||||
*/
|
||||
|
||||
private static int sqlite3RowSetTest(RowSet pRowSet, u8 iBatch, sqlite3_int64 iRowid)
|
||||
{
|
||||
RowSetEntry p;
|
||||
if (iBatch != pRowSet.iBatch)
|
||||
{
|
||||
if (pRowSet.pEntry != null)
|
||||
{
|
||||
rowSetToList(pRowSet);
|
||||
pRowSet.pTree = rowSetListToTree(pRowSet.pEntry);
|
||||
pRowSet.pEntry = null;
|
||||
pRowSet.pLast = null;
|
||||
}
|
||||
pRowSet.iBatch = iBatch;
|
||||
}
|
||||
p = pRowSet.pTree;
|
||||
while (p != null)
|
||||
{
|
||||
if (p.v < iRowid)
|
||||
{
|
||||
p = p.pRight;
|
||||
}
|
||||
else if (p.v > iRowid)
|
||||
{
|
||||
p = p.pLeft;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
5223
original/Community.CsharpSqlite/src/select_c.cs
Normal file
5223
original/Community.CsharpSqlite/src/select_c.cs
Normal file
File diff suppressed because it is too large
Load diff
7532
original/Community.CsharpSqlite/src/sqlite3_h.cs
Normal file
7532
original/Community.CsharpSqlite/src/sqlite3_h.cs
Normal file
File diff suppressed because it is too large
Load diff
4826
original/Community.CsharpSqlite/src/sqliteInt_h.cs
Normal file
4826
original/Community.CsharpSqlite/src/sqliteInt_h.cs
Normal file
File diff suppressed because it is too large
Load diff
225
original/Community.CsharpSqlite/src/sqliteLimit_h.cs
Normal file
225
original/Community.CsharpSqlite/src/sqliteLimit_h.cs
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2007 May 7
|
||||
**
|
||||
** 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 defines various limits of what SQLite can process.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2011-05-19 13:26:54 ed1da510a239ea767a01dc332b667119fa3c908e
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
/*
|
||||
** The maximum length of a TEXT or BLOB in bytes. This also
|
||||
** limits the size of a row in a table or index.
|
||||
**
|
||||
** The hard limit is the ability of a 32-bit signed integer
|
||||
** to count the size: 2^31-1 or 2147483647.
|
||||
*/
|
||||
#if !SQLITE_MAX_LENGTH
|
||||
private const int SQLITE_MAX_LENGTH = 1000000000;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This is the maximum number of
|
||||
**
|
||||
** * Columns in a table
|
||||
** * Columns in an index
|
||||
** * Columns in a view
|
||||
** * Terms in the SET clause of an UPDATE statement
|
||||
** * Terms in the result set of a SELECT statement
|
||||
** * Terms in the GROUP BY or ORDER BY clauses of a SELECT statement.
|
||||
** * Terms in the VALUES clause of an INSERT statement
|
||||
**
|
||||
** The hard upper limit here is 32676. Most database people will
|
||||
** tell you that in a well-normalized database, you usually should
|
||||
** not have more than a dozen or so columns in any table. And if
|
||||
** that is the case, there is no point in having more than a few
|
||||
** dozen values in any of the other situations described above.
|
||||
*/
|
||||
#if !SQLITE_MAX_COLUMN
|
||||
private const int SQLITE_MAX_COLUMN = 2000;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The maximum length of a single SQL statement in bytes.
|
||||
**
|
||||
** It used to be the case that setting this value to zero would
|
||||
** turn the limit off. That is no longer true. It is not possible
|
||||
** to turn this limit off.
|
||||
*/
|
||||
#if !SQLITE_MAX_SQL_LENGTH
|
||||
private const int SQLITE_MAX_SQL_LENGTH = 1000000000;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The maximum depth of an expression tree. This is limited to
|
||||
** some extent by SQLITE_MAX_SQL_LENGTH. But sometime you might
|
||||
** want to place more severe limits on the complexity of an
|
||||
** expression.
|
||||
**
|
||||
** A value of 0 used to mean that the limit was not enforced.
|
||||
** But that is no longer true. The limit is now strictly enforced
|
||||
** at all times.
|
||||
*/
|
||||
#if !SQLITE_MAX_EXPR_DEPTH
|
||||
private const int SQLITE_MAX_EXPR_DEPTH = 1000;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The maximum number of terms in a compound SELECT statement.
|
||||
** The code generator for compound SELECT statements does one
|
||||
** level of recursion for each term. A stack overflow can result
|
||||
** if the number of terms is too large. In practice, most SQL
|
||||
** never has more than 3 or 4 terms. Use a value of 0 to disable
|
||||
** any limit on the number of terms in a compount SELECT.
|
||||
*/
|
||||
#if !SQLITE_MAX_COMPOUND_SELECT
|
||||
private const int SQLITE_MAX_COMPOUND_SELECT = 250;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The maximum number of opcodes in a VDBE program.
|
||||
** Not currently enforced.
|
||||
*/
|
||||
#if !SQLITE_MAX_VDBE_OP
|
||||
private const int SQLITE_MAX_VDBE_OP = 25000;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The maximum number of arguments to an SQL function.
|
||||
*/
|
||||
#if !SQLITE_MAX_FUNCTION_ARG
|
||||
private const int SQLITE_MAX_FUNCTION_ARG = 127;//# define SQLITE_MAX_FUNCTION_ARG 127
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The maximum number of in-memory pages to use for the main database
|
||||
** table and for temporary tables. The SQLITE_DEFAULT_CACHE_SIZE
|
||||
*/
|
||||
#if !SQLITE_DEFAULT_CACHE_SIZE
|
||||
private const int SQLITE_DEFAULT_CACHE_SIZE = 2000;
|
||||
#endif
|
||||
#if !SQLITE_DEFAULT_TEMP_CACHE_SIZE
|
||||
private const int SQLITE_DEFAULT_TEMP_CACHE_SIZE = 500;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The default number of frames to accumulate in the log file before
|
||||
** checkpointing the database in WAL mode.
|
||||
*/
|
||||
#if !SQLITE_DEFAULT_WAL_AUTOCHECKPOINT
|
||||
private const int SQLITE_DEFAULT_WAL_AUTOCHECKPOINT = 1000;
|
||||
//# define SQLITE_DEFAULT_WAL_AUTOCHECKPOINT 1000
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The maximum number of attached databases. This must be between 0
|
||||
** and 62. The upper bound on 62 is because a 64-bit integer bitmap
|
||||
** is used internally to track attached databases.
|
||||
*/
|
||||
#if !SQLITE_MAX_ATTACHED
|
||||
private const int SQLITE_MAX_ATTACHED = 10;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The maximum value of a ?nnn wildcard that the parser will accept.
|
||||
*/
|
||||
#if !SQLITE_MAX_VARIABLE_NUMBER
|
||||
private const int SQLITE_MAX_VARIABLE_NUMBER = 999;
|
||||
#endif
|
||||
|
||||
/* Maximum page size. The upper bound on this value is 65536. This a limit
|
||||
** imposed by the use of 16-bit offsets within each page.
|
||||
**
|
||||
**
|
||||
** Earlier versions of SQLite allowed the user to change this value at
|
||||
** compile time. This is no longer permitted, on the grounds that it creates
|
||||
** a library that is technically incompatible with an SQLite library
|
||||
** compiled with a different limit. If a process operating on a database
|
||||
** with a page-size of 65536 bytes crashes, then an instance of SQLite
|
||||
** compiled with the default page-size limit will not be able to rollback
|
||||
** the aborted transaction. This could lead to database corruption.
|
||||
*/
|
||||
|
||||
//#if SQLITE_MAX_PAGE_SIZE
|
||||
//# undef SQLITE_MAX_PAGE_SIZE
|
||||
//#endif
|
||||
//#define SQLITE_MAX_PAGE_SIZE 65536
|
||||
private const int SQLITE_MAX_PAGE_SIZE = 65535;
|
||||
|
||||
/*
|
||||
** The default size of a database page.
|
||||
*/
|
||||
#if !SQLITE_DEFAULT_PAGE_SIZE
|
||||
private const int SQLITE_DEFAULT_PAGE_SIZE = 1024;
|
||||
#endif
|
||||
#if SQLITE_DEFAULT_PAGE_SIZE //SQLITE_DEFAULT_PAGE_SIZE>SQLITE_MAX_PAGE_SIZE
|
||||
//# undef SQLITE_DEFAULT_PAGE_SIZE
|
||||
const int SQLITE_DEFAULT_PAGE_SIZE SQLITE_MAX_PAGE_SIZE
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Ordinarily, if no value is explicitly provided, SQLite creates databases
|
||||
** with page size SQLITE_DEFAULT_PAGE_SIZE. However, based on certain
|
||||
** device characteristics (sector-size and atomic write() support),
|
||||
** SQLite may choose a larger value. This constant is the maximum value
|
||||
** SQLite will choose on its own.
|
||||
*/
|
||||
#if !SQLITE_MAX_DEFAULT_PAGE_SIZE
|
||||
private const int SQLITE_MAX_DEFAULT_PAGE_SIZE = 8192;
|
||||
#endif
|
||||
#if SQLITE_MAX_DEFAULT_PAGE_SIZE //SQLITE_MAX_DEFAULT_PAGE_SIZE>SQLITE_MAX_PAGE_SIZE
|
||||
//# undef SQLITE_MAX_DEFAULT_PAGE_SIZE
|
||||
const int SQLITE_MAX_DEFAULT_PAGE_SIZE SQLITE_MAX_PAGE_SIZE
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Maximum number of pages in one database file.
|
||||
**
|
||||
** This is really just the default value for the max_page_count pragma.
|
||||
** This value can be lowered (or raised) at run-time using that the
|
||||
** max_page_count macro.
|
||||
*/
|
||||
#if !SQLITE_MAX_PAGE_COUNT
|
||||
private const int SQLITE_MAX_PAGE_COUNT = 1073741823;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Maximum length (in bytes) of the pattern in a LIKE or GLOB
|
||||
** operator.
|
||||
*/
|
||||
|
||||
//#if !SQLITE_MAX_LIKE_PATTERN_LENGTH
|
||||
private const int SQLITE_MAX_LIKE_PATTERN_LENGTH = 50000;
|
||||
|
||||
//#endif
|
||||
|
||||
/*
|
||||
** Maximum depth of recursion for triggers.
|
||||
**
|
||||
** A value of 1 means that a trigger program will not be able to itself
|
||||
** fire any triggers. A value of 0 means that no trigger programs at all
|
||||
** may be executed.
|
||||
*/
|
||||
#if !SQLITE_MAX_TRIGGER_DEPTH
|
||||
private const int SQLITE_MAX_TRIGGER_DEPTH = 101; // # define SQLITE_MAX_TRIGGER_DEPTH 1000
|
||||
#else
|
||||
const int SQLITE_MAX_TRIGGER_DEPTH=1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
284
original/Community.CsharpSqlite/src/status_c.cs
Normal file
284
original/Community.CsharpSqlite/src/status_c.cs
Normal file
|
|
@ -0,0 +1,284 @@
|
|||
using System.Diagnostics;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2008 June 18
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This module implements the sqlite3_status() interface and related
|
||||
** functionality.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2011-05-19 13:26:54 ed1da510a239ea767a01dc332b667119fa3c908e
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#include "sqliteInt.h"
|
||||
//#include "vdbeInt.h"
|
||||
|
||||
/*
|
||||
** Variables in which to record status information.
|
||||
*/
|
||||
|
||||
//typedef struct sqlite3StatType sqlite3StatType;
|
||||
public class sqlite3StatType
|
||||
{
|
||||
public int[] nowValue = new int[10]; /* Current value */
|
||||
public int[] mxValue = new int[10]; /* Maximum value */
|
||||
}
|
||||
|
||||
public static sqlite3StatType sqlite3Stat = new sqlite3StatType();
|
||||
|
||||
/* The "wsdStat" macro will resolve to the status information
|
||||
** state vector. If writable static data is unsupported on the target,
|
||||
** we have to locate the state vector at run-time. In the more common
|
||||
** case where writable static data is supported, wsdStat can refer directly
|
||||
** to the "sqlite3Stat" state vector declared above.
|
||||
*/
|
||||
#if SQLITE_OMIT_WSD
|
||||
//# define wsdStatInit sqlite3StatType *x = &GLOBAL(sqlite3StatType,sqlite3Stat)
|
||||
//# define wsdStat x[0]
|
||||
#else
|
||||
|
||||
//# define wsdStatInit
|
||||
private static void wsdStatInit()
|
||||
{
|
||||
}
|
||||
|
||||
//# define wsdStat sqlite3Stat
|
||||
private static sqlite3StatType wsdStat = sqlite3Stat;
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Return the current value of a status parameter.
|
||||
*/
|
||||
|
||||
private static int sqlite3StatusValue(int op)
|
||||
{
|
||||
wsdStatInit();
|
||||
Debug.Assert(op >= 0 && op < ArraySize(wsdStat.nowValue));
|
||||
return wsdStat.nowValue[op];
|
||||
}
|
||||
|
||||
/*
|
||||
** Add N to the value of a status record. It is assumed that the
|
||||
** caller holds appropriate locks.
|
||||
*/
|
||||
|
||||
private static void sqlite3StatusAdd(int op, int N)
|
||||
{
|
||||
wsdStatInit();
|
||||
Debug.Assert(op >= 0 && op < ArraySize(wsdStat.nowValue));
|
||||
wsdStat.nowValue[op] += N;
|
||||
if (wsdStat.nowValue[op] > wsdStat.mxValue[op])
|
||||
{
|
||||
wsdStat.mxValue[op] = wsdStat.nowValue[op];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the value of a status to X.
|
||||
*/
|
||||
|
||||
private static void sqlite3StatusSet(int op, int X)
|
||||
{
|
||||
wsdStatInit();
|
||||
Debug.Assert(op >= 0 && op < ArraySize(wsdStat.nowValue));
|
||||
wsdStat.nowValue[op] = X;
|
||||
if (wsdStat.nowValue[op] > wsdStat.mxValue[op])
|
||||
{
|
||||
wsdStat.mxValue[op] = wsdStat.nowValue[op];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Query status information.
|
||||
**
|
||||
** This implementation assumes that reading or writing an aligned
|
||||
** 32-bit integer is an atomic operation. If that assumption is not true,
|
||||
** then this routine is not threadsafe.
|
||||
*/
|
||||
|
||||
static public int sqlite3_status(int op, ref int pCurrent, ref int pHighwater, int resetFlag)
|
||||
{
|
||||
wsdStatInit();
|
||||
if (op < 0 || op >= ArraySize(wsdStat.nowValue))
|
||||
{
|
||||
return SQLITE_MISUSE_BKPT();
|
||||
}
|
||||
pCurrent = wsdStat.nowValue[op];
|
||||
pHighwater = wsdStat.mxValue[op];
|
||||
if (resetFlag != 0)
|
||||
{
|
||||
wsdStat.mxValue[op] = wsdStat.nowValue[op];
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Query status information for a single database connection
|
||||
*/
|
||||
|
||||
static public int sqlite3_db_status(
|
||||
sqlite3 db, /* The database connection whose status is desired */
|
||||
int op, /* Status verb */
|
||||
ref int pCurrent, /* Write current value here */
|
||||
ref int pHighwater, /* Write high-water mark here */
|
||||
int resetFlag /* Reset high-water mark if true */
|
||||
)
|
||||
{
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
sqlite3_mutex_enter(db.mutex);
|
||||
switch (op)
|
||||
{
|
||||
case SQLITE_DBSTATUS_LOOKASIDE_USED:
|
||||
{
|
||||
pCurrent = db.lookaside.nOut;
|
||||
pHighwater = db.lookaside.mxOut;
|
||||
if (resetFlag != 0)
|
||||
{
|
||||
db.lookaside.mxOut = db.lookaside.nOut;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SQLITE_DBSTATUS_LOOKASIDE_HIT:
|
||||
case SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE:
|
||||
case SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL:
|
||||
{
|
||||
testcase(op == SQLITE_DBSTATUS_LOOKASIDE_HIT);
|
||||
testcase(op == SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE);
|
||||
testcase(op == SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL);
|
||||
Debug.Assert((op - SQLITE_DBSTATUS_LOOKASIDE_HIT) >= 0);
|
||||
Debug.Assert((op - SQLITE_DBSTATUS_LOOKASIDE_HIT) < 3);
|
||||
pCurrent = 0;
|
||||
pHighwater = db.lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT];
|
||||
if (resetFlag != 0)
|
||||
{
|
||||
db.lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return an approximation for the amount of memory currently used
|
||||
** by all pagers associated with the given database connection. The
|
||||
** highwater mark is meaningless and is returned as zero.
|
||||
*/
|
||||
case SQLITE_DBSTATUS_CACHE_USED:
|
||||
{
|
||||
int totalUsed = 0;
|
||||
int i;
|
||||
sqlite3BtreeEnterAll(db);
|
||||
for (i = 0; i < db.nDb; i++)
|
||||
{
|
||||
Btree pBt = db.aDb[i].pBt;
|
||||
if (pBt != null)
|
||||
{
|
||||
Pager pPager = sqlite3BtreePager(pBt);
|
||||
totalUsed += sqlite3PagerMemUsed(pPager);
|
||||
}
|
||||
}
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
pCurrent = totalUsed;
|
||||
pHighwater = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** *pCurrent gets an accurate estimate of the amount of memory used
|
||||
** to store the schema for all databases (main, temp, and any ATTACHed
|
||||
** databases. *pHighwater is set to zero.
|
||||
*/
|
||||
case SQLITE_DBSTATUS_SCHEMA_USED:
|
||||
{
|
||||
int i; /* Used to iterate through schemas */
|
||||
int nByte = 0; /* Used to accumulate return value */
|
||||
|
||||
sqlite3BtreeEnterAll(db);
|
||||
//db.pnBytesFreed = nByte;
|
||||
for (i = 0; i < db.nDb; i++)
|
||||
{
|
||||
Schema pSchema = db.aDb[i].pSchema;
|
||||
if (ALWAYS(pSchema != null))
|
||||
{
|
||||
HashElem p;
|
||||
|
||||
//nByte += (int)(sqlite3GlobalConfig.m.xRoundup(sizeof(HashElem)) * (
|
||||
// pSchema.tblHash.count
|
||||
// + pSchema.trigHash.count
|
||||
// + pSchema.idxHash.count
|
||||
// + pSchema.fkeyHash.count
|
||||
//));
|
||||
//nByte += (int)sqlite3MallocSize( pSchema.tblHash.ht );
|
||||
//nByte += (int)sqlite3MallocSize( pSchema.trigHash.ht );
|
||||
//nByte += (int)sqlite3MallocSize( pSchema.idxHash.ht );
|
||||
//nByte += (int)sqlite3MallocSize( pSchema.fkeyHash.ht );
|
||||
|
||||
for (p = sqliteHashFirst(pSchema.trigHash); p != null; p = sqliteHashNext(p))
|
||||
{
|
||||
Trigger t = (Trigger)sqliteHashData(p);
|
||||
sqlite3DeleteTrigger(db, ref t);
|
||||
}
|
||||
for (p = sqliteHashFirst(pSchema.tblHash); p != null; p = sqliteHashNext(p))
|
||||
{
|
||||
Table t = (Table)sqliteHashData(p);
|
||||
sqlite3DeleteTable(db, ref t);
|
||||
}
|
||||
}
|
||||
}
|
||||
db.pnBytesFreed = 0;
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
|
||||
pHighwater = 0;
|
||||
pCurrent = nByte;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** *pCurrent gets an accurate estimate of the amount of memory used
|
||||
** to store all prepared statements.
|
||||
** *pHighwater is set to zero.
|
||||
*/
|
||||
case SQLITE_DBSTATUS_STMT_USED:
|
||||
{
|
||||
Vdbe pVdbe; /* Used to iterate through VMs */
|
||||
int nByte = 0; /* Used to accumulate return value */
|
||||
|
||||
//db.pnBytesFreed = nByte;
|
||||
for (pVdbe = db.pVdbe; pVdbe != null; pVdbe = pVdbe.pNext)
|
||||
{
|
||||
sqlite3VdbeDeleteObject(db, ref pVdbe);
|
||||
}
|
||||
db.pnBytesFreed = 0;
|
||||
|
||||
pHighwater = 0;
|
||||
pCurrent = nByte;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
rc = SQLITE_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
sqlite3_mutex_leave(db.mutex);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
216
original/Community.CsharpSqlite/src/table_c.cs
Normal file
216
original/Community.CsharpSqlite/src/table_c.cs
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains the sqlite3_get_table() and //sqlite3_free_table()
|
||||
** interface routines. These are just wrappers around the main
|
||||
** interface routine of sqlite3_exec().
|
||||
**
|
||||
** These routines are in a separate files so that they will not be linked
|
||||
** if they are not used.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2010-08-23 18:52:01 42537b60566f288167f1b5864a5435986838e3a3
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#include "sqliteInt.h"
|
||||
//#include <stdlib.h>
|
||||
//#include <string.h>
|
||||
|
||||
#if !SQLITE_OMIT_GET_TABLE
|
||||
|
||||
/*
|
||||
** This structure is used to pass data from sqlite3_get_table() through
|
||||
** to the callback function is uses to build the result.
|
||||
*/
|
||||
class TabResult {
|
||||
public string[] azResult;
|
||||
public string zErrMsg;
|
||||
public int nResult;
|
||||
public int nAlloc;
|
||||
public int nRow;
|
||||
public int nColumn;
|
||||
public int nData;
|
||||
public int rc;
|
||||
};
|
||||
|
||||
/*
|
||||
** This routine is called once for each row in the result table. Its job
|
||||
** is to fill in the TabResult structure appropriately, allocating new
|
||||
** memory as necessary.
|
||||
*/
|
||||
static public int sqlite3_get_table_cb( object pArg, i64 nCol, object Oargv, object Ocolv )
|
||||
{
|
||||
string[] argv = (string[])Oargv;
|
||||
string[]colv = (string[])Ocolv;
|
||||
TabResult p = (TabResult)pArg;
|
||||
int need;
|
||||
int i;
|
||||
string z;
|
||||
|
||||
/* Make sure there is enough space in p.azResult to hold everything
|
||||
** we need to remember from this invocation of the callback.
|
||||
*/
|
||||
if( p.nRow==0 && argv!=null ){
|
||||
need = (int)nCol*2;
|
||||
}else{
|
||||
need = (int)nCol;
|
||||
}
|
||||
if( p.nData + need >= p.nAlloc ){
|
||||
string[] azNew;
|
||||
p.nAlloc = p.nAlloc*2 + need + 1;
|
||||
azNew = new string[p.nAlloc];//sqlite3_realloc( p.azResult, sizeof(char*)*p.nAlloc );
|
||||
if( azNew==null ) goto malloc_failed;
|
||||
p.azResult = azNew;
|
||||
}
|
||||
|
||||
/* If this is the first row, then generate an extra row containing
|
||||
** the names of all columns.
|
||||
*/
|
||||
if( p.nRow==0 ){
|
||||
p.nColumn = (int)nCol;
|
||||
for(i=0; i<nCol; i++){
|
||||
z = sqlite3_mprintf("%s", colv[i]);
|
||||
if( z==null ) goto malloc_failed;
|
||||
p.azResult[p.nData++ -1] = z;
|
||||
}
|
||||
}else if( p.nColumn!=nCol ){
|
||||
//sqlite3_free(ref p.zErrMsg);
|
||||
p.zErrMsg = sqlite3_mprintf(
|
||||
"sqlite3_get_table() called with two or more incompatible queries"
|
||||
);
|
||||
p.rc = SQLITE_ERROR;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Copy over the row data
|
||||
*/
|
||||
if( argv!=null ){
|
||||
for(i=0; i<nCol; i++){
|
||||
if( argv[i]==null ){
|
||||
z = null;
|
||||
}else{
|
||||
int n = sqlite3Strlen30(argv[i])+1;
|
||||
//z = sqlite3_malloc( n );
|
||||
//if( z==0 ) goto malloc_failed;
|
||||
z= argv[i];//memcpy(z, argv[i], n);
|
||||
}
|
||||
p.azResult[p.nData++ -1] = z;
|
||||
}
|
||||
p.nRow++;
|
||||
}
|
||||
return 0;
|
||||
|
||||
malloc_failed:
|
||||
p.rc = SQLITE_NOMEM;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Query the database. But instead of invoking a callback for each row,
|
||||
** malloc() for space to hold the result and return the entire results
|
||||
** at the conclusion of the call.
|
||||
**
|
||||
** The result that is written to ***pazResult is held in memory obtained
|
||||
** from malloc(). But the caller cannot free this memory directly.
|
||||
** Instead, the entire table should be passed to //sqlite3_free_table() when
|
||||
** the calling procedure is finished using it.
|
||||
*/
|
||||
static public int sqlite3_get_table(
|
||||
sqlite3 db, /* The database on which the SQL executes */
|
||||
string zSql, /* The SQL to be executed */
|
||||
ref string[] pazResult, /* Write the result table here */
|
||||
ref int pnRow, /* Write the number of rows in the result here */
|
||||
ref int pnColumn, /* Write the number of columns of result here */
|
||||
ref string pzErrMsg /* Write error messages here */
|
||||
){
|
||||
int rc;
|
||||
TabResult res = new TabResult();
|
||||
|
||||
pazResult = null;
|
||||
pnColumn = 0;
|
||||
pnRow = 0;
|
||||
pzErrMsg = "";
|
||||
res.zErrMsg = "";
|
||||
res.nResult = 0;
|
||||
res.nRow = 0;
|
||||
res.nColumn = 0;
|
||||
res.nData = 1;
|
||||
res.nAlloc = 20;
|
||||
res.rc = SQLITE_OK;
|
||||
res.azResult = new string[res.nAlloc];// sqlite3_malloc( sizeof( char* ) * res.nAlloc );
|
||||
if( res.azResult==null ){
|
||||
db.errCode = SQLITE_NOMEM;
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
res.azResult[0] = null;
|
||||
rc = sqlite3_exec(db, zSql, (dxCallback) sqlite3_get_table_cb, res, ref pzErrMsg);
|
||||
//Debug.Assert( sizeof(res.azResult[0])>= sizeof(res.nData) );
|
||||
//res.azResult = SQLITE_INT_TO_PTR( res.nData );
|
||||
if( (rc&0xff)==SQLITE_ABORT ){
|
||||
//sqlite3_free_table(ref res.azResult[1] );
|
||||
if( res.zErrMsg !=""){
|
||||
if( pzErrMsg !=null ){
|
||||
//sqlite3_free(ref pzErrMsg);
|
||||
pzErrMsg = sqlite3_mprintf("%s",res.zErrMsg);
|
||||
}
|
||||
//sqlite3_free(ref res.zErrMsg);
|
||||
}
|
||||
db.errCode = res.rc; /* Assume 32-bit assignment is atomic */
|
||||
return res.rc;
|
||||
}
|
||||
//sqlite3_free(ref res.zErrMsg);
|
||||
if( rc!=SQLITE_OK ){
|
||||
//sqlite3_free_table(ref res.azResult[1]);
|
||||
return rc;
|
||||
}
|
||||
if( res.nAlloc>res.nData ){
|
||||
string[] azNew;
|
||||
Array.Resize(ref res.azResult, res.nData-1);//sqlite3_realloc( res.azResult, sizeof(char*)*(res.nData+1) );
|
||||
//if( azNew==null ){
|
||||
// //sqlite3_free_table(ref res.azResult[1]);
|
||||
// db.errCode = SQLITE_NOMEM;
|
||||
// return SQLITE_NOMEM;
|
||||
//}
|
||||
res.nAlloc = res.nData+1;
|
||||
//res.azResult = azNew;
|
||||
}
|
||||
pazResult = res.azResult;
|
||||
pnColumn = res.nColumn;
|
||||
pnRow = res.nRow;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine frees the space the sqlite3_get_table() malloced.
|
||||
*/
|
||||
static void //sqlite3_free_table(
|
||||
ref string azResult /* Result returned from from sqlite3_get_table() */
|
||||
){
|
||||
if( azResult !=null){
|
||||
int i, n;
|
||||
//azResult--;
|
||||
//Debug.Assert( azResult!=0 );
|
||||
//n = SQLITE_PTR_TO_INT(azResult[0]);
|
||||
//for(i=1; i<n; i++){ if( azResult[i] ) //sqlite3_free(azResult[i]); }
|
||||
//sqlite3_free(ref azResult);
|
||||
}
|
||||
}
|
||||
|
||||
#endif //* SQLITE_OMIT_GET_TABLE */
|
||||
}
|
||||
}
|
||||
711
original/Community.CsharpSqlite/src/tokenize_c.cs
Normal file
711
original/Community.CsharpSqlite/src/tokenize_c.cs
Normal file
|
|
@ -0,0 +1,711 @@
|
|||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** An tokenizer for SQL
|
||||
**
|
||||
** This file contains C code that splits an SQL input string up into
|
||||
** individual tokens and sends those tokens one-by-one over to the
|
||||
** parser for analysis.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#include "sqliteInt.h"
|
||||
//#include <stdlib.h>
|
||||
|
||||
/*
|
||||
** The charMap() macro maps alphabetic characters into their
|
||||
** lower-case ASCII equivalent. On ASCII machines, this is just
|
||||
** an upper-to-lower case map. On EBCDIC machines we also need
|
||||
** to adjust the encoding. Only alphabetic characters and underscores
|
||||
** need to be translated.
|
||||
*/
|
||||
#if SQLITE_ASCII
|
||||
//# define charMap(X) sqlite3UpperToLower[(unsigned char)X]
|
||||
#endif
|
||||
//#if SQLITE_EBCDIC
|
||||
//# define charMap(X) ebcdicToAscii[(unsigned char)X]
|
||||
//const unsigned char ebcdicToAscii[] = {
|
||||
///* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
||||
// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */
|
||||
// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */
|
||||
// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */
|
||||
// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3x */
|
||||
// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4x */
|
||||
// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5x */
|
||||
// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, /* 6x */
|
||||
// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7x */
|
||||
// 0, 97, 98, 99,100,101,102,103,104,105, 0, 0, 0, 0, 0, 0, /* 8x */
|
||||
// 0,106,107,108,109,110,111,112,113,114, 0, 0, 0, 0, 0, 0, /* 9x */
|
||||
// 0, 0,115,116,117,118,119,120,121,122, 0, 0, 0, 0, 0, 0, /* Ax */
|
||||
// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Bx */
|
||||
// 0, 97, 98, 99,100,101,102,103,104,105, 0, 0, 0, 0, 0, 0, /* Cx */
|
||||
// 0,106,107,108,109,110,111,112,113,114, 0, 0, 0, 0, 0, 0, /* Dx */
|
||||
// 0, 0,115,116,117,118,119,120,121,122, 0, 0, 0, 0, 0, 0, /* Ex */
|
||||
// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Fx */
|
||||
//};
|
||||
//#endif
|
||||
|
||||
/*
|
||||
** The sqlite3KeywordCode function looks up an identifier to determine if
|
||||
** it is a keyword. If it is a keyword, the token code of that keyword is
|
||||
** returned. If the input is not a keyword, TK_ID is returned.
|
||||
**
|
||||
** The implementation of this routine was generated by a program,
|
||||
** mkkeywordhash.h, located in the tool subdirectory of the distribution.
|
||||
** The output of the mkkeywordhash.c program is written into a file
|
||||
** named keywordhash.h and then included into this source file by
|
||||
** the #include below.
|
||||
*/
|
||||
//#include "keywordhash.h"
|
||||
|
||||
/*
|
||||
** If X is a character that can be used in an identifier then
|
||||
** IdChar(X) will be true. Otherwise it is false.
|
||||
**
|
||||
** For ASCII, any character with the high-order bit set is
|
||||
** allowed in an identifier. For 7-bit characters,
|
||||
** sqlite3IsIdChar[X] must be 1.
|
||||
**
|
||||
** For EBCDIC, the rules are more complex but have the same
|
||||
** end result.
|
||||
**
|
||||
** Ticket #1066. the SQL standard does not allow '$' in the
|
||||
** middle of identfiers. But many SQL implementations do.
|
||||
** SQLite will allow '$' in identifiers for compatibility.
|
||||
** But the feature is undocumented.
|
||||
*/
|
||||
#if SQLITE_ASCII
|
||||
//#define IdChar(C) ((sqlite3CtypeMap[(unsigned char)C]&0x46)!=0)
|
||||
#endif
|
||||
//#if SQLITE_EBCDIC
|
||||
//const char sqlite3IsEbcdicIdChar[] = {
|
||||
///* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
|
||||
// 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 4x */
|
||||
// 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, /* 5x */
|
||||
// 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, /* 6x */
|
||||
// 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, /* 7x */
|
||||
// 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, /* 8x */
|
||||
// 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, /* 9x */
|
||||
// 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, /* Ax */
|
||||
// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Bx */
|
||||
// 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* Cx */
|
||||
// 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* Dx */
|
||||
// 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* Ex */
|
||||
// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, /* Fx */
|
||||
//};
|
||||
//#define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40]))
|
||||
//#endif
|
||||
|
||||
/*
|
||||
** Return the length of the token that begins at z[iOffset + 0].
|
||||
** Store the token type in *tokenType before returning.
|
||||
*/
|
||||
|
||||
private static int sqlite3GetToken(string z, int iOffset, ref int tokenType)
|
||||
{
|
||||
int i;
|
||||
byte c = 0;
|
||||
switch (z[iOffset + 0])
|
||||
{
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\n':
|
||||
case '\f':
|
||||
case '\r':
|
||||
{
|
||||
testcase(z[iOffset + 0] == ' ');
|
||||
testcase(z[iOffset + 0] == '\t');
|
||||
testcase(z[iOffset + 0] == '\n');
|
||||
testcase(z[iOffset + 0] == '\f');
|
||||
testcase(z[iOffset + 0] == '\r');
|
||||
for (i = 1; z.Length > iOffset + i && sqlite3Isspace(z[iOffset + i]); i++)
|
||||
{
|
||||
}
|
||||
tokenType = TK_SPACE;
|
||||
return i;
|
||||
}
|
||||
case '-':
|
||||
{
|
||||
if (z.Length > iOffset + 1 && z[iOffset + 1] == '-')
|
||||
{
|
||||
/* IMP: R-15891-05542 -- syntax diagram for comments */
|
||||
for (i = 2; z.Length > iOffset + i && (c = (byte)z[iOffset + i]) != 0 && c != '\n'; i++)
|
||||
{
|
||||
}
|
||||
tokenType = TK_SPACE; /* IMP: R-22934-25134 */
|
||||
return i;
|
||||
}
|
||||
tokenType = TK_MINUS;
|
||||
return 1;
|
||||
}
|
||||
case '(':
|
||||
{
|
||||
tokenType = TK_LP;
|
||||
return 1;
|
||||
}
|
||||
case ')':
|
||||
{
|
||||
tokenType = TK_RP;
|
||||
return 1;
|
||||
}
|
||||
case ';':
|
||||
{
|
||||
tokenType = TK_SEMI;
|
||||
return 1;
|
||||
}
|
||||
case '+':
|
||||
{
|
||||
tokenType = TK_PLUS;
|
||||
return 1;
|
||||
}
|
||||
case '*':
|
||||
{
|
||||
tokenType = TK_STAR;
|
||||
return 1;
|
||||
}
|
||||
case '/':
|
||||
{
|
||||
if (iOffset + 2 >= z.Length || z[iOffset + 1] != '*')
|
||||
{
|
||||
tokenType = TK_SLASH;
|
||||
return 1;
|
||||
}
|
||||
/* IMP: R-15891-05542 -- syntax diagram for comments */
|
||||
for (i = 3, c = (byte)z[iOffset + 2]; iOffset + i < z.Length && (c != '*' || (z[iOffset + i] != '/') && (c != 0)); i++)
|
||||
{
|
||||
c = (byte)z[iOffset + i];
|
||||
}
|
||||
if (iOffset + i == z.Length)
|
||||
c = 0;
|
||||
if (c != 0)
|
||||
i++;
|
||||
tokenType = TK_SPACE; /* IMP: R-22934-25134 */
|
||||
return i;
|
||||
}
|
||||
case '%':
|
||||
{
|
||||
tokenType = TK_REM;
|
||||
return 1;
|
||||
}
|
||||
case '=':
|
||||
{
|
||||
tokenType = TK_EQ;
|
||||
return 1 + (z[iOffset + 1] == '=' ? 1 : 0);
|
||||
}
|
||||
case '<':
|
||||
{
|
||||
if ((c = (byte)z[iOffset + 1]) == '=')
|
||||
{
|
||||
tokenType = TK_LE;
|
||||
return 2;
|
||||
}
|
||||
else if (c == '>')
|
||||
{
|
||||
tokenType = TK_NE;
|
||||
return 2;
|
||||
}
|
||||
else if (c == '<')
|
||||
{
|
||||
tokenType = TK_LSHIFT;
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
tokenType = TK_LT;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
case '>':
|
||||
{
|
||||
if (z.Length > iOffset + 1 && (c = (byte)z[iOffset + 1]) == '=')
|
||||
{
|
||||
tokenType = TK_GE;
|
||||
return 2;
|
||||
}
|
||||
else if (c == '>')
|
||||
{
|
||||
tokenType = TK_RSHIFT;
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
tokenType = TK_GT;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
case '!':
|
||||
{
|
||||
if (z[iOffset + 1] != '=')
|
||||
{
|
||||
tokenType = TK_ILLEGAL;
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
tokenType = TK_NE;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
case '|':
|
||||
{
|
||||
if (z[iOffset + 1] != '|')
|
||||
{
|
||||
tokenType = TK_BITOR;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
tokenType = TK_CONCAT;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
case ',':
|
||||
{
|
||||
tokenType = TK_COMMA;
|
||||
return 1;
|
||||
}
|
||||
case '&':
|
||||
{
|
||||
tokenType = TK_BITAND;
|
||||
return 1;
|
||||
}
|
||||
case '~':
|
||||
{
|
||||
tokenType = TK_BITNOT;
|
||||
return 1;
|
||||
}
|
||||
case '`':
|
||||
case '\'':
|
||||
case '"':
|
||||
{
|
||||
int delim = z[iOffset + 0];
|
||||
testcase(delim == '`');
|
||||
testcase(delim == '\'');
|
||||
testcase(delim == '"');
|
||||
for (i = 1; (iOffset + i) < z.Length && (c = (byte)z[iOffset + i]) != 0; i++)
|
||||
{
|
||||
if (c == delim)
|
||||
{
|
||||
if (z.Length > iOffset + i + 1 && z[iOffset + i + 1] == delim)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((iOffset + i == z.Length && c != delim) || z[iOffset + i] != delim)
|
||||
{
|
||||
tokenType = TK_ILLEGAL;
|
||||
return i + 1;
|
||||
}
|
||||
if (c == '\'')
|
||||
{
|
||||
tokenType = TK_STRING;
|
||||
return i + 1;
|
||||
}
|
||||
else if (c != 0)
|
||||
{
|
||||
tokenType = TK_ID;
|
||||
return i + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
tokenType = TK_ILLEGAL;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
case '.':
|
||||
{
|
||||
#if !SQLITE_OMIT_FLOATING_POINT
|
||||
if (!sqlite3Isdigit(z[iOffset + 1]))
|
||||
#endif
|
||||
{
|
||||
tokenType = TK_DOT;
|
||||
return 1;
|
||||
}
|
||||
/* If the next character is a digit, this is a floating point
|
||||
** number that begins with ".". Fall thru into the next case */
|
||||
goto case '0';
|
||||
}
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
{
|
||||
testcase(z[iOffset] == '0');
|
||||
testcase(z[iOffset] == '1');
|
||||
testcase(z[iOffset] == '2');
|
||||
testcase(z[iOffset] == '3');
|
||||
testcase(z[iOffset] == '4');
|
||||
testcase(z[iOffset] == '5');
|
||||
testcase(z[iOffset] == '6');
|
||||
testcase(z[iOffset] == '7');
|
||||
testcase(z[iOffset] == '8');
|
||||
testcase(z[iOffset] == '9');
|
||||
tokenType = TK_INTEGER;
|
||||
for (i = 0; z.Length > iOffset + i && sqlite3Isdigit(z[iOffset + i]); i++)
|
||||
{
|
||||
}
|
||||
#if !SQLITE_OMIT_FLOATING_POINT
|
||||
if (z.Length > iOffset + i && z[iOffset + i] == '.')
|
||||
{
|
||||
i++;
|
||||
while (z.Length > iOffset + i && sqlite3Isdigit(z[iOffset + i]))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
tokenType = TK_FLOAT;
|
||||
}
|
||||
if (z.Length > iOffset + i + 1 && (z[iOffset + i] == 'e' || z[iOffset + i] == 'E') &&
|
||||
(sqlite3Isdigit(z[iOffset + i + 1])
|
||||
|| z.Length > iOffset + i + 2 && ((z[iOffset + i + 1] == '+' || z[iOffset + i + 1] == '-') && sqlite3Isdigit(z[iOffset + i + 2]))
|
||||
)
|
||||
)
|
||||
{
|
||||
i += 2;
|
||||
while (z.Length > iOffset + i && sqlite3Isdigit(z[iOffset + i]))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
tokenType = TK_FLOAT;
|
||||
}
|
||||
#endif
|
||||
while (iOffset + i < z.Length && IdChar((byte)z[iOffset + i]))
|
||||
{
|
||||
tokenType = TK_ILLEGAL;
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
case '[':
|
||||
{
|
||||
for (i = 1, c = (byte)z[iOffset + 0]; c != ']' && (iOffset + i) < z.Length && (c = (byte)z[iOffset + i]) != 0; i++)
|
||||
{
|
||||
}
|
||||
tokenType = c == ']' ? TK_ID : TK_ILLEGAL;
|
||||
return i;
|
||||
}
|
||||
case '?':
|
||||
{
|
||||
tokenType = TK_VARIABLE;
|
||||
for (i = 1; z.Length > iOffset + i && sqlite3Isdigit(z[iOffset + i]); i++)
|
||||
{
|
||||
}
|
||||
return i;
|
||||
}
|
||||
case '#':
|
||||
{
|
||||
for (i = 1; z.Length > iOffset + i && sqlite3Isdigit(z[iOffset + i]); i++)
|
||||
{
|
||||
}
|
||||
if (i > 1)
|
||||
{
|
||||
/* Parameters of the form #NNN (where NNN is a number) are used
|
||||
** internally by sqlite3NestedParse. */
|
||||
tokenType = TK_REGISTER;
|
||||
return i;
|
||||
}
|
||||
/* Fall through into the next case if the '#' is not followed by
|
||||
** a digit. Try to match #AAAA where AAAA is a parameter name. */
|
||||
goto case ':';
|
||||
}
|
||||
#if !SQLITE_OMIT_TCL_VARIABLE
|
||||
case '$':
|
||||
#endif
|
||||
case '@': /* For compatibility with MS SQL Server */
|
||||
case ':':
|
||||
{
|
||||
int n = 0;
|
||||
testcase(z[iOffset + 0] == '$');
|
||||
testcase(z[iOffset + 0] == '@');
|
||||
testcase(z[iOffset + 0] == ':');
|
||||
tokenType = TK_VARIABLE;
|
||||
for (i = 1; z.Length > iOffset + i && (c = (byte)z[iOffset + i]) != 0; i++)
|
||||
{
|
||||
if (IdChar(c))
|
||||
{
|
||||
n++;
|
||||
#if !SQLITE_OMIT_TCL_VARIABLE
|
||||
}
|
||||
else if (c == '(' && n > 0)
|
||||
{
|
||||
do
|
||||
{
|
||||
i++;
|
||||
} while ((iOffset + i) < z.Length && (c = (byte)z[iOffset + i]) != 0 && !sqlite3Isspace(c) && c != ')');
|
||||
if (c == ')')
|
||||
{
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
tokenType = TK_ILLEGAL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (c == ':' && z[iOffset + i + 1] == ':')
|
||||
{
|
||||
i++;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (n == 0)
|
||||
tokenType = TK_ILLEGAL;
|
||||
return i;
|
||||
}
|
||||
#if !SQLITE_OMIT_BLOB_LITERAL
|
||||
case 'x':
|
||||
case 'X':
|
||||
{
|
||||
testcase(z[iOffset + 0] == 'x');
|
||||
testcase(z[iOffset + 0] == 'X');
|
||||
if (z.Length > iOffset + 1 && z[iOffset + 1] == '\'')
|
||||
{
|
||||
tokenType = TK_BLOB;
|
||||
for (i = 2; z.Length > iOffset + i && sqlite3Isxdigit(z[iOffset + i]); i++)
|
||||
{
|
||||
}
|
||||
if (iOffset + i == z.Length || z[iOffset + i] != '\'' || i % 2 != 0)
|
||||
{
|
||||
tokenType = TK_ILLEGAL;
|
||||
while (z.Length > iOffset + i && z[iOffset + i] != '\'')
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (z.Length > iOffset + i)
|
||||
i++;
|
||||
return i;
|
||||
}
|
||||
goto default;
|
||||
/* Otherwise fall through to the next case */
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
{
|
||||
if (!IdChar((byte)z[iOffset]))
|
||||
{
|
||||
break;
|
||||
}
|
||||
for (i = 1; i < z.Length - iOffset && IdChar((byte)z[iOffset + i]); i++)
|
||||
{
|
||||
}
|
||||
tokenType = keywordCode(z, iOffset, i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
tokenType = TK_ILLEGAL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Run the parser on the given SQL string. The parser structure is
|
||||
** passed in. An SQLITE_ status code is returned. If an error occurs
|
||||
** then an and attempt is made to write an error message into
|
||||
** memory obtained from sqlite3_malloc() and to make pzErrMsg point to that
|
||||
** error message.
|
||||
*/
|
||||
|
||||
private static int sqlite3RunParser(Parse pParse, string zSql, ref string pzErrMsg)
|
||||
{
|
||||
int nErr = 0; /* Number of errors encountered */
|
||||
int i; /* Loop counter */
|
||||
yyParser pEngine; /* The LEMON-generated LALR(1) parser */
|
||||
int tokenType = 0; /* type of the next token */
|
||||
int lastTokenParsed = -1; /* type of the previous token */
|
||||
byte enableLookaside; /* Saved value of db->lookaside.bEnabled */
|
||||
sqlite3 db = pParse.db; /* The database connection */
|
||||
int mxSqlLen; /* Max length of an SQL string */
|
||||
|
||||
mxSqlLen = db.aLimit[SQLITE_LIMIT_SQL_LENGTH];
|
||||
if (db.activeVdbeCnt == 0)
|
||||
{
|
||||
db.u1.isInterrupted = false;
|
||||
}
|
||||
pParse.rc = SQLITE_OK;
|
||||
pParse.zTail = new StringBuilder(zSql);
|
||||
i = 0;
|
||||
Debug.Assert(pzErrMsg != null);
|
||||
pEngine = sqlite3ParserAlloc();//sqlite3ParserAlloc((void*(*)(size_t))sqlite3Malloc);
|
||||
//if ( pEngine == null )
|
||||
//{
|
||||
// db.mallocFailed = 1;
|
||||
// return SQLITE_NOMEM;
|
||||
//}
|
||||
Debug.Assert(pParse.pNewTable == null);
|
||||
Debug.Assert(pParse.pNewTrigger == null);
|
||||
Debug.Assert(pParse.nVar == 0);
|
||||
Debug.Assert(pParse.nzVar == 0);
|
||||
Debug.Assert(pParse.azVar == null);
|
||||
enableLookaside = db.lookaside.bEnabled;
|
||||
if (db.lookaside.pStart != 0)
|
||||
db.lookaside.bEnabled = 1;
|
||||
while ( /* 0 == db.mallocFailed && */ i < zSql.Length)
|
||||
{
|
||||
Debug.Assert(i >= 0);
|
||||
//pParse->sLastToken.z = &zSql[i];
|
||||
pParse.sLastToken.n = sqlite3GetToken(zSql, i, ref tokenType);
|
||||
pParse.sLastToken.z = zSql.Substring(i);
|
||||
i += pParse.sLastToken.n;
|
||||
if (i > mxSqlLen)
|
||||
{
|
||||
pParse.rc = SQLITE_TOOBIG;
|
||||
break;
|
||||
}
|
||||
switch (tokenType)
|
||||
{
|
||||
case TK_SPACE:
|
||||
{
|
||||
if (db.u1.isInterrupted)
|
||||
{
|
||||
sqlite3ErrorMsg(pParse, "interrupt");
|
||||
pParse.rc = SQLITE_INTERRUPT;
|
||||
goto abort_parse;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TK_ILLEGAL:
|
||||
{
|
||||
sqlite3DbFree(db, ref pzErrMsg);
|
||||
pzErrMsg = sqlite3MPrintf(db, "unrecognized token: \"%T\"",
|
||||
(object)pParse.sLastToken);
|
||||
nErr++;
|
||||
goto abort_parse;
|
||||
}
|
||||
case TK_SEMI:
|
||||
{
|
||||
//pParse.zTail = new StringBuilder(zSql.Substring( i,zSql.Length-i ));
|
||||
/* Fall thru into the default case */
|
||||
goto default;
|
||||
}
|
||||
default:
|
||||
{
|
||||
sqlite3Parser(pEngine, tokenType, pParse.sLastToken, pParse);
|
||||
lastTokenParsed = tokenType;
|
||||
if (pParse.rc != SQLITE_OK)
|
||||
{
|
||||
goto abort_parse;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
abort_parse:
|
||||
pParse.zTail = new StringBuilder(zSql.Length <= i ? "" : zSql.Substring(i, zSql.Length - i));
|
||||
if (zSql.Length >= i && nErr == 0 && pParse.rc == SQLITE_OK)
|
||||
{
|
||||
if (lastTokenParsed != TK_SEMI)
|
||||
{
|
||||
sqlite3Parser(pEngine, TK_SEMI, pParse.sLastToken, pParse);
|
||||
}
|
||||
sqlite3Parser(pEngine, 0, pParse.sLastToken, pParse);
|
||||
}
|
||||
#if YYTRACKMAXSTACKDEPTH
|
||||
sqlite3StatusSet(SQLITE_STATUS_PARSER_STACK,
|
||||
sqlite3ParserStackPeak(pEngine)
|
||||
);
|
||||
#endif //* YYDEBUG */
|
||||
sqlite3ParserFree(pEngine, null);//sqlite3_free );
|
||||
db.lookaside.bEnabled = enableLookaside;
|
||||
//if ( db.mallocFailed != 0 )
|
||||
//{
|
||||
// pParse.rc = SQLITE_NOMEM;
|
||||
//}
|
||||
if (pParse.rc != SQLITE_OK && pParse.rc != SQLITE_DONE && pParse.zErrMsg == "")
|
||||
{
|
||||
sqlite3SetString(ref pParse.zErrMsg, db, sqlite3ErrStr(pParse.rc));
|
||||
}
|
||||
//assert( pzErrMsg!=0 );
|
||||
if (pParse.zErrMsg != null)
|
||||
{
|
||||
pzErrMsg = pParse.zErrMsg;
|
||||
sqlite3_log(pParse.rc, "%s", pzErrMsg);
|
||||
pParse.zErrMsg = "";
|
||||
nErr++;
|
||||
}
|
||||
if (pParse.pVdbe != null && pParse.nErr > 0 && pParse.nested == 0)
|
||||
{
|
||||
sqlite3VdbeDelete(ref pParse.pVdbe);
|
||||
pParse.pVdbe = null;
|
||||
}
|
||||
#if !SQLITE_OMIT_SHARED_CACHE
|
||||
if ( pParse.nested == 0 )
|
||||
{
|
||||
sqlite3DbFree( db, ref pParse.aTableLock );
|
||||
pParse.aTableLock = null;
|
||||
pParse.nTableLock = 0;
|
||||
}
|
||||
#endif
|
||||
#if !SQLITE_OMIT_VIRTUALTABLE
|
||||
pParse.apVtabLock = null;//sqlite3_free( pParse.apVtabLock );
|
||||
#endif
|
||||
if (!IN_DECLARE_VTAB(pParse))
|
||||
{
|
||||
/* If the pParse.declareVtab flag is set, do not delete any table
|
||||
** structure built up in pParse.pNewTable. The calling code (see vtab.c)
|
||||
** will take responsibility for freeing the Table structure.
|
||||
*/
|
||||
sqlite3DeleteTable(db, ref pParse.pNewTable);
|
||||
}
|
||||
|
||||
#if !SQLITE_OMIT_TRIGGER
|
||||
sqlite3DeleteTrigger(db, ref pParse.pNewTrigger);
|
||||
#endif
|
||||
//for ( i = pParse.nzVar - 1; i >= 0; i-- )
|
||||
// sqlite3DbFree( db, pParse.azVar[i] );
|
||||
sqlite3DbFree(db, ref pParse.azVar);
|
||||
sqlite3DbFree(db, ref pParse.aAlias);
|
||||
while (pParse.pAinc != null)
|
||||
{
|
||||
AutoincInfo p = pParse.pAinc;
|
||||
pParse.pAinc = p.pNext;
|
||||
sqlite3DbFree(db, ref p);
|
||||
}
|
||||
while (pParse.pZombieTab != null)
|
||||
{
|
||||
Table p = pParse.pZombieTab;
|
||||
pParse.pZombieTab = p.pNextZombie;
|
||||
sqlite3DeleteTable(db, ref p);
|
||||
}
|
||||
if (nErr > 0 && pParse.rc == SQLITE_OK)
|
||||
{
|
||||
pParse.rc = SQLITE_ERROR;
|
||||
}
|
||||
return nErr;
|
||||
}
|
||||
}
|
||||
}
|
||||
1337
original/Community.CsharpSqlite/src/trigger_c.cs
Normal file
1337
original/Community.CsharpSqlite/src/trigger_c.cs
Normal file
File diff suppressed because it is too large
Load diff
785
original/Community.CsharpSqlite/src/update_c.cs
Normal file
785
original/Community.CsharpSqlite/src/update_c.cs
Normal file
|
|
@ -0,0 +1,785 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
using u32 = System.UInt32;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
using sqlite3_value = Sqlite3.Mem;
|
||||
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle UPDATE statements.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#include "sqliteInt.h"
|
||||
|
||||
#if !SQLITE_OMIT_VIRTUALTABLE
|
||||
/* Forward declaration */
|
||||
//static void updateVirtualTable(
|
||||
//Parse pParse, /* The parsing context */
|
||||
//SrcList pSrc, /* The virtual table to be modified */
|
||||
//Table pTab, /* The virtual table */
|
||||
//ExprList pChanges, /* The columns to change in the UPDATE statement */
|
||||
//Expr pRowidExpr, /* Expression used to recompute the rowid */
|
||||
//int aXRef, /* Mapping from columns of pTab to entries in pChanges */
|
||||
//Expr *pWhere, /* WHERE clause of the UPDATE statement */
|
||||
//int onError /* ON CONFLICT strategy */
|
||||
//);
|
||||
#endif // * SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
/*
|
||||
** The most recently coded instruction was an OP_Column to retrieve the
|
||||
** i-th column of table pTab. This routine sets the P4 parameter of the
|
||||
** OP_Column to the default value, if any.
|
||||
**
|
||||
** The default value of a column is specified by a DEFAULT clause in the
|
||||
** column definition. This was either supplied by the user when the table
|
||||
** was created, or added later to the table definition by an ALTER TABLE
|
||||
** command. If the latter, then the row-records in the table btree on disk
|
||||
** may not contain a value for the column and the default value, taken
|
||||
** from the P4 parameter of the OP_Column instruction, is returned instead.
|
||||
** If the former, then all row-records are guaranteed to include a value
|
||||
** for the column and the P4 value is not required.
|
||||
**
|
||||
** Column definitions created by an ALTER TABLE command may only have
|
||||
** literal default values specified: a number, null or a string. (If a more
|
||||
** complicated default expression value was provided, it is evaluated
|
||||
** when the ALTER TABLE is executed and one of the literal values written
|
||||
** into the sqlite_master table.)
|
||||
**
|
||||
** Therefore, the P4 parameter is only required if the default value for
|
||||
** the column is a literal number, string or null. The sqlite3ValueFromExpr()
|
||||
** function is capable of transforming these types of expressions into
|
||||
** sqlite3_value objects.
|
||||
**
|
||||
** If parameter iReg is not negative, code an OP_RealAffinity instruction
|
||||
** on register iReg. This is used when an equivalent integer value is
|
||||
** stored in place of an 8-byte floating point value in order to save
|
||||
** space.
|
||||
*/
|
||||
|
||||
private static void sqlite3ColumnDefault(Vdbe v, Table pTab, int i, int iReg)
|
||||
{
|
||||
Debug.Assert(pTab != null);
|
||||
if (null == pTab.pSelect)
|
||||
{
|
||||
sqlite3_value pValue = new sqlite3_value();
|
||||
int enc = ENC(sqlite3VdbeDb(v));
|
||||
Column pCol = pTab.aCol[i];
|
||||
#if SQLITE_DEBUG
|
||||
VdbeComment(v, "%s.%s", pTab.zName, pCol.zName);
|
||||
#endif
|
||||
Debug.Assert(i < pTab.nCol);
|
||||
sqlite3ValueFromExpr(sqlite3VdbeDb(v), pCol.pDflt, enc,
|
||||
pCol.affinity, ref pValue);
|
||||
if (pValue != null)
|
||||
{
|
||||
sqlite3VdbeChangeP4(v, -1, pValue, P4_MEM);
|
||||
}
|
||||
#if !SQLITE_OMIT_FLOATING_POINT
|
||||
if (iReg >= 0 && pTab.aCol[i].affinity == SQLITE_AFF_REAL)
|
||||
{
|
||||
sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Process an UPDATE statement.
|
||||
**
|
||||
** UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL;
|
||||
** \_______/ \________/ \______/ \________________/
|
||||
* onError pTabList pChanges pWhere
|
||||
*/
|
||||
|
||||
private static void sqlite3Update(
|
||||
Parse pParse, /* The parser context */
|
||||
SrcList pTabList, /* The table in which we should change things */
|
||||
ExprList pChanges, /* Things to be changed */
|
||||
Expr pWhere, /* The WHERE clause. May be null */
|
||||
int onError /* How to handle constraint errors */
|
||||
)
|
||||
{
|
||||
int i, j; /* Loop counters */
|
||||
Table pTab; /* The table to be updated */
|
||||
int addr = 0; /* VDBE instruction address of the start of the loop */
|
||||
WhereInfo pWInfo; /* Information about the WHERE clause */
|
||||
Vdbe v; /* The virtual database engine */
|
||||
Index pIdx; /* For looping over indices */
|
||||
int nIdx; /* Number of indices that need updating */
|
||||
int iCur; /* VDBE Cursor number of pTab */
|
||||
sqlite3 db; /* The database structure */
|
||||
int[] aRegIdx = null; /* One register assigned to each index to be updated */
|
||||
int[] aXRef = null; /* aXRef[i] is the index in pChanges.a[] of the
|
||||
** an expression for the i-th column of the table.
|
||||
** aXRef[i]==-1 if the i-th column is not changed. */
|
||||
bool chngRowid; /* True if the record number is being changed */
|
||||
Expr pRowidExpr = null; /* Expression defining the new record number */
|
||||
bool openAll = false; /* True if all indices need to be opened */
|
||||
AuthContext sContext; /* The authorization context */
|
||||
NameContext sNC; /* The name-context to resolve expressions in */
|
||||
int iDb; /* Database containing the table being updated */
|
||||
bool okOnePass; /* True for one-pass algorithm without the FIFO */
|
||||
bool hasFK; /* True if foreign key processing is required */
|
||||
|
||||
#if !SQLITE_OMIT_TRIGGER
|
||||
bool isView; /* True when updating a view (INSTEAD OF trigger) */
|
||||
Trigger pTrigger; /* List of triggers on pTab, if required */
|
||||
int tmask = 0; /* Mask of TRIGGER_BEFORE|TRIGGER_AFTER */
|
||||
#endif
|
||||
int newmask; /* Mask of NEW.* columns accessed by BEFORE triggers */
|
||||
|
||||
/* Register Allocations */
|
||||
int regRowCount = 0; /* A count of rows changed */
|
||||
int regOldRowid; /* The old rowid */
|
||||
int regNewRowid; /* The new rowid */
|
||||
int regNew;
|
||||
int regOld = 0;
|
||||
int regRowSet = 0; /* Rowset of rows to be updated */
|
||||
|
||||
sContext = new AuthContext(); //memset( &sContext, 0, sizeof( sContext ) );
|
||||
db = pParse.db;
|
||||
if (pParse.nErr != 0 /*|| db.mallocFailed != 0 */ )
|
||||
{
|
||||
goto update_cleanup;
|
||||
}
|
||||
Debug.Assert(pTabList.nSrc == 1);
|
||||
|
||||
/* Locate the table which we want to update.
|
||||
*/
|
||||
pTab = sqlite3SrcListLookup(pParse, pTabList);
|
||||
if (pTab == null)
|
||||
goto update_cleanup;
|
||||
iDb = sqlite3SchemaToIndex(pParse.db, pTab.pSchema);
|
||||
|
||||
/* Figure out if we have any triggers and if the table being
|
||||
** updated is a view.
|
||||
*/
|
||||
#if !SQLITE_OMIT_TRIGGER
|
||||
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_UPDATE, pChanges, out tmask);
|
||||
isView = pTab.pSelect != null;
|
||||
Debug.Assert(pTrigger != null || tmask == 0);
|
||||
#else
|
||||
const Trigger pTrigger = null;//# define pTrigger 0
|
||||
const int tmask = 0; //# define tmask 0
|
||||
#endif
|
||||
#if SQLITE_OMIT_TRIGGER || SQLITE_OMIT_VIEW
|
||||
// # undef isView
|
||||
const bool isView = false; //# define isView 0
|
||||
#endif
|
||||
|
||||
if (sqlite3ViewGetColumnNames(pParse, pTab) != 0)
|
||||
{
|
||||
goto update_cleanup;
|
||||
}
|
||||
if (sqlite3IsReadOnly(pParse, pTab, tmask))
|
||||
{
|
||||
goto update_cleanup;
|
||||
}
|
||||
aXRef = new int[pTab.nCol];// sqlite3DbMallocRaw(db, sizeof(int) * pTab.nCol);
|
||||
//if ( aXRef == null ) goto update_cleanup;
|
||||
for (i = 0; i < pTab.nCol; i++)
|
||||
aXRef[i] = -1;
|
||||
|
||||
/* Allocate a cursors for the main database table and for all indices.
|
||||
** The index cursors might not be used, but if they are used they
|
||||
** need to occur right after the database cursor. So go ahead and
|
||||
** allocate enough space, just in case.
|
||||
*/
|
||||
pTabList.a[0].iCursor = iCur = pParse.nTab++;
|
||||
for (pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext)
|
||||
{
|
||||
pParse.nTab++;
|
||||
}
|
||||
|
||||
/* Initialize the name-context */
|
||||
sNC = new NameContext();// memset(&sNC, 0, sNC).Length;
|
||||
sNC.pParse = pParse;
|
||||
sNC.pSrcList = pTabList;
|
||||
|
||||
/* Resolve the column names in all the expressions of the
|
||||
** of the UPDATE statement. Also find the column index
|
||||
** for each column to be updated in the pChanges array. For each
|
||||
** column to be updated, make sure we have authorization to change
|
||||
** that column.
|
||||
*/
|
||||
chngRowid = false;
|
||||
for (i = 0; i < pChanges.nExpr; i++)
|
||||
{
|
||||
if (sqlite3ResolveExprNames(sNC, ref pChanges.a[i].pExpr) != 0)
|
||||
{
|
||||
goto update_cleanup;
|
||||
}
|
||||
for (j = 0; j < pTab.nCol; j++)
|
||||
{
|
||||
if (pTab.aCol[j].zName.Equals(pChanges.a[i].zName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (j == pTab.iPKey)
|
||||
{
|
||||
chngRowid = true;
|
||||
pRowidExpr = pChanges.a[i].pExpr;
|
||||
}
|
||||
aXRef[j] = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j >= pTab.nCol)
|
||||
{
|
||||
if (sqlite3IsRowid(pChanges.a[i].zName))
|
||||
{
|
||||
chngRowid = true;
|
||||
pRowidExpr = pChanges.a[i].pExpr;
|
||||
}
|
||||
else
|
||||
{
|
||||
sqlite3ErrorMsg(pParse, "no such column: %s", pChanges.a[i].zName);
|
||||
pParse.checkSchema = 1;
|
||||
goto update_cleanup;
|
||||
}
|
||||
}
|
||||
#if !SQLITE_OMIT_AUTHORIZATION
|
||||
{
|
||||
int rc;
|
||||
rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab.zName,
|
||||
pTab.aCol[j].zName, db.aDb[iDb].zName);
|
||||
if( rc==SQLITE_DENY ){
|
||||
goto update_cleanup;
|
||||
}else if( rc==SQLITE_IGNORE ){
|
||||
aXRef[j] = -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
hasFK = sqlite3FkRequired(pParse, pTab, aXRef, chngRowid ? 1 : 0) != 0;
|
||||
|
||||
/* Allocate memory for the array aRegIdx[]. There is one entry in the
|
||||
** array for each index associated with table being updated. Fill in
|
||||
** the value with a register number for indices that are to be used
|
||||
** and with zero for unused indices.
|
||||
*/
|
||||
for (nIdx = 0, pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext, nIdx++)
|
||||
{
|
||||
}
|
||||
if (nIdx > 0)
|
||||
{
|
||||
aRegIdx = new int[nIdx]; // sqlite3DbMallocRaw(db, Index*.Length * nIdx);
|
||||
if (aRegIdx == null)
|
||||
goto update_cleanup;
|
||||
}
|
||||
for (j = 0, pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext, j++)
|
||||
{
|
||||
int reg;
|
||||
if (hasFK || chngRowid)
|
||||
{
|
||||
reg = ++pParse.nMem;
|
||||
}
|
||||
else
|
||||
{
|
||||
reg = 0;
|
||||
for (i = 0; i < pIdx.nColumn; i++)
|
||||
{
|
||||
if (aXRef[pIdx.aiColumn[i]] >= 0)
|
||||
{
|
||||
reg = ++pParse.nMem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
aRegIdx[j] = reg;
|
||||
}
|
||||
|
||||
/* Begin generating code. */
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if (v == null)
|
||||
goto update_cleanup;
|
||||
if (pParse.nested == 0)
|
||||
sqlite3VdbeCountChanges(v);
|
||||
sqlite3BeginWriteOperation(pParse, 1, iDb);
|
||||
|
||||
#if !SQLITE_OMIT_VIRTUALTABLE
|
||||
/* Virtual tables must be handled separately */
|
||||
if (IsVirtual(pTab))
|
||||
{
|
||||
updateVirtualTable(pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef,
|
||||
pWhere, onError);
|
||||
pWhere = null;
|
||||
pTabList = null;
|
||||
goto update_cleanup;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Allocate required registers. */
|
||||
regOldRowid = regNewRowid = ++pParse.nMem;
|
||||
if (pTrigger != null || hasFK)
|
||||
{
|
||||
regOld = pParse.nMem + 1;
|
||||
pParse.nMem += pTab.nCol;
|
||||
}
|
||||
if (chngRowid || pTrigger != null || hasFK)
|
||||
{
|
||||
regNewRowid = ++pParse.nMem;
|
||||
}
|
||||
regNew = pParse.nMem + 1;
|
||||
pParse.nMem += pTab.nCol;
|
||||
|
||||
/* Start the view context. */
|
||||
if (isView)
|
||||
{
|
||||
sqlite3AuthContextPush(pParse, sContext, pTab.zName);
|
||||
}
|
||||
|
||||
/* If we are trying to update a view, realize that view into
|
||||
** a ephemeral table.
|
||||
*/
|
||||
#if !(SQLITE_OMIT_VIEW) && !(SQLITE_OMIT_TRIGGER)
|
||||
if (isView)
|
||||
{
|
||||
sqlite3MaterializeView(pParse, pTab, pWhere, iCur);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Resolve the column names in all the expressions in the
|
||||
** WHERE clause.
|
||||
*/
|
||||
if (sqlite3ResolveExprNames(sNC, ref pWhere) != 0)
|
||||
{
|
||||
goto update_cleanup;
|
||||
}
|
||||
|
||||
/* Begin the database scan
|
||||
*/
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regOldRowid);
|
||||
ExprList NullOrderby = null;
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, ref NullOrderby, WHERE_ONEPASS_DESIRED);
|
||||
if (pWInfo == null)
|
||||
goto update_cleanup;
|
||||
okOnePass = pWInfo.okOnePass != 0;
|
||||
|
||||
/* Remember the rowid of every item to be updated.
|
||||
*/
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regOldRowid);
|
||||
if (!okOnePass)
|
||||
{
|
||||
regRowSet = ++pParse.nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid);
|
||||
}
|
||||
|
||||
/* End the database scan loop.
|
||||
*/
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
|
||||
/* Initialize the count of updated rows
|
||||
*/
|
||||
if ((db.flags & SQLITE_CountRows) != 0 && null == pParse.pTriggerTab)
|
||||
{
|
||||
regRowCount = ++pParse.nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount);
|
||||
}
|
||||
|
||||
if (!isView)
|
||||
{
|
||||
/*
|
||||
** Open every index that needs updating. Note that if any
|
||||
** index could potentially invoke a REPLACE conflict resolution
|
||||
** action, then we need to open all indices because we might need
|
||||
** to be deleting some records.
|
||||
*/
|
||||
if (!okOnePass)
|
||||
sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite);
|
||||
if (onError == OE_Replace)
|
||||
{
|
||||
openAll = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
openAll = false;
|
||||
for (pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext)
|
||||
{
|
||||
if (pIdx.onError == OE_Replace)
|
||||
{
|
||||
openAll = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0, pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext, i++)
|
||||
{
|
||||
if (openAll || aRegIdx[i] > 0)
|
||||
{
|
||||
KeyInfo pKey = sqlite3IndexKeyinfo(pParse, pIdx);
|
||||
sqlite3VdbeAddOp4(v, OP_OpenWrite, iCur + i + 1, pIdx.tnum, iDb,
|
||||
pKey, P4_KEYINFO_HANDOFF);
|
||||
Debug.Assert(pParse.nTab > iCur + i + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Top of the update loop */
|
||||
if (okOnePass)
|
||||
{
|
||||
int a1 = sqlite3VdbeAddOp1(v, OP_NotNull, regOldRowid);
|
||||
addr = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
sqlite3VdbeJumpHere(v, a1);
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = sqlite3VdbeAddOp3(v, OP_RowSetRead, regRowSet, 0, regOldRowid);
|
||||
}
|
||||
|
||||
/* Make cursor iCur point to the record that is being updated. If
|
||||
** this record does not exist for some reason (deleted by a trigger,
|
||||
** for example, then jump to the next iteration of the RowSet loop. */
|
||||
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, regOldRowid);
|
||||
|
||||
/* If the record number will change, set register regNewRowid to
|
||||
** contain the new value. If the record number is not being modified,
|
||||
** then regNewRowid is the same register as regOldRowid, which is
|
||||
** already populated. */
|
||||
Debug.Assert(chngRowid || pTrigger != null || hasFK || regOldRowid == regNewRowid);
|
||||
if (chngRowid)
|
||||
{
|
||||
sqlite3ExprCode(pParse, pRowidExpr, regNewRowid);
|
||||
sqlite3VdbeAddOp1(v, OP_MustBeInt, regNewRowid);
|
||||
}
|
||||
|
||||
/* If there are triggers on this table, populate an array of registers
|
||||
** with the required old.* column data. */
|
||||
if (hasFK || pTrigger != null)
|
||||
{
|
||||
u32 oldmask = (hasFK ? sqlite3FkOldmask(pParse, pTab) : 0);
|
||||
oldmask |= sqlite3TriggerColmask(pParse,
|
||||
pTrigger, pChanges, 0, TRIGGER_BEFORE | TRIGGER_AFTER, pTab, onError
|
||||
);
|
||||
for (i = 0; i < pTab.nCol; i++)
|
||||
{
|
||||
if (aXRef[i] < 0 || oldmask == 0xffffffff || (i < 32 && 0 != (oldmask & (1 << i))))
|
||||
{
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOld + i);
|
||||
}
|
||||
else
|
||||
{
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regOld + i);
|
||||
}
|
||||
}
|
||||
if (chngRowid == false)
|
||||
{
|
||||
sqlite3VdbeAddOp2(v, OP_Copy, regOldRowid, regNewRowid);
|
||||
}
|
||||
}
|
||||
|
||||
/* Populate the array of registers beginning at regNew with the new
|
||||
** row data. This array is used to check constaints, create the new
|
||||
** table and index records, and as the values for any new.* references
|
||||
** made by triggers.
|
||||
**
|
||||
** If there are one or more BEFORE triggers, then do not populate the
|
||||
** registers associated with columns that are (a) not modified by
|
||||
** this UPDATE statement and (b) not accessed by new.* references. The
|
||||
** values for registers not modified by the UPDATE must be reloaded from
|
||||
** the database after the BEFORE triggers are fired anyway (as the trigger
|
||||
** may have modified them). So not loading those that are not going to
|
||||
** be used eliminates some redundant opcodes.
|
||||
*/
|
||||
newmask = (int)sqlite3TriggerColmask(
|
||||
pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError
|
||||
);
|
||||
for (i = 0; i < pTab.nCol; i++)
|
||||
{
|
||||
if (i == pTab.iPKey)
|
||||
{
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regNew + i);
|
||||
}
|
||||
else
|
||||
{
|
||||
j = aXRef[i];
|
||||
if (j >= 0)
|
||||
{
|
||||
sqlite3ExprCode(pParse, pChanges.a[j].pExpr, regNew + i);
|
||||
}
|
||||
else if (0 == (tmask & TRIGGER_BEFORE) || i > 31 || (newmask & (1 << i)) != 0)
|
||||
{
|
||||
/* This branch loads the value of a column that will not be changed
|
||||
** into a register. This is done if there are no BEFORE triggers, or
|
||||
** if there are one or more BEFORE triggers that use this value via
|
||||
** a new.* reference in a trigger program.
|
||||
*/
|
||||
testcase(i == 31);
|
||||
testcase(i == 32);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regNew + i);
|
||||
sqlite3ColumnDefault(v, pTab, i, regNew + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Fire any BEFORE UPDATE triggers. This happens before constraints are
|
||||
** verified. One could argue that this is wrong.
|
||||
*/
|
||||
if ((tmask & TRIGGER_BEFORE) != 0)
|
||||
{
|
||||
sqlite3VdbeAddOp2(v, OP_Affinity, regNew, pTab.nCol);
|
||||
sqlite3TableAffinityStr(v, pTab);
|
||||
sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
|
||||
TRIGGER_BEFORE, pTab, regOldRowid, onError, addr);
|
||||
|
||||
/* The row-trigger may have deleted the row being updated. In this
|
||||
** case, jump to the next row. No updates or AFTER triggers are
|
||||
** required. This behaviour - what happens when the row being updated
|
||||
** is deleted or renamed by a BEFORE trigger - is left undefined in the
|
||||
** documentation.
|
||||
*/
|
||||
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, regOldRowid);
|
||||
|
||||
/* If it did not delete it, the row-trigger may still have modified
|
||||
** some of the columns of the row being updated. Load the values for
|
||||
** all columns not modified by the update statement into their
|
||||
** registers in case this has happened.
|
||||
*/
|
||||
for (i = 0; i < pTab.nCol; i++)
|
||||
{
|
||||
if (aXRef[i] < 0 && i != pTab.iPKey)
|
||||
{
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regNew + i);
|
||||
sqlite3ColumnDefault(v, pTab, i, regNew + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isView)
|
||||
{
|
||||
int j1; /* Address of jump instruction */
|
||||
|
||||
/* Do constraint checks. */
|
||||
int iDummy;
|
||||
sqlite3GenerateConstraintChecks(pParse, pTab, iCur, regNewRowid,
|
||||
aRegIdx, (chngRowid ? regOldRowid : 0), true, onError, addr, out iDummy);
|
||||
|
||||
/* Do FK constraint checks. */
|
||||
if (hasFK)
|
||||
{
|
||||
sqlite3FkCheck(pParse, pTab, regOldRowid, 0);
|
||||
}
|
||||
|
||||
/* Delete the index entries associated with the current record. */
|
||||
j1 = sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regOldRowid);
|
||||
sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, aRegIdx);
|
||||
|
||||
/* If changing the record number, delete the old record. */
|
||||
if (hasFK || chngRowid)
|
||||
{
|
||||
sqlite3VdbeAddOp2(v, OP_Delete, iCur, 0);
|
||||
}
|
||||
sqlite3VdbeJumpHere(v, j1);
|
||||
|
||||
if (hasFK)
|
||||
{
|
||||
sqlite3FkCheck(pParse, pTab, 0, regNewRowid);
|
||||
}
|
||||
|
||||
/* Insert the new index entries and the new record. */
|
||||
sqlite3CompleteInsertion(pParse, pTab, iCur, regNewRowid, aRegIdx, true, false, false);
|
||||
|
||||
/* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
|
||||
** handle rows (possibly in other tables) that refer via a foreign key
|
||||
** to the row just updated. */
|
||||
if (hasFK)
|
||||
{
|
||||
sqlite3FkActions(pParse, pTab, pChanges, regOldRowid);
|
||||
}
|
||||
}
|
||||
|
||||
/* Increment the row counter
|
||||
*/
|
||||
if ((db.flags & SQLITE_CountRows) != 0 && null == pParse.pTriggerTab)
|
||||
{
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1);
|
||||
}
|
||||
|
||||
sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
|
||||
TRIGGER_AFTER, pTab, regOldRowid, onError, addr);
|
||||
|
||||
/* Repeat the above with the next record to be updated, until
|
||||
** all record selected by the WHERE clause have been updated.
|
||||
*/
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addr);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
|
||||
/* Close all tables */
|
||||
for (i = 0, pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext, i++)
|
||||
{
|
||||
if (openAll || aRegIdx[i] > 0)
|
||||
{
|
||||
sqlite3VdbeAddOp2(v, OP_Close, iCur + i + 1, 0);
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Close, iCur, 0);
|
||||
|
||||
/* Update the sqlite_sequence table by storing the content of the
|
||||
** maximum rowid counter values recorded while inserting into
|
||||
** autoincrement tables.
|
||||
*/
|
||||
if (pParse.nested == 0 && pParse.pTriggerTab == null)
|
||||
{
|
||||
sqlite3AutoincrementEnd(pParse);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of rows that were changed. If this routine is
|
||||
** generating code because of a call to sqlite3NestedParse(), do not
|
||||
** invoke the callback function.
|
||||
*/
|
||||
if ((db.flags & SQLITE_CountRows) != 0 && null == pParse.pTriggerTab && 0 == pParse.nested)
|
||||
{
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, regRowCount, 1);
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", SQLITE_STATIC);
|
||||
}
|
||||
|
||||
update_cleanup:
|
||||
#if !SQLITE_OMIT_AUTHORIZATION
|
||||
sqlite3AuthContextPop(sContext);
|
||||
#endif
|
||||
sqlite3DbFree(db, ref aRegIdx);
|
||||
sqlite3DbFree(db, ref aXRef);
|
||||
sqlite3SrcListDelete(db, ref pTabList);
|
||||
sqlite3ExprListDelete(db, ref pChanges);
|
||||
sqlite3ExprDelete(db, ref pWhere);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Make sure "isView" and other macros defined above are undefined. Otherwise
|
||||
** thely may interfere with compilation of other functions in this file
|
||||
** (or in another file, if this file becomes part of the amalgamation). */
|
||||
//#if isView
|
||||
// #undef isView
|
||||
//#endif
|
||||
//#if pTrigger
|
||||
// #undef pTrigger
|
||||
//#endif
|
||||
|
||||
#if !SQLITE_OMIT_VIRTUALTABLE
|
||||
/*
|
||||
** Generate code for an UPDATE of a virtual table.
|
||||
**
|
||||
** The strategy is that we create an ephemerial table that contains
|
||||
** for each row to be changed:
|
||||
**
|
||||
** (A) The original rowid of that row.
|
||||
** (B) The revised rowid for the row. (note1)
|
||||
** (C) The content of every column in the row.
|
||||
**
|
||||
** Then we loop over this ephemeral table and for each row in
|
||||
** the ephermeral table call VUpdate.
|
||||
**
|
||||
** When finished, drop the ephemeral table.
|
||||
**
|
||||
** (note1) Actually, if we know in advance that (A) is always the same
|
||||
** as (B) we only store (A), then duplicate (A) when pulling
|
||||
** it out of the ephemeral table before calling VUpdate.
|
||||
*/
|
||||
|
||||
private static void updateVirtualTable(
|
||||
Parse pParse, /* The parsing context */
|
||||
SrcList pSrc, /* The virtual table to be modified */
|
||||
Table pTab, /* The virtual table */
|
||||
ExprList pChanges, /* The columns to change in the UPDATE statement */
|
||||
Expr pRowid, /* Expression used to recompute the rowid */
|
||||
int[] aXRef, /* Mapping from columns of pTab to entries in pChanges */
|
||||
Expr pWhere, /* WHERE clause of the UPDATE statement */
|
||||
int onError /* ON CONFLICT strategy */
|
||||
)
|
||||
{
|
||||
Vdbe v = pParse.pVdbe; /* Virtual machine under construction */
|
||||
ExprList pEList = null; /* The result set of the SELECT statement */
|
||||
Select pSelect = null; /* The SELECT statement */
|
||||
Expr pExpr; /* Temporary expression */
|
||||
int ephemTab; /* Table holding the result of the SELECT */
|
||||
int i; /* Loop counter */
|
||||
int addr; /* Address of top of loop */
|
||||
int iReg; /* First register in set passed to OP_VUpdate */
|
||||
sqlite3 db = pParse.db; /* Database connection */
|
||||
VTable pVTab = sqlite3GetVTable(db, pTab);
|
||||
SelectDest dest = new SelectDest();
|
||||
|
||||
/* Construct the SELECT statement that will find the new values for
|
||||
** all updated rows.
|
||||
*/
|
||||
pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ID, "_rowid_"));
|
||||
if (pRowid != null)
|
||||
{
|
||||
pEList = sqlite3ExprListAppend(pParse, pEList,
|
||||
sqlite3ExprDup(db, pRowid, 0));
|
||||
}
|
||||
Debug.Assert(pTab.iPKey < 0);
|
||||
for (i = 0; i < pTab.nCol; i++)
|
||||
{
|
||||
if (aXRef[i] >= 0)
|
||||
{
|
||||
pExpr = sqlite3ExprDup(db, pChanges.a[aXRef[i]].pExpr, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
pExpr = sqlite3Expr(db, TK_ID, pTab.aCol[i].zName);
|
||||
}
|
||||
pEList = sqlite3ExprListAppend(pParse, pEList, pExpr);
|
||||
}
|
||||
pSelect = sqlite3SelectNew(pParse, pEList, pSrc, pWhere, null, null, null, 0, null, null);
|
||||
|
||||
/* Create the ephemeral table into which the update results will
|
||||
** be stored.
|
||||
*/
|
||||
Debug.Assert(v != null);
|
||||
ephemTab = pParse.nTab++;
|
||||
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, pTab.nCol + 1 + ((pRowid != null) ? 1 : 0));
|
||||
sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
|
||||
|
||||
/* fill the ephemeral table
|
||||
*/
|
||||
sqlite3SelectDestInit(dest, SRT_Table, ephemTab);
|
||||
sqlite3Select(pParse, pSelect, ref dest);
|
||||
|
||||
/* Generate code to scan the ephemeral table and call VUpdate. */
|
||||
iReg = ++pParse.nMem;
|
||||
pParse.nMem += pTab.nCol + 1;
|
||||
addr = sqlite3VdbeAddOp2(v, OP_Rewind, ephemTab, 0);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, ephemTab, 0, iReg);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, ephemTab, (pRowid != null ? 1 : 0), iReg + 1);
|
||||
for (i = 0; i < pTab.nCol; i++)
|
||||
{
|
||||
sqlite3VdbeAddOp3(v, OP_Column, ephemTab, i + 1 + ((pRowid != null) ? 1 : 0), iReg + 2 + i);
|
||||
}
|
||||
sqlite3VtabMakeWritable(pParse, pTab);
|
||||
sqlite3VdbeAddOp4(v, OP_VUpdate, 0, pTab.nCol + 2, iReg, pVTab, P4_VTAB);
|
||||
sqlite3VdbeChangeP5(v, (byte)(onError == OE_Default ? OE_Abort : onError));
|
||||
sqlite3MayAbort(pParse);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr + 1);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0);
|
||||
|
||||
/* Cleanup */
|
||||
sqlite3SelectDelete(db, ref pSelect);
|
||||
}
|
||||
|
||||
#endif // * SQLITE_OMIT_VIRTUALTABLE */
|
||||
}
|
||||
}
|
||||
631
original/Community.CsharpSqlite/src/utf_c.cs
Normal file
631
original/Community.CsharpSqlite/src/utf_c.cs
Normal file
|
|
@ -0,0 +1,631 @@
|
|||
using System;
|
||||
using u32 = System.UInt32;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2004 April 13
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains routines used to translate between UTF-8,
|
||||
** UTF-16, UTF-16BE, and UTF-16LE.
|
||||
**
|
||||
** Notes on UTF-8:
|
||||
**
|
||||
** Byte-0 Byte-1 Byte-2 Byte-3 Value
|
||||
** 0xxxxxxx 00000000 00000000 0xxxxxxx
|
||||
** 110yyyyy 10xxxxxx 00000000 00000yyy yyxxxxxx
|
||||
** 1110zzzz 10yyyyyy 10xxxxxx 00000000 zzzzyyyy yyxxxxxx
|
||||
** 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx 000uuuuu zzzzyyyy yyxxxxxx
|
||||
**
|
||||
**
|
||||
** Notes on UTF-16: (with wwww+1==uuuuu)
|
||||
**
|
||||
** Word-0 Word-1 Value
|
||||
** 110110ww wwzzzzyy 110111yy yyxxxxxx 000uuuuu zzzzyyyy yyxxxxxx
|
||||
** zzzzyyyy yyxxxxxx 00000000 zzzzyyyy yyxxxxxx
|
||||
**
|
||||
**
|
||||
** BOM or Byte Order Mark:
|
||||
** 0xff 0xfe little-endian utf-16 follows
|
||||
** 0xfe 0xff big-endian utf-16 follows
|
||||
**
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#include "sqliteInt.h"
|
||||
//#include <assert.h>
|
||||
//#include "vdbeInt.h"
|
||||
|
||||
#if !SQLITE_AMALGAMATION
|
||||
/*
|
||||
** The following constant value is used by the SQLITE_BIGENDIAN and
|
||||
** SQLITE_LITTLEENDIAN macros.
|
||||
*/
|
||||
//const int sqlite3one = 1;
|
||||
#endif //* SQLITE_AMALGAMATION */
|
||||
|
||||
/*
|
||||
** This lookup table is used to help decode the first byte of
|
||||
** a multi-byte UTF8 character.
|
||||
*/
|
||||
|
||||
private static byte[] sqlite3Utf8Trans1 = new byte[] {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00,
|
||||
};
|
||||
|
||||
//#define WRITE_UTF8(zOut, c) { \
|
||||
// if( c<0x00080 ){ \
|
||||
// *zOut++ = (u8)(c&0xFF); \
|
||||
// } \
|
||||
// else if( c<0x00800 ){ \
|
||||
// *zOut++ = 0xC0 + (u8)((c>>6)&0x1F); \
|
||||
// *zOut++ = 0x80 + (u8)(c & 0x3F); \
|
||||
// } \
|
||||
// else if( c<0x10000 ){ \
|
||||
// *zOut++ = 0xE0 + (u8)((c>>12)&0x0F); \
|
||||
// *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); \
|
||||
// *zOut++ = 0x80 + (u8)(c & 0x3F); \
|
||||
// }else{ \
|
||||
// *zOut++ = 0xF0 + (u8)((c>>18) & 0x07); \
|
||||
// *zOut++ = 0x80 + (u8)((c>>12) & 0x3F); \
|
||||
// *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); \
|
||||
// *zOut++ = 0x80 + (u8)(c & 0x3F); \
|
||||
// } \
|
||||
//}
|
||||
|
||||
//#define WRITE_UTF16LE(zOut, c) { \
|
||||
// if( c<=0xFFFF ){ \
|
||||
// *zOut++ = (u8)(c&0x00FF); \
|
||||
// *zOut++ = (u8)((c>>8)&0x00FF); \
|
||||
// }else{ \
|
||||
// *zOut++ = (u8)(((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \
|
||||
// *zOut++ = (u8)(0x00D8 + (((c-0x10000)>>18)&0x03)); \
|
||||
// *zOut++ = (u8)(c&0x00FF); \
|
||||
// *zOut++ = (u8)(0x00DC + ((c>>8)&0x03)); \
|
||||
// } \
|
||||
//}
|
||||
|
||||
//#define WRITE_UTF16BE(zOut, c) { \
|
||||
// if( c<=0xFFFF ){ \
|
||||
// *zOut++ = (u8)((c>>8)&0x00FF); \
|
||||
// *zOut++ = (u8)(c&0x00FF); \
|
||||
// }else{ \
|
||||
// *zOut++ = (u8)(0x00D8 + (((c-0x10000)>>18)&0x03)); \
|
||||
// *zOut++ = (u8)(((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \
|
||||
// *zOut++ = (u8)(0x00DC + ((c>>8)&0x03)); \
|
||||
// *zOut++ = (u8)(c&0x00FF); \
|
||||
// } \
|
||||
//}
|
||||
|
||||
//#define READ_UTF16LE(zIn, TERM, c){ \
|
||||
// c = (*zIn++); \
|
||||
// c += ((*zIn++)<<8); \
|
||||
// if( c>=0xD800 && c<0xE000 && TERM ){ \
|
||||
// int c2 = (*zIn++); \
|
||||
// c2 += ((*zIn++)<<8); \
|
||||
// c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \
|
||||
// } \
|
||||
//}
|
||||
|
||||
//#define READ_UTF16BE(zIn, TERM, c){ \
|
||||
// c = ((*zIn++)<<8); \
|
||||
// c += (*zIn++); \
|
||||
// if( c>=0xD800 && c<0xE000 && TERM ){ \
|
||||
// int c2 = ((*zIn++)<<8); \
|
||||
// c2 += (*zIn++); \
|
||||
// c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \
|
||||
// } \
|
||||
//}
|
||||
|
||||
/*
|
||||
** Translate a single UTF-8 character. Return the unicode value.
|
||||
**
|
||||
** During translation, assume that the byte that zTerm points
|
||||
** is a 0x00.
|
||||
**
|
||||
** Write a pointer to the next unread byte back into pzNext.
|
||||
**
|
||||
** Notes On Invalid UTF-8:
|
||||
**
|
||||
** * This routine never allows a 7-bit character (0x00 through 0x7f) to
|
||||
** be encoded as a multi-byte character. Any multi-byte character that
|
||||
** attempts to encode a value between 0x00 and 0x7f is rendered as 0xfffd.
|
||||
**
|
||||
** * This routine never allows a UTF16 surrogate value to be encoded.
|
||||
** If a multi-byte character attempts to encode a value between
|
||||
** 0xd800 and 0xe000 then it is rendered as 0xfffd.
|
||||
**
|
||||
** * Bytes in the range of 0x80 through 0xbf which occur as the first
|
||||
** byte of a character are interpreted as single-byte characters
|
||||
** and rendered as themselves even though they are technically
|
||||
** invalid characters.
|
||||
**
|
||||
** * This routine accepts an infinite number of different UTF8 encodings
|
||||
** for unicode values 0x80 and greater. It do not change over-length
|
||||
** encodings to 0xfffd as some systems recommend.
|
||||
*/
|
||||
|
||||
//#define READ_UTF8(zIn, zTerm, c) \
|
||||
// c = *(zIn++); \
|
||||
// if( c>=0xc0 ){ \
|
||||
// c = sqlite3Utf8Trans1[c-0xc0]; \
|
||||
// while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \
|
||||
// c = (c<<6) + (0x3f & *(zIn++)); \
|
||||
// } \
|
||||
// if( c<0x80 \
|
||||
// || (c&0xFFFFF800)==0xD800 \
|
||||
// || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \
|
||||
// }
|
||||
private static u32 sqlite3Utf8Read(
|
||||
string zIn, /* First byte of UTF-8 character */
|
||||
ref string pzNext /* Write first byte past UTF-8 char here */
|
||||
)
|
||||
{
|
||||
//unsigned int c;
|
||||
/* Same as READ_UTF8() above but without the zTerm parameter.
|
||||
** For this routine, we assume the UTF8 string is always zero-terminated.
|
||||
*/
|
||||
if (String.IsNullOrEmpty(zIn))
|
||||
return 0;
|
||||
//c = *( zIn++ );
|
||||
//if ( c >= 0xc0 )
|
||||
//{
|
||||
// c = sqlite3Utf8Trans1[c - 0xc0];
|
||||
// while ( ( *zIn & 0xc0 ) == 0x80 )
|
||||
// {
|
||||
// c = ( c << 6 ) + ( 0x3f & *( zIn++ ) );
|
||||
// }
|
||||
// if ( c < 0x80
|
||||
// || ( c & 0xFFFFF800 ) == 0xD800
|
||||
// || ( c & 0xFFFFFFFE ) == 0xFFFE ) { c = 0xFFFD; }
|
||||
//}
|
||||
//*pzNext = zIn;
|
||||
int zIndex = 0;
|
||||
u32 c = zIn[zIndex++];
|
||||
if (c >= 0xc0)
|
||||
{
|
||||
//if ( c > 0xff ) c = 0;
|
||||
//else
|
||||
{
|
||||
//c = sqlite3Utf8Trans1[c - 0xc0];
|
||||
while (zIndex != zIn.Length && (zIn[zIndex] & 0xc0) == 0x80)
|
||||
{
|
||||
c = (u32)((c << 6) + (0x3f & zIn[zIndex++]));
|
||||
}
|
||||
if (c < 0x80
|
||||
|| (c & 0xFFFFF800) == 0xD800
|
||||
|| (c & 0xFFFFFFFE) == 0xFFFE)
|
||||
{
|
||||
c = 0xFFFD;
|
||||
}
|
||||
}
|
||||
}
|
||||
pzNext = zIn.Substring(zIndex);
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
** If the TRANSLATE_TRACE macro is defined, the value of each Mem is
|
||||
** printed on stderr on the way into and out of sqlite3VdbeMemTranslate().
|
||||
*/
|
||||
/* #define TRANSLATE_TRACE 1 */
|
||||
|
||||
#if !SQLITE_OMIT_UTF16
|
||||
|
||||
/*
|
||||
** This routine transforms the internal text encoding used by pMem to
|
||||
** desiredEnc. It is an error if the string is already of the desired
|
||||
** encoding, or if pMem does not contain a string value.
|
||||
*/
|
||||
static int sqlite3VdbeMemTranslate(Mem pMem, int desiredEnc){
|
||||
int len; /* Maximum length of output string in bytes */
|
||||
Debugger.Break (); // TODO -
|
||||
//unsigned char *zOut; /* Output buffer */
|
||||
//unsigned char *zIn; /* Input iterator */
|
||||
//unsigned char *zTerm; /* End of input */
|
||||
//unsigned char *z; /* Output iterator */
|
||||
//unsigned int c;
|
||||
|
||||
Debug.Assert( pMem.db==null || sqlite3_mutex_held(pMem.db.mutex) );
|
||||
Debug.Assert( (pMem.flags&MEM_Str )!=0);
|
||||
Debug.Assert( pMem.enc!=desiredEnc );
|
||||
Debug.Assert( pMem.enc!=0 );
|
||||
Debug.Assert( pMem.n>=0 );
|
||||
|
||||
#if TRANSLATE_TRACE && SQLITE_DEBUG
|
||||
{
|
||||
char zBuf[100];
|
||||
sqlite3VdbeMemPrettyPrint(pMem, zBuf);
|
||||
fprintf(stderr, "INPUT: %s\n", zBuf);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If the translation is between UTF-16 little and big endian, then
|
||||
** all that is required is to swap the byte order. This case is handled
|
||||
** differently from the others.
|
||||
*/
|
||||
Debugger.Break (); // TODO -
|
||||
//if( pMem->enc!=SQLITE_UTF8 && desiredEnc!=SQLITE_UTF8 ){
|
||||
// u8 temp;
|
||||
// int rc;
|
||||
// rc = sqlite3VdbeMemMakeWriteable(pMem);
|
||||
// if( rc!=SQLITE_OK ){
|
||||
// Debug.Assert( rc==SQLITE_NOMEM );
|
||||
// return SQLITE_NOMEM;
|
||||
// }
|
||||
// zIn = (u8*)pMem.z;
|
||||
// zTerm = &zIn[pMem->n&~1];
|
||||
// while( zIn<zTerm ){
|
||||
// temp = *zIn;
|
||||
// *zIn = *(zIn+1);
|
||||
// zIn++;
|
||||
// *zIn++ = temp;
|
||||
// }
|
||||
// pMem->enc = desiredEnc;
|
||||
// goto translate_out;
|
||||
//}
|
||||
|
||||
/* Set len to the maximum number of bytes required in the output buffer. */
|
||||
if( desiredEnc==SQLITE_UTF8 ){
|
||||
/* When converting from UTF-16, the maximum growth results from
|
||||
** translating a 2-byte character to a 4-byte UTF-8 character.
|
||||
** A single byte is required for the output string
|
||||
** nul-terminator.
|
||||
*/
|
||||
pMem->n &= ~1;
|
||||
len = pMem.n * 2 + 1;
|
||||
}else{
|
||||
/* When converting from UTF-8 to UTF-16 the maximum growth is caused
|
||||
** when a 1-byte UTF-8 character is translated into a 2-byte UTF-16
|
||||
** character. Two bytes are required in the output buffer for the
|
||||
** nul-terminator.
|
||||
*/
|
||||
len = pMem.n * 2 + 2;
|
||||
}
|
||||
|
||||
/* Set zIn to point at the start of the input buffer and zTerm to point 1
|
||||
** byte past the end.
|
||||
**
|
||||
** Variable zOut is set to point at the output buffer, space obtained
|
||||
** from sqlite3Malloc().
|
||||
*/
|
||||
Debugger.Break (); // TODO -
|
||||
//zIn = (u8*)pMem.z;
|
||||
//zTerm = &zIn[pMem->n];
|
||||
//zOut = sqlite3DbMallocRaw(pMem->db, len);
|
||||
//if( !zOut ){
|
||||
// return SQLITE_NOMEM;
|
||||
//}
|
||||
//z = zOut;
|
||||
|
||||
//if( pMem->enc==SQLITE_UTF8 ){
|
||||
// if( desiredEnc==SQLITE_UTF16LE ){
|
||||
// /* UTF-8 -> UTF-16 Little-endian */
|
||||
// while( zIn<zTerm ){
|
||||
///* c = sqlite3Utf8Read(zIn, zTerm, (const u8**)&zIn); */
|
||||
//READ_UTF8(zIn, zTerm, c);
|
||||
// WRITE_UTF16LE(z, c);
|
||||
// }
|
||||
// }else{
|
||||
// Debug.Assert( desiredEnc==SQLITE_UTF16BE );
|
||||
// /* UTF-8 -> UTF-16 Big-endian */
|
||||
// while( zIn<zTerm ){
|
||||
///* c = sqlite3Utf8Read(zIn, zTerm, (const u8**)&zIn); */
|
||||
//READ_UTF8(zIn, zTerm, c);
|
||||
// WRITE_UTF16BE(z, c);
|
||||
// }
|
||||
// }
|
||||
// pMem->n = (int)(z - zOut);
|
||||
// *z++ = 0;
|
||||
//}else{
|
||||
// Debug.Assert( desiredEnc==SQLITE_UTF8 );
|
||||
// if( pMem->enc==SQLITE_UTF16LE ){
|
||||
// /* UTF-16 Little-endian -> UTF-8 */
|
||||
// while( zIn<zTerm ){
|
||||
// READ_UTF16LE(zIn, zIn<zTerm, c);
|
||||
// WRITE_UTF8(z, c);
|
||||
// }
|
||||
// }else{
|
||||
// /* UTF-16 Big-endian -> UTF-8 */
|
||||
// while( zIn<zTerm ){
|
||||
// READ_UTF16BE(zIn, zIn<zTerm, c);
|
||||
// WRITE_UTF8(z, c);
|
||||
// }
|
||||
// }
|
||||
// pMem->n = (int)(z - zOut);
|
||||
//}
|
||||
//*z = 0;
|
||||
//Debug.Assert( (pMem->n+(desiredEnc==SQLITE_UTF8?1:2))<=len );
|
||||
|
||||
//sqlite3VdbeMemRelease(pMem);
|
||||
//pMem->flags &= ~(MEM_Static|MEM_Dyn|MEM_Ephem);
|
||||
//pMem->enc = desiredEnc;
|
||||
//pMem->flags |= (MEM_Term|MEM_Dyn);
|
||||
//pMem.z = (char*)zOut;
|
||||
//pMem.zMalloc = pMem.z;
|
||||
|
||||
translate_out:
|
||||
#if TRANSLATE_TRACE && SQLITE_DEBUG
|
||||
{
|
||||
char zBuf[100];
|
||||
sqlite3VdbeMemPrettyPrint(pMem, zBuf);
|
||||
fprintf(stderr, "OUTPUT: %s\n", zBuf);
|
||||
}
|
||||
#endif
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine checks for a byte-order mark at the beginning of the
|
||||
** UTF-16 string stored in pMem. If one is present, it is removed and
|
||||
** the encoding of the Mem adjusted. This routine does not do any
|
||||
** byte-swapping, it just sets Mem.enc appropriately.
|
||||
**
|
||||
** The allocation (static, dynamic etc.) and encoding of the Mem may be
|
||||
** changed by this function.
|
||||
*/
|
||||
static int sqlite3VdbeMemHandleBom(Mem pMem){
|
||||
int rc = SQLITE_OK;
|
||||
int bom = 0;
|
||||
byte[] b01 = new byte[2];
|
||||
Encoding.Unicode.GetBytes( pMem.z, 0, 1,b01,0 );
|
||||
assert( pMem->n>=0 );
|
||||
if( pMem->n>1 ){
|
||||
// u8 b1 = *(u8 *)pMem.z;
|
||||
// u8 b2 = *(((u8 *)pMem.z) + 1);
|
||||
if( b01[0]==0xFE && b01[1]==0xFF ){// if( b1==0xFE && b2==0xFF ){
|
||||
bom = SQLITE_UTF16BE;
|
||||
}
|
||||
if( b01[0]==0xFF && b01[1]==0xFE ){ // if( b1==0xFF && b2==0xFE ){
|
||||
bom = SQLITE_UTF16LE;
|
||||
}
|
||||
}
|
||||
|
||||
if( bom!=0 ){
|
||||
rc = sqlite3VdbeMemMakeWriteable(pMem);
|
||||
if( rc==SQLITE_OK ){
|
||||
pMem.n -= 2;
|
||||
Debugger.Break (); // TODO -
|
||||
//memmove(pMem.z, pMem.z[2], pMem.n);
|
||||
//pMem.z[pMem.n] = '\0';
|
||||
//pMem.z[pMem.n+1] = '\0';
|
||||
pMem.flags |= MEM_Term;
|
||||
pMem.enc = bom;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
#endif // * SQLITE_OMIT_UTF16 */
|
||||
|
||||
/*
|
||||
** pZ is a UTF-8 encoded unicode string. If nByte is less than zero,
|
||||
** return the number of unicode characters in pZ up to (but not including)
|
||||
** the first 0x00 byte. If nByte is not less than zero, return the
|
||||
** number of unicode characters in the first nByte of pZ (or up to
|
||||
** the first 0x00, whichever comes first).
|
||||
*/
|
||||
|
||||
private static int sqlite3Utf8CharLen(string zIn, int nByte)
|
||||
{
|
||||
//int r = 0;
|
||||
//string z = zIn;
|
||||
if (zIn.Length == 0)
|
||||
return 0;
|
||||
int zInLength = zIn.Length;
|
||||
int zTerm = (nByte >= 0 && nByte <= zInLength) ? nByte : zInLength;
|
||||
//Debug.Assert( z<=zTerm );
|
||||
//for ( int i = 0 ; i < zTerm ; i++ ) //while( *z!=0 && z<zTerm ){
|
||||
//{
|
||||
// SQLITE_SKIP_UTF8( ref z);// SQLITE_SKIP_UTF8(z);
|
||||
// r++;
|
||||
//}
|
||||
//return r;
|
||||
if (zTerm == zInLength)
|
||||
return zInLength - (zIn[zTerm - 1] == 0 ? 1 : 0);
|
||||
else
|
||||
return nByte;
|
||||
}
|
||||
|
||||
/* This test function is not currently used by the automated test-suite.
|
||||
** Hence it is only available in debug builds.
|
||||
*/
|
||||
#if SQLITE_TEST && SQLITE_DEBUG
|
||||
/*
|
||||
** Translate UTF-8 to UTF-8.
|
||||
**
|
||||
** This has the effect of making sure that the string is well-formed
|
||||
** UTF-8. Miscoded characters are removed.
|
||||
**
|
||||
** The translation is done in-place and aborted if the output
|
||||
** overruns the input.
|
||||
*/
|
||||
static int sqlite3Utf8To8(byte[] zIn){
|
||||
//byte[] zOut = zIn;
|
||||
//byte[] zStart = zIn;
|
||||
//u32 c;
|
||||
|
||||
// while( zIn[0] && zOut<=zIn ){
|
||||
// c = sqlite3Utf8Read(zIn, (const u8**)&zIn);
|
||||
// if( c!=0xfffd ){
|
||||
// WRITE_UTF8(zOut, c);
|
||||
// }
|
||||
//}
|
||||
//zOut = 0;
|
||||
//return (int)(zOut - zStart);
|
||||
try
|
||||
{
|
||||
string z1 = Encoding.UTF8.GetString( zIn, 0, zIn.Length );
|
||||
byte[] zOut = Encoding.UTF8.GetBytes( z1 );
|
||||
//if ( zOut.Length != zIn.Length )
|
||||
// return 0;
|
||||
//else
|
||||
{
|
||||
Array.Copy( zOut, 0, zIn, 0,zIn.Length );
|
||||
return zIn.Length;}
|
||||
}
|
||||
catch ( EncoderFallbackException e )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !SQLITE_OMIT_UTF16
|
||||
/*
|
||||
** Convert a UTF-16 string in the native encoding into a UTF-8 string.
|
||||
** Memory to hold the UTF-8 string is obtained from sqlite3Malloc and must
|
||||
** be freed by the calling function.
|
||||
**
|
||||
** NULL is returned if there is an allocation error.
|
||||
*/
|
||||
static string sqlite3Utf16to8(sqlite3 db, string z, int nByte, u8 enc){
|
||||
Debugger.Break (); // TODO -
|
||||
Mem m = Pool.Allocate_Mem();
|
||||
// memset(&m, 0, sizeof(m));
|
||||
// m.db = db;
|
||||
// sqlite3VdbeMemSetStr(&m, z, nByte, enc, SQLITE_STATIC);
|
||||
// sqlite3VdbeChangeEncoding(&m, SQLITE_UTF8);
|
||||
// if( db.mallocFailed !=0{
|
||||
// sqlite3VdbeMemRelease(&m);
|
||||
// m.z = 0;
|
||||
// }
|
||||
// Debug.Assert( (m.flags & MEM_Term)!=0 || db.mallocFailed !=0);
|
||||
// Debug.Assert( (m.flags & MEM_Str)!=0 || db.mallocFailed !=0);
|
||||
assert( (m.flags & MEM_Dyn)!=0 || db->mallocFailed );
|
||||
assert( m.z || db->mallocFailed );
|
||||
return m.z;
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert a UTF-8 string to the UTF-16 encoding specified by parameter
|
||||
** enc. A pointer to the new string is returned, and the value of *pnOut
|
||||
** is set to the length of the returned string in bytes. The call should
|
||||
** arrange to call sqlite3DbFree() on the returned pointer when it is
|
||||
** no longer required.
|
||||
**
|
||||
** If a malloc failure occurs, NULL is returned and the db.mallocFailed
|
||||
** flag set.
|
||||
*/
|
||||
#if SQLITE_ENABLE_STAT2
|
||||
char *sqlite3Utf8to16(sqlite3 db, u8 enc, char *z, int n, int *pnOut){
|
||||
Mem m;
|
||||
memset(&m, 0, sizeof(m));
|
||||
m.db = db;
|
||||
sqlite3VdbeMemSetStr(&m, z, n, SQLITE_UTF8, SQLITE_STATIC);
|
||||
if( sqlite3VdbeMemTranslate(&m, enc) ){
|
||||
assert( db->mallocFailed );
|
||||
return 0;
|
||||
}
|
||||
assert( m.z==m.zMalloc );
|
||||
*pnOut = m.n;
|
||||
return m.z;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** zIn is a UTF-16 encoded unicode string at least nChar characters long.
|
||||
** Return the number of bytes in the first nChar unicode characters
|
||||
** in pZ. nChar must be non-negative.
|
||||
*/
|
||||
int sqlite3Utf16ByteLen(const void *zIn, int nChar){
|
||||
int c;
|
||||
unsigned char const *z = zIn;
|
||||
int n = 0;
|
||||
|
||||
if( SQLITE_UTF16NATIVE==SQLITE_UTF16BE ){
|
||||
while( n<nChar ){
|
||||
READ_UTF16BE(z, 1, c);
|
||||
n++;
|
||||
}
|
||||
}else{
|
||||
while( n<nChar ){
|
||||
READ_UTF16LE(z, 1, c);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
return (int)(z-(unsigned char const *)zIn);
|
||||
}
|
||||
|
||||
#if SQLITE_TEST
|
||||
/*
|
||||
** This routine is called from the TCL test function "translate_selftest".
|
||||
** It checks that the primitives for serializing and deserializing
|
||||
** characters in each encoding are inverses of each other.
|
||||
*/
|
||||
/*
|
||||
** This routine is called from the TCL test function "translate_selftest".
|
||||
** It checks that the primitives for serializing and deserializing
|
||||
** characters in each encoding are inverses of each other.
|
||||
*/
|
||||
void sqlite3UtfSelfTest(void){
|
||||
unsigned int i, t;
|
||||
unsigned char zBuf[20];
|
||||
unsigned char *z;
|
||||
int n;
|
||||
unsigned int c;
|
||||
|
||||
for(i=0; i<0x00110000; i++){
|
||||
z = zBuf;
|
||||
WRITE_UTF8(z, i);
|
||||
n = (int)(z-zBuf);
|
||||
assert( n>0 && n<=4 );
|
||||
z[0] = 0;
|
||||
z = zBuf;
|
||||
c = sqlite3Utf8Read(z, (const u8**)&z);
|
||||
t = i;
|
||||
if( i>=0xD800 && i<=0xDFFF ) t = 0xFFFD;
|
||||
if( (i&0xFFFFFFFE)==0xFFFE ) t = 0xFFFD;
|
||||
assert( c==t );
|
||||
assert( (z-zBuf)==n );
|
||||
}
|
||||
for(i=0; i<0x00110000; i++){
|
||||
if( i>=0xD800 && i<0xE000 ) continue;
|
||||
z = zBuf;
|
||||
WRITE_UTF16LE(z, i);
|
||||
n = (int)(z-zBuf);
|
||||
assert( n>0 && n<=4 );
|
||||
z[0] = 0;
|
||||
z = zBuf;
|
||||
READ_UTF16LE(z, 1, c);
|
||||
assert( c==i );
|
||||
assert( (z-zBuf)==n );
|
||||
}
|
||||
for(i=0; i<0x00110000; i++){
|
||||
if( i>=0xD800 && i<0xE000 ) continue;
|
||||
z = zBuf;
|
||||
WRITE_UTF16BE(z, i);
|
||||
n = (int)(z-zBuf);
|
||||
assert( n>0 && n<=4 );
|
||||
z[0] = 0;
|
||||
z = zBuf;
|
||||
READ_UTF16BE(z, 1, c);
|
||||
assert( c==i );
|
||||
assert( (z-zBuf)==n );
|
||||
}
|
||||
}
|
||||
#endif // * SQLITE_TEST */
|
||||
#endif // * SQLITE_OMIT_UTF16 */
|
||||
}
|
||||
}
|
||||
1720
original/Community.CsharpSqlite/src/util_c.cs
Normal file
1720
original/Community.CsharpSqlite/src/util_c.cs
Normal file
File diff suppressed because it is too large
Load diff
416
original/Community.CsharpSqlite/src/vacuum_c.cs
Normal file
416
original/Community.CsharpSqlite/src/vacuum_c.cs
Normal file
|
|
@ -0,0 +1,416 @@
|
|||
using System.Diagnostics;
|
||||
|
||||
using u32 = System.UInt32;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
using sqlite3_stmt = Sqlite3.Vdbe;
|
||||
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2003 April 6
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains code used to implement the VACUUM command.
|
||||
**
|
||||
** Most of the code in this file may be omitted by defining the
|
||||
** SQLITE_OMIT_VACUUM macro.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2011-05-19 13:26:54 ed1da510a239ea767a01dc332b667119fa3c908e
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#include "sqliteInt.h"
|
||||
//#include "vdbeInt.h"
|
||||
|
||||
#if !SQLITE_OMIT_VACUUM && !SQLITE_OMIT_ATTACH
|
||||
/*
|
||||
** Finalize a prepared statement. If there was an error, store the
|
||||
** text of the error message in *pzErrMsg. Return the result code.
|
||||
*/
|
||||
|
||||
private static int vacuumFinalize(sqlite3 db, sqlite3_stmt pStmt, string pzErrMsg)
|
||||
{
|
||||
int rc;
|
||||
rc = sqlite3VdbeFinalize(ref pStmt);
|
||||
if (rc != 0)
|
||||
{
|
||||
sqlite3SetString(ref pzErrMsg, db, sqlite3_errmsg(db));
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Execute zSql on database db. Return an error code.
|
||||
*/
|
||||
|
||||
private static int execSql(sqlite3 db, string pzErrMsg, string zSql)
|
||||
{
|
||||
sqlite3_stmt pStmt = null;
|
||||
#if !NDEBUG
|
||||
int rc;
|
||||
//VVA_ONLY( int rc; )
|
||||
#endif
|
||||
if (zSql == null)
|
||||
{
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
if (SQLITE_OK != sqlite3_prepare(db, zSql, -1, ref pStmt, 0))
|
||||
{
|
||||
sqlite3SetString(ref pzErrMsg, db, sqlite3_errmsg(db));
|
||||
return sqlite3_errcode(db);
|
||||
}
|
||||
#if !NDEBUG
|
||||
rc = sqlite3_step(pStmt);
|
||||
//VVA_ONLY( rc = ) sqlite3_step(pStmt);
|
||||
Debug.Assert(rc != SQLITE_ROW);
|
||||
#else
|
||||
sqlite3_step(pStmt);
|
||||
#endif
|
||||
return vacuumFinalize(db, pStmt, pzErrMsg);
|
||||
}
|
||||
|
||||
/*
|
||||
** Execute zSql on database db. The statement returns exactly
|
||||
** one column. Execute this as SQL on the same database.
|
||||
*/
|
||||
|
||||
private static int execExecSql(sqlite3 db, string pzErrMsg, string zSql)
|
||||
{
|
||||
sqlite3_stmt pStmt = null;
|
||||
int rc;
|
||||
|
||||
rc = sqlite3_prepare(db, zSql, -1, ref pStmt, 0);
|
||||
if (rc != SQLITE_OK)
|
||||
return rc;
|
||||
|
||||
while (SQLITE_ROW == sqlite3_step(pStmt))
|
||||
{
|
||||
rc = execSql(db, pzErrMsg, sqlite3_column_text(pStmt, 0));
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
vacuumFinalize(db, pStmt, pzErrMsg);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return vacuumFinalize(db, pStmt, pzErrMsg);
|
||||
}
|
||||
|
||||
/*
|
||||
** The non-standard VACUUM command is used to clean up the database,
|
||||
** collapse free space, etc. It is modelled after the VACUUM command
|
||||
** in PostgreSQL.
|
||||
**
|
||||
** In version 1.0.x of SQLite, the VACUUM command would call
|
||||
** gdbm_reorganize() on all the database tables. But beginning
|
||||
** with 2.0.0, SQLite no longer uses GDBM so this command has
|
||||
** become a no-op.
|
||||
*/
|
||||
|
||||
private static void sqlite3Vacuum(Parse pParse)
|
||||
{
|
||||
Vdbe v = sqlite3GetVdbe(pParse);
|
||||
if (v != null)
|
||||
{
|
||||
sqlite3VdbeAddOp2(v, OP_Vacuum, 0, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine implements the OP_Vacuum opcode of the VDBE.
|
||||
*/
|
||||
|
||||
private static int sqlite3RunVacuum(ref string pzErrMsg, sqlite3 db)
|
||||
{
|
||||
int rc = SQLITE_OK; /* Return code from service routines */
|
||||
Btree pMain; /* The database being vacuumed */
|
||||
Btree pTemp; /* The temporary database we vacuum into */
|
||||
string zSql = ""; /* SQL statements */
|
||||
int saved_flags; /* Saved value of the db.flags */
|
||||
int saved_nChange; /* Saved value of db.nChange */
|
||||
int saved_nTotalChange; /* Saved value of db.nTotalChange */
|
||||
dxTrace saved_xTrace; //void (*saved_xTrace)(void*,const char*); /* Saved db->xTrace */
|
||||
Db pDb = null; /* Database to detach at end of vacuum */
|
||||
bool isMemDb; /* True if vacuuming a :memory: database */
|
||||
int nRes; /* Bytes of reserved space at the end of each page */
|
||||
int nDb; /* Number of attached databases */
|
||||
|
||||
if (0 == db.autoCommit)
|
||||
{
|
||||
sqlite3SetString(ref pzErrMsg, db, "cannot VACUUM from within a transaction");
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
if (db.activeVdbeCnt > 1)
|
||||
{
|
||||
sqlite3SetString(ref pzErrMsg, db, "cannot VACUUM - SQL statements in progress");
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
/* Save the current value of the database flags so that it can be
|
||||
** restored before returning. Then set the writable-schema flag, and
|
||||
** disable CHECK and foreign key constraints. */
|
||||
saved_flags = db.flags;
|
||||
saved_nChange = db.nChange;
|
||||
saved_nTotalChange = db.nTotalChange;
|
||||
saved_xTrace = db.xTrace;
|
||||
db.flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks | SQLITE_PreferBuiltin;
|
||||
db.flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder);
|
||||
|
||||
db.xTrace = null;
|
||||
|
||||
pMain = db.aDb[0].pBt;
|
||||
isMemDb = sqlite3PagerIsMemdb(sqlite3BtreePager(pMain));
|
||||
|
||||
/* Attach the temporary database as 'vacuum_db'. The synchronous pragma
|
||||
** can be set to 'off' for this file, as it is not recovered if a crash
|
||||
** occurs anyway. The integrity of the database is maintained by a
|
||||
** (possibly synchronous) transaction opened on the main database before
|
||||
** sqlite3BtreeCopyFile() is called.
|
||||
**
|
||||
** An optimisation would be to use a non-journaled pager.
|
||||
** (Later:) I tried setting "PRAGMA vacuum_db.journal_mode=OFF" but
|
||||
** that actually made the VACUUM run slower. Very little journalling
|
||||
** actually occurs when doing a vacuum since the vacuum_db is initially
|
||||
** empty. Only the journal header is written. Apparently it takes more
|
||||
** time to parse and run the PRAGMA to turn journalling off than it does
|
||||
** to write the journal header file.
|
||||
*/
|
||||
nDb = db.nDb;
|
||||
if (sqlite3TempInMemory(db))
|
||||
{
|
||||
zSql = "ATTACH ':memory:' AS vacuum_db;";
|
||||
}
|
||||
else
|
||||
{
|
||||
zSql = "ATTACH '' AS vacuum_db;";
|
||||
}
|
||||
rc = execSql(db, pzErrMsg, zSql);
|
||||
if (db.nDb > nDb)
|
||||
{
|
||||
pDb = db.aDb[db.nDb - 1];
|
||||
Debug.Assert(pDb.zName == "vacuum_db");
|
||||
}
|
||||
if (rc != SQLITE_OK)
|
||||
goto end_of_vacuum;
|
||||
pDb = db.aDb[db.nDb - 1];
|
||||
Debug.Assert(db.aDb[db.nDb - 1].zName == "vacuum_db");
|
||||
pTemp = db.aDb[db.nDb - 1].pBt;
|
||||
|
||||
/* The call to execSql() to attach the temp database has left the file
|
||||
** locked (as there was more than one active statement when the transaction
|
||||
** to read the schema was concluded. Unlock it here so that this doesn't
|
||||
** cause problems for the call to BtreeSetPageSize() below. */
|
||||
sqlite3BtreeCommit(pTemp);
|
||||
|
||||
nRes = sqlite3BtreeGetReserve(pMain);
|
||||
|
||||
/* A VACUUM cannot change the pagesize of an encrypted database. */
|
||||
#if SQLITE_HAS_CODEC
|
||||
if (db.nextPagesize != 0)
|
||||
{
|
||||
//extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
|
||||
int nKey;
|
||||
string zKey;
|
||||
sqlite3CodecGetKey(db, 0, out zKey, out nKey); // sqlite3CodecGetKey(db, 0, (void**)&zKey, nKey);
|
||||
if (nKey != 0)
|
||||
db.nextPagesize = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Do not attempt to change the page size for a WAL database */
|
||||
if (sqlite3PagerGetJournalMode(sqlite3BtreePager(pMain))
|
||||
== PAGER_JOURNALMODE_WAL)
|
||||
{
|
||||
db.nextPagesize = 0;
|
||||
}
|
||||
|
||||
if (sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain), nRes, 0) != 0
|
||||
|| (!isMemDb && sqlite3BtreeSetPageSize(pTemp, db.nextPagesize, nRes, 0) != 0)
|
||||
//|| NEVER( db.mallocFailed != 0 )
|
||||
)
|
||||
{
|
||||
rc = SQLITE_NOMEM;
|
||||
goto end_of_vacuum;
|
||||
}
|
||||
rc = execSql(db, pzErrMsg, "PRAGMA vacuum_db.synchronous=OFF");
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
goto end_of_vacuum;
|
||||
}
|
||||
|
||||
#if !SQLITE_OMIT_AUTOVACUUM
|
||||
sqlite3BtreeSetAutoVacuum(pTemp, db.nextAutovac >= 0 ? db.nextAutovac :
|
||||
sqlite3BtreeGetAutoVacuum(pMain));
|
||||
#endif
|
||||
|
||||
/* Begin a transaction */
|
||||
rc = execSql(db, pzErrMsg, "BEGIN EXCLUSIVE;");
|
||||
if (rc != SQLITE_OK)
|
||||
goto end_of_vacuum;
|
||||
|
||||
/* Query the schema of the main database. Create a mirror schema
|
||||
** in the temporary database.
|
||||
*/
|
||||
rc = execExecSql(db, pzErrMsg,
|
||||
"SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14) " +
|
||||
" FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'" +
|
||||
" AND rootpage>0"
|
||||
);
|
||||
if (rc != SQLITE_OK)
|
||||
goto end_of_vacuum;
|
||||
rc = execExecSql(db, pzErrMsg,
|
||||
"SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14)" +
|
||||
" FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %' ");
|
||||
if (rc != SQLITE_OK)
|
||||
goto end_of_vacuum;
|
||||
rc = execExecSql(db, pzErrMsg,
|
||||
"SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21) " +
|
||||
" FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'");
|
||||
if (rc != SQLITE_OK)
|
||||
goto end_of_vacuum;
|
||||
|
||||
/* Loop through the tables in the main database. For each, do
|
||||
** an "INSERT INTO vacuum_db.xxx SELECT * FROM main.xxx;" to copy
|
||||
** the contents to the temporary database.
|
||||
*/
|
||||
rc = execExecSql(db, pzErrMsg,
|
||||
"SELECT 'INSERT INTO vacuum_db.' || quote(name) " +
|
||||
"|| ' SELECT * FROM main.' || quote(name) || ';'" +
|
||||
"FROM main.sqlite_master " +
|
||||
"WHERE type = 'table' AND name!='sqlite_sequence' " +
|
||||
" AND rootpage>0"
|
||||
|
||||
);
|
||||
if (rc != SQLITE_OK)
|
||||
goto end_of_vacuum;
|
||||
|
||||
/* Copy over the sequence table
|
||||
*/
|
||||
rc = execExecSql(db, pzErrMsg,
|
||||
"SELECT 'DELETE FROM vacuum_db.' || quote(name) || ';' " +
|
||||
"FROM vacuum_db.sqlite_master WHERE name='sqlite_sequence' "
|
||||
);
|
||||
if (rc != SQLITE_OK)
|
||||
goto end_of_vacuum;
|
||||
rc = execExecSql(db, pzErrMsg,
|
||||
"SELECT 'INSERT INTO vacuum_db.' || quote(name) " +
|
||||
"|| ' SELECT * FROM main.' || quote(name) || ';' " +
|
||||
"FROM vacuum_db.sqlite_master WHERE name=='sqlite_sequence';"
|
||||
);
|
||||
if (rc != SQLITE_OK)
|
||||
goto end_of_vacuum;
|
||||
|
||||
/* Copy the triggers, views, and virtual tables from the main database
|
||||
** over to the temporary database. None of these objects has any
|
||||
** associated storage, so all we have to do is copy their entries
|
||||
** from the SQLITE_MASTER table.
|
||||
*/
|
||||
rc = execSql(db, pzErrMsg,
|
||||
"INSERT INTO vacuum_db.sqlite_master " +
|
||||
" SELECT type, name, tbl_name, rootpage, sql" +
|
||||
" FROM main.sqlite_master" +
|
||||
" WHERE type='view' OR type='trigger'" +
|
||||
" OR (type='table' AND rootpage=0)"
|
||||
);
|
||||
if (rc != 0)
|
||||
goto end_of_vacuum;
|
||||
|
||||
/* At this point, unless the main db was completely empty, there is now a
|
||||
** transaction open on the vacuum database, but not on the main database.
|
||||
** Open a btree level transaction on the main database. This allows a
|
||||
** call to sqlite3BtreeCopyFile(). The main database btree level
|
||||
** transaction is then committed, so the SQL level never knows it was
|
||||
** opened for writing. This way, the SQL transaction used to create the
|
||||
** temporary database never needs to be committed.
|
||||
*/
|
||||
{
|
||||
u32 meta = 0;
|
||||
int i;
|
||||
|
||||
/* This array determines which meta meta values are preserved in the
|
||||
** vacuum. Even entries are the meta value number and odd entries
|
||||
** are an increment to apply to the meta value after the vacuum.
|
||||
** The increment is used to increase the schema cookie so that other
|
||||
** connections to the same database will know to reread the schema.
|
||||
*/
|
||||
byte[] aCopy = new byte[] {
|
||||
BTREE_SCHEMA_VERSION, 1, /* Add one to the old schema cookie */
|
||||
BTREE_DEFAULT_CACHE_SIZE, 0, /* Preserve the default page cache size */
|
||||
BTREE_TEXT_ENCODING, 0, /* Preserve the text encoding */
|
||||
BTREE_USER_VERSION, 0, /* Preserve the user version */
|
||||
};
|
||||
|
||||
Debug.Assert(sqlite3BtreeIsInTrans(pTemp));
|
||||
Debug.Assert(sqlite3BtreeIsInTrans(pMain));
|
||||
|
||||
/* Copy Btree meta values */
|
||||
for (i = 0; i < ArraySize(aCopy); i += 2)
|
||||
{
|
||||
/* GetMeta() and UpdateMeta() cannot fail in this context because
|
||||
** we already have page 1 loaded into cache and marked dirty. */
|
||||
sqlite3BtreeGetMeta(pMain, aCopy[i], ref meta);
|
||||
rc = sqlite3BtreeUpdateMeta(pTemp, aCopy[i], (u32)(meta + aCopy[i + 1]));
|
||||
if (NEVER(rc != SQLITE_OK))
|
||||
goto end_of_vacuum;
|
||||
}
|
||||
|
||||
rc = sqlite3BtreeCopyFile(pMain, pTemp);
|
||||
if (rc != SQLITE_OK)
|
||||
goto end_of_vacuum;
|
||||
rc = sqlite3BtreeCommit(pTemp);
|
||||
if (rc != SQLITE_OK)
|
||||
goto end_of_vacuum;
|
||||
#if !SQLITE_OMIT_AUTOVACUUM
|
||||
sqlite3BtreeSetAutoVacuum(pMain, sqlite3BtreeGetAutoVacuum(pTemp));
|
||||
#endif
|
||||
}
|
||||
Debug.Assert(rc == SQLITE_OK);
|
||||
rc = sqlite3BtreeSetPageSize(pMain, sqlite3BtreeGetPageSize(pTemp), nRes, 1);
|
||||
|
||||
end_of_vacuum:
|
||||
/* Restore the original value of db.flags */
|
||||
db.flags = saved_flags;
|
||||
db.nChange = saved_nChange;
|
||||
db.nTotalChange = saved_nTotalChange;
|
||||
db.xTrace = saved_xTrace;
|
||||
sqlite3BtreeSetPageSize(pMain, -1, -1, 1);
|
||||
|
||||
/* Currently there is an SQL level transaction open on the vacuum
|
||||
** database. No locks are held on any other files (since the main file
|
||||
** was committed at the btree level). So it safe to end the transaction
|
||||
** by manually setting the autoCommit flag to true and detaching the
|
||||
** vacuum database. The vacuum_db journal file is deleted when the pager
|
||||
** is closed by the DETACH.
|
||||
*/
|
||||
db.autoCommit = 1;
|
||||
|
||||
if (pDb != null)
|
||||
{
|
||||
sqlite3BtreeClose(ref pDb.pBt);
|
||||
pDb.pBt = null;
|
||||
pDb.pSchema = null;
|
||||
}
|
||||
|
||||
/* This both clears the schemas and reduces the size of the db->aDb[]
|
||||
** array. */
|
||||
sqlite3ResetInternalSchema(db, -1);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif // * SQLITE_OMIT_VACUUM && SQLITE_OMIT_ATTACH */
|
||||
}
|
||||
}
|
||||
7093
original/Community.CsharpSqlite/src/vdbe_c.cs
Normal file
7093
original/Community.CsharpSqlite/src/vdbe_c.cs
Normal file
File diff suppressed because it is too large
Load diff
1675
original/Community.CsharpSqlite/src/vdbeapi_c.cs
Normal file
1675
original/Community.CsharpSqlite/src/vdbeapi_c.cs
Normal file
File diff suppressed because it is too large
Load diff
4401
original/Community.CsharpSqlite/src/vdbeaux_c.cs
Normal file
4401
original/Community.CsharpSqlite/src/vdbeaux_c.cs
Normal file
File diff suppressed because it is too large
Load diff
399
original/Community.CsharpSqlite/src/vdbeblob_c.cs
Normal file
399
original/Community.CsharpSqlite/src/vdbeblob_c.cs
Normal file
|
|
@ -0,0 +1,399 @@
|
|||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2007 May 1
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This file contains code used to implement incremental BLOB I/O.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#include "sqliteInt.h"
|
||||
//#include "vdbeInt.h"
|
||||
|
||||
#if !SQLITE_OMIT_INCRBLOB
|
||||
/*
|
||||
** Valid sqlite3_blob* handles point to Incrblob structures.
|
||||
*/
|
||||
typedef struct Incrblob Incrblob;
|
||||
struct Incrblob {
|
||||
int flags; /* Copy of "flags" passed to sqlite3_blob_open() */
|
||||
int nByte; /* Size of open blob, in bytes */
|
||||
int iOffset; /* Byte offset of blob in cursor data */
|
||||
BtCursor *pCsr; /* Cursor pointing at blob row */
|
||||
sqlite3_stmt *pStmt; /* Statement holding cursor open */
|
||||
sqlite3 db; /* The associated database */
|
||||
};
|
||||
|
||||
/*
|
||||
** Open a blob handle.
|
||||
*/
|
||||
int sqlite3_blob_open(
|
||||
sqlite3* db, /* The database connection */
|
||||
string zDb, /* The attached database containing the blob */
|
||||
string zTable, /* The table containing the blob */
|
||||
string zColumn, /* The column containing the blob */
|
||||
sqlite_int64 iRow, /* The row containing the glob */
|
||||
int flags, /* True -> read/write access, false -> read-only */
|
||||
sqlite3_blob **ppBlob /* Handle for accessing the blob returned here */
|
||||
){
|
||||
int nAttempt = 0;
|
||||
int iCol; /* Index of zColumn in row-record */
|
||||
|
||||
/* This VDBE program seeks a btree cursor to the identified
|
||||
** db/table/row entry. The reason for using a vdbe program instead
|
||||
** of writing code to use the b-tree layer directly is that the
|
||||
** vdbe program will take advantage of the various transaction,
|
||||
** locking and error handling infrastructure built into the vdbe.
|
||||
**
|
||||
** After seeking the cursor, the vdbe executes an OP_ResultRow.
|
||||
** Code external to the Vdbe then "borrows" the b-tree cursor and
|
||||
** uses it to implement the blob_read(), blob_write() and
|
||||
** blob_bytes() functions.
|
||||
**
|
||||
** The sqlite3_blob_close() function finalizes the vdbe program,
|
||||
** which closes the b-tree cursor and (possibly) commits the
|
||||
** transaction.
|
||||
*/
|
||||
static const VdbeOpList openBlob[] = {
|
||||
{OP_Transaction, 0, 0, 0}, /* 0: Start a transaction */
|
||||
{OP_VerifyCookie, 0, 0, 0}, /* 1: Check the schema cookie */
|
||||
{OP_TableLock, 0, 0, 0}, /* 2: Acquire a read or write lock */
|
||||
|
||||
/* One of the following two instructions is replaced by an OP_Noop. */
|
||||
{OP_OpenRead, 0, 0, 0}, /* 3: Open cursor 0 for reading */
|
||||
{OP_OpenWrite, 0, 0, 0}, /* 4: Open cursor 0 for read/write */
|
||||
|
||||
{OP_Variable, 1, 1, 1}, /* 5: Push the rowid to the stack */
|
||||
{OP_NotExists, 0, 9, 1}, /* 6: Seek the cursor */
|
||||
{OP_Column, 0, 0, 1}, /* 7 */
|
||||
{OP_ResultRow, 1, 0, 0}, /* 8 */
|
||||
{OP_Close, 0, 0, 0}, /* 9 */
|
||||
{OP_Halt, 0, 0, 0}, /* 10 */
|
||||
};
|
||||
|
||||
Vdbe *v = 0;
|
||||
int rc = SQLITE_OK;
|
||||
string zErr = 0;
|
||||
Table *pTab;
|
||||
Parse *pParse;
|
||||
|
||||
*ppBlob = 0;
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
pParse = sqlite3StackAllocRaw(db, sizeof(*pParse));
|
||||
if( pParse==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto blob_open_out;
|
||||
}
|
||||
do {
|
||||
memset(pParse, 0, sizeof(Parse));
|
||||
pParse->db = db;
|
||||
|
||||
sqlite3BtreeEnterAll(db);
|
||||
pTab = sqlite3LocateTable(pParse, 0, zTable, zDb);
|
||||
if( pTab && IsVirtual(pTab) ){
|
||||
pTab = 0;
|
||||
sqlite3ErrorMsg(pParse, "cannot open virtual table: %s", zTable);
|
||||
}
|
||||
#if !SQLITE_OMIT_VIEW
|
||||
if( pTab && pTab->pSelect ){
|
||||
pTab = 0;
|
||||
sqlite3ErrorMsg(pParse, "cannot open view: %s", zTable);
|
||||
}
|
||||
#endif
|
||||
if( null==pTab ){
|
||||
if( pParse->zErrMsg ){
|
||||
sqlite3DbFree(db, zErr);
|
||||
zErr = pParse->zErrMsg;
|
||||
pParse->zErrMsg = 0;
|
||||
}
|
||||
rc = SQLITE_ERROR;
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
goto blob_open_out;
|
||||
}
|
||||
|
||||
/* Now search pTab for the exact column. */
|
||||
for(iCol=0; iCol < pTab->nCol; iCol++) {
|
||||
if( sqlite3StrICmp(pTab->aCol[iCol].zName, zColumn)==0 ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( iCol==pTab->nCol ){
|
||||
sqlite3DbFree(db, zErr);
|
||||
zErr = sqlite3MPrintf(db, "no such column: \"%s\"", zColumn);
|
||||
rc = SQLITE_ERROR;
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
goto blob_open_out;
|
||||
}
|
||||
|
||||
/* If the value is being opened for writing, check that the
|
||||
** column is not indexed, and that it is not part of a foreign key.
|
||||
** It is against the rules to open a column to which either of these
|
||||
** descriptions applies for writing. */
|
||||
if( flags ){
|
||||
string zFault = 0;
|
||||
Index *pIdx;
|
||||
#if !SQLITE_OMIT_FOREIGN_KEY
|
||||
if( db->flags&SQLITE_ForeignKeys ){
|
||||
/* Check that the column is not part of an FK child key definition. It
|
||||
** is not necessary to check if it is part of a parent key, as parent
|
||||
** key columns must be indexed. The check below will pick up this
|
||||
** case. */
|
||||
FKey *pFKey;
|
||||
for(pFKey=pTab->pFKey; pFKey; pFKey=pFKey->pNextFrom){
|
||||
int j;
|
||||
for(j=0; j<pFKey->nCol; j++){
|
||||
if( pFKey->aCol[j].iFrom==iCol ){
|
||||
zFault = "foreign key";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
int j;
|
||||
for(j=0; j<pIdx->nColumn; j++){
|
||||
if( pIdx->aiColumn[j]==iCol ){
|
||||
zFault = "indexed";
|
||||
}
|
||||
}
|
||||
}
|
||||
if( zFault ){
|
||||
sqlite3DbFree(db, zErr);
|
||||
zErr = sqlite3MPrintf(db, "cannot open %s column for writing", zFault);
|
||||
rc = SQLITE_ERROR;
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
goto blob_open_out;
|
||||
}
|
||||
}
|
||||
|
||||
v = sqlite3VdbeCreate(db);
|
||||
if( v ){
|
||||
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
sqlite3VdbeAddOpList(v, sizeof(openBlob)/sizeof(VdbeOpList), openBlob);
|
||||
flags = !!flags; /* flags = (flags ? 1 : 0); */
|
||||
|
||||
/* Configure the OP_Transaction */
|
||||
sqlite3VdbeChangeP1(v, 0, iDb);
|
||||
sqlite3VdbeChangeP2(v, 0, flags);
|
||||
|
||||
/* Configure the OP_VerifyCookie */
|
||||
sqlite3VdbeChangeP1(v, 1, iDb);
|
||||
sqlite3VdbeChangeP2(v, 1, pTab->pSchema->schema_cookie);
|
||||
sqlite3VdbeChangeP3(v, 1, pTab->pSchema->iGeneration);
|
||||
|
||||
/* Make sure a mutex is held on the table to be accessed */
|
||||
sqlite3VdbeUsesBtree(v, iDb);
|
||||
|
||||
/* Configure the OP_TableLock instruction */
|
||||
#if SQLITE_OMIT_SHARED_CACHE
|
||||
sqlite3VdbeChangeToNoop(v, 2, 1);
|
||||
#else
|
||||
sqlite3VdbeChangeP1(v, 2, iDb);
|
||||
sqlite3VdbeChangeP2(v, 2, pTab->tnum);
|
||||
sqlite3VdbeChangeP3(v, 2, flags);
|
||||
sqlite3VdbeChangeP4(v, 2, pTab->zName, P4_TRANSIENT);
|
||||
#endif
|
||||
|
||||
/* Remove either the OP_OpenWrite or OpenRead. Set the P2
|
||||
** parameter of the other to pTab->tnum. */
|
||||
sqlite3VdbeChangeToNoop(v, 4 - flags, 1);
|
||||
sqlite3VdbeChangeP2(v, 3 + flags, pTab->tnum);
|
||||
sqlite3VdbeChangeP3(v, 3 + flags, iDb);
|
||||
|
||||
/* Configure the number of columns. Configure the cursor to
|
||||
** think that the table has one more column than it really
|
||||
** does. An OP_Column to retrieve this imaginary column will
|
||||
** always return an SQL NULL. This is useful because it means
|
||||
** we can invoke OP_Column to fill in the vdbe cursors type
|
||||
** and offset cache without causing any IO.
|
||||
*/
|
||||
sqlite3VdbeChangeP4(v, 3+flags, SQLITE_INT_TO_PTR(pTab->nCol+1),P4_INT32);
|
||||
sqlite3VdbeChangeP2(v, 7, pTab->nCol);
|
||||
if( null==db->mallocFailed ){
|
||||
pParse->nVar = 1;
|
||||
pParse->nMem = 1;
|
||||
pParse->nTab = 1;
|
||||
sqlite3VdbeMakeReady(v, pParse);
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
goto blob_open_out;
|
||||
}
|
||||
|
||||
sqlite3_bind_int64((sqlite3_stmt )v, 1, iRow);
|
||||
rc = sqlite3_step((sqlite3_stmt )v);
|
||||
if( rc!=SQLITE_ROW ){
|
||||
nAttempt++;
|
||||
rc = sqlite3_finalize((sqlite3_stmt )v);
|
||||
sqlite3DbFree(db, zErr);
|
||||
zErr = sqlite3MPrintf(db, sqlite3_errmsg(db));
|
||||
v = 0;
|
||||
}
|
||||
} while( nAttempt<5 && rc==SQLITE_SCHEMA );
|
||||
|
||||
if( rc==SQLITE_ROW ){
|
||||
/* The row-record has been opened successfully. Check that the
|
||||
** column in question contains text or a blob. If it contains
|
||||
** text, it is up to the caller to get the encoding right.
|
||||
*/
|
||||
Incrblob *pBlob;
|
||||
u32 type = v->apCsr[0]->aType[iCol];
|
||||
|
||||
if( type<12 ){
|
||||
sqlite3DbFree(db, zErr);
|
||||
zErr = sqlite3MPrintf(db, "cannot open value of type %s",
|
||||
type==0?"null": type==7?"real": "integer"
|
||||
);
|
||||
rc = SQLITE_ERROR;
|
||||
goto blob_open_out;
|
||||
}
|
||||
pBlob = (Incrblob )sqlite3DbMallocZero(db, sizeof(Incrblob));
|
||||
if( db->mallocFailed ){
|
||||
sqlite3DbFree(db, ref pBlob);
|
||||
goto blob_open_out;
|
||||
}
|
||||
pBlob->flags = flags;
|
||||
pBlob->pCsr = v->apCsr[0]->pCursor;
|
||||
sqlite3BtreeEnterCursor(pBlob->pCsr);
|
||||
sqlite3BtreeCacheOverflow(pBlob->pCsr);
|
||||
sqlite3BtreeLeaveCursor(pBlob->pCsr);
|
||||
pBlob->pStmt = (sqlite3_stmt )v;
|
||||
pBlob->iOffset = v->apCsr[0]->aOffset[iCol];
|
||||
pBlob->nByte = sqlite3VdbeSerialTypeLen(type);
|
||||
pBlob->db = db;
|
||||
*ppBlob = (sqlite3_blob )pBlob;
|
||||
rc = SQLITE_OK;
|
||||
}else if( rc==SQLITE_OK ){
|
||||
sqlite3DbFree(db, zErr);
|
||||
zErr = sqlite3MPrintf(db, "no such rowid: %lld", iRow);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
|
||||
blob_open_out:
|
||||
if( v && (rc!=SQLITE_OK || db->mallocFailed) ){
|
||||
sqlite3VdbeFinalize(v);
|
||||
}
|
||||
sqlite3Error(db, rc, zErr);
|
||||
sqlite3DbFree(db, zErr);
|
||||
sqlite3StackFree(db, pParse);
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Close a blob handle that was previously created using
|
||||
** sqlite3_blob_open().
|
||||
*/
|
||||
int sqlite3_blob_close(sqlite3_blob *pBlob){
|
||||
Incrblob *p = (Incrblob )pBlob;
|
||||
int rc;
|
||||
sqlite3 db;
|
||||
|
||||
if( p ){
|
||||
db = p->db;
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
rc = sqlite3_finalize(p->pStmt);
|
||||
sqlite3DbFree(db, ref p);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
}else{
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Perform a read or write operation on a blob
|
||||
*/
|
||||
static int blobReadWrite(
|
||||
sqlite3_blob *pBlob,
|
||||
void *z,
|
||||
int n,
|
||||
int iOffset,
|
||||
int (*xCall)(BtCursor*, u32, u32, void)
|
||||
){
|
||||
int rc;
|
||||
Incrblob *p = (Incrblob )pBlob;
|
||||
Vdbe *v;
|
||||
sqlite3 db;
|
||||
|
||||
if( p==0 ) return SQLITE_MISUSE_BKPT();
|
||||
db = p->db;
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
v = (Vdbe)p->pStmt;
|
||||
|
||||
if( n<0 || iOffset<0 || (iOffset+n)>p->nByte ){
|
||||
/* Request is out of range. Return a transient error. */
|
||||
rc = SQLITE_ERROR;
|
||||
sqlite3Error(db, SQLITE_ERROR, 0);
|
||||
} else if( v==0 ){
|
||||
/* If there is no statement handle, then the blob-handle has
|
||||
** already been invalidated. Return SQLITE_ABORT in this case.
|
||||
*/
|
||||
rc = SQLITE_ABORT;
|
||||
}else{
|
||||
/* Call either BtreeData() or BtreePutData(). If SQLITE_ABORT is
|
||||
** returned, clean-up the statement handle.
|
||||
*/
|
||||
Debug.Assert( db == v->db );
|
||||
sqlite3BtreeEnterCursor(p->pCsr);
|
||||
rc = xCall(p->pCsr, iOffset+p->iOffset, n, z);
|
||||
sqlite3BtreeLeaveCursor(p->pCsr);
|
||||
if( rc==SQLITE_ABORT ){
|
||||
sqlite3VdbeFinalize(v);
|
||||
p->pStmt = null;
|
||||
}else{
|
||||
db->errCode = rc;
|
||||
v->rc = rc;
|
||||
}
|
||||
}
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Read data from a blob handle.
|
||||
*/
|
||||
int sqlite3_blob_read(sqlite3_blob *pBlob, object *z, int n, int iOffset){
|
||||
return blobReadWrite(pBlob, z, n, iOffset, sqlite3BtreeData);
|
||||
}
|
||||
|
||||
/*
|
||||
** Write data to a blob handle.
|
||||
*/
|
||||
int sqlite3_blob_write(sqlite3_blob *pBlob, string z, int n, int iOffset){
|
||||
return blobReadWrite(pBlob, (void )z, n, iOffset, sqlite3BtreePutData);
|
||||
}
|
||||
|
||||
/*
|
||||
** Query a blob handle for the size of the data.
|
||||
**
|
||||
** The Incrblob.nByte field is fixed for the lifetime of the Incrblob
|
||||
** so no mutex is required for access.
|
||||
*/
|
||||
int sqlite3_blob_bytes(sqlite3_blob *pBlob){
|
||||
Incrblob *p = (Incrblob )pBlob;
|
||||
return p ? p->nByte : 0;
|
||||
}
|
||||
|
||||
#endif // * #if !SQLITE_OMIT_INCRBLOB */
|
||||
}
|
||||
}
|
||||
1640
original/Community.CsharpSqlite/src/vdbemem_c.cs
Normal file
1640
original/Community.CsharpSqlite/src/vdbemem_c.cs
Normal file
File diff suppressed because it is too large
Load diff
200
original/Community.CsharpSqlite/src/vdbetrace_c.cs
Normal file
200
original/Community.CsharpSqlite/src/vdbetrace_c.cs
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
using System.Diagnostics;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2009 November 25
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This file contains code used to insert the values of host parameters
|
||||
** (aka "wildcards") into the SQL text output by sqlite3_trace().
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2011-05-19 13:26:54 ed1da510a239ea767a01dc332b667119fa3c908e
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#include "sqliteInt.h"
|
||||
//#include "vdbeInt.h"
|
||||
|
||||
#if !SQLITE_OMIT_TRACE
|
||||
|
||||
/*
|
||||
** zSql is a zero-terminated string of UTF-8 SQL text. Return the number of
|
||||
** bytes in this text up to but excluding the first character in
|
||||
** a host parameter. If the text contains no host parameters, return
|
||||
** the total number of bytes in the text.
|
||||
*/
|
||||
|
||||
private static int findNextHostParameter(string zSql, int iOffset, ref int pnToken)
|
||||
{
|
||||
int tokenType = 0;
|
||||
int nTotal = 0;
|
||||
int n;
|
||||
|
||||
pnToken = 0;
|
||||
while (iOffset < zSql.Length)
|
||||
{
|
||||
n = sqlite3GetToken(zSql, iOffset, ref tokenType);
|
||||
Debug.Assert(n > 0 && tokenType != TK_ILLEGAL);
|
||||
if (tokenType == TK_VARIABLE)
|
||||
{
|
||||
pnToken = n;
|
||||
break;
|
||||
}
|
||||
nTotal += n;
|
||||
iOffset += n;// zSql += n;
|
||||
}
|
||||
return nTotal;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function returns a pointer to a nul-terminated string in memory
|
||||
** obtained from sqlite3DbMalloc(). If sqlite3.vdbeExecCnt is 1, then the
|
||||
** string contains a copy of zRawSql but with host parameters expanded to
|
||||
** their current bindings. Or, if sqlite3.vdbeExecCnt is greater than 1,
|
||||
** then the returned string holds a copy of zRawSql with "-- " prepended
|
||||
** to each line of text.
|
||||
**
|
||||
** The calling function is responsible for making sure the memory returned
|
||||
** is eventually freed.
|
||||
**
|
||||
** ALGORITHM: Scan the input string looking for host parameters in any of
|
||||
** these forms: ?, ?N, $A, @A, :A. Take care to avoid text within
|
||||
** string literals, quoted identifier names, and comments. For text forms,
|
||||
** the host parameter index is found by scanning the perpared
|
||||
** statement for the corresponding OP_Variable opcode. Once the host
|
||||
** parameter index is known, locate the value in p->aVar[]. Then render
|
||||
** the value as a literal in place of the host parameter name.
|
||||
*/
|
||||
|
||||
private static string sqlite3VdbeExpandSql(
|
||||
Vdbe p, /* The prepared statement being evaluated */
|
||||
string zRawSql /* Raw text of the SQL statement */
|
||||
)
|
||||
{
|
||||
sqlite3 db; /* The database connection */
|
||||
int idx = 0; /* Index of a host parameter */
|
||||
int nextIndex = 1; /* Index of next ? host parameter */
|
||||
int n; /* Length of a token prefix */
|
||||
int nToken = 0; /* Length of the parameter token */
|
||||
int i; /* Loop counter */
|
||||
Mem pVar; /* Value of a host parameter */
|
||||
StrAccum _out = new StrAccum(1000); /* Accumulate the _output here */
|
||||
int izRawSql = 0;
|
||||
|
||||
db = p.db;
|
||||
sqlite3StrAccumInit(_out, null, 100,
|
||||
db.aLimit[SQLITE_LIMIT_LENGTH]);
|
||||
_out.db = db;
|
||||
if (db.vdbeExecCnt > 1)
|
||||
{
|
||||
while (izRawSql < zRawSql.Length)
|
||||
{
|
||||
//string zStart = zRawSql;
|
||||
while (zRawSql[izRawSql++] != '\n' && izRawSql < zRawSql.Length)
|
||||
;
|
||||
sqlite3StrAccumAppend(_out, "-- ", 3);
|
||||
sqlite3StrAccumAppend(_out, zRawSql, (int)izRawSql);//zRawSql - zStart );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (izRawSql < zRawSql.Length)
|
||||
{
|
||||
n = findNextHostParameter(zRawSql, izRawSql, ref nToken);
|
||||
Debug.Assert(n > 0);
|
||||
sqlite3StrAccumAppend(_out, zRawSql.Substring(izRawSql, n), n);
|
||||
izRawSql += n;
|
||||
Debug.Assert(izRawSql < zRawSql.Length || nToken == 0);
|
||||
if (nToken == 0)
|
||||
break;
|
||||
if (zRawSql[izRawSql] == '?')
|
||||
{
|
||||
if (nToken > 1)
|
||||
{
|
||||
Debug.Assert(sqlite3Isdigit(zRawSql[izRawSql + 1]));
|
||||
sqlite3GetInt32(zRawSql, izRawSql + 1, ref idx);
|
||||
}
|
||||
else
|
||||
{
|
||||
idx = nextIndex;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Assert(zRawSql[izRawSql] == ':' || zRawSql[izRawSql] == '$' || zRawSql[izRawSql] == '@');
|
||||
testcase(zRawSql[izRawSql] == ':');
|
||||
testcase(zRawSql[izRawSql] == '$');
|
||||
testcase(zRawSql[izRawSql] == '@');
|
||||
idx = sqlite3VdbeParameterIndex(p, zRawSql.Substring(izRawSql, nToken), nToken);
|
||||
Debug.Assert(idx > 0);
|
||||
}
|
||||
izRawSql += nToken;
|
||||
nextIndex = idx + 1;
|
||||
Debug.Assert(idx > 0 && idx <= p.nVar);
|
||||
pVar = p.aVar[idx - 1];
|
||||
if ((pVar.flags & MEM_Null) != 0)
|
||||
{
|
||||
sqlite3StrAccumAppend(_out, "NULL", 4);
|
||||
}
|
||||
else if ((pVar.flags & MEM_Int) != 0)
|
||||
{
|
||||
sqlite3XPrintf(_out, "%lld", pVar.u.i);
|
||||
}
|
||||
else if ((pVar.flags & MEM_Real) != 0)
|
||||
{
|
||||
sqlite3XPrintf(_out, "%!.15g", pVar.r);
|
||||
}
|
||||
else if ((pVar.flags & MEM_Str) != 0)
|
||||
{
|
||||
#if !SQLITE_OMIT_UTF16
|
||||
u8 enc = ENC(db);
|
||||
if( enc!=SQLITE_UTF8 ){
|
||||
Mem utf8;
|
||||
memset(&utf8, 0, sizeof(utf8));
|
||||
utf8.db = db;
|
||||
sqlite3VdbeMemSetStr(&utf8, pVar.z, pVar.n, enc, SQLITE_STATIC);
|
||||
sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8);
|
||||
sqlite3XPrintf(_out, "'%.*q'", utf8.n, utf8.z);
|
||||
sqlite3VdbeMemRelease(&utf8);
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
sqlite3XPrintf(_out, "'%.*q'", pVar.n, pVar.z);
|
||||
}
|
||||
}
|
||||
else if ((pVar.flags & MEM_Zero) != 0)
|
||||
{
|
||||
sqlite3XPrintf(_out, "zeroblob(%d)", pVar.u.nZero);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Assert((pVar.flags & MEM_Blob) != 0);
|
||||
sqlite3StrAccumAppend(_out, "x'", 2);
|
||||
for (i = 0; i < pVar.n; i++)
|
||||
{
|
||||
sqlite3XPrintf(_out, "%02x", pVar.zBLOB[i] & 0xff);
|
||||
}
|
||||
sqlite3StrAccumAppend(_out, "'", 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sqlite3StrAccumFinish(_out);
|
||||
}
|
||||
|
||||
#endif //* #if !SQLITE_OMIT_TRACE */
|
||||
}
|
||||
}
|
||||
1280
original/Community.CsharpSqlite/src/vtab_c.cs
Normal file
1280
original/Community.CsharpSqlite/src/vtab_c.cs
Normal file
File diff suppressed because it is too large
Load diff
2952
original/Community.CsharpSqlite/src/wal_c.cs
Normal file
2952
original/Community.CsharpSqlite/src/wal_c.cs
Normal file
File diff suppressed because it is too large
Load diff
230
original/Community.CsharpSqlite/src/wal_h.cs
Normal file
230
original/Community.CsharpSqlite/src/wal_h.cs
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
using u8 = System.Byte;
|
||||
using Pgno = System.UInt32;
|
||||
|
||||
#if SQLITE_OMIT_WAL
|
||||
|
||||
using Wal = System.Object;
|
||||
|
||||
#endif
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2010 February 1
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This header file defines the interface to the write-ahead logging
|
||||
** system. Refer to the comments below and the header comment attached to
|
||||
** the implementation of each function in log.c for further details.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
|
||||
//#if !_WAL_H_
|
||||
//#define _WAL_H_
|
||||
|
||||
//#include "sqliteInt.h"
|
||||
|
||||
#if SQLITE_OMIT_WAL
|
||||
|
||||
//# define sqlite3WalOpen(x,y,z) 0
|
||||
private static int sqlite3WalOpen(sqlite3_vfs x, sqlite3_file y, string z)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//# define sqlite3WalLimit(x,y)
|
||||
private static void sqlite3WalLimit(sqlite3_vfs x, long y)
|
||||
{
|
||||
}
|
||||
|
||||
//# define sqlite3WalClose(w,x,y,z) 0
|
||||
private static int sqlite3WalClose(Wal w, int x, int y, u8 z)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//# define sqlite3WalBeginReadTransaction(y,z) 0
|
||||
private static int sqlite3WalBeginReadTransaction(Wal y, int z)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//# define sqlite3WalEndReadTransaction(z)
|
||||
private static void sqlite3WalEndReadTransaction(Wal z)
|
||||
{
|
||||
}
|
||||
|
||||
//# define sqlite3WalRead(v,w,x,y,z) 0
|
||||
private static int sqlite3WalRead(Wal v, Pgno w, ref int x, int y, u8[] z)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//# define sqlite3WalDbsize(y) 0
|
||||
private static Pgno sqlite3WalDbsize(Wal y)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//# define sqlite3WalBeginWriteTransaction(y) 0
|
||||
private static int sqlite3WalBeginWriteTransaction(Wal y)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//# define sqlite3WalEndWriteTransaction(x) 0
|
||||
private static int sqlite3WalEndWriteTransaction(Wal x)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//# define sqlite3WalUndo(x,y,z) 0
|
||||
private static int sqlite3WalUndo(Wal x, int y, object z)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//# define sqlite3WalSavepoint(y,z)
|
||||
private static void sqlite3WalSavepoint(Wal y, object z)
|
||||
{
|
||||
}
|
||||
|
||||
//# define sqlite3WalSavepointUndo(y,z) 0
|
||||
private static int sqlite3WalSavepointUndo(Wal y, object z)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//# define sqlite3WalFrames(u,v,w,x,y,z) 0
|
||||
private static int sqlite3WalFrames(Wal u, int v, PgHdr w, Pgno x, int y, int z)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//# define sqlite3WalCheckpoint(r,s,t,u,v,w,x,y,z) 0
|
||||
private static int sqlite3WalCheckpoint(Wal r, int s, int t, u8[] u, int v, int w, u8[] x, ref int y, ref int z)//r,s,t,u,v,w,x,y,z
|
||||
{
|
||||
y = 0;
|
||||
z = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//# define sqlite3WalCallback(z) 0
|
||||
private static int sqlite3WalCallback(Wal z)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//# define sqlite3WalExclusiveMode(y,z) 0
|
||||
private static bool sqlite3WalExclusiveMode(Wal y, int z)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//# define sqlite3WalHeapMemory(z) 0
|
||||
private static bool sqlite3WalHeapMemory(Wal z)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
//#define WAL_SAVEPOINT_NDATA 4
|
||||
const int WAL_SAVEPOINT_NDATA = 4;
|
||||
|
||||
/* Connection to a write-ahead log (WAL) file.
|
||||
** There is one object of this type for each pager.
|
||||
*/
|
||||
typedef struct Wal Wal;
|
||||
|
||||
/* Open and close a connection to a write-ahead log. */
|
||||
int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, string , int, i64, Wal*);
|
||||
int sqlite3WalClose(Wal *pWal, int sync_flags, int, u8 );
|
||||
|
||||
/* Set the limiting size of a WAL file. */
|
||||
void sqlite3WalLimit(Wal*, i64);
|
||||
|
||||
/* Used by readers to open (lock) and close (unlock) a snapshot. A
|
||||
** snapshot is like a read-transaction. It is the state of the database
|
||||
** at an instant in time. sqlite3WalOpenSnapshot gets a read lock and
|
||||
** preserves the current state even if the other threads or processes
|
||||
** write to or checkpoint the WAL. sqlite3WalCloseSnapshot() closes the
|
||||
** transaction and releases the lock.
|
||||
*/
|
||||
int sqlite3WalBeginReadTransaction(Wal *pWal, int );
|
||||
void sqlite3WalEndReadTransaction(Wal *pWal);
|
||||
|
||||
/* Read a page from the write-ahead log, if it is present. */
|
||||
int sqlite3WalRead(Wal *pWal, Pgno pgno, int *pInWal, int nOut, u8 *pOut);
|
||||
|
||||
/* If the WAL is not empty, return the size of the database. */
|
||||
Pgno sqlite3WalDbsize(Wal *pWal);
|
||||
|
||||
/* Obtain or release the WRITER lock. */
|
||||
int sqlite3WalBeginWriteTransaction(Wal *pWal);
|
||||
int sqlite3WalEndWriteTransaction(Wal *pWal);
|
||||
|
||||
/* Undo any frames written (but not committed) to the log */
|
||||
int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), object *pUndoCtx);
|
||||
|
||||
/* Return an integer that records the current (uncommitted) write
|
||||
** position in the WAL */
|
||||
void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData);
|
||||
|
||||
/* Move the write position of the WAL back to iFrame. Called in
|
||||
** response to a ROLLBACK TO command. */
|
||||
int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData);
|
||||
|
||||
/* Write a frame or frames to the log. */
|
||||
int sqlite3WalFrames(Wal *pWal, int, PgHdr *, Pgno, int, int);
|
||||
|
||||
/* Copy pages from the log to the database file */
|
||||
int sqlite3WalCheckpoint(
|
||||
Wal *pWal, /* Write-ahead log connection */
|
||||
int eMode, /* One of PASSIVE, FULL and RESTART */
|
||||
int (*xBusy)(void), /* Function to call when busy */
|
||||
void *pBusyArg, /* Context argument for xBusyHandler */
|
||||
int sync_flags, /* Flags to sync db file with (or 0) */
|
||||
int nBuf, /* Size of buffer nBuf */
|
||||
u8 *zBuf, /* Temporary buffer to use */
|
||||
int *pnLog, /* OUT: Number of frames in WAL */
|
||||
int *pnCkpt /* OUT: Number of backfilled frames in WAL */
|
||||
);
|
||||
|
||||
/* Return the value to pass to a sqlite3_wal_hook callback, the
|
||||
** number of frames in the WAL at the point of the last commit since
|
||||
** sqlite3WalCallback() was called. If no commits have occurred since
|
||||
** the last call, then return 0.
|
||||
*/
|
||||
int sqlite3WalCallback(Wal *pWal);
|
||||
|
||||
/* Tell the wal layer that an EXCLUSIVE lock has been obtained (or released)
|
||||
** by the pager layer on the database file.
|
||||
*/
|
||||
int sqlite3WalExclusiveMode(Wal *pWal, int op);
|
||||
|
||||
/* Return true if the argument is non-NULL and the WAL module is using
|
||||
** heap-memory for the wal-index. Otherwise, if the argument is NULL or the
|
||||
** WAL module is using shared-memory, return false.
|
||||
*/
|
||||
int sqlite3WalHeapMemory(Wal *pWal);
|
||||
|
||||
#endif //* ifndef SQLITE_OMIT_WAL */
|
||||
//#endif //* _WAL_H_ */
|
||||
}
|
||||
}
|
||||
187
original/Community.CsharpSqlite/src/walker_c.cs
Normal file
187
original/Community.CsharpSqlite/src/walker_c.cs
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2008 August 16
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains routines used for walking the parser tree for
|
||||
** an SQL statement.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2010-08-23 18:52:01 42537b60566f288167f1b5864a5435986838e3a3
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#include "sqliteInt.h"
|
||||
//#include <stdlib.h>
|
||||
//#include <string.h>
|
||||
|
||||
/*
|
||||
** Walk an expression tree. Invoke the callback once for each node
|
||||
** of the expression, while decending. (In other words, the callback
|
||||
** is invoked before visiting children.)
|
||||
**
|
||||
** The return value from the callback should be one of the WRC_*
|
||||
** constants to specify how to proceed with the walk.
|
||||
**
|
||||
** WRC_Continue Continue descending down the tree.
|
||||
**
|
||||
** WRC_Prune Do not descend into child nodes. But allow
|
||||
** the walk to continue with sibling nodes.
|
||||
**
|
||||
** WRC_Abort Do no more callbacks. Unwind the stack and
|
||||
** return the top-level walk call.
|
||||
**
|
||||
** The return value from this routine is WRC_Abort to abandon the tree walk
|
||||
** and WRC_Continue to continue.
|
||||
*/
|
||||
|
||||
private static int sqlite3WalkExpr(Walker pWalker, ref Expr pExpr)
|
||||
{
|
||||
int rc;
|
||||
if (pExpr == null)
|
||||
return WRC_Continue;
|
||||
testcase(ExprHasProperty(pExpr, EP_TokenOnly));
|
||||
testcase(ExprHasProperty(pExpr, EP_Reduced));
|
||||
rc = pWalker.xExprCallback(pWalker, ref pExpr);
|
||||
if (rc == WRC_Continue
|
||||
&& !ExprHasAnyProperty(pExpr, EP_TokenOnly))
|
||||
{
|
||||
if (sqlite3WalkExpr(pWalker, ref pExpr.pLeft) != 0)
|
||||
return WRC_Abort;
|
||||
if (sqlite3WalkExpr(pWalker, ref pExpr.pRight) != 0)
|
||||
return WRC_Abort;
|
||||
if (ExprHasProperty(pExpr, EP_xIsSelect))
|
||||
{
|
||||
if (sqlite3WalkSelect(pWalker, pExpr.x.pSelect) != 0)
|
||||
return WRC_Abort;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sqlite3WalkExprList(pWalker, pExpr.x.pList) != 0)
|
||||
return WRC_Abort;
|
||||
}
|
||||
}
|
||||
return rc & WRC_Abort;
|
||||
}
|
||||
|
||||
/*
|
||||
** Call sqlite3WalkExpr() for every expression in list p or until
|
||||
** an abort request is seen.
|
||||
*/
|
||||
|
||||
private static int sqlite3WalkExprList(Walker pWalker, ExprList p)
|
||||
{
|
||||
int i;
|
||||
ExprList_item pItem;
|
||||
if (p != null)
|
||||
{
|
||||
for (i = p.nExpr; i > 0; i--)
|
||||
{//, pItem++){
|
||||
pItem = p.a[p.nExpr - i];
|
||||
if (sqlite3WalkExpr(pWalker, ref pItem.pExpr) != 0)
|
||||
return WRC_Abort;
|
||||
}
|
||||
}
|
||||
return WRC_Continue;
|
||||
}
|
||||
|
||||
/*
|
||||
** Walk all expressions associated with SELECT statement p. Do
|
||||
** not invoke the SELECT callback on p, but do (of course) invoke
|
||||
** any expr callbacks and SELECT callbacks that come from subqueries.
|
||||
** Return WRC_Abort or WRC_Continue.
|
||||
*/
|
||||
|
||||
private static int sqlite3WalkSelectExpr(Walker pWalker, Select p)
|
||||
{
|
||||
if (sqlite3WalkExprList(pWalker, p.pEList) != 0)
|
||||
return WRC_Abort;
|
||||
if (sqlite3WalkExpr(pWalker, ref p.pWhere) != 0)
|
||||
return WRC_Abort;
|
||||
if (sqlite3WalkExprList(pWalker, p.pGroupBy) != 0)
|
||||
return WRC_Abort;
|
||||
if (sqlite3WalkExpr(pWalker, ref p.pHaving) != 0)
|
||||
return WRC_Abort;
|
||||
if (sqlite3WalkExprList(pWalker, p.pOrderBy) != 0)
|
||||
return WRC_Abort;
|
||||
if (sqlite3WalkExpr(pWalker, ref p.pLimit) != 0)
|
||||
return WRC_Abort;
|
||||
if (sqlite3WalkExpr(pWalker, ref p.pOffset) != 0)
|
||||
return WRC_Abort;
|
||||
return WRC_Continue;
|
||||
}
|
||||
|
||||
/*
|
||||
** Walk the parse trees associated with all subqueries in the
|
||||
** FROM clause of SELECT statement p. Do not invoke the select
|
||||
** callback on p, but do invoke it on each FROM clause subquery
|
||||
** and on any subqueries further down in the tree. Return
|
||||
** WRC_Abort or WRC_Continue;
|
||||
*/
|
||||
|
||||
private static int sqlite3WalkSelectFrom(Walker pWalker, Select p)
|
||||
{
|
||||
SrcList pSrc;
|
||||
int i;
|
||||
SrcList_item pItem;
|
||||
|
||||
pSrc = p.pSrc;
|
||||
if (ALWAYS(pSrc))
|
||||
{
|
||||
for (i = pSrc.nSrc; i > 0; i--)// pItem++ )
|
||||
{
|
||||
pItem = pSrc.a[pSrc.nSrc - i];
|
||||
if (sqlite3WalkSelect(pWalker, pItem.pSelect) != 0)
|
||||
{
|
||||
return WRC_Abort;
|
||||
}
|
||||
}
|
||||
}
|
||||
return WRC_Continue;
|
||||
}
|
||||
|
||||
/*
|
||||
** Call sqlite3WalkExpr() for every expression in Select statement p.
|
||||
** Invoke sqlite3WalkSelect() for subqueries in the FROM clause and
|
||||
** on the compound select chain, p.pPrior.
|
||||
**
|
||||
** Return WRC_Continue under normal conditions. Return WRC_Abort if
|
||||
** there is an abort request.
|
||||
**
|
||||
** If the Walker does not have an xSelectCallback() then this routine
|
||||
** is a no-op returning WRC_Continue.
|
||||
*/
|
||||
|
||||
private static int sqlite3WalkSelect(Walker pWalker, Select p)
|
||||
{
|
||||
int rc;
|
||||
if (p == null || pWalker.xSelectCallback == null)
|
||||
return WRC_Continue;
|
||||
rc = WRC_Continue;
|
||||
while (p != null)
|
||||
{
|
||||
rc = pWalker.xSelectCallback(pWalker, p);
|
||||
if (rc != 0)
|
||||
break;
|
||||
if (sqlite3WalkSelectExpr(pWalker, p) != 0)
|
||||
return WRC_Abort;
|
||||
if (sqlite3WalkSelectFrom(pWalker, p) != 0)
|
||||
return WRC_Abort;
|
||||
p = p.pPrior;
|
||||
}
|
||||
return rc & WRC_Abort;
|
||||
}
|
||||
}
|
||||
}
|
||||
5902
original/Community.CsharpSqlite/src/where_c.cs
Normal file
5902
original/Community.CsharpSqlite/src/where_c.cs
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,241 @@
|
|||
/*
|
||||
Copyright (c) 2018, Kevin Pope, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.Image;
|
||||
using MatterHackers.Agg.Platform;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.MatterControl.PartPreviewWindow;
|
||||
|
||||
namespace MatterHackers.MatterControl.ConfigurationPage
|
||||
{
|
||||
public class ThemeColorPanel : FlowLayoutWidget
|
||||
{
|
||||
private Color lastColor;
|
||||
private AccentColorsWidget colorSelector;
|
||||
|
||||
private IColorTheme _themeProvider;
|
||||
private GuiWidget previewButtonPanel;
|
||||
|
||||
public ThemeColorPanel(ThemeConfig activeTheme)
|
||||
: base (FlowDirection.TopToBottom)
|
||||
{
|
||||
string currentProviderName = UserSettings.Instance.get(UserSettingsKey.ThemeName) ?? "";
|
||||
|
||||
if (AppContext.ThemeProviders.TryGetValue(currentProviderName, out IColorTheme currentProvider))
|
||||
{
|
||||
_themeProvider = currentProvider;
|
||||
}
|
||||
else
|
||||
{
|
||||
_themeProvider = AppContext.ThemeProviders.Values.First();
|
||||
}
|
||||
|
||||
this.SelectionColor = activeTheme.GetBorderColor(80);
|
||||
|
||||
// Add color selector
|
||||
this.AddChild(colorSelector = new AccentColorsWidget(this)
|
||||
{
|
||||
Margin = new BorderDouble(activeTheme.DefaultContainerPadding, 0)
|
||||
});
|
||||
|
||||
this.AddChild(previewButtonPanel = new FlowLayoutWidget()
|
||||
{
|
||||
HAnchor = HAnchor.Stretch,
|
||||
VAnchor = VAnchor.Fit,
|
||||
BackgroundColor = this.SelectionColor,
|
||||
Padding = new BorderDouble(left: colorSelector.ColorButtons.First().Border.Left)
|
||||
});
|
||||
|
||||
this.CreateThemeModeButtons();
|
||||
}
|
||||
|
||||
public ImageBuffer CheckMark { get; } = AggContext.StaticData.LoadIcon("426.png", 16, 16, invertImage: true);
|
||||
|
||||
public Color SelectionColor { get; private set; }
|
||||
|
||||
public IColorTheme ThemeProvider
|
||||
{
|
||||
get => _themeProvider;
|
||||
set
|
||||
{
|
||||
_themeProvider = value;
|
||||
|
||||
var previewColor = _themeProvider.Colors.First();
|
||||
|
||||
colorSelector.RebuildColorButtons();
|
||||
|
||||
this.CreateThemeModeButtons();
|
||||
|
||||
this.PreviewTheme(previewColor);
|
||||
}
|
||||
}
|
||||
private void CreateThemeModeButtons()
|
||||
{
|
||||
previewButtonPanel.CloseAllChildren();
|
||||
|
||||
var theme = AppContext.Theme;
|
||||
|
||||
var accentColor = theme.Colors.PrimaryAccentColor;
|
||||
|
||||
if (!_themeProvider.Colors.Contains(accentColor))
|
||||
{
|
||||
accentColor = _themeProvider.DefaultColor;
|
||||
}
|
||||
|
||||
var activeMode = UserSettings.Instance.get(UserSettingsKey.ThemeMode);
|
||||
|
||||
foreach (var mode in _themeProvider.Modes)
|
||||
{
|
||||
var themeset = _themeProvider.GetTheme(mode, accentColor);
|
||||
|
||||
previewButtonPanel.AddChild(new ThemePreviewButton(themeset.Theme, this)
|
||||
{
|
||||
HAnchor = HAnchor.Absolute,
|
||||
VAnchor = VAnchor.Absolute,
|
||||
Width = 80,
|
||||
Height = 65,
|
||||
Mode = mode,
|
||||
Margin = new BorderDouble(theme.DefaultContainerPadding, theme.DefaultContainerPadding, 0, theme.DefaultContainerPadding),
|
||||
Border = 1,
|
||||
IsActive = mode == activeMode,
|
||||
BorderColor = theme.GetBorderColor(20),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void PreviewTheme(Color sourceAccentColor)
|
||||
{
|
||||
foreach (var previewButton in previewButtonPanel.Children<ThemePreviewButton>())
|
||||
{
|
||||
previewButton.PreviewThemeColor(sourceAccentColor);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetThemeColor(Color accentColor, string mode = null)
|
||||
{
|
||||
lastColor = accentColor;
|
||||
|
||||
foreach (var colorButton in colorSelector.ColorButtons)
|
||||
{
|
||||
colorButton.BorderColor = (colorButton.SourceColor == accentColor) ? Color.White : Color.Transparent;
|
||||
}
|
||||
|
||||
if (mode == null)
|
||||
{
|
||||
mode = this.ThemeProvider.DefaultMode;
|
||||
|
||||
var lastMode = UserSettings.Instance.get(UserSettingsKey.ThemeMode);
|
||||
if (this.ThemeProvider.Modes.Contains(lastMode))
|
||||
{
|
||||
mode = lastMode;
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine("Getting/setting theme for " + accentColor.Html);
|
||||
|
||||
AppContext.SetTheme(this.ThemeProvider.GetTheme(mode, accentColor));
|
||||
previewButtonPanel.BackgroundColor = this.SelectionColor;
|
||||
}
|
||||
|
||||
public class AccentColorsWidget : FlowLayoutWidget
|
||||
{
|
||||
private int containerHeight = (int)(20 * GuiWidget.DeviceScale);
|
||||
private ThemeColorPanel themeColorPanel;
|
||||
|
||||
public AccentColorsWidget(ThemeColorPanel themeColorPanel)
|
||||
{
|
||||
this.Padding = new BorderDouble(2, 0);
|
||||
this.themeColorPanel = themeColorPanel;
|
||||
|
||||
this.RebuildColorButtons();
|
||||
}
|
||||
|
||||
private List<ColorButton> colorButtons = new List<ColorButton>();
|
||||
|
||||
public IEnumerable<ColorButton> ColorButtons => colorButtons;
|
||||
|
||||
public void RebuildColorButtons()
|
||||
{
|
||||
this.CloseAllChildren();
|
||||
|
||||
colorButtons.Clear();
|
||||
|
||||
bool firstItem = true;
|
||||
|
||||
foreach (var color in themeColorPanel.ThemeProvider.Colors)
|
||||
{
|
||||
var colorButton = CreateThemeButton(color);
|
||||
colorButton.Width = containerHeight;
|
||||
colorButton.BorderColor = (color == AppContext.Theme.Colors.SourceColor) ? themeColorPanel.SelectionColor : Color.Transparent;
|
||||
|
||||
colorButtons.Add(colorButton);
|
||||
|
||||
if (firstItem)
|
||||
{
|
||||
firstItem = false;
|
||||
colorButton.Margin = colorButton.Margin.Clone(left: 0);
|
||||
}
|
||||
|
||||
this.AddChild(colorButton);
|
||||
}
|
||||
}
|
||||
|
||||
public ColorButton CreateThemeButton(Color color)
|
||||
{
|
||||
var colorButton = new ColorButton(color)
|
||||
{
|
||||
Cursor = Cursors.Hand,
|
||||
Width = containerHeight,
|
||||
Height = containerHeight,
|
||||
Border = 5,
|
||||
};
|
||||
colorButton.Click += (s, e) =>
|
||||
{
|
||||
themeColorPanel.SetThemeColor(colorButton.BackgroundColor);
|
||||
};
|
||||
|
||||
colorButton.MouseEnterBounds += (s, e) =>
|
||||
{
|
||||
foreach(var button in this.ColorButtons)
|
||||
{
|
||||
button.BorderColor = (button == colorButton) ? themeColorPanel.SelectionColor : Color.Transparent;
|
||||
}
|
||||
|
||||
themeColorPanel.PreviewTheme(colorButton.BackgroundColor);
|
||||
};
|
||||
|
||||
return colorButton;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
10
original/KnownPlugins.json
Normal file
10
original/KnownPlugins.json
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
[
|
||||
{
|
||||
"Name": "MatterControl Cloud Services",
|
||||
"TypeName": "MatterHackers.MatterControl.Plugins.CloudServices.CloudServicesPlugin"
|
||||
},
|
||||
{
|
||||
"Name": "Firmware Updater",
|
||||
"TypeName": "MatterHackers.MatterControl.Plugins.MarlinFirmwareUpdatePlugin.MarlinFirmwareUpdatePlugin"
|
||||
}
|
||||
]
|
||||
23
original/LICENSE
Normal file
23
original/LICENSE
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
Copyright (c) 2014, MatterHackers, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
44
original/Launcher/Launcher.cs
Normal file
44
original/Launcher/Launcher.cs
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
namespace MatterHackers.MatterControl.Launcher
|
||||
{
|
||||
public class LauncherApp
|
||||
{
|
||||
public LauncherApp()
|
||||
{
|
||||
}
|
||||
|
||||
[STAThread]
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
// this sets the global culture for the app and all new threads
|
||||
CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture;
|
||||
CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture;
|
||||
|
||||
// and make sure the app is set correctly
|
||||
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
|
||||
Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
|
||||
|
||||
if (args.Length == 2 && File.Exists(args[0]))
|
||||
{
|
||||
ProcessStartInfo runAppLauncherStartInfo = new ProcessStartInfo();
|
||||
runAppLauncherStartInfo.FileName = args[0];
|
||||
|
||||
int timeToWait = 0;
|
||||
int.TryParse(args[1], out timeToWait);
|
||||
|
||||
Stopwatch waitTime = new Stopwatch();
|
||||
waitTime.Start();
|
||||
while (waitTime.ElapsedMilliseconds < timeToWait)
|
||||
{
|
||||
}
|
||||
|
||||
Process.Start(runAppLauncherStartInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
15
original/Launcher/Launcher.csproj
Normal file
15
original/Launcher/Launcher.csproj
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>MatterHackers.MatterControl.Launcher</RootNamespace>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers" Version="0.4.410601">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
8
original/Launcher/Properties/launchSettings.json
Normal file
8
original/Launcher/Properties/launchSettings.json
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"profiles": {
|
||||
"Launcher": {
|
||||
"commandName": "Project",
|
||||
"commandLineArgs": "C:\\Windows\\notepad.exe 1000"
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue