8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-27 20:03:03 +01:00
firebird-mirror/src/jrd/inf.cpp

1022 lines
25 KiB
C++
Raw Normal View History

2001-05-23 15:26:42 +02:00
/*
* PROGRAM: JRD Access Method
* MODULE: inf.cpp
2001-05-23 15:26:42 +02:00
* DESCRIPTION: Information handler
*
* 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): ______________________________________.
* 2001.07.06 Sean Leyne - Code Cleanup, removed "#ifdef READONLY_DATABASE"
* conditionals, as the engine now fully supports
* readonly databases.
2002-07-01 17:46:07 +02:00
* 2001.08.09 Claudio Valderrama - Added new isc_info_* tokens to INF_database_info():
* oldest_transaction, oldest_active, oldest_snapshot and next_transaction.
* Make INF_put_item() to reserve 4 bytes: item + length as short + info_end;
* otherwise to signal output buffer truncation.
*
* 2001.11.28 Ann Harrison - the dbb has to be refreshed before reporting
* oldest_transaction, oldest_active, oldest_snapshot and next_transaction.
*
* 2001.11.29 Paul Reeves - Added refresh of dbb to ensure forced_writes
* reports correctly when called immediately after a create database
* operation.
2001-05-23 15:26:42 +02:00
*/
#include "firebird.h"
2001-05-23 15:26:42 +02:00
#include <string.h>
2004-03-22 12:38:23 +01:00
#include "../jrd/common.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/jrd.h"
2003-11-08 17:40:17 +01:00
#include "../jrd/ibase.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/tra.h"
#include "../jrd/blb.h"
#include "../jrd/req.h"
#include "../jrd/val.h"
#include "../jrd/exe.h"
2003-07-14 12:35:49 +02:00
#include "../jrd/os/pio.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/ods.h"
#include "../jrd/scl.h"
#include "../jrd/lck.h"
#include "../jrd/cch.h"
#include "../jrd/license.h"
#include "../jrd/cch_proto.h"
#include "../jrd/inf_proto.h"
#include "../jrd/isc_proto.h"
#include "../jrd/opt_proto.h"
#include "../jrd/pag_proto.h"
2003-07-14 12:35:49 +02:00
#include "../jrd/os/pio_proto.h"
#include "../jrd/thd.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/tra_proto.h"
#include "../jrd/gds_proto.h"
#include "../jrd/err_proto.h"
2005-05-28 00:45:31 +02:00
#include "../jrd/intl_proto.h"
2001-05-23 15:26:42 +02:00
using namespace Jrd;
2001-05-23 15:26:42 +02:00
/*
* The variable DBSERVER_BASE_LEVEL was originally IB_MAJOR_VER but with
* the change to Firebird this number could no longer be used.
* The DBSERVER_BASE_LEVEL for firebird starts at 6 which is the base level
* of InterBase(r) from which Firebird was derived.
* It is expected that this value will increase as changes are added to
2001-05-23 15:26:42 +02:00
* Firebird
*/
#define DBSERVER_BASE_LEVEL 6
#define STUFF_WORD(p, value) {*p++ = value; *p++ = value >> 8;}
#define STUFF(p, value) *p++ = value
static USHORT get_counts(USHORT, SCHAR*, USHORT);
2001-05-23 15:26:42 +02:00
#pragma FB_COMPILER_MESSAGE("Our caller doesn't check our boolean result, only traps an exception!")
int INF_blob_info(const blb* blob,
const SCHAR* items,
const SSHORT item_length,
SCHAR* info,
const SSHORT output_length)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I N F _ b l o b _ i n f o
*
**************************************
*
* Functional description
* Process requests for blob info.
*
**************************************/
SCHAR buffer[128];
2001-05-23 15:26:42 +02:00
SSHORT length;
const SCHAR* const end_items = items + item_length;
const SCHAR* const end = info + output_length;
2001-05-23 15:26:42 +02:00
2003-11-08 17:40:17 +01:00
while (items < end_items && *items != isc_info_end) {
SCHAR item = *items++;
switch (item) {
2003-11-08 17:40:17 +01:00
case isc_info_end:
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_info_blob_num_segments:
2001-05-23 15:26:42 +02:00
length = INF_convert(blob->blb_count, buffer);
break;
2003-11-08 17:40:17 +01:00
case isc_info_blob_max_segment:
2001-05-23 15:26:42 +02:00
length = INF_convert(blob->blb_max_segment, buffer);
break;
2003-11-08 17:40:17 +01:00
case isc_info_blob_total_length:
2001-05-23 15:26:42 +02:00
length = INF_convert(blob->blb_length, buffer);
break;
2003-11-08 17:40:17 +01:00
case isc_info_blob_type:
2001-05-23 15:26:42 +02:00
buffer[0] = (blob->blb_flags & BLB_stream) ? 1 : 0;
length = 1;
break;
default:
buffer[0] = item;
2003-11-08 17:40:17 +01:00
item = isc_info_error;
length = 1 + INF_convert(isc_infunk, buffer + 1);
2001-05-23 15:26:42 +02:00
break;
}
if (!(info = INF_put_item(item, length, buffer, info, end)))
return FALSE;
}
2003-11-08 17:40:17 +01:00
*info++ = isc_info_end;
2001-05-23 15:26:42 +02:00
return TRUE;
}
USHORT INF_convert(SLONG number, SCHAR* buffer)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I N F _ c o n v e r t
*
**************************************
*
* Functional description
* Convert a number to VAX form -- least significant bytes first.
* Return the length.
*
**************************************/
const SCHAR* p;
2001-05-23 15:26:42 +02:00
#ifndef WORDS_BIGENDIAN
// CVC: What's the need for an intermediate "n" here?
const SLONG n = number;
p = reinterpret_cast<const SCHAR*>(&n);
2001-05-23 15:26:42 +02:00
*buffer++ = *p++;
*buffer++ = *p++;
*buffer++ = *p++;
*buffer = *p;
#else
p = reinterpret_cast<const SCHAR*>(&number);
2001-05-23 15:26:42 +02:00
p += 3;
*buffer++ = *p--;
*buffer++ = *p--;
*buffer++ = *p--;
*buffer = *p;
#endif
return 4;
}
int INF_database_info(const SCHAR* items,
const SSHORT item_length,
SCHAR* info, const SSHORT output_length)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I N F _ d a t a b a s e _ i n f o ( J R D )
*
**************************************
*
* Functional description
* Process requests for database info.
*
**************************************/
SCHAR buffer[256];
SSHORT length;
2001-05-23 15:26:42 +02:00
SLONG id;
SLONG err_val;
bool header_refreshed = false;
2001-05-23 15:26:42 +02:00
thread_db* tdbb = JRD_get_thread_data();
2004-03-07 08:58:55 +01:00
Database* dbb = tdbb->tdbb_database;
2001-05-23 15:26:42 +02:00
CHECK_DBB(dbb);
jrd_tra* transaction = NULL;
const SCHAR* const end_items = items + item_length;
const SCHAR* const end = info + output_length;
2001-05-23 15:26:42 +02:00
Attachment* err_att = 0;
Attachment* att = 0;
const SCHAR* q;
2001-05-23 15:26:42 +02:00
2003-11-08 17:40:17 +01:00
while (items < end_items && *items != isc_info_end) {
SCHAR* p = buffer;
SCHAR item = *items++;
switch (item) {
2002-07-01 17:46:07 +02:00
case isc_info_end:
2001-05-23 15:26:42 +02:00
break;
2002-07-01 17:46:07 +02:00
case isc_info_reads:
2001-05-23 15:26:42 +02:00
length = INF_convert(dbb->dbb_reads, buffer);
break;
2002-07-01 17:46:07 +02:00
case isc_info_writes:
2001-05-23 15:26:42 +02:00
length = INF_convert(dbb->dbb_writes, buffer);
break;
2002-07-01 17:46:07 +02:00
case isc_info_fetches:
2001-05-23 15:26:42 +02:00
length = INF_convert(dbb->dbb_fetches, buffer);
break;
2002-07-01 17:46:07 +02:00
case isc_info_marks:
2001-05-23 15:26:42 +02:00
length = INF_convert(dbb->dbb_marks, buffer);
break;
2002-07-01 17:46:07 +02:00
case isc_info_page_size:
2001-05-23 15:26:42 +02:00
length = INF_convert(dbb->dbb_page_size, buffer);
break;
2002-07-01 17:46:07 +02:00
case isc_info_num_buffers:
2001-05-23 15:26:42 +02:00
length = INF_convert(dbb->dbb_bcb->bcb_count, buffer);
break;
case isc_info_set_page_buffers:
length = INF_convert(dbb->dbb_page_buffers, buffer);
break;
2002-07-01 17:46:07 +02:00
case isc_info_logfile:
length = INF_convert(FALSE, buffer);
2001-05-23 15:26:42 +02:00
break;
2002-07-01 17:46:07 +02:00
case isc_info_cur_logfile_name:
*p++ = 0;
2001-05-23 15:26:42 +02:00
length = p - buffer;
break;
2002-07-01 17:46:07 +02:00
case isc_info_cur_log_part_offset:
length = INF_convert(0, buffer);
2001-05-23 15:26:42 +02:00
break;
2002-07-01 17:46:07 +02:00
case isc_info_num_wal_buffers:
case isc_info_wal_buffer_size:
case isc_info_wal_ckpt_length:
case isc_info_wal_cur_ckpt_interval:
case isc_info_wal_recv_ckpt_fname:
case isc_info_wal_recv_ckpt_poffset:
case isc_info_wal_grpc_wait_usecs:
case isc_info_wal_num_io:
case isc_info_wal_avg_io_size:
2005-06-14 07:44:29 +02:00
case isc_info_wal_num_commits:
case isc_info_wal_avg_grpc_size:
// WAL obsolete
length = 0;
2001-05-23 15:26:42 +02:00
break;
2005-06-14 07:44:29 +02:00
case isc_info_wal_prv_ckpt_fname:
*p++ = 0;
length = p - buffer;
2001-05-23 15:26:42 +02:00
break;
2005-06-14 07:44:29 +02:00
case isc_info_wal_prv_ckpt_poffset:
length = INF_convert(0, buffer);
2001-05-23 15:26:42 +02:00
break;
#ifdef SUPERSERVER
2002-07-01 17:46:07 +02:00
case isc_info_current_memory:
length = INF_convert(dbb->dbb_memory_stats.get_current_usage(), buffer);
2001-05-23 15:26:42 +02:00
break;
2002-07-01 17:46:07 +02:00
case isc_info_max_memory:
length = INF_convert(dbb->dbb_memory_stats.get_maximum_usage(), buffer);
2001-05-23 15:26:42 +02:00
break;
#else
case isc_info_current_memory:
length = INF_convert(MemoryPool::default_stats_group.get_current_usage(), buffer);
break;
case isc_info_max_memory:
length = INF_convert(MemoryPool::default_stats_group.get_maximum_usage(), buffer);
break;
#endif
2001-05-23 15:26:42 +02:00
2002-07-01 17:46:07 +02:00
case isc_info_attachment_id:
2001-05-23 15:26:42 +02:00
length = INF_convert(PAG_attachment_id(), buffer);
break;
2002-07-01 17:46:07 +02:00
case isc_info_ods_version:
2001-05-23 15:26:42 +02:00
length = INF_convert(dbb->dbb_ods_version, buffer);
break;
2002-07-01 17:46:07 +02:00
case isc_info_ods_minor_version:
2001-05-23 15:26:42 +02:00
length = INF_convert(dbb->dbb_minor_version, buffer);
break;
2002-07-01 17:46:07 +02:00
case isc_info_allocation:
CCH_flush(tdbb, FLUSH_ALL, 0L);
2001-05-23 15:26:42 +02:00
length = INF_convert(PIO_max_alloc(dbb), buffer);
break;
2002-07-01 17:46:07 +02:00
case isc_info_sweep_interval:
2001-05-23 15:26:42 +02:00
length = INF_convert(dbb->dbb_sweep_interval, buffer);
break;
2002-07-01 17:46:07 +02:00
case isc_info_read_seq_count:
2001-05-23 15:26:42 +02:00
length =
get_counts(DBB_read_seq_count,
buffer,
2001-05-23 15:26:42 +02:00
sizeof(buffer));
break;
2002-07-01 17:46:07 +02:00
case isc_info_read_idx_count:
2001-05-23 15:26:42 +02:00
length =
get_counts(DBB_read_idx_count,
buffer,
2001-05-23 15:26:42 +02:00
sizeof(buffer));
break;
2002-07-01 17:46:07 +02:00
case isc_info_update_count:
2001-05-23 15:26:42 +02:00
length =
get_counts(DBB_update_count,
buffer,
2001-05-23 15:26:42 +02:00
sizeof(buffer));
break;
2002-07-01 17:46:07 +02:00
case isc_info_insert_count:
2001-05-23 15:26:42 +02:00
length =
get_counts(DBB_insert_count,
buffer,
2001-05-23 15:26:42 +02:00
sizeof(buffer));
break;
2002-07-01 17:46:07 +02:00
case isc_info_delete_count:
2001-05-23 15:26:42 +02:00
length =
get_counts(DBB_delete_count,
buffer,
2001-05-23 15:26:42 +02:00
sizeof(buffer));
break;
2002-07-01 17:46:07 +02:00
case isc_info_backout_count:
2001-05-23 15:26:42 +02:00
length =
get_counts(DBB_backout_count,
buffer,
2001-05-23 15:26:42 +02:00
sizeof(buffer));
break;
2002-07-01 17:46:07 +02:00
case isc_info_purge_count:
2001-05-23 15:26:42 +02:00
length =
get_counts(DBB_purge_count,
buffer,
2001-05-23 15:26:42 +02:00
sizeof(buffer));
break;
2002-07-01 17:46:07 +02:00
case isc_info_expunge_count:
2001-05-23 15:26:42 +02:00
length =
get_counts(DBB_expunge_count,
buffer,
2001-05-23 15:26:42 +02:00
sizeof(buffer));
break;
2002-07-01 17:46:07 +02:00
case isc_info_implementation:
2001-05-23 15:26:42 +02:00
STUFF(p, 1); /* Count */
STUFF(p, IMPLEMENTATION);
STUFF(p, 1); /* Class */
length = p - buffer;
break;
2002-07-01 17:46:07 +02:00
case isc_info_base_level:
2001-05-23 15:26:42 +02:00
/* info_base_level is used by the client to represent
* what the server is capable of. It is equivalent to the
* ods version of a database. For example,
2001-05-23 15:26:42 +02:00
* ods_version represents what the database 'knows'
* base_level represents what the server 'knows'
*/
STUFF(p, 1); /* Count */
#ifdef SCROLLABLE_CURSORS
UPDATE WITH VERSION OF SERVER SUPPORTING
SCROLLABLE CURSORS STUFF(p, 5); /* base level of scrollable cursors */
#else
/* IB_MAJOR_VER is defined as a character string */
STUFF(p, DBSERVER_BASE_LEVEL); /* base level of current version */
#endif
length = p - buffer;
break;
2002-07-01 17:46:07 +02:00
case isc_info_isc_version:
2001-05-23 15:26:42 +02:00
STUFF(p, 1);
2003-06-08 15:13:25 +02:00
STUFF(p, sizeof(ISC_VERSION) - 1);
for (q = ISC_VERSION; *q;)
2001-05-23 15:26:42 +02:00
STUFF(p, *q++);
length = p - buffer;
break;
2002-07-01 17:46:07 +02:00
case isc_info_firebird_version:
STUFF(p, 1);
STUFF(p, sizeof(FB_VERSION) - 1);
for (q = FB_VERSION; *q;)
STUFF(p, *q++);
length = p - buffer;
break;
2003-06-08 15:13:25 +02:00
2002-07-01 17:46:07 +02:00
case isc_info_db_id:
{
const Firebird::PathName& str_fn = dbb->dbb_database_name;
STUFF(p, 2);
SSHORT l = str_fn.length();
*p++ = l;
for (q = str_fn.c_str(); *q;)
*p++ = *q++;
SCHAR site[256];
ISC_get_host(site, sizeof(site));
*p++ = l = strlen(site);
for (q = site; *q;)
*p++ = *q++;
length = p - buffer;
break;
}
2001-05-23 15:26:42 +02:00
2002-07-01 17:46:07 +02:00
case isc_info_no_reserve:
2001-05-23 15:26:42 +02:00
*p++ = (dbb->dbb_flags & DBB_no_reserve) ? 1 : 0;
length = p - buffer;
break;
2002-07-01 17:46:07 +02:00
case isc_info_forced_writes:
if (!header_refreshed)
{
const jrd_file* file = dbb->dbb_file;
PAG_header(file->fil_string, file->fil_length, true);
header_refreshed = true;
2002-07-01 17:46:07 +02:00
}
2001-05-23 15:26:42 +02:00
*p++ = (dbb->dbb_flags & DBB_force_write) ? 1 : 0;
length = p - buffer;
break;
2002-07-01 17:46:07 +02:00
case isc_info_limbo:
2001-05-23 15:26:42 +02:00
if (!transaction)
transaction = TRA_start(tdbb, 0, NULL);
for (id = transaction->tra_oldest;
id < transaction->tra_number; id++)
{
2001-05-23 15:26:42 +02:00
if (TRA_snapshot_state(tdbb, transaction, id) == tra_limbo &&
TRA_wait(tdbb, transaction, id, jrd_tra::tra_wait) == tra_limbo)
{
2001-05-23 15:26:42 +02:00
length = INF_convert(id, buffer);
if (!
(info =
INF_put_item(item, length, buffer, info, end)))
{
2001-05-23 15:26:42 +02:00
if (transaction)
TRA_commit(tdbb, transaction, false);
2001-05-23 15:26:42 +02:00
return FALSE;
}
}
}
2001-05-23 15:26:42 +02:00
continue;
case isc_info_active_transactions:
if (!transaction)
transaction = TRA_start(tdbb, 0, NULL);
for (id = transaction->tra_oldest_active;
id < transaction->tra_number; id++)
{
if (TRA_snapshot_state(tdbb, transaction, id) == tra_active) {
length = INF_convert(id, buffer);
if (!
(info =
INF_put_item(item, length, buffer, info, end)))
{
if (transaction)
TRA_commit(tdbb, transaction, false);
return FALSE;
}
}
}
continue;
2001-05-23 15:26:42 +02:00
case isc_info_user_names:
for (att = dbb->dbb_attachments; att; att = att->att_next) {
if (att->att_flags & ATT_shutdown)
continue;
const UserId* user = att->att_user;
if (user) {
const char* user_name = user->usr_user_name ?
user->usr_user_name : "(SQL Server)";
2001-05-23 15:26:42 +02:00
p = buffer;
SSHORT l = strlen (user_name);
*p++ = l;
for (q = user_name; l; l--)
2001-05-23 15:26:42 +02:00
*p++ = *q++;
length = p - buffer;
info = INF_put_item(item, length, buffer, info, end);
if (!info) {
2001-05-23 15:26:42 +02:00
if (transaction)
TRA_commit(tdbb, transaction, false);
2001-05-23 15:26:42 +02:00
return FALSE;
}
}
}
continue;
case isc_info_page_errors:
err_att = tdbb->tdbb_attachment;
if (err_att->att_val_errors) {
err_val =
2001-12-24 03:51:06 +01:00
(*err_att->att_val_errors)[VAL_PAG_WRONG_TYPE]
+ (*err_att->att_val_errors)[VAL_PAG_CHECKSUM_ERR]
+ (*err_att->att_val_errors)[VAL_PAG_DOUBLE_ALLOC]
+ (*err_att->att_val_errors)[VAL_PAG_IN_USE]
+ (*err_att->att_val_errors)[VAL_PAG_ORPHAN];
2001-05-23 15:26:42 +02:00
}
else
err_val = 0;
length = INF_convert(err_val, buffer);
break;
case isc_info_bpage_errors:
err_att = tdbb->tdbb_attachment;
if (err_att->att_val_errors) {
err_val =
2001-12-24 03:51:06 +01:00
(*err_att->att_val_errors)[VAL_BLOB_INCONSISTENT]
+ (*err_att->att_val_errors)[VAL_BLOB_CORRUPT]
+ (*err_att->att_val_errors)[VAL_BLOB_TRUNCATED];
2001-05-23 15:26:42 +02:00
}
else
err_val = 0;
length = INF_convert(err_val, buffer);
break;
case isc_info_record_errors:
err_att = tdbb->tdbb_attachment;
if (err_att->att_val_errors) {
err_val =
2001-12-24 03:51:06 +01:00
(*err_att->att_val_errors)[VAL_REC_CHAIN_BROKEN]
+ (*err_att->att_val_errors)[VAL_REC_DAMAGED]
+ (*err_att->att_val_errors)[VAL_REC_BAD_TID]
2001-05-23 15:26:42 +02:00
+
2001-12-24 03:51:06 +01:00
(*err_att->att_val_errors)[VAL_REC_FRAGMENT_CORRUPT] +
(*err_att->att_val_errors)[VAL_REC_WRONG_LENGTH] +
(*err_att->att_val_errors)[VAL_REL_CHAIN_ORPHANS];
2001-05-23 15:26:42 +02:00
}
else
err_val = 0;
length = INF_convert(err_val, buffer);
break;
case isc_info_dpage_errors:
err_att = tdbb->tdbb_attachment;
if (err_att->att_val_errors) {
err_val =
2001-12-24 03:51:06 +01:00
(*err_att->att_val_errors)[VAL_DATA_PAGE_CONFUSED]
2001-05-23 15:26:42 +02:00
+
2001-12-24 03:51:06 +01:00
(*err_att->att_val_errors)[VAL_DATA_PAGE_LINE_ERR];
2001-05-23 15:26:42 +02:00
}
else
err_val = 0;
length = INF_convert(err_val, buffer);
break;
case isc_info_ipage_errors:
err_att = tdbb->tdbb_attachment;
if (err_att->att_val_errors) {
err_val =
2001-12-24 03:51:06 +01:00
(*err_att->att_val_errors)[VAL_INDEX_PAGE_CORRUPT]
2001-05-23 15:26:42 +02:00
+
2001-12-24 03:51:06 +01:00
(*err_att->att_val_errors)[VAL_INDEX_ROOT_MISSING] +
(*err_att->att_val_errors)[VAL_INDEX_MISSING_ROWS] +
(*err_att->att_val_errors)[VAL_INDEX_ORPHAN_CHILD];
2001-05-23 15:26:42 +02:00
}
else
err_val = 0;
length = INF_convert(err_val, buffer);
break;
case isc_info_ppage_errors:
err_att = tdbb->tdbb_attachment;
if (err_att->att_val_errors) {
2001-12-24 03:51:06 +01:00
err_val = (*err_att->att_val_errors)[VAL_P_PAGE_LOST]
2001-05-23 15:26:42 +02:00
+
2001-12-24 03:51:06 +01:00
(*err_att->att_val_errors)[VAL_P_PAGE_INCONSISTENT];
2001-05-23 15:26:42 +02:00
}
else
err_val = 0;
length = INF_convert(err_val, buffer);
break;
case isc_info_tpage_errors:
err_att = tdbb->tdbb_attachment;
if (err_att->att_val_errors) {
2001-12-24 03:51:06 +01:00
err_val = (*err_att->att_val_errors)[VAL_TIP_LOST]
+ (*err_att->att_val_errors)[VAL_TIP_LOST_SEQUENCE]
+ (*err_att->att_val_errors)[VAL_TIP_CONFUSED];
2001-05-23 15:26:42 +02:00
}
else
err_val = 0;
length = INF_convert(err_val, buffer);
break;
case isc_info_db_sql_dialect:
/*
**
** there are 3 types of databases:
**
** 1. a DB that is created before V6.0. This DB only speak SQL
2001-05-23 15:26:42 +02:00
** dialect 1 and 2.
**
** 2. a non ODS 10 DB is backed up/restored in IB V6.0. Since
** this DB contained some old SQL dialect, therefore it
** speaks SQL dialect 1, 2, and 3
**
** 3. a DB that is created in V6.0. This DB speak SQL
2001-05-23 15:26:42 +02:00
** dialect 1, 2 or 3 depending the DB was created
** under which SQL dialect.
**
*/
if (ENCODE_ODS(dbb->dbb_ods_version, dbb->dbb_minor_original)
>= ODS_10_0)
{
if (dbb->dbb_flags & DBB_DB_SQL_dialect_3) {
/*
** DB created in IB V6.0 by client SQL dialect 3
2001-05-23 15:26:42 +02:00
*/
*p++ = SQL_DIALECT_V6;
}
else {
/*
2001-05-23 15:26:42 +02:00
** old DB was gbaked in IB V6.0
*/
*p++ = SQL_DIALECT_V5;
}
}
2001-05-23 15:26:42 +02:00
else
*p++ = SQL_DIALECT_V5; /* pre ODS 10 DB */
length = p - buffer;
break;
case isc_info_db_read_only:
*p++ = (dbb->dbb_flags & DBB_read_only) ? 1 : 0;
length = p - buffer;
break;
case isc_info_db_size_in_pages:
CCH_flush(tdbb, FLUSH_ALL, 0L);
2001-05-23 15:26:42 +02:00
length = INF_convert(PIO_act_alloc(dbb), buffer);
break;
2002-07-01 17:46:07 +02:00
case isc_info_oldest_transaction:
if (!header_refreshed)
{
const jrd_file* file = dbb->dbb_file;
PAG_header(file->fil_string, file->fil_length, true);
header_refreshed = true;
2002-07-01 17:46:07 +02:00
}
length = INF_convert(dbb->dbb_oldest_transaction, buffer);
break;
case isc_info_oldest_active:
if (!header_refreshed)
{
const jrd_file* file = dbb->dbb_file;
PAG_header(file->fil_string, file->fil_length, true);
header_refreshed = true;
2002-07-01 17:46:07 +02:00
}
length = INF_convert(dbb->dbb_oldest_active, buffer);
break;
case isc_info_oldest_snapshot:
if (!header_refreshed)
{
const jrd_file* file = dbb->dbb_file;
PAG_header(file->fil_string, file->fil_length, true);
header_refreshed = true;
2002-07-01 17:46:07 +02:00
}
length = INF_convert(dbb->dbb_oldest_snapshot, buffer);
break;
case isc_info_next_transaction:
if (!header_refreshed)
{
const jrd_file* file = dbb->dbb_file;
PAG_header(file->fil_string, file->fil_length, true);
header_refreshed = true;
2002-07-01 17:46:07 +02:00
}
length = INF_convert(dbb->dbb_next_transaction, buffer);
break;
case isc_info_db_provider:
length = INF_convert(isc_info_db_code_firebird, buffer);
break;
case isc_info_db_class:
length = INF_convert(FB_ARCHITECTURE, buffer);
break;
2001-05-23 15:26:42 +02:00
case frb_info_att_charset:
length = INF_convert(tdbb->tdbb_attachment->att_charset, buffer);
break;
default:
buffer[0] = item;
2003-11-08 17:40:17 +01:00
item = isc_info_error;
length = 1 + INF_convert(isc_infunk, buffer + 1);
2001-05-23 15:26:42 +02:00
break;
}
if (!(info = INF_put_item(item, length, buffer, info, end))) {
if (transaction)
TRA_commit(tdbb, transaction, false);
2001-05-23 15:26:42 +02:00
return FALSE;
}
}
if (transaction)
TRA_commit(tdbb, transaction, false);
2001-05-23 15:26:42 +02:00
2003-11-08 17:40:17 +01:00
*info++ = isc_info_end;
2001-05-23 15:26:42 +02:00
return TRUE;
}
SCHAR* INF_put_item(SCHAR item,
USHORT length, const SCHAR* string, SCHAR* ptr,
const SCHAR* end)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I N F _ p u t _ i t e m
*
**************************************
*
* Functional description
* Put information item in output buffer if there is room, and
* return an updated pointer. If there isn't room for the item,
* indicate truncation and return NULL.
*
**************************************/
if (ptr + length + 4 >= end) {
2003-11-08 17:40:17 +01:00
*ptr = isc_info_truncated;
2001-05-23 15:26:42 +02:00
return NULL;
}
// Typically, in other places, STUFF_WORD is applied to UCHAR*
2001-05-23 15:26:42 +02:00
*ptr++ = item;
STUFF_WORD(ptr, length);
if (length) {
MEMMOVE(string, ptr, length);
ptr += length;
}
return ptr;
}
int INF_request_info(const jrd_req* request,
const SCHAR* items,
const SSHORT item_length,
SCHAR* info, const SSHORT output_length)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I N F _ r e q u e s t _ i n f o
*
**************************************
*
* Functional description
* Return information about requests.
*
**************************************/
2004-01-13 10:52:19 +01:00
jrd_nod* node;
2001-05-23 15:26:42 +02:00
SSHORT state;
USHORT length = 0;
const SCHAR* const end_items = items + item_length;
const SCHAR* const end = info + output_length;
SCHAR buffer[256];
2001-05-23 15:26:42 +02:00
memset(buffer, 0, sizeof(buffer));
SCHAR* buffer_ptr = buffer;
2001-05-23 15:26:42 +02:00
2003-11-08 17:40:17 +01:00
while (items < end_items && *items != isc_info_end) {
SCHAR item = *items++;
switch (item) {
2003-11-08 17:40:17 +01:00
case isc_info_end:
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_info_number_messages:
2001-05-23 15:26:42 +02:00
length = INF_convert(request->req_nmsgs, buffer_ptr);
break;
2003-11-08 17:40:17 +01:00
case isc_info_max_message:
2001-05-23 15:26:42 +02:00
length = INF_convert(request->req_mmsg, buffer_ptr);
break;
2003-11-08 17:40:17 +01:00
case isc_info_max_send:
2001-05-23 15:26:42 +02:00
length = INF_convert(request->req_msend, buffer_ptr);
break;
2003-11-08 17:40:17 +01:00
case isc_info_max_receive:
2001-05-23 15:26:42 +02:00
length = INF_convert(request->req_mreceive, buffer_ptr);
break;
2003-11-08 17:40:17 +01:00
case isc_info_req_select_count:
2001-05-23 15:26:42 +02:00
length = INF_convert(request->req_records_selected, buffer_ptr);
break;
2003-11-08 17:40:17 +01:00
case isc_info_req_insert_count:
2001-05-23 15:26:42 +02:00
length = INF_convert(request->req_records_inserted, buffer_ptr);
break;
2003-11-08 17:40:17 +01:00
case isc_info_req_update_count:
2001-05-23 15:26:42 +02:00
length = INF_convert(request->req_records_updated, buffer_ptr);
break;
2003-11-08 17:40:17 +01:00
case isc_info_req_delete_count:
2001-05-23 15:26:42 +02:00
length = INF_convert(request->req_records_deleted, buffer_ptr);
break;
2003-11-08 17:40:17 +01:00
case isc_info_access_path:
2001-05-23 15:26:42 +02:00
/* the access path has the potential to be large, so if the default
buffer is not big enough, allocate a really large one--don't
continue to allocate larger and larger, because of the potential
2001-05-23 15:26:42 +02:00
for a bug which would bring the server to its knees */
if (!OPT_access_path(request, buffer_ptr, sizeof(buffer), &length))
{
buffer_ptr = FB_NEW(*getDefaultMemoryPool()) char[BUFFER_XLARGE];
2001-05-23 15:26:42 +02:00
OPT_access_path(request, buffer_ptr, BUFFER_XLARGE, &length);
}
break;
2003-11-08 17:40:17 +01:00
case isc_info_state:
state = isc_info_req_active;
if (request->req_operation == jrd_req::req_send)
2003-11-08 17:40:17 +01:00
state = isc_info_req_send;
else if (request->req_operation == jrd_req::req_receive) {
2001-05-23 15:26:42 +02:00
node = request->req_next;
if (node->nod_type == nod_select)
2003-11-08 17:40:17 +01:00
state = isc_info_req_select;
2001-05-23 15:26:42 +02:00
else
2003-11-08 17:40:17 +01:00
state = isc_info_req_receive;
2001-05-23 15:26:42 +02:00
}
else if ((request->req_operation == jrd_req::req_return) &&
2001-05-23 15:26:42 +02:00
(request->req_flags & req_stall))
2004-02-02 12:02:12 +01:00
{
2001-05-23 15:26:42 +02:00
state = isc_info_req_sql_stall;
2004-02-02 12:02:12 +01:00
}
2001-05-23 15:26:42 +02:00
if (!(request->req_flags & req_active))
2003-11-08 17:40:17 +01:00
state = isc_info_req_inactive;
2001-05-23 15:26:42 +02:00
length = INF_convert(state, buffer_ptr);
break;
2003-11-08 17:40:17 +01:00
case isc_info_message_number:
case isc_info_message_size:
2001-05-23 15:26:42 +02:00
if (!(request->req_flags & req_active) ||
(request->req_operation != jrd_req::req_receive &&
request->req_operation != jrd_req::req_send))
{
2001-05-23 15:26:42 +02:00
buffer_ptr[0] = item;
2003-11-08 17:40:17 +01:00
item = isc_info_error;
length = 1 + INF_convert(isc_infinap, buffer_ptr + 1);
2001-05-23 15:26:42 +02:00
break;
}
node = request->req_message;
2003-11-08 17:40:17 +01:00
if (item == isc_info_message_number)
2001-05-23 15:26:42 +02:00
length =
INF_convert((IPTR) node->nod_arg[e_msg_number],
2001-05-23 15:26:42 +02:00
buffer_ptr);
else {
2004-03-30 06:10:52 +02:00
const Format* format = (Format*) node->nod_arg[e_msg_format];
2001-05-23 15:26:42 +02:00
length = INF_convert(format->fmt_length, buffer_ptr);
}
break;
2003-11-08 17:40:17 +01:00
case isc_info_request_cost:
2001-05-23 15:26:42 +02:00
default:
buffer_ptr[0] = item;
2003-11-08 17:40:17 +01:00
item = isc_info_error;
length = 1 + INF_convert(isc_infunk, buffer_ptr + 1);
2001-05-23 15:26:42 +02:00
break;
}
info = INF_put_item(item, length, buffer_ptr, info, end);
if (buffer_ptr != buffer) {
delete[] buffer_ptr;
2001-05-23 15:26:42 +02:00
buffer_ptr = buffer;
}
if (!info)
return FALSE;
}
2003-11-08 17:40:17 +01:00
*info++ = isc_info_end;
2001-05-23 15:26:42 +02:00
return TRUE;
}
int INF_transaction_info(const jrd_tra* transaction,
const SCHAR* items,
const SSHORT item_length,
SCHAR* info, const SSHORT output_length)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* I N F _ t r a n s a c t i o n _ i n f o
*
**************************************
*
* Functional description
* Process requests for blob info.
*
**************************************/
SCHAR buffer[128];
2001-05-23 15:26:42 +02:00
SSHORT length;
const SCHAR* const end_items = items + item_length;
const SCHAR* const end = info + output_length;
2001-05-23 15:26:42 +02:00
2003-11-08 17:40:17 +01:00
while (items < end_items && *items != isc_info_end) {
SCHAR item = *items++;
switch (item) {
2003-11-08 17:40:17 +01:00
case isc_info_end:
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_info_tra_id:
2001-05-23 15:26:42 +02:00
length = INF_convert(transaction->tra_number, buffer);
break;
default:
buffer[0] = item;
2003-11-08 17:40:17 +01:00
item = isc_info_error;
length = 1 + INF_convert(isc_infunk, buffer + 1);
2001-05-23 15:26:42 +02:00
break;
}
if (!(info = INF_put_item(item, length, buffer, info, end)))
return FALSE;
}
2003-11-08 17:40:17 +01:00
*info++ = isc_info_end;
2001-05-23 15:26:42 +02:00
return TRUE;
}
static USHORT get_counts(USHORT count_id, SCHAR* buffer, USHORT length)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g e t _ c o u n t s
*
**************************************
*
* Functional description
* Return operation counts for relation.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
2001-05-23 15:26:42 +02:00
const vcl* vector = tdbb->tdbb_attachment->att_counts[count_id];
if (!vector)
2001-05-23 15:26:42 +02:00
return 0;
// CVC: This function was receiving UCHAR* but to avoid all the casts
// when calling it, I changed it to SCHAR* and I'm doing here the cast
// to avoid signed/unsigned surprises.
UCHAR* p = reinterpret_cast<UCHAR*>(buffer);
const UCHAR* const end = p + length - 6;
2001-05-23 15:26:42 +02:00
USHORT relation_id = 0;
for (vcl::const_iterator ptr = vector->begin();
2003-04-23 09:29:54 +02:00
relation_id < vector->count() && p < end; ++relation_id)
{
const SLONG n = *ptr++;
if (n) {
2001-05-23 15:26:42 +02:00
STUFF_WORD(p, relation_id);
p += INF_convert(n, reinterpret_cast<char*>(p));
2001-05-23 15:26:42 +02:00
}
}
2001-05-23 15:26:42 +02:00
return p - reinterpret_cast<UCHAR*>(buffer);
2001-05-23 15:26:42 +02:00
}