# # This contains code for managing snapons (adding and removing them from a profile) # include "lib.database"; include "lib.profile"; #include "lib.profile_setup.util"; # # get_unique_node_name() # # Purpose: This gets a unique name of the form N where is specified and N is chosen to be the lowest # integer > 1, that gives a node name not found in the specified now. # # Parameters: n: the node to look in # name: the desired name of the node # returns name if it does not exist in n, or nameN where N is an integer and nameN does not exist in n # subroutine(get_unique_node_name(node n, string name), ( # If there is no node using the desired name, just use that name. if (!n?{name}) then name; # Otherwise, count up until we find an unused node with the name we wanted, plus an integer else ( int num = 2; while (n?{name . '_' . num}) num++; name . '_' . num; ); # if name used )); #### get_unique_node_name() #### # # set_node_with_default() # # Purpose: This copies a particular subnode value from the snapon node to the final node, using a default if it doesn't exist # # Parameters: snapon: the snapon instance # profile_node: the node in the profile # snapon_node: the node in the snapon # name: the subnode name # value: the default value, or "" if the subnode must exist in snapon_node # # formerly set_node_with_default subroutine(set_node_with_default(node snapon, node profile_node, node snapon_node, string name, string value), ( if (snapon_node?{name}) then ( # if (starts_with(@report_element{name}, "variable:")) then ( # string resolved_variable = resolve_variable(snapon, @report_element{name}); # @profile_report_element{name} = resolved_variable; ## error("variable detected: " . @report_element{name}); # ); # else ( @profile_node{name} = @snapon_node{name}; # ); ); else ( if (value eq "") then error("Snapon: Required report element parameter " . name . " not specified in snapon"); else @profile_node{name} = value; ); )); #### set_node_with_default() #### # # add_in_snapon() # # Purpose: This determines whether to add this element in a snapon, by looking at the add_in_snapon subnode # subroutine(add_in_snapon(node n), ( (!(n?{'add_in_snapon'}) or @n{'add_in_snapon'}); )); # add_in_snapon() # # resolve_variables() # # Purpose: This resolves any variables/parameters in the node we're attaching # # Parameters: n: the node to resolve variables in # parameters: the parameters node # subroutine(resolve_variables(node n, node parameters), ( # echo("Resolving: " . node_as_string(n)); # Evaluate (expand) all Salang section in the node name while (matches_regular_expression(node_name(n), "^(.*)[{]=(.*)$")) ( string prefix = $1; string suffix = $2; if (matches_regular_expression(suffix, "^(.*)=[}](.*)$")) then ( suffix = $2; string expression = $1; node compiled_expression = compile(expression); string evaluated_expression = evaluate(compiled_expression); #echo("Resolved (node name): " . expression . " -> " . evaluated_expression); if (evaluated_expression eq "") then error("Empty value for resolved snapon expression '" . expression . "'; node name expressions cannot resolve to empty"); rename_node(n, prefix . evaluated_expression . suffix); ); else ( error("No closing =} in snapon expression: " . @n); ); ); # while node name contains Salang # Evaluate (expand) all Salang section in the node value while (matches_regular_expression(@n, "^(.*)[{]=(.*)$")) ( string prefix = $1; string suffix = $2; if (matches_regular_expression(suffix, "^(.*)=[}](.*)$")) then ( suffix = $2; string expression = $1; #echo("prefix=" . prefix); #echo("suffix=" . suffix); #echo("expression=" . expression); node compiled_expression = compile(expression); string evaluated_expression = evaluate(compiled_expression); #echo("Resolved: " . expression . " -> " . evaluated_expression); # if (evaluated_expression eq "") then # echo("Warning: Empty value for resolved expression '" . expression . "'"); @n = prefix . evaluated_expression . suffix; ); else ( error("No closing =} in snapon expression: " . @n); ); ); # while node value contains Salang # Recursively evaluate the subnodes node subn; foreach subn n ( resolve_variables(subn, parameters); ); #echo("done resolving"); )); #### resolve_variables() #### # # resolve_escaped_salang_sections() # # Purpose: This resolves any {x= =x} sections into { = = }. # # Parameters: n: the node to resolve variables in # subroutine(resolve_escaped_salang_sections(node n), ( # echo("Resolving escaped Salang: " . node_as_string(n)); # Replace all {x= with { =, an all =x} with = } if (contains(@n, "{x=")) then ( @n = replace_all(@n, "{x=", "{="); @n = replace_all(@n, "=x}", "=}"); ); # if node value contains {x= # Recursively evaluate the subnodes node subn; foreach subn n ( resolve_escaped_salang_sections(subn); ); )); #### resolve_escaped_salang_sections() #### # # snapon_add_database_fields() # # Purpose: This adds a database field to a profile, using a snapon node operation # # Parameters: profile: the profile to add to # attach_operation: the snapon add_database_fields operation node # detach_operations: the node of detach operations to build (how to undo this attach operation) # subroutine(snapon_add_database_fields(node snapon, node profile, node attach_operation, node detach_operations), ( node fields = attach_operation{"fields"}; node field; node profile_database_fields = profile{"database"}{"fields"}; # echo("profile_database_fields BEFORE: " . node_as_string(profile_database_fields)); # Remember the detach information string detach_operation_name = get_unique_node_name(detach_operations, "op"); node detach_operation = detach_operations{detach_operation_name}; @detach_operation{"type"} = "remove_database_fields"; # Add all specified database fields foreach field fields ( if (add_in_snapon(field)) then ( # Add the database field node to the profile # echo("field: " . node_as_string(field)); if (profile_database_fields?{node_name(field)}) then error("Snapon attempted to add database field '" . node_name(field) . "', which already exists"); string name = get_unique_node_name(profile_database_fields, node_name(field)); node field_clone = clone_node(field); rename_node(field_clone, name); string label = get_default_field_label(name, "none"); #echo("label: " . label); # Set node defaults set_node_with_default(snapon, field_clone, field_clone, "type", "string"); set_node_with_default(snapon, field_clone, field_clone, "label", label); set_node_with_default(snapon, field_clone, field_clone, "derivation_method", "log_field"); set_node_with_default(snapon, field_clone, field_clone, "category", ""); set_node_with_default(snapon, field_clone, field_clone, "log_field", name); set_node_with_default(snapon, field_clone, field_clone, "aggregation_method", "none"); set_node_with_default(snapon, field_clone, field_clone, "index", false); set_node_with_default(snapon, field_clone, field_clone, "suppress_top", 0); set_node_with_default(snapon, field_clone, field_clone, "suppress_bottom", 2); set_node_with_default(snapon, field_clone, field_clone, "always_include_bottom_level_items", false); set_node_with_default(snapon, field_clone, field_clone, "integer_bits", 0); set_node_with_default(snapon, field_clone, field_clone, "itemnums_hash_function", "rand_sum"); set_node_with_default(snapon, field_clone, field_clone, "sql_field_length", 200); insert_node(profile_database_fields, field_clone, num_subnodes(profile_database_fields)); # echo("Added database field '" . node_name(field) . "'"); bool has_source_dbfield = field?{"source_database_field"}; # Get the database info node database_info = get_database_info(node_name(profile), false); # echo("database info: " . node_as_string(database_info)); #echo("field_clone: " . node_as_string(field_clone)); # Add the database field column to main_table, if it exists, and if it's not sourced from another field if (!has_source_dbfield) then ( if (database_info?{"database_is_ready_for_reporting"}) then ( if (database_table_exists(get_database_table_name(profile, "main_table"))) then ( string sql_field_type = @field_clone{"type"}; if (sql_field_type eq "unique") then sql_field_type = "int"; else if (sql_field_type eq "string") then sql_field_type = "int"; string query = "alter table " . get_database_table_name(profile, "main_table") . " add " . node_name(field) . " " . sql_field_type; # echo(query); database_sql_query(query, true, false); ); ); ); # if !has_source_dbfield @detach_operation{"fields"}{name} = ""; ); # if add field ); # foreach fields # echo("profile_database_fields AFTER: " . node_as_string(profile_database_fields)); # error("add_snapon: add_database_fields unimplemented"); )); #### snapon_add_database_fields() #### # # snapon_remove_database_fields() # # Purpose: This removes a database field from a profile, using a snapon node operation # # Parameters: profile: the profile to remove to # attach_operation: the snapon remove_database_fields operation node # subroutine(snapon_remove_database_fields(node profile, node attach_operation), ( node fields = attach_operation{"fields"}; node field; node profile_database_fields = profile{"database"}{"fields"}; node profile_log_fields = profile{"log"}{"fields"}; # echo("profile_database_fields BEFORE: " . node_as_string(profile_database_fields)); # Remove all specified database fields foreach field fields ( # Remove the database field node to the profile # echo("field: " . node_as_string(field)); node database_field_node = profile_database_fields{node_name(field)}; bool has_source_dbfield = database_field_node?{"source_database_field"}; # echo("database_field_node=" . node_as_string(database_field_node)); #echo("has_source_dbfield: " . has_source_dbfield); delete_node(database_field_node); # echo("Removed database field '" . node_name(field) . "'"); # echo("profile_database_fields=" . profile_database_fields); # save_node(profile); #rewrite_database_config(profile); # If there is a log field for this database field, remove it too if (profile_log_fields?{node_name(field)}) then ( node log_field_node = profile_log_fields{node_name(field)}; delete_node(log_field_node); ); # Remove the database field column from main_table, if it exists, and if it's not sourced from another field if (!has_source_dbfield) then ( if (database_table_exists(get_database_table_name(profile, "main_table"))) then ( string query = "alter table " . get_database_table_name(profile, "main_table") . " drop column " . node_name(field); # echo(query); database_sql_query(query, true, false); ); ); # if !has source dbfield ); # foreach fields # echo("profile_database_fields AFTER: " . node_as_string(profile_database_fields)); )); #### snapon_remove_database_fields() #### # # snapon_add_log_fields() # # Purpose: This adds a log field to a profile, using a snapon node operation # # Parameters: profile: the profile to add to # attach_operation: the snapon add_log_fields operation node # detach_operations: the node of detach operations to build (how to undo this attach operation) # subroutine(snapon_add_log_fields(node snapon, node profile, node attach_operation, node detach_operations), ( #echo("snapon_add_log_fields()"); node fields = attach_operation{"fields"}; node field; node profile_log_fields = profile{"log"}{"fields"}; # echo("profile_log_fields BEFORE: " . node_as_string(profile_log_fields)); # Remember the detach information string detach_operation_name = get_unique_node_name(detach_operations, "op"); node detach_operation = detach_operations{detach_operation_name}; @detach_operation{"type"} = "remove_log_fields"; # Add all specified log fields foreach field fields ( if (add_in_snapon(field)) then ( # Add the log field node to the profile # echo("field: " . node_as_string(field)); if (profile_log_fields?{node_name(field)}) then error("Snapon attempted to add log field '" . node_name(field) . "', which already exists"); string name = get_unique_node_name(profile_log_fields, node_name(field)); node field_clone = clone_node(field); rename_node(field_clone, name); string label = get_default_field_label(name, "none"); # Set node defaults set_node_with_default(snapon, field_clone, field_clone, "label", label); set_node_with_default(snapon, field_clone, field_clone, "type", "flat"); set_node_with_default(snapon, field_clone, field_clone, "index", 0); set_node_with_default(snapon, field_clone, field_clone, "subindex", 0); set_node_with_default(snapon, field_clone, field_clone, "hierarchy_dividers", ""); set_node_with_default(snapon, field_clone, field_clone, "left_to_right", false); set_node_with_default(snapon, field_clone, field_clone, "leading_divider", false); set_node_with_default(snapon, field_clone, field_clone, "case_sensitive", false); insert_node(profile_log_fields, field_clone, num_subnodes(profile_log_fields)); # echo("Added log field '" . node_name(field) . "'"); @detach_operation{"fields"}{name} = ""; ); # if add field ); # foreach fields # echo("profile_log_fields AFTER: " . node_as_string(profile_log_fields)); # error("add_snapon: add_log_fields unimplemented"); )); #### snapon_add_log_fields() #### # # snapon_remove_log_fields() # # Purpose: This removes a log field from a profile, using a snapon node operation # # Parameters: profile: the profile to remove to # attach_operation: the snapon remove_log_fields operation node # subroutine(snapon_remove_log_fields(node profile, node attach_operation), ( node fields = attach_operation{"fields"}; node field; node profile_log_fields = profile{"log"}{"fields"}; node profile_log_fields = profile{"log"}{"fields"}; # echo("profile_log_fields BEFORE: " . node_as_string(profile_log_fields)); # Remove all specified log fields foreach field fields ( # Remove the log field node to the profile # echo("field: " . node_as_string(field)); node log_field_node = profile_log_fields{node_name(field)}; # echo("log_field_node=" . node_as_string(log_field_node)); delete_node(log_field_node); # echo("Removed log field '" . node_name(field) . "'"); # echo("profile_log_fields=" . profile_log_fields); # save_node(profile); #rewrite_log_config(profile); ); # foreach fields # echo("profile_log_fields AFTER: " . node_as_string(profile_log_fields)); )); #### snapon_remove_log_fields() #### # # snapon_edit_profile_node() # # Purpose: This edits a profile node, using a snapon node operation # # Parameters: profile: the profile to add to # attach_operation: the snapon edit_profile_node operation node # detach_operations: the node of detach operations to build (how to undo this attach operation) # subroutine(snapon_edit_profile_node(node snapon, node profile, node attach_operation, node detach_operations), ( if (add_in_snapon(attach_operation)) then ( string nodepath = @attach_operation{"node"}; string original_value = @profile{nodepath}; string new_value = @attach_operation{"new_value"}; @profile{nodepath} = new_value; # Remember the detach information string detach_operation_name = get_unique_node_name(detach_operations, "op"); node detach_operation = detach_operations{detach_operation_name}; @detach_operation{"type"} = "unedit_profile_node"; @detach_operation{"nodepath"} = nodepath; @detach_operation{"original_value"} = original_value; ); # if add_in_snapon )); #### snapon_edit_profile_node() #### # # snapon_unedit_profile_node() # # Purpose: This removes an edit of a profile node, using a snapon node operation # # Parameters: profile: the profile # attach_operation: the snapon unedit_profile_node operation node # subroutine(snapon_unedit_profile_node(node profile, node detach_operations), ( string nodepath = @detach_operations{"nodepath"}; string original_value = @detach_operations{"original_value"}; @profile{nodepath} = original_value; )); #### snapon_unedit_profile_node() #### # # snapon_add_snapons() # # Purpose: This adds a snapon to a profile, using a snapon node operation # # Parameters: profile: the profile to add to # attach_operation: the snapon add_snapon operation node # detach_operations: the node of detach operations to build (how to undo this attach operation) # subroutine(attach_snapon(node profile, node snapon_node, string attached_snapon_name), ()); subroutine(snapon_add_snapons(node profile, node attach_operation, node detach_operations), ( #echo("snapon_add_snapons()"); node snapons = attach_operation{"snapons"}; node snapon; node profile_snapons = profile{"snapons"}; # echo("profile_snapons BEFORE: " . node_as_string(profile_snapons)); # Remember the detach information string detach_operation_name = get_unique_node_name(detach_operations, "op"); node detach_operation = detach_operations{detach_operation_name}; @detach_operation{"type"} = "remove_snapons"; # Add all specified database snapons node snapon_info; foreach snapon_info snapons ( if (add_in_snapon(snapon_info)) then ( #echo("Got snapon info: " . node_as_string(snapon_info)); # Touch up parameters #echo("Touching up parameters"); node parameters = snapon_info{"parameters"}; node parameter; foreach parameter parameters ( if (parameter?{"final_node_name"} and (@parameter{"parameter_value"} eq "")) then ( #echo("No parameter_value for " . parameter); if ('lang_stats.field_labels'?{@parameter{"final_node_name"}}) then ( @parameter{"parameter_value"} = "$lang_stats.field_labels." . @parameter{"final_node_name"}; #echo("Computed parameter_value=" . @parameter{"parameter_value"}); ); ); ); #echo("Retouched parameters: " . node_as_string(parameters)); # Attach the snapon string snapon_name = @snapon_info{"snapon"}; # Get the name which will be used string snapon_instance_name; if (snapon_info?{"name"}) then snapon_instance_name = @snapon_info{"name"}; else snapon_instance_name = node_name(snapon_info); #echo("snapon_instance_name: " . snapon_instance_name); # string snapon_instance_node_name = get_unique_node_name(profile_snapons, @snapon_info{"name"}); string snapon_instance_node_name = get_unique_node_name(profile_snapons, snapon_instance_name); #echo("snapon_name: " . snapon_name); #echo("snapon_instance_node_name: " . snapon_instance_node_name); # Get the snapon we're going to attach node snapon = clone_node('snapons'{snapon_name}); # If there's no label in snapon_info, use the node name if (!snapon_info?{"label"}) then @snapon_info{"label"} = node_name(snapon_info); # Overlay the information from the plug-in, onto the snapon node overlay_node(snapon, snapon_info); #echo("Attaching snapon [" . snapon_instance_node_name . "]: info=" . node_as_string(snapon_info)); attach_snapon(profile, snapon, snapon_instance_node_name); @detach_operation{"snapons"}{snapon_instance_node_name} = ""; ); # if add_in_snapon ); # foreach snapons #echo("Exiting snapon_add_snapons()"); # echo("profile_database_snapons AFTER: " . node_as_string(profile_database_snapons)); # error("add_snapon: add_database_snapons unimplemented"); )); #### snapon_add_snapons() #### # # snapon_remove_snapons() # # Purpose: This removes a snapon from a profile, using a snapon node operation # # Parameters: profile: the profile to remove to # attach_operation: the snapon remove_snapons operation node # subroutine(detach_snapon_instance(node profile, string snapon_instance_name), ()); subroutine(snapon_remove_snapons(node profile, node attach_operation), ( node snapons = attach_operation{"snapons"}; node snapon; node profile_snapons = profile{"database"}{"snapons"}; node profile_log_snapons = profile{"log"}{"snapons"}; # echo("profile_snapons BEFORE: " . node_as_string(profile_snapons)); # Remove all specified snapons foreach snapon snapons ( # Remove the database snapon node to the profile string snapon_instance_name = node_name(snapon); #echo("Detaching instance " . snapon_instance_name); detach_snapon_instance(profile, snapon_instance_name); ); # foreach snapons # echo("profile_snapons AFTER: " . node_as_string(profile_snapons)); )); #### snapon_remove_snapons() #### # # snapon_execute_expression() # # Purpose: This executes a Salang expression requested by a snapon # # Parameters: profile: the profile # attach_operation: the snapon add_snapon operation node (which contains the expression) # detach_operations: the node of detach operations to build (how to undo this attach operation) # subroutine(snapon_execute_expression(node profile, node attach_operation, node detach_operations), ( # Remember the detach information string detach_operation_name = get_unique_node_name(detach_operations, "op"); node detach_operation = detach_operations{detach_operation_name}; @detach_operation{"type"} = "execute_expression"; @detach_operation{"expression"} = "# no undo of execute_expression"; # Execute the expression string expression = @attach_operation{"expression"}; #echo("expression: " . expression); node compiled_expression = compile(expression); #echo("compiled_expression: " . compiled_expression); evaluate(compiled_expression); )); #### snapon_execute_expression() #### # # snapon_add_database_filters() # # Purpose: This adds a database filter to a profile, using a snapon node operation # # Parameters: profile: the profile to add to # attach_operation: the snapon add_database_filters operation node # detach_operations: the node of detach operations to build (how to undo this attach operation) # subroutine(snapon_add_database_filters(node profile, node attach_operation, node detach_operations), ( node filters = attach_operation{"filters"}; node filter; node profile_database_filters = profile{"database"}{"filters"}; # echo("profile_database_filters BEFORE: " . node_as_string(profile_database_filters)); # Remember the detach information string detach_operation_name = get_unique_node_name(detach_operations, "op"); node detach_operation = detach_operations{detach_operation_name}; @detach_operation{"type"} = "remove_database_filters"; # Add all specified database filters foreach filter filters ( if (add_in_snapon(filter)) then ( # Add the database filter node to the profile # echo("filter: " . node_as_string(filter)); if (profile_database_filters?{node_name(filter)}) then error("Snapon attempted to add database filter '" . node_name(filter) . "', which already exists"); string filter_node_name = get_unique_node_name(profile_database_filters, node_name(filter)); node cloned_filter = clone_node(filter); rename_node(cloned_filter, filter_node_name); insert_node(profile_database_filters, cloned_filter, num_subnodes(profile_database_filters)); # echo("Added database filter '" . node_name(filter) . "'"); @detach_operation{"filters"}{filter_node_name} = ""; ); # if add_in_snapon ); # foreach filters # echo("profile_database_filters AFTER: " . node_as_string(profile_database_filters)); # error("add_snapon: add_database_filters unimplemented"); )); #### snapon_add_database_filters() #### # # snapon_remove_database_filters() # # Purpose: This removes a database filter from a profile, using a snapon node operation # # Parameters: profile: the profile to remove from # attach_operation: the snapon remove_database_filters operation node # subroutine(snapon_remove_database_filters(node profile, node attach_operation), ( node filters = attach_operation{"filters"}; node filter; node profile_database_filters = profile{"database"}{"filters"}; # echo("profile_database_filters BEFORE: " . node_as_string(profile_database_filters)); # Remove all specified database filters foreach filter filters ( # Remove the database filter node to the profile # echo("filter: " . node_as_string(filter)); node database_filter_node = profile_database_filters{node_name(filter)}; delete_node(database_filter_node); # echo("Removed database filter '" . node_name(filter) . "'"); ); # foreach filters # echo("profile_database_filters AFTER: " . node_as_string(profile_database_filters)); )); #### snapon_remove_database_filters() #### # # snapon_add_log_filters() # # Purpose: This adds a log filter to a profile, using a snapon node operation # # Parameters: profile: the profile to add to # attach_operation: the snapon add_log_filters operation node # detach_operations: the node of detach operations to build (how to undo this attach operation) # subroutine(snapon_add_log_filters(node profile, node attach_operation, node detach_operations), ( #echo("attach_operation: " . node_as_string(attach_operation)); node filters = attach_operation{"filters"}; node filter; node profile_log_filters = profile{"log"}{"filters"}; # echo("profile_log_filters BEFORE: " . node_as_string(profile_log_filters)); # Remember the detach information string detach_operation_name = get_unique_node_name(detach_operations, "op"); node detach_operation = detach_operations{detach_operation_name}; @detach_operation{"type"} = "remove_log_filters"; # Add all specified log filters foreach filter filters ( if (add_in_snapon(filter)) then ( # Add the log filter node to the profile # echo("filter: " . node_as_string(filter)); if (profile_log_filters?{node_name(filter)}) then error("Snapon attempted to add log filter '" . node_name(filter) . "', which already exists"); string filter_node_name = get_unique_node_name(profile_log_filters, node_name(filter)); node cloned_filter = clone_node(filter); rename_node(cloned_filter, filter_node_name); int add_position; if (filter?{"add_position"}) then add_position = @filter{"add_position"}; else add_position = num_subnodes(profile_log_filters); insert_node(profile_log_filters, cloned_filter, add_position); # insert_node(profile_log_filters, cloned_filter, num_subnodes(profile_log_filters)); # echo("Added log filter '" . node_name(filter) . "'"); @detach_operation{"filters"}{filter_node_name} = ""; ); # if add_in_snapon ); # foreach filters # echo("profile_log_filters AFTER: " . node_as_string(profile_log_filters)); # error("add_snapon: add_log_filters unimplemented"); )); #### snapon_add_log_filters() #### # # snapon_add_log_filter_initializations() # # Purpose: This adds filter initialization sections to a profile, using a snapon node operation # # Parameters: profile: the profile to add to # attach_operation: the snapon add_log_filter_initializations operation node # detach_operations: the node of detach operations to build (how to undo this attach operation) # subroutine(snapon_add_log_filter_initializations(node profile, node attach_operation, node detach_operations), ( node log_filter_initializations = attach_operation{"log_filter_initializations"}; node profile_log_filter_initialization = profile{"log"}{"filter_initialization"}; # Remember the detach information string detach_operation_name = get_unique_node_name(detach_operations, "op"); node detach_operation = detach_operations{detach_operation_name}; @detach_operation{"type"} = "remove_log_filter_initializations"; # Add all specified log filter initializations node log_filter_initialization; foreach log_filter_initialization log_filter_initializations ( # Add the log filter_initialization node to the profile string log_filter_initialization_node_name = get_unique_node_name(profile_log_filter_initialization, node_name(log_filter_initialization)); node cloned_log_filter_initialization = clone_node(log_filter_initialization); rename_node(cloned_log_filter_initialization, log_filter_initialization_node_name); insert_node(profile_log_filter_initialization, cloned_log_filter_initialization, num_subnodes(profile_log_filter_initialization)); @detach_operation{"log_filter_initializations"}{log_filter_initialization_node_name} = ""; ); # foreach log_filter_initialization )); #### snapon_add_log_filter_initializations() #### # # snapon_add_log_filter_finalizations() # # Purpose: This adds filter finalization sections to a profile, using a snapon node operation # # Parameters: profile: the profile to add to # attach_operation: the snapon add_log_filter_finalizations operation node # detach_operations: the node of detach operations to build (how to undo this attach operation) # subroutine(snapon_add_log_filter_finalizations(node profile, node attach_operation, node detach_operations), ( node log_filter_finalizations = attach_operation{"log_filter_finalizations"}; node profile_log_filter_finalization = profile{"log"}{"filter_finalization"}; # Remember the detach information string detach_operation_name = get_unique_node_name(detach_operations, "op"); node detach_operation = detach_operations{detach_operation_name}; @detach_operation{"type"} = "remove_log_filter_finalizations"; # Add all specified log filter finalizations node log_filter_finalization; foreach log_filter_finalization log_filter_finalizations ( # Add the log filter_finalization node to the profile string log_filter_finalization_node_name = get_unique_node_name(profile_log_filter_finalization, node_name(log_filter_finalization)); node cloned_log_filter_finalization = clone_node(log_filter_finalization); rename_node(cloned_log_filter_finalization, log_filter_finalization_node_name); insert_node(profile_log_filter_finalization, cloned_log_filter_finalization, num_subnodes(profile_log_filter_finalization)); @detach_operation{"log_filter_finalizations"}{log_filter_finalization_node_name} = ""; ); # foreach log_filter_finalization )); #### snapon_add_log_filter_finalizations() #### # # snapon_remove_log_filters() # # Purpose: This removes a log filter from a profile, using a snapon node operation # # Parameters: profile: the profile to remove from # attach_operation: the snapon remove_log_filters operation node # subroutine(snapon_remove_log_filters(node profile, node attach_operation), ( node filters = attach_operation{"filters"}; node filter; node profile_log_filters = profile{"log"}{"filters"}; # echo("profile_log_filters BEFORE: " . node_as_string(profile_log_filters)); # Remove all specified log filters foreach filter filters ( # Remove the log filter node to the profile # echo("filter: " . node_as_string(filter)); node log_filter_node = profile_log_filters{node_name(filter)}; delete_node(log_filter_node); # echo("Removed log filter '" . node_name(filter) . "'"); ); # foreach filters # echo("profile_log_filters AFTER: " . node_as_string(profile_log_filters)); )); #### snapon_remove_log_filters() #### # # snapon_remove_log_filter_initializations() # # Purpose: This removes a log filter from a profile, using a snapon node operation # # Parameters: profile: the profile to remove from # attach_operation: the snapon remove_log_filter_initializations operation node # subroutine(snapon_remove_log_filter_initializations(node profile, node attach_operation), ( #echo("snapon_remove_log_filter_initializations()"); node log_filter_initializations = attach_operation{"log_filter_initializations"}; node log_filter_initialization; node profile_log_filter_initializations = profile{"log"}{"filter_initialization"}; # Remove all specified log filters foreach log_filter_initialization log_filter_initializations ( #echo("log_filter_initialization: " . log_filter_initialization); # Remove the log log_filter_initialization node to the profile node log_filter_initialization_node = profile_log_filter_initializations{node_name(log_filter_initialization)}; delete_node(log_filter_initialization_node); ); # foreach log_filter_initializations )); #### snapon_remove_log_filter_initializations() #### # # snapon_remove_log_filter_finalizations() # # Purpose: This removes a log filter from a profile, using a snapon node operation # # Parameters: profile: the profile to remove from # attach_operation: the snapon remove_log_filter_finalizations operation node # subroutine(snapon_remove_log_filter_finalizations(node profile, node attach_operation), ( #echo("snapon_remove_log_filter_finalizations()"); node log_filter_finalizations = attach_operation{"log_filter_finalizations"}; node log_filter_finalization; node profile_log_filter_finalizations = profile{"log"}{"filter_finalization"}; # Remove all specified log filters foreach log_filter_finalization log_filter_finalizations ( #echo("log_filter_finalization: " . log_filter_finalization); # Remove the log log_filter_finalization node to the profile node log_filter_finalization_node = profile_log_filter_finalizations{node_name(log_filter_finalization)}; delete_node(log_filter_finalization_node); ); # foreach log_filter_finalizations )); #### snapon_remove_log_filter_finalizations() #### # # snapon_add_report_fields() # # Purpose: This adds a report field to a profile, using a snapon node operation # # Parameters: profile: the profile to add to # attach_operation: the snapon add_report_fields operation node # detach_operations: the node of detach operations to build (how to undo this attach operation) # subroutine(snapon_add_report_fields(node snapon, node profile, node attach_operation, node detach_operations), ( node fields = attach_operation{"fields"}; node field; node profile_report_fields = profile{"statistics"}{"report_fields"}; # echo("profile_report_fields BEFORE: " . node_as_string(profile_report_fields)); #echo("attach_operation: " . node_as_string(attach_operation)); # Remember the detach information string detach_operation_name = get_unique_node_name(detach_operations, "op"); node detach_operation = detach_operations{detach_operation_name}; @detach_operation{"type"} = "remove_report_fields"; # Add all specified report fields foreach field fields ( if (add_in_snapon(field)) then ( # Add the report field node to the profile #echo("field: " . node_as_string(field)); if (profile_report_fields?{node_name(field)}) then error("Snapon attempted to add report field '" . node_name(field) . "', which already exists"); string name = get_unique_node_name(profile_report_fields, node_name(field)); node field_clone = clone_node(field); rename_node(field_clone, name); string default_field_label; if ("lang_stats.field_labels"?{name}) then default_field_label = "{=capitalize(expand(lang_stats.field_labels." . name . "))=}"; else default_field_label = name; # Set defaults set_node_with_default(snapon, field_clone, field_clone, "label", default_field_label); set_node_with_default(snapon, field_clone, field_clone, "database_field", node_name(field)); set_node_with_default(snapon, field_clone, field_clone, "column_label", ""); set_node_with_default(snapon, field_clone, field_clone, "column_info", ""); set_node_with_default(snapon, field_clone, field_clone, "display_format_type", "string"); set_node_with_default(snapon, field_clone, field_clone, "show_remainder_value", "true"); set_node_with_default(snapon, field_clone, field_clone, "show_min_value", "true"); set_node_with_default(snapon, field_clone, field_clone, "show_max_value", "true"); set_node_with_default(snapon, field_clone, field_clone, "show_total_value", "true"); set_node_with_default(snapon, field_clone, field_clone, "percent_calculation", "sum"); #echo("2field_clone: " . node_as_string(field_clone)); insert_node(profile_report_fields, field_clone, num_subnodes(profile_report_fields)); # echo("Added report field '" . node_name(field) . "'"); #echo("field: " . node_as_string(field)); @detach_operation{"fields"}{name} = ""; ); # if add ); # foreach fields # echo("profile_report_fields AFTER: " . node_as_string(profile_report_fields)); )); #### snapon_add_report_fields() #### # # snapon_remove_report_fields() # # Purpose: This removes a report field from a profile, using a snapon node operation # # Parameters: profile: the profile to remove from # attach_operation: the snapon remove_report_fields operation node # subroutine(snapon_remove_report_fields(node profile, node attach_operation), ( node fields = attach_operation{"fields"}; node field; node profile_report_fields = profile{"statistics"}{"report_fields"}; # echo("profile_report_fields BEFORE: " . node_as_string(profile_report_fields)); # Remove all specified report fields foreach field fields ( # Remove the report field node to the profile # echo("field: " . node_as_string(field)); node report_field_node = profile_report_fields{node_name(field)}; delete_node(report_field_node); # echo("Removeed report field '" . node_name(field) . "'"); ); # foreach fields # echo("profile_report_fields AFTER: " . node_as_string(profile_report_fields)); )); #### snapon_remove_report_fields() #### # # snapon_add_xref_fields() # # Purpose: This adds a xref field to a profile, using a snapon node operation # # Parameters: profile: the profile to add to # attach_operation: the snapon add_xref_fields operation node # detach_operations: the node of detach operations to build (how to undo this attach operation) # subroutine(snapon_add_xref_fields(node profile, node attach_operation, node detach_operations), ( node fields = attach_operation{"fields"}; node field; node profile_cross_reference_groups = profile{"database"}{"cross_reference_groups"}; # echo("profile_cross_reference_groups BEFORE: " . node_as_string(profile_cross_reference_groups)); string xref_group = @attach_operation{"xref_group"}; # Remember the detach information string detach_operation_name = get_unique_node_name(detach_operations, "op"); node detach_operation = detach_operations{detach_operation_name}; @detach_operation{"type"} = "remove_xref_fields"; @detach_operation{"xref_group"} = xref_group; # Add all specified xref fields foreach field fields ( # Get the name of the database field we actually added, by looking it up in v.dbfieldnames, which was created in snapon_add_xref_fields. # if (!?'v.dbfieldnames') then # error("Snapon adds database fields to xref, before adding the fields themselves (with add_database_fields)"); # string actual_dbfieldname = @'v.dbfieldnames'{node_name(field)}; string actual_dbfieldname = node_name(field); # echo("field: " . node_name(field)); node profile_cross_reference_group; int xrefgroupnum = 0; foreach profile_cross_reference_group profile_cross_reference_groups ( # echo("profile_cross_reference_group: " . node_name(profile_cross_reference_group)); if (matches_wildcard_expression(node_name(profile_cross_reference_group), xref_group)) then ( # echo("MATCH: " . node_name(profile_cross_reference_groups)); # echo(" Adding field '" . node_name(field) . "' to xref group '" . node_name(profile_cross_reference_group) . "'"); @profile_cross_reference_group{"fields"}{actual_dbfieldname} = ""; # echo("Xref group '" . node_name(profile_cross_reference_group) . "' modified; we need to rebuild it"); # string query = "drop table if exists xref" . xrefgroupnum; # string query = "drop table xref" . xrefgroupnum; # echo("query: " . query); # database_sql_query(query, true, false); force_xref_table_rebuild(profile, xrefgroupnum); ); # if group matches pattern xrefgroupnum++; ); # foreach profile_cross_reference_groups @detach_operation{"fields"}{actual_dbfieldname} = ""; ); # foreach fields # echo("profile_cross_reference_groups AFTER: " . node_as_string(profile_cross_reference_groups)); )); #### snapon_add_xref_fields() #### # # snapon_remove_xref_field() # # Purpose: This removes a xref field from a profile, using a snapon node operation # # Parameters: profile: the profile to remove from # attach_operation: the snapon remove_xref_fields operation node # subroutine(snapon_remove_xref_fields(node profile, node attach_operation), ( node fields = attach_operation{"fields"}; node field; # echo("profile_cross_reference_groups BEFORE: " . node_as_string(profile_cross_reference_groups)); string xref_group = @attach_operation{"xref_group"}; # Remove all specified xref fields foreach field fields ( node profile_cross_reference_groups = profile{"database"}{"cross_reference_groups"}; # echo("field: " . node_name(field)); node profile_cross_reference_group; int xrefgroupnum = 0; foreach profile_cross_reference_group profile_cross_reference_groups ( # echo("profile_cross_reference_group: " . node_name(profile_cross_reference_group)); if (matches_wildcard_expression(node_name(profile_cross_reference_group), xref_group)) then ( # echo("MATCH: " . node_name(profile_cross_reference_groups)); # echo(" Removing field '" . node_name(field) . "' from xref group '" . node_name(profile_cross_reference_group) . "'"); delete_node(profile_cross_reference_group{"fields"}{node_name(field)}); # echo("Xref group '" . node_name(profile_cross_reference_group) . "' modified; we need to rebuild it"); # save_node(profile); # rewrite_database_config(profile); force_xref_table_rebuild(profile, xrefgroupnum); ); # xref group name matches xrefgroupnum++; ); # foreach profile_cross_reference_groups ); # foreach fields # echo("profile_cross_reference_groups AFTER: " . node_as_string(profile_cross_reference_groups)); )); #### snapon_remove_xref_fields() #### # # snapon_add_xref_groups() # # Purpose: This adds a xref group to a profile, using a snapon node operation # # Parameters: profile: the profile to add to # attach_operation: the snapon add_xref_groups operation node # detach_operations: the node of detach operations to build (how to undo this attach operation) # subroutine(snapon_add_xref_groups(node profile, node attach_operation, node detach_operations), ( node groups = attach_operation{"groups"}; # node group; node profile_cross_reference_groups = profile{"database"}{"cross_reference_groups"}; # echo("profile_cross_reference_groups BEFORE: " . node_as_string(profile_cross_reference_groups)); node xref_groups = attach_operation{"xref_groups"}; #echo("xref_groups: " . node_as_string(xref_groups)); # Remember the detach information string detach_operation_name = get_unique_node_name(detach_operations, "op"); node detach_operation = detach_operations{detach_operation_name}; @detach_operation{"type"} = "remove_xref_groups"; # @detach_operation{"xref_group"} = xref_group; # Add all specified xref groups node xref_group; foreach xref_group xref_groups ( #echo("xref_group: " . xref_group); string xref_groupname = node_name(xref_group); node profile_xref_group = clone_node(xref_group); # If add_all_aggregating_fields=true, add all aggregating fields to this xref group if ((!xref_group?{"add_all_aggregating_fields"}) or (@xref_group{"add_all_aggregating_fields"})) then ( #echo("add_all_aggregating_columns"); node profile_report_fields = profile{"statistics"}{"report_fields"}; node profile_database_fields = profile{"database"}{"fields"}; node report_field; foreach report_field profile_report_fields ( if ((!report_field?{"include_field_in_reports_by_default"} or (@report_field{"include_field_in_reports_by_default"})) and report_field?{"database_field"}) then ( string database_field_name = @report_field{"database_field"}; #echo("database field: " . database_field_name); node database_field = profile_database_fields{database_field_name}; #echo("database_field: " . node_as_string(database_field)); if (database_field?{"aggregation_method"} and (@database_field{"aggregation_method"} ne "none")) then ( @profile_xref_group{"fields"}{node_name(database_field)} = ""; ); # if aggregating ); # if database_field ); # foreach report field #echo("columns: " . node_as_string(columns)); delete_node(profile_xref_group{"add_all_aggregating_fields"}); ); # if add_all_aggregating_fields #echo("profile_xref_group: " . node_as_string(profile_xref_group)); insert_node(profile_cross_reference_groups, profile_xref_group, num_subnodes(profile_cross_reference_groups)); int xrefgroupnum = num_subnodes(profile_cross_reference_groups) - 1; force_xref_table_rebuild(profile, xrefgroupnum); @detach_operation{"groups"}{xref_groupname} = ""; ); # foreach groups # echo("profile_cross_reference_groups AFTER: " . node_as_string(profile_cross_reference_groups)); )); #### snapon_add_xref_groups() #### # # snapon_remove_xref_groups() # # Purpose: This removes a xref field from a profile, using a snapon node operation # # Parameters: profile: the profile to remove from # attach_operation: the snapon remove_xref_fields operation node # subroutine(snapon_remove_xref_groups(node profile, node attach_operation), ( node xref_groups = attach_operation{"xref_groups"}; node profile_cross_reference_groups = profile{"database"}{"cross_reference_groups"}; # echo("profile_cross_reference_groups BEFORE: " . node_as_string(profile_cross_reference_groups)); # Remove all specified xref groups node xref_group; foreach xref_group xref_groups ( delete_node(profile_cross_reference_groups{node_name(xref_group)}); ); # echo("profile_cross_reference_groups AFTER: " . node_as_string(profile_cross_reference_groups)); )); #### snapon_remove_xref_groups() #### # # snapon_add_report_element_columns() # # Purpose: This adds report element columns to a profile, using a snapon node operation # # Parameters: profile: the profile to add to # attach_operation: the snapon add_report_element_column operation node # detach_operations: the node of detach operations to build (how to undo this attach operation) # subroutine(snapon_add_report_element_columns(node profile, node attach_operation, node detach_operations), ( #echo("snapon_add_report_element_columns()"); node columns = attach_operation{"columns"}; node profile_reports = profile{"statistics"}{"reports"}; # echo("profile_reports BEFORE: " . node_as_string(profile_reports)); string report = @attach_operation{"report"}; string report_element = @attach_operation{"report_element"}; # echo("Adding column '" . node_name(columns) . "' to report=" . report . "; report_element=" . report_element); # Remember the detach information string detach_operation_name = get_unique_node_name(detach_operations, "op"); node detach_operation = detach_operations{detach_operation_name}; @detach_operation{"type"} = "remove_report_element_columns"; @detach_operation{"report"} = report; @detach_operation{"report_element"} = report_element; # Add all specified report columns node column; foreach column columns ( # echo("Adding column '" . node_name(column) . "' to report=" . report . "; report_element=" . report_element); if (add_in_snapon(column)) then ( # Get the name of the report field we actually added, by looking it up in v.reportfieldnames, which was created in snapon_add_report_fields. # if (!?'v.reportfieldnames') then # error("Snapon adds report fields to report elements, before adding the fields themselves (with add_report_fields)"); # string actual_reportfieldname = @'v.reportfieldnames'{node_name(column)}; string actual_reportfieldname = node_name(column); # echo("column: " . node_name(column)); node profile_report; foreach profile_report profile_reports ( #echo("profile_report: " . profile_report); if (matches_wildcard_expression(node_name(profile_report), report)) then ( node profile_report_elements = profile_report{"report_elements"}; node profile_report_element; foreach profile_report_element profile_report_elements ( if (matches_wildcard_expression(node_name(profile_report_element), report_element)) then ( if (profile_report_element?{"columns"}) then ( #echo('add_in_snapon? column=' . node_as_string(column)); bool add = true; if (column?{"add_condition"}) then ( node add_condition_compiled = compile(@column{"add_condition"}); add = evaluate(add_condition_compiled); #echo("add: " . add); ); if (add) then ( # if require_report_field_columns is listed, check if all required columns exist in this report bool found_all_required_columns = true; if (attach_operation?{"require_report_field_columns"}) then ( #echo("Checking report element " . profile_report_element); #echo("FOUND require_report_field_columns"); node report_element_column; node required_column; #echo("profile_report_columns: " . node_as_string(profile_report_columns)); foreach report_element_column (profile_report_element{"columns"}) ( #echo("report_element_column: " . report_element_column); foreach required_column (attach_operation{"require_report_field_columns"}) ( #echo("required_column: " . required_column . ' [' . @required_column . ']'); if (@report_element_column{"report_field"} eq @required_column) then ( @required_column{"found"} = true; #echo(" FOUND " . @required_column); ); ); # foreach required_column ); # foreach report_element_column # Check if we found all required columns #echo('attach_operation{"require_report_field_columns"}: ' . node_as_string(attach_operation{"require_report_field_columns"})); foreach required_column (attach_operation{"require_report_field_columns"}) ( if (!(@required_column{"found"})) then ( found_all_required_columns = false; # echo("Not adding to " . expand(@profile_report_element{'label'}) . ", because we didn't find required column " . @required_column); ); # if not found @required_column{"found"} = false; ); # foreach required_column ); # if require_report_field_columns #echo("@@ found_all_required_columns: " . found_all_required_columns); if (!found_all_required_columns) then next; #echo("Adding to " . expand(@profile_report_element{'label'}) . "; we found all required fields"); node columns = profile_report_element{"columns"}; if (columns?{node_name(column)}) then error("Snapon attempted to add report column '" . node_name(column) . "', which already exists"); string column_name = get_unique_node_name(columns, node_name(column)); node column_clone = clone_node(column); rename_node(column_clone, column_name); insert_node(columns, column_clone, num_subnodes(columns)); # echo(" Added report column '" . node_name(column) . "' to " . profile_report_element); # echo(" Added report column '" . node_name(column) . "' to " . profile_report_element . " [show_graph=" . @column{"show_graph"} . "]"); #echo("column_clone : " . node_as_string(column_clone)); ); # if add ); # if has columns ); # if report element matches ); # foreach profile_report_element ); # if report matches ); # foreach profile_report @detach_operation{"columns"}{actual_reportfieldname} = ""; ); # if add_in_snapon ); # foreach columns # echo("profile_reports AFTER: " . node_as_string(profile_reports)); )); ### snapon_add_report_element_columns() #### # # snapon_remove_report_element_columns() # # Purpose: This removes report element columns from a profile, using a snapon node operation # # Parameters: profile: the profile to remove from # attach_operation: the snapon remove_report_element_column operation node # subroutine(snapon_remove_report_element_columns(node profile, node attach_operation), ( node columns = attach_operation{"columns"}; node profile_reports = profile{"statistics"}{"reports"}; # echo("profile_reports BEFORE: " . node_as_string(profile_reports)); string report = @attach_operation{"report"}; string report_element = @attach_operation{"report_element"}; # echo("Removing column '" . node_name(columns) . "' from report=" . report . "; report_element=" . report_element); # Remove all specified report columns node column; foreach column columns ( # echo("column: " . node_name(column)); node profile_report; foreach profile_report profile_reports ( if (matches_wildcard_expression(node_name(profile_report), report)) then ( node profile_report_elements = profile_report{"report_elements"}; node profile_report_element; foreach profile_report_element profile_report_elements ( if (matches_wildcard_expression(node_name(profile_report_element), report_element)) then ( if (profile_report_element?{"columns"}) then ( node columns = profile_report_element{"columns"}; # Remove any columns which have report_field equal to the column we're removing node profile_report_element_column; foreach profile_report_element_column columns ( if (@profile_report_element_column{"report_field"} eq node_name(column)) then ( delete_node(profile_report_element_column); # echo(" Removed report column '" . node_name(column) . "' from " . profile_report_element); ); ); ); # if has columns ); # if report element matches ); # foreach profile_report_element ); # if report matches ); # foreach profile_report ); # foreach columns # echo("profile_reports AFTER: " . node_as_string(profile_reports)); )); ### snapon_remove_report_element_columns() #### # # snapon_add_reports() # # Purpose: This adds reports to a profile # subroutine(snapon_add_reports(node snapon, node profile, node attach_operation, node detach_operations), ( node reports = attach_operation{"reports"}; node profile_reports = profile{"statistics"}{"reports"}; # echo("profile_reports BEFORE: " . node_as_string(profile_reports)); #echo("snapon_add_reports()"); # Remember the detach information string detach_operation_name = get_unique_node_name(detach_operations, "op"); #echo("detach_operation_name: " . detach_operation_name); node detach_operation = detach_operations{detach_operation_name}; #echo("detach_operation: " . detach_operation); @detach_operation{"type"} = "remove_reports"; node reports_to_remove = detach_operation{"reports"}; node reports_menu_to_remove = detach_operation{"reports_menu"}; # Add all specified reports node report; foreach report reports ( # Don't add this report if add_in_snapon evaluates to false if (add_in_snapon(report)) then ( #echo(" rerport: " . report); #echo(" report: " . node_as_string(report)); # string report_name = node_name(report); if (profile_reports?{node_name(report)}) then error("Snapon attempted to add report '" . node_name(report) . "', which already exists"); string report_name = get_unique_node_name(profile_reports, node_name(report)); string default_report_label; if ("lang_stats.menu.reports"?{report_name}) then default_report_label = "{=capitalize(expand(lang_stats.menu.reports." . report_name . "))=}"; else default_report_label = report_name; # Get the node of the report we're creating, in the profile @profile_reports{report_name} = ""; node profile_report = profile_reports{report_name}; #echo("Got profile_report from report_name=" . report_name); # Set standard report variables set_node_with_default(snapon, profile_report, report, "label", default_report_label); node report_elements = report{"report_elements"}; node profile_report_elements = profile_report{"report_elements"}; # Add all specified report elements node report_element; foreach report_element report_elements ( if (add_in_snapon(report_element)) then ( bool contains_nonexistent_report_fields = false; if (report_element?{"columns"}) then ( node column; foreach column (report_element{"columns"}) ( string report_field_name = @column{"report_field"}; if (add_in_snapon(column)) then ( # Ideally, we'd like to see if the *report* field exists, before adding this report. But report fields are created from database fields, later, so they don't exist yet. Just check if the database field exists, which will hopefully determine whether the report field *will* exist. #echo('profile{"statistics"}{"report_fields"}: ' . node_as_string(profile{"statistics"}{"report_fields"})); if (!profile{"database"}{"fields"}?{report_field_name}) then ( if ((report_field_name eq 'day') or (report_field_name eq 'month') or (report_field_name eq 'year') and (profile{"database"}{"fields"}?{"date_time"})) then ( #echo("Report field " . report_field_name . " doesn't exist; BUT it's year or month or day and date_time exists, so we'll assume it's going to exist"); ); # If it doesn't exist as a database field, but does exist as a report field, that's OK; it must have been created already by a snapon else if (profile{"statistics"}{"report_fields"}?{report_field_name}) then ( ); else ( #echo("Report field " . report_field_name . " doesn't exist; not adding report element " . report_element); contains_nonexistent_report_fields = true; ); ); else ( #echo("Report field " . report_field_name . " does exist"); ); #else ); # if add_in_snapon(column) ); # foreach column ); # if columns # Don't add this report element if add_in_snapon evaluates to false if (add_in_snapon(report_element) and !contains_nonexistent_report_fields) then ( # echo(" report_element: " . report_element); if (profile_report_elements?{node_name(report_element)}) then error("Snapon attempted to add report element '" . node_name(report_element) . "', which already exists"); string report_element_name = get_unique_node_name(profile_report_elements, node_name(report_element)); # Remember to remove this report on detach reports_to_remove{report_name}{"report_elements"}{report_element_name} = true; # Get the node of the report element we're creating, in the profile @profile_report_elements{report_element_name} = ""; node profile_report_element = profile_report_elements{report_element_name}; # Set the report element type @profile_report_element{"type"} = @report_element{"type"}; # echo("report_element: " . node_as_string(report_element)); # Set standard report element variables set_node_with_default(snapon, profile_report_element, report_element, "label", default_report_label); set_node_with_default(snapon, profile_report_element, report_element, "show_header_bar", false); set_node_with_default(snapon, profile_report_element, report_element, "header", ""); set_node_with_default(snapon, profile_report_element, report_element, "footer", ""); set_node_with_default(snapon, profile_report_element, report_element, "date_filter.df", ""); set_node_with_default(snapon, profile_report_element, report_element, "filter.expression", ""); set_node_with_default(snapon, profile_report_element, report_element, "table_filter_expression", ""); set_node_with_default(snapon, profile_report_element, report_element, "compact_view", false); set_node_with_default(snapon, profile_report_element, report_element, "display_side_by_side", false); set_node_with_default(snapon, profile_report_element, report_element, "display_graphs_side_by_side", true); set_node_with_default(snapon, profile_report_element, report_element, "report_link", ""); # KHP 2/Dec/2012 - Changed maximum_table_bar_graph_length to default 200 set_node_with_default(snapon, profile_report_element, report_element, "maximum_table_bar_graph_length", 200); # KHP 2/Dec/2012 - disabled display_graphs_table_side_by_side because tables are not a good fit to be displayed side by side # set_node_with_default(snapon, profile_report_element, report_element, "display_graphs_table_side_by_side", true); # Handle session_overview parameters if (@report_element{"type"} eq "sessions_overview") then ( set_node_with_default(snapon, profile_report_element, report_element, "session_user_field", ""); set_node_with_default(snapon, profile_report_element, report_element, "session_date_time_field", ""); set_node_with_default(snapon, profile_report_element, report_element, "session_id_field", ""); set_node_with_default(snapon, profile_report_element, report_element, "session_duration_field", ""); set_node_with_default(snapon, profile_report_element, report_element, "session_events_field", ""); set_node_with_default(snapon, profile_report_element, report_element, "session_entrances_field", ""); set_node_with_default(snapon, profile_report_element, report_element, "session_exits_field", ""); ); # if sessions_overview # Handle session_paths parameters if (@report_element{"type"} eq "session_paths") then ( #echo("### session paths"); set_node_with_default(snapon, profile_report_element, report_element, "session_user_field", ""); set_node_with_default(snapon, profile_report_element, report_element, "session_sequence_number_field", ""); set_node_with_default(snapon, profile_report_element, report_element, "session_id_field", ""); set_node_with_default(snapon, profile_report_element, report_element, "session_page_field", ""); ); # if session_paths # Handle session_page_paths parameters if (@report_element{"type"} eq "session_page_paths") then ( set_node_with_default(snapon, profile_report_element, report_element, "session_page_field", ""); set_node_with_default(snapon, profile_report_element, report_element, "session_date_time_field", ""); set_node_with_default(snapon, profile_report_element, report_element, "session_id_field", ""); set_node_with_default(snapon, profile_report_element, report_element, "session_entrances_field", ""); set_node_with_default(snapon, profile_report_element, report_element, "session_exits_field", ""); ); # if session_page_paths if (report_element?{"columns"}) then ( #echo("Processing columns"); node columns = report_element{"columns"}; # Use the first column as the default report field # string default_report_field = @(columns[0]){"report_field"}; # Get the label from lang_stats.menu.reports, if possible string label = report_element_name; if ("lang_stats.menu.reports"?{report_element_name}) then label = "{=capitalize(expand(lang_stats.menu.reports." . report_element_name . "))=}"; set_node_with_default(snapon, profile_report_element, report_element, "omit_parenthesized_items", false); set_node_with_default(snapon, profile_report_element, report_element, "use_overview_for_totals", false); # set_node_with_default(snapon, profile_report_element, report_element, "report_field", default_report_field); set_node_with_default(snapon, profile_report_element, report_element, "show_graphs", true); set_node_with_default(snapon, profile_report_element, report_element, "show_table", "true"); set_node_with_default(snapon, profile_report_element, report_element, "number_of_rows", "10"); set_node_with_default(snapon, profile_report_element, report_element, "sort_by", ""); set_node_with_default(snapon, profile_report_element, report_element, "sort_direction", "descending"); set_node_with_default(snapon, profile_report_element, report_element, "show_remainder_row", "true"); set_node_with_default(snapon, profile_report_element, report_element, "show_averages_row", "false"); set_node_with_default(snapon, profile_report_element, report_element, "show_min_row", "false"); set_node_with_default(snapon, profile_report_element, report_element, "show_max_row", "false"); set_node_with_default(snapon, profile_report_element, report_element, "show_totals_row", "true"); # If sort_by is "MAIN_SORT_FIELD", that means we should use the main sort field (first aggregating report field) as the sort. Figure out which one that is, and set sort_by. #echo("sort_by: " . @profile_report_element{"sort_by"}); if (@profile_report_element{"sort_by"} eq "MAIN_SORT_FIELD") then ( node report_field; node profile_report_fields = profile{"statistics"}{"report_fields"}; node profile_database_fields = profile{"database"}{"fields"}; foreach report_field profile_report_fields ( # echo("report_field: " . node_as_string(report_field)); if (report_field?{"database_field"}) then ( node database_field = profile_database_fields{@report_field{"database_field"}}; # echo("database_field: " . node_as_string(database_field)); if (@database_field{"aggregation_method"} ne "none") then ( @profile_report_element{"sort_by"} = node_name(database_field); last; ); # if non-aggregating ); # if database_field ); # foreach report_field ); # if MAIN_SORT_FIELD #echo("sort_by: " . @profile_report_element{"sort_by"}); # If there is a pivot table, add all that if (report_element?{"pivot_table"}) then ( set_node_with_default(snapon, profile_report_element, report_element, "pivot_table.show_pivot_table", "true"); set_node_with_default(snapon, profile_report_element, report_element, "pivot_table.report_field", ""); set_node_with_default(snapon, profile_report_element, report_element, "pivot_table.number_of_rows", "11"); set_node_with_default(snapon, profile_report_element, report_element, "pivot_table.sort_direction", "descending"); set_node_with_default(snapon, profile_report_element, report_element, "pivot_table.show_averages_row", "false"); set_node_with_default(snapon, profile_report_element, report_element, "pivot_table.show_min_row", "false"); set_node_with_default(snapon, profile_report_element, report_element, "pivot_table.show_max_row", "false"); ); # if pivot table #echo("report_element: " . report_element); #echo("report_element: " . node_as_string(report_element)); # If there is are graphs, add all that if (report_element?{"graphs"} or (report_element?{"show_graphs"} and @report_element{"show_graphs"})) then ( #echo("graphs detected"); set_node_with_default(snapon, profile_report_element, report_element, "graphs.graph_type", "pie"); set_node_with_default(snapon, profile_report_element, report_element, "graphs.y_axis_height", "200"); set_node_with_default(snapon, profile_report_element, report_element, "graphs.x_axis_length", "200"); set_node_with_default(snapon, profile_report_element, report_element, "graphs.show_3d", false); set_node_with_default(snapon, profile_report_element, report_element, "graphs.max_variables", "10"); set_node_with_default(snapon, profile_report_element, report_element, "graphs.sort_all_descending", "true"); set_node_with_default(snapon, profile_report_element, report_element, "graphs.show_legend", "true"); set_node_with_default(snapon, profile_report_element, report_element, "graphs.max_legend_rows", "10"); set_node_with_default(snapon, profile_report_element, report_element, "graphs.show_percent_on_y_axis", false); set_node_with_default(snapon, profile_report_element, report_element, "graphs.show_percent_in_legend", true); set_node_with_default(snapon, profile_report_element, report_element, "graphs.show_values_in_legend", true); set_node_with_default(snapon, profile_report_element, report_element, "graphs.display_graphs_side_by_side", true); ); # if pivot table # Get the node of the columns we're creating, in the profile @profile_report_element{"columns"} = ""; node profile_columns = profile_report_element{"columns"}; # If add_all_aggregating_columns=true, add all aggregating report fields to this report if (report_element?{"add_all_aggregating_columns"}) then ( #echo("add_all_aggregating_columns"); node profile_report_fields = profile{"statistics"}{"report_fields"}; node profile_database_fields = profile{"database"}{"fields"}; node report_field; bool first_column = true; foreach report_field profile_report_fields ( if ((!report_field?{"include_field_in_reports_by_default"} or (@report_field{"include_field_in_reports_by_default"})) and report_field?{"database_field"}) then ( string database_field_name = @report_field{"database_field"}; #echo("database field: " . database_field_name); bool add_field = false; # If it's a calculated field (not based on database field), dno't add it if (database_field_name eq '') then add_field = true; else ( node database_field = profile_database_fields{database_field_name}; #echo("database_field: " . node_as_string(database_field)); if (database_field?{"aggregation_method"} and (@database_field{"aggregation_method"} ne "none")) then add_field = true; ); if (add_field) then ( node column = new_node(); rename_node(column, node_name(report_field)); @column{"report_field"} = node_name(report_field); if (first_column) then ( #echo("first_column"); @column{"show_percent_column"} = true; @column{"show_bar_column"} = true; # Don't graph the first column unless they asked for it if (report_element?{"graph_main_field"}) then @column{"show_graph"} = @report_element{"graph_main_field"}; first_column = false; ); # if first_column insert_node(columns, column, num_subnodes(columns)); ); # if add_field ); # if database_field ); # foreach report field #echo("columns: " . node_as_string(columns)); ); # if add_all_aggregating_columns node column; foreach column columns ( # Don't add this column if add_in_snapon evaluates to false if (add_in_snapon(column)) then ( #echo("column: " . node_as_string(column)); string column_name = node_name(column); # Get the node of the column we're creating, in the profile @profile_columns{column_name} = ""; node profile_column = profile_columns{column_name}; #echo("BEFORE applying column defaults: column=" . node_as_string(column)); #echo("BEFORE applying column defaults: profile_column=" . node_as_string(profile_column)); set_node_with_default(snapon, profile_column, column, "report_field", ""); set_node_with_default(snapon, profile_column, column, "show_column", true); set_node_with_default(snapon, profile_column, column, "show_percent_column", false); set_node_with_default(snapon, profile_column, column, "show_bar_column", false); set_node_with_default(snapon, profile_column, column, "show_graph", false); #echo("AFTER applying column defaults: profile_column: " . node_as_string(profile_column)); ); # if add_in_snapon(column) ); # foreach column ); # if columns ); # add_in_snapon(report_element) and !contains_nonexistent_report_fields #echo("profile_report_element: " . profile_report_element); #echo("profile_report_element: " . node_as_string(profile_report_element)); ); # if add_in_snapon(report_element) ); # foreach report element #echo("profile_report: " . node_as_string(profile_report)); # If no report elements were added, delete the report; it has nothing in it. if (num_subnodes(profile_report{"report_elements"}) == 0) then ( #echo("Deleting report " . profile_report . "; no elements added"); delete_node(profile_report); #echo("Done deleting report"); ); ); # if add_in_snapon ); # foreach report node profile_reports_menu = profile{"statistics"}{"reports_menu"}; # This sub-subroutine recursively adds a section of the reports menu, as specified in the snapon subroutine(add_reports_menu_items(node snapon, node reports_menu_subnode, node profile_reports_menu_subnode, node detach_operations_subnode, node profile), ( # echo("reports_menu_subnode: " . reports_menu_subnode . ": " . node_as_string(reports_menu_subnode)); node reports_menu_item; foreach reports_menu_item reports_menu_subnode ( #echo("report_menu_item: " . node_as_string(reports_menu_item)); bool report_exists = true; string report_name = ""; if (reports_menu_item?{"report"}) then report_name = @reports_menu_item{"report"}; #echo("report_name: " . report_name); #echo("exists: " . (profile{"statistics"}{"reports"}?{report_name})); #echo("profile: " . profile); #echo('profile{"statistics"}{"reports"}: ' . profile{"statistics"}{"reports"}); if ((report_name ne "") and (!(profile{"statistics"}{"reports"})?{report_name})) then ( report_exists = false; # echo("Report " . report_name . " doesn't exist; not adding menu item"); ); # else # echo("Report " . report_name . " exists; adding menu item"); if (add_in_snapon(reports_menu_item) and report_exists) then ( # if (profile_reports_menu_subnode?{node_name(reports_menu_item)}) then ( # # No need for an error; just don't add it again (or remove it when we remove the snapon) # error("Snapon attempted to add report menu item '" . node_name(reports_menu_item) . "', which already exists"); # ); # # If the reports menu item doesn't exist, add it # else ( # Compute the node name in the reports menu. If this is a group, just use the name (which will cause new reports to be added to existing groups). If it's a report, get a new node name (which will cause reports with the same name to appear twice). string reports_menu_item_name; if (reports_menu_item?{"items"}) then ( reports_menu_item_name = node_name(reports_menu_item); ); else ( reports_menu_item_name = get_unique_node_name(profile_reports_menu_subnode, node_name(reports_menu_item)); ); # Remember to remove this item on detach # @detach_operations_subnode{reports_menu_item_name} = true; @profile_reports_menu_subnode{reports_menu_item_name} = ""; node profile_reports_menu_item = profile_reports_menu_subnode{reports_menu_item_name}; #echo("profile_reports_menu_item: " . node_as_string(profile_reports_menu_item)); string menu_item_label = reports_menu_item_name; # If this has move_to_top=true, move it to the top of the group or menu if (reports_menu_item?{"move_to_top"} and @reports_menu_item{"move_to_top"}) then ( #echo("Moving " . profile_reports_menu_item . " to top of " . profile_reports_menu_subnode); insert_node(profile_reports_menu_subnode, profile_reports_menu_item, 0); #echo("Moved menu item to top"); ); # if top_group # If this has items, it must be a group. Handle it recursively. if (reports_menu_item?{"items"}) then ( # echo("Detected group: " . reports_menu_item_name); # Get the label from lang_stats.menu.groups, if possible if ("lang_stats.menu.groups"?{reports_menu_item_name}) then menu_item_label = "{=capitalize(expand(lang_stats.menu.groups." . reports_menu_item_name . "))=}"; #echo("reports_menu_item?{'label'}: " . reports_menu_item?{'label'} ); set_node_with_default(snapon, profile_reports_menu_item, reports_menu_item, "label", menu_item_label); #echo("profile_reports_menu_item: " . node_as_string(profile_reports_menu_item)); add_reports_menu_items(snapon, reports_menu_item{"items"}, profile_reports_menu_item{"items"}, detach_operations_subnode{reports_menu_item_name}{"items"}, profile); #echo("2 profile_reports_menu_item: " . node_as_string(profile_reports_menu_item)); # If no items were added to this groups, delete the gropu; it has nothing in it. if (num_subnodes(profile_reports_menu_item{"items"}) == 0) then ( delete_node(profile_reports_menu_item); #echo("Deleting report menu group " . profile_reports_menu_item . "; no elements added"); ); ); # if has items # This isn't a group; handle it as a normal report else ( # echo("Detected report link: " . reports_menu_item_name); @profile_reports_menu_item{"report"} = reports_menu_item_name; # Remember to remove this item on detach @detach_operations_subnode{reports_menu_item_name} = true; # Get the label from lang_stats.menu.reports, if possible if ("lang_stats.menu.reports"?{reports_menu_item_name}) then menu_item_label = "{=capitalize(expand(lang_stats.menu.reports." . reports_menu_item_name . "))=}"; # Set the values of the "show" variables set_node_with_default(snapon, profile_reports_menu_item, reports_menu_item, "label", menu_item_label); set_node_with_default(snapon, profile_reports_menu_item, reports_menu_item, "show_in_dynamic_reports", true); set_node_with_default(snapon, profile_reports_menu_item, reports_menu_item, "show_in_static_reports", true); ); # if no items # ); # if doesn't exist #echo("reports_menu_item_name: " . reports_menu_item_name); ); # if add_in_snapon ); # reports_menu_items )); #### add_reports_menu_items() #### node reports_menu = attach_operation{"reports_menu"}; add_reports_menu_items(snapon, reports_menu, profile_reports_menu, reports_menu_to_remove, profile); # echo("profile_reports AFTER: " . node_as_string(profile_reports)); # echo("profile_reports_menu AFTER: " . node_as_string(profile_reports_menu)); )); ### snapon_add_reports() #### # # snapon_remove_reports() # # Purpose: This removes report element columns from a profile, using a snapon node operation # # Parameters: profile: the profile to remove from # attach_operation: the snapon remove_report operation node # subroutine(snapon_remove_reports(node profile, node attach_operation), ( node reports = attach_operation{"reports"}; node profile_reports = profile{"statistics"}{"reports"}; # Remove all specified reports node report; foreach report reports ( string report_name = node_name(report); node report_elements = report{"report_elements"}; node report_element; foreach report_element report_elements ( string report_element_name = node_name(report_element); delete_node(profile_reports{report_name}{"report_elements"}{report_element_name}); ); # foreach report_element delete_node(profile_reports{report_name}); ); # foreach report node reports_menu = attach_operation{"reports_menu"}; # This sub-subroutine recursively removes a section of the reports menu, as specified in the snapon subroutine(remove_reports_menu_items(node reports_menu_subnode, node profile_reports_menu_subnode), ( # echo("reports_menu_subnode: " . reports_menu_subnode . ": " . node_as_string(reports_menu_subnode)); node reports_menu_item; foreach reports_menu_item reports_menu_subnode ( string reports_menu_item_name = node_name(reports_menu_item); @profile_reports_menu_subnode{reports_menu_item_name} = ""; node profile_reports_menu_item = profile_reports_menu_subnode{reports_menu_item_name}; #echo("profile_reports_menu_item: " . node_as_string(profile_reports_menu_item)); string label = reports_menu_item_name; # If this has items, it must be a group. Handle it recursively. if (reports_menu_item?{"items"}) then ( remove_reports_menu_items(reports_menu_item{"items"}, profile_reports_menu_item{"items"}); if (num_subnodes(profile_reports_menu_item{"items"}) == 0) then ( delete_node(profile_reports_menu_item); ); #echo("profile_reports_menu_item{items} size: " . num_subnodes(profile_reports_menu_item{"items"})); ); # if has items # This isn't a group; handle it as a normal report else ( # echo("Detected report link: " . reports_menu_item_name); delete_node(profile_reports_menu_item); ); # if no items #echo("reports_menu_item_name: " . reports_menu_item_name); ); # reports_menu_items )); #### remove_reports_menu_items() #### node profile_reports_menu = profile{"statistics"}{"reports_menu"}; remove_reports_menu_items(reports_menu, profile_reports_menu); # echo("profile_reports AFTER: " . node_as_string(profile_reports)); )); ### snapon_remove_reports() #### # # set_task_action() # # Purpose: This sets the action for this task, by writing IPC/Task-#-Action # # Parameters: action: the action to write # subroutine(set_task_action(string action), ( # Get our task ID string taskID = current_task_id(); # string database_directory = get_database_directory(profile); string ipcDirectory = internal.LOGANALYSISINFO_DIRECTORY . "IPC"; string taskActionPathname = ipcDirectory . internal.directory_divider . "Task-" . taskID . "-Action"; write_file(taskActionPathname, action); # echo("Set task action to '" . action . "' (" . taskActionPathname . ")"); )); #### set_task_action() #### # # attach_snapon() # # Purpose: This attaches a snapon to a profile # # Parameters: profile: the profile to attached to # snapon_node: the snapon node to attach. This is a clone of the original snapon node which must have the same node name as the original node name! # attached_snapon_name: the node name as it is attached in the profile.snapons node. # subroutine(attach_snapon(node profile, node snapon_node, string attached_snapon_name), ( # echo("attach_snapon(); attached_snapon_name=" . attached_snapon_name); #save_node(profile); # Remember what action this is, for progress reporting @'command_line.action' = 'attach_snapon'; #echo("snapon_node: " . node_as_string(snapon_node)); node snapons = profile{"snapons"}; # There must be a label in a snapon if (!snapon_node?{"label"} or (@snapon_node{"label"} eq "(unspecified)")) then error("Snapon " . snapon_node . " does not include required label"); node parameters = snapon_node{"parameters"}; # echo("parameters: " . node_as_string(parameters)); resolve_variables(snapon_node, parameters); #echo("resolved node: " . node_as_string(snapon_node)); # Make sure this snapon isn't already attached, with the same label node snapon; string label; label = @snapon_node{"label"}; #echo("label: " . label); foreach snapon snapons ( #echo("snapon: " . snapon); #echo("snapon: " . node_as_string(snapon)); if (snapon?{"label"} and (@snapon{"label"} eq label)) then ( error("A snapon with label '" . label . "' already exists; please choose a different label"); ); ); # foreach snapon # if (snapons?{node_name(snapon_node)}) then # error("Snapon " . node_name(snapon_node) . " is already attached; doing nothing"); #LM #echo("attached_snapon_name: " . attached_snapon_name); # If there is no snapon using the snapon as its name, use that. # KHP, disabled snapon_node_name code because the callee function requires # the snapon_node_name of the profile, so it is given as argument. snapon = snapons{attached_snapon_name}; # string snapon_node_name = node_name(snapon_node); # if (!snapons?{snapon_node_name}) then ( # snapon = snapons{snapon_node_name}; # ); # Otherwise, count up until we find an unused snapon name # else ( # int snaponnum = 2; # while (snapons?{snapon_node_name . snaponnum}) # snaponnum++; # snapon = snapons{snapon_node_name . snaponnum}; # label = @snapon_node{"label"} . ' ' . snaponnum; # ); # if name used #echo("snapon: " . snapon); #echo("label: " . label); # Save the lable of this snapon instance @snapon{"label"} = label; # Save the source snapon name # KHP - added source_snapon_name because the node_name of the cloned snapon node is different than the source node name # 2010-03-11 - GMF - Switched back (removed source_snapon_name), because I modified handle_attach_snapon.cfv so it keeps the node name in the clone. @snapon{"snapon_name"} = node_name(snapon_node); # @snapon{"snapon_name"} = source_snapon_name; # Get a node to save the detach operations in, in the profile. node detach_operations = snapon{"detach_operations"}; # Mark the action for this task as "attaching_snapon" to the UI knows what we're doing. set_task_action("attaching_snapon"); #echo("0 log.fields: " . node_as_string(profile{"log.fields"})); # Apply all the "attach" operations node attach_operations = snapon_node{"attach_operations"}; #echo("attach_operations: " . node_as_string(attach_operations)); node attach_operation; foreach attach_operation attach_operations ( string type = @attach_operation{"type"}; # echo("type: " . type); # Handle add_log_fields if (type eq "add_log_fields") then snapon_add_log_fields(snapon_node, profile, attach_operation, detach_operations); # Handle add_database_fields else if (type eq "add_database_fields") then snapon_add_database_fields(snapon_node, profile, attach_operation, detach_operations); else if (type eq "add_database_filters") then snapon_add_database_filters(profile, attach_operation, detach_operations); else if (type eq "add_log_filters") then snapon_add_log_filters(profile, attach_operation, detach_operations); else if (type eq "add_log_filter_initializations") then snapon_add_log_filter_initializations(profile, attach_operation, detach_operations); else if (type eq "add_log_filter_finalizations") then snapon_add_log_filter_finalizations(profile, attach_operation, detach_operations); else if (type eq "add_report_fields") then snapon_add_report_fields(snapon_node, profile, attach_operation, detach_operations); else if (type eq "add_xref_fields") then snapon_add_xref_fields(profile, attach_operation, detach_operations); else if (type eq "add_xref_groups") then snapon_add_xref_groups(profile, attach_operation, detach_operations); else if (type eq "add_report_element_columns") then snapon_add_report_element_columns(profile, attach_operation, detach_operations); else if (type eq "add_reports") then snapon_add_reports(snapon_node, profile, attach_operation, detach_operations); else if (type eq "edit_profile_node") then snapon_edit_profile_node(snapon_node, profile, attach_operation, detach_operations); else if (type eq "add_snapons") then snapon_add_snapons(profile, attach_operation, detach_operations); else if (type eq "execute_expression") then snapon_execute_expression(profile, attach_operation, detach_operations); else ( error("attach_snapon: unknown type '" . type . "'"); ); #echo("Done with attach operation '" . type . "': " . node_as_string(attach_operation)); #echo("log.fields: " . node_as_string(profile{"log.fields"})); #echo("log.filters: " . node_as_string(profile{"log.filters"})); ); # foreach attach operations # Add this to the list of attached snapons #echo("node_name(snapon_node): " . node_name(snapon_node)); # snapons{node_name(snapon_node)}{"name"} = node_name(snapon_node); # Rewrite the database config file #echo("Writing config"); rewrite_database_config(profile); # Resolve {x= =x} sections in to plain { = = }. resolve_escaped_salang_sections(profile); # Save the modified profile #echo("Saving profile"); #echo("profile node: " . node_as_string(profile)); save_node(profile); #echo("Saved profile"); # Apply the database filters for this snap-on, if the main table exists if (database_table_exists(get_database_table_name(profile, "main_table"))) then ( node options = new_node(); @options{1} = "background"; @options{2} = "-p"; @options{3} = internal.profile_name; @options{4} = "-a"; @options{5} = "udf"; @options{6} = "-fr"; @options{7} = "true"; @options{8} = "volatile.snapon"; #echo("snapon_node: " . snapon_node); @options{9} = node_name(snapon_node); @options{10} = "-v"; @options{11} = "egboUh"; # echo("options=" . node_as_string(options)); int res = exec("", options, true); # echo("res=" . res); ); #echo("Returning from attach_snapon()1"); )); #### attach_snapon() #### # # detach_snapon_instance() # # Purpose: This detaches an instance of a snapon from a profile # # Parameters: profile: the profile to detached from # snapon_instance_name: the snapon node to detach # subroutine(detach_snapon_instance(node profile, string snapon_instance_name), ( # Run a dummy query, which does nothing, to force the database to be fully loaded before we start messing with it. drop_table_if_exists("table_which_doesnt_exist"); # database_sql_query("create table snapon_dummy", true, false); # database_sql_query("drop table snapon_dummy", true, false); # Mark the action for this task as "detaching_snapon" to the UI knows what we're doing. set_task_action("detaching_snapon"); # Make sure this snapon is attached node snapons = profile{"snapons"}; if (!snapons?{snapon_instance_name}) then error("Snapon instance " . snapon_instance_name . " is not attached; doing nothing"); #LM node snapon_instance = snapons{snapon_instance_name}; # Apply all the "detach" operations node detach_operations = snapon_instance{"detach_operations"}; # echo("detach_operations: " . node_as_string(detach_operations)); node detach_operation; foreach detach_operation detach_operations ( # echo("detach_operation: " . node_as_string(detach_operation)); string type = @detach_operation{"type"}; # echo("type: " . type); # Handle remove_database_fields if (type eq "remove_database_fields") then snapon_remove_database_fields(profile, detach_operation); else if (type eq "remove_log_fields") then snapon_remove_log_fields(profile, detach_operation); else if (type eq "remove_database_filters") then snapon_remove_database_filters(profile, detach_operation); else if (type eq "remove_log_filters") then snapon_remove_log_filters(profile, detach_operation); else if (type eq "remove_log_filter_initializations") then snapon_remove_log_filter_initializations(profile, detach_operation); else if (type eq "remove_log_filter_finalizations") then snapon_remove_log_filter_finalizations(profile, detach_operation); else if (type eq "remove_report_fields") then snapon_remove_report_fields(profile, detach_operation); else if (type eq "remove_xref_fields") then snapon_remove_xref_fields(profile, detach_operation); else if (type eq "remove_xref_groups") then snapon_remove_xref_groups(profile, detach_operation); else if (type eq "remove_report_element_columns") then snapon_remove_report_element_columns(profile, detach_operation); else if (type eq "remove_reports") then snapon_remove_reports(profile, detach_operation); else if (type eq "unedit_profile_node") then snapon_unedit_profile_node(profile, detach_operation); else if (type eq "remove_snapons") then snapon_remove_snapons(profile, detach_operation); else if (type eq "remove_database_snapons") then snapon_remove_snapons(profile, detach_operation); # Expressions can't be undone else if (type eq "execute_expression") then ( ); else ( error("detach_snapon: unknown type '" . type . "'"); ); #echo("rewriting after detach op " . type); rewrite_database_config(profile); ); # foreach detach operations # Remove this from the list of attached snapon instances delete_node(snapon_instance); # Rewrite the database config file #echo("rewriting after detach"); rewrite_database_config(profile); # Save the modified profile save_node(profile); # Apply the database filters for internal_optimize, if the main table exists. Otherwise, fields removed by this snapon # will not be propagated to xref tables. if (database_table_exists(get_database_table_name(profile, "main_table"))) then ( node options = new_node(); @options{1} = "background"; @options{2} = "-p"; @options{3} = internal.profile_name; @options{4} = "-a"; @options{5} = "udf"; @options{6} = "-fr"; @options{7} = "true"; @options{8} = "volatile.snapon"; @options{9} = "internal_optimize"; @options{10} = "-v"; @options{11} = "egboUh"; # echo("options=" . node_as_string(options)); int res = exec("", options, true); # echo("res=" . res); ); )); #### detach_snapon_instance() ####