2001-05-23 15:26:42 +02:00
|
|
|
/*
|
|
|
|
* PROGRAM: JRD Access Method
|
2003-09-25 13:49:12 +02:00
|
|
|
* MODULE: dba.epp
|
2001-05-23 15:26:42 +02:00
|
|
|
* DESCRIPTION: Database analysis tool
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* The Original Code was created by Inprise Corporation
|
|
|
|
* and its predecessors. Portions created by Inprise Corporation are
|
|
|
|
* Copyright (C) Inprise Corporation.
|
|
|
|
*
|
|
|
|
* All Rights Reserved.
|
|
|
|
* Contributor(s): ______________________________________.
|
2002-06-29 10:49:39 +02:00
|
|
|
*
|
|
|
|
* 2001.08.07 Sean Leyne - Code Cleanup, removed "#ifdef READONLY_DATABASE"
|
|
|
|
* conditionals, as the engine now fully supports
|
|
|
|
* readonly databases.
|
2002-10-30 07:40:58 +01:00
|
|
|
*
|
|
|
|
* 2002.10.29 Sean Leyne - Removed obsolete "Netware" port
|
|
|
|
*
|
2001-05-23 15:26:42 +02:00
|
|
|
*/
|
|
|
|
|
2002-06-29 10:49:39 +02:00
|
|
|
|
2001-07-30 01:43:24 +02:00
|
|
|
#include "firebird.h"
|
2002-07-05 17:00:26 +02:00
|
|
|
#include "../jrd/common.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/ib_stdio.h"
|
2003-01-16 18:47:10 +01:00
|
|
|
#include "../common/classes/alloc.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include "../jrd/ibsetjmp.h"
|
2003-02-14 03:14:41 +01:00
|
|
|
#include "../jrd/jrd_time.h"
|
2003-11-08 17:40:17 +01:00
|
|
|
#include "../jrd/y_ref.h"
|
|
|
|
#include "../jrd/ibase.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/ods.h"
|
2003-12-01 03:37:25 +01:00
|
|
|
#include "../jrd/btn.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/license.h"
|
|
|
|
#include "../jrd/msg_encode.h"
|
|
|
|
#include "../jrd/gdsassert.h"
|
|
|
|
#ifndef SUPERSERVER
|
2003-07-15 04:43:36 +02:00
|
|
|
#include "../utilities/gstat/ppg_proto.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
2003-07-15 04:43:36 +02:00
|
|
|
#include "../utilities/gstat/dbaswi.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/gds_proto.h"
|
|
|
|
#include "../jrd/isc_f_proto.h"
|
|
|
|
#include "../jrd/thd.h"
|
|
|
|
#include "../jrd/enc_proto.h"
|
|
|
|
#ifdef SUPERSERVER
|
2003-07-15 04:43:36 +02:00
|
|
|
#include "../utilities/common/cmd_util_proto.h"
|
2001-12-24 03:51:06 +01:00
|
|
|
#include "../jrd/thd_proto.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
2003-12-31 06:36:12 +01:00
|
|
|
#include "../common/utils_proto.h"
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-07-12 08:32:05 +02:00
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
#ifdef WIN_NT
|
2003-12-14 05:44:58 +01:00
|
|
|
#include <io.h>
|
2003-02-14 03:14:41 +01:00
|
|
|
#include "../jrd/jrd_pwd.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/* For Netware the follow DB handle and isc_status is #defined to be a */
|
|
|
|
/* local variable on the stack in main. This is to avoid multiple */
|
|
|
|
/* threading problems with module level statics. */
|
|
|
|
DATABASE DB = STATIC "yachts.lnk";
|
|
|
|
#define DB db_handle
|
|
|
|
#define isc_status status_vector
|
|
|
|
|
2003-04-09 14:45:21 +02:00
|
|
|
#define ALLOC(size) alloc ((size_t) size);
|
2001-05-23 15:26:42 +02:00
|
|
|
#define BUCKETS 5
|
|
|
|
#define WINDOW_SIZE (1 << 17)
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
struct dba_idx {
|
2004-02-02 12:02:12 +01:00
|
|
|
dba_idx* idx_next;
|
2001-05-23 15:26:42 +02:00
|
|
|
SSHORT idx_id;
|
|
|
|
SSHORT idx_depth;
|
|
|
|
SLONG idx_leaf_buckets;
|
|
|
|
SLONG idx_total_duplicates;
|
|
|
|
SLONG idx_max_duplicates;
|
|
|
|
SLONG idx_nodes;
|
|
|
|
SLONG idx_data_length;
|
|
|
|
SLONG idx_fill_distribution[BUCKETS];
|
|
|
|
SCHAR idx_name[32];
|
2003-12-31 06:36:12 +01:00
|
|
|
};
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
struct dba_rel {
|
2004-02-02 12:02:12 +01:00
|
|
|
dba_rel* rel_next;
|
|
|
|
dba_idx* rel_indexes;
|
2001-05-23 15:26:42 +02:00
|
|
|
SLONG rel_index_root;
|
|
|
|
SLONG rel_pointer_page;
|
|
|
|
SLONG rel_slots;
|
|
|
|
SLONG rel_data_pages;
|
|
|
|
ULONG rel_records;
|
|
|
|
ULONG rel_record_space;
|
|
|
|
ULONG rel_versions;
|
|
|
|
ULONG rel_version_space;
|
|
|
|
ULONG rel_max_versions;
|
|
|
|
SLONG rel_fill_distribution[BUCKETS];
|
|
|
|
ULONG rel_total_space;
|
|
|
|
SSHORT rel_id;
|
|
|
|
SCHAR rel_name[32];
|
2003-12-31 06:36:12 +01:00
|
|
|
};
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* kidnapped from jrd/pio.h and abused */
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
struct dba_fil {
|
2004-02-02 12:02:12 +01:00
|
|
|
dba_fil* fil_next; /* Next file in database */
|
2001-05-23 15:26:42 +02:00
|
|
|
ULONG fil_min_page; /* Minimum page number in file */
|
|
|
|
ULONG fil_max_page; /* Maximum page number in file */
|
|
|
|
USHORT fil_fudge; /* Fudge factor for page relocation */
|
|
|
|
#ifdef WIN_NT
|
|
|
|
void *fil_desc;
|
|
|
|
#else
|
|
|
|
int fil_desc;
|
|
|
|
#endif
|
|
|
|
USHORT fil_length; /* Length of expanded file name */
|
|
|
|
SCHAR fil_string[1]; /* Expanded file name */
|
2003-12-31 06:36:12 +01:00
|
|
|
};
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
static SCHAR* alloc(size_t);
|
|
|
|
static void analyze_data(dba_rel*, bool);
|
2004-02-02 12:02:12 +01:00
|
|
|
static bool analyze_data_page(dba_rel*, const data_page*, bool);
|
2003-12-31 06:36:12 +01:00
|
|
|
static ULONG analyze_fragments(const dba_rel*, const rhdf*);
|
2004-02-02 12:02:12 +01:00
|
|
|
static ULONG analyze_versions(dba_rel*, const rhdf*);
|
2003-12-31 06:36:12 +01:00
|
|
|
static void analyze_index(dba_rel*, dba_idx*);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
#if (defined WIN_NT)
|
|
|
|
static void db_error(SLONG);
|
|
|
|
#else
|
|
|
|
static void db_error(int);
|
|
|
|
#endif
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
static dba_fil* db_open(const char*, USHORT);
|
2004-02-02 12:02:12 +01:00
|
|
|
static const pag* db_read(SLONG);
|
2003-04-03 11:19:22 +02:00
|
|
|
#ifdef SUPERSERVER
|
2001-05-23 15:26:42 +02:00
|
|
|
static void db_close(int);
|
2003-04-03 11:19:22 +02:00
|
|
|
#endif
|
2003-12-31 06:36:12 +01:00
|
|
|
static void move(const SCHAR*, SCHAR*, SSHORT);
|
|
|
|
static void print_distribution(const SCHAR*, const SLONG*);
|
|
|
|
static void dba_error(USHORT, const TEXT*, const TEXT*, const TEXT*,
|
|
|
|
const TEXT*, const TEXT*);
|
|
|
|
static void dba_print(USHORT, const TEXT*, const TEXT*, const TEXT*,
|
|
|
|
const TEXT*, const TEXT*);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
#ifndef INCLUDE_FB_BLK
|
|
|
|
#include "../include/fb_blk.h"
|
|
|
|
#endif
|
|
|
|
|
2003-12-13 15:43:18 +01:00
|
|
|
#include "../jrd/db_alias.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/svc.h"
|
|
|
|
#include "../jrd/svc_proto.h"
|
|
|
|
|
|
|
|
#ifdef SUPERSERVER
|
|
|
|
#include <fcntl.h>
|
2002-10-30 07:40:58 +01:00
|
|
|
#if (defined WIN_NT)
|
2001-05-23 15:26:42 +02:00
|
|
|
#include <share.h>
|
|
|
|
#endif
|
|
|
|
|
2003-02-14 03:14:41 +01:00
|
|
|
#include "../jrd/jrd_pwd.h"
|
2003-07-15 04:43:36 +02:00
|
|
|
#include "../utilities/gstat/ppg_proto.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
#define FPRINTF SVC_fprintf
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
struct open_files {
|
2001-05-23 15:26:42 +02:00
|
|
|
int desc;
|
|
|
|
struct open_files *open_files_next;
|
2003-12-31 06:36:12 +01:00
|
|
|
};
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
struct dba_mem {
|
2003-04-09 14:45:21 +02:00
|
|
|
char *memory;
|
|
|
|
struct dba_mem *mem_next;
|
2003-12-31 06:36:12 +01:00
|
|
|
};
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef FPRINTF
|
|
|
|
#define FPRINTF ib_fprintf
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* threading declarations for thread data */
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
struct tdba {
|
2001-05-23 15:26:42 +02:00
|
|
|
struct thdd tdba_thd_data;
|
|
|
|
UCHAR *dba_env;
|
2003-12-31 06:36:12 +01:00
|
|
|
dba_fil* files;
|
|
|
|
dba_rel* relations;
|
2001-05-23 15:26:42 +02:00
|
|
|
SSHORT page_size;
|
|
|
|
SLONG page_number;
|
2004-02-02 12:02:12 +01:00
|
|
|
pag* buffer1;
|
|
|
|
pag* buffer2;
|
|
|
|
pag* global_buffer;
|
2001-05-23 15:26:42 +02:00
|
|
|
int exit_code;
|
|
|
|
#ifdef SUPERSERVER
|
2003-12-31 06:36:12 +01:00
|
|
|
svc* sw_outfile;
|
2003-04-09 14:45:21 +02:00
|
|
|
dba_mem *head_of_mem_list;
|
2001-05-23 15:26:42 +02:00
|
|
|
open_files *head_of_files_list;
|
2004-02-20 07:43:27 +01:00
|
|
|
svc* dba_service_blk;
|
2001-05-23 15:26:42 +02:00
|
|
|
#else
|
2003-12-31 06:36:12 +01:00
|
|
|
IB_FILE* sw_outfile;
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
2003-04-10 12:42:56 +02:00
|
|
|
ISC_STATUS *dba_status;
|
2003-04-16 12:18:51 +02:00
|
|
|
ISC_STATUS_ARRAY dba_status_vector;
|
2003-12-31 06:36:12 +01:00
|
|
|
};
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
#ifdef GET_THREAD_DATA
|
|
|
|
#undef GET_THREAD_DATA
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef SUPERSERVER
|
2003-12-31 06:36:12 +01:00
|
|
|
#define GET_THREAD_DATA ((tdba*) THD_get_specific())
|
2001-05-23 15:26:42 +02:00
|
|
|
#define SET_THREAD_DATA { tddba = &thd_context; \
|
|
|
|
THD_put_specific ((THDD) tddba);\
|
|
|
|
tddba->tdba_thd_data.thdd_type = THDD_TYPE_TDBA; }
|
|
|
|
#define RESTORE_THREAD_DATA THD_restore_specific()
|
|
|
|
#else
|
2003-12-31 06:36:12 +01:00
|
|
|
static struct tdba* gddba;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
#define GET_THREAD_DATA (gddba)
|
|
|
|
#define SET_THREAD_DATA gddba = tddba = &thd_context; \
|
|
|
|
tddba->tdba_thd_data.thdd_type = THDD_TYPE_TDBA
|
|
|
|
#define RESTORE_THREAD_DATA
|
|
|
|
#endif
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
void inline dba_exit(int code, tdba* tddba)
|
2003-08-26 20:43:29 +02:00
|
|
|
{
|
|
|
|
tddba->exit_code = code;
|
2004-03-01 05:57:43 +01:00
|
|
|
throw std::exception();
|
2003-08-26 20:43:29 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
#define GSTAT_MSG_FAC 21
|
|
|
|
|
2003-02-11 21:17:56 +01:00
|
|
|
#if defined (WIN95)
|
2003-08-26 08:52:05 +02:00
|
|
|
static bool fAnsiCP = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
#define TRANSLATE_CP(a) if (!fAnsiCP) CharToOem(a, a)
|
|
|
|
#else
|
|
|
|
#define TRANSLATE_CP(a)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef SUPERSERVER
|
2004-02-20 07:43:27 +01:00
|
|
|
int main_gstat( svc* service)
|
2001-05-23 15:26:42 +02:00
|
|
|
#else
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
int CLIB_ROUTINE main(int argc, char** argv)
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* m a i n
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Gather information from system relations to do analysis
|
|
|
|
* of a database.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-31 06:36:12 +01:00
|
|
|
SCHAR temp[1024], file_name[1024];
|
2003-08-26 08:52:05 +02:00
|
|
|
bool sw_system = false;
|
|
|
|
bool sw_data = false;
|
|
|
|
bool sw_index = false;
|
|
|
|
bool sw_version = false;
|
|
|
|
bool sw_header = false;
|
|
|
|
bool sw_log = false;
|
|
|
|
bool sw_record = false;
|
|
|
|
bool sw_relation = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
isc_db_handle db_handle = NULL;
|
|
|
|
UCHAR buf[256];
|
|
|
|
UCHAR pass_buff[128], user_buff[128], *password = pass_buff, *username =
|
|
|
|
user_buff;
|
|
|
|
struct tdba thd_context, *tddba;
|
|
|
|
JMP_BUF env;
|
2003-02-16 12:17:36 +01:00
|
|
|
#if defined (WIN95) && !defined (SUPERSERVER)
|
2001-05-23 15:26:42 +02:00
|
|
|
BOOL fAnsiCP;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
SET_THREAD_DATA;
|
|
|
|
SVC_PUTSPECIFIC_DATA;
|
|
|
|
memset(tddba, 0, sizeof(*tddba));
|
|
|
|
tddba->dba_env = (UCHAR *) env;
|
|
|
|
|
|
|
|
#ifdef SUPERSERVER
|
|
|
|
/* Reinitialize static variables for multi-threading */
|
2003-12-31 06:36:12 +01:00
|
|
|
int argc = service->svc_argc;
|
|
|
|
char** argv = service->svc_argv;
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
|
2003-09-25 13:49:12 +02:00
|
|
|
ISC_STATUS* status_vector = NULL;
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
try {
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
#ifdef SUPERSERVER
|
2003-12-31 06:36:12 +01:00
|
|
|
svc* sw_outfile = tddba->sw_outfile = service;
|
2001-05-23 15:26:42 +02:00
|
|
|
#else
|
2003-12-31 06:36:12 +01:00
|
|
|
IB_FILE* sw_outfile = tddba->sw_outfile = ib_stdout;
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
|
2003-02-11 21:17:56 +01:00
|
|
|
#if defined (WIN95) && !defined (SUPERSERVER)
|
2003-08-26 08:52:05 +02:00
|
|
|
fAnsiCP = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Perform some special handling when run as an Interbase service. The
|
|
|
|
first switch can be "-svc" (lower case!) or it can be "-svc_re" followed
|
|
|
|
by 3 file descriptors to use in re-directing ib_stdin, ib_stdout, and ib_stderr. */
|
|
|
|
tddba->dba_status = tddba->dba_status_vector;
|
|
|
|
status_vector = tddba->dba_status;
|
|
|
|
|
2003-12-14 05:44:58 +01:00
|
|
|
bool called_as_service = false;
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
if (argc > 1 && !strcmp(argv[1], "-svc")) {
|
2003-12-14 05:44:58 +01:00
|
|
|
called_as_service = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
argv++;
|
|
|
|
argc--;
|
|
|
|
}
|
|
|
|
#ifdef SUPERSERVER
|
|
|
|
else if (!strcmp(argv[1], "-svc_thd")) {
|
2003-12-14 05:44:58 +01:00
|
|
|
called_as_service = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
tddba->dba_service_blk = service;
|
|
|
|
tddba->dba_status = service->svc_status;
|
|
|
|
argv++;
|
|
|
|
argc--;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
else if (argc > 4 && !strcmp(argv[1], "-svc_re")) {
|
2003-12-14 05:44:58 +01:00
|
|
|
called_as_service = true;
|
|
|
|
long redir_in = atol(argv[2]);
|
|
|
|
long redir_out = atol(argv[3]);
|
|
|
|
long redir_err = atol(argv[4]);
|
2001-05-23 15:26:42 +02:00
|
|
|
#ifdef WIN_NT
|
2003-02-11 21:17:56 +01:00
|
|
|
#if defined (WIN95) && !defined (SUPERSERVER)
|
2003-08-26 08:52:05 +02:00
|
|
|
fAnsiCP = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
redir_in = _open_osfhandle(redir_in, 0);
|
|
|
|
redir_out = _open_osfhandle(redir_out, 0);
|
|
|
|
redir_err = _open_osfhandle(redir_err, 0);
|
|
|
|
#endif
|
|
|
|
if (redir_in != 0)
|
|
|
|
if (dup2((int) redir_in, 0))
|
|
|
|
close((int) redir_in);
|
|
|
|
if (redir_out != 1)
|
|
|
|
if (dup2((int) redir_out, 1))
|
|
|
|
close((int) redir_out);
|
|
|
|
if (redir_err != 2)
|
|
|
|
if (dup2((int) redir_err, 2))
|
|
|
|
close((int) redir_err);
|
|
|
|
argv += 4;
|
|
|
|
argc -= 4;
|
|
|
|
}
|
2003-12-31 06:36:12 +01:00
|
|
|
const char* name = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
MOVE_CLEAR(user_buff, sizeof(user_buff));
|
|
|
|
MOVE_CLEAR(pass_buff, sizeof(pass_buff));
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
const TEXT* const* const end = argv + argc;
|
|
|
|
++argv;
|
|
|
|
while (argv < end) {
|
|
|
|
const TEXT* str = *argv++;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (*str == '-') {
|
|
|
|
if (!str[1])
|
|
|
|
str = "-*NONE*";
|
2003-12-31 06:36:12 +01:00
|
|
|
in_sw_tab_t* in_sw_tab;
|
|
|
|
const TEXT* q;
|
2001-05-23 15:26:42 +02:00
|
|
|
for (in_sw_tab = dba_in_sw_table; q = in_sw_tab->in_sw_name;
|
2003-11-28 07:48:34 +01:00
|
|
|
in_sw_tab++)
|
|
|
|
{
|
2003-12-31 06:36:12 +01:00
|
|
|
TEXT c;
|
|
|
|
for (const TEXT* p = str + 1; c = *p++;) {
|
2001-05-23 15:26:42 +02:00
|
|
|
if (UPPER(c) != *q++)
|
|
|
|
break;
|
2003-12-31 06:36:12 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!c)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
in_sw_tab->in_sw_state = TRUE;
|
2004-02-02 12:02:12 +01:00
|
|
|
|
|
|
|
switch (in_sw_tab->in_sw)
|
|
|
|
{
|
|
|
|
case 0:
|
2001-05-23 15:26:42 +02:00
|
|
|
dba_print(20, str + 1, 0, 0, 0, 0); /* msg 20: unknown switch "%s" */
|
|
|
|
dba_print(21, 0, 0, 0, 0, 0); /* msg 21: Available switches: */
|
|
|
|
for (in_sw_tab = dba_in_sw_table; in_sw_tab->in_sw;
|
|
|
|
in_sw_tab++)
|
2003-12-31 06:36:12 +01:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
if (in_sw_tab->in_sw_msg)
|
|
|
|
dba_print(in_sw_tab->in_sw_msg, 0, 0, 0, 0, 0);
|
2003-12-31 06:36:12 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
#ifdef SUPERSERVER
|
|
|
|
CMD_UTIL_put_svc_status(tddba->dba_service_blk->svc_status,
|
|
|
|
GSTAT_MSG_FAC, 1,
|
|
|
|
0, NULL,
|
|
|
|
0, NULL, 0, NULL, 0, NULL, 0, NULL);
|
|
|
|
#endif
|
|
|
|
dba_error(1, 0, 0, 0, 0, 0); /* msg 1: found unknown switch */
|
2004-02-02 12:02:12 +01:00
|
|
|
break;
|
|
|
|
case IN_SW_DBA_USERNAME:
|
2003-09-03 09:39:03 +02:00
|
|
|
if (argv < end)
|
|
|
|
strcpy((char*) username, *argv++);
|
2004-02-02 12:02:12 +01:00
|
|
|
break;
|
|
|
|
case IN_SW_DBA_PASSWORD:
|
2003-09-03 09:39:03 +02:00
|
|
|
if (argv < end)
|
|
|
|
strcpy((char*) password, *argv++);
|
2004-02-02 12:02:12 +01:00
|
|
|
break;
|
|
|
|
case IN_SW_DBA_SYSTEM:
|
2003-08-26 08:52:05 +02:00
|
|
|
sw_system = true;
|
2004-02-02 12:02:12 +01:00
|
|
|
break;
|
|
|
|
case IN_SW_DBA_DATA:
|
2003-08-26 08:52:05 +02:00
|
|
|
sw_data = true;
|
2004-02-02 12:02:12 +01:00
|
|
|
break;
|
|
|
|
case IN_SW_DBA_INDEX:
|
2003-08-26 08:52:05 +02:00
|
|
|
sw_index = true;
|
2004-02-02 12:02:12 +01:00
|
|
|
break;
|
|
|
|
case IN_SW_DBA_VERSION:
|
2003-08-26 08:52:05 +02:00
|
|
|
sw_version = true;
|
2004-02-02 12:02:12 +01:00
|
|
|
break;
|
|
|
|
case IN_SW_DBA_HEADER:
|
2003-08-26 08:52:05 +02:00
|
|
|
sw_header = true;
|
2004-02-02 12:02:12 +01:00
|
|
|
break;
|
|
|
|
case IN_SW_DBA_LOG:
|
2003-08-26 08:52:05 +02:00
|
|
|
sw_log = true;
|
2004-02-02 12:02:12 +01:00
|
|
|
break;
|
|
|
|
case IN_SW_DBA_DATAIDX:
|
2003-08-26 08:52:05 +02:00
|
|
|
sw_index = sw_data = true;
|
2004-02-02 12:02:12 +01:00
|
|
|
break;
|
|
|
|
case IN_SW_DBA_RECORD:
|
2003-08-26 08:52:05 +02:00
|
|
|
sw_record = true;
|
2004-02-02 12:02:12 +01:00
|
|
|
break;
|
|
|
|
case IN_SW_DBA_RELATION:
|
2003-08-26 08:52:05 +02:00
|
|
|
sw_relation = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
while (argv < end && **argv != '-') {
|
|
|
|
if (strlen(*argv) > 31) {
|
|
|
|
argv++;
|
|
|
|
continue;
|
|
|
|
}
|
2003-12-31 06:36:12 +01:00
|
|
|
dba_rel* relation = (dba_rel*) ALLOC(sizeof(struct dba_rel));
|
2001-05-23 15:26:42 +02:00
|
|
|
strcpy(relation->rel_name, *argv++);
|
2003-12-31 06:36:12 +01:00
|
|
|
fb_utils::fb_exact_name(relation->rel_name);
|
2001-05-23 15:26:42 +02:00
|
|
|
relation->rel_id = -1;
|
2003-12-31 06:36:12 +01:00
|
|
|
dba_rel** next = &tddba->relations;
|
|
|
|
while (*next) {
|
|
|
|
next = &(*next)->rel_next;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
*next = relation;
|
|
|
|
}
|
2004-02-02 12:02:12 +01:00
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2004-02-02 12:02:12 +01:00
|
|
|
} // if (*str == '-')
|
2003-12-31 06:36:12 +01:00
|
|
|
else {
|
2001-05-23 15:26:42 +02:00
|
|
|
name = str;
|
2003-12-31 06:36:12 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-10-03 14:34:54 +02:00
|
|
|
if (sw_version)
|
|
|
|
dba_print(5, GDS_VERSION, 0, 0, 0, 0); /* msg 5: gstat version %s */
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!name) {
|
|
|
|
#ifdef SUPERSERVER
|
|
|
|
CMD_UTIL_put_svc_status(tddba->dba_service_blk->svc_status,
|
|
|
|
GSTAT_MSG_FAC, 2,
|
|
|
|
0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL);
|
|
|
|
#endif
|
|
|
|
dba_error(2, 0, 0, 0, 0, 0); /* msg 2: please retry, giving a database name */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sw_data && !sw_index)
|
2003-08-26 08:52:05 +02:00
|
|
|
sw_data = sw_index = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (sw_record && !sw_data)
|
2003-08-26 08:52:05 +02:00
|
|
|
sw_data = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-11 21:17:56 +01:00
|
|
|
#if defined (WIN95) && !defined (SUPERSERVER)
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!fAnsiCP) {
|
2003-12-31 06:36:12 +01:00
|
|
|
const ULONG ulConsoleCP = GetConsoleCP();
|
2001-05-23 15:26:42 +02:00
|
|
|
if (ulConsoleCP == GetACP())
|
2003-08-26 08:52:05 +02:00
|
|
|
fAnsiCP = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
else if (ulConsoleCP != GetOEMCP()) {
|
|
|
|
FPRINTF(sw_outfile,
|
|
|
|
"WARNING: The current codepage is not supported. Any use of any\n"
|
|
|
|
" extended characters may result in incorrect file names.\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Open database and go to work */
|
|
|
|
|
2003-12-13 15:43:18 +01:00
|
|
|
TEXT temp_buf[MAXPATHLEN];
|
2003-12-31 06:36:12 +01:00
|
|
|
if (ResolveDatabaseAlias(name, temp_buf)) {
|
2003-12-13 15:43:18 +01:00
|
|
|
name = temp_buf;
|
2003-12-31 06:36:12 +01:00
|
|
|
}
|
2003-12-13 15:43:18 +01:00
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
dba_fil* current = db_open(name, strlen(name));
|
2001-05-23 15:26:42 +02:00
|
|
|
tddba->page_size = sizeof(temp);
|
2004-02-02 12:02:12 +01:00
|
|
|
tddba->global_buffer = (pag*) temp;
|
2001-05-23 15:26:42 +02:00
|
|
|
tddba->page_number = -1;
|
2004-02-20 07:43:27 +01:00
|
|
|
const header_page* header = (const header_page*) db_read((SLONG) 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
#ifdef SUPERSERVER
|
2004-02-20 07:43:27 +01:00
|
|
|
service->svc_started();
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* ODS7 was not released as a shipping ODS and was replaced
|
|
|
|
* by ODS 8 in version 4.0 of InterBase. There will not be any
|
|
|
|
* customer databases which have an ODS of 7 */
|
|
|
|
|
|
|
|
if (header->hdr_ods_version > ODS_VERSION ||
|
|
|
|
(header->hdr_ods_version < ODS_VERSION8 &&
|
2003-12-31 06:36:12 +01:00
|
|
|
header->hdr_ods_version != ODS_VERSION6))
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
#ifdef SUPERSERVER
|
|
|
|
CMD_UTIL_put_svc_status(tddba->dba_service_blk->svc_status,
|
|
|
|
GSTAT_MSG_FAC, 3,
|
2001-12-24 03:51:06 +01:00
|
|
|
isc_arg_number, reinterpret_cast<void*>(ODS_VERSION),
|
|
|
|
isc_arg_number, reinterpret_cast<void*>(header->hdr_ods_version),
|
2001-05-23 15:26:42 +02:00
|
|
|
0, NULL, 0, NULL, 0, NULL);
|
|
|
|
#endif
|
2003-04-08 12:37:19 +02:00
|
|
|
dba_error(3, (TEXT *) ODS_VERSION, (TEXT *)(ULONG) header->hdr_ods_version,
|
2001-05-23 15:26:42 +02:00
|
|
|
0, 0, 0); /* msg 3: Wrong ODS version, expected %d, encountered %d? */
|
|
|
|
}
|
|
|
|
|
2003-02-11 21:17:56 +01:00
|
|
|
#if defined (WIN95) && !defined (SUPERSERVER)
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!fAnsiCP)
|
|
|
|
AnsiToOem(name, file_name);
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
strcpy(file_name, name);
|
|
|
|
|
|
|
|
dba_print(6, file_name, 0, 0, 0, 0); /* msg 6: \nDatabase \"%s\"\n */
|
|
|
|
|
|
|
|
tddba->page_size = header->hdr_page_size;
|
2004-02-02 12:02:12 +01:00
|
|
|
tddba->buffer1 = (pag*) ALLOC(tddba->page_size);
|
|
|
|
tddba->buffer2 = (pag*) ALLOC(tddba->page_size);
|
|
|
|
tddba->global_buffer = (pag*) ALLOC(tddba->page_size);
|
2001-05-23 15:26:42 +02:00
|
|
|
tddba->page_number = -1;
|
|
|
|
|
|
|
|
/* gather continuation files */
|
|
|
|
|
2003-12-05 11:35:47 +01:00
|
|
|
SLONG page = HEADER_PAGE;
|
2001-05-23 15:26:42 +02:00
|
|
|
do {
|
|
|
|
if (page != HEADER_PAGE)
|
2003-10-29 11:53:47 +01:00
|
|
|
current = db_open(file_name, strlen(file_name));
|
2001-05-23 15:26:42 +02:00
|
|
|
do {
|
2004-02-20 07:43:27 +01:00
|
|
|
header = (const header_page*) db_read((SLONG) page);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (current != tddba->files)
|
|
|
|
current->fil_fudge = 1; /* ignore header page once read it */
|
|
|
|
*file_name = '\0';
|
2003-12-31 06:36:12 +01:00
|
|
|
const UCHAR* vp = header->hdr_data;
|
|
|
|
for (const UCHAR* const vend = vp + header->hdr_page_size;
|
|
|
|
vp < vend && *vp != HDR_end; vp += 2 + vp[1])
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
if (*vp == HDR_file) {
|
|
|
|
memcpy(file_name, vp + 2, vp[1]);
|
|
|
|
*(file_name + vp[1]) = '\0';
|
2003-02-11 21:17:56 +01:00
|
|
|
#if defined (WIN95) && !defined (SUPERSERVER)
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!fAnsiCP)
|
|
|
|
AnsiToOem(file_name, file_name);
|
|
|
|
#endif
|
|
|
|
}
|
2003-12-31 06:36:12 +01:00
|
|
|
if (*vp == HDR_last_page) {
|
2001-05-23 15:26:42 +02:00
|
|
|
memcpy(¤t->fil_max_page, vp + 2,
|
|
|
|
sizeof(current->fil_max_page));
|
2003-12-31 06:36:12 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2003-12-31 06:36:12 +01:00
|
|
|
} while (page = header->hdr_next_page);
|
2001-05-23 15:26:42 +02:00
|
|
|
page = current->fil_max_page + 1; /* first page of next file */
|
2003-12-05 11:35:47 +01:00
|
|
|
} while (*file_name);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Print header page */
|
|
|
|
|
|
|
|
page = HEADER_PAGE;
|
|
|
|
do {
|
2004-02-20 07:43:27 +01:00
|
|
|
header = (const header_page*) db_read((SLONG) page);
|
2001-05-23 15:26:42 +02:00
|
|
|
PPG_print_header(header, page, sw_outfile);
|
2003-12-05 11:35:47 +01:00
|
|
|
page = header->hdr_next_page;
|
|
|
|
} while (page);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (sw_header)
|
2003-08-26 20:43:29 +02:00
|
|
|
dba_exit(FINI_OK, tddba);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* print continuation file sequence */
|
|
|
|
|
2003-08-26 08:52:05 +02:00
|
|
|
dba_print(7, 0, 0, 0, 0, 0);
|
|
|
|
// msg 7: \n\nDatabase file sequence:
|
2003-12-31 06:36:12 +01:00
|
|
|
for (current = tddba->files; current->fil_next; current = current->fil_next)
|
|
|
|
{
|
2003-08-26 08:52:05 +02:00
|
|
|
dba_print(8, current->fil_string, current->fil_next->fil_string, 0, 0, 0);
|
|
|
|
//* msg 8: File %s continues as file %s
|
2003-12-31 06:36:12 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
dba_print(9, current->fil_string,
|
2003-08-26 08:52:05 +02:00
|
|
|
(TEXT*)((current == tddba->files) ? "only" : "last"), 0, 0, 0);
|
|
|
|
// msg 9: File %s is the %s file\n
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* print log page */
|
|
|
|
|
|
|
|
page = LOG_PAGE;
|
|
|
|
do {
|
2003-12-05 11:35:47 +01:00
|
|
|
const log_info_page* logp = (const log_info_page*) db_read((SLONG) page);
|
2001-05-23 15:26:42 +02:00
|
|
|
PPG_print_log(logp, page, sw_outfile);
|
2003-12-05 11:35:47 +01:00
|
|
|
page = logp->log_next_page;
|
|
|
|
} while (page);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (sw_log)
|
2003-08-26 20:43:29 +02:00
|
|
|
dba_exit(FINI_OK, tddba);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Check to make sure that the user accessing the database is either
|
|
|
|
* SYSDBA or owner of the database */
|
2003-12-31 06:36:12 +01:00
|
|
|
UCHAR dpb_string[256];
|
|
|
|
UCHAR* dpb = dpb_string;
|
2003-11-08 17:40:17 +01:00
|
|
|
*dpb++ = isc_dpb_version1;
|
2001-05-23 15:26:42 +02:00
|
|
|
*dpb++ = isc_dpb_gstat_attach;
|
|
|
|
*dpb++ = 0;
|
|
|
|
|
|
|
|
if (*username) {
|
2003-11-08 17:40:17 +01:00
|
|
|
*dpb++ = isc_dpb_user_name;
|
2001-07-12 08:32:05 +02:00
|
|
|
*dpb++ = strlen((char*) username);
|
|
|
|
strcpy((char*) dpb, (char*) username);
|
|
|
|
dpb += strlen((char*) username);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (*password) {
|
2003-12-14 05:44:58 +01:00
|
|
|
if (called_as_service)
|
|
|
|
*dpb++ = isc_dpb_password_enc;
|
|
|
|
else
|
|
|
|
*dpb++ = isc_dpb_password;
|
2001-07-12 08:32:05 +02:00
|
|
|
*dpb++ = strlen((char*) password);
|
|
|
|
strcpy((char*) dpb, (char*) password);
|
|
|
|
dpb += strlen((char*) password);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
const SSHORT dpb_length = dpb - dpb_string;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-08-30 03:35:29 +02:00
|
|
|
isc_attach_database(status_vector, 0, name, &DB, dpb_length,
|
2001-07-12 08:32:05 +02:00
|
|
|
(char*) dpb_string);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (status_vector[1])
|
2003-08-26 20:43:29 +02:00
|
|
|
dba_exit(FINI_ERROR, tddba);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (sw_version)
|
2003-11-08 17:40:17 +01:00
|
|
|
isc_version(&DB, NULL, NULL);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
isc_tr_handle transact1 = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
START_TRANSACTION transact1 READ_ONLY;
|
|
|
|
ON_ERROR
|
2003-08-26 20:43:29 +02:00
|
|
|
dba_exit(FINI_ERROR, tddba);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
isc_req_handle request1 = NULL;
|
|
|
|
isc_req_handle request2 = NULL;
|
|
|
|
isc_req_handle request3 = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(TRANSACTION_HANDLE transact1 REQUEST_HANDLE request1)
|
|
|
|
X IN RDB$RELATIONS SORTED BY DESC X.RDB$RELATION_NAME
|
2001-12-24 03:51:06 +01:00
|
|
|
|
|
|
|
if (!sw_system && X.RDB$SYSTEM_FLAG) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!X.RDB$VIEW_BLR.NULL || !X.RDB$EXTERNAL_FILE.NULL) {
|
2001-05-23 15:26:42 +02:00
|
|
|
continue;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2003-12-31 06:36:12 +01:00
|
|
|
|
|
|
|
dba_rel* relation;
|
2001-12-24 03:51:06 +01:00
|
|
|
if (sw_relation)
|
|
|
|
{
|
2003-12-31 06:36:12 +01:00
|
|
|
fb_utils::fb_exact_name(X.RDB$RELATION_NAME);
|
|
|
|
for (relation = tddba->relations; relation;
|
|
|
|
relation = relation->rel_next)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!(strcmp(relation->rel_name, X.RDB$RELATION_NAME))) {
|
|
|
|
relation->rel_id = X.RDB$RELATION_ID;
|
|
|
|
break;
|
|
|
|
}
|
2003-12-31 06:36:12 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!relation)
|
|
|
|
continue;
|
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
else
|
|
|
|
{
|
2003-12-31 06:36:12 +01:00
|
|
|
relation = (dba_rel*) ALLOC(sizeof(struct dba_rel));
|
2001-05-23 15:26:42 +02:00
|
|
|
relation->rel_next = tddba->relations;
|
|
|
|
tddba->relations = relation;
|
|
|
|
relation->rel_id = X.RDB$RELATION_ID;
|
|
|
|
strcpy(relation->rel_name, X.RDB$RELATION_NAME);
|
2003-12-31 06:36:12 +01:00
|
|
|
fb_utils::fb_exact_name(relation->rel_name);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
FOR(TRANSACTION_HANDLE transact1 REQUEST_HANDLE request2)
|
|
|
|
Y IN RDB$PAGES WITH Y.RDB$RELATION_ID EQ relation->rel_id AND
|
2001-07-12 08:32:05 +02:00
|
|
|
Y.RDB$PAGE_SEQUENCE EQ 0
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (Y.RDB$PAGE_TYPE == pag_pointer) {
|
2001-05-23 15:26:42 +02:00
|
|
|
relation->rel_pointer_page = Y.RDB$PAGE_NUMBER;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
|
|
|
if (Y.RDB$PAGE_TYPE == pag_root) {
|
2001-05-23 15:26:42 +02:00
|
|
|
relation->rel_index_root = Y.RDB$PAGE_NUMBER;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
END_FOR;
|
|
|
|
ON_ERROR
|
2003-08-26 20:43:29 +02:00
|
|
|
dba_exit(FINI_ERROR, tddba);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR
|
2003-12-31 06:36:12 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
if (sw_index)
|
|
|
|
FOR(TRANSACTION_HANDLE transact1 REQUEST_HANDLE request3)
|
|
|
|
Y IN RDB$INDICES WITH Y.RDB$RELATION_NAME EQ relation->rel_name
|
2001-07-12 08:32:05 +02:00
|
|
|
SORTED BY DESC Y.RDB$INDEX_NAME
|
2001-05-23 15:26:42 +02:00
|
|
|
if (Y.RDB$INDEX_INACTIVE)
|
|
|
|
continue;
|
2003-12-31 06:36:12 +01:00
|
|
|
dba_idx* index = (dba_idx*) ALLOC(sizeof(struct dba_idx));
|
2001-05-23 15:26:42 +02:00
|
|
|
index->idx_next = relation->rel_indexes;
|
|
|
|
relation->rel_indexes = index;
|
|
|
|
strcpy(index->idx_name, Y.RDB$INDEX_NAME);
|
2003-12-31 06:36:12 +01:00
|
|
|
fb_utils::fb_exact_name(index->idx_name);
|
2001-05-23 15:26:42 +02:00
|
|
|
index->idx_id = Y.RDB$INDEX_ID - 1;
|
|
|
|
END_FOR;
|
|
|
|
ON_ERROR
|
2003-08-26 20:43:29 +02:00
|
|
|
dba_exit(FINI_ERROR, tddba);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR
|
|
|
|
END_FOR;
|
|
|
|
ON_ERROR
|
2003-08-26 20:43:29 +02:00
|
|
|
dba_exit(FINI_ERROR, tddba);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (request1) {
|
2001-05-23 15:26:42 +02:00
|
|
|
isc_release_request(status_vector, &request1);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
|
|
|
if (request2) {
|
2001-05-23 15:26:42 +02:00
|
|
|
isc_release_request(status_vector, &request2);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
|
|
|
if (request3) {
|
2001-05-23 15:26:42 +02:00
|
|
|
isc_release_request(status_vector, &request3);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
COMMIT transact1;
|
|
|
|
ON_ERROR
|
2003-08-26 20:43:29 +02:00
|
|
|
dba_exit(FINI_ERROR, tddba);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR
|
2003-03-05 15:38:48 +01:00
|
|
|
// FINISH; error!
|
2001-07-12 08:32:05 +02:00
|
|
|
FINISH
|
2001-05-23 15:26:42 +02:00
|
|
|
ON_ERROR
|
2003-08-26 20:43:29 +02:00
|
|
|
dba_exit(FINI_ERROR, tddba);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_ERROR
|
|
|
|
|
2003-08-26 08:52:05 +02:00
|
|
|
dba_print(10, 0, 0, 0, 0, 0);
|
|
|
|
// msg 10: \nAnalyzing database pages ...\n
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
{ // scope for MSVC6
|
|
|
|
for (dba_rel* relation = tddba->relations; relation;
|
|
|
|
relation = relation->rel_next)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
|
|
|
if (relation->rel_id == -1) {
|
2001-05-23 15:26:42 +02:00
|
|
|
continue;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
|
|
|
if (sw_data) {
|
2001-05-23 15:26:42 +02:00
|
|
|
analyze_data(relation, sw_record);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2003-12-31 06:36:12 +01:00
|
|
|
for (dba_idx* index = relation->rel_indexes; index;
|
|
|
|
index = index->idx_next)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
analyze_index(relation, index);
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2003-12-31 06:36:12 +01:00
|
|
|
} // scope for MSVC6
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Print results */
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
for (const dba_rel* relation = tddba->relations; relation;
|
|
|
|
relation = relation->rel_next)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
|
|
|
if (relation->rel_id == -1) {
|
2001-05-23 15:26:42 +02:00
|
|
|
continue;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
FPRINTF(sw_outfile, "%s (%d)\n", relation->rel_name,
|
|
|
|
relation->rel_id);
|
2001-12-24 03:51:06 +01:00
|
|
|
if (sw_data)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
dba_print(11, (TEXT *) relation->rel_pointer_page,
|
2003-08-26 08:52:05 +02:00
|
|
|
(TEXT *) relation->rel_index_root, 0, 0, 0);
|
|
|
|
// msg 11: " Primary pointer page: %ld, Index root page: %ld"
|
2001-05-23 15:26:42 +02:00
|
|
|
if (sw_record) {
|
2003-12-31 06:36:12 +01:00
|
|
|
double average = (relation->rel_records) ?
|
2001-05-23 15:26:42 +02:00
|
|
|
(double) relation->rel_record_space /
|
|
|
|
relation->rel_records : 0.0;
|
2001-07-12 08:32:05 +02:00
|
|
|
sprintf((char*) buf, "%.2f", average);
|
2001-05-23 15:26:42 +02:00
|
|
|
FPRINTF(sw_outfile,
|
|
|
|
" Average record length: %s, total records: %ld\n",
|
|
|
|
buf, relation->rel_records);
|
2003-08-26 08:52:05 +02:00
|
|
|
// dba_print(18, buf, relation->rel_records, 0, 0, 0);
|
|
|
|
// msg 18: " Average record length: %s, total records: %ld
|
2001-05-23 15:26:42 +02:00
|
|
|
average = (relation->rel_versions) ?
|
|
|
|
(double) relation->rel_version_space /
|
|
|
|
relation->rel_versions : 0.0;
|
2001-07-12 08:32:05 +02:00
|
|
|
sprintf((char*) buf, "%.2f", average);
|
2001-05-23 15:26:42 +02:00
|
|
|
FPRINTF(sw_outfile,
|
|
|
|
" Average version length: %s, total versions: %ld, max versions: %ld\n",
|
|
|
|
buf, relation->rel_versions,
|
|
|
|
relation->rel_max_versions);
|
2003-08-26 08:52:05 +02:00
|
|
|
// dba_print(19, buf, relation->rel_versions,
|
|
|
|
// relation->rel_max_versions, 0, 0);
|
|
|
|
// msg 19: " Average version length: %s, total versions: %ld, max versions: %ld
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
const double average = (relation->rel_data_pages) ?
|
2001-05-23 15:26:42 +02:00
|
|
|
(double) relation->rel_total_space * 100 /
|
|
|
|
((double) relation->rel_data_pages *
|
2003-12-31 06:36:12 +01:00
|
|
|
(tddba->page_size - DPG_SIZE)) : 0.0;
|
2001-07-12 08:32:05 +02:00
|
|
|
sprintf((char*) buf, "%.0f%%", average);
|
|
|
|
dba_print(12, (TEXT*) relation->rel_data_pages, (TEXT*) relation->rel_slots,
|
|
|
|
(TEXT*) buf, 0, 0); /* msg 12: " Data pages: %ld, data page slots: %ld, average fill: %s */
|
2001-05-23 15:26:42 +02:00
|
|
|
dba_print(13, 0, 0, 0, 0, 0); /* msg 13: " Fill distribution:" */
|
|
|
|
print_distribution("\t", relation->rel_fill_distribution);
|
|
|
|
}
|
|
|
|
FPRINTF(sw_outfile, "\n");
|
2003-12-31 06:36:12 +01:00
|
|
|
|
|
|
|
for (const dba_idx* index = relation->rel_indexes; index; index = index->idx_next)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2003-08-26 08:52:05 +02:00
|
|
|
dba_print(14, index->idx_name, (TEXT *)(SLONG) index->idx_id, 0, 0, 0);
|
|
|
|
// msg 14: " Index %s (%d)"
|
2003-04-08 12:37:19 +02:00
|
|
|
dba_print(15, (TEXT *)(SLONG) index->idx_depth,
|
2001-05-23 15:26:42 +02:00
|
|
|
(TEXT *) index->idx_leaf_buckets,
|
|
|
|
(TEXT *) index->idx_nodes, 0, 0);
|
2003-08-26 08:52:05 +02:00
|
|
|
// msg 15: \tDepth: %d, leaf buckets: %ld, nodes: %ld
|
2003-12-31 06:36:12 +01:00
|
|
|
const double average = (index->idx_nodes) ?
|
2001-05-23 15:26:42 +02:00
|
|
|
index->idx_data_length / index->idx_nodes : 0;
|
2001-07-12 08:32:05 +02:00
|
|
|
sprintf((char*) buf, "%.2f", average);
|
|
|
|
dba_print(16, (TEXT*) buf, (TEXT*) index->idx_total_duplicates,
|
2003-08-26 08:52:05 +02:00
|
|
|
(TEXT*) index->idx_max_duplicates, 0, 0);
|
|
|
|
// msg 16: \tAverage data length: %s, total dup: %ld, max dup: %ld"
|
|
|
|
dba_print(17, 0, 0, 0, 0, 0);
|
|
|
|
// msg 17: \tFill distribution:
|
2001-05-23 15:26:42 +02:00
|
|
|
print_distribution("\t ", index->idx_fill_distribution);
|
|
|
|
FPRINTF(sw_outfile, "\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-08-26 20:43:29 +02:00
|
|
|
dba_exit(FINI_OK, tddba);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
} // try
|
2004-03-01 04:35:23 +01:00
|
|
|
catch (const std::exception& ex)
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
2004-03-01 04:35:23 +01:00
|
|
|
Firebird::stuff_exception(status_vector, ex);
|
2001-12-24 03:51:06 +01:00
|
|
|
/* free mem */
|
|
|
|
|
|
|
|
if (status_vector[1])
|
|
|
|
{
|
|
|
|
#ifdef SUPERSERVER
|
2003-09-25 13:49:12 +02:00
|
|
|
ISC_STATUS* status = tddba->dba_service_blk->svc_status;
|
2001-12-24 03:51:06 +01:00
|
|
|
if (status != status_vector)
|
|
|
|
{
|
2003-12-31 06:36:12 +01:00
|
|
|
int i = 0;
|
2001-12-24 03:51:06 +01:00
|
|
|
while (*status && (++i < ISC_STATUS_LENGTH)) {
|
|
|
|
status++;
|
|
|
|
}
|
2003-12-31 06:36:12 +01:00
|
|
|
for (int j = 0; status_vector[j] && (i < ISC_STATUS_LENGTH);
|
2001-12-24 03:51:06 +01:00
|
|
|
j++, i++)
|
|
|
|
{
|
|
|
|
*status++ = status_vector[j];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2003-09-25 13:49:12 +02:00
|
|
|
const ISC_STATUS* vector = status_vector;
|
|
|
|
SCHAR s[1024];
|
2003-09-29 14:43:14 +02:00
|
|
|
if (isc_interprete_cpp(s, &vector))
|
2001-12-24 03:51:06 +01:00
|
|
|
{
|
|
|
|
FPRINTF(tddba->sw_outfile, "%s\n", s);
|
|
|
|
s[0] = '-';
|
2003-09-29 14:43:14 +02:00
|
|
|
while (isc_interprete_cpp(s + 1, &vector)) {
|
2001-12-24 03:51:06 +01:00
|
|
|
FPRINTF(tddba->sw_outfile, "%s\n", s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if there still exists a database handle, disconnect from the
|
|
|
|
* server
|
|
|
|
*/
|
|
|
|
FINISH;
|
|
|
|
|
|
|
|
#ifdef SUPERSERVER
|
2004-02-20 07:43:27 +01:00
|
|
|
service->svc_started();
|
2003-12-31 06:36:12 +01:00
|
|
|
dba_mem* alloced = tddba->head_of_mem_list;
|
2001-12-24 03:51:06 +01:00
|
|
|
while (alloced != 0) {
|
2003-04-09 14:45:21 +02:00
|
|
|
delete[] alloced->memory;
|
2001-12-24 03:51:06 +01:00
|
|
|
alloced = alloced->mem_next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* close files */
|
2003-12-31 06:36:12 +01:00
|
|
|
open_files* open_file = tddba->head_of_files_list;
|
2001-12-24 03:51:06 +01:00
|
|
|
while (open_file) {
|
|
|
|
db_close(open_file->desc);
|
|
|
|
open_file = open_file->open_files_next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* free linked lists */
|
|
|
|
while (tddba->head_of_files_list != 0) {
|
2003-12-31 06:36:12 +01:00
|
|
|
open_files* tmp1 = tddba->head_of_files_list;
|
2001-12-24 03:51:06 +01:00
|
|
|
tddba->head_of_files_list =
|
|
|
|
tddba->head_of_files_list->open_files_next;
|
2003-01-31 13:22:55 +01:00
|
|
|
delete tmp1;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
while (tddba->head_of_mem_list != 0) {
|
2003-12-31 06:36:12 +01:00
|
|
|
dba_mem* tmp2 = tddba->head_of_mem_list;
|
2001-12-24 03:51:06 +01:00
|
|
|
tddba->head_of_mem_list = tddba->head_of_mem_list->mem_next;
|
2003-01-31 13:22:55 +01:00
|
|
|
delete tmp2;
|
2001-12-24 03:51:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Mark service thread as finished and cleanup memory being
|
|
|
|
* used by service in case if client detached from the service
|
|
|
|
*/
|
|
|
|
|
|
|
|
SVC_finish(service, SVC_finished);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int exit_code = tddba->exit_code;
|
|
|
|
RESTORE_THREAD_DATA;
|
|
|
|
|
|
|
|
#ifdef SUPERSERVER
|
|
|
|
return exit_code;
|
|
|
|
#else
|
|
|
|
exit(exit_code);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
static char* alloc(size_t size)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* a l l o c
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Allocate and zero a piece of memory.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
#ifdef SUPERSERVER
|
2003-12-31 06:36:12 +01:00
|
|
|
tdba* tddba = GET_THREAD_DATA;
|
|
|
|
char* const block = FB_NEW(*getDefaultMemoryPool()) SCHAR[size];
|
|
|
|
#else
|
|
|
|
char* const block = (char*) gds__alloc(size);
|
|
|
|
#endif
|
|
|
|
if (!block) {
|
2001-05-23 15:26:42 +02:00
|
|
|
/* NOMEM: return error */
|
|
|
|
dba_error(31, 0, 0, 0, 0, 0);
|
|
|
|
}
|
|
|
|
/* note: shouldn't we check for the NULL?? */
|
2003-12-31 06:36:12 +01:00
|
|
|
char* p = block;
|
|
|
|
do {
|
2001-05-23 15:26:42 +02:00
|
|
|
*p++ = 0;
|
2003-12-31 06:36:12 +01:00
|
|
|
} while (--size);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
#ifdef SUPERSERVER
|
2003-04-09 14:45:21 +02:00
|
|
|
dba_mem* mem_list = FB_NEW(*getDefaultMemoryPool()) dba_mem;
|
2001-12-24 03:51:06 +01:00
|
|
|
if (!mem_list) {
|
2001-05-23 15:26:42 +02:00
|
|
|
/* NOMEM: return error */
|
|
|
|
dba_error(31, 0, 0, 0, 0, 0);
|
|
|
|
}
|
|
|
|
mem_list->memory = block;
|
|
|
|
mem_list->mem_next = 0;
|
|
|
|
|
|
|
|
if (tddba->head_of_mem_list == 0)
|
|
|
|
tddba->head_of_mem_list = mem_list;
|
|
|
|
else {
|
|
|
|
mem_list->mem_next = tddba->head_of_mem_list;
|
|
|
|
tddba->head_of_mem_list = mem_list;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return block;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
static void analyze_data( dba_rel* relation, bool sw_record)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* a n a l y z e _ d a t a
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Analyze data pages associated with relation.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-31 06:36:12 +01:00
|
|
|
tdba* tddba = GET_THREAD_DATA;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
pointer_page* ptr_page = (pointer_page*) tddba->buffer1;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
for (SLONG next_pp = relation->rel_pointer_page; next_pp;
|
2004-02-02 12:02:12 +01:00
|
|
|
next_pp = ptr_page->ppg_next)
|
2003-12-31 06:36:12 +01:00
|
|
|
{
|
2004-02-02 12:02:12 +01:00
|
|
|
move((const SCHAR*) db_read(next_pp), (SCHAR*) ptr_page, tddba->page_size);
|
|
|
|
const SLONG* ptr = ptr_page->ppg_page;
|
|
|
|
for (const SLONG* const end = ptr + ptr_page->ppg_count;
|
2003-12-31 06:36:12 +01:00
|
|
|
ptr < end; ptr++)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
++relation->rel_slots;
|
|
|
|
if (*ptr) {
|
|
|
|
++relation->rel_data_pages;
|
2004-02-02 12:02:12 +01:00
|
|
|
if (!analyze_data_page(relation, (const data_page*) db_read(*ptr), sw_record))
|
2003-12-31 06:36:12 +01:00
|
|
|
{
|
|
|
|
dba_print(18, (TEXT*) *ptr, 0, 0, 0, 0);
|
2003-08-26 08:52:05 +02:00
|
|
|
// msg 18: " Expected data on page %ld" */
|
2003-12-31 06:36:12 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static bool analyze_data_page( dba_rel* relation, const data_page* page, bool sw_record)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* a n a l y z e _ d a t a _ p a g e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Analyze space utilization for data page.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-31 06:36:12 +01:00
|
|
|
tdba* tddba = GET_THREAD_DATA;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (page->dpg_header.pag_type != pag_data)
|
2003-08-26 08:52:05 +02:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (sw_record) {
|
2004-02-02 12:02:12 +01:00
|
|
|
move((const SCHAR*) page, (SCHAR*) tddba->buffer2, tddba->page_size);
|
|
|
|
page = (const data_page*) tddba->buffer2;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
SSHORT space = page->dpg_count * sizeof(struct data_page::dpg_repeat);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
const data_page::dpg_repeat* tail = page->dpg_rpt;
|
|
|
|
for (const data_page::dpg_repeat* const end = tail + page->dpg_count; tail < end;
|
2001-05-23 15:26:42 +02:00
|
|
|
tail++)
|
2004-02-02 12:02:12 +01:00
|
|
|
{
|
|
|
|
if (tail->dpg_offset && tail->dpg_length)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
space += tail->dpg_length;
|
|
|
|
if (sw_record) {
|
2004-02-02 12:02:12 +01:00
|
|
|
const rhdf* header =
|
|
|
|
(const rhdf*) ((SCHAR *) page + tail->dpg_offset);
|
2003-12-31 06:36:12 +01:00
|
|
|
if (!(header->rhdf_flags &
|
|
|
|
(rhd_blob | rhd_chain | rhd_fragment)))
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
++relation->rel_records;
|
|
|
|
relation->rel_record_space += tail->dpg_length;
|
|
|
|
if (header->rhdf_flags & rhd_incomplete) {
|
|
|
|
relation->rel_record_space -= RHDF_SIZE;
|
|
|
|
relation->rel_record_space +=
|
|
|
|
analyze_fragments(relation, header);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
relation->rel_record_space -= RHD_SIZE;
|
|
|
|
|
|
|
|
if (header->rhdf_b_page)
|
|
|
|
relation->rel_version_space +=
|
|
|
|
analyze_versions(relation, header);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2004-02-02 12:02:12 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
relation->rel_total_space += space;
|
2004-02-02 12:02:12 +01:00
|
|
|
SSHORT bucket = (space * BUCKETS) / (tddba->page_size - DPG_SIZE);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (bucket == BUCKETS)
|
|
|
|
--bucket;
|
|
|
|
|
|
|
|
++relation->rel_fill_distribution[bucket];
|
|
|
|
|
2003-08-26 08:52:05 +02:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
static ULONG analyze_fragments(const dba_rel* relation, const rhdf* header)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* a n a l y z e _ f r a g m e n t s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Analyze space used by a record's fragments.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-31 06:36:12 +01:00
|
|
|
tdba* tddba = GET_THREAD_DATA;
|
|
|
|
ULONG space = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
while (header->rhdf_flags & rhd_incomplete) {
|
2003-12-31 06:36:12 +01:00
|
|
|
const SLONG f_page = header->rhdf_f_page;
|
|
|
|
const USHORT f_line = header->rhdf_f_line;
|
2004-02-02 12:02:12 +01:00
|
|
|
const data_page* page = (const data_page*) db_read(f_page);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (page->dpg_header.pag_type != pag_data ||
|
|
|
|
page->dpg_relation != relation->rel_id ||
|
2003-12-31 06:36:12 +01:00
|
|
|
page->dpg_count <= f_line)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2004-02-02 12:02:12 +01:00
|
|
|
const data_page::dpg_repeat* index = &page->dpg_rpt[f_line];
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!index->dpg_offset)
|
|
|
|
break;
|
|
|
|
space += index->dpg_length;
|
|
|
|
space -= RHDF_SIZE;
|
2003-12-31 06:36:12 +01:00
|
|
|
header = (const rhdf*) ((SCHAR *) page + index->dpg_offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return space;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
static void analyze_index( dba_rel* relation, dba_idx* index)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* a n a l y z e _ i n d e x
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-31 06:36:12 +01:00
|
|
|
tdba* tddba = GET_THREAD_DATA;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
const index_root_page* index_root =
|
|
|
|
(const index_root_page*) db_read(relation->rel_index_root);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-01 03:37:25 +01:00
|
|
|
SLONG page;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (index_root->irt_count <= index->idx_id ||
|
2003-12-01 03:37:25 +01:00
|
|
|
!(page = index_root->irt_rpt[index->idx_id].irt_root))
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
2003-12-01 03:37:25 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
// CVC: The two const_cast's for bucket can go away if BTreeNode's functions
|
|
|
|
// are overloaded for constness. They don't modify bucket and pointer's contents.
|
|
|
|
const btree_page* bucket = (const btree_page*) db_read(page);
|
2001-05-23 15:26:42 +02:00
|
|
|
index->idx_depth = bucket->btr_level + 1;
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
UCHAR* pointer;
|
2003-12-01 03:37:25 +01:00
|
|
|
IndexNode node;
|
|
|
|
while (bucket->btr_level)
|
|
|
|
{
|
2004-02-02 12:02:12 +01:00
|
|
|
pointer = BTreeNode::getPointerFirstNode(const_cast<btree_page*>(bucket));
|
2003-12-01 03:37:25 +01:00
|
|
|
BTreeNode::readNode(&node, pointer, bucket->btr_header.pag_flags, false);
|
2004-02-02 12:02:12 +01:00
|
|
|
bucket = (const btree_page*) db_read(node.pageNumber);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-12-01 03:37:25 +01:00
|
|
|
bool firstLeafNode = true;
|
|
|
|
SLONG number;
|
|
|
|
SLONG duplicates = 0;
|
|
|
|
// AB: In fact length for KEY should be MAX_KEY (1/4 of used page-size)
|
|
|
|
// This value should be kept equal with size declared in btr.h
|
|
|
|
//UCHAR key[4096];
|
|
|
|
UCHAR* key = (UCHAR*) ALLOC(tddba->page_size / 4);
|
|
|
|
USHORT key_length = 0;
|
|
|
|
while (true)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
++index->idx_leaf_buckets;
|
2004-02-02 12:02:12 +01:00
|
|
|
pointer = BTreeNode::getPointerFirstNode(const_cast<btree_page*>(bucket));
|
|
|
|
const UCHAR* const firstNode = pointer;
|
|
|
|
while (true)
|
2003-12-01 03:37:25 +01:00
|
|
|
{
|
|
|
|
pointer = BTreeNode::readNode(&node, pointer,
|
|
|
|
bucket->btr_header.pag_flags, true);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-01 03:37:25 +01:00
|
|
|
if (BTreeNode::isEndBucket(&node, true) ||
|
|
|
|
BTreeNode::isEndLevel(&node, true))
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
2003-12-01 03:37:25 +01:00
|
|
|
}
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
++index->idx_nodes;
|
2003-12-01 03:37:25 +01:00
|
|
|
index->idx_data_length += node.length;
|
2004-02-02 12:02:12 +01:00
|
|
|
USHORT l = node.length + node.prefix;
|
|
|
|
|
|
|
|
bool dup;
|
2003-12-01 03:37:25 +01:00
|
|
|
if (node.nodePointer == firstNode) {
|
|
|
|
dup = BTreeNode::keyEquality(key_length, key, &node);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
dup = (!node.length) && (l == key_length);
|
|
|
|
}
|
|
|
|
if (firstLeafNode) {
|
|
|
|
dup = false;
|
|
|
|
firstLeafNode = false;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
if (dup) {
|
|
|
|
++index->idx_total_duplicates;
|
|
|
|
++duplicates;
|
|
|
|
}
|
|
|
|
else {
|
2003-12-01 03:37:25 +01:00
|
|
|
if (duplicates > index->idx_max_duplicates) {
|
2001-05-23 15:26:42 +02:00
|
|
|
index->idx_max_duplicates = duplicates;
|
2003-12-01 03:37:25 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
duplicates = 0;
|
|
|
|
}
|
2003-12-01 03:37:25 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
key_length = l;
|
2003-12-01 03:37:25 +01:00
|
|
|
l = node.length;
|
|
|
|
if (l) {
|
2003-12-31 06:36:12 +01:00
|
|
|
UCHAR* p = key + node.prefix;
|
|
|
|
const UCHAR* q = node.data;
|
2003-12-01 03:37:25 +01:00
|
|
|
do {
|
2001-05-23 15:26:42 +02:00
|
|
|
*p++ = *q++;
|
2003-12-01 03:37:25 +01:00
|
|
|
} while (--l);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
2003-12-01 03:37:25 +01:00
|
|
|
|
|
|
|
if (duplicates > index->idx_max_duplicates) {
|
2001-05-23 15:26:42 +02:00
|
|
|
index->idx_max_duplicates = duplicates;
|
2003-12-01 03:37:25 +01:00
|
|
|
}
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
const USHORT header = (USHORT)(firstNode - (UCHAR*) bucket);
|
|
|
|
const USHORT space = bucket->btr_length - header;
|
|
|
|
USHORT n = (space * BUCKETS) / (tddba->page_size - header);
|
2003-12-01 03:37:25 +01:00
|
|
|
if (n == BUCKETS) {
|
2001-05-23 15:26:42 +02:00
|
|
|
--n;
|
2003-12-01 03:37:25 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
++index->idx_fill_distribution[n];
|
2003-12-01 03:37:25 +01:00
|
|
|
|
|
|
|
if (BTreeNode::isEndLevel(&node, true)) {
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
2003-12-01 03:37:25 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
number = page;
|
|
|
|
page = bucket->btr_sibling;
|
2004-02-02 12:02:12 +01:00
|
|
|
bucket = (const btree_page*) db_read(page);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (bucket->btr_header.pag_type != pag_index) {
|
2004-02-02 12:02:12 +01:00
|
|
|
dba_print(19, (const TEXT*) page, (const TEXT*) number, 0, 0, 0);
|
2003-12-01 03:37:25 +01:00
|
|
|
// mag 19: " Expected b-tree bucket on page %ld from %ld"
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static ULONG analyze_versions( dba_rel* relation, const rhdf* header)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* a n a l y z e _ v e r s i o n s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Analyze space used by a record's back versions.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-31 06:36:12 +01:00
|
|
|
tdba* tddba = GET_THREAD_DATA;
|
|
|
|
ULONG space = 0, versions = 0;
|
|
|
|
SLONG b_page = header->rhdf_b_page;
|
|
|
|
USHORT b_line = header->rhdf_b_line;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
while (b_page) {
|
2004-02-02 12:02:12 +01:00
|
|
|
const data_page* page = (const data_page*) db_read(b_page);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (page->dpg_header.pag_type != pag_data ||
|
|
|
|
page->dpg_relation != relation->rel_id ||
|
2003-12-31 06:36:12 +01:00
|
|
|
page->dpg_count <= b_line)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2004-02-02 12:02:12 +01:00
|
|
|
const data_page::dpg_repeat* index = &page->dpg_rpt[b_line];
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!index->dpg_offset)
|
|
|
|
break;
|
|
|
|
space += index->dpg_length;
|
|
|
|
++relation->rel_versions;
|
|
|
|
++versions;
|
2004-02-02 12:02:12 +01:00
|
|
|
header = (const rhdf*) ((SCHAR *) page + index->dpg_offset);
|
2001-05-23 15:26:42 +02:00
|
|
|
b_page = header->rhdf_b_page;
|
|
|
|
b_line = header->rhdf_b_line;
|
|
|
|
if (header->rhdf_flags & rhd_incomplete) {
|
|
|
|
space -= RHDF_SIZE;
|
|
|
|
space += analyze_fragments(relation, header);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
space -= RHD_SIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (versions > relation->rel_max_versions)
|
|
|
|
relation->rel_max_versions = versions;
|
|
|
|
|
|
|
|
return space;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef WIN_NT
|
2003-04-03 11:19:22 +02:00
|
|
|
#ifdef SUPERSERVER
|
2001-05-23 15:26:42 +02:00
|
|
|
static void db_close( int file_desc)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d b _ c l o s e ( W I N _ N T )
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Close an open file
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
CloseHandle((HANDLE) file_desc);
|
|
|
|
}
|
2003-04-03 11:19:22 +02:00
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
static void db_error( SLONG status)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d b _ e r r o r ( W I N _ N T )
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
TEXT s[128];
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
tdba* tddba = GET_THREAD_DATA;
|
2001-05-23 15:26:42 +02:00
|
|
|
tddba->page_number = -1;
|
|
|
|
|
|
|
|
if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
|
|
|
|
NULL,
|
|
|
|
status,
|
|
|
|
GetUserDefaultLangID(),
|
|
|
|
s,
|
|
|
|
sizeof(s),
|
|
|
|
NULL))
|
|
|
|
sprintf(s, "unknown Windows NT error %ld", status);
|
|
|
|
|
|
|
|
FPRINTF(tddba->sw_outfile, "%s\n", s);
|
2003-08-26 20:43:29 +02:00
|
|
|
dba_exit(FINI_ERROR, tddba);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-10-29 11:53:47 +01:00
|
|
|
// CVC: This function was using cast to char* for the first param always
|
|
|
|
// and the callers had to cast their char*'s to UCHAR*, too. Since the
|
|
|
|
// real parameter is char* and always the usage is char*, I changed signature.
|
2003-12-31 06:36:12 +01:00
|
|
|
static dba_fil* db_open(const char* file_name, USHORT file_length)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d b _ o p e n ( W I N _ N T )
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Open a database file.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-31 06:36:12 +01:00
|
|
|
tdba* tddba = GET_THREAD_DATA;
|
2001-12-24 03:51:06 +01:00
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
dba_fil* fil;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (tddba->files) {
|
|
|
|
for (fil = tddba->files; fil->fil_next; fil = fil->fil_next);
|
|
|
|
fil->fil_next =
|
2004-02-02 12:02:12 +01:00
|
|
|
(dba_fil*) ALLOC(sizeof(dba_fil) + strlen(file_name) + 1);
|
2001-05-23 15:26:42 +02:00
|
|
|
fil->fil_next->fil_min_page = fil->fil_max_page + 1;
|
|
|
|
fil = fil->fil_next;
|
|
|
|
}
|
|
|
|
else { /* empty list */
|
|
|
|
|
|
|
|
fil = tddba->files =
|
2004-02-02 12:02:12 +01:00
|
|
|
(dba_fil*) ALLOC(sizeof(dba_fil) + strlen(file_name) + 1);
|
2001-05-23 15:26:42 +02:00
|
|
|
fil->fil_min_page = 0L;
|
|
|
|
}
|
|
|
|
|
|
|
|
fil->fil_next = NULL;
|
2003-10-29 11:53:47 +01:00
|
|
|
strcpy(fil->fil_string, file_name);
|
|
|
|
fil->fil_length = strlen(file_name);
|
2001-05-23 15:26:42 +02:00
|
|
|
fil->fil_fudge = 0;
|
|
|
|
fil->fil_max_page = 0L;
|
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
fil->fil_desc = CreateFile( reinterpret_cast<LPCTSTR>(file_name),
|
|
|
|
GENERIC_READ,
|
|
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
|
|
NULL,
|
|
|
|
OPEN_EXISTING,
|
|
|
|
FILE_ATTRIBUTE_NORMAL |
|
|
|
|
FILE_FLAG_RANDOM_ACCESS,
|
|
|
|
0);
|
|
|
|
|
|
|
|
if (fil->fil_desc == INVALID_HANDLE_VALUE)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
#ifdef SUPERSERVER
|
|
|
|
CMD_UTIL_put_svc_status(tddba->dba_service_blk->svc_status,
|
|
|
|
GSTAT_MSG_FAC, 29,
|
|
|
|
isc_arg_string, file_name,
|
2003-08-26 08:52:05 +02:00
|
|
|
0, NULL, 0, NULL, 0, NULL, 0, NULL);
|
|
|
|
// msg 29: Can't open database file %s
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
db_error(GetLastError());
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef SUPERSERVER
|
2002-09-25 19:12:16 +02:00
|
|
|
open_files* file_list = FB_NEW(*getDefaultMemoryPool()) open_files;
|
2001-12-24 03:51:06 +01:00
|
|
|
if (!file_list) {
|
2001-05-23 15:26:42 +02:00
|
|
|
/* NOMEM: return error */
|
|
|
|
dba_error(31, 0, 0, 0, 0, 0);
|
|
|
|
}
|
2001-12-24 03:51:06 +01:00
|
|
|
file_list->desc = reinterpret_cast<int>(fil->fil_desc);
|
2001-05-23 15:26:42 +02:00
|
|
|
file_list->open_files_next = 0;
|
|
|
|
|
|
|
|
if (tddba->head_of_files_list == 0)
|
|
|
|
tddba->head_of_files_list = file_list;
|
|
|
|
else {
|
|
|
|
file_list->open_files_next = tddba->head_of_files_list;
|
|
|
|
tddba->head_of_files_list = file_list;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return fil;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static const pag* db_read( SLONG page_number)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d b _ r e a d ( W I N _ N T )
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Read a database page.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-31 06:36:12 +01:00
|
|
|
tdba* tddba = GET_THREAD_DATA;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (tddba->page_number == page_number)
|
|
|
|
return tddba->global_buffer;
|
|
|
|
|
|
|
|
tddba->page_number = page_number;
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
dba_fil* fil;
|
2003-08-10 02:48:49 +02:00
|
|
|
for (fil = tddba->files; page_number > (SLONG) fil->fil_max_page
|
|
|
|
&& fil->fil_next;)
|
2003-12-31 06:36:12 +01:00
|
|
|
{
|
2003-08-10 02:48:49 +02:00
|
|
|
fil = fil->fil_next;
|
2003-12-31 06:36:12 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
page_number -= fil->fil_min_page - fil->fil_fudge;
|
2003-12-31 06:36:12 +01:00
|
|
|
|
|
|
|
LARGE_INTEGER liOffset;
|
2001-05-23 15:26:42 +02:00
|
|
|
liOffset.QuadPart =
|
|
|
|
UInt32x32To64((DWORD) page_number, (DWORD) tddba->page_size);
|
|
|
|
if (SetFilePointer
|
|
|
|
(fil->fil_desc, (LONG) liOffset.LowPart, &liOffset.HighPart,
|
2003-12-31 06:36:12 +01:00
|
|
|
FILE_BEGIN) == (DWORD) -1)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
#ifdef SUPERSERVER
|
|
|
|
CMD_UTIL_put_svc_status(tddba->dba_service_blk->svc_status,
|
|
|
|
GSTAT_MSG_FAC, 30,
|
2003-08-26 08:52:05 +02:00
|
|
|
0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL);
|
|
|
|
// msg 30: Can't read a database page
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
db_error(GetLastError());
|
|
|
|
}
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
SLONG actual_length;
|
2001-12-24 03:51:06 +01:00
|
|
|
if (!ReadFile( fil->fil_desc,
|
|
|
|
tddba->global_buffer,
|
|
|
|
tddba->page_size,
|
|
|
|
reinterpret_cast<LPDWORD>(&actual_length),
|
|
|
|
NULL))
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
#ifdef SUPERSERVER
|
|
|
|
CMD_UTIL_put_svc_status(tddba->dba_service_blk->svc_status,
|
|
|
|
GSTAT_MSG_FAC, 30,
|
2003-08-26 08:52:05 +02:00
|
|
|
0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL);
|
|
|
|
// msg 30: Can't read a database page
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
db_error(GetLastError());
|
|
|
|
}
|
|
|
|
if (actual_length != tddba->page_size) {
|
|
|
|
#ifdef SUPERSERVER
|
|
|
|
CMD_UTIL_put_svc_status(tddba->dba_service_blk->svc_status,
|
|
|
|
GSTAT_MSG_FAC, 4,
|
|
|
|
0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL);
|
|
|
|
#endif
|
2003-08-26 08:52:05 +02:00
|
|
|
dba_error(4, 0, 0, 0, 0, 0);
|
|
|
|
// msg 4: Unexpected end of database file.
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return tddba->global_buffer;
|
|
|
|
}
|
2003-10-29 11:53:47 +01:00
|
|
|
#endif // ifdef WIN_NT
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
|
|
|
|
#ifndef WIN_NT
|
2003-04-03 11:19:22 +02:00
|
|
|
#ifdef SUPERSERVER
|
2001-05-23 15:26:42 +02:00
|
|
|
static void db_close( int file_desc)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d b _ c l o s e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Close an open file
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
close(file_desc);
|
|
|
|
}
|
2003-04-03 11:19:22 +02:00
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
static void db_error( int status)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d b _ e r r o r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-31 06:36:12 +01:00
|
|
|
tdba* tddba = GET_THREAD_DATA;
|
2001-05-23 15:26:42 +02:00
|
|
|
tddba->page_number = -1;
|
|
|
|
|
2003-08-25 09:26:39 +02:00
|
|
|
/* FIXME: The strerror() function returns the appropriate description
|
|
|
|
string, or an unknown error message if the error code is unknown.
|
|
|
|
EKU: p cannot be NULL! */
|
|
|
|
#if 1
|
|
|
|
FPRINTF(tddba->sw_outfile, "%s\n", strerror(status));
|
|
|
|
#else
|
|
|
|
/* EKU: Old code */
|
2001-05-23 15:26:42 +02:00
|
|
|
#ifndef VMS
|
2003-08-25 09:26:39 +02:00
|
|
|
FPRINTF(tddba->sw_outfile, "%s\n", strerror(status));
|
2001-05-23 15:26:42 +02:00
|
|
|
#else
|
2003-12-31 06:36:12 +01:00
|
|
|
const char* p;
|
2001-05-23 15:26:42 +02:00
|
|
|
if ((p = strerror(status)) || (p = strerror(EVMSERR, status)))
|
|
|
|
FPRINTF(tddba->sw_outfile, "%s\n", p);
|
|
|
|
else
|
|
|
|
FPRINTF(tddba->sw_outfile, "uninterpreted code %x\n", status);
|
2003-08-25 09:26:39 +02:00
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
2003-08-26 20:43:29 +02:00
|
|
|
dba_exit(FINI_ERROR, tddba);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-10-29 11:53:47 +01:00
|
|
|
// CVC: This function was using cast to char* for the first param always
|
|
|
|
// and the callers had to cast their char*'s to UCHAR*, too. Since the
|
|
|
|
// real parameter is char* and always the usage is char*, I changed signature.
|
2003-12-31 06:36:12 +01:00
|
|
|
static dba_fil* db_open(const char* file_name, USHORT file_length)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d b _ o p e n
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Open a database file.
|
|
|
|
* Put the file on an ordered list.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-31 06:36:12 +01:00
|
|
|
tdba* tddba = GET_THREAD_DATA;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
dba_fil* fil;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (tddba->files) {
|
|
|
|
for (fil = tddba->files; fil->fil_next; fil = fil->fil_next);
|
|
|
|
fil->fil_next =
|
2004-02-02 12:02:12 +01:00
|
|
|
(dba_fil*) ALLOC(sizeof(dba_fil) + strlen(file_name) + 1);
|
2001-05-23 15:26:42 +02:00
|
|
|
fil->fil_next->fil_min_page = fil->fil_max_page + 1;
|
|
|
|
fil = fil->fil_next;
|
|
|
|
}
|
|
|
|
else { /* empty list */
|
|
|
|
|
|
|
|
fil = tddba->files =
|
2004-02-02 12:02:12 +01:00
|
|
|
(dba_fil*) ALLOC(sizeof(dba_fil) + strlen(file_name) + 1);
|
2001-05-23 15:26:42 +02:00
|
|
|
fil->fil_min_page = 0L;
|
|
|
|
}
|
|
|
|
|
|
|
|
fil->fil_next = NULL;
|
2003-10-29 11:53:47 +01:00
|
|
|
strcpy(fil->fil_string, file_name);
|
|
|
|
fil->fil_length = strlen(file_name);
|
2001-05-23 15:26:42 +02:00
|
|
|
fil->fil_fudge = 0;
|
|
|
|
fil->fil_max_page = 0L;
|
|
|
|
|
2003-10-29 11:53:47 +01:00
|
|
|
if ((fil->fil_desc = open(file_name, O_RDONLY)) == -1)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
#ifdef SUPERSERVER
|
|
|
|
CMD_UTIL_put_svc_status(tddba->dba_service_blk->svc_status,
|
|
|
|
GSTAT_MSG_FAC, 29,
|
|
|
|
isc_arg_string, file_name,
|
2003-08-26 08:52:05 +02:00
|
|
|
0, NULL, 0, NULL, 0, NULL, 0, NULL);
|
|
|
|
// msg 29: Can't open database file %s
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
db_error(errno);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef SUPERSERVER
|
2004-02-02 12:02:12 +01:00
|
|
|
open_files* file_list = FB_NEW(*getDefaultMemoryPool()) open_files;
|
2002-07-29 17:37:59 +02:00
|
|
|
if (!file_list) {
|
2001-05-23 15:26:42 +02:00
|
|
|
/* NOMEM: return error */
|
|
|
|
dba_error(31, 0, 0, 0, 0, 0);
|
|
|
|
}
|
|
|
|
file_list->desc = fil->fil_desc;
|
|
|
|
file_list->open_files_next = 0;
|
|
|
|
|
|
|
|
if (tddba->head_of_files_list == 0)
|
|
|
|
tddba->head_of_files_list = file_list;
|
|
|
|
else {
|
|
|
|
file_list->open_files_next = tddba->head_of_files_list;
|
|
|
|
tddba->head_of_files_list = file_list;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return fil;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
static const pag* db_read( SLONG page_number)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d b _ r e a d
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Read a database page.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-31 06:36:12 +01:00
|
|
|
tdba* tddba = GET_THREAD_DATA;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (tddba->page_number == page_number)
|
|
|
|
return tddba->global_buffer;
|
|
|
|
|
|
|
|
tddba->page_number = page_number;
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
dba_fil* fil;
|
2003-08-10 02:48:49 +02:00
|
|
|
for (fil = tddba->files; page_number > (SLONG) fil->fil_max_page
|
|
|
|
&& fil->fil_next;)
|
2003-12-31 06:36:12 +01:00
|
|
|
{
|
2003-08-10 02:48:49 +02:00
|
|
|
fil = fil->fil_next;
|
2003-12-31 06:36:12 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
page_number -= fil->fil_min_page - fil->fil_fudge;
|
2003-12-31 06:36:12 +01:00
|
|
|
const UINT64 offset = ((UINT64)page_number) * ((UINT64)tddba->page_size);
|
2002-07-05 17:00:26 +02:00
|
|
|
if (lseek (fil->fil_desc, offset, 0) == -1) {
|
2001-05-23 15:26:42 +02:00
|
|
|
#ifdef SUPERSERVER
|
|
|
|
CMD_UTIL_put_svc_status(tddba->dba_service_blk->svc_status,
|
|
|
|
GSTAT_MSG_FAC, 30,
|
2003-08-26 08:52:05 +02:00
|
|
|
0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL);
|
|
|
|
// msg 30: Can't read a database page
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
db_error(errno);
|
|
|
|
}
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
SSHORT length = tddba->page_size;
|
|
|
|
for (SCHAR* p = (SCHAR *) tddba->global_buffer; length > 0;)
|
2003-12-31 06:36:12 +01:00
|
|
|
{
|
|
|
|
const SSHORT l = read(fil->fil_desc, p, length);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (l < 0) {
|
|
|
|
#ifdef SUPERSERVER
|
|
|
|
CMD_UTIL_put_svc_status(tddba->dba_service_blk->svc_status,
|
|
|
|
GSTAT_MSG_FAC, 30,
|
2003-08-26 08:52:05 +02:00
|
|
|
0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL);
|
|
|
|
// msg 30: Can't read a database page
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
db_error(errno);
|
|
|
|
}
|
|
|
|
if (!l) {
|
|
|
|
#ifdef SUPERSERVER
|
|
|
|
CMD_UTIL_put_svc_status(tddba->dba_service_blk->svc_status,
|
|
|
|
GSTAT_MSG_FAC, 4,
|
|
|
|
0, NULL,
|
|
|
|
0, NULL, 0, NULL, 0, NULL, 0, NULL);
|
|
|
|
#endif
|
2003-08-26 08:52:05 +02:00
|
|
|
dba_error(4, 0, 0, 0, 0, 0);
|
|
|
|
// msg 4: Unexpected end of database file.
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
p += l;
|
|
|
|
length -= l;
|
|
|
|
}
|
|
|
|
|
|
|
|
return tddba->global_buffer;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
static void dba_error(
|
|
|
|
USHORT errcode,
|
2003-12-31 06:36:12 +01:00
|
|
|
const TEXT* arg1,
|
|
|
|
const TEXT* arg2, const TEXT* arg3,
|
|
|
|
const TEXT* arg4, const TEXT* arg5)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d b a _ e r r o r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Format and print an error message, then punt.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-31 06:36:12 +01:00
|
|
|
tdba* tddba = GET_THREAD_DATA;
|
2001-05-23 15:26:42 +02:00
|
|
|
tddba->page_number = -1;
|
|
|
|
|
|
|
|
dba_print(errcode, arg1, arg2, arg3, arg4, arg5);
|
2003-08-26 20:43:29 +02:00
|
|
|
dba_exit(FINI_ERROR, tddba);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void dba_print(
|
|
|
|
USHORT number,
|
2003-12-31 06:36:12 +01:00
|
|
|
const TEXT* arg1,
|
|
|
|
const TEXT* arg2, const TEXT* arg3,
|
|
|
|
const TEXT* arg4, const TEXT* arg5)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d b a _ p r i n t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Retrieve a message from the error file, format it, and print it.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
TEXT buffer[256];
|
2003-12-31 06:36:12 +01:00
|
|
|
tdba* tddba = GET_THREAD_DATA;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-08-26 08:52:05 +02:00
|
|
|
gds__msg_format(NULL, GSTAT_MSG_FAC, number, sizeof(buffer), buffer,
|
2001-05-23 15:26:42 +02:00
|
|
|
arg1, arg2, arg3, arg4, arg5);
|
|
|
|
TRANSLATE_CP(buffer);
|
|
|
|
FPRINTF(tddba->sw_outfile, "%s\n", buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
static void move(const SCHAR* from, SCHAR* to, SSHORT length)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* m o v e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Move some stuff.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
memcpy(to, from, (int) length);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
static void print_distribution(const SCHAR* prefix, const SLONG* vector)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* p r i n t _ d i s t r i b u t i o n
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Print distribution as percentages.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-31 06:36:12 +01:00
|
|
|
tdba* tddba = GET_THREAD_DATA;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
for (SSHORT n = 0; n < BUCKETS; n++) {
|
2001-05-23 15:26:42 +02:00
|
|
|
FPRINTF(tddba->sw_outfile, "%s%2d - %2d%% = %ld\n",
|
|
|
|
prefix,
|
|
|
|
n * 100 / BUCKETS, (n + 1) * 100 / BUCKETS - 1, vector[n]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|