emit() sweep: converting several of the stragglers remaining
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
This commit is contained in:
108
exec.c
108
exec.c
@ -47,6 +47,14 @@ void sqlp_alias(const char *alias)
|
||||
printf("exec ALIAS %s\n", alias);
|
||||
}
|
||||
|
||||
void sqlp_assign(const char *db_name, const char *name)
|
||||
{
|
||||
printf("exec ASSIGN %s%s%s\n",
|
||||
db_name ? db_name : "",
|
||||
db_name ? "." : "",
|
||||
name);
|
||||
}
|
||||
|
||||
void sqlp_bool(int val)
|
||||
{
|
||||
printf("exec BOOL %d\n", val);
|
||||
@ -97,6 +105,21 @@ void sqlp_col_def_bool(int bool)
|
||||
printf("exec ATTR DEFAULT-BOOL %d\n", bool);
|
||||
}
|
||||
|
||||
void sqlp_col_key_pri(int n_cols)
|
||||
{
|
||||
printf("exec KEY-PRI %d\n", n_cols);
|
||||
}
|
||||
|
||||
void sqlp_col_key(int n_cols)
|
||||
{
|
||||
printf("exec KEY %d\n", n_cols);
|
||||
}
|
||||
|
||||
void sqlp_col_key_textidx(int n_cols)
|
||||
{
|
||||
printf("exec KEY-TEXTIDX %d\n", n_cols);
|
||||
}
|
||||
|
||||
void sqlp_column(const char *name)
|
||||
{
|
||||
printf("exec COLUMN %s\n", name);
|
||||
@ -117,6 +140,16 @@ void sqlp_create_tbl(int temp, int if_n_exists, int n_cols,
|
||||
name);
|
||||
}
|
||||
|
||||
void sqlp_create_tbl_sel(int temp, int if_n_exists, int n_cols,
|
||||
const char *db_name, const char *name)
|
||||
{
|
||||
printf("exec CREATE-TABLE-SELECT %d %d %d %s%s%s\n",
|
||||
temp, if_n_exists, n_cols,
|
||||
db_name ? db_name : "",
|
||||
db_name ? "." : "",
|
||||
name);
|
||||
}
|
||||
|
||||
void sqlp_def_col(int flags, const char *name)
|
||||
{
|
||||
printf("exec DEFINE-COL %d %s\n", flags, name);
|
||||
@ -182,6 +215,16 @@ void sqlp_float(float val)
|
||||
printf("exec FLOAT %g\n", val);
|
||||
}
|
||||
|
||||
void sqlp_index(const char *name)
|
||||
{
|
||||
printf("exec INDEX %s\n", name);
|
||||
}
|
||||
|
||||
void sqlp_index_hint(int n_indexed, int opts)
|
||||
{
|
||||
printf("exec INDEX-HINT %d %d\n", n_indexed, opts);
|
||||
}
|
||||
|
||||
void sqlp_ins_cols(int n_cols)
|
||||
{
|
||||
printf("exec INSERT-COLS %d\n", n_cols);
|
||||
@ -192,11 +235,41 @@ void sqlp_ins_default(void)
|
||||
printf("exec INSERT-DEFAULT\n");
|
||||
}
|
||||
|
||||
void sqlp_ins_dup_update(int n_assn)
|
||||
{
|
||||
printf("exec INSERT DUP-ONUPDATE %d\n", n_assn);
|
||||
}
|
||||
|
||||
void sqlp_insert(int opts, int n_vals, const char *tbl_name)
|
||||
{
|
||||
printf("exec INSERT %d %d %s\n", opts, n_vals, tbl_name);
|
||||
}
|
||||
|
||||
void sqlp_insert_assn(int opts, int n_assn, const char *tbl_name)
|
||||
{
|
||||
printf("exec INSERT-ASSN %d %d %s\n", opts, n_assn, tbl_name);
|
||||
}
|
||||
|
||||
void sqlp_insert_sel(int opts, const char *tbl_name)
|
||||
{
|
||||
printf("exec INSERT-SEL %d %s\n", opts, tbl_name);
|
||||
}
|
||||
|
||||
void sqlp_join(int opts)
|
||||
{
|
||||
printf("exec JOIN %d\n", opts);
|
||||
}
|
||||
|
||||
void sqlp_join_expr(void)
|
||||
{
|
||||
printf("exec JOIN-ON EXPR\n");
|
||||
}
|
||||
|
||||
void sqlp_join_using(int n_cols)
|
||||
{
|
||||
printf("exec JOIN-USING %d\n", n_cols);
|
||||
}
|
||||
|
||||
void sqlp_name(const char *name)
|
||||
{
|
||||
printf("exec NAME %s\n", name);
|
||||
@ -207,11 +280,31 @@ void sqlp_number(int val)
|
||||
printf("exec INT/NUMBER %d\n", val);
|
||||
}
|
||||
|
||||
void sqlp_replace_assn(int opts, int n_assn, const char *name)
|
||||
{
|
||||
printf("exec REPLACE-ASSN %d %d %s\n", opts, n_assn, name);
|
||||
}
|
||||
|
||||
void sqlp_replace_vals(int opts, int n_vals, const char *name)
|
||||
{
|
||||
printf("exec REPLACE-VALS %d %d %s\n", opts, n_vals, name);
|
||||
}
|
||||
|
||||
void sqlp_replace_sel(int opts, const char *name)
|
||||
{
|
||||
printf("exec REPLACE-SEL %d %s\n", opts, name);
|
||||
}
|
||||
|
||||
void sqlp_select(int opts, int n_expr, int n_tbl_ref)
|
||||
{
|
||||
printf("exec SELECT %d %d %d\n", opts, n_expr, n_tbl_ref);
|
||||
}
|
||||
|
||||
void sqlp_select_nodata(int opts, int n_expr)
|
||||
{
|
||||
printf("exec SELECT-NODATA %d %d\n", opts, n_expr);
|
||||
}
|
||||
|
||||
void sqlp_select_all(void)
|
||||
{
|
||||
printf("exec SELECT-ALL\n");
|
||||
@ -232,6 +325,16 @@ void sqlp_string(const char *str)
|
||||
printf("exec STRING %s\n", str);
|
||||
}
|
||||
|
||||
void sqlp_subquery(void)
|
||||
{
|
||||
printf("exec SUBQUERY\n");
|
||||
}
|
||||
|
||||
void sqlp_subquery_as(const char *name)
|
||||
{
|
||||
printf("exec SUBQUERY-AS %s\n", name);
|
||||
}
|
||||
|
||||
void sqlp_table(const char *db_name, const char *name)
|
||||
{
|
||||
printf("exec TABLE %s%s%s\n",
|
||||
@ -240,6 +343,11 @@ void sqlp_table(const char *db_name, const char *name)
|
||||
name);
|
||||
}
|
||||
|
||||
void sqlp_update(int opts, int n_tbl_ref, int n_assn)
|
||||
{
|
||||
printf("exec UPDATE %d %d %d\n", opts, n_tbl_ref, n_assn);
|
||||
}
|
||||
|
||||
void sqlp_uservar(const char *str)
|
||||
{
|
||||
printf("exec USER-VAR %s\n", str);
|
||||
|
21
sql-parser.h
21
sql-parser.h
@ -40,6 +40,7 @@ enum sqlp_expr_ops {
|
||||
};
|
||||
|
||||
extern void sqlp_alias(const char *alias);
|
||||
extern void sqlp_assign(const char *db_name, const char *name);
|
||||
extern void sqlp_bool(int val);
|
||||
extern void sqlp_col_attr(enum sqlp_col_attribs attr);
|
||||
extern void sqlp_col_attr_uniq(int n_cols);
|
||||
@ -50,10 +51,15 @@ extern void sqlp_col_def_str(const char *str);
|
||||
extern void sqlp_col_def_num(int num);
|
||||
extern void sqlp_col_def_float(float num);
|
||||
extern void sqlp_col_def_bool(int bool);
|
||||
extern void sqlp_col_key_pri(int n_cols);
|
||||
extern void sqlp_col_key(int n_cols);
|
||||
extern void sqlp_col_key_textidx(int n_cols);
|
||||
extern void sqlp_column(const char *name);
|
||||
extern void sqlp_create_db(int if_n_exists, const char *name);
|
||||
extern void sqlp_create_tbl(int temp, int if_n_exists, int n_cols,
|
||||
const char *db_name, const char *name);
|
||||
extern void sqlp_create_tbl_sel(int temp, int if_n_exists, int n_cols,
|
||||
const char *db_name, const char *name);
|
||||
extern void sqlp_def_col(int flags, const char *name);
|
||||
extern void sqlp_delete(int opts, const char *name);
|
||||
extern void sqlp_delete_multi(int opts, int n_del, int n_tbl_ref);
|
||||
@ -67,17 +73,32 @@ extern void sqlp_expr_is_bool(int val);
|
||||
extern void sqlp_expr_is_in(int val);
|
||||
extern void sqlp_fieldname(const char *db_name, const char *name);
|
||||
extern void sqlp_float(float val);
|
||||
extern void sqlp_index(const char *name);
|
||||
extern void sqlp_index_hint(int n_indexed, int opts);
|
||||
extern void sqlp_ins_cols(int n_cols);
|
||||
extern void sqlp_ins_default(void);
|
||||
extern void sqlp_ins_dup_update(int n_assn);
|
||||
extern void sqlp_insert(int opts, int n_vals, const char *tbl_name);
|
||||
extern void sqlp_insert_assn(int opts, int n_assn, const char *tbl_name);
|
||||
extern void sqlp_insert_sel(int opts, const char *tbl_name);
|
||||
extern void sqlp_join(int opts);
|
||||
extern void sqlp_join_expr(void);
|
||||
extern void sqlp_join_using(int n_cols);
|
||||
extern void sqlp_name(const char *name);
|
||||
extern void sqlp_number(int val);
|
||||
extern void sqlp_replace_assn(int opts, int n_assn, const char *name);
|
||||
extern void sqlp_replace_vals(int opts, int n_vals, const char *name);
|
||||
extern void sqlp_replace_sel(int opts, const char *name);
|
||||
extern void sqlp_select(int opts, int n_expr, int n_tbl_ref);
|
||||
extern void sqlp_select_nodata(int opts, int n_expr);
|
||||
extern void sqlp_select_all(void);
|
||||
extern void sqlp_start_col(void);
|
||||
extern void sqlp_string(const char *str);
|
||||
extern void sqlp_stmt(void);
|
||||
extern void sqlp_subquery(void);
|
||||
extern void sqlp_subquery_as(const char *name);
|
||||
extern void sqlp_table(const char *db_name, const char *name);
|
||||
extern void sqlp_update(int opts, int n_tbl_ref, int n_assn);
|
||||
extern void sqlp_uservar(const char *str);
|
||||
extern void sqlp_values(int n_vals);
|
||||
extern void sqlp_where(void);
|
||||
|
80
sql.y
80
sql.y
@ -352,7 +352,7 @@ stmt: select_stmt { sqlp_stmt(); }
|
||||
;
|
||||
|
||||
select_stmt: SELECT select_opts select_expr_list
|
||||
{ emit("SELECTNODATA %d %d", $2, $3); } ;
|
||||
{ sqlp_select_nodata($2, $3); } ;
|
||||
| SELECT select_opts select_expr_list
|
||||
FROM table_references
|
||||
opt_where opt_groupby opt_having opt_orderby opt_limit
|
||||
@ -433,7 +433,7 @@ table_factor:
|
||||
NAME opt_as_alias index_hint { sqlp_table(NULL, $1); free($1); }
|
||||
| NAME '.' NAME opt_as_alias index_hint { sqlp_table($1, $3);
|
||||
free($1); free($3); }
|
||||
| table_subquery opt_as NAME { emit("SUBQUERYAS %s", $3); free($3); }
|
||||
| table_subquery opt_as NAME { sqlp_subquery_as($3); free($3); }
|
||||
| '(' table_references ')' { emit("TABLEREFERENCES %d", $2); }
|
||||
;
|
||||
|
||||
@ -448,15 +448,15 @@ opt_as_alias: AS NAME { sqlp_alias($2); free($2); }
|
||||
|
||||
join_table:
|
||||
table_reference opt_inner_cross JOIN table_factor opt_join_condition
|
||||
{ emit("JOIN %d", 0100+$2); }
|
||||
{ sqlp_join(0100+$2); }
|
||||
| table_reference STRAIGHT_JOIN table_factor
|
||||
{ emit("JOIN %d", 0200); }
|
||||
{ sqlp_join(0200); }
|
||||
| table_reference STRAIGHT_JOIN table_factor ON expr
|
||||
{ emit("JOIN %d", 0200); }
|
||||
{ sqlp_join(0200); }
|
||||
| table_reference left_or_right opt_outer JOIN table_factor join_condition
|
||||
{ emit("JOIN %d", 0300+$2+$3); }
|
||||
{ sqlp_join(0300+$2+$3); }
|
||||
| table_reference NATURAL opt_left_or_right_outer JOIN table_factor
|
||||
{ emit("JOIN %d", 0400+$3); }
|
||||
{ sqlp_join(0400+$3); }
|
||||
;
|
||||
|
||||
opt_inner_cross: /* nil */ { $$ = 0; }
|
||||
@ -480,17 +480,17 @@ opt_left_or_right_outer: LEFT opt_outer { $$ = 1 + $2; }
|
||||
opt_join_condition: join_condition | /* nil */ ;
|
||||
|
||||
join_condition:
|
||||
ON expr { emit("ONEXPR"); }
|
||||
| USING '(' column_list ')' { emit("USING %d", $3); }
|
||||
ON expr { sqlp_join_expr(); }
|
||||
| USING '(' column_list ')' { sqlp_join_using($3); }
|
||||
;
|
||||
|
||||
index_hint:
|
||||
USE KEY opt_for_join '(' index_list ')'
|
||||
{ emit("INDEXHINT %d %d", $5, 010+$3); }
|
||||
{ sqlp_index_hint($5, 010+$3); }
|
||||
| IGNORE KEY opt_for_join '(' index_list ')'
|
||||
{ emit("INDEXHINT %d %d", $5, 020+$3); }
|
||||
{ sqlp_index_hint($5, 020+$3); }
|
||||
| FORCE KEY opt_for_join '(' index_list ')'
|
||||
{ emit("INDEXHINT %d %d", $5, 030+$3); }
|
||||
{ sqlp_index_hint($5, 030+$3); }
|
||||
| /* nil */
|
||||
;
|
||||
|
||||
@ -498,11 +498,11 @@ opt_for_join: FOR JOIN { $$ = 1; }
|
||||
| /* nil */ { $$ = 0; }
|
||||
;
|
||||
|
||||
index_list: NAME { emit("INDEX %s", $1); free($1); $$ = 1; }
|
||||
| index_list ',' NAME { emit("INDEX %s", $3); free($3); $$ = $1 + 1; }
|
||||
index_list: NAME { sqlp_index($1); free($1); $$ = 1; }
|
||||
| index_list ',' NAME { sqlp_index($3); free($3); $$ = $1 + 1; }
|
||||
;
|
||||
|
||||
table_subquery: '(' select_stmt ')' { emit("SUBQUERY"); }
|
||||
table_subquery: '(' select_stmt ')' { sqlp_subquery(); }
|
||||
;
|
||||
|
||||
/* statements: delete statement */
|
||||
@ -536,7 +536,7 @@ opt_dot_star: /* nil */ | '.' '*' ;
|
||||
delete_stmt: DELETE delete_opts
|
||||
FROM delete_list
|
||||
USING table_references opt_where
|
||||
{ emit("DELETEMULTI %d %d %d", $2, $4, $6); }
|
||||
{ sqlp_delete_multi($2, $4, $6); }
|
||||
;
|
||||
|
||||
/* statements: insert statement */
|
||||
@ -551,7 +551,7 @@ insert_stmt: INSERT insert_opts opt_into NAME
|
||||
;
|
||||
|
||||
opt_ondupupdate: /* nil */
|
||||
| ONDUPLICATE KEY UPDATE insert_asgn_list { emit("DUPUPDATE %d", $4); }
|
||||
| ONDUPLICATE KEY UPDATE insert_asgn_list { sqlp_ins_dup_update($4); }
|
||||
;
|
||||
|
||||
insert_opts: /* nil */ { $$ = 0; }
|
||||
@ -581,27 +581,27 @@ insert_vals:
|
||||
insert_stmt: INSERT insert_opts opt_into NAME
|
||||
SET insert_asgn_list
|
||||
opt_ondupupdate
|
||||
{ emit("INSERTASGN %d %d %s", $2, $6, $4); free($4) }
|
||||
{ sqlp_insert_assn($2, $6, $4); free($4) }
|
||||
;
|
||||
|
||||
insert_stmt: INSERT insert_opts opt_into NAME opt_col_names
|
||||
select_stmt
|
||||
opt_ondupupdate { emit("INSERTSELECT %d %s", $2, $4); free($4); }
|
||||
opt_ondupupdate { sqlp_insert_sel($2, $4); free($4); }
|
||||
;
|
||||
|
||||
insert_asgn_list:
|
||||
NAME COMPARISON expr
|
||||
{ if ($2 != 4) { lyyerror(@2,"bad insert assignment to %s", $1); YYERROR; }
|
||||
emit("ASSIGN %s", $1); free($1); $$ = 1; }
|
||||
sqlp_assign(NULL, $1); free($1); $$ = 1; }
|
||||
| NAME COMPARISON DEFAULT
|
||||
{ if ($2 != 4) { lyyerror(@2,"bad insert assignment to %s", $1); YYERROR; }
|
||||
emit("DEFAULT"); emit("ASSIGN %s", $1); free($1); $$ = 1; }
|
||||
sqlp_ins_default(); sqlp_assign(NULL, $1); free($1); $$ = 1; }
|
||||
| insert_asgn_list ',' NAME COMPARISON expr
|
||||
{ if ($4 != 4) { lyyerror(@4,"bad insert assignment to %s", $1); YYERROR; }
|
||||
emit("ASSIGN %s", $3); free($3); $$ = $1 + 1; }
|
||||
sqlp_assign(NULL, $3); free($3); $$ = $1 + 1; }
|
||||
| insert_asgn_list ',' NAME COMPARISON DEFAULT
|
||||
{ if ($4 != 4) { lyyerror(@4,"bad insert assignment to %s", $1); YYERROR; }
|
||||
emit("DEFAULT"); emit("ASSIGN %s", $3); free($3); $$ = $1 + 1; }
|
||||
sqlp_ins_default(); sqlp_assign(NULL, $3); free($3); $$ = $1 + 1; }
|
||||
;
|
||||
|
||||
/** replace just like insert **/
|
||||
@ -611,18 +611,18 @@ stmt: replace_stmt { sqlp_stmt(); }
|
||||
replace_stmt: REPLACE insert_opts opt_into NAME
|
||||
opt_col_names
|
||||
VALUES insert_vals_list
|
||||
opt_ondupupdate { emit("REPLACEVALS %d %d %s", $2, $7, $4); free($4) }
|
||||
opt_ondupupdate { sqlp_replace_vals($2, $7, $4); free($4) }
|
||||
;
|
||||
|
||||
replace_stmt: REPLACE insert_opts opt_into NAME
|
||||
SET insert_asgn_list
|
||||
opt_ondupupdate
|
||||
{ emit("REPLACEASGN %d %d %s", $2, $6, $4); free($4) }
|
||||
{ sqlp_replace_assn($2, $6, $4); free($4) }
|
||||
;
|
||||
|
||||
replace_stmt: REPLACE insert_opts opt_into NAME opt_col_names
|
||||
select_stmt
|
||||
opt_ondupupdate { emit("REPLACESELECT %d %s", $2, $4); free($4); }
|
||||
opt_ondupupdate { sqlp_replace_sel($2, $4); free($4); }
|
||||
;
|
||||
|
||||
/** update **/
|
||||
@ -633,7 +633,7 @@ update_stmt: UPDATE update_opts table_references
|
||||
SET update_asgn_list
|
||||
opt_where
|
||||
opt_orderby
|
||||
opt_limit { emit("UPDATE %d %d %d", $2, $3, $5); }
|
||||
opt_limit { sqlp_update($2, $3, $5); }
|
||||
;
|
||||
|
||||
update_opts: /* nil */ { $$ = 0; }
|
||||
@ -644,16 +644,16 @@ update_opts: /* nil */ { $$ = 0; }
|
||||
update_asgn_list:
|
||||
NAME COMPARISON expr
|
||||
{ if ($2 != 4) { lyyerror(@2,"bad update assignment to %s", $1); YYERROR; }
|
||||
emit("ASSIGN %s", $1); free($1); $$ = 1; }
|
||||
sqlp_assign(NULL, $1); free($1); $$ = 1; }
|
||||
| NAME '.' NAME COMPARISON expr
|
||||
{ if ($4 != 4) { lyyerror(@4,"bad update assignment to %s", $1); YYERROR; }
|
||||
emit("ASSIGN %s.%s", $1, $3); free($1); free($3); $$ = 1; }
|
||||
sqlp_assign($1, $3); free($1); free($3); $$ = 1; }
|
||||
| update_asgn_list ',' NAME COMPARISON expr
|
||||
{ if ($4 != 4) { lyyerror(@4,"bad update assignment to %s", $3); YYERROR; }
|
||||
emit("ASSIGN %s.%s", $3); free($3); $$ = $1 + 1; }
|
||||
sqlp_assign(NULL, $3); free($3); $$ = $1 + 1; }
|
||||
| update_asgn_list ',' NAME '.' NAME COMPARISON expr
|
||||
{ if ($6 != 4) { lyyerror(@6,"bad update assignment to %s.$s", $3, $5); YYERROR; }
|
||||
emit("ASSIGN %s.%s", $3, $5); free($3); free($5); $$ = 1; }
|
||||
sqlp_assign($3, $5); free($3); free($5); $$ = 1; }
|
||||
;
|
||||
|
||||
|
||||
@ -702,21 +702,21 @@ create_table_stmt: CREATE opt_temporary TABLE opt_if_not_exists NAME '.' NAME
|
||||
|
||||
create_table_stmt: CREATE opt_temporary TABLE opt_if_not_exists NAME
|
||||
'(' create_col_list ')'
|
||||
create_select_statement { emit("CREATESELECT %d %d %d %s", $2, $4, $7, $5); free($5); }
|
||||
create_select_statement { sqlp_create_tbl_sel($2, $4, $7, NULL, $5); free($5); }
|
||||
;
|
||||
|
||||
create_table_stmt: CREATE opt_temporary TABLE opt_if_not_exists NAME
|
||||
create_select_statement { emit("CREATESELECT %d %d 0 %s", $2, $4, $5); free($5); }
|
||||
create_select_statement { sqlp_create_tbl_sel($2, $4, 0, NULL, $5); free($5); }
|
||||
;
|
||||
|
||||
create_table_stmt: CREATE opt_temporary TABLE opt_if_not_exists NAME '.' NAME
|
||||
'(' create_col_list ')'
|
||||
create_select_statement { emit("CREATESELECT %d %d 0 %s.%s", $2, $4, $5, $7);
|
||||
create_select_statement { sqlp_create_tbl_sel($2, $4, 0, $5, $7);
|
||||
free($5); free($7); }
|
||||
;
|
||||
|
||||
create_table_stmt: CREATE opt_temporary TABLE opt_if_not_exists NAME '.' NAME
|
||||
create_select_statement { emit("CREATESELECT %d %d 0 %s.%s", $2, $4, $5, $7);
|
||||
create_select_statement { sqlp_create_tbl_sel($2, $4, 0, $5, $7);
|
||||
free($5); free($7); }
|
||||
;
|
||||
|
||||
@ -727,11 +727,11 @@ create_col_list: create_definition { $$ = 1; }
|
||||
create_definition: { sqlp_start_col(); } NAME data_type column_atts
|
||||
{ sqlp_def_col($3, $2); free($2); }
|
||||
|
||||
| PRIMARY KEY '(' column_list ')' { emit("PRIKEY %d", $4); }
|
||||
| KEY '(' column_list ')' { emit("KEY %d", $3); }
|
||||
| INDEX '(' column_list ')' { emit("KEY %d", $3); }
|
||||
| FULLTEXT INDEX '(' column_list ')' { emit("TEXTINDEX %d", $4); }
|
||||
| FULLTEXT KEY '(' column_list ')' { emit("TEXTINDEX %d", $4); }
|
||||
| PRIMARY KEY '(' column_list ')' { sqlp_col_key_pri($4); }
|
||||
| KEY '(' column_list ')' { sqlp_col_key($3); }
|
||||
| INDEX '(' column_list ')' { sqlp_col_key($3); }
|
||||
| FULLTEXT INDEX '(' column_list ')' { sqlp_col_key_textidx($4); }
|
||||
| FULLTEXT KEY '(' column_list ')' { sqlp_col_key_textidx($4); }
|
||||
;
|
||||
|
||||
column_atts: /* nil */ { $$ = 0; }
|
||||
|
Reference in New Issue
Block a user