├── .codecov.yml ├── .editorconfig ├── .gitattributes ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug-report.md │ └── feature-report.md ├── stale.yml └── workflows │ └── go.yml ├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── CONTRIBUTING.zh.md ├── CONTRIBUTORS.md ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── README.zh.md ├── ast ├── ast.go ├── base.go ├── ddl.go ├── ddl_test.go ├── dml.go ├── dml_test.go ├── expressions.go ├── expressions_test.go ├── flag.go ├── flag_test.go ├── format_test.go ├── functions.go ├── functions_test.go ├── inception.go ├── misc.go ├── misc_test.go ├── stats.go ├── util.go └── util_test.go ├── bin └── pt-online-schema-change ├── build ├── addComponents.js ├── delComponents.js └── findMarkdown.js ├── checklist.md ├── circle.yml ├── cmd ├── benchdb │ ├── README.md │ └── main.go ├── benchfilesort │ ├── README.md │ └── main.go ├── benchkv │ └── main.go ├── benchraw │ └── main.go ├── explaintest │ ├── README.md │ ├── _helper.sh │ ├── config.toml │ ├── main.go │ ├── r │ │ ├── explain.result │ │ ├── explain_complex.result │ │ ├── explain_complex_stats.result │ │ ├── explain_easy.result │ │ ├── explain_easy_stats.result │ │ ├── explain_stats.result │ │ ├── select.result │ │ ├── topn_push_down.result │ │ └── tpch.result │ ├── run-tests.sh │ ├── s │ │ ├── explain_complex_stats_dd.json │ │ ├── explain_complex_stats_dt.json │ │ ├── explain_complex_stats_pp.json │ │ ├── explain_complex_stats_rr.json │ │ ├── explain_complex_stats_st.json │ │ ├── explain_complex_stats_tbl_001.json │ │ ├── explain_complex_stats_tbl_002.json │ │ ├── explain_complex_stats_tbl_003.json │ │ ├── explain_complex_stats_tbl_004.json │ │ ├── explain_complex_stats_tbl_005.json │ │ ├── explain_complex_stats_tbl_006.json │ │ ├── explain_complex_stats_tbl_007.json │ │ ├── explain_complex_stats_tbl_008.json │ │ ├── explain_complex_stats_tbl_009.json │ │ ├── explain_easy_stats_index_prune.json │ │ ├── explain_easy_stats_t1.json │ │ ├── explain_easy_stats_t2.json │ │ ├── explain_easy_stats_t3.json │ │ ├── explain_stats_t.json │ │ └── tpch_stats │ │ │ ├── customer.json │ │ │ ├── lineitem.json │ │ │ ├── nation.json │ │ │ ├── orders.json │ │ │ ├── part.json │ │ │ ├── partsupp.json │ │ │ ├── region.json │ │ │ └── supplier.json │ └── t │ │ ├── explain.test │ │ ├── explain_complex.test │ │ ├── explain_complex_stats.test │ │ ├── explain_easy.test │ │ ├── explain_easy_stats.test │ │ ├── explain_stats.test │ │ ├── select.test │ │ ├── topn_push_down.test │ │ └── tpch.test └── importer │ ├── README.md │ ├── config.go │ ├── config.toml │ ├── data.go │ ├── db.go │ ├── db_test.go │ ├── job.go │ ├── main.go │ ├── parser.go │ ├── rand.go │ ├── stats.go │ └── stats.json ├── code_review_guide.md ├── config ├── config.go ├── config.toml.default ├── config_test.go ├── error_level.go └── generate_levels │ └── main.go ├── ddl ├── callback.go ├── callback_test.go ├── column.go ├── column_change_test.go ├── column_test.go ├── db_change_test.go ├── db_integration_test.go ├── db_test.go ├── ddl.go ├── ddl_api.go ├── ddl_test.go ├── ddl_worker.go ├── ddl_worker_test.go ├── delete_range.go ├── foreign_key.go ├── foreign_key_test.go ├── generated_column.go ├── index.go ├── index_change_test.go ├── mock.go ├── partition.go ├── reorg.go ├── reorg_test.go ├── schema.go ├── schema_test.go ├── session_pool.go ├── stat.go ├── stat_test.go ├── syncer.go ├── table.go ├── table_split_test.go ├── table_test.go └── util │ ├── event.go │ └── util.go ├── distsql ├── distsql.go ├── distsql_test.go ├── request_builder.go ├── request_builder_test.go ├── select_result.go └── stream.go ├── docker-compose.yml ├── docs ├── .vuepress │ ├── components │ │ ├── fonts │ │ │ ├── iconfont.eot │ │ │ ├── iconfont.svg │ │ │ ├── iconfont.ttf │ │ │ └── iconfont.woff │ │ ├── gitalk.vue │ │ └── my-progress.vue │ ├── config.js │ ├── public │ │ └── fonts │ │ │ ├── iconfont.eot │ │ │ ├── iconfont.svg │ │ │ ├── iconfont.ttf │ │ │ └── iconfont.woff │ └── styles │ │ ├── index.styl │ │ └── palette.styl ├── README.md ├── backup.md ├── changelog.md ├── config.md ├── demo.md ├── deploy.sh ├── diff.md ├── ghost.md ├── images │ ├── levels_0.png │ ├── levels_1.png │ ├── levels_2.png │ ├── levels_all.png │ ├── pay.jpeg │ ├── process.png │ ├── processlist.png │ ├── statistic.png │ ├── variables.png │ └── wechat.jpeg ├── install.md ├── kill_stmt.md ├── levels.md ├── options.md ├── osc.md ├── params.md ├── permission.md ├── result.md ├── rules.md ├── safe.md ├── statistics.md ├── support.md ├── trans.md ├── tree.md └── zh │ ├── README.md │ ├── backup.md │ ├── changelog.md │ ├── config.md │ ├── demo.md │ ├── diff.md │ ├── ghost.md │ ├── images │ ├── levels_0.png │ ├── levels_1.png │ ├── levels_2.png │ ├── levels_all.png │ ├── pay.jpeg │ ├── process.png │ ├── processlist.png │ ├── statistic.png │ ├── variables.png │ └── wechat.jpeg │ ├── install.md │ ├── kill_stmt.md │ ├── levels.md │ ├── options.md │ ├── osc.md │ ├── params.md │ ├── permission.md │ ├── result.md │ ├── rules.md │ ├── safe.md │ ├── statistics.md │ ├── support.md │ ├── trans.md │ └── tree.md ├── domain ├── domain.go ├── domain_test.go ├── domainctx.go ├── domainctx_test.go ├── global_vars_cache.go ├── info.go ├── schema_checker.go ├── schema_checker_test.go ├── schema_validator.go ├── topn_slow_query.go └── topn_slow_query_test.go ├── executor ├── adapter.go ├── admin.go ├── admin_test.go ├── aggfuncs │ ├── aggfunc_test.go │ ├── aggfuncs.go │ ├── builder.go │ ├── func_avg.go │ ├── func_avg_test.go │ ├── func_bitfuncs.go │ ├── func_count.go │ ├── func_first_row.go │ ├── func_group_concat.go │ ├── func_max_min.go │ └── func_sum.go ├── aggregate.go ├── aggregate_test.go ├── analyze.go ├── analyze_test.go ├── batch_checker.go ├── builder.go ├── checksum.go ├── compiler.go ├── ddl.go ├── ddl_test.go ├── delete.go ├── distsql.go ├── distsql_test.go ├── errors.go ├── executor.go ├── executor_pkg_test.go ├── executor_test.go ├── explain.go ├── grant.go ├── grant_test.go ├── index_lookup_join.go ├── index_lookup_join_test.go ├── insert.go ├── insert_common.go ├── insert_test.go ├── join.go ├── join_test.go ├── joiner.go ├── load_data.go ├── load_stats.go ├── merge_join.go ├── merge_join_test.go ├── metrics_test.go ├── pkg_test.go ├── point_get.go ├── point_get_test.go ├── prepared.go ├── prepared_test.go ├── projection.go ├── replace.go ├── revoke.go ├── revoke_test.go ├── rowid_test.go ├── set.go ├── set_test.go ├── show.go ├── show_stats.go ├── show_stats_test.go ├── show_test.go ├── simple.go ├── simple_test.go ├── sort.go ├── statement_context_test.go ├── table_reader.go ├── trace.go ├── trace_test.go ├── union_scan.go ├── union_scan_test.go ├── update.go ├── write.go └── write_test.go ├── expression ├── aggregation │ ├── agg_to_pb.go │ ├── agg_to_pb_test.go │ ├── aggregation.go │ ├── aggregation_test.go │ ├── avg.go │ ├── bench_test.go │ ├── bit_and.go │ ├── bit_or.go │ ├── bit_xor.go │ ├── concat.go │ ├── count.go │ ├── descriptor.go │ ├── explain.go │ ├── first_row.go │ ├── max_min.go │ ├── sum.go │ ├── util.go │ └── util_test.go ├── bench_test.go ├── builtin.go ├── builtin_arithmetic.go ├── builtin_arithmetic_test.go ├── builtin_cast.go ├── builtin_cast_test.go ├── builtin_compare.go ├── builtin_compare_test.go ├── builtin_control.go ├── builtin_control_test.go ├── builtin_encryption.go ├── builtin_encryption_test.go ├── builtin_info.go ├── builtin_info_test.go ├── builtin_json.go ├── builtin_json_test.go ├── builtin_like.go ├── builtin_math.go ├── builtin_math_test.go ├── builtin_miscellaneous.go ├── builtin_miscellaneous_test.go ├── builtin_op.go ├── builtin_op_test.go ├── builtin_other.go ├── builtin_other_test.go ├── builtin_string.go ├── builtin_string_test.go ├── builtin_test.go ├── builtin_time.go ├── builtin_time_test.go ├── chunk_executor.go ├── column.go ├── column_test.go ├── constant.go ├── constant_fold.go ├── constant_propagation.go ├── constant_propagation_test.go ├── constant_test.go ├── distsql_builtin.go ├── distsql_builtin_test.go ├── errors.go ├── evaluator.go ├── evaluator_test.go ├── explain.go ├── expr_to_pb.go ├── expr_to_pb_test.go ├── expression.go ├── expression_test.go ├── function_traits.go ├── function_traits_test.go ├── helper.go ├── helper_test.go ├── integration_test.go ├── scalar_function.go ├── scalar_function_test.go ├── schema.go ├── schema_test.go ├── simple_rewriter.go ├── typeinfer_test.go ├── util.go └── util_test.go ├── format ├── format.go └── format_test.go ├── gitcookie.sh ├── go.mod ├── go.mod_wall ├── go.sum ├── hack ├── clean_vendor.sh └── retool-install.sh ├── hooks └── pre-commit ├── infoschema ├── builder.go ├── infoschema.go ├── infoschema_test.go ├── tables.go └── tables_test.go ├── kv ├── buffer_store.go ├── buffer_store_test.go ├── error.go ├── fault_injection.go ├── fault_injection_test.go ├── iter.go ├── key.go ├── key_test.go ├── kv.go ├── mem_buffer_test.go ├── memdb_buffer.go ├── mock.go ├── mock_test.go ├── txn.go ├── txn_test.go ├── union_iter.go ├── union_store.go ├── union_store_test.go ├── utils.go ├── utils_test.go ├── variables.go ├── version.go └── version_test.go ├── meta ├── autoid │ ├── autoid.go │ └── autoid_test.go ├── meta.go └── meta_test.go ├── mkdocs.yml ├── model ├── ddl.go ├── flags.go ├── model.go └── model_test.go ├── mysql ├── charset.go ├── const.go ├── const_test.go ├── errcode.go ├── errname.go ├── error.go ├── error_test.go ├── locale_format.go ├── state.go ├── type.go ├── type_test.go └── util.go ├── owner ├── manager.go └── mock.go ├── package-lock.json ├── package.json ├── parser ├── bench_test.go ├── consistent_test.go ├── goyacc │ ├── format_yacc.go │ └── main.go ├── hintparser.go ├── hintparser.y ├── hintparser_test.go ├── hintparserimpl.go ├── lexer.go ├── lexer_test.go ├── misc.go ├── opcode │ ├── opcode.go │ └── opcode_test.go ├── parser.go ├── parser.y ├── parser_test.go └── yy_parser.go ├── planner ├── cascades │ └── pattern.go ├── core │ ├── cache.go │ ├── cache_test.go │ ├── cacheable_checker.go │ ├── cacheable_checker_test.go │ ├── cbo_test.go │ ├── common_plans.go │ ├── errors.go │ ├── exhaust_physical_plans.go │ ├── explain.go │ ├── expression_rewriter.go │ ├── expression_test.go │ ├── find_best_task.go │ ├── initialize.go │ ├── logical_plan_builder.go │ ├── logical_plan_test.go │ ├── logical_plans.go │ ├── logical_plans_test.go │ ├── optimizer.go │ ├── physical_plan_test.go │ ├── physical_plans.go │ ├── plan.go │ ├── plan_to_pb.go │ ├── plan_to_pb_test.go │ ├── planbuilder.go │ ├── planbuilder_test.go │ ├── point_get_plan.go │ ├── prepare_test.go │ ├── preprocess.go │ ├── preprocess_test.go │ ├── property_cols_prune.go │ ├── resolve_indices.go │ ├── rule_aggregation_elimination.go │ ├── rule_aggregation_push_down.go │ ├── rule_build_key_info.go │ ├── rule_column_pruning.go │ ├── rule_decorrelate.go │ ├── rule_eliminate_projection.go │ ├── rule_join_reorder.go │ ├── rule_max_min_eliminate.go │ ├── rule_partition_processor.go │ ├── rule_predicate_push_down.go │ ├── rule_topn_push_down.go │ ├── stats.go │ ├── stringer.go │ ├── task.go │ ├── trace.go │ └── util.go ├── optimize.go └── property │ ├── physical_property.go │ ├── stats_info.go │ └── task_type.go ├── privilege ├── privilege.go └── privileges │ ├── cache.go │ ├── cache_test.go │ ├── privileges.go │ └── privileges_test.go ├── revive.toml ├── server ├── buffered_read_conn.go ├── column.go ├── conn.go ├── conn_stmt.go ├── conn_stmt_test.go ├── conn_test.go ├── driver.go ├── driver_tidb.go ├── driver_tidb_test.go ├── http_handler.go ├── http_handler_test.go ├── http_status.go ├── packetio.go ├── server.go ├── server_test.go ├── statistics_handler.go ├── statistics_handler_test.go ├── tidb_test.go ├── tokenlimiter.go ├── util.go └── util_test.go ├── session ├── bench_test.go ├── bootstrap.go ├── bootstrap_test.go ├── camel.go ├── common.go ├── conn.go ├── const.go ├── core.go ├── core_test.go ├── errors.go ├── helper.go ├── helper_test.go ├── inception_masking_test.go ├── inception_result.go ├── isolation_test.go ├── osc.go ├── parser.go ├── rewrite.go ├── session.go ├── session_backup.go ├── session_base_test.go ├── session_inception.go ├── session_inception_backup_test.go ├── session_inception_common_test.go ├── session_inception_exec_test.go ├── session_inception_parallel_test.go ├── session_inception_print_test.go ├── session_inception_split_test.go ├── session_inception_test.go ├── session_inception_tran_test.go ├── session_masking.go ├── session_print.go ├── session_test.go ├── socket.go ├── sql_split.go ├── tidb.go ├── tidb_check.go ├── tidb_test.go └── txn.go ├── sessionctx ├── binloginfo │ ├── binloginfo.go │ └── binloginfo_test.go ├── context.go ├── stmtctx │ └── stmtctx.go └── variable │ ├── mock_globalaccessor.go │ ├── session.go │ ├── session_test.go │ ├── statusvar.go │ ├── statusvar_test.go │ ├── sysvar.go │ ├── sysvar_test.go │ ├── tidb_vars.go │ ├── varsutil.go │ └── varsutil_test.go ├── sonar-project.properties ├── statistics ├── bootstrap.go ├── builder.go ├── cmsketch.go ├── cmsketch_test.go ├── ddl.go ├── ddl_test.go ├── dump.go ├── dump_test.go ├── feedback.go ├── feedback_test.go ├── fmsketch.go ├── fmsketch_test.go ├── gc.go ├── gc_test.go ├── handle.go ├── handle_test.go ├── histogram.go ├── sample.go ├── sample_test.go ├── scalar.go ├── scalar_test.go ├── selectivity.go ├── selectivity_test.go ├── statistics_test.go ├── table.go ├── update.go ├── update_list_test.go └── update_test.go ├── store ├── mockoracle │ └── oracle.go ├── mockstore │ ├── mocktikv │ │ ├── aggregate.go │ │ ├── analyze.go │ │ ├── checksum.go │ │ ├── cluster.go │ │ ├── cluster_manipulate.go │ │ ├── cluster_test.go │ │ ├── cop_handler_dag.go │ │ ├── cop_handler_dag_test.go │ │ ├── errors.go │ │ ├── executor.go │ │ ├── mock.go │ │ ├── mock_tikv_test.go │ │ ├── mvcc.go │ │ ├── mvcc_leveldb.go │ │ ├── pd.go │ │ ├── rpc.go │ │ └── topn.go │ ├── tikv.go │ └── tikv_test.go ├── store_test.go └── tikv │ ├── 2pc.go │ ├── 2pc_slow_test.go │ ├── 2pc_test.go │ ├── backoff.go │ ├── client.go │ ├── client_test.go │ ├── coprocessor.go │ ├── coprocessor_test.go │ ├── delete_range.go │ ├── delete_range_test.go │ ├── error.go │ ├── gcworker │ └── gc_worker.go │ ├── interface.go │ ├── isolation_test.go │ ├── kv.go │ ├── latch │ ├── latch.go │ ├── latch_test.go │ ├── scheduler.go │ └── scheduler_test.go │ ├── lock_resolver.go │ ├── lock_test.go │ ├── oracle │ ├── oracle.go │ └── oracles │ │ ├── local.go │ │ ├── local_test.go │ │ └── pd.go │ ├── pd_codec.go │ ├── rawkv.go │ ├── rawkv_test.go │ ├── region_cache.go │ ├── region_cache_test.go │ ├── region_request.go │ ├── region_request_test.go │ ├── safepoint.go │ ├── safepoint_test.go │ ├── scan.go │ ├── scan_mock_test.go │ ├── scan_test.go │ ├── snapshot.go │ ├── snapshot_test.go │ ├── split_region.go │ ├── split_test.go │ ├── store_test.go │ ├── test_util.go │ ├── ticlient_test.go │ ├── tikv_test.go │ ├── tikvrpc │ └── tikvrpc.go │ └── txn.go ├── structure ├── hash.go ├── list.go ├── string.go ├── structure.go ├── structure_test.go └── type.go ├── table ├── column.go ├── column_test.go ├── index.go ├── table.go ├── table_test.go └── tables │ ├── gen_expr.go │ ├── gen_expr_test.go │ ├── index.go │ ├── index_test.go │ ├── partition.go │ ├── tables.go │ └── tables_test.go ├── tablecodec ├── bench_test.go └── tablecodec.go ├── terror ├── terror.go └── terror_test.go ├── tidb-server └── main.go ├── tools.json ├── tools └── check │ ├── check-gogenerate.sh │ ├── check-tidy.sh │ ├── check_parser_replace.sh │ ├── check_testSuite.sh │ ├── errcheck_excludes.txt │ ├── go.mod │ └── revive.toml ├── types ├── binary_literal.go ├── binary_literal_test.go ├── compare.go ├── compare_test.go ├── convert.go ├── convert_test.go ├── datum.go ├── datum_eval.go ├── datum_test.go ├── enum.go ├── enum_test.go ├── errors.go ├── etc.go ├── etc_test.go ├── eval_type.go ├── export_test.go ├── field_type.go ├── field_type_test.go ├── format_test.go ├── fsp.go ├── helper.go ├── helper_test.go ├── json │ ├── binary.go │ ├── binary_functions.go │ ├── binary_test.go │ ├── constants.go │ ├── path_expr.go │ └── path_expr_test.go ├── mydecimal.go ├── mydecimal_test.go ├── mytime.go ├── mytime_test.go ├── overflow.go ├── overflow_test.go ├── set.go ├── set_test.go ├── time.go └── time_test.go ├── util ├── admin │ ├── admin.go │ └── admin_test.go ├── arena │ ├── arena.go │ └── arena_test.go ├── auth │ ├── auth.go │ └── auth_test.go ├── charset │ ├── charset.go │ ├── charset_test.go │ └── encoding_table.go ├── chunk │ ├── chunk.go │ ├── chunk_test.go │ ├── chunk_util.go │ ├── chunk_util_test.go │ ├── codec.go │ ├── codec_test.go │ ├── column.go │ ├── compare.go │ ├── iterator.go │ ├── iterator_test.go │ ├── list.go │ ├── list_test.go │ ├── mutrow.go │ ├── mutrow_test.go │ └── row.go ├── codec │ ├── bench_test.go │ ├── bytes.go │ ├── bytes_test.go │ ├── codec.go │ ├── codec_test.go │ ├── decimal.go │ ├── decimal_test.go │ ├── float.go │ └── number.go ├── encrypt │ ├── aes.go │ ├── aes_test.go │ ├── crypt.go │ └── crypt_test.go ├── execdetails │ ├── execdetails.go │ └── execdetails_test.go ├── filesort │ ├── filesort.go │ └── filesort_test.go ├── format │ ├── format.go │ └── format_test.go ├── hack │ ├── hack.go │ └── hack_test.go ├── israce │ ├── israce.go │ └── norace.go ├── kvcache │ ├── simple_lru.go │ └── simple_lru_test.go ├── kvencoder │ ├── allocator.go │ ├── kv_encoder.go │ └── kv_encoder_test.go ├── logutil │ ├── log.go │ └── log_test.go ├── memory │ ├── action.go │ ├── tracker.go │ └── tracker_test.go ├── misc.go ├── misc_test.go ├── mock │ ├── client.go │ ├── context.go │ ├── mock_test.go │ └── store.go ├── mvmap │ ├── fnv.go │ ├── mvmap.go │ └── mvmap_test.go ├── prefix_helper.go ├── prefix_helper_test.go ├── printer │ ├── printer.go │ └── printer_test.go ├── processinfo.go ├── random.go ├── ranger │ ├── checker.go │ ├── detacher.go │ ├── points.go │ ├── ranger.go │ ├── ranger_test.go │ ├── types.go │ └── types_test.go ├── rowDecoder │ └── decoder.go ├── set │ ├── decimal_set.go │ ├── float64_set.go │ └── string_set.go ├── signal │ ├── signal_posix.go │ └── signal_windows.go ├── sqlexec │ └── restricted_sql_executor.go ├── stringutil │ ├── string_util.go │ └── string_util_test.go ├── testkit │ ├── testkit.go │ └── testkit_test.go ├── testleak │ ├── add-leaktest.sh │ ├── check-leaktest.sh │ ├── fake.go │ └── leaktest.go ├── testutil │ ├── testutil.go │ └── testutil_test.go └── timeutil │ ├── time.go │ └── time_test.go └── yarn.lock /.codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | notify: 3 | require_ci_to_pass: yes 4 | 5 | coverage: 6 | precision: 4 7 | round: down 8 | range: "60...90" 9 | 10 | status: 11 | project: 12 | default: 13 | threshold: 0.2 #Allow the coverage to drop by threshold%, and posting a success status. 14 | patch: 15 | default: 16 | target: 0% # trial operation 17 | changes: no 18 | 19 | parsers: 20 | gcov: 21 | branch_detection: 22 | conditional: yes 23 | loop: yes 24 | method: no 25 | macro: no 26 | 27 | comment: 28 | layout: "header, diff" 29 | behavior: default 30 | require_changes: no 31 | 32 | ignore: 33 | - "LICENSES" 34 | - "*_test.go" 35 | - ".git" 36 | - "*.yml" 37 | - "*.md" 38 | - "cmd/.*" 39 | - "docs/.*" 40 | - "vendor/.*" 41 | - "ddl/failtest/.*" 42 | - "ddl/testutil/.*" 43 | - "executor/seqtest/.*" 44 | - "metrics/.*" 45 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | end_of_line = lf 3 | insert_final_newline = true 4 | charset = utf-8 5 | 6 | # tab_size = 4 spaces 7 | [*.go] 8 | indent_style = tab 9 | indent_size = 4 10 | trim_trailing_whitespace = true 11 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text eol=lf 2 | 3 | *.png binary -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # [hanchuanchuan] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: goinception # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: https://hanchuanchuan.github.io/goInception/support.html 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F41B Bug报告" 3 | about: 不符合预期的或者程序崩溃的问题报告 4 | 5 | --- 6 | 7 | **描述** 8 | 对问题简单清晰的描述 9 | 10 | **重现** 11 | 模拟重现的步骤 12 | 13 | **环境** 14 | - 数据库: [mysql/mariadb] 15 | - 版本: [例如 5.7.21] 16 | 17 | **参数** 18 | 可能与问题相关的设置参数 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F680 功能建议" 3 | about: 建议和想法 4 | 5 | --- 6 | 7 | **描述您想要的功能:** 8 | 9 | 10 | **描述您考虑过的解决/替代方案:** 11 | 12 | 13 | **可参考文档,资料,引用等:** 14 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 14 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | - security 9 | - bug 10 | - enhancement 11 | # Label to use when marking an issue as stale 12 | staleLabel: wontfix 13 | # Comment to post when marking an issue as stale. Set to `false` to disable 14 | markComment: > 15 | 由于此问题没有最近的活动,因此已被自动标记为陈旧。如果没有进一步的活动,会作为不活跃issue关闭。感谢你对本项目的贡献。 16 | This issue has been automatically marked as stale because it has not had 17 | recent activity. It will be closed if no further activity occurs. Thank you 18 | for your contributions. 19 | # Comment to post when closing a stale issue. Set to `false` to disable 20 | closeComment: false 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | /interpreter/interpreter 3 | /interpreter/test 4 | /tidb-server/tidb-server 5 | /tidb-server/debug 6 | coverage.out 7 | .idea/ 8 | *.iml 9 | *.swp 10 | *.log 11 | tags 12 | temp_parser_file 13 | y.output 14 | profile.coverprofile 15 | explain_test 16 | cmd/explaintest/explain-test.out 17 | _tools/ 18 | *.fail.go 19 | site/ 20 | util/logutil/slow_query 21 | test/ 22 | release/ 23 | config/config.toml 24 | tools/bin/ 25 | tools/check/go.sum 26 | node_modules 27 | docs/.vuepress/dist 28 | /goInception 29 | -------------------------------------------------------------------------------- /CONTRIBUTORS.md: -------------------------------------------------------------------------------- 1 | # goInception contributors 2 | 3 | [BigChaoChao](https://github.com/BigChaoChao) 4 | 5 | [Qiong Zhang](https://github.com/nwsuafzq) 6 | -------------------------------------------------------------------------------- /ast/util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package ast 15 | 16 | // IsReadOnly checks whether the input ast is readOnly. 17 | func IsReadOnly(node Node) bool { 18 | switch st := node.(type) { 19 | case *SelectStmt: 20 | if st.LockTp == SelectLockForUpdate { 21 | return false 22 | } 23 | 24 | checker := readOnlyChecker{ 25 | readOnly: true, 26 | } 27 | 28 | node.Accept(&checker) 29 | return checker.readOnly 30 | case *ExplainStmt, *DoStmt: 31 | return true 32 | default: 33 | return false 34 | } 35 | } 36 | 37 | // readOnlyChecker checks whether a query's ast is readonly, if it satisfied 38 | // 1. selectstmt; 39 | // 2. need not to set var; 40 | // it is readonly statement. 41 | type readOnlyChecker struct { 42 | readOnly bool 43 | } 44 | 45 | // Enter implements Visitor interface. 46 | func (checker *readOnlyChecker) Enter(in Node) (out Node, skipChildren bool) { 47 | switch node := in.(type) { 48 | case *VariableExpr: 49 | // like func rewriteVariable(), this stands for SetVar. 50 | if !node.IsSystem && node.Value != nil { 51 | checker.readOnly = false 52 | return in, true 53 | } 54 | } 55 | return in, false 56 | } 57 | 58 | // Leave implements Visitor interface. 59 | func (checker *readOnlyChecker) Leave(in Node) (out Node, ok bool) { 60 | return in, checker.readOnly 61 | } 62 | -------------------------------------------------------------------------------- /build/addComponents.js: -------------------------------------------------------------------------------- 1 | 2 | const fs = require('fs') 3 | const findMarkdown = require('./findMarkdown') 4 | const rootDir = './docs' 5 | 6 | findMarkdown(rootDir, writeComponents) 7 | 8 | function writeComponents(dir) { 9 | fs.appendFile(dir, `\n \n \n `, (err) => { 10 | if (err) throw err 11 | console.log(`add components to ${dir}`) 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /build/delComponents.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const findMarkdown = require('./findMarkdown') 3 | const rootDir = './docs' 4 | 5 | findMarkdown(rootDir,delComponents) 6 | 7 | function delComponents(dir){ 8 | fs.readFile(dir,'utf-8', (err, content) => { 9 | if (err) throw err 10 | 11 | fs.writeFile(dir, content.replace(/\n \n \n /g,''), (err) => { 12 | if (err) throw err 13 | console.log(`del components from ${dir}`) 14 | }) 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /build/findMarkdown.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | 3 | function findMarkdown(dir, callback) { 4 | fs.readdir(dir, function (err, files) { 5 | if (err) throw err 6 | 7 | files.forEach((fileName) => { 8 | // let innerDir = `${dir}/${fileName}` 9 | 10 | // if (fileName.indexOf('.') !== 0) { 11 | // fs.stat(innerDir, function (err, stat) { 12 | 13 | // if (stat.isDirectory()) { 14 | // findMarkdown(innerDir, callback) 15 | // } else { 16 | // callback(innerDir) 17 | // } 18 | // }) 19 | // } 20 | let innerDir = `${dir}/${fileName}`; 21 | if (fileName.indexOf(".") !== 0) { 22 | fs.stat(innerDir, function(err, stat) { 23 | if (stat.isDirectory()) { 24 | findMarkdown(innerDir, callback); 25 | } else { 26 | // 跳过readme文件 27 | if (/\.md$/.test(fileName) && !/README/.test(fileName)) 28 | callback(innerDir); 29 | } 30 | }); 31 | } 32 | 33 | }) 34 | }) 35 | } 36 | 37 | module.exports = findMarkdown 38 | -------------------------------------------------------------------------------- /checklist.md: -------------------------------------------------------------------------------- 1 | # 按照清单以便于PR快速审核通过 2 | 3 | # 单一目的 4 | 确保PR只做一件事,没有别的。 5 | 6 | # 自查 7 | 是否查看过您更改的每一行? 8 | 9 | # 测试 10 | 您是否添加了足够的测试用例来涵盖新功能或错误修复? 11 | *请添加注释来描述您的测试用例* 12 | 13 | # 命名 14 | 函数名称是否与其行为保持一致? 15 | 通过名称推断函数的行为是否容易? 16 | 17 | # 重构 18 | 有没有办法重构代码,使其更具可读性? 19 | 如果重构涉及大量现有代码,请发送另一个PR来执行此操作。 20 | 21 | # 差异大小 22 | 确保差异大小不超过500,如果太大则将其拆分为小PR。 23 | -------------------------------------------------------------------------------- /cmd/benchdb/README.md: -------------------------------------------------------------------------------- 1 | ## BenchDB 2 | 3 | BenchDB is a command line tool to test the performance of TiDB. 4 | 5 | ### Quick Start 6 | 7 | Make sure you have started PD and TiKV, then run: 8 | 9 | ``` 10 | ./benchdb -run="create|truncate|insert:0_10000|update-random:0_10000:100000|select:0_10000:10" 11 | ``` 12 | 13 | 14 | ### Arguments 15 | 16 | #### `run` 17 | The `run` argument defines the workflow of the test. You can define 18 | multiple jobs, separated by `|`. The jobs are executed sequentially. 19 | The `run` argument has the following options: 20 | 21 | * `create` creates a table. Currently it's just a typical simple table, with a few columns. 22 | 23 | * `truncate` truncates the table. 24 | 25 | * `insert:xxx_yyy` inserts rows with ID in `[xxx, yyy)`. 26 | e.g. `insert:0_10000` inserts 10000 rows with ID in range `[0, 9999)`. 27 | 28 | * `update-random:xxx_yyy:zzz` updates a row with a random ID in range `[xxx, yyy)`, for `zzz` times. 29 | e.g. `update-random:100_200:50` updates 50 random rows with ID in range `[100, 200)`. 30 | 31 | * `update-range:xxx_yyy:zzz` update a range of rows with ID in range `[xxx, yyy)`, for `zzz` times. 32 | 33 | * `select:xxx_yyy:zzz` select rows with ID range in `[xxx, yyy)`, for `zzz` times. 34 | 35 | * `gc` does a manually triggered GC, so we can compare the performance before and after GC. 36 | 37 | * `query:xxx:zzz` run a sql query `xxx`, for `zzz` times. 38 | 39 | The output shows the execution time. 40 | 41 | #### `table` 42 | 43 | The name of the table, so we can create many tables for different tests without the need to clean up. 44 | Default is `bench_db`. 45 | 46 | #### `blob` 47 | 48 | The blob column size in bytes, so we can test performance for different row size. 49 | Default is `1000`. 50 | 51 | #### `batch` 52 | 53 | The batch number of statements in a transaction, used for insert and update-random only, to speed up the test workflow. 54 | Default is `100`. 55 | 56 | #### `addr` 57 | 58 | The PD address. Default is `127.0.0.1:2379`. 59 | 60 | ### `L` 61 | 62 | The log level. Default is `warn`. 63 | -------------------------------------------------------------------------------- /cmd/explaintest/_helper.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # set -ueax 3 | # when you want to debug, please uncomment the above line and comment the following line. 4 | set -ea 5 | 6 | OLD_GOPATH=$GOPATH 7 | PINGCAP_PATH="$(dirname $PWD)" 8 | while [ "$(basename $PINGCAP_PATH)" != "hanchuanchuan" ]; do 9 | PINGCAP_PATH="$(dirname $PINGCAP_PATH)" 10 | done 11 | TIDB_VENDOR_PATH=$PINGCAP_PATH/goInception/vendor 12 | 13 | function prepare_env { 14 | export GOPATH=$GOPATH:$TIDB_VENDOR_PATH 15 | } 16 | 17 | function recover_env { 18 | export GOPATH=$OLD_GOPATH 19 | } 20 | 21 | function kill_proc_by_port() { 22 | if [ ! -z $1 ]; then 23 | kill $(lsof -t -i:$1) 24 | else 25 | echo "please specify port number" 26 | fi 27 | } 28 | 29 | set +uea 30 | trap 'set +e; PIDS=$(jobs -p); [ -n "$PIDS" ] && kill -9 $PIDS' EXIT 31 | 32 | -------------------------------------------------------------------------------- /cmd/explaintest/config.toml: -------------------------------------------------------------------------------- 1 | host = "0.0.0.0" 2 | port = 4001 3 | lease = "0" 4 | run-ddl = true 5 | 6 | [log] 7 | level = "error" 8 | 9 | [status] 10 | status-port = 10081 11 | 12 | [performance] 13 | stats-lease = "0" 14 | 15 | 16 | -------------------------------------------------------------------------------- /cmd/explaintest/r/explain.result: -------------------------------------------------------------------------------- 1 | drop table if exists t; 2 | create table t (id int, c1 timestamp); 3 | show columns from t; 4 | Field Type Null Key Default Extra 5 | id int(11) YES NULL 6 | c1 timestamp YES NULL 7 | explain t; 8 | Field Type Null Key Default Extra 9 | id int(11) YES NULL 10 | c1 timestamp YES NULL 11 | describe t; 12 | Field Type Null Key Default Extra 13 | id int(11) YES NULL 14 | c1 timestamp YES NULL 15 | desc t; 16 | Field Type Null Key Default Extra 17 | id int(11) YES NULL 18 | c1 timestamp YES NULL 19 | desc t c1; 20 | Field Type Null Key Default Extra 21 | c1 timestamp YES NULL 22 | desc t id; 23 | Field Type Null Key Default Extra 24 | id int(11) YES NULL 25 | -------------------------------------------------------------------------------- /cmd/explaintest/r/explain_stats.result: -------------------------------------------------------------------------------- 1 | drop table if exists t; 2 | create table t (id int, c1 timestamp); 3 | load stats 's/explain_stats_t.json'; 4 | show columns from t; 5 | Field Type Null Key Default Extra 6 | id int(11) YES NULL 7 | c1 timestamp YES NULL 8 | explain t; 9 | Field Type Null Key Default Extra 10 | id int(11) YES NULL 11 | c1 timestamp YES NULL 12 | describe t; 13 | Field Type Null Key Default Extra 14 | id int(11) YES NULL 15 | c1 timestamp YES NULL 16 | desc t; 17 | Field Type Null Key Default Extra 18 | id int(11) YES NULL 19 | c1 timestamp YES NULL 20 | desc t c1; 21 | Field Type Null Key Default Extra 22 | c1 timestamp YES NULL 23 | desc t id; 24 | Field Type Null Key Default Extra 25 | id int(11) YES NULL 26 | -------------------------------------------------------------------------------- /cmd/explaintest/t/explain.test: -------------------------------------------------------------------------------- 1 | drop table if exists t; 2 | create table t (id int, c1 timestamp); 3 | show columns from t; 4 | explain t; 5 | describe t; 6 | desc t; 7 | desc t c1; 8 | desc t id; 9 | -------------------------------------------------------------------------------- /cmd/explaintest/t/explain_stats.test: -------------------------------------------------------------------------------- 1 | drop table if exists t; 2 | create table t (id int, c1 timestamp); 3 | load stats 's/explain_stats_t.json'; 4 | show columns from t; 5 | explain t; 6 | describe t; 7 | desc t; 8 | desc t c1; 9 | desc t id; 10 | -------------------------------------------------------------------------------- /cmd/importer/config.toml: -------------------------------------------------------------------------------- 1 | # Importer Configuration. 2 | 3 | [ddl] 4 | table-sql = "create table t(a int primary key, b double, c varchar(10), d date unique, e time unique, f timestamp unique, g date unique, h datetime unique, i year);" 5 | 6 | index-sql = "create unique index u_b on t(b);" 7 | 8 | [stats] 9 | stats-file-path = "./stats.json" 10 | 11 | [sys] 12 | log-level = "info" 13 | 14 | worker-count = 2 15 | job-count = 10000 16 | # batch insert rows 17 | batch = 1000 18 | 19 | [db] 20 | host = "127.0.0.1" 21 | user = "root" 22 | password = "" 23 | name = "test" 24 | port = 4000 25 | -------------------------------------------------------------------------------- /cmd/importer/db_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package main 15 | 16 | import ( 17 | "testing" 18 | ) 19 | 20 | func TestIntToDecimalString(t *testing.T) { 21 | tests := []struct { 22 | intValue int64 23 | decimal int 24 | expect string 25 | }{ 26 | {100, 3, "0.100"}, 27 | {100, 1, "10.0"}, 28 | {100, 0, "100"}, 29 | {1, 3, "0.001"}, 30 | {0, 1, "0.0"}, 31 | {0, 5, "0.00000"}, 32 | {12, 0, "12"}, 33 | {999, 1, "99.9"}, 34 | {1234, 1, "123.4"}, 35 | {12345678, 2, "123456.78"}, 36 | } 37 | for _, s := range tests { 38 | if u := intToDecimalString(s.intValue, s.decimal); u != s.expect { 39 | t.Errorf("test failed on (%d, %d): expected %s, but we got %s\n", s.intValue, s.decimal, s.expect, u) 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /config/generate_levels/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "sort" 6 | "text/template" 7 | 8 | "github.com/hanchuanchuan/goInception/session" 9 | ) 10 | 11 | type ErrorLevel struct { 12 | OptionName string 13 | Level uint8 14 | TomlValue string 15 | } 16 | 17 | const tmpl = ` 18 | // Code generated by make level. DO NOT EDIT. 19 | 20 | package config 21 | 22 | type IncLevel struct { 23 | {{ range $opt := . }}` + " {{ $opt.OptionName }} uint8 `toml:\"{{ $opt.TomlValue }}\"`" + 24 | ` 25 | {{ end }}} 26 | 27 | var defaultLevel = IncLevel { 28 | {{ range $opt := . }} {{ $opt.OptionName }}: {{ $opt.Level }}, 29 | {{ end }}} 30 | ` 31 | 32 | const defaultToml = ` 33 | [inc_level] 34 | {{ range $opt := . }}{{ $opt.TomlValue }} = {{ $opt.Level }} 35 | {{ end }} 36 | ` 37 | 38 | func GenerateLevels() []ErrorLevel { 39 | results := make([]ErrorLevel, 0, len(session.ErrorsDefault)) 40 | for e := range session.ErrorsDefault { 41 | if e <= session.ErrorCode(session.ER_ERROR_FIRST) || 42 | e >= session.ErrorCode(session.ER_ERROR_LAST) { 43 | continue 44 | } 45 | name := e.String() 46 | if name == "" { 47 | continue 48 | } 49 | results = append(results, ErrorLevel{ 50 | OptionName: session.ToCamel(name), 51 | Level: session.GetErrorLevel(e), 52 | TomlValue: name, 53 | }) 54 | } 55 | sort.SliceStable(results, func(i, j int) bool { 56 | return results[i].TomlValue < results[j].TomlValue 57 | }) 58 | return results 59 | } 60 | 61 | func main() { 62 | t := template.Must(template.New("tmpl").Parse(tmpl)) 63 | file, err := os.OpenFile("config/error_level.go", os.O_TRUNC|os.O_RDWR|os.O_CREATE, 0600) 64 | if err != nil { 65 | panic(err) 66 | } 67 | err = t.Execute(file, GenerateLevels()) 68 | if err != nil { 69 | panic(err) 70 | } 71 | file.Close() 72 | 73 | t = template.Must(template.New("toml_default").Parse(defaultToml)) 74 | file, err = os.OpenFile("config/config.toml.default.tmp", os.O_TRUNC|os.O_RDWR|os.O_CREATE, 0600) 75 | if err != nil { 76 | panic(err) 77 | } 78 | defer file.Close() 79 | err = t.Execute(file, GenerateLevels()) 80 | if err != nil { 81 | panic(err) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /ddl/session_pool.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package ddl 15 | 16 | import ( 17 | "sync" 18 | 19 | "github.com/hanchuanchuan/goInception/mysql" 20 | "github.com/hanchuanchuan/goInception/sessionctx" 21 | "github.com/hanchuanchuan/goInception/util/mock" 22 | "github.com/ngaut/pools" 23 | "github.com/pingcap/errors" 24 | ) 25 | 26 | // sessionPool is used to new session. 27 | type sessionPool struct { 28 | mu sync.Mutex 29 | resPool *pools.ResourcePool 30 | } 31 | 32 | // get gets sessionctx from context resource pool. 33 | // Please remember to call put after you finished using sessionctx. 34 | func (sg *sessionPool) get() (sessionctx.Context, error) { 35 | if sg.resPool == nil { 36 | return mock.NewContext(), nil 37 | } 38 | 39 | resource, err := sg.resPool.Get() 40 | if err != nil { 41 | return nil, errors.Trace(err) 42 | } 43 | 44 | ctx := resource.(sessionctx.Context) 45 | ctx.GetSessionVars().SetStatusFlag(mysql.ServerStatusAutocommit, true) 46 | ctx.GetSessionVars().InRestrictedSQL = true 47 | return ctx, nil 48 | } 49 | 50 | // put returns sessionctx to context resource pool. 51 | func (sg *sessionPool) put(ctx sessionctx.Context) { 52 | if sg.resPool == nil { 53 | return 54 | } 55 | 56 | sg.resPool.Put(ctx.(pools.Resource)) 57 | } 58 | 59 | // close clean up the sessionPool. 60 | func (sg *sessionPool) close() { 61 | sg.mu.Lock() 62 | defer sg.mu.Unlock() 63 | if sg.resPool == nil { 64 | return 65 | } 66 | 67 | sg.resPool.Close() 68 | sg.resPool = nil 69 | } 70 | -------------------------------------------------------------------------------- /ddl/util/event.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package util 15 | 16 | import ( 17 | "fmt" 18 | 19 | "github.com/hanchuanchuan/goInception/model" 20 | ) 21 | 22 | // Event is an event that a ddl operation happened. 23 | type Event struct { 24 | Tp model.ActionType 25 | TableInfo *model.TableInfo 26 | ColumnInfo *model.ColumnInfo 27 | IndexInfo *model.IndexInfo 28 | } 29 | 30 | // String implements fmt.Stringer interface. 31 | func (e *Event) String() string { 32 | ret := fmt.Sprintf("(Event Type: %s", e.Tp) 33 | if e.TableInfo != nil { 34 | ret += fmt.Sprintf(", Table ID: %d, Table Name %s", e.TableInfo.ID, e.TableInfo.Name) 35 | } 36 | if e.ColumnInfo != nil { 37 | ret += fmt.Sprintf(", Column ID: %d, Column Name %s", e.ColumnInfo.ID, e.ColumnInfo.Name) 38 | } 39 | if e.IndexInfo != nil { 40 | ret += fmt.Sprintf(", Index ID: %d, Index Name %s", e.IndexInfo.ID, e.IndexInfo.Name) 41 | } 42 | return ret 43 | } 44 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | services: 4 | goinception: 5 | image: hanchuanchuan/goinception 6 | container_name: goinception 7 | restart: always 8 | # 网络模式二选一,使用主机host模式或者映射端口 9 | network_mode: "host" 10 | # ports: 11 | # - 4000:4000 12 | volumes: 13 | # 时区 14 | # - /etc/localtime:/etc/localtime 15 | # 配置文件 16 | - ./config/config.toml:/etc/config.toml 17 | -------------------------------------------------------------------------------- /docs/.vuepress/components/fonts/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanchuanchuan/goInception/cfb88db9954aecdebbbae8bc1c91f464e22725dd/docs/.vuepress/components/fonts/iconfont.eot -------------------------------------------------------------------------------- /docs/.vuepress/components/fonts/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanchuanchuan/goInception/cfb88db9954aecdebbbae8bc1c91f464e22725dd/docs/.vuepress/components/fonts/iconfont.ttf -------------------------------------------------------------------------------- /docs/.vuepress/components/fonts/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanchuanchuan/goInception/cfb88db9954aecdebbbae8bc1c91f464e22725dd/docs/.vuepress/components/fonts/iconfont.woff -------------------------------------------------------------------------------- /docs/.vuepress/components/gitalk.vue: -------------------------------------------------------------------------------- 1 | 6 | 34 | -------------------------------------------------------------------------------- /docs/.vuepress/public/fonts/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanchuanchuan/goInception/cfb88db9954aecdebbbae8bc1c91f464e22725dd/docs/.vuepress/public/fonts/iconfont.eot -------------------------------------------------------------------------------- /docs/.vuepress/public/fonts/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanchuanchuan/goInception/cfb88db9954aecdebbbae8bc1c91f464e22725dd/docs/.vuepress/public/fonts/iconfont.ttf -------------------------------------------------------------------------------- /docs/.vuepress/public/fonts/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanchuanchuan/goInception/cfb88db9954aecdebbbae8bc1c91f464e22725dd/docs/.vuepress/public/fonts/iconfont.woff -------------------------------------------------------------------------------- /docs/.vuepress/styles/index.styl: -------------------------------------------------------------------------------- 1 | /* .vuepress/styles/index.styl */ 2 | 3 | // img + .icon.outbound { 4 | // display: none; 5 | // } 6 | 7 | .theme-default-content.custom { 8 | max-width: 960px; 9 | margin: 0 auto; 10 | padding: 2rem 2.5rem; 11 | } 12 | 13 | a[target] span { 14 | display: none !important 15 | } 16 | 17 | 18 | .gitbook-link { 19 | display: none !important; 20 | } 21 | 22 | .book .book-body .page-wrapper .page-inner { 23 | max-width: 1000px; 24 | } 25 | 26 | .markdown-section table{ 27 | display: block; 28 | } 29 | 30 | .aceCode { 31 | font-size: 14px !important; 32 | } 33 | 34 | .page-footer-ex-footer-update { 35 | font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; 36 | } 37 | 38 | .page-footer-ex-copyright { 39 | font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; 40 | } 41 | 42 | .markdown-section p>code,.markdown-section table tr td code{ 43 | color: red; 44 | } 45 | 46 | .text-success{ 47 | font-weight: bold; 48 | font-size: 22px; 49 | color: #28a745!important; 50 | } 51 | 52 | 53 | .text-success-small{ 54 | font-weight: bold; 55 | color: #28a745!important; 56 | } 57 | 58 | .text-error{ 59 | font-weight: bold; 60 | font-size: 22px; 61 | color: #dc3545!important; 62 | } 63 | 64 | .progress{ 65 | width: 100px; 66 | height: 20px; 67 | margin: 10px auto; 68 | position: relative; 69 | border:1px solid #ddd; 70 | border-radius: 10px; 71 | } 72 | 73 | .rect{ 74 | height: 20px; 75 | position: absolute; 76 | top:0; 77 | color: #007bff!important; 78 | border-radius: 10px; 79 | overflow: hidden; /*注意这里*/ 80 | } 81 | .left{ 82 | left:0; 83 | border-radius: 10px 0px 0px 10px; 84 | background-color: #007bff!important; 85 | height: 20px; 86 | } 87 | 88 | /*.left::after { 89 | display: block; 90 | content: ' '; 91 | width: 100px; 92 | height: 200px; 93 | }*/ 94 | -------------------------------------------------------------------------------- /docs/.vuepress/styles/palette.styl: -------------------------------------------------------------------------------- 1 | // layout 2 | $navbarHeight = 3.6rem 3 | $sidebarWidth = 20rem 4 | $contentWidth = 860px 5 | $homePageWidth = 960px 6 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Introdunction 2 | 3 | [![GitHub stars](https://img.shields.io/github/stars/hanchuanchuan/goInception?style=brightgreen)](https://github.com/hanchuanchuan/goInception/stargazers) 4 | [![GitHub forks](https://img.shields.io/github/forks/hanchuanchuan/goInception?style=brightgreen)](https://github.com/hanchuanchuan/goInception/network) 5 | [![codecov](https://codecov.io/gh/hanchuanchuan/goInception/branch/master/graph/badge.svg)](https://codecov.io/gh/hanchuanchuan/goInception) 6 | ![](https://img.shields.io/github/downloads/hanchuanchuan/goInception/total.svg) 7 | [![GitHub release](https://img.shields.io/github/release-pre/hanchuanchuan/goInception.svg?style=brightgreen)](https://github.com/hanchuanchuan/goInception/releases) 8 | ![](https://img.shields.io/github/license/hanchuanchuan/goInception.svg) 9 | 10 | goInception is a MySQL maintenance tool, which can be used to review, implement, backup, and generate SQL statements for rollback. It parses SQL syntax and returns the result of the review based on custom rules. 11 | 12 | 13 | ## Architecture 14 | 15 | 16 | ![process](./images/process.png) 17 | 18 | ## Usage 19 | 20 | GoInception extension of the usage of Inception, to specify the remote server by adding annotations before the SQL review, and for distinguishing SQL and review adding special comments at the beginning and the end of SQL. 21 | 22 | Any MySQL protocol-driven can connect in the same way, but the syntax is slightly different. Support different parameters to set for review by specific formats. 23 | 24 | ```sql 25 | /*--user=root;--password=root;--host=127.0.0.1;--check=1;--port=3306;*/ 26 | inception_magic_start; 27 | use test; 28 | create table t1(id int primary key); 29 | inception_magic_commit; 30 | ``` 31 | 32 | ## What did 33 | 34 | What audit rules goInception does, and what grammar audits are supported can be referred to [Audit rules](rules.html) 35 | 36 | 37 | ## Acknowledgments 38 | 39 | GoInception reconstructs from the Inception which is a well-known MySQL auditing tool and uses TiDB SQL parser. 40 | 41 | - [Inception](https://github.com/hanchuanchuan/inception) 42 | - [TiDB](https://github.com/pingcap/tidb) 43 | -------------------------------------------------------------------------------- /docs/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 确保脚本抛出遇到的错误 4 | set -e 5 | 6 | # 生成静态文件 7 | npm run docs:build 8 | 9 | # 进入生成的文件夹 10 | cd docs/.vuepress/dist 11 | 12 | git init 13 | git add -A 14 | git commit -m 'update docs[ci skip]' 15 | 16 | # 如果发布到 https://.github.io 17 | # git push -f git@github.com:/.github.io.git master 18 | 19 | # 如果发布到 https://.github.io/ 20 | git push -f git@github.com:hanchuanchuan/goInception.git master:gh-pages 21 | 22 | cd - 23 | -------------------------------------------------------------------------------- /docs/images/levels_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanchuanchuan/goInception/cfb88db9954aecdebbbae8bc1c91f464e22725dd/docs/images/levels_0.png -------------------------------------------------------------------------------- /docs/images/levels_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanchuanchuan/goInception/cfb88db9954aecdebbbae8bc1c91f464e22725dd/docs/images/levels_1.png -------------------------------------------------------------------------------- /docs/images/levels_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanchuanchuan/goInception/cfb88db9954aecdebbbae8bc1c91f464e22725dd/docs/images/levels_2.png -------------------------------------------------------------------------------- /docs/images/levels_all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanchuanchuan/goInception/cfb88db9954aecdebbbae8bc1c91f464e22725dd/docs/images/levels_all.png -------------------------------------------------------------------------------- /docs/images/pay.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanchuanchuan/goInception/cfb88db9954aecdebbbae8bc1c91f464e22725dd/docs/images/pay.jpeg -------------------------------------------------------------------------------- /docs/images/process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanchuanchuan/goInception/cfb88db9954aecdebbbae8bc1c91f464e22725dd/docs/images/process.png -------------------------------------------------------------------------------- /docs/images/processlist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanchuanchuan/goInception/cfb88db9954aecdebbbae8bc1c91f464e22725dd/docs/images/processlist.png -------------------------------------------------------------------------------- /docs/images/statistic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanchuanchuan/goInception/cfb88db9954aecdebbbae8bc1c91f464e22725dd/docs/images/statistic.png -------------------------------------------------------------------------------- /docs/images/variables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanchuanchuan/goInception/cfb88db9954aecdebbbae8bc1c91f464e22725dd/docs/images/variables.png -------------------------------------------------------------------------------- /docs/images/wechat.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanchuanchuan/goInception/cfb88db9954aecdebbbae8bc1c91f464e22725dd/docs/images/wechat.jpeg -------------------------------------------------------------------------------- /docs/install.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Install package 4 | 5 | 6 | [goInception package](https://github.com/hanchuanchuan/goInception/releases) 7 | 8 | 9 | ### Source code 10 | 11 | - Golang v1.12 and above 12 | - Go mod to manage package dependencies 13 | 14 | ```sh 15 | 16 | # download source code 17 | git clone https://github.com/hanchuanchuan/goInception 18 | 19 | cd goInception 20 | 21 | make parser 22 | 23 | # build package 24 | go build -o goInception tidb-server/main.go 25 | 26 | ``` 27 | 28 | #### start with configuration file 29 | 30 | ```sh 31 | ./goInception -config=config/config.toml 32 | ``` 33 | 34 | 35 | -------------------------------------------------------------------------------- /docs/levels.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### function description 4 | 5 | Customize audit level for setting the audit error lever `error_level`. 6 | - `2` is error, force probit 7 | - `1` is warning, weak probit, can by ignored by the setting ignore_warnings. 8 | - `0` is correct. 9 | 10 | 11 | ### check levels 12 | 13 | ```sql 14 | inception show levels; 15 | ``` 16 | 17 | check demo 18 | ```sql 19 | inception show levels like '%blob%'; 20 | inception show levels where value=2; 21 | inception show levels where `desc` like '%index%'; 22 | ``` 23 | 24 | ![Option List](./images/levels_all.png) 25 | 26 | ### Setting audit level 27 | 28 | ```sql 29 | inception set level er_no_where_condition = 2; 30 | ``` 31 | 32 | #### Configuration file 33 | 34 | **config.toml** 35 | 36 | *Options: `0`,`1`,`2`* 37 | ``` 38 | [inc_level] 39 | er_alter_table_once = 1 40 | er_auto_incr_id_warning = 1 41 | er_autoinc_unsigned = 1 42 | ... 43 | ``` 44 | 45 | ### deno:limit `delete must contain where` 46 | 47 | 1.turn on `where` audit option 48 | ```sql 49 | inception show variables like '%where%'; 50 | 51 | inception set check_dml_where = 1; 52 | ``` 53 | 54 | ![turn on where audit](./images/levels_0.png) 55 | 56 | 2.setting where audit level is (`2`) 57 | 58 | ```sql 59 | inception show levels like '%where%'; 60 | 61 | inception set level er_no_where_condition = 2; 62 | ``` 63 | 64 | ![setting where audit level](./images/levels_1.png) 65 | 66 | 67 | -------------------------------------------------------------------------------- /docs/permission.md: -------------------------------------------------------------------------------- 1 | # Permission Desc 2 | 3 | Different functions and stages require different permissions. The permission requirements that may be involved in each function are listed below. If there are any omissions, please suggest and add. 4 | 5 | The suggested permissions are: 6 | 7 | `GRANT ALL PRIVILEGES ON *.* TO ...` 8 | 9 | or 10 | 11 | `GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, PROCESS, REFERENCES, INDEX, ALTER, SUPER, REPLICATION SLAVE, REPLICATION CLIENT, TRIGGER ON *.* TO ...` 12 | 13 | 14 | ## Audit function 15 | 16 | * `information_schema db` Metadata query permissions, table structure, index information, constraints, etc. 17 | * `mysql db` use permission, no query, the library is connected by default, and it can be modified by calling the option `--db` parameter 18 | * `DML` During the audit, the explain operation will be performed on the DML statement, and this operation requires the actual corresponding DML authority. 19 | * `REFERENCES` Only required for foreign keys 20 | 21 | ## Execute 22 | 23 | * Actual SQL execution permissions 24 | 25 | 26 | ### Use pt-osc 27 | 28 | * `PROCESS` permission, view processlist information 29 | * `TRIGGER` create and delete triggers 30 | * `SUPER` or `REPLICATION CLIENT` When there is a master-slave, check the master-slave delay 31 | 32 | ### Use gh-ost 33 | 34 | * `SUPER|REPLICATION CLIENT, REPLICATION SLAVE` Simulate slave pull binlog events 35 | * `ALTER`, `CREATE`, `DELETE`, `DROP`, `INDEX`, `INSERT`, `LOCK TABLES`, `SELECT`, `TRIGGER`, `UPDATE` 36 | 37 | 38 | ## Backup 39 | 40 | ### Remote database 41 | 42 | * `SUPER` When the binlog format is not row, execute `set session binlog_format='row'` 43 | 44 | * `SUPER|REPLICATION CLIENT, REPLICATION SLAVE` binlog解析 45 | 46 | ### Database used for backup 47 | 48 | * `It is recommended to grant all permissions to the backup library instance` 49 | -------------------------------------------------------------------------------- /docs/safe.md: -------------------------------------------------------------------------------- 1 | # [Safe] User authentication 2 | 3 | ### Desc 4 | 5 | Goinception itself is based on TiDB, so it has a complete user management module. For ease of use, this function is turned off by default. 6 | 7 | **Open authentication method:** 8 | 9 | Add the following parameters in the **config.toml** configuration file (file root node or [inc] node) 10 | 11 | ``` 12 | skip_grant_table = false 13 | ``` 14 | 15 | The supported syntax is as follows: 16 | 17 | - CREATE USER 18 | - DROP USER 19 | - ALTER USER 20 | - SET PASSWORD FOR 21 | - GRANK/REVOKE `May not be used` 22 | - SELECT * FROM MYSQL.USER `Query user list` 23 | 24 | `The default initial user is root, and the password is empty` 25 | 26 | If you forget the password, you can restart it by skipping authentication. After changing the password, turn on authentication and restart goinception (this method is similar to MySQL). 27 | 28 | **Note**: The data directory (default is `/tmp/tidb`) may be damaged during abnormal shutdown. At this time, you need to delete the directory and restart, but the created users will be lost, so please pay attention to back up the directory or save the user creation script. 29 | 30 | This function is the only one that needs attention to save the data directory, and no other functions are needed. 31 | 32 | -------------------------------------------------------------------------------- /docs/statistics.md: -------------------------------------------------------------------------------- 1 | # Statistics function 2 | 3 | For percentage of recorded operations, set by `enable_sql_statistic` and need to turn on backup, because statistics data is stored in the backup database. Schema name is inception, and this schema has only one table `statistic`. 4 | 5 | ![](images/statistic.png) 6 | 7 | Partial Column comment 8 | - **deleting** : Including the common deletion and multi-table delete operation 9 | inserting : Including single-row inserts, multi-row insert and insert query 10 | - **updating** : Including updates ordinary single-table and multi-table update 11 | - **renaming** : rename in `ALTER table` 12 | - **createindex** : add index in `ALTER table` 13 | - **dropindex** : drop index in `ALTER table` 14 | - **alteroption** : some modify table options in `ALTER table`, such as storage `engines, auto_increment`, character. 15 | - **alterconvert** : modify character in `ALTER table` 16 | For `ALTER TABLE`, maybe contains multi-options, such as rename, drop index, engine innodb, etc. the value is the sum value of renaming, createindex, dropindex, addcolumn, dropcolumn, changecolumn, alteroption, alterconvert. 17 | 18 | If you want to calculate some specific option, you can check below. 19 | ```` 20 | select sum(a.oprate)/count(1) updaterate from 21 | (select (updating)/(usedb+deleting+inserting+updating+selecting+altertable+ 22 | createtable+droptable+createdb+truncating) oprate from 23 | inception.statistic) a; 24 | ```` 25 | 26 | # Tips 27 | 28 | * If only audit options or audit failed, won’t be calculated in statistics. 29 | * goInception only records the actual execution option.if partial failed, only records the success part. 30 | * If the error is caused by backup, it won't affect statistics. 31 | 32 | -------------------------------------------------------------------------------- /docs/support.md: -------------------------------------------------------------------------------- 1 | ### Sponsorship and support 2 | 3 | If goInception can help, welcome to sponsor the author. 4 | 5 | Thans for your sponsor, your company or personal information will be displayed in the `Sponsor List`. 6 | 7 | For a strong endorsement of companies and individuals can contact the author to add your company or personal logo to the project home page, customize and prioritize the needs of their development. 8 | 9 | 10 | 15 | 16 |
17 | Alipay 18 |
19 | WeChat 20 |
21 | 22 | ------ 23 | 24 | #### Sponsor List 25 | 26 | 27 | ------ 28 | 29 | ### Customization requirements 30 | 31 | Please connect me by e-mail or QQ group talk. 32 | 33 | e-mail: `chuanchuanhan@gmail.com` 34 | 35 | QQ group talk: `499262190` 36 | -------------------------------------------------------------------------------- /docs/zh/README.md: -------------------------------------------------------------------------------- 1 | # 介绍 2 | 3 | 4 | [![GitHub stars](https://img.shields.io/github/stars/hanchuanchuan/goInception?style=brightgreen)](https://github.com/hanchuanchuan/goInception/stargazers) 5 | [![GitHub forks](https://img.shields.io/github/forks/hanchuanchuan/goInception?style=brightgreen)](https://github.com/hanchuanchuan/goInception/network) 6 | [![codecov](https://codecov.io/gh/hanchuanchuan/goInception/branch/master/graph/badge.svg)](https://codecov.io/gh/hanchuanchuan/goInception) 7 | ![](https://img.shields.io/github/downloads/hanchuanchuan/goInception/total.svg) 8 | [![GitHub release](https://img.shields.io/github/release-pre/hanchuanchuan/goInception.svg?style=brightgreen)](https://github.com/hanchuanchuan/goInception/releases) 9 | ![](https://img.shields.io/github/license/hanchuanchuan/goInception.svg) 10 | 11 | goInception是一个集审核、执行、备份及生成回滚语句于一身的MySQL运维工具, 通过对执行SQL的语法解析,返回基于自定义规则的审核结果,并提供执行和备份及生成回滚语句的功能。 12 | 13 | ## 架构 14 | 15 | ![审核流程](./images/process.png) 16 | 17 | ## 使用方式 18 | 19 | 实现了mysql协议驱动的语言均可访问,访问方式和mysql一致,语法略有差异,通过特定格式设置不同参数以供审核。 20 | 21 | goInception延用inception的使用方式,在审核的sql开始前添加注释来指定远端服务器,并在sql的前后添加特殊标识以区分待审核语句,示例如下: 22 | 23 | ```sql 24 | /*--user=root;--password=root;--host=127.0.0.1;--check=1;--port=3306;*/ 25 | inception_magic_start; 26 | use test; 27 | create table t1(id int primary key); 28 | inception_magic_commit; 29 | ``` 30 | 31 | ## 做了什么 32 | 33 | goInception做了哪些审核规则,以及支持什么语法的审核均可参考[审核规则](rules.html) 34 | 35 | 36 | ## 致谢 37 | 38 | ``` 39 | goInception基于TiDB的语法解析器,和业内有名的inception审核工具重构。 40 | ``` 41 | 42 | * [Inception - 审核工具](https://github.com/hanchuanchuan/inception) 43 | * [TiDB](https://github.com/pingcap/tidb) 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /docs/zh/config.md: -------------------------------------------------------------------------------- 1 | # config.toml 2 | 3 | ## config.toml配置文件说明 4 | 5 | goInception通过`./goInception -config=config/config.toml`方式启动,接下来说明config.toml中的各项配置。 6 | 7 | **由于goInception采用TiDB源码重构,所以部分参数可参考TiDB相关文档** 8 | 9 | `config.toml`文件由几部分组成,分别为最外层配置如`host`,`port`等,以及各分组如`[inc]`,`[log]`等,接下来逐一说明。 10 | 11 | 示例(该示例仅为展示config.toml文件结构,[详细参数请参考](https://github.com/hanchuanchuan/goInception/blob/master/config/config.toml.default)): 12 | ```toml 13 | 14 | host = "0.0.0.0" 15 | port = 4000 16 | path = "/tmp/tidb" 17 | 18 | [log] 19 | # 日志参数 20 | level = "info" 21 | format = "text" 22 | 23 | [log.file] 24 | # 日志文件参数 25 | filename = "" 26 | max-size = 300 27 | 28 | [inc] 29 | # 审核选项 30 | enable_nullable = true 31 | enable_drop_table = false 32 | check_table_comment = false 33 | check_column_comment = false 34 | # 等等... 35 | 36 | [osc] 37 | # pt-osc参数 38 | osc_on = false 39 | osc_min_table_size = 16 40 | 41 | [ghost] 42 | # gh-ost参数 43 | ghost_allow_on_master = true 44 | 45 | ``` 46 | 47 | ### host 48 | 绑定的IP地址,默认值 `0.0.0.0` 49 | 50 | ### port 51 | 绑定的端口,默认值 `4000` 52 | 53 | ### path 54 | TiDB数据库目录,默认值 `/tmp/tidb`,该参数会创建少量TiDB的系统表,如果设置为空时,则会在内存中创建。 55 | 建议指定实际目录,这样会加快启动的速度。 56 | 57 | 58 | 59 | ### [inc] 60 | 61 | 所有的 **[审核选项](options.html)** 在此处设置 62 | 63 | ### [osc] 64 | 65 | 所有的 **[pt-osc选项](osc.html)** 在此处设置 66 | 67 | ### [gh-ost] 68 | 69 | 所有的 **[gh-ost选项](ghost.html)** 在此处设置 70 | 71 | 72 | 73 | ### [log] 74 | 75 | #### level 76 | 日志级别,默认值 `info` 77 | 可选值: `debug`, `info`, `warn`, `error`. 78 | 79 | #### format 80 | 日志格式,默认值 `text` 81 | 可选值: `json`, `text`, `console` 82 | 83 | #### disable-timestamp 84 | 禁用时间戳输出,默认值 `false` 85 | 86 | 87 | ### [log.file] 88 | #### filename 89 | 日志文件,默认值 `""` 90 | 建议指定日志文件,便于问题追溯 91 | 92 | #### max-size 93 | 日志文件的最大上限(MB),默认值 `300` 94 | 95 | #### max-days 96 | 日志文件的保存天数,默认值 `0`,即不清理 97 | 98 | #### max-backups 99 | 要保留的最大旧日志文件数,默认值 `0`,即不清理 100 | 101 | #### log-rotate 102 | 日志轮询,默认值 `true`,即开启 103 | 104 | -------------------------------------------------------------------------------- /docs/zh/diff.md: -------------------------------------------------------------------------------- 1 | # 对比inception 2 | 3 | 4 | ## 功能对比 5 | 6 | 功能 | inception | goInception | 说明 7 | ------------ | :--------: | :--------: | ------------ 8 | 审核 |
|
| 基本无差异 9 | 执行 |
|
| 基本无差异 10 | pt-osc工具 |
|
| 基本无差异 11 | gh-ost工具 |
|
| 12 | 备份 |
|
| 基本无差异 13 | 忽略警告 |
|
| 基本无差异 14 | 只读参数 |
|
| goinception未提供 15 | 打印SQL语法树 |
|
| inception的感觉更友好 16 | DDL和DML拆分功能 |
|
| goinception支持混合执行,不会影响回滚解析 17 | 执行部分后休眠 |
|
| goinception支持执行指定条数后休眠 18 | 计算真实受影响行数 |
|
| 19 | 事务支持 |
|
| 20 | SQL指纹功能 |
|
| dml语句相似时,可以根据相同的指纹ID复用explain结果,以减少远端数据库explain操作,提高审核速度 21 | 22 | ## 速度 23 | 24 | 模块 | inception | goInception | 说明 25 | ------------ | :--------: | :--------: | ------------ 26 | 审核 | ☆☆ | ☆☆ | 审核速度inception占优,优势微弱 27 | 执行 | ☆☆ | ☆☆ | 执行速度相近 28 | 备份 | ☆ | ☆☆ | 备份速度goinception领先(批量备份),优势较大 29 | 30 | ## 上手和使用 31 | 32 | 分类 | inception | goInception | 说明 33 | ------------ | :--------: | :--------: | ------------ 34 | 快速部署 | ☆ | ☆☆ | goinception可使用二进制部署,下载即用 35 | 问题调试 | ☆ | ☆☆ | goinception有较多日志输出,便于问题快速定位 36 | 接口调用 | 限`python`,`c`,`c++` | 实现了`mysql数据库驱动的语言` | 37 | -------------------------------------------------------------------------------- /docs/zh/images/levels_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanchuanchuan/goInception/cfb88db9954aecdebbbae8bc1c91f464e22725dd/docs/zh/images/levels_0.png -------------------------------------------------------------------------------- /docs/zh/images/levels_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanchuanchuan/goInception/cfb88db9954aecdebbbae8bc1c91f464e22725dd/docs/zh/images/levels_1.png -------------------------------------------------------------------------------- /docs/zh/images/levels_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanchuanchuan/goInception/cfb88db9954aecdebbbae8bc1c91f464e22725dd/docs/zh/images/levels_2.png -------------------------------------------------------------------------------- /docs/zh/images/levels_all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanchuanchuan/goInception/cfb88db9954aecdebbbae8bc1c91f464e22725dd/docs/zh/images/levels_all.png -------------------------------------------------------------------------------- /docs/zh/images/pay.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanchuanchuan/goInception/cfb88db9954aecdebbbae8bc1c91f464e22725dd/docs/zh/images/pay.jpeg -------------------------------------------------------------------------------- /docs/zh/images/process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanchuanchuan/goInception/cfb88db9954aecdebbbae8bc1c91f464e22725dd/docs/zh/images/process.png -------------------------------------------------------------------------------- /docs/zh/images/processlist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanchuanchuan/goInception/cfb88db9954aecdebbbae8bc1c91f464e22725dd/docs/zh/images/processlist.png -------------------------------------------------------------------------------- /docs/zh/images/statistic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanchuanchuan/goInception/cfb88db9954aecdebbbae8bc1c91f464e22725dd/docs/zh/images/statistic.png -------------------------------------------------------------------------------- /docs/zh/images/variables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanchuanchuan/goInception/cfb88db9954aecdebbbae8bc1c91f464e22725dd/docs/zh/images/variables.png -------------------------------------------------------------------------------- /docs/zh/images/wechat.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanchuanchuan/goInception/cfb88db9954aecdebbbae8bc1c91f464e22725dd/docs/zh/images/wechat.jpeg -------------------------------------------------------------------------------- /docs/zh/install.md: -------------------------------------------------------------------------------- 1 | 2 | # 安装 3 | 4 | ## 二进制安装 5 | 6 | 7 | [goInception安装包](https://github.com/hanchuanchuan/goInception/releases) 8 | 9 | 10 | ## 源码安装 11 | 12 | - *go版本v1.12及以上* 13 | 14 | - *使用go mod做依赖管理* 15 | 16 | ```sh 17 | 18 | # 下载源码 19 | git clone https://github.com/hanchuanchuan/goInception 20 | 21 | cd goInception 22 | 23 | make parser 24 | 25 | # 构建二进制包 26 | go build -o goInception tidb-server/main.go 27 | 28 | ``` 29 | 30 | ## 启动(注意指定配置文件) 31 | 32 | ```sh 33 | ./goInception -config=config/config.toml 34 | ``` 35 | 36 | 37 | -------------------------------------------------------------------------------- /docs/zh/kill_stmt.md: -------------------------------------------------------------------------------- 1 | # KILL操作 2 | 3 | **使用前请连接goInception并使用`inception show processlist`确认当前阶段(`STATE`)** 4 | 5 | 6 | 阶段分为三种: 7 | 8 | - CHECKING (`审核中`) 9 | - EXECUTING (`执行中`) 10 | - BACKUP (`备份中`) 11 | 12 | ####KILL操作执行位置 13 | 14 | - 远端数据库,即执行实际sql的数据库 15 | - goInception 16 | - goInception配置的备份库 17 | 18 | 19 | ### goInception KILL 20 | 21 | 当前阶段 | kill后的结果 22 | ----------|--------- 23 | CHECKING | 在`当前语句` `审核完成` 后中止审核,此时仅返回从开始到当前语句的审核结果,后续SQL不再审核 24 | EXECUTING | 在`当前语句` `执行完成` 后中止执行,如果开启了备份,会执行备份操作,未开启则直接返回 25 | BACKUP | 在`当前binlog事件` 解析完成后中止备份,但已生成的回滚语句会继续写入备份库,待写入完成后返回 26 | 27 | 28 | ### 远端数据库KILL(不建议) 29 | 30 | 当前阶段 | kill后的结果 31 | ----------|--------- 32 | CHECKING | kill操作不会影响审核,连接被kill后会自动重连(`原因是审核失败**不会中止审核**,所以需要重连,并恢复断开的数据库,以避免后续SQL访问错数据库`) 33 | EXECUTING (`语句kill后执行失败`) | 语句用时过长时,此时kill会直接停止goInception语句的执行,如果开启了备份,会执行备份操作,未开启则直接返回 34 | EXECUTING (`语句kill后执行成功,连接断开`)| 语句执行比较快时,可能已经执行成功,此时需要根据binlog备份做进一步校验,所以`依赖备份功能` 35 | BACKUP | `<无>` 36 | 37 | 38 | ### goInception备份库KILL (`完全不建议`) 39 | 40 | 当前阶段 | kill后的结果 41 | ----------|--------- 42 | CHECKING | 在开始备份前会自动检测连接并重连,所以该操作`无效` 43 | EXECUTING | 在开始备份前会自动检测连接并重连,所以该操作`无效` 44 | BACKUP | 执行可能成功也可能失败,会导致备份结果不确定,因此`完全不建议`在备份库执行KILL操作 45 | 46 | -------------------------------------------------------------------------------- /docs/zh/levels.md: -------------------------------------------------------------------------------- 1 | 2 | # 自定义审核级别 3 | 4 | ### 功能说明 5 | 6 | 7 | 自定义审核级别用以实现指定审核结果的错误级别。 8 | 9 | 对应审核结果的 `error_level` 字段: 10 | 11 | - `2` 为错误,即强限制,无法执行 12 | - `1` 为警告,即弱限制,可通过忽略警告参数`ignore_warnings`跳过 13 | - `0` 为正常,即不做限制 14 | 15 | 16 | ##### 查看命令 17 | 18 | ```sql 19 | inception show levels; 20 | ``` 21 | 22 | 筛选查看 23 | ```sql 24 | # 筛选指定审核名称 25 | inception show levels like '%blob%'; 26 | # 筛选指定级别 27 | inception show levels where value=2; 28 | # 筛选指定关键字 29 | inception show levels where `desc` like '%index%'; 30 | ``` 31 | 32 | ![支持参数](./images/levels_all.png) 33 | 34 | ##### 设置审核级别命令 35 | 36 | ```sql 37 | inception set level er_no_where_condition = 2; 38 | ``` 39 | 40 | ##### 配置文件 41 | 42 | ** config.toml配置文件 ** 43 | 44 | *参数的可选值均为 `0`,`1`,`2`* 45 | ``` 46 | [inc_level] 47 | er_alter_table_once = 1 48 | er_auto_incr_id_warning = 1 49 | er_autoinc_unsigned = 1 50 | ... 51 | ``` 52 | 53 | ### 示例:实现限制 `delete语句必须有where条件` 54 | 55 | 1.开启where条件审核选项 56 | ```sql 57 | inception show variables like '%where%'; 58 | 59 | inception set check_dml_where = 1; 60 | ``` 61 | 62 | ![开启where条件审核选项](./images/levels_0.png) 63 | 64 | 2.设置where条件的审核级别为错误 (`2`) 65 | 66 | ```sql 67 | inception show levels like '%where%'; 68 | 69 | inception set level er_no_where_condition = 2; 70 | ``` 71 | 72 | ![设置where条件的审核级别](./images/levels_1.png) 73 | 74 | 3.验证审核结果 75 | 76 | -------------------------------------------------------------------------------- /docs/zh/permission.md: -------------------------------------------------------------------------------- 1 | # 权限说明 2 | 3 | 不同功能及阶段需要不同的权限,下面会列出各项功能可能涉及的权限要求,如有遗漏之处欢迎提出和补充。 4 | 5 | 建议的权限为: 6 | `GRANT ALL PRIVILEGES ON *.* TO ...` 7 | 8 | 或者 9 | 10 | `GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, PROCESS, REFERENCES, INDEX, ALTER, SUPER, REPLICATION SLAVE, REPLICATION CLIENT, TRIGGER ON *.* TO ...` 11 | 12 | 13 | ## 审核功能 14 | 15 | * `information_schema库` 元数据查询权限,表结构,索引信息,约束等 16 | * `mysql库` use权限,没有查询,默认连接该库,可通过调用选项的`--db`参数修改 17 | * `DML操作` 审核时会对DML语句做explain操作,该操作需要实际的相应DML权限。 18 | * `REFERENCES` 仅外键需要 19 | 20 | ## 执行 21 | 22 | * 实际的SQL执行权限 23 | 24 | 25 | ### 使用pt-osc 26 | 27 | * `PROCESS` 权限,查看processlist信息 28 | * `TRIGGER` 创建和删除触发器 29 | * `SUPER` 或 `REPLICATION CLIENT` 有主从时,查看主从延迟 30 | 31 | ### 使用gh-ost 32 | 33 | * `SUPER|REPLICATION CLIENT, REPLICATION SLAVE` binlog解析 34 | * `ALTER`, `CREATE`, `DELETE`, `DROP`, `INDEX`, `INSERT`, `LOCK TABLES`, `SELECT`, `TRIGGER`, `UPDATE` 35 | 36 | 37 | ## 备份 38 | 39 | ### 远端数据库 40 | 41 | * `SUPER权限`,用以binlog格式不为row时执行`set session binlog_format='row'` 42 | 43 | * `SUPER|REPLICATION CLIENT, REPLICATION SLAVE` binlog解析 44 | 45 | ### 备份库 46 | 47 | 48 | 49 | * `建议授予备份库实例的所有权限` 50 | -------------------------------------------------------------------------------- /docs/zh/safe.md: -------------------------------------------------------------------------------- 1 | # goinception用户鉴权 2 | 3 | ### 说明 4 | 5 | goinception本身基于TiDB,所以拥有完整的用户管理模块,为了简单使用,默认是关闭该功能的。 6 | 7 | **开启鉴权方法:** 8 | 9 | 在 config.toml 配置文件添加以下参数(文件根节点或者[inc]节点) 10 | 11 | ``` 12 | skip_grant_table = false 13 | ``` 14 | 15 | 相应的语法支持如下: 16 | 17 | - CREATE USER 18 | - DROP USER 19 | - ALTER USER 20 | - SET PASSWORD FOR 21 | - GRANT/REVOKE `可能用不到` 22 | - SELECT * FROM MYSQL.USER `用户查询` 23 | 24 | `默认初始用户为root, 密码为空` 25 | 26 | 忘记密码后可以通过跳过鉴权的方式重新启动,修改密码后开启鉴权并重启goinception。 27 | 28 | 在非正常关闭时数据目录(默认为`/tmp/tidb`)可能损坏,此时需要删除该目录并重启,但已创建用户会丢失,因此请注意备份该目录或保存用户创建脚本。 29 | 30 | 该功能是唯一需要注意保存数据目录的,其他功能均不需要。 31 | 32 | -------------------------------------------------------------------------------- /docs/zh/statistics.md: -------------------------------------------------------------------------------- 1 | # 统计功能 2 | 3 | 统计功能用以记录操作占比,通过参数 `enable_sql_statistic` 开启。 4 | 5 | 除了上面的参数之外,使用这个功能还需要开启操作备份功能,因为这些统计数据需要存储到备份数据库中,存储的数据库名为inception中, 6 | 这个数据库现在只有一个表statistic,存储的就是SQL执行数目的统计数据。 7 | 8 | 9 | **statistic**表的结构如下: 10 | ![](images/statistic.png) 11 | 12 | 从每一个列的名字就可以看到,其值对应的操作是什么,每一个列就是一个自增列,第二个列optime是操作时间,这个主要是用来统计在某一段时间内的某一个操作占多少比例。 13 | 14 | 部分列说明: 15 | 16 | * **deleting** : 包括普通的删除操作及多表删除操作。 17 | * **inserting** : 包括单行插入、多行插入及查询插入。 18 | * **updating** : 包括普通单表更新及多表的更新。 19 | * **renaming** : 指的是ALTER table语句中的rename操作。 20 | * **createindex** : 指的是ALTER table语句中的add index操作。 21 | * **dropindex** : 指的是ALTER table语句中的drop index操作。 22 | * **alteroption** : 指的是ALTER table语句中的修改表属性的操作,比如存储引擎、自增值及字符集中操作。 23 | * **alterconvert** : 指的是ALTER table语句中修改表字符集的操作。 24 | 25 | 对于ALTER TABLE操作,因为这个操作包含很多的子操作,比如rename、drop index、engine innodb等操作,所以对于列altertable,它的值是renaming, createindex, dropindex, addcolumn, dropcolumn, changecolumn, alteroption, alterconvert的和, 而后面的是对ALTER TABLE语句的细分操作统计。 26 | 27 | 那么如果现在想要统计某一个操作,比如修改表占所有操作的百分比,则使用如下语句即可完成: 28 | ```sql 29 | SELECT Sum(a.oprate) / Count(1) updaterate 30 | FROM (SELECT ( updating ) / ( usedb + deleting + inserting + updating + 31 | selecting 32 | + altertable + createtable + droptable + 33 | createdb 34 | + truncating ) oprate 35 | FROM inception.statistic) a; 36 | ``` 37 | 38 | # 说明 39 | 40 | * 只是审核操作,或者审核失败未执行时,不会进行操作统计。 41 | * goInception会记录实际执行的数据,即如果执行一部分后失败时,只记录实际执行的操作。 42 | * 备份出错导致提前返回时,不会影响统计信息。 43 | -------------------------------------------------------------------------------- /docs/zh/support.md: -------------------------------------------------------------------------------- 1 | # 赞助与支持 2 | 3 | 如果goInception于你有所帮助,可以激励一下作者以作支持。 4 | 5 | 您的企业or个人信息将会展示在 `赞助者名单` 中以作感谢。 6 | 7 | 对于大力赞助的企业与个人,可联系作者将公司或个人logo添加到项目首页,并优先考虑对其需求定制化开发。 8 | 9 | 12 | 13 | 18 | 19 |
20 | 支付宝 21 |
22 | 微信 23 |
24 | 25 | 26 | 27 | ------ 28 | 29 | ## 赞助者名单 30 | 31 | 32 | ------ 33 | 34 | ## 定制化需求 35 | 36 | 提供定制化服务。 37 | 38 | 具体事宜请通过邮箱或QQ群联系。 39 | 40 | 邮箱:`chuanchuanhan@gmail.com` 41 | 42 | QQ群:`499262190` 43 | -------------------------------------------------------------------------------- /docs/zh/trans.md: -------------------------------------------------------------------------------- 1 | 2 | # 事务 3 | 4 | ## 介绍 5 | 6 | 事务功能实现了DML语句按批次提交,以提高大批量DML语句的执行效率,以及保证事务一致性(`仅同一批次中`)。 7 | 8 | 以下详细说明配置方式以及涉及的回滚差异等。 9 | 10 | ## 配置 11 | 12 | 在调用goInception时添加参数`--trans=?`,其中参数值为数字, 13 | * 默认为0,即不开启事务(逐行提交) 14 | * 当大于1时,会按该参数分批进行提交,如500,则会按500条DML提交一次 15 | 16 | 17 | ### 示例 18 | ```py 19 | 20 | import pymysql 21 | 22 | sql = '''/*--host=127.0.0.1;--port=3306;--user=test;--password=test;\ 23 | --execute=1;--backup=1;--ignore-warnings=1;--trans=100;*/ 24 | inception_magic_start; 25 | use test_inc; 26 | 27 | -- drop table if exists t1; 28 | create table t1 (id int primary key,c1 int ,c2 varchar(100)); 29 | 30 | insert into t1 values(1,2,'ccc'); 31 | insert into t1 values(2,2,'ccc'); 32 | insert into t1 values(3,3,'ccc'); 33 | insert into t1 values(4,2,'ccc'); 34 | insert into t1 values(5,2,'ccc'); 35 | 36 | inception_magic_commit;''' 37 | 38 | conn = pymysql.connect(host='127.0.0.1', user='', passwd='', 39 | db='', port=4000, charset="utf8mb4") 40 | cur = conn.cursor() 41 | ret = cur.execute(sql) 42 | result = cur.fetchall() 43 | cur.close() 44 | conn.close() 45 | 46 | for row in result: 47 | print(row) 48 | ``` 49 | 50 | ## 执行 51 | 52 | * 未开启事务前为逐行提交 53 | * 开启事务后,按设置条数提交。如设为500,则会500条DML提交一次 54 | * DDL执行不受事务功能影响,和MySQL一样,其独立为一个事务 55 | * 当事务提交失败时,会`回滚该批次的SQL`,并立即中止(已执行SQL仍会生成回滚语句,以便有需要时快速回滚) 56 | 57 | 在事务中如果有DDL语句,会自动提交DML,因此`混合DDL和DML不会影响该功能`。 58 | -------------------------------------------------------------------------------- /domain/domainctx.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package domain 15 | 16 | import "github.com/hanchuanchuan/goInception/sessionctx" 17 | 18 | // domainKeyType is a dummy type to avoid naming collision in context. 19 | type domainKeyType int 20 | 21 | // String defines a Stringer function for debugging and pretty printing. 22 | func (k domainKeyType) String() string { 23 | return "domain" 24 | } 25 | 26 | const domainKey domainKeyType = 0 27 | 28 | // BindDomain binds domain to context. 29 | func BindDomain(ctx sessionctx.Context, domain *Domain) { 30 | ctx.SetValue(domainKey, domain) 31 | } 32 | 33 | // GetDomain gets domain from context. 34 | func GetDomain(ctx sessionctx.Context) *Domain { 35 | v, ok := ctx.Value(domainKey).(*Domain) 36 | if !ok { 37 | return nil 38 | } 39 | return v 40 | } 41 | -------------------------------------------------------------------------------- /domain/domainctx_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package domain 15 | 16 | import ( 17 | "github.com/hanchuanchuan/goInception/util/mock" 18 | "github.com/hanchuanchuan/goInception/util/testleak" 19 | . "github.com/pingcap/check" 20 | ) 21 | 22 | var _ = Suite(&testDomainCtxSuite{}) 23 | 24 | type testDomainCtxSuite struct { 25 | } 26 | 27 | func (s *testDomainCtxSuite) TestDomain(c *C) { 28 | defer testleak.AfterTest(c)() 29 | ctx := mock.NewContext() 30 | 31 | c.Assert(domainKey.String(), Not(Equals), "") 32 | 33 | BindDomain(ctx, nil) 34 | v := GetDomain(ctx) 35 | c.Assert(v, IsNil) 36 | 37 | ctx.ClearValue(domainKey) 38 | v = GetDomain(ctx) 39 | c.Assert(v, IsNil) 40 | } 41 | -------------------------------------------------------------------------------- /domain/global_vars_cache.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package domain 15 | 16 | import ( 17 | "sync" 18 | "time" 19 | 20 | "github.com/hanchuanchuan/goInception/ast" 21 | "github.com/hanchuanchuan/goInception/util/chunk" 22 | ) 23 | 24 | // GlobalVariableCache caches global variables. 25 | type GlobalVariableCache struct { 26 | sync.RWMutex 27 | lastModify time.Time 28 | rows []chunk.Row 29 | fields []*ast.ResultField 30 | } 31 | 32 | const globalVariableCacheExpiry time.Duration = 2 * time.Second 33 | 34 | // Update updates the global variable cache. 35 | func (gvc *GlobalVariableCache) Update(rows []chunk.Row, fields []*ast.ResultField) { 36 | gvc.Lock() 37 | gvc.lastModify = time.Now() 38 | gvc.rows = rows 39 | gvc.fields = fields 40 | gvc.Unlock() 41 | } 42 | 43 | // Get gets the global variables from cache. 44 | func (gvc *GlobalVariableCache) Get() (succ bool, rows []chunk.Row, fields []*ast.ResultField) { 45 | gvc.RLock() 46 | defer gvc.RUnlock() 47 | if time.Now().Sub(gvc.lastModify) < globalVariableCacheExpiry { 48 | succ, rows, fields = true, gvc.rows, gvc.fields 49 | return 50 | } 51 | succ = false 52 | return 53 | } 54 | 55 | // GetGlobalVarsCache gets the global variable cache. 56 | func (do *Domain) GetGlobalVarsCache() *GlobalVariableCache { 57 | return &do.gvc 58 | } 59 | -------------------------------------------------------------------------------- /domain/schema_checker.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package domain 15 | 16 | import ( 17 | "sync/atomic" 18 | "time" 19 | ) 20 | 21 | // SchemaChecker is used for checking schema-validity. 22 | type SchemaChecker struct { 23 | SchemaValidator 24 | schemaVer int64 25 | relatedTableIDs []int64 26 | } 27 | 28 | var ( 29 | // SchemaOutOfDateRetryInterval is the backoff time before retrying. 30 | SchemaOutOfDateRetryInterval = int64(500 * time.Millisecond) 31 | // SchemaOutOfDateRetryTimes is the max retry count when the schema is out of date. 32 | SchemaOutOfDateRetryTimes = int32(10) 33 | ) 34 | 35 | // NewSchemaChecker creates a new schema checker. 36 | func NewSchemaChecker(do *Domain, schemaVer int64, relatedTableIDs []int64) *SchemaChecker { 37 | return &SchemaChecker{ 38 | SchemaValidator: do.SchemaValidator, 39 | schemaVer: schemaVer, 40 | relatedTableIDs: relatedTableIDs, 41 | } 42 | } 43 | 44 | // Check checks the validity of the schema version. 45 | func (s *SchemaChecker) Check(txnTS uint64) error { 46 | schemaOutOfDateRetryInterval := atomic.LoadInt64(&SchemaOutOfDateRetryInterval) 47 | schemaOutOfDateRetryTimes := int(atomic.LoadInt32(&SchemaOutOfDateRetryTimes)) 48 | for i := 0; i < schemaOutOfDateRetryTimes; i++ { 49 | result := s.SchemaValidator.Check(txnTS, s.schemaVer, s.relatedTableIDs) 50 | switch result { 51 | case ResultSucc: 52 | return nil 53 | case ResultFail: 54 | return ErrInfoSchemaChanged 55 | case ResultUnknown: 56 | time.Sleep(time.Duration(schemaOutOfDateRetryInterval)) 57 | } 58 | 59 | } 60 | return ErrInfoSchemaExpired 61 | } 62 | -------------------------------------------------------------------------------- /executor/aggfuncs/aggfunc_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package aggfuncs_test 15 | 16 | import ( 17 | "testing" 18 | "time" 19 | 20 | "github.com/hanchuanchuan/goInception/parser" 21 | "github.com/hanchuanchuan/goInception/sessionctx" 22 | "github.com/hanchuanchuan/goInception/util/mock" 23 | "github.com/hanchuanchuan/goInception/util/testleak" 24 | . "github.com/pingcap/check" 25 | ) 26 | 27 | var _ = Suite(&testSuite{}) 28 | 29 | func TestT(t *testing.T) { 30 | CustomVerboseFlag = true 31 | TestingT(t) 32 | } 33 | 34 | type testSuite struct { 35 | *parser.Parser 36 | ctx sessionctx.Context 37 | } 38 | 39 | func (s *testSuite) SetUpSuite(c *C) { 40 | s.Parser = parser.New() 41 | s.ctx = mock.NewContext() 42 | s.ctx.GetSessionVars().StmtCtx.TimeZone = time.Local 43 | } 44 | 45 | func (s *testSuite) TearDownSuite(c *C) { 46 | } 47 | 48 | func (s *testSuite) SetUpTest(c *C) { 49 | s.ctx.GetSessionVars().PlanColumnID = 0 50 | testleak.BeforeTest() 51 | } 52 | 53 | func (s *testSuite) TearDownTest(c *C) { 54 | s.ctx.GetSessionVars().StmtCtx.SetWarnings(nil) 55 | testleak.AfterTest(c)() 56 | } 57 | -------------------------------------------------------------------------------- /executor/rowid_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package executor_test 15 | 16 | import ( 17 | "github.com/hanchuanchuan/goInception/util/testkit" 18 | . "github.com/pingcap/check" 19 | ) 20 | 21 | func (s *testSuite) TestExportRowID(c *C) { 22 | tk := testkit.NewTestKit(c, s.store) 23 | tk.MustExec("use test") 24 | tk.MustExec("drop table if exists t") 25 | tk.MustExec("create table t (a int, b int)") 26 | tk.MustExec("insert t values (1, 7), (1, 8), (1, 9)") 27 | tk.MustQuery("select *, _tidb_rowid from t"). 28 | Check(testkit.Rows("1 7 1", "1 8 2", "1 9 3")) 29 | tk.MustExec("update t set a = 2 where _tidb_rowid = 2") 30 | tk.MustQuery("select *, _tidb_rowid from t"). 31 | Check(testkit.Rows("1 7 1", "2 8 2", "1 9 3")) 32 | 33 | tk.MustExec("delete from t where _tidb_rowid = 2") 34 | tk.MustQuery("select *, _tidb_rowid from t"). 35 | Check(testkit.Rows("1 7 1", "1 9 3")) 36 | 37 | tk.MustExec("insert t (a, b, _tidb_rowid) values (2, 2, 2), (5, 5, 5)") 38 | tk.MustQuery("select *, _tidb_rowid from t"). 39 | Check(testkit.Rows("1 7 1", "2 2 2", "1 9 3", "5 5 5")) 40 | 41 | // If PK is handle, _tidb_rowid is unknown column. 42 | tk.MustExec("create table s (a int primary key)") 43 | tk.MustExec("insert s values (1)") 44 | _, err := tk.Exec("insert s (a, _tidb_rowid) values (1, 2)") 45 | c.Assert(err, NotNil) 46 | _, err = tk.Exec("select _tidb_rowid from s") 47 | c.Assert(err, NotNil) 48 | _, err = tk.Exec("update s set a = 2 where _tidb_rowid = 1") 49 | c.Assert(err, NotNil) 50 | _, err = tk.Exec("delete from s where _tidb_rowid = 1") 51 | c.Assert(err, NotNil) 52 | } 53 | -------------------------------------------------------------------------------- /executor/trace.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package executor 15 | 16 | import ( 17 | "github.com/hanchuanchuan/goInception/ast" 18 | "github.com/hanchuanchuan/goInception/planner" 19 | plannercore "github.com/hanchuanchuan/goInception/planner/core" 20 | "github.com/hanchuanchuan/goInception/util/chunk" 21 | "github.com/pingcap/errors" 22 | "golang.org/x/net/context" 23 | ) 24 | 25 | // TraceExec represents a root executor of trace query. 26 | type TraceExec struct { 27 | baseExecutor 28 | // exhausted being true means there is no more result. 29 | exhausted bool 30 | // stmtNode is the real query ast tree and it is used for building real query's plan. 31 | stmtNode ast.StmtNode 32 | 33 | builder *executorBuilder 34 | } 35 | 36 | // Next executes real query and collects span later. 37 | func (e *TraceExec) Next(ctx context.Context, chk *chunk.Chunk) error { 38 | chk.Reset() 39 | if e.exhausted { 40 | return nil 41 | } 42 | 43 | // record how much time was spent for optimizeing plan 44 | stmtPlan, err := planner.Optimize(e.builder.ctx, e.stmtNode, e.builder.is) 45 | if err != nil { 46 | return err 47 | } 48 | 49 | pp, ok := stmtPlan.(plannercore.PhysicalPlan) 50 | if !ok { 51 | return errors.New("cannot cast logical plan to physical plan") 52 | } 53 | 54 | // append select executor to trace executor 55 | stmtExec := e.builder.build(pp) 56 | 57 | err = stmtExec.Open(ctx) 58 | if err != nil { 59 | return errors.Trace(err) 60 | } 61 | stmtExecChk := stmtExec.newFirstChunk() 62 | 63 | for { 64 | if err := stmtExec.Next(ctx, stmtExecChk); err != nil { 65 | return errors.Trace(err) 66 | } 67 | if stmtExecChk.NumRows() == 0 { 68 | break 69 | } 70 | } 71 | 72 | e.exhausted = true 73 | return nil 74 | } 75 | -------------------------------------------------------------------------------- /executor/trace_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package executor_test 15 | 16 | import ( 17 | "github.com/hanchuanchuan/goInception/util/testkit" 18 | . "github.com/pingcap/check" 19 | ) 20 | 21 | type testTraceExec struct{} 22 | 23 | func (s *testTraceExec) SetupSuite(c *C) { 24 | } 25 | 26 | func (s *testSuite) TestTraceExec(c *C) { 27 | tk := testkit.NewTestKit(c, s.store) 28 | tk.MustExec("use test") 29 | testSQL := `create table trace (id int PRIMARY KEY AUTO_INCREMENT, c1 int, c2 int, c3 int default 1);` 30 | tk.MustExec(testSQL) 31 | // TODO: check result later in another PR. 32 | tk.MustExec("trace select * from trace where id = 0;") 33 | } 34 | -------------------------------------------------------------------------------- /expression/aggregation/agg_to_pb.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package aggregation 15 | 16 | import ( 17 | "github.com/hanchuanchuan/goInception/ast" 18 | "github.com/hanchuanchuan/goInception/expression" 19 | "github.com/hanchuanchuan/goInception/kv" 20 | "github.com/hanchuanchuan/goInception/sessionctx/stmtctx" 21 | "github.com/pingcap/tipb/go-tipb" 22 | ) 23 | 24 | // AggFuncToPBExpr converts aggregate function to pb. 25 | func AggFuncToPBExpr(sc *stmtctx.StatementContext, client kv.Client, aggFunc *AggFuncDesc) *tipb.Expr { 26 | if aggFunc.HasDistinct { 27 | return nil 28 | } 29 | pc := expression.NewPBConverter(client, sc) 30 | var tp tipb.ExprType 31 | switch aggFunc.Name { 32 | case ast.AggFuncCount: 33 | tp = tipb.ExprType_Count 34 | case ast.AggFuncFirstRow: 35 | tp = tipb.ExprType_First 36 | case ast.AggFuncGroupConcat: 37 | tp = tipb.ExprType_GroupConcat 38 | case ast.AggFuncMax: 39 | tp = tipb.ExprType_Max 40 | case ast.AggFuncMin: 41 | tp = tipb.ExprType_Min 42 | case ast.AggFuncSum: 43 | tp = tipb.ExprType_Sum 44 | case ast.AggFuncAvg: 45 | tp = tipb.ExprType_Avg 46 | case ast.AggFuncBitOr: 47 | tp = tipb.ExprType_Agg_BitOr 48 | case ast.AggFuncBitXor: 49 | tp = tipb.ExprType_Agg_BitXor 50 | case ast.AggFuncBitAnd: 51 | tp = tipb.ExprType_Agg_BitAnd 52 | } 53 | if !client.IsRequestTypeSupported(kv.ReqTypeSelect, int64(tp)) { 54 | return nil 55 | } 56 | 57 | children := make([]*tipb.Expr, 0, len(aggFunc.Args)) 58 | for _, arg := range aggFunc.Args { 59 | pbArg := pc.ExprToPB(arg) 60 | if pbArg == nil { 61 | return nil 62 | } 63 | children = append(children, pbArg) 64 | } 65 | return &tipb.Expr{Tp: tp, Children: children, FieldType: expression.ToPBFieldType(aggFunc.RetTp)} 66 | } 67 | -------------------------------------------------------------------------------- /expression/aggregation/explain.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package aggregation 15 | 16 | import ( 17 | "bytes" 18 | "fmt" 19 | ) 20 | 21 | // ExplainAggFunc generates explain information for a aggregation function. 22 | func ExplainAggFunc(agg *AggFuncDesc) string { 23 | var buffer bytes.Buffer 24 | fmt.Fprintf(&buffer, "%s(", agg.Name) 25 | if agg.HasDistinct { 26 | buffer.WriteString("distinct ") 27 | } 28 | for i, arg := range agg.Args { 29 | buffer.WriteString(arg.ExplainInfo()) 30 | if i+1 < len(agg.Args) { 31 | buffer.WriteString(", ") 32 | } 33 | } 34 | buffer.WriteString(")") 35 | return buffer.String() 36 | } 37 | -------------------------------------------------------------------------------- /expression/aggregation/first_row.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package aggregation 15 | 16 | import ( 17 | "github.com/hanchuanchuan/goInception/sessionctx/stmtctx" 18 | "github.com/hanchuanchuan/goInception/types" 19 | "github.com/hanchuanchuan/goInception/util/chunk" 20 | "github.com/pingcap/errors" 21 | ) 22 | 23 | type firstRowFunction struct { 24 | aggFunction 25 | } 26 | 27 | // Update implements Aggregation interface. 28 | func (ff *firstRowFunction) Update(evalCtx *AggEvaluateContext, sc *stmtctx.StatementContext, row chunk.Row) error { 29 | if evalCtx.GotFirstRow { 30 | return nil 31 | } 32 | if len(ff.Args) != 1 { 33 | return errors.New("Wrong number of args for AggFuncFirstRow") 34 | } 35 | value, err := ff.Args[0].Eval(row) 36 | if err != nil { 37 | return errors.Trace(err) 38 | } 39 | evalCtx.Value = types.CopyDatum(value) 40 | evalCtx.GotFirstRow = true 41 | return nil 42 | } 43 | 44 | // GetResult implements Aggregation interface. 45 | func (ff *firstRowFunction) GetResult(evalCtx *AggEvaluateContext) types.Datum { 46 | return evalCtx.Value 47 | } 48 | 49 | func (ff *firstRowFunction) ResetContext(_ *stmtctx.StatementContext, evalCtx *AggEvaluateContext) { 50 | evalCtx.GotFirstRow = false 51 | } 52 | 53 | // GetPartialResult implements Aggregation interface. 54 | func (ff *firstRowFunction) GetPartialResult(evalCtx *AggEvaluateContext) []types.Datum { 55 | return []types.Datum{ff.GetResult(evalCtx)} 56 | } 57 | -------------------------------------------------------------------------------- /expression/aggregation/max_min.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package aggregation 15 | 16 | import ( 17 | "github.com/hanchuanchuan/goInception/sessionctx/stmtctx" 18 | "github.com/hanchuanchuan/goInception/types" 19 | "github.com/hanchuanchuan/goInception/util/chunk" 20 | "github.com/pingcap/errors" 21 | ) 22 | 23 | type maxMinFunction struct { 24 | aggFunction 25 | isMax bool 26 | } 27 | 28 | // GetResult implements Aggregation interface. 29 | func (mmf *maxMinFunction) GetResult(evalCtx *AggEvaluateContext) (d types.Datum) { 30 | return evalCtx.Value 31 | } 32 | 33 | // GetPartialResult implements Aggregation interface. 34 | func (mmf *maxMinFunction) GetPartialResult(evalCtx *AggEvaluateContext) []types.Datum { 35 | return []types.Datum{mmf.GetResult(evalCtx)} 36 | } 37 | 38 | // Update implements Aggregation interface. 39 | func (mmf *maxMinFunction) Update(evalCtx *AggEvaluateContext, sc *stmtctx.StatementContext, row chunk.Row) error { 40 | a := mmf.Args[0] 41 | value, err := a.Eval(row) 42 | if err != nil { 43 | return errors.Trace(err) 44 | } 45 | if evalCtx.Value.IsNull() { 46 | evalCtx.Value = *(&value).Copy() 47 | } 48 | if value.IsNull() { 49 | return nil 50 | } 51 | var c int 52 | c, err = evalCtx.Value.CompareDatum(sc, &value) 53 | if err != nil { 54 | return errors.Trace(err) 55 | } 56 | if (mmf.isMax && c == -1) || (!mmf.isMax && c == 1) { 57 | evalCtx.Value = *(&value).Copy() 58 | } 59 | return nil 60 | } 61 | -------------------------------------------------------------------------------- /expression/aggregation/sum.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package aggregation 15 | 16 | import ( 17 | "github.com/hanchuanchuan/goInception/sessionctx/stmtctx" 18 | "github.com/hanchuanchuan/goInception/types" 19 | "github.com/hanchuanchuan/goInception/util/chunk" 20 | ) 21 | 22 | type sumFunction struct { 23 | aggFunction 24 | } 25 | 26 | // Update implements Aggregation interface. 27 | func (sf *sumFunction) Update(evalCtx *AggEvaluateContext, sc *stmtctx.StatementContext, row chunk.Row) error { 28 | return sf.updateSum(sc, evalCtx, row) 29 | } 30 | 31 | // GetResult implements Aggregation interface. 32 | func (sf *sumFunction) GetResult(evalCtx *AggEvaluateContext) (d types.Datum) { 33 | return evalCtx.Value 34 | } 35 | 36 | // GetPartialResult implements Aggregation interface. 37 | func (sf *sumFunction) GetPartialResult(evalCtx *AggEvaluateContext) []types.Datum { 38 | return []types.Datum{sf.GetResult(evalCtx)} 39 | } 40 | -------------------------------------------------------------------------------- /expression/aggregation/util_test.go: -------------------------------------------------------------------------------- 1 | package aggregation 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/hanchuanchuan/goInception/sessionctx/stmtctx" 7 | "github.com/hanchuanchuan/goInception/types" 8 | "github.com/hanchuanchuan/goInception/util/testleak" 9 | "github.com/pingcap/check" 10 | ) 11 | 12 | var _ = check.Suite(&testUtilSuite{}) 13 | 14 | type testUtilSuite struct { 15 | } 16 | 17 | func (s *testUtilSuite) TestDistinct(c *check.C) { 18 | defer testleak.AfterTest(c)() 19 | sc := &stmtctx.StatementContext{TimeZone: time.Local} 20 | dc := createDistinctChecker(sc) 21 | tests := []struct { 22 | vals []interface{} 23 | expect bool 24 | }{ 25 | {[]interface{}{1, 1}, true}, 26 | {[]interface{}{1, 1}, false}, 27 | {[]interface{}{1, 2}, true}, 28 | {[]interface{}{1, 2}, false}, 29 | {[]interface{}{1, nil}, true}, 30 | {[]interface{}{1, nil}, false}, 31 | } 32 | for _, tt := range tests { 33 | d, err := dc.Check(types.MakeDatums(tt.vals...)) 34 | c.Assert(err, check.IsNil) 35 | c.Assert(d, check.Equals, tt.expect) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /expression/function_traits.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package expression 15 | 16 | import ( 17 | "github.com/hanchuanchuan/goInception/ast" 18 | ) 19 | 20 | // UnCacheableFunctions stores functions which can not be cached to plan cache. 21 | var UnCacheableFunctions = map[string]struct{}{ 22 | ast.Now: {}, 23 | ast.CurrentTimestamp: {}, 24 | ast.UTCTime: {}, 25 | ast.Curtime: {}, 26 | ast.CurrentTime: {}, 27 | ast.UTCTimestamp: {}, 28 | ast.UnixTimestamp: {}, 29 | ast.Sysdate: {}, 30 | ast.Curdate: {}, 31 | ast.CurrentDate: {}, 32 | ast.UTCDate: {}, 33 | ast.Database: {}, 34 | ast.CurrentUser: {}, 35 | ast.User: {}, 36 | ast.ConnectionID: {}, 37 | ast.LastInsertId: {}, 38 | ast.Version: {}, 39 | } 40 | 41 | // unFoldableFunctions stores functions which can not be folded duration constant folding stage. 42 | var unFoldableFunctions = map[string]struct{}{ 43 | ast.Sysdate: {}, 44 | ast.FoundRows: {}, 45 | ast.Rand: {}, 46 | ast.UUID: {}, 47 | ast.Sleep: {}, 48 | ast.RowFunc: {}, 49 | ast.Values: {}, 50 | ast.SetVar: {}, 51 | ast.GetVar: {}, 52 | ast.GetParam: {}, 53 | } 54 | 55 | // inequalFunctions stores functions which cannot be propagated from column equal condition. 56 | var inequalFunctions = map[string]struct{}{ 57 | ast.IsNull: {}, 58 | } 59 | -------------------------------------------------------------------------------- /expression/function_traits_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package expression 15 | 16 | import ( 17 | "github.com/hanchuanchuan/goInception/ast" 18 | "github.com/hanchuanchuan/goInception/util/testleak" 19 | . "github.com/pingcap/check" 20 | ) 21 | 22 | func (s *testEvaluatorSuite) TestUnfoldableFuncs(c *C) { 23 | defer testleak.AfterTest(c)() 24 | _, ok := unFoldableFunctions[ast.Sysdate] 25 | c.Assert(ok, IsTrue) 26 | } 27 | -------------------------------------------------------------------------------- /gitcookie.sh: -------------------------------------------------------------------------------- 1 | touch ~/.gitcookies 2 | chmod 0600 ~/.gitcookies 3 | 4 | git config --global http.cookiefile ~/.gitcookies 5 | 6 | tr , \\t <<\__END__ >>~/.gitcookies 7 | go.googlesource.com,FALSE,/,TRUE,2147483647,o,git-shenli.pingcap.com=1/rGvVlvFq_x9rxOmXqQe_rfcrjbOk6NSOHIQKhhsfidM 8 | go-review.googlesource.com,FALSE,/,TRUE,2147483647,o,git-shenli.pingcap.com=1/rGvVlvFq_x9rxOmXqQe_rfcrjbOk6NSOHIQKhhsfidM 9 | __END__ 10 | 11 | -------------------------------------------------------------------------------- /hack/clean_vendor.sh: -------------------------------------------------------------------------------- 1 | # delete internal vendor folders 2 | find vendor -type d -name "_vendor" | xargs -I {} rm -r {} 3 | # delete all files that are not go, c, h, or legal 4 | find vendor -type f -not -name "*.go" -not -name "NOTICE*" -not -name "COPYING*" -not -name "LICENSE*" -not -name "*.s" -not -name "PATENTS*" -not -name "*.h" -not -name "*.c" | xargs -I {} rm {} 5 | # delete all generated files 6 | find vendor -type f -name "*_generated.go" | xargs -I {} rm {} 7 | # delete all test files 8 | find vendor -type f -name "*_test.go" | xargs -I {} rm {} 9 | find vendor -type d -name "fixtures" | xargs -I {} rm -r {} 10 | # Delete documentation files. Keep doc.go. 11 | find vendor -type d -name "Documentation" | xargs -I {} rm -r {} 12 | find vendor -type d -name "tutorial" | xargs -I {} rm -r {} 13 | find vendor -name "*.md" | xargs -I {} rm {} 14 | # Delete unused languages 15 | find vendor -type d -name "ruby" | xargs -I {} rm -r {} 16 | -------------------------------------------------------------------------------- /hack/retool-install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | # This script generates tools.json 5 | # It helps record what releases/branches are being used 6 | which retool >/dev/null || go get github.com/twitchtv/retool 7 | 8 | # This tool can run other checks in a standardized way 9 | retool add gopkg.in/alecthomas/gometalinter.v2 v2.0.5 10 | 11 | # check spelling 12 | # misspell works with gometalinter 13 | retool add github.com/client9/misspell/cmd/misspell v0.3.4 14 | # goword adds additional capability to check comments 15 | retool add github.com/chzchzchz/goword a9744cb52b033fe5c269df48eeef2c954526cd79 16 | 17 | # checks correctness 18 | retool add github.com/gordonklaus/ineffassign 7bae11eba15a3285c75e388f77eb6357a2d73ee2 19 | retool add honnef.co/go/tools/cmd/megacheck master 20 | retool add github.com/dnephin/govet 4a96d43e39d340b63daa8bc5576985aa599885f6 21 | 22 | # slow checks 23 | retool add github.com/kisielk/errcheck v1.1.0 24 | retool add github.com/securego/gosec/cmd/gosec 1.0.0 25 | 26 | # linter 27 | retool add github.com/mgechev/revive 7773f47324c2bf1c8f7a5500aff2b6c01d3ed73b 28 | -------------------------------------------------------------------------------- /kv/buffer_store_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package kv 15 | 16 | import ( 17 | "bytes" 18 | "fmt" 19 | 20 | . "github.com/pingcap/check" 21 | ) 22 | 23 | type testBufferStoreSuite struct{} 24 | 25 | var _ = Suite(testBufferStoreSuite{}) 26 | 27 | func (s testBufferStoreSuite) TestGetSet(c *C) { 28 | bs := NewBufferStore(&mockSnapshot{NewMemDbBuffer(DefaultTxnMembufCap)}, DefaultTxnMembufCap) 29 | key := Key("key") 30 | value, err := bs.Get(key) 31 | c.Check(err, NotNil) 32 | 33 | err = bs.Set(key, []byte("value")) 34 | c.Check(err, IsNil) 35 | 36 | value, err = bs.Get(key) 37 | c.Check(err, IsNil) 38 | c.Check(bytes.Compare(value, []byte("value")), Equals, 0) 39 | } 40 | 41 | func (s testBufferStoreSuite) TestSaveTo(c *C) { 42 | bs := NewBufferStore(&mockSnapshot{NewMemDbBuffer(DefaultTxnMembufCap)}, DefaultTxnMembufCap) 43 | var buf bytes.Buffer 44 | for i := 0; i < 10; i++ { 45 | fmt.Fprint(&buf, i) 46 | err := bs.Set(buf.Bytes(), buf.Bytes()) 47 | c.Check(err, IsNil) 48 | buf.Reset() 49 | } 50 | bs.Set(Key("novalue"), nil) 51 | 52 | mutator := NewMemDbBuffer(DefaultTxnMembufCap) 53 | err := bs.SaveTo(mutator) 54 | c.Check(err, IsNil) 55 | 56 | iter, err := mutator.Seek(nil) 57 | c.Check(err, IsNil) 58 | for iter.Valid() { 59 | cmp := bytes.Compare(iter.Key(), iter.Value()) 60 | c.Check(cmp, Equals, 0) 61 | iter.Next() 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /kv/fault_injection_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package kv_test 15 | 16 | import ( 17 | "github.com/hanchuanchuan/goInception/kv" 18 | . "github.com/pingcap/check" 19 | "github.com/pingcap/errors" 20 | ) 21 | 22 | type testFaultInjectionSuite struct{} 23 | 24 | var _ = Suite(testFaultInjectionSuite{}) 25 | 26 | func (s testFaultInjectionSuite) TestFaultInjectionBasic(c *C) { 27 | var cfg kv.InjectionConfig 28 | err := errors.New("foo") 29 | cfg.SetGetError(err) 30 | 31 | storage := kv.NewInjectedStore(kv.NewMockStorage(), &cfg) 32 | txn, err := storage.Begin() 33 | c.Assert(err, IsNil) 34 | _, err = storage.BeginWithStartTS(0) 35 | c.Assert(err, IsNil) 36 | ver := kv.Version{Ver: 1} 37 | snap, err := storage.GetSnapshot(ver) 38 | c.Assert(err, IsNil) 39 | b, err := txn.Get([]byte{'a'}) 40 | c.Assert(err.Error(), Equals, errors.New("foo").Error()) 41 | c.Assert(b, IsNil) 42 | b, err = snap.Get([]byte{'a'}) 43 | c.Assert(err.Error(), Equals, errors.New("foo").Error()) 44 | c.Assert(b, IsNil) 45 | } 46 | -------------------------------------------------------------------------------- /kv/iter.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package kv 15 | 16 | import "github.com/pingcap/errors" 17 | 18 | // NextUntil applies FnKeyCmp to each entry of the iterator until meets some condition. 19 | // It will stop when fn returns true, or iterator is invalid or an error occurs. 20 | func NextUntil(it Iterator, fn FnKeyCmp) error { 21 | var err error 22 | for it.Valid() && !fn(it.Key()) { 23 | err = it.Next() 24 | if err != nil { 25 | return errors.Trace(err) 26 | } 27 | } 28 | return nil 29 | } 30 | -------------------------------------------------------------------------------- /kv/txn_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package kv 15 | 16 | import ( 17 | "time" 18 | 19 | "github.com/hanchuanchuan/goInception/util/testleak" 20 | . "github.com/pingcap/check" 21 | ) 22 | 23 | var _ = Suite(&testTxnSuite{}) 24 | 25 | type testTxnSuite struct { 26 | } 27 | 28 | func (s *testTxnSuite) SetUpTest(c *C) { 29 | } 30 | 31 | func (s *testTxnSuite) TearDownTest(c *C) { 32 | } 33 | 34 | func (s *testTxnSuite) TestBackOff(c *C) { 35 | defer testleak.AfterTest(c)() 36 | mustBackOff(c, 1, 2) 37 | mustBackOff(c, 2, 4) 38 | mustBackOff(c, 3, 8) 39 | mustBackOff(c, 100000, 100) 40 | } 41 | 42 | func mustBackOff(c *C, cnt uint, sleep int) { 43 | c.Assert(BackOff(cnt), LessEqual, sleep*int(time.Millisecond)) 44 | } 45 | 46 | func (s *testTxnSuite) TestRetryExceedCountError(c *C) { 47 | defer testleak.AfterTest(c)() 48 | maxRetryCnt = 5 49 | err := RunInNewTxn(&mockStorage{}, true, func(txn Transaction) error { 50 | return nil 51 | }) 52 | c.Assert(err, NotNil) 53 | maxRetryCnt = 100 54 | } 55 | -------------------------------------------------------------------------------- /kv/utils.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package kv 15 | 16 | import ( 17 | "strconv" 18 | 19 | "github.com/pingcap/errors" 20 | ) 21 | 22 | // IncInt64 increases the value for key k in kv store by step. 23 | func IncInt64(rm RetrieverMutator, k Key, step int64) (int64, error) { 24 | val, err := rm.Get(k) 25 | if IsErrNotFound(err) { 26 | err = rm.Set(k, []byte(strconv.FormatInt(step, 10))) 27 | if err != nil { 28 | return 0, errors.Trace(err) 29 | } 30 | return step, nil 31 | } 32 | if err != nil { 33 | return 0, errors.Trace(err) 34 | } 35 | 36 | intVal, err := strconv.ParseInt(string(val), 10, 0) 37 | if err != nil { 38 | return 0, errors.Trace(err) 39 | } 40 | 41 | intVal += step 42 | err = rm.Set(k, []byte(strconv.FormatInt(intVal, 10))) 43 | if err != nil { 44 | return 0, errors.Trace(err) 45 | } 46 | return intVal, nil 47 | } 48 | 49 | // GetInt64 get int64 value which created by IncInt64 method. 50 | func GetInt64(r Retriever, k Key) (int64, error) { 51 | val, err := r.Get(k) 52 | if IsErrNotFound(err) { 53 | return 0, nil 54 | } 55 | if err != nil { 56 | return 0, errors.Trace(err) 57 | } 58 | intVal, err := strconv.ParseInt(string(val), 10, 0) 59 | return intVal, errors.Trace(err) 60 | } 61 | -------------------------------------------------------------------------------- /kv/utils_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package kv 15 | 16 | import ( 17 | . "github.com/pingcap/check" 18 | ) 19 | 20 | var _ = Suite(testUtilsSuite{}) 21 | 22 | type testUtilsSuite struct { 23 | } 24 | 25 | func (s testUtilsSuite) TestIncInt64(c *C) { 26 | mb := NewMemDbBuffer(DefaultTxnMembufCap) 27 | key := Key("key") 28 | v, err := IncInt64(mb, key, 1) 29 | c.Check(err, IsNil) 30 | c.Check(v, Equals, int64(1)) 31 | v, err = IncInt64(mb, key, 10) 32 | c.Check(err, IsNil) 33 | c.Check(v, Equals, int64(11)) 34 | 35 | mb.Set(key, []byte("not int")) 36 | _, err = IncInt64(mb, key, 1) 37 | c.Check(err, NotNil) 38 | } 39 | 40 | func (s testUtilsSuite) TestGetInt64(c *C) { 41 | mb := NewMemDbBuffer(DefaultTxnMembufCap) 42 | key := Key("key") 43 | v, err := GetInt64(mb, key) 44 | c.Check(v, Equals, int64(0)) 45 | c.Check(err, IsNil) 46 | 47 | _, err = IncInt64(mb, key, 15) 48 | c.Check(err, IsNil) 49 | v, err = GetInt64(mb, key) 50 | c.Check(v, Equals, int64(15)) 51 | c.Check(err, IsNil) 52 | } 53 | -------------------------------------------------------------------------------- /kv/variables.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package kv 15 | 16 | // Variables defines the variables used by KV storage. 17 | type Variables struct { 18 | // BackoffLockFast specifies the LockFast backoff base duration in milliseconds. 19 | BackoffLockFast int 20 | 21 | // Hook is used for test to verify the variable take effect. 22 | Hook func(name string, vars *Variables) 23 | } 24 | 25 | // NewVariables create a new Variables instance with default values. 26 | func NewVariables() *Variables { 27 | return &Variables{ 28 | BackoffLockFast: DefBackoffLockFast, 29 | } 30 | } 31 | 32 | // DefaultVars is the default variables instance. 33 | var DefaultVars = NewVariables() 34 | 35 | // Default values 36 | const ( 37 | DefBackoffLockFast = 100 38 | ) 39 | -------------------------------------------------------------------------------- /kv/version.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package kv 15 | 16 | import "math" 17 | 18 | // VersionProvider provides increasing IDs. 19 | type VersionProvider interface { 20 | CurrentVersion() (Version, error) 21 | } 22 | 23 | // Version is the wrapper of KV's version. 24 | type Version struct { 25 | Ver uint64 26 | } 27 | 28 | var ( 29 | // MaxVersion is the maximum version, notice that it's not a valid version. 30 | MaxVersion = Version{Ver: math.MaxUint64} 31 | // MinVersion is the minimum version, it's not a valid version, too. 32 | MinVersion = Version{Ver: 0} 33 | ) 34 | 35 | // NewVersion creates a new Version struct. 36 | func NewVersion(v uint64) Version { 37 | return Version{ 38 | Ver: v, 39 | } 40 | } 41 | 42 | // Cmp returns the comparison result of two versions. 43 | // The result will be 0 if a==b, -1 if a < b, and +1 if a > b. 44 | func (v Version) Cmp(another Version) int { 45 | if v.Ver > another.Ver { 46 | return 1 47 | } else if v.Ver < another.Ver { 48 | return -1 49 | } 50 | return 0 51 | } 52 | -------------------------------------------------------------------------------- /kv/version_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package kv 15 | 16 | import ( 17 | . "github.com/pingcap/check" 18 | ) 19 | 20 | var _ = Suite(testVersionSuite{}) 21 | 22 | type testVersionSuite struct{} 23 | 24 | func (s testVersionSuite) TestVersion(c *C) { 25 | le := NewVersion(42).Cmp(NewVersion(43)) 26 | gt := NewVersion(42).Cmp(NewVersion(41)) 27 | eq := NewVersion(42).Cmp(NewVersion(42)) 28 | 29 | c.Assert(le < 0, IsTrue) 30 | c.Assert(gt > 0, IsTrue) 31 | c.Assert(eq == 0, IsTrue) 32 | 33 | c.Check(MinVersion.Cmp(MaxVersion) < 0, IsTrue) 34 | } 35 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: goInception使用文档 2 | site_url: https://github.com/hanchuanchuan/goInception/ 3 | repo_url: https://github.com/hanchuanchuan/goInception/ 4 | repo_name: GitHub 5 | site_description: goInception使用文档 6 | site_author: hanchuanchuan 7 | theme: 8 | name: material 9 | font: 10 | text: Ubuntu 11 | code: Ubuntu Mono 12 | icon: 13 | logo: material/file-document-multiple 14 | palette: 15 | primary: blue 16 | dev_addr: 0.0.0.0:8000 17 | plugins: 18 | - search 19 | - i18n: 20 | default_language: zh 21 | languages: 22 | en: English 23 | zh: 中文 24 | # nav_translations: 25 | # en: 26 | # 开始: Start 27 | # zh: 28 | # 开始: 开始 29 | 30 | # pages: 31 | # - ['README.md', 'Introduction'] 32 | # - ['user-guide.md', 'User Guide'] 33 | # - ['about.md', 'About'] 34 | 35 | nav: 36 | - 介绍 : README.md 37 | - 开始: 38 | - 安装: install.md 39 | - 调用选项: params.md 40 | - 使用示例: demo.md 41 | - 结果集说明: result.md 42 | - config.toml说明: config.md 43 | - 权限说明: permission.md 44 | 45 | - 配置: 46 | - 审核选项: options.md 47 | - 审核规则: rules.md 48 | - 备份功能: backup.md 49 | - DDL变更:pt-osc: osc.md 50 | - DDL变更:gh-ost: ghost.md 51 | 52 | - 进阶: 53 | - 自定义审核级别: levels.md 54 | - KILL操作: kill_stmt.md 55 | - 统计功能: statistics.md 56 | - 语法树打印: tree.md 57 | - 事务: trans.md 58 | - 用户管理/鉴权: safe.md 59 | - 对比inception: diff.md 60 | 61 | - 赞助&定制: support.md 62 | - 更新日志: changelog.md 63 | -------------------------------------------------------------------------------- /mysql/error.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package mysql 15 | 16 | import ( 17 | "errors" 18 | "fmt" 19 | ) 20 | 21 | // Portable analogs of some common call errors. 22 | var ( 23 | ErrBadConn = errors.New("connection was bad") 24 | ErrMalformPacket = errors.New("malform packet error") 25 | ) 26 | 27 | // SQLError records an error information, from executing SQL. 28 | type SQLError struct { 29 | Code uint16 30 | Message string 31 | State string 32 | } 33 | 34 | // Error prints errors, with a formatted string. 35 | func (e *SQLError) Error() string { 36 | return fmt.Sprintf("ERROR %d (%s): %s", e.Code, e.State, e.Message) 37 | } 38 | 39 | // NewErr generates a SQL error, with an error code and default format specifier defined in MySQLErrName. 40 | func NewErr(errCode uint16, args ...interface{}) *SQLError { 41 | e := &SQLError{Code: errCode} 42 | 43 | if s, ok := MySQLState[errCode]; ok { 44 | e.State = s 45 | } else { 46 | e.State = DefaultMySQLState 47 | } 48 | 49 | if format, ok := MySQLErrName[errCode]; ok { 50 | e.Message = fmt.Sprintf(format, args...) 51 | } else { 52 | e.Message = fmt.Sprint(args...) 53 | } 54 | 55 | return e 56 | } 57 | 58 | // NewErrf creates a SQL error, with an error code and a format specifier. 59 | func NewErrf(errCode uint16, format string, args ...interface{}) *SQLError { 60 | e := &SQLError{Code: errCode} 61 | 62 | if s, ok := MySQLState[errCode]; ok { 63 | e.State = s 64 | } else { 65 | e.State = DefaultMySQLState 66 | } 67 | 68 | e.Message = fmt.Sprintf(format, args...) 69 | 70 | return e 71 | } 72 | -------------------------------------------------------------------------------- /mysql/error_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package mysql 15 | 16 | import ( 17 | . "github.com/pingcap/check" 18 | ) 19 | 20 | var _ = Suite(&testSQLErrorSuite{}) 21 | 22 | type testSQLErrorSuite struct { 23 | } 24 | 25 | func (s *testSQLErrorSuite) TestSQLError(c *C) { 26 | e := NewErrf(ErrNoDB, "no db error") 27 | c.Assert(len(e.Error()), Greater, 0) 28 | 29 | e = NewErrf(0, "customized error") 30 | c.Assert(len(e.Error()), Greater, 0) 31 | 32 | e = NewErr(ErrNoDB) 33 | c.Assert(len(e.Error()), Greater, 0) 34 | 35 | e = NewErr(0, "customized error") 36 | c.Assert(len(e.Error()), Greater, 0) 37 | } 38 | -------------------------------------------------------------------------------- /mysql/type_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package mysql 15 | 16 | import ( 17 | . "github.com/pingcap/check" 18 | ) 19 | 20 | var _ = Suite(&testTypeSuite{}) 21 | 22 | type testTypeSuite struct{} 23 | 24 | func (s *testTypeSuite) TestFlags(c *C) { 25 | c.Assert(HasNotNullFlag(NotNullFlag), IsTrue) 26 | c.Assert(HasUniKeyFlag(UniqueKeyFlag), IsTrue) 27 | c.Assert(HasNotNullFlag(NotNullFlag), IsTrue) 28 | c.Assert(HasNoDefaultValueFlag(NoDefaultValueFlag), IsTrue) 29 | c.Assert(HasAutoIncrementFlag(AutoIncrementFlag), IsTrue) 30 | c.Assert(HasUnsignedFlag(UnsignedFlag), IsTrue) 31 | c.Assert(HasZerofillFlag(ZerofillFlag), IsTrue) 32 | c.Assert(HasBinaryFlag(BinaryFlag), IsTrue) 33 | c.Assert(HasPriKeyFlag(PriKeyFlag), IsTrue) 34 | c.Assert(HasMultipleKeyFlag(MultipleKeyFlag), IsTrue) 35 | c.Assert(HasTimestampFlag(TimestampFlag), IsTrue) 36 | c.Assert(HasOnUpdateNowFlag(OnUpdateNowFlag), IsTrue) 37 | } 38 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "goInception", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "repository": "https://github.com/hanchuanchuan/goInception.git", 6 | "author": "hanchuanchuan", 7 | "license": "GPL-3.0", 8 | "devDependencies": { 9 | "axios": "0.21.2", 10 | "less": "^4.1.1", 11 | "less-loader": "7.3.0", 12 | "node-less": "^1.0.0", 13 | "vuepress": "^1.8.2" 14 | }, 15 | "scripts": { 16 | "docs:dev": "vuepress dev docs", 17 | "docs:build-test": "node ./build/addComponents.js && vuepress build docs && node ./build/delComponents.js", 18 | "docs:build": "vuepress build docs" 19 | }, 20 | "dependencies": { 21 | "gitalk": "^1.7.2" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /parser/opcode/opcode_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package opcode 15 | 16 | import ( 17 | "bytes" 18 | "testing" 19 | ) 20 | 21 | func TestT(t *testing.T) { 22 | op := Plus 23 | if op.String() != "plus" { 24 | t.Fatalf("invalid op code") 25 | } 26 | 27 | if len(Ops) != len(opsLiteral) { 28 | t.Error("inconsistent count ops and opsliteral") 29 | } 30 | var buf bytes.Buffer 31 | for op := range Ops { 32 | op.Format(&buf) 33 | if buf.String() != opsLiteral[op] { 34 | t.Error("format op fail", op) 35 | } 36 | buf.Reset() 37 | } 38 | 39 | // Test invalid opcode 40 | defer func() { 41 | recover() 42 | }() 43 | 44 | op = 0 45 | s := op.String() 46 | if len(s) > 0 { 47 | t.Fail() 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /planner/core/cache_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // // Unless required by applicable law or agreed to in writing, software 9 | // distributed under the License is distributed on an "AS IS" BASIS, 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | package core 14 | 15 | import ( 16 | "time" 17 | 18 | "github.com/hanchuanchuan/goInception/mysql" 19 | "github.com/hanchuanchuan/goInception/sessionctx" 20 | "github.com/hanchuanchuan/goInception/util/testleak" 21 | . "github.com/pingcap/check" 22 | ) 23 | 24 | var _ = Suite(&testCacheSuite{}) 25 | 26 | type testCacheSuite struct { 27 | ctx sessionctx.Context 28 | } 29 | 30 | func (s *testCacheSuite) SetUpSuite(c *C) { 31 | ctx := mockContext() 32 | ctx.GetSessionVars().SnapshotTS = 0 33 | ctx.GetSessionVars().SQLMode = mysql.ModeNone 34 | ctx.GetSessionVars().TimeZone = time.UTC 35 | ctx.GetSessionVars().ConnectionID = 0 36 | s.ctx = ctx 37 | } 38 | 39 | func (s *testCacheSuite) TestCacheKey(c *C) { 40 | defer testleak.AfterTest(c)() 41 | key := NewPSTMTPlanCacheKey(s.ctx.GetSessionVars(), 1, 1) 42 | c.Assert(key.Hash(), DeepEquals, []byte{0x74, 0x65, 0x73, 0x74, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}) 43 | } 44 | -------------------------------------------------------------------------------- /planner/core/trace.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "github.com/hanchuanchuan/goInception/ast" 5 | ) 6 | 7 | // Trace represents a trace plan. 8 | type Trace struct { 9 | baseSchemaProducer 10 | 11 | StmtNode ast.StmtNode 12 | } 13 | -------------------------------------------------------------------------------- /planner/property/task_type.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package property 15 | 16 | // TaskType is the type of execution task. 17 | type TaskType int 18 | 19 | const ( 20 | // RootTaskType stands for the tasks that executed in the TiDB layer. 21 | RootTaskType TaskType = iota 22 | 23 | // CopSingleReadTaskType stands for the a TableScan or IndexScan tasks 24 | // executed in the coprocessor layer. 25 | CopSingleReadTaskType 26 | 27 | // CopDoubleReadTaskType stands for the a IndexLookup tasks executed in the 28 | // coprocessor layer. 29 | CopDoubleReadTaskType 30 | ) 31 | 32 | // String implements fmt.Stringer interface. 33 | func (t TaskType) String() string { 34 | switch t { 35 | case RootTaskType: 36 | return "rootTask" 37 | case CopSingleReadTaskType: 38 | return "copSingleReadTask" 39 | case CopDoubleReadTaskType: 40 | return "copDoubleReadTask" 41 | } 42 | return "UnknownTaskType" 43 | } 44 | -------------------------------------------------------------------------------- /revive.toml: -------------------------------------------------------------------------------- 1 | ignoreGeneratedHeader = false 2 | severity = "error" 3 | confidence = 0.8 4 | errorCode = -1 5 | warningCode = -1 6 | 7 | [rule.blank-imports] 8 | [rule.context-as-argument] 9 | [rule.dot-imports] 10 | [rule.error-return] 11 | [rule.error-strings] 12 | [rule.error-naming] 13 | [rule.exported] 14 | [rule.if-return] 15 | [rule.var-naming] 16 | [rule.package-comments] 17 | [rule.range] 18 | [rule.receiver-naming] 19 | [rule.indent-error-flow] 20 | [rule.superfluous-else] 21 | [rule.modifies-parameter] 22 | 23 | # This can be checked by other tools like megacheck 24 | [rule.unreachable-code] 25 | 26 | 27 | # Currently this makes too much noise, but should add it in 28 | # and perhaps ignore it in a few files 29 | #[rule.confusing-naming] 30 | # severity = "warning" 31 | #[rule.confusing-results] 32 | # severity = "warning" 33 | #[rule.unused-parameter] 34 | # severity = "warning" 35 | #[rule.deep-exit] 36 | # severity = "warning" 37 | #[rule.flag-parameter] 38 | # severity = "warning" 39 | 40 | 41 | 42 | # Adding these will slow down the linter 43 | # They are already provided by megacheck 44 | # [rule.unexported-return] 45 | # [rule.time-naming] 46 | # [rule.errorf] 47 | 48 | # Adding these will slow down the linter 49 | # Not sure if they are already provided by megacheck 50 | # [rule.var-declaration] 51 | # [rule.context-keys-type] 52 | -------------------------------------------------------------------------------- /server/buffered_read_conn.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package server 15 | 16 | import ( 17 | "bufio" 18 | "net" 19 | ) 20 | 21 | const defaultReaderSize = 16 * 1024 22 | 23 | // bufferedReadConn is a net.Conn compatible structure that reads from bufio.Reader. 24 | type bufferedReadConn struct { 25 | net.Conn 26 | rb *bufio.Reader 27 | } 28 | 29 | func (conn bufferedReadConn) Read(b []byte) (n int, err error) { 30 | return conn.rb.Read(b) 31 | } 32 | 33 | func newBufferedReadConn(conn net.Conn) *bufferedReadConn { 34 | return &bufferedReadConn{ 35 | Conn: conn, 36 | rb: bufio.NewReaderSize(conn, defaultReaderSize), 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /server/statistics_handler.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package server 15 | 16 | import ( 17 | "net/http" 18 | 19 | "github.com/gorilla/mux" 20 | "github.com/hanchuanchuan/goInception/domain" 21 | "github.com/hanchuanchuan/goInception/model" 22 | ) 23 | 24 | // StatsHandler is the handler for dumping statistics. 25 | type StatsHandler struct { 26 | do *domain.Domain 27 | } 28 | 29 | func (sh StatsHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { 30 | w.Header().Set("Content-Type", "application/json") 31 | 32 | params := mux.Vars(req) 33 | 34 | is := sh.do.InfoSchema() 35 | h := sh.do.StatsHandle() 36 | tbl, err := is.TableByName(model.NewCIStr(params[pDBName]), model.NewCIStr(params[pTableName])) 37 | if err != nil { 38 | writeError(w, err) 39 | } else { 40 | js, err := h.DumpStatsToJSON(params[pDBName], tbl.Meta()) 41 | if err != nil { 42 | writeError(w, err) 43 | } else { 44 | writeData(w, js) 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /server/tokenlimiter.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package server 15 | 16 | // Token is used as a permission to keep on running. 17 | type Token struct { 18 | } 19 | 20 | // TokenLimiter is used to limit the number of concurrent tasks. 21 | type TokenLimiter struct { 22 | count uint 23 | ch chan *Token 24 | } 25 | 26 | // Put releases the token. 27 | func (tl *TokenLimiter) Put(tk *Token) { 28 | tl.ch <- tk 29 | } 30 | 31 | // Get obtains a token. 32 | func (tl *TokenLimiter) Get() *Token { 33 | return <-tl.ch 34 | } 35 | 36 | // NewTokenLimiter creates a TokenLimiter with count tokens. 37 | func NewTokenLimiter(count uint) *TokenLimiter { 38 | tl := &TokenLimiter{count: count, ch: make(chan *Token, count)} 39 | for i := uint(0); i < count; i++ { 40 | tl.ch <- &Token{} 41 | } 42 | 43 | return tl 44 | } 45 | -------------------------------------------------------------------------------- /session/socket.go: -------------------------------------------------------------------------------- 1 | // go-mysqlbinlog: a simple binlog tool to sync remote MySQL binlog. 2 | // go-mysqlbinlog supports semi-sync mode like facebook mysqlbinlog. 3 | // see http://yoshinorimatsunobu.blogspot.com/2014/04/semi-synchronous-replication-at-facebook.html 4 | package session 5 | 6 | // time go run mainRemote.go -start-time="2018-09-17 00:00:00" -stop-time="2018-09-25 00:00:00" -o=1.sql 7 | import ( 8 | "fmt" 9 | "time" 10 | 11 | "github.com/imroc/req" 12 | log "github.com/sirupsen/logrus" 13 | ) 14 | 15 | // const ( 16 | // // SOCKET_HOST = "127.0.0.1" 17 | // // SOCKET_PORT = 8090 18 | // // URL string = "http://127.0.0.1:8090/socket" 19 | // ) 20 | 21 | var URL string 22 | 23 | var header = req.Header{"Accept": "application/json"} 24 | 25 | func init() { 26 | req.SetTimeout(5 * time.Second) 27 | } 28 | 29 | // 向客户端推送消息 30 | func sendMsg(user string, event string, title string, text string, kwargs map[string]interface{}) bool { 31 | 32 | if user == "" { 33 | return true 34 | } 35 | if URL == "" { 36 | return false 37 | } 38 | 39 | url := fmt.Sprintf("%s/room/%s", URL, user) 40 | 41 | param := req.Param{ 42 | "event": event, 43 | "title": title, 44 | "content": text, 45 | } 46 | 47 | if kwargs != nil && len(kwargs) > 0 { 48 | for k, v := range kwargs { 49 | param[k] = v 50 | } 51 | } 52 | 53 | r, err := req.Post(url, header, param) 54 | if err != nil { 55 | log.Error("请求websocket失败!") 56 | log.Print(err) 57 | return false 58 | } 59 | // r.ToJSON(&foo) // 响应体转成对象 60 | // log.Printf("%+v", r) // 打印详细信息 61 | 62 | resp := r.Response() 63 | 64 | if resp.StatusCode == 200 { 65 | return true 66 | } 67 | log.Error("请求websocket失败!") 68 | log.Printf("%+v", r) // 打印详细信息 69 | return false 70 | } 71 | -------------------------------------------------------------------------------- /sessionctx/variable/mock_globalaccessor.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package variable 15 | 16 | // MockGlobalAccessor implements GlobalVarAccessor interface. it's used in tests 17 | type MockGlobalAccessor struct { 18 | } 19 | 20 | // NewMockGlobalAccessor implements GlobalVarAccessor interface. 21 | func NewMockGlobalAccessor() *MockGlobalAccessor { 22 | return new(MockGlobalAccessor) 23 | } 24 | 25 | // GetGlobalSysVar implements GlobalVarAccessor.GetGlobalSysVar interface. 26 | func (m *MockGlobalAccessor) GetGlobalSysVar(name string) (string, error) { 27 | v, ok := SysVars[name] 28 | if ok { 29 | return v.Value, nil 30 | } 31 | return "", nil 32 | } 33 | 34 | // SetGlobalSysVar implements GlobalVarAccessor.SetGlobalSysVar interface. 35 | func (m *MockGlobalAccessor) SetGlobalSysVar(name string, value string) error { 36 | panic("not supported") 37 | } 38 | 39 | // GetAllSysVars implements GlobalVarAccessor.GetAllSysVars interface. 40 | func (m *MockGlobalAccessor) GetAllSysVars() (map[string]string, error) { 41 | panic("not supported") 42 | } 43 | -------------------------------------------------------------------------------- /sessionctx/variable/session_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package variable_test 15 | 16 | import ( 17 | "github.com/hanchuanchuan/goInception/util/mock" 18 | . "github.com/pingcap/check" 19 | ) 20 | 21 | var _ = Suite(&testSessionSuite{}) 22 | 23 | type testSessionSuite struct { 24 | } 25 | 26 | func (*testSessionSuite) TestSession(c *C) { 27 | ctx := mock.NewContext() 28 | 29 | ss := ctx.GetSessionVars().StmtCtx 30 | c.Assert(ss, NotNil) 31 | 32 | // For AffectedRows 33 | ss.AddAffectedRows(1) 34 | c.Assert(ss.AffectedRows(), Equals, uint64(1)) 35 | ss.AddAffectedRows(1) 36 | c.Assert(ss.AffectedRows(), Equals, uint64(2)) 37 | 38 | // For FoundRows 39 | ss.AddFoundRows(1) 40 | c.Assert(ss.FoundRows(), Equals, uint64(1)) 41 | ss.AddFoundRows(1) 42 | c.Assert(ss.FoundRows(), Equals, uint64(2)) 43 | 44 | // For last insert id 45 | ctx.GetSessionVars().SetLastInsertID(1) 46 | c.Assert(ctx.GetSessionVars().LastInsertID, Equals, uint64(1)) 47 | 48 | ss.ResetForRetry() 49 | c.Assert(ss.AffectedRows(), Equals, uint64(0)) 50 | c.Assert(ss.FoundRows(), Equals, uint64(0)) 51 | c.Assert(ss.WarningCount(), Equals, uint16(0)) 52 | } 53 | -------------------------------------------------------------------------------- /sessionctx/variable/statusvar_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package variable 15 | 16 | import ( 17 | "github.com/hanchuanchuan/goInception/util/testleak" 18 | . "github.com/pingcap/check" 19 | ) 20 | 21 | var _ = Suite(&testStatusVarSuite{}) 22 | 23 | type testStatusVarSuite struct { 24 | ms *mockStatistics 25 | } 26 | 27 | func (s *testStatusVarSuite) SetUpSuite(c *C) { 28 | s.ms = &mockStatistics{} 29 | RegisterStatistics(s.ms) 30 | } 31 | 32 | // mockStatistics represents mocked statistics. 33 | type mockStatistics struct{} 34 | 35 | const ( 36 | testStatus = "test_status" 37 | testSessionStatus = "test_session_status" 38 | testStatusVal = "test_status_val" 39 | ) 40 | 41 | var specificStatusScopes = map[string]ScopeFlag{ 42 | testSessionStatus: ScopeSession, 43 | } 44 | 45 | func (ms *mockStatistics) GetScope(status string) ScopeFlag { 46 | scope, ok := specificStatusScopes[status] 47 | if !ok { 48 | return DefaultStatusVarScopeFlag 49 | } 50 | 51 | return scope 52 | } 53 | 54 | func (ms *mockStatistics) Stats(vars *SessionVars) (map[string]interface{}, error) { 55 | m := make(map[string]interface{}, len(specificStatusScopes)) 56 | m[testStatus] = testStatusVal 57 | 58 | return m, nil 59 | } 60 | 61 | func (s *testStatusVarSuite) TestStatusVar(c *C) { 62 | defer testleak.AfterTest(c)() 63 | scope := s.ms.GetScope(testStatus) 64 | c.Assert(scope, Equals, DefaultStatusVarScopeFlag) 65 | scope = s.ms.GetScope(testSessionStatus) 66 | c.Assert(scope, Equals, ScopeSession) 67 | 68 | vars, err := GetStatusVars(nil) 69 | c.Assert(err, IsNil) 70 | v := &StatusVal{Scope: DefaultStatusVarScopeFlag, Value: testStatusVal} 71 | c.Assert(v, DeepEquals, vars[testStatus]) 72 | } 73 | -------------------------------------------------------------------------------- /sessionctx/variable/sysvar_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package variable 15 | 16 | import ( 17 | "testing" 18 | 19 | . "github.com/pingcap/check" 20 | ) 21 | 22 | func TestT(t *testing.T) { 23 | CustomVerboseFlag = true 24 | TestingT(t) 25 | } 26 | 27 | var _ = Suite(&testSysVarSuite{}) 28 | 29 | type testSysVarSuite struct { 30 | } 31 | 32 | func (*testSysVarSuite) TestSysVar(c *C) { 33 | f := GetSysVar("autocommit") 34 | c.Assert(f, NotNil) 35 | 36 | f = GetSysVar("wrong-var-name") 37 | c.Assert(f, IsNil) 38 | 39 | f = GetSysVar("explicit_defaults_for_timestamp") 40 | c.Assert(f, NotNil) 41 | c.Assert(f.Value, Equals, "ON") 42 | } 43 | -------------------------------------------------------------------------------- /sonar-project.properties: -------------------------------------------------------------------------------- 1 | sonar.projectName=goInception 2 | sonar.organization=hanchuanchuan 3 | sonar.projectVersion=1.3.0 4 | 5 | sonar.projectKey=goInception 6 | 7 | sonar.sources=. 8 | sonar.exclusions=**/*_test.go,**/vendor/**,**/testdata/* 9 | 10 | sonar.sourceEncoding=UTF-8 11 | 12 | sonar.language=go 13 | 14 | sonar.tests=. 15 | sonar.test.inclusions=**/*_test.go 16 | sonar.test.exclusions=**/vendor/** 17 | sonar.go.coverage.reportPaths=/github/workspace/coverage.out 18 | -------------------------------------------------------------------------------- /statistics/update_list_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package statistics 15 | 16 | import ( 17 | . "github.com/pingcap/check" 18 | ) 19 | 20 | var _ = Suite(&testUpdateListSuite{}) 21 | 22 | type testUpdateListSuite struct { 23 | } 24 | 25 | func (s *testUpdateListSuite) TestInsertAndDelete(c *C) { 26 | h := Handle{listHead: &SessionStatsCollector{mapper: make(tableDeltaMap)}} 27 | var items []*SessionStatsCollector 28 | for i := 0; i < 5; i++ { 29 | items = append(items, h.NewSessionStatsCollector()) 30 | } 31 | items[0].Delete() // delete tail 32 | items[2].Delete() // delete middle 33 | items[4].Delete() // delete head 34 | h.DumpStatsDeltaToKV(DumpAll) 35 | 36 | c.Assert(h.listHead.next, Equals, items[3]) 37 | c.Assert(items[3].next, Equals, items[1]) 38 | c.Assert(items[1].next, IsNil) 39 | c.Assert(items[1].prev, Equals, items[3]) 40 | c.Assert(items[3].prev, Equals, h.listHead) 41 | 42 | // delete rest 43 | items[1].Delete() 44 | items[3].Delete() 45 | h.DumpStatsDeltaToKV(DumpAll) 46 | c.Assert(h.listHead.next, IsNil) 47 | } 48 | -------------------------------------------------------------------------------- /store/mockstore/mocktikv/checksum.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package mocktikv 15 | 16 | import ( 17 | "fmt" 18 | 19 | "github.com/pingcap/kvproto/pkg/coprocessor" 20 | "github.com/pingcap/tipb/go-tipb" 21 | ) 22 | 23 | func (h *rpcHandler) handleCopChecksumRequest(req *coprocessor.Request) *coprocessor.Response { 24 | resp := &tipb.ChecksumResponse{ 25 | Checksum: 1, 26 | TotalKvs: 1, 27 | TotalBytes: 1, 28 | } 29 | data, err := resp.Marshal() 30 | if err != nil { 31 | panic(fmt.Sprintf("marshal checksum response error: %v", err)) 32 | } 33 | return &coprocessor.Response{Data: data} 34 | } 35 | -------------------------------------------------------------------------------- /store/mockstore/mocktikv/errors.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package mocktikv 15 | 16 | import "fmt" 17 | 18 | // ErrLocked is returned when trying to Read/Write on a locked key. Client should 19 | // backoff or cleanup the lock then retry. 20 | type ErrLocked struct { 21 | Key MvccKey 22 | Primary []byte 23 | StartTS uint64 24 | TTL uint64 25 | } 26 | 27 | // Error formats the lock to a string. 28 | func (e *ErrLocked) Error() string { 29 | return fmt.Sprintf("key is locked, key: %q, primary: %q, startTS: %v", e.Key, e.Primary, e.StartTS) 30 | } 31 | 32 | // ErrRetryable suggests that client may restart the txn. e.g. write conflict. 33 | type ErrRetryable string 34 | 35 | func (e ErrRetryable) Error() string { 36 | return fmt.Sprintf("retryable: %s", string(e)) 37 | } 38 | 39 | // ErrAbort means something is wrong and client should abort the txn. 40 | type ErrAbort string 41 | 42 | func (e ErrAbort) Error() string { 43 | return fmt.Sprintf("abort: %s", string(e)) 44 | } 45 | 46 | // ErrAlreadyCommitted is returned specially when client tries to rollback a 47 | // committed lock. 48 | type ErrAlreadyCommitted uint64 49 | 50 | func (e ErrAlreadyCommitted) Error() string { 51 | return "txn already committed" 52 | } 53 | -------------------------------------------------------------------------------- /store/mockstore/mocktikv/mock.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package mocktikv 15 | 16 | import ( 17 | "github.com/pingcap/errors" // NewTiKVAndPDClient creates a TiKV client and PD client from options. 18 | "github.com/pingcap/pd/client" 19 | ) 20 | 21 | func NewTiKVAndPDClient(cluster *Cluster, mvccStore MVCCStore, path string) (*RPCClient, pd.Client, error) { 22 | if cluster == nil { 23 | cluster = NewCluster() 24 | BootstrapWithSingleStore(cluster) 25 | } 26 | 27 | if mvccStore == nil { 28 | var err error 29 | mvccStore, err = NewMVCCLevelDB(path) 30 | if err != nil { 31 | return nil, nil, errors.Trace(err) 32 | } 33 | } 34 | 35 | return NewRPCClient(cluster, mvccStore), NewPDClient(cluster), nil 36 | } 37 | -------------------------------------------------------------------------------- /store/mockstore/tikv_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package mockstore 15 | 16 | import ( 17 | "testing" 18 | 19 | "github.com/hanchuanchuan/goInception/config" 20 | . "github.com/pingcap/check" 21 | ) 22 | 23 | func TestT(t *testing.T) { 24 | TestingT(t) 25 | } 26 | 27 | type testSuite struct{} 28 | 29 | func (s testSuite) SetUpSuite(c *C) {} 30 | 31 | var _ = Suite(testSuite{}) 32 | 33 | func (s testSuite) TestConfig(c *C) { 34 | config.GetGlobalConfig().TxnLocalLatches = config.TxnLocalLatches{ 35 | Enabled: true, 36 | Capacity: 10240, 37 | } 38 | 39 | type LatchEnableChecker interface { 40 | IsLatchEnabled() bool 41 | } 42 | 43 | var driver MockDriver 44 | store, err := driver.Open("mocktikv://") 45 | c.Assert(err, IsNil) 46 | c.Assert(store.(LatchEnableChecker).IsLatchEnabled(), IsTrue) 47 | store.Close() 48 | 49 | config.GetGlobalConfig().TxnLocalLatches = config.TxnLocalLatches{ 50 | Enabled: false, 51 | Capacity: 10240, 52 | } 53 | store, err = driver.Open("mocktikv://") 54 | c.Assert(err, IsNil) 55 | c.Assert(store.(LatchEnableChecker).IsLatchEnabled(), IsFalse) 56 | store.Close() 57 | } 58 | -------------------------------------------------------------------------------- /store/tikv/2pc_slow_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | // +build !race 15 | 16 | package tikv 17 | 18 | import . "github.com/pingcap/check" 19 | 20 | // The test takes too long under the race detector. 21 | func (s *testCommitterSuite) TestCommitMultipleRegions(c *C) { 22 | m := make(map[string]string) 23 | for i := 0; i < 100; i++ { 24 | k, v := randKV(10, 10) 25 | m[k] = v 26 | } 27 | s.mustCommit(c, m) 28 | 29 | // Test big values. 30 | m = make(map[string]string) 31 | for i := 0; i < 50; i++ { 32 | k, v := randKV(11, txnCommitBatchSize/7) 33 | m[k] = v 34 | } 35 | s.mustCommit(c, m) 36 | } 37 | -------------------------------------------------------------------------------- /store/tikv/client_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package tikv 15 | 16 | import ( 17 | "testing" 18 | 19 | "github.com/hanchuanchuan/goInception/config" 20 | . "github.com/pingcap/check" 21 | ) 22 | 23 | func TestT(t *testing.T) { 24 | CustomVerboseFlag = true 25 | TestingT(t) 26 | } 27 | 28 | type testClientSuite struct { 29 | OneByOneSuite 30 | } 31 | 32 | var _ = Suite(&testClientSuite{}) 33 | 34 | func (s *testClientSuite) TestConn(c *C) { 35 | client := newRPCClient(config.Security{}) 36 | 37 | addr := "127.0.0.1:6379" 38 | conn1, err := client.getConnArray(addr) 39 | c.Assert(err, IsNil) 40 | 41 | conn2, err := client.getConnArray(addr) 42 | c.Assert(err, IsNil) 43 | c.Assert(conn2.Get(), Not(Equals), conn1.Get()) 44 | 45 | client.Close() 46 | conn3, err := client.getConnArray(addr) 47 | c.Assert(err, NotNil) 48 | c.Assert(conn3, IsNil) 49 | } 50 | -------------------------------------------------------------------------------- /store/tikv/latch/scheduler_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package latch 15 | 16 | import ( 17 | "sync" 18 | 19 | . "github.com/pingcap/check" 20 | ) 21 | 22 | var _ = Suite(&testSchedulerSuite{}) 23 | 24 | type testSchedulerSuite struct { 25 | } 26 | 27 | func (s *testSchedulerSuite) SetUpTest(c *C) { 28 | } 29 | 30 | func (s *testSchedulerSuite) TestWithConcurrency(c *C) { 31 | txns := [][][]byte{ 32 | {[]byte("a"), []byte("b"), []byte("c")}, 33 | {[]byte("a"), []byte("d"), []byte("e"), []byte("f")}, 34 | {[]byte("e"), []byte("f"), []byte("g"), []byte("h")}, 35 | } 36 | sched := NewScheduler(1024) 37 | defer sched.Close() 38 | 39 | var wg sync.WaitGroup 40 | wg.Add(len(txns)) 41 | for _, txn := range txns { 42 | go func(txn [][]byte, wg *sync.WaitGroup) { 43 | lock := sched.Lock(getTso(), txn) 44 | defer sched.UnLock(lock) 45 | if lock.IsStale() { 46 | // Should restart the transaction or return error 47 | } else { 48 | lock.SetCommitTS(getTso()) 49 | // Do 2pc 50 | } 51 | wg.Done() 52 | }(txn, &wg) 53 | } 54 | wg.Wait() 55 | } 56 | -------------------------------------------------------------------------------- /store/tikv/oracle/oracle.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package oracle 15 | 16 | import ( 17 | "time" 18 | 19 | "golang.org/x/net/context" 20 | ) 21 | 22 | // Oracle is the interface that provides strictly ascending timestamps. 23 | type Oracle interface { 24 | GetTimestamp(ctx context.Context) (uint64, error) 25 | GetTimestampAsync(ctx context.Context) Future 26 | IsExpired(lockTimestamp uint64, TTL uint64) bool 27 | Close() 28 | } 29 | 30 | // Future is a future which promises to return a timestamp. 31 | type Future interface { 32 | Wait() (uint64, error) 33 | } 34 | 35 | const physicalShiftBits = 18 36 | 37 | // ComposeTS creates a ts from physical and logical parts. 38 | func ComposeTS(physical, logical int64) uint64 { 39 | return uint64((physical << physicalShiftBits) + logical) 40 | } 41 | 42 | // ExtractPhysical returns a ts's physical part. 43 | func ExtractPhysical(ts uint64) int64 { 44 | return int64(ts >> physicalShiftBits) 45 | } 46 | 47 | // GetPhysical returns physical from an instant time with millisecond precision. 48 | func GetPhysical(t time.Time) int64 { 49 | return t.UnixNano() / int64(time.Millisecond) 50 | } 51 | 52 | // EncodeTSO encodes a millisecond into tso. 53 | func EncodeTSO(ts int64) uint64 { 54 | return uint64(ts) << physicalShiftBits 55 | } 56 | 57 | // GetTimeFromTS extracts time.Time from a timestamp. 58 | func GetTimeFromTS(ts uint64) time.Time { 59 | ms := ExtractPhysical(ts) 60 | return time.Unix(ms/1e3, (ms%1e3)*1e6) 61 | } 62 | -------------------------------------------------------------------------------- /store/tikv/oracle/oracles/local.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package oracles 15 | 16 | import ( 17 | "sync" 18 | "time" 19 | 20 | "github.com/hanchuanchuan/goInception/store/tikv/oracle" 21 | "golang.org/x/net/context" 22 | ) 23 | 24 | var _ oracle.Oracle = &localOracle{} 25 | 26 | type localOracle struct { 27 | sync.Mutex 28 | lastTimeStampTS uint64 29 | n uint64 30 | } 31 | 32 | // NewLocalOracle creates an Oracle that uses local time as data source. 33 | func NewLocalOracle() oracle.Oracle { 34 | return &localOracle{} 35 | } 36 | 37 | func (l *localOracle) IsExpired(lockTS uint64, TTL uint64) bool { 38 | return oracle.GetPhysical(time.Now()) >= oracle.ExtractPhysical(lockTS)+int64(TTL) 39 | } 40 | 41 | func (l *localOracle) GetTimestamp(context.Context) (uint64, error) { 42 | l.Lock() 43 | defer l.Unlock() 44 | physical := oracle.GetPhysical(time.Now()) 45 | ts := oracle.ComposeTS(physical, 0) 46 | if l.lastTimeStampTS == ts { 47 | l.n++ 48 | return ts + l.n, nil 49 | } 50 | l.lastTimeStampTS = ts 51 | l.n = 0 52 | return ts, nil 53 | } 54 | 55 | func (l *localOracle) GetTimestampAsync(ctx context.Context) oracle.Future { 56 | return &future{ 57 | ctx: ctx, 58 | l: l, 59 | } 60 | } 61 | 62 | type future struct { 63 | ctx context.Context 64 | l *localOracle 65 | } 66 | 67 | func (f *future) Wait() (uint64, error) { 68 | return f.l.GetTimestamp(f.ctx) 69 | } 70 | 71 | func (l *localOracle) Close() { 72 | } 73 | -------------------------------------------------------------------------------- /store/tikv/oracle/oracles/local_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package oracles 15 | 16 | import ( 17 | "testing" 18 | "time" 19 | 20 | "golang.org/x/net/context" 21 | ) 22 | 23 | func TestLocalOracle(t *testing.T) { 24 | l := NewLocalOracle() 25 | defer l.Close() 26 | m := map[uint64]struct{}{} 27 | for i := 0; i < 100000; i++ { 28 | ts, err := l.GetTimestamp(context.Background()) 29 | if err != nil { 30 | t.Error(err) 31 | } 32 | m[ts] = struct{}{} 33 | } 34 | 35 | if len(m) != 100000 { 36 | t.Error("generated same ts") 37 | } 38 | } 39 | 40 | func TestIsExpired(t *testing.T) { 41 | o := NewLocalOracle() 42 | defer o.Close() 43 | ts, _ := o.GetTimestamp(context.Background()) 44 | time.Sleep(1 * time.Second) 45 | expire := o.IsExpired(uint64(ts), 500) 46 | if !expire { 47 | t.Error("should expired") 48 | } 49 | expire = o.IsExpired(uint64(ts), 2000) 50 | if expire { 51 | t.Error("should not expired") 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /store/tikv/scan_mock_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package tikv 15 | 16 | import ( 17 | "github.com/hanchuanchuan/goInception/kv" 18 | . "github.com/pingcap/check" 19 | "golang.org/x/net/context" 20 | ) 21 | 22 | type testScanMockSuite struct { 23 | OneByOneSuite 24 | } 25 | 26 | var _ = Suite(&testScanMockSuite{}) 27 | 28 | func (s *testScanMockSuite) TestScanMultipleRegions(c *C) { 29 | store := NewTestStore(c).(*tikvStore) 30 | defer store.Close() 31 | 32 | txn, err := store.Begin() 33 | c.Assert(err, IsNil) 34 | for ch := byte('a'); ch <= byte('z'); ch++ { 35 | err = txn.Set([]byte{ch}, []byte{ch}) 36 | c.Assert(err, IsNil) 37 | } 38 | err = txn.Commit(context.Background()) 39 | c.Assert(err, IsNil) 40 | 41 | txn, err = store.Begin() 42 | c.Assert(err, IsNil) 43 | snapshot := newTiKVSnapshot(store, kv.Version{Ver: txn.StartTS()}) 44 | scanner, err := newScanner(snapshot, []byte("a"), 10) 45 | c.Assert(err, IsNil) 46 | for ch := byte('a'); ch <= byte('z'); ch++ { 47 | c.Assert([]byte{ch}, BytesEquals, []byte(scanner.Key())) 48 | c.Assert(scanner.Next(), IsNil) 49 | } 50 | c.Assert(scanner.Valid(), IsFalse) 51 | } 52 | -------------------------------------------------------------------------------- /store/tikv/test_util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package tikv 15 | 16 | import ( 17 | "github.com/gofrs/uuid" 18 | "github.com/hanchuanchuan/goInception/kv" 19 | "github.com/pingcap/errors" 20 | pd "github.com/pingcap/pd/client" 21 | ) 22 | 23 | // NewTestTiKVStore creates a test store with Option 24 | func NewTestTiKVStore(client Client, pdClient pd.Client, clientHijack func(Client) Client, pdClientHijack func(pd.Client) pd.Client, txnLocalLatches uint) (kv.Storage, error) { 25 | if clientHijack != nil { 26 | client = clientHijack(client) 27 | } 28 | 29 | pdCli := pd.Client(&codecPDClient{pdClient}) 30 | if pdClientHijack != nil { 31 | pdCli = pdClientHijack(pdCli) 32 | } 33 | 34 | // Make sure the uuid is unique. 35 | tmpUid, _ := uuid.NewV4() 36 | uid := tmpUid.String() 37 | spkv := NewMockSafePointKV() 38 | tikvStore, err := newTikvStore(uid, pdCli, spkv, client, false) 39 | 40 | if txnLocalLatches > 0 { 41 | tikvStore.EnableTxnLocalLatches(txnLocalLatches) 42 | } 43 | 44 | tikvStore.mock = true 45 | return tikvStore, errors.Trace(err) 46 | } 47 | -------------------------------------------------------------------------------- /structure/structure.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package structure 15 | 16 | import ( 17 | "github.com/hanchuanchuan/goInception/kv" 18 | "github.com/hanchuanchuan/goInception/terror" 19 | ) 20 | 21 | // structure error codes. 22 | const ( 23 | codeInvalidHashKeyFlag terror.ErrCode = 1 24 | codeInvalidHashKeyPrefix = 2 25 | codeInvalidListIndex = 3 26 | codeInvalidListMetaData = 4 27 | codeWriteOnSnapshot = 5 28 | ) 29 | 30 | var ( 31 | errInvalidHashKeyFlag = terror.ClassStructure.New(codeInvalidHashKeyFlag, "invalid encoded hash key flag") 32 | errInvalidHashKeyPrefix = terror.ClassStructure.New(codeInvalidHashKeyPrefix, "invalid encoded hash key prefix") 33 | errInvalidListIndex = terror.ClassStructure.New(codeInvalidListMetaData, "invalid list index") 34 | errInvalidListMetaData = terror.ClassStructure.New(codeInvalidListMetaData, "invalid list meta data") 35 | errWriteOnSnapshot = terror.ClassStructure.New(codeWriteOnSnapshot, "write on snapshot") 36 | ) 37 | 38 | // NewStructure creates a TxStructure with Retriever, RetrieverMutator and key prefix. 39 | func NewStructure(reader kv.Retriever, readWriter kv.RetrieverMutator, prefix []byte) *TxStructure { 40 | return &TxStructure{ 41 | reader: reader, 42 | readWriter: readWriter, 43 | prefix: prefix, 44 | } 45 | } 46 | 47 | // TxStructure supports some simple data structures like string, hash, list, etc... and 48 | // you can use these in a transaction. 49 | type TxStructure struct { 50 | reader kv.Retriever 51 | readWriter kv.RetrieverMutator 52 | prefix []byte 53 | } 54 | -------------------------------------------------------------------------------- /table/table_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package table 15 | 16 | import ( 17 | . "github.com/pingcap/check" 18 | ) 19 | 20 | var _ = Suite(&testTableSuite{}) 21 | 22 | type testTableSuite struct{} 23 | 24 | func (t *testTableSuite) TestSlice(c *C) { 25 | sl := make(Slice, 2) 26 | length := sl.Len() 27 | c.Assert(length, Equals, 2) 28 | sl.Swap(0, 1) 29 | } 30 | -------------------------------------------------------------------------------- /table/tables/gen_expr_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package tables 15 | 16 | import ( 17 | "github.com/hanchuanchuan/goInception/ast" 18 | . "github.com/pingcap/check" 19 | ) 20 | 21 | var _ = Suite(&testGenExprSuite{}) 22 | 23 | type testGenExprSuite struct{} 24 | 25 | func (s *testGenExprSuite) TestParseExpression(c *C) { 26 | tests := []struct { 27 | input string 28 | output string 29 | success bool 30 | }{ 31 | {"json_extract(a, '$.a')", "json_extract", true}, 32 | } 33 | for _, tt := range tests { 34 | node, err := parseExpression(tt.input) 35 | if tt.success { 36 | fc := node.(*ast.FuncCallExpr) 37 | c.Assert(fc.FnName.L, Equals, tt.output) 38 | } else { 39 | c.Assert(err, NotNil) 40 | } 41 | } 42 | } 43 | 44 | var PartitionRecordKey = partitionRecordKey 45 | -------------------------------------------------------------------------------- /tablecodec/bench_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package tablecodec 15 | 16 | import ( 17 | "testing" 18 | ) 19 | 20 | func BenchmarkEncodeRowKeyWithHandle(b *testing.B) { 21 | for i := 0; i < b.N; i++ { 22 | EncodeRowKeyWithHandle(100, 100) 23 | } 24 | } 25 | 26 | func BenchmarkEncodeEndKey(b *testing.B) { 27 | for i := 0; i < b.N; i++ { 28 | EncodeRowKeyWithHandle(100, 100) 29 | EncodeRowKeyWithHandle(100, 101) 30 | } 31 | } 32 | 33 | // BenchmarkEncodeRowKeyWithPrefixNex tests the performance of encoding row key with prefixNext 34 | // PrefixNext() is slow than using EncodeRowKeyWithHandle. 35 | // BenchmarkEncodeEndKey-4 20000000 97.2 ns/op 36 | // BenchmarkEncodeRowKeyWithPrefixNex-4 10000000 121 ns/op 37 | func BenchmarkEncodeRowKeyWithPrefixNex(b *testing.B) { 38 | for i := 0; i < b.N; i++ { 39 | sk := EncodeRowKeyWithHandle(100, 100) 40 | sk.PrefixNext() 41 | } 42 | } 43 | 44 | func BenchmarkDecodeRowKey(b *testing.B) { 45 | rowKey := EncodeRowKeyWithHandle(100, 100) 46 | for i := 0; i < b.N; i++ { 47 | DecodeRowKey(rowKey) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "Tools": [ 3 | { 4 | "Repository": "gopkg.in/alecthomas/gometalinter.v2", 5 | "Commit": "46cc1ea3778b247666c2949669a3333c532fa9c6" 6 | }, 7 | { 8 | "Repository": "github.com/client9/misspell/cmd/misspell", 9 | "Commit": "7888c6b6ce89353cd98e196bce3c3f9e4cdf31f6" 10 | }, 11 | { 12 | "Repository": "github.com/chzchzchz/goword", 13 | "Commit": "a9744cb52b033fe5c269df48eeef2c954526cd79" 14 | }, 15 | { 16 | "Repository": "github.com/gordonklaus/ineffassign", 17 | "Commit": "7bae11eba15a3285c75e388f77eb6357a2d73ee2" 18 | }, 19 | { 20 | "Repository": "honnef.co/go/tools/cmd/megacheck", 21 | "Commit": "88497007e8588ea5b6baee991f74a1607e809487" 22 | }, 23 | { 24 | "Repository": "github.com/dnephin/govet", 25 | "Commit": "4a96d43e39d340b63daa8bc5576985aa599885f6" 26 | }, 27 | { 28 | "Repository": "github.com/securego/gosec/cmd/gosec", 29 | "Commit": "5fb530cda357c16175f2c049577d2030de735b28" 30 | }, 31 | { 32 | "Repository": "github.com/kisielk/errcheck", 33 | "Commit": "55d8f507faff4d6eddd0c41a3e713e2567fca4e5" 34 | }, 35 | { 36 | "Repository": "github.com/mgechev/revive", 37 | "Commit": "7773f47324c2bf1c8f7a5500aff2b6c01d3ed73b" 38 | } 39 | ], 40 | "RetoolVersion": "1.3.7" 41 | } -------------------------------------------------------------------------------- /tools/check/check-gogenerate.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright 2019 PingCAP, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | set -euo pipefail 16 | 17 | go generate ./... 18 | set +e 19 | diffline=$(git status -s | awk '{print $2}' | xargs grep '^// Code generated .* DO NOT EDIT\.$' 2>/dev/null) 20 | set -e 21 | if [[ $diffline != "" ]] 22 | then 23 | echo "Your commit is changed after running go generate ./..., it should not happen." 24 | exit 1 25 | fi 26 | -------------------------------------------------------------------------------- /tools/check/check-tidy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright 2019 PingCAP, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | # set is used to set the environment variables. 16 | # -e: exit immediately when a command returning a non-zero exit code. 17 | # -u: treat unset variables as an error. 18 | # -o pipefail: sets the exit code of a pipeline to that of the rightmost command to exit with a non-zero status, 19 | # or to zero if all commands of the pipeline exit successfully. 20 | set -euo pipefail 21 | 22 | # go mod tidy do not support symlink 23 | cd -P . 24 | 25 | cp go.sum /tmp/go.sum.before 26 | GO111MODULE=on go mod tidy 27 | diff -q go.sum /tmp/go.sum.before 28 | -------------------------------------------------------------------------------- /tools/check/check_parser_replace.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright 2019 PingCAP, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | set -uo pipefail 16 | 17 | grep "replace.*github.com/pingcap/parser" go.mod 18 | grep_ret=$? 19 | 20 | if [ $grep_ret -eq 0 ];then 21 | exit 1 22 | else 23 | exit 0 24 | fi 25 | -------------------------------------------------------------------------------- /tools/check/check_testSuite.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright 2019 PingCAP, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | set -euo pipefail 16 | 17 | exitCode=0 18 | 19 | list=$(find . -name "*_test.go" -not -path "./vendor/*" -print0 | xargs -0 grep -E "type test(.*)Suite" | awk -F ':| ' '{print $1" "$3}') 20 | while read -r file testSuite; do 21 | # TODO: ugly regex 22 | # TODO: check code comment 23 | dir=$(dirname "$file") 24 | if ! find "$dir" -name "*_test.go" -print0 | xargs -0 grep -E "_ = (check\.)?(Suite|SerialSuites)\((&?${testSuite}{|new\(${testSuite}\))" > /dev/null 25 | then 26 | if find "$dir" -name "*_test.go" -print0 | xargs -0 grep -E "func \((.* )?\*?${testSuite}\) Test" > /dev/null 27 | then 28 | echo "${testSuite} in ${dir} is not enabled" && exitCode=1 29 | fi 30 | fi 31 | done <<< "$list" 32 | exit ${exitCode} 33 | -------------------------------------------------------------------------------- /tools/check/errcheck_excludes.txt: -------------------------------------------------------------------------------- 1 | fmt.Fprintf 2 | fmt.Fprint 3 | fmt.Sscanf 4 | -------------------------------------------------------------------------------- /tools/check/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/hanchuanchuan/goInception/_tools 2 | 3 | require ( 4 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc // indirect 5 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf // indirect 6 | github.com/chzchzchz/goword v0.0.0-20170907005317-a9744cb52b03 7 | github.com/dnephin/govet v0.0.0-20171012192244-4a96d43e39d3 8 | github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf // indirect 9 | github.com/kisielk/errcheck v1.2.0 10 | github.com/mdempsky/unconvert v0.0.0-20200228143138-95ecdbfc0b5f // indirect 11 | github.com/mgechev/revive v0.0.0-20181210140514-b4cc152955fb 12 | github.com/nicksnyder/go-i18n v1.10.0 // indirect 13 | github.com/pelletier/go-toml v1.2.0 // indirect 14 | github.com/securego/gosec v0.0.0-20181211171558-12400f9a1ca7 15 | gopkg.in/alecthomas/gometalinter.v2 v2.0.12 // indirect 16 | gopkg.in/alecthomas/gometalinter.v3 v3.0.0 // indirect 17 | gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect 18 | gopkg.in/alecthomas/kingpin.v3-unstable v3.0.0-20170321130658-9670b87a702e // indirect 19 | gopkg.in/yaml.v2 v2.2.2 // indirect 20 | honnef.co/go/tools v0.0.0-20180920025451-e3ad64cb4ed3 21 | ) 22 | 23 | go 1.13 24 | -------------------------------------------------------------------------------- /tools/check/revive.toml: -------------------------------------------------------------------------------- 1 | ignoreGeneratedHeader = false 2 | severity = "error" 3 | confidence = 0.8 4 | errorCode = -1 5 | warningCode = -1 6 | 7 | [rule.blank-imports] 8 | [rule.context-as-argument] 9 | [rule.dot-imports] 10 | [rule.error-return] 11 | #[rule.error-strings] 12 | #[rule.error-naming] 13 | #[rule.exported] 14 | [rule.if-return] 15 | #[rule.var-naming] 16 | [rule.package-comments] 17 | [rule.range] 18 | [rule.receiver-naming] 19 | [rule.indent-error-flow] 20 | [rule.superfluous-else] 21 | [rule.modifies-parameter] 22 | 23 | # This can be checked by other tools like megacheck 24 | [rule.unreachable-code] 25 | 26 | 27 | # Currently this makes too much noise, but should add it in 28 | # and perhaps ignore it in a few files 29 | #[rule.confusing-naming] 30 | # severity = "warning" 31 | #[rule.confusing-results] 32 | # severity = "warning" 33 | #[rule.unused-parameter] 34 | # severity = "warning" 35 | #[rule.deep-exit] 36 | # severity = "warning" 37 | #[rule.flag-parameter] 38 | # severity = "warning" 39 | 40 | 41 | 42 | # Adding these will slow down the linter 43 | # They are already provided by megacheck 44 | # [rule.unexported-return] 45 | # [rule.time-naming] 46 | # [rule.errorf] 47 | 48 | # Adding these will slow down the linter 49 | # Not sure if they are already provided by megacheck 50 | # [rule.var-declaration] 51 | # [rule.context-keys-type] 52 | -------------------------------------------------------------------------------- /types/compare.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package types 15 | 16 | // CompareInt64 returns an integer comparing the int64 x to y. 17 | func CompareInt64(x, y int64) int { 18 | if x < y { 19 | return -1 20 | } else if x == y { 21 | return 0 22 | } 23 | 24 | return 1 25 | } 26 | 27 | // CompareUint64 returns an integer comparing the uint64 x to y. 28 | func CompareUint64(x, y uint64) int { 29 | if x < y { 30 | return -1 31 | } else if x == y { 32 | return 0 33 | } 34 | 35 | return 1 36 | } 37 | 38 | // CompareFloat64 returns an integer comparing the float64 x to y. 39 | func CompareFloat64(x, y float64) int { 40 | if x < y { 41 | return -1 42 | } else if x == y { 43 | return 0 44 | } 45 | 46 | return 1 47 | } 48 | 49 | // CompareString returns an integer comparing the string x to y. 50 | func CompareString(x, y string) int { 51 | if x < y { 52 | return -1 53 | } else if x == y { 54 | return 0 55 | } 56 | 57 | return 1 58 | } 59 | -------------------------------------------------------------------------------- /types/datum_eval.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package types 15 | 16 | import ( 17 | "github.com/hanchuanchuan/goInception/parser/opcode" 18 | "github.com/pingcap/errors" 19 | "modernc.org/mathutil" 20 | ) 21 | 22 | // ComputePlus computes the result of a+b. 23 | func ComputePlus(a, b Datum) (d Datum, err error) { 24 | switch a.Kind() { 25 | case KindInt64: 26 | switch b.Kind() { 27 | case KindInt64: 28 | r, err1 := AddInt64(a.GetInt64(), b.GetInt64()) 29 | d.SetInt64(r) 30 | return d, errors.Trace(err1) 31 | case KindUint64: 32 | r, err1 := AddInteger(b.GetUint64(), a.GetInt64()) 33 | d.SetUint64(r) 34 | return d, errors.Trace(err1) 35 | } 36 | case KindUint64: 37 | switch b.Kind() { 38 | case KindInt64: 39 | r, err1 := AddInteger(a.GetUint64(), b.GetInt64()) 40 | d.SetUint64(r) 41 | return d, errors.Trace(err1) 42 | case KindUint64: 43 | r, err1 := AddUint64(a.GetUint64(), b.GetUint64()) 44 | d.SetUint64(r) 45 | return d, errors.Trace(err1) 46 | } 47 | case KindFloat64: 48 | switch b.Kind() { 49 | case KindFloat64: 50 | r := a.GetFloat64() + b.GetFloat64() 51 | d.SetFloat64(r) 52 | return d, nil 53 | } 54 | case KindMysqlDecimal: 55 | switch b.Kind() { 56 | case KindMysqlDecimal: 57 | r := new(MyDecimal) 58 | err = DecimalAdd(a.GetMysqlDecimal(), b.GetMysqlDecimal(), r) 59 | d.SetMysqlDecimal(r) 60 | d.SetFrac(mathutil.Max(a.Frac(), b.Frac())) 61 | return d, err 62 | } 63 | } 64 | _, err = InvOp2(a.GetValue(), b.GetValue(), opcode.Plus) 65 | return d, err 66 | } 67 | -------------------------------------------------------------------------------- /types/enum.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package types 15 | 16 | import ( 17 | "strconv" 18 | "strings" 19 | 20 | "github.com/pingcap/errors" 21 | ) 22 | 23 | // Enum is for MySQL enum type. 24 | type Enum struct { 25 | Name string 26 | Value uint64 27 | } 28 | 29 | // String implements fmt.Stringer interface. 30 | func (e Enum) String() string { 31 | return e.Name 32 | } 33 | 34 | // ToNumber changes enum index to float64 for numeric operation. 35 | func (e Enum) ToNumber() float64 { 36 | return float64(e.Value) 37 | } 38 | 39 | // ParseEnumName creates a Enum with item name. 40 | func ParseEnumName(elems []string, name string) (Enum, error) { 41 | for i, n := range elems { 42 | if strings.EqualFold(n, name) { 43 | return Enum{Name: n, Value: uint64(i) + 1}, nil 44 | } 45 | } 46 | 47 | // name doesn't exist, maybe an integer? 48 | if num, err := strconv.ParseUint(name, 0, 64); err == nil { 49 | return ParseEnumValue(elems, num) 50 | } 51 | 52 | return Enum{}, errors.Errorf("item %s is not in enum %v", name, elems) 53 | } 54 | 55 | // ParseEnumValue creates a Enum with special number. 56 | func ParseEnumValue(elems []string, number uint64) (Enum, error) { 57 | if number == 0 || number > uint64(len(elems)) { 58 | return Enum{}, errors.Errorf("number %d overflow enum boundary [1, %d]", number, len(elems)) 59 | } 60 | 61 | return Enum{Name: elems[number-1], Value: number}, nil 62 | } 63 | -------------------------------------------------------------------------------- /types/enum_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package types 15 | 16 | import ( 17 | "github.com/hanchuanchuan/goInception/util/testleak" 18 | . "github.com/pingcap/check" 19 | ) 20 | 21 | var _ = Suite(&testEnumSuite{}) 22 | 23 | type testEnumSuite struct { 24 | } 25 | 26 | func (s *testEnumSuite) TestEnum(c *C) { 27 | defer testleak.AfterTest(c)() 28 | tbl := []struct { 29 | Elems []string 30 | Name string 31 | Expected int 32 | }{ 33 | {[]string{"a", "b"}, "a", 1}, 34 | {[]string{"a"}, "b", 0}, 35 | {[]string{"a"}, "1", 1}, 36 | } 37 | 38 | for _, t := range tbl { 39 | e, err := ParseEnumName(t.Elems, t.Name) 40 | if t.Expected == 0 { 41 | c.Assert(err, NotNil) 42 | c.Assert(e.ToNumber(), Equals, float64(0)) 43 | c.Assert(e.String(), Equals, "") 44 | continue 45 | } 46 | 47 | c.Assert(err, IsNil) 48 | c.Assert(e.String(), Equals, t.Elems[t.Expected-1]) 49 | c.Assert(e.ToNumber(), Equals, float64(t.Expected)) 50 | } 51 | 52 | tblNumber := []struct { 53 | Elems []string 54 | Number uint64 55 | Expected int 56 | }{ 57 | {[]string{"a"}, 1, 1}, 58 | {[]string{"a"}, 0, 0}, 59 | } 60 | 61 | for _, t := range tblNumber { 62 | e, err := ParseEnumValue(t.Elems, t.Number) 63 | if t.Expected == 0 { 64 | c.Assert(err, NotNil) 65 | continue 66 | } 67 | 68 | c.Assert(err, IsNil) 69 | c.Assert(e.ToNumber(), Equals, float64(t.Expected)) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /types/eval_type.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package types 15 | 16 | // EvalType indicates the specified types that arguments and result of a built-in function should be. 17 | type EvalType byte 18 | 19 | const ( 20 | // ETInt represents type INT in evaluation. 21 | ETInt EvalType = iota 22 | // ETReal represents type REAL in evaluation. 23 | ETReal 24 | // ETDecimal represents type DECIMAL in evaluation. 25 | ETDecimal 26 | // ETString represents type STRING in evaluation. 27 | ETString 28 | // ETDatetime represents type DATETIME in evaluation. 29 | ETDatetime 30 | // ETTimestamp represents type TIMESTAMP in evaluation. 31 | ETTimestamp 32 | // ETDuration represents type DURATION in evaluation. 33 | ETDuration 34 | // ETJson represents type JSON in evaluation. 35 | ETJson 36 | ) 37 | 38 | // IsStringKind returns true for ETString, ETDatetime, ETTimestamp, ETDuration, ETJson EvalTypes. 39 | func (et EvalType) IsStringKind() bool { 40 | return et == ETString || et == ETDatetime || 41 | et == ETTimestamp || et == ETDuration || et == ETJson 42 | } 43 | -------------------------------------------------------------------------------- /types/export_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package types 15 | 16 | // CheckTimestampTypeForTest export CheckTimestampType for test. 17 | var CheckTimestampTypeForTest = checkTimestampType 18 | -------------------------------------------------------------------------------- /types/helper_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package types 15 | 16 | import ( 17 | "strconv" 18 | 19 | . "github.com/pingcap/check" 20 | "github.com/pingcap/errors" 21 | ) 22 | 23 | var _ = Suite(&testTypeHelperSuite{}) 24 | 25 | type testTypeHelperSuite struct { 26 | } 27 | 28 | func (s *testTypeHelperSuite) TestStrToInt(c *C) { 29 | tests := []struct { 30 | input string 31 | output string 32 | err error 33 | }{ 34 | {"9223372036854775806", "9223372036854775806", nil}, 35 | {"9223372036854775807", "9223372036854775807", nil}, 36 | {"9223372036854775808", "9223372036854775807", ErrBadNumber}, 37 | {"-9223372036854775807", "-9223372036854775807", nil}, 38 | {"-9223372036854775808", "-9223372036854775808", nil}, 39 | {"-9223372036854775809", "-9223372036854775808", ErrBadNumber}, 40 | } 41 | for _, tt := range tests { 42 | output, err := strToInt(tt.input) 43 | c.Assert(errors.Cause(err), Equals, tt.err) 44 | c.Check(strconv.FormatInt(output, 10), Equals, tt.output) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /types/json/path_expr_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package json 15 | 16 | import ( 17 | . "github.com/pingcap/check" 18 | ) 19 | 20 | func (s *testJSONSuite) TestContainsAnyAsterisk(c *C) { 21 | var tests = []struct { 22 | exprString string 23 | containsAsterisks bool 24 | }{ 25 | {"$.a[b]", false}, 26 | {"$.a[*]", true}, 27 | {"$.*[b]", true}, 28 | {"$**.a[b]", true}, 29 | } 30 | for _, tt := range tests { 31 | pe, err := ParseJSONPathExpr(tt.exprString) 32 | c.Assert(err, IsNil) 33 | c.Assert(pe.flags.containsAnyAsterisk(), Equals, tt.containsAsterisks) 34 | } 35 | } 36 | 37 | func (s *testJSONSuite) TestValidatePathExpr(c *C) { 38 | var tests = []struct { 39 | exprString string 40 | success bool 41 | legs int 42 | }{ 43 | {` $ `, true, 0}, 44 | {" $ . key1 [ 3 ]\t[*].*.key3", true, 5}, 45 | {" $ . key1 [ 3 ]**[*].*.key3", true, 6}, 46 | {`$."key1 string"[ 3 ][*].*.key3`, true, 5}, 47 | {`$."hello \"escaped quotes\" world\\n"[3][*].*.key3`, true, 5}, 48 | 49 | {`$.\"escaped quotes\"[3][*].*.key3`, false, 0}, 50 | {`$.hello \"escaped quotes\" world[3][*].*.key3`, false, 0}, 51 | {`$NoValidLegsHere`, false, 0}, 52 | {`$ No Valid Legs Here .a.b.c`, false, 0}, 53 | } 54 | 55 | for _, tt := range tests { 56 | pe, err := ParseJSONPathExpr(tt.exprString) 57 | if tt.success { 58 | c.Assert(err, IsNil) 59 | c.Assert(len(pe.legs), Equals, tt.legs) 60 | } else { 61 | c.Assert(err, NotNil) 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /types/set_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package types 15 | 16 | import ( 17 | "github.com/hanchuanchuan/goInception/util/testleak" 18 | . "github.com/pingcap/check" 19 | ) 20 | 21 | var _ = Suite(&testSetSuite{}) 22 | 23 | type testSetSuite struct { 24 | } 25 | 26 | func (s *testSetSuite) TestSet(c *C) { 27 | defer testleak.AfterTest(c)() 28 | elems := []string{"a", "b", "c", "d"} 29 | tbl := []struct { 30 | Name string 31 | ExpectedValue uint64 32 | ExpectedName string 33 | }{ 34 | {"a", 1, "a"}, 35 | {"a,b,a", 3, "a,b"}, 36 | {"b,a", 3, "a,b"}, 37 | {"a,b,c,d", 15, "a,b,c,d"}, 38 | {"d", 8, "d"}, 39 | {"", 0, ""}, 40 | {"0", 0, ""}, 41 | } 42 | 43 | for _, t := range tbl { 44 | e, err := ParseSetName(elems, t.Name) 45 | c.Assert(err, IsNil) 46 | c.Assert(e.ToNumber(), Equals, float64(t.ExpectedValue)) 47 | c.Assert(e.String(), Equals, t.ExpectedName) 48 | } 49 | 50 | tblNumber := []struct { 51 | Number uint64 52 | ExpectedName string 53 | }{ 54 | {0, ""}, 55 | {1, "a"}, 56 | {3, "a,b"}, 57 | {9, "a,d"}, 58 | } 59 | 60 | for _, t := range tblNumber { 61 | e, err := ParseSetValue(elems, t.Number) 62 | c.Assert(err, IsNil) 63 | c.Assert(e.String(), Equals, t.ExpectedName) 64 | c.Assert(e.ToNumber(), Equals, float64(t.Number)) 65 | } 66 | 67 | tblErr := []string{ 68 | "a.e", 69 | "e.f", 70 | } 71 | for _, t := range tblErr { 72 | _, err := ParseSetName(elems, t) 73 | c.Assert(err, NotNil) 74 | } 75 | 76 | tblNumberErr := []uint64{ 77 | 100, 16, 64, 78 | } 79 | for _, t := range tblNumberErr { 80 | _, err := ParseSetValue(elems, t) 81 | c.Assert(err, NotNil) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /util/arena/arena_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package arena 15 | 16 | import ( 17 | "testing" 18 | ) 19 | 20 | func TestSimpleArenaAllocator(t *testing.T) { 21 | arena := NewAllocator(1000) 22 | slice := arena.Alloc(10) 23 | if arena.off != 10 { 24 | t.Error("off not match, expect 10 bug got", arena.off) 25 | } 26 | 27 | if len(slice) != 0 || cap(slice) != 10 { 28 | t.Error("slice length or cap not match") 29 | } 30 | 31 | slice = arena.Alloc(20) 32 | if arena.off != 30 { 33 | t.Error("off not match, expect 30 bug got", arena.off) 34 | } 35 | 36 | if len(slice) != 0 || cap(slice) != 20 { 37 | t.Error("slice length or cap not match") 38 | } 39 | 40 | slice = arena.Alloc(1024) 41 | if arena.off != 30 { 42 | t.Error("off not match, expect 30 bug got", arena.off) 43 | } 44 | 45 | if len(slice) != 0 || cap(slice) != 1024 { 46 | t.Error("slice length or cap not match") 47 | } 48 | 49 | slice = arena.AllocWithLen(2, 10) 50 | if arena.off != 40 { 51 | t.Error("off not match, expect 40 bug got", arena.off) 52 | } 53 | 54 | if len(slice) != 2 || cap(slice) != 10 { 55 | t.Error("slice length or cap not match") 56 | } 57 | 58 | arena.Reset() 59 | if arena.off != 0 || cap(arena.arena) != 1000 { 60 | t.Error("off or cap not match") 61 | } 62 | } 63 | 64 | func TestStdAllocator(t *testing.T) { 65 | slice := StdAllocator.Alloc(20) 66 | if len(slice) != 0 { 67 | t.Error("length not match") 68 | } 69 | 70 | if cap(slice) != 20 { 71 | t.Error("cap not match") 72 | } 73 | 74 | slice = StdAllocator.AllocWithLen(10, 20) 75 | if len(slice) != 10 { 76 | t.Error("length not match") 77 | } 78 | 79 | if cap(slice) != 20 { 80 | t.Error("cap not match") 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /util/auth/auth_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package auth 15 | 16 | import ( 17 | "github.com/hanchuanchuan/goInception/util/testleak" 18 | . "github.com/pingcap/check" 19 | ) 20 | 21 | var _ = Suite(&testAuthSuite{}) 22 | 23 | type testAuthSuite struct { 24 | } 25 | 26 | func (s *testAuthSuite) TestEncodePassword(c *C) { 27 | defer testleak.AfterTest(c)() 28 | pwd := "123" 29 | c.Assert(EncodePassword(pwd), Equals, "*23AE809DDACAF96AF0FD78ED04B6A265E05AA257") 30 | } 31 | 32 | func (s *testAuthSuite) TestDecodePassword(c *C) { 33 | defer testleak.AfterTest(c)() 34 | x, err := DecodePassword(EncodePassword("123")) 35 | c.Assert(err, IsNil) 36 | c.Assert(x, DeepEquals, Sha1Hash(Sha1Hash([]byte("123")))) 37 | } 38 | 39 | func (s *testAuthSuite) TestCheckScramble(c *C) { 40 | defer testleak.AfterTest(c)() 41 | pwd := "abc" 42 | salt := []byte{85, 92, 45, 22, 58, 79, 107, 6, 122, 125, 58, 80, 12, 90, 103, 32, 90, 10, 74, 82} 43 | auth := []byte{24, 180, 183, 225, 166, 6, 81, 102, 70, 248, 199, 143, 91, 204, 169, 9, 161, 171, 203, 33} 44 | encodepwd := EncodePassword(pwd) 45 | hpwd, err := DecodePassword(encodepwd) 46 | c.Assert(err, IsNil) 47 | 48 | res := CheckScrambledPassword(salt, hpwd, auth) 49 | c.Assert(res, IsTrue) 50 | } 51 | -------------------------------------------------------------------------------- /util/codec/decimal.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package codec 15 | 16 | import ( 17 | "github.com/hanchuanchuan/goInception/types" 18 | "github.com/pingcap/errors" 19 | ) 20 | 21 | // EncodeDecimal encodes a decimal into a byte slice which can be sorted lexicographically later. 22 | func EncodeDecimal(b []byte, dec *types.MyDecimal, precision, frac int) ([]byte, error) { 23 | if precision == 0 { 24 | precision, frac = dec.PrecisionAndFrac() 25 | } 26 | b = append(b, byte(precision), byte(frac)) 27 | bin, err := dec.ToBin(precision, frac) 28 | b = append(b, bin...) 29 | return b, errors.Trace(err) 30 | } 31 | 32 | // DecodeDecimal decodes bytes to decimal. 33 | func DecodeDecimal(b []byte) ([]byte, *types.MyDecimal, int, int, error) { 34 | // gofail: var errorInDecodeDecimal bool 35 | // if errorInDecodeDecimal { 36 | // return b, nil, 0, 0, errors.New("gofail error") 37 | // } 38 | 39 | if len(b) < 3 { 40 | return b, nil, 0, 0, errors.New("insufficient bytes to decode value") 41 | } 42 | precision := int(b[0]) 43 | frac := int(b[1]) 44 | b = b[2:] 45 | dec := new(types.MyDecimal) 46 | binSize, err := dec.FromBin(b, precision, frac) 47 | b = b[binSize:] 48 | if err != nil { 49 | return b, nil, precision, frac, errors.Trace(err) 50 | } 51 | return b, dec, precision, frac, nil 52 | } 53 | -------------------------------------------------------------------------------- /util/codec/float.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package codec 15 | 16 | import ( 17 | "math" 18 | 19 | "github.com/pingcap/errors" 20 | ) 21 | 22 | func encodeFloatToCmpUint64(f float64) uint64 { 23 | u := math.Float64bits(f) 24 | if f >= 0 { 25 | u |= signMask 26 | } else { 27 | u = ^u 28 | } 29 | return u 30 | } 31 | 32 | func decodeCmpUintToFloat(u uint64) float64 { 33 | if u&signMask > 0 { 34 | u &= ^signMask 35 | } else { 36 | u = ^u 37 | } 38 | return math.Float64frombits(u) 39 | } 40 | 41 | // EncodeFloat encodes a float v into a byte slice which can be sorted lexicographically later. 42 | // EncodeFloat guarantees that the encoded value is in ascending order for comparison. 43 | func EncodeFloat(b []byte, v float64) []byte { 44 | u := encodeFloatToCmpUint64(v) 45 | return EncodeUint(b, u) 46 | } 47 | 48 | // DecodeFloat decodes a float from a byte slice generated with EncodeFloat before. 49 | func DecodeFloat(b []byte) ([]byte, float64, error) { 50 | b, u, err := DecodeUint(b) 51 | return b, decodeCmpUintToFloat(u), errors.Trace(err) 52 | } 53 | 54 | // EncodeFloatDesc encodes a float v into a byte slice which can be sorted lexicographically later. 55 | // EncodeFloatDesc guarantees that the encoded value is in descending order for comparison. 56 | func EncodeFloatDesc(b []byte, v float64) []byte { 57 | u := encodeFloatToCmpUint64(v) 58 | return EncodeUintDesc(b, u) 59 | } 60 | 61 | // DecodeFloatDesc decodes a float from a byte slice generated with EncodeFloatDesc before. 62 | func DecodeFloatDesc(b []byte) ([]byte, float64, error) { 63 | b, u, err := DecodeUintDesc(b) 64 | return b, decodeCmpUintToFloat(u), errors.Trace(err) 65 | } 66 | -------------------------------------------------------------------------------- /util/execdetails/execdetails_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package execdetails 15 | 16 | import ( 17 | "testing" 18 | "time" 19 | ) 20 | 21 | func TestString(t *testing.T) { 22 | detail := &ExecDetails{ 23 | ProcessTime: time.Second, 24 | WaitTime: time.Second, 25 | BackoffTime: time.Second, 26 | RequestCount: 1, 27 | TotalKeys: 100, 28 | ProcessedKeys: 10, 29 | } 30 | expected := "process_time:1s wait_time:1s backoff_time:1s request_count:1 total_keys:100 processed_keys:10" 31 | if str := detail.String(); str != expected { 32 | t.Errorf("got:\n%s\nexpected:\n%s", str, expected) 33 | } 34 | detail = &ExecDetails{} 35 | if str := detail.String(); str != "" { 36 | t.Errorf("got:\n%s\nexpected:\n", str) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /util/format/format_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package format 15 | 16 | import ( 17 | "bytes" 18 | "io/ioutil" 19 | "testing" 20 | 21 | "github.com/hanchuanchuan/goInception/util/testleak" 22 | . "github.com/pingcap/check" 23 | ) 24 | 25 | func TestT(t *testing.T) { 26 | CustomVerboseFlag = true 27 | TestingT(t) 28 | } 29 | 30 | var _ = Suite(&testFormatSuite{}) 31 | 32 | type testFormatSuite struct { 33 | } 34 | 35 | func checkFormat(c *C, f Formatter, buf *bytes.Buffer, str, expect string) { 36 | _, err := f.Format(str, 3) 37 | c.Assert(err, IsNil) 38 | b, err := ioutil.ReadAll(buf) 39 | c.Assert(err, IsNil) 40 | c.Assert(string(b), Equals, expect) 41 | } 42 | 43 | func (s *testFormatSuite) TestFormat(c *C) { 44 | defer testleak.AfterTest(c)() 45 | str := "abc%d%%e%i\nx\ny\n%uz\n" 46 | buf := &bytes.Buffer{} 47 | f := IndentFormatter(buf, "\t") 48 | expect := `abc3%e 49 | x 50 | y 51 | z 52 | ` 53 | checkFormat(c, f, buf, str, expect) 54 | 55 | str = "abc%d%%e%i\nx\ny\n%uz\n%i\n" 56 | buf = &bytes.Buffer{} 57 | f = FlatFormatter(buf) 58 | expect = "abc3%e x y z\n " 59 | checkFormat(c, f, buf, str, expect) 60 | } 61 | -------------------------------------------------------------------------------- /util/hack/hack.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package hack 15 | 16 | import ( 17 | "reflect" 18 | "unsafe" 19 | ) 20 | 21 | // String converts slice to string without copy. 22 | // Use at your own risk. 23 | func String(b []byte) (s string) { 24 | if len(b) == 0 { 25 | return "" 26 | } 27 | pbytes := (*reflect.SliceHeader)(unsafe.Pointer(&b)) 28 | pstring := (*reflect.StringHeader)(unsafe.Pointer(&s)) 29 | pstring.Data = pbytes.Data 30 | pstring.Len = pbytes.Len 31 | return 32 | } 33 | 34 | // Slice converts string to slice without copy. 35 | // Use at your own risk. 36 | func Slice(s string) (b []byte) { 37 | pbytes := (*reflect.SliceHeader)(unsafe.Pointer(&b)) 38 | pstring := (*reflect.StringHeader)(unsafe.Pointer(&s)) 39 | pbytes.Data = pstring.Data 40 | pbytes.Len = pstring.Len 41 | pbytes.Cap = pstring.Len 42 | return 43 | } 44 | -------------------------------------------------------------------------------- /util/hack/hack_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package hack 15 | 16 | import ( 17 | "bytes" 18 | "testing" 19 | ) 20 | 21 | func TestString(t *testing.T) { 22 | b := []byte("hello world") 23 | a := String(b) 24 | 25 | if a != "hello world" { 26 | t.Fatal(a) 27 | } 28 | 29 | b[0] = 'a' 30 | 31 | if a != "aello world" { 32 | t.Fatal(a) 33 | } 34 | 35 | b = append(b, "abc"...) 36 | if a != "aello world" { 37 | t.Fatalf("a:%v, b:%v", a, b) 38 | } 39 | } 40 | 41 | func TestByte(t *testing.T) { 42 | a := "hello world" 43 | 44 | b := Slice(a) 45 | 46 | if !bytes.Equal(b, []byte("hello world")) { 47 | t.Fatal(string(b)) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /util/israce/israce.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | // +build race 15 | 16 | package israce 17 | 18 | // RaceEnabled checks if race is enabled. 19 | const RaceEnabled = true 20 | -------------------------------------------------------------------------------- /util/israce/norace.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | // +build !race 15 | 16 | package israce 17 | 18 | // RaceEnabled checks if race is enabled. 19 | const RaceEnabled = false 20 | -------------------------------------------------------------------------------- /util/misc_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package util 15 | 16 | import ( 17 | "github.com/hanchuanchuan/goInception/util/testleak" 18 | . "github.com/pingcap/check" 19 | "github.com/pingcap/errors" 20 | ) 21 | 22 | var _ = Suite(&testMiscSuite{}) 23 | 24 | type testMiscSuite struct { 25 | } 26 | 27 | func (s *testMiscSuite) SetUpSuite(c *C) { 28 | } 29 | 30 | func (s *testMiscSuite) TearDownSuite(c *C) { 31 | } 32 | 33 | func (s testMiscSuite) TestRunWithRetry(c *C) { 34 | defer testleak.AfterTest(c)() 35 | // Run succ. 36 | cnt := 0 37 | err := RunWithRetry(3, 1, func() (bool, error) { 38 | cnt++ 39 | if cnt < 2 { 40 | return true, errors.New("err") 41 | } 42 | return true, nil 43 | }) 44 | c.Assert(err, IsNil) 45 | c.Assert(cnt, Equals, 2) 46 | 47 | // Run failed. 48 | cnt = 0 49 | err = RunWithRetry(3, 1, func() (bool, error) { 50 | cnt++ 51 | if cnt < 4 { 52 | return true, errors.New("err") 53 | } 54 | return true, nil 55 | }) 56 | c.Assert(err, NotNil) 57 | c.Assert(cnt, Equals, 3) 58 | 59 | // Run failed. 60 | cnt = 0 61 | err = RunWithRetry(3, 1, func() (bool, error) { 62 | cnt++ 63 | if cnt < 2 { 64 | return false, errors.New("err") 65 | } 66 | return true, nil 67 | }) 68 | c.Assert(err, NotNil) 69 | c.Assert(cnt, Equals, 1) 70 | } 71 | -------------------------------------------------------------------------------- /util/mock/mock_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package mock 15 | 16 | import ( 17 | "testing" 18 | 19 | "github.com/hanchuanchuan/goInception/util/testleak" 20 | . "github.com/pingcap/check" 21 | ) 22 | 23 | func TestT(t *testing.T) { 24 | CustomVerboseFlag = true 25 | TestingT(t) 26 | } 27 | 28 | var _ = Suite(&testMockSuite{}) 29 | 30 | type testMockSuite struct { 31 | } 32 | 33 | type contextKeyType int 34 | 35 | func (k contextKeyType) String() string { 36 | return "mock_key" 37 | } 38 | 39 | const contextKey contextKeyType = 0 40 | 41 | func (s *testMockSuite) TestContext(c *C) { 42 | defer testleak.AfterTest(c)() 43 | ctx := NewContext() 44 | 45 | ctx.SetValue(contextKey, 1) 46 | v := ctx.Value(contextKey) 47 | c.Assert(v, Equals, 1) 48 | 49 | ctx.ClearValue(contextKey) 50 | v = ctx.Value(contextKey) 51 | c.Assert(v, IsNil) 52 | } 53 | 54 | func BenchmarkNewContext(b *testing.B) { 55 | b.ReportAllocs() 56 | for i := 0; i < b.N; i++ { 57 | NewContext() 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /util/mock/store.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package mock 15 | 16 | import ( 17 | "github.com/hanchuanchuan/goInception/kv" 18 | "github.com/hanchuanchuan/goInception/store/tikv/oracle" 19 | ) 20 | 21 | // Store implements kv.Storage interface. 22 | type Store struct { 23 | Client kv.Client 24 | } 25 | 26 | // GetClient implements kv.Storage interface. 27 | func (s *Store) GetClient() kv.Client { return s.Client } 28 | 29 | // GetOracle implements kv.Storage interface. 30 | func (s *Store) GetOracle() oracle.Oracle { return nil } 31 | 32 | // Begin implements kv.Storage interface. 33 | func (s *Store) Begin() (kv.Transaction, error) { return nil, nil } 34 | 35 | // BeginWithStartTS implements kv.Storage interface. 36 | func (s *Store) BeginWithStartTS(startTS uint64) (kv.Transaction, error) { return s.Begin() } 37 | 38 | // GetSnapshot implements kv.Storage interface. 39 | func (s *Store) GetSnapshot(ver kv.Version) (kv.Snapshot, error) { return nil, nil } 40 | 41 | // Close implements kv.Storage interface. 42 | func (s *Store) Close() error { return nil } 43 | 44 | // UUID implements kv.Storage interface. 45 | func (s *Store) UUID() string { return "mock" } 46 | 47 | // CurrentVersion implements kv.Storage interface. 48 | func (s *Store) CurrentVersion() (kv.Version, error) { return kv.Version{}, nil } 49 | 50 | // SupportDeleteRange implements kv.Storage interface. 51 | func (s *Store) SupportDeleteRange() bool { return false } 52 | -------------------------------------------------------------------------------- /util/mvmap/fnv.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Copyright 2017 PingCAP, Inc. 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package mvmap 19 | 20 | const ( 21 | offset64 uint64 = 14695981039346656037 22 | prime64 = 1099511628211 23 | ) 24 | 25 | // fnvHash64 is ported from go library, which is thread-safe. 26 | func fnvHash64(data []byte) uint64 { 27 | hash := offset64 28 | for _, c := range data { 29 | hash *= prime64 30 | hash ^= uint64(c) 31 | } 32 | return hash 33 | } 34 | -------------------------------------------------------------------------------- /util/printer/printer_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package printer 15 | 16 | import ( 17 | "testing" 18 | 19 | "github.com/hanchuanchuan/goInception/util/testleak" 20 | . "github.com/pingcap/check" 21 | ) 22 | 23 | func TestT(t *testing.T) { 24 | CustomVerboseFlag = true 25 | TestingT(t) 26 | } 27 | 28 | var _ = Suite(&testPrinterSuite{}) 29 | 30 | type testPrinterSuite struct { 31 | } 32 | 33 | func (s *testPrinterSuite) TestPrintResult(c *C) { 34 | defer testleak.AfterTest(c)() 35 | cols := []string{"col1", "col2", "col3"} 36 | datas := [][]string{{"11"}, {"21", "22", "23"}} 37 | result, ok := GetPrintResult(cols, datas) 38 | c.Assert(ok, IsFalse) 39 | c.Assert(result, Equals, "") 40 | 41 | datas = [][]string{{"11", "12", "13"}, {"21", "22", "23"}} 42 | expect := ` 43 | +------+------+------+ 44 | | col1 | col2 | col3 | 45 | +------+------+------+ 46 | | 11 | 12 | 13 | 47 | | 21 | 22 | 23 | 48 | +------+------+------+ 49 | ` 50 | result, ok = GetPrintResult(cols, datas) 51 | c.Assert(ok, IsTrue) 52 | c.Assert(result, Equals, expect[1:]) 53 | 54 | datas = nil 55 | result, ok = GetPrintResult(cols, datas) 56 | c.Assert(ok, IsFalse) 57 | c.Assert(result, Equals, "") 58 | 59 | cols = nil 60 | result, ok = GetPrintResult(cols, datas) 61 | c.Assert(ok, IsFalse) 62 | c.Assert(result, Equals, "") 63 | } 64 | -------------------------------------------------------------------------------- /util/random.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package util 15 | 16 | import ( 17 | "math/rand" 18 | ) 19 | 20 | // RandomBuf generates a random string using ASCII characters but avoid separator character. 21 | // See https://github.com/mysql/mysql-server/blob/5.7/mysys_ssl/crypt_genhash_impl.cc#L435 22 | func RandomBuf(size int) []byte { 23 | buf := make([]byte, size) 24 | for i := 0; i < size; i++ { 25 | buf[i] = byte(rand.Intn(127)) 26 | if buf[i] == 0 || buf[i] == byte('$') { 27 | buf[i]++ 28 | } 29 | } 30 | return buf 31 | } 32 | -------------------------------------------------------------------------------- /util/set/decimal_set.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package set 15 | 16 | import ( 17 | "github.com/hanchuanchuan/goInception/types" 18 | ) 19 | 20 | // DecimalSet is a decimal set. 21 | type DecimalSet map[types.MyDecimal]struct{} 22 | 23 | // NewDecimalSet builds a decimal set. 24 | func NewDecimalSet() DecimalSet { 25 | return make(map[types.MyDecimal]struct{}) 26 | } 27 | 28 | // Exist checks whether `val` exists in `s`. 29 | func (s DecimalSet) Exist(val *types.MyDecimal) bool { 30 | _, ok := s[*val] 31 | return ok 32 | } 33 | 34 | // Insert inserts `val` into `s`. 35 | func (s DecimalSet) Insert(val *types.MyDecimal) { 36 | s[*val] = struct{}{} 37 | } 38 | -------------------------------------------------------------------------------- /util/set/float64_set.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package set 15 | 16 | // Float64Set is a float64 set. 17 | type Float64Set map[float64]struct{} 18 | 19 | // NewFloat64Set builds a float64 set. 20 | func NewFloat64Set() Float64Set { 21 | return make(map[float64]struct{}) 22 | } 23 | 24 | // Exist checks whether `val` exists in `s`. 25 | func (s Float64Set) Exist(val float64) bool { 26 | _, ok := s[val] 27 | return ok 28 | } 29 | 30 | // Insert inserts `val` into `s`. 31 | func (s Float64Set) Insert(val float64) { 32 | s[val] = struct{}{} 33 | } 34 | -------------------------------------------------------------------------------- /util/set/string_set.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package set 15 | 16 | // StringSet is a string set. 17 | type StringSet map[string]struct{} 18 | 19 | // NewStringSet builds a float64 set. 20 | func NewStringSet() StringSet { 21 | return make(map[string]struct{}) 22 | } 23 | 24 | // Exist checks whether `val` exists in `s`. 25 | func (s StringSet) Exist(val string) bool { 26 | _, ok := s[val] 27 | return ok 28 | } 29 | 30 | // Insert inserts `val` into `s`. 31 | func (s StringSet) Insert(val string) { 32 | s[val] = struct{}{} 33 | } 34 | -------------------------------------------------------------------------------- /util/signal/signal_posix.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | // +build linux darwin freebsd unix 14 | 15 | package signal 16 | 17 | import ( 18 | "os" 19 | "os/signal" 20 | "runtime" 21 | "syscall" 22 | 23 | log "github.com/sirupsen/logrus" 24 | ) 25 | 26 | // SetupSignalHandler setup signal handler for TiDB Server 27 | func SetupSignalHandler(ignoreSighup bool, shudownFunc func(bool)) { 28 | usrDefSignalChan := make(chan os.Signal, 1) 29 | 30 | signal.Notify(usrDefSignalChan, syscall.SIGUSR1) 31 | go func() { 32 | buf := make([]byte, 1<<16) 33 | for { 34 | sig := <-usrDefSignalChan 35 | if sig == syscall.SIGUSR1 { 36 | stackLen := runtime.Stack(buf, true) 37 | log.Printf("\n=== Got signal [%s] to dump goroutine stack. ===\n%s\n=== Finished dumping goroutine stack. ===\n", sig, buf[:stackLen]) 38 | } 39 | } 40 | }() 41 | 42 | closeSignalChan := make(chan os.Signal, 1) 43 | 44 | // 忽略信号 终端控制进程结束(终端连接断开) 45 | if ignoreSighup { 46 | signal.Ignore(syscall.SIGHUP) 47 | signal.Notify(closeSignalChan, 48 | syscall.SIGINT, 49 | syscall.SIGTERM, 50 | syscall.SIGQUIT) 51 | } else { 52 | signal.Notify(closeSignalChan, 53 | syscall.SIGHUP, 54 | syscall.SIGINT, 55 | syscall.SIGTERM, 56 | syscall.SIGQUIT) 57 | } 58 | 59 | go func() { 60 | sig := <-closeSignalChan 61 | log.Infof("Got signal [%s] to exit.", sig) 62 | shudownFunc(sig == syscall.SIGQUIT) 63 | }() 64 | } 65 | -------------------------------------------------------------------------------- /util/signal/signal_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | // +build windows 14 | 15 | package signal 16 | 17 | import ( 18 | "os" 19 | "os/signal" 20 | "syscall" 21 | 22 | log "github.com/sirupsen/logrus" 23 | ) 24 | 25 | // SetupSignalHandler setup signal handler for TiDB Server 26 | func SetupSignalHandler(shudownFunc func(bool)) { 27 | //todo deal with dump goroutine stack on windows 28 | closeSignalChan := make(chan os.Signal, 1) 29 | signal.Notify(closeSignalChan, 30 | syscall.SIGHUP, 31 | syscall.SIGINT, 32 | syscall.SIGTERM, 33 | syscall.SIGQUIT) 34 | 35 | go func() { 36 | sig := <-closeSignalChan 37 | log.Infof("Got signal [%s] to exit.", sig) 38 | shudownFunc(sig == syscall.SIGQUIT) 39 | }() 40 | } 41 | -------------------------------------------------------------------------------- /util/testkit/testkit_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package testkit 15 | 16 | import ( 17 | "testing" 18 | 19 | "github.com/pingcap/check" 20 | ) 21 | 22 | var _ = check.Suite(&testKitSuite{}) 23 | 24 | func TestT(t *testing.T) { 25 | check.TestingT(t) 26 | } 27 | 28 | type testKitSuite struct { 29 | } 30 | 31 | func (s testKitSuite) TestSort(c *check.C) { 32 | result := &Result{ 33 | rows: [][]string{{"1", "1", "", ""}, {"2", "2", "2", "3"}}, 34 | c: c, 35 | comment: check.Commentf(""), 36 | } 37 | result.Sort().Check(Rows("1 1 ", "2 2 2 3")) 38 | } 39 | -------------------------------------------------------------------------------- /util/testleak/add-leaktest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Usage: add-leaktest.sh pkg/*_test.go 4 | 5 | set -eu 6 | 7 | sed -i'~' -e ' 8 | /^func (s \*test.*Suite) Test.*(c \*C) {/ { 9 | n 10 | /testleak.AfterTest/! i\ 11 | defer testleak.AfterTest(c)() 12 | } 13 | ' $@ 14 | 15 | for i in $@; do 16 | if ! cmp -s $i $i~ ; then 17 | goimports -w $i 18 | fi 19 | echo $i 20 | rm -f $i~ 21 | done 22 | -------------------------------------------------------------------------------- /util/testleak/check-leaktest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Usage: check-leaktest.sh 4 | # It needs to run under the github.com/pingcap/tidb directory. 5 | 6 | set -e 7 | 8 | pkgs=$(git grep 'Suite' |grep -vE "Godeps|tags" |awk -F: '{print $1}' | xargs -n1 dirname | sort |uniq) 9 | echo $pkgs 10 | for pkg in ${pkgs}; do 11 | if [ -z "$(ls ${pkg}/*_test.go 2>/dev/null)" ]; then 12 | continue 13 | fi 14 | awk -F'[(]' ' 15 | /func \(s .*Suite\) Test.*C\) {/ { 16 | test = $1"("$2 17 | next 18 | } 19 | 20 | /defer testleak.AfterTest/ { 21 | test = 0 22 | next 23 | } 24 | 25 | { 26 | if (test && (FILENAME != "./tidb_test.go")) { 27 | printf "%s: %s: missing defer testleak.AfterTest\n", FILENAME, test 28 | test = 0 29 | code = 1 30 | } 31 | } 32 | 33 | END { 34 | exit code 35 | } 36 | 37 | ' ${pkg}/*_test.go 38 | done 39 | -------------------------------------------------------------------------------- /util/testleak/fake.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | // +build !leak 14 | 15 | package testleak 16 | 17 | import "github.com/pingcap/check" 18 | 19 | // BeforeTest is a dummy implementation when build tag 'leak' is not set. 20 | func BeforeTest() { 21 | } 22 | 23 | // AfterTest is a dummy implementation when build tag 'leak' is not set. 24 | func AfterTest(c *check.C) func() { 25 | return func() { 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /util/testutil/testutil_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package testutil 15 | 16 | import ( 17 | "testing" 18 | 19 | "github.com/hanchuanchuan/goInception/util/testleak" 20 | . "github.com/pingcap/check" 21 | ) 22 | 23 | func TestT(t *testing.T) { 24 | CustomVerboseFlag = true 25 | TestingT(t) 26 | } 27 | 28 | var _ = Suite(&testTestUtilSuite{}) 29 | 30 | type testTestUtilSuite struct { 31 | } 32 | 33 | func (s *testTestUtilSuite) TestCompareUnorderedString(c *C) { 34 | defer testleak.AfterTest(c)() 35 | tbl := []struct { 36 | a []string 37 | b []string 38 | r bool 39 | }{ 40 | {[]string{"1", "1", "2"}, []string{"1", "1", "2"}, true}, 41 | {[]string{"1", "1", "2"}, []string{"1", "2", "1"}, true}, 42 | {[]string{"1", "1"}, []string{"1", "2", "1"}, false}, 43 | {[]string{"1", "1", "2"}, []string{"1", "2", "2"}, false}, 44 | {nil, nil, true}, 45 | {[]string{}, nil, false}, 46 | {nil, []string{}, false}, 47 | } 48 | for _, t := range tbl { 49 | c.Assert(CompareUnorderedStringSlice(t.a, t.b), Equals, t.r) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /util/timeutil/time_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 PingCAP, Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSES/QL-LICENSE file. 4 | 5 | // Copyright 2015 PingCAP, Inc. 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package timeutil 19 | 20 | import ( 21 | "os" 22 | "testing" 23 | 24 | . "github.com/pingcap/check" 25 | ) 26 | 27 | var _ = Suite(&testTimeSuite{}) 28 | 29 | func TestT(t *testing.T) { 30 | TestingT(t) 31 | } 32 | 33 | type testTimeSuite struct{} 34 | 35 | func (s *testTimeSuite) TestgetTZNameFromFileName(c *C) { 36 | tz, err := inferTZNameFromFileName("/user/share/zoneinfo/Asia/Shanghai") 37 | 38 | c.Assert(err, IsNil) 39 | c.Assert(tz, Equals, "Asia/Shanghai") 40 | 41 | tz, err = inferTZNameFromFileName("/usr/share/zoneinfo.default/Asia/Shanghai") 42 | 43 | c.Assert(err, IsNil) 44 | c.Assert(tz, Equals, "Asia/Shanghai") 45 | } 46 | 47 | func (s *testTimeSuite) TestLocal(c *C) { 48 | os.Setenv("TZ", "Asia/Shanghai") 49 | systemTZ = InferSystemTZ() 50 | loc := SystemLocation() 51 | c.Assert(systemTZ, Equals, "Asia/Shanghai") 52 | c.Assert(loc.String(), Equals, "Asia/Shanghai") 53 | 54 | os.Setenv("TZ", "UTC") 55 | // reset systemTZ 56 | systemTZ = InferSystemTZ() 57 | loc = SystemLocation() 58 | c.Assert(loc.String(), Equals, "UTC") 59 | 60 | os.Setenv("TZ", "") 61 | // reset systemTZ 62 | systemTZ = InferSystemTZ() 63 | loc = SystemLocation() 64 | c.Assert(loc.String(), Equals, "UTC") 65 | os.Unsetenv("TZ") 66 | } 67 | --------------------------------------------------------------------------------