Revision 3235
Added by sledge over 17 years ago
src/edu/ucsb/nceas/metacat/QuerySpecification.java | ||
---|---|---|
61 | 61 |
/** flag determining whether extended query terms are present */ |
62 | 62 |
private boolean containsExtendedSQL = false; |
63 | 63 |
|
64 |
/** flag determining whether predicates are present */ |
|
65 |
private boolean containsPredicates = false; |
|
66 |
|
|
64 | 67 |
/** Identifier for this query document */ |
65 | 68 |
private String meta_file_id; |
66 | 69 |
|
... | ... | |
107 | 110 |
|
108 | 111 |
public static final String ATTRIBUTESYMBOL = "@"; |
109 | 112 |
|
113 |
public static final char PREDICATE_START = '['; |
|
114 |
|
|
115 |
public static final char PREDICATE_END = ']'; |
|
116 |
|
|
110 | 117 |
private boolean hasAttributeReturnField = false; |
111 | 118 |
|
112 | 119 |
private Hashtable attributeReturnList = new Hashtable(); |
... | ... | |
626 | 633 |
} |
627 | 634 |
|
628 | 635 |
//rest textBuffer |
629 |
textBuffer = null; |
|
630 | 636 |
textBuffer = new StringBuffer(); |
631 | 637 |
|
632 | 638 |
} |
... | ... | |
647 | 653 |
/** |
648 | 654 |
* Method to transfer string to return field |
649 | 655 |
*/ |
650 |
public void handleReturnField(String inputString) |
|
656 |
/* public void handleReturnField(String inputString)
|
|
651 | 657 |
{ |
652 | 658 |
// make sure if return fields has an attribute or not |
653 | 659 |
if (inputString.indexOf(ATTRIBUTESYMBOL) == -1) { |
... | ... | |
703 | 709 |
} |
704 | 710 |
} |
705 | 711 |
} |
712 |
*/ |
|
713 |
public void handleReturnField(String inputString) |
|
714 |
{ |
|
715 |
int attributePos = inputString.indexOf(ATTRIBUTESYMBOL); |
|
716 |
int predicateStart = -1; |
|
717 |
int predicateEnd; |
|
718 |
boolean hasPredicate = false; |
|
706 | 719 |
|
720 |
while (true) |
|
721 |
{ |
|
722 |
predicateStart = inputString.indexOf(PREDICATE_START, predicateStart + 1); |
|
723 |
|
|
724 |
if (attributePos == -1) |
|
725 |
break; |
|
726 |
|
|
727 |
if (predicateStart == -1) |
|
728 |
break; |
|
729 |
|
|
730 |
hasPredicate = true; |
|
731 |
|
|
732 |
if (attributePos < predicateStart) |
|
733 |
break; |
|
734 |
|
|
735 |
predicateEnd = inputString.indexOf(PREDICATE_END, predicateStart); |
|
736 |
|
|
737 |
if (predicateEnd == -1) |
|
738 |
{ |
|
739 |
logMetacat.warn("handleReturnField(): "); |
|
740 |
logMetacat.warn(" Invalid path: " + inputString); |
|
741 |
return; |
|
742 |
} |
|
743 |
|
|
744 |
while (attributePos < predicateEnd) |
|
745 |
{ |
|
746 |
attributePos = inputString.indexOf(ATTRIBUTESYMBOL, attributePos + 1); |
|
747 |
|
|
748 |
if (attributePos == -1) |
|
749 |
break; |
|
750 |
} |
|
751 |
} |
|
752 |
|
|
753 |
if (hasPredicate) |
|
754 |
containsPredicates = true; |
|
755 |
|
|
756 |
containsExtendedSQL = true; |
|
757 |
|
|
758 |
// make sure if return fields has an attribute or not |
|
759 |
if (attributePos == -1) |
|
760 |
{ |
|
761 |
// no attribute value will be returned |
|
762 |
logMetacat.info("QuerySpecification.handleReturnField(): " ); |
|
763 |
logMetacat.info(" there are no attributes in the XPATH statement" ); |
|
764 |
returnFieldList.add(inputString); |
|
765 |
return; |
|
766 |
} |
|
767 |
|
|
768 |
// case where the return field is solely an attribute |
|
769 |
logMetacat.info("QuerySpecification.handleReturnField(): " ); |
|
770 |
logMetacat.info(" Found an attribute in the XPATH statement." ); |
|
771 |
String returnPath = inputString.substring(0, |
|
772 |
attributePos == 0 ? attributePos : attributePos - 1); |
|
773 |
String attributeName = inputString.substring(attributePos + 1).trim(); |
|
774 |
Vector pathInfo = new Vector(); |
|
775 |
// the vector has the information about return path and |
|
776 |
// attributename |
|
777 |
pathInfo.addElement(returnPath); |
|
778 |
pathInfo.addElement(attributeName); |
|
779 |
// put the vector into a hash table. The reseaon why don't put |
|
780 |
// return path or attributename as a key is because they are not |
|
781 |
// unique |
|
782 |
attributeReturnList.put(new Integer(countAttributeReturnField), |
|
783 |
pathInfo); |
|
784 |
countAttributeReturnField++; |
|
785 |
hasAttributeReturnField = true; |
|
786 |
} |
|
787 |
|
|
707 | 788 |
/** |
708 | 789 |
* create a SQL serialization of the query that this instance represents |
709 | 790 |
*/ |
... | ... | |
859 | 940 |
public String printExtendedSQL(String doclist, |
860 | 941 |
Hashtable unaccessableNodePair, boolean useXMLIndex) |
861 | 942 |
{ |
862 |
if (useXMLIndex) { |
|
943 |
if (useXMLIndex && !containsPredicates) |
|
944 |
{ |
|
863 | 945 |
return printExtendedSQL(doclist, unaccessableNodePair); |
864 |
} else { |
|
946 |
} |
|
947 |
else |
|
948 |
{ |
|
865 | 949 |
StringBuffer self = new StringBuffer(); |
866 | 950 |
|
867 | 951 |
boolean firstfield = true; |
868 | 952 |
//put the returnfields into the query |
869 | 953 |
//the for loop allows for multiple fields |
870 |
for (int i = 0; i < returnFieldList.size(); i++) { |
|
871 |
if (firstfield) { |
|
954 |
for (int i = 0; i < returnFieldList.size(); i++) |
|
955 |
{ |
|
956 |
if (firstfield) |
|
957 |
{ |
|
872 | 958 |
firstfield = false; |
873 |
} else { |
|
959 |
} |
|
960 |
else |
|
961 |
{ |
|
874 | 962 |
self.append(" UNION "); |
875 | 963 |
} |
876 | 964 |
String path = (String) returnFieldList.elementAt(i); |
877 | 965 |
self.append("select xml_nodes.docid, "); |
878 |
self.append("'"+ path + "' as path, xml_nodes.nodedata, ");
|
|
966 |
self.append("'"+ path.replaceAll("'", "''") + "' as path, xml_nodes.nodedata, ");
|
|
879 | 967 |
self.append("xml_nodes.parentnodeid "); |
880 | 968 |
self.append("from xml_nodes, xml_documents "); |
881 | 969 |
self.append("where parentnodeid IN "); |
... | ... | |
1072 | 1160 |
*/ |
1073 | 1161 |
public String printAttributeQuery(String doclist, boolean useXMLIndex) |
1074 | 1162 |
{ |
1075 |
if (useXMLIndex) { |
|
1163 |
if (useXMLIndex && !containsPredicates) {
|
|
1076 | 1164 |
return printAttributeQuery(doclist); |
1077 | 1165 |
} else { |
1078 | 1166 |
StringBuffer self = new StringBuffer(); |
... | ... | |
1090 | 1178 |
self.append(" UNION "); |
1091 | 1179 |
} |
1092 | 1180 |
self.append("select xml_nodes.docid, '"); |
1093 |
self.append(returnPath); |
|
1181 |
self.append(returnPath.replaceAll("'", "''"));
|
|
1094 | 1182 |
self.append("' as path, xml_nodes.nodedata, xml_nodes.nodename "); |
1095 | 1183 |
self.append("from xml_nodes, xml_documents "); |
1096 | 1184 |
self.append("where parentnodeid IN "); |
src/edu/ucsb/nceas/metacat/QueryTerm.java | ||
---|---|---|
30 | 30 |
package edu.ucsb.nceas.metacat; |
31 | 31 |
|
32 | 32 |
import java.util.Vector; |
33 |
import org.apache.log4j.Logger; |
|
33 | 34 |
|
34 | 35 |
/** a utility class that represents a single term in a query */ |
35 | 36 |
public class QueryTerm |
36 | 37 |
{ |
38 |
private static Logger log = Logger.getLogger(QueryTerm.class); |
|
37 | 39 |
|
38 | 40 |
private boolean casesensitive = false; |
39 | 41 |
|
... | ... | |
286 | 288 |
} |
287 | 289 |
} |
288 | 290 |
|
289 |
/* |
|
291 |
/**
|
|
290 | 292 |
* Constraint the query with @pathexp without using the XML Index, but |
291 | 293 |
* nested SQL statements instead. The query migth be slower. |
292 |
*/ |
|
293 | 294 |
public static String useNestedStatements(String pathexpr) |
294 | 295 |
{ |
295 | 296 |
System.out.println("pathexpr: " + pathexpr); |
... | ... | |
310 | 311 |
for (i = 0; i < nodes.size() - 1; i++) { |
311 | 312 |
nestedStmts.append("(SELECT nodeid FROM xml_nodes" |
312 | 313 |
+ " WHERE nodename LIKE '" + (String) nodes.elementAt(i) |
313 |
+ "'" + " AND parentnodeid IN ");
|
|
314 |
+ "' AND parentnodeid IN "); |
|
314 | 315 |
} |
315 | 316 |
// for the last statement: it is without " AND parentnodeid IN " |
316 | 317 |
nestedStmts.append("(SELECT nodeid FROM xml_nodes" |
... | ... | |
322 | 323 |
|
323 | 324 |
return nestedStmts.toString(); |
324 | 325 |
} |
326 |
*/ |
|
327 |
public static String useNestedStatements(String pathexpr) |
|
328 |
{ |
|
329 |
log.info("useNestedStatements()"); |
|
330 |
log.info("pathexpr: " + pathexpr); |
|
331 |
StringBuffer nestedStmts = new StringBuffer(); |
|
332 |
String path = pathexpr.trim(); |
|
325 | 333 |
|
334 |
if (path.indexOf('/') == 0) |
|
335 |
{ |
|
336 |
nestedStmts.append("AND parentnodeid = rootnodeid "); |
|
337 |
path = path.substring(1).trim(); |
|
338 |
} |
|
339 |
|
|
340 |
do |
|
341 |
{ |
|
342 |
int inx = path.indexOf('/'); |
|
343 |
int predicateStart = -1; |
|
344 |
int predicateEnd; |
|
345 |
String node; |
|
346 |
Vector predicates = new Vector(); |
|
347 |
|
|
348 |
// extract predicates |
|
349 |
predicateStart = path.indexOf(QuerySpecification.PREDICATE_START, predicateStart + 1); |
|
350 |
|
|
351 |
// any predicates in this node? |
|
352 |
if (inx != -1 && (predicateStart == -1 || predicateStart > inx)) |
|
353 |
{ |
|
354 |
// no |
|
355 |
node = path.substring(0, inx).trim(); |
|
356 |
path = path.substring(inx + 1).trim(); |
|
357 |
} |
|
358 |
else if (predicateStart == -1) |
|
359 |
{ |
|
360 |
// no and it's the last node |
|
361 |
node = path; |
|
362 |
path = ""; |
|
363 |
} |
|
364 |
else |
|
365 |
{ |
|
366 |
// yes |
|
367 |
node = path.substring(0, predicateStart).trim(); |
|
368 |
path = path.substring(predicateStart); |
|
369 |
predicateStart = 0; |
|
370 |
|
|
371 |
while (predicateStart == 0) |
|
372 |
{ |
|
373 |
predicateEnd = path.indexOf(QuerySpecification.PREDICATE_END, |
|
374 |
predicateStart); |
|
375 |
|
|
376 |
if (predicateEnd == -1) |
|
377 |
{ |
|
378 |
log.warn("useNestedStatements(): "); |
|
379 |
log.warn(" Invalid path: " + pathexpr); |
|
380 |
return ""; |
|
381 |
} |
|
382 |
|
|
383 |
predicates.add(path.substring(1, predicateEnd).trim()); |
|
384 |
path = path.substring(predicateEnd + 1).trim(); |
|
385 |
inx = path.indexOf('/'); |
|
386 |
predicateStart = path.indexOf(QuerySpecification.PREDICATE_START); |
|
387 |
} |
|
388 |
|
|
389 |
if (inx == 0) |
|
390 |
path = path.substring(1).trim(); |
|
391 |
else if (!path.equals("")) |
|
392 |
{ |
|
393 |
log.warn("useNestedStatements(): "); |
|
394 |
log.warn(" Invalid path: " + pathexpr); |
|
395 |
return ""; |
|
396 |
} |
|
397 |
} |
|
398 |
|
|
399 |
nestedStmts.insert(0, "' ").insert(0, node).insert(0, |
|
400 |
"(SELECT nodeid FROM xml_nodes WHERE nodename LIKE '"); |
|
401 |
|
|
402 |
// for the last statement: it is without " AND parentnodeid IN " |
|
403 |
if (!path.equals("")) |
|
404 |
nestedStmts.insert(0, "AND parentnodeid IN "); |
|
405 |
|
|
406 |
if (predicates.size() > 0) |
|
407 |
{ |
|
408 |
for (int n = 0; n < predicates.size(); n++) |
|
409 |
{ |
|
410 |
String predSQL = predicate2SQL((String) predicates.get(n)); |
|
411 |
|
|
412 |
if (predSQL.equals("")) |
|
413 |
return ""; |
|
414 |
|
|
415 |
nestedStmts.append(predSQL).append(' '); |
|
416 |
} |
|
417 |
} |
|
418 |
|
|
419 |
nestedStmts.append(") "); |
|
420 |
} |
|
421 |
while (!path.equals("")); |
|
422 |
|
|
423 |
return nestedStmts.toString(); |
|
424 |
} |
|
425 |
|
|
326 | 426 |
/** |
427 |
* |
|
428 |
*/ |
|
429 |
public static String predicate2SQL(String predicate) |
|
430 |
{ |
|
431 |
String path = predicate.trim(); |
|
432 |
int equals = path.indexOf('='); |
|
433 |
String literal = null; |
|
434 |
|
|
435 |
if (equals != -1) |
|
436 |
{ |
|
437 |
literal = path.substring(equals + 1).trim(); |
|
438 |
path = path.substring(0, equals).trim(); |
|
439 |
int sQuote = literal.indexOf('\''); |
|
440 |
int dQuote = literal.indexOf('"'); |
|
441 |
|
|
442 |
if (sQuote == -1 && dQuote == -1) |
|
443 |
{ |
|
444 |
log.warn("predicate2SQL(): "); |
|
445 |
log.warn(" Invalid or unsupported predicate: " + predicate); |
|
446 |
return ""; |
|
447 |
} |
|
448 |
|
|
449 |
if (sQuote == -1 && |
|
450 |
(dQuote != 0 || |
|
451 |
literal.indexOf('"', dQuote + 1) != literal.length() - 1)) |
|
452 |
{ |
|
453 |
log.warn("predicate2SQL(): "); |
|
454 |
log.warn(" Invalid or unsupported predicate: " + predicate); |
|
455 |
return ""; |
|
456 |
} |
|
457 |
|
|
458 |
if (sQuote != 0 || |
|
459 |
literal.indexOf('\'', sQuote + 1) != literal.length() - 1) |
|
460 |
{ |
|
461 |
log.warn("predicate2SQL(): "); |
|
462 |
log.warn(" Invalid or unsupported predicate: " + predicate); |
|
463 |
return ""; |
|
464 |
} |
|
465 |
} |
|
466 |
|
|
467 |
StringBuffer sql = new StringBuffer(); |
|
468 |
int attribute = path.indexOf('@'); |
|
469 |
|
|
470 |
if (attribute == -1) |
|
471 |
{ |
|
472 |
if (literal != null) |
|
473 |
{ |
|
474 |
sql.append("AND nodeid IN (SELECT parentnodeid FROM xml_nodes WHERE nodetype = 'TEXT' AND nodedata LIKE ") |
|
475 |
.append(literal).append(")"); |
|
476 |
} |
|
477 |
} |
|
478 |
else |
|
479 |
{ |
|
480 |
sql.append( |
|
481 |
"AND nodeid IN (SELECT parentnodeid FROM xml_nodes WHERE nodetype = 'ATTRIBUTE' AND nodename LIKE '") |
|
482 |
.append(path.substring(attribute + 1).trim()).append("' "); |
|
483 |
|
|
484 |
if (literal != null) |
|
485 |
{ |
|
486 |
sql.append("AND nodedata LIKE ").append(literal); |
|
487 |
} |
|
488 |
|
|
489 |
sql.append(")"); |
|
490 |
path = path.substring(0, attribute).trim(); |
|
491 |
|
|
492 |
if (path.endsWith("/")) |
|
493 |
path = path.substring(0, path.length() - 1).trim(); |
|
494 |
else |
|
495 |
{ |
|
496 |
if (!path.equals("")) |
|
497 |
{ |
|
498 |
log.warn("predicate2SQL(): "); |
|
499 |
log.warn(" Invalid or unsupported predicate: " + predicate); |
|
500 |
return ""; |
|
501 |
} |
|
502 |
} |
|
503 |
} |
|
504 |
|
|
505 |
while (!path.equals("")) |
|
506 |
{ |
|
507 |
int ndx = path.lastIndexOf('/'); |
|
508 |
int predicateEnd = -1; |
|
509 |
int predicateStart; |
|
510 |
String node; |
|
511 |
|
|
512 |
if (ndx != -1) |
|
513 |
{ |
|
514 |
node = path.substring(ndx + 1).trim(); |
|
515 |
path = path.substring(0, ndx).trim(); |
|
516 |
} |
|
517 |
else |
|
518 |
{ |
|
519 |
node = path; |
|
520 |
path = ""; |
|
521 |
} |
|
522 |
|
|
523 |
if (!node.equals("")) |
|
524 |
sql.insert(0, "' ").insert(0, node) |
|
525 |
.insert(0, "(SELECT parentnodeid FROM xml_nodes WHERE nodename LIKE '").append(") "); |
|
526 |
else if (!path.equals("")) |
|
527 |
{ |
|
528 |
log.warn("predicate2SQL(): "); |
|
529 |
log.warn(" Invalid or unsupported predicate: " + predicate); |
|
530 |
return ""; |
|
531 |
} |
|
532 |
|
|
533 |
if (path.equals("")) |
|
534 |
{ |
|
535 |
sql.insert(0, |
|
536 |
node.equals("") ? "AND rootnodeid IN " : "AND nodeid IN "); |
|
537 |
} |
|
538 |
else |
|
539 |
{ |
|
540 |
sql.append("AND nodeid IN "); |
|
541 |
} |
|
542 |
} |
|
543 |
|
|
544 |
return sql.toString(); |
|
545 |
} |
|
546 |
|
|
547 |
/** |
|
327 | 548 |
* create a String description of the query that this instance represents. |
328 | 549 |
* This should become a way to get the XML serialization of the query. |
329 | 550 |
*/ |
Also available in: Unified diff
Limited use of predicates in XPath return fields