TbBool columns_add_static_entries(void) { struct Column *colmn; struct Column lcolmn; short *wptr; short c[3]; long ncol; long i,k; for (i=0; i < 3; i++) c[i] = 0; LbMemorySet(&lcolmn,0,sizeof(struct Column)); wptr = &game.field_14A818[0]; for (i=0; i < 3; i++) { LbMemorySet(&lcolmn, 0, sizeof(struct Column)); lcolmn.baseblock = c[i]; for (k=0; k < 6; k++) { lcolmn.cubes[0] = player_cubes[k]; make_solidmask(&lcolmn); ncol = find_column(&lcolmn); if (ncol == 0) ncol = create_column(&lcolmn); colmn = get_column(ncol); colmn->bitfields |= 0x01; *wptr = -(short)ncol; wptr++; } } return true; }
int ai_findandset_imatch(as_sindex_metadata *imd, as_sindex_pmetadata *pimd, int idx) { if (!Num_tbls) { return AS_SINDEX_ERR; } char *tname = NULL, *cname = NULL, *iname = NULL; int ret = AS_SINDEX_OK; if (!(tname = create_tname_from_imd(imd))) { return AS_SINDEX_ERR_NO_MEMORY; } ret = AS_SINDEX_ERR; AI_GRLOCK(); int tmatch = find_table(tname); if (tmatch == -1) { goto END; } if (imd->iname) { if (!(iname = get_iname_from_imd(imd))) { ret = AS_SINDEX_ERR_NO_MEMORY; goto END; } char idx_str[NAME_STR_LEN]; snprintf(idx_str, sizeof(idx_str), "%d", idx); char *piname = str_concat(iname, '.', idx_str); pimd->imatch = match_partial_index_name(piname); cf_free(piname); } else { if (!(cname = create_cname_from_imd(imd))) { ret = AS_SINDEX_ERR_NO_MEMORY; goto END; } icol_t *ic = find_column(tmatch, cname); if (!ic) { goto END; } pimd->imatch = find_partial_index(tmatch, ic); } if (pimd->imatch == -1) { SITRACE(imd->si, META, debug, "Index%s: %s not found", imd->iname ? "" : "column-name", imd->iname ? iname : cname); goto END; } ret = AS_SINDEX_OK; END: AI_UNLOCK(); cf_free(tname); cf_free(iname); cf_free(cname); return ret; }
void init_whole_blocks(void) { struct Column *colmn; struct Column lcolmn; long i; game.field_149E6E = -1; LbMemorySet(&lcolmn, 0, sizeof(struct Column)); // Prepare the local column lcolmn.baseblock = 22; lcolmn.cubes[0] = 10; lcolmn.cubes[1] = 1; lcolmn.cubes[2] = 1; lcolmn.cubes[3] = 1; lcolmn.cubes[4] = 141; make_solidmask(&lcolmn); // Find it or add to column list i = find_column(&lcolmn); if (i == 0) i = create_column(&lcolmn); colmn = get_column(i); // Update its parameters colmn->bitfields |= 0x01; game.field_149E7C = 24; game.unrevealed_column_idx = i; }
static void row_cs( sqlInfo_t * db, tableInfo_t * table, cellInfo_t * row, const char * cs ) { columnInfo_t * c; char key [ MAX_INFO_KEY ]; char value [ MAX_INFO_VALUE ]; for ( ; ; ) { Info_NextPair( &cs, key, value ); if ( key[ 0 ] == '\0' ) break; c = find_column( table, key ); if ( c ) { if ( c->format == INTEGER ) { int v = atoi( value ); if ( row[ c->num ].integer != v ) { table->modified |= (1<<c->num); row[ c->num ].integer = v; } } else { const char * s = sql_alloc_string( db, value ); if ( Q_stricmp( row[ c->num ].string, s ) ) { table->modified |= (1<<c->num); row[ c->num ].string = s; } } } } }
TbBool update_slabset_column_indices(struct Column *cols, long ccount) { struct Column *colmn; struct Column lcolmn; struct SlabSet *sset; long ncol; long i,k,n; LbMemorySet(&lcolmn,0,sizeof(struct Column)); for (i=0; i < game.slabset_num; i++) { sset = &game.slabset[i]; for (k=0; k < 9; k++) { n = sset->col_idx[k]; if (n >= 0) { lcolmn.baseblock = n; ncol = find_column(&lcolmn); if (ncol == 0) { ncol = create_column(&lcolmn); colmn = get_column(ncol); colmn->bitfields |= 0x01; } } else { if (-n < ccount) ncol = find_column(&cols[-n]); else ncol = 0; if (ncol == 0) { ERRORLOG("E14R432Q#222564-3; I should be able to find a column here"); continue; } } sset->col_idx[k] = -ncol; } } return true; }
TbBool create_columns_from_list(struct Column *cols, long ccount) { struct Column *colmn; long ncol; long i; for (i=1; i < ccount; i++) { if (cols[i].use) { ncol = find_column(&cols[i]); if (ncol == 0) ncol = create_column(&cols[i]); colmn = get_column(ncol); colmn->bitfields |= 0x01; } } return true; }
// SQL_AOF SQL_AOF SQL_AOF SQL_AOF SQL_AOF SQL_AOF SQL_AOF SQL_AOF SQL_AOF sds DXDB_SQL_feedAppendOnlyFile(rcommand *cmd, robj **argv, int argc) { if (cmd->proc == insertCommand || cmd->proc == updateCommand || cmd->proc == deleteCommand || cmd->proc == replaceCommand || cmd->proc == createCommand || cmd->proc == dropCommand || cmd->proc == alterCommand) { if (cmd->proc == createCommand) { if ((!strcasecmp(argv[1]->ptr, "LRUINDEX")) || (!strcasecmp(argv[1]->ptr, "LUATRIGGER"))) return sdsempty(); int arg = 1, targ = 4, coln = 5; if (!strcasecmp(argv[1]->ptr, "UNIQUE")) { arg = 2; targ = 5; coln = 6; } if (!strcasecmp(argv[arg]->ptr, "INDEX")) { // index on TEXT int tmatch = find_table(argv[targ]->ptr); r_tbl_t *rt = &Tbl[tmatch]; char *token = argv[coln]->ptr; char *end = strchr(token, ')'); STACK_STRDUP(cname, (token + 1), (end - token - 1)) icol_t ic = find_column(tmatch, cname); uchar ctype = rt->col[ic.cmatch].type; if (C_IS_S(ctype)) { int imatch = find_index(tmatch, ic); r_ind_t *ri = &Index[imatch]; return createAlterTableFullText(rt, ri, ic.cmatch, 1); } } } sds buf = sdsempty(); for (int j = 0; j < argc; j++) { robj *o = getDecodedObject(argv[j]); buf = sdscatlen(buf, o->ptr, sdslen(o->ptr)); if (j != (argc - 1)) buf = sdscatlen(buf," ", 1); decrRefCount(o); } buf = sdscatlen(buf, ";\n", 2); return buf; } return sdsempty(); }
/* NOTE: The creation of a secondary index is the following two commands 0.) optional: CREATE TABLE namespace (pk U160, __dummy TEXT) 1.) ALTER TABLE namespace ADD COLUMN binname columntype 2.) CREATE [UNIQUE] INDEX indexname ON namespace (binname) */ int ai_btree_create(as_sindex_metadata *imd, int simatch, int *bimatch, int nprts) { char *iname = NULL, *cname = NULL, *tname = NULL; int ret = AS_SINDEX_ERR, rv; if (1 != imd->num_bins) { cf_warning(AS_SINDEX, "Multi-bin indexes not supported"); return ret; } if (!(tname = create_tname_from_imd(imd))) { return AS_SINDEX_ERR_NO_MEMORY; } if (!(cname = create_cname_from_imd(imd))) { return AS_SINDEX_ERR_NO_MEMORY; } AI_GWLOCK(); int tmatch = find_table(tname); if (tmatch == -1) { if (0 > (rv = ai_create_table(tname))) { cf_warning(AS_SINDEX, "Create table %s failed (rv %d)", tname, rv); goto END; } tmatch = find_table(tname); } r_tbl_t *rt = &Tbl[tmatch]; // 1.) add entries in Aerospike Index's virtual TABLE int col_type = imd->btype[0]; icol_t *ic = find_column(tmatch, cname); if (!ic) { // COLUMN does not exist if (0 > ai_add_column(tname, cname, col_type)) { goto END; } // Add (cmatch+1) always non-zero SITRACE(imd->si, META, debug, "Added Mapping [BINNAME=%s: BINID=%d: COLID%d] [IMATCH=%d: SIMATCH=%d: INAME=%s]", imd->bnames[0], imd->binid[0], rt->col_count, Num_indx - 1, simatch, imd->iname); } //NOTE: COMMAND: CREATE PARTITIONED INDEX iname ON tname (cname) NUM = nprts if (!(iname = get_iname_from_imd(imd))) { ret = AS_SINDEX_ERR_NO_MEMORY; goto END; } if (0 > (rv = ai_create_index(iname, tname, cname, col_type, nprts))) { cf_warning(AS_SINDEX, "Create index %s failed (rv %d)", iname, rv); goto END; } *bimatch = match_partial_index_name(iname); GTRACE(META, debug, "cr8SecIndex: iname: %s bname: %s type: %d ns: %s set: %s tmatch: %d bimatch: %d", imd->iname, imd->bnames[0], imd->btype[0], imd->ns_name, imd->set, tmatch, *bimatch); ret = AS_SINDEX_OK; END: AI_UNLOCK(); cf_free(tname); cf_free(cname); cf_free(iname); return ret; }
int ai_findandset_imatch(as_sindex_metadata *imd, as_sindex_pmetadata *pimd, int idx) { if (!Num_tbls) { return AS_SINDEX_ERR; } char *tname = NULL; char *cname = NULL; char *iname = NULL; if (!(tname = create_tname_from_imd(imd))) { return AS_SINDEX_ERR_NO_MEMORY; } int ret = AS_SINDEX_ERR; AI_GRLOCK(); int tmatch = find_table(tname); if (tmatch == -1) { goto END; } if (imd->iname) { // This is always true if (!(iname = get_iname_from_imd(imd))) { ret = AS_SINDEX_ERR_NO_MEMORY; goto END; } char piname[INDD_HASH_KEY_SIZE]; snprintf(piname, sizeof(piname), "%s.%d", iname, idx); pimd->imatch = match_partial_index_name(piname); } else { // CAUTION : This will not work. Since ci->list is only populated for 0th pimd if (!(cname = create_cname_from_imd(imd))) { ret = AS_SINDEX_ERR_NO_MEMORY; goto END; } icol_t *ic = find_column(tmatch, cname); if (!ic) { goto END; } pimd->imatch = find_partial_index(tmatch, ic); cf_free(ic); } if (pimd->imatch == -1) { cf_debug(AS_SINDEX, "Index %s not found for %dth pimd", imd->iname, idx); goto END; } ret = AS_SINDEX_OK; END: AI_UNLOCK(); if (tname) { cf_free(tname); } if (iname) { cf_free(iname); } if (cname) { cf_free(cname); } return ret; }
/* NOTE: The creation of a secondary index is the following two commands 0.) optional: CREATE TABLE namespace (pk U160, __dummy TEXT) 1.) ALTER TABLE namespace ADD COLUMN binname columntype 2.) CREATE [UNIQUE] INDEX indexname ON namespace (binname) */ int ai_btree_create(as_sindex_metadata *imd, int simatch, int *bimatch, int nprts) { char *iname = NULL, *cname = NULL, *tname = NULL; int ret = AS_SINDEX_ERR, rv; if (!(tname = create_tname_from_imd(imd))) { return AS_SINDEX_ERR_NO_MEMORY; } if (!(cname = create_cname_from_imd(imd))) { if (tname) { cf_free(tname); } return AS_SINDEX_ERR_NO_MEMORY; } AI_GWLOCK(); // TODO : ai_create_table has this check. So this is redundant // 3 shash_get can be reduced to 1 through ai_get_or_create_table func int tmatch = find_table(tname); if (tmatch == -1) { if (0 > (rv = ai_create_table(tname))) { cf_warning(AS_SINDEX, "Create table %s failed (rv %d)", tname, rv); goto END; } tmatch = find_table(tname); } r_tbl_t *rt = &Tbl[tmatch]; // 1.) add entries in Aerospike Index's virtual TABLE int col_type = imd->btype; icol_t *ic = find_column(tmatch, cname); if (!ic) { // COLUMN does not exist if (0 > ai_add_column(tname, cname, col_type)) { goto END; } // Add (cmatch+1) always non-zero cf_debug(AS_SINDEX, "Added Mapping [BINNAME=%s: BINID=%d: COLID%d] [IMATCH=%d: SIMATCH=%d: INAME=%s]", imd->bname, imd->binid, rt->col_count, Num_indx - 1, simatch, imd->iname); } else { cf_free(ic); } //NOTE: COMMAND: CREATE PARTITIONED INDEX iname ON tname (cname) NUM = nprts if (!(iname = get_iname_from_imd(imd))) { ret = AS_SINDEX_ERR_NO_MEMORY; goto END; } if (0 > (rv = ai_create_index(iname, tname, cname, col_type, nprts))) { cf_warning(AS_SINDEX, "Create index %s failed (rv %d)", iname, rv); goto END; } *bimatch = match_partial_index_name(iname); cf_debug(AS_SINDEX, "cr8SecIndex: iname: %s bname: %s type: %d ns: %s set: %s tmatch: %d bimatch: %d", imd->iname, imd->bname, imd->btype, imd->ns_name, imd->set, tmatch, *bimatch); ret = AS_SINDEX_OK; END: AI_UNLOCK(); if (tname) { cf_free(tname); } if (cname) { cf_free(cname); } if (iname) { cf_free(iname); } return ret; }
int execute(char *sql, cursor * c) { int i, j, tab, ret; SQLPSTMT *st; ROW *dbrows; VALUE *dbval; int row, nrows; int *cols = NULL, ncols, col; int *selset; int dtype, stype; int width, decimals; char *tmpsql, name[500]; SQLPVALUE *calctmp; /* store for calculated values in UPDATE, if any */ /* parse sql statement */ /* I don't know why, but if the statement ends by string in quotes 'xxx' and is not * followed by space or '\n' it is not parsed properly -> */ tmpsql = (char *)G_malloc(strlen(sql) + 2); sprintf(tmpsql, "%s ", sql); st = sqpInitStmt(); st->stmt = tmpsql; sqpInitParser(st); if (yyparse() != 0) { G_free(tmpsql); append_error("SQL parser error: %s\n", st->errmsg); append_error("in statement:\n%s\n", sql); sqpFreeStmt(st); return DB_FAILED; } G_free(tmpsql); G_debug(3, "SQL statement parsed successfully: %s", sql); /* sqpPrintStmt(st); *//* debug output only */ /* find table */ tab = find_table(st->table); if (tab < 0 && st->command != SQLP_CREATE) { append_error("Table '%s' doesn't exist.\n", st->table); return DB_FAILED; } /* For DROP we have to call load_table_head() because it reads permissions */ if ((st->command != SQLP_CREATE)) { ret = load_table_head(tab); if (ret == DB_FAILED) { append_error("Cannot load table head.\n"); return DB_FAILED; } } if ((st->command == SQLP_DROP) || (st->command == SQLP_DELETE) || (st->command == SQLP_INSERT) || (st->command == SQLP_UPDATE) || (st->command == SQLP_ADD_COLUMN) || (st->command == SQLP_DROP_COLUMN) ) { if (db.tables[tab].write == FALSE) { append_error ("Cannot modify table, don't have write permission for DBF file.\n"); return DB_FAILED; } } /* find columns */ ncols = st->nCol; if (st->command == SQLP_INSERT || st->command == SQLP_SELECT || st->command == SQLP_UPDATE || st->command == SQLP_DROP_COLUMN) { if (ncols > 0) { /* colums were specified */ cols = (int *)G_malloc(ncols * sizeof(int)); for (i = 0; i < ncols; i++) { cols[i] = find_column(tab, st->Col[i].s); if (cols[i] == -1) { append_error("Column '%s' not found\n", st->Col[i].s); return DB_FAILED; } } } else { /* all columns */ ncols = db.tables[tab].ncols; cols = (int *)G_malloc(ncols * sizeof(int)); for (i = 0; i < ncols; i++) cols[i] = i; } } /* check column types */ if (st->command == SQLP_INSERT || st->command == SQLP_UPDATE) { for (i = 0; i < st->nVal; i++) { col = cols[i]; if (st->Val[i].type != SQLP_NULL && st->Val[i].type != SQLP_EXPR) { dtype = db.tables[tab].cols[col].type; stype = st->Val[i].type; if ((dtype == DBF_INT && stype != SQLP_I) || (dtype == DBF_DOUBLE && stype == SQLP_S) || (dtype == DBF_CHAR && stype != SQLP_S)) { append_error("Incompatible value type.\n"); return DB_FAILED; } } } } /* do command */ G_debug(3, "Doing SQL command <%d> on DBF table... (see include/sqlp.h)", st->command); switch (st->command) { case (SQLP_ADD_COLUMN): load_table(tab); get_col_def(st, 0, &dtype, &width, &decimals); ret = add_column(tab, dtype, st->Col[0].s, width, decimals); if (ret == DB_FAILED) { append_error("Cannot add column.\n"); return DB_FAILED; } /* Add column to each row */ for (i = 0; i < db.tables[tab].nrows; i++) { db.tables[tab].rows[i].values = (VALUE *) G_realloc(db.tables[tab].rows[i].values, db.tables[tab].ncols * sizeof(VALUE)); dbval = &(db.tables[tab].rows[i].values[db.tables[tab].ncols - 1]); dbval->i = 0; dbval->d = 0.0; dbval->c = NULL; dbval->is_null = 1; } db.tables[tab].updated = TRUE; break; case (SQLP_DROP_COLUMN): load_table(tab); if (drop_column(tab, st->Col[0].s) != DB_OK) { append_error("Cannot delete column.\n"); return DB_FAILED; } db.tables[tab].updated = TRUE; break; case (SQLP_CREATE): if (tab >= 0) { append_error("Table %s already exists\n", st->table); return DB_FAILED; } sprintf(name, "%s.dbf", st->table); add_table(st->table, name); tab = find_table(st->table); db.tables[tab].read = TRUE; db.tables[tab].write = TRUE; for (i = 0; i < ncols; i++) { get_col_def(st, i, &dtype, &width, &decimals); ret = add_column(tab, dtype, st->Col[i].s, width, decimals); if (ret == DB_FAILED) { append_error("Cannot create table.\n"); db.tables[tab].alive = FALSE; return DB_FAILED; } } db.tables[tab].described = TRUE; db.tables[tab].loaded = TRUE; db.tables[tab].updated = TRUE; break; case (SQLP_DROP): unlink(db.tables[tab].file); db.tables[tab].alive = FALSE; break; case (SQLP_INSERT): load_table(tab); /* add row */ if (db.tables[tab].nrows == db.tables[tab].arows) { db.tables[tab].arows += 1000; db.tables[tab].rows = (ROW *) G_realloc(db.tables[tab].rows, db.tables[tab].arows * sizeof(ROW)); } dbrows = db.tables[tab].rows; row = db.tables[tab].nrows; dbrows[row].values = (VALUE *) G_calloc(db.tables[tab].ncols, sizeof(VALUE)); dbrows[row].alive = TRUE; /* set to null */ for (i = 0; i < db.tables[tab].ncols; i++) { VALUE *dbval; dbval = &(dbrows[row].values[i]); dbval->is_null = 1; } /* set values */ for (i = 0; i < st->nVal; i++) { col = cols[i]; set_val(tab, row, col, &(st->Val[i])); } db.tables[tab].nrows++; db.tables[tab].updated = TRUE; break; case (SQLP_SELECT): G_debug(2, "SELECT"); c->st = st; c->table = tab; c->cols = cols; c->ncols = ncols; c->nrows = sel(st, tab, &(c->set)); if (c->nrows < 0) { append_error("Error in selecting rows\n"); return DB_FAILED; } c->cur = -1; break; case (SQLP_UPDATE): nrows = sel(st, tab, &selset); if (nrows < 0) { append_error("Error in selecting rows\n"); return DB_FAILED; } dbrows = db.tables[tab].rows; /* update rows */ for (i = 0; i < nrows; i++) { SQLPVALUE *temp_p; calctmp = (SQLPVALUE *) G_malloc((st->nVal) * sizeof(SQLPVALUE)); row = selset[i]; for (j = 0; j < st->nVal; j++) { col = cols[j]; eval_val(tab, row, col, &(st->Val[j]), &(calctmp[j])); } temp_p = st->Val; st->Val = calctmp; for (j = 0; j < st->nVal; j++) { col = cols[j]; set_val(tab, row, col, &(st->Val[j])); db.tables[tab].updated = TRUE; } st->Val = temp_p; G_free(calctmp); } break; case (SQLP_DELETE): nrows = sel(st, tab, &selset); if (nrows < 0) { append_error("Error in selecting rows\n"); return DB_FAILED; } dbrows = db.tables[tab].rows; /* delete rows */ for (i = 0; i < nrows; i++) { row = selset[i]; dbrows[row].alive = FALSE; db.tables[tab].updated = TRUE; } break; } if (st->command != SQLP_SELECT) { /* because statement is released with cursor */ sqpFreeStmt(st); if (cols) G_free(cols); } return DB_OK; }
cellInfo_t sql_eval( sqlInfo_t *db, Expr expr, tableInfo_t * table, cellInfo_t * row, int index, int total, sqlData_t * params, cellInfo_t * aggregate ) { value_t stack[ 64 ]; int sp; int i; static char buffer[ 16384 ]; // FIX ME: this is the source of bugs static int size = 0; int top = size; for ( i=0,sp=0; expr[ i ] != OP_END; ) { op_t op = READ_OP; switch( op ) { case OP_PUSH_INTEGER: stack[ sp++ ].i = READ_INT; break; case OP_PUSH_STRING: stack[ sp++ ].s = READ_STRING; break; case OP_PUSH_COLUMN: stack[ sp++ ].p = table->columns + READ_OP; break; case OP_PUSH_COLUMN_VAL: stack[ sp++ ].i = row[ READ_OP ].integer; break; case OP_PUSH_STRING_PARAM: stack[ sp++ ].s = params[ READ_OP ].payload.string; break; case OP_PUSH_INTEGER_PARAM: stack[ sp++ ].i = params[ READ_OP ].payload.integer; break; case OP_ROWINDEX: stack[ sp++ ].i = (row - table->rows) / table->column_count; break; case OP_ROWNUMBER: stack[ sp++ ].i = index; break; case OP_ROWTOTAL: stack[ sp++ ].i = total; break; case OP_ROWCOUNT: stack[ sp++ ].i = table->row_count; break; case OP_SYS_TIME: stack[ sp++ ].i = Sys_Milliseconds(); break; case OP_SUBTRACT: LVALUE.i = LEFT_OPERAND.i - RIGHT_OPERAND.i; sp--; break; case OP_ADD: LVALUE.i = LEFT_OPERAND.i + RIGHT_OPERAND.i; sp--; break; case OP_DIVIDE: LVALUE.i = LEFT_OPERAND.i / RIGHT_OPERAND.i; sp--; break; case OP_MULTIPLY: LVALUE.i = LEFT_OPERAND.i * RIGHT_OPERAND.i; sp--; break; case OP_MODULUS: LVALUE.i = LEFT_OPERAND.i % RIGHT_OPERAND.i; sp--; break; case OP_LOGICAL_AND: LVALUE.i = LEFT_OPERAND.i && RIGHT_OPERAND.i; sp--; break; case OP_LOGICAL_OR: LVALUE.i = LEFT_OPERAND.i || RIGHT_OPERAND.i; sp--; break; case OP_BITWISE_AND: LVALUE.i = LEFT_OPERAND.i & RIGHT_OPERAND.i; sp--; break; case OP_BITWISE_OR: LVALUE.i = LEFT_OPERAND.i | RIGHT_OPERAND.i; sp--; break; case OP_GT: LVALUE.i = LEFT_OPERAND.i > RIGHT_OPERAND.i; sp--; break; case OP_LT: LVALUE.i = LEFT_OPERAND.i < RIGHT_OPERAND.i; sp--; break; case OP_GE: LVALUE.i = LEFT_OPERAND.i >= RIGHT_OPERAND.i; sp--; break; case OP_LE: LVALUE.i = LEFT_OPERAND.i <= RIGHT_OPERAND.i; sp--; break; case OP_EQ: LVALUE.i = LEFT_OPERAND.i == RIGHT_OPERAND.i; sp--; break; case OP_NE: LVALUE.i = LEFT_OPERAND.i != RIGHT_OPERAND.i; sp--; break; case OP_ATOI: if (stack[ sp-1 ].s) { stack[ sp-1 ].i = atoi( stack[ sp-1 ].s ); } else { stack[ sp-1 ].i = -1; } break; case OP_LIKE: LVALUE.i = Q_stricmp( LEFT_OPERAND.s, RIGHT_OPERAND.s ) == 0; sp--; break; case OP_MATCH: LVALUE.i = Com_Filter( RIGHT_OPERAND.s, LEFT_OPERAND.s, 0 ); sp--; break; case OP_NOTLIKE: LVALUE.i = Q_stricmp( LEFT_OPERAND.s, RIGHT_OPERAND.s ) != 0; sp--; break; case OP_INT_MIN: LVALUE.i = (LEFT_OPERAND.i<RIGHT_OPERAND.i)?LEFT_OPERAND.i:RIGHT_OPERAND.i; sp--; break; case OP_INT_MAX: LVALUE.i = (LEFT_OPERAND.i>RIGHT_OPERAND.i)?LEFT_OPERAND.i:RIGHT_OPERAND.i; sp--; break; case OP_ABS: stack[ sp-1 ].i = abs( stack[ sp-1 ].i ); break; case OP_UMINUS: stack[ sp-1 ].i = -stack[ sp-1 ].i; break; case OP_NOT: stack[ sp-1 ].i = !(stack[ sp-1 ].i); break; case OP_REMOVE: { int p = READ_OP; int n = min( params[ p ].payload.integer, stack[ sp-1 ].i ); params[ p ].payload.integer -= n; stack[ sp-1 ].i = n; } break; case OP_ASSIGN_INT_TO_COLUMN: { columnInfo_t * c = (columnInfo_t*)LEFT_OPERAND.p; ASSERT( c->num >= 0 && c->num < table->column_count ); if ( row[ c->num ].integer != RIGHT_OPERAND.i ) { table->modified |= (1<<c->num); } LVALUE.i = row[ c->num ].integer = RIGHT_OPERAND.i; sp--; } break; case OP_ASSIGN_STRING_TO_COLUMN: { // a string is being inserted into a table. this string is expected to remain // constant throughout the life of the table. strings stored in tables do not // change. string cells can not be modified with an 'UPDATE' command columnInfo_t * c = (columnInfo_t*)LEFT_OPERAND.p; cellInfo_t * cell = row + c->num; const char * o = cell->string; ASSERT( c->format == STRING ); //ASSERT( cell->string == 0 ); // help!! if ( abs(RIGHT_OPERAND.i) < 0x10000 ) { // can't figure out data type for cases like: INSERT INTO missions VALUES(7,'wealth',500); 3rd column in text // so trying to guess LVALUE.s = cell->string = sql_alloc_string( db, fn( RIGHT_OPERAND.i, FN_PLAIN ) ); sp--; } else { LVALUE.s = cell->string = sql_alloc_string( db, RIGHT_OPERAND.s ); sp--; } if ( Q_stricmp( o, cell->string ) ) { table->modified |= (1<<c->num); } } break; case OP_ASSIGN_CS_TO_ROW: { row_cs( db, table, row, stack[ sp-1 ].s ); } break; case OP_COUNT: (*aggregate).integer++; break; case OP_MAX: { int v = stack[ sp-1 ].i; (*aggregate).integer = (index==0)?v:max( (*aggregate).integer, v ); } break; case OP_MIN: { int v = stack[ sp-1 ].i; (*aggregate).integer = (index==0)?v:min( (*aggregate).integer, v ); } break; case OP_SUM: (*aggregate).integer += stack[ sp-1 ].i; break; case OP_FORMAT: { char * s = buffer + size; int flags = READ_INT; size += fn_buffer( s, stack[ sp-1 ].i, flags ); stack[ sp-1 ].s = s; } break; case OP_CONCAT: { LVALUE.s = concat( LEFT_OPERAND.s, RIGHT_OPERAND.s, buffer, sizeof(buffer), &size ); sp--; } break; case OP_COLLAPSE: { char * s = buffer + size; size += concat2( s, sizeof(buffer)-size, stack, sp ); stack[ 0 ].s = s; sp = 1; } break; case OP_CVAR: { stack[ sp-1 ].s = Cvar_VariableString( stack[ sp-1 ].s ); } break; case OP_ACCESS_TABLE: { tableInfo_t * table; columnInfo_t * c; table = find_table( db, LEFT_OPERAND.s ); // allow table access outside current db if ( !table ) { table = find_table( sql_getclientdb(), LEFT_OPERAND.s ); if ( !table ) { table = find_table( sql_getserverdb(), LEFT_OPERAND.s ); if ( !table ) { table = find_table( sql_getcommondb(), LEFT_OPERAND.s ); } } } #ifdef DEVELOPER if ( !table ) { Com_Error( ERR_FATAL, "table '%s' does not exist.\n\n%s", LEFT_OPERAND.s, CURRENT_STMT ); } #endif c = find_column( table, RIGHT_OPERAND.s ); #ifdef DEVELOPER if ( !c ) { Com_Error( ERR_FATAL, "column '%s' expected on table '%s'.\n\n%s\n", RIGHT_OPERAND.s, LEFT_OPERAND.s, CURRENT_STMT ); } #endif LVALUE.p = table; sp--; stack[ sp++ ].p = c; } break; case OP_LOOKUP_I: { tableInfo_t * t = stack[ sp-3 ].p; columnInfo_t * c = stack[ sp-2 ].p; cellInfo_t k; int index; k.integer = stack[ sp-1 ].i; if ( !c->index ) { sql_create_index( db, t, c ); } #ifdef DEVELOPER if ( !c->index ) { Com_Error( ERR_FATAL, "index needed for column '%s' on table '%s'.\n\n%s", c->name, t->name, CURRENT_STMT ); } if ( c->format != INTEGER ) { Com_Error( ERR_FATAL, "expecting column '%s' on table '%s' to be integer, not string.\n\n%s", c->name, t->name, CURRENT_STMT ); } #endif if ( t->last_changed != t->last_indexed ) sql_table_reindex( t ); index = search_index_i( c->index, t->row_count, t->rows, t->column_count, c->num, k ); LVALUE.i = (index>=0)?c->index[ index ]:index; sp--; } break; case OP_ACCESS_ROW_I: { tableInfo_t * t = stack[ sp-3 ].p; int r = stack[ sp-2 ].i; columnInfo_t * c = find_column( t, stack[ sp-1 ].s ); #ifdef DEVELOPER if ( !t ) { Com_Error( ERR_FATAL, "table '%s' does not exist.\n\n%s", stack[sp-3].s, CURRENT_STMT ); } if ( !c ) { Com_Error( ERR_FATAL, "could not find column '%s' on table '%s' in statement:\n\n%s", stack[ sp-1 ].s, stack[sp-3].s, CURRENT_STMT ); } #endif sp -= 3; if ( r < 0 ) { stack[ sp++ ].i = -1; } else { int cell = (t->column_count*r) + c->num; if ( c->format == STRING ) { stack[ sp++ ].i = atoi( t->rows[ cell ].string ); } else { stack[ sp++ ].i = t->rows[ cell ].integer; } } } break; case OP_LOOKUP_S: { tableInfo_t * t = stack[ sp-3 ].p; columnInfo_t * c = stack[ sp-2 ].p; cellInfo_t k; int index; k.string = stack[ sp-1 ].s; if ( !c->index ) { sql_create_index( db, t, c ); } #ifdef DEVELOPER if ( !c->index ) { Com_Error( ERR_FATAL, "index needed for column '%s' on table '%s'.\n\n%s", c->name, t->name, CURRENT_STMT ); } if ( c->format != STRING ) { Com_Error( ERR_FATAL, "expecting column '%s' on table '%s' to be string, not integer.\n\n%s", c->name, t->name, CURRENT_STMT ); } #endif if ( t->last_changed != t->last_indexed ) sql_table_reindex( t ); index = search_index_s( c->index, t->row_count, t->rows, t->column_count, c->num, k ); LVALUE.i = (index>=0)?c->index[ index ]:index; sp--; } break; case OP_ACCESS_ROW_S: { tableInfo_t * t = stack[ sp-3 ].p; int r = stack[ sp-2 ].i; columnInfo_t * c = find_column( t, stack[ sp-1 ].s ); #ifdef DEVELOPER if ( !t ) { Com_Error( ERR_FATAL, "table does not exist.\n\n%s", CURRENT_STMT ); } if ( !c ) { Com_Error( ERR_FATAL, "invalid column for table '%s' in statement:\n\n%s", t->name, CURRENT_STMT ); } #endif sp -= 3; stack[ sp++ ].s = (r>=0)?t->rows[ (t->column_count*r) + c->num ].string:"???"; } break; case OP_PUSH_GS: { int offset = READ_INT; stack[ sp++ ].i = db->gs[ offset ]; } break; case OP_PUSH_GS_OFFSET: { int offset = READ_INT; stack[ sp-1 ].i = db->gs[ offset + stack[ sp-1 ].i ]; } break; case OP_PUSH_PS_CLIENT: { int offset = READ_INT; stack[ sp++ ].i = db->ps[ offset ]; } break; case OP_PUSH_PS_CLIENT_OFFSET: { int offset = READ_INT; stack[ sp-1 ].i = db->ps[ offset + stack[ sp-1 ].i ]; } break; case OP_IFTHENELSE: { int c = stack[ sp-1 ].i; value_t a = stack[ sp-2 ]; value_t b = stack[ sp-3 ]; sp -= 3; stack[ sp++ ] = (c)?b:a; } break; case OP_SHADER: { ASSERT( db->shader ); stack[ sp-1 ].i = db->shader( stack[ sp-1 ].s ); } break; case OP_SOUND: { ASSERT( db->sound ); stack[ sp-1 ].i = db->sound( stack[ sp-1 ].s ); } break; case OP_MODEL: { ASSERT( db->model ); stack[ sp-1 ].i = db->model( stack[ sp-1 ].s ); } break; case OP_PORTRAIT: { ASSERT( db->portrait ); stack[ sp-1 ].i = db->portrait( stack[ sp-1 ].s ); } break; case OP_PUSH_INTEGER_GLOBAL: { const char * global_id = READ_STRING; ASSERT( db->global_int ); stack[ sp++ ].i = db->global_int( global_id ); } break; // recursive integer call case OP_EVAL: { const char * s = stack[ sp-1 ].s; int r; switch ( SWITCHSTRING(s) ) { case 0: case CS('0',0,0,0): r = 0; break; case CS('1',0,0,0): r = 1; break; default: { Expr e; parseInfo_t pi = { 0 }; char tmp[ SQL_STMT_ALLOC ]; sqlStack_t* save = db->stmt_buffer.c; db->stmt_buffer.c = (sqlStack_t*)tmp; db->stmt_buffer.c->top = sizeof(sqlStack_t); pi.db = db; e = parse_expression( &s, &pi ); ASSERT( pi.rt == INTEGER ); ASSERT( pi.more == 0 ); r = sql_eval( db, e, table, row, index, total, params, aggregate ).integer; db->stmt_buffer.c = save; } break; } stack[ sp-1 ].i = r; } break; // recursive string call case OP_PRINT: { const char * s = stack[ sp-1 ].s; Expr e; parseInfo_t pi = { 0 }; char tmp[ SQL_STMT_ALLOC ]; sqlStack_t* save = db->stmt_buffer.c; db->stmt_buffer.c = (sqlStack_t*)tmp; db->stmt_buffer.c->top = sizeof(sqlStack_t); pi.db = db; pi.flags = PARSE_STRINGLITERAL; e = parse_expression( &s, &pi ); ASSERT( pi.rt == STRING ); ASSERT( pi.more == 0 ); stack[ sp-1 ].s = sql_eval( db, e, table, row, index, total, params, aggregate ).string; db->stmt_buffer.c = save; } break; // execute a precompiled expression, returns string case OP_RUN: { int index = stack[ sp-1 ].i; if ( index < 0 || index >= db->stmts_byindex_count || !db->stmts_byindex[ index ] ) { stack[ sp-1 ].s = "???"; break; } stack[ sp-1 ].s = sql_eval( db, ((formatInfo_t*)db->stmts_byindex[ index ])->print, 0, 0, 0, 0, 0, 0 ).string; size += strlen(stack[ sp-1 ].s) + 1; } break; case OP_RND: { LVALUE.i = Rand_NextInt32InRange( &db->rand, LEFT_OPERAND.i, RIGHT_OPERAND.i ); sp--; } break; #if DEVELOPER default: { Com_Error(ERR_FATAL, "invalid sql op code: '%d'.\n", op ); } break; #endif } #ifdef DEVELOPER db->ops++; #endif } ASSERT( size <= sizeof(buffer) ); // stack overflow size = top; if ( sp == 0 ) { cellInfo_t c; c.integer = 0; return c; } ASSERT( sp == 1 ); return *(cellInfo_t*)stack; }
// INSERT INTO "commodities_events" VALUES(7, 5, 3, 400, 600); // INSERT INTO contacts(player,npc) VALUES(?,?); stmtInfo_t * sql_insert_parse( sqlInfo_t * db, const char ** s ) { columnInfo_t * c[ MAX_COLUMNS_PER_TABLE ]; int i,count=0; tableInfo_t * table; insertInfo_t * insert; char * n; // 'INTO' parse_temp( s ); n = parse_temp( s ); if ( db->create_filter ) { if ( Q_stricmp( n, db->create_filter ) ) { return 0; } } switch ( CS(n[0],n[1],n[2],0) ) { case CS('s','v','_',0): if ( db->memory_tag == TAG_SQL_CLIENT && !db->create_filter ) return 0; n += 3; break; case CS('c','l','_',0): if ( db->memory_tag == TAG_SQL_SERVER && !db->create_filter ) return 0; n += 3; break; case CS('b','g','_',0): n += 3; break; } table = find_table( db, n ); if ( !table ) return 0; ASSERT( table ); insert = sql_calloc_stmt( db, sizeof(insertInfo_t) ); insert->stmt.type = SQL_INSERT; insert->stmt.table = table; // parse column names if ( parse_tofirstparam( s ) ) { do { char * name = parse_temp( s ); c[ count ] = find_column( table, name ); #ifdef DEVELOPER if ( c[ count ] == 0 ) { Com_Error( ERR_FATAL, "column '%s' does not exist on table '%s'.\n", name, table->name ); } #endif count++; } while( parse_tonextparam( s ) ); } else { for ( i=0; i<table->column_count; i++ ) c[ count++ ] = &table->columns[ i ]; } // skip VALUES keyword switch ( SWITCHSTRING( parse_temp( s ) ) ) { case CS('s','e','l','e'): { insert->select = (selectInfo_t*)sql_select_parse( db, s ); for ( i=0; i<count; i++ ) { insert->columns[ i ] = (char)c[ i ]->num; } ASSERT( count == insert->select->column_count ); } break; case CS('v','a','l','u'): { parseInfo_t pi = { 0 }; pi.db = db; pi.params = insert->stmt.params; pi.table = insert->stmt.table; pi.flags = PARSE_ASSIGN_TO_COLUMN; pi.more = 1; // parse column assignments if ( parse_tofirstparam( s ) ) { for ( i=0; pi.more; i++ ) { pi.column = c[ i ]->num; insert->values_expr[ i ] = parse_expression( s, &pi ); } insert->values_count = i; } ASSERT( insert->values_count == count ); } break; case CS('r','o','w','s'): { cellInfo_t * row; parseInfo_t pi = { 0 }; Expr e; pi.db = db; pi.params = insert->stmt.params; pi.table = insert->stmt.table; pi.more = 1; if ( parse_tofirstparam( s ) ) { while ( pi.more ) { row = sql_insert_begin( db, table ); for ( i=0; i<table->column_count; i++ ) { int top = db->stmt_buffer.c->top; e = parse_expression( s, &pi ); row[ i ] = sql_eval( db, e, table, 0,0,1, 0, 0 ); if ( table->columns[ i ].format == STRING ) { row[ i ].string = sql_alloc_string( db, row[ i ].string ); } db->stmt_buffer.c->top = top; } sql_insert_done( db, table ); } } return 0; } break; } return &insert->stmt; }
/* Evaluate node recursively. * * Returns: * NODE_NULL result/value is unknown * NODE_TRUE * NODE_FALSE * NODE_VALUE result is a value stored in 'value' * (if value is not NULL otherwise NODE_NULL is returned and value is not set) * NODE_ERROR e.g. division by 0 * * If results is NODE_VALUE, the 'value' is set, if value is type SQLP_S the string is not duplicated * and only pointer is set -> do not free value->s */ double eval_node(SQLPNODE * nptr, int tab, int row, SQLPVALUE * value) { int left, right; SQLPVALUE left_value, right_value; int ccol; COLUMN *col; VALUE *val; double left_dval, right_dval, dval; char *rightbuf; /* Note: node types were previously checked by eval_node_type */ G_debug(4, "eval_node node_type = %d", nptr->node_type); switch (nptr->node_type) { case SQLP_NODE_VALUE: if (nptr->value.type == SQLP_NULL) return NODE_NULL; value->type = nptr->value.type; value->s = nptr->value.s; value->i = nptr->value.i; value->d = nptr->value.d; return NODE_VALUE; break; case SQLP_NODE_COLUMN: ccol = find_column(tab, nptr->column_name); col = &(db.tables[tab].cols[ccol]); val = &(db.tables[tab].rows[row].values[ccol]); if (val->is_null) return NODE_NULL; switch (col->type) { case DBF_CHAR: value->s = val->c; value->type = SQLP_S; break; case DBF_INT: value->i = val->i; value->type = SQLP_I; break; case DBF_DOUBLE: value->d = val->d; value->type = SQLP_D; break; } return NODE_VALUE; break; case SQLP_NODE_EXPRESSION: /* Note: Some expressions (e.g. NOT) have only one side */ if (nptr->left) { left = eval_node(nptr->left, tab, row, &left_value); G_debug(4, " left = %d", left); if (left == NODE_ERROR) return NODE_ERROR; if (left != NODE_NULL) { if (left_value.type == SQLP_I) left_dval = left_value.i; else left_dval = left_value.d; G_debug(4, " left_dval = %f", left_dval); } } if (nptr->right) { right = eval_node(nptr->right, tab, row, &right_value); G_debug(4, " right = %d", right); if (right == NODE_ERROR) return NODE_ERROR; if (right != NODE_NULL) { if (right_value.type == SQLP_I) right_dval = right_value.i; else right_dval = right_value.d; G_debug(4, " right_dval = %f", right_dval); } } G_debug(4, " operator = %d", nptr->oper); switch (nptr->oper) { /* Arithmetical */ case SQLP_ADD: case SQLP_SUBTR: case SQLP_MLTP: case SQLP_DIV: if (left == NODE_NULL || right == NODE_NULL) return NODE_NULL; switch (nptr->oper) { case SQLP_ADD: dval = left_dval + right_dval; break; case SQLP_SUBTR: dval = left_dval - right_dval; break; case SQLP_MLTP: dval = left_dval * right_dval; break; case SQLP_DIV: if (right_dval != 0.0) { dval = left_dval / right_dval; } else { append_error("Division by zero\n"); return NODE_ERROR; } break; } if (left_value.type == SQLP_I && right_value.type == SQLP_I && (nptr->oper == SQLP_ADD || nptr->oper == SQLP_SUBTR || nptr->oper == SQLP_MLTP)) { value->type = SQLP_I; value->i = (int)dval; } else { value->type = SQLP_D; value->d = dval; } return NODE_VALUE; break; /* Comparison */ /* Operators valid for all type */ case SQLP_EQ: if (left == NODE_NULL || right == NODE_NULL) { return NODE_NULL; } else if (left_value.type == SQLP_S) { /* we checked before if right is also string */ if (left_value.s && right_value.s && strcmp(left_value.s, right_value.s) == 0) return NODE_TRUE; else return NODE_FALSE; } else { /* numbers */ if (left_dval == right_dval) return NODE_TRUE; else return NODE_FALSE; } break; case SQLP_NE: if (left == NODE_NULL || right == NODE_NULL) { return NODE_NULL; } else if (left_value.type == SQLP_S) { /* we checked before if right is also string */ if (left_value.s && right_value.s && strcmp(left_value.s, right_value.s) != 0) return NODE_TRUE; else return NODE_FALSE; } else { /* numbers */ if (left_dval != right_dval) return NODE_TRUE; else return NODE_FALSE; } /* Operators valid for numbers */ case SQLP_LT: if (left == NODE_NULL || right == NODE_NULL) { return NODE_NULL; } else { if (left_dval < right_dval) return NODE_TRUE; else return NODE_FALSE; } case SQLP_LE: if (left == NODE_NULL || right == NODE_NULL) { return NODE_NULL; } else { if (left_dval <= right_dval) return NODE_TRUE; else return NODE_FALSE; } case SQLP_GT: if (left == NODE_NULL || right == NODE_NULL) { return NODE_NULL; } else { if (left_dval > right_dval) return NODE_TRUE; else return NODE_FALSE; } case SQLP_GE: if (left == NODE_NULL || right == NODE_NULL) { return NODE_NULL; } else { if (left_dval >= right_dval) return NODE_TRUE; else return NODE_FALSE; } /* Operator valid for string */ case SQLP_MTCH: if (left == NODE_NULL || right == NODE_NULL) { return NODE_NULL; } else { /* hack to get '%substring' and 'substring%' working */ rightbuf = G_str_replace(right_value.s, "%", ""); G_chop(rightbuf); if (left_value.s && right_value.s && strstr(left_value.s, rightbuf) != NULL) { G_free(rightbuf); return NODE_TRUE; } else { G_free(rightbuf); return NODE_FALSE; } } case SQLP_ISNULL: return right == NODE_NULL ? NODE_TRUE : NODE_FALSE; case SQLP_NOTNULL: return right != NODE_NULL ? NODE_TRUE : NODE_FALSE; /* Logical */ case SQLP_AND: if (left == NODE_NULL || right == NODE_NULL) { return NODE_NULL; } else if (left == NODE_TRUE && right == NODE_TRUE) { return NODE_TRUE; } else if (left == NODE_VALUE || right == NODE_VALUE) { /* Should not happen */ append_error("Value operand for AND\n"); return NODE_ERROR; } else { return NODE_FALSE; } case SQLP_OR: if (left == NODE_NULL && right == NODE_NULL) { return NODE_NULL; } else if (left == NODE_TRUE || right == NODE_TRUE) { return NODE_TRUE; } else if (left == NODE_VALUE || right == NODE_VALUE) { /* Should not happen */ append_error("Value operand for OR\n"); return NODE_ERROR; } else { return NODE_FALSE; } case SQLP_NOT: /* sub node stored on the right side */ if (right == NODE_NULL) { return NODE_NULL; } else if (right == NODE_TRUE) { return NODE_FALSE; } else if (right == NODE_VALUE) { /* Should not happen */ append_error("Value operand for NOT\n"); return NODE_ERROR; } else { return NODE_TRUE; } default: append_error("Unknown operator %d\n", nptr->oper); return NODE_FALSE; } } return NODE_ERROR; /* Not reached */ }
void test_table() { // Create a database with the default options. auto db = grnxx::open_db(""); // Create a table named "Table". auto table = db->create_table("Table"); assert(table->db() == db.get()); assert(table->name() == "Table"); assert(table->num_columns() == 0); assert(!table->key_column()); assert(table->num_rows() == 0); assert(table->max_row_id().is_na()); assert(table->is_empty()); assert(table->is_full()); // Create a column named "Column_1". auto column = table->create_column("Column_1", GRNXX_BOOL); assert(column->name() == "Column_1"); assert(table->num_columns() == 1); assert(table->get_column(0) == column); assert(table->find_column("Column_1") == column); // The following create_column() must fail because "Column_1" already exists. try { table->create_column("Column_1", GRNXX_BOOL); assert(false); } catch (...) { } // Create columns named "Column_2" and Column_3". table->create_column("Column_2", GRNXX_BOOL); table->create_column("Column_3", GRNXX_BOOL); assert(table->num_columns() == 3); // Remove "Column_2". table->remove_column("Column_2"); assert(table->num_columns() == 2); assert(table->get_column(0)->name() == "Column_1"); assert(table->get_column(1)->name() == "Column_3"); // Recreate "Column_2". table->create_column("Column_2", GRNXX_BOOL); // Move "Column_3" to the next to "Column_2". table->reorder_column("Column_3", "Column_2"); assert(table->get_column(0)->name() == "Column_1"); assert(table->get_column(1)->name() == "Column_2"); assert(table->get_column(2)->name() == "Column_3"); // Move "Column_3" to the head. table->reorder_column("Column_3", ""); assert(table->get_column(0)->name() == "Column_3"); assert(table->get_column(1)->name() == "Column_1"); assert(table->get_column(2)->name() == "Column_2"); // Move "Column_2" to the next to "Column3". table->reorder_column("Column_2", "Column_3"); assert(table->get_column(0)->name() == "Column_3"); assert(table->get_column(1)->name() == "Column_2"); assert(table->get_column(2)->name() == "Column_1"); }
Column* Database::find_column(Column column) { return find_column(column.get_column_name()); }
/* Recursively get value/expression type. * Returns: node type (SQLP_S, SQLP_I, SQLP_D, SQLP_NULL, SQLP_BOOL) * -1 on error (if types in expression are not compatible) * * Rules: * Values (in SQL Statement): * SQLP_S -> SQLP_S * SQLP_I -> SQLP_I * SQLP_D -> SQLP_D * SQLP_NULL -> SQLP_NULL * Columns (in dbf table): * DBF_CHAR -> SQLP_S * DBF_INT -> SQLP_I * DBF_DOUBLE -> SQLP_D * Arithetical Expressions : * side1 side2 exp * SQLP_S ALL ALL -> error * SQLP_NULL SQLP_I ALL -> SQLP_NULL * SQLP_NULL SQLP_D ALL -> SQLP_NULL * SQLP_I SQLP_I +,-,* -> SQLP_I * SQLP_I SQLP_I / -> SQLP_D * SQLP_I SQLP_D ALL -> SQLP_D * SQLP_D SQLP_D ALL -> SQLP_D * Comparisons : * side1 side2 exp * SQLP_S SQLP_S =,<>,~ -> SQLP_BOOL * SQLP_S SQLP_S <,<=,>,>= -> error * SQLP_S SQLP_I ALL -> error * SQLP_S SQLP_D ALL -> error * SQLP_I SQLP_I =,<>,<,<=,>,>= -> SQLP_BOOL * SQLP_D SQLP_D =,<>,<,<=,>,>= -> SQLP_BOOL * SQLP_I SQLP_D =,<>,<,<=,>,>= -> SQLP_BOOL * SQLP_I ALL ~ -> error * SQLP_D ALL ~ -> error * SQLP_NULL ALL ALL -> SQLP_NULL * Logical expressions * In general, if we know that the result is NULL regardless actual values it returns SQLP_NULL * so that tests for individual rows are not performed, otherwise SQLP_BOOL * SQLP_BOOL SQLP_BOOL AND -> SQLP_BOOL * SQLP_BOOL SQLP_NULL AND -> SQLP_NULL * SQLP_NULL SQLP_NULL AND -> SQLP_NULL * SQLP_BOOL SQLP_BOOL OR -> SQLP_BOOL * SQLP_BOOL SQLP_NULL OR -> SQLP_BOOL * SQLP_NULL SQLP_NULL OR -> SQLP_NULL * SQLP_BOOL - NOT -> SQLP_BOOL * SQLP_NULL - NOT -> SQLP_NULL */ int eval_node_type(SQLPNODE * nptr, int tab) { int left, right; int ccol; COLUMN *col = NULL; switch (nptr->node_type) { case SQLP_NODE_VALUE: return nptr->value.type; break; case SQLP_NODE_COLUMN: ccol = find_column(tab, nptr->column_name); if (ccol == -1) { append_error("Column '%s' not found\n", nptr->column_name); return (-1); } col = &(db.tables[tab].cols[ccol]); switch (col->type) { case DBF_CHAR: return (SQLP_S); break; case DBF_INT: return (SQLP_I); break; case DBF_DOUBLE: return (SQLP_D); break; } break; case SQLP_NODE_EXPRESSION: /* Note: Some expressions (e.g. NOT) have only one side */ if (nptr->left) { left = eval_node_type(nptr->left, tab); if (left == -1) return -1; } if (nptr->right) { right = eval_node_type(nptr->right, tab); if (right == -1) return -1; } switch (nptr->oper) { /* Arithmetical */ case SQLP_ADD: case SQLP_SUBTR: case SQLP_MLTP: case SQLP_DIV: if (left == SQLP_S || right == SQLP_S) { append_error ("Arithmetical operation with strings is not allowed\n"); return -1; } else if (left == SQLP_NULL || right == SQLP_NULL) { return SQLP_NULL; } else if (left == SQLP_I && right == SQLP_I && (nptr->oper == SQLP_ADD || nptr->oper == SQLP_SUBTR || nptr->oper == SQLP_MLTP)) { return SQLP_I; } else { return SQLP_D; } break; /* Comparison */ /* Operators valid for all type */ case SQLP_EQ: case SQLP_NE: if ((left == SQLP_S && (right == SQLP_I || right == SQLP_D)) || (right == SQLP_S && (left == SQLP_I || left == SQLP_D))) { append_error ("Comparison between string and number is not allowed\n"); return -1; } else if (left == SQLP_NULL || right == SQLP_NULL) { return SQLP_NULL; } else { return SQLP_BOOL; } /* Operators valid for numbers */ case SQLP_LT: case SQLP_LE: case SQLP_GT: case SQLP_GE: if (left == SQLP_S || right == SQLP_S) { append_error("Comparison '%s' between strings not allowed\n", sqpOperatorName(nptr->oper)); return -1; } else if (left == SQLP_NULL || right == SQLP_NULL) { return SQLP_NULL; } else { return SQLP_BOOL; } /* Operator valid for string */ case SQLP_MTCH: if (left == SQLP_I || left == SQLP_D || right == SQLP_I || right == SQLP_D) { append_error("Match (~) between numbers not allowed\n"); return -1; } else if (left == SQLP_NULL || right == SQLP_NULL) { return SQLP_NULL; } else { return SQLP_BOOL; } case SQLP_ISNULL: case SQLP_NOTNULL: return SQLP_BOOL; /* Logical */ case SQLP_AND: if (left == SQLP_NULL || right == SQLP_NULL) { return SQLP_NULL; } else { return SQLP_BOOL; } case SQLP_OR: if (left == SQLP_NULL && right == SQLP_NULL) { return SQLP_NULL; } else { return SQLP_BOOL; } case SQLP_NOT: /* sub node stored on the right side */ if (right == SQLP_NULL) { return SQLP_NULL; } else { return SQLP_BOOL; } default: append_error("Unknown operator %d\n", nptr->oper); return -1; } } return -1; /* Not reached */ }