/** * Determine whether or not any columns in the current index row are being changed by the update. * No need to update the index if no columns changed. * * @return Nothing. * @exception StandardException Thrown on error */ private boolean indexRowChanged() throws StandardException { int numColumns = ourIndexRow.nColumns(); for (int index = 1; index <= numColumns; index++) { DataValueDescriptor oldOrderable = ourIndexRow.getColumn(index); DataValueDescriptor newOrderable = ourUpdatedIndexRow.getColumn(index); if (!(oldOrderable.compare(DataValueDescriptor.ORDER_OP_EQUALS, newOrderable, true, true))) { return true; } } return false; }
/** * Insert the given row into the given conglomerate and check for duplicate key error. * * @param row The row to insert * @exception StandardException Thrown on duplicate key error */ private void insertAndCheckDups(ExecIndexRow row) throws StandardException { openIndexCC(); int insertStatus = indexCC.insert(row.getRowArray()); if (insertStatus == ConglomerateController.ROWISDUPLICATE) { /* ** We have a duplicate key error. */ String indexOrConstraintName = indexName; // now get table name, and constraint name if needed LanguageConnectionContext lcc = activation.getLanguageConnectionContext(); DataDictionary dd = lcc.getDataDictionary(); // get the descriptors ConglomerateDescriptor cd = dd.getConglomerateDescriptor(indexCID); UUID tableID = cd.getTableID(); TableDescriptor td = dd.getTableDescriptor(tableID); String tableName = td.getName(); if (indexOrConstraintName == null) // no index name passed in { ConstraintDescriptor conDesc = dd.getConstraintDescriptor(td, cd.getUUID()); indexOrConstraintName = conDesc.getConstraintName(); } throw StandardException.newException( SQLState.LANG_DUPLICATE_KEY_CONSTRAINT, indexOrConstraintName, tableName); } if (SanityManager.DEBUG) { if (insertStatus != 0) { SanityManager.THROWASSERT("Unknown insert status " + insertStatus); } } }
/** * Delete a row from our index. This assumes our index ScanController is positioned before the row * by setScan if we own the SC, otherwise it is positioned on the row by the underlying index * scan. * * <p>This verifies the row exists and is unique. * * @exception StandardException Thrown on error */ private void doDelete() throws StandardException { if (ownIndexSC) { if (!indexSC.next()) { // This means that the entry for the index does not exist, this // is a serious problem with the index. Past fixed problems // like track 3703 can leave db's in the field with this problem // even though the bug in the code which caused it has long // since been fixed. Then the problem can surface months later // when the customer attempts to upgrade. By "ignoring" the // missing row here the problem is automatically "fixed" and // since the code is trying to delete the row anyway it doesn't // seem like such a bad idea. It also then gives a tool to // support to be able to fix some system catalog problems where // they can delete the base rows by dropping the system objects // like stored statements. /* dem 2013/04/10 - temporarily comment this out while we are getting snapshot isolation DDL support in place if (SanityManager.DEBUG) SanityManager.THROWASSERT( "Index row "+RowUtil.toString(ourIndexRow)+ " not found in conglomerateid " + indexCID + "Current scan = " + indexSC); */ Object[] args = new Object[2]; args[0] = ourIndexRow.getRowArray()[ourIndexRow.getRowArray().length - 1]; args[1] = new Long(indexCID); Monitor.getStream() .println( MessageService.getCompleteMessage( SQLState.LANG_IGNORE_MISSING_INDEX_ROW_DURING_DELETE, args)); // just return indicating the row has been deleted. return; } } indexSC.delete(); }
/** * Position our index scan to 'ourIndexRow'. * * <p>This creates the scan the first time it is called. * * @exception StandardException Thrown on error */ private void setScan() throws StandardException { /* * -sf- Derby makes an assumption about system tables that isn't true * for Splice land, which results in WriteConflicts occurring * when you try to drop tables * * With indices, Derby only ever creates start and stop keys for the scan. * However, if the entire index is to be scanned, one or more column in the start/stop * key may be null. With db this was apparently treated acceptably, but in Splice * this results in garbage start and stop row keys, which in turn results in deleting * every row in the index instead of deleting just the rows of interest. * * Thus, the following hack. When the row is not entirely filled, we convert * the start/stop key into a single ANDed equals qualifier[], and use that instead */ DataValueDescriptor[] ourRowDvds = ourIndexRow.getRowArray(); int numNonNull = ourRowDvds.length; for (int i = 0; i < ourRowDvds.length; i++) { if (ourRowDvds[i].isNull()) { numNonNull--; } } Qualifier[][] qualifiers = null; if (numNonNull < ourRowDvds.length) { qualifiers = new Qualifier[1][]; qualifiers[0] = new Qualifier[numNonNull]; for (int dvdPos = 0, qualPos = 0; dvdPos < ourRowDvds.length; dvdPos++) { if (ourRowDvds[dvdPos].isNull()) continue; ScanQualifier qualifier = new GenericScanQualifier(); qualifier.setQualifier( dvdPos, ourRowDvds[dvdPos], DataValueDescriptor.ORDER_OP_EQUALS, false, false, false); qualifiers[0][qualPos] = qualifier; } } /* Get the SC from the activation if re-using */ if (!ownIndexSC) { indexSC = activation.getIndexScanController(); } else if (indexSC == null) { RowLocation templateBaseRowLocation = baseCC.newRowLocationTemplate(); /* DataDictionary doesn't have compiled info */ if (indexSCOCI == null) { indexSC = tc.openScan( indexCID, false, /* hold */ TransactionController.OPENMODE_FORUPDATE, /* forUpdate */ lockMode, isolationLevel, (FormatableBitSet) null, /* all fields */ ourIndexRow.getRowArray(), /* startKeyValue */ ScanController.GE, /* startSearchOp */ qualifiers, /* qualifier */ ourIndexRow.getRowArray(), /* stopKeyValue */ ScanController.GT /* stopSearchOp */); } else { indexSC = tc.openCompiledScan( false, /* hold */ TransactionController.OPENMODE_FORUPDATE, /* forUpdate */ lockMode, isolationLevel, (FormatableBitSet) null, /* all fields */ ourIndexRow.getRowArray(), /* startKeyValue */ ScanController.GE, /* startSearchOp */ qualifiers, /* qualifier */ ourIndexRow.getRowArray(), /* stopKeyValue */ ScanController.GT, /* stopSearchOp */ indexSCOCI, indexDCOCI); } } else { indexSC.reopenScan( ourIndexRow.getRowArray(), /* startKeyValue */ ScanController.GE, /* startSearchOperator */ qualifiers, /* qualifier */ ourIndexRow.getRowArray(), /* stopKeyValue */ ScanController.GT /* stopSearchOperator */); } }