-
Notifications
You must be signed in to change notification settings - Fork 1
/
commonDB.c
4361 lines (3518 loc) · 217 KB
/
commonDB.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// ========================================================================================================
// ========================================================================================================
// ******************************************** commonDB.c ************************************************
// ========================================================================================================
// ========================================================================================================
//
//--------------------------------------------------------------------------------
// Company: IC-Safety, LLC and University of New Mexico
// Engineer: Professor Jim Plusquellic
// Exclusive License: IC-Safety, LLC
// Copyright: Univ. of New Mexico
//--------------------------------------------------------------------------------
#include "commonDB.h"
// SQL commands depend on the structure of the tables in the database. Keeping these all in one place where possible.
const char *SQL_PUFDesign_get_index_cmd = "SELECT id FROM PUFDesign WHERE netlist_name = ? AND synthesis_name = ?;";
const char *SQL_PUFDesign_insert_into_cmd = "INSERT INTO PUFDesign (netlist_name, synthesis_name, num_PIs, num_POs) VALUES (?, ?, ?, ?);";
const char *SQL_PUFInstance_get_index_cmd = "SELECT id FROM PUFInstance WHERE Instance_name = ? AND Dev = ? AND Placement = ?;";
const char *SQL_PUFInstance_insert_into_cmd = "INSERT INTO PUFInstance (Instance_name, Dev, Placement, EnrollDate, PUFDesign_id) VALUES (?, ?, ?, ?, ?);";
const char *SQL_PUFInstance_delete_cmd = "DELETE FROM PUFInstance WHERE id = ?;";
const char *SQL_Vectors_insert_into_cmd = "INSERT INTO Vectors (vector) VALUES (?);";
const char *SQL_Vectors_read_vector_cmd = "SELECT vector FROM Vectors WHERE id = ?;";
const char *SQL_Vectors_get_index_cmd = "SELECT id FROM Vectors WHERE vector = ?;";
const char *SQL_VecPairs_insert_into_cmd = "INSERT INTO VecPairs (R_F_str, VA, VB, NumPNs, PUFDesign_id) VALUES (?, ?, ?, ?, ?);";
const char *SQL_VecPairs_get_index_cmd = "SELECT id FROM VecPairs WHERE VA = ? AND VB = ? AND PUFDesign_id = ?;";
const char *SQL_TimingVals_insert_into_cmd = "INSERT INTO TimingVals (VecPair, PO, Ave, TSig, PUFInstance) VALUES (?, ?, ?, ?, ?);";
const char *SQL_PathSelectMasks_insert_into_cmd = "INSERT INTO PathSelectMasks (vector_str) VALUES (?);";
const char *SQL_PathSelectMasks_get_index_cmd = "SELECT id FROM PathSelectMasks WHERE vector_str = ?;";
const char *SQL_Challenges_insert_into_cmd = "INSERT INTO Challenges (Name, NumVecs, NumRiseVecs, NumPNs, NumRisePNs, PUFDesign_id) VALUES (?, ?, ?, ?, ?, ?);";
const char *SQL_Challenges_get_index_cmd = "SELECT id FROM Challenges WHERE Name = ?;";
const char *SQL_ChallengeVecPairs_insert_into_cmd = "INSERT INTO ChallengeVecPairs (Chlng, VecPair, PSM) VALUES (?, ?, ?);";
const char *SQL_ChallengeVecPairs_get_index_cmd = "SELECT id FROM ChallengeVecPairs WHERE Chlng = ? AND VecPair = ? AND PSM = ?;";
// ===========================================================================================================
// ===========================================================================================================
// Got this from https://www.sqlite.org/backup.html. This function is used to load the contents of a database
// file on disk into the "main" database of open database connection pInMemory, or to save the current contents
// of the database opened by pInMemory into database file on disk. pInMemory is probably an in-memory database,
// but this function will also work fine if it is not. Parameter zFilename points to a null-terminated string
// containing the name of the database file on disk to load from or save to. If parameter isSave is non-zero,
// then the contents of the file zFilename are overwritten with the contents of the database opened by pInMemory.
// If parameter isSave is zero, then the contents of the database opened by pInMemory are replaced by data loaded
// from the file zFilename. If the operation is successful, SQLITE_OK is returned. Otherwise, if an error occurs,
// an SQLite error code is returned.
int LoadOrSaveDb(sqlite3 *pInMemory, const char *zFilename, int isSave)
{
int rc; // Function return code
sqlite3 *pFile; // Database connection opened on zFilename
sqlite3_backup *pBackup; // Backup object used to copy data
sqlite3 *pTo; // Database to copy to (pFile or pInMemory)
sqlite3 *pFrom; // Database to copy from (pFile or pInMemory)
// Open the database file identified by zFilename. Exit early if this fails for any reason.
rc = sqlite3_open(zFilename, &pFile);
if ( rc == SQLITE_OK )
{
// If this is a 'load' operation (isSave==0), then data is copied from the database file just opened to database pInMemory.
// Otherwise, if this is a 'save' operation (isSave==1), then data is copied from pInMemory to pFile. Set the variables pFrom and
// pTo accordingly.
pFrom = (isSave ? pInMemory : pFile);
pTo = (isSave ? pFile : pInMemory);
// Set up the backup procedure to copy from the "main" database of connection pFile to the main database of connection pInMemory.
// If something goes wrong, pBackup will be set to NULL and an error code and message left in connection pTo. If the backup object
// is successfully created, call backup_step() to copy data from pFile to pInMemory. Then call backup_finish() to release resources
// associated with the pBackup object. If an error occurred, then an error code and message will be left in connection pTo. If no
// error occurred, then the error code belonging to pTo is set to SQLITE_OK.
pBackup = sqlite3_backup_init(pTo, "main", pFrom, "main");
if ( pBackup )
{
(void)sqlite3_backup_step(pBackup, -1);
(void)sqlite3_backup_finish(pBackup);
}
rc = sqlite3_errcode(pTo);
}
// Close the database connection opened on database file zFilename and return the result of this function.
(void)sqlite3_close(pFile);
return rc;
}
// ========================================================================================================
// ========================================================================================================
// Get all IDs from the table.
void Get_IDs(int max_string_len, sqlite3 *db, char *table_name, SQLIntStruct *index_struct_ptr)
{
char sql_command_str[max_string_len];
sprintf(sql_command_str, "SELECT ID FROM %s;", table_name);
GetAllocateListOfInts(max_string_len, db, sql_command_str, index_struct_ptr);
return;
}
// ========================================================================================================
// ========================================================================================================
// Delete from 'table_name' the ID given as parameter.
void Delete_ForID(int max_string_len, sqlite3 *db, char *table_name, int index)
{
char sql_command_str[max_string_len];
char *zErrMsg = 0;
int fc;
sprintf(sql_command_str, "DELETE FROM %s WHERE ID = %d;", table_name, index);
// No callback for delete operation.
fc = sqlite3_exec(db, sql_command_str, NULL, 0, &zErrMsg);
if ( fc != SQLITE_OK )
{ printf("Delete_ForID(): SQL ERROR: %s\n", zErrMsg); sqlite3_free(zErrMsg); exit(EXIT_FAILURE); }
return;
}
// ========================================================================================================
// ========================================================================================================
// This callback invoked for each result row coming out of the evaluated SQL statements. First arg is
// user-specified arg, 2nd arg is number of columns in the result, 3rd arg is an array of pointers to
// strings RESULTS obtained from something like sqlite3_column_text() and 4th arg are pointers to strings
// of column names.
int SQL_callback(void *UserSpecifiedData, int argc, char **argv, char **azColName)
{
int i;
printf("SQL_callback() called!\n"); fflush(stdout);
for( i = 0; i < argc; i++ )
{ printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL"); }
printf("\n");
return 0;
}
// ========================================================================================================
// ========================================================================================================
// A utility routine that does sanity checks and gets the integer row result.
void GetRowResultFloat(SQLRowStringsStruct *row_strings_struct_ptr, char *calling_routine_str, int num_cols,
int col_index, char *field_name_str, float *field_val_float_ptr)
{
if ( row_strings_struct_ptr->num_cols != num_cols )
{ printf("ERROR: %s: Expected %d column names in return row_strings_struct, found %d!\n", calling_routine_str, num_cols, row_strings_struct_ptr->num_cols); exit(EXIT_FAILURE); }
if ( strcmp(row_strings_struct_ptr->ColNames[col_index], field_name_str) != 0 )
{ printf("ERROR: %s: Unexpected column names: Got %s instead of %s\n", calling_routine_str, row_strings_struct_ptr->ColNames[col_index], field_name_str); exit(EXIT_FAILURE); }
if ( sscanf(row_strings_struct_ptr->ColStringVals[col_index], "%f", field_val_float_ptr) != 1 )
{ printf("ERROR: %s: Failed to convert to numeric values for %s!\n", calling_routine_str, row_strings_struct_ptr->ColStringVals[col_index]); exit(EXIT_FAILURE); }
return;
}
// ========================================================================================================
// ========================================================================================================
// A utility routine that does sanity checks and gets the integer row result data.
void GetRowResultInt(SQLRowStringsStruct *row_strings_struct_ptr, char *calling_routine_str, int num_cols,
int col_index, char *field_name_str, int *field_val_int_ptr)
{
if ( row_strings_struct_ptr->num_cols != num_cols )
{ printf("ERROR: %s: Expected %d column names in return row_strings_struct, found %d!\n", calling_routine_str, num_cols, row_strings_struct_ptr->num_cols); exit(EXIT_FAILURE); }
if ( strcmp(row_strings_struct_ptr->ColNames[col_index], field_name_str) != 0 )
{ printf("ERROR: %s: Unexpected column names: Got %s instead of %s\n", calling_routine_str, row_strings_struct_ptr->ColNames[col_index], field_name_str); exit(EXIT_FAILURE); }
if ( sscanf(row_strings_struct_ptr->ColStringVals[col_index], "%d", field_val_int_ptr) != 1 )
{ printf("ERROR: %s: Failed to convert to numeric values for %s!\n", calling_routine_str, row_strings_struct_ptr->ColStringVals[col_index]); exit(EXIT_FAILURE); }
return;
}
// ========================================================================================================
// ========================================================================================================
// A utility routine that does sanity checks and gets the string row result data.
void GetRowResultString(SQLRowStringsStruct *row_strings_struct_ptr, char *calling_routine_str, int num_cols,
int col_index, char *field_name_str, int required_string_len, char *field_val_str)
{
if ( row_strings_struct_ptr->num_cols != num_cols )
{ printf("ERROR: %s: Expected %d column names in return row_strings_struct, found %d!\n", calling_routine_str, num_cols, row_strings_struct_ptr->num_cols); exit(EXIT_FAILURE); }
if ( strcmp(row_strings_struct_ptr->ColNames[col_index], field_name_str) != 0 )
{ printf("ERROR: %s: Unexpected column names: Got %s instead of %s\n", calling_routine_str, row_strings_struct_ptr->ColNames[col_index], field_name_str); exit(EXIT_FAILURE); }
if ( required_string_len != -1 && strlen(row_strings_struct_ptr->ColStringVals[col_index]) != required_string_len )
{ printf("ERROR: %s: Length of string %d expected to be %d\n", calling_routine_str, (int)strlen(row_strings_struct_ptr->ColStringVals[col_index]), required_string_len); exit(EXIT_FAILURE); }
strcpy(field_val_str, row_strings_struct_ptr->ColStringVals[col_index]);
return;
}
// ========================================================================================================
// ========================================================================================================
// This callback invoked for SQL queries that return EXACTLY ONE row. We simply transfer the string data from
// the argc and argv incoming data to the UserSpecifiedData argument. First arg is user-specified arg, 2nd arg
// is number of columns in the result, 3rd arg is an array of pointers to strings RESULTS obtained from something
// like sqlite3_column_text() and 4th arg are pointers to strings of column names.
int SQL_GetStringsDataForRow_callback(void *UserSpecifiedData, int argc, char **argv, char **azColName)
{
SQLRowStringsStruct *SQL_row_strings_struct_ptr = (SQLRowStringsStruct *)UserSpecifiedData;
int col_num;
#ifdef DEBUG
printf("SQL_GetStringsDataForRow_callback(): called!\n"); fflush(stdout);
#endif
// Sanity check. Check to make sure the SQLRowStringsStruct is NOT NULL;
if ( SQL_row_strings_struct_ptr == NULL )
{ printf("ERROR: SQL_GetStringsDataForRow_callback(): UserSpecified data MUST NOT BE NULL!\n"); exit(EXIT_FAILURE); }
// Sanity check. Make sure this callback was called ONLY ONCE.
if ( SQL_row_strings_struct_ptr->num_cols != 0 )
{ printf("ERROR: SQL_GetStringsDataForRow_callback(): More than 1 row matched in table -- SQLRowStringsStruct already has data!\n"); exit(EXIT_FAILURE); }
// Force realloc to behave like malloc
SQL_row_strings_struct_ptr->ColNames = NULL;
SQL_row_strings_struct_ptr->ColStringVals = NULL;
// Transfer the string data to our data structure, creating storage as needed.
for ( col_num = 0; col_num < argc; col_num++ )
{
#ifdef DEBUG
printf("Creating SQLRowStringsStruct element for column number %d\n", col_num); fflush(stdout);
#endif
// Copy column name first and then value.
if ( (SQL_row_strings_struct_ptr->ColNames = (char **)realloc(SQL_row_strings_struct_ptr->ColNames, sizeof(char *)*(SQL_row_strings_struct_ptr->num_cols + 1))) == NULL )
{ printf("ERROR: SQL_GetStringsDataForRow_callback(): Failed to (re)allocate storage for SQL_row_strings_struct_ptr.ColNames pointer!\n"); exit(EXIT_FAILURE); }
if ( (SQL_row_strings_struct_ptr->ColStringVals = (char **)realloc(SQL_row_strings_struct_ptr->ColStringVals, sizeof(char *)*(SQL_row_strings_struct_ptr->num_cols + 1))) == NULL )
{ printf("ERROR: SQL_GetStringsDataForRow_callback(): Failed to (re)allocate storage for SQL_row_strings_struct_ptr.ColStringVals pointer!\n"); exit(EXIT_FAILURE); }
if ( (SQL_row_strings_struct_ptr->ColNames[col_num] = (char *)malloc(sizeof(char)*(strlen(azColName[col_num]) + 1))) == NULL )
{ printf("ERROR: SQL_GetStringsDataForRow_callback(): Failed to allocate storage for SQL_row_strings_struct_ptr.ColNames string!\n"); exit(EXIT_FAILURE); }
strcpy(SQL_row_strings_struct_ptr->ColNames[col_num], azColName[col_num]);
if ( (SQL_row_strings_struct_ptr->ColStringVals[col_num] = (char *)malloc(sizeof(char)*(strlen(argv[col_num]) + 1))) == NULL )
{ printf("ERROR: SQL_GetStringsDataForRow_callback(): Failed to allocate storage for SQL_row_strings_struct_ptr.ColStringVals string!\n"); exit(EXIT_FAILURE); }
strcpy(SQL_row_strings_struct_ptr->ColStringVals[col_num], argv[col_num]);
SQL_row_strings_struct_ptr->num_cols++;
}
#ifdef DEBUG
int i;
for( i = 0; i < argc; i++ )
{ printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL"); }
printf("\n");
#endif
#ifdef DEBUG
printf("SQL_GetStringsDataForRow_callback(): DONE!\n"); fflush(stdout);
#endif
return 0;
}
// ========================================================================================================
// ========================================================================================================
// Get generic string data for the entire row of some table.
void GetStringsDataForRow(int max_string_len, sqlite3 *db, char *sql_command_str,
SQLRowStringsStruct *row_strings_struct_ptr)
{
char *zErrMsg = 0;
int fc;
#ifdef DEBUG
printf("GetStringsDataForRow(): called!\n"); fflush(stdout);
#endif
// Initialize the number of columns to 0.
row_strings_struct_ptr->num_cols = 0;
fc = sqlite3_exec(db, sql_command_str, SQL_GetStringsDataForRow_callback, row_strings_struct_ptr, &zErrMsg);
if ( fc != SQLITE_OK )
{ printf("SQL ERROR: %s\n", zErrMsg); sqlite3_free(zErrMsg); exit(EXIT_FAILURE); }
return;
}
// ========================================================================================================
// ========================================================================================================
// Free up the strings allocated in SQL_GetStringsDataForRow_callback.
void FreeStringsDataForRow(SQLRowStringsStruct *row_strings_struct_ptr)
{
int col_num;
#ifdef DEBUG
printf("FreeStringsDataForRow(): called!\n"); fflush(stdout);
#endif
for ( col_num = 0; col_num < row_strings_struct_ptr->num_cols; col_num++ )
{
free(row_strings_struct_ptr->ColNames[col_num]);
free(row_strings_struct_ptr->ColStringVals[col_num]);
}
free(row_strings_struct_ptr->ColNames);
free(row_strings_struct_ptr->ColStringVals);
row_strings_struct_ptr->ColNames = NULL;
row_strings_struct_ptr->ColStringVals = NULL;
row_strings_struct_ptr->num_cols = 0;
}
// ========================================================================================================
// ========================================================================================================
// This callback is called once for each matching row in a table referred to by the SQL query. It adds 1
// element to the float array in UserSpecifiedData on each call dynamically.
int SQL_GetAllocateListOfFloats_callback(void *UserSpecifiedData, int argc, char **argv, char **azColName)
{
SQLFloatStruct *SQL_float_struct_ptr = (SQLFloatStruct *)UserSpecifiedData;
#ifdef DEBUG
printf("SQL_GetAllocateListOfFloats_callback(): called!\n"); fflush(stdout);
#endif
// Sanity check. The SQL query MUST restrict the number of fields retrieved to ONLY 1.
if ( argc != 1 )
{ printf("ERROR: SQL_GetAllocateListOfFloats_callback(): Expected argc to be 1!\n"); exit(EXIT_FAILURE); }
// Sanity check. Check to make sure the SQLFloatStruct is NOT NULL;
if ( SQL_float_struct_ptr == NULL )
{ printf("ERROR: SQL_GetAllocateListOfFloats_callback(): UserSpecified data MUST NOT BE NULL!\n"); exit(EXIT_FAILURE); }
// Allocate or re-allocate another element to the array. THIS ROUTINE GETS CALLED MULTIPLE TIMES.
if ( SQL_float_struct_ptr->num_floats == 0 )
{
if ( (SQL_float_struct_ptr->float_arr = (float *)malloc(sizeof(float))) == NULL )
{ printf("ERROR: SQL_GetAllocateListOfFloats_callback(): Failed to allocate storage for SQLFloatStruct.float_arr!\n"); exit(EXIT_FAILURE); }
}
else
{
if ( (SQL_float_struct_ptr->float_arr = (float *)realloc(SQL_float_struct_ptr->float_arr, sizeof(float)*(SQL_float_struct_ptr->num_floats + 1))) == NULL )
{ printf("ERROR: SQL_GetAllocateListOfFloats_callback(): Failed to reallocate storage for SQLFloatStruct.float_arr!\n"); exit(EXIT_FAILURE); }
}
sscanf(argv[0], "%f", &(SQL_float_struct_ptr->float_arr[SQL_float_struct_ptr->num_floats]));
(SQL_float_struct_ptr->num_floats)++;
#ifdef DEBUG
printf("SQL_GetAllocateListOfFloats_callback(): New number of elements in float array %d\n", SQL_float_struct_ptr->num_floats); fflush(stdout);
#endif
#ifdef DEBUG
int i;
for( i = 0; i < argc; i++ )
{ printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL"); }
printf("\n");
#endif
#ifdef DEBUG
printf("SQL_GetAllocateListOfFloats_callback(): DONE!\n"); fflush(stdout);
#endif
return 0;
}
// ========================================================================================================
// ========================================================================================================
// This routine will return an array of floats associated with a database table that match the SQL_query_str
// passed in as an argument. The array in the struct is allocated dynamically so the caller is responsible for
// freeing it once it is used.
void GetAllocateListOfFloats(int max_string_len, sqlite3 *db, char *sql_command_str, SQLFloatStruct *float_struct)
{
char *zErrMsg = 0;
int fc;
#ifdef DEBUG
printf("GetAllocateListOfFloats(): Called!\n"); fflush(stdout);
#endif
// Initialize the fields before the callback is called.
float_struct->float_arr = NULL;
float_struct->num_floats = 0;
// The callback will be called multiple times, once for each matching database element to sql_command_str.
fc = sqlite3_exec(db, sql_command_str, SQL_GetAllocateListOfFloats_callback, float_struct, &zErrMsg);
if ( fc != SQLITE_OK )
{ printf("SQL ERROR: %s\n", zErrMsg); sqlite3_free(zErrMsg); exit(EXIT_FAILURE); }
return;
}
// ========================================================================================================
// ========================================================================================================
// This callback is called once for each matching row in a table referred to by the SQL query. It adds 1
// element to the integer array in UserSpecifiedData on each call dynamically.
int SQL_GetAllocateListOfInts_callback(void *UserSpecifiedData, int argc, char **argv, char **azColName)
{
SQLIntStruct *SQL_int_struct_ptr = (SQLIntStruct *)UserSpecifiedData;
#ifdef DEBUG
printf("SQL_GetAllocateListOfInts_callback(): BEGIN\n"); fflush(stdout);
#endif
// Sanity check. The SQL query MUST restrict the number of fields retrieved to ONLY 1.
if ( argc != 1 )
{ printf("ERROR: SQL_GetAllocateListOfInts_callback(): Expected argc to be 1!\n"); exit(EXIT_FAILURE); }
// Sanity check. Check to make sure the SQLIntStruct is NOT NULL;
if ( SQL_int_struct_ptr == NULL )
{ printf("ERROR: SQL_GetAllocateListOfInts_callback(): UserSpecified data MUST NOT BE NULL!\n"); exit(EXIT_FAILURE); }
// Allocate or re-allocate another element to the array. THIS ROUTINE GETS CALLED MULTIPLE TIMES.
if ( SQL_int_struct_ptr->num_ints == 0 )
{
if ( (SQL_int_struct_ptr->int_arr = (int *)malloc(sizeof(int))) == NULL )
{ printf("ERROR: SQL_GetAllocateListOfInts_callback(): Failed to allocate storage for SQLIntStruct.int_arr!\n"); exit(EXIT_FAILURE); }
}
else
{
if ( (SQL_int_struct_ptr->int_arr = (int *)realloc(SQL_int_struct_ptr->int_arr, sizeof(int)*(SQL_int_struct_ptr->num_ints + 1))) == NULL )
{ printf("ERROR: SQL_GetAllocateListOfInts_callback(): Failed to reallocate storage for SQLIntStruct.int_arr!\n"); exit(EXIT_FAILURE); }
}
sscanf(argv[0], "%d", &(SQL_int_struct_ptr->int_arr[SQL_int_struct_ptr->num_ints]));
(SQL_int_struct_ptr->num_ints)++;
#ifdef DEBUG
printf("SQL_GetAllocateListOfInts_callback(): New number of elements in integer array %d\n", SQL_int_struct_ptr->num_ints); fflush(stdout);
#endif
#ifdef DEBUG
int i;
for( i = 0; i < argc; i++ )
{ printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL"); }
printf("\n");
#endif
return 0;
}
// ========================================================================================================
// ========================================================================================================
// This routine will return an array of integers associated with a database table that match the SQL_query_str
// passed in as an argument. The array in the struct is allocated dynamically so the caller is responsible for
// freeing it once it is used.
void GetAllocateListOfInts(int max_string_len, sqlite3 *db, char *sql_command_str, SQLIntStruct *int_struct)
{
char *zErrMsg = 0;
int fc;
#ifdef DEBUG
printf("GetAllocateListOfInts(): Called!\n"); fflush(stdout);
#endif
// Initialize the fields before the callback is called.
int_struct->int_arr = NULL;
int_struct->num_ints = 0;
// The callback will be called multiple times, once for each matching database element to sql_command_str.
fc = sqlite3_exec(db, sql_command_str, SQL_GetAllocateListOfInts_callback, int_struct, &zErrMsg);
if ( fc != SQLITE_OK )
{ printf("SQL ERROR: %s\n", zErrMsg); sqlite3_free(zErrMsg); exit(EXIT_FAILURE); }
return;
}
// ========================================================================================================
// ========================================================================================================
// ========================================================================================================
// Update NumPNs field in the VecPairs record with 'num_vals_per_vecpair'. Called from enrollDB.c
void UpdateVecPairsNumPNsField(int max_string_len, sqlite3 *db, int num_vals_per_vecpair, int vecpair_index)
{
char sql_command_str[max_string_len];
char *zErrMsg = 0;
int fc;
#ifdef DEBUG
printf("UpdateVecPairsNumPNsField(): Replacing NumPNs for vecpair_index %d with %d\n", vecpair_index, num_vals_per_vecpair); fflush(stdout);
#endif
sprintf(sql_command_str, "UPDATE VecPairs SET NumPNs = %d WHERE id = %d;", num_vals_per_vecpair, vecpair_index);
// 'sqlite3_exec' calls sqlite3_prepare_v2(), sqlite3_step(), and sqlite3_finalize(), and can process multiple ';' separated SQL statements.
// 'callback' function is called for each row produced in the result set. 4th arg is user-specified data. If an error occurs, 'zErrMesg' is
// filled in, otherwise is NULL (if error, it must be freed).
// NOTE: There is no need to have a callback function (is NULL here) because 'UPDATE' does NOT return any result rows.
fc = sqlite3_exec(db, sql_command_str, NULL, 0, &zErrMsg);
if ( fc != SQLITE_OK )
{ printf("SQL ERROR: %s\n", zErrMsg); sqlite3_free(zErrMsg); exit(EXIT_FAILURE); }
return;
}
// ========================================================================================================
// ========================================================================================================
// Get NumPNs field in the VecPair record.
int GetVecPairsNumPNsField(int max_string_len, sqlite3 *db, int vecpair_index)
{
SQLRowStringsStruct row_strings_struct;
char sql_command_str[max_string_len];
int num_PNs_per_vecpair = -1;
char *col1_name = "NumPNs";
sprintf(sql_command_str, "SELECT %s FROM VecPairs WHERE id = %d;", col1_name, vecpair_index);
GetStringsDataForRow(max_string_len, db, sql_command_str, &row_strings_struct);
GetRowResultInt(&row_strings_struct, "GetVecPairsNumPNsField()", 1, 0, col1_name, &num_PNs_per_vecpair);
FreeStringsDataForRow(&row_strings_struct);
#ifdef DEBUG
printf("GetVecPairsNumPNsField(): Got %d for NumPNs for vecpair_index %d\n", num_PNs_per_vecpair, vecpair_index); fflush(stdout);
#endif
return num_PNs_per_vecpair;
}
// ========================================================================================================
// ========================================================================================================
// Get R_F_str field in the VecPair record. Return 0 for 'R' and 1 for 'F'.
int GetVecPairsRiseFallStrField(int max_string_len, sqlite3 *db, int vecpair_index)
{
SQLRowStringsStruct row_strings_struct;
char sql_command_str[max_string_len];
char rise_fall_str[max_string_len];
char *col1_name = "R_F_str";
sprintf(sql_command_str, "SELECT %s FROM VecPairs WHERE id = %d;", col1_name, vecpair_index);
row_strings_struct.num_cols = 0;
GetStringsDataForRow(max_string_len, db, sql_command_str, &row_strings_struct);
GetRowResultString(&row_strings_struct, "GetVecPairsRiseFallStrField()", 1, 0, col1_name, 1, rise_fall_str);
#ifdef DEBUG
printf("GetVecPairsNumPNsField(): Got %s for R_F_str for vecpair_index %d\n", row_strings_struct.ColStringVals[0], vecpair_index); fflush(stdout);
#endif
FreeStringsDataForRow(&row_strings_struct);
// Sanity check on the expected value for this field.
if ( strcmp(rise_fall_str, "R") != 0 && strcmp(rise_fall_str, "F") != 0 )
{
printf("ERROR: GetVecPairsNumPNsField(): Expected to find 'R' or 'F', found %s instead!\n", rise_fall_str);
exit(EXIT_FAILURE);
}
if ( strcmp(rise_fall_str, "R") == 0 )
return 0;
else
return 1;
}
// ========================================================================================================
// ========================================================================================================
// Update NumVecs and NumRiseVecs fields in the Challenges record with parameters. Called from add_challengeDB.c
void UpdateChallengesNumVecFields(int max_string_len, sqlite3 *db, int challenge_index, int tot_vecs, int tot_rise_vecs)
{
char sql_command_str[max_string_len];
char *zErrMsg = 0;
int fc;
#ifdef DEBUG
printf("UpdateChallengesNumVecFields(): Replacing NumVecs and NumRiseVecs for challenge %d with %d and %d\n", challenge_index,
tot_vecs, tot_rise_vecs); fflush(stdout);
#endif
sprintf(sql_command_str, "UPDATE Challenges SET NumVecs = %d, NumRiseVecs = %d WHERE id = %d;", tot_vecs, tot_rise_vecs,
challenge_index);
// NOTE: There is no need to have a callback function (is NULL here) because 'UPDATE' does NOT return any result rows.
fc = sqlite3_exec(db, sql_command_str, NULL, 0, &zErrMsg);
if ( fc != SQLITE_OK )
{ printf("SQL ERROR: %s\n", zErrMsg); sqlite3_free(zErrMsg); exit(EXIT_FAILURE); }
return;
}
// ========================================================================================================
// ========================================================================================================
// Update NumPNs and NumRisePNs fields in the Challenges record with parameters. Called from add_challengeDB.c
void UpdateChallengesNumPNFields(int max_string_len, sqlite3 *db, int challenge_index, int tot_PNs, int tot_rise_PNs)
{
char sql_command_str[max_string_len];
char *zErrMsg = 0;
int fc;
#ifdef DEBUG
printf("UpdateChallengesNumPNFields(): Replacing NumPNs and NumRisePNs for challenge %d with %d and %d\n", challenge_index,
tot_PNs, tot_rise_PNs); fflush(stdout);
#endif
sprintf(sql_command_str, "UPDATE Challenges SET NumPNs = %d, NumRisePNs = %d WHERE id = %d;", tot_PNs, tot_rise_PNs,
challenge_index);
// NOTE: There is no need to have a callback function (is NULL here) because 'UPDATE' does NOT return any result rows.
fc = sqlite3_exec(db, sql_command_str, NULL, 0, &zErrMsg);
if ( fc != SQLITE_OK )
{ printf("SQL ERROR: %s\n", zErrMsg); sqlite3_free(zErrMsg); exit(EXIT_FAILURE); }
return;
}
// ========================================================================================================
// ========================================================================================================
// Get the field values associated with a challenge_index.
void GetChallengeNumVecsNumPNs(int max_string_len, sqlite3 *db, int *num_vecpairs_ptr, int *num_rising_vecpairs_ptr,
int *num_PNs_ptr, int *num_rising_PNs_ptr, int challenge_index)
{
SQLRowStringsStruct row_strings_struct;
char sql_command_str[max_string_len];
char *col1_name = "NumVecs";
char *col2_name = "NumRiseVecs";
char *col3_name = "NumPNs";
char *col4_name = "NumRisePNs";
sprintf(sql_command_str, "SELECT %s, %s, %s, %s FROM Challenges WHERE id = %d;", col1_name, col2_name, col3_name, col4_name,
challenge_index);
GetStringsDataForRow(max_string_len, db, sql_command_str, &row_strings_struct);
GetRowResultInt(&row_strings_struct, "GetChallengeNumVecsNumPNs()", 4, 0, col1_name, num_vecpairs_ptr);
GetRowResultInt(&row_strings_struct, "GetChallengeNumVecsNumPNs()", 4, 1, col2_name, num_rising_vecpairs_ptr);
GetRowResultInt(&row_strings_struct, "GetChallengeNumVecsNumPNs()", 4, 2, col3_name, num_PNs_ptr);
GetRowResultInt(&row_strings_struct, "GetChallengeNumVecsNumPNs()", 4, 3, col4_name, num_rising_PNs_ptr);
FreeStringsDataForRow(&row_strings_struct);
#ifdef DEBUG
printf("GetChallengeNumVecsNumPNs(): Got num_vecpairs %d, num_rising_vecpairs %d, num_PNs %d and num_rising_PNs %d for Challenge index %d\n",
*num_vecpairs_ptr, *num_rising_vecpairs_ptr, *num_PNs_ptr, *num_rising_PNs_ptr, challenge_index); fflush(stdout);
#endif
return;
}
// ========================================================================================================
// ========================================================================================================
// Look up the Challenge and get it's parameters.
void GetChallengeParams(int max_string_len, sqlite3 *db, char *ChallengeSetName, int *challenge_index_ptr,
int *num_vecpairs_ptr, int *num_rising_vecpairs_ptr, int *num_qualified_PNs_ptr, int *num_rise_qualified_PNs_ptr)
{
// Get the index for this challenge.
if ( (*challenge_index_ptr = GetIndexFromTable(max_string_len, db, "Challenges", SQL_Challenges_get_index_cmd, NULL, 0, ChallengeSetName,
NULL, NULL, NULL, -1, -1, -1)) == -1 )
{
printf("ERROR: GetChallengeParams(): Failed to find challenge index for ChallengeSetName '%s' in Challenge table!\n", ChallengeSetName);
exit(EXIT_FAILURE);
}
// Get the NumVecs and NumPNs fields from challenge
GetChallengeNumVecsNumPNs(max_string_len, db, num_vecpairs_ptr, num_rising_vecpairs_ptr, num_qualified_PNs_ptr,
num_rise_qualified_PNs_ptr, *challenge_index_ptr);
return;
}
// ========================================================================================================
// ========================================================================================================
// Get Ave field in the TimingVals record. I started storing the Ave and TSig fields as integers, multiplied
// by 16 (fixed point) on 9/28/2018. Here we fetch the integer value as a floating point and then scale it
// to an actual floating point by dividing by 16.
float GetTimingValsAveField(int max_string_len, sqlite3 *db, int PUF_instance_index, int vecpair_index, int PO_num)
{
SQLRowStringsStruct row_strings_struct;
char sql_command_str[max_string_len];
char *col1_name = "Ave";
float ave_val;
sprintf(sql_command_str, "SELECT %s FROM TimingVals WHERE PUFInstance = %d AND VecPair = %d AND PO = %d;", col1_name,
PUF_instance_index, vecpair_index, PO_num);
GetStringsDataForRow(max_string_len, db, sql_command_str, &row_strings_struct);
GetRowResultFloat(&row_strings_struct, "GetTimingValsAveField()", 1, 0, col1_name, &ave_val);
FreeStringsDataForRow(&row_strings_struct);
// FIXED POINT
ave_val /= 16.0;
#ifdef DEBUG
printf("GetTimingValsAveField(): Got %f for Ave for PUFInstance ID %d, vecpair index %d, PO %d\n", ave_val, PUF_instance_index,
vecpair_index, PO_num); fflush(stdout);
#endif
return ave_val;
}
// ========================================================================================================
// ========================================================================================================
// Get TSig field in the TimingVals record. I started storing the Ave and TSig fields as integers, multiplied
// by 16 (fixed point) on 9/28/2018. Here we fetch the integer value as a floating point and then scale it
// to an actual floating point by dividing by 16.
float GetTimingValsTSigField(int max_string_len, sqlite3 *db, int PUF_instance_index, int vecpair_index, int PO_num)
{
SQLRowStringsStruct row_strings_struct;
char sql_command_str[max_string_len];
float tsig_val = -1.0;
char *col1_name = "TSig";
sprintf(sql_command_str, "SELECT %s FROM TimingVals WHERE PUFInstance = %d AND VecPair = %d AND PO = %d;", col1_name,
PUF_instance_index, vecpair_index, PO_num);
row_strings_struct.num_cols = 0;
GetStringsDataForRow(max_string_len, db, sql_command_str, &row_strings_struct);
GetRowResultFloat(&row_strings_struct, "GetTimingValsTSigField()", 1, 0, col1_name, &tsig_val);
FreeStringsDataForRow(&row_strings_struct);
tsig_val /= 16.0;
#ifdef DEBUG
printf("GetTimingValsTSigField(): Got %f for TSig for PUFInstance ID %d, vecpair index %d, PO %d\n", tsig_val, PUF_instance_index,
vecpair_index, PO_num); fflush(stdout);
#endif
return tsig_val;
}
// ========================================================================================================
// ========================================================================================================
// Get PUFInstances that match search criteria. Trying to get database table names out of application code.
// Note, wildcard '*' can be used for PUF_instance_name to get all elements.
void GetPUFInstanceIDsForInstanceName(int max_string_len, sqlite3 *db, SQLIntStruct *PUF_instance_index_struct_ptr,
char *PUF_instance_name)
{
char sql_command_str[max_string_len];
//printf("PUF_instance_name to match '%s'\n", PUF_instance_name); fflush(stdout);
// NOTE: Use '%' for * and '_' for ?, e.g., '%' matches everything, 'C%' matches everything that starts with a
// 'c' or 'C' (unless you set 'PRAGMA case_sensitive_like = true;').
sprintf(sql_command_str, "SELECT ID FROM PUFInstance WHERE Instance_name LIKE '%s' ORDER BY ID ASC;", PUF_instance_name);
GetAllocateListOfInts(max_string_len, db, sql_command_str, PUF_instance_index_struct_ptr);
return;
}
// ========================================================================================================
// ========================================================================================================
// Retrieve the string information about the PUFInstance ID given as parameter.
void GetPUFInstanceInfoForID(int max_string_len, sqlite3 *db, int PUFInstance_id, char *Instance_name, char *Dev,
char *Placement)
{
SQLRowStringsStruct row_strings_struct;
char sql_command_str[max_string_len];
char *col1_name = "Instance_name";
char *col2_name = "Dev";
char *col3_name = "Placement";
sprintf(sql_command_str, "SELECT %s, %s, %s FROM PUFInstance WHERE id = %d;", col1_name, col2_name, col3_name, PUFInstance_id);
GetStringsDataForRow(max_string_len, db, sql_command_str, &row_strings_struct);
GetRowResultString(&row_strings_struct, "GetPUFInstanceInfoForID", 3, 0, col1_name, -1, Instance_name);
GetRowResultString(&row_strings_struct, "GetPUFInstanceInfoForID", 3, 1, col2_name, -1, Dev);
GetRowResultString(&row_strings_struct, "GetPUFInstanceInfoForID", 3, 2, col3_name, -1, Placement);
FreeStringsDataForRow(&row_strings_struct);
return;
}
// ========================================================================================================
// ========================================================================================================
// Get num_PIs and num_POs fields associated with the PUFDesign index.
void GetPUFDesignNumPIPOFields(int max_string_len, sqlite3 *db, int *num_PIs_ptr, int *num_POs_ptr, int design_index)
{
SQLRowStringsStruct row_strings_struct;
char sql_command_str[max_string_len];
char *col1_name = "num_PIs";
char *col2_name = "num_POs";
sprintf(sql_command_str, "SELECT %s, %s FROM PUFDesign WHERE id = %d;", col1_name, col2_name, design_index);
GetStringsDataForRow(max_string_len, db, sql_command_str, &row_strings_struct);
GetRowResultInt(&row_strings_struct, "GetPUFDesignNumPIPOFields()", 2, 0, col1_name, num_PIs_ptr);
GetRowResultInt(&row_strings_struct, "GetPUFDesignNumPIPOFields()", 2, 1, col2_name, num_POs_ptr);
FreeStringsDataForRow(&row_strings_struct);
#ifdef DEBUG
printf("GetPUFDesignNumPIPOFields(): Got num_PIs %d and num_POs %d for PUFDesign index %d\n", *num_PIs_ptr, *num_POs_ptr, design_index); fflush(stdout);
#endif
return;
}
// ========================================================================================================
// ========================================================================================================
// Look up the PUFDesign and get it's parameters.
int GetPUFDesignParams(int max_string_len, sqlite3 *db, char *Netlist_name, char *Synthesis_name, int *design_index_ptr,
int *num_PIs_ptr, int *num_POs_ptr)
{
if ( (*design_index_ptr = GetIndexFromTable(max_string_len, db, "PUFDesign", SQL_PUFDesign_get_index_cmd, NULL, 0,
Netlist_name, Synthesis_name, NULL, NULL, -1, -1, -1)) == -1 )
{
// printf("INFO: GetPUFDesignParams(): PUFDesign index NOT found for '%s', '%s'!\n", Netlist_name, Synthesis_name);
return -1;
}
// Get the num_PIs and num_POs values for this design.
GetPUFDesignNumPIPOFields(max_string_len, db, num_PIs_ptr, num_POs_ptr, *design_index_ptr);
return 0;
}
// ========================================================================================================
// ========================================================================================================
// Read blobs, e.g., binary vectors from DB. Note, space MUST be allocated in the caller for 'binary_vec'.
// Added 'allocate_storage' on 5/3/2019 for HOST.
int ReadBinaryBlob(sqlite3 *db, const char *sql_command_str, int id, unsigned char *binary_blob, int expected_size,
int allocate_storage, unsigned char **binary_blob_ptr)
{
int num_bytes_binary_blob = 0;
sqlite3_stmt *pStmt;
int rc;
// If allocate_storage is 0, then storage has already been allocated. In case there is no table entry for id or an error occurs.
if ( allocate_storage == 0 )
{
// Sanity check
if ( binary_blob == NULL )
{ printf("ERROR: ReadBinaryBlob(): UNEXPECTED: Incoming binary_blob is NULL\n"); exit(EXIT_FAILURE); }
binary_blob[0] = '\0';
}
// Compile the SELECT statement into a virtual machine.
do
{
rc = sqlite3_prepare_v2(db, sql_command_str, strlen(sql_command_str) + 1, &pStmt, 0);
if( rc != SQLITE_OK )
{ printf("ERROR: ReadBinaryBlob(): 'sqlite3_prepare_v2' failed\n"); exit(EXIT_FAILURE); }
// Bind the Blob, e.g., binary vector, to the SQL variable.
sqlite3_bind_int(pStmt, 1, id);
// Run the virtual machine. The SQL statement prepared MUST return at most 1 row of data since we call sqlite3_step() ONLY once
// here. Normally, we would keep calling sqlite3_step until it returned something other than SQLITE_ROW, e.g., SQLITE_DONE.
// Multiple kinds of errors can occur as well -- see doc.
rc = sqlite3_step(pStmt);
if ( rc == SQLITE_ROW )
{
// The pointer returned by sqlite3_column_blob() points to memory that is owned by the statement handle (pStmt). It is only good
// until the next call to an sqlite3_XXX() function (e.g. the sqlite3_finalize() below) that involves the statement handle.
// So we need to make a copy of the blob into memory obtained from malloc() to return to the caller.
num_bytes_binary_blob = sqlite3_column_bytes(pStmt, 0);
// Added 5/3/2019 for HOST
if ( allocate_storage == 0 )
{
if ( num_bytes_binary_blob != expected_size )
{ printf("ERROR: ReadBinaryBlob(): UNEXPECTED return size from vector! %d vs expected %d\n", num_bytes_binary_blob, expected_size); exit(EXIT_FAILURE); }
memcpy(binary_blob, sqlite3_column_blob(pStmt, 0), num_bytes_binary_blob);
}
else
{
if ( (*binary_blob_ptr = (unsigned char *)calloc(num_bytes_binary_blob, sizeof(unsigned char))) == NULL )
{ printf("ReadBinaryBlob(): ERROR: Failed to allocate storage for binary_blob of %d bytes\n", num_bytes_binary_blob); exit(EXIT_FAILURE); }
memcpy(*binary_blob_ptr, sqlite3_column_blob(pStmt, 0), num_bytes_binary_blob);
}
}
// NOT the only possibility, SQLITE_BUSY, SQLITE_DONE, etc. are possible.
else
{ printf("ReadBinaryBlob(): ERROR: UNEXPECTED return value for sqlite3_step() -- More than one row in the results perhaps? %d\n", rc); exit(EXIT_FAILURE); }
// Finalize the statement (this releases resources allocated by sqlite3_prepare() ).
rc = sqlite3_finalize(pStmt);
// If sqlite3_finalize() returned SQLITE_SCHEMA, then try to execute the statement all over again.
} while( rc == SQLITE_SCHEMA );
if ( rc != SQLITE_OK )
{ printf("ReadBinaryBlob(): ERROR: Some other error condition %d\n", rc); exit(EXIT_FAILURE); }
return num_bytes_binary_blob;
}
// ========================================================================================================
// ========================================================================================================
// Search a table for a match to the input args. Return its index.
int GetIndexFromTable(int max_string_len, sqlite3 *db, char *Table, const char *SQL_cmd, unsigned char *blob,
int blob_size_bytes, char *text1, char *text2, char *text3, char *text4, int int1, int int2, int int3)
{
sqlite3_stmt *pStmt;
int rc, fc;
int index;
#ifdef DEBUG
printf("GetIndexFromTable(): SQL cmd %s\n", SQL_cmd); fflush(stdout);
#endif
// Prepare 'pStmt' with SQL query.
rc = sqlite3_prepare_v2(db, SQL_cmd, strlen(SQL_cmd) + 1, &pStmt, 0);
if( rc != SQLITE_OK )
{ printf("ERROR: GetIndexFromTable(): 'sqlite3_prepare_v2' failed with %d\n", rc); exit(EXIT_FAILURE); }
// Bind the variables to '?' in 'SQL_cmd'.
if ( strcmp(Table, "PUFDesign") == 0 )
{
sqlite3_bind_text(pStmt, 1, text1, -1, SQLITE_STATIC);
sqlite3_bind_text(pStmt, 2, text2, -1, SQLITE_STATIC);
}
else if ( strcmp(Table, "PUFInstance") == 0 )
{
sqlite3_bind_text(pStmt, 1, text1, -1, SQLITE_STATIC);
sqlite3_bind_text(pStmt, 2, text2, -1, SQLITE_STATIC);
sqlite3_bind_text(pStmt, 3, text3, -1, SQLITE_STATIC);
}
else if ( strcmp(Table, "VecPairs") == 0 )
{
sqlite3_bind_int(pStmt, 1, int1);
sqlite3_bind_int(pStmt, 2, int2);
sqlite3_bind_int(pStmt, 3, int3);
}
else if ( strcmp(Table, "Vectors") == 0 )
sqlite3_bind_blob(pStmt, 1, blob, blob_size_bytes, SQLITE_STATIC);
else if ( strcmp(Table, "PathSelectMasks") == 0 )
sqlite3_bind_text(pStmt, 1, text1, -1, SQLITE_STATIC);
else if ( strcmp(Table, "Challenges") == 0 )
sqlite3_bind_text(pStmt, 1, text1, -1, SQLITE_STATIC);
else if ( strcmp(Table, "ChallengeVecPairs") == 0 )
{
sqlite3_bind_int(pStmt, 1, int1);
sqlite3_bind_int(pStmt, 2, int2);
sqlite3_bind_int(pStmt, 3, int3);
}
else
{ printf("ERROR: GetIndexFromTable(): Unknown Table '%s'\n", Table); exit(EXIT_FAILURE); }
// Run the virtual machine. The SQL statement prepared MUST return at most 1 row of data since we call sqlite3_step() ONLY once
// here. Normally, we would keep calling sqlite3_step until it returned something other than SQLITE_ROW. Multiple kinds of errors
// can occur as well -- see doc.
rc = sqlite3_step(pStmt);
#ifdef DEBUG
printf("GetIndexFromTable(): Table '%s', Column cnt %d\n", Table, sqlite3_column_count(pStmt)); fflush(stdout);
printf("GetIndexFromTable(): Table '%s', Column type %d => Integer type %d\n", Table, sqlite3_column_type(pStmt, 0), SQLITE_INTEGER); fflush(stdout);
#endif
index = sqlite3_column_int64(pStmt, 0);
if ( (fc = sqlite3_finalize(pStmt)) != 0 )
{ printf("ERROR: GetIndexFromTable(): Finalize failed %d for Table '%s'\n", fc, Table); exit(EXIT_FAILURE); }
// Classify the return code. 'DONE' means search failed while 'ROW' means it found the item.
if ( rc == SQLITE_DONE )
{
// printf("WARNING: GetIndexFromTable(): Search string NOT FOUND in Table '%s': Return code %d\n", Table, rc); fflush(stdout);
index = -1;
}
else if ( rc != SQLITE_ROW )
{ printf("ERROR: GetIndexFromTable(): Return code for 'sqlite3_step' not SQLITE_DONE or SQLITE_ROW => %d for Table '%s'\n", rc, Table); exit(EXIT_FAILURE); }
#ifdef DEBUG
printf("GetIndexFromTable(): Index %d for Table '%s'\n", index, Table); fflush(stdout);
#endif