8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-24 14:03:02 +01:00
firebird-mirror/src/qli/parse.cpp

5532 lines
122 KiB
C++
Raw Normal View History

2001-05-23 15:26:42 +02:00
/*
* PROGRAM: JRD Command Oriented Query Language
* MODULE: parse.cpp
2001-05-23 15:26:42 +02:00
* DESCRIPTION: Statement parser
*
* 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): ______________________________________.
*/
#include "firebird.h"
2004-04-29 00:36:29 +02:00
#include <stdio.h>
2001-05-23 15:26:42 +02:00
#include <stdlib.h>
#include <string.h>
#include "../qli/dtr.h"
#include "../qli/exe.h" // This is only included to suppress a compiler warning
2001-05-23 15:26:42 +02:00
#include "../qli/parse.h"
#include "../qli/compile.h"
#include "../qli/report.h"
#include "../qli/all_proto.h"
#include "../qli/err_proto.h"
#include "../qli/hsh_proto.h"
#include "../qli/lex_proto.h"
#include "../qli/mov_proto.h"
#include "../qli/parse_proto.h"
#include "../qli/proc_proto.h"
#include "../jrd/gdsassert.h"
#include "../jrd/constants.h"
2001-05-23 15:26:42 +02:00
using MsgFormat::SafeArg;
2001-05-23 15:26:42 +02:00
#define KEYWORD(kw) (QLI_token->tok_keyword == kw)
2004-03-07 08:58:55 +01:00
#define INT_CAST (qli_syntax*) (IPTR)
2001-05-23 15:26:42 +02:00
static void check_end(void);
static void command_end(void);
2004-02-02 12:02:12 +01:00
static DBB get_dbb(qli_symbol*);
2004-03-07 08:58:55 +01:00
static qli_syntax* make_list(qli_lls*);
2001-05-23 15:26:42 +02:00
static NAM make_name(void);
2004-02-02 12:02:12 +01:00
static qli_const* make_numeric_constant(const TEXT*, USHORT);
static TEXT* make_string(const TEXT*, USHORT);
2004-03-07 08:58:55 +01:00
static qli_syntax* negate(qli_syntax*);
2001-05-23 15:26:42 +02:00
static KWWORDS next_keyword(void);
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_abort(void);
static qli_syntax* parse_accept(void);
2004-03-14 06:51:54 +01:00
static qli_syntax* parse_add(USHORT *, bool *);
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_and(USHORT *);
static qli_syntax* parse_assignment(void);
static qli_syntax* parse_boolean(USHORT *);
static qli_syntax* parse_copy(void);
2001-05-23 15:26:42 +02:00
static DBB parse_database(void);
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_declare(void);
static qli_syntax* parse_define(void);
static qli_syntax* parse_def_index(void);
static qli_syntax* parse_def_relation(void);
static qli_syntax* parse_delete(void);
static qli_syntax* parse_drop(void);
2001-05-23 15:26:42 +02:00
static int parse_dtype(USHORT *, USHORT *);
static int parse_dtype_subtype(void);
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_edit(void);
2004-02-02 12:02:12 +01:00
static TEXT* parse_edit_string(void);
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_erase(void);
static qli_syntax* parse_extract(void);
static qli_fld* parse_field(bool);
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_field_name(qli_syntax* *);
static qli_syntax* parse_for(void);
static qli_syntax* parse_from(USHORT*, bool*);
static qli_syntax* parse_function(void);
2004-02-02 12:02:12 +01:00
static TEXT* parse_header(void);
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_help(void);
static qli_syntax* parse_if(void);
static qli_syntax* parse_in(qli_syntax*, NOD_T, bool);
static qli_syntax* parse_insert(void);
2001-05-23 15:26:42 +02:00
static NOD_T parse_join_type(void);
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_list_fields(void);
2004-02-02 12:02:12 +01:00
static qli_const* parse_literal(void);
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_matches(void);
2001-05-23 15:26:42 +02:00
static void parse_matching_paren(void);
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_modify(void);
static qli_syntax* parse_modify_index(void);
static qli_syntax* parse_modify_relation(void);
static qli_syntax* parse_multiply(USHORT*, bool*);
2001-05-23 15:26:42 +02:00
static NAM parse_name(void);
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_not(USHORT *);
2001-05-23 15:26:42 +02:00
static int parse_ordinal(void);
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_output(void);
static qli_syntax* parse_primitive_value(USHORT*, bool*);
static qli_syntax* parse_print_list(void);
static qli_syntax* parse_print(void);
static qli_syntax* parse_prompt(void);
2001-05-23 15:26:42 +02:00
static QFL parse_qualified_filter(void);
static QFN parse_qualified_function(void);
static QPR parse_qualified_procedure(void);
2004-02-02 12:02:12 +01:00
static qli_rel* parse_qualified_relation(void);
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_ready(NOD_T);
static qli_syntax* parse_relational(USHORT*);
static qli_syntax* parse_relation(void);
static qli_syntax* parse_rename(void);
static qli_syntax* parse_repeat(void);
static qli_syntax* parse_report(void);
static qli_syntax* parse_rse(void);
static qli_syntax* parse_select(void);
static qli_syntax* parse_set(void);
static qli_syntax* parse_shell(void);
static qli_syntax* parse_show(void);
static qli_syntax* parse_sort(void);
static qli_syntax* parse_sql_alter(void);
static qli_syntax* parse_sql_create(void);
static int parse_sql_dtype(USHORT* length, USHORT* scale, USHORT* precision,
USHORT* sub_type);
2004-02-02 12:02:12 +01:00
static qli_fld* parse_sql_field(void);
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_sql_grant_revoke(USHORT);
static qli_syntax* parse_sql_index_create(const bool, const bool);
static qli_syntax* parse_sql_joined_relation(qli_syntax*);
static qli_syntax* parse_sql_join_clause(qli_syntax*);
static qli_syntax* parse_sql_table_create(void);
#ifdef NOT_USED_OR_REPLACED
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_sql_view_create(void);
#endif
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_sql_relation(void);
static qli_syntax* parse_sql_rse(void);
static qli_syntax* parse_sql_singleton_select(void);
static qli_syntax* parse_sql_subquery(void);
static qli_syntax* parse_statement(void);
static qli_syntax* parse_statistical(void);
static qli_syntax* parse_store(void);
2001-05-23 15:26:42 +02:00
static TEXT *parse_string(void);
2004-02-02 12:02:12 +01:00
static qli_symbol* parse_symbol(void);
static void parse_terminating_parens(USHORT*, USHORT*);
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_transaction(NOD_T);
static qli_syntax* parse_udf_or_field(void);
static qli_syntax* parse_update(void);
static qli_syntax* parse_value(USHORT*, bool*);
static bool potential_rse(void);
2004-02-02 12:02:12 +01:00
static qli_rel* resolve_relation(qli_symbol*, qli_symbol*);
2004-03-07 08:58:55 +01:00
static qli_syntax* syntax_node(NOD_T, USHORT);
static bool test_end(void);
2001-05-23 15:26:42 +02:00
typedef struct {
SLONG gds_quad_high;
ULONG gds_quad_low;
} gds_quad;
/*
The following flags are:
2001-05-23 15:26:42 +02:00
sql_flag indicates whether we are parsing in a SQL environment.
2001-05-23 15:26:42 +02:00
The flag is used to turn off automatic end-of-command
recognition.
else_count indicates the depth of if/then/else's
sw_report indicates whether we're in a report statement
sw_statement indicates that we're actively parsing a statement/command
sw_sql_view indicates parsing a SQL VIEW, so restrict the select.
*/
static USHORT sql_flag, else_count, sw_report;
static bool sw_statement, sw_sql_view;
static SSHORT function_count; // indicates the depth of UDF calls
2001-05-23 15:26:42 +02:00
struct nod_types {
2001-05-23 15:26:42 +02:00
KWWORDS nod_t_keyword;
NOD_T nod_t_node;
NOD_T nod_t_rpt_node;
NOD_T nod_t_sql_node;
};
static const nod_types statisticals[] = {
{ KW_MAX, nod_max, nod_rpt_max, nod_agg_max },
{ KW_MIN, nod_min, nod_rpt_min, nod_agg_min },
{ KW_COUNT, nod_count, nod_rpt_count, nod_agg_count },
{ KW_AVERAGE, nod_average, nod_rpt_average, nod_agg_average },
{ KW_TOTAL, nod_total, nod_rpt_total, nod_agg_total },
{ KW_none, nod_any, nod_any, nod_any }
};
2001-05-23 15:26:42 +02:00
static const NOD_T relationals[] = {
2001-05-23 15:26:42 +02:00
nod_eql, nod_neq, nod_leq, nod_lss, nod_gtr, nod_geq, nod_containing,
nod_like, nod_starts, nod_missing, nod_between, nod_sleuth,
nod_matches, nod_and, nod_or, nod_not, nod_any, nod_unique, (NOD_T) 0
};
2004-03-07 08:58:55 +01:00
qli_syntax* PARQ_parse(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* P A R Q _ p a r s e
*
**************************************
*
* Functional description
* Parse a single statement or command.
*
**************************************/
sql_flag = else_count = sw_report = 0;
sw_statement = true;
2001-05-23 15:26:42 +02:00
switch (next_keyword()) {
case KW_COMMIT:
return parse_transaction(nod_commit);
case KW_COPY:
return parse_copy();
case KW_EXIT:
2004-05-16 03:42:11 +02:00
return syntax_node(nod_exit, 0);
2001-05-23 15:26:42 +02:00
case KW_EXTRACT:
return parse_extract();
case KW_QUIT:
2004-05-16 03:42:11 +02:00
return syntax_node(nod_quit, 0);
2001-05-23 15:26:42 +02:00
case KW_DELETE:
case KW_DROP:
{
2004-03-07 08:58:55 +01:00
qli_syntax* node = parse_drop();
if (node)
return node;
node = parse_delete();
check_end();
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_THEN))
return node;
qli_lls* stack = NULL;
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) node, &stack);
ALLQ_push((blk*) parse_statement(), &stack);
return make_list(stack);
}
2001-05-23 15:26:42 +02:00
case KW_DEFINE:
return parse_define();
case KW_CREATE:
return parse_sql_create();
case KW_ALTER:
return parse_sql_alter();
case KW_EDIT:
return parse_edit();
case KW_FINISH:
return parse_transaction(nod_finish);
case KW_GRANT:
return parse_sql_grant_revoke(nod_sql_grant);
case KW_HELP:
return parse_help();
case KW_PREPARE:
return parse_transaction(nod_prepare);
case KW_READY:
return parse_ready(nod_ready);
case KW_RENAME:
return parse_rename();
case KW_REVOKE:
return parse_sql_grant_revoke(nod_sql_revoke);
case KW_ROLLBACK:
return parse_transaction(nod_rollback);
case KW_SET:
return parse_set();
case KW_SHELL:
return parse_shell();
case KW_SHOW:
return parse_show();
}
return parse_statement();
}
2004-03-07 08:58:55 +01:00
bool PAR_match( KWWORDS keyword)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* P A R _ m a t c h
*
**************************************
*
* Functional description
* Test the current token for a particular keyword.
* If so, advance the token stream.
*
**************************************/
if (KEYWORD(keyword)) {
PAR_token();
2004-03-07 08:58:55 +01:00
return true;
2001-05-23 15:26:42 +02:00
}
2004-05-29 07:03:08 +02:00
for (const qli_symbol* symbol = QLI_token->tok_symbol; symbol;
symbol = symbol->sym_homonym)
{
2001-05-23 15:26:42 +02:00
if (symbol->sym_type == SYM_keyword &&
symbol->sym_keyword == (int) keyword)
{
2001-05-23 15:26:42 +02:00
PAR_token();
2004-03-07 08:58:55 +01:00
return true;
2001-05-23 15:26:42 +02:00
}
2004-05-29 07:03:08 +02:00
}
2001-05-23 15:26:42 +02:00
2004-03-07 08:58:55 +01:00
return false;
2001-05-23 15:26:42 +02:00
}
void PAR_real(void)
{
/**************************************
*
* P A R _ r e a l
*
**************************************
*
* Functional description
* Get a real (not EOL) token.
*
* If the token is an end of line, get the next token.
* If the next token is a colon, start reading the
* procedure.
*
**************************************/
while ((QLI_token->tok_type == tok_eol) || KEYWORD(KW_continuation))
LEX_token();
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_COLON)) {
DBB database = parse_database();
2001-05-23 15:26:42 +02:00
PRO_invoke(database, QLI_token->tok_string);
}
}
void PAR_real_token(void)
{
/**************************************
*
* P A R _ r e a l _ t o k e n
*
**************************************
*
* Functional description
* Composition of PAR_token followed by PAR_real.
*
**************************************/
PAR_token();
PAR_real();
}
void PAR_token(void)
{
/**************************************
*
* P A R _ t o k e n
*
**************************************
*
* Functional description
* Get the next token.
2001-05-23 15:26:42 +02:00
* If it's a procedure invocation, handle it
* or complain and get rid of the evidence.
*
**************************************/
for (;;) {
LEX_token();
if (!(KEYWORD(KW_continuation)) &&
!(sw_statement && QLI_semi && QLI_token->tok_type == tok_eol))
2004-05-29 07:03:08 +02:00
{
2001-05-23 15:26:42 +02:00
break;
2004-05-29 07:03:08 +02:00
}
2001-05-23 15:26:42 +02:00
}
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_COLON)) {
2001-05-23 15:26:42 +02:00
if (!QLI_databases) {
ERRQ_error_format(159); // Msg159 no databases are ready
2001-05-23 15:26:42 +02:00
ERRQ_pending();
LEX_token();
}
else {
DBB database = parse_database();
2001-05-23 15:26:42 +02:00
PRO_invoke(database, QLI_token->tok_string);
}
}
}
static void check_end(void)
{
/**************************************
*
* c h e c k _ e n d
*
**************************************
*
* Functional description
* Check for end of statement. If it isn't complain bitterly.
*
**************************************/
if (QLI_token->tok_type == tok_eol ||
KEYWORD(KW_SEMI) ||
KEYWORD(KW_THEN) || (else_count && KEYWORD(KW_ELSE)))
{
sw_statement = false;
2001-05-23 15:26:42 +02:00
return;
}
2004-05-16 03:42:11 +02:00
ERRQ_syntax(161); // Msg161 end of statement
2001-05-23 15:26:42 +02:00
}
static void command_end(void)
{
/**************************************
*
* c o m m a n d _ e n d
*
**************************************
*
* Functional description
* Check for end of command. If it isn't complain bitterly.
*
**************************************/
if (QLI_token->tok_type == tok_eol || KEYWORD(KW_SEMI)) {
sw_statement = false;
2001-05-23 15:26:42 +02:00
return;
}
2004-05-16 03:42:11 +02:00
ERRQ_syntax(162); // Msg162 end of command
2001-05-23 15:26:42 +02:00
}
2004-02-02 12:02:12 +01:00
static DBB get_dbb( qli_symbol* symbol)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g e t _ d b b
*
**************************************
*
* Functional description
* Find a database block from a symbol
* or its homonyms.
*
**************************************/
for (; symbol; symbol = symbol->sym_homonym)
if (symbol->sym_type == SYM_database)
return (DBB) symbol->sym_object;
return NULL;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* make_list( qli_lls* stack)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* m a k e _ l i s t
*
**************************************
*
* Functional description
* Dump a stack of junk into a list node. Best count
* them first.
*
**************************************/
2004-02-02 12:02:12 +01:00
qli_lls* temp = stack;
USHORT count = 0;
2001-05-23 15:26:42 +02:00
while (temp) {
count++;
temp = temp->lls_next;
}
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_list, count);
2004-03-07 08:58:55 +01:00
qli_syntax** ptr = &node->syn_arg[count];
2001-05-23 15:26:42 +02:00
while (stack)
2004-05-16 03:42:11 +02:00
*--ptr = (qli_syntax*) ALLQ_pop(&stack);
2001-05-23 15:26:42 +02:00
return node;
}
static NAM make_name(void)
{
/**************************************
*
* m a k e _ n a m e
*
**************************************
*
* Functional description
* Generate a unique name for something
* (like a database) that needs one.
*
**************************************/
SSHORT l;
TEXT string[32];
2001-05-23 15:26:42 +02:00
for (SSHORT i = 0; i < 1000; i++) {
2001-05-23 15:26:42 +02:00
sprintf(string, "QLI_%d", i);
if (i < 10)
l = 5;
else
l = (i < 100) ? 6 : 7;
if (!(HSH_lookup(string, l)))
break;
}
NAM name = (NAM) ALLOCDV(type_nam, l);
2001-05-23 15:26:42 +02:00
name->nam_length = l;
TEXT* p = name->nam_string;
const TEXT* q = string;
2001-05-23 15:26:42 +02:00
if (l)
do {
const TEXT c = *q++;
2001-05-23 15:26:42 +02:00
*p++ = UPPER(c);
} while (--l);
return name;
}
2004-02-02 12:02:12 +01:00
static qli_const* make_numeric_constant(const TEXT* string, USHORT length)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* m a k e _ n u m e r i c _ c o n s t a n t
*
**************************************
*
* Functional description
* Build a constant block for a numeric
* constant. Numeric constants are normally
* stored as long words, but especially large
* ones become text. They ought to become
* double precision, one would think, but they'd
* have to be VAX style double precision which is
* more pain than gain.
*
**************************************/
2004-02-02 12:02:12 +01:00
qli_const* constant;
2001-05-23 15:26:42 +02:00
// If there are a reasonable number of digits, convert to binary
2001-05-23 15:26:42 +02:00
if (length < 9) {
2004-02-02 12:02:12 +01:00
constant = (qli_const*) ALLOCDV(type_con, sizeof(SLONG));
2001-05-23 15:26:42 +02:00
constant->con_desc.dsc_dtype = dtype_long;
constant->con_desc.dsc_length = sizeof(SLONG);
constant->con_desc.dsc_address = constant->con_data;
constant->con_desc.dsc_scale =
2001-07-12 07:46:06 +02:00
MOVQ_decompose(string, length, (SLONG*) constant->con_data);
2001-05-23 15:26:42 +02:00
}
else {
++length;
2004-02-02 12:02:12 +01:00
constant = (qli_const*) ALLOCDV(type_con, length);
2001-05-23 15:26:42 +02:00
constant->con_desc.dsc_dtype = dtype_text;
constant->con_desc.dsc_length = length;
constant->con_desc.dsc_address = constant->con_data;
TEXT* p = (TEXT *) constant->con_desc.dsc_address;
2001-05-23 15:26:42 +02:00
*p++ = '0';
while (--length)
*p++ = *string++;
}
return constant;
}
static TEXT* make_string(const TEXT* address, USHORT length)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* m a k e _ s t r i n g
*
**************************************
*
* Functional description
* Copy a string into a temporary string block.
*
**************************************/
2004-02-02 12:02:12 +01:00
qli_str* string = (qli_str*) ALLOCDV(type_str, length);
TEXT* p = string->str_data;
2001-05-23 15:26:42 +02:00
if (length)
do {
2001-05-23 15:26:42 +02:00
*p++ = *address++;
} while (--length);
2001-05-23 15:26:42 +02:00
return string->str_data;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* negate( qli_syntax* expr)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* n e g a t e
*
**************************************
*
* Functional description
* Build negation of expression.
*
**************************************/
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_not, 1);
2001-05-23 15:26:42 +02:00
node->syn_arg[0] = expr;
return node;
}
static KWWORDS next_keyword(void)
{
/**************************************
*
* n e x t _ k e y w o r d
*
**************************************
*
* Functional description
* Get a real token and return the keyword number.
*
**************************************/
PAR_real();
2004-05-29 07:03:08 +02:00
for (const qli_symbol* symbol = QLI_token->tok_symbol; symbol;
symbol = symbol->sym_homonym)
{
2001-05-23 15:26:42 +02:00
if (symbol->sym_type == SYM_keyword)
return (KWWORDS) symbol->sym_keyword;
}
2001-05-23 15:26:42 +02:00
return KW_none;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_abort(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ a b o r t
*
**************************************
*
* Functional description
* Parse an ABORT statement.
*
**************************************/
PAR_token();
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_abort, 1);
2001-05-23 15:26:42 +02:00
if (KEYWORD(KW_SEMI))
node->syn_count = 0;
else
node->syn_arg[0] = parse_value(0, 0);
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_accept(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ a c c e p t
*
**************************************
*
* Functional description
* Parse form update statement.
*
**************************************/
IBERROR(484); // FORMs not supported
2002-11-06 15:50:09 +01:00
return 0;
2001-05-23 15:26:42 +02:00
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_add( USHORT* paren_count, bool* bool_flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ a d d
*
**************************************
*
* Functional description
2001-07-12 07:46:06 +02:00
* Parse the lowest precedence operatrs, ADD and SUBTRACT.
2001-05-23 15:26:42 +02:00
*
**************************************/
2001-07-12 07:46:06 +02:00
NOD_T operatr;
2001-05-23 15:26:42 +02:00
2004-03-07 08:58:55 +01:00
qli_syntax* node = parse_multiply(paren_count, bool_flag);
2001-05-23 15:26:42 +02:00
2003-09-10 19:52:12 +02:00
while (true) {
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_PLUS))
2001-07-12 07:46:06 +02:00
operatr = nod_add;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_MINUS))
2001-07-12 07:46:06 +02:00
operatr = nod_subtract;
2001-05-23 15:26:42 +02:00
else
return node;
2004-03-07 08:58:55 +01:00
qli_syntax* arg = node;
2004-05-16 03:42:11 +02:00
node = syntax_node(operatr, 2);
2001-05-23 15:26:42 +02:00
node->syn_arg[0] = arg;
node->syn_arg[1] = parse_multiply(paren_count, bool_flag);
}
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_and( USHORT * paren_count)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ a n d
*
**************************************
*
* Functional description
* Parse an AND expression.
*
**************************************/
2004-03-07 08:58:55 +01:00
qli_syntax* expr = parse_not(paren_count);
2001-05-23 15:26:42 +02:00
/*
while (*paren_count && KEYWORD (KW_RIGHT_PAREN))
{
parse_matching_paren();
(*paren_count)--;
}
*/
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_AND))
2001-05-23 15:26:42 +02:00
return expr;
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_and, 2);
2001-05-23 15:26:42 +02:00
node->syn_arg[0] = expr;
node->syn_arg[1] = parse_and(paren_count);
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_assignment(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ a s s i g n m e n t
*
**************************************
*
* Functional description
* Parse an assignment statement (or give an error). The
* assignment statement can be either a simple assignment
* (field = value) or a restructure (relation = rse).
* If the assignment operator is missing,
2001-05-23 15:26:42 +02:00
* generate an "expected statement" error.
*
**************************************/
2004-03-07 08:58:55 +01:00
qli_syntax* field;
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_assign, s_asn_count);
2001-05-23 15:26:42 +02:00
node->syn_arg[s_asn_to] = parse_field_name(&field);
NAM name = (NAM) field->syn_arg[0];
2001-05-23 15:26:42 +02:00
/* If the next token is an equals sign, the statement really is an
assignment, and we're off the hook. */
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_EQUALS))
ERRQ_print_error(156, name->nam_string); // Msg156 expected statement, encountered %s
2001-05-23 15:26:42 +02:00
/* See if the "field name" is really a relation reference. If so,
turn the assignment into a restructure. */
2004-02-02 12:02:12 +01:00
qli_rel* relation = NULL;
2001-05-23 15:26:42 +02:00
if (field->syn_count == 1)
relation = resolve_relation(0, name->nam_symbol);
else if (field->syn_count == 2 && name->nam_symbol) {
NAM name2 = (NAM) field->syn_arg[1];
2001-05-23 15:26:42 +02:00
relation = resolve_relation(name->nam_symbol, name2->nam_symbol);
}
if (relation) {
2004-05-16 03:42:11 +02:00
ALLQ_release((FRB) field);
2001-05-23 15:26:42 +02:00
node->syn_type = nod_restructure;
node->syn_arg[s_asn_to] = field =
2004-05-16 03:42:11 +02:00
syntax_node(nod_relation, s_rel_count);
2004-03-07 08:58:55 +01:00
field->syn_arg[s_rel_relation] = (qli_syntax*) relation;
2001-05-23 15:26:42 +02:00
node->syn_arg[s_asn_from] = parse_rse();
}
else
node->syn_arg[s_asn_from] = parse_value(0, 0);
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_boolean( USHORT * paren_count)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ b o o l e a n
*
**************************************
*
* Functional description
* Parse a general boolean expression. By precedence, handle an OR
* here.
*
**************************************/
USHORT local_count;
if (!paren_count) {
local_count = 0;
paren_count = &local_count;
}
2004-03-07 08:58:55 +01:00
qli_syntax* expr = parse_and(paren_count);
2001-05-23 15:26:42 +02:00
/*
while (*paren_count && KEYWORD (KW_RIGHT_PAREN))
{
parse_matching_paren();
(*paren_count)--;
}
*/
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_OR)) {
2001-05-23 15:26:42 +02:00
parse_terminating_parens(paren_count, &local_count);
return expr;
}
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_or, 2);
2001-05-23 15:26:42 +02:00
node->syn_arg[0] = expr;
node->syn_arg[1] = parse_boolean(paren_count);
parse_terminating_parens(paren_count, &local_count);
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_copy(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ c o p y
*
**************************************
*
* Functional description
* Parse a copy command, which copies
* one procedure to another.
*
**************************************/
PAR_real_token();
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_PROCEDURE)) {
qli_syntax* node = syntax_node(nod_copy_proc, 2);
2004-03-07 08:58:55 +01:00
node->syn_arg[0] = (qli_syntax*) parse_qualified_procedure();
2004-05-16 03:42:11 +02:00
PAR_match(KW_TO);
2004-03-07 08:58:55 +01:00
node->syn_arg[1] = (qli_syntax*) parse_qualified_procedure();
2001-05-23 15:26:42 +02:00
return node;
}
ERRQ_print_error(157, QLI_token->tok_string); // Msg157 Expected PROCEDURE encountered %s
2003-02-07 10:40:54 +01:00
return NULL;
2001-05-23 15:26:42 +02:00
}
static DBB parse_database(void)
{
/**************************************
*
* p a r s e _ d a t a b a s e
*
**************************************
*
* Functional description
* Pick up a database for a meta-data or
* procedure update. Return NULL if the
* token is not a database name.
*
**************************************/
2004-02-02 12:02:12 +01:00
qli_symbol* db_symbol = QLI_token->tok_symbol;
2001-05-23 15:26:42 +02:00
if (db_symbol && db_symbol->sym_type == SYM_database)
{
DBB database = (DBB) db_symbol->sym_object;
2001-05-23 15:26:42 +02:00
PAR_real_token();
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_DOT))
ERRQ_syntax(158); // Msg158 period in qualified name
2001-05-23 15:26:42 +02:00
PAR_real();
return database;
}
if (!QLI_databases)
IBERROR(159); // Msg159 no databases are ready
2001-05-23 15:26:42 +02:00
return NULL;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_declare(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ d e c l a r e
*
**************************************
*
* Functional description
* Parse a variable declaration.
*
**************************************/
PAR_token();
PAR_real();
USHORT dtype = 0, length = 0, scale = 0;
SSHORT sub_type = 0;
SSHORT sub_type_missing = 1;
2004-03-07 08:58:55 +01:00
qli_syntax* field_node = NULL;
2004-02-02 12:02:12 +01:00
qli_symbol* query_name = NULL;
const TEXT* edit_string = NULL;
const TEXT* query_header = NULL;
2004-02-02 12:02:12 +01:00
qli_symbol* name = parse_symbol();
2001-05-23 15:26:42 +02:00
/*if (global_flag) PAR_real();*/
while (!KEYWORD(KW_SEMI) && !KEYWORD(KW_COMMA)) {
PAR_real();
switch (QLI_token->tok_keyword) {
case KW_SHORT:
case KW_LONG:
case KW_FLOAT:
case KW_DOUBLE:
case KW_DATE:
case KW_CHAR:
case KW_VARYING:
if (dtype)
2004-05-16 03:42:11 +02:00
ERRQ_syntax(164); // Msg164 variable definition clause
2001-05-23 15:26:42 +02:00
dtype = parse_dtype(&length, &scale);
break;
case KW_BLOB:
IBERROR(160); // Msg160 blob variables are not supported
2001-05-23 15:26:42 +02:00
break;
case KW_SUB_TYPE:
sub_type = parse_dtype_subtype();
sub_type_missing = 0;
break;
case KW_EDIT_STRING:
PAR_token();
if (QLI_token->tok_type != tok_quoted)
2004-05-16 03:42:11 +02:00
ERRQ_syntax(163); // Msg163 quoted edit string
2001-05-23 15:26:42 +02:00
edit_string =
make_string(QLI_token->tok_string + 1,
QLI_token->tok_length - 2);
PAR_token();
break;
case KW_QUERY_NAME:
PAR_token();
2004-05-16 03:42:11 +02:00
PAR_match(KW_IS);
2001-05-23 15:26:42 +02:00
if (QLI_token->tok_type != tok_ident)
2004-05-16 03:42:11 +02:00
ERRQ_syntax(199); // Msg199 identifier
2001-05-23 15:26:42 +02:00
query_name = parse_symbol();
break;
case KW_QUERY_HEADER:
PAR_token();
query_header = parse_header();
break;
case KW_BASED:
PAR_token();
2004-05-16 03:42:11 +02:00
PAR_match(KW_ON);
2001-05-23 15:26:42 +02:00
field_node = parse_field_name(0);
break;
default:
2004-05-16 03:42:11 +02:00
ERRQ_syntax(164); // Msg164 variable definition clause
2001-05-23 15:26:42 +02:00
break;
}
}
2004-02-02 12:02:12 +01:00
qli_rel* relation = NULL;
2001-05-23 15:26:42 +02:00
if (field_node && field_node->syn_count == 3) {
NAM db_name = (NAM) field_node->syn_arg[0];
NAM rel_name = (NAM) field_node->syn_arg[1];
2001-05-23 15:26:42 +02:00
if (!db_name->nam_symbol)
ERRQ_print_error(165, db_name->nam_string);
// Msg165 %s is not a database
relation = resolve_relation(db_name->nam_symbol, rel_name->nam_symbol);
if (!relation)
{
ERRQ_print_error(166, SafeArg() << rel_name->nam_string <<
db_name->nam_string);
// Msg166 %s is not a relation in database %s
}
2001-05-23 15:26:42 +02:00
}
if (!dtype && !field_node)
2004-05-16 03:42:11 +02:00
ERRQ_syntax(167); // Msg167 variable data type
2001-05-23 15:26:42 +02:00
if (field_node && (dtype || length || scale))
IBERROR(168); // Msg168 no datatype may be specified for a variable based on a field
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_declare, 2);
// Not global to this unit, misleading name "global..."
2004-02-02 12:02:12 +01:00
qli_fld* global_variable = (qli_fld*) ALLOCDV(type_fld, length);
2004-03-07 08:58:55 +01:00
node->syn_arg[0] = (qli_syntax*) global_variable;
2001-05-23 15:26:42 +02:00
global_variable->fld_name = name;
global_variable->fld_dtype = dtype;
global_variable->fld_scale = scale;
global_variable->fld_sub_type = sub_type;
global_variable->fld_sub_type_missing = sub_type_missing;
global_variable->fld_length = length;
global_variable->fld_edit_string = edit_string;
global_variable->fld_query_name = query_name;
global_variable->fld_query_header = query_header;
global_variable->fld_relation = relation;
node->syn_arg[1] = field_node;
check_end();
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_define(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ d e f i n e
*
**************************************
*
* Functional description
* Parse a DEFINE command.
* There are, of course, a whole class of define commands.
2001-05-23 15:26:42 +02:00
*
**************************************/
PAR_real_token();
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_PROCEDURE)) {
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
qli_syntax* anode = syntax_node(nod_define, 1);
2004-03-07 08:58:55 +01:00
anode->syn_arg[0] = (qli_syntax*) parse_qualified_procedure();
return anode;
2001-05-23 15:26:42 +02:00
}
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_FIELD)) {
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_def_field, 2);
2004-03-07 08:58:55 +01:00
node->syn_arg[0] = (qli_syntax*) parse_database();
node->syn_arg[1] = (qli_syntax*) parse_field(true);
2001-05-23 15:26:42 +02:00
return node;
}
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_RELATION))
2001-05-23 15:26:42 +02:00
return parse_def_relation();
if (KEYWORD(KW_DATABASE))
return parse_ready(nod_def_database);
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_INDEX))
2001-05-23 15:26:42 +02:00
return parse_def_index();
2004-05-16 03:42:11 +02:00
ERRQ_syntax(169); // Msg169 object type for DEFINE
2003-02-07 10:40:54 +01:00
return NULL;
2001-05-23 15:26:42 +02:00
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_def_index(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ d e f _ i n d e x
*
**************************************
*
* Functional description
* Parse a DEFINE INDEX command.
2001-05-23 15:26:42 +02:00
*
**************************************/
PAR_real();
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_def_index, s_dfi_count);
2004-03-07 08:58:55 +01:00
node->syn_arg[s_dfi_name] = (qli_syntax*) parse_symbol();
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
PAR_match(KW_FOR);
2001-05-23 15:26:42 +02:00
2004-03-07 08:58:55 +01:00
if (!(node->syn_arg[s_dfi_relation] = (qli_syntax*) parse_qualified_relation()))
2004-05-16 03:42:11 +02:00
ERRQ_syntax(170); // Msg170 relation name
2001-05-23 15:26:42 +02:00
PAR_real();
2003-09-10 19:52:12 +02:00
while (true) {
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_UNIQUE))
2001-05-23 15:26:42 +02:00
node->syn_flags |= s_dfi_flag_unique;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_DUPLICATE))
2001-05-23 15:26:42 +02:00
node->syn_flags &= ~s_dfi_flag_unique;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_ACTIVE))
2001-05-23 15:26:42 +02:00
node->syn_flags &= ~s_dfi_flag_inactive;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_INACTIVE))
2001-05-23 15:26:42 +02:00
node->syn_flags |= s_dfi_flag_inactive;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_DESCENDING))
2001-05-23 15:26:42 +02:00
node->syn_flags |= s_dfi_flag_descending;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_ASCENDING))
2001-05-23 15:26:42 +02:00
node->syn_flags &= ~s_dfi_flag_descending;
else
break;
}
2004-02-02 12:02:12 +01:00
qli_lls* stack = NULL;
2001-05-23 15:26:42 +02:00
for (;;) {
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) parse_name(), &stack);
if (!PAR_match(KW_COMMA))
2001-05-23 15:26:42 +02:00
break;
}
node->syn_arg[s_dfi_fields] = make_list(stack);
command_end();
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_def_relation(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ d e f _ r e l a t i o n
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
2001-05-23 15:26:42 +02:00
* Parse a DEFINE RELATION command,
* which include the field definitions
* for a primitive relation definition
* or it may just reference another relation
* whose field definitions we will copy.
2001-05-23 15:26:42 +02:00
*
**************************************/
PAR_real();
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_def_relation, 2);
2004-02-02 12:02:12 +01:00
qli_rel* relation = (qli_rel*) ALLOCD(type_rel);
2004-03-07 08:58:55 +01:00
node->syn_arg[0] = (qli_syntax*) relation;
2001-05-23 15:26:42 +02:00
relation->rel_database = parse_database();
relation->rel_symbol = parse_symbol();
PAR_real();
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_BASED)) {
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
PAR_match(KW_ON);
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
PAR_match(KW_RELATION);
2001-05-23 15:26:42 +02:00
PAR_real();
2004-02-02 12:02:12 +01:00
relation = (qli_rel*) ALLOCD(type_rel);
2004-03-07 08:58:55 +01:00
node->syn_arg[1] = (qli_syntax*) relation;
2001-05-23 15:26:42 +02:00
relation->rel_database = parse_database();
relation->rel_symbol = parse_symbol();
}
else {
node->syn_arg[1] = NULL;
2004-02-02 12:02:12 +01:00
qli_fld** ptr = &relation->rel_fields;
2001-05-23 15:26:42 +02:00
for (;;) {
2004-05-16 03:42:11 +02:00
PAR_match(KW_ADD);
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
PAR_match(KW_FIELD);
qli_fld* field = parse_field(false);
*ptr = field;
2001-05-23 15:26:42 +02:00
ptr = &field->fld_next;
if (KEYWORD(KW_SEMI))
break;
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_COMMA))
ERRQ_syntax(171); // Msg171 comma between field definitions
2001-05-23 15:26:42 +02:00
}
}
command_end();
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_delete(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ d e l e t e
*
**************************************
*
* Functional description
* Parse a SQL DELETE statement.
2001-05-23 15:26:42 +02:00
* (DELETE PROCEDURE is parsed in parse_drop)
*
**************************************/
++sql_flag;
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_FROM))
ERRQ_syntax(172); // Msg172 FROM
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_erase, s_era_count);
qli_syntax* rse = syntax_node(nod_rse, (int) s_rse_count + 2);
node->syn_arg[s_era_rse] = rse;
2001-05-23 15:26:42 +02:00
rse->syn_count = 1;
rse->syn_arg[s_rse_count] = parse_sql_relation();
// Pick up boolean, if present
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_WITH))
2001-05-23 15:26:42 +02:00
rse->syn_arg[s_rse_boolean] = parse_boolean(0);
--sql_flag;
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_drop(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ d r o p
*
**************************************
*
* Functional description
* Parse a DDL DROP/DELETE command. It it isn't one,
* just return NULL.
*
**************************************/
2004-03-07 08:58:55 +01:00
qli_syntax* node;
2001-05-23 15:26:42 +02:00
NOD_T type;
DBB database;
SSHORT l;
TEXT* p;
const TEXT* q;
2001-05-23 15:26:42 +02:00
PAR_real_token();
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_RELATION) || PAR_match(KW_VIEW) || PAR_match(KW_TABLE)) {
node = syntax_node(nod_del_relation, 1);
2004-03-07 08:58:55 +01:00
if (!(node->syn_arg[0] = (qli_syntax*) parse_qualified_relation()))
2004-05-16 03:42:11 +02:00
ERRQ_syntax(173); // Msg173 relation or view name
2001-05-23 15:26:42 +02:00
return node;
}
switch (QLI_token->tok_keyword) {
case KW_PROCEDURE:
type = nod_delete_proc;
break;
case KW_INDEX:
type = nod_del_index;
break;
case KW_FIELD:
type = nod_del_field;
break;
case KW_DATABASE:
LEX_filename();
if (!(l = QLI_token->tok_length))
ERRQ_error(429); // Msg429 database file name required on DROP DATABASE
2001-05-23 15:26:42 +02:00
q = QLI_token->tok_string;
if (QLI_token->tok_type == tok_quoted) {
l -= 2;
q++;
}
database = (DBB) ALLOCDV(type_dbb, l);
database->dbb_filename_length = l;
p = database->dbb_filename;
do {
2001-05-23 15:26:42 +02:00
*p++ = *q++;
} while (--l);
2001-05-23 15:26:42 +02:00
PAR_token();
// parse an optional user name and password if given
2001-05-23 15:26:42 +02:00
for (;;) {
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_USER))
2001-05-23 15:26:42 +02:00
database->dbb_user = parse_literal();
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_PASSWORD))
2001-05-23 15:26:42 +02:00
database->dbb_password = parse_literal();
else
break;
}
command_end();
2004-05-16 03:42:11 +02:00
node = syntax_node(nod_del_database, 1);
2004-03-07 08:58:55 +01:00
node->syn_arg[0] = (qli_syntax*) database;
2001-05-23 15:26:42 +02:00
return node;
default:
return NULL;
}
PAR_real_token();
2004-05-16 03:42:11 +02:00
node = syntax_node(type, 2);
2001-05-23 15:26:42 +02:00
if (type == nod_delete_proc)
2004-03-07 08:58:55 +01:00
node->syn_arg[0] = (qli_syntax*) parse_qualified_procedure();
2001-05-23 15:26:42 +02:00
else {
2004-03-07 08:58:55 +01:00
node->syn_arg[0] = (qli_syntax*) parse_database();
node->syn_arg[1] = (qli_syntax*) parse_name();
2001-05-23 15:26:42 +02:00
}
return node;
}
static int parse_dtype( USHORT * length, USHORT * scale)
{
/**************************************
*
* p a r s e _ d t y p e
*
**************************************
*
* Functional description
* Parse a datatype clause.
*
**************************************/
USHORT dtype;
2001-05-23 15:26:42 +02:00
KWWORDS keyword = QLI_token->tok_keyword;
2001-05-23 15:26:42 +02:00
PAR_token();
*scale = 0;
switch (keyword) {
case KW_SHORT:
*length = sizeof(SSHORT);
dtype = dtype_short;
break;
case KW_BIGINT:
*length = sizeof(SINT64);
dtype = dtype_int64;
break;
2001-05-23 15:26:42 +02:00
case KW_LONG:
*length = sizeof(SLONG);
dtype = dtype_long;
break;
case KW_FLOAT:
*length = sizeof(float);
return dtype_real;
case KW_DOUBLE:
*length = sizeof(double);
return dtype_double;
case KW_DATE:
*length = sizeof(gds_quad);
return dtype_timestamp;
case KW_CHAR:
dtype = dtype_text;
break;
case KW_VARYING:
dtype = dtype_varying;
break;
case KW_BLOB:
*length = sizeof(gds_quad);
return dtype_blob;
}
if (dtype == dtype_short || dtype == dtype_long || dtype == dtype_int64 )
{
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_SCALE)) {
const bool m = (PAR_match(KW_MINUS)) ? true : false;
2001-05-23 15:26:42 +02:00
*scale = parse_ordinal();
if (m)
2001-05-23 15:26:42 +02:00
*scale = -(*scale);
}
}
else if (dtype == dtype_text || dtype == dtype_varying)
{
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_L_BRCKET) && !PAR_match(KW_LT))
ERRQ_syntax(174); /* Msg174 "[" */
2001-05-23 15:26:42 +02:00
USHORT l = parse_ordinal();
2001-05-23 15:26:42 +02:00
if (dtype == dtype_varying)
l += sizeof(SSHORT);
*length = l;
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_R_BRCKET) && !PAR_match(KW_GT))
ERRQ_syntax(175); /* Msg175 "]" */
2001-05-23 15:26:42 +02:00
}
return dtype;
}
static int parse_dtype_subtype(void)
{
/**************************************
*
* p a r s e _ d t y p e _ s u b t y p e
*
**************************************
*
* Functional description
* Parse a sub-type definition, which can be any of
* SUB_TYPE {IS} [TEXT | FIXED | <n>]
*
* Returns the numeric subtype value,
*
**************************************/
// grab KW_SUB_TYPE
2001-05-23 15:26:42 +02:00
PAR_token();
2004-05-16 03:42:11 +02:00
PAR_match(KW_IS);
if (PAR_match(KW_TEXT) || PAR_match(KW_FIXED))
2001-05-23 15:26:42 +02:00
return 1;
2004-05-16 03:42:11 +02:00
const int sign = (PAR_match(KW_MINUS)) ? -1 : 1;
2001-05-23 15:26:42 +02:00
return (sign * parse_ordinal());
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_edit(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ e d i t
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* Parse an edit statement which can
* be any of EDIT <procedure_name>
* EDIT <n>
2001-05-23 15:26:42 +02:00
* EDIT <*>
* EDIT
2001-05-23 15:26:42 +02:00
*
*
**************************************/
LEX_token();
/*
* edit previous statements. The top of the statment list
* is this edit command, which we conveniently ignore.
*/
if (KEYWORD(KW_SEMI) ||
(QLI_token->tok_type == tok_number) || (KEYWORD(KW_ASTERISK)))
{
2004-02-02 12:02:12 +01:00
qli_lls* statement_list = LEX_statement_list();
if (!statement_list)
IBERROR(176); // Msg176 No statements issued yet
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_ASTERISK))
2004-03-14 06:51:54 +01:00
LEX_edit(0, (IPTR) statement_list->lls_object);
2001-05-23 15:26:42 +02:00
else {
int l = 0; // initialize, will catch changes in logic here.
2001-05-23 15:26:42 +02:00
if (KEYWORD(KW_SEMI))
l = 1;
else if (QLI_token->tok_type == tok_number) // redundant for now
2001-05-23 15:26:42 +02:00
l = parse_ordinal();
2004-02-02 12:02:12 +01:00
qli_lls* start = statement_list;
qli_lls* stop = start;
while (l && start->lls_next)
{
--l;
start = start->lls_next;
}
2001-05-23 15:26:42 +02:00
command_end();
2004-03-14 06:51:54 +01:00
LEX_edit((IPTR) start->lls_object, (IPTR) stop->lls_object);
2001-05-23 15:26:42 +02:00
}
}
else {
const NOD_T type = nod_edit_proc;
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(type, 2);
2004-03-07 08:58:55 +01:00
node->syn_arg[0] = (qli_syntax*) parse_qualified_procedure();
2001-05-23 15:26:42 +02:00
command_end();
return node;
}
return NULL;
}
2004-02-02 12:02:12 +01:00
static TEXT* parse_edit_string(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ e d i t _ s t r i n g
*
**************************************
*
* Functional description
* Look for and parse a clause of the form:
* USING <edit_string>
*
**************************************/
if (!KEYWORD(KW_USING))
return NULL;
LEX_edit_string();
return parse_string();
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_erase(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ e r a s e
*
**************************************
*
* Functional description
* Parse an ERASE statement. Erase can be any of the
* following:
*
* ERASE [ALL] [OF <rse>]
*
**************************************/
PAR_token();
2004-05-16 03:42:11 +02:00
PAR_match(KW_ALL);
PAR_match(KW_OF);
qli_syntax* node = syntax_node(nod_erase, s_era_count);
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_ALL) || potential_rse()) {
PAR_match(KW_OF);
2001-05-23 15:26:42 +02:00
node->syn_arg[s_era_rse] = parse_rse();
}
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_extract(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ e x t r a c t
*
**************************************
*
* Functional description
* Parse a procedure extract statement. Syntax is:
*
* EXTRACT [ON <file>] proc [, ...] [ON <file> ]
*
**************************************/
PAR_real_token();
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_extract, 2);
2001-05-23 15:26:42 +02:00
node->syn_arg[1] = parse_output();
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_ALL)) {
2004-02-02 12:02:12 +01:00
qli_lls* stack = NULL;
2001-05-23 15:26:42 +02:00
for (;;) {
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) parse_qualified_procedure(), &stack);
if (!PAR_match(KW_COMMA))
2001-05-23 15:26:42 +02:00
break;
}
node->syn_arg[0] = make_list(stack);
}
if (!node->syn_arg[1] && !(node->syn_arg[1] = parse_output()))
2004-05-16 03:42:11 +02:00
ERRQ_syntax(177); // Msg177 "ON or TO"
2001-05-23 15:26:42 +02:00
return node;
}
static qli_fld* parse_field( bool global_flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ f i e l d
*
**************************************
*
* Functional description
* Parse a field description.
*
**************************************/
PAR_real();
USHORT dtype = 0, length = 0, scale = 0;
SSHORT sub_type = 0;
SSHORT sub_type_missing = 1;
2004-02-02 12:02:12 +01:00
qli_symbol* query_name = NULL;
qli_symbol* based_on = NULL;
const TEXT* edit_string = NULL;
const TEXT* query_header = NULL;
2004-02-02 12:02:12 +01:00
qli_symbol* name = parse_symbol();
2001-05-23 15:26:42 +02:00
if (global_flag)
PAR_real();
while (!KEYWORD(KW_SEMI) && !KEYWORD(KW_COMMA)) {
PAR_real();
switch (QLI_token->tok_keyword) {
case KW_SHORT:
case KW_LONG:
case KW_FLOAT:
case KW_DOUBLE:
case KW_DATE:
case KW_CHAR:
case KW_VARYING:
case KW_BLOB:
if (dtype)
2004-05-16 03:42:11 +02:00
ERRQ_syntax(179); // Msg179 field definition clause
2001-05-23 15:26:42 +02:00
dtype = parse_dtype(&length, &scale);
break;
case KW_SUB_TYPE:
sub_type = parse_dtype_subtype();
sub_type_missing = 0;
break;
case KW_EDIT_STRING:
PAR_token();
if (QLI_token->tok_type != tok_quoted)
2004-05-16 03:42:11 +02:00
ERRQ_syntax(178); // Msg178 quoted edit string
2001-05-23 15:26:42 +02:00
edit_string =
make_string(QLI_token->tok_string + 1,
QLI_token->tok_length - 2);
PAR_token();
break;
case KW_QUERY_NAME:
PAR_token();
2004-05-16 03:42:11 +02:00
PAR_match(KW_IS);
2001-05-23 15:26:42 +02:00
if (QLI_token->tok_type != tok_ident)
2004-05-16 03:42:11 +02:00
ERRQ_syntax(199); // Msg199 identifier
2001-05-23 15:26:42 +02:00
query_name = parse_symbol();
break;
case KW_BASED:
PAR_token();
2004-05-16 03:42:11 +02:00
PAR_match(KW_ON);
2001-05-23 15:26:42 +02:00
based_on = parse_symbol();
break;
default:
2004-05-16 03:42:11 +02:00
ERRQ_syntax(179); // Msg179 field definition clause
2001-05-23 15:26:42 +02:00
break;
}
}
2004-02-02 12:02:12 +01:00
qli_fld* field = (qli_fld*) ALLOCDV(type_fld, length);
2001-05-23 15:26:42 +02:00
field->fld_name = name;
field->fld_dtype = dtype;
field->fld_scale = scale;
field->fld_sub_type = sub_type;
field->fld_sub_type_missing = sub_type_missing;
field->fld_length = length;
field->fld_edit_string = edit_string;
field->fld_query_name = query_name;
field->fld_query_header = query_header;
if (!global_flag)
field->fld_based = based_on;
else if (based_on)
IBERROR(180); // Msg180 global fields may not be based on other fields
2001-05-23 15:26:42 +02:00
return field;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_field_name( qli_syntax** fld_ptr)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ f i e l d _ n a m e
*
**************************************
*
* Functional description
* Parse a qualified field name, or
* qualified * expression.
*
**************************************/
2004-02-02 12:02:12 +01:00
qli_lls* stack = NULL;
2001-05-23 15:26:42 +02:00
2003-09-10 19:52:12 +02:00
while (true) {
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_ASTERISK)) {
2001-05-23 15:26:42 +02:00
if (!stack)
2004-05-16 03:42:11 +02:00
ERRQ_syntax(181); // Msg181 field name or asterisk expression
2004-03-07 08:58:55 +01:00
qli_syntax* afield = make_list(stack);
afield->syn_type = nod_star;
return afield;
2001-05-23 15:26:42 +02:00
}
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) parse_name(), &stack);
if (!PAR_match(KW_DOT))
2001-05-23 15:26:42 +02:00
break;
}
2004-03-07 08:58:55 +01:00
qli_syntax* field = make_list(stack);
2001-05-23 15:26:42 +02:00
field->syn_type = nod_field;
if (fld_ptr)
*fld_ptr = field;
2004-05-16 03:42:11 +02:00
if (!(PAR_match(KW_L_BRCKET)))
2001-05-23 15:26:42 +02:00
return field;
// Parse an array reference
2001-05-23 15:26:42 +02:00
stack = NULL;
for (;;) {
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) parse_value(0, 0), &stack);
if (PAR_match(KW_R_BRCKET))
2001-05-23 15:26:42 +02:00
break;
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_COMMA))
ERRQ_syntax(183); // Msg183 comma
2001-05-23 15:26:42 +02:00
}
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_index, s_idx_count);
2001-05-23 15:26:42 +02:00
node->syn_arg[s_idx_field] = field;
node->syn_arg[s_idx_subs] = make_list(stack);
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_for(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ f o r
*
**************************************
*
* Functional description
* Parse a FOR statement.
*
**************************************/
PAR_token();
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_for, s_for_count);
2001-05-23 15:26:42 +02:00
node->syn_arg[s_for_rse] = parse_rse();
node->syn_arg[s_for_statement] = parse_statement();
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_from( USHORT * paren_count, bool* bool_flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ f r o m
*
**************************************
*
* Functional description
* Parse either an explicit or implicit FIRST ... FROM statement.
*
**************************************/
2004-03-07 08:58:55 +01:00
qli_syntax* value;
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_FIRST)) {
2001-05-23 15:26:42 +02:00
value = parse_primitive_value(0, 0);
PAR_real();
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_FROM))
ERRQ_syntax(182); // Msg182 FROM rse clause
2001-05-23 15:26:42 +02:00
}
else {
value = parse_primitive_value(paren_count, bool_flag);
2004-05-16 03:42:11 +02:00
if (sql_flag || !PAR_match(KW_FROM))
2001-05-23 15:26:42 +02:00
return value;
}
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_from, s_stt_count);
2001-05-23 15:26:42 +02:00
node->syn_arg[s_stt_value] = value;
node->syn_arg[s_stt_rse] = parse_rse();
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_ELSE))
2001-05-23 15:26:42 +02:00
node->syn_arg[s_stt_default] = parse_value(0, 0);
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_function(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ f u n c t i o n
*
**************************************
*
* Functional description
* Parse a function reference.
*
**************************************/
function_count++;
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_function, s_fun_count);
2004-03-07 08:58:55 +01:00
node->syn_arg[s_fun_function] = (qli_syntax*) QLI_token->tok_symbol;
2001-05-23 15:26:42 +02:00
node->syn_count = 1;
PAR_token();
2004-02-02 12:02:12 +01:00
qli_lls* stack = NULL;
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_LEFT_PAREN))
2001-05-23 15:26:42 +02:00
for (;;) {
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) parse_value(0, 0), &stack);
if (PAR_match(KW_RIGHT_PAREN))
2001-05-23 15:26:42 +02:00
break;
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_COMMA))
ERRQ_syntax(183); // Msg183 comma
2001-05-23 15:26:42 +02:00
}
node->syn_arg[s_fun_args] = make_list(stack);
function_count--;
return node;
}
2004-02-02 12:02:12 +01:00
static TEXT* parse_header(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ h e a d e r
*
**************************************
*
* Functional description
* Parse and store headers of the form:
* "quoted_string" [/ "more_string"]...
* or even the non-header -
*
**************************************/
TEXT header[1024];
2001-05-23 15:26:42 +02:00
TEXT* p = header;
2001-05-23 15:26:42 +02:00
2003-09-10 19:52:12 +02:00
while (true) {
2001-05-23 15:26:42 +02:00
PAR_real();
if ((QLI_token->tok_keyword != KW_MINUS) &&
2004-02-02 12:02:12 +01:00
(QLI_token->tok_type != tok_quoted))
{
2004-05-16 03:42:11 +02:00
ERRQ_syntax(184); // Msg184 quoted header segment
2004-02-02 12:02:12 +01:00
}
const TEXT* q = QLI_token->tok_string;
2001-05-23 15:26:42 +02:00
while (*q)
*p++ = *q++;
PAR_real_token();
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_SLASH))
2001-05-23 15:26:42 +02:00
break;
}
return make_string(header, p - header);
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_help(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ h e l p
*
**************************************
*
* Functional description
* Parse HELP statement. Unreasonable, but the masses
* must be appeased. Bread, circuses, help.
*
**************************************/
2004-02-02 12:02:12 +01:00
qli_lls* stack = NULL;
2001-05-23 15:26:42 +02:00
PAR_token();
while (!KEYWORD(KW_SEMI)) {
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) parse_name(), &stack);
PAR_match(KW_COMMA);
2001-05-23 15:26:42 +02:00
}
2004-03-07 08:58:55 +01:00
qli_syntax* node = make_list(stack);
2001-05-23 15:26:42 +02:00
node->syn_type = nod_help;
command_end();
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_if(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ i f
*
**************************************
*
* Functional description
* Parse an IF THEN ELSE statement.
*
**************************************/
PAR_token();
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_if, s_if_count);
2001-05-23 15:26:42 +02:00
node->syn_arg[s_if_boolean] = parse_boolean(0);
PAR_real();
2004-05-16 03:42:11 +02:00
PAR_match(KW_THEN);
2001-05-23 15:26:42 +02:00
++else_count;
node->syn_arg[s_if_true] = parse_statement();
--else_count;
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_ELSE))
2001-05-23 15:26:42 +02:00
node->syn_arg[s_if_false] = parse_statement();
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_in( qli_syntax* value, NOD_T operatr, bool all_flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ i n
*
**************************************
*
* Functional description
* Parse a SQL "IN" clause. This can have two forms:
*
* value IN (exp1, exp2...)
*
* value IN (column <select expression>)
*
**************************************/
PAR_real();
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_LEFT_PAREN))
ERRQ_syntax(185); // Msg185 left parenthesis
2001-05-23 15:26:42 +02:00
// Time to chose between two forms of the expression
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_SELECT)) {
qli_syntax* node1 = syntax_node(operatr, 2);
node1->syn_arg[0] = value;
node1->syn_arg[1] = parse_primitive_value(0, 0);
2004-05-16 03:42:11 +02:00
while (PAR_match(KW_COMMA)) {
2004-03-07 08:58:55 +01:00
qli_syntax* node2 = node1;
2004-05-16 03:42:11 +02:00
node1 = syntax_node(nod_or, 2);
node1->syn_arg[0] = node2;
2004-05-16 03:42:11 +02:00
node1->syn_arg[1] = node2 = syntax_node(nod_eql, 2);
2001-05-23 15:26:42 +02:00
node2->syn_arg[0] = value;
node2->syn_arg[1] = parse_value(0, 0);
}
parse_matching_paren();
return node1;
2001-05-23 15:26:42 +02:00
}
2004-03-07 08:58:55 +01:00
qli_syntax* value2 = parse_value(0, 0);
2001-05-23 15:26:42 +02:00
// We have the "hard" -- an implicit ANY
2001-05-23 15:26:42 +02:00
2004-03-07 08:58:55 +01:00
qli_syntax* rse = parse_sql_rse();
2001-05-23 15:26:42 +02:00
parse_matching_paren();
rse->syn_arg[s_rse_outer] = value;
rse->syn_arg[s_rse_inner] = value2;
2001-07-12 07:46:06 +02:00
rse->syn_arg[s_rse_op] = INT_CAST operatr;
rse->syn_arg[s_rse_all_flag] = INT_CAST (all_flag ? TRUE: FALSE);
2001-05-23 15:26:42 +02:00
// Finally, construct an ANY node
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_any, 1);
2001-05-23 15:26:42 +02:00
node->syn_arg[0] = rse;
return (all_flag) ? negate(node) : node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_insert(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ i n s e r t
*
**************************************
*
* Functional description
* Parse a STORE statement.
*
**************************************/
++sql_flag;
PAR_real_token();
2004-05-16 03:42:11 +02:00
PAR_match(KW_INTO);
qli_syntax* node = syntax_node(nod_store, s_sto_count);
2001-05-23 15:26:42 +02:00
// Pick up relation name for insert
2001-05-23 15:26:42 +02:00
node->syn_arg[s_sto_relation] = parse_sql_relation();
// Pick up field list, provided one is present
2001-05-23 15:26:42 +02:00
PAR_real();
2004-02-02 12:02:12 +01:00
qli_lls* fields = NULL;
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_LEFT_PAREN))
2003-09-10 19:52:12 +02:00
while (true) {
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) parse_field_name(0), &fields);
if (PAR_match(KW_RIGHT_PAREN))
2001-05-23 15:26:42 +02:00
break;
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_COMMA))
ERRQ_syntax(186); // Msg186 comma or terminating right parenthesis
2001-05-23 15:26:42 +02:00
}
// Pick up value list or SELECT statement
2001-05-23 15:26:42 +02:00
PAR_real();
bool select_flag;
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_VALUES)) {
select_flag = false;
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_LEFT_PAREN))
ERRQ_syntax(187); // Msg187 left parenthesis
2001-05-23 15:26:42 +02:00
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_SELECT))
select_flag = true;
2001-05-23 15:26:42 +02:00
else
2004-05-16 03:42:11 +02:00
ERRQ_syntax(188); // Msg188 VALUES list or SELECT clause
2001-05-23 15:26:42 +02:00
2004-02-02 12:02:12 +01:00
qli_lls* values = NULL;
qli_lls* distinct = NULL;
2003-09-10 19:52:12 +02:00
while (true) {
2004-05-16 03:42:11 +02:00
if (distinct || PAR_match(KW_DISTINCT)) {
ALLQ_push((blk*) parse_value(0, 0), &distinct);
ALLQ_push(distinct->lls_object, &values);
ALLQ_push(0, &distinct);
2001-05-23 15:26:42 +02:00
}
else
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) parse_value(0, 0), &values);
if (!PAR_match(KW_COMMA))
2001-05-23 15:26:42 +02:00
break;
}
if (select_flag)
node->syn_arg[s_sto_rse] = parse_sql_rse();
else
parse_matching_paren();
if (distinct)
node->syn_arg[s_sto_rse]->syn_arg[s_rse_reduced] =
make_list(distinct);
2004-03-07 08:58:55 +01:00
node->syn_arg[s_sto_fields] = (qli_syntax*) fields;
node->syn_arg[s_sto_values] = (qli_syntax*) values;
2001-05-23 15:26:42 +02:00
--sql_flag;
return node;
}
static NOD_T parse_join_type(void)
{
/**************************************
*
* p a r s e _ j o i n _ t y p e
*
**************************************
*
* Functional description
* Parse a join type.
*
**************************************/
2001-07-12 07:46:06 +02:00
NOD_T operatr;
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_INNER))
2001-07-12 07:46:06 +02:00
operatr = nod_join_inner;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_LEFT))
2001-07-12 07:46:06 +02:00
operatr = nod_join_left;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_RIGHT))
2001-07-12 07:46:06 +02:00
operatr = nod_join_right;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_FULL))
2001-07-12 07:46:06 +02:00
operatr = nod_join_full;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_JOIN))
2001-05-23 15:26:42 +02:00
return nod_join_inner;
else
return (NOD_T) 0;
2001-07-12 07:46:06 +02:00
if (operatr != nod_join_inner)
2004-05-16 03:42:11 +02:00
PAR_match(KW_OUTER);
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_JOIN))
ERRQ_syntax(489); // Msg489 JOIN
2001-05-23 15:26:42 +02:00
2001-07-12 07:46:06 +02:00
return operatr;
2001-05-23 15:26:42 +02:00
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_list_fields(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ l i s t _ f i e l d s
*
**************************************
*
* Functional description
* Parse a LIST statement. LIST is like PRINT, but does vertical
* formatting.
*
**************************************/
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_list_fields, s_prt_count);
2001-05-23 15:26:42 +02:00
PAR_token();
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_ALL) && PAR_match(KW_DISTINCT))
2001-05-23 15:26:42 +02:00
node->syn_arg[s_prt_distinct] = INT_CAST TRUE;
if (node->syn_arg[s_prt_output] = parse_output())
return node;
if (test_end())
return node;
/* If there is a potential record selection expression, there obviously
can't be a print list. Get the rse. Otherwise, pick up the print
list. */
if (potential_rse())
node->syn_arg[s_prt_rse] = parse_rse();
else {
if (!test_end()) {
2004-02-02 12:02:12 +01:00
qli_lls* stack = NULL;
2001-05-23 15:26:42 +02:00
for (;;) {
2004-05-16 03:42:11 +02:00
qli_syntax* item = syntax_node(nod_print_item, s_itm_count);
2001-05-23 15:26:42 +02:00
item->syn_arg[s_itm_value] = parse_value(0, 0);
2004-03-07 08:58:55 +01:00
item->syn_arg[s_itm_edit_string] = (qli_syntax*) parse_edit_string();
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) item, &stack);
if (!PAR_match(KW_COMMA) && !PAR_match(KW_AND))
2001-05-23 15:26:42 +02:00
break;
PAR_real();
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_AND))
2001-05-23 15:26:42 +02:00
PAR_real();
}
node->syn_arg[s_prt_list] = make_list(stack);
}
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_OF))
2001-05-23 15:26:42 +02:00
node->syn_arg[s_prt_rse] = parse_rse();
}
node->syn_arg[s_prt_output] = parse_output();
return node;
}
2004-02-02 12:02:12 +01:00
static qli_const* parse_literal(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ l i t e r a l
*
**************************************
*
* Functional description
* Parse a literal expression.
*
**************************************/
2004-02-02 12:02:12 +01:00
qli_const* constant;
2001-05-23 15:26:42 +02:00
PAR_real();
const UCHAR* q = (UCHAR *) QLI_token->tok_string;
USHORT l = QLI_token->tok_length;
2001-05-23 15:26:42 +02:00
if (QLI_token->tok_type == tok_quoted) {
q++;
l -= 2;
2004-02-02 12:02:12 +01:00
constant = (qli_const*) ALLOCDV(type_con, l);
2001-05-23 15:26:42 +02:00
constant->con_desc.dsc_dtype = dtype_text;
UCHAR* p = constant->con_desc.dsc_address = constant->con_data;
2001-05-23 15:26:42 +02:00
if (constant->con_desc.dsc_length = l)
do {
2001-05-23 15:26:42 +02:00
*p++ = *q++;
} while (--l);
2001-05-23 15:26:42 +02:00
}
else if (QLI_token->tok_type == tok_number)
constant = make_numeric_constant(QLI_token->tok_string,
QLI_token->tok_length);
else
2004-05-16 03:42:11 +02:00
ERRQ_syntax(190); // Msg190 value expression
2001-05-23 15:26:42 +02:00
PAR_token();
return constant;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_matches(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ m a t c h e s
*
**************************************
*
* Functional description
* Parse a matching expressing, including
* the preset matching language template.
*
**************************************/
PAR_token();
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_sleuth, 3);
2001-05-23 15:26:42 +02:00
node->syn_arg[1] = parse_value(0, 0);
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_USING))
2001-05-23 15:26:42 +02:00
node->syn_arg[2] = parse_value(0, 0);
else if (QLI_matching_language) {
2004-05-16 03:42:11 +02:00
qli_syntax* language = syntax_node(nod_constant, 1);
node->syn_arg[2] = language;
2004-03-07 08:58:55 +01:00
language->syn_arg[0] = (qli_syntax*) QLI_matching_language;
2001-05-23 15:26:42 +02:00
}
else {
node->syn_type = nod_matches;
node->syn_count = 2;
}
return node;
}
static void parse_matching_paren(void)
{
/**************************************
*
* p a r s e _ m a t c h i n g _ p a r e n
*
**************************************
*
* Functional description
* Check for a trailing (right) parenthesis. Complain if
* its not there.
*
**************************************/
PAR_real();
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_RIGHT_PAREN))
2001-05-23 15:26:42 +02:00
return;
2004-05-16 03:42:11 +02:00
ERRQ_syntax(191); // Msg191 right parenthesis
2001-05-23 15:26:42 +02:00
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_modify(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ m o d i f y
*
**************************************
*
* Functional description
* Parse a MODIFY statement. Modify can be any of the
* following:
*
* MODIFY [ALL] [<field> [, <field>]...] [OF <rse> ]
* MODIFY [ALL] USING <statement> [OF <rse>]
*
**************************************/
PAR_token();
// If this is a meta-data change, handle it elsewhere
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_INDEX))
2001-05-23 15:26:42 +02:00
return parse_modify_index();
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_FIELD)) {
qli_syntax* anode = syntax_node(nod_mod_field, 1);
2004-03-07 08:58:55 +01:00
anode->syn_arg[0] = (qli_syntax*) parse_database();
anode->syn_arg[1] = (qli_syntax*) parse_field(true);
return anode;
2001-05-23 15:26:42 +02:00
}
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_RELATION))
2001-05-23 15:26:42 +02:00
return parse_modify_relation();
// Not a meta-data modification, just a simple data modify
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
PAR_match(KW_ALL);
qli_syntax* node = syntax_node(nod_modify, s_mod_count);
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_USING))
2001-05-23 15:26:42 +02:00
node->syn_arg[s_mod_statement] = parse_statement();
else if (!KEYWORD(KW_SEMI)) {
2004-02-02 12:02:12 +01:00
qli_lls* stack = NULL;
2003-09-10 19:52:12 +02:00
while (true) {
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) parse_field_name(0), &stack);
if (!PAR_match(KW_COMMA))
2001-05-23 15:26:42 +02:00
break;
}
node->syn_arg[s_mod_list] = make_list(stack);
}
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_OF))
2001-05-23 15:26:42 +02:00
node->syn_arg[s_mod_rse] = parse_rse();
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_modify_index(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ m o d i f y _ i n d e x
*
**************************************
*
* Functional description
* Parse a MODIFY INDEX statement.
2001-05-23 15:26:42 +02:00
*
**************************************/
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_mod_index, s_mfi_count);
2004-03-07 08:58:55 +01:00
node->syn_arg[s_mfi_database] = (qli_syntax*) parse_database();
node->syn_arg[s_mfi_name] = (qli_syntax*) parse_name();
2001-05-23 15:26:42 +02:00
PAR_real();
2003-09-10 19:52:12 +02:00
while (true) {
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_UNIQUE))
2001-05-23 15:26:42 +02:00
node->syn_flags |= (s_dfi_flag_selectivity | s_dfi_flag_unique);
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_DUPLICATE)) {
2001-05-23 15:26:42 +02:00
node->syn_flags |= s_dfi_flag_selectivity;
node->syn_flags &= ~s_dfi_flag_unique;
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_INACTIVE))
2001-05-23 15:26:42 +02:00
node->syn_flags |= (s_dfi_flag_activity | s_dfi_flag_inactive);
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_ACTIVE)) {
2001-05-23 15:26:42 +02:00
node->syn_flags |= s_dfi_flag_activity;
node->syn_flags &= ~s_dfi_flag_inactive;
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_DESCENDING))
2001-05-23 15:26:42 +02:00
node->syn_flags |= (s_dfi_flag_order | s_dfi_flag_descending);
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_ASCENDING)) {
2001-05-23 15:26:42 +02:00
node->syn_flags |= s_dfi_flag_order;
node->syn_flags &= ~s_dfi_flag_inactive;
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_STATISTICS))
2001-05-23 15:26:42 +02:00
node->syn_flags |= s_dfi_flag_statistics;
else
break;
}
if (!node->syn_flags)
2004-05-16 03:42:11 +02:00
ERRQ_syntax(195); // Msg195 index state option
2001-05-23 15:26:42 +02:00
command_end();
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_modify_relation(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ m o d i f y _ r e l a t i o n
*
**************************************
*
* Functional description
* Parse a MODIFY RELATION statement.
2001-05-23 15:26:42 +02:00
*
**************************************/
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_mod_relation, 2);
2004-02-02 12:02:12 +01:00
qli_rel* relation = parse_qualified_relation();
2004-03-07 08:58:55 +01:00
node->syn_arg[0] = (qli_syntax*) relation;
2001-05-23 15:26:42 +02:00
if (!relation)
2004-05-16 03:42:11 +02:00
ERRQ_syntax(196); // Msg196 relation name
2001-05-23 15:26:42 +02:00
for (;;) {
PAR_real();
2004-02-02 12:02:12 +01:00
qli_fld* field;
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_ADD)) {
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
PAR_match(KW_FIELD);
field = parse_field(false);
2001-05-23 15:26:42 +02:00
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_MODIFY)) {
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
PAR_match(KW_FIELD);
field = parse_field(false);
2001-05-23 15:26:42 +02:00
field->fld_flags |= FLD_modify;
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_DROP)) {
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
PAR_match(KW_FIELD);
field = parse_field(false);
2001-05-23 15:26:42 +02:00
field->fld_flags |= FLD_drop;
}
else
2004-05-16 03:42:11 +02:00
ERRQ_syntax(197); // Msg197 ADD, MODIFY, or DROP
2004-02-02 12:02:12 +01:00
field->fld_next = (qli_fld*) node->syn_arg[1];
2004-03-07 08:58:55 +01:00
node->syn_arg[1] = (qli_syntax*) field;
2001-05-23 15:26:42 +02:00
if (KEYWORD(KW_SEMI))
break;
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_COMMA))
ERRQ_syntax(198); // Msg198 comma between field definitions
2001-05-23 15:26:42 +02:00
}
command_end();
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_multiply( USHORT * paren_count, bool* bool_flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ m u l t i p l y
*
**************************************
*
* Functional description
2001-07-12 07:46:06 +02:00
* Parse the operatrs * and /.
2001-05-23 15:26:42 +02:00
*
**************************************/
2001-07-12 07:46:06 +02:00
NOD_T operatr;
2001-05-23 15:26:42 +02:00
2004-03-07 08:58:55 +01:00
qli_syntax* node = parse_from(paren_count, bool_flag);
2001-05-23 15:26:42 +02:00
2003-09-10 19:52:12 +02:00
while (true) {
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_ASTERISK))
2001-07-12 07:46:06 +02:00
operatr = nod_multiply;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_SLASH))
2001-07-12 07:46:06 +02:00
operatr = nod_divide;
2001-05-23 15:26:42 +02:00
else
return node;
2004-03-07 08:58:55 +01:00
qli_syntax* arg = node;
2004-05-16 03:42:11 +02:00
node = syntax_node(operatr, 2);
2001-05-23 15:26:42 +02:00
node->syn_arg[0] = arg;
node->syn_arg[1] = parse_from(paren_count, bool_flag);
}
}
static NAM parse_name(void)
{
/**************************************
*
* p a r s e _ n a m e
*
**************************************
*
* Functional description
* Turn current token into a name and get the next token.
*
**************************************/
PAR_real();
const bool isQuoted = QLI_token->tok_type == tok_quoted && sql_flag &&
QLI_token->tok_string[0] == '"';
if (QLI_token->tok_type != tok_ident && !isQuoted)
2004-05-16 03:42:11 +02:00
ERRQ_syntax(199); // Msg199 identifier
2001-05-23 15:26:42 +02:00
SSHORT l = QLI_token->tok_length - 2 * int(isQuoted);
NAM name = (NAM) ALLOCDV(type_nam, l);
2001-05-23 15:26:42 +02:00
name->nam_length = l;
name->nam_symbol = QLI_token->tok_symbol;
const TEXT* q = QLI_token->tok_string + int(isQuoted);
TEXT* p = name->nam_string;
2001-05-23 15:26:42 +02:00
if (isQuoted)
memcpy(p, q, l);
else if (l)
2001-05-23 15:26:42 +02:00
do {
const TEXT c = *q++;
2001-05-23 15:26:42 +02:00
*p++ = UPPER(c);
} while (--l);
PAR_token();
return name;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_not( USHORT * paren_count)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ n o t
*
**************************************
*
* Functional description
* Parse a prefix NOT expression.
*
**************************************/
PAR_real();
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_NOT))
2001-05-23 15:26:42 +02:00
return parse_relational(paren_count);
return negate(parse_not(paren_count));
}
static int parse_ordinal(void)
{
/**************************************
*
* p a r s e _ o r d i n a l
*
**************************************
*
* Functional description
* Pick up a simple number as a number. This is
* used for SKIP [n], SPACE [n], COL n, and SQL
2001-05-23 15:26:42 +02:00
* positions.
*
**************************************/
PAR_real();
if (QLI_token->tok_type != tok_number)
2004-05-16 03:42:11 +02:00
ERRQ_syntax(200); // Msg200 positive number
2001-05-23 15:26:42 +02:00
const int n = atoi(QLI_token->tok_string);
2001-05-23 15:26:42 +02:00
if (n < 0)
2004-05-16 03:42:11 +02:00
ERRQ_syntax(200); // Msg200 positive number
2001-05-23 15:26:42 +02:00
PAR_token();
return n;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_output(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ o u t p u t
*
**************************************
*
* Functional description
* Parse an output clause the the absence thereof.
*
**************************************/
USHORT flag;
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_ON))
2001-05-23 15:26:42 +02:00
flag = FALSE;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_TO))
2001-05-23 15:26:42 +02:00
flag = TRUE;
else
return NULL;
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_output, s_out_count);
2001-05-23 15:26:42 +02:00
node->syn_arg[s_out_file] = parse_value(0, 0);
node->syn_arg[s_out_pipe] = INT_CAST flag;
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_primitive_value( USHORT* paren_count, bool* bool_flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ p r i m i t i v e _ v a l u e
*
**************************************
*
* Functional description
* Pick up a value expression. This may be either a field reference
* or a constant value.
*
**************************************/
USHORT local_count;
if (!paren_count) {
local_count = 0;
paren_count = &local_count;
}
PAR_real();
2004-03-07 08:58:55 +01:00
qli_syntax* node;
2001-05-23 15:26:42 +02:00
switch (next_keyword()) {
case KW_LEFT_PAREN:
PAR_token();
(*paren_count)++;
if (bool_flag && *bool_flag)
node = parse_boolean(paren_count);
else
node = parse_value(paren_count, bool_flag);
/*
if (*paren_count && KEYWORD (KW_RIGHT_PAREN))
*/
{
parse_matching_paren();
(*paren_count)--;
}
break;
case KW_PLUS:
PAR_token();
return parse_primitive_value(paren_count, 0);
case KW_MINUS:
2004-03-07 08:58:55 +01:00
{
PAR_token();
qli_syntax* sub = parse_primitive_value(paren_count, 0);
if (sub->syn_type == nod_constant) {
qli_const* constant = (qli_const*) sub->syn_arg[0];
UCHAR* p = constant->con_desc.dsc_address;
switch (constant->con_desc.dsc_dtype) {
case dtype_long:
*(SLONG *) p = -*(SLONG *) p;
return sub;
case dtype_text:
*p = '-';
return sub;
}
2001-05-23 15:26:42 +02:00
}
2004-05-16 03:42:11 +02:00
node = syntax_node(nod_negate, 1);
2004-03-07 08:58:55 +01:00
node->syn_arg[0] = sub;
break;
2001-05-23 15:26:42 +02:00
}
case KW_ASTERISK:
node = parse_prompt();
break;
case KW_EDIT:
PAR_token();
2004-05-16 03:42:11 +02:00
node = syntax_node(nod_edit_blob, 1);
2001-05-23 15:26:42 +02:00
if (!KEYWORD(KW_SEMI))
node->syn_arg[0] = parse_value(0, 0);
break;
case KW_FORMAT:
PAR_token();
2004-05-16 03:42:11 +02:00
node = syntax_node(nod_format, s_fmt_count);
2001-05-23 15:26:42 +02:00
node->syn_arg[s_fmt_value] = parse_value(0, 0);
2004-03-07 08:58:55 +01:00
node->syn_arg[s_fmt_edit] = (qli_syntax*) parse_edit_string();
2001-05-23 15:26:42 +02:00
break;
case KW_NULL:
PAR_token();
2004-05-16 03:42:11 +02:00
node = syntax_node(nod_null, 0);
2001-05-23 15:26:42 +02:00
break;
case KW_USER_NAME:
PAR_token();
2004-05-16 03:42:11 +02:00
node = syntax_node(nod_user_name, 0);
2001-05-23 15:26:42 +02:00
break;
case KW_COUNT:
case KW_MAX:
case KW_MIN:
case KW_AVERAGE:
case KW_TOTAL:
node = parse_statistical();
break;
case KW_RUNNING:
if (function_count > 0)
IBERROR(487); // Msg487 Invalid argument for UDF
2001-05-23 15:26:42 +02:00
PAR_real_token();
2004-05-16 03:42:11 +02:00
node = syntax_node(nod_running_total, s_stt_count);
if (PAR_match(KW_COUNT))
2001-05-23 15:26:42 +02:00
node->syn_type = nod_running_count;
else {
2004-05-16 03:42:11 +02:00
PAR_match(KW_TOTAL);
2001-05-23 15:26:42 +02:00
node->syn_arg[s_stt_value] = parse_value(0, 0);
}
break;
case KW_SELECT:
node = parse_sql_subquery();
break;
default:
2004-02-02 12:02:12 +01:00
{
const qli_symbol* symbol = QLI_token->tok_symbol;
if (symbol && symbol->sym_type == SYM_function)
{
node = parse_function();
break;
}
if (QLI_token->tok_type == tok_ident
|| QLI_token->tok_type == tok_quoted && sql_flag &&
QLI_token->tok_string[0] == '"')
{
2004-02-02 12:02:12 +01:00
node = parse_field_name(0);
break;
}
2004-05-16 03:42:11 +02:00
node = syntax_node(nod_constant, 1);
2004-03-07 08:58:55 +01:00
node->syn_arg[0] = (qli_syntax*) parse_literal();
2001-05-23 15:26:42 +02:00
}
}
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_print_list(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ p r i n t _ l i s t
*
**************************************
*
* Functional description
* Pick up a print item. The syntax of a print item is:
*
* <value> [ '[ <query_header> '] ] [USING <edit_string> ]
*
**************************************/
2004-03-07 08:58:55 +01:00
qli_syntax* node;
2004-02-02 12:02:12 +01:00
qli_lls* stack = NULL;
2001-05-23 15:26:42 +02:00
2003-09-10 19:52:12 +02:00
while (true) {
NOD_T op;
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_SKIP))
2001-05-23 15:26:42 +02:00
op = nod_skip;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_SPACE))
2001-05-23 15:26:42 +02:00
op = nod_space;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_TAB))
2001-05-23 15:26:42 +02:00
op = nod_tab;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_COLUMN))
2001-05-23 15:26:42 +02:00
op = nod_column;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_NEW_PAGE))
2001-05-23 15:26:42 +02:00
op = nod_new_page;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_REPORT_HEADER))
2001-05-23 15:26:42 +02:00
op = nod_report_header;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_COLUMN_HEADER))
2001-05-23 15:26:42 +02:00
op = nod_column_header;
else {
op = nod_print_item;
2004-05-16 03:42:11 +02:00
node = syntax_node(nod_print_item, s_itm_count);
2001-05-23 15:26:42 +02:00
node->syn_arg[s_itm_value] = parse_value(0, 0);
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_LEFT_PAREN)) {
if (PAR_match(KW_MINUS))
2004-03-07 08:58:55 +01:00
node->syn_arg[s_itm_header] = (qli_syntax*) "-";
2001-05-23 15:26:42 +02:00
else
2004-03-07 08:58:55 +01:00
node->syn_arg[s_itm_header] = (qli_syntax*) parse_header();
2001-05-23 15:26:42 +02:00
parse_matching_paren();
}
2004-03-07 08:58:55 +01:00
node->syn_arg[s_itm_edit_string] = (qli_syntax*) parse_edit_string();
2001-05-23 15:26:42 +02:00
}
if (op != nod_print_item) {
2004-05-16 03:42:11 +02:00
node = syntax_node(op, 1);
2001-05-23 15:26:42 +02:00
node->syn_count = 0;
node->syn_arg[0] = INT_CAST 1;
if (op == nod_column || QLI_token->tok_type == tok_number)
node->syn_arg[0] = INT_CAST parse_ordinal();
2004-03-14 06:51:54 +01:00
if ((op == nod_skip) && ((IPTR) node->syn_arg[0] < 1))
2004-05-16 03:42:11 +02:00
ERRQ_syntax(478); /* Msg478 number > 0 */
2001-05-23 15:26:42 +02:00
}
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) node, &stack);
if (!PAR_match(KW_COMMA) && !PAR_match(KW_AND))
2001-05-23 15:26:42 +02:00
break;
PAR_real();
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_AND))
2001-05-23 15:26:42 +02:00
PAR_real();
}
node = make_list(stack);
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_print(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ p r i n t
*
**************************************
*
* Functional description
* Parse the PRINT statement. This is the richest and most general
* Datatrieve statement. Hence this may get a bit long. The syntax is:
*
* [<item> [, <item>]] OF <rse>
* PRINT [ ] [ON <file>]
* <rse>
*
**************************************/
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_print, s_prt_count);
2001-05-23 15:26:42 +02:00
PAR_token();
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_ALL) && PAR_match(KW_DISTINCT))
2001-05-23 15:26:42 +02:00
node->syn_arg[s_prt_distinct] = INT_CAST TRUE;
if (node->syn_arg[s_prt_output] = parse_output())
return node;
if (test_end())
return node;
/* If there is a potential record selection expression, there obviously
can't be a print list. Get the rse. Otherwise, pick up the print
list. */
if (potential_rse())
node->syn_arg[s_prt_rse] = parse_rse();
else if (!KEYWORD(KW_USING)) {
if (!KEYWORD(KW_THEN) && !KEYWORD(KW_OF) && !KEYWORD(KW_ON))
node->syn_arg[s_prt_list] = parse_print_list();
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_OF))
2001-05-23 15:26:42 +02:00
node->syn_arg[s_prt_rse] = parse_rse();
}
2004-05-16 03:42:11 +02:00
if (!node->syn_arg[s_prt_list] && PAR_match(KW_USING)) {
IBERROR(484); // FORMs not supported
2001-05-23 15:26:42 +02:00
}
else
node->syn_arg[s_prt_output] = parse_output();
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_prompt(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ p r o m p t
*
**************************************
*
* Functional description
* Parse a prompt expression.
*
**************************************/
PAR_token();
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_prompt, 1);
2001-05-23 15:26:42 +02:00
// If there is a period, get the prompt string and make a string node
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_DOT)) {
2001-05-23 15:26:42 +02:00
PAR_real();
USHORT l = QLI_token->tok_length;
const TEXT* q = QLI_token->tok_string;
2001-05-23 15:26:42 +02:00
if (QLI_token->tok_type == tok_quoted) {
q++;
l -= 2;
}
2004-03-07 08:58:55 +01:00
node->syn_arg[0] = (qli_syntax*) make_string(q, l);
2001-05-23 15:26:42 +02:00
PAR_token();
}
return node;
}
static QFL parse_qualified_filter(void)
{
/**************************************
*
* p a r s e _ q u a l i f i e d _ f i l t e r
*
**************************************
*
* Functional description
* This token ought to be a filter, possibly qualified.
* Return a qualified filter block, containing the
2001-05-23 15:26:42 +02:00
* filter name in a NAM block and the database in a
* DBB block if a database was specified. Somebody
* else will decide what to do if the database was not
* specified.
*
**************************************/
QFL filter = (QFL) ALLOCD(type_qfl);
2001-05-23 15:26:42 +02:00
filter->qfl_database = parse_database();
filter->qfl_name = parse_name();
return filter;
}
static QFN parse_qualified_function(void)
{
/**************************************
*
* p a r s e _ q u a l i f i e d _ f u n c t i o n
*
**************************************
*
* Functional description
* This token ought to be a function, possibly qualified.
* Return a qualified function block, containing the
2001-05-23 15:26:42 +02:00
* function name in a NAM block and the database in a
* DBB block if a database was specified. Somebody
* else will decide what to do if the database was not
* specified.
*
**************************************/
QFN func = (QFN) ALLOCD(type_qfn);
2001-05-23 15:26:42 +02:00
func->qfn_database = parse_database();
func->qfn_name = parse_name();
return func;
}
static QPR parse_qualified_procedure(void)
{
/**************************************
*
* p a r s e _ q u a l i f i e d _ p r o c e d u r e
*
**************************************
*
* Functional description
* This token ought to be a procedure, possibly qualified.
* Return a qualified procedure block, containing the
2001-05-23 15:26:42 +02:00
* procedure name in a NAM block and the database in a
* DBB block if a database was specified. Somebody
* else will decide what to do if the database was not
* specified.
*
**************************************/
QPR proc = (QPR) ALLOCD(type_qpr);
2001-05-23 15:26:42 +02:00
proc->qpr_database = parse_database();
proc->qpr_name = parse_name();
return proc;
}
2004-02-02 12:02:12 +01:00
static qli_rel* parse_qualified_relation(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ q u a l i f i e d _ r e l a t i o n
*
**************************************
*
* Functional description
* Check for a relation name, possible qualified. If there
* is a relation name, parse it and return the relation. If
* not, return NULL. Produce a syntax error only if there is
* a partially qualified name.
*
**************************************/
PAR_real();
// If the next token is a database symbol, take it as a qualifier
2001-05-23 15:26:42 +02:00
2004-02-02 12:02:12 +01:00
qli_symbol* db_symbol = QLI_token->tok_symbol;
if (db_symbol && db_symbol->sym_type == SYM_database)
{
2001-05-23 15:26:42 +02:00
PAR_real_token();
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_DOT))
ERRQ_syntax(202); // Msg202 period in qualified relation name
2001-05-23 15:26:42 +02:00
PAR_real();
qli_rel* relation = resolve_relation(db_symbol, QLI_token->tok_symbol);
if (relation) {
2001-05-23 15:26:42 +02:00
PAR_token();
return relation;
}
ERRQ_print_error(203, SafeArg() << QLI_token->tok_string << db_symbol->sym_string);
// Msg203 %s is not a relation in database %s
2001-05-23 15:26:42 +02:00
}
qli_rel* relation = resolve_relation(0, QLI_token->tok_symbol);
if (relation)
2001-05-23 15:26:42 +02:00
PAR_token();
return relation;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_ready( NOD_T node_type)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ r e a d y
*
**************************************
*
* Functional description
* Parse a READY statement:
2001-05-23 15:26:42 +02:00
*
* READY <filename> [AS <symbol>] [,...];
*
**************************************/
2004-02-02 12:02:12 +01:00
qli_lls* stack = NULL;
2001-05-23 15:26:42 +02:00
2003-09-10 19:52:12 +02:00
while (true) {
2001-05-23 15:26:42 +02:00
LEX_filename();
SSHORT l = QLI_token->tok_length;
if (!l)
ERRQ_error(204);
// Msg204 database file name required on READY
const TEXT* q = QLI_token->tok_string;
2001-05-23 15:26:42 +02:00
if (QLI_token->tok_type == tok_quoted) {
l -= 2;
q++;
}
DBB database = (DBB) ALLOCDV(type_dbb, l);
2001-05-23 15:26:42 +02:00
database->dbb_filename_length = l;
TEXT* p = database->dbb_filename;
do {
2001-05-23 15:26:42 +02:00
*p++ = *q++;
} while (--l);
2001-05-23 15:26:42 +02:00
PAR_token();
if (node_type == nod_def_database || node_type == nod_ready) {
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_AS)) {
NAM name = parse_name();
2004-02-02 12:02:12 +01:00
database->dbb_symbol = (qli_symbol*) name;
2001-05-23 15:26:42 +02:00
if (HSH_lookup(name->nam_string, name->nam_length))
ERRQ_error(408, name->nam_string);
// Database handle is not unique
2001-05-23 15:26:42 +02:00
}
else
2004-02-02 12:02:12 +01:00
database->dbb_symbol = (qli_symbol*) make_name();
2001-05-23 15:26:42 +02:00
}
else if (node_type == nod_sql_database) {
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_PAGESIZE)) {
2001-05-23 15:26:42 +02:00
if (database->dbb_pagesize)
2004-05-16 03:42:11 +02:00
ERRQ_syntax(390); // Msg390 Multiple page size specifications
if (!PAR_match(KW_EQUALS))
ERRQ_syntax(396); // Msg396 = (equals)
2001-05-23 15:26:42 +02:00
database->dbb_pagesize = parse_ordinal();
}
2004-02-02 12:02:12 +01:00
database->dbb_symbol = (qli_symbol*) make_name();
2001-05-23 15:26:42 +02:00
}
for (;;) {
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_USER))
2001-05-23 15:26:42 +02:00
database->dbb_user = parse_literal();
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_PASSWORD))
2001-05-23 15:26:42 +02:00
database->dbb_password = parse_literal();
else
break;
}
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) database, &stack);
2001-05-23 15:26:42 +02:00
if (!KEYWORD(KW_COMMA) || (node_type == nod_sql_database))
break;
}
command_end();
2004-03-07 08:58:55 +01:00
qli_syntax* node = make_list(stack);
2001-05-23 15:26:42 +02:00
node->syn_type = node_type;
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_relational( USHORT * paren_count)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ r e l a t i o n a l
*
**************************************
*
* Functional description
* Parse a relational expression.
*
**************************************/
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_ANY)) {
qli_syntax* anode = syntax_node(nod_any, 1);
anode->syn_arg[0] = parse_rse();
return anode;
2001-05-23 15:26:42 +02:00
}
NOD_T operatr = (NOD_T) 0;
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_EXISTS))
2001-07-12 07:46:06 +02:00
operatr = nod_any;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_SINGULAR))
2001-07-12 07:46:06 +02:00
operatr = nod_unique;
2001-05-23 15:26:42 +02:00
2001-07-12 07:46:06 +02:00
if (operatr != (NOD_T) 0) {
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_LEFT_PAREN)) {
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_SELECT)) {
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(operatr, 2);
if (!PAR_match(KW_ASTERISK))
2001-05-23 15:26:42 +02:00
node->syn_arg[1] = parse_value(0, 0);
node->syn_arg[0] = parse_sql_rse();
parse_matching_paren();
return node;
}
}
2001-07-12 07:46:06 +02:00
if (operatr == nod_any)
2004-05-16 03:42:11 +02:00
ERRQ_syntax(205); /* Msg205 EXISTS (SELECT * <sql rse>) */
2001-05-23 15:26:42 +02:00
else
2004-05-16 03:42:11 +02:00
ERRQ_syntax(488); /* Msg488 SINGULAR (SELECT * <sql rse>) */
2001-05-23 15:26:42 +02:00
}
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_UNIQUE)) {
qli_syntax* node = syntax_node(nod_unique, 1);
2001-05-23 15:26:42 +02:00
node->syn_arg[0] = parse_rse();
return node;
}
bool local_flag = true;
2004-03-07 08:58:55 +01:00
qli_syntax* expr1 = parse_value(paren_count, &local_flag);
2001-05-23 15:26:42 +02:00
if (KEYWORD(KW_RIGHT_PAREN))
return expr1;
const nod_t* rel_ops;
2001-05-23 15:26:42 +02:00
if (KEYWORD(KW_SEMI))
for (rel_ops = relationals; *rel_ops != (NOD_T) 0; rel_ops++)
if (expr1->syn_type == *rel_ops)
return expr1;
bool negation = false;
2004-03-07 08:58:55 +01:00
qli_syntax* node = NULL;
2004-05-16 03:42:11 +02:00
PAR_match(KW_IS);
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_NOT)) {
negation = true;
2001-05-23 15:26:42 +02:00
PAR_real();
}
switch (next_keyword()) {
case KW_IN:
PAR_token();
node = parse_in(expr1, nod_eql, false);
2001-05-23 15:26:42 +02:00
break;
case KW_EQUALS:
case KW_EQ:
2001-07-12 07:46:06 +02:00
operatr = (negation) ? nod_neq : nod_eql;
negation = false;
2001-05-23 15:26:42 +02:00
break;
case KW_NE:
2001-07-12 07:46:06 +02:00
operatr = (negation) ? nod_eql : nod_neq;
negation = false;
2001-05-23 15:26:42 +02:00
break;
case KW_GT:
2001-07-12 07:46:06 +02:00
operatr = (negation) ? nod_leq : nod_gtr;
negation = false;
2001-05-23 15:26:42 +02:00
break;
case KW_GE:
2001-07-12 07:46:06 +02:00
operatr = (negation) ? nod_lss : nod_geq;
negation = false;
2001-05-23 15:26:42 +02:00
break;
case KW_LE:
2001-07-12 07:46:06 +02:00
operatr = (negation) ? nod_gtr : nod_leq;
negation = false;
2001-05-23 15:26:42 +02:00
break;
case KW_LT:
2001-07-12 07:46:06 +02:00
operatr = (negation) ? nod_geq : nod_lss;
negation = false;
2001-05-23 15:26:42 +02:00
break;
case KW_CONTAINING:
2001-07-12 07:46:06 +02:00
operatr = nod_containing;
2001-05-23 15:26:42 +02:00
break;
case KW_MATCHES:
node = parse_matches();
node->syn_arg[0] = expr1;
2001-07-12 07:46:06 +02:00
operatr = node->syn_type;
2001-05-23 15:26:42 +02:00
break;
case KW_LIKE:
PAR_token();
2004-05-16 03:42:11 +02:00
node = syntax_node(nod_like, 3);
2001-05-23 15:26:42 +02:00
node->syn_arg[0] = expr1;
node->syn_arg[1] = parse_value(0, 0);
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_ESCAPE))
2001-05-23 15:26:42 +02:00
node->syn_arg[2] = parse_value(0, 0);
else
node->syn_count = 2;
break;
case KW_STARTS:
PAR_token();
2004-05-16 03:42:11 +02:00
PAR_match(KW_WITH);
node = syntax_node(nod_starts, 2);
2001-05-23 15:26:42 +02:00
node->syn_arg[0] = expr1;
node->syn_arg[1] = parse_value(0, 0);
break;
case KW_NULL:
case KW_MISSING:
PAR_token();
2004-05-16 03:42:11 +02:00
node = syntax_node(nod_missing, 1);
2001-05-23 15:26:42 +02:00
node->syn_arg[0] = expr1;
break;
case KW_BETWEEN:
PAR_token();
2004-05-16 03:42:11 +02:00
node = syntax_node(nod_between, 3);
2001-05-23 15:26:42 +02:00
node->syn_arg[0] = expr1;
node->syn_arg[1] = parse_value(0, 0);
2004-05-16 03:42:11 +02:00
PAR_match(KW_AND);
2001-05-23 15:26:42 +02:00
node->syn_arg[2] = parse_value(0, 0);
break;
default:
for (rel_ops = relationals; *rel_ops != (NOD_T) 0; rel_ops++)
if (expr1->syn_type == *rel_ops)
return expr1;
2004-05-16 03:42:11 +02:00
ERRQ_syntax(206); // Msg206 relational operatr
2001-05-23 15:26:42 +02:00
}
2001-07-12 07:46:06 +02:00
/* If we haven't already built a node, it must be an ordinary binary operatr.
2001-05-23 15:26:42 +02:00
Build it. */
if (!node) {
PAR_token();
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_ANY))
return parse_in(expr1, operatr, false);
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_ALL))
return parse_in(expr1, operatr, true);
2004-05-16 03:42:11 +02:00
node = syntax_node(operatr, 2);
2001-05-23 15:26:42 +02:00
node->syn_arg[0] = expr1;
node->syn_arg[1] = parse_value(paren_count, &local_flag);
}
// If a negation remains to be handled, zap the node under a NOT.
2001-05-23 15:26:42 +02:00
if (negation)
node = negate(node);
/* If the node isn't an equality, we've done. Since equalities can be
structured as implicit ORs, build them here. */
2001-07-12 07:46:06 +02:00
if (operatr != nod_eql)
2001-05-23 15:26:42 +02:00
return node;
/* We have an equality operation, which can take a number of values. Generate
implicit ORs */
2004-05-16 03:42:11 +02:00
while (PAR_match(KW_COMMA)) {
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
PAR_match(KW_OR);
qli_syntax* or_node = syntax_node(nod_or, 2);
2001-05-23 15:26:42 +02:00
or_node->syn_arg[0] = node;
2004-05-16 03:42:11 +02:00
or_node->syn_arg[1] = node = syntax_node(nod_eql, 2);
2001-05-23 15:26:42 +02:00
node->syn_arg[0] = expr1;
node->syn_arg[1] = parse_value(paren_count, &local_flag);
node = or_node;
}
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_relation(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ r e l a t i o n
*
**************************************
*
* Functional description
* Parse a relation expression. Syntax is:
*
* [ <context_variable> IN ] <relation>
*
**************************************/
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_relation, s_rel_count);
2001-05-23 15:26:42 +02:00
// Token wasn't a relation name, maybe it's a context variable.
2001-05-23 15:26:42 +02:00
2004-03-07 08:58:55 +01:00
if (!(node->syn_arg[s_rel_relation] = (qli_syntax*) parse_qualified_relation())) {
2004-02-02 12:02:12 +01:00
qli_symbol* context = parse_symbol();
2004-03-07 08:58:55 +01:00
node->syn_arg[s_rel_context] = (qli_syntax*) context;
2004-05-16 03:42:11 +02:00
if (sql_flag || !PAR_match(KW_IN)) {
2001-05-23 15:26:42 +02:00
if (!QLI_databases)
IBERROR(207); // Msg207 a database has not been readied
ERRQ_print_error(208, context->sym_string);
// Msg208 expected \"relation_name\", encountered \"%s\"
2001-05-23 15:26:42 +02:00
}
if (!
2004-03-07 08:58:55 +01:00
(node->syn_arg[s_rel_relation] = (qli_syntax*) parse_qualified_relation()))
{
2004-05-16 03:42:11 +02:00
ERRQ_syntax(209); // Msg209 relation name
}
2001-05-23 15:26:42 +02:00
}
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_rename(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ r e n a m e
*
**************************************
*
* Functional description
* Parse a PROCEDURE rename statement.
*
**************************************/
PAR_real_token();
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_PROCEDURE))
ERRQ_syntax(210); // Msg210 PROCEDURE
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_rename_proc, 2);
2004-03-07 08:58:55 +01:00
node->syn_arg[0] = (qli_syntax*) parse_qualified_procedure();
2004-05-16 03:42:11 +02:00
PAR_match(KW_TO);
2004-03-07 08:58:55 +01:00
node->syn_arg[1] = (qli_syntax*) parse_qualified_procedure();
2001-05-23 15:26:42 +02:00
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_repeat(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ r e p e a t
*
**************************************
*
* Functional description
* Parse REPEAT statement.
*
**************************************/
PAR_token();
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_repeat, s_rpt_count);
2001-05-23 15:26:42 +02:00
node->syn_arg[s_rpt_value] = parse_value(0, 0);
node->syn_arg[s_rpt_statement] = parse_statement();
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_report(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ r e p o r t
*
**************************************
*
* Functional description
* Parse a report specification.
*
**************************************/
++sw_report;
PAR_token();
2004-02-02 12:02:12 +01:00
qli_rpt* report = (qli_rpt*) ALLOCD(type_rpt);
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_report, s_prt_count);
2004-03-07 08:58:55 +01:00
node->syn_arg[s_prt_list] = (qli_syntax*) report;
2001-05-23 15:26:42 +02:00
// Pick up record select expression
2001-05-23 15:26:42 +02:00
2004-03-07 08:58:55 +01:00
qli_syntax* rse = node->syn_arg[s_prt_rse] = parse_rse();
2001-05-23 15:26:42 +02:00
node->syn_arg[s_prt_output] = parse_output();
// Pick up report clauses
2001-05-23 15:26:42 +02:00
bool top;
2001-05-23 15:26:42 +02:00
for (;;) {
PAR_real();
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_END_REPORT))
2001-05-23 15:26:42 +02:00
break;
switch (next_keyword()) {
case KW_PRINT:
PAR_token();
2004-02-02 12:02:12 +01:00
report->rpt_detail_line = (qli_nod*) parse_print_list();
2001-05-23 15:26:42 +02:00
break;
case KW_AT:
PAR_token();
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_TOP))
top = true;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_BOTTOM))
top = false;
2001-05-23 15:26:42 +02:00
else
2004-05-16 03:42:11 +02:00
ERRQ_syntax(382); // Msg382 TOP or BOTTOM
PAR_match(KW_OF);
if (PAR_match(KW_REPORT)) {
qli_brk* control = (qli_brk*) ALLOCD(type_brk);
qli_brk** ptr =
(top) ? &report->rpt_top_rpt : &report->rpt_bottom_rpt;
2001-05-23 15:26:42 +02:00
control->brk_next = *ptr;
*ptr = control;
2004-05-16 03:42:11 +02:00
PAR_match(KW_PRINT);
2001-05-23 15:26:42 +02:00
control->brk_line = parse_print_list();
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_PAGE)) {
qli_brk* control = (qli_brk*) ALLOCD(type_brk);
qli_brk** ptr =
2001-05-23 15:26:42 +02:00
(top) ? &report->rpt_top_page : &report->rpt_bottom_page;
control->brk_next = *ptr;
*ptr = control;
2004-05-16 03:42:11 +02:00
PAR_match(KW_PRINT);
2001-05-23 15:26:42 +02:00
control->brk_line = parse_print_list();
}
else {
qli_brk** ptr =
(top) ? &report->rpt_top_breaks : &report->rpt_bottom_breaks;
2001-05-23 15:26:42 +02:00
if (!*ptr) {
/* control breaks should only be on sorted fields, set up list
of control breaks based on sorted fields and then add action (print)
items to that list. */
2004-03-07 08:58:55 +01:00
qli_syntax* flds = rse->syn_arg[s_rse_sort];
if (!flds)
2004-05-16 03:42:11 +02:00
ERRQ_syntax(383); // Msg383 sort field
qli_brk* tmpptr = *ptr;
for (USHORT i = 0; i < flds->syn_count; i += 2) {
qli_brk* control = (qli_brk*) ALLOCD(type_brk);
2001-05-23 15:26:42 +02:00
control->brk_field = flds->syn_arg[i];
control->brk_line = NULL;
control->brk_statisticals = NULL;
control->brk_next = tmpptr;
tmpptr = control;
}
if (!top) {
/* reverse the 'at bottom' control break list as the
lower control breaks should be performed prior to the higher ones. */
qli_brk* control = 0;
for (qli_brk* tmpptr1 = tmpptr->brk_next; tmpptr;) {
2001-05-23 15:26:42 +02:00
tmpptr->brk_next = control;
control = tmpptr;
if (tmpptr = tmpptr1)
tmpptr1 = tmpptr->brk_next;
}
tmpptr = control;
}
*ptr = tmpptr;
}
2004-03-07 08:58:55 +01:00
qli_syntax* qli_fld = parse_field_name(0);
qli_brk* control;
2001-05-23 15:26:42 +02:00
for (control = *ptr; control; control = control->brk_next) {
2004-03-07 08:58:55 +01:00
qli_syntax* rse_fld = (qli_syntax*) control->brk_field;
if (rse_fld->syn_type != qli_fld->syn_type)
2001-05-23 15:26:42 +02:00
continue;
/* if number of field qualifiers on sort field and control field
are not equal test match of rightmost set */
2004-05-29 07:03:08 +02:00
const USHORT syn_count = MIN(rse_fld->syn_count, qli_fld->syn_count);
USHORT srt_syn = 0, ctl_syn = 0;
2001-05-23 15:26:42 +02:00
if (syn_count != rse_fld->syn_count)
srt_syn = rse_fld->syn_count - syn_count;
if (syn_count != qli_fld->syn_count)
ctl_syn = qli_fld->syn_count - syn_count;
USHORT i;
2001-05-23 15:26:42 +02:00
for (i = 0; i < syn_count; i++) {
const nam* name1 = (NAM) rse_fld->syn_arg[i + srt_syn];
const nam* name2 = (NAM) qli_fld->syn_arg[i + ctl_syn];
2001-05-23 15:26:42 +02:00
if (strcmp(name1->nam_string, name2->nam_string))
break;
}
if (i == qli_fld->syn_count)
2001-05-23 15:26:42 +02:00
break;
}
if (!control)
2004-05-16 03:42:11 +02:00
ERRQ_syntax(383); // Msg383 sort field
PAR_match(KW_PRINT);
control->brk_field = qli_fld;
2001-05-23 15:26:42 +02:00
control->brk_line = parse_print_list();
}
break;
case KW_SET:
PAR_token();
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_COLUMNS)) {
PAR_match(KW_EQUALS);
2001-05-23 15:26:42 +02:00
report->rpt_columns = parse_ordinal();
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_LINES)) {
PAR_match(KW_EQUALS);
2001-05-23 15:26:42 +02:00
report->rpt_lines = parse_ordinal();
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_REPORT_NAME)) {
PAR_match(KW_EQUALS);
report->rpt_name = parse_header();
2001-05-23 15:26:42 +02:00
}
else
2004-05-16 03:42:11 +02:00
ERRQ_syntax(212); // Msg212 report writer SET option
2001-05-23 15:26:42 +02:00
break;
default:
2004-05-16 03:42:11 +02:00
ERRQ_syntax(213); // Msg213 report item
2001-05-23 15:26:42 +02:00
}
2004-05-16 03:42:11 +02:00
PAR_match(KW_SEMI);
2001-05-23 15:26:42 +02:00
}
if (!node->syn_arg[s_prt_output])
node->syn_arg[s_prt_output] = parse_output();
check_end();
--sw_report;
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_rse(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ r s e
*
**************************************
*
* Functional description
* Parse a record selection expression.
*
**************************************/
PAR_real();
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_ALL))
2001-05-23 15:26:42 +02:00
PAR_real();
2004-03-07 08:58:55 +01:00
qli_syntax* first = NULL;
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_FIRST))
2001-05-23 15:26:42 +02:00
first = parse_value(0, 0);
USHORT count = 0;
2004-02-02 12:02:12 +01:00
qli_lls* stack = NULL;
2003-09-10 19:52:12 +02:00
while (true) {
2001-05-23 15:26:42 +02:00
count++;
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) parse_relation(), &stack);
2004-03-07 08:58:55 +01:00
qli_syntax* over = NULL;
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_OVER)) {
2004-02-02 12:02:12 +01:00
qli_lls* field_stack = NULL;
2003-09-10 19:52:12 +02:00
while (true) {
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) parse_field_name(0), &field_stack);
if (!PAR_match(KW_COMMA))
2001-05-23 15:26:42 +02:00
break;
}
over = make_list(field_stack);
}
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) over, &stack);
if (!PAR_match(KW_CROSS))
2001-05-23 15:26:42 +02:00
break;
}
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_rse, (int) s_rse_count + 2 * count);
2001-05-23 15:26:42 +02:00
node->syn_count = count;
node->syn_arg[s_rse_first] = first;
2004-03-07 08:58:55 +01:00
qli_syntax** ptr = &node->syn_arg[(int) s_rse_count + 2 * count];
2001-05-23 15:26:42 +02:00
while (stack)
2004-05-16 03:42:11 +02:00
*--ptr = (qli_syntax*) ALLQ_pop(&stack);
2001-05-23 15:26:42 +02:00
// Pick up various other clauses
2001-05-23 15:26:42 +02:00
USHORT sw_with = 0;
2003-09-10 19:52:12 +02:00
while (true) {
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_WITH)) {
2001-05-23 15:26:42 +02:00
if (!sw_with) {
sw_with++;
node->syn_arg[s_rse_boolean] = parse_boolean(0);
}
else
IBERROR(384); // Msg384 Too many WITHs
2001-05-23 15:26:42 +02:00
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_SORTED)) {
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
PAR_match(KW_BY);
2001-05-23 15:26:42 +02:00
node->syn_arg[s_rse_sort] = parse_sort();
}
#ifdef PC_ENGINE
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_USING)) {
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
PAR_match(KW_INDEX);
2004-03-07 08:58:55 +01:00
node->syn_arg[s_rse_index] = (qli_syntax*) parse_name();
2001-05-23 15:26:42 +02:00
}
#endif
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_REDUCED)) {
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
PAR_match(KW_TO);
2001-05-23 15:26:42 +02:00
node->syn_arg[s_rse_reduced] = parse_sort();
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_GROUP)) {
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
PAR_match(KW_BY);
2001-05-23 15:26:42 +02:00
stack = NULL;
2003-09-10 19:52:12 +02:00
while (true) {
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) parse_udf_or_field(), &stack);
if (!PAR_match(KW_COMMA))
2001-05-23 15:26:42 +02:00
break;
}
node->syn_arg[s_rse_group_by] = make_list(stack);
}
else
break;
}
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_select(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ s e l e c t
*
**************************************
*
* Functional description
* Parse a SQL select statement.
*
**************************************/
++sql_flag;
PAR_token();
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_print, s_prt_count);
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_ALL) && PAR_match(KW_DISTINCT))
2001-05-23 15:26:42 +02:00
node->syn_arg[s_prt_distinct] = INT_CAST TRUE;
// Get list of items
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_ASTERISK)) {
2004-02-02 12:02:12 +01:00
qli_lls* stack = NULL;
2003-09-10 19:52:12 +02:00
while (true) {
2004-05-16 03:42:11 +02:00
qli_syntax* item = syntax_node(nod_print_item, s_itm_count);
2001-05-23 15:26:42 +02:00
item->syn_arg[s_itm_value] = parse_value(0, 0);
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) item, &stack);
if (!PAR_match(KW_COMMA))
2001-05-23 15:26:42 +02:00
break;
}
node->syn_arg[s_prt_list] = make_list(stack);
}
2004-03-07 08:58:55 +01:00
qli_syntax* rse = parse_sql_rse();
node->syn_arg[s_prt_rse] = rse;
2001-05-23 15:26:42 +02:00
rse->syn_arg[s_rse_list] = node->syn_arg[s_prt_list];
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_ORDER)) {
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
PAR_match(KW_BY);
2001-05-23 15:26:42 +02:00
node->syn_arg[s_prt_order] = parse_sort();
}
--sql_flag;
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_set(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ s e t
*
**************************************
*
* Functional description
* Parse a SET statement.
*
**************************************/
PAR_token();
2004-02-02 12:02:12 +01:00
qli_lls* stack = NULL;
USHORT count = 0;
2001-05-23 15:26:42 +02:00
2003-09-10 19:52:12 +02:00
while (true) {
2001-05-23 15:26:42 +02:00
PAR_real();
U_IPTR value = TRUE;
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_NO)) {
2001-05-23 15:26:42 +02:00
value = FALSE;
PAR_real();
}
enum set_t sw;
2001-05-23 15:26:42 +02:00
switch (QLI_token->tok_keyword) {
case KW_BLR:
sw = set_blr;
PAR_token();
break;
case KW_STATISTICS:
sw = set_statistics;
PAR_token();
break;
case KW_COLUMNS:
sw = set_columns;
PAR_token();
2004-05-16 03:42:11 +02:00
PAR_match(KW_EQUALS);
2001-05-23 15:26:42 +02:00
value = parse_ordinal();
break;
case KW_LINES:
sw = set_lines;
PAR_token();
2004-05-16 03:42:11 +02:00
PAR_match(KW_EQUALS);
2001-05-23 15:26:42 +02:00
value = parse_ordinal();
break;
case KW_SEMICOLON:
sw = set_semi;
PAR_token();
break;
case KW_ECHO:
sw = set_echo;
PAR_token();
break;
2001-05-23 15:26:42 +02:00
case KW_MATCHING_LANGUAGE:
sw = set_matching_language;
PAR_token();
2004-05-16 03:42:11 +02:00
PAR_match(KW_EQUALS);
2001-05-23 15:26:42 +02:00
if (value)
value = (U_IPTR) parse_literal();
break;
case KW_PASSWORD:
sw = set_password;
PAR_token();
value = (U_IPTR) parse_literal();
break;
case KW_PROMPT:
sw = set_prompt;
PAR_token();
value = (U_IPTR) parse_literal();
break;
case KW_CONT_PROMPT:
sw = set_continuation;
PAR_token();
value = (U_IPTR) parse_literal();
break;
case KW_USER:
sw = set_user;
PAR_token();
value = (U_IPTR) parse_literal();
break;
case KW_COUNT:
sw = set_count;
PAR_token();
break;
case KW_CHAR:
sw = set_charset;
PAR_token();
2004-05-16 03:42:11 +02:00
PAR_match(KW_SET);
if (value) { // allow for NO
2004-05-16 03:42:11 +02:00
PAR_match(KW_EQUALS);
2001-05-23 15:26:42 +02:00
value = (U_IPTR) parse_name();
}
break;
case KW_NAMES:
sw = set_charset;
PAR_token();
if (value) {
value = (U_IPTR) parse_name();
}
break;
#ifdef DEV_BUILD
case KW_EXPLAIN:
sw = set_explain;
PAR_token();
break;
case KW_HEXOUT:
sw = set_hex_output;
PAR_token();
break;
#endif
default:
2004-05-16 03:42:11 +02:00
ERRQ_syntax(214); // Msg214 set option
2001-05-23 15:26:42 +02:00
}
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) sw, &stack);
ALLQ_push((blk*) value, &stack);
2001-05-23 15:26:42 +02:00
count++;
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_COMMA))
2001-05-23 15:26:42 +02:00
break;
}
command_end();
2004-03-07 08:58:55 +01:00
qli_syntax* node = make_list(stack);
2001-05-23 15:26:42 +02:00
node->syn_count = count;
node->syn_type = nod_set;
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_shell(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ s h e l l
*
**************************************
*
* Functional description
* Parse SHELL command.
*
**************************************/
PAR_token();
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_shell, 1);
2001-05-23 15:26:42 +02:00
if (!KEYWORD(KW_SEMI))
2004-03-07 08:58:55 +01:00
node->syn_arg[0] = (qli_syntax*) parse_literal();
2001-05-23 15:26:42 +02:00
command_end();
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_show(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ s h o w
*
**************************************
*
* Functional description
* Parse a SHOW statement. The first
* group are individual things (one
2001-05-23 15:26:42 +02:00
* named relation, field, form, ...)
*
2001-05-23 15:26:42 +02:00
* the second group are sets of things
* and can be qualified with a FOR
2001-05-23 15:26:42 +02:00
* [DATABASE] <handle>
*
**************************************/
PAR_token();
2004-02-02 12:02:12 +01:00
qli_lls* stack = NULL;
USHORT count = 0;
2001-05-23 15:26:42 +02:00
2003-09-10 19:52:12 +02:00
while (true) {
2001-05-23 15:26:42 +02:00
PAR_real();
BLK value = NULL;
2004-02-02 12:02:12 +01:00
qli_symbol* symbol = QLI_token->tok_symbol;
enum show_t sw;
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_ALL))
2001-05-23 15:26:42 +02:00
sw = show_all;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_MATCHING_LANGUAGE))
2001-05-23 15:26:42 +02:00
sw = show_matching_language;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_VERSION))
2001-05-23 15:26:42 +02:00
sw = show_version;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_RELATION)) {
2001-05-23 15:26:42 +02:00
if (!(value = (BLK) parse_qualified_relation()))
2004-05-16 03:42:11 +02:00
ERRQ_syntax(216); // Msg216 relation name
2001-05-23 15:26:42 +02:00
else
sw = show_relation;
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_FILTER)) {
2001-05-23 15:26:42 +02:00
sw = show_filter;
value = (BLK) parse_qualified_filter();
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_FUNCTION)) {
2001-05-23 15:26:42 +02:00
sw = show_function;
value = (BLK) parse_qualified_function();
}
2004-05-16 03:42:11 +02:00
else if ((PAR_match(KW_DATABASES)) || (PAR_match(KW_READY)))
2001-05-23 15:26:42 +02:00
sw = show_databases;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_DATABASE)) {
2001-05-23 15:26:42 +02:00
sw = show_database;
if (value = (BLK) get_dbb(QLI_token->tok_symbol))
PAR_token();
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_FIELD)) {
2001-05-23 15:26:42 +02:00
sw = show_field;
value = (BLK) parse_field_name(0);
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_PROCEDURE)) {
2001-05-23 15:26:42 +02:00
sw = show_procedure;
value = (BLK) parse_qualified_procedure();
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_VARIABLE)) {
2001-05-23 15:26:42 +02:00
sw = show_variable;
value = (BLK) parse_name();
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_VARIABLES))
2001-05-23 15:26:42 +02:00
sw = show_variables;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_FIELDS)) {
if (PAR_match(KW_FOR)) {
if (PAR_match(KW_DATABASE)) {
2001-05-23 15:26:42 +02:00
if (value = (BLK) get_dbb(QLI_token->tok_symbol))
PAR_token();
else
2004-05-16 03:42:11 +02:00
ERRQ_syntax(221); // Msg221 database name
2001-05-23 15:26:42 +02:00
sw = show_db_fields;
}
else {
2004-05-16 03:42:11 +02:00
PAR_match(KW_RELATION);
2001-05-23 15:26:42 +02:00
if (!(value = (BLK) parse_qualified_relation()))
2004-05-16 03:42:11 +02:00
ERRQ_syntax(218); // Msg218 relation name
2001-05-23 15:26:42 +02:00
else
sw = show_relation;
}
}
else
sw = show_all;
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_INDICES)) {
2001-05-23 15:26:42 +02:00
sw = show_indices;
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_FOR))
if (PAR_match(KW_DATABASE)) {
2001-05-23 15:26:42 +02:00
if (value = (BLK) get_dbb(QLI_token->tok_symbol))
PAR_token();
else
2004-05-16 03:42:11 +02:00
ERRQ_syntax(221); // Msg221 database name
2001-05-23 15:26:42 +02:00
sw = show_db_indices;
}
else if (!(value = (BLK) parse_qualified_relation()))
2004-05-16 03:42:11 +02:00
ERRQ_syntax(220); // Msg220 relation name
2001-05-23 15:26:42 +02:00
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_SECURITY_CLASS)) {
2001-05-23 15:26:42 +02:00
sw = show_security_class;
value = (BLK) parse_name();
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_TRIGGERS)) {
2001-05-23 15:26:42 +02:00
sw = show_triggers;
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_FOR)) {
if (PAR_match(KW_DATABASE)) {
2001-05-23 15:26:42 +02:00
if (value = (BLK) get_dbb(QLI_token->tok_symbol))
PAR_token();
else
2004-05-16 03:42:11 +02:00
ERRQ_syntax(221); // Msg221 database name
2001-05-23 15:26:42 +02:00
}
else {
2004-05-16 03:42:11 +02:00
PAR_match(KW_RELATION);
2001-05-23 15:26:42 +02:00
if (!(value = (BLK) parse_qualified_relation()))
2004-05-16 03:42:11 +02:00
ERRQ_syntax(222); // Msg222 relation_name
2001-05-23 15:26:42 +02:00
sw = show_trigger;
}
}
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_RELATIONS))
2001-05-23 15:26:42 +02:00
sw = show_relations;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_VIEWS))
2001-05-23 15:26:42 +02:00
sw = show_views;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_SECURITY_CLASSES))
2001-05-23 15:26:42 +02:00
sw = show_security_classes;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_SYSTEM)) {
if (PAR_match(KW_TRIGGERS))
2001-05-23 15:26:42 +02:00
sw = show_system_triggers;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_RELATIONS) ||
2001-05-23 15:26:42 +02:00
QLI_token->tok_type == tok_eol ||
KEYWORD(KW_SEMI) || KEYWORD(KW_FOR))
sw = show_system_relations;
else
2004-05-16 03:42:11 +02:00
ERRQ_syntax(215); // Msg215 RELATIONS or TRIGGERS
2001-05-23 15:26:42 +02:00
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_PROCEDURES))
2001-05-23 15:26:42 +02:00
sw = show_procedures;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_FILTERS))
2001-05-23 15:26:42 +02:00
sw = show_filters;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_FUNCTIONS))
2001-05-23 15:26:42 +02:00
sw = show_functions;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_GLOBAL)) {
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_FIELD)) {
2001-05-23 15:26:42 +02:00
sw = show_global_field;
value = (BLK) parse_field_name(0);
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_FIELDS))
2001-05-23 15:26:42 +02:00
sw = show_global_fields;
}
else if (symbol && symbol->sym_type == SYM_relation) {
sw = show_relation;
value = symbol->sym_object;
PAR_token();
}
else if (value = (BLK) get_dbb(symbol)) {
sw = show_database;
PAR_token();
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_DOT)) {
if (PAR_match(KW_RELATIONS))
2001-05-23 15:26:42 +02:00
sw = show_relations;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_FIELDS))
2001-05-23 15:26:42 +02:00
sw = show_db_fields;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_INDICES))
2001-05-23 15:26:42 +02:00
sw = show_db_indices;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_SECURITY_CLASS))
2001-05-23 15:26:42 +02:00
sw = show_security_class;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_TRIGGERS))
2001-05-23 15:26:42 +02:00
sw = show_triggers;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_VIEWS))
2001-05-23 15:26:42 +02:00
sw = show_views;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_SECURITY_CLASSES))
2001-05-23 15:26:42 +02:00
sw = show_security_classes;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_SYSTEM)) {
if (PAR_match(KW_TRIGGERS))
2001-05-23 15:26:42 +02:00
sw = show_system_triggers;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_RELATIONS) ||
2001-05-23 15:26:42 +02:00
QLI_token->tok_type == tok_eol ||
KEYWORD(KW_SEMI) || KEYWORD(KW_FOR))
2004-05-29 07:03:08 +02:00
{
2001-05-23 15:26:42 +02:00
sw = show_system_relations;
2004-05-29 07:03:08 +02:00
}
2001-05-23 15:26:42 +02:00
else
2004-05-16 03:42:11 +02:00
ERRQ_syntax(215); // Msg215 RELATIONS or TRIGGERS
2001-05-23 15:26:42 +02:00
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_PROCEDURES))
2001-05-23 15:26:42 +02:00
sw = show_procedures;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_FILTERS))
2001-05-23 15:26:42 +02:00
sw = show_filters;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_FUNCTIONS))
2001-05-23 15:26:42 +02:00
sw = show_functions;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_GLOBAL)) {
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_FIELD)) {
2001-05-23 15:26:42 +02:00
sw = show_global_field;
value = (BLK) parse_field_name(0);
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_FIELDS))
2001-05-23 15:26:42 +02:00
sw = show_global_fields;
}
else {
2004-02-02 12:02:12 +01:00
qli_rel* relation =
resolve_relation(symbol, QLI_token->tok_symbol);
if (relation) {
sw = show_relation;
value = relation->rel_symbol->sym_object;
PAR_token();
}
else {
sw = show_procedure;
QPR proc = (QPR) ALLOCD(type_qpr);
proc->qpr_database = (DBB) value;
proc->qpr_name = parse_name();
value = (BLK) proc;
}
2001-05-23 15:26:42 +02:00
}
}
2001-05-23 15:26:42 +02:00
}
else {
sw = show_procedure;
value = (BLK) parse_qualified_procedure();
}
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) sw, &stack);
2001-05-23 15:26:42 +02:00
if (!value && (sw == show_relations || sw == show_views ||
sw == show_security_classes
|| sw == show_system_triggers
|| sw == show_system_relations || sw == show_procedures
2003-03-11 14:38:16 +01:00
|| sw == show_filters
2001-05-23 15:26:42 +02:00
|| sw == show_functions || sw == show_global_fields))
2003-09-11 04:17:05 +02:00
{
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_FOR)) {
PAR_match(KW_DATABASE);
2001-05-23 15:26:42 +02:00
if (value = (BLK) get_dbb(QLI_token->tok_symbol))
PAR_token();
else
2004-05-16 03:42:11 +02:00
ERRQ_syntax(221); // Msg221 database name
2001-05-23 15:26:42 +02:00
}
2003-09-11 04:17:05 +02:00
}
2004-05-16 03:42:11 +02:00
ALLQ_push(value, &stack);
2001-05-23 15:26:42 +02:00
count++;
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_COMMA))
2001-05-23 15:26:42 +02:00
break;
}
command_end();
2004-03-07 08:58:55 +01:00
qli_syntax* node = make_list(stack);
2001-05-23 15:26:42 +02:00
node->syn_count = count;
node->syn_type = nod_show;
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_sort(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ s o r t
*
**************************************
*
* Functional description
* Parse a sort list.
*
**************************************/
USHORT direction = 0;
bool sensitive = false;
2004-02-02 12:02:12 +01:00
qli_lls* stack = NULL;
2001-05-23 15:26:42 +02:00
2003-09-10 19:52:12 +02:00
while (true) {
2001-05-23 15:26:42 +02:00
PAR_real();
if (!sql_flag) {
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_ASCENDING)) {
2001-05-23 15:26:42 +02:00
direction = 0;
continue;
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_DESCENDING)) {
2001-05-23 15:26:42 +02:00
direction = 1;
continue;
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_EXACTCASE)) {
sensitive = false;
2001-05-23 15:26:42 +02:00
continue;
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_ANYCASE)) {
sensitive = true;
2001-05-23 15:26:42 +02:00
continue;
}
}
2004-03-07 08:58:55 +01:00
qli_syntax* node;
2001-05-23 15:26:42 +02:00
if (sql_flag && QLI_token->tok_type == tok_number) {
2004-05-16 03:42:11 +02:00
node = syntax_node(nod_position, 1);
2001-05-23 15:26:42 +02:00
node->syn_arg[0] = INT_CAST parse_ordinal();
}
else
node = parse_value(0, 0);
if (sensitive) {
2004-05-16 03:42:11 +02:00
qli_syntax* upcase = syntax_node(nod_upcase, 1);
2001-05-23 15:26:42 +02:00
upcase->syn_arg[0] = node;
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) upcase, &stack);
2001-05-23 15:26:42 +02:00
}
else
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) node, &stack);
2001-05-23 15:26:42 +02:00
if (sql_flag)
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_ASCENDING))
2001-05-23 15:26:42 +02:00
direction = 0;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_DESCENDING))
2001-05-23 15:26:42 +02:00
direction = 1;
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) (IPTR) direction, &stack);
if (!PAR_match(KW_COMMA))
2001-05-23 15:26:42 +02:00
break;
}
return make_list(stack);
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_sql_alter(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ s q l _ a l t e r
*
**************************************
*
* Functional description
* Parse the leading clauses of a SQL ALTER statement.
*
**************************************/
PAR_real_token();
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_TABLE))
ERRQ_syntax(407); // Msg407 TABLE
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_sql_al_table, 2);
2004-02-02 12:02:12 +01:00
qli_rel* relation = parse_qualified_relation();
2004-03-07 08:58:55 +01:00
node->syn_arg[0] = (qli_syntax*) relation;
2001-05-23 15:26:42 +02:00
for (;;) {
2004-02-02 12:02:12 +01:00
qli_fld* field;
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_ADD)) {
2001-05-23 15:26:42 +02:00
field = parse_sql_field();
field->fld_flags |= FLD_add;
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_DROP)) {
field = parse_field(false);
2001-05-23 15:26:42 +02:00
field->fld_flags |= FLD_drop;
}
else
2004-05-16 03:42:11 +02:00
ERRQ_syntax(405); // Msg405 ADD or DROP
2001-05-23 15:26:42 +02:00
2004-02-02 12:02:12 +01:00
field->fld_next = (qli_fld*) node->syn_arg[1];
2004-03-07 08:58:55 +01:00
node->syn_arg[1] = (qli_syntax*) field;
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_COMMA))
2001-05-23 15:26:42 +02:00
break;
}
command_end();
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_sql_create(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ s q l _ c r e a t e
*
**************************************
*
* Functional description
* Parse the leading clauses of a SQL CREATE statement.
*
**************************************/
PAR_real_token();
if (KEYWORD(KW_DATABASE))
return parse_ready(nod_sql_database);
if (KEYWORD(KW_UNIQUE) || KEYWORD(KW_ASCENDING)
|| KEYWORD(KW_DESCENDING) || KEYWORD(KW_INDEX))
{
bool unique = false, descending = false;
2003-09-10 19:52:12 +02:00
while (true) {
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_UNIQUE))
unique = true;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_ASCENDING))
descending = false;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_DESCENDING))
descending = true;
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_INDEX))
2001-05-23 15:26:42 +02:00
return parse_sql_index_create(unique, descending);
else
2004-05-16 03:42:11 +02:00
ERRQ_syntax(389); // Msg389 INDEX
2001-05-23 15:26:42 +02:00
}
}
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_TABLE))
2001-05-23 15:26:42 +02:00
return parse_sql_table_create();
#ifdef NOT_USED_OR_REPLACED
2001-05-23 15:26:42 +02:00
/***
2004-05-16 03:42:11 +02:00
if (PAR_match (KW_VIEW))
2001-05-23 15:26:42 +02:00
return parse_sql_view_create();
***/
#endif
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
ERRQ_syntax(386); // Msg386 object type for CREATE
2003-02-07 10:40:54 +01:00
return NULL;
2001-05-23 15:26:42 +02:00
}
static int parse_sql_dtype( USHORT* length, USHORT* scale, USHORT* precision,
USHORT* sub_type)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ s q l _ d t y p e
*
**************************************
*
* Functional description
* Parse a SQL datatype clause.
*
**************************************/
USHORT dtype = dtype_unknown;
2001-05-23 15:26:42 +02:00
const KWWORDS keyword = QLI_token->tok_keyword;
2001-05-23 15:26:42 +02:00
PAR_token();
*scale = 0;
*length = 1;
*precision = 0;
*sub_type = 0;
2001-05-23 15:26:42 +02:00
switch (keyword) {
case KW_DATE:
*length = 8;
return dtype_timestamp;
case KW_CHAR:
dtype = dtype_text;
break;
case KW_VARCHAR:
dtype = dtype_varying;
break;
case KW_SMALLINT:
*length = sizeof(SSHORT);
return dtype_short;
case KW_INTEGER:
*length = sizeof(SLONG);
return dtype_long;
case KW_BIGINT:
*length = sizeof(SINT64);
return dtype_int64;
2001-05-23 15:26:42 +02:00
case KW_REAL:
case KW_FLOAT:
*length = sizeof(float);
dtype = dtype_real;
break;
case KW_LONG:
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_FLOAT))
ERRQ_syntax(388); // Msg388 "FLOAT"
*length = sizeof(double);
dtype = dtype_double;
break;
2001-05-23 15:26:42 +02:00
case KW_DOUBLE:
if (!PAR_match(KW_PRECISION))
ERRQ_syntax(509); // Msg509 "PRECISION"
2001-05-23 15:26:42 +02:00
*length = sizeof(double);
dtype = dtype_double;
break;
case KW_DECIMAL:
*length = sizeof(SLONG);
dtype = dtype_long;
*sub_type = dsc_num_type_decimal;
break;
case KW_NUMERIC:
*length = sizeof(SLONG);
dtype = dtype_long;
*sub_type = dsc_num_type_numeric;
2001-05-23 15:26:42 +02:00
break;
}
// CVC: SQL doesn't accept arbitrary types with scale specification.
//if (dtype == dtype_long || dtype == dtype_real || dtype == dtype_double) {
if (keyword == KW_DECIMAL || keyword == KW_NUMERIC)
{
if (PAR_match(KW_LEFT_PAREN))
{
const USHORT logLength = parse_ordinal();
if (logLength < 1)
ERRQ_syntax(512); // Msg512 "Field length should be greater than zero"
else if (logLength < 5)
{
*length = sizeof(SSHORT);
dtype = dtype_short;
}
else if (logLength > 18)
ERRQ_syntax(511); // Msg511 "Field length exceeds allowed range"
else if (logLength > 9)
{
*length = sizeof(SINT64);
dtype = dtype_int64;
}
if (PAR_match(KW_COMMA))
{
const bool l = (PAR_match(KW_MINUS)) ? true : false;
*scale = parse_ordinal();
2006-09-01 12:51:57 +02:00
if (*scale > logLength)
ERRQ_syntax(510); // Msg510 "Field scale exceeds allowed range"
if (l || *scale > 0) // We need to have it negative in system tables.
*scale = -(*scale);
}
*precision = logLength;
2001-05-23 15:26:42 +02:00
parse_matching_paren();
}
}
else if (dtype == dtype_text || dtype == dtype_varying)
{
if (PAR_match(KW_LEFT_PAREN))
{
USHORT l = parse_ordinal();
if (l > MAX_COLUMN_SIZE)
ERRQ_syntax(511); // Msg511 "Field length exceeds allowed range"
2001-05-23 15:26:42 +02:00
if (dtype == dtype_varying)
{
if (l > MAX_COLUMN_SIZE - sizeof(SSHORT))
ERRQ_syntax(511); // Msg511 "Field length exceeds allowed range"
2001-05-23 15:26:42 +02:00
l += sizeof(SSHORT);
}
2001-05-23 15:26:42 +02:00
*length = l;
parse_matching_paren();
}
}
return dtype;
}
2004-02-02 12:02:12 +01:00
static qli_fld* parse_sql_field(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ s q l _ f i e l d
*
**************************************
*
* Functional description
* Parse a field description.
*
**************************************/
PAR_real();
USHORT dtype, length, scale, precision, sub_type;
dtype = length = scale = precision = sub_type = 0;
2004-02-02 12:02:12 +01:00
qli_symbol* name = parse_symbol();
2001-05-23 15:26:42 +02:00
PAR_real();
switch (QLI_token->tok_keyword) {
case KW_DOUBLE:
2004-05-16 03:42:11 +02:00
PAR_match(KW_PRECISION);
2001-05-23 15:26:42 +02:00
case KW_NUMERIC:
case KW_REAL:
case KW_DATE:
case KW_CHAR:
case KW_VARCHAR:
case KW_SMALLINT:
case KW_INTEGER:
case KW_FLOAT:
case KW_LONG:
case KW_DECIMAL:
case KW_BIGINT:
dtype = parse_sql_dtype(&length, &scale, &precision, &sub_type);
2001-05-23 15:26:42 +02:00
break;
default:
2004-05-16 03:42:11 +02:00
ERRQ_syntax(179); // Msg179 field definition clause
2001-05-23 15:26:42 +02:00
break;
}
2004-02-02 12:02:12 +01:00
qli_fld* field = (qli_fld*) ALLOCDV(type_fld, length);
2001-05-23 15:26:42 +02:00
field->fld_name = name;
field->fld_dtype = dtype;
field->fld_scale = scale;
field->fld_length = length;
field->fld_precision = precision;
field->fld_sub_type = sub_type;
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_NOT))
if (PAR_match(KW_NULL)) {
2001-05-23 15:26:42 +02:00
field->fld_flags |= FLD_not_null;
}
else {
2004-05-16 03:42:11 +02:00
ERRQ_syntax(393); // Msg393 NULL
2001-05-23 15:26:42 +02:00
}
return field;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_sql_grant_revoke( USHORT type)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ s q l _ g r a n t _ r e v o k e
*
**************************************
*
* Functional description
* Parse a SQL GRANT/REVOKE statement.
*
**************************************/
PAR_real_token();
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node((NOD_T) type, s_grant_count);
2004-02-02 12:02:12 +01:00
qli_lls* stack = NULL;
USHORT privileges = 0;
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_ALL)) {
PAR_match(KW_PRIVILEGES);
2001-05-23 15:26:42 +02:00
privileges |= PRV_all;
}
else
2003-09-10 19:52:12 +02:00
while (true) {
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_SELECT)) {
2001-05-23 15:26:42 +02:00
privileges |= PRV_select;
continue;
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_INSERT)) {
2001-05-23 15:26:42 +02:00
privileges |= PRV_insert;
continue;
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_DELETE)) {
2001-05-23 15:26:42 +02:00
privileges |= PRV_delete;
continue;
}
2004-05-16 03:42:11 +02:00
else if (PAR_match(KW_UPDATE)) {
2001-05-23 15:26:42 +02:00
privileges |= PRV_update;
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_COMMA))
2001-05-23 15:26:42 +02:00
continue;
if (KEYWORD(KW_ON))
break;
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_LEFT_PAREN))
ERRQ_syntax(187); // Msg187 left parenthesis
2001-05-23 15:26:42 +02:00
do {
if (KEYWORD(KW_SELECT) || KEYWORD(KW_INSERT)
|| KEYWORD(KW_DELETE) || KEYWORD(KW_UPDATE))
2004-05-29 07:03:08 +02:00
{
2001-05-23 15:26:42 +02:00
break;
2004-05-29 07:03:08 +02:00
}
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) parse_name(), &stack);
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
} while (PAR_match(KW_COMMA));
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_RIGHT_PAREN))
ERRQ_syntax(191); // Msg191 right parenthesis
2001-05-23 15:26:42 +02:00
continue;
}
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_COMMA))
2001-05-23 15:26:42 +02:00
break;
}
node->syn_arg[s_grant_fields] = make_list(stack);
PAR_real();
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_ON))
ERRQ_syntax(397); // Msg397 ON
2001-05-23 15:26:42 +02:00
PAR_real();
2004-03-07 08:58:55 +01:00
if (!(node->syn_arg[s_grant_relation] = (qli_syntax*) parse_qualified_relation()))
2004-05-16 03:42:11 +02:00
ERRQ_syntax(170); // Msg170 relation name
2001-05-23 15:26:42 +02:00
if (type == (USHORT) nod_sql_grant) {
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_TO))
ERRQ_syntax(404); // Msg404 TO
2001-05-23 15:26:42 +02:00
}
else {
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_FROM))
ERRQ_syntax(403); // Msg403 FROM
2001-05-23 15:26:42 +02:00
}
stack = NULL;
2003-09-10 19:52:12 +02:00
while (true) {
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) parse_name(), &stack);
if (!PAR_match(KW_COMMA))
2001-05-23 15:26:42 +02:00
break;
}
node->syn_arg[s_grant_users] = make_list(stack);
if (type == (USHORT) nod_sql_grant)
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_WITH)) {
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_GRANT))
ERRQ_syntax(401); // Msg401 GRANT
PAR_match(KW_OPTION);
2001-05-23 15:26:42 +02:00
privileges |= PRV_grant_option;
}
node->syn_arg[s_grant_privileges] = INT_CAST privileges;
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_sql_index_create(const bool unique, const bool descending)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ s q l _ i n d e x _ c r e a t e
*
**************************************
*
* Functional description
* Parse the SQL CREATE INDEX statement.
*
**************************************/
PAR_real();
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_def_index, s_dfi_count);
2001-05-23 15:26:42 +02:00
if (unique)
node->syn_flags |= s_dfi_flag_unique;
if (descending)
node->syn_flags |= s_dfi_flag_descending;
2004-03-07 08:58:55 +01:00
node->syn_arg[s_dfi_name] = (qli_syntax*) parse_symbol();
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_ON))
ERRQ_syntax(397); // Msg397 ON
2001-05-23 15:26:42 +02:00
2004-03-07 08:58:55 +01:00
if (!(node->syn_arg[s_dfi_relation] = (qli_syntax*) parse_qualified_relation()))
2004-05-16 03:42:11 +02:00
ERRQ_syntax(170); // Msg170 relation name
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_LEFT_PAREN))
ERRQ_syntax(185); // Msg185 left parenthesis
2001-05-23 15:26:42 +02:00
2004-02-02 12:02:12 +01:00
qli_lls* stack = NULL;
2001-05-23 15:26:42 +02:00
for (;;) {
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) parse_name(), &stack);
if (PAR_match(KW_RIGHT_PAREN))
2001-05-23 15:26:42 +02:00
break;
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_COMMA))
ERRQ_syntax(171); // Msg171 comma between field definitions
2001-05-23 15:26:42 +02:00
}
node->syn_arg[s_dfi_fields] = make_list(stack);
command_end();
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_sql_joined_relation( qli_syntax* prior_context)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ s q l _ j o i n e d _ r e l a t i o n
*
**************************************
*
* Functional description
* Parse a join relation clause.
*
**************************************/
2004-03-07 08:58:55 +01:00
qli_syntax* left;
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_LEFT_PAREN)) {
2001-05-23 15:26:42 +02:00
left = parse_sql_joined_relation(0);
parse_matching_paren();
}
else if (!(left = parse_sql_relation()))
return NULL;
return parse_sql_join_clause(left);
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_sql_join_clause( qli_syntax* left)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ s q l _ j o i n _ c l a u s e
*
**************************************
*
* Functional description
* Parse a join relation clause.
*
**************************************/
NOD_T join_type = parse_join_type();
2001-05-23 15:26:42 +02:00
if (join_type == (NOD_T) 0)
return left;
2004-03-07 08:58:55 +01:00
qli_syntax* right = parse_sql_joined_relation(left);
if (!right)
2004-05-16 03:42:11 +02:00
ERRQ_syntax(490); // Msg490 joined relation clause
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_ON))
ERRQ_syntax(492); // Msg492 ON
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_rse, (int) s_rse_count + 2 * 2);
2001-05-23 15:26:42 +02:00
node->syn_count = 2;
node->syn_arg[s_rse_count] = left;
node->syn_arg[s_rse_count + 2] = right;
2004-03-07 08:58:55 +01:00
node->syn_arg[s_rse_join_type] = (qli_syntax*) join_type;
2001-05-23 15:26:42 +02:00
node->syn_arg[s_rse_boolean] = parse_boolean(0);
return parse_sql_join_clause(node);
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_sql_table_create(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ s q l _ t a b l e _ c r e a t e
*
**************************************
*
* Functional description
* Parse the SQL CREATE TABLE statement.
*
**************************************/
PAR_real();
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_sql_cr_table, 1);
2004-02-02 12:02:12 +01:00
qli_rel* relation = (qli_rel*) ALLOCD(type_rel);
2004-03-07 08:58:55 +01:00
node->syn_arg[0] = (qli_syntax*) relation;
2001-05-23 15:26:42 +02:00
relation->rel_database = parse_database();
relation->rel_symbol = parse_symbol();
2004-02-02 12:02:12 +01:00
qli_fld** ptr = &relation->rel_fields;
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_LEFT_PAREN))
ERRQ_syntax(185); // Msg185 left parenthesis
2001-05-23 15:26:42 +02:00
PAR_real();
for (;;) {
2004-02-02 12:02:12 +01:00
qli_fld* field = parse_sql_field();
*ptr = field;
2001-05-23 15:26:42 +02:00
ptr = &field->fld_next;
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_RIGHT_PAREN))
2001-05-23 15:26:42 +02:00
break;
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_COMMA))
ERRQ_syntax(171); // Msg171 comma between field definitions
2001-05-23 15:26:42 +02:00
}
command_end();
return node;
}
#ifdef NOT_USED_OR_REPLACED
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_sql_view_create(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ s q l _ v i e w _ c r e a t e
*
**************************************
*
* Functional description
* Parse the SQL CREATE VIEW statement.
*
**************************************/
PAR_real();
sw_sql_view = true;
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_sql_cr_view, s_crv_count);
2004-02-02 12:02:12 +01:00
qli_lls* stack = NULL;
2001-05-23 15:26:42 +02:00
2004-02-02 12:02:12 +01:00
qli_rel* relation = (qli_rel*) ALLOCD(type_rel);
2004-03-07 08:58:55 +01:00
node->syn_arg[s_crv_name] = (qli_syntax*) relation;
2001-05-23 15:26:42 +02:00
relation->rel_database = parse_database();
relation->rel_symbol = parse_symbol();
// if field list is present parse it and create corresponding field blocks
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_LEFT_PAREN)) {
2001-05-23 15:26:42 +02:00
for (;;) {
2004-05-16 03:42:11 +02:00
ALLQ_push(parse_name(), &stack);
if (PAR_match(KW_RIGHT_PAREN))
2001-05-23 15:26:42 +02:00
break;
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_COMMA))
ERRQ_syntax(171); // Msg171 comma between field definitions
2001-05-23 15:26:42 +02:00
}
}
/* node->syn_arg [s_crv_fields] = make_list (stack); */
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_AS))
ERRQ_syntax(394); // Msg394 As
2001-05-23 15:26:42 +02:00
if (!KEYWORD(KW_SELECT))
2004-05-16 03:42:11 +02:00
ERRQ_syntax(395); // Msg395 Select
2001-05-23 15:26:42 +02:00
node->syn_arg[s_crv_rse] = parse_select();
sw_sql_view = false;
2001-05-23 15:26:42 +02:00
return node;
}
#endif
2001-05-23 15:26:42 +02:00
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_sql_relation(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ s q l _ r e l a t i o n
*
**************************************
*
* Functional description
* Parse a SQL relation clause.
*
**************************************/
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_relation, s_rel_count);
2001-05-23 15:26:42 +02:00
2004-03-07 08:58:55 +01:00
if (!(node->syn_arg[s_rel_relation] = (qli_syntax*) parse_qualified_relation()))
2004-05-16 03:42:11 +02:00
ERRQ_syntax(223); // Msg223 relation name
2001-05-23 15:26:42 +02:00
if (!QLI_token->tok_symbol)
2004-03-07 08:58:55 +01:00
node->syn_arg[s_rel_context] = (qli_syntax*) parse_symbol();
2001-05-23 15:26:42 +02:00
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_sql_rse(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ s q l _ r s e
*
**************************************
*
* Functional description
* Parse the trailing clauses of a SQL SELECT statement.
*
**************************************/
2004-02-02 12:02:12 +01:00
qli_lls* stack = NULL;
USHORT count = 0;
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_FROM))
ERRQ_syntax(224); // Msg224 FROM clause
2001-05-23 15:26:42 +02:00
// Parse FROM list of relations
2001-05-23 15:26:42 +02:00
2003-09-10 19:52:12 +02:00
while (true) {
2001-05-23 15:26:42 +02:00
count++;
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) parse_sql_joined_relation(0), &stack);
if (!PAR_match(KW_COMMA))
2001-05-23 15:26:42 +02:00
break;
}
/* Build a syntax node. Since SQL doesn't support OVER, only every
other slot will be used in the RSE. */
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_rse, (int) s_rse_count + 2 * count);
2001-05-23 15:26:42 +02:00
node->syn_count = count;
2004-03-07 08:58:55 +01:00
qli_syntax** ptr = &node->syn_arg[(int) s_rse_count + 2 * count];
2001-05-23 15:26:42 +02:00
while (stack) {
--ptr;
2004-05-16 03:42:11 +02:00
*--ptr = (qli_syntax*) ALLQ_pop(&stack);
2001-05-23 15:26:42 +02:00
}
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_WITH))
2001-05-23 15:26:42 +02:00
node->syn_arg[s_rse_boolean] = parse_boolean(0);
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_GROUP)) {
2001-05-23 15:26:42 +02:00
if (sw_sql_view)
2004-05-16 03:42:11 +02:00
ERRQ_syntax(391); // Msg391 No group by in view def
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
PAR_match(KW_BY);
2001-05-23 15:26:42 +02:00
stack = NULL;
2003-09-10 19:52:12 +02:00
while (true) {
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) parse_udf_or_field(), &stack);
if (!PAR_match(KW_COMMA))
2001-05-23 15:26:42 +02:00
break;
}
node->syn_arg[s_rse_group_by] = make_list(stack);
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_HAVING))
2001-05-23 15:26:42 +02:00
node->syn_arg[s_rse_having] = parse_boolean(0);
}
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_sql_singleton_select(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ s q l _ s i n g l e t o n _ s e l e c t
*
**************************************
*
* Functional description
* Finish parsing an SQL singleton select and
* turn it into a FIRST ... FROM --- not exactly
* kosher, but a start.
*
**************************************/
2004-03-07 08:58:55 +01:00
qli_syntax* value = parse_primitive_value(0, 0);
2001-05-23 15:26:42 +02:00
PAR_real();
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_from, s_stt_count);
2001-05-23 15:26:42 +02:00
node->syn_arg[s_stt_value] = value;
node->syn_arg[s_stt_rse] = parse_sql_rse();
--sql_flag; // The increment was done in parse_sql_subquery, the only caller.
2001-05-23 15:26:42 +02:00
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_sql_subquery(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ s q l _ s u b q u e r y
*
**************************************
*
* Functional description
* Parse an sql subquery that should
* return a single value.
*
**************************************/
if (sw_sql_view)
2004-05-16 03:42:11 +02:00
ERRQ_syntax(392); // Msg392 No aggregates in view def
2001-05-23 15:26:42 +02:00
PAR_token();
KWWORDS keyword = next_keyword();
2001-05-23 15:26:42 +02:00
++sql_flag;
const nod_types* ntypes;
const nod_types* const endtypes = statisticals + FB_NELEM(statisticals);
for (ntypes = statisticals; ntypes < endtypes; ntypes++)
if (ntypes->nod_t_keyword == KW_none)
2001-05-23 15:26:42 +02:00
return parse_sql_singleton_select();
else if (ntypes->nod_t_keyword == keyword)
2001-05-23 15:26:42 +02:00
break;
fb_assert(ntypes < endtypes);
if (ntypes >= endtypes)
return NULL;
2001-05-23 15:26:42 +02:00
PAR_token();
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(ntypes->nod_t_node, s_stt_count);
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
PAR_match(KW_LEFT_PAREN);
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
if (node->syn_type != nod_count || !PAR_match(KW_ASTERISK)) {
if (PAR_match(KW_DISTINCT))
2001-05-23 15:26:42 +02:00
node->syn_arg[s_prt_distinct] = INT_CAST TRUE;
node->syn_arg[s_stt_value] = parse_value(0, 0);
}
parse_matching_paren();
node->syn_arg[s_stt_rse] = parse_sql_rse();
--sql_flag;
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_statement(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ s t a t e m e n t
*
**************************************
*
* Functional description
* Parse a statement. (Set statement switch
* to true here as well as in PARQ_parse to
* avoid confusion with linked statements
2001-05-23 15:26:42 +02:00
* e.g. THEN conjuncts )
*
**************************************/
2004-03-07 08:58:55 +01:00
qli_syntax* node;
2001-05-23 15:26:42 +02:00
PAR_real();
sw_statement = true;
2001-05-23 15:26:42 +02:00
function_count = 0;
switch (next_keyword()) {
case KW_ABORT:
node = parse_abort();
break;
case KW_ACCEPT:
node = parse_accept();
break;
case KW_COMMIT:
node = parse_transaction(nod_commit_retaining);
break;
case KW_DECLARE:
node = parse_declare();
break;
case KW_DELETE:
2004-05-16 03:42:11 +02:00
PAR_match(KW_DELETE);
2001-05-23 15:26:42 +02:00
node = parse_delete();
break;
case KW_ERASE:
node = parse_erase();
break;
case KW_FOR:
node = parse_for();
break;
case KW_IF:
node = parse_if();
break;
case KW_INSERT:
node = parse_insert();
break;
case KW_LIST:
node = parse_list_fields();
break;
case KW_MODIFY:
node = parse_modify();
break;
case KW_PRINT:
node = parse_print();
break;
case KW_REPEAT:
node = parse_repeat();
break;
case KW_REPORT:
node = parse_report();
break;
case KW_SELECT:
node = parse_select();
break;
case KW_STORE:
node = parse_store();
break;
case KW_UPDATE:
node = parse_update();
break;
case KW_BEGIN:
{
2004-02-02 12:02:12 +01:00
qli_lls* stack = NULL;
PAR_token();
while (true) {
PAR_real();
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_END))
break;
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) parse_statement(), &stack);
PAR_match(KW_SEMI);
}
node = make_list(stack);
2001-05-23 15:26:42 +02:00
}
break;
default:
node = parse_assignment();
}
check_end();
// Check for the "THEN" connective. If found, make a list of statements.
2001-05-23 15:26:42 +02:00
if (QLI_token->tok_type != tok_eol || (QLI_semi && !KEYWORD(KW_SEMI)))
2004-05-16 03:42:11 +02:00
PAR_match(KW_SEMI);
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_THEN))
2001-05-23 15:26:42 +02:00
return node;
2004-02-02 12:02:12 +01:00
qli_lls* stack = NULL;
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) node, &stack);
ALLQ_push((blk*) parse_statement(), &stack);
2001-05-23 15:26:42 +02:00
return make_list(stack);
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_statistical(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ s t a t i s t i c a l
*
**************************************
*
* Functional description
* Parse statistical expression.
*
**************************************/
KWWORDS keyword = next_keyword();
2001-05-23 15:26:42 +02:00
PAR_token();
const nod_types* ntypes;
const nod_types* const endtypes = statisticals + FB_NELEM(statisticals);
for (ntypes = statisticals; ntypes < endtypes; ntypes++)
if (ntypes->nod_t_keyword == keyword)
2001-05-23 15:26:42 +02:00
break;
2003-11-04 00:59:24 +01:00
fb_assert(ntypes < endtypes);
if (ntypes >= endtypes)
return NULL;
// Handle SQL statisticals a little differently
2001-05-23 15:26:42 +02:00
if (sql_flag) {
2004-05-16 03:42:11 +02:00
qli_syntax* anode = syntax_node(ntypes->nod_t_sql_node, s_stt_count);
if (!PAR_match(KW_LEFT_PAREN))
ERRQ_syntax(227); // Msg227 left parenthesis
if (anode->syn_type != nod_agg_count || !PAR_match(KW_ASTERISK)) {
if (PAR_match(KW_DISTINCT))
anode->syn_arg[s_prt_distinct] = INT_CAST TRUE;
anode->syn_arg[s_stt_value] = parse_value(0, 0);
2001-05-23 15:26:42 +02:00
}
parse_matching_paren();
return anode;
2001-05-23 15:26:42 +02:00
}
// Handle GDML statisticals
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(ntypes->nod_t_node, s_stt_count);
2001-05-23 15:26:42 +02:00
if (node->syn_type != nod_count)
node->syn_arg[s_stt_value] = parse_value(0, 0);
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_OF)) {
2001-05-23 15:26:42 +02:00
if (sw_report) {
if (function_count > 0)
IBERROR(487); // Msg487 Invalid argument for UDF
node->syn_type = ntypes->nod_t_rpt_node;
2001-05-23 15:26:42 +02:00
return node;
}
PAR_real();
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_OF))
ERRQ_syntax(228); // Msg 228 OF
2001-05-23 15:26:42 +02:00
}
node->syn_arg[s_stt_rse] = parse_rse();
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_store(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ s t o r e
*
**************************************
*
* Functional description
* Parse a STORE statement.
*
**************************************/
PAR_token();
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_store, s_sto_count);
2001-05-23 15:26:42 +02:00
node->syn_arg[s_sto_relation] = parse_relation();
if (test_end())
return node;
2004-05-16 03:42:11 +02:00
PAR_match(KW_USING);
2001-05-23 15:26:42 +02:00
2003-09-11 04:17:05 +02:00
node->syn_arg[s_sto_statement] = parse_statement();
2001-05-23 15:26:42 +02:00
return node;
}
static TEXT *parse_string(void)
{
/**************************************
*
* p a r s e _ s t r i n g
*
**************************************
*
* Functional description
* Save the current token as a string, advance to the next
* token, and return a pointer to the string.
*
**************************************/
TEXT* string = make_string(QLI_token->tok_string, QLI_token->tok_length);
2001-05-23 15:26:42 +02:00
PAR_token();
return string;
}
2004-02-02 12:02:12 +01:00
static qli_symbol* parse_symbol(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ s y m b o l
*
**************************************
*
* Functional description
* Parse the next token as a context symbol.
*
**************************************/
USHORT l = QLI_token->tok_length;
2004-02-02 12:02:12 +01:00
qli_symbol* context = (qli_symbol*) ALLOCDV(type_sym, l);
2001-05-23 15:26:42 +02:00
context->sym_type = SYM_context;
context->sym_length = l;
const TEXT* q = QLI_token->tok_string;
context->sym_string = context->sym_name;
TEXT* p = context->sym_name;
2001-05-23 15:26:42 +02:00
if (l)
do {
const TEXT c = *q++;
2001-05-23 15:26:42 +02:00
*p++ = UPPER(c);
} while (--l);
PAR_token();
return context;
}
2002-11-06 15:50:09 +01:00
static void parse_terminating_parens( USHORT * paren_count, USHORT * local_count)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ t e r m i n a t i n g _ p a r e n s
*
**************************************
*
* Functional description
* Check for balancing parenthesis. If missing, barf.
*
**************************************/
if (*paren_count && paren_count == local_count)
do {
2001-05-23 15:26:42 +02:00
parse_matching_paren();
} while (--(*paren_count));
2001-05-23 15:26:42 +02:00
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_transaction( NOD_T node_type)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ t r a n s a c t i o n
*
**************************************
*
* Functional description
* Parse the FINISH, COMMIT, ROLLBACK,
* and PREPARE commands and the COMMIT statement.
*
**************************************/
2004-02-02 12:02:12 +01:00
qli_lls* stack = NULL;
2001-05-23 15:26:42 +02:00
PAR_token();
if (!KEYWORD(KW_SEMI))
2003-09-10 19:52:12 +02:00
while (true) {
2004-02-02 12:02:12 +01:00
qli_symbol* symbol;
2001-05-23 15:26:42 +02:00
for (symbol = QLI_token->tok_symbol; symbol;
symbol = symbol->sym_homonym)
{
if (symbol->sym_type == SYM_database)
break;
}
2001-05-23 15:26:42 +02:00
if (!symbol)
2004-05-16 03:42:11 +02:00
ERRQ_syntax(229); // Msg229 database name
ALLQ_push(symbol->sym_object, &stack);
2001-05-23 15:26:42 +02:00
PAR_token();
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_COMMA))
2001-05-23 15:26:42 +02:00
break;
}
command_end();
2004-03-07 08:58:55 +01:00
qli_syntax* node = make_list(stack);
2001-05-23 15:26:42 +02:00
node->syn_type = node_type;
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_udf_or_field(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ u d f _ o r _ f i e l d
*
**************************************
*
* Functional description
* Parse a function or field reference.
*
**************************************/
2004-05-29 07:03:08 +02:00
const qli_symbol* symbol = QLI_token->tok_symbol;
2001-05-23 15:26:42 +02:00
if (symbol && symbol->sym_type == SYM_function)
2001-05-23 15:26:42 +02:00
return parse_function();
return parse_field_name(0);
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_update(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ u p d a t e
*
**************************************
*
* Functional description
* Parse a SQL UPDATE statement.
*
**************************************/
++sql_flag;
PAR_token();
2004-05-16 03:42:11 +02:00
qli_syntax* node = syntax_node(nod_modify, s_mod_count);
qli_syntax* rse = syntax_node(nod_rse, (int) s_rse_count + 2);
node->syn_arg[s_mod_rse] = rse;
2001-05-23 15:26:42 +02:00
rse->syn_count = 1;
rse->syn_arg[s_rse_count] = parse_sql_relation();
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_SET))
ERRQ_syntax(230); // Msg230 SET
2001-05-23 15:26:42 +02:00
// Pick up assignments
2001-05-23 15:26:42 +02:00
2004-02-02 12:02:12 +01:00
qli_lls* stack = NULL;
2001-05-23 15:26:42 +02:00
2003-09-10 19:52:12 +02:00
while (true) {
2004-05-16 03:42:11 +02:00
ALLQ_push((blk*) parse_assignment(), &stack);
if (!PAR_match(KW_COMMA))
2001-05-23 15:26:42 +02:00
break;
}
// Pick up boolean, if present
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
if (PAR_match(KW_WITH))
2001-05-23 15:26:42 +02:00
rse->syn_arg[s_rse_boolean] = parse_boolean(0);
node->syn_arg[s_mod_statement] = make_list(stack);
--sql_flag;
return node;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* parse_value( USHORT* paren_count, bool* bool_flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p a r s e _ v a l u e
*
**************************************
*
* Functional description
* Parse a general value expression. In practice, this means parse the
* lowest precedence operator CONCATENATE.
2001-05-23 15:26:42 +02:00
*
**************************************/
USHORT local_count;
2001-05-23 15:26:42 +02:00
if (!paren_count) {
local_count = 0;
paren_count = &local_count;
}
bool local_flag;
2001-05-23 15:26:42 +02:00
if (!bool_flag) {
local_flag = false;
2001-05-23 15:26:42 +02:00
bool_flag = &local_flag;
}
2004-03-07 08:58:55 +01:00
qli_syntax* node = parse_add(paren_count, bool_flag);
2001-05-23 15:26:42 +02:00
2003-09-10 19:52:12 +02:00
while (true) {
2004-05-16 03:42:11 +02:00
if (!PAR_match(KW_BAR)) {
2001-05-23 15:26:42 +02:00
parse_terminating_parens(paren_count, &local_count);
return node;
}
2004-03-07 08:58:55 +01:00
qli_syntax* arg = node;
2004-05-16 03:42:11 +02:00
node = syntax_node(nod_concatenate, 2);
2001-05-23 15:26:42 +02:00
node->syn_arg[0] = arg;
node->syn_arg[1] = parse_add(paren_count, bool_flag);
}
}
2004-03-07 08:58:55 +01:00
static bool potential_rse(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p o t e n t i a l _ r s e
*
**************************************
*
* Functional description
* Test to see if the current token is likely (sic!) to be part of
* a record selection expression.
*
**************************************/
2004-05-29 07:03:08 +02:00
for (const qli_symbol* symbol = QLI_token->tok_symbol; symbol;
symbol = symbol->sym_homonym)
{
2001-05-23 15:26:42 +02:00
if ((symbol->sym_type == SYM_keyword &&
symbol->sym_keyword == (int) KW_FIRST) ||
symbol->sym_type == SYM_relation ||
symbol->sym_type == SYM_database)
{
2004-03-07 08:58:55 +01:00
return true;
}
}
2001-05-23 15:26:42 +02:00
2004-03-07 08:58:55 +01:00
return false;
2001-05-23 15:26:42 +02:00
}
2004-02-02 12:02:12 +01:00
static qli_rel* resolve_relation( qli_symbol* db_symbol, qli_symbol* relation_symbol)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* r e s o l v e _ r e l a t i o n
*
**************************************
*
* Functional description
* Given symbols for a database and a relation (either may be null),
* resolve the relation. If the relation can't be resolved, return
* NULL (don't error!).
*
**************************************/
2004-02-02 12:02:12 +01:00
qli_rel* relation;
qli_symbol* temp;
2001-05-23 15:26:42 +02:00
// If we don't recognize the relation, punt.
2001-05-23 15:26:42 +02:00
if (!relation_symbol)
return NULL;
/* If a database symbol is present, resolve the relation against the
the given database. */
if (db_symbol) { /* && db_symbol->sym_type == SYM_database ? */
for (; db_symbol; db_symbol = db_symbol->sym_homonym)
for (temp = relation_symbol; temp; temp = temp->sym_homonym)
if (temp->sym_type == SYM_relation)
{
2004-02-02 12:02:12 +01:00
relation = (qli_rel*) temp->sym_object;
2001-05-23 15:26:42 +02:00
if (relation->rel_database == (DBB) db_symbol->sym_object)
return relation;
}
return NULL;
}
// No database qualifier, so search all databases.
2001-05-23 15:26:42 +02:00
for (DBB dbb = QLI_databases; dbb; dbb = dbb->dbb_next)
2001-05-23 15:26:42 +02:00
for (temp = relation_symbol; temp; temp = temp->sym_homonym)
if (temp->sym_type == SYM_relation)
{
2004-02-02 12:02:12 +01:00
relation = (qli_rel*) temp->sym_object;
2001-05-23 15:26:42 +02:00
if (relation->rel_database == dbb)
return relation;
}
return NULL;
}
2004-03-07 08:58:55 +01:00
static qli_syntax* syntax_node( NOD_T type, USHORT count)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s y n t a x _ n o d e
*
**************************************
*
* Functional description
* Allocate and initialize a syntax node of given type.
*
**************************************/
2004-03-07 08:58:55 +01:00
qli_syntax* node = (qli_syntax*) ALLOCDV(type_syn, count);
2001-05-23 15:26:42 +02:00
node->syn_type = type;
node->syn_count = count;
return node;
}
2004-03-07 08:58:55 +01:00
static bool test_end(void)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* t e s t _ e n d
*
**************************************
*
* Functional description
* Test for end of a statement. In specific, test for one of
* THEN, ELSE, ON, or a semi-colon.
*
**************************************/
if (KEYWORD(KW_THEN) ||
KEYWORD(KW_ON) || KEYWORD(KW_ELSE) || KEYWORD(KW_SEMI))
{
2004-03-07 08:58:55 +01:00
return true;
}
2001-05-23 15:26:42 +02:00
2004-03-07 08:58:55 +01:00
return false;
2001-05-23 15:26:42 +02:00
}