OA_Optimizer.bas 13 KB

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