1 6 7 package com.hp.hpl.jena.db.impl; 10 11 import java.sql.*; 14 import java.util.*; 15 import java.io.*; 16 17 import com.hp.hpl.jena.db.*; 18 import com.hp.hpl.jena.shared.JenaException; 19 import com.hp.hpl.jena.util.CollectionFactory; 20 21 import org.apache.commons.logging.Log; 22 import org.apache.commons.logging.LogFactory; 23 24 51 52 public class SQLCache { 53 54 57 58 protected Properties m_sql; 59 60 62 protected Map m_preparedStatements = CollectionFactory.createHashedMap(); 63 64 66 protected Map m_cachedStmtInUse = CollectionFactory.createHashedMap(); 67 68 69 protected IDBConnection m_connection; 70 71 72 protected static final int MAX_PS_CACHE = 4; 73 74 75 protected boolean CACHE_PREPARED_STATEMENTS = true; 76 77 static protected Log logger = LogFactory.getLog( SQLCache.class ); 78 81 92 public SQLCache(String sqlFile, Properties defaultOps, IDBConnection connection, String idType) throws IOException { 93 m_sql = loadSQLFile(sqlFile, defaultOps, idType); 94 m_connection = connection; 95 } 96 97 100 public void setCachePreparedStatements(boolean state) { 101 CACHE_PREPARED_STATEMENTS = state; 102 } 103 104 107 public boolean getCachePreparedStatements() { 108 return CACHE_PREPARED_STATEMENTS; 109 } 110 111 114 public void flushPreparedStatementCache() throws RDFRDBException { 115 try { 116 Iterator it = m_preparedStatements.values().iterator(); 117 while (it.hasNext()) { 118 Iterator psit = ((List)it.next()).iterator(); 119 while (psit.hasNext()) { 120 ((PreparedStatement)psit.next()).close(); 121 } 122 } 123 } catch (SQLException e) { 124 throw new RDFRDBException("Problem flushing PS cache", e); 125 } finally { 126 m_preparedStatements = CollectionFactory.createHashedMap(); 127 m_cachedStmtInUse = CollectionFactory.createHashedMap(); 128 } 129 } 130 133 public Connection getConnection() throws SQLException { 134 return m_connection.getConnection(); 135 } 136 137 140 public void setConnection(IDBConnection connection) { 141 m_connection = connection; 142 } 143 144 147 public String getSQLStatement(String opname) throws SQLException { 148 return getSQLStatement(opname, (String []) null); 149 } 150 151 155 public String getSQLStatement(String opname, String [] attr) throws SQLException { 156 String cmd = m_sql.getProperty(opname); 157 if (cmd == null) { 158 if ( opname.startsWith("*") ) { 159 cmd = genSQLStatement(opname); 160 m_sql.setProperty(opname, cmd); 161 } else { 162 logger.error("Unable to find SQL for operation: " + opname); 163 throw new SQLException("Unable to find SQL for operation: " + opname); 164 } 165 } 166 int attrCnt = (attr == null) ? 0 : attr.length; 167 if ( attrCnt > 0 ) cmd = substitute(cmd, "${a}", attr[0]); 168 if ( attrCnt > 1 ) cmd = substitute(cmd, "${b}", attr[1]); 169 if ( attrCnt > 2 ) cmd = substitute(cmd, "${c}", attr[2]); 170 if ( attrCnt > 3 ) throw new JenaException("Too many arguments"); 171 172 return cmd; 173 } 174 175 176 177 public String getSQLStatement(String opname, String attr) throws SQLException { 178 String [] param = {attr}; 179 return getSQLStatement(opname,param); 180 } 181 182 187 public String getSQLStatement(String opname, String attrA, String attrB) throws SQLException { 188 String [] param = {attrA,attrB}; 189 return getSQLStatement(opname,param); 190 } 191 192 201 public Collection getSQLStatementGroup(String opname) throws SQLException { 202 String statementSrc = m_sql.getProperty(opname); 203 if (statementSrc == null) { 204 throw new SQLException("Unable to find SQL for operation: " + opname); 205 } 206 int start = 0; 207 int split = 0; 208 List statements = new LinkedList(); 209 while (split != -1) { 210 split = statementSrc.indexOf(";;\n", start); 211 String statement = null; 212 if (split == -1) { 213 statement = statementSrc.substring(start); 214 } else { 215 statement = statementSrc.substring(start, split); 216 start = split +2; 217 } 218 if (!statement.trim().equals("")) 219 statements.add(statement); 220 } 221 return statements; 222 } 223 224 238 239 public synchronized PreparedStatement getPreparedSQLStatement(String opname, String [] attr) throws SQLException { 240 243 PreparedStatement ps; 244 if (m_connection == null || opname == null) return null; 245 int attrCnt = (attr == null) ? 0 : attr.length; 246 String aop = opname; 247 if ( attrCnt > 0 ) aop = concatOpName(aop, attr[0]); 248 if ( attrCnt > 1 ) aop = concatOpName(aop, attr[1]); 249 if ( attrCnt > 2 ) aop = concatOpName(aop, attr[2]); 250 if ( attrCnt > 3 ) throw new JenaException("Too many arguments"); 251 252 List psl = (List) m_preparedStatements.get(aop); 253 if (psl == null || psl.isEmpty()) { 254 String sql = getSQLStatement(opname, attr); 255 if (sql == null) { 256 throw new SQLException("No SQL defined for operation: " + opname); 257 } 258 if (psl == null && CACHE_PREPARED_STATEMENTS) { 259 psl = new LinkedList(); 260 m_preparedStatements.put(aop, psl); 261 } 262 ps = doPrepareSQLStatement(sql); 263 } else { 264 ps = (PreparedStatement) psl.remove(0); 265 } 266 if ( CACHE_PREPARED_STATEMENTS ) m_cachedStmtInUse.put(ps,psl); 267 return ps; 268 } 269 270 279 280 private synchronized PreparedStatement doPrepareSQLStatement(String sql) throws SQLException { 281 if (m_connection == null) return null; 282 return getConnection().prepareStatement(sql); 283 } 284 285 295 296 public synchronized PreparedStatement prepareSQLStatement(String sql) throws SQLException { 297 if (m_connection == null) return null; 298 return doPrepareSQLStatement(sql); 299 } 300 301 public synchronized PreparedStatement getPreparedSQLStatement(String opname) throws SQLException { 302 return getPreparedSQLStatement(opname, (String []) null); 303 } 304 305 309 public synchronized PreparedStatement getPreparedSQLStatement(String opname, String attr) throws SQLException { 310 String [] param = {attr}; 311 return getPreparedSQLStatement(opname,param); 312 } 313 314 318 public synchronized PreparedStatement getPreparedSQLStatement(String opname, String attrA, String attrB) throws SQLException { 319 String [] param = {attrA,attrB}; 320 return getPreparedSQLStatement(opname,param); 321 } 322 323 329 public synchronized void returnPreparedSQLStatement(PreparedStatement ps) { 330 if (!CACHE_PREPARED_STATEMENTS) { 331 try { 332 ps.close(); 333 } catch (SQLException e) { 334 logger.warn("Problem discarded prepared statement", e); 335 } 336 return; 337 } 338 List psl = (List) m_cachedStmtInUse.get(ps); 339 if (psl != null) { 340 if (psl.size() >= MAX_PS_CACHE) { 341 try { 342 ps.close(); 343 } catch (SQLException e) { 344 logger.warn("Problem discarded prepared statement", e); 345 } 346 } else { 347 psl.add(ps); 348 } 349 m_cachedStmtInUse.remove(ps); 350 } else { 351 throw new JenaException("Attempt to return unused prepared statement"); 352 } 353 } 354 355 369 public ResultSetIterator runSQLQuery(String opname, Object [] args) throws SQLException { 370 PreparedStatement ps = getPreparedSQLStatement(opname); 371 if (args != null) { 372 for (int i = 0; i < args.length; i++) { 373 ps.setObject(i+1, args[i]); 374 } 375 } 376 return executeSQL(ps, opname, new ResultSetIterator()); 377 } 378 379 383 public ResultSetIterator runSQLQuery(String opname,String attr, Object [] args) throws SQLException { 384 String aop = concatOpName(opname, attr); 385 PreparedStatement ps = getPreparedSQLStatement(aop); 386 387 if (args != null) { 388 for (int i = 0; i < args.length; i++) { 389 ps.setObject(i+1, args[i]); 390 } 391 } 392 return executeSQL(ps, aop, new ResultSetIterator()); 393 } 394 395 399 public ResultSetIterator runSQLQuery(String opname,String attrA, String attrB, Object [] args) throws SQLException { 400 String aop = concatOpName(opname, attrA, attrB); 401 PreparedStatement ps = getPreparedSQLStatement(aop); 402 403 if (args != null) { 404 for (int i = 0; i < args.length; i++) { 405 ps.setObject(i+1, args[i]); 406 } 407 } 408 return executeSQL(ps, aop, new ResultSetIterator()); 409 } 410 411 412 416 public int runSQLUpdate(String opname, Object [] args) throws SQLException { 417 PreparedStatement ps = getPreparedSQLStatement(opname); 418 if (args != null) { 419 for (int i = 0; i < args.length; i++) { 420 ps.setObject(i+1, args[i]); 421 } 422 } 423 int result = ps.executeUpdate(); 424 returnPreparedSQLStatement(ps); 425 return result; 426 } 427 428 432 public int runSQLUpdate(String opname,String attrA, Object [] args) throws SQLException { 433 String aop = concatOpName(opname, attrA); 434 PreparedStatement ps = getPreparedSQLStatement(aop); 435 if (args != null) { 436 for (int i = 0; i < args.length; i++) { 437 ps.setObject(i+1, args[i]); 438 } 439 } 440 int result = ps.executeUpdate(); 441 returnPreparedSQLStatement(ps); 442 return result; 443 } 444 445 449 public int runSQLUpdate(String opname,String attrA, String attrB, Object [] args) throws SQLException { 450 String aop = concatOpName(opname, attrA, attrB); 451 PreparedStatement ps = getPreparedSQLStatement(aop); 452 if (args != null) { 453 for (int i = 0; i < args.length; i++) { 454 ps.setObject(i+1, args[i]); 455 } 456 } 457 int result = ps.executeUpdate(); 458 returnPreparedSQLStatement(ps); 459 return result; 460 } 461 462 463 464 465 466 467 468 484 public ResultSetIterator runSQLQuery(String opname, Object [] args, ResultSetIterator iterator) throws SQLException { 485 PreparedStatement ps = getPreparedSQLStatement(opname); 486 if (args != null) { 487 for (int i = 0; i < args.length; i++) { 488 ps.setObject(i+1, args[i]); 489 } 490 } 491 return executeSQL(ps, opname, iterator); 492 } 493 494 498 public ResultSetIterator runSQLQuery(String opname, String attrA, Object [] args, ResultSetIterator iterator) throws SQLException { 499 String aop = concatOpName(opname,attrA); 500 PreparedStatement ps = getPreparedSQLStatement(aop); 501 if (args != null) { 502 for (int i = 0; i < args.length; i++) { 503 ps.setObject(i+1, args[i]); 504 } 505 } 506 507 return executeSQL(ps, aop, iterator); 508 } 509 510 514 public ResultSetIterator runSQLQuery(String opname, String attrA, String attrB, Object [] args, ResultSetIterator iterator) throws SQLException { 515 String aop = concatOpName(opname,attrA, attrB); 516 PreparedStatement ps = getPreparedSQLStatement(aop); 517 if (args != null) { 518 for (int i = 0; i < args.length; i++) { 519 ps.setObject(i+1, args[i]); 520 } 521 } 522 523 return executeSQL(ps, aop, iterator); 524 } 525 526 527 535 public void runSQLGroup(String opname, String [] attr) throws SQLException { 536 String op = null; 537 SQLException eignore = null; 538 String operror = null; 539 java.sql.Statement sql = getConnection().createStatement(); 540 Iterator ops = getSQLStatementGroup(opname).iterator(); 541 int attrCnt = attr == null ? 0 : attr.length; 542 if ( attrCnt > 6 ) 543 throw new RDFRDBException("Too many parameters"); 544 while (ops.hasNext()) { 545 op = (String ) ops.next(); 546 if ( attrCnt > 0 ) op = substitute(op,"${a}",attr[0]); 547 if ( attrCnt > 1 ) op = substitute(op,"${b}",attr[1]); 548 if ( attrCnt > 2 ) op = substitute(op,"${c}",attr[2]); 549 if ( attrCnt > 3 ) op = substitute(op,"${d}",attr[3]); 550 if ( attrCnt > 4 ) op = substitute(op,"${e}",attr[4]); 551 if ( attrCnt > 5 ) op = substitute(op,"${f}",attr[5]); 552 try { 553 sql.execute(op); 554 } catch (SQLException e) { 555 operror = op; 558 eignore = e; 559 } 560 } 561 sql.close(); 562 if (eignore != null) { 563 throw eignore; 565 } 566 } 567 568 569 570 575 public void runSQLGroup(String opname) throws SQLException { 576 runSQLGroup(opname,(String [])null); 577 } 578 579 587 public void runSQLGroup(String opname, String attr) throws SQLException { 588 String [] param = {attr}; 589 runSQLGroup(opname,param); 590 } 591 592 600 public void runSQLGroup(String opname, String attrA, String attrB) throws SQLException { 601 String [] param = {attrA,attrB}; 602 runSQLGroup(opname,param); 603 } 604 605 606 607 610 public void close() throws SQLException { 611 Iterator it = m_preparedStatements.values().iterator(); 612 while (it.hasNext()) { 613 List psl = (List) it.next(); 614 Iterator itl = psl.iterator(); 615 while (itl.hasNext()) { 616 PreparedStatement ps = (PreparedStatement)itl.next(); 617 ps.close(); 618 } 619 it.remove(); 620 } 621 it = m_cachedStmtInUse.values().iterator(); 622 while (it.hasNext()) { 623 it.remove(); 624 } 625 } 626 627 636 public static Properties loadSQLFile(String sqlFile, Properties defaultOps, String idType) throws IOException { 637 Properties sqlTable = new Properties(defaultOps); 638 BufferedReader src = openResourceFile(sqlFile); 639 String line = null; 640 while ((line = src.readLine()) != null) { 641 if (line.startsWith("#")) { 642 continue; } 644 String opName = line.trim(); 645 StringBuffer sql = new StringBuffer (); 646 while (true) { 647 line = src.readLine(); 648 if (line == null || line.trim().equals("")) { 649 sqlTable.setProperty(opName, sql.toString()); 651 break; 652 } else if (line.startsWith("#")) { 653 continue; 654 } else { 655 sql.append(substitute(line.trim(), "${id}", idType)); 656 sql.append("\n"); 657 } 658 } 659 if (line == null) break; } 661 return sqlTable; 662 } 663 664 665 666 public static String concatOpName(String opName, String attr) { 667 return (opName + attr); 668 } 669 670 671 public static String concatOpName(String opName, String attrA, String attrB) { 672 return (opName + attrA + attrB); 673 } 674 675 676 public static String substitute(String line, String macro, String subs) { 677 int loc = line.indexOf(macro); 678 if (loc != -1) { 679 return line.substring(0, loc) + subs + substitute(line.substring(loc+macro.length()),macro, subs); 680 } else { 681 return line; 682 } 683 } 684 685 686 689 693 protected Properties getSQLTable() { 694 return m_sql; 695 } 696 697 700 public static BufferedReader openResourceFile(String filename) throws IOException { 701 InputStream is = SQLCache.class.getClassLoader().getResourceAsStream(filename); 702 if (is == null) 703 throw new IOException("Can't open resource " + filename); 704 return new BufferedReader(new InputStreamReader(is, "US-ASCII")); 705 } 706 707 712 protected ResultSetIterator executeSQL(PreparedStatement ps, String opname, ResultSetIterator iterator) throws SQLException { 713 if (ps.execute()) { 714 ResultSet rs = ps.getResultSet(); 715 iterator.reset(rs, ps, this, opname); 716 return iterator; 717 } else { 718 returnPreparedSQLStatement(ps); 719 return null; 720 } 721 } 722 723 724 729 730 protected String genSQLStatement ( String opname ) throws SQLException { 731 734 String sql = ""; 735 boolean badop = false; 736 if ( opname.startsWith("*") ) { 737 int delim = opname.indexOf(' '); 739 String op = opname.substring(1,delim); 740 String args = opname.substring(delim+1); 741 if ( op.equals("findReif") ) { 742 sql = genSQLStmtFindReif(op,args); 743 } else badop = true; 744 } else badop = true; 745 if ( badop ) { 746 logger.error("Unable to generate SQL for operation: " + opname); 747 throw new JenaException("Unable to generate SQL for operation: " + opname); 748 } 749 return sql; 750 } 751 752 761 762 protected String genSQLStmtFindReif ( String op, String args ) throws SQLException { 763 780 781 String stmtStr = getSQLStatement("selectReified"); 782 String qual = ""; 783 IRDBDriver driver = m_connection.getDriver(); 784 785 if ( args.equals("") ) { 786 } else { 788 int ix = 0; 789 boolean hasSubj = false; 790 boolean hasProp = false; 791 boolean hasObj = false; 792 boolean objIsStmt = false; 793 char reifProp = ' '; 794 int argLen = args.length(); 795 796 if ( args.charAt(ix) == 'N' ) { 797 hasSubj = true; 798 ix++; 799 } 800 hasProp = (ix < argLen) && (args.charAt(ix) == 'P'); 801 if ( hasProp && (ix < argLen) ) { 802 ix++; 803 reifProp = args.charAt(ix++); 804 } 805 hasObj = (ix < argLen) && (args.charAt(ix) == 'O'); 806 if ( hasObj ) { 807 ix++; 808 objIsStmt = (ix < argLen) && (args.charAt(ix) == 'C'); 809 } 810 if ( !hasProp ) { 811 if ( hasSubj ) { 812 qual += driver.genSQLReifQualStmt(); 814 if ( hasObj ) { 815 qual += " AND " + driver.genSQLReifQualAnyObj(objIsStmt); 817 } 818 } else { 819 qual += driver.genSQLReifQualAnyObj(objIsStmt); 821 } 822 } else { 823 if ( hasSubj ) qual += driver.genSQLReifQualStmt() + " AND "; 825 qual += driver.genSQLReifQualObj(reifProp,hasObj); 826 } 827 stmtStr += " AND " + qual; 828 } 829 return stmtStr; 830 } 831 832 } 833 834 860 | Popular Tags |