string _userRawSql; //raw sql from user code public SqlStringTemplate(string rawSql) { _userRawSql = rawSql; //------------------------------ //parse int length = rawSql.Length; ParseState state = ParseState.FIND_MARKER; StringBuilder stBuilder = new StringBuilder(); //TODO: review parser state, escape ' or " or ` char binderEscapeChar = '\0'; char escapeChar = '\0'; for (int i = 0; i < length; i++) { char ch = rawSql[i]; switch (state) { default: //unknown state must throw exception, so we can see if something changed throw new NotSupportedException(); case ParseState.FIND_MARKER: if (ch == '?' || ch == '@') { binderEscapeChar = ch; //found begining point of new marker if (stBuilder.Length > 0) { _sqlSections.Add(new SqlSection(stBuilder.ToString(), SqlSectionKind.SqlText)); stBuilder.Length = 0; } state = ParseState.COLLECT_MARKER_KEY; } else if (ch == '\'' || ch == '"' || ch == '`') { escapeChar = ch; state = ParseState.STRING_ESCAPE; } stBuilder.Append(ch); break; case ParseState.COLLECT_MARKER_KEY: if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch == '_') { stBuilder.Append(ch); } else if (ch == '?') { //this is special marker key stBuilder.Append(ch); if (binderEscapeChar == '?') { state = ParseState.COLLECT_SP_MARKER_KEY; } else { //eg ?@ //error throw new NotSupportedException("syntax err!"); } } else if (ch == '@') { stBuilder.Append(ch); if (binderEscapeChar == '@') { //@@ state = ParseState.FIND_MARKER; //goto normal text state } else { //eg @? //eg ?@ //error throw new NotSupportedException("syntax err!"); } } else { //value binding marking end here if (stBuilder.Length > 0) { var valueSection = new SqlBoundSection(stBuilder.ToString()); _sqlSections.Add(valueSection); _valuesKeys.Add(valueSection); stBuilder.Length = 0; } state = ParseState.FIND_MARKER; stBuilder.Append(ch); } break; case ParseState.COLLECT_SP_MARKER_KEY: if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch == '_') { stBuilder.Append(ch); } else { //special marker end here if (stBuilder.Length > 0) { var specialSection = new SqlSection(stBuilder.ToString(), SqlSectionKind.SpecialKey); _sqlSections.Add(specialSection); _specialKeys.Add(specialSection); stBuilder.Length = 0; } state = ParseState.FIND_MARKER; stBuilder.Append(ch); } break; case ParseState.STRING_ESCAPE: { if (ch == '\'' || ch == '"' || ch == '`') { if (escapeChar == ch) { escapeChar = '\0'; //go back to find marker state state = ParseState.FIND_MARKER; } } stBuilder.Append(ch); } break; }//end swicth }//end for if (stBuilder.Length > 0) { switch (state) { default: throw new NotSupportedException(); case ParseState.FIND_MARKER: _sqlSections.Add(new SqlSection(stBuilder.ToString(), SqlSectionKind.SqlText)); break; case ParseState.COLLECT_MARKER_KEY: var valueSection = new SqlBoundSection(stBuilder.ToString()); _sqlSections.Add(valueSection); _valuesKeys.Add(valueSection); break; case ParseState.COLLECT_SP_MARKER_KEY: var specialSection = new SqlSection(stBuilder.ToString(), SqlSectionKind.SpecialKey); _sqlSections.Add(specialSection); _specialKeys.Add(specialSection); break; } } }
string _userRawSql; //raw sql from user code public SqlStringTemplate(string rawSql) { _userRawSql = rawSql; //------------------------------ //parse int length = rawSql.Length; ParseState state = ParseState.FIND_MARKER; StringBuilder stBuilder = new StringBuilder(); //TODO: review parser state, escape ' or " or ` char binderEscapeChar = '\0'; char escapeChar = '\0'; for (int i = 0; i < length; i++) { char ch = rawSql[i]; switch (state) { default: //unknown state must throw exception, so we can see if something changed throw new NotSupportedException(); case ParseState.FIND_MARKER: if (ch == '?' || ch == '@') { binderEscapeChar = ch; //found begining point of new marker if (stBuilder.Length > 0) { _sqlSections.Add(new SqlSection(stBuilder.ToString(), SqlSectionKind.SqlText)); stBuilder.Length = 0; } state = ParseState.COLLECT_MARKER_KEY; } else if (ch == '\'' || ch == '"' || ch == '`') { escapeChar = ch; state = ParseState.STRING_ESCAPE; } stBuilder.Append(ch); break; case ParseState.COLLECT_MARKER_KEY: if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch == '_') { stBuilder.Append(ch); } else if (ch == '?') { //this is special marker key stBuilder.Append(ch); if (binderEscapeChar == '?') { state = ParseState.COLLECT_SP_MARKER_KEY; } else { //eg ?@ //error throw new NotSupportedException("syntax err!"); } } else if (ch == '@') { stBuilder.Append(ch); if (binderEscapeChar == '@') { //@@ state = ParseState.FIND_MARKER; //goto normal text state } else { //eg @? //eg ?@ //error throw new NotSupportedException("syntax err!"); } } else { //value binding marking end here if (stBuilder.Length > 0) { var valueSection = new SqlBoundSection(stBuilder.ToString()); _sqlSections.Add(valueSection); _valuesKeys.Add(valueSection); stBuilder.Length = 0; } state = ParseState.FIND_MARKER; stBuilder.Append(ch); } break; case ParseState.COLLECT_SP_MARKER_KEY: if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch == '_') { stBuilder.Append(ch); } else { //special marker end here if (stBuilder.Length > 0) { var specialSection = new SqlSection(stBuilder.ToString(), SqlSectionKind.SpecialKey); _sqlSections.Add(specialSection); _specialKeys.Add(specialSection); stBuilder.Length = 0; } state = ParseState.FIND_MARKER; stBuilder.Append(ch); } break; case ParseState.STRING_ESCAPE: { if (ch == '\'' || ch == '"' || ch == '`') { if (escapeChar == ch) { escapeChar = '\0'; //go back to find marker state state = ParseState.FIND_MARKER; } } stBuilder.Append(ch); } break; } //end swicth } //end for if (stBuilder.Length > 0) { switch (state) { default: throw new NotSupportedException(); case ParseState.FIND_MARKER: _sqlSections.Add(new SqlSection(stBuilder.ToString(), SqlSectionKind.SqlText)); break; case ParseState.COLLECT_MARKER_KEY: var valueSection = new SqlBoundSection(stBuilder.ToString()); _sqlSections.Add(valueSection); _valuesKeys.Add(valueSection); break; case ParseState.COLLECT_SP_MARKER_KEY: var specialSection = new SqlSection(stBuilder.ToString(), SqlSectionKind.SpecialKey); _sqlSections.Add(specialSection); _specialKeys.Add(specialSection); break; } } }