Lightweight SQLite Reader

xuanbao · · 941 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>I am looking for a light SQLite reader, I only need it to be able to read from a database file. I would like it to be PURE Go, no cgo. All the examples i find are cgo and include a bunch of usless stuff for me.</p> <p>I found a example in VB.net that does this;</p> <pre><code>&#39;************************************************************** &#39; &#39; Coded By: RockingWithTheBest &#39; &#39; v 0.1 &#39; &#39; &#39; A Handler for SQLite without needing the sqlite3.dll! &#39; You can read every table and value from database, but &#39; there is no support for input. Also no support for &#39; journal files and overflow pages, maybe i will add &#39; that in a later release. &#39; &#39; &#39; Have Fun! &#39; &#39; If u want to learn more about or enhance it then visit: &#39; http://www.sqlite.org/fileformat.html &#39; &#39; If you copy or modify it, please add me to credits! &#39; &#39; Questions etc. to: peterrlustig@googlemail.com &#39; &#39;************************************************************** &#39; &#39; Example: &#39; &#39; Dim SQLDatabase = New SQLiteHandler(&#34;C:\Temp\Login Data&#34;) &#39; SQLDatabase.ReadTable(&#34;logins&#34;) &#39; &#39; MsgBox(GetValue(SQLDatabase.GetValue(0, &#34;username_value&#34;))) &#39; &#39;************************************************************** Imports System.IO Public Class SQLiteHandler Private db_bytes() As Byte Private page_size As UInt16 Private encoding As UInt64 Private master_table_entries() As sqlite_master_entry Private SQLDataTypeSize() As Byte = New Byte() {0, 1, 2, 3, 4, 6, 8, 8, 0, 0} Private table_entries() As table_entry Private field_names() As String Private Structure record_header_field Dim size As Int64 Dim type As Int64 End Structure Private Structure table_entry Dim row_id As Int64 Dim content() As String End Structure Private Structure sqlite_master_entry Dim row_id As Int64 Dim item_type As String Dim item_name As String Dim astable_name As String Dim root_num As Int64 Dim sql_statement As String End Structure &#39;Needs BigEndian &#39;GetVariableLength &#39; returns the endindex of an variable length integer Private Function GVL(ByVal startIndex As Integer) As Integer Try If startIndex &gt; db_bytes.Length Then Return Nothing For i = startIndex To startIndex + 8 Step 1 If i &gt; db_bytes.Length - 1 Then Return Nothing ElseIf (db_bytes(i) And &amp;H80) &lt;&gt; &amp;H80 Then Return i End If Next Return startIndex + 8 Catch : End Try End Function &#39; Eingaberichtung BigEndian &#39; ConvertVariableLength Private Function CVL(ByVal startIndex As Integer, ByVal endIndex As Integer) As Int64 Try endIndex = endIndex + 1 Dim retus(7) As Byte Dim Length = endIndex - startIndex Dim Bit64 As Boolean = False If Length = 0 Or Length &gt; 9 Then Return Nothing If Length = 1 Then retus(0) = (db_bytes(startIndex) And &amp;H7F) Return BitConverter.ToInt64(retus, 0) End If If Length = 9 Then &#39; Ein Byte wird nämlich grad hinzugefügt Bit64 = True End If Dim j As Integer = 1 Dim k As Integer = 7 Dim y As Integer = 0 If Bit64 Then retus(0) = db_bytes(endIndex - 1) endIndex = endIndex - 1 y = 1 End If For i = (endIndex - 1) To startIndex Step -1 If (i - 1) &gt;= startIndex Then retus(y) = ((db_bytes(i) &gt;&gt; (j - 1)) And (&amp;HFF &gt;&gt; j)) Or (db_bytes(i - 1) &lt;&lt; k) j = j + 1 y = y + 1 k = k - 1 Else If Not Bit64 Then retus(y) = ((db_bytes(i) &gt;&gt; (j - 1)) And (&amp;HFF &gt;&gt; j)) End If Next Return BitConverter.ToInt64(retus, 0) Catch : End Try End Function &#39;Checks if a number is odd Private Function IsOdd(ByVal value As Int64) As Boolean Return (value And 1) = 1 End Function &#39;Big Endian Conversation Private Function ConvertToInteger(ByVal startIndex As Integer, ByVal Size As Integer) As UInt64 Try If Size &gt; 8 Or Size = 0 Then Return Nothing Dim retVal As UInt64 = 0 For i = 0 To Size - 1 Step 1 retVal = ((retVal &lt;&lt; 8) Or db_bytes(startIndex + i)) Next Return retVal Catch : End Try End Function Private Sub ReadMasterTable(ByVal Offset As UInt64) Try If db_bytes(Offset) = &amp;HD Then &#39;Leaf node &#39;Length for setting the array length for the entries Dim Length As UInt16 = ConvertToInteger(Offset + 3, 2) - 1 Dim ol As Integer = 0 If Not master_table_entries Is Nothing Then ol = master_table_entries.Length ReDim Preserve master_table_entries(master_table_entries.Length + Length) Else ReDim master_table_entries(Length) End If Dim ent_offset As UInt64 For i = 0 To Length Step 1 ent_offset = ConvertToInteger(Offset + 8 + (i * 2), 2) If Offset &lt;&gt; 100 Then ent_offset = ent_offset + Offset &#39;Table Cell auslesen Dim t = GVL(ent_offset) Dim size As Int64 = CVL(ent_offset, t) Dim s = GVL(ent_offset + (t - ent_offset) + 1) master_table_entries(ol + i).row_id = CVL(ent_offset + (t - ent_offset) + 1, s) &#39;Table Content &#39;Resetting the offset ent_offset = ent_offset + (s - ent_offset) + 1 &#39;Now get to the Record Header t = GVL(ent_offset) s = t Dim Rec_Header_Size As Int64 = CVL(ent_offset, t) &#39;Record Header Length Dim Field_Size(4) As Int64 &#39;Now get the field sizes and fill in the Values For j = 0 To 4 Step 1 t = s + 1 s = GVL(t) Field_Size(j) = CVL(t, s) If Field_Size(j) &gt; 9 Then If IsOdd(Field_Size(j)) Then Field_Size(j) = (Field_Size(j) - 13) / 2 Else Field_Size(j) = (Field_Size(j) - 12) / 2 End If Else Field_Size(j) = SQLDataTypeSize(Field_Size(j)) End If Next &#39; Wir lesen nur unbedingt notwendige Sachen aus If encoding = 1 Then master_table_entries(ol + i).item_type = System.Text.Encoding.Default.GetString(db_bytes, ent_offset + Rec_Header_Size, Field_Size(0)) ElseIf encoding = 2 Then master_table_entries(ol + i).item_type = System.Text.Encoding.Unicode.GetString(db_bytes, ent_offset + Rec_Header_Size, Field_Size(0)) ElseIf encoding = 3 Then master_table_entries(ol + i).item_type = System.Text.Encoding.BigEndianUnicode.GetString(db_bytes, ent_offset + Rec_Header_Size, Field_Size(0)) End If If encoding = 1 Then master_table_entries(ol + i).item_name = System.Text.Encoding.Default.GetString(db_bytes, ent_offset + Rec_Header_Size + Field_Size(0), Field_Size(1)) ElseIf encoding = 2 Then master_table_entries(ol + i).item_name = System.Text.Encoding.Unicode.GetString(db_bytes, ent_offset + Rec_Header_Size + Field_Size(0), Field_Size(1)) ElseIf encoding = 3 Then master_table_entries(ol + i).item_name = System.Text.Encoding.BigEndianUnicode.GetString(db_bytes, ent_offset + Rec_Header_Size + Field_Size(0), Field_Size(1)) End If &#39;master_table_entries(ol + i).astable_name = System.Text.Encoding.Default.GetString(db_bytes, ent_offset + Rec_Header_Size + Field_Size(0) + Field_Size(1), Field_Size(2)) master_table_entries(ol + i).root_num = ConvertToInteger(ent_offset + Rec_Header_Size + Field_Size(0) + Field_Size(1) + Field_Size(2), Field_Size(3)) If encoding = 1 Then master_table_entries(ol + i).sql_statement = System.Text.Encoding.Default.GetString(db_bytes, ent_offset + Rec_Header_Size + Field_Size(0) + Field_Size(1) + Field_Size(2) + Field_Size(3), Field_Size(4)) ElseIf encoding = 2 Then master_table_entries(ol + i).sql_statement = System.Text.Encoding.Unicode.GetString(db_bytes, ent_offset + Rec_Header_Size + Field_Size(0) + Field_Size(1) + Field_Size(2) + Field_Size(3), Field_Size(4)) ElseIf encoding = 3 Then master_table_entries(ol + i).sql_statement = System.Text.Encoding.BigEndianUnicode.GetString(db_bytes, ent_offset + Rec_Header_Size + Field_Size(0) + Field_Size(1) + Field_Size(2) + Field_Size(3), Field_Size(4)) End If Next ElseIf db_bytes(Offset) = &amp;H5 Then &#39;internal node Dim Length As UInt16 = ConvertToInteger(Offset + 3, 2) - 1 Dim ent_offset As UInt16 For i = 0 To Length Step 1 ent_offset = ConvertToInteger(Offset + 12 + (i * 2), 2) If Offset = 100 Then ReadMasterTable((ConvertToInteger(ent_offset, 4) - 1) * page_size) Else ReadMasterTable((ConvertToInteger(Offset + ent_offset, 4) - 1) * page_size) End If Next ReadMasterTable((ConvertToInteger(Offset + 8, 4) - 1) * page_size) End If Catch : End Try End Sub Private Function ReadTableFromOffset(ByVal Offset As UInt64) As Boolean Try If db_bytes(Offset) = &amp;HD Then &#39;Leaf node &#39;Length for setting the array length for the entries Dim Length As UInt16 = ConvertToInteger(Offset + 3, 2) - 1 Dim ol As Integer = 0 If Not table_entries Is Nothing Then ol = table_entries.Length ReDim Preserve table_entries(table_entries.Length + Length) Else ReDim table_entries(Length) End If Dim ent_offset As UInt64 For i = 0 To Length Step 1 ent_offset = ConvertToInteger(Offset + 8 + (i * 2), 2) If Offset &lt;&gt; 100 Then ent_offset = ent_offset + Offset &#39;Table Cell auslesen Dim t = GVL(ent_offset) Dim size As Int64 = CVL(ent_offset, t) Dim s = GVL(ent_offset + (t - ent_offset) + 1) table_entries(ol + i).row_id = CVL(ent_offset + (t - ent_offset) + 1, s) &#39;Table Content &#39;Resetting the offset ent_offset = ent_offset + (s - ent_offset) + 1 &#39;Now get to the Record Header t = GVL(ent_offset) s = t Dim Rec_Header_Size As Int64 = CVL(ent_offset, t) &#39;Record Header Length Dim Field_Size() As record_header_field Dim size_read As Int64 = (ent_offset - t) + 1 Dim j = 0 &#39;Now get the field sizes and fill in the Values While size_read &lt; Rec_Header_Size ReDim Preserve Field_Size(j) t = s + 1 s = GVL(t) Field_Size(j).type = CVL(t, s) If Field_Size(j).type &gt; 9 Then If IsOdd(Field_Size(j).type) Then Field_Size(j).size = (Field_Size(j).type - 13) / 2 Else Field_Size(j).size = (Field_Size(j).type - 12) / 2 End If Else Field_Size(j).size = SQLDataTypeSize(Field_Size(j).type) End If size_read = size_read + (s - t) + 1 j = j + 1 End While ReDim table_entries(ol + i).content(Field_Size.Length - 1) Dim counter As Integer = 0 For k = 0 To Field_Size.Length - 1 Step 1 If Field_Size(k).type &gt; 9 Then If Not IsOdd(Field_Size(k).type) Then If encoding = 1 Then table_entries(ol + i).content(k) = System.Text.Encoding.Default.GetString(db_bytes, ent_offset + Rec_Header_Size + counter, Field_Size(k).size) ElseIf encoding = 2 Then table_entries(ol + i).content(k) = System.Text.Encoding.Unicode.GetString(db_bytes, ent_offset + Rec_Header_Size + counter, Field_Size(k).size) ElseIf encoding = 3 Then table_entries(ol + i).content(k) = System.Text.Encoding.BigEndianUnicode.GetString(db_bytes, ent_offset + Rec_Header_Size + counter, Field_Size(k).size) End If Else table_entries(ol + i).content(k) = System.Text.Encoding.Default.GetString(db_bytes, ent_offset + Rec_Header_Size + counter, Field_Size(k).size) End If Else table_entries(ol + i).content(k) = CStr(ConvertToInteger(ent_offset + Rec_Header_Size + counter, Field_Size(k).size)) End If counter = counter + Field_Size(k).size Next Next ElseIf db_bytes(Offset) = &amp;H5 Then &#39;internal node Dim Length As UInt16 = ConvertToInteger(Offset + 3, 2) - 1 Dim ent_offset As UInt16 For i = 0 To Length Step 1 ent_offset = ConvertToInteger(Offset + 12 + (i * 2), 2) ReadTableFromOffset((ConvertToInteger(Offset + ent_offset, 4) - 1) * page_size) Next ReadTableFromOffset((ConvertToInteger(Offset + 8, 4) - 1) * page_size) End If Return True Catch : End Try End Function &#39; Reads a complete table with all entries in it Public Function ReadTable(ByVal TableName As String) As Boolean Try &#39; First loop through sqlite_master and look if table exists Dim found As Integer = -1 For i = 0 To master_table_entries.Length Step 1 If master_table_entries(i).item_name.ToLower().CompareTo(TableName.ToLower()) = 0 Then found = i Exit For End If Next If found = -1 Then Return False Dim fields() = master_table_entries(found).sql_statement.Substring(master_table_entries(found).sql_statement.IndexOf(&#34;(&#34;) + 1).Split(&#34;,&#34;) For i = 0 To fields.Length - 1 Step 1 fields(i) = LTrim(fields(i)) Dim index = fields(i).IndexOf(&#34; &#34;) If index &gt; 0 Then fields(i) = fields(i).Substring(0, index) If fields(i).IndexOf(&#34;UNIQUE&#34;) = 0 Then Exit For Else ReDim Preserve field_names(i) field_names(i) = fields(i) End If Next Return ReadTableFromOffset((master_table_entries(found).root_num - 1) * page_size) Catch : End Try End Function &#39; Returns the row count of current table Public Function GetRowCount() As Integer Return table_entries.Length End Function &#39; Returns a Value from current table in row row_num with field number field Public Function GetValue(ByVal row_num As Integer, ByVal field As Integer) As String Try If row_num &gt;= table_entries.Length Then Return Nothing If field &gt;= table_entries(row_num).content.Length Then Return Nothing Return table_entries(row_num).content(field) Catch : End Try End Function &#39; Returns a Value from current table in row row_num with field name field Public Function GetValue(ByVal row_num As Integer, ByVal field As String) As String Try Dim found As Integer = -1 For i = 0 To field_names.Length Step 1 If field_names(i).ToLower().CompareTo(field.ToLower()) = 0 Then found = i Exit For End If Next If found = -1 Then Return Nothing Return GetValue(row_num, found) Catch : End Try End Function &#39; Returns a String-Array with all Tablenames Public Function GetTableNames() As String() Try Dim retVal As String() Dim arr = 0 For i = 0 To master_table_entries.Length - 1 Step 1 If master_table_entries(i).item_type = &#34;table&#34; Then ReDim Preserve retVal(arr) retVal(arr) = master_table_entries(i).item_name arr = arr + 1 End If Next Return retVal Catch : End Try End Function &#39; Constructor Public Sub New(ByVal baseName As String) Try &#39;Page Number n is page_size*(n-1) If File.Exists(baseName) Then FileOpen(1, baseName, OpenMode.Binary, OpenAccess.Read, OpenShare.Shared) Dim asi As String = Space(LOF(1)) FileGet(1, asi) FileClose(1) db_bytes = System.Text.Encoding.Default.GetBytes(asi) If System.Text.Encoding.Default.GetString(db_bytes, 0, 15).CompareTo(&#34;SQLite format 3&#34;) &lt;&gt; 0 Then Throw New Exception(&#34;Not a valid SQLite 3 Database File&#34;) End End If If db_bytes(52) &lt;&gt; 0 Then Throw New Exception(&#34;Auto-vacuum capable database is not supported&#34;) End ElseIf ConvertToInteger(44, 4) &gt;= 4 Then Throw New Exception(&#34;No supported Schema layer file-format&#34;) End End If page_size = ConvertToInteger(16, 2) encoding = ConvertToInteger(56, 4) If encoding = 0 Then encoding = 1 &#39;Now we read the sqlite_master table &#39;Offset is 100 in first page ReadMasterTable(100) End If Catch : End Try End Sub End Class </code></pre> <p>Though i have no idea how to convert it to Go</p> <hr/>**评论:**<br/><br/>j_d_q: <pre><p>No useful content, here, just a thought: link to the code or create a gist. On mobile, it took me almost 19 1/2 minutes to scroll to the comments</p></pre>TheMerovius: <pre><p>Googling 8s, I found this: <a href="https://github.com/sbinet/sqlite3" rel="nofollow">https://github.com/sbinet/sqlite3</a> Probably not maintained and somewhat likely not working, but that what it&#39;d take; re-implementing sqlite in go. Because sqlite is an embedded database, there really are just two ways to use it: embed it (i.e. use cgo) or reimplement it. Most people won&#39;t find the latter very rewarding, which is why I assume you&#39;ll have trouble finding it.</p></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

941 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传