8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 22:43:04 +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/utld_proto.h"
#include "../jrd/gds_proto.h"
#include "../common/classes/ClumpletWriter.h"
enum pp_vals {
PP_CREATE = 0,
@ -49,29 +50,10 @@ enum pp_vals {
};
const int MAX_TOKEN_SIZE = 1024;
// 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 void generate_error(ISC_STATUS*, const Firebird::string&, SSHORT, SSHORT);
static SSHORT get_next_token(const SCHAR**, const SCHAR*, Firebird::string&);
static SSHORT get_token(ISC_STATUS*, SSHORT, bool, const SCHAR**,
const SCHAR* const, SCHAR*, USHORT*);
const SCHAR* const, Firebird::string&);
struct pp_table {
SCHAR symbol[10];
@ -131,234 +113,179 @@ bool PREPARSE_execute(
bool* stmt_eaten,
USHORT dialect)
{
char* const token = (SCHAR *) gds__alloc((SLONG) MAX_TOKEN_SIZE + 1);
// FREE: by return(s) in this procedure
if (!token) { // NOMEM:
user_status[0] = isc_arg_gds;
user_status[1] = isc_virmemexh;
user_status[2] = isc_arg_end;
return false;
}
// no use creating separate pool for a couple of strings
Firebird::ContextPoolHolder context(getDefaultMemoryPool());
if (!stmt_length)
stmt_length = strlen(stmt);
const char* const stmt_end = stmt + stmt_length;
USHORT token_length;
if (get_token(user_status, SYMBOL, false, &stmt, stmt_end, token,
&token_length) ||
token_length != pp_symbols[PP_CREATE].length ||
strcmp(token, pp_symbols[PP_CREATE].symbol))
try
{
gds__free(token);
return false;
}
if (!stmt_length)
stmt_length = strlen(stmt);
const char* const stmt_end = stmt + stmt_length;
Firebird::string 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_SCHEMA].length) ||
(strcmp(token, pp_symbols[PP_DATABASE].symbol) &&
strcmp(token, pp_symbols[PP_SCHEMA].symbol)))
{
gds__free(token);
return false;
}
if (get_token(user_status, STRING, false, &stmt, stmt_end, token,
&token_length))
{
gds__free(token);
return true;
}
TEXT file_name[MAX_TOKEN_SIZE + 1];
strcpy(file_name, token);
*stmt_eaten = false;
char* const dpb_array = (SCHAR*) gds__alloc((SLONG) 2 * MAX_TOKEN_SIZE + 25);
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);
stuff_dpb(dpb, isc_dpb_overwrite);
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;
bool matched;
do {
const SSHORT result = get_next_token(&stmt, stmt_end, token, &token_length);
if (result == NO_MORE_TOKENS) {
*stmt_eaten = true;
break;
if (get_token(user_status, SYMBOL, false, &stmt, stmt_end, token) ||
token.length() != pp_symbols[PP_CREATE].length ||
token != pp_symbols[PP_CREATE].symbol)
{
return false;
}
else if (result < 0)
break;
matched = false;
for (int i = 3; pp_symbols[i].length && !matched; i++) {
if (token_length == pp_symbols[i].length &&
!strcmp(token, pp_symbols[i].symbol))
{
bool get_out = false;
const SCHAR* ch;
SSHORT l;
// CVC: What's strange, this routine doesn't check token_length
// but it proceeds blindly, trying to exhaust the token itself.
if (get_token(user_status, SYMBOL, false, &stmt, stmt_end, token) ||
(token.length() != pp_symbols[PP_DATABASE].length &&
token.length() != pp_symbols[PP_SCHEMA].length) ||
(token != pp_symbols[PP_DATABASE].symbol &&
token != pp_symbols[PP_SCHEMA].symbol))
{
return false;
}
switch (pp_symbols[i].code) {
case PP_PAGE_SIZE:
case PP_PAGESIZE:
if (get_token(user_status, '=', true, &stmt, stmt_end,
token, &token_length) ||
get_token(user_status, NUMERIC, false, &stmt,
stmt_end, token, &token_length))
{
get_out = true;
if (get_token(user_status, STRING, false, &stmt, stmt_end, token))
{
return true;
}
Firebird::PathName file_name(token.ToPathName());
*stmt_eaten = false;
Firebird::ClumpletWriter dpb(true, 0x1000, isc_dpb_version1);
dpb.insertString(isc_dpb_overwrite, "\0", 1);
dpb.insertInt(isc_dpb_sql_dialect, dialect);
SLONG page_size = 0;
bool matched;
do {
const SSHORT result = get_next_token(&stmt, stmt_end, token);
if (result == NO_MORE_TOKENS) {
*stmt_eaten = true;
break;
}
else if (result < 0)
break;
matched = false;
for (int i = 3; pp_symbols[i].length && !matched; i++) {
if (token.length() == pp_symbols[i].length &&
token == pp_symbols[i].symbol)
{
bool get_out = false;
// CVC: What's strange, this routine doesn't check token.length()
// but it proceeds blindly, trying to exhaust the token itself.
switch (pp_symbols[i].code) {
case PP_PAGE_SIZE:
case PP_PAGESIZE:
if (get_token(user_status, '=', true, &stmt, stmt_end, token) ||
get_token(user_status, NUMERIC, false, &stmt, stmt_end, token))
{
get_out = true;
break;
}
page_size = atol(token.c_str());
dpb.insertInt(isc_dpb_page_size, page_size);
matched = true;
break;
}
page_size = atol(token);
stuff_dpb(dpb, isc_dpb_page_size);
stuff_dpb(dpb, 4);
stuff_dpb_long(dpb, page_size);
matched = true;
break;
case PP_USER:
if (get_token(user_status, STRING, false, &stmt, stmt_end,
token, &token_length))
{
get_out = true;
case PP_USER:
if (get_token(user_status, STRING, false, &stmt, stmt_end, token))
{
get_out = true;
break;
}
dpb.insertString(isc_dpb_user_name, token);
matched = true;
break;
case PP_PASSWORD:
if (get_token(user_status, STRING, false, &stmt, stmt_end, token))
{
get_out = true;
break;
}
dpb.insertString(isc_dpb_password, token);
matched = true;
break;
case PP_SET:
if (get_token(user_status, SYMBOL, false, &stmt, stmt_end, token) ||
token.length() != pp_symbols[PP_NAMES].length ||
token != pp_symbols[PP_NAMES].symbol ||
get_token(user_status, STRING, false, &stmt, stmt_end, token))
{
get_out = true;
break;
}
dpb.insertString(isc_dpb_lc_ctype, token);
matched = true;
break;
case PP_LENGTH:
// Skip a token for value
if (get_token(user_status, '=', true, &stmt, stmt_end, token) ||
get_token(user_status, NUMERIC, false, &stmt, stmt_end, token))
{
get_out = true;
break;
}
matched = true;
break;
case PP_PAGE:
case PP_PAGES:
matched = true;
break;
}
stuff_dpb(dpb, isc_dpb_user_name);
l = token_length;
stuff_dpb(dpb, l);
ch = token;
while (*ch)
stuff_dpb(dpb, *ch++);
matched = true;
break;
case PP_PASSWORD:
if (get_token(user_status, STRING, false, &stmt, stmt_end,
token, &token_length))
{
get_out = true;
break;
if (get_out) {
return true;
}
stuff_dpb(dpb, isc_dpb_password);
l = token_length;
stuff_dpb(dpb, l);
ch = token;
while (*ch)
stuff_dpb(dpb, *ch++);
matched = true;
break;
case PP_SET:
if (get_token(user_status, SYMBOL, false, &stmt, stmt_end,
token, &token_length) ||
token_length != pp_symbols[PP_NAMES].length ||
strcmp(token, pp_symbols[PP_NAMES].symbol) ||
get_token(user_status, STRING, false, &stmt, stmt_end,
token, &token_length))
{
get_out = true;
break;
}
stuff_dpb(dpb, isc_dpb_lc_ctype);
l = token_length;
stuff_dpb(dpb, l);
ch = token;
while (*ch)
stuff_dpb(dpb, *ch++);
matched = true;
break;
case PP_LENGTH:
// Skip a token for value
if (get_token(user_status, '=', true, &stmt, stmt_end,
token, &token_length) ||
get_token(user_status, NUMERIC, false, &stmt,
stmt_end, token, &token_length))
{
get_out = true;
break;
}
matched = true;
break;
case PP_PAGE:
case PP_PAGES:
matched = true;
break;
}
if (get_out) {
gds__free(dpb_array);
gds__free(token);
return true;
}
}
}
} while (matched);
const USHORT dpb_len = dpb - dpb_array;
} while (matched);
// This code is because 3.3 server does not recognize isc_dpb_overwrite.
FB_API_HANDLE temp_db_handle = 0;
if (!isc_attach_database(user_status, 0, file_name, &temp_db_handle,
dpb_len, dpb_array) ||
user_status[1] != isc_io_error)
FB_API_HANDLE temp_db_handle = 0;
if (!isc_attach_database(user_status, 0, file_name.c_str(),
&temp_db_handle, dpb.getBufferLength(),
reinterpret_cast<const ISC_SCHAR*>(dpb.getBuffer())) ||
user_status[1] != isc_io_error)
{
if (!user_status[1]) {
// Swallow status from detach.
ISC_STATUS_ARRAY temp_status;
isc_detach_database(temp_status, &temp_db_handle);
}
if (!user_status[1] || user_status[1] == isc_bad_db_format) {
user_status[0] = isc_arg_gds;
user_status[1] = isc_io_error;
user_status[2] = isc_arg_string;
user_status[3] = (ISC_STATUS) "open";
user_status[4] = isc_arg_string;
user_status[5] = (ISC_STATUS) file_name.c_str();
user_status[6] = isc_arg_gds;
user_status[7] = isc_db_or_file_exists;
user_status[8] = isc_arg_end;
UTLD_save_status_strings(user_status);
}
return true;
}
isc_create_database(user_status, 0, file_name.c_str(),
(db_handle), dpb.getBufferLength(),
reinterpret_cast<const ISC_SCHAR*>(dpb.getBuffer()),
0);
}
catch(const std::exception& ex)
{
if (!user_status[1]) {
// Swallow status from detach.
ISC_STATUS_ARRAY temp_status;
isc_detach_database(temp_status, &temp_db_handle);
}
if (!user_status[1] || user_status[1] == isc_bad_db_format) {
user_status[0] = isc_arg_gds;
user_status[1] = isc_io_error;
user_status[2] = isc_arg_string;
user_status[3] = (ISC_STATUS) "open";
user_status[4] = isc_arg_string;
user_status[5] = (ISC_STATUS) file_name;
user_status[6] = isc_arg_gds;
user_status[7] = isc_db_or_file_exists;
user_status[8] = isc_arg_end;
UTLD_save_status_strings(user_status);
}
if (dpb_array)
gds__free(dpb_array);
gds__free(token);
Firebird::stuff_exception(user_status, ex);
return true;
}
isc_create_database(user_status, 0, file_name,
(db_handle), dpb_len,
dpb_array, 0);
if (dpb_array)
gds__free(dpb_array);
gds__free(token);
return true;
}
@ -377,9 +304,9 @@ bool PREPARSE_execute(
**/
static void generate_error(
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[1] = isc_sqlerr;
@ -396,19 +323,17 @@ static void generate_error(
case UNEXPECTED_TOKEN:
case TOKEN_TOO_LONG:
if (result) {
err_string[0] = (TEXT) result;
strcpy(err_string + 1, token);
const size_t length = strlen(token);
err_string[length + 1] = (TEXT) result;
err_string[length + 2] = '\0';
err_string.assign(1, (TEXT) result);
err_string += token;
err_string += (TEXT) result;
}
else
strcpy(err_string, token);
err_string = token;
user_status[5] = isc_token_err;
user_status[6] = isc_arg_gds;
user_status[7] = isc_random;
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;
UTLD_save_status_strings(user_status);
break;
@ -425,17 +350,16 @@ static void generate_error(
@param stmt
@param stmt_end
@param token
@param token_length
**/
static SSHORT get_next_token(
const SCHAR** stmt,
const SCHAR* stmt_end,
SCHAR* token, USHORT* token_length)
Firebird::string& token)
{
UCHAR c, char_class;
*token_length = 0;
token.erase();
const SCHAR* s = *stmt;
for (;;) {
@ -467,12 +391,8 @@ static SSHORT get_next_token(
/* In here we handle only 4 cases, STRING, INTEGER, arbitrary
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) {
for (; p < token_end; p++) {
for (;;) {
if (s >= stmt_end)
return UNEXPECTED_END_OF_COMMAND;
@ -480,18 +400,9 @@ static SSHORT get_next_token(
if ((*s == c) && ((++s == stmt_end) || (*s != c)))
break;
*p = *s++;
token += *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;
}
@ -501,36 +412,19 @@ static SSHORT get_next_token(
for (; s < stmt_end && (classes[c = *s] & CHR_DIGIT); ++s); // empty body
const ptrdiff_t length = (s - start_of_token);
*stmt = s;
if (length > MAX_TOKEN_SIZE) {
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;
token.assign(start_of_token, length);
return NUMERIC;
}
// Is is a symbol
if (char_class & CHR_LETTER) {
*p++ = UPPER(c);
for (; s < stmt_end && (classes[static_cast<UCHAR>(*s)] & CHR_IDENT) && p < token_end; s++) {
*p++ = UPPER(*s);
token += UPPER(c);
for (; s < stmt_end && (classes[static_cast<UCHAR>(*s)] & CHR_IDENT); s++) {
token += UPPER(*s);
}
// what happend to token size check. It went to hell
*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;
}
@ -554,7 +448,6 @@ static SSHORT get_next_token(
@param stmt
@param stmt_end
@param token
@param token_length
**/
static SSHORT get_token(ISC_STATUS* status,
@ -562,11 +455,10 @@ static SSHORT get_token(ISC_STATUS* status,
bool optional,
const SCHAR** stmt,
const SCHAR* const stmt_end,
SCHAR* token,
USHORT* token_length)
Firebird::string& token)
{
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) {
case NO_MORE_TOKENS: