EMMA Coverage Report (generated Wed Jun 28 19:54:35 CEST 2006)
[all classes][smallsql.database]

COVERAGE SUMMARY FOR SOURCE FILE [Database.java]

nameclass, %method, %block, %line, %
Database.java100% (1/1)100% (22/22)91%  (1097/1207)93%  (233/250)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class Database100% (1/1)100% (22/22)91%  (1097/1207)93%  (233/250)
getDatabase (String, SSConnection, boolean): Database 100% (1/1)63%  (50/79)69%  (11/16)
getDatabase (SSConnection, String): Database 100% (1/1)64%  (7/11)67%  (2/3)
Database (String): void 100% (1/1)65%  (49/75)73%  (11/15)
dropView (String): void 100% (1/1)69%  (25/36)83%  (5/6)
createTable (SSConnection, String, Columns, IndexDescriptions, ForeignKeys): ... 100% (1/1)75%  (46/61)88%  (7,9/9)
closeConnection (SSConnection): void 100% (1/1)82%  (33/40)80%  (8,8/11)
getTableView (SSConnection, String): TableView 100% (1/1)90%  (28/31)97%  (5,8/6)
close (): void 100% (1/1)92%  (34/37)98%  (8,9/9)
getCatalogs (Database): Object [][] 100% (1/1)94%  (62/66)93%  (14/15)
getColumns (SSConnection, String, String): Object [][] 100% (1/1)98%  (135/138)96%  (25,9/27)
getIndexInfo (SSConnection, String, boolean): Object [][] 100% (1/1)98%  (115/117)100% (23,9/24)
getPrimaryKeys (SSConnection, String): Object [][] 100% (1/1)99%  (102/103)100% (21,9/22)
getBestRowIdentifier (SSConnection, String): Object [][] 100% (1/1)99%  (122/123)100% (26,9/27)
getReferenceKeys (SSConnection, String, String): Object [][] 100% (1/1)99%  (171/172)100% (32,9/33)
<static initializer> 100% (1/1)100% (5/5)100% (2/2)
createView (String, String): void 100% (1/1)100% (6/6)100% (2/2)
dropTable (SSConnection, String): void 100% (1/1)100% (32/32)100% (7/7)
dropTable (SSConnection, String, String): void 100% (1/1)100% (7/7)100% (2/2)
dropView (SSConnection, String, String): void 100% (1/1)100% (6/6)100% (2/2)
getName (): String 100% (1/1)100% (3/3)100% (1/1)
getTableView (SSConnection, String, String): TableView 100% (1/1)100% (7/7)100% (1/1)
getTables (String): Strings 100% (1/1)100% (52/52)100% (10/10)

