'The biggest problem I had while trying to get this source code to work was...
' errors, somehow, related to the variables within each and every sub or function
' I don't understand why, but I had to empty them before exiting a sub or function.
' I thought local variables, within a sub or function, were suppose to br valid ONLY within that sub or function.
' For some strange reason... they were not... they were causing errors on the global level.
' (even after giving them each a unique name)
$Option EXPLICIT

$Include "RapidQ.inc"
$Include "rq_sqlite.inc"
$Include "RegistryRead.inc" 'NOTE: Used in the DateTime_Conversion Function

Const GWL_HWNDPARENT = (-8)
Const HWND_DESKTOP   = 0

Type SYSTEMTIME_UDT
    wYear         As WORD
    wMonth        As WORD
    wDayOfWeek    As WORD
    wDay          As WORD
    wHour         As WORD
    wMinute       As WORD
    wSecond       As WORD
    wMilliseconds As WORD
End Type

Dim ST As SYSTEMTIME_UDT

Declare Sub GetLocalTime _ 'LOCAL
            Lib "kernel32" Alias "GetLocalTime" _
            (ByRef lpSystemTime As SYSTEMTIME_UDT)

Declare Sub GetSystemTime _ 'UTC
            Lib "kernel32" Alias "GetSystemTime" _
            (ByRef lpSystemTime As SYSTEMTIME_UDT)

Declare Function SetWindowLong _
        Lib "user32" Alias "SetWindowLongA" _
        (ByVal hWnd As Long, ByVal nIndex As Long, _
         ByVal dwNewLong As Long) As Long

Declare Function SetFocus _
        Lib "user32" Alias "SetFocus" _
        (ByVal hwnd As Long) As Long

Declare Sub MainForm_OnShow
Declare Sub MainForm_OnClose
Declare Sub MainForm_OnResize

Declare Sub mnuOpen_OnClick

' These subroutines are UNFINISHED!!!
' I never got around to getting them to work.
' Obviously they of great importance but
' I only got as far as reading in a sqlite file.
' WARNING: ALWAYS use a "backup" copy of a sqlite file
' before implementing these subroutines.
'Declare Sub mnuUpdate_OnClick
'Declare Sub mnuInsert_OnClick
'Declare Sub mnuDelete_OnClick

Declare Sub ComboBox_OnChange(Sender As QComboBox)

Declare Sub StringGrid_OnDrawCell(Col%, Row%, State%, Rect As QRect, Sender As QStringGrid)

Declare Sub StringGrid_Clear
Declare Sub StringGrid_AutoFit

Declare Sub ShowDataType(Col%, Row%)

Declare Function DateTime_Conversion(ByVal FromTo As String, ByVal sDate As String) As String

'numeric variable to signal the form OnResize event when it's ok to place
' the components on the form. form resizing occurs twice before
' you every actually see the form.
' the order of events are... OnResize, OnShow, OnResize, OnPaint
' I'm defining the location of the components within the OnResize
' event (so they're always adjusted nicely)... if I had let the
' placement occur during the first OnResize... an error message
' would occur before the OnShow event and halt execution. when
' I set formisshowing to True during the OnShow event... no error.
DefByte formisshowing = False

'numeric variable used for the result code from calling sqlcomm
' upon return it should be one of the following...
' if no error occurred for a query... 0 (zero)
' if an error did occur for a query... an error code
' if no error occurred for a statement... the number of records changed
' if an error did occur for a statement... an error code
DefLng sqlResRtn = 0

'string variable to hold the database name for use with
' the sqlite3_table_column_metadata function.
DefStr dbname = ""

'string variable passed as a parameter to sqlcomm
' (in case you forgot to clear it before calling sqlcomm... sqlcomm will clear it for you)
' upon return... it will be either null or contain an error message
DefStr sqlErrMsg = ""

'string variable passed as a parameter to sqlcomm
' this is the only parameter that can not be empty when you call sqlcomm
' it must be filled with a valid sql query or statement
DefStr sqlStrCmd = ""

'stringlist passed as a parameter to sqlcomm
' (in case you forgot to clear it before calling sqlcomm... sqlcomm will clear it for you)
' upon return... it should be filled with your results
Dim sqlStrLst As QStringList

DefStr MMDD  = ""
DefStr MMDDs = ""
DefStr MMDDe = ""
DefStr sRet  = ""

Dim OpenDialog As QOpenDialog
    OpenDialog.Filter = "sqlite or db|*.sqlite;*.db"

Create MainForm As QForm
  Width    = 1024
  Height   = 768
  Left     = 0
  Top      = 30
  Caption  = " rq sql editor"
  OnShow   = MainForm_OnShow
  OnClose  = MainForm_OnClose
  OnResize = MainForm_OnResize
  Create MainMenu As QMainMenu
    Create mnuOpen As QMenuItem
      Caption = " Open "
      OnClick = mnuOpen_OnClick
    End Create
    Create mnuExit As QMenuItem
      Caption = " Exit "
      OnClick = MainForm_OnClose
    End Create

