diff --git a/.github/workflows/perf.yml b/.github/workflows/perf.yml new file mode 100644 index 0000000000..c4e8a97206 --- /dev/null +++ b/.github/workflows/perf.yml @@ -0,0 +1,88 @@ +name: Perf analysis of what has changed +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + perf: + runs-on: ubuntu-latest + steps: + - name: Info + shell: bash + run: | + arch + uname -a + if [ -f /proc/cpuinfo ]; then cat /proc/cpuinfo; fi + - name: Install Octave + run: | + sudo apt install octave + sudo apt install octave-statistics + octave --version + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Install Dotnet + uses: actions/setup-dotnet@v4.0.0 + with: + dotnet-version: '8.0.x' + - name: Test Dotnet + run: | + dotnet --version + dotnet --info + dotnet --list-runtimes + dotnet --list-sdks + - name: Install Java + uses: actions/setup-java@v4 + with: + java-version: '11' + distribution: 'zulu' + - name: Test Java + run: | + dotnet --version + java --version + javac --version + - name: Install Antlr tool + run: | + pip install antlr4-tools + - name: Install JavaScript + if: ${{ matrix.language == 'JavaScript' }} + uses: actions/setup-node@v4.0.2 + with: + node-version: '16.13.0' + - name: Test JavaScript + if: ${{ matrix.language == 'JavaScript' }} + run: | + node --version + - name: Update paths + shell: pwsh + run: | + if ("${{ matrix.os }}" -eq "ubuntu-latest") { + echo "$HOME/.dotnet/tools" >> $env:GITHUB_PATH + } + - name: Install Trash + shell: bash + run: | + dotnet tool restore + - name: Test Trash install + shell: bash + run: | + dotnet trgen -- --help + - name: Test + shell: bash + run: | + if [ "${{github.event_name}}" == "pull_request" ] ; then + Before="${{github.event.pull_request.base.sha}}" + After="${{github.event.pull_request.head.sha}}" + else + Before="${{github.event.before}}" + After="${{github.event.after}}" + fi + bash _scripts/perf-changed.sh -b "$Before" -a "$After" + diff --git a/_scripts/perf-changed.sh b/_scripts/perf-changed.sh new file mode 100644 index 0000000000..27c642350e --- /dev/null +++ b/_scripts/perf-changed.sh @@ -0,0 +1,270 @@ +# + +# set -x +set -e + +# Check requirements. +if ! command -v dotnet &> /dev/null +then + echo "'dotnet' could not be found. Install Microsoft NET." + exit 1 +fi +if ! command -v trxml2 &> /dev/null +then + local=1 +fi +if ! command -v dotnet trxml2 -- --version &> /dev/null +then + echo "'dotnet' could not be found. Install Microsoft NET." + exit 1 +fi + +cwd=`pwd` + +while getopts 'a:b:' opt; do + case "$opt" in + a) + after="${OPTARG}" + ;; + b) + before="${OPTARG}" + ;; + esac +done + +if [ "$after" == "" ] +then + echo "'after' not set." + exit 1 +fi +if [ "$before" == "" ] +then + echo "'before' not set." + exit 1 +fi + +############################# +############################# +# Get last commit/pr. Note, some of the PR merges don't +# fit the pattern, but we'll ignore them. Get "prior" commit before all these +# changes. +prs=( After Before ) +com=( $after $before ) +echo PRS = ${prs[@]} +echo COM = ${com[@]} +echo '#PRS' = ${#prs[@]} + +# Clean up. +for ((i=0; i<${#prs[@]}; i++)) +do + rm -rf "$cwd/${prs[$i]}" +done +rm -rf `find . -name 'Generated-*'` + +# The PR that is more recent is the first in the list. +# Get grammars changed for current PR. This will focus exactly on what to +# test. Note, we only consider .g4 changes, no examples, no duplicates. +tests=() +changes=`git diff --name-only ${com[0]} ${com[1]} | grep '[.]g4$' | sed 's#\(.*\)[/][^/]*$#\1#' | sort -u | grep -v _scripts | fgrep -v .github | fgrep -v examples | sort -u | tr -d '\r'` +echo Changed files = $changes + +############################# +echo Computing grammars changed... +prefix=`pwd` +for g in ${changes[@]} +do + if [ ! -d "$g" ]; then continue; fi + pushd $g > /dev/null 2> /dev/null + while true + do + if [ -f `pwd`/desc.xml ] + then + break + elif [ `pwd` == "$prefix" ] + then + break + fi + cd .. + done + g=`pwd` + g=${g##*$prefix} + g=${g##/} + if [ "$g" == "" ]; then continue; fi + if [ -f desc.xml ] + then + if [ "$local" == "" ] + then + gtargets=`trxml2 desc.xml | fgrep -e '/desc/targets' | awk -F '=' '{print $2}' | tr ';' '\n' | fgrep -e 'Java' | fgrep -v 'JavaScript'` + else + gtargets=`dotnet trxml2 -- desc.xml | fgrep -e '/desc/targets' | awk -F '=' '{print $2}' | tr ';' '\n' | fgrep -e 'Java' | fgrep -v 'JavaScript'` + fi + if [ "$gtargets" == "" ]; then continue; fi + fi + tests=( ${tests[@]} $g ) + popd > /dev/null +done +echo Grammars to test = ${tests[@]} + +############################# +echo Build each grammar changed in PR. +for ((i=0; i<${#prs[@]}; i++)) +do + rm -rf "$cwd/${prs[$i]}" + mkdir "$cwd/${prs[$i]}" + git checkout ${com[$i]} + for g in ${tests[@]} + do + echo Grammar $g + pushd $g + gg=`echo $g | tr '/' '-'` + if [ "$local" == "" ] + then + trgen -t CSharp + else + dotnet trgen -- -t CSharp + fi + where=`echo Generated-CSharp* | tr ' ' '\n' | head -1` + echo $where + cd $where + make + popd + cp -r $g "$cwd/${prs[$i]}/$gg" + done +done + +#=========================== +echo Test each grammar and PR in turn. +for g in ${tests[@]} +do + echo Grammar $g + rm -f "$cwd"/p[0-1]* + gg=`echo $g | tr '/' '-'` + what=() + for ((i=0; i<${#prs[@]}; i++)) + do + pushd "$cwd/${prs[$i]}/$gg" + where=`echo Generated-CSharp* | tr ' ' '\n' | head -1` + echo $where + cd $where + if [ "${#what[@]}" -eq 0 ] + then + if [ "$local" == "" ] + then + what=`trxml2 desc.xml | grep inputs | head -1 | sed 's%^[^=]*=%%'` + else + what=`dotnet trxml2 -- desc.xml | grep inputs | head -1 | sed 's%^[^=]*=%%'` + fi + if [ "$what" == "" ] + then + dir=`pwd` + p=`realpath -s --relative-to=$dir "$cwd/${prs[1]}/$gg/examples"` + if [ "$local" == "" ] + then + what=( `trglob $p | grep -v '.errors$' | grep -v '.tree$'` ) + else + what=( `dotnet trglob -- $p | grep -v '.errors$' | grep -v '.tree$'` ) + fi + else + dir=`pwd` + p=`realpath -s --relative-to=$dir "$cwd/${prs[1]}/$gg/$what"` + if [ "$local" == "" ] + then + what=( `trglob $p | grep -v '.errors$' | grep -v '.tree$'` ) + else + what=( `dotnet trglob -- $p | grep -v '.errors$' | grep -v '.tree$'` ) + fi + fi + echo what = $what + newwhat=() + for f in ${what[@]} + do + if [ -d $f ]; then continue; fi + newwhat=( ${newwhat[@]} $f ) + done + what=( ${newwhat[@]} ) + if [ ${#what[@]} -eq 0 ]; then popd; continue; fi + fi + # Try first and scale number of times to work in 10 minutes tops. + # Format is in seconds, in floating point format. + runtime=`bash run.sh ${what[@]} 2>&1 | grep "Total Time" | awk '{print $3}'` + times=`python -c "print(int(min(40,600/$runtime)))"` + for ((j=1;j<=times;j++)); do + bash run.sh ${what[@]} 2>&1 | grep "Total Time" | awk '{print $3}' >> "$cwd/p$i-$gg.txt" + done + popd + done + + echo Graphing out. + cd $cwd + rm -f xx.m + echo "pkg load statistics" >> xx.m + for ((i=0; i<${#prs[@]}; i++)) + do + echo "p$i=["`cat "$cwd/p$i-$gg.txt"`"];" >> xx.m + echo "mp$i=mean(p$i);" >> xx.m + echo "sd$i=std(p$i);" >> xx.m + echo "printf('disp($i)\n');" >> xx.m + echo "disp($i);" >> xx.m + echo "printf('disp(p$i)\n');" >> xx.m + echo "disp(p$i);" >> xx.m + echo "printf('mp$i = %f\n', mp$i);" >> xx.m + echo "printf('sd$i = %f\n', sd$i);" >> xx.m + done + echo -n "x = [" >> xx.m + for ((i=1; i<=${#prs[@]}; i++)) + do + echo -n " $i" >> xx.m + done + echo "];" >> xx.m + echo -n "str = [ " >> xx.m + for ((i=0; i<${#prs[@]}; i++)) + do + if [ "$i" != "0" ]; then echo -n "; " >> xx.m; fi + echo -n " '"PR${prs[$i]}"'" >> xx.m + done + echo " ];" >> xx.m + echo -n "data = [" >> xx.m + for ((i=0; i<${#prs[@]}; i++)) + do + echo -n " mp$i" >> xx.m + done + echo " ];" >> xx.m + echo -n "errhigh = [" >> xx.m + for ((i=0; i<${#prs[@]}; i++)) + do + echo -n " sd$i" >> xx.m + done + echo " ];" >> xx.m + echo -n "errlow = [" >> xx.m + for ((i=0; i<${#prs[@]}; i++)) + do + echo -n " sd$i" >> xx.m + done + echo " ];" >> xx.m + cat >> xx.m < 1.05) + printf("The PR statistically and practically decreased performance for $gg.\n"); + else + printf("The PR did not signficantly negatively alter performance for $gg.\n"); + endif +EOF + echo ======== + cat xx.m + echo ======== + cat xx.m | octave --no-gui + +done diff --git a/sql/plsql/PlSqlLexer.g4 b/sql/plsql/PlSqlLexer.g4 index 63ef43868f..66bd41163b 100644 --- a/sql/plsql/PlSqlLexer.g4 +++ b/sql/plsql/PlSqlLexer.g4 @@ -2363,16 +2363,16 @@ LEAST : 'LEAST'; GREATEST : 'GREATEST'; TO_DATE : 'TO_DATE'; -CHARSETID : 'CHARSETID'; -CHARSETFORM : 'CHARSETFORM'; -DURATION : 'DURATION'; -EXTEND : 'EXTEND'; -MAXLEN : 'MAXLEN'; -PERSISTABLE : 'PERSISTABLE'; -POLYMORPHIC : 'POLYMORPHIC'; -STRUCT : 'STRUCT'; -TDO : 'TDO'; -WM_CONCAT : 'WM_CONCAT'; +CHARSETID : 'CHARSETID'; +CHARSETFORM : 'CHARSETFORM'; +DURATION : 'DURATION'; +EXTEND : 'EXTEND'; +MAXLEN : 'MAXLEN'; +PERSISTABLE : 'PERSISTABLE'; +POLYMORPHIC : 'POLYMORPHIC'; +STRUCT : 'STRUCT'; +TDO : 'TDO'; +WM_CONCAT : 'WM_CONCAT'; // Rule #358 - subtoken typecast in , it also incorporates // Lowercase 'n' is a usual addition to the standard diff --git a/sql/plsql/PlSqlParser.g4 b/sql/plsql/PlSqlParser.g4 index f01928359b..37a65f77d2 100644 --- a/sql/plsql/PlSqlParser.g4 +++ b/sql/plsql/PlSqlParser.g4 @@ -492,7 +492,11 @@ alter_hierarchy ; alter_function - : ALTER FUNCTION function_name (EDITIONABLE | NONEDITIONABLE | COMPILE DEBUG? compiler_parameters_clause* (REUSE SETTINGS)?) + : ALTER FUNCTION function_name ( + EDITIONABLE + | NONEDITIONABLE + | COMPILE DEBUG? compiler_parameters_clause* (REUSE SETTINGS)? + ) ; // https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/ALTER-JAVA.html @@ -560,7 +564,7 @@ pipelined_using_clause ; accessor - : unitKind=(FUNCTION | PROCEDURE | PACKAGE | TRIGGER | TYPE) function_name + : unitKind = (FUNCTION | PROCEDURE | PACKAGE | TRIGGER | TYPE) function_name ; relies_on_part @@ -741,12 +745,13 @@ alter_procedure function_body : FUNCTION identifier ('(' parameter (',' parameter)* ')')? RETURN type_spec ( - PIPELINED + PIPELINED | DETERMINISTIC | invoker_rights_clause | parallel_enable_clause | result_cache_clause - | streaming_clause // see example in section "How Table Functions Stream their Input Data" on streaming_clause in Oracle 9i: https://docs.oracle.com/cd/B10501_01/appdev.920/a96624/08_subs.htm#20554 + | streaming_clause + // see example in section "How Table Functions Stream their Input Data" on streaming_clause in Oracle 9i: https://docs.oracle.com/cd/B10501_01/appdev.920/a96624/08_subs.htm#20554 )* ( ( (IS | AS) (DECLARE? seq_of_declare_specs? body | call_spec)) | (PIPELINED | AGGREGATE) USING implementation_type_name @@ -757,11 +762,7 @@ procedure_body : PROCEDURE identifier ('(' parameter (',' parameter)* ')')? ( accessible_by_clause | PARALLEL_ENABLE - )* (IS | AS) ( - DECLARE? seq_of_declare_specs? body - | call_spec - | EXTERNAL - ) ';' + )* (IS | AS) (DECLARE? seq_of_declare_specs? body | call_spec | EXTERNAL) ';' ; create_procedure_body @@ -894,10 +895,10 @@ compound_trigger_block ; timing_point_section - : bk=BEFORE STATEMENT IS tps_block BEFORE STATEMENT ';' - | bk=BEFORE EACH ROW IS tps_block BEFORE EACH ROW ';' - | ak=AFTER STATEMENT IS tps_block AFTER STATEMENT ';' - | ak=AFTER EACH ROW IS tps_block AFTER EACH ROW ';' + : bk = BEFORE STATEMENT IS tps_block BEFORE STATEMENT ';' + | bk = BEFORE EACH ROW IS tps_block BEFORE EACH ROW ';' + | ak = AFTER STATEMENT IS tps_block AFTER STATEMENT ';' + | ak = AFTER EACH ROW IS tps_block AFTER EACH ROW ';' ; non_dml_event @@ -1655,7 +1656,6 @@ index_partitioning_clause : PARTITION partition_name? VALUES LESS THAN '(' index_partitioning_values_list ')' segment_attributes_clause? ; - index_partitioning_values_list : literal (',' literal)* | TIMESTAMP literal (',' TIMESTAMP literal)* @@ -2719,10 +2719,14 @@ alter_view_editionable // https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/CREATE-VIEW.html create_view - : CREATE (OR REPLACE)? (NO? FORCE)? editioning_clause? VIEW (schema_name '.')? v = id_expression (IF NOT EXISTS)? ( - SHARING '=' (METADATA | EXTENDED? DATA | NONE) - )? view_options? (DEFAULT COLLATION cn = id_expression)? (BEQUEATH (CURRENT_USER | DEFINER))? AS select_only_statement subquery_restriction_clause - ? (CONTAINER_MAP | CONTAINERS_DEFAULT)? + : CREATE (OR REPLACE)? (NO? FORCE)? editioning_clause? VIEW (schema_name '.')? v = id_expression ( + IF NOT EXISTS + )? (SHARING '=' (METADATA | EXTENDED? DATA | NONE))? view_options? ( + DEFAULT COLLATION cn = id_expression + )? (BEQUEATH (CURRENT_USER | DEFINER))? AS select_only_statement subquery_restriction_clause? ( + CONTAINER_MAP + | CONTAINERS_DEFAULT + )? ; editioning_clause @@ -2911,13 +2915,11 @@ segment_management_clause ; temporary_tablespace_clause - : TEMPORARY TABLESPACE tablespace_name = id_expression - (IF NOT EXISTS)? tempfile_specification? tablespace_group_clause? extent_management_clause? + : TEMPORARY TABLESPACE tablespace_name = id_expression (IF NOT EXISTS)? tempfile_specification? tablespace_group_clause? extent_management_clause? ; undo_tablespace_clause - : UNDO TABLESPACE tablespace_name = id_expression - (IF NOT EXISTS)? datafile_specification? extent_management_clause? tablespace_retention_clause? + : UNDO TABLESPACE tablespace_name = id_expression (IF NOT EXISTS)? datafile_specification? extent_management_clause? tablespace_retention_clause? ; tablespace_retention_clause @@ -3379,11 +3381,11 @@ create_table | DUPLICATED | IMMUTABLE? BLOCKCHAIN | IMMUTABLE - )? TABLE (schema_name '.')? table_name (IF NOT EXISTS)? (SHARING '=' (METADATA | EXTENDED? DATA | NONE))? ( - relational_table - | xmltype_table - | object_table - ) memoptimize_read_write_clause? (PARENT tableview_name)? (USAGE QUEUE)? + )? TABLE (schema_name '.')? table_name (IF NOT EXISTS)? ( + SHARING '=' (METADATA | EXTENDED? DATA | NONE) + )? (relational_table | xmltype_table | object_table) memoptimize_read_write_clause? ( + PARENT tableview_name + )? (USAGE QUEUE)? ; xmltype_table @@ -4796,9 +4798,12 @@ modify_table_partition split_table_partition : SPLIT partition_extended_names ( - AT '(' literal (',' literal)* ')' INTO '(' range_partition_desc (',' range_partition_desc)* ')' - | INTO '(' (range_partition_desc (',' range_partition_desc)* | list_partition_desc (',' list_partition_desc)* ) ')' - ) (update_global_index_clause | update_index_clauses)? + AT '(' literal (',' literal)* ')' INTO '(' range_partition_desc (',' range_partition_desc)* ')' + | INTO '(' ( + range_partition_desc (',' range_partition_desc)* + | list_partition_desc (',' list_partition_desc)* + ) ')' + ) (update_global_index_clause | update_index_clauses)? ; truncate_table_partition @@ -5391,11 +5396,10 @@ java_spec ; c_spec - : (LANGUAGE C_LETTER | EXTERNAL) - ( NAME id_expression LIBRARY identifier - | LIBRARY identifier (NAME id_expression)? - ) - c_agent_in_clause? (WITH CONTEXT)? c_parameters_clause? + : (LANGUAGE C_LETTER | EXTERNAL) ( + NAME id_expression LIBRARY identifier + | LIBRARY identifier (NAME id_expression)? + ) c_agent_in_clause? (WITH CONTEXT)? c_parameters_clause? ; c_agent_in_clause @@ -5409,7 +5413,7 @@ c_parameters_clause c_external_parameter : CONTEXT | SELF (TDO | c_property)? - | (parameter_name | RETURN) c_property? (BY REFERENCE)? external_datatype=regular_id? + | (parameter_name | RETURN) c_property? (BY REFERENCE)? external_datatype = regular_id? ; c_property @@ -5636,9 +5640,9 @@ pipe_row_statement ; selection_directive - : DOLLAR_IF condition DOLLAR_THEN selection_directive_body - (DOLLAR_ELSIF selection_directive_body)* (DOLLAR_ELSE selection_directive_body)? - DOLLAR_END + : DOLLAR_IF condition DOLLAR_THEN selection_directive_body ( + DOLLAR_ELSIF selection_directive_body + )* (DOLLAR_ELSE selection_directive_body)? DOLLAR_END ; error_directive @@ -5646,12 +5650,13 @@ error_directive ; selection_directive_body - : ( pragma_declaration? statement ';' - | variable_declaration - | error_directive - | function_body - | procedure_body - )+ + : ( + pragma_declaration? statement ';' + | variable_declaration + | error_directive + | function_body + | procedure_body + )+ ; body @@ -5795,9 +5800,10 @@ savepoint_statement // https://docs.oracle.com/en/database/oracle/oracle-database/19/lnpls/collection-method.html#GUID-7AF1A3C4-D04B-4F91-9D7B-C92C75E3A300 collection_method_call // collection methods invocation that could be used as a statement - : expression '.' ( (DELETE | EXTEND) ('(' index+=expression (',' index+=expression)* ')')? - | TRIM ('(' index+=expression ')')? - ) + : expression '.' ( + (DELETE | EXTEND) ('(' index += expression (',' index += expression)* ')')? + | TRIM ('(' index += expression ')')? + ) ; // Dml @@ -5841,10 +5847,8 @@ select_statement // Select Specific Clauses with_clause - : WITH (function_body | procedure_body)* - with_factoring_clause (',' with_factoring_clause)* - | WITH (function_body | procedure_body)+ - (with_factoring_clause (',' with_factoring_clause)*)? + : WITH (function_body | procedure_body)* with_factoring_clause (',' with_factoring_clause)* + | WITH (function_body | procedure_body)+ (with_factoring_clause (',' with_factoring_clause)*)? ; with_factoring_clause @@ -5867,15 +5871,15 @@ cycle_clause ; subav_factoring_clause - : subav_name=id_expression ANALYTIC VIEW AS '(' subav_clause ')' + : subav_name = id_expression ANALYTIC VIEW AS '(' subav_clause ')' ; subav_clause - : USING subav_name=object_name hierarchies_clause? filter_clauses? add_calcs_clause? + : USING subav_name = object_name hierarchies_clause? filter_clauses? add_calcs_clause? ; hierarchies_clause - : HIERARCHIES '(' hier_alias+=object_name (',' hier_alias+=object_name)* ')' + : HIERARCHIES '(' hier_alias += object_name (',' hier_alias += object_name)* ')' ; filter_clauses @@ -5883,7 +5887,7 @@ filter_clauses ; filter_clause - : ( MEASURES | hier_alias=object_name) TO condition + : (MEASURES | hier_alias = object_name) TO condition ; add_calcs_clause @@ -5891,7 +5895,7 @@ add_calcs_clause ; add_calc_meas_clause - : meas_name=id_expression AS '(' expression ')' + : meas_name = id_expression AS '(' expression ')' ; subquery @@ -5908,8 +5912,10 @@ subquery_operation_part ; query_block - : SELECT (DISTINCT | UNIQUE | ALL)? selected_list into_clause? from_clause? where_clause? (hierarchical_query_clause | group_by_clause)* model_clause? - order_by_clause? fetch_clause? + : SELECT (DISTINCT | UNIQUE | ALL)? selected_list into_clause? from_clause? where_clause? ( + hierarchical_query_clause + | group_by_clause + )* model_clause? order_by_clause? fetch_clause? ; selected_list @@ -6351,7 +6357,10 @@ logical_operation multiset_expression : relational_expression (multiset_type = (MEMBER | SUBMULTISET) OF? concatenation)? - | multiset_expression MULTISET multiset_operator=(EXCEPT | INTERSECT | UNION) (ALL | DISTINCT)? relational_expression + | multiset_expression MULTISET multiset_operator = (EXCEPT | INTERSECT | UNION) ( + ALL + | DISTINCT + )? relational_expression ; relational_expression @@ -6436,9 +6445,10 @@ unary_expression | DISTINCT unary_expression | ALL unary_expression | /*TODO{(input.LA(1) == CASE || input.LA(2) == CASE)}?*/ case_statement /*[false]*/ - | unary_expression '.' ( (COUNT | FIRST | LAST | LIMIT) - | (EXISTS | NEXT | PRIOR) '(' index+=expression ')' - ) + | unary_expression '.' ( + (COUNT | FIRST | LAST | LIMIT) + | (EXISTS | NEXT | PRIOR) '(' index += expression ')' + ) | quantified_expression | standard_function | atom @@ -6447,9 +6457,10 @@ unary_expression // https://docs.oracle.com/en/database/oracle/oracle-database/21/lnpls/plsql-optimization-and-tuning.html#GUID-DAF46F06-EF3F-4B1A-A518-5238B80C69FA implicit_cursor_expression - : SQL ( PERCENT_BULK_ROWCOUNT '(' index=expression ')' - | PERCENT_BULK_EXCEPTIONS ('.' COUNT | '(' expression ')' '.' (ERROR_INDEX | ERROR_CODE)) - ) + : SQL ( + PERCENT_BULK_ROWCOUNT '(' index = expression ')' + | PERCENT_BULK_EXCEPTIONS ('.' COUNT | '(' expression ')' '.' (ERROR_INDEX | ERROR_CODE)) + ) ; collection_expression @@ -6497,7 +6508,10 @@ atom ; quantified_expression - : (SOME | EXISTS | ALL | ANY) ('(' select_only_statement ')' | '(' expression (',' expression)*')') + : (SOME | EXISTS | ALL | ANY) ( + '(' select_only_statement ')' + | '(' expression (',' expression)* ')' + ) ; string_function @@ -6549,10 +6563,9 @@ json_object_content ; json_object_entry - : (KEY? expression (VALUE | IS)? expression - | expression ':' expression - | identifier - ) (FORMAT JSON)? + : (KEY? expression (VALUE | IS)? expression | expression ':' expression | identifier) ( + FORMAT JSON + )? ; json_table_clause diff --git a/sql/plsql/desc.xml b/sql/plsql/desc.xml index 112f4e43e1..876f8b1562 100644 --- a/sql/plsql/desc.xml +++ b/sql/plsql/desc.xml @@ -2,19 +2,19 @@ ^4.12.0 CSharp;Java;JavaScript;Python3 + + full + CSharp;Java + examples + hw JavaScript;Python3 hw-examples - full + examples-sql-script CSharp;Java - examples + examples-sql-script - - examples-sql-script - CSharp;Java - examples-sql-script -