1 9 package org.mmbase.storage.search.implementation.database; 10 11 import java.sql.*; 12 import java.util.*; 13 import javax.sql.DataSource ; 14 15 import org.mmbase.cache.NodeCache; 16 import org.mmbase.cache.Cache; 17 import org.mmbase.bridge.NodeManager; 18 import org.mmbase.core.CoreField; 19 import org.mmbase.module.core.*; 20 import org.mmbase.storage.implementation.database.DatabaseStorageManager; 21 import org.mmbase.storage.implementation.database.DatabaseStorageManagerFactory; 22 import org.mmbase.storage.search.*; 23 import org.mmbase.util.logging.*; 24 import org.mmbase.storage.search.implementation.ModifiableQuery; 25 26 27 39 public class BasicQueryHandler implements SearchQueryHandler { 40 41 42 private static final StepField[] STEP_FIELD_ARRAY = new StepField[0]; 43 44 45 private static final Logger log = Logging.getLoggerInstance(BasicQueryHandler.class); 46 47 48 private SqlHandler sqlHandler = null; 49 50 51 private MMBase mmbase = null; 52 53 59 public BasicQueryHandler(SqlHandler sqlHandler) { 60 this.sqlHandler = sqlHandler; 61 mmbase = MMBase.getMMBase(); 62 } 63 64 65 public List getNodes(SearchQuery query, MMObjectBuilder builder) throws SearchQueryException { 67 68 List results; 69 Connection con = null; 70 Statement stmt = null; 71 String sqlString = null; 72 73 try { 74 boolean mustSkipResults = 76 (query.getOffset() != SearchQuery.DEFAULT_OFFSET) && 77 (sqlHandler.getSupportLevel(SearchQueryHandler.FEATURE_OFFSET, query) == SearchQueryHandler.SUPPORT_NONE); 78 79 80 boolean sqlHandlerSupportsMaxNumber = sqlHandler.getSupportLevel(SearchQueryHandler.FEATURE_MAX_NUMBER, query) != SearchQueryHandler.SUPPORT_NONE; 82 83 if (log.isDebugEnabled()) { 85 log.debug("Database offset support = " + (sqlHandler.getSupportLevel(SearchQueryHandler.FEATURE_OFFSET, query) != SearchQueryHandler.SUPPORT_NONE)); 86 log.debug("mustSkipResults = " + mustSkipResults); 87 log.debug("Database max support = " + sqlHandlerSupportsMaxNumber); 88 } 89 90 sqlString = createSqlString(query, mustSkipResults, sqlHandlerSupportsMaxNumber); 91 92 log.debug("sql: " + sqlString); 93 94 DataSource dataSource = ((DatabaseStorageManagerFactory) mmbase.getStorageManagerFactory()).getDataSource(); 97 con = dataSource.getConnection(); 98 stmt = con.createStatement(); 99 ResultSet rs = stmt.executeQuery(sqlString); 100 101 try { 102 if (mustSkipResults) { 103 log.debug("skipping results, to provide weak support for offset"); 104 for (int i = 0; i < query.getOffset(); i++) { 105 rs.next(); 106 } 107 } 108 109 StepField[] fields = (StepField[]) query.getFields().toArray(STEP_FIELD_ARRAY); 111 int maxNumber = query.getMaxNumber(); 112 113 if (builder instanceof ClusterBuilder) { 115 results = readNodes((ClusterBuilder) builder, fields, rs, sqlHandlerSupportsMaxNumber, maxNumber, query.getSteps().size()); 116 } else if (builder instanceof ResultBuilder) { 117 results = readNodes((ResultBuilder) builder, fields, rs, sqlHandlerSupportsMaxNumber, maxNumber); 118 } else { 119 results = readNodes(builder, fields, rs, sqlHandlerSupportsMaxNumber, maxNumber); 120 } 121 } finally { 122 rs.close(); 123 } 124 } catch (SQLException e) { 125 if (log.isDebugEnabled()) { 128 log.debug("Query failed:" + query + "\n" + e + Logging.stackTrace(e)); 129 } 130 throw new SearchQueryException("Query '" + (sqlString == null ? "" + query.toString() : sqlString) + "' failed: " + e.getClass().getName() + ": " + e.getMessage(), e); 131 } finally { 132 closeConnection(con, stmt); 133 } 134 135 return results; 136 } 137 138 143 protected void closeConnection(Connection con, Statement stmt) { 144 try { 145 if (stmt != null) { 146 stmt.close(); 147 } 148 } catch (Exception g) {} 149 try { 150 if (con != null) { 151 con.close(); 152 } 153 } catch (Exception g) {} 154 } 155 156 160 161 private String createSqlString(SearchQuery query, boolean mustSkipResults, boolean sqlHandlerSupportsMaxNumber) throws SearchQueryException { 162 int maxNumber = query.getMaxNumber(); 163 boolean mustTruncateResults = (maxNumber != SearchQuery.DEFAULT_MAX_NUMBER) && (! sqlHandlerSupportsMaxNumber); 165 String sqlString; 166 if (mustSkipResults) { log.debug("offset used in query and not supported in database."); 168 ModifiableQuery modifiedQuery = new ModifiableQuery(query); 169 modifiedQuery.setOffset(SearchQuery.DEFAULT_OFFSET); 170 171 if (mustTruncateResults) { 172 log.debug("max used in query but not supported in database."); 173 modifiedQuery.setMaxNumber(SearchQuery.DEFAULT_MAX_NUMBER); } else if (maxNumber != SearchQuery.DEFAULT_MAX_NUMBER) { 176 log.debug("max used in query and supported by database."); 177 modifiedQuery.setMaxNumber(query.getOffset() + maxNumber); 180 } 181 sqlString = sqlHandler.toSql(modifiedQuery, sqlHandler); 182 183 } else { 184 log.debug("offset not used or offset is supported by the database."); 185 if (mustTruncateResults) { 186 log.debug("max used in query but not supported in database."); 187 ModifiableQuery modifiedQuery = new ModifiableQuery(query); 190 modifiedQuery.setMaxNumber(SearchQuery.DEFAULT_MAX_NUMBER); sqlString = sqlHandler.toSql(modifiedQuery, sqlHandler); 192 } else { 193 log.debug("no need for modifying Query"); 195 sqlString = sqlHandler.toSql(query, sqlHandler); 196 } 197 } 198 return sqlString; 200 } 201 202 205 private List readNodes(ClusterBuilder builder, StepField[] fields, ResultSet rs, boolean sqlHandlerSupportsMaxNumber, int maxNumber, int numberOfSteps) throws SQLException { 206 List results = new ArrayList(); 207 DatabaseStorageManager storageManager = (DatabaseStorageManager)mmbase.getStorageManager(); 208 209 boolean storesAsFile = builder.getMMBase().getStorageManagerFactory().hasOption(org.mmbase.storage.implementation.database.Attributes.STORES_BINARY_AS_FILE); 210 try { 212 while (rs.next() && (results.size()<maxNumber || maxNumber==-1)) { 213 try { 214 ClusterNode node = new ClusterNode(builder, numberOfSteps); 215 node.start(); 216 217 int j = 1; 218 for (int i = 0; i < fields.length; i++) { 221 String fieldName = fields[i].getFieldName(); Step step = fields[i].getStep(); 223 String alias = step.getAlias(); 224 if (alias == null) { 225 alias = step.getTableName(); 227 } 228 CoreField field = builder.getField(alias + '.' + fieldName); 229 if (field.getType() == CoreField.TYPE_BINARY) continue; 230 Object value = storageManager.getValue(rs, j++, field, false); 231 node.storeValue(alias + '.' + fieldName, value); 232 } 233 node.clearChanged(); 234 node.finish(); 235 results.add(node); 236 } catch (Exception e) { 237 log.error(e.getMessage(), e); 239 } 240 } 241 } catch (SQLException sqe) { 242 log.error(sqe); 244 } 245 return results; 246 } 247 248 251 private List readNodes(ResultBuilder builder, StepField[] fields, ResultSet rs, boolean sqlHandlerSupportsMaxNumber, int maxNumber) throws SQLException { 252 List results = new ArrayList(); 253 DatabaseStorageManager storageManager = (DatabaseStorageManager)mmbase.getStorageManager(); 254 255 boolean storesAsFile = builder.getMMBase().getStorageManagerFactory().hasOption(org.mmbase.storage.implementation.database.Attributes.STORES_BINARY_AS_FILE); 256 try { 258 while (rs.next() && (maxNumber>results.size() || maxNumber==-1)) { 259 try { 260 ResultNode node = new ResultNode(builder); 261 node.start(); 262 int j = 1; 263 for (int i = 0; i < fields.length; i++) { 264 String fieldName = fields[i].getAlias(); 265 if (fieldName == null) { 266 fieldName = fields[i].getFieldName(); 267 } 268 CoreField field = builder.getField(fieldName); 269 if (field != null && field.getType() == CoreField.TYPE_BINARY) continue; 270 Object value = storageManager.getValue(rs, j++, field, false); 271 node.storeValue(fieldName, value); 272 } 273 node.clearChanged(); 274 node.finish(); 275 results.add(node); 276 } catch (Exception e) { 277 log.error(e.getMessage(), e); 279 } 280 } 281 } catch (SQLException sqe) { 282 log.error(sqe); 284 } 285 return results; 286 } 287 288 291 private List readNodes(MMObjectBuilder builder, StepField[] fields, ResultSet rs, boolean sqlHandlerSupportsMaxNumber, int maxNumber) throws SQLException { 292 List results= new ArrayList(); 293 DatabaseStorageManager storageManager = (DatabaseStorageManager)mmbase.getStorageManager(); 294 295 boolean storesAsFile = builder.getMMBase().getStorageManagerFactory().hasOption(org.mmbase.storage.implementation.database.Attributes.STORES_BINARY_AS_FILE); 296 Map fieldIndices = new HashMap(); 298 Step nodeStep = fields[0].getStep(); 299 int j = 1; 300 for (int i = 0; i < fields.length; i++) { 301 if (fields[i].getType() == CoreField.TYPE_BINARY) continue; 302 Integer index = new Integer (j++); 303 if (fields[i].getStep() == nodeStep) { 304 String fieldName = fields[i].getFieldName(); 305 CoreField field = builder.getField(fieldName); 306 if (field == null) { 307 log.warn("Did not find the field '" + fieldName + "' in builder " + builder); 308 continue; } 310 fieldIndices.put(field, index); 311 } 312 } 313 314 List builderFields = builder.getFields(NodeManager.ORDER_CREATE); 316 StringBuffer missingFields = null; 317 for (Iterator f = builderFields.iterator(); f.hasNext();) { 318 CoreField field = (CoreField)f.next(); 319 if (field.inStorage()) { 320 if (field.getType() == CoreField.TYPE_BINARY) continue; 321 if (fieldIndices.get(field) == null) { 322 if (missingFields == null) { 323 missingFields = new StringBuffer (field.getName()); 324 } else { 325 missingFields.append(", ").append(field.getName()); 326 } 327 } 328 } 329 } 330 331 boolean isVirtual = missingFields != null; 333 if (isVirtual) { 334 log.warn("This query returns virtual nodes (not querying: '" + missingFields + "')"); 335 } 336 337 try { 339 NodeCache nodeCache = NodeCache.getCache(); 340 Cache typeCache = Cache.getCache("TypeCache"); 341 int builderType = builder.getObjectType(); 342 Integer oTypeInteger = new Integer (builderType); 343 while (rs.next() && (maxNumber > results.size() || maxNumber==-1)) { 344 try { 345 352 353 MMObjectNode node; 354 if (!isVirtual) { 355 node = new MMObjectNode(builder, false); 356 } else { 357 node = new VirtualNode(builder); 358 } 359 node.start(); 360 for (Iterator i = builder.getFields(NodeManager.ORDER_CREATE).iterator(); i.hasNext(); ) { 361 CoreField field = (CoreField)i.next(); 362 if (! field.inStorage()) continue; 363 Integer index = (Integer ) fieldIndices.get(field); 364 Object value = null; 365 String fieldName = field.getName(); 366 if (index != null) { 367 value = storageManager.getValue(rs, index.intValue(), field, true); 368 } else { 369 java.sql.Blob b = null; 370 if (field.getType() == CoreField.TYPE_BINARY && storesAsFile) { 371 log.debug("Storage did not return data for '" + fieldName + "', supposing it on disk"); 372 b = storageManager.getBlobValue(node, field, true); 374 } else if (field.getType() == CoreField.TYPE_BINARY) { 375 value = MMObjectNode.VALUE_SHORTED; 377 } else if (! isVirtual){ 378 throw new IllegalStateException ("Storage did not return data for field '" + fieldName + "'"); 381 } 382 if (b != null) { 383 if (b.length() == -1) { 384 value = MMObjectNode.VALUE_SHORTED; 385 } else { 386 value = b.getBytes(0L, (int) b.length()); 387 } 388 } 389 } 390 node.storeValue(fieldName, value); 391 } 392 node.clearChanged(); 393 node.finish(); 394 395 if (! isVirtual) { 398 int otype = node.getOType(); 399 Integer number = new Integer (node.getNumber()); 400 if (otype == builderType) { 401 MMObjectNode cacheNode = (MMObjectNode) nodeCache.get(number); 402 if (cacheNode != null) { 403 node = cacheNode; 404 } else { 405 nodeCache.put(number, node); 406 } 407 typeCache.put(number, oTypeInteger); 408 } else { 409 typeCache.put(number, new Integer (otype)); 410 } 411 } 412 413 results.add(node); 414 } catch (Exception e) { 415 log.error(e.getMessage(), e); 417 } 418 } 419 } catch (SQLException sqe) { 420 log.error(sqe); 422 } 423 return results; 424 } 425 426 427 public int getSupportLevel(int feature, SearchQuery query) throws SearchQueryException { 429 int supportLevel; 430 switch (feature) { 431 case SearchQueryHandler.FEATURE_OFFSET: 432 case SearchQueryHandler.FEATURE_MAX_NUMBER: 436 int handlerSupport = sqlHandler.getSupportLevel(feature, query); 439 if (handlerSupport == SearchQueryHandler.SUPPORT_NONE) { 440 supportLevel = SearchQueryHandler.SUPPORT_NONE; 443 } else { 444 supportLevel = handlerSupport; 445 } 446 break; 447 448 default: 449 supportLevel = sqlHandler.getSupportLevel(feature, query); 450 } 451 return supportLevel; 452 } 453 454 public int getSupportLevel(Constraint constraint, SearchQuery query) throws SearchQueryException { 456 return sqlHandler.getSupportLevel(constraint, query); 457 } 458 459 } 460 | Popular Tags |