' ONLY uncomment these menuitems AFTER
' you've got coding that "should" work.
' AND only use a "backup" copy of a sqlite
' file for testing your code.
'    Create mnuUpdate As QMenuItem
'      Caption = " Update "
'      OnClick = mnuUpdate_OnClick
'      Enabled = False
'    End Create
'    Create mnuInsert As QMenuItem
'      Caption = " Insert "
'      OnClick = mnuInsert_OnClick
'      Enabled = False
'    End Create
'    Create mnuDelete As QMenuItem
'      Caption = " Delete "
'      OnClick = mnuDelete_OnClick
'      Enabled = False
'    End Create

  End Create
  Create conPanel As QPanel
    BevelWidth = 1
    BevelInner = bvNone
    BevelOuter = bvLowered
    Create tblLabel As QLabel
      AutoSize  = False
      Font.Name = "Lucida Sans Typewriter"
      Font.Size = 10
      Caption   = "Tables"
    End Create
    Create tblCombo As QComboBox
      Style     = csDropDownList
      Font.Name = "Lucida Sans Typewriter"
      Font.Size = 10
      OnChange  = ComboBox_OnChange
      Enabled   = False
    End Create
    Create colLabel As QLabel
      AutoSize  = False
      Font.Name = "Lucida Sans Typewriter"
      Font.Size = 10
      Caption   = "Columns"
    End Create
    Create colCombo As QComboBox
      Style     = csDropDownList
      Font.Name = "Lucida Sans Typewriter"
      Font.Size = 10
      OnChange  = ComboBox_OnChange
      Enabled   = False
    End Create
    Create srtLabel As QLabel
      AutoSize  = False
      Font.Name = "Lucida Sans Typewriter"
      Font.Size = 10
      Caption   = "Sort"
    End Create
    Create srtCombo As QComboBox
      Style     = csDropDownList
      Font.Name = "Lucida Sans Typewriter"
      Font.Size = 10
      OnChange  = ComboBox_OnChange
      Enabled   = False
    End Create
    Create msgEdit As QEdit
      AutoSize  = False
      ReadOnly  = True
      Font.Name = "Lucida Sans Typewriter"
      Font.Size = 10
      Text      = " Open a database file"
    End Create
  End Create
  Create datPanel As QPanel
    BevelWidth = 1
    BevelInner = bvNone
    BevelOuter = bvLowered
    Color      = clWhite
    Create datLabel1 As QLabel
      AutoSize  = False
      Font.Name = "Lucida Sans Typewriter"
      Font.Size = 10
      Alignment = taCenter
      Caption   = "If data is a Date"
      Enabled = False
    End Create
    Create datLabel2 As QLabel
      AutoSize  = False
      Font.Name = "Lucida Sans Typewriter"
      Font.Size = 10
      Font.Bold = True
      Alignment = taCenter
      Caption   = ""
    End Create
    Create datLabel3 As QLabel
      AutoSize  = False
      Font.Name = "Lucida Sans Typewriter"
      Font.Size = 10
      Caption   = ""
    End Create
  End Create
  Create dbPanel As QPanel
    BevelWidth = 1
    BevelInner = bvNone
    BevelOuter = bvLowered
    Create dbStrGrd As QStringGrid
      BorderStyle      = bsNone
      FixedCols        = 0
      FixedRows        = 1
      ColCount         = 2
      RowCount         = 2
      DefaultRowHeight = 18
      DefaultColWidth  = 80
      ScrollBars       = ssboth
      Separator        = dbsepar
      Font.Name        = "Lucida Sans Typewriter" '"Courier New"
      Font.Size        = 10
      Row              = 1
      Col              = 1
      OnDrawCell       = StringGrid_OnDrawCell
      Cell(0,0)        = "  Record"
      DelOptions(goRangeSelect)
    End Create
  End Create
  Create typPanel As QPanel
    BevelWidth = 1
    BevelInner = bvNone
    BevelOuter = bvLowered
    Color      = clWhite
    Create typLabel01 As QLabel
      AutoSize  = False
      Font.Name = "Lucida Sans Typewriter"
      Font.Size = 10
      Alignment = taCenter
      Caption   = "Declared DataType"
      Enabled   = False
    End Create
    Create typLabel02 As QLabel
      AutoSize  = False
      Font.Name = "Lucida Sans Typewriter"
      Font.Size = 10
      Font.Bold = True
      Alignment = taCenter
      Caption   = ""
    End Create
    Create typLabel03 As QLabel
      AutoSize  = False
      Font.Name = "Lucida Sans Typewriter"
      Font.Size = 10
      Alignment = taCenter
      Caption   = "Collation Sequence"
      Enabled   = False
    End Create
    Create typLabel04 As QLabel
      AutoSize  = False
      Font.Name = "Lucida Sans Typewriter"
      Font.Size = 10
      Font.Bold = True
      Alignment = taCenter
      Caption   = ""
    End Create
    Create typLabel05 As QLabel
      AutoSize  = False
      Font.Name = "Lucida Sans Typewriter"
      Font.Size = 10
      Alignment = taCenter
      Caption   = "NOT NULL"
      Enabled   = False
    End Create
    Create typLabel06 As QLabel
      AutoSize  = False
      Font.Name = "Lucida Sans Typewriter"
      Font.Size = 10
      Alignment = taCenter
      Caption   = "Constraint Exists"
      Enabled   = False
    End Create
    Create typLabel07 As QLabel
      AutoSize  = False
      Font.Name = "Lucida Sans Typewriter"
      Font.Size = 10
      Font.Bold = True
      Alignment = taCenter
      Caption   = ""
    End Create
    Create typLabel08 As QLabel
      AutoSize  = False
      Font.Name = "Lucida Sans Typewriter"
      Font.Size = 10
      Alignment = taCenter
      Caption   = "PrimaryKey"
      Enabled   = False
    End Create
    Create typLabel09 As QLabel
      AutoSize  = False
      Font.Name = "Lucida Sans Typewriter"
      Font.Size = 10
      Font.Bold = True
      Alignment = taCenter
      Caption   = ""
    End Create
    Create typLabel10 As QLabel
      AutoSize  = False
      Font.Name = "Lucida Sans Typewriter"
      Font.Size = 10
      Alignment = taCenter
      Caption   = "Auto-Incremented"
      Enabled   = False
    End Create
    Create typLabel11 As QLabel
      AutoSize  = False
      Font.Name = "Lucida Sans Typewriter"
      Font.Size = 10
      Font.Bold = True
      Alignment = taCenter
      Caption   = ""
    End Create
  End Create
