home *** CD-ROM | disk | FTP | other *** search
- '------------------------------------------------------------
- ' VISDATA.BAS
- ' support functions for the Visual Data sample application
- '
- ' General Information: This app is intended to demonstrate
- ' and exercise all of the functionality available in the
- ' VT (Virtual Table) Object layer in VB 2.0 Pro. It has
- ' the following limitations (not imposed by VB):
- ' 1. Only one DataBase may be open at a time
- ' 2. Only one Dynaset may be open at a time
- ' 3. Only one record is displayed at a time
- '
- ' Any valid SQL statement may be sent via the Utility SQL
- ' function excluding "select" statements which may be
- ' executed from the Dynaset Create function. With these
- ' two features, this simple app becomes a powerful data
- ' definition and query tool accessing any ODBC driver
- ' available at the time.
- '
- ' The app has the capability to perform all DDL (data
- ' definition language) functions. These are accessed
- ' from the "Tables" form. This form accesses the
- ' "NewTable", "AddField" and "IndexAdd" forms to do
- ' the actual table, field and index definition.
- ' Tables and Indexes may be deleted when the corresponding
- ' "Delete" button is enabled. It is not possible to
- ' delete fields.
- '
- ' Naming Conventions:
- ' "f..." = Form
- ' "c..." = Form control
- ' "F..." = Form level variable
- ' "gst..." = Global String
- ' "gf..." = Global flag (true/false)
- ' "gw..." = Global 2 byte integer value
- '
- '------------------------------------------------------------
-
- Option Explicit
-
- 'api declarations
- Declare Function OSGetPrivateProfileString% Lib "Kernel" Alias "GetPrivateProfileString" (ByVal AppName$, ByVal KeyName$, ByVal keydefault$, ByVal ReturnString$, ByVal NumBytes As Integer, ByVal FileName$)
- Declare Function OSWritePrivateProfileString% Lib "Kernel" Alias "WritePrivateProfileString" (ByVal AppName$, ByVal KeyName$, ByVal keydefault$, ByVal FileName$)
-
- 'global object variables
- Global gCurrentDB As Database
- Global gfDBOpenFlag As Integer
- Global gCurrentDS As Dynaset
-
- 'global database variables
- Global gstDBName As String
- Global gstUserName As String
- Global gstPassword As String
- Global gstDataBase As String
- Global gstDynaString As String
- Global gstTblName As String
- Global gfUpdatable As Integer
-
- 'other global vars
- Global gstZoomData As String
- Global gstTableFilter As String
- Global gwMaxGridRows As Long
-
- 'new field properties
- Global gwFldType As Integer
- Global gwFldSize As Integer
-
- 'global find values
- Global gfFindFailed As Integer
- Global gstFindExpr As String
- Global gstFindOp As String
- Global gstFindField As String
- Global gfFindMatch As Integer
- Global gfFromTableView As Integer
-
- 'global flags
- Global gfDBChanged As Integer
- Global gfFromSQL As Integer
- Global gfTransPending As Integer
- Global gfAddTableFlag As Integer
-
- 'global constants
- Global Const DEFAULTDRIVER = "SQL Server"
- Global Const MODAL = 1
- Global Const HOURGLASS = 11
- Global Const DEFAULT_MOUSE = 0
- Global Const YES = 6
- Global Const MSGBOX_TYPE = 4 + 48 + 256
- Global Const TRUE_ST = "True"
- Global Const FALSE_ST = "False"
- Global Const EOF_ERR = 626
- Global Const FTBLS = 0
- Global Const FFLDS = 1
- Global Const FINDX = 2
- Global Const MAX_GRID_ROWS = 1999
- Global Const MAX_MEMO_SIZE = 20000
- Global Const GETCHUNK_CUTOFF = 50
-
- 'field type constants
- Global Const FT_TRUEFALSE = 1
- Global Const FT_BYTE = 2
- Global Const FT_INTEGER = 3
- Global Const FT_LONG = 4
- Global Const FT_CURRENCY = 5
- Global Const FT_SINGLE = 6
- Global Const FT_DOUBLE = 7
- Global Const FT_DATETIME = 8
- Global Const FT_STRING = 10
- Global Const FT_MEMO = 12
-
- Function CheckTransPending (msg As String) As Integer
-
- If gfTransPending = True Then
- MsgBox msg + Chr(13) + Chr(10) + "Execute Commit or Rollback First.", 48
- CheckTransPending = True
- Else
- CheckTransPending = False
- End If
-
- End Function
-
- Sub CloseAllDynasets ()
- Dim i As Integer
-
- MsgBar "Closing Dynasets", True
- While i < forms.Count
- If forms(i).Tag = "Dynaset" Then
- Unload forms(i)
- Else
- i = i + 1
- End If
- Wend
- MsgBar "", False
-
- End Sub
-
- Function CopyStruct (from_db As Database, to_db As Database, from_nm As String, to_nm As String, create_ind As Integer) As Integer
- On Error GoTo CSErr
-
- Dim i As Integer
- Dim tbl As New tabledef 'table object
- Dim fld As Field 'field object
- Dim ind As Index 'index object
-
- 'search to see if table exists
- For i = 0 To to_db.TableDefs.Count - 1
- If UCase(to_db.TableDefs(i).Name) = UCase(to_nm) Then
- If MsgBox(to_nm + " already exists, delete it?", 4) = YES Then
- to_db.TableDefs.Delete to_db.TableDefs(to_nm)
- Else
- CopyStruct = False
- Exit Function
- End If
- Exit For
- End If
- Next
-
- tbl.Name = to_nm
-
- 'get the needed data from the source database
- from_db.TableDefs(from_nm).Fields.Refresh
- from_db.TableDefs(from_nm).Indexes.Refresh
-
- 'create the fields
- For i = 0 To from_db.TableDefs(from_nm).Fields.Count - 1
- Set fld = New Field
- fld.Name = from_db.TableDefs(from_nm).Fields(i).Name
- fld.Type = from_db.TableDefs(from_nm).Fields(i).Type
- fld.Size = from_db.TableDefs(from_nm).Fields(i).Size
- tbl.Fields.Append fld
- Next
-
- 'create the indexes
- If create_ind <> False Then
- For i = 0 To from_db.TableDefs(from_nm).Indexes.Count - 1
- Set ind = New Index
- ind.Name = from_db.TableDefs(from_nm).Indexes(i).Name
- ind.Fields = from_db.TableDefs(from_nm).Indexes(i).Fields
- ind.Unique = from_db.TableDefs(from_nm).Indexes(i).Unique
- tbl.Indexes.Append ind
- Next
- End If
-
- 'append the new table
- to_db.TableDefs.Append tbl
-
- CopyStruct = True
- GoTo CSEnd
-
- CSErr:
- ShowError
- CopyStruct = False
- Resume CSEnd
-
- CSEnd:
-
- End Function
-
- 'sub used to create a sample table and fill it
- 'with NumbRecs number of rows
- 'can only be called from the debug window
- 'for example:
- 'CreateSampleTable("mytbl",100)
- Sub CreateSampleTable (TblName As String, NumbRecs As Long)
- Dim ds As Dynaset
- Dim ii As Long
- Dim t1 As New tabledef
- Dim f1 As New Field
- Dim f2 As New Field
- Dim f3 As New Field
- Dim f4 As New Field
- Dim i1 As New Index
- Dim i2 As New Index
-
- 'create the data holding table
- t1.Name = TblName
-
- f1.Name = "name"
- f1.Type = FT_STRING
- f1.Size = 25
- t1.Fields.Append f1
-
- f2.Name = "address"
- f2.Type = FT_STRING
- f2.Size = 25
- t1.Fields.Append f2
-
- f3.Name = "record"
- f3.Type = FT_STRING
- f3.Size = 10
- t1.Fields.Append f3
-
- f4.Name = "id"
- f4.Type = FT_LONG
- f4.Size = 4
- t1.Fields.Append f4
-
- gCurrentDB.TableDefs.Append t1
-
- 'add the indexes
- i1.Name = TblName + "1"
- i1.Fields = "name"
- i1.Unique = False
- gCurrentDB.TableDefs(TblName).Indexes.Append i1
-
- i2.Name = TblName + "2"
- i2.Fields = "id"
- i2.Unique = True
- gCurrentDB.TableDefs(TblName).Indexes.Append i2
-
- 'add records to the table in reverse order
- 'so indexes have some work to do
- Set ds = gCurrentDB.CreateDynaset(TblName)
- For ii = NumbRecs To 1 Step -1
- ds.AddNew
- ds(0) = "name" + CStr(ii)
- ds(1) = "addr" + CStr(ii)
- ds(2) = "rec" + CStr(ii)
- ds(3) = ii
- ds.Update
- Next
-
- End Sub
-
- Function GetFieldType (ft As String) As Integer
- 'return field length
- If ft = "String" Then
- GetFieldType = FT_STRING
- Else
- Select Case ft
- Case "True/False"
- GetFieldType = FT_TRUEFALSE
- Case "Byte"
- GetFieldType = FT_BYTE
- Case "Integer"
- GetFieldType = FT_INTEGER
- Case "Long"
- GetFieldType = FT_LONG
- Case "Currency"
- GetFieldType = FT_CURRENCY
- Case "Single"
- GetFieldType = FT_SINGLE
- Case "Double"
- GetFieldType = FT_DOUBLE
- Case "Date/Time"
- GetFieldType = FT_DATETIME
- Case "Memo"
- GetFieldType = FT_MEMO
- End Select
- End If
-
- End Function
-
- Function GetFieldWidth (t As Integer)
- 'determines the form control width
- 'based on the field type
- Select Case t
- Case FT_TRUEFALSE
- GetFieldWidth = 850
- Case FT_BYTE
- GetFieldWidth = 650
- Case FT_INTEGER
- GetFieldWidth = 900
- Case FT_LONG
- GetFieldWidth = 1100
- Case FT_CURRENCY
- GetFieldWidth = 1800
- Case FT_SINGLE
- GetFieldWidth = 1800
- Case FT_DOUBLE
- GetFieldWidth = 2200
- Case FT_DATETIME
- GetFieldWidth = 2000
- Case FT_STRING
- GetFieldWidth = 3250
- Case FT_MEMO
- GetFieldWidth = 3250
- Case Else
- GetFieldWidth = 3250
- End Select
-
- End Function
-
- Function GetINIString$ (ByVal szItem$, ByVal szDefault$)
- Dim tmp As String
- Dim x As Integer
-
- tmp = String$(255, 32)
- x = OSGetPrivateProfileString("VISDATA", szItem$, szDefault$, tmp, Len(tmp), "VISDATA.INI")
-
- GetINIString = Mid$(tmp, 1, x)
- End Function
-
- Function GetNumbRecs (fds As Dynaset, wh As String) As Long
- Dim ds As Dynaset
-
- On Error GoTo GNRErr
-
- 'this is a quick way to get the number of
- 'records in a dynaset
- If fds.Updatable = True Then
- Set ds = gCurrentDB.CreateDynaset("select count(*) from " + fds.Name)
- gfUpdatable = True
- GetNumbRecs = ds(0)
- ds.Close
- Else
- gfUpdatable = False
- 'use the where clause only if "group by" not found
- If InStr(1, wh, "group by") = 0 Then
- Set ds = gCurrentDB.CreateDynaset("select count(*) from " + wh)
- GetNumbRecs = ds(0)
- ds.Close
- End If
- End If
-
- GoTo GNREnd
-
- GNRErr:
- If InStr(1, Error$, "Timeout") > 0 Then
- MsgBox "Timeout Occurred Getting Record Count, try Increasing QueryTimeout!", 48
- GetNumbRecs = -1
- Resume GNREnd
- End If
- Resume Next
- GetNumbRecs = 0
- Resume GNREnd
-
- GNREnd:
-
- End Function
-
- '----------------------------------------------------------------------------
- 'to use this function in any app,
- '1. create a form with a grid
- '2. create a dynaset
- '3. call this function from the form with
- ' grd = your grid control name
- ' dynst$ = your dynaset open string (table name or SQL select statement)
- ' numb& = the max number of rows to load (grid is limited to 2000)
- ' start& = starting row (needed to display the record number in the
- ' left column when loading blocks of records as the
- ' DynaGrid form in this app does with the "More" button)
- '----------------------------------------------------------------------------
- Function LoadGrid (grd As Control, fds As Dynaset, dynst$, numb&, start&) As Integer
- Dim ft As Integer 'field type
- Dim i As Integer, j As Integer 'for loop indexes
- Dim fn As String 'field name
- Dim rc As Integer 'record count
- Dim gs As String 'grid string
-
- On Error GoTo LGErr
-
- MsgBar "Loading Grid for Table View", True
- 'setup the grid
- grd.Rows = 2 'reduce the grid
- grd.FixedRows = 0 'allow next step
- grd.Rows = 1 'clears the grid completely
- grd.Cols = fds.Fields.Count + 1
-
- If start& = 0 Then 'only do it on first call
- 'set the column widths
- For i = 0 To fds.Fields.Count - 1
- ft = fds(i).Type
- If ft = FT_STRING Then
- If fds(i).Size > Len(fds(i).Name) Then
- If fds(i).Size <= 10 Then
- grd.ColWidth(i + 1) = fds(i).Size * fTables.TextWidth("A")
- Else
- grd.ColWidth(i + 1) = 10 * fTables.TextWidth("A")
- End If
- Else
- If Len(fds(i).Name) <= 10 Then
- grd.ColWidth(i + 1) = Len(fds(i).Name) * fTables.TextWidth("A")
- Else
- grd.ColWidth(i + 1) = 10 * fTables.TextWidth("A")
- End If
- End If
- ElseIf ft = FT_MEMO Then
- grd.ColWidth(i + 1) = 1200
- Else
- grd.ColWidth(i + 1) = GetFieldWidth(ft)
- End If
- Next
-
- 'load the field names
- grd.Row = 0
- If gfFromSQL = False Or InStr(1, dynst, "*") > 1 Then
- For i = 0 To fds.Fields.Count - 1
- grd.Col = i + 1
- grd.Text = UCase(fds(i).Name)
- Next
-
- Else
- 'parse off field names in select statement
- j = 8
- For i = 0 To fds.Fields.Count - 1
- fn = ""
- While Mid(dynst, j, 1) <> "," And Mid(dynst, j, 1) <> " "
- fn = fn + Mid(dynst, j, 1)
- j = j + 1
- Wend
- While Mid(dynst, j, 1) = "," Or Mid(dynst, j, 1) = " "
- j = j + 1
- Wend
- grd.Col = i + 1
- grd.Text = UCase(fn)
- Next
- End If
- End If
-
- rc = 1
-
- 'fill method 1
- 'add the rows with the additem method
- While fds.EOF = False And rc <= numb
- gs = CStr(rc + start) + Chr$(9)
- For i = 0 To fds.Fields.Count - 1
- If fds(i).Type = FT_MEMO Then
- If fds(i).FieldSize() < 255 Then
- gs = gs + StripNonAscii(vFieldVal(fds(i))) + Chr$(9)
- Else
- 'can only get the 1st 255 chars
- gs = gs + StripNonAscii(vFieldVal(fds(i).GetChunk(0, 255))) + Chr$(9)
- End If
- ElseIf fds(i).Type = FT_STRING Then
- gs = gs + StripNonAscii(vFieldVal(fds(i))) + Chr$(9)
- Else
- gs = gs + vFieldVal(fds(i)) + Chr$(9)
- End If
- Next
- gs = Mid(gs, 1, Len(gs) - 1)
- grd.AddItem gs
- fds.MoveNext
- rc = rc + 1
- Wend
-
- 'fill method 2
- 'add the cells individually
- ' While fds.EOF = False And rc <= numb
- ' grd.Rows = rc + 1
- ' grd.Row = rc
- ' grd.Col = 0
- ' grd.Text = CStr(rc + start)
- ' For i = 0 To fds.Fields.Count - 1
- ' grd.Col = i + 1
- ' If fds(i).Type = FT_MEMO Then
- ' 'can only get the 1st 255 chars
- ' grd.Text = StripNonAscii(vFieldVal((fds(i).GetChunk(0, 255))))
- ' ElseIf fds(i).Type = FT_STRING Then
- ' grd.Text = StripNonAscii(vFieldVal((fds(i))))
- ' Else
- ' grd.Text = CStr(vFieldVal(fds(i)))
- ' End If
- ' Next
- ' fds.MoveNext
- ' rc = rc + 1
- ' Wend
-
- grd.FixedRows = 1 'freeze the field names
- grd.FixedCols = 1 'freeze the row numbers
- grd.Row = 1 'set current position
- grd.Col = 1
-
- LoadGrid = rc 'return number added
- GoTo LGEnd
-
- LGErr:
- ShowError
- LoadGrid = False 'return 0
- Resume LGEnd
-
- LGEnd:
- MsgBar "", False
-
- End Function
-
- Sub MsgBar (msg As String, pw As Integer)
- If msg = "" Then
- VDMDI.cMsg = "Ready"
- Else
- If pw = True Then
- VDMDI.cMsg = msg + ", please wait..."
- Else
- VDMDI.cMsg = msg
- End If
- End If
- VDMDI.cMsg.Refresh
- End Sub
-
- Sub RefreshTables (tbl_list As Control)
- Dim i As Integer, j As Integer, h As Integer
- Dim st As String
- ReDim fltrs(1) As String
- Dim OkayToAdd As Integer
-
- On Error GoTo TRefErr
-
- MsgBar "Refreshing Table List", True
- SetHourGlass VDMDI
-
- i = 1
- While i <= Len(gstTableFilter) + 1
- If Mid(gstTableFilter, i, 1) = "," Or i = Len(gstTableFilter) + 1 Then
- ReDim Preserve fltrs(UBound(fltrs) + 1)
- fltrs(j) = st
- st = ""
- j = j + 1
- Else
- st = st + Mid(gstTableFilter, i, 1)
- End If
- i = i + 1
- Wend
-
- gCurrentDB.TableDefs.Refresh
- tbl_list.Clear
- For i = 0 To gCurrentDB.TableDefs.Count - 1
- st = gCurrentDB.TableDefs(i).Name
- If gstTableFilter = "" Then
- tbl_list.AddItem st
- Else
- OkayToAdd = True
- For h = 0 To j - 1
- If Mid(fltrs(h), 1, 1) = "-" Then
- If UCase(st) Like UCase(Mid(fltrs(h), 2, Len(fltrs(h)) - 1)) Then
- OkayToAdd = False
- End If
- Else
- If Not UCase(st) Like UCase(fltrs(h)) Then
- OkayToAdd = False
- End If
- End If
- Next
- If OkayToAdd = True Then
- tbl_list.AddItem st
- End If
- End If
- Next
-
- GoTo TRefEnd
-
- TRefErr:
- ShowError
- gfDBOpenFlag = False
- Resume TRefEnd
-
- TRefEnd:
- ResetMouse VDMDI
- MsgBar "", False
-
- End Sub
-
- Sub ResetMouse (f As Form)
- VDMDI.MousePointer = DEFAULT_MOUSE
- f.MousePointer = DEFAULT_MOUSE
- End Sub
-
- Function SetFldProperties (ft As String) As String
- 'return field length
- If ft = "String" Then
- gwFldType = FT_STRING
- Else
- Select Case ft
- Case "True/False"
- SetFldProperties = "1"
- gwFldType = FT_TRUEFALSE
- gwFldSize = 1
- Case "Byte"
- SetFldProperties = "1"
- gwFldType = FT_BYTE
- gwFldSize = 1
- Case "Integer"
- SetFldProperties = "2"
- gwFldType = FT_INTEGER
- gwFldSize = 2
- Case "Long"
- SetFldProperties = "4"
- gwFldType = FT_LONG
- gwFldSize = 4
- Case "Currency"
- SetFldProperties = "8"
- gwFldType = FT_CURRENCY
- gwFldSize = 8
- Case "Single"
- SetFldProperties = "4"
- gwFldType = FT_SINGLE
- gwFldSize = 4
- Case "Double"
- SetFldProperties = "8"
- gwFldType = FT_DOUBLE
- gwFldSize = 8
- Case "Date/Time"
- SetFldProperties = "8"
- gwFldType = FT_DATETIME
- gwFldSize = 8
- Case "Memo"
- SetFldProperties = "0"
- gwFldType = FT_MEMO
- gwFldSize = 0
- End Select
- End If
- End Function
-
- Sub SetHourGlass (f As Form)
- DoEvents 'cause forms to repaint before going on
- VDMDI.MousePointer = HOURGLASS
- f.MousePointer = HOURGLASS
- End Sub
-
- Sub ShowError ()
- Dim s As String
- Dim crlf As String
-
- crlf = Chr(13) + Chr(10)
- s = "The following Error occurred:" + crlf + crlf
- 'add the error string
- s = s + Error$ + crlf
- 'add the error number
- s = s + "Number: " + CStr(Err)
- 'beep and show the error
- Beep
- MsgBox (s)
-
- End Sub
-
- Function StripNonAscii (vs As Variant) As String
- Dim i As Integer
- Dim ts As String
-
- For i = 1 To Len(vs)
- If Asc(Mid(vs, i, 1)) < 32 Or Asc(Mid(vs, i, 1)) > 126 Then
- ts = ts + " "
- Else
- ts = ts + Mid(vs, i, 1)
- End If
- Next
-
- StripNonAscii = ts
-
- End Function
-
- Function vFieldVal (fv As Variant) As Variant
- If IsNull(fv) Then
- vFieldVal = ""
- Else
- vFieldVal = CStr(fv)
- End If
- End Function
-
-