Merge lp:~percona-toolkit-dev/percona-toolkit/fix-pt-heartbeat-dupe-key-bug-1004567 into lp:percona-toolkit/2.0

Proposed by Daniel Nichter on 2012-07-20
Status: Merged
Merged at revision: 250
Proposed branch: lp:~percona-toolkit-dev/percona-toolkit/fix-pt-heartbeat-dupe-key-bug-1004567
Merge into: lp:percona-toolkit/2.0
Diff against target: 99953 lines (+70763/-13287) (has conflicts)
617 files modified
.bzrignore (+1/-0)
Changelog (+91/-0)
MANIFEST (+2/-0)
Makefile.PL (+6/-2)
bin/pt-align (+4/-0)
bin/pt-archiver (+811/-455)
bin/pt-config-diff (+67/-49)
bin/pt-deadlock-logger (+695/-76)
bin/pt-diskstats (+111/-6)
bin/pt-duplicate-key-checker (+301/-548)
bin/pt-fifo-split (+5/-1)
bin/pt-find (+203/-501)
bin/pt-fingerprint (+2143/-0)
bin/pt-fk-error-logger (+194/-46)
bin/pt-heartbeat (+308/-197)
bin/pt-index-usage (+426/-553)
bin/pt-ioprofile (+59/-22)
bin/pt-kill (+1655/-148)
bin/pt-log-player (+64/-47)
bin/pt-mext (+20/-4)
bin/pt-mysql-summary (+2092/-681)
bin/pt-online-schema-change (+5820/-1324)
bin/pt-pmp (+21/-9)
bin/pt-query-advisor (+486/-458)
bin/pt-query-digest (+341/-436)
bin/pt-show-grants (+62/-54)
bin/pt-sift (+37/-14)
bin/pt-slave-delay (+658/-178)
bin/pt-slave-find (+754/-85)
bin/pt-slave-restart (+702/-82)
bin/pt-stalk (+33/-11)
bin/pt-summary (+2046/-792)
bin/pt-table-checksum (+1454/-272)
bin/pt-table-sync (+957/-160)
bin/pt-table-usage (+7375/-0)
bin/pt-tcp-model (+106/-3)
bin/pt-trend (+106/-3)
bin/pt-upgrade (+291/-543)
bin/pt-variable-advisor (+656/-98)
bin/pt-visual-explain (+60/-46)
config/deb/changelog (+94/-0)
config/sphinx-build/conf.py (+5/-1)
docs/percona-toolkit.pod (+16/-4)
docs/release_notes.rst (+139/-0)
lib/CleanupTask.pm (+7/-2)
lib/CompareQueryTimes.pm (+13/-7)
lib/CompareResults.pm (+8/-4)
lib/CompareWarnings.pm (+14/-8)
lib/Cxn.pm (+20/-8)
lib/DSNParser.pm (+61/-51)
lib/DiskstatsGroupByAll.pm (+1/-1)
lib/DiskstatsGroupByDisk.pm (+1/-1)
lib/EventAggregator.pm (+1/-1)
lib/IndexLength.pm (+175/-0)
lib/IndexUsage.pm (+1/-0)
lib/MasterSlave.pm (+12/-10)
lib/Mo.pm (+519/-0)
lib/MySQLProtocolParser.pm (+1/-1)
lib/NibbleIterator.pm (+224/-50)
lib/OSCCaptureSync.pm (+0/-142)
lib/OobNibbleIterator.pm (+1/-1)
lib/PerconaTest.pm (+132/-5)
lib/Processlist.pm (+16/-3)
lib/ProtocolParser.pm (+1/-1)
lib/QueryAdvisorRules.pm (+1/-1)
lib/QueryReportFormatter.pm (+6/-8)
lib/QueryRewriter.pm (+24/-4)
lib/ReadKeyMini.pm (+23/-14)
lib/RowChecksum.pm (+1/-1)
lib/SQLParser.pm (+103/-8)
lib/Sandbox.pm (+240/-17)
lib/TableChecksum.pm (+3/-10)
lib/TableNibbler.pm (+7/-1)
lib/TableParser.pm (+34/-14)
lib/TableSyncChunk.pm (+1/-1)
lib/TableSyncNibble.pm (+1/-1)
lib/TableSyncer.pm (+3/-8)
lib/TableUsage.pm (+1080/-0)
lib/Transformers.pm (+94/-0)
lib/UpgradeReportFormatter.pm (+14/-5)
lib/VariableAdvisorRules.pm (+6/-22)
lib/VersionParser.pm (+146/-26)
lib/bash/alt_cmds.sh (+25/-1)
lib/bash/collect_mysql_info.sh (+264/-0)
lib/bash/collect_system_info.sh (+576/-0)
lib/bash/log_warn_die.sh (+6/-0)
lib/bash/parse_options.sh (+7/-7)
lib/bash/report_formatting.sh (+122/-0)
lib/bash/report_mysql_info.sh (+1391/-0)
lib/bash/report_system_info.sh (+1050/-0)
lib/bash/summary_common.sh (+155/-0)
lib/bash/tmpdir.sh (+14/-10)
sandbox/jenkins-test (+44/-17)
sandbox/servers/4.1/my.sandbox.cnf (+1/-0)
sandbox/servers/5.0/my.sandbox.cnf (+1/-0)
sandbox/servers/5.1/my.sandbox.cnf (+1/-0)
sandbox/servers/5.5/my.sandbox.cnf (+2/-0)
sandbox/start-sandbox (+31/-15)
sandbox/stop-sandbox (+8/-2)
sandbox/test-env (+63/-67)
t/lib/ChangeHandler.t (+18/-15)
t/lib/CleanupTask.t (+18/-1)
t/lib/CompareQueryTimes.t (+8/-7)
t/lib/CompareResults.t (+29/-32)
t/lib/CompareWarnings.t (+10/-9)
t/lib/CopyRowsInsertSelect.t (+3/-3)
t/lib/Cxn.t (+3/-2)
t/lib/DSNParser.t (+108/-17)
t/lib/Daemon.t (+50/-36)
t/lib/DuplicateKeyFinder.t (+2/-1)
t/lib/EventAggregator.t (+16/-1)
t/lib/ExplainAnalyzer.t (+2/-1)
t/lib/IndexLength.pm (+135/-0)
t/lib/IndexUsage.t (+3/-2)
t/lib/KeySize.t (+2/-1)
t/lib/MasterSlave.t (+114/-16)
t/lib/Mo/Bar.pm (+4/-0)
t/lib/Mo/Boo.pm (+6/-0)
t/lib/Mo/Foo.pm (+6/-0)
t/lib/Mo/build.t (+51/-0)
t/lib/Mo/buildargs.t (+62/-0)
t/lib/Mo/coerce.t (+27/-0)
t/lib/Mo/extends.t (+26/-0)
t/lib/Mo/handles.t (+482/-0)
t/lib/Mo/init_arg.t (+91/-0)
t/lib/Mo/is.t (+26/-0)
t/lib/Mo/isa.t (+185/-0)
t/lib/Mo/object.t (+20/-0)
t/lib/Mo/required.t (+39/-0)
t/lib/Mo/strict.t (+19/-0)
t/lib/Mo/test.t (+140/-0)
t/lib/MockSyncStream.t (+3/-2)
t/lib/MySQLConfig.t (+2/-1)
t/lib/NibbleIterator.t (+80/-35)
t/lib/OSCCaptureSync.t (+0/-131)
t/lib/OobNibbleIterator.t (+38/-3)
t/lib/Outfile.t (+2/-1)
t/lib/Processlist.t (+26/-20)
t/lib/QueryReportFormatter.t (+2/-2)
t/lib/QueryReview.t (+3/-2)
t/lib/QueryRewriter.t (+59/-1)
t/lib/Quoter.t (+14/-7)
t/lib/RowChecksum.t (+2/-1)
t/lib/RowDiff-custom.t (+2/-1)
t/lib/RowDiff.t (+2/-1)
t/lib/SQLParser.t (+1/-1)
t/lib/SchemaIterator.t (+35/-9)
t/lib/TableChecksum.t (+7/-15)
t/lib/TableChunker.t (+25/-15)
t/lib/TableNibbler.t (+62/-1)
t/lib/TableParser.t (+27/-11)
t/lib/TableSyncChunk.t (+3/-4)
t/lib/TableSyncNibble.t (+2/-5)
t/lib/TableSyncer.t (+2/-9)
t/lib/TableUsage.t (+817/-0)
t/lib/Transformers.t (+106/-2)
t/lib/UpgradeReportFormatter.t (+4/-2)
t/lib/VariableAdvisorRules.t (+7/-6)
t/lib/VersionParser.t (+114/-8)
t/lib/bash/alt_cmds.sh (+2/-2)
t/lib/bash/collect.sh (+15/-13)
t/lib/bash/collect_mysql_info.sh (+199/-0)
t/lib/bash/collect_system_info.sh (+314/-0)
t/lib/bash/daemon.sh (+9/-9)
t/lib/bash/log_warn_die.sh (+8/-8)
t/lib/bash/parse_options.sh (+2/-2)
t/lib/bash/report_formatting.sh (+113/-0)
t/lib/bash/report_mysql_info.sh (+723/-0)
t/lib/bash/report_system_info.sh (+1580/-0)
t/lib/bash/safeguards.sh (+12/-12)
t/lib/bash/summary_common.sh (+79/-0)
t/lib/bash/tmpdir.sh (+29/-7)
t/lib/samples/SchemaIterator.sql (+29/-10)
t/lib/samples/SchemaIterator/all-dbs-tbls-5.0.txt (+99/-41)
t/lib/samples/SchemaIterator/all-dbs-tbls-5.1.txt (+226/-60)
t/lib/samples/SchemaIterator/all-dbs-tbls.txt (+553/-0)
t/lib/samples/SchemaIterator/mysql-user-ddl-5.5.txt (+47/-0)
t/lib/samples/SchemaIterator/resume-from-ignored-sakila-payment-5.0.txt (+52/-0)
t/lib/samples/SchemaIterator/resume-from-sakila-payment-5.0.txt (+70/-0)
t/lib/samples/ansi.quoting.sql (+9/-0)
t/lib/samples/pod/mqa-rule-LIT.001.pod (+2/-2)
t/lib/samples/pod/pod_sample_01.txt (+3/-3)
t/lib/samples/pod/pod_sample_02.txt (+3/-3)
t/lib/samples/pod/pod_sample_03.txt (+3/-3)
t/lib/samples/pod/pod_sample_04.txt (+3/-3)
t/lib/samples/pod/pod_sample_issue_140.txt (+2/-2)
t/lib/samples/pod/pod_sample_mqa.txt (+2/-2)
t/lib/samples/podsample.txt (+4/-4)
t/lib/samples/ro-checksum-user.sql (+3/-0)
t/lib/samples/slowlogs/slow055.txt (+15/-0)
t/pt-archiver/basics.t (+5/-0)
t/pt-archiver/bulk_delete.t (+2/-1)
t/pt-archiver/bulk_insert.t (+2/-1)
t/pt-archiver/bulk_regular_insert.t (+2/-1)
t/pt-archiver/check_slave_lag.t (+2/-2)
t/pt-archiver/compact_col_vals.t (+2/-1)
t/pt-archiver/delete_more.t (+2/-4)
t/pt-archiver/dest.t (+2/-1)
t/pt-archiver/file.t (+5/-0)
t/pt-archiver/gt_n.t (+2/-2)
t/pt-archiver/indexes.t (+2/-1)
t/pt-archiver/issue_1152.t (+2/-1)
t/pt-archiver/issue_1166.t (+2/-1)
t/pt-archiver/issue_1225.t (+2/-4)
t/pt-archiver/issue_1229.t (+6/-2)
t/pt-archiver/issue_131.t (+2/-1)
t/pt-archiver/issue_524.t (+2/-1)
t/pt-archiver/issue_655.t (+2/-1)
t/pt-archiver/plugin.t (+2/-1)
t/pt-archiver/purge.t (+2/-1)
t/pt-archiver/res_fk.t (+2/-1)
t/pt-archiver/safe_auto_increment.t (+2/-1)
t/pt-archiver/samples/bulk_regular_insert.pm (+3/-3)
t/pt-archiver/samples/compact_col_vals.pm (+10/-10)
t/pt-archiver/samples/delete_more.pm (+8/-8)
t/pt-archiver/samples/gt_n.pm (+8/-8)
t/pt-archiver/samples/res_fk.pm (+11/-11)
t/pt-archiver/samples/table1.sql (+1/-1)
t/pt-archiver/samples/table5.sql (+4/-4)
t/pt-archiver/samples/tables1-4.sql (+4/-4)
t/pt-archiver/samples/tables7-9.sql (+2/-2)
t/pt-archiver/standard_options.t (+5/-5)
t/pt-config-diff/basics.t (+2/-1)
t/pt-config-diff/reports.t (+2/-1)
t/pt-deadlock-logger/basics.t (+10/-2)
t/pt-deadlock-logger/bugs.t (+73/-0)
t/pt-deadlock-logger/clear_deadlocks.t (+2/-1)
t/pt-deadlock-logger/create_dest_table.t (+4/-3)
t/pt-deadlock-logger/samples/bug_903443.txt (+53/-0)
t/pt-deadlock-logger/standard_options.t (+2/-1)
t/pt-diskstats/pt-diskstats.t (+6/-0)
t/pt-duplicate-key-checker/basics.t (+60/-11)
t/pt-duplicate-key-checker/clustered_keys.t (+2/-1)
t/pt-duplicate-key-checker/issue_1192.t (+2/-1)
t/pt-duplicate-key-checker/issue_298.t (+2/-1)
t/pt-duplicate-key-checker/issue_331.t (+2/-1)
t/pt-duplicate-key-checker/issue_663.t (+2/-1)
t/pt-duplicate-key-checker/samples/bug-894140.txt (+32/-0)
t/pt-duplicate-key-checker/samples/key-types-f.txt (+5/-0)
t/pt-duplicate-key-checker/samples/key-types-fk.txt (+5/-0)
t/pt-duplicate-key-checker/samples/key-types-k.txt (+5/-0)
t/pt-find/pt-find.t (+15/-6)
t/pt-fingerprint/basics.t (+101/-0)
t/pt-fingerprint/samples/query001 (+2/-0)
t/pt-fingerprint/samples/query001.fingerprint (+1/-0)
t/pt-fingerprint/samples/query002 (+2/-0)
t/pt-fingerprint/samples/query002.fingerprint (+1/-0)
t/pt-fk-error-logger/basics.t (+2/-1)
t/pt-heartbeat/basics.t (+78/-15)
t/pt-heartbeat/multi_update_mode.t (+2/-1)
t/pt-heartbeat/standard_options.t (+2/-1)
t/pt-index-usage/basics.t (+3/-2)
t/pt-index-usage/save_results.t (+3/-2)
t/pt-ioprofile/pt-ioprofile.t (+5/-5)
t/pt-ioprofile/summarize_strace.sh (+5/-5)
t/pt-ioprofile/tabulate_strace.sh (+5/-5)
t/pt-kill/basics.t (+31/-4)
t/pt-kill/execute_command.t (+6/-4)
t/pt-kill/kill.t (+158/-3)
t/pt-kill/match.t (+2/-1)
t/pt-kill/standard_options.t (+3/-2)
t/pt-log-player/issue_799.t (+2/-1)
t/pt-log-player/issue_903.t (+2/-1)
t/pt-log-player/play.t (+2/-1)
t/pt-mysql-summary/find_my_cnf_file.sh (+0/-20)
t/pt-mysql-summary/format_binlog_filters.sh (+0/-12)
t/pt-mysql-summary/format_innodb_status.sh (+0/-147)
t/pt-mysql-summary/format_overall_db_stats.sh (+0/-61)
t/pt-mysql-summary/format_status_variables.sh (+0/-97)
t/pt-mysql-summary/fuzz.sh (+0/-7)
t/pt-mysql-summary/get_mysql_info.sh (+0/-26)
t/pt-mysql-summary/parse_mysqld_instances.sh (+0/-47)
t/pt-mysql-summary/pretty_print_cnf_file.sh (+0/-40)
t/pt-mysql-summary/pt-mysql-summary.t (+54/-2)
t/pt-mysql-summary/samples/expected_output_temp002.txt (+276/-0)
t/pt-mysql-summary/samples/expected_output_temp003.txt (+219/-0)
t/pt-mysql-summary/samples/expected_output_temp004.txt (+218/-0)
t/pt-mysql-summary/samples/expected_output_temp005.txt (+291/-0)
t/pt-mysql-summary/samples/expected_result_report_summary.txt (+257/-0)
t/pt-mysql-summary/samples/mysql-variables-with-semisync.txt (+326/-0)
t/pt-mysql-summary/samples/temp001/mysql-status (+304/-0)
t/pt-mysql-summary/samples/temp001/mysql-variables (+356/-0)
t/pt-mysql-summary/samples/temp002/innodb-status (+118/-0)
t/pt-mysql-summary/samples/temp002/mysql-config-file (+26/-0)
t/pt-mysql-summary/samples/temp002/mysql-databases (+6/-0)
t/pt-mysql-summary/samples/temp002/mysql-plugins (+35/-0)
t/pt-mysql-summary/samples/temp002/mysql-processlist (+12/-0)
t/pt-mysql-summary/samples/temp002/mysql-status (+370/-0)
t/pt-mysql-summary/samples/temp002/mysql-status-defer (+370/-0)
t/pt-mysql-summary/samples/temp002/mysql-users (+1/-0)
t/pt-mysql-summary/samples/temp002/mysql-variables (+372/-0)
t/pt-mysql-summary/samples/temp002/mysqld-instances (+4/-0)
t/pt-mysql-summary/samples/temp002/mysqldump (+396/-0)
t/pt-mysql-summary/samples/temp003/innodb-status (+77/-0)
t/pt-mysql-summary/samples/temp003/mysql-config-file (+26/-0)
t/pt-mysql-summary/samples/temp003/mysql-databases (+2/-0)
t/pt-mysql-summary/samples/temp003/mysql-master-logs (+1/-0)
t/pt-mysql-summary/samples/temp003/mysql-master-status (+1/-0)
t/pt-mysql-summary/samples/temp003/mysql-plugins (+10/-0)
t/pt-mysql-summary/samples/temp003/mysql-processlist (+9/-0)
t/pt-mysql-summary/samples/temp003/mysql-status (+291/-0)
t/pt-mysql-summary/samples/temp003/mysql-status-defer (+291/-0)
t/pt-mysql-summary/samples/temp003/mysql-users (+1/-0)
t/pt-mysql-summary/samples/temp003/mysql-variables (+285/-0)
t/pt-mysql-summary/samples/temp003/mysqld-instances (+2/-0)
t/pt-mysql-summary/samples/temp004/innodb-status (+77/-0)
t/pt-mysql-summary/samples/temp004/mysql-config-file (+26/-0)
t/pt-mysql-summary/samples/temp004/mysql-databases (+3/-0)
t/pt-mysql-summary/samples/temp004/mysql-master-logs (+2/-0)
t/pt-mysql-summary/samples/temp004/mysql-master-status (+1/-0)
t/pt-mysql-summary/samples/temp004/mysql-plugins (+10/-0)
t/pt-mysql-summary/samples/temp004/mysql-processlist (+9/-0)
t/pt-mysql-summary/samples/temp004/mysql-status (+291/-0)
t/pt-mysql-summary/samples/temp004/mysql-status-defer (+291/-0)
t/pt-mysql-summary/samples/temp004/mysql-users (+1/-0)
t/pt-mysql-summary/samples/temp004/mysql-variables (+285/-0)
t/pt-mysql-summary/samples/temp004/mysqld-instances (+2/-0)
t/pt-mysql-summary/samples/temp005/innodb-status (+108/-0)
t/pt-mysql-summary/samples/temp005/mysql-config-file (+26/-0)
t/pt-mysql-summary/samples/temp005/mysql-databases (+3/-0)
t/pt-mysql-summary/samples/temp005/mysql-master-logs (+1/-0)
t/pt-mysql-summary/samples/temp005/mysql-master-status (+1/-0)
t/pt-mysql-summary/samples/temp005/mysql-plugins (+28/-0)
t/pt-mysql-summary/samples/temp005/mysql-processlist (+18/-0)
t/pt-mysql-summary/samples/temp005/mysql-status (+304/-0)
t/pt-mysql-summary/samples/temp005/mysql-status-defer (+304/-0)
t/pt-mysql-summary/samples/temp005/mysql-users (+1/-0)
t/pt-mysql-summary/samples/temp005/mysql-variables (+363/-0)
t/pt-mysql-summary/samples/temp005/mysqld-executables (+1/-0)
t/pt-mysql-summary/samples/temp005/mysqld-instances (+4/-0)
t/pt-mysql-summary/samples/temp005/mysqldump (+1084/-0)
t/pt-mysql-summary/samples/tempdir/innodb-status (+77/-0)
t/pt-mysql-summary/samples/tempdir/mysql-config-file (+26/-0)
t/pt-mysql-summary/samples/tempdir/mysql-databases (+3/-0)
t/pt-mysql-summary/samples/tempdir/mysql-master-logs (+3/-0)
t/pt-mysql-summary/samples/tempdir/mysql-master-status (+1/-0)
t/pt-mysql-summary/samples/tempdir/mysql-plugins (+10/-0)
t/pt-mysql-summary/samples/tempdir/mysql-processlist (+9/-0)
t/pt-mysql-summary/samples/tempdir/mysql-status (+291/-0)
t/pt-mysql-summary/samples/tempdir/mysql-status-defer (+291/-0)
t/pt-mysql-summary/samples/tempdir/mysql-users (+5/-0)
t/pt-mysql-summary/samples/tempdir/mysql-variables (+283/-0)
t/pt-mysql-summary/samples/tempdir/mysqld-instances (+4/-0)
t/pt-mysql-summary/samples/tempdir/mysqldump (+328/-0)
t/pt-mysql-summary/samples/tempdir/tempfile (+130/-0)
t/pt-mysql-summary/summarize_binlogs.sh (+0/-13)
t/pt-mysql-summary/summarize_processlist.sh (+0/-64)
t/pt-online-schema-change/alter_active_table.t (+73/-52)
t/pt-online-schema-change/basics.t (+566/-220)
t/pt-online-schema-change/bugs.t (+119/-0)
t/pt-online-schema-change/check_tables.t (+0/-126)
t/pt-online-schema-change/option_sanity.t (+34/-13)
t/pt-online-schema-change/privs.t (+96/-0)
t/pt-online-schema-change/samples/basic_no_fks.data (+500/-500)
t/pt-online-schema-change/samples/basic_no_fks.sql (+30/-0)
t/pt-online-schema-change/samples/basic_with_fks.sql (+56/-0)
t/pt-online-schema-change/samples/bug-1002448.sql (+14/-0)
t/pt-online-schema-change/samples/bug-1003315.sql (+23/-0)
t/pt-online-schema-change/samples/fk_tables_schema.sql (+0/-31)
t/pt-online-schema-change/samples/osc-user.sql (+3/-0)
t/pt-online-schema-change/samples/pk-bug-994002.sql (+29/-0)
t/pt-online-schema-change/samples/query_table.pl (+14/-6)
t/pt-online-schema-change/samples/small_table.sql (+0/-27)
t/pt-online-schema-change/sanity_checks.t (+112/-0)
t/pt-online-schema-change/skip_innodb.t (+58/-0)
t/pt-pmp/aggregate_stacktrace.sh (+19/-19)
t/pt-query-advisor/get_create_table.t (+2/-1)
t/pt-query-advisor/review.t (+10/-9)
t/pt-query-advisor/samples/cla-006-01.txt (+1/-1)
t/pt-query-advisor/samples/cla-007-01.txt (+1/-1)
t/pt-query-digest/collect_and_report_cycles.t (+2/-1)
t/pt-query-digest/daemon.t (+2/-1)
t/pt-query-digest/execute.t (+2/-3)
t/pt-query-digest/explain.t (+6/-6)
t/pt-query-digest/explain_partitions.t (+3/-3)
t/pt-query-digest/issue_1186.t (+2/-1)
t/pt-query-digest/issue_360.t (+30/-15)
t/pt-query-digest/mirror.t (+3/-2)
t/pt-query-digest/processlist.t (+2/-1)
t/pt-query-digest/read_timeout.t (+9/-2)
t/pt-query-digest/review.t (+97/-58)
t/pt-query-digest/run_time.t (+2/-1)
t/pt-query-digest/samples/filter-add-ymdh-attribs.txt (+2/-2)
t/pt-query-digest/samples/slow007_explain_1-55.txt (+46/-0)
t/pt-query-digest/samples/slow055.txt (+30/-0)
t/pt-query-digest/since_until.t (+2/-1)
t/pt-query-digest/slowlog_analyses.t (+13/-1)
t/pt-query-digest/standard_options.t (+2/-1)
t/pt-show-grants/all_grants.t (+2/-1)
t/pt-show-grants/basics.t (+2/-1)
t/pt-show-grants/issue_445.t (+2/-1)
t/pt-sift/pt-sift.t (+1/-4)
t/pt-slave-delay/auto_restart.t (+42/-5)
t/pt-slave-delay/basics.t (+9/-1)
t/pt-slave-delay/issue_1169.t (+1/-1)
t/pt-slave-delay/standard_options.t (+3/-2)
t/pt-slave-find/pt-slave-find.t (+42/-11)
t/pt-slave-restart/pt-slave-restart.t (+11/-5)
t/pt-stalk/pt-stalk.t (+17/-17)
t/pt-summary/format_vmstat.sh (+0/-37)
t/pt-summary/parse_arcconf.sh (+0/-176)
t/pt-summary/parse_dmidecode_mem_devices.sh (+0/-104)
t/pt-summary/parse_ethernet_controller_lspci.sh (+0/-11)
t/pt-summary/parse_fdisk.sh (+0/-16)
t/pt-summary/parse_filesystems.sh (+0/-52)
t/pt-summary/parse_free_minus_b.sh (+0/-67)
t/pt-summary/parse_fusionmpt_lsiutil.sh (+0/-50)
t/pt-summary/parse_hpacucli.sh (+0/-26)
t/pt-summary/parse_ip_s_link.sh (+0/-28)
t/pt-summary/parse_lsi_megaraid.sh (+0/-696)
t/pt-summary/parse_netstat.sh (+0/-49)
t/pt-summary/parse_proc_cpuinfo.sh (+0/-74)
t/pt-summary/parse_raid_controller_dmesg.sh (+0/-32)
t/pt-summary/parse_raid_controller_lspci.sh (+0/-39)
t/pt-summary/parse_virtualization_dmesg.sh (+0/-10)
t/pt-summary/pt-summary.t (+12/-2)
t/pt-summary/samples/BSD/freebsd_001/mounted_fs (+7/-0)
t/pt-summary/samples/BSD/freebsd_001/notable_procs (+2/-0)
t/pt-summary/samples/BSD/freebsd_001/processes (+10/-0)
t/pt-summary/samples/BSD/freebsd_001/summary (+10/-0)
t/pt-summary/samples/BSD/freebsd_001/sysctl (+1481/-0)
t/pt-summary/samples/BSD/freebsd_001/uptime (+1/-0)
t/pt-summary/samples/BSD/freebsd_001/vmstat (+7/-0)
t/pt-summary/samples/BSD/netbsd_001/mounted_fs (+5/-0)
t/pt-summary/samples/BSD/netbsd_001/notable_procs (+2/-0)
t/pt-summary/samples/BSD/netbsd_001/proc_cpuinfo_copy (+14/-0)
t/pt-summary/samples/BSD/netbsd_001/processes (+10/-0)
t/pt-summary/samples/BSD/netbsd_001/summary (+10/-0)
t/pt-summary/samples/BSD/netbsd_001/swapctl (+1/-0)
t/pt-summary/samples/BSD/netbsd_001/sysctl (+511/-0)
t/pt-summary/samples/BSD/netbsd_001/uptime (+1/-0)
t/pt-summary/samples/BSD/netbsd_001/vmstat (+7/-0)
t/pt-summary/samples/BSD/openbsd_001/mounted_fs (+4/-0)
t/pt-summary/samples/BSD/openbsd_001/notable_procs (+2/-0)
t/pt-summary/samples/BSD/openbsd_001/processes (+10/-0)
t/pt-summary/samples/BSD/openbsd_001/summary (+10/-0)
t/pt-summary/samples/BSD/openbsd_001/swapctl (+1/-0)
t/pt-summary/samples/BSD/openbsd_001/sysctl (+423/-0)
t/pt-summary/samples/BSD/openbsd_001/uptime (+1/-0)
t/pt-summary/samples/BSD/openbsd_001/vmstat (+7/-0)
t/pt-summary/samples/Linux/001/dmesg_file (+786/-0)
t/pt-summary/samples/Linux/001/dmidecode (+412/-0)
t/pt-summary/samples/Linux/001/ip (+24/-0)
t/pt-summary/samples/Linux/001/lspci_file (+17/-0)
t/pt-summary/samples/Linux/001/lvs (+1/-0)
t/pt-summary/samples/Linux/001/memory (+50/-0)
t/pt-summary/samples/Linux/001/mounted_fs (+12/-0)
t/pt-summary/samples/Linux/001/netstat (+6/-0)
t/pt-summary/samples/Linux/001/notable_procs (+5/-0)
t/pt-summary/samples/Linux/001/partitioning (+30/-0)
t/pt-summary/samples/Linux/001/proc_cpuinfo_copy (+58/-0)
t/pt-summary/samples/Linux/001/proc_cpuinfo_copy.unq (+1/-0)
t/pt-summary/samples/Linux/001/processes (+10/-0)
t/pt-summary/samples/Linux/001/summary (+23/-0)
t/pt-summary/samples/Linux/001/sysctl (+905/-0)
t/pt-summary/samples/Linux/001/uptime (+1/-0)
t/pt-summary/samples/Linux/001/vmstat (+7/-0)
t/pt-summary/samples/Linux/002/dmesg_file (+283/-0)
t/pt-summary/samples/Linux/002/memory (+34/-0)
t/pt-summary/samples/Linux/002/mounted_fs (+3/-0)
t/pt-summary/samples/Linux/002/netstat (+6/-0)
t/pt-summary/samples/Linux/002/notable_procs (+2/-0)
t/pt-summary/samples/Linux/002/partitioning (+9/-0)
t/pt-summary/samples/Linux/002/proc_cpuinfo_copy (+19/-0)
t/pt-summary/samples/Linux/002/processes (+10/-0)
t/pt-summary/samples/Linux/002/summary (+19/-0)
t/pt-summary/samples/Linux/002/uptime (+1/-0)
t/pt-summary/samples/Linux/002/vmstat (+7/-0)
t/pt-summary/samples/Linux/003/dmesg_file (+283/-0)
t/pt-summary/samples/Linux/003/memory (+34/-0)
t/pt-summary/samples/Linux/003/mounted_fs (+3/-0)
t/pt-summary/samples/Linux/003/netstat (+6/-0)
t/pt-summary/samples/Linux/003/notable_procs (+2/-0)
t/pt-summary/samples/Linux/003/partitioning (+1/-0)
t/pt-summary/samples/Linux/003/proc_cpuinfo_copy (+19/-0)
t/pt-summary/samples/Linux/003/processes (+10/-0)
t/pt-summary/samples/Linux/003/summary (+19/-0)
t/pt-summary/samples/Linux/003/uptime (+1/-0)
t/pt-summary/samples/Linux/003/vmstat (+7/-0)
t/pt-summary/samples/Linux/output_002.txt (+82/-0)
t/pt-summary/samples/Linux/output_003.txt (+79/-0)
t/pt-summary/samples/MegaCli64_AdpAllInfo_aALL001.txt (+227/-0)
t/pt-summary/samples/MegaCli64_LdPdInfo_aALL_886223 (+214/-0)
t/pt-summary/samples/arcconf-001.txt (+133/-0)
t/pt-summary/samples/arcconf-003_900285.txt (+228/-0)
t/pt-summary/samples/arcconf-004_917781.txt (+162/-0)
t/pt-summary/samples/dmesg-005.txt (+787/-0)
t/pt-summary/samples/dmesg-007.txt (+136/-0)
t/pt-summary/samples/hpaculi-001.txt (+11/-0)
t/pt-summary/samples/hpaculi-002.txt (+354/-0)
t/pt-summary/samples/hpaculi-003.txt (+11/-0)
t/pt-summary/samples/ip-s-link-003.txt (+24/-0)
t/pt-summary/samples/lspci-005.txt (+38/-0)
t/pt-summary/samples/netstat-002.txt (+1328/-0)
t/pt-summary/samples/proc_cpuinfo001.txt (+57/-0)
t/pt-summary/samples/proc_cpuinfo001.txt.unq (+1/-0)
t/pt-summary/samples/proc_cpuinfo002.txt (+57/-0)
t/pt-summary/samples/proc_cpuinfo002.txt.unq (+1/-0)
t/pt-table-checksum/basics.t (+47/-24)
t/pt-table-checksum/bugs.t (+142/-0)
t/pt-table-checksum/char_chunking.t (+2/-1)
t/pt-table-checksum/chunk_index.t (+106/-0)
t/pt-table-checksum/chunk_size.t (+5/-4)
t/pt-table-checksum/create_replicate_table.t (+2/-2)
t/pt-table-checksum/error_handling.t (+2/-1)
t/pt-table-checksum/filters.t (+2/-2)
t/pt-table-checksum/float_precision.t (+2/-1)
t/pt-table-checksum/fnv_64.t (+2/-1)
t/pt-table-checksum/ignore_columns.t (+2/-3)
t/pt-table-checksum/issue_388.t (+3/-2)
t/pt-table-checksum/issue_47.t (+2/-1)
t/pt-table-checksum/issue_602.t (+2/-1)
t/pt-table-checksum/privs.t (+106/-0)
t/pt-table-checksum/progress.t (+52/-16)
t/pt-table-checksum/replication_filters.t (+82/-49)
t/pt-table-checksum/resume.t (+9/-7)
t/pt-table-checksum/samples/bad-plan-bug-1010232.sql (+17/-0)
t/pt-table-checksum/samples/default-results-5.0.txt (+4/-2)
t/pt-table-checksum/samples/default-results-5.1.txt (+3/-1)
t/pt-table-checksum/samples/default-results-5.5.txt (+41/-0)
t/pt-table-checksum/samples/dsn-table.sql (+15/-0)
t/pt-table-checksum/samples/empty-table-bug-987393.sql (+18/-0)
t/pt-table-checksum/samples/issue_602.sql (+18/-18)
t/pt-table-checksum/samples/n-chunk-index-cols.txt (+19/-0)
t/pt-table-checksum/samples/not-using-pk-bug.out (+20/-0)
t/pt-table-checksum/samples/not-using-pk-bug.sql (+20/-0)
t/pt-table-checksum/samples/static-chunk-size-results-5.0.txt (+4/-2)
t/pt-table-checksum/samples/static-chunk-size-results-5.1.txt (+3/-1)
t/pt-table-checksum/samples/static-chunk-size-results-5.5.txt (+41/-0)
t/pt-table-checksum/samples/undef-arrayref-bug-995274.sql (+18/-0)
t/pt-table-checksum/skip_innodb.t (+77/-0)
t/pt-table-checksum/standard_options.t (+2/-1)
t/pt-table-checksum/throttle.t (+34/-27)
t/pt-table-sync/basics.t (+10/-9)
t/pt-table-sync/bidirectional.t (+4/-3)
t/pt-table-sync/binlog_format.t (+26/-27)
t/pt-table-sync/bugs.t (+156/-0)
t/pt-table-sync/char_chunking.t (+2/-1)
t/pt-table-sync/check_privs.t (+2/-2)
t/pt-table-sync/columns.t (+2/-2)
t/pt-table-sync/filters.t (+210/-71)
t/pt-table-sync/float_precision.t (+2/-2)
t/pt-table-sync/force_index.t (+2/-2)
t/pt-table-sync/hex_blob.t (+2/-1)
t/pt-table-sync/instrumentaiton.t (+2/-1)
t/pt-table-sync/issue_1052.t (+2/-1)
t/pt-table-sync/issue_1065.t (+15/-7)
t/pt-table-sync/issue_218.t (+2/-1)
t/pt-table-sync/issue_22.t (+2/-1)
t/pt-table-sync/issue_262.t (+2/-1)
t/pt-table-sync/issue_408.t (+3/-2)
t/pt-table-sync/issue_560.t (+3/-7)
t/pt-table-sync/issue_616.t (+13/-9)
t/pt-table-sync/issue_627.t (+2/-1)
t/pt-table-sync/issue_631.t (+2/-1)
t/pt-table-sync/issue_634.t (+19/-8)
t/pt-table-sync/issue_644.t (+2/-1)
t/pt-table-sync/issue_79.t (+0/-85)
t/pt-table-sync/issue_804.t (+2/-4)
t/pt-table-sync/issue_920.t (+2/-1)
t/pt-table-sync/issue_96.t (+2/-1)
t/pt-table-sync/issue_965.t (+2/-1)
t/pt-table-sync/issue_996.t (+2/-1)
t/pt-table-sync/lock_and_rename.t (+10/-11)
t/pt-table-sync/lock_level.t (+2/-2)
t/pt-table-sync/master_master.t (+60/-23)
t/pt-table-sync/replicate_do_db.t (+108/-98)
t/pt-table-sync/samples/filter_tables.sql (+0/-13)
t/pt-table-sync/samples/issue_22.sql (+1/-1)
t/pt-table-sync/samples/issue_533.sql (+12/-8)
t/pt-table-sync/samples/wrong-tbl-struct-bug-1003014.sql (+35/-0)
t/pt-table-sync/specify_column_or_index.t (+2/-2)
t/pt-table-sync/sync_to_differnt_db.t (+2/-2)
t/pt-table-sync/traces.t (+28/-18)
t/pt-table-sync/triggers.t (+5/-17)
t/pt-table-sync/wait.t (+2/-1)
t/pt-table-sync/zero_chunk.t (+2/-1)
t/pt-table-usage/basics.t (+186/-0)
t/pt-table-usage/create_table_definitions.t (+41/-0)
t/pt-table-usage/explain_extended.t (+80/-0)
t/pt-table-usage/samples/ee.out (+6/-0)
t/pt-table-usage/samples/ee.sql (+26/-0)
t/pt-table-usage/samples/in/slow001.txt (+24/-0)
t/pt-table-usage/samples/in/slow002.txt (+20/-0)
t/pt-table-usage/samples/in/slow003.txt (+3/-0)
t/pt-table-usage/samples/out/create-table-defs-001.txt (+4/-0)
t/pt-table-usage/samples/out/create001.txt (+5/-0)
t/pt-table-usage/samples/out/drop-table-if-exists.txt (+3/-0)
t/pt-table-usage/samples/out/query001.txt (+6/-0)
t/pt-table-usage/samples/out/query002.txt (+5/-0)
t/pt-table-usage/samples/out/slow001.txt (+31/-0)
t/pt-table-usage/samples/out/slow002.txt (+40/-0)
t/pt-table-usage/samples/out/slow003-001.txt (+6/-0)
t/pt-table-usage/samples/out/slow003-002.txt (+8/-0)
t/pt-table-usage/samples/out/slow003-003.txt (+6/-0)
t/pt-upgrade/basics.t (+4/-3)
t/pt-upgrade/daemon.t (+3/-1)
t/pt-upgrade/rewrite_non_select.t (+16/-9)
t/pt-upgrade/samples/001/non-selects-rewritten.txt (+63/-57)
t/pt-upgrade/samples/001/non-selects.txt (+21/-19)
t/pt-upgrade/samples/001/select-everyone-no-stats.txt (+21/-19)
t/pt-upgrade/samples/001/select-everyone-rows.txt (+21/-19)
t/pt-upgrade/samples/001/select-everyone.txt (+21/-19)
t/pt-upgrade/samples/001/select-one-rows.txt (+21/-19)
t/pt-upgrade/samples/001/select-one.txt (+21/-19)
t/pt-upgrade/samples/002/report-01.txt (+24/-22)
t/pt-upgrade/samples/003/report001.txt (+24/-22)
t/pt-upgrade/skip_non_select.t (+3/-2)
t/pt-upgrade/warnings.t (+6/-5)
t/pt-variable-advisor/show_variables_online.t (+2/-1)
util/build-snapshot (+171/-0)
util/checksum-test-dataset (+65/-0)
util/diff-and-restart-sandbox (+27/-0)
util/kill-mysql-process (+44/-0)
util/make-barebones (+47/-0)
util/test-bash-functions (+71/-9)
util/update-modules (+4/-4)
Text conflict in Changelog
Text conflict in Makefile.PL
Text conflict in bin/pt-align
Text conflict in bin/pt-archiver
Text conflict in bin/pt-config-diff
Text conflict in bin/pt-deadlock-logger
Text conflict in bin/pt-diskstats
Text conflict in bin/pt-duplicate-key-checker
Text conflict in bin/pt-fifo-split
Text conflict in bin/pt-find
Text conflict in bin/pt-fk-error-logger
Text conflict in bin/pt-heartbeat
Text conflict in bin/pt-index-usage
Text conflict in bin/pt-ioprofile
Text conflict in bin/pt-kill
Text conflict in bin/pt-log-player
Text conflict in bin/pt-mext
Text conflict in bin/pt-mysql-summary
Text conflict in bin/pt-online-schema-change
Text conflict in bin/pt-pmp
Text conflict in bin/pt-query-advisor
Text conflict in bin/pt-query-digest
Text conflict in bin/pt-show-grants
Text conflict in bin/pt-sift
Text conflict in bin/pt-slave-delay
Text conflict in bin/pt-slave-find
Text conflict in bin/pt-slave-restart
Text conflict in bin/pt-stalk
Text conflict in bin/pt-summary
Text conflict in bin/pt-table-checksum
Text conflict in bin/pt-table-sync
Text conflict in bin/pt-tcp-model
Text conflict in bin/pt-trend
Text conflict in bin/pt-upgrade
Text conflict in bin/pt-variable-advisor
Text conflict in bin/pt-visual-explain
Text conflict in config/deb/changelog
Text conflict in config/sphinx-build/conf.py
Text conflict in docs/percona-toolkit.pod
Text conflict in docs/release_notes.rst
Text conflict in lib/Cxn.pm
Text conflict in lib/NibbleIterator.pm
Text conflict in lib/bash/tmpdir.sh
Text conflict in sandbox/start-sandbox
Text conflict in t/lib/DSNParser.t
Text conflict in t/lib/NibbleIterator.t
Text conflict in t/lib/OobNibbleIterator.t
Text conflict in t/lib/Processlist.t
Text conflict in t/lib/SchemaIterator.t
Text conflict in t/lib/TableChunker.t
Text conflict in t/lib/samples/SchemaIterator/all-dbs-tbls-5.0.txt
Text conflict in t/lib/samples/SchemaIterator/all-dbs-tbls-5.1.txt
Conflict adding file t/lib/samples/SchemaIterator/resume-from-ignored-sakila-payment-5.0.txt.  Moved existing file to t/lib/samples/SchemaIterator/resume-from-ignored-sakila-payment-5.0.txt.moved.
Conflict adding file t/lib/samples/SchemaIterator/resume-from-sakila-payment-5.0.txt.  Moved existing file to t/lib/samples/SchemaIterator/resume-from-sakila-payment-5.0.txt.moved.
Text conflict in t/pt-archiver/basics.t
Text conflict in t/pt-archiver/file.t
Conflict adding file t/pt-deadlock-logger/bugs.t.  Moved existing file to t/pt-deadlock-logger/bugs.t.moved.
Conflict adding file t/pt-deadlock-logger/samples.  Moved existing file to t/pt-deadlock-logger/samples.moved.
Text conflict in t/pt-duplicate-key-checker/basics.t
Text conflict in t/pt-duplicate-key-checker/samples/bug-894140.txt
Text conflict in t/pt-query-digest/read_timeout.t
Text conflict in t/pt-stalk/pt-stalk.t
Conflict adding file t/pt-table-checksum/bugs.t.  Moved existing file to t/pt-table-checksum/bugs.t.moved.
Text conflict in t/pt-table-checksum/chunk_index.t
Conflict adding file t/pt-table-checksum/samples/empty-table-bug-987393.sql.  Moved existing file to t/pt-table-checksum/samples/empty-table-bug-987393.sql.moved.
Conflict adding file t/pt-table-checksum/samples/not-using-pk-bug.out.  Moved existing file to t/pt-table-checksum/samples/not-using-pk-bug.out.moved.
Conflict adding file t/pt-table-checksum/samples/not-using-pk-bug.sql.  Moved existing file to t/pt-table-checksum/samples/not-using-pk-bug.sql.moved.
Conflict adding file t/pt-table-checksum/samples/undef-arrayref-bug-995274.sql.  Moved existing file to t/pt-table-checksum/samples/undef-arrayref-bug-995274.sql.moved.
Text conflict in t/pt-table-checksum/skip_innodb.t
Conflict adding file t/pt-table-sync/bugs.t.  Moved existing file to t/pt-table-sync/bugs.t.moved.
Text conflict in t/pt-table-sync/filters.t
Conflict adding file t/pt-table-sync/samples/wrong-tbl-struct-bug-1003014.sql.  Moved existing file to t/pt-table-sync/samples/wrong-tbl-struct-bug-1003014.sql.moved.
To merge this branch: bzr merge lp:~percona-toolkit-dev/percona-toolkit/fix-pt-heartbeat-dupe-key-bug-1004567
Reviewer Review Type Date Requested Status
Daniel Nichter Approve on 2012-07-20
Review via email: mp+116084@code.launchpad.net
To post a comment you must log in.
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2011-12-30 00:39:26 +0000
3+++ .bzrignore 2012-07-20 22:10:28 +0000
4@@ -4,5 +4,6 @@
5 docs/test-coverage/db
6 docs/test-coverage/html
7 release
8+snapshot
9 .DS_Store
10 build
11
12=== modified file 'Changelog'
13--- Changelog 2012-06-09 21:53:04 +0000
14+++ Changelog 2012-07-20 22:10:28 +0000
15@@ -1,5 +1,6 @@
16 Changelog for Percona Toolkit
17
18+<<<<<<< TREE
19 v2.0.5 released 2012-06-09
20
21 * Fixed bug 1002365: pt-table-sync --ignore-* options don't work with --replicate
22@@ -30,6 +31,96 @@
23 * Fixed bug 953461: pt-upgrade manual broken 'output' section
24 * Fixed bug 949653: pt-table-checksum docs don't mention risks posed by inconsistent schemas
25
26+=======
27+v2.1.2 released 2012-06-12
28+
29+ * pt-heartbeat: Implemented --recursion-method=none
30+ * pt-index-usage: MySQL 5.5 compatibility fixes
31+ * pt-log-player: MySQL 5.5 compatibility fixes
32+ * pt-online-schema-change: Added --chunk-index-columns
33+ * pt-online-schema-change: Added --[no]check-plan
34+ * pt-online-schema-change: Added --[no]drop-new-table
35+ * pt-online-schema-change: Implemented --recursion-method=none
36+ * pt-query-advisor: Added --report-type for JSON output
37+ * pt-query-digest: Removed --[no]zero-bool
38+ * pt-slave-delay: Added --database
39+ * pt-slave-find: Implemented --recursion-method=none
40+ * pt-slave-restart: Implemented --recursion-method=none
41+ * pt-table-checksum: Added --chunk-index-columns
42+ * pt-table-checksum: Added --[no]check-plan
43+ * pt-table-checksum: Implemented --recursion-method=none
44+ * pt-table-sync: Disabled --lock-and-rename except for MySQL 5.5 and newer
45+ * pt-table-sync: Implemented --recursion-method=none
46+ * Fixed bug 945079: Shell tools TMPDIR may break
47+ * Fixed bug 912902: Some shell tools still use basename
48+ * Fixed bug 987694: There is no --recursion-method=none option
49+ * Fixed bug 886077: Passwords with commas don't work, expose part of password
50+ * Fixed bug 856024: Lintian warnings when building percona-toolkit Debian package
51+ * Fixed bug 903379: pt-archiver --file doesn't create a file
52+ * Fixed bug 979092: pt-archiver --sleep conflicts with bulk operations
53+ * Fixed bug 903443: pt-deadlock-logger crashes on MySQL 5.5
54+ * Fixed bug 941064: pt-deadlock-logger can't clear deadlocks on 5.5
55+ * Fixed bug 952727: pt-diskstats shows incorrect wr_mb_s
56+ * Fixed bug 994176: pt-diskstats --group-by=all --headers=scroll prints a header for every sample
57+ * Fixed bug 894140: pt-duplicate-key-checker sometimes recreates a key it shouldn't
58+ * Fixed bug 923896: pt-kill: uninitialized value causes script to exit
59+ * Fixed bug 1003003: pt-online-schema-change uses different keys for chunking and triggers
60+ * Fixed bug 1003315: pt-online-schema-change --dry-run always fails on table with foreign keys
61+ * Fixed bug 1004551: pt-online-schema-change --no-swap-tables causes error
62+ * Fixed bug 976108: pt-online-schema-change doesn't allow to disable foreign key checks
63+ * Fixed bug 976109: pt-online-schema-change doesn't handle column renames
64+ * Fixed bug 988036: pt-online-schema-change causes deadlocks under heavy write load
65+ * Fixed bug 989227: pt-online-schema-change crashes with PTDEBUG
66+ * Fixed bug 994002: pt-online-schema-change 2.1.1 doesn't choose the PRIMARY KEY
67+ * Fixed bug 994010: pt-online-schema-change 2.1.1 crashes without InnoDB
68+ * Fixed bug 996915: pt-online-schema-change crashes with invalid --max-load and --critical-load
69+ * Fixed bug 998831: pt-online-schema-change -- Should have an option to NOT drop tables on failure
70+ * Fixed bug 1002448: pt-online-schema-change: typo for finding usable indexes
71+ * Fixed bug 885382: pt-query-digest --embedded-attributes doesn't check cardinality
72+ * Fixed bug 888114: pt-query-digest report crashes with infinite loop
73+ * Fixed bug 949630: pt-query-digest mentions a Subversion repository
74+ * Fixed bug 844034: pt-show-grants --separate fails with proxy user
75+ * Fixed bug 946707: pt-sift loses STDIN after pt-diskstats
76+ * Fixed bug 994947: pt-stalk doesn't reset cycles_true after collection
77+ * Fixed bug 986151: pt-stalk-has mktemp error
78+ * Fixed bug 993436: pt-summary Memory: Total reports M instead of G
79+ * Fixed bug 1008778: pt-table-checksum doesn't wait for checksum table to replicate
80+ * Fixed bug 1010232: pt-table-checksum doesn't check the size of checksum chunks
81+ * Fixed bug 1011738: pt-table-checksum SKIPPED is zero but chunks were skipped
82+ * Fixed bug 919499: pt-table-checksum fails with binary log error in mysql >= 5.5.18
83+ * Fixed bug 972399: pt-table-checksum docs are not rendered right
84+ * Fixed bug 978432: pt-table-checksum ignoring primary key
85+ * Fixed bug 995274: pt-table-checksum can't use an undefined value as an ARRAY reference at line 2206
86+ * Fixed bug 996110: pt-table-checksum crashes if InnoDB is disabled
87+ * Fixed bug 987393: pt-table-checksum: Empy tables cause "undefined value as an ARRAY" errors
88+ * Fixed bug 997155: pt-table-sync sets binlog_format needlessly
89+ * Fixed bug 1002365: pt-table-sync --ignore-* options don't work with --replicate
90+ * Fixed bug 1003014: pt-table-sync --replicate and --sync-to-master error "index does not exist"
91+ * Fixed bug 823403: pt-table-sync --lock-and-rename doesn't work on 5.1
92+ * Fixed bug 898138: pt-variable-advisor doesn't recognize 5.5.3+ concurrent_insert values
93+
94+v2.1.1 released 2012-04-03
95+
96+ * Completely redesigned pt-online-schema-change
97+ * Completely redesigned pt-mysql-summary
98+ * Completely redesigned pt-summary
99+ * Added new tool: pt-table-usage
100+ * Added new tool: pt-fingerprint
101+ * Fixed bug 955860: pt-stalk doesn't run vmstat, iostat, and mpstat for --run-time
102+ * Fixed bug 960513: SHOW TABLE STATUS is used needlessly
103+ * Fixed bug 969726: pt-online-schema-change loses foreign keys
104+ * Fixed bug 846028: pt-online-schema-change does not show progress until completed
105+ * Fixed bug 898695: pt-online-schema-change add useless ORDER BY
106+ * Fixed bug 952727: pt-diskstats shows incorrect wr_mb_s
107+ * Fixed bug 963225: pt-query-digest fails to set history columns for disk tmp tables and disk filesort
108+ * Fixed bug 967451: Char chunking doesn't quote column name
109+ * Fixed bug 972399: pt-table-checksum docs are not rendered right
110+ * Fixed bug 896553: Various documentation spelling fixes
111+ * Fixed bug 949154: pt-variable-advisor advice for relay-log-space-limit
112+ * Fixed bug 953461: pt-upgrade manual broken 'output' section
113+ * Fixed bug 949653: pt-table-checksum docs don't mention risks posed by inconsistent schemas
114+
115+>>>>>>> MERGE-SOURCE
116 v2.0.4 released 2012-03-07
117
118 * Added --filter to pt-kill to allow arbitrary --group-by
119
120=== modified file 'MANIFEST'
121--- MANIFEST 2012-02-03 23:25:29 +0000
122+++ MANIFEST 2012-07-20 22:10:28 +0000
123@@ -12,6 +12,7 @@
124 bin/pt-duplicate-key-checker
125 bin/pt-fifo-split
126 bin/pt-find
127+bin/pt-fingerprint
128 bin/pt-fk-error-logger
129 bin/pt-heartbeat
130 bin/pt-index-usage
131@@ -33,6 +34,7 @@
132 bin/pt-summary
133 bin/pt-table-checksum
134 bin/pt-table-sync
135+bin/pt-table-usage
136 bin/pt-tcp-model
137 bin/pt-trend
138 bin/pt-upgrade
139
140=== modified file 'Makefile.PL'
141--- Makefile.PL 2012-06-09 21:53:04 +0000
142+++ Makefile.PL 2012-07-20 22:10:28 +0000
143@@ -2,13 +2,17 @@
144
145 WriteMakefile(
146 NAME => 'percona-toolkit',
147+<<<<<<< TREE
148 VERSION => '2.0.5',
149+=======
150+ VERSION => '2.1.2',
151+>>>>>>> MERGE-SOURCE
152 EXE_FILES => [ <bin/*> ],
153 MAN1PODS => {
154- 'docs/percona-toolkit.pod' => 'blib/man1/percona-toolkit.1',
155+ 'docs/percona-toolkit.pod' => 'blib/man1/percona-toolkit.1p',
156 map {
157 (my $name = $_) =~ s/^bin.//;
158- $_ => "blib/man1/$name.1";
159+ $_ => "blib/man1/$name.1p";
160 } <bin/*>
161 },
162 MAN3PODS => {}, # man(3) pages are for C libs
163
164=== modified file 'bin/pt-align'
165--- bin/pt-align 2012-06-09 21:53:04 +0000
166+++ bin/pt-align 2012-07-20 22:10:28 +0000
167@@ -218,6 +218,10 @@
168
169 =head1 VERSION
170
171+<<<<<<< TREE
172 pt-align 2.0.5
173+=======
174+pt-align 2.1.2
175+>>>>>>> MERGE-SOURCE
176
177 =cut
178
179=== modified file 'bin/pt-archiver'
180--- bin/pt-archiver 2012-06-09 21:53:04 +0000
181+++ bin/pt-archiver 2012-07-20 22:10:28 +0000
182@@ -959,7 +959,7 @@
183 $opt->{value} = ($pre || '') . $num;
184 }
185 else {
186- $self->save_error("Invalid size for --$opt->{long}");
187+ $self->save_error("Invalid size for --$opt->{long}: $val");
188 }
189 return;
190 }
191@@ -1034,6 +1034,456 @@
192 # ###########################################################################
193
194 # ###########################################################################
195+# Mo package
196+# This package is a copy without comments from the original. The original
197+# with comments and its test file can be found in the Bazaar repository at,
198+# lib/Mo.pm
199+# t/lib/Mo.t
200+# See https://launchpad.net/percona-toolkit for more information.
201+# ###########################################################################
202+{
203+BEGIN {
204+$INC{"Mo.pm"} = __FILE__;
205+package Mo;
206+our $VERSION = '0.30_Percona'; # Forked from 0.30 of Mo.
207+
208+{
209+ no strict 'refs';
210+ sub _glob_for {
211+ return \*{shift()}
212+ }
213+
214+ sub _stash_for {
215+ return \%{ shift() . "::" };
216+ }
217+}
218+
219+use strict;
220+use warnings qw( FATAL all );
221+
222+use Carp ();
223+use Scalar::Util ();
224+
225+our %TYPES = (
226+ Bool => sub { !$_[0] || (defined $_[0] && &Scalar::Util::looks_like_number && $_[0] == 1) },
227+ Num => sub { defined $_[0] && &Scalar::Util::looks_like_number },
228+ Int => sub { defined $_[0] && &Scalar::Util::looks_like_number && $_[0] == int $_[0] },
229+ Str => sub { defined $_[0] },
230+ Object => sub { defined $_[0] && &Scalar::Util::blessed },
231+ FileHandle => sub { local $@; require IO::Handle; fileno($_[0]) && $_[0]->opened },
232+
233+ map {
234+ my $type = /R/ ? $_ : uc $_;
235+ $_ . "Ref" => sub { ref $_[0] eq $type }
236+ } qw(Array Code Hash Regexp Glob Scalar)
237+);
238+
239+our %metadata_for;
240+{
241+ package Mo::Object;
242+
243+ sub new {
244+ my $class = shift;
245+ my $args = $class->BUILDARGS(@_);
246+
247+ my @args_to_delete;
248+ while ( my ($attr, $meta) = each %{$metadata_for{$class}} ) {
249+ next unless exists $meta->{init_arg};
250+ my $init_arg = $meta->{init_arg};
251+
252+ if ( defined $init_arg ) {
253+ $args->{$attr} = delete $args->{$init_arg};
254+ }
255+ else {
256+ push @args_to_delete, $attr;
257+ }
258+ }
259+
260+ delete $args->{$_} for @args_to_delete;
261+
262+ for my $attribute ( keys %$args ) {
263+ if ( my $coerce = $metadata_for{$class}{$attribute}{coerce} ) {
264+ $args->{$attribute} = $coerce->($args->{$attribute});
265+ }
266+ if ( my $I = $metadata_for{$class}{$attribute}{isa} ) {
267+ ( (my $I_name), $I ) = @{$I};
268+ Mo::_check_type_constaints($attribute, $I, $I_name, $args->{$attribute});
269+ }
270+ }
271+
272+ while ( my ($attribute, $meta) = each %{$metadata_for{$class}} ) {
273+ next unless $meta->{required};
274+ Carp::confess("Attribute ($attribute) is required for $class")
275+ if ! exists $args->{$attribute}
276+ }
277+
278+ @_ = %$args;
279+ my $self = bless $args, $class;
280+
281+ my @build_subs;
282+ my $linearized_isa = mro::get_linear_isa($class);
283+
284+ for my $isa_class ( @$linearized_isa ) {
285+ unshift @build_subs, *{ Mo::_glob_for "${isa_class}::BUILD" }{CODE};
286+ }
287+ exists &$_ && $_->( $self, @_ ) for grep { defined } @build_subs;
288+ return $self;
289+ }
290+
291+ sub BUILDARGS {
292+ shift;
293+ my $ref;
294+ if ( @_ == 1 && ref($_[0]) ) {
295+ Carp::confess("Single parameters to new() must be a HASH ref")
296+ unless ref($_[0]) eq ref({});
297+ $ref = {%{$_[0]}} # We want a new reference, always
298+ }
299+ else {
300+ $ref = { @_ };
301+ }
302+ return $ref;
303+ }
304+}
305+
306+my %export_for;
307+sub Mo::import {
308+ warnings->import(qw(FATAL all));
309+ strict->import();
310+
311+ my $caller = scalar caller(); # Caller's package
312+ my $caller_pkg = $caller . "::"; # Caller's package with :: at the end
313+ my (%exports, %options);
314+
315+ my (undef, @features) = @_;
316+ my %ignore = ( map { $_ => 1 } qw( is isa init_arg builder buildargs clearer predicate build handles default required ) );
317+ for my $feature (grep { !$ignore{$_} } @features) {
318+ { local $@; require "Mo/$feature.pm"; }
319+ {
320+ no strict 'refs';
321+ &{"Mo::${feature}::e"}(
322+ $caller_pkg,
323+ \%exports,
324+ \%options,
325+ \@_
326+ );
327+ }
328+ }
329+
330+ return if $exports{M};
331+
332+ %exports = (
333+ extends => sub {
334+ for my $class ( map { "$_" } @_ ) {
335+ $class =~ s{::|'}{/}g;
336+ { local $@; eval { require "$class.pm" } } # or warn $@;
337+ }
338+ _set_package_isa($caller, @_);
339+ _set_inherited_metadata($caller);
340+ },
341+ has => sub {
342+ my $names = shift;
343+ for my $attribute ( ref $names ? @$names : $names ) {
344+ my %args = @_;
345+ my $method = ($args{is} || '') eq 'ro'
346+ ? sub {
347+ Carp::confess("Cannot assign a value to a read-only accessor at reader ${caller_pkg}${attribute}")
348+ if $#_;
349+ return $_[0]{$attribute};
350+ }
351+ : sub {
352+ return $#_
353+ ? $_[0]{$attribute} = $_[1]
354+ : $_[0]{$attribute};
355+ };
356+
357+ $metadata_for{$caller}{$attribute} = ();
358+
359+ if ( my $I = $args{isa} ) {
360+ my $orig_I = $I;
361+ my $type;
362+ if ( $I =~ /\A(ArrayRef|Maybe)\[(.*)\]\z/ ) {
363+ $I = _nested_constraints($attribute, $1, $2);
364+ }
365+ $metadata_for{$caller}{$attribute}{isa} = [$orig_I, $I];
366+ my $orig_method = $method;
367+ $method = sub {
368+ if ( $#_ ) {
369+ Mo::_check_type_constaints($attribute, $I, $orig_I, $_[1]);
370+ }
371+ goto &$orig_method;
372+ };
373+ }
374+
375+ if ( my $builder = $args{builder} ) {
376+ my $original_method = $method;
377+ $method = sub {
378+ $#_
379+ ? goto &$original_method
380+ : ! exists $_[0]{$attribute}
381+ ? $_[0]{$attribute} = $_[0]->$builder
382+ : goto &$original_method
383+ };
384+ }
385+
386+ if ( my $code = $args{default} ) {
387+ Carp::confess("${caller}::${attribute}'s default is $code, but should be a coderef")
388+ unless ref($code) eq 'CODE';
389+ my $original_method = $method;
390+ $method = sub {
391+ $#_
392+ ? goto &$original_method
393+ : ! exists $_[0]{$attribute}
394+ ? $_[0]{$attribute} = $_[0]->$code
395+ : goto &$original_method
396+ };
397+ }
398+
399+ if ( my $role = $args{does} ) {
400+ my $original_method = $method;
401+ $method = sub {
402+ if ( $#_ ) {
403+ Carp::confess(qq<Attribute ($attribute) doesn't consume a '$role' role">)
404+ unless blessed($_[1]) && $_[1]->does($role)
405+ }
406+ goto &$original_method
407+ };
408+ }
409+
410+ if ( my $coercion = $args{coerce} ) {
411+ $metadata_for{$caller}{$attribute}{coerce} = $coercion;
412+ my $original_method = $method;
413+ $method = sub {
414+ if ( $#_ ) {
415+ return $original_method->($_[0], $coercion->($_[1]))
416+ }
417+ goto &$original_method;
418+ }
419+ }
420+
421+ $method = $options{$_}->($method, $attribute, @_)
422+ for sort keys %options;
423+
424+ *{ _glob_for "${caller}::$attribute" } = $method;
425+
426+ if ( $args{required} ) {
427+ $metadata_for{$caller}{$attribute}{required} = 1;
428+ }
429+
430+ if ($args{clearer}) {
431+ *{ _glob_for "${caller}::$args{clearer}" }
432+ = sub { delete shift->{$attribute} }
433+ }
434+
435+ if ($args{predicate}) {
436+ *{ _glob_for "${caller}::$args{predicate}" }
437+ = sub { exists shift->{$attribute} }
438+ }
439+
440+ if ($args{handles}) {
441+ _has_handles($caller, $attribute, \%args);
442+ }
443+
444+ if (exists $args{init_arg}) {
445+ $metadata_for{$caller}{$attribute}{init_arg} = $args{init_arg};
446+ }
447+ }
448+ },
449+ %exports,
450+ );
451+
452+ $export_for{$caller} = [ keys %exports ];
453+
454+ for my $keyword ( keys %exports ) {
455+ *{ _glob_for "${caller}::$keyword" } = $exports{$keyword}
456+ }
457+ *{ _glob_for "${caller}::extends" }{CODE}->( "Mo::Object" )
458+ unless @{ *{ _glob_for "${caller}::ISA" }{ARRAY} || [] };
459+};
460+
461+sub _check_type_constaints {
462+ my ($attribute, $I, $I_name, $val) = @_;
463+ ( ref($I) eq 'CODE'
464+ ? $I->($val)
465+ : (ref $val eq $I
466+ || ($val && $val eq $I)
467+ || (exists $TYPES{$I} && $TYPES{$I}->($val)))
468+ )
469+ || Carp::confess(
470+ qq<Attribute ($attribute) does not pass the type constraint because: >
471+ . qq<Validation failed for '$I_name' with value >
472+ . (defined $val ? Mo::Dumper($val) : 'undef') )
473+}
474+
475+sub _has_handles {
476+ my ($caller, $attribute, $args) = @_;
477+ my $handles = $args->{handles};
478+
479+ my $ref = ref $handles;
480+ my $kv;
481+ if ( $ref eq ref [] ) {
482+ $kv = { map { $_,$_ } @{$handles} };
483+ }
484+ elsif ( $ref eq ref {} ) {
485+ $kv = $handles;
486+ }
487+ elsif ( $ref eq ref qr// ) {
488+ Carp::confess("Cannot delegate methods based on a Regexp without a type constraint (isa)")
489+ unless $args->{isa};
490+ my $target_class = $args->{isa};
491+ $kv = {
492+ map { $_, $_ }
493+ grep { $_ =~ $handles }
494+ grep { !exists $Mo::Object::{$_} && $target_class->can($_) }
495+ grep { $_ ne 'has' && $_ ne 'extends' }
496+ keys %{ _stash_for $target_class }
497+ };
498+ }
499+ else {
500+ Carp::confess("handles for $ref not yet implemented");
501+ }
502+
503+ while ( my ($method, $target) = each %{$kv} ) {
504+ my $name = _glob_for "${caller}::$method";
505+ Carp::confess("You cannot overwrite a locally defined method ($method) with a delegation")
506+ if defined &$name;
507+
508+ my ($target, @curried_args) = ref($target) ? @$target : $target;
509+ *$name = sub {
510+ my $self = shift;
511+ my $delegate_to = $self->$attribute();
512+ my $error = "Cannot delegate $method to $target because the value of $attribute";
513+ Carp::confess("$error is not defined") unless $delegate_to;
514+ Carp::confess("$error is not an object (got '$delegate_to')")
515+ unless Scalar::Util::blessed($delegate_to) || (!ref($delegate_to) && $delegate_to->can($target));
516+ return $delegate_to->$target(@curried_args, @_);
517+ }
518+ }
519+}
520+
521+sub _nested_constraints {
522+ my ($attribute, $aggregate_type, $type) = @_;
523+
524+ my $inner_types;
525+ if ( $type =~ /\A(ArrayRef|Maybe)\[(.*)\]\z/ ) {
526+ $inner_types = _nested_constraints($1, $2);
527+ }
528+ else {
529+ $inner_types = $TYPES{$type};
530+ }
531+
532+ if ( $aggregate_type eq 'ArrayRef' ) {
533+ return sub {
534+ my ($val) = @_;
535+ return unless ref($val) eq ref([]);
536+
537+ if ($inner_types) {
538+ for my $value ( @{$val} ) {
539+ return unless $inner_types->($value)
540+ }
541+ }
542+ else {
543+ for my $value ( @{$val} ) {
544+ return unless $value && ($value eq $type
545+ || (Scalar::Util::blessed($value) && $value->isa($type)));
546+ }
547+ }
548+ return 1;
549+ };
550+ }
551+ elsif ( $aggregate_type eq 'Maybe' ) {
552+ return sub {
553+ my ($value) = @_;
554+ return 1 if ! defined($value);
555+ if ($inner_types) {
556+ return unless $inner_types->($value)
557+ }
558+ else {
559+ return unless $value eq $type
560+ || (Scalar::Util::blessed($value) && $value->isa($type));
561+ }
562+ return 1;
563+ }
564+ }
565+ else {
566+ Carp::confess("Nested aggregate types are only implemented for ArrayRefs and Maybe");
567+ }
568+}
569+
570+sub _set_package_isa {
571+ my ($package, @new_isa) = @_;
572+
573+ *{ _glob_for "${package}::ISA" } = [@new_isa];
574+}
575+
576+sub _set_inherited_metadata {
577+ my $class = shift;
578+ my $linearized_isa = mro::get_linear_isa($class);
579+ my %new_metadata;
580+
581+ for my $isa_class (reverse @$linearized_isa) {
582+ %new_metadata = (
583+ %new_metadata,
584+ %{ $metadata_for{$isa_class} || {} },
585+ );
586+ }
587+ $metadata_for{$class} = \%new_metadata;
588+}
589+
590+sub unimport {
591+ my $caller = scalar caller();
592+ my $stash = _stash_for( $caller );
593+
594+ delete $stash->{$_} for @{$export_for{$caller}};
595+}
596+
597+sub Dumper {
598+ require Data::Dumper;
599+ local $Data::Dumper::Indent = 0;
600+ local $Data::Dumper::Sortkeys = 0;
601+ local $Data::Dumper::Quotekeys = 0;
602+ local $Data::Dumper::Terse = 1;
603+
604+ Data::Dumper::Dumper(@_)
605+}
606+
607+BEGIN {
608+ if ($] >= 5.010) {
609+ { local $@; require mro; }
610+ }
611+ else {
612+ local $@;
613+ eval {
614+ require MRO::Compat;
615+ } or do {
616+ *mro::get_linear_isa = *mro::get_linear_isa_dfs = sub {
617+ no strict 'refs';
618+
619+ my $classname = shift;
620+
621+ my @lin = ($classname);
622+ my %stored;
623+ foreach my $parent (@{"$classname\::ISA"}) {
624+ my $plin = mro::get_linear_isa_dfs($parent);
625+ foreach (@$plin) {
626+ next if exists $stored{$_};
627+ push(@lin, $_);
628+ $stored{$_} = 1;
629+ }
630+ }
631+ return \@lin;
632+ };
633+ }
634+ }
635+}
636+
637+}
638+1;
639+}
640+# ###########################################################################
641+# End Mo package
642+# ###########################################################################
643+
644+# ###########################################################################
645 # TableParser package
646 # This package is a copy without comments from the original. The original
647 # with comments and its test file can be found in the Bazaar repository at,
648@@ -1064,23 +1514,64 @@
649 return bless $self, $class;
650 }
651
652+sub get_create_table {
653+ my ( $self, $dbh, $db, $tbl ) = @_;
654+ die "I need a dbh parameter" unless $dbh;
655+ die "I need a db parameter" unless $db;
656+ die "I need a tbl parameter" unless $tbl;
657+ my $q = $self->{Quoter};
658+
659+ my $new_sql_mode
660+ = '/*!40101 SET @OLD_SQL_MODE := @@SQL_MODE, '
661+ . q{@@SQL_MODE := REPLACE(REPLACE(@@SQL_MODE, 'ANSI_QUOTES', ''), ',,', ','), }
662+ . '@OLD_QUOTE := @@SQL_QUOTE_SHOW_CREATE, '
663+ . '@@SQL_QUOTE_SHOW_CREATE := 1 */';
664+
665+ my $old_sql_mode = '/*!40101 SET @@SQL_MODE := @OLD_SQL_MODE, '
666+ . '@@SQL_QUOTE_SHOW_CREATE := @OLD_QUOTE */';
667+
668+ PTDEBUG && _d($new_sql_mode);
669+ eval { $dbh->do($new_sql_mode); };
670+ PTDEBUG && $EVAL_ERROR && _d($EVAL_ERROR);
671+
672+ my $use_sql = 'USE ' . $q->quote($db);
673+ PTDEBUG && _d($dbh, $use_sql);
674+ $dbh->do($use_sql);
675+
676+ my $show_sql = "SHOW CREATE TABLE " . $q->quote($db, $tbl);
677+ PTDEBUG && _d($show_sql);
678+ my $href;
679+ eval { $href = $dbh->selectrow_hashref($show_sql); };
680+ if ( $EVAL_ERROR ) {
681+ PTDEBUG && _d($EVAL_ERROR);
682+
683+ PTDEBUG && _d($old_sql_mode);
684+ $dbh->do($old_sql_mode);
685+
686+ return;
687+ }
688+
689+ PTDEBUG && _d($old_sql_mode);
690+ $dbh->do($old_sql_mode);
691+
692+ my ($key) = grep { m/create (?:table|view)/i } keys %$href;
693+ if ( !$key ) {
694+ die "Error: no 'Create Table' or 'Create View' in result set from "
695+ . "$show_sql: " . Dumper($href);
696+ }
697+
698+ return $href->{$key};
699+}
700+
701 sub parse {
702 my ( $self, $ddl, $opts ) = @_;
703 return unless $ddl;
704- if ( ref $ddl eq 'ARRAY' ) {
705- if ( lc $ddl->[0] eq 'table' ) {
706- $ddl = $ddl->[1];
707- }
708- else {
709- return {
710- engine => 'VIEW',
711- };
712- }
713+
714+ if ( $ddl =~ m/CREATE (?:TEMPORARY )?TABLE "/ ) {
715+ $ddl = $self->ansi_to_legacy($ddl);
716 }
717-
718- if ( $ddl !~ m/CREATE (?:TEMPORARY )?TABLE `/ ) {
719- die "Cannot parse table definition; is ANSI quoting "
720- . "enabled or SQL_QUOTE_SHOW_CREATE disabled?";
721+ elsif ( $ddl !~ m/CREATE (?:TEMPORARY )?TABLE `/ ) {
722+ die "TableParser doesn't handle CREATE TABLE without quoting.";
723 }
724
725 my ($name) = $ddl =~ m/CREATE (?:TEMPORARY )?TABLE\s+(`.+?`)/;
726@@ -1289,19 +1780,13 @@
727 my $key_ddl = $key;
728 PTDEBUG && _d('Parsed key:', $key_ddl);
729
730- if ( $engine !~ m/MEMORY|HEAP/ ) {
731+ if ( !$engine || $engine !~ m/MEMORY|HEAP/ ) {
732 $key =~ s/USING HASH/USING BTREE/;
733 }
734
735 my ( $type, $cols ) = $key =~ m/(?:USING (\w+))? \((.+)\)/;
736 my ( $special ) = $key =~ m/(FULLTEXT|SPATIAL)/;
737 $type = $type || $special || 'BTREE';
738- if ( $opts->{mysql_version} && $opts->{mysql_version} lt '004001000'
739- && $engine =~ m/HEAP|MEMORY/i )
740- {
741- $type = 'HASH'; # MySQL pre-4.1 supports only HASH indexes on HEAP
742- }
743-
744 my ($name) = $key =~ m/(PRIMARY|`[^`]*`)/;
745 my $unique = $key =~ m/PRIMARY|UNIQUE/ ? 1 : 0;
746 my @cols;
747@@ -1327,7 +1812,7 @@
748 ddl => $key_ddl,
749 };
750
751- if ( $engine =~ m/InnoDB/i && !$clustered_key ) {
752+ if ( ($engine || '') =~ m/InnoDB/i && !$clustered_key ) {
753 my $this_key = $keys->{$name};
754 if ( $this_key->{name} eq 'PRIMARY' ) {
755 $clustered_key = 'PRIMARY';
756@@ -1383,41 +1868,46 @@
757 return $ddl;
758 }
759
760-sub remove_secondary_indexes {
761- my ( $self, $ddl ) = @_;
762- my $sec_indexes_ddl;
763- my $tbl_struct = $self->parse($ddl);
764-
765- if ( ($tbl_struct->{engine} || '') =~ m/InnoDB/i ) {
766- my $clustered_key = $tbl_struct->{clustered_key};
767- $clustered_key ||= '';
768-
769- my @sec_indexes = map {
770- my $key_def = $_->{ddl};
771- $key_def =~ s/([\(\)])/\\$1/g;
772- $ddl =~ s/\s+$key_def//i;
773-
774- my $key_ddl = "ADD $_->{ddl}";
775- $key_ddl .= ',' unless $key_ddl =~ m/,$/;
776- $key_ddl;
777- }
778- grep { $_->{name} ne $clustered_key }
779- values %{$tbl_struct->{keys}};
780- PTDEBUG && _d('Secondary indexes:', Dumper(\@sec_indexes));
781-
782- if ( @sec_indexes ) {
783- $sec_indexes_ddl = join(' ', @sec_indexes);
784- $sec_indexes_ddl =~ s/,$//;
785- }
786-
787- $ddl =~ s/,(\n\) )/$1/s;
788- }
789- else {
790- PTDEBUG && _d('Not removing secondary indexes from',
791- $tbl_struct->{engine}, 'table');
792- }
793-
794- return $ddl, $sec_indexes_ddl, $tbl_struct;
795+sub get_table_status {
796+ my ( $self, $dbh, $db, $like ) = @_;
797+ my $q = $self->{Quoter};
798+ my $sql = "SHOW TABLE STATUS FROM " . $q->quote($db);
799+ my @params;
800+ if ( $like ) {
801+ $sql .= ' LIKE ?';
802+ push @params, $like;
803+ }
804+ PTDEBUG && _d($sql, @params);
805+ my $sth = $dbh->prepare($sql);
806+ eval { $sth->execute(@params); };
807+ if ($EVAL_ERROR) {
808+ PTDEBUG && _d($EVAL_ERROR);
809+ return;
810+ }
811+ my @tables = @{$sth->fetchall_arrayref({})};
812+ @tables = map {
813+ my %tbl; # Make a copy with lowercased keys
814+ @tbl{ map { lc $_ } keys %$_ } = values %$_;
815+ $tbl{engine} ||= $tbl{type} || $tbl{comment};
816+ delete $tbl{type};
817+ \%tbl;
818+ } @tables;
819+ return @tables;
820+}
821+
822+my $ansi_quote_re = qr/" [^"]* (?: "" [^"]* )* (?<=.) "/ismx;
823+sub ansi_to_legacy {
824+ my ($self, $ddl) = @_;
825+ $ddl =~ s/($ansi_quote_re)/ansi_quote_replace($1)/ge;
826+ return $ddl;
827+}
828+
829+sub ansi_quote_replace {
830+ my ($val) = @_;
831+ $val =~ s/^"|"$//g;
832+ $val =~ s/`/``/g;
833+ $val =~ s/""/"/g;
834+ return "`$val`";
835 }
836
837 sub _d {
838@@ -1663,51 +2153,10 @@
839 PTDEBUG && _d($cxn_string, ' ', $user, ' ', $pass,
840 join(', ', map { "$_=>$defaults->{$_}" } keys %$defaults ));
841
842- eval {
843- $dbh = DBI->connect($cxn_string, $user, $pass, $defaults);
844-
845- if ( $cxn_string =~ m/mysql/i ) {
846- my $sql;
847-
848- $sql = 'SELECT @@SQL_MODE';
849- PTDEBUG && _d($dbh, $sql);
850- my ($sql_mode) = $dbh->selectrow_array($sql);
851-
852- $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1'
853- . '/*!40101, @@SQL_MODE=\'NO_AUTO_VALUE_ON_ZERO'
854- . ($sql_mode ? ",$sql_mode" : '')
855- . '\'*/';
856- PTDEBUG && _d($dbh, $sql);
857- $dbh->do($sql);
858-
859- if ( my ($charset) = $cxn_string =~ m/charset=(\w+)/ ) {
860- $sql = "/*!40101 SET NAMES $charset*/";
861- PTDEBUG && _d($dbh, ':', $sql);
862- $dbh->do($sql);
863- PTDEBUG && _d('Enabling charset for STDOUT');
864- if ( $charset eq 'utf8' ) {
865- binmode(STDOUT, ':utf8')
866- or die "Can't binmode(STDOUT, ':utf8'): $OS_ERROR";
867- }
868- else {
869- binmode(STDOUT) or die "Can't binmode(STDOUT): $OS_ERROR";
870- }
871- }
872-
873- if ( $self->prop('set-vars') ) {
874- $sql = "SET " . $self->prop('set-vars');
875- PTDEBUG && _d($dbh, ':', $sql);
876- $dbh->do($sql);
877- }
878- }
879- };
880+ $dbh = eval { DBI->connect($cxn_string, $user, $pass, $defaults) };
881+
882 if ( !$dbh && $EVAL_ERROR ) {
883- PTDEBUG && _d($EVAL_ERROR);
884- if ( $EVAL_ERROR =~ m/not a compiled character set|character set utf8/ ) {
885- PTDEBUG && _d('Going to try again without utf8 support');
886- delete $defaults->{mysql_enable_utf8};
887- }
888- elsif ( $EVAL_ERROR =~ m/locate DBD\/mysql/i ) {
889+ if ( $EVAL_ERROR =~ m/locate DBD\/mysql/i ) {
890 die "Cannot connect to MySQL because the Perl DBD::mysql module is "
891 . "not installed or not found. Run 'perl -MDBD::mysql' to see "
892 . "the directories that Perl searches for DBD::mysql. If "
893@@ -1716,19 +2165,70 @@
894 . " RHEL/CentOS yum install perl-DBD-MySQL\n"
895 . " OpenSolaris pgk install pkg:/SUNWapu13dbd-mysql\n";
896 }
897+ elsif ( $EVAL_ERROR =~ m/not a compiled character set|character set utf8/ ) {
898+ PTDEBUG && _d('Going to try again without utf8 support');
899+ delete $defaults->{mysql_enable_utf8};
900+ }
901 if ( !$tries ) {
902 die $EVAL_ERROR;
903 }
904 }
905 }
906
907+ if ( $cxn_string =~ m/mysql/i ) {
908+ my $sql;
909+
910+ $sql = 'SELECT @@SQL_MODE';
911+ PTDEBUG && _d($dbh, $sql);
912+ my ($sql_mode) = eval { $dbh->selectrow_array($sql) };
913+ if ( $EVAL_ERROR ) {
914+ die $EVAL_ERROR;
915+ }
916+
917+ $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1'
918+ . '/*!40101, @@SQL_MODE=\'NO_AUTO_VALUE_ON_ZERO'
919+ . ($sql_mode ? ",$sql_mode" : '')
920+ . '\'*/';
921+ PTDEBUG && _d($dbh, $sql);
922+ eval { $dbh->do($sql) };
923+ if ( $EVAL_ERROR ) {
924+ die $EVAL_ERROR;
925+ }
926+
927+ if ( my ($charset) = $cxn_string =~ m/charset=(\w+)/ ) {
928+ $sql = "/*!40101 SET NAMES $charset*/";
929+ PTDEBUG && _d($dbh, ':', $sql);
930+ eval { $dbh->do($sql) };
931+ if ( $EVAL_ERROR ) {
932+ die $EVAL_ERROR;
933+ }
934+ PTDEBUG && _d('Enabling charset for STDOUT');
935+ if ( $charset eq 'utf8' ) {
936+ binmode(STDOUT, ':utf8')
937+ or die "Can't binmode(STDOUT, ':utf8'): $OS_ERROR";
938+ }
939+ else {
940+ binmode(STDOUT) or die "Can't binmode(STDOUT): $OS_ERROR";
941+ }
942+ }
943+
944+ if ( $self->prop('set-vars') ) {
945+ $sql = "SET " . $self->prop('set-vars');
946+ PTDEBUG && _d($dbh, ':', $sql);
947+ eval { $dbh->do($sql) };
948+ if ( $EVAL_ERROR ) {
949+ die $EVAL_ERROR;
950+ }
951+ }
952+ }
953+
954 PTDEBUG && _d('DBH info: ',
955 $dbh,
956 Dumper($dbh->selectrow_hashref(
957 'SELECT DATABASE(), CONNECTION_ID(), VERSION()/*!50038 , @@hostname*/')),
958 'Connection info:', $dbh->{mysql_hostinfo},
959 'Character set info:', Dumper($dbh->selectall_arrayref(
960- 'SHOW VARIABLES LIKE "character_set%"', { Slice => {}})),
961+ "SHOW VARIABLES LIKE 'character_set%'", { Slice => {}})),
962 '$DBD::mysql::VERSION:', $DBD::mysql::VERSION,
963 '$DBI::VERSION:', $DBI::VERSION,
964 );
965@@ -1806,35 +2306,145 @@
966 {
967 package VersionParser;
968
969-use strict;
970-use warnings FATAL => 'all';
971+use Mo;
972+use Scalar::Util qw(blessed);
973 use English qw(-no_match_vars);
974 use constant PTDEBUG => $ENV{PTDEBUG} || 0;
975
976-sub new {
977- my ( $class ) = @_;
978- bless {}, $class;
979-}
980-
981-sub parse {
982- my ( $self, $str ) = @_;
983- my $result = sprintf('%03d%03d%03d', $str =~ m/(\d+)/g);
984- PTDEBUG && _d($str, 'parses to', $result);
985- return $result;
986-}
987-
988-sub version_ge {
989- my ( $self, $dbh, $target ) = @_;
990- if ( !$self->{$dbh} ) {
991- $self->{$dbh} = $self->parse(
992- $dbh->selectrow_array('SELECT VERSION()'));
993- }
994- my $result = $self->{$dbh} ge $self->parse($target) ? 1 : 0;
995- PTDEBUG && _d($self->{$dbh}, 'ge', $target, ':', $result);
996- return $result;
997-}
998-
999-sub innodb_version {
1000+use overload (
1001+ '""' => "version",
1002+ '<=>' => "cmp",
1003+ 'cmp' => "cmp",
1004+ fallback => 1,
1005+);
1006+
1007+use Carp ();
1008+
1009+our $VERSION = 0.01;
1010+
1011+has major => (
1012+ is => 'ro',
1013+ isa => 'Int',
1014+ required => 1,
1015+);
1016+
1017+has [qw( minor revision )] => (
1018+ is => 'ro',
1019+ isa => 'Num',
1020+);
1021+
1022+has flavor => (
1023+ is => 'ro',
1024+ isa => 'Str',
1025+ default => sub { 'Unknown' },
1026+);
1027+
1028+has innodb_version => (
1029+ is => 'ro',
1030+ isa => 'Str',
1031+ default => sub { 'NO' },
1032+);
1033+
1034+sub series {
1035+ my $self = shift;
1036+ return $self->_join_version($self->major, $self->minor);
1037+}
1038+
1039+sub version {
1040+ my $self = shift;
1041+ return $self->_join_version($self->major, $self->minor, $self->revision);
1042+}
1043+
1044+sub is_in {
1045+ my ($self, $target) = @_;
1046+
1047+ return $self eq $target;
1048+}
1049+
1050+sub _join_version {
1051+ my ($self, @parts) = @_;
1052+
1053+ return join ".", map { my $c = $_; $c =~ s/^0\./0/; $c } grep defined, @parts;
1054+}
1055+sub _split_version {
1056+ my ($self, $str) = @_;
1057+ my @version_parts = map { s/^0(?=\d)/0./; $_ } $str =~ m/(\d+)/g;
1058+ return @version_parts[0..2];
1059+}
1060+
1061+sub normalized_version {
1062+ my ( $self ) = @_;
1063+ my $result = sprintf('%d%02d%02d', map { $_ || 0 } $self->major,
1064+ $self->minor,
1065+ $self->revision);
1066+ PTDEBUG && _d($self->version, 'normalizes to', $result);
1067+ return $result;
1068+}
1069+
1070+sub comment {
1071+ my ( $self, $cmd ) = @_;
1072+ my $v = $self->normalized_version();
1073+
1074+ return "/*!$v $cmd */"
1075+}
1076+
1077+my @methods = qw(major minor revision);
1078+sub cmp {
1079+ my ($left, $right) = @_;
1080+ my $right_obj = (blessed($right) && $right->isa(ref($left)))
1081+ ? $right
1082+ : ref($left)->new($right);
1083+
1084+ my $retval = 0;
1085+ for my $m ( @methods ) {
1086+ last unless defined($left->$m) && defined($right_obj->$m);
1087+ $retval = $left->$m <=> $right_obj->$m;
1088+ last if $retval;
1089+ }
1090+ return $retval;
1091+}
1092+
1093+sub BUILDARGS {
1094+ my $self = shift;
1095+
1096+ if ( @_ == 1 ) {
1097+ my %args;
1098+ if ( blessed($_[0]) && $_[0]->can("selectrow_hashref") ) {
1099+ PTDEBUG && _d("VersionParser got a dbh, trying to get the version");
1100+ my $dbh = $_[0];
1101+ local $dbh->{FetchHashKeyName} = 'NAME_lc';
1102+ my $query = eval {
1103+ $dbh->selectall_arrayref(q/SHOW VARIABLES LIKE 'version%'/, { Slice => {} })
1104+ };
1105+ if ( $query ) {
1106+ $query = { map { $_->{variable_name} => $_->{value} } @$query };
1107+ @args{@methods} = $self->_split_version($query->{version});
1108+ $args{flavor} = delete $query->{version_comment}
1109+ if $query->{version_comment};
1110+ }
1111+ elsif ( eval { ($query) = $dbh->selectrow_array(q/SELECT VERSION()/) } ) {
1112+ @args{@methods} = $self->_split_version($query);
1113+ }
1114+ else {
1115+ Carp::confess("Couldn't get the version from the dbh while "
1116+ . "creating a VersionParser object: $@");
1117+ }
1118+ $args{innodb_version} = eval { $self->_innodb_version($dbh) };
1119+ }
1120+ elsif ( !ref($_[0]) ) {
1121+ @args{@methods} = $self->_split_version($_[0]);
1122+ }
1123+
1124+ for my $method (@methods) {
1125+ delete $args{$method} unless defined $args{$method};
1126+ }
1127+ @_ = %args if %args;
1128+ }
1129+
1130+ return $self->SUPER::BUILDARGS(@_);
1131+}
1132+
1133+sub _innodb_version {
1134 my ( $self, $dbh ) = @_;
1135 return unless $dbh;
1136 my $innodb_version = "NO";
1137@@ -1872,6 +2482,7 @@
1138 print STDERR "# $package:$line $PID ", join(' ', @_), "\n";
1139 }
1140
1141+no Mo;
1142 1;
1143 }
1144 # ###########################################################################
1145@@ -1949,6 +2560,48 @@
1146 return $db ? "$db.$tbl" : $tbl;
1147 }
1148
1149+sub serialize_list {
1150+ my ( $self, @args ) = @_;
1151+ return unless @args;
1152+
1153+ return $args[0] if @args == 1 && !defined $args[0];
1154+
1155+ die "Cannot serialize multiple values with undef/NULL"
1156+ if grep { !defined $_ } @args;
1157+
1158+ return join ',', map { quotemeta } @args;
1159+}
1160+
1161+sub deserialize_list {
1162+ my ( $self, $string ) = @_;
1163+ return $string unless defined $string;
1164+ my @escaped_parts = $string =~ /
1165+ \G # Start of string, or end of previous match.
1166+ ( # Each of these is an element in the original list.
1167+ [^\\,]* # Anything not a backslash or a comma
1168+ (?: # When we get here, we found one of the above.
1169+ \\. # A backslash followed by something so we can continue
1170+ [^\\,]* # Same as above.
1171+ )* # Repeat zero of more times.
1172+ )
1173+ , # Comma dividing elements
1174+ /sxgc;
1175+
1176+ push @escaped_parts, pos($string) ? substr( $string, pos($string) ) : $string;
1177+
1178+ my @unescaped_parts = map {
1179+ my $part = $_;
1180+
1181+ my $char_class = utf8::is_utf8($part) # If it's a UTF-8 string,
1182+ ? qr/(?=\p{ASCII})\W/ # We only care about non-word
1183+ : qr/(?=\p{ASCII})\W|[\x{80}-\x{FF}]/; # Otherwise,
1184+ $part =~ s/\\($char_class)/$1/g;
1185+ $part;
1186+ } @escaped_parts;
1187+
1188+ return @unescaped_parts;
1189+}
1190+
1191 1;
1192 }
1193 # ###########################################################################
1194@@ -1988,23 +2641,26 @@
1195 die "I need a $arg argument" unless defined $args{$arg};
1196 }
1197 my ($tbl_struct, $index) = @args{@required_args};
1198- my @cols = $args{cols} ? @{$args{cols}} : @{$tbl_struct->{cols}};
1199+ my @cols = $args{cols} ? @{$args{cols}} : @{$tbl_struct->{cols}};
1200 my $q = $self->{Quoter};
1201
1202 die "Index '$index' does not exist in table"
1203 unless exists $tbl_struct->{keys}->{$index};
1204+ PTDEBUG && _d('Will ascend index', $index);
1205
1206 my @asc_cols = @{$tbl_struct->{keys}->{$index}->{cols}};
1207- my @asc_slice;
1208-
1209- @asc_cols = @{$tbl_struct->{keys}->{$index}->{cols}};
1210- PTDEBUG && _d('Will ascend index', $index);
1211- PTDEBUG && _d('Will ascend columns', join(', ', @asc_cols));
1212 if ( $args{asc_first} ) {
1213+ PTDEBUG && _d('Ascending only first column');
1214 @asc_cols = $asc_cols[0];
1215- PTDEBUG && _d('Ascending only first column');
1216- }
1217+ }
1218+ elsif ( my $n = $args{n_index_cols} ) {
1219+ $n = scalar @asc_cols if $n > @asc_cols;
1220+ PTDEBUG && _d('Ascending only first', $n, 'columns');
1221+ @asc_cols = @asc_cols[0..($n-1)];
1222+ }
1223+ PTDEBUG && _d('Will ascend columns', join(', ', @asc_cols));
1224
1225+ my @asc_slice;
1226 my %col_posn = do { my $i = 0; map { $_ => $i++ } @cols };
1227 foreach my $col ( @asc_cols ) {
1228 if ( !exists $col_posn{$col} ) {
1229@@ -2215,311 +2871,6 @@
1230 # ###########################################################################
1231
1232 # ###########################################################################
1233-# MySQLDump package
1234-# This package is a copy without comments from the original. The original
1235-# with comments and its test file can be found in the Bazaar repository at,
1236-# lib/MySQLDump.pm
1237-# t/lib/MySQLDump.t
1238-# See https://launchpad.net/percona-toolkit for more information.
1239-# ###########################################################################
1240-{
1241-package MySQLDump;
1242-
1243-use strict;
1244-use warnings FATAL => 'all';
1245-use English qw(-no_match_vars);
1246-use constant PTDEBUG => $ENV{PTDEBUG} || 0;
1247-
1248-( our $before = <<'EOF') =~ s/^ //gm;
1249- /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
1250- /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
1251- /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
1252- /*!40101 SET NAMES utf8 */;
1253- /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
1254- /*!40103 SET TIME_ZONE='+00:00' */;
1255- /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
1256- /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
1257- /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
1258- /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
1259-EOF
1260-
1261-( our $after = <<'EOF') =~ s/^ //gm;
1262- /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
1263- /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
1264- /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
1265- /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
1266- /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
1267- /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
1268- /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
1269- /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
1270-EOF
1271-
1272-sub new {
1273- my ( $class, %args ) = @_;
1274- my $self = {
1275- cache => 0, # Afaik no script uses this cache any longer because
1276- };
1277- return bless $self, $class;
1278-}
1279-
1280-sub dump {
1281- my ( $self, $dbh, $quoter, $db, $tbl, $what ) = @_;
1282-
1283- if ( $what eq 'table' ) {
1284- my $ddl = $self->get_create_table($dbh, $quoter, $db, $tbl);
1285- return unless $ddl;
1286- if ( $ddl->[0] eq 'table' ) {
1287- return $before
1288- . 'DROP TABLE IF EXISTS ' . $quoter->quote($tbl) . ";\n"
1289- . $ddl->[1] . ";\n";
1290- }
1291- else {
1292- return 'DROP TABLE IF EXISTS ' . $quoter->quote($tbl) . ";\n"
1293- . '/*!50001 DROP VIEW IF EXISTS '
1294- . $quoter->quote($tbl) . "*/;\n/*!50001 "
1295- . $self->get_tmp_table($dbh, $quoter, $db, $tbl) . "*/;\n";
1296- }
1297- }
1298- elsif ( $what eq 'triggers' ) {
1299- my $trgs = $self->get_triggers($dbh, $quoter, $db, $tbl);
1300- if ( $trgs && @$trgs ) {
1301- my $result = $before . "\nDELIMITER ;;\n";
1302- foreach my $trg ( @$trgs ) {
1303- if ( $trg->{sql_mode} ) {
1304- $result .= qq{/*!50003 SET SESSION SQL_MODE='$trg->{sql_mode}' */;;\n};
1305- }
1306- $result .= "/*!50003 CREATE */ ";
1307- if ( $trg->{definer} ) {
1308- my ( $user, $host )
1309- = map { s/'/''/g; "'$_'"; }
1310- split('@', $trg->{definer}, 2);
1311- $result .= "/*!50017 DEFINER=$user\@$host */ ";
1312- }
1313- $result .= sprintf("/*!50003 TRIGGER %s %s %s ON %s\nFOR EACH ROW %s */;;\n\n",
1314- $quoter->quote($trg->{trigger}),
1315- @{$trg}{qw(timing event)},
1316- $quoter->quote($trg->{table}),
1317- $trg->{statement});
1318- }
1319- $result .= "DELIMITER ;\n\n/*!50003 SET SESSION SQL_MODE=\@OLD_SQL_MODE */;\n\n";
1320- return $result;
1321- }
1322- else {
1323- return undef;
1324- }
1325- }
1326- elsif ( $what eq 'view' ) {
1327- my $ddl = $self->get_create_table($dbh, $quoter, $db, $tbl);
1328- return '/*!50001 DROP TABLE IF EXISTS ' . $quoter->quote($tbl) . "*/;\n"
1329- . '/*!50001 DROP VIEW IF EXISTS ' . $quoter->quote($tbl) . "*/;\n"
1330- . '/*!50001 ' . $ddl->[1] . "*/;\n";
1331- }
1332- else {
1333- die "You didn't say what to dump.";
1334- }
1335-}
1336-
1337-sub _use_db {
1338- my ( $self, $dbh, $quoter, $new ) = @_;
1339- if ( !$new ) {
1340- PTDEBUG && _d('No new DB to use');
1341- return;
1342- }
1343- my $sql = 'USE ' . $quoter->quote($new);
1344- PTDEBUG && _d($dbh, $sql);
1345- $dbh->do($sql);
1346- return;
1347-}
1348-
1349-sub get_create_table {
1350- my ( $self, $dbh, $quoter, $db, $tbl ) = @_;
1351- if ( !$self->{cache} || !$self->{tables}->{$db}->{$tbl} ) {
1352- my $sql = '/*!40101 SET @OLD_SQL_MODE := @@SQL_MODE, '
1353- . q{@@SQL_MODE := REPLACE(REPLACE(@@SQL_MODE, 'ANSI_QUOTES', ''), ',,', ','), }
1354- . '@OLD_QUOTE := @@SQL_QUOTE_SHOW_CREATE, '
1355- . '@@SQL_QUOTE_SHOW_CREATE := 1 */';
1356- PTDEBUG && _d($sql);
1357- eval { $dbh->do($sql); };
1358- PTDEBUG && $EVAL_ERROR && _d($EVAL_ERROR);
1359- $self->_use_db($dbh, $quoter, $db);
1360- $sql = "SHOW CREATE TABLE " . $quoter->quote($db, $tbl);
1361- PTDEBUG && _d($sql);
1362- my $href;
1363- eval { $href = $dbh->selectrow_hashref($sql); };
1364- if ( $EVAL_ERROR ) {
1365- warn "Failed to $sql. The table may be damaged.\nError: $EVAL_ERROR";
1366- return;
1367- }
1368-
1369- $sql = '/*!40101 SET @@SQL_MODE := @OLD_SQL_MODE, '
1370- . '@@SQL_QUOTE_SHOW_CREATE := @OLD_QUOTE */';
1371- PTDEBUG && _d($sql);
1372- $dbh->do($sql);
1373- my ($key) = grep { m/create table/i } keys %$href;
1374- if ( $key ) {
1375- PTDEBUG && _d('This table is a base table');
1376- $self->{tables}->{$db}->{$tbl} = [ 'table', $href->{$key} ];
1377- }
1378- else {
1379- PTDEBUG && _d('This table is a view');
1380- ($key) = grep { m/create view/i } keys %$href;
1381- $self->{tables}->{$db}->{$tbl} = [ 'view', $href->{$key} ];
1382- }
1383- }
1384- return $self->{tables}->{$db}->{$tbl};
1385-}
1386-
1387-sub get_columns {
1388- my ( $self, $dbh, $quoter, $db, $tbl ) = @_;
1389- PTDEBUG && _d('Get columns for', $db, $tbl);
1390- if ( !$self->{cache} || !$self->{columns}->{$db}->{$tbl} ) {
1391- $self->_use_db($dbh, $quoter, $db);
1392- my $sql = "SHOW COLUMNS FROM " . $quoter->quote($db, $tbl);
1393- PTDEBUG && _d($sql);
1394- my $cols = $dbh->selectall_arrayref($sql, { Slice => {} });
1395-
1396- $self->{columns}->{$db}->{$tbl} = [
1397- map {
1398- my %row;
1399- @row{ map { lc $_ } keys %$_ } = values %$_;
1400- \%row;
1401- } @$cols
1402- ];
1403- }
1404- return $self->{columns}->{$db}->{$tbl};
1405-}
1406-
1407-sub get_tmp_table {
1408- my ( $self, $dbh, $quoter, $db, $tbl ) = @_;
1409- my $result = 'CREATE TABLE ' . $quoter->quote($tbl) . " (\n";
1410- $result .= join(",\n",
1411- map { ' ' . $quoter->quote($_->{field}) . ' ' . $_->{type} }
1412- @{$self->get_columns($dbh, $quoter, $db, $tbl)});
1413- $result .= "\n)";
1414- PTDEBUG && _d($result);
1415- return $result;
1416-}
1417-
1418-sub get_triggers {
1419- my ( $self, $dbh, $quoter, $db, $tbl ) = @_;
1420- if ( !$self->{cache} || !$self->{triggers}->{$db} ) {
1421- $self->{triggers}->{$db} = {};
1422- my $sql = '/*!40101 SET @OLD_SQL_MODE := @@SQL_MODE, '
1423- . q{@@SQL_MODE := REPLACE(REPLACE(@@SQL_MODE, 'ANSI_QUOTES', ''), ',,', ','), }
1424- . '@OLD_QUOTE := @@SQL_QUOTE_SHOW_CREATE, '
1425- . '@@SQL_QUOTE_SHOW_CREATE := 1 */';
1426- PTDEBUG && _d($sql);
1427- eval { $dbh->do($sql); };
1428- PTDEBUG && $EVAL_ERROR && _d($EVAL_ERROR);
1429- $sql = "SHOW TRIGGERS FROM " . $quoter->quote($db);
1430- PTDEBUG && _d($sql);
1431- my $sth = $dbh->prepare($sql);
1432- $sth->execute();
1433- if ( $sth->rows ) {
1434- my $trgs = $sth->fetchall_arrayref({});
1435- foreach my $trg (@$trgs) {
1436- my %trg;
1437- @trg{ map { lc $_ } keys %$trg } = values %$trg;
1438- push @{ $self->{triggers}->{$db}->{ $trg{table} } }, \%trg;
1439- }
1440- }
1441- $sql = '/*!40101 SET @@SQL_MODE := @OLD_SQL_MODE, '
1442- . '@@SQL_QUOTE_SHOW_CREATE := @OLD_QUOTE */';
1443- PTDEBUG && _d($sql);
1444- $dbh->do($sql);
1445- }
1446- if ( $tbl ) {
1447- return $self->{triggers}->{$db}->{$tbl};
1448- }
1449- return values %{$self->{triggers}->{$db}};
1450-}
1451-
1452-sub get_databases {
1453- my ( $self, $dbh, $quoter, $like ) = @_;
1454- if ( !$self->{cache} || !$self->{databases} || $like ) {
1455- my $sql = 'SHOW DATABASES';
1456- my @params;
1457- if ( $like ) {
1458- $sql .= ' LIKE ?';
1459- push @params, $like;
1460- }
1461- my $sth = $dbh->prepare($sql);
1462- PTDEBUG && _d($sql, @params);
1463- $sth->execute( @params );
1464- my @dbs = map { $_->[0] } @{$sth->fetchall_arrayref()};
1465- $self->{databases} = \@dbs unless $like;
1466- return @dbs;
1467- }
1468- return @{$self->{databases}};
1469-}
1470-
1471-sub get_table_status {
1472- my ( $self, $dbh, $quoter, $db, $like ) = @_;
1473- if ( !$self->{cache} || !$self->{table_status}->{$db} || $like ) {
1474- my $sql = "SHOW TABLE STATUS FROM " . $quoter->quote($db);
1475- my @params;
1476- if ( $like ) {
1477- $sql .= ' LIKE ?';
1478- push @params, $like;
1479- }
1480- PTDEBUG && _d($sql, @params);
1481- my $sth = $dbh->prepare($sql);
1482- $sth->execute(@params);
1483- my @tables = @{$sth->fetchall_arrayref({})};
1484- @tables = map {
1485- my %tbl; # Make a copy with lowercased keys
1486- @tbl{ map { lc $_ } keys %$_ } = values %$_;
1487- $tbl{engine} ||= $tbl{type} || $tbl{comment};
1488- delete $tbl{type};
1489- \%tbl;
1490- } @tables;
1491- $self->{table_status}->{$db} = \@tables unless $like;
1492- return @tables;
1493- }
1494- return @{$self->{table_status}->{$db}};
1495-}
1496-
1497-sub get_table_list {
1498- my ( $self, $dbh, $quoter, $db, $like ) = @_;
1499- if ( !$self->{cache} || !$self->{table_list}->{$db} || $like ) {
1500- my $sql = "SHOW /*!50002 FULL*/ TABLES FROM " . $quoter->quote($db);
1501- my @params;
1502- if ( $like ) {
1503- $sql .= ' LIKE ?';
1504- push @params, $like;
1505- }
1506- PTDEBUG && _d($sql, @params);
1507- my $sth = $dbh->prepare($sql);
1508- $sth->execute(@params);
1509- my @tables = @{$sth->fetchall_arrayref()};
1510- @tables = map {
1511- my %tbl = (
1512- name => $_->[0],
1513- engine => ($_->[1] || '') eq 'VIEW' ? 'VIEW' : '',
1514- );
1515- \%tbl;
1516- } @tables;
1517- $self->{table_list}->{$db} = \@tables unless $like;
1518- return @tables;
1519- }
1520- return @{$self->{table_list}->{$db}};
1521-}
1522-
1523-sub _d {
1524- my ($package, undef, $line) = caller 0;
1525- @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
1526- map { defined $_ ? $_ : 'undef' }
1527- @_;
1528- print STDERR "# $package:$line $PID ", join(' ', @_), "\n";
1529-}
1530-
1531-1;
1532-}
1533-# ###########################################################################
1534-# End MySQLDump package
1535-# ###########################################################################
1536-
1537-# ###########################################################################
1538 # Daemon package
1539 # This package is a copy without comments from the original. The original
1540 # with comments and its test file can be found in the Bazaar repository at,
1541@@ -2774,6 +3125,9 @@
1542 dsn_table_dsn => $dsn_table_dsn,
1543 );
1544 }
1545+ elsif ( $method =~ m/none/i ) {
1546+ PTDEBUG && _d('Not getting to slaves');
1547+ }
1548 else {
1549 die "Invalid --recursion-method: $method. Valid values are: "
1550 . "dsn=DSN, hosts, or processlist.\n";
1551@@ -2788,6 +3142,11 @@
1552 my $dp = $args->{dsn_parser};
1553 my $dsn = $args->{dsn};
1554
1555+ if ( lc($args->{method} || '') eq 'none' ) {
1556+ PTDEBUG && _d('Not recursing to slaves');
1557+ return;
1558+ }
1559+
1560 my $dbh;
1561 eval {
1562 $dbh = $args->{dbh} || $dp->get_dbh(
1563@@ -2915,11 +3274,6 @@
1564
1565 my $show = "SHOW GRANTS FOR ";
1566 my $user = 'CURRENT_USER()';
1567- my $vp = $self->{VersionParser};
1568- if ( $vp && !$vp->version_ge($dbh, '4.1.2') ) {
1569- $user = $dbh->selectrow_arrayref('SELECT USER()')->[0];
1570- $user =~ s/([^@]+)@(.+)/'$1'\@'$2'/;
1571- }
1572 my $sql = $show . $user;
1573 PTDEBUG && _d($dbh, $sql);
1574
1575@@ -2969,7 +3323,7 @@
1576 or die "The server specified as a slave is not a slave";
1577 my @connected = $self->get_connected_slaves($master)
1578 or die "The server specified as a master has no connected slaves";
1579- my (undef, $port) = $master->selectrow_array('SHOW VARIABLES LIKE "port"');
1580+ my (undef, $port) = $master->selectrow_array("SHOW VARIABLES LIKE 'port'");
1581
1582 if ( $port != $slave_status->{master_port} ) {
1583 die "The slave is connected to $slave_status->{master_port} "
1584@@ -3443,7 +3797,6 @@
1585 # Holds the arguments for the $sth's bind variables, so it can be re-tried
1586 # easily.
1587 my @beginning_of_txn;
1588-my $vp = new VersionParser;
1589 my $q = new Quoter;
1590
1591 sub main {
1592@@ -3591,7 +3944,6 @@
1593 # ########################################################################
1594
1595 my $tp = new TableParser(Quoter => $q);
1596- my $du = new MySQLDump();
1597 foreach my $table ( grep { $_ } ($src, $dst) ) {
1598 my $ac = !$txnsize && !$commit_each;
1599 if ( !defined $table->{p} && $o->get('ask-pass') ) {
1600@@ -3641,7 +3993,7 @@
1601 }
1602
1603 $table->{info} = $tp->parse(
1604- $du->get_create_table($dbh, $q, $table->{D}, $table->{t}));
1605+ $tp->get_create_table( $dbh, $table->{D}, $table->{t} ));
1606
1607 if ( $o->get('check-charset') ) {
1608 my $sql = 'SELECT CONCAT(/*!40100 @@session.character_set_connection, */ "")';
1609@@ -3700,7 +4052,7 @@
1610 my $dsn_defaults = $dp->parse_options($o);
1611 my $dsn = $dp->parse($o->get('check-slave-lag'), $dsn_defaults);
1612 $lag_dbh = $dp->get_dbh($dp->get_cxn_params($dsn), { AutoCommit => 1 });
1613- $ms = new MasterSlave(VersionParser => $vp);
1614+ $ms = new MasterSlave();
1615 }
1616
1617 # ########################################################################
1618@@ -3773,7 +4125,7 @@
1619 . join(',', map { $q->quote($_) } @{$sel_stmt->{cols}} )
1620 . " FROM $src->{db_tbl}"
1621 . ( $sel_stmt->{index}
1622- ? (($vp->version_ge($dbh, '4.0.9') ? " FORCE" : " USE")
1623+ ? ((VersionParser->new($dbh) >= '4.0.9' ? " FORCE" : " USE")
1624 . " INDEX(`$sel_stmt->{index}`)")
1625 : '')
1626 . " WHERE (".$o->get('where').")";
1627@@ -4473,7 +4825,7 @@
1628
1629 sub get_irot {
1630 my ( $dbh ) = @_;
1631- return 1 unless $vp->version_ge($dbh, '5.0.13');
1632+ return 1 unless VersionParser->new($dbh) >= '5.0.13';
1633 my $rows = $dbh->selectall_arrayref(
1634 "show variables like 'innodb_rollback_on_timeout'",
1635 { Slice => {} });
1636@@ -4576,8 +4928,8 @@
1637 rows. Specifying the index with the 'i' part of the L<"--source"> argument can
1638 be crucial for this; use L<"--dry-run"> to examine the generated queries and be
1639 sure to EXPLAIN them to see if they are efficient (most of the time you probably
1640-want to scan the PRIMARY key, which is the default). Even better, profile
1641-pt-archiver with mk-query-profiler (L<http://maatkit.org/get/mk-query-profiler>)
1642+want to scan the PRIMARY key, which is the default). Even better, examine the
1643+difference in the Handler status counters before and after running the query,
1644 and make sure it is not scanning the whole table every query.
1645
1646 You can disable the seek-then-scan optimizations partially or wholly with
1647@@ -5743,6 +6095,10 @@
1648
1649 =head1 VERSION
1650
1651+<<<<<<< TREE
1652 pt-archiver 2.0.5
1653+=======
1654+pt-archiver 2.1.2
1655+>>>>>>> MERGE-SOURCE
1656
1657 =cut
1658
1659=== modified file 'bin/pt-config-diff'
1660--- bin/pt-config-diff 2012-06-09 21:53:04 +0000
1661+++ bin/pt-config-diff 2012-07-20 22:10:28 +0000
1662@@ -1262,51 +1262,10 @@
1663 PTDEBUG && _d($cxn_string, ' ', $user, ' ', $pass,
1664 join(', ', map { "$_=>$defaults->{$_}" } keys %$defaults ));
1665
1666- eval {
1667- $dbh = DBI->connect($cxn_string, $user, $pass, $defaults);
1668-
1669- if ( $cxn_string =~ m/mysql/i ) {
1670- my $sql;
1671-
1672- $sql = 'SELECT @@SQL_MODE';
1673- PTDEBUG && _d($dbh, $sql);
1674- my ($sql_mode) = $dbh->selectrow_array($sql);
1675-
1676- $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1'
1677- . '/*!40101, @@SQL_MODE=\'NO_AUTO_VALUE_ON_ZERO'
1678- . ($sql_mode ? ",$sql_mode" : '')
1679- . '\'*/';
1680- PTDEBUG && _d($dbh, $sql);
1681- $dbh->do($sql);
1682-
1683- if ( my ($charset) = $cxn_string =~ m/charset=(\w+)/ ) {
1684- $sql = "/*!40101 SET NAMES $charset*/";
1685- PTDEBUG && _d($dbh, ':', $sql);
1686- $dbh->do($sql);
1687- PTDEBUG && _d('Enabling charset for STDOUT');
1688- if ( $charset eq 'utf8' ) {
1689- binmode(STDOUT, ':utf8')
1690- or die "Can't binmode(STDOUT, ':utf8'): $OS_ERROR";
1691- }
1692- else {
1693- binmode(STDOUT) or die "Can't binmode(STDOUT): $OS_ERROR";
1694- }
1695- }
1696-
1697- if ( $self->prop('set-vars') ) {
1698- $sql = "SET " . $self->prop('set-vars');
1699- PTDEBUG && _d($dbh, ':', $sql);
1700- $dbh->do($sql);
1701- }
1702- }
1703- };
1704+ $dbh = eval { DBI->connect($cxn_string, $user, $pass, $defaults) };
1705+
1706 if ( !$dbh && $EVAL_ERROR ) {
1707- PTDEBUG && _d($EVAL_ERROR);
1708- if ( $EVAL_ERROR =~ m/not a compiled character set|character set utf8/ ) {
1709- PTDEBUG && _d('Going to try again without utf8 support');
1710- delete $defaults->{mysql_enable_utf8};
1711- }
1712- elsif ( $EVAL_ERROR =~ m/locate DBD\/mysql/i ) {
1713+ if ( $EVAL_ERROR =~ m/locate DBD\/mysql/i ) {
1714 die "Cannot connect to MySQL because the Perl DBD::mysql module is "
1715 . "not installed or not found. Run 'perl -MDBD::mysql' to see "
1716 . "the directories that Perl searches for DBD::mysql. If "
1717@@ -1315,19 +1274,70 @@
1718 . " RHEL/CentOS yum install perl-DBD-MySQL\n"
1719 . " OpenSolaris pgk install pkg:/SUNWapu13dbd-mysql\n";
1720 }
1721+ elsif ( $EVAL_ERROR =~ m/not a compiled character set|character set utf8/ ) {
1722+ PTDEBUG && _d('Going to try again without utf8 support');
1723+ delete $defaults->{mysql_enable_utf8};
1724+ }
1725 if ( !$tries ) {
1726 die $EVAL_ERROR;
1727 }
1728 }
1729 }
1730
1731+ if ( $cxn_string =~ m/mysql/i ) {
1732+ my $sql;
1733+
1734+ $sql = 'SELECT @@SQL_MODE';
1735+ PTDEBUG && _d($dbh, $sql);
1736+ my ($sql_mode) = eval { $dbh->selectrow_array($sql) };
1737+ if ( $EVAL_ERROR ) {
1738+ die $EVAL_ERROR;
1739+ }
1740+
1741+ $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1'
1742+ . '/*!40101, @@SQL_MODE=\'NO_AUTO_VALUE_ON_ZERO'
1743+ . ($sql_mode ? ",$sql_mode" : '')
1744+ . '\'*/';
1745+ PTDEBUG && _d($dbh, $sql);
1746+ eval { $dbh->do($sql) };
1747+ if ( $EVAL_ERROR ) {
1748+ die $EVAL_ERROR;
1749+ }
1750+
1751+ if ( my ($charset) = $cxn_string =~ m/charset=(\w+)/ ) {
1752+ $sql = "/*!40101 SET NAMES $charset*/";
1753+ PTDEBUG && _d($dbh, ':', $sql);
1754+ eval { $dbh->do($sql) };
1755+ if ( $EVAL_ERROR ) {
1756+ die $EVAL_ERROR;
1757+ }
1758+ PTDEBUG && _d('Enabling charset for STDOUT');
1759+ if ( $charset eq 'utf8' ) {
1760+ binmode(STDOUT, ':utf8')
1761+ or die "Can't binmode(STDOUT, ':utf8'): $OS_ERROR";
1762+ }
1763+ else {
1764+ binmode(STDOUT) or die "Can't binmode(STDOUT): $OS_ERROR";
1765+ }
1766+ }
1767+
1768+ if ( $self->prop('set-vars') ) {
1769+ $sql = "SET " . $self->prop('set-vars');
1770+ PTDEBUG && _d($dbh, ':', $sql);
1771+ eval { $dbh->do($sql) };
1772+ if ( $EVAL_ERROR ) {
1773+ die $EVAL_ERROR;
1774+ }
1775+ }
1776+ }
1777+
1778 PTDEBUG && _d('DBH info: ',
1779 $dbh,
1780 Dumper($dbh->selectrow_hashref(
1781 'SELECT DATABASE(), CONNECTION_ID(), VERSION()/*!50038 , @@hostname*/')),
1782 'Connection info:', $dbh->{mysql_hostinfo},
1783 'Character set info:', Dumper($dbh->selectall_arrayref(
1784- 'SHOW VARIABLES LIKE "character_set%"', { Slice => {}})),
1785+ "SHOW VARIABLES LIKE 'character_set%'", { Slice => {}})),
1786 '$DBD::mysql::VERSION:', $DBD::mysql::VERSION,
1787 '$DBI::VERSION:', $DBI::VERSION,
1788 );
1789@@ -1408,9 +1418,11 @@
1790 use strict;
1791 use warnings FATAL => 'all';
1792 use English qw(-no_match_vars);
1793-use constant PTDEBUG => $ENV{PTDEBUG} || 0;
1794-
1795-use constant PERCONA_TOOLKIT_TEST_USE_DSN_NAMES => $ENV{PERCONA_TOOLKIT_TEST_USE_DSN_NAMES} || 0;
1796+use Scalar::Util qw(blessed);
1797+use constant {
1798+ PTDEBUG => $ENV{PTDEBUG} || 0,
1799+ PERCONA_TOOLKIT_TEST_USE_DSN_NAMES => $ENV{PERCONA_TOOLKIT_TEST_USE_DSN_NAMES} || 0,
1800+};
1801
1802 sub new {
1803 my ( $class, %args ) = @_;
1804@@ -1513,7 +1525,9 @@
1805
1806 sub DESTROY {
1807 my ($self) = @_;
1808- if ( $self->{dbh} ) {
1809+ if ( $self->{dbh}
1810+ && blessed($self->{dbh})
1811+ && $self->{dbh}->can("disconnect") ) {
1812 PTDEBUG && _d('Disconnecting dbh', $self->{dbh}, $self->{name});
1813 $self->{dbh}->disconnect();
1814 }
1815@@ -3408,6 +3422,10 @@
1816
1817 =head1 VERSION
1818
1819+<<<<<<< TREE
1820 pt-config-diff 2.0.5
1821+=======
1822+pt-config-diff 2.1.2
1823+>>>>>>> MERGE-SOURCE
1824
1825 =cut
1826
1827=== modified file 'bin/pt-deadlock-logger'
1828--- bin/pt-deadlock-logger 2012-06-09 21:53:04 +0000
1829+++ bin/pt-deadlock-logger 2012-07-20 22:10:28 +0000
1830@@ -959,7 +959,7 @@
1831 $opt->{value} = ($pre || '') . $num;
1832 }
1833 else {
1834- $self->save_error("Invalid size for --$opt->{long}");
1835+ $self->save_error("Invalid size for --$opt->{long}: $val");
1836 }
1837 return;
1838 }
1839@@ -1034,6 +1034,455 @@
1840 # ###########################################################################
1841
1842 # ###########################################################################
1843+# Mo package
1844+# This package is a copy without comments from the original. The original
1845+# with comments and its test file can be found in the Bazaar repository at,
1846+# lib/Mo.pm
1847+# t/lib/Mo.t
1848+# See https://launchpad.net/percona-toolkit for more information.
1849+# ###########################################################################
1850+{
1851+BEGIN {
1852+$INC{"Mo.pm"} = __FILE__;
1853+package Mo;
1854+our $VERSION = '0.30_Percona'; # Forked from 0.30 of Mo.
1855+
1856+{
1857+ no strict 'refs';
1858+ sub _glob_for {
1859+ return \*{shift()}
1860+ }
1861+
1862+ sub _stash_for {
1863+ return \%{ shift() . "::" };
1864+ }
1865+}
1866+
1867+use strict;
1868+use warnings qw( FATAL all );
1869+
1870+use Carp ();
1871+use Scalar::Util ();
1872+
1873+our %TYPES = (
1874+ Bool => sub { !$_[0] || (defined $_[0] && &Scalar::Util::looks_like_number && $_[0] == 1) },
1875+ Num => sub { defined $_[0] && &Scalar::Util::looks_like_number },
1876+ Int => sub { defined $_[0] && &Scalar::Util::looks_like_number && $_[0] == int $_[0] },
1877+ Str => sub { defined $_[0] },
1878+ Object => sub { defined $_[0] && &Scalar::Util::blessed },
1879+ FileHandle => sub { local $@; require IO::Handle; fileno($_[0]) && $_[0]->opened },
1880+
1881+ map {
1882+ my $type = /R/ ? $_ : uc $_;
1883+ $_ . "Ref" => sub { ref $_[0] eq $type }
1884+ } qw(Array Code Hash Regexp Glob Scalar)
1885+);
1886+
1887+our %metadata_for;
1888+{
1889+ package Mo::Object;
1890+
1891+ sub new {
1892+ my $class = shift;
1893+ my $args = $class->BUILDARGS(@_);
1894+
1895+ my @args_to_delete;
1896+ while ( my ($attr, $meta) = each %{$metadata_for{$class}} ) {
1897+ next unless exists $meta->{init_arg};
1898+ my $init_arg = $meta->{init_arg};
1899+
1900+ if ( defined $init_arg ) {
1901+ $args->{$attr} = delete $args->{$init_arg};
1902+ }
1903+ else {
1904+ push @args_to_delete, $attr;
1905+ }
1906+ }
1907+
1908+ delete $args->{$_} for @args_to_delete;
1909+
1910+ for my $attribute ( keys %$args ) {
1911+ if ( my $coerce = $metadata_for{$class}{$attribute}{coerce} ) {
1912+ $args->{$attribute} = $coerce->($args->{$attribute});
1913+ }
1914+ if ( my $I = $metadata_for{$class}{$attribute}{isa} ) {
1915+ ( (my $I_name), $I ) = @{$I};
1916+ Mo::_check_type_constaints($attribute, $I, $I_name, $args->{$attribute});
1917+ }
1918+ }
1919+
1920+ while ( my ($attribute, $meta) = each %{$metadata_for{$class}} ) {
1921+ next unless $meta->{required};
1922+ Carp::confess("Attribute ($attribute) is required for $class")
1923+ if ! exists $args->{$attribute}
1924+ }
1925+
1926+ @_ = %$args;
1927+ my $self = bless $args, $class;
1928+
1929+ my @build_subs;
1930+ my $linearized_isa = mro::get_linear_isa($class);
1931+
1932+ for my $isa_class ( @$linearized_isa ) {
1933+ unshift @build_subs, *{ Mo::_glob_for "${isa_class}::BUILD" }{CODE};
1934+ }
1935+ exists &$_ && $_->( $self, @_ ) for grep { defined } @build_subs;
1936+ return $self;
1937+ }
1938+
1939+ sub BUILDARGS {
1940+ shift;
1941+ my $ref;
1942+ if ( @_ == 1 && ref($_[0]) ) {
1943+ Carp::confess("Single parameters to new() must be a HASH ref")
1944+ unless ref($_[0]) eq ref({});
1945+ $ref = {%{$_[0]}} # We want a new reference, always
1946+ }
1947+ else {
1948+ $ref = { @_ };
1949+ }
1950+ return $ref;
1951+ }
1952+}
1953+
1954+my %export_for;
1955+sub Mo::import {
1956+ warnings->import(qw(FATAL all));
1957+ strict->import();
1958+
1959+ my $caller = scalar caller(); # Caller's package
1960+ my $caller_pkg = $caller . "::"; # Caller's package with :: at the end
1961+ my (%exports, %options);
1962+
1963+ my (undef, @features) = @_;
1964+ my %ignore = ( map { $_ => 1 } qw( is isa init_arg builder buildargs clearer predicate build handles default required ) );
1965+ for my $feature (grep { !$ignore{$_} } @features) {
1966+ { local $@; require "Mo/$feature.pm"; }
1967+ {
1968+ no strict 'refs';
1969+ &{"Mo::${feature}::e"}(
1970+ $caller_pkg,
1971+ \%exports,
1972+ \%options,
1973+ \@_
1974+ );
1975+ }
1976+ }
1977+
1978+ return if $exports{M};
1979+
1980+ %exports = (
1981+ extends => sub {
1982+ for my $class ( map { "$_" } @_ ) {
1983+ $class =~ s{::|'}{/}g;
1984+ { local $@; eval { require "$class.pm" } } # or warn $@;
1985+ }
1986+ _set_package_isa($caller, @_);
1987+ _set_inherited_metadata($caller);
1988+ },
1989+ has => sub {
1990+ my $names = shift;
1991+ for my $attribute ( ref $names ? @$names : $names ) {
1992+ my %args = @_;
1993+ my $method = ($args{is} || '') eq 'ro'
1994+ ? sub {
1995+ Carp::confess("Cannot assign a value to a read-only accessor at reader ${caller_pkg}${attribute}")
1996+ if $#_;
1997+ return $_[0]{$attribute};
1998+ }
1999+ : sub {
2000+ return $#_
2001+ ? $_[0]{$attribute} = $_[1]
2002+ : $_[0]{$attribute};
2003+ };
2004+
2005+ $metadata_for{$caller}{$attribute} = ();
2006+
2007+ if ( my $I = $args{isa} ) {
2008+ my $orig_I = $I;
2009+ my $type;
2010+ if ( $I =~ /\A(ArrayRef|Maybe)\[(.*)\]\z/ ) {
2011+ $I = _nested_constraints($attribute, $1, $2);
2012+ }
2013+ $metadata_for{$caller}{$attribute}{isa} = [$orig_I, $I];
2014+ my $orig_method = $method;
2015+ $method = sub {
2016+ if ( $#_ ) {
2017+ Mo::_check_type_constaints($attribute, $I, $orig_I, $_[1]);
2018+ }
2019+ goto &$orig_method;
2020+ };
2021+ }
2022+
2023+ if ( my $builder = $args{builder} ) {
2024+ my $original_method = $method;
2025+ $method = sub {
2026+ $#_
2027+ ? goto &$original_method
2028+ : ! exists $_[0]{$attribute}
2029+ ? $_[0]{$attribute} = $_[0]->$builder
2030+ : goto &$original_method
2031+ };
2032+ }
2033+
2034+ if ( my $code = $args{default} ) {
2035+ Carp::confess("${caller}::${attribute}'s default is $code, but should be a coderef")
2036+ unless ref($code) eq 'CODE';
2037+ my $original_method = $method;
2038+ $method = sub {
2039+ $#_
2040+ ? goto &$original_method
2041+ : ! exists $_[0]{$attribute}
2042+ ? $_[0]{$attribute} = $_[0]->$code
2043+ : goto &$original_method
2044+ };
2045+ }
2046+
2047+ if ( my $role = $args{does} ) {
2048+ my $original_method = $method;
2049+ $method = sub {
2050+ if ( $#_ ) {
2051+ Carp::confess(qq<Attribute ($attribute) doesn't consume a '$role' role">)
2052+ unless blessed($_[1]) && $_[1]->does($role)
2053+ }
2054+ goto &$original_method
2055+ };
2056+ }
2057+
2058+ if ( my $coercion = $args{coerce} ) {
2059+ $metadata_for{$caller}{$attribute}{coerce} = $coercion;
2060+ my $original_method = $method;
2061+ $method = sub {
2062+ if ( $#_ ) {
2063+ return $original_method->($_[0], $coercion->($_[1]))
2064+ }
2065+ goto &$original_method;
2066+ }
2067+ }
2068+
2069+ $method = $options{$_}->($method, $attribute, @_)
2070+ for sort keys %options;
2071+
2072+ *{ _glob_for "${caller}::$attribute" } = $method;
2073+
2074+ if ( $args{required} ) {
2075+ $metadata_for{$caller}{$attribute}{required} = 1;
2076+ }
2077+
2078+ if ($args{clearer}) {
2079+ *{ _glob_for "${caller}::$args{clearer}" }
2080+ = sub { delete shift->{$attribute} }
2081+ }
2082+
2083+ if ($args{predicate}) {
2084+ *{ _glob_for "${caller}::$args{predicate}" }
2085+ = sub { exists shift->{$attribute} }
2086+ }
2087+
2088+ if ($args{handles}) {
2089+ _has_handles($caller, $attribute, \%args);
2090+ }
2091+
2092+ if (exists $args{init_arg}) {
2093+ $metadata_for{$caller}{$attribute}{init_arg} = $args{init_arg};
2094+ }
2095+ }
2096+ },
2097+ %exports,
2098+ );
2099+
2100+ $export_for{$caller} = [ keys %exports ];
2101+
2102+ for my $keyword ( keys %exports ) {
2103+ *{ _glob_for "${caller}::$keyword" } = $exports{$keyword}
2104+ }
2105+ *{ _glob_for "${caller}::extends" }{CODE}->( "Mo::Object" )
2106+ unless @{ *{ _glob_for "${caller}::ISA" }{ARRAY} || [] };
2107+};
2108+
2109+sub _check_type_constaints {
2110+ my ($attribute, $I, $I_name, $val) = @_;
2111+ ( ref($I) eq 'CODE'
2112+ ? $I->($val)
2113+ : (ref $val eq $I
2114+ || ($val && $val eq $I)
2115+ || (exists $TYPES{$I} && $TYPES{$I}->($val)))
2116+ )
2117+ || Carp::confess(
2118+ qq<Attribute ($attribute) does not pass the type constraint because: >
2119+ . qq<Validation failed for '$I_name' with value >
2120+ . (defined $val ? Mo::Dumper($val) : 'undef') )
2121+}
2122+
2123+sub _has_handles {
2124+ my ($caller, $attribute, $args) = @_;
2125+ my $handles = $args->{handles};
2126+
2127+ my $ref = ref $handles;
2128+ my $kv;
2129+ if ( $ref eq ref [] ) {
2130+ $kv = { map { $_,$_ } @{$handles} };
2131+ }
2132+ elsif ( $ref eq ref {} ) {
2133+ $kv = $handles;
2134+ }
2135+ elsif ( $ref eq ref qr// ) {
2136+ Carp::confess("Cannot delegate methods based on a Regexp without a type constraint (isa)")
2137+ unless $args->{isa};
2138+ my $target_class = $args->{isa};
2139+ $kv = {
2140+ map { $_, $_ }
2141+ grep { $_ =~ $handles }
2142+ grep { !exists $Mo::Object::{$_} && $target_class->can($_) }
2143+ grep { $_ ne 'has' && $_ ne 'extends' }
2144+ keys %{ _stash_for $target_class }
2145+ };
2146+ }
2147+ else {
2148+ Carp::confess("handles for $ref not yet implemented");
2149+ }
2150+
2151+ while ( my ($method, $target) = each %{$kv} ) {
2152+ my $name = _glob_for "${caller}::$method";
2153+ Carp::confess("You cannot overwrite a locally defined method ($method) with a delegation")
2154+ if defined &$name;
2155+
2156+ my ($target, @curried_args) = ref($target) ? @$target : $target;
2157+ *$name = sub {
2158+ my $self = shift;
2159+ my $delegate_to = $self->$attribute();
2160+ my $error = "Cannot delegate $method to $target because the value of $attribute";
2161+ Carp::confess("$error is not defined") unless $delegate_to;
2162+ Carp::confess("$error is not an object (got '$delegate_to')")
2163+ unless Scalar::Util::blessed($delegate_to) || (!ref($delegate_to) && $delegate_to->can($target));
2164+ return $delegate_to->$target(@curried_args, @_);
2165+ }
2166+ }
2167+}
2168+
2169+sub _nested_constraints {
2170+ my ($attribute, $aggregate_type, $type) = @_;
2171+
2172+ my $inner_types;
2173+ if ( $type =~ /\A(ArrayRef|Maybe)\[(.*)\]\z/ ) {
2174+ $inner_types = _nested_constraints($1, $2);
2175+ }
2176+ else {
2177+ $inner_types = $TYPES{$type};
2178+ }
2179+
2180+ if ( $aggregate_type eq 'ArrayRef' ) {
2181+ return sub {
2182+ my ($val) = @_;
2183+ return unless ref($val) eq ref([]);
2184+
2185+ if ($inner_types) {
2186+ for my $value ( @{$val} ) {
2187+ return unless $inner_types->($value)
2188+ }
2189+ }
2190+ else {
2191+ for my $value ( @{$val} ) {
2192+ return unless $value && ($value eq $type
2193+ || (Scalar::Util::blessed($value) && $value->isa($type)));
2194+ }
2195+ }
2196+ return 1;
2197+ };
2198+ }
2199+ elsif ( $aggregate_type eq 'Maybe' ) {
2200+ return sub {
2201+ my ($value) = @_;
2202+ return 1 if ! defined($value);
2203+ if ($inner_types) {
2204+ return unless $inner_types->($value)
2205+ }
2206+ else {
2207+ return unless $value eq $type
2208+ || (Scalar::Util::blessed($value) && $value->isa($type));
2209+ }
2210+ return 1;
2211+ }
2212+ }
2213+ else {
2214+ Carp::confess("Nested aggregate types are only implemented for ArrayRefs and Maybe");
2215+ }
2216+}
2217+
2218+sub _set_package_isa {
2219+ my ($package, @new_isa) = @_;
2220+
2221+ *{ _glob_for "${package}::ISA" } = [@new_isa];
2222+}
2223+
2224+sub _set_inherited_metadata {
2225+ my $class = shift;
2226+ my $linearized_isa = mro::get_linear_isa($class);
2227+ my %new_metadata;
2228+
2229+ for my $isa_class (reverse @$linearized_isa) {
2230+ %new_metadata = (
2231+ %new_metadata,
2232+ %{ $metadata_for{$isa_class} || {} },
2233+ );
2234+ }
2235+ $metadata_for{$class} = \%new_metadata;
2236+}
2237+
2238+sub unimport {
2239+ my $caller = scalar caller();
2240+ my $stash = _stash_for( $caller );
2241+
2242+ delete $stash->{$_} for @{$export_for{$caller}};
2243+}
2244+
2245+sub Dumper {
2246+ require Data::Dumper;
2247+ local $Data::Dumper::Indent = 0;
2248+ local $Data::Dumper::Sortkeys = 0;
2249+ local $Data::Dumper::Quotekeys = 0;
2250+ local $Data::Dumper::Terse = 1;
2251+
2252+ Data::Dumper::Dumper(@_)
2253+}
2254+
2255+BEGIN {
2256+ if ($] >= 5.010) {
2257+ { local $@; require mro; }
2258+ }
2259+ else {
2260+ local $@;
2261+ eval {
2262+ require MRO::Compat;
2263+ } or do {
2264+ *mro::get_linear_isa = *mro::get_linear_isa_dfs = sub {
2265+ no strict 'refs';
2266+
2267+ my $classname = shift;
2268+
2269+ my @lin = ($classname);
2270+ my %stored;
2271+ foreach my $parent (@{"$classname\::ISA"}) {
2272+ my $plin = mro::get_linear_isa_dfs($parent);
2273+ foreach (@$plin) {
2274+ next if exists $stored{$_};
2275+ push(@lin, $_);
2276+ $stored{$_} = 1;
2277+ }
2278+ }
2279+ return \@lin;
2280+ };
2281+ }
2282+ }
2283+}
2284+
2285+}
2286+1;
2287+}
2288+# ###########################################################################
2289+# End Mo package
2290+# ###########################################################################
2291+# ###########################################################################
2292 # VersionParser package
2293 # This package is a copy without comments from the original. The original
2294 # with comments and its test file can be found in the Bazaar repository at,
2295@@ -1044,35 +1493,145 @@
2296 {
2297 package VersionParser;
2298
2299-use strict;
2300-use warnings FATAL => 'all';
2301+use Mo;
2302+use Scalar::Util qw(blessed);
2303 use English qw(-no_match_vars);
2304 use constant PTDEBUG => $ENV{PTDEBUG} || 0;
2305
2306-sub new {
2307- my ( $class ) = @_;
2308- bless {}, $class;
2309-}
2310-
2311-sub parse {
2312- my ( $self, $str ) = @_;
2313- my $result = sprintf('%03d%03d%03d', $str =~ m/(\d+)/g);
2314- PTDEBUG && _d($str, 'parses to', $result);
2315- return $result;
2316-}
2317-
2318-sub version_ge {
2319- my ( $self, $dbh, $target ) = @_;
2320- if ( !$self->{$dbh} ) {
2321- $self->{$dbh} = $self->parse(
2322- $dbh->selectrow_array('SELECT VERSION()'));
2323- }
2324- my $result = $self->{$dbh} ge $self->parse($target) ? 1 : 0;
2325- PTDEBUG && _d($self->{$dbh}, 'ge', $target, ':', $result);
2326- return $result;
2327-}
2328-
2329-sub innodb_version {
2330+use overload (
2331+ '""' => "version",
2332+ '<=>' => "cmp",
2333+ 'cmp' => "cmp",
2334+ fallback => 1,
2335+);
2336+
2337+use Carp ();
2338+
2339+our $VERSION = 0.01;
2340+
2341+has major => (
2342+ is => 'ro',
2343+ isa => 'Int',
2344+ required => 1,
2345+);
2346+
2347+has [qw( minor revision )] => (
2348+ is => 'ro',
2349+ isa => 'Num',
2350+);
2351+
2352+has flavor => (
2353+ is => 'ro',
2354+ isa => 'Str',
2355+ default => sub { 'Unknown' },
2356+);
2357+
2358+has innodb_version => (
2359+ is => 'ro',
2360+ isa => 'Str',
2361+ default => sub { 'NO' },
2362+);
2363+
2364+sub series {
2365+ my $self = shift;
2366+ return $self->_join_version($self->major, $self->minor);
2367+}
2368+
2369+sub version {
2370+ my $self = shift;
2371+ return $self->_join_version($self->major, $self->minor, $self->revision);
2372+}
2373+
2374+sub is_in {
2375+ my ($self, $target) = @_;
2376+
2377+ return $self eq $target;
2378+}
2379+
2380+sub _join_version {
2381+ my ($self, @parts) = @_;
2382+
2383+ return join ".", map { my $c = $_; $c =~ s/^0\./0/; $c } grep defined, @parts;
2384+}
2385+sub _split_version {
2386+ my ($self, $str) = @_;
2387+ my @version_parts = map { s/^0(?=\d)/0./; $_ } $str =~ m/(\d+)/g;
2388+ return @version_parts[0..2];
2389+}
2390+
2391+sub normalized_version {
2392+ my ( $self ) = @_;
2393+ my $result = sprintf('%d%02d%02d', map { $_ || 0 } $self->major,
2394+ $self->minor,
2395+ $self->revision);
2396+ PTDEBUG && _d($self->version, 'normalizes to', $result);
2397+ return $result;
2398+}
2399+
2400+sub comment {
2401+ my ( $self, $cmd ) = @_;
2402+ my $v = $self->normalized_version();
2403+
2404+ return "/*!$v $cmd */"
2405+}
2406+
2407+my @methods = qw(major minor revision);
2408+sub cmp {
2409+ my ($left, $right) = @_;
2410+ my $right_obj = (blessed($right) && $right->isa(ref($left)))
2411+ ? $right
2412+ : ref($left)->new($right);
2413+
2414+ my $retval = 0;
2415+ for my $m ( @methods ) {
2416+ last unless defined($left->$m) && defined($right_obj->$m);
2417+ $retval = $left->$m <=> $right_obj->$m;
2418+ last if $retval;
2419+ }
2420+ return $retval;
2421+}
2422+
2423+sub BUILDARGS {
2424+ my $self = shift;
2425+
2426+ if ( @_ == 1 ) {
2427+ my %args;
2428+ if ( blessed($_[0]) && $_[0]->can("selectrow_hashref") ) {
2429+ PTDEBUG && _d("VersionParser got a dbh, trying to get the version");
2430+ my $dbh = $_[0];
2431+ local $dbh->{FetchHashKeyName} = 'NAME_lc';
2432+ my $query = eval {
2433+ $dbh->selectall_arrayref(q/SHOW VARIABLES LIKE 'version%'/, { Slice => {} })
2434+ };
2435+ if ( $query ) {
2436+ $query = { map { $_->{variable_name} => $_->{value} } @$query };
2437+ @args{@methods} = $self->_split_version($query->{version});
2438+ $args{flavor} = delete $query->{version_comment}
2439+ if $query->{version_comment};
2440+ }
2441+ elsif ( eval { ($query) = $dbh->selectrow_array(q/SELECT VERSION()/) } ) {
2442+ @args{@methods} = $self->_split_version($query);
2443+ }
2444+ else {
2445+ Carp::confess("Couldn't get the version from the dbh while "
2446+ . "creating a VersionParser object: $@");
2447+ }
2448+ $args{innodb_version} = eval { $self->_innodb_version($dbh) };
2449+ }
2450+ elsif ( !ref($_[0]) ) {
2451+ @args{@methods} = $self->_split_version($_[0]);
2452+ }
2453+
2454+ for my $method (@methods) {
2455+ delete $args{$method} unless defined $args{$method};
2456+ }
2457+ @_ = %args if %args;
2458+ }
2459+
2460+ return $self->SUPER::BUILDARGS(@_);
2461+}
2462+
2463+sub _innodb_version {
2464 my ( $self, $dbh ) = @_;
2465 return unless $dbh;
2466 my $innodb_version = "NO";
2467@@ -1110,6 +1669,7 @@
2468 print STDERR "# $package:$line $PID ", join(' ', @_), "\n";
2469 }
2470
2471+no Mo;
2472 1;
2473 }
2474 # ###########################################################################
2475@@ -1187,6 +1747,48 @@
2476 return $db ? "$db.$tbl" : $tbl;
2477 }
2478
2479+sub serialize_list {
2480+ my ( $self, @args ) = @_;
2481+ return unless @args;
2482+
2483+ return $args[0] if @args == 1 && !defined $args[0];
2484+
2485+ die "Cannot serialize multiple values with undef/NULL"
2486+ if grep { !defined $_ } @args;
2487+
2488+ return join ',', map { quotemeta } @args;
2489+}
2490+
2491+sub deserialize_list {
2492+ my ( $self, $string ) = @_;
2493+ return $string unless defined $string;
2494+ my @escaped_parts = $string =~ /
2495+ \G # Start of string, or end of previous match.
2496+ ( # Each of these is an element in the original list.
2497+ [^\\,]* # Anything not a backslash or a comma
2498+ (?: # When we get here, we found one of the above.
2499+ \\. # A backslash followed by something so we can continue
2500+ [^\\,]* # Same as above.
2501+ )* # Repeat zero of more times.
2502+ )
2503+ , # Comma dividing elements
2504+ /sxgc;
2505+
2506+ push @escaped_parts, pos($string) ? substr( $string, pos($string) ) : $string;
2507+
2508+ my @unescaped_parts = map {
2509+ my $part = $_;
2510+
2511+ my $char_class = utf8::is_utf8($part) # If it's a UTF-8 string,
2512+ ? qr/(?=\p{ASCII})\W/ # We only care about non-word
2513+ : qr/(?=\p{ASCII})\W|[\x{80}-\x{FF}]/; # Otherwise,
2514+ $part =~ s/\\($char_class)/$1/g;
2515+ $part;
2516+ } @escaped_parts;
2517+
2518+ return @unescaped_parts;
2519+}
2520+
2521 1;
2522 }
2523 # ###########################################################################
2524@@ -1422,51 +2024,10 @@
2525 PTDEBUG && _d($cxn_string, ' ', $user, ' ', $pass,
2526 join(', ', map { "$_=>$defaults->{$_}" } keys %$defaults ));
2527
2528- eval {
2529- $dbh = DBI->connect($cxn_string, $user, $pass, $defaults);
2530-
2531- if ( $cxn_string =~ m/mysql/i ) {
2532- my $sql;
2533-
2534- $sql = 'SELECT @@SQL_MODE';
2535- PTDEBUG && _d($dbh, $sql);
2536- my ($sql_mode) = $dbh->selectrow_array($sql);
2537-
2538- $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1'
2539- . '/*!40101, @@SQL_MODE=\'NO_AUTO_VALUE_ON_ZERO'
2540- . ($sql_mode ? ",$sql_mode" : '')
2541- . '\'*/';
2542- PTDEBUG && _d($dbh, $sql);
2543- $dbh->do($sql);
2544-
2545- if ( my ($charset) = $cxn_string =~ m/charset=(\w+)/ ) {
2546- $sql = "/*!40101 SET NAMES $charset*/";
2547- PTDEBUG && _d($dbh, ':', $sql);
2548- $dbh->do($sql);
2549- PTDEBUG && _d('Enabling charset for STDOUT');
2550- if ( $charset eq 'utf8' ) {
2551- binmode(STDOUT, ':utf8')
2552- or die "Can't binmode(STDOUT, ':utf8'): $OS_ERROR";
2553- }
2554- else {
2555- binmode(STDOUT) or die "Can't binmode(STDOUT): $OS_ERROR";
2556- }
2557- }
2558-
2559- if ( $self->prop('set-vars') ) {
2560- $sql = "SET " . $self->prop('set-vars');
2561- PTDEBUG && _d($dbh, ':', $sql);
2562- $dbh->do($sql);
2563- }
2564- }
2565- };
2566+ $dbh = eval { DBI->connect($cxn_string, $user, $pass, $defaults) };
2567+
2568 if ( !$dbh && $EVAL_ERROR ) {
2569- PTDEBUG && _d($EVAL_ERROR);
2570- if ( $EVAL_ERROR =~ m/not a compiled character set|character set utf8/ ) {
2571- PTDEBUG && _d('Going to try again without utf8 support');
2572- delete $defaults->{mysql_enable_utf8};
2573- }
2574- elsif ( $EVAL_ERROR =~ m/locate DBD\/mysql/i ) {
2575+ if ( $EVAL_ERROR =~ m/locate DBD\/mysql/i ) {
2576 die "Cannot connect to MySQL because the Perl DBD::mysql module is "
2577 . "not installed or not found. Run 'perl -MDBD::mysql' to see "
2578 . "the directories that Perl searches for DBD::mysql. If "
2579@@ -1475,19 +2036,70 @@
2580 . " RHEL/CentOS yum install perl-DBD-MySQL\n"
2581 . " OpenSolaris pgk install pkg:/SUNWapu13dbd-mysql\n";
2582 }
2583+ elsif ( $EVAL_ERROR =~ m/not a compiled character set|character set utf8/ ) {
2584+ PTDEBUG && _d('Going to try again without utf8 support');
2585+ delete $defaults->{mysql_enable_utf8};
2586+ }
2587 if ( !$tries ) {
2588 die $EVAL_ERROR;
2589 }
2590 }
2591 }
2592
2593+ if ( $cxn_string =~ m/mysql/i ) {
2594+ my $sql;
2595+
2596+ $sql = 'SELECT @@SQL_MODE';
2597+ PTDEBUG && _d($dbh, $sql);
2598+ my ($sql_mode) = eval { $dbh->selectrow_array($sql) };
2599+ if ( $EVAL_ERROR ) {
2600+ die $EVAL_ERROR;
2601+ }
2602+
2603+ $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1'
2604+ . '/*!40101, @@SQL_MODE=\'NO_AUTO_VALUE_ON_ZERO'
2605+ . ($sql_mode ? ",$sql_mode" : '')
2606+ . '\'*/';
2607+ PTDEBUG && _d($dbh, $sql);
2608+ eval { $dbh->do($sql) };
2609+ if ( $EVAL_ERROR ) {
2610+ die $EVAL_ERROR;
2611+ }
2612+
2613+ if ( my ($charset) = $cxn_string =~ m/charset=(\w+)/ ) {
2614+ $sql = "/*!40101 SET NAMES $charset*/";
2615+ PTDEBUG && _d($dbh, ':', $sql);
2616+ eval { $dbh->do($sql) };
2617+ if ( $EVAL_ERROR ) {
2618+ die $EVAL_ERROR;
2619+ }
2620+ PTDEBUG && _d('Enabling charset for STDOUT');
2621+ if ( $charset eq 'utf8' ) {
2622+ binmode(STDOUT, ':utf8')
2623+ or die "Can't binmode(STDOUT, ':utf8'): $OS_ERROR";
2624+ }
2625+ else {
2626+ binmode(STDOUT) or die "Can't binmode(STDOUT): $OS_ERROR";
2627+ }
2628+ }
2629+
2630+ if ( $self->prop('set-vars') ) {
2631+ $sql = "SET " . $self->prop('set-vars');
2632+ PTDEBUG && _d($dbh, ':', $sql);
2633+ eval { $dbh->do($sql) };
2634+ if ( $EVAL_ERROR ) {
2635+ die $EVAL_ERROR;
2636+ }
2637+ }
2638+ }
2639+
2640 PTDEBUG && _d('DBH info: ',
2641 $dbh,
2642 Dumper($dbh->selectrow_hashref(
2643 'SELECT DATABASE(), CONNECTION_ID(), VERSION()/*!50038 , @@hostname*/')),
2644 'Connection info:', $dbh->{mysql_hostinfo},
2645 'Character set info:', Dumper($dbh->selectall_arrayref(
2646- 'SHOW VARIABLES LIKE "character_set%"', { Slice => {}})),
2647+ "SHOW VARIABLES LIKE 'character_set%'", { Slice => {}})),
2648 '$DBD::mysql::VERSION:', $DBD::mysql::VERSION,
2649 '$DBI::VERSION:', $DBI::VERSION,
2650 );
2651@@ -1773,7 +2385,7 @@
2652
2653 # Some common patterns and variables
2654 my $d = qr/(\d+)/; # Digit
2655-my $t = qr/(\d+ \d+)/; # Transaction ID
2656+my $t = qr/((?:\d+ \d+)|(?:[A-Fa-f0-9]+))/; # Transaction ID
2657 my $i = qr/((?:\d{1,3}\.){3}\d+)/; # IP address
2658 my $n = qr/([^`\s]+)/; # MySQL object name
2659 my $w = qr/(\w+)/; # Words
2660@@ -1816,7 +2428,6 @@
2661 @ARGV = @_; # set global ARGV for this package
2662
2663 my $q = new Quoter();
2664- my $vp = new VersionParser();
2665
2666 # ########################################################################
2667 # Get configuration information.
2668@@ -1969,7 +2580,7 @@
2669 $dbh->{AutoCommit} = 0;
2670 my $sql = $o->read_para_after(__FILE__, qr/MAGIC_clear_deadlocks/);
2671
2672- if ( !$vp->version_ge($dbh, '4.1.2') ) {
2673+ if ( VersionParser->new($dbh) < '4.1.2') {
2674 $sql =~ s/ENGINE=/TYPE=/;
2675 }
2676 $sql =~ s/test.deadlock_maker/$db_tbl/;
2677@@ -1987,7 +2598,7 @@
2678 PTDEBUG && _d($sql);
2679 eval { $dbh_child->do($sql); }; # Should block against parent.
2680 PTDEBUG && _d($EVAL_ERROR); # Parent inserted value 0.
2681- $sql = "DROP TABLE $db_tbl";
2682+ $sql = "COMMIT";
2683 PTDEBUG && _d($sql);
2684 $dbh_child->do($sql);
2685 exit;
2686@@ -2001,6 +2612,9 @@
2687 eval { $dbh->do($sql); };
2688 PTDEBUG && _d($EVAL_ERROR);
2689 waitpid($pid, 0);
2690+ $sql = "DROP TABLE $db_tbl";
2691+ PTDEBUG && _d($sql);
2692+ $dbh->do($sql);
2693 }
2694
2695 # If there's an --interval argument, run forever or till specified.
2696@@ -2030,6 +2644,7 @@
2697 while ( my ( $start, $name, $text, $end ) = splice(@matches, 0, 4) ) {
2698 next unless $name eq 'LATEST DETECTED DEADLOCK';
2699 $dl_text = $text;
2700+ last;
2701 }
2702
2703 return {} unless $dl_text;
2704@@ -2748,6 +3363,10 @@
2705
2706 =head1 VERSION
2707
2708+<<<<<<< TREE
2709 pt-deadlock-logger 2.0.5
2710+=======
2711+pt-deadlock-logger 2.1.2
2712+>>>>>>> MERGE-SOURCE
2713
2714 =cut
2715
2716=== modified file 'bin/pt-diskstats'
2717--- bin/pt-diskstats 2012-06-09 21:53:04 +0000
2718+++ bin/pt-diskstats 2012-07-20 22:10:28 +0000
2719@@ -6,7 +6,7 @@
2720
2721 use strict;
2722 use warnings FATAL => 'all';
2723-use constant MKDEBUG => $ENV{MKDEBUG} || 0;
2724+use constant PTDEBUG => $ENV{PTDEBUG} || 0;
2725
2726 # %INC magic to allow us to require/use these even within the big file.
2727 BEGIN {
2728@@ -1058,6 +1058,7 @@
2729
2730 use Time::Local qw(timegm timelocal);
2731 use Digest::MD5 qw(md5_hex);
2732+use B qw();
2733
2734 require Exporter;
2735 our @ISA = qw(Exporter);
2736@@ -1075,6 +1076,7 @@
2737 any_unix_timestamp
2738 make_checksum
2739 crc32
2740+ encode_json
2741 );
2742
2743 our $mysql_ts = qr/(\d\d)(\d\d)(\d\d) +(\d+):(\d+):(\d+)(\.\d+)?/;
2744@@ -1282,6 +1284,96 @@
2745 return $crc ^ 0xFFFFFFFF;
2746 }
2747
2748+my $got_json = eval { require JSON };
2749+sub encode_json {
2750+ return JSON::encode_json(@_) if $got_json;
2751+ my ( $data ) = @_;
2752+ return (object_to_json($data) || '');
2753+}
2754+
2755+
2756+sub object_to_json {
2757+ my ($obj) = @_;
2758+ my $type = ref($obj);
2759+
2760+ if($type eq 'HASH'){
2761+ return hash_to_json($obj);
2762+ }
2763+ elsif($type eq 'ARRAY'){
2764+ return array_to_json($obj);
2765+ }
2766+ else {
2767+ return value_to_json($obj);
2768+ }
2769+}
2770+
2771+sub hash_to_json {
2772+ my ($obj) = @_;
2773+ my @res;
2774+ for my $k ( sort { $a cmp $b } keys %$obj ) {
2775+ push @res, string_to_json( $k )
2776+ . ":"
2777+ . ( object_to_json( $obj->{$k} ) || value_to_json( $obj->{$k} ) );
2778+ }
2779+ return '{' . ( @res ? join( ",", @res ) : '' ) . '}';
2780+}
2781+
2782+sub array_to_json {
2783+ my ($obj) = @_;
2784+ my @res;
2785+
2786+ for my $v (@$obj) {
2787+ push @res, object_to_json($v) || value_to_json($v);
2788+ }
2789+
2790+ return '[' . ( @res ? join( ",", @res ) : '' ) . ']';
2791+}
2792+
2793+sub value_to_json {
2794+ my ($value) = @_;
2795+
2796+ return 'null' if(!defined $value);
2797+
2798+ my $b_obj = B::svref_2object(\$value); # for round trip problem
2799+ my $flags = $b_obj->FLAGS;
2800+ return $value # as is
2801+ if $flags & ( B::SVp_IOK | B::SVp_NOK ) and !( $flags & B::SVp_POK ); # SvTYPE is IV or NV?
2802+
2803+ my $type = ref($value);
2804+
2805+ if( !$type ) {
2806+ return string_to_json($value);
2807+ }
2808+ else {
2809+ return 'null';
2810+ }
2811+
2812+}
2813+
2814+my %esc = (
2815+ "\n" => '\n',
2816+ "\r" => '\r',
2817+ "\t" => '\t',
2818+ "\f" => '\f',
2819+ "\b" => '\b',
2820+ "\"" => '\"',
2821+ "\\" => '\\\\',
2822+ "\'" => '\\\'',
2823+);
2824+
2825+sub string_to_json {
2826+ my ($arg) = @_;
2827+
2828+ $arg =~ s/([\x22\x5c\n\r\t\f\b])/$esc{$1}/g;
2829+ $arg =~ s/\//\\\//g;
2830+ $arg =~ s/([\x00-\x08\x0b\x0e-\x1f])/'\\u00' . unpack('H2', $1)/eg;
2831+
2832+ utf8::upgrade($arg);
2833+ utf8::encode($arg);
2834+
2835+ return '"' . $arg . '"';
2836+}
2837+
2838 sub _d {
2839 my ($package, undef, $line) = caller 0;
2840 @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
2841@@ -1319,9 +1411,10 @@
2842 use warnings;
2843 use strict;
2844 use English qw(-no_match_vars);
2845-use constant MKDEBUG => $ENV{MKDEBUG} || 0;
2846+use constant PTDEBUG => $ENV{PTDEBUG} || 0;
2847
2848 use POSIX qw( :termios_h );
2849+use Fcntl qw( F_SETFL F_GETFL );
2850
2851 use base qw( Exporter );
2852
2853@@ -1344,8 +1437,12 @@
2854 # This primarily comes from the Perl Cookbook, recipe 15.8
2855
2856 {
2857-
2858 my $fd_stdin = fileno(STDIN);
2859+ my $flags;
2860+ unless ( $PerconaTest::DONT_RESTORE_STDIN ) {
2861+ $flags = fcntl(STDIN, F_GETFL, 0)
2862+ or die "can't fcntl F_GETFL: $!";
2863+ }
2864 my $term = POSIX::Termios->new();
2865 $term->getattr($fd_stdin);
2866 my $oterm = $term->getlflag();
2867@@ -1376,6 +1473,10 @@
2868 $term->setlflag($oterm);
2869 $term->setcc( VTIME, 0 );
2870 $term->setattr( $fd_stdin, TCSANOW );
2871+ unless ( $PerconaTest::DONT_RESTORE_STDIN ) {
2872+ fcntl(STDIN, F_SETFL, $flags)
2873+ or die "can't fcntl F_SETFL: $!";
2874+ }
2875 }
2876
2877 END { cooked() }
2878@@ -2480,7 +2581,7 @@
2879 use warnings;
2880 use strict;
2881 use English qw(-no_match_vars);
2882-use constant MKDEBUG => $ENV{MKDEBUG} || 0;
2883+use constant PTDEBUG => $ENV{PTDEBUG} || 0;
2884
2885 use base qw( Diskstats );
2886
2887@@ -2553,7 +2654,7 @@
2888 use warnings;
2889 use strict;
2890 use English qw(-no_match_vars);
2891-use constant MKDEBUG => $ENV{MKDEBUG} || 0;
2892+use constant PTDEBUG => $ENV{PTDEBUG} || 0;
2893
2894 use base qw( Diskstats );
2895
2896@@ -3407,7 +3508,7 @@
2897 use constant PTDEBUG => $ENV{PTDEBUG} || 0;
2898
2899 sub main {
2900- @ARGV = @_; # set global ARGV for this package
2901+ local @ARGV = @_; # set global ARGV for this package
2902
2903 # ########################################################################
2904 # Get configuration information.
2905@@ -4106,6 +4207,10 @@
2906
2907 =head1 VERSION
2908
2909+<<<<<<< TREE
2910 pt-diskstats 2.0.5
2911+=======
2912+pt-diskstats 2.1.2
2913+>>>>>>> MERGE-SOURCE
2914
2915 =cut
2916
2917=== modified file 'bin/pt-duplicate-key-checker'
2918--- bin/pt-duplicate-key-checker 2012-06-09 21:53:04 +0000
2919+++ bin/pt-duplicate-key-checker 2012-07-20 22:10:28 +0000
2920@@ -9,89 +9,6 @@
2921 use constant PTDEBUG => $ENV{PTDEBUG} || 0;
2922
2923 # ###########################################################################
2924-# VersionParser package
2925-# This package is a copy without comments from the original. The original
2926-# with comments and its test file can be found in the Bazaar repository at,
2927-# lib/VersionParser.pm
2928-# t/lib/VersionParser.t
2929-# See https://launchpad.net/percona-toolkit for more information.
2930-# ###########################################################################
2931-{
2932-package VersionParser;
2933-
2934-use strict;
2935-use warnings FATAL => 'all';
2936-use English qw(-no_match_vars);
2937-use constant PTDEBUG => $ENV{PTDEBUG} || 0;
2938-
2939-sub new {
2940- my ( $class ) = @_;
2941- bless {}, $class;
2942-}
2943-
2944-sub parse {
2945- my ( $self, $str ) = @_;
2946- my $result = sprintf('%03d%03d%03d', $str =~ m/(\d+)/g);
2947- PTDEBUG && _d($str, 'parses to', $result);
2948- return $result;
2949-}
2950-
2951-sub version_ge {
2952- my ( $self, $dbh, $target ) = @_;
2953- if ( !$self->{$dbh} ) {
2954- $self->{$dbh} = $self->parse(
2955- $dbh->selectrow_array('SELECT VERSION()'));
2956- }
2957- my $result = $self->{$dbh} ge $self->parse($target) ? 1 : 0;
2958- PTDEBUG && _d($self->{$dbh}, 'ge', $target, ':', $result);
2959- return $result;
2960-}
2961-
2962-sub innodb_version {
2963- my ( $self, $dbh ) = @_;
2964- return unless $dbh;
2965- my $innodb_version = "NO";
2966-
2967- my ($innodb) =
2968- grep { $_->{engine} =~ m/InnoDB/i }
2969- map {
2970- my %hash;
2971- @hash{ map { lc $_ } keys %$_ } = values %$_;
2972- \%hash;
2973- }
2974- @{ $dbh->selectall_arrayref("SHOW ENGINES", {Slice=>{}}) };
2975- if ( $innodb ) {
2976- PTDEBUG && _d("InnoDB support:", $innodb->{support});
2977- if ( $innodb->{support} =~ m/YES|DEFAULT/i ) {
2978- my $vars = $dbh->selectrow_hashref(
2979- "SHOW VARIABLES LIKE 'innodb_version'");
2980- $innodb_version = !$vars ? "BUILTIN"
2981- : ($vars->{Value} || $vars->{value});
2982- }
2983- else {
2984- $innodb_version = $innodb->{support}; # probably DISABLED or NO
2985- }
2986- }
2987-
2988- PTDEBUG && _d("InnoDB version:", $innodb_version);
2989- return $innodb_version;
2990-}
2991-
2992-sub _d {
2993- my ($package, undef, $line) = caller 0;
2994- @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
2995- map { defined $_ ? $_ : 'undef' }
2996- @_;
2997- print STDERR "# $package:$line $PID ", join(' ', @_), "\n";
2998-}
2999-
3000-1;
3001-}
3002-# ###########################################################################
3003-# End VersionParser package
3004-# ###########################################################################
3005-
3006-# ###########################################################################
3007 # Quoter package
3008 # This package is a copy without comments from the original. The original
3009 # with comments and its test file can be found in the Bazaar repository at,
3010@@ -162,6 +79,48 @@
3011 return $db ? "$db.$tbl" : $tbl;
3012 }
3013
3014+sub serialize_list {
3015+ my ( $self, @args ) = @_;
3016+ return unless @args;
3017+
3018+ return $args[0] if @args == 1 && !defined $args[0];
3019+
3020+ die "Cannot serialize multiple values with undef/NULL"
3021+ if grep { !defined $_ } @args;
3022+
3023+ return join ',', map { quotemeta } @args;
3024+}
3025+
3026+sub deserialize_list {
3027+ my ( $self, $string ) = @_;
3028+ return $string unless defined $string;
3029+ my @escaped_parts = $string =~ /
3030+ \G # Start of string, or end of previous match.
3031+ ( # Each of these is an element in the original list.
3032+ [^\\,]* # Anything not a backslash or a comma
3033+ (?: # When we get here, we found one of the above.
3034+ \\. # A backslash followed by something so we can continue
3035+ [^\\,]* # Same as above.
3036+ )* # Repeat zero of more times.
3037+ )
3038+ , # Comma dividing elements
3039+ /sxgc;
3040+
3041+ push @escaped_parts, pos($string) ? substr( $string, pos($string) ) : $string;
3042+
3043+ my @unescaped_parts = map {
3044+ my $part = $_;
3045+
3046+ my $char_class = utf8::is_utf8($part) # If it's a UTF-8 string,
3047+ ? qr/(?=\p{ASCII})\W/ # We only care about non-word
3048+ : qr/(?=\p{ASCII})\W|[\x{80}-\x{FF}]/; # Otherwise,
3049+ $part =~ s/\\($char_class)/$1/g;
3050+ $part;
3051+ } @escaped_parts;
3052+
3053+ return @unescaped_parts;
3054+}
3055+
3056 1;
3057 }
3058 # ###########################################################################
3059@@ -199,23 +158,64 @@
3060 return bless $self, $class;
3061 }
3062
3063+sub get_create_table {
3064+ my ( $self, $dbh, $db, $tbl ) = @_;
3065+ die "I need a dbh parameter" unless $dbh;
3066+ die "I need a db parameter" unless $db;
3067+ die "I need a tbl parameter" unless $tbl;
3068+ my $q = $self->{Quoter};
3069+
3070+ my $new_sql_mode
3071+ = '/*!40101 SET @OLD_SQL_MODE := @@SQL_MODE, '
3072+ . q{@@SQL_MODE := REPLACE(REPLACE(@@SQL_MODE, 'ANSI_QUOTES', ''), ',,', ','), }
3073+ . '@OLD_QUOTE := @@SQL_QUOTE_SHOW_CREATE, '
3074+ . '@@SQL_QUOTE_SHOW_CREATE := 1 */';
3075+
3076+ my $old_sql_mode = '/*!40101 SET @@SQL_MODE := @OLD_SQL_MODE, '
3077+ . '@@SQL_QUOTE_SHOW_CREATE := @OLD_QUOTE */';
3078+
3079+ PTDEBUG && _d($new_sql_mode);
3080+ eval { $dbh->do($new_sql_mode); };
3081+ PTDEBUG && $EVAL_ERROR && _d($EVAL_ERROR);
3082+
3083+ my $use_sql = 'USE ' . $q->quote($db);
3084+ PTDEBUG && _d($dbh, $use_sql);
3085+ $dbh->do($use_sql);
3086+
3087+ my $show_sql = "SHOW CREATE TABLE " . $q->quote($db, $tbl);
3088+ PTDEBUG && _d($show_sql);
3089+ my $href;
3090+ eval { $href = $dbh->selectrow_hashref($show_sql); };
3091+ if ( $EVAL_ERROR ) {
3092+ PTDEBUG && _d($EVAL_ERROR);
3093+
3094+ PTDEBUG && _d($old_sql_mode);
3095+ $dbh->do($old_sql_mode);
3096+
3097+ return;
3098+ }
3099+
3100+ PTDEBUG && _d($old_sql_mode);
3101+ $dbh->do($old_sql_mode);
3102+
3103+ my ($key) = grep { m/create (?:table|view)/i } keys %$href;
3104+ if ( !$key ) {
3105+ die "Error: no 'Create Table' or 'Create View' in result set from "
3106+ . "$show_sql: " . Dumper($href);
3107+ }
3108+
3109+ return $href->{$key};
3110+}
3111+
3112 sub parse {
3113 my ( $self, $ddl, $opts ) = @_;
3114 return unless $ddl;
3115- if ( ref $ddl eq 'ARRAY' ) {
3116- if ( lc $ddl->[0] eq 'table' ) {
3117- $ddl = $ddl->[1];
3118- }
3119- else {
3120- return {
3121- engine => 'VIEW',
3122- };
3123- }
3124+
3125+ if ( $ddl =~ m/CREATE (?:TEMPORARY )?TABLE "/ ) {
3126+ $ddl = $self->ansi_to_legacy($ddl);
3127 }
3128-
3129- if ( $ddl !~ m/CREATE (?:TEMPORARY )?TABLE `/ ) {
3130- die "Cannot parse table definition; is ANSI quoting "
3131- . "enabled or SQL_QUOTE_SHOW_CREATE disabled?";
3132+ elsif ( $ddl !~ m/CREATE (?:TEMPORARY )?TABLE `/ ) {
3133+ die "TableParser doesn't handle CREATE TABLE without quoting.";
3134 }
3135
3136 my ($name) = $ddl =~ m/CREATE (?:TEMPORARY )?TABLE\s+(`.+?`)/;
3137@@ -424,19 +424,13 @@
3138 my $key_ddl = $key;
3139 PTDEBUG && _d('Parsed key:', $key_ddl);
3140
3141- if ( $engine !~ m/MEMORY|HEAP/ ) {
3142+ if ( !$engine || $engine !~ m/MEMORY|HEAP/ ) {
3143 $key =~ s/USING HASH/USING BTREE/;
3144 }
3145
3146 my ( $type, $cols ) = $key =~ m/(?:USING (\w+))? \((.+)\)/;
3147 my ( $special ) = $key =~ m/(FULLTEXT|SPATIAL)/;
3148 $type = $type || $special || 'BTREE';
3149- if ( $opts->{mysql_version} && $opts->{mysql_version} lt '004001000'
3150- && $engine =~ m/HEAP|MEMORY/i )
3151- {
3152- $type = 'HASH'; # MySQL pre-4.1 supports only HASH indexes on HEAP
3153- }
3154-
3155 my ($name) = $key =~ m/(PRIMARY|`[^`]*`)/;
3156 my $unique = $key =~ m/PRIMARY|UNIQUE/ ? 1 : 0;
3157 my @cols;
3158@@ -462,7 +456,7 @@
3159 ddl => $key_ddl,
3160 };
3161
3162- if ( $engine =~ m/InnoDB/i && !$clustered_key ) {
3163+ if ( ($engine || '') =~ m/InnoDB/i && !$clustered_key ) {
3164 my $this_key = $keys->{$name};
3165 if ( $this_key->{name} eq 'PRIMARY' ) {
3166 $clustered_key = 'PRIMARY';
3167@@ -518,41 +512,46 @@
3168 return $ddl;
3169 }
3170
3171-sub remove_secondary_indexes {
3172- my ( $self, $ddl ) = @_;
3173- my $sec_indexes_ddl;
3174- my $tbl_struct = $self->parse($ddl);
3175-
3176- if ( ($tbl_struct->{engine} || '') =~ m/InnoDB/i ) {
3177- my $clustered_key = $tbl_struct->{clustered_key};
3178- $clustered_key ||= '';
3179-
3180- my @sec_indexes = map {
3181- my $key_def = $_->{ddl};
3182- $key_def =~ s/([\(\)])/\\$1/g;
3183- $ddl =~ s/\s+$key_def//i;
3184-
3185- my $key_ddl = "ADD $_->{ddl}";
3186- $key_ddl .= ',' unless $key_ddl =~ m/,$/;
3187- $key_ddl;
3188- }
3189- grep { $_->{name} ne $clustered_key }
3190- values %{$tbl_struct->{keys}};
3191- PTDEBUG && _d('Secondary indexes:', Dumper(\@sec_indexes));
3192-
3193- if ( @sec_indexes ) {
3194- $sec_indexes_ddl = join(' ', @sec_indexes);
3195- $sec_indexes_ddl =~ s/,$//;
3196- }
3197-
3198- $ddl =~ s/,(\n\) )/$1/s;
3199- }
3200- else {
3201- PTDEBUG && _d('Not removing secondary indexes from',
3202- $tbl_struct->{engine}, 'table');
3203- }
3204-
3205- return $ddl, $sec_indexes_ddl, $tbl_struct;
3206+sub get_table_status {
3207+ my ( $self, $dbh, $db, $like ) = @_;
3208+ my $q = $self->{Quoter};
3209+ my $sql = "SHOW TABLE STATUS FROM " . $q->quote($db);
3210+ my @params;
3211+ if ( $like ) {
3212+ $sql .= ' LIKE ?';
3213+ push @params, $like;
3214+ }
3215+ PTDEBUG && _d($sql, @params);
3216+ my $sth = $dbh->prepare($sql);
3217+ eval { $sth->execute(@params); };
3218+ if ($EVAL_ERROR) {
3219+ PTDEBUG && _d($EVAL_ERROR);
3220+ return;
3221+ }
3222+ my @tables = @{$sth->fetchall_arrayref({})};
3223+ @tables = map {
3224+ my %tbl; # Make a copy with lowercased keys
3225+ @tbl{ map { lc $_ } keys %$_ } = values %$_;
3226+ $tbl{engine} ||= $tbl{type} || $tbl{comment};
3227+ delete $tbl{type};
3228+ \%tbl;
3229+ } @tables;
3230+ return @tables;
3231+}
3232+
3233+my $ansi_quote_re = qr/" [^"]* (?: "" [^"]* )* (?<=.) "/ismx;
3234+sub ansi_to_legacy {
3235+ my ($self, $ddl) = @_;
3236+ $ddl =~ s/($ansi_quote_re)/ansi_quote_replace($1)/ge;
3237+ return $ddl;
3238+}
3239+
3240+sub ansi_quote_replace {
3241+ my ($val) = @_;
3242+ $val =~ s/^"|"$//g;
3243+ $val =~ s/`/``/g;
3244+ $val =~ s/""/"/g;
3245+ return "`$val`";
3246 }
3247
3248 sub _d {
3249@@ -570,311 +569,6 @@
3250 # ###########################################################################
3251
3252 # ###########################################################################
3253-# MySQLDump package
3254-# This package is a copy without comments from the original. The original
3255-# with comments and its test file can be found in the Bazaar repository at,
3256-# lib/MySQLDump.pm
3257-# t/lib/MySQLDump.t
3258-# See https://launchpad.net/percona-toolkit for more information.
3259-# ###########################################################################
3260-{
3261-package MySQLDump;
3262-
3263-use strict;
3264-use warnings FATAL => 'all';
3265-use English qw(-no_match_vars);
3266-use constant PTDEBUG => $ENV{PTDEBUG} || 0;
3267-
3268-( our $before = <<'EOF') =~ s/^ //gm;
3269- /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
3270- /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
3271- /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
3272- /*!40101 SET NAMES utf8 */;
3273- /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
3274- /*!40103 SET TIME_ZONE='+00:00' */;
3275- /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
3276- /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
3277- /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
3278- /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
3279-EOF
3280-
3281-( our $after = <<'EOF') =~ s/^ //gm;
3282- /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
3283- /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
3284- /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
3285- /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
3286- /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
3287- /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
3288- /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
3289- /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
3290-EOF
3291-
3292-sub new {
3293- my ( $class, %args ) = @_;
3294- my $self = {
3295- cache => 0, # Afaik no script uses this cache any longer because
3296- };
3297- return bless $self, $class;
3298-}
3299-
3300-sub dump {
3301- my ( $self, $dbh, $quoter, $db, $tbl, $what ) = @_;
3302-
3303- if ( $what eq 'table' ) {
3304- my $ddl = $self->get_create_table($dbh, $quoter, $db, $tbl);
3305- return unless $ddl;
3306- if ( $ddl->[0] eq 'table' ) {
3307- return $before
3308- . 'DROP TABLE IF EXISTS ' . $quoter->quote($tbl) . ";\n"
3309- . $ddl->[1] . ";\n";
3310- }
3311- else {
3312- return 'DROP TABLE IF EXISTS ' . $quoter->quote($tbl) . ";\n"
3313- . '/*!50001 DROP VIEW IF EXISTS '
3314- . $quoter->quote($tbl) . "*/;\n/*!50001 "
3315- . $self->get_tmp_table($dbh, $quoter, $db, $tbl) . "*/;\n";
3316- }
3317- }
3318- elsif ( $what eq 'triggers' ) {
3319- my $trgs = $self->get_triggers($dbh, $quoter, $db, $tbl);
3320- if ( $trgs && @$trgs ) {
3321- my $result = $before . "\nDELIMITER ;;\n";
3322- foreach my $trg ( @$trgs ) {
3323- if ( $trg->{sql_mode} ) {
3324- $result .= qq{/*!50003 SET SESSION SQL_MODE='$trg->{sql_mode}' */;;\n};
3325- }
3326- $result .= "/*!50003 CREATE */ ";
3327- if ( $trg->{definer} ) {
3328- my ( $user, $host )
3329- = map { s/'/''/g; "'$_'"; }
3330- split('@', $trg->{definer}, 2);
3331- $result .= "/*!50017 DEFINER=$user\@$host */ ";
3332- }
3333- $result .= sprintf("/*!50003 TRIGGER %s %s %s ON %s\nFOR EACH ROW %s */;;\n\n",
3334- $quoter->quote($trg->{trigger}),
3335- @{$trg}{qw(timing event)},
3336- $quoter->quote($trg->{table}),
3337- $trg->{statement});
3338- }
3339- $result .= "DELIMITER ;\n\n/*!50003 SET SESSION SQL_MODE=\@OLD_SQL_MODE */;\n\n";
3340- return $result;
3341- }
3342- else {
3343- return undef;
3344- }
3345- }
3346- elsif ( $what eq 'view' ) {
3347- my $ddl = $self->get_create_table($dbh, $quoter, $db, $tbl);
3348- return '/*!50001 DROP TABLE IF EXISTS ' . $quoter->quote($tbl) . "*/;\n"
3349- . '/*!50001 DROP VIEW IF EXISTS ' . $quoter->quote($tbl) . "*/;\n"
3350- . '/*!50001 ' . $ddl->[1] . "*/;\n";
3351- }
3352- else {
3353- die "You didn't say what to dump.";
3354- }
3355-}
3356-
3357-sub _use_db {
3358- my ( $self, $dbh, $quoter, $new ) = @_;
3359- if ( !$new ) {
3360- PTDEBUG && _d('No new DB to use');
3361- return;
3362- }
3363- my $sql = 'USE ' . $quoter->quote($new);
3364- PTDEBUG && _d($dbh, $sql);
3365- $dbh->do($sql);
3366- return;
3367-}
3368-
3369-sub get_create_table {
3370- my ( $self, $dbh, $quoter, $db, $tbl ) = @_;
3371- if ( !$self->{cache} || !$self->{tables}->{$db}->{$tbl} ) {
3372- my $sql = '/*!40101 SET @OLD_SQL_MODE := @@SQL_MODE, '
3373- . q{@@SQL_MODE := REPLACE(REPLACE(@@SQL_MODE, 'ANSI_QUOTES', ''), ',,', ','), }
3374- . '@OLD_QUOTE := @@SQL_QUOTE_SHOW_CREATE, '
3375- . '@@SQL_QUOTE_SHOW_CREATE := 1 */';
3376- PTDEBUG && _d($sql);
3377- eval { $dbh->do($sql); };
3378- PTDEBUG && $EVAL_ERROR && _d($EVAL_ERROR);
3379- $self->_use_db($dbh, $quoter, $db);
3380- $sql = "SHOW CREATE TABLE " . $quoter->quote($db, $tbl);
3381- PTDEBUG && _d($sql);
3382- my $href;
3383- eval { $href = $dbh->selectrow_hashref($sql); };
3384- if ( $EVAL_ERROR ) {
3385- warn "Failed to $sql. The table may be damaged.\nError: $EVAL_ERROR";
3386- return;
3387- }
3388-
3389- $sql = '/*!40101 SET @@SQL_MODE := @OLD_SQL_MODE, '
3390- . '@@SQL_QUOTE_SHOW_CREATE := @OLD_QUOTE */';
3391- PTDEBUG && _d($sql);
3392- $dbh->do($sql);
3393- my ($key) = grep { m/create table/i } keys %$href;
3394- if ( $key ) {
3395- PTDEBUG && _d('This table is a base table');
3396- $self->{tables}->{$db}->{$tbl} = [ 'table', $href->{$key} ];
3397- }
3398- else {
3399- PTDEBUG && _d('This table is a view');
3400- ($key) = grep { m/create view/i } keys %$href;
3401- $self->{tables}->{$db}->{$tbl} = [ 'view', $href->{$key} ];
3402- }
3403- }
3404- return $self->{tables}->{$db}->{$tbl};
3405-}
3406-
3407-sub get_columns {
3408- my ( $self, $dbh, $quoter, $db, $tbl ) = @_;
3409- PTDEBUG && _d('Get columns for', $db, $tbl);
3410- if ( !$self->{cache} || !$self->{columns}->{$db}->{$tbl} ) {
3411- $self->_use_db($dbh, $quoter, $db);
3412- my $sql = "SHOW COLUMNS FROM " . $quoter->quote($db, $tbl);
3413- PTDEBUG && _d($sql);
3414- my $cols = $dbh->selectall_arrayref($sql, { Slice => {} });
3415-
3416- $self->{columns}->{$db}->{$tbl} = [
3417- map {
3418- my %row;
3419- @row{ map { lc $_ } keys %$_ } = values %$_;
3420- \%row;
3421- } @$cols
3422- ];
3423- }
3424- return $self->{columns}->{$db}->{$tbl};
3425-}
3426-
3427-sub get_tmp_table {
3428- my ( $self, $dbh, $quoter, $db, $tbl ) = @_;
3429- my $result = 'CREATE TABLE ' . $quoter->quote($tbl) . " (\n";
3430- $result .= join(",\n",
3431- map { ' ' . $quoter->quote($_->{field}) . ' ' . $_->{type} }
3432- @{$self->get_columns($dbh, $quoter, $db, $tbl)});
3433- $result .= "\n)";
3434- PTDEBUG && _d($result);
3435- return $result;
3436-}
3437-
3438-sub get_triggers {
3439- my ( $self, $dbh, $quoter, $db, $tbl ) = @_;
3440- if ( !$self->{cache} || !$self->{triggers}->{$db} ) {
3441- $self->{triggers}->{$db} = {};
3442- my $sql = '/*!40101 SET @OLD_SQL_MODE := @@SQL_MODE, '
3443- . q{@@SQL_MODE := REPLACE(REPLACE(@@SQL_MODE, 'ANSI_QUOTES', ''), ',,', ','), }
3444- . '@OLD_QUOTE := @@SQL_QUOTE_SHOW_CREATE, '
3445- . '@@SQL_QUOTE_SHOW_CREATE := 1 */';
3446- PTDEBUG && _d($sql);
3447- eval { $dbh->do($sql); };
3448- PTDEBUG && $EVAL_ERROR && _d($EVAL_ERROR);
3449- $sql = "SHOW TRIGGERS FROM " . $quoter->quote($db);
3450- PTDEBUG && _d($sql);
3451- my $sth = $dbh->prepare($sql);
3452- $sth->execute();
3453- if ( $sth->rows ) {
3454- my $trgs = $sth->fetchall_arrayref({});
3455- foreach my $trg (@$trgs) {
3456- my %trg;
3457- @trg{ map { lc $_ } keys %$trg } = values %$trg;
3458- push @{ $self->{triggers}->{$db}->{ $trg{table} } }, \%trg;
3459- }
3460- }
3461- $sql = '/*!40101 SET @@SQL_MODE := @OLD_SQL_MODE, '
3462- . '@@SQL_QUOTE_SHOW_CREATE := @OLD_QUOTE */';
3463- PTDEBUG && _d($sql);
3464- $dbh->do($sql);
3465- }
3466- if ( $tbl ) {
3467- return $self->{triggers}->{$db}->{$tbl};
3468- }
3469- return values %{$self->{triggers}->{$db}};
3470-}
3471-
3472-sub get_databases {
3473- my ( $self, $dbh, $quoter, $like ) = @_;
3474- if ( !$self->{cache} || !$self->{databases} || $like ) {
3475- my $sql = 'SHOW DATABASES';
3476- my @params;
3477- if ( $like ) {
3478- $sql .= ' LIKE ?';
3479- push @params, $like;
3480- }
3481- my $sth = $dbh->prepare($sql);
3482- PTDEBUG && _d($sql, @params);
3483- $sth->execute( @params );
3484- my @dbs = map { $_->[0] } @{$sth->fetchall_arrayref()};
3485- $self->{databases} = \@dbs unless $like;
3486- return @dbs;
3487- }
3488- return @{$self->{databases}};
3489-}
3490-
3491-sub get_table_status {
3492- my ( $self, $dbh, $quoter, $db, $like ) = @_;
3493- if ( !$self->{cache} || !$self->{table_status}->{$db} || $like ) {
3494- my $sql = "SHOW TABLE STATUS FROM " . $quoter->quote($db);
3495- my @params;
3496- if ( $like ) {
3497- $sql .= ' LIKE ?';
3498- push @params, $like;
3499- }
3500- PTDEBUG && _d($sql, @params);
3501- my $sth = $dbh->prepare($sql);
3502- $sth->execute(@params);
3503- my @tables = @{$sth->fetchall_arrayref({})};
3504- @tables = map {
3505- my %tbl; # Make a copy with lowercased keys
3506- @tbl{ map { lc $_ } keys %$_ } = values %$_;
3507- $tbl{engine} ||= $tbl{type} || $tbl{comment};
3508- delete $tbl{type};
3509- \%tbl;
3510- } @tables;
3511- $self->{table_status}->{$db} = \@tables unless $like;
3512- return @tables;
3513- }
3514- return @{$self->{table_status}->{$db}};
3515-}
3516-
3517-sub get_table_list {
3518- my ( $self, $dbh, $quoter, $db, $like ) = @_;
3519- if ( !$self->{cache} || !$self->{table_list}->{$db} || $like ) {
3520- my $sql = "SHOW /*!50002 FULL*/ TABLES FROM " . $quoter->quote($db);
3521- my @params;
3522- if ( $like ) {
3523- $sql .= ' LIKE ?';
3524- push @params, $like;
3525- }
3526- PTDEBUG && _d($sql, @params);
3527- my $sth = $dbh->prepare($sql);
3528- $sth->execute(@params);
3529- my @tables = @{$sth->fetchall_arrayref()};
3530- @tables = map {
3531- my %tbl = (
3532- name => $_->[0],
3533- engine => ($_->[1] || '') eq 'VIEW' ? 'VIEW' : '',
3534- );
3535- \%tbl;
3536- } @tables;
3537- $self->{table_list}->{$db} = \@tables unless $like;
3538- return @tables;
3539- }
3540- return @{$self->{table_list}->{$db}};
3541-}
3542-
3543-sub _d {
3544- my ($package, undef, $line) = caller 0;
3545- @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
3546- map { defined $_ ? $_ : 'undef' }
3547- @_;
3548- print STDERR "# $package:$line $PID ", join(' ', @_), "\n";
3549-}
3550-
3551-1;
3552-}
3553-# ###########################################################################
3554-# End MySQLDump package
3555-# ###########################################################################
3556-
3557-# ###########################################################################
3558 # DSNParser package
3559 # This package is a copy without comments from the original. The original
3560 # with comments and its test file can be found in the Bazaar repository at,
3561@@ -1103,51 +797,10 @@
3562 PTDEBUG && _d($cxn_string, ' ', $user, ' ', $pass,
3563 join(', ', map { "$_=>$defaults->{$_}" } keys %$defaults ));
3564
3565- eval {
3566- $dbh = DBI->connect($cxn_string, $user, $pass, $defaults);
3567-
3568- if ( $cxn_string =~ m/mysql/i ) {
3569- my $sql;
3570-
3571- $sql = 'SELECT @@SQL_MODE';
3572- PTDEBUG && _d($dbh, $sql);
3573- my ($sql_mode) = $dbh->selectrow_array($sql);
3574-
3575- $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1'
3576- . '/*!40101, @@SQL_MODE=\'NO_AUTO_VALUE_ON_ZERO'
3577- . ($sql_mode ? ",$sql_mode" : '')
3578- . '\'*/';
3579- PTDEBUG && _d($dbh, $sql);
3580- $dbh->do($sql);
3581-
3582- if ( my ($charset) = $cxn_string =~ m/charset=(\w+)/ ) {
3583- $sql = "/*!40101 SET NAMES $charset*/";
3584- PTDEBUG && _d($dbh, ':', $sql);
3585- $dbh->do($sql);
3586- PTDEBUG && _d('Enabling charset for STDOUT');
3587- if ( $charset eq 'utf8' ) {
3588- binmode(STDOUT, ':utf8')
3589- or die "Can't binmode(STDOUT, ':utf8'): $OS_ERROR";
3590- }
3591- else {
3592- binmode(STDOUT) or die "Can't binmode(STDOUT): $OS_ERROR";
3593- }
3594- }
3595-
3596- if ( $self->prop('set-vars') ) {
3597- $sql = "SET " . $self->prop('set-vars');
3598- PTDEBUG && _d($dbh, ':', $sql);
3599- $dbh->do($sql);
3600- }
3601- }
3602- };
3603+ $dbh = eval { DBI->connect($cxn_string, $user, $pass, $defaults) };
3604+
3605 if ( !$dbh && $EVAL_ERROR ) {
3606- PTDEBUG && _d($EVAL_ERROR);
3607- if ( $EVAL_ERROR =~ m/not a compiled character set|character set utf8/ ) {
3608- PTDEBUG && _d('Going to try again without utf8 support');
3609- delete $defaults->{mysql_enable_utf8};
3610- }
3611- elsif ( $EVAL_ERROR =~ m/locate DBD\/mysql/i ) {
3612+ if ( $EVAL_ERROR =~ m/locate DBD\/mysql/i ) {
3613 die "Cannot connect to MySQL because the Perl DBD::mysql module is "
3614 . "not installed or not found. Run 'perl -MDBD::mysql' to see "
3615 . "the directories that Perl searches for DBD::mysql. If "
3616@@ -1156,19 +809,70 @@
3617 . " RHEL/CentOS yum install perl-DBD-MySQL\n"
3618 . " OpenSolaris pgk install pkg:/SUNWapu13dbd-mysql\n";
3619 }
3620+ elsif ( $EVAL_ERROR =~ m/not a compiled character set|character set utf8/ ) {
3621+ PTDEBUG && _d('Going to try again without utf8 support');
3622+ delete $defaults->{mysql_enable_utf8};
3623+ }
3624 if ( !$tries ) {
3625 die $EVAL_ERROR;
3626 }
3627 }
3628 }
3629
3630+ if ( $cxn_string =~ m/mysql/i ) {
3631+ my $sql;
3632+
3633+ $sql = 'SELECT @@SQL_MODE';
3634+ PTDEBUG && _d($dbh, $sql);
3635+ my ($sql_mode) = eval { $dbh->selectrow_array($sql) };
3636+ if ( $EVAL_ERROR ) {
3637+ die $EVAL_ERROR;
3638+ }
3639+
3640+ $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1'
3641+ . '/*!40101, @@SQL_MODE=\'NO_AUTO_VALUE_ON_ZERO'
3642+ . ($sql_mode ? ",$sql_mode" : '')
3643+ . '\'*/';
3644+ PTDEBUG && _d($dbh, $sql);
3645+ eval { $dbh->do($sql) };
3646+ if ( $EVAL_ERROR ) {
3647+ die $EVAL_ERROR;
3648+ }
3649+
3650+ if ( my ($charset) = $cxn_string =~ m/charset=(\w+)/ ) {
3651+ $sql = "/*!40101 SET NAMES $charset*/";
3652+ PTDEBUG && _d($dbh, ':', $sql);
3653+ eval { $dbh->do($sql) };
3654+ if ( $EVAL_ERROR ) {
3655+ die $EVAL_ERROR;
3656+ }
3657+ PTDEBUG && _d('Enabling charset for STDOUT');
3658+ if ( $charset eq 'utf8' ) {
3659+ binmode(STDOUT, ':utf8')
3660+ or die "Can't binmode(STDOUT, ':utf8'): $OS_ERROR";
3661+ }
3662+ else {
3663+ binmode(STDOUT) or die "Can't binmode(STDOUT): $OS_ERROR";
3664+ }
3665+ }
3666+
3667+ if ( $self->prop('set-vars') ) {
3668+ $sql = "SET " . $self->prop('set-vars');
3669+ PTDEBUG && _d($dbh, ':', $sql);
3670+ eval { $dbh->do($sql) };
3671+ if ( $EVAL_ERROR ) {
3672+ die $EVAL_ERROR;
3673+ }
3674+ }
3675+ }
3676+
3677 PTDEBUG && _d('DBH info: ',
3678 $dbh,
3679 Dumper($dbh->selectrow_hashref(
3680 'SELECT DATABASE(), CONNECTION_ID(), VERSION()/*!50038 , @@hostname*/')),
3681 'Connection info:', $dbh->{mysql_hostinfo},
3682 'Character set info:', Dumper($dbh->selectall_arrayref(
3683- 'SHOW VARIABLES LIKE "character_set%"', { Slice => {}})),
3684+ "SHOW VARIABLES LIKE 'character_set%'", { Slice => {}})),
3685 '$DBD::mysql::VERSION:', $DBD::mysql::VERSION,
3686 '$DBI::VERSION:', $DBI::VERSION,
3687 );
3688@@ -2186,7 +1890,7 @@
3689 $opt->{value} = ($pre || '') . $num;
3690 }
3691 else {
3692- $self->save_error("Invalid size for --$opt->{long}");
3693+ $self->save_error("Invalid size for --$opt->{long}: $val");
3694 }
3695 return;
3696 }
3697@@ -3054,9 +2758,9 @@
3698 ($col, $tbl, $db) = @args{qw(col tbl db)};
3699 }
3700
3701- $db = lc $db;
3702- $tbl = lc $tbl;
3703- $col = lc $col;
3704+ $db = lc($db || '');
3705+ $tbl = lc($tbl || '');
3706+ $col = lc($col || '');
3707
3708 if ( !$col ) {
3709 PTDEBUG && _d('No column specified or parsed');
3710@@ -3116,8 +2820,8 @@
3711 ($tbl, $db) = @args{qw(tbl db)};
3712 }
3713
3714- $db = lc $db;
3715- $tbl = lc $tbl;
3716+ $db = lc($db || '');
3717+ $tbl = lc($tbl || '');
3718
3719 if ( !$tbl ) {
3720 PTDEBUG && _d('No table specified or parsed');
3721@@ -3200,7 +2904,7 @@
3722
3723 sub new {
3724 my ( $class, %args ) = @_;
3725- my @required_args = qw(OptionParser Quoter);
3726+ my @required_args = qw(OptionParser TableParser Quoter);
3727 foreach my $arg ( @required_args ) {
3728 die "I need a $arg argument" unless $args{$arg};
3729 }
3730@@ -3209,8 +2913,19 @@
3731 die "I need either a dbh or file_itr argument"
3732 if (!$dbh && !$file_itr) || ($dbh && $file_itr);
3733
3734+ my %resume;
3735+ if ( my $table = $args{resume} ) {
3736+ PTDEBUG && _d('Will resume from or after', $table);
3737+ my ($db, $tbl) = $args{Quoter}->split_unquote($table);
3738+ die "Resume table must be database-qualified: $table"
3739+ unless $db && $tbl;
3740+ $resume{db} = $db;
3741+ $resume{tbl} = $tbl;
3742+ }
3743+
3744 my $self = {
3745 %args,
3746+ resume => \%resume,
3747 filters => _make_filters(%args),
3748 };
3749
3750@@ -3271,9 +2986,19 @@
3751 return \%filters;
3752 }
3753
3754-sub next_schema_object {
3755+sub next {
3756 my ( $self ) = @_;
3757
3758+ if ( !$self->{initialized} ) {
3759+ $self->{initialized} = 1;
3760+ if ( $self->{resume}->{tbl}
3761+ && !$self->table_is_allowed(@{$self->{resume}}{qw(db tbl)}) ) {
3762+ PTDEBUG && _d('Will resume after',
3763+ join('.', @{$self->{resume}}{qw(db tbl)}));
3764+ $self->{resume}->{after} = 1;
3765+ }
3766+ }
3767+
3768 my $schema_obj;
3769 if ( $self->{file_itr} ) {
3770 $schema_obj= $self->_iterate_files();
3771@@ -3283,19 +3008,13 @@
3772 }
3773
3774 if ( $schema_obj ) {
3775- if ( $schema_obj->{ddl} && $self->{TableParser} ) {
3776- $schema_obj->{tbl_struct}
3777- = $self->{TableParser}->parse($schema_obj->{ddl});
3778- }
3779-
3780- delete $schema_obj->{ddl} unless $self->{keep_ddl};
3781-
3782 if ( my $schema = $self->{Schema} ) {
3783 $schema->add_schema_object($schema_obj);
3784 }
3785+ PTDEBUG && _d('Next schema object:',
3786+ $schema_obj->{db}, $schema_obj->{tbl});
3787 }
3788
3789- PTDEBUG && _d('Next schema object:', $schema_obj->{db}, $schema_obj->{tbl});
3790 return $schema_obj;
3791 }
3792
3793@@ -3321,7 +3040,8 @@
3794 my $db = $1; # XXX
3795 $db =~ s/^`//; # strip leading `
3796 $db =~ s/`$//; # and trailing `
3797- if ( $self->database_is_allowed($db) ) {
3798+ if ( $self->database_is_allowed($db)
3799+ && $self->_resume_from_database($db) ) {
3800 $self->{db} = $db;
3801 }
3802 }
3803@@ -3334,21 +3054,22 @@
3804 my ($tbl) = $chunk =~ m/$tbl_name/;
3805 $tbl =~ s/^\s*`//;
3806 $tbl =~ s/`\s*$//;
3807- if ( $self->table_is_allowed($self->{db}, $tbl) ) {
3808+ if ( $self->_resume_from_table($tbl)
3809+ && $self->table_is_allowed($self->{db}, $tbl) ) {
3810 my ($ddl) = $chunk =~ m/^(?:$open_comment)?(CREATE TABLE.+?;)$/ms;
3811 if ( !$ddl ) {
3812 warn "Failed to parse CREATE TABLE from\n" . $chunk;
3813 next CHUNK;
3814 }
3815 $ddl =~ s/ \*\/;\Z/;/; # remove end of version comment
3816-
3817- my ($engine) = $ddl =~ m/\).*?(?:ENGINE|TYPE)=(\w+)/;
3818-
3819- if ( !$engine || $self->engine_is_allowed($engine) ) {
3820+ my $tbl_struct = $self->{TableParser}->parse($ddl);
3821+ if ( $self->engine_is_allowed($tbl_struct->{engine}) ) {
3822 return {
3823- db => $self->{db},
3824- tbl => $tbl,
3825- ddl => $ddl,
3826+ db => $self->{db},
3827+ tbl => $tbl,
3828+ name => $self->{Quoter}->quote($self->{db}, $tbl),
3829+ ddl => $ddl,
3830+ tbl_struct => $tbl_struct,
3831 };
3832 }
3833 }
3834@@ -3365,6 +3086,7 @@
3835 sub _iterate_dbh {
3836 my ( $self ) = @_;
3837 my $q = $self->{Quoter};
3838+ my $tp = $self->{TableParser};
3839 my $dbh = $self->{dbh};
3840 PTDEBUG && _d('Getting next schema object from dbh', $dbh);
3841
3842@@ -3378,7 +3100,9 @@
3843 }
3844
3845 if ( !$self->{db} ) {
3846- $self->{db} = shift @{$self->{dbs}};
3847+ do {
3848+ $self->{db} = shift @{$self->{dbs}};
3849+ } until $self->_resume_from_database($self->{db});
3850 PTDEBUG && _d('Next database:', $self->{db});
3851 return unless $self->{db};
3852 }
3853@@ -3391,8 +3115,9 @@
3854 }
3855 grep {
3856 my ($tbl, $type) = @$_;
3857- $self->table_is_allowed($self->{db}, $tbl)
3858- && (!$type || ($type ne 'VIEW'));
3859+ (!$type || ($type ne 'VIEW'))
3860+ && $self->_resume_from_table($tbl)
3861+ && $self->table_is_allowed($self->{db}, $tbl);
3862 }
3863 @{$dbh->selectall_arrayref($sql)};
3864 PTDEBUG && _d('Found', scalar @tbls, 'tables in database', $self->{db});
3865@@ -3400,27 +3125,15 @@
3866 }
3867
3868 while ( my $tbl = shift @{$self->{tbls}} ) {
3869- my $engine;
3870- if ( $self->{filters}->{'engines'}
3871- || $self->{filters}->{'ignore-engines'} ) {
3872- my $sql = "SHOW TABLE STATUS FROM " . $q->quote($self->{db})
3873- . " LIKE \'$tbl\'";
3874- PTDEBUG && _d($sql);
3875- $engine = $dbh->selectrow_hashref($sql)->{engine};
3876- PTDEBUG && _d($tbl, 'uses', $engine, 'engine');
3877- }
3878-
3879-
3880- if ( !$engine || $self->engine_is_allowed($engine) ) {
3881- my $ddl;
3882- if ( my $du = $self->{MySQLDump} ) {
3883- $ddl = $du->get_create_table($dbh, $q, $self->{db}, $tbl)->[1];
3884- }
3885-
3886+ my $ddl = $tp->get_create_table($dbh, $self->{db}, $tbl);
3887+ my $tbl_struct = $tp->parse($ddl);
3888+ if ( $self->engine_is_allowed($tbl_struct->{engine}) ) {
3889 return {
3890- db => $self->{db},
3891- tbl => $tbl,
3892- ddl => $ddl,
3893+ db => $self->{db},
3894+ tbl => $tbl,
3895+ name => $q->quote($self->{db}, $tbl),
3896+ ddl => $ddl,
3897+ tbl_struct => $tbl_struct,
3898 };
3899 }
3900 }
3901@@ -3481,6 +3194,10 @@
3902
3903 my $filter = $self->{filters};
3904
3905+ if ( $db eq 'mysql' && ($tbl eq 'general_log' || $tbl eq 'slow_log') ) {
3906+ return 0;
3907+ }
3908+
3909 if ( $filter->{'ignore-tables'}->{$tbl}
3910 && ($filter->{'ignore-tables'}->{$tbl} eq '*'
3911 || $filter->{'ignore-tables'}->{$tbl} eq $db) ) {
3912@@ -3520,7 +3237,11 @@
3913
3914 sub engine_is_allowed {
3915 my ( $self, $engine ) = @_;
3916- die "I need an engine argument" unless $engine;
3917+
3918+ if ( !$engine ) {
3919+ PTDEBUG && _d('No engine specified; allowing the table');
3920+ return 1;
3921+ }
3922
3923 $engine = lc $engine;
3924
3925@@ -3540,6 +3261,40 @@
3926 return 1;
3927 }
3928
3929+sub _resume_from_database {
3930+ my ($self, $db) = @_;
3931+
3932+ return 1 unless $self->{resume}->{db};
3933+
3934+ if ( $db eq $self->{resume}->{db} ) {
3935+ PTDEBUG && _d('At resume db', $db);
3936+ delete $self->{resume}->{db};
3937+ return 1;
3938+ }
3939+
3940+ return 0;
3941+}
3942+
3943+sub _resume_from_table {
3944+ my ($self, $tbl) = @_;
3945+
3946+ return 1 unless $self->{resume}->{tbl};
3947+
3948+ if ( $tbl eq $self->{resume}->{tbl} ) {
3949+ if ( !$self->{resume}->{after} ) {
3950+ PTDEBUG && _d('Resuming from table', $tbl);
3951+ delete $self->{resume}->{tbl};
3952+ return 1;
3953+ }
3954+ else {
3955+ PTDEBUG && _d('Resuming after table', $tbl);
3956+ delete $self->{resume}->{tbl};
3957+ }
3958+ }
3959+
3960+ return 0;
3961+}
3962+
3963 sub _d {
3964 my ($package, undef, $line) = caller 0;
3965 @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
3966@@ -3622,15 +3377,11 @@
3967 my $dbh = $dp->get_dbh($dp->get_cxn_params($dsn),
3968 { AutoCommit => 1, });
3969
3970- my $vp = new VersionParser();
3971- my $version = $vp->parse($dbh->selectrow_array('SELECT VERSION()'));
3972-
3973 # #######################################################################
3974 # Do the main work.
3975 # #######################################################################
3976 my $ks = $o->get('summary') ? new KeySize(q=>$q) : undef;
3977 my $dk = new DuplicateKeyFinder();
3978- my $du = new MySQLDump();
3979
3980 my %tp_opts = (
3981 ignore_type => $o->get('all-structs'),
3982@@ -3646,25 +3397,23 @@
3983 dbh => $dbh,
3984 OptionParser => $o,
3985 Quoter => $q,
3986- MySQLDump => $du,
3987 TableParser => $tp,
3988 Schema => $schema,
3989- keep_ddl => 1,
3990 );
3991 TABLE:
3992- while ( my $tbl = $schema_itr->next_schema_object() ) {
3993- $tbl->{engine} = $tp->get_engine($tbl->{ddl});
3994+ while ( my $tbl = $schema_itr->next() ) {
3995+ $tbl->{engine} = $tbl->{tbl_struct}->{engine};
3996
3997 my ($keys, $clustered_key, $fks);
3998 if ( $get_keys ) {
3999 ($keys, $clustered_key)
4000- = $tp->get_keys($tbl->{ddl}, {version => $version});
4001+ = $tp->get_keys($tbl->{ddl}, {});
4002 }
4003 if ( $get_fks ) {
4004 $fks = $tp->get_fks($tbl->{ddl}, {database => $tbl->{db}});
4005 }
4006
4007- next TABLE unless %$keys || %$fks;
4008+ next TABLE unless ($keys && %$keys) || ($fks && %$fks);
4009
4010 if ( $o->got('verbose') ) {
4011 print_all_keys($keys, $tbl, \%seen_tbl) if $keys;
4012@@ -4279,6 +4028,10 @@
4013
4014 =head1 VERSION
4015
4016+<<<<<<< TREE
4017 pt-duplicate-key-checker 2.0.5
4018+=======
4019+pt-duplicate-key-checker 2.1.2
4020+>>>>>>> MERGE-SOURCE
4021
4022 =cut
4023
4024=== modified file 'bin/pt-fifo-split'
4025--- bin/pt-fifo-split 2012-06-09 21:53:04 +0000
4026+++ bin/pt-fifo-split 2012-07-20 22:10:28 +0000
4027@@ -959,7 +959,7 @@
4028 $opt->{value} = ($pre || '') . $num;
4029 }
4030 else {
4031- $self->save_error("Invalid size for --$opt->{long}");
4032+ $self->save_error("Invalid size for --$opt->{long}: $val");
4033 }
4034 return;
4035 }
4036@@ -1547,6 +1547,10 @@
4037
4038 =head1 VERSION
4039
4040+<<<<<<< TREE
4041 pt-fifo-split 2.0.5
4042+=======
4043+pt-fifo-split 2.1.2
4044+>>>>>>> MERGE-SOURCE
4045
4046 =cut
4047
4048=== modified file 'bin/pt-find'
4049--- bin/pt-find 2012-06-09 21:53:04 +0000
4050+++ bin/pt-find 2012-07-20 22:10:28 +0000
4051@@ -237,51 +237,10 @@
4052 PTDEBUG && _d($cxn_string, ' ', $user, ' ', $pass,
4053 join(', ', map { "$_=>$defaults->{$_}" } keys %$defaults ));
4054
4055- eval {
4056- $dbh = DBI->connect($cxn_string, $user, $pass, $defaults);
4057-
4058- if ( $cxn_string =~ m/mysql/i ) {
4059- my $sql;
4060-
4061- $sql = 'SELECT @@SQL_MODE';
4062- PTDEBUG && _d($dbh, $sql);
4063- my ($sql_mode) = $dbh->selectrow_array($sql);
4064-
4065- $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1'
4066- . '/*!40101, @@SQL_MODE=\'NO_AUTO_VALUE_ON_ZERO'
4067- . ($sql_mode ? ",$sql_mode" : '')
4068- . '\'*/';
4069- PTDEBUG && _d($dbh, $sql);
4070- $dbh->do($sql);
4071-
4072- if ( my ($charset) = $cxn_string =~ m/charset=(\w+)/ ) {
4073- $sql = "/*!40101 SET NAMES $charset*/";
4074- PTDEBUG && _d($dbh, ':', $sql);
4075- $dbh->do($sql);
4076- PTDEBUG && _d('Enabling charset for STDOUT');
4077- if ( $charset eq 'utf8' ) {
4078- binmode(STDOUT, ':utf8')
4079- or die "Can't binmode(STDOUT, ':utf8'): $OS_ERROR";
4080- }
4081- else {
4082- binmode(STDOUT) or die "Can't binmode(STDOUT): $OS_ERROR";
4083- }
4084- }
4085-
4086- if ( $self->prop('set-vars') ) {
4087- $sql = "SET " . $self->prop('set-vars');
4088- PTDEBUG && _d($dbh, ':', $sql);
4089- $dbh->do($sql);
4090- }
4091- }
4092- };
4093+ $dbh = eval { DBI->connect($cxn_string, $user, $pass, $defaults) };
4094+
4095 if ( !$dbh && $EVAL_ERROR ) {
4096- PTDEBUG && _d($EVAL_ERROR);
4097- if ( $EVAL_ERROR =~ m/not a compiled character set|character set utf8/ ) {
4098- PTDEBUG && _d('Going to try again without utf8 support');
4099- delete $defaults->{mysql_enable_utf8};
4100- }
4101- elsif ( $EVAL_ERROR =~ m/locate DBD\/mysql/i ) {
4102+ if ( $EVAL_ERROR =~ m/locate DBD\/mysql/i ) {
4103 die "Cannot connect to MySQL because the Perl DBD::mysql module is "
4104 . "not installed or not found. Run 'perl -MDBD::mysql' to see "
4105 . "the directories that Perl searches for DBD::mysql. If "
4106@@ -290,19 +249,70 @@
4107 . " RHEL/CentOS yum install perl-DBD-MySQL\n"
4108 . " OpenSolaris pgk install pkg:/SUNWapu13dbd-mysql\n";
4109 }
4110+ elsif ( $EVAL_ERROR =~ m/not a compiled character set|character set utf8/ ) {
4111+ PTDEBUG && _d('Going to try again without utf8 support');
4112+ delete $defaults->{mysql_enable_utf8};
4113+ }
4114 if ( !$tries ) {
4115 die $EVAL_ERROR;
4116 }
4117 }
4118 }
4119
4120+ if ( $cxn_string =~ m/mysql/i ) {
4121+ my $sql;
4122+
4123+ $sql = 'SELECT @@SQL_MODE';
4124+ PTDEBUG && _d($dbh, $sql);
4125+ my ($sql_mode) = eval { $dbh->selectrow_array($sql) };
4126+ if ( $EVAL_ERROR ) {
4127+ die $EVAL_ERROR;
4128+ }
4129+
4130+ $sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1'
4131+ . '/*!40101, @@SQL_MODE=\'NO_AUTO_VALUE_ON_ZERO'
4132+ . ($sql_mode ? ",$sql_mode" : '')
4133+ . '\'*/';
4134+ PTDEBUG && _d($dbh, $sql);
4135+ eval { $dbh->do($sql) };
4136+ if ( $EVAL_ERROR ) {
4137+ die $EVAL_ERROR;
4138+ }
4139+
4140+ if ( my ($charset) = $cxn_string =~ m/charset=(\w+)/ ) {
4141+ $sql = "/*!40101 SET NAMES $charset*/";
4142+ PTDEBUG && _d($dbh, ':', $sql);
4143+ eval { $dbh->do($sql) };
4144+ if ( $EVAL_ERROR ) {
4145+ die $EVAL_ERROR;
4146+ }
4147+ PTDEBUG && _d('Enabling charset for STDOUT');
4148+ if ( $charset eq 'utf8' ) {
4149+ binmode(STDOUT, ':utf8')
4150+ or die "Can't binmode(STDOUT, ':utf8'): $OS_ERROR";
4151+ }
4152+ else {
4153+ binmode(STDOUT) or die "Can't binmode(STDOUT): $OS_ERROR";
4154+ }
4155+ }
4156+
4157+ if ( $self->prop('set-vars') ) {
4158+ $sql = "SET " . $self->prop('set-vars');
4159+ PTDEBUG && _d($dbh, ':', $sql);
4160+ eval { $dbh->do($sql) };
4161+ if ( $EVAL_ERROR ) {
4162+ die $EVAL_ERROR;
4163+ }
4164+ }
4165+ }
4166+
4167 PTDEBUG && _d('DBH info: ',
4168 $dbh,
4169 Dumper($dbh->selectrow_hashref(
4170 'SELECT DATABASE(), CONNECTION_ID(), VERSION()/*!50038 , @@hostname*/')),
4171 'Connection info:', $dbh->{mysql_hostinfo},
4172 'Character set info:', Dumper($dbh->selectall_arrayref(
4173- 'SHOW VARIABLES LIKE "character_set%"', { Slice => {}})),
4174+ "SHOW VARIABLES LIKE 'character_set%'", { Slice => {}})),
4175 '$DBD::mysql::VERSION:', $DBD::mysql::VERSION,
4176 '$DBI::VERSION:', $DBI::VERSION,
4177 );
4178@@ -1320,7 +1330,7 @@
4179 $opt->{value} = ($pre || '') . $num;
4180 }
4181 else {
4182- $self->save_error("Invalid size for --$opt->{long}");
4183+ $self->save_error("Invalid size for --$opt->{long}: $val");
4184 }
4185 return;
4186 }
4187@@ -1465,6 +1475,48 @@
4188 return $db ? "$db.$tbl" : $tbl;
4189 }
4190
4191+sub serialize_list {
4192+ my ( $self, @args ) = @_;
4193+ return unless @args;
4194+
4195+ return $args[0] if @args == 1 && !defined $args[0];
4196+
4197+ die "Cannot serialize multiple values with undef/NULL"
4198+ if grep { !defined $_ } @args;
4199+
4200+ return join ',', map { quotemeta } @args;
4201+}
4202+
4203+sub deserialize_list {
4204+ my ( $self, $string ) = @_;
4205+ return $string unless defined $string;
4206+ my @escaped_parts = $string =~ /
4207+ \G # Start of string, or end of previous match.
4208+ ( # Each of these is an element in the original list.
4209+ [^\\,]* # Anything not a backslash or a comma
4210+ (?: # When we get here, we found one of the above.
4211+ \\. # A backslash followed by something so we can continue
4212+ [^\\,]* # Same as above.
4213+ )* # Repeat zero of more times.
4214+ )
4215+ , # Comma dividing elements
4216+ /sxgc;
4217+
4218+ push @escaped_parts, pos($string) ? substr( $string, pos($string) ) : $string;
4219+
4220+ my @unescaped_parts = map {
4221+ my $part = $_;
4222+
4223+ my $char_class = utf8::is_utf8($part) # If it's a UTF-8 string,
4224+ ? qr/(?=\p{ASCII})\W/ # We only care about non-word
4225+ : qr/(?=\p{ASCII})\W|[\x{80}-\x{FF}]/; # Otherwise,
4226+ $part =~ s/\\($char_class)/$1/g;
4227+ $part;
4228+ } @escaped_parts;
4229+
4230+ return @unescaped_parts;
4231+}
4232+
4233 1;
4234 }
4235 # ###########################################################################
4236@@ -1472,89 +1524,6 @@
4237 # ###########################################################################
4238
4239 # ###########################################################################
4240-# VersionParser package
4241-# This package is a copy without comments from the original. The original
4242-# with comments and its test file can be found in the Bazaar repository at,
4243-# lib/VersionParser.pm
4244-# t/lib/VersionParser.t
4245-# See https://launchpad.net/percona-toolkit for more information.
4246-# ###########################################################################
4247-{
4248-package VersionParser;
4249-
4250-use strict;
4251-use warnings FATAL => 'all';
4252-use English qw(-no_match_vars);
4253-use constant PTDEBUG => $ENV{PTDEBUG} || 0;
4254-
4255-sub new {
4256- my ( $class ) = @_;
4257- bless {}, $class;
4258-}
4259-
4260-sub parse {
4261- my ( $self, $str ) = @_;
4262- my $result = sprintf('%03d%03d%03d', $str =~ m/(\d+)/g);
4263- PTDEBUG && _d($str, 'parses to', $result);
4264- return $result;
4265-}
4266-
4267-sub version_ge {
4268- my ( $self, $dbh, $target ) = @_;
4269- if ( !$self->{$dbh} ) {
4270- $self->{$dbh} = $self->parse(
4271- $dbh->selectrow_array('SELECT VERSION()'));
4272- }
4273- my $result = $self->{$dbh} ge $self->parse($target) ? 1 : 0;
4274- PTDEBUG && _d($self->{$dbh}, 'ge', $target, ':', $result);
4275- return $result;
4276-}
4277-
4278-sub innodb_version {
4279- my ( $self, $dbh ) = @_;
4280- return unless $dbh;
4281- my $innodb_version = "NO";
4282-
4283- my ($innodb) =
4284- grep { $_->{engine} =~ m/InnoDB/i }
4285- map {
4286- my %hash;
4287- @hash{ map { lc $_ } keys %$_ } = values %$_;
4288- \%hash;
4289- }
4290- @{ $dbh->selectall_arrayref("SHOW ENGINES", {Slice=>{}}) };
4291- if ( $innodb ) {
4292- PTDEBUG && _d("InnoDB support:", $innodb->{support});
4293- if ( $innodb->{support} =~ m/YES|DEFAULT/i ) {
4294- my $vars = $dbh->selectrow_hashref(
4295- "SHOW VARIABLES LIKE 'innodb_version'");
4296- $innodb_version = !$vars ? "BUILTIN"
4297- : ($vars->{Value} || $vars->{value});
4298- }
4299- else {
4300- $innodb_version = $innodb->{support}; # probably DISABLED or NO
4301- }
4302- }
4303-
4304- PTDEBUG && _d("InnoDB version:", $innodb_version);
4305- return $innodb_version;
4306-}
4307-
4308-sub _d {
4309- my ($package, undef, $line) = caller 0;
4310- @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
4311- map { defined $_ ? $_ : 'undef' }
4312- @_;
4313- print STDERR "# $package:$line $PID ", join(' ', @_), "\n";
4314-}
4315-
4316-1;
4317-}
4318-# ###########################################################################
4319-# End VersionParser package
4320-# ###########################################################################
4321-
4322-# ###########################################################################
4323 # TableParser package
4324 # This package is a copy without comments from the original. The original
4325 # with comments and its test file can be found in the Bazaar repository at,
4326@@ -1585,23 +1554,64 @@
4327 return bless $self, $class;
4328 }
4329
4330+sub get_create_table {
4331+ my ( $self, $dbh, $db, $tbl ) = @_;
4332+ die "I need a dbh parameter" unless $dbh;
4333+ die "I need a db parameter" unless $db;
4334+ die "I need a tbl parameter" unless $tbl;
4335+ my $q = $self->{Quoter};
4336+
4337+ my $new_sql_mode
4338+ = '/*!40101 SET @OLD_SQL_MODE := @@SQL_MODE, '
4339+ . q{@@SQL_MODE := REPLACE(REPLACE(@@SQL_MODE, 'ANSI_QUOTES', ''), ',,', ','), }
4340+ . '@OLD_QUOTE := @@SQL_QUOTE_SHOW_CREATE, '
4341+ . '@@SQL_QUOTE_SHOW_CREATE := 1 */';
4342+
4343+ my $old_sql_mode = '/*!40101 SET @@SQL_MODE := @OLD_SQL_MODE, '
4344+ . '@@SQL_QUOTE_SHOW_CREATE := @OLD_QUOTE */';
4345+
4346+ PTDEBUG && _d($new_sql_mode);
4347+ eval { $dbh->do($new_sql_mode); };
4348+ PTDEBUG && $EVAL_ERROR && _d($EVAL_ERROR);
4349+
4350+ my $use_sql = 'USE ' . $q->quote($db);
4351+ PTDEBUG && _d($dbh, $use_sql);
4352+ $dbh->do($use_sql);
4353+
4354+ my $show_sql = "SHOW CREATE TABLE " . $q->quote($db, $tbl);
4355+ PTDEBUG && _d($show_sql);
4356+ my $href;
4357+ eval { $href = $dbh->selectrow_hashref($show_sql); };
4358+ if ( $EVAL_ERROR ) {
4359+ PTDEBUG && _d($EVAL_ERROR);
4360+
4361+ PTDEBUG && _d($old_sql_mode);
4362+ $dbh->do($old_sql_mode);
4363+
4364+ return;
4365+ }
4366+
4367+ PTDEBUG && _d($old_sql_mode);
4368+ $dbh->do($old_sql_mode);
4369+
4370+ my ($key) = grep { m/create (?:table|view)/i } keys %$href;
4371+ if ( !$key ) {
4372+ die "Error: no 'Create Table' or 'Create View' in result set from "
4373+ . "$show_sql: " . Dumper($href);
4374+ }
4375+
4376+ return $href->{$key};
4377+}
4378+
4379 sub parse {
4380 my ( $self, $ddl, $opts ) = @_;
4381 return unless $ddl;
4382- if ( ref $ddl eq 'ARRAY' ) {
4383- if ( lc $ddl->[0] eq 'table' ) {
4384- $ddl = $ddl->[1];
4385- }
4386- else {
4387- return {
4388- engine => 'VIEW',
4389- };
4390- }
4391+
4392+ if ( $ddl =~ m/CREATE (?:TEMPORARY )?TABLE "/ ) {
4393+ $ddl = $self->ansi_to_legacy($ddl);
4394 }
4395-
4396- if ( $ddl !~ m/CREATE (?:TEMPORARY )?TABLE `/ ) {
4397- die "Cannot parse table definition; is ANSI quoting "
4398- . "enabled or SQL_QUOTE_SHOW_CREATE disabled?";
4399+ elsif ( $ddl !~ m/CREATE (?:TEMPORARY )?TABLE `/ ) {
4400+ die "TableParser doesn't handle CREATE TABLE without quoting.";
4401 }
4402
4403 my ($name) = $ddl =~ m/CREATE (?:TEMPORARY )?TABLE\s+(`.+?`)/;
4404@@ -1810,19 +1820,13 @@
4405 my $key_ddl = $key;
4406 PTDEBUG && _d('Parsed key:', $key_ddl);
4407
4408- if ( $engine !~ m/MEMORY|HEAP/ ) {
4409+ if ( !$engine || $engine !~ m/MEMORY|HEAP/ ) {
4410 $key =~ s/USING HASH/USING BTREE/;
4411 }
4412
4413 my ( $type, $cols ) = $key =~ m/(?:USING (\w+))? \((.+)\)/;
4414 my ( $special ) = $key =~ m/(FULLTEXT|SPATIAL)/;
4415 $type = $type || $special || 'BTREE';
4416- if ( $opts->{mysql_version} && $opts->{mysql_version} lt '004001000'
4417- && $engine =~ m/HEAP|MEMORY/i )
4418- {
4419- $type = 'HASH'; # MySQL pre-4.1 supports only HASH indexes on HEAP
4420- }
4421-
4422 my ($name) = $key =~ m/(PRIMARY|`[^`]*`)/;
4423 my $unique = $key =~ m/PRIMARY|UNIQUE/ ? 1 : 0;
4424 my @cols;
4425@@ -1848,7 +1852,7 @@
4426 ddl => $key_ddl,
4427 };
4428
4429- if ( $engine =~ m/InnoDB/i && !$clustered_key ) {
4430+ if ( ($engine || '') =~ m/InnoDB/i && !$clustered_key ) {
4431 my $this_key = $keys->{$name};
4432 if ( $this_key->{name} eq 'PRIMARY' ) {
4433 $clustered_key = 'PRIMARY';
4434@@ -1904,41 +1908,46 @@
4435 return $ddl;
4436 }
4437
4438-sub remove_secondary_indexes {
4439- my ( $self, $ddl ) = @_;
4440- my $sec_indexes_ddl;
4441- my $tbl_struct = $self->parse($ddl);
4442-
4443- if ( ($tbl_struct->{engine} || '') =~ m/InnoDB/i ) {
4444- my $clustered_key = $tbl_struct->{clustered_key};
4445- $clustered_key ||= '';
4446-
4447- my @sec_indexes = map {
4448- my $key_def = $_->{ddl};
4449- $key_def =~ s/([\(\)])/\\$1/g;
4450- $ddl =~ s/\s+$key_def//i;
4451-
4452- my $key_ddl = "ADD $_->{ddl}";
4453- $key_ddl .= ',' unless $key_ddl =~ m/,$/;
4454- $key_ddl;
4455- }
4456- grep { $_->{name} ne $clustered_key }
4457- values %{$tbl_struct->{keys}};
4458- PTDEBUG && _d('Secondary indexes:', Dumper(\@sec_indexes));
4459-
4460- if ( @sec_indexes ) {
4461- $sec_indexes_ddl = join(' ', @sec_indexes);
4462- $sec_indexes_ddl =~ s/,$//;
4463- }
4464-
4465- $ddl =~ s/,(\n\) )/$1/s;
4466- }
4467- else {
4468- PTDEBUG && _d('Not removing secondary indexes from',
4469- $tbl_struct->{engine}, 'table');
4470- }
4471-
4472- return $ddl, $sec_indexes_ddl, $tbl_struct;
4473+sub get_table_status {
4474+ my ( $self, $dbh, $db, $like ) = @_;
4475+ my $q = $self->{Quoter};
4476+ my $sql = "SHOW TABLE STATUS FROM " . $q->quote($db);
4477+ my @params;
4478+ if ( $like ) {
4479+ $sql .= ' LIKE ?';
4480+ push @params, $like;
4481+ }
4482+ PTDEBUG && _d($sql, @params);
4483+ my $sth = $dbh->prepare($sql);
4484+ eval { $sth->execute(@params); };
4485+ if ($EVAL_ERROR) {
4486+ PTDEBUG && _d($EVAL_ERROR);
4487+ return;
4488+ }
4489+ my @tables = @{$sth->fetchall_arrayref({})};
4490+ @tables = map {
4491+ my %tbl; # Make a copy with lowercased keys
4492+ @tbl{ map { lc $_ } keys %$_ } = values %$_;
4493+ $tbl{engine} ||= $tbl{type} || $tbl{comment};
4494+ delete $tbl{type};
4495+ \%tbl;
4496+ } @tables;
4497+ return @tables;
4498+}
4499+
4500+my $ansi_quote_re = qr/" [^"]* (?: "" [^"]* )* (?<=.) "/ismx;
4501+sub ansi_to_legacy {
4502+ my ($self, $ddl) = @_;
4503+ $ddl =~ s/($ansi_quote_re)/ansi_quote_replace($1)/ge;
4504+ return $ddl;
4505+}
4506+
4507+sub ansi_quote_replace {
4508+ my ($val) = @_;
4509+ $val =~ s/^"|"$//g;
4510+ $val =~ s/`/``/g;
4511+ $val =~ s/""/"/g;
4512+ return "`$val`";
4513 }
4514
4515 sub _d {
4516@@ -1956,311 +1965,6 @@
4517 # ###########################################################################
4518
4519 # ###########################################################################
4520-# MySQLDump package
4521-# This package is a copy without comments from the original. The original
4522-# with comments and its test file can be found in the Bazaar repository at,
4523-# lib/MySQLDump.pm
4524-# t/lib/MySQLDump.t
4525-# See https://launchpad.net/percona-toolkit for more information.
4526-# ###########################################################################
4527-{
4528-package MySQLDump;
4529-
4530-use strict;
4531-use warnings FATAL => 'all';
4532-use English qw(-no_match_vars);
4533-use constant PTDEBUG => $ENV{PTDEBUG} || 0;
4534-
4535-( our $before = <<'EOF') =~ s/^ //gm;
4536- /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
4537- /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
4538- /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
4539- /*!40101 SET NAMES utf8 */;
4540- /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
4541- /*!40103 SET TIME_ZONE='+00:00' */;
4542- /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
4543- /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
4544- /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
4545- /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
4546-EOF
4547-
4548-( our $after = <<'EOF') =~ s/^ //gm;
4549- /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
4550- /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
4551- /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
4552- /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
4553- /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
4554- /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
4555- /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
4556- /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
4557-EOF
4558-
4559-sub new {
4560- my ( $class, %args ) = @_;
4561- my $self = {
4562- cache => 0, # Afaik no script uses this cache any longer because
4563- };
4564- return bless $self, $class;
4565-}
4566-
4567-sub dump {
4568- my ( $self, $dbh, $quoter, $db, $tbl, $what ) = @_;
4569-
4570- if ( $what eq 'table' ) {
4571- my $ddl = $self->get_create_table($dbh, $quoter, $db, $tbl);
4572- return unless $ddl;
4573- if ( $ddl->[0] eq 'table' ) {
4574- return $before
4575- . 'DROP TABLE IF EXISTS ' . $quoter->quote($tbl) . ";\n"
4576- . $ddl->[1] . ";\n";
4577- }
4578- else {
4579- return 'DROP TABLE IF EXISTS ' . $quoter->quote($tbl) . ";\n"
4580- . '/*!50001 DROP VIEW IF EXISTS '
4581- . $quoter->quote($tbl) . "*/;\n/*!50001 "
4582- . $self->get_tmp_table($dbh, $quoter, $db, $tbl) . "*/;\n";
4583- }
4584- }
4585- elsif ( $what eq 'triggers' ) {
4586- my $trgs = $self->get_triggers($dbh, $quoter, $db, $tbl);
4587- if ( $trgs && @$trgs ) {
4588- my $result = $before . "\nDELIMITER ;;\n";
4589- foreach my $trg ( @$trgs ) {
4590- if ( $trg->{sql_mode} ) {
4591- $result .= qq{/*!50003 SET SESSION SQL_MODE='$trg->{sql_mode}' */;;\n};
4592- }
4593- $result .= "/*!50003 CREATE */ ";
4594- if ( $trg->{definer} ) {
4595- my ( $user, $host )
4596- = map { s/'/''/g; "'$_'"; }
4597- split('@', $trg->{definer}, 2);
4598- $result .= "/*!50017 DEFINER=$user\@$host */ ";
4599- }
4600- $result .= sprintf("/*!50003 TRIGGER %s %s %s ON %s\nFOR EACH ROW %s */;;\n\n",
4601- $quoter->quote($trg->{trigger}),
4602- @{$trg}{qw(timing event)},
4603- $quoter->quote($trg->{table}),
4604- $trg->{statement});
4605- }
4606- $result .= "DELIMITER ;\n\n/*!50003 SET SESSION SQL_MODE=\@OLD_SQL_MODE */;\n\n";
4607- return $result;
4608- }
4609- else {
4610- return undef;
4611- }
4612- }
4613- elsif ( $what eq 'view' ) {
4614- my $ddl = $self->get_create_table($dbh, $quoter, $db, $tbl);
4615- return '/*!50001 DROP TABLE IF EXISTS ' . $quoter->quote($tbl) . "*/;\n"
4616- . '/*!50001 DROP VIEW IF EXISTS ' . $quoter->quote($tbl) . "*/;\n"
4617- . '/*!50001 ' . $ddl->[1] . "*/;\n";
4618- }
4619- else {
4620- die "You didn't say what to dump.";
4621- }
4622-}
4623-
4624-sub _use_db {
4625- my ( $self, $dbh, $quoter, $new ) = @_;
4626- if ( !$new ) {
4627- PTDEBUG && _d('No new DB to use');
4628- return;
4629- }
4630- my $sql = 'USE ' . $quoter->quote($new);
4631- PTDEBUG && _d($dbh, $sql);
4632- $dbh->do($sql);
4633- return;
4634-}
4635-
4636-sub get_create_table {
4637- my ( $self, $dbh, $quoter, $db, $tbl ) = @_;
4638- if ( !$self->{cache} || !$self->{tables}->{$db}->{$tbl} ) {
4639- my $sql = '/*!40101 SET @OLD_SQL_MODE := @@SQL_MODE, '
4640- . q{@@SQL_MODE := REPLACE(REPLACE(@@SQL_MODE, 'ANSI_QUOTES', ''), ',,', ','), }
4641- . '@OLD_QUOTE := @@SQL_QUOTE_SHOW_CREATE, '
4642- . '@@SQL_QUOTE_SHOW_CREATE := 1 */';
4643- PTDEBUG && _d($sql);
4644- eval { $dbh->do($sql); };
4645- PTDEBUG && $EVAL_ERROR && _d($EVAL_ERROR);
4646- $self->_use_db($dbh, $quoter, $db);
4647- $sql = "SHOW CREATE TABLE " . $quoter->quote($db, $tbl);
4648- PTDEBUG && _d($sql);
4649- my $href;
4650- eval { $href = $dbh->selectrow_hashref($sql); };
4651- if ( $EVAL_ERROR ) {
4652- warn "Failed to $sql. The table may be damaged.\nError: $EVAL_ERROR";
4653- return;
4654- }
4655-
4656- $sql = '/*!40101 SET @@SQL_MODE := @OLD_SQL_MODE, '
4657- . '@@SQL_QUOTE_SHOW_CREATE := @OLD_QUOTE */';
4658- PTDEBUG && _d($sql);
4659- $dbh->do($sql);
4660- my ($key) = grep { m/create table/i } keys %$href;
4661- if ( $key ) {
4662- PTDEBUG && _d('This table is a base table');
4663- $self->{tables}->{$db}->{$tbl} = [ 'table', $href->{$key} ];
4664- }
4665- else {
4666- PTDEBUG && _d('This table is a view');
4667- ($key) = grep { m/create view/i } keys %$href;
4668- $self->{tables}->{$db}->{$tbl} = [ 'view', $href->{$key} ];
4669- }
4670- }
4671- return $self->{tables}->{$db}->{$tbl};
4672-}
4673-
4674-sub get_columns {
4675- my ( $self, $dbh, $quoter, $db, $tbl ) = @_;
4676- PTDEBUG && _d('Get columns for', $db, $tbl);
4677- if ( !$self->{cache} || !$self->{columns}->{$db}->{$tbl} ) {
4678- $self->_use_db($dbh, $quoter, $db);
4679- my $sql = "SHOW COLUMNS FROM " . $quoter->quote($db, $tbl);
4680- PTDEBUG && _d($sql);
4681- my $cols = $dbh->selectall_arrayref($sql, { Slice => {} });
4682-
4683- $self->{columns}->{$db}->{$tbl} = [
4684- map {
4685- my %row;
4686- @row{ map { lc $_ } keys %$_ } = values %$_;
4687- \%row;
4688- } @$cols
4689- ];
4690- }
4691- return $self->{columns}->{$db}->{$tbl};
4692-}
4693-
4694-sub get_tmp_table {
4695- my ( $self, $dbh, $quoter, $db, $tbl ) = @_;
4696- my $result = 'CREATE TABLE ' . $quoter->quote($tbl) . " (\n";
4697- $result .= join(",\n",
4698- map { ' ' . $quoter->quote($_->{field}) . ' ' . $_->{type} }
4699- @{$self->get_columns($dbh, $quoter, $db, $tbl)});
4700- $result .= "\n)";
4701- PTDEBUG && _d($result);
4702- return $result;
4703-}
4704-
4705-sub get_triggers {
4706- my ( $self, $dbh, $quoter, $db, $tbl ) = @_;
4707- if ( !$self->{cache} || !$self->{triggers}->{$db} ) {
4708- $self->{triggers}->{$db} = {};
4709- my $sql = '/*!40101 SET @OLD_SQL_MODE := @@SQL_MODE, '
4710- . q{@@SQL_MODE := REPLACE(REPLACE(@@SQL_MODE, 'ANSI_QUOTES', ''), ',,', ','), }
4711- . '@OLD_QUOTE := @@SQL_QUOTE_SHOW_CREATE, '
4712- . '@@SQL_QUOTE_SHOW_CREATE := 1 */';
4713- PTDEBUG && _d($sql);
4714- eval { $dbh->do($sql); };
4715- PTDEBUG && $EVAL_ERROR && _d($EVAL_ERROR);
4716- $sql = "SHOW TRIGGERS FROM " . $quoter->quote($db);
4717- PTDEBUG && _d($sql);
4718- my $sth = $dbh->prepare($sql);
4719- $sth->execute();
4720- if ( $sth->rows ) {
4721- my $trgs = $sth->fetchall_arrayref({});
4722- foreach my $trg (@$trgs) {
4723- my %trg;
4724- @trg{ map { lc $_ } keys %$trg } = values %$trg;
4725- push @{ $self->{triggers}->{$db}->{ $trg{table} } }, \%trg;
4726- }
4727- }
4728- $sql = '/*!40101 SET @@SQL_MODE := @OLD_SQL_MODE, '
4729- . '@@SQL_QUOTE_SHOW_CREATE := @OLD_QUOTE */';
4730- PTDEBUG && _d($sql);
4731- $dbh->do($sql);
4732- }
4733- if ( $tbl ) {
4734- return $self->{triggers}->{$db}->{$tbl};
4735- }
4736- return values %{$self->{triggers}->{$db}};
4737-}
4738-
4739-sub get_databases {
4740- my ( $self, $dbh, $quoter, $like ) = @_;
4741- if ( !$self->{cache} || !$self->{databases} || $like ) {
4742- my $sql = 'SHOW DATABASES';
4743- my @params;
4744- if ( $like ) {
4745- $sql .= ' LIKE ?';
4746- push @params, $like;
4747- }
4748- my $sth = $dbh->prepare($sql);
4749- PTDEBUG && _d($sql, @params);
4750- $sth->execute( @params );
4751- my @dbs = map { $_->[0] } @{$sth->fetchall_arrayref()};
4752- $self->{databases} = \@dbs unless $like;
4753- return @dbs;
4754- }
4755- return @{$self->{databases}};
4756-}
4757-
4758-sub get_table_status {
4759- my ( $self, $dbh, $quoter, $db, $like ) = @_;
4760- if ( !$self->{cache} || !$self->{table_status}->{$db} || $like ) {
4761- my $sql = "SHOW TABLE STATUS FROM " . $quoter->quote($db);
4762- my @params;
4763- if ( $like ) {
4764- $sql .= ' LIKE ?';
4765- push @params, $like;
4766- }
4767- PTDEBUG && _d($sql, @params);
4768- my $sth = $dbh->prepare($sql);
4769- $sth->execute(@params);
4770- my @tables = @{$sth->fetchall_arrayref({})};
4771- @tables = map {
4772- my %tbl; # Make a copy with lowercased keys
4773- @tbl{ map { lc $_ } keys %$_ } = values %$_;
4774- $tbl{engine} ||= $tbl{type} || $tbl{comment};
4775- delete $tbl{type};
4776- \%tbl;
4777- } @tables;
4778- $self->{table_status}->{$db} = \@tables unless $like;
4779- return @tables;
4780- }
4781- return @{$self->{table_status}->{$db}};
4782-}
4783-
4784-sub get_table_list {
4785- my ( $self, $dbh, $quoter, $db, $like ) = @_;
4786- if ( !$self->{cache} || !$self->{table_list}->{$db} || $like ) {
4787- my $sql = "SHOW /*!50002 FULL*/ TABLES FROM " . $quoter->quote($db);
4788- my @params;
4789- if ( $like ) {
4790- $sql .= ' LIKE ?';
4791- push @params, $like;
4792- }
4793- PTDEBUG && _d($sql, @params);
4794- my $sth = $dbh->prepare($sql);
4795- $sth->execute(@params);
4796- my @tables = @{$sth->fetchall_arrayref()};
4797- @tables = map {
4798- my %tbl = (
4799- name => $_->[0],
4800- engine => ($_->[1] || '') eq 'VIEW' ? 'VIEW' : '',
4801- );
4802- \%tbl;
4803- } @tables;
4804- $self->{table_list}->{$db} = \@tables unless $like;
4805- return @tables;
4806- }
4807- return @{$self->{table_list}->{$db}};
4808-}
4809-
4810-sub _d {
4811- my ($package, undef, $line) = caller 0;
4812- @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
4813- map { defined $_ ? $_ : 'undef' }
4814- @_;
4815- print STDERR "# $package:$line $PID ", join(' ', @_), "\n";
4816-}
4817-
4818-1;
4819-}
4820-# ###########################################################################
4821-# End MySQLDump package
4822-# ###########################################################################
4823-
4824-# ###########################################################################
4825 # Daemon package
4826 # This package is a copy without comments from the original. The original
4827 # with comments and its test file can be found in the Bazaar repository at,
4828@@ -2479,7 +2183,6 @@
4829 my $dbh; # This program's $dbh
4830 my $exec_dbh; # The $dbh to use for exec and exec-plus
4831 my $tp;
4832-my $du;
4833
4834 # Functions to call while evaluating tests.
4835 my %test_for = (
4836@@ -2774,7 +2477,6 @@
4837 my $need_table_struct = grep { $o->got($_); } @table_struct_tests;
4838 PTDEBUG && _d('Need table struct:', $need_table_struct);
4839 if ( $need_table_struct ) {
4840- $du = new MySQLDump();
4841 $tp = new TableParser(Quoter => $q);
4842 }
4843
4844@@ -2847,11 +2549,7 @@
4845 ($server_id) = $dbh->selectrow_array('SELECT @@SERVER_ID');
4846
4847 # Discover if we need to get stored code. Need dbh to do this.
4848- my $vp = new VersionParser();
4849- my $need_stored_code = $vp->version_ge($dbh, '5.0.0');
4850- $need_stored_code = grep { $o->got($_); } @stored_code_tests
4851- if $need_stored_code;
4852- PTDEBUG && _d('Need stored code:', $need_stored_code);
4853+ my $need_stored_code = grep { $o->got($_); } @stored_code_tests;
4854
4855 # ########################################################################
4856 # Go do it.
4857@@ -2900,8 +2598,8 @@
4858 if ( $need_table_struct ) {
4859 PTDEBUG && _d('Getting table struct for',
4860 $database, '.', $table->{Name});
4861- my $ddl = $du->get_create_table($dbh,$q, $database, $table->{Name});
4862- if ( $ddl->[0] eq 'table' ) {
4863+ my $ddl = $tp->get_create_table($dbh, $database, $table->{Name});
4864+ if ( $ddl =~ m/CREATE TABLE/ ) {
4865 my $table_struct;
4866 eval { $table_struct = $tp->parse($ddl) };
4867 if ( $EVAL_ERROR ) {
4868@@ -2909,8 +2607,8 @@
4869 }
4870 $table->{struct} = $table_struct;
4871 }
4872- elsif ( $ddl->[0] eq 'view' ) {
4873- $table->{view} = $ddl->[1];
4874+ else {
4875+ $table->{view} = $ddl;
4876 }
4877 }
4878 }
4879@@ -3827,6 +3525,10 @@
4880
4881 =head1 VERSION
4882
4883+<<<<<<< TREE
4884 pt-find 2.0.5
4885+=======
4886+pt-find 2.1.2
4887+>>>>>>> MERGE-SOURCE
4888
4889 =cut
4890
4891=== added file 'bin/pt-fingerprint'
4892--- bin/pt-fingerprint 1970-01-01 00:00:00 +0000
4893+++ bin/pt-fingerprint 2012-07-20 22:10:28 +0000
4894@@ -0,0 +1,2143 @@
4895+#!/usr/bin/env perl
4896+
4897+# This program is part of Percona Toolkit: http://www.percona.com/software/
4898+# See "COPYRIGHT, LICENSE, AND WARRANTY" at the end of this file for legal
4899+# notices and disclaimers.
4900+
4901+use strict;
4902+use warnings FATAL => 'all';
4903+use constant PTDEBUG => $ENV{PTDEBUG} || 0;
4904+
4905+# ###########################################################################
4906+# OptionParser package
4907+# This package is a copy without comments from the original. The original
4908+# with comments and its test file can be found in the Bazaar repository at,
4909+# lib/OptionParser.pm
4910+# t/lib/OptionParser.t
4911+# See https://launchpad.net/percona-toolkit for more information.
4912+# ###########################################################################
4913+{
4914+package OptionParser;
4915+
4916+use strict;
4917+use warnings FATAL => 'all';
4918+use English qw(-no_match_vars);
4919+use constant PTDEBUG => $ENV{PTDEBUG} || 0;
4920+
4921+use List::Util qw(max);
4922+use Getopt::Long;
4923+
4924+my $POD_link_re = '[LC]<"?([^">]+)"?>';
4925+
4926+sub new {
4927+ my ( $class, %args ) = @_;
4928+ my @required_args = qw();
4929+ foreach my $arg ( @required_args ) {
4930+ die "I need a $arg argument" unless $args{$arg};
4931+ }
4932+
4933+ my ($program_name) = $PROGRAM_NAME =~ m/([.A-Za-z-]+)$/;
4934+ $program_name ||= $PROGRAM_NAME;
4935+ my $home = $ENV{HOME} || $ENV{HOMEPATH} || $ENV{USERPROFILE} || '.';
4936+
4937+ my %attributes = (
4938+ 'type' => 1,
4939+ 'short form' => 1,
4940+ 'group' => 1,
4941+ 'default' => 1,
4942+ 'cumulative' => 1,
4943+ 'negatable' => 1,
4944+ );
4945+
4946+ my $self = {
4947+ head1 => 'OPTIONS', # These args are used internally
4948+ skip_rules => 0, # to instantiate another Option-
4949+ item => '--(.*)', # Parser obj that parses the
4950+ attributes => \%attributes, # DSN OPTIONS section. Tools
4951+ parse_attributes => \&_parse_attribs, # don't tinker with these args.
4952+
4953+ %args,
4954+
4955+ strict => 1, # disabled by a special rule
4956+ program_name => $program_name,
4957+ opts => {},
4958+ got_opts => 0,
4959+ short_opts => {},
4960+ defaults => {},
4961+ groups => {},
4962+ allowed_groups => {},
4963+ errors => [],
4964+ rules => [], # desc of rules for --help
4965+ mutex => [], # rule: opts are mutually exclusive
4966+ atleast1 => [], # rule: at least one opt is required
4967+ disables => {}, # rule: opt disables other opts
4968+ defaults_to => {}, # rule: opt defaults to value of other opt
4969+ DSNParser => undef,
4970+ default_files => [
4971+ "/etc/percona-toolkit/percona-toolkit.conf",
4972+ "/etc/percona-toolkit/$program_name.conf",
4973+ "$home/.percona-toolkit.conf",
4974+ "$home/.$program_name.conf",
4975+ ],
4976+ types => {
4977+ string => 's', # standard Getopt type
4978+ int => 'i', # standard Getopt type
4979+ float => 'f', # standard Getopt type
4980+ Hash => 'H', # hash, formed from a comma-separated list
4981+ hash => 'h', # hash as above, but only if a value is given
4982+ Array => 'A', # array, similar to Hash
4983+ array => 'a', # array, similar to hash
4984+ DSN => 'd', # DSN
4985+ size => 'z', # size with kMG suffix (powers of 2^10)
4986+ time => 'm', # time, with an optional suffix of s/h/m/d
4987+ },
4988+ };
4989+
4990+ return bless $self, $class;
4991+}
4992+
4993+sub get_specs {
4994+ my ( $self, $file ) = @_;
4995+ $file ||= $self->{file} || __FILE__;
4996+ my @specs = $self->_pod_to_specs($file);
4997+ $self->_parse_specs(@specs);
4998+
4999+ open my $fh, "<", $file or die "Cannot open $file: $OS_ERROR";
5000+ my $contents = do { local $/ = undef; <$fh> };
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches