001    /*
002     * JBoss DNA (http://www.jboss.org/dna)
003     * See the COPYRIGHT.txt file distributed with this work for information
004     * regarding copyright ownership.  Some portions may be licensed
005     * to Red Hat, Inc. under one or more contributor license agreements.
006     * See the AUTHORS.txt file in the distribution for a full listing of 
007     * individual contributors. 
008     *
009     * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
010     * is licensed to you under the terms of the GNU Lesser General Public License as
011     * published by the Free Software Foundation; either version 2.1 of
012     * the License, or (at your option) any later version.
013     *
014     * JBoss DNA is distributed in the hope that it will be useful,
015     * but WITHOUT ANY WARRANTY; without even the implied warranty of
016     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017     * Lesser General Public License for more details.
018     *
019     * You should have received a copy of the GNU Lesser General Public
020     * License along with this software; if not, write to the Free
021     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
022     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
023     */
024    package org.jboss.dna.common.jdbc.util;
025    
026    import java.lang.reflect.Method;
027    import java.sql.DatabaseMetaData;
028    import java.sql.ResultSet;
029    import java.sql.SQLException;
030    import java.sql.Types;
031    import java.util.HashMap;
032    import java.util.Map;
033    import java.util.Set;
034    import org.apache.commons.beanutils.PropertyUtils;
035    import org.jboss.dna.common.jdbc.JdbcMetadataI18n;
036    import org.jboss.dna.common.jdbc.model.ModelFactory;
037    import org.jboss.dna.common.jdbc.model.api.Attribute;
038    import org.jboss.dna.common.jdbc.model.api.BestRowIdentifier;
039    import org.jboss.dna.common.jdbc.model.api.BestRowIdentifierScopeType;
040    import org.jboss.dna.common.jdbc.model.api.Catalog;
041    import org.jboss.dna.common.jdbc.model.api.ColumnPseudoType;
042    import org.jboss.dna.common.jdbc.model.api.Database;
043    import org.jboss.dna.common.jdbc.model.api.DatabaseMetaDataMethodException;
044    import org.jboss.dna.common.jdbc.model.api.ForeignKey;
045    import org.jboss.dna.common.jdbc.model.api.ForeignKeyColumn;
046    import org.jboss.dna.common.jdbc.model.api.Index;
047    import org.jboss.dna.common.jdbc.model.api.IndexColumn;
048    import org.jboss.dna.common.jdbc.model.api.IndexType;
049    import org.jboss.dna.common.jdbc.model.api.KeyDeferrabilityType;
050    import org.jboss.dna.common.jdbc.model.api.KeyModifyRuleType;
051    import org.jboss.dna.common.jdbc.model.api.NullabilityType;
052    import org.jboss.dna.common.jdbc.model.api.Parameter;
053    import org.jboss.dna.common.jdbc.model.api.ParameterIoType;
054    import org.jboss.dna.common.jdbc.model.api.PrimaryKey;
055    import org.jboss.dna.common.jdbc.model.api.PrimaryKeyColumn;
056    import org.jboss.dna.common.jdbc.model.api.Privilege;
057    import org.jboss.dna.common.jdbc.model.api.PrivilegeType;
058    import org.jboss.dna.common.jdbc.model.api.Reference;
059    import org.jboss.dna.common.jdbc.model.api.ResultSetConcurrencyType;
060    import org.jboss.dna.common.jdbc.model.api.ResultSetHoldabilityType;
061    import org.jboss.dna.common.jdbc.model.api.ResultSetType;
062    import org.jboss.dna.common.jdbc.model.api.SQLStateType;
063    import org.jboss.dna.common.jdbc.model.api.Schema;
064    import org.jboss.dna.common.jdbc.model.api.SearchabilityType;
065    import org.jboss.dna.common.jdbc.model.api.SortSequenceType;
066    import org.jboss.dna.common.jdbc.model.api.SqlType;
067    import org.jboss.dna.common.jdbc.model.api.SqlTypeInfo;
068    import org.jboss.dna.common.jdbc.model.api.StoredProcedure;
069    import org.jboss.dna.common.jdbc.model.api.StoredProcedureResultType;
070    import org.jboss.dna.common.jdbc.model.api.Table;
071    import org.jboss.dna.common.jdbc.model.api.TableColumn;
072    import org.jboss.dna.common.jdbc.model.api.TableType;
073    import org.jboss.dna.common.jdbc.model.api.TransactionIsolationLevelType;
074    import org.jboss.dna.common.jdbc.model.api.UserDefinedType;
075    import org.jboss.dna.common.util.Logger;
076    
077    /**
078     * Database related utilities
079     * 
080     * @author <a href="mailto:litsenko_sergey@yahoo.com">Sergiy Litsenko</a>
081     */
082    public class DatabaseUtil {
083        /**
084         * Logging for this instance
085         */
086        private static Logger log = Logger.getLogger(DatabaseUtil.class);
087    
088        /**
089         * Standard UDT types as string
090         */
091        private static String standardUserDefinedTypes = "JAVA_OBJECT,STRUCT,DISTINCT";
092    
093        private static Map<String, Integer> standardUserDefinedTypesMapping = new HashMap<String, Integer>();
094    
095        static {
096            standardUserDefinedTypesMapping.put("JAVA_OBJECT", new Integer(SqlType.JAVA_OBJECT.getType()));
097            standardUserDefinedTypesMapping.put("STRUCT", new Integer(SqlType.STRUCT.getType()));
098            standardUserDefinedTypesMapping.put("DISTINCT", new Integer(SqlType.DISTINCT.getType()));
099        }
100    
101        // ~ Constructors ---------------------------------------------------------------------
102    
103        /**
104         * Constructor
105         */
106        private DatabaseUtil() {
107        }
108    
109        // ~ Methods --------------------------------------------------------------------------
110    
111        /**
112         * Returns Standard UDT types as string
113         * 
114         * @return Standard UDT types as string
115         */
116        public static String getStandardUserDefinedTypes() {
117            return standardUserDefinedTypes;
118        }
119    
120        /**
121         * Converts string array of UDT names to appropriate int array of UDT types specified in java.sql.Types
122         * 
123         * @param userDefinedTypes the string array of UDT names
124         * @return int array of user defined types specified in java.sql.Types
125         */
126        public static int[] getUserDefinedTypes( String userDefinedTypes ) {
127            // convert comma separated list of user defined types to array
128            String[] userDefinedTypesStringArray = (userDefinedTypes == null) ? null : userDefinedTypes.split(",");
129            // create UDT int array
130            int[] userDefinedTypesArray = new int[userDefinedTypesStringArray.length];
131            // fill array
132            for (int i = 0; i < userDefinedTypesStringArray.length; i++) {
133                // get value from map
134                Integer udtType = standardUserDefinedTypesMapping.get(userDefinedTypesStringArray[i]);
135                // set int value
136                userDefinedTypesArray[i] = (udtType == null) ? Types.NULL : udtType.intValue();
137            }
138            return userDefinedTypesArray;
139        }
140    
141        /**
142         * Returns boolean with respect to NULL values (ResultSet.wasNull())
143         * 
144         * @param resultSet the result set to fetch from
145         * @param columnName the name of column
146         * @return boolean with respect to NULL values (could be null)
147         * @throws SQLException
148         */
149        public static Boolean getBoolean( ResultSet resultSet,
150                                          String columnName ) throws SQLException {
151            // check result set
152            if (resultSet == null) {
153                return null;
154            }
155            // get boolean
156            boolean value = resultSet.getBoolean(columnName);
157            // return
158            return (resultSet.wasNull()) ? null : (value == true) ? Boolean.TRUE : Boolean.FALSE;
159        }
160    
161        /**
162         * Returns boolean with respect to NULL values (ResultSet.wasNull())
163         * 
164         * @param resultSet the result set to fetch from
165         * @param columnName the name of column
166         * @param failOnError if true raises exception
167         * @return boolean with respect to NULL values (could be null)
168         * @throws SQLException
169         */
170        public static Boolean getBoolean( ResultSet resultSet,
171                                          String columnName,
172                                          boolean failOnError ) throws SQLException {
173            // check result set
174            if (resultSet == null) {
175                return null;
176            }
177            // get boolean
178            boolean value = false;
179            try {
180                value = resultSet.getBoolean(columnName);
181                // return
182                return (resultSet.wasNull()) ? null : (value == true) ? Boolean.TRUE : Boolean.FALSE;
183            } catch (SQLException e) {
184                if (failOnError) {
185                    throw e;
186                }
187                log.error(JdbcMetadataI18n.unableToGetValueFromColumn, columnName, e.getMessage());
188                return null;
189            }
190        }
191    
192        /**
193         * Returns boolean with respect to NULL values (ResultSet.wasNull())
194         * 
195         * @param resultSet the result set to fetch from
196         * @param columnIndex the index of column
197         * @return boolean with respect to NULL values (could be null)
198         * @throws SQLException
199         */
200        public static Boolean getBoolean( ResultSet resultSet,
201                                          int columnIndex ) throws SQLException {
202            // check result set
203            if (resultSet == null) {
204                return null;
205            }
206            // get boolean
207            boolean value = resultSet.getBoolean(columnIndex);
208            // return
209            return (resultSet.wasNull()) ? null : (value == true) ? Boolean.TRUE : Boolean.FALSE;
210        }
211    
212        /**
213         * Returns boolean with respect to NULL values (ResultSet.wasNull())
214         * 
215         * @param resultSet the result set to fetch from
216         * @param columnIndex the index of column
217         * @param failOnError if true raises exception
218         * @return boolean with respect to NULL values (could be null)
219         * @throws SQLException
220         */
221        public static Boolean getBoolean( ResultSet resultSet,
222                                          int columnIndex,
223                                          boolean failOnError ) throws SQLException {
224            // check result set
225            if (resultSet == null) {
226                return null;
227            }
228            // get boolean
229            boolean value = false;
230            try {
231                value = resultSet.getBoolean(columnIndex);
232                // return
233                return (resultSet.wasNull()) ? null : (value == true) ? Boolean.TRUE : Boolean.FALSE;
234            } catch (SQLException e) {
235                if (failOnError) {
236                    throw e;
237                }
238                log.error(JdbcMetadataI18n.unableToGetValueFromColumn, columnIndex, e.getMessage());
239                return null;
240            }
241        }
242    
243        /**
244         * Returns integer with respect to NULL values (ResultSet.wasNull())
245         * 
246         * @param resultSet the result set to fetch from
247         * @param columnName the name of column
248         * @return integer with respect to NULL values (could be null)
249         * @throws SQLException
250         */
251        public static Integer getInteger( ResultSet resultSet,
252                                          String columnName ) throws SQLException {
253            // check result set
254            if (resultSet == null) {
255                return null;
256            }
257            // get integer
258            int value = resultSet.getInt(columnName);
259            // return
260            return (resultSet.wasNull()) ? null : new Integer(value);
261        }
262    
263        /**
264         * Returns integer with respect to NULL values (ResultSet.wasNull())
265         * 
266         * @param resultSet the result set to fetch from
267         * @param columnName the name of column
268         * @param failOnError if true raises exception
269         * @return integer with respect to NULL values (could be null)
270         * @throws SQLException
271         */
272        public static Integer getInteger( ResultSet resultSet,
273                                          String columnName,
274                                          boolean failOnError ) throws SQLException {
275            // check result set
276            if (resultSet == null) {
277                return null;
278            }
279            // get
280            int value = 0;
281            try {
282                value = resultSet.getInt(columnName);
283                // return
284                return (resultSet.wasNull()) ? null : new Integer(value);
285    
286            } catch (SQLException e) {
287                if (failOnError) {
288                    throw e;
289                }
290                log.error(JdbcMetadataI18n.unableToGetValueFromColumn, columnName, e.getMessage());
291                return null;
292            }
293        }
294    
295        /**
296         * Returns integer with respect to NULL values (ResultSet.wasNull())
297         * 
298         * @param resultSet the result set to fetch from
299         * @param columnIndex the index of column
300         * @return integer with respect to NULL values (could be null)
301         * @throws SQLException
302         */
303        public static Integer getInteger( ResultSet resultSet,
304                                          int columnIndex ) throws SQLException {
305            // check result set
306            if (resultSet == null) {
307                return null;
308            }
309            // get integer
310            int value = resultSet.getInt(columnIndex);
311            // return
312            return (resultSet.wasNull()) ? null : new Integer(value);
313        }
314    
315        /**
316         * Returns integer with respect to NULL values (ResultSet.wasNull())
317         * 
318         * @param resultSet the result set to fetch from
319         * @param columnIndex the index of column
320         * @param failOnError if true raises exception
321         * @return integer with respect to NULL values (could be null)
322         * @throws SQLException
323         */
324        public static Integer getInteger( ResultSet resultSet,
325                                          int columnIndex,
326                                          boolean failOnError ) throws SQLException {
327            // check result set
328            if (resultSet == null) {
329                return null;
330            }
331            // get
332            int value = 0;
333            try {
334                value = resultSet.getInt(columnIndex);
335                // return
336                return (resultSet.wasNull()) ? null : new Integer(value);
337    
338            } catch (SQLException e) {
339                if (failOnError) {
340                    throw e;
341                }
342                log.error(JdbcMetadataI18n.unableToGetValueFromColumn, columnIndex, e.getMessage());
343                return null;
344            }
345        }
346    
347        /**
348         * Returns long with respect to NULL values (ResultSet.wasNull())
349         * 
350         * @param resultSet the result set to fetch from
351         * @param columnName the name of column
352         * @return long with respect to NULL values (could be null)
353         * @throws SQLException
354         */
355        public static Long getLong( ResultSet resultSet,
356                                    String columnName ) throws SQLException {
357            // check result set
358            if (resultSet == null) {
359                return null;
360            }
361            // get integer
362            long value = resultSet.getLong(columnName);
363            // return
364            return (resultSet.wasNull()) ? null : new Long(value);
365        }
366    
367        /**
368         * Returns long with respect to NULL values (ResultSet.wasNull())
369         * 
370         * @param resultSet the result set to fetch from
371         * @param columnName the name of column
372         * @param failOnError if true raises exception
373         * @return long with respect to NULL values (could be null)
374         * @throws SQLException
375         */
376        public static Long getLong( ResultSet resultSet,
377                                    String columnName,
378                                    boolean failOnError ) throws SQLException {
379            // check result set
380            if (resultSet == null) {
381                return null;
382            }
383            // get
384            long value = 0;
385            try {
386                value = resultSet.getLong(columnName);
387                // return
388                return (resultSet.wasNull()) ? null : new Long(value);
389    
390            } catch (SQLException e) {
391                if (failOnError) {
392                    throw e;
393                }
394                log.error(JdbcMetadataI18n.unableToGetValueFromColumn, columnName, e.getMessage());
395                return null;
396            }
397        }
398    
399        /**
400         * Returns long with respect to NULL values (ResultSet.wasNull())
401         * 
402         * @param resultSet the result set to fetch from
403         * @param columnIndex the index of column
404         * @return long with respect to NULL values (could be null)
405         * @throws SQLException
406         */
407        public static Long getLong( ResultSet resultSet,
408                                    int columnIndex ) throws SQLException {
409            // check result set
410            if (resultSet == null) {
411                return null;
412            }
413            // get integer
414            long value = resultSet.getLong(columnIndex);
415            // return
416            return (resultSet.wasNull()) ? null : new Long(value);
417        }
418    
419        /**
420         * Returns long with respect to NULL values (ResultSet.wasNull())
421         * 
422         * @param resultSet the result set to fetch from
423         * @param columnIndex the index of column
424         * @param failOnError if true raises exception
425         * @return long with respect to NULL values (could be null)
426         * @throws SQLException
427         */
428        public static Long getLong( ResultSet resultSet,
429                                    int columnIndex,
430                                    boolean failOnError ) throws SQLException {
431            // check result set
432            if (resultSet == null) {
433                return null;
434            }
435            // get
436            long value = 0;
437            try {
438                value = resultSet.getLong(columnIndex);
439                // return
440                return (resultSet.wasNull()) ? null : new Long(value);
441    
442            } catch (SQLException e) {
443                if (failOnError) {
444                    throw e;
445                }
446                log.error(JdbcMetadataI18n.unableToGetValueFromColumn, columnIndex, e.getMessage());
447                return null;
448            }
449        }
450    
451        /**
452         * Returns double with respect to NULL values (ResultSet.wasNull())
453         * 
454         * @param resultSet the result set to fetch from
455         * @param columnName the name of column
456         * @return double with respect to NULL values (could be null)
457         * @throws SQLException
458         */
459        public static Double getDouble( ResultSet resultSet,
460                                        String columnName ) throws SQLException {
461            // check result set
462            if (resultSet == null) {
463                return null;
464            }
465            // get integer
466            double value = resultSet.getDouble(columnName);
467            // return
468            return (resultSet.wasNull()) ? null : new Double(value);
469        }
470    
471        /**
472         * Returns double with respect to NULL values (ResultSet.wasNull())
473         * 
474         * @param resultSet the result set to fetch from
475         * @param columnName the name of column
476         * @param failOnError if true raises exception
477         * @return double with respect to NULL values (could be null)
478         * @throws SQLException
479         */
480        public static Double getDouble( ResultSet resultSet,
481                                        String columnName,
482                                        boolean failOnError ) throws SQLException {
483            // check result set
484            if (resultSet == null) {
485                return null;
486            }
487            // get
488            double value = 0.0;
489            try {
490                value = resultSet.getLong(columnName);
491                // return
492                return (resultSet.wasNull()) ? null : new Double(value);
493    
494            } catch (SQLException e) {
495                if (failOnError) {
496                    throw e;
497                }
498                log.error(JdbcMetadataI18n.unableToGetValueFromColumn, columnName, e.getMessage());
499                return null;
500            }
501        }
502    
503        /**
504         * Returns double with respect to NULL values (ResultSet.wasNull())
505         * 
506         * @param resultSet the result set to fetch from
507         * @param columnIndex the index of column
508         * @return double with respect to NULL values (could be null)
509         * @throws SQLException
510         */
511        public static Double getDouble( ResultSet resultSet,
512                                        int columnIndex ) throws SQLException {
513            // check result set
514            if (resultSet == null) {
515                return null;
516            }
517            // get integer
518            double value = resultSet.getDouble(columnIndex);
519            // return
520            return (resultSet.wasNull()) ? null : new Double(value);
521        }
522    
523        /**
524         * Returns double with respect to NULL values (ResultSet.wasNull())
525         * 
526         * @param resultSet the result set to fetch from
527         * @param columnIndex the index of column
528         * @param failOnError if true raises exception
529         * @return double with respect to NULL values (could be null)
530         * @throws SQLException
531         */
532        public static Double getDouble( ResultSet resultSet,
533                                        int columnIndex,
534                                        boolean failOnError ) throws SQLException {
535            // check result set
536            if (resultSet == null) {
537                return null;
538            }
539            // get
540            double value = 0.0;
541            try {
542                value = resultSet.getLong(columnIndex);
543                // return
544                return (resultSet.wasNull()) ? null : new Double(value);
545    
546            } catch (SQLException e) {
547                if (failOnError) {
548                    throw e;
549                }
550                log.error(JdbcMetadataI18n.unableToGetValueFromColumn, columnIndex, e.getMessage());
551                return null;
552            }
553        }
554    
555        /**
556         * Returns String with respect to NULL values (ResultSet.wasNull())
557         * 
558         * @param resultSet the result set to fetch from
559         * @param columnName the name of column
560         * @return double with respect to NULL values (could be null)
561         * @throws SQLException
562         */
563        public static String getString( ResultSet resultSet,
564                                        String columnName ) throws SQLException {
565            // check result set
566            if (resultSet == null) {
567                return null;
568            }
569            // get integer
570            String value = resultSet.getString(columnName);
571            // return
572            return (resultSet.wasNull()) ? null : value;
573        }
574    
575        /**
576         * Returns String with respect to NULL values (ResultSet.wasNull())
577         * 
578         * @param resultSet the result set to fetch from
579         * @param columnName the name of column
580         * @param failOnError if true raises exception
581         * @return double with respect to NULL values (could be null)
582         * @throws SQLException
583         */
584        public static String getString( ResultSet resultSet,
585                                        String columnName,
586                                        boolean failOnError ) throws SQLException {
587            // check result set
588            if (resultSet == null) {
589                return null;
590            }
591            // get
592            String value = null;
593            try {
594                value = resultSet.getString(columnName);
595                // return
596                return (resultSet.wasNull()) ? null : value;
597    
598            } catch (SQLException e) {
599                if (failOnError) {
600                    throw e;
601                }
602                log.error(JdbcMetadataI18n.unableToGetValueFromColumn, columnName, e.getMessage());
603                return null;
604            }
605        }
606    
607        /**
608         * Returns String with respect to NULL values (ResultSet.wasNull())
609         * 
610         * @param resultSet the result set to fetch from
611         * @param columnIndex the index of column
612         * @return double with respect to NULL values (could be null)
613         * @throws SQLException
614         */
615        public static String getString( ResultSet resultSet,
616                                        int columnIndex ) throws SQLException {
617            // check result set
618            if (resultSet == null) {
619                return null;
620            }
621            // get integer
622            String value = resultSet.getString(columnIndex);
623            // return
624            return (resultSet.wasNull()) ? null : value;
625        }
626    
627        /**
628         * Returns String with respect to NULL values (ResultSet.wasNull())
629         * 
630         * @param resultSet the result set to fetch from
631         * @param columnIndex the index of column
632         * @param failOnError if true raises exception
633         * @return double with respect to NULL values (could be null)
634         * @throws SQLException
635         */
636        public static String getString( ResultSet resultSet,
637                                        int columnIndex,
638                                        boolean failOnError ) throws SQLException {
639            // check result set
640            if (resultSet == null) {
641                return null;
642            }
643            String value = null;
644            try {
645                value = resultSet.getString(columnIndex);
646                // return
647                return (resultSet.wasNull()) ? null : value;
648    
649            } catch (SQLException e) {
650                if (failOnError) {
651                    throw e;
652                }
653                log.error(JdbcMetadataI18n.unableToGetValueFromColumn, columnIndex, e.getMessage());
654                return null;
655            }
656        }
657    
658        /**
659         * Returns BestRowIdentifierScopeType or null
660         * 
661         * @param type the best row identifier
662         * @return BestRowIdentifierScopeType or null
663         */
664        public static BestRowIdentifierScopeType getBestRowIdentifierScopeType( Integer type ) {
665            // check input
666            if (type == null) {
667                return null;
668            }
669            // check for values
670            for (BestRowIdentifierScopeType sType : BestRowIdentifierScopeType.values()) {
671                if (sType.getScope() == type.intValue()) {
672                    return sType;
673                }
674            }
675            // log only if not found
676            log.debug(String.format("[%s] Unknown best row identifier scope type %d", "getBestRowIdentifierScopeType", type));
677    
678            return null;
679        }
680    
681        /**
682         * Returns ColumnPseudoType or null
683         * 
684         * @param type the column pseudo type
685         * @return ColumnPseudoType or null
686         */
687        public static ColumnPseudoType getColumnPseudoType( Integer type ) {
688            // check input
689            if (type == null) {
690                return null;
691            }
692            // check for values
693            for (ColumnPseudoType pType : ColumnPseudoType.values()) {
694                if (pType.getType() == type.intValue()) {
695                    return pType;
696                }
697            }
698            // log only if not found
699            log.debug(String.format("[%s] Unknown column pseudo type %d", "getColumnPseudoType", type));
700    
701            return null;
702        }
703    
704        /**
705         * Returns IndexType or null
706         * 
707         * @param type the index type
708         * @return IndexType or null
709         */
710        public static IndexType getIndexType( Integer type ) {
711            // check input
712            if (type == null) {
713                return null;
714            }
715            // check for values
716            for (IndexType iType : IndexType.values()) {
717                if (iType.getType() == type.intValue()) {
718                    return iType;
719                }
720            }
721            // log only if not found
722            log.debug(String.format("[%s] Unknown index type %d", "getKeyDeferrabilityType", type));
723    
724            return null;
725        }
726    
727        /**
728         * Returns KeyDeferrabilityType or null
729         * 
730         * @param type the key defferability type
731         * @return KeyDeferrabilityType or null
732         */
733        public static KeyDeferrabilityType getKeyDeferrabilityType( Integer type ) {
734            // check input
735            if (type == null) {
736                return null;
737            }
738            // check for values
739            for (KeyDeferrabilityType dType : KeyDeferrabilityType.values()) {
740                if (dType.getDeferrability() == type.intValue()) {
741                    return dType;
742                }
743            }
744            // log only if not found
745            log.debug(String.format("[%s] Unknown key deferrability type %d", "getKeyDeferrabilityType", type));
746    
747            return null;
748        }
749    
750        /**
751         * Returns KeyModifyRuleType or null
752         * 
753         * @param type the key modify rule type
754         * @return KeyModifyRuleType or null
755         */
756        public static KeyModifyRuleType getKeyModifyRuleType( Integer type ) {
757            // check input
758            if (type == null) {
759                return null;
760            }
761            // check for values
762            for (KeyModifyRuleType rType : KeyModifyRuleType.values()) {
763                if (rType.getRule() == type.intValue()) {
764                    return rType;
765                }
766            }
767            // log only if not found
768            log.debug(String.format("[%s] Unknown key modify rule type %d", "getKeyModifyRuleType", type));
769    
770            return null;
771        }
772    
773        /**
774         * Returns column nullability, or null
775         * 
776         * @param type
777         * @return NullabilityType
778         */
779        public static NullabilityType getNullabilityType( Integer type ) {
780            // check input
781            if (type == null) {
782                return null;
783            }
784            // check for values
785            for (NullabilityType nType : NullabilityType.values()) {
786                if (nType.getNullability() == type.intValue()) {
787                    return nType;
788                }
789            }
790            // log only if not found
791            log.debug(String.format("[%s] Unknown nullability type %d", "getNullabilityType", type));
792    
793            return null;
794        }
795    
796        /**
797         * Returns ParameterIoType based on type, or null
798         * 
799         * @param type i/o type
800         * @return ParameterIoType based on type, or null
801         */
802        public static ParameterIoType getParameterIoType( Integer type ) {
803            // check input
804            if (type == null) {
805                return null;
806            }
807            // check for values
808            for (ParameterIoType ioType : ParameterIoType.values()) {
809                if (ioType.getType() == type.intValue()) {
810                    return ioType;
811                }
812            }
813            // log only if not found
814            log.debug(String.format("[%s] Unknown parameter I/O type %d", "getParameterIoType", type));
815    
816            return null;
817        }
818    
819        /**
820         * Returns PrivilegeType or null
821         * 
822         * @param type the privilege type
823         * @return PrivilegeType or null
824         */
825        public static PrivilegeType getPrivilegeType( String type ) {
826            // check input
827            if (type == null) {
828                return null;
829            }
830            // check for values
831            for (PrivilegeType pType : PrivilegeType.values()) {
832                if (pType.getType().equals(type)) {
833                    return pType;
834                }
835            }
836            // log only if not found
837            log.debug(String.format("[%s] Unknown privilege type %s", "getPrivilegeType", type));
838    
839            return null;
840        }
841    
842        /**
843         * Returns ResultSetConcurrencyType or null
844         * 
845         * @param type the concurrency
846         * @return ResultSetConcurrencyType or null
847         */
848        public static ResultSetConcurrencyType getResultSetConcurrencyType( Integer type ) {
849            // check input
850            if (type == null) {
851                return null;
852            }
853            // check for values
854            for (ResultSetConcurrencyType cType : ResultSetConcurrencyType.values()) {
855                if (cType.getConcurrency() == type.intValue()) {
856                    return cType;
857                }
858            }
859            // log only if not found
860            log.debug(String.format("[%s] Unknown result set concurrency type %d", "getResultSetConcurrencyType", type));
861    
862            return null;
863        }
864    
865        /**
866         * Returns ResultSetHoldabilityType or null
867         * 
868         * @param type the holdability
869         * @return ResultSetHoldabilityType or null
870         */
871        public static ResultSetHoldabilityType getResultSetHoldabilityType( Integer type ) {
872            // check input
873            if (type == null) {
874                return null;
875            }
876            // check for values
877            for (ResultSetHoldabilityType hType : ResultSetHoldabilityType.values()) {
878                if (hType.getHoldability() == type.intValue()) {
879                    return hType;
880                }
881            }
882            // log only if not found
883            log.debug(String.format("[%s] Unknown result set holdability type %d", "getResultSetHoldabilityType", type));
884    
885            return null;
886        }
887    
888        /**
889         * Returns ResultSetType or null
890         * 
891         * @param type the result set type
892         * @return ResultSetType or null
893         */
894        public static ResultSetType getResultSetType( Integer type ) {
895            // check input
896            if (type == null) {
897                return null;
898            }
899            // check for values
900            for (ResultSetType rsType : ResultSetType.values()) {
901                if (rsType.getType() == type.intValue()) {
902                    return rsType;
903                }
904            }
905            // log only if not found
906            log.debug(String.format("[%s] Unknown result set type %d", "getResultSetType", type));
907    
908            return null;
909        }
910    
911        /**
912         * Returns SearchabilityType or null
913         * 
914         * @param type the searchability
915         * @return SearchabilityType or null
916         */
917        public static SearchabilityType getSearchabilityType( Integer type ) {
918            // check input
919            if (type == null) {
920                return null;
921            }
922            // check for values
923            for (SearchabilityType sType : SearchabilityType.values()) {
924                if (sType.getSearchability() == type.intValue()) {
925                    return sType;
926                }
927            }
928            // log only if not found
929            log.debug(String.format("[%s] Unknown serachability type %d", "getSearchabilityType", type));
930    
931            return null;
932        }
933    
934        /**
935         * Returns SortSequenceType or null
936         * 
937         * @param type the sort sequence
938         * @return SortSequenceType or null
939         */
940        public static SortSequenceType getSortSequenceType( String type ) {
941            // check input
942            if (type == null) {
943                return null;
944            }
945            // check for values
946            for (SortSequenceType sType : SortSequenceType.values()) {
947                if ((sType.getType() != null) && (sType.getType().equals(type))) {
948                    return sType;
949                }
950            }
951            // log only if not found
952            log.debug(String.format("[%s] Unknown sort sequence type %s", "getSortSequenceType", type));
953    
954            return null;
955        }
956    
957        /**
958         * Returns SqlStateType based on type, or null
959         * 
960         * @param type the SQL state type
961         * @return SqlStateType based on type, or null
962         */
963        public static SQLStateType getSqlStateType( Integer type ) {
964            // check input
965            if (type == null) {
966                return null;
967            }
968            // check for Type values
969            for (SQLStateType stateType : SQLStateType.values()) {
970                if (stateType.getState() == type.intValue()) {
971                    return stateType;
972                }
973            }
974            // log only if not found
975            log.debug(String.format("[%s] Unknown SQL state type %d", "getSqlStateType", type));
976    
977            return null;
978        }
979    
980        /**
981         * Returns SqlType based on data type, or null
982         * 
983         * @param type the SQL type
984         * @return SqlType based on data type, or null
985         */
986        public static SqlType getSqlType( Integer type ) {
987            // check input
988            if (type == null) {
989                return null;
990            }
991            // check for SqlType values
992            for (SqlType sqlType : SqlType.values()) {
993                if (sqlType.getType() == type.intValue()) {
994                    return sqlType;
995                }
996            }
997            // log only if not found
998            log.debug(String.format("[%s] Unknown SQL Type %d", "getSqlType", type));
999    
1000            return null;
1001        }
1002    
1003        /**
1004         * Returns SP result type based on PROCEDURE_TYPE
1005         * 
1006         * @param type the stored procedure result type
1007         * @return SP result type based on PROCEDURE_TYPE, or null
1008         */
1009        public static StoredProcedureResultType getStoredProcedureResultType( Integer type ) {
1010            // check input
1011            if (type == null) {
1012                return null;
1013            }
1014            // check for SqlType values
1015            for (StoredProcedureResultType spResultType : StoredProcedureResultType.values()) {
1016                if (spResultType.getType() == type.intValue()) {
1017                    return spResultType;
1018                }
1019            }
1020            // log only if not found
1021            log.debug(String.format("[%s] Unknown stored procedure result type %d", "getStoredProcedureResultType", type));
1022    
1023            return null;
1024        }
1025    
1026        /**
1027         * Returns transaction isolation level, or null
1028         * 
1029         * @param type the level type
1030         * @return transaction isolation level, or null
1031         */
1032        public static TransactionIsolationLevelType getTransactionIsolationLevelType( Integer type ) {
1033            // check input
1034            if (type == null) {
1035                return null;
1036            }
1037            // check for Type values
1038            for (TransactionIsolationLevelType txType : TransactionIsolationLevelType.values()) {
1039                if (txType.getLevel() == type.intValue()) {
1040                    return txType;
1041                }
1042            }
1043            // log only if not found
1044            log.debug(String.format("[%s] Unknown transaction isolation level type %d", "getTransactionIsolationLevelType", type));
1045    
1046            return null;
1047        }
1048    
1049        /**
1050         * Creates catalog based on current record in result set; adds catalog to the database
1051         * 
1052         * @param factory the model factory to create table
1053         * @param resultSet the table result set from DatabaseMetadata
1054         * @param traceLog the log to write if any
1055         * @param failOnError
1056         * @param database the owner database
1057         * @return created catalog
1058         * @throws Exception if any error occurs and failOnError is true then generates exception
1059         */
1060        public static Catalog populateCatalog( ModelFactory factory,
1061                                               ResultSet resultSet,
1062                                               Logger traceLog,
1063                                               boolean failOnError,
1064                                               Database database ) throws Exception {
1065            // check for null
1066            if (factory == null) {
1067                throw new IllegalArgumentException("factory");
1068            }
1069    
1070            // check for null
1071            if (database == null) {
1072                throw new IllegalArgumentException("database");
1073            }
1074    
1075            // check for null
1076            if (resultSet == null) {
1077                throw new IllegalArgumentException("resultSet");
1078            }
1079    
1080            // set trace log
1081            if (traceLog == null) {
1082                traceLog = log;
1083            }
1084    
1085            // get type catalog
1086            String catalogName = getString(resultSet, "TABLE_CAT", false);
1087    
1088            // create catalog object
1089            Catalog catalog = factory.createCatalog();
1090    
1091            // ***************************
1092            // *** DatabaseNamedObject ***
1093            // ***************************
1094    
1095            // set name
1096            catalog.setName(catalogName);
1097            // set remarks
1098            // catalog.setRemarks (remarks); // N/A
1099            // TODO set extra properties
1100            // catalog.addExtraProperty (String key, Object value);
1101    
1102            // ***************
1103            // *** Catalog ***
1104            // ***************
1105    
1106            // add catalog to the list
1107            database.addCatalog(catalog);
1108    
1109            // log
1110            if (traceLog.isDebugEnabled()) {
1111                traceLog.debug(String.format("[Database %s] The catalog '%s' has been added.", database.getName(), catalogName));
1112            }
1113    
1114            return catalog;
1115        }
1116    
1117        /**
1118         * Creates schema based on current record in result set; adds schema to the database
1119         * 
1120         * @param factory the model factory to create table
1121         * @param resultSet the table result set from DatabaseMetadata
1122         * @param traceLog the log to write if any
1123         * @param failOnError
1124         * @param database the owner database
1125         * @return created schema
1126         * @throws Exception if any error occurs and failOnError is true then generates exception
1127         */
1128        public static Schema populateSchema( ModelFactory factory,
1129                                             ResultSet resultSet,
1130                                             Logger traceLog,
1131                                             boolean failOnError,
1132                                             Database database ) throws Exception {
1133            // check for null
1134            if (factory == null) {
1135                throw new IllegalArgumentException("factory");
1136            }
1137    
1138            // check for null
1139            if (database == null) {
1140                throw new IllegalArgumentException("database");
1141            }
1142    
1143            // check for null
1144            if (resultSet == null) {
1145                throw new IllegalArgumentException("resultSet");
1146            }
1147    
1148            // set trace log
1149            if (traceLog == null) {
1150                traceLog = log;
1151            }
1152    
1153            // get schema name
1154            String schemaName = getString(resultSet, "TABLE_SCHEM", false);
1155    
1156            // get catalog name
1157            String catalogName = getString(resultSet, "TABLE_CATALOG", false);
1158    
1159            // create schema object
1160            Schema schema = factory.createSchema();
1161    
1162            // ***************************
1163            // *** DatabaseNamedObject ***
1164            // ***************************
1165    
1166            // set name
1167            schema.setName(schemaName);
1168            // set remarks
1169            // schema.setRemarks (remarks); // N/A
1170            // TODO set extra properties
1171            // schema.addExtraProperty (String key, Object value);
1172    
1173            // ***************
1174            // *** Schema ***
1175            // ***************
1176    
1177            // check catalog name
1178            if (catalogName != null) {
1179                Catalog catalog = database.findCatalogByName(catalogName);
1180                schema.setCatalog(catalog);
1181            }
1182    
1183            // add schema to the list
1184            database.addSchema(schema);
1185    
1186            // log
1187            if (traceLog.isDebugEnabled()) {
1188                traceLog.debug(String.format("[Database %s] The schema '%s' has been added.", database.getName(), schemaName));
1189            }
1190    
1191            return schema;
1192        }
1193    
1194        /**
1195         * Creates table types based on current record in result set; adds table types to the database
1196         * 
1197         * @param factory the model factory to create table
1198         * @param resultSet the table result set from DatabaseMetadata
1199         * @param traceLog the log to write if any
1200         * @param failOnError
1201         * @param database the owner database
1202         * @return created schema
1203         * @throws Exception if any error occurs and failOnError is true then generates exception
1204         */
1205    
1206        public static TableType populateTableType( ModelFactory factory,
1207                                                   ResultSet resultSet,
1208                                                   Logger traceLog,
1209                                                   boolean failOnError,
1210                                                   Database database ) throws Exception {
1211            // check for null
1212            if (factory == null) {
1213                throw new IllegalArgumentException("factory");
1214            }
1215    
1216            // check for null
1217            if (database == null) {
1218                throw new IllegalArgumentException("database");
1219            }
1220    
1221            // check for null
1222            if (resultSet == null) {
1223                throw new IllegalArgumentException("resultSet");
1224            }
1225    
1226            // set trace log
1227            if (traceLog == null) {
1228                traceLog = log;
1229            }
1230    
1231            // get table type
1232            String tableTypeName = getString(resultSet, "TABLE_TYPE", false);
1233    
1234            // create table type object
1235            TableType tableType = factory.createTableType();
1236    
1237            // ***************************
1238            // *** DatabaseNamedObject ***
1239            // ***************************
1240    
1241            // set name
1242            tableType.setName(tableTypeName);
1243            // set remarks
1244            // schema.setRemarks (remarks); // N/A
1245            // TODO set extra properties
1246            // schema.addExtraProperty (String key, Object value);
1247    
1248            // ***************
1249            // *** Table Type ***
1250            // ***************
1251    
1252            // add table type to the list
1253            database.addTableType(tableType);
1254    
1255            // log
1256            if (traceLog.isDebugEnabled()) {
1257                traceLog.debug(String.format("[Database %s] The table type '%s' has been added.", database.getName(), tableType));
1258            }
1259    
1260            return tableType;
1261        }
1262    
1263        /**
1264         * Creates stored procedure based on current record in result set; adds SP to the database
1265         * 
1266         * @param factory the model factory to create SP
1267         * @param resultSet the stored procedure result set from DatabaseMetadata
1268         * @param traceLog the log to write if any
1269         * @param failOnError
1270         * @param database the owner database
1271         * @return created SP
1272         * @throws Exception if any error occurs and failOnError is true then generates exception
1273         */
1274        public static StoredProcedure populateStoredProcedure( ModelFactory factory,
1275                                                               ResultSet resultSet,
1276                                                               Logger traceLog,
1277                                                               boolean failOnError,
1278                                                               Database database ) throws Exception {
1279            // check for null
1280            if (factory == null) {
1281                throw new IllegalArgumentException("factory");
1282            }
1283    
1284            // check for null
1285            if (database == null) {
1286                throw new IllegalArgumentException("database");
1287            }
1288    
1289            // check for null
1290            if (resultSet == null) {
1291                throw new IllegalArgumentException("resultSet");
1292            }
1293    
1294            // set trace log
1295            if (traceLog == null) {
1296                traceLog = log;
1297            }
1298    
1299            // get procedure catalog
1300            String procedureCatalog = getString(resultSet, "PROCEDURE_CAT", false);
1301            // get procedure schema
1302            String procedureSchema = getString(resultSet, "PROCEDURE_SCHEM", false);
1303            // get procedure name
1304            String procedureName = getString(resultSet, "PROCEDURE_NAME", false);
1305            // get remarks
1306            String remarks = getString(resultSet, "REMARKS", false);
1307            // get kind of procedure
1308            Integer procedureType = getInteger(resultSet, "PROCEDURE_TYPE", false);
1309    
1310            // create Stored Procedure object
1311            StoredProcedure sp = factory.createStoredProcedure();
1312    
1313            // ***************************
1314            // *** DatabaseNamedObject ***
1315            // ***************************
1316    
1317            // set name
1318            sp.setName(procedureName);
1319            // set remarks
1320            sp.setRemarks(remarks);
1321            // TODO set extra properties
1322            // sp.addExtraProperty (String key, Object value);
1323    
1324            // ********************
1325            // *** SchemaObject ***
1326            // ********************
1327    
1328            // set catalog
1329            if ((procedureCatalog != null) && (procedureCatalog.trim().length() != 0)) {
1330                // find catalog
1331                Catalog catalog = database.findCatalogByName(procedureCatalog);
1332                // set catalog
1333                sp.setCatalog(catalog);
1334                // warn if null
1335                if (catalog == null) {
1336                    traceLog.debug(String.format("[Database %s] Unable to find catalog '%4$s' for the procedure %s (schema %s, catalog %s)",
1337                                                 database.getName(),
1338                                                 procedureName,
1339                                                 procedureSchema,
1340                                                 procedureCatalog));
1341                }
1342                // if fail is enabled
1343                if (failOnError && (catalog == null)) {
1344                    throw new DatabaseMetaDataMethodException("Catalog name shall be provided", "populateStoredProcedure");
1345                }
1346            }
1347    
1348            // set schema
1349            if ((procedureSchema != null) && (procedureSchema.trim().length() != 0)) {
1350                // find schema
1351                Schema schema = database.findSchemaByName(procedureCatalog, procedureSchema);
1352                // set schema
1353                sp.setSchema(schema);
1354                // warn if null
1355                if (schema == null) {
1356                    traceLog.debug(String.format("[Database %s] Unable to find schema '%3$s' for the procedure %s (schema %s, catalog %s)",
1357                                                 database.getName(),
1358                                                 procedureName,
1359                                                 procedureSchema,
1360                                                 procedureCatalog));
1361                }
1362                // if fail is enabled
1363                if (failOnError && (schema == null)) {
1364                    throw new DatabaseMetaDataMethodException("Schema name shall be provided", "populateStoredProcedure");
1365                }
1366            }
1367    
1368            // ***********************
1369            // *** StoredProcedure ***
1370            // ***********************
1371    
1372            // set sp result type
1373            sp.setResultType(getStoredProcedureResultType(procedureType));
1374    
1375            // add SP to the list
1376            database.addStoredProcedure(sp);
1377    
1378            // log
1379            if (traceLog.isDebugEnabled()) {
1380                traceLog.debug(String.format("[Database %s] The Stored procedure '%s' (schema %s, catalog %s) has been added.",
1381                                             database.getName(),
1382                                             procedureName,
1383                                             procedureSchema,
1384                                             procedureCatalog));
1385            }
1386    
1387            return sp;
1388        }
1389    
1390        /**
1391         * Creates stored procedure parameter based on current record in result set; adds SP parameter to the SP
1392         * 
1393         * @param factory the model factory to create SP parameter
1394         * @param resultSet the stored procedure parameter result set from DatabaseMetadata
1395         * @param traceLog the log to write if any
1396         * @param failOnError
1397         * @param database the owner database
1398         * @param storedProcedure the owner stored procedure
1399         * @param ordinalPosition the parameter ordinal position
1400         * @return created SP parameter
1401         * @throws Exception if any error occurs and failOnError is true then generates exception
1402         */
1403        public static Parameter populateStoredProcedureParameter( ModelFactory factory,
1404                                                                  ResultSet resultSet,
1405                                                                  Logger traceLog,
1406                                                                  boolean failOnError,
1407                                                                  Database database,
1408                                                                  StoredProcedure storedProcedure,
1409                                                                  int ordinalPosition ) throws Exception {
1410            // check for null
1411            if (factory == null) {
1412                throw new IllegalArgumentException("factory");
1413            }
1414    
1415            // check for null
1416            if (database == null) {
1417                throw new IllegalArgumentException("database");
1418            }
1419    
1420            // check for null
1421            if (resultSet == null) {
1422                throw new IllegalArgumentException("resultSet");
1423            }
1424    
1425            // set trace log
1426            if (traceLog == null) {
1427                traceLog = log;
1428            }
1429    
1430            // check for null
1431            if (storedProcedure == null) {
1432                throw new IllegalArgumentException("storedProcedure");
1433            }
1434            // get procedure catalog
1435            String procedureCatalog = (storedProcedure.getCatalog() == null) ? null : storedProcedure.getCatalog().getName();
1436            // get procedure schema
1437            String procedureSchema = (storedProcedure.getSchema() == null) ? null : storedProcedure.getSchema().getName();
1438            // get procedure name
1439            String procedureName = storedProcedure.getName();
1440    
1441            // parameter name
1442            String parameterName = getString(resultSet, "COLUMN_NAME", false);
1443            // parameter i/o type
1444            Integer parameterType = getInteger(resultSet, "COLUMN_TYPE", false);
1445            // data type
1446            Integer dataType = getInteger(resultSet, "DATA_TYPE", false);
1447            // type name
1448            String typeName = getString(resultSet, "TYPE_NAME", false);
1449            // precision
1450            Integer precision = getInteger(resultSet, "PRECISION", false);
1451            // length
1452            Integer length = getInteger(resultSet, "LENGTH", false);
1453            // scale
1454            Integer scale = getInteger(resultSet, "SCALE", false);
1455            // radix
1456            Integer radix = getInteger(resultSet, "RADIX", false);
1457            // nullable
1458            Integer nullableType = getInteger(resultSet, "NULLABLE", false);
1459            // remarks
1460            String remarks = getString(resultSet, "REMARKS", false);
1461    
1462            // create Stored Procedure Parameter object
1463            Parameter parameter = factory.createParameter();
1464    
1465            // ***************************************
1466            // *** DatabaseNamedObject properties ***
1467            // ***************************************
1468    
1469            // name
1470            parameter.setName(parameterName);
1471            // remarks
1472            parameter.setRemarks(remarks);
1473            // TODO set extra properties
1474            // parameter.addExtraProperty (String key, Object value);
1475    
1476            // ***************
1477            // *** Column ***
1478            // ***************
1479    
1480            // owner
1481            parameter.setOwner(storedProcedure);
1482            // nullability
1483            parameter.setNullabilityType(getNullabilityType(nullableType));
1484            // SQL type
1485            parameter.setSqlType(getSqlType(dataType));
1486            // type name
1487            parameter.setTypeName(typeName);
1488            // Size
1489            parameter.setSize(length);
1490            // precision
1491            parameter.setPrecision(precision);
1492            // Radix
1493            parameter.setRadix(radix);
1494            // DefaultValue
1495            parameter.setDefaultValue(null); // not defined among standard columns
1496            // OrdinalPosition
1497            parameter.setOrdinalPosition(ordinalPosition);
1498            // CharOctetLength
1499            parameter.setCharOctetLength(null); // N/A
1500            // addPrivilege
1501            // parameter.addPrivilege (privilege); // N/A
1502    
1503            // *****************
1504            // *** Parameter ***
1505            // *****************
1506    
1507            // i/o type
1508            parameter.setIoType(getParameterIoType(parameterType));
1509            // scale
1510            parameter.setScale(scale);
1511    
1512            // add parameter to the SP
1513            storedProcedure.addParameter(parameter);
1514    
1515            // log
1516            if (traceLog.isDebugEnabled()) {
1517                traceLog.debug(String.format("[Database %s] The Stored procedure '%s' (schema %s, catalog %s) parameter %s has been added.",
1518                                             database.getName(),
1519                                             procedureName,
1520                                             procedureSchema,
1521                                             procedureCatalog,
1522                                             parameterName));
1523            }
1524    
1525            return parameter;
1526        }
1527    
1528        /**
1529         * Creates table based on current record in result set; adds table to the database
1530         * 
1531         * @param factory the model factory to create table
1532         * @param resultSet the table result set from DatabaseMetadata
1533         * @param traceLog the log to write if any
1534         * @param failOnError
1535         * @param database the owner database
1536         * @return created table
1537         * @throws Exception if any error occurs and failOnError is true then generates exception
1538         */
1539        public static Table populateTable( ModelFactory factory,
1540                                           ResultSet resultSet,
1541                                           Logger traceLog,
1542                                           boolean failOnError,
1543                                           Database database ) throws Exception {
1544            // check for null
1545            if (factory == null) {
1546                throw new IllegalArgumentException("factory");
1547            }
1548    
1549            // check for null
1550            if (database == null) {
1551                throw new IllegalArgumentException("database");
1552            }
1553    
1554            // check for null
1555            if (resultSet == null) {
1556                throw new IllegalArgumentException("resultSet");
1557            }
1558    
1559            // set trace log
1560            if (traceLog == null) {
1561                traceLog = log;
1562            }
1563    
1564            // get catalog
1565            String tableCatalog = getString(resultSet, "TABLE_CAT", false);
1566    
1567            // get schema
1568            String tableSchema = getString(resultSet, "TABLE_SCHEM", false);
1569    
1570            // get name
1571            String tableName = getString(resultSet, "TABLE_NAME", false);
1572            // get type
1573            String tableTypeName = getString(resultSet, "TABLE_TYPE", false);
1574            // get remarks
1575            String remarks = getString(resultSet, "REMARKS", false);
1576            // get type catalog
1577            String typeCatalogName = getString(resultSet, "TYPE_CAT", false);
1578    
1579            // get type schema
1580            String typeSchemaName = getString(resultSet, "TYPE_SCHEM", false);
1581            // get type name
1582            String typeName = getString(resultSet, "TYPE_NAME", false);
1583            // get self reeferencing column name
1584            String selfRefColumnName = getString(resultSet, "SELF_REFERENCING_COL_NAME", false);
1585            // get ref generation
1586            String refGeneration = getString(resultSet, "REF_GENERATION", false);
1587    
1588            // create Table object
1589            Table table = factory.createTable();
1590    
1591            // ***************************
1592            // *** DatabaseNamedObject ***
1593            // ***************************
1594    
1595            // set name
1596            table.setName(tableName);
1597            // set remarks
1598            table.setRemarks(remarks);
1599            // TODO set extra properties
1600            // table.addExtraProperty (String key, Object value);
1601    
1602            // ********************
1603            // *** SchemaObject ***
1604            // ********************
1605    
1606            // set catalog
1607            if ((tableCatalog != null) && (tableCatalog.trim().length() != 0)) {
1608                // find catalog
1609                Catalog catalog = database.findCatalogByName(tableCatalog);
1610                // set catalog
1611                table.setCatalog(catalog);
1612                // warn if null
1613                if (catalog == null) {
1614                    traceLog.debug(String.format("[Database %s] Unable to find catalog '%4$s' for the table %s (schema %s, catalog %s)",
1615                                                 database.getName(),
1616                                                 tableName,
1617                                                 tableSchema,
1618                                                 tableCatalog));
1619                }
1620                // if fail is enabled
1621                if (failOnError) {
1622                    throw new DatabaseMetaDataMethodException("Catalog name shall be provided", "populateTable");
1623    
1624                }
1625            }
1626    
1627            // set schema
1628            if ((tableSchema != null) && (tableSchema.trim().length() != 0)) {
1629                // find schema
1630                Schema schema = database.findSchemaByName(tableCatalog, tableSchema);
1631                // set schema
1632                table.setSchema(schema);
1633                // warn if null
1634                if (schema == null) {
1635                    traceLog.debug(String.format("[Database %s] Unable to find schema '%3$s' for the table %s (schema %s, catalog %s)",
1636                                                 database.getName(),
1637                                                 tableName,
1638                                                 tableSchema,
1639                                                 tableCatalog));
1640                }
1641                // if fail is enabled
1642                if (failOnError) {
1643                    throw new DatabaseMetaDataMethodException("Table name shall be provided", "populateTable");
1644                }
1645            }
1646    
1647            // **************
1648            // *** Table ***
1649            // **************
1650    
1651            // set table type
1652            if (tableTypeName != null) {
1653                // create
1654                TableType tableType = factory.createTableType();
1655                // fill
1656                tableType.setName(tableTypeName);
1657                // set type
1658                table.setTableType(tableType);
1659            }
1660    
1661            // set catalog
1662            if ((typeCatalogName != null) && (typeCatalogName.trim().length() != 0)) {
1663                // find catalog
1664                Catalog typeCatalog = database.findCatalogByName(typeCatalogName);
1665                // set type catalog
1666                table.setTypeCatalog(typeCatalog);
1667                // warn if null
1668                if (typeCatalog == null) {
1669                    traceLog.debug(String.format("[Database %s] Unable to find catalog '%4$s' for the table %s (schema %s, catalog %s)",
1670                                                 database.getName(),
1671                                                 tableName,
1672                                                 tableSchema,
1673                                                 typeCatalogName));
1674                }
1675            }
1676    
1677            // set schema
1678            if ((typeSchemaName != null) && (typeSchemaName.trim().length() != 0)) {
1679                // find schema
1680                Schema typeSchema = database.findSchemaByName(typeCatalogName, typeSchemaName);
1681                // set schema
1682                table.setTypeSchema(typeSchema);
1683                // warn if null
1684                if (typeSchema == null) {
1685                    traceLog.debug(String.format("[Database %s] Unable to find schema '%3$s' for the table %s (schema %s, catalog %s)",
1686                                                 database.getName(),
1687                                                 tableName,
1688                                                 typeSchemaName,
1689                                                 typeCatalogName));
1690                }
1691                // if fail is enabled
1692                if (failOnError && (typeSchema == null)) {
1693                    throw new DatabaseMetaDataMethodException("Schema name shall be provided", "populateTable");
1694                }
1695            }
1696    
1697            // set type name
1698            table.setTypeName(typeName);
1699            // set self referencing column name
1700            table.setSelfReferencingColumnName(selfRefColumnName);
1701            // set reference generation
1702            table.setReferenceGeneration(refGeneration);
1703    
1704            // add table to the list
1705            database.addTable(table);
1706    
1707            // log
1708            if (traceLog.isDebugEnabled()) {
1709                traceLog.debug(String.format("[Database %s] The table '%s' (schema %s, catalog %s) has been added.",
1710                                             database.getName(),
1711                                             tableName,
1712                                             tableSchema,
1713                                             tableCatalog));
1714            }
1715    
1716            return table;
1717        }
1718    
1719        /**
1720         * Creates table column based on current record in result set; adds column to the table
1721         * 
1722         * @param factory the model factory to create SP parameter
1723         * @param resultSet the stored procedure parameter result set from DatabaseMetadata
1724         * @param traceLog the log to write if any
1725         * @param failOnError
1726         * @param database the owner database
1727         * @param table the owner table
1728         * @return created table column
1729         * @throws Exception if any error occurs and failOnError is true then generates exception
1730         */
1731        public static TableColumn populateTableColumn( ModelFactory factory,
1732                                                       ResultSet resultSet,
1733                                                       Logger traceLog,
1734                                                       boolean failOnError,
1735                                                       Database database,
1736                                                       Table table ) throws Exception {
1737            // check for null
1738            if (factory == null) {
1739                throw new IllegalArgumentException("factory");
1740            }
1741    
1742            // check for null
1743            if (database == null) {
1744                throw new IllegalArgumentException("database");
1745            }
1746    
1747            // check for null
1748            if (resultSet == null) {
1749                throw new IllegalArgumentException("resultSet");
1750            }
1751    
1752            // set trace log
1753            if (traceLog == null) {
1754                traceLog = log;
1755            }
1756    
1757            // check for null
1758            if (table == null) {
1759                throw new IllegalArgumentException("table");
1760            }
1761            // get catalog name
1762            String catalogName = (table.getCatalog() == null) ? null : table.getCatalog().getName();
1763            // get schema name
1764            String schemaName = (table.getSchema() == null) ? null : table.getSchema().getName();
1765            // get table name
1766            String tableName = table.getName();
1767    
1768            // column name
1769            String columnName = getString(resultSet, "COLUMN_NAME", false);
1770            // data type
1771            Integer dataType = getInteger(resultSet, "DATA_TYPE", false);
1772            // type name
1773            String typeName = getString(resultSet, "TYPE_NAME", false);
1774            // size
1775            Integer size = getInteger(resultSet, "COLUMN_SIZE", false);
1776            // precision
1777            Integer precision = getInteger(resultSet, "DECIMAL_DIGITS", false);
1778            // radix
1779            Integer radix = getInteger(resultSet, "NUM_PREC_RADIX", false);
1780            // nullable
1781            Integer nullableType = getInteger(resultSet, "NULLABLE", false);
1782            // remarks
1783            String remarks = getString(resultSet, "REMARKS", false);
1784            // default value
1785            String defaultValue = getString(resultSet, "COLUMN_DEF", false);
1786            // character Octet Length
1787            Integer charOctetLength = getInteger(resultSet, "CHAR_OCTET_LENGTH", false);
1788            // ordinal position
1789            Integer ordinalPosition = getInteger(resultSet, "ORDINAL_POSITION", false);
1790            // is nullable string
1791            // String isNullableString = getString(resultSet, "IS_NULLABLE", false);
1792            // scope catalog
1793            String scopeCatalog = getString(resultSet, "SCOPE_CATLOG", false);
1794            // scope schema
1795            String scopeSchema = getString(resultSet, "SCOPE_SCHEMA", false);
1796            // scope table
1797            String scopeTable = getString(resultSet, "SCOPE_TABLE", false);
1798            // sourceDataType
1799            Integer sourceDataType = getInteger(resultSet, "SOURCE_DATA_TYPE", false);
1800    
1801            // create table column object
1802            TableColumn column = factory.createTableColumn();
1803    
1804            // ***************************************
1805            // *** DatabaseNamedObject properties ***
1806            // ***************************************
1807    
1808            // name
1809            column.setName(columnName);
1810            // remarks
1811            column.setRemarks(remarks);
1812            // TODO set extra properties
1813            // column.addExtraProperty (String key, Object value);
1814    
1815            // ***************
1816            // *** Column ***
1817            // ***************
1818    
1819            // owner
1820            column.setOwner(table);
1821            // nullability. The isNullableString is not used so far
1822            column.setNullabilityType(getNullabilityType(nullableType));
1823            // SQL type
1824            column.setSqlType(getSqlType(dataType));
1825            // type name
1826            column.setTypeName(typeName);
1827            // Size
1828            column.setSize(size);
1829            // precision
1830            column.setPrecision(precision);
1831            // Radix
1832            column.setRadix(radix);
1833            // DefaultValue
1834            column.setDefaultValue(defaultValue);
1835            // OrdinalPosition
1836            column.setOrdinalPosition(ordinalPosition);
1837            // CharOctetLength
1838            column.setCharOctetLength(charOctetLength);
1839            // addPrivilege
1840            // column.addPrivilege (privilege); //
1841    
1842            // ********************
1843            // *** Table Column ***
1844            // ********************
1845    
1846            // pseudo type
1847            column.setPseudoType(ColumnPseudoType.NOT_PSEUDO);
1848    
1849            // set reference
1850            if ((scopeCatalog != null) || (scopeSchema != null) || (scopeTable != null) || (sourceDataType != null)) {
1851                // create reference
1852                Reference reference = factory.createReference();
1853                // set Source Data Type
1854                reference.setSourceDataType(getSqlType(sourceDataType));
1855                // find table and set as source
1856                reference.setSourceTable(database.findTableByName(scopeCatalog, scopeSchema, scopeTable));
1857    
1858                // set reference
1859                column.setReference(reference);
1860            }
1861    
1862            // add column to the table
1863            table.addColumn(column);
1864    
1865            // log
1866            if (traceLog.isDebugEnabled()) {
1867                traceLog.debug(String.format("[Database %s] The table '%s' (schema %s, catalog %s) column %s has been added.",
1868                                             database.getName(),
1869                                             tableName,
1870                                             schemaName,
1871                                             catalogName,
1872                                             columnName));
1873            }
1874    
1875            return column;
1876        }
1877    
1878        /**
1879         * Creates table best row identifier based on current record in result set; adds best row identifier to the table
1880         * 
1881         * @param factory the model factory to create SP parameter
1882         * @param resultSet the stored procedure parameter result set from DatabaseMetadata
1883         * @param traceLog the log to write if any
1884         * @param failOnError
1885         * @param database the owner database
1886         * @param table the owner table
1887         * @return created table best row identifier
1888         * @throws Exception if any error occurs and failOnError is true then generates exception
1889         */
1890        public static BestRowIdentifier populateBestRowIdentifier( ModelFactory factory,
1891                                                                   ResultSet resultSet,
1892                                                                   Logger traceLog,
1893                                                                   boolean failOnError,
1894                                                                   Database database,
1895                                                                   Table table ) throws Exception {
1896            // check for null
1897            if (factory == null) {
1898                throw new IllegalArgumentException("factory");
1899            }
1900    
1901            // check for null
1902            if (database == null) {
1903                throw new IllegalArgumentException("database");
1904            }
1905    
1906            // check for null
1907            if (resultSet == null) {
1908                throw new IllegalArgumentException("resultSet");
1909            }
1910    
1911            // set trace log
1912            if (traceLog == null) {
1913                traceLog = log;
1914            }
1915    
1916            // check for null
1917            if (table == null) {
1918                throw new IllegalArgumentException("table");
1919            }
1920            // get catalog name
1921            String catalogName = (table.getCatalog() == null) ? null : table.getCatalog().getName();
1922            // get schema name
1923            String schemaName = (table.getSchema() == null) ? null : table.getSchema().getName();
1924            // get table name
1925            String tableName = table.getName();
1926    
1927            // scope type
1928            Integer scope = getInteger(resultSet, "SCOPE", false);
1929            // column name
1930            String columnName = getString(resultSet, "COLUMN_NAME", false);
1931            // data type
1932            Integer dataType = getInteger(resultSet, "DATA_TYPE", false);
1933            // type name
1934            String typeName = getString(resultSet, "TYPE_NAME", false);
1935            // precision
1936            Integer precision = getInteger(resultSet, "COLUMN_SIZE", false);
1937            // scale
1938            Integer scale = getInteger(resultSet, "DECIMAL_DIGITS", false);
1939            // pseudoColumn
1940            Integer pseudoColumn = getInteger(resultSet, "PSEUDO_COLUMN", false);
1941    
1942            // *************************************
1943            // *** BestRowIdentifier properties ***
1944            // *************************************
1945    
1946            // get scope type
1947            BestRowIdentifierScopeType scopeType = getBestRowIdentifierScopeType(scope);
1948    
1949            // check not null
1950            if (scopeType == null) {
1951                // if exception generation is enabled then raise exception - invalid scope
1952                if (failOnError == true) {
1953                    throw new IllegalArgumentException("scopeType");
1954                }
1955                return null;
1956            }
1957    
1958            // find table best row identifier object
1959            BestRowIdentifier brId = table.findBestRowIdentifierByScopeType(scopeType);
1960            // check if null
1961            if (brId == null) {
1962                // create
1963                brId = factory.createBestRowIdentifier();
1964            }
1965    
1966            // set scope type
1967            brId.setScopeType(scopeType);
1968    
1969            // determine if current record shows pseudo column
1970            boolean isPseudoColumn = ((getColumnPseudoType(pseudoColumn) != null) && (getColumnPseudoType(pseudoColumn) == ColumnPseudoType.PSEUDO));
1971    
1972            TableColumn column = null;
1973    
1974            if (isPseudoColumn) {
1975                // create
1976                column = factory.createTableColumn();
1977    
1978                // ***************************************
1979                // *** DatabaseNamedObject properties ***
1980                // ***************************************
1981    
1982                // name
1983                column.setName(columnName);
1984                // remarks
1985                // column.setRemarks (remarks); // N/A
1986                // TODO set extra properties
1987                // column.addExtraProperty (String key, Object value);
1988    
1989                // ***************
1990                // *** Column ***
1991                // ***************
1992    
1993                // owner
1994                column.setOwner(table);
1995                // SQL type
1996                column.setSqlType(getSqlType(dataType));
1997                // type name
1998                column.setTypeName(typeName);
1999                // precision
2000                column.setPrecision(precision);
2001                // size
2002                column.setSize(precision);
2003                // scale
2004                column.setRadix(scale);
2005                // pseudo type
2006                column.setPseudoType(getColumnPseudoType(pseudoColumn));
2007                // add to the table
2008                table.addColumn(column);
2009            } else {
2010                // trying to find column
2011                column = table.findColumnByName(columnName);
2012    
2013                // if column exists
2014                if (column != null) {
2015                    // pseudo type
2016                    column.setPseudoType(getColumnPseudoType(pseudoColumn));
2017                }
2018            }
2019    
2020            // if column exists
2021            if (column != null) {
2022                // add to the best row identifier
2023                brId.addColumn(column);
2024            }
2025    
2026            // add best row identifier to the table
2027            table.addBestRowIdentifier(brId);
2028    
2029            // get scope type string
2030            String scopeName = (brId.getScopeType() == null) ? null : brId.getScopeType().getName();
2031    
2032            // log
2033            if (traceLog.isDebugEnabled()) {
2034                traceLog.debug(String.format("[Database %s] The table '%s' (schema %s, catalog %s) best row identifier with scope %s has been added.",
2035                                             database.getName(),
2036                                             tableName,
2037                                             schemaName,
2038                                             catalogName,
2039                                             scopeName));
2040            }
2041    
2042            return brId;
2043        }
2044    
2045        /**
2046         * Creates table's primary key based on ALL records in result set; adds pk columns to the table's primary key
2047         * 
2048         * @param factory the model factory to create SP parameter
2049         * @param resultSet the stored procedure parameter result set from DatabaseMetadata
2050         * @param traceLog the log to write if any
2051         * @param failOnError
2052         * @param database the owner database
2053         * @param table the owner table
2054         * @return created primary key
2055         * @throws Exception if any error occurs and failOnError is true then generates exception
2056         */
2057        public static PrimaryKey populatePrimaryKey( ModelFactory factory,
2058                                                     ResultSet resultSet,
2059                                                     Logger traceLog,
2060                                                     boolean failOnError,
2061                                                     Database database,
2062                                                     Table table ) throws Exception {
2063            // check for null
2064            if (factory == null) {
2065                throw new IllegalArgumentException("factory");
2066            }
2067    
2068            // check for null
2069            if (database == null) {
2070                throw new IllegalArgumentException("database");
2071            }
2072    
2073            // check for null
2074            if (resultSet == null) {
2075                throw new IllegalArgumentException("resultSet");
2076            }
2077    
2078            // set trace log
2079            if (traceLog == null) {
2080                traceLog = log;
2081            }
2082    
2083            // check for null
2084            if (table == null) {
2085                throw new IllegalArgumentException("table");
2086            }
2087            // get catalog name
2088            String catalogName = (table.getCatalog() == null) ? null : table.getCatalog().getName();
2089            // get schema name
2090            String schemaName = (table.getSchema() == null) ? null : table.getSchema().getName();
2091            // get table name
2092            String tableName = table.getName();
2093            // pk name
2094            String primaryKeyName = null; // initially null
2095    
2096            // create table's primary key
2097            PrimaryKey pk = factory.createPrimaryKey();
2098    
2099            // ***************************
2100            // *** DatabaseNamedObject ***
2101            // ***************************
2102    
2103            // set name
2104            // pk.setName (primaryKeyName); // it will be overriden later in this code
2105            // set remarks
2106            // pk.setRemarks (remarks); // N/A
2107    
2108            // TODO set extra properties
2109            // table.addExtraProperty (String key, Object value);
2110    
2111            // ********************
2112            // *** SchemaObject ***
2113            // ********************
2114    
2115            // set catalog
2116            pk.setCatalog(table.getCatalog());
2117            // set schema
2118            pk.setSchema(table.getSchema());
2119    
2120            // process all columns included into primary key
2121            while (resultSet.next()) {
2122                // get PK name
2123                if (primaryKeyName == null) {
2124                    primaryKeyName = getString(resultSet, "PK_NAME", false);
2125                    // set name
2126                    pk.setName(primaryKeyName);
2127                }
2128    
2129                // column name
2130                String columnName = getString(resultSet, "COLUMN_NAME", false);
2131                // sequence number within primary key
2132                Integer ordinalPosition = getInteger(resultSet, "KEY_SEQ", false);
2133    
2134                // trying to find table column with specified name
2135                TableColumn tableColumn = table.findColumnByName(columnName);
2136    
2137                String errMessage = null;
2138                // warn if null
2139                if (tableColumn == null) {
2140                    errMessage = String.format("[Database %s] Unable to find table column '%5$s' for the table %s (schema %s, catalog %s)",
2141                                               database.getName(),
2142                                               tableName,
2143                                               schemaName,
2144                                               catalogName,
2145                                               columnName);
2146                    traceLog.debug(errMessage);
2147                }
2148                // if fail is enabled
2149                if (failOnError && (tableColumn == null)) {
2150                    throw new DatabaseMetaDataMethodException(errMessage, "populatePrimaryKey");
2151                }
2152    
2153                // create PK column
2154                PrimaryKeyColumn pkColumn = factory.createPrimaryKeyColumn();
2155                // check if we found the original table column
2156                if (tableColumn != null) {
2157                    // mark original table column as part of PK
2158                    tableColumn.setPrimaryKeyColumn(Boolean.TRUE);
2159                    // clone properties from original table column to the pkcolumn
2160                    PropertyUtils.copyProperties(pkColumn, tableColumn);
2161                } else { // recovery if table column is not found but we still want to create pk column
2162                    // set name at least
2163                    pkColumn.setName(columnName);
2164                }
2165                // modify ordinal position that correspond to the position in PK
2166                pkColumn.setOrdinalPosition(ordinalPosition);
2167    
2168                // add PK column to the primary key
2169                pk.addColumn(pkColumn);
2170            }
2171    
2172            // set table primary key
2173            table.setPrimaryKey(pk);
2174    
2175            // log
2176            if (traceLog.isDebugEnabled()) {
2177                traceLog.debug(String.format("[Database %s] The table '%s' (schema %s, catalog %s) primary key %s has been added.",
2178                                             database.getName(),
2179                                             tableName,
2180                                             schemaName,
2181                                             catalogName,
2182                                             primaryKeyName));
2183            }
2184    
2185            return pk;
2186        }
2187    
2188        /**
2189         * Creates table's foreign keys based on ALL records in result set; adds fk columns to the table's foreing key
2190         * 
2191         * @param factory the model factory to create SP parameter
2192         * @param resultSet the stored procedure parameter result set from DatabaseMetadata
2193         * @param traceLog the log to write if any
2194         * @param failOnError
2195         * @param database the owner database
2196         * @param table the owner table
2197         * @return created list of foreign keys
2198         * @throws Exception if any error occurs and failOnError is true then generates exception
2199         */
2200        public static Set<ForeignKey> populateForeignKeys( ModelFactory factory,
2201                                                           ResultSet resultSet,
2202                                                           Logger traceLog,
2203                                                           boolean failOnError,
2204                                                           Database database,
2205                                                           Table table ) throws Exception {
2206            // check for null
2207            if (factory == null) {
2208                throw new IllegalArgumentException("factory");
2209            }
2210    
2211            // check for null
2212            if (database == null) {
2213                throw new IllegalArgumentException("database");
2214            }
2215    
2216            // check for null
2217            if (resultSet == null) {
2218                throw new IllegalArgumentException("resultSet");
2219            }
2220    
2221            // set trace log
2222            if (traceLog == null) {
2223                traceLog = log;
2224            }
2225    
2226            // check for null
2227            if (table == null) {
2228                throw new IllegalArgumentException("table");
2229            }
2230            // get catalog name
2231            String catalogName = (table.getCatalog() == null) ? null : table.getCatalog().getName();
2232            // get schema name
2233            String schemaName = (table.getSchema() == null) ? null : table.getSchema().getName();
2234            // get table name
2235            String tableName = table.getName();
2236    
2237            // create table's foreign key
2238            ForeignKey fk = factory.createForeignKey();
2239    
2240            // process all columns included into foreign key
2241            while (resultSet.next()) {
2242                // primary key table catalog being imported
2243                String pkTableCatalogName = getString(resultSet, "PKTABLE_CAT", false);
2244                // primary key table schema being imported
2245                String pkTableSchemaName = getString(resultSet, "PKTABLE_SCHEM", false);
2246                // primary key table name being imported
2247                String pkTableName = getString(resultSet, "PKTABLE_NAME", false);
2248                // primary key column name being imported
2249                String pkColumnName = getString(resultSet, "PKCOLUMN_NAME", false);
2250    
2251                // FK table name, schema and catalog are already known, so it is useless to fetch
2252    
2253                // foreign key column name
2254                String fkColumnName = getString(resultSet, "FKCOLUMN_NAME", false);
2255                // sequence number within foreign key
2256                Integer ordinalPosition = getInteger(resultSet, "KEY_SEQ", false);
2257                // update rule - What happens to a foreign key when the primary key is updated
2258                Integer updateRule = getInteger(resultSet, "UPDATE_RULE", false);
2259                // delete rule - What happens to the foreign key when primary is deleted
2260                Integer deleteRule = getInteger(resultSet, "DELETE_RULE", false);
2261                // foreign key name
2262                String foreignKeyName = getString(resultSet, "FK_NAME", false);
2263                // primary key name
2264                //String primaryKeyName = getString(resultSet, "PK_NAME", false);
2265                // can the evaluation of foreign key constraints be deferred until commit
2266                Integer defferability = getInteger(resultSet, "DEFERRABILITY", false);
2267    
2268                //
2269                // check if FK name has been set earlier and current record shows different FK -
2270                // so we need to add FK (previous) to the table
2271                //
2272                if ((fk.getName() != null) && (!fk.getName().equals(foreignKeyName))) {
2273                    // add previous FK to the table
2274                    table.addForeignKey(fk);
2275    
2276                    // log
2277                    if (traceLog.isTraceEnabled()) {
2278                        traceLog.trace(String.format("[Database %s] The table '%s' (schema %s, catalog %s) foreign key %s has been added.",
2279                                                     database.getName(),
2280                                                     tableName,
2281                                                     schemaName,
2282                                                     catalogName,
2283                                                     foreignKeyName));
2284                    }
2285    
2286                    // create new FK if a record is not last
2287                    fk = factory.createForeignKey();
2288                } else {
2289    
2290                    // ***************************
2291                    // *** DatabaseNamedObject ***
2292                    // ***************************
2293    
2294                    // set FK name
2295                    fk.setName(foreignKeyName);
2296                    // set remarks
2297                    // fk.setRemarks (remarks); // N/A
2298    
2299                    // TODO set extra properties
2300                    // fk.addExtraProperty (String key, Object value);
2301    
2302                    // ********************
2303                    // *** SchemaObject ***
2304                    // ********************
2305    
2306                    // set catalog
2307                    fk.setCatalog(table.getCatalog());
2308                    // set schema
2309                    fk.setSchema(table.getSchema());
2310    
2311                    // ***************************
2312                    // *** ForeignKey ***
2313                    // ***************************
2314    
2315                    // trying to find table column with specified name
2316                    TableColumn tableColumn = table.findColumnByName(fkColumnName);
2317    
2318                    String errMessage = null;
2319                    // warn if null
2320                    if (tableColumn == null) {
2321                        errMessage = String.format("[Database %s] Unable to find table column '%5$s' for the table %s (schema %s, catalog %s)",
2322                                                   database.getName(),
2323                                                   tableName,
2324                                                   schemaName,
2325                                                   catalogName,
2326                                                   fkColumnName);
2327                        traceLog.debug(errMessage);
2328                    }
2329                    // if fail is enabled
2330                    if (failOnError && (tableColumn == null)) {
2331                        throw new DatabaseMetaDataMethodException(errMessage, "populateForeignKeys");
2332                    }
2333    
2334                    // create FK column
2335                    ForeignKeyColumn fkColumn = factory.createForeignKeyColumn();
2336    
2337                    // check if we found the original table column
2338                    if (tableColumn != null) {
2339                        // mark original table column as part of FK
2340                        tableColumn.setForeignKeyColumn(Boolean.TRUE);
2341                        // clone properties from original table column to the fkcolumn
2342                        PropertyUtils.copyProperties(fkColumn, tableColumn);
2343                    } else { // recovery if table column is not found but we still want to create fk column
2344                        // set name at least
2345                        fkColumn.setName(fkColumnName);
2346                    }
2347                    // modify ordinal position that correspond to the position in FK
2348                    fkColumn.setOrdinalPosition(ordinalPosition);
2349    
2350                    // check for PK table and corresponding PK column
2351                    Table pkTable = database.findTableByName(pkTableCatalogName, pkTableSchemaName, pkTableName);
2352                    // sets the scope table of a foreign key.
2353                    fk.setSourceTable(pkTable);
2354                    // find PK
2355                    PrimaryKey pk = (pkTable == null) ? null : pkTable.getPrimaryKey();
2356                    // set
2357                    fk.setSourcePrimaryKey(pk);
2358    
2359                    // What happens to a foreign key when the primary key is updated
2360                    fk.setUpdateRule(getKeyModifyRuleType(updateRule));
2361                    // What happens to a foreign key when the primary key is deleted
2362                    fk.setDeleteRule(getKeyModifyRuleType(deleteRule));
2363                    // Can the evaluation of foreign key constraints be deferred until commit
2364                    fk.setDeferrability(getKeyDeferrabilityType(defferability));
2365    
2366                    // find PK table column
2367                    TableColumn pkColumn = (pkTable == null) ? null : pkTable.findColumnByName(pkColumnName);
2368                    // Sets mapped source column (in PK/source table) for this foreign key column
2369                    fkColumn.setSourceColumn(pkColumn);
2370    
2371                    // add FK column to the foreign key
2372                    fk.addColumn(fkColumn);
2373                }
2374            }
2375    
2376            // add FK to the table
2377            table.addForeignKey(fk);
2378            // log
2379            if (traceLog.isDebugEnabled()) {
2380                traceLog.debug(String.format("[Database %s] The table '%s' (schema %s, catalog %s) foreign key %s has been added.",
2381                                             database.getName(),
2382                                             tableName,
2383                                             schemaName,
2384                                             catalogName,
2385                                             fk.getName()));
2386            }
2387    
2388            // return set of created FK
2389            return table.getForeignKeys();
2390        }
2391    
2392        /**
2393         * Creates table's indexes based on ALL records in result set; adds columns to the table's index
2394         * 
2395         * @param factory the model factory to create SP parameter
2396         * @param resultSet the stored procedure parameter result set from DatabaseMetadata
2397         * @param traceLog the log to write if any
2398         * @param failOnError
2399         * @param database the owner database
2400         * @param table the owner table
2401         * @return created list of index
2402         * @throws Exception if any error occurs and failOnError is true then generates exception
2403         */
2404        public static Set<Index> populateIndexes( ModelFactory factory,
2405                                                  ResultSet resultSet,
2406                                                  Logger traceLog,
2407                                                  boolean failOnError,
2408                                                  Database database,
2409                                                  Table table ) throws Exception {
2410            // check for null
2411            if (factory == null) {
2412                throw new IllegalArgumentException("factory");
2413            }
2414    
2415            // check for null
2416            if (database == null) {
2417                throw new IllegalArgumentException("database");
2418            }
2419    
2420            // check for null
2421            if (resultSet == null) {
2422                throw new IllegalArgumentException("resultSet");
2423            }
2424    
2425            // set trace log
2426            if (traceLog == null) {
2427                traceLog = log;
2428            }
2429    
2430            // check for null
2431            if (table == null) {
2432                throw new IllegalArgumentException("table");
2433            }
2434            // get catalog name
2435            String catalogName = (table.getCatalog() == null) ? null : table.getCatalog().getName();
2436            // get schema name
2437            String schemaName = (table.getSchema() == null) ? null : table.getSchema().getName();
2438            // get table name
2439            String tableName = table.getName();
2440    
2441            // create table's index
2442            Index index = factory.createIndex();
2443    
2444            // process all columns included into index
2445            while (resultSet.next()) {
2446                // table name, schema and catalog are already known, so it is useless to fetch
2447    
2448                // Can index values be non-unique
2449                Boolean nonUnique = getBoolean(resultSet, "NON_UNIQUE", false);
2450                // index catalog
2451                String indexQualifier = getString(resultSet, "INDEX_QUALIFIER", false);
2452                // index name ; null when TYPE is tableIndexStatistic
2453                String indexName = getString(resultSet, "INDEX_NAME", false);
2454                // index type
2455                Integer indexType = getInteger(resultSet, "TYPE", false);
2456                // sequence number within index
2457                Integer ordinalPosition = getInteger(resultSet, "ORDINAL_POSITION", false);
2458                // index column name
2459                String indexColumnName = getString(resultSet, "COLUMN_NAME", false);
2460                // column sort sequence, "A" => ascending, "D" => descending, may be null if sort sequence is not supported;
2461                // null when TYPE is tableIndexStatistic
2462                String ascOrDesc = getString(resultSet, "ASC_OR_DESC", false);
2463                // cardinality; When TYPE is tableIndexStatistic, then this is the number of rows in the table;
2464                // otherwise, it is the number of unique values in the index.
2465                Integer cardinality = getInteger(resultSet, "CARDINALITY", false);
2466                // pages; When TYPE is tableIndexStatisic then this is the number of pages used for the table,
2467                // otherwise it is the number of pages used for the current index.
2468                Integer pages = getInteger(resultSet, "PAGES", false);
2469                // filter condition if any (may be null)
2470                String filterCondition = getString(resultSet, "FILTER_CONDITION", false);
2471    
2472                //
2473                // check if index name has been set earlier and current record shows different index -
2474                // so we need to add index (previous) to the table
2475                //
2476                if ((index.getName() != null) && (!index.getName().equals(indexName))) {
2477                    // add previous FK to the table
2478                    table.addIndex(index);
2479    
2480                    // log
2481                    if (traceLog.isDebugEnabled()) {
2482                        traceLog.debug(String.format("[Database %s] The table '%s' (schema %s, catalog %s) index %s has been added.",
2483                                                     database.getName(),
2484                                                     tableName,
2485                                                     schemaName,
2486                                                     catalogName,
2487                                                     indexName));
2488                    }
2489    
2490                    // create new index if a record is not last
2491                    index = factory.createIndex();
2492                } else {
2493    
2494                    // ***************************
2495                    // *** DatabaseNamedObject ***
2496                    // ***************************
2497    
2498                    // set name
2499                    index.setName(indexName);
2500                    // set remarks
2501                    // index.setRemarks (remarks); // N/A
2502    
2503                    // TODO set extra properties
2504                    // index.addExtraProperty (String key, Object value);
2505    
2506                    // ********************
2507                    // *** SchemaObject ***
2508                    // ********************
2509    
2510                    // set catalog; index catalog me be defined by indexQualifier
2511                    index.setCatalog((indexQualifier == null) ? table.getCatalog() : database.findCatalogByName(indexQualifier));
2512                    // set schema
2513                    index.setSchema(table.getSchema());
2514    
2515                    // ***************************
2516                    // *** Index ***
2517                    // ***************************
2518    
2519                    // set unique as inversion of non unique
2520                    index.setUnique(nonUnique == null ? null : (nonUnique.booleanValue() == true) ? Boolean.FALSE : Boolean.TRUE);
2521                    // set Index Type
2522                    index.setIndexType(getIndexType(indexType));
2523                    // set Cardinality
2524                    index.setCardinality(cardinality);
2525                    // set Pages
2526                    index.setPages(pages);
2527                    // set filter condition
2528                    index.setFilterCondition(filterCondition);
2529    
2530                    // trying to find table column with specified name
2531                    TableColumn tableColumn = table.findColumnByName(indexColumnName);
2532    
2533                    String errMessage = null;
2534                    // warn if null
2535                    if (tableColumn == null) {
2536                        errMessage = String.format("[Database %s] Unable to find table column '%5$s' for the table %s (schema %s, catalog %s)",
2537                                                   database.getName(),
2538                                                   tableName,
2539                                                   schemaName,
2540                                                   catalogName,
2541                                                   indexColumnName);
2542                        traceLog.debug(errMessage);
2543                    }
2544                    // if fail is enabled
2545                    if (failOnError && (tableColumn == null)) {
2546                        throw new DatabaseMetaDataMethodException(errMessage, "populateIndexes");
2547    
2548                    }
2549    
2550                    // create index column
2551                    IndexColumn indexColumn = factory.createIndexColumn();
2552    
2553                    // check if we found the original table column
2554                    if (tableColumn != null) {
2555                        // mark original table column as part of index
2556                        tableColumn.setIndexColumn(Boolean.TRUE);
2557                        // clone properties from original table column to the index column
2558                        PropertyUtils.copyProperties(indexColumn, tableColumn);
2559                    } else { // recovery if table column is not found but we still want to create index column
2560                        // set name at least
2561                        indexColumn.setName(indexColumnName);
2562                    }
2563                    // modify ordinal position that correspond to the position in index
2564                    indexColumn.setOrdinalPosition(ordinalPosition);
2565                    // sort sequence type
2566                    indexColumn.setSortSequenceType(getSortSequenceType(ascOrDesc));
2567    
2568                    // add index column to the index
2569                    index.addColumn(indexColumn);
2570                }
2571    
2572            }
2573    
2574            // add index to the table
2575            table.addIndex(index);
2576            // log
2577            if (traceLog.isDebugEnabled()) {
2578                traceLog.debug(String.format("[Database %s] The table '%s' (schema %s, catalog %s) index %s has been added.",
2579                                             database.getName(),
2580                                             tableName,
2581                                             schemaName,
2582                                             catalogName,
2583                                             index.getName()));
2584            }
2585    
2586            // return set of created indexes
2587            return table.getIndexes();
2588        }
2589    
2590        /**
2591         * Creates table's version column (if pseudo) based on current record in result set; adds column to the table
2592         * 
2593         * @param factory the model factory to create SP parameter
2594         * @param resultSet the stored procedure parameter result set from DatabaseMetadata
2595         * @param traceLog the log to write if any
2596         * @param failOnError
2597         * @param database the owner database
2598         * @param table the owner table
2599         * @return created/updated version table column
2600         * @throws Exception if any error occurs and failOnError is true then generates exception
2601         */
2602        public static TableColumn populateVersionColumn( ModelFactory factory,
2603                                                         ResultSet resultSet,
2604                                                         Logger traceLog,
2605                                                         boolean failOnError,
2606                                                         Database database,
2607                                                         Table table ) throws Exception {
2608            // check for null
2609            if (factory == null) {
2610                throw new IllegalArgumentException("factory");
2611            }
2612    
2613            // check for null
2614            if (database == null) {
2615                throw new IllegalArgumentException("database");
2616            }
2617    
2618            // check for null
2619            if (resultSet == null) {
2620                throw new IllegalArgumentException("resultSet");
2621            }
2622    
2623            // set trace log
2624            if (traceLog == null) {
2625                traceLog = log;
2626            }
2627    
2628            // check for null
2629            if (table == null) {
2630                throw new IllegalArgumentException("table");
2631            }
2632    
2633            // get catalog name
2634            String catalogName = (table.getCatalog() == null) ? null : table.getCatalog().getName();
2635            // get schema name
2636            String schemaName = (table.getSchema() == null) ? null : table.getSchema().getName();
2637            // get table name
2638            String tableName = table.getName();
2639    
2640            // column name
2641            String columnName = getString(resultSet, "COLUMN_NAME", false);
2642            // data type
2643            Integer dataType = getInteger(resultSet, "DATA_TYPE", false);
2644            // type name
2645            String typeName = getString(resultSet, "TYPE_NAME", false);
2646            // size
2647            Integer size = getInteger(resultSet, "COLUMN_SIZE", false);
2648            // column length in bytes
2649            // Integer bufferLength = getInteger(resultSet, "BUFFER_LENGTH", false);
2650            // precision
2651            Integer precision = getInteger(resultSet, "DECIMAL_DIGITS", false);
2652    
2653            // pseudo Column Type
2654            Integer columnPseudoType = getInteger(resultSet, "PSEUDO_COLUMN", false);
2655    
2656            // find table column object
2657            TableColumn column = table.findColumnByName(columnName);
2658    
2659            // create new
2660            if (column == null) {
2661                // creating column if not found (it is pseudo)
2662                column = factory.createTableColumn();
2663    
2664                // ***************************************
2665                // *** DatabaseNamedObject properties ***
2666                // ***************************************
2667    
2668                // name
2669                column.setName(columnName);
2670    
2671                // ***************
2672                // *** Column ***
2673                // ***************
2674    
2675                // owner
2676                column.setOwner(table);
2677                // SQL type
2678                column.setSqlType(getSqlType(dataType));
2679                // type name
2680                column.setTypeName(typeName);
2681                // Size
2682                column.setSize(size);
2683                // precision
2684                column.setPrecision(precision);
2685                // OrdinalPosition
2686                column.setOrdinalPosition(null); // N/A
2687    
2688                // ********************
2689                // *** Table Column ***
2690                // ********************
2691    
2692                // add column to the table
2693                table.addColumn(column);
2694            }
2695    
2696            // set pseudo type
2697            column.setPseudoType(getColumnPseudoType(columnPseudoType));
2698    
2699            // log
2700            if (traceLog.isDebugEnabled()) {
2701                traceLog.debug(String.format("[Database %s] The table '%s' (schema %s, catalog %s) column %s has been updated or added.",
2702                                             database.getName(),
2703                                             tableName,
2704                                             schemaName,
2705                                             catalogName,
2706                                             columnName));
2707            }
2708    
2709            return column;
2710        }
2711    
2712        /**
2713         * Creates table's privileges based on ALL records in result set;
2714         * 
2715         * @param factory the model factory to create SP parameter
2716         * @param resultSet the stored procedure parameter result set from DatabaseMetadata
2717         * @param traceLog the log to write if any
2718         * @param failOnError
2719         * @param database the owner database
2720         * @param table the owner table
2721         * @return created list of privileges
2722         * @throws Exception if any error occurs and failOnError is true then generates exception
2723         */
2724        public static Set<Privilege> populateTablePrivileges( ModelFactory factory,
2725                                                              ResultSet resultSet,
2726                                                              Logger traceLog,
2727                                                              boolean failOnError,
2728                                                              Database database,
2729                                                              Table table ) throws Exception {
2730            // check for null
2731            if (factory == null) {
2732                throw new IllegalArgumentException("factory");
2733            }
2734    
2735            // check for null
2736            if (database == null) {
2737                throw new IllegalArgumentException("database");
2738            }
2739    
2740            // check for null
2741            if (resultSet == null) {
2742                throw new IllegalArgumentException("resultSet");
2743            }
2744    
2745            // set trace log
2746            if (traceLog == null) {
2747                traceLog = log;
2748            }
2749    
2750            // check for null
2751            if (table == null) {
2752                throw new IllegalArgumentException("table");
2753            }
2754            // get catalog name
2755            String catalogName = (table.getCatalog() == null) ? null : table.getCatalog().getName();
2756            // get schema name
2757            String schemaName = (table.getSchema() == null) ? null : table.getSchema().getName();
2758            // get table name
2759            String tableName = table.getName();
2760    
2761            // process all privileges
2762            while (resultSet.next()) {
2763                // grantor of access (may be null)
2764                String grantor = getString(resultSet, "GRANTOR", false);
2765                // grantee of access
2766                String grantee = getString(resultSet, "GRANTEE", false);
2767                // name of access (SELECT, INSERT, UPDATE, REFRENCES, ...)
2768                String privilegeName = getString(resultSet, "PRIVILEGE", false);
2769                // grantable string; "YES" if grantee is permitted to grant to others; "NO" if not; null if unknown
2770                String isGrantableStr = getString(resultSet, "IS_GRANTABLE", false);
2771    
2772                // create table's privilege
2773                Privilege privilege = factory.createPrivilege();
2774                // set name
2775                privilege.setName(privilegeName);
2776                // set PrivilegeType
2777                privilege.setPrivilegeType(getPrivilegeType(privilegeName));
2778                // set Grantor
2779                privilege.setGrantor(grantor);
2780                // set Grantee
2781                privilege.setGrantee(grantee);
2782                // set Grantable
2783                privilege.setGrantable("YES".equals(isGrantableStr) == true ? Boolean.TRUE : ("NO".equals(isGrantableStr) == true ? Boolean.FALSE : null));
2784    
2785                // add privilege
2786                table.addPrivilege(privilege);
2787                // log
2788                if (traceLog.isDebugEnabled()) {
2789                    traceLog.debug(String.format("[Database %s] The table '%s' (schema %s, catalog %s) privilege %s has been added.",
2790                                                 database.getName(),
2791                                                 tableName,
2792                                                 schemaName,
2793                                                 catalogName,
2794                                                 privilegeName));
2795                }
2796            }
2797    
2798            // return
2799            return table.getPrivileges();
2800        }
2801    
2802        /**
2803         * Creates table's column privileges based on ALL records in result set;
2804         * 
2805         * @param factory the model factory to create SP parameter
2806         * @param resultSet the stored procedure parameter result set from DatabaseMetadata
2807         * @param traceLog the log to write if any
2808         * @param failOnError
2809         * @param database the owner database
2810         * @param table the owner table
2811         * @param column the table column
2812         * @return created list of privileges
2813         * @throws Exception if any error occurs and failOnError is true then generates exception
2814         */
2815        public static Set<Privilege> populateTableColumnPrivileges( ModelFactory factory,
2816                                                                    ResultSet resultSet,
2817                                                                    Logger traceLog,
2818                                                                    boolean failOnError,
2819                                                                    Database database,
2820                                                                    Table table,
2821                                                                    TableColumn column ) throws Exception {
2822            // check for null
2823            if (factory == null) {
2824                throw new IllegalArgumentException("factory");
2825            }
2826    
2827            // check for null
2828            if (database == null) {
2829                throw new IllegalArgumentException("database");
2830            }
2831    
2832            // check for null
2833            if (resultSet == null) {
2834                throw new IllegalArgumentException("resultSet");
2835            }
2836    
2837            // set trace log
2838            if (traceLog == null) {
2839                traceLog = log;
2840            }
2841    
2842            // check for null
2843            if (table == null) {
2844                throw new IllegalArgumentException("table");
2845            }
2846    
2847            // check for null
2848            if (column == null) {
2849                throw new IllegalArgumentException("column");
2850            }
2851    
2852            // get catalog name
2853            String catalogName = (table.getCatalog() == null) ? null : table.getCatalog().getName();
2854            // get schema name
2855            String schemaName = (table.getSchema() == null) ? null : table.getSchema().getName();
2856            // get table name
2857            String tableName = table.getName();
2858    
2859            // process all privileges
2860            while (resultSet.next()) {
2861                // grantor of access (may be null)
2862                String grantor = getString(resultSet, "GRANTOR", false);
2863                // grantee of access
2864                String grantee = getString(resultSet, "GRANTEE", false);
2865                // name of access (SELECT, INSERT, UPDATE, REFRENCES, ...)
2866                String privilegeName = getString(resultSet, "PRIVILEGE", false);
2867                // grantable string; "YES" if grantee is permitted to grant to others; "NO" if not; null if unknown
2868                String isGrantableStr = getString(resultSet, "IS_GRANTABLE", false);
2869    
2870                // create table's privilege
2871                Privilege privilege = factory.createPrivilege();
2872                // set name
2873                privilege.setName(privilegeName);
2874                // set PrivilegeType
2875                privilege.setPrivilegeType(getPrivilegeType(privilegeName));
2876                // set Grantor
2877                privilege.setGrantor(grantor);
2878                // set Grantee
2879                privilege.setGrantee(grantee);
2880                // set Grantable
2881                privilege.setGrantable("YES".equals(isGrantableStr) == true ? Boolean.TRUE : ("NO".equals(isGrantableStr) == true ? Boolean.FALSE : null));
2882    
2883                // add privilege
2884                column.addPrivilege(privilege);
2885                // log
2886                if (traceLog.isDebugEnabled()) {
2887                    traceLog.debug(String.format("[Database %s] The table '%s' (schema %s, catalog %s) column %s privilege %s has been added.",
2888                                                 database.getName(),
2889                                                 tableName,
2890                                                 schemaName,
2891                                                 catalogName,
2892                                                 column.getName(),
2893                                                 privilegeName));
2894                }
2895            }
2896    
2897            // return
2898            return column.getPrivileges();
2899        }
2900    
2901        /**
2902         * Creates SQL type info based on current record in result set; adds SQL type info to the database
2903         * 
2904         * @param factory the model factory to create table
2905         * @param resultSet the table result set from DatabaseMetadata
2906         * @param traceLog the log to write if any
2907         * @param failOnError
2908         * @param database the owner database
2909         * @return created SQL type info
2910         * @throws Exception if any error occurs and failOnError is true then generates exception
2911         */
2912        public static SqlTypeInfo populateSqlTypeInfo( ModelFactory factory,
2913                                                       ResultSet resultSet,
2914                                                       Logger traceLog,
2915                                                       boolean failOnError,
2916                                                       Database database ) throws Exception {
2917            // check for null
2918            if (factory == null) {
2919                throw new IllegalArgumentException("factory");
2920            }
2921    
2922            // check for null
2923            if (database == null) {
2924                throw new IllegalArgumentException("database");
2925            }
2926    
2927            // check for null
2928            if (resultSet == null) {
2929                throw new IllegalArgumentException("resultSet");
2930            }
2931    
2932            // set trace log
2933            if (traceLog == null) {
2934                traceLog = log;
2935            }
2936    
2937            // get type name
2938            String typeName = getString(resultSet, "TYPE_NAME", false);
2939            // data type
2940            Integer dataType = getInteger(resultSet, "DATA_TYPE", false);
2941            // precision
2942            Long precision = getLong(resultSet, "PRECISION", false);
2943            // literal prefix
2944            String literalPrefix = getString(resultSet, "LITERAL_PREFIX", false);
2945            // literal suffix
2946            String literalSuffix = getString(resultSet, "LITERAL_SUFFIX", false);
2947            // create params
2948            String createParams = getString(resultSet, "CREATE_PARAMS", false);
2949            // nullable
2950            Integer nullableType = getInteger(resultSet, "NULLABLE", false);
2951            // case sensitive
2952            Boolean caseSensitive = getBoolean(resultSet, "CASE_SENSITIVE", false);
2953            // searchable
2954            Integer searchableType = getInteger(resultSet, "SEARCHABLE", false);
2955            // is it unsigned
2956            Boolean unsignedAttribute = getBoolean(resultSet, "UNSIGNED_ATTRIBUTE", false);
2957            // is it fixed precision scale (can it be a money value)
2958            Boolean fixedPrecisionScale = getBoolean(resultSet, "FIXED_PREC_SCALE", false);
2959            // can it be used for an auto-increment value
2960            Boolean autoIncrement = getBoolean(resultSet, "AUTO_INCREMENT", false);
2961            // get local type name
2962            String localTypeName = getString(resultSet, "LOCAL_TYPE_NAME", false);
2963            // min scale supported
2964            Integer minScale = getInteger(resultSet, "MINIMUM_SCALE", false);
2965            // max scale supported
2966            Integer maxScale = getInteger(resultSet, "MAXIMUM_SCALE", false);
2967            // radix
2968            Integer radix = getInteger(resultSet, "NUM_PREC_RADIX", false);
2969    
2970            // create SQL type info object
2971            SqlTypeInfo typeInfo = factory.createSqlTypeInfo();
2972    
2973            // ***************************
2974            // *** DatabaseNamedObject ***
2975            // ***************************
2976    
2977            // set name
2978            typeInfo.setName(typeName);
2979            // set remarks
2980            // typeInfo.setRemarks (remarks); // N/A
2981            // TODO set extra properties
2982            // typeInfo.addExtraProperty (String key, Object value);
2983    
2984            // *******************
2985            // *** SqlTypeInfo ***
2986            // *******************
2987    
2988            // Localized type name
2989            typeInfo.setLocalizedTypeName(localTypeName);
2990            // SQL type nullability
2991            typeInfo.setNullabilityType(getNullabilityType(nullableType));
2992            // SQL type from java.sql.Types
2993            typeInfo.setSqlType(getSqlType(dataType));
2994            // precision
2995            typeInfo.setPrecision(precision);
2996            // fixed precision scale
2997            typeInfo.setFixedPrecisionScale(fixedPrecisionScale);
2998            // number precision radix
2999            typeInfo.setNumberPrecisionRadix(radix);
3000            // minimum scale supported
3001            typeInfo.setMinScale(minScale);
3002            // maximum scale supported
3003            typeInfo.setMaxScale(maxScale);
3004            // literal prefix
3005            typeInfo.setLiteralPrefix(literalPrefix);
3006            // literal suffix
3007            typeInfo.setLiteralSuffix(literalSuffix);
3008            // parameters used in creating the type (may be null)
3009            typeInfo.setCreateParams(createParams);
3010            // Case Sensitive
3011            typeInfo.setCaseSensitive(caseSensitive);
3012            // searchability type
3013            typeInfo.setSearchabilityType(getSearchabilityType(searchableType));
3014            // Unsigned
3015            typeInfo.setUnsigned(unsignedAttribute);
3016            // Auto Increment
3017            typeInfo.setAutoIncrement(autoIncrement);
3018    
3019            // add SQL type info to the list
3020            database.addSqlTypeInfo(typeInfo);
3021    
3022            // log
3023            if (traceLog.isDebugEnabled()) {
3024                traceLog.debug(String.format("[Database %s] The SQL type '%s' has been added.", database.getName(), typeName));
3025            }
3026    
3027            return typeInfo;
3028        }
3029    
3030        /**
3031         * Creates UDT based on current record in result set; adds UDT to the database
3032         * 
3033         * @param factory the model factory to create table
3034         * @param resultSet the table result set from DatabaseMetadata
3035         * @param traceLog the log to write if any
3036         * @param failOnError
3037         * @param database the owner database
3038         * @return created UDT
3039         * @throws Exception if any error occurs and failOnError is true then generates exception
3040         */
3041        public static UserDefinedType populateUDT( ModelFactory factory,
3042                                                   ResultSet resultSet,
3043                                                   Logger traceLog,
3044                                                   boolean failOnError,
3045                                                   Database database ) throws Exception {
3046            // check for null
3047            if (factory == null) {
3048                throw new IllegalArgumentException("factory");
3049            }
3050    
3051            // check for null
3052            if (database == null) {
3053                throw new IllegalArgumentException("database");
3054            }
3055    
3056            // check for null
3057            if (resultSet == null) {
3058                throw new IllegalArgumentException("resultSet");
3059            }
3060    
3061            // set trace log
3062            if (traceLog == null) {
3063                traceLog = log;
3064            }
3065    
3066            // get type catalog
3067            String udtCatalog = getString(resultSet, "TYPE_CAT", false);
3068            // get type schema
3069            String udtSchema = getString(resultSet, "TYPE_SCHEM", false);
3070            // get type name
3071            String udtName = getString(resultSet, "TYPE_NAME", false);
3072            // get class name
3073            String className = getString(resultSet, "CLASS_NAME", false);
3074            // get data type
3075            Integer dataType = getInteger(resultSet, "DATA_TYPE", false);
3076            // get remarks
3077            String remarks = getString(resultSet, "REMARKS", false);
3078            // get base type
3079            Integer baseType = getInteger(resultSet, "BASE_TYPE", false);
3080    
3081            // create UDT object
3082            UserDefinedType udt = factory.createUserDefinedType();
3083    
3084            // ***************************
3085            // *** DatabaseNamedObject ***
3086            // ***************************
3087    
3088            // set name
3089            udt.setName(udtName);
3090            // set remarks
3091            udt.setRemarks(remarks);
3092            // TODO set extra properties
3093            // udt.addExtraProperty (String key, Object value);
3094    
3095            // ********************
3096            // *** SchemaObject ***
3097            // ********************
3098    
3099            // set catalog
3100            if ((udtCatalog != null) && (udtCatalog.trim().length() != 0)) {
3101                // find catalog
3102                Catalog catalog = database.findCatalogByName(udtCatalog);
3103                // set catalog
3104                udt.setCatalog(catalog);
3105    
3106                String errMessage = null;
3107                // warn if null
3108                if (catalog == null) {
3109                    errMessage = String.format("[Database %s] Unable to find catalog '%4$s' for the UDT %s (schema %s, catalog %s)",
3110                                               database.getName(),
3111                                               udtName,
3112                                               udtSchema,
3113                                               udtCatalog);
3114                    traceLog.debug(errMessage);
3115                }
3116                // if fail is enabled
3117                if (failOnError) {
3118                    throw new DatabaseMetaDataMethodException(errMessage, "populateUDT");
3119                }
3120            }
3121    
3122            // set schema
3123            if ((udtSchema != null) && (udtSchema.trim().length() != 0)) {
3124                // find schema
3125                Schema schema = database.findSchemaByName(udtCatalog, udtSchema);
3126                // set schema
3127                udt.setSchema(schema);
3128    
3129                String errMessage = null;
3130                // warn if null
3131                if (schema == null) {
3132                    errMessage = String.format("[Database %s] Unable to find schema '%3$s' for the UDT %s (schema %s, catalog %s)",
3133                                               database.getName(),
3134                                               udtName,
3135                                               udtSchema,
3136                                               udtCatalog);
3137                    traceLog.debug(errMessage);
3138                }
3139                // if fail is enabled
3140                if (failOnError) {
3141                    throw new DatabaseMetaDataMethodException(errMessage, "populateUTD");
3142    
3143                }
3144            }
3145    
3146            // **************
3147            // *** UDT ***
3148            // **************
3149    
3150            // class name
3151            udt.setClassName(className);
3152            // SQL type
3153            udt.setSqlType(getSqlType(dataType));
3154            // base type
3155            udt.setBaseType(getSqlType(baseType));
3156    
3157            // add UDT to the list
3158            database.addUserDefinedType(udt);
3159    
3160            // log
3161            if (traceLog.isDebugEnabled()) {
3162                traceLog.debug(String.format("[Database %s] The UDT '%s' (schema %s, catalog %s) has been added.",
3163                                             database.getName(),
3164                                             udtName,
3165                                             udtSchema,
3166                                             udtCatalog));
3167            }
3168    
3169            return udt;
3170        }
3171    
3172        /**
3173         * Creates UDT attribute based on current record in result set; adds attribute to the UDT
3174         * 
3175         * @param factory the model factory to create SP parameter
3176         * @param resultSet the stored procedure parameter result set from DatabaseMetadata
3177         * @param traceLog the log to write if any
3178         * @param failOnError
3179         * @param database the owner database
3180         * @param udt the owner UDT
3181         * @return created UDT attribute
3182         * @throws Exception if any error occurs and failOnError is true then generates exception
3183         */
3184        public static Attribute populateUDTAttribute( ModelFactory factory,
3185                                                      ResultSet resultSet,
3186                                                      Logger traceLog,
3187                                                      boolean failOnError,
3188                                                      Database database,
3189                                                      UserDefinedType udt ) throws Exception {
3190            // check for null
3191            if (factory == null) {
3192                throw new IllegalArgumentException("factory");
3193            }
3194    
3195            // check for null
3196            if (database == null) {
3197                throw new IllegalArgumentException("database");
3198            }
3199    
3200            // check for null
3201            if (resultSet == null) {
3202                throw new IllegalArgumentException("resultSet");
3203            }
3204    
3205            // set trace log
3206            if (traceLog == null) {
3207                traceLog = log;
3208            }
3209    
3210            // check for null
3211            if (udt == null) {
3212                throw new IllegalArgumentException("udt");
3213            }
3214            // get catalog name
3215            String catalogName = (udt.getCatalog() == null) ? null : udt.getCatalog().getName();
3216            // get schema name
3217            String schemaName = (udt.getSchema() == null) ? null : udt.getSchema().getName();
3218            // get UDT name
3219            String udtName = udt.getName();
3220    
3221            // column name
3222            String columnName = getString(resultSet, "ATTR_NAME", false);
3223            // data type
3224            Integer dataType = getInteger(resultSet, "DATA_TYPE", false);
3225            // type name
3226            String typeName = getString(resultSet, "ATTR_TYPE_NAME", false);
3227            // size
3228            Integer size = getInteger(resultSet, "ATTR_SIZE", false);
3229            // precision
3230            Integer precision = getInteger(resultSet, "DECIMAL_DIGITS", false);
3231            // radix
3232            Integer radix = getInteger(resultSet, "NUM_PREC_RADIX", false);
3233            // nullable
3234            Integer nullableType = getInteger(resultSet, "NULLABLE", false);
3235            // remarks
3236            String remarks = getString(resultSet, "REMARKS", false);
3237            // default value
3238            String defaultValue = getString(resultSet, "ATTR_DEF", false);
3239            // character Octet Length
3240            Integer charOctetLength = getInteger(resultSet, "CHAR_OCTET_LENGTH", false);
3241            // ordinal position
3242            Integer ordinalPosition = getInteger(resultSet, "ORDINAL_POSITION", false);
3243            // is nullable string
3244            // String isNullableString = getString(resultSet, "IS_NULLABLE", false);
3245            // scope catalog
3246            String scopeCatalog = getString(resultSet, "SCOPE_CATLOG", false);
3247            // scope schema
3248            String scopeSchema = getString(resultSet, "SCOPE_SCHEMA", false);
3249            // scope table
3250            String scopeTable = getString(resultSet, "SCOPE_TABLE", false);
3251            // sourceDataType
3252            Integer sourceDataType = getInteger(resultSet, "SOURCE_DATA_TYPE", false);
3253    
3254            // create UDT attribute object
3255            Attribute column = factory.createAttribute();
3256    
3257            // ***************************************
3258            // *** DatabaseNamedObject properties ***
3259            // ***************************************
3260    
3261            // name
3262            column.setName(columnName);
3263            // remarks
3264            column.setRemarks(remarks);
3265            // TODO set extra properties
3266            // column.addExtraProperty (String key, Object value);
3267    
3268            // ***************
3269            // *** Column ***
3270            // ***************
3271    
3272            // owner
3273            column.setOwner(udt);
3274            // nullability. The isNullableString is not used so far
3275            column.setNullabilityType(getNullabilityType(nullableType));
3276            // SQL type
3277            column.setSqlType(getSqlType(dataType));
3278            // type name
3279            column.setTypeName(typeName);
3280            // Size
3281            column.setSize(size);
3282            // precision
3283            column.setPrecision(precision);
3284            // Radix
3285            column.setRadix(radix);
3286            // DefaultValue
3287            column.setDefaultValue(defaultValue);
3288            // OrdinalPosition
3289            column.setOrdinalPosition(ordinalPosition);
3290            // CharOctetLength
3291            column.setCharOctetLength(charOctetLength);
3292            // addPrivilege
3293            // column.addPrivilege (privilege); //
3294    
3295            // ********************
3296            // *** Attribute ***
3297            // ********************
3298    
3299            // set reference
3300            if ((scopeCatalog != null) || (scopeSchema != null) || (scopeTable != null) || (sourceDataType != null)) {
3301                // create reference
3302                Reference reference = factory.createReference();
3303                // set Source Data Type
3304                reference.setSourceDataType(getSqlType(sourceDataType));
3305                // find table and set as source
3306                reference.setSourceTable(database.findTableByName(scopeCatalog, scopeSchema, scopeTable));
3307    
3308                // set reference
3309                column.setReference(reference);
3310            }
3311    
3312            // add attribute to the UDT
3313            udt.addAttribute(column);
3314    
3315            // log
3316            if (traceLog.isDebugEnabled()) {
3317                traceLog.debug(String.format("[Database %s] The UDT '%s' (schema %s, catalog %s) attribute %s has been added.",
3318                                             database.getName(),
3319                                             udtName,
3320                                             schemaName,
3321                                             catalogName,
3322                                             columnName));
3323            }
3324    
3325            return column;
3326        }
3327    
3328        /**
3329         * Updates UDT super type info based on current record in result set
3330         * 
3331         * @param factory the model factory to create SP parameter
3332         * @param resultSet the stored procedure parameter result set from DatabaseMetadata
3333         * @param traceLog the log to write if any
3334         * @param failOnError
3335         * @param database the owner database
3336         * @param udt the UDT to update
3337         * @throws Exception if any error occurs and failOnError is true then generates exception
3338         */
3339        public static void updateUDTSuperType( ModelFactory factory,
3340                                               ResultSet resultSet,
3341                                               Logger traceLog,
3342                                               boolean failOnError,
3343                                               Database database,
3344                                               UserDefinedType udt ) throws Exception {
3345            // check for null
3346            if (factory == null) {
3347                throw new IllegalArgumentException("factory");
3348            }
3349    
3350            // check for null
3351            if (database == null) {
3352                throw new IllegalArgumentException("database");
3353            }
3354    
3355            // check for null
3356            if (resultSet == null) {
3357                throw new IllegalArgumentException("resultSet");
3358            }
3359    
3360            // set trace log
3361            if (traceLog == null) {
3362                traceLog = log;
3363            }
3364    
3365            // check for null
3366            if (udt == null) {
3367                throw new IllegalArgumentException("udt");
3368            }
3369            // get catalog name
3370            String catalogName = (udt.getCatalog() == null) ? null : udt.getCatalog().getName();
3371            // get schema name
3372            String schemaName = (udt.getSchema() == null) ? null : udt.getSchema().getName();
3373            // get UDT name
3374            String udtName = udt.getName();
3375    
3376            // super type catalog
3377            String superTypeCatalog = getString(resultSet, "SUPERTYPE_CAT", false);
3378            // super type schema
3379            String superTypeSchema = getString(resultSet, "SUPERTYPE_SCHEM", false);
3380            // super type
3381            String superTypeName = getString(resultSet, "SUPERTYPE_NAME", false);
3382    
3383            // ***********************
3384            // *** UserDefinedType ***
3385            // ***********************
3386    
3387            // set super type if found in database
3388            udt.setSuperType(database.findUserDefinedTypeByName(superTypeCatalog, superTypeSchema, superTypeName));
3389    
3390            // log
3391            if (udt.getSuperType() != null) {
3392                traceLog.debug(String.format("[Database %s] The UDT '%s' (schema %s, catalog %s) has super type %s (schema %s, catalog %s).",
3393                                             database.getName(),
3394                                             udtName,
3395                                             schemaName,
3396                                             catalogName,
3397                                             superTypeName,
3398                                             superTypeSchema,
3399                                             superTypeCatalog));
3400            }
3401        }
3402    
3403        /**
3404         * Updates table super table info based on current record in result set
3405         * 
3406         * @param factory the model factory to create SP parameter
3407         * @param resultSet the stored procedure parameter result set from DatabaseMetadata
3408         * @param traceLog the log to write if any
3409         * @param failOnError
3410         * @param database the owner database
3411         * @param table the table to update
3412         * @throws Exception if any error occurs and failOnError is true then generates exception
3413         */
3414        public static void updateTableSuperTable( ModelFactory factory,
3415                                                  ResultSet resultSet,
3416                                                  Logger traceLog,
3417                                                  boolean failOnError,
3418                                                  Database database,
3419                                                  Table table ) throws Exception {
3420            // check for null
3421            if (factory == null) {
3422                throw new IllegalArgumentException("factory");
3423            }
3424    
3425            // check for null
3426            if (database == null) {
3427                throw new IllegalArgumentException("database");
3428            }
3429    
3430            // check for null
3431            if (resultSet == null) {
3432                throw new IllegalArgumentException("resultSet");
3433            }
3434    
3435            // set trace log
3436            if (traceLog == null) {
3437                traceLog = log;
3438            }
3439    
3440            // check for null
3441            if (table == null) {
3442                throw new IllegalArgumentException("table");
3443            }
3444            // get catalog name
3445            String catalogName = (table.getCatalog() == null) ? null : table.getCatalog().getName();
3446            // get schema name
3447            String schemaName = (table.getSchema() == null) ? null : table.getSchema().getName();
3448            // get table name
3449            String tableName = table.getName();
3450    
3451            // super table name
3452            String superTableName = getString(resultSet, "SUPERTABLE_NAME", false);
3453    
3454            // *************
3455            // *** Table ***
3456            // *************
3457    
3458            // set super table if found in database
3459            table.setSuperTable(database.findTableByName(catalogName, schemaName, tableName));
3460    
3461            // log
3462            if (table.getSuperTable() != null) {
3463                traceLog.debug(String.format("[Database %s] The table '%s' (schema %s, catalog %s) has super table %s.",
3464                                             database.getName(),
3465                                             tableName,
3466                                             schemaName,
3467                                             catalogName,
3468                                             superTableName));
3469            }
3470        }
3471        
3472        /**
3473         * Get simple database metadata for the getter method (no input parameters)
3474         * @param <T> the return type 
3475         * @param instance the instance of database metadata implementation
3476         * @param methodName the full name of a getter method to execute
3477         * @param traceLog the log
3478         * @return simple database metadata for the getter method
3479         */
3480        @SuppressWarnings("unchecked")
3481        public static <T> T getDatabaseMetadataProperty (DatabaseMetaData instance, String methodName, Logger traceLog) {
3482            try {
3483              // acces to the instance's RTTI  
3484              Method m = instance.getClass().getDeclaredMethod (methodName);
3485              // trying to execute method without parameters
3486              return (T) m.invoke(instance);
3487            } catch (Exception e) {
3488               traceLog.debug(String.format ("Unable to execute getDatabaseMetadata for the '%1$s' method - %2$s: %3$s", 
3489                                             methodName, e.getClass().getName(), e.getMessage()));
3490               // default is null
3491               return null;
3492            }
3493        } 
3494    }