8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-24 06:03:02 +01:00

use new classes to preparse 'create database' statement

This commit is contained in:
alexpeshkoff 2004-12-05 11:57:25 +00:00
parent 41b2712dc2
commit 637e5ed95a

View File

@ -32,6 +32,7 @@
#include "../dsql/prepa_proto.h" #include "../dsql/prepa_proto.h"
#include "../dsql/utld_proto.h" #include "../dsql/utld_proto.h"
#include "../jrd/gds_proto.h" #include "../jrd/gds_proto.h"
#include "../common/classes/ClumpletWriter.h"
enum pp_vals { enum pp_vals {
PP_CREATE = 0, PP_CREATE = 0,
@ -49,29 +50,10 @@ enum pp_vals {
}; };
const int MAX_TOKEN_SIZE = 1024; static void generate_error(ISC_STATUS*, const Firebird::string&, SSHORT, SSHORT);
static SSHORT get_next_token(const SCHAR**, const SCHAR*, Firebird::string&);
// use stuff_dpb in place of STUFF to avoid confusion with BLR STUFF
// macro defined in dsql.h
static inline void stuff_dpb(SCHAR*& dpb, const SCHAR blr)
{
*dpb++ = blr;
}
static inline void stuff_dpb_long(SCHAR*& dpb, const SLONG blr)
{
stuff_dpb(dpb, blr);
stuff_dpb(dpb, blr >> 8);
stuff_dpb(dpb, blr >> 16);
stuff_dpb(dpb, blr >> 24);
}
static void generate_error(ISC_STATUS*, const SCHAR*, SSHORT, SSHORT);
static SSHORT get_next_token(const SCHAR**, const SCHAR*, SCHAR*, USHORT*);
static SSHORT get_token(ISC_STATUS*, SSHORT, bool, const SCHAR**, static SSHORT get_token(ISC_STATUS*, SSHORT, bool, const SCHAR**,
const SCHAR* const, SCHAR*, USHORT*); const SCHAR* const, Firebird::string&);
struct pp_table { struct pp_table {
SCHAR symbol[10]; SCHAR symbol[10];
@ -131,73 +113,48 @@ bool PREPARSE_execute(
bool* stmt_eaten, bool* stmt_eaten,
USHORT dialect) USHORT dialect)
{ {
char* const token = (SCHAR *) gds__alloc((SLONG) MAX_TOKEN_SIZE + 1); // no use creating separate pool for a couple of strings
// FREE: by return(s) in this procedure Firebird::ContextPoolHolder context(getDefaultMemoryPool());
if (!token) { // NOMEM:
user_status[0] = isc_arg_gds;
user_status[1] = isc_virmemexh;
user_status[2] = isc_arg_end;
return false;
}
try
{
if (!stmt_length) if (!stmt_length)
stmt_length = strlen(stmt); stmt_length = strlen(stmt);
const char* const stmt_end = stmt + stmt_length; const char* const stmt_end = stmt + stmt_length;
Firebird::string token;
USHORT token_length; if (get_token(user_status, SYMBOL, false, &stmt, stmt_end, token) ||
if (get_token(user_status, SYMBOL, false, &stmt, stmt_end, token, token.length() != pp_symbols[PP_CREATE].length ||
&token_length) || token != pp_symbols[PP_CREATE].symbol)
token_length != pp_symbols[PP_CREATE].length ||
strcmp(token, pp_symbols[PP_CREATE].symbol))
{ {
gds__free(token);
return false; return false;
} }
if (get_token(user_status, SYMBOL, false, &stmt, stmt_end, token, if (get_token(user_status, SYMBOL, false, &stmt, stmt_end, token) ||
&token_length) || (token.length() != pp_symbols[PP_DATABASE].length &&
(token_length != pp_symbols[PP_DATABASE].length && token.length() != pp_symbols[PP_SCHEMA].length) ||
token_length != pp_symbols[PP_SCHEMA].length) || (token != pp_symbols[PP_DATABASE].symbol &&
(strcmp(token, pp_symbols[PP_DATABASE].symbol) && token != pp_symbols[PP_SCHEMA].symbol))
strcmp(token, pp_symbols[PP_SCHEMA].symbol)))
{ {
gds__free(token);
return false; return false;
} }
if (get_token(user_status, STRING, false, &stmt, stmt_end, token, if (get_token(user_status, STRING, false, &stmt, stmt_end, token))
&token_length))
{ {
gds__free(token);
return true; return true;
} }
TEXT file_name[MAX_TOKEN_SIZE + 1]; Firebird::PathName file_name(token.ToPathName());
strcpy(file_name, token);
*stmt_eaten = false; *stmt_eaten = false;
char* const dpb_array = (SCHAR*) gds__alloc((SLONG) 2 * MAX_TOKEN_SIZE + 25); Firebird::ClumpletWriter dpb(true, 0x1000, isc_dpb_version1);
char* dpb = dpb_array;
// FREE: by following return(s) in this procedure
if (!dpb_array) { // NOMEM:
user_status[0] = isc_arg_gds;
user_status[1] = isc_virmemexh;
user_status[2] = isc_arg_end;
gds__free(token);
return true;
}
stuff_dpb(dpb, isc_dpb_version1); dpb.insertString(isc_dpb_overwrite, "\0", 1);
stuff_dpb(dpb, isc_dpb_overwrite); dpb.insertInt(isc_dpb_sql_dialect, dialect);
stuff_dpb(dpb, 1);
stuff_dpb(dpb, 0);
stuff_dpb(dpb, isc_dpb_sql_dialect);
stuff_dpb(dpb, 4);
stuff_dpb_long(dpb, dialect);
SLONG page_size = 0; SLONG page_size = 0;
bool matched; bool matched;
do { do {
const SSHORT result = get_next_token(&stmt, stmt_end, token, &token_length); const SSHORT result = get_next_token(&stmt, stmt_end, token);
if (result == NO_MORE_TOKENS) { if (result == NO_MORE_TOKENS) {
*stmt_eaten = true; *stmt_eaten = true;
break; break;
@ -207,95 +164,68 @@ bool PREPARSE_execute(
matched = false; matched = false;
for (int i = 3; pp_symbols[i].length && !matched; i++) { for (int i = 3; pp_symbols[i].length && !matched; i++) {
if (token_length == pp_symbols[i].length && if (token.length() == pp_symbols[i].length &&
!strcmp(token, pp_symbols[i].symbol)) token == pp_symbols[i].symbol)
{ {
bool get_out = false; bool get_out = false;
const SCHAR* ch; // CVC: What's strange, this routine doesn't check token.length()
SSHORT l;
// CVC: What's strange, this routine doesn't check token_length
// but it proceeds blindly, trying to exhaust the token itself. // but it proceeds blindly, trying to exhaust the token itself.
switch (pp_symbols[i].code) { switch (pp_symbols[i].code) {
case PP_PAGE_SIZE: case PP_PAGE_SIZE:
case PP_PAGESIZE: case PP_PAGESIZE:
if (get_token(user_status, '=', true, &stmt, stmt_end, if (get_token(user_status, '=', true, &stmt, stmt_end, token) ||
token, &token_length) || get_token(user_status, NUMERIC, false, &stmt, stmt_end, token))
get_token(user_status, NUMERIC, false, &stmt,
stmt_end, token, &token_length))
{ {
get_out = true; get_out = true;
break; break;
} }
page_size = atol(token); page_size = atol(token.c_str());
stuff_dpb(dpb, isc_dpb_page_size); dpb.insertInt(isc_dpb_page_size, page_size);
stuff_dpb(dpb, 4);
stuff_dpb_long(dpb, page_size);
matched = true; matched = true;
break; break;
case PP_USER: case PP_USER:
if (get_token(user_status, STRING, false, &stmt, stmt_end, if (get_token(user_status, STRING, false, &stmt, stmt_end, token))
token, &token_length))
{ {
get_out = true; get_out = true;
break; break;
} }
stuff_dpb(dpb, isc_dpb_user_name); dpb.insertString(isc_dpb_user_name, token);
l = token_length;
stuff_dpb(dpb, l);
ch = token;
while (*ch)
stuff_dpb(dpb, *ch++);
matched = true; matched = true;
break; break;
case PP_PASSWORD: case PP_PASSWORD:
if (get_token(user_status, STRING, false, &stmt, stmt_end, if (get_token(user_status, STRING, false, &stmt, stmt_end, token))
token, &token_length))
{ {
get_out = true; get_out = true;
break; break;
} }
stuff_dpb(dpb, isc_dpb_password); dpb.insertString(isc_dpb_password, token);
l = token_length;
stuff_dpb(dpb, l);
ch = token;
while (*ch)
stuff_dpb(dpb, *ch++);
matched = true; matched = true;
break; break;
case PP_SET: case PP_SET:
if (get_token(user_status, SYMBOL, false, &stmt, stmt_end, if (get_token(user_status, SYMBOL, false, &stmt, stmt_end, token) ||
token, &token_length) || token.length() != pp_symbols[PP_NAMES].length ||
token_length != pp_symbols[PP_NAMES].length || token != pp_symbols[PP_NAMES].symbol ||
strcmp(token, pp_symbols[PP_NAMES].symbol) || get_token(user_status, STRING, false, &stmt, stmt_end, token))
get_token(user_status, STRING, false, &stmt, stmt_end,
token, &token_length))
{ {
get_out = true; get_out = true;
break; break;
} }
stuff_dpb(dpb, isc_dpb_lc_ctype); dpb.insertString(isc_dpb_lc_ctype, token);
l = token_length;
stuff_dpb(dpb, l);
ch = token;
while (*ch)
stuff_dpb(dpb, *ch++);
matched = true; matched = true;
break; break;
case PP_LENGTH: case PP_LENGTH:
// Skip a token for value // Skip a token for value
if (get_token(user_status, '=', true, &stmt, stmt_end, if (get_token(user_status, '=', true, &stmt, stmt_end, token) ||
token, &token_length) || get_token(user_status, NUMERIC, false, &stmt, stmt_end, token))
get_token(user_status, NUMERIC, false, &stmt,
stmt_end, token, &token_length))
{ {
get_out = true; get_out = true;
break; break;
@ -311,8 +241,6 @@ bool PREPARSE_execute(
} }
if (get_out) { if (get_out) {
gds__free(dpb_array);
gds__free(token);
return true; return true;
} }
} }
@ -320,12 +248,11 @@ bool PREPARSE_execute(
} while (matched); } while (matched);
const USHORT dpb_len = dpb - dpb_array;
// This code is because 3.3 server does not recognize isc_dpb_overwrite. // This code is because 3.3 server does not recognize isc_dpb_overwrite.
FB_API_HANDLE temp_db_handle = 0; FB_API_HANDLE temp_db_handle = 0;
if (!isc_attach_database(user_status, 0, file_name, &temp_db_handle, if (!isc_attach_database(user_status, 0, file_name.c_str(),
dpb_len, dpb_array) || &temp_db_handle, dpb.getBufferLength(),
reinterpret_cast<const ISC_SCHAR*>(dpb.getBuffer())) ||
user_status[1] != isc_io_error) user_status[1] != isc_io_error)
{ {
if (!user_status[1]) { if (!user_status[1]) {
@ -339,25 +266,25 @@ bool PREPARSE_execute(
user_status[2] = isc_arg_string; user_status[2] = isc_arg_string;
user_status[3] = (ISC_STATUS) "open"; user_status[3] = (ISC_STATUS) "open";
user_status[4] = isc_arg_string; user_status[4] = isc_arg_string;
user_status[5] = (ISC_STATUS) file_name; user_status[5] = (ISC_STATUS) file_name.c_str();
user_status[6] = isc_arg_gds; user_status[6] = isc_arg_gds;
user_status[7] = isc_db_or_file_exists; user_status[7] = isc_db_or_file_exists;
user_status[8] = isc_arg_end; user_status[8] = isc_arg_end;
UTLD_save_status_strings(user_status); UTLD_save_status_strings(user_status);
} }
if (dpb_array)
gds__free(dpb_array);
gds__free(token);
return true; return true;
} }
isc_create_database(user_status, 0, file_name, isc_create_database(user_status, 0, file_name.c_str(),
(db_handle), dpb_len, (db_handle), dpb.getBufferLength(),
dpb_array, 0); reinterpret_cast<const ISC_SCHAR*>(dpb.getBuffer()),
0);
if (dpb_array) }
gds__free(dpb_array); catch(const std::exception& ex)
gds__free(token); {
Firebird::stuff_exception(user_status, ex);
return true;
}
return true; return true;
} }
@ -377,9 +304,9 @@ bool PREPARSE_execute(
**/ **/
static void generate_error( static void generate_error(
ISC_STATUS* user_status, ISC_STATUS* user_status,
const SCHAR* token, SSHORT error, SSHORT result) const Firebird::string& token, SSHORT error, SSHORT result)
{ {
TEXT err_string[MAX_TOKEN_SIZE + 3]; Firebird::string err_string;
user_status[0] = isc_arg_gds; user_status[0] = isc_arg_gds;
user_status[1] = isc_sqlerr; user_status[1] = isc_sqlerr;
@ -396,19 +323,17 @@ static void generate_error(
case UNEXPECTED_TOKEN: case UNEXPECTED_TOKEN:
case TOKEN_TOO_LONG: case TOKEN_TOO_LONG:
if (result) { if (result) {
err_string[0] = (TEXT) result; err_string.assign(1, (TEXT) result);
strcpy(err_string + 1, token); err_string += token;
const size_t length = strlen(token); err_string += (TEXT) result;
err_string[length + 1] = (TEXT) result;
err_string[length + 2] = '\0';
} }
else else
strcpy(err_string, token); err_string = token;
user_status[5] = isc_token_err; user_status[5] = isc_token_err;
user_status[6] = isc_arg_gds; user_status[6] = isc_arg_gds;
user_status[7] = isc_random; user_status[7] = isc_random;
user_status[8] = isc_arg_string; user_status[8] = isc_arg_string;
user_status[9] = (ISC_STATUS) err_string; user_status[9] = (ISC_STATUS)(err_string.c_str());
user_status[10] = isc_arg_end; user_status[10] = isc_arg_end;
UTLD_save_status_strings(user_status); UTLD_save_status_strings(user_status);
break; break;
@ -425,17 +350,16 @@ static void generate_error(
@param stmt @param stmt
@param stmt_end @param stmt_end
@param token @param token
@param token_length
**/ **/
static SSHORT get_next_token( static SSHORT get_next_token(
const SCHAR** stmt, const SCHAR** stmt,
const SCHAR* stmt_end, const SCHAR* stmt_end,
SCHAR* token, USHORT* token_length) Firebird::string& token)
{ {
UCHAR c, char_class; UCHAR c, char_class;
*token_length = 0; token.erase();
const SCHAR* s = *stmt; const SCHAR* s = *stmt;
for (;;) { for (;;) {
@ -467,12 +391,8 @@ static SSHORT get_next_token(
/* In here we handle only 4 cases, STRING, INTEGER, arbitrary /* In here we handle only 4 cases, STRING, INTEGER, arbitrary
SYMBOL and single character punctuation. */ SYMBOL and single character punctuation. */
// token can be up to MAX_TOKEN_SIZE and 1 is for null termination
SCHAR* p = token;
const char* const token_end = token + MAX_TOKEN_SIZE + 1;
if (char_class & CHR_QUOTE) { if (char_class & CHR_QUOTE) {
for (; p < token_end; p++) { for (;;) {
if (s >= stmt_end) if (s >= stmt_end)
return UNEXPECTED_END_OF_COMMAND; return UNEXPECTED_END_OF_COMMAND;
@ -480,18 +400,9 @@ static SSHORT get_next_token(
if ((*s == c) && ((++s == stmt_end) || (*s != c))) if ((*s == c) && ((++s == stmt_end) || (*s != c)))
break; break;
*p = *s++; token += *s++;
} }
*stmt = s; *stmt = s;
if (p >= token_end) {
// '=' used as then there is no place for null termination
*token_length = MAX_TOKEN_SIZE;
token[MAX_TOKEN_SIZE] = '\0';
return TOKEN_TOO_LONG;
}
*token_length = (s - start_of_token) - 2;
*p = '\0';
return STRING; return STRING;
} }
@ -501,36 +412,19 @@ static SSHORT get_next_token(
for (; s < stmt_end && (classes[c = *s] & CHR_DIGIT); ++s); // empty body for (; s < stmt_end && (classes[c = *s] & CHR_DIGIT); ++s); // empty body
const ptrdiff_t length = (s - start_of_token); const ptrdiff_t length = (s - start_of_token);
*stmt = s; *stmt = s;
if (length > MAX_TOKEN_SIZE) { token.assign(start_of_token, length);
memcpy(token, start_of_token, MAX_TOKEN_SIZE);
token[MAX_TOKEN_SIZE] = '\0';
*token_length = MAX_TOKEN_SIZE;
return TOKEN_TOO_LONG;
}
memcpy(token, start_of_token, length);
token[length] = '\0';
*token_length = length;
return NUMERIC; return NUMERIC;
} }
// Is is a symbol // Is is a symbol
if (char_class & CHR_LETTER) { if (char_class & CHR_LETTER) {
*p++ = UPPER(c); token += UPPER(c);
for (; s < stmt_end && (classes[static_cast<UCHAR>(*s)] & CHR_IDENT) && p < token_end; s++) { for (; s < stmt_end && (classes[static_cast<UCHAR>(*s)] & CHR_IDENT); s++) {
*p++ = UPPER(*s); token += UPPER(*s);
} }
// what happend to token size check. It went to hell
*stmt = s; *stmt = s;
if (p >= token_end) {
*token_length = MAX_TOKEN_SIZE;
token[MAX_TOKEN_SIZE] = '\0';
return TOKEN_TOO_LONG;
}
*token_length = s - start_of_token;
*p = 0;
return SYMBOL; return SYMBOL;
} }
@ -554,7 +448,6 @@ static SSHORT get_next_token(
@param stmt @param stmt
@param stmt_end @param stmt_end
@param token @param token
@param token_length
**/ **/
static SSHORT get_token(ISC_STATUS* status, static SSHORT get_token(ISC_STATUS* status,
@ -562,11 +455,10 @@ static SSHORT get_token(ISC_STATUS* status,
bool optional, bool optional,
const SCHAR** stmt, const SCHAR** stmt,
const SCHAR* const stmt_end, const SCHAR* const stmt_end,
SCHAR* token, Firebird::string& token)
USHORT* token_length)
{ {
const SCHAR* temp_stmt = *stmt; const SCHAR* temp_stmt = *stmt;
const SSHORT result = get_next_token(&temp_stmt, stmt_end, token, token_length); const SSHORT result = get_next_token(&temp_stmt, stmt_end, token);
switch (result) { switch (result) {
case NO_MORE_TOKENS: case NO_MORE_TOKENS: