8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-31 17:23:03 +01:00
firebird-mirror/src/jrd/dyn_mod.epp

3181 lines
85 KiB
Plaintext
Raw Normal View History

2001-05-23 15:26:42 +02:00
/*
* PROGRAM: JRD Data Definition Utility
* MODULE: dyn_mod.epp
2001-05-23 15:26:42 +02:00
* DESCRIPTION: Dynamic data definition - DYN_modify_<x>
*
* 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.5.20: Claudio Valderrama: when changing a domain's name,
2002-06-30 10:46:51 +02:00
* if it has dimensions, rdb$field_dimensions should be updated, too.
* 2001.5.23: Claudio Valderrama: Forbid zero length identifiers,
* they are not ANSI SQL compliant.
* 2001.5.27 Claudio Valderrama: Prevent rdb$field_length from going
* out of sync when toggling between char and varchar data types.
* This caused check_update_fld_type() to lose ability to detect potentially
* dangerous changes. For example, you could alter a field or a domain and
* be able to change char(10) to varchar(8).
* Unfortunately, Borland chose to have DYN_modify_global_field() and add to the
* party DYN_modify_sql_field(); therefore bug fixes should be done twice.
* 2001.10.08 Claudio Valderrama: put a comment with suggested code to hide
* special non-system triggers from user manipulation.
* 2002-02-24 Sean Leyne - Code Cleanup of old Win 3.1 port (WINDOWS_ONLY)
* 2002.08.10 Dmitry Yemanov: ALTER VIEW
2001-05-23 15:26:42 +02:00
*/
#include "firebird.h"
2010-01-10 18:56:57 +01:00
#include "dyn_consts.h"
2004-04-29 00:36:29 +02:00
#include <stdio.h>
2001-05-23 15:26:42 +02:00
#include <string.h>
#include "../jrd/common.h"
#include "../jrd/jrd.h"
#include "../jrd/tra.h"
#include "../jrd/scl.h"
#include "../jrd/drq.h"
#include "../jrd/flags.h"
2003-11-08 17:40:17 +01:00
#include "../jrd/ibase.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/lls.h"
#include "../jrd/met.h"
#include "../jrd/btr.h"
#include "../jrd/ini.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/intl.h"
#include "../jrd/dyn.h"
2003-10-20 12:53:52 +02:00
#include "../jrd/ods.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/blb_proto.h"
#include "../jrd/cmp_proto.h"
#include "../jrd/dyn_proto.h"
#include "../jrd/dyn_df_proto.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/dyn_md_proto.h"
#include "../jrd/dyn_ut_proto.h"
#include "../jrd/err_proto.h"
#include "../jrd/exe_proto.h"
#include "../jrd/gds_proto.h"
#include "../jrd/inf_proto.h"
#include "../jrd/intl_proto.h"
#include "../jrd/isc_f_proto.h"
#include "../jrd/met_proto.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/vio_proto.h"
#include "../jrd/dsc_proto.h"
2003-12-31 06:36:12 +01:00
#include "../common/utils_proto.h"
#include "../dsql/DdlNodes.h"
#include "../dsql/metd_proto.h"
#include "../jrd/PreparedStatement.h"
2001-05-23 15:26:42 +02:00
using MsgFormat::SafeArg;
using namespace Jrd;
using namespace Firebird;
DATABASE DB = STATIC "ODS.RDB";
2001-05-23 15:26:42 +02:00
2003-11-08 17:40:17 +01:00
static const UCHAR alloc_info[] = { isc_info_allocation, isc_info_end };
2009-12-17 02:36:33 +01:00
static void change_backup_mode(Global*, UCHAR verb);
2009-04-28 15:48:18 +02:00
static void modify_lfield_position(thread_db*, Global*, const MetaName&, const MetaName&,
2008-12-18 11:57:12 +01:00
USHORT, USHORT);
2009-04-28 15:48:18 +02:00
static bool check_view_dependency(thread_db*, Global*, const MetaName&, const MetaName&);
static bool check_sptrig_dependency(thread_db*, Global*, const MetaName&, const MetaName&);
static void modify_lfield_index(thread_db*, Global*, const MetaName&, const MetaName&,
2008-12-18 11:57:12 +01:00
const MetaName&);
2009-04-28 15:48:18 +02:00
static bool field_exists(thread_db*, Global*, const MetaName&, const MetaName&);
static bool domain_exists(thread_db*, Global*, const MetaName&);
static void get_domain_type(thread_db*, Global*, dyn_fld&);
static ULONG check_update_fld_type(const dyn_fld&, const dyn_fld&);
2007-03-28 06:51:48 +02:00
static ULONG check_update_numeric_type(const dyn_fld&, const dyn_fld&);
static void modify_err_punt(thread_db*, ULONG, const dyn_fld&, const dyn_fld&);
2001-05-23 15:26:42 +02:00
void DYN_modify_database( Global* gbl, const UCHAR** ptr)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* D Y N _ m o d i f y _ d a t a b a s e
*
**************************************
*
* Functional description
* Modify a database.
*
**************************************/
UCHAR s[128];
2001-05-23 15:26:42 +02:00
thread_db* tdbb = JRD_get_thread_data();
Database* dbb = tdbb->getDatabase();
Jrd::Attachment* attachment = tdbb->getAttachment();
2001-05-23 15:26:42 +02:00
jrd_req* request = NULL;
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
try {
2009-11-25 05:06:48 +01:00
INF_database_info(alloc_info, sizeof(alloc_info), s, sizeof(s));
2001-05-23 15:26:42 +02:00
2009-11-25 05:06:48 +01:00
if (s[0] != isc_info_allocation) {
goto dyn_punt_84;
}
2001-05-23 15:26:42 +02:00
2009-11-25 05:06:48 +01:00
request = CMP_find_request(tdbb, drq_m_database, DYN_REQUESTS);
2001-05-23 15:26:42 +02:00
2009-11-25 05:06:48 +01:00
const SSHORT length = gds__vax_integer(s + 1, 2);
SLONG start = gds__vax_integer(s + 3, length);
2001-05-23 15:26:42 +02:00
2009-11-25 05:06:48 +01:00
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
DBB IN RDB$DATABASE
2001-05-23 15:26:42 +02:00
2009-11-25 05:06:48 +01:00
if (!DYN_REQUEST(drq_m_database))
DYN_REQUEST(drq_m_database) = request;
2001-05-23 15:26:42 +02:00
2009-11-25 05:06:48 +01:00
MODIFY DBB USING
UCHAR verb;
while ((verb = *(*ptr)++) != isc_dyn_end)
2009-11-26 01:20:59 +01:00
{
2009-11-25 05:06:48 +01:00
switch (verb)
{
case isc_dyn_security_class:
if (GET_STRING(ptr, DBB.RDB$SECURITY_CLASS))
DBB.RDB$SECURITY_CLASS.NULL = FALSE;
else
DBB.RDB$SECURITY_CLASS.NULL = TRUE;
break;
2001-05-23 15:26:42 +02:00
2009-11-25 05:06:48 +01:00
case isc_dyn_def_file:
DYN_define_file(gbl, ptr, (SLONG) 0, &start, 84);
break;
2001-05-23 15:26:42 +02:00
2009-11-25 05:06:48 +01:00
case isc_dyn_def_difference:
DYN_define_difference(gbl, ptr);
break;
2009-11-25 05:06:48 +01:00
case isc_dyn_drop_difference:
case isc_dyn_begin_backup:
case isc_dyn_end_backup:
change_backup_mode(gbl, verb);
break;
2001-05-23 15:26:42 +02:00
2009-11-25 05:06:48 +01:00
case isc_dyn_fld_character_set_name:
if (!tdbb->getAttachment()->locksmith())
ERR_post(Arg::Gds(isc_adm_task_denied));
2009-11-25 05:06:48 +01:00
if (GET_STRING(ptr, DBB.RDB$CHARACTER_SET_NAME))
DBB.RDB$CHARACTER_SET_NAME.NULL = FALSE;
else
DBB.RDB$CHARACTER_SET_NAME.NULL = TRUE;
break;
2009-11-25 05:06:48 +01:00
case isc_dyn_fld_collation:
{
2009-11-25 05:06:48 +01:00
MetaName collation;
GET_STRING(ptr, collation);
if (!DBB.RDB$CHARACTER_SET_NAME.NULL)
{
string sql;
sql.printf("alter character set \"%s\" set default collation \"%s\"",
PreparedStatement::escapeName(DBB.RDB$CHARACTER_SET_NAME).c_str(),
PreparedStatement::escapeName(collation).c_str());
AutoPtr<PreparedStatement> ps(attachment->prepareStatement(tdbb,
2010-01-03 01:19:14 +01:00
gbl->gbl_transaction, sql));
ps->execute(tdbb, gbl->gbl_transaction);
2009-11-25 05:06:48 +01:00
}
}
2009-11-25 05:06:48 +01:00
break;
2009-11-25 05:06:48 +01:00
default:
--(*ptr);
DYN_execute(gbl, ptr, NULL, NULL, NULL, NULL, NULL);
}
2009-11-26 01:20:59 +01:00
}
2009-11-25 05:06:48 +01:00
END_MODIFY;
END_FOR;
2001-05-23 15:26:42 +02:00
if (!DYN_REQUEST(drq_m_database))
DYN_REQUEST(drq_m_database) = request;
2001-12-24 03:51:06 +01:00
}
2009-11-25 05:06:48 +01:00
catch (const Exception& ex)
{
stuff_exception(tdbb->tdbb_status_vector, ex);
DYN_rundown_request(request, -1);
DYN_error_punt(true, 84);
// msg 84: "MODIFY DATABASE failed"
2001-12-24 03:51:06 +01:00
}
return;
dyn_punt_84:
DYN_error_punt(true, 84);
// msg 84: "MODIFY DATABASE failed"
2001-05-23 15:26:42 +02:00
}
void DYN_modify_exception( Global* gbl, const UCHAR** ptr)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* D Y N _ m o d i f y _ e x c e p t i o n
*
**************************************
*
* Functional description
* Modify an exception.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
Database* dbb = tdbb->getDatabase();
2001-05-23 15:26:42 +02:00
jrd_req* request = CMP_find_request(tdbb, drq_m_xcp, DYN_REQUESTS);
bool found = false;
2001-05-23 15:26:42 +02:00
MetaName t;
2001-05-23 15:26:42 +02:00
GET_STRING(ptr, t);
try {
2009-11-25 05:06:48 +01:00
found = false;
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
X IN RDB$EXCEPTIONS
WITH X.RDB$EXCEPTION_NAME EQ t.c_str()
2001-05-23 15:26:42 +02:00
2009-11-25 05:06:48 +01:00
if (!DYN_REQUEST(drq_m_xcp))
DYN_REQUEST(drq_m_xcp) = request;
2001-05-23 15:26:42 +02:00
2009-11-25 05:06:48 +01:00
found = true;
2009-11-25 05:06:48 +01:00
DdlNode::executeDdlTrigger(tdbb, gbl->gbl_transaction, DdlNode::DTW_BEFORE,
DDL_TRIGGER_ALTER_EXCEPTION, t, gbl->sqlText);
2009-11-25 05:06:48 +01:00
MODIFY X
UCHAR verb;
while ((verb = *(*ptr)++) != isc_dyn_end)
switch (verb)
{
case isc_dyn_xcp_msg:
GET_BYTES(ptr, X.RDB$MESSAGE);
X.RDB$MESSAGE.NULL = FALSE;
break;
2001-05-23 15:26:42 +02:00
2009-11-25 05:06:48 +01:00
default:
DYN_unsupported_verb();
}
END_MODIFY;
END_FOR;
2001-05-23 15:26:42 +02:00
2009-11-25 05:06:48 +01:00
if (!DYN_REQUEST(drq_m_xcp))
DYN_REQUEST(drq_m_xcp) = request;
2001-05-23 15:26:42 +02:00
} // try
2009-11-25 05:06:48 +01:00
catch (const Exception& ex)
{
stuff_exception(tdbb->tdbb_status_vector, ex);
DYN_rundown_request(request, -1);
DYN_error_punt(true, 145);
// msg 145: "MODIFY EXCEPTION failed"
2001-12-24 03:51:06 +01:00
}
if (found)
{
DdlNode::executeDdlTrigger(tdbb, gbl->gbl_transaction, DdlNode::DTW_AFTER,
DDL_TRIGGER_ALTER_EXCEPTION, t, gbl->sqlText);
}
else
2001-12-24 03:51:06 +01:00
{
DYN_error_punt(false, 144);
// msg 144: "Exception not found"
}
}
// *************************************
// D Y N _ m o d i f y _ f u n c t i o n
// *************************************
// Its purpose is to change the comment in the function's record and to
// allow changing the entry point and/or the module name.
void DYN_modify_function(Global* gbl, const UCHAR** ptr)
{
thread_db* tdbb = JRD_get_thread_data();
Database* dbb = tdbb->getDatabase();
jrd_req* request = CMP_find_request(tdbb, drq_m_fun, DYN_REQUESTS);
bool found = false;
SqlIdentifier t;
GET_STRING(ptr, t);
try {
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
X IN RDB$FUNCTIONS
WITH X.RDB$FUNCTION_NAME EQ t AND
X.RDB$PACKAGE_NAME MISSING
2006-07-09 07:08:23 +02:00
if (!DYN_REQUEST(drq_m_fun))
DYN_REQUEST(drq_m_fun) = request;
2010-01-02 10:42:09 +01:00
if (!X.RDB$ENGINE_NAME.NULL)
status_exception::raise(Arg::Gds(isc_dyn_newfc_oldsyntax) << t);
DdlNode::executeDdlTrigger(tdbb, gbl->gbl_transaction, DdlNode::DTW_BEFORE,
DDL_TRIGGER_ALTER_FUNCTION, t, gbl->sqlText);
found = true;
MODIFY X
UCHAR verb;
while ((verb = *(*ptr)++) != isc_dyn_end)
{
switch (verb)
{
case isc_dyn_func_module_name:
GET_STRING(ptr, X.RDB$MODULE_NAME);
X.RDB$MODULE_NAME.NULL = FALSE;
break;
case isc_dyn_func_entry_point:
GET_STRING(ptr, X.RDB$ENTRYPOINT);
X.RDB$ENTRYPOINT.NULL = FALSE;
break;
default:
DYN_unsupported_verb();
}
}
END_MODIFY;
END_FOR;
if (!DYN_REQUEST(drq_m_fun))
DYN_REQUEST(drq_m_fun) = request;
}
2009-11-25 05:06:48 +01:00
catch (const Exception& ex)
{
stuff_exception(tdbb->tdbb_status_vector, ex);
DYN_rundown_request(request, -1);
DYN_error_punt(true, 92);
// msg 92: "MODIFY RDB$FUNCTIONS failed"
}
if (found)
{
DdlNode::executeDdlTrigger(tdbb, gbl->gbl_transaction, DdlNode::DTW_AFTER,
DDL_TRIGGER_ALTER_FUNCTION, t, gbl->sqlText);
}
else
{
DYN_error_punt(false, 41, t);
// msg 41: "Function %s not found"
}
}
void DYN_modify_global_field(Global* gbl,
const UCHAR** ptr,
2008-12-18 11:57:12 +01:00
const MetaName* relation_name,
MetaName* field_name)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* D Y N _ m o d i f y _ g l o b a l _ f i e l d
*
**************************************
*
* Functional description
* Execute a dynamic ddl statement.
* Note: a global field here is a SQL domain.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
Database* dbb = tdbb->getDatabase();
2001-05-23 15:26:42 +02:00
jrd_req* request = CMP_find_request(tdbb, drq_m_gfield, DYN_REQUESTS);
bool found = false;
2008-12-18 11:57:12 +01:00
dyn_fld orig_dom, new_dom;
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
try {
2008-12-18 11:57:12 +01:00
bool dtype, scale, prec, subtype, charlen, collation, fldlen, nullflg, charset;
dtype = scale = prec = subtype = charlen = collation = fldlen = nullflg = charset = false;
2009-12-17 01:38:55 +01:00
bool bqryname, bqryhdr, bedtstr, bmissingval, bfldvald, bfldvaldsrc,
bdelvald, bdeldflt, bflddftval, bflddfltsrc;
bqryname = bqryhdr = bedtstr = bmissingval = false;
2009-12-17 01:38:55 +01:00
bfldvald = bfldvaldsrc = bdelvald = bdeldflt = bflddftval = bflddfltsrc = false;
2008-12-18 11:57:12 +01:00
const UCHAR *qryname, *edtstr;
2009-12-17 01:38:55 +01:00
const UCHAR *qryhdr, *missingval, *fldvald, *fldvaldsrc, *flddftval, *flddfltsrc;
GET_STRING(ptr, orig_dom.dyn_fld_name);
2001-05-23 15:26:42 +02:00
int field_adjusted_count = 0;
2008-12-18 11:57:12 +01:00
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
FLD IN RDB$FIELDS WITH FLD.RDB$FIELD_NAME EQ orig_dom.dyn_fld_name.c_str()
2001-05-23 15:26:42 +02:00
2006-07-09 07:08:23 +02:00
if (!DYN_REQUEST(drq_m_gfield))
DYN_REQUEST(drq_m_gfield) = request;
2001-05-23 15:26:42 +02:00
found = true;
2001-05-23 15:26:42 +02:00
DdlNode::executeDdlTrigger(tdbb, gbl->gbl_transaction, DdlNode::DTW_BEFORE,
DDL_TRIGGER_ALTER_DOMAIN, orig_dom.dyn_fld_name, gbl->sqlText);
DSC_make_descriptor(&orig_dom.dyn_dsc,
2001-05-23 15:26:42 +02:00
FLD.RDB$FIELD_TYPE,
FLD.RDB$FIELD_SCALE,
FLD.RDB$FIELD_LENGTH,
FLD.RDB$FIELD_SUB_TYPE,
FLD.RDB$CHARACTER_SET_ID, FLD.RDB$COLLATION_ID);
orig_dom.dyn_charbytelen = FLD.RDB$FIELD_LENGTH;
orig_dom.dyn_dtype = FLD.RDB$FIELD_TYPE;
orig_dom.dyn_precision = FLD.RDB$FIELD_PRECISION;
orig_dom.dyn_sub_type = FLD.RDB$FIELD_SUB_TYPE;
orig_dom.dyn_charlen = FLD.RDB$CHARACTER_LENGTH;
orig_dom.dyn_collation = FLD.RDB$COLLATION_ID;
orig_dom.dyn_null_flag = FLD.RDB$NULL_FLAG != 0;
2001-05-23 15:26:42 +02:00
2009-11-21 08:38:05 +01:00
// If the original field type is an array, force its blr type to blr_blob
bool has_dimensions = false;
2001-05-23 15:26:42 +02:00
if (FLD.RDB$DIMENSIONS != 0)
{
orig_dom.dyn_dtype = blr_blob;
has_dimensions = true;
2001-05-23 15:26:42 +02:00
}
2006-07-09 07:08:23 +02:00
bool single_validate = false;
2001-05-23 15:26:42 +02:00
UCHAR verb;
2003-11-08 17:40:17 +01:00
while ((verb = *(*ptr)++) != isc_dyn_end)
2001-05-23 15:26:42 +02:00
{
switch (verb)
{
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_name:
2001-05-23 15:26:42 +02:00
{
MetaName newfld;
2001-05-23 15:26:42 +02:00
2009-12-17 02:36:33 +01:00
GET_STRING(ptr, newfld);
if (!domain_exists(tdbb, gbl, newfld))
2001-05-23 15:26:42 +02:00
{
2009-12-17 02:36:33 +01:00
MODIFY FLD USING
strcpy(FLD.RDB$FIELD_NAME, newfld.c_str());
FLD.RDB$FIELD_NAME.NULL = FALSE;
jrd_req* old_request = request;
request = NULL;
// CVC: Let's update the dimensions, too.
if (has_dimensions)
{
FOR (REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
DIM_DOM IN RDB$FIELD_DIMENSIONS
WITH DIM_DOM.RDB$FIELD_NAME EQ orig_dom.dyn_fld_name.c_str()
MODIFY DIM_DOM USING
strcpy (DIM_DOM.RDB$FIELD_NAME, newfld.c_str());
DIM_DOM.RDB$FIELD_NAME.NULL = FALSE;
2001-05-23 15:26:42 +02:00
END_MODIFY;
END_FOR;
2009-12-17 02:36:33 +01:00
CMP_release (tdbb, request);
request = NULL;
}
// CVC: End modification.
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
DOM IN RDB$RELATION_FIELDS
WITH DOM.RDB$FIELD_SOURCE EQ orig_dom.dyn_fld_name.c_str()
MODIFY DOM USING
strcpy(DOM.RDB$FIELD_SOURCE, newfld.c_str());
DOM.RDB$FIELD_SOURCE.NULL = FALSE;
END_MODIFY;
modify_lfield_index(tdbb, gbl,
DOM.RDB$RELATION_NAME,
DOM.RDB$FIELD_NAME,
DOM.RDB$FIELD_NAME);
END_FOR;
CMP_release(tdbb, request);
request = old_request;
END_MODIFY;
2001-05-23 15:26:42 +02:00
}
2002-06-30 10:46:51 +02:00
else
{
2009-12-17 02:36:33 +01:00
DYN_error_punt(false, 204, SafeArg() << orig_dom.dyn_fld_name.c_str() <<
newfld.c_str());
// msg 204: Cannot rename domain %s to %s. A domain with that name already exists.
2002-06-30 10:46:51 +02:00
}
2009-12-17 02:36:33 +01:00
2001-05-23 15:26:42 +02:00
break;
}
2003-11-08 17:40:17 +01:00
case isc_dyn_rel_name:
GET_STRING(ptr, new_dom.dyn_rel_name);
2001-05-23 15:26:42 +02:00
break;
2009-11-21 08:38:05 +01:00
// CVC: The syntax for DDL alter domain was accepting multiple
2009-11-22 01:09:30 +01:00
// changes in one command even to the same features, IE two length alterations.
// This repetitive type change will cause havoc so it should be stopped in the future.
2002-06-30 10:46:51 +02:00
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_length:
fldlen = true;
new_dom.dyn_dsc.dsc_length = DYN_get_number(ptr);
2002-06-30 10:46:51 +02:00
if (++field_adjusted_count > 2)
{
2004-08-26 13:07:57 +02:00
EXE_unwind(tdbb, request);
DYN_error_punt(false, 148, orig_dom.dyn_fld_name.c_str());
// msg 148: "Only one data type change to the domain %s allowed at a time"
2002-06-30 10:46:51 +02:00
}
2009-01-20 09:33:59 +01:00
switch (new_dom.dyn_dtype)
{
2008-12-18 11:57:12 +01:00
2002-06-30 10:46:51 +02:00
case blr_text:
case blr_text2:
case blr_varying:
case blr_varying2:
case blr_cstring:
case blr_cstring2:
new_dom.dyn_charbytelen = new_dom.dyn_dsc.dsc_length;
2002-06-30 10:46:51 +02:00
break;
default:
new_dom.dyn_charbytelen = 0; // It won't be used, anyway.
2002-06-30 10:46:51 +02:00
break;
}
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_type:
dtype = true;
new_dom.dyn_dtype = DYN_get_number(ptr);
2002-06-30 10:46:51 +02:00
if (++field_adjusted_count > 2)
{
2004-08-26 13:07:57 +02:00
EXE_unwind(tdbb, request);
DYN_error_punt(false, 148, orig_dom.dyn_fld_name.c_str());
// msg 148: "Only one data type change to the domain %s allowed at a time"
2002-06-30 10:46:51 +02:00
}
2001-05-23 15:26:42 +02:00
2009-01-20 09:33:59 +01:00
switch (new_dom.dyn_dtype)
{
2001-05-23 15:26:42 +02:00
case blr_text:
case blr_text2:
case blr_varying:
case blr_varying2:
case blr_cstring:
case blr_cstring2:
if (new_dom.dyn_dsc.dsc_length && !new_dom.dyn_charbytelen)
new_dom.dyn_charbytelen = new_dom.dyn_dsc.dsc_length;
new_dom.dyn_dsc.dsc_length = DSC_string_length(&new_dom.dyn_dsc);
2001-05-23 15:26:42 +02:00
break;
case blr_short:
new_dom.dyn_dsc.dsc_length = 2;
2001-05-23 15:26:42 +02:00
break;
case blr_long:
case blr_float:
new_dom.dyn_dsc.dsc_length = 4;
2001-05-23 15:26:42 +02:00
break;
case blr_int64:
case blr_sql_time:
case blr_sql_date:
case blr_timestamp:
case blr_double:
case blr_d_float:
new_dom.dyn_dsc.dsc_length = 8;
2001-05-23 15:26:42 +02:00
break;
default:
break;
}
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_scale:
scale = true;
new_dom.dyn_dsc.dsc_scale = DYN_get_number(ptr);
2001-05-23 15:26:42 +02:00
break;
case isc_dyn_fld_precision:
prec = true;
new_dom.dyn_precision = DYN_get_number(ptr);
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_sub_type:
subtype = true;
new_dom.dyn_sub_type = DYN_get_number(ptr);
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_char_length:
charlen = true;
new_dom.dyn_charlen = DYN_get_number(ptr);
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_collation:
collation = true;
new_dom.dyn_collation = DYN_get_number(ptr);
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_character_set:
charset = true;
new_dom.dyn_charset = DYN_get_number(ptr);
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_not_null:
nullflg = true;
new_dom.dyn_null_flag = true;
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_query_name:
2009-12-07 16:55:40 +01:00
qryname = *ptr;
bqryname = true;
2001-05-23 15:26:42 +02:00
DYN_skip_attribute(ptr);
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_query_header:
qryhdr = *ptr;
bqryhdr = true;
2001-05-23 15:26:42 +02:00
DYN_skip_attribute(ptr);
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_edit_string:
edtstr = *ptr;
bedtstr = true;
2001-05-23 15:26:42 +02:00
DYN_skip_attribute(ptr);
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_missing_value:
missingval = *ptr;
bmissingval = true;
2001-05-23 15:26:42 +02:00
DYN_skip_attribute(ptr);
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_single_validation:
2009-11-25 05:06:48 +01:00
if (single_validate)
{
2004-08-26 13:07:57 +02:00
EXE_unwind(tdbb, request);
DYN_error_punt(false, 160);
2009-11-21 08:38:05 +01:00
// msg 160: "Only one constraint allowed for a domain"
2001-05-23 15:26:42 +02:00
break;
}
2008-01-16 09:46:02 +01:00
single_validate = true;
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_validation_blr:
2009-11-25 05:06:48 +01:00
if (single_validate && (!FLD.RDB$VALIDATION_BLR.NULL))
{
2004-08-26 13:07:57 +02:00
EXE_unwind(tdbb, request);
DYN_error_punt(false, 160);
2009-11-21 08:38:05 +01:00
// msg 160: "Only one constraint allowed for a domain"
2001-05-23 15:26:42 +02:00
break;
}
2008-01-16 09:46:02 +01:00
single_validate = true;
fldvald = *ptr;
bfldvald = true;
2001-05-23 15:26:42 +02:00
DYN_skip_attribute(ptr);
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_validation_source:
fldvaldsrc = *ptr;
bfldvaldsrc = true;
2001-05-23 15:26:42 +02:00
DYN_skip_attribute(ptr);
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_del_validation:
bdelvald = true;
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_del_default:
bdeldflt = true;
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_default_value:
if (has_dimensions)
{
DYN_error_punt(false, 226, orig_dom.dyn_fld_name.c_str());
// msg 226: "Default value is not allowed for array type in domain %s"
}
flddftval = *ptr;
bflddftval = true;
2001-05-23 15:26:42 +02:00
DYN_skip_attribute(ptr);
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_default_source:
if (has_dimensions)
{
DYN_error_punt(false, 226, orig_dom.dyn_fld_name.c_str());
// msg 226: "Default value is not allowed for array type in domain %s"
}
flddfltsrc = *ptr;
bflddfltsrc = true;
2001-05-23 15:26:42 +02:00
DYN_skip_attribute(ptr);
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_dimensions:
new_dom.dyn_dtype = blr_blob;
2001-05-23 15:26:42 +02:00
break;
2009-11-21 08:38:05 +01:00
// These should only be defined for BLOB types and should not come through with
// any other types. Do nothing with them.
2001-05-23 15:26:42 +02:00
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_segment_length:
2001-05-23 15:26:42 +02:00
DYN_get_number(ptr);
break;
default:
--(*ptr);
2008-12-18 11:57:12 +01:00
DYN_execute(gbl, ptr, relation_name, field_name, NULL, NULL, NULL);
2001-05-23 15:26:42 +02:00
}
}
2009-11-21 08:38:05 +01:00
// Now that we have all of the information needed, let's check to see if the field type can be modifed.
// Only do this, however, if we are actually modifying the datatype of the domain.
2001-05-23 15:26:42 +02:00
2009-11-25 05:06:48 +01:00
if (dtype)
{
DSC_make_descriptor(&new_dom.dyn_dsc,
new_dom.dyn_dtype,
new_dom.dyn_dsc.dsc_scale,
new_dom.dyn_dsc.dsc_length,
new_dom.dyn_sub_type,
2008-12-18 11:57:12 +01:00
new_dom.dyn_charset,
new_dom.dyn_collation);
2006-07-09 07:08:23 +02:00
const ULONG retval = check_update_fld_type(orig_dom, new_dom);
if (retval != FB_SUCCESS)
modify_err_punt(tdbb, retval, orig_dom, new_dom);
if (!new_dom.dyn_dsc.isExact() || new_dom.dyn_dsc.dsc_scale != 0)
{
AutoCacheRequest request(tdbb, drq_l_ident_gens, DYN_REQUESTS);
FOR (REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
RFR IN RDB$RELATION_FIELDS
WITH RFR.RDB$FIELD_SOURCE = FLD.RDB$FIELD_NAME AND
RFR.RDB$GENERATOR_NAME NOT MISSING
{
// Domain @1 must be of exact number type with zero scale because it's used in
// an identity column.
DYN_error_punt(false, 276, SafeArg() << orig_dom.dyn_fld_name.c_str());
}
END_FOR
}
2001-05-23 15:26:42 +02:00
}
MODIFY FLD USING
2009-11-25 05:06:48 +01:00
if (dtype)
{
FLD.RDB$FIELD_TYPE = new_dom.dyn_dtype;
2001-05-23 15:26:42 +02:00
FLD.RDB$FIELD_TYPE.NULL = FALSE;
2009-11-21 08:38:05 +01:00
// If the datatype was changed, update any indexes that involved the domain
2001-05-23 15:26:42 +02:00
jrd_req* old_request = request;
2001-05-23 15:26:42 +02:00
request = NULL;
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
2008-12-18 11:57:12 +01:00
DOM IN RDB$RELATION_FIELDS
2006-07-09 07:08:23 +02:00
WITH DOM.RDB$FIELD_SOURCE EQ orig_dom.dyn_fld_name.c_str()
2009-04-28 15:48:18 +02:00
modify_lfield_index(tdbb, gbl,
2006-07-09 07:08:23 +02:00
DOM.RDB$RELATION_NAME,
DOM.RDB$FIELD_NAME,
DOM.RDB$FIELD_NAME);
2001-05-23 15:26:42 +02:00
END_FOR;
2004-08-26 13:07:57 +02:00
CMP_release(tdbb, request);
2001-05-23 15:26:42 +02:00
request = old_request;
}
2009-11-25 05:06:48 +01:00
if (scale)
{
FLD.RDB$FIELD_SCALE = new_dom.dyn_dsc.dsc_scale;
2001-05-23 15:26:42 +02:00
FLD.RDB$FIELD_SCALE.NULL = FALSE;
}
2009-11-25 05:06:48 +01:00
if (prec)
{
FLD.RDB$FIELD_PRECISION = new_dom.dyn_precision;
2001-05-23 15:26:42 +02:00
FLD.RDB$FIELD_PRECISION.NULL = FALSE;
}
2009-11-25 05:06:48 +01:00
if (subtype)
{
FLD.RDB$FIELD_SUB_TYPE = new_dom.dyn_sub_type;
2001-05-23 15:26:42 +02:00
FLD.RDB$FIELD_SUB_TYPE.NULL = FALSE;
}
2009-11-25 05:06:48 +01:00
if (charlen)
{
FLD.RDB$CHARACTER_LENGTH = new_dom.dyn_charlen;
2001-05-23 15:26:42 +02:00
FLD.RDB$CHARACTER_LENGTH.NULL = FALSE;
}
2009-11-25 05:06:48 +01:00
if (charset)
{
2006-12-18 08:01:18 +01:00
FLD.RDB$CHARACTER_SET_ID = new_dom.dyn_charset;
FLD.RDB$CHARACTER_SET_ID.NULL = FALSE;
}
2009-11-25 05:06:48 +01:00
if (collation)
{
2006-12-18 08:01:18 +01:00
FLD.RDB$COLLATION_ID = new_dom.dyn_collation;
FLD.RDB$COLLATION_ID.NULL = FALSE;
}
2009-11-25 05:06:48 +01:00
if (fldlen)
{
2009-11-21 08:38:05 +01:00
// CVC: Rescue from the wrong field_length with a helper.
if (new_dom.dyn_dsc.dsc_dtype <= dtype_varying && new_dom.dyn_charbytelen)
FLD.RDB$FIELD_LENGTH = new_dom.dyn_charbytelen;
2002-06-30 10:46:51 +02:00
else
FLD.RDB$FIELD_LENGTH = new_dom.dyn_dsc.dsc_length;
2001-05-23 15:26:42 +02:00
FLD.RDB$FIELD_LENGTH.NULL = FALSE;
}
2009-11-25 05:06:48 +01:00
if (bqryname)
{
2001-05-23 15:26:42 +02:00
if (GET_STRING(&qryname, FLD.RDB$QUERY_NAME))
FLD.RDB$QUERY_NAME.NULL = FALSE;
else
FLD.RDB$QUERY_NAME.NULL = TRUE;
}
2009-11-25 05:06:48 +01:00
if (bqryhdr)
{
if (DYN_put_blr_blob(gbl, &qryhdr, &FLD.RDB$QUERY_HEADER))
2001-05-23 15:26:42 +02:00
FLD.RDB$QUERY_HEADER.NULL = FALSE;
else
FLD.RDB$QUERY_HEADER.NULL = TRUE;
}
2009-11-25 05:06:48 +01:00
if (bedtstr)
{
2001-05-23 15:26:42 +02:00
if (GET_STRING(&edtstr, FLD.RDB$EDIT_STRING))
FLD.RDB$EDIT_STRING.NULL = FALSE;
else
FLD.RDB$EDIT_STRING.NULL = TRUE;
}
2009-11-25 05:06:48 +01:00
if (bmissingval)
{
if (DYN_put_blr_blob(gbl, &missingval, &FLD.RDB$MISSING_VALUE))
FLD.RDB$MISSING_VALUE.NULL = FALSE;
2001-05-23 15:26:42 +02:00
else
FLD.RDB$MISSING_VALUE.NULL = TRUE;
}
2009-11-25 05:06:48 +01:00
if (bfldvald)
{
if (DYN_put_blr_blob(gbl, &fldvald, &FLD.RDB$VALIDATION_BLR))
2001-05-23 15:26:42 +02:00
FLD.RDB$VALIDATION_BLR.NULL = FALSE;
else
FLD.RDB$VALIDATION_BLR.NULL = TRUE;
}
2009-11-25 05:06:48 +01:00
if (bfldvaldsrc)
{
if (DYN_put_text_blob(gbl, &fldvaldsrc, &FLD.RDB$VALIDATION_SOURCE))
{
FLD.RDB$VALIDATION_SOURCE.NULL = FALSE;
}
2001-05-23 15:26:42 +02:00
else
FLD.RDB$VALIDATION_SOURCE.NULL = TRUE;
}
2009-11-25 05:06:48 +01:00
if (bdelvald)
{
2001-05-23 15:26:42 +02:00
FLD.RDB$VALIDATION_BLR.NULL = TRUE;
FLD.RDB$VALIDATION_SOURCE.NULL = TRUE;
}
2009-11-25 05:06:48 +01:00
if (bdeldflt)
{
2001-05-23 15:26:42 +02:00
FLD.RDB$DEFAULT_VALUE.NULL = TRUE;
FLD.RDB$DEFAULT_SOURCE.NULL = TRUE;
}
2009-11-25 05:06:48 +01:00
if (bflddftval)
{
if (DYN_put_blr_blob(gbl, &flddftval, &FLD.RDB$DEFAULT_VALUE))
FLD.RDB$DEFAULT_VALUE.NULL = FALSE;
else
FLD.RDB$DEFAULT_VALUE.NULL = TRUE;
2001-05-23 15:26:42 +02:00
}
2009-11-25 05:06:48 +01:00
if (bflddfltsrc)
{
if (DYN_put_text_blob(gbl, &flddfltsrc, &FLD.RDB$DEFAULT_SOURCE))
FLD.RDB$DEFAULT_SOURCE.NULL = FALSE;
else
FLD.RDB$DEFAULT_SOURCE.NULL = TRUE;
2001-05-23 15:26:42 +02:00
}
END_MODIFY;
END_FOR;
if (!DYN_REQUEST(drq_m_gfield))
DYN_REQUEST(drq_m_gfield) = request;
} // try
2009-11-25 05:06:48 +01:00
catch (const Exception& ex)
{
stuff_exception(tdbb->tdbb_status_vector, ex);
DYN_rundown_request(request, -1);
DYN_error_punt(true, 87);
2009-11-21 08:38:05 +01:00
// msg 87: "MODIFY RDB$FIELDS failed"
2001-12-24 03:51:06 +01:00
}
if (found)
{
DdlNode::executeDdlTrigger(tdbb, gbl->gbl_transaction, DdlNode::DTW_AFTER,
DDL_TRIGGER_ALTER_DOMAIN, orig_dom.dyn_fld_name, gbl->sqlText);
}
else
2001-12-24 03:51:06 +01:00
{
DYN_error_punt(false, 89);
2009-11-21 08:38:05 +01:00
// msg 89: "Global field not found"
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
}
void DYN_modify_index( Global* gbl, const UCHAR** ptr)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* D Y N _ m o d i f y _ i n d e x
*
**************************************
*
* Functional description
* Modify an existing index
*
**************************************/
MetaName name;
2001-05-23 15:26:42 +02:00
thread_db* tdbb = JRD_get_thread_data();
Database* dbb = tdbb->getDatabase();
2001-05-23 15:26:42 +02:00
jrd_req* request = CMP_find_request(tdbb, drq_m_index, DYN_REQUESTS);
bool found = false;
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
try {
2009-11-25 05:06:48 +01:00
GET_STRING(ptr, name);
2001-05-23 15:26:42 +02:00
2009-11-25 05:06:48 +01:00
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
IDX IN RDB$INDICES WITH IDX.RDB$INDEX_NAME EQ name.c_str()
2001-05-23 15:26:42 +02:00
2009-11-25 05:06:48 +01:00
if (!DYN_REQUEST(drq_m_index))
DYN_REQUEST(drq_m_index) = request;
2001-05-23 15:26:42 +02:00
2009-11-25 05:06:48 +01:00
found = true;
2009-11-25 05:06:48 +01:00
DdlNode::executeDdlTrigger(tdbb, gbl->gbl_transaction, DdlNode::DTW_BEFORE,
DDL_TRIGGER_ALTER_INDEX, name, gbl->sqlText);
2009-11-25 05:06:48 +01:00
MODIFY IDX USING
UCHAR verb;
while ((verb = *(*ptr)++) != isc_dyn_end)
2009-11-26 01:20:59 +01:00
{
2009-11-25 05:06:48 +01:00
switch (verb)
{
case isc_dyn_idx_unique:
IDX.RDB$UNIQUE_FLAG = DYN_get_number(ptr);
IDX.RDB$UNIQUE_FLAG.NULL = FALSE;
break;
2001-05-23 15:26:42 +02:00
2009-11-25 05:06:48 +01:00
case isc_dyn_idx_inactive:
IDX.RDB$INDEX_INACTIVE = DYN_get_number(ptr);
IDX.RDB$INDEX_INACTIVE.NULL = FALSE;
break;
2001-05-23 15:26:42 +02:00
2009-12-17 01:38:55 +01:00
// For V4 index selectivity can be set only to -1
2009-11-25 05:06:48 +01:00
case isc_dyn_idx_statistic:
IDX.RDB$STATISTICS = -1.0;
IDX.RDB$STATISTICS.NULL = FALSE;
break;
2001-05-23 15:26:42 +02:00
2009-11-25 05:06:48 +01:00
default:
DYN_unsupported_verb();
}
2009-11-26 01:20:59 +01:00
}
2009-11-25 05:06:48 +01:00
END_MODIFY;
END_FOR;
2001-05-23 15:26:42 +02:00
2009-11-25 05:06:48 +01:00
if (!DYN_REQUEST(drq_m_index))
DYN_REQUEST(drq_m_index) = request;
2001-05-23 15:26:42 +02:00
} // try
2009-11-25 05:06:48 +01:00
catch (const Exception& ex)
{
stuff_exception(tdbb->tdbb_status_vector, ex);
DYN_rundown_request(request, -1);
DYN_error_punt(true, 91);
// msg 91: "MODIFY RDB$INDICES failed"
2001-12-24 03:51:06 +01:00
}
if (found)
{
DdlNode::executeDdlTrigger(tdbb, gbl->gbl_transaction, DdlNode::DTW_AFTER,
DDL_TRIGGER_ALTER_INDEX, name, gbl->sqlText);
}
else
2001-12-24 03:51:06 +01:00
{
DYN_error_punt(false, 48);
2009-11-21 08:38:05 +01:00
// msg 48: "Index not found"
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
}
2009-11-25 05:06:48 +01:00
void DYN_modify_local_field(Global* gbl, const UCHAR** ptr, const MetaName* relation_name)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* D Y N _ m o d i f y _ l o c a l _ f i e l d
*
**************************************
*
* Functional description
* Execute a dynamic ddl statement.
*
**************************************/
USHORT position;
MetaName f, r;
2008-01-16 09:46:02 +01:00
const UCHAR* query_name;
const UCHAR* edit_string;
const UCHAR* security_class;
const UCHAR* new_name;
const UCHAR* query_header;
const UCHAR* new_source = NULL;
2001-05-23 15:26:42 +02:00
thread_db* tdbb = JRD_get_thread_data();
Database* dbb = tdbb->getDatabase();
2001-05-23 15:26:42 +02:00
GET_STRING(ptr, f);
2008-12-18 11:57:12 +01:00
2009-12-17 01:38:55 +01:00
bool sfflag, qnflag, qhflag, esflag, system_flag, scflag, nnflag, ntflag, npflag;
sfflag = qnflag = qhflag = esflag = scflag = npflag = nnflag = ntflag = false;
TriState nullFlag;
2008-12-18 11:57:12 +01:00
UCHAR verb;
2003-11-08 17:40:17 +01:00
while ((verb = *(*ptr)++) != isc_dyn_end)
{
2009-01-20 09:33:59 +01:00
switch (verb)
{
2003-11-08 17:40:17 +01:00
case isc_dyn_rel_name:
2001-05-23 15:26:42 +02:00
GET_STRING(ptr, r);
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_system_flag:
2001-05-23 15:26:42 +02:00
system_flag = DYN_get_number(ptr);
sfflag = true;
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_position:
2001-05-23 15:26:42 +02:00
position = DYN_get_number(ptr);
npflag = true;
2001-05-23 15:26:42 +02:00
break;
case isc_dyn_new_fld_name:
2008-01-16 09:46:02 +01:00
new_name = *ptr;
nnflag = true;
2001-05-23 15:26:42 +02:00
DYN_skip_attribute(ptr);
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_query_name:
2008-01-16 09:46:02 +01:00
query_name = *ptr;
qnflag = true;
2001-05-23 15:26:42 +02:00
DYN_skip_attribute(ptr);
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_query_header:
query_header = *ptr;
qhflag = true;
2001-05-23 15:26:42 +02:00
DYN_skip_attribute(ptr);
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_edit_string:
2008-01-16 09:46:02 +01:00
edit_string = *ptr;
esflag = true;
2001-05-23 15:26:42 +02:00
DYN_skip_attribute(ptr);
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_security_class:
2008-01-16 09:46:02 +01:00
security_class = *ptr;
scflag = true;
2001-05-23 15:26:42 +02:00
DYN_skip_attribute(ptr);
break;
2008-01-16 09:46:02 +01:00
case isc_dyn_fld_source:
new_source = *ptr;
DYN_skip_attribute(ptr);
break;
case isc_dyn_fld_not_null:
nullFlag = true;
break;
case isc_dyn_fld_null:
nullFlag = false;
break;
2001-05-23 15:26:42 +02:00
default:
--(*ptr);
DYN_execute(gbl, ptr, relation_name, NULL, NULL, NULL, NULL);
2001-05-23 15:26:42 +02:00
}
}
2001-05-23 15:26:42 +02:00
jrd_req* request = CMP_find_request(tdbb, drq_m_lfield, DYN_REQUESTS);
bool found = false;
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
try {
USHORT existing_position;
found = false;
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
FLD IN RDB$RELATION_FIELDS
2008-12-18 11:57:12 +01:00
WITH FLD.RDB$FIELD_NAME EQ f.c_str()
AND FLD.RDB$RELATION_NAME EQ r.c_str()
2001-05-23 15:26:42 +02:00
2006-07-09 07:08:23 +02:00
if (!DYN_REQUEST(drq_m_lfield))
DYN_REQUEST(drq_m_lfield) = request;
2001-05-23 15:26:42 +02:00
found = true;
2001-05-23 15:26:42 +02:00
MODIFY FLD USING
if (npflag)
existing_position = FLD.RDB$FIELD_POSITION;
2009-11-25 05:06:48 +01:00
if (sfflag)
{
2001-05-23 15:26:42 +02:00
FLD.RDB$SYSTEM_FLAG = system_flag;
FLD.RDB$SYSTEM_FLAG.NULL = FALSE;
}
2009-11-25 05:06:48 +01:00
if (qnflag)
{
2001-05-23 15:26:42 +02:00
if (GET_STRING(&query_name, FLD.RDB$QUERY_NAME))
FLD.RDB$QUERY_NAME.NULL = FALSE;
else
FLD.RDB$QUERY_NAME.NULL = TRUE;
}
2009-11-25 05:06:48 +01:00
if (nnflag)
{
MetaName new_fld;
2001-05-23 15:26:42 +02:00
GET_STRING(&new_name, new_fld);
2009-04-28 15:48:18 +02:00
check_view_dependency(tdbb, gbl, r, f);
check_sptrig_dependency(tdbb, gbl, r, f);
2009-11-25 05:06:48 +01:00
if (!field_exists(tdbb, gbl, r, new_fld))
{
strcpy(FLD.RDB$FIELD_NAME, new_fld.c_str());
2009-04-28 15:48:18 +02:00
modify_lfield_index(tdbb, gbl, r, f, FLD.RDB$FIELD_NAME);
2001-05-23 15:26:42 +02:00
}
2009-11-25 05:06:48 +01:00
else
{
DYN_error_punt(false, 205, SafeArg() << f.c_str() << new_fld.c_str() <<
r.c_str());
2009-11-21 08:38:05 +01:00
// msg 205: Cannot rename field %s to %s. A field with that name already exists in table %s.
2001-05-23 15:26:42 +02:00
}
}
2009-11-25 05:06:48 +01:00
if (qhflag)
{
if (DYN_put_blr_blob(gbl, &query_header, &FLD.RDB$QUERY_HEADER))
2001-05-23 15:26:42 +02:00
FLD.RDB$QUERY_HEADER.NULL = FALSE;
else
FLD.RDB$QUERY_HEADER.NULL = TRUE;
}
2009-11-25 05:06:48 +01:00
if (esflag)
{
2001-05-23 15:26:42 +02:00
if (GET_STRING(&edit_string, FLD.RDB$EDIT_STRING))
FLD.RDB$EDIT_STRING.NULL = FALSE;
else
FLD.RDB$EDIT_STRING.NULL = TRUE;
}
2009-11-25 05:06:48 +01:00
if (scflag)
{
2001-05-23 15:26:42 +02:00
if (GET_STRING(&security_class, FLD.RDB$SECURITY_CLASS))
FLD.RDB$SECURITY_CLASS.NULL = FALSE;
else
FLD.RDB$SECURITY_CLASS.NULL = TRUE;
}
2008-01-16 09:46:02 +01:00
if (new_source)
GET_STRING(&new_source, FLD.RDB$FIELD_SOURCE);
if (nullFlag.isAssigned())
{
if (!nullFlag.asBool() && !FLD.RDB$GENERATOR_NAME.NULL)
{
// msg 274: Identity column @1 of table @2 cannot be changed to NULLable
DYN_error_punt(false, 274, SafeArg() << f.c_str() << r.c_str());
}
FLD.RDB$NULL_FLAG = (SSHORT) nullFlag.asBool();
}
2001-05-23 15:26:42 +02:00
END_MODIFY;
END_FOR;
if (!DYN_REQUEST(drq_m_lfield))
DYN_REQUEST(drq_m_lfield) = request;
2002-06-30 10:46:51 +02:00
if (npflag && found && position != existing_position)
2009-04-28 15:48:18 +02:00
modify_lfield_position(tdbb, gbl, r, f, position, existing_position);
2008-01-16 09:46:02 +01:00
} // try
2009-11-25 05:06:48 +01:00
catch (const Exception& ex)
{
stuff_exception(tdbb->tdbb_status_vector, ex);
DYN_rundown_request(request, -1);
DYN_error_punt(true, 95);
2009-11-21 08:38:05 +01:00
// msg 95: "MODIFY RDB$RELATION_FIELDS failed"
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
if (!found)
2001-12-24 03:51:06 +01:00
{
DYN_error_punt(false, 176, SafeArg() << f.c_str() << r.c_str());
// msg 176: "column %s does not exist in table/view %s"
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
}
void DYN_modify_relation( Global* gbl, const UCHAR** ptr)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* D Y N _ m o d i f y _ r e l a t i o n
*
**************************************
*
* Functional description
* Modify an existing relation
*
**************************************/
MetaName name, field_name;
2001-05-23 15:26:42 +02:00
thread_db* tdbb = JRD_get_thread_data();
Database* dbb = tdbb->getDatabase();
2001-05-23 15:26:42 +02:00
GET_STRING(ptr, name);
jrd_req* request = CMP_find_request(tdbb, drq_m_relation, DYN_REQUESTS);
bool found = false;
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
try {
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
REL IN RDB$RELATIONS WITH REL.RDB$RELATION_NAME EQ name.c_str()
2001-05-23 15:26:42 +02:00
2006-07-09 07:08:23 +02:00
if (!DYN_REQUEST(drq_m_relation))
DYN_REQUEST(drq_m_relation) = request;
2001-05-23 15:26:42 +02:00
if (!REL.RDB$VIEW_BLR.NULL)
DYN_error_punt(false, 177);
2008-12-18 11:57:12 +01:00
DdlNode::executeDdlTrigger(tdbb, gbl->gbl_transaction, DdlNode::DTW_BEFORE,
DDL_TRIGGER_ALTER_TABLE, name, gbl->sqlText);
found = true;
2001-05-23 15:26:42 +02:00
MODIFY REL USING
UCHAR verb;
2003-11-08 17:40:17 +01:00
while ((verb = *(*ptr)++) != isc_dyn_end)
2009-01-20 09:33:59 +01:00
switch (verb)
{
2003-11-08 17:40:17 +01:00
case isc_dyn_system_flag:
2001-05-23 15:26:42 +02:00
REL.RDB$SYSTEM_FLAG = DYN_get_number(ptr);
REL.RDB$SYSTEM_FLAG.NULL = FALSE;
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_security_class:
2001-05-23 15:26:42 +02:00
if (GET_STRING(ptr, REL.RDB$SECURITY_CLASS))
REL.RDB$SECURITY_CLASS.NULL = FALSE;
else
REL.RDB$SECURITY_CLASS.NULL = TRUE;
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_rel_ext_file:
2009-11-25 05:06:48 +01:00
if (REL.RDB$EXTERNAL_FILE.NULL)
{
DYN_rundown_request(request, -1);
DYN_error_punt(false, 97);
2009-11-21 08:38:05 +01:00
// msg 97: "add EXTERNAL FILE not allowed"
2001-05-23 15:26:42 +02:00
}
2009-11-25 05:06:48 +01:00
if (!GET_STRING(ptr, REL.RDB$EXTERNAL_FILE))
{
DYN_rundown_request(request, -1);
DYN_error_punt(false, 98);
2009-11-21 08:38:05 +01:00
// msg 98: "drop EXTERNAL FILE not allowed"
2001-05-23 15:26:42 +02:00
}
break;
default:
--(*ptr);
DYN_execute(gbl, ptr, &name, &field_name, NULL, NULL, NULL);
2001-05-23 15:26:42 +02:00
}
END_MODIFY;
END_FOR;
if (!DYN_REQUEST(drq_m_relation))
DYN_REQUEST(drq_m_relation) = request;
} // try
2009-11-25 05:06:48 +01:00
catch (const Exception& ex)
{
stuff_exception(tdbb->tdbb_status_vector, ex);
DYN_rundown_request(request, -1);
DYN_error_punt(true, 99);
2009-11-21 08:38:05 +01:00
// msg 99: "MODIFY RDB$RELATIONS failed"
2001-12-24 03:51:06 +01:00
}
if (found)
{
DdlNode::executeDdlTrigger(tdbb, gbl->gbl_transaction, DdlNode::DTW_AFTER,
DDL_TRIGGER_ALTER_TABLE, name, gbl->sqlText);
}
else
2001-12-24 03:51:06 +01:00
{
DYN_error_punt(false, 101);
2009-11-21 08:38:05 +01:00
// msg 101: "Relation field not found"
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
}
void DYN_modify_view( Global* gbl, const UCHAR** ptr)
{
/**************************************
*
* D Y N _ m o d i f y _ v i e w
*
**************************************
*
* Functional description
* Execute a dynamic ddl statement.
*
**************************************/
thread_db* tdbb = JRD_get_thread_data();
Database* dbb = tdbb->getDatabase();
MetaName view_name;
GET_STRING(ptr, view_name);
jrd_req* request = NULL;
bool found = false;
try {
request = CMP_find_request(tdbb, drq_m_view, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
REL IN RDB$RELATIONS
WITH REL.RDB$RELATION_NAME EQ view_name.c_str()
AND REL.RDB$VIEW_BLR NOT MISSING
2006-07-09 07:08:23 +02:00
if (!DYN_REQUEST(drq_m_view))
DYN_REQUEST(drq_m_view) = request;
found = true;
DdlNode::executeDdlTrigger(tdbb, gbl->gbl_transaction, DdlNode::DTW_BEFORE,
DDL_TRIGGER_ALTER_VIEW, view_name, gbl->sqlText);
MODIFY REL
2009-12-17 01:38:55 +01:00
REL.RDB$SYSTEM_FLAG = 0;
REL.RDB$SYSTEM_FLAG.NULL = FALSE;
REL.RDB$VIEW_BLR.NULL = TRUE;
REL.RDB$VIEW_SOURCE.NULL = TRUE;
2009-12-17 01:38:55 +01:00
jrd_req* request2 = NULL;
2009-12-17 01:38:55 +01:00
FOR (REQUEST_HANDLE request2 TRANSACTION_HANDLE gbl->gbl_transaction)
VR IN RDB$VIEW_RELATIONS
WITH VR.RDB$VIEW_NAME EQ view_name.c_str()
2009-12-17 01:38:55 +01:00
ERASE VR;
END_FOR;
2009-12-17 01:38:55 +01:00
CMP_release(tdbb, request2);
2008-12-18 11:57:12 +01:00
2009-12-17 01:38:55 +01:00
request2 = NULL;
2009-12-17 01:38:55 +01:00
FOR (REQUEST_HANDLE request2 TRANSACTION_HANDLE gbl->gbl_transaction)
TRG IN RDB$TRIGGERS
WITH TRG.RDB$RELATION_NAME EQ view_name.c_str() AND
TRG.RDB$SYSTEM_FLAG EQ fb_sysflag_view_check
2009-12-17 01:38:55 +01:00
ERASE TRG;
END_FOR
2009-12-17 01:38:55 +01:00
CMP_release(tdbb, request2);
UCHAR verb;
2003-11-08 17:40:17 +01:00
while ((verb = *(*ptr)++) != isc_dyn_end)
2009-12-17 01:38:55 +01:00
{
switch (verb)
{
2003-11-08 17:40:17 +01:00
case isc_dyn_system_flag:
REL.RDB$SYSTEM_FLAG = DYN_get_number(ptr);
REL.RDB$SYSTEM_FLAG.NULL = FALSE;
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_view_blr:
if (DYN_put_blr_blob(gbl, ptr, &REL.RDB$VIEW_BLR))
REL.RDB$VIEW_BLR.NULL = FALSE;
else
REL.RDB$VIEW_BLR.NULL = TRUE;
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_view_source:
if (DYN_put_text_blob(gbl, ptr, &REL.RDB$VIEW_SOURCE))
REL.RDB$VIEW_SOURCE.NULL = FALSE;
else
REL.RDB$VIEW_SOURCE.NULL = TRUE;
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_security_class:
GET_STRING(ptr, REL.RDB$SECURITY_CLASS);
REL.RDB$SECURITY_CLASS.NULL = FALSE;
break;
2008-12-18 11:57:12 +01:00
default:
--(*ptr);
MetaTmp(REL.RDB$RELATION_NAME)
DYN_execute(gbl, ptr, &tmp, NULL, NULL, NULL, NULL);
}
2009-12-17 01:38:55 +01:00
}
END_MODIFY;
END_FOR;
if (!DYN_REQUEST(drq_m_view))
DYN_REQUEST(drq_m_view) = request;
} // try
2009-11-25 05:06:48 +01:00
catch (const Exception& ex)
{
stuff_exception(tdbb->tdbb_status_vector, ex);
DYN_rundown_request(request, -1);
DYN_error_punt(true, 99);
2009-11-21 08:38:05 +01:00
// msg 99: "MODIFY RDB$RELATIONS failed"
}
if (found)
{
DdlNode::executeDdlTrigger(tdbb, gbl->gbl_transaction, DdlNode::DTW_AFTER,
DDL_TRIGGER_ALTER_VIEW, view_name, gbl->sqlText);
}
else
{
DYN_error_punt(false, 54, view_name.c_str());
2009-11-21 08:38:05 +01:00
// msg 54: "View %s not found"
}
}
static void change_backup_mode( Global* gbl, UCHAR verb)
{
/**************************************
*
* c h a n g e _ b a c k u p _ m o d e
*
**************************************
*
* Functional description
* Drop backup difference file for the database,
* begin or end backup
*
**************************************/
bool invalid_state = false;
thread_db* tdbb = JRD_get_thread_data();
Database* dbb = tdbb->getDatabase();
if (!tdbb->getAttachment()->locksmith())
{
ERR_post(Arg::Gds(isc_adm_task_denied));
}
jrd_req* request = CMP_find_request(tdbb, drq_d_difference, DYN_REQUESTS);
bool found = false;
try {
2009-11-25 05:06:48 +01:00
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
X IN RDB$FILES
2009-11-25 05:06:48 +01:00
if (X.RDB$FILE_FLAGS & FILE_difference)
2009-01-20 09:33:59 +01:00
{
2009-11-25 05:06:48 +01:00
found = true;
switch (verb)
{
case isc_dyn_drop_difference:
ERASE X;
break;
case isc_dyn_begin_backup:
if (X.RDB$FILE_FLAGS & FILE_backing_up) {
invalid_state = true;
}
2009-11-25 05:06:48 +01:00
else
{
MODIFY X USING
2009-11-25 05:06:48 +01:00
X.RDB$FILE_FLAGS |= FILE_backing_up;
END_MODIFY;
}
2009-11-25 05:06:48 +01:00
break;
case isc_dyn_end_backup:
if (X.RDB$FILE_FLAGS & FILE_backing_up)
{
if (X.RDB$FILE_NAME.NULL) {
ERASE X;
}
else
{
MODIFY X USING
X.RDB$FILE_FLAGS &= ~FILE_backing_up;
END_MODIFY;
}
}
else {
invalid_state = true;
}
break;
}
}
2009-11-25 05:06:48 +01:00
END_FOR;
2009-11-26 01:20:59 +01:00
if (!DYN_REQUEST(drq_d_difference))
2009-11-25 05:06:48 +01:00
DYN_REQUEST(drq_d_difference) = request;
}
2009-11-25 05:06:48 +01:00
catch (const Exception& ex)
{
stuff_exception(tdbb->tdbb_status_vector, ex);
2008-12-18 11:57:12 +01:00
DYN_rundown_request(request, drq_d_difference);
DYN_error_punt(true, 63);
2009-11-21 08:38:05 +01:00
// msg 63: ERASE RDB$FILE failed
}
2008-12-18 11:57:12 +01:00
2009-11-25 05:06:48 +01:00
if (!found && verb == isc_dyn_begin_backup)
{
2008-04-23 10:01:36 +02:00
try {
2009-11-14 10:29:08 +01:00
request = CMP_find_request(tdbb, drq_s2_difference, DYN_REQUESTS);
2008-04-23 10:01:36 +02:00
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
2008-12-18 11:57:12 +01:00
X IN RDB$FILES
2008-04-23 10:01:36 +02:00
X.RDB$FILE_NAME.NULL = TRUE;
X.RDB$FILE_FLAGS.NULL = FALSE;
X.RDB$FILE_FLAGS = FILE_difference | FILE_backing_up;
X.RDB$FILE_START = 0;
X.RDB$FILE_START.NULL = FALSE;
X.RDB$FILE_LENGTH.NULL = TRUE;
X.RDB$SHADOW_NUMBER.NULL = TRUE;
END_STORE;
2008-12-18 11:57:12 +01:00
2008-04-23 10:01:36 +02:00
found = true;
2009-11-14 10:29:08 +01:00
if (!DYN_REQUEST(drq_s2_difference))
2008-04-23 10:01:36 +02:00
{
2009-11-14 10:29:08 +01:00
DYN_REQUEST(drq_s2_difference) = request;
2008-12-18 11:57:12 +01:00
}
2008-04-23 10:01:36 +02:00
}
2009-11-25 05:06:48 +01:00
catch (const Exception& ex)
{
stuff_exception(tdbb->tdbb_status_vector, ex);
2009-11-14 10:29:08 +01:00
DYN_rundown_request(request, drq_s2_difference);
2008-04-23 10:01:36 +02:00
DYN_error_punt(true, 150);
2009-11-21 08:38:05 +01:00
// msg 150: STORE RDB$FILES failed
2008-04-23 10:01:36 +02:00
}
}
2008-12-18 11:57:12 +01:00
2009-11-25 05:06:48 +01:00
if (invalid_state)
{
DYN_error_punt(false, verb == isc_dyn_begin_backup ? 217 : 218);
2009-11-21 08:38:05 +01:00
// msg 217: "Database is already in the physical backup mode"
// msg 218: "Database is not in the physical backup mode"
}
if (!found)
{
DYN_error_punt(false, verb == isc_dyn_end_backup ? 218 : 215);
2009-11-21 08:38:05 +01:00
// msg 218: "Database is not in the physical backup mode"
// msg 215: "Difference file is not defined"
}
}
static void modify_lfield_position(thread_db* tdbb,
Global* gbl,
const MetaName& relation_name,
const MetaName& field_name,
2001-05-23 15:26:42 +02:00
USHORT new_position,
USHORT existing_position)
{
/***********************************************************
*
* m o d i f y _ l f i e l d _ p o s i t i o n
***********************************************************
*
* Functional Description:
2008-12-18 11:57:12 +01:00
* Alters the position of a field with respect to the
2001-05-23 15:26:42 +02:00
* other fields in the relation. This will only affect
* the order in which the fields will be returned when either
* viewing the relation or performing select * from the relation.
*
* The rules of engagement are as follows:
* if new_position > original position
2008-12-18 11:57:12 +01:00
* increase RDB$FIELD_POSITION for all fields with RDB$FIELD_POSITION
2001-05-23 15:26:42 +02:00
* between the new_position and existing position of the field
* then update the position of the field being altered.
* just update the position
*
* if new_position < original position
2008-12-18 11:57:12 +01:00
* decrease RDB$FIELD_POSITION for all fields with RDB$FIELD_POSITION
2001-05-23 15:26:42 +02:00
* between the new_position and existing position of the field
* then update the position of the field being altered.
*
* if new_position == original_position -- no_op
*
***********************************************************/
jrd_req* request = NULL;
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
try {
2009-11-21 08:38:05 +01:00
// Find the position of the last field in the relation
SLONG max_position = -1;
DYN_UTIL_generate_field_position(tdbb, gbl, relation_name, &max_position);
2001-05-23 15:26:42 +02:00
2009-11-21 08:38:05 +01:00
// If the existing position of the field is less than the new position of
// the field, subtract 1 to move the fields to their new positions otherwise,
// increase the value in RDB$FIELD_POSITION by one
2001-05-23 15:26:42 +02:00
bool move_down = false;
2001-05-23 15:26:42 +02:00
if (existing_position < new_position)
move_down = true;
2001-05-23 15:26:42 +02:00
2009-11-21 08:38:05 +01:00
// Retrieve the records for the fields which have a position between the
// existing field position and the new field position
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
2008-12-18 11:57:12 +01:00
FLD IN RDB$RELATION_FIELDS
2006-07-09 07:08:23 +02:00
WITH FLD.RDB$RELATION_NAME EQ relation_name.c_str() AND
FLD.RDB$FIELD_POSITION >= MIN(new_position, existing_position) AND
FLD.RDB$FIELD_POSITION <= MAX(new_position, existing_position)
2001-05-23 15:26:42 +02:00
MODIFY FLD USING
2009-11-21 08:38:05 +01:00
// If the field is the one we want, change the position, otherwise
// increase the value of RDB$FIELD_POSITION
2009-11-25 05:06:48 +01:00
if (field_name == FLD.RDB$FIELD_NAME)
{
2001-05-23 15:26:42 +02:00
if (new_position > max_position)
2009-11-22 01:09:30 +01:00
{
2009-11-21 08:38:05 +01:00
// This prevents gaps in the position sequence of the fields
2001-05-23 15:26:42 +02:00
FLD.RDB$FIELD_POSITION = max_position;
2009-11-22 01:09:30 +01:00
}
2001-05-23 15:26:42 +02:00
else
FLD.RDB$FIELD_POSITION = new_position;
}
2009-11-25 05:06:48 +01:00
else
{
2001-05-23 15:26:42 +02:00
if (move_down)
FLD.RDB$FIELD_POSITION = FLD.RDB$FIELD_POSITION - 1;
else
FLD.RDB$FIELD_POSITION = FLD.RDB$FIELD_POSITION + 1;
}
FLD.RDB$FIELD_POSITION.NULL = FALSE;
END_MODIFY;
END_FOR;
2004-08-26 13:07:57 +02:00
CMP_release(tdbb, request);
2001-05-23 15:26:42 +02:00
request = NULL;
2009-11-21 08:38:05 +01:00
// Once the field position has been changed, make sure that there are no
// duplicate field positions and no gaps in the position sequence (this can
// not be guaranteed by the query above
2001-05-23 15:26:42 +02:00
USHORT new_pos = 0;
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
FLD IN RDB$RELATION_FIELDS WITH FLD.RDB$RELATION_NAME EQ relation_name.c_str()
2001-05-23 15:26:42 +02:00
SORTED BY ASCENDING FLD.RDB$FIELD_POSITION
2009-11-25 05:06:48 +01:00
if (FLD.RDB$FIELD_POSITION != new_pos)
{
2001-05-23 15:26:42 +02:00
MODIFY FLD USING
FLD.RDB$FIELD_POSITION = new_pos;
END_MODIFY;
}
new_pos += 1;
END_FOR;
2004-08-26 13:07:57 +02:00
CMP_release(tdbb, request);
2001-12-24 03:51:06 +01:00
}
2009-11-25 05:06:48 +01:00
catch (const Exception& ex)
{
stuff_exception(tdbb->tdbb_status_vector, ex);
DYN_error_punt(true, 95);
2009-11-21 08:38:05 +01:00
// msg 95: "MODIFY RDB$RELATION_FIELDS failed"
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
}
static bool check_view_dependency(thread_db* tdbb,
Global* gbl,
const MetaName& relation_name,
const MetaName& field_name)
2001-05-23 15:26:42 +02:00
{
/***********************************************************
*
* c h e c k _ v i e w _ d e p e n d e n c y
***********************************************************
*
* Functional Description:
* Checks to see if the given field is referenced in a view. If the field
* is referenced in a view, return true, else return false
* CVC: The function never has a chance to return true because it punts.
2001-05-23 15:26:42 +02:00
*
***********************************************************/
jrd_req* request = NULL;
bool retval = false;
MetaName view_name;
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
FIRST 1
X IN RDB$RELATION_FIELDS CROSS Y IN RDB$RELATION_FIELDS CROSS
Z IN RDB$VIEW_RELATIONS WITH
X.RDB$RELATION_NAME EQ relation_name.c_str() AND
X.RDB$FIELD_NAME EQ field_name.c_str() AND
2001-05-23 15:26:42 +02:00
X.RDB$FIELD_NAME EQ Y.RDB$BASE_FIELD AND
X.RDB$FIELD_SOURCE EQ Y.RDB$FIELD_SOURCE AND
Y.RDB$RELATION_NAME EQ Z.RDB$VIEW_NAME AND
X.RDB$RELATION_NAME EQ Z.RDB$RELATION_NAME AND
2008-12-18 11:57:12 +01:00
Y.RDB$VIEW_CONTEXT EQ Z.RDB$VIEW_CONTEXT
2006-07-09 07:08:23 +02:00
retval = true;
2001-05-23 15:26:42 +02:00
view_name = Z.RDB$VIEW_NAME;
END_FOR;
2004-08-26 13:07:57 +02:00
CMP_release(tdbb, request);
2001-05-23 15:26:42 +02:00
if (retval)
2009-11-22 01:09:30 +01:00
{
2008-12-18 11:57:12 +01:00
DYN_error_punt(false, 206, SafeArg() << field_name.c_str() <<
relation_name.c_str() << view_name.c_str());
2009-11-21 08:38:05 +01:00
// msg 206: Column %s from table %s is referenced in %s.
2009-11-22 01:09:30 +01:00
}
2001-05-23 15:26:42 +02:00
return retval;
}
static bool check_sptrig_dependency(thread_db* tdbb,
Global* gbl,
const MetaName& relation_name,
const MetaName& field_name)
2001-05-23 15:26:42 +02:00
{
/***********************************************************
*
* c h e c k _ s p t r i g _ d e p e n d e n c y
***********************************************************
*
* Functional Description:
* Checks to see if the given field is referenced in a stored procedure
2006-07-08 05:45:13 +02:00
* or trigger. If the field is referenced, return true, else return
* false, but true causes the function to punt instead.
2001-05-23 15:26:42 +02:00
***********************************************************/
jrd_req* request = NULL;
bool retval = false;
MetaName dep_name;
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
FIRST 1
DEP IN RDB$DEPENDENCIES WITH
DEP.RDB$DEPENDED_ON_NAME EQ relation_name.c_str() AND
2008-12-18 11:57:12 +01:00
DEP.RDB$FIELD_NAME EQ field_name.c_str()
2006-07-09 07:08:23 +02:00
retval = true;
2001-05-23 15:26:42 +02:00
dep_name = DEP.RDB$DEPENDENT_NAME;
END_FOR;
2004-08-26 13:07:57 +02:00
CMP_release(tdbb, request);
2001-05-23 15:26:42 +02:00
if (retval)
2009-11-22 01:09:30 +01:00
{
DYN_error_punt(false, 206, SafeArg() << field_name.c_str() <<
relation_name.c_str() << dep_name.c_str());
2009-11-21 08:38:05 +01:00
// msg 206: Column %s from table %s is referenced in %s.
2009-11-22 01:09:30 +01:00
}
2001-05-23 15:26:42 +02:00
return retval;
}
2008-07-06 18:42:52 +02:00
static void modify_lfield_index(thread_db* tdbb,
Global* gbl,
const MetaName& relation_name,
const MetaName& field_name,
const MetaName& new_fld_name)
2001-05-23 15:26:42 +02:00
{
/***********************************************************
*
* m o d i f y _ l f i e l d _ i n d e x
***********************************************************
*
* Functional Description:
* Updates the field names in an index and forces the index to be rebuilt
* with the new field names
*
***********************************************************/
jrd_req* request = NULL;
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
IDX IN RDB$INDICES CROSS IDXS IN RDB$INDEX_SEGMENTS WITH
IDX.RDB$INDEX_NAME EQ IDXS.RDB$INDEX_NAME AND
IDX.RDB$RELATION_NAME EQ relation_name.c_str() AND
IDXS.RDB$FIELD_NAME EQ field_name.c_str()
2009-11-21 08:38:05 +01:00
// Change the name of the field in the index
2001-05-23 15:26:42 +02:00
MODIFY IDXS USING
2008-02-03 11:41:44 +01:00
memcpy(IDXS.RDB$FIELD_NAME, new_fld_name.c_str(), sizeof(IDXS.RDB$FIELD_NAME));
2001-05-23 15:26:42 +02:00
END_MODIFY;
2009-11-21 08:38:05 +01:00
// Set the index name to itself to tell the index to rebuild
2001-05-23 15:26:42 +02:00
MODIFY IDX USING
// This is to fool both gpre and gcc.
char* p = IDX.RDB$INDEX_NAME;
p[MAX_SQL_IDENTIFIER_LEN] = 0;
2001-05-23 15:26:42 +02:00
END_MODIFY;
END_FOR;
2004-08-26 13:07:57 +02:00
CMP_release(tdbb, request);
2001-05-23 15:26:42 +02:00
}
2008-07-06 18:42:52 +02:00
static bool field_exists(thread_db* tdbb,
Global* gbl,
const MetaName& relation_name,
const MetaName& field_name)
2001-05-23 15:26:42 +02:00
{
/***********************************************************
*
* f i e l d _ e x i s t s
***********************************************************
*
* Functional Description:
* Checks to see if the given field already exists in a relation
***********************************************************/
jrd_req* request = NULL;
bool retval = false;
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
FLD IN RDB$RELATION_FIELDS WITH
FLD.RDB$RELATION_NAME EQ relation_name.c_str() AND
FLD.RDB$FIELD_NAME EQ field_name.c_str()
2006-07-09 07:08:23 +02:00
retval = true;
2001-05-23 15:26:42 +02:00
END_FOR;
2004-08-26 13:07:57 +02:00
CMP_release(tdbb, request);
2001-05-23 15:26:42 +02:00
return retval;
}
2009-11-25 05:06:48 +01:00
static bool domain_exists(thread_db* tdbb, Global* gbl, const MetaName& field_name)
2001-05-23 15:26:42 +02:00
{
/***********************************************************
*
* d o m a i n _ e x i s t s
***********************************************************
*
* Functional Description:
* Checks to see if the given field already exists in a relation
***********************************************************/
jrd_req* request = NULL;
bool retval = false;
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
FLD IN RDB$FIELDS WITH FLD.RDB$FIELD_NAME EQ field_name.c_str()
2006-07-09 07:08:23 +02:00
retval = true;
2001-05-23 15:26:42 +02:00
END_FOR;
2004-08-26 13:07:57 +02:00
CMP_release(tdbb, request);
2001-05-23 15:26:42 +02:00
return retval;
}
2009-11-25 05:06:48 +01:00
void DYN_modify_sql_field(Global* gbl, const UCHAR** ptr, const MetaName* relation_name)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
2002-06-30 10:46:51 +02:00
* D Y N _ m o d i f y _ s q l _ f i e l d
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
2008-12-18 11:57:12 +01:00
* Execute a dynamic ddl statement
2001-05-23 15:26:42 +02:00
* to modify the datatype of a field.
*
* If there are dependencies on the field, abort the operation
2008-12-18 11:57:12 +01:00
* unless the dependency is an index. In this case, rebuild the
2001-05-23 15:26:42 +02:00
* index once the operation has completed.
*
* If the original datatype of the field was a domain:
* if the new type is a domain, just make the change to the new domain
* if it exists
*
* if the new type is a base type, just make the change
*
* If the original datatype of the field was a base type:
* if the new type is a base type, just make the change
*
* if the new type is a domain, make the change to the field
* definition and remove the entry for RDB$FIELD_SOURCE from the original
* field. In other words ... clean up after ourselves
*
* The following conversions are not allowed:
* Blob to anything
* Array to anything
* Date to anything
* Char to any numeric
* Varchar to any numeric
* Anything to Blob
* Anything to Array
*
* The following operations return a warning
* Decreasing the length of a char (varchar) field
*
2002-06-30 10:46:51 +02:00
* CVC: This is a misleading comment. There's no code that
* produces a warning. This condition raises an error, too.
*
2001-05-23 15:26:42 +02:00
**************************************/
thread_db* tdbb = JRD_get_thread_data();
2008-12-18 11:57:12 +01:00
dyn_fld orig_fld, new_fld, dom_fld;
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
try {
GET_STRING(ptr, orig_fld.dyn_fld_name);
2001-05-23 15:26:42 +02:00
// Check to see if the field being altered is involved in any type of dependency.
// If there is a dependency, call DYN_error_punt (inside the function).
fb_assert(relation_name);
2008-01-16 09:46:02 +01:00
// ASF: check disabled to allow change of field type to be used
// with TYPE OF COLUMN table.column feature.
2009-04-28 15:48:18 +02:00
//check_sptrig_dependency(tdbb, gbl, *relation_name,
2008-01-16 09:46:02 +01:00
// orig_fld.dyn_fld_name);
2001-05-23 15:26:42 +02:00
jrd_req* request = NULL;
jrd_req* first_request = NULL;
bool found = false;
2008-12-18 11:57:12 +01:00
bool dtype, scale, prec, subtype, charlen, collation, fldlen, nullflg, charset;
dtype = scale = prec = subtype = charlen = collation = fldlen = nullflg = charset = false;
2008-01-16 09:46:02 +01:00
int field_adjusted_count = 0;
2008-01-16 09:46:02 +01:00
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
2008-01-16 09:46:02 +01:00
RFR IN RDB$RELATION_FIELDS CROSS
REL IN RDB$RELATIONS WITH
REL.RDB$RELATION_NAME = RFR.RDB$RELATION_NAME AND
RFR.RDB$RELATION_NAME = relation_name->c_str() AND
RFR.RDB$FIELD_NAME = orig_fld.dyn_fld_name.c_str()
2006-07-09 07:08:23 +02:00
first_request = request;
2001-05-23 15:26:42 +02:00
request = NULL;
found = true;
2008-01-16 09:46:02 +01:00
bool is_view = !REL.RDB$VIEW_BLR.NULL;
bool has_dimensions = false;
bool update_domain = false;
bool domain_has_default = false;
2006-07-08 05:45:13 +02:00
bool domain_is_computed = false;
2008-01-16 09:46:02 +01:00
SSHORT fld_position = 0;
bool fld_position_change = false;
SSHORT view_context = 0;
bool view_context_change = false;
MetaName fld_base_field;
2008-01-16 09:46:02 +01:00
bool fld_base_field_change = false;
bool orig_computed = false;
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
FLD IN RDB$FIELDS WITH FLD.RDB$FIELD_NAME = RFR.RDB$FIELD_SOURCE
2006-07-09 04:41:49 +02:00
// Get information about the original field type. If a conversion
// can not be at any time made between the two datatypes, error.
DSC_make_descriptor(&orig_fld.dyn_dsc,
FLD.RDB$FIELD_TYPE,
FLD.RDB$FIELD_SCALE,
FLD.RDB$FIELD_LENGTH,
FLD.RDB$FIELD_SUB_TYPE,
FLD.RDB$CHARACTER_SET_ID,
FLD.RDB$COLLATION_ID);
2006-07-09 07:08:23 +02:00
orig_fld.dyn_charbytelen = FLD.RDB$FIELD_LENGTH;
orig_fld.dyn_dtype = FLD.RDB$FIELD_TYPE;
orig_fld.dyn_precision = FLD.RDB$FIELD_PRECISION;
orig_fld.dyn_sub_type = FLD.RDB$FIELD_SUB_TYPE;
orig_fld.dyn_charlen = FLD.RDB$CHARACTER_LENGTH;
orig_fld.dyn_collation = FLD.RDB$COLLATION_ID;
orig_fld.dyn_null_flag = FLD.RDB$NULL_FLAG != 0;
orig_fld.dyn_fld_source = RFR.RDB$FIELD_SOURCE;
2008-01-16 09:46:02 +01:00
orig_computed = !FLD.RDB$COMPUTED_BLR.NULL;
2001-05-23 15:26:42 +02:00
// If the original field type is an array, force its blr type to blr_blob
2001-05-23 15:26:42 +02:00
if (FLD.RDB$DIMENSIONS != 0)
2002-06-30 10:46:51 +02:00
{
orig_fld.dyn_dtype = blr_blob;
has_dimensions = true;
2002-06-30 10:46:51 +02:00
}
2008-12-18 11:57:12 +01:00
domain_has_default = !FLD.RDB$DEFAULT_VALUE.NULL;
2006-07-08 05:45:13 +02:00
domain_is_computed = !FLD.RDB$COMPUTED_BLR.NULL;
2001-05-23 15:26:42 +02:00
UCHAR verb;
2009-11-25 05:06:48 +01:00
while ((verb = *(*ptr)++) != isc_dyn_end)
{
2009-01-20 09:33:59 +01:00
switch (verb)
{
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_source:
GET_STRING(ptr, dom_fld.dyn_fld_source);
if (fb_utils::implicit_domain(dom_fld.dyn_fld_source.c_str()))
{
DYN_error_punt(false, 224, SafeArg() << dom_fld.dyn_fld_source.c_str() <<
orig_fld.dyn_fld_name.c_str());
// msg 224: "Cannot use the internal domain %s as new type for field %s".
}
2009-04-28 15:48:18 +02:00
get_domain_type(tdbb, gbl, dom_fld);
update_domain = true;
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_rel_name:
GET_STRING(ptr, new_fld.dyn_rel_name);
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_length:
fldlen = true;
new_fld.dyn_dsc.dsc_length = DYN_get_number(ptr);
2002-06-30 10:46:51 +02:00
if (++field_adjusted_count > 2)
2006-07-09 04:41:49 +02:00
{
DYN_error_punt(false, 149, orig_fld.dyn_fld_name.c_str());
// msg 149: "Only one data type change to the field %s allowed at a time"
2006-07-09 04:41:49 +02:00
}
switch (new_fld.dyn_dtype)
2002-06-30 10:46:51 +02:00
{
case blr_text:
case blr_text2:
case blr_varying:
case blr_varying2:
case blr_cstring:
case blr_cstring2:
new_fld.dyn_charbytelen = new_fld.dyn_dsc.dsc_length;
2002-06-30 10:46:51 +02:00
break;
default:
2008-12-18 11:57:12 +01:00
new_fld.dyn_charbytelen = 0; // It won't be used, anyway.
2002-06-30 10:46:51 +02:00
break;
}
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_type:
dtype = true;
new_fld.dyn_dtype = DYN_get_number(ptr);
2002-06-30 10:46:51 +02:00
if (++field_adjusted_count > 2)
2006-07-09 04:41:49 +02:00
{
DYN_error_punt(false, 149, orig_fld.dyn_fld_name.c_str());
// msg 149: "Only one data type change to the field %s allowed at a time"
2006-07-09 04:41:49 +02:00
}
2001-05-23 15:26:42 +02:00
2009-01-20 09:33:59 +01:00
switch (new_fld.dyn_dtype)
{
2001-05-23 15:26:42 +02:00
case blr_text:
case blr_text2:
case blr_varying:
case blr_varying2:
case blr_cstring:
case blr_cstring2:
if (new_fld.dyn_dsc.dsc_length && !new_fld.dyn_charbytelen)
new_fld.dyn_charbytelen = new_fld.dyn_dsc.dsc_length;
new_fld.dyn_dsc.dsc_length = DSC_string_length (&new_fld.dyn_dsc);
2001-05-23 15:26:42 +02:00
break;
case blr_short:
new_fld.dyn_dsc.dsc_length = 2;
2001-05-23 15:26:42 +02:00
break;
case blr_long:
case blr_float:
new_fld.dyn_dsc.dsc_length = 4;
2001-05-23 15:26:42 +02:00
break;
case blr_int64:
case blr_sql_time:
case blr_sql_date:
case blr_timestamp:
case blr_double:
case blr_d_float:
new_fld.dyn_dsc.dsc_length = 8;
2001-05-23 15:26:42 +02:00
break;
default:
break;
}
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_scale:
scale = true;
new_fld.dyn_dsc.dsc_scale = DYN_get_number(ptr);
2001-05-23 15:26:42 +02:00
break;
case isc_dyn_fld_precision:
prec = true;
new_fld.dyn_precision = DYN_get_number(ptr);
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_sub_type:
subtype = true;
new_fld.dyn_sub_type = DYN_get_number(ptr);
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_char_length:
charlen = true;
new_fld.dyn_charlen = DYN_get_number(ptr);
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_collation:
collation = true;
new_fld.dyn_collation = DYN_get_number(ptr);
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_character_set:
charset = true;
new_fld.dyn_charset = DYN_get_number(ptr);
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_not_null:
nullflg = true;
new_fld.dyn_null_flag = true;
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_dimensions:
new_fld.dyn_dtype = blr_blob;
2001-05-23 15:26:42 +02:00
break;
2008-01-16 09:46:02 +01:00
case isc_dyn_fld_position:
fld_position = DYN_get_number(ptr);
fld_position_change = true;
break;
case isc_dyn_fld_base_fld:
GET_STRING(ptr, fld_base_field);
fld_base_field_change = true;
break;
case isc_dyn_view_context:
view_context = DYN_get_number(ptr);
view_context_change = true;
break;
case isc_dyn_fld_computed_blr:
domain_is_computed = true;
new_fld.dyn_computed_val = *ptr;
DYN_skip_attribute(ptr);
break;
case isc_dyn_fld_computed_source:
new_fld.dyn_computed_src = *ptr;
DYN_skip_attribute(ptr);
break;
case isc_dyn_del_computed:
domain_is_computed = false;
new_fld.dyn_drop_computed = true;
break;
case isc_dyn_del_default:
new_fld.dyn_drop_default = true;
break;
case isc_dyn_fld_default_value:
if (!RFR.RDB$GENERATOR_NAME.NULL)
{
// msg 275: Identity column @1 of table @2 cannot have default value
DYN_error_punt(false, 275,
SafeArg() << orig_fld.dyn_fld_name.c_str() << relation_name->c_str());
}
if (has_dimensions)
{
DYN_error_punt(false, 225, orig_fld.dyn_fld_name.c_str());
// msg 225: "Default value is not allowed for array type in field %s"
}
new_fld.dyn_default_val = *ptr;
DYN_skip_attribute(ptr);
break;
case isc_dyn_fld_default_source:
if (has_dimensions)
{
DYN_error_punt(false, 225, orig_fld.dyn_fld_name.c_str());
// msg 225: "Default value is not allowed for array type in field %s"
}
new_fld.dyn_default_src = *ptr;
DYN_skip_attribute(ptr);
break;
2008-01-16 09:46:02 +01:00
// These should only be defined for BLOB types and should not come through with
// any other types. BLOB types are detected above
2003-11-08 17:40:17 +01:00
case isc_dyn_fld_segment_length:
2001-05-23 15:26:42 +02:00
DYN_get_number(ptr);
break;
default:
--(*ptr);
MetaTmp(RFR.RDB$FIELD_SOURCE)
DYN_execute(gbl, ptr, relation_name, &tmp, NULL, NULL, NULL);
2001-05-23 15:26:42 +02:00
}
}
2008-01-16 09:46:02 +01:00
if (fld_base_field_change && view_context_change)
{
fb_assert(is_view);
if (fld_base_field.hasData())
{
char field_name[MAX_SQL_IDENTIFIER_SIZE];
DYN_UTIL_find_field_source(tdbb, gbl, RFR.RDB$RELATION_NAME, view_context,
fld_base_field.c_str(), field_name);
dom_fld.dyn_fld_source = field_name;
update_domain = true;
}
else
DYN_UTIL_generate_field_name(tdbb, gbl, new_fld.dyn_fld_source);
}
END_FOR; // FLD in RDB$FIELDS
2004-08-26 13:07:57 +02:00
CMP_release(tdbb, request);
2001-05-23 15:26:42 +02:00
request = NULL;
2008-01-16 09:46:02 +01:00
if (!is_view &&
((new_fld.dyn_computed_val && !orig_computed) ||
2008-12-18 11:57:12 +01:00
(!new_fld.dyn_computed_val && orig_computed)))
2008-01-16 09:46:02 +01:00
{
// Cannot add or remove COMPUTED from column @1
2008-12-18 11:57:12 +01:00
DYN_error_punt(false, 249, SafeArg() << orig_fld.dyn_fld_name.c_str());
2008-01-16 09:46:02 +01:00
}
const bool sourceIsInternalDomain =
2008-01-16 09:46:02 +01:00
fb_utils::implicit_domain(orig_fld.dyn_fld_source.c_str()) && RFR.RDB$BASE_FIELD.NULL;
const bool changeComputed = new_fld.dyn_computed_val || new_fld.dyn_drop_computed;
// Now that we have all of the information needed, let's check to see
2008-01-16 09:46:02 +01:00
// if the field type can be modified
2001-05-23 15:26:42 +02:00
2008-01-16 09:46:02 +01:00
if (update_domain)
{
// a1. Internal domain -> domain.
// a2. Domain -> domain.
2008-12-18 11:57:12 +01:00
2002-06-30 10:46:51 +02:00
/* CVC: Since get_domain_type() called above already called DSC_make_descriptor,
there's no point in calling it again, since it will increment AGAIN the length
of varchar fields! This bug detected thanks to new check field dyn_charbytelen.
DSC_make_descriptor(&dom_fld.dyn_dsc,
dom_fld.dyn_dtype,
dom_fld.dyn_dsc.dsc_scale,
dom_fld.dyn_dsc.dsc_length,
dom_fld.dyn_sub_type,
dom_fld.dyn_charset, dom_fld.dyn_collation);
2002-06-30 10:46:51 +02:00
*/
2001-05-23 15:26:42 +02:00
2008-01-16 09:46:02 +01:00
if (!domain_is_computed && !is_view)
{
if (!RFR.RDB$GENERATOR_NAME.NULL)
{
if (!dom_fld.dyn_dsc.isExact() || dom_fld.dyn_dsc.dsc_scale != 0)
{
// Identity column @1 of table @2 must be exact numeric with zero scale.
DYN_error_punt(false, 273,
SafeArg() << orig_fld.dyn_fld_name.c_str() << relation_name->c_str());
}
}
2008-01-16 09:46:02 +01:00
const ULONG retval = check_update_fld_type(orig_fld, dom_fld);
if (retval != FB_SUCCESS)
modify_err_punt(tdbb, retval, orig_fld, dom_fld);
}
2001-05-23 15:26:42 +02:00
// If the original definition was a base field type, remove the entries from RDB$FIELDS
if (sourceIsInternalDomain)
{
// a1. Internal domain -> domain.
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
FLD IN RDB$FIELDS
WITH FLD.RDB$FIELD_NAME = RFR.RDB$FIELD_SOURCE
2008-12-18 11:57:12 +01:00
2006-07-09 07:08:23 +02:00
ERASE FLD;
2001-05-23 15:26:42 +02:00
END_FOR;
2004-08-26 13:07:57 +02:00
CMP_release(tdbb, request);
2001-05-23 15:26:42 +02:00
request = NULL;
}
request = first_request;
MODIFY RFR USING
strcpy(RFR.RDB$FIELD_SOURCE, dom_fld.dyn_fld_source.c_str());
2001-05-23 15:26:42 +02:00
RFR.RDB$FIELD_SOURCE.NULL = FALSE;
if (domain_is_computed)
{
RFR.RDB$UPDATE_FLAG.NULL = FALSE;
RFR.RDB$UPDATE_FLAG = 1;
}
RFR.RDB$COLLATION_ID.NULL = TRUE; // CORE-2426
2001-05-23 15:26:42 +02:00
END_MODIFY;
first_request = request;
request = NULL;
2008-01-16 09:46:02 +01:00
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
PRM IN RDB$PROCEDURE_PARAMETERS
WITH PRM.RDB$RELATION_NAME = relation_name->c_str() AND
PRM.RDB$FIELD_NAME = orig_fld.dyn_fld_name.c_str()
2008-01-16 09:46:02 +01:00
MODIFY PRM USING
strcpy(PRM.RDB$FIELD_SOURCE, dom_fld.dyn_fld_source.c_str());
END_MODIFY;
END_FOR;
2008-01-16 09:46:02 +01:00
CMP_release(tdbb, request);
request = NULL;
2001-05-23 15:26:42 +02:00
}
2008-01-16 09:46:02 +01:00
else
{
// b1. Domain -> internal domain.
// b2. Internal domain -> internal domain.
const UCHAR* defVal = new_fld.dyn_default_val;
const UCHAR* defSrc = new_fld.dyn_default_src;
const bool dropDefault = new_fld.dyn_drop_default;
const bool changeDefault = defVal || defSrc || dropDefault;
2008-01-16 09:46:02 +01:00
// If we are altering only the default, we need the old field settings.
if (changeDefault && !new_fld.dyn_dsc.dsc_dtype)
2006-07-08 06:10:06 +02:00
{
new_fld = orig_fld;
2006-07-08 06:10:06 +02:00
// We already called DSC_make_descriptor on orig_fld, so fix new_fld.
switch (new_fld.dyn_dtype)
{
case blr_text:
case blr_varying:
case blr_cstring:
new_fld.dyn_dsc.dsc_length = DSC_string_length(&orig_fld.dyn_dsc);
break;
}
}
DSC_make_descriptor(&new_fld.dyn_dsc,
new_fld.dyn_dtype,
new_fld.dyn_dsc.dsc_scale,
new_fld.dyn_dsc.dsc_length,
new_fld.dyn_sub_type,
new_fld.dyn_charset, new_fld.dyn_collation);
2008-01-16 09:46:02 +01:00
if (!changeComputed && !orig_computed && !is_view)
{
const ULONG retval = check_update_fld_type(orig_fld, new_fld);
if (retval != FB_SUCCESS)
modify_err_punt(tdbb, retval, orig_fld, new_fld);
if (!RFR.RDB$GENERATOR_NAME.NULL)
{
if (!new_fld.dyn_dsc.isExact() || new_fld.dyn_dsc.dsc_scale != 0)
{
// Identity column @1 of table @2 must be exact numeric with zero scale.
DYN_error_punt(false, 273,
SafeArg() << orig_fld.dyn_fld_name.c_str() << relation_name->c_str());
}
}
2008-01-16 09:46:02 +01:00
}
2001-05-23 15:26:42 +02:00
// Check to see if the original data type for the field was based on a domain. If it
// was (and now it isn't), remove the domain information and replace it with a generated
// field name for RDB$FIELDS
2001-05-23 15:26:42 +02:00
if (!changeDefault && !sourceIsInternalDomain)
{
// b1. Domain -> internal domain. Not for changing DEFAULT value.
2008-01-16 09:46:02 +01:00
2001-05-23 15:26:42 +02:00
request = first_request;
MODIFY RFR USING
2008-01-16 09:46:02 +01:00
DYN_UTIL_generate_field_name(tdbb, gbl, RFR.RDB$FIELD_SOURCE);
new_fld.dyn_fld_source = RFR.RDB$FIELD_SOURCE;
2001-05-23 15:26:42 +02:00
END_MODIFY;
first_request = request;
request = NULL;
2001-05-23 15:26:42 +02:00
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
2008-12-18 11:57:12 +01:00
FLD IN RDB$FIELDS
2006-07-09 07:08:23 +02:00
FLD.RDB$SYSTEM_FLAG = 0;
FLD.RDB$SYSTEM_FLAG.NULL = FALSE;
2001-05-23 15:26:42 +02:00
FLD.RDB$FIELD_SCALE.NULL = TRUE;
FLD.RDB$FIELD_PRECISION.NULL = TRUE;
FLD.RDB$FIELD_SUB_TYPE.NULL = TRUE;
FLD.RDB$SEGMENT_LENGTH.NULL = TRUE;
FLD.RDB$COMPUTED_BLR.NULL = TRUE;
FLD.RDB$COMPUTED_SOURCE.NULL = TRUE;
FLD.RDB$DEFAULT_VALUE.NULL = TRUE;
FLD.RDB$DEFAULT_SOURCE.NULL = TRUE;
FLD.RDB$VALIDATION_BLR.NULL = TRUE;
FLD.RDB$VALIDATION_SOURCE.NULL = TRUE;
FLD.RDB$NULL_FLAG.NULL = TRUE;
FLD.RDB$EDIT_STRING.NULL = TRUE;
FLD.RDB$DIMENSIONS.NULL = TRUE;
FLD.RDB$CHARACTER_LENGTH.NULL = TRUE;
FLD.RDB$CHARACTER_SET_ID.NULL = TRUE;
FLD.RDB$COLLATION_ID.NULL = TRUE;
2009-11-25 05:06:48 +01:00
if (dtype)
{
FLD.RDB$FIELD_TYPE = new_fld.dyn_dtype;
2001-05-23 15:26:42 +02:00
FLD.RDB$FIELD_TYPE.NULL = FALSE;
}
2009-11-25 05:06:48 +01:00
if (scale)
{
FLD.RDB$FIELD_SCALE = new_fld.dyn_dsc.dsc_scale;
2001-05-23 15:26:42 +02:00
FLD.RDB$FIELD_SCALE.NULL = FALSE;
}
2009-11-25 05:06:48 +01:00
if (prec)
{
FLD.RDB$FIELD_PRECISION = new_fld.dyn_precision;
2001-05-23 15:26:42 +02:00
FLD.RDB$FIELD_PRECISION.NULL = FALSE;
}
2009-11-25 05:06:48 +01:00
if (subtype)
{
FLD.RDB$FIELD_SUB_TYPE = new_fld.dyn_sub_type;
2001-05-23 15:26:42 +02:00
FLD.RDB$FIELD_SUB_TYPE.NULL = FALSE;
}
2009-11-25 05:06:48 +01:00
if (charlen)
{
FLD.RDB$CHARACTER_LENGTH = new_fld.dyn_charlen;
2001-05-23 15:26:42 +02:00
FLD.RDB$CHARACTER_LENGTH.NULL = FALSE;
}
2009-11-25 05:06:48 +01:00
if (charset)
{
2006-12-18 08:01:18 +01:00
FLD.RDB$CHARACTER_SET_ID = new_fld.dyn_charset;
FLD.RDB$CHARACTER_SET_ID.NULL = FALSE;
}
2009-11-25 05:06:48 +01:00
if (collation)
{
2006-12-18 08:01:18 +01:00
FLD.RDB$COLLATION_ID = new_fld.dyn_collation;
FLD.RDB$COLLATION_ID.NULL = FALSE;
}
2009-11-25 05:06:48 +01:00
if (fldlen)
{
// CVC: Rescue from the wrong field_length with a helper.
if (new_fld.dyn_dsc.dsc_dtype <= dtype_varying && new_fld.dyn_charbytelen)
FLD.RDB$FIELD_LENGTH = new_fld.dyn_charbytelen;
2002-06-30 10:46:51 +02:00
else
FLD.RDB$FIELD_LENGTH = new_fld.dyn_dsc.dsc_length;
2001-05-23 15:26:42 +02:00
FLD.RDB$FIELD_LENGTH.NULL = FALSE;
}
2008-01-16 09:46:02 +01:00
if (new_fld.dyn_computed_val)
{
DYN_put_blr_blob(gbl, &new_fld.dyn_computed_val, &FLD.RDB$COMPUTED_BLR);
FLD.RDB$COMPUTED_BLR.NULL = FALSE;
}
if (new_fld.dyn_computed_src)
{
DYN_put_text_blob(gbl, &new_fld.dyn_computed_src, &FLD.RDB$COMPUTED_SOURCE);
FLD.RDB$COMPUTED_SOURCE.NULL = FALSE;
}
// Copy the field name into RDB$FIELDS
strcpy(FLD.RDB$FIELD_NAME, new_fld.dyn_fld_source.c_str());
2001-05-23 15:26:42 +02:00
END_STORE;
2004-08-26 13:07:57 +02:00
CMP_release(tdbb, request);
2001-05-23 15:26:42 +02:00
request = NULL;
2008-01-16 09:46:02 +01:00
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
PRM IN RDB$PROCEDURE_PARAMETERS
WITH PRM.RDB$RELATION_NAME = relation_name->c_str() AND
PRM.RDB$FIELD_NAME = orig_fld.dyn_fld_name.c_str()
2008-01-16 09:46:02 +01:00
MODIFY PRM USING
strcpy(PRM.RDB$FIELD_SOURCE, new_fld.dyn_fld_source.c_str());
END_MODIFY;
END_FOR;
2008-01-16 09:46:02 +01:00
CMP_release(tdbb, request);
request = NULL;
2001-05-23 15:26:42 +02:00
}
else if (changeDefault)
{
request = first_request;
MODIFY RFR USING
if (dropDefault)
{
if (RFR.RDB$DEFAULT_VALUE.NULL)
{
if (sourceIsInternalDomain || !domain_has_default)
2006-07-09 04:41:49 +02:00
{
DYN_error_punt(false, 229, orig_fld.dyn_fld_name.c_str());
// msg 229: "Local column %s doesn't have a default"
2006-07-09 04:41:49 +02:00
}
else if (domain_has_default)
2006-07-09 04:41:49 +02:00
{
DYN_error_punt(false, 230, SafeArg() << orig_fld.dyn_fld_name.c_str() <<
orig_fld.dyn_fld_source.c_str());
// msg 230: "Local column %s default belongs to domain %s"
2006-07-09 04:41:49 +02:00
}
}
else
{
RFR.RDB$DEFAULT_VALUE.NULL = TRUE;
RFR.RDB$DEFAULT_SOURCE.NULL = TRUE;
}
}
else
{
2006-07-08 06:10:06 +02:00
if (domain_is_computed)
{
DYN_error_punt(false, 233, orig_fld.dyn_fld_name.c_str());
2006-07-08 06:10:06 +02:00
// msg 233: "Local column %s is computed, cannot set a default value"
}
if (defVal)
{
const UCHAR* p = defVal;
if (DYN_put_blr_blob(gbl, &p, &RFR.RDB$DEFAULT_VALUE))
RFR.RDB$DEFAULT_VALUE.NULL = FALSE;
}
if (defSrc)
{
const UCHAR* p = defSrc;
if (DYN_put_text_blob(gbl, &p, &RFR.RDB$DEFAULT_SOURCE))
RFR.RDB$DEFAULT_SOURCE.NULL = FALSE;
}
}
END_MODIFY
first_request = request;
request = NULL;
}
else //if (sourceIsInternalDomain)
2009-11-16 09:06:31 +01:00
{
// The original and new definitions are both base types.
// b2. Internal domain -> internal domain.
// Modify in place, since there cannot be other fields using it.
//if (!sourceIsInternalDomain)
// DYN_UTIL_copy_domain(tdbb, gbl, orig_fld.dyn_fld_source, new_fld.dyn_fld_source);
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
FLD IN RDB$FIELDS WITH FLD.RDB$FIELD_NAME = RFR.RDB$FIELD_SOURCE
MODIFY FLD USING
2009-11-25 05:06:48 +01:00
if (dtype)
{
FLD.RDB$FIELD_TYPE = new_fld.dyn_dtype;
2001-05-23 15:26:42 +02:00
FLD.RDB$FIELD_TYPE.NULL = FALSE;
}
2009-11-25 05:06:48 +01:00
if (scale)
{
FLD.RDB$FIELD_SCALE = new_fld.dyn_dsc.dsc_scale;
2001-05-23 15:26:42 +02:00
FLD.RDB$FIELD_SCALE.NULL = FALSE;
}
2009-11-25 05:06:48 +01:00
if (prec)
{
FLD.RDB$FIELD_PRECISION = new_fld.dyn_precision;
2001-05-23 15:26:42 +02:00
FLD.RDB$FIELD_PRECISION.NULL = FALSE;
}
2009-11-25 05:06:48 +01:00
if (subtype)
{
FLD.RDB$FIELD_SUB_TYPE = new_fld.dyn_sub_type;
2001-05-23 15:26:42 +02:00
FLD.RDB$FIELD_SUB_TYPE.NULL = FALSE;
}
2009-11-25 05:06:48 +01:00
if (charlen)
{
FLD.RDB$CHARACTER_LENGTH = new_fld.dyn_charlen;
2001-05-23 15:26:42 +02:00
FLD.RDB$CHARACTER_LENGTH.NULL = FALSE;
}
2009-11-25 05:06:48 +01:00
if (charset)
{
2006-12-18 08:01:18 +01:00
FLD.RDB$CHARACTER_SET_ID = new_fld.dyn_charset;
FLD.RDB$CHARACTER_SET_ID.NULL = FALSE;
}
2009-11-25 05:06:48 +01:00
if (collation)
{
2006-12-18 08:01:18 +01:00
FLD.RDB$COLLATION_ID = new_fld.dyn_collation;
FLD.RDB$COLLATION_ID.NULL = FALSE;
}
2009-11-25 05:06:48 +01:00
if (fldlen)
{
// CVC: Rescue from the wrong field_length with a helper.
if (new_fld.dyn_dsc.dsc_dtype <= dtype_varying && new_fld.dyn_charbytelen)
FLD.RDB$FIELD_LENGTH = new_fld.dyn_charbytelen;
2002-06-30 10:46:51 +02:00
else
FLD.RDB$FIELD_LENGTH = new_fld.dyn_dsc.dsc_length;
2001-05-23 15:26:42 +02:00
FLD.RDB$FIELD_LENGTH.NULL = FALSE;
}
2006-07-09 07:08:23 +02:00
2008-01-16 09:46:02 +01:00
if (changeComputed)
2006-07-08 05:45:13 +02:00
{
2008-01-16 09:46:02 +01:00
FLD.RDB$DEFAULT_SOURCE.NULL = TRUE;
FLD.RDB$DEFAULT_VALUE.NULL = TRUE;
if (new_fld.dyn_computed_val)
{
DYN_put_blr_blob(gbl, &new_fld.dyn_computed_val, &FLD.RDB$COMPUTED_BLR);
FLD.RDB$COMPUTED_BLR.NULL = FALSE;
}
if (new_fld.dyn_computed_src)
{
DYN_put_text_blob(gbl, &new_fld.dyn_computed_src, &FLD.RDB$COMPUTED_SOURCE);
FLD.RDB$COMPUTED_SOURCE.NULL = FALSE;
}
2006-07-08 05:45:13 +02:00
}
2001-05-23 15:26:42 +02:00
END_MODIFY;
END_FOR; // FLD in RDB$FIELDS
2004-08-26 13:07:57 +02:00
CMP_release(tdbb, request);
if (domain_is_computed)
{
request = first_request;
MODIFY RFR USING
RFR.RDB$UPDATE_FLAG.NULL = FALSE;
RFR.RDB$UPDATE_FLAG = 1;
END_MODIFY;
first_request = request;
}
2008-12-18 11:57:12 +01:00
2001-05-23 15:26:42 +02:00
request = NULL;
}
} // else not a domain
2008-01-16 09:46:02 +01:00
2001-05-23 15:26:42 +02:00
request = first_request;
2008-01-16 09:46:02 +01:00
if (fld_position_change || view_context_change || fld_base_field_change)
{
MODIFY RFR USING
if (fld_position_change)
RFR.RDB$FIELD_POSITION = fld_position;
if (view_context_change)
RFR.RDB$VIEW_CONTEXT = view_context;
if (fld_base_field_change)
{
RFR.RDB$BASE_FIELD.NULL = fld_base_field.isEmpty();
strcpy(RFR.RDB$BASE_FIELD, fld_base_field.c_str());
}
END_MODIFY;
}
END_FOR; // RFR IN RDB$RELATION_FIELDS
2004-08-26 13:07:57 +02:00
CMP_release(tdbb, request);
2001-05-23 15:26:42 +02:00
request = NULL;
if (!found)
{
DYN_error_punt(false, 176, SafeArg() << orig_fld.dyn_fld_name.c_str() <<
relation_name->c_str());
// msg 176: "column %s does not exist in table/view %s"
}
2001-05-23 15:26:42 +02:00
// Update any indices that exist
2009-04-28 15:48:18 +02:00
modify_lfield_index(tdbb, gbl, *relation_name, orig_fld.dyn_fld_name, orig_fld.dyn_fld_name);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
}
2009-11-25 05:06:48 +01:00
catch (const Exception& ex)
{
stuff_exception(tdbb->tdbb_status_vector, ex);
DYN_error_punt(true, 95);
// msg 95: "MODIFY RDB$RELATION_FIELDS failed"
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
}
2008-01-16 09:46:02 +01:00
// *************************************
// D Y N _ m o d i f y _ m a p p i n g
// *************************************
// It's purpose is to add/drop mapping from OS security name
// to DB security object
void DYN_modify_mapping(Global* gbl, const UCHAR** ptr)
{
thread_db* tdbb = JRD_get_thread_data();
2008-01-16 13:08:00 +01:00
Database* dbb = tdbb->getDatabase();
2008-01-16 09:46:02 +01:00
jrd_req* request = CMP_find_request(tdbb, drq_m_map, DYN_REQUESTS);
bool found = false;
string osName, dbName;
2008-01-16 09:46:02 +01:00
GET_STRING(ptr, osName);
const UCHAR op = *(*ptr)++;
GET_STRING(ptr, dbName);
// This is FB 2.5 limited implementation!
// Later it should work with new system table, something like RDB$MAPPING.
if (dbName != ADMIN_ROLE)
2008-01-16 09:46:02 +01:00
{
status_exception::raise(Arg::Gds(isc_no_meta_update) << Arg::Gds(isc_wish_list));
2008-01-16 09:46:02 +01:00
}
2008-01-16 13:08:00 +01:00
if (!(tdbb->getAttachment() && tdbb->getAttachment()->locksmith()))
ERR_post(Arg::Gds(isc_adm_task_denied));
2008-01-16 09:46:02 +01:00
found = false;
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
X IN RDB$ROLES
WITH X.RDB$ROLE_NAME EQ dbName.c_str()
if (!DYN_REQUEST(drq_m_map))
DYN_REQUEST(drq_m_map) = request;
found = true;
MODIFY X
switch (op)
{
case isc_dyn_automap_role:
2008-01-16 09:46:02 +01:00
X.RDB$SYSTEM_FLAG = ROLE_FLAG_DBO | ROLE_FLAG_MAY_TRUST;
break;
case isc_dyn_autounmap_role:
2008-01-16 09:46:02 +01:00
X.RDB$SYSTEM_FLAG = ROLE_FLAG_DBO;
break;
default:
DYN_unsupported_verb();
}
END_MODIFY;
END_FOR;
if (!DYN_REQUEST(drq_m_map))
DYN_REQUEST(drq_m_map) = request;
if (!found)
{
status_exception::raise(Arg::Gds(isc_no_meta_update) <<
Arg::Gds(isc_random) << Arg::Str("Missing RDB$ADMIN role in the database"));
2008-01-16 09:46:02 +01:00
}
}
2009-04-28 15:48:18 +02:00
void get_domain_type(thread_db* tdbb, Global* gbl, dyn_fld& dom_fld)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
2008-12-18 11:57:12 +01:00
* g e t _ d o m a i n _ t y p e
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* Retrieves the type information for a domain so
2001-05-23 15:26:42 +02:00
* that it can be compared to a local field before
* modifying the datatype of a field.
*
**************************************/
jrd_req* request = NULL;
2001-05-23 15:26:42 +02:00
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
FLD IN RDB$FIELDS WITH FLD.RDB$FIELD_NAME EQ dom_fld.dyn_fld_source.c_str();
2001-05-23 15:26:42 +02:00
DSC_make_descriptor(&dom_fld.dyn_dsc,
2001-05-23 15:26:42 +02:00
FLD.RDB$FIELD_TYPE,
FLD.RDB$FIELD_SCALE,
FLD.RDB$FIELD_LENGTH,
FLD.RDB$FIELD_SUB_TYPE,
FLD.RDB$CHARACTER_SET_ID,
FLD.RDB$COLLATION_ID);
2001-05-23 15:26:42 +02:00
dom_fld.dyn_charbytelen = FLD.RDB$FIELD_LENGTH;
dom_fld.dyn_dtype = FLD.RDB$FIELD_TYPE;
dom_fld.dyn_precision = FLD.RDB$FIELD_PRECISION;
dom_fld.dyn_sub_type = FLD.RDB$FIELD_SUB_TYPE;
dom_fld.dyn_charlen = FLD.RDB$CHARACTER_LENGTH;
dom_fld.dyn_collation = FLD.RDB$COLLATION_ID;
dom_fld.dyn_null_flag = FLD.RDB$NULL_FLAG != 0;
2008-12-18 11:57:12 +01:00
if (!FLD.RDB$DIMENSIONS.NULL && FLD.RDB$DIMENSIONS > 0)
dom_fld.dyn_dtype = blr_blob;
2001-05-23 15:26:42 +02:00
END_FOR;
2004-08-26 13:07:57 +02:00
CMP_release(tdbb, request);
2001-05-23 15:26:42 +02:00
}
2009-11-25 05:06:48 +01:00
static ULONG check_update_fld_type(const dyn_fld& orig_fld, const dyn_fld& new_fld)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* c h e c k _ u p d a t e _ f l d _ t y p e
*
**************************************
*
* Functional description
* Compare the original field type with the new field type to
* determine if the original type can be changed to the new type
*
* The following conversions are not allowed:
* Blob to anything
* Array to anything
* Date to anything
* Char to any numeric
* Varchar to any numeric
* Anything to Blob
* Anything to Array
*
* This function returns an error code if the conversion can not be
* made. If the conversion can be made, FB_SUCCESS is returned
2001-05-23 15:26:42 +02:00
**************************************/
2009-11-21 08:38:05 +01:00
// Check to make sure that the old and new types are compatible
2009-01-20 09:33:59 +01:00
switch (orig_fld.dyn_dtype)
{
2009-11-21 08:38:05 +01:00
// CHARACTER types
2001-05-23 15:26:42 +02:00
case blr_text:
case blr_varying:
case blr_cstring:
2009-01-20 09:33:59 +01:00
switch (new_fld.dyn_dtype)
{
2001-05-23 15:26:42 +02:00
case blr_blob:
case blr_blob_id:
return isc_dyn_dtype_invalid;
2009-11-21 08:38:05 +01:00
// Cannot change datatype for column %s.
// The operation cannot be performed on BLOB, or ARRAY columns.
2001-05-23 15:26:42 +02:00
break;
case blr_sql_date:
case blr_sql_time:
case blr_timestamp:
case blr_int64:
case blr_long:
case blr_short:
case blr_d_float:
case blr_double:
case blr_float:
return isc_dyn_dtype_conv_invalid;
2009-11-21 08:38:05 +01:00
// Cannot convert column %s from character to non-character data.
2001-05-23 15:26:42 +02:00
break;
2009-11-21 08:38:05 +01:00
// If the original field is a character field and the new field is a character field,
// is there enough space in the new field?
2001-05-23 15:26:42 +02:00
case blr_text:
case blr_varying:
case blr_cstring:
{
2009-11-21 08:38:05 +01:00
// CVC: Because our caller invoked DSC_make_descriptor() on new_fld previously,
// we should have the added bytes for varchar. For cstring, we are done, since
// DSC_make_descriptor(DSC_string_length) != DSC_string_length(DSC_make_descriptor).
2001-05-23 15:26:42 +02:00
const USHORT maxflen = DSC_string_length(&orig_fld.dyn_dsc);
2001-05-23 15:26:42 +02:00
2009-11-21 08:38:05 +01:00
// We can have this assertion since this case is for both string fields.
2006-07-08 06:10:06 +02:00
const ULONG new_len = DSC_string_length(&new_fld.dyn_dsc);
fb_assert(new_len - maxflen == (ULONG) new_fld.dyn_charbytelen - orig_fld.dyn_charbytelen);
// if (new_fld.dyn_dsc.dsc_length < maxflen)
2006-07-08 06:10:06 +02:00
if (new_len < maxflen)
2001-05-23 15:26:42 +02:00
return isc_dyn_char_fld_too_small;
2007-03-28 06:51:48 +02:00
// msg 208: New size specified for column %s must be at least %d characters.
2001-05-23 15:26:42 +02:00
}
break;
default:
2003-11-04 00:59:24 +01:00
fb_assert(FALSE);
2009-11-21 08:38:05 +01:00
return 87; // MODIFY RDB$FIELDS FAILED
2001-05-23 15:26:42 +02:00
}
break;
2009-11-21 08:38:05 +01:00
// BLOB and ARRAY types
2001-05-23 15:26:42 +02:00
case blr_blob:
case blr_blob_id:
return isc_dyn_dtype_invalid;
2009-11-21 08:38:05 +01:00
// Cannot change datatype for column %s.
// The operation cannot be performed on BLOB, or ARRAY columns.
2001-05-23 15:26:42 +02:00
2009-11-21 08:38:05 +01:00
// DATE types
2001-05-23 15:26:42 +02:00
case blr_sql_date:
case blr_sql_time:
case blr_timestamp:
2009-01-20 09:33:59 +01:00
switch (new_fld.dyn_dtype)
{
2001-05-23 15:26:42 +02:00
case blr_sql_date:
if (orig_fld.dyn_dtype == blr_sql_time)
2001-05-23 15:26:42 +02:00
return isc_dyn_invalid_dtype_conversion;
2009-11-21 08:38:05 +01:00
// Cannot change datatype for column %s. Conversion from base type %s to base type %s is not supported.
2001-05-23 15:26:42 +02:00
break;
case blr_sql_time:
if (orig_fld.dyn_dtype == blr_sql_date)
2001-05-23 15:26:42 +02:00
return isc_dyn_invalid_dtype_conversion;
2009-11-21 08:38:05 +01:00
// Cannot change datatype for column %s. Conversion from base type %s to base type %s is not supported.
2001-05-23 15:26:42 +02:00
break;
case blr_timestamp:
if (orig_fld.dyn_dtype == blr_sql_time)
2001-05-23 15:26:42 +02:00
return isc_dyn_invalid_dtype_conversion;
2009-11-21 08:38:05 +01:00
// Cannot change datatype for column %s. Conversion from base type %s to base type %s is not supported.
2001-05-23 15:26:42 +02:00
break;
2009-11-22 01:09:30 +01:00
// If the original field is a date field and the new field is a character field,
// is there enough space in the new field?
2001-05-23 15:26:42 +02:00
case blr_text:
case blr_text2:
case blr_varying:
case blr_varying2:
case blr_cstring:
case blr_cstring2:
{
const USHORT maxflen = DSC_string_length(&orig_fld.dyn_dsc);
2001-05-23 15:26:42 +02:00
2004-04-11 09:14:27 +02:00
// CVC: Solve bug #910423, missing DSC_string_length call.
// if (new_fld.dyn_dsc.dsc_length < maxflen)
2006-07-09 07:08:23 +02:00
if (DSC_string_length(&new_fld.dyn_dsc) < maxflen)
2001-05-23 15:26:42 +02:00
return isc_dyn_char_fld_too_small;
2007-03-28 06:51:48 +02:00
// msg 208: New size specified for column %s must be at least %d characters.
2001-05-23 15:26:42 +02:00
}
break;
default:
return isc_dyn_invalid_dtype_conversion;
2009-11-21 08:38:05 +01:00
// Cannot change datatype for column %s. Conversion from base type %s to base type %s is not supported.
2001-05-23 15:26:42 +02:00
}
break;
2009-11-21 08:38:05 +01:00
// NUMERIC types
2001-05-23 15:26:42 +02:00
case blr_int64:
case blr_long:
case blr_short:
case blr_d_float:
case blr_double:
case blr_float:
2009-01-20 09:33:59 +01:00
switch (new_fld.dyn_dtype)
{
2001-05-23 15:26:42 +02:00
case blr_blob:
case blr_blob_id:
return isc_dyn_dtype_invalid;
2009-11-21 08:38:05 +01:00
// Cannot change datatype for column %s.
// The operation cannot be performed on BLOB, or ARRAY columns.
2001-05-23 15:26:42 +02:00
case blr_sql_date:
case blr_sql_time:
case blr_timestamp:
return isc_dyn_invalid_dtype_conversion;
2009-11-21 08:38:05 +01:00
// Cannot change datatype for column %s. Conversion from base type %s to base type %s is not supported.
2001-05-23 15:26:42 +02:00
2009-11-22 01:09:30 +01:00
// If the original field is a numeric field and the new field is a numeric field,
// is there enough space in the new field (do not allow the base type to decrease)
2001-05-23 15:26:42 +02:00
case blr_short:
2009-01-20 09:33:59 +01:00
switch (orig_fld.dyn_dtype)
{
2001-05-23 15:26:42 +02:00
case blr_short:
2007-03-28 06:51:48 +02:00
return check_update_numeric_type(orig_fld, new_fld);
2008-12-18 11:57:12 +01:00
2001-05-23 15:26:42 +02:00
default:
return isc_dyn_invalid_dtype_conversion;
2009-11-21 08:38:05 +01:00
// Cannot change datatype for column %s. Conversion from base type %s to base type %s is not supported.
2001-05-23 15:26:42 +02:00
}
break;
case blr_long:
2009-01-20 09:33:59 +01:00
switch (orig_fld.dyn_dtype)
{
2001-05-23 15:26:42 +02:00
case blr_long:
case blr_short:
2007-03-28 06:51:48 +02:00
return check_update_numeric_type(orig_fld, new_fld);
2008-12-18 11:57:12 +01:00
2001-05-23 15:26:42 +02:00
default:
return isc_dyn_invalid_dtype_conversion;
2009-11-21 08:38:05 +01:00
// Cannot change datatype for column %s. Conversion from base type %s to base type %s is not supported.
2001-05-23 15:26:42 +02:00
}
break;
case blr_float:
2009-01-20 09:33:59 +01:00
switch (orig_fld.dyn_dtype)
{
2001-05-23 15:26:42 +02:00
case blr_float:
case blr_short:
break;
default:
return isc_dyn_invalid_dtype_conversion;
2009-11-21 08:38:05 +01:00
// Cannot change datatype for column %s. Conversion from base type %s to base type %s is not supported.
2001-05-23 15:26:42 +02:00
}
break;
case blr_int64:
2009-01-20 09:33:59 +01:00
switch (orig_fld.dyn_dtype)
{
2001-05-23 15:26:42 +02:00
case blr_int64:
case blr_long:
case blr_short:
2007-03-28 06:51:48 +02:00
return check_update_numeric_type(orig_fld, new_fld);
2001-05-23 15:26:42 +02:00
default:
return isc_dyn_invalid_dtype_conversion;
2009-11-21 08:38:05 +01:00
// Cannot change datatype for column %s. Conversion from base type %s to base type %s is not supported.
2001-05-23 15:26:42 +02:00
}
break;
case blr_d_float:
case blr_double:
2009-01-20 09:33:59 +01:00
switch (orig_fld.dyn_dtype)
{
2001-05-23 15:26:42 +02:00
case blr_double:
case blr_d_float:
case blr_float:
case blr_short:
case blr_long:
break;
default:
return isc_dyn_invalid_dtype_conversion;
2009-11-21 08:38:05 +01:00
// Cannot change datatype for column %s. Conversion from base type %s to base type %s is not supported.
2001-05-23 15:26:42 +02:00
}
break;
2009-11-22 01:09:30 +01:00
// If the original field is a numeric field and the new field is a character field,
// is there enough space in the new field?
2001-05-23 15:26:42 +02:00
case blr_text:
case blr_varying:
case blr_cstring:
{
const USHORT maxflen = DSC_string_length(&orig_fld.dyn_dsc);
2001-05-23 15:26:42 +02:00
2004-04-11 09:14:27 +02:00
// CVC: Solve bug #910423, missing DSC_string_length call.
// if (new_fld.dyn_dsc.dsc_length < maxflen)
2006-07-09 07:08:23 +02:00
if (DSC_string_length(&new_fld.dyn_dsc) < maxflen)
2001-05-23 15:26:42 +02:00
return isc_dyn_char_fld_too_small;
2007-03-28 06:51:48 +02:00
// msg 208: New size specified for column %s must be at least %d characters.
2001-05-23 15:26:42 +02:00
}
break;
default:
2003-11-04 00:59:24 +01:00
fb_assert(FALSE);
2009-11-21 08:38:05 +01:00
return 87; // MODIFY RDB$FIELDS FAILED
2001-05-23 15:26:42 +02:00
}
break;
default:
2003-11-04 00:59:24 +01:00
fb_assert(FALSE);
2009-11-21 08:38:05 +01:00
return 87; // MODIFY RDB$FIELDS FAILED
2001-05-23 15:26:42 +02:00
}
return FB_SUCCESS;
2001-05-23 15:26:42 +02:00
}
2008-12-18 11:57:12 +01:00
static ULONG check_update_numeric_type(const dyn_fld& orig_fld, const dyn_fld& new_fld)
2007-03-28 06:51:48 +02:00
{
/**************************************
*
* c h e c k _ u p d a t e _ n u m e r i c _ t y p e
*
**************************************
*
* Functional description
* Compare the original field type with the new field type to
* determine if the original type can be changed to the new type.
* The types should be integral, since it tests only numeric/decimal subtypes
* to ensure the scale is not being widened at the expense of the precision,
* because the old stored values should fit in the new definition.
*
* This function returns an error code if the conversion can not be
* made. If the conversion can be made, FB_SUCCESS is returned.
**************************************/
// Since dsc_scale is negative, the sum of precision and scale produces
// the width of the integral part.
if (orig_fld.dyn_sub_type && new_fld.dyn_sub_type &&
2007-03-28 06:51:48 +02:00
orig_fld.dyn_precision + orig_fld.dyn_dsc.dsc_scale >
2008-12-18 11:57:12 +01:00
new_fld.dyn_precision + new_fld.dyn_dsc.dsc_scale)
2007-03-28 06:51:48 +02:00
{
return isc_dyn_scale_too_big;
}
return FB_SUCCESS;
}
2009-04-28 15:48:18 +02:00
static void modify_err_punt(thread_db* /*tdbb*/,
2001-05-23 15:26:42 +02:00
ULONG errorcode,
const dyn_fld& orig_fld_def,
const dyn_fld& new_fld_def)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* m o d i f y _ e r r _ p u n t
*
**************************************
*
* Functional description
* A generic error routine that calls DYN_error_punt
* based on the error code returned by check_update_field_type.
2008-12-18 11:57:12 +01:00
*
* This function is called by DYN_modify_global_field and by
2001-05-23 15:26:42 +02:00
* DYN_modify_sql_field
**************************************/
2007-03-28 06:51:48 +02:00
switch (errorcode)
{
2001-05-23 15:26:42 +02:00
case isc_dyn_dtype_invalid:
2007-03-28 06:51:48 +02:00
DYN_error_punt(false, errorcode, orig_fld_def.dyn_fld_name.c_str());
2009-11-21 08:38:05 +01:00
// Cannot change datatype for column %s.The operation cannot be performed on DATE, BLOB, or ARRAY columns.
2001-05-23 15:26:42 +02:00
break;
case isc_dyn_dtype_conv_invalid:
2007-03-28 06:51:48 +02:00
DYN_error_punt(false, errorcode, orig_fld_def.dyn_fld_name.c_str());
2009-11-21 08:38:05 +01:00
// Cannot convert column %s from character to non-character data.
2001-05-23 15:26:42 +02:00
break;
case isc_dyn_char_fld_too_small:
DYN_error_punt(false,
2007-03-28 06:51:48 +02:00
errorcode,
SafeArg() << orig_fld_def.dyn_fld_name.c_str() <<
DSC_string_length(&orig_fld_def.dyn_dsc));
2007-03-28 06:51:48 +02:00
// msg 208: New size specified for column %s must be at least %d characters.
break;
2008-12-18 11:57:12 +01:00
2007-03-28 06:51:48 +02:00
case isc_dyn_scale_too_big:
{
int code = errorcode;
int diff = new_fld_def.dyn_precision -
(orig_fld_def.dyn_precision + orig_fld_def.dyn_dsc.dsc_scale);
if (diff < 0)
{
// If new scale becomes negative externally, the message is useless for the user.
// (The scale is always zero or negative for us but externally is non-negative.)
// Let's ask the user to widen the precision, then. Example: numeric(4, 0) -> numeric(1, 1).
code = isc_dyn_precision_too_small;
diff = new_fld_def.dyn_precision - new_fld_def.dyn_dsc.dsc_scale - diff;
}
2008-12-18 11:57:12 +01:00
DYN_error_punt(false, code, SafeArg() << orig_fld_def.dyn_fld_name.c_str() << diff);
2007-03-28 06:51:48 +02:00
// scale_too_big: New scale specified for column @1 must be at most @2.
// precision_too_small: New precision specified for column @1 must be at least @2.
}
2001-05-23 15:26:42 +02:00
break;
case isc_dyn_invalid_dtype_conversion:
{
TEXT orig_type[25], new_type[25];
2008-12-18 11:57:12 +01:00
DSC_get_dtype_name(&orig_fld_def.dyn_dsc, orig_type, sizeof(orig_type));
DSC_get_dtype_name(&new_fld_def.dyn_dsc, new_type, sizeof(new_type));
2001-05-23 15:26:42 +02:00
2007-03-28 06:51:48 +02:00
DYN_error_punt(false, errorcode,
SafeArg() << orig_fld_def.dyn_fld_name.c_str() <<
orig_type << new_type);
// Cannot change datatype for @1. Conversion from base type @2 to @3 is not supported.
2001-05-23 15:26:42 +02:00
}
2007-03-28 06:51:48 +02:00
break;
2001-05-23 15:26:42 +02:00
default:
DYN_error_punt(true, 95);
2009-11-21 08:38:05 +01:00
// msg 95: "MODIFY RDB$RELATION_FIELDS failed"
2001-05-23 15:26:42 +02:00
}
}