Repository navigation
Conversation
…hared utility options PostgreSQL maintenance scripts failed to parse: VACUUM, CLUSTER and CHECKPOINT had no statement, and ANALYZE accepted only the MySQL form, so option lists, ANALYZE VERBOSE, column lists and a bare ANALYZE failed. Add UtilityOption, one name [value] element of PostgreSQL's utility_option_list with a typed value, and the shared UtilityOptionList()/UtilityOptionArgument() productions. VACUUM, ANALYZE and CLUSTER use them and, like PostgreSQL's grammar, accept any option name and value but PostgreSQL's reserved words; the server checks them when it runs the statement, and getKind() maps known names to each statement's OptionKind. EXPLAIN reads its options through the same production and accepts no more than before. The unparenthesized keywords (VACUUM FULL, ANALYZE VERBOSE, CLUSTER VERBOSE) are kept as options with isParenthesizedOptions() false. Add VacuumStatement, ClusterStatement (also the pre-8.3 CLUSTER index ON table) and CheckpointStatement, and extend Analyze with options, the ANALYSE spelling and MaintenanceTarget tables ([ONLY] t [*] [(columns)]). Analyze keeps its MySQL form with the whole histogram clause (bucket count, AUTO/MANUAL UPDATE, USING DATA); the MySQL clauses and the PostgreSQL options and targets exclude each other, and getTables() is derived from the targets. The statements, options and targets carry AST nodes spanning their source. VACUUM and CLUSTER become non-reserved keywords. The PostgreSQL forms are read with Dialect.POSTGRESQL and without a dialect; other dialects are unchanged. Wire the statements into the deparser, visitors, table finder, validation (vacuum, cluster, checkpoint; analyze is now in the MySQL, MariaDB and PostgreSQL capabilities) and feature analysis. Signed-off-by: minleejae <mmj9808@gmail.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Purpose
PostgreSQL maintenance scripts run
VACUUM,ANALYZE,CLUSTERandCHECKPOINT. Onmaster(7123d25a1) these fail in every configuration, for example:VACUUM (PARALLEL 2, INDEX_CLEANUP OFF) t (a),VACUUM FULL t,VACUUM (VERBOSE, ANALYZE) tANALYZE VERBOSE t (a),ANALYZE (SKIP_LOCKED) t, s, a bareANALYZECLUSTER t USING t_pkey,CLUSTER VERBOSE,CLUSTER (VERBOSE) t, a bareCLUSTER, the pre-8.3CLUSTER t_pkey ON tANALYSE t, PostgreSQL's other spelling ofANALYZECHECKPOINTPostgreSQL 18 references: VACUUM, ANALYZE, CLUSTER, CHECKPOINT.
Current design (As-is)
VACUUM,CLUSTERorCHECKPOINT;CHECKPOINTis only known inside Oracle'sALTER SYSTEM CHECKPOINT.Analyzemodels MySQL'sANALYZE [NO_WRITE_TO_BINLOG | LOCAL] [TABLE] t, … [histogram], where feat: parse MySQL CHECKSUM TABLE and histogram update options #2883 completed the MySQL 8.4 histogram clause:UPDATE HISTOGRAM ON c, … [WITH n BUCKETS] [{AUTO | MANUAL} UPDATE],UPDATE HISTOGRAM ON c USING DATA 'json'andDROP HISTOGRAM ON c, …(getHistogramBucketCount(),getHistogramUpdateMode(),getHistogramData()). It requires a table and has no options, soANALYZE (SKIP_LOCKED) t,ANALYZE t (a)andANALYZEfail, andANALYZE VERBOSE tstops att.Analyzehas small defects:toString()always appends a space and the table list, so a statement without tables would render asANALYZE.StatementDeParser.visit(Analyze)lacks@Override.Feature.analyzeis in no capability list, so the validator rejectsANALYZEfor MySQL, MariaDB and PostgreSQL alike.utility_option_list(( name [value], … )) is shared byVACUUM,ANALYZE,CLUSTER,EXPLAINandREINDEX. JSqlParser parses it forEXPLAIN, with a closed option enum and its own list of value tokens, and forREINDEX(Parse PostgreSQL event triggers, REINDEX, SECURITY LABEL and schema elements #2818) with another closed enum.Target design (To-be)
Shared option model:
UtilityOption(net.sf.jsqlparser.statement) is onename [value]element.getName()keeps the name as written.getValueType()isBOOLEAN(TRUE/FALSE/ON/OFF),NUMBER(signed integer or decimal),STRINGorWORD(such asAUTO);getValue()is the SQL text.ReplicationOption:getBooleanValue()(as PostgreSQL'sdefGetBoolean: also0/1and'on'),getLongValue(),getStringValue()(unquoted and unescaped) andgetEnumValue(Class).OptionKindenum (VacuumStatement.OptionKind,Analyze.OptionKind,ClusterStatement.OptionKind), andgetKind(Class)maps a name to it, or null. A new PostgreSQL option therefore needs one enum constant, not a model change. As in PostgreSQL,ANALYSEnames theANALYZEoption.UtilityOption.of(name, boolean),of(name, long),ofString(name, text)andofWord(name, word).Shared grammar that follows PostgreSQL's:
UtilityOptionList(),UtilityOption()andUtilityOptionArgument()followutility_option_list/utility_option_elem/utility_option_argof PostgreSQL 18'sgram.y.VACUUM,ANALYZEandCLUSTERuse them and accept what PostgreSQL's grammar accepts: any option name, and as value a Boolean word, a non-reserved word, a string (alsoE'…'and$$…$$) or a signed integer or decimal (NumericOnly). A name or word can be a double-quoted identifier, such as"verbose".VACUUM (FOO) tandVACUUM (PARALLEL -1) tparse, and PostgreSQL then reportsunrecognized VACUUM option "foo"orparallel workers for vacuum must be between 0 and 1024. The model still tells them apart:getKind(Class)is null for an unknown name,getValueType()records the value as written, and the typed readers return null for a value of another type (getLongValue()ofPARALLEL 1.5).NonReservedWord. PostgreSQL's reserved keywords are rejected as unquoted names and words (VACUUM (TABLE) t,VACUUM (VERBOSE analyze) t), exceptANALYZEandANALYSEas names (analyze_keyword), as ingram.y.getKindreads"verbose"asVERBOSEand"VERBOSE"as unknown, and the unquotedANALYSEis the optionANALYZE.EXPLAIN (…)is unchanged: it reads its elements throughUtilityOption()and maps them to its releasedExplainStatement.Option, whose closedOptionTypenames and existing value checks still decide what is accepted. On a grid of 1,092 option combinations it accepts and renders exactly whatmasterdoes. MovingExplainStatement.Option, and theReindex.OptionofREINDEX (…), toUtilityOptionwould let them follow the grammar too; that is left for a follow-up because it changes their released APIs.Unparenthesized keywords are options:
VACUUM FULL tholds the optionFULLlikeVACUUM (FULL) t, andisParenthesizedOptions()tells the forms apart, asExplainStatementdoes forEXPLAIN ANALYZE. Consumers read one list for both spellings. The keyword form is rendered in PostgreSQL's required order (FULL FREEZE VERBOSE ANALYZE); options it cannot express are rendered in parentheses.MaintenanceTarget(statement.maintenance) is PostgreSQL'stable_and_columns:[ONLY] table [*] [(column, …)].TableReferenceand theRelationTarget()production ofLOCKandTRUNCATE; PostgreSQL 18'svacuum_relationis arelation_expr, soONLYand*are accepted. Columns areColumns.VACUUMandANALYZEshare it and theMaintenanceTargetList()production.One
Analyzefor both products:Analyzeis extended in place, and the MySQL and PostgreSQL forms are two mutually exclusive shapes of the same statement.ANALYZE NO_WRITE_TO_BINLOG TABLE t1, t2 UPDATE HISTOGRAM ON c WITH 32 BUCKETS AUTO UPDATEANALYZE (VERBOSE, SKIP_LOCKED) ONLY t (a, b), ugetModifier(),isTableKeyword(),getHistogramAction(),getHistogramColumns(),getHistogramBucketCount(),getHistogramUpdateMode(),getHistogramData()getOptions(),isParenthesizedOptions(), targets withONLY,*or columnsgetTargets()(plain tables)getTargets()MaintenanceTargets ingetTargets(), the single source of truth. A MySQL table is a plain target (isPlainTable()).getTable(),getTables(),setTable,setTables,addTablesand the builders stay and are derived from the targets:getTables()is now a read-only snapshot, and the setters create plain targets.requireAnalyzeForm): the modifier, theTABLEkeyword and the histogram clause, which carries the bucket count, the update mode and the JSON data, cannot be combined with options or with targets that useONLY,*or columns, and they require a table. Every feat: parse MySQL CHECKSUM TABLE and histogram update options #2883 rule stays as it is:USING DATAexcludes the bucket count and the update mode, andDROP HISTOGRAMtakes none of them.analyze_keywordisANALYZE | ANALYSE.Analyze.Command(ANALYZE,ANALYSE) keeps the spelling, likeStartTransaction.Command, soANALYSE VERBOSE t (a)round-trips.ANALYSEtakes only the PostgreSQL form;ANALYSE TABLE tis rejected, as in both databases.toString()andStatementDeParsershareappendTo, which renders{ANALYZE | ANALYSE} [modifier] [options] [TABLE] [targets] [histogram], so each form prints as written and a programmaticAnalyzewithout targets printsANALYZE.getOptions(),isParenthesizedOptions(),getTargets(),getCommand(),Analyze.OptionKindandAnalyze.Command;Modifier,HistogramAction,HistogramUpdateModeand all histogram accessors keep their signatures and behaviour.Other statements:
VacuumStatement: options,isParenthesizedOptions(), targets.VACUUM [FULL] [FREEZE] [VERBOSE] [ANALYZE | ANALYSE]accepts the words in that order; as in PostgreSQL they are never table names here.ClusterStatement: options, table and index name. Without a table the index name is discarded, andsetIndexNamerequires a table.CLUSTER [VERBOSE] index ON table(CLUSTER opt_verbose name ON qualified_name). It parses to the same table and index, andClusterStatement.IndexSyntax(USING,ON) keeps the spelling. TheONform takes no option list, so a programmatic statement that has parenthesized options is rendered in theUSINGform.CheckpointStatement. PostgreSQL 18 accepts no options;CHECKPOINT (…)comes in a later release and can be added to this class the same way.AST nodes (fix: give every parsed object a node spanning its source #2870): the three statements extend
ASTNodeAccessImpland get the nodeSingleStatementlinks.UtilityOptionandMaintenanceTargetextendASTNodeAccessImpltoo and are linked to their source range (PARALLEL 2,VERBOSE,ONLY s.t (a, b),u *), and the columns of a target get the node of their name.ASTNodeCoverageTestwalks VACUUM, ANALYZE (both forms and theANALYSEspelling), CLUSTER (withON) and CHECKPOINT statements.Dialects:
Dialect.POSTGRESQLand without a dialect. Other dialects do not change:VACUUM,CLUSTERandCHECKPOINTare not statements there, andANALYZEkeeps the MySQL form.VACUUM,CLUSTER,CHECKPOINTandANALYSEstart a statement only when the next tokens take the PostgreSQL form. Other products' variants such asVACUUM INTO 'backup.db',VACUUM t RETAIN 168 HOURSorCHECKPOINT 10stayUnsupportedStatements. Other dialects never readANALYSEas a statement.Dialect.POSTGRESQL,ANALYZE verbosenow means theVERBOSEoption, as in PostgreSQL. Without a dialect it still analyzes a table namedverboseunless a table name follows (ANALYZE VERBOSE t); other dialects keep the table reading.Grammar:
VACUUMandCLUSTERbecome non-reserved tokens, next to feat: parse MySQL CHECKSUM TABLE and histogram update options #2883'sCHECKSUM. A statement that starts with a plain identifier adds choice conflicts at trailing optional identifiers, as forNOTIFYandREINDEX. Both remain identifiers (KeywordsTest, keyword sweeps). The contextualCLUSTER ON/SET WITHOUT CLUSTERofALTER TABLEand BigQuery'sCLUSTER BYaccept the new token.FREEZEstays a contextual keyword;ANALYZE,CHECKPOINTandVERBOSEwere already non-reserved tokens.FULLafterVACUUMis read with an explicit lookahead, becauseFULLcan now also be a name (reserved keyword usable as an identifier).ANALYSEwas already a non-reserved token (for MySQL'sPROCEDURE ANALYSE()).SingleStatementtakes it as a statement start only throughisPostgreSqlMaintenanceAhead(), soanalysestays an identifier (SELECT analyse FROM analyse) andPROCEDURE ANALYSE()is unchanged.isStatementStartAhead()recognizesVACUUM,CLUSTER,CHECKPOINTandANALYSE, so with unsupported statements enabled they are no longer captured as opaque, and they end a preceding statement.Wiring:
StatementVisitordefaults,StatementVisitorAdapter,StatementDeParser(now also@OverrideandappendToforAnalyze).TablesNamesFinderreports the target tables and theCLUSTERtable, not the columns or the index.vacuum,clusterandcheckpoint. They andanalyzeare inPostgresqlVersion;analyzeis also added toMySqlVersionandMariaDbVersion.VACUUMandCLUSTERreportMODIFIES_SCHEMAandREADS_DATA, likeANALYZE;CHECKPOINTreportsMODIFIES_SESSION, likeALTER SYSTEM CHECKPOINT.Validation
VacuumStatementTest36,PostgreSqlAnalyzeTest42,ClusterStatementTest25,CheckpointStatementTest8,UtilityOptionTest5,MaintenanceValidatorTest4 andMaintenanceNodeTest3.toString(),StatementDeParserand reparse withDialect.POSTGRESQLand without a dialect, plus the AST fields (option kinds, typed values,ONLY/*, columns, index,IndexSyntax,Command).VACUUM (FOO) t,VACUUM (PARALLEL -1) t,VERBOSE maybe,PARALLEL 1.5,(t)), with a nullgetKindor the value type as parsed; double-quoted names and values,$$…$$strings, and the syntax errors (VACUUM (),VACUUM (VERBOSE,) t,VACUUM (TABLE) t,VACUUM (VERBOSE analyze) t,VACUUM ANALYZE FULL t,VACUUM t USING x,CLUSTER t USING,CLUSTER (VERBOSE) i ON t,CLUSTER s.i ON t,CHECKPOINT (FLUSH_UNLOGGED)).ANALYZEforms, including the feat: parse MySQL CHECKSUM TABLE and histogram update options #2883 histogram options (ANALYZE (VERBOSE) t UPDATE HISTOGRAM ON a WITH 8 BUCKETS AUTO UPDATE,ANALYZE t (a) UPDATE HISTOGRAM ON a,ANALYZE UPDATE HISTOGRAM ON a) andANALYSE TABLE t.AUTO UPDATE,MANUAL UPDATEandUSING DATA, unchanged in the MySQL, MariaDB and PostgreSQL dialects and held as plain targets; the existingAnalyzeTestof feat: parse MySQL CHECKSUM TABLE and histogram update options #2883 passes unchanged.SHOWand after an unsupported statement), builders and rendering of programmatic options and of theONform, table discovery, validation capabilities and statement features.vacuum,cluster,checkpoint,freeze,analyse), MySQL'sPROCEDURE ANALYSE(),ALTER TABLE … CLUSTER ON,SET WITHOUT CLUSTER, BigQueryCLUSTER BY, andEXPLAIN (…)through the shared production, including the option names and values it still rejects;KeywordsTestcoversVACUUMandCLUSTER.MaintenanceNodeTest);ASTNodeCoverageTestwalks nine VACUUM, ANALYZE, ANALYSE, CLUSTER and CHECKPOINT statements, the MySQL histogram form among them.ReindexTestandSecurityLabelTestusedVACUUM tas their example of an unsupported statement beforeREINDEXandSECURITY LABEL; they now useLISTEN ch.spotlessApply check jar: 12,565 tests, 12,540 passed, 25 skipped, zero failures/errors. The grammar choice conflict check passes.master(7123d25a1) on a corpus of 188 MySQL 8.4 and 166 PostgreSQL 18 statements other than DDL/DCL, each accepted by the server, with the MySQL or PostgreSQL dialect and without a dialect:Dialect.POSTGRESQLand without a dialect:ANALYZE VERBOSE t (a),ANALYZE (SKIP_LOCKED) t, s,VACUUM (VERBOSE, ANALYZE) t,VACUUM FULL t,VACUUM (PARALLEL 2, INDEX_CLEANUP OFF) t (a),CLUSTER t USING t_pkey,CLUSTER VERBOSEandCHECKPOINT. Each renders identically to the source.ANALYZE TABLE t UPDATE HISTOGRAM ON a WITH 10 BUCKETSandANALYZE NO_WRITE_TO_BINLOG TABLE t, shold their tables astargets[i].reference.tableinstead oftables[i]and gaincommand = ANALYZE;getTables()returns the same tables.master(7123d25a1) on a corpus of 635 MySQL 8.4 and PostgreSQL 18 DDL/DCL statements, each accepted by the server, plus variants, scripts and the keyword sweeps (which usevacuum,clusterandcheckpointas table and column names): 0 regressed, 0 changed.ANALYZE TABLE t1, t2has the same AST change.EXPLAIN (…)compared withmaster(7123d25a1) on 1,092 option combinations (21 names, 26 values, withDialect.POSTGRESQLand without a dialect): identical acceptance and rendering.AI assistance: prepared with Claude Code.