End Create

SetWindowLong(MainForm.Handle, GWL_HWNDPARENT, HWND_DESKTOP)
SetWindowLong(Application.Handle, GWL_HWNDPARENT, MainForm.Handle)

MainForm.ShowModal

Sub MainForm_OnShow
    formisshowing = True
End Sub

Sub MainForm_OnClose
    formisshowing = False
    dbname = ""
    sqlStrLst.Clear
    sqlErrMsg = ""
    sqlStrCmd = ""
    sqlResRtn = 0
    Application.Terminate
End Sub

Sub MainForm_OnResize
    If formisshowing = True Then
      conPanel.Width  = (MainForm.ClientWidth - 200)
      conPanel.Height = 63
      conPanel.Left   = 0
      conPanel.Top    = 0

      tblLabel.Width  = 50
      tblLabel.Height = 16
      tblLabel.Left   = 10
      tblLabel.Top    = 10

      tblCombo.Width  = 180
      tblCombo.Height = 21
      tblCombo.Left   = 66
      tblCombo.Top    = 7

      colLabel.Width  = 60
      colLabel.Height = 16
      colLabel.Left   = ((conPanel.ClientWidth / 2) - 118)
      colLabel.Top    = 10

      colCombo.Width  = 180
      colCombo.Height = 21
      colCombo.Left   = ((conPanel.ClientWidth / 2) - 52)
      colCombo.Top    = 7

      srtLabel.Width  = 36
      srtLabel.Height = 16
      srtLabel.Left   = (conPanel.ClientWidth - 232)
      srtLabel.Top    = 10

      srtCombo.Width     = 180
      srtCombo.Height    = 21
      srtCombo.Left      = (conPanel.ClientWidth - 190)
      srtCombo.Top       = 7
      srtCombo.Clear
      srtCombo.ItemIndex = 0

      msgEdit.Width    = (conPanel.ClientWidth - 20)
      msgEdit.Height   = 21
      msgEdit.Left     = 10
      msgEdit.Top      = 36
      msgEdit.SelStart = 0

      datPanel.Width  = 200
      datPanel.Height = 63
      datPanel.Left   = (MainForm.ClientWidth - 200)
      datPanel.Top    = 0

      datLabel1.Width  = (datPanel.ClientWidth - 46)
      datLabel1.Height = 16
      datLabel1.Left   = 23
      datLabel1.Top    = 5

      datLabel2.Width  = (datPanel.ClientWidth - 46)
      datLabel2.Height = 16
      datLabel2.Left   = 23
      datLabel2.Top    = 25

      datLabel3.Width  = (datPanel.ClientWidth - 46)
      datLabel3.Height = 16
      datLabel3.Left   = 23
      datLabel3.Top    = 45

      dbPanel.Width  = (MainForm.ClientWidth - 200)
      dbPanel.Height = (MainForm.ClientHeight - 63)
      dbPanel.Left   = 0
      dbPanel.Top    = 63

      dbStrGrd.Width  = (dbPanel.ClientWidth - 2)
      dbStrGrd.Height = (dbPanel.ClientHeight - 2)
      dbStrGrd.Left   = 1
      dbStrGrd.Top    = 1

      typPanel.Width  = 200
      typPanel.Height = (MainForm.ClientHeight - 440)
      typPanel.Left   = (MainForm.ClientWidth - 200)
      typPanel.Top    = 440

      typLabel01.Width  = (typPanel.ClientWidth - 46)
      typLabel01.Height = 16
      typLabel01.Left   = 23
      typLabel01.Top    = 10

      typLabel02.Width  = (typPanel.ClientWidth - 46)
      typLabel02.Height = 16
      typLabel02.Left   = 23
      typLabel02.Top    = 30

      typLabel03.Width  = (typPanel.ClientWidth - 46)
      typLabel03.Height = 16
      typLabel03.Left   = 23
      typLabel03.Top    = 60

      typLabel04.Width  = (typPanel.ClientWidth - 46)
      typLabel04.Height = 16
      typLabel04.Left   = 23
      typLabel04.Top    = 80

      typLabel05.Width  = (typPanel.ClientWidth - 46)
      typLabel05.Height = 16
      typLabel05.Left   = 23
      typLabel05.Top    = 110

      typLabel06.Width  = (typPanel.ClientWidth - 46)
      typLabel06.Height = 16
      typLabel06.Left   = 23
      typLabel06.Top    = 125

      typLabel07.Width  = (typPanel.ClientWidth - 46)
      typLabel07.Height = 16
      typLabel07.Left   = 23
      typLabel07.Top    = 145

      typLabel08.Width  = (typPanel.ClientWidth - 46)
      typLabel08.Height = 16
      typLabel08.Left   = 23
      typLabel08.Top    = 175

      typLabel09.Width  = (typPanel.ClientWidth - 46)
      typLabel09.Height = 16
      typLabel09.Left   = 23
      typLabel09.Top    = 195

      typLabel10.Width  = (typPanel.ClientWidth - 46)
      typLabel10.Height = 16
      typLabel10.Left   = 23
      typLabel10.Top    = 225

      typLabel11.Width  = (typPanel.ClientWidth - 46)
      typLabel11.Height = 16
      typLabel11.Left   = 23
      typLabel11.Top    = 245

      SetFocus(dbStrGrd.Handle)
    End If
End Sub

Sub mnuOpen_OnClick
    Dim i As Long

    If OpenDialog.Execute Then
      dbfile = OpenDialog.FileName

      tblCombo.Clear
      tblCombo.Additems("")
      tblCombo.Enabled = False
      StringGrid_Clear

      sqlStrLst.Clear
      sqlErrMsg = ""
      sqlStrCmd = ""
      sqlResRtn = 0

      sqlStrCmd = "SELECT * FROM sqlite_master WHERE type='table';"
      sqlResRtn = sql3comm(sqlStrCmd, sqlErrMsg, sqlStrLst)

      If sqlResRtn <> SQLITE_OK Then
        msgEdit.Text = " " + sqlErrMsg
      Else
        For i = 1 To sqlStrLst.ItemCount - 1
          tblCombo.Additems(Field$(sqlStrLst.Item(i), dbsepar, 2))
        Next i
        tblCombo.ItemIndex = 0
        tblCombo.Enabled = True
        msgEdit.Text = " Select a table from the left ComboBox"
        colCombo.Clear
        colCombo.AddItems("*")
        colCombo.ItemIndex = 0
      End If

      dbname = ""

      sqlStrLst.Clear
      sqlErrMsg = ""
      sqlStrCmd = ""
      sqlResRtn = 0

      sqlStrCmd = "Pragma database_list;"
      sqlResRtn = sql3comm(sqlStrCmd, sqlErrMsg, sqlStrLst)

      If sqlResRtn <> SQLITE_OK Then
        msgEdit.Text = " " + sqlErrMsg
      Else
        dbname = Field$(sqlStrLst.Item(1),dbsepar,2)
      End If

      sqlStrLst.Clear
      sqlErrMsg = ""
      sqlStrCmd = ""
      sqlResRtn = 0
    End If

    i = 0

    SetFocus(dbStrGrd.Handle)
End Sub

' These are the 3 subroutines I never got around to working on.
' Leave them commented out until you've got code that should work.
' And ONLY test them with a backup copy of a sqlite file.

'Sub mnuUpdate_OnClick
'    ShowMessage("Are you sure?")
''    sql = "UPDATE tb_states SET state_name = '" + ediStateName.EditText + "', state_code = '" + ediStateCode.EditText + "' " + "WHERE state_id = '" + lviStates.Item(lviStates.itemIndex).Caption + "';"
'    SetFocus(dbStrGrd.Handle)
'End Sub

'Sub mnuInsert_OnClick
''    sql = "insert into tb_states (state_name, state_code) values ('" + ediStateName.EditText + "', '" + ediStateCode.EditText + "');"
'    SetFocus(dbStrGrd.Handle)
'End Sub

'Sub mnuDelete_OnClick
''    sql = "DELETE FROM tb_states WHERE state_id = '" + lviStates.Item(lviStates.itemIndex).Caption + "';"
'    SetFocus(dbStrGrd.Handle)
'End Sub

