OA_Optimizer.bas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. Option Compare Database
  2. Option Explicit
  3. '****
  4. '*
  5. '* Optimizer for Open Access: only import/export objects which were updated since last import/export
  6. '*
  7. '****
  8. ' *** activates the optimizer
  9. Private p_optimizer As Boolean
  10. 'needs_export
  11. Public Const NoExportNeeded = 0
  12. Public Const MissingFiles = 1
  13. Public Const UpdateNeeded = 2
  14. Public Sub activate_optimizer()
  15. p_optimizer = True
  16. End Sub
  17. Public Function optimizer_activated()
  18. optimizer_activated = p_optimizer
  19. End Function
  20. '***
  21. '*** main methods
  22. Public Function needs_export(acType As Integer, name As String) As Integer
  23. ' a file needs to be export if it has been updated since last export, or if its source files are missing
  24. ' returns an integer (see constants)
  25. If Not files_exist_for(acType, name) Then
  26. needs_export = MissingFiles
  27. ElseIf get_last_update_date(acType, name) > get_sources_date() Then
  28. needs_export = UpdateNeeded
  29. Else
  30. needs_export = NoExportNeeded
  31. End If
  32. End Function
  33. Public Function get_last_update_date(ByVal acType As Integer, ByVal name As String)
  34. On Error GoTo err
  35. 'get the date of the last update of an object
  36. Select Case acType
  37. 'case table or query: get [DateUpdate] in MSysObjects
  38. Case acTable
  39. get_last_update_date = DFirst("DateUpdate", "MSysObjects", "([Type]=1 or [Type]=4 or [Type]=6) and [name]=" & Chr(34) & name & Chr(34) & "")
  40. Case acQuery
  41. get_last_update_date = DFirst("DateUpdate", "MSysObjects", "[Type]=5 and [name]=" & Chr(34) & name & Chr(34) & "")
  42. 'MSysObjects is not reliable for other objects,
  43. 'So we used the DateModified property:
  44. Case acForm
  45. get_last_update_date = CurrentProject.AllForms(name).DateModified
  46. Case acReport
  47. get_last_update_date = CurrentProject.AllReports(name).DateModified
  48. Case acMacro
  49. get_last_update_date = CurrentProject.AllMacros(name).DateModified
  50. Case acModule
  51. get_last_update_date = CurrentProject.AllModules(name).DateModified
  52. End Select
  53. Exit Function
  54. err:
  55. Debug.Print "get_last_update_date - erreur - " & acType & ", " & name & ": " & err.Description
  56. get_last_update_date = #1/1/1900#
  57. End Function
  58. '*** displays modified (dirties) objects
  59. Public Function list_to_export(acType As Integer)
  60. ' returns a list (string with ';' separator) of the objects wich will be exported
  61. Dim sources_date As Date
  62. list_to_export = ""
  63. sources_date = get_sources_date()
  64. Dim rs As DAO.Recordset
  65. Set rs = CurrentDb.OpenRecordset("SELECT * FROM MSysObjects WHERE " & msys_type_filter(acType) & ";", _
  66. dbOpenSnapshot)
  67. If rs.RecordCount = 0 Then GoTo emptylist
  68. rs.MoveFirst
  69. Do Until rs.EOF
  70. If Left$(rs![name], 4) <> "MSys" And _
  71. Left$(rs![name], 1) <> "~" Then
  72. If get_last_update_date(acType, rs![name]) > sources_date Or _
  73. Not files_exist_for(acType, rs![name]) Then
  74. If Len(list_to_export) > 0 Then
  75. list_to_export = list_to_export & ";" & rs![name]
  76. Else
  77. list_to_export = rs![name]
  78. End If
  79. End If
  80. End If
  81. rs.MoveNext
  82. Loop
  83. Exit Function
  84. emptylist:
  85. End Function
  86. Public Function msg_list_to_export() As String
  87. 'returns a formatted text listing all of the objects which were updated since last export of the sources
  88. Dim lstmod, obj_type_split, obj_type_label, obj_type_num As String
  89. Dim obj_type, objname As Variant
  90. msg_list_to_export = ""
  91. For Each obj_type In Split( _
  92. "tables|" & acTable & "," & _
  93. "queries|" & acQuery & "," & _
  94. "forms|" & acForm & "," & _
  95. "reports|" & acReport & "," & _
  96. "macros|" & acMacro & "," & _
  97. "modules|" & acModule _
  98. , "," _
  99. )
  100. obj_type_split = Split(obj_type, "|")
  101. obj_type_label = obj_type_split(0)
  102. obj_type_num = obj_type_split(1)
  103. lstmod = list_to_export(CInt(obj_type_num))
  104. If Len(lstmod) > 0 Then
  105. msg_list_to_export = msg_list_to_export & "> " & UCase(obj_type_label) & ":" & vbNewLine
  106. For Each objname In Split(lstmod, ";")
  107. msg_list_to_export = msg_list_to_export & objname
  108. msg_list_to_export = msg_list_to_export & ", "
  109. Next objname
  110. msg_list_to_export = Left(msg_list_to_export, Len(msg_list_to_export) - 2) & vbNewLine & vbNewLine
  111. End If
  112. Next obj_type
  113. End Function
  114. '******
  115. '*** sources_date is the date of the last export of the sources files
  116. Public Function get_sources_date() As Date
  117. ' get the registered sources date
  118. get_sources_date = CDate(oa_param("sources_date", "01/01/1900 00:00:00"))
  119. End Function
  120. Public Sub update_sources_date()
  121. ' update the sources date with Now()
  122. Dim new_val As String
  123. new_val = CStr(Now)
  124. Call update_oa_param("sources_date", CStr(Now))
  125. logger "update_sources_date", "DEBUG", "Source's date updated to " & new_val
  126. End Sub
  127. '*****
  128. '**** cleans sources or objects after differential import/export
  129. Public Function CleanDirs(Optional ByVal sim As Boolean = False)
  130. ' cleans the directories after a differential export
  131. ' returns a list of the deleted relative file paths (string with '|' separator)
  132. ' if 'sim' is set to True, doesn't process to the delete but still return the list
  133. CleanDirs = ""
  134. Dim source_path As String
  135. source_path = VCS_Dir.ProjectPath() & "source\"
  136. logger "CleanDirs", "INFO", "Optimizer ON: cleans the directories from " & source_path
  137. Dim rsSys As DAO.Recordset
  138. Dim sql As String
  139. sql = "SELECT name, type FROM MSysObjects;"
  140. Set rsSys = CurrentDb.OpenRecordset(sql, dbOpenSnapshot)
  141. Dim subdir, filename, objectname, dirname, short_path As String
  142. Dim obj_type, obj_type_split As Variant
  143. Dim obj_type_num As Integer
  144. Dim oFSO As Scripting.FileSystemObject
  145. Dim oFld As Scripting.Folder
  146. Dim file As Scripting.file
  147. 'Instanciation du FSO
  148. Set oFSO = New Scripting.FileSystemObject
  149. For Each obj_type In Split( _
  150. "tables|" & acTable & "," & _
  151. "tbldef|" & acTable & "," & _
  152. "queries|" & acQuery & "," & _
  153. "forms|" & acForm & "," & _
  154. "reports|" & acReport & "," & _
  155. "macros|" & acMacro & "," & _
  156. "modules|" & acModule _
  157. , "," _
  158. )
  159. obj_type_split = Split(obj_type, "|")
  160. dirname = obj_type_split(0)
  161. obj_type_num = obj_type_split(1)
  162. subdir = source_path & dirname
  163. If Not oFSO.FolderExists(subdir) Then GoTo next_obj_type
  164. Set oFld = oFSO.GetFolder(subdir)
  165. For Each file In oFld.Files
  166. objectname = remove_ext(file.name)
  167. objectname = to_accessname(objectname)
  168. rsSys.FindFirst (msys_type_filter(obj_type_num) & " AND [name]=" & Chr(34) & objectname & Chr(34) & "")
  169. If rsSys.NoMatch Then
  170. 'object doesn't exist anymore
  171. If Len(CleanDirs) > 0 Then CleanDirs = CleanDirs & "|"
  172. short_path = Replace(file.Path, CurrentProject.Path, ".")
  173. CleanDirs = CleanDirs & short_path
  174. If Not sim Then
  175. oFSO.DeleteFile file
  176. logger "CleanDirs", "DEBUG", "> removed: " & short_path
  177. End If
  178. End If
  179. Next file
  180. next_obj_type:
  181. Next obj_type
  182. logger "CleanDirs", "INFO", "> Cleaned: " & CleanDirs
  183. End Function
  184. Public Function files_exist_for(acType As Integer, name As String) As Boolean
  185. 'does the object has its files in sources
  186. Dim source_path As String
  187. source_path = VCS_Dir.ProjectPath() & "source\"
  188. name = to_filename(name)
  189. Select Case acType
  190. Case acForm
  191. files_exist_for = (dir(source_path & "forms\" & name & ".bas") <> "")
  192. Case acReport
  193. files_exist_for = (dir(source_path & "reports\" & name & ".bas") <> "" _
  194. And _
  195. dir(source_path & "reports\" & name & ".pv") <> "")
  196. Case acQuery
  197. files_exist_for = (dir(source_path & "queries\" & name & ".bas") <> "")
  198. Case acTable
  199. files_exist_for = ( _
  200. dir(source_path & "tbldef\" & name & ".sql") <> "" _
  201. Or _
  202. dir(source_path & "tbldef\" & name & ".lnkd") <> "" _
  203. )
  204. Case acMacro
  205. files_exist_for = (dir(source_path & "macros\" & name & ".bas") <> "")
  206. Case acModule
  207. files_exist_for = (dir(source_path & "modules\" & name & ".bas") <> "")
  208. End Select
  209. End Function
  210. Public Function CleanApp(Optional ByVal sim As Boolean = False) As String
  211. ' cleans the directories after a differential export
  212. ' returns a list of the deleted relative file paths (string with '|' separator)
  213. ' if 'sim' is set to True, doesn't process to the delete but still return the list
  214. Dim subdir, filename, objectname, dirname, short_path As String
  215. Dim obj_type, obj_type_split As Variant
  216. Dim obj_type_num As Integer
  217. Dim acType As Integer
  218. CleanApp = ""
  219. logger "CleanApp", "INFO", "Cleans the application objects"
  220. Dim rsSys As DAO.Recordset
  221. Dim sql As String
  222. sql = "SELECT name, type FROM MSysObjects;"
  223. Set rsSys = CurrentDb.OpenRecordset(sql, dbOpenSnapshot)
  224. On Error GoTo next_record
  225. rsSys.MoveFirst
  226. Do Until rsSys.EOF = True
  227. If Left(rsSys![name], 1) = "~" Or Left(rsSys![name], 4) = "MSys" Then GoTo next_record
  228. Select Case rsSys![Type]
  229. Case -32768 'form
  230. acType = acForm
  231. Case -32766 'macro
  232. acType = acMacro
  233. Case -32764 'report
  234. acType = acReport
  235. Case 32761 'module
  236. acType = acModule
  237. Case 1 'local table
  238. acType = acTable
  239. Case 4 'linked table
  240. acType = acTable
  241. Case 5 'queries
  242. acType = acQuery
  243. Case Else
  244. GoTo next_record
  245. End Select
  246. If Not files_exist_for(acType, rsSys![name]) Then
  247. If sim = False Then
  248. logger "CleanApp", "DEBUG", "> remove: " & rsSys![name] & " (" & acType & ")"
  249. DoCmd.DeleteObject acType, rsSys![name]
  250. End If
  251. If Len(CleanApp) > 0 Then CleanApp = CleanApp & "|"
  252. CleanApp = CleanApp & rsSys![name]
  253. End If
  254. next_record:
  255. If err.number > 0 Then
  256. logger "CleanApp", "ERROR", "Unable to delete " & rsSys![name] & " (" & acType & "): " & err.Description
  257. err.Clear
  258. End If
  259. rsSys.MoveNext
  260. Loop
  261. logger "CleanApp", "INFO", "> Cleaned: " & CleanApp
  262. End Function