sqlparser mysql_SQL Parser

69dceaa732a7202ba0879c14cd51f7a8.gif

Introduction

Sometimes it is necessary to apply a custom filter to an existing SQL query (to perform search by a custom criteria) or to order the query results depending on the user action (when you work with large amounts of data and display only a small part of it to the user, such as displaying only N first records). I faced this problem while implementing a reusable control for searching. In this control the user should be able to specify a filter and order the search results as he needs. A SQL query is specified in the control’s data source and it can contain any parts including sub-queries. In this case it is not enough just to add a custom ‘where’ clause to the end of the query as it may already contain parts which should follow thewhereclause according to the SQL syntax. This article describes a simple SQL parser which allows you to add or modify the ‘where’ and ‘order by’ clauses of a SQL query (PL/SQL).

Background

Any document can be separated into tags (special words or specially formatted characters which have some extra meaning; it depends on the document format and task which sequence of character should be treated as a tag), words, separators (points, commas, braces, etc.), and white spaces. Tags can contain other elements such as sub-tags, words, etc. The parser presented in this article separates a text (sequence of characters) into elements mentioned above and builds a tree from them. Later this tree can be restructured, some its nodes can be changed or removed according to the task.

Every tag in the document is represented with a special class (every type of tag has its own class). While parsing a document, the parser reads the document symbol by symbol and determines whether the current sequence of characters is a tag or a simple text. If it is a tag, the parser creates an instance of the class which represents the tag.

Every class which describes a tag is derived from anabstractclass namedTagBaseand has common information about the tag (whether it has contents, its type (string identifier), value, and whether it can be terminated by the end of the document (whether its ending should be specified explicitly)).The parser has a static set of classes (types) which correspond to the set of the tags of the document format (theTagsproperty). When the parser needs to determine whether there is a tag at the current position of the document, it enumerates through its collection of tag types. For every tag type (element in the collection) it requests a special attribute (derived from theMatchTagAttributeBaseclass). This attribute has a special method namedMatch, which returns a value indicating whether this type of tag is located at the specified position in the document. If so, the parser creates an instance of that class. After an instance of a tag class is created, it is converted into an XML node and then added into the XML tree which reflects the structure of the query.

Here is how a tag class declaration looks like:

74fd2798202fde65c452efa4582b9818.pngCollapse|Copy Code

[TagType(“STRING_LITERAL”)]

[MatchStringLiteralTag]

internal class StringLiteralTag : TagBase

{

...

}

internal class MatchStringLiteralTagAttribute : MatchTagAttributeBase

{

public override bool Match(string sql, int position)

{

...

}

}

Here is the class diagram of the tags used in the SQL parser:

a532cd0f191a33b210dfc5152341c440.gif

This list of tags does not include all the tags which may be present in a SQL query, it includes only those tags which are necessary for modifying the ‘where’ and ‘order by’ clauses of a query.

Using the Code

To modify a SQL query, you should first create an instance of theSqlParserclass and then invoke itsParsemethod:

74fd2798202fde65c452efa4582b9818.pngCollapse|Copy Code

SqlParser myParser = new SqlParser();

myParser.Parse(mySqlQuery);

If you need to modify the ‘where’ clause, you should modify theWhereClauseproperty of the parser:

74fd2798202fde65c452efa4582b9818.pngCollapse|Copy Code

string myOrginalWhereClause = myParser.WhereClause;

if (string.IsNullOrEmpty(myOrginalWhereClause))

myParser.WhereClause = myAdditionalWhereClause;

else

myParser.WhereClause = string.Format("({0}) AND ({1})", myOrginalWhereClause,

myAdditionalWhereClause);

If you need to modify the ‘order by’ clause, you should modify theOrderByClauseproperty of the parser:

74fd2798202fde65c452efa4582b9818.pngCollapse|Copy Code

string myOrginalOrderByClause = myParser.OrderByClause;

if (string.IsNullOrEmpty(myOrginalOrderByClause))

myParser.OrderByClause = myAdditionalOrderByClause;

else

myParser.OrderByClause = string.Format("{0}, {1}", myOrginalOrderByClause,

myAdditionalOrderByClause);

After all the necessary modifications, you can get the final SQL query by using theToTextmethod:

74fd2798202fde65c452efa4582b9818.pngCollapse|Copy Code

myParser.ToText();

Ways to Make Code Faster

There are a few ways to make the code work faster. When the parser builds a tree, it uses theXmlDocumentclass. This is useful for debugging as we can save the tree to a file and then look through it with an internet browser or another tool. Also we can search certain nodes with the x-path syntax. But the parser will work faster if we make our own tree-like data structure without redundant functionality.

Also, it may be preferable not to use reflection as it is quite slow compared to other parser operations (the method which returns attributes of a class may be accessed thousands of times when parsing large documents). Instead we can make some data structures which will store metadata about tag classes. It is not so substantial for the SQL parser, but it may be much more substantial for parsers of large documents.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值