Sub ComboBox_OnChange(Sender As QComboBox)
    Dim x As Long
    Dim y As Long

    If tblCombo.ItemIndex > 0 Then
      If Sender.Handle = tblCombo.Handle Then
        colCombo.Clear
        colCombo.AddItems("*")
        colCombo.ItemIndex = 0
        srtCombo.Clear
        srtCombo.AddItems("")
        srtCombo.ItemIndex = 0
      End If
      sqlStrLst.Clear
      sqlErrMsg = ""
      sqlStrCmd = ""
      sqlResRtn = 0
      If srtCombo.ItemIndex = 0 Then
        sqlStrCmd = "Select "+colCombo.Item(colCombo.ItemIndex)+" From "+tblCombo.Item(tblCombo.ItemIndex)+";"
      Else
        If dbStrGrd.RowCount > 2 Then
          sqlStrCmd = "Select "+colCombo.Item(colCombo.ItemIndex)+" From "+tblCombo.Item(tblCombo.ItemIndex)+" Order By "+srtCombo.Item(srtCombo.ItemIndex)+";"
        End If
      End If
      msgEdit.text = " Query: " + sqlStrCmd
      sqlResRtn = sql3comm(sqlStrCmd, sqlErrMsg, sqlStrLst)
      If sqlResRtn <> SQLITE_OK Then
        msgEdit.Text = " " + sqlErrMsg
      Else
        StringGrid_Clear
        y = Tally(sqlStrLst.Item(0), dbsepar) + 2
        dbStrGrd.ColCount = y
        x = sqlStrLst.ItemCount
        dbStrGrd.RowCount = x
        For x = 0 To dbStrGrd.RowCount - 1
          For y = 0 To dbStrGrd.ColCount - 1
            If (y = 0) AND (x > 0) Then dbStrGrd.Cell(y, x) = Format$("  %.6d", x)
            If (y > 0) Then dbStrGrd.Cell(y, x) = Field$(sqlStrLst.Item(x), dbsepar, y)
            If ((y > 0) And (x = 0) And (Sender.Handle = tblCombo.Handle)) Then
              colCombo.AddItems(dbStrGrd.Cell(y, x))
              srtCombo.AddItems(dbStrGrd.Cell(y, x))
            End If
          Next y
        Next x
        StringGrid_AutoFit
        dbStrGrd.Row = 1
        dbStrGrd.Col = 1
      End If
'uncomment this AFTER you've got code that works
'      mnuInsert.Enabled = True
      colCombo.Enabled = True
      srtCombo.Enabled = True
    Else
      msgEdit.text = "Choose a table or Open a file"
      colCombo.Clear
      colCombo.AddItems("*")
      colCombo.ItemIndex = 0
      colCombo.Enabled = False
      srtCombo.Clear
      srtCombo.ItemIndex = 0
      srtCombo.Enabled = False
      StringGrid_Clear
'uncomment these AFTER you've got code that works
'      mnuUpdate.Enabled = False
'      mnuInsert.Enabled = False
'      mnuDelete.Enabled = False
    End If

    x = 0
    y = 0

    SetFocus(dbStrGrd.Handle)
End Sub

Sub StringGrid_OnDrawCell (Col%, Row%, State%, Rect As QRect, Sender AS QStringGrid)
    If Row% > 0 Then
      If State% = True Then
        If (Col% = 0) Then
          Sender.FillRect(Rect.Left+1, Rect.Top+1, Rect.Right-1, Rect.Bottom-1, RGB(000,128,255))
          Sender.TextOut(Rect.Left, Rect.Top, Sender.Cell(Col%, Row%), RGB(255,255,255), -1)
          If tblCombo.ItemIndex > 0 Then
'uncomment these AFTER you've got code that works
'            mnuUpdate.Enabled = True
'            mnuDelete.Enabled = True
          End If
        End If
        If (Col% > 0) Then
          Sender.FillRect(Rect.Left+1, Rect.Top+1, Rect.Right-1, Rect.Bottom-1, RGB(255,255,255))
          Sender.Rectangle(Rect.Left, Rect.Top, Rect.Left+Sender.ColWidths(Col%), Rect.Top+Sender.RowHeights(Row%), RGB(255,000,000))
          Sender.TextOut(Rect.Left, Rect.Top, Sender.Cell(Col%, Row%), 0, -1)
'uncomment these AFTER you've got code that works
'          mnuUpdate.Enabled = False
'          mnuDelete.Enabled = False
        End If
        If (Col% > 0) Then
          ShowDataType(Col%, Row%)
        Else
          typLabel01.Enabled = False
          typLabel02.Caption = ""
          typLabel03.Enabled = False
          typLabel04.Caption = ""
          typLabel05.Enabled = False
          typLabel06.Enabled = False
          typLabel07.Caption = ""
          typLabel08.Enabled = False
          typLabel09.Caption = ""
          typLabel10.Enabled = False
          typLabel11.Caption = ""
        End If
      Else
        Sender.FillRect(Rect.Left+1, Rect.Top+1, Rect.Right-1, Rect.Bottom-1, RGB(255,255,255))
        Sender.TextOut(Rect.Left, Rect.Top, Sender.Cell(Col%, Row%), 0, -1)
      End If
    End If
