@ -10,93 +10,90 @@ module L = Logging
module F = Format
module F = Format
module Implementation = struct
module Implementation = struct
let attribute_replace_statement =
let replace_attributes =
(* The innermost SELECT returns either the current attributes_kind and source_file associated with
let attribute_replace_statement =
the given proc name , or default values of ( - 1 , " " ) . These default values have the property that
(* The innermost SELECT returns either the current attributes_kind and source_file associated with
they are always " less than " any legit value . More precisely , MAX ensures that some value is
the given proc name , or default values of ( - 1 , " " ) . These default values have the property that
returned even if there is no row satisfying WHERE ( we'll get NULL in that case , the value in
they are always " less than " any legit value . More precisely , MAX ensures that some value is
the row otherwise ) . COALESCE then returns the first non - NULL value , which will be either the
returned even if there is no row satisfying WHERE ( we'll get NULL in that case , the value in
value of the row corresponding to that pname in the DB , or the default if no such row exists .
the row otherwise ) . COALESCE then returns the first non - NULL value , which will be either the
value of the row corresponding to that pname in the DB , or the default if no such row exists .
The next ( second - outermost ) SELECT filters out that value if it is " more defined " than the ones
we would like to insert ( which will never be the case if the default values are returned ) . If
The next ( second - outermost ) SELECT filters out that value if it is " more defined " than the ones
not , it returns a trivial row ( consisting solely of NULL since we don't use its values ) and the
we would like to insert ( which will never be the case if the default values are returned ) . If
INSERT OR REPLACE will proceed and insert or update the values stored into the DB for that
not , it returns a trivial row ( consisting solely of NULL since we don't use its values ) and the
pname . * )
INSERT OR REPLACE will proceed and insert or update the values stored into the DB for that
(* TRICK: use the source file to be more deterministic in case the same procedure name is defined
pname . * )
in several files * )
(* TRICK: use the source file to be more deterministic in case the same procedure name is defined
(* TRICK: older versions of sqlite ( prior to version 3.15.0 ( 2016-10-14 ) ) do not support row
in several files * )
values so the lexicographic ordering for ( : akind , : sfile ) is done by hand * )
(* TRICK: older versions of sqlite ( prior to version 3.15.0 ( 2016-10-14 ) ) do not support row
ResultsDatabase . register_statement
values so the lexicographic ordering for ( : akind , : sfile ) is done by hand * )
{ |
ResultsDatabase . register_statement
INSERT OR REPLACE INTO procedures
{ |
SELECT : pname , : proc_name_hum , : akind , : sfile , : pattr , : cfg , : callees
INSERT OR REPLACE INTO procedures
FROM (
SELECT : pname , : proc_name_hum , : akind , : sfile , : pattr , : cfg , : callees
SELECT NULL
FROM (
FROM (
SELECT COALESCE ( MAX ( attr_kind ) , - 1 ) AS attr_kind ,
SELECT NULL
COALESCE ( MAX ( source_file ) , " " ) AS source_file
FROM (
FROM procedures
SELECT COALESCE ( MAX ( attr_kind ) , - 1 ) AS attr_kind ,
WHERE proc_name = : pname )
COALESCE ( MAX ( source_file ) , " " ) AS source_file
WHERE attr_kind < : akind
FROM procedures
OR ( attr_kind = : akind AND source_file < = : sfile ) )
WHERE proc_name = : pname )
| }
WHERE attr_kind < : akind
OR ( attr_kind = : akind AND source_file < = : sfile ) )
| }
let replace_attributes ~ pname_str ~ pname ~ akind ~ source_file ~ attributes ~ proc_desc ~ callees =
in
ResultsDatabase . with_registered_statement attribute_replace_statement ~ f : ( fun db replace_stmt ->
fun ~ pname_str ~ pname ~ akind ~ source_file ~ attributes ~ proc_desc ~ callees ->
Sqlite3 . bind replace_stmt 1 (* :pname *) pname
ResultsDatabase . with_registered_statement attribute_replace_statement
| > SqliteUtils . check_result_code db ~ log : " replace bind pname " ;
~ f : ( fun db replace_stmt ->
Sqlite3 . bind replace_stmt 2 (* :proc_name_hum *) ( Sqlite3 . Data . TEXT pname_str )
Sqlite3 . bind replace_stmt 1 (* :pname *) pname
| > SqliteUtils . check_result_code db ~ log : " replace bind proc_name_hum " ;
| > SqliteUtils . check_result_code db ~ log : " replace bind pname " ;
Sqlite3 . bind replace_stmt 3 (* :akind *) ( Sqlite3 . Data . INT akind )
Sqlite3 . bind replace_stmt 2 (* :proc_name_hum *) ( Sqlite3 . Data . TEXT pname_str )
| > SqliteUtils . check_result_code db ~ log : " replace bind attribute kind " ;
| > SqliteUtils . check_result_code db ~ log : " replace bind proc_name_hum " ;
Sqlite3 . bind replace_stmt 4 (* :sfile *) source_file
Sqlite3 . bind replace_stmt 3 (* :akind *) ( Sqlite3 . Data . INT akind )
| > SqliteUtils . check_result_code db ~ log : " replace bind source file " ;
| > SqliteUtils . check_result_code db ~ log : " replace bind attribute kind " ;
Sqlite3 . bind replace_stmt 5 (* :pattr *) attributes
Sqlite3 . bind replace_stmt 4 (* :sfile *) source_file
| > SqliteUtils . check_result_code db ~ log : " replace bind proc attributes " ;
| > SqliteUtils . check_result_code db ~ log : " replace bind source file " ;
Sqlite3 . bind replace_stmt 6 (* :cfg *) proc_desc
Sqlite3 . bind replace_stmt 5 (* :pattr *) attributes
| > SqliteUtils . check_result_code db ~ log : " replace bind cfg " ;
| > SqliteUtils . check_result_code db ~ log : " replace bind proc attributes " ;
Sqlite3 . bind replace_stmt 7 (* :callees *) callees
Sqlite3 . bind replace_stmt 6 (* :cfg *) proc_desc
| > SqliteUtils . check_result_code db ~ log : " replace bind callees " ;
| > SqliteUtils . check_result_code db ~ log : " replace bind cfg " ;
SqliteUtils . result_unit db ~ finalize : false ~ log : " Attributes.replace " replace_stmt )
Sqlite3 . bind replace_stmt 7 (* :callees *) callees
| > SqliteUtils . check_result_code db ~ log : " replace bind callees " ;
SqliteUtils . result_unit db ~ finalize : false ~ log : " Attributes.replace " replace_stmt )
let source_file_store_statement =
ResultsDatabase . register_statement
{ |
let add_source_file =
INSERT OR REPLACE INTO source_files
let source_file_store_statement =
VALUES ( : source , : tenv , : integer_type_widths , : proc_names , : freshly_captured )
ResultsDatabase . register_statement
| }
{ |
INSERT OR REPLACE INTO source_files
VALUES ( : source , : tenv , : integer_type_widths , : proc_names , : freshly_captured )
let add_source_file ~ source_file ~ tenv ~ integer_type_widths ~ proc_names =
| }
ResultsDatabase . with_registered_statement source_file_store_statement ~ f : ( fun db store_stmt ->
in
Sqlite3 . bind store_stmt 1 source_file
fun ~ source_file ~ tenv ~ integer_type_widths ~ proc_names ->
(* :source *)
ResultsDatabase . with_registered_statement source_file_store_statement ~ f : ( fun db store_stmt ->
| > SqliteUtils . check_result_code db ~ log : " store bind source file " ;
Sqlite3 . bind store_stmt 1 source_file
Sqlite3 . bind store_stmt 2 tenv
(* :source *)
(* :tenv *)
| > SqliteUtils . check_result_code db ~ log : " store bind source file " ;
| > SqliteUtils . check_result_code db ~ log : " store bind type environment " ;
Sqlite3 . bind store_stmt 2 tenv
Sqlite3 . bind store_stmt 3 integer_type_widths
(* :tenv *)
(* :integer_type_widths *)
| > SqliteUtils . check_result_code db ~ log : " store bind type environment " ;
| > SqliteUtils . check_result_code db ~ log : " store bind integer type widths " ;
Sqlite3 . bind store_stmt 3 integer_type_widths
Sqlite3 . bind store_stmt 4 proc_names
(* :integer_type_widths *)
(* :proc_names *)
| > SqliteUtils . check_result_code db ~ log : " store bind integer type widths " ;
| > SqliteUtils . check_result_code db ~ log : " store bind proc names " ;
Sqlite3 . bind store_stmt 4 proc_names
Sqlite3 . bind store_stmt 5 ( Sqlite3 . Data . INT Int64 . one )
(* :proc_names *)
(* :freshly_captured *)
| > SqliteUtils . check_result_code db ~ log : " store bind proc names " ;
| > SqliteUtils . check_result_code db ~ log : " store freshness " ;
Sqlite3 . bind store_stmt 5 ( Sqlite3 . Data . INT Int64 . one )
SqliteUtils . result_unit ~ finalize : false ~ log : " Cfg.store " db store_stmt )
(* :freshly_captured *)
| > SqliteUtils . check_result_code db ~ log : " store freshness " ;
SqliteUtils . result_unit ~ finalize : false ~ log : " Cfg.store " db store_stmt )
let mark_all_source_files_stale_statement =
ResultsDatabase . register_statement " UPDATE source_files SET freshly_captured = 0 "
let mark_all_source_files_stale () =
let mark_all_source_files_stale () =
ResultsDatabase . with_registered_statement mark_all_source_files_stale_statement
ResultsDatabase . get_database ()
~ f : ( fun db stmt -> SqliteUtils . result_unit db ~ finalize : false ~ log : " mark_all_stale " stmt )
| > SqliteUtils . exec ~ stmt : " UPDATE source_files SET freshly_captured = 0 " ~ log : " mark_all_stale "
let merge_procedures_table ~ db_file =
let merge_procedures_table ~ db_file =