Exemplo n.º 1
0
def database_compare(server1_val, server2_val, db1, db2, options):
    """Perform a consistency check among two databases

    This method performs a database consistency check among two databases which
    ensures the databases exist, the objects match in number and type, the row
    counts match for all tables, and the data for each matching tables is
    consistent.

    If any errors or differences are found, the operation stops and the
    difference is printed.

    The following steps are therefore performed:

    1) check to make sure the databases exist and are the same definition
    2) check to make sure the same objects exist in each database
    3) for each object, ensure the object definitions match among the databases
    4) for each table, ensure the row counts are the same
    5) for each table, ensure the data is the same

    By default, the operation stops on any failure of any test. The caller can
    override this behavior by specifying run_all_tests = True in the options
    dictionary.

    TODO:   allow the user to skip object types (e.g. --skip-triggers, et. al.)

    server1_val[in]    a dictionary containing connection information for the
                       first server including:
                       (user, password, host, port, socket)
    server2_val[in]    a dictionary containing connection information for the
                       second server including:
                       (user, password, host, port, socket)
    db1[in]            the first database in the compare
    db2[in]            the second database in the compare
    options[in]        a dictionary containing the options for the operation:
                       (quiet, verbosity, difftype, run_all_tests)

    Returns bool True if all object match, False if partial match
    """

    _check_option_defaults(options)

    # Connect to servers
    server1, server2 = server_connect(server1_val, server2_val, db1, db2,
                                      options)

    # Check to see if databases exist
    db1_conn = Database(server1, db1, options)
    if not db1_conn.exists():
        raise UtilDBError(_ERROR_DB_MISSING.format(db1))

    db2_conn = Database(server2, db2, options)
    if not db2_conn.exists():
        raise UtilDBError(_ERROR_DB_MISSING.format(db2))

    # Print a different message is server2 is not defined
    if not server2_val:
        message = "# Checking databases {0} and {1} on server1\n#"
    else:
        message = "# Checking databases {0} on server1 and {1} on server2\n#"
    print(message.format(db1_conn.db_name, db2_conn.db_name))

    # Check for database existence and CREATE differences
    _check_databases(server1, server2, db1_conn.q_db_name, db2_conn.q_db_name,
                     options)

    # Get common objects and report discrepancies
    (in_both, differs) = _check_objects(server1, server2, db1, db2, db1_conn,
                                        db2_conn, options)
    success = not differs

    reporter = _CompareDBReport(options)
    reporter.print_heading()

    # Remaining operations can occur in a loop one for each object.
    for item in in_both:
        error_list = []
        debug_msgs = []
        # Set the object type
        obj_type = item[0]

        q_obj1 = "{0}.{1}".format(quote_with_backticks(db1),
                                  quote_with_backticks(item[1][0]))
        q_obj2 = "{0}.{1}".format(quote_with_backticks(db2),
                                  quote_with_backticks(item[1][0]))

        reporter.report_object(obj_type, item[1][0])

        # Check for differences in CREATE
        errors = _compare_objects(server1, server2, q_obj1, q_obj2, reporter,
                                  options, obj_type)
        error_list.extend(errors)

        # Check row counts
        if obj_type == 'TABLE':
            errors = _check_row_counts(server1, server2, q_obj1, q_obj2,
                                       reporter, options)
            if len(errors) != 0:
                error_list.extend(errors)
        else:
            reporter.report_state("-")

        # Check data consistency for tables
        if obj_type == 'TABLE':
            errors, debug_msgs = _check_data_consistency(
                server1, server2, q_obj1, q_obj2, reporter, options)
            if len(errors) != 0:
                error_list.extend(errors)
        else:
            reporter.report_state("-")

        if options['verbosity'] > 0:
            print
            get_create_object(server1, q_obj1, options, obj_type)
            get_create_object(server2, q_obj2, options, obj_type)

        if debug_msgs and options['verbosity'] > 2:
            reporter.report_errors(debug_msgs)

        reporter.report_errors(error_list)

        # Fail if errors are found
        if error_list:
            success = False

    return success
Exemplo n.º 2
0
def database_compare(server1_val, server2_val, db1, db2, options):
    """Perform a consistency check among two databases

    This method performs a database consistency check among two databases which
    ensures the databases exist, the objects match in number and type, the row
    counts match for all tables, and the data for each matching tables is
    consistent.

    If any errors or differences are found, the operation stops and the
    difference is printed.

    The following steps are therefore performed:

    1) check to make sure the databases exist and are the same definition
    2) check to make sure the same objects exist in each database
    3) for each object, ensure the object definitions match among the databases
    4) for each table, ensure the row counts are the same
    5) for each table, ensure the data is the same

    By default, the operation stops on any failure of any test. The caller can
    override this behavior by specifying run_all_tests = True in the options
    dictionary.

    TODO:   allow the user to skip object types (e.g. --skip-triggers, et. al.)

    server1_val[in]    a dictionary containing connection information for the
                       first server including:
                       (user, password, host, port, socket)
    server2_val[in]    a dictionary containing connection information for the
                       second server including:
                       (user, password, host, port, socket)
    db1[in]            the first database in the compare
    db2[in]            the second database in the compare
    options[in]        a dictionary containing the options for the operation:
                       (quiet, verbosity, difftype, run_all_tests)

    Returns bool True if all object match, False if partial match
    """

    _check_option_defaults(options)

    # Connect to servers
    server1, server2 = server_connect(server1_val, server2_val,
                                      db1, db2, options)

    # Check to see if databases exist
    db1_conn = Database(server1, db1, options)
    if not db1_conn.exists():
        raise UtilDBError(_ERROR_DB_MISSING.format(db1))

    db2_conn = Database(server2, db2, options)
    if not db2_conn.exists():
        raise UtilDBError(_ERROR_DB_MISSING.format(db2))

    # Print a different message is server2 is not defined
    if not server2_val:
        message = "# Checking databases {0} and {1} on server1\n#"
    else:
        message = "# Checking databases {0} on server1 and {1} on server2\n#"
    print(message.format(db1_conn.db_name, db2_conn.db_name))

    # Check for database existence and CREATE differences
    _check_databases(server1, server2, db1_conn.q_db_name, db2_conn.q_db_name,
                     options)

    # Get common objects and report discrepancies
    (in_both, differs) = _check_objects(server1, server2, db1, db2,
                                        db1_conn, db2_conn, options)
    success = not differs

    reporter = _CompareDBReport(options)
    reporter.print_heading()

    # Remaining operations can occur in a loop one for each object.
    for item in in_both:
        error_list = []

        # Set the object type
        obj_type = item[0]

        obj1 = "{0}.{1}".format(db1, item[1][0])
        obj2 = "{0}.{1}".format(db2, item[1][0])
        q_obj1 = "{0}.{1}".format(quote_with_backticks(db1),
                                  quote_with_backticks(item[1][0]))
        q_obj2 = "{0}.{1}".format(quote_with_backticks(db2),
                                  quote_with_backticks(item[1][0]))

        reporter.report_object(obj_type, item[1][0])

        # Check for differences in CREATE
        errors = _compare_objects(server1, server2, q_obj1, q_obj2,
                                  reporter, options, obj_type)
        error_list.extend(errors)

        # Check row counts
        if obj_type == 'TABLE':
            errors = _check_row_counts(server1, server2, q_obj1, q_obj2,
                                       reporter, options)
            if len(errors) != 0:
                error_list.extend(errors)
        else:
            reporter.report_state("-")

        # Check data consistency for tables
        if obj_type == 'TABLE':
            errors = _check_data_consistency(server1, server2, q_obj1, q_obj2,
                                             reporter, options)
            if len(errors) != 0:
                error_list.extend(errors)
        else:
            reporter.report_state("-")

        if options['verbosity'] > 0:
            print
            get_create_object(server1, obj1, options, obj_type)
            get_create_object(server2, obj2, options, obj_type)

        reporter.report_errors(error_list)

        # Fail if errors are found
        if error_list:
            success = False

    return success