2001-05-23 15:26:42 +02:00
|
|
|
/*
|
|
|
|
* PROGRAM: JRD Access Method
|
2003-10-08 10:42:48 +02:00
|
|
|
* MODULE: evl.cpp
|
2001-05-23 15:26:42 +02:00
|
|
|
* DESCRIPTION: Expression evaluation
|
|
|
|
*
|
|
|
|
* 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): ______________________________________.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Modified by: Patrick J. P. Griffin
|
|
|
|
* Date: 11/24/2000
|
|
|
|
* Problem: select count(0)+1 from rdb$relations where 0=1; returns 0
|
2005-05-28 00:45:31 +02:00
|
|
|
* In the EVL_group processing, the internal assigment for
|
|
|
|
* the literal in the computation is being done on every
|
2001-05-23 15:26:42 +02:00
|
|
|
* statement fetch, so if there are no statements fetched
|
|
|
|
* then the internal field never gets set.
|
|
|
|
* Change: Added an assignment process for the literal
|
|
|
|
* before the first fetch.
|
2002-06-30 11:58:20 +02:00
|
|
|
*
|
2001-05-23 15:26:42 +02:00
|
|
|
* Modified by: Neil McCalden
|
|
|
|
* Date: 05 Jan 2001
|
|
|
|
* Problem: Firebird bug: 127375
|
|
|
|
* Group by on a calculated expression would cause segv
|
|
|
|
* when it encountered a NULL value as the calculation
|
|
|
|
* was trying reference a null pointer.
|
|
|
|
* Change: Test the null flag before trying to expand the value.
|
2002-06-30 11:58:20 +02:00
|
|
|
*
|
|
|
|
* 2001.6.17 Claudio Valderrama: Fix the annoying behavior that causes silent
|
|
|
|
* overflow in dialect 1. If you define the macro FIREBIRD_AVOID_DIALECT1_OVERFLOW
|
|
|
|
* it will work with double should an overflow happen. Otherwise, an error will be
|
|
|
|
* issued to the user if the overflow happens. The multiplication is done using
|
|
|
|
* SINT64 quantities. I had the impression that casting this SINT64 result to double
|
|
|
|
* when we detect overflow was faster than achieving the failed full multiplication
|
|
|
|
* with double operands again. Usage will tell the truth.
|
|
|
|
* For now, the aforementioned macro is enabled.
|
|
|
|
* 2001.6.18 Claudio Valderrama: substring() is working with international charsets,
|
|
|
|
* thanks to Dave Schnepper's directions.
|
|
|
|
* 2002.2.15 Claudio Valderrama: divide2() should not mangle negative values.
|
2005-05-28 00:45:31 +02:00
|
|
|
* 2002.04.16 Paul Beach HP10 Port - (UCHAR*) desc.dsc_address = p; modified for HP
|
2002-06-30 11:58:20 +02:00
|
|
|
* Compiler
|
2002-09-28 16:04:35 +02:00
|
|
|
* 2002.09.28 Dmitry Yemanov: Reworked internal_info stuff, enhanced
|
|
|
|
* exception handling in SPs/triggers,
|
|
|
|
* implemented ROWS_AFFECTED system variable
|
2003-08-12 11:56:50 +02:00
|
|
|
* 2003.08.10 Claudio Valderrama: Fix SF bug# 784121.
|
2007-04-13 03:37:44 +02:00
|
|
|
* Adriano dos Santos Fernandes
|
2001-05-23 15:26:42 +02:00
|
|
|
*/
|
|
|
|
|
2001-07-29 19:42:23 +02:00
|
|
|
#include "firebird.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include <string.h>
|
2004-04-09 00:29:50 +02:00
|
|
|
#include <math.h>
|
2010-02-13 21:29:29 +01:00
|
|
|
#include "../dsql/Nodes.h"
|
2010-10-12 13:36:51 +02:00
|
|
|
#include "../dsql/ExprNodes.h"
|
2010-12-04 23:15:03 +01:00
|
|
|
#include "../dsql/StmtNodes.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/jrd.h"
|
|
|
|
#include "../jrd/val.h"
|
|
|
|
#include "../jrd/req.h"
|
|
|
|
#include "../jrd/exe.h"
|
|
|
|
#include "../jrd/sbm.h"
|
|
|
|
#include "../jrd/blb.h"
|
2003-11-11 13:19:20 +01:00
|
|
|
#include "gen/iberror.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/scl.h"
|
|
|
|
#include "../jrd/lck.h"
|
|
|
|
#include "../jrd/lls.h"
|
|
|
|
#include "../jrd/intl.h"
|
2002-06-04 21:56:16 +02:00
|
|
|
#include "../jrd/intl_classes.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/rse.h"
|
|
|
|
#include "../jrd/sort.h"
|
|
|
|
#include "../jrd/blr.h"
|
|
|
|
#include "../jrd/tra.h"
|
2010-10-13 12:39:52 +02:00
|
|
|
#include "../common/gdsassert.h"
|
2008-01-16 09:54:50 +01:00
|
|
|
#include "../common/classes/auto.h"
|
2006-02-03 09:39:36 +01:00
|
|
|
#include "../common/classes/timestamp.h"
|
2009-04-29 16:00:32 +02:00
|
|
|
#include "../common/classes/VaryStr.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/blb_proto.h"
|
|
|
|
#include "../jrd/btr_proto.h"
|
|
|
|
#include "../jrd/cvt_proto.h"
|
2006-08-10 04:53:16 +02:00
|
|
|
#include "../jrd/DataTypeUtil.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/dpm_proto.h"
|
2010-10-12 10:02:57 +02:00
|
|
|
#include "../common/dsc_proto.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/err_proto.h"
|
|
|
|
#include "../jrd/evl_proto.h"
|
|
|
|
#include "../jrd/exe_proto.h"
|
|
|
|
#include "../jrd/fun_proto.h"
|
|
|
|
#include "../jrd/intl_proto.h"
|
|
|
|
#include "../jrd/lck_proto.h"
|
|
|
|
#include "../jrd/met_proto.h"
|
|
|
|
#include "../jrd/mov_proto.h"
|
|
|
|
#include "../jrd/pag_proto.h"
|
|
|
|
#include "../jrd/rlck_proto.h"
|
|
|
|
#include "../jrd/scl_proto.h"
|
2010-10-12 10:02:57 +02:00
|
|
|
#include "../yvalve/gds_proto.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/align.h"
|
2002-06-30 11:58:20 +02:00
|
|
|
#include "../jrd/met_proto.h"
|
2003-02-21 10:17:03 +01:00
|
|
|
#include "../common/config/config.h"
|
2007-04-12 17:56:34 +02:00
|
|
|
#include "../jrd/SysFunction.h"
|
2009-12-09 19:45:44 +01:00
|
|
|
#include "../jrd/recsrc/RecordSource.h"
|
|
|
|
#include "../jrd/recsrc/Cursor.h"
|
2009-11-05 18:04:30 +01:00
|
|
|
#include "../common/classes/Aligner.h"
|
2009-12-21 18:43:01 +01:00
|
|
|
#include "../jrd/Function.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-03-20 15:57:40 +01:00
|
|
|
using namespace Jrd;
|
2008-08-27 14:20:47 +02:00
|
|
|
using namespace Firebird;
|
2004-03-20 15:57:40 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2010-11-21 04:47:29 +01:00
|
|
|
dsc* EVL_assign_to(thread_db* tdbb, const ValueExprNode* node)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* E V L _ a s s i g n _ t o
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Evaluate the descriptor of the
|
|
|
|
* destination node of an assignment.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
|
|
|
DEV_BLKCHK(node, type_nod);
|
|
|
|
|
2007-12-03 16:46:39 +01:00
|
|
|
jrd_req* request = tdbb->getRequest();
|
2010-11-21 04:47:29 +01:00
|
|
|
impure_value* impure = request->getImpure<impure_value>(node->impureOffset);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-11-22 04:56:20 +01:00
|
|
|
// The only nodes that can be assigned to are: argument, field and variable.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-23 21:17:30 +01:00
|
|
|
int arg_number;
|
2010-10-12 13:36:51 +02:00
|
|
|
const dsc* desc;
|
2010-12-04 23:15:03 +01:00
|
|
|
const MessageNode* message;
|
2010-10-12 13:36:51 +02:00
|
|
|
Record* record;
|
|
|
|
const ParameterNode* paramNode;
|
2010-11-02 18:05:01 +01:00
|
|
|
const VariableNode* varNode;
|
2010-11-14 18:25:48 +01:00
|
|
|
const FieldNode* fieldNode;
|
2003-11-23 21:17:30 +01:00
|
|
|
|
2010-10-12 13:36:51 +02:00
|
|
|
if ((paramNode = ExprNode::as<ParameterNode>(node)))
|
2009-01-20 09:33:59 +01:00
|
|
|
{
|
2010-10-12 13:36:51 +02:00
|
|
|
message = paramNode->message;
|
|
|
|
arg_number = paramNode->argNumber;
|
2010-12-04 23:15:03 +01:00
|
|
|
desc = &message->format->fmt_desc[arg_number];
|
2010-10-12 13:36:51 +02:00
|
|
|
|
2010-04-05 23:20:08 +02:00
|
|
|
impure->vlu_desc.dsc_address = request->getImpure<UCHAR>(
|
2010-12-04 23:15:03 +01:00
|
|
|
message->impureOffset + (IPTR) desc->dsc_address);
|
2001-05-23 15:26:42 +02:00
|
|
|
impure->vlu_desc.dsc_dtype = desc->dsc_dtype;
|
|
|
|
impure->vlu_desc.dsc_length = desc->dsc_length;
|
|
|
|
impure->vlu_desc.dsc_scale = desc->dsc_scale;
|
|
|
|
impure->vlu_desc.dsc_sub_type = desc->dsc_sub_type;
|
2010-10-12 13:36:51 +02:00
|
|
|
|
2003-10-21 00:41:11 +02:00
|
|
|
if (DTYPE_IS_TEXT(desc->dsc_dtype) &&
|
2008-12-20 09:12:19 +01:00
|
|
|
((INTL_TTYPE(desc) == ttype_dynamic) || (INTL_GET_CHARSET(desc) == CS_dynamic)))
|
2004-02-24 06:34:44 +01:00
|
|
|
{
|
2010-10-12 13:36:51 +02:00
|
|
|
// Value is a text value, we're assigning it back to the user
|
|
|
|
// process, user process has not specified a subtype, user
|
|
|
|
// process specified dynamic translation and the dsc isn't from
|
|
|
|
// a 3.3 type request (blr_cstring2 instead of blr_cstring) so
|
|
|
|
// convert the charset to the declared charset of the process.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-11-28 20:39:23 +01:00
|
|
|
impure->vlu_desc.setTextType(tdbb->getCharSet());
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2010-10-12 13:36:51 +02:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
return &impure->vlu_desc;
|
2010-10-12 13:36:51 +02:00
|
|
|
}
|
2010-10-22 17:00:22 +02:00
|
|
|
else if (ExprNode::is<NullNode>(node))
|
|
|
|
return NULL;
|
2010-11-02 18:05:01 +01:00
|
|
|
else if ((varNode = ExprNode::as<VariableNode>(node)))
|
|
|
|
{
|
|
|
|
// Calculate descriptor
|
2010-12-04 23:15:03 +01:00
|
|
|
impure = request->getImpure<impure_value>(varNode->varDecl->impureOffset);
|
2010-11-02 18:05:01 +01:00
|
|
|
return &impure->vlu_desc;
|
|
|
|
}
|
2010-11-14 18:25:48 +01:00
|
|
|
else if ((fieldNode = ExprNode::as<FieldNode>(node)))
|
2010-10-12 13:36:51 +02:00
|
|
|
{
|
2010-11-14 18:25:48 +01:00
|
|
|
record = request->req_rpb[fieldNode->fieldStream].rpb_record;
|
|
|
|
|
|
|
|
if (!EVL_field(0, record, fieldNode->fieldId, &impure->vlu_desc))
|
2006-03-28 11:55:45 +02:00
|
|
|
{
|
|
|
|
// The below condition means that EVL_field() returned
|
|
|
|
// a read-only dummy value which cannot be assigned to.
|
|
|
|
// The usual reason is a field being unexpectedly dropped.
|
2010-11-14 18:25:48 +01:00
|
|
|
if (impure->vlu_desc.dsc_address && !(impure->vlu_desc.dsc_flags & DSC_null))
|
2008-08-27 14:20:47 +02:00
|
|
|
ERR_post(Arg::Gds(isc_field_disappeared));
|
2006-03-28 11:55:45 +02:00
|
|
|
}
|
2010-11-14 18:25:48 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!impure->vlu_desc.dsc_address)
|
2008-08-27 14:20:47 +02:00
|
|
|
ERR_post(Arg::Gds(isc_read_only_field));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2010-11-14 18:25:48 +01:00
|
|
|
return &impure->vlu_desc;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2010-10-12 19:40:27 +02:00
|
|
|
|
2010-11-14 18:25:48 +01:00
|
|
|
BUGCHECK(229); // msg 229 EVL_assign_to: invalid operation
|
2001-05-23 15:26:42 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-10-12 13:36:51 +02:00
|
|
|
RecordBitmap** EVL_bitmap(thread_db* tdbb, const InversionNode* node, RecordBitmap* bitmap_and)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* E V L _ b i t m a p
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Evaluate bitmap valued expression.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
|
|
|
DEV_BLKCHK(node, type_nod);
|
|
|
|
|
2004-10-03 14:10:19 +02:00
|
|
|
if (--tdbb->tdbb_quantum < 0)
|
|
|
|
JRD_reschedule(tdbb, 0, true);
|
|
|
|
|
2010-10-12 13:36:51 +02:00
|
|
|
switch (node->type)
|
2009-01-20 09:33:59 +01:00
|
|
|
{
|
2010-10-12 13:36:51 +02:00
|
|
|
case InversionNode::TYPE_AND:
|
2006-12-27 22:01:02 +01:00
|
|
|
{
|
2010-10-12 13:36:51 +02:00
|
|
|
RecordBitmap** bitmap = EVL_bitmap(tdbb, node->node1, bitmap_and);
|
2006-12-27 22:01:02 +01:00
|
|
|
if (!(*bitmap) || !(*bitmap)->getFirst())
|
|
|
|
return bitmap;
|
2008-01-16 09:54:50 +01:00
|
|
|
|
2010-10-12 13:36:51 +02:00
|
|
|
return EVL_bitmap(tdbb, node->node2, *bitmap);
|
2006-12-27 22:01:02 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2010-10-12 13:36:51 +02:00
|
|
|
case InversionNode::TYPE_OR:
|
2004-09-28 08:28:38 +02:00
|
|
|
return RecordBitmap::bit_or(
|
2010-10-12 13:36:51 +02:00
|
|
|
EVL_bitmap(tdbb, node->node1, bitmap_and),
|
|
|
|
EVL_bitmap(tdbb, node->node2, bitmap_and));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2010-10-12 13:36:51 +02:00
|
|
|
case InversionNode::TYPE_IN:
|
2004-08-17 19:52:19 +02:00
|
|
|
{
|
2010-10-12 13:36:51 +02:00
|
|
|
RecordBitmap** inv_bitmap = EVL_bitmap(tdbb, node->node1, bitmap_and);
|
|
|
|
BTR_evaluate(tdbb, node->node2->retrieval, inv_bitmap, bitmap_and);
|
2004-08-17 19:52:19 +02:00
|
|
|
return inv_bitmap;
|
|
|
|
}
|
|
|
|
|
2010-10-12 13:36:51 +02:00
|
|
|
case InversionNode::TYPE_DBKEY:
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2010-11-21 04:47:29 +01:00
|
|
|
jrd_req* request = tdbb->getRequest();
|
|
|
|
impure_inversion* impure = request->getImpure<impure_inversion>(node->impure);
|
2004-09-28 08:28:38 +02:00
|
|
|
RecordBitmap::reset(impure->inv_bitmap);
|
2015-02-18 13:55:06 +01:00
|
|
|
const dsc* const desc = EVL_expr(tdbb, request, node->value);
|
2007-07-02 01:13:09 +02:00
|
|
|
|
2015-02-18 13:55:06 +01:00
|
|
|
if (!(tdbb->getRequest()->req_flags & req_null) &&
|
|
|
|
(desc->isText() || desc->isDbKey()))
|
2007-07-02 01:13:09 +02:00
|
|
|
{
|
2013-11-07 19:41:27 +01:00
|
|
|
UCHAR* ptr = NULL;
|
2016-11-11 15:59:55 +01:00
|
|
|
const int length = MOV_get_string(tdbb, desc, &ptr, NULL, 0);
|
2013-11-07 19:41:27 +01:00
|
|
|
|
|
|
|
if (length == sizeof(RecordNumber::Packed))
|
|
|
|
{
|
|
|
|
const USHORT id = node->id;
|
|
|
|
Aligner<RecordNumber::Packed> alignedNumbers(ptr, length);
|
|
|
|
const RecordNumber::Packed* numbers = alignedNumbers;
|
|
|
|
RecordNumber rel_dbkey;
|
|
|
|
rel_dbkey.bid_decode(&numbers[id]);
|
|
|
|
// Decrement the value in order to switch back to the zero based numbering
|
|
|
|
// (from the user point of view the DB_KEY numbering starts from one)
|
|
|
|
rel_dbkey.decrement();
|
|
|
|
if (!bitmap_and || bitmap_and->test(rel_dbkey.getValue()))
|
|
|
|
RBM_SET(tdbb->getDefaultPool(), &impure->inv_bitmap, rel_dbkey.getValue());
|
|
|
|
}
|
2007-07-02 01:13:09 +02:00
|
|
|
}
|
|
|
|
|
2004-10-29 01:26:16 +02:00
|
|
|
return &impure->inv_bitmap;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2010-10-12 13:36:51 +02:00
|
|
|
case InversionNode::TYPE_INDEX:
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2010-10-12 13:36:51 +02:00
|
|
|
impure_inversion* impure = tdbb->getRequest()->getImpure<impure_inversion>(node->impure);
|
2004-09-28 08:28:38 +02:00
|
|
|
RecordBitmap::reset(impure->inv_bitmap);
|
2010-10-12 13:36:51 +02:00
|
|
|
BTR_evaluate(tdbb, node->retrieval, &impure->inv_bitmap, bitmap_and);
|
2004-10-29 01:26:16 +02:00
|
|
|
return &impure->inv_bitmap;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
2009-11-22 04:56:20 +01:00
|
|
|
BUGCHECK(230); // msg 230 EVL_bitmap: invalid operation
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2010-10-12 13:36:51 +02:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-18 06:56:06 +01:00
|
|
|
bool EVL_field(jrd_rel* relation, Record* record, USHORT id, dsc* desc)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* E V L _ f i e l d
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Evaluate a field by filling out a descriptor.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
DEV_BLKCHK(record, type_rec);
|
|
|
|
|
2009-07-16 15:09:00 +02:00
|
|
|
if (!record)
|
|
|
|
{
|
|
|
|
// ASF: Usage of ERR_warning with Arg::Gds (instead of Arg::Warning) is correct here.
|
|
|
|
// Maybe not all code paths are prepared for throwing an exception here,
|
|
|
|
// but it will leave the engine as an error (when testing for req_warning).
|
|
|
|
ERR_warning(Arg::Gds(isc_no_cur_rec));
|
2003-12-22 11:00:59 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2015-02-19 15:15:00 +01:00
|
|
|
const Format* format = record->getFormat();
|
|
|
|
fb_assert(format);
|
2003-02-13 18:28:38 +01:00
|
|
|
|
2015-02-19 15:15:00 +01:00
|
|
|
if (id < format->fmt_count)
|
2001-05-23 15:26:42 +02:00
|
|
|
*desc = format->fmt_desc[id];
|
2002-06-16 16:19:15 +02:00
|
|
|
|
2015-02-19 15:15:00 +01:00
|
|
|
if (id >= format->fmt_count || desc->isUnknown())
|
2003-02-13 18:28:38 +01:00
|
|
|
{
|
2015-02-19 15:15:00 +01:00
|
|
|
// Map a non-existent field to a default value, if available.
|
|
|
|
// This enables automatic format upgrade for data rows.
|
|
|
|
// Reference: Bug 10424, 10116
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2015-02-19 15:15:00 +01:00
|
|
|
if (relation)
|
2003-02-13 18:28:38 +01:00
|
|
|
{
|
2009-11-18 15:24:47 +01:00
|
|
|
thread_db* tdbb = JRD_get_thread_data();
|
|
|
|
|
2015-11-16 13:09:38 +01:00
|
|
|
const Format* const currentFormat = MET_current(tdbb, relation);
|
|
|
|
|
2015-02-19 15:15:00 +01:00
|
|
|
while (id >= format->fmt_defaults.getCount() ||
|
|
|
|
format->fmt_defaults[id].vlu_desc.isUnknown())
|
2009-11-18 15:24:47 +01:00
|
|
|
{
|
2015-11-16 13:09:38 +01:00
|
|
|
if (format->fmt_version >= currentFormat->fmt_version)
|
2009-11-18 15:24:47 +01:00
|
|
|
{
|
2009-11-27 03:33:40 +01:00
|
|
|
format = NULL;
|
|
|
|
break;
|
2009-11-18 15:24:47 +01:00
|
|
|
}
|
|
|
|
|
2009-11-27 03:33:40 +01:00
|
|
|
format = MET_format(tdbb, relation, format->fmt_version + 1);
|
2015-02-19 15:15:00 +01:00
|
|
|
fb_assert(format);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2015-02-19 15:15:00 +01:00
|
|
|
if (format)
|
|
|
|
{
|
|
|
|
*desc = format->fmt_defaults[id].vlu_desc;
|
|
|
|
|
|
|
|
if (record->isNull())
|
|
|
|
desc->dsc_flags |= DSC_null;
|
|
|
|
|
|
|
|
return !(desc->dsc_flags & DSC_null);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2005-10-28 10:11:35 +02:00
|
|
|
|
2011-02-12 21:26:24 +01:00
|
|
|
desc->makeText(1, ttype_ascii, (UCHAR*) " ");
|
2005-10-28 10:11:35 +02:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2009-11-22 04:56:20 +01:00
|
|
|
// If the offset of the field is 0, the field can't possible exist
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2015-02-19 15:15:00 +01:00
|
|
|
if (!desc->dsc_address)
|
2003-12-22 11:00:59 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2015-02-19 15:15:00 +01:00
|
|
|
desc->dsc_address = record->getData() + (IPTR) desc->dsc_address;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2013-03-17 18:35:53 +01:00
|
|
|
if (record->isNull(id))
|
2009-11-23 06:24:29 +01:00
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
desc->dsc_flags |= DSC_null;
|
2003-12-22 11:00:59 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2008-01-16 09:54:50 +01:00
|
|
|
|
|
|
|
desc->dsc_flags &= ~DSC_null;
|
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2004-10-09 03:40:32 +02:00
|
|
|
|
2011-02-11 01:43:15 +01:00
|
|
|
void EVL_make_value(thread_db* tdbb, const dsc* desc, impure_value* value, MemoryPool* pool)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* E V L _ m a k e _ v a l u e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2005-05-28 00:45:31 +02:00
|
|
|
* Make a value block reflect the value of a descriptor.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
2009-11-22 04:56:20 +01:00
|
|
|
// Handle the fixed length data types first. They're easy.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-04-12 13:56:32 +02:00
|
|
|
const dsc from = *desc;
|
2001-05-23 15:26:42 +02:00
|
|
|
value->vlu_desc = *desc;
|
2011-02-11 01:43:15 +01:00
|
|
|
value->vlu_desc.dsc_address = (UCHAR*) &value->vlu_misc;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-01-20 09:33:59 +01:00
|
|
|
switch (from.dsc_dtype)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
case dtype_short:
|
2011-02-11 01:43:15 +01:00
|
|
|
value->vlu_misc.vlu_short = *((SSHORT*) from.dsc_address);
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
case dtype_long:
|
|
|
|
case dtype_real:
|
|
|
|
case dtype_sql_time:
|
|
|
|
case dtype_sql_date:
|
2011-02-11 01:43:15 +01:00
|
|
|
value->vlu_misc.vlu_long = *((SLONG*) from.dsc_address);
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
case dtype_int64:
|
2011-02-11 01:43:15 +01:00
|
|
|
value->vlu_misc.vlu_int64 = *((SINT64*) from.dsc_address);
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
case dtype_double:
|
2011-02-11 01:43:15 +01:00
|
|
|
value->vlu_misc.vlu_double = *((double*) from.dsc_address);
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
|
|
|
|
2016-11-11 15:59:55 +01:00
|
|
|
case dtype_dec64:
|
|
|
|
value->vlu_misc.vlu_dec64 = *((Decimal64*) from.dsc_address);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case dtype_dec128:
|
|
|
|
value->vlu_misc.vlu_dec128 = *((Decimal128*) from.dsc_address);
|
|
|
|
return;
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
case dtype_timestamp:
|
|
|
|
case dtype_quad:
|
2011-02-11 01:43:15 +01:00
|
|
|
value->vlu_misc.vlu_dbkey[0] = ((SLONG*) from.dsc_address)[0];
|
|
|
|
value->vlu_misc.vlu_dbkey[1] = ((SLONG*) from.dsc_address)[1];
|
2001-05-23 15:26:42 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
case dtype_text:
|
|
|
|
case dtype_varying:
|
|
|
|
case dtype_cstring:
|
2009-07-09 16:04:42 +02:00
|
|
|
case dtype_dbkey:
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
2006-04-16 20:45:40 +02:00
|
|
|
|
|
|
|
case dtype_blob:
|
2011-02-11 01:43:15 +01:00
|
|
|
value->vlu_misc.vlu_bid = *(bid*) from.dsc_address;
|
2006-04-16 20:45:40 +02:00
|
|
|
return;
|
|
|
|
|
2010-12-18 03:17:06 +01:00
|
|
|
case dtype_boolean:
|
|
|
|
value->vlu_misc.vlu_uchar = *from.dsc_address;
|
|
|
|
return;
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
default:
|
2004-10-30 21:41:54 +02:00
|
|
|
fb_assert(false);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-04-29 16:00:32 +02:00
|
|
|
VaryStr<128> temp;
|
2008-04-14 17:22:52 +02:00
|
|
|
UCHAR* address;
|
|
|
|
USHORT ttype;
|
|
|
|
|
|
|
|
// Get string. If necessary, get_string will convert the string into a
|
|
|
|
// temporary buffer. Since this will always be the result of a conversion,
|
|
|
|
// this isn't a serious problem.
|
|
|
|
|
2016-11-11 15:59:55 +01:00
|
|
|
const USHORT length = MOV_get_string_ptr(tdbb, &from, &ttype, &address, &temp, sizeof(temp));
|
2008-04-14 17:22:52 +02:00
|
|
|
|
|
|
|
// Allocate a string block of sufficient size.
|
2011-02-11 01:43:15 +01:00
|
|
|
|
2008-04-14 17:22:52 +02:00
|
|
|
VaryingString* string = value->vlu_string;
|
2011-02-11 01:43:15 +01:00
|
|
|
|
2009-07-14 03:18:17 +02:00
|
|
|
if (string && string->str_length < length)
|
2009-07-09 16:04:42 +02:00
|
|
|
{
|
2008-04-14 17:22:52 +02:00
|
|
|
delete string;
|
|
|
|
string = NULL;
|
|
|
|
}
|
2011-02-11 01:43:15 +01:00
|
|
|
|
2009-07-14 03:18:17 +02:00
|
|
|
if (!string)
|
2009-07-09 16:04:42 +02:00
|
|
|
{
|
2011-02-11 01:43:15 +01:00
|
|
|
if (!pool)
|
|
|
|
pool = tdbb->getDefaultPool();
|
|
|
|
|
|
|
|
string = value->vlu_string = FB_NEW_RPT(*pool, length) VaryingString();
|
2008-04-14 17:22:52 +02:00
|
|
|
string->str_length = length;
|
|
|
|
}
|
|
|
|
|
|
|
|
value->vlu_desc.dsc_length = length;
|
|
|
|
UCHAR* target = string->str_data;
|
|
|
|
value->vlu_desc.dsc_address = target;
|
|
|
|
value->vlu_desc.dsc_sub_type = 0;
|
|
|
|
value->vlu_desc.dsc_scale = 0;
|
2011-02-11 01:43:15 +01:00
|
|
|
|
2009-07-09 16:04:42 +02:00
|
|
|
if (from.dsc_dtype == dtype_dbkey)
|
|
|
|
value->vlu_desc.dsc_dtype = dtype_dbkey;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
value->vlu_desc.dsc_dtype = dtype_text;
|
2009-11-28 20:39:23 +01:00
|
|
|
value->vlu_desc.setTextType(ttype);
|
2009-07-09 16:04:42 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-04-14 17:22:52 +02:00
|
|
|
if (address && length && target != address)
|
|
|
|
memcpy(target, address, length);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-01-17 02:19:01 +01:00
|
|
|
void EVL_validate(thread_db* tdbb, const Item& item, const ItemInfo* itemInfo, dsc* desc, bool null)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* E V L _ v a l i d a t e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Validate argument/variable for not null and check constraint
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
if (itemInfo == NULL)
|
|
|
|
return;
|
|
|
|
|
2007-12-03 16:46:39 +01:00
|
|
|
jrd_req* request = tdbb->getRequest();
|
2007-01-18 00:59:23 +01:00
|
|
|
bool err = false;
|
2007-01-17 02:19:01 +01:00
|
|
|
|
|
|
|
if (null && !itemInfo->nullable)
|
2007-01-18 00:59:23 +01:00
|
|
|
err = true;
|
|
|
|
|
|
|
|
const char* value = NULL_STRING_MARK;
|
2009-04-29 16:00:32 +02:00
|
|
|
VaryStr<128> temp;
|
2007-01-17 02:19:01 +01:00
|
|
|
|
|
|
|
MapFieldInfo::ValueType fieldInfo;
|
2007-01-18 00:59:23 +01:00
|
|
|
if (!err && itemInfo->fullDomain &&
|
2010-04-19 00:19:11 +02:00
|
|
|
request->getStatement()->mapFieldInfo.get(itemInfo->field, fieldInfo) &&
|
2010-11-07 21:26:11 +01:00
|
|
|
fieldInfo.validationExpr)
|
2007-01-17 02:19:01 +01:00
|
|
|
{
|
2008-08-12 09:22:12 +02:00
|
|
|
if (desc && null)
|
|
|
|
desc->dsc_flags |= DSC_null;
|
|
|
|
|
|
|
|
const bool desc_is_null = !desc || (desc->dsc_flags & DSC_null);
|
|
|
|
|
2007-01-17 02:19:01 +01:00
|
|
|
request->req_domain_validation = desc;
|
2015-09-24 18:19:18 +02:00
|
|
|
const ULONG flags = request->req_flags;
|
2007-01-17 02:19:01 +01:00
|
|
|
|
2010-11-07 21:26:11 +01:00
|
|
|
if (!fieldInfo.validationExpr->execute(tdbb, request) && !(request->req_flags & req_null))
|
2007-01-17 02:19:01 +01:00
|
|
|
{
|
2008-08-12 09:22:12 +02:00
|
|
|
const USHORT length = desc_is_null ? 0 :
|
2016-11-11 15:59:55 +01:00
|
|
|
MOV_make_string(tdbb, desc, ttype_dynamic, &value, &temp, sizeof(temp) - 1);
|
2007-01-17 02:19:01 +01:00
|
|
|
|
2008-08-12 09:22:12 +02:00
|
|
|
if (desc_is_null)
|
2007-01-17 02:19:01 +01:00
|
|
|
value = NULL_STRING_MARK;
|
|
|
|
else if (!length)
|
|
|
|
value = "";
|
|
|
|
else
|
2008-08-27 14:20:47 +02:00
|
|
|
const_cast<char*>(value)[length] = 0; // safe cast - data is on our local stack
|
2007-01-17 02:19:01 +01:00
|
|
|
|
2007-01-18 00:59:23 +01:00
|
|
|
err = true;
|
|
|
|
}
|
2007-05-18 03:50:26 +02:00
|
|
|
|
|
|
|
request->req_flags = flags;
|
2007-01-18 00:59:23 +01:00
|
|
|
}
|
|
|
|
|
2008-08-30 05:07:35 +02:00
|
|
|
Firebird::string s;
|
|
|
|
|
2007-01-18 00:59:23 +01:00
|
|
|
if (err)
|
|
|
|
{
|
|
|
|
ISC_STATUS status = isc_not_valid_for_var;
|
|
|
|
const char* arg;
|
|
|
|
|
2010-10-12 13:36:51 +02:00
|
|
|
if (item.type == Item::TYPE_CAST)
|
2007-01-18 00:59:23 +01:00
|
|
|
{
|
Refactor a number of expression nodes: nod_add, nod_divide, nod_multiply, nod_negate, nod_user_name, nod_subtract, nod_current_date, nod_current_time, nod_current_timestamp, nod_add2, nod_subtract2, nod_multiply2, nod_divide2, nod_current_role, nod_internal_info
2010-09-04 23:36:41 +02:00
|
|
|
status = isc_not_valid_for;
|
|
|
|
arg = "CAST";
|
|
|
|
}
|
|
|
|
else
|
2003-12-11 11:33:30 +01:00
|
|
|
{
|
Refactor a number of expression nodes: nod_add, nod_divide, nod_multiply, nod_negate, nod_user_name, nod_subtract, nod_current_date, nod_current_time, nod_current_timestamp, nod_add2, nod_subtract2, nod_multiply2, nod_divide2, nod_current_role, nod_internal_info
2010-09-04 23:36:41 +02:00
|
|
|
if (itemInfo->name.isEmpty())
|
2009-08-04 15:01:53 +02:00
|
|
|
{
|
Refactor a number of expression nodes: nod_add, nod_divide, nod_multiply, nod_negate, nod_user_name, nod_subtract, nod_current_date, nod_current_time, nod_current_timestamp, nod_add2, nod_subtract2, nod_multiply2, nod_divide2, nod_current_role, nod_internal_info
2010-09-04 23:36:41 +02:00
|
|
|
int index = item.index + 1;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
Refactor a number of expression nodes: nod_add, nod_divide, nod_multiply, nod_negate, nod_user_name, nod_subtract, nod_current_date, nod_current_time, nod_current_timestamp, nod_add2, nod_subtract2, nod_multiply2, nod_divide2, nod_current_role, nod_internal_info
2010-09-04 23:36:41 +02:00
|
|
|
status = isc_not_valid_for;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2010-10-12 13:36:51 +02:00
|
|
|
if (item.type == Item::TYPE_VARIABLE)
|
Refactor a number of expression nodes: nod_add, nod_divide, nod_multiply, nod_negate, nod_user_name, nod_subtract, nod_current_date, nod_current_time, nod_current_timestamp, nod_add2, nod_subtract2, nod_multiply2, nod_divide2, nod_current_role, nod_internal_info
2010-09-04 23:36:41 +02:00
|
|
|
{
|
|
|
|
const jrd_prc* procedure = request->getStatement()->procedure;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
Refactor a number of expression nodes: nod_add, nod_divide, nod_multiply, nod_negate, nod_user_name, nod_subtract, nod_current_date, nod_current_time, nod_current_timestamp, nod_add2, nod_subtract2, nod_multiply2, nod_divide2, nod_current_role, nod_internal_info
2010-09-04 23:36:41 +02:00
|
|
|
if (procedure)
|
|
|
|
{
|
2011-10-16 22:36:07 +02:00
|
|
|
if (index <= int(procedure->getOutputFields().getCount()))
|
Refactor a number of expression nodes: nod_add, nod_divide, nod_multiply, nod_negate, nod_user_name, nod_subtract, nod_current_date, nod_current_time, nod_current_timestamp, nod_add2, nod_subtract2, nod_multiply2, nod_divide2, nod_current_role, nod_internal_info
2010-09-04 23:36:41 +02:00
|
|
|
s.printf("output parameter number %d", index);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
s.printf("variable number %d",
|
2011-10-16 22:36:07 +02:00
|
|
|
index - int(procedure->getOutputFields().getCount()));
|
Refactor a number of expression nodes: nod_add, nod_divide, nod_multiply, nod_negate, nod_user_name, nod_subtract, nod_current_date, nod_current_time, nod_current_timestamp, nod_add2, nod_subtract2, nod_multiply2, nod_divide2, nod_current_role, nod_internal_info
2010-09-04 23:36:41 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
s.printf("variable number %d", index);
|
|
|
|
}
|
2010-10-12 13:36:51 +02:00
|
|
|
else if (item.type == Item::TYPE_PARAMETER && item.subType == 0)
|
Refactor a number of expression nodes: nod_add, nod_divide, nod_multiply, nod_negate, nod_user_name, nod_subtract, nod_current_date, nod_current_time, nod_current_timestamp, nod_add2, nod_subtract2, nod_multiply2, nod_divide2, nod_current_role, nod_internal_info
2010-09-04 23:36:41 +02:00
|
|
|
s.printf("input parameter number %d", (index - 1) / 2 + 1);
|
2010-10-12 13:36:51 +02:00
|
|
|
else if (item.type == Item::TYPE_PARAMETER && item.subType == 1)
|
Refactor a number of expression nodes: nod_add, nod_divide, nod_multiply, nod_negate, nod_user_name, nod_subtract, nod_current_date, nod_current_time, nod_current_timestamp, nod_add2, nod_subtract2, nod_multiply2, nod_divide2, nod_current_role, nod_internal_info
2010-09-04 23:36:41 +02:00
|
|
|
s.printf("output parameter number %d", index);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
Refactor a number of expression nodes: nod_add, nod_divide, nod_multiply, nod_negate, nod_user_name, nod_subtract, nod_current_date, nod_current_time, nod_current_timestamp, nod_add2, nod_subtract2, nod_multiply2, nod_divide2, nod_current_role, nod_internal_info
2010-09-04 23:36:41 +02:00
|
|
|
if (s.isEmpty())
|
|
|
|
arg = UNKNOWN_STRING_MARK;
|
|
|
|
else
|
|
|
|
arg = s.c_str();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
arg = itemInfo->name.c_str();
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
Refactor a number of expression nodes: nod_add, nod_divide, nod_multiply, nod_negate, nod_user_name, nod_subtract, nod_current_date, nod_current_time, nod_current_timestamp, nod_add2, nod_subtract2, nod_multiply2, nod_divide2, nod_current_role, nod_internal_info
2010-09-04 23:36:41 +02:00
|
|
|
ERR_post(Arg::Gds(status) << Arg::Str(arg) << Arg::Str(value));
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|