Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commita1dc6ab

Browse files
author
Michael Meskes
committed
Implement PREPARE AS statement for ECPG.
Besides implementing the new statement this change fix some issues with theparsing of PREPARE and EXECUTE statements. The different forms of thesestatements are now all handled in a ujnified way.Author: Matsumura-san <matsumura.ryo@jp.fujitsu.com>
1 parent5af2e97 commita1dc6ab

File tree

16 files changed

+1163
-23
lines changed

16 files changed

+1163
-23
lines changed

‎src/interfaces/ecpg/ecpglib/ecpglib_extern.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ char *ecpg_prepared(const char *, struct connection *);
231231
boolecpg_deallocate_all_conn(intlineno,enumCOMPAT_MODEc,structconnection*conn);
232232
voidecpg_log(constchar*format,...)pg_attribute_printf(1,2);
233233
boolecpg_auto_prepare(int,constchar*,constint,char**,constchar*);
234+
boolecpg_register_prepared_stmt(structstatement*);
234235
voidecpg_init_sqlca(structsqlca_t*sqlca);
235236

236237
structsqlda_compat*ecpg_build_compat_sqlda(int,PGresult*,int,enumCOMPAT_MODE);

‎src/interfaces/ecpg/ecpglib/execute.c

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,23 @@ sprintf_float_value(char *ptr, float value, const char *delim)
488488
sprintf(ptr,"%.15g%s",value,delim);
489489
}
490490

491+
staticchar*
492+
convert_bytea_to_string(char*from_data,intfrom_len,intlineno)
493+
{
494+
char*to_data;
495+
intto_len=ecpg_hex_enc_len(from_len)+4+1;/* backslash + 'x' + quote + quote */
496+
497+
to_data=ecpg_alloc(to_len,lineno);
498+
if (!to_data)
499+
returnNULL;
500+
501+
strcpy(to_data,"'\\x");
502+
ecpg_hex_encode(from_data,from_len,to_data+3);
503+
strcpy(to_data+3+ecpg_hex_enc_len(from_len),"\'");
504+
505+
returnto_data;
506+
}
507+
491508
bool
492509
ecpg_store_input(constintlineno,constboolforce_indicator,conststructvariable*var,
493510
char**tobeinserted_p,boolquote)
@@ -1433,6 +1450,36 @@ ecpg_build_params(struct statement *stmt)
14331450
*/
14341451
elseif (stmt->command[position]=='0')
14351452
{
1453+
if (stmt->statement_type==ECPGst_prepare||
1454+
stmt->statement_type==ECPGst_exec_with_exprlist)
1455+
{
1456+
/* Add double quote both side for embedding statement name. */
1457+
char*str=ecpg_alloc(strlen(tobeinserted)+2+1,stmt->lineno);
1458+
sprintf(str,"\"%s\"",tobeinserted);
1459+
ecpg_free(tobeinserted);
1460+
tobeinserted=str;
1461+
}
1462+
if (!insert_tobeinserted(position,2,stmt,tobeinserted))
1463+
{
1464+
ecpg_free_params(stmt, false);
1465+
return false;
1466+
}
1467+
tobeinserted=NULL;
1468+
}
1469+
elseif (stmt->statement_type==ECPGst_exec_with_exprlist)
1470+
{
1471+
1472+
if (binary_format)
1473+
{
1474+
char*p=convert_bytea_to_string(tobeinserted,binary_length,stmt->lineno);
1475+
if (!p)
1476+
{
1477+
ecpg_free_params(stmt, false);
1478+
return false;
1479+
}
1480+
tobeinserted=p;
1481+
}
1482+
14361483
if (!insert_tobeinserted(position,2,stmt,tobeinserted))
14371484
{
14381485
ecpg_free_params(stmt, false);
@@ -1493,8 +1540,12 @@ ecpg_build_params(struct statement *stmt)
14931540
var=var->next;
14941541
}
14951542

1496-
/* Check if there are unmatched things left. */
1497-
if (next_insert(stmt->command,position,stmt->questionmarks,std_strings) >=0)
1543+
/*
1544+
* Check if there are unmatched things left.
1545+
* PREPARE AS has no parameter. Check other statement.
1546+
*/
1547+
if (stmt->statement_type!=ECPGst_prepare&&
1548+
next_insert(stmt->command,position,stmt->questionmarks,std_strings) >=0)
14981549
{
14991550
ecpg_raise(stmt->lineno,ECPG_TOO_FEW_ARGUMENTS,
15001551
ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS,NULL);
@@ -1560,8 +1611,18 @@ ecpg_execute(struct statement *stmt)
15601611
(constint*)stmt->paramlengths,
15611612
(constint*)stmt->paramformats,
15621613
0);
1614+
15631615
ecpg_log("ecpg_execute on line %d: using PQexecParams\n",stmt->lineno);
15641616
}
1617+
1618+
if (stmt->statement_type==ECPGst_prepare)
1619+
{
1620+
if(!ecpg_register_prepared_stmt(stmt))
1621+
{
1622+
ecpg_free_params(stmt, true);
1623+
return false;
1624+
}
1625+
}
15651626
}
15661627

15671628
ecpg_free_params(stmt, true);
@@ -1874,6 +1935,7 @@ ecpg_do_prologue(int lineno, const int compat, const int force_indicator,
18741935
enumECPGttypetype;
18751936
structvariable**list;
18761937
char*prepname;
1938+
boolis_prepared_name_set;
18771939

18781940
*stmt_out=NULL;
18791941

@@ -1975,6 +2037,7 @@ ecpg_do_prologue(int lineno, const int compat, const int force_indicator,
19752037
return false;
19762038
}
19772039
}
2040+
/* name of PREPARE AS will be set in loop of inlist */
19782041

19792042
stmt->connection=con;
19802043
stmt->lineno=lineno;
@@ -2004,6 +2067,8 @@ ecpg_do_prologue(int lineno, const int compat, const int force_indicator,
20042067
*------
20052068
*/
20062069

2070+
is_prepared_name_set= false;
2071+
20072072
list=&(stmt->inlist);
20082073

20092074
type=va_arg(args,enumECPGttype);
@@ -2092,6 +2157,12 @@ ecpg_do_prologue(int lineno, const int compat, const int force_indicator,
20922157
*list=var;
20932158
else
20942159
ptr->next=var;
2160+
2161+
if (!is_prepared_name_set&&stmt->statement_type==ECPGst_prepare)
2162+
{
2163+
stmt->name=ecpg_strdup(var->value,lineno);
2164+
is_prepared_name_set= true;
2165+
}
20952166
}
20962167

20972168
type=va_arg(args,enumECPGttype);
@@ -2105,6 +2176,13 @@ ecpg_do_prologue(int lineno, const int compat, const int force_indicator,
21052176
return false;
21062177
}
21072178

2179+
if (!is_prepared_name_set&&stmt->statement_type==ECPGst_prepare)
2180+
{
2181+
ecpg_raise(lineno,ECPG_TOO_FEW_ARGUMENTS,ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, (con) ?con->name :ecpg_gettext("<empty>"));
2182+
ecpg_do_epilogue(stmt);
2183+
return false;
2184+
}
2185+
21082186
/* initialize auto_mem struct */
21092187
ecpg_clear_auto_mem();
21102188

‎src/interfaces/ecpg/ecpglib/prepare.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,60 @@ isvarchar(unsigned char c)
5656
return false;
5757
}
5858

59+
bool
60+
ecpg_register_prepared_stmt(structstatement*stmt)
61+
{
62+
structstatement*prep_stmt;
63+
structprepared_statement*this;
64+
structconnection*con=NULL;
65+
structprepared_statement*prev=NULL;
66+
char*real_connection_name;
67+
intlineno=stmt->lineno;
68+
69+
real_connection_name=ecpg_get_con_name_by_declared_name(stmt->name);
70+
if (real_connection_name==NULL)
71+
real_connection_name=stmt->connection->name;
72+
73+
con=ecpg_get_connection(real_connection_name);
74+
if (!ecpg_init(con,real_connection_name,stmt->lineno))
75+
return false;
76+
77+
/* check if we already have prepared this statement */
78+
this=ecpg_find_prepared_statement(stmt->name,con,&prev);
79+
if (this&& !deallocate_one(lineno,ECPG_COMPAT_PGSQL,con,prev,this))
80+
return false;
81+
82+
/* allocate new statement */
83+
this= (structprepared_statement*)ecpg_alloc(sizeof(structprepared_statement),lineno);
84+
if (!this)
85+
return false;
86+
87+
prep_stmt= (structstatement*)ecpg_alloc(sizeof(structstatement),lineno);
88+
if (!stmt)
89+
{
90+
ecpg_free(this);
91+
return false;
92+
}
93+
memset(prep_stmt,0,sizeof(structstatement));
94+
95+
/* create statement */
96+
prep_stmt->lineno=lineno;
97+
prep_stmt->connection=con;
98+
prep_stmt->command=ecpg_strdup(stmt->command,lineno);
99+
prep_stmt->inlist=prep_stmt->outlist=NULL;
100+
this->name=ecpg_strdup(stmt->name,lineno);
101+
this->stmt=prep_stmt;
102+
this->prepared= true;
103+
104+
if (con->prep_stmts==NULL)
105+
this->next=NULL;
106+
else
107+
this->next=con->prep_stmts;
108+
109+
con->prep_stmts=this;
110+
return true;
111+
}
112+
59113
staticbool
60114
replace_variables(char**text,intlineno)
61115
{

‎src/interfaces/ecpg/include/ecpgtype.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,9 @@ enum ECPG_statement_type
9797
ECPGst_normal,
9898
ECPGst_execute,
9999
ECPGst_exec_immediate,
100-
ECPGst_prepnormal
100+
ECPGst_prepnormal,
101+
ECPGst_prepare,
102+
ECPGst_exec_with_exprlist
101103
};
102104

