/** * 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 */ protected function writePropertyTableRowUpdates(array &$propertyUseIncrements, SMWSQLStore3Table $propertyTable, array $rows, $insert) { if (empty($rows)) { return; } if (!$propertyTable->usesIdSubject()) { // does not occur, but let's be strict throw new InvalidArgumentException('Operation not supported for tables without subject IDs.'); } $db = $this->store->getConnection(); if ($insert) { $db->insert($propertyTable->getName(), $rows, "SMW::writePropertyTableRowUpdates-insert-{$propertyTable->getName()}"); } else { $this->deleteRows($rows, $propertyTable); } if ($propertyTable->isFixedPropertyTable()) { $property = new SMWDIProperty($propertyTable->getFixedProperty()); $pid = $this->store->getObjectIds()->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; } }
/** * 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 for reading all data for from a given property table * (specified by an SMWSQLStore3Table object), based on certain * restrictions. The function can filter data based on the subject (1) * or on the property it belongs to (2) -- but one of those must be * done. The Boolean $issubject is true for (1) and false for (2). * * In case (1), the first two parameters are taken to refer to a * subject; in case (2) they are taken to refer to a property. In any * case, the retrieval is limited to the specified $proptable. The * parameters are an internal $id (of a subject or property), and an * $object (being an SMWDIWikiPage or SMWDIProperty). Moreover, when * filtering by property, it is assumed that the given $proptable * belongs to the property: if it is a table with fixed property, it * will not be checked that this is the same property as the one that * was given in $object. * * In case (1), the result in general is an array of pairs (arrays of * size 2) consisting of a property key (string), and DB keys (array if * many, string if one) from which a datvalue object for this value can * be built. It is possible that some of the DB keys are based on * internal objects; these will be represented by similar result arrays * of (recursive calls of) fetchSemanticData(). * * In case (2), the result is simply an array of DB keys (array) * without the property keys. Container objects will be encoded with * nested arrays like in case (1). * * @todo Maybe share DB handler; asking for it seems to take quite some * time and we do not want to change it in one call. * * @since 1.8 * @param integer $id * @param SMWDataItem $object * @param SMWSQLStore3Table $proptable * @param boolean $issubject * @param SMWRequestOptions $requestoptions * * @return array */ protected function fetchSemanticData($id, SMWDataItem $object = null, SMWSQLStore3Table $proptable, $issubject = true, SMWRequestOptions $requestoptions = null) { // stop if there is not enough data: // properties always need to be given as object, // subjects at least if !$proptable->idsubject if ($id == 0 || is_null($object) && (!$issubject || !$proptable->usesIdSubject())) { return array(); } wfProfileIn("SMWSQLStore3::fetchSemanticData-" . $proptable->getName() . " (SMW)"); $result = array(); $db = wfGetDB(DB_SLAVE, 'smw'); $diHandler = $this->store->getDataItemHandlerForDIType($proptable->getDiType()); // *** First build $from, $select, and $where for the DB query ***// $from = $db->tableName($proptable->getName()); // always use actual table $select = ''; $where = ''; if ($issubject) { // restrict subject, select property $where .= $proptable->usesIdSubject() ? 's_id=' . $db->addQuotes($id) : 's_title=' . $db->addQuotes($object->getDBkey()) . ' AND s_namespace=' . $db->addQuotes($object->getNamespace()); if (!$proptable->isFixedPropertyTable()) { // select property name $from .= ' INNER JOIN ' . $db->tableName(SMWSql3SmwIds::tableName) . ' AS p ON p_id=p.smw_id'; $select .= 'p.smw_title as prop'; } // else: fixed property, no select needed } elseif (!$proptable->isFixedPropertyTable()) { // restrict property only $where .= 'p_id=' . $db->addQuotes($id); } $valuecount = 0; // Don't use DISTINCT for value of one subject: $usedistinct = !$issubject; $valueField = $diHandler->getIndexField(); $labelField = $diHandler->getLabelField(); $fields = $diHandler->getFetchFields(); foreach ($fields as $fieldname => $typeid) { // select object column(s) if ($typeid == 'p') { // get data from ID table $from .= ' INNER JOIN ' . $db->tableName(SMWSql3SmwIds::tableName) . " AS o{$valuecount} ON {$fieldname}=o{$valuecount}.smw_id"; $select .= ($select !== '' ? ',' : '') . "{$fieldname} AS id{$valuecount}" . ",o{$valuecount}.smw_title AS v{$valuecount}" . ",o{$valuecount}.smw_namespace AS v" . ($valuecount + 1) . ",o{$valuecount}.smw_iw AS v" . ($valuecount + 2) . ",o{$valuecount}.smw_sortkey AS v" . ($valuecount + 3) . ",o{$valuecount}.smw_subobject AS v" . ($valuecount + 4); if ($valueField == $fieldname) { $valueField = "o{$valuecount}.smw_sortkey"; } if ($labelField == $fieldname) { $labelField = "o{$valuecount}.smw_sortkey"; } $valuecount += 4; } else { $select .= ($select !== '' ? ',' : '') . "{$fieldname} AS v{$valuecount}"; } $valuecount += 1; } if (!$issubject) { // Apply sorting/string matching; only with given property $where .= $this->store->getSQLConditions($requestoptions, $valueField, $labelField, $where !== ''); } else { $valueField = ''; } // *** Now execute the query and read the results ***// $res = $db->select($from, $select, $where, 'SMW::getSemanticData', $usedistinct ? $this->store->getSQLOptions($requestoptions, $valueField) + array('DISTINCT') : $this->store->getSQLOptions($requestoptions, $valueField)); foreach ($res as $row) { if ($issubject) { // use joined or predefined property name $propertykey = $proptable->isFixedPropertyTable() ? $proptable->getFixedProperty() : $row->prop; } // Use enclosing array only for results with many values: if ($valuecount > 1) { $valuekeys = array(); for ($i = 0; $i < $valuecount; $i += 1) { // read the value fields from the current row $fieldname = "v{$i}"; $valuekeys[] = $row->{$fieldname}; } } else { $valuekeys = $row->v0; } // Filter out any accidentally retrieved internal things (interwiki starts with ":"): if ($valuecount < 3 || implode('', $fields) != 'p' || $valuekeys[2] === '' || $valuekeys[2][0] != ':') { $result[] = $issubject ? array($propertykey, $valuekeys) : $valuekeys; } } $db->freeResult($res); wfProfileOut("SMWSQLStore3::fetchSemanticData-" . $proptable->getName() . " (SMW)"); return $result; }