Fix for embedded PL/SQL blocks (Oracle Pro*C) (#985)
* fix for correct parsing of embedded PL/SQL blocks (Oracle Pro*C) * enforce SQL block end at the end of nearest outer C block, when appropriate terminator is not found * added check for ; at the end of END-EXEC and made SQL block detection more readable
This commit is contained in:
parent
a8700f5622
commit
02461753f3
|
@ -1981,12 +1981,12 @@ void Tokenizer::simplifySQL()
|
|||
{
|
||||
for (Token *tok = list.front(); tok; tok = tok->next()) {
|
||||
if (Token::simpleMatch(tok, "EXEC SQL")) {
|
||||
const Token *end = tok->tokAt(2);
|
||||
while (end && end->str() != ";")
|
||||
end = end->next();
|
||||
const Token *end = findSQLBlockEnd(tok);
|
||||
if (end == nullptr)
|
||||
syntaxError(nullptr);
|
||||
|
||||
std::string instruction = tok->stringifyList(end);
|
||||
// delete all tokens until ';'
|
||||
// delete all tokens until the embedded SQL block end
|
||||
Token::eraseTokens(tok, end);
|
||||
|
||||
// insert "asm ( "instruction" ) ;"
|
||||
|
@ -9886,3 +9886,25 @@ void Tokenizer::SimplifyNamelessRValueReferences()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Token *Tokenizer::findSQLBlockEnd(const Token *tokSQLStart) const
|
||||
{
|
||||
const Token *tokSQLEnd = nullptr;
|
||||
const Token *tokLastEnd = nullptr;
|
||||
for (const Token *tok = tokSQLStart->tokAt(2); tok != nullptr && tokSQLEnd == nullptr; tok = tok->next()) {
|
||||
if (tokLastEnd == nullptr && tok->str() == ";")
|
||||
tokLastEnd = tok;
|
||||
else if (tok->str() == "EXEC") {
|
||||
if (Token::simpleMatch(tok->tokAt(-2), "END - EXEC ;"))
|
||||
tokSQLEnd = tok->next();
|
||||
else
|
||||
tokSQLEnd = tokLastEnd;
|
||||
break;
|
||||
}
|
||||
else if (Token::Match(tok, "{|}|==|&&|!|&|^|<<|>>|++|+=|-=|/=|*=|>>=|<<=|->|::|~"))
|
||||
break; // We are obviously outside the SQL block
|
||||
}
|
||||
|
||||
return tokSQLEnd ? tokSQLEnd : tokLastEnd;
|
||||
}
|
||||
|
||||
|
|
|
@ -718,6 +718,9 @@ private:
|
|||
*/
|
||||
void printUnknownTypes() const;
|
||||
|
||||
/** Find end of SQL (or PL/SQL) block */
|
||||
const Token *findSQLBlockEnd(const Token *tokSQLStart) const;
|
||||
|
||||
public:
|
||||
|
||||
/** Was there templates in the code? */
|
||||
|
|
|
@ -5783,8 +5783,18 @@ private:
|
|||
// Oracle PRO*C extensions for inline SQL. Just replace the SQL with "asm()" to fix wrong error messages
|
||||
// ticket: #1959
|
||||
ASSERT_EQUALS("asm ( \"\"EXEC SQL SELECT A FROM B\"\" ) ;", tokenizeAndStringify("EXEC SQL SELECT A FROM B;",false));
|
||||
ASSERT_EQUALS("asm ( \"\"EXEC SQL\"\" ) ;", tokenizeAndStringify("EXEC SQL",false));
|
||||
ASSERT_THROW(tokenizeAndStringify("EXEC SQL",false), InternalError);
|
||||
|
||||
ASSERT_EQUALS("asm ( \"\"EXEC SQL EXECUTE BEGIN Proc1 ( A ) ; END ; END - EXEC\"\" ) ; asm ( \"\"EXEC SQL COMMIT\"\" ) ;",
|
||||
tokenizeAndStringify("EXEC SQL EXECUTE BEGIN Proc1(A); END; END-EXEC; EXEC SQL COMMIT;",false));
|
||||
ASSERT_EQUALS("asm ( \"\"EXEC SQL UPDATE A SET B = C\"\" ) ; asm ( \"\"EXEC SQL COMMIT\"\" ) ;",
|
||||
tokenizeAndStringify("EXEC SQL UPDATE A SET B = C; EXEC SQL COMMIT;",false));
|
||||
ASSERT_EQUALS("asm ( \"\"EXEC SQL COMMIT\"\" ) ; asm ( \"\"EXEC SQL EXECUTE BEGIN Proc1 ( A ) ; END ; END - EXEC\"\" ) ;",
|
||||
tokenizeAndStringify("EXEC SQL COMMIT; EXEC SQL EXECUTE BEGIN Proc1(A); END; END-EXEC;",false));
|
||||
|
||||
ASSERT_THROW(tokenizeAndStringify("int f(){ EXEC SQL } int a;",false), InternalError);
|
||||
ASSERT_THROW(tokenizeAndStringify("EXEC SQL int f(){",false), InternalError);
|
||||
ASSERT_THROW(tokenizeAndStringify("EXEC SQL END-EXEC int a;",false), InternalError);
|
||||
}
|
||||
|
||||
void simplifyCAlternativeTokens() {
|
||||
|
|
Loading…
Reference in New Issue