Commit a1dc6ab4 authored by Michael Meskes's avatar Michael Meskes

Implement PREPARE AS statement for ECPG.

Besides implementing the new statement this change fix some issues with the
parsing of PREPARE and EXECUTE statements. The different forms of these
statements are now all handled in a ujnified way.

Author: Matsumura-san <matsumura.ryo@jp.fujitsu.com>
parent 5af2e976
......@@ -231,6 +231,7 @@ char *ecpg_prepared(const char *, struct connection *);
bool ecpg_deallocate_all_conn(int lineno, enum COMPAT_MODE c, struct connection *conn);
void ecpg_log(const char *format,...) pg_attribute_printf(1, 2);
bool ecpg_auto_prepare(int, const char *, const int, char **, const char *);
bool ecpg_register_prepared_stmt(struct statement *);
void ecpg_init_sqlca(struct sqlca_t *sqlca);
struct sqlda_compat *ecpg_build_compat_sqlda(int, PGresult *, int, enum COMPAT_MODE);
......
......@@ -488,6 +488,23 @@ sprintf_float_value(char *ptr, float value, const char *delim)
sprintf(ptr, "%.15g%s", value, delim);
}
static char*
convert_bytea_to_string(char *from_data, int from_len, int lineno)
{
char *to_data;
int to_len = ecpg_hex_enc_len(from_len) + 4 + 1; /* backslash + 'x' + quote + quote */
to_data = ecpg_alloc(to_len, lineno);
if (!to_data)
return NULL;
strcpy(to_data, "'\\x");
ecpg_hex_encode(from_data, from_len, to_data + 3);
strcpy(to_data + 3 + ecpg_hex_enc_len(from_len), "\'");
return to_data;
}
bool
ecpg_store_input(const int lineno, const bool force_indicator, const struct variable *var,
char **tobeinserted_p, bool quote)
......@@ -1433,6 +1450,36 @@ ecpg_build_params(struct statement *stmt)
*/
else if (stmt->command[position] == '0')
{
if (stmt->statement_type == ECPGst_prepare ||
stmt->statement_type == ECPGst_exec_with_exprlist)
{
/* Add double quote both side for embedding statement name. */
char *str = ecpg_alloc(strlen(tobeinserted) + 2 + 1, stmt->lineno);
sprintf(str, "\"%s\"", tobeinserted);
ecpg_free(tobeinserted);
tobeinserted = str;
}
if (!insert_tobeinserted(position, 2, stmt, tobeinserted))
{
ecpg_free_params(stmt, false);
return false;
}
tobeinserted = NULL;
}
else if (stmt->statement_type == ECPGst_exec_with_exprlist)
{
if (binary_format)
{
char *p = convert_bytea_to_string(tobeinserted, binary_length, stmt->lineno);
if (!p)
{
ecpg_free_params(stmt, false);
return false;
}
tobeinserted = p;
}
if (!insert_tobeinserted(position, 2, stmt, tobeinserted))
{
ecpg_free_params(stmt, false);
......@@ -1493,8 +1540,12 @@ ecpg_build_params(struct statement *stmt)
var = var->next;
}
/* Check if there are unmatched things left. */
if (next_insert(stmt->command, position, stmt->questionmarks, std_strings) >= 0)
/*
* Check if there are unmatched things left.
* PREPARE AS has no parameter. Check other statement.
*/
if (stmt->statement_type != ECPGst_prepare &&
next_insert(stmt->command, position, stmt->questionmarks, std_strings) >= 0)
{
ecpg_raise(stmt->lineno, ECPG_TOO_FEW_ARGUMENTS,
ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS, NULL);
......@@ -1560,8 +1611,18 @@ ecpg_execute(struct statement *stmt)
(const int *) stmt->paramlengths,
(const int *) stmt->paramformats,
0);
ecpg_log("ecpg_execute on line %d: using PQexecParams\n", stmt->lineno);
}
if (stmt->statement_type == ECPGst_prepare)
{
if(! ecpg_register_prepared_stmt(stmt))
{
ecpg_free_params(stmt, true);
return false;
}
}
}
ecpg_free_params(stmt, true);
......@@ -1874,6 +1935,7 @@ ecpg_do_prologue(int lineno, const int compat, const int force_indicator,
enum ECPGttype type;
struct variable **list;
char *prepname;
bool is_prepared_name_set;
*stmt_out = NULL;
......@@ -1975,6 +2037,7 @@ ecpg_do_prologue(int lineno, const int compat, const int force_indicator,
return false;
}
}
/* name of PREPARE AS will be set in loop of inlist */
stmt->connection = con;
stmt->lineno = lineno;
......@@ -2004,6 +2067,8 @@ ecpg_do_prologue(int lineno, const int compat, const int force_indicator,
*------
*/
is_prepared_name_set = false;
list = &(stmt->inlist);
type = va_arg(args, enum ECPGttype);
......@@ -2092,6 +2157,12 @@ ecpg_do_prologue(int lineno, const int compat, const int force_indicator,
*list = var;
else
ptr->next = var;
if (!is_prepared_name_set && stmt->statement_type == ECPGst_prepare)
{
stmt->name = ecpg_strdup(var->value, lineno);
is_prepared_name_set = true;
}
}
type = va_arg(args, enum ECPGttype);
......@@ -2105,6 +2176,13 @@ ecpg_do_prologue(int lineno, const int compat, const int force_indicator,
return false;
}
if (!is_prepared_name_set && stmt->statement_type == ECPGst_prepare)
{
ecpg_raise(lineno, ECPG_TOO_FEW_ARGUMENTS, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, (con) ? con->name : ecpg_gettext("<empty>"));
ecpg_do_epilogue(stmt);
return false;
}
/* initialize auto_mem struct */
ecpg_clear_auto_mem();
......
......@@ -56,6 +56,60 @@ isvarchar(unsigned char c)
return false;
}
bool
ecpg_register_prepared_stmt(struct statement *stmt)
{
struct statement *prep_stmt;
struct prepared_statement *this;
struct connection *con = NULL;
struct prepared_statement *prev = NULL;
char *real_connection_name;
int lineno = stmt->lineno;
real_connection_name = ecpg_get_con_name_by_declared_name(stmt->name);
if (real_connection_name == NULL)
real_connection_name = stmt->connection->name;
con = ecpg_get_connection(real_connection_name);
if (!ecpg_init(con, real_connection_name, stmt->lineno))
return false;
/* check if we already have prepared this statement */
this = ecpg_find_prepared_statement(stmt->name, con, &prev);
if (this && !deallocate_one(lineno, ECPG_COMPAT_PGSQL, con, prev, this))
return false;
/* allocate new statement */
this = (struct prepared_statement *) ecpg_alloc(sizeof(struct prepared_statement), lineno);
if (!this)
return false;
prep_stmt = (struct statement *) ecpg_alloc(sizeof(struct statement), lineno);
if (!stmt)
{
ecpg_free(this);
return false;
}
memset(prep_stmt, 0, sizeof(struct statement));
/* create statement */
prep_stmt->lineno = lineno;
prep_stmt->connection = con;
prep_stmt->command = ecpg_strdup(stmt->command, lineno);
prep_stmt->inlist = prep_stmt->outlist = NULL;
this->name = ecpg_strdup(stmt->name, lineno);
this->stmt = prep_stmt;
this->prepared = true;
if (con->prep_stmts == NULL)
this->next = NULL;
else
this->next = con->prep_stmts;
con->prep_stmts = this;
return true;
}
static bool
replace_variables(char **text, int lineno)
{
......
......@@ -97,7 +97,9 @@ enum ECPG_statement_type
ECPGst_normal,
ECPGst_execute,
ECPGst_exec_immediate,
ECPGst_prepnormal
ECPGst_prepnormal,
ECPGst_prepare,
ECPGst_exec_with_exprlist
};
enum ECPG_cursor_statement_type
......
......@@ -39,8 +39,11 @@ my %replace_line = (
'ExecuteStmtEXECUTEnameexecute_param_clause' =>
'EXECUTE prepared_name execute_param_clause execute_rest',
'ExecuteStmtCREATEOptTempTABLEcreate_as_targetASEXECUTEnameexecute_param_clause'
=> 'CREATE OptTemp TABLE create_as_target AS EXECUTE prepared_name execute_param_clause',
'ExecuteStmtCREATEOptTempTABLEcreate_as_targetASEXECUTEnameexecute_param_clauseopt_with_data' =>
'CREATE OptTemp TABLE create_as_target AS EXECUTE prepared_name execute_param_clause opt_with_data execute_rest' ,
'ExecuteStmtCREATEOptTempTABLEIF_PNOTEXISTScreate_as_targetASEXECUTEnameexecute_param_clauseopt_with_data' =>
'CREATE OptTemp TABLE IF_P NOT EXISTS create_as_target AS EXECUTE prepared_name execute_param_clause opt_with_data execute_rest' ,
'PrepareStmtPREPAREnameprep_type_clauseASPreparableStmt' =>
'PREPARE prepared_name prep_type_clause AS PreparableStmt');
......
......@@ -20,13 +20,54 @@ ECPG: stmtSelectStmt block
ECPG: stmtUpdateStmt block
{ output_statement($1, 1, ECPGst_prepnormal); }
ECPG: stmtExecuteStmt block
{ output_statement($1, 1, ECPGst_execute); }
ECPG: stmtPrepareStmt block
{
if ($1.type == NULL || strlen($1.type) == 0)
output_statement($1.name, 1, ECPGst_execute);
else
{
if ($1.name[0] != '"')
/* case of char_variable */
add_variable_to_tail(&argsinsert, find_variable($1.name), &no_indicator);
else
{
/* case of ecpg_ident or CSTRING */
char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3);
char *str = mm_strdup($1.name + 1);
/* It must be cut off double quotation because new_variable() double-quotes. */
str[strlen(str) - 1] = '\0';
sprintf(length, "%d", (int) strlen(str));
add_variable_to_tail(&argsinsert, new_variable(str, ECPGmake_simple_type(ECPGt_const, length, 0), 0), &no_indicator);
}
output_statement(cat_str(3, mm_strdup("execute"), mm_strdup("$0"), $1.type), 0, ECPGst_exec_with_exprlist);
}
}
ECPG: stmtPrepareStmt block
{
if ($1.type == NULL)
output_prepare_statement($1.name, $1.stmt);
else if (strlen($1.type) == 0)
{
char *stmt = cat_str(3, mm_strdup("\""), $1.stmt, mm_strdup("\""));
output_prepare_statement($1.name, stmt);
}
else
output_statement(cat_str(5, mm_strdup("prepare"), $1.name, $1.type, mm_strdup("as"), $1.stmt), 0, ECPGst_normal);
{
if ($1.name[0] != '"')
/* case of char_variable */
add_variable_to_tail(&argsinsert, find_variable($1.name), &no_indicator);
else
{
char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3);
char *str = mm_strdup($1.name + 1);
/* It must be cut off double quotation because new_variable() double-quotes. */
str[strlen(str) - 1] = '\0';
sprintf(length, "%d", (int) strlen(str));
add_variable_to_tail(&argsinsert, new_variable(str, ECPGmake_simple_type(ECPGt_const, length, 0), 0), &no_indicator);
}
output_statement(cat_str(5, mm_strdup("prepare"), mm_strdup("$0"), $1.type, mm_strdup("as"), $1.stmt), 0, ECPGst_prepare);
}
}
ECPG: stmtTransactionStmt block
{
......@@ -276,11 +317,15 @@ ECPG: cursor_namename rule
$1 = curname;
$$ = $1;
}
ECPG: ExplainableStmtExecuteStmt block
{
$$ = $1.name;
}
ECPG: PrepareStmtPREPAREprepared_nameprep_type_clauseASPreparableStmt block
{
$$.name = $2;
$$.type = $3;
$$.stmt = cat_str(3, mm_strdup("\""), $5, mm_strdup("\""));
$$.stmt = $5;
}
| PREPARE prepared_name FROM execstring
{
......@@ -289,7 +334,18 @@ ECPG: PrepareStmtPREPAREprepared_nameprep_type_clauseASPreparableStmt block
$$.stmt = $4;
}
ECPG: ExecuteStmtEXECUTEprepared_nameexecute_param_clauseexecute_rest block
{ $$ = $2; }
{
$$.name = $2;
$$.type = $3;
}
ECPG: ExecuteStmtCREATEOptTempTABLEcreate_as_targetASEXECUTEprepared_nameexecute_param_clauseopt_with_dataexecute_rest block
{
$$.name = cat_str(8,mm_strdup("create"),$2,mm_strdup("table"),$4,mm_strdup("as execute"),$7,$8,$9);
}
ECPG: ExecuteStmtCREATEOptTempTABLEIF_PNOTEXISTScreate_as_targetASEXECUTEprepared_nameexecute_param_clauseopt_with_dataexecute_rest block
{
$$.name = cat_str(8,mm_strdup("create"),$2,mm_strdup("table if not exists"),$7,mm_strdup("as execute"),$10,$11,$12);
}
ECPG: DeclareCursorStmtDECLAREcursor_namecursor_optionsCURSORopt_holdFORSelectStmt block
{
struct cursor *ptr, *this;
......
......@@ -593,4 +593,5 @@ add_typedef(char *name, char *dimension, char *length, enum ECPGttype type_enum,
struct fetch_desc descriptor;
struct su_symbol struct_union;
struct prep prep;
struct exec exec;
}
......@@ -128,24 +128,30 @@ static char *ecpg_statement_type_name[] = {
"ECPGst_normal",
"ECPGst_execute",
"ECPGst_exec_immediate",
"ECPGst_prepnormal"
"ECPGst_prepnormal",
"ECPGst_prepare",
"ECPGst_exec_with_exprlist"
};
void
output_statement(char *stmt, int whenever_mode, enum ECPG_statement_type st)
{
fprintf(base_yyout, "{ ECPGdo(__LINE__, %d, %d, %s, %d, ", compat, force_indicator, connection ? connection : "NULL", questionmarks);
if (st == ECPGst_prepnormal && !auto_prepare)
st = ECPGst_normal;
/*
* In following cases, stmt is CSTRING or char_variable. They must be output directly.
* - prepared_name of EXECUTE without exprlist
* - execstring of EXECUTE IMMEDIATE
*/
fprintf(base_yyout, "%s, ", ecpg_statement_type_name[st]);
if (st == ECPGst_execute || st == ECPGst_exec_immediate)
{
fprintf(base_yyout, "%s, %s, ", ecpg_statement_type_name[st], stmt);
}
fprintf(base_yyout, "%s, ", stmt);
else
{
if (st == ECPGst_prepnormal && auto_prepare)
fputs("ECPGst_prepnormal, \"", base_yyout);
else
fputs("ECPGst_normal, \"", base_yyout);
fputs("\"", base_yyout);
output_escaped_str(stmt, false);
fputs("\", ", base_yyout);
}
......
......@@ -58,6 +58,7 @@ my %replace_string = (
# ECPG-only replace_types are defined in ecpg-replace_types
my %replace_types = (
'PrepareStmt' => '<prep>',
'ExecuteStmt' => '<exec>',
'opt_array_bounds' => '<index>',
# "ignore" means: do not create type and rules for this non-term-id
......@@ -102,11 +103,13 @@ my %replace_line = (
'RETURNING target_list opt_ecpg_into',
'ExecuteStmtEXECUTEnameexecute_param_clause' =>
'EXECUTE prepared_name execute_param_clause execute_rest',
'ExecuteStmtCREATEOptTempTABLEcreate_as_targetASEXECUTEnameexecute_param_clause'
=> 'CREATE OptTemp TABLE create_as_target AS EXECUTE prepared_name execute_param_clause',
'ExecuteStmtCREATEOptTempTABLEcreate_as_targetASEXECUTEnameexecute_param_clauseopt_with_data' =>
'CREATE OptTemp TABLE create_as_target AS EXECUTE prepared_name execute_param_clause opt_with_data execute_rest',
'ExecuteStmtCREATEOptTempTABLEIF_PNOTEXISTScreate_as_targetASEXECUTEnameexecute_param_clauseopt_with_data' =>
'CREATE OptTemp TABLE IF_P NOT EXISTS create_as_target AS EXECUTE prepared_name execute_param_clause opt_with_data execute_rest',
'PrepareStmtPREPAREnameprep_type_clauseASPreparableStmt' =>
'PREPARE prepared_name prep_type_clause AS PreparableStmt',
'var_nameColId' => 'ECPGColId',);
'var_nameColId' => 'ECPGColId');
preload_addons();
......
......@@ -106,6 +106,12 @@ struct prep
char *type;
};
struct exec
{
char *name;
char *type;
};
struct this_type
{
enum ECPGttype type_enum;
......
......@@ -52,6 +52,7 @@ test: sql/quote
test: sql/show
test: sql/insupd
test: sql/parser
test: sql/prepareas
test: sql/declare
test: thread/thread
test: thread/thread_implicit
......
This diff is collapsed.
+++++ Test for prepnormal +++++
insert into test values(:ivar1,:ivar2)
1 2
+++++ Test for execute immediate +++++
execute immediate "insert into test values(1,2)"
1 2
+++++ Test for PREPARE ident FROM CString +++++
prepare ident_name from "insert into test values(?,?)"
execute ident_name using :ivar1,:ivar2
1 2
+++++ Test for PREPARE char_variable_normal_name FROM char_variable +++++
prepare :v_normal_name from :v_query
execute :v_normal_name using :ivar1,:ivar2
1 2
+++++ Test for PREPARE char_variable_inc_dq_name FROM char_variable +++++
prepare :v_include_dq_name from :v_query
execute :v_include_dq_name using :ivar1,:ivar2
1 2
+++++ Test for PREPARE char_variable_inc_ws_name FROM char_variable +++++
prepare :v_include_ws_name from :v_query
execute :v_include_ws_name using :ivar1,:ivar2
1 2
+++++ Test for PREPARE CString_inc_ws_name FROM char_variable +++++
prepare "include_ _name" from :v_query
exec sql execute "include_ _name" using :ivar1,:ivar2
1 2
+++++ Test for PREPARE CString_normal_name FROM char_variable +++++
prepare "norma_name" from :v_query
exec sql execute "normal_name" using :ivar1,:ivar2
1 2
+++++ Test for PREPARE ident(typelist) AS +++++
prepare ident_name(int,int) as insert into test values($1,$2)
execute ident_name(:ivar1,:ivar2)
1 2
+++++ Test for PREPARE CString_normal_name(typelist) AS +++++
prepare "normal_name"(int,int) as insert into test values($1,$2)
execute "normal_name"(:ivar1,:ivar2)
1 2
+++++ Test for PREPARE CString_include_ws_name(typelist) AS +++++
prepare "include_ _name"(int,int) as insert into test values($1,$2)
execute "include_ _name"(:ivar1,:ivar2)
1 2
+++++ Test for PREPARE char_variable_normal_name(typelist) AS +++++
prepare :v_normal_name(int,int) as insert into test values($1,$2)
execute :v_normal_name(:ivar1,:ivar2)
1 2
+++++ Test for PREPARE char_variable_include_ws_name(typelist) AS +++++
prepare :v_include_ws_name(int,int) as insert into test values($1,$2)
execute :v_include_ws_name(:ivar1,:ivar2)
1 2
+++++ Test for EXECUTE :v_normal_name(const,const) +++++
prepare :v_normal_name from :v_query
execute :v_normal_name(1,2)
1 2
+++++ Test for EXECUTE :v_normal_name(expr,expr) +++++
prepare :v_normal_name from :v_query
execute :v_normal_name(0+1,1+1)
1 2
+++++ Test for combination PREPARE FROM and EXECUTE ident(typelist) +++++
prepare ident_name from :v_query
execute ident_name(:ivar1,:ivar2)
1 2
+++++ Test for combination PREPARE FROM and EXECUTE CString_include_ws_name(typelist) +++++
prepare "include_ _name" from :v_query
execute "include_ _name"(:ivar1,:ivar2)
1 2
......@@ -27,7 +27,8 @@ TESTS = array array.c \
twophase twophase.c \
insupd insupd.c \
declare declare.c \
bytea bytea.c
bytea bytea.c \
prepareas prepareas.c
all: $(TESTS)
......
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
exec sql include ../regression;
exec sql whenever sqlerror sqlprint;
static void
check_result_of_insert(void)
{
exec sql begin declare section;
int ivar1 = 0, ivar2 = 0;
exec sql end declare section;
exec sql select c1,c2 into :ivar1,:ivar2 from test;
printf("%d %d\n", ivar1, ivar2);
}
int main(void)
{
exec sql begin declare section;
int ivar1 = 1, ivar2 = 2;
char v_include_dq_name[16], v_include_ws_name[16], v_normal_name[16], v_query[64];
exec sql end declare section;
strcpy(v_normal_name, "normal_name");
strcpy(v_include_dq_name, "include_\"_name");
strcpy(v_include_ws_name, "include_ _name");
strcpy(v_query, "insert into test values(?,?)");
/*
* preparing for test
*/
exec sql connect to REGRESSDB1;
exec sql begin;
exec sql create table test (c1 int, c2 int);
exec sql commit work;
exec sql begin;
/*
* Non dynamic statement
*/
exec sql truncate test;
printf("+++++ Test for prepnormal +++++\n");
printf("insert into test values(:ivar1,:ivar2)\n");
exec sql insert into test values(:ivar1,:ivar2);
check_result_of_insert();
exec sql truncate test;
printf("+++++ Test for execute immediate +++++\n");
printf("execute immediate \"insert into test values(1,2)\"\n");
exec sql execute immediate "insert into test values(1,2)";
check_result_of_insert();
/*
* PREPARE FROM
*/
exec sql truncate test;
printf("+++++ Test for PREPARE ident FROM CString +++++\n");
printf("prepare ident_name from \"insert into test values(?,?)\"\n");
exec sql prepare ident_name from "insert into test values(?,?)";
printf("execute ident_name using :ivar1,:ivar2\n");
exec sql execute ident_name using :ivar1,:ivar2;
check_result_of_insert();
exec sql truncate test;
printf("+++++ Test for PREPARE char_variable_normal_name FROM char_variable +++++\n");
printf("prepare :v_normal_name from :v_query\n");
exec sql prepare :v_normal_name from :v_query;
printf("execute :v_normal_name using :ivar1,:ivar2\n");
exec sql execute :v_normal_name using :ivar1,:ivar2;
check_result_of_insert();
exec sql truncate test;
printf("+++++ Test for PREPARE char_variable_inc_dq_name FROM char_variable +++++\n");
printf("prepare :v_include_dq_name from :v_query\n");
exec sql prepare :v_include_dq_name from :v_query;
printf("execute :v_include_dq_name using :ivar1,:ivar2\n");
exec sql execute :v_include_dq_name using :ivar1,:ivar2;
check_result_of_insert();
exec sql truncate test;
printf("+++++ Test for PREPARE char_variable_inc_ws_name FROM char_variable +++++\n");
printf("prepare :v_include_ws_name from :v_query\n");
exec sql prepare :v_include_ws_name from :v_query;
printf("execute :v_include_ws_name using :ivar1,:ivar2\n");
exec sql execute :v_include_ws_name using :ivar1,:ivar2;
check_result_of_insert();
exec sql truncate test;
printf("+++++ Test for PREPARE CString_inc_ws_name FROM char_variable +++++\n");
printf("prepare \"include_ _name\" from :v_query\n");
exec sql prepare "include_ _name" from :v_query;
printf("exec sql execute \"include_ _name\" using :ivar1,:ivar2\n");
exec sql execute "include_ _name" using :ivar1,:ivar2;
check_result_of_insert();
exec sql truncate test;
printf("+++++ Test for PREPARE CString_normal_name FROM char_variable +++++\n");
printf("prepare \"norma_name\" from :v_query\n");
exec sql prepare "normal_name" from :v_query;
printf("exec sql execute \"normal_name\" using :ivar1,:ivar2\n");
exec sql execute "normal_name" using :ivar1,:ivar2;
check_result_of_insert();
/*
* PREPARE AS
*/
exec sql deallocate "ident_name";
exec sql deallocate "normal_name";
exec sql deallocate "include_ _name";
exec sql truncate test;
printf("+++++ Test for PREPARE ident(typelist) AS +++++\n");
printf("prepare ident_name(int,int) as insert into test values($1,$2)\n");
exec sql prepare ident_name(int,int) as insert into test values($1,$2);
printf("execute ident_name(:ivar1,:ivar2)\n");
exec sql execute ident_name(:ivar1,:ivar2);
check_result_of_insert();
exec sql deallocate "ident_name";
exec sql truncate test;
printf("+++++ Test for PREPARE CString_normal_name(typelist) AS +++++\n");
printf("prepare \"normal_name\"(int,int) as insert into test values($1,$2)\n");
exec sql prepare "normal_name"(int,int) as insert into test values($1,$2);
printf("execute \"normal_name\"(:ivar1,:ivar2)\n");
exec sql execute "normal_name"(:ivar1,:ivar2);
check_result_of_insert();
exec sql deallocate "normal_name";
exec sql truncate test;
printf("+++++ Test for PREPARE CString_include_ws_name(typelist) AS +++++\n");
printf("prepare \"include_ _name\"(int,int) as insert into test values($1,$2)\n");
exec sql prepare "include_ _name"(int,int) as insert into test values($1,$2);
printf("execute \"include_ _name\"(:ivar1,:ivar2)\n");
exec sql execute "include_ _name"(:ivar1,:ivar2);
check_result_of_insert();
exec sql deallocate "include_ _name";
exec sql truncate test;
printf("+++++ Test for PREPARE char_variable_normal_name(typelist) AS +++++\n");
printf("prepare :v_normal_name(int,int) as insert into test values($1,$2)\n");
exec sql prepare :v_normal_name(int,int) as insert into test values($1,$2);
printf("execute :v_normal_name(:ivar1,:ivar2)\n");
exec sql execute :v_normal_name(:ivar1,:ivar2);
check_result_of_insert();
exec sql deallocate "normal_name";
exec sql truncate test;
printf("+++++ Test for PREPARE char_variable_include_ws_name(typelist) AS +++++\n");
printf("prepare :v_include_ws_name(int,int) as insert into test values($1,$2)\n");
exec sql prepare :v_include_ws_name(int,int) as insert into test values($1,$2);
printf("execute :v_include_ws_name(:ivar1,:ivar2)\n");
exec sql execute :v_include_ws_name(:ivar1,:ivar2);
check_result_of_insert();
exec sql deallocate "include_ _name";
exec sql truncate test;
printf("+++++ Test for EXECUTE :v_normal_name(const,const) +++++\n");
printf("prepare :v_normal_name from :v_query\n");
exec sql prepare :v_normal_name from :v_query;
printf("execute :v_normal_name(1,2)\n");
exec sql execute :v_normal_name(1,2);
check_result_of_insert();
exec sql deallocate "normal_name";
exec sql truncate test;
printf("+++++ Test for EXECUTE :v_normal_name(expr,expr) +++++\n");
printf("prepare :v_normal_name from :v_query\n");
exec sql prepare :v_normal_name from :v_query;
printf("execute :v_normal_name(0+1,1+1)\n");
exec sql execute :v_normal_name(0+1,1+1);
check_result_of_insert();
exec sql deallocate "normal_name";
exec sql truncate test;
printf("+++++ Test for combination PREPARE FROM and EXECUTE ident(typelist) +++++\n");
printf("prepare ident_name from :v_query\n");
exec sql prepare ident_name from :v_query;
printf("execute ident_name(:ivar1,:ivar2)\n");
exec sql execute ident_name(:ivar1,:ivar2);
check_result_of_insert();
exec sql deallocate "ident_name";
exec sql truncate test;
printf("+++++ Test for combination PREPARE FROM and EXECUTE CString_include_ws_name(typelist) +++++\n");
printf("prepare \"include_ _name\" from :v_query\n");
exec sql prepare "include_ _name" from :v_query;
printf("execute \"include_ _name\"(:ivar1,:ivar2)\n");
exec sql execute "include_ _name"(:ivar1,:ivar2);
check_result_of_insert();
exec sql deallocate "include_ _name";
exec sql drop table test;
exec sql commit work;
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment