diff --git a/sql/src/createdatabase.cpp b/sql/src/createdatabase.cpp index c8e58ae..5d6011b 100644 --- a/sql/src/createdatabase.cpp +++ b/sql/src/createdatabase.cpp @@ -573,7 +573,7 @@ RCODE SQLStatement::processCreateDatabase( void) for (;;) { - if (f_stricmp( szToken, "data_dir") == 0) + if (f_stricmp( szToken, SFLM_DATA_DIR_STR) == 0) { if (RC_BAD( rc = getUTF8String( TRUE, TRUE, (FLMBYTE *)szDataDirName, sizeof( szDataDirName), @@ -582,7 +582,7 @@ RCODE SQLStatement::processCreateDatabase( void) goto Exit; } } - else if (f_stricmp( szToken, "rfl_dir") == 0) + else if (f_stricmp( szToken, SFLM_RFL_DIR_STR) == 0) { if (RC_BAD( rc = getUTF8String( TRUE, TRUE, (FLMBYTE *)szRflDirName, sizeof( szRflDirName), @@ -591,7 +591,7 @@ RCODE SQLStatement::processCreateDatabase( void) goto Exit; } } - else if (f_stricmp( szToken, "block_size") == 0) + else if (f_stricmp( szToken, SFLM_BLOCK_SIZE_STR) == 0) { if (RC_BAD( rc = getUINT( TRUE, &createOpts.uiBlockSize))) { @@ -608,35 +608,35 @@ RCODE SQLStatement::processCreateDatabase( void) goto Exit; } } - else if (f_stricmp( szToken, "min_rfl_size") == 0) + else if (f_stricmp( szToken, SFLM_MIN_RFL_SIZE_STR) == 0) { if (RC_BAD( rc = getUINT( TRUE, &createOpts.uiMinRflFileSize))) { goto Exit; } } - else if (f_stricmp( szToken, "max_rfl_size") == 0) + else if (f_stricmp( szToken, SFLM_MAX_RFL_SIZE_STR) == 0) { if (RC_BAD( rc = getUINT( TRUE, &createOpts.uiMaxRflFileSize))) { goto Exit; } } - else if (f_stricmp( szToken, "keep_rfl") == 0) + else if (f_stricmp( szToken, SFLM_KEEP_RFL_STR) == 0) { if (RC_BAD( rc = getBool( TRUE, &createOpts.bKeepRflFiles))) { goto Exit; } } - else if (f_stricmp( szToken, "log_aborted_trans") == 0) + else if (f_stricmp( szToken, SFLM_LOG_ABORTED_TRANS_STR) == 0) { if (RC_BAD( rc = getBool( TRUE, &createOpts.bLogAbortedTransToRfl))) { goto Exit; } } - else if (f_stricmp( szToken, "language") == 0) + else if (f_stricmp( szToken, SFLM_LANGUAGE_STR) == 0) { if (RC_BAD( rc = getUTF8String( TRUE, TRUE, (FLMBYTE *)szLanguage, sizeof( szLanguage), diff --git a/sql/src/createindex.cpp b/sql/src/createindex.cpp index 537e282..6651309 100644 --- a/sql/src/createindex.cpp +++ b/sql/src/createindex.cpp @@ -580,6 +580,19 @@ RCODE SQLStatement::processCreateIndex( goto Exit; } + // See if too many columns have been specified. + + if (uiNumIxColumns == MAX_INDEX_COLUMNS) + { + setErrInfo( m_uiCurrLineNum, + uiTokenLineOffset, + SQL_ERR_TOO_MANY_INDEX_COLUMNS, + m_uiCurrLineFilePos, + m_uiCurrLineBytes); + rc = RC_SET( NE_SFLM_INVALID_SQL); + goto Exit; + } + // Allocate an index column def structure if (RC_BAD( rc = m_tmpPool.poolAlloc( sizeof( F_INDEX_COL_DEF), @@ -841,7 +854,7 @@ Invalid_Ix_Option: } } - if (f_stricmp( szToken, "offline") == 0) + if (f_stricmp( szToken, SFLM_INDEX_SUSPENDED_STR) == 0) { // Ignore offline option if suspended was specified. @@ -851,16 +864,16 @@ Invalid_Ix_Option: uiFlags |= IXD_OFFLINE; } } - else if (f_stricmp( szToken, "suspended") == 0) + else if (f_stricmp( szToken, SFLM_INDEX_SUSPENDED_STR) == 0) { uiFlags &= (~(IXD_OFFLINE)); uiFlags |= IXD_SUSPENDED; } - else if (f_stricmp( szToken, "abspos") == 0) + else if (f_stricmp( szToken, SFLM_ABS_POS_OPTION_STR) == 0) { uiFlags |= IXD_ABS_POS; } - else if (f_stricmp( szToken, "encrypt_with") == 0) + else if (f_stricmp( szToken, SFLM_ENCRYPT_WITH_STR) == 0) { if (RC_BAD( rc = getEncDefName( TRUE, szEncDefName, sizeof( szEncDefName), &uiEncDefNameLen, &pEncDef))) diff --git a/sql/src/createtable.cpp b/sql/src/createtable.cpp index 0edfa4b..67187c2 100644 --- a/sql/src/createtable.cpp +++ b/sql/src/createtable.cpp @@ -283,7 +283,8 @@ Exit: RCODE SQLStatement::getDataType( eDataType * peDataType, FLMUINT * puiMax, - FLMUINT * puiEncDefNum) + FLMUINT * puiEncDefNum, + FLMUINT * puiFlags) { RCODE rc = NE_SFLM_OK; char szToken [MAX_SQL_TOKEN_SIZE + 1]; @@ -403,28 +404,42 @@ Invalid_Data_Type: goto Exit; } - // See if they specified any encryption. + // See if they specified any encryption or not null - if (RC_BAD( rc = haveToken( "encrypt_with", FALSE))) + for (;;) { - if (rc == NE_SFLM_NOT_FOUND) + if (RC_BAD( rc = getToken( szToken, sizeof( szToken), FALSE, + &uiTokenLineOffset, NULL))) { - rc = NE_SFLM_OK; + goto Exit; + } + + if (f_stricmp( szToken, SFLM_ENCRYPT_WITH_STR) == 0) + { + if (RC_BAD( rc = getEncDefName( TRUE, szEncDefName, sizeof( szEncDefName), + &uiEncDefNameLen, &pEncDef))) + { + goto Exit; + } + *puiEncDefNum = pEncDef->uiEncDefNum; + } + else if (f_stricmp( szToken, "not") == 0) + { + if (RC_BAD( rc = haveToken( "null", FALSE, SQL_ERR_EXPECTING_NULL))) + { + goto exit; + } + (*puiFlags) &= (~(COL_NULL_ALLOWED)); } else { - goto Exit; + + // Process the token on the outside + + m_uiCurrLineOffset = uiTokenLineOffset; + break; } } - else - { - if (RC_BAD( rc = getEncDefName( TRUE, szEncDefName, sizeof( szEncDefName), - &uiEncDefNameLen, &pEncDef))) - { - goto Exit; - } - *puiEncDefNum = pEncDef->uiEncDefNum; - } Exit: return( rc); @@ -546,7 +561,8 @@ RCODE SQLStatement::processCreateTable( void) if (RC_BAD( rc = getDataType( &pColumnDef->eColumnDataType, &pColumnDef->uiMaxLen, - &pColumnDef->uiEncDefNum))) + &pColumnDef->uiEncDefNum, + &pColumnDef->uiFlags))) { goto Exit; } @@ -585,7 +601,7 @@ RCODE SQLStatement::processCreateTable( void) // See if an encryption definition was specified uiEncDefNum = 0; - if (RC_BAD( rc = haveToken( "encrypt_with", TRUE))) + if (RC_BAD( rc = haveToken( SFLM_ENCRYPT_WITH_STR, TRUE))) { if (rc == NE_SFLM_NOT_FOUND || rc == NE_SFLM_EOF_HIT) { diff --git a/sql/src/dropdatabase.cpp b/sql/src/dropdatabase.cpp index 8e53e1e..30ace88 100644 --- a/sql/src/dropdatabase.cpp +++ b/sql/src/dropdatabase.cpp @@ -373,7 +373,7 @@ RCODE SQLStatement::processDropDatabase( void) } } - if (f_stricmp( szToken, "data_dir") == 0) + if (f_stricmp( szToken, SFLM_DATA_DIR_STR) == 0) { if (RC_BAD( rc = getUTF8String( TRUE, TRUE, (FLMBYTE *)szDataDirName, sizeof( szDataDirName), @@ -382,7 +382,7 @@ RCODE SQLStatement::processDropDatabase( void) goto Exit; } } - else if (f_stricmp( szToken, "data_dir") == 0) + else if (f_stricmp( szToken, SFLM_RFL_DIR_STR) == 0) { if (RC_BAD( rc = getUTF8String( TRUE, TRUE, (FLMBYTE *)szRflDirName, sizeof( szRflDirName), diff --git a/sql/src/fcache.h b/sql/src/fcache.h index 3263c76..05446f5 100644 --- a/sql/src/fcache.h +++ b/sql/src/fcache.h @@ -2183,7 +2183,7 @@ public: RCODE setValue( F_Db * pDb, - FLMUINT uiColumnNum, + F_COLUMN * pColumn, const FLMBYTE * pucValue, FLMUINT uiValueLen); diff --git a/sql/src/fdict.cpp b/sql/src/fdict.cpp index 72121a1..1e17287 100644 --- a/sql/src/fdict.cpp +++ b/sql/src/fdict.cpp @@ -997,6 +997,10 @@ RCODE F_Dict::addColumn( pColumn->uiEncDefNum = uiEncDefNum; pColumn->pFirstIcd = NULL; pColumn->pFirstDataIcd = NULL; + if (!(uiFlags & COL_NULL_ALLOWED)) + { + pTable->uiNumReqColumns++; + } Exit: diff --git a/sql/src/fdict.h b/sql/src/fdict.h index 5986578..43c6f41 100644 --- a/sql/src/fdict.h +++ b/sql/src/fdict.h @@ -106,12 +106,18 @@ typedef struct F_TABLE FLMBOOL bSystemTable; // System table - cannot be dropped or altered by // an application. FLMUINT uiNumColumns; // Number of columns in the table. + FLMUINT uiNumReqColumns; // Number of columns that are required to + // have values. F_COLUMN * pColumns; // Contains all columns for the table. F_NameTable * pColumnNames; // Contains all column names for the table LFILE lfInfo; // Logical file information. FLMUINT uiFirstIndexNum; // Number of first index on this table } F_TABLE; +#define MAX_INDEX_COLUMNS ((SFLM_MAX_KEY_SIZE - FLM_MAX_NUM_BUF_SIZE) / 2) +#define MAX_ORDER_BY_COLUMNS MAX_INDEX_COLUMNS +#define MAX_SELECT_TABLES 50 + /***************************************************************************** Desc: Index definition *****************************************************************************/ diff --git a/sql/src/flaimsql.h b/sql/src/flaimsql.h index ee705b4..9f63f80 100644 --- a/sql/src/flaimsql.h +++ b/sql/src/flaimsql.h @@ -147,6 +147,10 @@ typedef enum SQL_ERR_EXPECTING_BY, ///< 67 = Expecting "BY" keyword. SQL_ERR_INDEX_NOT_DEFINED_FOR_TABLE,///< 68 = Index specified is not associated with the specified table. SQL_ERR_EXPECTING_INDEX_OR_NOINDEX, ///< 69 = Expecting INDEX or NOINDEX keyword. + SQL_ERR_TOO_MANY_INDEX_COLUMNS, ///< 70 = Too many columns specified in CREATE INDEX statement. + SQL_ERR_TOO_MANY_ORDER_BY_COLUMNS, ///< 71 = Too many columns specified in the ORDER BY clause. + SQL_ERR_EXPECTING_NULL, ///< 72 = Expecting "NULL" keyword. + SQL_ERR_INVALID_CHAR_IN_NAME, ///< 73 = Invalid character found in quoted name identifier. // IMPORTANT NOTE: If new codes are added, please update gv_SQLParseErrors in fshell.cpp SQL_NUM_ERRORS @@ -160,6 +164,7 @@ typedef struct FLMUINT uiErrLineNum; ///< Line number where error occurred. FLMUINT uiErrLineOffset; ///< Offset in line where error occurred.| NOTE: This is a zero-based offset. SQLParseError eErrorType; ///< Parsing error that occurred. + FLMUINT uiErrLineFilePos; ///< Absolute offset in the file (or buffer) where the line containing the error occurred. FLMUINT uiErrLineBytes; ///< Number of bytes in the line that contains the error. } SQL_STATS; @@ -381,139 +386,161 @@ typedef enum // Predefined table names and numbers #define SFLM_TBLNUM_ENCDEFS 1 -#define SFLM_TBLNAM_ENCDEFS "flmtbl_encdefs" +#define SFLM_TBLNAM_ENCDEFS "FLMTBL_ENCDEFS" #define SFLM_TBLNUM_TABLES 2 -#define SFLM_TBLNAM_TABLES "flmtbl_tables" +#define SFLM_TBLNAM_TABLES "FLMTBL_TABLES" #define SFLM_TBLNUM_COLUMNS 3 -#define SFLM_TBLNAM_COLUMNS "flmtbl_columns" +#define SFLM_TBLNAM_COLUMNS "FLMTBL_COLUMNS" #define SFLM_TBLNUM_INDEXES 4 -#define SFLM_TBLNAM_INDEXES "flmtbl_indexes" +#define SFLM_TBLNAM_INDEXES "FLMTBL_INDEXES" #define SFLM_TBLNUM_INDEX_COMPONENTS 5 -#define SFLM_TBLNAM_INDEX_COMPONENTS "flmtbl_index_components" +#define SFLM_TBLNAM_INDEX_COMPONENTS "FLMTBL_INDEX_COMPONENTS" #define SFLM_TBLNUM_BLOCK_CHAINS 6 -#define SFLM_TBLNAM_BLOCK_CHAINS "flmtbl_block_chains" +#define SFLM_TBLNAM_BLOCK_CHAINS "FLMTBL_BLOCK_CHAINS" // Predefined index names and numbers #define SFLM_IXNUM_ENCDEF_NAME 1 -#define SFLM_IXNAM_ENCDEF_NAME "flmix_encdef_name" +#define SFLM_IXNAM_ENCDEF_NAME "FLMIX_ENCDEF_NAME" #define SFLM_IXNUM_TABLE_NAME 2 -#define SFLM_IXNAM_TABLE_NAME "flmix_table_name" +#define SFLM_IXNAM_TABLE_NAME "FLMIX_TABLE_NAME" #define SFLM_IXNUM_TABLE_ENCDEF_NUM 3 -#define SFLM_IXNAM_TABLE_ENCDEF_NUM "flmix_table_encdef_num" +#define SFLM_IXNAM_TABLE_ENCDEF_NUM "FLMIX_TABLE_ENCDEF_NUM" #define SFLM_IXNUM_COLUMN_TABLE_NUM 4 -#define SFLM_IXNAM_COLUMN_TABLE_NUM "flmix_column_table_num" +#define SFLM_IXNAM_COLUMN_TABLE_NUM "FLMIX_COLUMN_TABLE_NUM" #define SFLM_IXNUM_COLUMN_ENCDEF_NUM 5 -#define SFLM_IXNAM_COLUMN_ENCDEF_NUM "flmix_column_encdef_num" +#define SFLM_IXNAM_COLUMN_ENCDEF_NUM "FLMIX_COLUMN_ENCDEF_NUM" #define SFLM_IXNUM_INDEX_NAME 6 -#define SFLM_IXNAM_INDEX_NAME "flmix_index_name" +#define SFLM_IXNAM_INDEX_NAME "FLMIX_INDEX_NAME" #define SFLM_IXNUM_INDEX_TABLE_NUM 7 -#define SFLM_IXNAM_INDEX_TABLE_NUM "flmix_index_table_num" +#define SFLM_IXNAM_INDEX_TABLE_NUM "FLMIX_INDEX_TABLE_NUM" #define SFLM_IXNUM_INDEX_ENCDEF_NUM 8 -#define SFLM_IXNAM_INDEX_ENCDEF_NUM "flmix_index_encdef_num" +#define SFLM_IXNAM_INDEX_ENCDEF_NUM "FLMIX_INDEX_ENCDEF_NUM" #define SFLM_IXNUM_INDEX_COMP_INDEX_NUM 9 -#define SFLM_IXNAM_INDEX_COMP_INDEX_NUM "flmix_index_comp_index_num" +#define SFLM_IXNAM_INDEX_COMP_INDEX_NUM "FLMIX_INDEX_COMP_INDEX_NUM" // Column names and numbers for the encryption definitions table #define SFLM_COLNUM_ENCDEFS_ENCDEF_NAME 1 -#define SFLM_COLNAM_ENCDEFS_ENCDEF_NAME "encdef_name" +#define SFLM_COLNAM_ENCDEFS_ENCDEF_NAME "ENCDEF_NAME" #define SFLM_COLNUM_ENCDEFS_ENCDEF_NUM 2 -#define SFLM_COLNAM_ENCDEFS_ENCDEF_NUM "encdef_num" +#define SFLM_COLNAM_ENCDEFS_ENCDEF_NUM "ENCDEF_NUM" #define SFLM_COLNUM_ENCDEFS_ENC_ALGORITHM 3 -#define SFLM_COLNAM_ENCDEFS_ENC_ALGORITHM "enc_algorithm" +#define SFLM_COLNAM_ENCDEFS_ENC_ALGORITHM "ENC_ALGORITHM" #define SFLM_COLNUM_ENCDEFS_ENC_KEY_SIZE 4 -#define SFLM_COLNAM_ENCDEFS_ENC_KEY_SIZE "enc_key_size" +#define SFLM_COLNAM_ENCDEFS_ENC_KEY_SIZE "ENC_KEY_SIZE" #define SFLM_COLNUM_ENCDEFS_ENC_KEY 5 -#define SFLM_COLNAM_ENCDEFS_ENC_KEY "enc_key" +#define SFLM_COLNAM_ENCDEFS_ENC_KEY "ENC_KEY" #define SFLM_ENCDEFS_NUM_COLUMNS 5 // Column names and numbers for the tables table #define SFLM_COLNUM_TABLES_TABLE_NAME 1 -#define SFLM_COLNAM_TABLES_TABLE_NAME "table_name" +#define SFLM_COLNAM_TABLES_TABLE_NAME "TABLE_NAME" #define SFLM_COLNUM_TABLES_TABLE_NUM 2 -#define SFLM_COLNAM_TABLES_TABLE_NUM "table_num" +#define SFLM_COLNAM_TABLES_TABLE_NUM "TABLE_NUM" #define SFLM_COLNUM_TABLES_ENCDEF_NUM 3 -#define SFLM_COLNAM_TABLES_ENCDEF_NUM "encdef_num" +#define SFLM_COLNAM_TABLES_ENCDEF_NUM "ENCDEF_NUM" #define SFLM_COLNUM_TABLES_NUM_COLUMNS 4 -#define SFLM_COLNAM_TABLES_NUM_COLUMNS "num_columns" +#define SFLM_COLNAM_TABLES_NUM_COLUMNS "NUM_COLUMNS" #define SFLM_TABLES_NUM_COLUMNS 4 // Column names and numbers for the columns table #define SFLM_COLNUM_COLUMNS_TABLE_NUM 1 -#define SFLM_COLNAM_COLUMNS_TABLE_NUM "table_num" +#define SFLM_COLNAM_COLUMNS_TABLE_NUM "TABLE_NUM" #define SFLM_COLNUM_COLUMNS_COLUMN_NAME 2 -#define SFLM_COLNAM_COLUMNS_COLUMN_NAME "column_name" +#define SFLM_COLNAM_COLUMNS_COLUMN_NAME "COLUMN_NAME" #define SFLM_COLNUM_COLUMNS_COLUMN_NUM 3 -#define SFLM_COLNAM_COLUMNS_COLUMN_NUM "column_num" +#define SFLM_COLNAM_COLUMNS_COLUMN_NUM "COLUMN_NUM" #define SFLM_COLNUM_COLUMNS_DATA_TYPE 4 -#define SFLM_COLNAM_COLUMNS_DATA_TYPE "data_type" +#define SFLM_COLNAM_COLUMNS_DATA_TYPE "DATA_TYPE" #define SFLM_COLNUM_COLUMNS_MAX_LEN 5 -#define SFLM_COLNAM_COLUMNS_MAX_LEN "max_len" +#define SFLM_COLNAM_COLUMNS_MAX_LEN "MAX_LEN" #define SFLM_COLNUM_COLUMNS_ENCDEF_NUM 6 -#define SFLM_COLNAM_COLUMNS_ENCDEF_NUM "encdef_num" +#define SFLM_COLNAM_COLUMNS_ENCDEF_NUM "ENCDEF_NUM" #define SFLM_COLNUM_COLUMNS_READ_ONLY 7 -#define SFLM_COLNAM_COLUMNS_READ_ONLY "read_only" +#define SFLM_COLNAM_COLUMNS_READ_ONLY "READ_ONLY" #define SFLM_COLNUM_COLUMNS_NULL_ALLOWED 8 -#define SFLM_COLNAM_COLUMNS_NULL_ALLOWED "null_allowed" +#define SFLM_COLNAM_COLUMNS_NULL_ALLOWED "NULL_ALLOWED" #define SFLM_COLUMNS_NUM_COLUMNS 8 // Column names and numbers for the indexes table #define SFLM_COLNUM_INDEXES_INDEX_NAME 1 -#define SFLM_COLNAM_INDEXES_INDEX_NAME "index_name" +#define SFLM_COLNAM_INDEXES_INDEX_NAME "INDEX_NAME" #define SFLM_COLNUM_INDEXES_INDEX_NUM 2 -#define SFLM_COLNAM_INDEXES_INDEX_NUM "index_num" +#define SFLM_COLNAM_INDEXES_INDEX_NUM "INDEX_NUM" #define SFLM_COLNUM_INDEXES_TABLE_NUM 3 -#define SFLM_COLNAM_INDEXES_TABLE_NUM "table_num" +#define SFLM_COLNAM_INDEXES_TABLE_NUM "TABLE_NUM" #define SFLM_COLNUM_INDEXES_ENCDEF_NUM 4 -#define SFLM_COLNAM_INDEXES_ENCDEF_NUM "encdef_num" +#define SFLM_COLNAM_INDEXES_ENCDEF_NUM "ENCDEF_NUM" #define SFLM_COLNUM_INDEXES_LANGUAGE 5 -#define SFLM_COLNAM_INDEXES_LANGUAGE "language" +#define SFLM_COLNAM_INDEXES_LANGUAGE "LANGUAGE" #define SFLM_COLNUM_INDEXES_NUM_KEY_COMPONENTS 6 -#define SFLM_COLNAM_INDEXES_NUM_KEY_COMPONENTS "num_key_components" +#define SFLM_COLNAM_INDEXES_NUM_KEY_COMPONENTS "NUM_KEY_COMPONENTS" #define SFLM_COLNUM_INDEXES_NUM_DATA_COMPONENTS 7 -#define SFLM_COLNAM_INDEXES_NUM_DATA_COMPONENTS "num_data_components" +#define SFLM_COLNAM_INDEXES_NUM_DATA_COMPONENTS "NUM_DATA_COMPONENTS" #define SFLM_COLNUM_INDEXES_LAST_ROW_INDEXED 8 -#define SFLM_COLNAM_INDEXES_LAST_ROW_INDEXED "last_row_indexed" +#define SFLM_COLNAM_INDEXES_LAST_ROW_INDEXED "LAST_ROW_INDEXED" #define SFLM_COLNUM_INDEXES_INDEX_STATE 9 -#define SFLM_COLNAM_INDEXES_INDEX_STATE "index_state" +#define SFLM_COLNAM_INDEXES_INDEX_STATE "INDEX_STATE" #define SFLM_COLNUM_INDEXES_KEEP_ABS_POS_INFO 10 -#define SFLM_COLNAM_INDEXES_KEEP_ABS_POS_INFO "keep_abs_pos_info" +#define SFLM_COLNAM_INDEXES_KEEP_ABS_POS_INFO "KEEP_ABS_POS_INFO" #define SFLM_COLNUM_INDEXES_KEYS_UNIQUE 11 -#define SFLM_COLNAM_INDEXES_KEYS_UNIQUE "keys_unique" +#define SFLM_COLNAM_INDEXES_KEYS_UNIQUE "KEYS_UNIQUE" #define SFLM_INDEXES_NUM_COLUMNS 11 // Column names and numbers for the index components table #define SFLM_COLNUM_INDEX_COMP_INDEX_NUM 1 -#define SFLM_COLNAM_INDEX_COMP_INDEX_NUM "index_num" +#define SFLM_COLNAM_INDEX_COMP_INDEX_NUM "INDEX_NUM" #define SFLM_COLNUM_INDEX_COMP_COLUMN_NUM 2 -#define SFLM_COLNAM_INDEX_COMP_COLUMN_NUM "column_num" +#define SFLM_COLNAM_INDEX_COMP_COLUMN_NUM "COLUMN_NUM" #define SFLM_COLNUM_INDEX_COMP_KEY_COMPONENT 3 -#define SFLM_COLNAM_INDEX_COMP_KEY_COMPONENT "key_component" +#define SFLM_COLNAM_INDEX_COMP_KEY_COMPONENT "KEY_COMPONENT" #define SFLM_COLNUM_INDEX_COMP_DATA_COMPONENT 4 -#define SFLM_COLNAM_INDEX_COMP_DATA_COMPONENT "data_component" +#define SFLM_COLNAM_INDEX_COMP_DATA_COMPONENT "DATA_COMPONENT" #define SFLM_COLNUM_INDEX_COMP_INDEX_ON 5 -#define SFLM_COLNAM_INDEX_COMP_INDEX_ON "index_on" +#define SFLM_COLNAM_INDEX_COMP_INDEX_ON "INDEX_ON" #define SFLM_COLNUM_INDEX_COMP_COMPARE_RULES 6 -#define SFLM_COLNAM_INDEX_COMP_COMPARE_RULES "compare_rules" +#define SFLM_COLNAM_INDEX_COMP_COMPARE_RULES "COMPARE_RULES" #define SFLM_COLNUM_INDEX_COMP_SORT_DESCENDING 7 -#define SFLM_COLNAM_INDEX_COMP_SORT_DESCENDING "sort_descending" +#define SFLM_COLNAM_INDEX_COMP_SORT_DESCENDING "SORT_DESCENDING" #define SFLM_COLNUM_INDEX_COMP_SORT_MISSING_HIGH 8 -#define SFLM_COLNAM_INDEX_COMP_SORT_MISSING_HIGH "sort_missing_high" +#define SFLM_COLNAM_INDEX_COMP_SORT_MISSING_HIGH "SORT_MISSING_HIGH" #define SFLM_COLNUM_INDEX_COMP_LIMIT 9 -#define SFLM_COLNAM_INDEX_COMP_LIMIT "limit" +#define SFLM_COLNAM_INDEX_COMP_LIMIT "LIMIT" #define SFLM_INDEX_COMP_NUM_COLUMNS 9 // Column names and numbers for the block chains table #define SFLM_COLNUM_BLOCK_CHAINS_BLOCK_ADDRESS 1 -#define SFLM_COLNAM_BLOCK_CHAINS_BLOCK_ADDRESS "block_address" +#define SFLM_COLNAM_BLOCK_CHAINS_BLOCK_ADDRESS "BLOCK_ADDRESS" #define SFLM_BLOCK_CHAINS_NUM_COLUMNS 1 +#define SFLM_DATA_DIR_STR "data_dir" +#define SFLM_DATA_DIR_STR_LEN 8 +#define SFLM_RFL_DIR_STR "rfl_dir" +#define SFLM_RFL_DIR_STR_LEN 7 +#define SFLM_PASSWORD_STR "password" +#define SFLM_PASSWORD_STR_LEN 8 +#define SFLM_ALLOW_LIMITED_STR "allow_limited" +#define SFLM_ALLOW_LIMITED_STR_LEN 13 +#define SFLM_BLOCK_SIZE_STR "block_size" +#define SFLM_BLOCK_SIZE_STR_LEN 10 +#define SFLM_MIN_RFL_SIZE_STR "min_rfl_size" +#define SFLM_MIN_RFL_SIZE_STR_LEN 12 +#define SFLM_MAX_RFL_SIZE_STR "max_rfl_size" +#define SFLM_MAX_RFL_SIZE_STR_LEN 12 +#define SFLM_KEEP_RFL_STR "keep_rfl" +#define SFLM_KEEP_RFL_STR_LEN 8 +#define SFLM_LOG_ABORTED_TRANS_STR "log_aborted_trans" +#define SFLM_LOG_ABORTED_TRANS_STR_LEN 17 +#define SFLM_LANGUAGE_STR "language" +#define SFLM_LANGUAGE_STR_LEN 8 +#define SFLM_ENCRYPT_WITH_STR "encrypt_with" +#define SFLM_ENCRYPT_WITH_STR_LEN 12 #define SFLM_STRING_OPTION_STR "string" #define SFLM_STRING_OPTION_STR_LEN 6 #define SFLM_INTEGER_OPTION_STR "integer" @@ -1285,6 +1312,9 @@ typedef struct #define NE_SFLM_INVALID_SQL 0xE05C ///< 0xE05C = SQL statement is invalid. #define NE_SFLM_STRING_TOO_LONG 0xE05D ///< 0xE05D = String specified for column exceeds maximum length for column. #define NE_SFLM_BINARY_TOO_LONG 0xE05E ///< 0xE05E = Binary value specified for column exceeds maximum length for column. +#define NE_SFLM_NULL_NOT_ALLOWED_IN_COLUMN 0xE05F ///< 0xE05F = Column does not allow storing of NULL values. +#define NE_SFLM_COLUMN_IS_READ_ONLY 0xE060 ///< 0xE060 = Column cannot be modified. +#define NE_SFLM_MISSING_REQUIRED_COLUMN 0xE061 ///< 0xE061 = Required column is missing from column list on INSERT statement.\ Required columns are those that are marked as NOT NULL. // Dictionary definition errors. diff --git a/sql/src/frow.cpp b/sql/src/frow.cpp index d3e2c17..d2d1068 100644 --- a/sql/src/frow.cpp +++ b/sql/src/frow.cpp @@ -3313,8 +3313,10 @@ RCODE F_Row::setBinary( const void * pvValue, FLMUINT uiValueLen) { - RCODE rc = NE_SFLM_OK; - + RCODE rc = NE_SFLM_OK; + F_TABLE * pTable; + F_COLUMN * pColumn; + if (RC_BAD( rc = allocColumnDataSpace( pDb, uiColumnNum, uiValueLen, FALSE))) { goto Exit; @@ -3445,19 +3447,38 @@ Desc: ******************************************************************************/ RCODE F_Row::setValue( F_Db * pDb, - FLMUINT uiColumnNum, + F_COLUMN * pColumn, const FLMBYTE * pucValue, FLMUINT uiValueLen) { RCODE rc = NE_SFLM_OK; + + // Make sure this is not a read-only column + + if (pColumn->uiFlags & COL_READ_ONLY) + { + rc = RC_SET( NE_SFLM_COLUMN_IS_READ_ONLY); + goto Exit; + } - if (RC_BAD( rc = allocColumnDataSpace( pDb, uiColumnNum, uiValueLen, FALSE))) + // If a length of zero is specified, we have a NULL value. Make sure + // that is legal. + + if (!uiValueLen && + !(pColumn->uiFlags & COL_NULL_ALLOWED)) + { + rc = RC_SET( NE_SFLM_NULL_NOT_ALLOWED_IN_COLUMN); + goto Exit; + } + + + if (RC_BAD( rc = allocColumnDataSpace( pDb, pColumn->uiColumnNum, uiValueLen, FALSE))) { goto Exit; } if (uiValueLen) { - FLMBYTE * pucTmp = getColumnDataPtr( uiColumnNum); + FLMBYTE * pucTmp = getColumnDataPtr( pColumn->uiColumnNum); f_memcpy( pucTmp, pucValue, uiValueLen); } diff --git a/sql/src/fstructs.h b/sql/src/fstructs.h index 04dfa8e..b5ecc47 100644 --- a/sql/src/fstructs.h +++ b/sql/src/fstructs.h @@ -54,6 +54,10 @@ class F_ColumnDataRelocator; class F_ColumnListRelocator; class F_BTreeIStreamPool; class SQLQuery; +class SQLEnv; +class SQLConnection; +class SQLDesc; +class SQLStatement; /**************************************************************************** Desc: Tests to see if database is NOT in native platform format. @@ -1143,6 +1147,10 @@ friend class F_ColumnDataRelocator; friend class F_ColumnListRelocator; friend class F_BlockRelocator; friend class SQLQuery; +friend class SQLEnv; +friend class SQLConnection; +friend class SQLDesc; +friend class SQLStatement; }; typedef struct QUERY_HDR diff --git a/sql/src/insertrow.cpp b/sql/src/insertrow.cpp index f0481f2..ecc2a16 100644 --- a/sql/src/insertrow.cpp +++ b/sql/src/insertrow.cpp @@ -38,6 +38,7 @@ RCODE F_Db::insertRow( F_TABLE * pTable; F_COLUMN * pColumn; FLMBOOL bStartedTrans = FALSE; + FLMUINT uiNumReqColumns; // Make sure we are in an update transaction. @@ -63,7 +64,7 @@ RCODE F_Db::insertRow( // Set the column values into the row. - for (pColumnValue = pColumnValues; + for (pColumnValue = pColumnValues, uiNumReqColumns = 0; pColumnValue; pColumnValue = pColumnValue->pNext) { @@ -105,7 +106,12 @@ RCODE F_Db::insertRow( } } } - if (RC_BAD( rc = pRow->setValue( this, pColumnValue->uiColumnNum, + if (!(pColumn->uiFlags & COL_NULL_ALLOWED)) + { + uiNumReqColumns++; + } + + if (RC_BAD( rc = pRow->setValue( this, pColumn, pColumnValue->pucColumnValue, pColumnValue->uiValueLen))) { @@ -113,6 +119,14 @@ RCODE F_Db::insertRow( } } + // See if we got all of the required columns + + if (uiNumReqColumns != pTable->uiNumReqColumns) + { + rc = RC_SET( NE_SFLM_MISSING_REQUIRED_COLUMN); + goto Exit; + } + // Do whatever indexing needs to be done. if (RC_BAD( rc = updateIndexKeys( uiTableNum, pRow, TRUE, NULL))) diff --git a/sql/src/opendatabase.cpp b/sql/src/opendatabase.cpp index 425c09c..39fa3f7 100644 --- a/sql/src/opendatabase.cpp +++ b/sql/src/opendatabase.cpp @@ -2002,7 +2002,7 @@ RCODE SQLStatement::processOpenDatabase( void) } } - if (f_stricmp( szToken, "data_dir") == 0) + if (f_stricmp( szToken, SFLM_DATA_DIR_STR) == 0) { if (RC_BAD( rc = getUTF8String( TRUE, TRUE, (FLMBYTE *)szDataDirName, sizeof( szDataDirName), @@ -2011,7 +2011,7 @@ RCODE SQLStatement::processOpenDatabase( void) goto Exit; } } - else if (f_stricmp( szToken, "data_dir") == 0) + else if (f_stricmp( szToken, SFLM_RFL_DIR_STR) == 0) { if (RC_BAD( rc = getUTF8String( TRUE, TRUE, (FLMBYTE *)szRflDirName, sizeof( szRflDirName), @@ -2020,7 +2020,7 @@ RCODE SQLStatement::processOpenDatabase( void) goto Exit; } } - else if (f_stricmp( szToken, "password") == 0) + else if (f_stricmp( szToken, SFLM_PASSWORD_STR) == 0) { if (RC_BAD( rc = getUTF8String( TRUE, TRUE, (FLMBYTE *)szPassword, sizeof( szPassword), @@ -2029,7 +2029,7 @@ RCODE SQLStatement::processOpenDatabase( void) goto Exit; } } - else if (f_stricmp( szToken, "allow_limited") == 0) + else if (f_stricmp( szToken, SFLM_ALLOW_LIMITED_STR) == 0) { uiFlags |= SFLM_ALLOW_LIMITED_MODE; } diff --git a/sql/src/select.cpp b/sql/src/select.cpp index 6f85f3d..18653f1 100644 --- a/sql/src/select.cpp +++ b/sql/src/select.cpp @@ -146,7 +146,6 @@ Exit: //------------------------------------------------------------------------------ RCODE SQLStatement::processSelect( void) { -#define MAX_SELECT_TABLES 15 RCODE rc = NE_SFLM_OK; FLMBOOL bStartedTrans = FALSE; char szToken [MAX_SQL_TOKEN_SIZE + 1]; @@ -497,6 +496,16 @@ Get_Index: { goto Exit; } + if (uiNumOrderByColumns == MAX_ORDER_BY_COLUMNS) + { + setErrInfo( m_uiCurrLineNum, + uiTokenLineOffset, + SQL_ERR_TOO_MANY_ORDER_BY_COLUMNS, + m_uiCurrLineFilePos, + m_uiCurrLineBytes); + rc = RC_SET( NE_SFLM_INVALID_SQL); + goto Exit; + } // See if we have a period after the name. diff --git a/sql/src/sqlstatement.cpp b/sql/src/sqlstatement.cpp index 6111b27..8b2ae81 100644 --- a/sql/src/sqlstatement.cpp +++ b/sql/src/sqlstatement.cpp @@ -36,6 +36,9 @@ SQLStatement::SQLStatement() m_pucCurrLineBuf = NULL; m_uiCurrLineBufMaxBytes = 0; m_pXml = NULL; + m_pConnection = NULL; + m_pNextInConnection = NULL; + m_pPrevInConnection = NULL; resetStatement(); } @@ -51,6 +54,10 @@ SQLStatement::~SQLStatement() f_free( &m_pucCurrLineBuf); } + // Better not be associated with a connection at this point. + + flmAssert( !m_pConnection); + m_tmpPool.poolFree(); } @@ -1338,6 +1345,7 @@ RCODE SQLStatement::getName( RCODE rc = NE_SFLM_OK; FLMUINT uiCharCount = 0; FLMBYTE ucChar; + FLMBYTE ucQuoteChar; if (RC_BAD( rc = skipWhitespace( FALSE))) { @@ -1348,6 +1356,19 @@ RCODE SQLStatement::getName( uiNameBufSize--; *puiTokenLineOffset = m_uiCurrLineOffset; + + // If the first character is a quote, it means we are going to + // preserve case. + + ucChar = getChar(); + if (ucChar == '"' || ucChar == '\'') + { + ucQuoteChar = ucChar; + } + else + { + ucQuoteChar = 0; + } // Get the first character - must be between A and Z @@ -1377,6 +1398,10 @@ RCODE SQLStatement::getName( { break; } + if (ucQuoteChar && ucChar == ucQuoteChar) + { + break; + } if ((ucChar >= 'a' && ucChar <= 'z') || (ucChar >= 'A' && ucChar <= 'Z') || (ucChar >= '0' && ucChar <= '9') || @@ -1392,7 +1417,27 @@ RCODE SQLStatement::getName( rc = RC_SET( NE_SFLM_INVALID_SQL); goto Exit; } - pszName [uiCharCount++] = (char)ucChar; + + // Convert name to upper case unless the name is quoted. + + if (ucChar >= 'a' && ucChar <= 'z' && !ucQuoteChar) + { + pszName [uiCharCount++] = (char)(ucChar - 'a' + 'A'); + } + else + { + pszName [uiCharCount++] = (char)ucChar; + } + } + else if (ucQuoteChar) + { + setErrInfo( m_uiCurrLineNum, + m_uiCurrLineOffset - 1, + SQL_ERR_INVALID_CHAR_IN_NAME, + m_uiCurrLineFilePos, + m_uiCurrLineBytes); + rc = RC_SET( NE_SFLM_INVALID_SQL); + goto Exit; } else { diff --git a/sql/src/sqlstatement.h b/sql/src/sqlstatement.h index 772bdea..30e6968 100644 --- a/sql/src/sqlstatement.h +++ b/sql/src/sqlstatement.h @@ -65,10 +65,144 @@ typedef RCODE (* SQL_STATUS_HOOK)( void * pvArg3, void * pvUserData); +//------------------------------------------------------------------------------ +// Desc: Base object that defines methods which must be present for all ODBC +// handle objects. +//------------------------------------------------------------------------------ +class ODBCObject : public F_Object +{ +public: + + ODBCObject() + { + m_hMutex = F_MUTEX_NULL; + m_pszStateInfo = NULL; + m_uiErrMsgLen = 0; + m_bHaveError = FALSE; + m_uiNumDiagRecs = 0; + } + + virtual ~ODBCObject() + { + if (m_hMutex != F_MUTEX_NULL) + { + f_mutexDestroy( &m_hMutex); + } + } + + FINLINE FLMINT FLMAPI AddRef( void) + { + return( f_atomicInc( &m_refCnt); + } + + FINLINE FLMINT FLMAPI Release( void) + { + FLMINT iRefCnt; + + if ((iRefCnt = f_atomicDec( &m_refCnt)) == 0) + { + delete this; + } + return( iRefCnt); + } + + FINLINE RCODE setupObject( void) + { + return( f_mutexCreate( &m_hMutex)); + } + + FINLINE void lockObject( void) + { + f_mutexLock( m_hMutex); + } + + FINLINE void unlockObject( void) + { + f_mutexUnlock( m_hMutex); + } + + FINLINE const char * getStateInfo( void) + { + return( m_pszStateInfo); + } + + FINLINE FLMUINT getErrMsgLen( void) + { + return( m_uiErrMsgLen); + } + + FINLINE const char * getErrMsg( void) + { + if (m_uiErrMsgLen) + { + return( &m_szErrMsg [0]); + } + else + { + return( NULL); + } + } + + FINLINE RCODE getRCODE( void) + { + return( m_rc); + } + + FINLINE FLMBOOL haveError( void) + { + return( m_bHaveError); + } + + FINLINE void clearState( void) + { + m_bHaveError = FALSE; + m_uiNumDiagRecs = 0; + } + + FINLINE void setStateInfo( + const char * pszStateInfo) + { + m_pszStateInfo = pszStateInfo; + m_uiErrMsgLen = 0; + m_rc = NE_SFLM_OK; + m_bHaveError = TRUE; + } + + FINLINE void setGeneralErrMsg( + const char * pszErrMsg, + RCODE rc = NE_SFLM_OK) + { + m_pszStateInfo = "HY000"; + m_uiErrMsgLen = f_strlen( pszErrMsg); + + // Copy null terminator character too. + + f_memcpy( m_szErrMsg, pszErrMsg, m_uiErrMsgLen + 1); + m_rc = rc; + m_bHaveError = TRUE; + } + + // Must be implemented by inheriting class. + + virtual FLMBOOL canRelease( void) = 0; + +private: + + F_MUTEX m_hMutex; + const char * m_pszLastStateInfo; + char * m_szErrMsg [200]; + FLMUINT m_uiErrMsgLen; + RCODE m_rc; + FLMUINT m_bHaveError; + FLMUINT m_uiNumDiagRecs; +} + /*============================================================================ -Desc: SQL statement class. Parses and executes SQL statements. +Desc: SQL statement class. Parses and executes SQL statements. This object + type is returned for ODBC for handles of type SQL_HANDLE_STMT or + SQLHSTMT. ============================================================================*/ -class SQLStatement : public F_Object +class SQLStatement : public ODBCObject { public: @@ -77,6 +211,8 @@ public: SQLStatement(); virtual ~SQLStatement(); + + FLMBOOL canRelease( void); RCODE setupStatement( void); @@ -86,6 +222,18 @@ public: IF_IStream * pStream, F_Db * pDb, SQL_STATS * pSQLStats); + + FINLINE FLMBOOL canRelease( void) + { + // VISIT: Need to determine whether or not this is possible. + + return( TRUE); + } + + SQLConnection * getConnection( void) + { + return( m_pConnection); + } private: @@ -250,7 +398,8 @@ private: RCODE getDataType( eDataType * peDataType, FLMUINT * puiMax, - FLMUINT * puiEncDefNum); + FLMUINT * puiEncDefNum, + FLMUINT * puiFlags); RCODE processCreateTable( void); @@ -311,9 +460,15 @@ private: void * m_pvCallbackData; SQL_STATS m_sqlStats; F_Pool m_tmpPool; + SQLConnection * m_pConnection; + SQLStatement * m_pNextInConnection; + SQLStatement * m_pPrevInConnection; friend class F_Db; friend class F_Database; +friend class SQLConnection; +friend class SQLEnv; +friend class SQLDesc; }; RCODE resolveColumnName( diff --git a/sql/src/updaterow.cpp b/sql/src/updaterow.cpp index c9d8423..a7e58a0 100644 --- a/sql/src/updaterow.cpp +++ b/sql/src/updaterow.cpp @@ -141,7 +141,7 @@ RCODE F_Db::updateRow( } } } - if (RC_BAD( rc = pRow->setValue( this, pColumnValue->uiColumnNum, + if (RC_BAD( rc = pRow->setValue( this, pColumn, pColumnValue->pucColumnValue, pColumnValue->uiValueLen))) { diff --git a/sql/src/whereclause.cpp b/sql/src/whereclause.cpp index e72be15..f00d1ae 100644 --- a/sql/src/whereclause.cpp +++ b/sql/src/whereclause.cpp @@ -1601,7 +1601,7 @@ RCODE SQLStatement::parseCriteria( { goto Exit; } - + break; case '+':