001
002package gudusoft.gsqlparser.pp.stmtformatter;
003
004import gudusoft.gsqlparser.TCustomSqlStatement;
005import gudusoft.gsqlparser.ETokenType;
006import gudusoft.gsqlparser.TGSqlParser;
007import gudusoft.gsqlparser.TSourceToken;
008import gudusoft.gsqlparser.TSourceTokenList;
009import gudusoft.gsqlparser.TStatementList;
010import gudusoft.gsqlparser.pp.mediator.MediatorFactory;
011import gudusoft.gsqlparser.pp.output.OutputConfig;
012import gudusoft.gsqlparser.pp.output.OutputConfigFactory;
013import gudusoft.gsqlparser.pp.para.GFmtOpt;
014import gudusoft.gsqlparser.pp.para.styleenums.TCompactMode;
015import gudusoft.gsqlparser.pp.print.IPrinter;
016import gudusoft.gsqlparser.pp.print.PrinterFactory;
017import gudusoft.gsqlparser.pp.processor.ProcessorFactory;
018import gudusoft.gsqlparser.pp.stmtformatter.builder.AbstractStmtFormatterBuilder;
019import gudusoft.gsqlparser.pp.stmtformatter.builder.comm.AllStmtsFormatterBuilder;
020import gudusoft.gsqlparser.pp.stmtformatter.builder.comm.AlterTableStmtFormatterBuilder;
021import gudusoft.gsqlparser.pp.stmtformatter.builder.comm.CommonStmtFormatterBuilder;
022import gudusoft.gsqlparser.pp.stmtformatter.builder.comm.CompactModeStmtFormatterBuilder;
023import gudusoft.gsqlparser.pp.stmtformatter.builder.comm.CreateTableStmtFormatterBuilder;
024import gudusoft.gsqlparser.pp.stmtformatter.builder.comm.CreateViewStmtFormatterBuilder;
025import gudusoft.gsqlparser.pp.stmtformatter.builder.comm.DeclareStmtFormatterBuilder;
026import gudusoft.gsqlparser.pp.stmtformatter.builder.comm.DeleteStmtFormatterBuilder;
027import gudusoft.gsqlparser.pp.stmtformatter.builder.comm.ExecuteStmtFormatterBuilder;
028import gudusoft.gsqlparser.pp.stmtformatter.builder.comm.GoStmtFormatterBuilder;
029import gudusoft.gsqlparser.pp.stmtformatter.builder.comm.IfStmtFormatterBuilder;
030import gudusoft.gsqlparser.pp.stmtformatter.builder.comm.InsertStmtFormatterBuilder;
031import gudusoft.gsqlparser.pp.stmtformatter.builder.comm.MergeStmtFormatterBuilder;
032import gudusoft.gsqlparser.pp.stmtformatter.builder.comm.PlsqlBlockStmtFormatterBuilder;
033import gudusoft.gsqlparser.pp.stmtformatter.builder.comm.PlsqlIfStmtFormatterBuilder;
034import gudusoft.gsqlparser.pp.stmtformatter.builder.comm.PlsqlStmtFormatterBuilder;
035import gudusoft.gsqlparser.pp.stmtformatter.builder.comm.ReturnStmtFormatterBuilder;
036import gudusoft.gsqlparser.pp.stmtformatter.builder.comm.SelectStmtFormatterBuilder;
037import gudusoft.gsqlparser.pp.stmtformatter.builder.comm.SetStmtFormatterBuilder;
038import gudusoft.gsqlparser.pp.stmtformatter.builder.comm.UpdateStmtFormatterBuilder;
039import gudusoft.gsqlparser.pp.stmtformatter.type.AbstractStmtFormatter;
040import gudusoft.gsqlparser.pp.stmtformatter.type.comm.AllStmtsFormatter;
041import gudusoft.gsqlparser.pp.stmtformatter.type.comm.AlterTableStmtFormatter;
042import gudusoft.gsqlparser.pp.stmtformatter.type.comm.CommonStmtFormatter;
043import gudusoft.gsqlparser.pp.stmtformatter.type.comm.CompactModeStmtFormatter;
044import gudusoft.gsqlparser.pp.stmtformatter.type.comm.CreateTableStmtFormatter;
045import gudusoft.gsqlparser.pp.stmtformatter.type.comm.CreateViewStmtFormatter;
046import gudusoft.gsqlparser.pp.stmtformatter.type.comm.DeclareStmtFormatter;
047import gudusoft.gsqlparser.pp.stmtformatter.type.comm.DeleteStmtFormatter;
048import gudusoft.gsqlparser.pp.stmtformatter.type.comm.ExecuteStmtFormatter;
049import gudusoft.gsqlparser.pp.stmtformatter.type.comm.GoStmtFormatter;
050import gudusoft.gsqlparser.pp.stmtformatter.type.comm.IfStmtFormatter;
051import gudusoft.gsqlparser.pp.stmtformatter.type.comm.InsertStmtFormatter;
052import gudusoft.gsqlparser.pp.stmtformatter.type.comm.MergeStmtFormatter;
053import gudusoft.gsqlparser.pp.stmtformatter.type.comm.PlsqlBlockStmtFormatter;
054import gudusoft.gsqlparser.pp.stmtformatter.type.comm.PlsqlIfStmtFormatter;
055import gudusoft.gsqlparser.pp.stmtformatter.type.comm.PlsqlStmtFormatter;
056import gudusoft.gsqlparser.pp.stmtformatter.type.comm.ReturnStmtFormatter;
057import gudusoft.gsqlparser.pp.stmtformatter.type.comm.SelectStmtFormatter;
058import gudusoft.gsqlparser.pp.stmtformatter.type.comm.SetStmtFormatter;
059import gudusoft.gsqlparser.pp.stmtformatter.type.comm.UpdateStmtFormatter;
060import gudusoft.gsqlparser.pp.utils.SourceTokenOperator;
061import gudusoft.gsqlparser.stmt.TAlterTableStatement;
062import gudusoft.gsqlparser.stmt.TCommonBlock;
063import gudusoft.gsqlparser.stmt.TCreateTableSqlStatement;
064import gudusoft.gsqlparser.stmt.TCreateViewSqlStatement;
065import gudusoft.gsqlparser.stmt.TDeleteSqlStatement;
066import gudusoft.gsqlparser.stmt.TIfStmt;
067import gudusoft.gsqlparser.stmt.TInsertSqlStatement;
068import gudusoft.gsqlparser.stmt.TMergeSqlStatement;
069import gudusoft.gsqlparser.stmt.TSelectSqlStatement;
070import gudusoft.gsqlparser.stmt.TStoredProcedureSqlStatement;
071import gudusoft.gsqlparser.stmt.TUpdateSqlStatement;
072import gudusoft.gsqlparser.stmt.mssql.TMssqlBlock;
073import gudusoft.gsqlparser.stmt.mssql.TMssqlDeclare;
074import gudusoft.gsqlparser.stmt.mssql.TMssqlExecute;
075import gudusoft.gsqlparser.stmt.mssql.TMssqlGo;
076import gudusoft.gsqlparser.stmt.mssql.TMssqlIfElse;
077import gudusoft.gsqlparser.stmt.mssql.TMssqlReturn;
078import gudusoft.gsqlparser.stmt.mssql.TMssqlSet;
079import gudusoft.gsqlparser.pp2.Pp2FormatOptions;
080import gudusoft.gsqlparser.pp2.Pp2FormatResult;
081import gudusoft.gsqlparser.pp2.engine.Pp2Engine;
082
083import java.io.ByteArrayOutputStream;
084import java.io.OutputStream;
085import java.util.ArrayList;
086import java.util.List;
087import java.util.Map;
088import java.util.concurrent.ConcurrentHashMap;
089
090public class FormatterFactory
091{
092
093        /**
094         * all formatters
095         */
096        private volatile static Map<String, AbstractStmtFormatter> formatter = new ConcurrentHashMap<String, AbstractStmtFormatter>( );
097
098        private static Object object = new Object( );
099
100        private static OutputConfig outputConfig;
101
102        /**
103         * create select statment formatter
104         * 
105         * @param opt
106         *            options
107         * @return instance
108         */
109        public static SelectStmtFormatter createSelectStmtFormatter( GFmtOpt opt )
110        {
111                return createFormatter( opt,
112                                SelectStmtFormatter.class,
113                                new IFormatterBuilderCreator<SelectStmtFormatter>( ) {
114
115                                        public AbstractStmtFormatterBuilder<SelectStmtFormatter> create( )
116                                        {
117                                                return new SelectStmtFormatterBuilder( );
118                                        }
119                                } );
120        }
121
122        public static InsertStmtFormatter createInsertStmtFormatter( GFmtOpt opt )
123        {
124                return createFormatter( opt,
125                                InsertStmtFormatter.class,
126                                new IFormatterBuilderCreator<InsertStmtFormatter>( ) {
127
128                                        public AbstractStmtFormatterBuilder<InsertStmtFormatter> create( )
129                                        {
130                                                return new InsertStmtFormatterBuilder( );
131                                        }
132                                } );
133        }
134
135        public static DeleteStmtFormatter createDeleteStmtFormatter( GFmtOpt opt )
136        {
137                return createFormatter( opt,
138                                DeleteStmtFormatter.class,
139                                new IFormatterBuilderCreator<DeleteStmtFormatter>( ) {
140
141                                        public AbstractStmtFormatterBuilder<DeleteStmtFormatter> create( )
142                                        {
143                                                return new DeleteStmtFormatterBuilder( );
144                                        }
145                                } );
146        }
147
148        public static UpdateStmtFormatter createUpdateStmtFormatter( GFmtOpt opt )
149        {
150                return createFormatter( opt,
151                                UpdateStmtFormatter.class,
152                                new IFormatterBuilderCreator<UpdateStmtFormatter>( ) {
153
154                                        public AbstractStmtFormatterBuilder<UpdateStmtFormatter> create( )
155                                        {
156                                                return new UpdateStmtFormatterBuilder( );
157                                        }
158                                } );
159        }
160
161        public static CreateTableStmtFormatter createCreateTableStmtFormatter(
162                        GFmtOpt opt )
163        {
164                return createFormatter( opt,
165                                CreateTableStmtFormatter.class,
166                                new IFormatterBuilderCreator<CreateTableStmtFormatter>( ) {
167
168                                        public AbstractStmtFormatterBuilder<CreateTableStmtFormatter> create( )
169                                        {
170                                                return new CreateTableStmtFormatterBuilder( );
171                                        }
172                                } );
173        }
174
175        public static DeclareStmtFormatter createDeclareStmtFormatter( GFmtOpt opt )
176        {
177                return createFormatter( opt,
178                                DeclareStmtFormatter.class,
179                                new IFormatterBuilderCreator<DeclareStmtFormatter>( ) {
180
181                                        public AbstractStmtFormatterBuilder<DeclareStmtFormatter> create( )
182                                        {
183                                                return new DeclareStmtFormatterBuilder( );
184                                        }
185                                } );
186        }
187
188        public static ExecuteStmtFormatter createExecuteStmtFormatter( GFmtOpt opt )
189        {
190                return createFormatter( opt,
191                                ExecuteStmtFormatter.class,
192                                new IFormatterBuilderCreator<ExecuteStmtFormatter>( ) {
193
194                                        public AbstractStmtFormatterBuilder<ExecuteStmtFormatter> create( )
195                                        {
196                                                return new ExecuteStmtFormatterBuilder( );
197                                        }
198                                } );
199        }
200
201        public static SetStmtFormatter createSetStmtFormatter( GFmtOpt opt )
202        {
203                return createFormatter( opt,
204                                SetStmtFormatter.class,
205                                new IFormatterBuilderCreator<SetStmtFormatter>( ) {
206
207                                        public AbstractStmtFormatterBuilder<SetStmtFormatter> create( )
208                                        {
209                                                return new SetStmtFormatterBuilder( );
210                                        }
211                                } );
212        }
213
214        public static IfStmtFormatter createIfStmtFormatter( GFmtOpt opt )
215        {
216                return createFormatter( opt,
217                                IfStmtFormatter.class,
218                                new IFormatterBuilderCreator<IfStmtFormatter>( ) {
219
220                                        public AbstractStmtFormatterBuilder<IfStmtFormatter> create( )
221                                        {
222                                                return new IfStmtFormatterBuilder( );
223                                        }
224                                } );
225        }
226
227        public static PlsqlIfStmtFormatter createPlsqlIfStmtFormatter( GFmtOpt opt )
228        {
229                return createFormatter( opt,
230                                PlsqlIfStmtFormatter.class,
231                                new IFormatterBuilderCreator<PlsqlIfStmtFormatter>( ) {
232
233                                        public AbstractStmtFormatterBuilder<PlsqlIfStmtFormatter> create( )
234                                        {
235                                                return new PlsqlIfStmtFormatterBuilder( );
236                                        }
237                                } );
238        }
239
240        public static PlsqlStmtFormatter createPlsqlStmtFormatter( GFmtOpt opt )
241        {
242                return createFormatter( opt,
243                                PlsqlStmtFormatter.class,
244                                new IFormatterBuilderCreator<PlsqlStmtFormatter>( ) {
245
246                                        public AbstractStmtFormatterBuilder<PlsqlStmtFormatter> create( )
247                                        {
248                                                return new PlsqlStmtFormatterBuilder( );
249                                        }
250                                } );
251        }
252
253        public static GoStmtFormatter createGoStmtFormatter( GFmtOpt opt )
254        {
255                return createFormatter( opt,
256                                GoStmtFormatter.class,
257                                new IFormatterBuilderCreator<GoStmtFormatter>( ) {
258
259                                        public AbstractStmtFormatterBuilder<GoStmtFormatter> create( )
260                                        {
261                                                return new GoStmtFormatterBuilder( );
262                                        }
263                                } );
264        }
265
266        public static CompactModeStmtFormatter createCompactModeStmtFormatter(
267                        GFmtOpt opt )
268        {
269                return createFormatter( opt,
270                                CompactModeStmtFormatter.class,
271                                new IFormatterBuilderCreator<CompactModeStmtFormatter>( ) {
272
273                                        public AbstractStmtFormatterBuilder<CompactModeStmtFormatter> create( )
274                                        {
275                                                return new CompactModeStmtFormatterBuilder( );
276                                        }
277                                } );
278        }
279
280        public static ReturnStmtFormatter createReturnStmtFormatter( GFmtOpt opt )
281        {
282                return createFormatter( opt,
283                                ReturnStmtFormatter.class,
284                                new IFormatterBuilderCreator<ReturnStmtFormatter>( ) {
285
286                                        public AbstractStmtFormatterBuilder<ReturnStmtFormatter> create( )
287                                        {
288                                                return new ReturnStmtFormatterBuilder( );
289                                        }
290                                } );
291        }
292
293        public static CreateViewStmtFormatter createCreateViewStmtFormatter(
294                        GFmtOpt opt )
295        {
296                return createFormatter( opt,
297                                CreateViewStmtFormatter.class,
298                                new IFormatterBuilderCreator<CreateViewStmtFormatter>( ) {
299
300                                        public AbstractStmtFormatterBuilder<CreateViewStmtFormatter> create( )
301                                        {
302                                                return new CreateViewStmtFormatterBuilder( );
303                                        }
304                                } );
305        }
306
307        public static gudusoft.gsqlparser.pp.stmtformatter.type.comm.CreateMaterializedViewStmtFormatter createCreateMaterializedViewStmtFormatter(
308                        GFmtOpt opt )
309        {
310                return createFormatter( opt,
311                                gudusoft.gsqlparser.pp.stmtformatter.type.comm.CreateMaterializedViewStmtFormatter.class,
312                                new IFormatterBuilderCreator<gudusoft.gsqlparser.pp.stmtformatter.type.comm.CreateMaterializedViewStmtFormatter>( ) {
313
314                                        public AbstractStmtFormatterBuilder<gudusoft.gsqlparser.pp.stmtformatter.type.comm.CreateMaterializedViewStmtFormatter> create( )
315                                        {
316                                                return new gudusoft.gsqlparser.pp.stmtformatter.builder.comm.CreateMaterializedViewStmtFormatterBuilder( );
317                                        }
318                                } );
319        }
320
321        public static AlterTableStmtFormatter createAlterTableStatement( GFmtOpt opt )
322        {
323                return createFormatter( opt,
324                                AlterTableStmtFormatter.class,
325                                new IFormatterBuilderCreator<AlterTableStmtFormatter>( ) {
326
327                                        public AbstractStmtFormatterBuilder<AlterTableStmtFormatter> create( )
328                                        {
329                                                return new AlterTableStmtFormatterBuilder( );
330                                        }
331                                } );
332        }
333
334        /**
335         * the callback interface to achieve the formatter builder
336         * 
337         * @author zhoujun
338         * 
339         */
340        public interface IFormatterBuilderCreator<E extends AbstractStmtFormatter>
341        {
342
343                AbstractStmtFormatterBuilder<E> create( );
344        }
345
346        /**
347         * create the formatter
348         * 
349         * @param <E>
350         * @param opt
351         * @param clazz
352         * @param creater
353         * @return
354         */
355        public static <E extends AbstractStmtFormatter> E createFormatter(
356                        GFmtOpt opt, Class<E> clazz, IFormatterBuilderCreator<E> creater )
357        {
358                String id = opt.sessionId + clazz.getName( );
359                if ( !formatter.containsKey( id ) )
360                {
361                        synchronized ( FormatterFactory.class )
362                        {
363                                if ( !formatter.containsKey( id ) )
364                                {
365                                        AbstractStmtFormatterBuilder builder = creater.create( );
366                                        builder.setOption( opt );
367                                        formatter.put( id, builder.build( ) );
368                                }
369                        }
370                }
371                return (E) formatter.get( id );
372        }
373
374        public static void processStatement( GFmtOpt option, TCustomSqlStatement sql )
375        {
376                if ( option.compactMode == TCompactMode.Cpmugly )
377                {
378                        FormatterFactory.createCompactModeStmtFormatter( option )
379                                        .format( sql );
380                        return;
381                }
382
383                if ( isNotNeedFormat( sql ) )
384                {
385                        return;
386                }
387                if ( sql instanceof TSelectSqlStatement )
388                {
389                        FormatterFactory.createSelectStmtFormatter( option )
390                                        .format( (TSelectSqlStatement) sql );
391                }
392                else if ( sql instanceof TInsertSqlStatement )
393                {
394                        FormatterFactory.createInsertStmtFormatter( option )
395                                        .format( (TInsertSqlStatement) sql );
396                }
397                else if ( sql instanceof TDeleteSqlStatement )
398                {
399                        FormatterFactory.createDeleteStmtFormatter( option )
400                                        .format( (TDeleteSqlStatement) sql );
401                }
402                else if ( sql instanceof TUpdateSqlStatement )
403                {
404                        FormatterFactory.createUpdateStmtFormatter( option )
405                                        .format( (TUpdateSqlStatement) sql );
406                }
407                else if ( sql instanceof TCreateTableSqlStatement )
408                {
409                        FormatterFactory.createCreateTableStmtFormatter( option )
410                                        .format( (TCreateTableSqlStatement) sql );
411                }
412                else if ( sql instanceof TMssqlDeclare )
413                {
414                        FormatterFactory.createDeclareStmtFormatter( option )
415                                        .format( (TMssqlDeclare) sql );
416                }
417                else if ( sql instanceof TMssqlExecute )
418                {
419                        FormatterFactory.createExecuteStmtFormatter( option )
420                                        .format( (TMssqlExecute) sql );
421                }
422                else if ( sql instanceof TStoredProcedureSqlStatement )
423                {
424                        FormatterFactory.createPlsqlStmtFormatter( option )
425                                        .format( (TStoredProcedureSqlStatement) sql );
426                }
427                else if ( sql instanceof TMssqlSet )
428                {
429                        FormatterFactory.createSetStmtFormatter( option )
430                                        .format( (TMssqlSet) sql );
431                }
432                else if ( sql instanceof TMssqlIfElse )
433                {
434                        FormatterFactory.createIfStmtFormatter( option )
435                                        .format( (TMssqlIfElse) sql );
436                }
437                else if ( sql instanceof TMssqlGo )
438                {
439                        FormatterFactory.createGoStmtFormatter( option )
440                                        .format( (TMssqlGo) sql );
441                }
442                else if ( sql instanceof TMssqlReturn )
443                {
444                        FormatterFactory.createReturnStmtFormatter( option )
445                                        .format( (TMssqlReturn) sql );
446                }
447                else if ( sql instanceof TCreateViewSqlStatement )
448                {
449                        FormatterFactory.createCreateViewStmtFormatter( option )
450                                        .format( (TCreateViewSqlStatement) sql );
451                }
452                else if ( sql instanceof gudusoft.gsqlparser.stmt.TCreateMaterializedSqlStatement )
453                {
454                        FormatterFactory.createCreateMaterializedViewStmtFormatter( option )
455                                        .format( (gudusoft.gsqlparser.stmt.TCreateMaterializedSqlStatement) sql );
456                }
457                else if ( sql instanceof TAlterTableStatement )
458                {
459                        FormatterFactory.createAlterTableStatement( option )
460                                        .format( (TAlterTableStatement) sql );
461                }
462                else if ( sql instanceof TMergeSqlStatement )
463                {
464                        FormatterFactory.createMergeSqlStatement( option )
465                                        .format( (TMergeSqlStatement) sql );
466                }
467                else if ( sql instanceof TIfStmt )
468                {
469                        FormatterFactory.createPlsqlIfStmtFormatter( option )
470                                        .format( (TIfStmt) sql );
471                }
472                else
473                {
474                        FormatterFactory.createCommonStatement( option ).format( sql );
475                }
476        }
477
478        private static AbstractStmtFormatter<TCommonBlock> createPlsqlBlockStmtFormatter(
479                        GFmtOpt opt )
480        {
481                return createFormatter( opt,
482                                PlsqlBlockStmtFormatter.class,
483                                new IFormatterBuilderCreator<PlsqlBlockStmtFormatter>( ) {
484
485                                        public AbstractStmtFormatterBuilder<PlsqlBlockStmtFormatter> create( )
486                                        {
487                                                return new PlsqlBlockStmtFormatterBuilder( );
488                                        }
489                                } );
490        }
491
492        private static MergeStmtFormatter createMergeSqlStatement( GFmtOpt opt )
493        {
494                return createFormatter( opt,
495                                MergeStmtFormatter.class,
496                                new IFormatterBuilderCreator<MergeStmtFormatter>( ) {
497
498                                        public AbstractStmtFormatterBuilder<MergeStmtFormatter> create( )
499                                        {
500                                                return new MergeStmtFormatterBuilder( );
501                                        }
502                                } );
503        }
504
505        private static CommonStmtFormatter createCommonStatement( GFmtOpt opt )
506        {
507                return createFormatter( opt,
508                                CommonStmtFormatter.class,
509                                new IFormatterBuilderCreator<CommonStmtFormatter>( ) {
510
511                                        public AbstractStmtFormatterBuilder<CommonStmtFormatter> create( )
512                                        {
513                                                return new CommonStmtFormatterBuilder( );
514                                        }
515                                } );
516        }
517
518        public static boolean isNotNeedFormat( TCustomSqlStatement sql )
519        {
520                if ( sql == null )
521                {
522                        // the null statement needn't formatting.
523                        return true;
524                }
525                if ( sql.getStartToken( ) != null )
526                {
527                        TSourceToken t = sql.getStartToken( );
528                        return isNotNeedFormat( t );
529                }
530                return false;
531        }
532
533        public static boolean isNotNeedFormat( TSourceToken t )
534        {
535                if ( t == null )
536                {
537                        return false;
538                }
539                TSourceTokenList bts = t.getTokensBefore( );
540                if ( bts.size( ) > 0 )
541                {
542                        for ( int i = 0; i < bts.size( ); i++ )
543                        {
544                                if ( SourceTokenOperator.createNoFormatFlagToken( )
545                                                .equals( bts.get( i ) ) )
546                                {
547                                        return true;
548                                }
549                        }
550                }
551                return false;
552        }
553
554        public static void processBlockStmt( GFmtOpt opt, TMssqlBlock stmt,
555                        TSourceToken ifToken )
556        {
557                TSourceToken startToken = stmt.getStartToken( );
558                TSourceToken endToken = stmt.getEndToken( );
559                if ( startToken == null || endToken == null )
560                {
561                        return;
562                }
563                int curBeginIndent = SourceTokenOperator.curColumnNumberVT( ifToken );
564                if ( opt.beStyleBlockLeftBEOnNewline )
565                {
566                        curBeginIndent += opt.beStyleBlockLeftBEIndentSize;
567                        // process the begin token
568                        SourceTokenOperator.addBefore( opt,
569                                        startToken,
570                                        SourceTokenOperator.createReturnSourceToken( ) );
571                        SourceTokenOperator.addBefore( opt,
572                                        startToken,
573                                        SourceTokenOperator.createWhitespaceSourceToken( curBeginIndent ) );
574                }
575                // process the end token
576                int curEndIndent = SourceTokenOperator.curColumnNumberVT( ifToken )
577                                + ( opt.beStyleBlockLeftBEOnNewline ? opt.beStyleBlockLeftBEIndentSize
578                                                : opt.beStyleBlockRightBEIndentSize );
579                SourceTokenOperator.addBefore( opt,
580                                endToken,
581                                SourceTokenOperator.createReturnSourceToken( ) );
582                SourceTokenOperator.addBefore( opt,
583                                endToken,
584                                SourceTokenOperator.createWhitespaceSourceToken( curEndIndent ) );
585
586                TStatementList list = stmt.getBodyStatements( );
587
588                // first, process the indent for the first statement
589                if ( list != null && list.size( ) > 0 )
590                {
591                        int curBlockIndent = curEndIndent + opt.beStyleBlockIndentSize;
592                        TCustomSqlStatement bstmt = list.get( 0 );
593                        TSourceToken bstartToken = bstmt.getStartToken( );
594                        if ( bstartToken != null )
595                        {
596                                SourceTokenOperator.addBefore( opt,
597                                                bstartToken,
598                                                SourceTokenOperator.createReturnSourceToken( ) );
599                                SourceTokenOperator.addBefore( opt,
600                                                bstartToken,
601                                                SourceTokenOperator.createWhitespaceSourceToken( curBlockIndent ) );
602                        }
603                }
604                // second, process all the empty lines between the statements
605                AllStmtsFormatter.processEmptyLine( list, opt, true );
606
607                // third, format the statements in the begin-end block
608                if ( list != null && list.size( ) > 0 )
609                {
610                        // int curBlockIndent = curEndIndent + opt.beStyleBlockIndentSize;
611                        for ( int i = 0; i < list.size( ); i++ )
612                        {
613                                TCustomSqlStatement bstmt = list.get( i );
614                                // TSourceToken bstartToken = bstmt.getStartToken();
615                                // if (bstartToken != null) {
616                                // SourceTokenOperator.addBefore(opt, bstartToken,
617                                // SourceTokenOperator.createReturnSourceToken());
618                                // if (i != 0 && opt.insertBlankLineInBatchSqls) {
619                                // TCustomSqlStatement preBstmt = list.get(i - 1);
620                                // TSourceToken preBEndToken = preBstmt.getEndToken();
621                                // if (preBEndToken != null) {
622                                // SourceTokenOperator.addAfter(opt, preBstmt.getEndToken(),
623                                // SourceTokenOperator.createReturnSourceToken());
624                                // }
625                                // }
626                                // SourceTokenOperator.addBefore(opt, bstartToken,
627                                // SourceTokenOperator.createWhitespaceSourceToken(curBlockIndent));
628                                //
629                                // }
630                                FormatterFactory.processStatement( opt, bstmt );
631
632                        }
633                }
634
635        }
636
637        /**
638         * A statement that starts on the line of the previous statement's
639         * terminator ({@code SELECT x FROM t; SELECT y ...}) gets a line break
640         * first. Every column the processors compute for it is measured from the
641         * last line break, so without one the whole statement was laid out as if
642         * it started at the column after the terminator.
643         */
644        private static void startOnNewLine( GFmtOpt opt, TCustomSqlStatement prev, TCustomSqlStatement sql )
645        {
646                TSourceToken start = sql.getStartToken( );
647                TSourceToken prevEnd = prev.getEndToken( );
648                if ( start == null || prevEnd == null || start.container == null
649                                || start.container != prevEnd.container || prevEnd.posinlist >= start.posinlist
650                                || start.lineNo <= 0 || prevEnd.lineNo <= 0 )
651                {
652                        return;
653                }
654                // the original line numbers: the whitespace pre-pass has already rewritten the tokens between
655                if ( start.lineNo != prevEnd.lineNo )
656                {
657                        return;
658                }
659                TSourceTokenList before = start.getTokensBefore( );
660                for ( int i = 0; before != null && i < before.size( ); i++ )
661                {
662                        if ( before.get( i ) == SourceTokenOperator.createNoFormatFlagToken( ) )
663                        {
664                                return; // a no-format zone is reproduced verbatim
665                        }
666                }
667                SourceTokenOperator.removeWhitespaceAndReturnFromEnd( opt, start.container, start.posinlist );
668                SourceTokenOperator.addBefore( opt, start, SourceTokenOperator.createStatementBreakToken( ) );
669        }
670
671        public static String pp( TGSqlParser parser, GFmtOpt option )
672        {
673                if (option.removeComment) {
674                        parser = SqlFormatter.preHandleRemoveComment(parser);
675                }
676                OutputStream o = new ByteArrayOutputStream( );
677                IPrinter printer = PrinterFactory.createTextPrinter( o );
678
679                FormatterFactory.createAllStmtsFormatter( option )
680                                .beforeFormat( parser.sqlstatements );
681
682                for ( int i = 0; i < parser.sqlstatements.size( ); i++ )
683                {
684                        TCustomSqlStatement sql = parser.sqlstatements.get( i );
685                        if ( i > 0 )
686                        {
687                                startOnNewLine( option, parser.sqlstatements.get( i - 1 ), sql );
688                        }
689                        processStatement( option, sql );
690                }
691                if ( parser.sqlstatements != null && parser.sqlstatements.size( ) > 0 )
692                {
693                        FormatterFactory.createAllStmtsFormatter( option )
694                                        .doFormat( parser.sqlstatements );
695                        FormatterFactory.createAllStmtsFormatter( option )
696                                        .afterFormat( parser.sqlstatements );
697
698                        if ( outputConfig == null )
699                        {
700                                outputConfig = OutputConfigFactory.getOutputConfig( option,
701                                                parser.getDbVendor( ) );
702                        }
703
704                        printer.setOutputConfig( outputConfig );
705                        printer.print( parser.sqlstatements.get( 0 ).getStartToken( ).container );
706                }
707
708                clearAllObject( option.sessionId );
709                return o.toString( );
710
711        }
712
713        /**
714         * Fault-tolerant formatter entry point (pp2). Unlike {@link #pp(TGSqlParser, GFmtOpt)},
715         * this does <b>not</b> require {@code parser.parse()} to have returned 0: it
716         * re-tokenizes {@code parser.sqltext} internally, splits the script into
717         * statement regions, formats each region independently, and recovers
718         * gracefully from malformed input. It never throws for non-null inputs and
719         * preserves every solid input token.
720         *
721         * <p>This is the single additive pp2 bridge (plan ยง4.1/S17). It does not
722         * change the behavior of {@link #pp(TGSqlParser, GFmtOpt)} or any other
723         * existing method. The heavy lifting lives in
724         * {@code gudusoft.gsqlparser.pp2.engine.Pp2Engine}.
725         *
726         * @param parser carries the SQL text ({@code parser.sqltext}) and dialect
727         *               ({@code parser.getDbVendor()}); need not be parsed first
728         * @param opts   pp2 formatting options; must not be null
729         * @return a structured {@link Pp2FormatResult} with per-region renderer
730         *         choice, status, and diagnostics; never null
731         * @throws NullPointerException if {@code parser} or {@code opts} is null
732         */
733        public static Pp2FormatResult pp2( TGSqlParser parser, Pp2FormatOptions opts )
734        {
735                if ( parser == null ) throw new NullPointerException( "parser" );
736                if ( opts == null ) throw new NullPointerException( "opts" );
737                String sql = parser.sqltext == null ? "" : parser.sqltext;
738                return new Pp2Engine( ).format( sql, parser.getDbVendor( ), opts );
739        }
740
741        /**
742         * Convenience overload mirroring the {@link #pp(TGSqlParser, GFmtOpt)}
743         * signature: returns the formatted text directly. The caller's
744         * {@link GFmtOpt} is copied into a {@link Pp2FormatOptions} via
745         * {@link Pp2FormatOptions#from(GFmtOpt)} so casing/comma/indent options
746         * carry over (giving byte-parity with {@code pp()} on parseable input).
747         *
748         * @param parser carries the SQL text and dialect; need not be parsed first
749         * @param opt    existing formatter options; must not be null
750         * @return the formatted SQL text; never null
751         * @throws NullPointerException if {@code parser} or {@code opt} is null
752         */
753        public static String pp2( TGSqlParser parser, GFmtOpt opt )
754        {
755                if ( parser == null ) throw new NullPointerException( "parser" );
756                if ( opt == null ) throw new NullPointerException( "opt" );
757                return pp2( parser, Pp2FormatOptions.from( opt ) ).getText( );
758        }
759
760        public static OutputConfig getOutputConfig( )
761        {
762                return outputConfig;
763        }
764
765        public static void setOutputConfig( OutputConfig outputConfig )
766        {
767                FormatterFactory.outputConfig = outputConfig;
768        }
769
770        public static AllStmtsFormatter createAllStmtsFormatter( GFmtOpt option )
771        {
772                return AllStmtsFormatterBuilder.create( option );
773        }
774
775        public static void clearAllObject( String sessionId )
776        {
777                FormatterFactory.clear( sessionId );
778                ProcessorFactory.clear( sessionId );
779                MediatorFactory.clear( sessionId );
780        }
781
782        public static void clear( String sessionId )
783        {
784                synchronized ( object )
785                {
786                        List<String> removedKeys = new ArrayList<String>( );
787                        for ( String key : formatter.keySet( ) )
788                        {
789                                if ( key.startsWith( sessionId ) )
790                                {
791                                        removedKeys.add( key );
792                                }
793                        }
794                        for ( String key : removedKeys )
795                        {
796                                formatter.remove( key );
797                        }
798                }
799        }
800}