Project

General

Profile

« Previous | Next » 

Revision 6602

uses prepared statement parameter binding for queries
http://bugzilla.ecoinformatics.org/show_bug.cgi?id=5527

View differences:

QueryTerm.java
29 29

  
30 30
package edu.ucsb.nceas.metacat;
31 31

  
32
import java.util.ArrayList;
32 33
import java.util.Calendar;
34
import java.util.List;
33 35
import java.util.Vector;
34 36

  
35 37
import javax.xml.bind.DatatypeConverter;
......
151 153
    }
152 154

  
153 155
    
154
    public String printSearchExprSQL() {
156
    public String printSearchExprSQL(List<Object> parameterValues) {
155 157

  
156 158
        // Uppercase the search string if case match is not important
157 159
        String casevalue = null;
......
168 170
        // Add appropriate wildcards to search string
169 171
        String searchexpr = null;
170 172
        if (searchmode.equals("starts-with")) {
171
            searchexpr = nodedataterm + " LIKE '" + casevalue + "%' ";
173
            searchexpr = nodedataterm + " LIKE ? ";
174
            parameterValues.add(casevalue + "%");
172 175
        } else if (searchmode.equals("ends-with")) {
173
            searchexpr = nodedataterm + " LIKE '%" + casevalue + "' ";
176
            searchexpr = nodedataterm + " LIKE ? ";
177
            parameterValues.add("%" + casevalue + "%");
174 178
        } else if (searchmode.equals("contains")) {
175 179
            if (!casevalue.equals("%")) {
176
                searchexpr = nodedataterm + " LIKE '%" + casevalue + "%' ";
180
                searchexpr = nodedataterm + " LIKE ? ";
181
                parameterValues.add("%" + casevalue + "%");
177 182
            } else {
178
                searchexpr = nodedataterm + " LIKE '" + casevalue + "' ";
183
                searchexpr = nodedataterm + " LIKE ? ";
184
                parameterValues.add(casevalue);
179 185
                // find percentage symbol
180 186
                percentageSymbol = true;
181 187
            }
182 188
        } else if (searchmode.equals("not-contains")) {
183 189
        	notEqual = true;
184
            searchexpr = nodedataterm + " LIKE '%" + casevalue + "%' ";
190
            searchexpr = nodedataterm + " LIKE ? ";
191
            parameterValues.add("%" + casevalue + "%");
185 192
        } else if (searchmode.equals("equals")) {
186
            searchexpr = nodedataterm + " = '" + casevalue + "' ";
193
            searchexpr = nodedataterm + " = ? ";
194
            parameterValues.add(casevalue);
187 195
        } else if (searchmode.equals("isnot-equal")) {
188 196
        	notEqual = true;
189
            searchexpr = nodedataterm + " = '" + casevalue + "' ";
197
            searchexpr = nodedataterm + " = ? ";
198
            parameterValues.add(casevalue);
190 199
        } else {
191 200
            String oper = null;
192 201
            if (searchmode.equals("greater-than")) {
......
211 220
            
212 221
            try {
213 222
                // it is number; numeric comparison
214
                searchexpr = nodedataterm + " " + oper + " " + new Double(casevalue) + " ";
223
            	Double doubleVal = new Double(casevalue);
224
                searchexpr = nodedataterm + " " + oper + " ? ";
225
                parameterValues.add(doubleVal);
215 226
            } catch (NumberFormatException nfe) {
216 227
            	// is it a date?
217 228
            	try {
218 229
                	// try ISO 8601 formats
219 230
                	Calendar dataDateValue = DatatypeConverter.parseDateTime(casevalue);
220
                	String lexicalString = DatatypeConverter.printDateTime(dataDateValue);
231
                	//String lexicalString = DatatypeConverter.printDateTime(dataDateValue);
221 232
                    nodedataterm = "nodedatadate";
222 233
            		searchexpr = 
223
            			nodedataterm + " " + oper + " '" + lexicalString + "' ";
234
            			nodedataterm + " " + oper + " ? ";
235
            		parameterValues.add(dataDateValue.getTime());
224 236
            	} catch (Exception pe) {
225 237
            		// these are characters; character comparison
226
                    searchexpr = nodedataterm + " " + oper + " '" + casevalue + "' ";
238
                    searchexpr = nodedataterm + " " + oper + " ? ";
239
                    parameterValues.add(casevalue);
227 240
            	}
228 241
            }
229 242
        }
......
245 258
    /**
246 259
     * create a SQL serialization of the query that this instance represents
247 260
     */
248
    public String printSQL(boolean useXMLIndex)
261
    public String printSQL(boolean useXMLIndex, List<Object> parameterValues)
249 262
    {
263
    	
250 264
        StringBuffer self = new StringBuffer();
251 265
        
252 266
        // does it contain a not equals?
253 267
        boolean notEqual = isNotEqualTerm();
254 268

  
269
        // keep track of parameter values
270
        List<Object> searchValues = new ArrayList<Object>();
271
        
255 272
        // get the general search expression
256
        String searchexpr = printSearchExprSQL();
273
        String searchexpr = printSearchExprSQL(searchValues);
274
        
275
        // add our parameter values
276
        parameterValues.addAll(searchValues);
257 277
       
258 278
        // to check xml_path_index can be used
259 279
        boolean usePathIndex = false;
......
277 297
        			self.append("SELECT DISTINCT docid from xml_path_index WHERE");
278 298
        			self.append(" docid NOT IN (Select docid FROM xml_path_index WHERE ");
279 299
        			self.append(searchexpr);
280
        			self.append("AND path LIKE '" + pathexpr + "') ");
300
        			self.append("AND path LIKE ? ) ");
301
        			parameterValues.add(pathexpr);
281 302
        		}
282 303
        		else
283 304
        		{
284 305
        			//if this is in union group we need to use "OR" to modify query
285 306
        			self.append("("+searchexpr);
286
        			self.append("AND path LIKE '" + pathexpr + "') ");
307
        			self.append("AND path LIKE ?) ");
308
        			parameterValues.add(pathexpr);
287 309
        		}
288 310
        	} else {
289 311
        		if (!inUnionGroup)
290 312
        		{
291 313
        			self.append("SELECT DISTINCT docid FROM xml_path_index WHERE ");
292 314
        			self.append(searchexpr);
293
        			self.append("AND path LIKE '" + pathexpr + "' ");
315
        			self.append("AND path LIKE ? ");
316
        			parameterValues.add(pathexpr);
294 317
        		}
295 318
        		else
296 319
        		{
297 320
        			//if this is in union group we need to use "OR" to modify query
298 321
        			self.append("("+searchexpr);
299
        			self.append("AND path LIKE '" + pathexpr + "') ");
322
        			self.append("AND path LIKE ?) ");
323
        			parameterValues.add(pathexpr);
300 324
        		}
301 325
        	}
302 326

  
......
319 343
                        // without attributes in path
320 344
                        self.append("AND parentnodeid IN ");
321 345
                        self.append(
322
                            "(SELECT nodeid FROM xml_index WHERE path LIKE "
323
                            + "'" + path + "') ");
346
                            "(SELECT nodeid FROM xml_index WHERE path LIKE ?) ");
347
                        parameterValues.add(path);
324 348
                    } else {
325 349
                        // has a attribute in path
326 350
                        String attributeName = QuerySpecification
327 351
                            .getAttributeName(pathexpr);
328 352
                        self.append(
329
                            "AND nodetype LIKE 'ATTRIBUTE' AND nodename LIKE '"
330
                            + attributeName + "' ");
353
                            "AND nodetype LIKE 'ATTRIBUTE' AND nodename LIKE ? ");