End Sub

Sub StringGrid_Clear
    Dim x As Long
    Dim y As Long

    For x = 0 To dbStrGrd.RowCount - 1
      For y = 0 To dbStrGrd.ColCount - 1
        dbStrGrd.Cell(y, x) = ""
      Next y
    Next x

    dbStrGrd.ColCount = 2
    dbStrGrd.RowCount = 2
    dbStrGrd.Row = 1
    dbStrGrd.Col = 1
    dbStrGrd.Cell(0,0) = "  Record"

    x = 0
    y = 0
End Sub

Sub StringGrid_AutoFit
    Dim ColChrCnt(dbStrGrd.ColCount) As Long
    Dim x As Long
    Dim y As Long

    For y = 0 To dbStrGrd.ColCount - 1
      ColChrCnt(y) = 0
    Next y

    For x = 0 To dbStrGrd.RowCount - 1
      For y = 0 To dbStrGrd.ColCount - 1
        ColChrCnt(y) = IIF(Len(dbStrGrd.Cell(y, x)) > ColChrCnt(y), Len(dbStrGrd.Cell(y, x)), ColChrCnt(y))
      Next y
    Next x

    For y = 0 To dbStrGrd.ColCount - 1
      dbStrGrd.ColWidths(y) = IIF(ColChrCnt(y) > 0, Int((ColChrCnt(y) * 8) + 16), 100)
      dbStrGrd.ColWidths(y) = IIF(dbStrGrd.ColWidths(y) < 80, 80, dbStrGrd.ColWidths(y))
    Next y

    For y = 0 To dbStrGrd.ColCount - 1
      ColChrCnt(y) = 0
    Next y

    ReDim ColChrCnt(0) As Long
    x = 0
    y = 0
End Sub

Sub ShowDataType(Col%, Row%)
    Dim hwdDB         As Long    '/* Connection handle */
    Dim szDbName      As String  '/* Database name or NULL */ (note: NULL does not work)
    Dim szTableName   As String  '/* Table name */
    Dim szColumnName  As String  '/* Column name */
    Dim lpzDataType   As Long    '/* OUTPUT: Declared data type */
    Dim lpzCollSeq    As Long    '/* OUTPUT: Collation sequence name */
    Dim lpNotNull     As Long    '/* OUTPUT: True if NOT NULL constraint exists */
    Dim lpPrimaryKey  As Long    '/* OUTPUT: True if column part of PrimaryKey */
    Dim lpAutoinc     As Long    '/* OUTPUT: True if column is auto-increment */

    Dim idx As Long
    Dim chr As String

    Dim Rtn  As Long
    Dim VFsM As String

    If (tblCombo.ItemIndex > 0) AND (dbfile <> "") AND (dbname <> "") Then
      VFsM         = ""
      szDbName     = dbname
      szTableName  = tblCombo.Item(tblCombo.ItemIndex)
      szColumnName = dbStrGrd.Cell(Col%,0)
      Rtn = sqlite3_open_v2(dbfile, hwdDB, dbflags, VFsM)
      If Rtn <> SQLITE_OK Then
        msgEdit.Text = sql3errMsg(hwdDB)
        Rtn = sqlite3_close_v2(hwdDB)
      Else
        Rtn = sqlite3_table_column_metadata(hwdDB, szDbName, szTableName, szColumnName, Varptr(lpzDataType), Varptr(lpzCollSeq), Varptr(lpNotNull), Varptr(lpPrimaryKey), Varptr(lpAutoinc))
        If Rtn <> SQLITE_OK Then
          msgEdit.Text = sql3errMsg(hwdDB)
          Rtn = sqlite3_close_v2(hwdDB)
        Else
          typLabel01.Enabled = True
          typLabel02.Caption = Varptr$(lpzDataType)
          typLabel03.Enabled = True
          typLabel04.Caption = Varptr$(lpzCollSeq)
          typLabel05.Enabled = True
          typLabel06.Enabled = True
          typLabel07.Caption = IIF(lpNotNull = 0, "False", "True")
          typLabel08.Enabled = True
          typLabel09.Caption = IIF(lpPrimaryKey = 0, "False", "True")
          typLabel10.Enabled = True
          typLabel11.Caption = IIF(lpAutoinc = 0, "False", "True")
          Rtn = sqlite3_close_v2(hwdDB)
          If lCase$(Varptr$(lpzDataType)) = "integer" Then
            If Len(dbStrGrd.Cell(Col%, Row%)) >= 10 Then
              idx = 0
