Author Topic: SQLite in QB64 - Windows only (so far)  (Read 3301 times)

0 Members and 1 Guest are viewing this topic.

Offline SpriggsySpriggs

  • Forum Resident
  • Posts: 1145
  • Larger than life
    • View Profile
    • GitHub
SQLite in QB64 - Windows only (so far)
« on: September 07, 2021, 06:10:54 pm »
Since I do so much programming with SQL, I decided to try my hand at SQLite. SQLite uses SQL syntax to interact with a file as a database. It is used in millions of applications and software across the world. It is quicker than standard file operations and quicker than algorithms you could write yourself to get data from a file. I've started using it and all the testing so far has been magnificent. SQLite could be used to replace random access files and possibly even INIs. If you already know SQL then you will feel right at home using SQLite. I've kept the function names the same as the ones I'm using in my ODBC project and my MySQL rewrite.

Here is the code I've been using in my tests:
Code: QB64 $NOPREFIX: [Select]
  1. $ExeIcon:'databases.ico'
  2.  
  3. Const SQLITE_ABORT = 4
  4. Const SQLITE_AUTH = 23
  5. Const SQLITE_BUSY = 5
  6. Const SQLITE_CANTOPEN = 14
  7. Const SQLITE_CONSTRAINT = 19
  8. Const SQLITE_CORRUPT = 11
  9. Const SQLITE_DONE = 101
  10. Const SQLITE_EMPTY = 16
  11. Const SQLITE_ERROR = 1
  12. Const SQLITE_FORMAT = 24
  13. Const SQLITE_FULL = 13
  14. Const SQLITE_INTERNAL = 2
  15. Const SQLITE_INTERRUPT = 9
  16. Const SQLITE_IOERR = 10
  17. Const SQLITE_LOCKED = 6
  18. Const SQLITE_MISMATCH = 20
  19. Const SQLITE_MISUSE = 21
  20. Const SQLITE_NOLFS = 22
  21. Const SQLITE_NOMEM = 7
  22. Const SQLITE_NOTADB = 26
  23. Const SQLITE_NOTFOUND = 12
  24. Const SQLITE_NOTICE = 27
  25. Const SQLITE_OK = 0
  26. Const SQLITE_PERM = 3
  27. Const SQLITE_PROTOCOL = 15
  28. Const SQLITE_RANGE = 25
  29. Const SQLITE_READONLY = 8
  30. Const SQLITE_ROW = 100
  31. Const SQLITE_SCHEMA = 17
  32. Const SQLITE_TOOBIG = 18
  33. Const SQLITE_WARNING = 28
  34.  
  35. Const SQLITE_INTEGER = 1
  36. Const SQLITE_FLOAT = 2
  37. Const SQLITE_BLOB = 4
  38. Const SQLITE_NULL = 5
  39. Const SQLITE_TEXT = 3
  40.  
  41. Type SQLITE_FIELD
  42.     As Long type
  43.     As String columnName, value
  44.  
  45. ConsoleTitle "SQLite Test"
  46.  
  47.     Function sqlite3_open& (filename As String, Byval ppDb As Offset)
  48.     Sub sqlite3_open (filename As String, Byval ppDb As Offset)
  49.     Function sqlite3_prepare& (ByVal db As Offset, zSql As String, Byval nByte As Long, Byval ppStmt As Offset, Byval pzTail As Offset)
  50.     Function sqlite3_step& (ByVal sqlite3_stmt As Offset)
  51.     Function sqlite3_changes& (ByVal sqlite3_stmt As Offset)
  52.     Function sqlite3_column_count& (ByVal sqlite3_stmt As Offset)
  53.     Function sqlite3_column_type& (ByVal sqlite3_stmt As Offset, Byval iCol As Long)
  54.     Function sqlite3_column_name$ (ByVal sqlite3_stmt As Offset, Byval N As Long)
  55.     Function sqlite3_column_text$ (ByVal sqlite3_stmt As Offset, Byval iCol As Long)
  56.     Function sqlite3_column_bytes& (ByVal sqlite3_stmt As Offset, Byval iCol As Long)
  57.     Sub sqlite3_finalize (ByVal sqlite3_stmt As Offset)
  58.     Sub sqlite3_close (ByVal db As Offset)
  59.  
  60. Dim Shared As Offset hSqlite, hStmt
  61. ReDim Shared As SQLITE_FIELD DB_Result(1 To 1, 1 To 1)
  62.  
  63. Dim As String db: db = "test.db"
  64. If DB_Open(db) Then
  65.     Dim As String conTitle: conTitle = "SQLite Test - " + db: ConsoleTitle conTitle
  66.     If DB_QUERY("SELECT * FROM test") = SQLITE_OK Then
  67.         Dim As Long column, row
  68.         For row = 1 To UBound(DB_Result, 2)
  69.             Print "Row"; row
  70.             For column = 1 To UBound(DB_Result, 1)
  71.                 Print , GetDataType(DB_Result(column, row).type), DB_Result(column, row).columnName, DB_Result(column, row).value
  72.             Next
  73.         Next
  74.     End If
  75.     'If DB_QUERY("INSERT INTO test(column2) VALUES ('And now, a fifth row!');") = SQLITE_OK Then
  76.     '    Print DB_AffectedRows
  77.     'End If
  78.     'If DB_QUERY("UPDATE test SET column2 = 'And now, a fourth row!' WHERE column1 = '4';") = SQLITE_OK Then
  79.     '    Print DB_AffectedRows
  80.     'End If
  81.  
  82. DB_Close
  83.  
  84. Function DB_Open%% (sqlitedb As String)
  85.     If sqlite3_open(sqlitedb, Offset(hSqlite)) = SQLITE_OK Then DB_Open = -1 Else DB_Open = 0
  86.  
  87. Sub DB_Open (sqlitedb As String)
  88.     sqlite3_open sqlitedb, Offset(hSqlite)
  89.  
  90. Sub DB_QUERY (sql_command As String)
  91.     If sqlite3_prepare(hSqlite, sql_command, Len(sql_command), Offset(hStmt), 0) = SQLITE_OK Then
  92.         Dim As Long colCount: colCount = sqlite3_column_count(hStmt)
  93.         Dim As Long column, row, ret
  94.         ret = sqlite3_step(hStmt)
  95.         If ret = SQLITE_ROW Then
  96.             Do
  97.                 row = row + 1
  98.                 For column = 0 To colCount - 1
  99.                     ReDim Preserve As SQLITE_FIELD DB_Result(colCount, row)
  100.                     DB_Result(column + 1, row).type = sqlite3_column_type(hStmt, column)
  101.                     DB_Result(column + 1, row).columnName = sqlite3_column_name(hStmt, column)
  102.                     DB_Result(column + 1, row).value = sqlite3_column_text(hStmt, column)
  103.                 Next
  104.                 ret = sqlite3_step(hStmt)
  105.             Loop While ret = SQLITE_ROW
  106.         Else
  107.             'do some error catching
  108.         End If
  109.         sqlite3_finalize hStmt
  110.     End If
  111.  
  112. Function DB_QUERY& (sql_command As String)
  113.     If sqlite3_prepare(hSqlite, sql_command, Len(sql_command), Offset(hStmt), 0) = SQLITE_OK Then
  114.         Dim As Long colCount: colCount = sqlite3_column_count(hStmt)
  115.         Dim As Long column, row, ret
  116.         ret = sqlite3_step(hStmt)
  117.         If ret = SQLITE_ROW Then
  118.             DB_QUERY = SQLITE_OK
  119.             Do
  120.                 row = row + 1
  121.                 For column = 0 To colCount - 1
  122.                     ReDim Preserve As SQLITE_FIELD DB_Result(colCount, row)
  123.                     DB_Result(column + 1, row).type = sqlite3_column_type(hStmt, column)
  124.                     DB_Result(column + 1, row).columnName = sqlite3_column_name(hStmt, column)
  125.                     DB_Result(column + 1, row).value = sqlite3_column_text(hStmt, column)
  126.                 Next
  127.                 ret = sqlite3_step(hStmt)
  128.             Loop While ret = SQLITE_ROW
  129.         ElseIf ret = SQLITE_DONE Then DB_QUERY = SQLITE_OK
  130.         Else DB_QUERY = SQLITE_ERROR
  131.             'do some error catching
  132.         End If
  133.         sqlite3_finalize hStmt
  134.     End If
  135.  
  136. Function DB_AffectedRows&
  137.     DB_AffectedRows = sqlite3_changes(hSqlite)
  138.  
  139. Function GetDataType$ (dataType As Long)
  140.     Select Case dataType
  141.         Case SQLITE_INTEGER
  142.             GetDataType = "INTEGER"
  143.         Case SQLITE_FLOAT
  144.             GetDataType = "FLOAT"
  145.         Case SQLITE_BLOB
  146.             GetDataType = "BLOB"
  147.         Case SQLITE_NULL
  148.             GetDataType = "NULL"
  149.         Case SQLITE_TEXT
  150.             GetDataType = "TEXT"
  151.     End Select
  152.  
  153. Sub DB_Close
  154.     sqlite3_close hSqlite

A screenshot of the above code running:
 
Screenshot 2021-09-07 180659.png


I've attached the database file I'm working with. You can run regular SQL queries (INSERT, UPDATE, DELETE, SELECT, etc.) against it and test it out for yourself. Personally, SQLite will be something I end up incorporating in future projects for myself.
* test.db (Filesize: 8 KB, Downloads: 216)
* sqlite3.dll (Filesize: 2.03 MB, Downloads: 236)

* databases.ico (Filesize: 29.22 KB, Dimensions: 16x16, Views: 468)
Shuwatch!