1
|
/**
|
2
|
* '$RCSfile$'
|
3
|
* Purpose: A Class that represents a structured query, and can be
|
4
|
* constructed from an XML serialization conforming to
|
5
|
* pathquery.dtd. The printSQL() method can be used to print
|
6
|
* a SQL serialization of the query.
|
7
|
* Copyright: 2000 Regents of the University of California and the
|
8
|
* National Center for Ecological Analysis and Synthesis
|
9
|
* Authors: Matt Jones
|
10
|
* Release: @release@
|
11
|
*
|
12
|
* '$Author: berkley $'
|
13
|
* '$Date: 2000-10-03 15:48:41 -0700 (Tue, 03 Oct 2000) $'
|
14
|
* '$Revision: 489 $'
|
15
|
*/
|
16
|
|
17
|
package edu.ucsb.nceas.metacat;
|
18
|
|
19
|
import java.io.*;
|
20
|
import java.util.Stack;
|
21
|
import java.util.Vector;
|
22
|
import java.util.Enumeration;
|
23
|
|
24
|
import org.xml.sax.Attributes;
|
25
|
import org.xml.sax.InputSource;
|
26
|
import org.xml.sax.SAXException;
|
27
|
import org.xml.sax.SAXParseException;
|
28
|
import org.xml.sax.XMLReader;
|
29
|
import org.xml.sax.helpers.XMLReaderFactory;
|
30
|
import org.xml.sax.helpers.DefaultHandler;
|
31
|
|
32
|
/**
|
33
|
* A Class that represents a structured query, and can be
|
34
|
* constructed from an XML serialization conforming to @see pathquery.dtd.
|
35
|
* The printSQL() method can be used to print a SQL serialization of the query.
|
36
|
*/
|
37
|
public class QuerySpecification extends DefaultHandler {
|
38
|
|
39
|
private boolean containsExtendedSQL=false;
|
40
|
|
41
|
// Query data structures
|
42
|
private String meta_file_id;
|
43
|
private String querytitle;
|
44
|
private Vector doctypeList;
|
45
|
private Vector returnFieldList;
|
46
|
private QueryGroup query = null;
|
47
|
|
48
|
private Stack elementStack;
|
49
|
private Stack queryStack;
|
50
|
private String currentValue;
|
51
|
private String currentPathexpr;
|
52
|
private String parserName = null;
|
53
|
|
54
|
/**
|
55
|
* construct an instance of the QuerySpecification class
|
56
|
*
|
57
|
* @param queryspec the XML representation of the query (should conform
|
58
|
* to pathquery.dtd) as a Reader
|
59
|
* @param parserName the fully qualified name of a Java Class implementing
|
60
|
* the org.xml.sax.XMLReader interface
|
61
|
*/
|
62
|
public QuerySpecification( Reader queryspec, String parserName )
|
63
|
throws IOException {
|
64
|
super();
|
65
|
|
66
|
// Initialize the class variables
|
67
|
doctypeList = new Vector();
|
68
|
elementStack = new Stack();
|
69
|
queryStack = new Stack();
|
70
|
returnFieldList = new Vector();
|
71
|
this.parserName = parserName;
|
72
|
|
73
|
// Initialize the parser and read the queryspec
|
74
|
XMLReader parser = initializeParser();
|
75
|
if (parser == null) {
|
76
|
System.err.println("SAX parser not instantiated properly.");
|
77
|
}
|
78
|
try {
|
79
|
parser.parse(new InputSource(queryspec));
|
80
|
} catch (SAXException e) {
|
81
|
System.err.println("error parsing data");
|
82
|
System.err.println(e.getMessage());
|
83
|
}
|
84
|
}
|
85
|
|
86
|
/**
|
87
|
* construct an instance of the QuerySpecification class
|
88
|
*
|
89
|
* @param queryspec the XML representation of the query (should conform
|
90
|
* to pathquery.dtd) as a String
|
91
|
* @param parserName the fully qualified name of a Java Class implementing
|
92
|
* the org.xml.sax.Parser interface
|
93
|
*/
|
94
|
public QuerySpecification( String queryspec, String parserName )
|
95
|
throws IOException {
|
96
|
this(new StringReader(queryspec), parserName);
|
97
|
}
|
98
|
|
99
|
/** Main routine for testing */
|
100
|
static public void main(String[] args) {
|
101
|
|
102
|
if (args.length < 1) {
|
103
|
System.err.println("Wrong number of arguments!!!");
|
104
|
System.err.println("USAGE: java QuerySpecification <xmlfile>");
|
105
|
return;
|
106
|
} else {
|
107
|
String xmlfile = args[0];
|
108
|
|
109
|
try {
|
110
|
MetaCatUtil util = new MetaCatUtil();
|
111
|
FileReader xml = new FileReader(new File(xmlfile));
|
112
|
QuerySpecification qspec =
|
113
|
new QuerySpecification(xml, util.getOption("saxparser"));
|
114
|
System.out.println(qspec.printSQL());
|
115
|
|
116
|
} catch (IOException e) {
|
117
|
System.err.println(e.getMessage());
|
118
|
}
|
119
|
|
120
|
}
|
121
|
}
|
122
|
|
123
|
/**
|
124
|
* Returns true if the parsed query contains and extended xml query
|
125
|
* (i.e. there is at least one <returnfield> in the pathquery document)
|
126
|
*/
|
127
|
public boolean containsExtendedSQL()
|
128
|
{
|
129
|
if(containsExtendedSQL)
|
130
|
{
|
131
|
return true;
|
132
|
}
|
133
|
else
|
134
|
{
|
135
|
return false;
|
136
|
}
|
137
|
}
|
138
|
|
139
|
/**
|
140
|
* Accessor method to return a vector of the extended return fields as
|
141
|
* defined in the <returnfield> tag in the pathquery dtd.
|
142
|
*/
|
143
|
public Vector getReturnFieldList()
|
144
|
{
|
145
|
return this.returnFieldList;
|
146
|
}
|
147
|
|
148
|
/**
|
149
|
* Set up the SAX parser for reading the XML serialized query
|
150
|
*/
|
151
|
private XMLReader initializeParser() {
|
152
|
XMLReader parser = null;
|
153
|
|
154
|
// Set up the SAX document handlers for parsing
|
155
|
try {
|
156
|
|
157
|
// Get an instance of the parser
|
158
|
parser = XMLReaderFactory.createXMLReader(parserName);
|
159
|
|
160
|
// Set the ContentHandler to this instance
|
161
|
parser.setContentHandler(this);
|
162
|
|
163
|
// Set the error Handler to this instance
|
164
|
parser.setErrorHandler(this);
|
165
|
|
166
|
} catch (Exception e) {
|
167
|
System.err.println(e.toString());
|
168
|
}
|
169
|
|
170
|
return parser;
|
171
|
}
|
172
|
|
173
|
/**
|
174
|
* callback method used by the SAX Parser when the start tag of an
|
175
|
* element is detected. Used in this context to parse and store
|
176
|
* the query information in class variables.
|
177
|
*/
|
178
|
public void startElement (String uri, String localName,
|
179
|
String qName, Attributes atts)
|
180
|
throws SAXException {
|
181
|
BasicNode currentNode = new BasicNode(localName);
|
182
|
// add attributes to BasicNode here
|
183
|
if (atts != null) {
|
184
|
int len = atts.getLength();
|
185
|
for (int i = 0; i < len; i++) {
|
186
|
currentNode.setAttribute(atts.getLocalName(i), atts.getValue(i));
|
187
|
}
|
188
|
}
|
189
|
|
190
|
elementStack.push(currentNode);
|
191
|
if (currentNode.getTagName().equals("querygroup")) {
|
192
|
QueryGroup currentGroup = new QueryGroup(
|
193
|
currentNode.getAttribute("operator"));
|
194
|
if (query == null) {
|
195
|
query = currentGroup;
|
196
|
} else {
|
197
|
QueryGroup parentGroup = (QueryGroup)queryStack.peek();
|
198
|
parentGroup.addChild(currentGroup);
|
199
|
}
|
200
|
queryStack.push(currentGroup);
|
201
|
}
|
202
|
}
|
203
|
|
204
|
/**
|
205
|
* callback method used by the SAX Parser when the end tag of an
|
206
|
* element is detected. Used in this context to parse and store
|
207
|
* the query information in class variables.
|
208
|
*/
|
209
|
public void endElement (String uri, String localName,
|
210
|
String qName) throws SAXException {
|
211
|
BasicNode leaving = (BasicNode)elementStack.pop();
|
212
|
if (leaving.getTagName().equals("queryterm")) {
|
213
|
boolean isCaseSensitive = (new Boolean(
|
214
|
leaving.getAttribute("casesensitive"))).booleanValue();
|
215
|
QueryTerm currentTerm = null;
|
216
|
if (currentPathexpr == null) {
|
217
|
currentTerm = new QueryTerm(isCaseSensitive,
|
218
|
leaving.getAttribute("searchmode"),currentValue);
|
219
|
} else {
|
220
|
currentTerm = new QueryTerm(isCaseSensitive,
|
221
|
leaving.getAttribute("searchmode"),currentValue,
|
222
|
currentPathexpr);
|
223
|
}
|
224
|
QueryGroup currentGroup = (QueryGroup)queryStack.peek();
|
225
|
currentGroup.addChild(currentTerm);
|
226
|
currentValue = null;
|
227
|
currentPathexpr = null;
|
228
|
} else if (leaving.getTagName().equals("querygroup")) {
|
229
|
QueryGroup leavingGroup = (QueryGroup)queryStack.pop();
|
230
|
}
|
231
|
}
|
232
|
|
233
|
/**
|
234
|
* callback method used by the SAX Parser when the text sequences of an
|
235
|
* xml stream are detected. Used in this context to parse and store
|
236
|
* the query information in class variables.
|
237
|
*/
|
238
|
public void characters(char ch[], int start, int length) {
|
239
|
|
240
|
String inputString = new String(ch, start, length);
|
241
|
BasicNode currentNode = (BasicNode)elementStack.peek();
|
242
|
String currentTag = currentNode.getTagName();
|
243
|
if (currentTag.equals("meta_file_id")) {
|
244
|
meta_file_id = inputString;
|
245
|
} else if (currentTag.equals("querytitle")) {
|
246
|
querytitle = inputString;
|
247
|
} else if (currentTag.equals("value")) {
|
248
|
currentValue = inputString;
|
249
|
} else if (currentTag.equals("pathexpr")) {
|
250
|
currentPathexpr = inputString;
|
251
|
} else if (currentTag.equals("returndoctype")) {
|
252
|
doctypeList.add(inputString);
|
253
|
} else if (currentTag.equals("returnfield")) {
|
254
|
returnFieldList.add(inputString);
|
255
|
containsExtendedSQL = true;
|
256
|
}
|
257
|
}
|
258
|
|
259
|
|
260
|
/**
|
261
|
* create a SQL serialization of the query that this instance represents
|
262
|
*/
|
263
|
public String printSQL() {
|
264
|
StringBuffer self = new StringBuffer();
|
265
|
|
266
|
self.append("SELECT docid,docname,doctype,doctitle,");
|
267
|
self.append("date_created, date_updated ");
|
268
|
self.append("FROM xml_documents WHERE docid IN (");
|
269
|
|
270
|
// This determines the documents that meet the query conditions
|
271
|
self.append(query.printSQL());
|
272
|
|
273
|
self.append(") ");
|
274
|
|
275
|
// Add SQL to filter for doctypes requested in the query
|
276
|
if (!doctypeList.isEmpty()) {
|
277
|
boolean firstdoctype = true;
|
278
|
self.append(" AND (");
|
279
|
Enumeration en = doctypeList.elements();
|
280
|
while (en.hasMoreElements()) {
|
281
|
String currentDoctype = (String)en.nextElement();
|
282
|
if (firstdoctype) {
|
283
|
firstdoctype = false;
|
284
|
self.append(" doctype = '" + currentDoctype + "'");
|
285
|
} else {
|
286
|
self.append(" OR doctype = '" + currentDoctype + "'");
|
287
|
}
|
288
|
}
|
289
|
self.append(") ");
|
290
|
}
|
291
|
|
292
|
return self.toString();
|
293
|
}
|
294
|
|
295
|
/**
|
296
|
* This method prints sql based upon the <returnfield> tag in the
|
297
|
* pathquery document. This allows for customization of the
|
298
|
* returned fields
|
299
|
* @param doclist the list of document ids to search by
|
300
|
*/
|
301
|
public String printExtendedSQL(String doclist)
|
302
|
{
|
303
|
StringBuffer self = new StringBuffer();
|
304
|
self.append("select xml_nodes.docid, xml_index.path, xml_nodes.nodedata ");
|
305
|
self.append("from xml_index, xml_nodes where xml_index.nodeid=");
|
306
|
self.append("xml_nodes.parentnodeid and (xml_index.path like '");
|
307
|
boolean firstfield = true;
|
308
|
//put the returnfields into the query
|
309
|
//the for loop allows for multiple fields
|
310
|
for(int i=0; i<returnFieldList.size(); i++)
|
311
|
{
|
312
|
if(firstfield)
|
313
|
{
|
314
|
firstfield = false;
|
315
|
self.append((String)returnFieldList.elementAt(i));
|
316
|
self.append("' ");
|
317
|
}
|
318
|
else
|
319
|
{
|
320
|
self.append("or xml_index.path like '");
|
321
|
self.append((String)returnFieldList.elementAt(i));
|
322
|
self.append("' ");
|
323
|
}
|
324
|
}
|
325
|
self.append(") AND xml_nodes.docid in (");
|
326
|
//self.append(query.printSQL());
|
327
|
self.append(doclist);
|
328
|
self.append(")");
|
329
|
self.append(" AND xml_nodes.nodetype = 'TEXT'");
|
330
|
|
331
|
//System.out.println(self.toString());
|
332
|
return self.toString();
|
333
|
}
|
334
|
|
335
|
public static String printRelationSQL(String docid)
|
336
|
{
|
337
|
StringBuffer self = new StringBuffer();
|
338
|
self.append("select subject, relationship, object, subdoctype, ");
|
339
|
self.append("objdoctype from xml_relation ");
|
340
|
self.append("where subject like '").append(docid).append("'");
|
341
|
return self.toString();
|
342
|
}
|
343
|
|
344
|
/**
|
345
|
* Prints sql that returns all relations in the database.
|
346
|
*/
|
347
|
public static String printPackageSQL()
|
348
|
{
|
349
|
StringBuffer self = new StringBuffer();
|
350
|
self.append("select z.nodedata, x.nodedata, y.nodedata from ");
|
351
|
self.append("(select nodeid, parentnodeid from xml_index where path like ");
|
352
|
self.append("'package/relation/subject') s, (select nodeid, parentnodeid ");
|
353
|
self.append("from xml_index where path like ");
|
354
|
self.append("'package/relation/relationship') rel, ");
|
355
|
self.append("(select nodeid, parentnodeid from xml_index where path like ");
|
356
|
self.append("'package/relation/object') o, ");
|
357
|
self.append("xml_nodes x, xml_nodes y, xml_nodes z ");
|
358
|
self.append("where s.parentnodeid = rel.parentnodeid ");
|
359
|
self.append("and rel.parentnodeid = o.parentnodeid ");
|
360
|
self.append("and x.parentnodeid in rel.nodeid ");
|
361
|
self.append("and y.parentnodeid in o.nodeid ");
|
362
|
self.append("and z.parentnodeid in s.nodeid ");
|
363
|
//self.append("and z.nodedata like '%");
|
364
|
//self.append(docid);
|
365
|
//self.append("%'");
|
366
|
return self.toString();
|
367
|
}
|
368
|
|
369
|
/**
|
370
|
* Prints sql that returns all relations in the database that were input
|
371
|
* under a specific docid
|
372
|
* @param docid the docid to search for.
|
373
|
*/
|
374
|
public static String printPackageSQL(String docid)
|
375
|
{
|
376
|
StringBuffer self = new StringBuffer();
|
377
|
self.append("select z.nodedata, x.nodedata, y.nodedata from ");
|
378
|
self.append("(select nodeid, parentnodeid from xml_index where path like ");
|
379
|
self.append("'package/relation/subject') s, (select nodeid, parentnodeid ");
|
380
|
self.append("from xml_index where path like ");
|
381
|
self.append("'package/relation/relationship') rel, ");
|
382
|
self.append("(select nodeid, parentnodeid from xml_index where path like ");
|
383
|
self.append("'package/relation/object') o, ");
|
384
|
self.append("xml_nodes x, xml_nodes y, xml_nodes z ");
|
385
|
self.append("where s.parentnodeid = rel.parentnodeid ");
|
386
|
self.append("and rel.parentnodeid = o.parentnodeid ");
|
387
|
self.append("and x.parentnodeid in rel.nodeid ");
|
388
|
self.append("and y.parentnodeid in o.nodeid ");
|
389
|
self.append("and z.parentnodeid in s.nodeid ");
|
390
|
self.append("and z.docid like '").append(docid).append("'");
|
391
|
|
392
|
return self.toString();
|
393
|
}
|
394
|
|
395
|
/**
|
396
|
* Returns all of the relations that has a certain docid in the subject
|
397
|
* or the object.
|
398
|
*
|
399
|
* @param docid the docid to search for
|
400
|
*/
|
401
|
public static String printPackageSQL(String subDocidURL, String objDocidURL)
|
402
|
{
|
403
|
StringBuffer self = new StringBuffer();
|
404
|
self.append("select z.nodedata, x.nodedata, y.nodedata from ");
|
405
|
self.append("(select nodeid, parentnodeid from xml_index where path like ");
|
406
|
self.append("'package/relation/subject') s, (select nodeid, parentnodeid ");
|
407
|
self.append("from xml_index where path like ");
|
408
|
self.append("'package/relation/relationship') rel, ");
|
409
|
self.append("(select nodeid, parentnodeid from xml_index where path like ");
|
410
|
self.append("'package/relation/object') o, ");
|
411
|
self.append("xml_nodes x, xml_nodes y, xml_nodes z ");
|
412
|
self.append("where s.parentnodeid = rel.parentnodeid ");
|
413
|
self.append("and rel.parentnodeid = o.parentnodeid ");
|
414
|
self.append("and x.parentnodeid in rel.nodeid ");
|
415
|
self.append("and y.parentnodeid in o.nodeid ");
|
416
|
self.append("and z.parentnodeid in s.nodeid ");
|
417
|
self.append("and (z.nodedata like '");
|
418
|
self.append(subDocidURL);
|
419
|
self.append("' or y.nodedata like '");
|
420
|
self.append(objDocidURL);
|
421
|
self.append("')");
|
422
|
return self.toString();
|
423
|
}
|
424
|
|
425
|
public static String printGetDocByDoctypeSQL(String docid)
|
426
|
{
|
427
|
StringBuffer self = new StringBuffer();
|
428
|
|
429
|
self.append("SELECT docid,docname,doctype,doctitle,");
|
430
|
self.append("date_created, date_updated ");
|
431
|
self.append("FROM xml_documents WHERE docid IN (");
|
432
|
self.append(docid).append(")");
|
433
|
return self.toString();
|
434
|
}
|
435
|
|
436
|
/**
|
437
|
* create a String description of the query that this instance represents.
|
438
|
* This should become a way to get the XML serialization of the query.
|
439
|
*/
|
440
|
public String toString() {
|
441
|
return "meta_file_id=" + meta_file_id + "\n" +
|
442
|
"querytitle=" + querytitle + "\n" + query;
|
443
|
}
|
444
|
|
445
|
/** a utility class that represents a group of terms in a query */
|
446
|
private class QueryGroup {
|
447
|
private String operator = null; // indicates how query terms are combined
|
448
|
private Vector children = null; // the list of query terms and groups
|
449
|
|
450
|
/**
|
451
|
* construct a new QueryGroup
|
452
|
*
|
453
|
* @param operator the boolean conector used to connect query terms
|
454
|
* in this query group
|
455
|
*/
|
456
|
public QueryGroup(String operator) {
|
457
|
this.operator = operator;
|
458
|
children = new Vector();
|
459
|
}
|
460
|
|
461
|
/**
|
462
|
* Add a child QueryGroup to this QueryGroup
|
463
|
*
|
464
|
* @param qgroup the query group to be added to the list of terms
|
465
|
*/
|
466
|
public void addChild(QueryGroup qgroup) {
|
467
|
children.add((Object)qgroup);
|
468
|
}
|
469
|
|
470
|
/**
|
471
|
* Add a child QueryTerm to this QueryGroup
|
472
|
*
|
473
|
* @param qterm the query term to be added to the list of terms
|
474
|
*/
|
475
|
public void addChild(QueryTerm qterm) {
|
476
|
children.add((Object)qterm);
|
477
|
}
|
478
|
|
479
|
/**
|
480
|
* Retrieve an Enumeration of query terms for this QueryGroup
|
481
|
*/
|
482
|
public Enumeration getChildren() {
|
483
|
return children.elements();
|
484
|
}
|
485
|
|
486
|
/**
|
487
|
* create a SQL serialization of the query that this instance represents
|
488
|
*/
|
489
|
public String printSQL() {
|
490
|
StringBuffer self = new StringBuffer();
|
491
|
boolean first = true;
|
492
|
|
493
|
self.append("(");
|
494
|
|
495
|
Enumeration en= getChildren();
|
496
|
while (en.hasMoreElements()) {
|
497
|
Object qobject = en.nextElement();
|
498
|
if (first) {
|
499
|
first = false;
|
500
|
} else {
|
501
|
self.append(" " + operator + " ");
|
502
|
}
|
503
|
if (qobject instanceof QueryGroup) {
|
504
|
QueryGroup qg = (QueryGroup)qobject;
|
505
|
self.append(qg.printSQL());
|
506
|
} else if (qobject instanceof QueryTerm) {
|
507
|
QueryTerm qt = (QueryTerm)qobject;
|
508
|
self.append(qt.printSQL());
|
509
|
} else {
|
510
|
System.err.println("qobject wrong type: fatal error");
|
511
|
}
|
512
|
}
|
513
|
self.append(") \n");
|
514
|
return self.toString();
|
515
|
}
|
516
|
|
517
|
/**
|
518
|
* create a String description of the query that this instance represents.
|
519
|
* This should become a way to get the XML serialization of the query.
|
520
|
*/
|
521
|
public String toString() {
|
522
|
StringBuffer self = new StringBuffer();
|
523
|
|
524
|
self.append(" (Query group operator=" + operator + "\n");
|
525
|
Enumeration en= getChildren();
|
526
|
while (en.hasMoreElements()) {
|
527
|
Object qobject = en.nextElement();
|
528
|
self.append(qobject);
|
529
|
}
|
530
|
self.append(" )\n");
|
531
|
return self.toString();
|
532
|
}
|
533
|
}
|
534
|
|
535
|
/** a utility class that represents a single term in a query */
|
536
|
private class QueryTerm {
|
537
|
private boolean casesensitive = false;
|
538
|
private String searchmode = null;
|
539
|
private String value = null;
|
540
|
private String pathexpr = null;
|
541
|
|
542
|
/**
|
543
|
* Construct a new instance of a query term for a free text search
|
544
|
* (using the value only)
|
545
|
*
|
546
|
* @param casesensitive flag indicating whether case is used to match
|
547
|
* @param searchmode determines what kind of substring match is performed
|
548
|
* (one of starts-with|ends-with|contains|matches-exactly)
|
549
|
* @param value the text value to match
|
550
|
*/
|
551
|
public QueryTerm(boolean casesensitive, String searchmode,
|
552
|
String value) {
|
553
|
this.casesensitive = casesensitive;
|
554
|
this.searchmode = searchmode;
|
555
|
this.value = value;
|
556
|
}
|
557
|
|
558
|
/**
|
559
|
* Construct a new instance of a query term for a structured search
|
560
|
* (matching the value only for those nodes in the pathexpr)
|
561
|
*
|
562
|
* @param casesensitive flag indicating whether case is used to match
|
563
|
* @param searchmode determines what kind of substring match is performed
|
564
|
* (one of starts-with|ends-with|contains|matches-exactly)
|
565
|
* @param value the text value to match
|
566
|
* @param pathexpr the hierarchical path to the nodes to be searched
|
567
|
*/
|
568
|
public QueryTerm(boolean casesensitive, String searchmode,
|
569
|
String value, String pathexpr) {
|
570
|
this(casesensitive, searchmode, value);
|
571
|
this.pathexpr = pathexpr;
|
572
|
}
|
573
|
|
574
|
/** determine if the QueryTerm is case sensitive */
|
575
|
public boolean isCaseSensitive() {
|
576
|
return casesensitive;
|
577
|
}
|
578
|
|
579
|
/** get the searchmode parameter */
|
580
|
public String getSearchMode() {
|
581
|
return searchmode;
|
582
|
}
|
583
|
|
584
|
/** get the Value parameter */
|
585
|
public String getValue() {
|
586
|
return value;
|
587
|
}
|
588
|
|
589
|
/** get the path expression parameter */
|
590
|
public String getPathExpression() {
|
591
|
return pathexpr;
|
592
|
}
|
593
|
|
594
|
/**
|
595
|
* create a SQL serialization of the query that this instance represents
|
596
|
*/
|
597
|
public String printSQL() {
|
598
|
StringBuffer self = new StringBuffer();
|
599
|
|
600
|
// Uppercase the search string if case match is not important
|
601
|
String casevalue = null;
|
602
|
String nodedataterm = null;
|
603
|
|
604
|
if (casesensitive) {
|
605
|
nodedataterm = "nodedata";
|
606
|
casevalue = value;
|
607
|
} else {
|
608
|
nodedataterm = "UPPER(nodedata)";
|
609
|
casevalue = value.toUpperCase();
|
610
|
}
|
611
|
|
612
|
// Add appropriate wildcards to search string
|
613
|
String searchvalue = null;
|
614
|
if (searchmode.equals("starts-with")) {
|
615
|
searchvalue = casevalue + "%";
|
616
|
} else if (searchmode.equals("ends-with")) {
|
617
|
searchvalue = "%" + casevalue;
|
618
|
} else if (searchmode.equals("contains")) {
|
619
|
searchvalue = "%" + casevalue + "%";
|
620
|
} else {
|
621
|
searchvalue = casevalue;
|
622
|
}
|
623
|
|
624
|
self.append("SELECT DISTINCT docid FROM xml_nodes WHERE \n");
|
625
|
|
626
|
if (pathexpr != null) {
|
627
|
self.append(nodedataterm + " LIKE " + "'" + searchvalue + "' ");
|
628
|
self.append("AND parentnodeid IN ");
|
629
|
self.append("(SELECT nodeid FROM xml_index WHERE path LIKE " +
|
630
|
"'" + pathexpr + "') " );
|
631
|
} else {
|
632
|
self.append(nodedataterm + " LIKE " + "'" + searchvalue + "' ");
|
633
|
}
|
634
|
|
635
|
return self.toString();
|
636
|
}
|
637
|
|
638
|
/**
|
639
|
* create a String description of the query that this instance represents.
|
640
|
* This should become a way to get the XML serialization of the query.
|
641
|
*/
|
642
|
public String toString() {
|
643
|
StringBuffer self = new StringBuffer();
|
644
|
|
645
|
self.append(" Query Term iscasesensitive=" + casesensitive + "\n");
|
646
|
self.append(" searchmode=" + searchmode + "\n");
|
647
|
self.append(" value=" + value + "\n");
|
648
|
if (pathexpr != null) {
|
649
|
self.append(" pathexpr=" + pathexpr + "\n");
|
650
|
}
|
651
|
|
652
|
return self.toString();
|
653
|
}
|
654
|
}
|
655
|
}
|
656
|
|
657
|
/**
|
658
|
* '$Log$
|
659
|
* 'Revision 1.16 2000/09/26 22:06:52 berkley
|
660
|
* 'Added backtrack functionality. Backtracking works by passing a returndoc parameter. There can be more than one. If a document that is hit by a query is not of type returndoc then it searches the database for a related file of type returndoc. If one is found it is displayed, if no relation is found, the original is displayed.
|
661
|
* '
|
662
|
* 'Support was also added for an index of relations. the table xml_relation handles the all of the relation indexing.
|
663
|
* '
|
664
|
* 'Revision 1.15 2000/09/15 19:52:12 berkley
|
665
|
* 'Added functionality for package specifications. metacatservlet now contains a new action called getrelateddocument that handles retrieving related documents using the metacatURL specification (metacatURL.java). DBQuery contains new code in runQuery that embeds relation tags in the returned hashtable describing the documents related to each docid. querySpecification contains a new method which prints the sql that does the relation query.
|
666
|
* '
|
667
|
* 'Revision 1.14 2000/08/31 21:20:39 berkley
|
668
|
* 'changed xslf for new returnfield scheme. the returnfields are now returned as <param name="<returnfield>"> tags.
|
669
|
* 'hThe sql for the returnfield query was redone to fix a previous problem with slow queries
|
670
|
* '
|
671
|
* 'Revision 1.13 2000/08/23 22:55:38 berkley
|
672
|
* 'changed the field names to be case-sensitive in the returnfields
|
673
|
* '
|
674
|
* 'Revision 1.12 2000/08/23 17:29:05 berkley
|
675
|
* 'added support for the returnfield parameter
|
676
|
* '-QuerySpecification now sets a flag (containsExtendedSQL) when there are returnfield items in the pathquery document.
|
677
|
* 'the accessor method containsExtendedSQL() can be called by other classes to check for extended return parameters
|
678
|
* '-getReturnFields returns a Vector of the names of each specified return field.
|
679
|
* '-printExtendedSQL returns a string of the extra SQL statements required for the query.
|
680
|
* '
|
681
|
* '-a calling class should first check containsExtendedSQL to make sure that there are extra fields being returned, then call printExtendedSQL to
|
682
|
* 'insert the extra SQL into the query. (Note that this is how DBQuery implements this.)
|
683
|
* '
|
684
|
* 'Revision 1.11 2000/08/14 20:53:34 jones
|
685
|
* 'Added "release" keyword to all metacat source files so that the release
|
686
|
* 'number will be evident in software distributions.
|
687
|
* '
|
688
|
* 'Revision 1.10 2000/06/26 10:35:05 jones
|
689
|
* 'Merged in substantial changes to DBWriter and associated classes and to
|
690
|
* 'the MetaCatServlet in order to accomodate the new UPDATE and DELETE
|
691
|
* 'functions. The command line tools and the parameters for the
|
692
|
* 'servlet have changed substantially.
|
693
|
* '
|
694
|
* 'Revision 1.9.2.3 2000/06/25 23:38:17 jones
|
695
|
* 'Added RCSfile keyword
|
696
|
* '
|
697
|
* 'Revision 1.9.2.2 2000/06/25 23:34:18 jones
|
698
|
* 'Changed documentation formatting, added log entries at bottom of source files
|
699
|
* ''
|
700
|
*/
|