2001-05-23 15:26:42 +02:00
|
|
|
//____________________________________________________________
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
// PROGRAM: Alice (All Else) Utility
|
|
|
|
// MODULE: tdr.cpp
|
|
|
|
// DESCRIPTION: Routines for automated transaction recovery
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
// The contents of this file are subject to the Interbase Public
|
|
|
|
// License Version 1.0 (the "License"); you may not use this file
|
|
|
|
// except in compliance with the License. You may obtain a copy
|
|
|
|
// of the License at http://www.Inprise.com/IPL.html
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
// Software distributed under the License is distributed on an
|
|
|
|
// "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
|
|
|
|
// or implied. See the License for the specific language governing
|
|
|
|
// rights and limitations under the License.
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
// The Original Code was created by Inprise Corporation
|
|
|
|
// and its predecessors. Portions created by Inprise Corporation are
|
|
|
|
// Copyright (C) Inprise Corporation.
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
// All Rights Reserved.
|
|
|
|
// Contributor(s): ______________________________________.
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
//
|
|
|
|
//____________________________________________________________
|
|
|
|
//
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
|
|
|
// 2002.02.15 Sean Leyne - Code Cleanup, removed obsolete "Apollo" port
|
2001-05-23 15:26:42 +02:00
|
|
|
//
|
2002-10-28 06:19:52 +01:00
|
|
|
// 2002.10.27 Sean Leyne - Code Cleanup, removed obsolete "Ultrix" port
|
|
|
|
//
|
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-07-30 01:43:24 +02:00
|
|
|
#include "firebird.h"
|
2004-04-29 00:00:03 +02:00
|
|
|
#include <stdio.h>
|
2001-05-23 15:26:42 +02:00
|
|
|
#include <string.h>
|
2003-11-08 00:09:04 +01:00
|
|
|
#include "../jrd/ibase.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/common.h"
|
|
|
|
#include "../alice/alice.h"
|
|
|
|
#include "../alice/aliceswi.h"
|
|
|
|
#include "../alice/alice_proto.h"
|
|
|
|
#include "../alice/alice_meta.h"
|
|
|
|
#include "../alice/tdr_proto.h"
|
|
|
|
#include "../jrd/gds_proto.h"
|
|
|
|
#include "../jrd/isc_proto.h"
|
2008-01-16 06:58:53 +01:00
|
|
|
#include "../jrd/constants.h"
|
2004-12-09 20:19:47 +01:00
|
|
|
#include "../common/classes/ClumpletWriter.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2007-03-28 06:20:36 +02:00
|
|
|
using MsgFormat::SafeArg;
|
|
|
|
|
|
|
|
|
2009-01-03 10:14:29 +01:00
|
|
|
static ULONG ask();
|
2003-11-01 11:26:43 +01:00
|
|
|
static void print_description(const tdr*);
|
2009-01-03 10:14:29 +01:00
|
|
|
static void reattach_database(tdr*);
|
|
|
|
static void reattach_databases(tdr*);
|
2004-05-03 01:06:37 +02:00
|
|
|
static bool reconnect(FB_API_HANDLE, SLONG, const TEXT*, ULONG);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
|
2004-10-07 10:21:15 +02:00
|
|
|
//const char* const NEWLINE = "\n";
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-08 00:09:04 +01:00
|
|
|
static const UCHAR limbo_info[] = { isc_info_limbo, isc_info_end };
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
// The following routines are shared by the command line gfix and
|
|
|
|
// the windows server manager. These routines should not contain
|
2004-04-29 00:00:03 +02:00
|
|
|
// any direct screen I/O (i.e. printf/getc statements).
|
2001-05-23 15:26:42 +02:00
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
//____________________________________________________________
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
// Determine the proper action to take
|
|
|
|
// based on the state of the various
|
|
|
|
// transactions.
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
USHORT TDR_analyze(const tdr* trans)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-09-25 13:49:12 +02:00
|
|
|
USHORT advice = TRA_none;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (trans == NULL)
|
|
|
|
return TRA_none;
|
|
|
|
|
2009-04-17 16:10:11 +02:00
|
|
|
// if the tdr for the first transaction is missing,
|
|
|
|
// we can assume it was committed
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
USHORT state = trans->tdr_state;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (state == TRA_none)
|
|
|
|
state = TRA_commit;
|
|
|
|
else if (state == TRA_unknown)
|
|
|
|
advice = TRA_unknown;
|
|
|
|
|
2009-01-03 10:14:29 +01:00
|
|
|
for (trans = trans->tdr_next; trans; trans = trans->tdr_next)
|
|
|
|
{
|
|
|
|
switch (trans->tdr_state)
|
|
|
|
{
|
2003-09-25 13:49:12 +02:00
|
|
|
// an explicitly committed transaction necessitates a check for the
|
|
|
|
// perverse case of a rollback, otherwise a commit if at all possible
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case TRA_commit:
|
|
|
|
if (state == TRA_rollback) {
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(105);
|
2003-09-25 13:49:12 +02:00
|
|
|
// msg 105: Warning: Multidatabase transaction is in inconsistent state for recovery.
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(106, SafeArg() << trans->tdr_id);
|
2003-09-25 13:49:12 +02:00
|
|
|
// msg 106: Transaction %ld was committed, but prior ones were rolled back.
|
2001-05-23 15:26:42 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
advice = TRA_commit;
|
|
|
|
break;
|
|
|
|
|
|
|
|
// a prepared transaction requires a commit if there are missing
|
|
|
|
// records up to now, otherwise only do something if somebody else
|
2002-02-16 05:36:05 +01:00
|
|
|
// already has
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case TRA_limbo:
|
2008-01-16 06:58:53 +01:00
|
|
|
switch (state)
|
|
|
|
{
|
|
|
|
case TRA_none:
|
|
|
|
case TRA_commit:
|
2001-05-23 15:26:42 +02:00
|
|
|
advice = TRA_commit;
|
2008-01-16 06:58:53 +01:00
|
|
|
break;
|
|
|
|
case TRA_rollback:
|
2001-05-23 15:26:42 +02:00
|
|
|
advice = TRA_rollback;
|
2008-01-16 06:58:53 +01:00
|
|
|
break;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
// an explicitly rolled back transaction requires a rollback unless a
|
2002-02-16 05:36:05 +01:00
|
|
|
// transaction has committed or is assumed committed
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case TRA_rollback:
|
|
|
|
if ((state == TRA_commit) || (state == TRA_none)) {
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(105);
|
2003-09-25 13:49:12 +02:00
|
|
|
// msg 105: Warning: Multidatabase transaction is in inconsistent state for recovery.
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(107, SafeArg() << trans->tdr_id);
|
2003-09-25 13:49:12 +02:00
|
|
|
// msg 107: Transaction %ld was rolled back, but prior ones were committed.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2009-01-03 10:14:29 +01:00
|
|
|
advice = TRA_rollback;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
// a missing TDR indicates a committed transaction if a limbo one hasn't
|
|
|
|
// been found yet, otherwise it implies that the transaction wasn't
|
2002-02-16 05:36:05 +01:00
|
|
|
// prepared
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case TRA_none:
|
|
|
|
if (state == TRA_commit)
|
|
|
|
advice = TRA_commit;
|
|
|
|
else if (state == TRA_limbo)
|
|
|
|
advice = TRA_rollback;
|
|
|
|
break;
|
|
|
|
|
|
|
|
// specifically advise TRA_unknown to prevent assumption that all are
|
|
|
|
// in limbo
|
|
|
|
|
|
|
|
case TRA_unknown:
|
|
|
|
if (!advice)
|
|
|
|
advice = TRA_unknown;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(67, SafeArg() << trans->tdr_state);
|
|
|
|
// msg 67: Transaction state %d not in valid range.
|
2001-05-23 15:26:42 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return advice;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//____________________________________________________________
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
// Attempt to attach a database with a given pathname.
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-01-03 10:14:29 +01:00
|
|
|
bool TDR_attach_database(ISC_STATUS* status_vector, tdr* trans, const TEXT* pathname)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2004-07-02 12:02:46 +02:00
|
|
|
AliceGlobals* tdgbl = AliceGlobals::getSpecific();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (tdgbl->ALICE_data.ua_debug)
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(68, SafeArg() << pathname);
|
2003-09-25 13:49:12 +02:00
|
|
|
// msg 68: ATTACH_DATABASE: attempted attach of %s
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2005-11-27 21:53:09 +01:00
|
|
|
Firebird::ClumpletWriter dpb(Firebird::ClumpletReader::Tagged, MAX_DPB_SIZE, isc_dpb_version1);
|
2004-12-09 20:19:47 +01:00
|
|
|
dpb.insertTag(isc_dpb_no_garbage_collect);
|
|
|
|
dpb.insertTag(isc_dpb_gfix_attach);
|
2008-05-04 15:38:02 +02:00
|
|
|
tdgbl->uSvc->getAddressPath(dpb);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (tdgbl->ALICE_data.ua_user) {
|
2009-01-03 10:14:29 +01:00
|
|
|
dpb.insertString(isc_dpb_user_name, tdgbl->ALICE_data.ua_user, strlen(tdgbl->ALICE_data.ua_user));
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
if (tdgbl->ALICE_data.ua_password) {
|
2009-01-03 10:14:29 +01:00
|
|
|
dpb.insertString(tdgbl->uSvc->isService() ? isc_dpb_password_enc : isc_dpb_password,
|
|
|
|
tdgbl->ALICE_data.ua_password, strlen(tdgbl->ALICE_data.ua_password));
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2006-12-08 19:38:15 +01:00
|
|
|
if (tdgbl->ALICE_data.ua_tr_user) {
|
2008-01-16 06:58:53 +01:00
|
|
|
tdgbl->uSvc->checkService();
|
2008-12-05 02:20:14 +01:00
|
|
|
dpb.insertString(isc_dpb_trusted_auth,
|
2006-12-08 19:38:15 +01:00
|
|
|
tdgbl->ALICE_data.ua_tr_user,
|
|
|
|
strlen(reinterpret_cast<const char*>(tdgbl->ALICE_data.ua_tr_user)));
|
|
|
|
}
|
2008-01-16 06:58:53 +01:00
|
|
|
if (tdgbl->ALICE_data.ua_tr_role) {
|
|
|
|
tdgbl->uSvc->checkService();
|
|
|
|
dpb.insertString(isc_dpb_trusted_role, ADMIN_ROLE, strlen(ADMIN_ROLE));
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-03 01:06:37 +02:00
|
|
|
trans->tdr_db_handle = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-08 00:09:04 +01:00
|
|
|
isc_attach_database(status_vector, 0, pathname,
|
2004-12-09 20:19:47 +01:00
|
|
|
&trans->tdr_db_handle, dpb.getBufferLength(),
|
|
|
|
reinterpret_cast<const char*>(dpb.getBuffer()));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (status_vector[1]) {
|
|
|
|
if (tdgbl->ALICE_data.ua_debug) {
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(69); // msg 69: failed
|
2001-05-23 15:26:42 +02:00
|
|
|
ALICE_print_status(status_vector);
|
|
|
|
}
|
2003-09-10 19:52:12 +02:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
MET_set_capabilities(status_vector, trans);
|
|
|
|
|
|
|
|
if (tdgbl->ALICE_data.ua_debug)
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(70); // msg 70: succeeded
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-10 19:52:12 +02:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//____________________________________________________________
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
// Get the state of the various transactions
|
|
|
|
// in a multidatabase transaction.
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-01-03 10:14:29 +01:00
|
|
|
void TDR_get_states(tdr* trans)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-04-16 12:18:51 +02:00
|
|
|
ISC_STATUS_ARRAY status_vector;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-01-03 10:14:29 +01:00
|
|
|
for (tdr* ptr = trans; ptr; ptr = ptr->tdr_next)
|
2001-05-23 15:26:42 +02:00
|
|
|
MET_get_state(status_vector, ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//____________________________________________________________
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
// Detach all databases associated with
|
|
|
|
// a multidatabase transaction.
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-01-03 10:14:29 +01:00
|
|
|
void TDR_shutdown_databases(tdr* trans)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-04-16 12:18:51 +02:00
|
|
|
ISC_STATUS_ARRAY status_vector;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-01-03 10:14:29 +01:00
|
|
|
for (tdr* ptr = trans; ptr; ptr = ptr->tdr_next)
|
2003-11-08 00:09:04 +01:00
|
|
|
isc_detach_database(status_vector, &ptr->tdr_db_handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
|
|
|
// The following routines are only for the command line utility.
|
2001-05-23 15:26:42 +02:00
|
|
|
// This should really be split into two files...
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
|
|
|
|
//____________________________________________________________
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
// List transaction stuck in limbo. If the prompt switch is set,
|
|
|
|
// prompt for commit, rollback, or leave well enough alone.
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-05-03 01:06:37 +02:00
|
|
|
void TDR_list_limbo(FB_API_HANDLE handle, const TEXT* name, const ULONG switches)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-09-25 13:49:12 +02:00
|
|
|
UCHAR buffer[1024];
|
2003-04-16 12:18:51 +02:00
|
|
|
ISC_STATUS_ARRAY status_vector;
|
2004-07-02 12:02:46 +02:00
|
|
|
AliceGlobals* tdgbl = AliceGlobals::getSpecific();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-08 00:09:04 +01:00
|
|
|
if (isc_database_info(status_vector, &handle, sizeof(limbo_info),
|
2003-10-29 11:53:47 +01:00
|
|
|
reinterpret_cast<const char*>(limbo_info),
|
2001-05-23 15:26:42 +02:00
|
|
|
sizeof(buffer),
|
2006-04-05 00:48:29 +02:00
|
|
|
reinterpret_cast<char*>(buffer)))
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
ALICE_print_status(status_vector);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
SLONG id;
|
2009-01-03 10:14:29 +01:00
|
|
|
tdr* trans;
|
2003-09-25 13:49:12 +02:00
|
|
|
UCHAR* ptr = buffer;
|
|
|
|
bool flag = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-01-03 10:14:29 +01:00
|
|
|
while (flag)
|
|
|
|
{
|
2003-09-25 13:49:12 +02:00
|
|
|
const USHORT item = *ptr++;
|
2003-11-16 02:44:51 +01:00
|
|
|
const USHORT length = (USHORT) gds__vax_integer(ptr, 2);
|
2001-05-23 15:26:42 +02:00
|
|
|
ptr += 2;
|
2009-01-03 10:14:29 +01:00
|
|
|
switch (item)
|
|
|
|
{
|
2003-11-08 00:09:04 +01:00
|
|
|
case isc_info_limbo:
|
2003-11-16 02:44:51 +01:00
|
|
|
id = gds__vax_integer(ptr, length);
|
2009-01-03 10:14:29 +01:00
|
|
|
if (switches & (sw_commit | sw_rollback | sw_two_phase | sw_prompt))
|
2003-09-10 19:52:12 +02:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
TDR_reconnect_multiple(handle, id, name, switches);
|
|
|
|
ptr += length;
|
|
|
|
break;
|
|
|
|
}
|
2008-01-16 06:58:53 +01:00
|
|
|
if (!tdgbl->uSvc->isService())
|
|
|
|
{
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(71, SafeArg() << id);
|
2003-09-25 13:49:12 +02:00
|
|
|
// msg 71: Transaction %d is in limbo.
|
2008-01-16 06:58:53 +01:00
|
|
|
}
|
2008-12-05 02:20:14 +01:00
|
|
|
if (trans = MET_get_transaction(status_vector, handle, id))
|
2008-01-16 06:58:53 +01:00
|
|
|
{
|
|
|
|
tdgbl->uSvc->putSLong(isc_spb_multi_tra_id, id);
|
2001-05-23 15:26:42 +02:00
|
|
|
reattach_databases(trans);
|
|
|
|
TDR_get_states(trans);
|
|
|
|
TDR_shutdown_databases(trans);
|
|
|
|
print_description(trans);
|
|
|
|
}
|
2008-12-05 02:20:14 +01:00
|
|
|
else
|
2008-01-16 06:58:53 +01:00
|
|
|
{
|
|
|
|
tdgbl->uSvc->putSLong(isc_spb_single_tra_id, id);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
ptr += length;
|
|
|
|
break;
|
|
|
|
|
2003-11-08 00:09:04 +01:00
|
|
|
case isc_info_truncated:
|
2008-01-16 06:58:53 +01:00
|
|
|
if (!tdgbl->uSvc->isService())
|
|
|
|
{
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(72);
|
2003-09-25 13:49:12 +02:00
|
|
|
// msg 72: More limbo transactions than fit. Try again
|
2008-01-16 06:58:53 +01:00
|
|
|
}
|
|
|
|
// fall through
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-08 00:09:04 +01:00
|
|
|
case isc_info_end:
|
2003-09-10 19:52:12 +02:00
|
|
|
flag = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2008-01-16 06:58:53 +01:00
|
|
|
if (!tdgbl->uSvc->isService())
|
|
|
|
{
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(73, SafeArg() << item);
|
2003-09-25 13:49:12 +02:00
|
|
|
// msg 73: Unrecognized info item %d
|
2008-01-16 06:58:53 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//____________________________________________________________
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
// Check a transaction's TDR to see if it is
|
|
|
|
// a multi-database transaction. If so, commit
|
|
|
|
// or rollback according to the user's wishes.
|
|
|
|
// Object strongly if the transaction is in a
|
2002-02-16 05:36:05 +01:00
|
|
|
// state that would seem to preclude committing
|
|
|
|
// or rolling back, but essentially do what the
|
|
|
|
// user wants. Intelligence is assumed for the
|
2001-05-23 15:26:42 +02:00
|
|
|
// gfix user.
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-01-03 10:14:29 +01:00
|
|
|
bool TDR_reconnect_multiple(FB_API_HANDLE handle, SLONG id, const TEXT* name, ULONG switches)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-04-16 12:18:51 +02:00
|
|
|
ISC_STATUS_ARRAY status_vector;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-04-17 16:10:11 +02:00
|
|
|
// get the state of all the associated transactions
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-01-03 10:14:29 +01:00
|
|
|
tdr* trans = MET_get_transaction(status_vector, handle, id);
|
2003-09-25 13:49:12 +02:00
|
|
|
if (!trans)
|
2001-05-23 15:26:42 +02:00
|
|
|
return reconnect(handle, id, name, switches);
|
|
|
|
|
|
|
|
reattach_databases(trans);
|
|
|
|
TDR_get_states(trans);
|
|
|
|
|
2009-04-17 16:10:11 +02:00
|
|
|
// analyze what to do with them; if the advice contradicts the user's
|
|
|
|
// desire, make them confirm it; otherwise go with the flow.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-10-16 10:51:06 +02:00
|
|
|
const USHORT advice = TDR_analyze(trans);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!advice) {
|
|
|
|
print_description(trans);
|
|
|
|
switches = ask();
|
|
|
|
}
|
2009-01-03 10:14:29 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
switch (advice)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
case TRA_rollback:
|
|
|
|
if (switches & sw_commit) {
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(74, SafeArg() << trans->tdr_id);
|
2003-09-25 13:49:12 +02:00
|
|
|
// msg 74: A commit of transaction %ld will violate two-phase commit.
|
2001-05-23 15:26:42 +02:00
|
|
|
print_description(trans);
|
|
|
|
switches = ask();
|
|
|
|
}
|
|
|
|
else if (switches & sw_rollback)
|
|
|
|
switches |= sw_rollback;
|
|
|
|
else if (switches & sw_two_phase)
|
|
|
|
switches |= sw_rollback;
|
|
|
|
else if (switches & sw_prompt) {
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(75, SafeArg() << trans->tdr_id);
|
2003-09-25 13:49:12 +02:00
|
|
|
// msg 75: A rollback of transaction %ld is needed to preserve two-phase commit.
|
2001-05-23 15:26:42 +02:00
|
|
|
print_description(trans);
|
|
|
|
switches = ask();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TRA_commit:
|
|
|
|
if (switches & sw_rollback) {
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(76, SafeArg() << trans->tdr_id);
|
2003-09-25 13:49:12 +02:00
|
|
|
// msg 76: Transaction %ld has already been partially committed.
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(77);
|
2003-09-25 13:49:12 +02:00
|
|
|
// msg 77: A rollback of this transaction will violate two-phase commit.
|
2001-05-23 15:26:42 +02:00
|
|
|
print_description(trans);
|
|
|
|
switches = ask();
|
|
|
|
}
|
|
|
|
else if (switches & sw_commit)
|
|
|
|
switches |= sw_commit;
|
|
|
|
else if (switches & sw_two_phase)
|
|
|
|
switches |= sw_commit;
|
2001-05-24 16:54:26 +02:00
|
|
|
else if (switches & sw_prompt)
|
|
|
|
{
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(78, SafeArg() << trans->tdr_id);
|
2003-09-25 13:49:12 +02:00
|
|
|
// msg 78: Transaction %ld has been partially committed.
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(79);
|
2003-09-25 13:49:12 +02:00
|
|
|
// msg 79: A commit is necessary to preserve the two-phase commit.
|
2001-05-23 15:26:42 +02:00
|
|
|
print_description(trans);
|
|
|
|
switches = ask();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TRA_unknown:
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(80);
|
2003-09-25 13:49:12 +02:00
|
|
|
// msg 80: Insufficient information is available to determine
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(81, SafeArg() << trans->tdr_id);
|
2003-09-25 13:49:12 +02:00
|
|
|
// msg 81: a proper action for transaction %ld.
|
2001-05-23 15:26:42 +02:00
|
|
|
print_description(trans);
|
|
|
|
switches = ask();
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2001-05-24 16:54:26 +02:00
|
|
|
if (!(switches & (sw_commit | sw_rollback)))
|
|
|
|
{
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(82, SafeArg() << trans->tdr_id);
|
2003-09-25 13:49:12 +02:00
|
|
|
// msg 82: Transaction %ld: All subtransactions have been prepared.
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(83);
|
2003-09-25 13:49:12 +02:00
|
|
|
// msg 83: Either commit or rollback is possible.
|
2001-05-23 15:26:42 +02:00
|
|
|
print_description(trans);
|
|
|
|
switches = ask();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
bool error = false;
|
2008-01-16 06:58:53 +01:00
|
|
|
if (switches != ULONG(~0))
|
2001-05-24 16:54:26 +02:00
|
|
|
{
|
2003-09-25 13:49:12 +02:00
|
|
|
// now do the required operation with all the subtransactions
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (switches & (sw_commit | sw_rollback))
|
2001-05-24 16:54:26 +02:00
|
|
|
{
|
2009-01-03 10:14:29 +01:00
|
|
|
for (tdr* ptr = trans; ptr; ptr = ptr->tdr_next)
|
2001-05-24 16:54:26 +02:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
if (ptr->tdr_state == TRA_limbo)
|
2001-05-24 16:54:26 +02:00
|
|
|
{
|
2009-01-03 10:14:29 +01:00
|
|
|
reconnect(ptr->tdr_db_handle, ptr->tdr_id, ptr->tdr_filename, switches);
|
2001-05-24 16:54:26 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2001-05-24 16:54:26 +02:00
|
|
|
else
|
|
|
|
{
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(84); // msg 84: unexpected end of input
|
2003-09-10 19:52:12 +02:00
|
|
|
error = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2009-04-17 16:10:11 +02:00
|
|
|
// shutdown all the databases for cleanliness' sake
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
TDR_shutdown_databases(trans);
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//____________________________________________________________
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
// format and print description of a transaction in
|
|
|
|
// limbo, including all associated transactions
|
|
|
|
// in other databases.
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-01 11:26:43 +01:00
|
|
|
static void print_description(const tdr* trans)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2004-07-02 12:02:46 +02:00
|
|
|
AliceGlobals* tdgbl = AliceGlobals::getSpecific();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!trans)
|
2001-05-24 16:54:26 +02:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
2001-05-24 16:54:26 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-16 06:58:53 +01:00
|
|
|
if (!tdgbl->uSvc->isService())
|
2001-05-24 16:54:26 +02:00
|
|
|
{
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(92); // msg 92: Multidatabase transaction:
|
2001-05-24 16:54:26 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
bool prepared_seen = false;
|
2003-11-01 11:26:43 +01:00
|
|
|
for (const tdr* ptr = trans; ptr; ptr = ptr->tdr_next)
|
2001-05-24 16:54:26 +02:00
|
|
|
{
|
|
|
|
if (ptr->tdr_host_site)
|
|
|
|
{
|
2009-01-03 10:14:29 +01:00
|
|
|
const char* pszHostSize = reinterpret_cast<const char*>(ptr->tdr_host_site->str_data);
|
2001-05-24 16:54:26 +02:00
|
|
|
|
2008-01-16 06:58:53 +01:00
|
|
|
if (!tdgbl->uSvc->isService())
|
2001-05-24 16:54:26 +02:00
|
|
|
{
|
2008-01-16 06:58:53 +01:00
|
|
|
// msg 93: Host Site: %s
|
|
|
|
ALICE_print(93, SafeArg() << pszHostSize);
|
2001-05-24 16:54:26 +02:00
|
|
|
}
|
2008-01-16 06:58:53 +01:00
|
|
|
tdgbl->uSvc->putLine(isc_spb_tra_host_site, pszHostSize);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ptr->tdr_id)
|
2001-05-24 16:54:26 +02:00
|
|
|
{
|
2008-01-16 06:58:53 +01:00
|
|
|
if (!tdgbl->uSvc->isService())
|
|
|
|
{
|
|
|
|
// msg 94: Transaction %ld
|
|
|
|
ALICE_print(94, SafeArg() << ptr->tdr_id);
|
|
|
|
}
|
|
|
|
tdgbl->uSvc->putSLong(isc_spb_tra_id, ptr->tdr_id);
|
2001-05-24 16:54:26 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-05-24 16:54:26 +02:00
|
|
|
switch (ptr->tdr_state)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
case TRA_limbo:
|
2008-01-16 06:58:53 +01:00
|
|
|
if (!tdgbl->uSvc->isService())
|
|
|
|
{
|
|
|
|
ALICE_print(95); // msg 95: has been prepared.
|
|
|
|
}
|
|
|
|
tdgbl->uSvc->putChar(isc_spb_tra_state, isc_spb_tra_state_limbo);
|
2003-09-10 19:52:12 +02:00
|
|
|
prepared_seen = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TRA_commit:
|
2008-01-16 06:58:53 +01:00
|
|
|
if (!tdgbl->uSvc->isService())
|
|
|
|
{
|
|
|
|
ALICE_print(96); // msg 96: has been committed.
|
|
|
|
}
|
|
|
|
tdgbl->uSvc->putChar(isc_spb_tra_state, isc_spb_tra_state_commit);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TRA_rollback:
|
2008-01-16 06:58:53 +01:00
|
|
|
if (!tdgbl->uSvc->isService())
|
|
|
|
{
|
|
|
|
ALICE_print(97); // msg 97: has been rolled back.
|
|
|
|
}
|
|
|
|
tdgbl->uSvc->putChar(isc_spb_tra_state, isc_spb_tra_state_rollback);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TRA_unknown:
|
2008-01-16 06:58:53 +01:00
|
|
|
if (!tdgbl->uSvc->isService())
|
|
|
|
{
|
|
|
|
ALICE_print(98); // msg 98: is not available.
|
|
|
|
}
|
|
|
|
tdgbl->uSvc->putChar(isc_spb_tra_state, isc_spb_tra_state_unknown);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2008-01-16 06:58:53 +01:00
|
|
|
if (!tdgbl->uSvc->isService())
|
2001-05-24 16:54:26 +02:00
|
|
|
{
|
2003-09-25 13:49:12 +02:00
|
|
|
// msg 99: is not found, assumed not prepared.
|
|
|
|
// msg 100: is not found, assumed to be committed.
|
2008-01-16 06:58:53 +01:00
|
|
|
ALICE_print(prepared_seen ? 99 : 100);
|
2001-05-24 16:54:26 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-05-24 16:54:26 +02:00
|
|
|
if (ptr->tdr_remote_site)
|
|
|
|
{
|
2009-01-03 10:14:29 +01:00
|
|
|
const char* pszRemoteSite = reinterpret_cast<const char*>(ptr->tdr_remote_site->str_data);
|
2001-05-24 16:54:26 +02:00
|
|
|
|
2008-01-16 06:58:53 +01:00
|
|
|
if (!tdgbl->uSvc->isService())
|
2001-05-24 16:54:26 +02:00
|
|
|
{
|
2009-04-17 16:10:11 +02:00
|
|
|
// msg 101: Remote Site: %s
|
2008-01-16 06:58:53 +01:00
|
|
|
ALICE_print(101, SafeArg() << pszRemoteSite);
|
2001-05-24 16:54:26 +02:00
|
|
|
}
|
2008-01-16 06:58:53 +01:00
|
|
|
tdgbl->uSvc->putLine(isc_spb_tra_remote_site, pszRemoteSite);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2001-05-24 16:54:26 +02:00
|
|
|
if (ptr->tdr_fullpath)
|
|
|
|
{
|
2009-01-03 10:14:29 +01:00
|
|
|
const char* pszFullpath = reinterpret_cast<const char*>(ptr->tdr_fullpath->str_data);
|
2001-05-24 16:54:26 +02:00
|
|
|
|
2008-01-16 06:58:53 +01:00
|
|
|
if (!tdgbl->uSvc->isService())
|
2001-05-24 16:54:26 +02:00
|
|
|
{
|
2008-01-16 06:58:53 +01:00
|
|
|
// msg 102: Database Path: %s
|
|
|
|
ALICE_print(102, SafeArg() << pszFullpath);
|
2001-05-24 16:54:26 +02:00
|
|
|
}
|
2008-01-16 06:58:53 +01:00
|
|
|
tdgbl->uSvc->putLine(isc_spb_tra_db_path, pszFullpath);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-17 16:10:11 +02:00
|
|
|
// let the user know what the suggested action is
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-05-24 16:54:26 +02:00
|
|
|
switch (TDR_analyze(trans))
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
case TRA_commit:
|
2008-01-16 06:58:53 +01:00
|
|
|
if (!tdgbl->uSvc->isService())
|
|
|
|
{
|
|
|
|
// msg 103: Automated recovery would commit this transaction.
|
|
|
|
ALICE_print(103);
|
|
|
|
}
|
|
|
|
tdgbl->uSvc->putChar(isc_spb_tra_advise, isc_spb_tra_advise_commit);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TRA_rollback:
|
2008-01-16 06:58:53 +01:00
|
|
|
if (!tdgbl->uSvc->isService())
|
|
|
|
{
|
|
|
|
// msg 104: Automated recovery would rollback this transaction.
|
|
|
|
ALICE_print(104);
|
|
|
|
}
|
|
|
|
tdgbl->uSvc->putChar(isc_spb_tra_advise, isc_spb_tra_advise_rollback);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2008-01-16 06:58:53 +01:00
|
|
|
tdgbl->uSvc->putChar(isc_spb_tra_advise, isc_spb_tra_advise_unknown);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//____________________________________________________________
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
// Ask the user whether to commit or rollback.
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-01-03 10:14:29 +01:00
|
|
|
static ULONG ask()
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2004-07-02 12:02:46 +02:00
|
|
|
AliceGlobals* tdgbl = AliceGlobals::getSpecific();
|
2008-01-16 06:58:53 +01:00
|
|
|
if (tdgbl->uSvc->isService())
|
2007-06-19 09:35:34 +02:00
|
|
|
{
|
2008-01-16 06:58:53 +01:00
|
|
|
return ~0;
|
2007-06-19 09:35:34 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2007-06-19 09:35:34 +02:00
|
|
|
char response[32];
|
2003-09-25 13:49:12 +02:00
|
|
|
ULONG switches = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-01-03 10:14:29 +01:00
|
|
|
while (true)
|
|
|
|
{
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(85);
|
2003-09-25 13:49:12 +02:00
|
|
|
// msg 85: Commit, rollback, or neither (c, r, or n)?
|
|
|
|
int c;
|
2004-09-26 09:37:34 +02:00
|
|
|
char* p;
|
2005-07-24 17:53:06 +02:00
|
|
|
for (p = response; (c = getchar()) != '\n' && !feof(stdin) && !ferror(stdin);)
|
2001-05-23 15:26:42 +02:00
|
|
|
*p++ = c;
|
2005-07-24 17:53:06 +02:00
|
|
|
if (p == response)
|
2008-01-16 06:58:53 +01:00
|
|
|
return ~0;
|
2001-05-23 15:26:42 +02:00
|
|
|
*p = 0;
|
2004-09-26 09:37:34 +02:00
|
|
|
ALICE_down_case(response, response, sizeof(response));
|
2008-12-31 06:06:08 +01:00
|
|
|
if (!strcmp(response, "n") || !strcmp(response, "c") || !strcmp(response, "r"))
|
2003-09-25 13:49:12 +02:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
2003-09-25 13:49:12 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (response[0] == 'c')
|
|
|
|
switches |= sw_commit;
|
|
|
|
else if (response[0] == 'r')
|
|
|
|
switches |= sw_rollback;
|
|
|
|
|
|
|
|
return switches;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//____________________________________________________________
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
|
|
|
// Generate pathnames for a given database
|
2001-05-23 15:26:42 +02:00
|
|
|
// until the database is successfully attached.
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-01-03 10:14:29 +01:00
|
|
|
static void reattach_database(tdr* trans)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-04-16 12:18:51 +02:00
|
|
|
ISC_STATUS_ARRAY status_vector;
|
2004-09-26 09:37:34 +02:00
|
|
|
char buffer[1024];
|
2003-10-16 10:51:06 +02:00
|
|
|
// sizeof(buffer) - 1 => leave space for the terminator.
|
2004-09-26 09:37:34 +02:00
|
|
|
const char* const end = buffer + sizeof(buffer) - 1;
|
2004-07-02 12:02:46 +02:00
|
|
|
AliceGlobals* tdgbl = AliceGlobals::getSpecific();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-09-26 09:37:34 +02:00
|
|
|
ISC_get_host(buffer, sizeof(buffer));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-04-17 16:10:11 +02:00
|
|
|
// if this is being run from the same host,
|
|
|
|
// try to reconnect using the same pathname
|
2002-02-19 02:17:23 +01:00
|
|
|
|
2009-01-03 10:14:29 +01:00
|
|
|
if (!strcmp(buffer, reinterpret_cast<const char*>(trans->tdr_host_site->str_data)))
|
2003-09-10 19:52:12 +02:00
|
|
|
{
|
|
|
|
if (TDR_attach_database(status_vector, trans,
|
2009-01-03 10:14:29 +01:00
|
|
|
reinterpret_cast<char*>(trans->tdr_fullpath->str_data)))
|
2003-09-10 19:52:12 +02:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2009-01-03 10:14:29 +01:00
|
|
|
else if (trans->tdr_host_site)
|
|
|
|
{
|
2003-10-16 10:51:06 +02:00
|
|
|
// try going through the previous host with all available
|
|
|
|
// protocols, using chaining to try the same method of
|
|
|
|
// attachment originally used from that host
|
2004-09-26 09:37:34 +02:00
|
|
|
char* p = buffer;
|
2003-10-16 10:51:06 +02:00
|
|
|
const UCHAR* q = trans->tdr_host_site->str_data;
|
|
|
|
while (*q && p < end)
|
2001-05-23 15:26:42 +02:00
|
|
|
*p++ = *q++;
|
2003-02-18 03:36:47 +01:00
|
|
|
*p++ = ':';
|
2003-10-16 10:51:06 +02:00
|
|
|
q = trans->tdr_fullpath->str_data;
|
|
|
|
while (*q && p < end)
|
2003-02-18 03:36:47 +01:00
|
|
|
*p++ = *q++;
|
2003-10-16 10:51:06 +02:00
|
|
|
*p = 0;
|
2004-09-26 09:37:34 +02:00
|
|
|
if (TDR_attach_database(status_vector, trans, buffer))
|
2003-09-10 19:52:12 +02:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2009-04-17 16:10:11 +02:00
|
|
|
// attaching using the old method didn't work;
|
|
|
|
// try attaching to the remote node directly
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (trans->tdr_remote_site) {
|
2004-09-26 09:37:34 +02:00
|
|
|
char* p = buffer;
|
2003-10-16 10:51:06 +02:00
|
|
|
const UCHAR* q = trans->tdr_remote_site->str_data;
|
|
|
|
while (*q && p < end)
|
2001-05-23 15:26:42 +02:00
|
|
|
*p++ = *q++;
|
2003-02-18 03:36:47 +01:00
|
|
|
*p++ = ':';
|
2004-09-26 09:37:34 +02:00
|
|
|
q = reinterpret_cast<const UCHAR*>(trans->tdr_filename);
|
2003-10-16 10:51:06 +02:00
|
|
|
while (*q && p < end)
|
2003-02-18 03:36:47 +01:00
|
|
|
*p++ = *q++;
|
2003-10-16 10:51:06 +02:00
|
|
|
*p = 0;
|
2004-09-26 09:37:34 +02:00
|
|
|
if (TDR_attach_database (status_vector, trans, buffer))
|
2003-09-10 19:52:12 +02:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2009-04-17 16:10:11 +02:00
|
|
|
// we have failed to reattach; notify the user
|
|
|
|
// and let them try to succeed where we have failed
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(86, SafeArg() << trans->tdr_id);
|
2003-09-25 13:49:12 +02:00
|
|
|
// msg 86: Could not reattach to database for transaction %ld.
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(87, SafeArg() << trans->tdr_fullpath->str_data);
|
|
|
|
// msg 87: Original path: %s
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-01-16 06:58:53 +01:00
|
|
|
if (tdgbl->uSvc->isService())
|
2007-06-19 09:35:34 +02:00
|
|
|
{
|
|
|
|
ALICE_exit(FINI_ERROR, tdgbl);
|
|
|
|
}
|
|
|
|
|
2008-12-05 02:20:14 +01:00
|
|
|
for (;;)
|
2007-06-19 09:35:34 +02:00
|
|
|
{
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(88); // msg 88: Enter a valid path:
|
2004-09-26 09:37:34 +02:00
|
|
|
char* p = buffer;
|
2005-07-24 17:53:06 +02:00
|
|
|
while (p < end && (*p = getchar()) != '\n' && !feof(stdin) && !ferror(stdin))
|
2003-10-16 10:51:06 +02:00
|
|
|
++p;
|
2001-05-23 15:26:42 +02:00
|
|
|
*p = 0;
|
|
|
|
if (!buffer[0])
|
|
|
|
break;
|
|
|
|
p = buffer;
|
|
|
|
while (*p == ' ')
|
2003-10-16 10:51:06 +02:00
|
|
|
++p;
|
2004-09-26 09:37:34 +02:00
|
|
|
if (TDR_attach_database(status_vector, trans, p))
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2004-09-26 09:37:34 +02:00
|
|
|
const size_t p_len = strlen(p);
|
2009-01-03 10:14:29 +01:00
|
|
|
alice_str* string = FB_NEW_RPT(*tdgbl->getDefaultPool(), p_len + 1) alice_str;
|
2004-09-26 09:37:34 +02:00
|
|
|
strcpy(reinterpret_cast<char*>(string->str_data), p);
|
|
|
|
string->str_length = p_len;
|
2001-05-23 15:26:42 +02:00
|
|
|
trans->tdr_fullpath = string;
|
|
|
|
trans->tdr_filename = (TEXT *) string->str_data;
|
|
|
|
return;
|
|
|
|
}
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(89); // msg 89: Attach unsuccessful.
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//____________________________________________________________
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
|
|
|
// Attempt to locate all databases used in
|
2001-05-23 15:26:42 +02:00
|
|
|
// a multidatabase transaction.
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-01-03 10:14:29 +01:00
|
|
|
static void reattach_databases(tdr* trans)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2009-01-03 10:14:29 +01:00
|
|
|
for (tdr* ptr = trans; ptr; ptr = ptr->tdr_next)
|
2001-05-23 15:26:42 +02:00
|
|
|
reattach_database(ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//____________________________________________________________
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
// Commit or rollback a named transaction.
|
2002-02-16 05:36:05 +01:00
|
|
|
//
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-01-03 10:14:29 +01:00
|
|
|
static bool reconnect(FB_API_HANDLE handle, SLONG number, const TEXT* name, ULONG switches)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-04-16 12:18:51 +02:00
|
|
|
ISC_STATUS_ARRAY status_vector;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-18 08:58:35 +01:00
|
|
|
const SLONG id = gds__vax_integer(reinterpret_cast<const UCHAR*>(&number), 4);
|
2004-05-03 01:06:37 +02:00
|
|
|
FB_API_HANDLE transaction = 0;
|
2003-11-08 00:09:04 +01:00
|
|
|
if (isc_reconnect_transaction(status_vector, &handle, &transaction,
|
2009-01-03 10:14:29 +01:00
|
|
|
sizeof(id), reinterpret_cast<const char*>(&id)))
|
2003-11-01 11:26:43 +01:00
|
|
|
{
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(90, SafeArg() << name);
|
2003-09-10 19:52:12 +02:00
|
|
|
// msg 90: failed to reconnect to a transaction in database %s
|
2001-05-23 15:26:42 +02:00
|
|
|
ALICE_print_status(status_vector);
|
2003-09-10 19:52:12 +02:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!(switches & (sw_commit | sw_rollback))) {
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(91, SafeArg() << number);
|
2003-09-10 19:52:12 +02:00
|
|
|
// msg 91: Transaction %ld:
|
2001-05-23 15:26:42 +02:00
|
|
|
switches = ask();
|
2008-01-16 06:58:53 +01:00
|
|
|
if (switches == ULONG(~0)) {
|
2007-03-28 06:20:36 +02:00
|
|
|
ALICE_print(84);
|
2003-09-10 19:52:12 +02:00
|
|
|
// msg 84: unexpected end of input
|
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (switches & sw_commit)
|
2003-11-08 00:09:04 +01:00
|
|
|
isc_commit_transaction(status_vector, &transaction);
|
2001-05-23 15:26:42 +02:00
|
|
|
else if (switches & sw_rollback)
|
2003-11-08 00:09:04 +01:00
|
|
|
isc_rollback_transaction(status_vector, &transaction);
|
2001-05-23 15:26:42 +02:00
|
|
|
else
|
2003-09-10 19:52:12 +02:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (status_vector[1]) {
|
|
|
|
ALICE_print_status(status_vector);
|
2003-09-10 19:52:12 +02:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-09-10 19:52:12 +02:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2002-03-11 17:34:08 +01:00
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
|