001    /*
002     * Copyright (c) 2009 The openGion Project.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *     http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
013     * either express or implied. See the License for the specific language
014     * governing permissions and limitations under the License.
015     */
016    package org.opengion.plugin.table;
017    
018    import java.io.File;
019    import java.io.PrintWriter;
020    import java.util.Locale;
021    import java.util.Map;
022    
023    import org.opengion.fukurou.db.DBUtil;
024    import org.opengion.fukurou.db.Transaction;                     // 5.5.2.6 (2012/05/25)
025    import org.opengion.fukurou.util.ErrorMessage;
026    import org.opengion.fukurou.util.FileUtil;
027    import org.opengion.fukurou.util.FixLengthData;
028    import org.opengion.fukurou.util.StringUtil;
029    import org.opengion.hayabusa.common.HybsSystem;
030    import org.opengion.hayabusa.common.HybsSystemException;
031    import org.opengion.hayabusa.db.AbstractTableFilter;
032    import org.opengion.hayabusa.db.DBTableModel;
033    
034    /**
035     * TableFilter_TABLE は、TableFilter インターフェースを継承した、DBTableModel 処?の
036     * 実?ラスです?
037     *
038     * ここでは、テーブル?の検索結果より、GF05 の??ブルカラ?義??ブルから
039     * ?な??を取得し、テーブル作?スクリプトを作?します?
040     * 出力ファイルは、テーブル名?S.sql" と?命名規則で作?します?
041     * 検索では?SYSTEM_ID,TBLSYU,TABLE_NAME,NAME_JA,TABLESPACE_NAME,INITIAL_EXTENT,NEXT_EXTENT,COMMENTS)
042     * の?を取得する?があります?
043     *
044     * パラメータは、tableFilterタグの keys, vals にそれぞれ記述するか?BODY 部にCSS形式で記述します?
045     * 【パラメータ?
046     *  {
047     *       DIR : {@BASE_DIR}/sql/install/01_TABLE ;    出力ファイルの基準フォル???)
048     *       XML : false ;                                    XML出力を行うかど?[true/false]を指定しま?初期値:false)?
049     *  }
050     *
051     * @og.formSample
052     * ●形式?
053     *      select SYSTEM_ID,TBLSYU,TABLE_NAME,NAME_JA,TABLESPACE_NAME,INITIAL_EXTENT,NEXT_EXTENT,COMMENTS from GF02
054     * 
055     *      ?<og:tableFilter classId="TABLE" keys="DIR,XML" vals='"{@BASE_DIR}/sql/install/01_TABLE,"' />
056     *
057     *      ② <og:tableFilter classId="TABLE" >
058     *               {
059     *                   DIR : {@BASE_DIR}/sql/install/01_TABLE ;
060     *                   XML : false ;
061     *               }
062     *         </og:tableFilter>
063     *
064     * @og.rev 4.0.0.0 (2005/08/31) 新規作?
065     * @og.rev 5.6.6.0 (2013/07/05) keys の整合?チェ?を追?
066     *
067     * @version  0.9.0  2000/10/17
068     * @author   Kazuhiko Hasegawa
069     * @since    JDK1.1,
070     */
071    public class TableFilter_TABLE extends AbstractTableFilter {
072            //* こ?プログラ??VERSION??を設定します?       {@value} */
073            private static final String VERSION = "5.6.6.2 (2013/07/19)" ;
074    
075            /**
076             * keys の整合?チェ?を行うための初期設定を行います?
077             *
078             * @og.rev 5.6.6.1 (2013/07/12) keys の整合?チェ?対?
079             *
080             * @param       keysMap keys の整合?チェ?を行うための Map
081             */
082            @Override
083            protected void init( final Map<String,String> keysMap ) {
084                    keysMap.put( "DIR"      , "出力ファイルの基準フォル???)"                                                );
085                    keysMap.put( "XML"      , "XML出力を行うかど?[true/false]を指?初期値:false)"      );
086            }
087    
088            private static final String[] DBKEY = {"SYSTEM_ID","TBLSYU","TABLE_NAME","NAME_JA",
089                                                            "TABLESPACE_NAME","INITIAL_EXTENT","NEXT_EXTENT","COMMENTS" };
090    
091            // 5.1.1.0 (2009/12/01) ??タのアクセス用の配?番号のID?private ?protected にします?
092            /** ??タのアクセス用の配?番号 {@value} */
093            protected static final int SYSTEM_ID            = 0;
094            /** ??タのアクセス用の配?番号 {@value} */
095            protected static final int TBLSYU                       = 1;
096            /** ??タのアクセス用の配?番号 {@value} */
097            protected static final int TABLE_NAME           = 2;
098            /** ??タのアクセス用の配?番号 {@value} */
099            protected static final int NAME_JA                      = 3;
100            /** ??タのアクセス用の配?番号 {@value} */
101            protected static final int TABLESPACE_NAME      = 4;
102            /** ??タのアクセス用の配?番号 {@value} */
103            protected static final int INITIAL_EXTENT       = 5;
104            /** ??タのアクセス用の配?番号 {@value} */
105            protected static final int NEXT_EXTENT          = 6;
106            /** ??タのアクセス用の配?番号 {@value} */
107            protected static final int COMMENTS                     = 7;
108    
109            private static final String GF05_SEL = "SELECT CLM,SEQNO,NAME_JA,CLS_NAME,USE_LENGTH,DATA_DEFAULT,NOT_NULL,'' AS OPTS"
110                                                                                            + " FROM GF05"
111                                                                                            + " WHERE SYSTEM_ID=? AND TBLSYU=? AND TABLE_NAME=?"
112                                                                                            + " AND   FGJ='1'"
113                                                                                            + " ORDER BY SEQNO" ;
114    
115            /** ??タのアクセス用の配?番号 {@value} */
116            protected static final int GF05_CLM                     = 0;
117            /** ??タのアクセス用の配?番号 {@value} */
118            protected static final int GF05_SEQNO           = 1;
119            /** ??タのアクセス用の配?番号 {@value} */
120            protected static final int GF05_NAME_JA         = 2;
121            /** ??タのアクセス用の配?番号 {@value} */
122            protected static final int GF05_CLS_NAME        = 3;
123            /** ??タのアクセス用の配?番号 {@value} */
124            protected static final int GF05_USE_LENGTH      = 4;
125            /** ??タのアクセス用の配?番号 {@value} */
126            protected static final int GF05_DATA_DEFAULT= 5;
127            /** ??タのアクセス用の配?番号 {@value} */
128            protected static final int GF05_NOT_NULL        = 6;
129            /** ??タのアクセス用の配?番号 {@value} */
130            protected static final int GF05_OPTIONS         = 7;
131    
132     //     private static final String ENCODE = "Windows-31J" ;
133            private static final String ENCODE = "UTF-8" ; // 4.3.6.6 (2009/05/15)
134    
135            private static final String CMNT  = "************************************************************************" ;
136    
137            private static final int X = FixLengthData.X ;          // type 定数
138            private static final int S = FixLengthData.S ;          // type 定数
139            private static final int K = FixLengthData.K ;          // type 定数
140            private static final int T = FixLengthData.T ;          // addLen 定数
141            private static final int T2= FixLengthData.T2 ;         // addLen 定数
142    
143            /** ?定数  */
144            protected static final String XML_START_TAG     = "<?xml version='1.0' encoding='UTF-8'?>" + CR + "<ROWSET tableName='xxx'>";
145            protected static final String XML_END_TAG       = "</ROWSET>";
146            protected static final String EXEC_START_TAG= "<EXEC_SQL>";
147            protected static final String EXEC_END_TAG      = "</EXEC_SQL>";
148    
149            /** XML形式かど? */
150            protected boolean               isXml                           = false; // 4.3.7.0 (2009/06/01)
151    
152            /**
153             * DBTableModel処?実行します?
154             *
155             * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得?為,ApplicationInfoオブジェクトを設?
156             * @og.rev 4.0.0.0 (2007/11/28) メソ?の戻り?をチェ?します?
157             * @og.rev 4.3.7.0 (2009/06/01) トリガー、SEQUENCE作?機?、XML出力機?追?
158             * @og.rev 5.1.1.0 (2009/12/01) XML_START_TAG に、tableName をセ?します?
159             * @og.rev 5.1.9.0 (2010/08/01) Transaction 対?
160             * @og.rev 5.5.2.6 (2012/05/25) protected変数を?private化したため?getterメソ?で取得するよ?変更
161             * @og.rev 5.6.6.0 (2013/07/05) FixLengthData の簡易コンストラクタを使用
162             *
163             * @return      実行結果の??ブルモ?
164             */
165            public DBTableModel execute() {
166                    DBTableModel table = getDBTableModel();         // 5.5.2.6 (2012/05/25) インターフェースにgetterメソ?追?
167    
168                    isXml = StringUtil.nval( getValue( "XML" ), false );
169    
170                    int[] clmNo = getTableColumnNo( DBKEY );
171                    int rowCnt = table.getRowCount();
172    
173                    File dir = new File( getValue( "DIR" ) );
174                    if( ! dir.exists() && ! dir.mkdirs() ) {
175                            String errMsg = "??フォル?作?できませんでした?" + dir + "]" ;
176                            // 4.3.4.4 (2009/01/01)
177                            throw new HybsSystemException( errMsg );
178                    }
179    
180                    // カン?カラ?クラス,(,桁数,),初期値,NOT_NULL,拡張機?,コメント開?行番号,名称,コメント終?
181                    int[] addLen = new int[] { 0,T,0,0,0,T2,T,T,T2,0,1,T,0 };       // ?ータ間?スペ?ス
182                    int[] type   = new int[] { X,X,X,X,S,X, X,X,X, X,S,K,X };       // ?ータの種別 X:半?S:空白前埋?K:全角混在
183                    FixLengthData fixData = new FixLengthData( addLen,type );
184    
185                    String[] data  = null;
186                    Transaction tran = getTransaction();    // 5.5.2.6 (2012/05/25)
187                    for( int row=0; row<rowCnt; row++ ) {
188                            String tableName = null;
189                            try {
190                                    data  = table.getValues( row );
191                                    String systemId = data[clmNo[SYSTEM_ID]];
192                                    String tblsyu   = data[clmNo[TBLSYU]];
193                                    tableName               = data[clmNo[TABLE_NAME]];
194    
195                                    PrintWriter writer = FileUtil.getPrintWriter( new File( dir,tableName + ( isXml ? "S.xml" : "S.sql" ) ),ENCODE );
196    
197                                    if( isXml ) { writer.println( XML_START_TAG.replace( "xxx",tableName ) ); }             // 5.1.1.0 (2009/12/01) tableName をセ?
198                                    writer.print( makeHeadLine( clmNo,data ) );
199    
200                                    String[] vals = new String[] { systemId,tblsyu,tableName };
201                                    String[][] gf05 = DBUtil.dbExecute( GF05_SEL,vals,tran );       // 5.1.9.0 (2010/08/01) Transaction 対?
202    
203                                    String uniqName = null;
204                                    fixData.clear();
205                                    // 値セ??まず?、最大長を求める?がある?
206                                    for( int i=0; i<gf05.length; i++ ) {
207                                            String[] outData = makeLineList( gf05[i],i==0 );
208                                            fixData.addListData( outData );
209    
210                                            // 4.3.7.0 (2009/06/01)
211                                            if( "UNIQ".equalsIgnoreCase( gf05[i][GF05_CLM] ) || "UNIQSEQ".equalsIgnoreCase( gf05[i][GF05_CLM] ) ) {
212                                                    uniqName = gf05[i][GF05_CLM].toUpperCase( Locale.JAPAN );
213                                            }
214                                    }
215                                    // 固定長化:最大長であわせた??を?力します?
216                                    for( int i=0; i<gf05.length; i++ ) {
217                                            writer.println( fixData.getFixData( i ) );
218                                    }
219                                    writer.println( makeEndLine( clmNo,data ) );
220    
221                                    // 4.3.7.0 (2009/06/01) UNIQ?のSEQとトリガーを作?
222                                    if( uniqName != null ) {
223                                            writer.println( makeUniqSeq( clmNo,data ) );
224                                            writer.println( makeUniqTrig( clmNo,data, uniqName ) );
225                                    }
226    
227                                    if( isXml ) { writer.println( XML_END_TAG ); }
228                                    writer.close();
229                            }
230                            catch( RuntimeException ex ) {
231                                    ErrorMessage errMessage = makeErrorMessage( "TableFilter_TABLE Error",ErrorMessage.NG );
232                                    errMessage.addMessage( row+1,ErrorMessage.NG,"TABLE",ex.toString() );
233                                    errMessage.addMessage( row+1,ErrorMessage.NG,"TABLE",StringUtil.array2csv( data ) );
234                                    errMessage.addMessage( row+1,ErrorMessage.NG,"TABLE","TABLE=[" + tableName + "]" );
235                                    // BAT から呼び出す?合があるため、標準エラー出力にも情報を?しておきます?
236                                    System.out.println( errMessage );
237                            }
238                    }
239    
240                    return table;
241            }
242    
243            /**
244             * ヘッ??部??処?実行します?
245             *
246             * @og.rev 5.6.6.0 (2013/07/05) FixLengthData の簡易コンストラクタを使用
247             * @og.rev 5.6.6.2 (2013/07/19) EXEC_START_TAG の付け忘れ
248             *
249             * @param       clmNo   カラ?号配?
250             * @param       data    ?行?の??タ配?
251             *
252             * @return      ヘッ??部????
253             */
254            protected String makeHeadLine( final int[] clmNo,final String[] data ) {
255                    final String TBL_NAME = data[clmNo[TABLE_NAME]];
256    
257                    String LINE1 = TBL_NAME + " ( " + data[clmNo[NAME_JA]] + " )" ;
258                    String LINE2 = data[clmNo[COMMENTS]] ;
259                    String LINE3 = "Created : " + HybsSystem.getDate() ;
260    
261                    // 5.6.6.0 (2013/07/05) FixLengthData の簡易コンストラクタを使用
262                    int[] addLen = new int[] { 0,0,0 };     // ?ータ間?スペ?ス
263                    int[] type   = new int[] { X,K,X };     // ?ータの種別 X:半?S:空白前埋?K:全角混在
264                    FixLengthData fixData = new FixLengthData( addLen,type );
265    
266                    String[][] outData = new String[][] {
267                            { "/**",        CMNT ,  "**/" },
268                            { "/* ",        LINE1,  " */" },
269                            { "/* ",        LINE2,  " */" },
270                            { "/* ",        LINE3,  " */" },
271                            { "/**",        CMNT ,  "**/" },
272                    };
273    
274                    fixData.addAllListData( outData );
275    
276                    StringBuilder buf = new StringBuilder();
277                    fixData.getAllFixData( buf );
278    
279                    if( isXml ) { buf.append( EXEC_START_TAG ).append( CR ); }                      // 5.6.6.2 (2013/07/19) 出力忘れ
280    
281                    buf.append( "CREATE TABLE " ).append( TBL_NAME ).append( " (" ).append( CR );
282    
283                    return buf.toString();
284            }
285    
286            /**
287             * ?部?カラ?義)の処?実行します?
288             * カン?カラ?クラス,(,桁数,),初期値,NOT_NULL,拡張機?,コメント開?行番号,名称,コメント終?
289             * の?配?にセ?します?
290             *
291             * @og.rev 5.5.1.9 (2012/04/18) useLen.length=0対?
292             * @param       data    ?行?の??タ配?
293             * @param       first   ??の行かど?[true:??/false:それ以降]
294             *
295             * @return      ?部?カラ?義)配?
296             */
297            protected String[] makeLineList( final String[] data,final boolean first ) {
298                    // カン?カラ?クラス(桁数),初期値,NOT_NULL,独自拡張,行番号,名称,終?
299                    String[] outData = new String[13];
300                    String clsName = data[GF05_CLS_NAME];
301    
302                    outData[0] = first ? "   " : " , " ;                            // 0:カン?
303                    outData[1] = data[GF05_CLM] ;                                                   // 1:カラ?
304    
305                    if( clsName.startsWith( "CLOB" ) || clsName.startsWith( "DATE" ) ) {
306                            data[GF05_USE_LENGTH] = null;
307                    }
308                    String useLen = data[GF05_USE_LENGTH];
309                    if( useLen != null && ! useLen.equals( "0" ) && useLen.length() > 0 ) { // 5.5.1.9 (2012/04/18)
310                            outData[2] = clsName ;                                                          // 2:クラス
311                            outData[3] = " ( " ;                                                            // 3:(
312                            outData[4] = useLen ;                                                           // 4:桁数
313                            outData[5] = " )" ;                                                                     // 5:)
314                    }
315                    else {
316                            outData[2] = clsName ;                                                          // NUMBER型?桁数?なし?ケース
317                    }
318    
319                    String def = data[GF05_DATA_DEFAULT];
320                    if( def != null && def.length() > 0 ) {
321                            String comma = ( clsName.indexOf( "CHAR" ) >= 0 ) ? "'" : "" ;
322                            outData[6] = "DEFAULT " + comma + def + comma ;         // 6:初期値
323                    }
324    
325                    String notNull = data[GF05_NOT_NULL];
326                    if( notNull != null && notNull.equals( "1" ) ) {
327                            outData[7] = "NOT NULL" ;                                                       // 7:NOT_NULL
328                    }
329    
330                    String options = data[GF05_OPTIONS];
331                    if( options != null ) {
332                            outData[8] = options    ;                                                       // 8:拡張機?
333                    }
334    
335                    String nameJA = data[GF05_NAME_JA] ;                                    // 名称
336                    if( nameJA != null ) {
337                            outData[9]  = "/* " ;                                                           // 9:コメント開?
338                            outData[10] = data[GF05_SEQNO] ;                                        // 10:行番号
339                            outData[11] = nameJA ;                                                          // 11:名称
340                            outData[12] = "*/" ;                                                            // 12:コメント終?
341                    }
342    
343                    return outData ;
344            }
345    
346            /**
347             * 定義の??部??処?実行します?
348             * 5.8.3.2 (2015/01/23)より
349             * ?.TABLESPACE_NAME を指定しな??合?、TABLESPACE 句を?力しません?
350             * ?.INITIAL_EXTENT,NEXT_EXTENT ?0 で?した?合?該当?を?力しません?
351             * ?.PCTINCREASE は、?力しません?
352             * 
353             * @og.rev 5.8.3.1 (2015/01/23) 不??目を?さな??する(V6の6.1.0.0と類似の対?
354             *                                              V6ではNEXT_EXTENT完?削除ですが、V5では互換性のため?残しておきます?
355             *
356             * @param       clmNo   カラ?号配?
357             * @param       data    ?行?の??タ配?
358             *
359             * @return      定義の??部?
360             */
361            protected String makeEndLine( final int[] clmNo,final String[] data ) {
362                    StringBuilder buf = new StringBuilder();
363                    
364                    final String tblSpcse = data[clmNo[TABLESPACE_NAME]] ;
365                    final String initExt  = data[clmNo[INITIAL_EXTENT]] ;
366                    final String nextExt  = data[clmNo[NEXT_EXTENT]] ;
367    
368                    buf.append( ")" ).append( CR );
369                    if( !StringUtil.isNull( tblSpcse ) ) {
370                            buf.append( "TABLESPACE " ).append( tblSpcse ).append( CR );
371                    }
372                    if( !StringUtil.isNull( initExt ) && initExt.charAt(0) != '0' ) {
373                            buf.append( "STORAGE( INITIAL " ).append(  initExt ).append("K");
374                            if( !StringUtil.isNull( nextExt ) && nextExt.charAt(0) != '0' ) {
375                                    buf.append( " NEXT " ).append(  nextExt ).append( "K" );
376                            }
377    //                      buf.append( "K PCTINCREASE 0 )" );
378                            buf.append( " )" );
379                    }
380    
381                    if( isXml )     { buf.append( CR ).append( EXEC_END_TAG ); }
382                    else            { buf.append( ";" ); }
383    
384                    return buf.toString();
385            }
386    
387            /**
388             * ユニ?クシーケンスの作?処?実行します?
389             *
390             * @og.rev 5.1.9.0 (2010/08/01) シーケンス名を[TABLE_NAME]S00に変更
391             *
392             * @param       clmNo   カラ?号配?
393             * @param       data    ?行?の??タ配?
394             *
395             * @return      ユニ?クシーケンス
396             */
397            protected String makeUniqSeq( final int[] clmNo,final String[] data ) {
398                    StringBuilder buf = new StringBuilder();
399    
400                    buf.append( CR );
401                    if( isXml ) { buf.append( EXEC_START_TAG ).append( CR ); }
402    
403                    // 5.1.9.0 (2010/08/01) シーケンス名を[TABLE_NAME]S00に変更
404                    buf.append( "CREATE SEQUENCE " ).append( data[clmNo[TABLE_NAME]] ).append( "S00 " ).append( CR );
405                    buf.append( "  INCREMENT BY 1 START WITH 1 MAXVALUE 999999999 CYCLE NOCACHE" );
406    
407                    if( isXml )     { buf.append( CR ).append( EXEC_END_TAG ); }
408                    else            { buf.append( ";" ); }
409    
410                    return buf.toString();
411            }
412    
413            /**
414             * ユニ?クシーケンスと関連付けるトリガの作?処?実行します?
415             *
416             * @og.rev 5.1.9.0 (2010/08/01) トリガー名を[TABLE_NAME]T00に変更
417             *
418             * @param       clmNo   カラ?号配?
419             * @param       data    ?行?の??タ配?
420             * @param   uniqName    ユニ?クトリガ?
421             *
422             * @return      ユニ?クシーケンスと関連付けるトリガ
423             */
424            protected String makeUniqTrig( final int[] clmNo,final String[] data, final String uniqName ) {
425                    final String TBL_NAME = data[clmNo[TABLE_NAME]] ;
426                    StringBuilder buf = new StringBuilder();
427    
428                    buf.append( CR );
429                    if( isXml ) { buf.append( EXEC_START_TAG ).append( CR ); }
430    
431                    // 5.1.9.0 (2010/08/01) トリガー名を[TABLE_NAME]T00に変更
432                    buf.append( "CREATE OR REPLACE TRIGGER " ).append( TBL_NAME ).append( "T00 " ).append( CR );
433                    buf.append( "  BEFORE INSERT ON ").append( TBL_NAME ).append( CR );
434                    buf.append( "  FOR EACH ROW " ).append( CR );
435                    buf.append( "  BEGIN " ).append( CR );
436                    // 5.1.9.0 (2010/08/01) シーケンス名を[TABLE_NAME]S00に変更
437                    buf.append( "    SELECT " ).append( TBL_NAME ).append( "S00.NEXTVAL INTO :NEW." )
438                            .append( uniqName ).append( " FROM DUAL; " ).append( CR );
439                    buf.append( "  END; " ).append( CR );
440    
441                    if( isXml )     { buf.append( EXEC_END_TAG ); }
442                    else            { buf.append( "/" ); }
443    
444                    return buf.toString();
445            }
446    }