Add support for SQL_MACRO

This commit is contained in:
Arjen Duursma
2024-06-27 14:18:30 +02:00
parent f994ae0e6f
commit 44ecb87c43
6 changed files with 124 additions and 116 deletions

View File

@ -27,6 +27,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/**
* Add support for SQL_MACRO
*
* Arjen Duursma 06/2024
*====================================================================
* Add support for MERGE (INTO) statement
* Add support Error Logging for INSERT, UPDATE, DELETE
*
@ -728,7 +732,7 @@ ASTMethodDeclarator MethodDeclarator() :
}
}
// There is no RETURN for a WRAPPED object
[ <RETURN> Datatype() ]
[ <RETURN> Datatype() [ SqlMacroClause() ] ]
)
| <PROCEDURE>
@ -2115,7 +2119,7 @@ void QueryTableExpression() #void :
{}
{
(
LOOKAHEAD(2) [ LOOKAHEAD(2) SchemaName() "." ] TableName()
LOOKAHEAD(2) [ LOOKAHEAD(2) SchemaName() "." ] ( LOOKAHEAD(2) FunctionCall() | TableName() )
|
TableCollectionExpression()
|
@ -2146,6 +2150,7 @@ ASTTableCollectionExpression TableCollectionExpression() :
/**
* Special production, used in joins. The table reference might have
* a table alias, but this should not match any following NATURAL, CROSS, etc.
* keywords, although these are allowed as alias names since these are
* not reserved words.
*/
@ -2690,7 +2695,7 @@ ASTDeleteStatement DeleteStatement() :
ASTMergeStatement MergeStatement() :
{}
{
<MERGE> <INTO> [ LOOKAHEAD(2) SchemaName() "." ] TableName() [ LOOKAHEAD(1, ID(), { getToken(1).kind != USING } ) TableAlias() ]
<MERGE> <INTO> [ LOOKAHEAD(2) SchemaName() "." ] TableName() [ TableAlias() ]
<USING>
(
LOOKAHEAD(3) "(" ValuesClause() ")"
@ -5133,6 +5138,7 @@ TOKEN [IGNORE_CASE]:
<ROWTYPE: "ROWTYPE"> |
<SAVE: "SAVE"> |
<SAVEPOINT: "SAVEPOINT"> |
<SCALAR: "SCALAR"> |
<SECOND: "SECOND"> |
<SELF: "SELF"> |
<SEPARATE: "SEPARATE"> |
@ -5146,6 +5152,7 @@ TOKEN [IGNORE_CASE]:
<SPACE: "SPACE"> |
<SQLCODE: "SQLCODE"> |
<SQLERRM: "SQLERRM"> |
<SQL_MACRO: "SQL_MACRO"> |
<STATIC: "STATIC"> |
<SUBSTITUTABLE: "SUBSTITUTABLE"> |
<SUCCESSFUL: "SUCCESSFUL"> |
@ -7058,3 +7065,14 @@ ASTJavaInterfaceClass JavaInterfaceClass(): {}
)
{ jjtThis.setImage(token.getImage()) ; jjtThis.value = token ; return jjtThis ; }
}
/**
* https://docs.oracle.com/en/database/oracle/oracle-database/23/lnpls/SQL_MACRO-clause.html#LNPLS-GUID-292C3A17-2A4B-4EFB-AD38-68DF6380E5F7
*/
ASTSqlMacroClause SqlMacroClause(): {}
{
(
<SQL_MACRO> [ <LPAREN> [ <TYPE> "=>" ] ( <SCALAR> | <TABLE> ) { jjtThis.setType(token.getImage()); } <RPAREN> ]
)
{ return jjtThis; }
}

View File

@ -0,0 +1,31 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.plsql.ast;
import java.util.Locale;
public final class ASTSqlMacroClause extends AbstractPLSQLNode {
private String type = "TABLE";
ASTSqlMacroClause(int id) {
super(id);
}
@Override
protected <P, R> R acceptPlsqlVisitor(PlsqlVisitor<? super P, ? extends R> visitor, P data) {
return visitor.visit(this, data);
}
public String getType() {
return type;
}
void setType(String type) {
this.type = type;
if (this.type != null) {
this.type = this.type.toUpperCase(Locale.ROOT);
}
}
}

View File

@ -0,0 +1,31 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.plsql.ast;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import java.util.List;
import org.junit.jupiter.api.Test;
import net.sourceforge.pmd.lang.plsql.AbstractPLSQLParserTst;
class ASTSqlMacroClauseTest extends AbstractPLSQLParserTst {
@Test
void testEmpty() {
ASTInput input = plsql.parseResource("SqlMacroClause.pls");
List<ASTSqlMacroClause> sqlMacros = input.descendants(ASTSqlMacroClause.class).toList();
assertFalse(sqlMacros.isEmpty());
assertEquals("TABLE", sqlMacros.get(0).getType());
assertEquals("SCALAR", sqlMacros.get(1).getType());
assertEquals("SCALAR", sqlMacros.get(2).getType());
assertEquals("TABLE", sqlMacros.get(3).getType());
//assertEquals("=", conditions.get(0).getOperator());
}
}

View File

@ -14,12 +14,5 @@ BEGIN
WHEN NOT MATCHED
THEN INSERT (ID,KEY1, TEXT,LCE_ID) values (JHS_SEQ.NEXTVAL,'PROM_EDIT_PROM_NR','Edycja promocji nr',123123);
MERGE INTO b
USING ( SELECT 'PROM_EDIT_PROM_NR' key1,'Edycja promocji nr' text,123123 lce_id FROM dual ) e
ON (b.key1 = e.key1 and b.lce_id=e.lce_id)
WHEN MATCHED
THEN UPDATE SET b.text = e.text
WHEN NOT MATCHED
THEN INSERT (ID,KEY1, TEXT,LCE_ID) values (JHS_SEQ.NEXTVAL,'PROM_EDIT_PROM_NR','Edycja promocji nr',123123);
END;
/

View File

