OA_Optimizer.bas 13 KB

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