354
                        parameterValues.add(attributeName);
331 355
                        // and the path expression includes element content other than
332 356
                        // just './' or '../'
333 357
                        if ( (!pathexpr.startsWith(QuerySpecification.
......
341 365
                            path = QuerySpecification
342 366
                                .newPathExpressionWithOutAttribute(pathexpr);
343 367
                            self.append(
344
                                "(SELECT nodeid FROM xml_index WHERE path LIKE "
345
                                + "'" + path + "') ");
368
                                "(SELECT nodeid FROM xml_index WHERE path LIKE ?) ");
369
                            parameterValues.add(path);
346 370
                        }
347 371
                    }
348 372
                }
349 373
                else {
350 374
                    // without using XML Index; using nested statements instead
375
                	// keep track of the values we add as prepared statement question marks (?)
376
                	List<Object> nestedParameterValues = new ArrayList<Object>();
351 377
                    //self.append("AND parentnodeid IN ");
352 378
                	self.append("AND ");
353
                    self.append(useNestedStatements(pathexpr));
379
                	String nested = useNestedStatements(pathexpr, nestedParameterValues);		
380
                    self.append(nested);
381
                	// include them
382
                    parameterValues.addAll(nestedParameterValues);
354 383
                }
355 384
            }
356 385
            else if ( (value.trim()).equals("%")) {
......
377 406
    }
378 407

  
379 408
   
380
    public static String useNestedStatements(String pathexpr)
409
    public static String useNestedStatements(String pathexpr, List<Object> parameterValues)
381 410
    {
411
    	
382 412
        log.info("useNestedStatements()");
383 413
        log.info("pathexpr: " + pathexpr);
384 414
        String elementPrefix = " parentnodeid IN ";
......
400 430
            int predicateStart = -1;
401 431
            int predicateEnd;
402 432
            String node;
403
            Vector predicates = new Vector();
433
            Vector<String> predicates = new Vector<String>();
404 434

  
405 435
            // extract predicates
406 436
            predicateStart = path.indexOf(QuerySpecification.PREDICATE_START, predicateStart + 1);
......
458 488
                }
