OA_Optimizer.bas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  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. msg_list_to_export = msg_list_to_export & "> " & UCase(obj_type_label) & ": "
  104. If p_optimizer = False Then
  105. msg_list_to_export = msg_list_to_export & "(All)"
  106. Else
  107. lstmod = list_to_export(CInt(obj_type_num))
  108. If Len(lstmod) > 0 Then
  109. Dim count, total As Integer
  110. count = UBound(Split(lstmod, ";")) + 1
  111. total = DCount("name", "MSysObjects", "[name] not like 'MSys*' and [name] not like '~*' and " & msys_type_filter(obj_type_num))
  112. If count = total Then
  113. msg_list_to_export = msg_list_to_export & "(All)"
  114. Else
  115. If count < 12 Then
  116. For Each objname In Split(lstmod, ";")
  117. msg_list_to_export = msg_list_to_export & objname
  118. msg_list_to_export = msg_list_to_export & ", "
  119. Next objname
  120. msg_list_to_export = Left(msg_list_to_export, Len(msg_list_to_export) - 2)
  121. Else
  122. msg_list_to_export = msg_list_to_export & CStr(count) & " on " & CStr(total)
  123. End If
  124. End If
  125. Else
  126. msg_list_to_export = msg_list_to_export & "(None)"
  127. End If
  128. End If
  129. msg_list_to_export = msg_list_to_export & vbNewLine
  130. Next obj_type
  131. Dim include_tables As String
  132. include_tables = get_include_tables()
  133. If UBound(Split(include_tables, ",")) < 5 Then
  134. msg_list_to_export = msg_list_to_export & "> DATA: " & include_tables & vbNewLine
  135. Else
  136. msg_list_to_export = msg_list_to_export & "> DATA: (more than 5)" & vbNewLine
  137. End If
  138. msg_list_to_export = msg_list_to_export & "> RELATIONS, DB PROPERTIES"
  139. End Function
  140. '******
  141. '*** sources_date is the date of the last export of the sources files
  142. Public Function get_sources_date() As Date
  143. ' get the registered sources date
  144. get_sources_date = CDate(oa_param("sources_date", "01/01/1900 00:00:00"))
  145. End Function
  146. Public Sub update_sources_date()
  147. ' update the sources date with Now()
  148. Dim new_val As String
  149. new_val = CStr(Now)
  150. Call update_oa_param("sources_date", CStr(Now))
  151. logger "update_sources_date", "DEBUG", "Source's date updated to " & new_val
  152. End Sub
  153. '*****
  154. '**** cleans sources or objects after differential import/export
  155. Public Function CleanDirs(Optional ByVal sim As Boolean = False)
  156. ' cleans the directories after a differential export
  157. ' returns a list of the deleted relative file paths (string with '|' separator)
  158. ' if 'sim' is set to True, doesn't process to the delete but still return the list
  159. CleanDirs = ""
  160. Dim source_path As String
  161. source_path = VCS_Dir.ProjectPath() & "source\"
  162. logger "CleanDirs", "INFO", "Optimizer ON: cleans the directories from " & source_path
  163. Dim rsSys As DAO.Recordset
  164. Dim sql As String
  165. sql = "SELECT name, type FROM MSysObjects;"
  166. Set rsSys = CurrentDb.OpenRecordset(sql, dbOpenSnapshot)
  167. Dim subdir, filename, objectname, dirname, short_path As String
  168. Dim obj_type, obj_type_split As Variant
  169. Dim obj_type_num As Integer
  170. Dim oFSO As Scripting.FileSystemObject
  171. Dim oFld As Scripting.Folder
  172. Dim file As Scripting.file
  173. 'Instanciation du FSO
  174. Set oFSO = New Scripting.FileSystemObject
  175. For Each obj_type In Split( _
  176. "tables|" & acTable & "," & _
  177. "tbldef|" & acTable & "," & _
  178. "queries|" & acQuery & "," & _
  179. "forms|" & acForm & "," & _
  180. "reports|" & acReport & "," & _
  181. "macros|" & acMacro & "," & _
  182. "modules|" & acModule _
  183. , "," _
  184. )
  185. obj_type_split = Split(obj_type, "|")
  186. dirname = obj_type_split(0)
  187. obj_type_num = obj_type_split(1)
  188. subdir = source_path & dirname
  189. If Not oFSO.FolderExists(subdir) Then GoTo next_obj_type
  190. Set oFld = oFSO.GetFolder(subdir)
  191. For Each file In oFld.Files
  192. objectname = remove_ext(file.name)
  193. objectname = to_accessname(objectname)
  194. rsSys.FindFirst (msys_type_filter(obj_type_num) & " AND [name]=" & Chr(34) & objectname & Chr(34) & "")
  195. If rsSys.NoMatch Then
  196. 'object doesn't exist anymore
  197. If Len(CleanDirs) > 0 Then CleanDirs = CleanDirs & "|"
  198. short_path = Replace(file.Path, CurrentProject.Path, ".")
  199. CleanDirs = CleanDirs & short_path
  200. If Not sim Then
  201. oFSO.DeleteFile file
  202. logger "CleanDirs", "DEBUG", "> removed: " & short_path
  203. End If
  204. End If
  205. Next file
  206. next_obj_type:
  207. Next obj_type
  208. logger "CleanDirs", "INFO", "> Cleaned: " & CleanDirs
  209. End Function
  210. Public Function files_exist_for(acType As Integer, name As String) As Boolean
  211. 'does the object has its files in sources
  212. Dim source_path As String
  213. source_path = VCS_Dir.ProjectPath() & "source\"
  214. name = to_filename(name)
  215. Select Case acType
  216. Case acForm
  217. files_exist_for = (dir(source_path & "forms\" & name & ".bas") <> "")
  218. Case acReport
  219. files_exist_for = (dir(source_path & "reports\" & name & ".bas") <> "" _
  220. And _
  221. dir(source_path & "reports\" & name & ".pv") <> "")
  222. Case acQuery
  223. files_exist_for = (dir(source_path & "queries\" & name & ".bas") <> "")
  224. Case acTable
  225. files_exist_for = ( _
  226. dir(source_path & "tbldef\" & name & ".sql") <> "" _
  227. Or _
  228. dir(source_path & "tbldef\" & name & ".lnkd") <> "" _
  229. )
  230. Case acMacro
  231. files_exist_for = (dir(source_path & "macros\" & name & ".bas") <> "")
  232. Case acModule
  233. files_exist_for = (dir(source_path & "modules\" & name & ".bas") <> "")
  234. End Select
  235. End Function
  236. Public Function CleanApp(Optional ByVal sim As Boolean = False) As String
  237. ' cleans the directories after a differential export
  238. ' returns a list of the deleted relative file paths (string with '|' separator)
  239. ' if 'sim' is set to True, doesn't process to the delete but still return the list
  240. Dim subdir, filename, objectname, dirname, short_path As String
  241. Dim obj_type, obj_type_split As Variant
  242. Dim obj_type_num As Integer
  243. Dim acType As Integer
  244. CleanApp = ""
  245. logger "CleanApp", "INFO", "Cleans the application objects"
  246. Dim rsSys As DAO.Recordset
  247. Dim sql As String
  248. sql = "SELECT name, type FROM MSysObjects WHERE " & _
  249. "(name not like '~*' and name not like 'MSys*' and name not like 'f_*_Data' and name <> 'USysOpenAccess');"
  250. Set rsSys = CurrentDb.OpenRecordset(sql, dbOpenSnapshot)
  251. On Error GoTo next_record
  252. rsSys.MoveFirst
  253. Do Until rsSys.EOF = True
  254. Select Case rsSys![Type]
  255. Case -32768 'form
  256. acType = acForm
  257. Case -32766 'macro
  258. acType = acMacro
  259. Case -32764 'report
  260. acType = acReport
  261. Case 32761 'module
  262. acType = acModule
  263. Case 1 'local table
  264. acType = acTable
  265. Case 4 'linked table
  266. acType = acTable
  267. Case 5 'queries
  268. acType = acQuery
  269. Case Else
  270. GoTo next_record
  271. End Select
  272. If Not files_exist_for(acType, rsSys![name]) Then
  273. If sim = False Then
  274. logger "CleanApp", "DEBUG", "> remove: " & rsSys![name] & " (" & acType & ")"
  275. DoCmd.DeleteObject acType, rsSys![name]
  276. End If
  277. If Len(CleanApp) > 0 Then CleanApp = CleanApp & "|"
  278. CleanApp = CleanApp & rsSys![name]
  279. End If
  280. next_record:
  281. If err.number > 0 Then
  282. logger "CleanApp", "ERROR", "Unable to delete " & rsSys![name] & " (" & acType & "): " & err.Description
  283. err.Clear
  284. End If
  285. rsSys.MoveNext
  286. Loop
  287. logger "CleanApp", "INFO", "> Cleaned: " & CleanApp
  288. End Function