KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > mondrian > rolap > aggmatcher > AggGen


1 /*
2 // $Id: //open/mondrian/src/main/mondrian/rolap/aggmatcher/AggGen.java#15 $
3 // This software is subject to the terms of the Common Public License
4 // Agreement, available at the following URL:
5 // http://www.opensource.org/licenses/cpl.html.
6 // Copyright (C) 2005-2007 Julian Hyde and others
7 // All Rights Reserved.
8 // You must accept the terms of that agreement to use this software.
9 */

10
11 package mondrian.rolap.aggmatcher;
12
13 import mondrian.olap.MondrianDef;
14 import mondrian.olap.Util;
15 import mondrian.rolap.RolapStar;
16 import mondrian.rolap.sql.SqlQuery;
17 import mondrian.rolap.RolapAggregator;
18 import org.apache.log4j.Logger;
19 import java.io.PrintWriter JavaDoc;
20 import java.io.StringWriter JavaDoc;
21 import java.util.List JavaDoc;
22 import java.util.ArrayList JavaDoc;
23 import java.util.Set JavaDoc;
24 import java.util.HashSet JavaDoc;
25 import java.util.Map JavaDoc;
26 import java.util.HashMap JavaDoc;
27 import java.util.Iterator JavaDoc;
28 import java.sql.SQLException JavaDoc;
29 import java.sql.Types JavaDoc;
30
31 /**
32  * This class is used to create "lost" and "collapsed" aggregate table
33  * creation sql (creates the rdbms table and inserts into it from the base
34  * fact table).
35  *
36  * @author Richard M. Emberson
37  * @version $Id: //open/mondrian/src/main/mondrian/rolap/aggmatcher/AggGen.java#15 $
38  */

39 public class AggGen {
40     private static final Logger LOGGER = Logger.getLogger(AggGen.class);
41
42     private final RolapStar star;
43     private final RolapStar.Column[] columns;
44
45     /** map RolapStar.Table to list of JdbcSchema Column Usages */
46     private final Map JavaDoc<RolapStar.Table, List JavaDoc<JdbcSchema.Table.Column.Usage>> collapsedColumnUsages;
47
48     /** set of JdbcSchema Column Usages */
49     private final Set JavaDoc<JdbcSchema.Table.Column.Usage> notLostColumnUsages;
50
51     /** list of JdbcSchema Column Usages */
52     private final List JavaDoc<JdbcSchema.Table.Column.Usage> measures;
53     private boolean isReady;
54
55     public AggGen(RolapStar star, RolapStar.Column[] columns) {
56         this.star = star;
57         this.columns = columns;
58         this.notLostColumnUsages = new HashSet JavaDoc<JdbcSchema.Table.Column.Usage>();
59         this.collapsedColumnUsages = new HashMap JavaDoc<RolapStar.Table, List JavaDoc<JdbcSchema.Table.Column.Usage>>();
60         this.measures = new ArrayList JavaDoc<JdbcSchema.Table.Column.Usage>();
61         init();
62     }
63     private Logger getLogger() {
64         return LOGGER;
65     }
66
67     /**
68      * Return true if this instance is ready to generate the sql. If false,
69      * then something went wrong as it was trying to understand the columns.
70      */

71     public boolean isReady() {
72         return isReady;
73     }
74
75     protected RolapStar.Table getFactTable() {
76         return star.getFactTable();
77     }
78
79     protected String JavaDoc getFactTableName() {
80         return getFactTable().getAlias();
81     }
82
83     protected SqlQuery getSqlQuery() {
84         return star.getSqlQuery();
85     }
86
87     protected String JavaDoc getFactCount() {
88         return "fact_count";
89     }
90
91     protected JdbcSchema.Table getTable(JdbcSchema db, RolapStar.Table rt) {
92         JdbcSchema.Table jt = getTable(db, rt.getAlias());
93         return (jt == null)
94             ? getTable(db, rt.getTableName())
95             : jt;
96     }
97
98     protected JdbcSchema.Table getTable(JdbcSchema db, String JavaDoc name) {
99         return db.getTable(name);
100     }
101
102     protected JdbcSchema.Table.Column getColumn(
103             JdbcSchema.Table table,
104             String JavaDoc name) {
105         return table.getColumn(name);
106     }
107
108     protected String JavaDoc getRolapStarColumnName(RolapStar.Column rColumn) {
109         MondrianDef.Expression expr = rColumn.getExpression();
110         if (expr instanceof MondrianDef.Column) {
111             MondrianDef.Column cx = (MondrianDef.Column) expr;
112             return cx.getColumnName();
113         }
114         return null;
115     }
116     protected void addForeignKeyToNotLostColumnUsages(
117             JdbcSchema.Table.Column column) {
118
119         // first make sure its not already in
120
String JavaDoc cname = column.getName();
121         for (JdbcSchema.Table.Column.Usage usage : notLostColumnUsages) {
122             JdbcSchema.Table.Column c = usage.getColumn();
123             if (cname.equals(c.getName())) {
124                 return;
125             }
126         }
127         JdbcSchema.Table.Column.Usage usage;
128         if (column.hasUsage(JdbcSchema.UsageType.FOREIGN_KEY)) {
129             Iterator JavaDoc<JdbcSchema.Table.Column.Usage> it =
130                 column.getUsages(JdbcSchema.UsageType.FOREIGN_KEY);
131             it.hasNext();
132             usage = it.next();
133         } else {
134             usage = column.newUsage(JdbcSchema.UsageType.FOREIGN_KEY);
135             usage.setSymbolicName(JdbcSchema.UsageType.FOREIGN_KEY.name());
136         }
137         notLostColumnUsages.add(usage);
138     }
139
140     /**
141      * The columns are the RolapStar columns taking part in an aggregation
142      * request. This is what happens.
143      * First, for each column, walk up the column's table until one level below
144      * the base fact table. The left join condition contains the base fact table
145      * and the foreign key column name. This column should not be lost.
146      * Get the base fact table's measure columns.
147      * With a list of columns that should not be lost and measure, one can
148      * create lost create and insert commands.
149      */

150     private void init() {
151         JdbcSchema db = JdbcSchema.makeDB(star.getDataSource());
152         try {
153             db.load();
154         } catch (SQLException JavaDoc ex) {
155             getLogger().error(ex);
156             return;
157         }
158
159         JdbcSchema.Table factTable = getTable(db, getFactTableName());
160         if (factTable == null) {
161             StringBuilder JavaDoc buf = new StringBuilder JavaDoc(64);
162             buf.append("Init: ");
163             buf.append("No fact table with name \"");
164             buf.append(getFactTableName());
165             buf.append("\"");
166             getLogger().warn(buf.toString());
167             return;
168         }
169         try {
170             factTable.load();
171         } catch (SQLException JavaDoc ex) {
172             getLogger().error(ex);
173             return;
174         }
175
176         if (getLogger().isDebugEnabled()) {
177             StringBuilder JavaDoc buf = new StringBuilder JavaDoc(512);
178             buf.append("Init: ");
179             buf.append("RolapStar:");
180             buf.append(Util.nl);
181             buf.append(getFactTable());
182             buf.append(Util.nl);
183             buf.append("FactTable:");
184             buf.append(Util.nl);
185             buf.append(factTable);
186             getLogger().debug(buf.toString());
187         }
188
189         // do foreign keys
190
for (RolapStar.Column column : columns) {
191             if (getLogger().isDebugEnabled()) {
192                 StringBuilder JavaDoc buf = new StringBuilder JavaDoc(64);
193                 buf.append("Init: ");
194                 buf.append("Column: ");
195                 buf.append(column);
196                 getLogger().debug(buf.toString());
197             }
198             RolapStar.Table table = column.getTable();
199
200             if (table.getParentTable() == null) {
201                 // this is for those crazy dimensions which are in the
202
// fact table, you know, non-shared with no table element
203

204                 // How the firetruck to enter information for the
205
// collapsed case. This column is in the base fact table
206
// and can be part of a dimension hierarchy but no where
207
// in the RolapStar is this hiearchy captured - ugg.
208
if (!addSpecialCollapsedColumn(db, column)) {
209                     return;
210                 }
211
212
213                 MondrianDef.Expression expr = column.getExpression();
214                 if (expr instanceof MondrianDef.Column) {
215                     MondrianDef.Column exprColumn = (MondrianDef.Column) expr;
216                     String JavaDoc name = exprColumn.getColumnName();
217                     JdbcSchema.Table.Column c = getColumn(factTable, name);
218                     if (c == null) {
219                         StringBuilder JavaDoc buf = new StringBuilder JavaDoc(64);
220                         buf.append("Init: ");
221                         buf.append("FactTable:");
222                         buf.append(getFactTableName());
223                         buf.append(Util.nl);
224                         buf.append("No Column with name \"");
225                         buf.append(name);
226                         buf.append("\"");
227                         getLogger().warn(buf.toString());
228                         return;
229                     }
230                     if (getLogger().isDebugEnabled()) {
231                         getLogger().debug(" Jdbc Column: c=" + c);
232                     }
233                     addForeignKeyToNotLostColumnUsages(c);
234                 }
235
236             } else {
237
238                 if (!addCollapsedColumn(db, column)) {
239                     return;
240                 }
241
242                 while (table.getParentTable().getParentTable() != null) {
243                     table = table.getParentTable();
244                 }
245                 RolapStar.Condition cond = table.getJoinCondition();
246                 if (getLogger().isDebugEnabled()) {
247                     getLogger().debug(" RolapStar.Condition: cond=" + cond);
248                 }
249                 MondrianDef.Expression left = cond.getLeft();
250                 if (left instanceof MondrianDef.Column) {
251                     MondrianDef.Column leftColumn = (MondrianDef.Column) left;
252                     String JavaDoc name = leftColumn.getColumnName();
253                     JdbcSchema.Table.Column c = getColumn(factTable, name);
254                     if (c == null) {
255                         StringBuilder JavaDoc buf = new StringBuilder JavaDoc(64);
256                         buf.append("Init: ");
257                         buf.append("FactTable:");
258                         buf.append(getFactTableName());
259                         buf.append(Util.nl);
260                         buf.append("No Column with name \"");
261                         buf.append(name);
262                         buf.append("\"");
263                         getLogger().warn(buf.toString());
264                         return;
265                     }
266                     if (getLogger().isDebugEnabled()) {
267                         getLogger().debug(" Jdbc Column: c=" + c);
268                     }
269                     addForeignKeyToNotLostColumnUsages(c);
270                 }
271             }
272         }
273
274         // do measures
275
for (RolapStar.Column rColumn : getFactTable().getColumns()) {
276             String JavaDoc name = getRolapStarColumnName(rColumn);
277             if (name == null) {
278                 StringBuilder JavaDoc buf = new StringBuilder JavaDoc(64);
279                 buf.append("Init: ");
280                 buf.append("For fact table \"");
281                 buf.append(getFactTableName());
282                 buf.append(
283                     "\", could not get column name for RolapStar.Column: ");
284                 buf.append(rColumn);
285                 getLogger().warn(buf.toString());
286                 return;
287             }
288             RolapAggregator aggregator;
289             if (!(rColumn instanceof RolapStar.Measure)) {
290                 // TODO: whats the solution to this?
291
// its a funky dimension column in the fact table!!!
292
getLogger().warn("not a measure: " + name);
293                 continue;
294             } else {
295                 RolapStar.Measure rMeasure = (RolapStar.Measure) rColumn;
296                 aggregator = rMeasure.getAggregator();
297             }
298             JdbcSchema.Table.Column c = getColumn(factTable, name);
299             if (c == null) {
300                 StringBuilder JavaDoc buf = new StringBuilder JavaDoc(64);
301                 buf.append("For RolapStar: \"");
302                 buf.append(getFactTable().getAlias());
303                 buf.append("\" measure with name, ");
304                 buf.append(name);
305                 buf.append(", is not a column name. ");
306                 buf.append("The measure's column name may be an expression");
307                 buf.append(" and currently AggGen does not handle expressions.");
308                 buf.append(" You will have to add this measure to the");
309                 buf.append(" aggregate table definition by hand.");
310                 getLogger().warn(buf.toString());
311                 continue;
312             }
313             if (getLogger().isDebugEnabled()) {
314                 getLogger().debug(" Jdbc Column m=" + c);
315             }
316 /*
317             JdbcSchema.Table.Column.Usage usage =
318                 c.newUsage(JdbcSchema.MEASURE_COLUMN_USAGE);
319             usage.setAggregator(aggregator);
320             usage.setSymbolicName(rColumn.getName());
321             measures.add(usage);
322 */

323
324             JdbcSchema.Table.Column.Usage usage = null;
325             if (c.hasUsage(JdbcSchema.UsageType.MEASURE)) {
326                 for (Iterator JavaDoc<JdbcSchema.Table.Column.Usage> uit =
327                     c.getUsages(JdbcSchema.UsageType.MEASURE);
328                     uit.hasNext();) {
329                     JdbcSchema.Table.Column.Usage tmpUsage = uit.next();
330                     if ((tmpUsage.getAggregator() == aggregator) &&
331                         tmpUsage.getSymbolicName().equals(rColumn.getName())) {
332                         usage = tmpUsage;
333                         break;
334                     }
335                 }
336             }
337             if (usage == null) {
338                 usage = c.newUsage(JdbcSchema.UsageType.MEASURE);
339                 usage.setAggregator(aggregator);
340                 usage.setSymbolicName(rColumn.getName());
341             }
342             measures.add(usage);
343         }
344
345         // If we got to here, then everything is ok.
346
isReady = true;
347     }
348     private boolean addSpecialCollapsedColumn(final JdbcSchema db,
349                                               final RolapStar.Column rColumn) {
350         String JavaDoc rname = getRolapStarColumnName(rColumn);
351         if (rname == null) {
352             StringBuilder JavaDoc buf = new StringBuilder JavaDoc(64);
353             buf.append("Adding Special Collapsed Column: ");
354             buf.append("For fact table \"");
355             buf.append(getFactTableName());
356             buf.append("\", could not get column name for RolapStar.Column: ");
357             buf.append(rColumn);
358             getLogger().warn(buf.toString());
359             return false;
360         }
361         // this is in fact the fact table.
362
RolapStar.Table rt = rColumn.getTable();
363
364         JdbcSchema.Table jt = getTable(db, rt);
365         if (jt == null) {
366             StringBuilder JavaDoc buf = new StringBuilder JavaDoc(64);
367             buf.append("Adding Special Collapsed Column: ");
368             buf.append("For fact table \"");
369             buf.append(getFactTableName());
370             buf.append("\", could not get jdbc schema table ");
371             buf.append("for RolapStar.Table with alias \"");
372             buf.append(rt.getAlias());
373             buf.append("\"");
374             getLogger().warn(buf.toString());
375             return false;
376         }
377         try {
378             jt.load();
379         } catch (SQLException JavaDoc ex) {
380             getLogger().error(ex);
381             return false;
382         }
383
384         List JavaDoc<JdbcSchema.Table.Column.Usage> list = collapsedColumnUsages.get(rt);
385         if (list == null) {
386             list = new ArrayList JavaDoc<JdbcSchema.Table.Column.Usage>();
387             collapsedColumnUsages.put(rt, list);
388         }
389
390         JdbcSchema.Table.Column c = getColumn(jt, rname);
391         if (c == null) {
392             StringBuilder JavaDoc buf = new StringBuilder JavaDoc(64);
393             buf.append("Adding Special Collapsed Column: ");
394             buf.append("For fact table \"");
395             buf.append(getFactTableName());
396             buf.append("\", could not get jdbc schema column ");
397             buf.append("for RolapStar.Table with alias \"");
398             buf.append(rt.getAlias());
399             buf.append("\" and column name \"");
400             buf.append(rname);
401             buf.append("\"");
402             getLogger().warn(buf.toString());
403             return false;
404         }
405         // NOTE: this creates a new usage for the fact table
406
// I do not know if this is a problem is AggGen is run before
407
// Mondrian uses aggregate tables.
408
list.add(c.newUsage(JdbcSchema.UsageType.FOREIGN_KEY));
409
410         RolapStar.Column prColumn = rColumn;
411         while (prColumn.getParentColumn() != null) {
412             prColumn = prColumn.getParentColumn();
413             rname = getRolapStarColumnName(prColumn);
414             if (rname == null) {
415                 StringBuilder JavaDoc buf = new StringBuilder JavaDoc(64);
416                 buf.append("Adding Special Collapsed Column: ");
417                 buf.append("For fact table \"");
418                 buf.append(getFactTableName());
419                 buf.append("\", could not get parent column name");
420                 buf.append("for RolapStar.Column \"");
421                 buf.append(rname);
422                 buf.append("\" for RolapStar.Table with alias \"");
423                 buf.append(rt.getAlias());
424                 buf.append("\"");
425                 getLogger().warn(buf.toString());
426                 return false;
427             }
428             c = getColumn(jt, rname);
429             if (c == null) {
430                 getLogger().warn("Can not find column: " +rname);
431                 break;
432             }
433             // NOTE: this creates a new usage for the fact table
434
// I do not know if this is a problem is AggGen is run before
435
// Mondrian uses aggregate tables.
436
list.add(c.newUsage(JdbcSchema.UsageType.FOREIGN_KEY));
437         }
438
439         return true;
440     }
441
442     private boolean addCollapsedColumn(final JdbcSchema db,
443                                        final RolapStar.Column rColumn) {
444         // TODO: if column is "id" column, then there is no collapse
445
String JavaDoc rname = getRolapStarColumnName(rColumn);
446         if (rname == null) {
447             StringBuilder JavaDoc buf = new StringBuilder JavaDoc(64);
448             buf.append("Adding Collapsed Column: ");
449             buf.append("For fact table \"");
450             buf.append(getFactTableName());
451             buf.append("\", could not get column name for RolapStar.Column: ");
452             buf.append(rColumn);
453             getLogger().warn(buf.toString());
454             return false;
455         }
456
457         RolapStar.Table rt = rColumn.getTable();
458
459         JdbcSchema.Table jt = getTable(db, rt);
460         if (jt == null) {
461             StringBuilder JavaDoc buf = new StringBuilder JavaDoc(64);
462             buf.append("Adding Collapsed Column: ");
463             buf.append("For fact table \"");
464             buf.append(getFactTableName());
465             buf.append("\", could not get jdbc schema table ");
466             buf.append("for RolapStar.Table with alias \"");
467             buf.append(rt.getAlias());
468             buf.append("\"");
469             getLogger().warn(buf.toString());
470             return false;
471         }
472         try {
473             jt.load();
474         } catch (SQLException JavaDoc ex) {
475             getLogger().error(ex);
476             return false;
477         }
478
479         //CG guarantee the columns has been loaded before looking up them
480
try {
481             jt.load();
482         } catch (SQLException JavaDoc sqle) {
483             getLogger().error(sqle);
484             return false;
485         }
486
487         // if this is a dimension table, then walk down the levels until
488
// we hit the current column
489
List JavaDoc<JdbcSchema.Table.Column.Usage> list =
490             new ArrayList JavaDoc<JdbcSchema.Table.Column.Usage>();
491         for (RolapStar.Column rc : rt.getColumns()) {
492             // do not include name columns
493
if (rc.isNameColumn()) {
494                 continue;
495             }
496             String JavaDoc name = getRolapStarColumnName(rc);
497             if (name == null) {
498                 StringBuilder JavaDoc buf = new StringBuilder JavaDoc(64);
499                 buf.append("Adding Collapsed Column: ");
500                 buf.append("For fact table \"");
501                 buf.append(getFactTableName());
502                 buf.append("\", could not get column name");
503                 buf.append(" for RolapStar.Column \"");
504                 buf.append(rc);
505                 buf.append("\" for RolapStar.Table with alias \"");
506                 buf.append(rt.getAlias());
507                 buf.append("\"");
508                 getLogger().warn(buf.toString());
509                 return false;
510             }
511             JdbcSchema.Table.Column c = getColumn(jt, name);
512             if (c == null) {
513                 getLogger().warn("Can not find column: " + name);
514                 break;
515             }
516
517             JdbcSchema.Table.Column.Usage usage =
518                 c.newUsage(JdbcSchema.UsageType.FOREIGN_KEY);
519             usage.usagePrefix = rc.getUsagePrefix();
520
521             list.add(usage);
522
523             if (rname.equals(name)) {
524                 break;
525             }
526         }
527         // may already be there so only enter if new list is bigger
528
List JavaDoc<JdbcSchema.Table.Column.Usage> l = collapsedColumnUsages.get(rt);
529         if ((l == null) || (l.size() < list.size())) {
530             collapsedColumnUsages.put(rt, list);
531         }
532
533         return true;
534     }
535
536     private static final String JavaDoc AGG_LOST_PREFIX = "agg_l_XXX_";
537
538     String JavaDoc makeLostAggregateTableName(String JavaDoc factTableName) {
539         StringBuilder JavaDoc buf = new StringBuilder JavaDoc(64);
540         buf.append(AGG_LOST_PREFIX);
541         buf.append(factTableName);
542         return buf.toString();
543     }
544
545     private static final String JavaDoc AGG_COLLAPSED_PREFIX = "agg_c_XXX_";
546
547     String JavaDoc makeCollapsedAggregateTableName(String JavaDoc factTableName) {
548         StringBuilder JavaDoc buf = new StringBuilder JavaDoc(64);
549         buf.append(AGG_COLLAPSED_PREFIX);
550         buf.append(factTableName);
551         return buf.toString();
552     }
553
554
555
556     /**
557      * Return a String containing the sql code to create a lost dimension
558      * table.
559      *
560      * @return lost dimension sql code
561      */

562     public String JavaDoc createLost() {
563         StringWriter JavaDoc sw = new StringWriter JavaDoc(512);
564         PrintWriter JavaDoc pw = new PrintWriter JavaDoc(sw);
565         String JavaDoc prefix = " ";
566
567         pw.print("CREATE TABLE ");
568         pw.print(makeLostAggregateTableName(getFactTableName()));
569         pw.println(" (");
570
571         // do foreign keys
572
for (JdbcSchema.Table.Column.Usage usage : notLostColumnUsages) {
573             addColumnCreate(pw, prefix, usage);
574         }
575
576         // do measures
577
for (JdbcSchema.Table.Column.Usage usage : measures) {
578             addColumnCreate(pw, prefix, usage);
579         }
580         // do fact_count
581
pw.print(prefix);
582         pw.print(getFactCount());
583         pw.println(" INTEGER NOT NULL");
584
585         pw.println(");");
586         return sw.toString();
587     }
588
589     /**
590      * Return the sql code to populate a lost dimension table from the fact
591      * table.
592      */

593     public String JavaDoc insertIntoLost() {
594         StringWriter JavaDoc sw = new StringWriter JavaDoc(512);
595         PrintWriter JavaDoc pw = new PrintWriter JavaDoc(sw);
596         String JavaDoc prefix = " ";
597         String JavaDoc factTableName = getFactTableName();
598         SqlQuery sqlQuery = getSqlQuery();
599
600         pw.print("INSERT INTO ");
601         pw.print(makeLostAggregateTableName(getFactTableName()));
602         pw.println(" (");
603
604         for (JdbcSchema.Table.Column.Usage usage : notLostColumnUsages) {
605             JdbcSchema.Table.Column c = usage.getColumn();
606
607             pw.print(prefix);
608             pw.print(c.getName());
609             pw.println(',');
610         }
611
612         for (JdbcSchema.Table.Column.Usage usage : measures) {
613             JdbcSchema.Table.Column c = usage.getColumn();
614
615             pw.print(prefix);
616             String JavaDoc name = getUsageName(usage);
617             pw.print(name);
618             pw.println(',');
619         }
620         // do fact_count
621
pw.print(prefix);
622         pw.print(getFactCount());
623         pw.println(")");
624
625         pw.println("SELECT");
626         for (JdbcSchema.Table.Column.Usage usage : notLostColumnUsages) {
627             JdbcSchema.Table.Column c = usage.getColumn();
628
629             pw.print(prefix);
630             pw.print(sqlQuery.getDialect().quoteIdentifier(factTableName,
631                 c.getName()));
632             pw.print(" AS ");
633             pw.print(sqlQuery.getDialect().quoteIdentifier(c.getName()));
634             pw.println(',');
635         }
636         for (JdbcSchema.Table.Column.Usage usage : measures) {
637             JdbcSchema.Table.Column c = usage.getColumn();
638             RolapAggregator agg = usage.getAggregator();
639
640             pw.print(prefix);
641             pw.print(
642                 agg.getExpression(sqlQuery.getDialect().quoteIdentifier(
643                     factTableName, c.getName())).toUpperCase());
644             pw.print(" AS ");
645             pw.print(sqlQuery.getDialect().quoteIdentifier(c.getName()));
646             pw.println(',');
647         }
648
649         // do fact_count
650
pw.print(prefix);
651         pw.print("COUNT(*) AS ");
652         pw.println(sqlQuery.getDialect().quoteIdentifier(getFactCount()));
653
654         pw.println("FROM ");
655         pw.print(prefix);
656         pw.print(sqlQuery.getDialect().quoteIdentifier(factTableName));
657         pw.print(" ");
658         pw.println(sqlQuery.getDialect().quoteIdentifier(factTableName));
659
660         pw.println("GROUP BY ");
661         int k = 0;
662         for (JdbcSchema.Table.Column.Usage notLostColumnUsage : notLostColumnUsages) {
663             if (k++ > 0) {
664                 pw.println(",");
665             }
666             JdbcSchema.Table.Column.Usage usage = notLostColumnUsage;
667             JdbcSchema.Table.Column c = usage.getColumn();
668
669             pw.print(prefix);
670             pw.print(sqlQuery.getDialect().quoteIdentifier(factTableName,
671                 c.getName()));
672         }
673
674         pw.println(';');
675         return sw.toString();
676     }
677     /**
678      * Return a String containing the sql code to create a collapsed dimension
679      * table.
680      *
681      * @return collapsed dimension sql code
682      */

683     public String JavaDoc createCollapsed() {
684         StringWriter JavaDoc sw = new StringWriter JavaDoc(512);
685         PrintWriter JavaDoc pw = new PrintWriter JavaDoc(sw);
686         String JavaDoc prefix = " ";
687
688         pw.print("CREATE TABLE ");
689         pw.print(makeCollapsedAggregateTableName(getFactTableName()));
690         pw.println(" (");
691
692         // do foreign keys
693
for (List JavaDoc<JdbcSchema.Table.Column.Usage> list : collapsedColumnUsages.values()) {
694             for (JdbcSchema.Table.Column.Usage usage : list) {
695                 addColumnCreate(pw, prefix, usage);
696             }
697         }
698
699         // do measures
700
for (JdbcSchema.Table.Column.Usage usage : measures) {
701             addColumnCreate(pw, prefix, usage);
702         }
703         // do fact_count
704
pw.print(prefix);
705         pw.print(getFactCount());
706         pw.println(" INTEGER NOT NULL");
707
708         pw.println(");");
709         return sw.toString();
710     }
711
712     /**
713      * Return the sql code to populate a collapsed dimension table from
714      * the fact table.
715      */

716     public String JavaDoc insertIntoCollapsed() {
717         StringWriter JavaDoc sw = new StringWriter JavaDoc(512);
718         PrintWriter JavaDoc pw = new PrintWriter JavaDoc(sw);
719         String JavaDoc prefix = " ";
720         String JavaDoc factTableName = getFactTableName();
721         SqlQuery sqlQuery = getSqlQuery();
722
723         pw.print("INSERT INTO ");
724         pw.print(makeCollapsedAggregateTableName(getFactTableName()));
725         pw.println(" (");
726
727
728         for (List JavaDoc<JdbcSchema.Table.Column.Usage> list : collapsedColumnUsages.values()) {
729             for (JdbcSchema.Table.Column.Usage usage : list) {
730                 JdbcSchema.Table.Column c = usage.getColumn();
731                 pw.print(prefix);
732                 if (usage.usagePrefix != null) {
733                     pw.print(usage.usagePrefix);
734                 }
735                 pw.print(c.getName());
736                 pw.println(',');
737             }
738         }
739
740         for (JdbcSchema.Table.Column.Usage usage : measures) {
741             JdbcSchema.Table.Column c = usage.getColumn();
742
743             pw.print(prefix);
744             String JavaDoc name = getUsageName(usage);
745             pw.print(name);
746             //pw.print(c.getName());
747
pw.println(',');
748         }
749         // do fact_count
750
pw.print(prefix);
751         pw.print(getFactCount());
752         pw.println(")");
753
754         pw.println("SELECT");
755         for (List JavaDoc<JdbcSchema.Table.Column.Usage> list : collapsedColumnUsages.values()) {
756             for (JdbcSchema.Table.Column.Usage usage : list) {
757                 JdbcSchema.Table.Column c = usage.getColumn();
758                 JdbcSchema.Table t = c.getTable();
759
760                 pw.print(prefix);
761                 pw.print(sqlQuery.getDialect().quoteIdentifier(t.getName(),
762                     c.getName()));
763                 pw.print(" AS ");
764                 String JavaDoc n = (usage.usagePrefix == null)
765                     ? c.getName() : usage.usagePrefix + c.getName();
766                 pw.print(sqlQuery.getDialect().quoteIdentifier(n));
767                 pw.println(',');
768             }
769         }
770         for (JdbcSchema.Table.Column.Usage usage : measures) {
771             JdbcSchema.Table.Column c = usage.getColumn();
772             JdbcSchema.Table t = c.getTable();
773             RolapAggregator agg = usage.getAggregator();
774
775             pw.print(prefix);
776             pw.print(
777                 agg.getExpression(sqlQuery.getDialect().quoteIdentifier(
778                     t.getName(), c.getName())).toUpperCase());
779             pw.print(" AS ");
780             pw.print(sqlQuery.getDialect().quoteIdentifier(c.getName()));
781             pw.println(',');
782         }
783
784         // do fact_count
785
pw.print(prefix);
786         pw.print("COUNT(*) AS ");
787         pw.println(sqlQuery.getDialect().quoteIdentifier(getFactCount()));
788
789         pw.println("FROM ");
790         pw.print(prefix);
791         pw.print(sqlQuery.getDialect().quoteIdentifier(factTableName));
792         pw.print(" ");
793         pw.print(sqlQuery.getDialect().quoteIdentifier(factTableName));
794         pw.println(',');
795
796         // add dimension tables
797
int k = 0;
798         for (RolapStar.Table rt : collapsedColumnUsages.keySet()) {
799             if (k++ > 0) {
800                 pw.println(',');
801             }
802             pw.print(prefix);
803             pw.print(sqlQuery.getDialect().quoteIdentifier(rt.getAlias()));
804             pw.print(" AS ");
805             pw.print(sqlQuery.getDialect().quoteIdentifier(rt.getAlias()));
806
807             // walk up tables
808
if (rt.getParentTable() != null) {
809                 while (rt.getParentTable().getParentTable() != null) {
810                     rt = rt.getParentTable();
811
812                     pw.println(',');
813
814                     pw.print(prefix);
815                     pw.print(sqlQuery
816                         .getDialect().quoteIdentifier(rt.getAlias()));
817                     pw.print(" AS ");
818                     pw.print(sqlQuery
819                         .getDialect().quoteIdentifier(rt.getAlias()));
820                 }
821             }
822         }
823
824         pw.println();
825         pw.println("WHERE ");
826         k = 0;
827         for (RolapStar.Table rt : collapsedColumnUsages.keySet()) {
828             if (k++ > 0) {
829                 pw.println(" and");
830             }
831
832             RolapStar.Condition cond = rt.getJoinCondition();
833             if (cond == null) {
834                 continue;
835             }
836             pw.print(prefix);
837             pw.print(cond.toString(sqlQuery));
838
839             if (rt.getParentTable() != null) {
840                 while (rt.getParentTable().getParentTable() != null) {
841                     rt = rt.getParentTable();
842                     cond = rt.getJoinCondition();
843
844                     pw.println(" and");
845
846                     pw.print(prefix);
847                     pw.print(cond.toString(sqlQuery));
848                 }
849             }
850         }
851
852         pw.println();
853         pw.println("GROUP BY ");
854         k = 0;
855         for (List JavaDoc<JdbcSchema.Table.Column.Usage> list : collapsedColumnUsages.values()) {
856             for (JdbcSchema.Table.Column.Usage usage : list) {
857                 if (k++ > 0) {
858                     pw.println(",");
859                 }
860                 JdbcSchema.Table.Column c = usage.getColumn();
861                 JdbcSchema.Table t = c.getTable();
862
863                 String JavaDoc n = (usage.usagePrefix == null)
864                     ? c.getName() : usage.usagePrefix + c.getName();
865                 pw.print(prefix);
866                 pw.print(sqlQuery.getDialect().quoteIdentifier(t.getName(), n));
867             }
868         }
869         pw.println(';');
870
871         return sw.toString();
872     }
873
874
875
876     private String JavaDoc getUsageName(final JdbcSchema.Table.Column.Usage usage) {
877         JdbcSchema.Table.Column c = usage.getColumn();
878         String JavaDoc name = c.getName();
879         // if its a measure which is based upon a foreign key, then
880
// the foreign key column name is already used (for the foreign key
881
// column) so we must choose a different name.
882
if (usage.getUsageType() == JdbcSchema.UsageType.MEASURE) {
883             if (c.hasUsage(JdbcSchema.UsageType.FOREIGN_KEY)) {
884                 name = usage.getSymbolicName().replace(' ', '_').toUpperCase();
885             }
886         }
887         return name;
888     }
889
890     private void addColumnCreate(final PrintWriter JavaDoc pw,
891                                  final String JavaDoc prefix,
892                                  final JdbcSchema.Table.Column.Usage usage) {
893         JdbcSchema.Table.Column c = usage.getColumn();
894         String JavaDoc name = getUsageName(usage);
895
896         pw.print(prefix);
897         if (usage.usagePrefix != null) {
898             pw.print(usage.usagePrefix);
899         }
900         pw.print(name);
901         pw.print(' ');
902         pw.print(c.getTypeName().toUpperCase());
903         switch (c.getType()) {
904         case Types.NUMERIC:
905         case Types.DECIMAL:
906             pw.print('(');
907             pw.print(c.getNumPrecRadix());
908             pw.print(",");
909             pw.print(c.getDecimalDigits());
910             pw.print(')');
911             break;
912         case Types.CHAR:
913         case Types.VARCHAR:
914             pw.print('(');
915             pw.print(c.getCharOctetLength());
916             pw.print(')');
917             break;
918         default:
919         }
920         if (! c.isNullable()) {
921             pw.print(" NOT NULL");
922         }
923         pw.println(',');
924
925     }
926 }
927
928 // AggGen.java
929
Popular Tags