Guest User

Untitled

a guest
Mar 21st, 2018
96
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.93 KB | None | 0 0
  1. Imports System.Text.RegularExpressions
  2. Imports System.Text
  3.  
  4. ''' <summary>
  5. '' 'Dynamic SQL parser
  6. ''' </summary>
  7. ''' <remarks></remarks>
  8. Public Class DynamicSqlParser
  9. ''' <summary>
  10. '' 'Create the DB command
  11. ''' </summary>
  12. '' '<param name = "cn"> DB connection </ param>
  13. ''' <param name="dsql">DynamicSQL</param>
  14. '' '<param name = "prefix"> Parameter prefix </ param>
  15. '' '<param name = "params"> Parameter value dictionary </ param>
  16. ''' <returns></returns>
  17. ''' <remarks></remarks>
  18. Public Shared Function CreateDbCommand(cn As IDbConnection, dsql As String, prefix As String, params As Dictionary(Of String, Object)) As IDbCommand
  19. Dim cmd As IDbCommand = cn.CreateCommand
  20.  
  21. 'Parameter addition
  22. Dim paramAdder As Action(Of String, Object) =
  23. Sub(name As String, value As Object)
  24. If cmd.Parameters.Contains(name) Then Return
  25. Dim prm As IDbDataParameter = cmd.CreateParameter
  26. prm.ParameterName = name
  27. prm.Value = If(value Is Nothing, DBNull.Value, value)
  28. cmd.Parameters.Add(prm)
  29. End Sub
  30.  
  31. 'Command text substitution
  32. cmd.CommandText = Read(dsql, prefix, params, paramAdder)
  33. If cmd.CommandText.Any = False Then cmd.CommandText = dsql
  34.  
  35. Return cmd
  36. End Function
  37.  
  38. ''' <summary>
  39. '' 'Create StaticSQL
  40. ''' </summary>
  41. ''' <param name="dsql"></param>
  42. ''' <param name="prefix">DynamicSQL</param>
  43. ''' <param name="params">ラメータ接</</param>
  44. '' '<param name = "paramAdder"> Parameter value dictionary </ param>
  45. ''' <returns></returns>
  46. ''' <remarks></remarks>
  47. Public Shared Function Read(dsql As String, prefix As String, params As Dictionary(Of String, Object), paramAdder As Action(Of String, Object)) As String
  48. Return ReadAsWhereBlock(dsql, prefix, params, paramAdder)
  49. End Function
  50.  
  51. ''' <summary>
  52. '' 'WHERE block read
  53. ''' </summary>
  54. ''' <returns></returns>
  55. ''' <remarks>
  56. '' 'If there is no extraction condition, delete the WHERE clause
  57. ''' </remarks>
  58. Private Shared Function ReadAsWhereBlock(dsql As String, prefix As String, params As Dictionary(Of String, Object), paramAdder As Action(Of String, Object)) As String
  59. 'WHERE block format
  60. Const WHERE_BLOCK As String = "/\*ds where\*/.*?(?<where>where)(?<block>.*?)/\*ds end where\*/[ ]?"
  61.  
  62. Dim s As New StringBuilder
  63. Dim post As Integer = 0
  64.  
  65. 'Analyze dsql
  66. Dim m As Match = Regex.Match(dsql, WHERE_BLOCK, RegexOptions.IgnoreCase Or RegexOptions.Singleline)
  67. If m.Success = False Then Return ReadAsIfBlock(dsql, prefix, params, paramAdder)
  68.  
  69. While m.Success
  70. Dim g As Group = m.Groups("where")
  71. Dim block As Group = m.Groups("block")
  72. Dim parts As String = ReadAsIfBlock(block.Value, prefix, params, paramAdder)
  73.  
  74. 'Command text
  75. If String.IsNullOrEmpty(parts) Then
  76. 'If WHERE block is empty, no WHERE clause
  77. s.AppendFormat("{0} ", dsql.Substring(pos, m.Index - pos))
  78. Else
  79. 'If the WHERE block is not empty, write a WHERE clause
  80. s.AppendFormat("{0}{1}{2} ", dsql.Substring(pos, m.Index - pos), g.Value, parts.ToString)
  81. End If
  82.  
  83. 'post process
  84. pos = m.Index + m.Length
  85. m = m.NextMatch
  86. End While
  87.  
  88. Return s.ToString.TrimEnd
  89. End Function
  90.  
  91. ''' <summary>
  92. '' 'IF block read
  93. ''' </summary>
  94. ''' <returns></returns>
  95. ''' <remarks>
  96. '' 'If NULL Erase the conditional expression itself
  97. ''' </remarks>
  98. Private Shared Function ReadAsIfBlock(dsql As String, prefix As String, params As Dictionary(Of String, Object), paramAdder As Action(Of String, Object)) As String
  99. 'Format
  100. Const IF_BLOCK As String = "/\*ds if (?<name>.*?)[ ]?\!\=[ ]?null\*/[ ]?\r\n(?<block>.*?)\r\n/\*ds end if\*/[ ]?"
  101.  
  102. Dim s As New StringBuilder
  103. Dim post As Integer = 0
  104.  
  105. 'Analyze dsql
  106. Dim m As Match = Regex.Match(dsql, IF_BLOCK, RegexOptions.IgnoreCase Or RegexOptions.Singleline)
  107. If m.Success = False Then Return ReadAsParamCode(dsql, prefix, params, paramAdder)
  108.  
  109. While m.Success
  110. Dim g As Group = m.Groups("name")
  111. Dim block As Group = m.Groups("block")
  112. Dim val = If(params.Keys.Contains(g.Value) = False, Nothing, params.Item(g.Value))
  113. Dim parts As String = String.Empty
  114.  
  115. If Not (val Is Nothing OrElse DBNull.Value.Equals(val)) Then
  116. parts = ReadAsParamCode(block.Value, prefix, params, paramAdder)
  117. End If
  118.  
  119. 'Command text
  120. If String.IsNullOrEmpty(parts) = False Then
  121. 'Operator (Prefix Format) Processing
  122. Const PREFIX_OPERATOR_CODE As String = "^(?<space>\s*)(?<operator>(and|or)\s*)(?<code>.*)"
  123.  
  124. Dim mPrefix As Match = Regex.Match(parts, PREFIX_OPERATOR_CODE, RegexOptions.IgnoreCase)
  125. Dim tmp As String = dsql.Substring(pos, m.Index - pos)
  126.  
  127. If s.Length = 0 AndAlso String.IsNullOrEmpty(mPrefix.Groups("operator").Value) = False Then
  128. s.AppendFormat("{0}{1}{2}", tmp, mPrefix.Groups("space").Value, mPrefix.Groups("code").Value)
  129. Else
  130. s.AppendFormat("{0}{1}", tmp, parts.ToString)
  131. End If
  132. End If
  133.  
  134. 'post process
  135. pos = m.Index + m.Length
  136. m = m.NextMatch
  137. End While
  138.  
  139. 'Operator (suffix format) processing
  140. Const SUFFIX_OPERATOR_CODE As String = "(?<code>.*)(?<op>(and|or))\s*$"
  141. Dim opSuffix As Match = Regex.Match(s.ToString, SUFFIX_OPERATOR_CODE, RegexOptions.IgnoreCase Or RegexOptions.Singleline)
  142. If opSuffix.Success Then
  143. Return opSuffix.Groups("code").Value.TrimEnd
  144. Else
  145. Return s.ToString.TrimEnd
  146. End If
  147. End Function
  148.  
  149. ''' <summary>
  150. '' 'Read parameter code
  151. ''' </summary>
  152. ''' <returns></returns>
  153. ''' <remarks>
  154. '' '... / * ds condition name * / dummy value ...
  155. ''' <code>Age Between /*ds minage*/30 AND /*ds maxage*/40</code>
  156. ''' </remarks>
  157. Private Shared Function ReadAsParamCode(dsql As String, prefix As String, params As Dictionary(Of String, Object), paramAdder As Action(Of String, Object)) As String
  158. 'Parameter format
  159. Const PARAM_CODE As String = "/\*ds (?<name>[^ ]+)\*/(?<dummy>[^ ]+)(?<space> ?)"
  160.  
  161. Dim s As New StringBuilder
  162. Dim post As Integer = 0
  163.  
  164. 'Analyze dsql
  165. Dim m As Match = Regex.Match(dsql, PARAM_CODE, RegexOptions.IgnoreCase)
  166. If m.Success = False Then Return dsql
  167.  
  168. While m.Success
  169. Dim g As Group = m.Groups("name")
  170. Dim sp As Group = m.Groups("space")
  171.  
  172. Dim val = params.Item(g.Value)
  173. Dim vals = TryCast(val, ICollection)
  174. Dim parts As New StringBuilder
  175.  
  176. If vals Is Nothing Then
  177. 'standard
  178. Dim name As String = g.Value
  179. paramAdder.Invoke(name, val)
  180. parts.AppendFormat("{0}{1}", prefix, name)
  181. Else
  182. 'Array
  183. Dim idx As Integer = 0
  184. For Each item In vals
  185. Dim name As String = String.Format("{0}_{1}", g.Value, idx)
  186. paramAdder.Invoke(name, item)
  187. parts.AppendDelimiter(", ").AppendFormat("{0}{1}", prefix, name)
  188. idx += 1
  189. Next
  190. parts.Decorate("({0})")
  191. End If
  192.  
  193. 'Command text
  194. s.AppendFormat("{0}{1}{2}", dsql.Substring(pos, m.Index - pos), parts.ToString, sp.Value)
  195.  
  196. 'post process
  197. pos = m.Index + m.Length
  198. m = m.NextMatch
  199. End While
  200.  
  201. 'Add remaining strings as is
  202. s.Append(dsql.Substring(pos, dsql.Length - pos))
  203.  
  204. Return s.ToString.TrimEnd
  205. End Function
  206. End Class
Add Comment
Please, Sign In to add comment