1/* =============================================================
2 * SmallSQL : a free Java DBMS library for the Java(tm) platform
3 * =============================================================
4 *
5 * (C) Copyright 2004-2006, by Volker Berlin.
6 *
7 * Project Info:  http://www.smallsql.de/
8 *
9 * This library is free software; you can redistribute it and/or modify it 
10 * under the terms of the GNU Lesser General Public License as published by 
11 * the Free Software Foundation; either version 2.1 of the License, or 
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful, but 
15 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
16 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
17 * License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
22 * USA.  
23 *
24 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
25 * in the United States and other countries.]
26 *
27 * ---------------
28 * Database.java
29 * ---------------
30 * Author: Volker Berlin
31 * 
32 */
33package smallsql.database;
34 
35import java.util.*;
36import java.io.*;
37import java.sql.*;
38 
39 
40final class Database {
41 
42    /*
43    Es gibt nur eine Instance dieser Klasse pro Datenbank. Sie wird geschert zwischen
44    allen Connections zu dieser Datenbank und allen Threads. Deshalb muß der Zugriff
45    auf diese Klasse Thread sicher sein.
46 
47    Hier werden vor allem Table Definitionen und Locks gespeichert.
48    */
49 
50    static private HashMap databases = new HashMap();
51 
52    final private HashMap tableViews = new HashMap();
53    private String name;
54        private File directory;
55        private RandomAccessFile master;
56        final private WeakHashMap connections = new WeakHashMap();
57 
58 
59        /**
60         * Get a instance of the Database Class. If the Datbase with the given name is not open 
61         * then it will be open. 
62         */
63    static Database getDatabase( String name, SSConnection con, boolean create ) throws SQLException{
64            if(name == null) return null;
65        if(name.startsWith("file:"))
66            name = name.substring(5);
67            if(File.separatorChar == '\\')
68                    name = name.replace( '/', File.separatorChar);
69            else
70                    name = name.replace( '\\', File.separatorChar);
71        synchronized(databases){
72            Database db = (Database)databases.get(name);
73            if(db == null){
74                if(create && !new File(name).isDirectory()){
75                    CommandCreateDatabase command = new CommandCreateDatabase(con.log,name);
76                    command.execute(con,null);
77                }
78                db = new Database(name);
79                databases.put( name, db);
80            }
81                        db.connections.put(con, null);
82            return db;
83        }
84    }
85    
86    
87    private static Database getDatabase(SSConnection con, String name) throws SQLException{
88                return name == null ?
89                                        con.getDatabase(false) :
90                                        getDatabase( name, con, false );
91    }
92    
93 
94    private Database(String name ) throws SQLException{
95        try{
96                this.name = name;
97                        directory = new File(name);
98                        if(!directory.isDirectory()){
99                throw Utils.createSQLException("Database '" + name + "' does not exists.");
100            }
101                        directory = directory.getAbsoluteFile();
102                        File file = new File( directory, Utils.MASTER_FILENAME);
103                        if(!file.exists())
104                                throw Utils.createSQLException("Directory '" + name + "' is not a SmallSQL database.");
105                        master = new RandomAccessFile( file, "rw");
106        }catch(Exception e){
107                throw Utils.createSQLException(e);
108        }
109    }
110 
111    String getName(){
112        return name;
113    }
114    
115        
116        
117 
118        /**
119         * Remove a connection from this database.
120         */
121        static final void closeConnection(SSConnection con) throws SQLException{
122                synchronized(databases){
123                        Iterator iterator = databases.values().iterator();
124                        while(iterator.hasNext()){
125                                Database database = (Database)iterator.next();
126                                WeakHashMap connections = database.connections;
127                                connections.remove(con);
128                                if(connections.size() == 0){
129                                        try {
130                                                database.close();
131                                        } catch (Exception e) {
132                                                throw Utils.createSQLException(e);
133                                        }
134                                }
135                        }
136                }
137        }
138        
139 
140        /**
141         * Close this Database and all tables and views.
142         */
143        final void close() throws Exception{
144                databases.remove(this.name);
145                synchronized(tableViews){
146                        Iterator iterator = tableViews.values().iterator();
147                        while(iterator.hasNext()){
148                                TableView tableView = (TableView)iterator.next();
149                                tableView.close();
150                                iterator.remove();
151                        }
152                }
153                master.close();
154        }
155        
156    static TableView getTableView(SSConnection con, String catalog, String tableName) throws SQLException{
157            return getDatabase( con, catalog).getTableView( con, tableName);
158    }
159 
160    
161    /**
162     * Return a TableView object. If the TableView object is not loaded then it load it.
163     * @param con
164     * @param tableName
165     * @return ever a valid TableView object and never null.
166     * @throws SQLException if the table or view does not exists
167     */
168    TableView getTableView(SSConnection con, String tableName) throws SQLException{
169        synchronized(tableViews){
170            TableView tableView = (TableView)tableViews.get(tableName);
171            if(tableView == null){
172                // FIXME hier sollt nur die eine Tabelle gelockt sein und nicht alle Tabellen, Tabelle lesen sollte auserhalb des globalen syn sein.
173                tableView = TableView.load(con, this, tableName);
174                tableViews.put( tableName, tableView);
175            }
176            return tableView;
177        }
178    }
179    
180 
181        static void dropTable(SSConnection con, String catalog, String tableName) throws Exception{
182                getDatabase( con, catalog).dropTable( con, tableName);
183        }
184        
185 
186    void dropTable(SSConnection con, String tableName) throws Exception{
187        synchronized(tableViews){
188            Table table = (Table)tableViews.get( tableName );
189            if(table != null){
190                                tableViews.remove( tableName );
191                table.drop(con);
192            }else{
193                    Table.drop( this, tableName );
194            }
195        }
196    }
197    
198 
199        static void dropView(SSConnection con, String catalog, String tableName) throws Exception{
200                getDatabase( con, catalog).dropView(tableName);
201        }
202        
203 
204        void dropView(String viewName) throws Exception{
205                synchronized(tableViews){
206                        Object view = tableViews.remove( viewName );
207                        if(view != null && !(view instanceof View))
208                                throw Utils.createSQLException("Cannot use DROP VIEW with '" + viewName + "' because it does not is a view.");
209                        
210                        View.drop( this, viewName );
211                }
212        }
213    
214 
215    /**
216     * @param con current Connections
217     * @param name the name of the new Table
218     * @param columns the column descriptions of the table
219     * @param indexes the indexes of the new table
220     * @param foreignKeys 
221     * @throws Exception
222     */
223        void createTable(SSConnection con, String name, Columns columns, IndexDescriptions indexes, ForeignKeys foreignKeys) throws Exception{
224        // createFile() can run only one Thread success (it is atomic)
225        // Thats the create of the Table does not need in the Synchronized.
226        for(int i=0; i<foreignKeys.size(); i++){
227            ForeignKey foreignKey = foreignKeys.get(i);
228            TableView pkTable = getTableView(con, foreignKey.pkTable);
229            if(!(pkTable instanceof Table)){
230                throw Utils.createSQLException("'" + foreignKey.pkTable +"' is not a table.");
231            }
232        }
233        Table table = new Table( this, con, name, columns, indexes, foreignKeys);
234        synchronized(tableViews){
235            tableViews.put( name, table);
236        }
237    }
238 
239 
240        void createView(String name, String sql) throws Exception{
241                // createFile() can run only one Thread success (it is atomic)
242                // Thats the create of the View does not need in the Synchronized.
243                new View( this, name, sql);
244        }
245 
246 
247    /**
248     * Create a list of all available Databases from the point of the current 
249     * Database or current working directory
250     * @param database - current database
251     * @return
252     */
253    static Object[][] getCatalogs(Database database){
254            List catalogs = new ArrayList();
255            File baseDir = (database != null) ?
256                                            database.directory.getParentFile() :
257                                                new File(".");
258                File dirs[] = baseDir.listFiles();
259                if(dirs != null)
260                        for(int i=0; i<dirs.length; i++){
261                                if(dirs[i].isDirectory()){
262                                        if(new File(dirs[i], Utils.MASTER_FILENAME).exists()){
263                                                Object[] catalog = new Object[1];
264                                                catalog[0] = dirs[i].getPath();
265                                                catalogs.add(catalog);
266                                        }
267                                }
268                        }
269                Object[][] result = new Object[catalogs.size()][];
270                catalogs.toArray(result);
271                return result;
272    }
273        
274    
275        Strings getTables(String tablePattern){
276                Strings list = new Strings();
277                File dirs[] = directory.listFiles();    
278                if(dirs != null)
279                        if(tablePattern == null) tablePattern = "%"; 
280                        tablePattern += Utils.TABLE_VIEW_EXTENTION;
281                        for(int i=0; i<dirs.length; i++){
282                                String name = dirs[i].getName();
283                                if(Utils.like(name, tablePattern)){
284                                        list.add(name.substring( 0, name.length()-Utils.TABLE_VIEW_EXTENTION.length() ));
285                                }
286                        }
287            return list;
288    }
289        
290    
291    Object[][] getColumns( SSConnection con, String tablePattern, String colPattern) throws Exception{
292            List rows = new ArrayList();
293                Strings tables = getTables(tablePattern);
294            for(int i=0; i<tables.size(); i++){
295                    String tableName = tables.get(i);
296                        try{
297                            TableView tab = getTableView( con, tableName);
298                            Columns cols = tab.columns;
299                            for(int c=0; c<cols.size(); c++){
300                                    Column col = cols.get(c);
301                                        Object[] row = new Object[18];
302                                        row[0] = getName();                         //TABLE_CAT
303                                                                                                           //TABLE_SCHEM
304                                        row[2] = tableName;                                //TABLE_NAME        
305                                        row[3] = col.getName();                        //COLUMN_NAME        
306                                        row[4] = Utils.getShort( SQLTokenizer.getSQLDataType( col.getDataType() )); //DATA_TYPE  
307                                        row[5] = SQLTokenizer.getKeyWord( col.getDataType() );        //TYPE_NAME
308                                        row[6] = Utils.getInteger(col.getColumnSize());//COLUMN_SIZE
309                                                                                                        //BUFFER_LENGTH
310                                        row[8] = Utils.getInteger(col.getScale());//DECIMAL_DIGITS
311                                        row[9] = Utils.getInteger(10);                //NUM_PREC_RADIX
312                                        row[10]= Utils.getInteger(col.isNullable() ? DatabaseMetaData.columnNullable : DatabaseMetaData.columnNoNulls); //NULLABLE
313                                                                                                        //REMARKS
314                                        row[12]= col.getDefaultDefinition(); //COLUMN_DEF
315                                                                                                        //SQL_DATA_TYPE
316                                                                                                        //SQL_DATETIME_SUB
317                                        row[15]= row[6];                                //CHAR_OCTET_LENGTH
318                                        row[16]= Utils.getInteger(i);         //ORDINAL_POSITION                
319                                        row[17]= col.isNullable() ? "YES" : "NO"; //IS_NULLABLE                                        
320                                        rows.add(row);
321                            }
322                        }catch(Exception e){
323                                //invalid Tables and View will not show 
324                        }
325            }
326                Object[][] result = new Object[rows.size()][];
327                rows.toArray(result);
328                return result;
329    }
330        
331        
332        Object[][] getReferenceKeys(SSConnection con, String pkTable, String fkTable) throws SQLException{
333                List rows = new ArrayList();
334                Strings tables = (pkTable != null) ? getTables(pkTable) : getTables(fkTable);
335                for(int t=0; t<tables.size(); t++){
336                    String tableName = tables.get(t);
337                    TableView tab = getTableView( con, tableName);
338                        if(!(tab instanceof Table)) continue;
339                        ForeignKeys references = ((Table)tab).references;
340                        for(int i=0; i<references.size(); i++){
341                                ForeignKey foreignKey = references.get(i);
342                                IndexDescription pk = foreignKey.pk;
343                                IndexDescription fk = foreignKey.fk;
344                                if((pkTable == null || pkTable.equals(foreignKey.pkTable)) &&
345                                   (fkTable == null || fkTable.equals(foreignKey.fkTable))){
346                                        Strings columnsPk = pk.getColumns();
347                                        Strings columnsFk = fk.getColumns();
348                                        for(int c=0; c<columnsPk.size(); c++){
349                                                Object[] row = new Object[14];
350                                                row[0] = getName();                                //PKTABLE_CAT
351                                                                                                                //PKTABLE_SCHEM
352                                                row[2] = foreignKey.pkTable;        //PKTABLE_NAME
353                                                row[3] = columnsPk.get(c);                //PKCOLUMN_NAME
354                                                row[4] = getName();                                //FKTABLE_CAT
355                                                                                                                //FKTABLE_SCHEM
356                                                row[6] = foreignKey.fkTable;        //FKTABLE_NAME
357                                                row[7] = columnsFk.get(c);                //FKCOLUMN_NAME
358                                                row[8] = Utils.getShort(c+1);        //KEY_SEQ
359                                                row[9] = Utils.getShort(foreignKey.updateRule);//UPDATE_RULE
360                                                row[10]= Utils.getShort(foreignKey.deleteRule); //DELETE_RULE
361                                                row[11]= fk.getName();        //FK_NAME
362                                                row[12]= pk.getName();        //PK_NAME
363                                                row[13]= Utils.getShort(DatabaseMetaData.importedKeyNotDeferrable); //DEFERRABILITY
364                                                rows.add(row);
365                                        }
366                                }
367                        }
368                }
369                Object[][] result = new Object[rows.size()][];
370                rows.toArray(result);
371                return result;                
372        }
373        
374        
375        Object[][] getBestRowIdentifier(SSConnection con, String table) throws SQLException{
376                List rows = new ArrayList();
377                Strings tables = getTables(table);
378                for(int t=0; t<tables.size(); t++){
379                    String tableName = tables.get(t);
380                    TableView tab = getTableView( con, tableName);
381                        if(!(tab instanceof Table)) continue;
382                        IndexDescriptions indexes = ((Table)tab).indexes;
383                        for(int i=0; i<indexes.size(); i++){
384                                IndexDescription index = indexes.get(i);
385                                if(index.isUnique()){
386                                        Strings columns = index.getColumns();
387                                        for(int c=0; c<columns.size(); c++){
388                                                String columnName = columns.get(c);
389                                                Column column = tab.findColumn(columnName);
390                                                Object[] row = new Object[8];
391                                                row[0] = Utils.getShort(DatabaseMetaData.bestRowSession);//SCOPE
392                                                row[1] = columnName;                        //COLUMN_NAME
393                                                final int dataType = column.getDataType();
394                                                row[2] = Utils.getInteger(dataType);//DATA_TYPE
395                                                row[3] = SQLTokenizer.getKeyWord(dataType);//TYPE_NAME
396                                                row[4] = Utils.getInteger(column.getPrecision());        //COLUMN_SIZE
397                                                                                                                //BUFFER_LENGTH
398                                                row[6] = Utils.getShort(column.getScale());                //DECIMAL_DIGITS
399                                                row[7] = Utils.getShort(DatabaseMetaData.bestRowNotPseudo);//PSEUDO_COLUMN
400                                                rows.add(row);
401                                        }
402                                }
403                        }
404                }
405                Object[][] result = new Object[rows.size()][];
406                rows.toArray(result);
407                return result;                
408        }
409 
410        
411        Object[][] getPrimaryKeys(SSConnection con, String table) throws SQLException{
412                List rows = new ArrayList();
413                Strings tables = getTables(table);
414                for(int t=0; t<tables.size(); t++){
415                    String tableName = tables.get(t);
416                    TableView tab = getTableView( con, tableName);
417                        if(!(tab instanceof Table)) continue;
418                        IndexDescriptions indexes = ((Table)tab).indexes;
419                        for(int i=0; i<indexes.size(); i++){
420                                IndexDescription index = indexes.get(i);
421                                if(index.isPrimary()){
422                                        Strings columns = index.getColumns();
423                                        for(int c=0; c<columns.size(); c++){
424                                                Object[] row = new Object[6];
425                                                row[0] = getName();                         //TABLE_CAT
426                                                                                                                //TABLE_SCHEM
427                                                row[2] = tableName;                                //TABLE_NAME
428                                                row[3] = columns.get(c);                //COLUMN_NAME
429                                                row[4] = Utils.getShort(c+1);        //KEY_SEQ
430                                                row[5] = index.getName();                //PK_NAME
431                                                rows.add(row);
432                                        }
433                                }
434                        }
435                }
436                Object[][] result = new Object[rows.size()][];
437                rows.toArray(result);
438                return result;                
439        }
440        
441        
442        Object[][] getIndexInfo( SSConnection con, String table, boolean unique) throws SQLException {
443                List rows = new ArrayList();
444                Strings tables = getTables(table);
445                Short type = Utils.getShort( DatabaseMetaData.tableIndexOther );
446                for(int t=0; t<tables.size(); t++){
447                    String tableName = tables.get(t);
448                    TableView tab = getTableView( con, tableName);
449                        if(!(tab instanceof Table)) continue;
450                        IndexDescriptions indexes = ((Table)tab).indexes;
451                        for(int i=0; i<indexes.size(); i++){
452                                IndexDescription index = indexes.get(i);
453                                Strings columns = index.getColumns();
454                                for(int c=0; c<columns.size(); c++){
455                                        Object[] row = new Object[13];
456                                        row[0] = getName();                         //TABLE_CAT
457                                                                                                        //TABLE_SCHEM
458                                        row[2] = tableName;                                //TABLE_NAME
459                                        row[3] = Boolean.valueOf(!index.isUnique());//NON_UNIQUE
460                                                                                                        //INDEX_QUALIFIER
461                                        row[5] = index.getName();                //INDEX_NAME
462                                        row[6] = type;                                        //TYPE
463                                        row[7] = Utils.getShort(c+1);        //ORDINAL_POSITION
464                                        row[8] = columns.get(c);                //COLUMN_NAME
465                                                                                                        //ASC_OR_DESC
466                                                                                                        //CARDINALITY
467                                                                                                        //PAGES
468                                                                                                        //FILTER_CONDITION
469                                        rows.add(row);
470                                }
471                        }
472            }
473                Object[][] result = new Object[rows.size()][];
474                rows.toArray(result);
475                return result;
476        }
477}

[all classes][smallsql.database]
EMMA 2.1.5320 (stable) (C) Vladimir Roubtsov