mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 20:12:31 +01:00
4dabfa5de7
into mysql.com:/home/kent/bk/main/mysql-5.1 BUILD/Makefile.am: Auto merged BitKeeper/deleted/.del-ArrayFifoList.hpp~7036ae04dd7e7bd2: Auto merged BitKeeper/deleted/.del-ArrayList.hpp~44695d09b1a02179: Auto merged BitKeeper/deleted/.del-DbtupLCP.cpp~855b1ed3fbc86a42: Auto merged BitKeeper/deleted/.del-DbtupSystemRestart.cpp~15b54d7e4e75d2d: Auto merged BitKeeper/deleted/.del-DbtupUndoLog.cpp~5a2ef6e86b1404e9: Auto merged Makefile.am: Auto merged BitKeeper/deleted/.del-Makefile.am~2: Auto merged BitKeeper/deleted/.del-Makefile.am~ab5c84d46412dc2e: Auto merged BitKeeper/deleted/.del-Makefile.am~abb265028eb9b6a7: Auto merged BitKeeper/deleted/.del-Makefile.am~de166d6fcac3b9b6: Auto merged BitKeeper/deleted/.del-Makefile.am~e5b911533dad2713: Auto merged BitKeeper/deleted/.del-Makefile.am~ead19441cc5ff35c: Auto merged BitKeeper/deleted/.del-Makefile.am~f87185e232d7c4f: Auto merged BitKeeper/deleted/.del-Makefile.in: Auto merged BitKeeper/deleted/.del-MemoryChannelOSE.hpp: Auto merged BitKeeper/deleted/.del-MetaData.cpp~146ae9865dd35829: Auto merged BitKeeper/deleted/.del-MetaData.hpp~538342afcd8ac53c: Auto merged BitKeeper/deleted/.del-NdbCondition.c~ad83464328ab37af: Auto merged BitKeeper/deleted/.del-NdbCondition.c~ee56562abdd718cf: Auto merged BitKeeper/deleted/.del-NdbConditionOSE.h~455dd2c29c2e6344: Auto merged BitKeeper/deleted/.del-NdbDaemon.c~3b8101f376b28df: Auto merged BitKeeper/deleted/.del-NdbEnv.c~207f9ce9754c9e8a: Auto merged BitKeeper/deleted/.del-NdbEnv.c~bb6fe7572d45288a: Auto merged BitKeeper/deleted/.del-NdbErrHnd.cpp: Auto merged BitKeeper/deleted/.del-NdbHost.c~2c29816c77396d7b: Auto merged BitKeeper/deleted/.del-NdbHost.c~cf18d6b3c825180c: Auto merged BitKeeper/deleted/.del-NdbMem.c~6285b159985d46da: Auto merged BitKeeper/deleted/.del-NdbMem.c~6c2b317c1ce230ab: Auto merged BitKeeper/deleted/.del-NdbMem_SoftOse.cpp~9c61e311ec168d44: Auto merged BitKeeper/deleted/.del-NdbMutex.c~768131269bccca10: Auto merged BitKeeper/deleted/.del-NdbMutex.c~f4bdd19be08b84ab: Auto merged BitKeeper/deleted/.del-NdbOut.cpp~8caa99a0d729540c: Auto merged BitKeeper/deleted/.del-NdbSleep.c~b643ea3e7103eb62: Auto merged BitKeeper/deleted/.del-NdbSleep.c~b88fbc5b140de10d: Auto merged BitKeeper/deleted/.del-NdbTCP.c~1e9f416992352f6d: Auto merged BitKeeper/deleted/.del-NdbTCP.c~b09cdcbef3ea2c57: Auto merged BitKeeper/deleted/.del-NdbThread.c~2fe1fa5f47801772: Auto merged BitKeeper/deleted/.del-NdbThread.c~fe71a67b5c3a4724: Auto merged BitKeeper/deleted/.del-NdbTick.c~aa6385567216509d: Auto merged BitKeeper/deleted/.del-NdbTick.c~b76feba2cf1493d1: Auto merged BitKeeper/deleted/.del-OSE_Receiver.cpp: Auto merged BitKeeper/deleted/.del-OSE_Receiver.hpp: Auto merged BitKeeper/deleted/.del-OSE_Signals.hpp: Auto merged BitKeeper/deleted/.del-OSE_Transporter.cpp: Auto merged BitKeeper/deleted/.del-OSE_Transporter.hpp: Auto merged BitKeeper/deleted/.del-TraceNdbApi.hpp~7a7f0ae5b70358bc: Auto merged BitKeeper/deleted/.del-VerifyNdbApi.hpp~f417f78f7cd05935: Auto merged BitKeeper/deleted/.del-bcd.h~81fbfcc1530534da: Auto merged BitKeeper/deleted/.del-config-os2.h~a16b51851ddd317b: Auto merged BitKeeper/deleted/.del-dbGenerator.c~7509c19f70cad0bf: Auto merged BitKeeper/deleted/.del-dbGenerator.h~63f1aeb98260bcb7: Auto merged BitKeeper/deleted/.del-dbGenerator.h~e1aaa6725999d458: Auto merged BitKeeper/deleted/.del-dbPopulate.c~5dcff1c99783d83b: Auto merged BitKeeper/deleted/.del-dbPopulate.h~229a894b59d4da73: Auto merged BitKeeper/deleted/.del-ha_berkeley.cc: Auto merged BitKeeper/deleted/.del-ha_berkeley.h: Auto merged BitKeeper/deleted/.del-localDbPrepare.c~33a2c46afc8fac9a: Auto merged BitKeeper/deleted/.del-macros.h~58097d584e29b5df: Auto merged BitKeeper/deleted/.del-macros.h~742871fab0681964: Auto merged BitKeeper/deleted/.del-mainGenerator.c~2d1c8016f72b2517: Auto merged BitKeeper/deleted/.del-mainPopulate.c~37def9a44980b8ec: Auto merged BitKeeper/deleted/.del-mgmapi_logevent.cpp~f1e7cf3e70edc4: Auto merged BitKeeper/deleted/.del-mmslist.cpp: Auto merged BitKeeper/deleted/.del-my_lread.c: Auto merged BitKeeper/deleted/.del-my_lwrite.c: Auto merged BitKeeper/deleted/.del-my_os2cond.c~e3b520af1c371bb5: Auto merged BitKeeper/deleted/.del-my_os2dirsrch.c~4e2479b2abb2eb5a: Auto merged BitKeeper/deleted/.del-my_os2dirsrch.h~5011cbc657537d0: Auto merged BitKeeper/deleted/.del-my_os2dlfcn.c~6d94b488717683dd: Auto merged BitKeeper/deleted/.del-my_os2dlfcn.h0~eae8edb8555eff87: Auto merged BitKeeper/deleted/.del-my_os2file64.c~251fb8a1e950c31b: Auto merged BitKeeper/deleted/.del-my_os2thread.c~65dca991548cec2a: Auto merged BitKeeper/deleted/.del-my_os2tls.c~58ade7a0f70ad5ea: Auto merged BitKeeper/deleted/.del-mysqlmanager-pwgen.c~d8f5f91ec54432b9: Auto merged BitKeeper/deleted/.del-mysqlmanager.c~e97636d71145a0b: Auto merged BitKeeper/deleted/.del-mysqlmanagerc.c~4f6e3499e68508f6: Auto merged BitKeeper/deleted/.del-ndb_error.hpp~24468bb7f20a0b41: Auto merged BitKeeper/deleted/.del-ndb_error.hpp~45a2fef922beae3: Auto merged BitKeeper/deleted/.del-ndb_schema.hpp~de9c21185d6bfe4e: Auto merged BitKeeper/deleted/.del-ndbapi_async.cpp~319189569fb659ec: Auto merged BitKeeper/deleted/.del-ndbapi_async1.cpp~2995dac9b963a0d: Auto merged BitKeeper/deleted/.del-ndbapi_event.cpp~c5d949802966180: Auto merged BitKeeper/deleted/.del-ndbapi_retries.cpp~7301496d8c1c310a: Auto merged BitKeeper/deleted/.del-ndbapi_scan.cpp~14ed2aa9a5d9e597: Auto merged BitKeeper/deleted/.del-ndbapi_simple.cpp~80962179f3c2f5b8: Auto merged BitKeeper/deleted/.del-ndbapi_simple_index.cpp~4b95a4d71808b5b6: Auto merged BitKeeper/deleted/.del-print-limit-table~b8e808031daa3758: Auto merged BitKeeper/deleted/.del-raid.cc~488f5fa6538394e1: Auto merged BitKeeper/deleted/.del-raid.h~2d2503a66b128ac6: Auto merged BitKeeper/deleted/.del-raid2.c~fe7aea5fb4b9748c: Auto merged BitKeeper/deleted/.del-sql_manager.h: Auto merged BitKeeper/deleted/.del-testData.h~696038ea2623a90b: Auto merged BitKeeper/deleted/.del-testData.h~898b71d7c639319e: Auto merged BitKeeper/deleted/.del-testDefinitions.h~f18a4553579a3725: Auto merged BitKeeper/deleted/.del-userHandle.h~3275bb415e1ca2c2: Auto merged BitKeeper/deleted/.del-userHandle.h~ec22dc7a7ed2f81b: Auto merged BitKeeper/deleted/.del-userInterface.cpp~82ee612ab14b3d48: Auto merged BitKeeper/deleted/.del-userInterface.c~92a20032f7d1e91: Auto merged BitKeeper/deleted/.del-userInterface.h~1f76ad2f28b283fd: Auto merged BitKeeper/deleted/.del-userInterface.h~49139f029bbdaabc: Auto merged BitKeeper/deleted/.del-userTransaction.c~438012ecc761b776: Auto merged BitKeeper/deleted/.del-userTransaction.c~f50661b4f54b0bdd: Auto merged BitKeeper/deleted/.del-utv.h~f64af026b9705ebb: Auto merged BitKeeper/deleted/.del-vcdrfunc.h~85803875180684cd: Auto merged BitKeeper/deleted/.del-waiter.cpp~b188e4bfddf2cf98: Auto merged Docs/Makefile.am: Auto merged client/Makefile.am: Auto merged client/client_priv.h: Auto merged client/get_password.c: Auto merged client/mysql.cc: Auto merged client/mysql_upgrade.c: Auto merged client/mysqladmin.cc: Auto merged client/mysqlbinlog.cc: Auto merged client/mysqlcheck.c: Auto merged client/mysqldump.c: Auto merged client/mysqlimport.c: Auto merged client/mysqlshow.c: Auto merged client/mysqltest.c: Auto merged dbug/Makefile.am: Auto merged extra/Makefile.am: Auto merged extra/comp_err.c: Auto merged extra/perror.c: Auto merged extra/replace.c: Auto merged extra/resolveip.c: Auto merged include/Makefile.am: Auto merged include/base64.h: Auto merged include/config-netware.h: Auto merged include/config-win.h: Auto merged include/decimal.h: Auto merged include/errmsg.h: Auto merged include/ft_global.h: Auto merged include/heap.h: Auto merged include/m_ctype.h: Auto merged include/m_string.h: Auto merged include/my_base.h: Auto merged include/my_bitmap.h: Auto merged include/my_dbug.h: Auto merged include/my_global.h: Auto merged include/my_net.h: Auto merged include/my_no_pthread.h: Auto merged include/my_nosys.h: Auto merged include/my_pthread.h: Auto merged include/my_sys.h: Auto merged include/my_time.h: Auto merged include/my_tree.h: Auto merged include/my_xml.h: Auto merged include/myisam.h: Auto merged include/myisammrg.h: Auto merged include/mysql.h: Auto merged include/mysql_com.h: Auto merged include/mysys_err.h: Auto merged include/queues.h: Auto merged include/thr_alarm.h: Auto merged include/thr_lock.h: Auto merged include/violite.h: Auto merged libmysqld/Makefile.am: Auto merged libmysqld/emb_qcache.cc: Auto merged libmysqld/embedded_priv.h: Auto merged libmysqld/examples/Makefile.am: Auto merged libmysqld/libmysqld.c: Auto merged mysql-test/Makefile.am: Auto merged mysys/Makefile.am: Auto merged mysys/array.c: Auto merged mysys/base64.c: Auto merged mysys/charset-def.c: Auto merged mysys/default.c: Auto merged mysys/default_modify.c: Auto merged mysys/errors.c: Auto merged mysys/hash.c: Auto merged mysys/mf_dirname.c: Auto merged mysys/mf_format.c: Auto merged mysys/mf_iocache.c: Auto merged mysys/mf_iocache2.c: Auto merged mysys/mf_keycache.c: Auto merged mysys/mf_pack.c: Auto merged mysys/mf_path.c: Auto merged mysys/mf_tempdir.c: Auto merged mysys/mf_tempfile.c: Auto merged mysys/my_access.c: Auto merged mysys/my_alloc.c: Auto merged mysys/my_append.c: Auto merged mysys/my_bit.c: Auto merged mysys/my_bitmap.c: Auto merged mysys/my_clock.c: Auto merged mysys/my_compress.c: Auto merged mysys/my_copy.c: Auto merged mysys/my_create.c: Auto merged mysys/my_dup.c: Auto merged mysys/my_error.c: Auto merged mysys/my_file.c: Auto merged mysys/my_gethostbyname.c: Auto merged mysys/my_getopt.c: Auto merged mysys/my_getwd.c: Auto merged mysys/my_handler.c: Auto merged mysys/my_init.c: Auto merged mysys/my_lib.c: Auto merged mysys/my_lock.c: Auto merged mysys/my_malloc.c: Auto merged mysys/my_mkdir.c: Auto merged mysys/my_mmap.c: Auto merged mysys/my_net.c: Auto merged mysys/my_once.c: Auto merged mysys/my_open.c: Auto merged mysys/my_pread.c: Auto merged mysys/my_pthread.c: Auto merged mysys/my_redel.c: Auto merged mysys/my_rename.c: Auto merged mysys/my_seek.c: Auto merged mysys/my_sleep.c: Auto merged mysys/my_static.c: Auto merged mysys/my_symlink2.c: Auto merged mysys/my_thr_init.c: Auto merged mysys/mysys_priv.h: Auto merged mysys/ptr_cmp.c: Auto merged mysys/queues.c: Auto merged mysys/safemalloc.c: Auto merged mysys/string.c: Auto merged mysys/test_dir.c: Auto merged mysys/testhash.c: Auto merged mysys/thr_alarm.c: Auto merged mysys/thr_lock.c: Auto merged mysys/thr_mutex.c: Auto merged regex/Makefile.am: Auto merged scripts/Makefile.am: Auto merged server-tools/instance-manager/Makefile.am: Auto merged server-tools/instance-manager/buffer.cc: Auto merged server-tools/instance-manager/command.cc: Auto merged server-tools/instance-manager/command.h: Auto merged server-tools/instance-manager/commands.cc: Auto merged server-tools/instance-manager/commands.h: Auto merged server-tools/instance-manager/guardian.cc: Auto merged server-tools/instance-manager/guardian.h: Auto merged server-tools/instance-manager/instance.cc: Auto merged server-tools/instance-manager/instance.h: Auto merged server-tools/instance-manager/instance_map.cc: Auto merged server-tools/instance-manager/instance_map.h: Auto merged server-tools/instance-manager/instance_options.cc: Auto merged server-tools/instance-manager/instance_options.h: Auto merged server-tools/instance-manager/listener.cc: Auto merged server-tools/instance-manager/listener.h: Auto merged server-tools/instance-manager/log.cc: Auto merged server-tools/instance-manager/log.h: Auto merged server-tools/instance-manager/manager.cc: Auto merged server-tools/instance-manager/manager.h: Auto merged server-tools/instance-manager/messages.cc: Auto merged server-tools/instance-manager/mysql_connection.cc: Auto merged server-tools/instance-manager/mysql_connection.h: Auto merged server-tools/instance-manager/mysql_manager_error.h: Auto merged server-tools/instance-manager/mysqlmanager.cc: Auto merged server-tools/instance-manager/options.cc: Auto merged server-tools/instance-manager/options.h: Auto merged server-tools/instance-manager/parse.cc: Auto merged server-tools/instance-manager/parse.h: Auto merged server-tools/instance-manager/parse_output.cc: Auto merged server-tools/instance-manager/parse_output.h: Auto merged server-tools/instance-manager/priv.cc: Auto merged server-tools/instance-manager/priv.h: Auto merged server-tools/instance-manager/protocol.cc: Auto merged server-tools/instance-manager/protocol.h: Auto merged server-tools/instance-manager/thread_registry.cc: Auto merged server-tools/instance-manager/thread_registry.h: Auto merged server-tools/instance-manager/user_map.cc: Auto merged server-tools/instance-manager/user_map.h: Auto merged sql/Makefile.am: Auto merged sql/discover.cc: Auto merged sql/field.cc: Auto merged sql/field.h: Auto merged sql/field_conv.cc: Auto merged sql/filesort.cc: Auto merged sql/gen_lex_hash.cc: Auto merged sql/ha_ndbcluster.cc: Auto merged sql/ha_ndbcluster.h: Auto merged sql/handler.cc: Auto merged sql/handler.h: Auto merged sql/hostname.cc: Auto merged sql/init.cc: Auto merged sql/item.cc: Auto merged sql/item.h: Auto merged sql/item_cmpfunc.cc: Auto merged sql/item_cmpfunc.h: Auto merged sql/item_create.cc: Auto merged sql/item_create.h: Auto merged sql/item_func.cc: Auto merged sql/item_func.h: Auto merged sql/item_geofunc.cc: Auto merged sql/item_geofunc.h: Auto merged sql/item_row.cc: Auto merged sql/item_row.h: Auto merged sql/item_strfunc.cc: Auto merged sql/item_strfunc.h: Auto merged sql/item_subselect.cc: Auto merged sql/item_subselect.h: Auto merged sql/item_sum.cc: Auto merged sql/item_sum.h: Auto merged sql/item_timefunc.cc: Auto merged sql/item_timefunc.h: Auto merged sql/item_uniq.cc: Auto merged sql/key.cc: Auto merged sql/lex.h: Auto merged sql/lex_symbol.h: Auto merged sql/lock.cc: Auto merged sql/log.cc: Auto merged sql/log_event.cc: Auto merged sql/log_event.h: Auto merged sql/my_decimal.cc: Auto merged sql/my_decimal.h: Auto merged sql/my_lock.c: Auto merged sql/mysql_priv.h: Auto merged sql/mysqld.cc: Auto merged sql/net_serv.cc: Auto merged sql/opt_range.cc: Auto merged sql/opt_range.h: Auto merged sql/opt_sum.cc: Auto merged sql/parse_file.cc: Auto merged sql/parse_file.h: Auto merged sql/password.c: Auto merged sql/procedure.h: Auto merged sql/protocol.cc: Auto merged sql/protocol.h: Auto merged sql/records.cc: Auto merged sql/repl_failsafe.cc: Auto merged sql/set_var.cc: Auto merged sql/set_var.h: Auto merged sql/slave.cc: Auto merged sql/slave.h: Auto merged sql/sp.cc: Auto merged sql/sp.h: Auto merged sql/sp_cache.cc: Auto merged sql/sp_head.cc: Auto merged sql/sp_head.h: Auto merged sql/spatial.cc: Auto merged sql/spatial.h: Auto merged sql/sql_acl.cc: Auto merged sql/sql_acl.h: Auto merged sql/sql_analyse.cc: Auto merged sql/sql_analyse.h: Auto merged sql/sql_base.cc: Auto merged sql/sql_bitmap.h: Auto merged sql/sql_cache.cc: Auto merged sql/sql_cache.h: Auto merged sql/sql_class.cc: Auto merged sql/sql_class.h: Auto merged sql/sql_crypt.cc: Auto merged sql/sql_cursor.cc: Auto merged sql/sql_db.cc: Auto merged sql/sql_delete.cc: Auto merged sql/sql_derived.cc: Auto merged sql/sql_do.cc: Auto merged sql/sql_error.cc: Auto merged sql/sql_error.h: Auto merged sql/sql_handler.cc: Auto merged sql/sql_help.cc: Auto merged sql/sql_insert.cc: Auto merged sql/sql_lex.cc: Auto merged sql/sql_lex.h: Auto merged sql/sql_list.h: Auto merged sql/sql_load.cc: Auto merged sql/sql_manager.cc: Auto merged sql/sql_map.cc: Auto merged sql/sql_olap.cc: Auto merged sql/sql_parse.cc: Auto merged sql/sql_prepare.cc: Auto merged sql/sql_rename.cc: Auto merged sql/sql_repl.cc: Auto merged sql/sql_repl.h: Auto merged sql/sql_select.cc: Auto merged sql/sql_select.h: Auto merged sql/sql_show.cc: Auto merged sql/sql_string.cc: Auto merged sql/sql_string.h: Auto merged sql/sql_table.cc: Auto merged sql/sql_test.cc: Auto merged sql/sql_trigger.cc: Auto merged sql/sql_trigger.h: Auto merged sql/sql_udf.cc: Auto merged sql/sql_union.cc: Auto merged sql/sql_update.cc: Auto merged sql/sql_view.cc: Auto merged sql-bench/Makefile.am: Auto merged sql-bench/as3ap.sh: Auto merged sql-bench/bench-count-distinct.sh: Auto merged sql-bench/bench-init.pl.sh: Auto merged sql-bench/compare-results.sh: Auto merged sql-bench/copy-db.sh: Auto merged sql/share/charsets/Index.xml: Auto merged sql/share/charsets/cp1250.xml: Auto merged sql/sql_view.h: Auto merged sql/sql_yacc.yy: Auto merged sql/stacktrace.c: Auto merged sql/stacktrace.h: Auto merged sql/strfunc.cc: Auto merged sql/structs.h: Auto merged sql/table.cc: Auto merged sql/table.h: Auto merged sql/time.cc: Auto merged sql/tztime.cc: Auto merged sql/tztime.h: Auto merged sql/udf_example.c: Auto merged sql/unireg.cc: Auto merged sql/unireg.h: Auto merged sql-bench/crash-me.sh: Auto merged sql-bench/run-all-tests.sh: Auto merged sql-bench/server-cfg.sh: Auto merged sql-bench/test-ATIS.sh: Auto merged sql-bench/test-alter-table.sh: Auto merged sql-bench/test-big-tables.sh: Auto merged sql-bench/test-connect.sh: Auto merged sql-bench/test-create.sh: Auto merged sql-bench/test-insert.sh: Auto merged sql-bench/test-select.sh: Auto merged sql-bench/test-transactions.sh: Auto merged sql-bench/test-wisconsin.sh: Auto merged sql-common/client.c: Auto merged sql-common/my_time.c: Auto merged storage/archive/ha_archive.cc: Auto merged storage/archive/ha_archive.h: Auto merged storage/blackhole/ha_blackhole.cc: Auto merged storage/blackhole/ha_blackhole.h: Auto merged storage/csv/ha_tina.cc: Auto merged storage/csv/ha_tina.h: Auto merged storage/example/ha_example.cc: Auto merged storage/example/ha_example.h: Auto merged storage/federated/ha_federated.cc: Auto merged storage/federated/ha_federated.h: Auto merged storage/heap/Makefile.am: Auto merged storage/heap/_check.c: Auto merged storage/heap/_rectest.c: Auto merged storage/heap/ha_heap.cc: Auto merged storage/heap/ha_heap.h: Auto merged storage/heap/heapdef.h: Auto merged storage/heap/hp_block.c: Auto merged storage/heap/hp_clear.c: Auto merged storage/heap/hp_close.c: Auto merged storage/heap/hp_create.c: Auto merged storage/heap/hp_delete.c: Auto merged storage/heap/hp_extra.c: Auto merged storage/heap/hp_hash.c: Auto merged storage/heap/hp_info.c: Auto merged storage/heap/hp_open.c: Auto merged storage/heap/hp_panic.c: Auto merged storage/heap/hp_rename.c: Auto merged storage/heap/hp_rfirst.c: Auto merged storage/heap/hp_rkey.c: Auto merged storage/heap/hp_rlast.c: Auto merged storage/heap/hp_rnext.c: Auto merged storage/heap/hp_rprev.c: Auto merged storage/heap/hp_rrnd.c: Auto merged storage/heap/hp_rsame.c: Auto merged storage/heap/hp_scan.c: Auto merged storage/heap/hp_static.c: Auto merged storage/heap/hp_test1.c: Auto merged storage/heap/hp_test2.c: Auto merged storage/heap/hp_update.c: Auto merged storage/heap/hp_write.c: Auto merged storage/innobase/Makefile.am: Auto merged storage/innobase/btr/Makefile.am: Auto merged storage/innobase/buf/Makefile.am: Auto merged storage/innobase/data/Makefile.am: Auto merged storage/innobase/dict/Makefile.am: Auto merged storage/innobase/dyn/Makefile.am: Auto merged storage/innobase/eval/Makefile.am: Auto merged storage/innobase/fil/Makefile.am: Auto merged storage/innobase/fsp/Makefile.am: Auto merged storage/innobase/fut/Makefile.am: Auto merged storage/innobase/ha/Makefile.am: Auto merged storage/innobase/handler/ha_innodb.cc: Auto merged storage/innobase/handler/ha_innodb.h: Auto merged storage/innobase/ibuf/Makefile.am: Auto merged storage/innobase/lock/Makefile.am: Auto merged storage/innobase/log/Makefile.am: Auto merged storage/innobase/mach/Makefile.am: Auto merged storage/innobase/mem/Makefile.am: Auto merged storage/innobase/mtr/Makefile.am: Auto merged storage/innobase/os/Makefile.am: Auto merged storage/innobase/page/Makefile.am: Auto merged storage/innobase/pars/Makefile.am: Auto merged storage/innobase/que/Makefile.am: Auto merged storage/innobase/read/Makefile.am: Auto merged storage/innobase/rem/Makefile.am: Auto merged storage/innobase/row/Makefile.am: Auto merged storage/innobase/srv/Makefile.am: Auto merged storage/innobase/sync/Makefile.am: Auto merged storage/innobase/thr/Makefile.am: Auto merged storage/innobase/trx/Makefile.am: Auto merged storage/innobase/usr/Makefile.am: Auto merged storage/innobase/ut/Makefile.am: Auto merged storage/myisam/Makefile.am: Auto merged storage/myisam/ft_boolean_search.c: Auto merged storage/myisam/ft_eval.c: Auto merged storage/myisam/ft_eval.h: Auto merged storage/myisam/ft_nlq_search.c: Auto merged storage/myisam/ft_parser.c: Auto merged storage/myisam/ft_static.c: Auto merged storage/myisam/ft_stem.c: Auto merged storage/myisam/ft_stopwords.c: Auto merged storage/myisam/ft_test1.c: Auto merged storage/myisam/ft_test1.h: Auto merged storage/myisam/ft_update.c: Auto merged storage/myisam/ftdefs.h: Auto merged storage/myisam/fulltext.h: Auto merged storage/myisam/ha_myisam.cc: Auto merged storage/myisam/ha_myisam.h: Auto merged storage/myisam/mi_cache.c: Auto merged storage/myisam/mi_changed.c: Auto merged storage/myisam/mi_check.c: Auto merged storage/myisam/mi_checksum.c: Auto merged storage/myisam/mi_close.c: Auto merged storage/myisam/mi_create.c: Auto merged storage/myisam/mi_dbug.c: Auto merged storage/myisam/mi_delete.c: Auto merged storage/myisam/mi_delete_all.c: Auto merged storage/myisam/mi_delete_table.c: Auto merged storage/myisam/mi_dynrec.c: Auto merged storage/myisam/mi_extra.c: Auto merged storage/myisam/mi_info.c: Auto merged storage/myisam/mi_key.c: Auto merged storage/myisam/mi_keycache.c: Auto merged storage/myisam/mi_locking.c: Auto merged storage/myisam/mi_log.c: Auto merged storage/myisam/mi_open.c: Auto merged storage/myisam/mi_packrec.c: Auto merged storage/myisam/mi_page.c: Auto merged storage/myisam/mi_panic.c: Auto merged storage/myisam/mi_preload.c: Auto merged storage/myisam/mi_range.c: Auto merged storage/myisam/mi_rename.c: Auto merged storage/myisam/mi_rfirst.c: Auto merged storage/myisam/mi_rkey.c: Auto merged storage/myisam/mi_rlast.c: Auto merged storage/myisam/mi_rnext.c: Auto merged storage/myisam/mi_rnext_same.c: Auto merged storage/myisam/mi_rprev.c: Auto merged storage/myisam/mi_rrnd.c: Auto merged storage/myisam/mi_rsame.c: Auto merged storage/myisam/mi_rsamepos.c: Auto merged storage/myisam/mi_scan.c: Auto merged storage/myisam/mi_search.c: Auto merged storage/myisam/mi_static.c: Auto merged storage/myisam/mi_statrec.c: Auto merged storage/myisam/mi_test1.c: Auto merged storage/myisam/mi_test2.c: Auto merged storage/myisam/mi_test3.c: Auto merged storage/myisam/mi_unique.c: Auto merged storage/myisam/mi_update.c: Auto merged storage/myisam/mi_write.c: Auto merged storage/myisam/myisam_ftdump.c: Auto merged storage/myisam/myisamchk.c: Auto merged storage/myisam/myisamdef.h: Auto merged storage/myisam/myisamlog.c: Auto merged storage/myisam/myisampack.c: Auto merged storage/myisam/rt_index.c: Auto merged storage/myisam/rt_index.h: Auto merged storage/myisam/rt_key.c: Auto merged storage/myisam/rt_key.h: Auto merged storage/myisam/rt_mbr.c: Auto merged storage/myisam/rt_mbr.h: Auto merged storage/myisam/rt_split.c: Auto merged storage/myisam/rt_test.c: Auto merged storage/myisam/sort.c: Auto merged storage/myisam/sp_defs.h: Auto merged storage/myisam/sp_key.c: Auto merged storage/myisam/sp_test.c: Auto merged storage/myisammrg/Makefile.am: Auto merged storage/myisammrg/ha_myisammrg.cc: Auto merged storage/myisammrg/ha_myisammrg.h: Auto merged storage/myisammrg/myrg_close.c: Auto merged storage/myisammrg/myrg_create.c: Auto merged storage/myisammrg/myrg_def.h: Auto merged storage/myisammrg/myrg_delete.c: Auto merged storage/myisammrg/myrg_extra.c: Auto merged storage/myisammrg/myrg_info.c: Auto merged storage/myisammrg/myrg_locking.c: Auto merged storage/myisammrg/myrg_open.c: Auto merged storage/myisammrg/myrg_panic.c: Auto merged storage/myisammrg/myrg_queue.c: Auto merged storage/myisammrg/myrg_range.c: Auto merged storage/myisammrg/myrg_rfirst.c: Auto merged storage/myisammrg/myrg_rkey.c: Auto merged storage/myisammrg/myrg_rlast.c: Auto merged storage/myisammrg/myrg_rnext.c: Auto merged storage/myisammrg/myrg_rnext_same.c: Auto merged storage/myisammrg/myrg_rprev.c: Auto merged storage/myisammrg/myrg_rrnd.c: Auto merged storage/myisammrg/myrg_rsame.c: Auto merged storage/myisammrg/myrg_static.c: Auto merged storage/myisammrg/myrg_update.c: Auto merged storage/myisammrg/myrg_write.c: Auto merged storage/ndb/include/debugger/DebuggerNames.hpp: Auto merged storage/ndb/include/debugger/EventLogger.hpp: Auto merged storage/ndb/include/debugger/GrepError.hpp: Auto merged storage/ndb/include/debugger/SignalLoggerManager.hpp: Auto merged storage/ndb/include/ndb_constants.h: Auto merged storage/ndb/include/ndb_global.h.in: Auto merged storage/ndb/include/ndb_init.h: Auto merged storage/ndb/include/ndb_types.h.in: Auto merged storage/ndb/include/ndb_version.h.in: Auto merged storage/ndb/include/editline/editline.h: Auto merged storage/ndb/include/kernel/AttributeDescriptor.hpp: Auto merged storage/ndb/include/kernel/AttributeHeader.hpp: Auto merged storage/ndb/include/kernel/AttributeList.hpp: Auto merged storage/ndb/include/kernel/BlockNumbers.h: Auto merged storage/ndb/include/kernel/GlobalSignalNumbers.h: Auto merged storage/ndb/include/kernel/GrepEvent.hpp: Auto merged storage/ndb/include/kernel/Interpreter.hpp: Auto merged storage/ndb/include/kernel/LogLevel.hpp: Auto merged storage/ndb/include/kernel/NodeBitmask.hpp: Auto merged storage/ndb/include/kernel/NodeInfo.hpp: Auto merged storage/ndb/include/kernel/NodeState.hpp: Auto merged storage/ndb/include/kernel/RefConvert.hpp: Auto merged storage/ndb/include/kernel/kernel_types.h: Auto merged storage/ndb/include/kernel/ndb_limits.h: Auto merged storage/ndb/include/kernel/signaldata/AbortAll.hpp: Auto merged storage/ndb/include/kernel/signaldata/AccFrag.hpp: Auto merged storage/ndb/include/kernel/signaldata/AccLock.hpp: Auto merged storage/ndb/include/kernel/signaldata/AccScan.hpp: Auto merged storage/ndb/include/kernel/signaldata/AccSizeAltReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/AlterIndx.hpp: Auto merged storage/ndb/include/kernel/signaldata/AlterTab.hpp: Auto merged storage/ndb/include/kernel/signaldata/AlterTable.hpp: Auto merged storage/ndb/include/kernel/signaldata/AlterTrig.hpp: Auto merged storage/ndb/include/kernel/signaldata/ApiBroadcast.hpp: Auto merged storage/ndb/include/kernel/signaldata/ApiRegSignalData.hpp: Auto merged storage/ndb/include/kernel/signaldata/ApiVersion.hpp: Auto merged storage/ndb/include/kernel/signaldata/ArbitSignalData.hpp: Auto merged storage/ndb/include/kernel/signaldata/AttrInfo.hpp: Auto merged storage/ndb/include/kernel/signaldata/BackupContinueB.hpp: Auto merged storage/ndb/include/kernel/signaldata/BackupImpl.hpp: Auto merged storage/ndb/include/kernel/signaldata/BackupSignalData.hpp: Auto merged storage/ndb/include/kernel/signaldata/BlockCommitOrd.hpp: Auto merged storage/ndb/include/kernel/signaldata/BuildIndx.hpp: Auto merged storage/ndb/include/kernel/signaldata/CheckNodeGroups.hpp: Auto merged storage/ndb/include/kernel/signaldata/CloseComReqConf.hpp: Auto merged storage/ndb/include/kernel/signaldata/CmInit.hpp: Auto merged storage/ndb/include/kernel/trigger_definitions.h: Auto merged storage/ndb/include/kernel/signaldata/CmRegSignalData.hpp: Auto merged storage/ndb/include/kernel/signaldata/CmvmiCfgConf.hpp: Auto merged storage/ndb/include/kernel/signaldata/CntrMasterConf.hpp: Auto merged storage/ndb/include/kernel/signaldata/CntrMasterReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/ConfigParamId.hpp: Auto merged storage/ndb/include/kernel/signaldata/ContinueFragmented.hpp: Auto merged storage/ndb/include/kernel/signaldata/CopyActive.hpp: Auto merged storage/ndb/include/kernel/signaldata/CopyFrag.hpp: Auto merged storage/ndb/include/kernel/signaldata/CopyGCIReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/CreateEvnt.hpp: Auto merged storage/ndb/include/kernel/signaldata/CreateFrag.hpp: Auto merged storage/ndb/include/kernel/signaldata/CreateFragmentation.hpp: Auto merged storage/ndb/include/kernel/signaldata/CreateIndx.hpp: Auto merged storage/ndb/include/kernel/signaldata/CreateTab.hpp: Auto merged storage/ndb/include/kernel/signaldata/CreateTable.hpp: Auto merged storage/ndb/include/kernel/signaldata/CreateTrig.hpp: Auto merged storage/ndb/include/kernel/signaldata/DiAddTab.hpp: Auto merged storage/ndb/include/kernel/signaldata/DiGetNodes.hpp: Auto merged storage/ndb/include/kernel/signaldata/DictLock.hpp: Auto merged storage/ndb/include/kernel/signaldata/DictSchemaInfo.hpp: Auto merged storage/ndb/include/kernel/signaldata/DictSizeAltReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/DictStart.hpp: Auto merged storage/ndb/include/kernel/signaldata/DictTabInfo.hpp: Auto merged storage/ndb/include/kernel/signaldata/DihAddFrag.hpp: Auto merged storage/ndb/include/kernel/signaldata/DihContinueB.hpp: Auto merged storage/ndb/include/kernel/signaldata/DihSizeAltReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/DihStartTab.hpp: Auto merged storage/ndb/include/kernel/signaldata/DihSwitchReplica.hpp: Auto merged storage/ndb/include/kernel/signaldata/DisconnectRep.hpp: Auto merged storage/ndb/include/kernel/signaldata/DropIndx.hpp: Auto merged storage/ndb/include/kernel/signaldata/DropTab.hpp: Auto merged storage/ndb/include/kernel/signaldata/DropTabFile.hpp: Auto merged storage/ndb/include/kernel/signaldata/DropTable.hpp: Auto merged storage/ndb/include/kernel/signaldata/DropTrig.hpp: Auto merged storage/ndb/include/kernel/signaldata/DumpStateOrd.hpp: Auto merged storage/ndb/include/kernel/signaldata/EmptyLcp.hpp: Auto merged storage/ndb/include/kernel/signaldata/EndTo.hpp: Auto merged storage/ndb/include/kernel/signaldata/EventReport.hpp: Auto merged storage/ndb/include/kernel/signaldata/EventSubscribeReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/ExecFragReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/FailRep.hpp: Auto merged storage/ndb/include/kernel/signaldata/FireTrigOrd.hpp: Auto merged storage/ndb/include/kernel/signaldata/FsAppendReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/FsCloseReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/FsConf.hpp: Auto merged storage/ndb/include/kernel/signaldata/FsOpenReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/FsReadWriteReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/FsRef.hpp: Auto merged storage/ndb/include/kernel/signaldata/FsRemoveReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/GCPSave.hpp: Auto merged storage/ndb/include/kernel/signaldata/GetTabInfo.hpp: Auto merged storage/ndb/include/kernel/signaldata/GetTableId.hpp: Auto merged storage/ndb/include/kernel/signaldata/GrepImpl.hpp: Auto merged storage/ndb/include/kernel/signaldata/HotSpareRep.hpp: Auto merged storage/ndb/include/kernel/signaldata/IndxAttrInfo.hpp: Auto merged storage/ndb/include/kernel/signaldata/IndxKeyInfo.hpp: Auto merged storage/ndb/include/kernel/signaldata/InvalidateNodeLCPConf.hpp: Auto merged storage/ndb/include/kernel/signaldata/InvalidateNodeLCPReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/KeyInfo.hpp: Auto merged storage/ndb/include/kernel/signaldata/LCP.hpp: Auto merged storage/ndb/include/kernel/signaldata/ListTables.hpp: Auto merged storage/ndb/include/kernel/signaldata/LqhFrag.hpp: Auto merged storage/ndb/include/kernel/signaldata/LqhKey.hpp: Auto merged storage/ndb/include/kernel/signaldata/LqhSizeAltReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/LqhTransConf.hpp: Auto merged storage/ndb/include/kernel/signaldata/ManagementServer.hpp: Auto merged storage/ndb/include/kernel/signaldata/MasterGCP.hpp: Auto merged storage/ndb/include/kernel/signaldata/MasterLCP.hpp: Auto merged storage/ndb/include/kernel/signaldata/NFCompleteRep.hpp: Auto merged storage/ndb/include/kernel/signaldata/NdbSttor.hpp: Auto merged storage/ndb/include/kernel/signaldata/NdbfsContinueB.hpp: Auto merged storage/ndb/include/kernel/signaldata/NextScan.hpp: Auto merged storage/ndb/include/kernel/signaldata/NodeFailRep.hpp: Auto merged storage/ndb/include/kernel/signaldata/NodeStateSignalData.hpp: Auto merged storage/ndb/include/kernel/signaldata/PackedSignal.hpp: Auto merged storage/ndb/include/kernel/signaldata/PrepDropTab.hpp: Auto merged storage/ndb/include/kernel/signaldata/PrepFailReqRef.hpp: Auto merged storage/ndb/include/kernel/signaldata/ReadNodesConf.hpp: Auto merged storage/ndb/include/kernel/signaldata/RelTabMem.hpp: Auto merged storage/ndb/include/kernel/signaldata/RepImpl.hpp: Auto merged storage/ndb/include/kernel/signaldata/ResumeReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/ScanFrag.hpp: Auto merged storage/ndb/include/kernel/signaldata/ScanTab.hpp: Auto merged storage/ndb/include/kernel/signaldata/SetLogLevelOrd.hpp: Auto merged storage/ndb/include/kernel/signaldata/SetVarReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/SignalData.hpp: Auto merged storage/ndb/include/kernel/signaldata/SignalDataPrint.hpp: Auto merged storage/ndb/include/kernel/signaldata/SignalDroppedRep.hpp: Auto merged storage/ndb/include/kernel/signaldata/SrFragidConf.hpp: Auto merged storage/ndb/include/kernel/signaldata/StartFragReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/StartInfo.hpp: Auto merged storage/ndb/include/kernel/signaldata/StartMe.hpp: Auto merged storage/ndb/include/kernel/signaldata/StartOrd.hpp: Auto merged storage/ndb/include/kernel/signaldata/StartPerm.hpp: Auto merged storage/ndb/include/kernel/signaldata/StartRec.hpp: Auto merged storage/ndb/include/kernel/signaldata/StartTo.hpp: Auto merged storage/ndb/include/kernel/signaldata/StopMe.hpp: Auto merged storage/ndb/include/kernel/signaldata/StopPerm.hpp: Auto merged storage/ndb/include/kernel/signaldata/StopReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/SumaImpl.hpp: Auto merged storage/ndb/include/kernel/signaldata/SystemError.hpp: Auto merged storage/ndb/include/kernel/signaldata/TamperOrd.hpp: Auto merged storage/ndb/include/kernel/signaldata/TcCommit.hpp: Auto merged storage/ndb/include/kernel/signaldata/TcContinueB.hpp: Auto merged storage/ndb/include/kernel/signaldata/TcHbRep.hpp: Auto merged storage/ndb/include/kernel/signaldata/TcIndx.hpp: Auto merged storage/ndb/include/kernel/signaldata/TcKeyConf.hpp: Auto merged storage/ndb/include/kernel/signaldata/TcKeyFailConf.hpp: Auto merged storage/ndb/include/kernel/signaldata/TcKeyRef.hpp: Auto merged storage/ndb/include/kernel/signaldata/TcKeyReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/TcRollbackRep.hpp: Auto merged storage/ndb/include/kernel/signaldata/TcSizeAltReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/TestOrd.hpp: Auto merged storage/ndb/include/kernel/signaldata/TransIdAI.hpp: Auto merged storage/ndb/include/kernel/signaldata/TrigAttrInfo.hpp: Auto merged storage/ndb/include/kernel/signaldata/TupCommit.hpp: Auto merged storage/ndb/include/kernel/signaldata/TupFrag.hpp: Auto merged storage/ndb/include/kernel/signaldata/TupKey.hpp: Auto merged storage/ndb/include/kernel/signaldata/TupSizeAltReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/TuxBound.hpp: Auto merged storage/ndb/include/kernel/signaldata/TuxContinueB.hpp: Auto merged storage/ndb/include/kernel/signaldata/TuxMaint.hpp: Auto merged storage/ndb/include/kernel/signaldata/TuxSizeAltReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/UpdateTo.hpp: Auto merged storage/ndb/include/kernel/signaldata/UtilDelete.hpp: Auto merged storage/ndb/include/kernel/signaldata/UtilExecute.hpp: Auto merged storage/ndb/include/kernel/signaldata/UtilLock.hpp: Auto merged storage/ndb/include/kernel/signaldata/UtilPrepare.hpp: Auto merged storage/ndb/include/kernel/signaldata/UtilRelease.hpp: Auto merged storage/ndb/include/kernel/signaldata/UtilSequence.hpp: Auto merged storage/ndb/include/kernel/signaldata/WaitGCP.hpp: Auto merged storage/ndb/include/logger/ConsoleLogHandler.hpp: Auto merged storage/ndb/include/logger/FileLogHandler.hpp: Auto merged storage/ndb/include/logger/LogHandler.hpp: Auto merged storage/ndb/include/logger/Logger.hpp: Auto merged storage/ndb/include/logger/SysLogHandler.hpp: Auto merged storage/ndb/include/mgmapi/mgmapi.h: Auto merged storage/ndb/include/mgmapi/mgmapi_debug.h: Auto merged storage/ndb/include/mgmapi/ndb_logevent.h: Auto merged storage/ndb/include/mgmapi/ndbd_exit_codes.h: Auto merged storage/ndb/include/mgmcommon/ConfigRetriever.hpp: Auto merged storage/ndb/include/mgmcommon/IPCConfig.hpp: Auto merged storage/ndb/include/mgmcommon/MgmtErrorReporter.hpp: Auto merged storage/ndb/include/ndbapi/Ndb.hpp: Auto merged storage/ndb/include/ndbapi/NdbApi.hpp: Auto merged storage/ndb/include/ndbapi/NdbBlob.hpp: Auto merged storage/ndb/include/ndbapi/NdbDictionary.hpp: Auto merged storage/ndb/include/ndbapi/NdbError.hpp: Auto merged storage/ndb/include/ndbapi/NdbEventOperation.hpp: Auto merged storage/ndb/include/ndbapi/NdbIndexOperation.hpp: Auto merged storage/ndb/include/ndbapi/NdbIndexScanOperation.hpp: Auto merged storage/ndb/include/ndbapi/NdbOperation.hpp: Auto merged storage/ndb/include/ndbapi/NdbPool.hpp: Auto merged storage/ndb/include/ndbapi/NdbRecAttr.hpp: Auto merged storage/ndb/include/ndbapi/NdbReceiver.hpp: Auto merged storage/ndb/include/ndbapi/NdbScanFilter.hpp: Auto merged storage/ndb/include/ndbapi/NdbScanOperation.hpp: Auto merged storage/ndb/include/ndbapi/NdbTransaction.hpp: Auto merged storage/ndb/include/ndbapi/ndb_cluster_connection.hpp: Auto merged storage/ndb/include/ndbapi/ndb_opt_defaults.h: Auto merged storage/ndb/include/ndbapi/ndbapi_limits.h: Auto merged storage/ndb/include/ndbapi/ndberror.h: Auto merged storage/ndb/include/newtonapi/dba.h: Auto merged storage/ndb/include/newtonapi/defs/pcn_types.h: Auto merged storage/ndb/include/portlib/NdbCondition.h: Auto merged storage/ndb/include/portlib/NdbConfig.h: Auto merged storage/ndb/include/portlib/NdbDaemon.h: Auto merged storage/ndb/include/portlib/NdbEnv.h: Auto merged storage/ndb/include/portlib/NdbHost.h: Auto merged storage/ndb/include/portlib/NdbMain.h: Auto merged storage/ndb/include/portlib/NdbMem.h: Auto merged storage/ndb/include/portlib/NdbMutex.h: Auto merged storage/ndb/include/portlib/NdbSleep.h: Auto merged storage/ndb/include/portlib/NdbTCP.h: Auto merged storage/ndb/include/portlib/NdbThread.h: Auto merged storage/ndb/include/portlib/NdbTick.h: Auto merged storage/ndb/include/portlib/PortDefs.h: Auto merged storage/ndb/include/portlib/prefetch.h: Auto merged storage/ndb/include/transporter/TransporterCallback.hpp: Auto merged storage/ndb/include/transporter/TransporterDefinitions.hpp: Auto merged storage/ndb/include/transporter/TransporterRegistry.hpp: Auto merged storage/ndb/include/util/BaseString.hpp: Auto merged storage/ndb/include/util/Bitmask.hpp: Auto merged storage/ndb/include/util/File.hpp: Auto merged storage/ndb/include/util/InputStream.hpp: Auto merged storage/ndb/include/util/NdbAutoPtr.hpp: Auto merged storage/ndb/include/util/NdbOut.hpp: Auto merged storage/ndb/include/util/NdbSqlUtil.hpp: Auto merged storage/ndb/include/util/OutputStream.hpp: Auto merged storage/ndb/include/util/Parser.hpp: Auto merged storage/ndb/include/util/Properties.hpp: Auto merged storage/ndb/include/util/SimpleProperties.hpp: Auto merged storage/ndb/include/util/SocketAuthenticator.hpp: Auto merged storage/ndb/include/util/SocketClient.hpp: Auto merged storage/ndb/include/util/SocketServer.hpp: Auto merged storage/ndb/include/util/UtilBuffer.hpp: Auto merged storage/ndb/include/util/Vector.hpp: Auto merged storage/ndb/include/util/basestring_vsnprintf.h: Auto merged storage/ndb/include/util/md5_hash.hpp: Auto merged storage/ndb/include/util/ndb_opts.h: Auto merged storage/ndb/include/util/random.h: Auto merged storage/ndb/include/util/socket_io.h: Auto merged storage/ndb/include/util/uucode.h: Auto merged storage/ndb/include/util/version.h: Auto merged storage/ndb/src/common/debugger/BlockNames.cpp: Auto merged storage/ndb/src/common/debugger/DebuggerNames.cpp: Auto merged storage/ndb/src/common/debugger/EventLogger.cpp: Auto merged storage/ndb/src/common/debugger/GrepError.cpp: Auto merged storage/ndb/src/common/debugger/SignalLoggerManager.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/AccLock.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/AlterIndx.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/AlterTab.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/AlterTable.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/AlterTrig.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/BackupImpl.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/BackupSignalData.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/CloseComReqConf.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/ContinueB.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/CopyGCI.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/CreateEvnt.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/CreateFragmentation.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/CreateIndx.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/CreateTrig.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/DictTabInfo.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/DihContinueB.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/DihSwitchReplicaReq.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/DisconnectRep.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/DropIndx.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/DropTab.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/DropTrig.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/FailRep.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/FireTrigOrd.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/FsAppendReq.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/FsCloseReq.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/FsConf.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/FsOpenReq.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/FsReadWriteReq.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/FsRef.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/GCPSave.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/IndxAttrInfo.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/IndxKeyInfo.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/LCP.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/LqhFrag.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/LqhKey.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/LqhTrans.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/MasterLCP.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/NFCompleteRep.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/NdbSttor.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/NdbfsContinueB.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/PackedSignal.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/PrepDropTab.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/PrepFailReqRef.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/ScanFrag.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/ScanTab.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/SignalDroppedRep.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/SignalNames.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/StartRec.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/SumaImpl.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/SystemError.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/TcIndx.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/TcKeyConf.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/TcKeyRef.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/TcKeyReq.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/TcRollbackRep.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/TrigAttrInfo.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/TupCommit.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/TupKey.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/TuxMaint.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/UtilDelete.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/UtilExecute.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/UtilLock.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/UtilPrepare.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/UtilSequence.cpp: Auto merged storage/ndb/src/common/logger/ConsoleLogHandler.cpp: Auto merged storage/ndb/src/common/logger/FileLogHandler.cpp: Auto merged storage/ndb/src/common/logger/LogHandler.cpp: Auto merged storage/ndb/src/common/logger/LogHandlerList.cpp: Auto merged storage/ndb/src/common/logger/LogHandlerList.hpp: Auto merged storage/ndb/src/common/logger/Logger.cpp: Auto merged storage/ndb/src/common/logger/SysLogHandler.cpp: Auto merged storage/ndb/src/common/logger/listtest/LogHandlerListUnitTest.cpp: Auto merged storage/ndb/src/common/logger/listtest/LogHandlerListUnitTest.hpp: Auto merged storage/ndb/src/common/logger/loggertest/LoggerUnitTest.cpp: Auto merged storage/ndb/src/common/logger/loggertest/LoggerUnitTest.hpp: Auto merged storage/ndb/src/common/mgmcommon/ConfigRetriever.cpp: Auto merged storage/ndb/src/common/mgmcommon/IPCConfig.cpp: Auto merged storage/ndb/src/common/mgmcommon/printConfig/printConfig.cpp: Auto merged storage/ndb/src/common/portlib/NdbCondition.c: Auto merged storage/ndb/src/common/portlib/NdbConfig.c: Auto merged storage/ndb/src/common/portlib/NdbDaemon.c: Auto merged storage/ndb/src/common/portlib/NdbEnv.c: Auto merged storage/ndb/src/common/portlib/NdbHost.c: Auto merged storage/ndb/src/common/portlib/NdbMem.c: Auto merged storage/ndb/src/common/portlib/NdbMutex.c: Auto merged storage/ndb/src/common/portlib/NdbPortLibTest.cpp: Auto merged storage/ndb/src/common/portlib/NdbSleep.c: Auto merged storage/ndb/src/common/portlib/NdbTCP.cpp: Auto merged storage/ndb/src/common/portlib/NdbThread.c: Auto merged storage/ndb/src/common/portlib/NdbTick.c: Auto merged storage/ndb/src/common/portlib/memtest.c: Auto merged storage/ndb/src/common/portlib/mmstest.cpp: Auto merged storage/ndb/src/common/portlib/munmaptest.cpp: Auto merged storage/ndb/src/common/portlib/win32/NdbCondition.c: Auto merged storage/ndb/src/common/portlib/win32/NdbDaemon.c: Auto merged storage/ndb/src/common/portlib/win32/NdbEnv.c: Auto merged storage/ndb/src/common/portlib/win32/NdbHost.c: Auto merged storage/ndb/src/common/portlib/win32/NdbMem.c: Auto merged storage/ndb/src/common/portlib/win32/NdbMutex.c: Auto merged storage/ndb/src/common/portlib/win32/NdbSleep.c: Auto merged storage/ndb/src/common/portlib/win32/NdbTCP.c: Auto merged storage/ndb/src/common/portlib/win32/NdbThread.c: Auto merged storage/ndb/src/common/portlib/win32/NdbTick.c: Auto merged storage/ndb/src/common/transporter/Packer.cpp: Auto merged storage/ndb/src/common/transporter/Packer.hpp: Auto merged storage/ndb/src/common/transporter/SCI_Transporter.cpp: Auto merged storage/ndb/src/common/transporter/SCI_Transporter.hpp: Auto merged storage/ndb/src/common/transporter/SHM_Buffer.hpp: Auto merged storage/ndb/src/common/transporter/SHM_Transporter.cpp: Auto merged storage/ndb/src/common/transporter/SHM_Transporter.hpp: Auto merged storage/ndb/src/common/transporter/SHM_Transporter.unix.cpp: Auto merged storage/ndb/src/common/transporter/SHM_Transporter.win32.cpp: Auto merged storage/ndb/src/common/transporter/SendBuffer.cpp: Auto merged storage/ndb/src/common/transporter/SendBuffer.hpp: Auto merged storage/ndb/src/common/transporter/TCP_Transporter.cpp: Auto merged storage/ndb/src/common/transporter/TCP_Transporter.hpp: Auto merged storage/ndb/src/common/transporter/Transporter.cpp: Auto merged storage/ndb/src/common/transporter/Transporter.hpp: Auto merged storage/ndb/src/common/transporter/TransporterInternalDefinitions.hpp: Auto merged storage/ndb/src/common/transporter/TransporterRegistry.cpp: Auto merged storage/ndb/src/common/transporter/basictest/basicTransporterTest.cpp: Auto merged storage/ndb/src/common/transporter/buddy.cpp: Auto merged storage/ndb/src/common/transporter/buddy.hpp: Auto merged storage/ndb/src/common/transporter/failoverSCI/failoverSCI.cpp: Auto merged storage/ndb/src/common/transporter/perftest/perfTransporterTest.cpp: Auto merged storage/ndb/src/common/transporter/priotest/prioSCI/prioSCI.cpp: Auto merged storage/ndb/src/common/transporter/priotest/prioSHM/prioSHM.cpp: Auto merged storage/ndb/src/common/transporter/priotest/prioTCP/prioTCP.cpp: Auto merged storage/ndb/src/common/transporter/priotest/prioTransporterTest.cpp: Auto merged storage/ndb/src/common/transporter/priotest/prioTransporterTest.hpp: Auto merged storage/ndb/src/common/util/BaseString.cpp: Auto merged storage/ndb/src/common/util/File.cpp: Auto merged storage/ndb/src/common/util/InputStream.cpp: Auto merged storage/ndb/src/common/util/NdbOut.cpp: Auto merged storage/ndb/src/common/util/NdbSqlUtil.cpp: Auto merged storage/ndb/src/common/util/OutputStream.cpp: Auto merged storage/ndb/src/common/util/Parser.cpp: Auto merged storage/ndb/src/common/util/Properties.cpp: Auto merged storage/ndb/src/common/util/SimpleProperties.cpp: Auto merged storage/ndb/src/common/util/SocketAuthenticator.cpp: Auto merged storage/ndb/src/common/util/SocketClient.cpp: Auto merged storage/ndb/src/common/util/SocketServer.cpp: Auto merged storage/ndb/src/common/util/basestring_vsnprintf.c: Auto merged storage/ndb/src/common/util/md5_hash.cpp: Auto merged storage/ndb/src/common/util/ndb_init.c: Auto merged storage/ndb/src/common/util/random.c: Auto merged storage/ndb/src/common/util/socket_io.cpp: Auto merged storage/ndb/src/common/util/strdup.c: Auto merged storage/ndb/src/common/util/filetest/FileUnitTest.cpp: Auto merged storage/ndb/src/common/util/filetest/FileUnitTest.hpp: Auto merged storage/ndb/src/common/util/testProperties/testProperties.cpp: Auto merged storage/ndb/src/common/util/testSimpleProperties/sp_test.cpp: Auto merged storage/ndb/src/common/util/uucode.c: Auto merged storage/ndb/src/common/util/version.c: Auto merged storage/ndb/src/cw/cpcc-win32/C++/CPC_GUI.cpp: Auto merged storage/ndb/src/cw/cpcc-win32/C++/CPC_GUI.h: Auto merged storage/ndb/src/cw/cpcc-win32/C++/NdbControls.cpp: Auto merged storage/ndb/src/cw/cpcc-win32/C++/StdAfx.cpp: Auto merged storage/ndb/src/cw/cpcc-win32/C++/StdAfx.h: Auto merged storage/ndb/src/cw/cpcc-win32/C++/TreeView.cpp: Auto merged storage/ndb/src/cw/cpcc-win32/C++/TreeView.h: Auto merged storage/ndb/src/cw/cpcc-win32/C++/resource.h: Auto merged storage/ndb/src/cw/cpcd/APIService.cpp: Auto merged storage/ndb/src/cw/cpcd/APIService.hpp: Auto merged storage/ndb/src/cw/cpcd/CPCD.cpp: Auto merged storage/ndb/src/cw/cpcd/CPCD.hpp: Auto merged storage/ndb/src/cw/cpcd/Monitor.cpp: Auto merged storage/ndb/src/cw/cpcd/Process.cpp: Auto merged storage/ndb/src/cw/cpcd/common.cpp: Auto merged storage/ndb/src/cw/cpcd/common.hpp: Auto merged storage/ndb/src/cw/cpcd/main.cpp: Auto merged storage/ndb/src/cw/test/socketclient/socketClientTest.cpp: Auto merged storage/ndb/src/cw/util/ClientInterface.cpp: Auto merged storage/ndb/src/cw/util/ClientInterface.hpp: Auto merged storage/ndb/src/cw/util/SocketRegistry.cpp: Auto merged storage/ndb/src/cw/util/SocketRegistry.hpp: Auto merged storage/ndb/src/cw/util/SocketService.cpp: Auto merged storage/ndb/src/cw/util/SocketService.hpp: Auto merged storage/ndb/src/kernel/SimBlockList.cpp: Auto merged storage/ndb/src/kernel/blocks/mutexes.hpp: Auto merged storage/ndb/src/kernel/main.cpp: Auto merged storage/ndb/src/kernel/blocks/backup/Backup.cpp: Auto merged storage/ndb/src/kernel/blocks/backup/Backup.hpp: Auto merged storage/ndb/src/kernel/blocks/backup/BackupFormat.hpp: Auto merged storage/ndb/src/kernel/blocks/backup/BackupInit.cpp: Auto merged storage/ndb/src/kernel/blocks/backup/FsBuffer.hpp: Auto merged storage/ndb/src/kernel/blocks/backup/read.cpp: Auto merged storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp: Auto merged storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.hpp: Auto merged storage/ndb/src/kernel/blocks/dbacc/Dbacc.hpp: Auto merged storage/ndb/src/kernel/blocks/dbacc/DbaccInit.cpp: Auto merged storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp: Auto merged storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp: Auto merged storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp: Auto merged storage/ndb/src/kernel/blocks/dbdict/SchemaFile.hpp: Auto merged storage/ndb/src/kernel/blocks/dbdict/printSchemaFile.cpp: Auto merged storage/ndb/src/kernel/blocks/dbdih/Dbdih.hpp: Auto merged storage/ndb/src/kernel/blocks/dbdih/DbdihInit.cpp: Auto merged storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp: Auto merged storage/ndb/src/kernel/blocks/dbdih/Sysfile.hpp: Auto merged storage/ndb/src/kernel/blocks/dbdih/printSysfile/printSysfile.cpp: Auto merged storage/ndb/src/kernel/blocks/dblqh/Dblqh.hpp: Auto merged storage/ndb/src/kernel/blocks/dblqh/DblqhInit.cpp: Auto merged storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp: Auto merged storage/ndb/src/kernel/blocks/dblqh/redoLogReader/records.cpp: Auto merged storage/ndb/src/kernel/blocks/dblqh/redoLogReader/records.hpp: Auto merged storage/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtc/Dbtc.hpp: Auto merged storage/ndb/src/kernel/blocks/dbtc/DbtcInit.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/AttributeOffset.hpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupAbort.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupBuffer.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupDebug.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupFixAlloc.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupIndex.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupPagMan.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupPageMap.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupScan.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupStoredProcDef.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupTabDesMan.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtux/Dbtux.hpp: Auto merged storage/ndb/src/kernel/blocks/dbtux/DbtuxCmp.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtux/DbtuxNode.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtux/DbtuxSearch.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtux/DbtuxTree.cpp: Auto merged storage/ndb/src/kernel/blocks/dbutil/DbUtil.cpp: Auto merged storage/ndb/src/kernel/blocks/dbutil/DbUtil.hpp: Auto merged storage/ndb/src/kernel/blocks/ndbcntr/Ndbcntr.hpp: Auto merged storage/ndb/src/kernel/blocks/ndbcntr/NdbcntrInit.cpp: Auto merged storage/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp: Auto merged storage/ndb/src/kernel/blocks/ndbcntr/NdbcntrSysTable.cpp: Auto merged storage/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp: Auto merged storage/ndb/src/kernel/blocks/ndbfs/AsyncFile.hpp: Auto merged storage/ndb/src/kernel/blocks/ndbfs/AsyncFileTest/AsyncFileTest.cpp: Auto merged storage/ndb/src/kernel/blocks/ndbfs/CircularIndex.cpp: Auto merged storage/ndb/src/kernel/blocks/ndbfs/CircularIndex.hpp: Auto merged storage/ndb/src/kernel/blocks/ndbfs/Filename.cpp: Auto merged storage/ndb/src/kernel/blocks/ndbfs/Filename.hpp: Auto merged storage/ndb/src/kernel/blocks/ndbfs/MemoryChannel.cpp: Auto merged storage/ndb/src/kernel/blocks/ndbfs/MemoryChannel.hpp: Auto merged storage/ndb/src/kernel/blocks/ndbfs/MemoryChannelTest/MemoryChannelTest.cpp: Auto merged storage/ndb/src/kernel/blocks/ndbfs/Ndbfs.cpp: Auto merged storage/ndb/src/kernel/blocks/ndbfs/Ndbfs.hpp: Auto merged storage/ndb/src/kernel/blocks/ndbfs/OpenFiles.hpp: Auto merged storage/ndb/src/kernel/blocks/ndbfs/Pool.hpp: Auto merged storage/ndb/src/kernel/blocks/ndbfs/VoidFs.cpp: Auto merged storage/ndb/src/kernel/blocks/qmgr/Qmgr.hpp: Auto merged storage/ndb/src/kernel/blocks/qmgr/QmgrInit.cpp: Auto merged storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp: Auto merged storage/ndb/src/kernel/blocks/qmgr/timer.hpp: Auto merged storage/ndb/src/kernel/blocks/suma/Suma.cpp: Auto merged storage/ndb/src/kernel/blocks/suma/Suma.hpp: Auto merged storage/ndb/src/kernel/blocks/suma/SumaInit.cpp: Auto merged storage/ndb/src/kernel/blocks/trix/Trix.cpp: Auto merged storage/ndb/src/kernel/blocks/trix/Trix.hpp: Auto merged storage/ndb/src/kernel/error/ErrorHandlingMacros.hpp: Auto merged storage/ndb/src/kernel/error/ErrorReporter.cpp: Auto merged storage/ndb/src/kernel/error/ErrorReporter.hpp: Auto merged storage/ndb/src/kernel/error/TimeModule.cpp: Auto merged storage/ndb/src/kernel/error/TimeModule.hpp: Auto merged storage/ndb/src/kernel/error/ndbd_exit_codes.c: Auto merged storage/ndb/src/kernel/vm/Array.hpp: Auto merged storage/ndb/src/kernel/vm/ArrayPool.hpp: Auto merged storage/ndb/src/kernel/vm/CArray.hpp: Auto merged storage/ndb/src/kernel/vm/Callback.hpp: Auto merged storage/ndb/src/kernel/vm/ClusterConfiguration.cpp: Auto merged storage/ndb/src/kernel/vm/ClusterConfiguration.hpp: Auto merged storage/ndb/src/kernel/vm/Configuration.cpp: Auto merged storage/ndb/src/kernel/vm/Configuration.hpp: Auto merged storage/ndb/src/kernel/vm/DLFifoList.hpp: Auto merged storage/ndb/src/kernel/vm/DLHashTable.hpp: Auto merged storage/ndb/src/kernel/vm/DLHashTable2.hpp: Auto merged storage/ndb/src/kernel/vm/DLList.hpp: Auto merged storage/ndb/src/kernel/vm/DataBuffer.hpp: Auto merged storage/ndb/src/kernel/vm/Emulator.cpp: Auto merged storage/ndb/src/kernel/vm/Emulator.hpp: Auto merged storage/ndb/src/kernel/vm/FastScheduler.cpp: Auto merged storage/ndb/src/kernel/vm/FastScheduler.hpp: Auto merged storage/ndb/src/kernel/vm/GlobalData.hpp: Auto merged storage/ndb/src/kernel/vm/KeyDescriptor.hpp: Auto merged storage/ndb/src/kernel/vm/KeyTable.hpp: Auto merged storage/ndb/src/kernel/vm/KeyTable2.hpp: Auto merged storage/ndb/src/kernel/vm/LongSignal.hpp: Auto merged storage/ndb/src/kernel/vm/Mutex.cpp: Auto merged storage/ndb/src/kernel/vm/Mutex.hpp: Auto merged storage/ndb/src/kernel/vm/Prio.hpp: Auto merged storage/ndb/src/kernel/vm/RequestTracker.hpp: Auto merged storage/ndb/src/kernel/vm/SLList.hpp: Auto merged storage/ndb/src/kernel/vm/SafeCounter.cpp: Auto merged storage/ndb/src/kernel/vm/SafeCounter.hpp: Auto merged storage/ndb/src/kernel/vm/SectionReader.cpp: Auto merged storage/ndb/src/kernel/vm/SectionReader.hpp: Auto merged storage/ndb/src/kernel/vm/SignalCounter.hpp: Auto merged storage/ndb/src/kernel/vm/SimBlockList.hpp: Auto merged storage/ndb/src/kernel/vm/SimplePropertiesSection.cpp: Auto merged storage/ndb/src/kernel/vm/SimulatedBlock.cpp: Auto merged storage/ndb/src/kernel/vm/SimulatedBlock.hpp: Auto merged storage/ndb/src/kernel/vm/SuperPool.cpp: Auto merged storage/ndb/src/kernel/vm/SuperPool.hpp: Auto merged storage/ndb/src/kernel/vm/ThreadConfig.cpp: Auto merged storage/ndb/src/kernel/vm/ThreadConfig.hpp: Auto merged storage/ndb/src/kernel/vm/TimeQueue.cpp: Auto merged storage/ndb/src/kernel/vm/TimeQueue.hpp: Auto merged storage/ndb/src/kernel/vm/TransporterCallback.cpp: Auto merged storage/ndb/src/kernel/vm/VMSignal.cpp: Auto merged storage/ndb/src/kernel/vm/VMSignal.hpp: Auto merged storage/ndb/src/kernel/vm/WaitQueue.hpp: Auto merged storage/ndb/src/kernel/vm/WatchDog.cpp: Auto merged storage/ndb/src/kernel/vm/WatchDog.hpp: Auto merged storage/ndb/src/kernel/vm/al_test/arrayListTest.cpp: Auto merged storage/ndb/src/kernel/vm/al_test/arrayPoolTest.cpp: Auto merged storage/ndb/src/kernel/vm/al_test/main.cpp: Auto merged storage/ndb/src/kernel/vm/ndbd_malloc.cpp: Auto merged storage/ndb/src/kernel/vm/ndbd_malloc.hpp: Auto merged storage/ndb/src/kernel/vm/pc.hpp: Auto merged storage/ndb/src/kernel/vm/testCopy/rr.cpp: Auto merged storage/ndb/src/kernel/vm/testCopy/testCopy.cpp: Auto merged storage/ndb/src/kernel/vm/testDataBuffer/testDataBuffer.cpp: Auto merged storage/ndb/src/kernel/vm/testLongSig/testLongSig.cpp: Auto merged storage/ndb/src/kernel/vm/testSimplePropertiesSection/test.cpp: Auto merged storage/ndb/src/kernel/vm/testSuperPool.cpp: Auto merged storage/ndb/src/mgmapi/LocalConfig.cpp: Auto merged storage/ndb/src/mgmapi/LocalConfig.hpp: Auto merged storage/ndb/src/mgmapi/mgmapi.cpp: Auto merged storage/ndb/src/mgmapi/mgmapi_configuration.hpp: Auto merged storage/ndb/src/mgmapi/mgmapi_internal.h: Auto merged storage/ndb/src/mgmapi/ndb_logevent.cpp: Auto merged storage/ndb/src/mgmapi/ndb_logevent.hpp: Auto merged storage/ndb/src/mgmapi/test/keso.c: Auto merged storage/ndb/src/mgmapi/test/mgmSrvApi.cpp: Auto merged storage/ndb/src/mgmclient/CommandInterpreter.cpp: Auto merged storage/ndb/src/mgmclient/main.cpp: Auto merged storage/ndb/src/mgmclient/ndb_mgmclient.hpp: Auto merged storage/ndb/src/mgmclient/ndb_mgmclient.h: Auto merged storage/ndb/src/mgmclient/test_cpcd/test_cpcd.cpp: Auto merged storage/ndb/src/mgmsrv/Config.cpp: Auto merged storage/ndb/src/mgmsrv/Config.hpp: Auto merged storage/ndb/src/mgmsrv/ConfigInfo.cpp: Auto merged storage/ndb/src/mgmsrv/ConfigInfo.hpp: Auto merged storage/ndb/src/mgmsrv/InitConfigFileParser.cpp: Auto merged storage/ndb/src/mgmsrv/InitConfigFileParser.hpp: Auto merged storage/ndb/src/mgmsrv/MgmtSrvr.cpp: Auto merged storage/ndb/src/mgmsrv/MgmtSrvr.hpp: Auto merged storage/ndb/src/mgmsrv/MgmtSrvrConfig.cpp: Auto merged storage/ndb/src/mgmsrv/MgmtSrvrGeneralSignalHandling.cpp: Auto merged storage/ndb/src/mgmsrv/Services.cpp: Auto merged storage/ndb/src/mgmsrv/Services.hpp: Auto merged storage/ndb/src/mgmsrv/SignalQueue.cpp: Auto merged storage/ndb/src/mgmsrv/SignalQueue.hpp: Auto merged storage/ndb/src/mgmsrv/convertStrToInt.cpp: Auto merged storage/ndb/src/mgmsrv/convertStrToInt.hpp: Auto merged storage/ndb/src/mgmsrv/main.cpp: Auto merged storage/ndb/src/mgmsrv/mkconfig/mkconfig.cpp: Auto merged storage/ndb/src/ndbapi/API.hpp: Auto merged storage/ndb/src/ndbapi/ClusterMgr.cpp: Auto merged storage/ndb/src/ndbapi/ClusterMgr.hpp: Auto merged storage/ndb/src/ndbapi/DictCache.cpp: Auto merged storage/ndb/src/ndbapi/DictCache.hpp: Auto merged storage/ndb/src/ndbapi/Ndb.cpp: Auto merged storage/ndb/src/ndbapi/NdbApiSignal.cpp: Auto merged storage/ndb/src/ndbapi/NdbApiSignal.hpp: Auto merged storage/ndb/src/ndbapi/NdbBlob.cpp: Auto merged storage/ndb/src/ndbapi/NdbBlobImpl.hpp: Auto merged storage/ndb/src/ndbapi/NdbDictionary.cpp: Auto merged storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp: Auto merged storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp: Auto merged storage/ndb/src/ndbapi/NdbErrorOut.cpp: Auto merged storage/ndb/src/ndbapi/NdbEventOperation.cpp: Auto merged storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp: Auto merged storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp: Auto merged storage/ndb/src/ndbapi/NdbImpl.hpp: Auto merged storage/ndb/src/ndbapi/NdbIndexOperation.cpp: Auto merged storage/ndb/src/ndbapi/NdbLinHash.hpp: Auto merged storage/ndb/src/ndbapi/NdbOperation.cpp: Auto merged storage/ndb/src/ndbapi/NdbOperationDefine.cpp: Auto merged storage/ndb/src/ndbapi/NdbOperationExec.cpp: Auto merged storage/ndb/src/ndbapi/NdbOperationInt.cpp: Auto merged storage/ndb/src/ndbapi/NdbOperationScan.cpp: Auto merged storage/ndb/src/ndbapi/NdbOperationSearch.cpp: Auto merged storage/ndb/src/ndbapi/NdbPool.cpp: Auto merged storage/ndb/src/ndbapi/NdbPoolImpl.cpp: Auto merged storage/ndb/src/ndbapi/NdbPoolImpl.hpp: Auto merged storage/ndb/src/ndbapi/NdbRecAttr.cpp: Auto merged storage/ndb/src/ndbapi/NdbReceiver.cpp: Auto merged storage/ndb/src/ndbapi/NdbScanFilter.cpp: Auto merged storage/ndb/src/ndbapi/NdbScanOperation.cpp: Auto merged storage/ndb/src/ndbapi/NdbTransaction.cpp: Auto merged storage/ndb/src/ndbapi/NdbTransactionScan.cpp: Auto merged storage/ndb/src/ndbapi/NdbUtil.cpp: Auto merged storage/ndb/src/ndbapi/NdbUtil.hpp: Auto merged storage/ndb/src/ndbapi/NdbWaiter.hpp: Auto merged storage/ndb/src/ndbapi/Ndberr.cpp: Auto merged storage/ndb/src/ndbapi/Ndbif.cpp: Auto merged storage/ndb/src/ndbapi/Ndbinit.cpp: Auto merged storage/ndb/src/ndbapi/Ndblist.cpp: Auto merged storage/ndb/src/ndbapi/ObjectMap.hpp: Auto merged storage/ndb/src/ndbapi/SignalSender.cpp: Auto merged storage/ndb/src/ndbapi/SignalSender.hpp: Auto merged storage/ndb/src/ndbapi/TransporterFacade.cpp: Auto merged storage/ndb/src/ndbapi/TransporterFacade.hpp: Auto merged storage/ndb/src/ndbapi/ndb_cluster_connection.cpp: Auto merged storage/ndb/src/ndbapi/ndb_cluster_connection_impl.hpp: Auto merged storage/ndb/src/ndbapi/ndberror.c: Auto merged storage/ndb/src/ndbapi/signal-sender/SignalSender.cpp: Auto merged storage/ndb/src/ndbapi/signal-sender/SignalSender.hpp: Auto merged storage/ndb/test/include/CpcClient.hpp: Auto merged storage/ndb/test/include/HugoAsynchTransactions.hpp: Auto merged storage/ndb/test/include/HugoCalculator.hpp: Auto merged storage/ndb/test/include/HugoOperations.hpp: Auto merged storage/ndb/test/include/HugoTransactions.hpp: Auto merged storage/ndb/test/include/NDBT.hpp: Auto merged storage/ndb/test/include/NDBT_DataSet.hpp: Auto merged storage/ndb/test/include/NDBT_DataSetTransaction.hpp: Auto merged storage/ndb/test/include/NDBT_Error.hpp: Auto merged storage/ndb/test/include/NDBT_Output.hpp: Auto merged storage/ndb/test/include/NDBT_ResultRow.hpp: Auto merged storage/ndb/test/include/NDBT_ReturnCodes.h: Auto merged storage/ndb/test/include/NDBT_Stats.hpp: Auto merged storage/ndb/test/include/NDBT_Table.hpp: Auto merged storage/ndb/test/include/NDBT_Tables.hpp: Auto merged storage/ndb/test/include/NDBT_Test.hpp: Auto merged storage/ndb/test/include/NdbBackup.hpp: Auto merged storage/ndb/test/include/NdbConfig.hpp: Auto merged storage/ndb/test/include/NdbGrep.hpp: Auto merged storage/ndb/test/include/NdbRestarter.hpp: Auto merged storage/ndb/test/include/NdbRestarts.hpp: Auto merged storage/ndb/test/include/NdbSchemaCon.hpp: Auto merged storage/ndb/test/include/NdbSchemaOp.hpp: Auto merged storage/ndb/test/include/NdbTest.hpp: Auto merged storage/ndb/test/include/NdbTimer.hpp: Auto merged storage/ndb/test/include/TestNdbEventOperation.hpp: Auto merged storage/ndb/test/include/UtilTransactions.hpp: Auto merged storage/ndb/test/include/getarg.h: Auto merged storage/ndb/test/ndbapi/InsertRecs.cpp: Auto merged storage/ndb/test/ndbapi/ScanFilter.hpp: Auto merged storage/ndb/test/ndbapi/ScanFunctions.hpp: Auto merged storage/ndb/test/ndbapi/ScanInterpretTest.hpp: Auto merged storage/ndb/test/ndbapi/TraceNdbApi.cpp: Auto merged storage/ndb/test/ndbapi/VerifyNdbApi.cpp: Auto merged storage/ndb/test/ndbapi/acid.cpp: Auto merged storage/ndb/test/ndbapi/acid2.cpp: Auto merged storage/ndb/test/ndbapi/adoInsertRecs.cpp: Auto merged storage/ndb/test/ndbapi/asyncGenerator.cpp: Auto merged storage/ndb/test/ndbapi/benchronja.cpp: Auto merged storage/ndb/test/ndbapi/bulk_copy.cpp: Auto merged storage/ndb/test/ndbapi/cdrserver.cpp: Auto merged storage/ndb/test/ndbapi/celloDb.cpp: Auto merged storage/ndb/test/ndbapi/create_all_tabs.cpp: Auto merged storage/ndb/test/ndbapi/create_tab.cpp: Auto merged storage/ndb/test/ndbapi/drop_all_tabs.cpp: Auto merged storage/ndb/test/ndbapi/flexAsynch.cpp: Auto merged storage/ndb/test/ndbapi/flexBench.cpp: Auto merged storage/ndb/test/ndbapi/flexHammer.cpp: Auto merged storage/ndb/test/ndbapi/flexScan.cpp: Auto merged storage/ndb/test/ndbapi/flexTT.cpp: Auto merged storage/ndb/test/ndbapi/flexTimedAsynch.cpp: Auto merged storage/ndb/test/ndbapi/flex_bench_mysql.cpp: Auto merged storage/ndb/test/ndbapi/index.cpp: Auto merged storage/ndb/test/ndbapi/index2.cpp: Auto merged storage/ndb/test/ndbapi/initronja.cpp: Auto merged storage/ndb/test/ndbapi/interpreterInTup.cpp: Auto merged storage/ndb/test/ndbapi/mainAsyncGenerator.cpp: Auto merged storage/ndb/test/ndbapi/msa.cpp: Auto merged storage/ndb/test/ndbapi/ndb_async1.cpp: Auto merged storage/ndb/test/ndbapi/ndb_async2.cpp: Auto merged storage/ndb/test/ndbapi/ndb_user_populate.cpp: Auto merged storage/ndb/test/ndbapi/ndb_user_transaction.cpp: Auto merged storage/ndb/test/ndbapi/ndb_user_transaction2.cpp: Auto merged storage/ndb/test/ndbapi/ndb_user_transaction3.cpp: Auto merged storage/ndb/test/ndbapi/ndb_user_transaction4.cpp: Auto merged storage/ndb/test/ndbapi/ndb_user_transaction5.cpp: Auto merged storage/ndb/test/ndbapi/ndb_user_transaction6.cpp: Auto merged storage/ndb/test/ndbapi/restarter.cpp: Auto merged storage/ndb/test/ndbapi/restarter2.cpp: Auto merged storage/ndb/test/ndbapi/restarts.cpp: Auto merged storage/ndb/test/ndbapi/size.cpp: Auto merged storage/ndb/test/ndbapi/testBackup.cpp: Auto merged storage/ndb/test/ndbapi/testBasic.cpp: Auto merged storage/ndb/test/ndbapi/testBasicAsynch.cpp: Auto merged storage/ndb/test/ndbapi/testBlobs.cpp: Auto merged storage/ndb/test/ndbapi/testDataBuffers.cpp: Auto merged storage/ndb/test/ndbapi/testDeadlock.cpp: Auto merged storage/ndb/test/ndbapi/testDict.cpp: Auto merged storage/ndb/test/ndbapi/testGrepVerify.cpp: Auto merged storage/ndb/test/ndbapi/testIndex.cpp: Auto merged storage/ndb/test/ndbapi/testInterpreter.cpp: Auto merged storage/ndb/test/ndbapi/testMgm.cpp: Auto merged storage/ndb/test/ndbapi/testNdbApi.cpp: Auto merged storage/ndb/test/ndbapi/testNodeRestart.cpp: Auto merged storage/ndb/test/ndbapi/testOIBasic.cpp: Auto merged storage/ndb/test/ndbapi/testOperations.cpp: Auto merged storage/ndb/test/ndbapi/testOrderedIndex.cpp: Auto merged storage/ndb/test/ndbapi/testPartitioning.cpp: Auto merged storage/ndb/test/ndbapi/testReadPerf.cpp: Auto merged storage/ndb/test/ndbapi/bank/Bank.cpp: Auto merged storage/ndb/test/ndbapi/bank/Bank.hpp: Auto merged storage/ndb/test/ndbapi/bank/BankLoad.cpp: Auto merged storage/ndb/test/ndbapi/bank/bankCreator.cpp: Auto merged storage/ndb/test/ndbapi/bank/bankMakeGL.cpp: Auto merged storage/ndb/test/ndbapi/bank/bankSumAccounts.cpp: Auto merged storage/ndb/test/ndbapi/bank/bankTimer.cpp: Auto merged storage/ndb/test/ndbapi/bank/bankTransactionMaker.cpp: Auto merged storage/ndb/test/ndbapi/bank/bankValidateAllGLs.cpp: Auto merged storage/ndb/test/ndbapi/bank/testBank.cpp: Auto merged storage/ndb/test/ndbapi/bench/asyncGenerator.cpp: Auto merged storage/ndb/test/ndbapi/bench/dbGenerator.h: Auto merged storage/ndb/test/ndbapi/bench/dbPopulate.cpp: Auto merged storage/ndb/test/ndbapi/bench/dbPopulate.h: Auto merged storage/ndb/test/ndbapi/bench/macros.h: Auto merged storage/ndb/test/ndbapi/bench/mainAsyncGenerator.cpp: Auto merged storage/ndb/test/ndbapi/bench/mainPopulate.cpp: Auto merged storage/ndb/test/ndbapi/bench/ndb_async1.cpp: Auto merged storage/ndb/test/ndbapi/bench/ndb_async2.cpp: Auto merged storage/ndb/test/ndbapi/testRestartGci.cpp: Auto merged storage/ndb/test/ndbapi/testSRBank.cpp: Auto merged storage/ndb/test/ndbapi/testScan.cpp: Auto merged storage/ndb/test/ndbapi/testScanInterpreter.cpp: Auto merged storage/ndb/test/ndbapi/testScanPerf.cpp: Auto merged storage/ndb/test/ndbapi/testSystemRestart.cpp: Auto merged storage/ndb/test/ndbapi/testTimeout.cpp: Auto merged storage/ndb/test/ndbapi/testTransactions.cpp: Auto merged storage/ndb/test/ndbapi/test_event.cpp: Auto merged storage/ndb/test/ndbapi/test_event_merge.cpp: Auto merged storage/ndb/test/ndbapi/test_event_multi_table.cpp: Auto merged storage/ndb/test/ndbapi/userInterface.cpp: Auto merged storage/ndb/test/ndbapi/bench/ndb_error.hpp: Auto merged storage/ndb/test/ndbapi/bench/ndb_schema.hpp: Auto merged storage/ndb/test/ndbapi/bench/ndb_user_transaction.cpp: Auto merged storage/ndb/test/ndbapi/bench/ndb_user_transaction2.cpp: Auto merged storage/ndb/test/ndbapi/bench/ndb_user_transaction3.cpp: Auto merged storage/ndb/test/ndbapi/bench/ndb_user_transaction4.cpp: Auto merged storage/ndb/test/ndbapi/bench/ndb_user_transaction5.cpp: Auto merged storage/ndb/test/ndbapi/bench/ndb_user_transaction6.cpp: Auto merged storage/ndb/test/ndbapi/bench/testData.h: Auto merged storage/ndb/test/ndbapi/bench/testDefinitions.h: Auto merged storage/ndb/test/ndbapi/bench/userInterface.cpp: Auto merged storage/ndb/test/ndbapi/bench/userInterface.h: Auto merged storage/ndb/test/newtonapi/basic_test/basic/basic.cpp: Auto merged storage/ndb/test/newtonapi/basic_test/bulk_read/br_test.cpp: Auto merged storage/ndb/test/newtonapi/basic_test/common.cpp: Auto merged storage/ndb/test/newtonapi/basic_test/common.hpp: Auto merged storage/ndb/test/newtonapi/basic_test/ptr_binding/ptr_binding_test.cpp: Auto merged storage/ndb/test/newtonapi/basic_test/too_basic.cpp: Auto merged storage/ndb/test/newtonapi/perf_test/perf.cpp: Auto merged storage/ndb/test/odbc/SQL99_test/SQL99_test.cpp: Auto merged storage/ndb/test/odbc/SQL99_test/SQL99_test.h: Auto merged storage/ndb/test/odbc/client/NDBT_ALLOCHANDLE.cpp: Auto merged storage/ndb/test/odbc/client/NDBT_ALLOCHANDLE_HDBC.cpp: Auto merged storage/ndb/test/odbc/client/NDBT_SQLConnect.cpp: Auto merged storage/ndb/test/odbc/client/NDBT_SQLPrepare.cpp: Auto merged storage/ndb/test/odbc/client/SQLAllocEnvTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLAllocHandleTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLAllocHandleTest_bf.cpp: Auto merged storage/ndb/test/odbc/client/SQLBindColTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLBindParameterTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLCancelTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLCloseCursorTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLColAttributeTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLColAttributeTest1.cpp: Auto merged storage/ndb/test/odbc/client/SQLColAttributeTest2.cpp: Auto merged storage/ndb/test/odbc/client/SQLColAttributeTest3.cpp: Auto merged storage/ndb/test/odbc/client/SQLConnectTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLCopyDescTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLDescribeColTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLDisconnectTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLDriverConnectTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLEndTranTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLErrorTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLExecDirectTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLExecuteTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLFetchScrollTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLFetchTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLFreeHandleTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLFreeStmtTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLGetConnectAttrTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLGetCursorNameTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLGetDataTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLGetDescFieldTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLGetDescRecTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLGetDiagFieldTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLGetDiagRecSimpleTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLGetDiagRecTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLGetEnvAttrTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLGetFunctionsTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLGetInfoTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLGetStmtAttrTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLGetTypeInfoTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLMoreResultsTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLNumResultColsTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLParamDataTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLPrepareTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLPutDataTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLRowCountTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLSetConnectAttrTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLSetCursorNameTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLSetDescFieldTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLSetDescRecTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLSetEnvAttrTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLSetStmtAttrTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLTablesTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLTransactTest.cpp: Auto merged storage/ndb/test/odbc/client/common.hpp: Auto merged storage/ndb/test/odbc/client/main.cpp: Auto merged storage/ndb/test/odbc/driver/testOdbcDriver.cpp: Auto merged storage/ndb/test/odbc/test_compiler/test_compiler.cpp: Auto merged storage/ndb/test/run-test/main.cpp: Auto merged storage/ndb/test/run-test/run-test.hpp: Auto merged storage/ndb/test/src/CpcClient.cpp: Auto merged storage/ndb/test/src/HugoAsynchTransactions.cpp: Auto merged storage/ndb/test/src/HugoCalculator.cpp: Auto merged storage/ndb/test/src/HugoOperations.cpp: Auto merged storage/ndb/test/src/HugoTransactions.cpp: Auto merged storage/ndb/test/src/NDBT_Error.cpp: Auto merged storage/ndb/test/src/NDBT_Output.cpp: Auto merged storage/ndb/test/src/NDBT_ResultRow.cpp: Auto merged storage/ndb/test/src/NDBT_ReturnCodes.cpp: Auto merged storage/ndb/test/src/NDBT_Table.cpp: Auto merged storage/ndb/test/src/NDBT_Tables.cpp: Auto merged storage/ndb/test/src/NDBT_Test.cpp: Auto merged storage/ndb/test/src/NdbBackup.cpp: Auto merged storage/ndb/test/src/NdbConfig.cpp: Auto merged storage/ndb/test/src/NdbGrep.cpp: Auto merged storage/ndb/test/src/NdbRestarter.cpp: Auto merged storage/ndb/test/src/NdbRestarts.cpp: Auto merged storage/ndb/test/src/NdbSchemaCon.cpp: Auto merged storage/ndb/test/src/NdbSchemaOp.cpp: Auto merged storage/ndb/test/src/UtilTransactions.cpp: Auto merged storage/ndb/test/tools/copy_tab.cpp: Auto merged storage/ndb/test/tools/cpcc.cpp: Auto merged storage/ndb/test/tools/create_index.cpp: Auto merged storage/ndb/test/tools/hugoCalculator.cpp: Auto merged storage/ndb/test/tools/hugoFill.cpp: Auto merged storage/ndb/test/tools/hugoLoad.cpp: Auto merged storage/ndb/test/tools/hugoLockRecords.cpp: Auto merged storage/ndb/test/tools/hugoPkDelete.cpp: Auto merged storage/ndb/test/tools/hugoPkRead.cpp: Auto merged storage/ndb/test/tools/hugoPkReadRecord.cpp: Auto merged storage/ndb/test/tools/hugoPkUpdate.cpp: Auto merged storage/ndb/test/tools/hugoScanRead.cpp: Auto merged storage/ndb/test/tools/hugoScanUpdate.cpp: Auto merged storage/ndb/test/tools/restart.cpp: Auto merged storage/ndb/test/tools/transproxy.cpp: Auto merged storage/ndb/test/tools/verify_index.cpp: Auto merged storage/ndb/tools/delete_all.cpp: Auto merged storage/ndb/tools/desc.cpp: Auto merged storage/ndb/tools/drop_index.cpp: Auto merged storage/ndb/tools/drop_tab.cpp: Auto merged storage/ndb/tools/listTables.cpp: Auto merged storage/ndb/tools/ndb_condig.cpp: Auto merged storage/ndb/tools/ndb_test_platform.cpp: Auto merged storage/ndb/tools/ndbsql.cpp: Auto merged storage/ndb/tools/restore/Restore.cpp: Auto merged storage/ndb/tools/restore/Restore.hpp: Auto merged storage/ndb/tools/restore/consumer.cpp: Auto merged storage/ndb/tools/restore/consumer.hpp: Auto merged storage/ndb/tools/restore/consumer_printer.cpp: Auto merged storage/ndb/tools/restore/consumer_printer.hpp: Auto merged storage/ndb/tools/restore/consumer_restore.cpp: Auto merged storage/ndb/tools/restore/consumer_restore.hpp: Auto merged storage/ndb/tools/restore/consumer_restorem.cpp: Auto merged storage/ndb/tools/restore/restore_main.cpp: Auto merged storage/ndb/tools/select_all.cpp: Auto merged storage/ndb/tools/select_count.cpp: Auto merged storage/ndb/tools/waiter.cpp: Auto merged strings/Makefile.am: Auto merged strings/ctype-big5.c: Auto merged strings/ctype-bin.c: Auto merged strings/ctype-cp932.c: Auto merged strings/ctype-euc_kr.c: Auto merged strings/ctype-eucjpms.c: Auto merged strings/ctype-gb2312.c: Auto merged strings/ctype-gbk.c: Auto merged strings/ctype-latin1.c: Auto merged strings/ctype-mb.c: Auto merged strings/ctype-simple.c: Auto merged strings/ctype-sjis.c: Auto merged strings/ctype-tis620.c: Auto merged strings/ctype-ucs2.c: Auto merged strings/ctype-ujis.c: Auto merged strings/ctype-utf8.c: Auto merged strings/ctype-win1250ch.c: Auto merged strings/ctype.c: Auto merged strings/decimal.c: Auto merged strings/strxnmov.c: Auto merged strings/xml.c: Auto merged tests/Makefile.am: Auto merged tests/mysql_client_test.c: Auto merged vio/Makefile.am: Auto merged vio/vio.c: Auto merged vio/viosocket.c: Auto merged vio/viossl.c: Auto merged vio/viosslfactories.c: Auto merged zlib/Makefile.am: Auto merged
7434 lines
194 KiB
C
7434 lines
194 KiB
C
/* Copyright (C) 2000 MySQL AB
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
|
|
/*
|
|
mysqltest
|
|
|
|
Tool used for executing a .test file
|
|
|
|
See the "MySQL Test framework manual" for more information
|
|
http://dev.mysql.com/doc/mysqltest/en/index.html
|
|
|
|
Please keep the test framework tools identical in all versions!
|
|
|
|
Written by:
|
|
Sasha Pachev <sasha@mysql.com>
|
|
Matt Wagner <matt@mysql.com>
|
|
Monty
|
|
Jani
|
|
Holyfoot
|
|
*/
|
|
|
|
#define MTEST_VERSION "3.1"
|
|
|
|
#include <my_global.h>
|
|
#include <mysql_embed.h>
|
|
#include <my_sys.h>
|
|
#include <m_string.h>
|
|
#include <mysql.h>
|
|
#include <mysql_version.h>
|
|
#include <mysqld_error.h>
|
|
#include <errmsg.h>
|
|
#include <m_ctype.h>
|
|
#include <my_dir.h>
|
|
#include <hash.h>
|
|
#include <my_getopt.h>
|
|
#include <stdarg.h>
|
|
#include <violite.h>
|
|
#include "my_regex.h" /* Our own version of regex */
|
|
#ifdef HAVE_SYS_WAIT_H
|
|
#include <sys/wait.h>
|
|
#endif
|
|
|
|
#ifndef WEXITSTATUS
|
|
# ifdef __WIN__
|
|
# define WEXITSTATUS(stat_val) (stat_val)
|
|
# else
|
|
# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
|
|
# endif
|
|
#endif
|
|
|
|
#define MAX_VAR_NAME_LENGTH 256
|
|
#define MAX_COLUMNS 256
|
|
#define MAX_EMBEDDED_SERVER_ARGS 64
|
|
#define MAX_DELIMITER_LENGTH 16
|
|
|
|
/* Flags controlling send and reap */
|
|
#define QUERY_SEND_FLAG 1
|
|
#define QUERY_REAP_FLAG 2
|
|
|
|
enum {
|
|
RESULT_OK= 0,
|
|
RESULT_CONTENT_MISMATCH= 1,
|
|
RESULT_LENGTH_MISMATCH= 2
|
|
};
|
|
|
|
enum {
|
|
OPT_SKIP_SAFEMALLOC=256, OPT_SSL_SSL, OPT_SSL_KEY, OPT_SSL_CERT,
|
|
OPT_SSL_CA, OPT_SSL_CAPATH, OPT_SSL_CIPHER, OPT_PS_PROTOCOL,
|
|
OPT_SP_PROTOCOL, OPT_CURSOR_PROTOCOL, OPT_VIEW_PROTOCOL,
|
|
OPT_SSL_VERIFY_SERVER_CERT, OPT_MAX_CONNECT_RETRIES,
|
|
OPT_MARK_PROGRESS, OPT_CHARSETS_DIR, OPT_LOG_DIR, OPT_DEBUG_INFO
|
|
};
|
|
|
|
static int record= 0, opt_sleep= -1;
|
|
static char *db= 0, *pass= 0;
|
|
const char *user= 0, *host= 0, *unix_sock= 0, *opt_basedir= "./";
|
|
const char *opt_logdir= "";
|
|
const char *opt_include= 0, *opt_charsets_dir;
|
|
static int port= 0;
|
|
static int opt_max_connect_retries;
|
|
static my_bool opt_compress= 0, silent= 0, verbose= 0;
|
|
static my_bool tty_password= 0;
|
|
static my_bool opt_mark_progress= 0;
|
|
static my_bool ps_protocol= 0, ps_protocol_enabled= 0;
|
|
static my_bool sp_protocol= 0, sp_protocol_enabled= 0;
|
|
static my_bool view_protocol= 0, view_protocol_enabled= 0;
|
|
static my_bool cursor_protocol= 0, cursor_protocol_enabled= 0;
|
|
static my_bool parsing_disabled= 0;
|
|
static my_bool info_flag;
|
|
static my_bool display_result_vertically= FALSE, display_metadata= FALSE;
|
|
static my_bool disable_query_log= 0, disable_result_log= 0;
|
|
static my_bool disable_warnings= 0, disable_ps_warnings= 0;
|
|
static my_bool disable_info= 1;
|
|
static my_bool abort_on_error= 1;
|
|
static my_bool server_initialized= 0;
|
|
|
|
static char **default_argv;
|
|
static const char *load_default_groups[]= { "mysqltest", "client", 0 };
|
|
static char line_buffer[MAX_DELIMITER_LENGTH], *line_buffer_pos= line_buffer;
|
|
|
|
static uint start_lineno= 0; /* Start line of current command */
|
|
|
|
static char delimiter[MAX_DELIMITER_LENGTH]= ";";
|
|
static uint delimiter_length= 1;
|
|
|
|
static char TMPDIR[FN_REFLEN];
|
|
|
|
/* Block stack */
|
|
enum block_cmd {
|
|
cmd_none,
|
|
cmd_if,
|
|
cmd_while
|
|
};
|
|
|
|
struct st_block
|
|
{
|
|
int line; /* Start line of block */
|
|
my_bool ok; /* Should block be executed */
|
|
enum block_cmd cmd; /* Command owning the block */
|
|
};
|
|
|
|
static struct st_block block_stack[32];
|
|
static struct st_block *cur_block, *block_stack_end;
|
|
|
|
/* Open file stack */
|
|
struct st_test_file
|
|
{
|
|
FILE* file;
|
|
const char *file_name;
|
|
uint lineno; /* Current line in file */
|
|
};
|
|
|
|
static struct st_test_file file_stack[16];
|
|
static struct st_test_file* cur_file;
|
|
static struct st_test_file* file_stack_end;
|
|
|
|
|
|
static CHARSET_INFO *charset_info= &my_charset_latin1; /* Default charset */
|
|
|
|
static const char *embedded_server_groups[]=
|
|
{
|
|
"server",
|
|
"embedded",
|
|
"mysqltest_SERVER",
|
|
NullS
|
|
};
|
|
|
|
static int embedded_server_arg_count=0;
|
|
static char *embedded_server_args[MAX_EMBEDDED_SERVER_ARGS];
|
|
|
|
/*
|
|
Timer related variables
|
|
See the timer_output() definition for details
|
|
*/
|
|
static char *timer_file = NULL;
|
|
static ulonglong timer_start;
|
|
static void timer_output(void);
|
|
static ulonglong timer_now(void);
|
|
|
|
static ulonglong progress_start= 0;
|
|
|
|
/* Precompiled re's */
|
|
static my_regex_t ps_re; /* the query can be run using PS protocol */
|
|
static my_regex_t sp_re; /* the query can be run as a SP */
|
|
static my_regex_t view_re; /* the query can be run as a view*/
|
|
|
|
static void init_re(void);
|
|
static int match_re(my_regex_t *, char *);
|
|
static void free_re(void);
|
|
|
|
DYNAMIC_ARRAY q_lines;
|
|
|
|
#include "sslopt-vars.h"
|
|
|
|
struct
|
|
{
|
|
int read_lines,current_line;
|
|
} parser;
|
|
|
|
struct
|
|
{
|
|
char file[FN_REFLEN];
|
|
ulong pos;
|
|
} master_pos;
|
|
|
|
/* if set, all results are concated and compared against this file */
|
|
const char *result_file_name= 0;
|
|
|
|
typedef struct st_var
|
|
{
|
|
char *name;
|
|
int name_len;
|
|
char *str_val;
|
|
int str_val_len;
|
|
int int_val;
|
|
int alloced_len;
|
|
int int_dirty; /* do not update string if int is updated until first read */
|
|
int alloced;
|
|
char *env_s;
|
|
} VAR;
|
|
|
|
/*Perl/shell-like variable registers */
|
|
VAR var_reg[10];
|
|
|
|
HASH var_hash;
|
|
|
|
struct st_connection
|
|
{
|
|
MYSQL mysql;
|
|
/* Used when creating views and sp, to avoid implicit commit */
|
|
MYSQL* util_mysql;
|
|
char *name;
|
|
MYSQL_STMT* stmt;
|
|
|
|
#ifdef EMBEDDED_LIBRARY
|
|
const char *cur_query;
|
|
int cur_query_len;
|
|
pthread_mutex_t mutex;
|
|
pthread_cond_t cond;
|
|
int query_done;
|
|
#endif /*EMBEDDED_LIBRARY*/
|
|
};
|
|
struct st_connection connections[128];
|
|
struct st_connection* cur_con, *next_con, *connections_end;
|
|
|
|
/*
|
|
List of commands in mysqltest
|
|
Must match the "command_names" array
|
|
Add new commands before Q_UNKNOWN!
|
|
*/
|
|
enum enum_commands {
|
|
Q_CONNECTION=1, Q_QUERY,
|
|
Q_CONNECT, Q_SLEEP, Q_REAL_SLEEP,
|
|
Q_INC, Q_DEC,
|
|
Q_SOURCE, Q_DISCONNECT,
|
|
Q_LET, Q_ECHO,
|
|
Q_WHILE, Q_END_BLOCK,
|
|
Q_SYSTEM, Q_RESULT,
|
|
Q_REQUIRE, Q_SAVE_MASTER_POS,
|
|
Q_SYNC_WITH_MASTER,
|
|
Q_SYNC_SLAVE_WITH_MASTER,
|
|
Q_ERROR,
|
|
Q_SEND, Q_REAP,
|
|
Q_DIRTY_CLOSE, Q_REPLACE, Q_REPLACE_COLUMN,
|
|
Q_PING, Q_EVAL,
|
|
Q_RPL_PROBE, Q_ENABLE_RPL_PARSE,
|
|
Q_DISABLE_RPL_PARSE, Q_EVAL_RESULT,
|
|
Q_ENABLE_QUERY_LOG, Q_DISABLE_QUERY_LOG,
|
|
Q_ENABLE_RESULT_LOG, Q_DISABLE_RESULT_LOG,
|
|
Q_WAIT_FOR_SLAVE_TO_STOP,
|
|
Q_ENABLE_WARNINGS, Q_DISABLE_WARNINGS,
|
|
Q_ENABLE_PS_WARNINGS, Q_DISABLE_PS_WARNINGS,
|
|
Q_ENABLE_INFO, Q_DISABLE_INFO,
|
|
Q_ENABLE_METADATA, Q_DISABLE_METADATA,
|
|
Q_EXEC, Q_DELIMITER,
|
|
Q_DISABLE_ABORT_ON_ERROR, Q_ENABLE_ABORT_ON_ERROR,
|
|
Q_DISPLAY_VERTICAL_RESULTS, Q_DISPLAY_HORIZONTAL_RESULTS,
|
|
Q_QUERY_VERTICAL, Q_QUERY_HORIZONTAL,
|
|
Q_START_TIMER, Q_END_TIMER,
|
|
Q_CHARACTER_SET, Q_DISABLE_PS_PROTOCOL, Q_ENABLE_PS_PROTOCOL,
|
|
Q_DISABLE_RECONNECT, Q_ENABLE_RECONNECT,
|
|
Q_IF,
|
|
Q_DISABLE_PARSING, Q_ENABLE_PARSING,
|
|
Q_REPLACE_REGEX, Q_REMOVE_FILE, Q_FILE_EXIST,
|
|
Q_WRITE_FILE, Q_COPY_FILE, Q_PERL, Q_DIE, Q_EXIT,
|
|
Q_CHMOD_FILE,
|
|
|
|
Q_UNKNOWN, /* Unknown command. */
|
|
Q_COMMENT, /* Comments, ignored. */
|
|
Q_COMMENT_WITH_COMMAND
|
|
};
|
|
|
|
|
|
const char *command_names[]=
|
|
{
|
|
"connection",
|
|
"query",
|
|
"connect",
|
|
"sleep",
|
|
"real_sleep",
|
|
"inc",
|
|
"dec",
|
|
"source",
|
|
"disconnect",
|
|
"let",
|
|
"echo",
|
|
"while",
|
|
"end",
|
|
"system",
|
|
"result",
|
|
"require",
|
|
"save_master_pos",
|
|
"sync_with_master",
|
|
"sync_slave_with_master",
|
|
"error",
|
|
"send",
|
|
"reap",
|
|
"dirty_close",
|
|
"replace_result",
|
|
"replace_column",
|
|
"ping",
|
|
"eval",
|
|
"rpl_probe",
|
|
"enable_rpl_parse",
|
|
"disable_rpl_parse",
|
|
"eval_result",
|
|
/* Enable/disable that the _query_ is logged to result file */
|
|
"enable_query_log",
|
|
"disable_query_log",
|
|
/* Enable/disable that the _result_ from a query is logged to result file */
|
|
"enable_result_log",
|
|
"disable_result_log",
|
|
"wait_for_slave_to_stop",
|
|
"enable_warnings",
|
|
"disable_warnings",
|
|
"enable_ps_warnings",
|
|
"disable_ps_warnings",
|
|
"enable_info",
|
|
"disable_info",
|
|
"enable_metadata",
|
|
"disable_metadata",
|
|
"exec",
|
|
"delimiter",
|
|
"disable_abort_on_error",
|
|
"enable_abort_on_error",
|
|
"vertical_results",
|
|
"horizontal_results",
|
|
"query_vertical",
|
|
"query_horizontal",
|
|
"start_timer",
|
|
"end_timer",
|
|
"character_set",
|
|
"disable_ps_protocol",
|
|
"enable_ps_protocol",
|
|
"disable_reconnect",
|
|
"enable_reconnect",
|
|
"if",
|
|
"disable_parsing",
|
|
"enable_parsing",
|
|
"replace_regex",
|
|
"remove_file",
|
|
"file_exists",
|
|
"write_file",
|
|
"copy_file",
|
|
"perl",
|
|
"die",
|
|
/* Don't execute any more commands, compare result */
|
|
"exit",
|
|
"chmod",
|
|
0
|
|
};
|
|
|
|
|
|
/*
|
|
The list of error codes to --error are stored in an internal array of
|
|
structs. This struct can hold numeric SQL error codes, error names or
|
|
SQLSTATE codes as strings. The element next to the last active element
|
|
in the list is set to type ERR_EMPTY. When an SQL statement returns an
|
|
error, we use this list to check if this is an expected error.
|
|
*/
|
|
enum match_err_type
|
|
{
|
|
ERR_EMPTY= 0,
|
|
ERR_ERRNO,
|
|
ERR_SQLSTATE
|
|
};
|
|
|
|
struct st_match_err
|
|
{
|
|
enum match_err_type type;
|
|
union
|
|
{
|
|
uint errnum;
|
|
char sqlstate[SQLSTATE_LENGTH+1]; /* \0 terminated string */
|
|
} code;
|
|
};
|
|
|
|
struct st_expected_errors
|
|
{
|
|
struct st_match_err err[10];
|
|
uint count;
|
|
};
|
|
static struct st_expected_errors saved_expected_errors;
|
|
|
|
struct st_command
|
|
{
|
|
char *query, *query_buf,*first_argument,*last_argument,*end;
|
|
int first_word_len, query_len;
|
|
my_bool abort_on_error;
|
|
struct st_expected_errors expected_errors;
|
|
char require_file[FN_REFLEN];
|
|
enum enum_commands type;
|
|
};
|
|
|
|
TYPELIB command_typelib= {array_elements(command_names),"",
|
|
command_names, 0};
|
|
|
|
DYNAMIC_STRING ds_res, ds_progress, ds_warning_messages;
|
|
|
|
void die(const char *fmt, ...)
|
|
ATTRIBUTE_FORMAT(printf, 1, 2);
|
|
void abort_not_supported_test(const char *fmt, ...)
|
|
ATTRIBUTE_FORMAT(printf, 1, 2);
|
|
void verbose_msg(const char *fmt, ...)
|
|
ATTRIBUTE_FORMAT(printf, 1, 2);
|
|
void warning_msg(const char *fmt, ...)
|
|
ATTRIBUTE_FORMAT(printf, 1, 2);
|
|
|
|
VAR* var_from_env(const char *, const char *);
|
|
VAR* var_init(VAR* v, const char *name, int name_len, const char *val,
|
|
int val_len);
|
|
void var_free(void* v);
|
|
VAR* var_get(const char *var_name, const char** var_name_end,
|
|
my_bool raw, my_bool ignore_not_existing);
|
|
void eval_expr(VAR* v, const char *p, const char** p_end);
|
|
my_bool match_delimiter(int c, const char *delim, uint length);
|
|
void dump_result_to_reject_file(char *buf, int size);
|
|
void dump_result_to_log_file(char *buf, int size);
|
|
void dump_warning_messages();
|
|
void dump_progress();
|
|
|
|
void do_eval(DYNAMIC_STRING *query_eval, const char *query,
|
|
const char *query_end, my_bool pass_through_escape_chars);
|
|
void str_to_file(const char *fname, char *str, int size);
|
|
|
|
#ifdef __WIN__
|
|
void free_tmp_sh_file();
|
|
void free_win_path_patterns();
|
|
#endif
|
|
|
|
static int eval_result = 0;
|
|
|
|
/* For replace_column */
|
|
static char *replace_column[MAX_COLUMNS];
|
|
static uint max_replace_column= 0;
|
|
void do_get_replace_column(struct st_command*);
|
|
void free_replace_column();
|
|
|
|
/* For replace */
|
|
void do_get_replace(struct st_command *command);
|
|
void free_replace();
|
|
|
|
/* For replace_regex */
|
|
void do_get_replace_regex(struct st_command *command);
|
|
void free_replace_regex();
|
|
|
|
|
|
void free_all_replace(){
|
|
free_replace();
|
|
free_replace_regex();
|
|
free_replace_column();
|
|
}
|
|
|
|
|
|
/* Disable functions that only exist in MySQL 4.0 */
|
|
#if MYSQL_VERSION_ID < 40000
|
|
void mysql_enable_rpl_parse(MYSQL* mysql __attribute__((unused))) {}
|
|
void mysql_disable_rpl_parse(MYSQL* mysql __attribute__((unused))) {}
|
|
int mysql_rpl_parse_enabled(MYSQL* mysql __attribute__((unused))) { return 1; }
|
|
my_bool mysql_rpl_probe(MYSQL *mysql __attribute__((unused))) { return 1; }
|
|
#endif
|
|
void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val,
|
|
int len);
|
|
void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val);
|
|
void replace_dynstr_append_uint(DYNAMIC_STRING *ds, uint val);
|
|
|
|
void handle_error(struct st_command*,
|
|
unsigned int err_errno, const char *err_error,
|
|
const char *err_sqlstate, DYNAMIC_STRING *ds);
|
|
void handle_no_error(struct st_command*);
|
|
|
|
#ifdef EMBEDDED_LIBRARY
|
|
/*
|
|
send_one_query executes query in separate thread what is
|
|
necessary in embedded library to run 'send' in proper way.
|
|
This implementation doesn't handle errors returned
|
|
by mysql_send_query. It's technically possible, though
|
|
i don't see where it is needed.
|
|
*/
|
|
pthread_handler_t send_one_query(void *arg)
|
|
{
|
|
struct st_connection *cn= (struct st_connection*)arg;
|
|
|
|
mysql_thread_init();
|
|
VOID(mysql_send_query(&cn->mysql, cn->cur_query, cn->cur_query_len));
|
|
|
|
mysql_thread_end();
|
|
pthread_mutex_lock(&cn->mutex);
|
|
cn->query_done= 1;
|
|
VOID(pthread_cond_signal(&cn->cond));
|
|
pthread_mutex_unlock(&cn->mutex);
|
|
pthread_exit(0);
|
|
return 0;
|
|
}
|
|
|
|
static int do_send_query(struct st_connection *cn, const char *q, int q_len,
|
|
int flags)
|
|
{
|
|
pthread_t tid;
|
|
|
|
if (flags & QUERY_REAP_FLAG)
|
|
return mysql_send_query(&cn->mysql, q, q_len);
|
|
|
|
if (pthread_mutex_init(&cn->mutex, NULL) ||
|
|
pthread_cond_init(&cn->cond, NULL))
|
|
die("Error in the thread library");
|
|
|
|
cn->cur_query= q;
|
|
cn->cur_query_len= q_len;
|
|
cn->query_done= 0;
|
|
if (pthread_create(&tid, NULL, send_one_query, (void*)cn))
|
|
die("Cannot start new thread for query");
|
|
|
|
return 0;
|
|
}
|
|
|
|
#else /*EMBEDDED_LIBRARY*/
|
|
|
|
#define do_send_query(cn,q,q_len,flags) mysql_send_query(&cn->mysql, q, q_len)
|
|
|
|
#endif /*EMBEDDED_LIBRARY*/
|
|
|
|
void do_eval(DYNAMIC_STRING *query_eval, const char *query,
|
|
const char *query_end, my_bool pass_through_escape_chars)
|
|
{
|
|
const char *p;
|
|
register char c, next_c;
|
|
register int escaped = 0;
|
|
VAR *v;
|
|
DBUG_ENTER("do_eval");
|
|
|
|
for (p= query; (c= *p) && p < query_end; ++p)
|
|
{
|
|
switch(c) {
|
|
case '$':
|
|
if (escaped)
|
|
{
|
|
escaped= 0;
|
|
dynstr_append_mem(query_eval, p, 1);
|
|
}
|
|
else
|
|
{
|
|
if (!(v= var_get(p, &p, 0, 0)))
|
|
die("Bad variable in eval");
|
|
dynstr_append_mem(query_eval, v->str_val, v->str_val_len);
|
|
}
|
|
break;
|
|
case '\\':
|
|
next_c= *(p+1);
|
|
if (escaped)
|
|
{
|
|
escaped= 0;
|
|
dynstr_append_mem(query_eval, p, 1);
|
|
}
|
|
else if (next_c == '\\' || next_c == '$' || next_c == '"')
|
|
{
|
|
/* Set escaped only if next char is \, " or $ */
|
|
escaped= 1;
|
|
|
|
if (pass_through_escape_chars)
|
|
{
|
|
/* The escape char should be added to the output string. */
|
|
dynstr_append_mem(query_eval, p, 1);
|
|
}
|
|
}
|
|
else
|
|
dynstr_append_mem(query_eval, p, 1);
|
|
break;
|
|
default:
|
|
dynstr_append_mem(query_eval, p, 1);
|
|
break;
|
|
}
|
|
}
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
enum arg_type
|
|
{
|
|
ARG_STRING,
|
|
ARG_REST
|
|
};
|
|
|
|
struct command_arg {
|
|
const char *argname; /* Name of argument */
|
|
enum arg_type type; /* Type of argument */
|
|
my_bool required; /* Argument required */
|
|
DYNAMIC_STRING *ds; /* Storage for argument */
|
|
const char *description; /* Description of the argument */
|
|
};
|
|
|
|
|
|
void check_command_args(struct st_command *command,
|
|
const char *arguments,
|
|
const struct command_arg *args,
|
|
int num_args, const char delimiter_arg)
|
|
{
|
|
int i;
|
|
const char *ptr= arguments;
|
|
const char *start;
|
|
|
|
DBUG_ENTER("check_command_args");
|
|
DBUG_PRINT("enter", ("num_args: %d", num_args));
|
|
for (i= 0; i < num_args; i++)
|
|
{
|
|
const struct command_arg *arg= &args[i];
|
|
|
|
switch (arg->type)
|
|
{
|
|
/* A string */
|
|
case ARG_STRING:
|
|
/* Skip leading spaces */
|
|
while (*ptr && *ptr == ' ')
|
|
ptr++;
|
|
start= ptr;
|
|
/* Find end of arg, terminated by "delimiter_arg" */
|
|
while (*ptr && *ptr != delimiter_arg)
|
|
ptr++;
|
|
if (ptr > start)
|
|
{
|
|
init_dynamic_string(arg->ds, 0, ptr-start, 32);
|
|
do_eval(arg->ds, start, ptr, FALSE);
|
|
}
|
|
else
|
|
{
|
|
/* Empty string */
|
|
init_dynamic_string(arg->ds, "", 0, 0);
|
|
}
|
|
command->last_argument= (char*)ptr;
|
|
|
|
/* Step past the delimiter */
|
|
if (*ptr && *ptr == delimiter_arg)
|
|
ptr++;
|
|
DBUG_PRINT("info", ("val: %s", arg->ds->str));
|
|
break;
|
|
|
|
/* Rest of line */
|
|
case ARG_REST:
|
|
start= ptr;
|
|
init_dynamic_string(arg->ds, 0, command->query_len, 256);
|
|
do_eval(arg->ds, start, command->end, FALSE);
|
|
command->last_argument= command->end;
|
|
DBUG_PRINT("info", ("val: %s", arg->ds->str));
|
|
break;
|
|
|
|
default:
|
|
DBUG_ASSERT("Unknown argument type");
|
|
break;
|
|
}
|
|
|
|
/* Check required arg */
|
|
if (arg->ds->length == 0 && arg->required)
|
|
die("Missing required argument '%s' to command '%.*s'", arg->argname,
|
|
command->first_word_len, command->query);
|
|
|
|
}
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
void handle_command_error(struct st_command *command, uint error)
|
|
{
|
|
DBUG_ENTER("handle_command_error");
|
|
DBUG_PRINT("enter", ("error: %d", error));
|
|
if (error != 0)
|
|
{
|
|
uint i;
|
|
|
|
if (command->abort_on_error)
|
|
die("command \"%.*s\" failed with error %d",
|
|
command->first_word_len, command->query, error);
|
|
for (i= 0; i < command->expected_errors.count; i++)
|
|
{
|
|
DBUG_PRINT("info", ("expected error: %d",
|
|
command->expected_errors.err[i].code.errnum));
|
|
if ((command->expected_errors.err[i].type == ERR_ERRNO) &&
|
|
(command->expected_errors.err[i].code.errnum == error))
|
|
{
|
|
DBUG_PRINT("info", ("command \"%.*s\" failed with expected error: %d",
|
|
command->first_word_len, command->query, error));
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
}
|
|
die("command \"%.*s\" failed with wrong error: %d",
|
|
command->first_word_len, command->query, error);
|
|
}
|
|
else if (command->expected_errors.err[0].type == ERR_ERRNO &&
|
|
command->expected_errors.err[0].code.errnum != 0)
|
|
{
|
|
/* Error code we wanted was != 0, i.e. not an expected success */
|
|
die("command \"%.*s\" succeeded - should have failed with errno %d...",
|
|
command->first_word_len, command->query,
|
|
command->expected_errors.err[0].code.errnum);
|
|
}
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
void close_connections()
|
|
{
|
|
DBUG_ENTER("close_connections");
|
|
for (--next_con; next_con >= connections; --next_con)
|
|
{
|
|
if (next_con->stmt)
|
|
mysql_stmt_close(next_con->stmt);
|
|
next_con->stmt= 0;
|
|
mysql_close(&next_con->mysql);
|
|
if (next_con->util_mysql)
|
|
mysql_close(next_con->util_mysql);
|
|
my_free(next_con->name, MYF(MY_ALLOW_ZERO_PTR));
|
|
}
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
void close_files()
|
|
{
|
|
DBUG_ENTER("close_files");
|
|
for (; cur_file >= file_stack; cur_file--)
|
|
{
|
|
if (cur_file->file && cur_file->file != stdin)
|
|
{
|
|
DBUG_PRINT("info", ("closing file: %s", cur_file->file_name));
|
|
my_fclose(cur_file->file, MYF(0));
|
|
}
|
|
my_free((gptr)cur_file->file_name, MYF(MY_ALLOW_ZERO_PTR));
|
|
cur_file->file_name= 0;
|
|
}
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
void free_used_memory()
|
|
{
|
|
uint i;
|
|
DBUG_ENTER("free_used_memory");
|
|
|
|
close_connections();
|
|
close_files();
|
|
hash_free(&var_hash);
|
|
|
|
for (i= 0 ; i < q_lines.elements ; i++)
|
|
{
|
|
struct st_command **q= dynamic_element(&q_lines, i, struct st_command**);
|
|
my_free((gptr) (*q)->query_buf,MYF(MY_ALLOW_ZERO_PTR));
|
|
my_free((gptr) (*q),MYF(0));
|
|
}
|
|
for (i= 0; i < 10; i++)
|
|
{
|
|
if (var_reg[i].alloced_len)
|
|
my_free(var_reg[i].str_val, MYF(MY_WME));
|
|
}
|
|
while (embedded_server_arg_count > 1)
|
|
my_free(embedded_server_args[--embedded_server_arg_count],MYF(0));
|
|
delete_dynamic(&q_lines);
|
|
dynstr_free(&ds_res);
|
|
dynstr_free(&ds_progress);
|
|
dynstr_free(&ds_warning_messages);
|
|
free_all_replace();
|
|
my_free(pass,MYF(MY_ALLOW_ZERO_PTR));
|
|
free_defaults(default_argv);
|
|
free_re();
|
|
#ifdef __WIN__
|
|
free_tmp_sh_file();
|
|
free_win_path_patterns();
|
|
#endif
|
|
|
|
/* Only call mysql_server_end if mysql_server_init has been called */
|
|
if (server_initialized)
|
|
mysql_server_end();
|
|
|
|
/* Don't use DBUG after mysql_server_end() */
|
|
return;
|
|
}
|
|
|
|
|
|
void die(const char *fmt, ...)
|
|
{
|
|
va_list args;
|
|
DBUG_ENTER("die");
|
|
DBUG_PRINT("enter", ("start_lineno: %d", start_lineno));
|
|
|
|
/* Print the error message */
|
|
va_start(args, fmt);
|
|
if (fmt)
|
|
{
|
|
fprintf(stderr, "mysqltest: ");
|
|
if (cur_file && cur_file != file_stack)
|
|
fprintf(stderr, "In included file \"%s\": ",
|
|
cur_file->file_name);
|
|
if (start_lineno > 0)
|
|
fprintf(stderr, "At line %u: ", start_lineno);
|
|
vfprintf(stderr, fmt, args);
|
|
fprintf(stderr, "\n");
|
|
fflush(stderr);
|
|
}
|
|
va_end(args);
|
|
|
|
/* Dump the result that has been accumulated so far to .log file */
|
|
if (result_file_name && ds_res.length)
|
|
dump_result_to_log_file(ds_res.str, ds_res.length);
|
|
|
|
/* Dump warning messages */
|
|
if (result_file_name && ds_warning_messages.length)
|
|
dump_warning_messages();
|
|
|
|
/* Clean up and exit */
|
|
free_used_memory();
|
|
my_end(info_flag ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
|
|
|
|
if (!silent)
|
|
printf("not ok\n");
|
|
|
|
exit(1);
|
|
}
|
|
|
|
|
|
void abort_not_supported_test(const char *fmt, ...)
|
|
{
|
|
va_list args;
|
|
struct st_test_file* err_file= cur_file;
|
|
DBUG_ENTER("abort_not_supported_test");
|
|
|
|
/* Print include filestack */
|
|
fprintf(stderr, "The test '%s' is not supported by this installation\n",
|
|
file_stack->file_name);
|
|
fprintf(stderr, "Detected in file %s at line %d\n",
|
|
err_file->file_name, err_file->lineno);
|
|
while (err_file != file_stack)
|
|
{
|
|
err_file--;
|
|
fprintf(stderr, "included from %s at line %d\n",
|
|
err_file->file_name, err_file->lineno);
|
|
}
|
|
|
|
/* Print error message */
|
|
va_start(args, fmt);
|
|
if (fmt)
|
|
{
|
|
fprintf(stderr, "reason: ");
|
|
vfprintf(stderr, fmt, args);
|
|
fprintf(stderr, "\n");
|
|
fflush(stderr);
|
|
}
|
|
va_end(args);
|
|
|
|
/* Clean up and exit */
|
|
free_used_memory();
|
|
my_end(info_flag ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
|
|
|
|
if (!silent)
|
|
printf("skipped\n");
|
|
|
|
exit(62);
|
|
}
|
|
|
|
|
|
void abort_not_in_this_version()
|
|
{
|
|
die("Not available in this version of mysqltest");
|
|
}
|
|
|
|
|
|
void verbose_msg(const char *fmt, ...)
|
|
{
|
|
va_list args;
|
|
DBUG_ENTER("verbose_msg");
|
|
if (!verbose)
|
|
DBUG_VOID_RETURN;
|
|
|
|
va_start(args, fmt);
|
|
fprintf(stderr, "mysqltest: ");
|
|
if (cur_file && cur_file != file_stack)
|
|
fprintf(stderr, "In included file \"%s\": ",
|
|
cur_file->file_name);
|
|
if (start_lineno != 0)
|
|
fprintf(stderr, "At line %u: ", start_lineno);
|
|
vfprintf(stderr, fmt, args);
|
|
fprintf(stderr, "\n");
|
|
va_end(args);
|
|
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
void warning_msg(const char *fmt, ...)
|
|
{
|
|
va_list args;
|
|
char buff[512];
|
|
size_t len;
|
|
DBUG_ENTER("warning_msg");
|
|
|
|
va_start(args, fmt);
|
|
dynstr_append(&ds_warning_messages, "mysqltest: ");
|
|
if (start_lineno != 0)
|
|
{
|
|
dynstr_append(&ds_warning_messages, "Warning detected ");
|
|
if (cur_file && cur_file != file_stack)
|
|
{
|
|
len= my_snprintf(buff, sizeof(buff), "in included file %s ",
|
|
cur_file->file_name);
|
|
dynstr_append_mem(&ds_warning_messages,
|
|
buff, len);
|
|
}
|
|
len= my_snprintf(buff, sizeof(buff), "at line %d: ",
|
|
start_lineno);
|
|
dynstr_append_mem(&ds_warning_messages,
|
|
buff, len);
|
|
}
|
|
#ifndef __WIN__
|
|
len= vsnprintf(buff, sizeof(buff), fmt, args);
|
|
dynstr_append_mem(&ds_warning_messages, buff, len);
|
|
#endif
|
|
dynstr_append(&ds_warning_messages, "\n");
|
|
va_end(args);
|
|
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
/*
|
|
Compare content of the string ds to content of file fname
|
|
*/
|
|
|
|
int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname)
|
|
{
|
|
MY_STAT stat_info;
|
|
char *tmp, *res_ptr;
|
|
char eval_file[FN_REFLEN];
|
|
int res;
|
|
uint res_len;
|
|
int fd;
|
|
DYNAMIC_STRING res_ds;
|
|
DBUG_ENTER("dyn_string_cmp");
|
|
|
|
if (!test_if_hard_path(fname))
|
|
{
|
|
strxmov(eval_file, opt_basedir, fname, NullS);
|
|
fn_format(eval_file, eval_file, "", "", MY_UNPACK_FILENAME);
|
|
}
|
|
else
|
|
fn_format(eval_file, fname, "", "", MY_UNPACK_FILENAME);
|
|
|
|
if (!my_stat(eval_file, &stat_info, MYF(MY_WME)))
|
|
die(NullS);
|
|
if (!eval_result && (uint) stat_info.st_size != ds->length)
|
|
{
|
|
DBUG_PRINT("info",("Size differs: result size: %u file size: %lu",
|
|
ds->length, (ulong) stat_info.st_size));
|
|
DBUG_PRINT("info",("result: '%s'", ds->str));
|
|
DBUG_RETURN(RESULT_LENGTH_MISMATCH);
|
|
}
|
|
if (!(tmp = (char*) my_malloc(stat_info.st_size + 1, MYF(MY_WME))))
|
|
die("Out of memory");
|
|
|
|
if ((fd = my_open(eval_file, O_RDONLY, MYF(MY_WME))) < 0)
|
|
die("Failed to open file %s", eval_file);
|
|
if (my_read(fd, (byte*)tmp, stat_info.st_size, MYF(MY_WME|MY_NABP)))
|
|
die("Failed to read from file %s, errno: %d", eval_file, errno);
|
|
tmp[stat_info.st_size] = 0;
|
|
init_dynamic_string(&res_ds, "", stat_info.st_size+256, 256);
|
|
if (eval_result)
|
|
{
|
|
do_eval(&res_ds, tmp, tmp + stat_info.st_size, FALSE);
|
|
res_ptr= res_ds.str;
|
|
res_len= res_ds.length;
|
|
if (res_len != ds->length)
|
|
{
|
|
res= RESULT_LENGTH_MISMATCH;
|
|
goto err;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
res_ptr = tmp;
|
|
res_len = stat_info.st_size;
|
|
}
|
|
|
|
res= (memcmp(res_ptr, ds->str, res_len)) ?
|
|
RESULT_CONTENT_MISMATCH : RESULT_OK;
|
|
|
|
err:
|
|
if (res && eval_result)
|
|
str_to_file(fn_format(eval_file, fname, "", ".eval",
|
|
MY_REPLACE_EXT),
|
|
res_ptr, res_len);
|
|
|
|
dynstr_free(&res_ds);
|
|
my_free((gptr) tmp, MYF(0));
|
|
my_close(fd, MYF(MY_WME));
|
|
|
|
DBUG_RETURN(res);
|
|
}
|
|
|
|
|
|
/*
|
|
Check the content of ds against result file
|
|
|
|
SYNOPSIS
|
|
check_result
|
|
ds - content to be checked
|
|
|
|
RETURN VALUES
|
|
error - the function will not return
|
|
|
|
*/
|
|
|
|
void check_result(DYNAMIC_STRING* ds)
|
|
{
|
|
DBUG_ENTER("check_result");
|
|
DBUG_ASSERT(result_file_name);
|
|
|
|
switch (dyn_string_cmp(ds, result_file_name))
|
|
{
|
|
case RESULT_OK:
|
|
break; /* ok */
|
|
case RESULT_LENGTH_MISMATCH:
|
|
dump_result_to_reject_file(ds->str, ds->length);
|
|
die("Result length mismatch");
|
|
break;
|
|
case RESULT_CONTENT_MISMATCH:
|
|
dump_result_to_reject_file(ds->str, ds->length);
|
|
die("Result content mismatch");
|
|
break;
|
|
default: /* impossible */
|
|
die("Unknown error code from dyn_string_cmp()");
|
|
}
|
|
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
/*
|
|
Check the content of ds against a require file
|
|
If match fails, abort the test with special error code
|
|
indicating that test is not supported
|
|
|
|
SYNOPSIS
|
|
check_result
|
|
ds - content to be checked
|
|
fname - name of file to check against
|
|
|
|
RETURN VALUES
|
|
error - the function will not return
|
|
|
|
*/
|
|
|
|
void check_require(DYNAMIC_STRING* ds, const char *fname)
|
|
{
|
|
DBUG_ENTER("check_require");
|
|
|
|
if (dyn_string_cmp(ds, fname))
|
|
{
|
|
char reason[FN_REFLEN];
|
|
fn_format(reason, fname, "", "", MY_REPLACE_EXT | MY_REPLACE_DIR);
|
|
abort_not_supported_test("Test requires: '%s'", reason);
|
|
}
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
static byte *get_var_key(const byte* var, uint* len,
|
|
my_bool __attribute__((unused)) t)
|
|
{
|
|
register char* key;
|
|
key = ((VAR*)var)->name;
|
|
*len = ((VAR*)var)->name_len;
|
|
return (byte*)key;
|
|
}
|
|
|
|
|
|
VAR *var_init(VAR *v, const char *name, int name_len, const char *val,
|
|
int val_len)
|
|
{
|
|
int val_alloc_len;
|
|
VAR *tmp_var;
|
|
if (!name_len && name)
|
|
name_len = strlen(name);
|
|
if (!val_len && val)
|
|
val_len = strlen(val) ;
|
|
val_alloc_len = val_len + 16; /* room to grow */
|
|
if (!(tmp_var=v) && !(tmp_var = (VAR*)my_malloc(sizeof(*tmp_var)
|
|
+ name_len+1, MYF(MY_WME))))
|
|
die("Out of memory");
|
|
|
|
tmp_var->name = (name) ? (char*) tmp_var + sizeof(*tmp_var) : 0;
|
|
tmp_var->alloced = (v == 0);
|
|
|
|
if (!(tmp_var->str_val = my_malloc(val_alloc_len+1, MYF(MY_WME))))
|
|
die("Out of memory");
|
|
|
|
memcpy(tmp_var->name, name, name_len);
|
|
if (val)
|
|
{
|
|
memcpy(tmp_var->str_val, val, val_len);
|
|
tmp_var->str_val[val_len]= 0;
|
|
}
|
|
tmp_var->name_len = name_len;
|
|
tmp_var->str_val_len = val_len;
|
|
tmp_var->alloced_len = val_alloc_len;
|
|
tmp_var->int_val = (val) ? atoi(val) : 0;
|
|
tmp_var->int_dirty = 0;
|
|
tmp_var->env_s = 0;
|
|
return tmp_var;
|
|
}
|
|
|
|
|
|
void var_free(void *v)
|
|
{
|
|
my_free(((VAR*) v)->str_val, MYF(MY_WME));
|
|
if (((VAR*)v)->alloced)
|
|
my_free((char*) v, MYF(MY_WME));
|
|
}
|
|
|
|
|
|
VAR* var_from_env(const char *name, const char *def_val)
|
|
{
|
|
const char *tmp;
|
|
VAR *v;
|
|
if (!(tmp = getenv(name)))
|
|
tmp = def_val;
|
|
|
|
v = var_init(0, name, strlen(name), tmp, strlen(tmp));
|
|
my_hash_insert(&var_hash, (byte*)v);
|
|
return v;
|
|
}
|
|
|
|
|
|
VAR* var_get(const char *var_name, const char **var_name_end, my_bool raw,
|
|
my_bool ignore_not_existing)
|
|
{
|
|
int digit;
|
|
VAR *v;
|
|
DBUG_ENTER("var_get");
|
|
DBUG_PRINT("enter", ("var_name: %s",var_name));
|
|
|
|
if (*var_name != '$')
|
|
goto err;
|
|
digit = *++var_name - '0';
|
|
if (digit < 0 || digit >= 10)
|
|
{
|
|
const char *save_var_name = var_name, *end;
|
|
uint length;
|
|
end = (var_name_end) ? *var_name_end : 0;
|
|
while (my_isvar(charset_info,*var_name) && var_name != end)
|
|
var_name++;
|
|
if (var_name == save_var_name)
|
|
{
|
|
if (ignore_not_existing)
|
|
DBUG_RETURN(0);
|
|
die("Empty variable");
|
|
}
|
|
length= (uint) (var_name - save_var_name);
|
|
if (length >= MAX_VAR_NAME_LENGTH)
|
|
die("Too long variable name: %s", save_var_name);
|
|
|
|
if (!(v = (VAR*) hash_search(&var_hash, save_var_name, length)))
|
|
{
|
|
char buff[MAX_VAR_NAME_LENGTH+1];
|
|
strmake(buff, save_var_name, length);
|
|
v= var_from_env(buff, "");
|
|
}
|
|
var_name--; /* Point at last character */
|
|
}
|
|
else
|
|
v = var_reg + digit;
|
|
|
|
if (!raw && v->int_dirty)
|
|
{
|
|
sprintf(v->str_val, "%d", v->int_val);
|
|
v->int_dirty = 0;
|
|
v->str_val_len = strlen(v->str_val);
|
|
}
|
|
if (var_name_end)
|
|
*var_name_end = var_name ;
|
|
DBUG_RETURN(v);
|
|
err:
|
|
if (var_name_end)
|
|
*var_name_end = 0;
|
|
die("Unsupported variable name: %s", var_name);
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
VAR *var_obtain(const char *name, int len)
|
|
{
|
|
VAR* v;
|
|
if ((v = (VAR*)hash_search(&var_hash, name, len)))
|
|
return v;
|
|
v = var_init(0, name, len, "", 0);
|
|
my_hash_insert(&var_hash, (byte*)v);
|
|
return v;
|
|
}
|
|
|
|
|
|
/*
|
|
- if variable starts with a $ it is regarded as a local test varable
|
|
- if not it is treated as a environment variable, and the corresponding
|
|
environment variable will be updated
|
|
*/
|
|
|
|
void var_set(const char *var_name, const char *var_name_end,
|
|
const char *var_val, const char *var_val_end)
|
|
{
|
|
int digit, env_var= 0;
|
|
VAR *v;
|
|
DBUG_ENTER("var_set");
|
|
DBUG_PRINT("enter", ("var_name: '%.*s' = '%.*s' (length: %d)",
|
|
(int) (var_name_end - var_name), var_name,
|
|
(int) (var_val_end - var_val), var_val,
|
|
(int) (var_val_end - var_val)));
|
|
|
|
if (*var_name != '$')
|
|
env_var= 1;
|
|
else
|
|
var_name++;
|
|
|
|
digit= *var_name - '0';
|
|
if (!(digit < 10 && digit >= 0))
|
|
{
|
|
v= var_obtain(var_name, (uint) (var_name_end - var_name));
|
|
}
|
|
else
|
|
v= var_reg + digit;
|
|
|
|
eval_expr(v, var_val, (const char**) &var_val_end);
|
|
|
|
if (env_var)
|
|
{
|
|
char buf[1024], *old_env_s= v->env_s;
|
|
if (v->int_dirty)
|
|
{
|
|
sprintf(v->str_val, "%d", v->int_val);
|
|
v->int_dirty= 0;
|
|
v->str_val_len= strlen(v->str_val);
|
|
}
|
|
strxmov(buf, v->name, "=", v->str_val, NullS);
|
|
if (!(v->env_s= my_strdup(buf, MYF(MY_WME))))
|
|
die("Out of memory");
|
|
putenv(v->env_s);
|
|
my_free((gptr)old_env_s, MYF(MY_ALLOW_ZERO_PTR));
|
|
}
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
/*
|
|
Store an integer (typically the returncode of the last SQL)
|
|
statement in the mysqltest builtin variable $mysql_errno, by
|
|
simulating of a user statement "let $mysql_errno= <integer>"
|
|
*/
|
|
|
|
void var_set_errno(int sql_errno)
|
|
{
|
|
/* TODO MASV make easier */
|
|
const char *var_name= "$mysql_errno";
|
|
char var_val[21];
|
|
uint length= my_sprintf(var_val, (var_val, "%d", sql_errno));
|
|
var_set(var_name, var_name + 12, var_val, var_val + length);
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
Set variable from the result of a query
|
|
|
|
SYNOPSIS
|
|
var_query_set()
|
|
var variable to set from query
|
|
query start of query string to execute
|
|
query_end end of the query string to execute
|
|
|
|
|
|
DESCRIPTION
|
|
let @<var_name> = `<query>`
|
|
|
|
Execute the query and assign the first row of result to var as
|
|
a tab separated strings
|
|
|
|
Also assign each column of the result set to
|
|
variable "$<var_name>_<column_name>"
|
|
Thus the tab separated output can be read from $<var_name> and
|
|
and each individual column can be read as $<var_name>_<col_name>
|
|
|
|
*/
|
|
|
|
void var_query_set(VAR *var, const char *query, const char** query_end)
|
|
{
|
|
char* end = (char*)((query_end && *query_end) ?
|
|
*query_end : query + strlen(query));
|
|
MYSQL_RES *res;
|
|
MYSQL_ROW row;
|
|
MYSQL* mysql = &cur_con->mysql;
|
|
DBUG_ENTER("var_query_set");
|
|
LINT_INIT(res);
|
|
|
|
while (end > query && *end != '`')
|
|
--end;
|
|
if (query == end)
|
|
die("Syntax error in query, missing '`'");
|
|
++query;
|
|
|
|
if (mysql_real_query(mysql, query, (int)(end - query)) ||
|
|
!(res = mysql_store_result(mysql)))
|
|
{
|
|
*end = 0;
|
|
die("Error running query '%s': %d %s", query,
|
|
mysql_errno(mysql), mysql_error(mysql));
|
|
}
|
|
|
|
if ((row = mysql_fetch_row(res)) && row[0])
|
|
{
|
|
/*
|
|
Concatenate all row results with tab in between to allow us to work
|
|
with results from many columns (for example from SHOW VARIABLES)
|
|
*/
|
|
DYNAMIC_STRING result;
|
|
uint i;
|
|
ulong *lengths;
|
|
char *end;
|
|
#ifdef NOT_YET
|
|
MYSQL_FIELD *fields= mysql_fetch_fields(res);
|
|
#endif
|
|
|
|
init_dynamic_string(&result, "", 2048, 2048);
|
|
lengths= mysql_fetch_lengths(res);
|
|
for (i=0; i < mysql_num_fields(res); i++)
|
|
{
|
|
if (row[0])
|
|
{
|
|
#ifdef NOT_YET
|
|
/* Add to <var_name>_<col_name> */
|
|
uint j;
|
|
char var_col_name[MAX_VAR_NAME_LENGTH];
|
|
uint length= snprintf(var_col_name, MAX_VAR_NAME_LENGTH,
|
|
"$%s_%s", var->name, fields[i].name);
|
|
/* Convert characters not allowed in variable names to '_' */
|
|
for (j= 1; j < length; j++)
|
|
{
|
|
if (!my_isvar(charset_info,var_col_name[j]))
|
|
var_col_name[j]= '_';
|
|
}
|
|
var_set(var_col_name, var_col_name + length,
|
|
row[i], row[i] + lengths[i]);
|
|
#endif
|
|
/* Add column to tab separated string */
|
|
dynstr_append_mem(&result, row[i], lengths[i]);
|
|
}
|
|
dynstr_append_mem(&result, "\t", 1);
|
|
}
|
|
end= result.str + result.length-1;
|
|
eval_expr(var, result.str, (const char**) &end);
|
|
dynstr_free(&result);
|
|
}
|
|
else
|
|
eval_expr(var, "", 0);
|
|
|
|
mysql_free_result(res);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
void var_copy(VAR *dest, VAR *src)
|
|
{
|
|
dest->int_val= src->int_val;
|
|
dest->int_dirty= src->int_dirty;
|
|
|
|
/* Alloc/realloc data for str_val in dest */
|
|
if (dest->alloced_len < src->alloced_len &&
|
|
!(dest->str_val= dest->str_val
|
|
? my_realloc(dest->str_val, src->alloced_len, MYF(MY_WME))
|
|
: my_malloc(src->alloced_len, MYF(MY_WME))))
|
|
die("Out of memory");
|
|
else
|
|
dest->alloced_len= src->alloced_len;
|
|
|
|
/* Copy str_val data to dest */
|
|
dest->str_val_len= src->str_val_len;
|
|
if (src->str_val_len)
|
|
memcpy(dest->str_val, src->str_val, src->str_val_len);
|
|
}
|
|
|
|
|
|
void eval_expr(VAR *v, const char *p, const char **p_end)
|
|
{
|
|
static int MIN_VAR_ALLOC= 32; /* MASV why 32? */
|
|
VAR *vp;
|
|
if (*p == '$')
|
|
{
|
|
if ((vp= var_get(p, p_end, 0, 0)))
|
|
{
|
|
var_copy(v, vp);
|
|
return;
|
|
}
|
|
}
|
|
else if (*p == '`')
|
|
{
|
|
var_query_set(v, p, p_end);
|
|
}
|
|
else
|
|
{
|
|
int new_val_len = (p_end && *p_end) ?
|
|
(int) (*p_end - p) : (int) strlen(p);
|
|
if (new_val_len + 1 >= v->alloced_len)
|
|
{
|
|
v->alloced_len = (new_val_len < MIN_VAR_ALLOC - 1) ?
|
|
MIN_VAR_ALLOC : new_val_len + 1;
|
|
if (!(v->str_val =
|
|
v->str_val ? my_realloc(v->str_val, v->alloced_len+1,
|
|
MYF(MY_WME)) :
|
|
my_malloc(v->alloced_len+1, MYF(MY_WME))))
|
|
die("Out of memory");
|
|
}
|
|
v->str_val_len = new_val_len;
|
|
memcpy(v->str_val, p, new_val_len);
|
|
v->str_val[new_val_len] = 0;
|
|
v->int_val=atoi(p);
|
|
v->int_dirty=0;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
int open_file(const char *name)
|
|
{
|
|
char buff[FN_REFLEN];
|
|
DBUG_ENTER("open_file");
|
|
DBUG_PRINT("enter", ("name: %s", name));
|
|
if (!test_if_hard_path(name))
|
|
{
|
|
strxmov(buff, opt_basedir, name, NullS);
|
|
name=buff;
|
|
}
|
|
fn_format(buff, name, "", "", MY_UNPACK_FILENAME);
|
|
|
|
if (cur_file == file_stack_end)
|
|
die("Source directives are nesting too deep");
|
|
cur_file++;
|
|
if (!(cur_file->file = my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(0))))
|
|
{
|
|
cur_file--;
|
|
die("Could not open file %s", buff);
|
|
}
|
|
cur_file->file_name= my_strdup(buff, MYF(MY_FAE));
|
|
cur_file->lineno=1;
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
/*
|
|
Source and execute the given file
|
|
|
|
SYNOPSIS
|
|
do_source()
|
|
query called command
|
|
|
|
DESCRIPTION
|
|
source <file_name>
|
|
|
|
Open the file <file_name> and execute it
|
|
|
|
*/
|
|
|
|
void do_source(struct st_command *command)
|
|
{
|
|
static DYNAMIC_STRING ds_filename;
|
|
const struct command_arg source_args[] = {
|
|
"filename", ARG_STRING, TRUE, &ds_filename, "File to source"
|
|
};
|
|
DBUG_ENTER("do_source");
|
|
|
|
check_command_args(command, command->first_argument, source_args,
|
|
sizeof(source_args)/sizeof(struct command_arg),
|
|
' ');
|
|
|
|
/*
|
|
If this file has already been sourced, don't source it again.
|
|
It's already available in the q_lines cache.
|
|
*/
|
|
if (parser.current_line < (parser.read_lines - 1))
|
|
; /* Do nothing */
|
|
else
|
|
{
|
|
DBUG_PRINT("info", ("sourcing file: %s", ds_filename.str));
|
|
open_file(ds_filename.str);
|
|
}
|
|
|
|
dynstr_free(&ds_filename);
|
|
return;
|
|
}
|
|
|
|
|
|
#ifdef __WIN__
|
|
/* Variables used for temporary sh files used for emulating Unix on Windows */
|
|
char tmp_sh_name[64], tmp_sh_cmd[70];
|
|
|
|
void init_tmp_sh_file()
|
|
{
|
|
/* Format a name for the tmp sh file that is unique for this process */
|
|
my_snprintf(tmp_sh_name, sizeof(tmp_sh_name), "tmp_%d.sh", getpid());
|
|
/* Format the command to execute in order to run the script */
|
|
my_snprintf(tmp_sh_cmd, sizeof(tmp_sh_cmd), "sh %s", tmp_sh_name);
|
|
}
|
|
|
|
|
|
void free_tmp_sh_file()
|
|
{
|
|
my_delete(tmp_sh_name, MYF(0));
|
|
}
|
|
#endif
|
|
|
|
|
|
FILE* my_popen(DYNAMIC_STRING *ds_cmd, const char *mode)
|
|
{
|
|
#ifdef __WIN__
|
|
/* Dump the command into a sh script file and execute with popen */
|
|
str_to_file(tmp_sh_name, ds_cmd->str, ds_cmd->length);
|
|
return popen(tmp_sh_cmd, mode);
|
|
#else
|
|
return popen(ds_cmd->str, mode);
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
Execute given command.
|
|
|
|
SYNOPSIS
|
|
do_exec()
|
|
query called command
|
|
|
|
DESCRIPTION
|
|
exec <command>
|
|
|
|
Execute the text between exec and end of line in a subprocess.
|
|
The error code returned from the subprocess is checked against the
|
|
expected error array, previously set with the --error command.
|
|
It can thus be used to execute a command that shall fail.
|
|
|
|
NOTE
|
|
Although mysqltest is executed from cygwin shell, the command will be
|
|
executed in "cmd.exe". Thus commands like "rm" etc can NOT be used, use
|
|
system for those commands.
|
|
*/
|
|
|
|
void do_exec(struct st_command *command)
|
|
{
|
|
int error;
|
|
char buf[1024];
|
|
FILE *res_file;
|
|
char *cmd= command->first_argument;
|
|
DYNAMIC_STRING ds_cmd;
|
|
DBUG_ENTER("do_exec");
|
|
DBUG_PRINT("enter", ("cmd: '%s'", cmd));
|
|
|
|
/* Skip leading space */
|
|
while (*cmd && my_isspace(charset_info, *cmd))
|
|
cmd++;
|
|
if (!*cmd)
|
|
die("Missing argument in exec");
|
|
command->last_argument= command->end;
|
|
|
|
init_dynamic_string(&ds_cmd, 0, command->query_len+256, 256);
|
|
/* Eval the command, thus replacing all environment variables */
|
|
do_eval(&ds_cmd, cmd, command->end, TRUE);
|
|
|
|
DBUG_PRINT("info", ("Executing '%s' as '%s'",
|
|
command->first_argument, ds_cmd.str));
|
|
|
|
if (!(res_file= my_popen(&ds_cmd, "r")) && command->abort_on_error)
|
|
die("popen(\"%s\", \"r\") failed", command->first_argument);
|
|
|
|
while (fgets(buf, sizeof(buf), res_file))
|
|
{
|
|
if (disable_result_log)
|
|
{
|
|
buf[strlen(buf)-1]=0;
|
|
DBUG_PRINT("exec_result",("%s", buf));
|
|
}
|
|
else
|
|
{
|
|
replace_dynstr_append(&ds_res, buf);
|
|
}
|
|
}
|
|
error= pclose(res_file);
|
|
if (error > 0)
|
|
{
|
|
uint status= WEXITSTATUS(error), i;
|
|
my_bool ok= 0;
|
|
|
|
if (command->abort_on_error)
|
|
die("command \"%s\" failed", command->first_argument);
|
|
|
|
DBUG_PRINT("info",
|
|
("error: %d, status: %d", error, status));
|
|
for (i= 0; i < command->expected_errors.count; i++)
|
|
{
|
|
DBUG_PRINT("info", ("expected error: %d",
|
|
command->expected_errors.err[i].code.errnum));
|
|
if ((command->expected_errors.err[i].type == ERR_ERRNO) &&
|
|
(command->expected_errors.err[i].code.errnum == status))
|
|
{
|
|
ok= 1;
|
|
DBUG_PRINT("info", ("command \"%s\" failed with expected error: %d",
|
|
command->first_argument, status));
|
|
}
|
|
}
|
|
if (!ok)
|
|
die("command \"%s\" failed with wrong error: %d",
|
|
command->first_argument, status);
|
|
}
|
|
else if (command->expected_errors.err[0].type == ERR_ERRNO &&
|
|
command->expected_errors.err[0].code.errnum != 0)
|
|
{
|
|
/* Error code we wanted was != 0, i.e. not an expected success */
|
|
die("command \"%s\" succeeded - should have failed with errno %d...",
|
|
command->first_argument, command->expected_errors.err[0].code.errnum);
|
|
}
|
|
|
|
dynstr_free(&ds_cmd);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
enum enum_operator
|
|
{
|
|
DO_DEC,
|
|
DO_INC
|
|
};
|
|
|
|
|
|
/*
|
|
Decrease or increase the value of a variable
|
|
|
|
SYNOPSIS
|
|
do_modify_var()
|
|
query called command
|
|
operator operation to perform on the var
|
|
|
|
DESCRIPTION
|
|
dec $var_name
|
|
inc $var_name
|
|
|
|
*/
|
|
|
|
int do_modify_var(struct st_command *command,
|
|
enum enum_operator operator)
|
|
{
|
|
const char *p= command->first_argument;
|
|
VAR* v;
|
|
if (!*p)
|
|
die("Missing argument to %.*s", command->first_word_len, command->query);
|
|
if (*p != '$')
|
|
die("The argument to %.*s must be a variable (start with $)",
|
|
command->first_word_len, command->query);
|
|
v= var_get(p, &p, 1, 0);
|
|
switch (operator) {
|
|
case DO_DEC:
|
|
v->int_val--;
|
|
break;
|
|
case DO_INC:
|
|
v->int_val++;
|
|
break;
|
|
default:
|
|
die("Invalid operator to do_modify_var");
|
|
break;
|
|
}
|
|
v->int_dirty= 1;
|
|
command->last_argument= (char*)++p;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
Wrapper for 'system' function
|
|
|
|
NOTE
|
|
If mysqltest is executed from cygwin shell, the command will be
|
|
executed in the "windows command interpreter" cmd.exe and we prepend "sh"
|
|
to make it be executed by cygwins "bash". Thus commands like "rm",
|
|
"mkdir" as well as shellscripts can executed by "system" in Windows.
|
|
|
|
*/
|
|
|
|
int my_system(DYNAMIC_STRING* ds_cmd)
|
|
{
|
|
#ifdef __WIN__
|
|
/* Dump the command into a sh script file and execute with system */
|
|
str_to_file(tmp_sh_name, ds_cmd->str, ds_cmd->length);
|
|
return system(tmp_sh_cmd);
|
|
#else
|
|
return system(ds_cmd->str);
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
SYNOPSIS
|
|
do_system
|
|
command called command
|
|
|
|
DESCRIPTION
|
|
system <command>
|
|
|
|
Eval the query to expand any $variables in the command.
|
|
Execute the command with the "system" command.
|
|
|
|
*/
|
|
|
|
void do_system(struct st_command *command)
|
|
{
|
|
DYNAMIC_STRING ds_cmd;
|
|
DBUG_ENTER("do_system");
|
|
|
|
if (strlen(command->first_argument) == 0)
|
|
die("Missing arguments to system, nothing to do!");
|
|
|
|
init_dynamic_string(&ds_cmd, 0, command->query_len + 64, 256);
|
|
|
|
/* Eval the system command, thus replacing all environment variables */
|
|
do_eval(&ds_cmd, command->first_argument, command->end, TRUE);
|
|
|
|
DBUG_PRINT("info", ("running system command '%s' as '%s'",
|
|
command->first_argument, ds_cmd.str));
|
|
if (my_system(&ds_cmd))
|
|
{
|
|
if (command->abort_on_error)
|
|
die("system command '%s' failed", command->first_argument);
|
|
|
|
/* If ! abort_on_error, log message and continue */
|
|
dynstr_append(&ds_res, "system command '");
|
|
replace_dynstr_append(&ds_res, command->first_argument);
|
|
dynstr_append(&ds_res, "' failed\n");
|
|
}
|
|
|
|
command->last_argument= command->end;
|
|
dynstr_free(&ds_cmd);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
/*
|
|
SYNOPSIS
|
|
do_remove_file
|
|
command called command
|
|
|
|
DESCRIPTION
|
|
remove_file <file_name>
|
|
Remove the file <file_name>
|
|
*/
|
|
|
|
void do_remove_file(struct st_command *command)
|
|
{
|
|
int error;
|
|
static DYNAMIC_STRING ds_filename;
|
|
const struct command_arg rm_args[] = {
|
|
"filename", ARG_STRING, TRUE, &ds_filename, "File to delete"
|
|
};
|
|
DBUG_ENTER("do_remove_file");
|
|
|
|
check_command_args(command, command->first_argument,
|
|
rm_args, sizeof(rm_args)/sizeof(struct command_arg),
|
|
' ');
|
|
|
|
DBUG_PRINT("info", ("removing file: %s", ds_filename.str));
|
|
error= my_delete(ds_filename.str, MYF(0)) != 0;
|
|
handle_command_error(command, error);
|
|
dynstr_free(&ds_filename);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
/*
|
|
SYNOPSIS
|
|
do_copy_file
|
|
command command handle
|
|
|
|
DESCRIPTION
|
|
copy_file <from_file> <to_file>
|
|
Copy <from_file> to <to_file>
|
|
|
|
NOTE! Will fail if <to_file> exists
|
|
*/
|
|
|
|
void do_copy_file(struct st_command *command)
|
|
{
|
|
int error;
|
|
static DYNAMIC_STRING ds_from_file;
|
|
static DYNAMIC_STRING ds_to_file;
|
|
const struct command_arg copy_file_args[] = {
|
|
"from_file", ARG_STRING, TRUE, &ds_from_file, "Filename to copy from",
|
|
"to_file", ARG_STRING, TRUE, &ds_to_file, "Filename to copy to"
|
|
};
|
|
DBUG_ENTER("do_copy_file");
|
|
|
|
check_command_args(command, command->first_argument,
|
|
copy_file_args,
|
|
sizeof(copy_file_args)/sizeof(struct command_arg),
|
|
' ');
|
|
|
|
DBUG_PRINT("info", ("Copy %s to %s", ds_from_file.str, ds_to_file.str));
|
|
error= (my_copy(ds_from_file.str, ds_to_file.str,
|
|
MYF(MY_DONT_OVERWRITE_FILE)) != 0);
|
|
handle_command_error(command, error);
|
|
dynstr_free(&ds_from_file);
|
|
dynstr_free(&ds_to_file);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
/*
|
|
SYNOPSIS
|
|
do_chmod_file
|
|
command command handle
|
|
|
|
DESCRIPTION
|
|
chmod <octal> <file>
|
|
Change file permission of <file>
|
|
|
|
*/
|
|
|
|
void do_chmod_file(struct st_command *command)
|
|
{
|
|
ulong mode= 0;
|
|
static DYNAMIC_STRING ds_mode;
|
|
static DYNAMIC_STRING ds_file;
|
|
const struct command_arg chmod_file_args[] = {
|
|
"mode", ARG_STRING, TRUE, &ds_mode, "Mode of file",
|
|
"file", ARG_STRING, TRUE, &ds_file, "Filename of file to modify"
|
|
};
|
|
DBUG_ENTER("do_chmod_file");
|
|
|
|
check_command_args(command, command->first_argument,
|
|
chmod_file_args,
|
|
sizeof(chmod_file_args)/sizeof(struct command_arg),
|
|
' ');
|
|
|
|
/* Parse what mode to set */
|
|
if (ds_mode.length != 4 ||
|
|
str2int(ds_mode.str, 8, 0, INT_MAX, &mode) == NullS)
|
|
die("You must write a 4 digit octal number for mode");
|
|
|
|
DBUG_PRINT("info", ("chmod %o %s", (uint)mode, ds_file.str));
|
|
handle_command_error(command, chmod(ds_file.str, mode));
|
|
dynstr_free(&ds_mode);
|
|
dynstr_free(&ds_file);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
/*
|
|
SYNOPSIS
|
|
do_file_exists
|
|
command called command
|
|
|
|
DESCRIPTION
|
|
fiile_exist <file_name>
|
|
Check if file <file_name> exists
|
|
*/
|
|
|
|
void do_file_exist(struct st_command *command)
|
|
{
|
|
int error;
|
|
static DYNAMIC_STRING ds_filename;
|
|
const struct command_arg file_exist_args[] = {
|
|
"filename", ARG_STRING, TRUE, &ds_filename, "File to check if it exist"
|
|
};
|
|
DBUG_ENTER("do_file_exist");
|
|
|
|
check_command_args(command, command->first_argument,
|
|
file_exist_args,
|
|
sizeof(file_exist_args)/sizeof(struct command_arg),
|
|
' ');
|
|
|
|
DBUG_PRINT("info", ("Checking for existence of file: %s", ds_filename.str));
|
|
error= (access(ds_filename.str, F_OK) != 0);
|
|
handle_command_error(command, error);
|
|
dynstr_free(&ds_filename);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
/*
|
|
Read characters from line buffer or file. This is needed to allow
|
|
my_ungetc() to buffer MAX_DELIMITER_LENGTH characters for a file
|
|
|
|
NOTE:
|
|
This works as long as one doesn't change files (with 'source file_name')
|
|
when there is things pushed into the buffer. This should however not
|
|
happen for any tests in the test suite.
|
|
*/
|
|
|
|
int my_getc(FILE *file)
|
|
{
|
|
if (line_buffer_pos == line_buffer)
|
|
return fgetc(file);
|
|
return *--line_buffer_pos;
|
|
}
|
|
|
|
|
|
void my_ungetc(int c)
|
|
{
|
|
*line_buffer_pos++= (char) c;
|
|
}
|
|
|
|
|
|
void read_until_delimiter(DYNAMIC_STRING *ds,
|
|
DYNAMIC_STRING *ds_delimiter)
|
|
{
|
|
char c;
|
|
DBUG_ENTER("read_until_delimiter");
|
|
DBUG_PRINT("enter", ("delimiter: %s, length: %d",
|
|
ds_delimiter->str, ds_delimiter->length));
|
|
|
|
if (ds_delimiter->length > MAX_DELIMITER_LENGTH)
|
|
die("Max delimiter length(%d) exceeded", MAX_DELIMITER_LENGTH);
|
|
|
|
/* Read from file until delimiter is found */
|
|
while (1)
|
|
{
|
|
c= my_getc(cur_file->file);
|
|
|
|
if (c == '\n')
|
|
cur_file->lineno++;
|
|
|
|
if (feof(cur_file->file))
|
|
die("End of file encountered before '%s' delimiter was found",
|
|
ds_delimiter->str);
|
|
|
|
if (match_delimiter(c, ds_delimiter->str, ds_delimiter->length))
|
|
{
|
|
DBUG_PRINT("exit", ("Found delimiter '%s'", ds_delimiter->str));
|
|
break;
|
|
}
|
|
dynstr_append_mem(ds, (const char*)&c, 1);
|
|
}
|
|
DBUG_PRINT("exit", ("ds: %s", ds->str));
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
/*
|
|
SYNOPSIS
|
|
do_write_file
|
|
command called command
|
|
|
|
DESCRIPTION
|
|
write_file <file_name> [<delimiter>];
|
|
<what to write line 1>
|
|
<...>
|
|
< what to write line n>
|
|
EOF
|
|
|
|
--write_file <file_name>;
|
|
<what to write line 1>
|
|
<...>
|
|
< what to write line n>
|
|
EOF
|
|
|
|
Write everything between the "write_file" command and 'delimiter'
|
|
to "file_name"
|
|
|
|
NOTE! Overwrites existing file
|
|
|
|
Default <delimiter> is EOF
|
|
|
|
*/
|
|
|
|
void do_write_file(struct st_command *command)
|
|
{
|
|
static DYNAMIC_STRING ds_content;
|
|
static DYNAMIC_STRING ds_filename;
|
|
static DYNAMIC_STRING ds_delimiter;
|
|
const struct command_arg write_file_args[] = {
|
|
"filename", ARG_STRING, TRUE, &ds_filename, "File to write to",
|
|
"delimiter", ARG_STRING, FALSE, &ds_delimiter, "Delimiter to read until"
|
|
};
|
|
DBUG_ENTER("do_write_file");
|
|
|
|
check_command_args(command,
|
|
command->first_argument,
|
|
write_file_args,
|
|
sizeof(write_file_args)/sizeof(struct command_arg),
|
|
' ');
|
|
|
|
/* If no delimiter was provided, use EOF */
|
|
if (ds_delimiter.length == 0)
|
|
dynstr_set(&ds_delimiter, "EOF");
|
|
|
|
init_dynamic_string(&ds_content, "", 1024, 1024);
|
|
read_until_delimiter(&ds_content, &ds_delimiter);
|
|
DBUG_PRINT("info", ("Writing to file: %s", ds_filename.str));
|
|
str_to_file(ds_filename.str, ds_content.str, ds_content.length);
|
|
dynstr_free(&ds_content);
|
|
dynstr_free(&ds_filename);
|
|
dynstr_free(&ds_delimiter);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
/*
|
|
SYNOPSIS
|
|
do_perl
|
|
command command handle
|
|
|
|
DESCRIPTION
|
|
perl [<delimiter>];
|
|
<perlscript line 1>
|
|
<...>
|
|
<perlscript line n>
|
|
EOF
|
|
|
|
Execute everything after "perl" until <delimiter> as perl.
|
|
Useful for doing more advanced things
|
|
but still being able to execute it on all platforms.
|
|
|
|
Default <delimiter> is EOF
|
|
*/
|
|
|
|
void do_perl(struct st_command *command)
|
|
{
|
|
int error;
|
|
char buf[FN_REFLEN];
|
|
FILE *res_file;
|
|
static DYNAMIC_STRING ds_script;
|
|
static DYNAMIC_STRING ds_delimiter;
|
|
const struct command_arg perl_args[] = {
|
|
"delimiter", ARG_STRING, FALSE, &ds_delimiter, "Delimiter to read until"
|
|
};
|
|
DBUG_ENTER("do_perl");
|
|
|
|
check_command_args(command,
|
|
command->first_argument,
|
|
perl_args,
|
|
sizeof(perl_args)/sizeof(struct command_arg),
|
|
' ');
|
|
|
|
/* If no delimiter was provided, use EOF */
|
|
if (ds_delimiter.length == 0)
|
|
dynstr_set(&ds_delimiter, "EOF");
|
|
|
|
init_dynamic_string(&ds_script, "", 1024, 1024);
|
|
read_until_delimiter(&ds_script, &ds_delimiter);
|
|
|
|
DBUG_PRINT("info", ("Executing perl: %s", ds_script.str));
|
|
|
|
/* Format a name for a tmp .pl file that is unique for this process */
|
|
my_snprintf(buf, sizeof(buf), "%s/tmp/tmp_%d.pl",
|
|
getenv("MYSQLTEST_VARDIR"), getpid());
|
|
str_to_file(buf, ds_script.str, ds_script.length);
|
|
|
|
/* Format the perl <filename> command */
|
|
my_snprintf(buf, sizeof(buf), "perl %s/tmp/tmp_%d.pl",
|
|
getenv("MYSQLTEST_VARDIR"), getpid());
|
|
|
|
if (!(res_file= popen(buf, "r")) && command->abort_on_error)
|
|
die("popen(\"%s\", \"r\") failed", buf);
|
|
|
|
while (fgets(buf, sizeof(buf), res_file))
|
|
{
|
|
if (disable_result_log)
|
|
{
|
|
buf[strlen(buf)-1]=0;
|
|
DBUG_PRINT("exec_result",("%s", buf));
|
|
}
|
|
else
|
|
{
|
|
replace_dynstr_append(&ds_res, buf);
|
|
}
|
|
}
|
|
error= pclose(res_file);
|
|
handle_command_error(command, WEXITSTATUS(error));
|
|
dynstr_free(&ds_script);
|
|
dynstr_free(&ds_delimiter);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
/*
|
|
Print the content between echo and <delimiter> to result file.
|
|
Evaluate all variables in the string before printing, allow
|
|
for variable names to be escaped using \
|
|
|
|
SYNOPSIS
|
|
do_echo()
|
|
command called command
|
|
|
|
DESCRIPTION
|
|
echo text
|
|
Print the text after echo until end of command to result file
|
|
|
|
echo $<var_name>
|
|
Print the content of the variable <var_name> to result file
|
|
|
|
echo Some text $<var_name>
|
|
Print "Some text" plus the content of the variable <var_name> to
|
|
result file
|
|
|
|
echo Some text \$<var_name>
|
|
Print "Some text" plus $<var_name> to result file
|
|
*/
|
|
|
|
int do_echo(struct st_command *command)
|
|
{
|
|
DYNAMIC_STRING ds_echo;
|
|
|
|
init_dynamic_string(&ds_echo, "", command->query_len, 256);
|
|
do_eval(&ds_echo, command->first_argument, command->end, FALSE);
|
|
dynstr_append_mem(&ds_res, ds_echo.str, ds_echo.length);
|
|
dynstr_append_mem(&ds_res, "\n", 1);
|
|
dynstr_free(&ds_echo);
|
|
command->last_argument= command->end;
|
|
return(0);
|
|
}
|
|
|
|
|
|
void do_wait_for_slave_to_stop(struct st_command *c __attribute__((unused)))
|
|
{
|
|
static int SLAVE_POLL_INTERVAL= 300000;
|
|
MYSQL* mysql = &cur_con->mysql;
|
|
for (;;)
|
|
{
|
|
MYSQL_RES *res;
|
|
MYSQL_ROW row;
|
|
int done;
|
|
LINT_INIT(res);
|
|
|
|
if (mysql_query(mysql,"show status like 'Slave_running'") ||
|
|
!(res=mysql_store_result(mysql)))
|
|
die("Query failed while probing slave for stop: %s",
|
|
mysql_error(mysql));
|
|
if (!(row=mysql_fetch_row(res)) || !row[1])
|
|
{
|
|
mysql_free_result(res);
|
|
die("Strange result from query while probing slave for stop");
|
|
}
|
|
done = !strcmp(row[1],"OFF");
|
|
mysql_free_result(res);
|
|
if (done)
|
|
break;
|
|
my_sleep(SLAVE_POLL_INTERVAL);
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
void do_sync_with_master2(long offset)
|
|
{
|
|
MYSQL_RES *res;
|
|
MYSQL_ROW row;
|
|
MYSQL *mysql= &cur_con->mysql;
|
|
char query_buf[FN_REFLEN+128];
|
|
int tries= 0;
|
|
int rpl_parse;
|
|
|
|
if (!master_pos.file[0])
|
|
die("Calling 'sync_with_master' without calling 'save_master_pos'");
|
|
rpl_parse= mysql_rpl_parse_enabled(mysql);
|
|
mysql_disable_rpl_parse(mysql);
|
|
|
|
sprintf(query_buf, "select master_pos_wait('%s', %ld)", master_pos.file,
|
|
master_pos.pos + offset);
|
|
|
|
wait_for_position:
|
|
|
|
if (mysql_query(mysql, query_buf))
|
|
die("failed in '%s': %d: %s", query_buf, mysql_errno(mysql),
|
|
mysql_error(mysql));
|
|
|
|
if (!(res= mysql_store_result(mysql)))
|
|
die("mysql_store_result() returned NULL for '%s'", query_buf);
|
|
if (!(row= mysql_fetch_row(res)))
|
|
die("empty result in %s", query_buf);
|
|
if (!row[0])
|
|
{
|
|
/*
|
|
It may be that the slave SQL thread has not started yet, though START
|
|
SLAVE has been issued ?
|
|
*/
|
|
if (tries++ == 30)
|
|
die("could not sync with master ('%s' returned NULL)", query_buf);
|
|
sleep(1); /* So at most we will wait 30 seconds and make 31 tries */
|
|
mysql_free_result(res);
|
|
goto wait_for_position;
|
|
}
|
|
mysql_free_result(res);
|
|
if (rpl_parse)
|
|
mysql_enable_rpl_parse(mysql);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void do_sync_with_master(struct st_command *command)
|
|
{
|
|
long offset= 0;
|
|
char *p= command->first_argument;
|
|
const char *offset_start= p;
|
|
if (*offset_start)
|
|
{
|
|
for (; my_isdigit(charset_info, *p); p++)
|
|
offset = offset * 10 + *p - '0';
|
|
|
|
if(*p && !my_isspace(charset_info, *p))
|
|
die("Invalid integer argument \"%s\"", offset_start);
|
|
command->last_argument= p;
|
|
}
|
|
do_sync_with_master2(offset);
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
when ndb binlog is on, this call will wait until last updated epoch
|
|
(locally in the mysqld) has been received into the binlog
|
|
*/
|
|
int do_save_master_pos()
|
|
{
|
|
MYSQL_RES *res;
|
|
MYSQL_ROW row;
|
|
MYSQL *mysql = &cur_con->mysql;
|
|
const char *query;
|
|
int rpl_parse;
|
|
|
|
rpl_parse = mysql_rpl_parse_enabled(mysql);
|
|
mysql_disable_rpl_parse(mysql);
|
|
|
|
#ifdef HAVE_NDB_BINLOG
|
|
/*
|
|
Wait for ndb binlog to be up-to-date with all changes
|
|
done on the local mysql server
|
|
*/
|
|
{
|
|
ulong have_ndbcluster;
|
|
if (mysql_query(mysql, query= "show variables like 'have_ndbcluster'"))
|
|
die("'%s' failed: %d %s", query,
|
|
mysql_errno(mysql), mysql_error(mysql));
|
|
if (!(res= mysql_store_result(mysql)))
|
|
die("mysql_store_result() returned NULL for '%s'", query);
|
|
if (!(row= mysql_fetch_row(res)))
|
|
die("Query '%s' returned empty result", query);
|
|
|
|
have_ndbcluster= strcmp("YES", row[1]) == 0;
|
|
mysql_free_result(res);
|
|
|
|
if (have_ndbcluster)
|
|
{
|
|
ulonglong start_epoch= 0, applied_epoch= 0,
|
|
latest_epoch=0, latest_trans_epoch=0,
|
|
latest_handled_binlog_epoch= 0, latest_received_binlog_epoch= 0,
|
|
latest_applied_binlog_epoch= 0;
|
|
int count= 0;
|
|
int do_continue= 1;
|
|
while (do_continue)
|
|
{
|
|
const char binlog[]= "binlog";
|
|
const char latest_epoch_str[]=
|
|
"latest_epoch=";
|
|
const char latest_trans_epoch_str[]=
|
|
"latest_trans_epoch=";
|
|
const char latest_received_binlog_epoch_str[]=
|
|
"latest_received_binlog_epoch";
|
|
const char latest_handled_binlog_epoch_str[]=
|
|
"latest_handled_binlog_epoch=";
|
|
const char latest_applied_binlog_epoch_str[]=
|
|
"latest_applied_binlog_epoch=";
|
|
if (count)
|
|
sleep(1);
|
|
if (mysql_query(mysql, query= "show engine ndb status"))
|
|
die("failed in '%s': %d %s", query,
|
|
mysql_errno(mysql), mysql_error(mysql));
|
|
if (!(res= mysql_store_result(mysql)))
|
|
die("mysql_store_result() returned NULL for '%s'", query);
|
|
while ((row= mysql_fetch_row(res)))
|
|
{
|
|
if (strcmp(row[1], binlog) == 0)
|
|
{
|
|
const char *status= row[2];
|
|
|
|
/* latest_epoch */
|
|
while (*status && strncmp(status, latest_epoch_str,
|
|
sizeof(latest_epoch_str)-1))
|
|
status++;
|
|
if (*status)
|
|
{
|
|
status+= sizeof(latest_epoch_str)-1;
|
|
latest_epoch= strtoull(status, (char**) 0, 10);
|
|
}
|
|
else
|
|
die("result does not contain '%s' in '%s'",
|
|
latest_epoch_str, query);
|
|
/* latest_trans_epoch */
|
|
while (*status && strncmp(status, latest_trans_epoch_str,
|
|
sizeof(latest_trans_epoch_str)-1))
|
|
status++;
|
|
if (*status)
|
|
{
|
|
status+= sizeof(latest_trans_epoch_str)-1;
|
|
latest_trans_epoch= strtoull(status, (char**) 0, 10);
|
|
}
|
|
else
|
|
die("result does not contain '%s' in '%s'",
|
|
latest_trans_epoch_str, query);
|
|
/* latest_received_binlog_epoch */
|
|
while (*status &&
|
|
strncmp(status, latest_received_binlog_epoch_str,
|
|
sizeof(latest_received_binlog_epoch_str)-1))
|
|
status++;
|
|
if (*status)
|
|
{
|
|
status+= sizeof(latest_received_binlog_epoch_str)-1;
|
|
latest_received_binlog_epoch= strtoull(status, (char**) 0, 10);
|
|
}
|
|
else
|
|
die("result does not contain '%s' in '%s'",
|
|
latest_received_binlog_epoch_str, query);
|
|
/* latest_handled_binlog */
|
|
while (*status &&
|
|
strncmp(status, latest_handled_binlog_epoch_str,
|
|
sizeof(latest_handled_binlog_epoch_str)-1))
|
|
status++;
|
|
if (*status)
|
|
{
|
|
status+= sizeof(latest_handled_binlog_epoch_str)-1;
|
|
latest_handled_binlog_epoch= strtoull(status, (char**) 0, 10);
|
|
}
|
|
else
|
|
die("result does not contain '%s' in '%s'",
|
|
latest_handled_binlog_epoch_str, query);
|
|
/* latest_applied_binlog_epoch */
|
|
while (*status &&
|
|
strncmp(status, latest_applied_binlog_epoch_str,
|
|
sizeof(latest_applied_binlog_epoch_str)-1))
|
|
status++;
|
|
if (*status)
|
|
{
|
|
status+= sizeof(latest_applied_binlog_epoch_str)-1;
|
|
latest_applied_binlog_epoch= strtoull(status, (char**) 0, 10);
|
|
}
|
|
else
|
|
die("result does not contain '%s' in '%s'",
|
|
latest_applied_binlog_epoch_str, query);
|
|
if (count == 0)
|
|
start_epoch= latest_trans_epoch;
|
|
break;
|
|
}
|
|
}
|
|
if (!row)
|
|
die("result does not contain '%s' in '%s'",
|
|
binlog, query);
|
|
if (latest_applied_binlog_epoch > applied_epoch)
|
|
count= 0;
|
|
applied_epoch= latest_applied_binlog_epoch;
|
|
count++;
|
|
if (latest_handled_binlog_epoch >= start_epoch)
|
|
do_continue= 0;
|
|
else if (count > 30)
|
|
{
|
|
break;
|
|
}
|
|
mysql_free_result(res);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
if (mysql_query(mysql, query= "show master status"))
|
|
die("failed in 'show master status': %d %s",
|
|
mysql_errno(mysql), mysql_error(mysql));
|
|
|
|
if (!(res = mysql_store_result(mysql)))
|
|
die("mysql_store_result() retuned NULL for '%s'", query);
|
|
if (!(row = mysql_fetch_row(res)))
|
|
die("empty result in show master status");
|
|
strnmov(master_pos.file, row[0], sizeof(master_pos.file)-1);
|
|
master_pos.pos = strtoul(row[1], (char**) 0, 10);
|
|
mysql_free_result(res);
|
|
|
|
if (rpl_parse)
|
|
mysql_enable_rpl_parse(mysql);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
Assign the variable <var_name> with <var_val>
|
|
|
|
SYNOPSIS
|
|
do_let()
|
|
query called command
|
|
|
|
DESCRIPTION
|
|
let $<var_name>=<var_val><delimiter>
|
|
|
|
<var_name> - is the string string found between the $ and =
|
|
<var_val> - is the content between the = and <delimiter>, it may span
|
|
multiple line and contain any characters except <delimiter>
|
|
<delimiter> - is a string containing of one or more chars, default is ;
|
|
|
|
RETURN VALUES
|
|
Program will die if error detected
|
|
*/
|
|
|
|
void do_let(struct st_command *command)
|
|
{
|
|
char *p= command->first_argument;
|
|
char *var_name, *var_name_end;
|
|
DYNAMIC_STRING let_rhs_expr;
|
|
|
|
DBUG_ENTER("do_let");
|
|
|
|
init_dynamic_string(&let_rhs_expr, "", 512, 2048);
|
|
|
|
/* Find <var_name> */
|
|
if (!*p)
|
|
die("Missing arguments to let");
|
|
var_name= p;
|
|
while (*p && (*p != '=') && !my_isspace(charset_info,*p))
|
|
p++;
|
|
var_name_end= p;
|
|
if (var_name == var_name_end ||
|
|
(var_name+1 == var_name_end && *var_name == '$'))
|
|
die("Missing variable name in let");
|
|
while (my_isspace(charset_info,*p))
|
|
p++;
|
|
if (*p++ != '=')
|
|
die("Missing assignment operator in let");
|
|
|
|
/* Find start of <var_val> */
|
|
while (*p && my_isspace(charset_info,*p))
|
|
p++;
|
|
|
|
do_eval(&let_rhs_expr, p, command->end, FALSE);
|
|
|
|
command->last_argument= command->end;
|
|
/* Assign var_val to var_name */
|
|
var_set(var_name, var_name_end, let_rhs_expr.str,
|
|
(let_rhs_expr.str + let_rhs_expr.length));
|
|
dynstr_free(&let_rhs_expr);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
int do_rpl_probe(struct st_command *command __attribute__((unused)))
|
|
{
|
|
DBUG_ENTER("do_rpl_probe");
|
|
if (mysql_rpl_probe(&cur_con->mysql))
|
|
die("Failed in mysql_rpl_probe(): '%s'", mysql_error(&cur_con->mysql));
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
int do_enable_rpl_parse(struct st_command *command __attribute__((unused)))
|
|
{
|
|
mysql_enable_rpl_parse(&cur_con->mysql);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int do_disable_rpl_parse(struct st_command *command __attribute__((unused)))
|
|
{
|
|
mysql_disable_rpl_parse(&cur_con->mysql);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
Sleep the number of specified seconds
|
|
|
|
SYNOPSIS
|
|
do_sleep()
|
|
q called command
|
|
real_sleep use the value from opt_sleep as number of seconds to sleep
|
|
if real_sleep is false
|
|
|
|
DESCRIPTION
|
|
sleep <seconds>
|
|
real_sleep <seconds>
|
|
|
|
The difference between the sleep and real_sleep commands is that sleep
|
|
uses the delay from the --sleep command-line option if there is one.
|
|
(If the --sleep option is not given, the sleep command uses the delay
|
|
specified by its argument.) The real_sleep command always uses the
|
|
delay specified by its argument. The logic is that sometimes delays are
|
|
cpu-dependent, and --sleep can be used to set this delay. real_sleep is
|
|
used for cpu-independent delays.
|
|
*/
|
|
|
|
int do_sleep(struct st_command *command, my_bool real_sleep)
|
|
{
|
|
int error= 0;
|
|
char *p= command->first_argument;
|
|
char *sleep_start, *sleep_end= command->end;
|
|
double sleep_val;
|
|
|
|
while (my_isspace(charset_info, *p))
|
|
p++;
|
|
if (!*p)
|
|
die("Missing argument to %.*s", command->first_word_len, command->query);
|
|
sleep_start= p;
|
|
/* Check that arg starts with a digit, not handled by my_strtod */
|
|
if (!my_isdigit(charset_info, *sleep_start))
|
|
die("Invalid argument to %.*s \"%s\"", command->first_word_len,
|
|
command->query,command->first_argument);
|
|
sleep_val= my_strtod(sleep_start, &sleep_end, &error);
|
|
if (error)
|
|
die("Invalid argument to %.*s \"%s\"", command->first_word_len,
|
|
command->query, command->first_argument);
|
|
|
|
/* Fixed sleep time selected by --sleep option */
|
|
if (opt_sleep >= 0 && !real_sleep)
|
|
sleep_val= opt_sleep;
|
|
|
|
DBUG_PRINT("info", ("sleep_val: %f", sleep_val));
|
|
if (sleep_val)
|
|
my_sleep((ulong) (sleep_val * 1000000L));
|
|
command->last_argument= sleep_end;
|
|
return 0;
|
|
}
|
|
|
|
|
|
void do_get_file_name(struct st_command *command,
|
|
char* dest, uint dest_max_len)
|
|
{
|
|
char *p= command->first_argument, *name;
|
|
if (!*p)
|
|
die("Missing file name argument");
|
|
name= p;
|
|
while (*p && !my_isspace(charset_info,*p))
|
|
p++;
|
|
if (*p)
|
|
*p++= 0;
|
|
command->last_argument= p;
|
|
strmake(dest, name, dest_max_len);
|
|
}
|
|
|
|
|
|
void do_set_charset(struct st_command *command)
|
|
{
|
|
char *charset_name= command->first_argument;
|
|
char *p;
|
|
|
|
if (!charset_name || !*charset_name)
|
|
die("Missing charset name in 'character_set'");
|
|
/* Remove end space */
|
|
p= charset_name;
|
|
while (*p && !my_isspace(charset_info,*p))
|
|
p++;
|
|
if(*p)
|
|
*p++= 0;
|
|
command->last_argument= p;
|
|
charset_info= get_charset_by_csname(charset_name,MY_CS_PRIMARY,MYF(MY_WME));
|
|
if (!charset_info)
|
|
abort_not_supported_test("Test requires charset '%s'", charset_name);
|
|
}
|
|
|
|
|
|
#if MYSQL_VERSION_ID >= 50000
|
|
/* List of error names to error codes, available from 5.0 */
|
|
typedef struct
|
|
{
|
|
const char *name;
|
|
uint code;
|
|
} st_error;
|
|
|
|
static st_error global_error_names[] =
|
|
{
|
|
#include <mysqld_ername.h>
|
|
{ 0, 0 }
|
|
};
|
|
|
|
uint get_errcode_from_name(char *error_name, char *error_end)
|
|
{
|
|
/* SQL error as string */
|
|
st_error *e= global_error_names;
|
|
|
|
DBUG_ENTER("get_errcode_from_name");
|
|
DBUG_PRINT("enter", ("error_name: %s", error_name));
|
|
|
|
/* Loop through the array of known error names */
|
|
for (; e->name; e++)
|
|
{
|
|
/*
|
|
If we get a match, we need to check the length of the name we
|
|
matched against in case it was longer than what we are checking
|
|
(as in ER_WRONG_VALUE vs. ER_WRONG_VALUE_COUNT).
|
|
*/
|
|
if (!strncmp(error_name, e->name, (int) (error_end - error_name)) &&
|
|
(uint) strlen(e->name) == (uint) (error_end - error_name))
|
|
{
|
|
DBUG_RETURN(e->code);
|
|
}
|
|
}
|
|
if (!e->name)
|
|
die("Unknown SQL error name '%s'", error_name);
|
|
DBUG_RETURN(0);
|
|
}
|
|
#else
|
|
uint get_errcode_from_name(char *error_name __attribute__((unused)),
|
|
char *error_end __attribute__((unused)))
|
|
{
|
|
abort_not_in_this_version();
|
|
return 0; /* Never reached */
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
void do_get_errcodes(struct st_command *command)
|
|
{
|
|
struct st_match_err *to= saved_expected_errors.err;
|
|
char *p= command->first_argument;
|
|
uint count= 0;
|
|
|
|
DBUG_ENTER("do_get_errcodes");
|
|
|
|
if (!*p)
|
|
die("Missing argument(s) to 'error'");
|
|
|
|
do
|
|
{
|
|
char *end;
|
|
|
|
/* Skip leading spaces */
|
|
while (*p && *p == ' ')
|
|
p++;
|
|
|
|
/* Find end */
|
|
end= p;
|
|
while (*end && *end != ',' && *end != ' ')
|
|
end++;
|
|
|
|
if (*p == 'S')
|
|
{
|
|
char *to_ptr= to->code.sqlstate;
|
|
|
|
/*
|
|
SQLSTATE string
|
|
- Must be SQLSTATE_LENGTH long
|
|
- May contain only digits[0-9] and _uppercase_ letters
|
|
*/
|
|
p++; /* Step past the S */
|
|
if ((end - p) != SQLSTATE_LENGTH)
|
|
die("The sqlstate must be exactly %d chars long", SQLSTATE_LENGTH);
|
|
|
|
/* Check sqlstate string validity */
|
|
while (*p && p < end)
|
|
{
|
|
if (my_isdigit(charset_info, *p) || my_isupper(charset_info, *p))
|
|
*to_ptr++= *p++;
|
|
else
|
|
die("The sqlstate may only consist of digits[0-9] " \
|
|
"and _uppercase_ letters");
|
|
}
|
|
|
|
*to_ptr= 0;
|
|
to->type= ERR_SQLSTATE;
|
|
DBUG_PRINT("info", ("ERR_SQLSTATE: %s", to->code.sqlstate));
|
|
}
|
|
else if (*p == 's')
|
|
{
|
|
die("The sqlstate definition must start with an uppercase S");
|
|
}
|
|
else if (*p == 'E')
|
|
{
|
|
/* Error name string */
|
|
|
|
DBUG_PRINT("info", ("Error name: %s", p));
|
|
to->code.errnum= get_errcode_from_name(p, end);
|
|
to->type= ERR_ERRNO;
|
|
DBUG_PRINT("info", ("ERR_ERRNO: %d", to->code.errnum));
|
|
}
|
|
else if (*p == 'e')
|
|
{
|
|
die("The error name definition must start with an uppercase E");
|
|
}
|
|
else
|
|
{
|
|
long val;
|
|
char *start= p;
|
|
/* Check that the string passed to str2int only contain digits */
|
|
while (*p && p != end)
|
|
{
|
|
if (!my_isdigit(charset_info, *p))
|
|
die("Invalid argument to error: '%s' - "\
|
|
"the errno may only consist of digits[0-9]",
|
|
command->first_argument);
|
|
p++;
|
|
}
|
|
|
|
/* Convert the sting to int */
|
|
if (!str2int(start, 10, (long) INT_MIN, (long) INT_MAX, &val))
|
|
die("Invalid argument to error: '%s'", command->first_argument);
|
|
|
|
to->code.errnum= (uint) val;
|
|
to->type= ERR_ERRNO;
|
|
DBUG_PRINT("info", ("ERR_ERRNO: %d", to->code.errnum));
|
|
}
|
|
to++;
|
|
count++;
|
|
|
|
if (count >= (sizeof(saved_expected_errors.err) /
|
|
sizeof(struct st_match_err)))
|
|
die("Too many errorcodes specified");
|
|
|
|
/* Set pointer to the end of the last error code */
|
|
p= end;
|
|
|
|
/* Find next ',' */
|
|
while (*p && *p != ',')
|
|
p++;
|
|
|
|
if (*p)
|
|
p++; /* Step past ',' */
|
|
|
|
} while (*p);
|
|
|
|
command->last_argument= p;
|
|
to->type= ERR_EMPTY; /* End of data */
|
|
|
|
DBUG_PRINT("info", ("Expected errors: %d", count));
|
|
saved_expected_errors.count= count;
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
/*
|
|
Get a string; Return ptr to end of string
|
|
Strings may be surrounded by " or '
|
|
|
|
If string is a '$variable', return the value of the variable.
|
|
*/
|
|
|
|
char *get_string(char **to_ptr, char **from_ptr,
|
|
struct st_command *command)
|
|
{
|
|
char c, sep;
|
|
char *to= *to_ptr, *from= *from_ptr, *start=to;
|
|
DBUG_ENTER("get_string");
|
|
|
|
/* Find separator */
|
|
if (*from == '"' || *from == '\'')
|
|
sep= *from++;
|
|
else
|
|
sep=' '; /* Separated with space */
|
|
|
|
for ( ; (c=*from) ; from++)
|
|
{
|
|
if (c == '\\' && from[1])
|
|
{ /* Escaped character */
|
|
/* We can't translate \0 -> ASCII 0 as replace can't handle ASCII 0 */
|
|
switch (*++from) {
|
|
case 'n':
|
|
*to++= '\n';
|
|
break;
|
|
case 't':
|
|
*to++= '\t';
|
|
break;
|
|
case 'r':
|
|
*to++ = '\r';
|
|
break;
|
|
case 'b':
|
|
*to++ = '\b';
|
|
break;
|
|
case 'Z': /* ^Z must be escaped on Win32 */
|
|
*to++='\032';
|
|
break;
|
|
default:
|
|
*to++ = *from;
|
|
break;
|
|
}
|
|
}
|
|
else if (c == sep)
|
|
{
|
|
if (c == ' ' || c != *++from)
|
|
break; /* Found end of string */
|
|
*to++=c; /* Copy duplicated separator */
|
|
}
|
|
else
|
|
*to++=c;
|
|
}
|
|
if (*from != ' ' && *from)
|
|
die("Wrong string argument in %s", command->query);
|
|
|
|
while (my_isspace(charset_info,*from)) /* Point to next string */
|
|
from++;
|
|
|
|
*to =0; /* End of string marker */
|
|
*to_ptr= to+1; /* Store pointer to end */
|
|
*from_ptr= from;
|
|
|
|
/* Check if this was a variable */
|
|
if (*start == '$')
|
|
{
|
|
const char *end= to;
|
|
VAR *var=var_get(start, &end, 0, 1);
|
|
if (var && to == (char*) end+1)
|
|
{
|
|
DBUG_PRINT("info",("var: '%s' -> '%s'", start, var->str_val));
|
|
DBUG_RETURN(var->str_val); /* return found variable value */
|
|
}
|
|
}
|
|
DBUG_RETURN(start);
|
|
}
|
|
|
|
|
|
void set_reconnect(MYSQL* mysql, int val)
|
|
{
|
|
my_bool reconnect= val;
|
|
DBUG_ENTER("set_reconnect");
|
|
DBUG_PRINT("info", ("val: %d", val));
|
|
#if MYSQL_VERSION_ID < 50000
|
|
mysql->reconnect= reconnect;
|
|
#else
|
|
mysql_options(mysql, MYSQL_OPT_RECONNECT, (char *)&reconnect);
|
|
#endif
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
struct st_connection * find_connection_by_name(const char *name)
|
|
{
|
|
struct st_connection *con;
|
|
for (con= connections; con < next_con; con++)
|
|
{
|
|
if (!strcmp(con->name, name))
|
|
{
|
|
return con;
|
|
}
|
|
}
|
|
return 0; /* Connection not found */
|
|
}
|
|
|
|
|
|
int select_connection_name(const char *name)
|
|
{
|
|
DBUG_ENTER("select_connection2");
|
|
DBUG_PRINT("enter",("name: '%s'", name));
|
|
|
|
if (!(cur_con= find_connection_by_name(name)))
|
|
die("connection '%s' not found in connection pool", name);
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
int select_connection(struct st_command *command)
|
|
{
|
|
char *name;
|
|
char *p= command->first_argument;
|
|
DBUG_ENTER("select_connection");
|
|
|
|
if (!*p)
|
|
die("Missing connection name in connect");
|
|
name= p;
|
|
while (*p && !my_isspace(charset_info,*p))
|
|
p++;
|
|
if (*p)
|
|
*p++= 0;
|
|
command->last_argument= p;
|
|
return select_connection_name(name);
|
|
}
|
|
|
|
|
|
void do_close_connection(struct st_command *command)
|
|
{
|
|
char *p= command->first_argument, *name;
|
|
struct st_connection *con;
|
|
|
|
DBUG_ENTER("close_connection");
|
|
DBUG_PRINT("enter",("name: '%s'",p));
|
|
|
|
if (!*p)
|
|
die("Missing connection name in disconnect");
|
|
name= p;
|
|
while (*p && !my_isspace(charset_info,*p))
|
|
p++;
|
|
|
|
if (*p)
|
|
*p++= 0;
|
|
command->last_argument= p;
|
|
|
|
/* Loop through connection pool for connection to close */
|
|
for (con= connections; con < next_con; con++)
|
|
{
|
|
DBUG_PRINT("info", ("con->name: %s", con->name));
|
|
if (!strcmp(con->name, name))
|
|
{
|
|
DBUG_PRINT("info", ("Closing connection %s", con->name));
|
|
#ifndef EMBEDDED_LIBRARY
|
|
if (command->type == Q_DIRTY_CLOSE)
|
|
{
|
|
if (con->mysql.net.vio)
|
|
{
|
|
vio_delete(con->mysql.net.vio);
|
|
con->mysql.net.vio = 0;
|
|
}
|
|
}
|
|
#endif
|
|
mysql_close(&con->mysql);
|
|
if (con->util_mysql)
|
|
mysql_close(con->util_mysql);
|
|
con->util_mysql= 0;
|
|
my_free(con->name, MYF(0));
|
|
|
|
/*
|
|
When the connection is closed set name to "closed_connection"
|
|
to make it possible to reuse the connection name.
|
|
The connection slot will not be reused
|
|
*/
|
|
if (!(con->name = my_strdup("closed_connection", MYF(MY_WME))))
|
|
die("Out of memory");
|
|
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
}
|
|
die("connection '%s' not found in connection pool", name);
|
|
}
|
|
|
|
|
|
/*
|
|
Connect to a server doing several retries if needed.
|
|
|
|
SYNOPSIS
|
|
safe_connect()
|
|
con - connection structure to be used
|
|
host, user, pass, - connection parameters
|
|
db, port, sock
|
|
|
|
NOTE
|
|
|
|
Sometimes in a test the client starts before
|
|
the server - to solve the problem, we try again
|
|
after some sleep if connection fails the first
|
|
time
|
|
|
|
This function will try to connect to the given server
|
|
"opt_max_connect_retries" times and sleep "connection_retry_sleep"
|
|
seconds between attempts before finally giving up.
|
|
This helps in situation when the client starts
|
|
before the server (which happens sometimes).
|
|
It will only ignore connection errors during these retries.
|
|
|
|
*/
|
|
|
|
void safe_connect(MYSQL* mysql, const char *name, const char *host,
|
|
const char *user, const char *pass, const char *db,
|
|
int port, const char *sock)
|
|
{
|
|
int failed_attempts= 0;
|
|
static ulong connection_retry_sleep= 100000; /* Microseconds */
|
|
|
|
DBUG_ENTER("safe_connect");
|
|
while(!mysql_real_connect(mysql, host,user, pass, db, port, sock,
|
|
CLIENT_MULTI_STATEMENTS | CLIENT_REMEMBER_OPTIONS))
|
|
{
|
|
/*
|
|
Connect failed
|
|
|
|
Only allow retry if this was an error indicating the server
|
|
could not be contacted. Error code differs depending
|
|
on protocol/connection type
|
|
*/
|
|
|
|
if ((mysql_errno(mysql) == CR_CONN_HOST_ERROR ||
|
|
mysql_errno(mysql) == CR_CONNECTION_ERROR) &&
|
|
failed_attempts < opt_max_connect_retries)
|
|
my_sleep(connection_retry_sleep);
|
|
else
|
|
{
|
|
if (failed_attempts > 0)
|
|
die("Could not open connection '%s' after %d attempts: %d %s", name,
|
|
failed_attempts, mysql_errno(mysql), mysql_error(mysql));
|
|
else
|
|
die("Could not open connection '%s': %d %s", name,
|
|
mysql_errno(mysql), mysql_error(mysql));
|
|
}
|
|
failed_attempts++;
|
|
}
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
/*
|
|
Connect to a server and handle connection errors in case they occur.
|
|
|
|
SYNOPSIS
|
|
connect_n_handle_errors()
|
|
q - context of connect "query" (command)
|
|
con - connection structure to be used
|
|
host, user, pass, - connection parameters
|
|
db, port, sock
|
|
|
|
DESCRIPTION
|
|
This function will try to establish a connection to server and handle
|
|
possible errors in the same manner as if "connect" was usual SQL-statement
|
|
(If error is expected it will ignore it once it occurs and log the
|
|
"statement" to the query log).
|
|
Unlike safe_connect() it won't do several attempts.
|
|
|
|
RETURN VALUES
|
|
1 - Connected
|
|
0 - Not connected
|
|
|
|
*/
|
|
|
|
int connect_n_handle_errors(struct st_command *command,
|
|
MYSQL* con, const char* host,
|
|
const char* user, const char* pass,
|
|
const char* db, int port, const char* sock)
|
|
{
|
|
DYNAMIC_STRING *ds;
|
|
|
|
ds= &ds_res;
|
|
|
|
/* Only log if an error is expected */
|
|
if (!command->abort_on_error &&
|
|
!disable_query_log)
|
|
{
|
|
/*
|
|
Log the connect to result log
|
|
*/
|
|
dynstr_append_mem(ds, "connect(", 8);
|
|
replace_dynstr_append(ds, host);
|
|
dynstr_append_mem(ds, ",", 1);
|
|
replace_dynstr_append(ds, user);
|
|
dynstr_append_mem(ds, ",", 1);
|
|
replace_dynstr_append(ds, pass);
|
|
dynstr_append_mem(ds, ",", 1);
|
|
if (db)
|
|
replace_dynstr_append(ds, db);
|
|
dynstr_append_mem(ds, ",", 1);
|
|
replace_dynstr_append_uint(ds, port);
|
|
dynstr_append_mem(ds, ",", 1);
|
|
if (sock)
|
|
replace_dynstr_append(ds, sock);
|
|
dynstr_append_mem(ds, ")", 1);
|
|
dynstr_append_mem(ds, delimiter, delimiter_length);
|
|
dynstr_append_mem(ds, "\n", 1);
|
|
}
|
|
if (!mysql_real_connect(con, host, user, pass, db, port, sock ? sock: 0,
|
|
CLIENT_MULTI_STATEMENTS))
|
|
{
|
|
handle_error(command, mysql_errno(con), mysql_error(con),
|
|
mysql_sqlstate(con), ds);
|
|
return 0; /* Not connected */
|
|
}
|
|
|
|
handle_no_error(command);
|
|
return 1; /* Connected */
|
|
}
|
|
|
|
|
|
/*
|
|
Open a new connection to MySQL Server with the parameters
|
|
specified. Make the new connection the current connection.
|
|
|
|
SYNOPSIS
|
|
do_connect()
|
|
q called command
|
|
|
|
DESCRIPTION
|
|
connect(<name>,<host>,<user>,[<pass>,[<db>,[<port>,<sock>[<opts>]]]]);
|
|
connect <name>,<host>,<user>,[<pass>,[<db>,[<port>,<sock>[<opts>]]]];
|
|
|
|
<name> - name of the new connection
|
|
<host> - hostname of server
|
|
<user> - user to connect as
|
|
<pass> - password used when connecting
|
|
<db> - initial db when connected
|
|
<port> - server port
|
|
<sock> - server socket
|
|
<opts> - options to use for the connection
|
|
* SSL - use SSL if available
|
|
* COMPRESS - use compression if available
|
|
|
|
*/
|
|
|
|
void do_connect(struct st_command *command)
|
|
{
|
|
int con_port= port;
|
|
char *con_options;
|
|
bool con_ssl= 0, con_compress= 0;
|
|
char *ptr;
|
|
|
|
static DYNAMIC_STRING ds_connection_name;
|
|
static DYNAMIC_STRING ds_host;
|
|
static DYNAMIC_STRING ds_user;
|
|
static DYNAMIC_STRING ds_password;
|
|
static DYNAMIC_STRING ds_database;
|
|
static DYNAMIC_STRING ds_port;
|
|
static DYNAMIC_STRING ds_sock;
|
|
static DYNAMIC_STRING ds_options;
|
|
const struct command_arg connect_args[] = {
|
|
"connection name", ARG_STRING, TRUE, &ds_connection_name,
|
|
"Name of the connection",
|
|
"host", ARG_STRING, TRUE, &ds_host, "Host to connect to",
|
|
"user", ARG_STRING, FALSE, &ds_user, "User to connect as",
|
|
"passsword", ARG_STRING, FALSE, &ds_password,
|
|
"Password used when connecting",
|
|
"database", ARG_STRING, FALSE, &ds_database,
|
|
"Dtabase to select after connect",
|
|
"port", ARG_STRING, FALSE, &ds_port, "Port to connect to",
|
|
"socket", ARG_STRING, FALSE, &ds_sock, "Socket to connect with",
|
|
"options", ARG_STRING, FALSE, &ds_options,
|
|
"Options to use while connecting"
|
|
};
|
|
|
|
DBUG_ENTER("do_connect");
|
|
DBUG_PRINT("enter",("connect: %s", command->first_argument));
|
|
|
|
/* Remove parenteses around connect arguments */
|
|
if ((ptr= strstr(command->first_argument, "(")))
|
|
{
|
|
/* Replace it with a space */
|
|
*ptr= ' ';
|
|
if ((ptr= strstr(command->first_argument, ")")))
|
|
{
|
|
/* Replace it with \0 */
|
|
*ptr= 0;
|
|
}
|
|
else
|
|
die("connect - argument list started with '(' must be ended with ')'");
|
|
}
|
|
|
|
check_command_args(command, command->first_argument, connect_args,
|
|
sizeof(connect_args)/sizeof(struct command_arg),
|
|
',');
|
|
|
|
/* Port */
|
|
if (ds_port.length)
|
|
{
|
|
con_port= atoi(ds_port.str);
|
|
if (con_port == 0)
|
|
die("Illegal argument for port: '%s'", ds_port.str);
|
|
}
|
|
|
|
/* Sock */
|
|
if (ds_sock.length)
|
|
{
|
|
/*
|
|
If the socket is specified just as a name without path
|
|
append tmpdir in front
|
|
*/
|
|
if (*ds_sock.str != FN_LIBCHAR)
|
|
{
|
|
char buff[FN_REFLEN];
|
|
fn_format(buff, ds_sock.str, TMPDIR, "", 0);
|
|
dynstr_set(&ds_sock, buff);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* No socket specified, use default */
|
|
dynstr_set(&ds_sock, unix_sock);
|
|
}
|
|
DBUG_PRINT("info", ("socket: %s", ds_sock.str));
|
|
|
|
|
|
/* Options */
|
|
con_options= ds_options.str;
|
|
while (*con_options)
|
|
{
|
|
char* end;
|
|
/* Step past any spaces in beginning of option*/
|
|
while (*con_options && my_isspace(charset_info, *con_options))
|
|
con_options++;
|
|
/* Find end of this option */
|
|
end= con_options;
|
|
while (*end && !my_isspace(charset_info, *end))
|
|
end++;
|
|
if (!strncmp(con_options, "SSL", 3))
|
|
con_ssl= 1;
|
|
else if (!strncmp(con_options, "COMPRESS", 8))
|
|
con_compress= 1;
|
|
else
|
|
die("Illegal option to connect: %.*s",
|
|
(int) (end - con_options), con_options);
|
|
/* Process next option */
|
|
con_options= end;
|
|
}
|
|
|
|
if (next_con == connections_end)
|
|
die("Connection limit exhausted, you can have max %d connections",
|
|
(int) (sizeof(connections)/sizeof(struct st_connection)));
|
|
|
|
if (find_connection_by_name(ds_connection_name.str))
|
|
die("Connection %s already exists", ds_connection_name.str);
|
|
|
|
if (!mysql_init(&next_con->mysql))
|
|
die("Failed on mysql_init()");
|
|
if (opt_compress || con_compress)
|
|
mysql_options(&next_con->mysql, MYSQL_OPT_COMPRESS, NullS);
|
|
mysql_options(&next_con->mysql, MYSQL_OPT_LOCAL_INFILE, 0);
|
|
mysql_options(&next_con->mysql, MYSQL_SET_CHARSET_NAME,
|
|
charset_info->csname);
|
|
if (opt_charsets_dir)
|
|
mysql_options(&cur_con->mysql, MYSQL_SET_CHARSET_DIR,
|
|
opt_charsets_dir);
|
|
|
|
#ifdef HAVE_OPENSSL
|
|
if (opt_use_ssl || con_ssl)
|
|
{
|
|
mysql_ssl_set(&next_con->mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
|
|
opt_ssl_capath, opt_ssl_cipher);
|
|
#if MYSQL_VERSION_ID >= 50000
|
|
/* Turn on ssl_verify_server_cert only if host is "localhost" */
|
|
opt_ssl_verify_server_cert= !strcmp(ds_connection_name.str, "localhost");
|
|
mysql_options(&next_con->mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
|
|
&opt_ssl_verify_server_cert);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
/* Use default db name */
|
|
if (ds_database.length == 0)
|
|
dynstr_set(&ds_database, db);
|
|
|
|
/* Special database to allow one to connect without a database name */
|
|
if (ds_database.length && !strcmp(ds_database.str,"*NO-ONE*"))
|
|
dynstr_set(&ds_database, "");
|
|
|
|
|
|
if (connect_n_handle_errors(command, &next_con->mysql,
|
|
ds_host.str,ds_user.str,
|
|
ds_password.str, ds_database.str,
|
|
con_port, ds_sock.str))
|
|
{
|
|
DBUG_PRINT("info", ("Inserting connection %s in connection pool",
|
|
ds_connection_name.str));
|
|
if (!(next_con->name= my_strdup(ds_connection_name.str, MYF(MY_WME))))
|
|
die("Out of memory");
|
|
cur_con= next_con++;
|
|
}
|
|
|
|
dynstr_free(&ds_connection_name);
|
|
dynstr_free(&ds_host);
|
|
dynstr_free(&ds_user);
|
|
dynstr_free(&ds_password);
|
|
dynstr_free(&ds_database);
|
|
dynstr_free(&ds_port);
|
|
dynstr_free(&ds_sock);
|
|
dynstr_free(&ds_options);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
int do_done(struct st_command *command)
|
|
{
|
|
/* Check if empty block stack */
|
|
if (cur_block == block_stack)
|
|
{
|
|
if (*command->query != '}')
|
|
die("Stray 'end' command - end of block before beginning");
|
|
die("Stray '}' - end of block before beginning");
|
|
}
|
|
|
|
/* Test if inner block has been executed */
|
|
if (cur_block->ok && cur_block->cmd == cmd_while)
|
|
{
|
|
/* Pop block from stack, re-execute outer block */
|
|
cur_block--;
|
|
parser.current_line = cur_block->line;
|
|
}
|
|
else
|
|
{
|
|
/* Pop block from stack, goto next line */
|
|
cur_block--;
|
|
parser.current_line++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
Process start of a "if" or "while" statement
|
|
|
|
SYNOPSIS
|
|
do_block()
|
|
cmd Type of block
|
|
q called command
|
|
|
|
DESCRIPTION
|
|
if ([!]<expr>)
|
|
{
|
|
<block statements>
|
|
}
|
|
|
|
while ([!]<expr>)
|
|
{
|
|
<block statements>
|
|
}
|
|
|
|
Evaluates the <expr> and if it evaluates to
|
|
greater than zero executes the following code block.
|
|
A '!' can be used before the <expr> to indicate it should
|
|
be executed if it evaluates to zero.
|
|
|
|
*/
|
|
|
|
void do_block(enum block_cmd cmd, struct st_command* command)
|
|
{
|
|
char *p= command->first_argument;
|
|
const char *expr_start, *expr_end;
|
|
VAR v;
|
|
const char *cmd_name= (cmd == cmd_while ? "while" : "if");
|
|
my_bool not_expr= FALSE;
|
|
DBUG_ENTER("do_block");
|
|
DBUG_PRINT("enter", ("%s", cmd_name));
|
|
|
|
/* Check stack overflow */
|
|
if (cur_block == block_stack_end)
|
|
die("Nesting too deeply");
|
|
|
|
/* Set way to find outer block again, increase line counter */
|
|
cur_block->line= parser.current_line++;
|
|
|
|
/* If this block is ignored */
|
|
if (!cur_block->ok)
|
|
{
|
|
/* Inner block should be ignored too */
|
|
cur_block++;
|
|
cur_block->cmd= cmd;
|
|
cur_block->ok= FALSE;
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
/* Parse and evaluate test expression */
|
|
expr_start= strchr(p, '(');
|
|
if (!expr_start++)
|
|
die("missing '(' in %s", cmd_name);
|
|
|
|
/* Check for !<expr> */
|
|
if (*expr_start == '!')
|
|
{
|
|
not_expr= TRUE;
|
|
expr_start++; /* Step past the '!' */
|
|
}
|
|
/* Find ending ')' */
|
|
expr_end= strrchr(expr_start, ')');
|
|
if (!expr_end)
|
|
die("missing ')' in %s", cmd_name);
|
|
p= (char*)expr_end+1;
|
|
|
|
while (*p && my_isspace(charset_info, *p))
|
|
p++;
|
|
if (*p && *p != '{')
|
|
die("Missing '{' after %s. Found \"%s\"", cmd_name, p);
|
|
|
|
var_init(&v,0,0,0,0);
|
|
eval_expr(&v, expr_start, &expr_end);
|
|
|
|
/* Define inner block */
|
|
cur_block++;
|
|
cur_block->cmd= cmd;
|
|
cur_block->ok= (v.int_val ? TRUE : FALSE);
|
|
|
|
if (not_expr)
|
|
cur_block->ok = !cur_block->ok;
|
|
|
|
DBUG_PRINT("info", ("OK: %d", cur_block->ok));
|
|
|
|
var_free(&v);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
void do_delimiter(struct st_command* command)
|
|
{
|
|
char* p= command->first_argument;
|
|
DBUG_ENTER("do_delimiter");
|
|
DBUG_PRINT("enter", ("first_argument: %s", command->first_argument));
|
|
|
|
while (*p && my_isspace(charset_info, *p))
|
|
p++;
|
|
|
|
if (!(*p))
|
|
die("Can't set empty delimiter");
|
|
|
|
strmake(delimiter, p, sizeof(delimiter) - 1);
|
|
delimiter_length= strlen(delimiter);
|
|
|
|
DBUG_PRINT("exit", ("delimiter: %s", delimiter));
|
|
command->last_argument= p + delimiter_length;
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
my_bool match_delimiter(int c, const char *delim, uint length)
|
|
{
|
|
uint i;
|
|
char tmp[MAX_DELIMITER_LENGTH];
|
|
|
|
if (c != *delim)
|
|
return 0;
|
|
|
|
for (i= 1; i < length &&
|
|
(c= my_getc(cur_file->file)) == *(delim + i);
|
|
i++)
|
|
tmp[i]= c;
|
|
|
|
if (i == length)
|
|
return 1; /* Found delimiter */
|
|
|
|
/* didn't find delimiter, push back things that we read */
|
|
my_ungetc(c);
|
|
while (i > 1)
|
|
my_ungetc(tmp[--i]);
|
|
return 0;
|
|
}
|
|
|
|
|
|
my_bool end_of_query(int c)
|
|
{
|
|
return match_delimiter(c, delimiter, delimiter_length);
|
|
}
|
|
|
|
|
|
/*
|
|
Read one "line" from the file
|
|
|
|
SYNOPSIS
|
|
read_line
|
|
buf buffer for the read line
|
|
size size of the buffer i.e max size to read
|
|
|
|
DESCRIPTION
|
|
This function actually reads several lines and adds them to the
|
|
buffer buf. It continues to read until it finds what it believes
|
|
is a complete query.
|
|
|
|
Normally that means it will read lines until it reaches the
|
|
"delimiter" that marks end of query. Default delimiter is ';'
|
|
The function should be smart enough not to detect delimiter's
|
|
found inside strings surrounded with '"' and '\'' escaped strings.
|
|
|
|
If the first line in a query starts with '#' or '-' this line is treated
|
|
as a comment. A comment is always terminated when end of line '\n' is
|
|
reached.
|
|
|
|
*/
|
|
|
|
int read_line(char *buf, int size)
|
|
{
|
|
char c, last_quote;
|
|
char *p= buf, *buf_end= buf + size - 1;
|
|
int skip_char= 0;
|
|
enum {R_NORMAL, R_Q, R_SLASH_IN_Q,
|
|
R_COMMENT, R_LINE_START} state= R_LINE_START;
|
|
DBUG_ENTER("read_line");
|
|
LINT_INIT(last_quote);
|
|
|
|
start_lineno= cur_file->lineno;
|
|
DBUG_PRINT("info", ("Starting to read at lineno: %d", start_lineno));
|
|
for (; p < buf_end ;)
|
|
{
|
|
skip_char= 0;
|
|
c= my_getc(cur_file->file);
|
|
if (feof(cur_file->file))
|
|
{
|
|
found_eof:
|
|
if (cur_file->file != stdin)
|
|
{
|
|
my_fclose(cur_file->file, MYF(0));
|
|
cur_file->file= 0;
|
|
}
|
|
my_free((gptr)cur_file->file_name, MYF(MY_ALLOW_ZERO_PTR));
|
|
cur_file->file_name= 0;
|
|
if (cur_file == file_stack)
|
|
{
|
|
/* We're back at the first file, check if
|
|
all { have matching }
|
|
*/
|
|
if (cur_block != block_stack)
|
|
die("Missing end of block");
|
|
|
|
*p= 0;
|
|
DBUG_PRINT("info", ("end of file at line %d", cur_file->lineno));
|
|
DBUG_RETURN(1);
|
|
}
|
|
cur_file--;
|
|
start_lineno= cur_file->lineno;
|
|
continue;
|
|
}
|
|
|
|
if (c == '\n')
|
|
{
|
|
/* Line counting is independent of state */
|
|
cur_file->lineno++;
|
|
|
|
/* Convert cr/lf to lf */
|
|
if (p != buf && *(p-1) == '\r')
|
|
p--;
|
|
}
|
|
|
|
switch(state) {
|
|
case R_NORMAL:
|
|
if (end_of_query(c))
|
|
{
|
|
*p= 0;
|
|
DBUG_PRINT("exit", ("Found delimiter '%s' at line %d",
|
|
delimiter, cur_file->lineno));
|
|
DBUG_RETURN(0);
|
|
}
|
|
else if ((c == '{' &&
|
|
(!my_strnncoll_simple(charset_info, (const uchar*) "while", 5,
|
|
(uchar*) buf, min(5, p - buf), 0) ||
|
|
!my_strnncoll_simple(charset_info, (const uchar*) "if", 2,
|
|
(uchar*) buf, min(2, p - buf), 0))))
|
|
{
|
|
/* Only if and while commands can be terminated by { */
|
|
*p++= c;
|
|
*p= 0;
|
|
DBUG_PRINT("exit", ("Found '{' indicating start of block at line %d",
|
|
cur_file->lineno));
|
|
DBUG_RETURN(0);
|
|
}
|
|
else if (c == '\'' || c == '"' || c == '`')
|
|
{
|
|
last_quote= c;
|
|
state= R_Q;
|
|
}
|
|
break;
|
|
|
|
case R_COMMENT:
|
|
if (c == '\n')
|
|
{
|
|
/* Comments are terminated by newline */
|
|
*p= 0;
|
|
DBUG_PRINT("exit", ("Found newline in comment at line: %d",
|
|
cur_file->lineno));
|
|
DBUG_RETURN(0);
|
|
}
|
|
break;
|
|
|
|
case R_LINE_START:
|
|
if (c == '#' || c == '-')
|
|
{
|
|
/* A # or - in the first position of the line - this is a comment */
|
|
state = R_COMMENT;
|
|
}
|
|
else if (my_isspace(charset_info, c))
|
|
{
|
|
/* Skip all space at begining of line */
|
|
if (c == '\n')
|
|
{
|
|
/* Query hasn't started yet */
|
|
start_lineno= cur_file->lineno;
|
|
DBUG_PRINT("info", ("Query hasn't started yet, start_lineno: %d",
|
|
start_lineno));
|
|
}
|
|
skip_char= 1;
|
|
}
|
|
else if (end_of_query(c))
|
|
{
|
|
*p= 0;
|
|
DBUG_PRINT("exit", ("Found delimiter '%s' at line: %d",
|
|
delimiter, cur_file->lineno));
|
|
DBUG_RETURN(0);
|
|
}
|
|
else if (c == '}')
|
|
{
|
|
/* A "}" need to be by itself in the begining of a line to terminate */
|
|
*p++= c;
|
|
*p= 0;
|
|
DBUG_PRINT("exit", ("Found '}' in begining of a line at line: %d",
|
|
cur_file->lineno));
|
|
DBUG_RETURN(0);
|
|
}
|
|
else if (c == '\'' || c == '"' || c == '`')
|
|
{
|
|
last_quote= c;
|
|
state= R_Q;
|
|
}
|
|
else
|
|
state= R_NORMAL;
|
|
break;
|
|
|
|
case R_Q:
|
|
if (c == last_quote)
|
|
state= R_NORMAL;
|
|
else if (c == '\\')
|
|
state= R_SLASH_IN_Q;
|
|
break;
|
|
|
|
case R_SLASH_IN_Q:
|
|
state= R_Q;
|
|
break;
|
|
|
|
}
|
|
|
|
if (!skip_char)
|
|
{
|
|
/* Could be a multibyte character */
|
|
/* This code is based on the code in "sql_load.cc" */
|
|
#ifdef USE_MB
|
|
int charlen = my_mbcharlen(charset_info, c);
|
|
/* We give up if multibyte character is started but not */
|
|
/* completed before we pass buf_end */
|
|
if ((charlen > 1) && (p + charlen) <= buf_end)
|
|
{
|
|
int i;
|
|
char* mb_start = p;
|
|
|
|
*p++ = c;
|
|
|
|
for (i= 1; i < charlen; i++)
|
|
{
|
|
if (feof(cur_file->file))
|
|
goto found_eof;
|
|
c= my_getc(cur_file->file);
|
|
*p++ = c;
|
|
}
|
|
if (! my_ismbchar(charset_info, mb_start, p))
|
|
{
|
|
/* It was not a multiline char, push back the characters */
|
|
/* We leave first 'c', i.e. pretend it was a normal char */
|
|
while (p > mb_start)
|
|
my_ungetc(*--p);
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
*p++= c;
|
|
}
|
|
}
|
|
die("The input buffer is too small for this query.x\n" \
|
|
"check your query or increase MAX_QUERY and recompile");
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
/*
|
|
Convert the read query to result format version 1
|
|
|
|
That is: After newline, all spaces need to be skipped
|
|
unless the previous char was a quote
|
|
|
|
This is due to an old bug that has now been fixed, but the
|
|
version 1 output format is preserved by using this function
|
|
|
|
*/
|
|
|
|
void convert_to_format_v1(char* query)
|
|
{
|
|
int last_c_was_quote= 0;
|
|
char *p= query, *write= query;
|
|
char *end= strend(query);
|
|
char last_c;
|
|
|
|
while (p <= end)
|
|
{
|
|
if (*p == '\n' && !last_c_was_quote)
|
|
{
|
|
*write++ = *p++; /* Save the newline */
|
|
|
|
/* Skip any spaces on next line */
|
|
while (*p && my_isspace(charset_info, *p))
|
|
p++;
|
|
|
|
last_c_was_quote= 0;
|
|
}
|
|
else if (*p == '\'' || *p == '"' || *p == '`')
|
|
{
|
|
last_c= *p;
|
|
*write++ = *p++;
|
|
|
|
/* Copy anything until the next quote of same type */
|
|
while (*p && *p != last_c)
|
|
*write++ = *p++;
|
|
|
|
*write++ = *p++;
|
|
|
|
last_c_was_quote= 1;
|
|
}
|
|
else
|
|
{
|
|
*write++ = *p++;
|
|
last_c_was_quote= 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
Check a command that is about to be sent (or should have been
|
|
sent if parsing was enabled) to mysql server for
|
|
suspicious things and generate warnings.
|
|
*/
|
|
|
|
void scan_command_for_warnings(struct st_command *command)
|
|
{
|
|
const char *ptr= command->query;
|
|
DBUG_ENTER("scan_command_for_warnings");
|
|
DBUG_PRINT("enter", ("query: %s", command->query));
|
|
|
|
while(*ptr)
|
|
{
|
|
/*
|
|
Look for query's that lines that start with a -- comment
|
|
and has a mysqltest command
|
|
*/
|
|
if (ptr[0] == '\n' &&
|
|
ptr[1] && ptr[1] == '-' &&
|
|
ptr[2] && ptr[2] == '-' &&
|
|
ptr[3])
|
|
{
|
|
uint type;
|
|
char save;
|
|
char *end, *start= (char*)ptr+3;
|
|
/* Skip leading spaces */
|
|
while (*start && my_isspace(charset_info, *start))
|
|
start++;
|
|
end= start;
|
|
/* Find end of command(next space) */
|
|
while (*end && !my_isspace(charset_info, *end))
|
|
end++;
|
|
save= *end;
|
|
*end= 0;
|
|
DBUG_PRINT("info", ("Checking '%s'", start));
|
|
type= find_type(start, &command_typelib, 1+2);
|
|
if (type)
|
|
warning_msg("Embedded mysqltest command '--%s' detected in "
|
|
"query '%s' was this intentional? ",
|
|
start, command->query);
|
|
*end= save;
|
|
}
|
|
|
|
ptr++;
|
|
}
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
/*
|
|
Check for unexpected "junk" after the end of query
|
|
This is normally caused by missing delimiters or when
|
|
switching between different delimiters
|
|
*/
|
|
|
|
void check_eol_junk_line(const char *line)
|
|
{
|
|
const char *p= line;
|
|
DBUG_ENTER("check_eol_junk_line");
|
|
DBUG_PRINT("enter", ("line: %s", line));
|
|
|
|
/* Check for extra delimiter */
|
|
if (*p && !strncmp(p, delimiter, delimiter_length))
|
|
die("Extra delimiter \"%s\" found", delimiter);
|
|
|
|
/* Allow trailing # comment */
|
|
if (*p && *p != '#')
|
|
{
|
|
if (*p == '\n')
|
|
die("Missing delimiter");
|
|
die("End of line junk detected: \"%s\"", p);
|
|
}
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
void check_eol_junk(const char *eol)
|
|
{
|
|
const char *p= eol;
|
|
DBUG_ENTER("check_eol_junk");
|
|
DBUG_PRINT("enter", ("eol: %s", eol));
|
|
|
|
/* Skip past all spacing chars and comments */
|
|
while (*p && (my_isspace(charset_info, *p) || *p == '#' || *p == '\n'))
|
|
{
|
|
/* Skip past comments started with # and ended with newline */
|
|
if (*p && *p == '#')
|
|
{
|
|
p++;
|
|
while (*p && *p != '\n')
|
|
p++;
|
|
}
|
|
|
|
/* Check this line */
|
|
if (*p && *p == '\n')
|
|
check_eol_junk_line(p);
|
|
|
|
if (*p)
|
|
p++;
|
|
}
|
|
|
|
check_eol_junk_line(p);
|
|
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
Create a command from a set of lines
|
|
|
|
SYNOPSIS
|
|
read_command()
|
|
command_ptr pointer where to return the new query
|
|
|
|
DESCRIPTION
|
|
Converts lines returned by read_line into a command, this involves
|
|
parsing the first word in the read line to find the command type.
|
|
|
|
|
|
A -- comment may contain a valid query as the first word after the
|
|
comment start. Thus it's always checked to see if that is the case.
|
|
The advantage with this approach is to be able to execute commands
|
|
terminated by new line '\n' regardless how many "delimiter" it contain.
|
|
|
|
*/
|
|
|
|
#define MAX_QUERY (256*1024) /* 256K -- a test in sp-big is >128K */
|
|
static char read_command_buf[MAX_QUERY];
|
|
|
|
int read_command(struct st_command** command_ptr)
|
|
{
|
|
char *p= read_command_buf;
|
|
struct st_command* command;
|
|
DBUG_ENTER("read_command");
|
|
|
|
if (parser.current_line < parser.read_lines)
|
|
{
|
|
get_dynamic(&q_lines, (gptr) command_ptr, parser.current_line) ;
|
|
DBUG_RETURN(0);
|
|
}
|
|
if (!(*command_ptr= command=
|
|
(struct st_command*) my_malloc(sizeof(*command), MYF(MY_WME))) ||
|
|
insert_dynamic(&q_lines, (gptr) &command))
|
|
die(NullS);
|
|
|
|
command->require_file[0]= 0;
|
|
command->first_word_len= 0;
|
|
command->query_len= 0;
|
|
|
|
command->type= Q_UNKNOWN;
|
|
command->query_buf= command->query= 0;
|
|
read_command_buf[0]= 0;
|
|
if (read_line(read_command_buf, sizeof(read_command_buf)))
|
|
{
|
|
check_eol_junk(read_command_buf);
|
|
DBUG_RETURN(1);
|
|
}
|
|
|
|
convert_to_format_v1(read_command_buf);
|
|
|
|
DBUG_PRINT("info", ("query: %s", read_command_buf));
|
|
if (*p == '#')
|
|
{
|
|
command->type= Q_COMMENT;
|
|
}
|
|
else if (p[0] == '-' && p[1] == '-')
|
|
{
|
|
command->type= Q_COMMENT_WITH_COMMAND;
|
|
p+= 2; /* Skip past -- */
|
|
}
|
|
|
|
/* Skip leading spaces */
|
|
while (*p && my_isspace(charset_info, *p))
|
|
p++;
|
|
|
|
if (!(command->query_buf= command->query= my_strdup(p, MYF(MY_WME))))
|
|
die("Out of memory");
|
|
|
|
/* Calculate first word and first argument */
|
|
for (p= command->query; *p && !my_isspace(charset_info, *p) ; p++) ;
|
|
command->first_word_len= (uint) (p - command->query);
|
|
|
|
/* Skip spaces between command and first argument */
|
|
while (*p && my_isspace(charset_info, *p))
|
|
p++;
|
|
command->first_argument= p;
|
|
|
|
command->end= strend(command->query);
|
|
command->query_len= (command->end - command->query);
|
|
parser.read_lines++;
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
static struct my_option my_long_options[] =
|
|
{
|
|
{"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG,
|
|
0, 0, 0, 0, 0, 0},
|
|
{"basedir", 'b', "Basedir for tests.", (gptr*) &opt_basedir,
|
|
(gptr*) &opt_basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"character-sets-dir", OPT_CHARSETS_DIR,
|
|
"Directory where character sets are.", (gptr*) &opt_charsets_dir,
|
|
(gptr*) &opt_charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"compress", 'C', "Use the compressed server/client protocol.",
|
|
(gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
|
|
0, 0, 0},
|
|
{"cursor-protocol", OPT_CURSOR_PROTOCOL, "Use cursors for prepared statements.",
|
|
(gptr*) &cursor_protocol, (gptr*) &cursor_protocol, 0,
|
|
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"database", 'D', "Database to use.", (gptr*) &db, (gptr*) &db, 0,
|
|
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
|
#ifdef DBUG_OFF
|
|
{"debug", '#', "This is a non-debug version. Catch this and exit",
|
|
0,0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
|
|
#else
|
|
{"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.",
|
|
0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
|
|
#endif
|
|
{"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.", (gptr*) &info_flag,
|
|
(gptr*) &info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"host", 'h', "Connect to host.", (gptr*) &host, (gptr*) &host, 0,
|
|
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"include", 'i', "Include SQL before each test case.", (gptr*) &opt_include,
|
|
(gptr*) &opt_include, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"logdir", OPT_LOG_DIR, "Directory for log files", (gptr*) &opt_logdir,
|
|
(gptr*) &opt_logdir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"mark-progress", OPT_MARK_PROGRESS,
|
|
"Write linenumber and elapsed time to <testname>.progress",
|
|
(gptr*) &opt_mark_progress, (gptr*) &opt_mark_progress, 0,
|
|
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"max-connect-retries", OPT_MAX_CONNECT_RETRIES,
|
|
"Max number of connection attempts when connecting to server",
|
|
(gptr*) &opt_max_connect_retries, (gptr*) &opt_max_connect_retries, 0,
|
|
GET_INT, REQUIRED_ARG, 500, 1, 10000, 0, 0, 0},
|
|
{"password", 'p', "Password to use when connecting to server.",
|
|
0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"port", 'P', "Port number to use for connection.", (gptr*) &port,
|
|
(gptr*) &port, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"ps-protocol", OPT_PS_PROTOCOL, "Use prepared statements protocol for communication",
|
|
(gptr*) &ps_protocol, (gptr*) &ps_protocol, 0,
|
|
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"quiet", 's', "Suppress all normal output.", (gptr*) &silent,
|
|
(gptr*) &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"record", 'r', "Record output of test_file into result file.",
|
|
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"result-file", 'R', "Read/Store result from/in this file.",
|
|
(gptr*) &result_file_name, (gptr*) &result_file_name, 0,
|
|
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"server-arg", 'A', "Send option value to embedded server as a parameter.",
|
|
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"server-file", 'F', "Read embedded server arguments from file.",
|
|
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"silent", 's', "Suppress all normal output. Synonym for --quiet.",
|
|
(gptr*) &silent, (gptr*) &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"skip-safemalloc", OPT_SKIP_SAFEMALLOC,
|
|
"Don't use the memory allocation checking.", 0, 0, 0, GET_NO_ARG, NO_ARG,
|
|
0, 0, 0, 0, 0, 0},
|
|
{"sleep", 'T', "Sleep always this many seconds on sleep commands.",
|
|
(gptr*) &opt_sleep, (gptr*) &opt_sleep, 0, GET_INT, REQUIRED_ARG, -1, 0, 0,
|
|
0, 0, 0},
|
|
{"socket", 'S', "Socket file to use for connection.",
|
|
(gptr*) &unix_sock, (gptr*) &unix_sock, 0, GET_STR, REQUIRED_ARG, 0, 0, 0,
|
|
0, 0, 0},
|
|
{"sp-protocol", OPT_SP_PROTOCOL, "Use stored procedures for select",
|
|
(gptr*) &sp_protocol, (gptr*) &sp_protocol, 0,
|
|
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
|
#include "sslopt-longopts.h"
|
|
{"test-file", 'x', "Read test from/in this file (default stdin).",
|
|
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"timer-file", 'm', "File where the timing in micro seconds is stored.",
|
|
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"tmpdir", 't', "Temporary directory where sockets are put.",
|
|
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"user", 'u', "User for login.", (gptr*) &user, (gptr*) &user, 0, GET_STR,
|
|
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"verbose", 'v', "Write more.", (gptr*) &verbose, (gptr*) &verbose, 0,
|
|
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"version", 'V', "Output version information and exit.",
|
|
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
|
|
{"view-protocol", OPT_VIEW_PROTOCOL, "Use views for select",
|
|
(gptr*) &view_protocol, (gptr*) &view_protocol, 0,
|
|
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
|
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
|
|
};
|
|
|
|
|
|
#include <help_start.h>
|
|
|
|
void print_version(void)
|
|
{
|
|
printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,MTEST_VERSION,
|
|
MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
|
|
}
|
|
|
|
void usage()
|
|
{
|
|
print_version();
|
|
printf("MySQL AB, by Sasha, Matt, Monty & Jani\n");
|
|
printf("This software comes with ABSOLUTELY NO WARRANTY\n\n");
|
|
printf("Runs a test against the mysql server and compares output with a results file.\n\n");
|
|
printf("Usage: %s [OPTIONS] [database] < test_file\n", my_progname);
|
|
my_print_help(my_long_options);
|
|
printf(" --no-defaults Don't read default options from any options file.\n");
|
|
my_print_variables(my_long_options);
|
|
}
|
|
|
|
#include <help_end.h>
|
|
|
|
|
|
/*
|
|
Read arguments for embedded server and put them into
|
|
embedded_server_args[]
|
|
*/
|
|
|
|
void read_embedded_server_arguments(const char *name)
|
|
{
|
|
char argument[1024],buff[FN_REFLEN], *str=0;
|
|
FILE *file;
|
|
|
|
if (!test_if_hard_path(name))
|
|
{
|
|
strxmov(buff, opt_basedir, name, NullS);
|
|
name=buff;
|
|
}
|
|
fn_format(buff, name, "", "", MY_UNPACK_FILENAME);
|
|
|
|
if (!embedded_server_arg_count)
|
|
{
|
|
embedded_server_arg_count=1;
|
|
embedded_server_args[0]= (char*) ""; /* Progname */
|
|
}
|
|
if (!(file=my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(MY_WME))))
|
|
die("Failed to open file %s", buff);
|
|
|
|
while (embedded_server_arg_count < MAX_EMBEDDED_SERVER_ARGS &&
|
|
(str=fgets(argument,sizeof(argument), file)))
|
|
{
|
|
*(strend(str)-1)=0; /* Remove end newline */
|
|
if (!(embedded_server_args[embedded_server_arg_count]=
|
|
(char*) my_strdup(str,MYF(MY_WME))))
|
|
{
|
|
my_fclose(file,MYF(0));
|
|
die("Out of memory");
|
|
|
|
}
|
|
embedded_server_arg_count++;
|
|
}
|
|
my_fclose(file,MYF(0));
|
|
if (str)
|
|
die("Too many arguments in option file: %s",name);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
static my_bool
|
|
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
|
|
char *argument)
|
|
{
|
|
switch(optid) {
|
|
case '#':
|
|
#ifndef DBUG_OFF
|
|
DBUG_PUSH(argument ? argument : "d:t:S:i:O,/tmp/mysqltest.trace");
|
|
#endif
|
|
break;
|
|
case 'r':
|
|
record = 1;
|
|
break;
|
|
case 'x':
|
|
{
|
|
char buff[FN_REFLEN];
|
|
if (!test_if_hard_path(argument))
|
|
{
|
|
strxmov(buff, opt_basedir, argument, NullS);
|
|
argument= buff;
|
|
}
|
|
fn_format(buff, argument, "", "", MY_UNPACK_FILENAME);
|
|
DBUG_ASSERT(cur_file == file_stack && cur_file->file == 0);
|
|
if (!(cur_file->file=
|
|
my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(0))))
|
|
die("Could not open %s: errno = %d", buff, errno);
|
|
cur_file->file_name= my_strdup(buff, MYF(MY_FAE));
|
|
cur_file->lineno= 1;
|
|
break;
|
|
}
|
|
case 'm':
|
|
{
|
|
static char buff[FN_REFLEN];
|
|
if (!test_if_hard_path(argument))
|
|
{
|
|
strxmov(buff, opt_basedir, argument, NullS);
|
|
argument= buff;
|
|
}
|
|
fn_format(buff, argument, "", "", MY_UNPACK_FILENAME);
|
|
timer_file= buff;
|
|
unlink(timer_file); /* Ignore error, may not exist */
|
|
break;
|
|
}
|
|
case 'p':
|
|
if (argument)
|
|
{
|
|
my_free(pass, MYF(MY_ALLOW_ZERO_PTR));
|
|
pass= my_strdup(argument, MYF(MY_FAE));
|
|
while (*argument) *argument++= 'x'; /* Destroy argument */
|
|
tty_password= 0;
|
|
}
|
|
else
|
|
tty_password= 1;
|
|
break;
|
|
#include <sslopt-case.h>
|
|
case 't':
|
|
strnmov(TMPDIR, argument, sizeof(TMPDIR));
|
|
break;
|
|
case 'A':
|
|
if (!embedded_server_arg_count)
|
|
{
|
|
embedded_server_arg_count=1;
|
|
embedded_server_args[0]= (char*) "";
|
|
}
|
|
if (embedded_server_arg_count == MAX_EMBEDDED_SERVER_ARGS-1 ||
|
|
!(embedded_server_args[embedded_server_arg_count++]=
|
|
my_strdup(argument, MYF(MY_FAE))))
|
|
{
|
|
die("Can't use server argument");
|
|
}
|
|
break;
|
|
case 'F':
|
|
read_embedded_server_arguments(argument);
|
|
break;
|
|
case OPT_SKIP_SAFEMALLOC:
|
|
#ifdef SAFEMALLOC
|
|
sf_malloc_quick=1;
|
|
#endif
|
|
break;
|
|
case 'V':
|
|
print_version();
|
|
exit(0);
|
|
case '?':
|
|
usage();
|
|
exit(1);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int parse_args(int argc, char **argv)
|
|
{
|
|
load_defaults("my",load_default_groups,&argc,&argv);
|
|
default_argv= argv;
|
|
|
|
if ((handle_options(&argc, &argv, my_long_options, get_one_option)))
|
|
exit(1);
|
|
|
|
if (argc > 1)
|
|
{
|
|
usage();
|
|
exit(1);
|
|
}
|
|
if (argc == 1)
|
|
db= *argv;
|
|
if (tty_password)
|
|
pass=get_tty_password(NullS);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
Write the content of str into file
|
|
|
|
SYNOPSIS
|
|
str_to_file
|
|
fname - name of file to truncate/create and write to
|
|
str - content to write to file
|
|
size - size of content witten to file
|
|
*/
|
|
|
|
void str_to_file(const char *fname, char *str, int size)
|
|
{
|
|
int fd;
|
|
char buff[FN_REFLEN];
|
|
if (!test_if_hard_path(fname))
|
|
{
|
|
strxmov(buff, opt_basedir, fname, NullS);
|
|
fname= buff;
|
|
}
|
|
fn_format(buff, fname, "", "", MY_UNPACK_FILENAME);
|
|
|
|
if ((fd= my_open(buff, O_WRONLY | O_CREAT | O_TRUNC,
|
|
MYF(MY_WME | MY_FFNF))) < 0)
|
|
die("Could not open %s: errno = %d", buff, errno);
|
|
if (my_write(fd, (byte*)str, size, MYF(MY_WME|MY_FNABP)))
|
|
die("write failed");
|
|
my_close(fd, MYF(0));
|
|
}
|
|
|
|
|
|
void dump_result_to_reject_file(char *buf, int size)
|
|
{
|
|
char reject_file[FN_REFLEN];
|
|
str_to_file(fn_format(reject_file, result_file_name, "", ".reject",
|
|
MY_REPLACE_EXT),
|
|
buf, size);
|
|
}
|
|
|
|
void dump_result_to_log_file(char *buf, int size)
|
|
{
|
|
char log_file[FN_REFLEN];
|
|
str_to_file(fn_format(log_file, result_file_name, opt_logdir, ".log",
|
|
*opt_logdir ? MY_REPLACE_DIR | MY_REPLACE_EXT:
|
|
MY_REPLACE_EXT),
|
|
buf, size);
|
|
}
|
|
|
|
void dump_progress(void)
|
|
{
|
|
char log_file[FN_REFLEN];
|
|
str_to_file(fn_format(log_file, result_file_name, opt_logdir, ".progress",
|
|
*opt_logdir ? MY_REPLACE_DIR | MY_REPLACE_EXT:
|
|
MY_REPLACE_EXT),
|
|
ds_progress.str, ds_progress.length);
|
|
}
|
|
|
|
void dump_warning_messages(void)
|
|
{
|
|
char warn_file[FN_REFLEN];
|
|
|
|
str_to_file(fn_format(warn_file, result_file_name, "", ".warnings",
|
|
MY_REPLACE_EXT),
|
|
ds_warning_messages.str, ds_warning_messages.length);
|
|
}
|
|
|
|
void check_regerr(my_regex_t* r, int err)
|
|
{
|
|
char err_buf[1024];
|
|
|
|
if (err)
|
|
{
|
|
my_regerror(err,r,err_buf,sizeof(err_buf));
|
|
die("Regex error: %s\n", err_buf);
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef __WIN__
|
|
|
|
DYNAMIC_ARRAY patterns;
|
|
|
|
/*
|
|
init_win_path_patterns
|
|
|
|
DESCRIPTION
|
|
Setup string patterns that will be used to detect filenames that
|
|
needs to be converted from Win to Unix format
|
|
|
|
*/
|
|
|
|
void init_win_path_patterns()
|
|
{
|
|
/* List of string patterns to match in order to find paths */
|
|
const char* paths[] = { "$MYSQL_TEST_DIR",
|
|
"$MYSQL_TMP_DIR",
|
|
"$MYSQLTEST_VARDIR",
|
|
"./test/" };
|
|
int num_paths= sizeof(paths)/sizeof(char*);
|
|
int i;
|
|
char* p;
|
|
|
|
DBUG_ENTER("init_win_path_patterns");
|
|
|
|
my_init_dynamic_array(&patterns, sizeof(const char*), 16, 16);
|
|
|
|
/* Loop through all paths in the array */
|
|
for (i= 0; i < num_paths; i++)
|
|
{
|
|
VAR* v;
|
|
if (*(paths[i]) == '$')
|
|
{
|
|
v= var_get(paths[i], 0, 0, 0);
|
|
p= my_strdup(v->str_val, MYF(MY_FAE));
|
|
}
|
|
else
|
|
p= my_strdup(paths[i], MYF(MY_FAE));
|
|
|
|
/* Don't insert zero length strings in patterns array */
|
|
if (strlen(p) == 0)
|
|
{
|
|
my_free(p, MYF(0));
|
|
continue;
|
|
}
|
|
|
|
if (insert_dynamic(&patterns, (gptr) &p))
|
|
die(NullS);
|
|
|
|
DBUG_PRINT("info", ("p: %s", p));
|
|
while (*p)
|
|
{
|
|
if (*p == '/')
|
|
*p='\\';
|
|
p++;
|
|
}
|
|
}
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
void free_win_path_patterns()
|
|
{
|
|
uint i= 0;
|
|
for (i=0 ; i < patterns.elements ; i++)
|
|
{
|
|
const char** pattern= dynamic_element(&patterns, i, const char**);
|
|
my_free((gptr) *pattern, MYF(0));
|
|
}
|
|
delete_dynamic(&patterns);
|
|
}
|
|
|
|
/*
|
|
fix_win_paths
|
|
|
|
DESCRIPTION
|
|
Search the string 'val' for the patterns that are known to be
|
|
strings that contain filenames. Convert all \ to / in the
|
|
filenames that are found.
|
|
|
|
Ex:
|
|
val = 'Error "c:\mysql\mysql-test\var\test\t1.frm" didn't exist'
|
|
=> $MYSQL_TEST_DIR is found by strstr
|
|
=> all \ from c:\mysql\m... until next space is converted into /
|
|
*/
|
|
|
|
void fix_win_paths(const char *val, int len)
|
|
{
|
|
uint i;
|
|
char *p;
|
|
|
|
DBUG_ENTER("fix_win_paths");
|
|
for (i= 0; i < patterns.elements; i++)
|
|
{
|
|
const char** pattern= dynamic_element(&patterns, i, const char**);
|
|
DBUG_PRINT("info", ("pattern: %s", *pattern));
|
|
|
|
/* Search for the path in string */
|
|
while ((p= strstr(val, *pattern)))
|
|
{
|
|
DBUG_PRINT("info", ("Found %s in val p: %s", *pattern, p));
|
|
|
|
while (*p && !my_isspace(charset_info, *p))
|
|
{
|
|
if (*p == '\\')
|
|
*p= '/';
|
|
p++;
|
|
}
|
|
DBUG_PRINT("info", ("Converted \\ to /, p: %s", p));
|
|
}
|
|
}
|
|
DBUG_PRINT("exit", (" val: %s, len: %d", val, len));
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
Append the result for one field to the dynamic string ds
|
|
*/
|
|
|
|
void append_field(DYNAMIC_STRING *ds, uint col_idx, MYSQL_FIELD* field,
|
|
const char* val, ulonglong len, bool is_null)
|
|
{
|
|
if (col_idx < max_replace_column && replace_column[col_idx])
|
|
{
|
|
val= replace_column[col_idx];
|
|
len= strlen(val);
|
|
}
|
|
else if (is_null)
|
|
{
|
|
val= "NULL";
|
|
len= 4;
|
|
}
|
|
#ifdef __WIN__
|
|
else if ((field->type == MYSQL_TYPE_DOUBLE ||
|
|
field->type == MYSQL_TYPE_FLOAT ) &&
|
|
field->decimals >= 31)
|
|
{
|
|
/* Convert 1.2e+018 to 1.2e+18 and 1.2e-018 to 1.2e-18 */
|
|
char *start= strchr(val, 'e');
|
|
if (start && strlen(start) >= 5 &&
|
|
(start[1] == '-' || start[1] == '+') && start[2] == '0')
|
|
{
|
|
start+=2; /* Now points at first '0' */
|
|
/* Move all chars after the first '0' one step left */
|
|
memmove(start, start + 1, strlen(start));
|
|
len--;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (!display_result_vertically)
|
|
{
|
|
if (col_idx)
|
|
dynstr_append_mem(ds, "\t", 1);
|
|
replace_dynstr_append_mem(ds, val, (int)len);
|
|
}
|
|
else
|
|
{
|
|
dynstr_append(ds, field->name);
|
|
dynstr_append_mem(ds, "\t", 1);
|
|
replace_dynstr_append_mem(ds, val, (int)len);
|
|
dynstr_append_mem(ds, "\n", 1);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
Append all results to the dynamic string separated with '\t'
|
|
Values may be converted with 'replace_column'
|
|
*/
|
|
|
|
void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res)
|
|
{
|
|
MYSQL_ROW row;
|
|
uint num_fields= mysql_num_fields(res);
|
|
MYSQL_FIELD *fields= mysql_fetch_fields(res);
|
|
ulong *lengths;
|
|
|
|
while ((row = mysql_fetch_row(res)))
|
|
{
|
|
uint i;
|
|
lengths = mysql_fetch_lengths(res);
|
|
for (i = 0; i < num_fields; i++)
|
|
append_field(ds, i, &fields[i],
|
|
(const char*)row[i], lengths[i], !row[i]);
|
|
if (!display_result_vertically)
|
|
dynstr_append_mem(ds, "\n", 1);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
Append all results from ps execution to the dynamic string separated
|
|
with '\t'. Values may be converted with 'replace_column'
|
|
*/
|
|
|
|
void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt,
|
|
MYSQL_FIELD *fields, uint num_fields)
|
|
{
|
|
MYSQL_BIND *bind;
|
|
my_bool *is_null;
|
|
ulong *length;
|
|
uint i;
|
|
|
|
/* Allocate array with bind structs, lengths and NULL flags */
|
|
bind= (MYSQL_BIND*) my_malloc(num_fields * sizeof(MYSQL_BIND),
|
|
MYF(MY_WME | MY_FAE | MY_ZEROFILL));
|
|
length= (ulong*) my_malloc(num_fields * sizeof(ulong),
|
|
MYF(MY_WME | MY_FAE));
|
|
is_null= (my_bool*) my_malloc(num_fields * sizeof(my_bool),
|
|
MYF(MY_WME | MY_FAE));
|
|
|
|
/* Allocate data for the result of each field */
|
|
for (i= 0; i < num_fields; i++)
|
|
{
|
|
uint max_length= fields[i].max_length + 1;
|
|
bind[i].buffer_type= MYSQL_TYPE_STRING;
|
|
bind[i].buffer= (char *)my_malloc(max_length, MYF(MY_WME | MY_FAE));
|
|
bind[i].buffer_length= max_length;
|
|
bind[i].is_null= &is_null[i];
|
|
bind[i].length= &length[i];
|
|
|
|
DBUG_PRINT("bind", ("col[%d]: buffer_type: %d, buffer_length: %lu",
|
|
i, bind[i].buffer_type, bind[i].buffer_length));
|
|
}
|
|
|
|
if (mysql_stmt_bind_result(stmt, bind))
|
|
die("mysql_stmt_bind_result failed: %d: %s",
|
|
mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
|
|
|
|
while (mysql_stmt_fetch(stmt) == 0)
|
|
{
|
|
for (i= 0; i < num_fields; i++)
|
|
append_field(ds, i, &fields[i], (const char *) bind[i].buffer,
|
|
*bind[i].length, *bind[i].is_null);
|
|
if (!display_result_vertically)
|
|
dynstr_append_mem(ds, "\n", 1);
|
|
}
|
|
|
|
if (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
|
|
die("fetch didn't end with MYSQL_NO_DATA from statement: %d %s",
|
|
mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
|
|
|
|
for (i= 0; i < num_fields; i++)
|
|
{
|
|
/* Free data for output */
|
|
my_free((gptr)bind[i].buffer, MYF(MY_WME | MY_FAE));
|
|
}
|
|
/* Free array with bind structs, lengths and NULL flags */
|
|
my_free((gptr)bind , MYF(MY_WME | MY_FAE));
|
|
my_free((gptr)length , MYF(MY_WME | MY_FAE));
|
|
my_free((gptr)is_null , MYF(MY_WME | MY_FAE));
|
|
}
|
|
|
|
|
|
/*
|
|
Append metadata for fields to output
|
|
*/
|
|
|
|
void append_metadata(DYNAMIC_STRING *ds,
|
|
MYSQL_FIELD *field,
|
|
uint num_fields)
|
|
{
|
|
MYSQL_FIELD *field_end;
|
|
dynstr_append(ds,"Catalog\tDatabase\tTable\tTable_alias\tColumn\t"
|
|
"Column_alias\tType\tLength\tMax length\tIs_null\t"
|
|
"Flags\tDecimals\tCharsetnr\n");
|
|
|
|
for (field_end= field+num_fields ;
|
|
field < field_end ;
|
|
field++)
|
|
{
|
|
dynstr_append_mem(ds, field->catalog,
|
|
field->catalog_length);
|
|
dynstr_append_mem(ds, "\t", 1);
|
|
dynstr_append_mem(ds, field->db, field->db_length);
|
|
dynstr_append_mem(ds, "\t", 1);
|
|
dynstr_append_mem(ds, field->org_table,
|
|
field->org_table_length);
|
|
dynstr_append_mem(ds, "\t", 1);
|
|
dynstr_append_mem(ds, field->table,
|
|
field->table_length);
|
|
dynstr_append_mem(ds, "\t", 1);
|
|
dynstr_append_mem(ds, field->org_name,
|
|
field->org_name_length);
|
|
dynstr_append_mem(ds, "\t", 1);
|
|
dynstr_append_mem(ds, field->name, field->name_length);
|
|
dynstr_append_mem(ds, "\t", 1);
|
|
replace_dynstr_append_uint(ds, field->type);
|
|
dynstr_append_mem(ds, "\t", 1);
|
|
replace_dynstr_append_uint(ds, field->length);
|
|
dynstr_append_mem(ds, "\t", 1);
|
|
replace_dynstr_append_uint(ds, field->max_length);
|
|
dynstr_append_mem(ds, "\t", 1);
|
|
dynstr_append_mem(ds, (char*) (IS_NOT_NULL(field->flags) ?
|
|
"N" : "Y"), 1);
|
|
dynstr_append_mem(ds, "\t", 1);
|
|
replace_dynstr_append_uint(ds, field->flags);
|
|
dynstr_append_mem(ds, "\t", 1);
|
|
replace_dynstr_append_uint(ds, field->decimals);
|
|
dynstr_append_mem(ds, "\t", 1);
|
|
replace_dynstr_append_uint(ds, field->charsetnr);
|
|
dynstr_append_mem(ds, "\n", 1);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
Append affected row count and other info to output
|
|
*/
|
|
|
|
void append_info(DYNAMIC_STRING *ds, ulonglong affected_rows,
|
|
const char *info)
|
|
{
|
|
char buf[40], buff2[21];
|
|
sprintf(buf,"affected rows: %s\n", llstr(affected_rows, buff2));
|
|
dynstr_append(ds, buf);
|
|
if (info)
|
|
{
|
|
dynstr_append(ds, "info: ");
|
|
dynstr_append(ds, info);
|
|
dynstr_append_mem(ds, "\n", 1);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
Display the table headings with the names tab separated
|
|
*/
|
|
|
|
void append_table_headings(DYNAMIC_STRING *ds,
|
|
MYSQL_FIELD *field,
|
|
uint num_fields)
|
|
{
|
|
uint col_idx;
|
|
for (col_idx= 0; col_idx < num_fields; col_idx++)
|
|
{
|
|
if (col_idx)
|
|
dynstr_append_mem(ds, "\t", 1);
|
|
replace_dynstr_append(ds, field[col_idx].name);
|
|
}
|
|
dynstr_append_mem(ds, "\n", 1);
|
|
}
|
|
|
|
/*
|
|
Fetch warnings from server and append to ds
|
|
|
|
RETURN VALUE
|
|
Number of warnings appended to ds
|
|
*/
|
|
|
|
int append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql)
|
|
{
|
|
uint count;
|
|
MYSQL_RES *warn_res;
|
|
DBUG_ENTER("append_warnings");
|
|
|
|
if (!(count= mysql_warning_count(mysql)))
|
|
DBUG_RETURN(0);
|
|
|
|
/*
|
|
If one day we will support execution of multi-statements
|
|
through PS API we should not issue SHOW WARNINGS until
|
|
we have not read all results...
|
|
*/
|
|
DBUG_ASSERT(!mysql_more_results(mysql));
|
|
|
|
if (mysql_real_query(mysql, "SHOW WARNINGS", 13))
|
|
die("Error running query \"SHOW WARNINGS\": %s", mysql_error(mysql));
|
|
|
|
if (!(warn_res= mysql_store_result(mysql)))
|
|
die("Warning count is %u but didn't get any warnings",
|
|
count);
|
|
|
|
append_result(ds, warn_res);
|
|
mysql_free_result(warn_res);
|
|
|
|
DBUG_PRINT("warnings", ("%s", ds->str));
|
|
|
|
DBUG_RETURN(count);
|
|
}
|
|
|
|
|
|
/*
|
|
Run query using MySQL C API
|
|
|
|
SYNPOSIS
|
|
run_query_normal
|
|
mysql - mysql handle
|
|
command - currrent command pointer
|
|
flags -flags indicating wheter to SEND and/or REAP
|
|
query - query string to execute
|
|
query_len - length query string to execute
|
|
ds - output buffer wherte to store result form query
|
|
|
|
RETURN VALUE
|
|
error - function will not return
|
|
*/
|
|
|
|
void run_query_normal(struct st_connection *cn, struct st_command *command,
|
|
int flags, char *query, int query_len,
|
|
DYNAMIC_STRING *ds, DYNAMIC_STRING *ds_warnings)
|
|
{
|
|
MYSQL_RES *res= 0;
|
|
MYSQL *mysql= &cn->mysql;
|
|
int err= 0, counter= 0;
|
|
DBUG_ENTER("run_query_normal");
|
|
DBUG_PRINT("enter",("flags: %d", flags));
|
|
DBUG_PRINT("enter", ("query: '%-.60s'", query));
|
|
|
|
if (flags & QUERY_SEND_FLAG)
|
|
{
|
|
/*
|
|
Send the query
|
|
*/
|
|
if (do_send_query(cn, query, query_len, flags))
|
|
{
|
|
handle_error(command, mysql_errno(mysql), mysql_error(mysql),
|
|
mysql_sqlstate(mysql), ds);
|
|
goto end;
|
|
}
|
|
}
|
|
#ifdef EMBEDDED_LIBRARY
|
|
/*
|
|
Here we handle 'reap' command, so we need to check if the
|
|
query's thread was finished and probably wait
|
|
*/
|
|
else if (flags & QUERY_REAP_FLAG)
|
|
{
|
|
pthread_mutex_lock(&cn->mutex);
|
|
while (!cn->query_done)
|
|
pthread_cond_wait(&cn->cond, &cn->mutex);
|
|
pthread_mutex_unlock(&cn->mutex);
|
|
}
|
|
#endif /*EMBEDDED_LIBRARY*/
|
|
if (!(flags & QUERY_REAP_FLAG))
|
|
DBUG_VOID_RETURN;
|
|
|
|
do
|
|
{
|
|
/*
|
|
When on first result set, call mysql_read_query_result to retrieve
|
|
answer to the query sent earlier
|
|
*/
|
|
if ((counter==0) && mysql_read_query_result(mysql))
|
|
{
|
|
handle_error(command, mysql_errno(mysql), mysql_error(mysql),
|
|
mysql_sqlstate(mysql), ds);
|
|
goto end;
|
|
|
|
}
|
|
|
|
/*
|
|
Store the result. If res is NULL, use mysql_field_count to
|
|
determine if that was expected
|
|
*/
|
|
if (!(res= mysql_store_result(mysql)) && mysql_field_count(mysql))
|
|
{
|
|
handle_error(command, mysql_errno(mysql), mysql_error(mysql),
|
|
mysql_sqlstate(mysql), ds);
|
|
goto end;
|
|
}
|
|
|
|
if (!disable_result_log)
|
|
{
|
|
ulonglong affected_rows; /* Ok to be undef if 'disable_info' is set */
|
|
LINT_INIT(affected_rows);
|
|
|
|
if (res)
|
|
{
|
|
MYSQL_FIELD *fields= mysql_fetch_fields(res);
|
|
uint num_fields= mysql_num_fields(res);
|
|
|
|
if (display_metadata)
|
|
append_metadata(ds, fields, num_fields);
|
|
|
|
if (!display_result_vertically)
|
|
append_table_headings(ds, fields, num_fields);
|
|
|
|
append_result(ds, res);
|
|
}
|
|
|
|
/*
|
|
Need to call mysql_affected_rows() before the "new"
|
|
query to find the warnings
|
|
*/
|
|
if (!disable_info)
|
|
affected_rows= mysql_affected_rows(mysql);
|
|
|
|
/*
|
|
Add all warnings to the result. We can't do this if we are in
|
|
the middle of processing results from multi-statement, because
|
|
this will break protocol.
|
|
*/
|
|
if (!disable_warnings && !mysql_more_results(mysql))
|
|
{
|
|
if (append_warnings(ds_warnings, mysql) || ds_warnings->length)
|
|
{
|
|
dynstr_append_mem(ds, "Warnings:\n", 10);
|
|
dynstr_append_mem(ds, ds_warnings->str, ds_warnings->length);
|
|
}
|
|
}
|
|
|
|
if (!disable_info)
|
|
append_info(ds, affected_rows, mysql_info(mysql));
|
|
}
|
|
|
|
if (res)
|
|
mysql_free_result(res);
|
|
counter++;
|
|
} while (!(err= mysql_next_result(mysql)));
|
|
if (err > 0)
|
|
{
|
|
/* We got an error from mysql_next_result, maybe expected */
|
|
handle_error(command, mysql_errno(mysql), mysql_error(mysql),
|
|
mysql_sqlstate(mysql), ds);
|
|
goto end;
|
|
}
|
|
DBUG_ASSERT(err == -1); /* Successful and there are no more results */
|
|
|
|
/* If we come here the query is both executed and read successfully */
|
|
handle_no_error(command);
|
|
|
|
end:
|
|
|
|
/*
|
|
We save the return code (mysql_errno(mysql)) from the last call sent
|
|
to the server into the mysqltest builtin variable $mysql_errno. This
|
|
variable then can be used from the test case itself.
|
|
*/
|
|
var_set_errno(mysql_errno(mysql));
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
/*
|
|
Handle errors which occurred during execution
|
|
|
|
SYNOPSIS
|
|
handle_error()
|
|
q - query context
|
|
err_errno - error number
|
|
err_error - error message
|
|
err_sqlstate - sql state
|
|
ds - dynamic string which is used for output buffer
|
|
|
|
NOTE
|
|
If there is an unexpected error this function will abort mysqltest
|
|
immediately.
|
|
|
|
RETURN VALUE
|
|
error - function will not return
|
|
*/
|
|
|
|
void handle_error(struct st_command *command,
|
|
unsigned int err_errno, const char *err_error,
|
|
const char *err_sqlstate, DYNAMIC_STRING *ds)
|
|
{
|
|
uint i;
|
|
|
|
DBUG_ENTER("handle_error");
|
|
|
|
if (command->require_file[0])
|
|
{
|
|
/*
|
|
The query after a "--require" failed. This is fine as long the server
|
|
returned a valid reponse. Don't allow 2013 or 2006 to trigger an
|
|
abort_not_supported_test
|
|
*/
|
|
if (err_errno == CR_SERVER_LOST ||
|
|
err_errno == CR_SERVER_GONE_ERROR)
|
|
die("require query '%s' failed: %d: %s", command->query,
|
|
err_errno, err_error);
|
|
|
|
/* Abort the run of this test, pass the failed query as reason */
|
|
abort_not_supported_test("Query '%s' failed, required functionality" \
|
|
"not supported", command->query);
|
|
}
|
|
|
|
if (command->abort_on_error)
|
|
die("query '%s' failed: %d: %s", command->query, err_errno, err_error);
|
|
|
|
DBUG_PRINT("info", ("expected_errors.count: %d",
|
|
command->expected_errors.count));
|
|
for (i= 0 ; (uint) i < command->expected_errors.count ; i++)
|
|
{
|
|
if (((command->expected_errors.err[i].type == ERR_ERRNO) &&
|
|
(command->expected_errors.err[i].code.errnum == err_errno)) ||
|
|
((command->expected_errors.err[i].type == ERR_SQLSTATE) &&
|
|
(strncmp(command->expected_errors.err[i].code.sqlstate,
|
|
err_sqlstate, SQLSTATE_LENGTH) == 0)))
|
|
{
|
|
if (!disable_result_log)
|
|
{
|
|
if (command->expected_errors.count == 1)
|
|
{
|
|
/* Only log error if there is one possible error */
|
|
dynstr_append_mem(ds, "ERROR ", 6);
|
|
replace_dynstr_append(ds, err_sqlstate);
|
|
dynstr_append_mem(ds, ": ", 2);
|
|
replace_dynstr_append(ds, err_error);
|
|
dynstr_append_mem(ds,"\n",1);
|
|
}
|
|
/* Don't log error if we may not get an error */
|
|
else if (command->expected_errors.err[0].type == ERR_SQLSTATE ||
|
|
(command->expected_errors.err[0].type == ERR_ERRNO &&
|
|
command->expected_errors.err[0].code.errnum != 0))
|
|
dynstr_append(ds,"Got one of the listed errors\n");
|
|
}
|
|
/* OK */
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
}
|
|
|
|
DBUG_PRINT("info",("i: %d expected_errors: %d", i,
|
|
command->expected_errors.count));
|
|
|
|
if (!disable_result_log)
|
|
{
|
|
dynstr_append_mem(ds, "ERROR ",6);
|
|
replace_dynstr_append(ds, err_sqlstate);
|
|
dynstr_append_mem(ds, ": ", 2);
|
|
replace_dynstr_append(ds, err_error);
|
|
dynstr_append_mem(ds, "\n", 1);
|
|
}
|
|
|
|
if (i)
|
|
{
|
|
if (command->expected_errors.err[0].type == ERR_ERRNO)
|
|
die("query '%s' failed with wrong errno %d: '%s', instead of %d...",
|
|
command->query, err_errno, err_error,
|
|
command->expected_errors.err[0].code.errnum);
|
|
else
|
|
die("query '%s' failed with wrong sqlstate %s: '%s', instead of %s...",
|
|
command->query, err_sqlstate, err_error,
|
|
command->expected_errors.err[0].code.sqlstate);
|
|
}
|
|
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
/*
|
|
Handle absence of errors after execution
|
|
|
|
SYNOPSIS
|
|
handle_no_error()
|
|
q - context of query
|
|
|
|
RETURN VALUE
|
|
error - function will not return
|
|
*/
|
|
|
|
void handle_no_error(struct st_command *command)
|
|
{
|
|
DBUG_ENTER("handle_no_error");
|
|
|
|
if (command->expected_errors.err[0].type == ERR_ERRNO &&
|
|
command->expected_errors.err[0].code.errnum != 0)
|
|
{
|
|
/* Error code we wanted was != 0, i.e. not an expected success */
|
|
die("query '%s' succeeded - should have failed with errno %d...",
|
|
command->query, command->expected_errors.err[0].code.errnum);
|
|
}
|
|
else if (command->expected_errors.err[0].type == ERR_SQLSTATE &&
|
|
strcmp(command->expected_errors.err[0].code.sqlstate,"00000") != 0)
|
|
{
|
|
/* SQLSTATE we wanted was != "00000", i.e. not an expected success */
|
|
die("query '%s' succeeded - should have failed with sqlstate %s...",
|
|
command->query, command->expected_errors.err[0].code.sqlstate);
|
|
}
|
|
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
/*
|
|
Run query using prepared statement C API
|
|
|
|
SYNPOSIS
|
|
run_query_stmt
|
|
mysql - mysql handle
|
|
command - currrent command pointer
|
|
query - query string to execute
|
|
query_len - length query string to execute
|
|
ds - output buffer where to store result form query
|
|
|
|
RETURN VALUE
|
|
error - function will not return
|
|
*/
|
|
|
|
void run_query_stmt(MYSQL *mysql, struct st_command *command,
|
|
char *query, int query_len, DYNAMIC_STRING *ds,
|
|
DYNAMIC_STRING *ds_warnings)
|
|
{
|
|
MYSQL_RES *res= NULL; /* Note that here 'res' is meta data result set */
|
|
MYSQL_STMT *stmt;
|
|
DYNAMIC_STRING ds_prepare_warnings;
|
|
DYNAMIC_STRING ds_execute_warnings;
|
|
DBUG_ENTER("run_query_stmt");
|
|
DBUG_PRINT("query", ("'%-.60s'", query));
|
|
|
|
/*
|
|
Init a new stmt if it's not already one created for this connection
|
|
*/
|
|
if(!(stmt= cur_con->stmt))
|
|
{
|
|
if (!(stmt= mysql_stmt_init(mysql)))
|
|
die("unable to init stmt structure");
|
|
cur_con->stmt= stmt;
|
|
}
|
|
|
|
/* Init dynamic strings for warnings */
|
|
if (!disable_warnings)
|
|
{
|
|
init_dynamic_string(&ds_prepare_warnings, NULL, 0, 256);
|
|
init_dynamic_string(&ds_execute_warnings, NULL, 0, 256);
|
|
}
|
|
|
|
/*
|
|
Prepare the query
|
|
*/
|
|
if (mysql_stmt_prepare(stmt, query, query_len))
|
|
{
|
|
handle_error(command, mysql_stmt_errno(stmt),
|
|
mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds);
|
|
goto end;
|
|
}
|
|
|
|
/*
|
|
Get the warnings from mysql_stmt_prepare and keep them in a
|
|
separate string
|
|
*/
|
|
if (!disable_warnings)
|
|
append_warnings(&ds_prepare_warnings, mysql);
|
|
|
|
/*
|
|
No need to call mysql_stmt_bind_param() because we have no
|
|
parameter markers.
|
|
*/
|
|
|
|
#if MYSQL_VERSION_ID >= 50000
|
|
if (cursor_protocol_enabled)
|
|
{
|
|
/*
|
|
Use cursor when retrieving result
|
|
*/
|
|
ulong type= CURSOR_TYPE_READ_ONLY;
|
|
if (mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type))
|
|
die("mysql_stmt_attr_set(STMT_ATTR_CURSOR_TYPE) failed': %d %s",
|
|
mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
Execute the query
|
|
*/
|
|
if (mysql_stmt_execute(stmt))
|
|
{
|
|
handle_error(command, mysql_stmt_errno(stmt),
|
|
mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds);
|
|
goto end;
|
|
}
|
|
|
|
/*
|
|
When running in cursor_protocol get the warnings from execute here
|
|
and keep them in a separate string for later.
|
|
*/
|
|
if (cursor_protocol_enabled && !disable_warnings)
|
|
append_warnings(&ds_execute_warnings, mysql);
|
|
|
|
/*
|
|
We instruct that we want to update the "max_length" field in
|
|
mysql_stmt_store_result(), this is our only way to know how much
|
|
buffer to allocate for result data
|
|
*/
|
|
{
|
|
my_bool one= 1;
|
|
if (mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*) &one))
|
|
die("mysql_stmt_attr_set(STMT_ATTR_UPDATE_MAX_LENGTH) failed': %d %s",
|
|
mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
|
|
}
|
|
|
|
/*
|
|
If we got here the statement succeeded and was expected to do so,
|
|
get data. Note that this can still give errors found during execution!
|
|
*/
|
|
if (mysql_stmt_store_result(stmt))
|
|
{
|
|
handle_error(command, mysql_stmt_errno(stmt),
|
|
mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds);
|
|
goto end;
|
|
}
|
|
|
|
/* If we got here the statement was both executed and read successfully */
|
|
handle_no_error(command);
|
|
if (!disable_result_log)
|
|
{
|
|
/*
|
|
Not all statements creates a result set. If there is one we can
|
|
now create another normal result set that contains the meta
|
|
data. This set can be handled almost like any other non prepared
|
|
statement result set.
|
|
*/
|
|
if ((res= mysql_stmt_result_metadata(stmt)) != NULL)
|
|
{
|
|
/* Take the column count from meta info */
|
|
MYSQL_FIELD *fields= mysql_fetch_fields(res);
|
|
uint num_fields= mysql_num_fields(res);
|
|
|
|
if (display_metadata)
|
|
append_metadata(ds, fields, num_fields);
|
|
|
|
if (!display_result_vertically)
|
|
append_table_headings(ds, fields, num_fields);
|
|
|
|
append_stmt_result(ds, stmt, fields, num_fields);
|
|
|
|
mysql_free_result(res); /* Free normal result set with meta data */
|
|
|
|
/* Clear prepare warnings */
|
|
dynstr_set(&ds_prepare_warnings, NULL);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
This is a query without resultset
|
|
*/
|
|
}
|
|
|
|
if (!disable_warnings)
|
|
{
|
|
/* Get the warnings from execute */
|
|
|
|
/* Append warnings to ds - if there are any */
|
|
if (append_warnings(&ds_execute_warnings, mysql) ||
|
|
ds_execute_warnings.length ||
|
|
ds_prepare_warnings.length ||
|
|
ds_warnings->length)
|
|
{
|
|
dynstr_append_mem(ds, "Warnings:\n", 10);
|
|
if (ds_warnings->length)
|
|
dynstr_append_mem(ds, ds_warnings->str,
|
|
ds_warnings->length);
|
|
if (ds_prepare_warnings.length)
|
|
dynstr_append_mem(ds, ds_prepare_warnings.str,
|
|
ds_prepare_warnings.length);
|
|
if (ds_execute_warnings.length)
|
|
dynstr_append_mem(ds, ds_execute_warnings.str,
|
|
ds_execute_warnings.length);
|
|
}
|
|
}
|
|
|
|
if (!disable_info)
|
|
append_info(ds, mysql_affected_rows(mysql), mysql_info(mysql));
|
|
|
|
}
|
|
|
|
end:
|
|
if (!disable_warnings)
|
|
{
|
|
dynstr_free(&ds_prepare_warnings);
|
|
dynstr_free(&ds_execute_warnings);
|
|
}
|
|
|
|
/*
|
|
We save the return code (mysql_stmt_errno(stmt)) from the last call sent
|
|
to the server into the mysqltest builtin variable $mysql_errno. This
|
|
variable then can be used from the test case itself.
|
|
*/
|
|
|
|
var_set_errno(mysql_stmt_errno(stmt));
|
|
#ifndef BUG15518_FIXED
|
|
mysql_stmt_close(stmt);
|
|
cur_con->stmt= NULL;
|
|
#endif
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
Create a util connection if one does not already exists
|
|
and use that to run the query
|
|
This is done to avoid implict commit when creating/dropping objects such
|
|
as view, sp etc.
|
|
*/
|
|
|
|
int util_query(MYSQL* org_mysql, const char* query){
|
|
|
|
MYSQL* mysql;
|
|
DBUG_ENTER("util_query");
|
|
|
|
if(!(mysql= cur_con->util_mysql))
|
|
{
|
|
DBUG_PRINT("info", ("Creating util_mysql"));
|
|
if (!(mysql= mysql_init(mysql)))
|
|
die("Failed in mysql_init()");
|
|
|
|
safe_connect(mysql, "util", org_mysql->host, org_mysql->user,
|
|
org_mysql->passwd, org_mysql->db, org_mysql->port,
|
|
org_mysql->unix_socket);
|
|
|
|
cur_con->util_mysql= mysql;
|
|
}
|
|
|
|
return mysql_query(mysql, query);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
Run query
|
|
|
|
flags control the phased/stages of query execution to be performed
|
|
if QUERY_SEND_FLAG bit is on, the query will be sent. If QUERY_REAP_FLAG
|
|
is on the result will be read - for regular query, both bits must be on
|
|
|
|
SYNPOSIS
|
|
run_query
|
|
mysql - mysql handle
|
|
command - currrent command pointer
|
|
|
|
*/
|
|
|
|
void run_query(struct st_connection *cn, struct st_command *command, int flags)
|
|
{
|
|
MYSQL *mysql= &cn->mysql;
|
|
DYNAMIC_STRING *ds;
|
|
DYNAMIC_STRING ds_result;
|
|
DYNAMIC_STRING ds_warnings;
|
|
DYNAMIC_STRING eval_query;
|
|
char *query;
|
|
int query_len;
|
|
my_bool view_created= 0, sp_created= 0;
|
|
my_bool complete_query= ((flags & QUERY_SEND_FLAG) &&
|
|
(flags & QUERY_REAP_FLAG));
|
|
|
|
init_dynamic_string(&ds_warnings, NULL, 0, 256);
|
|
|
|
/* Scan for warning before sendign to server */
|
|
scan_command_for_warnings(command);
|
|
|
|
/*
|
|
Evaluate query if this is an eval command
|
|
*/
|
|
if (command->type == Q_EVAL)
|
|
{
|
|
init_dynamic_string(&eval_query, "", command->query_len+256, 1024);
|
|
do_eval(&eval_query, command->query, command->end, FALSE);
|
|
query = eval_query.str;
|
|
query_len = eval_query.length;
|
|
}
|
|
else
|
|
{
|
|
query = command->query;
|
|
query_len = strlen(query);
|
|
}
|
|
|
|
/*
|
|
When command->require_file is set the output of _this_ query
|
|
should be compared with an already existing file
|
|
Create a temporary dynamic string to contain the output from
|
|
this query.
|
|
*/
|
|
if (command->require_file[0])
|
|
{
|
|
init_dynamic_string(&ds_result, "", 1024, 1024);
|
|
ds= &ds_result;
|
|
}
|
|
else
|
|
ds= &ds_res;
|
|
|
|
/*
|
|
Log the query into the output buffer
|
|
*/
|
|
if (!disable_query_log && (flags & QUERY_SEND_FLAG))
|
|
{
|
|
replace_dynstr_append_mem(ds, query, query_len);
|
|
dynstr_append_mem(ds, delimiter, delimiter_length);
|
|
dynstr_append_mem(ds, "\n", 1);
|
|
}
|
|
|
|
if (view_protocol_enabled &&
|
|
complete_query &&
|
|
match_re(&view_re, query))
|
|
{
|
|
/*
|
|
Create the query as a view.
|
|
Use replace since view can exist from a failed mysqltest run
|
|
*/
|
|
DYNAMIC_STRING query_str;
|
|
init_dynamic_string(&query_str,
|
|
"CREATE OR REPLACE VIEW mysqltest_tmp_v AS ",
|
|
query_len+64, 256);
|
|
dynstr_append_mem(&query_str, query, query_len);
|
|
if (util_query(mysql, query_str.str))
|
|
{
|
|
/*
|
|
Failed to create the view, this is not fatal
|
|
just run the query the normal way
|
|
*/
|
|
DBUG_PRINT("view_create_error",
|
|
("Failed to create view '%s': %d: %s", query_str.str,
|
|
mysql_errno(mysql), mysql_error(mysql)));
|
|
|
|
/* Log error to create view */
|
|
verbose_msg("Failed to create view '%s' %d: %s", query_str.str,
|
|
mysql_errno(mysql), mysql_error(mysql));
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
Yes, it was possible to create this query as a view
|
|
*/
|
|
view_created= 1;
|
|
query= (char*)"SELECT * FROM mysqltest_tmp_v";
|
|
query_len = strlen(query);
|
|
|
|
/*
|
|
Collect warnings from create of the view that should otherwise
|
|
have been produced when the SELECT was executed
|
|
*/
|
|
append_warnings(&ds_warnings, cur_con->util_mysql);
|
|
}
|
|
|
|
dynstr_free(&query_str);
|
|
|
|
}
|
|
|
|
if (sp_protocol_enabled &&
|
|
complete_query &&
|
|
match_re(&sp_re, query))
|
|
{
|
|
/*
|
|
Create the query as a stored procedure
|
|
Drop first since sp can exist from a failed mysqltest run
|
|
*/
|
|
DYNAMIC_STRING query_str;
|
|
init_dynamic_string(&query_str,
|
|
"DROP PROCEDURE IF EXISTS mysqltest_tmp_sp;",
|
|
query_len+64, 256);
|
|
util_query(mysql, query_str.str);
|
|
dynstr_set(&query_str, "CREATE PROCEDURE mysqltest_tmp_sp()\n");
|
|
dynstr_append_mem(&query_str, query, query_len);
|
|
if (util_query(mysql, query_str.str))
|
|
{
|
|
/*
|
|
Failed to create the stored procedure for this query,
|
|
this is not fatal just run the query the normal way
|
|
*/
|
|
DBUG_PRINT("sp_create_error",
|
|
("Failed to create sp '%s': %d: %s", query_str.str,
|
|
mysql_errno(mysql), mysql_error(mysql)));
|
|
|
|
/* Log error to create sp */
|
|
verbose_msg("Failed to create sp '%s' %d: %s", query_str.str,
|
|
mysql_errno(mysql), mysql_error(mysql));
|
|
|
|
}
|
|
else
|
|
{
|
|
sp_created= 1;
|
|
|
|
query= (char*)"CALL mysqltest_tmp_sp()";
|
|
query_len = strlen(query);
|
|
}
|
|
dynstr_free(&query_str);
|
|
}
|
|
|
|
/*
|
|
Find out how to run this query
|
|
|
|
Always run with normal C API if it's not a complete
|
|
SEND + REAP
|
|
|
|
If it is a '?' in the query it may be a SQL level prepared
|
|
statement already and we can't do it twice
|
|
*/
|
|
if (ps_protocol_enabled &&
|
|
complete_query &&
|
|
match_re(&ps_re, query))
|
|
run_query_stmt(mysql, command, query, query_len, ds, &ds_warnings);
|
|
else
|
|
run_query_normal(cn, command, flags, query, query_len,
|
|
ds, &ds_warnings);
|
|
|
|
if (sp_created)
|
|
{
|
|
if (util_query(mysql, "DROP PROCEDURE mysqltest_tmp_sp "))
|
|
die("Failed to drop sp: %d: %s", mysql_errno(mysql), mysql_error(mysql));
|
|
}
|
|
|
|
if (view_created)
|
|
{
|
|
if (util_query(mysql, "DROP VIEW mysqltest_tmp_v "))
|
|
die("Failed to drop view: %d: %s",
|
|
mysql_errno(mysql), mysql_error(mysql));
|
|
}
|
|
|
|
if (command->require_file[0])
|
|
{
|
|
|
|
/* A result file was specified for _this_ query
|
|
and the output should be checked against an already
|
|
existing file which has been specified using --require or --result
|
|
*/
|
|
check_require(ds, command->require_file);
|
|
}
|
|
|
|
dynstr_free(&ds_warnings);
|
|
if (ds == &ds_result)
|
|
dynstr_free(&ds_result);
|
|
if (command->type == Q_EVAL)
|
|
dynstr_free(&eval_query);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/*
|
|
Functions to detect different SQL statements
|
|
*/
|
|
|
|
char *re_eprint(int err)
|
|
{
|
|
static char epbuf[100];
|
|
size_t len= my_regerror(REG_ITOA|err, (my_regex_t *)NULL,
|
|
epbuf, sizeof(epbuf));
|
|
assert(len <= sizeof(epbuf));
|
|
return(epbuf);
|
|
}
|
|
|
|
void init_re_comp(my_regex_t *re, const char* str)
|
|
{
|
|
int err= my_regcomp(re, str, (REG_EXTENDED | REG_ICASE | REG_NOSUB),
|
|
&my_charset_latin1);
|
|
if (err)
|
|
{
|
|
char erbuf[100];
|
|
int len= my_regerror(err, re, erbuf, sizeof(erbuf));
|
|
die("error %s, %d/%d `%s'\n",
|
|
re_eprint(err), len, (int)sizeof(erbuf), erbuf);
|
|
}
|
|
}
|
|
|
|
void init_re(void)
|
|
{
|
|
/*
|
|
Filter for queries that can be run using the
|
|
MySQL Prepared Statements C API
|
|
*/
|
|
const char *ps_re_str =
|
|
"^("
|
|
"[[:space:]]*REPLACE[[:space:]]|"
|
|
"[[:space:]]*INSERT[[:space:]]|"
|
|
"[[:space:]]*UPDATE[[:space:]]|"
|
|
"[[:space:]]*DELETE[[:space:]]|"
|
|
"[[:space:]]*SELECT[[:space:]]|"
|
|
"[[:space:]]*CREATE[[:space:]]+TABLE[[:space:]]|"
|
|
"[[:space:]]*DO[[:space:]]|"
|
|
"[[:space:]]*SET[[:space:]]+OPTION[[:space:]]|"
|
|
"[[:space:]]*DELETE[[:space:]]+MULTI[[:space:]]|"
|
|
"[[:space:]]*UPDATE[[:space:]]+MULTI[[:space:]]|"
|
|
"[[:space:]]*INSERT[[:space:]]+SELECT[[:space:]])";
|
|
|
|
/*
|
|
Filter for queries that can be run using the
|
|
Stored procedures
|
|
*/
|
|
const char *sp_re_str =ps_re_str;
|
|
|
|
/*
|
|
Filter for queries that can be run as views
|
|
*/
|
|
const char *view_re_str =
|
|
"^("
|
|
"[[:space:]]*SELECT[[:space:]])";
|
|
|
|
init_re_comp(&ps_re, ps_re_str);
|
|
init_re_comp(&sp_re, sp_re_str);
|
|
init_re_comp(&view_re, view_re_str);
|
|
}
|
|
|
|
|
|
int match_re(my_regex_t *re, char *str)
|
|
{
|
|
int err= my_regexec(re, str, (size_t)0, NULL, 0);
|
|
|
|
if (err == 0)
|
|
return 1;
|
|
else if (err == REG_NOMATCH)
|
|
return 0;
|
|
|
|
{
|
|
char erbuf[100];
|
|
int len= my_regerror(err, re, erbuf, sizeof(erbuf));
|
|
die("error %s, %d/%d `%s'\n",
|
|
re_eprint(err), len, (int)sizeof(erbuf), erbuf);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void free_re(void)
|
|
{
|
|
my_regfree(&ps_re);
|
|
my_regfree(&sp_re);
|
|
my_regfree(&view_re);
|
|
my_regex_end();
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
void get_command_type(struct st_command* command)
|
|
{
|
|
char save;
|
|
uint type;
|
|
DBUG_ENTER("get_command_type");
|
|
|
|
if (*command->query == '}')
|
|
{
|
|
command->type = Q_END_BLOCK;
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
save= command->query[command->first_word_len];
|
|
command->query[command->first_word_len]= 0;
|
|
type= find_type(command->query, &command_typelib, 1+2);
|
|
command->query[command->first_word_len]= save;
|
|
if (type > 0)
|
|
{
|
|
command->type=(enum enum_commands) type; /* Found command */
|
|
|
|
/*
|
|
Look for case where "query" was explicitly specified to
|
|
force command being sent to server
|
|
*/
|
|
if (type == Q_QUERY)
|
|
{
|
|
/* Skip the "query" part */
|
|
command->query= command->first_argument;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* No mysqltest command matched */
|
|
|
|
if (command->type != Q_COMMENT_WITH_COMMAND)
|
|
{
|
|
/* A query that will sent to mysqld */
|
|
command->type= Q_QUERY;
|
|
}
|
|
else
|
|
{
|
|
/* -- comment that didn't contain a mysqltest command */
|
|
command->type= Q_COMMENT;
|
|
warning_msg("Suspicious command '--%s' detected, was this intentional? "\
|
|
"Use # instead of -- to avoid this warning",
|
|
command->query);
|
|
|
|
if (command->first_word_len &&
|
|
strcmp(command->query + command->first_word_len - 1, delimiter) == 0)
|
|
{
|
|
/*
|
|
Detect comment with command using extra delimiter
|
|
Ex --disable_query_log;
|
|
^ Extra delimiter causing the command
|
|
to be skipped
|
|
*/
|
|
save= command->query[command->first_word_len-1];
|
|
command->query[command->first_word_len-1]= 0;
|
|
if (find_type(command->query, &command_typelib, 1+2) > 0)
|
|
die("Extra delimiter \";\" found");
|
|
command->query[command->first_word_len-1]= save;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Set expected error on command */
|
|
memcpy(&command->expected_errors, &saved_expected_errors,
|
|
sizeof(saved_expected_errors));
|
|
DBUG_PRINT("info", ("There are %d expected errors",
|
|
command->expected_errors.count));
|
|
command->abort_on_error= (command->expected_errors.count == 0 &&
|
|
abort_on_error);
|
|
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
Record how many milliseconds it took to execute the test file
|
|
up until the current line and save it in the dynamic string ds_progress.
|
|
|
|
The ds_progress will be dumped to <test_name>.progress when
|
|
test run completes
|
|
|
|
*/
|
|
|
|
void mark_progress(struct st_command* command __attribute__((unused)),
|
|
int line)
|
|
{
|
|
char buf[32], *end;
|
|
ulonglong timer= timer_now();
|
|
if (!progress_start)
|
|
progress_start= timer;
|
|
timer-= progress_start;
|
|
|
|
/* Milliseconds since start */
|
|
end= longlong2str(timer, buf, 10);
|
|
dynstr_append_mem(&ds_progress, buf, (int)(end-buf));
|
|
dynstr_append_mem(&ds_progress, "\t", 1);
|
|
|
|
/* Parser line number */
|
|
end= int10_to_str(line, buf, 10);
|
|
dynstr_append_mem(&ds_progress, buf, (int)(end-buf));
|
|
dynstr_append_mem(&ds_progress, "\t", 1);
|
|
|
|
/* Filename */
|
|
dynstr_append(&ds_progress, cur_file->file_name);
|
|
dynstr_append_mem(&ds_progress, ":", 1);
|
|
|
|
/* Line in file */
|
|
end= int10_to_str(cur_file->lineno, buf, 10);
|
|
dynstr_append_mem(&ds_progress, buf, (int)(end-buf));
|
|
|
|
|
|
dynstr_append_mem(&ds_progress, "\n", 1);
|
|
|
|
}
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
struct st_command *command;
|
|
my_bool q_send_flag= 0, abort_flag= 0;
|
|
uint command_executed= 0, last_command_executed= 0;
|
|
char save_file[FN_REFLEN];
|
|
MY_STAT res_info;
|
|
MY_INIT(argv[0]);
|
|
|
|
save_file[0]= 0;
|
|
TMPDIR[0]= 0;
|
|
|
|
/* Init expected errors */
|
|
memset(&saved_expected_errors, 0, sizeof(saved_expected_errors));
|
|
|
|
/* Init connections */
|
|
memset(connections, 0, sizeof(connections));
|
|
connections_end= connections +
|
|
(sizeof(connections)/sizeof(struct st_connection)) - 1;
|
|
next_con= connections + 1;
|
|
cur_con= connections;
|
|
|
|
/* Init file stack */
|
|
memset(file_stack, 0, sizeof(file_stack));
|
|
file_stack_end=
|
|
file_stack + (sizeof(file_stack)/sizeof(struct st_test_file)) - 1;
|
|
cur_file= file_stack;
|
|
|
|
/* Init block stack */
|
|
memset(block_stack, 0, sizeof(block_stack));
|
|
block_stack_end=
|
|
block_stack + (sizeof(block_stack)/sizeof(struct st_block)) - 1;
|
|
cur_block= block_stack;
|
|
cur_block->ok= TRUE; /* Outer block should always be executed */
|
|
cur_block->cmd= cmd_none;
|
|
|
|
my_init_dynamic_array(&q_lines, sizeof(struct st_command*), 1024, 1024);
|
|
|
|
if (hash_init(&var_hash, charset_info,
|
|
1024, 0, 0, get_var_key, var_free, MYF(0)))
|
|
die("Variable hash initialization failed");
|
|
|
|
memset(&master_pos, 0, sizeof(master_pos));
|
|
|
|
parser.current_line= parser.read_lines= 0;
|
|
memset(&var_reg, 0, sizeof(var_reg));
|
|
|
|
#ifdef __WIN__
|
|
init_tmp_sh_file();
|
|
init_win_path_patterns();
|
|
#endif
|
|
|
|
init_dynamic_string(&ds_res, "", 65536, 65536);
|
|
init_dynamic_string(&ds_progress, "", 0, 2048);
|
|
init_dynamic_string(&ds_warning_messages, "", 0, 2048);
|
|
parse_args(argc, argv);
|
|
|
|
DBUG_PRINT("info",("result_file: '%s'",
|
|
result_file_name ? result_file_name : ""));
|
|
if (mysql_server_init(embedded_server_arg_count,
|
|
embedded_server_args,
|
|
(char**) embedded_server_groups))
|
|
die("Can't initialize MySQL server");
|
|
server_initialized= 1;
|
|
if (cur_file == file_stack && cur_file->file == 0)
|
|
{
|
|
cur_file->file= stdin;
|
|
cur_file->file_name= my_strdup("<stdin>", MYF(MY_WME));
|
|
cur_file->lineno= 1;
|
|
}
|
|
init_re();
|
|
ps_protocol_enabled= ps_protocol;
|
|
sp_protocol_enabled= sp_protocol;
|
|
view_protocol_enabled= view_protocol;
|
|
cursor_protocol_enabled= cursor_protocol;
|
|
/* Cursor protcol implies ps protocol */
|
|
if (cursor_protocol_enabled)
|
|
ps_protocol_enabled= 1;
|
|
|
|
if (!( mysql_init(&cur_con->mysql)))
|
|
die("Failed in mysql_init()");
|
|
if (opt_compress)
|
|
mysql_options(&cur_con->mysql,MYSQL_OPT_COMPRESS,NullS);
|
|
mysql_options(&cur_con->mysql, MYSQL_OPT_LOCAL_INFILE, 0);
|
|
mysql_options(&cur_con->mysql, MYSQL_SET_CHARSET_NAME,
|
|
charset_info->csname);
|
|
if (opt_charsets_dir)
|
|
mysql_options(&cur_con->mysql, MYSQL_SET_CHARSET_DIR,
|
|
opt_charsets_dir);
|
|
|
|
#ifdef HAVE_OPENSSL
|
|
|
|
#if MYSQL_VERSION_ID >= 50000
|
|
opt_ssl_verify_server_cert= TRUE; /* Always on in mysqltest */
|
|
#endif
|
|
|
|
if (opt_use_ssl)
|
|
{
|
|
mysql_ssl_set(&cur_con->mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
|
|
opt_ssl_capath, opt_ssl_cipher);
|
|
#if MYSQL_VERSION_ID >= 50000
|
|
mysql_options(&cur_con->mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
|
|
&opt_ssl_verify_server_cert);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
if (!(cur_con->name = my_strdup("default", MYF(MY_WME))))
|
|
die("Out of memory");
|
|
|
|
safe_connect(&cur_con->mysql, cur_con->name, host, user, pass,
|
|
db, port, unix_sock);
|
|
|
|
/* Use all time until exit if no explicit 'start_timer' */
|
|
timer_start= timer_now();
|
|
|
|
/*
|
|
Initialize $mysql_errno with -1, so we can
|
|
- distinguish it from valid values ( >= 0 ) and
|
|
- detect if there was never a command sent to the server
|
|
*/
|
|
var_set_errno(-1);
|
|
|
|
if (opt_include)
|
|
{
|
|
open_file(opt_include);
|
|
}
|
|
|
|
while (!read_command(&command) && !abort_flag)
|
|
{
|
|
int current_line_inc = 1, processed = 0;
|
|
if (command->type == Q_UNKNOWN || command->type == Q_COMMENT_WITH_COMMAND)
|
|
get_command_type(command);
|
|
|
|
if (parsing_disabled &&
|
|
command->type != Q_ENABLE_PARSING &&
|
|
command->type != Q_DISABLE_PARSING)
|
|
{
|
|
command->type= Q_COMMENT;
|
|
scan_command_for_warnings(command);
|
|
}
|
|
|
|
if (cur_block->ok)
|
|
{
|
|
command->last_argument= command->first_argument;
|
|
processed = 1;
|
|
switch (command->type) {
|
|
case Q_CONNECT:
|
|
do_connect(command);
|
|
break;
|
|
case Q_CONNECTION: select_connection(command); break;
|
|
case Q_DISCONNECT:
|
|
case Q_DIRTY_CLOSE:
|
|
do_close_connection(command); break;
|
|
case Q_RPL_PROBE: do_rpl_probe(command); break;
|
|
case Q_ENABLE_RPL_PARSE: do_enable_rpl_parse(command); break;
|
|
case Q_DISABLE_RPL_PARSE: do_disable_rpl_parse(command); break;
|
|
case Q_ENABLE_QUERY_LOG: disable_query_log=0; break;
|
|
case Q_DISABLE_QUERY_LOG: disable_query_log=1; break;
|
|
case Q_ENABLE_ABORT_ON_ERROR: abort_on_error=1; break;
|
|
case Q_DISABLE_ABORT_ON_ERROR: abort_on_error=0; break;
|
|
case Q_ENABLE_RESULT_LOG: disable_result_log=0; break;
|
|
case Q_DISABLE_RESULT_LOG: disable_result_log=1; break;
|
|
case Q_ENABLE_WARNINGS: disable_warnings=0; break;
|
|
case Q_DISABLE_WARNINGS: disable_warnings=1; break;
|
|
case Q_ENABLE_PS_WARNINGS: disable_ps_warnings=0; break;
|
|
case Q_DISABLE_PS_WARNINGS: disable_ps_warnings=1; break;
|
|
case Q_ENABLE_INFO: disable_info=0; break;
|
|
case Q_DISABLE_INFO: disable_info=1; break;
|
|
case Q_ENABLE_METADATA: display_metadata=1; break;
|
|
case Q_DISABLE_METADATA: display_metadata=0; break;
|
|
case Q_SOURCE: do_source(command); break;
|
|
case Q_SLEEP: do_sleep(command, 0); break;
|
|
case Q_REAL_SLEEP: do_sleep(command, 1); break;
|
|
case Q_WAIT_FOR_SLAVE_TO_STOP: do_wait_for_slave_to_stop(command); break;
|
|
case Q_INC: do_modify_var(command, DO_INC); break;
|
|
case Q_DEC: do_modify_var(command, DO_DEC); break;
|
|
case Q_ECHO: do_echo(command); command_executed++; break;
|
|
case Q_SYSTEM: do_system(command); break;
|
|
case Q_REMOVE_FILE: do_remove_file(command); break;
|
|
case Q_FILE_EXIST: do_file_exist(command); break;
|
|
case Q_WRITE_FILE: do_write_file(command); break;
|
|
case Q_COPY_FILE: do_copy_file(command); break;
|
|
case Q_CHMOD_FILE: do_chmod_file(command); break;
|
|
case Q_PERL: do_perl(command); break;
|
|
case Q_DELIMITER:
|
|
do_delimiter(command);
|
|
break;
|
|
case Q_DISPLAY_VERTICAL_RESULTS:
|
|
display_result_vertically= TRUE;
|
|
break;
|
|
case Q_DISPLAY_HORIZONTAL_RESULTS:
|
|
display_result_vertically= FALSE;
|
|
break;
|
|
case Q_LET: do_let(command); break;
|
|
case Q_EVAL_RESULT:
|
|
eval_result = 1; break;
|
|
case Q_EVAL:
|
|
if (command->query == command->query_buf)
|
|
{
|
|
command->query= command->first_argument;
|
|
command->first_word_len= 0;
|
|
}
|
|
/* fall through */
|
|
case Q_QUERY_VERTICAL:
|
|
case Q_QUERY_HORIZONTAL:
|
|
{
|
|
my_bool old_display_result_vertically= display_result_vertically;
|
|
|
|
/* Remove "query_*" if this is first iteration */
|
|
if (command->query == command->query_buf)
|
|
command->query= command->first_argument;
|
|
|
|
display_result_vertically= (command->type == Q_QUERY_VERTICAL);
|
|
if (save_file[0])
|
|
{
|
|
strmake(command->require_file, save_file, sizeof(save_file));
|
|
save_file[0]= 0;
|
|
}
|
|
run_query(cur_con, command, QUERY_REAP_FLAG|QUERY_SEND_FLAG);
|
|
display_result_vertically= old_display_result_vertically;
|
|
command->last_argument= command->end;
|
|
command_executed++;
|
|
break;
|
|
}
|
|
case Q_QUERY:
|
|
case Q_REAP:
|
|
{
|
|
int flags;
|
|
if (q_send_flag)
|
|
{
|
|
/* Last command was an empty 'send' */
|
|
flags= QUERY_SEND_FLAG;
|
|
q_send_flag= 0;
|
|
}
|
|
else if (command->type == Q_REAP)
|
|
{
|
|
flags= QUERY_REAP_FLAG;
|
|
}
|
|
else
|
|
{
|
|
/* full query, both reap and send */
|
|
flags= QUERY_REAP_FLAG | QUERY_SEND_FLAG;
|
|
}
|
|
|
|
if (save_file[0])
|
|
{
|
|
strmake(command->require_file, save_file, sizeof(save_file));
|
|
save_file[0]= 0;
|
|
}
|
|
run_query(cur_con, command, flags);
|
|
command_executed++;
|
|
command->last_argument= command->end;
|
|
break;
|
|
}
|
|
case Q_SEND:
|
|
if (!*command->first_argument)
|
|
{
|
|
/*
|
|
This is a send without arguments, it indicates that _next_ query
|
|
should be send only
|
|
*/
|
|
q_send_flag= 1;
|
|
break;
|
|
}
|
|
|
|
/* Remove "send" if this is first iteration */
|
|
if (command->query == command->query_buf)
|
|
command->query= command->first_argument;
|
|
|
|
/*
|
|
run_query() can execute a query partially, depending on the flags.
|
|
QUERY_SEND_FLAG flag without QUERY_REAP_FLAG tells it to just send
|
|
the query and read the result some time later when reap instruction
|
|
is given on this connection.
|
|
*/
|
|
run_query(cur_con, command, QUERY_SEND_FLAG);
|
|
command_executed++;
|
|
command->last_argument= command->end;
|
|
break;
|
|
case Q_REQUIRE:
|
|
do_get_file_name(command, save_file, sizeof(save_file));
|
|
break;
|
|
case Q_ERROR:
|
|
do_get_errcodes(command);
|
|
break;
|
|
case Q_REPLACE:
|
|
do_get_replace(command);
|
|
break;
|
|
case Q_REPLACE_REGEX:
|
|
do_get_replace_regex(command);
|
|
break;
|
|
case Q_REPLACE_COLUMN:
|
|
do_get_replace_column(command);
|
|
break;
|
|
case Q_SAVE_MASTER_POS: do_save_master_pos(); break;
|
|
case Q_SYNC_WITH_MASTER: do_sync_with_master(command); break;
|
|
case Q_SYNC_SLAVE_WITH_MASTER:
|
|
{
|
|
do_save_master_pos();
|
|
if (*command->first_argument)
|
|
select_connection(command);
|
|
else
|
|
select_connection_name("slave");
|
|
do_sync_with_master2(0);
|
|
break;
|
|
}
|
|
case Q_COMMENT: /* Ignore row */
|
|
command->last_argument= command->end;
|
|
break;
|
|
case Q_PING:
|
|
(void) mysql_ping(&cur_con->mysql);
|
|
break;
|
|
case Q_EXEC:
|
|
do_exec(command);
|
|
command_executed++;
|
|
break;
|
|
case Q_START_TIMER:
|
|
/* Overwrite possible earlier start of timer */
|
|
timer_start= timer_now();
|
|
break;
|
|
case Q_END_TIMER:
|
|
/* End timer before ending mysqltest */
|
|
timer_output();
|
|
break;
|
|
case Q_CHARACTER_SET:
|
|
do_set_charset(command);
|
|
break;
|
|
case Q_DISABLE_PS_PROTOCOL:
|
|
ps_protocol_enabled= 0;
|
|
break;
|
|
case Q_ENABLE_PS_PROTOCOL:
|
|
ps_protocol_enabled= ps_protocol;
|
|
break;
|
|
case Q_DISABLE_RECONNECT:
|
|
set_reconnect(&cur_con->mysql, 0);
|
|
break;
|
|
case Q_ENABLE_RECONNECT:
|
|
set_reconnect(&cur_con->mysql, 1);
|
|
break;
|
|
case Q_DISABLE_PARSING:
|
|
if (parsing_disabled == 0)
|
|
parsing_disabled= 1;
|
|
else
|
|
die("Parsing is already disabled");
|
|
break;
|
|
case Q_ENABLE_PARSING:
|
|
/*
|
|
Ensure we don't get parsing_disabled < 0 as this would accidentally
|
|
disable code we don't want to have disabled
|
|
*/
|
|
if (parsing_disabled == 1)
|
|
parsing_disabled= 0;
|
|
else
|
|
die("Parsing is already enabled");
|
|
break;
|
|
case Q_DIE:
|
|
/* Abort test with error code and error message */
|
|
die("%s", command->first_argument);
|
|
break;
|
|
case Q_EXIT:
|
|
/* Stop processing any more commands */
|
|
abort_flag= 1;
|
|
break;
|
|
|
|
case Q_RESULT:
|
|
die("result, deprecated command");
|
|
break;
|
|
|
|
default:
|
|
processed= 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!processed)
|
|
{
|
|
current_line_inc= 0;
|
|
switch (command->type) {
|
|
case Q_WHILE: do_block(cmd_while, command); break;
|
|
case Q_IF: do_block(cmd_if, command); break;
|
|
case Q_END_BLOCK: do_done(command); break;
|
|
default: current_line_inc = 1; break;
|
|
}
|
|
}
|
|
else
|
|
check_eol_junk(command->last_argument);
|
|
|
|
if (command->type != Q_ERROR &&
|
|
command->type != Q_COMMENT)
|
|
{
|
|
/*
|
|
As soon as any non "error" command or comment has been executed,
|
|
the array with expected errors should be cleared
|
|
*/
|
|
memset(&saved_expected_errors, 0, sizeof(saved_expected_errors));
|
|
}
|
|
|
|
if (command_executed != last_command_executed)
|
|
{
|
|
/*
|
|
As soon as any command has been executed,
|
|
the replace structures should be cleared
|
|
*/
|
|
free_all_replace();
|
|
}
|
|
last_command_executed= command_executed;
|
|
|
|
parser.current_line += current_line_inc;
|
|
if ( opt_mark_progress )
|
|
mark_progress(command, parser.current_line);
|
|
}
|
|
|
|
start_lineno= 0;
|
|
|
|
if (parsing_disabled)
|
|
die("Test ended with parsing disabled");
|
|
|
|
/*
|
|
The whole test has been executed _sucessfully_.
|
|
Time to compare result or save it to record file.
|
|
The entire output from test is now kept in ds_res.
|
|
*/
|
|
if (ds_res.length)
|
|
{
|
|
if (result_file_name)
|
|
{
|
|
/* A result file has been specified */
|
|
|
|
if (record)
|
|
{
|
|
/* Recording - dump the output from test to result file */
|
|
str_to_file(result_file_name, ds_res.str, ds_res.length);
|
|
}
|
|
else
|
|
{
|
|
/* Check that the output from test is equal to result file
|
|
- detect missing result file
|
|
- detect zero size result file
|
|
*/
|
|
check_result(&ds_res);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* No result_file_name specified to compare with, print to stdout */
|
|
printf("%s", ds_res.str);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
die("The test didn't produce any output");
|
|
}
|
|
|
|
if (!command_executed &&
|
|
result_file_name && my_stat(result_file_name, &res_info, 0))
|
|
{
|
|
/*
|
|
my_stat() successful on result file. Check if we have not run a
|
|
single query, but we do have a result file that contains data.
|
|
Note that we don't care, if my_stat() fails. For example, for a
|
|
non-existing or non-readable file, we assume it's fine to have
|
|
no query output from the test file, e.g. regarded as no error.
|
|
*/
|
|
die("No queries executed but result file found!");
|
|
}
|
|
|
|
if ( opt_mark_progress && result_file_name )
|
|
dump_progress();
|
|
|
|
/* Dump warning messages */
|
|
if (result_file_name && ds_warning_messages.length)
|
|
dump_warning_messages();
|
|
|
|
dynstr_free(&ds_res);
|
|
|
|
timer_output();
|
|
free_used_memory();
|
|
my_end(info_flag ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
|
|
|
|
/* Yes, if we got this far the test has suceeded! Sakila smiles */
|
|
if (!silent)
|
|
printf("ok\n");
|
|
exit(0);
|
|
return 0; /* Keep compiler happy */
|
|
}
|
|
|
|
|
|
/*
|
|
A primitive timer that give results in milliseconds if the
|
|
--timer-file=<filename> is given. The timer result is written
|
|
to that file when the result is available. To not confuse
|
|
mysql-test-run with an old obsolete result, we remove the file
|
|
before executing any commands. The time we measure is
|
|
|
|
- If no explicit 'start_timer' or 'end_timer' is given in the
|
|
test case, the timer measure how long we execute in mysqltest.
|
|
|
|
- If only 'start_timer' is given we measure how long we execute
|
|
from that point until we terminate mysqltest.
|
|
|
|
- If only 'end_timer' is given we measure how long we execute
|
|
from that we enter mysqltest to the 'end_timer' is command is
|
|
executed.
|
|
|
|
- If both 'start_timer' and 'end_timer' are given we measure
|
|
the time between executing the two commands.
|
|
*/
|
|
|
|
void timer_output(void)
|
|
{
|
|
if (timer_file)
|
|
{
|
|
char buf[32], *end;
|
|
ulonglong timer= timer_now() - timer_start;
|
|
end= longlong2str(timer, buf, 10);
|
|
str_to_file(timer_file,buf, (int) (end-buf));
|
|
/* Timer has been written to the file, don't use it anymore */
|
|
timer_file= 0;
|
|
}
|
|
}
|
|
|
|
|
|
ulonglong timer_now(void)
|
|
{
|
|
return my_getsystime() / 10000;
|
|
}
|
|
|
|
|
|
/*
|
|
Get arguments for replace_columns. The syntax is:
|
|
replace-column column_number to_string [column_number to_string ...]
|
|
Where each argument may be quoted with ' or "
|
|
A argument may also be a variable, in which case the value of the
|
|
variable is replaced.
|
|
*/
|
|
|
|
void do_get_replace_column(struct st_command *command)
|
|
{
|
|
char *from= command->first_argument;
|
|
char *buff, *start;
|
|
DBUG_ENTER("get_replace_columns");
|
|
|
|
free_replace_column();
|
|
if (!*from)
|
|
die("Missing argument in %s", command->query);
|
|
|
|
/* Allocate a buffer for results */
|
|
start= buff= my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE));
|
|
while (*from)
|
|
{
|
|
char *to;
|
|
uint column_number;
|
|
|
|
to= get_string(&buff, &from, command);
|
|
if (!(column_number= atoi(to)) || column_number > MAX_COLUMNS)
|
|
die("Wrong column number to replace_column in '%s'", command->query);
|
|
if (!*from)
|
|
die("Wrong number of arguments to replace_column in '%s'", command->query);
|
|
to= get_string(&buff, &from, command);
|
|
my_free(replace_column[column_number-1], MY_ALLOW_ZERO_PTR);
|
|
replace_column[column_number-1]= my_strdup(to, MYF(MY_WME | MY_FAE));
|
|
set_if_bigger(max_replace_column, column_number);
|
|
}
|
|
my_free(start, MYF(0));
|
|
command->last_argument= command->end;
|
|
}
|
|
|
|
|
|
void free_replace_column()
|
|
{
|
|
uint i;
|
|
for (i=0 ; i < max_replace_column ; i++)
|
|
{
|
|
if (replace_column[i])
|
|
{
|
|
my_free(replace_column[i], 0);
|
|
replace_column[i]= 0;
|
|
}
|
|
}
|
|
max_replace_column= 0;
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/*
|
|
Replace functions
|
|
*/
|
|
|
|
/* Definitions for replace result */
|
|
|
|
typedef struct st_pointer_array { /* when using array-strings */
|
|
TYPELIB typelib; /* Pointer to strings */
|
|
byte *str; /* Strings is here */
|
|
int7 *flag; /* Flag about each var. */
|
|
uint array_allocs,max_count,length,max_length;
|
|
} POINTER_ARRAY;
|
|
|
|
struct st_replace;
|
|
struct st_replace *init_replace(my_string *from, my_string *to, uint count,
|
|
my_string word_end_chars);
|
|
int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name);
|
|
void replace_strings_append(struct st_replace *rep, DYNAMIC_STRING* ds,
|
|
const char *from, int len);
|
|
void free_pointer_array(POINTER_ARRAY *pa);
|
|
|
|
struct st_replace *glob_replace;
|
|
|
|
/*
|
|
Get arguments for replace. The syntax is:
|
|
replace from to [from to ...]
|
|
Where each argument may be quoted with ' or "
|
|
A argument may also be a variable, in which case the value of the
|
|
variable is replaced.
|
|
*/
|
|
|
|
void do_get_replace(struct st_command *command)
|
|
{
|
|
uint i;
|
|
char *from= command->first_argument;
|
|
char *buff, *start;
|
|
char word_end_chars[256], *pos;
|
|
POINTER_ARRAY to_array, from_array;
|
|
DBUG_ENTER("get_replace");
|
|
|
|
free_replace();
|
|
|
|
bzero((char*) &to_array,sizeof(to_array));
|
|
bzero((char*) &from_array,sizeof(from_array));
|
|
if (!*from)
|
|
die("Missing argument in %s", command->query);
|
|
start= buff= my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE));
|
|
while (*from)
|
|
{
|
|
char *to= buff;
|
|
to= get_string(&buff, &from, command);
|
|
if (!*from)
|
|
die("Wrong number of arguments to replace_result in '%s'",
|
|
command->query);
|
|
insert_pointer_name(&from_array,to);
|
|
to= get_string(&buff, &from, command);
|
|
insert_pointer_name(&to_array,to);
|
|
}
|
|
for (i= 1,pos= word_end_chars ; i < 256 ; i++)
|
|
if (my_isspace(charset_info,i))
|
|
*pos++= i;
|
|
*pos=0; /* End pointer */
|
|
if (!(glob_replace= init_replace((char**) from_array.typelib.type_names,
|
|
(char**) to_array.typelib.type_names,
|
|
(uint) from_array.typelib.count,
|
|
word_end_chars)))
|
|
die("Can't initialize replace from '%s'", command->query);
|
|
free_pointer_array(&from_array);
|
|
free_pointer_array(&to_array);
|
|
my_free(start, MYF(0));
|
|
command->last_argument= command->end;
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
void free_replace()
|
|
{
|
|
DBUG_ENTER("free_replace");
|
|
if (glob_replace)
|
|
{
|
|
my_free((char*) glob_replace,MYF(0));
|
|
glob_replace=0;
|
|
}
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
typedef struct st_replace {
|
|
bool found;
|
|
struct st_replace *next[256];
|
|
} REPLACE;
|
|
|
|
typedef struct st_replace_found {
|
|
bool found;
|
|
char *replace_string;
|
|
uint to_offset;
|
|
int from_offset;
|
|
} REPLACE_STRING;
|
|
|
|
|
|
void replace_strings_append(REPLACE *rep, DYNAMIC_STRING* ds,
|
|
const char *str, int len)
|
|
{
|
|
reg1 REPLACE *rep_pos;
|
|
reg2 REPLACE_STRING *rep_str;
|
|
const char *start, *from;
|
|
DBUG_ENTER("replace_strings_append");
|
|
|
|
start= from= str;
|
|
rep_pos=rep+1;
|
|
for (;;)
|
|
{
|
|
/* Loop through states */
|
|
DBUG_PRINT("info", ("Looping through states"));
|
|
while (!rep_pos->found)
|
|
rep_pos= rep_pos->next[(uchar) *from++];
|
|
|
|
/* Does this state contain a string to be replaced */
|
|
if (!(rep_str = ((REPLACE_STRING*) rep_pos))->replace_string)
|
|
{
|
|
/* No match found */
|
|
dynstr_append_mem(ds, start, from - start - 1);
|
|
DBUG_PRINT("exit", ("Found no more string to replace, appended: %s", start));
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
/* Found a string that needs to be replaced */
|
|
DBUG_PRINT("info", ("found: %d, to_offset: %d, from_offset: %d, string: %s",
|
|
rep_str->found, rep_str->to_offset,
|
|
rep_str->from_offset, rep_str->replace_string));
|
|
|
|
/* Append part of original string before replace string */
|
|
dynstr_append_mem(ds, start, (from - rep_str->to_offset) - start);
|
|
|
|
/* Append replace string */
|
|
dynstr_append_mem(ds, rep_str->replace_string,
|
|
strlen(rep_str->replace_string));
|
|
|
|
if (!*(from-=rep_str->from_offset) && rep_pos->found != 2)
|
|
{
|
|
/* End of from string */
|
|
DBUG_PRINT("exit", ("Found end of from string"));
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
DBUG_ASSERT(from <= str+len);
|
|
start= from;
|
|
rep_pos=rep;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
Regex replace functions
|
|
*/
|
|
|
|
|
|
/* Stores regex substitutions */
|
|
|
|
struct st_regex
|
|
{
|
|
char* pattern; /* Pattern to be replaced */
|
|
char* replace; /* String or expression to replace the pattern with */
|
|
int icase; /* true if the match is case insensitive */
|
|
};
|
|
|
|
struct st_replace_regex
|
|
{
|
|
DYNAMIC_ARRAY regex_arr; /* stores a list of st_regex subsitutions */
|
|
|
|
/*
|
|
Temporary storage areas for substitutions. To reduce unnessary copying
|
|
and memory freeing/allocation, we pre-allocate two buffers, and alternate
|
|
their use, one for input/one for output, the roles changing on the next
|
|
st_regex substition. At the end of substitutions buf points to the
|
|
one containing the final result.
|
|
*/
|
|
char* buf;
|
|
char* even_buf;
|
|
char* odd_buf;
|
|
int even_buf_len;
|
|
int odd_buf_len;
|
|
};
|
|
|
|
struct st_replace_regex *glob_replace_regex= 0;
|
|
|
|
int reg_replace(char** buf_p, int* buf_len_p, char *pattern, char *replace,
|
|
char *string, int icase);
|
|
|
|
|
|
|
|
/*
|
|
Finds the next (non-escaped) '/' in the expression.
|
|
(If the character '/' is needed, it can be escaped using '\'.)
|
|
*/
|
|
|
|
#define PARSE_REGEX_ARG \
|
|
while (p < expr_end) \
|
|
{ \
|
|
char c= *p; \
|
|
if (c == '/') \
|
|
{ \
|
|
if (last_c == '\\') \
|
|
{ \
|
|
buf_p[-1]= '/'; \
|
|
} \
|
|
else \
|
|
{ \
|
|
*buf_p++ = 0; \
|
|
break; \
|
|
} \
|
|
} \
|
|
else \
|
|
*buf_p++ = c; \
|
|
\
|
|
last_c= c; \
|
|
p++; \
|
|
} \
|
|
\
|
|
/*
|
|
Initializes the regular substitution expression to be used in the
|
|
result output of test.
|
|
|
|
Returns: st_replace_regex struct with pairs of substitutions
|
|
*/
|
|
|
|
struct st_replace_regex* init_replace_regex(char* expr)
|
|
{
|
|
struct st_replace_regex* res;
|
|
char* buf,*expr_end;
|
|
char* p;
|
|
char* buf_p;
|
|
uint expr_len= strlen(expr);
|
|
char last_c = 0;
|
|
struct st_regex reg;
|
|
|
|
/* my_malloc() will die on fail with MY_FAE */
|
|
res=(struct st_replace_regex*)my_malloc(
|
|
sizeof(*res)+expr_len ,MYF(MY_FAE+MY_WME));
|
|
my_init_dynamic_array(&res->regex_arr,sizeof(struct st_regex),128,128);
|
|
|
|
buf= (char*)res + sizeof(*res);
|
|
expr_end= expr + expr_len;
|
|
p= expr;
|
|
buf_p= buf;
|
|
|
|
/* for each regexp substitution statement */
|
|
while (p < expr_end)
|
|
{
|
|
bzero(®,sizeof(reg));
|
|
/* find the start of the statement */
|
|
while (p < expr_end)
|
|
{
|
|
if (*p == '/')
|
|
break;
|
|
p++;
|
|
}
|
|
|
|
if (p == expr_end || ++p == expr_end)
|
|
{
|
|
if (res->regex_arr.elements)
|
|
break;
|
|
else
|
|
goto err;
|
|
}
|
|
/* we found the start */
|
|
reg.pattern= buf_p;
|
|
|
|
/* Find first argument -- pattern string to be removed */
|
|
PARSE_REGEX_ARG
|
|
|
|
if (p == expr_end || ++p == expr_end)
|
|
goto err;
|
|
|
|
/* buf_p now points to the replacement pattern terminated with \0 */
|
|
reg.replace= buf_p;
|
|
|
|
/* Find second argument -- replace string to replace pattern */
|
|
PARSE_REGEX_ARG
|
|
|
|
if (p == expr_end)
|
|
goto err;
|
|
|
|
/* skip the ending '/' in the statement */
|
|
p++;
|
|
|
|
/* Check if we should do matching case insensitive */
|
|
if (p < expr_end && *p == 'i')
|
|
reg.icase= 1;
|
|
|
|
/* done parsing the statement, now place it in regex_arr */
|
|
if (insert_dynamic(&res->regex_arr,(gptr) ®))
|
|
die("Out of memory");
|
|
}
|
|
res->odd_buf_len= res->even_buf_len= 8192;
|
|
res->even_buf= (char*)my_malloc(res->even_buf_len,MYF(MY_WME+MY_FAE));
|
|
res->odd_buf= (char*)my_malloc(res->odd_buf_len,MYF(MY_WME+MY_FAE));
|
|
res->buf= res->even_buf;
|
|
|
|
return res;
|
|
|
|
err:
|
|
my_free((gptr)res,0);
|
|
die("Error parsing replace_regex \"%s\"", expr);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
Execute all substitutions on val.
|
|
|
|
Returns: true if substituition was made, false otherwise
|
|
Side-effect: Sets r->buf to be the buffer with all substitutions done.
|
|
|
|
IN:
|
|
struct st_replace_regex* r
|
|
char* val
|
|
Out:
|
|
struct st_replace_regex* r
|
|
r->buf points at the resulting buffer
|
|
r->even_buf and r->odd_buf might have been reallocated
|
|
r->even_buf_len and r->odd_buf_len might have been changed
|
|
|
|
TODO: at some point figure out if there is a way to do everything
|
|
in one pass
|
|
*/
|
|
|
|
int multi_reg_replace(struct st_replace_regex* r,char* val)
|
|
{
|
|
uint i;
|
|
char* in_buf, *out_buf;
|
|
int* buf_len_p;
|
|
|
|
in_buf= val;
|
|
out_buf= r->even_buf;
|
|
buf_len_p= &r->even_buf_len;
|
|
r->buf= 0;
|
|
|
|
/* For each substitution, do the replace */
|
|
for (i= 0; i < r->regex_arr.elements; i++)
|
|
{
|
|
struct st_regex re;
|
|
char* save_out_buf= out_buf;
|
|
|
|
get_dynamic(&r->regex_arr,(gptr)&re,i);
|
|
|
|
if (!reg_replace(&out_buf, buf_len_p, re.pattern, re.replace,
|
|
in_buf, re.icase))
|
|
{
|
|
/* if the buffer has been reallocated, make adjustements */
|
|
if (save_out_buf != out_buf)
|
|
{
|
|
if (save_out_buf == r->even_buf)
|
|
r->even_buf= out_buf;
|
|
else
|
|
r->odd_buf= out_buf;
|
|
}
|
|
|
|
r->buf= out_buf;
|
|
if (in_buf == val)
|
|
in_buf= r->odd_buf;
|
|
|
|
swap_variables(char*,in_buf,out_buf);
|
|
|
|
buf_len_p= (out_buf == r->even_buf) ? &r->even_buf_len :
|
|
&r->odd_buf_len;
|
|
}
|
|
}
|
|
|
|
return (r->buf == 0);
|
|
}
|
|
|
|
/*
|
|
Parse the regular expression to be used in all result files
|
|
from now on.
|
|
|
|
The syntax is --replace_regex /from/to/i /from/to/i ...
|
|
i means case-insensitive match. If omitted, the match is
|
|
case-sensitive
|
|
|
|
*/
|
|
void do_get_replace_regex(struct st_command *command)
|
|
{
|
|
char *expr= command->first_argument;
|
|
free_replace_regex();
|
|
if (!(glob_replace_regex=init_replace_regex(expr)))
|
|
die("Could not init replace_regex");
|
|
command->last_argument= command->end;
|
|
}
|
|
|
|
void free_replace_regex()
|
|
{
|
|
if (glob_replace_regex)
|
|
{
|
|
delete_dynamic(&glob_replace_regex->regex_arr);
|
|
my_free(glob_replace_regex->even_buf,MYF(MY_ALLOW_ZERO_PTR));
|
|
my_free(glob_replace_regex->odd_buf,MYF(MY_ALLOW_ZERO_PTR));
|
|
my_free((char*) glob_replace_regex,MYF(0));
|
|
glob_replace_regex=0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
auxiluary macro used by reg_replace
|
|
makes sure the result buffer has sufficient length
|
|
*/
|
|
#define SECURE_REG_BUF if (buf_len < need_buf_len) \
|
|
{ \
|
|
int off= res_p - buf; \
|
|
buf= (char*)my_realloc(buf,need_buf_len,MYF(MY_WME+MY_FAE)); \
|
|
res_p= buf + off; \
|
|
buf_len= need_buf_len; \
|
|
} \
|
|
\
|
|
/*
|
|
Performs a regex substitution
|
|
|
|
IN:
|
|
|
|
buf_p - result buffer pointer. Will change if reallocated
|
|
buf_len_p - result buffer length. Will change if the buffer is reallocated
|
|
pattern - regexp pattern to match
|
|
replace - replacement expression
|
|
string - the string to perform substituions in
|
|
icase - flag, if set to 1 the match is case insensitive
|
|
*/
|
|
int reg_replace(char** buf_p, int* buf_len_p, char *pattern,
|
|
char *replace, char *string, int icase)
|
|
{
|
|
my_regex_t r;
|
|
my_regmatch_t *subs;
|
|
char *replace_end;
|
|
char *buf= *buf_p;
|
|
int len;
|
|
int buf_len, need_buf_len;
|
|
int cflags= REG_EXTENDED;
|
|
int err_code;
|
|
char *res_p,*str_p,*str_end;
|
|
|
|
buf_len= *buf_len_p;
|
|
len= strlen(string);
|
|
str_end= string + len;
|
|
|
|
/* start with a buffer of a reasonable size that hopefully will not
|
|
need to be reallocated
|
|
*/
|
|
need_buf_len= len * 2 + 1;
|
|
res_p= buf;
|
|
|
|
SECURE_REG_BUF
|
|
|
|
if (icase)
|
|
cflags|= REG_ICASE;
|
|
|
|
if ((err_code= my_regcomp(&r,pattern,cflags,&my_charset_latin1)))
|
|
{
|
|
check_regerr(&r,err_code);
|
|
return 1;
|
|
}
|
|
|
|
subs= (my_regmatch_t*)my_malloc(sizeof(my_regmatch_t) * (r.re_nsub+1),
|
|
MYF(MY_WME+MY_FAE));
|
|
|
|
*res_p= 0;
|
|
str_p= string;
|
|
replace_end= replace + strlen(replace);
|
|
|
|
/* for each pattern match instance perform a replacement */
|
|
while (!err_code)
|
|
{
|
|
/* find the match */
|
|
err_code= my_regexec(&r,str_p, r.re_nsub+1, subs,
|
|
(str_p == string) ? REG_NOTBOL : 0);
|
|
|
|
/* if regular expression error (eg. bad syntax, or out of memory) */
|
|
if (err_code && err_code != REG_NOMATCH)
|
|
{
|
|
check_regerr(&r,err_code);
|
|
my_regfree(&r);
|
|
return 1;
|
|
}
|
|
|
|
/* if match found */
|
|
if (!err_code)
|
|
{
|
|
char* expr_p= replace;
|
|
int c;
|
|
|
|
/*
|
|
we need at least what we have so far in the buffer + the part
|
|
before this match
|
|
*/
|
|
need_buf_len= (res_p - buf) + subs[0].rm_so;
|
|
|
|
/* on this pass, calculate the memory for the result buffer */
|
|
while (expr_p < replace_end)
|
|
{
|
|
int back_ref_num= -1;
|
|
c= *expr_p;
|
|
|
|
if (c == '\\' && expr_p + 1 < replace_end)
|
|
{
|
|
back_ref_num= expr_p[1] - '0';
|
|
}
|
|
|
|
/* found a valid back_ref (eg. \1)*/
|
|
if (back_ref_num >= 0 && back_ref_num <= (int)r.re_nsub)
|
|
{
|
|
int start_off,end_off;
|
|
if ((start_off=subs[back_ref_num].rm_so) > -1 &&
|
|
(end_off=subs[back_ref_num].rm_eo) > -1)
|
|
{
|
|
need_buf_len += (end_off - start_off);
|
|
}
|
|
expr_p += 2;
|
|
}
|
|
else
|
|
{
|
|
expr_p++;
|
|
need_buf_len++;
|
|
}
|
|
}
|
|
need_buf_len++;
|
|
/*
|
|
now that we know the size of the buffer,
|
|
make sure it is big enough
|
|
*/
|
|
SECURE_REG_BUF
|
|
|
|
/* copy the pre-match part */
|
|
if (subs[0].rm_so)
|
|
{
|
|
memcpy(res_p, str_p, subs[0].rm_so);
|
|
res_p+= subs[0].rm_so;
|
|
}
|
|
|
|
expr_p= replace;
|
|
|
|
/* copy the match and expand back_refs */
|
|
while (expr_p < replace_end)
|
|
{
|
|
int back_ref_num= -1;
|
|
c= *expr_p;
|
|
|
|
if (c == '\\' && expr_p + 1 < replace_end)
|
|
{
|
|
back_ref_num= expr_p[1] - '0';
|
|
}
|
|
|
|
if (back_ref_num >= 0 && back_ref_num <= (int)r.re_nsub)
|
|
{
|
|
int start_off,end_off;
|
|
if ((start_off=subs[back_ref_num].rm_so) > -1 &&
|
|
(end_off=subs[back_ref_num].rm_eo) > -1)
|
|
{
|
|
int block_len= end_off - start_off;
|
|
memcpy(res_p,str_p + start_off, block_len);
|
|
res_p += block_len;
|
|
}
|
|
expr_p += 2;
|
|
}
|
|
else
|
|
{
|
|
*res_p++ = *expr_p++;
|
|
}
|
|
}
|
|
|
|
/* handle the post-match part */
|
|
if (subs[0].rm_so == subs[0].rm_eo)
|
|
{
|
|
if (str_p + subs[0].rm_so >= str_end)
|
|
break;
|
|
str_p += subs[0].rm_eo ;
|
|
*res_p++ = *str_p++;
|
|
}
|
|
else
|
|
{
|
|
str_p += subs[0].rm_eo;
|
|
}
|
|
}
|
|
else /* no match this time, just copy the string as is */
|
|
{
|
|
int left_in_str= str_end-str_p;
|
|
need_buf_len= (res_p-buf) + left_in_str;
|
|
SECURE_REG_BUF
|
|
memcpy(res_p,str_p,left_in_str);
|
|
res_p += left_in_str;
|
|
str_p= str_end;
|
|
}
|
|
}
|
|
my_free((gptr)subs, MYF(0));
|
|
my_regfree(&r);
|
|
*res_p= 0;
|
|
*buf_p= buf;
|
|
*buf_len_p= buf_len;
|
|
return 0;
|
|
}
|
|
|
|
|
|
#ifndef WORD_BIT
|
|
#define WORD_BIT (8*sizeof(uint))
|
|
#endif
|
|
|
|
#define SET_MALLOC_HUNC 64
|
|
#define LAST_CHAR_CODE 259
|
|
|
|
typedef struct st_rep_set {
|
|
uint *bits; /* Pointer to used sets */
|
|
short next[LAST_CHAR_CODE]; /* Pointer to next sets */
|
|
uint found_len; /* Best match to date */
|
|
int found_offset;
|
|
uint table_offset;
|
|
uint size_of_bits; /* For convinience */
|
|
} REP_SET;
|
|
|
|
typedef struct st_rep_sets {
|
|
uint count; /* Number of sets */
|
|
uint extra; /* Extra sets in buffer */
|
|
uint invisible; /* Sets not chown */
|
|
uint size_of_bits;
|
|
REP_SET *set,*set_buffer;
|
|
uint *bit_buffer;
|
|
} REP_SETS;
|
|
|
|
typedef struct st_found_set {
|
|
uint table_offset;
|
|
int found_offset;
|
|
} FOUND_SET;
|
|
|
|
typedef struct st_follow {
|
|
int chr;
|
|
uint table_offset;
|
|
uint len;
|
|
} FOLLOWS;
|
|
|
|
|
|
int init_sets(REP_SETS *sets,uint states);
|
|
REP_SET *make_new_set(REP_SETS *sets);
|
|
void make_sets_invisible(REP_SETS *sets);
|
|
void free_last_set(REP_SETS *sets);
|
|
void free_sets(REP_SETS *sets);
|
|
void internal_set_bit(REP_SET *set, uint bit);
|
|
void internal_clear_bit(REP_SET *set, uint bit);
|
|
void or_bits(REP_SET *to,REP_SET *from);
|
|
void copy_bits(REP_SET *to,REP_SET *from);
|
|
int cmp_bits(REP_SET *set1,REP_SET *set2);
|
|
int get_next_bit(REP_SET *set,uint lastpos);
|
|
int find_set(REP_SETS *sets,REP_SET *find);
|
|
int find_found(FOUND_SET *found_set,uint table_offset,
|
|
int found_offset);
|
|
uint start_at_word(my_string pos);
|
|
uint end_of_word(my_string pos);
|
|
|
|
static uint found_sets=0;
|
|
|
|
|
|
uint replace_len(my_string str)
|
|
{
|
|
uint len=0;
|
|
while (*str)
|
|
{
|
|
if (str[0] == '\\' && str[1])
|
|
str++;
|
|
str++;
|
|
len++;
|
|
}
|
|
return len;
|
|
}
|
|
|
|
/* Init a replace structure for further calls */
|
|
|
|
REPLACE *init_replace(my_string *from, my_string *to,uint count,
|
|
my_string word_end_chars)
|
|
{
|
|
static const int SPACE_CHAR= 256;
|
|
static const int START_OF_LINE= 257;
|
|
static const int END_OF_LINE= 258;
|
|
|
|
uint i,j,states,set_nr,len,result_len,max_length,found_end,bits_set,bit_nr;
|
|
int used_sets,chr,default_state;
|
|
char used_chars[LAST_CHAR_CODE],is_word_end[256];
|
|
my_string pos,to_pos,*to_array;
|
|
REP_SETS sets;
|
|
REP_SET *set,*start_states,*word_states,*new_set;
|
|
FOLLOWS *follow,*follow_ptr;
|
|
REPLACE *replace;
|
|
FOUND_SET *found_set;
|
|
REPLACE_STRING *rep_str;
|
|
DBUG_ENTER("init_replace");
|
|
|
|
/* Count number of states */
|
|
for (i=result_len=max_length=0 , states=2 ; i < count ; i++)
|
|
{
|
|
len=replace_len(from[i]);
|
|
if (!len)
|
|
{
|
|
errno=EINVAL;
|
|
my_message(0,"No to-string for last from-string",MYF(ME_BELL));
|
|
DBUG_RETURN(0);
|
|
}
|
|
states+=len+1;
|
|
result_len+=(uint) strlen(to[i])+1;
|
|
if (len > max_length)
|
|
max_length=len;
|
|
}
|
|
bzero((char*) is_word_end,sizeof(is_word_end));
|
|
for (i=0 ; word_end_chars[i] ; i++)
|
|
is_word_end[(uchar) word_end_chars[i]]=1;
|
|
|
|
if (init_sets(&sets,states))
|
|
DBUG_RETURN(0);
|
|
found_sets=0;
|
|
if (!(found_set= (FOUND_SET*) my_malloc(sizeof(FOUND_SET)*max_length*count,
|
|
MYF(MY_WME))))
|
|
{
|
|
free_sets(&sets);
|
|
DBUG_RETURN(0);
|
|
}
|
|
VOID(make_new_set(&sets)); /* Set starting set */
|
|
make_sets_invisible(&sets); /* Hide previus sets */
|
|
used_sets=-1;
|
|
word_states=make_new_set(&sets); /* Start of new word */
|
|
start_states=make_new_set(&sets); /* This is first state */
|
|
if (!(follow=(FOLLOWS*) my_malloc((states+2)*sizeof(FOLLOWS),MYF(MY_WME))))
|
|
{
|
|
free_sets(&sets);
|
|
my_free((gptr) found_set,MYF(0));
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
/* Init follow_ptr[] */
|
|
for (i=0, states=1, follow_ptr=follow+1 ; i < count ; i++)
|
|
{
|
|
if (from[i][0] == '\\' && from[i][1] == '^')
|
|
{
|
|
internal_set_bit(start_states,states+1);
|
|
if (!from[i][2])
|
|
{
|
|
start_states->table_offset=i;
|
|
start_states->found_offset=1;
|
|
}
|
|
}
|
|
else if (from[i][0] == '\\' && from[i][1] == '$')
|
|
{
|
|
internal_set_bit(start_states,states);
|
|
internal_set_bit(word_states,states);
|
|
if (!from[i][2] && start_states->table_offset == (uint) ~0)
|
|
{
|
|
start_states->table_offset=i;
|
|
start_states->found_offset=0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
internal_set_bit(word_states,states);
|
|
if (from[i][0] == '\\' && (from[i][1] == 'b' && from[i][2]))
|
|
internal_set_bit(start_states,states+1);
|
|
else
|
|
internal_set_bit(start_states,states);
|
|
}
|
|
for (pos=from[i], len=0; *pos ; pos++)
|
|
{
|
|
if (*pos == '\\' && *(pos+1))
|
|
{
|
|
pos++;
|
|
switch (*pos) {
|
|
case 'b':
|
|
follow_ptr->chr = SPACE_CHAR;
|
|
break;
|
|
case '^':
|
|
follow_ptr->chr = START_OF_LINE;
|
|
break;
|
|
case '$':
|
|
follow_ptr->chr = END_OF_LINE;
|
|
break;
|
|
case 'r':
|
|
follow_ptr->chr = '\r';
|
|
break;
|
|
case 't':
|
|
follow_ptr->chr = '\t';
|
|
break;
|
|
case 'v':
|
|
follow_ptr->chr = '\v';
|
|
break;
|
|
default:
|
|
follow_ptr->chr = (uchar) *pos;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
follow_ptr->chr= (uchar) *pos;
|
|
follow_ptr->table_offset=i;
|
|
follow_ptr->len= ++len;
|
|
follow_ptr++;
|
|
}
|
|
follow_ptr->chr=0;
|
|
follow_ptr->table_offset=i;
|
|
follow_ptr->len=len;
|
|
follow_ptr++;
|
|
states+=(uint) len+1;
|
|
}
|
|
|
|
|
|
for (set_nr=0,pos=0 ; set_nr < sets.count ; set_nr++)
|
|
{
|
|
set=sets.set+set_nr;
|
|
default_state= 0; /* Start from beginning */
|
|
|
|
/* If end of found-string not found or start-set with current set */
|
|
|
|
for (i= (uint) ~0; (i=get_next_bit(set,i)) ;)
|
|
{
|
|
if (!follow[i].chr)
|
|
{
|
|
if (! default_state)
|
|
default_state= find_found(found_set,set->table_offset,
|
|
set->found_offset+1);
|
|
}
|
|
}
|
|
copy_bits(sets.set+used_sets,set); /* Save set for changes */
|
|
if (!default_state)
|
|
or_bits(sets.set+used_sets,sets.set); /* Can restart from start */
|
|
|
|
/* Find all chars that follows current sets */
|
|
bzero((char*) used_chars,sizeof(used_chars));
|
|
for (i= (uint) ~0; (i=get_next_bit(sets.set+used_sets,i)) ;)
|
|
{
|
|
used_chars[follow[i].chr]=1;
|
|
if ((follow[i].chr == SPACE_CHAR && !follow[i+1].chr &&
|
|
follow[i].len > 1) || follow[i].chr == END_OF_LINE)
|
|
used_chars[0]=1;
|
|
}
|
|
|
|
/* Mark word_chars used if \b is in state */
|
|
if (used_chars[SPACE_CHAR])
|
|
for (pos= word_end_chars ; *pos ; pos++)
|
|
used_chars[(int) (uchar) *pos] = 1;
|
|
|
|
/* Handle other used characters */
|
|
for (chr= 0 ; chr < 256 ; chr++)
|
|
{
|
|
if (! used_chars[chr])
|
|
set->next[chr]= chr ? default_state : -1;
|
|
else
|
|
{
|
|
new_set=make_new_set(&sets);
|
|
set=sets.set+set_nr; /* if realloc */
|
|
new_set->table_offset=set->table_offset;
|
|
new_set->found_len=set->found_len;
|
|
new_set->found_offset=set->found_offset+1;
|
|
found_end=0;
|
|
|
|
for (i= (uint) ~0 ; (i=get_next_bit(sets.set+used_sets,i)) ; )
|
|
{
|
|
if (!follow[i].chr || follow[i].chr == chr ||
|
|
(follow[i].chr == SPACE_CHAR &&
|
|
(is_word_end[chr] ||
|
|
(!chr && follow[i].len > 1 && ! follow[i+1].chr))) ||
|
|
(follow[i].chr == END_OF_LINE && ! chr))
|
|
{
|
|
if ((! chr || (follow[i].chr && !follow[i+1].chr)) &&
|
|
follow[i].len > found_end)
|
|
found_end=follow[i].len;
|
|
if (chr && follow[i].chr)
|
|
internal_set_bit(new_set,i+1); /* To next set */
|
|
else
|
|
internal_set_bit(new_set,i);
|
|
}
|
|
}
|
|
if (found_end)
|
|
{
|
|
new_set->found_len=0; /* Set for testing if first */
|
|
bits_set=0;
|
|
for (i= (uint) ~0; (i=get_next_bit(new_set,i)) ;)
|
|
{
|
|
if ((follow[i].chr == SPACE_CHAR ||
|
|
follow[i].chr == END_OF_LINE) && ! chr)
|
|
bit_nr=i+1;
|
|
else
|
|
bit_nr=i;
|
|
if (follow[bit_nr-1].len < found_end ||
|
|
(new_set->found_len &&
|
|
(chr == 0 || !follow[bit_nr].chr)))
|
|
internal_clear_bit(new_set,i);
|
|
else
|
|
{
|
|
if (chr == 0 || !follow[bit_nr].chr)
|
|
{ /* best match */
|
|
new_set->table_offset=follow[bit_nr].table_offset;
|
|
if (chr || (follow[i].chr == SPACE_CHAR ||
|
|
follow[i].chr == END_OF_LINE))
|
|
new_set->found_offset=found_end; /* New match */
|
|
new_set->found_len=found_end;
|
|
}
|
|
bits_set++;
|
|
}
|
|
}
|
|
if (bits_set == 1)
|
|
{
|
|
set->next[chr] = find_found(found_set,
|
|
new_set->table_offset,
|
|
new_set->found_offset);
|
|
free_last_set(&sets);
|
|
}
|
|
else
|
|
set->next[chr] = find_set(&sets,new_set);
|
|
}
|
|
else
|
|
set->next[chr] = find_set(&sets,new_set);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Alloc replace structure for the replace-state-machine */
|
|
|
|
if ((replace=(REPLACE*) my_malloc(sizeof(REPLACE)*(sets.count)+
|
|
sizeof(REPLACE_STRING)*(found_sets+1)+
|
|
sizeof(my_string)*count+result_len,
|
|
MYF(MY_WME | MY_ZEROFILL))))
|
|
{
|
|
rep_str=(REPLACE_STRING*) (replace+sets.count);
|
|
to_array=(my_string*) (rep_str+found_sets+1);
|
|
to_pos=(my_string) (to_array+count);
|
|
for (i=0 ; i < count ; i++)
|
|
{
|
|
to_array[i]=to_pos;
|
|
to_pos=strmov(to_pos,to[i])+1;
|
|
}
|
|
rep_str[0].found=1;
|
|
rep_str[0].replace_string=0;
|
|
for (i=1 ; i <= found_sets ; i++)
|
|
{
|
|
pos=from[found_set[i-1].table_offset];
|
|
rep_str[i].found= !bcmp(pos,"\\^",3) ? 2 : 1;
|
|
rep_str[i].replace_string=to_array[found_set[i-1].table_offset];
|
|
rep_str[i].to_offset=found_set[i-1].found_offset-start_at_word(pos);
|
|
rep_str[i].from_offset=found_set[i-1].found_offset-replace_len(pos)+
|
|
end_of_word(pos);
|
|
}
|
|
for (i=0 ; i < sets.count ; i++)
|
|
{
|
|
for (j=0 ; j < 256 ; j++)
|
|
if (sets.set[i].next[j] >= 0)
|
|
replace[i].next[j]=replace+sets.set[i].next[j];
|
|
else
|
|
replace[i].next[j]=(REPLACE*) (rep_str+(-sets.set[i].next[j]-1));
|
|
}
|
|
}
|
|
my_free((gptr) follow,MYF(0));
|
|
free_sets(&sets);
|
|
my_free((gptr) found_set,MYF(0));
|
|
DBUG_PRINT("exit",("Replace table has %d states",sets.count));
|
|
DBUG_RETURN(replace);
|
|
}
|
|
|
|
|
|
int init_sets(REP_SETS *sets,uint states)
|
|
{
|
|
bzero((char*) sets,sizeof(*sets));
|
|
sets->size_of_bits=((states+7)/8);
|
|
if (!(sets->set_buffer=(REP_SET*) my_malloc(sizeof(REP_SET)*SET_MALLOC_HUNC,
|
|
MYF(MY_WME))))
|
|
return 1;
|
|
if (!(sets->bit_buffer=(uint*) my_malloc(sizeof(uint)*sets->size_of_bits*
|
|
SET_MALLOC_HUNC,MYF(MY_WME))))
|
|
{
|
|
my_free((gptr) sets->set,MYF(0));
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Make help sets invisible for nicer codeing */
|
|
|
|
void make_sets_invisible(REP_SETS *sets)
|
|
{
|
|
sets->invisible=sets->count;
|
|
sets->set+=sets->count;
|
|
sets->count=0;
|
|
}
|
|
|
|
REP_SET *make_new_set(REP_SETS *sets)
|
|
{
|
|
uint i,count,*bit_buffer;
|
|
REP_SET *set;
|
|
if (sets->extra)
|
|
{
|
|
sets->extra--;
|
|
set=sets->set+ sets->count++;
|
|
bzero((char*) set->bits,sizeof(uint)*sets->size_of_bits);
|
|
bzero((char*) &set->next[0],sizeof(set->next[0])*LAST_CHAR_CODE);
|
|
set->found_offset=0;
|
|
set->found_len=0;
|
|
set->table_offset= (uint) ~0;
|
|
set->size_of_bits=sets->size_of_bits;
|
|
return set;
|
|
}
|
|
count=sets->count+sets->invisible+SET_MALLOC_HUNC;
|
|
if (!(set=(REP_SET*) my_realloc((gptr) sets->set_buffer,
|
|
sizeof(REP_SET)*count,
|
|
MYF(MY_WME))))
|
|
return 0;
|
|
sets->set_buffer=set;
|
|
sets->set=set+sets->invisible;
|
|
if (!(bit_buffer=(uint*) my_realloc((gptr) sets->bit_buffer,
|
|
(sizeof(uint)*sets->size_of_bits)*count,
|
|
MYF(MY_WME))))
|
|
return 0;
|
|
sets->bit_buffer=bit_buffer;
|
|
for (i=0 ; i < count ; i++)
|
|
{
|
|
sets->set_buffer[i].bits=bit_buffer;
|
|
bit_buffer+=sets->size_of_bits;
|
|
}
|
|
sets->extra=SET_MALLOC_HUNC;
|
|
return make_new_set(sets);
|
|
}
|
|
|
|
void free_last_set(REP_SETS *sets)
|
|
{
|
|
sets->count--;
|
|
sets->extra++;
|
|
return;
|
|
}
|
|
|
|
void free_sets(REP_SETS *sets)
|
|
{
|
|
my_free((gptr)sets->set_buffer,MYF(0));
|
|
my_free((gptr)sets->bit_buffer,MYF(0));
|
|
return;
|
|
}
|
|
|
|
void internal_set_bit(REP_SET *set, uint bit)
|
|
{
|
|
set->bits[bit / WORD_BIT] |= 1 << (bit % WORD_BIT);
|
|
return;
|
|
}
|
|
|
|
void internal_clear_bit(REP_SET *set, uint bit)
|
|
{
|
|
set->bits[bit / WORD_BIT] &= ~ (1 << (bit % WORD_BIT));
|
|
return;
|
|
}
|
|
|
|
|
|
void or_bits(REP_SET *to,REP_SET *from)
|
|
{
|
|
reg1 uint i;
|
|
for (i=0 ; i < to->size_of_bits ; i++)
|
|
to->bits[i]|=from->bits[i];
|
|
return;
|
|
}
|
|
|
|
void copy_bits(REP_SET *to,REP_SET *from)
|
|
{
|
|
memcpy((byte*) to->bits,(byte*) from->bits,
|
|
(size_t) (sizeof(uint) * to->size_of_bits));
|
|
}
|
|
|
|
int cmp_bits(REP_SET *set1,REP_SET *set2)
|
|
{
|
|
return bcmp((byte*) set1->bits,(byte*) set2->bits,
|
|
sizeof(uint) * set1->size_of_bits);
|
|
}
|
|
|
|
|
|
/* Get next set bit from set. */
|
|
|
|
int get_next_bit(REP_SET *set,uint lastpos)
|
|
{
|
|
uint pos,*start,*end,bits;
|
|
|
|
start=set->bits+ ((lastpos+1) / WORD_BIT);
|
|
end=set->bits + set->size_of_bits;
|
|
bits=start[0] & ~((1 << ((lastpos+1) % WORD_BIT)) -1);
|
|
|
|
while (! bits && ++start < end)
|
|
bits=start[0];
|
|
if (!bits)
|
|
return 0;
|
|
pos=(uint) (start-set->bits)*WORD_BIT;
|
|
while (! (bits & 1))
|
|
{
|
|
bits>>=1;
|
|
pos++;
|
|
}
|
|
return pos;
|
|
}
|
|
|
|
/* find if there is a same set in sets. If there is, use it and
|
|
free given set, else put in given set in sets and return its
|
|
position */
|
|
|
|
int find_set(REP_SETS *sets,REP_SET *find)
|
|
{
|
|
uint i;
|
|
for (i=0 ; i < sets->count-1 ; i++)
|
|
{
|
|
if (!cmp_bits(sets->set+i,find))
|
|
{
|
|
free_last_set(sets);
|
|
return i;
|
|
}
|
|
}
|
|
return i; /* return new postion */
|
|
}
|
|
|
|
/* find if there is a found_set with same table_offset & found_offset
|
|
If there is return offset to it, else add new offset and return pos.
|
|
Pos returned is -offset-2 in found_set_structure because it is
|
|
saved in set->next and set->next[] >= 0 points to next set and
|
|
set->next[] == -1 is reserved for end without replaces.
|
|
*/
|
|
|
|
int find_found(FOUND_SET *found_set,uint table_offset, int found_offset)
|
|
{
|
|
int i;
|
|
for (i=0 ; (uint) i < found_sets ; i++)
|
|
if (found_set[i].table_offset == table_offset &&
|
|
found_set[i].found_offset == found_offset)
|
|
return -i-2;
|
|
found_set[i].table_offset=table_offset;
|
|
found_set[i].found_offset=found_offset;
|
|
found_sets++;
|
|
return -i-2; /* return new postion */
|
|
}
|
|
|
|
/* Return 1 if regexp starts with \b or ends with \b*/
|
|
|
|
uint start_at_word(my_string pos)
|
|
{
|
|
return (((!bcmp(pos,"\\b",2) && pos[2]) || !bcmp(pos,"\\^",2)) ? 1 : 0);
|
|
}
|
|
|
|
uint end_of_word(my_string pos)
|
|
{
|
|
my_string end=strend(pos);
|
|
return ((end > pos+2 && !bcmp(end-2,"\\b",2)) ||
|
|
(end >= pos+2 && !bcmp(end-2,"\\$",2))) ?
|
|
1 : 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Handle replacement of strings
|
|
****************************************************************************/
|
|
|
|
#define PC_MALLOC 256 /* Bytes for pointers */
|
|
#define PS_MALLOC 512 /* Bytes for data */
|
|
|
|
int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name)
|
|
{
|
|
uint i,length,old_count;
|
|
byte *new_pos;
|
|
const char **new_array;
|
|
DBUG_ENTER("insert_pointer_name");
|
|
|
|
if (! pa->typelib.count)
|
|
{
|
|
if (!(pa->typelib.type_names=(const char **)
|
|
my_malloc(((PC_MALLOC-MALLOC_OVERHEAD)/
|
|
(sizeof(my_string)+sizeof(*pa->flag))*
|
|
(sizeof(my_string)+sizeof(*pa->flag))),MYF(MY_WME))))
|
|
DBUG_RETURN(-1);
|
|
if (!(pa->str= (byte*) my_malloc((uint) (PS_MALLOC-MALLOC_OVERHEAD),
|
|
MYF(MY_WME))))
|
|
{
|
|
my_free((gptr) pa->typelib.type_names,MYF(0));
|
|
DBUG_RETURN (-1);
|
|
}
|
|
pa->max_count=(PC_MALLOC-MALLOC_OVERHEAD)/(sizeof(byte*)+
|
|
sizeof(*pa->flag));
|
|
pa->flag= (int7*) (pa->typelib.type_names+pa->max_count);
|
|
pa->length=0;
|
|
pa->max_length=PS_MALLOC-MALLOC_OVERHEAD;
|
|
pa->array_allocs=1;
|
|
}
|
|
length=(uint) strlen(name)+1;
|
|
if (pa->length+length >= pa->max_length)
|
|
{
|
|
if (!(new_pos= (byte*) my_realloc((gptr) pa->str,
|
|
(uint) (pa->max_length+PS_MALLOC),
|
|
MYF(MY_WME))))
|
|
DBUG_RETURN(1);
|
|
if (new_pos != pa->str)
|
|
{
|
|
my_ptrdiff_t diff=PTR_BYTE_DIFF(new_pos,pa->str);
|
|
for (i=0 ; i < pa->typelib.count ; i++)
|
|
pa->typelib.type_names[i]= ADD_TO_PTR(pa->typelib.type_names[i],diff,
|
|
char*);
|
|
pa->str=new_pos;
|
|
}
|
|
pa->max_length+=PS_MALLOC;
|
|
}
|
|
if (pa->typelib.count >= pa->max_count-1)
|
|
{
|
|
int len;
|
|
pa->array_allocs++;
|
|
len=(PC_MALLOC*pa->array_allocs - MALLOC_OVERHEAD);
|
|
if (!(new_array=(const char **) my_realloc((gptr) pa->typelib.type_names,
|
|
(uint) len/
|
|
(sizeof(byte*)+sizeof(*pa->flag))*
|
|
(sizeof(byte*)+sizeof(*pa->flag)),
|
|
MYF(MY_WME))))
|
|
DBUG_RETURN(1);
|
|
pa->typelib.type_names=new_array;
|
|
old_count=pa->max_count;
|
|
pa->max_count=len/(sizeof(byte*) + sizeof(*pa->flag));
|
|
pa->flag= (int7*) (pa->typelib.type_names+pa->max_count);
|
|
memcpy((byte*) pa->flag,(my_string) (pa->typelib.type_names+old_count),
|
|
old_count*sizeof(*pa->flag));
|
|
}
|
|
pa->flag[pa->typelib.count]=0; /* Reset flag */
|
|
pa->typelib.type_names[pa->typelib.count++]= pa->str+pa->length;
|
|
pa->typelib.type_names[pa->typelib.count]= NullS; /* Put end-mark */
|
|
VOID(strmov(pa->str+pa->length,name));
|
|
pa->length+=length;
|
|
DBUG_RETURN(0);
|
|
} /* insert_pointer_name */
|
|
|
|
|
|
/* free pointer array */
|
|
|
|
void free_pointer_array(POINTER_ARRAY *pa)
|
|
{
|
|
if (pa->typelib.count)
|
|
{
|
|
pa->typelib.count=0;
|
|
my_free((gptr) pa->typelib.type_names,MYF(0));
|
|
pa->typelib.type_names=0;
|
|
my_free((gptr) pa->str,MYF(0));
|
|
}
|
|
} /* free_pointer_array */
|
|
|
|
|
|
/* Functions that uses replace and replace_regex */
|
|
|
|
/* Append the string to ds, with optional replace */
|
|
void replace_dynstr_append_mem(DYNAMIC_STRING *ds,
|
|
const char *val, int len)
|
|
{
|
|
#ifdef __WIN__
|
|
fix_win_paths(val, len);
|
|
#endif
|
|
|
|
if (glob_replace_regex)
|
|
{
|
|
/* Regex replace */
|
|
if (!multi_reg_replace(glob_replace_regex, (char*)val))
|
|
{
|
|
val= glob_replace_regex->buf;
|
|
len= strlen(val);
|
|
}
|
|
}
|
|
|
|
if (glob_replace)
|
|
{
|
|
/* Normal replace */
|
|
replace_strings_append(glob_replace, ds, val, len);
|
|
}
|
|
else
|
|
dynstr_append_mem(ds, val, len);
|
|
}
|
|
|
|
|
|
/* Append zero-terminated string to ds, with optional replace */
|
|
void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val)
|
|
{
|
|
replace_dynstr_append_mem(ds, val, strlen(val));
|
|
}
|
|
|
|
/* Append uint to ds, with optional replace */
|
|
void replace_dynstr_append_uint(DYNAMIC_STRING *ds, uint val)
|
|
{
|
|
char buff[22]; /* This should be enough for any int */
|
|
char *end= longlong10_to_str(val, buff, 10);
|
|
replace_dynstr_append_mem(ds, buff, end - buff);
|
|
}
|