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 = ", realFindings AS ("
41  " SELECT DISTINCT lf.pfile_fk"
42  " FROM license_file lf"
43  " INNER JOIN ars_master am ON lf.agent_fk = am.agent_fk AND am.upload_fk = $1"
44  " INNER JOIN " LICENSE_REF_TABLE " lr ON lf.rf_fk = lr.rf_pk"
45  " WHERE lr.rf_shortname NOT IN ('No_license_found', 'Void')"
46  ")"
47  " SELECT pfile_fk FROM allPfileData"
48  " WHERE pfile_fk IN (SELECT pfile_fk FROM realFindings)";
49 
50  if (!ignoreIrre && !scanFindings)
51  {
52  sql = g_strdup_printf(distinctPfile, tablename);
53  stmt = g_strdup_printf("queryFileIdsForUploadAndLimits.%s", tablename);
55  fo_dbManager_PrepareStamement(
56  dbManager,
57  stmt,
58  sql,
59  int, long, long),
60  uploadId, left, right
61  );
62  }
63  else if(!ignoreIrre && scanFindings)
64  {
65  sql = g_strdup_printf(
66  g_strconcat("WITH allPfileData AS (", distinctPfile, ") ", nonVoidPfile,
67  NULL), tablename);
68  stmt = g_strdup_printf("queryFileIdsForUploadAndLimitswithlicensefinding.%s", tablename);
70  fo_dbManager_PrepareStamement(
71  dbManager,
72  stmt,
73  sql,
74  int, long, long),
75  uploadId, left, right
76  );
77  }
78  else if(ignoreIrre && scanFindings)
79  {
80  sql = g_strdup_printf(
81  g_strconcat("WITH allPfileData AS (", distinctPfileNoDec, ") ",
82  nonVoidPfile, NULL), tablename);
83  stmt = g_strdup_printf("queryFileIdsForUploadAndLimits.%s.ignoreirreandscanFindings", tablename);
85  fo_dbManager_PrepareStamement(
86  dbManager,
87  stmt,
88  sql,
89  int, long, long, int, long),
90  uploadId, left, right, DECISION_TYPE_FOR_IRRELEVANT, groupId
91  );
92  }
93  else
94  {
95  sql = g_strdup_printf(distinctPfileNoDec, tablename);
96  stmt = g_strdup_printf("queryFileIdsForUploadAndLimits.%s.ignoreirre", tablename);
98  fo_dbManager_PrepareStamement(
99  dbManager,
100  stmt,
101  sql,
102  int, long, long, int, long),
103  uploadId, left, right, DECISION_TYPE_FOR_IRRELEVANT, groupId
104  );
105  }
106  g_free(sql);
107  g_free(stmt);
108  return result;
109 }
110 
111 PGresult* queryAllLicenses(fo_dbManager* dbManager) {
112  return fo_dbManager_Exec_printf(
113  dbManager,
114  "select rf_pk, rf_shortname from " LICENSE_REF_TABLE " where rf_detector_type = 1 and rf_active = 'true'"
115  );
116 }
117 
118 char* getLicenseTextForLicenseRefId(fo_dbManager* dbManager, long refId) {
119  PGresult* licenseTextResult = fo_dbManager_ExecPrepared(
120  fo_dbManager_PrepareStamement(
121  dbManager,
122  "getLicenseTextForLicenseRefId",
123  "select rf_text from " LICENSE_REF_TABLE " where rf_pk = $1",
124  long),
125  refId
126  );
127 
128  if (PQntuples(licenseTextResult) != 1) {
129  printf("cannot find license text!\n");
130  PQclear(licenseTextResult);
131  return g_strdup("");
132  }
133 
134  char* result = g_strdup(PQgetvalue(licenseTextResult, 0, 0));
135  PQclear(licenseTextResult);
136  return result;
137 }
138 
139 int hasAlreadyResultsFor(fo_dbManager* dbManager, int agentId, long pFileId) {
140  PGresult* insertResult = fo_dbManager_ExecPrepared(
141  fo_dbManager_PrepareStamement(
142  dbManager,
143  "hasAlreadyResultsFor",
144  "SELECT 1 WHERE EXISTS (SELECT 1"
145  " FROM license_file WHERE agent_fk = $1 AND pfile_fk = $2"
146  ")",
147  int, long),
148  agentId, pFileId
149  );
150 
151  int exists = 0;
152  if (insertResult) {
153  exists = (PQntuples(insertResult) == 1);
154  PQclear(insertResult);
155  }
156 
157  return exists;
158 }
159 
160 int saveNoResultToDb(fo_dbManager* dbManager, int agentId, long pFileId) {
161  PGresult* insertResult = fo_dbManager_ExecPrepared(
162  fo_dbManager_PrepareStamement(
163  dbManager,
164  "saveNoResultToDb",
165  "insert into license_file(agent_fk, pfile_fk) values($1,$2)",
166  int, long),
167  agentId, pFileId
168  );
169 
170  int result = 0;
171  if (insertResult) {
172  result = 1;
173  PQclear(insertResult);
174  }
175 
176  return result;
177 }
178 
179 long saveToDb(fo_dbManager* dbManager, int agentId, long refId, long pFileId, unsigned percent) {
180  PGresult* insertResult = fo_dbManager_ExecPrepared(
181  fo_dbManager_PrepareStamement(
182  dbManager,
183  "saveToDb",
184  "insert into license_file(rf_fk, agent_fk, pfile_fk, rf_match_pct) values($1,$2,$3,$4) RETURNING fl_pk",
185  long, int, long, unsigned),
186  refId, agentId, pFileId, percent
187  );
188 
189  long licenseFilePk = -1;
190  if (insertResult) {
191  if (PQntuples(insertResult) == 1) {
192  licenseFilePk = atol(PQgetvalue(insertResult, 0, 0));
193  }
194  PQclear(insertResult);
195  }
196 
197  return licenseFilePk;
198 }
199 
200 int saveDiffHighlightToDb(fo_dbManager* dbManager, const DiffMatchInfo* diffInfo, long licenseFileId) {
201  PGresult* insertResult = fo_dbManager_ExecPrepared(
202  fo_dbManager_PrepareStamement(
203  dbManager,
204  "saveDiffHighlightToDb",
205  "insert into highlight(fl_fk, type, start, len, rf_start, rf_len) values($1,$2,$3,$4,$5,$6)",
206  long, char*, size_t, size_t, size_t, size_t),
207  licenseFileId,
208  diffInfo->diffType,
209  diffInfo->text.start, diffInfo->text.length,
210  diffInfo->search.start, diffInfo->search.length
211  );
212 
213  if (!insertResult)
214  return 0;
215 
216  PQclear(insertResult);
217 
218  return 1;
219 }
220 
221 int saveDiffHighlightsToDb(fo_dbManager* dbManager, const GArray* matchedInfo, long licenseFileId) {
222  size_t matchedInfoLen = matchedInfo->len ;
223  for (size_t i = 0; i < matchedInfoLen; i++) {
224  DiffMatchInfo* diffMatchInfo = &g_array_index(matchedInfo, DiffMatchInfo, i);
225  if (!saveDiffHighlightToDb(dbManager, diffMatchInfo, licenseFileId))
226  return 0;
227  }
228 
229  return 1;
230 }
231 
237 GArray* queryActiveCustomPhrases(fo_dbManager* dbManager) {
238  /* Single JOIN avoids N+1: one query instead of 1 + (1 per phrase). */
239  PGresult* result = fo_dbManager_ExecPrepared(
240  fo_dbManager_PrepareStamement(
241  dbManager,
242  "queryActiveCustomPhrasesWithMappings",
243  "SELECT cp.cp_pk, cp.text, cp.acknowledgement, cp.comments,"
244  " cplm.rf_fk, cplm.removing,"
245  " cplm.comment, cplm.reportinfo, cplm.acknowledgement"
246  " FROM custom_phrase cp"
247  " LEFT JOIN custom_phrase_license_map cplm ON cp.cp_pk = cplm.cp_fk"
248  " WHERE cp.is_active = true"
249  " ORDER BY cp.cp_pk"
250  )
251  );
252 
253  GArray* phrases = g_array_new(FALSE, FALSE, sizeof(Phrase*));
254 
255  if (!result)
256  return phrases;
257 
258  int numRows = PQntuples(result);
259  Phrase* current = NULL;
260 
261  for (int i = 0; i < numRows; i++) {
262  long cpId = atol(PQgetvalue(result, i, 0));
263 
264  if (!current || current->cpId != cpId) {
265  Phrase* phrase = (Phrase*)g_malloc0(sizeof(Phrase));
266  phrase->cpId = cpId;
267  phrase->text = g_strdup(PQgetvalue(result, i, 1));
268  phrase->acknowledgement = PQgetisnull(result, i, 2) ? NULL : g_strdup(PQgetvalue(result, i, 2));
269  phrase->comments = PQgetisnull(result, i, 3) ? NULL : g_strdup(PQgetvalue(result, i, 3));
270  phrase->licenseMappings = g_array_new(FALSE, FALSE, sizeof(LicenseMapping));
271  phrase->stmtName = NULL;
272  g_array_append_val(phrases, phrase);
273  current = phrase;
274  }
275 
276  /* LEFT JOIN row with no mapping has rf_fk = NULL, skip it. */
277  if (!PQgetisnull(result, i, 4)) {
278  LicenseMapping mapping = {0};
279  mapping.rfPk = atol(PQgetvalue(result, i, 4));
280  mapping.removing = (strcmp(PQgetvalue(result, i, 5), "t") == 0) ? 1 : 0;
281  mapping.comment = PQgetisnull(result, i, 6) ? NULL : g_strdup(PQgetvalue(result, i, 6));
282  mapping.reportinfo = PQgetisnull(result, i, 7) ? NULL : g_strdup(PQgetvalue(result, i, 7));
283  mapping.acknowledgement = PQgetisnull(result, i, 8) ? NULL : g_strdup(PQgetvalue(result, i, 8));
284  g_array_append_val(current->licenseMappings, mapping);
285  }
286  }
287 
288  PQclear(result);
289  return phrases;
290 }
291 
296 void phrase_free(Phrase* phrase) {
297  if (!phrase) return;
298 
299  g_free(phrase->text);
300  g_free(phrase->acknowledgement);
301  g_free(phrase->comments);
302  g_free(phrase->stmtName);
303 
304  if (phrase->licenseMappings) {
305  for (guint i = 0; i < phrase->licenseMappings->len; i++) {
306  LicenseMapping* m = &g_array_index(phrase->licenseMappings, LicenseMapping, i);
307  g_free(m->comment);
308  g_free(m->reportinfo);
309  g_free(m->acknowledgement);
310  }
311  g_array_free(phrase->licenseMappings, TRUE);
312  }
313 
314  g_free(phrase);
315 }
316 
321 void phrases_free(GArray* phrases) {
322  if (!phrases) return;
323 
324  for (guint i = 0; i < phrases->len; i++) {
325  Phrase* phrase = g_array_index(phrases, Phrase*, i);
326  phrase_free(phrase);
327  }
328 
329  g_array_free(phrases, TRUE);
330 }
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