103105
enumECPG_cursor_statement_type

‎src/interfaces/ecpg/preproc/check_rules.pl

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,11 @@
3939
'ExecuteStmtEXECUTEnameexecute_param_clause'=>
4040
'EXECUTE prepared_name execute_param_clause execute_rest',
4141

42-
'ExecuteStmtCREATEOptTempTABLEcreate_as_targetASEXECUTEnameexecute_param_clause'
43-
=>'CREATE OptTemp TABLE create_as_target AS EXECUTE prepared_name execute_param_clause',
42+
'ExecuteStmtCREATEOptTempTABLEcreate_as_targetASEXECUTEnameexecute_param_clauseopt_with_data'=>
43+
'CREATE OptTemp TABLE create_as_target AS EXECUTE prepared_name execute_param_clause opt_with_data execute_rest' ,
44+
45+
'ExecuteStmtCREATEOptTempTABLEIF_PNOTEXISTScreate_as_targetASEXECUTEnameexecute_param_clauseopt_with_data'=>
46+
'CREATE OptTemp TABLE IF_P NOT EXISTS create_as_target AS EXECUTE prepared_name execute_param_clause opt_with_data execute_rest' ,
4447

4548
'PrepareStmtPREPAREnameprep_type_clauseASPreparableStmt'=>
4649
'PREPARE prepared_name prep_type_clause AS PreparableStmt');

