/** * Update one property table by inserting or deleting rows, and compute * the changes that this entails for the property usage counts. The * given rows are inserted into the table if $insert is true; otherwise * they are deleted. The property usage counts are recorded in the * call-by-ref parameter $propertyUseIncrements. * * The method assumes that all of the given rows are about the same * subject. This is ensured by callers. * * @since 1.8 * @param array $propertyUseIncrements * @param SMWSQLStore3Table $propertyTable * @param array $rows array of rows to insert/delete * @param boolean $insert * @param DatabaseBase $dbw used for writing */ protected function writePropertyTableRowUpdates(array &$propertyUseIncrements, SMWSQLStore3Table $propertyTable, array $rows, $insert, DatabaseBase $dbw) { if (empty($rows)) { //print "Nothing to " . ( $insert ? 'insert' : 'delete' ) . " for table {$propertyTable->getName()}.\n"; //DEBUG return; } //print ( $insert ? 'Inserting ' : 'Deleting ' ) . count( $rows ) . " row(s) in table {$propertyTable->getName()}.\n"; //DEBUG //print var_export( $rows, true ) . "\n"; //DEBUG if (!$propertyTable->usesIdSubject()) { // does not occur, but let's be strict throw new InvalidArgumentException('Operation not supported for tables without subject IDs.'); } if ($insert) { $dbw->insert($propertyTable->getName(), array_values($rows), "SMW::writePropertyTableRowUpdates-insert-{$propertyTable->getName()}"); } else { $condition = ''; // We build a condition that mentions s_id only once, // since it must be the same for all rows. This should // help the DBMS in selecting the rows (it would not be // easy for to detect that all tuples share one s_id). $sid = false; foreach ($rows as $row) { if ($sid === false) { $sid = $row['s_id']; // 's_id' exists for all tables with $propertyTable->usesIdSubject() } unset($row['s_id']); if ($condition != '') { $condition .= ' OR '; } $condition .= '(' . $dbw->makeList($row, LIST_AND) . ')'; } $condition = "s_id=" . $dbw->addQuotes($sid) . " AND ({$condition})"; $dbw->delete($propertyTable->getName(), array($condition), "SMW::writePropertyTableRowUpdates-delete-{$propertyTable->getName()}"); } if ($propertyTable->isFixedPropertyTable()) { $property = new SMWDIProperty($propertyTable->getFixedProperty()); $pid = $this->store->smwIds->makeSMWPropertyID($property); } foreach ($rows as $row) { if (!$propertyTable->isFixedPropertyTable()) { $pid = $row['p_id']; } if (!array_key_exists($pid, $propertyUseIncrements)) { $propertyUseIncrements[$pid] = 0; } $propertyUseIncrements[$pid] += $insert ? 1 : -1; } }
/** * Helper function to compute from and where strings for a DB query so that * only rows of the given value object match. The parameter $tableindex * counts that tables used in the query to avoid duplicate table names. The * parameter $proptable provides the SMWSQLStore3Table object that is * queried. * * @todo Maybe do something about redirects. The old code was * $oid = $this->store->smwIds->getSMWPageID($value->getDBkey(),$value->getNamespace(),$value->getInterwiki(),false); * * @param string $from * @param string $where * @param SMWSQLStore3Table $proptable * @param SMWDataItem $value * @param integer $tableindex */ protected function prepareValueQuery(&$from, &$where, $proptable, $value, $tableindex = 1) { $db = wfGetDB(DB_SLAVE); if ($value instanceof SMWDIContainer) { // recursive handling of containers $keys = array_keys($proptable->getFields($this->store)); $joinfield = "t{$tableindex}." . reset($keys); // this must be a type 'p' object $proptables = SMWSQLStore3::getPropertyTables(); $semanticData = $value->getSemanticData(); foreach ($semanticData->getProperties() as $subproperty) { $tableid = SMWSQLStore3::findPropertyTableID($subproperty); $subproptable = $proptables[$tableid]; foreach ($semanticData->getPropertyValues($subproperty) as $subvalue) { $tableindex++; if ($subproptable->idsubject) { // simply add property table to check values $from .= " INNER JOIN " . $db->tableName($subproptable->name) . " AS t{$tableindex} ON t{$tableindex}.s_id={$joinfield}"; } else { // exotic case with table that uses subject title+namespace in container object (should never happen in SMW core) $from .= " INNER JOIN " . $db->tableName('smw_ids') . " AS ids{$tableindex} ON ids{$tableindex}.smw_id={$joinfield}" . " INNER JOIN " . $db->tableName($subproptable->name) . " AS t{$tableindex} ON " . "t{$tableindex}.s_title=ids{$tableindex}.smw_title AND t{$tableindex}.s_namespace=ids{$tableindex}.smw_namespace"; } if ($subproptable->fixedproperty == false) { // the ID we get should be !=0, so no point in filtering the converse $where .= ($where ? ' AND ' : '') . "t{$tableindex}.p_id=" . $db->addQuotes($this->store->smwIds->getSMWPropertyID($subproperty)); } $this->prepareValueQuery($from, $where, $subproptable, $subvalue, $tableindex); } } } elseif (!is_null($value)) { // add conditions for given value $diHandler = $this->store->getDataItemHandlerForDIType($value->getDIType()); foreach ($diHandler->getWhereConds($value) as $fieldname => $value) { $where .= ($where ? ' AND ' : '') . "t{$tableindex}.{$fieldname}=" . $db->addQuotes($value); } } }
protected function deleteRows(array $rows, SMWSQLStore3Table $propertyTable) { $condition = ''; $db = $this->store->getConnection(); // We build a condition that mentions s_id only once, // since it must be the same for all rows. This should // help the DBMS in selecting the rows (it would not be // easy for to detect that all tuples share one s_id). $sid = false; foreach ($rows as $row) { if ($sid === false) { if (!array_key_exists('s_id', (array) $row)) { // FIXME: The assumption that s_id is present does not hold. // This return is there to prevent fatal errors, but does not fix the issue of this code being broken return; } $sid = $row['s_id']; // 's_id' exists for all tables with $propertyTable->usesIdSubject() } unset($row['s_id']); if ($condition != '') { $condition .= ' OR '; } $condition .= '(' . $db->makeList($row, LIST_AND) . ')'; } $condition = "s_id=" . $db->addQuotes($sid) . " AND ({$condition})"; $db->delete($propertyTable->getName(), array($condition), "SMW::writePropertyTableRowUpdates-delete-{$propertyTable->getName()}"); }