1 21 22 package org.apache.derby.impl.sql.compile; 23 24 import org.apache.derby.iapi.services.context.ContextManager; 25 26 import org.apache.derby.iapi.reference.SQLState; 27 import org.apache.derby.iapi.error.StandardException; 28 29 import org.apache.derby.iapi.sql.conn.Authorizer; 30 import org.apache.derby.iapi.sql.dictionary.DataDictionary; 31 import org.apache.derby.iapi.sql.dictionary.ColumnDescriptor; 32 import org.apache.derby.iapi.sql.dictionary.TableDescriptor; 33 import org.apache.derby.iapi.sql.dictionary.GenericDescriptorList; 34 import org.apache.derby.iapi.sql.dictionary.ColumnDescriptor; 35 import org.apache.derby.iapi.sql.dictionary.ColumnDescriptorList; 36 37 38 import org.apache.derby.iapi.sql.ResultSet; 39 import org.apache.derby.iapi.sql.StatementType; 40 41 import org.apache.derby.iapi.sql.compile.CompilerContext; 42 import org.apache.derby.iapi.sql.compile.C_NodeTypes; 43 import org.apache.derby.iapi.reference.ClassName; 44 45 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext; 46 47 import org.apache.derby.iapi.sql.execute.CursorResultSet; 48 import org.apache.derby.iapi.sql.execute.ConstantAction; 49 import org.apache.derby.iapi.sql.execute.ExecPreparedStatement; 50 import org.apache.derby.iapi.sql.execute.ExecRow; 51 52 import org.apache.derby.iapi.sql.Activation; 53 54 import org.apache.derby.iapi.services.sanity.SanityManager; 55 56 import org.apache.derby.iapi.services.compiler.MethodBuilder; 57 58 import org.apache.derby.iapi.store.access.StaticCompiledOpenConglomInfo; 59 import org.apache.derby.iapi.store.access.TransactionController; 60 61 import org.apache.derby.vti.DeferModification; 62 63 import org.apache.derby.catalog.UUID; 64 import org.apache.derby.iapi.services.io.FormatableBitSet; 65 66 import org.apache.derby.impl.sql.compile.ActivationClassBuilder; 67 68 import org.apache.derby.impl.sql.execute.DeleteConstantAction; 69 import org.apache.derby.impl.sql.execute.FKInfo; 70 71 import java.lang.reflect.Modifier ; 72 import org.apache.derby.iapi.services.classfile.VMOpcode; 73 import org.apache.derby.iapi.services.io.FormatableProperties; 74 import java.util.Vector ; 75 import java.util.Hashtable ; 76 import java.util.Properties ; 77 import org.apache.derby.iapi.sql.compile.NodeFactory; 78 import org.apache.derby.iapi.util.ReuseFactory; 79 import org.apache.derby.iapi.sql.depend.Dependent; 80 import org.apache.derby.iapi.sql.ResultDescription; 81 import org.apache.derby.iapi.services.compiler.LocalField; 82 83 84 94 95 public class DeleteNode extends DMLModStatementNode 96 { 97 98 private static final String COLUMNNAME = "###RowLocationToDelete"; 99 100 101 protected boolean deferred; 102 protected ExecRow emptyHeapRow; 103 protected FromTable targetTable; 104 protected FKInfo fkInfo; 105 protected FormatableBitSet readColsBitSet; 106 107 private ConstantAction[] dependentConstantActions; 108 private boolean cascadeDelete; 109 private QueryTreeNode[] dependentNodes; 110 111 118 119 public void init(Object targetTableName, 120 Object queryExpression) 121 { 122 super.init(queryExpression); 123 this.targetTableName = (TableName) targetTableName; 124 } 125 126 public String statementToString() 127 { 128 return "DELETE"; 129 } 130 131 147 148 public QueryTreeNode bind() throws StandardException 149 { 150 getCompilerContext().pushCurrentPrivType( Authorizer.SELECT_PRIV); 152 try 153 { 154 FromList fromList = (FromList) getNodeFactory().getNode( 155 C_NodeTypes.FROM_LIST, 156 getNodeFactory().doJoinOrderOptimization(), 157 getContextManager()); 158 ResultColumn rowLocationColumn = null; 159 CurrentRowLocationNode rowLocationNode; 160 TableName cursorTargetTableName = null; 161 CurrentOfNode currentOfNode = null; 162 163 DataDictionary dataDictionary = getDataDictionary(); 164 super.bindTables(dataDictionary); 165 166 170 if (SanityManager.DEBUG) 172 SanityManager.ASSERT(resultSet != null && resultSet instanceof SelectNode, 173 "Delete must have a select result set"); 174 175 SelectNode sel; 176 sel = (SelectNode)resultSet; 177 targetTable = (FromTable) sel.fromList.elementAt(0); 178 if (targetTable instanceof CurrentOfNode) 179 { 180 currentOfNode = (CurrentOfNode) targetTable; 181 182 cursorTargetTableName = currentOfNode.getBaseCursorTargetTableName(); 183 if (SanityManager.DEBUG) 185 SanityManager.ASSERT(cursorTargetTableName != null); 186 } 187 188 if (targetTable instanceof FromVTI) 189 { 190 targetVTI = (FromVTI) targetTable; 191 targetVTI.setTarget(); 192 } 193 else 194 { 195 if (targetTableName == null) 198 { 199 if (SanityManager.DEBUG) 201 SanityManager.ASSERT(cursorTargetTableName!=null); 202 203 targetTableName = cursorTargetTableName; 204 } 205 else if (cursorTargetTableName != null) 208 { 209 if ( !targetTableName.equals(cursorTargetTableName)) 212 { 213 throw StandardException.newException(SQLState.LANG_CURSOR_DELETE_MISMATCH, 214 targetTableName, 215 currentOfNode.getCursorName()); 216 } 217 } 218 } 219 220 verifyTargetTable(); 222 223 224 if (SanityManager.DEBUG) 225 SanityManager.ASSERT((resultSet.resultColumns == null), 226 "resultColumns is expected to be null until bind time"); 227 228 229 if (targetTable instanceof FromVTI) 230 { 231 getResultColumnList(); 232 resultColumnList = targetTable.getResultColumnsForList(null, 233 resultColumnList, null); 234 235 236 resultSet.setResultColumns(resultColumnList); 237 } 238 else 239 { 240 244 245 resultColumnList = new ResultColumnList(); 246 247 FromBaseTable fbt = getResultColumnList(resultColumnList); 248 249 readColsBitSet = getReadMap(dataDictionary, 250 targetTableDescriptor); 251 252 resultColumnList = fbt.addColsToList(resultColumnList, readColsBitSet); 253 254 258 int i = 1; 259 int size = targetTableDescriptor.getMaxColumnID(); 260 for (; i <= size; i++) 261 { 262 if (!readColsBitSet.get(i)) 263 { 264 break; 265 } 266 } 267 268 if (i > size) 269 { 270 readColsBitSet = null; 271 } 272 273 276 emptyHeapRow = targetTableDescriptor.getEmptyExecRow(getContextManager()); 277 278 279 rowLocationNode = (CurrentRowLocationNode) getNodeFactory().getNode( 280 C_NodeTypes.CURRENT_ROW_LOCATION_NODE, 281 getContextManager()); 282 rowLocationColumn = 283 (ResultColumn) getNodeFactory().getNode( 284 C_NodeTypes.RESULT_COLUMN, 285 COLUMNNAME, 286 rowLocationNode, 287 getContextManager()); 288 rowLocationColumn.markGenerated(); 289 290 291 resultColumnList.addResultColumn(rowLocationColumn); 292 293 294 correlateAddedColumns( resultColumnList, targetTable ); 295 296 297 resultSet.setResultColumns(resultColumnList); 298 } 299 300 301 super.bindExpressions(); 302 303 304 resultSet.getResultColumns(). 305 bindUntypedNullsToResultColumns(resultColumnList); 306 307 if (! (targetTable instanceof FromVTI)) 308 { 309 310 rowLocationColumn.bindResultColumnToExpression(); 311 312 bindConstraints(dataDictionary, 313 getNodeFactory(), 314 targetTableDescriptor, 315 null, 316 resultColumnList, 317 (int[]) null, 318 readColsBitSet, 319 false, 320 true); 321 322 328 if (resultSet.subqueryReferencesTarget( 329 targetTableDescriptor.getName(), true) || 330 requiresDeferredProcessing()) 331 { 332 deferred = true; 333 } 334 } 335 else 336 { 337 deferred = VTIDeferModPolicy.deferIt( DeferModification.DELETE_STATEMENT, 338 targetVTI, 339 null, 340 sel.getWhereClause()); 341 } 342 sel = null; 344 345 if (SanityManager.DEBUG) 346 { 347 SanityManager.ASSERT(fromList.size() == 0, 348 "fromList.size() is expected to be 0, not " + 349 fromList.size() + 350 " on return from RS.bindExpressions()"); 351 } 352 353 if(fkTableNames != null) 356 { 357 String currentTargetTableName = targetTableDescriptor.getSchemaName() + 358 "." + targetTableDescriptor.getName(); 359 360 if(!isDependentTable){ 361 graphHashTable = new Hashtable (); 363 } 364 365 369 if(!graphHashTable.containsKey(currentTargetTableName)) 370 { 371 cascadeDelete = true; 372 int noDependents = fkTableNames.length; 373 dependentNodes = new QueryTreeNode[noDependents]; 374 graphHashTable.put(currentTargetTableName, new Integer (noDependents)); 375 for(int i =0 ; i < noDependents ; i ++) 376 { 377 dependentNodes[i] = getDependentTableNode(fkTableNames[i], 378 fkRefActions[i], 379 fkColDescriptors[i]); 380 dependentNodes[i].bind(); 381 } 382 } 383 } 384 else 385 { 386 if(isDependentTable) 388 { 389 String currentTargetTableName = targetTableDescriptor.getSchemaName() 390 + "." + targetTableDescriptor.getName(); 391 graphHashTable.put(currentTargetTableName, new Integer (0)); 392 393 } 394 } 395 if (isPrivilegeCollectionRequired()) 396 { 397 getCompilerContext().pushCurrentPrivType( getPrivType()); 398 getCompilerContext().addRequiredTablePriv( targetTableDescriptor); 399 getCompilerContext().popCurrentPrivType(); 400 } 401 } 402 finally 403 { 404 getCompilerContext().popCurrentPrivType(); 405 } 406 return this; 407 } 409 int getPrivType() 410 { 411 return Authorizer.DELETE_PRIV; 412 } 413 414 421 public boolean referencesSessionSchema() 422 throws StandardException 423 { 424 return resultSet.referencesSessionSchema(); 426 } 427 428 433 public ConstantAction makeConstantAction() throws StandardException 434 { 435 436 437 if (targetTableDescriptor != null) 438 { 439 int lockMode = resultSet.updateTargetLockMode(); 441 long heapConglomId = targetTableDescriptor.getHeapConglomerateId(); 442 TransactionController tc = getLanguageConnectionContext().getTransactionCompile(); 443 StaticCompiledOpenConglomInfo[] indexSCOCIs = 444 new StaticCompiledOpenConglomInfo[indexConglomerateNumbers.length]; 445 446 for (int index = 0; index < indexSCOCIs.length; index++) 447 { 448 indexSCOCIs[index] = tc.getStaticCompiledConglomInfo(indexConglomerateNumbers[index]); 449 } 450 451 455 if (targetTableDescriptor.getLockGranularity() == TableDescriptor.TABLE_LOCK_GRANULARITY) 456 { 457 lockMode = TransactionController.MODE_TABLE; 458 } 459 460 ResultDescription resultDescription = null; 461 if(isDependentTable) 462 { 463 resultDescription = makeResultDescription(); 467 } 468 469 470 return getGenericConstantActionFactory().getDeleteConstantAction 471 ( heapConglomId, 472 targetTableDescriptor.getTableType(), 473 tc.getStaticCompiledConglomInfo(heapConglomId), 474 indicesToMaintain, 475 indexConglomerateNumbers, 476 indexSCOCIs, 477 emptyHeapRow, 478 deferred, 479 false, 480 targetTableDescriptor.getUUID(), 481 lockMode, 482 null, null, null, 0, null, null, 483 resultDescription, 484 getFKInfo(), 485 getTriggerInfo(), 486 (readColsBitSet == null) ? (FormatableBitSet)null : new FormatableBitSet(readColsBitSet), 487 getReadColMap(targetTableDescriptor.getNumberOfColumns(),readColsBitSet), 488 resultColumnList.getStreamStorableColIds(targetTableDescriptor.getNumberOfColumns()), 489 (readColsBitSet == null) ? 490 targetTableDescriptor.getNumberOfColumns() : 491 readColsBitSet.getNumBitsSet(), 492 (UUID) null, 493 resultSet.isOneRowResultSet(), 494 dependentConstantActions); 495 } 496 else 497 { 498 503 return getGenericConstantActionFactory().getUpdatableVTIConstantAction( DeferModification.DELETE_STATEMENT, 504 deferred); 505 } 506 } 507 508 527 public void generate(ActivationClassBuilder acb, 528 MethodBuilder mb) 529 throws StandardException 530 { 531 532 generateCodeForTemporaryTable(acb, mb); 534 535 536 if(!isDependentTable) 537 generateParameterValueSet(acb); 538 539 acb.pushGetResultSetFactoryExpression(mb); 540 acb.newRowLocationScanResultSetName(); 541 resultSet.generate(acb, mb); 543 String resultSetGetter; 544 int argCount; 545 String parentResultSetId; 546 547 if (targetTableDescriptor != null) 549 { 550 558 559 acb.newFieldDeclaration(Modifier.PRIVATE, 560 ClassName.CursorResultSet, 561 acb.getRowLocationScanResultSetName()); 562 563 if(cascadeDelete || isDependentTable) 564 { 565 resultSetGetter = "getDeleteCascadeResultSet"; 566 argCount = 4; 567 } 568 else 569 { 570 resultSetGetter = "getDeleteResultSet"; 571 argCount = 1; 572 } 573 574 } else { 575 argCount = 1; 576 resultSetGetter = "getDeleteVTIResultSet"; 577 } 578 579 if(isDependentTable) 580 { 581 mb.push(acb.addItem(makeConstantAction())); 582 583 }else 584 { 585 if(cascadeDelete) 586 { 587 mb.push(-1); } 589 } 590 591 String resultSetArrayType = ClassName.ResultSet + "[]"; 592 if(cascadeDelete) 593 { 594 parentResultSetId = targetTableDescriptor.getSchemaName() + 595 "." + targetTableDescriptor.getName(); 596 LocalField arrayField = 598 acb.newFieldDeclaration(Modifier.PRIVATE, resultSetArrayType); 599 mb.pushNewArray(ClassName.ResultSet, dependentNodes.length); mb.setField(arrayField); 601 for(int index=0 ; index < dependentNodes.length ; index++) 602 { 603 604 dependentNodes[index].setRefActionInfo(fkIndexConglomNumbers[index], 605 fkColArrays[index], 606 parentResultSetId, 607 true); 608 mb.getField(arrayField); 617 if(mb.statementNumHitLimit(10)) 618 { 619 MethodBuilder dmb = acb.newGeneratedFun(ClassName.ResultSet, Modifier.PRIVATE); 620 dependentNodes[index].generate(acb,dmb); dmb.methodReturn(); 622 dmb.complete(); 623 624 mb.pushThis(); 625 mb.callMethod(VMOpcode.INVOKEVIRTUAL, (String ) null, dmb.getName(), ClassName.ResultSet, 0); 627 }else 628 { 629 dependentNodes[index].generate(acb,mb); } 631 632 mb.setArrayElement(index); 633 } 634 mb.getField(arrayField); } 636 else 637 { 638 if(isDependentTable) 639 { 640 mb.pushNull(resultSetArrayType); } 642 } 643 644 645 if(cascadeDelete || isDependentTable) 646 { 647 parentResultSetId = targetTableDescriptor.getSchemaName() + 648 "." + targetTableDescriptor.getName(); 649 mb.push(parentResultSetId); 650 651 } 652 mb.callMethod(VMOpcode.INVOKEINTERFACE, (String ) null, resultSetGetter, ClassName.ResultSet, argCount); 653 654 655 if(!isDependentTable && cascadeDelete) 656 { 657 int numResultSets = acb.getRowCount(); 658 if(numResultSets > 0) 659 { 660 MethodBuilder constructor = acb.getConstructor(); 662 constructor.pushThis(); 663 constructor.pushNewArray(ClassName.CursorResultSet, numResultSets); 664 constructor.putField(ClassName.BaseActivation, 665 "raParentResultSets", 666 ClassName.CursorResultSet + "[]"); 667 constructor.endStatement(); 668 } 669 } 670 } 671 672 673 679 protected final int getStatementType() 680 { 681 return StatementType.DELETE; 682 } 683 684 685 704 public FormatableBitSet getReadMap 705 ( 706 DataDictionary dd, 707 TableDescriptor baseTable 708 ) 709 throws StandardException 710 { 711 boolean[] needsDeferredProcessing = new boolean[1]; 712 needsDeferredProcessing[0] = requiresDeferredProcessing(); 713 714 Vector conglomVector = new Vector (); 715 relevantTriggers = new GenericDescriptorList(); 716 717 FormatableBitSet columnMap = DeleteNode.getDeleteReadMap(baseTable, conglomVector, relevantTriggers, needsDeferredProcessing ); 718 719 markAffectedIndexes( conglomVector ); 720 721 adjustDeferredFlag( needsDeferredProcessing[0] ); 722 723 return columnMap; 724 } 725 726 731 private QueryTreeNode getDependentTableNode(String tableName, int refAction, 732 ColumnDescriptorList cdl) throws StandardException 733 { 734 QueryTreeNode node=null; 735 736 int index = tableName.indexOf('.'); 737 String schemaName = tableName.substring(0 , index); 738 String tName = tableName.substring(index+1); 739 if(refAction == StatementType.RA_CASCADE) 740 { 741 node = getEmptyDeleteNode(schemaName , tName); 742 ((DeleteNode)node).isDependentTable = true; 743 ((DeleteNode)node).graphHashTable = graphHashTable; 744 } 745 746 if(refAction == StatementType.RA_SETNULL) 747 { 748 node = getEmptyUpdateNode(schemaName , tName, cdl); 749 ((UpdateNode)node).isDependentTable = true; 750 ((UpdateNode)node).graphHashTable = graphHashTable; 751 } 752 753 return node; 754 } 755 756 757 private QueryTreeNode getEmptyDeleteNode(String schemaName, String targetTableName) 758 throws StandardException 759 { 760 761 ValueNode whereClause = null; 762 TableName tableName = null; 763 FromTable fromTable = null; 764 QueryTreeNode retval; 765 SelectNode resultSet; 766 767 tableName = new TableName(); 768 tableName.init(schemaName , targetTableName); 769 770 NodeFactory nodeFactory = getNodeFactory(); 771 FromList fromList = (FromList) nodeFactory.getNode(C_NodeTypes.FROM_LIST, getContextManager()); 772 fromTable = (FromTable) nodeFactory.getNode( 773 C_NodeTypes.FROM_BASE_TABLE, 774 tableName, 775 null, 776 ReuseFactory.getInteger(FromBaseTable.DELETE), 777 null, 778 getContextManager()); 779 780 Properties targetProperties = new FormatableProperties(); 783 targetProperties.put("index", "null"); 784 ((FromBaseTable) fromTable).setTableProperties(targetProperties); 785 786 fromList.addFromTable(fromTable); 787 resultSet = (SelectNode) nodeFactory.getNode( 788 C_NodeTypes.SELECT_NODE, 789 null, 790 null, 791 fromList, 792 whereClause, 793 null, 794 getContextManager()); 795 796 retval =(QueryTreeNode) nodeFactory.getNode( 797 C_NodeTypes.DELETE_NODE, 798 tableName, 799 resultSet, 800 getContextManager()); 801 802 return retval; 803 } 804 805 806 807 private QueryTreeNode getEmptyUpdateNode(String schemaName, 808 String targetTableName, 809 ColumnDescriptorList cdl) 810 throws StandardException 811 { 812 813 ValueNode whereClause = null; 814 TableName tableName = null; 815 FromTable fromTable = null; 816 QueryTreeNode retval; 817 SelectNode resultSet; 818 819 tableName = new TableName(); 820 tableName.init(schemaName , targetTableName); 821 822 NodeFactory nodeFactory = getNodeFactory(); 823 FromList fromList = (FromList) nodeFactory.getNode(C_NodeTypes.FROM_LIST, getContextManager()); 824 fromTable = (FromTable) nodeFactory.getNode( 825 C_NodeTypes.FROM_BASE_TABLE, 826 tableName, 827 null, 828 ReuseFactory.getInteger(FromBaseTable.DELETE), 829 null, 830 getContextManager()); 831 832 833 Properties targetProperties = new FormatableProperties(); 836 targetProperties.put("index", "null"); 837 ((FromBaseTable) fromTable).setTableProperties(targetProperties); 838 839 fromList.addFromTable(fromTable); 840 841 resultSet = (SelectNode) nodeFactory.getNode( 842 C_NodeTypes.SELECT_NODE, 843 getSetClause(tableName, cdl), 844 null, 845 fromList, 846 whereClause, 847 null, 848 getContextManager()); 849 850 retval =(QueryTreeNode) nodeFactory.getNode( 851 C_NodeTypes.UPDATE_NODE, 852 tableName, 853 resultSet, 854 getContextManager()); 855 856 return retval; 857 } 858 859 860 861 private ResultColumnList getSetClause(TableName tabName, 862 ColumnDescriptorList cdl) 863 throws StandardException 864 { 865 ResultColumn resultColumn; 866 ValueNode valueNode; 867 868 NodeFactory nodeFactory = getNodeFactory(); 869 ResultColumnList columnList = (ResultColumnList) nodeFactory.getNode( 870 C_NodeTypes.RESULT_COLUMN_LIST, 871 getContextManager()); 872 873 valueNode = (ValueNode) nodeFactory.getNode(C_NodeTypes.UNTYPED_NULL_CONSTANT_NODE, 874 getContextManager()); 875 for(int index =0 ; index < cdl.size() ; index++) 876 { 877 ColumnDescriptor cd = (ColumnDescriptor) cdl.elementAt(index); 878 if((cd.getType()).isNullable()) 881 { 882 resultColumn = (ResultColumn) nodeFactory.getNode( 883 C_NodeTypes.RESULT_COLUMN, 884 cd, 885 valueNode, 886 getContextManager()); 887 888 columnList.addResultColumn(resultColumn); 889 } 890 } 891 return columnList; 892 } 893 894 895 public QueryTreeNode optimize() throws StandardException 896 { 897 if(cascadeDelete) 898 { 899 for(int index=0 ; index < dependentNodes.length ; index++) 900 { 901 dependentNodes[index] = dependentNodes[index].optimize(); 902 } 903 } 904 905 return super.optimize(); 906 } 907 908 932 private static FormatableBitSet getDeleteReadMap 933 ( 934 TableDescriptor baseTable, 935 Vector conglomVector, 936 GenericDescriptorList relevantTriggers, 937 boolean[] needsDeferredProcessing 938 ) 939 throws StandardException 940 { 941 int columnCount = baseTable.getMaxColumnID(); 942 FormatableBitSet columnMap = new FormatableBitSet(columnCount + 1); 943 944 959 DMLModStatementNode.getXAffectedIndexes(baseTable, null, columnMap, conglomVector ); 960 961 966 baseTable.getAllRelevantTriggers( StatementType.DELETE, (int[])null, relevantTriggers ); 967 if ( relevantTriggers.size() > 0 ) { needsDeferredProcessing[0] = true; } 968 969 if (relevantTriggers.size() > 0) 970 { 971 for (int i = 1; i <= columnCount; i++) 972 { 973 columnMap.set(i); 974 } 975 } 976 977 return columnMap; 978 } 979 980 984 private void correlateAddedColumns( ResultColumnList rcl, FromTable fromTable ) 985 throws StandardException 986 { 987 String correlationName = fromTable.getCorrelationName(); 988 989 if ( correlationName == null ) { return; } 990 991 TableName correlationNameNode = makeTableName( null, correlationName ); 992 int count = rcl.size(); 993 994 for ( int i = 0; i < count; i++ ) 995 { 996 ResultColumn column = (ResultColumn) rcl.elementAt( i ); 997 998 ValueNode expression = column.getExpression(); 999 1000 if ( (expression != null) && (expression instanceof ColumnReference) ) 1001 { 1002 ColumnReference reference = (ColumnReference) expression; 1003 1004 reference.setTableNameNode( correlationNameNode ); 1005 } 1006 } 1007 1008 } 1009 1010} 1011 | Popular Tags |