FOSSology  4.7.1
Open Source License Compliance by Open Source Software
database.c
1 /*
2  Author: Daniele Fognini, Andreas Wuerl
3  SPDX-FileCopyrightText: © 2013-2017, 2021 Siemens AG
4  SPDX-FileCopyrightText: © Fossology contributors
5 
6  SPDX-License-Identifier: GPL-2.0-only
7 */
8 
9 #define _GNU_SOURCE
10 #include <stdio.h>
11 
12 #include "database.h"
13 
14 #define LICENSE_REF_TABLE "ONLY license_ref"
15 
16 PGresult* queryFileIdsForUploadAndLimits(fo_dbManager* dbManager, int uploadId,
17  long left, long right, long groupId,
18  bool ignoreIrre, bool scanFindings) {
19  char* tablename = getUploadTreeTableName(dbManager, uploadId);
20  gchar* stmt;
21  gchar* sql;
22  PGresult* result;
23 
24  char* distinctPfile = "SELECT DISTINCT pfile_fk FROM %s"
25  " WHERE upload_fk = $1 AND (ufile_mode&x'3C000000'::int) = 0 "
26  " AND (lft BETWEEN $2 AND $3) AND pfile_fk != 0";
27  char* distinctPfileNoDec = "SELECT DISTINCT pfile_fk FROM ("
28  "SELECT distinct ON(ut.uploadtree_pk, ut.pfile_fk, scopesort) ut.pfile_fk pfile_fk, ut.uploadtree_pk, decision_type,"
29  " CASE cd.scope WHEN 1 THEN 1 ELSE 0 END AS scopesort"
30  " FROM %s AS ut "
31  " LEFT JOIN clearing_decision cd ON ("
32  " (ut.uploadtree_pk = cd.uploadtree_fk AND cd.scope = 0 AND cd.group_fk = $5)"
33  " OR (EXISTS ("
34  " SELECT 1 FROM report_info ri WHERE ri.upload_fk=$1 AND ri.ri_globaldecision=1"
35  " ) AND ut.pfile_fk = cd.pfile_fk AND cd.scope = 1)"
36  ")"
37  " WHERE upload_fk=$1 AND (ufile_mode&x'3C000000'::int)=0 AND (lft BETWEEN $2 AND $3) AND ut.pfile_fk != 0"
38  " ORDER BY ut.uploadtree_pk, scopesort, ut.pfile_fk, clearing_decision_pk DESC"
39  ") itemView WHERE decision_type!=$4 OR decision_type IS NULL";
40  char* nonVoidPfile = "SELECT a.pfile_fk FROM allPfileData a"
41  " WHERE EXISTS (SELECT 1 FROM license_file lf"
42  " JOIN license_ref lr ON lf.rf_fk = lr.rf_pk"
43  " WHERE lf.pfile_fk = a.pfile_fk"
44  " AND lr.rf_shortname NOT IN ('No_license_found', 'Void'))"
45  " OR NOT EXISTS (SELECT 1 FROM license_file lf"
46  " JOIN license_ref lr ON lf.rf_fk = lr.rf_pk"
47  " WHERE lf.pfile_fk = a.pfile_fk)";
48 
49  if (!ignoreIrre && !scanFindings)
50  {
51  sql = g_strdup_printf(distinctPfile, tablename);
52  stmt = g_strdup_printf("queryFileIdsForUploadAndLimits.%s", tablename);
54  fo_dbManager_PrepareStamement(
55  dbManager,
56  stmt,
57  sql,
58  int, long, long),
59  uploadId, left, right
60  );
61  }
62  else if(!ignoreIrre && scanFindings)
63  {
64  sql = g_strdup_printf(
65  g_strconcat("WITH allPfileData AS (", distinctPfile, ") ", nonVoidPfile,
66  NULL), tablename);
67  stmt = g_strdup_printf("queryFileIdsForUploadAndLimitswithlicensefinding.%s", tablename);
69  fo_dbManager_PrepareStamement(
70  dbManager,
71  stmt,
72  sql,
73  int, long, long),
74  uploadId, left, right
75  );
76  }
77  else if(ignoreIrre && scanFindings)
78  {
79  sql = g_strdup_printf(
80  g_strconcat("WITH allPfileData AS (", distinctPfileNoDec, ") ",
81  nonVoidPfile, NULL), tablename);
82  stmt = g_strdup_printf("queryFileIdsForUploadAndLimits.%s.ignoreirreandscanFindings", tablename);
84  fo_dbManager_PrepareStamement(
85  dbManager,
86  stmt,
87  sql,
88  int, long, long, int, long),
89  uploadId, left, right, DECISION_TYPE_FOR_IRRELEVANT, groupId
90  );
91  }
92  else
93  {
94  sql = g_strdup_printf(distinctPfileNoDec, tablename);
95  stmt = g_strdup_printf("queryFileIdsForUploadAndLimits.%s.ignoreirre", tablename);
97  fo_dbManager_PrepareStamement(
98  dbManager,
99  stmt,
100  sql,
101  int, long, long, int, long),
102  uploadId, left, right, DECISION_TYPE_FOR_IRRELEVANT, groupId
103  );
104  }
105  g_free(sql);
106  g_free(stmt);
107  return result;
108 }
109 
110 PGresult* queryAllLicenses(fo_dbManager* dbManager) {
111  return fo_dbManager_Exec_printf(
112  dbManager,
113  "select rf_pk, rf_shortname from " LICENSE_REF_TABLE " where rf_detector_type = 1 and rf_active = 'true'"
114  );
115 }
116 
117 char* getLicenseTextForLicenseRefId(fo_dbManager* dbManager, long refId) {
118  PGresult* licenseTextResult = fo_dbManager_ExecPrepared(
119  fo_dbManager_PrepareStamement(
120  dbManager,
121  "getLicenseTextForLicenseRefId",
122  "select rf_text from " LICENSE_REF_TABLE " where rf_pk = $1",
123  long),
124  refId
125  );
126 
127  if (PQntuples(licenseTextResult) != 1) {
128  printf("cannot find license text!\n");
129  PQclear(licenseTextResult);
130  return g_strdup("");
131  }
132 
133  char* result = g_strdup(PQgetvalue(licenseTextResult, 0, 0));
134  PQclear(licenseTextResult);
135  return result;
136 }
137 
138 int hasAlreadyResultsFor(fo_dbManager* dbManager, int agentId, long pFileId) {
139  PGresult* insertResult = fo_dbManager_ExecPrepared(
140  fo_dbManager_PrepareStamement(
141  dbManager,
142  "hasAlreadyResultsFor",
143  "SELECT 1 WHERE EXISTS (SELECT 1"
144  " FROM license_file WHERE agent_fk = $1 AND pfile_fk = $2"
145  ")",
146  int, long),
147  agentId, pFileId
148  );
149 
150  int exists = 0;
151  if (insertResult) {
152  exists = (PQntuples(insertResult) == 1);
153  PQclear(insertResult);
154  }
155 
156  return exists;
157 }
158 
159 int saveNoResultToDb(fo_dbManager* dbManager, int agentId, long pFileId) {
160  PGresult* insertResult = fo_dbManager_ExecPrepared(
161  fo_dbManager_PrepareStamement(
162  dbManager,
163  "saveNoResultToDb",
164  "insert into license_file(agent_fk, pfile_fk) values($1,$2)",
165  int, long),
166  agentId, pFileId
167  );
168 
169  int result = 0;
170  if (insertResult) {
171  result = 1;
172  PQclear(insertResult);
173  }
174 
175  return result;
176 }
177 
178 long saveToDb(fo_dbManager* dbManager, int agentId, long refId, long pFileId, unsigned percent) {
179  PGresult* insertResult = fo_dbManager_ExecPrepared(
180  fo_dbManager_PrepareStamement(
181  dbManager,
182  "saveToDb",
183  "insert into license_file(rf_fk, agent_fk, pfile_fk, rf_match_pct) values($1,$2,$3,$4) RETURNING fl_pk",
184  long, int, long, unsigned),
185  refId, agentId, pFileId, percent
186  );
187 
188  long licenseFilePk = -1;
189  if (insertResult) {
190  if (PQntuples(insertResult) == 1) {
191  licenseFilePk = atol(PQgetvalue(insertResult, 0, 0));
192  }
193  PQclear(insertResult);
194  }
195 
196  return licenseFilePk;
197 }
198 
199 int saveDiffHighlightToDb(fo_dbManager* dbManager, const DiffMatchInfo* diffInfo, long licenseFileId) {
200  PGresult* insertResult = fo_dbManager_ExecPrepared(
201  fo_dbManager_PrepareStamement(
202  dbManager,
203  "saveDiffHighlightToDb",
204  "insert into highlight(fl_fk, type, start, len, rf_start, rf_len) values($1,$2,$3,$4,$5,$6)",
205  long, char*, size_t, size_t, size_t, size_t),
206  licenseFileId,
207  diffInfo->diffType,
208  diffInfo->text.start, diffInfo->text.length,
209  diffInfo->search.start, diffInfo->search.length
210  );
211 
212  if (!insertResult)
213  return 0;
214 
215  PQclear(insertResult);
216 
217  return 1;
218 }
219 
220 int saveDiffHighlightsToDb(fo_dbManager* dbManager, const GArray* matchedInfo, long licenseFileId) {
221  size_t matchedInfoLen = matchedInfo->len ;
222  for (size_t i = 0; i < matchedInfoLen; i++) {
223  DiffMatchInfo* diffMatchInfo = &g_array_index(matchedInfo, DiffMatchInfo, i);
224  if (!saveDiffHighlightToDb(dbManager, diffMatchInfo, licenseFileId))
225  return 0;
226  }
227 
228  return 1;
229 }
230 
236 GArray* queryActiveCustomPhrases(fo_dbManager* dbManager) {
237  /* Single JOIN avoids N+1: one query instead of 1 + (1 per phrase). */
238  PGresult* result = fo_dbManager_ExecPrepared(
239  fo_dbManager_PrepareStamement(
240  dbManager,
241  "queryActiveCustomPhrasesWithMappings",
242  "SELECT cp.cp_pk, cp.text, cp.acknowledgement, cp.comments,"
243  " cplm.rf_fk, cplm.removing,"
244  " cplm.comment, cplm.reportinfo, cplm.acknowledgement"
245  " FROM custom_phrase cp"
246  " LEFT JOIN custom_phrase_license_map cplm ON cp.cp_pk = cplm.cp_fk"
247  " WHERE cp.is_active = true"
248  " ORDER BY cp.cp_pk"
249  )
250  );
251 
252  GArray* phrases = g_array_new(FALSE, FALSE, sizeof(Phrase*));
253 
254  if (!result)
255  return phrases;
256 
257  int numRows = PQntuples(result);
258  Phrase* current = NULL;
259 
260  for (int i = 0; i < numRows; i++) {
261  long cpId = atol(PQgetvalue(result, i, 0));
262 
263  if (!current || current->cpId != cpId) {
264  Phrase* phrase = (Phrase*)g_malloc0(sizeof(Phrase));
265  phrase->cpId = cpId;
266  phrase->text = g_strdup(PQgetvalue(result, i, 1));
267  phrase->acknowledgement = PQgetisnull(result, i, 2) ? NULL : g_strdup(PQgetvalue(result, i, 2));
268  phrase->comments = PQgetisnull(result, i, 3) ? NULL : g_strdup(PQgetvalue(result, i, 3));
269  phrase->licenseMappings = g_array_new(FALSE, FALSE, sizeof(LicenseMapping));
270  phrase->stmtName = NULL;
271  g_array_append_val(phrases, phrase);
272  current = phrase;
273  }
274 
275  /* LEFT JOIN row with no mapping has rf_fk = NULL, skip it. */
276  if (!PQgetisnull(result, i, 4)) {
277  LicenseMapping mapping = {0};
278  mapping.rfPk = atol(PQgetvalue(result, i, 4));
279  mapping.removing = (strcmp(PQgetvalue(result, i, 5), "t") == 0) ? 1 : 0;
280  mapping.comment = PQgetisnull(result, i, 6) ? NULL : g_strdup(PQgetvalue(result, i, 6));
281  mapping.reportinfo = PQgetisnull(result, i, 7) ? NULL : g_strdup(PQgetvalue(result, i, 7));
282  mapping.acknowledgement = PQgetisnull(result, i, 8) ? NULL : g_strdup(PQgetvalue(result, i, 8));
283  g_array_append_val(current->licenseMappings, mapping);
284  }
285  }
286 
287  PQclear(result);
288  return phrases;
289 }
290 
295 void phrase_free(Phrase* phrase) {
296  if (!phrase) return;
297 
298  g_free(phrase->text);
299  g_free(phrase->acknowledgement);
300  g_free(phrase->comments);
301  g_free(phrase->stmtName);
302 
303  if (phrase->licenseMappings) {
304  for (guint i = 0; i < phrase->licenseMappings->len; i++) {
305  LicenseMapping* m = &g_array_index(phrase->licenseMappings, LicenseMapping, i);
306  g_free(m->comment);
307  g_free(m->reportinfo);
308  g_free(m->acknowledgement);
309  }
310  g_array_free(phrase->licenseMappings, TRUE);
311  }
312 
313  g_free(phrase);
314 }
315 
320 void phrases_free(GArray* phrases) {
321  if (!phrases) return;
322 
323  for (guint i = 0; i < phrases->len; i++) {
324  Phrase* phrase = g_array_index(phrases, Phrase*, i);
325  phrase_free(phrase);
326  }
327 
328  g_array_free(phrases, TRUE);
329 }
char * getUploadTreeTableName(fo_dbManager *dbManager, int uploadId)
Get the upload tree table name for a given upload.
Definition: libfossagent.c:25
fo_dbManager * dbManager
fo_dbManager object
Definition: process.c:16
PGresult * fo_dbManager_ExecPrepared(fo_dbManager_PreparedStatement *preparedStatement,...)
Execute a prepared statement.
Definition: standalone.c:37
License mapping entry with per-mapping report metadata.
Definition: database.h:22
int removing
0 = add license, 1 = remove license
Definition: database.h:24
char * acknowledgement
nullable
Definition: database.h:27
long rfPk
rf_pk from license_ref table
Definition: database.h:23
char * comment
nullable
Definition: database.h:25
char * reportinfo
nullable
Definition: database.h:26
Structure to hold a custom phrase and its mapped licenses.
Definition: database.h:33
int exists
Default not exists.
Definition: run_tests.c:20