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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
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;
}
Beispiel #7
0
// 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();
}
Beispiel #8
0
/* 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;
}
Beispiel #10
0
/* 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;
}
Beispiel #11
0
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;
}
Beispiel #14
0
/* 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 */
}
Beispiel #15
0
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");
}
Beispiel #16
0
Column* Database::find_column(Column column) {
  return find_column(column.get_column_name());
}
Beispiel #17
0
/* 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 */
}