/******************************************************************************* * Copyright (c) 2015 hangum. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser Public License v2.1 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * * Original: (MIT License) * https://code.google.com/p/framework-pegasus/source/browse/Pegasus/trunk/src/ar/pegasus/framework/util/jdbc/NamedParameterStatement.java?r=8 * * Contributors: * hangum - initial API and implementation ******************************************************************************/ package com.hangum.tadpole.engine.sql.paremeter.lang; import java.sql.PreparedStatement; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; /** * * This class wraps around a {@link PreparedStatement} and allows the * programmer to set parameters by name instead * of by index. This eliminates any confusion as to which parameter index * represents what. This also means that * rearranging the SQL statement or adding a parameter doesn't involve * renumbering your indices. * Code such as this: * * <PRE> * Connection con=getConnection(); * String query="select * from my_table where name=? or address=?"; * PreparedStatement p=con.prepareStatement(query); * p.setString(1, "bob"); * p.setString(2, "123 terrace ct"); * ResultSet rs=p.executeQuery(); * </PRE> * * can be replaced with: * * <PRE> * Connection con=getConnection(); * String query="select * from my_table where name=:name or address=:address"; * NamedParameterStatement p=new NamedParameterStatement(con, query); * p.setString("name", "bob"); * p.setString("address", "123 terrace ct"); * ResultSet rs=p.executeQuery(); * </PRE> * */ public class OracleStyleSQLNamedParameterUtil { /** Maps parameter names to arrays of ints which are the parameter indices. */ private Map<String, int[]> mapNameToIndex = new HashMap<String, int[]>(); private Map<Integer, String> mapIndexToName = new HashMap<Integer, String>(); public OracleStyleSQLNamedParameterUtil() {} /** * Parses a query with named parameters. The parameter-index mappings are * put into the map, and the * parsed query is returned. DO NOT CALL FROM CLIENT CODE. This * method is non-private so JUnit code can * test it. * @param query query to parse * @return the parsed query */ public String parse(String query) { // I was originally using regular expressions, but they didn't work well // for ignoring parameter-like strings inside quotes. Map<String, List<Integer>> paramMapAux = new HashMap<String, List<Integer>>(); int length=query.length(); StringBuffer parsedQuery=new StringBuffer(length); boolean inSingleQuote=false; boolean inDoubleQuote=false; int index=1; for(int i=0;i<length;i++) { char c=query.charAt(i); if(inSingleQuote) { if(c=='\'') { inSingleQuote=false; } } else if(inDoubleQuote) { if(c=='"') { inDoubleQuote=false; } } else { if(c=='\'') { inSingleQuote=true; } else if(c=='"') { inDoubleQuote=true; } else if(c==':' && i+1<length && Character.isJavaIdentifierStart(query.charAt(i+1))) { if(query.charAt(i-1) != ':') { int j=i+2; while(j<length && Character.isJavaIdentifierPart(query.charAt(j))) { j++; } String name=query.substring(i+1,j); c='?'; // replace the parameter with a question mark i+=name.length(); // skip past the end if the parameter List<Integer> indexList= paramMapAux.get(name); if(indexList==null) { indexList=new LinkedList<Integer>(); paramMapAux.put(name, indexList); } indexList.add(index); index++; } } } parsedQuery.append(c); } // // replace the lists of Integer objects with arrays of ints // for(Map.Entry<String, List<Integer>> entry : paramMapAux.entrySet()) { // List<Integer> list=entry.getValue(); // int[] indexes=new int[list.size()]; // int i=0; // for(Integer x : list) { // indexes[i++]=x; // } // mapNameToIndex.put(entry.getKey(), indexes) ; // } for(Map.Entry<String, List<Integer>> entry : paramMapAux.entrySet()) { List<Integer> list=entry.getValue(); for(Integer x : list) { mapIndexToName.put(x, entry.getKey()); } } return parsedQuery.toString(); } // /** // * Returns the indexes for a parameter. // * @param name parameter name // * @return parameter indexes // * @throws IllegalArgumentException if the parameter does not exist // */ // public int[] getIndexes(String name) { // int[] indexes=mapNameToIndex.get(name); // if(indexes==null) { // throw new IllegalArgumentException("Parameter not found: "+name); // } // return indexes; // } /** * Returns the index to param names * @param intIndex * @return */ public String getIndex(Integer intIndex) { return mapIndexToName.get(intIndex); } // /** // * Returns the indexMap // * @return // */ // public Map<String, int[]> getIndexMap() { // return mapNameToIndex; // } public Map<Integer, String> getMapIndexToName() { return mapIndexToName; } }