/**
  * 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()}");
 }