459 489
            }
460 490

  
461
            nestedStmts.insert(0, "' ").insert(0, node).insert(0,
462
                    "(SELECT nodeid FROM xml_nodes WHERE nodename LIKE '");
463

  
491
            nestedStmts.insert(0, "(SELECT nodeid FROM xml_nodes WHERE nodename LIKE ? ");
492
            parameterValues.add(node);
493
            
464 494
            // for the last statement: it is without " AND parentnodeid IN "
465
            if (!path.equals(""))
495
            if (!path.equals("")) {
466 496
                nestedStmts.insert(0, "AND parentnodeid IN ");
467

  
497
            }
498
            
468 499
            if (predicates.size() > 0)
469 500
            {
470 501
                for (int n = 0; n < predicates.size(); n++)
471 502
                {
472
                    String predSQL = predicate2SQL((String) predicates.get(n));
503
                	// keep track of the values we add as prepared statement question marks (?)
504
                	List<Object> predicateParameterValues = new ArrayList<Object>();
505
                    String predSQL = predicate2SQL(predicates.get(n), predicateParameterValues);
473 506

  
474
                    if (predSQL.equals(""))
507
                    if (predSQL.equals("")) {
475 508
                        return "";
476

  
509
                    }
510
                    
511
                    // include the values
512
                    parameterValues.addAll(predicateParameterValues);
513
                    // include the sql
477 514
                    nestedStmts.append(predSQL).append(' ');
478 515
                }
479 516
            }
......
536 573
    /**
537 574
     * 
538 575
     */
539
    public static String predicate2SQL(String predicate)
576
    public static String predicate2SQL(String predicate, List<Object> predicateParameterValues)
540 577
    {
541 578
        String path = predicate.trim();
542 579
        int equals = path.indexOf('=');
......
582 619
            if (literal != null)
583 620
            {
584 621
                sql.append("AND nodeid IN (SELECT parentnodeid FROM xml_nodes WHERE nodetype = 'TEXT' AND nodedata LIKE ")
585
                    .append(literal).append(")");
622
                    .append("?").append(")");
623
                // remove single or double quotes
624
                literal = literal.substring(1, literal.length() - 1);
625
                // add to vlaues list
626
                predicateParameterValues.add(literal);
586 627
            }
587 628
        }
588 629
        else
589 630
        {
590 631
            sql.append(
591
                    "AND nodeid IN (SELECT parentnodeid FROM xml_nodes WHERE nodetype = 'ATTRIBUTE' AND nodename LIKE '")
592
                    .append(path.substring(attribute + 1).trim()).append("' ");
632
                    "AND nodeid IN (SELECT parentnodeid FROM xml_nodes WHERE nodetype = 'ATTRIBUTE' AND nodename LIKE ? ");
633
            // add to values
634
            predicateParameterValues.add(path.substring(attribute + 1).trim());
593 635

  
594 636
            if (literal != null)
595 637
            {
596
                sql.append("AND nodedata LIKE ").append(literal);
638
                sql.append("AND nodedata LIKE ? ");
639
                // remove single or double quotes
640
                literal = literal.substring(1, literal.length() - 1);
641
                // add to values list
642
                predicateParameterValues.add(literal);
597 643
            }
598 644

  
599 645
            sql.append(")");
......
630 676
                path = "";
631 677
            }
632 678

  
633
            if (!node.equals(""))
634
                sql.insert(0, "' ").insert(0, node)
635
                    .insert(0, "(SELECT parentnodeid FROM xml_nodes WHERE nodename LIKE '").append(") ");
679
            if (!node.equals("")) {
680
                sql.insert(0, "(SELECT parentnodeid FROM xml_nodes WHERE nodename LIKE ? ) ");
681
                predicateParameterValues.add(node);
682
            }
636 683
            else if (!path.equals(""))
637 684
            {
638 685
                log.warn("predicate2SQL(): ");
......
655 702
    }
656 703

  
657 704
    /**
658
     * create a String description of the query that this instance represents.
659
     * This should become a way to get the XML serialization of the query.
705
     * Show a string representation of the query
706
     * @deprecated This should not be used for performing the query
707
     * because the parameter values are not bound in the raw SQL
660 708
     */
661 709
    public String toString()
662 710
    {
663 711

  
664
        return this.printSQL(true);
712
    	// keep track of the values we add as prepared statement question marks (?)
713
    	List<Object> parameterValues = new ArrayList<Object>();
714
        return this.printSQL(true, parameterValues);
665 715
    }
666 716
    
667 717
    /**

Also available in: Unified diff