/** * Creates and executes a query for the history rows related to bugs matched by the provided filter * @param array $p_filter Filter array * @param integer $p_start_time The start time to filter by, or null for all. * @param integer $p_end_time The end time to filter by, or null for all. * @param string $p_history_order The sort order. * @return database result to pass into history_get_event_from_row(). */ function history_get_range_result_filter($p_filter, $p_start_time = null, $p_end_time = null, $p_history_order = null) { if ($p_history_order === null) { $t_history_order = config_get('history_order'); } else { $t_history_order = $p_history_order; } # Note: filter_get_bug_rows_query_clauses() calls db_param_push(); $t_query_clauses = filter_get_bug_rows_query_clauses($p_filter, null, null, null); # if the query can't be formed, there are no results if (empty($t_query_clauses)) { # reset the db_param stack that was initialized by "filter_get_bug_rows_query_clauses()" db_param_pop(); return db_empty_result(); } $t_select_string = 'SELECT DISTINCT {bug}.id '; $t_from_string = ' FROM ' . implode(', ', $t_query_clauses['from']); $t_join_string = count($t_query_clauses['join']) > 0 ? implode(' ', $t_query_clauses['join']) : ' '; $t_where_string = ' WHERE ' . implode(' AND ', $t_query_clauses['project_where']); if (count($t_query_clauses['where']) > 0) { $t_where_string .= ' AND ( '; $t_where_string .= implode($t_query_clauses['operator'], $t_query_clauses['where']); $t_where_string .= ' ) '; } $t_query = 'SELECT * FROM {bug_history} JOIN' . ' ( ' . $t_select_string . $t_from_string . $t_join_string . $t_where_string . ' ) B' . ' ON {bug_history}.bug_id=B.id'; $t_params = $t_query_clauses['where_values']; $t_where = array(); if ($p_start_time !== null) { $t_where[] = 'date_modified >= ' . db_param(); $t_params[] = $p_start_time; } if ($p_end_time !== null) { $t_where[] = 'date_modified < ' . db_param(); $t_params[] = $p_end_time; } if (count($t_where) > 0) { $t_query .= ' WHERE ' . implode(' AND ', $t_where); } $t_query .= ' ORDER BY {bug_history}.date_modified ' . $t_history_order . ', {bug_history}.id ' . $t_history_order; $t_result = db_query($t_query, $t_params); return $t_result; }
/** * Move any attachments as needed when a bug is moved from project to project. * * @param integer $p_bug_id ID of bug containing attachments to be moved. * @param integer $p_project_id_to Destination project ID for the bug. * @return void * * @todo: this function can't cope with source or target storing attachments in DB */ function file_move_bug_attachments($p_bug_id, $p_project_id_to) { $t_project_id_from = bug_get_field($p_bug_id, 'project_id'); if ($t_project_id_from == $p_project_id_to) { return; } $t_method = config_get('file_upload_method'); if ($t_method != DISK) { return; } if (!file_bug_has_attachments($p_bug_id)) { return; } $t_path_from = project_get_field($t_project_id_from, 'file_path'); if (is_blank($t_path_from)) { $t_path_from = config_get('absolute_path_default_upload_folder', null, null, $t_project_id_from); } file_ensure_valid_upload_path($t_path_from); $t_path_to = project_get_field($p_project_id_to, 'file_path'); if (is_blank($t_path_to)) { $t_path_to = config_get('absolute_path_default_upload_folder', null, null, $p_project_id_to); } file_ensure_valid_upload_path($t_path_to); if ($t_path_from == $t_path_to) { return; } # Initialize the update query to update a single row $c_bug_id = (int) $p_bug_id; db_param_push(); $t_query_disk_attachment_update = 'UPDATE {bug_file} SET folder=' . db_param() . ' WHERE bug_id=' . db_param() . ' AND id =' . db_param(); $t_attachment_rows = bug_get_attachments($p_bug_id); $t_attachments_count = count($t_attachment_rows); for ($i = 0; $i < $t_attachments_count; $i++) { $t_row = $t_attachment_rows[$i]; $t_basename = basename($t_row['diskfile']); $t_disk_file_name_from = file_path_combine($t_path_from, $t_basename); $t_disk_file_name_to = file_path_combine($t_path_to, $t_basename); if (!file_exists($t_disk_file_name_to)) { chmod($t_disk_file_name_from, 0775); if (!rename($t_disk_file_name_from, $t_disk_file_name_to)) { if (!copy($t_disk_file_name_from, $t_disk_file_name_to)) { trigger_error(ERROR_FILE_MOVE_FAILED, ERROR); } file_delete_local($t_disk_file_name_from); } chmod($t_disk_file_name_to, config_get('attachments_file_permissions')); # Don't pop the parameters after query execution since we're in a loop db_query($t_query_disk_attachment_update, array(db_prepare_string($t_path_to), $c_bug_id, (int) $t_row['id']), false); } else { trigger_error(ERROR_FILE_DUPLICATE, ERROR); } } db_param_pop(); }
/** * Gets the candidates for the specified bug. These are existing tags * that are not associated with the bug already. * * @param integer $p_bug_id The bug id, if 0 returns all tags. * @return array The array of tag rows, each with id, name, and description. */ function tag_get_candidates_for_bug($p_bug_id) { db_param_push(); $t_params = array(); if (0 != $p_bug_id) { $t_params[] = $p_bug_id; if (config_get_global('db_type') == 'odbc_mssql') { db_param_push(); $t_query = 'SELECT t.id FROM {tag} t LEFT JOIN {bug_tag} b ON t.id=b.tag_id WHERE b.bug_id IS NULL OR b.bug_id != ' . db_param(); $t_result = db_query($t_query, $t_params); $t_params = null; $t_subquery_results = array(); while ($t_row = db_fetch_array($t_result)) { $t_subquery_results[] = (int) $t_row['id']; } if (count($t_subquery_results) == 0) { db_param_pop(); return array(); } $t_query = 'SELECT id, name, description FROM {tag} WHERE id IN ( ' . implode(', ', $t_subquery_results) . ')'; } else { $t_query = 'SELECT id, name, description FROM {tag} WHERE id IN ( SELECT t.id FROM {tag} t LEFT JOIN {bug_tag} b ON t.id=b.tag_id WHERE b.bug_id IS NULL OR b.bug_id != ' . db_param() . ')'; } } else { $t_query = 'SELECT id, name, description FROM {tag}'; } $t_query .= ' ORDER BY name ASC '; $t_result = db_query($t_query, $t_params); $t_results_to_return = array(); while ($t_row = db_fetch_array($t_result)) { $t_results_to_return[] = $t_row; } return $t_results_to_return; }
/** * Update the field definition * return true on success, false on failure * @param integer $p_field_id Custom field identifier. * @param array $p_def_array Custom field definition. * @return boolean * @access public */ function custom_field_update($p_field_id, array $p_def_array) { if (is_blank($p_def_array['name'])) { error_parameters('name'); trigger_error(ERROR_EMPTY_FIELD, ERROR); } if ($p_def_array['access_level_rw'] < $p_def_array['access_level_r']) { error_parameters(lang_get('custom_field_access_level_r') . ', ' . lang_get('custom_field_access_level_rw')); trigger_error(ERROR_CUSTOM_FIELD_INVALID_PROPERTY, ERROR); } if ($p_def_array['length_min'] < 0 || $p_def_array['length_max'] != 0 && $p_def_array['length_min'] > $p_def_array['length_max']) { error_parameters(lang_get('custom_field_length_min') . ', ' . lang_get('custom_field_length_max')); trigger_error(ERROR_CUSTOM_FIELD_INVALID_PROPERTY, ERROR); } if (!custom_field_is_name_unique($p_def_array['name'], $p_field_id)) { trigger_error(ERROR_CUSTOM_FIELD_NAME_NOT_UNIQUE, ERROR); } db_param_push(); # Build fields update statement $t_update = ''; foreach ($p_def_array as $t_field => $t_value) { switch ($t_field) { case 'name': case 'possible_values': case 'default_value': case 'valid_regexp': # Possible values doesn't apply to textarea fields if ($p_def_array['type'] == CUSTOM_FIELD_TYPE_TEXTAREA && $t_field == 'possible_values') { $t_value = ''; } $t_update .= $t_field . '=' . db_param() . ', '; $t_params[] = (string) $t_value; break; case 'type': case 'access_level_r': case 'access_level_rw': case 'length_min': case 'length_max': $t_update .= $t_field . '=' . db_param() . ', '; $t_params[] = (int) $t_value; break; case 'filter_by': case 'display_report': case 'display_update': case 'display_resolved': case 'display_closed': case 'require_report': case 'require_update': case 'require_resolved': case 'require_closed': $t_update .= $t_field . '=' . db_param() . ', '; $t_params[] = (bool) $t_value; break; } } # If there are fields to update, execute SQL if ($t_update !== '') { $t_query = 'UPDATE {custom_field} SET ' . rtrim($t_update, ', ') . ' WHERE id = ' . db_param(); $t_params[] = $p_field_id; db_query($t_query, $t_params); custom_field_clear_cache($p_field_id); return true; } # Reset the parameter count manually since the query was not executed db_param_pop(); return false; }
/** * Creates a sql query with the supplied filter query clauses, and returns the unprocessed result set opbject * * Note: The parameter $p_pop_param can be used as 'false' to keep db_params in the stack, * if the same query clauses object is reused for several queries. In that case a db_param_pop() * should be used manually when required. * This is the case when "filter_get_bug_count" is used followed by "filter_get_bug_rows_result" * @param array $p_query_clauses Array of query clauses * @param integer $p_count The number of rows to return * -1 or null indicates default query (no limits) * @param integer $p_offset Offset query results for paging (number of rows) * -1 or null indicates default query (no offset) * @param boolean $p_pop_param Whether to pop DB params from the stack * @return IteratorAggregate|boolean adodb result set or false if the query failed. */ function filter_get_bug_rows_result(array $p_query_clauses, $p_count = null, $p_offset = null, $p_pop_param = true) { # if the query can't be formed, there are no results if (empty($p_query_clauses)) { if ($p_pop_param) { # reset the db_param stack, this woould have been done by db_query if executed db_param_pop(); } return db_empty_result(); } if (null === $p_count) { $t_count = -1; } else { $t_count = $p_count; } if (null === $p_offset) { $t_offset = -1; } else { $t_offset = $p_offset; } $t_query_clauses = $p_query_clauses; $t_select_string = 'SELECT DISTINCT ' . implode(', ', $t_query_clauses['select']); $t_from_string = ' FROM ' . implode(', ', $t_query_clauses['from']); $t_order_string = ' ORDER BY ' . implode(', ', $t_query_clauses['order']); $t_join_string = count($t_query_clauses['join']) > 0 ? implode(' ', $t_query_clauses['join']) : ' '; $t_where_string = ' WHERE ' . implode(' AND ', $t_query_clauses['project_where']); if (count($t_query_clauses['where']) > 0) { $t_where_string .= ' AND ( '; $t_where_string .= implode($t_query_clauses['operator'], $t_query_clauses['where']); $t_where_string .= ' ) '; } $t_result = db_query($t_select_string . $t_from_string . $t_join_string . $t_where_string . $t_order_string, $t_query_clauses['where_values'], $t_count, $t_offset, $p_pop_param); return $t_result; }
/** * Migrate the legacy date format. * @param array $p_data Array: [0] = tablename, [1] id column, [2] = old column, [3] = new column. * @return integer */ function install_date_migrate(array $p_data) { # $p_data[0] = tablename, [1] id column, [2] = old column, [3] = new column # Disable query logging even if enabled in config, due to possibility of mass spam $t_log_queries = install_set_log_queries(); $t_table = $p_data[0]; $t_id_column = $p_data[1]; $t_date_array = is_array($p_data[2]); if ($t_date_array) { $t_old_column = implode(',', $p_data[2]); $t_cnt_fields = count($p_data[2]); $t_query = 'SELECT ' . $t_id_column . ', ' . $t_old_column . ' FROM ' . $t_table; $t_first_column = true; # In order to handle large databases where we may timeout during the upgrade, we don't # start from the beginning everytime. Here we will only pickup rows where at least one # of the datetime fields wasn't upgraded yet and upgrade them all. foreach ($p_data[3] as $t_new_column_name) { if ($t_first_column) { $t_first_column = false; $t_query .= ' WHERE '; } else { $t_query .= ' OR '; } $t_query .= $t_new_column_name . ' = 1'; } } else { $t_old_column = $p_data[2]; # The check for timestamp being = 1 is to make sure the field wasn't upgraded # already in a previous run - see bug #12601 for more details. $t_new_column_name = $p_data[3]; $t_query = 'SELECT ' . $t_id_column . ', ' . $t_old_column . ' FROM ' . $t_table . ' WHERE ' . $t_new_column_name . ' = 1'; } $t_result = db_query($t_query); if (db_num_rows($t_result) > 0) { db_param_push(); # Build the update query if ($t_date_array) { $t_pairs = array(); foreach ($p_data[3] as $t_var) { array_push($t_pairs, $t_var . '=' . db_param()); } $t_new_column = implode(',', $t_pairs); } else { $t_new_column = $p_data[3] . '=' . db_param(); } $t_query = 'UPDATE ' . $t_table . ' SET ' . $t_new_column . ' WHERE ' . $t_id_column . '=' . db_param(); while ($t_row = db_fetch_array($t_result)) { $t_id = (int) $t_row[$t_id_column]; if ($t_date_array) { for ($i = 0; $i < $t_cnt_fields; $i++) { $t_old_value = $t_row[$p_data[2][$i]]; if (is_numeric($t_old_value)) { return 1; # Fatal: conversion may have already been run. If it has been run, proceeding will wipe timestamps from db } $t_new_value[$i] = db_unixtimestamp($t_old_value); if ($t_new_value[$i] < 100000) { $t_new_value[$i] = 1; } } $t_values = $t_new_value; $t_values[] = $t_id; } else { $t_old_value = $t_row[$t_old_column]; if (is_numeric($t_old_value)) { return 1; # Fatal: conversion may have already been run. If it has been run, proceeding will wipe timestamps from db } $t_new_value = db_unixtimestamp($t_old_value); if ($t_new_value < 100000) { $t_new_value = 1; } $t_values = array($t_new_value, $t_id); } # Don't pop params since we're in a loop db_query($t_query, $t_values, -1, -1, false); } db_param_pop(); } # Re-enable query logging if we disabled it install_set_log_queries($t_log_queries); # return 2 because that's what ADOdb/DataDict does when things happen properly return 2; }