Source Code Cross Referenced for JdbcJDOQLCompiler.java in  » Testing » PolePosition-0.20 » com » versant » core » jdbc » query » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Testing » PolePosition 0.20 » com.versant.core.jdbc.query 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Copyright (c) 1998 - 2005 Versant Corporation
003:         * All rights reserved. This program and the accompanying materials
004:         * are made available under the terms of the Eclipse Public License v1.0
005:         * which accompanies this distribution, and is available at
006:         * http://www.eclipse.org/legal/epl-v10.html
007:         *
008:         * Contributors:
009:         * Versant Corporation - initial API and implementation
010:         */
011:        package com.versant.core.jdbc.query;
012:
013:        import com.versant.core.common.Debug;
014:        import com.versant.core.jdo.QueryDetails;
015:        import com.versant.core.common.CmdBitSet;
016:        import com.versant.core.metadata.*;
017:        import com.versant.core.jdo.query.*;
018:        import com.versant.core.jdbc.FgDs;
019:        import com.versant.core.jdbc.JdbcStorageManager;
020:        import com.versant.core.jdbc.ProjectionQueryDecoder;
021:        import com.versant.core.jdbc.metadata.JdbcClass;
022:        import com.versant.core.jdbc.metadata.JdbcColumn;
023:        import com.versant.core.jdbc.metadata.JdbcField;
024:        import com.versant.core.jdbc.metadata.JdbcFetchGroup;
025:        import com.versant.core.jdbc.sql.SqlDriver;
026:        import com.versant.core.jdbc.sql.exp.*;
027:
028:        import com.versant.core.common.BindingSupportImpl;
029:
030:        /**
031:         * This will compile a JDOQL query into a JdbcCompiledQuery.
032:         *
033:         * @see JdbcCompiledQuery
034:         * @see #reinit
035:         */
036:        public final class JdbcJDOQLCompiler {
037:
038:            private final JdbcStorageManager sm;
039:            private final ModelMetaData jmd;
040:            private final JDOQLNodeToSqlExp visitor;
041:
042:            // these fields must be set to null in reinit
043:            private ClassMetaData cmd;
044:            private ParamNode[] params;
045:            private OrderNode[] orders;
046:            private UnaryNode filter;
047:            private ResultNode resultNode;
048:            private GroupingNode groupingNode;
049:            private QueryParser qParser;
050:            private SelectExp candidateSelectExp;
051:
052:            public JdbcJDOQLCompiler(JdbcStorageManager sm) {
053:                this .sm = sm;
054:                this .jmd = sm.getJmd();
055:                visitor = new JDOQLNodeToSqlExp(this );
056:            }
057:
058:            /**
059:             * Get this compiler ready to compile more queries. This is called before
060:             * it is returned to the pool.
061:             */
062:            public void reinit() {
063:                cmd = null;
064:                params = null;
065:                orders = null;
066:                filter = null;
067:                qParser = null;
068:                resultNode = null;
069:                groupingNode = null;
070:                candidateSelectExp = null;
071:            }
072:
073:            public QueryParser getQParser() {
074:                return qParser;
075:            }
076:
077:            public JDOQLNodeToSqlExp getVisitor() {
078:                return visitor;
079:            }
080:
081:            /**
082:             * Compile a QueryDetails into a JdbcCompiledQuery ready to run.
083:             */
084:            public JdbcCompiledQuery compile(QueryDetails q) {
085:
086:                cmd = jmd.getClassMetaData(q.getCandidateClass());
087:                if (cmd == null) {
088:                    throw BindingSupportImpl.getInstance().invalidOperation(
089:                            "Class " + q.getCandidateClass().getName()
090:                                    + " not found in meta data");
091:                }
092:
093:                return compileImp(q);
094:            }
095:
096:            /**
097:             * Create a filter exp for a collection query.
098:             */
099:            public SqlExp compileParallelFetch(QueryDetails q) {
100:                cmd = jmd.getClassMetaData(q.getCandidateClass());
101:                if (cmd == null) {
102:                    throw BindingSupportImpl.getInstance().invalidOperation(
103:                            "Class " + q.getCandidateClass().getName()
104:                                    + " not found in meta data");
105:                }
106:                return compileParallelFetchImp(q);
107:            }
108:
109:            private JdbcCompiledQuery compileImp(QueryDetails q) {
110:                JdbcCompiledQuery cq = new JdbcCompiledQuery(cmd, q);
111:
112:                qParser = new QueryParser(jmd);
113:
114:                try {
115:                    qParser.parse(q);
116:
117:                    resolveVarNodes(qParser);
118:                    params = qParser.getParams();
119:                    orders = qParser.getOrders();
120:                    filter = qParser.getFilter();
121:                    resultNode = qParser.getResultNode();
122:                    groupingNode = qParser.getGroupingNode();
123:                } catch (Exception e) {
124:                    if (BindingSupportImpl.getInstance().isOwnException(e)) {
125:                        throw (RuntimeException) e;
126:                    } else {
127:                        throw BindingSupportImpl.getInstance()
128:                                .invalidOperation(e.getMessage(), e);
129:                    }
130:                } catch (TokenMgrError e) {
131:                    throw BindingSupportImpl.getInstance().invalidOperation(
132:                            e.getMessage(), e);
133:                }
134:
135:                // build the SQL query tree
136:                candidateSelectExp = new SelectExp();
137:                JdbcClass jdbcClass = (JdbcClass) cmd.storeClass;
138:                candidateSelectExp.table = jdbcClass.table;
139:
140:                FetchGroup fg = cmd.fetchGroups[q.getFetchGroupIndex()];
141:
142:                //do inner joins to basetable
143:                for (FetchGroup supg = fg.super FetchGroup; supg != null; supg = supg.super FetchGroup) {
144:                    JdbcClass sc = (JdbcClass) supg.classMetaData.storeClass;
145:
146:                    if (sc.table != candidateSelectExp.table) {
147:                        // different table so do an inner join
148:                        SelectExp se = candidateSelectExp.findTable(sc.table);
149:                        if (se == null) {
150:                            se = new SelectExp();
151:                            se.table = sc.table;
152:                            candidateSelectExp.addJoin(
153:                                    candidateSelectExp.table.pk, se.table.pk,
154:                                    se);
155:                        }
156:                    }
157:                }
158:
159:                if (filter != null) {
160:                    candidateSelectExp.whereExp = visitor.toSqlExp(filter,
161:                            candidateSelectExp, null, 0, null);
162:                    //            candidateSelectExp.whereExp = filter.toSqlExp(this,
163:                    //                    candidateSelectExp, null, 0, null);
164:                }
165:
166:                // include only correct subclass(es) if cmd is in a heirachy
167:                if (cmd.isInHeirachy())
168:                    addSubclassFilter(candidateSelectExp, cq);
169:
170:                if (Debug.DEBUG) {
171:                    Debug.OUT.println("\n* SQL tree:");
172:                    candidateSelectExp.dump("");
173:                }
174:
175:                SqlDriver driver = sm.getSqlDriver();
176:
177:                FgDs fgDs = cq.fgDs = ((JdbcFetchGroup) fg.storeFetchGroup)
178:                        .getFgDs(cq.isIncludeSubclasses(), false);
179:                SqlExp orderByFromCrossJoin = null;
180:                if (resultNode == null) {
181:                    candidateSelectExp.normalize(driver, null, driver
182:                            .isConvertExistsToDistinctJoin());
183:                    if (Debug.DEBUG) {
184:                        Debug.OUT.println("\n* Normalized SQL tree:");
185:                        candidateSelectExp.dump("");
186:                    }
187:
188:                    cq.process();
189:                    // add the fetch group to the query and make sure the pk is also there
190:                    sm.addSelectFetchGroup(candidateSelectExp, fg, cq
191:                            .isIncludeSubclasses(), fgDs, cq
192:                            .isCrossJoinAllowed());
193:
194:                    addPrimaryKey(candidateSelectExp);
195:
196:                    cq.setSelectColumnCount(candidateSelectExp
197:                            .getSelectListColumnCount());
198:                    orderByFromCrossJoin = candidateSelectExp.orderByList;
199:                    candidateSelectExp.orderByList = null;
200:                } else {
201:                    processNode(resultNode, "Result");
202:                    processNode(groupingNode, "Grouping");
203:                    if (groupingNode != null && groupingNode.havingNode != null) {
204:                        processNode(groupingNode.havingNode, "Having");
205:                    }
206:                    ProjectionQueryDecoder decoder = new ProjectionQueryDecoder(
207:                            resultNode, driver);
208:
209:                    cq.setProjectionDecoder(decoder);
210:                    cq.setGroupingNode(groupingNode);
211:                    cq.process();
212:
213:                    /**
214:                     * remove distinct if all the existExp that was removed was for the
215:                     * variable that is in the result string.
216:                     *
217:                     * Check to see if the candidateSelectExp constains joins that require
218:                     * a distinct
219:                     */
220:
221:                    boolean convertExistBecauseOfVarInProjection = resultNode
222:                            .processForVarNodes();
223:                    candidateSelectExp.normalize(driver, null,
224:                            convertExistBecauseOfVarInProjection
225:                                    || driver.isConvertExistsToDistinctJoin());
226:
227:                    if (resultNode.isDistinct()) {
228:                        candidateSelectExp.distinct = true;
229:                    }
230:
231:                    if (Debug.DEBUG) {
232:                        Debug.OUT.println("\n* Normalized SQL tree:");
233:                        candidateSelectExp.dump("");
234:                    }
235:
236:                    if (decoder.containsThis()) {
237:                        SqlExp tail = sm.addSelectFetchGroup(
238:                                candidateSelectExp, fg, cq
239:                                        .isIncludeSubclasses(), fgDs, false);
240:                        addPrimaryKey(candidateSelectExp);
241:                        cq
242:                                .setSelectColumnCount(candidateSelectExp.selectListCountBeforeAggregate = candidateSelectExp
243:                                        .getSelectListColumnCount());
244:                        tail.next = visitor.toSqlExp(resultNode,
245:                                candidateSelectExp, null, 0, null);
246:                    } else {
247:                        candidateSelectExp.selectList = visitor.toSqlExp(
248:                                resultNode, candidateSelectExp, null, 0, null);
249:                    }
250:
251:                }
252:
253:                candidateSelectExp.groupByList = getGroupingExp();
254:                if (groupingNode != null) {
255:                    if (groupingNode.havingNode == null) {
256:                        candidateSelectExp.havingExp = null;
257:                    } else {
258:                        candidateSelectExp.havingExp = new HavingExp(visitor
259:                                .toSqlExp(groupingNode.havingNode,
260:                                        candidateSelectExp, null, 0, null));
261:                    }
262:                }
263:
264:                reOrderJoinExp(cmd.fetchGroups[q.getFetchGroupIndex()],
265:                        candidateSelectExp);
266:
267:                // add an orderby if required
268:                if (orders != null) {
269:                    addOrderBy(candidateSelectExp);
270:                }
271:
272:                if (Debug.DEBUG) {
273:                    Debug.OUT.println("\n* Finished SQL tree:");
274:                    candidateSelectExp.dump("");
275:                }
276:
277:                /**
278:                 * determine if we should add a orderBy pk. This is only needed for
279:                 * parColFetching. If this is a aggregate only query then this is not needed.
280:                 */
281:                if (cq.isContainsThis()) {
282:                    if (cq.isParColFetchEnabled() || cq.isCrossJoinAllowed()) {
283:                        candidateSelectExp
284:                                .appendOrderByForColumns(((JdbcClass) cmd.storeClass).table.pk);
285:                    }
286:                }
287:
288:                /**
289:                 * Add the orderby as provided by the crossjoin
290:                 */
291:                if (orderByFromCrossJoin != null) {
292:                    candidateSelectExp.appendOrderByExp(orderByFromCrossJoin);
293:                }
294:
295:                //find all equivalent joins
296:                SelectExp.mergeJoinList(candidateSelectExp.joinList);
297:
298:                doFinalSql(cq.getSqlStruct(), candidateSelectExp, driver);
299:
300:                // build params from ParamNode usages
301:                if (params != null)
302:                    compileParams(qParser, cq.getSqlStruct());
303:
304:                if (Debug.DEBUG) {
305:                    Debug.OUT.println("\nParams:");
306:                    dumpParams(cq, cq.getParamList());
307:                }
308:
309:                final CmdBitSet bits = qParser.getCmds();
310:                int[] a = q.getExtraEvictClasses();
311:                if (a != null) {
312:                    for (int i = a.length - 1; i >= 0; i--) {
313:                        bits.add(jmd.classes[a[i]]);
314:                    }
315:                }
316:                cq.setFilterClsIndexs(bits.toArray());
317:                cq.setCacheable(bits.isCacheble() && !q.isRandomAccess());
318:                cq.setEvictionClassBits(bits.getBits());
319:                cq.setEvictionClassIndexes(bits.getIndexes());
320:                return cq;
321:            }
322:
323:            /**
324:             * Fill in the storeExtent of all variables.
325:             */
326:            private void resolveVarNodes(QueryParser qParser) {
327:                VarNode[] vars = qParser.getVars();
328:                if (vars == null || vars.length == 0) {
329:                    return;
330:                }
331:                for (int i = 0; i < vars.length; i++) {
332:                    VarNode var = vars[i];
333:                    ClassMetaData vcmd = var.getCmd();
334:                    if (vcmd == null) {
335:                        continue;
336:                    }
337:                    SelectExp se = new SelectExp();
338:                    se.table = ((JdbcClass) vcmd.storeClass).table;
339:                    se.var = var;
340:                    if (vcmd.pcSuperMetaData != null) {
341:                        // subclass so add test for correct class-id in jdo_class
342:                        // column
343:                        se.whereExp = ((JdbcClass) vcmd.storeClass)
344:                                .getCheckClassIdExp(se);
345:                    }
346:                    var.setStoreExtent(se);
347:                }
348:            }
349:
350:            public static void reOrderJoinExp(FetchGroup fg, SelectExp se) {
351:                Join current = se.joinList;
352:                FetchGroupField[] fgfs = fg.fields;
353:                for (int i = 0; i < fgfs.length; i++) {
354:                    FetchGroupField fgf = fgfs[i];
355:
356:                    if (fgf.fmd.category != MDStatics.CATEGORY_REF)
357:                        continue;
358:                    Join join = se.findJoin((JdbcField) fgf.fmd.storeField);
359:                    if (join != null) {
360:                        if (join == current) {
361:                            current = current.next;
362:                        } else {
363:                            Join beforeToMove = findJoinBefore(join,
364:                                    se.joinList);
365:                            Join beforeCurrent = findJoinBefore(current,
366:                                    se.joinList);
367:
368:                            if (beforeToMove.next != join) {
369:                                throw new RuntimeException(
370:                                        "before.next != join");
371:                            }
372:
373:                            beforeToMove.next = join.next;
374:                            join.next = current;
375:                            if (beforeCurrent != null)
376:                                beforeCurrent.next = join;
377:                            if (current == se.joinList) {
378:                                se.joinList = join;
379:                            }
380:                        }
381:                    }
382:                }
383:            }
384:
385:            private SqlExp getGroupingExp() {
386:                SqlExp gpExp = null;
387:                if (groupingNode != null) {
388:                    gpExp = visitor.toSqlExp(groupingNode, candidateSelectExp,
389:                            null, 0, null);
390:                }
391:                return gpExp;
392:            }
393:
394:            private void processNode(Node node, String info) {
395:                if (node == null)
396:                    return;
397:                if (Debug.DEBUG) {
398:                    Debug.OUT.println("\n* " + info + ": " + node);
399:                    Debug.OUT.println("\n* Parsed tree:");
400:                    node.dump("");
401:                }
402:
403:                node.normalize();
404:                if (Debug.DEBUG) {
405:                    Debug.OUT.println("\n* Normalized tree:");
406:                    node.dump("");
407:                }
408:
409:                node.resolve(qParser, cmd, false);
410:                if (Debug.DEBUG) {
411:                    Debug.OUT.println("\n* Resolved tree:");
412:                    node.dump("");
413:                }
414:
415:                node.normalize();
416:                if (Debug.DEBUG) {
417:                    Debug.OUT.println("\n* Second normalized tree:");
418:                    node.dump("");
419:                }
420:            }
421:
422:            private SqlExp compileParallelFetchImp(QueryDetails q) {
423:                JdbcCompiledQuery cq = new JdbcCompiledQuery(cmd, q);
424:                qParser = new QueryParser(jmd);
425:
426:                try {
427:                    qParser.parse(q);
428:                    resolveVarNodes(qParser);
429:                    params = qParser.getParams();
430:                    orders = qParser.getOrders();
431:                    filter = qParser.getFilter();
432:                } catch (Exception e) {
433:                    if (BindingSupportImpl.getInstance().isOwnException(e)) {
434:                        throw (RuntimeException) e;
435:                    } else {
436:                        throw BindingSupportImpl.getInstance()
437:                                .invalidOperation(e.getMessage(), e);
438:                    }
439:                } catch (TokenMgrError e) {
440:                    throw BindingSupportImpl.getInstance().invalidOperation(
441:                            e.getMessage(), e);
442:                }
443:
444:                if (filter != null) {
445:                    filter.normalize();
446:                    if (Debug.DEBUG) {
447:                        Debug.OUT.println("\n* Normalized tree:");
448:                        filter.dump("");
449:                    }
450:                }
451:
452:                // build the SQL query tree
453:                candidateSelectExp = new SelectExp();
454:                JdbcClass jdbcClass = (JdbcClass) cmd.storeClass;
455:                candidateSelectExp.table = jdbcClass.table;
456:
457:                FetchGroup fg = cmd.fetchGroups[q.getFetchGroupIndex()];
458:                //do inner joins to basetable
459:                for (FetchGroup supg = fg.super FetchGroup; supg != null; supg = supg.super FetchGroup) {
460:                    JdbcClass sc = (JdbcClass) supg.classMetaData.storeClass;
461:
462:                    if (sc.table != candidateSelectExp.table) {
463:                        // different table so do an inner join
464:                        SelectExp se = candidateSelectExp.findTable(sc.table);
465:                        if (se == null) {
466:                            se = new SelectExp();
467:                            se.table = sc.table;
468:                            candidateSelectExp.addJoin(
469:                                    candidateSelectExp.table.pk, se.table.pk,
470:                                    se);
471:                        }
472:                    }
473:                }
474:
475:                if (filter != null) {
476:                    candidateSelectExp.whereExp = visitor.toSqlExp(filter,
477:                            candidateSelectExp, null, 0, null);
478:                }
479:
480:                // include only correct subclass(es) if cmd is in a heirachy
481:                if (cmd.isInHeirachy())
482:                    addSubclassFilter(candidateSelectExp, cq);
483:
484:                if (Debug.DEBUG) {
485:                    Debug.OUT.println("\n* SQL tree:");
486:                    candidateSelectExp.dump("");
487:                }
488:
489:                SqlDriver driver = sm.getSqlDriver();
490:                candidateSelectExp.normalize(driver, null, driver
491:                        .isConvertExistsToDistinctJoin());
492:                if (Debug.DEBUG) {
493:                    Debug.OUT.println("\n* Normalized SQL tree:");
494:                    candidateSelectExp.dump("");
495:                }
496:
497:                reOrderJoinExp(cmd.fetchGroups[q.getFetchGroupIndex()],
498:                        candidateSelectExp);
499:
500:                // add an order by if required
501:                if (orders != null) {
502:                    addOrderBy(candidateSelectExp);
503:                }
504:
505:                if (Debug.DEBUG) {
506:                    Debug.OUT.println("\n* Finished SQL tree:");
507:                    candidateSelectExp.dump("");
508:                }
509:
510:                candidateSelectExp
511:                        .appendOrderByForColumns(((JdbcClass) cmd.storeClass).table.pk);
512:
513:                if (Debug.DEBUG) {
514:                    Debug.OUT.println("\nSQL:\n" + cq.getSqlbuf());
515:                }
516:                return candidateSelectExp;
517:            }
518:
519:            public static void doFinalSql(SqlStruct sqlStruct, SelectExp root,
520:                    SqlDriver driver) {
521:                // get the final SQL
522:                int aliasCount = root.createAlias(0);
523:                if (aliasCount == 1) {
524:                    root.alias = null;
525:                    sqlStruct.setFirstTableOrAlias(root.table.name);
526:                } else {
527:                    sqlStruct.setFirstTableOrAlias(root.alias);
528:                }
529:
530:                root.appendSQL(driver, sqlStruct.getSqlbuf(), null);
531:                sqlStruct.setSelectListRange(root.distinct,
532:                        root.selectListStartIndex,
533:                        root.selectListFirstColEndIndex,
534:                        root.selectListEndIndex);
535:                sqlStruct.setOrderByRange(root.orderByStartIndex,
536:                        root.orderByEndIndex);
537:
538:                // work around bug with replace in CharBuffer class
539:                sqlStruct.getSqlbuf().append(' ');
540:
541:                if (Debug.DEBUG) {
542:                    System.out.println("\nSQL:\n" + sqlStruct.getSqlbuf());
543:                }
544:            }
545:
546:            public static Join findJoinBefore(Join aJoin, Join root) {
547:                for (Join join = root; join != null; join = join.next) {
548:                    if (join.next == aJoin)
549:                        return join;
550:                }
551:                return null;
552:            }
553:
554:            private void addSubclassFilter(SelectExp root, JdbcCompiledQuery cq) {
555:                // no filter needed if we want the whole heirachy
556:                if (((JdbcClass) cmd.storeClass).classIdCol != null) {
557:                    if (cq.isIncludeSubclasses() && cmd.pcSuperMetaData == null)
558:                        return;
559:                    if (cq.isIncludeSubclasses()
560:                            && ((JdbcClass) cmd.storeClass).inheritance == JdbcClass.INHERITANCE_VERTICAL) {
561:                        return;
562:                    }
563:                    addClassIdFilter(root, cq);
564:                } else {
565:                    if (!cq.isIncludeSubclasses()) {
566:                        if (cmd.pcSubclasses == null)
567:                            return;
568:                        //must add joins to immediate sub tables and where id col is null
569:                        for (int i = 0; i < cmd.pcSubclasses.length; i++) {
570:                            ClassMetaData pcSubclass = cmd.pcSubclasses[i];
571:
572:                            SelectExp se = root
573:                                    .findTable(((JdbcClass) pcSubclass.storeClass).table);
574:                            if (se == null) {
575:                                se = new SelectExp();
576:                                se.outer = true;
577:                                se.table = ((JdbcClass) pcSubclass.storeClass).table;
578:
579:                                SqlExp colExp = ((JdbcClass) pcSubclass.storeClass).table.pk[0]
580:                                        .toSqlExp(se);
581:
582:                                root.appendToWhereExp(new IsNullExp(colExp));
583:                                root.addJoin(root.table.pk, se.table.pk, se);
584:                            }
585:                        }
586:                    }
587:                }
588:
589:            }
590:
591:            private void addClassIdFilter(SelectExp root, JdbcCompiledQuery cq) {
592:                // create expression for the class ID column
593:                JdbcColumn cidcol = ((JdbcClass) cmd.storeClass).classIdCol;
594:                SelectExp se = root.findTable(cidcol.table);
595:                if (se == null) {
596:                    throw BindingSupportImpl.getInstance().invalidOperation(
597:                            "Table for classId column not in SelectExp");
598:                }
599:                SqlExp cidexp = cidcol.toSqlExp(se);
600:                if (cidexp.next != null) {
601:                    throw BindingSupportImpl.getInstance().invalidOperation(
602:                            "Compound classId columns not implemented");
603:                }
604:
605:                SqlExp fe;
606:                if (!cq.isIncludeSubclasses() || cmd.pcSubclasses == null) {
607:                    // classid = literal expression
608:                    fe = new BinaryOpExp(
609:                            cidexp,
610:                            BinaryOpExp.EQUAL,
611:                            cidcol
612:                                    .createClassIdLiteralExp(((JdbcClass) cmd.storeClass).jdbcClassId));
613:                } else {
614:                    // in expression with a literal for each class id
615:                    cidexp.next = createClassIdLiteralExp(cmd);
616:                    fe = new InExp(cidexp);
617:                }
618:
619:                // add this to the where clause
620:                if (root.whereExp == null) {
621:                    root.whereExp = fe;
622:                } else if (root.whereExp instanceof  AndExp) {
623:                    root.whereExp.append(fe);
624:                } else {
625:                    root.whereExp.next = fe;
626:                    root.whereExp = new AndExp(root.whereExp);
627:                }
628:            }
629:
630:            /**
631:             * Create a list of LiteralExp's for the class ID's of cmd and all of
632:             * its subclasses.
633:             */
634:            private SqlExp createClassIdLiteralExp(ClassMetaData cmd) {
635:                SqlExp e = ((JdbcClass) cmd.storeClass).classIdCol
636:                        .createClassIdLiteralExp(((JdbcClass) cmd.storeClass).jdbcClassId);
637:                ClassMetaData[] a = cmd.pcSubclasses;
638:                if (a != null) {
639:                    SqlExp p = e;
640:                    for (int i = a.length - 1; i >= 0; i--) {
641:                        SqlExp q = createClassIdLiteralExp(a[i]);
642:                        for (; p.next != null; p = p.next)
643:                            ;
644:                        p = p.next = q;
645:                    }
646:                }
647:                return e;
648:            }
649:
650:            private SqlExp addOrderBy(SelectExp root) {
651:                int len = orders.length;
652:                for (int i = 0; i < len; i++)
653:                    orders[i].resolve(qParser, cmd, true);
654:                return root.addOrderBy(orders, false, visitor);
655:            }
656:
657:            private void addPrimaryKey(SelectExp root) {
658:                JdbcColumn[] pk = root.table.pkSimpleCols;
659:                ColumnExp list = new ColumnExp(pk[0], root, null);
660:                SqlExp pos = list;
661:                int n = pk.length;
662:                for (int i = 1; i < n; i++) {
663:                    pos = pos.next = new ColumnExp(pk[i], root, null);
664:                }
665:                pos.next = root.selectList;
666:                root.selectList = list;
667:            }
668:
669:            /**
670:             * This nasty code has to find the bits of SQL occupied by parameter
671:             * expressions that could be null. They may need to be converted into
672:             * 'is null' or 'is not null' or removed completely (for shared columns)
673:             * if the corresponding parameter is null.
674:             */
675:            public static void compileParams(QueryParser qParser,
676:                    SqlStruct sqlStruct) {
677:                if (qParser.getParams() == null)
678:                    return;
679:                SqlStruct.Param list = null;
680:                SqlStruct.Param pos = null;
681:                ParamNode[] params = qParser.getParams();
682:                int np = params.length;
683:                for (int i = 0; i < np; i++) {
684:                    ParamNode p = params[i];
685:                    SqlParamUsage usage = (SqlParamUsage) p.usageList;
686:                    if (usage == null)
687:                        continue;
688:
689:                    for (; usage != null; usage = usage.next) {
690:
691:                        // create new param and add it to the list
692:                        SqlStruct.Param param = new SqlStruct.Param(p
693:                                .getIdentifier());
694:                        if (pos == null) {
695:                            pos = list = param;
696:                        } else {
697:                            pos = pos.next = param;
698:                        }
699:
700:                        // fill in the param
701:                        param.declaredParamIndex = i;
702:                        JdbcField jdbcField = usage.jdbcField;
703:                        if (jdbcField == null) {
704:                            param.classIndex = usage.classIndex;
705:                            param.fieldNo = -1;
706:                            param.javaTypeCode = usage.javaTypeCode;
707:                            if (param.javaTypeCode == 0) {
708:                                p.resolve(qParser, null, false);
709:                                param.javaTypeCode = MDStaticUtils.toTypeCode(p
710:                                        .getCls());
711:                            }
712:                            param.jdbcType = usage.jdbcType;
713:                            param.col = usage.col;
714:                        } else {
715:                            param.classIndex = jdbcField.fmd.classMetaData.index;
716:                            param.fieldNo = jdbcField.stateFieldNo;
717:                            param.col = usage.col;
718:                        }
719:                        param.mod = usage.mod;
720:
721:                        //  make a CharSpan for each usage
722:                        if (usage.expCount > 0) {
723:                            SqlStruct.CharSpan cspos = null;
724:                            SqlStruct.CharSpan[] a = new SqlStruct.CharSpan[usage.expCount];
725:                            boolean multicol = usage.expCount > 1;
726:                            int j = 0;
727:                            int removeCount = 0;
728:                            for (SqlExp e = usage.expList; j < a.length; j++) {
729:                                SqlStruct.CharSpan cs = a[j] = new SqlStruct.CharSpan();
730:                                if (multicol && mustBeRemovedIfNull(e)) {
731:                                    if (++removeCount == a.length) {
732:                                        // all expressions are to be removed so restart
733:                                        // the loop making them all 'is null' instead
734:                                        multicol = false;
735:                                        e = usage.expList;
736:                                        j = -1;
737:                                        cspos = null;
738:                                        continue;
739:                                    }
740:                                    cs.firstCharIndex = e
741:                                            .getPreFirstCharIndex();
742:                                    if (e.next == null) { // last span
743:                                        cs.lastCharIndex = e.getLastCharIndex();
744:                                        // work back and remove trailing 'and' if any
745:                                        for (int k = j - 1; k >= 0; k--) {
746:                                            if (a[k].type != SqlStruct.CharSpan.TYPE_REMOVE) {
747:                                                a[k + 1].firstCharIndex -= 4; // 'and '
748:                                                break;
749:                                            }
750:                                        }
751:                                    } else { // first or middle span
752:                                        cs.lastCharIndex = e.next
753:                                                .getPreFirstCharIndex();
754:                                    }
755:                                    cs.type = SqlStruct.CharSpan.TYPE_REMOVE;
756:                                } else {
757:                                    cs.firstCharIndex = e.getFirstCharIndex();
758:                                    cs.lastCharIndex = e.getLastCharIndex();
759:                                    cs.type = e.isNegative() ? SqlStruct.CharSpan.TYPE_NOT_NULL
760:                                            : SqlStruct.CharSpan.TYPE_NULL;
761:                                }
762:
763:                                if (cspos == null) {
764:                                    cspos = param.charSpanList = cs;
765:                                    param.firstCharIndex = cs.firstCharIndex;
766:                                } else {
767:                                    cspos = cspos.next = cs;
768:                                }
769:
770:                                e = e.next;
771:                            }
772:                        } else {
773:                            param.firstCharIndex = usage.expList
774:                                    .getFirstCharIndex();
775:                        }
776:                    }
777:                }
778:                if (list != null)
779:                    sqlStruct.setParamList(sortParams(list));
780:            }
781:
782:            /**
783:             * Columns that are not updated (i.e. are shared) must be removed
784:             * completely if the matching parameter is null.
785:             */
786:            private static boolean mustBeRemovedIfNull(SqlExp e) {
787:                if (!e.isNegative() && e.childList instanceof  ColumnExp) {
788:                    ColumnExp ce = (ColumnExp) e.childList;
789:                    return !ce.col.isForUpdate();
790:                }
791:                return false;
792:            }
793:
794:            /**
795:             * Sort the params in the order that they appear in the query.
796:             */
797:            private static SqlStruct.Param sortParams(SqlStruct.Param list) {
798:                if (list.next == null)
799:                    return list;
800:                // stone sort the list (bubble sort except elements sink to the bottom)
801:                for (;;) {
802:                    boolean changed = false;
803:                    SqlStruct.Param p0 = null;
804:                    for (SqlStruct.Param p1 = list;;) {
805:                        SqlStruct.Param p2 = p1.next;
806:                        if (p2 == null)
807:                            break;
808:                        if (p1.firstCharIndex > p2.firstCharIndex) {
809:                            // exchange p and p2
810:                            p1.next = p2.next;
811:                            p2.next = p1;
812:                            if (p0 == null) {
813:                                list = p2;
814:                            } else {
815:                                p0.next = p2;
816:                            }
817:                            p0 = p2;
818:                            changed = true;
819:                        } else {
820:                            p0 = p1;
821:                            p1 = p2;
822:                        }
823:                    }
824:                    if (!changed)
825:                        return list;
826:                }
827:            }
828:
829:            private void dumpParams(JdbcCompiledQuery cq, SqlStruct.Param p) {
830:                for (; p != null; p = p.next) {
831:                    if (Debug.DEBUG) {
832:                        Debug.OUT.println("Param " + p.declaredParamIndex
833:                                + " firstCharIndex " + p.firstCharIndex);
834:                    }
835:                    for (SqlStruct.CharSpan s = p.charSpanList; s != null; s = s.next) {
836:                        if (Debug.DEBUG) {
837:                            String ts;
838:                            switch (s.type) {
839:                            case SqlStruct.CharSpan.TYPE_NULL:
840:                                ts = "NULL";
841:                                break;
842:                            case SqlStruct.CharSpan.TYPE_NOT_NULL:
843:                                ts = "NOT_NULL";
844:                                break;
845:                            case SqlStruct.CharSpan.TYPE_REMOVE:
846:                                ts = "REMOVE";
847:                                break;
848:                            default:
849:                                ts = "Unknown(" + s.type + ")";
850:                            }
851:                            Debug.OUT.println("  CharSpan "
852:                                    + s.firstCharIndex
853:                                    + " to "
854:                                    + s.lastCharIndex
855:                                    + " "
856:                                    + ts
857:                                    + " = '"
858:                                    + cq.getSqlbuf().toString(s.firstCharIndex,
859:                                            s.lastCharIndex - s.firstCharIndex)
860:                                    + "'");
861:                        }
862:                    }
863:                }
864:            }
865:
866:            public ModelMetaData getJmd() {
867:                return jmd;
868:            }
869:
870:            /**
871:             * Get the select for the candidate class. All other SqlExp's for the
872:             * query are reachable from this.
873:             */
874:            public SelectExp getCandidateSelectExp() {
875:                return candidateSelectExp;
876:            }
877:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.