@ -1,115 +1,12 @@
+- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0]
+- Global[@CanonicalImage = null]
+- Block[@CanonicalImage = null]
+- Statement[@CanonicalImage = null]
| +- UnlabelledStatement[@CanonicalImage = null]
| +- MergeStatement[@CanonicalImage = null]
| +- TableName[@CanonicalImage = "JHS_TRANSLATIONS", @Image = "jhs_translations"]
| | +- ID[@CanonicalImage = "JHS_TRANSLATIONS", @Image = "jhs_translations"]
| +- TableAlias[@CanonicalImage = "B", @Image = "b"]
| | +- ID[@CanonicalImage = "B", @Image = "b"]
| +- QueryBlock[@All = false, @CanonicalImage = null, @Distinct = false, @Unique = false]
| | +- SelectList[@CanonicalImage = null]
| | | +- SqlExpression[@CanonicalImage = "\'PROM_EDIT_PROM_NR\'", @Image = "\'PROM_EDIT_PROM_NR\'"]
| | | | +- PrimaryPrefix[@CanonicalImage = "\'PROM_EDIT_PROM_NR\'", @Image = "\'PROM_EDIT_PROM_NR\'", @SelfModifier = false]
| | | | +- Literal[@CanonicalImage = "\'PROM_EDIT_PROM_NR\'", @Image = "\'PROM_EDIT_PROM_NR\'"]
| | | | +- StringLiteral[@CanonicalImage = "\'PROM_EDIT_PROM_NR\'", @Image = "\'PROM_EDIT_PROM_NR\'", @String = "PROM_EDIT_PROM_NR"]
| | | +- ColumnAlias[@CanonicalImage = "KEY1", @Image = "key1"]
| | | | +- ID[@CanonicalImage = "KEY1", @Image = "key1"]
| | | +- SqlExpression[@CanonicalImage = "\'EDYCJA PROMOCJI NR\'", @Image = "\'Edycja promocji nr\'"]
| | | | +- PrimaryPrefix[@CanonicalImage = "\'EDYCJA PROMOCJI NR\'", @Image = "\'Edycja promocji nr\'", @SelfModifier = false]
| | | | +- Literal[@CanonicalImage = "\'EDYCJA PROMOCJI NR\'", @Image = "\'Edycja promocji nr\'"]
| | | | +- StringLiteral[@CanonicalImage = "\'EDYCJA PROMOCJI NR\'", @Image = "\'Edycja promocji nr\'", @String = "Edycja promocji nr"]
| | | +- ColumnAlias[@CanonicalImage = "TEXT", @Image = "text"]
| | | | +- ID[@CanonicalImage = "TEXT", @Image = "text"]
| | | +- SqlExpression[@CanonicalImage = "123123", @Image = "123123"]
| | | | +- PrimaryPrefix[@CanonicalImage = "123123", @Image = "123123", @SelfModifier = false]
| | | | +- Literal[@CanonicalImage = "123123", @Image = "123123"]
| | | | +- NumericLiteral[@CanonicalImage = "123123", @Image = "123123"]
| | | +- ColumnAlias[@CanonicalImage = "LCE_ID", @Image = "lce_id"]
| | | +- ID[@CanonicalImage = "LCE_ID", @Image = "lce_id"]
| | +- FromClause[@CanonicalImage = null]
| | +- TableReference[@CanonicalImage = null]
| | +- TableName[@CanonicalImage = "DUAL", @Image = "dual"]
| | +- ID[@CanonicalImage = "DUAL", @Image = "dual"]
| +- TableAlias[@CanonicalImage = "E", @Image = "e"]
| | +- ID[@CanonicalImage = "E", @Image = "e"]
| +- Condition[@CanonicalImage = null]
| | +- CompoundCondition[@CanonicalImage = null, @Type = "AND"]
| | +- ComparisonCondition[@CanonicalImage = null, @Operator = "="]
| | | +- SqlExpression[@CanonicalImage = "B.KEY1", @Image = "b.key1"]
| | | | +- PrimaryPrefix[@CanonicalImage = "B.KEY1", @Image = "b.key1", @SelfModifier = false]
| | | | +- SimpleExpression[@CanonicalImage = "B.KEY1", @Image = "b.key1"]
| | | | +- TableName[@CanonicalImage = "B", @Image = "b"]
| | | | | +- ID[@CanonicalImage = "B", @Image = "b"]
| | | | +- Column[@CanonicalImage = "KEY1", @Image = "key1"]
| | | | +- ID[@CanonicalImage = "KEY1", @Image = "key1"]
| | | +- SqlExpression[@CanonicalImage = "E.KEY1", @Image = "e.key1"]
| | | +- PrimaryPrefix[@CanonicalImage = "E.KEY1", @Image = "e.key1", @SelfModifier = false]
| | | +- SimpleExpression[@CanonicalImage = "E.KEY1", @Image = "e.key1"]
| | | +- TableName[@CanonicalImage = "E", @Image = "e"]
| | | | +- ID[@CanonicalImage = "E", @Image = "e"]
| | | +- Column[@CanonicalImage = "KEY1", @Image = "key1"]
| | | +- ID[@CanonicalImage = "KEY1", @Image = "key1"]
| | +- Condition[@CanonicalImage = null]
| | +- CompoundCondition[@CanonicalImage = null, @Type = null]
| | +- ComparisonCondition[@CanonicalImage = null, @Operator = "="]
| | +- SqlExpression[@CanonicalImage = "B.LCE_ID", @Image = "b.lce_id"]
| | | +- PrimaryPrefix[@CanonicalImage = "B.LCE_ID", @Image = "b.lce_id", @SelfModifier = false]
| | | +- SimpleExpression[@CanonicalImage = "B.LCE_ID", @Image = "b.lce_id"]
| | | +- TableName[@CanonicalImage = "B", @Image = "b"]
| | | | +- ID[@CanonicalImage = "B", @Image = "b"]
| | | +- Column[@CanonicalImage = "LCE_ID", @Image = "lce_id"]
| | | +- ID[@CanonicalImage = "LCE_ID", @Image = "lce_id"]
| | +- SqlExpression[@CanonicalImage = "E.LCE_ID", @Image = "e.lce_id"]
| | +- PrimaryPrefix[@CanonicalImage = "E.LCE_ID", @Image = "e.lce_id", @SelfModifier = false]
| | +- SimpleExpression[@CanonicalImage = "E.LCE_ID", @Image = "e.lce_id"]
| | +- TableName[@CanonicalImage = "E", @Image = "e"]
| | | +- ID[@CanonicalImage = "E", @Image = "e"]
| | +- Column[@CanonicalImage = "LCE_ID", @Image = "lce_id"]
| | +- ID[@CanonicalImage = "LCE_ID", @Image = "lce_id"]
| +- MergeUpdateClause[@CanonicalImage = null]
| | +- TableName[@CanonicalImage = "B", @Image = "b"]
| | | +- ID[@CanonicalImage = "B", @Image = "b"]
| | +- Column[@CanonicalImage = "TEXT", @Image = "text"]
| | | +- ID[@CanonicalImage = "TEXT", @Image = "text"]
| | +- Expression[@CanonicalImage = "E.TEXT", @Image = "e.text"]
| | +- PrimaryPrefix[@CanonicalImage = "E.TEXT", @Image = "e.text", @SelfModifier = false]
| | +- SimpleExpression[@CanonicalImage = "E.TEXT", @Image = "e.text"]
| | +- TableName[@CanonicalImage = "E", @Image = "e"]
| | | +- ID[@CanonicalImage = "E", @Image = "e"]
| | +- Column[@CanonicalImage = "TEXT", @Image = "text"]
| | +- ID[@CanonicalImage = "TEXT", @Image = "text"]
| +- MergeInsertClause[@CanonicalImage = null]
| +- Column[@CanonicalImage = "ID", @Image = "ID"]
| | +- ID[@CanonicalImage = "ID", @Image = "ID"]
| +- Column[@CanonicalImage = "KEY1", @Image = "KEY1"]
| | +- ID[@CanonicalImage = "KEY1", @Image = "KEY1"]
| +- Column[@CanonicalImage = "TEXT", @Image = "TEXT"]
| | +- ID[@CanonicalImage = "TEXT", @Image = "TEXT"]
| +- Column[@CanonicalImage = "LCE_ID", @Image = "LCE_ID"]
| | +- ID[@CanonicalImage = "LCE_ID", @Image = "LCE_ID"]
| +- ValuesClause[@CanonicalImage = null]
| +- Expression[@CanonicalImage = "", @Image = ""]
| | +- PrimaryPrefix[@CanonicalImage = "", @Image = "", @SelfModifier = false]
| | +- SimpleExpression[@CanonicalImage = "", @Image = ""]
| | +- ID[@CanonicalImage = "JHS_SEQ", @Image = "JHS_SEQ"]
| +- Expression[@CanonicalImage = "\'PROM_EDIT_PROM_NR\'", @Image = "\'PROM_EDIT_PROM_NR\'"]
| | +- PrimaryPrefix[@CanonicalImage = "\'PROM_EDIT_PROM_NR\'", @Image = "\'PROM_EDIT_PROM_NR\'", @SelfModifier = false]
| | +- Literal[@CanonicalImage = "\'PROM_EDIT_PROM_NR\'", @Image = "\'PROM_EDIT_PROM_NR\'"]
| | +- StringLiteral[@CanonicalImage = "\'PROM_EDIT_PROM_NR\'", @Image = "\'PROM_EDIT_PROM_NR\'", @String = "PROM_EDIT_PROM_NR"]
| +- Expression[@CanonicalImage = "\'EDYCJA PROMOCJI NR\'", @Image = "\'Edycja promocji nr\'"]
| | +- PrimaryPrefix[@CanonicalImage = "\'EDYCJA PROMOCJI NR\'", @Image = "\'Edycja promocji nr\'", @SelfModifier = false]
| | +- Literal[@CanonicalImage = "\'EDYCJA PROMOCJI NR\'", @Image = "\'Edycja promocji nr\'"]
| | +- StringLiteral[@CanonicalImage = "\'EDYCJA PROMOCJI NR\'", @Image = "\'Edycja promocji nr\'", @String = "Edycja promocji nr"]
| +- Expression[@CanonicalImage = "123123", @Image = "123123"]
| +- PrimaryPrefix[@CanonicalImage = "123123", @Image = "123123", @SelfModifier = false]
| +- Literal[@CanonicalImage = "123123", @Image = "123123"]
| +- NumericLiteral[@CanonicalImage = "123123", @Image = "123123"]
+- Statement[@CanonicalImage = null]
+- UnlabelledStatement[@CanonicalImage = null]
+- MergeStatement[@CanonicalImage = null]
+- TableName[@CanonicalImage = "B", @Image = "b"]
+- TableName[@CanonicalImage = "JHS_TRANSLATIONS", @Image = "jhs_translations"]
| +- ID[@CanonicalImage = "JHS_TRANSLATIONS", @Image = "jhs_translations"]
+- TableAlias[@CanonicalImage = "B", @Image = "b"]
| +- ID[@CanonicalImage = "B", @Image = "b"]
+- QueryBlock[@All = false, @CanonicalImage = null, @Distinct = false, @Unique = false]
| +- SelectList[@CanonicalImage = null]

View File

@ -0,0 +1,38 @@
create or replace package body test is
function test1() return clob sql_macro is
begin
return 'q[select * from dual]';
end test1;
function test2() return clob sql_macro(TYPE => SCALAR) is
begin
return 'q[select * from dual]';
end test2;
function test3() return clob sql_macro(SCALAR) is
begin
return 'q[select * from dual]';
end test3;
function test3() return clob sql_macro(TABLE) is
begin
return 'q[select * from dual]';
end test4;
function test5() return int is
cursor c is select 1 from test.test1();
begin
return 1;
end test5;
end test;