‎src/interfaces/ecpg/preproc/ecpg.addons

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,54 @@ ECPG: stmtSelectStmt block
2020
ECPG: stmtUpdateStmt block
2121
{ output_statement($1, 1, ECPGst_prepnormal); }
2222
ECPG: stmtExecuteStmt block
23-
{ output_statement($1, 1, ECPGst_execute); }
24-
ECPG: stmtPrepareStmt block
2523
{
2624
if ($1.type == NULL || strlen($1.type) == 0)
25+
output_statement($1.name, 1, ECPGst_execute);
26+
else
27+
{
28+
if ($1.name[0] != '"')
29+
/* case of char_variable */
30+
add_variable_to_tail(&argsinsert, find_variable($1.name), &no_indicator);
31+
else
32+
{
33+
/* case of ecpg_ident or CSTRING */
34+
char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3);
35+
char *str = mm_strdup($1.name + 1);
36+
37+
/* It must be cut off double quotation because new_variable() double-quotes. */
38+
str[strlen(str) - 1] = '\0';
39+
sprintf(length, "%d", (int) strlen(str));
40+
add_variable_to_tail(&argsinsert, new_variable(str, ECPGmake_simple_type(ECPGt_const, length, 0), 0), &no_indicator);
41+
}
42+
output_statement(cat_str(3, mm_strdup("execute"), mm_strdup("$0"), $1.type), 0, ECPGst_exec_with_exprlist);
43+
}
44+
}
45+
ECPG: stmtPrepareStmt block
46+
{
47+
if ($1.type == NULL)
2748
output_prepare_statement($1.name, $1.stmt);
49+
else if (strlen($1.type) == 0)
50+
{
51+
char *stmt = cat_str(3, mm_strdup("\""), $1.stmt, mm_strdup("\""));
52+
output_prepare_statement($1.name, stmt);
53+
}
2854
else
29-
output_statement(cat_str(5, mm_strdup("prepare"), $1.name, $1.type, mm_strdup("as"), $1.stmt), 0, ECPGst_normal);
55+
{
56+
if ($1.name[0] != '"')
57+
/* case of char_variable */
58+
add_variable_to_tail(&argsinsert, find_variable($1.name), &no_indicator);
59+
else
60+
{
61+
char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3);
62+
char *str = mm_strdup($1.name + 1);
63+
64+
/* It must be cut off double quotation because new_variable() double-quotes. */
65+
str[strlen(str) - 1] = '\0';
66+
sprintf(length, "%d", (int) strlen(str));
67+
add_variable_to_tail(&argsinsert, new_variable(str, ECPGmake_simple_type(ECPGt_const, length, 0), 0), &no_indicator);
68+
}
69+
output_statement(cat_str(5, mm_strdup("prepare"), mm_strdup("$0"), $1.type, mm_strdup("as"), $1.stmt), 0, ECPGst_prepare);
70+
}
3071
}
3172
ECPG: stmtTransactionStmt block
3273
{
@@ -276,11 +317,15 @@ ECPG: cursor_namename rule
276317
$1 = curname;
277318
$$ = $1;
278319
}
320+
ECPG: ExplainableStmtExecuteStmt block
321+
{
322+
$$ = $1.name;
323+
}
279324
ECPG: PrepareStmtPREPAREprepared_nameprep_type_clauseASPreparableStmt block
280325
{
281326
$$.name = $2;
282327
$$.type = $3;
283-
$$.stmt =cat_str(3, mm_strdup("\""), $5, mm_strdup("\""));
328+
$$.stmt =$5;
284329
}
285330
| PREPARE prepared_name FROM execstring
286331
{
@@ -289,7 +334,18 @@ ECPG: PrepareStmtPREPAREprepared_nameprep_type_clauseASPreparableStmt block
289334
$$.stmt = $4;
290335
}
291336
ECPG: ExecuteStmtEXECUTEprepared_nameexecute_param_clauseexecute_rest block
292-
{ $$ = $2; }
337+
{
338+
$$.name = $2;
339+
$$.type = $3;
340+
}
341+
ECPG: ExecuteStmtCREATEOptTempTABLEcreate_as_targetASEXECUTEprepared_nameexecute_param_clauseopt_with_dataexecute_rest block
342+
{
343+
$$.name = cat_str(8,mm_strdup("create"),$2,mm_strdup("table"),$4,mm_strdup("as execute"),$7,$8,$9);
344+
}
345+
ECPG: ExecuteStmtCREATEOptTempTABLEIF_PNOTEXISTScreate_as_targetASEXECUTEprepared_nameexecute_param_clauseopt_with_dataexecute_rest block
346+
{
347+
$$.name = cat_str(8,mm_strdup("create"),$2,mm_strdup("table if not exists"),$7,mm_strdup("as execute"),$10,$11,$12);
348+
}
293349
ECPG: DeclareCursorStmtDECLAREcursor_namecursor_optionsCURSORopt_holdFORSelectStmt block
294350
{
295351
struct cursor *ptr, *this;

‎src/interfaces/ecpg/preproc/ecpg.header

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,4 +593,5 @@ add_typedef(char *name, char *dimension, char *length, enum ECPGttype type_enum,
593593
structfetch_descdescriptor;
594594
struct su_symbolstruct_union;
595595
structprepprep;
596+
structexecexec;
596597
}

‎src/interfaces/ecpg/preproc/output.c

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -128,24 +128,30 @@ static char *ecpg_statement_type_name[] = {
128128
"ECPGst_normal",
129129
"ECPGst_execute",
130130
"ECPGst_exec_immediate",
131-
"ECPGst_prepnormal"
131+
"ECPGst_prepnormal",
132+
"ECPGst_prepare",
133+
"ECPGst_exec_with_exprlist"
132134
};
133135

134136
void
135137
output_statement(char*stmt,intwhenever_mode,enumECPG_statement_typest)
136138
{
137139
fprintf(base_yyout,"{ ECPGdo(__LINE__, %d, %d, %s, %d, ",compat,force_indicator,connection ?connection :"NULL",questionmarks);
140+
141+
if (st==ECPGst_prepnormal&& !auto_prepare)
142+
st=ECPGst_normal;
143+
144+
/*
145+
* In following cases, stmt is CSTRING or char_variable. They must be output directly.
146+
* - prepared_name of EXECUTE without exprlist
147+
* - execstring of EXECUTE IMMEDIATE
148+
*/
149+
fprintf(base_yyout,"%s, ",ecpg_statement_type_name[st]);
138150
if (st==ECPGst_execute||st==ECPGst_exec_immediate)
139-
{
140-
fprintf(base_yyout,"%s, %s, ",ecpg_statement_type_name[st],stmt);
141-
}
151+
fprintf(base_yyout,"%s, ",stmt);
142152
else
143153
{
144-
if (st==ECPGst_prepnormal&&auto_prepare)
145-
fputs("ECPGst_prepnormal, \"",base_yyout);
146-
else
147-
fputs("ECPGst_normal, \"",base_yyout);
148-
154+
fputs("\"",base_yyout);
149155
output_escaped_str(stmt, false);
150156
fputs("\", ",base_yyout);
151157
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp