Project

General

Profile

1 155 jones
/**
2 203 jones
 *  '$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 349 jones
 *    Release: @release@
11 155 jones
 *
12 203 jones
 *   '$Author$'
13
 *     '$Date$'
14
 * '$Revision$'
15 669 jones
 *
16
 * This program is free software; you can redistribute it and/or modify
17
 * it under the terms of the GNU General Public License as published by
18
 * the Free Software Foundation; either version 2 of the License, or
19
 * (at your option) any later version.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 * GNU General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU General Public License
27
 * along with this program; if not, write to the Free Software
28
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29 155 jones
 */
30
31
package edu.ucsb.nceas.metacat;
32
33 899 berkley
import edu.ucsb.nceas.dbadapter.*;
34
35 155 jones
import java.io.*;
36 1354 tao
import java.util.Hashtable;
37 155 jones
import java.util.Stack;
38 158 jones
import java.util.Vector;
39 159 jones
import java.util.Enumeration;
40 155 jones
41 185 jones
import org.xml.sax.Attributes;
42 158 jones
import org.xml.sax.InputSource;
43
import org.xml.sax.SAXException;
44
import org.xml.sax.SAXParseException;
45 185 jones
import org.xml.sax.XMLReader;
46
import org.xml.sax.helpers.XMLReaderFactory;
47
import org.xml.sax.helpers.DefaultHandler;
48 155 jones
49 402 berkley
/**
50 172 jones
 * A Class that represents a structured query, and can be
51
 * constructed from an XML serialization conforming to @see pathquery.dtd.
52
 * The printSQL() method can be used to print a SQL serialization of the query.
53 155 jones
 */
54 185 jones
public class QuerySpecification extends DefaultHandler {
55 155 jones
56 745 jones
  /** flag determining whether extended query terms are present */
57 402 berkley
  private boolean containsExtendedSQL=false;
58 745 jones
  /** Identifier for this query document */
59 158 jones
  private String meta_file_id;
60 745 jones
  /** Title of this query */
61
  private String queryTitle;
62
  /** List of document types to be returned using package back tracing */
63 743 jones
  private Vector returnDocList;
64 745 jones
  /** List of document types to be searched */
65 743 jones
  private Vector filterDocList;
66 745 jones
  /** List of fields to be returned in result set */
67 402 berkley
  private Vector returnFieldList;
68 745 jones
  /** List of users owning documents to be searched */
69 535 jones
  private Vector ownerList;
70 745 jones
  /** List of sites/scopes used to constrain search */
71 535 jones
  private Vector siteList;
72 745 jones
  /** The root query group that contains the recursive query constraints */
73 158 jones
  private QueryGroup query = null;
74 1348 tao
75 745 jones
  // Query data structures used temporarily during XML parsing
76 158 jones
  private Stack elementStack;
77
  private Stack queryStack;
78 159 jones
  private String currentValue;
79
  private String currentPathexpr;
80 172 jones
  private String parserName = null;
81 535 jones
  private String accNumberSeparator = null;
82 899 berkley
  private static final AbstractDatabase dbAdapter = MetaCatUtil.dbAdapter;
83 1301 tao
84 1350 tao
  private int countPercentageSearchItem = 0;
85
  private boolean percentageSearch = false;
86
87 1301 tao
  private String userName = null;
88
  private static final String PUBLIC = "public";
89
  private String [] group = null;
90 158 jones
91 1348 tao
  public static final String ATTRIBUTESYMBOL = "@";
92 1354 tao
  private boolean hasAttributeReturnField = false;
93
  private Hashtable attributeReturnList = new Hashtable();
94
  private int countAttributeReturnField = 0;
95 155 jones
  /**
96
   * construct an instance of the QuerySpecification class
97
   *
98 172 jones
   * @param queryspec the XML representation of the query (should conform
99
   *                  to pathquery.dtd) as a Reader
100
   * @param parserName the fully qualified name of a Java Class implementing
101 185 jones
   *                  the org.xml.sax.XMLReader interface
102 155 jones
   */
103 535 jones
  public QuerySpecification( Reader queryspec, String parserName,
104
         String accNumberSeparator ) throws IOException {
105 155 jones
    super();
106 402 berkley
107 172 jones
    // Initialize the class variables
108 743 jones
    returnDocList = new Vector();
109
    filterDocList = new Vector();
110 158 jones
    elementStack = new Stack();
111
    queryStack   = new Stack();
112 402 berkley
    returnFieldList = new Vector();
113 535 jones
    ownerList = new Vector();
114
    siteList = new Vector();
115 172 jones
    this.parserName = parserName;
116 535 jones
    this.accNumberSeparator = accNumberSeparator;
117 158 jones
118
    // Initialize the parser and read the queryspec
119 185 jones
    XMLReader parser = initializeParser();
120 181 jones
    if (parser == null) {
121
      System.err.println("SAX parser not instantiated properly.");
122
    }
123 155 jones
    try {
124
      parser.parse(new InputSource(queryspec));
125
    } catch (SAXException e) {
126 675 berkley
      System.err.println("error parsing data in " +
127
                         "QuerySpecification.QuerySpecification");
128 180 jones
      System.err.println(e.getMessage());
129 155 jones
    }
130
  }
131
132
  /**
133
   * construct an instance of the QuerySpecification class
134
   *
135 172 jones
   * @param queryspec the XML representation of the query (should conform
136
   *                  to pathquery.dtd) as a String
137
   * @param parserName the fully qualified name of a Java Class implementing
138
   *                  the org.xml.sax.Parser interface
139 155 jones
   */
140 535 jones
  public QuerySpecification( String queryspec, String parserName,
141
         String accNumberSeparator) throws IOException {
142
    this(new StringReader(queryspec), parserName, accNumberSeparator);
143 155 jones
  }
144 1301 tao
145
  /**
146
   * Method to set user name
147
   *
148
   * @param myName  the user name
149
   */
150
  public void setUserName(String myName)
151
  {
152
    this.userName = myName;
153
  }
154
155
  /**
156
   * Method to set user group
157
   *
158
   * @param myGroup  the user group
159
   */
160
  public void setGroup(String [] myGroup)
161
  {
162
    this.group = myGroup;
163
  }
164 1350 tao
  /**
165
   * Method to indicate this query is a percentage search
166
   */
167
  public boolean isPercentageSearch()
168
  {
169
    return percentageSearch;
170
  }
171 1301 tao
  /*
172
   * Method to get owner query. If it is owner it has all permission
173
   */
174
  private String createOwerQuery()
175
  {
176
    String ownerQuery = null;
177 1452 tao
    ownerQuery = "SELECT docid FROM xml_documents WHERE ";
178 1301 tao
    if (userName != null && !userName.equals(""))
179
    {
180 1452 tao
      ownerQuery = ownerQuery + "user_owner ='"+ userName +"'";
181 1301 tao
    }
182
183
    MetaCatUtil.debugMessage("OwnerQuery: "+ownerQuery, 30);
184
    return ownerQuery;
185
  }
186
187
  /*
188
   * Method to create query for xml_access, this part is to get docid list which
189
   * have a allow rule for a given user
190
   */
191
  private String createAllowRuleQuery()
192
  {
193
    String allowQuery = null;
194 1446 tao
    String allowString = constructAllowString();
195 1447 tao
    allowQuery ="SELECT docid from xml_access WHERE( "+allowString;
196
    allowQuery = allowQuery +") AND subtreeid IS NULL";
197 1446 tao
    MetaCatUtil.debugMessage("allow query is: "+ allowQuery, 30);
198
    return allowQuery;
199
200
201
  }
202
203
  /* Method to construct a allow rule string */
204
  private String constructAllowString()
205
  {
206
    String allowQuery ="";
207
     // add allow rule for user name
208
     if (userName != null && !userName.equals(""))
209 1301 tao
    {
210
      allowQuery = allowQuery +"(principal_name = '" + userName
211 1304 tao
                              +"' AND perm_type = 'allow'"
212
                              +" AND (permission='4' OR permission='7'))";
213 1301 tao
    }
214
    // add allow rule for public
215
    allowQuery = allowQuery +"OR (principal_name = '" + PUBLIC
216 1304 tao
                              +"' AND perm_type = 'allow'"
217
                              +" AND (permission='4' OR permission='7'))";
218 1301 tao
219
    // add allow rule for group
220
    if (group != null)
221
    {
222
      for (int i = 0; i< group.length; i++)
223
      {
224
        String groupUint = group[i];
225
        if (groupUint != null && !groupUint.equals(""))
226
        {
227
          allowQuery = allowQuery +" OR (principal_name = '" + groupUint
228 1304 tao
                              +"' AND perm_type = 'allow'"
229
                              +" AND (permission='4' OR permission='7'))";
230 1301 tao
        }//if
231
      }//for
232
    }//if
233 1446 tao
    MetaCatUtil.debugMessage("allow string is: "+ allowQuery, 40);
234 1301 tao
    return allowQuery;
235
  }
236 155 jones
237 1301 tao
   /*
238
   * Method to create query for xml_access, this part is to get docid list which
239
   * have a deny rule and perm_order is allowFirst for a given user. This means
240
   * the user will be denied to read
241
   */
242
  private String createDenyRuleQuery()
243
  {
244
    String denyQuery = null;
245 1446 tao
    String denyString = constructDenyString();
246 1447 tao
    denyQuery ="SELECT docid from xml_access WHERE( " + denyString;
247
    denyQuery = denyQuery + ") AND subtreeid IS NULL ";
248 1446 tao
    MetaCatUtil.debugMessage("denyquery is: "+ denyQuery, 30);
249
    return denyQuery;
250
251
  }
252
  /* Construct deny string */
253
  private String constructDenyString()
254
  {
255
    String denyQuery ="";
256 1301 tao
    // add deny rule for user name
257
    if (userName != null && !userName.equals(""))
258
    {
259
      denyQuery = denyQuery +"(principal_name = '" + userName
260
                              +"' AND perm_type = 'deny' "
261 1304 tao
                              +"AND perm_order ='allowFirst'"
262
                              +" AND (permission='4' OR permission='7'))";
263 1301 tao
    }
264
    // add deny rule for public
265
    denyQuery = denyQuery +"OR (principal_name = '" + PUBLIC
266
                               +"' AND perm_type = 'deny' "
267 1304 tao
                               +"AND perm_order ='allowFirst'"
268
                               +" AND (permission='4' OR permission='7'))";
269 1301 tao
270
    // add allow rule for group
271
    if (group != null)
272
    {
273
      for (int i = 0; i< group.length; i++)
274
      {
275
        String groupUint = group[i];
276
        if (groupUint != null && !groupUint.equals(""))
277
        {
278
          denyQuery = denyQuery +" OR (principal_name = '" + groupUint
279
                                +"' AND perm_type = 'deny' "
280 1304 tao
                                +"AND perm_order ='allowFirst'"
281
                                +" AND (permission='4' OR permission='7'))";
282 1301 tao
        }//if
283
      }//for
284
    }//if
285
    return denyQuery;
286
  }
287
288
  /**
289
   * Method to append a access control query to SQL. So in DBQuery class, we can
290
   * get docid from both user specified query and access control query. We don't
291
   * need to checking permission after we get the doclist. It will be good to
292
   * performance
293
   *
294
   */
295
  public String getAccessQuery()
296
  {
297
    String accessQuery = null;
298
    String onwer = createOwerQuery();
299
    String allow = createAllowRuleQuery();
300
    String deny = createDenyRuleQuery();
301
    accessQuery = " AND (docid IN("+ onwer + ")";
302
    accessQuery = accessQuery + " OR (docid IN (" + allow + ")"
303
                 + " AND docid NOT IN ("+ deny + ")))";
304
    MetaCatUtil.debugMessage("accessquery is: "+ accessQuery, 30);
305
    return accessQuery;
306
  }
307
308 155 jones
  /** Main routine for testing */
309
  static public void main(String[] args) {
310
311
     if (args.length < 1) {
312
       System.err.println("Wrong number of arguments!!!");
313
       System.err.println("USAGE: java QuerySpecification <xmlfile>");
314
       return;
315
     } else {
316 711 jones
       int i = 0;
317
       boolean useXMLIndex = true;
318
       if ( args[i].equals( "-noindex" ) ) {
319
         useXMLIndex = false;
320
         i++;
321
       }
322
       String xmlfile  = args[i];
323
324 155 jones
       try {
325 203 jones
         MetaCatUtil util = new MetaCatUtil();
326 155 jones
         FileReader xml = new FileReader(new File(xmlfile));
327 203 jones
         QuerySpecification qspec =
328 535 jones
                 new QuerySpecification(xml, util.getOption("saxparser"),
329
                                        util.getOption("accNumberSeparator"));
330 706 bojilova
         System.out.println(qspec.printSQL(useXMLIndex));
331 181 jones
332 155 jones
       } catch (IOException e) {
333
         System.err.println(e.getMessage());
334
       }
335
336
     }
337
  }
338 402 berkley
339
  /**
340
   * Returns true if the parsed query contains and extended xml query
341
   * (i.e. there is at least one &lt;returnfield&gt; in the pathquery document)
342
   */
343
  public boolean containsExtendedSQL()
344
  {
345
    if(containsExtendedSQL)
346
    {
347
      return true;
348
    }
349
    else
350
    {
351
      return false;
352
    }
353
  }
354
355
  /**
356 1354 tao
   * A method to get if the query has an attribute return field
357
   */
358
  public boolean containAttributeReturnField()
359
  {
360
    return hasAttributeReturnField;
361
  }
362
363
  /**
364 745 jones
   * Accessor method to return the identifier of this Query
365
   */
366
  public String getIdentifier()
367
  {
368
    return meta_file_id;
369
  }
370
371
  /**
372
   * method to set the identifier of this query
373
   */
374
  public void setIdentifier(String id) {
375
    this.meta_file_id = id;
376
  }
377
378
  /**
379
   * Accessor method to return the title of this Query
380
   */
381
  public String getQueryTitle()
382
  {
383
    return queryTitle;
384
  }
385
386
  /**
387
   * method to set the title of this query
388
   */
389
  public void setQueryTitle(String title)
390
  {
391
    this.queryTitle = title;
392
  }
393
394
  /**
395
   * Accessor method to return a vector of the return document types as
396
   * defined in the &lt;returndoctype&gt; tag in the pathquery dtd.
397
   */
398
  public Vector getReturnDocList()
399
  {
400
    return this.returnDocList;
401
  }
402
403
  /**
404
   * method to set the list of return docs of this query
405
   */
406
  public void setReturnDocList(Vector returnDocList)
407
  {
408
    this.returnDocList = returnDocList;
409
  }
410
411
  /**
412
   * Accessor method to return a vector of the filter doc types as
413
   * defined in the &lt;filterdoctype&gt; tag in the pathquery dtd.
414
   */
415
  public Vector getFilterDocList()
416
  {
417
    return this.filterDocList;
418
  }
419
420
  /**
421
   * method to set the list of filter docs of this query
422
   */
423
  public void setFilterDocList(Vector filterDocList)
424
  {
425
    this.filterDocList = filterDocList;
426
  }
427
428
  /**
429 402 berkley
   * Accessor method to return a vector of the extended return fields as
430
   * defined in the &lt;returnfield&gt; tag in the pathquery dtd.
431
   */
432
  public Vector getReturnFieldList()
433
  {
434
    return this.returnFieldList;
435
  }
436 155 jones
437 172 jones
  /**
438 745 jones
   * method to set the list of fields to be returned by this query
439
   */
440
  public void setReturnFieldList(Vector returnFieldList)
441
  {
442
    this.returnFieldList = returnFieldList;
443
  }
444
445
  /**
446
   * Accessor method to return a vector of the owner fields as
447
   * defined in the &lt;owner&gt; tag in the pathquery dtd.
448
   */
449
  public Vector getOwnerList()
450
  {
451
    return this.ownerList;
452
  }
453
454
  /**
455
   * method to set the list of owners used to constrain this query
456
   */
457
  public void setOwnerList(Vector ownerList)
458
  {
459
    this.ownerList = ownerList;
460
  }
461
462
  /**
463
   * Accessor method to return a vector of the site fields as
464
   * defined in the &lt;site&gt; tag in the pathquery dtd.
465
   */
466
  public Vector getSiteList()
467
  {
468
    return this.siteList;
469
  }
470
471
  /**
472
   * method to set the list of sites used to constrain this query
473
   */
474
  public void setSiteList(Vector siteList)
475
  {
476
    this.siteList = siteList;
477
  }
478
479
  /**
480
   * get the QueryGroup used to express query constraints
481
   */
482
  public QueryGroup getQueryGroup()
483
  {
484
    return query;
485
  }
486
487
  /**
488 172 jones
   * Set up the SAX parser for reading the XML serialized query
489
   */
490 185 jones
  private XMLReader initializeParser() {
491
    XMLReader parser = null;
492 172 jones
493 155 jones
    // Set up the SAX document handlers for parsing
494
    try {
495
496
      // Get an instance of the parser
497 185 jones
      parser = XMLReaderFactory.createXMLReader(parserName);
498 155 jones
499 185 jones
      // Set the ContentHandler to this instance
500
      parser.setContentHandler(this);
501 155 jones
502 185 jones
      // Set the error Handler to this instance
503 158 jones
      parser.setErrorHandler(this);
504 155 jones
505
    } catch (Exception e) {
506 675 berkley
       System.err.println("Error in QuerySpcecification.initializeParser " +
507
                           e.toString());
508 155 jones
    }
509
510
    return parser;
511
  }
512
513 172 jones
  /**
514
   * callback method used by the SAX Parser when the start tag of an
515
   * element is detected. Used in this context to parse and store
516
   * the query information in class variables.
517
   */
518 185 jones
  public void startElement (String uri, String localName,
519
                            String qName, Attributes atts)
520 155 jones
         throws SAXException {
521 185 jones
    BasicNode currentNode = new BasicNode(localName);
522 159 jones
    // add attributes to BasicNode here
523
    if (atts != null) {
524
      int len = atts.getLength();
525
      for (int i = 0; i < len; i++) {
526 185 jones
        currentNode.setAttribute(atts.getLocalName(i), atts.getValue(i));
527 159 jones
      }
528
    }
529
530 158 jones
    elementStack.push(currentNode);
531 159 jones
    if (currentNode.getTagName().equals("querygroup")) {
532 158 jones
      QueryGroup currentGroup = new QueryGroup(
533 178 jones
                                currentNode.getAttribute("operator"));
534 158 jones
      if (query == null) {
535
        query = currentGroup;
536 159 jones
      } else {
537
        QueryGroup parentGroup = (QueryGroup)queryStack.peek();
538
        parentGroup.addChild(currentGroup);
539 158 jones
      }
540 159 jones
      queryStack.push(currentGroup);
541 158 jones
    }
542 155 jones
  }
543
544 172 jones
  /**
545
   * callback method used by the SAX Parser when the end tag of an
546
   * element is detected. Used in this context to parse and store
547
   * the query information in class variables.
548
   */
549 185 jones
  public void endElement (String uri, String localName,
550
                          String qName) throws SAXException {
551 158 jones
    BasicNode leaving = (BasicNode)elementStack.pop();
552 159 jones
    if (leaving.getTagName().equals("queryterm")) {
553
      boolean isCaseSensitive = (new Boolean(
554
              leaving.getAttribute("casesensitive"))).booleanValue();
555
      QueryTerm currentTerm = null;
556
      if (currentPathexpr == null) {
557
        currentTerm = new QueryTerm(isCaseSensitive,
558
                      leaving.getAttribute("searchmode"),currentValue);
559
      } else {
560
        currentTerm = new QueryTerm(isCaseSensitive,
561
                      leaving.getAttribute("searchmode"),currentValue,
562
                      currentPathexpr);
563
      }
564
      QueryGroup currentGroup = (QueryGroup)queryStack.peek();
565
      currentGroup.addChild(currentTerm);
566
      currentValue = null;
567
      currentPathexpr = null;
568
    } else if (leaving.getTagName().equals("querygroup")) {
569
      QueryGroup leavingGroup = (QueryGroup)queryStack.pop();
570 158 jones
    }
571 155 jones
  }
572 158 jones
573 172 jones
  /**
574
   * callback method used by the SAX Parser when the text sequences of an
575
   * xml stream are detected. Used in this context to parse and store
576
   * the query information in class variables.
577
   */
578 158 jones
  public void characters(char ch[], int start, int length) {
579
580
    String inputString = new String(ch, start, length);
581
    BasicNode currentNode = (BasicNode)elementStack.peek();
582
    String currentTag = currentNode.getTagName();
583
    if (currentTag.equals("meta_file_id")) {
584
      meta_file_id = inputString;
585 745 jones
    } else if (currentTag.equals("querytitle")) {
586
      queryTitle = inputString;
587 159 jones
    } else if (currentTag.equals("value")) {
588
      currentValue = inputString;
589
    } else if (currentTag.equals("pathexpr")) {
590
      currentPathexpr = inputString;
591 172 jones
    } else if (currentTag.equals("returndoctype")) {
592 743 jones
      returnDocList.add(inputString);
593 745 jones
    } else if (currentTag.equals("filterdoctype")) {
594
      filterDocList.add(inputString);
595 402 berkley
    } else if (currentTag.equals("returnfield")) {
596 1354 tao
      // make sure if return fields has an attribute or not
597
      if (inputString.indexOf(ATTRIBUTESYMBOL) ==-1)
598
      {
599
        // no attribute value will be returned
600
        returnFieldList.add(inputString);
601
        containsExtendedSQL = true;
602
      }
603
      else
604
      {
605
        // has a attribute return field
606
        // divied the return filed into two parts, one is path and the
607
        // other is attribue name
608
        String returnPath = newPathExpressionWithOutAttribute(inputString);
609
        String attributeName = getAttributeName(inputString);
610
        Vector pathInfo = new Vector();
611
        // the vector has the information about return path and attributename
612
        pathInfo.addElement(returnPath);
613
        pathInfo.addElement(attributeName);
614
        // put the vector into a hash table. The reseaon why don't put
615
        // return path or attributename as a key is because they are not unique
616
        attributeReturnList.put
617
                            (new Integer(countAttributeReturnField), pathInfo);
618
        countAttributeReturnField++;
619
        hasAttributeReturnField = true;
620
        containsExtendedSQL = true;
621
622
      }
623 743 jones
    } else if (currentTag.equals("filterdoctype")) {
624
      filterDocList.add(inputString);
625 535 jones
    } else if (currentTag.equals("owner")) {
626
      ownerList.add(inputString);
627
    } else if (currentTag.equals("site")) {
628
      siteList.add(inputString);
629 158 jones
    }
630
  }
631
632 172 jones
  /**
633
   * create a SQL serialization of the query that this instance represents
634
   */
635 706 bojilova
  public String printSQL(boolean useXMLIndex) {
636 1350 tao
637
638 170 jones
    StringBuffer self = new StringBuffer();
639
640 692 bojilova
    self.append("SELECT docid,docname,doctype,");
641 626 berkley
    self.append("date_created, date_updated, rev ");
642 172 jones
    self.append("FROM xml_documents WHERE docid IN (");
643 170 jones
644 178 jones
    // This determines the documents that meet the query conditions
645 706 bojilova
    self.append(query.printSQL(useXMLIndex));
646 172 jones
647
    self.append(") ");
648 402 berkley
649 172 jones
    // Add SQL to filter for doctypes requested in the query
650 743 jones
    // This is an implicit OR for the list of doctypes. Only doctypes in this
651
    // list will be searched if the tag is present
652
    if (!filterDocList.isEmpty()) {
653 172 jones
      boolean firstdoctype = true;
654
      self.append(" AND (");
655 743 jones
      Enumeration en = filterDocList.elements();
656 172 jones
      while (en.hasMoreElements()) {
657
        String currentDoctype = (String)en.nextElement();
658
        if (firstdoctype) {
659 402 berkley
           firstdoctype = false;
660
           self.append(" doctype = '" + currentDoctype + "'");
661 172 jones
        } else {
662
          self.append(" OR doctype = '" + currentDoctype + "'");
663
        }
664
      }
665
      self.append(") ");
666
    }
667 743 jones
668 535 jones
    // Add SQL to filter for owners requested in the query
669
    // This is an implicit OR for the list of owners
670
    if (!ownerList.isEmpty()) {
671
      boolean first = true;
672
      self.append(" AND (");
673
      Enumeration en = ownerList.elements();
674
      while (en.hasMoreElements()) {
675
        String current = (String)en.nextElement();
676
        if (first) {
677
           first = false;
678
           self.append(" user_owner = '" + current + "'");
679
        } else {
680
          self.append(" OR user_owner = '" + current + "'");
681
        }
682
      }
683
      self.append(") ");
684
    }
685
686
    // Add SQL to filter for sites requested in the query
687
    // This is an implicit OR for the list of sites
688
    if (!siteList.isEmpty()) {
689
      boolean first = true;
690
      self.append(" AND (");
691
      Enumeration en = siteList.elements();
692
      while (en.hasMoreElements()) {
693
        String current = (String)en.nextElement();
694
        if (first) {
695
           first = false;
696
           self.append(" SUBSTR(docid, 1, INSTR(docid, '" +
697
               accNumberSeparator + "')-1) = '" + current + "'");
698
        } else {
699
          self.append(" OR SUBSTR(docid, 1, INSTR(docid, '" +
700
               accNumberSeparator + "')-1) = '" + current + "'");
701
        }
702
      }
703
      self.append(") ");
704
    }
705 1350 tao
706
    // if there is only one percentage search item, this query is a percentage
707
    // search query
708
    if (countPercentageSearchItem ==1)
709
    {
710
711
      percentageSearch =true;
712
    }
713
714 170 jones
    return self.toString();
715
  }
716 402 berkley
717 1446 tao
  /** This sql command will selecet startnodeid and endnodeid that user can NOT
718
    * access
719 1453 tao
    */
720 1446 tao
  public String printAccessControlSQLForReturnField(String doclist)
721
  {
722
    StringBuffer sql = new StringBuffer();
723
    String allowString = constructAllowString();
724
    String denyString = constructDenyString();
725 1451 tao
    sql.append("SELECT distinct startnodeid, endnodeid from xml_access ");
726 1446 tao
    sql.append("WHERE docid in (");
727
    sql.append(doclist);
728 1452 tao
    sql.append(") AND startnodeid IS NOT NULL AND ");
729 1446 tao
    sql.append("(");
730 1453 tao
    sql.append("(");
731
    sql.append("startnodeid NOT IN (SELECT startnodeid from xml_access, xml_documents ");
732
    sql.append(" WHERE xml_access.docid = xml_documents.docid");
733
    sql.append(" AND xml_documents.user_owner ='");
734
    sql.append(userName);
735 1454 tao
    sql.append("' AND xml_access.startnodeid IS NOT NULL)");
736 1453 tao
    sql.append(")");
737
    sql.append(" AND ");
738
    sql.append("(");
739 1454 tao
    sql.append("(startnodeid NOT IN (SELECT startnodeid from xml_access where( ");
740 1446 tao
    sql.append(allowString);
741 1454 tao
    sql.append(") AND (startnodeid IS NOT NULL))");
742 1446 tao
    sql.append(")");
743 1454 tao
    sql.append(" OR (startnodeid IN (SELECT startnodeid from xml_access where( ");
744 1446 tao
    sql.append(denyString);
745 1454 tao
    sql.append(") AND (startnodeid IS NOT NULL))");
746 1446 tao
    sql.append(")");
747
    sql.append(")");
748
    sql.append(")");
749
    MetaCatUtil.debugMessage("accessControlSQLForReturnField: " +
750
                             sql.toString(), 30);
751
    return sql.toString();
752
  }
753
754 402 berkley
  /**
755
   * This method prints sql based upon the &lt;returnfield&gt; tag in the
756
   * pathquery document.  This allows for customization of the
757
   * returned fields
758 465 berkley
   * @param doclist the list of document ids to search by
759 1449 tao
   * @param unaccessableNodePair  the node pair(start id and end id) which this
760
   *                               user could not access it
761 402 berkley
   */
762 1449 tao
  public String printExtendedSQL(String doclist, Hashtable unaccessableNodePair)
763 402 berkley
  {
764
    StringBuffer self = new StringBuffer();
765 1362 tao
    self.append("select xml_nodes.docid, xml_index.path, xml_nodes.nodedata, ");
766
    self.append("xml_nodes.parentnodeid ");
767 423 berkley
    self.append("from xml_index, xml_nodes where xml_index.nodeid=");
768
    self.append("xml_nodes.parentnodeid and (xml_index.path like '");
769 402 berkley
    boolean firstfield = true;
770
    //put the returnfields into the query
771
    //the for loop allows for multiple fields
772
    for(int i=0; i<returnFieldList.size(); i++)
773
    {
774
      if(firstfield)
775
      {
776
        firstfield = false;
777 405 berkley
        self.append((String)returnFieldList.elementAt(i));
778 402 berkley
        self.append("' ");
779
      }
780
      else
781
      {
782 423 berkley
        self.append("or xml_index.path like '");
783 405 berkley
        self.append((String)returnFieldList.elementAt(i));
784 402 berkley
        self.append("' ");
785
      }
786
    }
787 423 berkley
    self.append(") AND xml_nodes.docid in (");
788 465 berkley
    //self.append(query.printSQL());
789
    self.append(doclist);
790 402 berkley
    self.append(")");
791 423 berkley
    self.append(" AND xml_nodes.nodetype = 'TEXT'");
792 1449 tao
793
    // add control part for extended query
794
    Enumeration en = unaccessableNodePair.keys();
795
796
    while (en.hasMoreElements())
797
    {
798
      // Get control pairs in object
799
      Long startNodeIdObject = (Long)en.nextElement();
800
      Long endNodeIdObject = (Long)unaccessableNodePair.get(startNodeIdObject);
801
      // change it to long
802
      long startNodeId = startNodeIdObject.longValue();
803
      long endNodeId   = endNodeIdObject.longValue();
804
      // add into query
805 1451 tao
      self.append(" AND( xml_nodes.nodeid < ");
806 1449 tao
      self.append(startNodeId);
807 1451 tao
      self.append(" OR xml_nodes.nodeid > ");
808 1449 tao
      self.append(endNodeId);
809
      self.append(")");
810
    }
811 405 berkley
812 1350 tao
813 402 berkley
    return self.toString();
814
  }
815 465 berkley
816 1354 tao
  /**
817
   * This method prints sql based upon the returnfield tag in the
818
   * pathquery document has an attribute.  This allows for customization of the
819
   * returned fields
820
   * @param doclist the list of document ids to search by
821
   */
822
  public String printAttributeQuery(String doclist)
823
  {
824
    StringBuffer self = new StringBuffer();
825
    self.append("select xml_nodes.docid, xml_index.path, ");
826
    self.append("xml_nodes.nodedata, xml_nodes.nodename ");
827
    self.append("from xml_index, xml_nodes where xml_index.nodeid=");
828
    self.append("xml_nodes.parentnodeid and (");
829
    boolean firstfield = true;
830
    //put the returnfields attributes into the query
831
    //the for loop allows for multiple fields and attributes
832
    Enumeration returnAttributes = attributeReturnList.elements();
833
    while (returnAttributes.hasMoreElements())
834
    {
835
      Vector currentVector = (Vector)returnAttributes.nextElement();
836
      String returnPath = (String)currentVector.elementAt(0);
837
      String attributeName = (String)currentVector.elementAt(1);
838
      if(firstfield)
839
      {
840
        firstfield = false;
841
        self.append("( xml_index.path like '");
842
        self.append(returnPath);
843
        self.append("' AND xml_nodes.nodename like '");
844
        self.append(attributeName);
845
        self.append("') ");
846
      }
847
      else
848
      {
849
        self.append(" or ( xml_index.path like '");
850
        self.append(returnPath);
851
        self.append("' AND xml_nodes.nodename like '");
852
        self.append(attributeName);
853
        self.append("') ");
854
      }
855
    }
856
    self.append(") AND xml_nodes.docid in (");
857
    //self.append(query.printSQL());
858
    self.append(doclist);
859
    self.append(")");
860
    self.append(" AND xml_nodes.nodetype = 'ATTRIBUTE'");
861
    MetaCatUtil.debugMessage("Attribute query: "+self.toString(), 30);
862
863
    return self.toString();
864
  }
865
866 465 berkley
  public static String printRelationSQL(String docid)
867
  {
868
    StringBuffer self = new StringBuffer();
869 489 berkley
    self.append("select subject, relationship, object, subdoctype, ");
870
    self.append("objdoctype from xml_relation ");
871 743 jones
    self.append("where docid like '").append(docid).append("'");
872 465 berkley
    return self.toString();
873
  }
874 453 berkley
875 172 jones
  /**
876 465 berkley
   * Prints sql that returns all relations in the database.
877 453 berkley
   */
878
  public static String printPackageSQL()
879
  {
880
    StringBuffer self = new StringBuffer();
881
    self.append("select z.nodedata, x.nodedata, y.nodedata from ");
882
    self.append("(select nodeid, parentnodeid from xml_index where path like ");
883 743 jones
    self.append("'triple/subject') s, (select nodeid, parentnodeid ");
884 453 berkley
    self.append("from xml_index where path like ");
885 743 jones
    self.append("'triple/relationship') rel, ");
886 453 berkley
    self.append("(select nodeid, parentnodeid from xml_index where path like ");
887 743 jones
    self.append("'triple/object') o, ");
888 453 berkley
    self.append("xml_nodes x, xml_nodes y, xml_nodes z ");
889
    self.append("where s.parentnodeid = rel.parentnodeid ");
890
    self.append("and rel.parentnodeid = o.parentnodeid ");
891 899 berkley
    self.append("and x.parentnodeid in (rel.nodeid) ");
892
    self.append("and y.parentnodeid in (o.nodeid) ");
893
    self.append("and z.parentnodeid in (s.nodeid) ");
894 453 berkley
    //self.append("and z.nodedata like '%");
895
    //self.append(docid);
896
    //self.append("%'");
897
    return self.toString();
898
  }
899
900
  /**
901 465 berkley
   * Prints sql that returns all relations in the database that were input
902
   * under a specific docid
903
   * @param docid the docid to search for.
904
   */
905
  public static String printPackageSQL(String docid)
906
  {
907
    StringBuffer self = new StringBuffer();
908 1386 tao
    self.append("select z.nodedata, z.parentnodeid, ");
909
    self.append("x.nodedata, x.parentnodeid, y.nodedata, y.parentnodeid from ");
910 465 berkley
    self.append("(select nodeid, parentnodeid from xml_index where path like ");
911 743 jones
    self.append("'triple/subject') s, (select nodeid, parentnodeid ");
912 465 berkley
    self.append("from xml_index where path like ");
913 743 jones
    self.append("'triple/relationship') rel, ");
914 465 berkley
    self.append("(select nodeid, parentnodeid from xml_index where path like ");
915 743 jones
    self.append("'triple/object') o, ");
916 465 berkley
    self.append("xml_nodes x, xml_nodes y, xml_nodes z ");
917
    self.append("where s.parentnodeid = rel.parentnodeid ");
918
    self.append("and rel.parentnodeid = o.parentnodeid ");
919 899 berkley
    self.append("and x.parentnodeid in (rel.nodeid) ");
920
    self.append("and y.parentnodeid in (o.nodeid) ");
921
    self.append("and z.parentnodeid in (s.nodeid) ");
922 465 berkley
    self.append("and z.docid like '").append(docid).append("'");
923
924
    return self.toString();
925
  }
926
927
  /**
928
   * Returns all of the relations that has a certain docid in the subject
929
   * or the object.
930
   *
931
   * @param docid the docid to search for
932
   */
933
  public static String printPackageSQL(String subDocidURL, String objDocidURL)
934
  {
935
    StringBuffer self = new StringBuffer();
936
    self.append("select z.nodedata, x.nodedata, y.nodedata from ");
937
    self.append("(select nodeid, parentnodeid from xml_index where path like ");
938 743 jones
    self.append("'triple/subject') s, (select nodeid, parentnodeid ");
939 465 berkley
    self.append("from xml_index where path like ");
940 743 jones
    self.append("'triple/relationship') rel, ");
941 465 berkley
    self.append("(select nodeid, parentnodeid from xml_index where path like ");
942 743 jones
    self.append("'triple/object') o, ");
943 465 berkley
    self.append("xml_nodes x, xml_nodes y, xml_nodes z ");
944
    self.append("where s.parentnodeid = rel.parentnodeid ");
945
    self.append("and rel.parentnodeid = o.parentnodeid ");
946 899 berkley
    self.append("and x.parentnodeid in (rel.nodeid) ");
947
    self.append("and y.parentnodeid in (o.nodeid) ");
948
    self.append("and z.parentnodeid in (s.nodeid) ");
949 465 berkley
    self.append("and (z.nodedata like '");
950
    self.append(subDocidURL);
951
    self.append("' or y.nodedata like '");
952
    self.append(objDocidURL);
953
    self.append("')");
954
    return self.toString();
955
  }
956
957
  public static String printGetDocByDoctypeSQL(String docid)
958
  {
959
    StringBuffer self = new StringBuffer();
960
961 692 bojilova
    self.append("SELECT docid,docname,doctype,");
962 465 berkley
    self.append("date_created, date_updated ");
963
    self.append("FROM xml_documents WHERE docid IN (");
964
    self.append(docid).append(")");
965
    return self.toString();
966
  }
967
968
  /**
969 172 jones
   * create a String description of the query that this instance represents.
970
   * This should become a way to get the XML serialization of the query.
971
   */
972 159 jones
  public String toString() {
973 692 bojilova
    return "meta_file_id=" + meta_file_id + "\n" + query;
974
//DOCTITLE attr cleared from the db
975
//    return "meta_file_id=" + meta_file_id + "\n" +
976
//           "querytitle=" + querytitle + "\n" + query;
977 159 jones
  }
978 1354 tao
979
  /* A method to get rid of attribute part in path expression*/
980
  public static String newPathExpressionWithOutAttribute(String pathExpression)
981
  {
982
      if (pathExpression == null)
983
      {
984
        return null;
985
      }
986
      int index = pathExpression.lastIndexOf(ATTRIBUTESYMBOL);
987
      String newExpression = null;
988
      if (index != 1)
989
      {
990
        newExpression=pathExpression.substring(0, index-1);
991
      }
992
      MetaCatUtil.debugMessage("The path expression without attributes: )" +
993
                               newExpression, 30);
994
      return newExpression;
995
  }
996
997
  /* A method to get attribute name from path */
998
  public static String getAttributeName(String path)
999
  {
1000
      if (path == null)
1001
      {
1002
        return null;
1003
      }
1004
      int index = path.lastIndexOf(ATTRIBUTESYMBOL);
1005
      int size = path.length();
1006
      String attributeName = null;
1007
       if (index != 1)
1008
      {
1009
        attributeName = path.substring(index+1, size);
1010
      }
1011
      MetaCatUtil.debugMessage("The attirbute name from path: )" +
1012
                               attributeName, 30);
1013
      return attributeName;
1014
  }
1015 159 jones
1016 158 jones
  /** a utility class that represents a group of terms in a query */
1017
  private class QueryGroup {
1018 178 jones
    private String operator = null;  // indicates how query terms are combined
1019
    private Vector children = null;  // the list of query terms and groups
1020 158 jones
1021 172 jones
    /**
1022
     * construct a new QueryGroup
1023
     *
1024 178 jones
     * @param operator the boolean conector used to connect query terms
1025 172 jones
     *                    in this query group
1026
     */
1027 178 jones
    public QueryGroup(String operator) {
1028
      this.operator = operator;
1029 158 jones
      children = new Vector();
1030
    }
1031
1032 172 jones
    /**
1033
     * Add a child QueryGroup to this QueryGroup
1034
     *
1035
     * @param qgroup the query group to be added to the list of terms
1036
     */
1037 158 jones
    public void addChild(QueryGroup qgroup) {
1038
      children.add((Object)qgroup);
1039
    }
1040
1041 172 jones
    /**
1042
     * Add a child QueryTerm to this QueryGroup
1043
     *
1044
     * @param qterm the query term to be added to the list of terms
1045
     */
1046 158 jones
    public void addChild(QueryTerm qterm) {
1047
      children.add((Object)qterm);
1048
    }
1049
1050 172 jones
    /**
1051
     * Retrieve an Enumeration of query terms for this QueryGroup
1052
     */
1053 158 jones
    public Enumeration getChildren() {
1054
      return children.elements();
1055
    }
1056 159 jones
1057 172 jones
    /**
1058
     * create a SQL serialization of the query that this instance represents
1059
     */
1060 706 bojilova
    public String printSQL(boolean useXMLIndex) {
1061 170 jones
      StringBuffer self = new StringBuffer();
1062
      boolean first = true;
1063
1064
      self.append("(");
1065
1066
      Enumeration en= getChildren();
1067
      while (en.hasMoreElements()) {
1068
        Object qobject = en.nextElement();
1069
        if (first) {
1070
          first = false;
1071
        } else {
1072 178 jones
          self.append(" " + operator + " ");
1073 170 jones
        }
1074
        if (qobject instanceof QueryGroup) {
1075
          QueryGroup qg = (QueryGroup)qobject;
1076 706 bojilova
          self.append(qg.printSQL(useXMLIndex));
1077 170 jones
        } else if (qobject instanceof QueryTerm) {
1078
          QueryTerm qt = (QueryTerm)qobject;
1079 706 bojilova
          self.append(qt.printSQL(useXMLIndex));
1080 170 jones
        } else {
1081
          System.err.println("qobject wrong type: fatal error");
1082
        }
1083
      }
1084
      self.append(") \n");
1085
      return self.toString();
1086
    }
1087
1088 172 jones
    /**
1089
     * create a String description of the query that this instance represents.
1090
     * This should become a way to get the XML serialization of the query.
1091
     */
1092 159 jones
    public String toString() {
1093
      StringBuffer self = new StringBuffer();
1094
1095 178 jones
      self.append("  (Query group operator=" + operator + "\n");
1096 159 jones
      Enumeration en= getChildren();
1097
      while (en.hasMoreElements()) {
1098
        Object qobject = en.nextElement();
1099
        self.append(qobject);
1100
      }
1101
      self.append("  )\n");
1102
      return self.toString();
1103
    }
1104 158 jones
  }
1105
1106
  /** a utility class that represents a single term in a query */
1107
  private class QueryTerm {
1108
    private boolean casesensitive = false;
1109
    private String searchmode = null;
1110
    private String value = null;
1111
    private String pathexpr = null;
1112 1350 tao
    private boolean percentageSymbol = false;
1113
1114 158 jones
1115 172 jones
    /**
1116
     * Construct a new instance of a query term for a free text search
1117
     * (using the value only)
1118
     *
1119
     * @param casesensitive flag indicating whether case is used to match
1120
     * @param searchmode determines what kind of substring match is performed
1121
     *        (one of starts-with|ends-with|contains|matches-exactly)
1122
     * @param value the text value to match
1123
     */
1124 158 jones
    public QueryTerm(boolean casesensitive, String searchmode,
1125
                     String value) {
1126
      this.casesensitive = casesensitive;
1127
      this.searchmode = searchmode;
1128
      this.value = value;
1129
    }
1130
1131 172 jones
    /**
1132
     * Construct a new instance of a query term for a structured search
1133
     * (matching the value only for those nodes in the pathexpr)
1134
     *
1135
     * @param casesensitive flag indicating whether case is used to match
1136
     * @param searchmode determines what kind of substring match is performed
1137
     *        (one of starts-with|ends-with|contains|matches-exactly)
1138
     * @param value the text value to match
1139
     * @param pathexpr the hierarchical path to the nodes to be searched
1140
     */
1141 158 jones
    public QueryTerm(boolean casesensitive, String searchmode,
1142
                     String value, String pathexpr) {
1143
      this(casesensitive, searchmode, value);
1144
      this.pathexpr = pathexpr;
1145
    }
1146
1147 172 jones
    /** determine if the QueryTerm is case sensitive */
1148 158 jones
    public boolean isCaseSensitive() {
1149
      return casesensitive;
1150
    }
1151
1152 172 jones
    /** get the searchmode parameter */
1153 158 jones
    public String getSearchMode() {
1154
      return searchmode;
1155
    }
1156
1157 172 jones
    /** get the Value parameter */
1158 158 jones
    public String getValue() {
1159
      return value;
1160
    }
1161
1162 172 jones
    /** get the path expression parameter */
1163 158 jones
    public String getPathExpression() {
1164
      return pathexpr;
1165
    }
1166 159 jones
1167 172 jones
    /**
1168
     * create a SQL serialization of the query that this instance represents
1169
     */
1170 706 bojilova
    public String printSQL(boolean useXMLIndex) {
1171 170 jones
      StringBuffer self = new StringBuffer();
1172
1173
      // Uppercase the search string if case match is not important
1174
      String casevalue = null;
1175
      String nodedataterm = null;
1176
1177
      if (casesensitive) {
1178
        nodedataterm = "nodedata";
1179
        casevalue = value;
1180
      } else {
1181
        nodedataterm = "UPPER(nodedata)";
1182
        casevalue = value.toUpperCase();
1183
      }
1184
1185
      // Add appropriate wildcards to search string
1186 795 bojilova
      //String searchvalue = null;
1187
      String searchexpr = null;
1188 170 jones
      if (searchmode.equals("starts-with")) {
1189 795 bojilova
        //searchvalue = casevalue + "%";
1190
        searchexpr = nodedataterm + " LIKE '" + casevalue + "%' ";
1191 170 jones
      } else if (searchmode.equals("ends-with")) {
1192 795 bojilova
        //searchvalue = "%" + casevalue;
1193
        searchexpr = nodedataterm + " LIKE '%" + casevalue + "' ";
1194 170 jones
      } else if (searchmode.equals("contains")) {
1195 795 bojilova
        //searchvalue = "%" + casevalue + "%";
1196 1305 tao
        if (!casevalue.equals("%"))
1197
        {
1198
          searchexpr = nodedataterm + " LIKE '%" + casevalue + "%' ";
1199
        }
1200
        else
1201
        {
1202
          searchexpr = nodedataterm + " LIKE '" + casevalue + "' ";
1203 1350 tao
          // find percentage symbol
1204
          percentageSymbol = true;
1205 1305 tao
        }
1206 795 bojilova
      } else if (searchmode.equals("equals")) {
1207
        //searchvalue = casevalue;
1208
        searchexpr = nodedataterm + " = '" + casevalue + "' ";
1209
      } else if (searchmode.equals("isnot-equal")) {
1210
        //searchvalue = casevalue;
1211
        searchexpr = nodedataterm + " != '" + casevalue + "' ";
1212
      } else {
1213
        //searchvalue = casevalue;
1214
        String oper = null;
1215
        if (searchmode.equals("greater-than")) {
1216
          oper = ">";
1217
        } else if (searchmode.equals("greater-than-equals")) {
1218
          oper = ">=";
1219
        } else if (searchmode.equals("less-than")) {
1220
          oper = "<";
1221
        } else if (searchmode.equals("less-than-equals")) {
1222
          oper = "<=";
1223
        } else {
1224
          System.out.println("NOT expected case. NOT recognized operator: " +
1225
                             searchmode);
1226
          return null;
1227
        }
1228
        try {
1229
          // it is number; numeric comparison
1230 1332 tao
          // but we need to make sure there is no string in node data
1231
          String getRidOfString = " AND UPPER(nodedata) = LOWER(nodedata)" +
1232
                                  " AND LTRIM(nodedata) != ' ' " +
1233
                                  " AND nodedata IS NOT NULL ";
1234 795 bojilova
          searchexpr = nodedataterm + " " + oper + " " +
1235 1332 tao
                       new Double(casevalue) + " "+getRidOfString;
1236 795 bojilova
        } catch (NumberFormatException nfe) {
1237
          // these are characters; character comparison
1238
          searchexpr = nodedataterm + " " + oper + " '" + casevalue + "' ";
1239
        }
1240 170 jones
      }
1241
1242 178 jones
      self.append("SELECT DISTINCT docid FROM xml_nodes WHERE \n");
1243 795 bojilova
      //self.append(nodedataterm + " LIKE " + "'" + searchvalue + "' ");
1244
      self.append(searchexpr);
1245 170 jones
1246 1348 tao
      if (pathexpr != null)
1247
      {
1248
1249 706 bojilova
        // use XML Index
1250 1348 tao
        if ( useXMLIndex )
1251
        {
1252
          if (!hasAttributeInPath(pathexpr))
1253
          {
1254
            // without attributes in path
1255
            self.append("AND parentnodeid IN ");
1256
          }
1257
          else
1258
          {
1259
            // has a attribute in path
1260
            String attributeName = getAttributeName(pathexpr);
1261
            self.append("AND nodetype LIKE 'ATTRIBUTE' AND nodename LIKE '"+
1262
                        attributeName + "' ");
1263
            self.append("AND parentnodeid IN ");
1264
            pathexpr = newPathExpressionWithOutAttribute(pathexpr);
1265
1266
          }
1267 706 bojilova
          self.append("(SELECT nodeid FROM xml_index WHERE path LIKE " +
1268
                      "'" +  pathexpr + "') " );
1269 1348 tao
        }
1270
        else
1271
        {
1272
          // without using XML Index; using nested statements instead
1273
          self.append("AND parentnodeid IN ");
1274 706 bojilova
          self.append(useNestedStatements(pathexpr));
1275
        }
1276 170 jones
      }
1277 1350 tao
      else
1278
      {
1279
        //if pathexpr is null and search value is %, is a percentageSearchItem
1280
        // the count number will be increase one
1281
        countPercentageSearchItem++;
1282
1283
       }
1284 170 jones
1285
      return self.toString();
1286
    }
1287 1348 tao
1288
    /* A method to judge if a path have attribute */
1289
    private boolean hasAttributeInPath(String path)
1290
    {
1291
      if (path.indexOf(ATTRIBUTESYMBOL)!=-1)
1292
      {
1293
        return true;
1294
      }
1295
      else
1296
      {
1297
        return false;
1298
      }
1299
    }
1300
1301 1354 tao
1302 1348 tao
1303 706 bojilova
    /*
1304
     * Constraint the query with @pathexp without using the XML Index,
1305
     * but nested SQL statements instead. The query migth be slower.
1306
     */
1307
    private String useNestedStatements(String pathexpr)
1308
    {
1309
      StringBuffer nestedStmts = new StringBuffer();
1310
      Vector nodes = new Vector();
1311
      String path = pathexpr;
1312
      int inx = 0;
1313
1314
      do {
1315
        inx = path.lastIndexOf("/");
1316 1350 tao
1317 706 bojilova
        nodes.addElement(path.substring(inx+1));
1318
        path = path.substring(0, Math.abs(inx));
1319
      } while ( inx > 0 );
1320
1321
      // nested statements
1322
      int i = 0;
1323
      for (i = 0; i < nodes.size()-1; i++) {
1324
        nestedStmts.append("(SELECT nodeid FROM xml_nodes" +
1325
                           " WHERE nodename LIKE '" +
1326
                             (String)nodes.elementAt(i) + "'" +
1327
                           " AND parentnodeid IN ");
1328
      }
1329
      // for the last statement: it is without " AND parentnodeid IN "
1330
      nestedStmts.append("(SELECT nodeid FROM xml_nodes" +
1331
                         " WHERE nodename LIKE '" +
1332
                         (String)nodes.elementAt(i) + "'" );
1333
      // node.size() number of closing brackets
1334
      for (i = 0; i < nodes.size(); i++) {
1335
        nestedStmts.append(")");
1336
      }
1337
1338
1339 1350 tao
1340 706 bojilova
      return nestedStmts.toString();
1341
    }
1342
1343 172 jones
    /**
1344
     * create a String description of the query that this instance represents.
1345
     * This should become a way to get the XML serialization of the query.
1346
     */
1347 709 bojilova
    public String toString() {
1348 159 jones
1349 709 bojilova
      return this.printSQL(true);
1350 159 jones
    }
1351 158 jones
  }
1352 155 jones
}