📄 pass1.c
字号:
/* * PROGRAM: Dynamic SQL runtime support * MODULE: pass1.c * DESCRIPTION: First-pass compiler for request trees. * * 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.26: Claudio Valderrama: COMPUTED fields will be skipped if a dummy * "insert into tbl values(...)" sentence is issued. * 2001.5.26: Claudio Valderrama: field names should be skimmed from trailing * blanks to allow reliable comparisons in pass1_field. Same for table and * and index names in plans. * 2001.5.29: Claudio Valderrama: handle DROP VIEW case in pass1_statement(). * 2001.6.12: Claudio Valderrama: add basic BREAK capability to procedures. * 2001.6.27: Claudio Valderrama: pass1_variable() now gives the name of the * variable it can't find in the error message. * 2001.6.30: Claudio Valderrama: Enhanced again to provide (line, col), see node.h. * 2001.7.28: John Bellardo: added code to handle nod_limit and associated fields. * 2001.08.14 Claudio Valderrama: fixed crash with trigger and CURRENT OF <cursor> syntax. * 2001.09.10 John Bellardo: fixed gen_rse to attribute skip/first nodes to the parent_rse * if present instead of the child rse. BUG #451798 * 2001.09.26 Claudio Valderrama: ambiguous field names are rejected from now. * 2001.10.01 Claudio Valderrama: check constraints are allowed to have ambiguous field * names because they use OLD and NEW as aliases of the same table. However, if the * check constraint has an embedded ambiguous SELECT statement, it won't be detected. * The code should be revisited if check constraints' before delete triggers are used * for whatever reason. Currently they are never generated. The code can be improved * to not report errors for fields between NEW and OLD contexts but complain otherwise. * 2001.10.05 Neil McCalden: validate udf and parameters when comparing select list and * group by list, to detect invalid SQL statements when grouping by UDFs. */#include "../jrd/ib_stdio.h"#include <string.h>#include "../dsql/dsql.h"#include "../dsql/node.h"#include "../dsql/sym.h"#include "../jrd/codes.h"#include "../jrd/thd.h"#include "../jrd/intl.h"#include "../jrd/blr.h"#include "../jrd/gds.h"#include "../dsql/alld_proto.h"#include "../dsql/ddl_proto.h"#include "../dsql/errd_proto.h"#include "../dsql/hsh_proto.h"#include "../dsql/make_proto.h"#include "../dsql/metd_proto.h"#include "../dsql/pass1_proto.h"#include "../jrd/dsc_proto.h"#include "../jrd/thd_proto.h"ASSERT_FILENAME /* Define things assert() needs */static BOOLEAN aggregate_found (REQ, NOD, NOD *);static BOOLEAN aggregate_found2 (REQ, NOD, NOD *, BOOLEAN *);static void assign_fld_dtype_from_dsc (FLD, DSC *);static NOD compose (NOD, NOD, NOD_TYPE);static NOD copy_field (NOD, CTX);static NOD copy_fields (NOD, CTX);static void explode_asterisk (NOD, NOD, LLS *);static NOD explode_outputs (REQ, PRC);static void field_error (TEXT *, TEXT *, NOD);static PAR find_dbkey (REQ, NOD);static PAR find_record_version (REQ, NOD);static BOOLEAN invalid_reference (NOD, NOD);static void mark_ctx_outer_join (NOD);static BOOLEAN node_match (NOD, NOD);static NOD pass1_alias_list (REQ, NOD);static CTX pass1_alias (REQ, STR);static NOD pass1_any (REQ, NOD, NOD_TYPE);static DSQL_REL pass1_base_table (REQ, DSQL_REL, STR);static void pass1_blob (REQ, NOD);static NOD pass1_collate (REQ, NOD, STR);static NOD pass1_constant (REQ, NOD);static NOD pass1_cursor (REQ, NOD, NOD);static CTX pass1_cursor_context (REQ, NOD, NOD);static NOD pass1_dbkey (REQ, NOD);static NOD pass1_delete (REQ, NOD);static NOD pass1_field (REQ, NOD, USHORT, USHORT *);static NOD pass1_insert (REQ, NOD);static NOD pass1_node (REQ, NOD, USHORT, USHORT *);static NOD pass1_relation (REQ, NOD);static NOD pass1_rse (REQ, NOD, NOD);static NOD pass1_sel_list ( REQ, NOD);static NOD pass1_sort (REQ, NOD, NOD);static NOD pass1_udf (REQ, NOD, USHORT);static void pass1_udf_args (REQ, NOD, LLS *, USHORT);static NOD pass1_union (REQ, NOD, NOD);static NOD pass1_update (REQ, NOD);static NOD pass1_variable (REQ, NOD);static NOD post_map (NOD, CTX);static void remap_streams_to_parent_context (NOD, CTX);static FLD resolve_context (REQ, STR, STR, CTX, DSQL_REL*, PRC*);static BOOLEAN set_parameter_type (NOD, NOD, BOOLEAN);static void set_parameters_name (NOD, NOD);static void set_parameter_name (NOD, NOD, DSQL_REL);static TEXT *pass_exact_name (TEXT *);STR temp_collation_name = NULL;#define DB_KEY_STRING "DB_KEY" /* NTX: pseudo field name */#define MAX_MEMBER_LIST 1500 /* Maximum members in "IN" list. * For eg. SELECT * FROM T WHERE * F IN (1, 2, 3, ...) * * Bug 10061, bsriram - 19-Apr-1999 */#define FIREBIRD_REJECT_AMBIGUITYCTX PASS1_make_context ( REQ request, NOD relation_node){/************************************** * * P A S S 1 _ m a k e _ c o n t e x t * ************************************** * * Functional description * Generate a context for a request. * **************************************/CTX context, conflict;STR relation_name, string;DSQL_REL relation;PRC procedure;FLD field;NOD *input;LLS stack;TEXT *conflict_name;STATUS error_code;struct nod desc_node;TSQL tdsql;USHORT count;DEV_BLKCHK (request, type_req);DEV_BLKCHK (relation_node, type_nod);tdsql = GET_THREAD_DATA;relation = NULL;procedure = NULL;/* figure out whether this is a relation or a procedure and give an error if it is neither */if (relation_node->nod_type == nod_rel_proc_name) relation_name = (STR) relation_node->nod_arg [e_rpn_name];else relation_name = (STR) relation_node->nod_arg [e_rln_name];/* CVC: Let's skim the context, too. */if (relation_name && relation_name -> str_data) pass_exact_name (relation_name -> str_data);DEV_BLKCHK (relation_name, type_str);if ((relation_node->nod_type == nod_rel_proc_name) && relation_node->nod_arg [e_rpn_inputs]){ if (!(procedure = METD_get_procedure (request, relation_name))) { TEXT linecol [64]; sprintf (linecol, "At line %d, column %d.", (int) relation_node->nod_line, (int) relation_node->nod_column); ERRD_post (gds__sqlerr, gds_arg_number, (SLONG) -204, gds_arg_gds, gds__dsql_procedure_err, gds_arg_gds, gds__random, gds_arg_string, relation_name->str_data, gds_arg_gds, gds__random, gds_arg_string, linecol, 0); }}else{ if (!(relation = METD_get_relation (request, relation_name)) && (relation_node->nod_type == nod_rel_proc_name)) procedure = METD_get_procedure (request, relation_name); if (!relation && !procedure) { TEXT linecol [64]; sprintf (linecol, "At line %d, column %d.", (int) relation_node->nod_line, (int) relation_node->nod_column); ERRD_post (gds__sqlerr, gds_arg_number, (SLONG) -204, gds_arg_gds, gds__dsql_relation_err, gds_arg_gds, gds__random, gds_arg_string, relation_name->str_data, gds_arg_gds, gds__random, gds_arg_string, linecol, 0); }}if (procedure && !procedure->prc_out_count){ TEXT linecol [64]; sprintf (linecol, "At line %d, column %d.", (int) relation_node->nod_line, (int) relation_node->nod_column); ERRD_post (gds__sqlerr, gds_arg_number, (SLONG) -84, gds_arg_gds, gds__dsql_procedure_use_err, gds_arg_string, relation_name->str_data, gds_arg_gds, gds__random, gds_arg_string, linecol, 0);}/* Set up context block */context = (CTX) ALLOCD (type_ctx);context->ctx_relation = relation;context->ctx_procedure = procedure;context->ctx_request = request;context->ctx_context = request->req_context_number++;context->ctx_scope_level = request->req_scope_level;/* find the context alias name, if it exists */if (relation_node->nod_type == nod_rel_proc_name) string = (STR) relation_node->nod_arg [e_rpn_alias];else string = (STR) relation_node->nod_arg [e_rln_alias];DEV_BLKCHK (string, type_str);if (string) { context->ctx_alias = (TEXT*) string->str_data; /* check to make sure the context is not already used at this same query level (if there are no subqueries, this checks that the alias is not used twice in the request) */ for (stack = request->req_context; stack; stack = stack->lls_next) { conflict = (CTX) stack->lls_object; if (conflict->ctx_scope_level != context->ctx_scope_level) continue; if (conflict->ctx_alias) { conflict_name = conflict->ctx_alias; error_code = gds__alias_conflict_err; /* alias %s conflicts with an alias in the same statement */ } else if (conflict->ctx_procedure) { conflict_name = conflict->ctx_procedure->prc_name; error_code = gds__procedure_conflict_error; /* alias %s conflicts with a procedure in the same statement */ } else if (conflict->ctx_relation) { conflict_name = conflict->ctx_relation->rel_name; error_code = gds__relation_conflict_err; /* alias %s conflicts with a relation in the same statement */ } else continue; if (!strcmp (conflict_name, context->ctx_alias)) ERRD_post (gds__sqlerr, gds_arg_number, (SLONG) -204, gds_arg_gds, error_code, gds_arg_string, conflict_name, 0); } } if (procedure) { if (request->req_scope_level == 1) request->req_flags |= REQ_no_batch; if (relation_node->nod_arg [e_rpn_inputs]) { context->ctx_proc_inputs = PASS1_node (request, relation_node->nod_arg [e_rpn_inputs], 0); count = context->ctx_proc_inputs->nod_count; } else count = 0; if (!(request->req_type & REQ_procedure)) { if (count != procedure->prc_in_count) ERRD_post (gds__prcmismat, gds_arg_string, relation_name->str_data, 0); if (count) { /* Initialize this stack variable, and make it look like a node */ memset ((SCHAR *) &desc_node, 0, sizeof (desc_node)); desc_node.nod_header.blk_type = type_nod; for (input = context->ctx_proc_inputs->nod_arg, field = procedure->prc_inputs; field; input++, field = field->fld_next) { DEV_BLKCHK (field, type_fld); DEV_BLKCHK (*input, type_nod); MAKE_desc_from_field (&desc_node.nod_desc, field); set_parameter_type (*input, &desc_node, FALSE); } } } }/* push the context onto the request context stack for matching fields against */LLS_PUSH (context, &request->req_context);return context;}NOD PASS1_node ( REQ request, NOD input, USHORT proc_flag){/************************************** * * P A S S 1 _ n o d e * ************************************** * * Functional description * Compile a parsed request into something more interesting. * CVC: This function now is a wrapper around pass1_node(). * **************************************/ USHORT fcount; return pass1_node (request, input, proc_flag, &fcount);}NOD PASS1_rse ( REQ request, NOD input, NOD order){/************************************** * * P A S S 1 _ r s e * ************************************** * * Functional description * Compile a record selection expression, * bumping up the request scope level * everytime an rse is seen. The scope * level controls parsing of aliases. * **************************************/NOD node;int foo;DEV_BLKCHK (request, type_req);DEV_BLKCHK (input, type_nod);DEV_BLKCHK (order, type_nod);request->req_scope_level++;foo = request->req_scope_level;node = pass1_rse (request, input, order);request->req_scope_level--;return node;}NOD PASS1_statement ( REQ request, NOD input, USHORT proc_flag){/************************************** * * P A S S 1 _ s t a t e m e n t * ************************************** * * Functional description * Compile a parsed request into something more interesting. * **************************************/NOD node, *ptr, *end, *ptr2, *end2, into_in, into_out, procedure, cursor, temp, parameters, variables;LLS base;FLD field, field2;STR name;struct nod desc_node;USHORT count;/*CTX context;*/DEV_BLKCHK (request, type_req);DEV_BLKCHK (input, type_nod);#ifdef DEV_BUILDif (DSQL_debug > 2) DSQL_pretty (input, 0);#endifbase = request->req_context;/* Dispatch on node type. Fall thru on easy ones */switch (input->nod_type) { case nod_def_relation: case nod_redef_relation: case nod_def_index: case nod_def_view: case nod_def_constraint: case nod_def_exception: case nod_mod_relation: case nod_mod_exception: case nod_del_relation: /* CVC: Deleting view is a new case. */ case nod_del_view: case nod_del_index: case nod_del_exception: case nod_grant: case nod_revoke: case nod_def_database: case nod_mod_database: case nod_def_generator: case nod_def_role: case nod_del_role: case nod_del_generator: case nod_def_filter: case nod_del_filter: case nod_def_domain: case nod_del_domain: case nod_mod_domain: case nod_def_udf: case nod_del_udf: case nod_def_shadow: case nod_del_shadow: case nod_mod_index: case nod_set_statistics: request->req_type = REQ_DDL; return input; case nod_def_trigger: case nod_mod_trigger: case nod_del_trigger: request->req_type = REQ_DDL; request->req_flags |= REQ_procedure; request->req_flags |= REQ_trigger; return input; case nod_del_procedure: request->req_type = REQ_DDL; request->req_flags |= REQ_procedure; return input; case nod_def_procedure: case nod_redef_procedure: case nod_mod_procedure: request->req_type = REQ_DDL; request->req_flags |= REQ_procedure;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -