Skip to content

Commit d7154fd

Browse files
authored
Merge pull request #805 from jiaoshuntian/call_func
Call func step1,add "VARIABLE" and "PRINT" command
2 parents 212910c + 995e13c commit d7154fd

File tree

14 files changed

+3247
-14
lines changed

14 files changed

+3247
-14
lines changed

src/bin/psql/Makefile

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,16 @@ OBJS = \
3535
input.o \
3636
large_obj.o \
3737
mainloop.o \
38+
ora_prompt.o \
3839
ora_psqlscanslash.o \
3940
prompt.o \
40-
ora_prompt.o \
41+
psqlplusparse.o \
4142
psqlscanslash.o \
4243
sql_help.o \
4344
startup.o \
4445
stringutils.o \
4546
tab-complete.o \
47+
psqlplusscan.o \
4648
variables.o
4749

4850

@@ -51,8 +53,18 @@ all: psql
5153
psql: $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils
5254
$(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
5355

56+
# See notes in src/backend/parser/Makefile about the following two rules
57+
psqlplusparse.h: psqlplusparse.c
58+
touch $@
59+
psqlplusparse.c: BISONFLAGS += -d
60+
# Force these dependencies to be known even without dependency info built:
61+
psqlplusparse.o psqlplusscan.o: psqlplusparse.h
62+
5463
help.o: sql_help.h
5564

65+
# ReqID:SRS-CMD-PSQL
66+
psqlplusparse.o: psqlplusscan.c
67+
5668
# See notes in src/backend/parser/Makefile about the following two rules
5769
sql_help.c: sql_help.h
5870
touch $@
@@ -82,6 +94,8 @@ clean distclean:
8294
rm -f psql$(X) $(OBJS) lex.backup ora_psqlscanslash.c
8395
rm -rf tmp_check
8496
rm -f ora_psqlscanslash.c sql_help.h sql_help.c psqlscanslash.c
97+
rm -f psqlplusscan.c psqlplusparse.c
98+
rm -f psqlplusparse.h
8599

86100
check:
87101
$(prove_check)

src/bin/psql/mainloop.c

Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@
1414
#include "mainloop.h"
1515
#include "mb/pg_wchar.h"
1616
#include "prompt.h"
17+
#include "psqlplus.h"
1718
#include "settings.h"
19+
#include "stringutils.h"
20+
#include "variables.h"
1821
#include "oracle_fe_utils/ora_string_utils.h"
1922
#include "oracle_fe_utils/ora_psqlscan.h"
2023
#include "fe_utils/psqlscan_int.h"
@@ -428,6 +431,251 @@ MainLoop(FILE *source)
428431
ora_psql_scan_setup(ora_scan_state, line, strlen(line),
429432
pset.encoding, standard_strings());
430433
}
434+
/*
435+
* At present, compatible-oracle client commands are all single-line
436+
* commands, so we only scan the input of stmt_lineno = 1, which can
437+
* avoid the performance loss caused by the parser invoked by multi-line
438+
* commands.
439+
*
440+
* Note:
441+
* Oracle client command also extends over multiple lines, but
442+
* must using the SQL*Plus command continuation character(eg: -),
443+
* the ontinuation character we haven't implemented it yet, so for
444+
* the time being we're still assuming that these client commands
445+
* are all one-liners.
446+
*/
447+
if (db_mode == DB_ORACLE && pset.stmt_lineno == 1)
448+
{
449+
PsqlScanState pstate;
450+
yyscan_t yyscanner;
451+
char *psqlplus_line = pg_strdup(line);;
452+
453+
pstate = ora_psql_scan_create(&psqlplus_callbacks);
454+
ora_psql_scan_setup(pstate, psqlplus_line,
455+
strlen(psqlplus_line),
456+
pset.encoding,
457+
standard_strings());
458+
459+
yyscanner = psqlplus_scanner_init(pstate);
460+
if (psqlplus_yyparse(yyscanner) == 0)
461+
{
462+
/* Parser success, i.e. this is a ora client command */
463+
psqlplus_cmd *psqlpluscmd = pstate->psqlpluscmd;
464+
465+
switch(psqlpluscmd->cmd_type)
466+
{
467+
case PSQLPLUS_CMD_VARIABLE:
468+
{
469+
psqlplus_cmd_var *bind_var = (psqlplus_cmd_var *) pstate->psqlpluscmd;
470+
471+
if (bind_var->list_bind_var == true)
472+
{
473+
if (bind_var->var_name)
474+
ListBindVariables(pset.vars, bind_var->var_name);
475+
else
476+
ListBindVariables(pset.vars, NULL);
477+
}
478+
else if (bind_var->miss_termination_quote)
479+
{
480+
/*
481+
* init_value[0] indicates whether this is a single quote
482+
* or a double quote that is missing a terminating quote.
483+
*/
484+
char quote = bind_var->init_value[0];
485+
char *str_double_quote = pg_malloc0(strlen(bind_var->init_value) * 2); /* enough */
486+
char *ptr = str_double_quote;
487+
int i;
488+
489+
/* skip first char */
490+
*ptr++ = bind_var->init_value[0];
491+
i = 1;
492+
493+
while (bind_var->init_value[i] != '\0')
494+
{
495+
/* double write quote if needed */
496+
if (bind_var->init_value[i] == quote)
497+
*ptr++ = bind_var->init_value[i];
498+
499+
/* copy the character */
500+
*ptr++ = bind_var->init_value[i];
501+
i++;
502+
}
503+
504+
*ptr = '\0'; /* Paranoid */
505+
506+
/* report an error directly */
507+
pg_log_error("string \"%s\" missing terminating quote (%c).",
508+
str_double_quote ,
509+
quote);
510+
pg_free(str_double_quote);
511+
}
512+
else if (bind_var->assign_bind_var)
513+
{
514+
AssignBindVariable(pset.vars,
515+
bind_var->var_name,
516+
bind_var->init_value);
517+
}
518+
else
519+
{
520+
Assert(bind_var->vartype);
521+
SetBindVariable(pset.vars,
522+
bind_var->var_name,
523+
bind_var->vartype->oid,
524+
bind_var->vartype->typmod,
525+
bind_var->init_value,
526+
bind_var->initial_nonnull_value);
527+
}
528+
}
529+
break;
530+
case PSQLPLUS_CMD_PRINT:
531+
{
532+
psqlplus_cmd_print *pb = (psqlplus_cmd_print *) pstate->psqlpluscmd;
533+
PrintBindVariables(pset.vars, pb->print_items);
534+
}
535+
break;
536+
default:
537+
pg_log_error("Invalid PSQL*PLUS client command.");
538+
break;
539+
}
540+
541+
/* save client command in history */
542+
if (pset.cur_cmd_interactive)
543+
{
544+
pg_append_history(psqlplus_line, history_buf);
545+
pg_send_history(history_buf);
546+
}
547+
548+
/* reset */
549+
pset.stmt_lineno = 1;
550+
resetPQExpBuffer(query_buf);
551+
psql_scan_finish(scan_state);
552+
ora_psql_scan_finish(ora_scan_state);
553+
free(psqlplus_line);
554+
free(line);
555+
psqlplus_scanner_finish(yyscanner);
556+
ora_psql_scan_destroy(pstate);
557+
continue;
558+
}
559+
560+
/* Syntax parsing failed, but we know it's a client command */
561+
if (pstate->is_sqlplus_cmd)
562+
{
563+
char *token;
564+
const char *whitespace = " \t\n\r";
565+
566+
token = strtokx(pstate->scanline, whitespace, NULL, NULL,
567+
0, false, false, pset.encoding);
568+
569+
if (token && pg_strcasecmp(token, "variable") == 0)
570+
{
571+
token = strtokx(NULL, whitespace, NULL, NULL,
572+
0, false, false, pset.encoding);
573+
574+
/*
575+
* keep in sync with 'truncate_char' in psqlplusparse.y
576+
*/
577+
if (token)
578+
token[strcspn(token, ",()")] = '\0';
579+
580+
/*
581+
* Theoretically, this token is the name of a VARIABLE variable.
582+
* Check whether the reason for the parsing failure is that the
583+
* name is illegal.
584+
*/
585+
if (token && !ValidBindVariableName(token))
586+
pg_log_error("Illegal variable name \"%s\"", token);
587+
else
588+
pg_log_error("Usage: VAR[IABLE] [ <variable> [ NUMBER | CHAR | CHAR (n [CHAR|BYTE]) |\n"
589+
"\t\t\t VARCHAR2 (n [CHAR|BYTE]) | NCHAR | NCHAR (n) |\n"
590+
"\t\t\t NVARCHAR2 (n) | BINARY_FLOAT | BINARY_DOUBLE ] ]");
591+
}
592+
else if (token && pg_strcasecmp(token, "print") == 0)
593+
{
594+
print_list *pl = pg_malloc0(sizeof(print_list));
595+
596+
pl->items = NULL;
597+
pl->length = 0;
598+
599+
token = strtokx(NULL, whitespace, NULL, NULL,
600+
0, false, false, pset.encoding);
601+
while (token)
602+
{
603+
print_item *item;
604+
605+
pl->length++;
606+
607+
if (pl->length == 1)
608+
pl->items = (print_item **) pg_malloc0(sizeof(print_item *) * 1);
609+
else
610+
pl->items = (print_item **) pg_realloc(pl->items, sizeof(print_item *) * pl->length);
611+
612+
/* Strips the leading and trailing quote characters of double quotes */
613+
if (token[0] == '"' && token[strlen(token) - 1] == '"')
614+
{
615+
token[strlen(token) - 1] = '\0';
616+
token++;
617+
}
618+
619+
item = pg_malloc0(sizeof(print_item));
620+
item->bv_name = pg_strdup(token);
621+
622+
if (ValidBindVariableName(item->bv_name))
623+
item->valid = true;
624+
else
625+
item->valid = false;
626+
pl->items[pl->length - 1] = item;
627+
token = strtokx(NULL, whitespace, NULL, NULL,
628+
0, false, false, pset.encoding);
629+
}
630+
631+
if (pl->length == 0)
632+
PrintBindVariables(pset.vars, NULL);
633+
else
634+
PrintBindVariables(pset.vars, pl);
635+
636+
while (pl->length > 0)
637+
{
638+
pl->length--;
639+
if (pl->items &&
640+
pl->items[pl->length] &&
641+
pl->items[pl->length]->bv_name)
642+
{
643+
pg_free(pl->items[pl->length]->bv_name);
644+
pg_free(pl->items[pl->length]);
645+
}
646+
647+
if (pl->length == 0)
648+
{
649+
pg_free(pl->items);
650+
pg_free(pl);
651+
}
652+
}
653+
}
654+
655+
/* save client command in history */
656+
if (pset.cur_cmd_interactive)
657+
{
658+
pg_append_history(psqlplus_line, history_buf);
659+
pg_send_history(history_buf);
660+
}
661+
662+
/* reset */
663+
pset.stmt_lineno = 1;
664+
resetPQExpBuffer(query_buf);
665+
psql_scan_finish(scan_state);
666+
ora_psql_scan_finish(ora_scan_state);
667+
free(psqlplus_line);
668+
free(line);
669+
psqlplus_scanner_finish(yyscanner);
670+
ora_psql_scan_destroy(pstate);
671+
continue;
672+
}
673+
674+
/* Not a compatible-oracle client command */
675+
psqlplus_scanner_finish(yyscanner);
676+
ora_psql_scan_destroy(pstate);
677+
free(psqlplus_line);
678+
}
431679

432680
success = true;
433681
line_saved_in_history = false;

src/bin/psql/meson.build

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,19 @@ ora_psqlscanslash = custom_target('ora_psqlscanslash',
3232
generated_sources += ora_psqlscanslash
3333
psql_sources += ora_psqlscanslash
3434

35+
psqlplusscan = custom_target('psqlplusscan',
36+
input: 'psqlplusscan.l',
37+
output: 'psqlplusscan.c',
38+
command: [flex_cmd, '--no-backup', '--fix-warnings', '--', '-Cfe', '-p', '-p'])
39+
generated_sources += psqlplusscan
40+
psql_sources += psqlplusscan
41+
psqlplusparse = custom_target('psqlplusparse',
42+
input: 'psqlplusparse.y',
43+
kwargs: bison_kw,
44+
)
45+
generated_sources += psqlplusparse.to_list()
46+
psql_sources += psqlplusparse
47+
3548
sql_help = custom_target('psql_help',
3649
output: ['sql_help.c', 'sql_help.h'],
3750
depfile: 'sql_help.dep',

0 commit comments

Comments
 (0)