numchk1:      idx = idx + 1
              chr = Mid$(dbStrGrd.Cell(Col%, Row%), idx, 1)
              If ((chr < Chr$(48)) Or (chr > Chr$(57))) Then Goto numchk2
              If idx < Len(dbStrGrd.Cell(Col%, Row%)) Then Goto numchk1
numchk2:      If idx < Len(dbStrGrd.Cell(Col%, Row%)) Then
                datLabel1.Enabled = False
                datLabel2.Caption = ""
                datLabel3.Caption = ""
              Else
                datLabel1.Enabled = True
                datLabel2.Caption = DateTime_Conversion("int2str", Left$(dbStrGrd.Cell(Col%, Row%), 10))
                datLabel3.Caption = "YYYY-MM-DD HH:MM:SS"
              End If
            Else
              datLabel1.Enabled = False
              datLabel2.Caption = ""
              datLabel3.Caption = ""
            End If
          End If

          If lCase$(Varptr$(lpzDataType)) = "real" Then
            If Len(dbStrGrd.Cell(Col%, Row%)) >= 9 Then
              If Tally(dbStrGrd.Cell(Col%, Row%), ".") = 1 Then
                idx = 0
numchk3:        idx = idx + 1
                chr = Mid$(dbStrGrd.Cell(Col%, Row%), idx, 1)
                If (chr = Chr$(46)) Then Goto numchk4
                If ((chr < Chr$(48)) Or (chr > Chr$(57))) Then Goto numchk5
numchk4:        If idx < Len(dbStrGrd.Cell(Col%, Row%)) Then Goto numchk3
numchk5:        If idx < Len(dbStrGrd.Cell(Col%, Row%)) Then
                  datLabel1.Enabled = False
                  datLabel2.Caption = ""
                  datLabel3.Caption = ""
                Else
                  datLabel1.Enabled = True
                  datLabel2.Caption = DateTime_Conversion("jul2str", Left$(dbStrGrd.Cell(Col%, Row%), 15))
                  datLabel3.Caption = "YYYY-MM-DD HH:MM:SS"
                End If
              Else
                datLabel1.Enabled = False
                datLabel2.Caption = ""
                datLabel3.Caption = ""
              End If
            End If
          End If
        End If
      End If
    Else
      typLabel01.Enabled = False
      typLabel02.Caption = ""
      typLabel03.Enabled = False
      typLabel04.Caption = ""
      typLabel05.Enabled = False
      typLabel06.Enabled = False
      typLabel07.Caption = ""
      typLabel08.Enabled = False
      typLabel09.Caption = ""
      typLabel10.Enabled = False
      typLabel11.Caption = ""
      datLabel1.Enabled = False
      datLabel2.Caption = ""
    End If

    hwdDB        = 0
    szDbName     = ""
    szTableName  = ""
    szColumnName = ""
    lpzDataType  = 0
    lpzCollSeq   = 0
    lpNotNull    = 0
    lpPrimaryKey = 0
    lpAutoinc    = 0
    idx          = 0
    chr          = ""
    Rtn          = 0
    VFsM         = ""
End Sub

Function DateTime_Conversion(ByVal FromTo As String, ByVal sDate As String) As String
    Dim GLT_HH     As Word
    Dim GST_HH     As Word
    Dim retDateTime As Double
    Dim julDateTime As Double
    Dim outDateTime As Double

    GetLocalTime(ST)
    GLT_HH = ST.wHour
    GetSystemTime(ST)
    GST_HH = ST.wHour
    julDateTime = 2440587.5

    sqlStrLst.Clear
    sqlErrMsg = ""
    sqlStrCmd = ""
    sqlResRtn = 0

    Select Case FromTo
      Case "str2int" 'String to Integer
        'YYYY-MM-DD HH:MM:SS to Signed Integer : (MUST HAVE (-) dashes in date and (:) colons in time)
        sqlStrCmd = "Select strftime('%J', '" + sDate + "');"
        sqlResRtn = sql3comm(sqlStrCmd, sqlErrMsg, sqlStrLst)
        If sqlResRtn <> SQLITE_OK Then
          msgEdit.Text = " " + sqlErrMsg
          Result = ""
        Else
          retDateTime = Val(sqlStrLst.Item(1))
          MMDD = Field$(Date$,"-",1) + Field$(Date$,"-",2)
          sRet = RegReadValue(HKEY_LOCAL_MACHINE, "SYSTEM\CurrentControlSet\Control\TimeZoneInformation", "DaylightStart")
          MMDDs = Field$(sRet,dbsepar,3) + Field$(sRet,dbsepar,7)
          sRet = RegReadValue(HKEY_LOCAL_MACHINE, "SYSTEM\CurrentControlSet\Control\TimeZoneInformation", "StandardStart")
          MMDDe = Field$(sRet,dbsepar,3) + Field$(sRet,dbsepar,7)
          If (MMDD >= MMDDs) AND (MMDD <= MMDDe) Then
            outDateTime = ((retDateTime-julDateTime) * (24*60*60)) + (1*60*60)
          Else
            outDateTime = ((retDateTime-julDateTime) * (24*60*60))
          End If
          Result = Format$("%.0f", outDateTime)
        End If
      Case "int2str" 'Integer to String
        'Signed Integer to YYYY-MM-DD HH:MM:SS : (up to 11 whole numbers e.g. -nnnnnnnnnnn, nnnnnnnnnnnn)
        sqlStrCmd = "Select datetime('" + sDate + "', 'unixepoch');"
        sqlResRtn = sql3comm(sqlStrCmd, sqlErrMsg, sqlStrLst)
        If sqlResRtn <> SQLITE_OK Then
          msgEdit.Text = " " + sqlErrMsg
          Result = ""
        Else
          Result = sqlStrLst.Item(1)
        End If
      Case "str2jul" 'String to Julian
        'YYYY-MM-DD HH:MM:SS to Floating Point : (MUST HAVE (-) dashes in date and (:) colons in time)
        sqlStrCmd = "Select strftime('%J', '" + sDate + "');"
        sqlResRtn = sql3comm(sqlStrCmd, sqlErrMsg, sqlStrLst)
        If sqlResRtn <> SQLITE_OK Then
          msgEdit.Text = " " + sqlErrMsg
          Result = ""
        Else
          outDateTime = Val(sqlStrLst.Item(1))
          Result = Format$("%.9f", outDateTime)
        End If
      Case "jul2str" 'Julian to String
        'Floating Point to YYYY-MM-DD HH:MM:SS : (up to 7 whole numbers and 9 or less decimal places e.g. nnnnnnn.nnnnnnnnn, n.nnnnnnnnn, nnnnnnn.n)
        sqlStrCmd = "Select datetime('" + sDate + "');"
        sqlResRtn = sql3comm(sqlStrCmd, sqlErrMsg, sqlStrLst)
        If sqlResRtn <> SQLITE_OK Then
          msgEdit.Text = " " + sqlErrMsg
          Result = ""
        Else
          Result = sqlStrLst.Item(1)
        End If
    End Select

    retDateTime = 0
    julDateTime = 0
    outDateTime = 0
    GST_HH     = 0
    GLT_HH     = 0
End Sub

' DateTime_Conversion Function Information / Examples
'
'    ShowMessage(DateTime_Conversion("str2int", "2014-01-01 00:00:00")) 'string to integer | note: Military Time
'    ShowMessage(DateTime_Conversion("int2str", "1388534400"))          'integer to string | Same Date, Same Time (as above)
'    ShowMessage(DateTime_Conversion("str2jul", "2014-01-01 00:00:00")) ' string to julian | note: Military Time
'    ShowMessage(DateTime_Conversion("jul2str", "2456658.50000000"))    ' julian to string | Same Date, Same Time (as above)

'    The lowest Julian dates can go
'    (you can go lower on String to Julian, but there's no point if Julian to String can't go lower)
'    ShowMessage(DateTime_Conversion("jul2str", "-0000000.500000000"))   'julian to string | -4713-11-24 00:00:00
'    ShowMessage(DateTime_Conversion("str2jul", "-4713-11-24 00:00:00")) 'string to julian | -0000000.500000000

'    The highest Julian dates can go
'    (you can go higher on Julian to String, but there's no point if String To Julian can't go higher)
'    ShowMessage(DateTime_Conversion("jul2str", "5373484.499988426"))   'julian to string | 9999-12-31 23:59:59
'    ShowMessage(DateTime_Conversion("str2jul", "9999-12-31 23:59:59")) 'string to julian | 5373484.499988426

'    1 second in Julian time: 0.000011574074074 (approximately)
'    1 minute in Julian time: 0.000694444444444 (approximately)
'    1 hour   in Julian time: 0.041666666666667 (approximately)
'    1 day    in Julian time: 1.00000000000000
'    1 year   in Julian time: 365.000000000000 (non-leap years)
'    1 year   in Julian time: 366.000000000000 (leap years)

'    The lowest Integer dates can go
'    (you can go lower on Integer to String, but there's no point if String To Integer can't go lower)
'    ShowMessage(DateTime_Conversion("str2int", "0000-01-01 00:00:00")) 'string to integer | -62167219200
'    ShowMessage(DateTime_Conversion("int2str", "-62167219200"))        'integer to string | 0000-01-01 00:00:00

'    The highest Integer dates can go
'    (you can go higher on String to Integer, but there's no point if Integer to String can't go higher)
'    ShowMessage(DateTime_Conversion("str2int", "5352-11-01 10:52:47")) 'string to integer | 106751991167
'    ShowMessage(DateTime_Conversion("int2str", "106751991167"))        'integer to string | 5352-11-01 00:00:00

'    1 second in Integer time: 1
'    1 minute in Integer time: 60
'    1 hour   in Integer time: 3600
'    1 day    in Integer time: 86400
'    1 year   in Integer time: 31536000 (non-leap years)
'    1 year   in Integer time: 31622400 (leap years)
