FOSSology  4.7.0-rc1
Open Source License Compliance by Open Source Software
database.cc
1 /*
2  SPDX-FileCopyrightText: © 2014-2017,2022, Siemens AG
3  Author: Daniele Fognini, Johannes Najjar
4 
5  SPDX-License-Identifier: GPL-2.0-only
6 */
7 
8 #include "database.hpp"
9 #include "identity.hpp"
10 
11 #include <iostream>
12 #include <libfossUtils.hpp>
13 
14 using namespace fo;
15 
16 #define RETURN_IF_FALSE(query) \
17  do {\
18  if (!(query)) {\
19  return false;\
20  }\
21  } while(0)
22 
27  agent_fk(0),
28  pfile_fk(0),
29  content(""),
30  hash(""),
31  type(""),
32  copy_startbyte(0),
33  copy_endbyte(0),
34  is_enabled(true)
35 {
36 };
37 
43 {
44  DbManager spawnedDbMan(dbManager.spawn());
45  return CopyrightDatabaseHandler(spawnedDbMan);
46 }
47 
56 {
57  std::string result;
58  for (size_t i = 0; i < size; ++i)
59  {
60  if (i != 0)
61  result += ", ";
62  result += in[i].name;
63  }
64  return result;
65 }
66 
76 {
77  std::string result;
78  for (size_t i = 0; i < size; ++i)
79  {
80  if (i != 0)
81  result += ", ";
82  result += in[i].name;
83  result += " ";
84  result += in[i].type;
85  result += " ";
86  result += in[i].creationFlags;
87  }
88  return result;
89 }
90 
102 {
103  int failedCounter = 0;
104  bool tablesChecked = false;
105 
107  while (!tablesChecked && failedCounter < MAX_TABLE_CREATION_RETRIES)
108  {
109  dbManager.begin();
110 
111  tablesChecked = createTableAgentFindings() && createTableClearing();
112 
113  if (tablesChecked)
114  dbManager.commit();
115  else
116  {
118  ++failedCounter;
119  if (failedCounter < MAX_TABLE_CREATION_RETRIES)
120  std::cout << "WARNING: table creation failed: trying again"
121  " (" << failedCounter << "/" << MAX_TABLE_CREATION_RETRIES << ")"
122  << std::endl;
123  }
124  }
125  if (tablesChecked && (failedCounter > 0))
126  std::cout << "NOTICE: table creation succeded on try "
127  << failedCounter << "/" << MAX_TABLE_CREATION_RETRIES
128  << std::endl;
129 
130  dbManager.ignoreWarnings(false);
131  return tablesChecked;
132 }
133 
139  {
140 #define SEQUENCE_NAME IDENTITY"_pk_seq"
141 #define COLUMN_NAME_PK IDENTITY"_pk"
142  { COLUMN_NAME_PK, "bigint", "PRIMARY KEY DEFAULT nextval('" SEQUENCE_NAME "'::regclass)"},
143  {"agent_fk", "bigint", "NOT NULL"},
144  {"pfile_fk", "bigint", "NOT NULL"},
145  {"content", "text", ""},
146  {"hash", "text", ""},
147  {"type", "text", ""}, //TODO removed constrain: "CHECK (type in ('statement', 'email', 'url'))"},
148  {"copy_startbyte", "integer", ""},
149  {"copy_endbyte", "integer", ""},
150  {"is_enabled", "boolean", "NOT NULL DEFAULT TRUE"},
151  };
152 
159 {
160  if (!dbManager.sequenceExists(SEQUENCE_NAME))
161  {
162  RETURN_IF_FALSE(dbManager.queryPrintf("CREATE SEQUENCE "
163  SEQUENCE_NAME
164  " START WITH 1"
165  " INCREMENT BY 1"
166  " NO MAXVALUE"
167  " NO MINVALUE"
168  " CACHE 1"));
169  }
170 
171  if (!dbManager.tableExists(IDENTITY))
172  {
173  size_t ncolumns = (sizeof(CopyrightDatabaseHandler::columns) / sizeof(CopyrightDatabaseHandler::ColumnDef));
174  RETURN_IF_FALSE(dbManager.queryPrintf("CREATE table %s(%s)", IDENTITY,
176  )
177  );
178  RETURN_IF_FALSE(dbManager.queryPrintf(
179  "CREATE INDEX %s_agent_fk_index"
180  " ON %s"
181  " USING BTREE (agent_fk)",
182  IDENTITY, IDENTITY
183  ));
184 
185  RETURN_IF_FALSE(dbManager.queryPrintf(
186  "CREATE INDEX %s_hash_index"
187  " ON %s"
188  " USING BTREE (hash)",
189  IDENTITY, IDENTITY
190  ));
191 
192  RETURN_IF_FALSE(dbManager.queryPrintf(
193  "CREATE INDEX %s_pfile_fk_index"
194  " ON %s"
195  " USING BTREE (pfile_fk)",
196  IDENTITY, IDENTITY
197  ));
198 
199  RETURN_IF_FALSE(dbManager.queryPrintf(
200  "ALTER TABLE ONLY %s"
201  " ADD CONSTRAINT agent_fk"
202  " FOREIGN KEY (agent_fk)"
203  " REFERENCES agent(agent_pk) ON DELETE CASCADE",
204  IDENTITY
205  ));
206 
207  RETURN_IF_FALSE(dbManager.queryPrintf(
208  "ALTER TABLE ONLY %s"
209  " ADD CONSTRAINT pfile_fk"
210  " FOREIGN KEY (pfile_fk)"
211  " REFERENCES pfile(pfile_pk) ON DELETE CASCADE",
212  IDENTITY
213  ));
214  }
215  return true;
216 }
217 
222 #define SEQUENCE_NAMEClearing IDENTITY"_decision_pk_seq"
223  {IDENTITY"_decision_pk", "bigint", "PRIMARY KEY DEFAULT nextval('" SEQUENCE_NAMEClearing "'::regclass)"},
224  {"user_fk", "bigint", "NOT NULL"},
225  {"pfile_fk", "bigint", "NOT NULL"},
226  {"clearing_decision_type_fk", "bigint", "NOT NULL"},
227  {"description", "text", ""},
228  {"textFinding", "text", ""},
229  {"comment", "text", ""},
230  {"is_enabled", "boolean", "NOT NULL DEFAULT TRUE"}
231 };
232 
239 {
240  #define CLEARING_TABLE IDENTITY "_decision"
241 
242  if (!dbManager.sequenceExists(SEQUENCE_NAMEClearing))
243  {
244  RETURN_IF_FALSE(dbManager.queryPrintf("CREATE SEQUENCE "
245  SEQUENCE_NAMEClearing
246  " START WITH 1"
247  " INCREMENT BY 1"
248  " NO MAXVALUE"
249  " NO MINVALUE"
250  " CACHE 1"));
251  }
252 
253  if (!dbManager.tableExists(CLEARING_TABLE))
254  {
256  RETURN_IF_FALSE(dbManager.queryPrintf("CREATE table %s(%s)", CLEARING_TABLE,
258 
259  RETURN_IF_FALSE(dbManager.queryPrintf(
260  "CREATE INDEX %s_pfile_fk_index"
261  " ON %s"
262  " USING BTREE (pfile_fk)",
263  CLEARING_TABLE, CLEARING_TABLE
264  ));
265 
266  RETURN_IF_FALSE(dbManager.queryPrintf(
267  "CREATE INDEX %s_user_fk_index"
268  " ON %s"
269  " USING BTREE (user_fk)",
270  CLEARING_TABLE, CLEARING_TABLE
271  ));
272 
273  RETURN_IF_FALSE(dbManager.queryPrintf(
274  "CREATE INDEX %s_clearing_decision_type_fk_index"
275  " ON %s"
276  " USING BTREE (clearing_decision_type_fk)",
277  CLEARING_TABLE, CLEARING_TABLE
278  ));
279 
280  RETURN_IF_FALSE(dbManager.queryPrintf(
281  "ALTER TABLE ONLY %s"
282  " ADD CONSTRAINT user_fk"
283  " FOREIGN KEY (user_fk)"
284  " REFERENCES users(user_pk) ON DELETE CASCADE",
285  CLEARING_TABLE
286  ));
287 
288  RETURN_IF_FALSE(dbManager.queryPrintf(
289  "ALTER TABLE ONLY %s"
290  " ADD CONSTRAINT pfile_fk"
291  " FOREIGN KEY (pfile_fk)"
292  " REFERENCES pfile(pfile_pk) ON DELETE CASCADE",
293  CLEARING_TABLE
294  ));
295  }
296 
297  return true;
298 }
299 
307 std::vector<unsigned long> CopyrightDatabaseHandler::queryFileIdsForUpload(int agentId, int uploadId, bool ignoreFilesWithMimeType)
308 {
309  std::string uploadTreeTableName = queryUploadTreeTableName(uploadId);
310  fo_dbManager_PreparedStatement* preparedStatement;
311  std::string sql = "SELECT pfile_pk"
312  " FROM ("
313  " SELECT distinct(pfile_fk) AS PF"
314  " FROM " + uploadTreeTableName +
315  " WHERE upload_fk = $1 and (ufile_mode&x'3C000000'::int)=0"
316  " ) AS SS "
317  "LEFT OUTER JOIN " IDENTITY " ON (PF = pfile_fk AND agent_fk = $2) "
318 #ifdef IDENTITY_COPYRIGHT
319  "LEFT OUTER JOIN author AS au ON (PF = au.pfile_fk AND au.agent_fk = $2) "
320 #endif
321  "INNER JOIN pfile ON (PF = pfile_pk) "
322 #ifdef IDENTITY_COPYRIGHT
323  "WHERE copyright.copyright_pk IS NULL AND au.author_pk IS NULL"
324 #else
325  "WHERE (" IDENTITY "_pk IS NULL OR agent_fk <> $2)"
326 #endif
327  ;
328  std::string statementName = "queryFileIdsForUpload:" IDENTITY "Agent" + uploadTreeTableName;
329  if (ignoreFilesWithMimeType)
330  {
331  sql = sql + " AND (pfile_mimetypefk NOT IN ( "
332  "SELECT mimetype_pk FROM mimetype WHERE mimetype_name=ANY(string_to_array(( "
333  "SELECT conf_value FROM sysconfig WHERE variablename='SkipFiles'),','))));";
334  statementName = statementName + "withMimetype";
335  }
336  preparedStatement =
337  fo_dbManager_PrepareStamement(dbManager.getStruct_dbManager(),
338  statementName.c_str(),
339  sql.c_str(),
340  int, int);
341  QueryResult queryResult = dbManager.execPrepared(preparedStatement,
342  uploadId, agentId);
343 
344  return queryResult.getSimpleResults<unsigned long>(0, fo::stringToUnsignedLong);
345 
346 }
347 
355 {
356  std::string tableName = IDENTITY;
357 
358  if("author" == entry.type ||
359  "email" == entry.type ||
360  "url" == entry.type){
361  tableName = "author";
362  }
363 
364  return dbManager.execPrepared(
365  fo_dbManager_PrepareStamement(
367  ("insertInDatabaseFor" + tableName).c_str(),
368  ("INSERT INTO "+ tableName +
369  "(agent_fk, pfile_fk, content, hash, type, copy_startbyte, copy_endbyte)" +
370  " VALUES($1,$2,$3,md5($3),$4,$5,$6)").c_str(),
371  long, long, char*, char*, int, int
372  ),
373  entry.agent_fk, entry.pfile_fk,
374  entry.content.c_str(),
375  entry.type.c_str(),
376  entry.copy_startbyte, entry.copy_endbyte
377  );
378 }
379 
388  int uploadId, const std::string& uploadTreeTableName) const
389 {
390  // The query inserts one deactivated finding per uploadtree node for the given upload, for the given finding.
391  std::string sql =
392  "INSERT INTO copyright_event (upload_fk, copyright_fk, uploadtree_fk) "
393  "SELECT ut.upload_fk, cp.copyright_pk, ut.uploadtree_pk "
394  "FROM copyright AS cp "
395  "INNER JOIN " + uploadTreeTableName + " AS ut ON cp.pfile_fk = ut.pfile_fk "
396  "WHERE cp.hash = md5($1) AND cp.agent_fk = $2 "
397  " AND cp.pfile_fk = $3 AND ut.upload_fk = $4";
398 
399  return dbManager.execPrepared(
400  fo_dbManager_PrepareStamement(
402  ("insertDeactivatedEventsFor" + uploadTreeTableName).c_str(),
403  sql.c_str(),
404  char*, long, long, int
405  ),
406  entry.content.c_str(),
407  entry.agent_fk,
408  entry.pfile_fk,
409  uploadId
410  );
411 }
412 
417  AgentDatabaseHandler(manager)
418 {
419 
420 }
Manages database related requests for agent.
Definition: database.hpp:54
std::vector< unsigned long > queryFileIdsForUpload(int agentId, int uploadId, bool ignoreFilesWithMimeType)
Get the list of pfile ids on which the given agent has no findings for a given upload.
Definition: database.cc:307
static const ColumnDef columns[]
Columns required by agent in database.
Definition: database.hpp:80
bool createTableAgentFindings() const
Create table to store agent find data.
Definition: database.cc:158
bool insertInDatabase(DatabaseEntry &entry) const
Insert a finding in database.
Definition: database.cc:354
static const ColumnDef columnsDecision[]
Columns required to store user decisions in database.
Definition: database.hpp:81
std::string getColumnListString(const ColumnDef in[], size_t size) const
Given a list of ColumnDef, return a comma separated list of column names.
Definition: database.cc:55
CopyrightDatabaseHandler(fo::DbManager manager)
Constructor to initialize database handler.
Definition: database.cc:416
CopyrightDatabaseHandler spawn() const
Spawn/fork a new database handler and return it.
Definition: database.cc:42
bool insertDeactivatedEvents(const DatabaseEntry &entry, int uploadId, const std::string &uploadTreeTableName) const
Insert one deactivated finding per uploadtree node for a given upload, for a given finding.
Definition: database.cc:387
bool createTables() const
Create tables required by agent.
Definition: database.cc:101
std::string getColumnCreationString(const ColumnDef in[], size_t size) const
Return a comma delimited string with column elements separated by space. The string is used for datab...
Definition: database.cc:75
bool createTableClearing() const
Create table to store user decisions.
Definition: database.cc:238
Maps agent data to database schema.
Definition: database.hpp:25
int copy_startbyte
Definition: database.hpp:44
std::string content
Definition: database.hpp:31
std::string type
Type of statement found.
Definition: database.hpp:43
int copy_endbyte
Definition: database.hpp:45
DatabaseEntry()
Default constructor for DatabaseEntry.
Definition: database.cc:26
Database handler for agents.
std::string queryUploadTreeTableName(int uploadId)
Get the upload tree table name for a given upload id.
DbManager dbManager
DbManager to use.
DB wrapper for agents.
QueryResult execPrepared(fo_dbManager_PreparedStatement *stmt,...) const
Execute a prepared statement with new parameters.
bool tableExists(const char *tableName) const
void ignoreWarnings(bool) const
QueryResult queryPrintf(const char *queryFormat,...) const
Execute a query in printf format.
bool sequenceExists(const char *name) const
fo_dbManager * getStruct_dbManager() const
DbManager spawn() const
Wrapper for DB result.
std::vector< T > getSimpleResults(int columnN, T(functionP)(const char *)) const
Get vector of a single column from query result.
General utility functions for CPP.
fo namespace holds the FOSSology library functions.
unsigned long stringToUnsignedLong(const char *string)
Definition: libfossUtils.cc:20
Holds the column related data for table creation.
Definition: database.hpp:74