FOSSology  3.2.0rc1
Open Source License Compliance by Open Source Software
UploadTreeProxy.php
1 <?php
2 /*
3 Copyright (C) 2014-2015, Siemens AG
4 
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 version 2 as published by the Free Software Foundation.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18 
19 namespace Fossology\Lib\Proxy;
20 
26 
28 {
29  const OPT_SKIP_THESE = 'skipThese';
30  const OPT_ITEM_FILTER = 'ut.filter';
31  const OPT_GROUP_ID = 'groupId';
32  const OPT_REALPARENT = 'realParent';
33  const OPT_RANGE = 'lft,rgt';
34  const OPT_EXT = 'ext';
35  const OPT_HEAD = 'head';
36  const OPT_AGENT_SET = 'agentArray';
37  const OPT_SCAN_REF = 'scanRef';
38  const OPT_CONCLUDE_REF = 'conRef';
39  const OPT_SKIP_ALREADY_CLEARED = 'alreadyCleared';
40 
42  private $uploadTreeTableName;
44  private $uploadId;
46  private $params = array();
47 
53  public function __construct($uploadId, $options, $uploadTreeTableName, $uploadTreeViewName=null)
54  {
55  $this->uploadId = $uploadId;
56  $this->uploadTreeTableName = $uploadTreeTableName;
57  $dbViewName = $uploadTreeViewName ?: 'UploadTreeView'.(isset($this->dbViewName) ?: '');
58  $dbViewQuery = $this->createUploadTreeViewQuery($options, $uploadTreeTableName);
59  parent::__construct($dbViewQuery, $dbViewName);
60  }
61 
65  public function getUploadTreeTableName()
66  {
67  return $this->uploadTreeTableName;
68  }
69 
75  private function createUploadTreeViewQuery($options, $uploadTreeTableName)
76  {
77  if (empty($options)) {
78  return self::getDefaultUploadTreeView($this->uploadId, $uploadTreeTableName);
79  }
80 
81  $filter = '';
82  $this->dbViewName = '';
83 
84  if (array_key_exists(self::OPT_REALPARENT, $options)) {
85  $filter .= " AND ut.ufile_mode & (1<<28) = 0 AND ut.realparent=".$this->addParamAndGetExpr('realParent',$options[self::OPT_REALPARENT]);
86  $this->dbViewName .= "_".self::OPT_REALPARENT;
87  } elseif (array_key_exists(self::OPT_RANGE,$options)) {
88  $itemBounds = $options[self::OPT_RANGE];
89  $filter .= " AND ut.ufile_mode & (3<<28) = 0 AND (ut.lft BETWEEN ".$this->addParamAndGetExpr('lft',$itemBounds->getLeft()).
90  " AND ".$this->addParamAndGetExpr('rgt',$itemBounds->getRight()).")";
91  $this->dbViewName .= "_".self::OPT_RANGE;
92  }
93 
94  if (array_key_exists(self::OPT_EXT, $options)) {
95  $filter .= " AND ufile_name ILIKE ".$this->addParamAndGetExpr('patternExt','%.'.$options[self::OPT_EXT]);
96  $this->dbViewName .= "_".self::OPT_EXT;
97  }
98 
99  if (array_key_exists(self::OPT_HEAD, $options)) {
100  $filter .= " AND ufile_name ILIKE ".$this->addParamAndGetExpr('patternHead',$options[self::OPT_HEAD].'%');
101  $this->dbViewName .= "_".self::OPT_HEAD;
102  }
103 
104  if (array_key_exists(self::OPT_SCAN_REF,$options)) {
105  $filter .= $this->addScanFilter($options);
106  }
107 
108  if (array_key_exists(self::OPT_CONCLUDE_REF, $options) && array_key_exists(self::OPT_GROUP_ID, $options)) {
109  $filter .= $this->addConFilter($options);
110  }
111 
112  if (array_key_exists(self::OPT_SKIP_ALREADY_CLEARED, $options) && array_key_exists(self::OPT_GROUP_ID, $options)
113  && array_key_exists(self::OPT_AGENT_SET, $options)) {
114  $agentIdSet = '{' . implode(',', array_values($options[self::OPT_AGENT_SET])) . '}';
115  $agentFilter = " AND agent_fk=ANY(".$this->addParamAndGetExpr('agentIdSet', $agentIdSet).")";
116  $this->dbViewName .= "_".self::OPT_SKIP_ALREADY_CLEARED;
117  $groupAlias = $this->addParamAndGetExpr('groupId', $options[self::OPT_GROUP_ID]);
118  if (array_key_exists(self::OPT_RANGE, $options)) {
119  $filter .= ' AND '.self::getQueryCondition(self::OPT_SKIP_ALREADY_CLEARED, $groupAlias, $agentFilter);
120  } elseif (array_key_exists(self::OPT_SKIP_ALREADY_CLEARED, $options) && array_key_exists(self::OPT_GROUP_ID, $options)
121  && array_key_exists(self::OPT_AGENT_SET, $options) && array_key_exists(self::OPT_REALPARENT, $options)) {
122  $childFilter = self::getQueryCondition(self::OPT_SKIP_ALREADY_CLEARED, $groupAlias, $agentFilter);
123  $filter .= ' AND EXISTS(SELECT * FROM '.$this->uploadTreeTableName.' utc WHERE utc.upload_fk='.$this->uploadId
124  . ' AND (utc.lft BETWEEN ut.lft AND ut.rgt) AND utc.ufile_mode&(3<<28)=0 AND '
125  .preg_replace('/([a-z])ut\./', '\1utc.', $childFilter).')';
126  }
127  }
128 
129  if (array_key_exists(self::OPT_ITEM_FILTER, $options)) {
130  $filter .= ' '.$options[self::OPT_ITEM_FILTER];
131  $this->dbViewName .= "_".md5($options[self::OPT_ITEM_FILTER]);
132  }
133  $options[self::OPT_ITEM_FILTER] = $filter;
134  return self::getUploadTreeView($this->uploadId, $options, $uploadTreeTableName);
135  }
136 
137  private function addConFilter($options)
138  {
139  $filter = '';
140  if (array_key_exists(self::OPT_REALPARENT, $options)) {
141  $filter .=" AND EXISTS(SELECT * FROM ".$this->uploadTreeTableName." usub"
142  . " WHERE (usub.lft BETWEEN ut.lft AND ut.rgt) AND upload_fk=".$this->uploadId
143  . " AND ".$this->subqueryConcludeRefMatches('usub', $options) . ")";
144  $this->dbViewName .= "_".self::OPT_CONCLUDE_REF;
145  } elseif (array_key_exists(self::OPT_RANGE, $options)) {
146  $filter.= " AND ".$this->subqueryConcludeRefMatches('ut', $options);
147  $this->dbViewName .= "_".self::OPT_CONCLUDE_REF;
148  }
149  return $filter;
150  }
151 
152  private function addScanFilter($options)
153  {
154  $this->dbViewName .= "_".self::OPT_SCAN_REF;
155  if (array_key_exists(self::OPT_AGENT_SET, $options)) {
156  $this->dbViewName .= "_".self::OPT_AGENT_SET;
157  }
158  if (array_key_exists(self::OPT_REALPARENT, $options)) {
159  return " AND EXISTS(SELECT * FROM ".$this->uploadTreeTableName." usub, "
160  . $this->subqueryLicenseFileMatchWhere($options)
161  . " usub.pfile_fk=license_file.pfile_fk"
162  . " AND (usub.lft BETWEEN ut.lft AND ut.rgt) AND upload_fk=".$this->uploadId.")";
163  }
164  if (array_key_exists(self::OPT_RANGE, $options)) {
165  return " AND EXISTS(SELECT * FROM " . $this->subqueryLicenseFileMatchWhere($options)
166  . " ut.pfile_fk=license_file.pfile_fk)";
167  }
168  }
169 
170  private function subqueryLicenseFileMatchWhere($options)
171  {
172  $filter = " license_file LEFT JOIN license_map ON license_file.rf_fk=license_map.rf_fk"
173  . " AND usage=".LicenseMap::CONCLUSION." WHERE";
174  if (array_key_exists(self::OPT_AGENT_SET, $options)) {
175  $agentIdSet = '{' . implode(',', array_values($options[self::OPT_AGENT_SET])) . '}';
176  $filter .= " agent_fk=ANY(".$this->addParamAndGetExpr('agentIdSet', $agentIdSet).") AND";
177  }
178  $rfId = $this->addParamAndGetExpr('scanRef', $options[self::OPT_SCAN_REF]);
179  return $filter . " (license_file.rf_fk=$rfId OR rf_parent=$rfId) AND ";
180  }
181 
182  private function subqueryConcludeRefMatches($itemTable,$options)
183  {
184  return "NOT(SELECT (removed OR cd.decision_type=".DecisionTypes::IRRELEVANT.") excluded"
185  . " FROM clearing_decision cd, clearing_decision_event cde, clearing_event ce"
186  . " WHERE ((cd.group_fk=".$this->addParamAndGetExpr('groupId', $options[self::OPT_GROUP_ID])
187  . " AND cd.uploadtree_fk=$itemTable.uploadtree_pk)"
188  . " OR (cd.scope=".DecisionScopes::REPO." AND cd.pfile_fk=$itemTable.pfile_fk))"
189  . " AND clearing_decision_pk=clearing_decision_fk"
190  . " AND clearing_event_fk=clearing_event_pk"
191  . " AND rf_fk=".$this->addParamAndGetExpr('conId',$options[self::OPT_CONCLUDE_REF])
192  . " AND cd.decision_type!=".DecisionTypes::WIP
193  . " ORDER BY CASE cd.scope WHEN ".DecisionScopes::REPO." THEN 1 ELSE 0 END,cd.date_added DESC LIMIT 1)";
194  }
195 
202  private static function getDefaultUploadTreeView($uploadId, $uploadTreeTableName, $additionalCondition='')
203  {
204  $condition = "";
205  if ('uploadtree' === $uploadTreeTableName || 'uploadtree_a' == $uploadTreeTableName) {
206  $condition = " WHERE ut.upload_fk=$uploadId $additionalCondition";
207  } elseif ($additionalCondition) {
208  $condition = " WHERE 1=1 $additionalCondition";
209  }
210  $uploadTreeView = "SELECT * FROM $uploadTreeTableName ut $condition";
211  return $uploadTreeView;
212  }
213 
220  private static function getUploadTreeView($uploadId, $options, $uploadTreeTableName)
221  {
222  $additionalCondition = array_key_exists(self::OPT_ITEM_FILTER, $options) ? $options[self::OPT_ITEM_FILTER] : '';
223  $skipThese = array_key_exists(self::OPT_SKIP_THESE,$options) ? $options[self::OPT_SKIP_THESE] : 'none';
224  $groupId = array_key_exists(self::OPT_GROUP_ID, $options) ? $options[self::OPT_GROUP_ID] : null;
225  $agentFilter = self::getAgentFilter($options, $uploadId);
226 
227  switch ($skipThese) {
228  case "noLicense":
229  case self::OPT_SKIP_ALREADY_CLEARED:
230  case "noCopyright":
231  case "noEcc":
232 
233  $queryCondition = self::getQueryCondition($skipThese, $groupId, $agentFilter)." ".$additionalCondition;
234  if ('uploadtree' === $uploadTreeTableName || 'uploadtree_a' == $uploadTreeTableName) {
235  $queryCondition = "ut.upload_fk=$uploadId AND ($queryCondition)";
236  }
237  $uploadTreeView = "SELECT * FROM $uploadTreeTableName ut WHERE $queryCondition";
238  break;
239 
240  case "none":
241  default:
242  $uploadTreeView = self::getDefaultUploadTreeView($uploadId, $uploadTreeTableName, $additionalCondition);
243  }
244 
245  return $uploadTreeView;
246  }
247 
248  private static function getAgentFilter($options,$uploadId=0)
249  {
250  if (!array_key_exists(self::OPT_SKIP_THESE, $options)) {
251  return '';
252  }
253  $skipThese = $options[self::OPT_SKIP_THESE];
254  if ($skipThese != "noLicense" && $skipThese != self::OPT_SKIP_ALREADY_CLEARED) {
255  return '';
256  }
257 
258  if (array_key_exists(self::OPT_AGENT_SET, $options)) {
259  $agentIds = 'array[' . implode(',',$options[self::OPT_AGENT_SET]) . ']';
260  $agentFilter = " AND lf.agent_fk=ANY($agentIds)";
261  } else {
262  $scanJobProxy = new ScanJobProxy($GLOBALS['container']->get('dao.agent'),$uploadId);
263  $scanJobProxy->createAgentStatus(array_keys(AgentRef::AGENT_LIST));
264  $latestAgentIds = $scanJobProxy->getLatestSuccessfulAgentIds();
265  $agentFilter = $latestAgentIds ? " AND lf.agent_fk=ANY(array[".implode(',',$latestAgentIds)."])" : "AND 0=1";
266  }
267  return $agentFilter;
268  }
269 
274  private static function getQueryCondition($skipThese, $groupId = null, $agentFilter='')
275  {
276  $conditionQueryHasLicense = "(EXISTS (SELECT 1 FROM license_ref lr INNER JOIN license_file lf"
277  . " ON lf.rf_fk=lr.rf_pk WHERE rf_shortname NOT IN ('No_license_found', 'Void') AND lf.pfile_fk = ut.pfile_fk $agentFilter LIMIT 1)
278  OR EXISTS (SELECT 1 FROM clearing_decision AS cd WHERE cd.group_fk = $groupId AND ut.uploadtree_pk = cd.uploadtree_fk LIMIT 1))";
279 
280  switch ($skipThese) {
281  case "noLicense":
282  return $conditionQueryHasLicense;
283  case self::OPT_SKIP_ALREADY_CLEARED:
284  $decisionQuery = "
285 SELECT decision_type, ROW_NUMBER() OVER (
286  PARTITION BY pfile_fk ORDER BY clearing_decision_pk
287 ) AS rnum
288 FROM (
289  SELECT * FROM clearing_decision cd
290  WHERE (
291  ut.uploadtree_pk = cd.uploadtree_fk AND cd.group_fk = $groupId
292  ) OR (
293  cd.pfile_fk = ut.pfile_fk AND cd.scope=".DecisionScopes::REPO."
294  )
295 ) AS filtered_clearing_decision ORDER BY rnum DESC LIMIT 1";
296  return " $conditionQueryHasLicense
297  AND NOT EXISTS (SELECT 1 FROM ($decisionQuery) as latest_decision WHERE latest_decision.decision_type IN (".DecisionTypes::IRRELEVANT.",".DecisionTypes::IDENTIFIED.",".DecisionTypes::DO_NOT_USE.") )";
298  case "noCopyright":
299  return "EXISTS (SELECT copyright_pk FROM copyright cp WHERE cp.pfile_fk=ut.pfile_fk and cp.hash is not null )";
300  case "noEcc":
301  return "EXISTS (SELECT ecc_pk FROM ecc cp WHERE cp.pfile_fk=ut.pfile_fk and cp.hash is not null )";
302  }
303  }
304 
311  public function countMaskedNonArtifactChildren($parent)
312  {
313  $dbManager = $GLOBALS['container']->get('db.manager');
314  $params = $this->params;
315  if (array_key_exists('uploadId', $params)) {
316  $uploadExpr = '$'.(1+array_search('uploadId', array_keys($params)));
317  } else {
318  $params[] = $this->uploadId;
319  $uploadExpr = '$'.count($params);
320  }
321  $params[] = $parent;
322  $parentExpr = '$'.count($params);
323 
324  $sql = "SELECT count(*) cnt, u.uploadtree_pk, u.ufile_mode FROM ".$this->uploadTreeTableName." u, "
325  . $this->getDbViewName() ." v where u.upload_fk=$uploadExpr"
326  . " AND v.lft BETWEEN u.lft and u.rgt and u.parent=$parentExpr GROUP BY u.uploadtree_pk, u.ufile_mode";
327  $stmt = __METHOD__.'.'.$this->getDbViewName();
328  if (!$this->materialized) {
329  $sql = $this->asCTE().' '.$sql;
330  $stmt .= '.cte';
331  }
332  $dbManager->prepare($stmt,$sql);
333  $res = $dbManager->execute($stmt,$params);
334  $children = array();
335  $artifactContainers = array();
336  while ($row=$dbManager->fetchArray($res)) {
337  $children[$row['uploadtree_pk']] = $row['cnt'];
338  if (($row['ufile_mode'] & (3<<28)) == (3<<28)) {
339  $artifactContainers[] = $row['uploadtree_pk'];
340  }
341  }
342  $dbManager->freeResult($res);
343  foreach ($artifactContainers as $ac) {
344  foreach ($this->countMaskedNonArtifactChildren($ac) as $utid => $cnt) {
345  $children[$utid] = $cnt;
346  }
347  }
348  return $children;
349  }
350 
355  public function getNonArtifactDescendants(ItemTreeBounds $itemTreeBounds)
356  {
357  $uploadExpr = '$'.(count($this->params)+1);
358  $lftExpr = '$'.(count($this->params)+2);
359  $rgtExpr = '$'.(count($this->params)+3);
360  $dbManager = $GLOBALS['container']->get('db.manager');
361  $sql = "SELECT u.uploadtree_pk FROM ".$this->getDbViewName()." u "
362  . "WHERE u.upload_fk=$uploadExpr AND (u.lft BETWEEN $lftExpr AND $rgtExpr) AND u.ufile_mode & (3<<28) = 0";
363  $stmt = __METHOD__.'.'.$this->getDbViewName();
364  if (!$this->materialized) {
365  $sql = $this->asCTE().' '.$sql;
366  $stmt .= '.cte';
367  }
368  $dbManager->prepare($stmt,$sql);
369  $params = array_merge($this->params,
370  array($itemTreeBounds->getUploadId(),$itemTreeBounds->getLeft(),$itemTreeBounds->getRight()));
371  $res = $dbManager->execute($stmt,$params);
372  $descendants = array();
373  while ($row = $dbManager->fetchArray($res)) {
374  $descendants[$row['uploadtree_pk']] = 1;
375  }
376  $dbManager->freeResult($res);
377  return $descendants;
378  }
379 
383  public function count()
384  {
385  global $container;
386  $dbManager = $container->get('db.manager');
387  if ($this->materialized) {
388  $sql = "SELECT count(*) FROM $this->dbViewName";
389  } else {
390  $sql = "SELECT count(*) FROM ($this->dbViewQuery) $this->dbViewName";
391  }
392  $summary = $dbManager->getSingleRow($sql,$this->params,$this->dbViewName);
393  return $summary['count'];
394  }
395 
396  private function addParamAndGetExpr($key,$value)
397  {
398  if (array_key_exists($key, $this->params)) {
399  return '$' . (1 + array_search($key, array_keys($this->params)));
400  }
401 
402  $this->params[] = $value;
403  return '$'.count($this->params);
404  }
405 
406  public function getParams()
407  {
408  return $this->params;
409  }
410 }
static getQueryCondition($skipThese, $groupId=null, $agentFilter='')
__construct($uploadId, $options, $uploadTreeTableName, $uploadTreeViewName=null)
createUploadTreeViewQuery($options, $uploadTreeTableName)
static getDefaultUploadTreeView($uploadId, $uploadTreeTableName, $additionalCondition='')
countMaskedNonArtifactChildren($parent)
count elements childrenwise (or grandchildrenwise if child is artifact)
getNonArtifactDescendants(ItemTreeBounds $itemTreeBounds)
asCTE()
Common Table Expressions.
Definition: DbViewProxy.php:80
static getUploadTreeView($uploadId, $options, $uploadTreeTableName)