diff --git a/cmake/install_macros.cmake b/cmake/install_macros.cmake index aef438fe948..765f3be23e0 100644 --- a/cmake/install_macros.cmake +++ b/cmake/install_macros.cmake @@ -182,16 +182,20 @@ IF(WIN32) SET(SIGNTOOL_PARAMETERS /a /t http://timestamp.globalsign.com/?signature=sha2 CACHE STRING "parameters for signtool (list)") - FIND_PROGRAM(SIGNTOOL_EXECUTABLE signtool - PATHS "$ENV{ProgramFiles}/Microsoft SDKs/Windows/v7.0A/bin" - "$ENV{ProgramFiles}/Windows Kits/8.0/bin/x86" - "$ENV{ProgramFiles}/Windows Kits/8.1/bin/x86" - ) IF(NOT SIGNTOOL_EXECUTABLE) - MESSAGE(FATAL_ERROR - "signtool is not found. Signing executables not possible") + FILE(GLOB path_list + "$ENV{ProgramFiles} (x86)/Windows Kits/*/bin/*/x64" + "$ENV{ProgramFiles} (x86)/Windows Kits/*/App Certification Kit" + ) + FIND_PROGRAM(SIGNTOOL_EXECUTABLE signtool + PATHS ${path_list} + ) + IF(NOT SIGNTOOL_EXECUTABLE) + MESSAGE(FATAL_ERROR + "signtool is not found. Signing executables not possible") + ENDIF() + MARK_AS_ADVANCED(SIGNTOOL_EXECUTABLE SIGNTOOL_PARAMETERS) ENDIF() - MARK_AS_ADVANCED(SIGNTOOL_EXECUTABLE SIGNTOOL_PARAMETERS) ENDIF() ENDIF() diff --git a/mysql-test/main/cte_nonrecursive.result b/mysql-test/main/cte_nonrecursive.result index 17c73f74a49..407e9b6077e 100644 --- a/mysql-test/main/cte_nonrecursive.result +++ b/mysql-test/main/cte_nonrecursive.result @@ -2086,6 +2086,56 @@ a b a b 1 3 1 3 drop procedure sp; drop table t1; +# +# MDEV-26825: query with two usage of CTE that refers to another CTE +# with stored function using a base table. +# +create table t1 (id int primary key); +insert into t1 values +(1), (2), (3), (4), (5), (6), (7), (8), (9), (10); +create function f(in_id int) returns integer +return (select id from t1 where t1.id = in_id); +with c1 as (select id from t1 where f(id)=id group by id), +c2 as (select id from c1 as pt group by id) +select id from c2 as s1 union select id from c2 as s2; +id +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +with c1 as (select id from t1 as r where f(id)=id group by id), +c2 as (select id from c1 as pt group by id) +select id from c2 as s1 union select id from c2 as s2; +id +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +create function g() returns int return (select count(*) from t1); +create procedure sp1() +with c1 as (select id from t1 a where g() > 10), +c2 as (select id from c1) +select id from c2 as s1 union select id from c2 as s2; +call sp1(); +id +call sp1(); +id +drop procedure sp1; +drop function g; +drop function f; +drop table t1; # End of 10.2 tests # # MDEV-21673: several references to CTE that uses diff --git a/mysql-test/main/cte_nonrecursive.test b/mysql-test/main/cte_nonrecursive.test index 8ab3bddc410..78a901ba0f2 100644 --- a/mysql-test/main/cte_nonrecursive.test +++ b/mysql-test/main/cte_nonrecursive.test @@ -1554,6 +1554,42 @@ call sp(); drop procedure sp; drop table t1; +--echo # +--echo # MDEV-26825: query with two usage of CTE that refers to another CTE +--echo # with stored function using a base table. +--echo # + +create table t1 (id int primary key); +insert into t1 values +(1), (2), (3), (4), (5), (6), (7), (8), (9), (10); + +create function f(in_id int) returns integer +return (select id from t1 where t1.id = in_id); + +with c1 as (select id from t1 where f(id)=id group by id), + c2 as (select id from c1 as pt group by id) +select id from c2 as s1 union select id from c2 as s2; + +with c1 as (select id from t1 as r where f(id)=id group by id), + c2 as (select id from c1 as pt group by id) +select id from c2 as s1 union select id from c2 as s2; + +create function g() returns int return (select count(*) from t1); +create procedure sp1() + +with c1 as (select id from t1 a where g() > 10), + c2 as (select id from c1) +select id from c2 as s1 union select id from c2 as s2; + +call sp1(); +call sp1(); + +drop procedure sp1; +drop function g; + +drop function f; +drop table t1; + --echo # End of 10.2 tests --echo # diff --git a/mysql-test/suite/encryption/r/encryption_key_corruption.result b/mysql-test/suite/encryption/r/encryption_key_corruption.result new file mode 100644 index 00000000000..055abd687b6 --- /dev/null +++ b/mysql-test/suite/encryption/r/encryption_key_corruption.result @@ -0,0 +1,13 @@ +call mtr.add_suppression("InnoDB: .*: Page 0 at offset 0 looks corrupted"); +call mtr.add_suppression("Index for table 'dst' is corrupt; try to repair it"); +call mtr.add_suppression("Page for tablespace .* is index page with id .* but that index is not found from configuration file"); +CREATE TABLE src (pk INT PRIMARY KEY, value INT) ENGINE=INNODB; +INSERT INTO src VALUES (1, 1), (2, 2), (3, 3); +FLUSH TABLES src FOR EXPORT; +UNLOCK TABLES; +DROP TABLE src; +CREATE TABLE dst (pk INT PRIMARY KEY, value INT) ENGINE=INNODB; +ALTER TABLE dst DISCARD TABLESPACE; +ALTER TABLE dst IMPORT TABLESPACE; +ERROR HY000: Index for table 'dst' is corrupt; try to repair it +DROP TABLE dst; diff --git a/mysql-test/suite/encryption/t/encryption_key_corruption.combinations b/mysql-test/suite/encryption/t/encryption_key_corruption.combinations new file mode 100644 index 00000000000..ec77ac17760 --- /dev/null +++ b/mysql-test/suite/encryption/t/encryption_key_corruption.combinations @@ -0,0 +1,6 @@ +[crc32] +innodb-checksum-algorithm=crc32 +[none] +innodb-checksum-algorithm=none +[innodb] +innodb-checksum-algorithm=innodb diff --git a/mysql-test/suite/encryption/t/encryption_key_corruption.opt b/mysql-test/suite/encryption/t/encryption_key_corruption.opt new file mode 100644 index 00000000000..682d06d5732 --- /dev/null +++ b/mysql-test/suite/encryption/t/encryption_key_corruption.opt @@ -0,0 +1 @@ +--innodb-encrypt-tables=1 diff --git a/mysql-test/suite/encryption/t/encryption_key_corruption.test b/mysql-test/suite/encryption/t/encryption_key_corruption.test new file mode 100644 index 00000000000..9b4bd172a3a --- /dev/null +++ b/mysql-test/suite/encryption/t/encryption_key_corruption.test @@ -0,0 +1,44 @@ +--source include/have_innodb.inc +--source include/have_example_key_management_plugin.inc + +call mtr.add_suppression("InnoDB: .*: Page 0 at offset 0 looks corrupted"); +call mtr.add_suppression("Index for table 'dst' is corrupt; try to repair it"); +call mtr.add_suppression("Page for tablespace .* is index page with id .* but that index is not found from configuration file"); + +let MYSQLD_DATADIR = `SELECT @@datadir`; + + +CREATE TABLE src (pk INT PRIMARY KEY, value INT) ENGINE=INNODB; +INSERT INTO src VALUES (1, 1), (2, 2), (3, 3); + +FLUSH TABLES src FOR EXPORT; + +--copy_file $MYSQLD_DATADIR/test/src.ibd $MYSQLD_DATADIR/test/tmp.ibd +--copy_file $MYSQLD_DATADIR/test/src.cfg $MYSQLD_DATADIR/test/tmp.cfg + +perl; +use strict; +die unless open(FILE, "+<$ENV{MYSQLD_DATADIR}/test/tmp.ibd"); +binmode FILE; +die unless seek(FILE, 3 * 16384 + 26, 0); +print FILE pack("N", 0x00000000); +close(FILE); +EOF + +UNLOCK TABLES; + +DROP TABLE src; + +CREATE TABLE dst (pk INT PRIMARY KEY, value INT) ENGINE=INNODB; +ALTER TABLE dst DISCARD TABLESPACE; + +--copy_file $MYSQLD_DATADIR/test/tmp.ibd $MYSQLD_DATADIR/test/dst.ibd +--copy_file $MYSQLD_DATADIR/test/tmp.cfg $MYSQLD_DATADIR/test/dst.cfg + +--error ER_NOT_KEYFILE +ALTER TABLE dst IMPORT TABLESPACE; + +DROP TABLE dst; + +--remove_file $MYSQLD_DATADIR/test/tmp.ibd +--remove_file $MYSQLD_DATADIR/test/tmp.cfg diff --git a/mysql-test/suite/innodb/r/instant_alter_debug.result b/mysql-test/suite/innodb/r/instant_alter_debug.result index c74ec0a4bc4..d6229415d34 100644 --- a/mysql-test/suite/innodb/r/instant_alter_debug.result +++ b/mysql-test/suite/innodb/r/instant_alter_debug.result @@ -207,10 +207,11 @@ DELETE FROM t1; connection ddl; SET DEBUG_SYNC='row_log_table_apply1_before SIGNAL copied WAIT_FOR logged'; ALTER TABLE t1 FORCE; +connection default; +SET DEBUG_SYNC = 'now WAIT_FOR copied'; connection stop_purge; COMMIT; connection default; -SET DEBUG_SYNC = 'now WAIT_FOR copied'; InnoDB 1 transactions not purged INSERT INTO t1 SET a=1; INSERT INTO t1 SET a=2,b=3,c=4; @@ -230,9 +231,9 @@ DELETE FROM t1; connection ddl; SET DEBUG_SYNC='row_log_table_apply1_before SIGNAL copied WAIT_FOR logged'; ALTER TABLE t1 ADD COLUMN b INT NOT NULL DEFAULT 2 AFTER a, FORCE; -disconnect stop_purge; connection default; SET DEBUG_SYNC = 'now WAIT_FOR copied'; +disconnect stop_purge; InnoDB 1 transactions not purged INSERT INTO t1 SET a=1; INSERT INTO t1 SET a=2,c=4; diff --git a/mysql-test/suite/innodb/t/instant_alter_debug.test b/mysql-test/suite/innodb/t/instant_alter_debug.test index 9b174a1974b..02464d4f100 100644 --- a/mysql-test/suite/innodb/t/instant_alter_debug.test +++ b/mysql-test/suite/innodb/t/instant_alter_debug.test @@ -237,11 +237,11 @@ connection ddl; SET DEBUG_SYNC='row_log_table_apply1_before SIGNAL copied WAIT_FOR logged'; send ALTER TABLE t1 FORCE; -connection stop_purge; -COMMIT; - connection default; SET DEBUG_SYNC = 'now WAIT_FOR copied'; +connection stop_purge; +COMMIT; +connection default; let $wait_all_purged = 1; --source include/wait_all_purged.inc let $wait_all_purged = 0; @@ -266,10 +266,9 @@ connection ddl; SET DEBUG_SYNC='row_log_table_apply1_before SIGNAL copied WAIT_FOR logged'; send ALTER TABLE t1 ADD COLUMN b INT NOT NULL DEFAULT 2 AFTER a, FORCE; -disconnect stop_purge; - connection default; SET DEBUG_SYNC = 'now WAIT_FOR copied'; +disconnect stop_purge; let $wait_all_purged = 1; --source include/wait_all_purged.inc let $wait_all_purged = 0; diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc index c53ae300d0d..914b47dea6d 100644 --- a/sql/sql_cte.cc +++ b/sql/sql_cte.cc @@ -1048,6 +1048,15 @@ st_select_lex_unit *With_element::clone_parsed_spec(LEX *old_lex, lex_start(thd); lex->clone_spec_offset= unparsed_spec_offset; lex->with_cte_resolution= true; + /* + There's no need to add SPs/SFs referenced in the clone to the global + list of the SPs/SFs used in the query as they were added when the first + reference to the cloned CTE was parsed. Yet the recursive call of the + parser must to know that they were already included into the list. + */ + lex->sroutines= old_lex->sroutines; + lex->sroutines_list_own_last= old_lex->sroutines_list_own_last; + lex->sroutines_list_own_elements= old_lex->sroutines_list_own_elements; /* The specification of a CTE is to be parsed as a regular query. @@ -1092,6 +1101,29 @@ st_select_lex_unit *With_element::clone_parsed_spec(LEX *old_lex, if (parse_status) goto err; + /* + The unit of the specification that just has been parsed is included + as a slave of the select that contained in its from list the table + reference for which the unit has been created. + */ + lex->unit.include_down(with_table->select_lex); + lex->unit.set_slave(with_select); + lex->unit.cloned_from= spec; + + /* + Now all references to the CTE defined outside of the cloned specification + has to be resolved. Additionally if old_lex->only_cte_resolution == false + for the table references that has not been resolved requests for mdl_locks + has to be set. + */ + lex->only_cte_resolution= old_lex->only_cte_resolution; + if (lex->resolve_references_to_cte(lex->query_tables, + lex->query_tables_last)) + { + res= NULL; + goto err; + } + /* The global chain of TABLE_LIST objects created for the specification that just has been parsed is added to such chain that contains the reference @@ -1116,32 +1148,11 @@ st_select_lex_unit *With_element::clone_parsed_spec(LEX *old_lex, old_lex->query_tables_last= lex->query_tables_last; } } + old_lex->sroutines_list_own_last= lex->sroutines_list_own_last; + old_lex->sroutines_list_own_elements= lex->sroutines_list_own_elements; res= &lex->unit; res->with_element= this; - /* - The unit of the specification that just has been parsed is included - as a slave of the select that contained in its from list the table - reference for which the unit has been created. - */ - lex->unit.include_down(with_table->select_lex); - lex->unit.set_slave(with_select); - lex->unit.cloned_from= spec; - - /* - Now all references to the CTE defined outside of the cloned specification - has to be resolved. Additionally if old_lex->only_cte_resolution == false - for the table references that has not been resolved requests for mdl_locks - has to be set. - */ - lex->only_cte_resolution= old_lex->only_cte_resolution; - if (lex->resolve_references_to_cte(lex->query_tables, - lex->query_tables_last)) - { - res= NULL; - goto err; - } - last_clone_select= lex->all_selects_list; while (last_clone_select->next_select_in_list()) last_clone_select= last_clone_select->next_select_in_list(); diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc index 240a2682efc..fbd73209043 100644 --- a/storage/innobase/fil/fil0crypt.cc +++ b/storage/innobase/fil/fil0crypt.cc @@ -656,24 +656,19 @@ byte* fil_space_encrypt( @param[in] crypt_data crypt_data @param[in] tmp_frame Temporary buffer @param[in,out] src_frame Page to decrypt -@param[out] err DB_SUCCESS or DB_DECRYPTION_FAILED -@return true if page decrypted, false if not.*/ -static bool fil_space_decrypt_full_crc32( +@return DB_SUCCESS or error */ +static dberr_t fil_space_decrypt_full_crc32( ulint space, fil_space_crypt_t* crypt_data, byte* tmp_frame, - byte* src_frame, - dberr_t* err) + byte* src_frame) { uint key_version = mach_read_from_4( src_frame + FIL_PAGE_FCRC32_KEY_VERSION); lsn_t lsn = mach_read_from_8(src_frame + FIL_PAGE_LSN); uint offset = mach_read_from_4(src_frame + FIL_PAGE_OFFSET); - *err = DB_SUCCESS; - if (key_version == ENCRYPTION_KEY_NOT_ENCRYPTED) { - return false; - } + ut_a(key_version != ENCRYPTION_KEY_NOT_ENCRYPTED); ut_ad(crypt_data); ut_ad(crypt_data->is_encrypted()); @@ -687,9 +682,7 @@ static bool fil_space_decrypt_full_crc32( bool corrupted = false; uint size = buf_page_full_crc32_size(src_frame, NULL, &corrupted); if (UNIV_UNLIKELY(corrupted)) { -fail: - *err = DB_DECRYPTION_FAILED; - return false; + return DB_DECRYPTION_FAILED; } uint srclen = size - (FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION @@ -701,7 +694,7 @@ fail: if (rc != MY_AES_OK || dstlen != srclen) { if (rc == -1) { - goto fail; + return DB_DECRYPTION_FAILED; } ib::fatal() << "Unable to decrypt data-block " @@ -718,7 +711,7 @@ fail: srv_stats.pages_decrypted.inc(); - return true; /* page was decrypted */ + return DB_SUCCESS; /* page was decrypted */ } /** Decrypt a page for non full checksum format. @@ -726,14 +719,12 @@ fail: @param[in] tmp_frame Temporary buffer @param[in] physical_size page size @param[in,out] src_frame Page to decrypt -@param[out] err DB_SUCCESS or DB_DECRYPTION_FAILED -@return true if page decrypted, false if not.*/ -static bool fil_space_decrypt_for_non_full_checksum( +@return DB_SUCCESS or error */ +static dberr_t fil_space_decrypt_for_non_full_checksum( fil_space_crypt_t* crypt_data, byte* tmp_frame, ulint physical_size, - byte* src_frame, - dberr_t* err) + byte* src_frame) { uint key_version = mach_read_from_4( src_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION); @@ -744,12 +735,7 @@ static bool fil_space_decrypt_for_non_full_checksum( src_frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); ib_uint64_t lsn = mach_read_from_8(src_frame + FIL_PAGE_LSN); - *err = DB_SUCCESS; - - if (key_version == ENCRYPTION_KEY_NOT_ENCRYPTED) { - return false; - } - + ut_a(key_version != ENCRYPTION_KEY_NOT_ENCRYPTED); ut_a(crypt_data != NULL && crypt_data->is_encrypted()); /* read space & lsn */ @@ -779,8 +765,7 @@ static bool fil_space_decrypt_for_non_full_checksum( if (! ((rc == MY_AES_OK) && ((ulint) dstlen == srclen))) { if (rc == -1) { - *err = DB_DECRYPTION_FAILED; - return false; + return DB_DECRYPTION_FAILED; } ib::fatal() << "Unable to decrypt data-block " @@ -805,7 +790,7 @@ static bool fil_space_decrypt_for_non_full_checksum( srv_stats.pages_decrypted.inc(); - return true; /* page was decrypted */ + return DB_SUCCESS; /* page was decrypted */ } /** Decrypt a page. @@ -816,26 +801,25 @@ static bool fil_space_decrypt_for_non_full_checksum( @param[in] fsp_flags Tablespace flags @param[in,out] src_frame Page to decrypt @param[out] err DB_SUCCESS or DB_DECRYPTION_FAILED -@return true if page decrypted, false if not.*/ +@return DB_SUCCESS or error */ UNIV_INTERN -bool +dberr_t fil_space_decrypt( ulint space_id, fil_space_crypt_t* crypt_data, byte* tmp_frame, ulint physical_size, ulint fsp_flags, - byte* src_frame, - dberr_t* err) + byte* src_frame) { if (fil_space_t::full_crc32(fsp_flags)) { return fil_space_decrypt_full_crc32( - space_id, crypt_data, tmp_frame, src_frame, err); + space_id, crypt_data, tmp_frame, src_frame); } return fil_space_decrypt_for_non_full_checksum(crypt_data, tmp_frame, - physical_size, src_frame, - err); + physical_size, + src_frame); } /** @@ -852,29 +836,22 @@ fil_space_decrypt( byte* tmp_frame, byte* src_frame) { - dberr_t err = DB_SUCCESS; - byte* res = NULL; const ulint physical_size = space->physical_size(); ut_ad(space->crypt_data != NULL && space->crypt_data->is_encrypted()); ut_ad(space->referenced()); - bool encrypted = fil_space_decrypt(space->id, space->crypt_data, - tmp_frame, physical_size, - space->flags, - src_frame, &err); - - if (err == DB_SUCCESS) { - if (encrypted) { - /* Copy the decrypted page back to page buffer, not - really any other options. */ - memcpy(src_frame, tmp_frame, physical_size); - } - - res = src_frame; + if (DB_SUCCESS != fil_space_decrypt(space->id, space->crypt_data, + tmp_frame, physical_size, + space->flags, src_frame)) { + return nullptr; } - return res; + /* Copy the decrypted page back to page buffer, not + really any other options. */ + memcpy(src_frame, tmp_frame, physical_size); + + return src_frame; } /** @@ -2581,7 +2558,10 @@ encrypted, or corrupted. @return true if page is encrypted AND OK, false otherwise */ bool fil_space_verify_crypt_checksum(const byte* page, ulint zip_size) { - ut_ad(mach_read_from_4(page + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION)); + if (ENCRYPTION_KEY_NOT_ENCRYPTED == mach_read_from_4( + page + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION)) { + return false; + } /* Compressed and encrypted pages do not have checksum. Assume not corrupted. Page verification happens after decompression in diff --git a/storage/innobase/include/fil0crypt.h b/storage/innobase/include/fil0crypt.h index 872053dcbcb..45e88bb023c 100644 --- a/storage/innobase/include/fil0crypt.h +++ b/storage/innobase/include/fil0crypt.h @@ -323,18 +323,16 @@ byte* fil_space_encrypt( @param[in] physical_size page size @param[in] fsp_flags Tablespace flags @param[in,out] src_frame Page to decrypt -@param[out] err DB_SUCCESS or DB_DECRYPTION_FAILED -@return true if page decrypted, false if not.*/ +@return DB_SUCCESS or error */ UNIV_INTERN -bool +dberr_t fil_space_decrypt( ulint space_id, fil_space_crypt_t* crypt_data, byte* tmp_frame, ulint physical_size, ulint fsp_flags, - byte* src_frame, - dberr_t* err); + byte* src_frame); /****************************************************************** Decrypt a page diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc index 4e764302b8b..45cc8c278b5 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -3109,9 +3109,8 @@ static dberr_t decrypt_decompress(fil_space_crypt_t *space_crypt, if (!buf_page_verify_crypt_checksum(data, space_flags)) return DB_CORRUPTION; - dberr_t err; - if (!fil_space_decrypt(space_id, space_crypt, data, page.size(), - space_flags, data, &err) || err != DB_SUCCESS) + if (dberr_t err= fil_space_decrypt(space_id, space_crypt, data, + page.size(), space_flags, data)) return err; } @@ -3825,9 +3824,12 @@ page_corrupted: if (!buf_page_verify_crypt_checksum(readptr, m_space_flags)) goto page_corrupted; - if (!fil_space_decrypt(get_space_id(), iter.crypt_data, readptr, - size, m_space_flags, readptr, &err) || - err != DB_SUCCESS) + if (ENCRYPTION_KEY_NOT_ENCRYPTED == + buf_page_get_key_version(readptr, m_space_flags)) + goto page_corrupted; + + if ((err= fil_space_decrypt(get_space_id(), iter.crypt_data, readptr, size, + m_space_flags, readptr))) goto func_exit; } @@ -3978,7 +3980,6 @@ page_corrupted: if (!encrypted) { } else if (!key_version) { -not_encrypted: if (block->page.id().page_no() == 0 && block->page.zip.data) { block->page.zip.data = src; @@ -3997,21 +3998,16 @@ not_encrypted: goto page_corrupted; } - decrypted = fil_space_decrypt( + if ((err = fil_space_decrypt( actual_space_id, iter.crypt_data, dst, callback.physical_size(), callback.get_space_flags(), - src, &err); - - if (err != DB_SUCCESS) { + src))) { goto func_exit; } - if (!decrypted) { - goto not_encrypted; - } - + decrypted = true; updated = true; } diff --git a/win/upgrade_wizard/upgradeDlg.cpp b/win/upgrade_wizard/upgradeDlg.cpp index a1b6c279fa6..80f7c18f757 100644 --- a/win/upgrade_wizard/upgradeDlg.cpp +++ b/win/upgrade_wizard/upgradeDlg.cpp @@ -448,7 +448,7 @@ void CUpgradeDlg::UpgradeOneService(const string& servicename) output_line.push_back(pipeReadBuf[0]); } } - CloseHandle(hPipeWrite); + CloseHandle(hPipeRead); if(WaitForSingleObject(pi.hProcess, INFINITE) != WAIT_OBJECT_0) ErrorExit("WaitForSingleObject failed");